├── .gitignore
├── bin
└── phpctags
├── tests
├── bootstrap.php
└── Acceptance
│ ├── FilesystemTest.php
│ ├── FunctionsTest.php
│ ├── NamespacesTest.php
│ ├── ExtensionsText.php
│ ├── ConstantsTest.php
│ ├── ExcludeTest.php
│ ├── InterfacesTest.php
│ ├── VariablesTest.php
│ ├── TraitsTest.php
│ ├── ClassesTest.php
│ ├── KindsTest.php
│ └── AcceptanceTestCase.php
├── .travis.yml
├── phpunit.xml.dist
├── composer.json
├── Makefile
├── ChangeLog.md
├── README.md
├── bootstrap.php
├── PHPCtags.class.php
└── composer.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | .test_fs
2 | build/
3 | vendor/
4 | .phpunit.result.cache
5 |
--------------------------------------------------------------------------------
/bin/phpctags:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 |
2 |
3 |
4 |
5 |
6 | tests/
7 |
8 |
9 |
10 |
11 | src
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vim-php/phpctags",
3 | "description": "An enhanced php ctags index generator.",
4 | "keywords": ["ctags"],
5 | "type": "library",
6 | "require": {
7 | "php": ">=7.4",
8 | "nikic/php-parser": "^5.4.0"
9 | },
10 | "require-dev": {
11 | "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
12 | },
13 | "autoload": {
14 | "classmap": ["PHPCtags.class.php"]
15 | },
16 | "autoload-dev": {
17 | "psr-4": {
18 | "tests\\PHPCTags\\": "tests/"
19 | }
20 | },
21 | "bin": ["bin/phpctags"]
22 | }
23 |
--------------------------------------------------------------------------------
/tests/Acceptance/FilesystemTest.php:
--------------------------------------------------------------------------------
1 | givenDirectory('unreadable');
13 | $this->givenSourceFile('unreadable/UnreadableClass.php', <<givenMode('unreadable', 0000);
22 |
23 | $this->runPHPCtags();
24 | $this->assertTagsFileHeaderIsCorrect();
25 |
26 | $this->assertTagsFileContainsNoTagsFromFile('unreadable/UnreadableClass.php');
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/Acceptance/FunctionsTest.php:
--------------------------------------------------------------------------------
1 | givenSourceFile('FunctionExample.php', <<<'EOS'
13 | runPHPCtags();
22 |
23 | $this->assertTagsFileHeaderIsCorrect();
24 | $this->assertNumberOfTagsInTagsFileIs(1);
25 | $this->assertTagsFileContainsTag(
26 | 'FunctionExample.php',
27 | 'testFunction',
28 | self::KIND_FUNCTION,
29 | 3
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/Acceptance/NamespacesTest.php:
--------------------------------------------------------------------------------
1 | givenSourceFile('MultiLevelNamespace.php', <<<'EOS'
13 | runPHPCtags();
20 |
21 | $this->assertTagsFileHeaderIsCorrect();
22 | $this->assertNumberOfTagsInTagsFileIs(1);
23 | $this->assertTagsFileContainsTag(
24 | 'MultiLevelNamespace.php',
25 | 'Level1\Level2',
26 | self::KIND_NAMESPACE,
27 | 3
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | source := README.md \
2 | ChangeLog.md \
3 | composer.json \
4 | composer.lock \
5 | bootstrap.php \
6 | PHPCtags.class.php
7 |
8 | .PHONY: all
9 | all: build/phpctags.phar
10 |
11 | .PHONY: clean
12 | clean:
13 | @echo "Cleaning executables ..."
14 | @rm -f ./build/phpctags.phar
15 | @echo "Done!"
16 |
17 | .PHONY: dist-clean
18 | dist-clean:
19 | @echo "Cleaning old build files and vendor libraries ..."
20 | @rm -rf ./build
21 | @rm -rf ./vendor
22 | @echo "Done!"
23 |
24 | .PHONY: install
25 | install: phpctags
26 | @echo "Sorry, you need to move phpctags to /usr/bin/phpctags or /usr/local/bin/phpctags or any place you want manually."
27 |
28 | build:
29 | @if [ ! -x build ]; \
30 | then \
31 | mkdir build; \
32 | fi
33 |
34 | build/composer.phar: | build
35 | @echo "Installing composer ..."
36 | @curl -s http://getcomposer.org/installer | php -- --install-dir=build
37 |
38 | vendor: composer.lock build/composer.phar
39 | @echo "Installing vendor libraries ..."
40 | @php build/composer.phar install
41 | @touch vendor/
42 |
43 | build/phpctags.phar: vendor $(source) | build
44 | @php -dphar.readonly=0 buildPHAR.php
45 | @chmod +x build/phpctags.phar
46 |
--------------------------------------------------------------------------------
/tests/Acceptance/ExtensionsText.php:
--------------------------------------------------------------------------------
1 | givenSourceFile('new_extension.inc', <<runPHPCtags();
24 | $this->assertTagsFileHeaderIsCorrect();
25 |
26 | $this->assertTagsFileContainsNoTagsFromFile('new_extension.inc');
27 | }
28 |
29 | /**
30 | * @test
31 | */
32 | public function itUsesCustomExtensions()
33 | {
34 | $this->givenSourceFile('new_extension.inc', <<runPHPCtags(array('--extensions=+.inc'));
46 | $this->assertTagsFileHeaderIsCorrect();
47 | $this->assertNumberOfTagsInTagsFileIs(2);
48 |
49 | $this->assertTagsFileContainsTag(
50 | 'new_extension.inc',
51 | 'TestClass',
52 | self::KIND_CLASS,
53 | 3
54 | );
55 | $this->assertTagsFileContainsTag(
56 | 'new_extension.inc',
57 | 'publicMethod',
58 | self::KIND_METHOD,
59 | 5,
60 | 'class:TestClass',
61 | 'public'
62 | );
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/tests/Acceptance/ConstantsTest.php:
--------------------------------------------------------------------------------
1 | givenSourceFile('Constants.php', <<<'EOS'
13 | runPHPCtags();
22 |
23 | $this->assertTagsFileHeaderIsCorrect();
24 | $this->assertNumberOfTagsInTagsFileIs(2);
25 | $this->assertTagsFileContainsTag(
26 | 'Constants.php',
27 | 'CONSTANT_1',
28 | self::KIND_CONSTANT,
29 | 3
30 | );
31 | $this->assertTagsFileContainsTag(
32 | 'Constants.php',
33 | 'CONSTANT_2',
34 | self::KIND_CONSTANT,
35 | 5
36 | );
37 | }
38 |
39 | /**
40 | * @test
41 | */
42 | public function itCreatesTagFileForNamespacedConstants()
43 | {
44 | $this->givenSourceFile('Constants.php', <<<'EOS'
45 | runPHPCtags();
56 |
57 | $this->assertTagsFileHeaderIsCorrect();
58 | $this->assertNumberOfTagsInTagsFileIs(3);
59 | $this->assertTagsFileContainsTag(
60 | 'Constants.php',
61 | 'CONSTANT_1',
62 | self::KIND_CONSTANT,
63 | 5,
64 | 'namespace:Level1\Level2'
65 | );
66 | $this->assertTagsFileContainsTag(
67 | 'Constants.php',
68 | 'CONSTANT_2',
69 | self::KIND_CONSTANT,
70 | 7,
71 | 'namespace:Level1\Level2'
72 | );
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/tests/Acceptance/ExcludeTest.php:
--------------------------------------------------------------------------------
1 | givenSourceFile('File1.php', <<<'EOS'
13 | givenSourceFile('File2.php', <<<'EOS'
20 | runPHPCtagsWithExcludes(array('File2.php'));
27 |
28 | $this->assertTagsFileHeaderIsCorrect();
29 | $this->assertTagsFileContainsNoTagsFromFile('File2.php');
30 | }
31 |
32 | /**
33 | * @test
34 | */
35 | public function itExcludesMultipleFilesByName()
36 | {
37 | $this->givenSourceFile('File1.php', <<<'EOS'
38 | givenSourceFile('File2.php', <<<'EOS'
45 | givenSourceFile('File3.php', <<<'EOS'
52 | runPHPCtagsWithExcludes(array('File2.php', 'File3.php'));
59 |
60 | $this->assertTagsFileHeaderIsCorrect();
61 | $this->assertTagsFileContainsNoTagsFromFile('File2.php');
62 | $this->assertTagsFileContainsNoTagsFromFile('File3.php');
63 | }
64 |
65 | /**
66 | * @test
67 | */
68 | public function itExcludesFileByPatter()
69 | {
70 | $this->givenSourceFile('File.php', <<<'EOS'
71 | givenSourceFile('File.skip.php', <<<'EOS'
78 | markTestIncomplete('Pattern matching currently doesn\'t appear to work');
85 | $this->runPHPCtagsWithExcludes(array('*.skip.php'));
86 |
87 | $this->assertTagsFileHeaderIsCorrect();
88 | $this->assertTagsFileContainsNoTagsFromFile('File.skip.php');
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/ChangeLog.md:
--------------------------------------------------------------------------------
1 | Version 0.10.0
2 | -------------
3 |
4 | * Updated to PHP-Parser 4.13 to support PHP 8.1.
5 |
6 | Version 0.9.0
7 | -------------
8 |
9 | * Updated to PHP-Parser 4.10 to support PHP 8.0.
10 |
11 | Version 0.8.1
12 | -------------
13 |
14 | * Updated PHPUnit to 6.0.
15 | * Removed support for PHP 5.x.
16 |
17 | Version 0.7.0
18 | -------------
19 |
20 | * Updated to PHP-Parser 4.0.
21 |
22 | Version 0.6.1
23 | -------------
24 |
25 | * Follow symlinks below directories. (Previously only symlinks in the top
26 | directory were followed)
27 |
28 | Version 0.6.0
29 | -------------
30 |
31 | * Exclude phpctags when re-building phar
32 | * Fix typo in README.md
33 | * Fixed PHPUnit.xml.dist
34 | * Refactoring codebase
35 | * Refactroing testsuite
36 | * Now composer support an entry point to install in globally
37 | * Define new build flow
38 |
39 | Version 0.5.1
40 | -------------
41 |
42 | * Fix building compatiblity with PHP 5.3.*
43 | thanks to grep-awesome@github
44 |
45 | Version 0.5
46 | -----------
47 |
48 | * Add trait support
49 | thanks to Mark Wu
50 | * Add inherits support
51 | thanks to Mark Wu
52 | * Add namespace support
53 | thanks to Mark Wu
54 | * Add instruction to enable phar extension in README
55 |
56 | Version 0.4.2
57 | -------------
58 |
59 | * Add assign reference support to phpctags
60 | thanks to Mark Wu
61 |
62 | Version 0.4.1
63 | -------------
64 |
65 | * Add explaination for PHAR supported platforms
66 |
67 | Version 0.4
68 | -----------
69 |
70 | * add tagline support
71 | thanks to Mark Wu
72 | * add a Makefile to build stand-alone PHAR executable
73 | thanks to Mark Wu
74 | * update PHPParser dependency to version 0.9.3
75 |
76 | Version 0.3
77 | -----------
78 |
79 | * able to control the memroy size to be used
80 | thanks to Dannel Jurado
81 | * improved command line compatiblity to ctags
82 | thanks to Sander Marechal
83 | * bug fixes: #5 and #7
84 |
85 | Version 0.2
86 | -----------
87 |
88 | * new kind descriptor
89 | * ctags flags support
90 | * excmd
91 | * fields
92 | * format
93 | * new test case layer
94 | * introduce debug mode
95 | * bug fixes: #3 and #4
96 |
97 | Version 0.1
98 | -----------
99 |
100 | * ctags compatible
101 | * surppoted tokens
102 | * constant
103 | * variable
104 | * function
105 | * class
106 | * class method
107 | * class property
108 | * class constant
109 | * interface
110 | * scope field support
111 | * access field support
112 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # phpctags
2 |
3 | An enhanced php [ctags](http://ctags.sourceforge.net/) index file generator
4 | compatible with http://ctags.sourceforge.net/FORMAT.
5 |
6 | Using [PHP_Parser](https://github.com/nikic/PHP-Parser) as PHP syntax parsing
7 | backend, written in pure PHP. The generated ctags index file contains scope
8 | and access information about classes' methods and properties.
9 |
10 | This tool was originally developed to enhance the PHP syntax outline surport
11 | for vim [tagbar](http://majutsushi.github.com/tagbar/) plugin. The enhanced
12 | functionality has been included into an addon plugin for tagbar as
13 | [tagbar-phpctags](https://github.com/techlivezheng/tagbar-phpctags).
14 |
15 | Enjoy!
16 |
17 | ## Download and installation
18 |
19 | ```
20 | curl -Ss https://raw.githubusercontent.com/vim-php/phpctags/gh-pages/install/phpctags.phar > phpctags
21 | chmod +x phpctags
22 | ```
23 |
24 | Optionally one can move it into a directory on the `$PATH`:
25 |
26 | ```
27 | sudo mv phpctags /usr/local/bin/
28 | ```
29 |
30 | ## Usage
31 |
32 | Single file:
33 |
34 | ```
35 | phpctags phpfile.php
36 | ```
37 |
38 | Tags will be written to a `tags` file. In order to specify a different tags file
39 | use the `-f` option:
40 |
41 | ```
42 | phpctags -f myphp.tags phpfile.php
43 | ```
44 |
45 | Directory with recursive option:
46 |
47 | ```
48 | phpctags -f myphp.tags -R target_directory
49 | ```
50 |
51 | ## Build
52 |
53 | > We currently only support building PHAR executable for \*nix like platform
54 | > which provides `make` utility. If you are interested in building an executable
55 | > for other platform, especially for Windows, please help yourself out. It
56 | > should be easy though (Apologize for not being able to provide any help for
57 | > this, I am really not a Windows guy), it also would be great if someone could
58 | > provide a patch for this.
59 |
60 | Installation is straightforward, make sure you have PHP's PHAR extension enabled,
61 | then run `make` in the root directory of the source, you will get a `phpctags`
62 | PHAR executable, add it to your `$PATH`, then you can invoke `phpctags`
63 | directly from anywhere.
64 |
65 | See [phpctags on packagist](http://packagist.org/packages/techlivezheng/phpctags)
66 | for more details.
67 |
68 | Requirements
69 | ------------
70 |
71 | * PHP CLI 7.4+
72 | * [PHP-Parser](https://github.com/nikic/PHP-Parser)
73 |
74 | Acknowledgements
75 | ----------------
76 |
77 | * [Snapi](https://github.com/sanpii) for composer support.
78 | * [DeMarko](https://github.com/DeMarko) for memory limit support.
79 | * [Sander Marechal](https://github.com/sandermarechal) for improve console support.
80 | * [Mark Wu](https://github.com/markwu) for building a stand-alone PHAR executable.
81 | * [InFog](https://github.com/InFog) for maintaining the project since 2019.
82 |
--------------------------------------------------------------------------------
/tests/Acceptance/InterfacesTest.php:
--------------------------------------------------------------------------------
1 | givenSourceFile('InterfaceExample.php', <<<'EOS'
13 | runPHPCtags();
25 |
26 | $this->assertTagsFileHeaderIsCorrect();
27 | $this->assertNumberOfTagsInTagsFileIs(3);
28 | $this->assertTagsFileContainsTag(
29 | 'InterfaceExample.php',
30 | 'TestInterface',
31 | self::KIND_INTERFACE,
32 | 3
33 | );
34 | $this->assertTagsFileContainsTag(
35 | 'InterfaceExample.php',
36 | 'publicProperty',
37 | self::KIND_PROPERTY,
38 | 5,
39 | 'interface:TestInterface',
40 | 'public'
41 | );
42 | $this->assertTagsFileContainsTag(
43 | 'InterfaceExample.php',
44 | 'publicMethod',
45 | self::KIND_METHOD,
46 | 7,
47 | 'interface:TestInterface',
48 | 'public'
49 | );
50 | }
51 |
52 | /**
53 | * @test
54 | */
55 | public function itAddsNamespacesToInterfaceTags()
56 | {
57 | $this->givenSourceFile('MultiLevelNamespace.php', <<<'EOS'
58 | runPHPCtags();
72 |
73 | $this->assertTagsFileHeaderIsCorrect();
74 | $this->assertNumberOfTagsInTagsFileIs(4);
75 | $this->assertTagsFileContainsTag(
76 | 'MultiLevelNamespace.php',
77 | 'Level1\Level2',
78 | self::KIND_NAMESPACE,
79 | 3
80 | );
81 | $this->assertTagsFileContainsTag(
82 | 'MultiLevelNamespace.php',
83 | 'TestInterface',
84 | self::KIND_INTERFACE,
85 | 5,
86 | 'namespace:Level1\Level2'
87 | );
88 | $this->markTestIncomplete('Interface tag scopes are not fully qualified yet.');
89 | $this->assertTagsFileContainsTag(
90 | 'MultiLevelNamespace.php',
91 | 'testProperty',
92 | self::KIND_PROPERTY,
93 | 7,
94 | 'interface:Level1\Level2\TestInterface',
95 | 'public'
96 | );
97 | $this->assertTagsFileContainsTag(
98 | 'MultiLevelNamespace.php',
99 | 'setProperty',
100 | self::KIND_METHOD,
101 | 9,
102 | 'interface:Level1\Level2\TestInterface',
103 | 'public'
104 | );
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/tests/Acceptance/VariablesTest.php:
--------------------------------------------------------------------------------
1 | givenSourceFile('SingleVarExample.php', <<<'EOS'
13 | runPHPCtags();
20 |
21 | $this->assertTagsFileHeaderIsCorrect();
22 | $this->assertNumberOfTagsInTagsFileIs(1);
23 | $this->assertTagsFileContainsTag(
24 | 'SingleVarExample.php',
25 | 'var',
26 | self::KIND_VARIABLE,
27 | 3
28 | );
29 | }
30 |
31 | /**
32 | * @test
33 | */
34 | public function itCreatesTagForNamespacedVariables()
35 | {
36 | $this->givenSourceFile('NamespacedVariables.php', <<<'EOS'
37 | runPHPCtags();
46 |
47 | $this->assertTagsFileHeaderIsCorrect();
48 | $this->assertNumberOfTagsInTagsFileIs(2);
49 | $this->assertTagsFileContainsTag(
50 | 'NamespacedVariables.php',
51 | 'var',
52 | self::KIND_VARIABLE,
53 | 5,
54 | 'namespace:Level1\Level2'
55 | );
56 | }
57 |
58 | /**
59 | * @test
60 | */
61 | public function itCreatesTagForLocalVariableInsideFunction()
62 | {
63 | $this->givenSourceFile('LocalVariable.php', <<<'EOS'
64 | runPHPCtags();
74 |
75 | $this->assertTagsFileHeaderIsCorrect();
76 | $this->assertNumberOfTagsInTagsFileIs(2);
77 | $this->assertTagsFileContainsTag(
78 | 'LocalVariable.php',
79 | 'var',
80 | self::KIND_VARIABLE,
81 | 5,
82 | 'function:testFunction'
83 | );
84 | }
85 |
86 | /**
87 | * @test
88 | */
89 | public function itCreatesTagForLocalVariableInsideClassMethod()
90 | {
91 | $this->givenSourceFile('MethodVariable.php', <<<'EOS'
92 | runPHPCtags();
105 |
106 | $this->assertTagsFileHeaderIsCorrect();
107 | $this->assertNumberOfTagsInTagsFileIs(3);
108 | $this->assertTagsFileContainsTag(
109 | 'MethodVariable.php',
110 | 'var',
111 | self::KIND_VARIABLE,
112 | 7,
113 | 'method:TestClass::testMethod'
114 | );
115 | }
116 |
117 | /**
118 | * @test
119 | */
120 | public function itCreatesTagForVariablesInTryCatchBlocks()
121 | {
122 | $this->givenSourceFile('VariableInTryBlock.php', <<<'EOS'
123 | export($file, $options);
127 | } catch (Exception $e) {
128 | die("phpctags: {$e->getMessage()}");
129 | }
130 | EOS
131 | );
132 |
133 | $this->runPHPCtags();
134 |
135 | $this->assertTagsFileHeaderIsCorrect();
136 | $this->assertNumberOfTagsInTagsFileIs(2);
137 | $this->assertTagsFileContainsTag(
138 | 'VariableInTryBlock.php',
139 | 'ctags',
140 | self::KIND_VARIABLE,
141 | 3
142 | );
143 | $this->assertTagsFileContainsTag(
144 | 'VariableInTryBlock.php',
145 | 'result',
146 | self::KIND_VARIABLE,
147 | 4
148 | );
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/tests/Acceptance/TraitsTest.php:
--------------------------------------------------------------------------------
1 | ')) {
13 | $this->markTestSkipped('Traits were not introduced until 5.4');
14 | }
15 |
16 | $this->givenSourceFile('TopLevelTraitExample.php', <<<'EOS'
17 | runPHPCtags();
41 |
42 | $this->assertTagsFileHeaderIsCorrect();
43 | $this->assertNumberOfTagsInTagsFileIs(7);
44 | $this->assertTagsFileContainsTag(
45 | 'TopLevelTraitExample.php',
46 | 'TestTrait',
47 | self::KIND_TRAIT,
48 | 3
49 | );
50 | $this->assertTagsFileContainsTag(
51 | 'TopLevelTraitExample.php',
52 | 'publicProperty',
53 | self::KIND_PROPERTY,
54 | 5,
55 | 'trait:TestTrait',
56 | 'public'
57 | );
58 | $this->assertTagsFileContainsTag(
59 | 'TopLevelTraitExample.php',
60 | 'protectedProperty',
61 | self::KIND_PROPERTY,
62 | 6,
63 | 'trait:TestTrait',
64 | 'protected'
65 | );
66 | $this->assertTagsFileContainsTag(
67 | 'TopLevelTraitExample.php',
68 | 'privateProperty',
69 | self::KIND_PROPERTY,
70 | 7,
71 | 'trait:TestTrait',
72 | 'private'
73 | );
74 | $this->assertTagsFileContainsTag(
75 | 'TopLevelTraitExample.php',
76 | 'publicMethod',
77 | self::KIND_METHOD,
78 | 9,
79 | 'trait:TestTrait',
80 | 'public'
81 | );
82 | $this->assertTagsFileContainsTag(
83 | 'TopLevelTraitExample.php',
84 | 'protectedMethod',
85 | self::KIND_METHOD,
86 | 13,
87 | 'trait:TestTrait',
88 | 'protected'
89 | );
90 | $this->assertTagsFileContainsTag(
91 | 'TopLevelTraitExample.php',
92 | 'privateMethod',
93 | self::KIND_METHOD,
94 | 17,
95 | 'trait:TestTrait',
96 | 'private'
97 | );
98 | }
99 |
100 | /**
101 | * @test
102 | */
103 | public function itAddsNamespacesToTraitTags()
104 | {
105 | if (version_compare('5.4.0', PHP_VERSION, '>')) {
106 | $this->markTestSkipped('Traits were not introduced until 5.4');
107 | }
108 |
109 | $this->givenSourceFile('MultiLevelNamespace.php', <<<'EOS'
110 | testProperty = $value;
121 | }
122 | }
123 | EOS
124 | );
125 |
126 | $this->runPHPCtags();
127 |
128 | $this->assertTagsFileHeaderIsCorrect();
129 | $this->markTestIncomplete('Surely $this->varname shouldn\'t tag varname');
130 | $this->assertNumberOfTagsInTagsFileIs(4);
131 | $this->assertTagsFileContainsTag(
132 | 'MultiLevelNamespace.php',
133 | 'Level1\Level2',
134 | self::KIND_NAMESPACE,
135 | 3
136 | );
137 | $this->assertTagsFileContainsTag(
138 | 'MultiLevelNamespace.php',
139 | 'TestTrait',
140 | self::KIND_CLASS,
141 | 5,
142 | 'namespace:Level1\Level2'
143 | );
144 | $this->assertTagsFileContainsTag(
145 | 'MultiLevelNamespace.php',
146 | 'testProperty',
147 | self::KIND_PROPERTY,
148 | 7,
149 | 'trait:Level1\Level2\TestTrait',
150 | 'private'
151 | );
152 | $this->assertTagsFileContainsTag(
153 | 'MultiLevelNamespace.php',
154 | 'setProperty',
155 | self::KIND_METHOD,
156 | 9,
157 | 'trait:Level1\Level2\TestTrait',
158 | 'public'
159 | );
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/tests/Acceptance/ClassesTest.php:
--------------------------------------------------------------------------------
1 | givenSourceFile('TopLevelClassExample.php', <<<'EOS'
13 | runPHPCtags();
37 |
38 | $this->assertTagsFileHeaderIsCorrect();
39 | $this->assertNumberOfTagsInTagsFileIs(7);
40 | $this->assertTagsFileContainsTag(
41 | 'TopLevelClassExample.php',
42 | 'TestClass',
43 | self::KIND_CLASS,
44 | 3
45 | );
46 | $this->assertTagsFileContainsTag(
47 | 'TopLevelClassExample.php',
48 | 'publicProperty',
49 | self::KIND_PROPERTY,
50 | 5,
51 | 'class:TestClass',
52 | 'public'
53 | );
54 | $this->assertTagsFileContainsTag(
55 | 'TopLevelClassExample.php',
56 | 'protectedProperty',
57 | self::KIND_PROPERTY,
58 | 6,
59 | 'class:TestClass',
60 | 'protected'
61 | );
62 | $this->assertTagsFileContainsTag(
63 | 'TopLevelClassExample.php',
64 | 'privateProperty',
65 | self::KIND_PROPERTY,
66 | 7,
67 | 'class:TestClass',
68 | 'private'
69 | );
70 | $this->assertTagsFileContainsTag(
71 | 'TopLevelClassExample.php',
72 | 'publicMethod',
73 | self::KIND_METHOD,
74 | 9,
75 | 'class:TestClass',
76 | 'public'
77 | );
78 | $this->assertTagsFileContainsTag(
79 | 'TopLevelClassExample.php',
80 | 'protectedMethod',
81 | self::KIND_METHOD,
82 | 13,
83 | 'class:TestClass',
84 | 'protected'
85 | );
86 | $this->assertTagsFileContainsTag(
87 | 'TopLevelClassExample.php',
88 | 'privateMethod',
89 | self::KIND_METHOD,
90 | 17,
91 | 'class:TestClass',
92 | 'private'
93 | );
94 | }
95 |
96 | /**
97 | * @test
98 | */
99 | public function itAddsNamespacesToClassTags()
100 | {
101 | $this->givenSourceFile('MultiLevelNamespace.php', <<<'EOS'
102 | testProperty = $value;
113 | }
114 | }
115 | EOS
116 | );
117 |
118 | $this->runPHPCtags();
119 |
120 | $this->assertTagsFileHeaderIsCorrect();
121 | $this->markTestIncomplete('Surely $this->varname shouldn\'t tag varname');
122 | $this->assertNumberOfTagsInTagsFileIs(4);
123 | $this->assertTagsFileContainsTag(
124 | 'MultiLevelNamespace.php',
125 | 'Level1\Level2',
126 | self::KIND_NAMESPACE,
127 | 3
128 | );
129 | $this->assertTagsFileContainsTag(
130 | 'MultiLevelNamespace.php',
131 | 'TestClass',
132 | self::KIND_CLASS,
133 | 5,
134 | 'namespace:Level1\Level2'
135 | );
136 | $this->assertTagsFileContainsTag(
137 | 'MultiLevelNamespace.php',
138 | 'testProperty',
139 | self::KIND_PROPERTY,
140 | 7,
141 | 'class:Level1\Level2\TestClass',
142 | 'private'
143 | );
144 | $this->assertTagsFileContainsTag(
145 | 'MultiLevelNamespace.php',
146 | 'setProperty',
147 | self::KIND_METHOD,
148 | 9,
149 | 'class:Level1\Level2\TestClass',
150 | 'public'
151 | );
152 | }
153 |
154 | /**
155 | * @test
156 | * @group bugfix3
157 | */
158 | public function itTagsMagicMethods()
159 | {
160 | $this->givenSourceFile('DbConnectionUserDecorator.php', <<<'EOS'
161 | conn->$key = $value;
165 | }
166 | }
167 | EOS
168 | );
169 |
170 | $this->runPHPCtags();
171 |
172 | $this->assertTagsFileHeaderIsCorrect();
173 | $this->assertNumberOfTagsInTagsFileIs(2);
174 | $this->assertTagsFileContainsTag(
175 | 'DbConnectionUserDecorator.php',
176 | 'DbConnectionUserDecorator',
177 | self::KIND_CLASS,
178 | 2
179 | );
180 | $this->assertTagsFileContainsTag(
181 | 'DbConnectionUserDecorator.php',
182 | '__set',
183 | self::KIND_METHOD,
184 | 3,
185 | 'class:DbConnectionUserDecorator',
186 | 'public'
187 | );
188 | }
189 |
190 | /**
191 | * @test
192 | * @group bugfix7
193 | */
194 | public function itTagsClassInsideConditional()
195 | {
196 | $this->givenSourceFile('MultiLevelNamespace.php', <<<'EOS'
197 | runPHPCtags();
206 |
207 | $this->assertTagsFileHeaderIsCorrect();
208 | $this->assertNumberOfTagsInTagsFileIs(1);
209 | $this->assertTagsFileContainsTag(
210 | 'MultiLevelNamespace.php',
211 | 'MyClass',
212 | self::KIND_CLASS,
213 | 3
214 | );
215 | }
216 | }
217 |
--------------------------------------------------------------------------------
/tests/Acceptance/KindsTest.php:
--------------------------------------------------------------------------------
1 | givenSourceFile('KindsExample.php', $sourceCode);
56 | }
57 |
58 | /**
59 | * @test
60 | */
61 | public function itSupportsClassKindParameter()
62 | {
63 | $this->runPHPCtagsWithKinds('c');
64 |
65 | $this->assertTagsFileHeaderIsCorrect();
66 | $this->assertNumberOfTagsInTagsFileIs(1);
67 |
68 | $this->assertTagsFileContainsTag(
69 | 'KindsExample.php',
70 | 'KindsExampleClass',
71 | self::KIND_CLASS,
72 | 3,
73 | 'namespace:KindsExampleNamespace'
74 | );
75 | }
76 |
77 | /**
78 | * @test
79 | */
80 | public function itSupportsPropertyKindParameter()
81 | {
82 | $this->runPHPCtagsWithKinds('p');
83 |
84 | $this->assertTagsFileHeaderIsCorrect();
85 | $this->assertNumberOfTagsInTagsFileIs(3);
86 |
87 | $this->assertTagsFileContainsTag(
88 | 'KindsExample.php',
89 | 'publicProperty',
90 | self::KIND_PROPERTY,
91 | 5,
92 | 'class:KindsExampleNamespace\KindsExampleClass',
93 | 'public'
94 | );
95 | $this->assertTagsFileContainsTag(
96 | 'KindsExample.php',
97 | 'protectedProperty',
98 | self::KIND_PROPERTY,
99 | 6,
100 | 'class:KindsExampleNamespace\KindsExampleClass',
101 | 'protected'
102 | );
103 | $this->assertTagsFileContainsTag(
104 | 'KindsExample.php',
105 | 'privateProperty',
106 | self::KIND_PROPERTY,
107 | 7,
108 | 'class:KindsExampleNamespace\KindsExampleClass',
109 | 'private'
110 | );
111 | }
112 |
113 | /**
114 | * @test
115 | */
116 | public function itSupportsMethodKindParameter()
117 | {
118 | $this->runPHPCtagsWithKinds('m');
119 |
120 | $this->assertTagsFileHeaderIsCorrect();
121 | $this->assertNumberOfTagsInTagsFileIs(3);
122 |
123 | $this->assertTagsFileContainsTag(
124 | 'KindsExample.php',
125 | 'publicMethod',
126 | self::KIND_METHOD,
127 | 9,
128 | 'class:KindsExampleNamespace\KindsExampleClass',
129 | 'public'
130 | );
131 | $this->assertTagsFileContainsTag(
132 | 'KindsExample.php',
133 | 'protectedMethod',
134 | self::KIND_METHOD,
135 | 13,
136 | 'class:KindsExampleNamespace\KindsExampleClass',
137 | 'protected'
138 | );
139 | $this->assertTagsFileContainsTag(
140 | 'KindsExample.php',
141 | 'privateMethod',
142 | self::KIND_METHOD,
143 | 17,
144 | 'class:KindsExampleNamespace\KindsExampleClass',
145 | 'private'
146 | );
147 | }
148 |
149 | /**
150 | * @test
151 | */
152 | public function itSupportsFunctionKindParameter()
153 | {
154 | $this->runPHPCtagsWithKinds('f');
155 |
156 | $this->assertTagsFileHeaderIsCorrect();
157 | $this->assertNumberOfTagsInTagsFileIs(1);
158 |
159 | $this->assertTagsFileContainsTag(
160 | 'KindsExample.php',
161 | 'kindsExampleFunction',
162 | self::KIND_FUNCTION,
163 | 22,
164 | 'namespace:KindsExampleNamespace'
165 | );
166 | }
167 |
168 | /**
169 | * @test
170 | */
171 | public function itSupportsConstantKindsParameter()
172 | {
173 | $this->runPHPCtagsWithKinds('d');
174 |
175 | $this->assertTagsFileHeaderIsCorrect();
176 | $this->assertNumberOfTagsInTagsFileIs(2);
177 | $this->assertTagsFileContainsTag(
178 | 'KindsExample.php',
179 | 'CONSTANT_1',
180 | self::KIND_CONSTANT,
181 | 26,
182 | 'namespace:KindsExampleNamespace'
183 | );
184 | $this->assertTagsFileContainsTag(
185 | 'KindsExample.php',
186 | 'CONSTANT_2',
187 | self::KIND_CONSTANT,
188 | 27,
189 | 'namespace:KindsExampleNamespace'
190 | );
191 | }
192 |
193 | /**
194 | * @test
195 | */
196 | public function itSupportsVariableKindsParameter()
197 | {
198 | $this->runPHPCtagsWithKinds('v');
199 |
200 | $this->assertTagsFileHeaderIsCorrect();
201 | $this->assertNumberOfTagsInTagsFileIs(1);
202 | $this->assertTagsFileContainsTag(
203 | 'KindsExample.php',
204 | 'var',
205 | self::KIND_VARIABLE,
206 | 29,
207 | 'namespace:KindsExampleNamespace'
208 | );
209 | }
210 |
211 | /**
212 | * @test
213 | */
214 | public function itSupportsNamespaceKindsParameter()
215 | {
216 | $this->runPHPCtagsWithKinds('n');
217 |
218 | $this->assertTagsFileHeaderIsCorrect();
219 | $this->assertNumberOfTagsInTagsFileIs(1);
220 | $this->assertTagsFileContainsTag(
221 | 'KindsExample.php',
222 | 'KindsExampleNamespace',
223 | self::KIND_NAMESPACE,
224 | 2
225 | );
226 | }
227 |
228 | /**
229 | * @test
230 | */
231 | public function itSupportsInterfaceKindsParameter()
232 | {
233 | $this->runPHPCtagsWithKinds('i');
234 |
235 | $this->assertTagsFileHeaderIsCorrect();
236 | $this->assertNumberOfTagsInTagsFileIs(1);
237 | $this->assertTagsFileContainsTag(
238 | 'KindsExample.php',
239 | 'KindsExampleInterface',
240 | self::KIND_INTERFACE,
241 | 31,
242 | 'namespace:KindsExampleNamespace'
243 | );
244 | }
245 |
246 | /**
247 | * @test
248 | */
249 | public function itSupportsTraitKindsParameter()
250 | {
251 | if (version_compare('5.4.0', PHP_VERSION, '>')) {
252 | $this->markTestSkipped('Traits were not introduced until 5.4');
253 | }
254 |
255 | $this->runPHPCtagsWithKinds('t');
256 |
257 | $this->assertTagsFileHeaderIsCorrect();
258 | $this->assertNumberOfTagsInTagsFileIs(1);
259 | $this->assertTagsFileContainsTag(
260 | 'KindsExample.php',
261 | 'KindsExampleTrait',
262 | self::KIND_TRAIT,
263 | 33,
264 | 'namespace:KindsExampleNamespace'
265 | );
266 | }
267 | }
268 |
--------------------------------------------------------------------------------
/tests/Acceptance/AcceptanceTestCase.php:
--------------------------------------------------------------------------------
1 | \t\t/^$/;\"\t\tline:\t\t";
13 |
14 | const KIND_TRAIT = 't';
15 | const KIND_CLASS = 'c';
16 | const KIND_METHOD = 'm';
17 | const KIND_FUNCTION = 'f';
18 | const KIND_PROPERTY = 'p';
19 | const KIND_CONSTANT = 'd';
20 | const KIND_VARIABLE = 'v';
21 | const KIND_INTERFACE = 'i';
22 | const KIND_NAMESPACE = 'n';
23 |
24 | /**
25 | * @var string
26 | */
27 | private $testDir;
28 |
29 | /**
30 | * @var string
31 | */
32 | private $tagsFileContent;
33 |
34 | protected function setUp(): void
35 | {
36 | $this->testDir = __DIR__ . '/../../.test_fs';
37 |
38 | if (!file_exists($this->testDir)) {
39 | mkdir($this->testDir);
40 | }
41 |
42 | $this->testDir = realpath($this->testDir);
43 |
44 | $this->emptyTestDir();
45 | }
46 |
47 | /**
48 | * @param string $filename
49 | * @param string $content
50 | *
51 | * @return void
52 | */
53 | protected function givenSourceFile($filename, $content)
54 | {
55 | $filename = $this->testDir . DIRECTORY_SEPARATOR . $filename;
56 |
57 | file_put_contents($filename, $content);
58 | }
59 |
60 | protected function givenDirectory($dirname)
61 | {
62 | $dirname = $this->testDir . DIRECTORY_SEPARATOR . $dirname;
63 |
64 | mkdir($dirname);
65 | }
66 |
67 | protected function givenMode($file, $mode)
68 | {
69 | $file = $this->testDir . DIRECTORY_SEPARATOR . $file;
70 |
71 | chmod($file, $mode);
72 | }
73 |
74 | /**
75 | * @return void
76 | */
77 | protected function runPHPCtags(array $params = array())
78 | {
79 | $entryPoint = realpath(__DIR__ . '/../../bootstrap.php');
80 |
81 | $params = implode(' ', $params);
82 |
83 | exec("php \"$entryPoint\" --recurse=yes $params -f - {$this->testDir}", $output);
84 |
85 | $this->tagsFileContent = $output;
86 | }
87 |
88 | protected function runPHPCtagsWithKinds($kindString)
89 | {
90 | $this->runPHPCtags(array("--kinds=$kindString"));
91 | }
92 |
93 | /**
94 | * @param string $patterns
95 | *
96 | * @return void
97 | */
98 | protected function runPHPCtagsWithExcludes(array $patterns)
99 | {
100 | $entryPoint = realpath(__DIR__ . '/../../bootstrap.php');
101 |
102 | $excludes = implode(
103 | ' ',
104 | array_map(function ($pattern) {
105 | return '--exclude=\'' . $pattern . '\'';
106 | }, $patterns)
107 | );
108 |
109 | exec("php \"$entryPoint\" --recurse=yes -f - $excludes {$this->testDir}", $output);
110 |
111 | $this->tagsFileContent = $output;
112 | }
113 |
114 | /**
115 | * @return void
116 | */
117 | protected function assertTagsFileHeaderIsCorrect()
118 | {
119 | $expectedHeader = array(
120 | "!_TAG_FILE_FORMAT\t2\t/extended format; --format=1 will not append ;\" to lines/",
121 | "!_TAG_FILE_SORTED\t1\t/0=unsorted, 1=sorted, 2=foldcase/",
122 | "!_TAG_PROGRAM_AUTHOR\ttechlivezheng\t/techlivezheng@gmail.com/",
123 | "!_TAG_PROGRAM_NAME\tphpctags\t//",
124 | "!_TAG_PROGRAM_URL\thttps://github.com/techlivezheng/phpctags\t/official site/",
125 | "!_TAG_PROGRAM_VERSION\t0.10.0\t//",
126 | );
127 |
128 | $realHeader = array_splice($this->tagsFileContent, 0, count($expectedHeader));
129 |
130 | $this->assertEquals($expectedHeader, $realHeader, 'Tags file header is incorrect');
131 | }
132 |
133 | /**
134 | * @return void
135 | */
136 | protected function assertNumberOfTagsInTagsFileIs($count)
137 | {
138 | $this->assertCount(
139 | $count,
140 | $this->tagsFileContent,
141 | 'Tags file contains the wrong number of tags'
142 | );
143 | }
144 |
145 | /**
146 | * @param string $filename
147 | * @param string $name
148 | * @param string $kind
149 | * @param int $line
150 | * @param string $scope
151 | * @param string $access
152 | *
153 | * @return void
154 | */
155 | protected function assertTagsFileContainsTag(
156 | $filename,
157 | $name,
158 | $kind,
159 | $line,
160 | $scope = '',
161 | $access = ''
162 | ) {
163 | $this->assertContains(
164 | $this->createTagLine($filename, $name, $kind, $line, $scope, $access),
165 | $this->tagsFileContent,
166 | "Tag file content:\n" . print_r($this->tagsFileContent, true)
167 | );
168 | }
169 |
170 |
171 | /**
172 | * @param string $filename
173 | *
174 | * @return void
175 | */
176 | public function assertTagsFileContainsNoTagsFromFile($filename)
177 | {
178 | $filename = $this->testDir . DIRECTORY_SEPARATOR . $filename;
179 |
180 | $tags = array_filter(
181 | $this->tagsFileContent,
182 | function ($line) use ($filename) {
183 | $fields = explode("\t", $line);
184 |
185 | return $fields[1] === $filename;
186 | }
187 | );
188 |
189 | $this->assertEmpty($tags, "Tags for $filename were found in tag file.");
190 | }
191 |
192 | /**
193 | * @return void
194 | */
195 | private function emptyTestDir()
196 | {
197 | if (empty($this->testDir)) {
198 | throw \RuntimeException('Test directory does not exist');
199 | }
200 |
201 | foreach (glob($this->testDir . DIRECTORY_SEPARATOR . '*') as $file) {
202 | chmod($file, 0755);
203 | }
204 |
205 | $files = new RecursiveIteratorIterator(
206 | new RecursiveDirectoryIterator(
207 | $this->testDir,
208 | RecursiveDirectoryIterator::SKIP_DOTS
209 | ),
210 | RecursiveIteratorIterator::CHILD_FIRST
211 | );
212 |
213 | foreach ($files as $fileinfo) {
214 | if ($fileinfo->isDir()) {
215 | rmdir($fileinfo->getRealPath());
216 | } else {
217 | unlink($fileinfo->getRealPath());
218 | }
219 | }
220 | }
221 |
222 | /**
223 | * @param string $filename
224 | * @param string $name
225 | * @param string $kind
226 | * @param int $line
227 | * @param string $scope
228 | * @param string $access
229 | *
230 | * @return string
231 | */
232 | private function createTagLine($filename, $name, $kind, $line, $scope, $access)
233 | {
234 | $kinds = array(
235 | self::KIND_TRAIT => 'trait',
236 | self::KIND_CLASS => 'class',
237 | self::KIND_METHOD => 'method',
238 | self::KIND_FUNCTION => 'function',
239 | self::KIND_PROPERTY => 'property',
240 | self::KIND_CONSTANT => 'constant',
241 | self::KIND_VARIABLE => 'variable',
242 | self::KIND_INTERFACE => 'interface',
243 | self::KIND_NAMESPACE => 'namespace',
244 | );
245 |
246 | if(!empty($access)) {
247 | $access = 'access:' . $access;
248 | }
249 |
250 | $patterns = array(
251 | '//',
252 | '//',
253 | '//',
254 | '//',
255 | '//',
256 | '//',
257 | '//',
258 | '//'
259 | );
260 |
261 | $replacements = array(
262 | $name,
263 | $this->testDir . DIRECTORY_SEPARATOR . $filename,
264 | $this->getSourceFileLineContent($filename, $line),
265 | $kind,
266 | $kinds[$kind],
267 | $line,
268 | $scope,
269 | $access
270 | );
271 |
272 | $line = preg_replace($patterns, $replacements, self::FORMAT);
273 |
274 | return rtrim($line, "\t");
275 | }
276 |
277 | /**
278 | * @param string $filename
279 | * @param int $line
280 | *
281 | * @return string
282 | */
283 | private function getSourceFileLineContent($filename, $line)
284 | {
285 | $filename = $this->testDir . DIRECTORY_SEPARATOR . $filename;
286 | $line--;
287 | $file = file($filename);
288 | return rtrim($file[$line], PHP_EOL);
289 | }
290 | }
291 |
--------------------------------------------------------------------------------
/bootstrap.php:
--------------------------------------------------------------------------------
1 | , https://github.com/vim-php/phpctags
19 | EOF;
20 |
21 | $options = getopt('aC:f:Nno:RuV', array(
22 | 'append::',
23 | 'debug',
24 | 'exclude:',
25 | 'excmd::',
26 | 'fields::',
27 | 'kinds::',
28 | 'extensions::',
29 | 'format::',
30 | 'help',
31 | 'recurse::',
32 | 'sort::',
33 | 'verbose::',
34 | 'version',
35 | 'memory::',
36 | ));
37 |
38 | $options_info = <<<'EOF'
39 | phpctags currently only supports a subset of the original ctags' options.
40 |
41 | Usage: phpctags [options] [file(s)]
42 |
43 | -a Append the tags to an existing tag file.
44 | -f
45 | Write tags to specified file. Value of "-" writes tags to stdout
46 | ["tags"].
47 | -C
48 | Use a cache file to store tags for faster updates.
49 | -n Equivalent to --excmd=number.
50 | -N Equivalent to --excmd=pattern.
51 | -o Alternative for -f.
52 | -R Equivalent to --recurse.
53 | -u Equivalent to --sort=no.
54 | -V Equivalent to --verbose.
55 | --append=[yes|no]
56 | Should tags should be appended to existing tag file [no]?
57 | --debug
58 | phpctags only
59 | Repect PHP's error level configuration.
60 | --exclude=pattern
61 | Exclude files and directories matching 'pattern'.
62 | --excmd=number|pattern|mix
63 | Uses the specified type of EX command to locate tags [mix].
64 | --fields=[+|-]flags
65 | Include selected extension fields (flags: "afmikKlnsStz") [fks].
66 | --kinds=[+|-]flags
67 | Enable/disable tag kinds [cmfpvditn]
68 | --extensions=[+|-]extension[,[+|-]]extension
69 | Enable/disable file extensions [+.php,+.php3,+.php4,+.php5,+.phps]
70 | --format=level
71 | Force output of specified tag file format [2].
72 | --help
73 | Print this option summary.
74 | --memory=[-1|bytes|KMG]
75 | phpctags only
76 | Set how many memories phpctags could use.
77 | --recurse=[yes|no]
78 | Recurse into directories supplied on command line [no].
79 | --sort=[yes|no|foldcase]
80 | Should tags be sorted (optionally ignoring case) [yes]?.
81 | --verbose=[yes|no]
82 | Enable verbose messages describing actions on each source file.
83 | --version
84 | Print version identifier to standard output.
85 | EOF;
86 |
87 | // prune options and its value from the $argv array
88 | $argv_ = array();
89 |
90 | foreach ($options as $option => $value) {
91 | foreach ($argv as $key => $chunk) {
92 | $regex = '/^'. (isset($option[1]) ? '--' : '-') . $option . '/';
93 | if ($chunk == $value && $argv[$key-1][0] == '-' || preg_match($regex, $chunk)) {
94 | array_push($argv_, $key);
95 | }
96 | }
97 | }
98 | while ($key = array_pop($argv_)) unset($argv[$key]);
99 |
100 | // option -v is an alternative to --verbose
101 | if (isset($options['V'])) {
102 | $options['verbose'] = 'yes';
103 | }
104 |
105 | if (isset($options['verbose'])) {
106 | if ($options['verbose'] === FALSE || yes_or_no($options['verbose']) == 'yes') {
107 | $options['V'] = true;
108 | } else if (yes_or_no($options['verbose']) != 'no') {
109 | die('phpctags: Invalid value for "verbose" option'.PHP_EOL);
110 | } else {
111 | $options['V'] = false;
112 | }
113 | } else {
114 | $options['V'] = false;
115 | }
116 |
117 | if (isset($options['debug'])) {
118 | $options['debug'] = true;
119 | } else {
120 | error_reporting(0);
121 | }
122 |
123 | if (isset($options['help'])) {
124 | echo "Version: ".$version."\n\n".$copyright;
125 | echo PHP_EOL;
126 | echo PHP_EOL;
127 | echo $options_info;
128 | echo PHP_EOL;
129 | exit;
130 | }
131 |
132 | if (isset($options['version'])) {
133 | echo "Version: ".$version."\n\n".$copyright;
134 | echo PHP_EOL;
135 | exit;
136 | }
137 |
138 | array_shift($argv);
139 |
140 | // option -o is an alternative to -f
141 | if (isset($options['o']) && !isset($options['f'])) {
142 | $options['f'] = $options['o'];
143 | }
144 |
145 | // if both -n and -N options are given, use the last specified one
146 | if (isset($options['n']) && isset($options['N'])) {
147 | if (array_search('n', array_keys($options)) < array_search('N', array_keys($options))) {
148 | unset($options['n']);
149 | } else {
150 | unset($options['N']);
151 | }
152 | }
153 |
154 | // option -n is equivalent to --excmd=number
155 | if (isset($options['n']) && !isset($options['N'])) {
156 | $options['excmd'] = 'number';
157 | }
158 |
159 | // option -N is equivalent to --excmd=pattern
160 | if (isset($options['N']) && !isset($options['n'])) {
161 | $options['excmd'] = 'pattern';
162 | }
163 |
164 | if (!isset($options['excmd']))
165 | $options['excmd'] = 'pattern';
166 | if (!isset($options['format']))
167 | $options['format'] = 2;
168 | if (!isset($options['memory']))
169 | $options['memory'] = '128M';
170 |
171 | if (!isset($options['fields'])) {
172 | $options['fields'] = array('n', 'k', 's', 'a','i');
173 | } else {
174 | $options['fields'] = str_split($options['fields']);
175 | }
176 |
177 | if (!isset($options['kinds'])) {
178 | $options['kinds'] = array('c', 'm', 'f', 'p', 'd', 'v', 'i', 't', 'n');
179 | } else {
180 | $options['kinds'] = str_split($options['kinds']);
181 | }
182 |
183 | $default_extensions = array('.php', '.php3', '.php4', '.php5', '.phps');
184 | if (!isset($options['extensions'])) {
185 | $options['extensions'] = $default_extensions;
186 | } else {
187 | $extensions = explode(',', $options['extensions']);
188 | $options['extensions'] = $default_extensions;
189 | foreach ($extensions as $ext) {
190 | if ($ext[0] == '+') {
191 | $options['extensions'][] = substr($ext, 1);
192 | } elseif ($ext[0] == '-') {
193 | $options['extensions'] = array_diff($options['extensions'], array(substr($ext, 1)));
194 | } else {
195 | die('phpctags: Invalid value for "extensions" option ' . $ext . PHP_EOL);
196 | }
197 | }
198 | }
199 |
200 | // handle -u or --sort options
201 | if (isset($options['sort'])) {
202 | // --sort or --sort=[Y,y,YES,Yes,yes]
203 | if ($options['sort'] === FALSE || yes_or_no($options['sort']) == 'yes') {
204 | $options['sort'] = 'yes';
205 | // --sort=[N,n,NO,No,no]
206 | } else if (yes_or_no($options['sort']) == 'no') {
207 | $options['sort'] = 'no';
208 | // --sort=foldcase, case insensitive sorting
209 | } else if ($options['sort'] == 'foldcase') {
210 | $options['sort'] = 'foldcase';
211 | } else {
212 | die('phpctags: Invalid value for "sort" option'.PHP_EOL);
213 | }
214 | // option -n is equivalent to --sort=no
215 | } else if (isset($options['u'])) {
216 | $options['sort'] = 'no';
217 | // sort the result by default
218 | } else {
219 | $options['sort'] = 'yes';
220 | }
221 |
222 | // if the memory limit option is set and is valid, adjust memory
223 | if (isset($options['memory'])) {
224 | $memory_limit = trim($options['memory']);
225 | if (isMemoryLimitValid($memory_limit)) {
226 | ini_set('memory_limit', $memory_limit);
227 | }
228 | }
229 |
230 | if (isset($options['append'])) {
231 | if ($options['append'] === FALSE || yes_or_no($options['append']) == 'yes') {
232 | $options['a'] = FALSE;
233 | } else if (yes_or_no($options['append']) != 'no') {
234 | die('phpctags: Invalid value for "append" option'.PHP_EOL);
235 | }
236 | }
237 |
238 | if (isset($options['recurse'])) {
239 | if ($options['recurse'] === FALSE || yes_or_no($options['recurse']) == 'yes') {
240 | $options['R'] = FALSE;
241 | } else if (yes_or_no($options['recurse']) != 'no') {
242 | die('phpctags: Invalid value for "recurse" option'.PHP_EOL);
243 | }
244 | }
245 |
246 | // if option -R is given and no file is specified, use current working directory
247 | if (isset($options['R']) && empty($argv)) {
248 | $argv[] = getcwd();
249 | }
250 |
251 | try {
252 | $ctags = new PHPCtags($options);
253 | $ctags->addFiles($argv);
254 | $ctags->setCacheFile(isset($options['C']) ? $options['C'] : null);
255 | $result = $ctags->export();
256 | } catch (Exception $e) {
257 | die("phpctags: {$e->getMessage()}".PHP_EOL);
258 | }
259 |
260 | // write to a specified file
261 | if (isset($options['f']) && $options['f'] !== '-') {
262 | $tagfile = fopen($options['f'], isset($options['a']) ? 'a' : 'w');
263 | // write to stdout only when instructed
264 | } else if (isset($options['f']) && $options['f'] === '-') {
265 | $tagfile = fopen('php://stdout', 'w');
266 | // write to file 'tags' by default
267 | } else {
268 | $tagfile = fopen('tags', isset($options['a']) ? 'a' : 'w');
269 | }
270 |
271 | $mode = ($options['sort'] == 'yes' ? 1 : ($options['sort'] == 'foldcase' ? 2 : 0));
272 |
273 | if (!isset($options['a'])) {
274 | $tagline = << 0) {
302 | // memory limit provided in bytes
303 | return true;
304 | } elseif (preg_match("/\d+\s*[KMG]/", $memory_limit)) {
305 | // memory limit provided in human readable sizes
306 | // as specified here: http://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
307 | return true;
308 | }
309 |
310 | return false;
311 | }
312 |
--------------------------------------------------------------------------------
/PHPCtags.class.php:
--------------------------------------------------------------------------------
1 | 'trait',
16 | 'c' => 'class',
17 | 'm' => 'method',
18 | 'f' => 'function',
19 | 'p' => 'property',
20 | 'd' => 'constant',
21 | 'v' => 'variable',
22 | 'i' => 'interface',
23 | 'n' => 'namespace',
24 | );
25 |
26 | private $mParser;
27 | private $mLines;
28 | private $mOptions;
29 | private $tagdata;
30 | private $cachefile;
31 | private $filecount;
32 |
33 | public function __construct($options)
34 | {
35 | $this->mParser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
36 | $this->mLines = array();
37 | $this->mOptions = $options;
38 | $this->filecount = 0;
39 | }
40 |
41 | public function setMFile($file)
42 | {
43 | if (empty($file)) {
44 | throw new PHPCtagsException('No File specified.');
45 | }
46 |
47 | if (!file_exists($file)) {
48 | throw new PHPCtagsException('Warning: cannot open source file "' . $file . '" : No such file');
49 | }
50 |
51 | if (!is_readable($file)) {
52 | throw new PHPCtagsException('Warning: cannot open source file "' . $file . '" : File is not readable');
53 | }
54 |
55 | $this->mFile = realpath($file);
56 | }
57 |
58 | public static function getMKinds()
59 | {
60 | return self::$mKinds;
61 | }
62 |
63 | public function addFile($file)
64 | {
65 | $this->mFiles[realpath($file)] = 1;
66 | }
67 |
68 | public function setCacheFile($file) {
69 | $this->cachefile = $file;
70 | }
71 |
72 | public function addFiles($files)
73 | {
74 | foreach ($files as $file) {
75 | $this->addFile($file);
76 | }
77 | }
78 |
79 | private function getNodeAccess($node)
80 | {
81 | if ($node->isPrivate()) return 'private';
82 | if ($node->isProtected()) return 'protected';
83 | return 'public';
84 | }
85 |
86 | /**
87 | * stringSortByLine
88 | *
89 | * Sort a string based on its line delimiter
90 | *
91 | * @author Techlive Zheng
92 | *
93 | * @access public
94 | * @static
95 | *
96 | * @param string $str string to be sorted
97 | * @param boolean $foldcse case-insensitive sorting
98 | *
99 | * @return string sorted string
100 | **/
101 | public static function stringSortByLine($str, $foldcase=FALSE)
102 | {
103 | $arr = explode("\n", $str);
104 | if (!$foldcase)
105 | sort($arr, SORT_STRING);
106 | else
107 | sort($arr, SORT_STRING | SORT_FLAG_CASE);
108 | $str = implode("\n", $arr);
109 | return $str;
110 | }
111 |
112 | private static function helperSortByLine($a, $b)
113 | {
114 | return $a['line'] > $b['line'] ? 1 : 0;
115 | }
116 |
117 | private function struct($node, $reset=FALSE, $parent=array())
118 | {
119 | static $scope = array();
120 | static $structs = array();
121 |
122 | if ($reset) {
123 | $structs = array();
124 | }
125 |
126 | $kind = $name = $line = $access = $extends = '';
127 | $implements = array();
128 |
129 | if (!empty($parent)) array_push($scope, $parent);
130 |
131 | if (is_array($node)) {
132 | foreach ($node as $subNode) {
133 | $this->struct($subNode);
134 | }
135 | } elseif ($node instanceof Stmt\Expression) {
136 | foreach ($node as $subNode) {
137 | $this->struct($subNode);
138 | }
139 | } elseif ($node instanceof Stmt\Class_) {
140 | $kind = 'c';
141 | $name = $node->name;
142 | $extends = $node->extends;
143 | $implements = $node->implements;
144 | $line = $node->getLine();
145 | foreach ($node as $subNode) {
146 | $this->struct($subNode, FALSE, array('class' => $name));
147 | }
148 | } elseif ($node instanceof Stmt\Property) {
149 | $kind = 'p';
150 | $prop = $node->props[0];
151 | $name = $prop->name;
152 | $line = $prop->getLine();
153 | $access = $this->getNodeAccess($node);
154 | } elseif ($node instanceof Stmt\ClassConst) {
155 | $kind = 'd';
156 | $cons = $node->consts[0];
157 | $name = $cons->name;
158 | $line = $cons->getLine();
159 | } elseif ($node instanceof Stmt\ClassMethod) {
160 | $kind = 'm';
161 | $name = $node->name;
162 | $line = $node->getLine();
163 | $access = $this->getNodeAccess($node);
164 | foreach ($node as $subNode) {
165 | $this->struct($subNode, FALSE, array('method' => $name));
166 | }
167 | } elseif ($node instanceof Stmt\If_) {
168 | foreach ($node as $subNode) {
169 | $this->struct($subNode);
170 | }
171 | } elseif ($node instanceof Stmt\Const_) {
172 | $kind = 'd';
173 | $cons = $node->consts[0];
174 | $name = $cons->name;
175 | $line = $node->getLine();
176 | } elseif ($node instanceof Stmt\Global_) {
177 | $kind = 'v';
178 | $prop = $node->vars[0];
179 | $name = $prop->name;
180 | $line = $node->getLine();
181 | } elseif ($node instanceof Stmt\Static_) {
182 | //@todo
183 | } elseif ($node instanceof Stmt\Declare_) {
184 | //@todo
185 | } elseif ($node instanceof Stmt\TryCatch) {
186 | foreach ($node as $subNode) {
187 | $this->struct($subNode);
188 | }
189 | } elseif ($node instanceof Stmt\Function_) {
190 | $kind = 'f';
191 | $name = $node->name;
192 | $line = $node->getLine();
193 | foreach ($node as $subNode) {
194 | $this->struct($subNode, FALSE, array('function' => $name));
195 | }
196 | } elseif ($node instanceof Stmt\Interface_) {
197 | $kind = 'i';
198 | $name = $node->name;
199 | $line = $node->getLine();
200 | foreach ($node as $subNode) {
201 | $this->struct($subNode, FALSE, array('interface' => $name));
202 | }
203 | } elseif ($node instanceof Stmt\Trait_) {
204 | $kind = 't';
205 | $name = $node->name;
206 | $line = $node->getLine();
207 | foreach ($node as $subNode) {
208 | $this->struct($subNode, FALSE, array('trait' => $name));
209 | }
210 | } elseif ($node instanceof Stmt\Namespace_) {
211 | $kind = 'n';
212 | $name = $node->name;
213 | $line = $node->getLine();
214 | foreach ($node as $subNode) {
215 | $this->struct($subNode, FALSE, array('namespace' => $name));
216 | }
217 | } elseif ($node instanceof Expr\Assign) {
218 | if (isset($node->var->name) && is_string($node->var->name)) {
219 | $kind = 'v';
220 | $node = $node->var;
221 | $name = $node->name;
222 | $line = $node->getLine();
223 | }
224 | } elseif ($node instanceof Expr\AssignRef) {
225 | if (isset($node->var->name) && is_string($node->var->name)) {
226 | $kind = 'v';
227 | $node = $node->var;
228 | $name = $node->name;
229 | $line = $node->getLine();
230 | }
231 | } elseif ($node instanceof Expr\FuncCall) {
232 | switch ($node->name) {
233 | case 'define':
234 | $kind = 'd';
235 | $node = $node->args[0]->value;
236 | $name = $node->value;
237 | $line = $node->getLine();
238 | break;
239 | }
240 | } else {
241 | // we don't care the rest of them.
242 | }
243 |
244 | if (!empty($kind) && !empty($name) && !empty($line)) {
245 | $structs[] = array(
246 | 'file' => $this->mFile,
247 | 'kind' => $kind,
248 | 'name' => $name,
249 | 'extends' => $extends,
250 | 'implements' => $implements,
251 | 'line' => $line,
252 | 'scope' => $scope,
253 | 'access' => $access,
254 | );
255 | }
256 |
257 | if (!empty($parent)) array_pop($scope);
258 |
259 | // if no --sort is given, sort by occurrence
260 | if (!isset($this->mOptions['sort']) || $this->mOptions['sort'] == 'no') {
261 | usort($structs, 'self::helperSortByLine');
262 | }
263 |
264 | return $structs;
265 | }
266 |
267 | private function render($structure)
268 | {
269 | $str = '';
270 | foreach ($structure as $struct) {
271 | $file = $struct['file'];
272 |
273 | if (!in_array($struct['kind'], $this->mOptions['kinds'])) {
274 | continue;
275 | }
276 |
277 | if (!isset($files[$file]))
278 | $files[$file] = file($file);
279 |
280 | $lines = $files[$file];
281 |
282 | if (empty($struct['name']) || empty($struct['line']) || empty($struct['kind']))
283 | return;
284 |
285 | if ($struct['name'] instanceof Expr\Variable) {
286 | $str .= $struct['name']->name;
287 | }else{
288 | $str .= $struct['name'];
289 | }
290 |
291 | $str .= "\t" . $file;
292 |
293 | if ($this->mOptions['excmd'] == 'number') {
294 | $str .= "\t" . $struct['line'];
295 | } else { //excmd == 'mixed' or 'pattern', default behavior
296 | $str .= "\t" . "/^" . rtrim($lines[$struct['line'] - 1], "\n") . "$/";
297 | }
298 |
299 | if ($this->mOptions['format'] == 1) {
300 | $str .= "\n";
301 | continue;
302 | }
303 |
304 | $str .= ";\"";
305 |
306 | #field=k, kind of tag as single letter
307 | if (in_array('k', $this->mOptions['fields'])) {
308 | in_array('z', $this->mOptions['fields']) && $str .= "kind:";
309 | $str .= "\t" . $struct['kind'];
310 | } else
311 | #field=K, kind of tag as fullname
312 | if (in_array('K', $this->mOptions['fields'])) {
313 | in_array('z', $this->mOptions['fields']) && $str .= "kind:";
314 | $str .= "\t" . self::$mKinds[$struct['kind']];
315 | }
316 |
317 | #field=n
318 | if (in_array('n', $this->mOptions['fields'])) {
319 | $str .= "\t" . "line:" . $struct['line'];
320 | }
321 |
322 | #field=s
323 | if (in_array('s', $this->mOptions['fields']) && !empty($struct['scope'])) {
324 | // $scope, $type, $name are current scope variables
325 | $scope = array_pop($struct['scope']);
326 | $type = key($scope);
327 | $name = current($scope);
328 | switch ($type) {
329 | case 'class':
330 | // n_* stuffs are namespace related scope variables
331 | // current > class > namespace
332 | $n_scope = array_pop($struct['scope']);
333 | if(!empty($n_scope)) {
334 | $n_type = key($n_scope);
335 | $n_name = current($n_scope);
336 | $s_str = 'class:' . $n_name . '\\' . $name;
337 | } else {
338 | $s_str = 'class:' . $name;
339 | }
340 | break;
341 | case 'method':
342 | // c_* stuffs are class related scope variables
343 | // current > method > class > namespace
344 | $c_scope = array_pop($struct['scope']);
345 | $c_type = key($c_scope);
346 | $c_name = current($c_scope);
347 | $n_scope = array_pop($struct['scope']);
348 | if(!empty($n_scope)) {
349 | $n_type = key($n_scope);
350 | $n_name = current($n_scope);
351 | $s_str = 'method:' . $n_name . '\\' . $c_name . '::' . $name;
352 | } else {
353 | $s_str = 'method:' . $c_name . '::' . $name;
354 | }
355 | break;
356 | default:
357 | $s_str = $type . ':' . $name;
358 | break;
359 | }
360 | $str .= "\t" . $s_str;
361 | }
362 |
363 | #field=i
364 | if(in_array('i', $this->mOptions['fields'])) {
365 | $inherits = array();
366 | if(!empty($struct['extends'])) {
367 | $inherits[] = $struct['extends']->toString();
368 | }
369 | if(!empty($struct['implements'])) {
370 | foreach($struct['implements'] as $interface) {
371 | $inherits[] = $interface->toString();
372 | }
373 | }
374 | if(!empty($inherits))
375 | $str .= "\t" . 'inherits:' . implode(',', $inherits);
376 | }
377 |
378 | #field=a
379 | if (in_array('a', $this->mOptions['fields']) && !empty($struct['access'])) {
380 | $str .= "\t" . "access:" . $struct['access'];
381 | }
382 |
383 | $str .= "\n";
384 | }
385 |
386 | // remove the last line ending and carriage return
387 | $str = trim(str_replace("\x0D", "", $str));
388 |
389 | return $str;
390 | }
391 |
392 | private function full_render() {
393 | // Files will have been rendered already, just join and export.
394 |
395 | $str = '';
396 | foreach($this->mLines as $file => $data) {
397 | $str .= $data.PHP_EOL;
398 | }
399 |
400 | // sort the result as instructed
401 | if (isset($this->mOptions['sort']) && ($this->mOptions['sort'] == 'yes' || $this->mOptions['sort'] == 'foldcase')) {
402 | $str = self::stringSortByLine($str, $this->mOptions['sort'] == 'foldcase');
403 | }
404 |
405 | // Save all tag information to a file for faster updates if a cache file was specified.
406 | if (isset($this->cachefile)) {
407 | file_put_contents($this->cachefile, serialize($this->tagdata));
408 | if ($this->mOptions['V']) {
409 | echo "Saved cache file.".PHP_EOL;
410 | }
411 | }
412 |
413 | $str = trim($str);
414 |
415 | return $str;
416 | }
417 |
418 | public function export()
419 | {
420 | $start = microtime(true);
421 |
422 | if (empty($this->mFiles)) {
423 | throw new PHPCtagsException('No File specified.');
424 | }
425 |
426 | foreach (array_keys($this->mFiles) as $file) {
427 | $this->process($file);
428 | }
429 |
430 | $content = $this->full_render();
431 |
432 | $end = microtime(true);
433 |
434 | if ($this->mOptions['V']) {
435 | echo PHP_EOL."It took ".($end-$start)." seconds.".PHP_EOL;
436 | }
437 |
438 | return $content;
439 | }
440 |
441 | private function process($file)
442 | {
443 | // Load the tag md5 data to skip unchanged files.
444 | if (!isset($this->tagdata) && isset($this->cachefile) && file_exists(realpath($this->cachefile))) {
445 | if ($this->mOptions['V']) {
446 | echo "Loaded cache file.".PHP_EOL;
447 | }
448 | $this->tagdata = unserialize(file_get_contents(realpath($this->cachefile)));
449 | }
450 |
451 | if (is_dir($file) && isset($this->mOptions['R'])) {
452 | $iterator = new RecursiveIteratorIterator(
453 | new ReadableRecursiveDirectoryIterator(
454 | $file,
455 | FilesystemIterator::SKIP_DOTS |
456 | FilesystemIterator::FOLLOW_SYMLINKS
457 | )
458 | );
459 |
460 | $extensions = $this->mOptions['extensions'];
461 |
462 | foreach ($iterator as $filename) {
463 | if (!in_array(substr($filename, strrpos($filename, '.')), $extensions)) {
464 | continue;
465 | }
466 |
467 | // multiple --exclude options can be specified
468 | if (isset($this->mOptions['exclude'])) {
469 | $exclude = $this->mOptions['exclude'];
470 |
471 | if (is_array($exclude)) {
472 | foreach ($exclude as $item) {
473 | if (false !== strpos($filename, $item)) {
474 | continue 2;
475 | }
476 | }
477 | } elseif (false !== strpos($filename, $exclude)) {
478 | continue;
479 | }
480 | }
481 |
482 | try {
483 | $this->process_single_file($filename);
484 | } catch(Exception $e) {
485 | echo "PHPParser: {$e->getMessage()} - {$filename}".PHP_EOL;
486 | }
487 | }
488 | } else {
489 | try {
490 | $this->process_single_file($file);
491 | } catch(Exception $e) {
492 | echo "PHPParser: {$e->getMessage()} - {$file}".PHP_EOL;
493 | }
494 | }
495 | }
496 |
497 | private function process_single_file($filename)
498 | {
499 | if ($this->mOptions['V'] && $this->filecount > 1 && $this->filecount % 64 == 0) {
500 | echo " ".$this->filecount." files".PHP_EOL;
501 | }
502 | $this->filecount++;
503 | $startfile = microtime(true);
504 |
505 | $this->setMFile((string) $filename);
506 | $file = file_get_contents($this->mFile);
507 | $md5 = md5($file);
508 | if (isset($this->tagdata[$this->mFile][$md5])) {
509 | // The file is the same as the previous time we analyzed and saved.
510 | $this->mLines[$this->mFile] = $this->tagdata[$this->mFile][$md5];
511 | if ($this->mOptions['V']) {
512 | echo ".";
513 | }
514 | return;
515 | }
516 |
517 | $struct = $this->struct($this->mParser->parse($file), TRUE);
518 | $finishfile = microtime(true);
519 | $this->mLines[$this->mFile] = $this->render($struct);
520 | $finishmerge = microtime(true);
521 | $this->tagdata[$this->mFile][$md5] = $this->mLines[$this->mFile];
522 | if ($this->mOptions['debug']) {
523 | echo "Parse: ".($finishfile - $startfile).", Merge: ".($finishmerge-$finishfile)."; (".$this->filecount.")".$this->mFile.PHP_EOL;
524 | } else if ($this->mOptions['V']) {
525 | echo ".";
526 | }
527 | }
528 |
529 | }
530 |
531 | class PHPCtagsException extends Exception {
532 | public function __toString() {
533 | return "\nPHPCtags: {$this->message}\n";
534 | }
535 | }
536 |
537 | class ReadableRecursiveDirectoryIterator extends RecursiveDirectoryIterator {
538 | function getChildren() {
539 | try {
540 | return new ReadableRecursiveDirectoryIterator(
541 | $this->getPathname(),
542 | FilesystemIterator::SKIP_DOTS |
543 | FilesystemIterator::FOLLOW_SYMLINKS);
544 |
545 | } catch(UnexpectedValueException $e) {
546 | file_put_contents('php://stderr', "\nPHPPCtags: {$e->getMessage()} - {$this->getPathname()}\n");
547 | return new RecursiveArrayIterator(array());
548 | }
549 | }
550 | }
551 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "a18b5e09a8bb757cbcf44d908a56a119",
8 | "packages": [
9 | {
10 | "name": "nikic/php-parser",
11 | "version": "v5.4.0",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/nikic/PHP-Parser.git",
15 | "reference": "447a020a1f875a434d62f2a401f53b82a396e494"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494",
20 | "reference": "447a020a1f875a434d62f2a401f53b82a396e494",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "ext-ctype": "*",
25 | "ext-json": "*",
26 | "ext-tokenizer": "*",
27 | "php": ">=7.4"
28 | },
29 | "require-dev": {
30 | "ircmaxell/php-yacc": "^0.0.7",
31 | "phpunit/phpunit": "^9.0"
32 | },
33 | "bin": [
34 | "bin/php-parse"
35 | ],
36 | "type": "library",
37 | "extra": {
38 | "branch-alias": {
39 | "dev-master": "5.0-dev"
40 | }
41 | },
42 | "autoload": {
43 | "psr-4": {
44 | "PhpParser\\": "lib/PhpParser"
45 | }
46 | },
47 | "notification-url": "https://packagist.org/downloads/",
48 | "license": [
49 | "BSD-3-Clause"
50 | ],
51 | "authors": [
52 | {
53 | "name": "Nikita Popov"
54 | }
55 | ],
56 | "description": "A PHP parser written in PHP",
57 | "keywords": [
58 | "parser",
59 | "php"
60 | ],
61 | "support": {
62 | "issues": "https://github.com/nikic/PHP-Parser/issues",
63 | "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0"
64 | },
65 | "time": "2024-12-30T11:07:19+00:00"
66 | }
67 | ],
68 | "packages-dev": [
69 | {
70 | "name": "doctrine/instantiator",
71 | "version": "2.0.0",
72 | "source": {
73 | "type": "git",
74 | "url": "https://github.com/doctrine/instantiator.git",
75 | "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0"
76 | },
77 | "dist": {
78 | "type": "zip",
79 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
80 | "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
81 | "shasum": ""
82 | },
83 | "require": {
84 | "php": "^8.1"
85 | },
86 | "require-dev": {
87 | "doctrine/coding-standard": "^11",
88 | "ext-pdo": "*",
89 | "ext-phar": "*",
90 | "phpbench/phpbench": "^1.2",
91 | "phpstan/phpstan": "^1.9.4",
92 | "phpstan/phpstan-phpunit": "^1.3",
93 | "phpunit/phpunit": "^9.5.27",
94 | "vimeo/psalm": "^5.4"
95 | },
96 | "type": "library",
97 | "autoload": {
98 | "psr-4": {
99 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
100 | }
101 | },
102 | "notification-url": "https://packagist.org/downloads/",
103 | "license": [
104 | "MIT"
105 | ],
106 | "authors": [
107 | {
108 | "name": "Marco Pivetta",
109 | "email": "ocramius@gmail.com",
110 | "homepage": "https://ocramius.github.io/"
111 | }
112 | ],
113 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
114 | "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
115 | "keywords": [
116 | "constructor",
117 | "instantiate"
118 | ],
119 | "support": {
120 | "issues": "https://github.com/doctrine/instantiator/issues",
121 | "source": "https://github.com/doctrine/instantiator/tree/2.0.0"
122 | },
123 | "funding": [
124 | {
125 | "url": "https://www.doctrine-project.org/sponsorship.html",
126 | "type": "custom"
127 | },
128 | {
129 | "url": "https://www.patreon.com/phpdoctrine",
130 | "type": "patreon"
131 | },
132 | {
133 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
134 | "type": "tidelift"
135 | }
136 | ],
137 | "time": "2022-12-30T00:23:10+00:00"
138 | },
139 | {
140 | "name": "myclabs/deep-copy",
141 | "version": "1.13.0",
142 | "source": {
143 | "type": "git",
144 | "url": "https://github.com/myclabs/DeepCopy.git",
145 | "reference": "024473a478be9df5fdaca2c793f2232fe788e414"
146 | },
147 | "dist": {
148 | "type": "zip",
149 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414",
150 | "reference": "024473a478be9df5fdaca2c793f2232fe788e414",
151 | "shasum": ""
152 | },
153 | "require": {
154 | "php": "^7.1 || ^8.0"
155 | },
156 | "conflict": {
157 | "doctrine/collections": "<1.6.8",
158 | "doctrine/common": "<2.13.3 || >=3 <3.2.2"
159 | },
160 | "require-dev": {
161 | "doctrine/collections": "^1.6.8",
162 | "doctrine/common": "^2.13.3 || ^3.2.2",
163 | "phpspec/prophecy": "^1.10",
164 | "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
165 | },
166 | "type": "library",
167 | "autoload": {
168 | "files": [
169 | "src/DeepCopy/deep_copy.php"
170 | ],
171 | "psr-4": {
172 | "DeepCopy\\": "src/DeepCopy/"
173 | }
174 | },
175 | "notification-url": "https://packagist.org/downloads/",
176 | "license": [
177 | "MIT"
178 | ],
179 | "description": "Create deep copies (clones) of your objects",
180 | "keywords": [
181 | "clone",
182 | "copy",
183 | "duplicate",
184 | "object",
185 | "object graph"
186 | ],
187 | "support": {
188 | "issues": "https://github.com/myclabs/DeepCopy/issues",
189 | "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0"
190 | },
191 | "funding": [
192 | {
193 | "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
194 | "type": "tidelift"
195 | }
196 | ],
197 | "time": "2025-02-12T12:17:51+00:00"
198 | },
199 | {
200 | "name": "phar-io/manifest",
201 | "version": "2.0.4",
202 | "source": {
203 | "type": "git",
204 | "url": "https://github.com/phar-io/manifest.git",
205 | "reference": "54750ef60c58e43759730615a392c31c80e23176"
206 | },
207 | "dist": {
208 | "type": "zip",
209 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
210 | "reference": "54750ef60c58e43759730615a392c31c80e23176",
211 | "shasum": ""
212 | },
213 | "require": {
214 | "ext-dom": "*",
215 | "ext-libxml": "*",
216 | "ext-phar": "*",
217 | "ext-xmlwriter": "*",
218 | "phar-io/version": "^3.0.1",
219 | "php": "^7.2 || ^8.0"
220 | },
221 | "type": "library",
222 | "extra": {
223 | "branch-alias": {
224 | "dev-master": "2.0.x-dev"
225 | }
226 | },
227 | "autoload": {
228 | "classmap": [
229 | "src/"
230 | ]
231 | },
232 | "notification-url": "https://packagist.org/downloads/",
233 | "license": [
234 | "BSD-3-Clause"
235 | ],
236 | "authors": [
237 | {
238 | "name": "Arne Blankerts",
239 | "email": "arne@blankerts.de",
240 | "role": "Developer"
241 | },
242 | {
243 | "name": "Sebastian Heuer",
244 | "email": "sebastian@phpeople.de",
245 | "role": "Developer"
246 | },
247 | {
248 | "name": "Sebastian Bergmann",
249 | "email": "sebastian@phpunit.de",
250 | "role": "Developer"
251 | }
252 | ],
253 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
254 | "support": {
255 | "issues": "https://github.com/phar-io/manifest/issues",
256 | "source": "https://github.com/phar-io/manifest/tree/2.0.4"
257 | },
258 | "funding": [
259 | {
260 | "url": "https://github.com/theseer",
261 | "type": "github"
262 | }
263 | ],
264 | "time": "2024-03-03T12:33:53+00:00"
265 | },
266 | {
267 | "name": "phar-io/version",
268 | "version": "3.2.1",
269 | "source": {
270 | "type": "git",
271 | "url": "https://github.com/phar-io/version.git",
272 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
273 | },
274 | "dist": {
275 | "type": "zip",
276 | "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
277 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
278 | "shasum": ""
279 | },
280 | "require": {
281 | "php": "^7.2 || ^8.0"
282 | },
283 | "type": "library",
284 | "autoload": {
285 | "classmap": [
286 | "src/"
287 | ]
288 | },
289 | "notification-url": "https://packagist.org/downloads/",
290 | "license": [
291 | "BSD-3-Clause"
292 | ],
293 | "authors": [
294 | {
295 | "name": "Arne Blankerts",
296 | "email": "arne@blankerts.de",
297 | "role": "Developer"
298 | },
299 | {
300 | "name": "Sebastian Heuer",
301 | "email": "sebastian@phpeople.de",
302 | "role": "Developer"
303 | },
304 | {
305 | "name": "Sebastian Bergmann",
306 | "email": "sebastian@phpunit.de",
307 | "role": "Developer"
308 | }
309 | ],
310 | "description": "Library for handling version information and constraints",
311 | "support": {
312 | "issues": "https://github.com/phar-io/version/issues",
313 | "source": "https://github.com/phar-io/version/tree/3.2.1"
314 | },
315 | "time": "2022-02-21T01:04:05+00:00"
316 | },
317 | {
318 | "name": "phpunit/php-code-coverage",
319 | "version": "9.2.32",
320 | "source": {
321 | "type": "git",
322 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
323 | "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5"
324 | },
325 | "dist": {
326 | "type": "zip",
327 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5",
328 | "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5",
329 | "shasum": ""
330 | },
331 | "require": {
332 | "ext-dom": "*",
333 | "ext-libxml": "*",
334 | "ext-xmlwriter": "*",
335 | "nikic/php-parser": "^4.19.1 || ^5.1.0",
336 | "php": ">=7.3",
337 | "phpunit/php-file-iterator": "^3.0.6",
338 | "phpunit/php-text-template": "^2.0.4",
339 | "sebastian/code-unit-reverse-lookup": "^2.0.3",
340 | "sebastian/complexity": "^2.0.3",
341 | "sebastian/environment": "^5.1.5",
342 | "sebastian/lines-of-code": "^1.0.4",
343 | "sebastian/version": "^3.0.2",
344 | "theseer/tokenizer": "^1.2.3"
345 | },
346 | "require-dev": {
347 | "phpunit/phpunit": "^9.6"
348 | },
349 | "suggest": {
350 | "ext-pcov": "PHP extension that provides line coverage",
351 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
352 | },
353 | "type": "library",
354 | "extra": {
355 | "branch-alias": {
356 | "dev-main": "9.2.x-dev"
357 | }
358 | },
359 | "autoload": {
360 | "classmap": [
361 | "src/"
362 | ]
363 | },
364 | "notification-url": "https://packagist.org/downloads/",
365 | "license": [
366 | "BSD-3-Clause"
367 | ],
368 | "authors": [
369 | {
370 | "name": "Sebastian Bergmann",
371 | "email": "sebastian@phpunit.de",
372 | "role": "lead"
373 | }
374 | ],
375 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
376 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
377 | "keywords": [
378 | "coverage",
379 | "testing",
380 | "xunit"
381 | ],
382 | "support": {
383 | "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
384 | "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
385 | "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32"
386 | },
387 | "funding": [
388 | {
389 | "url": "https://github.com/sebastianbergmann",
390 | "type": "github"
391 | }
392 | ],
393 | "time": "2024-08-22T04:23:01+00:00"
394 | },
395 | {
396 | "name": "phpunit/php-file-iterator",
397 | "version": "3.0.6",
398 | "source": {
399 | "type": "git",
400 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
401 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf"
402 | },
403 | "dist": {
404 | "type": "zip",
405 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
406 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
407 | "shasum": ""
408 | },
409 | "require": {
410 | "php": ">=7.3"
411 | },
412 | "require-dev": {
413 | "phpunit/phpunit": "^9.3"
414 | },
415 | "type": "library",
416 | "extra": {
417 | "branch-alias": {
418 | "dev-master": "3.0-dev"
419 | }
420 | },
421 | "autoload": {
422 | "classmap": [
423 | "src/"
424 | ]
425 | },
426 | "notification-url": "https://packagist.org/downloads/",
427 | "license": [
428 | "BSD-3-Clause"
429 | ],
430 | "authors": [
431 | {
432 | "name": "Sebastian Bergmann",
433 | "email": "sebastian@phpunit.de",
434 | "role": "lead"
435 | }
436 | ],
437 | "description": "FilterIterator implementation that filters files based on a list of suffixes.",
438 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
439 | "keywords": [
440 | "filesystem",
441 | "iterator"
442 | ],
443 | "support": {
444 | "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
445 | "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6"
446 | },
447 | "funding": [
448 | {
449 | "url": "https://github.com/sebastianbergmann",
450 | "type": "github"
451 | }
452 | ],
453 | "time": "2021-12-02T12:48:52+00:00"
454 | },
455 | {
456 | "name": "phpunit/php-invoker",
457 | "version": "3.1.1",
458 | "source": {
459 | "type": "git",
460 | "url": "https://github.com/sebastianbergmann/php-invoker.git",
461 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67"
462 | },
463 | "dist": {
464 | "type": "zip",
465 | "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
466 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
467 | "shasum": ""
468 | },
469 | "require": {
470 | "php": ">=7.3"
471 | },
472 | "require-dev": {
473 | "ext-pcntl": "*",
474 | "phpunit/phpunit": "^9.3"
475 | },
476 | "suggest": {
477 | "ext-pcntl": "*"
478 | },
479 | "type": "library",
480 | "extra": {
481 | "branch-alias": {
482 | "dev-master": "3.1-dev"
483 | }
484 | },
485 | "autoload": {
486 | "classmap": [
487 | "src/"
488 | ]
489 | },
490 | "notification-url": "https://packagist.org/downloads/",
491 | "license": [
492 | "BSD-3-Clause"
493 | ],
494 | "authors": [
495 | {
496 | "name": "Sebastian Bergmann",
497 | "email": "sebastian@phpunit.de",
498 | "role": "lead"
499 | }
500 | ],
501 | "description": "Invoke callables with a timeout",
502 | "homepage": "https://github.com/sebastianbergmann/php-invoker/",
503 | "keywords": [
504 | "process"
505 | ],
506 | "support": {
507 | "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
508 | "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1"
509 | },
510 | "funding": [
511 | {
512 | "url": "https://github.com/sebastianbergmann",
513 | "type": "github"
514 | }
515 | ],
516 | "time": "2020-09-28T05:58:55+00:00"
517 | },
518 | {
519 | "name": "phpunit/php-text-template",
520 | "version": "2.0.4",
521 | "source": {
522 | "type": "git",
523 | "url": "https://github.com/sebastianbergmann/php-text-template.git",
524 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28"
525 | },
526 | "dist": {
527 | "type": "zip",
528 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
529 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
530 | "shasum": ""
531 | },
532 | "require": {
533 | "php": ">=7.3"
534 | },
535 | "require-dev": {
536 | "phpunit/phpunit": "^9.3"
537 | },
538 | "type": "library",
539 | "extra": {
540 | "branch-alias": {
541 | "dev-master": "2.0-dev"
542 | }
543 | },
544 | "autoload": {
545 | "classmap": [
546 | "src/"
547 | ]
548 | },
549 | "notification-url": "https://packagist.org/downloads/",
550 | "license": [
551 | "BSD-3-Clause"
552 | ],
553 | "authors": [
554 | {
555 | "name": "Sebastian Bergmann",
556 | "email": "sebastian@phpunit.de",
557 | "role": "lead"
558 | }
559 | ],
560 | "description": "Simple template engine.",
561 | "homepage": "https://github.com/sebastianbergmann/php-text-template/",
562 | "keywords": [
563 | "template"
564 | ],
565 | "support": {
566 | "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
567 | "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4"
568 | },
569 | "funding": [
570 | {
571 | "url": "https://github.com/sebastianbergmann",
572 | "type": "github"
573 | }
574 | ],
575 | "time": "2020-10-26T05:33:50+00:00"
576 | },
577 | {
578 | "name": "phpunit/php-timer",
579 | "version": "5.0.3",
580 | "source": {
581 | "type": "git",
582 | "url": "https://github.com/sebastianbergmann/php-timer.git",
583 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2"
584 | },
585 | "dist": {
586 | "type": "zip",
587 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
588 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
589 | "shasum": ""
590 | },
591 | "require": {
592 | "php": ">=7.3"
593 | },
594 | "require-dev": {
595 | "phpunit/phpunit": "^9.3"
596 | },
597 | "type": "library",
598 | "extra": {
599 | "branch-alias": {
600 | "dev-master": "5.0-dev"
601 | }
602 | },
603 | "autoload": {
604 | "classmap": [
605 | "src/"
606 | ]
607 | },
608 | "notification-url": "https://packagist.org/downloads/",
609 | "license": [
610 | "BSD-3-Clause"
611 | ],
612 | "authors": [
613 | {
614 | "name": "Sebastian Bergmann",
615 | "email": "sebastian@phpunit.de",
616 | "role": "lead"
617 | }
618 | ],
619 | "description": "Utility class for timing",
620 | "homepage": "https://github.com/sebastianbergmann/php-timer/",
621 | "keywords": [
622 | "timer"
623 | ],
624 | "support": {
625 | "issues": "https://github.com/sebastianbergmann/php-timer/issues",
626 | "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3"
627 | },
628 | "funding": [
629 | {
630 | "url": "https://github.com/sebastianbergmann",
631 | "type": "github"
632 | }
633 | ],
634 | "time": "2020-10-26T13:16:10+00:00"
635 | },
636 | {
637 | "name": "phpunit/phpunit",
638 | "version": "9.6.22",
639 | "source": {
640 | "type": "git",
641 | "url": "https://github.com/sebastianbergmann/phpunit.git",
642 | "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c"
643 | },
644 | "dist": {
645 | "type": "zip",
646 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f80235cb4d3caa59ae09be3adf1ded27521d1a9c",
647 | "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c",
648 | "shasum": ""
649 | },
650 | "require": {
651 | "doctrine/instantiator": "^1.5.0 || ^2",
652 | "ext-dom": "*",
653 | "ext-json": "*",
654 | "ext-libxml": "*",
655 | "ext-mbstring": "*",
656 | "ext-xml": "*",
657 | "ext-xmlwriter": "*",
658 | "myclabs/deep-copy": "^1.12.1",
659 | "phar-io/manifest": "^2.0.4",
660 | "phar-io/version": "^3.2.1",
661 | "php": ">=7.3",
662 | "phpunit/php-code-coverage": "^9.2.32",
663 | "phpunit/php-file-iterator": "^3.0.6",
664 | "phpunit/php-invoker": "^3.1.1",
665 | "phpunit/php-text-template": "^2.0.4",
666 | "phpunit/php-timer": "^5.0.3",
667 | "sebastian/cli-parser": "^1.0.2",
668 | "sebastian/code-unit": "^1.0.8",
669 | "sebastian/comparator": "^4.0.8",
670 | "sebastian/diff": "^4.0.6",
671 | "sebastian/environment": "^5.1.5",
672 | "sebastian/exporter": "^4.0.6",
673 | "sebastian/global-state": "^5.0.7",
674 | "sebastian/object-enumerator": "^4.0.4",
675 | "sebastian/resource-operations": "^3.0.4",
676 | "sebastian/type": "^3.2.1",
677 | "sebastian/version": "^3.0.2"
678 | },
679 | "suggest": {
680 | "ext-soap": "To be able to generate mocks based on WSDL files",
681 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
682 | },
683 | "bin": [
684 | "phpunit"
685 | ],
686 | "type": "library",
687 | "extra": {
688 | "branch-alias": {
689 | "dev-master": "9.6-dev"
690 | }
691 | },
692 | "autoload": {
693 | "files": [
694 | "src/Framework/Assert/Functions.php"
695 | ],
696 | "classmap": [
697 | "src/"
698 | ]
699 | },
700 | "notification-url": "https://packagist.org/downloads/",
701 | "license": [
702 | "BSD-3-Clause"
703 | ],
704 | "authors": [
705 | {
706 | "name": "Sebastian Bergmann",
707 | "email": "sebastian@phpunit.de",
708 | "role": "lead"
709 | }
710 | ],
711 | "description": "The PHP Unit Testing framework.",
712 | "homepage": "https://phpunit.de/",
713 | "keywords": [
714 | "phpunit",
715 | "testing",
716 | "xunit"
717 | ],
718 | "support": {
719 | "issues": "https://github.com/sebastianbergmann/phpunit/issues",
720 | "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
721 | "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.22"
722 | },
723 | "funding": [
724 | {
725 | "url": "https://phpunit.de/sponsors.html",
726 | "type": "custom"
727 | },
728 | {
729 | "url": "https://github.com/sebastianbergmann",
730 | "type": "github"
731 | },
732 | {
733 | "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
734 | "type": "tidelift"
735 | }
736 | ],
737 | "time": "2024-12-05T13:48:26+00:00"
738 | },
739 | {
740 | "name": "sebastian/cli-parser",
741 | "version": "1.0.2",
742 | "source": {
743 | "type": "git",
744 | "url": "https://github.com/sebastianbergmann/cli-parser.git",
745 | "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b"
746 | },
747 | "dist": {
748 | "type": "zip",
749 | "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
750 | "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
751 | "shasum": ""
752 | },
753 | "require": {
754 | "php": ">=7.3"
755 | },
756 | "require-dev": {
757 | "phpunit/phpunit": "^9.3"
758 | },
759 | "type": "library",
760 | "extra": {
761 | "branch-alias": {
762 | "dev-master": "1.0-dev"
763 | }
764 | },
765 | "autoload": {
766 | "classmap": [
767 | "src/"
768 | ]
769 | },
770 | "notification-url": "https://packagist.org/downloads/",
771 | "license": [
772 | "BSD-3-Clause"
773 | ],
774 | "authors": [
775 | {
776 | "name": "Sebastian Bergmann",
777 | "email": "sebastian@phpunit.de",
778 | "role": "lead"
779 | }
780 | ],
781 | "description": "Library for parsing CLI options",
782 | "homepage": "https://github.com/sebastianbergmann/cli-parser",
783 | "support": {
784 | "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
785 | "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2"
786 | },
787 | "funding": [
788 | {
789 | "url": "https://github.com/sebastianbergmann",
790 | "type": "github"
791 | }
792 | ],
793 | "time": "2024-03-02T06:27:43+00:00"
794 | },
795 | {
796 | "name": "sebastian/code-unit",
797 | "version": "1.0.8",
798 | "source": {
799 | "type": "git",
800 | "url": "https://github.com/sebastianbergmann/code-unit.git",
801 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120"
802 | },
803 | "dist": {
804 | "type": "zip",
805 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120",
806 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120",
807 | "shasum": ""
808 | },
809 | "require": {
810 | "php": ">=7.3"
811 | },
812 | "require-dev": {
813 | "phpunit/phpunit": "^9.3"
814 | },
815 | "type": "library",
816 | "extra": {
817 | "branch-alias": {
818 | "dev-master": "1.0-dev"
819 | }
820 | },
821 | "autoload": {
822 | "classmap": [
823 | "src/"
824 | ]
825 | },
826 | "notification-url": "https://packagist.org/downloads/",
827 | "license": [
828 | "BSD-3-Clause"
829 | ],
830 | "authors": [
831 | {
832 | "name": "Sebastian Bergmann",
833 | "email": "sebastian@phpunit.de",
834 | "role": "lead"
835 | }
836 | ],
837 | "description": "Collection of value objects that represent the PHP code units",
838 | "homepage": "https://github.com/sebastianbergmann/code-unit",
839 | "support": {
840 | "issues": "https://github.com/sebastianbergmann/code-unit/issues",
841 | "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8"
842 | },
843 | "funding": [
844 | {
845 | "url": "https://github.com/sebastianbergmann",
846 | "type": "github"
847 | }
848 | ],
849 | "time": "2020-10-26T13:08:54+00:00"
850 | },
851 | {
852 | "name": "sebastian/code-unit-reverse-lookup",
853 | "version": "2.0.3",
854 | "source": {
855 | "type": "git",
856 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
857 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5"
858 | },
859 | "dist": {
860 | "type": "zip",
861 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
862 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
863 | "shasum": ""
864 | },
865 | "require": {
866 | "php": ">=7.3"
867 | },
868 | "require-dev": {
869 | "phpunit/phpunit": "^9.3"
870 | },
871 | "type": "library",
872 | "extra": {
873 | "branch-alias": {
874 | "dev-master": "2.0-dev"
875 | }
876 | },
877 | "autoload": {
878 | "classmap": [
879 | "src/"
880 | ]
881 | },
882 | "notification-url": "https://packagist.org/downloads/",
883 | "license": [
884 | "BSD-3-Clause"
885 | ],
886 | "authors": [
887 | {
888 | "name": "Sebastian Bergmann",
889 | "email": "sebastian@phpunit.de"
890 | }
891 | ],
892 | "description": "Looks up which function or method a line of code belongs to",
893 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
894 | "support": {
895 | "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
896 | "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3"
897 | },
898 | "funding": [
899 | {
900 | "url": "https://github.com/sebastianbergmann",
901 | "type": "github"
902 | }
903 | ],
904 | "time": "2020-09-28T05:30:19+00:00"
905 | },
906 | {
907 | "name": "sebastian/comparator",
908 | "version": "4.0.8",
909 | "source": {
910 | "type": "git",
911 | "url": "https://github.com/sebastianbergmann/comparator.git",
912 | "reference": "fa0f136dd2334583309d32b62544682ee972b51a"
913 | },
914 | "dist": {
915 | "type": "zip",
916 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a",
917 | "reference": "fa0f136dd2334583309d32b62544682ee972b51a",
918 | "shasum": ""
919 | },
920 | "require": {
921 | "php": ">=7.3",
922 | "sebastian/diff": "^4.0",
923 | "sebastian/exporter": "^4.0"
924 | },
925 | "require-dev": {
926 | "phpunit/phpunit": "^9.3"
927 | },
928 | "type": "library",
929 | "extra": {
930 | "branch-alias": {
931 | "dev-master": "4.0-dev"
932 | }
933 | },
934 | "autoload": {
935 | "classmap": [
936 | "src/"
937 | ]
938 | },
939 | "notification-url": "https://packagist.org/downloads/",
940 | "license": [
941 | "BSD-3-Clause"
942 | ],
943 | "authors": [
944 | {
945 | "name": "Sebastian Bergmann",
946 | "email": "sebastian@phpunit.de"
947 | },
948 | {
949 | "name": "Jeff Welch",
950 | "email": "whatthejeff@gmail.com"
951 | },
952 | {
953 | "name": "Volker Dusch",
954 | "email": "github@wallbash.com"
955 | },
956 | {
957 | "name": "Bernhard Schussek",
958 | "email": "bschussek@2bepublished.at"
959 | }
960 | ],
961 | "description": "Provides the functionality to compare PHP values for equality",
962 | "homepage": "https://github.com/sebastianbergmann/comparator",
963 | "keywords": [
964 | "comparator",
965 | "compare",
966 | "equality"
967 | ],
968 | "support": {
969 | "issues": "https://github.com/sebastianbergmann/comparator/issues",
970 | "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8"
971 | },
972 | "funding": [
973 | {
974 | "url": "https://github.com/sebastianbergmann",
975 | "type": "github"
976 | }
977 | ],
978 | "time": "2022-09-14T12:41:17+00:00"
979 | },
980 | {
981 | "name": "sebastian/complexity",
982 | "version": "2.0.3",
983 | "source": {
984 | "type": "git",
985 | "url": "https://github.com/sebastianbergmann/complexity.git",
986 | "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a"
987 | },
988 | "dist": {
989 | "type": "zip",
990 | "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a",
991 | "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a",
992 | "shasum": ""
993 | },
994 | "require": {
995 | "nikic/php-parser": "^4.18 || ^5.0",
996 | "php": ">=7.3"
997 | },
998 | "require-dev": {
999 | "phpunit/phpunit": "^9.3"
1000 | },
1001 | "type": "library",
1002 | "extra": {
1003 | "branch-alias": {
1004 | "dev-master": "2.0-dev"
1005 | }
1006 | },
1007 | "autoload": {
1008 | "classmap": [
1009 | "src/"
1010 | ]
1011 | },
1012 | "notification-url": "https://packagist.org/downloads/",
1013 | "license": [
1014 | "BSD-3-Clause"
1015 | ],
1016 | "authors": [
1017 | {
1018 | "name": "Sebastian Bergmann",
1019 | "email": "sebastian@phpunit.de",
1020 | "role": "lead"
1021 | }
1022 | ],
1023 | "description": "Library for calculating the complexity of PHP code units",
1024 | "homepage": "https://github.com/sebastianbergmann/complexity",
1025 | "support": {
1026 | "issues": "https://github.com/sebastianbergmann/complexity/issues",
1027 | "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3"
1028 | },
1029 | "funding": [
1030 | {
1031 | "url": "https://github.com/sebastianbergmann",
1032 | "type": "github"
1033 | }
1034 | ],
1035 | "time": "2023-12-22T06:19:30+00:00"
1036 | },
1037 | {
1038 | "name": "sebastian/diff",
1039 | "version": "4.0.6",
1040 | "source": {
1041 | "type": "git",
1042 | "url": "https://github.com/sebastianbergmann/diff.git",
1043 | "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc"
1044 | },
1045 | "dist": {
1046 | "type": "zip",
1047 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc",
1048 | "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc",
1049 | "shasum": ""
1050 | },
1051 | "require": {
1052 | "php": ">=7.3"
1053 | },
1054 | "require-dev": {
1055 | "phpunit/phpunit": "^9.3",
1056 | "symfony/process": "^4.2 || ^5"
1057 | },
1058 | "type": "library",
1059 | "extra": {
1060 | "branch-alias": {
1061 | "dev-master": "4.0-dev"
1062 | }
1063 | },
1064 | "autoload": {
1065 | "classmap": [
1066 | "src/"
1067 | ]
1068 | },
1069 | "notification-url": "https://packagist.org/downloads/",
1070 | "license": [
1071 | "BSD-3-Clause"
1072 | ],
1073 | "authors": [
1074 | {
1075 | "name": "Sebastian Bergmann",
1076 | "email": "sebastian@phpunit.de"
1077 | },
1078 | {
1079 | "name": "Kore Nordmann",
1080 | "email": "mail@kore-nordmann.de"
1081 | }
1082 | ],
1083 | "description": "Diff implementation",
1084 | "homepage": "https://github.com/sebastianbergmann/diff",
1085 | "keywords": [
1086 | "diff",
1087 | "udiff",
1088 | "unidiff",
1089 | "unified diff"
1090 | ],
1091 | "support": {
1092 | "issues": "https://github.com/sebastianbergmann/diff/issues",
1093 | "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6"
1094 | },
1095 | "funding": [
1096 | {
1097 | "url": "https://github.com/sebastianbergmann",
1098 | "type": "github"
1099 | }
1100 | ],
1101 | "time": "2024-03-02T06:30:58+00:00"
1102 | },
1103 | {
1104 | "name": "sebastian/environment",
1105 | "version": "5.1.5",
1106 | "source": {
1107 | "type": "git",
1108 | "url": "https://github.com/sebastianbergmann/environment.git",
1109 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed"
1110 | },
1111 | "dist": {
1112 | "type": "zip",
1113 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
1114 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
1115 | "shasum": ""
1116 | },
1117 | "require": {
1118 | "php": ">=7.3"
1119 | },
1120 | "require-dev": {
1121 | "phpunit/phpunit": "^9.3"
1122 | },
1123 | "suggest": {
1124 | "ext-posix": "*"
1125 | },
1126 | "type": "library",
1127 | "extra": {
1128 | "branch-alias": {
1129 | "dev-master": "5.1-dev"
1130 | }
1131 | },
1132 | "autoload": {
1133 | "classmap": [
1134 | "src/"
1135 | ]
1136 | },
1137 | "notification-url": "https://packagist.org/downloads/",
1138 | "license": [
1139 | "BSD-3-Clause"
1140 | ],
1141 | "authors": [
1142 | {
1143 | "name": "Sebastian Bergmann",
1144 | "email": "sebastian@phpunit.de"
1145 | }
1146 | ],
1147 | "description": "Provides functionality to handle HHVM/PHP environments",
1148 | "homepage": "http://www.github.com/sebastianbergmann/environment",
1149 | "keywords": [
1150 | "Xdebug",
1151 | "environment",
1152 | "hhvm"
1153 | ],
1154 | "support": {
1155 | "issues": "https://github.com/sebastianbergmann/environment/issues",
1156 | "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5"
1157 | },
1158 | "funding": [
1159 | {
1160 | "url": "https://github.com/sebastianbergmann",
1161 | "type": "github"
1162 | }
1163 | ],
1164 | "time": "2023-02-03T06:03:51+00:00"
1165 | },
1166 | {
1167 | "name": "sebastian/exporter",
1168 | "version": "4.0.6",
1169 | "source": {
1170 | "type": "git",
1171 | "url": "https://github.com/sebastianbergmann/exporter.git",
1172 | "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72"
1173 | },
1174 | "dist": {
1175 | "type": "zip",
1176 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72",
1177 | "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72",
1178 | "shasum": ""
1179 | },
1180 | "require": {
1181 | "php": ">=7.3",
1182 | "sebastian/recursion-context": "^4.0"
1183 | },
1184 | "require-dev": {
1185 | "ext-mbstring": "*",
1186 | "phpunit/phpunit": "^9.3"
1187 | },
1188 | "type": "library",
1189 | "extra": {
1190 | "branch-alias": {
1191 | "dev-master": "4.0-dev"
1192 | }
1193 | },
1194 | "autoload": {
1195 | "classmap": [
1196 | "src/"
1197 | ]
1198 | },
1199 | "notification-url": "https://packagist.org/downloads/",
1200 | "license": [
1201 | "BSD-3-Clause"
1202 | ],
1203 | "authors": [
1204 | {
1205 | "name": "Sebastian Bergmann",
1206 | "email": "sebastian@phpunit.de"
1207 | },
1208 | {
1209 | "name": "Jeff Welch",
1210 | "email": "whatthejeff@gmail.com"
1211 | },
1212 | {
1213 | "name": "Volker Dusch",
1214 | "email": "github@wallbash.com"
1215 | },
1216 | {
1217 | "name": "Adam Harvey",
1218 | "email": "aharvey@php.net"
1219 | },
1220 | {
1221 | "name": "Bernhard Schussek",
1222 | "email": "bschussek@gmail.com"
1223 | }
1224 | ],
1225 | "description": "Provides the functionality to export PHP variables for visualization",
1226 | "homepage": "https://www.github.com/sebastianbergmann/exporter",
1227 | "keywords": [
1228 | "export",
1229 | "exporter"
1230 | ],
1231 | "support": {
1232 | "issues": "https://github.com/sebastianbergmann/exporter/issues",
1233 | "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
1234 | },
1235 | "funding": [
1236 | {
1237 | "url": "https://github.com/sebastianbergmann",
1238 | "type": "github"
1239 | }
1240 | ],
1241 | "time": "2024-03-02T06:33:00+00:00"
1242 | },
1243 | {
1244 | "name": "sebastian/global-state",
1245 | "version": "5.0.7",
1246 | "source": {
1247 | "type": "git",
1248 | "url": "https://github.com/sebastianbergmann/global-state.git",
1249 | "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9"
1250 | },
1251 | "dist": {
1252 | "type": "zip",
1253 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
1254 | "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
1255 | "shasum": ""
1256 | },
1257 | "require": {
1258 | "php": ">=7.3",
1259 | "sebastian/object-reflector": "^2.0",
1260 | "sebastian/recursion-context": "^4.0"
1261 | },
1262 | "require-dev": {
1263 | "ext-dom": "*",
1264 | "phpunit/phpunit": "^9.3"
1265 | },
1266 | "suggest": {
1267 | "ext-uopz": "*"
1268 | },
1269 | "type": "library",
1270 | "extra": {
1271 | "branch-alias": {
1272 | "dev-master": "5.0-dev"
1273 | }
1274 | },
1275 | "autoload": {
1276 | "classmap": [
1277 | "src/"
1278 | ]
1279 | },
1280 | "notification-url": "https://packagist.org/downloads/",
1281 | "license": [
1282 | "BSD-3-Clause"
1283 | ],
1284 | "authors": [
1285 | {
1286 | "name": "Sebastian Bergmann",
1287 | "email": "sebastian@phpunit.de"
1288 | }
1289 | ],
1290 | "description": "Snapshotting of global state",
1291 | "homepage": "http://www.github.com/sebastianbergmann/global-state",
1292 | "keywords": [
1293 | "global state"
1294 | ],
1295 | "support": {
1296 | "issues": "https://github.com/sebastianbergmann/global-state/issues",
1297 | "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7"
1298 | },
1299 | "funding": [
1300 | {
1301 | "url": "https://github.com/sebastianbergmann",
1302 | "type": "github"
1303 | }
1304 | ],
1305 | "time": "2024-03-02T06:35:11+00:00"
1306 | },
1307 | {
1308 | "name": "sebastian/lines-of-code",
1309 | "version": "1.0.4",
1310 | "source": {
1311 | "type": "git",
1312 | "url": "https://github.com/sebastianbergmann/lines-of-code.git",
1313 | "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5"
1314 | },
1315 | "dist": {
1316 | "type": "zip",
1317 | "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5",
1318 | "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5",
1319 | "shasum": ""
1320 | },
1321 | "require": {
1322 | "nikic/php-parser": "^4.18 || ^5.0",
1323 | "php": ">=7.3"
1324 | },
1325 | "require-dev": {
1326 | "phpunit/phpunit": "^9.3"
1327 | },
1328 | "type": "library",
1329 | "extra": {
1330 | "branch-alias": {
1331 | "dev-master": "1.0-dev"
1332 | }
1333 | },
1334 | "autoload": {
1335 | "classmap": [
1336 | "src/"
1337 | ]
1338 | },
1339 | "notification-url": "https://packagist.org/downloads/",
1340 | "license": [
1341 | "BSD-3-Clause"
1342 | ],
1343 | "authors": [
1344 | {
1345 | "name": "Sebastian Bergmann",
1346 | "email": "sebastian@phpunit.de",
1347 | "role": "lead"
1348 | }
1349 | ],
1350 | "description": "Library for counting the lines of code in PHP source code",
1351 | "homepage": "https://github.com/sebastianbergmann/lines-of-code",
1352 | "support": {
1353 | "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
1354 | "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4"
1355 | },
1356 | "funding": [
1357 | {
1358 | "url": "https://github.com/sebastianbergmann",
1359 | "type": "github"
1360 | }
1361 | ],
1362 | "time": "2023-12-22T06:20:34+00:00"
1363 | },
1364 | {
1365 | "name": "sebastian/object-enumerator",
1366 | "version": "4.0.4",
1367 | "source": {
1368 | "type": "git",
1369 | "url": "https://github.com/sebastianbergmann/object-enumerator.git",
1370 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71"
1371 | },
1372 | "dist": {
1373 | "type": "zip",
1374 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71",
1375 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71",
1376 | "shasum": ""
1377 | },
1378 | "require": {
1379 | "php": ">=7.3",
1380 | "sebastian/object-reflector": "^2.0",
1381 | "sebastian/recursion-context": "^4.0"
1382 | },
1383 | "require-dev": {
1384 | "phpunit/phpunit": "^9.3"
1385 | },
1386 | "type": "library",
1387 | "extra": {
1388 | "branch-alias": {
1389 | "dev-master": "4.0-dev"
1390 | }
1391 | },
1392 | "autoload": {
1393 | "classmap": [
1394 | "src/"
1395 | ]
1396 | },
1397 | "notification-url": "https://packagist.org/downloads/",
1398 | "license": [
1399 | "BSD-3-Clause"
1400 | ],
1401 | "authors": [
1402 | {
1403 | "name": "Sebastian Bergmann",
1404 | "email": "sebastian@phpunit.de"
1405 | }
1406 | ],
1407 | "description": "Traverses array structures and object graphs to enumerate all referenced objects",
1408 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
1409 | "support": {
1410 | "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
1411 | "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4"
1412 | },
1413 | "funding": [
1414 | {
1415 | "url": "https://github.com/sebastianbergmann",
1416 | "type": "github"
1417 | }
1418 | ],
1419 | "time": "2020-10-26T13:12:34+00:00"
1420 | },
1421 | {
1422 | "name": "sebastian/object-reflector",
1423 | "version": "2.0.4",
1424 | "source": {
1425 | "type": "git",
1426 | "url": "https://github.com/sebastianbergmann/object-reflector.git",
1427 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7"
1428 | },
1429 | "dist": {
1430 | "type": "zip",
1431 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
1432 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
1433 | "shasum": ""
1434 | },
1435 | "require": {
1436 | "php": ">=7.3"
1437 | },
1438 | "require-dev": {
1439 | "phpunit/phpunit": "^9.3"
1440 | },
1441 | "type": "library",
1442 | "extra": {
1443 | "branch-alias": {
1444 | "dev-master": "2.0-dev"
1445 | }
1446 | },
1447 | "autoload": {
1448 | "classmap": [
1449 | "src/"
1450 | ]
1451 | },
1452 | "notification-url": "https://packagist.org/downloads/",
1453 | "license": [
1454 | "BSD-3-Clause"
1455 | ],
1456 | "authors": [
1457 | {
1458 | "name": "Sebastian Bergmann",
1459 | "email": "sebastian@phpunit.de"
1460 | }
1461 | ],
1462 | "description": "Allows reflection of object attributes, including inherited and non-public ones",
1463 | "homepage": "https://github.com/sebastianbergmann/object-reflector/",
1464 | "support": {
1465 | "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
1466 | "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4"
1467 | },
1468 | "funding": [
1469 | {
1470 | "url": "https://github.com/sebastianbergmann",
1471 | "type": "github"
1472 | }
1473 | ],
1474 | "time": "2020-10-26T13:14:26+00:00"
1475 | },
1476 | {
1477 | "name": "sebastian/recursion-context",
1478 | "version": "4.0.5",
1479 | "source": {
1480 | "type": "git",
1481 | "url": "https://github.com/sebastianbergmann/recursion-context.git",
1482 | "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1"
1483 | },
1484 | "dist": {
1485 | "type": "zip",
1486 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
1487 | "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
1488 | "shasum": ""
1489 | },
1490 | "require": {
1491 | "php": ">=7.3"
1492 | },
1493 | "require-dev": {
1494 | "phpunit/phpunit": "^9.3"
1495 | },
1496 | "type": "library",
1497 | "extra": {
1498 | "branch-alias": {
1499 | "dev-master": "4.0-dev"
1500 | }
1501 | },
1502 | "autoload": {
1503 | "classmap": [
1504 | "src/"
1505 | ]
1506 | },
1507 | "notification-url": "https://packagist.org/downloads/",
1508 | "license": [
1509 | "BSD-3-Clause"
1510 | ],
1511 | "authors": [
1512 | {
1513 | "name": "Sebastian Bergmann",
1514 | "email": "sebastian@phpunit.de"
1515 | },
1516 | {
1517 | "name": "Jeff Welch",
1518 | "email": "whatthejeff@gmail.com"
1519 | },
1520 | {
1521 | "name": "Adam Harvey",
1522 | "email": "aharvey@php.net"
1523 | }
1524 | ],
1525 | "description": "Provides functionality to recursively process PHP variables",
1526 | "homepage": "https://github.com/sebastianbergmann/recursion-context",
1527 | "support": {
1528 | "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
1529 | "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5"
1530 | },
1531 | "funding": [
1532 | {
1533 | "url": "https://github.com/sebastianbergmann",
1534 | "type": "github"
1535 | }
1536 | ],
1537 | "time": "2023-02-03T06:07:39+00:00"
1538 | },
1539 | {
1540 | "name": "sebastian/resource-operations",
1541 | "version": "3.0.4",
1542 | "source": {
1543 | "type": "git",
1544 | "url": "https://github.com/sebastianbergmann/resource-operations.git",
1545 | "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e"
1546 | },
1547 | "dist": {
1548 | "type": "zip",
1549 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
1550 | "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
1551 | "shasum": ""
1552 | },
1553 | "require": {
1554 | "php": ">=7.3"
1555 | },
1556 | "require-dev": {
1557 | "phpunit/phpunit": "^9.0"
1558 | },
1559 | "type": "library",
1560 | "extra": {
1561 | "branch-alias": {
1562 | "dev-main": "3.0-dev"
1563 | }
1564 | },
1565 | "autoload": {
1566 | "classmap": [
1567 | "src/"
1568 | ]
1569 | },
1570 | "notification-url": "https://packagist.org/downloads/",
1571 | "license": [
1572 | "BSD-3-Clause"
1573 | ],
1574 | "authors": [
1575 | {
1576 | "name": "Sebastian Bergmann",
1577 | "email": "sebastian@phpunit.de"
1578 | }
1579 | ],
1580 | "description": "Provides a list of PHP built-in functions that operate on resources",
1581 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
1582 | "support": {
1583 | "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4"
1584 | },
1585 | "funding": [
1586 | {
1587 | "url": "https://github.com/sebastianbergmann",
1588 | "type": "github"
1589 | }
1590 | ],
1591 | "time": "2024-03-14T16:00:52+00:00"
1592 | },
1593 | {
1594 | "name": "sebastian/type",
1595 | "version": "3.2.1",
1596 | "source": {
1597 | "type": "git",
1598 | "url": "https://github.com/sebastianbergmann/type.git",
1599 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7"
1600 | },
1601 | "dist": {
1602 | "type": "zip",
1603 | "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
1604 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
1605 | "shasum": ""
1606 | },
1607 | "require": {
1608 | "php": ">=7.3"
1609 | },
1610 | "require-dev": {
1611 | "phpunit/phpunit": "^9.5"
1612 | },
1613 | "type": "library",
1614 | "extra": {
1615 | "branch-alias": {
1616 | "dev-master": "3.2-dev"
1617 | }
1618 | },
1619 | "autoload": {
1620 | "classmap": [
1621 | "src/"
1622 | ]
1623 | },
1624 | "notification-url": "https://packagist.org/downloads/",
1625 | "license": [
1626 | "BSD-3-Clause"
1627 | ],
1628 | "authors": [
1629 | {
1630 | "name": "Sebastian Bergmann",
1631 | "email": "sebastian@phpunit.de",
1632 | "role": "lead"
1633 | }
1634 | ],
1635 | "description": "Collection of value objects that represent the types of the PHP type system",
1636 | "homepage": "https://github.com/sebastianbergmann/type",
1637 | "support": {
1638 | "issues": "https://github.com/sebastianbergmann/type/issues",
1639 | "source": "https://github.com/sebastianbergmann/type/tree/3.2.1"
1640 | },
1641 | "funding": [
1642 | {
1643 | "url": "https://github.com/sebastianbergmann",
1644 | "type": "github"
1645 | }
1646 | ],
1647 | "time": "2023-02-03T06:13:03+00:00"
1648 | },
1649 | {
1650 | "name": "sebastian/version",
1651 | "version": "3.0.2",
1652 | "source": {
1653 | "type": "git",
1654 | "url": "https://github.com/sebastianbergmann/version.git",
1655 | "reference": "c6c1022351a901512170118436c764e473f6de8c"
1656 | },
1657 | "dist": {
1658 | "type": "zip",
1659 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c",
1660 | "reference": "c6c1022351a901512170118436c764e473f6de8c",
1661 | "shasum": ""
1662 | },
1663 | "require": {
1664 | "php": ">=7.3"
1665 | },
1666 | "type": "library",
1667 | "extra": {
1668 | "branch-alias": {
1669 | "dev-master": "3.0-dev"
1670 | }
1671 | },
1672 | "autoload": {
1673 | "classmap": [
1674 | "src/"
1675 | ]
1676 | },
1677 | "notification-url": "https://packagist.org/downloads/",
1678 | "license": [
1679 | "BSD-3-Clause"
1680 | ],
1681 | "authors": [
1682 | {
1683 | "name": "Sebastian Bergmann",
1684 | "email": "sebastian@phpunit.de",
1685 | "role": "lead"
1686 | }
1687 | ],
1688 | "description": "Library that helps with managing the version number of Git-hosted PHP projects",
1689 | "homepage": "https://github.com/sebastianbergmann/version",
1690 | "support": {
1691 | "issues": "https://github.com/sebastianbergmann/version/issues",
1692 | "source": "https://github.com/sebastianbergmann/version/tree/3.0.2"
1693 | },
1694 | "funding": [
1695 | {
1696 | "url": "https://github.com/sebastianbergmann",
1697 | "type": "github"
1698 | }
1699 | ],
1700 | "time": "2020-09-28T06:39:44+00:00"
1701 | },
1702 | {
1703 | "name": "theseer/tokenizer",
1704 | "version": "1.2.3",
1705 | "source": {
1706 | "type": "git",
1707 | "url": "https://github.com/theseer/tokenizer.git",
1708 | "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
1709 | },
1710 | "dist": {
1711 | "type": "zip",
1712 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
1713 | "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
1714 | "shasum": ""
1715 | },
1716 | "require": {
1717 | "ext-dom": "*",
1718 | "ext-tokenizer": "*",
1719 | "ext-xmlwriter": "*",
1720 | "php": "^7.2 || ^8.0"
1721 | },
1722 | "type": "library",
1723 | "autoload": {
1724 | "classmap": [
1725 | "src/"
1726 | ]
1727 | },
1728 | "notification-url": "https://packagist.org/downloads/",
1729 | "license": [
1730 | "BSD-3-Clause"
1731 | ],
1732 | "authors": [
1733 | {
1734 | "name": "Arne Blankerts",
1735 | "email": "arne@blankerts.de",
1736 | "role": "Developer"
1737 | }
1738 | ],
1739 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
1740 | "support": {
1741 | "issues": "https://github.com/theseer/tokenizer/issues",
1742 | "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
1743 | },
1744 | "funding": [
1745 | {
1746 | "url": "https://github.com/theseer",
1747 | "type": "github"
1748 | }
1749 | ],
1750 | "time": "2024-03-03T12:36:25+00:00"
1751 | }
1752 | ],
1753 | "aliases": [],
1754 | "minimum-stability": "stable",
1755 | "stability-flags": [],
1756 | "prefer-stable": false,
1757 | "prefer-lowest": false,
1758 | "platform": {
1759 | "php": ">=7.4"
1760 | },
1761 | "platform-dev": [],
1762 | "plugin-api-version": "2.6.0"
1763 | }
1764 |
--------------------------------------------------------------------------------