├── tests
├── input.txt
└── CLI
│ ├── TaskTest.php
│ └── CLITest.php
├── .gitignore
├── phpstan.neon
├── .github
└── workflows
│ ├── codeql.yml
│ ├── linter.yml
│ └── test.yml
├── psalm.xml
├── phpunit.xml
├── src
└── CLI
│ ├── Task.php
│ ├── Adapters
│ ├── Generic.php
│ └── Swoole.php
│ ├── Adapter.php
│ └── CLI.php
├── phpcs.xml
├── composer.json
├── LICENSE.md
├── README.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
└── composer.lock
/tests/input.txt:
--------------------------------------------------------------------------------
1 | this is an answer
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
2 | /.idea/
3 | .phpunit.result.cache
4 |
--------------------------------------------------------------------------------
/phpstan.neon:
--------------------------------------------------------------------------------
1 | parameters:
2 | level: 5
3 | paths:
4 | - src
5 | - tests
--------------------------------------------------------------------------------
/.github/workflows/codeql.yml:
--------------------------------------------------------------------------------
1 | name: "CodeQL"
2 |
3 | on: [pull_request]
4 | jobs:
5 | lint:
6 | name: CodeQL
7 | runs-on: ubuntu-latest
8 |
9 | steps:
10 | - name: Checkout repository
11 | uses: actions/checkout@v3
12 |
13 | - name: Run CodeQL
14 | run: |
15 | docker run --rm -v $PWD:/app composer sh -c \
16 | "composer install --profile --ignore-platform-reqs && composer check"
--------------------------------------------------------------------------------
/.github/workflows/linter.yml:
--------------------------------------------------------------------------------
1 | name: "Linter"
2 |
3 | on: [pull_request]
4 | jobs:
5 | lint:
6 | name: Linter
7 | runs-on: ubuntu-latest
8 |
9 | steps:
10 | - name: Checkout repository
11 | uses: actions/checkout@v3
12 | with:
13 | fetch-depth: 2
14 |
15 | - run: git checkout HEAD^2
16 |
17 | - name: Run Linter
18 | run: |
19 | docker run --rm -v $PWD:/app composer sh -c \
20 | "composer install --profile --ignore-platform-reqs && composer lint"
--------------------------------------------------------------------------------
/psalm.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 | ./tests/
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/CLI/Task.php:
--------------------------------------------------------------------------------
1 | name = $name;
22 | }
23 |
24 | /**
25 | * Get Name
26 | *
27 | * @return string
28 | */
29 | public function getName(): string
30 | {
31 | return $this->name;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/phpcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ./src
5 | ./tests
6 |
7 |
8 |
9 |
10 | *
11 |
12 |
13 |
14 | *
15 |
16 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: "Tests"
2 |
3 | on: [pull_request]
4 | jobs:
5 | lint:
6 | name: Tests ${{ matrix.php-versions }}
7 | runs-on: ubuntu-latest
8 | strategy:
9 | matrix:
10 | php-versions: ['8.1', '8.2', '8.3', 'nightly']
11 |
12 | steps:
13 | - name: Checkout repository
14 | uses: actions/checkout@v3
15 |
16 | - name: Setup PHP ${{ matrix.php-versions }}
17 | uses: shivammathur/setup-php@v2
18 | with:
19 | php-version: ${{ matrix.php-versions }}
20 |
21 | - name: Validate composer.json and composer.lock
22 | run: composer validate --strict
23 |
24 | - name: Compose install
25 | run: composer install --ignore-platform-reqs
26 |
27 | - name: Run tests
28 | run: composer test
29 |
--------------------------------------------------------------------------------
/src/CLI/Adapters/Generic.php:
--------------------------------------------------------------------------------
1 | =7.4",
20 | "utopia-php/servers": "0.2.*"
21 | },
22 | "require-dev": {
23 | "utopia-php/console": "0.0.*",
24 | "phpunit/phpunit": "^9.3",
25 | "squizlabs/php_codesniffer": "^3.6",
26 | "phpstan/phpstan": "^1.10",
27 | "laravel/pint": "1.2.*",
28 | "swoole/ide-helper": "4.8.8"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Eldad Fux
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/src/CLI/Adapter.php:
--------------------------------------------------------------------------------
1 | workerNum = $workerNum;
12 | }
13 |
14 | /**
15 | * Starts the Server.
16 | *
17 | * @param $callback
18 | * @return self
19 | */
20 | abstract public function start($callback): self;
21 |
22 | /**
23 | * Stops the Server.
24 | *
25 | * @return self
26 | */
27 | abstract public function stop(): self;
28 |
29 | /**
30 | * Is called when a Worker starts.
31 | *
32 | * @param callable $callback
33 | * @return self
34 | */
35 | abstract public function onWorkerStart(callable $callback): self;
36 |
37 | /**
38 | * Is called when a Worker stops.
39 | *
40 | * @param callable $callback
41 | * @return self
42 | */
43 | abstract public function onWorkerStop(callable $callback): self;
44 |
45 | /**
46 | * Is called when a job is processed.
47 | *
48 | * @param callable $callback
49 | * @return self
50 | */
51 | abstract public function onJob(callable $callback): self;
52 | }
53 |
--------------------------------------------------------------------------------
/src/CLI/Adapters/Swoole.php:
--------------------------------------------------------------------------------
1 | pool = new Pool($workerNum);
18 | }
19 |
20 | public function start($callback): self
21 | {
22 | Runtime::enableCoroutine();
23 | $this->pool->set(['enable_coroutine' => true]);
24 |
25 | $this->onWorkerStart($callback);
26 | $this->onWorkerStop(fn () => $this->pool->shutdown());
27 | $this->pool->start();
28 |
29 | return $this;
30 | }
31 |
32 | public function stop(): self
33 | {
34 | $this->pool->shutdown();
35 |
36 | return $this;
37 | }
38 |
39 | public function onWorkerStart($callback): self
40 | {
41 | $this->pool->on('WorkerStart', function (Pool $pool, string $workerId) use ($callback) {
42 | call_user_func($callback, $workerId);
43 | });
44 |
45 | return $this;
46 | }
47 |
48 | public function onWorkerStop(callable $callback): self
49 | {
50 | $this->pool->on('WorkerStop', function (Pool $pool, string $workerId) use ($callback) {
51 | call_user_func($callback, $workerId);
52 | });
53 |
54 | return $this;
55 | }
56 |
57 | public function onJob(callable $callback): self
58 | {
59 | call_user_func($callback);
60 |
61 | return $this;
62 | }
63 |
64 | public function getNative(): Pool
65 | {
66 | return $this->pool;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/tests/CLI/TaskTest.php:
--------------------------------------------------------------------------------
1 | task = new Task('test');
19 | }
20 |
21 | public function tearDown(): void
22 | {
23 | $this->task = null;
24 | }
25 |
26 | public function testName()
27 | {
28 | $this->assertEquals('test', $this->task->getName());
29 | }
30 |
31 | public function testDescription()
32 | {
33 | $this->task->desc('test task');
34 |
35 | $this->assertEquals('test task', $this->task->getDesc());
36 | }
37 |
38 | public function testAction()
39 | {
40 | $this->task->action(function () {
41 | return 'result';
42 | });
43 |
44 | $this->assertEquals('result', $this->task->getAction()());
45 | }
46 |
47 | public function testLabel()
48 | {
49 | $this->task->label('key', 'value');
50 |
51 | $this->assertEquals('value', $this->task->getLabel('key', 'default'));
52 | $this->assertEquals('default', $this->task->getLabel('unknown', 'default'));
53 | }
54 |
55 | public function testParam()
56 | {
57 | $this->task->param('email', 'me@example.com', new Text(0), 'Param with valid email address', false);
58 |
59 | $this->assertCount(1, $this->task->getParams());
60 | }
61 |
62 | public function testResources()
63 | {
64 | $this->assertEquals([], $this->task->getDependencies());
65 |
66 | $this->task
67 | ->inject('user')
68 | ->inject('time')
69 | ->action(function () {
70 | });
71 |
72 | $this->assertCount(2, $this->task->getDependencies());
73 | $this->assertEquals('user', $this->task->getDependencies()[0]);
74 | $this->assertEquals('time', $this->task->getDependencies()[1]);
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Utopia CLI
2 |
3 | [](https://travis-ci.com/utopia-php/cli)
4 | 
5 | [](https://appwrite.io/discord)
6 |
7 | Utopia framework CLI library is simple and lite library for extending Utopia PHP Framework to be able to code command line applications. This library is aiming to be as simple and easy to learn and use. This library is maintained by the [Appwrite team](https://appwrite.io).
8 |
9 | Although this library is part of the [Utopia Framework](https://github.com/utopia-php/framework) project it is dependency free and can be used as standalone with any other PHP project or framework.
10 |
11 | ## Getting Started
12 |
13 | Install using composer:
14 | ```bash
15 | composer require utopia-php/cli
16 | ```
17 |
18 | script.php
19 | ```php
20 | task('command-name')
32 | ->param('email', null, new Wildcard())
33 | ->action(function ($email) {
34 | Console::success($email);
35 | });
36 |
37 | $cli->run();
38 |
39 | ```
40 |
41 | And than, run from command line:
42 |
43 | ```bash
44 | php script.php command-name --email=me@example.com
45 | ```
46 |
47 | ### Hooks
48 |
49 | There are three types of hooks, init hooks, shutdown hooks and error hooks. Init hooks are executed before the task is executed. Shutdown hook is executed after task is executed before application shuts down. Finally error hooks are executed whenever there's an error in the application lifecycle. You can provide multiple hooks for each stage.
50 |
51 | ```php
52 | require_once __DIR__ . '/../../vendor/autoload.php';
53 |
54 | use Utopia\CLI\CLI;
55 | use Utopia\Console;
56 | use Utopia\Validator\Wildcard;
57 |
58 | CLI::setResource('res1', function() {
59 | return 'resource 1';
60 | })
61 |
62 | CLI::init()
63 | inject('res1')
64 | ->action(function($res1) {
65 | Console::info($res1);
66 | });
67 |
68 | CLI::error()
69 | ->inject('error')
70 | ->action(function($error) {
71 | Console::error('Error occurred ' . $error);
72 | });
73 |
74 | $cli = new CLI();
75 |
76 | $cli
77 | ->task('command-name')
78 | ->param('email', null, new Wildcard())
79 | ->action(function ($email) {
80 | Console::success($email);
81 | });
82 |
83 | $cli->run();
84 | ```
85 |
86 | ## System Requirements
87 |
88 | Utopia Framework requires PHP 7.4 or later. We recommend using the latest PHP version whenever possible.
89 |
90 | ## Copyright and license
91 |
92 | The MIT License (MIT) [http://www.opensource.org/licenses/mit-license.php](http://www.opensource.org/licenses/mit-license.php)
93 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to make participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity, expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | - Using welcoming and inclusive language
18 | - Being respectful of differing viewpoints and experiences
19 | - Gracefully accepting constructive criticism
20 | - Focusing on what is best for the community
21 | - Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | - The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | - Trolling, insulting/derogatory comments, and personal or political attacks
28 | - Public or private harassment
29 | - Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | - Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at team@appwrite.io. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | We would ❤️ for you to contribute to Utopia-php and help make it better! We want contributing to Utopia-php to be fun, enjoyable, and educational for anyone and everyone. All contributions are welcome, including issues, new docs as well as updates and tweaks, blog posts, workshops, and more.
4 |
5 | ## How to Start?
6 |
7 | If you are worried or don’t know where to start, check out our next section explaining what kind of help we could use and where can you get involved. You can reach out with questions to [Eldad Fux (@eldadfux)](https://twitter.com/eldadfux) or anyone from the [Appwrite team on Discord](https://discord.gg/GSeTUeA). You can also submit an issue, and a maintainer can guide you!
8 |
9 | ## Code of Conduct
10 |
11 | Help us keep Utopia-php open and inclusive. Please read and follow our [Code of Conduct](https://github.com/appwrite/appwrite/blob/master/CODE_OF_CONDUCT.md).
12 |
13 | ## Submit a Pull Request 🚀
14 |
15 | Branch naming convention is as following
16 |
17 | `TYPE-ISSUE_ID-DESCRIPTION`
18 |
19 | example:
20 |
21 | ```
22 | doc-548-submit-a-pull-request-section-to-contribution-guide
23 | ```
24 |
25 | When `TYPE` can be:
26 |
27 | - **feat** - is a new feature
28 | - **doc** - documentation only changes
29 | - **cicd** - changes related to CI/CD system
30 | - **fix** - a bug fix
31 | - **refactor** - code change that neither fixes a bug nor adds a feature
32 |
33 | **All PRs must include a commit message with the changes description!**
34 |
35 | For the initial start, fork the project and use git clone command to download the repository to your computer. A standard procedure for working on an issue would be to:
36 |
37 | 1. `git pull`, before creating a new branch, pull the changes from upstream. Your master needs to be up to date.
38 |
39 | ```
40 | $ git pull
41 | ```
42 |
43 | 2. Create new branch from `master` like: `doc-548-submit-a-pull-request-section-to-contribution-guide`
44 |
45 | ```
46 | $ git checkout -b [name_of_your_new_branch]
47 | ```
48 |
49 | 3. Work - commit - repeat ( be sure to be in your branch )
50 |
51 | 4. Push changes to GitHub
52 |
53 | ```
54 | $ git push origin [name_of_your_new_branch]
55 | ```
56 |
57 | 5. Submit your changes for review
58 | If you go to your repository on GitHub, you'll see a `Compare & pull request` button. Click on that button.
59 | 6. Start a Pull Request
60 | Now submit the pull request and click on `Create pull request`.
61 | 7. Get a code review approval/reject
62 | 8. After approval, merge your PR
63 | 9. GitHub will automatically delete the branch after the merge is done. (they can still be restored).
64 |
65 | ## Introducing New Features
66 |
67 | We would 💖 you to contribute to Utopia-php, but we would also like to make sure Utopia-php is as great as possible and loyal to its vision and mission statement 🙏.
68 |
69 | For us to find the right balance, please open an issue explaining your ideas before introducing a new pull request.
70 |
71 | This will allow the Utopia-php community to have sufficient discussion about the new feature value and how it fits in the product roadmap and vision.
72 |
73 | This is also important for the Utopia-php lead developers to be able to give technical input and different emphasis regarding the feature design and architecture. Some bigger features might need to go through our [RFC process](https://github.com/appwrite/rfc).
74 |
75 | ## Other Ways to Help
76 |
77 | Pull requests are great, but there are many other areas where you can help Utopia-php.
78 |
79 | ### Blogging & Speaking
80 |
81 | Blogging, speaking about, or creating tutorials about one of Utopia-php’s many features is great way to contribute and help our project grow.
82 |
83 | ### Presenting at Meetups
84 |
85 | Presenting at meetups and conferences about your Utopia-php projects. Your unique challenges and successes in building things with Utopia-php can provide great speaking material. We’d love to review your talk abstract/CFP, so get in touch with us if you’d like some help!
86 |
87 | ### Sending Feedbacks & Reporting Bugs
88 |
89 | Sending feedback is a great way for us to understand your different use cases of Utopia-php better. If you had any issues, bugs, or want to share about your experience, feel free to do so on our GitHub issues page or at our [Discord channel](https://discord.gg/GSeTUeA).
90 |
91 | ### Submitting New Ideas
92 |
93 | If you think Utopia-php could use a new feature, please open an issue on our GitHub repository, stating as much information as you can think about your new idea and it's implications. We would also use this issue to gather more information, get more feedback from the community, and have a proper discussion about the new feature.
94 |
95 | ### Improving Documentation
96 |
97 | Submitting documentation updates, enhancements, designs, or bug fixes. Spelling or grammar fixes will be very much appreciated.
98 |
99 | ### Helping Someone
100 |
101 | Searching for Utopia-php, GitHub or StackOverflow and helping someone else who needs help. You can also help by teaching others how to contribute to Utopia-php's repo!
102 |
--------------------------------------------------------------------------------
/tests/CLI/CLITest.php:
--------------------------------------------------------------------------------
1 | setName('rand')->setCallback(fn () => rand());
28 |
29 | $first = new Dependency();
30 | $first->setName('first')
31 | ->inject('second')
32 | ->setCallback(fn ($second) => 'first-'.$second);
33 |
34 | $second = new Dependency();
35 | $second->setName('second')->setCallback(fn () => 'second');
36 |
37 | $cli->setResource($rand);
38 | $cli->setResource($first);
39 | $cli->setResource($second);
40 |
41 | $second = $cli->getResource('second');
42 | $first = $cli->getResource('first');
43 | $this->assertEquals('second', $second);
44 | $this->assertEquals('first-second', $first);
45 |
46 | $resource = $cli->getResource('rand');
47 |
48 | $this->assertNotEmpty($resource);
49 | $this->assertEquals($resource, $cli->getResource('rand'));
50 | $this->assertEquals($resource, $cli->getResource('rand'));
51 | $this->assertEquals($resource, $cli->getResource('rand'));
52 | }
53 |
54 | public function testAppSuccess()
55 | {
56 | ob_start();
57 |
58 | $cli = new CLI(new Generic(), ['test.php', 'build', '--email=me@example.com']); // Mock command request
59 |
60 | $cli
61 | ->task('build')
62 | ->param('email', null, new Text(0), 'Valid email address')
63 | ->action(function ($email) {
64 | echo $email;
65 | });
66 |
67 | $cli->run();
68 |
69 | $result = ob_get_clean();
70 |
71 | $this->assertEquals('me@example.com', $result);
72 | }
73 |
74 | public function testAppFailure()
75 | {
76 | ob_start();
77 |
78 | $cli = new CLI(new Generic(), ['test.php', 'build', '--email=me.example.com']); // Mock command request
79 |
80 | $cli
81 | ->task('build')
82 | ->param('email', null, new Text(10), 'Valid email address')
83 | ->action(function ($email) {
84 | echo $email;
85 | });
86 |
87 | $cli->run();
88 |
89 | $result = ob_get_clean();
90 |
91 | $this->assertEquals('', $result);
92 | }
93 |
94 | public function testAppArray()
95 | {
96 | ob_start();
97 |
98 | $cli = new CLI(new Generic(), ['test.php', 'build', '--email=me@example.com', '--list=item1', '--list=item2']); // Mock command request
99 |
100 | $cli
101 | ->task('build')
102 | ->param('email', null, new Text(0), 'Valid email address')
103 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings')
104 | ->action(function ($email, $list) {
105 | echo $email.'-'.implode('-', $list);
106 | });
107 |
108 | $cli->run();
109 |
110 | $result = ob_get_clean();
111 |
112 | $this->assertEquals('me@example.com-item1-item2', $result);
113 | }
114 |
115 | public function testGetTasks()
116 | {
117 | $cli = new CLI(new Generic(), ['test.php', 'build', '--email=me@example.com', '--list=item1', '--list=item2']); // Mock command request
118 |
119 | $cli
120 | ->task('build1')
121 | ->param('email', null, new Text(0), 'Valid email address')
122 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings')
123 | ->action(function ($email, $list) {
124 | echo $email.'-'.implode('-', $list);
125 | });
126 |
127 | $cli
128 | ->task('build2')
129 | ->param('email', null, new Text(0), 'Valid email address')
130 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings')
131 | ->action(function ($email, $list) {
132 | echo $email.'-'.implode('-', $list);
133 | });
134 |
135 | $this->assertCount(2, $cli->getTasks());
136 | }
137 |
138 | public function testGetArgs()
139 | {
140 | $cli = new CLI(new Generic(), ['test.php', 'build', '--email=me@example.com', '--list=item1', '--list=item2']); // Mock command request
141 |
142 | $cli
143 | ->task('build1')
144 | ->param('email', null, new Text(0), 'Valid email address')
145 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings')
146 | ->action(function ($email, $list) {
147 | echo $email.'-'.implode('-', $list);
148 | });
149 |
150 | $cli
151 | ->task('build2')
152 | ->param('email', null, new Text(0), 'Valid email address')
153 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings')
154 | ->action(function ($email, $list) {
155 | echo $email.'-'.implode('-', $list);
156 | });
157 |
158 | $this->assertCount(2, $cli->getArgs());
159 | $this->assertEquals(['email' => 'me@example.com', 'list' => ['item1', 'item2']], $cli->getArgs());
160 | }
161 |
162 | public function testHook()
163 | {
164 | $cli = new CLI(new Generic(), ['test.php', 'build', '--email=me@example.com', '--list=item1', '--list=item2']);
165 |
166 | $cli
167 | ->init()
168 | ->action(function () {
169 | echo '(init)-';
170 | });
171 |
172 | $cli
173 | ->shutdown()
174 | ->action(function () {
175 | echo '-(shutdown)';
176 | });
177 |
178 | $cli
179 | ->task('build')
180 | ->param('email', null, new Text(0), 'Valid email address')
181 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings')
182 | ->action(function ($email, $list) {
183 | echo $email.'-'.implode('-', $list);
184 | });
185 |
186 | \ob_start();
187 |
188 | $cli->run();
189 | $result = \ob_get_clean();
190 |
191 | $this->assertEquals('(init)-me@example.com-item1-item2-(shutdown)', $result);
192 | }
193 |
194 | public function testInjection()
195 | {
196 | ob_start();
197 |
198 | $cli = new CLI(new Generic(), ['test.php', 'build', '--email=me@example.com']);
199 |
200 | $test = new Dependency();
201 | $test->setName('test')->setCallback(fn () => 'test-value');
202 |
203 | $cli->setResource($test);
204 |
205 | $cli->task('build')
206 | ->inject('test')
207 | ->param('email', null, new Text(15), 'valid email address')
208 | ->action(function ($test, $email) {
209 | echo $test.'-'.$email;
210 | });
211 |
212 | $cli->run();
213 |
214 | $result = ob_get_clean();
215 |
216 | $this->assertEquals('test-value-me@example.com', $result);
217 | }
218 |
219 | public function testMatch()
220 | {
221 | $cli = new CLI(new Generic(), ['test.php', 'build2', '--email=me@example.com', '--list=item1', '--list=item2']); // Mock command request
222 |
223 | $cli
224 | ->task('build1')
225 | ->param('email', null, new Text(0), 'Valid email address')
226 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings')
227 | ->action(function ($email, $list) {
228 | echo $email.'-'.implode('-', $list);
229 | });
230 |
231 | $cli
232 | ->task('build2')
233 | ->param('email', null, new Text(0), 'Valid email address')
234 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings')
235 | ->action(function ($email, $list) {
236 | echo $email.'-'.implode('-', $list);
237 | });
238 |
239 | $this->assertEquals('build2', $cli->match()->getName());
240 |
241 | $cli = new CLI(new Generic(), ['test.php', 'buildx', '--email=me@example.com', '--list=item1', '--list=item2']); // Mock command request
242 |
243 | $cli
244 | ->task('build1')
245 | ->param('email', null, new Text(0), 'Valid email address')
246 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings')
247 | ->action(function ($email, $list) {
248 | echo $email.'-'.implode('-', $list);
249 | });
250 |
251 | $cli
252 | ->task('build2')
253 | ->param('email', null, new Text(0), 'Valid email address')
254 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings')
255 | ->action(function ($email, $list) {
256 | echo $email.'-'.implode('-', $list);
257 | });
258 |
259 | $this->assertEquals(null, $cli->match());
260 | }
261 |
262 | public function testEscaping()
263 | {
264 | ob_start();
265 |
266 | $database = 'appwrite://database_db_fra1_self_hosted_0_0?database=appwrite&namespace=_1';
267 |
268 | $cli = new CLI(new Generic(), ['test.php', 'connect', '--database='.$database]);
269 |
270 | $cli
271 | ->task('connect')
272 | ->param('database', null, new Text(2048), 'Database DSN')
273 | ->action(function ($database) {
274 | echo $database;
275 | });
276 |
277 | $cli->run();
278 |
279 | $result = ob_get_clean();
280 |
281 | $this->assertEquals($database, $result);
282 | }
283 | }
284 |
--------------------------------------------------------------------------------
/src/CLI/CLI.php:
--------------------------------------------------------------------------------
1 | args = $this->parse((! empty($args) || ! isset($_SERVER['argv'])) ? $args : $_SERVER['argv']);
97 |
98 | @\cli_set_process_title($this->command);
99 |
100 | $this->adapter = $adapter ?? new Generic();
101 | $this->container = new Container();
102 | }
103 |
104 | /**
105 | * Init
106 | *
107 | * Set a callback function that will be initialized on application start
108 | *
109 | * @return Hook
110 | */
111 | public function init(): Hook
112 | {
113 | $hook = new Hook();
114 | $this->init[] = $hook;
115 |
116 | return $hook;
117 | }
118 |
119 | /**
120 | * Shutdown
121 | *
122 | * Set a callback function that will be initialized on application end
123 | *
124 | * @return Hook
125 | */
126 | public function shutdown(): Hook
127 | {
128 | $hook = new Hook();
129 | $this->shutdown[] = $hook;
130 |
131 | return $hook;
132 | }
133 |
134 | /**
135 | * Error
136 | *
137 | * An error callback for failed or no matched requests
138 | *
139 | * @return Hook
140 | */
141 | public function error(): Hook
142 | {
143 | $hook = new Hook();
144 | $this->errors[] = $hook;
145 |
146 | return $hook;
147 | }
148 |
149 | /**
150 | * Task
151 | *
152 | * Add a new command task
153 | *
154 | * @param string $name
155 | * @return Task
156 | */
157 | public function task(string $name): Task
158 | {
159 | $task = new Task($name);
160 |
161 | $this->tasks[$name] = $task;
162 |
163 | return $task;
164 | }
165 |
166 | /**
167 | * If a resource has been created return it, otherwise create it and then return it
168 | *
169 | * @param string $name
170 | * @return mixed
171 | *
172 | * @throws Exception
173 | */
174 | public function getResource(string $name): mixed
175 | {
176 | if (! $this->container->has($name)) {
177 | throw new Exception('Failed to find resource: "'.$name.'"');
178 | }
179 |
180 | return $this->container->get($name);
181 | }
182 |
183 | /**
184 | * Get Resources By List
185 | *
186 | * @param array $list
187 | * @return array
188 | *
189 | * @throws Exception
190 | */
191 | public function getResources(array $list): array
192 | {
193 | $resources = [];
194 |
195 | foreach ($list as $name) {
196 | $resources[$name] = $this->getResource($name);
197 | }
198 |
199 | return $resources;
200 | }
201 |
202 | /**
203 | * Set a new resource callback
204 | *
205 | * @param Dependency $dependency
206 | * @return void
207 | *
208 | * @throws Exception
209 | */
210 | public function setResource(Dependency $dependency): void
211 | {
212 | $this->container->set($dependency);
213 | }
214 |
215 | /**
216 | * task-name --foo=test
217 | *
218 | * @param array $args
219 | * @return array
220 | *
221 | * @throws Exception
222 | */
223 | public function parse(array $args): array
224 | {
225 | \array_shift($args); // Remove script path from args
226 |
227 | if (isset($args[0])) {
228 | $this->command = \array_shift($args);
229 | } else {
230 | throw new Exception('Missing command');
231 | }
232 |
233 | $output = [];
234 |
235 | foreach ($args as &$arg) {
236 | if (\substr($arg, 0, 2) === '--') {
237 | $arg = \substr($arg, 2);
238 | }
239 | }
240 |
241 | /**
242 | * Refer to this answer
243 | * https://stackoverflow.com/questions/18669499/php-issue-with-looping-over-an-array-twice-using-foreach-and-passing-value-by-re/18669732
244 | */
245 | unset($arg);
246 |
247 | foreach ($args as $arg) {
248 | $pair = explode('=', $arg, 2);
249 | $key = $pair[0];
250 | $value = $pair[1];
251 | $output[$key][] = $value;
252 | }
253 |
254 | foreach ($output as $key => $value) {
255 | /**
256 | * If there is only one element in a particular key
257 | * unshift the value out of the array
258 | */
259 | if (count($value) == 1) {
260 | $output[$key] = array_shift($output[$key]);
261 | }
262 | }
263 |
264 | return $output;
265 | }
266 |
267 | /**
268 | * Find the command that should be triggered
269 | *
270 | * @return Task|null
271 | */
272 | public function match(): ?Task
273 | {
274 | return $this->tasks[$this->command] ?? null;
275 | }
276 |
277 | /**
278 | * Get Params
279 | * Get runtime params for the provided Hook
280 | *
281 | * @param Hook $hook
282 | * @return array
283 | *
284 | * @throws Exception
285 | */
286 | protected function getParams(Hook $hook): array
287 | {
288 | $params = [];
289 |
290 | foreach ($hook->getParams() as $key => $param) {
291 | $value = (isset($this->args[$key])) ? $this->args[$key] : $param['default'];
292 |
293 | $this->validate($key, $param, $value);
294 |
295 | $params[$this->camelCaseIt($key)] = $value;
296 | }
297 |
298 | foreach ($hook->getDependencies() as $dependency) {
299 | if (array_key_exists($this->camelCaseIt($dependency), $params)) {
300 | continue;
301 | }
302 |
303 | $params[$this->camelCaseIt($dependency)] = $this->getResource($dependency);
304 | }
305 |
306 | return $params;
307 | }
308 |
309 | /**
310 | * Run
311 | *
312 | * @return $this
313 | *
314 | * @throws Exception
315 | */
316 | public function run(): self
317 | {
318 | $this->adapter->start(function () {
319 | $command = $this->match();
320 |
321 | try {
322 | if ($command) {
323 | foreach ($this->init as $hook) {
324 | \call_user_func_array($hook->getAction(), $this->getParams($hook));
325 | }
326 |
327 | // Call the callback with the matched positions as params
328 | \call_user_func_array($command->getAction(), $this->getParams($command));
329 |
330 | foreach ($this->shutdown as $hook) {
331 | \call_user_func_array($hook->getAction(), $this->getParams($hook));
332 | }
333 | } else {
334 | throw new Exception('No command found');
335 | }
336 | } catch (Exception $e) {
337 | foreach ($this->errors as $hook) {
338 | $error = new Dependency();
339 | $error->setName('error')->setCallback(fn () => $e);
340 |
341 | $this->setResource($error);
342 | \call_user_func_array($hook->getAction(), $this->getParams($hook));
343 | }
344 | }
345 | });
346 |
347 | return $this;
348 | }
349 |
350 | /**
351 | * Get list of all tasks
352 | *
353 | * @return Task[]
354 | */
355 | public function getTasks(): array
356 | {
357 | return $this->tasks;
358 | }
359 |
360 | /**
361 | * Get list of all args
362 | *
363 | * @return array
364 | */
365 | public function getArgs(): array
366 | {
367 | return $this->args;
368 | }
369 |
370 | /**
371 | * Validate Param
372 | *
373 | * Creates an validator instance and validate given value with given rules.
374 | *
375 | * @param string $key
376 | * @param array $param
377 | * @param mixed $value
378 | *
379 | * @throws Exception
380 | */
381 | protected function validate(string $key, array $param, $value): void
382 | {
383 | if ('' !== $value) {
384 | // checking whether the class exists
385 | $validator = $param['validator'];
386 |
387 | if (\is_callable($validator)) {
388 | $validator = $validator();
389 | }
390 |
391 | // is the validator object an instance of the Validator class
392 | if (! $validator instanceof Validator) {
393 | throw new Exception('Validator object is not an instance of the Validator class', 500);
394 | }
395 |
396 | if (! $validator->isValid($value)) {
397 | throw new Exception('Invalid '.$key.': '.$validator->getDescription(), 400);
398 | }
399 | } else {
400 | if (! $param['optional']) {
401 | throw new Exception('Param "'.$key.'" is not optional.', 400);
402 | }
403 | }
404 | }
405 |
406 | public function setContainer($container): self
407 | {
408 | $this->container = $container;
409 |
410 | return $this;
411 | }
412 |
413 | public function reset(): void
414 | {
415 | $this->container = new Container();
416 | }
417 |
418 | private function camelCaseIt($key): string
419 | {
420 | $key = str_replace('-', '_', $key);
421 | $camelCase = \lcfirst(\str_replace('_', '', \ucwords($key, '_')));
422 |
423 | return $camelCase;
424 | }
425 | }
426 |
--------------------------------------------------------------------------------
/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": "3a9f5f12fa406f92e927dc9b81050e77",
8 | "packages": [
9 | {
10 | "name": "utopia-php/di",
11 | "version": "0.1.0",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/utopia-php/di.git",
15 | "reference": "22490c95f7ac3898ed1c33f1b1b5dd577305ee31"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/utopia-php/di/zipball/22490c95f7ac3898ed1c33f1b1b5dd577305ee31",
20 | "reference": "22490c95f7ac3898ed1c33f1b1b5dd577305ee31",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "php": ">=8.2"
25 | },
26 | "require-dev": {
27 | "laravel/pint": "^1.2",
28 | "phpbench/phpbench": "^1.2",
29 | "phpstan/phpstan": "^1.10",
30 | "phpunit/phpunit": "^9.5.25",
31 | "swoole/ide-helper": "4.8.3"
32 | },
33 | "type": "library",
34 | "autoload": {
35 | "psr-4": {
36 | "Utopia\\": "src/",
37 | "Tests\\E2E\\": "tests/e2e"
38 | }
39 | },
40 | "notification-url": "https://packagist.org/downloads/",
41 | "license": [
42 | "MIT"
43 | ],
44 | "description": "A simple and lite library for managing dependency injections",
45 | "keywords": [
46 | "framework",
47 | "http",
48 | "php",
49 | "upf"
50 | ],
51 | "support": {
52 | "issues": "https://github.com/utopia-php/di/issues",
53 | "source": "https://github.com/utopia-php/di/tree/0.1.0"
54 | },
55 | "time": "2024-08-08T14:35:19+00:00"
56 | },
57 | {
58 | "name": "utopia-php/servers",
59 | "version": "0.2.0",
60 | "source": {
61 | "type": "git",
62 | "url": "https://github.com/utopia-php/servers.git",
63 | "reference": "92de8b5cd52fe2dc4bc873c39f8f4e8bb2ef2332"
64 | },
65 | "dist": {
66 | "type": "zip",
67 | "url": "https://api.github.com/repos/utopia-php/servers/zipball/92de8b5cd52fe2dc4bc873c39f8f4e8bb2ef2332",
68 | "reference": "92de8b5cd52fe2dc4bc873c39f8f4e8bb2ef2332",
69 | "shasum": ""
70 | },
71 | "require": {
72 | "php": ">=8.0",
73 | "utopia-php/di": "0.1.*",
74 | "utopia-php/validators": "0.0.*"
75 | },
76 | "require-dev": {
77 | "laravel/pint": "^0.2.3",
78 | "phpstan/phpstan": "^1.8",
79 | "phpunit/phpunit": "^9.5.5"
80 | },
81 | "type": "library",
82 | "autoload": {
83 | "psr-4": {
84 | "Utopia\\Servers\\": "src/Servers"
85 | }
86 | },
87 | "notification-url": "https://packagist.org/downloads/",
88 | "license": [
89 | "MIT"
90 | ],
91 | "authors": [
92 | {
93 | "name": "Team Appwrite",
94 | "email": "team@appwrite.io"
95 | }
96 | ],
97 | "description": "A base library for building Utopia style servers.",
98 | "keywords": [
99 | "framework",
100 | "php",
101 | "servers",
102 | "upf",
103 | "utopia"
104 | ],
105 | "support": {
106 | "issues": "https://github.com/utopia-php/servers/issues",
107 | "source": "https://github.com/utopia-php/servers/tree/0.2.0"
108 | },
109 | "time": "2025-10-21T08:56:24+00:00"
110 | },
111 | {
112 | "name": "utopia-php/validators",
113 | "version": "0.0.2",
114 | "source": {
115 | "type": "git",
116 | "url": "https://github.com/utopia-php/validators.git",
117 | "reference": "894210695c5d35fa248fb65f7fe7237b6ff4fb0b"
118 | },
119 | "dist": {
120 | "type": "zip",
121 | "url": "https://api.github.com/repos/utopia-php/validators/zipball/894210695c5d35fa248fb65f7fe7237b6ff4fb0b",
122 | "reference": "894210695c5d35fa248fb65f7fe7237b6ff4fb0b",
123 | "shasum": ""
124 | },
125 | "require": {
126 | "php": ">=8.1"
127 | },
128 | "require-dev": {
129 | "ext-xdebug": "*",
130 | "laravel/pint": "^1.2",
131 | "phpstan/phpstan": "1.*",
132 | "phpunit/phpunit": "^9.5.25"
133 | },
134 | "type": "library",
135 | "autoload": {
136 | "psr-4": {
137 | "Utopia\\": "src/"
138 | }
139 | },
140 | "notification-url": "https://packagist.org/downloads/",
141 | "license": [
142 | "MIT"
143 | ],
144 | "description": "A lightweight collection of reusable validators for Utopia projects",
145 | "keywords": [
146 | "php",
147 | "utopia",
148 | "validation",
149 | "validator"
150 | ],
151 | "support": {
152 | "issues": "https://github.com/utopia-php/validators/issues",
153 | "source": "https://github.com/utopia-php/validators/tree/0.0.2"
154 | },
155 | "time": "2025-10-20T21:52:28+00:00"
156 | }
157 | ],
158 | "packages-dev": [
159 | {
160 | "name": "doctrine/instantiator",
161 | "version": "2.0.0",
162 | "source": {
163 | "type": "git",
164 | "url": "https://github.com/doctrine/instantiator.git",
165 | "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0"
166 | },
167 | "dist": {
168 | "type": "zip",
169 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
170 | "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
171 | "shasum": ""
172 | },
173 | "require": {
174 | "php": "^8.1"
175 | },
176 | "require-dev": {
177 | "doctrine/coding-standard": "^11",
178 | "ext-pdo": "*",
179 | "ext-phar": "*",
180 | "phpbench/phpbench": "^1.2",
181 | "phpstan/phpstan": "^1.9.4",
182 | "phpstan/phpstan-phpunit": "^1.3",
183 | "phpunit/phpunit": "^9.5.27",
184 | "vimeo/psalm": "^5.4"
185 | },
186 | "type": "library",
187 | "autoload": {
188 | "psr-4": {
189 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
190 | }
191 | },
192 | "notification-url": "https://packagist.org/downloads/",
193 | "license": [
194 | "MIT"
195 | ],
196 | "authors": [
197 | {
198 | "name": "Marco Pivetta",
199 | "email": "ocramius@gmail.com",
200 | "homepage": "https://ocramius.github.io/"
201 | }
202 | ],
203 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
204 | "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
205 | "keywords": [
206 | "constructor",
207 | "instantiate"
208 | ],
209 | "support": {
210 | "issues": "https://github.com/doctrine/instantiator/issues",
211 | "source": "https://github.com/doctrine/instantiator/tree/2.0.0"
212 | },
213 | "funding": [
214 | {
215 | "url": "https://www.doctrine-project.org/sponsorship.html",
216 | "type": "custom"
217 | },
218 | {
219 | "url": "https://www.patreon.com/phpdoctrine",
220 | "type": "patreon"
221 | },
222 | {
223 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
224 | "type": "tidelift"
225 | }
226 | ],
227 | "time": "2022-12-30T00:23:10+00:00"
228 | },
229 | {
230 | "name": "laravel/pint",
231 | "version": "v1.2.1",
232 | "source": {
233 | "type": "git",
234 | "url": "https://github.com/laravel/pint.git",
235 | "reference": "e60e2112ee779ce60f253695b273d1646a17d6f1"
236 | },
237 | "dist": {
238 | "type": "zip",
239 | "url": "https://api.github.com/repos/laravel/pint/zipball/e60e2112ee779ce60f253695b273d1646a17d6f1",
240 | "reference": "e60e2112ee779ce60f253695b273d1646a17d6f1",
241 | "shasum": ""
242 | },
243 | "require": {
244 | "ext-json": "*",
245 | "ext-mbstring": "*",
246 | "ext-tokenizer": "*",
247 | "ext-xml": "*",
248 | "php": "^8.0"
249 | },
250 | "require-dev": {
251 | "friendsofphp/php-cs-fixer": "^3.11.0",
252 | "illuminate/view": "^9.32.0",
253 | "laravel-zero/framework": "^9.2.0",
254 | "mockery/mockery": "^1.5.1",
255 | "nunomaduro/larastan": "^2.2.0",
256 | "nunomaduro/termwind": "^1.14.0",
257 | "pestphp/pest": "^1.22.1"
258 | },
259 | "bin": [
260 | "builds/pint"
261 | ],
262 | "type": "project",
263 | "autoload": {
264 | "psr-4": {
265 | "App\\": "app/",
266 | "Database\\Seeders\\": "database/seeders/",
267 | "Database\\Factories\\": "database/factories/"
268 | }
269 | },
270 | "notification-url": "https://packagist.org/downloads/",
271 | "license": [
272 | "MIT"
273 | ],
274 | "authors": [
275 | {
276 | "name": "Nuno Maduro",
277 | "email": "enunomaduro@gmail.com"
278 | }
279 | ],
280 | "description": "An opinionated code formatter for PHP.",
281 | "homepage": "https://laravel.com",
282 | "keywords": [
283 | "format",
284 | "formatter",
285 | "lint",
286 | "linter",
287 | "php"
288 | ],
289 | "support": {
290 | "issues": "https://github.com/laravel/pint/issues",
291 | "source": "https://github.com/laravel/pint"
292 | },
293 | "time": "2022-11-29T16:25:20+00:00"
294 | },
295 | {
296 | "name": "myclabs/deep-copy",
297 | "version": "1.13.4",
298 | "source": {
299 | "type": "git",
300 | "url": "https://github.com/myclabs/DeepCopy.git",
301 | "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a"
302 | },
303 | "dist": {
304 | "type": "zip",
305 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a",
306 | "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a",
307 | "shasum": ""
308 | },
309 | "require": {
310 | "php": "^7.1 || ^8.0"
311 | },
312 | "conflict": {
313 | "doctrine/collections": "<1.6.8",
314 | "doctrine/common": "<2.13.3 || >=3 <3.2.2"
315 | },
316 | "require-dev": {
317 | "doctrine/collections": "^1.6.8",
318 | "doctrine/common": "^2.13.3 || ^3.2.2",
319 | "phpspec/prophecy": "^1.10",
320 | "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
321 | },
322 | "type": "library",
323 | "autoload": {
324 | "files": [
325 | "src/DeepCopy/deep_copy.php"
326 | ],
327 | "psr-4": {
328 | "DeepCopy\\": "src/DeepCopy/"
329 | }
330 | },
331 | "notification-url": "https://packagist.org/downloads/",
332 | "license": [
333 | "MIT"
334 | ],
335 | "description": "Create deep copies (clones) of your objects",
336 | "keywords": [
337 | "clone",
338 | "copy",
339 | "duplicate",
340 | "object",
341 | "object graph"
342 | ],
343 | "support": {
344 | "issues": "https://github.com/myclabs/DeepCopy/issues",
345 | "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4"
346 | },
347 | "funding": [
348 | {
349 | "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
350 | "type": "tidelift"
351 | }
352 | ],
353 | "time": "2025-08-01T08:46:24+00:00"
354 | },
355 | {
356 | "name": "nikic/php-parser",
357 | "version": "v5.6.1",
358 | "source": {
359 | "type": "git",
360 | "url": "https://github.com/nikic/PHP-Parser.git",
361 | "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2"
362 | },
363 | "dist": {
364 | "type": "zip",
365 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
366 | "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
367 | "shasum": ""
368 | },
369 | "require": {
370 | "ext-ctype": "*",
371 | "ext-json": "*",
372 | "ext-tokenizer": "*",
373 | "php": ">=7.4"
374 | },
375 | "require-dev": {
376 | "ircmaxell/php-yacc": "^0.0.7",
377 | "phpunit/phpunit": "^9.0"
378 | },
379 | "bin": [
380 | "bin/php-parse"
381 | ],
382 | "type": "library",
383 | "extra": {
384 | "branch-alias": {
385 | "dev-master": "5.x-dev"
386 | }
387 | },
388 | "autoload": {
389 | "psr-4": {
390 | "PhpParser\\": "lib/PhpParser"
391 | }
392 | },
393 | "notification-url": "https://packagist.org/downloads/",
394 | "license": [
395 | "BSD-3-Clause"
396 | ],
397 | "authors": [
398 | {
399 | "name": "Nikita Popov"
400 | }
401 | ],
402 | "description": "A PHP parser written in PHP",
403 | "keywords": [
404 | "parser",
405 | "php"
406 | ],
407 | "support": {
408 | "issues": "https://github.com/nikic/PHP-Parser/issues",
409 | "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1"
410 | },
411 | "time": "2025-08-13T20:13:15+00:00"
412 | },
413 | {
414 | "name": "phar-io/manifest",
415 | "version": "2.0.4",
416 | "source": {
417 | "type": "git",
418 | "url": "https://github.com/phar-io/manifest.git",
419 | "reference": "54750ef60c58e43759730615a392c31c80e23176"
420 | },
421 | "dist": {
422 | "type": "zip",
423 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
424 | "reference": "54750ef60c58e43759730615a392c31c80e23176",
425 | "shasum": ""
426 | },
427 | "require": {
428 | "ext-dom": "*",
429 | "ext-libxml": "*",
430 | "ext-phar": "*",
431 | "ext-xmlwriter": "*",
432 | "phar-io/version": "^3.0.1",
433 | "php": "^7.2 || ^8.0"
434 | },
435 | "type": "library",
436 | "extra": {
437 | "branch-alias": {
438 | "dev-master": "2.0.x-dev"
439 | }
440 | },
441 | "autoload": {
442 | "classmap": [
443 | "src/"
444 | ]
445 | },
446 | "notification-url": "https://packagist.org/downloads/",
447 | "license": [
448 | "BSD-3-Clause"
449 | ],
450 | "authors": [
451 | {
452 | "name": "Arne Blankerts",
453 | "email": "arne@blankerts.de",
454 | "role": "Developer"
455 | },
456 | {
457 | "name": "Sebastian Heuer",
458 | "email": "sebastian@phpeople.de",
459 | "role": "Developer"
460 | },
461 | {
462 | "name": "Sebastian Bergmann",
463 | "email": "sebastian@phpunit.de",
464 | "role": "Developer"
465 | }
466 | ],
467 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
468 | "support": {
469 | "issues": "https://github.com/phar-io/manifest/issues",
470 | "source": "https://github.com/phar-io/manifest/tree/2.0.4"
471 | },
472 | "funding": [
473 | {
474 | "url": "https://github.com/theseer",
475 | "type": "github"
476 | }
477 | ],
478 | "time": "2024-03-03T12:33:53+00:00"
479 | },
480 | {
481 | "name": "phar-io/version",
482 | "version": "3.2.1",
483 | "source": {
484 | "type": "git",
485 | "url": "https://github.com/phar-io/version.git",
486 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
487 | },
488 | "dist": {
489 | "type": "zip",
490 | "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
491 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
492 | "shasum": ""
493 | },
494 | "require": {
495 | "php": "^7.2 || ^8.0"
496 | },
497 | "type": "library",
498 | "autoload": {
499 | "classmap": [
500 | "src/"
501 | ]
502 | },
503 | "notification-url": "https://packagist.org/downloads/",
504 | "license": [
505 | "BSD-3-Clause"
506 | ],
507 | "authors": [
508 | {
509 | "name": "Arne Blankerts",
510 | "email": "arne@blankerts.de",
511 | "role": "Developer"
512 | },
513 | {
514 | "name": "Sebastian Heuer",
515 | "email": "sebastian@phpeople.de",
516 | "role": "Developer"
517 | },
518 | {
519 | "name": "Sebastian Bergmann",
520 | "email": "sebastian@phpunit.de",
521 | "role": "Developer"
522 | }
523 | ],
524 | "description": "Library for handling version information and constraints",
525 | "support": {
526 | "issues": "https://github.com/phar-io/version/issues",
527 | "source": "https://github.com/phar-io/version/tree/3.2.1"
528 | },
529 | "time": "2022-02-21T01:04:05+00:00"
530 | },
531 | {
532 | "name": "phpstan/phpstan",
533 | "version": "1.12.32",
534 | "dist": {
535 | "type": "zip",
536 | "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2770dcdf5078d0b0d53f94317e06affe88419aa8",
537 | "reference": "2770dcdf5078d0b0d53f94317e06affe88419aa8",
538 | "shasum": ""
539 | },
540 | "require": {
541 | "php": "^7.2|^8.0"
542 | },
543 | "conflict": {
544 | "phpstan/phpstan-shim": "*"
545 | },
546 | "bin": [
547 | "phpstan",
548 | "phpstan.phar"
549 | ],
550 | "type": "library",
551 | "autoload": {
552 | "files": [
553 | "bootstrap.php"
554 | ]
555 | },
556 | "notification-url": "https://packagist.org/downloads/",
557 | "license": [
558 | "MIT"
559 | ],
560 | "description": "PHPStan - PHP Static Analysis Tool",
561 | "keywords": [
562 | "dev",
563 | "static analysis"
564 | ],
565 | "support": {
566 | "docs": "https://phpstan.org/user-guide/getting-started",
567 | "forum": "https://github.com/phpstan/phpstan/discussions",
568 | "issues": "https://github.com/phpstan/phpstan/issues",
569 | "security": "https://github.com/phpstan/phpstan/security/policy",
570 | "source": "https://github.com/phpstan/phpstan-src"
571 | },
572 | "funding": [
573 | {
574 | "url": "https://github.com/ondrejmirtes",
575 | "type": "github"
576 | },
577 | {
578 | "url": "https://github.com/phpstan",
579 | "type": "github"
580 | }
581 | ],
582 | "time": "2025-09-30T10:16:31+00:00"
583 | },
584 | {
585 | "name": "phpunit/php-code-coverage",
586 | "version": "9.2.32",
587 | "source": {
588 | "type": "git",
589 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
590 | "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5"
591 | },
592 | "dist": {
593 | "type": "zip",
594 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5",
595 | "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5",
596 | "shasum": ""
597 | },
598 | "require": {
599 | "ext-dom": "*",
600 | "ext-libxml": "*",
601 | "ext-xmlwriter": "*",
602 | "nikic/php-parser": "^4.19.1 || ^5.1.0",
603 | "php": ">=7.3",
604 | "phpunit/php-file-iterator": "^3.0.6",
605 | "phpunit/php-text-template": "^2.0.4",
606 | "sebastian/code-unit-reverse-lookup": "^2.0.3",
607 | "sebastian/complexity": "^2.0.3",
608 | "sebastian/environment": "^5.1.5",
609 | "sebastian/lines-of-code": "^1.0.4",
610 | "sebastian/version": "^3.0.2",
611 | "theseer/tokenizer": "^1.2.3"
612 | },
613 | "require-dev": {
614 | "phpunit/phpunit": "^9.6"
615 | },
616 | "suggest": {
617 | "ext-pcov": "PHP extension that provides line coverage",
618 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
619 | },
620 | "type": "library",
621 | "extra": {
622 | "branch-alias": {
623 | "dev-main": "9.2.x-dev"
624 | }
625 | },
626 | "autoload": {
627 | "classmap": [
628 | "src/"
629 | ]
630 | },
631 | "notification-url": "https://packagist.org/downloads/",
632 | "license": [
633 | "BSD-3-Clause"
634 | ],
635 | "authors": [
636 | {
637 | "name": "Sebastian Bergmann",
638 | "email": "sebastian@phpunit.de",
639 | "role": "lead"
640 | }
641 | ],
642 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
643 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
644 | "keywords": [
645 | "coverage",
646 | "testing",
647 | "xunit"
648 | ],
649 | "support": {
650 | "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
651 | "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
652 | "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32"
653 | },
654 | "funding": [
655 | {
656 | "url": "https://github.com/sebastianbergmann",
657 | "type": "github"
658 | }
659 | ],
660 | "time": "2024-08-22T04:23:01+00:00"
661 | },
662 | {
663 | "name": "phpunit/php-file-iterator",
664 | "version": "3.0.6",
665 | "source": {
666 | "type": "git",
667 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
668 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf"
669 | },
670 | "dist": {
671 | "type": "zip",
672 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
673 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
674 | "shasum": ""
675 | },
676 | "require": {
677 | "php": ">=7.3"
678 | },
679 | "require-dev": {
680 | "phpunit/phpunit": "^9.3"
681 | },
682 | "type": "library",
683 | "extra": {
684 | "branch-alias": {
685 | "dev-master": "3.0-dev"
686 | }
687 | },
688 | "autoload": {
689 | "classmap": [
690 | "src/"
691 | ]
692 | },
693 | "notification-url": "https://packagist.org/downloads/",
694 | "license": [
695 | "BSD-3-Clause"
696 | ],
697 | "authors": [
698 | {
699 | "name": "Sebastian Bergmann",
700 | "email": "sebastian@phpunit.de",
701 | "role": "lead"
702 | }
703 | ],
704 | "description": "FilterIterator implementation that filters files based on a list of suffixes.",
705 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
706 | "keywords": [
707 | "filesystem",
708 | "iterator"
709 | ],
710 | "support": {
711 | "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
712 | "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6"
713 | },
714 | "funding": [
715 | {
716 | "url": "https://github.com/sebastianbergmann",
717 | "type": "github"
718 | }
719 | ],
720 | "time": "2021-12-02T12:48:52+00:00"
721 | },
722 | {
723 | "name": "phpunit/php-invoker",
724 | "version": "3.1.1",
725 | "source": {
726 | "type": "git",
727 | "url": "https://github.com/sebastianbergmann/php-invoker.git",
728 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67"
729 | },
730 | "dist": {
731 | "type": "zip",
732 | "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
733 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
734 | "shasum": ""
735 | },
736 | "require": {
737 | "php": ">=7.3"
738 | },
739 | "require-dev": {
740 | "ext-pcntl": "*",
741 | "phpunit/phpunit": "^9.3"
742 | },
743 | "suggest": {
744 | "ext-pcntl": "*"
745 | },
746 | "type": "library",
747 | "extra": {
748 | "branch-alias": {
749 | "dev-master": "3.1-dev"
750 | }
751 | },
752 | "autoload": {
753 | "classmap": [
754 | "src/"
755 | ]
756 | },
757 | "notification-url": "https://packagist.org/downloads/",
758 | "license": [
759 | "BSD-3-Clause"
760 | ],
761 | "authors": [
762 | {
763 | "name": "Sebastian Bergmann",
764 | "email": "sebastian@phpunit.de",
765 | "role": "lead"
766 | }
767 | ],
768 | "description": "Invoke callables with a timeout",
769 | "homepage": "https://github.com/sebastianbergmann/php-invoker/",
770 | "keywords": [
771 | "process"
772 | ],
773 | "support": {
774 | "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
775 | "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1"
776 | },
777 | "funding": [
778 | {
779 | "url": "https://github.com/sebastianbergmann",
780 | "type": "github"
781 | }
782 | ],
783 | "time": "2020-09-28T05:58:55+00:00"
784 | },
785 | {
786 | "name": "phpunit/php-text-template",
787 | "version": "2.0.4",
788 | "source": {
789 | "type": "git",
790 | "url": "https://github.com/sebastianbergmann/php-text-template.git",
791 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28"
792 | },
793 | "dist": {
794 | "type": "zip",
795 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
796 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
797 | "shasum": ""
798 | },
799 | "require": {
800 | "php": ">=7.3"
801 | },
802 | "require-dev": {
803 | "phpunit/phpunit": "^9.3"
804 | },
805 | "type": "library",
806 | "extra": {
807 | "branch-alias": {
808 | "dev-master": "2.0-dev"
809 | }
810 | },
811 | "autoload": {
812 | "classmap": [
813 | "src/"
814 | ]
815 | },
816 | "notification-url": "https://packagist.org/downloads/",
817 | "license": [
818 | "BSD-3-Clause"
819 | ],
820 | "authors": [
821 | {
822 | "name": "Sebastian Bergmann",
823 | "email": "sebastian@phpunit.de",
824 | "role": "lead"
825 | }
826 | ],
827 | "description": "Simple template engine.",
828 | "homepage": "https://github.com/sebastianbergmann/php-text-template/",
829 | "keywords": [
830 | "template"
831 | ],
832 | "support": {
833 | "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
834 | "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4"
835 | },
836 | "funding": [
837 | {
838 | "url": "https://github.com/sebastianbergmann",
839 | "type": "github"
840 | }
841 | ],
842 | "time": "2020-10-26T05:33:50+00:00"
843 | },
844 | {
845 | "name": "phpunit/php-timer",
846 | "version": "5.0.3",
847 | "source": {
848 | "type": "git",
849 | "url": "https://github.com/sebastianbergmann/php-timer.git",
850 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2"
851 | },
852 | "dist": {
853 | "type": "zip",
854 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
855 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
856 | "shasum": ""
857 | },
858 | "require": {
859 | "php": ">=7.3"
860 | },
861 | "require-dev": {
862 | "phpunit/phpunit": "^9.3"
863 | },
864 | "type": "library",
865 | "extra": {
866 | "branch-alias": {
867 | "dev-master": "5.0-dev"
868 | }
869 | },
870 | "autoload": {
871 | "classmap": [
872 | "src/"
873 | ]
874 | },
875 | "notification-url": "https://packagist.org/downloads/",
876 | "license": [
877 | "BSD-3-Clause"
878 | ],
879 | "authors": [
880 | {
881 | "name": "Sebastian Bergmann",
882 | "email": "sebastian@phpunit.de",
883 | "role": "lead"
884 | }
885 | ],
886 | "description": "Utility class for timing",
887 | "homepage": "https://github.com/sebastianbergmann/php-timer/",
888 | "keywords": [
889 | "timer"
890 | ],
891 | "support": {
892 | "issues": "https://github.com/sebastianbergmann/php-timer/issues",
893 | "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3"
894 | },
895 | "funding": [
896 | {
897 | "url": "https://github.com/sebastianbergmann",
898 | "type": "github"
899 | }
900 | ],
901 | "time": "2020-10-26T13:16:10+00:00"
902 | },
903 | {
904 | "name": "phpunit/phpunit",
905 | "version": "9.6.29",
906 | "source": {
907 | "type": "git",
908 | "url": "https://github.com/sebastianbergmann/phpunit.git",
909 | "reference": "9ecfec57835a5581bc888ea7e13b51eb55ab9dd3"
910 | },
911 | "dist": {
912 | "type": "zip",
913 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9ecfec57835a5581bc888ea7e13b51eb55ab9dd3",
914 | "reference": "9ecfec57835a5581bc888ea7e13b51eb55ab9dd3",
915 | "shasum": ""
916 | },
917 | "require": {
918 | "doctrine/instantiator": "^1.5.0 || ^2",
919 | "ext-dom": "*",
920 | "ext-json": "*",
921 | "ext-libxml": "*",
922 | "ext-mbstring": "*",
923 | "ext-xml": "*",
924 | "ext-xmlwriter": "*",
925 | "myclabs/deep-copy": "^1.13.4",
926 | "phar-io/manifest": "^2.0.4",
927 | "phar-io/version": "^3.2.1",
928 | "php": ">=7.3",
929 | "phpunit/php-code-coverage": "^9.2.32",
930 | "phpunit/php-file-iterator": "^3.0.6",
931 | "phpunit/php-invoker": "^3.1.1",
932 | "phpunit/php-text-template": "^2.0.4",
933 | "phpunit/php-timer": "^5.0.3",
934 | "sebastian/cli-parser": "^1.0.2",
935 | "sebastian/code-unit": "^1.0.8",
936 | "sebastian/comparator": "^4.0.9",
937 | "sebastian/diff": "^4.0.6",
938 | "sebastian/environment": "^5.1.5",
939 | "sebastian/exporter": "^4.0.8",
940 | "sebastian/global-state": "^5.0.8",
941 | "sebastian/object-enumerator": "^4.0.4",
942 | "sebastian/resource-operations": "^3.0.4",
943 | "sebastian/type": "^3.2.1",
944 | "sebastian/version": "^3.0.2"
945 | },
946 | "suggest": {
947 | "ext-soap": "To be able to generate mocks based on WSDL files",
948 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
949 | },
950 | "bin": [
951 | "phpunit"
952 | ],
953 | "type": "library",
954 | "extra": {
955 | "branch-alias": {
956 | "dev-master": "9.6-dev"
957 | }
958 | },
959 | "autoload": {
960 | "files": [
961 | "src/Framework/Assert/Functions.php"
962 | ],
963 | "classmap": [
964 | "src/"
965 | ]
966 | },
967 | "notification-url": "https://packagist.org/downloads/",
968 | "license": [
969 | "BSD-3-Clause"
970 | ],
971 | "authors": [
972 | {
973 | "name": "Sebastian Bergmann",
974 | "email": "sebastian@phpunit.de",
975 | "role": "lead"
976 | }
977 | ],
978 | "description": "The PHP Unit Testing framework.",
979 | "homepage": "https://phpunit.de/",
980 | "keywords": [
981 | "phpunit",
982 | "testing",
983 | "xunit"
984 | ],
985 | "support": {
986 | "issues": "https://github.com/sebastianbergmann/phpunit/issues",
987 | "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
988 | "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.29"
989 | },
990 | "funding": [
991 | {
992 | "url": "https://phpunit.de/sponsors.html",
993 | "type": "custom"
994 | },
995 | {
996 | "url": "https://github.com/sebastianbergmann",
997 | "type": "github"
998 | },
999 | {
1000 | "url": "https://liberapay.com/sebastianbergmann",
1001 | "type": "liberapay"
1002 | },
1003 | {
1004 | "url": "https://thanks.dev/u/gh/sebastianbergmann",
1005 | "type": "thanks_dev"
1006 | },
1007 | {
1008 | "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
1009 | "type": "tidelift"
1010 | }
1011 | ],
1012 | "time": "2025-09-24T06:29:11+00:00"
1013 | },
1014 | {
1015 | "name": "sebastian/cli-parser",
1016 | "version": "1.0.2",
1017 | "source": {
1018 | "type": "git",
1019 | "url": "https://github.com/sebastianbergmann/cli-parser.git",
1020 | "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b"
1021 | },
1022 | "dist": {
1023 | "type": "zip",
1024 | "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
1025 | "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
1026 | "shasum": ""
1027 | },
1028 | "require": {
1029 | "php": ">=7.3"
1030 | },
1031 | "require-dev": {
1032 | "phpunit/phpunit": "^9.3"
1033 | },
1034 | "type": "library",
1035 | "extra": {
1036 | "branch-alias": {
1037 | "dev-master": "1.0-dev"
1038 | }
1039 | },
1040 | "autoload": {
1041 | "classmap": [
1042 | "src/"
1043 | ]
1044 | },
1045 | "notification-url": "https://packagist.org/downloads/",
1046 | "license": [
1047 | "BSD-3-Clause"
1048 | ],
1049 | "authors": [
1050 | {
1051 | "name": "Sebastian Bergmann",
1052 | "email": "sebastian@phpunit.de",
1053 | "role": "lead"
1054 | }
1055 | ],
1056 | "description": "Library for parsing CLI options",
1057 | "homepage": "https://github.com/sebastianbergmann/cli-parser",
1058 | "support": {
1059 | "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
1060 | "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2"
1061 | },
1062 | "funding": [
1063 | {
1064 | "url": "https://github.com/sebastianbergmann",
1065 | "type": "github"
1066 | }
1067 | ],
1068 | "time": "2024-03-02T06:27:43+00:00"
1069 | },
1070 | {
1071 | "name": "sebastian/code-unit",
1072 | "version": "1.0.8",
1073 | "source": {
1074 | "type": "git",
1075 | "url": "https://github.com/sebastianbergmann/code-unit.git",
1076 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120"
1077 | },
1078 | "dist": {
1079 | "type": "zip",
1080 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120",
1081 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120",
1082 | "shasum": ""
1083 | },
1084 | "require": {
1085 | "php": ">=7.3"
1086 | },
1087 | "require-dev": {
1088 | "phpunit/phpunit": "^9.3"
1089 | },
1090 | "type": "library",
1091 | "extra": {
1092 | "branch-alias": {
1093 | "dev-master": "1.0-dev"
1094 | }
1095 | },
1096 | "autoload": {
1097 | "classmap": [
1098 | "src/"
1099 | ]
1100 | },
1101 | "notification-url": "https://packagist.org/downloads/",
1102 | "license": [
1103 | "BSD-3-Clause"
1104 | ],
1105 | "authors": [
1106 | {
1107 | "name": "Sebastian Bergmann",
1108 | "email": "sebastian@phpunit.de",
1109 | "role": "lead"
1110 | }
1111 | ],
1112 | "description": "Collection of value objects that represent the PHP code units",
1113 | "homepage": "https://github.com/sebastianbergmann/code-unit",
1114 | "support": {
1115 | "issues": "https://github.com/sebastianbergmann/code-unit/issues",
1116 | "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8"
1117 | },
1118 | "funding": [
1119 | {
1120 | "url": "https://github.com/sebastianbergmann",
1121 | "type": "github"
1122 | }
1123 | ],
1124 | "time": "2020-10-26T13:08:54+00:00"
1125 | },
1126 | {
1127 | "name": "sebastian/code-unit-reverse-lookup",
1128 | "version": "2.0.3",
1129 | "source": {
1130 | "type": "git",
1131 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
1132 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5"
1133 | },
1134 | "dist": {
1135 | "type": "zip",
1136 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
1137 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
1138 | "shasum": ""
1139 | },
1140 | "require": {
1141 | "php": ">=7.3"
1142 | },
1143 | "require-dev": {
1144 | "phpunit/phpunit": "^9.3"
1145 | },
1146 | "type": "library",
1147 | "extra": {
1148 | "branch-alias": {
1149 | "dev-master": "2.0-dev"
1150 | }
1151 | },
1152 | "autoload": {
1153 | "classmap": [
1154 | "src/"
1155 | ]
1156 | },
1157 | "notification-url": "https://packagist.org/downloads/",
1158 | "license": [
1159 | "BSD-3-Clause"
1160 | ],
1161 | "authors": [
1162 | {
1163 | "name": "Sebastian Bergmann",
1164 | "email": "sebastian@phpunit.de"
1165 | }
1166 | ],
1167 | "description": "Looks up which function or method a line of code belongs to",
1168 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
1169 | "support": {
1170 | "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
1171 | "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3"
1172 | },
1173 | "funding": [
1174 | {
1175 | "url": "https://github.com/sebastianbergmann",
1176 | "type": "github"
1177 | }
1178 | ],
1179 | "time": "2020-09-28T05:30:19+00:00"
1180 | },
1181 | {
1182 | "name": "sebastian/comparator",
1183 | "version": "4.0.9",
1184 | "source": {
1185 | "type": "git",
1186 | "url": "https://github.com/sebastianbergmann/comparator.git",
1187 | "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5"
1188 | },
1189 | "dist": {
1190 | "type": "zip",
1191 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/67a2df3a62639eab2cc5906065e9805d4fd5dfc5",
1192 | "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5",
1193 | "shasum": ""
1194 | },
1195 | "require": {
1196 | "php": ">=7.3",
1197 | "sebastian/diff": "^4.0",
1198 | "sebastian/exporter": "^4.0"
1199 | },
1200 | "require-dev": {
1201 | "phpunit/phpunit": "^9.3"
1202 | },
1203 | "type": "library",
1204 | "extra": {
1205 | "branch-alias": {
1206 | "dev-master": "4.0-dev"
1207 | }
1208 | },
1209 | "autoload": {
1210 | "classmap": [
1211 | "src/"
1212 | ]
1213 | },
1214 | "notification-url": "https://packagist.org/downloads/",
1215 | "license": [
1216 | "BSD-3-Clause"
1217 | ],
1218 | "authors": [
1219 | {
1220 | "name": "Sebastian Bergmann",
1221 | "email": "sebastian@phpunit.de"
1222 | },
1223 | {
1224 | "name": "Jeff Welch",
1225 | "email": "whatthejeff@gmail.com"
1226 | },
1227 | {
1228 | "name": "Volker Dusch",
1229 | "email": "github@wallbash.com"
1230 | },
1231 | {
1232 | "name": "Bernhard Schussek",
1233 | "email": "bschussek@2bepublished.at"
1234 | }
1235 | ],
1236 | "description": "Provides the functionality to compare PHP values for equality",
1237 | "homepage": "https://github.com/sebastianbergmann/comparator",
1238 | "keywords": [
1239 | "comparator",
1240 | "compare",
1241 | "equality"
1242 | ],
1243 | "support": {
1244 | "issues": "https://github.com/sebastianbergmann/comparator/issues",
1245 | "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.9"
1246 | },
1247 | "funding": [
1248 | {
1249 | "url": "https://github.com/sebastianbergmann",
1250 | "type": "github"
1251 | },
1252 | {
1253 | "url": "https://liberapay.com/sebastianbergmann",
1254 | "type": "liberapay"
1255 | },
1256 | {
1257 | "url": "https://thanks.dev/u/gh/sebastianbergmann",
1258 | "type": "thanks_dev"
1259 | },
1260 | {
1261 | "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator",
1262 | "type": "tidelift"
1263 | }
1264 | ],
1265 | "time": "2025-08-10T06:51:50+00:00"
1266 | },
1267 | {
1268 | "name": "sebastian/complexity",
1269 | "version": "2.0.3",
1270 | "source": {
1271 | "type": "git",
1272 | "url": "https://github.com/sebastianbergmann/complexity.git",
1273 | "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a"
1274 | },
1275 | "dist": {
1276 | "type": "zip",
1277 | "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a",
1278 | "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a",
1279 | "shasum": ""
1280 | },
1281 | "require": {
1282 | "nikic/php-parser": "^4.18 || ^5.0",
1283 | "php": ">=7.3"
1284 | },
1285 | "require-dev": {
1286 | "phpunit/phpunit": "^9.3"
1287 | },
1288 | "type": "library",
1289 | "extra": {
1290 | "branch-alias": {
1291 | "dev-master": "2.0-dev"
1292 | }
1293 | },
1294 | "autoload": {
1295 | "classmap": [
1296 | "src/"
1297 | ]
1298 | },
1299 | "notification-url": "https://packagist.org/downloads/",
1300 | "license": [
1301 | "BSD-3-Clause"
1302 | ],
1303 | "authors": [
1304 | {
1305 | "name": "Sebastian Bergmann",
1306 | "email": "sebastian@phpunit.de",
1307 | "role": "lead"
1308 | }
1309 | ],
1310 | "description": "Library for calculating the complexity of PHP code units",
1311 | "homepage": "https://github.com/sebastianbergmann/complexity",
1312 | "support": {
1313 | "issues": "https://github.com/sebastianbergmann/complexity/issues",
1314 | "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3"
1315 | },
1316 | "funding": [
1317 | {
1318 | "url": "https://github.com/sebastianbergmann",
1319 | "type": "github"
1320 | }
1321 | ],
1322 | "time": "2023-12-22T06:19:30+00:00"
1323 | },
1324 | {
1325 | "name": "sebastian/diff",
1326 | "version": "4.0.6",
1327 | "source": {
1328 | "type": "git",
1329 | "url": "https://github.com/sebastianbergmann/diff.git",
1330 | "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc"
1331 | },
1332 | "dist": {
1333 | "type": "zip",
1334 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc",
1335 | "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc",
1336 | "shasum": ""
1337 | },
1338 | "require": {
1339 | "php": ">=7.3"
1340 | },
1341 | "require-dev": {
1342 | "phpunit/phpunit": "^9.3",
1343 | "symfony/process": "^4.2 || ^5"
1344 | },
1345 | "type": "library",
1346 | "extra": {
1347 | "branch-alias": {
1348 | "dev-master": "4.0-dev"
1349 | }
1350 | },
1351 | "autoload": {
1352 | "classmap": [
1353 | "src/"
1354 | ]
1355 | },
1356 | "notification-url": "https://packagist.org/downloads/",
1357 | "license": [
1358 | "BSD-3-Clause"
1359 | ],
1360 | "authors": [
1361 | {
1362 | "name": "Sebastian Bergmann",
1363 | "email": "sebastian@phpunit.de"
1364 | },
1365 | {
1366 | "name": "Kore Nordmann",
1367 | "email": "mail@kore-nordmann.de"
1368 | }
1369 | ],
1370 | "description": "Diff implementation",
1371 | "homepage": "https://github.com/sebastianbergmann/diff",
1372 | "keywords": [
1373 | "diff",
1374 | "udiff",
1375 | "unidiff",
1376 | "unified diff"
1377 | ],
1378 | "support": {
1379 | "issues": "https://github.com/sebastianbergmann/diff/issues",
1380 | "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6"
1381 | },
1382 | "funding": [
1383 | {
1384 | "url": "https://github.com/sebastianbergmann",
1385 | "type": "github"
1386 | }
1387 | ],
1388 | "time": "2024-03-02T06:30:58+00:00"
1389 | },
1390 | {
1391 | "name": "sebastian/environment",
1392 | "version": "5.1.5",
1393 | "source": {
1394 | "type": "git",
1395 | "url": "https://github.com/sebastianbergmann/environment.git",
1396 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed"
1397 | },
1398 | "dist": {
1399 | "type": "zip",
1400 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
1401 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
1402 | "shasum": ""
1403 | },
1404 | "require": {
1405 | "php": ">=7.3"
1406 | },
1407 | "require-dev": {
1408 | "phpunit/phpunit": "^9.3"
1409 | },
1410 | "suggest": {
1411 | "ext-posix": "*"
1412 | },
1413 | "type": "library",
1414 | "extra": {
1415 | "branch-alias": {
1416 | "dev-master": "5.1-dev"
1417 | }
1418 | },
1419 | "autoload": {
1420 | "classmap": [
1421 | "src/"
1422 | ]
1423 | },
1424 | "notification-url": "https://packagist.org/downloads/",
1425 | "license": [
1426 | "BSD-3-Clause"
1427 | ],
1428 | "authors": [
1429 | {
1430 | "name": "Sebastian Bergmann",
1431 | "email": "sebastian@phpunit.de"
1432 | }
1433 | ],
1434 | "description": "Provides functionality to handle HHVM/PHP environments",
1435 | "homepage": "http://www.github.com/sebastianbergmann/environment",
1436 | "keywords": [
1437 | "Xdebug",
1438 | "environment",
1439 | "hhvm"
1440 | ],
1441 | "support": {
1442 | "issues": "https://github.com/sebastianbergmann/environment/issues",
1443 | "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5"
1444 | },
1445 | "funding": [
1446 | {
1447 | "url": "https://github.com/sebastianbergmann",
1448 | "type": "github"
1449 | }
1450 | ],
1451 | "time": "2023-02-03T06:03:51+00:00"
1452 | },
1453 | {
1454 | "name": "sebastian/exporter",
1455 | "version": "4.0.8",
1456 | "source": {
1457 | "type": "git",
1458 | "url": "https://github.com/sebastianbergmann/exporter.git",
1459 | "reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c"
1460 | },
1461 | "dist": {
1462 | "type": "zip",
1463 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/14c6ba52f95a36c3d27c835d65efc7123c446e8c",
1464 | "reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c",
1465 | "shasum": ""
1466 | },
1467 | "require": {
1468 | "php": ">=7.3",
1469 | "sebastian/recursion-context": "^4.0"
1470 | },
1471 | "require-dev": {
1472 | "ext-mbstring": "*",
1473 | "phpunit/phpunit": "^9.3"
1474 | },
1475 | "type": "library",
1476 | "extra": {
1477 | "branch-alias": {
1478 | "dev-master": "4.0-dev"
1479 | }
1480 | },
1481 | "autoload": {
1482 | "classmap": [
1483 | "src/"
1484 | ]
1485 | },
1486 | "notification-url": "https://packagist.org/downloads/",
1487 | "license": [
1488 | "BSD-3-Clause"
1489 | ],
1490 | "authors": [
1491 | {
1492 | "name": "Sebastian Bergmann",
1493 | "email": "sebastian@phpunit.de"
1494 | },
1495 | {
1496 | "name": "Jeff Welch",
1497 | "email": "whatthejeff@gmail.com"
1498 | },
1499 | {
1500 | "name": "Volker Dusch",
1501 | "email": "github@wallbash.com"
1502 | },
1503 | {
1504 | "name": "Adam Harvey",
1505 | "email": "aharvey@php.net"
1506 | },
1507 | {
1508 | "name": "Bernhard Schussek",
1509 | "email": "bschussek@gmail.com"
1510 | }
1511 | ],
1512 | "description": "Provides the functionality to export PHP variables for visualization",
1513 | "homepage": "https://www.github.com/sebastianbergmann/exporter",
1514 | "keywords": [
1515 | "export",
1516 | "exporter"
1517 | ],
1518 | "support": {
1519 | "issues": "https://github.com/sebastianbergmann/exporter/issues",
1520 | "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.8"
1521 | },
1522 | "funding": [
1523 | {
1524 | "url": "https://github.com/sebastianbergmann",
1525 | "type": "github"
1526 | },
1527 | {
1528 | "url": "https://liberapay.com/sebastianbergmann",
1529 | "type": "liberapay"
1530 | },
1531 | {
1532 | "url": "https://thanks.dev/u/gh/sebastianbergmann",
1533 | "type": "thanks_dev"
1534 | },
1535 | {
1536 | "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter",
1537 | "type": "tidelift"
1538 | }
1539 | ],
1540 | "time": "2025-09-24T06:03:27+00:00"
1541 | },
1542 | {
1543 | "name": "sebastian/global-state",
1544 | "version": "5.0.8",
1545 | "source": {
1546 | "type": "git",
1547 | "url": "https://github.com/sebastianbergmann/global-state.git",
1548 | "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6"
1549 | },
1550 | "dist": {
1551 | "type": "zip",
1552 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/b6781316bdcd28260904e7cc18ec983d0d2ef4f6",
1553 | "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6",
1554 | "shasum": ""
1555 | },
1556 | "require": {
1557 | "php": ">=7.3",
1558 | "sebastian/object-reflector": "^2.0",
1559 | "sebastian/recursion-context": "^4.0"
1560 | },
1561 | "require-dev": {
1562 | "ext-dom": "*",
1563 | "phpunit/phpunit": "^9.3"
1564 | },
1565 | "suggest": {
1566 | "ext-uopz": "*"
1567 | },
1568 | "type": "library",
1569 | "extra": {
1570 | "branch-alias": {
1571 | "dev-master": "5.0-dev"
1572 | }
1573 | },
1574 | "autoload": {
1575 | "classmap": [
1576 | "src/"
1577 | ]
1578 | },
1579 | "notification-url": "https://packagist.org/downloads/",
1580 | "license": [
1581 | "BSD-3-Clause"
1582 | ],
1583 | "authors": [
1584 | {
1585 | "name": "Sebastian Bergmann",
1586 | "email": "sebastian@phpunit.de"
1587 | }
1588 | ],
1589 | "description": "Snapshotting of global state",
1590 | "homepage": "http://www.github.com/sebastianbergmann/global-state",
1591 | "keywords": [
1592 | "global state"
1593 | ],
1594 | "support": {
1595 | "issues": "https://github.com/sebastianbergmann/global-state/issues",
1596 | "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.8"
1597 | },
1598 | "funding": [
1599 | {
1600 | "url": "https://github.com/sebastianbergmann",
1601 | "type": "github"
1602 | },
1603 | {
1604 | "url": "https://liberapay.com/sebastianbergmann",
1605 | "type": "liberapay"
1606 | },
1607 | {
1608 | "url": "https://thanks.dev/u/gh/sebastianbergmann",
1609 | "type": "thanks_dev"
1610 | },
1611 | {
1612 | "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state",
1613 | "type": "tidelift"
1614 | }
1615 | ],
1616 | "time": "2025-08-10T07:10:35+00:00"
1617 | },
1618 | {
1619 | "name": "sebastian/lines-of-code",
1620 | "version": "1.0.4",
1621 | "source": {
1622 | "type": "git",
1623 | "url": "https://github.com/sebastianbergmann/lines-of-code.git",
1624 | "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5"
1625 | },
1626 | "dist": {
1627 | "type": "zip",
1628 | "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5",
1629 | "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5",
1630 | "shasum": ""
1631 | },
1632 | "require": {
1633 | "nikic/php-parser": "^4.18 || ^5.0",
1634 | "php": ">=7.3"
1635 | },
1636 | "require-dev": {
1637 | "phpunit/phpunit": "^9.3"
1638 | },
1639 | "type": "library",
1640 | "extra": {
1641 | "branch-alias": {
1642 | "dev-master": "1.0-dev"
1643 | }
1644 | },
1645 | "autoload": {
1646 | "classmap": [
1647 | "src/"
1648 | ]
1649 | },
1650 | "notification-url": "https://packagist.org/downloads/",
1651 | "license": [
1652 | "BSD-3-Clause"
1653 | ],
1654 | "authors": [
1655 | {
1656 | "name": "Sebastian Bergmann",
1657 | "email": "sebastian@phpunit.de",
1658 | "role": "lead"
1659 | }
1660 | ],
1661 | "description": "Library for counting the lines of code in PHP source code",
1662 | "homepage": "https://github.com/sebastianbergmann/lines-of-code",
1663 | "support": {
1664 | "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
1665 | "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4"
1666 | },
1667 | "funding": [
1668 | {
1669 | "url": "https://github.com/sebastianbergmann",
1670 | "type": "github"
1671 | }
1672 | ],
1673 | "time": "2023-12-22T06:20:34+00:00"
1674 | },
1675 | {
1676 | "name": "sebastian/object-enumerator",
1677 | "version": "4.0.4",
1678 | "source": {
1679 | "type": "git",
1680 | "url": "https://github.com/sebastianbergmann/object-enumerator.git",
1681 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71"
1682 | },
1683 | "dist": {
1684 | "type": "zip",
1685 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71",
1686 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71",
1687 | "shasum": ""
1688 | },
1689 | "require": {
1690 | "php": ">=7.3",
1691 | "sebastian/object-reflector": "^2.0",
1692 | "sebastian/recursion-context": "^4.0"
1693 | },
1694 | "require-dev": {
1695 | "phpunit/phpunit": "^9.3"
1696 | },
1697 | "type": "library",
1698 | "extra": {
1699 | "branch-alias": {
1700 | "dev-master": "4.0-dev"
1701 | }
1702 | },
1703 | "autoload": {
1704 | "classmap": [
1705 | "src/"
1706 | ]
1707 | },
1708 | "notification-url": "https://packagist.org/downloads/",
1709 | "license": [
1710 | "BSD-3-Clause"
1711 | ],
1712 | "authors": [
1713 | {
1714 | "name": "Sebastian Bergmann",
1715 | "email": "sebastian@phpunit.de"
1716 | }
1717 | ],
1718 | "description": "Traverses array structures and object graphs to enumerate all referenced objects",
1719 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
1720 | "support": {
1721 | "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
1722 | "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4"
1723 | },
1724 | "funding": [
1725 | {
1726 | "url": "https://github.com/sebastianbergmann",
1727 | "type": "github"
1728 | }
1729 | ],
1730 | "time": "2020-10-26T13:12:34+00:00"
1731 | },
1732 | {
1733 | "name": "sebastian/object-reflector",
1734 | "version": "2.0.4",
1735 | "source": {
1736 | "type": "git",
1737 | "url": "https://github.com/sebastianbergmann/object-reflector.git",
1738 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7"
1739 | },
1740 | "dist": {
1741 | "type": "zip",
1742 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
1743 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
1744 | "shasum": ""
1745 | },
1746 | "require": {
1747 | "php": ">=7.3"
1748 | },
1749 | "require-dev": {
1750 | "phpunit/phpunit": "^9.3"
1751 | },
1752 | "type": "library",
1753 | "extra": {
1754 | "branch-alias": {
1755 | "dev-master": "2.0-dev"
1756 | }
1757 | },
1758 | "autoload": {
1759 | "classmap": [
1760 | "src/"
1761 | ]
1762 | },
1763 | "notification-url": "https://packagist.org/downloads/",
1764 | "license": [
1765 | "BSD-3-Clause"
1766 | ],
1767 | "authors": [
1768 | {
1769 | "name": "Sebastian Bergmann",
1770 | "email": "sebastian@phpunit.de"
1771 | }
1772 | ],
1773 | "description": "Allows reflection of object attributes, including inherited and non-public ones",
1774 | "homepage": "https://github.com/sebastianbergmann/object-reflector/",
1775 | "support": {
1776 | "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
1777 | "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4"
1778 | },
1779 | "funding": [
1780 | {
1781 | "url": "https://github.com/sebastianbergmann",
1782 | "type": "github"
1783 | }
1784 | ],
1785 | "time": "2020-10-26T13:14:26+00:00"
1786 | },
1787 | {
1788 | "name": "sebastian/recursion-context",
1789 | "version": "4.0.6",
1790 | "source": {
1791 | "type": "git",
1792 | "url": "https://github.com/sebastianbergmann/recursion-context.git",
1793 | "reference": "539c6691e0623af6dc6f9c20384c120f963465a0"
1794 | },
1795 | "dist": {
1796 | "type": "zip",
1797 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/539c6691e0623af6dc6f9c20384c120f963465a0",
1798 | "reference": "539c6691e0623af6dc6f9c20384c120f963465a0",
1799 | "shasum": ""
1800 | },
1801 | "require": {
1802 | "php": ">=7.3"
1803 | },
1804 | "require-dev": {
1805 | "phpunit/phpunit": "^9.3"
1806 | },
1807 | "type": "library",
1808 | "extra": {
1809 | "branch-alias": {
1810 | "dev-master": "4.0-dev"
1811 | }
1812 | },
1813 | "autoload": {
1814 | "classmap": [
1815 | "src/"
1816 | ]
1817 | },
1818 | "notification-url": "https://packagist.org/downloads/",
1819 | "license": [
1820 | "BSD-3-Clause"
1821 | ],
1822 | "authors": [
1823 | {
1824 | "name": "Sebastian Bergmann",
1825 | "email": "sebastian@phpunit.de"
1826 | },
1827 | {
1828 | "name": "Jeff Welch",
1829 | "email": "whatthejeff@gmail.com"
1830 | },
1831 | {
1832 | "name": "Adam Harvey",
1833 | "email": "aharvey@php.net"
1834 | }
1835 | ],
1836 | "description": "Provides functionality to recursively process PHP variables",
1837 | "homepage": "https://github.com/sebastianbergmann/recursion-context",
1838 | "support": {
1839 | "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
1840 | "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.6"
1841 | },
1842 | "funding": [
1843 | {
1844 | "url": "https://github.com/sebastianbergmann",
1845 | "type": "github"
1846 | },
1847 | {
1848 | "url": "https://liberapay.com/sebastianbergmann",
1849 | "type": "liberapay"
1850 | },
1851 | {
1852 | "url": "https://thanks.dev/u/gh/sebastianbergmann",
1853 | "type": "thanks_dev"
1854 | },
1855 | {
1856 | "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context",
1857 | "type": "tidelift"
1858 | }
1859 | ],
1860 | "time": "2025-08-10T06:57:39+00:00"
1861 | },
1862 | {
1863 | "name": "sebastian/resource-operations",
1864 | "version": "3.0.4",
1865 | "source": {
1866 | "type": "git",
1867 | "url": "https://github.com/sebastianbergmann/resource-operations.git",
1868 | "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e"
1869 | },
1870 | "dist": {
1871 | "type": "zip",
1872 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
1873 | "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
1874 | "shasum": ""
1875 | },
1876 | "require": {
1877 | "php": ">=7.3"
1878 | },
1879 | "require-dev": {
1880 | "phpunit/phpunit": "^9.0"
1881 | },
1882 | "type": "library",
1883 | "extra": {
1884 | "branch-alias": {
1885 | "dev-main": "3.0-dev"
1886 | }
1887 | },
1888 | "autoload": {
1889 | "classmap": [
1890 | "src/"
1891 | ]
1892 | },
1893 | "notification-url": "https://packagist.org/downloads/",
1894 | "license": [
1895 | "BSD-3-Clause"
1896 | ],
1897 | "authors": [
1898 | {
1899 | "name": "Sebastian Bergmann",
1900 | "email": "sebastian@phpunit.de"
1901 | }
1902 | ],
1903 | "description": "Provides a list of PHP built-in functions that operate on resources",
1904 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
1905 | "support": {
1906 | "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4"
1907 | },
1908 | "funding": [
1909 | {
1910 | "url": "https://github.com/sebastianbergmann",
1911 | "type": "github"
1912 | }
1913 | ],
1914 | "time": "2024-03-14T16:00:52+00:00"
1915 | },
1916 | {
1917 | "name": "sebastian/type",
1918 | "version": "3.2.1",
1919 | "source": {
1920 | "type": "git",
1921 | "url": "https://github.com/sebastianbergmann/type.git",
1922 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7"
1923 | },
1924 | "dist": {
1925 | "type": "zip",
1926 | "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
1927 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
1928 | "shasum": ""
1929 | },
1930 | "require": {
1931 | "php": ">=7.3"
1932 | },
1933 | "require-dev": {
1934 | "phpunit/phpunit": "^9.5"
1935 | },
1936 | "type": "library",
1937 | "extra": {
1938 | "branch-alias": {
1939 | "dev-master": "3.2-dev"
1940 | }
1941 | },
1942 | "autoload": {
1943 | "classmap": [
1944 | "src/"
1945 | ]
1946 | },
1947 | "notification-url": "https://packagist.org/downloads/",
1948 | "license": [
1949 | "BSD-3-Clause"
1950 | ],
1951 | "authors": [
1952 | {
1953 | "name": "Sebastian Bergmann",
1954 | "email": "sebastian@phpunit.de",
1955 | "role": "lead"
1956 | }
1957 | ],
1958 | "description": "Collection of value objects that represent the types of the PHP type system",
1959 | "homepage": "https://github.com/sebastianbergmann/type",
1960 | "support": {
1961 | "issues": "https://github.com/sebastianbergmann/type/issues",
1962 | "source": "https://github.com/sebastianbergmann/type/tree/3.2.1"
1963 | },
1964 | "funding": [
1965 | {
1966 | "url": "https://github.com/sebastianbergmann",
1967 | "type": "github"
1968 | }
1969 | ],
1970 | "time": "2023-02-03T06:13:03+00:00"
1971 | },
1972 | {
1973 | "name": "sebastian/version",
1974 | "version": "3.0.2",
1975 | "source": {
1976 | "type": "git",
1977 | "url": "https://github.com/sebastianbergmann/version.git",
1978 | "reference": "c6c1022351a901512170118436c764e473f6de8c"
1979 | },
1980 | "dist": {
1981 | "type": "zip",
1982 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c",
1983 | "reference": "c6c1022351a901512170118436c764e473f6de8c",
1984 | "shasum": ""
1985 | },
1986 | "require": {
1987 | "php": ">=7.3"
1988 | },
1989 | "type": "library",
1990 | "extra": {
1991 | "branch-alias": {
1992 | "dev-master": "3.0-dev"
1993 | }
1994 | },
1995 | "autoload": {
1996 | "classmap": [
1997 | "src/"
1998 | ]
1999 | },
2000 | "notification-url": "https://packagist.org/downloads/",
2001 | "license": [
2002 | "BSD-3-Clause"
2003 | ],
2004 | "authors": [
2005 | {
2006 | "name": "Sebastian Bergmann",
2007 | "email": "sebastian@phpunit.de",
2008 | "role": "lead"
2009 | }
2010 | ],
2011 | "description": "Library that helps with managing the version number of Git-hosted PHP projects",
2012 | "homepage": "https://github.com/sebastianbergmann/version",
2013 | "support": {
2014 | "issues": "https://github.com/sebastianbergmann/version/issues",
2015 | "source": "https://github.com/sebastianbergmann/version/tree/3.0.2"
2016 | },
2017 | "funding": [
2018 | {
2019 | "url": "https://github.com/sebastianbergmann",
2020 | "type": "github"
2021 | }
2022 | ],
2023 | "time": "2020-09-28T06:39:44+00:00"
2024 | },
2025 | {
2026 | "name": "squizlabs/php_codesniffer",
2027 | "version": "3.13.4",
2028 | "source": {
2029 | "type": "git",
2030 | "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
2031 | "reference": "ad545ea9c1b7d270ce0fc9cbfb884161cd706119"
2032 | },
2033 | "dist": {
2034 | "type": "zip",
2035 | "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/ad545ea9c1b7d270ce0fc9cbfb884161cd706119",
2036 | "reference": "ad545ea9c1b7d270ce0fc9cbfb884161cd706119",
2037 | "shasum": ""
2038 | },
2039 | "require": {
2040 | "ext-simplexml": "*",
2041 | "ext-tokenizer": "*",
2042 | "ext-xmlwriter": "*",
2043 | "php": ">=5.4.0"
2044 | },
2045 | "require-dev": {
2046 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4"
2047 | },
2048 | "bin": [
2049 | "bin/phpcbf",
2050 | "bin/phpcs"
2051 | ],
2052 | "type": "library",
2053 | "extra": {
2054 | "branch-alias": {
2055 | "dev-master": "3.x-dev"
2056 | }
2057 | },
2058 | "notification-url": "https://packagist.org/downloads/",
2059 | "license": [
2060 | "BSD-3-Clause"
2061 | ],
2062 | "authors": [
2063 | {
2064 | "name": "Greg Sherwood",
2065 | "role": "Former lead"
2066 | },
2067 | {
2068 | "name": "Juliette Reinders Folmer",
2069 | "role": "Current lead"
2070 | },
2071 | {
2072 | "name": "Contributors",
2073 | "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors"
2074 | }
2075 | ],
2076 | "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
2077 | "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
2078 | "keywords": [
2079 | "phpcs",
2080 | "standards",
2081 | "static analysis"
2082 | ],
2083 | "support": {
2084 | "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues",
2085 | "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy",
2086 | "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
2087 | "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki"
2088 | },
2089 | "funding": [
2090 | {
2091 | "url": "https://github.com/PHPCSStandards",
2092 | "type": "github"
2093 | },
2094 | {
2095 | "url": "https://github.com/jrfnl",
2096 | "type": "github"
2097 | },
2098 | {
2099 | "url": "https://opencollective.com/php_codesniffer",
2100 | "type": "open_collective"
2101 | },
2102 | {
2103 | "url": "https://thanks.dev/u/gh/phpcsstandards",
2104 | "type": "thanks_dev"
2105 | }
2106 | ],
2107 | "time": "2025-09-05T05:47:09+00:00"
2108 | },
2109 | {
2110 | "name": "swoole/ide-helper",
2111 | "version": "4.8.8",
2112 | "source": {
2113 | "type": "git",
2114 | "url": "https://github.com/swoole/ide-helper.git",
2115 | "reference": "dd87843a5040831f9ad40b68fb57879b7342ef61"
2116 | },
2117 | "dist": {
2118 | "type": "zip",
2119 | "url": "https://api.github.com/repos/swoole/ide-helper/zipball/dd87843a5040831f9ad40b68fb57879b7342ef61",
2120 | "reference": "dd87843a5040831f9ad40b68fb57879b7342ef61",
2121 | "shasum": ""
2122 | },
2123 | "type": "library",
2124 | "notification-url": "https://packagist.org/downloads/",
2125 | "license": [
2126 | "Apache-2.0"
2127 | ],
2128 | "authors": [
2129 | {
2130 | "name": "Team Swoole",
2131 | "email": "team@swoole.com"
2132 | }
2133 | ],
2134 | "description": "IDE help files for Swoole.",
2135 | "support": {
2136 | "issues": "https://github.com/swoole/ide-helper/issues",
2137 | "source": "https://github.com/swoole/ide-helper/tree/4.8.8"
2138 | },
2139 | "funding": [
2140 | {
2141 | "url": "https://gitee.com/swoole/swoole?donate=true",
2142 | "type": "custom"
2143 | },
2144 | {
2145 | "url": "https://github.com/swoole",
2146 | "type": "github"
2147 | }
2148 | ],
2149 | "time": "2022-03-17T18:24:39+00:00"
2150 | },
2151 | {
2152 | "name": "theseer/tokenizer",
2153 | "version": "1.2.3",
2154 | "source": {
2155 | "type": "git",
2156 | "url": "https://github.com/theseer/tokenizer.git",
2157 | "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
2158 | },
2159 | "dist": {
2160 | "type": "zip",
2161 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
2162 | "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
2163 | "shasum": ""
2164 | },
2165 | "require": {
2166 | "ext-dom": "*",
2167 | "ext-tokenizer": "*",
2168 | "ext-xmlwriter": "*",
2169 | "php": "^7.2 || ^8.0"
2170 | },
2171 | "type": "library",
2172 | "autoload": {
2173 | "classmap": [
2174 | "src/"
2175 | ]
2176 | },
2177 | "notification-url": "https://packagist.org/downloads/",
2178 | "license": [
2179 | "BSD-3-Clause"
2180 | ],
2181 | "authors": [
2182 | {
2183 | "name": "Arne Blankerts",
2184 | "email": "arne@blankerts.de",
2185 | "role": "Developer"
2186 | }
2187 | ],
2188 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
2189 | "support": {
2190 | "issues": "https://github.com/theseer/tokenizer/issues",
2191 | "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
2192 | },
2193 | "funding": [
2194 | {
2195 | "url": "https://github.com/theseer",
2196 | "type": "github"
2197 | }
2198 | ],
2199 | "time": "2024-03-03T12:36:25+00:00"
2200 | },
2201 | {
2202 | "name": "utopia-php/console",
2203 | "version": "0.0.1",
2204 | "source": {
2205 | "type": "git",
2206 | "url": "https://github.com/utopia-php/console.git",
2207 | "reference": "f77104e4a888fa9cb3e08f32955ec09479ab7a92"
2208 | },
2209 | "dist": {
2210 | "type": "zip",
2211 | "url": "https://api.github.com/repos/utopia-php/console/zipball/f77104e4a888fa9cb3e08f32955ec09479ab7a92",
2212 | "reference": "f77104e4a888fa9cb3e08f32955ec09479ab7a92",
2213 | "shasum": ""
2214 | },
2215 | "require": {
2216 | "php": ">=7.4"
2217 | },
2218 | "require-dev": {
2219 | "laravel/pint": "1.2.*",
2220 | "phpstan/phpstan": "^1.10",
2221 | "phpunit/phpunit": "^9.3",
2222 | "squizlabs/php_codesniffer": "^3.6",
2223 | "swoole/ide-helper": "4.8.8"
2224 | },
2225 | "type": "library",
2226 | "autoload": {
2227 | "psr-4": {
2228 | "Utopia\\": "src/"
2229 | }
2230 | },
2231 | "notification-url": "https://packagist.org/downloads/",
2232 | "license": [
2233 | "MIT"
2234 | ],
2235 | "description": "Console helpers for logging, prompting, and executing commands",
2236 | "keywords": [
2237 | "cli",
2238 | "console",
2239 | "php",
2240 | "terminal",
2241 | "utopia"
2242 | ],
2243 | "support": {
2244 | "issues": "https://github.com/utopia-php/console/issues",
2245 | "source": "https://github.com/utopia-php/console/tree/0.0.1"
2246 | },
2247 | "time": "2025-10-20T14:41:36+00:00"
2248 | }
2249 | ],
2250 | "aliases": [],
2251 | "minimum-stability": "stable",
2252 | "stability-flags": {},
2253 | "prefer-stable": false,
2254 | "prefer-lowest": false,
2255 | "platform": {
2256 | "php": ">=7.4"
2257 | },
2258 | "platform-dev": {},
2259 | "plugin-api-version": "2.6.0"
2260 | }
2261 |
--------------------------------------------------------------------------------