diff --git a/.editorconfig b/.editorconfig
index 8802775..518c149 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -10,12 +10,25 @@ indent_style = space
indent_size = 4
trim_trailing_whitespace = true
+[*.js]
+indent_size = 2
+
+[*.md]
+trim_trailing_whitespace = false
+
[*.php]
ij_php_space_before_short_closure_left_parenthesis = false
ij_php_space_after_type_cast = true
-[*.md]
-trim_trailing_whitespace = false
+[*.yaml]
+indent_size = 2
[*.yml]
indent_size = 2
+
+[*.xml.dist]
+indent_size = 2
+
+[LICENSE*]
+indent_style = unset
+indent_size = unset
diff --git a/.gitattributes b/.gitattributes
index 65a6a4e..fdf0ca4 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -26,6 +26,7 @@
/CHANGELOG.md merge=union
# Exclude files from the archive
+/.editorconfig export-ignore
/.gitattributes export-ignore
/.github export-ignore
/.gitignore export-ignore
@@ -33,7 +34,11 @@
/codeception.yml export-ignore
/composer-require-checker.json export-ignore
/docs export-ignore
+/ecs.php export-ignore
+/infection.json* export-ignore
+/phpstan*.neon* export-ignore
/phpunit.xml.dist export-ignore
/psalm.xml export-ignore
/rector.php export-ignore
+/runtime export-ignore
/tests export-ignore
diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md
deleted file mode 100644
index 1946f00..0000000
--- a/.github/CODE_OF_CONDUCT.md
+++ /dev/null
@@ -1,102 +0,0 @@
-# Code of Conduct
-
-## Our Pledge
-
-As contributors and maintainers of this project, and in order to keep community open and welcoming, we ask to
-respect all community members.
-
-## Our Standards
-
-Examples of behavior that contributes to a positive environment for our community include:
-
-* Demonstrating empathy and kindness toward other people
-* Being respectful of differing opinions, viewpoints, and experiences
-* Giving and gracefully accepting constructive feedback
-* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
-* Focusing on what is best not just for us as individuals, but for the overall community
-
-Examples of unacceptable behavior by participants include:
-
-* The use of sexualized language or imagery, and sexual attention or advances of any kind
-* Trolling, insulting or derogatory comments, and personal or political attacks
-* Public or private harassment
-* Publishing others' private information, such as a physical or email address, without their explicit permission
-* Other conduct which could reasonably be considered inappropriate in a professional setting
-
-## Enforcement Responsibilities
-
-Core team members are responsible for clarifying and enforcing our standards of acceptable behavior and will take
-appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive,
-or harmful.
-
-Core team members have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits,
-issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for
-moderation decisions when appropriate.
-
-## Scope
-
-This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing
-the community in public spaces. Examples of representing a project or community include using an official e-mail
-address, posting via an official social media account, within project GitHub, official forum or acting as an appointed
-representative at an online or offline event.
-
-## Enforcement
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting core team members. All
-complaints will be reviewed and investigated promptly and fairly.
-
-All core team members are obligated to respect the privacy and security of the reporter of any incident.
-
-## Enforcement Guidelines
-
-Core team members will follow these Community Impact Guidelines in determining the consequences for any action they
-deem in violation of this Code of Conduct:
-
-### 1. Correction
-
-**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in
-the community.
-
-**Consequence**: A private, written warning from core team members, providing clarity around the nature of the violation
-and an explanation of why the behavior was inappropriate. A public apology may be requested.
-
-### 2. Warning
-
-**Community Impact**: A violation through a single incident or series of actions.
-
-**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including
-unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding
-interactions in community spaces as well as external channels like social media. Violating these terms may lead to
-a temporary or permanent ban.
-
-### 3. Temporary Ban
-
-**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
-
-**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified
-period of time. No public or private interaction with the people involved, including unsolicited interaction with those
-enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
-
-### 4. Permanent Ban
-
-**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate
-behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
-
-**Consequence**: A permanent ban from any sort of public interaction within the community.
-
-## Attribution
-
-This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at
-[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
-
-Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
-
-For answers to common questions about this code of conduct, see the FAQ at
-[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
-[https://www.contributor-covenant.org/translations][translations].
-
-[homepage]: https://www.contributor-covenant.org
-[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
-[Mozilla CoC]: https://github.com/mozilla/diversity
-[FAQ]: https://www.contributor-covenant.org/faq
-[translations]: https://www.contributor-covenant.org/translations
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index 4b4046c..0000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-# These are supported funding model platforms
-
-github: [terabytesoftw]
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
deleted file mode 100644
index 7e17783..0000000
--- a/.github/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,14 +0,0 @@
-### What steps will reproduce the problem?
-
-### What is the expected result?
-
-### What do you get instead?
-
-
-### Additional info
-
-| Q | A
-| ---------------- | ---
-| Version | 1.0.?
-| PHP version |
-| Operating system |
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
deleted file mode 100644
index cecccf6..0000000
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ /dev/null
@@ -1,6 +0,0 @@
-| Q | A
-| ------------- | ---
-| Is bugfix? | ✔️/❌
-| New feature? | ✔️/❌
-| Breaks BC? | ✔️/❌
-| Fixed issues |
diff --git a/.github/linters/.editorconfig-checker.json b/.github/linters/.editorconfig-checker.json
new file mode 100644
index 0000000..f681ed3
--- /dev/null
+++ b/.github/linters/.editorconfig-checker.json
@@ -0,0 +1,8 @@
+{
+ "Exclude": [
+ "phpstan-baseline.neon",
+ "resources/doc/faqs.md",
+ "tests/Json/JsonFileTest.php",
+ "tests/Json/JsonFormatterTest.php"
+ ]
+}
diff --git a/.github/linters/actionlint.yml b/.github/linters/actionlint.yml
new file mode 100644
index 0000000..328407a
--- /dev/null
+++ b/.github/linters/actionlint.yml
@@ -0,0 +1,6 @@
+---
+paths:
+ .github/workflows/**/*.yml:
+ ignore:
+ - '"pull_request" section is alias node but mapping node is expected'
+ - '"push" section is alias node but mapping node is expected'
diff --git a/.github/workflows/dependency-check.yml b/.github/workflows/dependency-check.yml
index 169bb4b..e69d7d1 100644
--- a/.github/workflows/dependency-check.yml
+++ b/.github/workflows/dependency-check.yml
@@ -1,33 +1,21 @@
+---
on:
- pull_request:
+ pull_request: &ignore-paths
paths-ignore:
- - 'docs/**'
- - 'README.md'
- - 'CHANGELOG.md'
- - '.gitignore'
- - '.gitattributes'
- - 'infection.json.dist'
- - 'phpunit.xml.dist'
- - 'psalm.xml'
+ - ".gitattributes"
+ - ".gitignore"
+ - "CHANGELOG.md"
+ - "docs/**"
+ - "README.md"
- push:
- paths-ignore:
- - 'docs/**'
- - 'README.md'
- - 'CHANGELOG.md'
- - '.gitignore'
- - '.gitattributes'
- - 'infection.json.dist'
- - 'phpunit.xml.dist'
- - 'psalm.xml'
+ push: *ignore-paths
+
+name: Composer require checker
-name: dependency-check
+permissions:
+ contents: read
+ pull-requests: write
jobs:
composer-require-checker:
- uses: php-forge/actions/.github/workflows/composer-require-checker.yml@main
- with:
- os: >-
- ['ubuntu-latest']
- php-version: >-
- ['8.1']
+ uses: yii2-framework/actions/.github/workflows/composer-require-checker.yml@main
diff --git a/.github/workflows/ecs.yml b/.github/workflows/ecs.yml
index 93fb367..e18f15c 100644
--- a/.github/workflows/ecs.yml
+++ b/.github/workflows/ecs.yml
@@ -1,34 +1,21 @@
+---
on:
- pull_request:
+ pull_request: &ignore-paths
paths-ignore:
- - 'docs/**'
- - 'README.md'
- - 'CHANGELOG.md'
- - '.gitignore'
- - '.gitattributes'
- - 'infection.json.dist'
- - 'phpunit.xml.dist'
+ - ".gitattributes"
+ - ".gitignore"
+ - "CHANGELOG.md"
+ - "docs/**"
+ - "README.md"
- push:
- branches: ['main']
- paths-ignore:
- - 'docs/**'
- - 'README.md'
- - 'CHANGELOG.md'
- - '.gitignore'
- - '.gitattributes'
- - 'infection.json.dist'
- - 'phpunit.xml.dist'
+ push: *ignore-paths
name: ecs
+permissions:
+ contents: read
+ pull-requests: write
+
jobs:
easy-coding-standard:
- uses: php-forge/actions/.github/workflows/ecs.yml@main
- secrets:
- AUTH_TOKEN: ${{ secrets.AUTH_TOKEN }}
- with:
- os: >-
- ['ubuntu-latest']
- php-version: >-
- ['8.1']
+ uses: yii2-framework/actions/.github/workflows/ecs.yml@main
diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml
new file mode 100644
index 0000000..7b46557
--- /dev/null
+++ b/.github/workflows/linter.yml
@@ -0,0 +1,17 @@
+---
+on:
+ - pull_request
+ - push
+
+name: linter
+
+permissions:
+ checks: write
+ contents: read
+ statuses: write
+
+jobs:
+ linter:
+ uses: yii2-framework/actions/.github/workflows/super-linter.yml@v1
+ secrets:
+ AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml
new file mode 100644
index 0000000..c0267c3
--- /dev/null
+++ b/.github/workflows/mutation.yml
@@ -0,0 +1,26 @@
+---
+on:
+ pull_request: &ignore-paths
+ paths-ignore:
+ - ".gitattributes"
+ - ".gitignore"
+ - "CHANGELOG.md"
+ - "docs/**"
+ - "README.md"
+
+ push: *ignore-paths
+
+name: mutation test
+
+permissions:
+ contents: read
+ pull-requests: write
+
+jobs:
+ mutation:
+ uses: yii2-framework/actions/.github/workflows/infection.yml@v1
+ with:
+ before-hook: composer require infection/infection --dev --no-progress --no-suggest --prefer-dist
+ phpstan: true
+ secrets:
+ STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }}
diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml
new file mode 100644
index 0000000..99d7c1c
--- /dev/null
+++ b/.github/workflows/static.yml
@@ -0,0 +1,21 @@
+---
+on:
+ pull_request: &ignore-paths
+ paths-ignore:
+ - ".gitattributes"
+ - ".gitignore"
+ - "CHANGELOG.md"
+ - "docs/**"
+ - "README.md"
+
+ push: *ignore-paths
+
+name: static analysis
+
+permissions:
+ contents: read
+ pull-requests: write
+
+jobs:
+ phpstan:
+ uses: yii2-framework/actions/.github/workflows/phpstan.yml@main
diff --git a/.gitignore b/.gitignore
index 08dc4d4..d4c5c11 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,51 @@
-vendor/
-phpunit.xml
-.php-cs-fixer.cache
+# codecoverage (if present)
+code_coverage
+
+# codeception (if present)
+c3.php
+
+# composer
+composer.lock
+
+# gitHub copilot config (if present)
+.github/agents/**
+.github/copilot-instructions.md
+.github/copilot/**
+.github/instructions/**
+.github/prompts/**
+.github/skills/**
+
+# mac ds_store (if present)
+.DS_Store
+
+# netbeans project (if present)
+nbproject
+
+# node_modules (if present)
+node_modules
+package-lock.json
+
+# phpstorm project (if present)
+.idea
+
+# phpunit (if present)
+.phpunit.cache
.phpunit.result.cache
+phpunit.xml*
+
+# vagrant (if present)
+.vagrant
+
+# vendor
+vendor
+
+# vscode project (if present)
+.vscode
+
+# windows thumbnail cache (if present)
+Thumbs.db
+
+# zend studio for eclipse project (if present)
+.buildpath
+.project
+.settings
diff --git a/.styleci.yml b/.styleci.yml
index 5b7ddb2..6cf29b2 100644
--- a/.styleci.yml
+++ b/.styleci.yml
@@ -17,9 +17,10 @@ enabled:
- combine_nested_dirname
- declare_strict_types
- dir_constant
- - fully_qualified_strict_types
+ - empty_loop_body_braces
- function_to_constant
- hash_to_slash_comment
+ - integer_literal_case
- is_null
- logical_operators
- magic_constant_casing
@@ -56,7 +57,6 @@ enabled:
- phpdoc_order
- phpdoc_property
- phpdoc_scalar
- - phpdoc_separation
- phpdoc_singular_inheritdoc
- phpdoc_trim
- phpdoc_trim_consecutive_blank_line_separation
@@ -78,9 +78,10 @@ enabled:
- trailing_comma_in_multiline_array
- unalign_double_arrow
- unalign_equals
- - empty_loop_body_braces
- - integer_literal_case
- union_type_without_spaces
disabled:
- function_declaration
+ - new_with_parentheses
+ - psr12_braces
+ - psr12_class_definition
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 128a8ef..fa41cf6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,4 @@
-Change Log
-==========
+# ChangeLog
## 0.1.3 Under development
@@ -11,10 +10,11 @@ Change Log
- Bug #108: Restore working directory after running the asset manager (@terabytesoftw)
- Bug #109: Respect `root-package-json-dir` for `package.json` read/write (@terabytesoftw)
- Bug #110: Preserve nested empty arrays when rewriting `package.json` (@terabytesoftw)
-- Bug #111: Throw `RuntimeException` class on asset/json `I/O` failures (@terabytesoftw)
+- Bug #111: Throw `RuntimeException` class on asset/JSON `I/O` failures (@terabytesoftw)
- Bug #112: Update `README.md` and add development and testing documentation (@terabytesoftw)
- Bug #113: Fix PHP `8.4` nullable type deprecation warnings in tests (@terabytesoftw)
- Bug #114: Fix PHP `8.5` deprecation of `setAccessible()` in `ReflectionProperty` class (`@terabytesoftw`)
+- Bug #115: Update CI workflows and apply automated refactors (@terabytesoftw)
## 0.1.2 June 10, 2024
diff --git a/README.md b/README.md
index a18fc06..0f1174f 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
-
+
Foxy
diff --git a/composer.json b/composer.json
index 20b6cbe..94c1983 100644
--- a/composer.json
+++ b/composer.json
@@ -1,7 +1,17 @@
{
"name": "php-forge/foxy",
"description": "Fast, reliable, and secure Bun/NPM/Yarn/pnpm bridge for Composer",
- "keywords": ["bun", "npm", "yarn", "composer", "bridge", "dependency manager", "package", "asset", "nodejs"],
+ "keywords": [
+ "bun",
+ "npm",
+ "yarn",
+ "composer",
+ "bridge",
+ "dependency manager",
+ "package",
+ "asset",
+ "nodejs"
+ ],
"homepage": "https://github.com/fxpio/foxy",
"type": "composer-plugin",
"license": "MIT",
@@ -22,17 +32,27 @@
},
"require-dev": {
"maglnet/composer-require-checker": "^4.7",
- "php-forge/support": "^0.1",
+ "php-forge/support": "^0.3",
+ "phpstan/extension-installer": "^1.4",
+ "phpstan/phpstan": "^2.1",
+ "phpstan/phpstan-strict-rules": "^2.0.3",
"phpunit/phpunit": "^10.5",
- "symplify/easy-coding-standard": "^12.5",
- "vimeo/psalm": "^5.26.1|^6.4.1",
+ "rector/rector": "^2.2",
+ "symplify/easy-coding-standard": "^13.0",
"xepozz/internal-mocker": "^1.4"
},
+ "suggest": {
+ "infection/infection": "Mutation testing"
+ },
"config": {
"preferred-install": {
"*": "dist"
},
- "sort-packages": true
+ "sort-packages": true,
+ "allow-plugins": {
+ "infection/extension-installer": true,
+ "phpstan/extension-installer": true
+ }
},
"autoload": {
"psr-4": {
@@ -51,9 +71,22 @@
}
},
"scripts": {
- "check-dependencies": "composer-require-checker",
- "easy-coding-standard": "ecs check",
- "psalm": "psalm",
- "test": "phpunit"
+ "check-dependencies": "./vendor/bin/composer-require-checker check",
+ "ecs": "./vendor/bin/ecs --fix",
+ "mutation": "./vendor/bin/infection --threads=4 --ignore-msi-with-no-mutations --min-msi=100 --min-covered-msi=100",
+ "mutation-static": "./vendor/bin/infection --threads=4 --ignore-msi-with-no-mutations --min-msi=100 --min-covered-msi=100 --static-analysis-tool=phpstan --static-analysis-tool-options='--memory-limit=-1'",
+ "rector": "./vendor/bin/rector process src",
+ "static": "./vendor/bin/phpstan --memory-limit=-1",
+ "sync-metadata": [
+ "curl -fsSL -o .editorconfig https://raw.githubusercontent.com/yii2-extensions/template/main/.editorconfig",
+ "curl -fsSL -o .gitattributes https://raw.githubusercontent.com/yii2-extensions/template/main/.gitattributes",
+ "curl -fsSL -o .gitignore https://raw.githubusercontent.com/yii2-extensions/template/main/.gitignore",
+ "curl -fsSL -o ecs.php https://raw.githubusercontent.com/yii2-extensions/template/main/ecs.php",
+ "curl -fsSL -o infection.json5 https://raw.githubusercontent.com/yii2-extensions/template/main/infection.json5",
+ "curl -fsSL -o phpstan.neon https://raw.githubusercontent.com/yii2-extensions/template/main/phpstan.neon",
+ "curl -fsSL -o phpunit.xml.dist https://raw.githubusercontent.com/yii2-extensions/template/main/phpunit.xml.dist",
+ "curl -fsSL -o rector.php https://raw.githubusercontent.com/yii2-extensions/template/main/rector.php"
+ ],
+ "tests": "./vendor/bin/phpunit"
}
}
diff --git a/composer.lock b/composer.lock
deleted file mode 100644
index 5d1aebb..0000000
--- a/composer.lock
+++ /dev/null
@@ -1,6565 +0,0 @@
-{
- "_readme": [
- "This file locks the dependencies of your project to a known state",
- "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
- "This file is @generated automatically"
- ],
- "content-hash": "5307cf4524079df1b8fc7b5ff402c359",
- "packages": [
- {
- "name": "composer/ca-bundle",
- "version": "1.5.10",
- "source": {
- "type": "git",
- "url": "https://github.com/composer/ca-bundle.git",
- "reference": "961a5e4056dd2e4a2eedcac7576075947c28bf63"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/composer/ca-bundle/zipball/961a5e4056dd2e4a2eedcac7576075947c28bf63",
- "reference": "961a5e4056dd2e4a2eedcac7576075947c28bf63",
- "shasum": ""
- },
- "require": {
- "ext-openssl": "*",
- "ext-pcre": "*",
- "php": "^7.2 || ^8.0"
- },
- "require-dev": {
- "phpstan/phpstan": "^1.10",
- "phpunit/phpunit": "^8 || ^9",
- "psr/log": "^1.0 || ^2.0 || ^3.0",
- "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Composer\\CaBundle\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Jordi Boggiano",
- "email": "j.boggiano@seld.be",
- "homepage": "http://seld.be"
- }
- ],
- "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.",
- "keywords": [
- "cabundle",
- "cacert",
- "certificate",
- "ssl",
- "tls"
- ],
- "support": {
- "irc": "irc://irc.freenode.org/composer",
- "issues": "https://github.com/composer/ca-bundle/issues",
- "source": "https://github.com/composer/ca-bundle/tree/1.5.10"
- },
- "funding": [
- {
- "url": "https://packagist.com",
- "type": "custom"
- },
- {
- "url": "https://github.com/composer",
- "type": "github"
- }
- ],
- "time": "2025-12-08T15:06:51+00:00"
- },
- {
- "name": "composer/class-map-generator",
- "version": "1.7.1",
- "source": {
- "type": "git",
- "url": "https://github.com/composer/class-map-generator.git",
- "reference": "8f5fa3cc214230e71f54924bd0197a3bcc705eb1"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/composer/class-map-generator/zipball/8f5fa3cc214230e71f54924bd0197a3bcc705eb1",
- "reference": "8f5fa3cc214230e71f54924bd0197a3bcc705eb1",
- "shasum": ""
- },
- "require": {
- "composer/pcre": "^2.1 || ^3.1",
- "php": "^7.2 || ^8.0",
- "symfony/finder": "^4.4 || ^5.3 || ^6 || ^7 || ^8"
- },
- "require-dev": {
- "phpstan/phpstan": "^1.12 || ^2",
- "phpstan/phpstan-deprecation-rules": "^1 || ^2",
- "phpstan/phpstan-phpunit": "^1 || ^2",
- "phpstan/phpstan-strict-rules": "^1.1 || ^2",
- "phpunit/phpunit": "^8",
- "symfony/filesystem": "^5.4 || ^6 || ^7 || ^8"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Composer\\ClassMapGenerator\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Jordi Boggiano",
- "email": "j.boggiano@seld.be",
- "homepage": "https://seld.be"
- }
- ],
- "description": "Utilities to scan PHP code and generate class maps.",
- "keywords": [
- "classmap"
- ],
- "support": {
- "issues": "https://github.com/composer/class-map-generator/issues",
- "source": "https://github.com/composer/class-map-generator/tree/1.7.1"
- },
- "funding": [
- {
- "url": "https://packagist.com",
- "type": "custom"
- },
- {
- "url": "https://github.com/composer",
- "type": "github"
- }
- ],
- "time": "2025-12-29T13:15:25+00:00"
- },
- {
- "name": "composer/composer",
- "version": "2.9.3",
- "source": {
- "type": "git",
- "url": "https://github.com/composer/composer.git",
- "reference": "fb3bee27676fd852a8a11ebbb1de19b4dada5aba"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/composer/composer/zipball/fb3bee27676fd852a8a11ebbb1de19b4dada5aba",
- "reference": "fb3bee27676fd852a8a11ebbb1de19b4dada5aba",
- "shasum": ""
- },
- "require": {
- "composer/ca-bundle": "^1.5",
- "composer/class-map-generator": "^1.4.0",
- "composer/metadata-minifier": "^1.0",
- "composer/pcre": "^2.3 || ^3.3",
- "composer/semver": "^3.3",
- "composer/spdx-licenses": "^1.5.7",
- "composer/xdebug-handler": "^2.0.2 || ^3.0.3",
- "ext-json": "*",
- "justinrainbow/json-schema": "^6.5.1",
- "php": "^7.2.5 || ^8.0",
- "psr/log": "^1.0 || ^2.0 || ^3.0",
- "react/promise": "^3.3",
- "seld/jsonlint": "^1.4",
- "seld/phar-utils": "^1.2",
- "seld/signal-handler": "^2.0",
- "symfony/console": "^5.4.47 || ^6.4.25 || ^7.1.10 || ^8.0",
- "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.1.10 || ^8.0",
- "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.1.10 || ^8.0",
- "symfony/polyfill-php73": "^1.24",
- "symfony/polyfill-php80": "^1.24",
- "symfony/polyfill-php81": "^1.24",
- "symfony/polyfill-php84": "^1.30",
- "symfony/process": "^5.4.47 || ^6.4.25 || ^7.1.10 || ^8.0"
- },
- "require-dev": {
- "phpstan/phpstan": "^1.11.8",
- "phpstan/phpstan-deprecation-rules": "^1.2.0",
- "phpstan/phpstan-phpunit": "^1.4.0",
- "phpstan/phpstan-strict-rules": "^1.6.0",
- "phpstan/phpstan-symfony": "^1.4.0",
- "symfony/phpunit-bridge": "^6.4.25 || ^7.3.3 || ^8.0"
- },
- "suggest": {
- "ext-curl": "Provides HTTP support (will fallback to PHP streams if missing)",
- "ext-openssl": "Enables access to repositories and packages over HTTPS",
- "ext-zip": "Allows direct extraction of ZIP archives (unzip/7z binaries will be used instead if available)",
- "ext-zlib": "Enables gzip for HTTP requests"
- },
- "bin": [
- "bin/composer"
- ],
- "type": "library",
- "extra": {
- "phpstan": {
- "includes": [
- "phpstan/rules.neon"
- ]
- },
- "branch-alias": {
- "dev-main": "2.9-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Composer\\": "src/Composer/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nils Adermann",
- "email": "naderman@naderman.de",
- "homepage": "https://www.naderman.de"
- },
- {
- "name": "Jordi Boggiano",
- "email": "j.boggiano@seld.be",
- "homepage": "https://seld.be"
- }
- ],
- "description": "Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.",
- "homepage": "https://getcomposer.org/",
- "keywords": [
- "autoload",
- "dependency",
- "package"
- ],
- "support": {
- "irc": "ircs://irc.libera.chat:6697/composer",
- "issues": "https://github.com/composer/composer/issues",
- "security": "https://github.com/composer/composer/security/policy",
- "source": "https://github.com/composer/composer/tree/2.9.3"
- },
- "funding": [
- {
- "url": "https://packagist.com",
- "type": "custom"
- },
- {
- "url": "https://github.com/composer",
- "type": "github"
- }
- ],
- "time": "2025-12-30T12:40:17+00:00"
- },
- {
- "name": "composer/metadata-minifier",
- "version": "1.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/composer/metadata-minifier.git",
- "reference": "c549d23829536f0d0e984aaabbf02af91f443207"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/composer/metadata-minifier/zipball/c549d23829536f0d0e984aaabbf02af91f443207",
- "reference": "c549d23829536f0d0e984aaabbf02af91f443207",
- "shasum": ""
- },
- "require": {
- "php": "^5.3.2 || ^7.0 || ^8.0"
- },
- "require-dev": {
- "composer/composer": "^2",
- "phpstan/phpstan": "^0.12.55",
- "symfony/phpunit-bridge": "^4.2 || ^5"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Composer\\MetadataMinifier\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Jordi Boggiano",
- "email": "j.boggiano@seld.be",
- "homepage": "http://seld.be"
- }
- ],
- "description": "Small utility library that handles metadata minification and expansion.",
- "keywords": [
- "composer",
- "compression"
- ],
- "support": {
- "issues": "https://github.com/composer/metadata-minifier/issues",
- "source": "https://github.com/composer/metadata-minifier/tree/1.0.0"
- },
- "funding": [
- {
- "url": "https://packagist.com",
- "type": "custom"
- },
- {
- "url": "https://github.com/composer",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/composer/composer",
- "type": "tidelift"
- }
- ],
- "time": "2021-04-07T13:37:33+00:00"
- },
- {
- "name": "composer/pcre",
- "version": "3.3.2",
- "source": {
- "type": "git",
- "url": "https://github.com/composer/pcre.git",
- "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
- "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
- "shasum": ""
- },
- "require": {
- "php": "^7.4 || ^8.0"
- },
- "conflict": {
- "phpstan/phpstan": "<1.11.10"
- },
- "require-dev": {
- "phpstan/phpstan": "^1.12 || ^2",
- "phpstan/phpstan-strict-rules": "^1 || ^2",
- "phpunit/phpunit": "^8 || ^9"
- },
- "type": "library",
- "extra": {
- "phpstan": {
- "includes": [
- "extension.neon"
- ]
- },
- "branch-alias": {
- "dev-main": "3.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Composer\\Pcre\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Jordi Boggiano",
- "email": "j.boggiano@seld.be",
- "homepage": "http://seld.be"
- }
- ],
- "description": "PCRE wrapping library that offers type-safe preg_* replacements.",
- "keywords": [
- "PCRE",
- "preg",
- "regex",
- "regular expression"
- ],
- "support": {
- "issues": "https://github.com/composer/pcre/issues",
- "source": "https://github.com/composer/pcre/tree/3.3.2"
- },
- "funding": [
- {
- "url": "https://packagist.com",
- "type": "custom"
- },
- {
- "url": "https://github.com/composer",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/composer/composer",
- "type": "tidelift"
- }
- ],
- "time": "2024-11-12T16:29:46+00:00"
- },
- {
- "name": "composer/semver",
- "version": "3.4.4",
- "source": {
- "type": "git",
- "url": "https://github.com/composer/semver.git",
- "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95",
- "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95",
- "shasum": ""
- },
- "require": {
- "php": "^5.3.2 || ^7.0 || ^8.0"
- },
- "require-dev": {
- "phpstan/phpstan": "^1.11",
- "symfony/phpunit-bridge": "^3 || ^7"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "3.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Composer\\Semver\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nils Adermann",
- "email": "naderman@naderman.de",
- "homepage": "http://www.naderman.de"
- },
- {
- "name": "Jordi Boggiano",
- "email": "j.boggiano@seld.be",
- "homepage": "http://seld.be"
- },
- {
- "name": "Rob Bast",
- "email": "rob.bast@gmail.com",
- "homepage": "http://robbast.nl"
- }
- ],
- "description": "Semver library that offers utilities, version constraint parsing and validation.",
- "keywords": [
- "semantic",
- "semver",
- "validation",
- "versioning"
- ],
- "support": {
- "irc": "ircs://irc.libera.chat:6697/composer",
- "issues": "https://github.com/composer/semver/issues",
- "source": "https://github.com/composer/semver/tree/3.4.4"
- },
- "funding": [
- {
- "url": "https://packagist.com",
- "type": "custom"
- },
- {
- "url": "https://github.com/composer",
- "type": "github"
- }
- ],
- "time": "2025-08-20T19:15:30+00:00"
- },
- {
- "name": "composer/spdx-licenses",
- "version": "1.5.9",
- "source": {
- "type": "git",
- "url": "https://github.com/composer/spdx-licenses.git",
- "reference": "edf364cefe8c43501e21e88110aac10b284c3c9f"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/edf364cefe8c43501e21e88110aac10b284c3c9f",
- "reference": "edf364cefe8c43501e21e88110aac10b284c3c9f",
- "shasum": ""
- },
- "require": {
- "php": "^5.3.2 || ^7.0 || ^8.0"
- },
- "require-dev": {
- "phpstan/phpstan": "^1.11",
- "symfony/phpunit-bridge": "^3 || ^7"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Composer\\Spdx\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nils Adermann",
- "email": "naderman@naderman.de",
- "homepage": "http://www.naderman.de"
- },
- {
- "name": "Jordi Boggiano",
- "email": "j.boggiano@seld.be",
- "homepage": "http://seld.be"
- },
- {
- "name": "Rob Bast",
- "email": "rob.bast@gmail.com",
- "homepage": "http://robbast.nl"
- }
- ],
- "description": "SPDX licenses list and validation library.",
- "keywords": [
- "license",
- "spdx",
- "validator"
- ],
- "support": {
- "irc": "ircs://irc.libera.chat:6697/composer",
- "issues": "https://github.com/composer/spdx-licenses/issues",
- "source": "https://github.com/composer/spdx-licenses/tree/1.5.9"
- },
- "funding": [
- {
- "url": "https://packagist.com",
- "type": "custom"
- },
- {
- "url": "https://github.com/composer",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/composer/composer",
- "type": "tidelift"
- }
- ],
- "time": "2025-05-12T21:07:07+00:00"
- },
- {
- "name": "composer/xdebug-handler",
- "version": "3.0.5",
- "source": {
- "type": "git",
- "url": "https://github.com/composer/xdebug-handler.git",
- "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef",
- "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef",
- "shasum": ""
- },
- "require": {
- "composer/pcre": "^1 || ^2 || ^3",
- "php": "^7.2.5 || ^8.0",
- "psr/log": "^1 || ^2 || ^3"
- },
- "require-dev": {
- "phpstan/phpstan": "^1.0",
- "phpstan/phpstan-strict-rules": "^1.1",
- "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Composer\\XdebugHandler\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "John Stevenson",
- "email": "john-stevenson@blueyonder.co.uk"
- }
- ],
- "description": "Restarts a process without Xdebug.",
- "keywords": [
- "Xdebug",
- "performance"
- ],
- "support": {
- "irc": "ircs://irc.libera.chat:6697/composer",
- "issues": "https://github.com/composer/xdebug-handler/issues",
- "source": "https://github.com/composer/xdebug-handler/tree/3.0.5"
- },
- "funding": [
- {
- "url": "https://packagist.com",
- "type": "custom"
- },
- {
- "url": "https://github.com/composer",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/composer/composer",
- "type": "tidelift"
- }
- ],
- "time": "2024-05-06T16:37:16+00:00"
- },
- {
- "name": "justinrainbow/json-schema",
- "version": "6.6.4",
- "source": {
- "type": "git",
- "url": "https://github.com/jsonrainbow/json-schema.git",
- "reference": "2eeb75d21cf73211335888e7f5e6fd7440723ec7"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/2eeb75d21cf73211335888e7f5e6fd7440723ec7",
- "reference": "2eeb75d21cf73211335888e7f5e6fd7440723ec7",
- "shasum": ""
- },
- "require": {
- "ext-json": "*",
- "marc-mabe/php-enum": "^4.4",
- "php": "^7.2 || ^8.0"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "3.3.0",
- "json-schema/json-schema-test-suite": "^23.2",
- "marc-mabe/php-enum-phpstan": "^2.0",
- "phpspec/prophecy": "^1.19",
- "phpstan/phpstan": "^1.12",
- "phpunit/phpunit": "^8.5"
- },
- "bin": [
- "bin/validate-json"
- ],
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "6.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "JsonSchema\\": "src/JsonSchema/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Bruno Prieto Reis",
- "email": "bruno.p.reis@gmail.com"
- },
- {
- "name": "Justin Rainbow",
- "email": "justin.rainbow@gmail.com"
- },
- {
- "name": "Igor Wiedler",
- "email": "igor@wiedler.ch"
- },
- {
- "name": "Robert Schönthal",
- "email": "seroscho@googlemail.com"
- }
- ],
- "description": "A library to validate a json schema.",
- "homepage": "https://github.com/jsonrainbow/json-schema",
- "keywords": [
- "json",
- "schema"
- ],
- "support": {
- "issues": "https://github.com/jsonrainbow/json-schema/issues",
- "source": "https://github.com/jsonrainbow/json-schema/tree/6.6.4"
- },
- "time": "2025-12-19T15:01:32+00:00"
- },
- {
- "name": "marc-mabe/php-enum",
- "version": "v4.7.2",
- "source": {
- "type": "git",
- "url": "https://github.com/marc-mabe/php-enum.git",
- "reference": "bb426fcdd65c60fb3638ef741e8782508fda7eef"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/marc-mabe/php-enum/zipball/bb426fcdd65c60fb3638ef741e8782508fda7eef",
- "reference": "bb426fcdd65c60fb3638ef741e8782508fda7eef",
- "shasum": ""
- },
- "require": {
- "ext-reflection": "*",
- "php": "^7.1 | ^8.0"
- },
- "require-dev": {
- "phpbench/phpbench": "^0.16.10 || ^1.0.4",
- "phpstan/phpstan": "^1.3.1",
- "phpunit/phpunit": "^7.5.20 | ^8.5.22 | ^9.5.11",
- "vimeo/psalm": "^4.17.0 | ^5.26.1"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-3.x": "3.2-dev",
- "dev-master": "4.7-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "MabeEnum\\": "src/"
- },
- "classmap": [
- "stubs/Stringable.php"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Marc Bennewitz",
- "email": "dev@mabe.berlin",
- "homepage": "https://mabe.berlin/",
- "role": "Lead"
- }
- ],
- "description": "Simple and fast implementation of enumerations with native PHP",
- "homepage": "https://github.com/marc-mabe/php-enum",
- "keywords": [
- "enum",
- "enum-map",
- "enum-set",
- "enumeration",
- "enumerator",
- "enummap",
- "enumset",
- "map",
- "set",
- "type",
- "type-hint",
- "typehint"
- ],
- "support": {
- "issues": "https://github.com/marc-mabe/php-enum/issues",
- "source": "https://github.com/marc-mabe/php-enum/tree/v4.7.2"
- },
- "time": "2025-09-14T11:18:39+00:00"
- },
- {
- "name": "psr/container",
- "version": "2.0.2",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/container.git",
- "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
- "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
- "shasum": ""
- },
- "require": {
- "php": ">=7.4.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.0.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Psr\\Container\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "https://www.php-fig.org/"
- }
- ],
- "description": "Common Container Interface (PHP FIG PSR-11)",
- "homepage": "https://github.com/php-fig/container",
- "keywords": [
- "PSR-11",
- "container",
- "container-interface",
- "container-interop",
- "psr"
- ],
- "support": {
- "issues": "https://github.com/php-fig/container/issues",
- "source": "https://github.com/php-fig/container/tree/2.0.2"
- },
- "time": "2021-11-05T16:47:00+00:00"
- },
- {
- "name": "psr/log",
- "version": "3.0.2",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/log.git",
- "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
- "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
- "shasum": ""
- },
- "require": {
- "php": ">=8.0.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Psr\\Log\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "https://www.php-fig.org/"
- }
- ],
- "description": "Common interface for logging libraries",
- "homepage": "https://github.com/php-fig/log",
- "keywords": [
- "log",
- "psr",
- "psr-3"
- ],
- "support": {
- "source": "https://github.com/php-fig/log/tree/3.0.2"
- },
- "time": "2024-09-11T13:17:53+00:00"
- },
- {
- "name": "react/promise",
- "version": "v3.3.0",
- "source": {
- "type": "git",
- "url": "https://github.com/reactphp/promise.git",
- "reference": "23444f53a813a3296c1368bb104793ce8d88f04a"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/reactphp/promise/zipball/23444f53a813a3296c1368bb104793ce8d88f04a",
- "reference": "23444f53a813a3296c1368bb104793ce8d88f04a",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1.0"
- },
- "require-dev": {
- "phpstan/phpstan": "1.12.28 || 1.4.10",
- "phpunit/phpunit": "^9.6 || ^7.5"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions_include.php"
- ],
- "psr-4": {
- "React\\Promise\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Jan Sorgalla",
- "email": "jsorgalla@gmail.com",
- "homepage": "https://sorgalla.com/"
- },
- {
- "name": "Christian Lück",
- "email": "christian@clue.engineering",
- "homepage": "https://clue.engineering/"
- },
- {
- "name": "Cees-Jan Kiewiet",
- "email": "reactphp@ceesjankiewiet.nl",
- "homepage": "https://wyrihaximus.net/"
- },
- {
- "name": "Chris Boden",
- "email": "cboden@gmail.com",
- "homepage": "https://cboden.dev/"
- }
- ],
- "description": "A lightweight implementation of CommonJS Promises/A for PHP",
- "keywords": [
- "promise",
- "promises"
- ],
- "support": {
- "issues": "https://github.com/reactphp/promise/issues",
- "source": "https://github.com/reactphp/promise/tree/v3.3.0"
- },
- "funding": [
- {
- "url": "https://opencollective.com/reactphp",
- "type": "open_collective"
- }
- ],
- "time": "2025-08-19T18:57:03+00:00"
- },
- {
- "name": "seld/jsonlint",
- "version": "1.11.0",
- "source": {
- "type": "git",
- "url": "https://github.com/Seldaek/jsonlint.git",
- "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/1748aaf847fc731cfad7725aec413ee46f0cc3a2",
- "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2",
- "shasum": ""
- },
- "require": {
- "php": "^5.3 || ^7.0 || ^8.0"
- },
- "require-dev": {
- "phpstan/phpstan": "^1.11",
- "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13"
- },
- "bin": [
- "bin/jsonlint"
- ],
- "type": "library",
- "autoload": {
- "psr-4": {
- "Seld\\JsonLint\\": "src/Seld/JsonLint/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Jordi Boggiano",
- "email": "j.boggiano@seld.be",
- "homepage": "https://seld.be"
- }
- ],
- "description": "JSON Linter",
- "keywords": [
- "json",
- "linter",
- "parser",
- "validator"
- ],
- "support": {
- "issues": "https://github.com/Seldaek/jsonlint/issues",
- "source": "https://github.com/Seldaek/jsonlint/tree/1.11.0"
- },
- "funding": [
- {
- "url": "https://github.com/Seldaek",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/seld/jsonlint",
- "type": "tidelift"
- }
- ],
- "time": "2024-07-11T14:55:45+00:00"
- },
- {
- "name": "seld/phar-utils",
- "version": "1.2.1",
- "source": {
- "type": "git",
- "url": "https://github.com/Seldaek/phar-utils.git",
- "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/ea2f4014f163c1be4c601b9b7bd6af81ba8d701c",
- "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Seld\\PharUtils\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Jordi Boggiano",
- "email": "j.boggiano@seld.be"
- }
- ],
- "description": "PHAR file format utilities, for when PHP phars you up",
- "keywords": [
- "phar"
- ],
- "support": {
- "issues": "https://github.com/Seldaek/phar-utils/issues",
- "source": "https://github.com/Seldaek/phar-utils/tree/1.2.1"
- },
- "time": "2022-08-31T10:31:18+00:00"
- },
- {
- "name": "seld/signal-handler",
- "version": "2.0.2",
- "source": {
- "type": "git",
- "url": "https://github.com/Seldaek/signal-handler.git",
- "reference": "04a6112e883ad76c0ada8e4a9f7520bbfdb6bb98"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/Seldaek/signal-handler/zipball/04a6112e883ad76c0ada8e4a9f7520bbfdb6bb98",
- "reference": "04a6112e883ad76c0ada8e4a9f7520bbfdb6bb98",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.0"
- },
- "require-dev": {
- "phpstan/phpstan": "^1",
- "phpstan/phpstan-deprecation-rules": "^1.0",
- "phpstan/phpstan-phpunit": "^1",
- "phpstan/phpstan-strict-rules": "^1.3",
- "phpunit/phpunit": "^7.5.20 || ^8.5.23",
- "psr/log": "^1 || ^2 || ^3"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "2.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Seld\\Signal\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Jordi Boggiano",
- "email": "j.boggiano@seld.be",
- "homepage": "http://seld.be"
- }
- ],
- "description": "Simple unix signal handler that silently fails where signals are not supported for easy cross-platform development",
- "keywords": [
- "posix",
- "sigint",
- "signal",
- "sigterm",
- "unix"
- ],
- "support": {
- "issues": "https://github.com/Seldaek/signal-handler/issues",
- "source": "https://github.com/Seldaek/signal-handler/tree/2.0.2"
- },
- "time": "2023-09-03T09:24:00+00:00"
- },
- {
- "name": "symfony/console",
- "version": "v7.4.3",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/console.git",
- "reference": "732a9ca6cd9dfd940c639062d5edbde2f6727fb6"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/732a9ca6cd9dfd940c639062d5edbde2f6727fb6",
- "reference": "732a9ca6cd9dfd940c639062d5edbde2f6727fb6",
- "shasum": ""
- },
- "require": {
- "php": ">=8.2",
- "symfony/deprecation-contracts": "^2.5|^3",
- "symfony/polyfill-mbstring": "~1.0",
- "symfony/service-contracts": "^2.5|^3",
- "symfony/string": "^7.2|^8.0"
- },
- "conflict": {
- "symfony/dependency-injection": "<6.4",
- "symfony/dotenv": "<6.4",
- "symfony/event-dispatcher": "<6.4",
- "symfony/lock": "<6.4",
- "symfony/process": "<6.4"
- },
- "provide": {
- "psr/log-implementation": "1.0|2.0|3.0"
- },
- "require-dev": {
- "psr/log": "^1|^2|^3",
- "symfony/config": "^6.4|^7.0|^8.0",
- "symfony/dependency-injection": "^6.4|^7.0|^8.0",
- "symfony/event-dispatcher": "^6.4|^7.0|^8.0",
- "symfony/http-foundation": "^6.4|^7.0|^8.0",
- "symfony/http-kernel": "^6.4|^7.0|^8.0",
- "symfony/lock": "^6.4|^7.0|^8.0",
- "symfony/messenger": "^6.4|^7.0|^8.0",
- "symfony/process": "^6.4|^7.0|^8.0",
- "symfony/stopwatch": "^6.4|^7.0|^8.0",
- "symfony/var-dumper": "^6.4|^7.0|^8.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Console\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Eases the creation of beautiful and testable command line interfaces",
- "homepage": "https://symfony.com",
- "keywords": [
- "cli",
- "command-line",
- "console",
- "terminal"
- ],
- "support": {
- "source": "https://github.com/symfony/console/tree/v7.4.3"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://github.com/nicolas-grekas",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2025-12-23T14:50:43+00:00"
- },
- {
- "name": "symfony/deprecation-contracts",
- "version": "v3.6.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
- "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/contracts",
- "name": "symfony/contracts"
- },
- "branch-alias": {
- "dev-main": "3.6-dev"
- }
- },
- "autoload": {
- "files": [
- "function.php"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "A generic function and convention to trigger deprecation notices",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-09-25T14:21:43+00:00"
- },
- {
- "name": "symfony/filesystem",
- "version": "v8.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/filesystem.git",
- "reference": "d937d400b980523dc9ee946bb69972b5e619058d"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/d937d400b980523dc9ee946bb69972b5e619058d",
- "reference": "d937d400b980523dc9ee946bb69972b5e619058d",
- "shasum": ""
- },
- "require": {
- "php": ">=8.4",
- "symfony/polyfill-ctype": "~1.8",
- "symfony/polyfill-mbstring": "~1.8"
- },
- "require-dev": {
- "symfony/process": "^7.4|^8.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Filesystem\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Provides basic utilities for the filesystem",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/filesystem/tree/v8.0.1"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://github.com/nicolas-grekas",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2025-12-01T09:13:36+00:00"
- },
- {
- "name": "symfony/finder",
- "version": "v8.0.3",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/finder.git",
- "reference": "dd3a2953570a283a2ba4e17063bb98c734cf5b12"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/dd3a2953570a283a2ba4e17063bb98c734cf5b12",
- "reference": "dd3a2953570a283a2ba4e17063bb98c734cf5b12",
- "shasum": ""
- },
- "require": {
- "php": ">=8.4"
- },
- "require-dev": {
- "symfony/filesystem": "^7.4|^8.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Finder\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Finds files and directories via an intuitive fluent interface",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/finder/tree/v8.0.3"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://github.com/nicolas-grekas",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2025-12-23T14:52:06+00:00"
- },
- {
- "name": "symfony/polyfill-ctype",
- "version": "v1.33.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
- "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "provide": {
- "ext-ctype": "*"
- },
- "suggest": {
- "ext-ctype": "For best performance"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/polyfill",
- "name": "symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Ctype\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Gert de Pagter",
- "email": "BackEndTea@gmail.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill for ctype functions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "ctype",
- "polyfill",
- "portable"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://github.com/nicolas-grekas",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-09-09T11:45:10+00:00"
- },
- {
- "name": "symfony/polyfill-intl-grapheme",
- "version": "v1.33.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70",
- "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "suggest": {
- "ext-intl": "For best performance"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/polyfill",
- "name": "symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill for intl's grapheme_* functions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "grapheme",
- "intl",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://github.com/nicolas-grekas",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2025-06-27T09:58:17+00:00"
- },
- {
- "name": "symfony/polyfill-intl-normalizer",
- "version": "v1.33.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
- "reference": "3833d7255cc303546435cb650316bff708a1c75c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
- "reference": "3833d7255cc303546435cb650316bff708a1c75c",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "suggest": {
- "ext-intl": "For best performance"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/polyfill",
- "name": "symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
- },
- "classmap": [
- "Resources/stubs"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill for intl's Normalizer class and related functions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "intl",
- "normalizer",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://github.com/nicolas-grekas",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-09-09T11:45:10+00:00"
- },
- {
- "name": "symfony/polyfill-mbstring",
- "version": "v1.33.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
- "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
- "shasum": ""
- },
- "require": {
- "ext-iconv": "*",
- "php": ">=7.2"
- },
- "provide": {
- "ext-mbstring": "*"
- },
- "suggest": {
- "ext-mbstring": "For best performance"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/polyfill",
- "name": "symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Mbstring\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill for the Mbstring extension",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "mbstring",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://github.com/nicolas-grekas",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-12-23T08:48:59+00:00"
- },
- {
- "name": "symfony/polyfill-php73",
- "version": "v1.33.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-php73.git",
- "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb",
- "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/polyfill",
- "name": "symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Php73\\": ""
- },
- "classmap": [
- "Resources/stubs"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-php73/tree/v1.33.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://github.com/nicolas-grekas",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-09-09T11:45:10+00:00"
- },
- {
- "name": "symfony/polyfill-php80",
- "version": "v1.33.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-php80.git",
- "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
- "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/polyfill",
- "name": "symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Php80\\": ""
- },
- "classmap": [
- "Resources/stubs"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Ion Bazan",
- "email": "ion.bazan@gmail.com"
- },
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://github.com/nicolas-grekas",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2025-01-02T08:10:11+00:00"
- },
- {
- "name": "symfony/polyfill-php81",
- "version": "v1.33.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-php81.git",
- "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
- "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/polyfill",
- "name": "symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Php81\\": ""
- },
- "classmap": [
- "Resources/stubs"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://github.com/nicolas-grekas",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-09-09T11:45:10+00:00"
- },
- {
- "name": "symfony/polyfill-php84",
- "version": "v1.33.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-php84.git",
- "reference": "d8ced4d875142b6a7426000426b8abc631d6b191"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191",
- "reference": "d8ced4d875142b6a7426000426b8abc631d6b191",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/polyfill",
- "name": "symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Php84\\": ""
- },
- "classmap": [
- "Resources/stubs"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://github.com/nicolas-grekas",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2025-06-24T13:30:11+00:00"
- },
- {
- "name": "symfony/process",
- "version": "v8.0.3",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/process.git",
- "reference": "0cbbd88ec836f8757641c651bb995335846abb78"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/0cbbd88ec836f8757641c651bb995335846abb78",
- "reference": "0cbbd88ec836f8757641c651bb995335846abb78",
- "shasum": ""
- },
- "require": {
- "php": ">=8.4"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Process\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Executes commands in sub-processes",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/process/tree/v8.0.3"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://github.com/nicolas-grekas",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2025-12-19T10:01:18+00:00"
- },
- {
- "name": "symfony/service-contracts",
- "version": "v3.6.1",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/service-contracts.git",
- "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43",
- "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1",
- "psr/container": "^1.1|^2.0",
- "symfony/deprecation-contracts": "^2.5|^3"
- },
- "conflict": {
- "ext-psr": "<1.1|>=2"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/contracts",
- "name": "symfony/contracts"
- },
- "branch-alias": {
- "dev-main": "3.6-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Symfony\\Contracts\\Service\\": ""
- },
- "exclude-from-classmap": [
- "/Test/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Generic abstractions related to writing services",
- "homepage": "https://symfony.com",
- "keywords": [
- "abstractions",
- "contracts",
- "decoupling",
- "interfaces",
- "interoperability",
- "standards"
- ],
- "support": {
- "source": "https://github.com/symfony/service-contracts/tree/v3.6.1"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://github.com/nicolas-grekas",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2025-07-15T11:30:57+00:00"
- },
- {
- "name": "symfony/string",
- "version": "v8.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/string.git",
- "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/ba65a969ac918ce0cc3edfac6cdde847eba231dc",
- "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc",
- "shasum": ""
- },
- "require": {
- "php": ">=8.4",
- "symfony/polyfill-ctype": "^1.8",
- "symfony/polyfill-intl-grapheme": "^1.33",
- "symfony/polyfill-intl-normalizer": "^1.0",
- "symfony/polyfill-mbstring": "^1.0"
- },
- "conflict": {
- "symfony/translation-contracts": "<2.5"
- },
- "require-dev": {
- "symfony/emoji": "^7.4|^8.0",
- "symfony/http-client": "^7.4|^8.0",
- "symfony/intl": "^7.4|^8.0",
- "symfony/translation-contracts": "^2.5|^3.0",
- "symfony/var-exporter": "^7.4|^8.0"
- },
- "type": "library",
- "autoload": {
- "files": [
- "Resources/functions.php"
- ],
- "psr-4": {
- "Symfony\\Component\\String\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
- "homepage": "https://symfony.com",
- "keywords": [
- "grapheme",
- "i18n",
- "string",
- "unicode",
- "utf-8",
- "utf8"
- ],
- "support": {
- "source": "https://github.com/symfony/string/tree/v8.0.1"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://github.com/nicolas-grekas",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2025-12-01T09:13:36+00:00"
- }
- ],
- "packages-dev": [
- {
- "name": "amphp/amp",
- "version": "v3.1.1",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/amp.git",
- "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/amp/zipball/fa0ab33a6f47a82929c38d03ca47ebb71086a93f",
- "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1",
- "revolt/event-loop": "^1 || ^0.2"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "phpunit/phpunit": "^9",
- "psalm/phar": "5.23.1"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php",
- "src/Future/functions.php",
- "src/Internal/functions.php"
- ],
- "psr-4": {
- "Amp\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Bob Weinand",
- "email": "bobwei9@hotmail.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- },
- {
- "name": "Daniel Lowrey",
- "email": "rdlowrey@php.net"
- }
- ],
- "description": "A non-blocking concurrency framework for PHP applications.",
- "homepage": "https://amphp.org/amp",
- "keywords": [
- "async",
- "asynchronous",
- "awaitable",
- "concurrency",
- "event",
- "event-loop",
- "future",
- "non-blocking",
- "promise"
- ],
- "support": {
- "issues": "https://github.com/amphp/amp/issues",
- "source": "https://github.com/amphp/amp/tree/v3.1.1"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2025-08-27T21:42:00+00:00"
- },
- {
- "name": "amphp/byte-stream",
- "version": "v2.1.2",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/byte-stream.git",
- "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/byte-stream/zipball/55a6bd071aec26fa2a3e002618c20c35e3df1b46",
- "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^3",
- "amphp/parser": "^1.1",
- "amphp/pipeline": "^1",
- "amphp/serialization": "^1",
- "amphp/sync": "^2",
- "php": ">=8.1",
- "revolt/event-loop": "^1 || ^0.2.3"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "amphp/phpunit-util": "^3",
- "phpunit/phpunit": "^9",
- "psalm/phar": "5.22.1"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php",
- "src/Internal/functions.php"
- ],
- "psr-4": {
- "Amp\\ByteStream\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- }
- ],
- "description": "A stream abstraction to make working with non-blocking I/O simple.",
- "homepage": "https://amphp.org/byte-stream",
- "keywords": [
- "amp",
- "amphp",
- "async",
- "io",
- "non-blocking",
- "stream"
- ],
- "support": {
- "issues": "https://github.com/amphp/byte-stream/issues",
- "source": "https://github.com/amphp/byte-stream/tree/v2.1.2"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2025-03-16T17:10:27+00:00"
- },
- {
- "name": "amphp/cache",
- "version": "v2.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/cache.git",
- "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/cache/zipball/46912e387e6aa94933b61ea1ead9cf7540b7797c",
- "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^3",
- "amphp/serialization": "^1",
- "amphp/sync": "^2",
- "php": ">=8.1",
- "revolt/event-loop": "^1 || ^0.2"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "amphp/phpunit-util": "^3",
- "phpunit/phpunit": "^9",
- "psalm/phar": "^5.4"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Amp\\Cache\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- },
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Daniel Lowrey",
- "email": "rdlowrey@php.net"
- }
- ],
- "description": "A fiber-aware cache API based on Amp and Revolt.",
- "homepage": "https://amphp.org/cache",
- "support": {
- "issues": "https://github.com/amphp/cache/issues",
- "source": "https://github.com/amphp/cache/tree/v2.0.1"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2024-04-19T03:38:06+00:00"
- },
- {
- "name": "amphp/dns",
- "version": "v2.4.0",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/dns.git",
- "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/dns/zipball/78eb3db5fc69bf2fc0cb503c4fcba667bc223c71",
- "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^3",
- "amphp/byte-stream": "^2",
- "amphp/cache": "^2",
- "amphp/parser": "^1",
- "amphp/process": "^2",
- "daverandom/libdns": "^2.0.2",
- "ext-filter": "*",
- "ext-json": "*",
- "php": ">=8.1",
- "revolt/event-loop": "^1 || ^0.2"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "amphp/phpunit-util": "^3",
- "phpunit/phpunit": "^9",
- "psalm/phar": "5.20"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php"
- ],
- "psr-4": {
- "Amp\\Dns\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Chris Wright",
- "email": "addr@daverandom.com"
- },
- {
- "name": "Daniel Lowrey",
- "email": "rdlowrey@php.net"
- },
- {
- "name": "Bob Weinand",
- "email": "bobwei9@hotmail.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- },
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- }
- ],
- "description": "Async DNS resolution for Amp.",
- "homepage": "https://github.com/amphp/dns",
- "keywords": [
- "amp",
- "amphp",
- "async",
- "client",
- "dns",
- "resolve"
- ],
- "support": {
- "issues": "https://github.com/amphp/dns/issues",
- "source": "https://github.com/amphp/dns/tree/v2.4.0"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2025-01-19T15:43:40+00:00"
- },
- {
- "name": "amphp/parallel",
- "version": "v2.3.3",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/parallel.git",
- "reference": "296b521137a54d3a02425b464e5aee4c93db2c60"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/parallel/zipball/296b521137a54d3a02425b464e5aee4c93db2c60",
- "reference": "296b521137a54d3a02425b464e5aee4c93db2c60",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^3",
- "amphp/byte-stream": "^2",
- "amphp/cache": "^2",
- "amphp/parser": "^1",
- "amphp/pipeline": "^1",
- "amphp/process": "^2",
- "amphp/serialization": "^1",
- "amphp/socket": "^2",
- "amphp/sync": "^2",
- "php": ">=8.1",
- "revolt/event-loop": "^1"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "amphp/phpunit-util": "^3",
- "phpunit/phpunit": "^9",
- "psalm/phar": "^5.18"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/Context/functions.php",
- "src/Context/Internal/functions.php",
- "src/Ipc/functions.php",
- "src/Worker/functions.php"
- ],
- "psr-4": {
- "Amp\\Parallel\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- },
- {
- "name": "Stephen Coakley",
- "email": "me@stephencoakley.com"
- }
- ],
- "description": "Parallel processing component for Amp.",
- "homepage": "https://github.com/amphp/parallel",
- "keywords": [
- "async",
- "asynchronous",
- "concurrent",
- "multi-processing",
- "multi-threading"
- ],
- "support": {
- "issues": "https://github.com/amphp/parallel/issues",
- "source": "https://github.com/amphp/parallel/tree/v2.3.3"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2025-11-15T06:23:42+00:00"
- },
- {
- "name": "amphp/parser",
- "version": "v1.1.1",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/parser.git",
- "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/parser/zipball/3cf1f8b32a0171d4b1bed93d25617637a77cded7",
- "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7",
- "shasum": ""
- },
- "require": {
- "php": ">=7.4"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "phpunit/phpunit": "^9",
- "psalm/phar": "^5.4"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Amp\\Parser\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- }
- ],
- "description": "A generator parser to make streaming parsers simple.",
- "homepage": "https://github.com/amphp/parser",
- "keywords": [
- "async",
- "non-blocking",
- "parser",
- "stream"
- ],
- "support": {
- "issues": "https://github.com/amphp/parser/issues",
- "source": "https://github.com/amphp/parser/tree/v1.1.1"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2024-03-21T19:16:53+00:00"
- },
- {
- "name": "amphp/pipeline",
- "version": "v1.2.3",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/pipeline.git",
- "reference": "7b52598c2e9105ebcddf247fc523161581930367"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/pipeline/zipball/7b52598c2e9105ebcddf247fc523161581930367",
- "reference": "7b52598c2e9105ebcddf247fc523161581930367",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^3",
- "php": ">=8.1",
- "revolt/event-loop": "^1"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "amphp/phpunit-util": "^3",
- "phpunit/phpunit": "^9",
- "psalm/phar": "^5.18"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Amp\\Pipeline\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- }
- ],
- "description": "Asynchronous iterators and operators.",
- "homepage": "https://amphp.org/pipeline",
- "keywords": [
- "amp",
- "amphp",
- "async",
- "io",
- "iterator",
- "non-blocking"
- ],
- "support": {
- "issues": "https://github.com/amphp/pipeline/issues",
- "source": "https://github.com/amphp/pipeline/tree/v1.2.3"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2025-03-16T16:33:53+00:00"
- },
- {
- "name": "amphp/process",
- "version": "v2.0.3",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/process.git",
- "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/process/zipball/52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d",
- "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^3",
- "amphp/byte-stream": "^2",
- "amphp/sync": "^2",
- "php": ">=8.1",
- "revolt/event-loop": "^1 || ^0.2"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "amphp/phpunit-util": "^3",
- "phpunit/phpunit": "^9",
- "psalm/phar": "^5.4"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php"
- ],
- "psr-4": {
- "Amp\\Process\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Bob Weinand",
- "email": "bobwei9@hotmail.com"
- },
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- }
- ],
- "description": "A fiber-aware process manager based on Amp and Revolt.",
- "homepage": "https://amphp.org/process",
- "support": {
- "issues": "https://github.com/amphp/process/issues",
- "source": "https://github.com/amphp/process/tree/v2.0.3"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2024-04-19T03:13:44+00:00"
- },
- {
- "name": "amphp/serialization",
- "version": "v1.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/serialization.git",
- "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/serialization/zipball/693e77b2fb0b266c3c7d622317f881de44ae94a1",
- "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "dev-master",
- "phpunit/phpunit": "^9 || ^8 || ^7"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php"
- ],
- "psr-4": {
- "Amp\\Serialization\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- }
- ],
- "description": "Serialization tools for IPC and data storage in PHP.",
- "homepage": "https://github.com/amphp/serialization",
- "keywords": [
- "async",
- "asynchronous",
- "serialization",
- "serialize"
- ],
- "support": {
- "issues": "https://github.com/amphp/serialization/issues",
- "source": "https://github.com/amphp/serialization/tree/master"
- },
- "time": "2020-03-25T21:39:07+00:00"
- },
- {
- "name": "amphp/socket",
- "version": "v2.3.1",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/socket.git",
- "reference": "58e0422221825b79681b72c50c47a930be7bf1e1"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/socket/zipball/58e0422221825b79681b72c50c47a930be7bf1e1",
- "reference": "58e0422221825b79681b72c50c47a930be7bf1e1",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^3",
- "amphp/byte-stream": "^2",
- "amphp/dns": "^2",
- "ext-openssl": "*",
- "kelunik/certificate": "^1.1",
- "league/uri": "^6.5 | ^7",
- "league/uri-interfaces": "^2.3 | ^7",
- "php": ">=8.1",
- "revolt/event-loop": "^1 || ^0.2"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "amphp/phpunit-util": "^3",
- "amphp/process": "^2",
- "phpunit/phpunit": "^9",
- "psalm/phar": "5.20"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php",
- "src/Internal/functions.php",
- "src/SocketAddress/functions.php"
- ],
- "psr-4": {
- "Amp\\Socket\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Daniel Lowrey",
- "email": "rdlowrey@gmail.com"
- },
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- }
- ],
- "description": "Non-blocking socket connection / server implementations based on Amp and Revolt.",
- "homepage": "https://github.com/amphp/socket",
- "keywords": [
- "amp",
- "async",
- "encryption",
- "non-blocking",
- "sockets",
- "tcp",
- "tls"
- ],
- "support": {
- "issues": "https://github.com/amphp/socket/issues",
- "source": "https://github.com/amphp/socket/tree/v2.3.1"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2024-04-21T14:33:03+00:00"
- },
- {
- "name": "amphp/sync",
- "version": "v2.3.0",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/sync.git",
- "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/sync/zipball/217097b785130d77cfcc58ff583cf26cd1770bf1",
- "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^3",
- "amphp/pipeline": "^1",
- "amphp/serialization": "^1",
- "php": ">=8.1",
- "revolt/event-loop": "^1 || ^0.2"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "amphp/phpunit-util": "^3",
- "phpunit/phpunit": "^9",
- "psalm/phar": "5.23"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php"
- ],
- "psr-4": {
- "Amp\\Sync\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- },
- {
- "name": "Stephen Coakley",
- "email": "me@stephencoakley.com"
- }
- ],
- "description": "Non-blocking synchronization primitives for PHP based on Amp and Revolt.",
- "homepage": "https://github.com/amphp/sync",
- "keywords": [
- "async",
- "asynchronous",
- "mutex",
- "semaphore",
- "synchronization"
- ],
- "support": {
- "issues": "https://github.com/amphp/sync/issues",
- "source": "https://github.com/amphp/sync/tree/v2.3.0"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2024-08-03T19:31:26+00:00"
- },
- {
- "name": "danog/advanced-json-rpc",
- "version": "v3.2.3",
- "source": {
- "type": "git",
- "url": "https://github.com/danog/php-advanced-json-rpc.git",
- "reference": "ae703ea7b4811797a10590b6078de05b3b33dd91"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/danog/php-advanced-json-rpc/zipball/ae703ea7b4811797a10590b6078de05b3b33dd91",
- "reference": "ae703ea7b4811797a10590b6078de05b3b33dd91",
- "shasum": ""
- },
- "require": {
- "netresearch/jsonmapper": "^5",
- "php": ">=8.1",
- "phpdocumentor/reflection-docblock": "^4.3.4 || ^5.0.0 || ^6"
- },
- "replace": {
- "felixfbecker/php-advanced-json-rpc": "^3"
- },
- "require-dev": {
- "phpunit/phpunit": "^9"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "AdvancedJsonRpc\\": "lib/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "ISC"
- ],
- "authors": [
- {
- "name": "Felix Becker",
- "email": "felix.b@outlook.com"
- },
- {
- "name": "Daniil Gentili",
- "email": "daniil@daniil.it"
- }
- ],
- "description": "A more advanced JSONRPC implementation",
- "support": {
- "issues": "https://github.com/danog/php-advanced-json-rpc/issues",
- "source": "https://github.com/danog/php-advanced-json-rpc/tree/v3.2.3"
- },
- "time": "2026-01-12T21:07:10+00:00"
- },
- {
- "name": "daverandom/libdns",
- "version": "v2.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/DaveRandom/LibDNS.git",
- "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/DaveRandom/LibDNS/zipball/b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a",
- "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a",
- "shasum": ""
- },
- "require": {
- "ext-ctype": "*",
- "php": ">=7.1"
- },
- "suggest": {
- "ext-intl": "Required for IDN support"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php"
- ],
- "psr-4": {
- "LibDNS\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "DNS protocol implementation written in pure PHP",
- "keywords": [
- "dns"
- ],
- "support": {
- "issues": "https://github.com/DaveRandom/LibDNS/issues",
- "source": "https://github.com/DaveRandom/LibDNS/tree/v2.1.0"
- },
- "time": "2024-04-12T12:12:48+00:00"
- },
- {
- "name": "dnoegel/php-xdg-base-dir",
- "version": "v0.1.1",
- "source": {
- "type": "git",
- "url": "https://github.com/dnoegel/php-xdg-base-dir.git",
- "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd",
- "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.2"
- },
- "require-dev": {
- "phpunit/phpunit": "~7.0|~6.0|~5.0|~4.8.35"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "XdgBaseDir\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "implementation of xdg base directory specification for php",
- "support": {
- "issues": "https://github.com/dnoegel/php-xdg-base-dir/issues",
- "source": "https://github.com/dnoegel/php-xdg-base-dir/tree/v0.1.1"
- },
- "time": "2019-12-04T15:06:13+00:00"
- },
- {
- "name": "doctrine/deprecations",
- "version": "1.1.5",
- "source": {
- "type": "git",
- "url": "https://github.com/doctrine/deprecations.git",
- "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
- "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
- "shasum": ""
- },
- "require": {
- "php": "^7.1 || ^8.0"
- },
- "conflict": {
- "phpunit/phpunit": "<=7.5 || >=13"
- },
- "require-dev": {
- "doctrine/coding-standard": "^9 || ^12 || ^13",
- "phpstan/phpstan": "1.4.10 || 2.1.11",
- "phpstan/phpstan-phpunit": "^1.0 || ^2",
- "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12",
- "psr/log": "^1 || ^2 || ^3"
- },
- "suggest": {
- "psr/log": "Allows logging deprecations via PSR-3 logger implementation"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Doctrine\\Deprecations\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
- "homepage": "https://www.doctrine-project.org/",
- "support": {
- "issues": "https://github.com/doctrine/deprecations/issues",
- "source": "https://github.com/doctrine/deprecations/tree/1.1.5"
- },
- "time": "2025-04-07T20:06:18+00:00"
- },
- {
- "name": "felixfbecker/language-server-protocol",
- "version": "v1.5.3",
- "source": {
- "type": "git",
- "url": "https://github.com/felixfbecker/php-language-server-protocol.git",
- "reference": "a9e113dbc7d849e35b8776da39edaf4313b7b6c9"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/a9e113dbc7d849e35b8776da39edaf4313b7b6c9",
- "reference": "a9e113dbc7d849e35b8776da39edaf4313b7b6c9",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "require-dev": {
- "phpstan/phpstan": "*",
- "squizlabs/php_codesniffer": "^3.1",
- "vimeo/psalm": "^4.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "LanguageServerProtocol\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "ISC"
- ],
- "authors": [
- {
- "name": "Felix Becker",
- "email": "felix.b@outlook.com"
- }
- ],
- "description": "PHP classes for the Language Server Protocol",
- "keywords": [
- "language",
- "microsoft",
- "php",
- "server"
- ],
- "support": {
- "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues",
- "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.3"
- },
- "time": "2024-04-30T00:40:11+00:00"
- },
- {
- "name": "fidry/cpu-core-counter",
- "version": "1.3.0",
- "source": {
- "type": "git",
- "url": "https://github.com/theofidry/cpu-core-counter.git",
- "reference": "db9508f7b1474469d9d3c53b86f817e344732678"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678",
- "reference": "db9508f7b1474469d9d3c53b86f817e344732678",
- "shasum": ""
- },
- "require": {
- "php": "^7.2 || ^8.0"
- },
- "require-dev": {
- "fidry/makefile": "^0.2.0",
- "fidry/php-cs-fixer-config": "^1.1.2",
- "phpstan/extension-installer": "^1.2.0",
- "phpstan/phpstan": "^2.0",
- "phpstan/phpstan-deprecation-rules": "^2.0.0",
- "phpstan/phpstan-phpunit": "^2.0",
- "phpstan/phpstan-strict-rules": "^2.0",
- "phpunit/phpunit": "^8.5.31 || ^9.5.26",
- "webmozarts/strict-phpunit": "^7.5"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Fidry\\CpuCoreCounter\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Théo FIDRY",
- "email": "theo.fidry@gmail.com"
- }
- ],
- "description": "Tiny utility to get the number of CPU cores.",
- "keywords": [
- "CPU",
- "core"
- ],
- "support": {
- "issues": "https://github.com/theofidry/cpu-core-counter/issues",
- "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0"
- },
- "funding": [
- {
- "url": "https://github.com/theofidry",
- "type": "github"
- }
- ],
- "time": "2025-08-14T07:29:31+00:00"
- },
- {
- "name": "kelunik/certificate",
- "version": "v1.1.3",
- "source": {
- "type": "git",
- "url": "https://github.com/kelunik/certificate.git",
- "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/kelunik/certificate/zipball/7e00d498c264d5eb4f78c69f41c8bd6719c0199e",
- "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e",
- "shasum": ""
- },
- "require": {
- "ext-openssl": "*",
- "php": ">=7.0"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "phpunit/phpunit": "^6 | 7 | ^8 | ^9"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Kelunik\\Certificate\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- }
- ],
- "description": "Access certificate details and transform between different formats.",
- "keywords": [
- "DER",
- "certificate",
- "certificates",
- "openssl",
- "pem",
- "x509"
- ],
- "support": {
- "issues": "https://github.com/kelunik/certificate/issues",
- "source": "https://github.com/kelunik/certificate/tree/v1.1.3"
- },
- "time": "2023-02-03T21:26:53+00:00"
- },
- {
- "name": "league/uri",
- "version": "7.8.0",
- "source": {
- "type": "git",
- "url": "https://github.com/thephpleague/uri.git",
- "reference": "4436c6ec8d458e4244448b069cc572d088230b76"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/thephpleague/uri/zipball/4436c6ec8d458e4244448b069cc572d088230b76",
- "reference": "4436c6ec8d458e4244448b069cc572d088230b76",
- "shasum": ""
- },
- "require": {
- "league/uri-interfaces": "^7.8",
- "php": "^8.1",
- "psr/http-factory": "^1"
- },
- "conflict": {
- "league/uri-schemes": "^1.0"
- },
- "suggest": {
- "ext-bcmath": "to improve IPV4 host parsing",
- "ext-dom": "to convert the URI into an HTML anchor tag",
- "ext-fileinfo": "to create Data URI from file contennts",
- "ext-gmp": "to improve IPV4 host parsing",
- "ext-intl": "to handle IDN host with the best performance",
- "ext-uri": "to use the PHP native URI class",
- "jeremykendall/php-domain-parser": "to further parse the URI host and resolve its Public Suffix and Top Level Domain",
- "league/uri-components": "to provide additional tools to manipulate URI objects components",
- "league/uri-polyfill": "to backport the PHP URI extension for older versions of PHP",
- "php-64bit": "to improve IPV4 host parsing",
- "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification",
- "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "7.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "League\\Uri\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Ignace Nyamagana Butera",
- "email": "nyamsprod@gmail.com",
- "homepage": "https://nyamsprod.com"
- }
- ],
- "description": "URI manipulation library",
- "homepage": "https://uri.thephpleague.com",
- "keywords": [
- "URN",
- "data-uri",
- "file-uri",
- "ftp",
- "hostname",
- "http",
- "https",
- "middleware",
- "parse_str",
- "parse_url",
- "psr-7",
- "query-string",
- "querystring",
- "rfc2141",
- "rfc3986",
- "rfc3987",
- "rfc6570",
- "rfc8141",
- "uri",
- "uri-template",
- "url",
- "ws"
- ],
- "support": {
- "docs": "https://uri.thephpleague.com",
- "forum": "https://thephpleague.slack.com",
- "issues": "https://github.com/thephpleague/uri-src/issues",
- "source": "https://github.com/thephpleague/uri/tree/7.8.0"
- },
- "funding": [
- {
- "url": "https://github.com/sponsors/nyamsprod",
- "type": "github"
- }
- ],
- "time": "2026-01-14T17:24:56+00:00"
- },
- {
- "name": "league/uri-interfaces",
- "version": "7.8.0",
- "source": {
- "type": "git",
- "url": "https://github.com/thephpleague/uri-interfaces.git",
- "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/c5c5cd056110fc8afaba29fa6b72a43ced42acd4",
- "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4",
- "shasum": ""
- },
- "require": {
- "ext-filter": "*",
- "php": "^8.1",
- "psr/http-message": "^1.1 || ^2.0"
- },
- "suggest": {
- "ext-bcmath": "to improve IPV4 host parsing",
- "ext-gmp": "to improve IPV4 host parsing",
- "ext-intl": "to handle IDN host with the best performance",
- "php-64bit": "to improve IPV4 host parsing",
- "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification",
- "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "7.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "League\\Uri\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Ignace Nyamagana Butera",
- "email": "nyamsprod@gmail.com",
- "homepage": "https://nyamsprod.com"
- }
- ],
- "description": "Common tools for parsing and resolving RFC3987/RFC3986 URI",
- "homepage": "https://uri.thephpleague.com",
- "keywords": [
- "data-uri",
- "file-uri",
- "ftp",
- "hostname",
- "http",
- "https",
- "parse_str",
- "parse_url",
- "psr-7",
- "query-string",
- "querystring",
- "rfc3986",
- "rfc3987",
- "rfc6570",
- "uri",
- "url",
- "ws"
- ],
- "support": {
- "docs": "https://uri.thephpleague.com",
- "forum": "https://thephpleague.slack.com",
- "issues": "https://github.com/thephpleague/uri-src/issues",
- "source": "https://github.com/thephpleague/uri-interfaces/tree/7.8.0"
- },
- "funding": [
- {
- "url": "https://github.com/sponsors/nyamsprod",
- "type": "github"
- }
- ],
- "time": "2026-01-15T06:54:53+00:00"
- },
- {
- "name": "maglnet/composer-require-checker",
- "version": "4.17.0",
- "source": {
- "type": "git",
- "url": "https://github.com/maglnet/ComposerRequireChecker.git",
- "reference": "c4aeb5882988a23b22216ecf3e934ec50c072a40"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/maglnet/ComposerRequireChecker/zipball/c4aeb5882988a23b22216ecf3e934ec50c072a40",
- "reference": "c4aeb5882988a23b22216ecf3e934ec50c072a40",
- "shasum": ""
- },
- "require": {
- "composer-runtime-api": "^2.0.0",
- "ext-phar": "*",
- "nikic/php-parser": "^5.5.0",
- "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
- "symfony/console": "^6.4.1 || ^7.0.1",
- "webmozart/assert": "^1.11.0",
- "webmozart/glob": "^4.7.0"
- },
- "require-dev": {
- "doctrine/coding-standard": "^13.0.1",
- "ext-zend-opcache": "*",
- "phing/phing": "^3.0.1",
- "phpstan/phpstan": "^2.1.19",
- "phpunit/phpunit": "^11.5.27",
- "psalm/plugin-phpunit": "^0.19.5",
- "roave/infection-static-analysis-plugin": "^1.38.0",
- "spatie/temporary-directory": "^2.3.0",
- "vimeo/psalm": "^6.13.0"
- },
- "bin": [
- "bin/composer-require-checker"
- ],
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.1-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "ComposerRequireChecker\\": "src/ComposerRequireChecker"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Marco Pivetta",
- "email": "ocramius@gmail.com",
- "homepage": "http://ocramius.github.io/"
- },
- {
- "name": "Matthias Glaub",
- "email": "magl@magl.net",
- "homepage": "http://magl.net"
- }
- ],
- "description": "CLI tool to analyze composer dependencies and verify that no unknown symbols are used in the sources of a package",
- "homepage": "https://github.com/maglnet/ComposerRequireChecker",
- "keywords": [
- "cli",
- "composer",
- "dependency",
- "imports",
- "require",
- "requirements",
- "static analysis"
- ],
- "support": {
- "issues": "https://github.com/maglnet/ComposerRequireChecker/issues",
- "source": "https://github.com/maglnet/ComposerRequireChecker/tree/4.17.0"
- },
- "time": "2025-10-30T08:46:55+00:00"
- },
- {
- "name": "myclabs/deep-copy",
- "version": "1.13.4",
- "source": {
- "type": "git",
- "url": "https://github.com/myclabs/DeepCopy.git",
- "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a",
- "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a",
- "shasum": ""
- },
- "require": {
- "php": "^7.1 || ^8.0"
- },
- "conflict": {
- "doctrine/collections": "<1.6.8",
- "doctrine/common": "<2.13.3 || >=3 <3.2.2"
- },
- "require-dev": {
- "doctrine/collections": "^1.6.8",
- "doctrine/common": "^2.13.3 || ^3.2.2",
- "phpspec/prophecy": "^1.10",
- "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/DeepCopy/deep_copy.php"
- ],
- "psr-4": {
- "DeepCopy\\": "src/DeepCopy/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "Create deep copies (clones) of your objects",
- "keywords": [
- "clone",
- "copy",
- "duplicate",
- "object",
- "object graph"
- ],
- "support": {
- "issues": "https://github.com/myclabs/DeepCopy/issues",
- "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4"
- },
- "funding": [
- {
- "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
- "type": "tidelift"
- }
- ],
- "time": "2025-08-01T08:46:24+00:00"
- },
- {
- "name": "netresearch/jsonmapper",
- "version": "v5.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/cweiske/jsonmapper.git",
- "reference": "8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c",
- "reference": "8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c",
- "shasum": ""
- },
- "require": {
- "ext-json": "*",
- "ext-pcre": "*",
- "ext-reflection": "*",
- "ext-spl": "*",
- "php": ">=7.1"
- },
- "require-dev": {
- "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0",
- "squizlabs/php_codesniffer": "~3.5"
- },
- "type": "library",
- "autoload": {
- "psr-0": {
- "JsonMapper": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "OSL-3.0"
- ],
- "authors": [
- {
- "name": "Christian Weiske",
- "email": "cweiske@cweiske.de",
- "homepage": "http://github.com/cweiske/jsonmapper/",
- "role": "Developer"
- }
- ],
- "description": "Map nested JSON structures onto PHP classes",
- "support": {
- "email": "cweiske@cweiske.de",
- "issues": "https://github.com/cweiske/jsonmapper/issues",
- "source": "https://github.com/cweiske/jsonmapper/tree/v5.0.0"
- },
- "time": "2024-09-08T10:20:00+00:00"
- },
- {
- "name": "nikic/php-parser",
- "version": "v5.7.0",
- "source": {
- "type": "git",
- "url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82",
- "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82",
- "shasum": ""
- },
- "require": {
- "ext-ctype": "*",
- "ext-json": "*",
- "ext-tokenizer": "*",
- "php": ">=7.4"
- },
- "require-dev": {
- "ircmaxell/php-yacc": "^0.0.7",
- "phpunit/phpunit": "^9.0"
- },
- "bin": [
- "bin/php-parse"
- ],
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "PhpParser\\": "lib/PhpParser"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Nikita Popov"
- }
- ],
- "description": "A PHP parser written in PHP",
- "keywords": [
- "parser",
- "php"
- ],
- "support": {
- "issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0"
- },
- "time": "2025-12-06T11:56:16+00:00"
- },
- {
- "name": "phar-io/manifest",
- "version": "2.0.4",
- "source": {
- "type": "git",
- "url": "https://github.com/phar-io/manifest.git",
- "reference": "54750ef60c58e43759730615a392c31c80e23176"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
- "reference": "54750ef60c58e43759730615a392c31c80e23176",
- "shasum": ""
- },
- "require": {
- "ext-dom": "*",
- "ext-libxml": "*",
- "ext-phar": "*",
- "ext-xmlwriter": "*",
- "phar-io/version": "^3.0.1",
- "php": "^7.2 || ^8.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.0.x-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Arne Blankerts",
- "email": "arne@blankerts.de",
- "role": "Developer"
- },
- {
- "name": "Sebastian Heuer",
- "email": "sebastian@phpeople.de",
- "role": "Developer"
- },
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "Developer"
- }
- ],
- "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
- "support": {
- "issues": "https://github.com/phar-io/manifest/issues",
- "source": "https://github.com/phar-io/manifest/tree/2.0.4"
- },
- "funding": [
- {
- "url": "https://github.com/theseer",
- "type": "github"
- }
- ],
- "time": "2024-03-03T12:33:53+00:00"
- },
- {
- "name": "phar-io/version",
- "version": "3.2.1",
- "source": {
- "type": "git",
- "url": "https://github.com/phar-io/version.git",
- "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
- "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
- "shasum": ""
- },
- "require": {
- "php": "^7.2 || ^8.0"
- },
- "type": "library",
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Arne Blankerts",
- "email": "arne@blankerts.de",
- "role": "Developer"
- },
- {
- "name": "Sebastian Heuer",
- "email": "sebastian@phpeople.de",
- "role": "Developer"
- },
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "Developer"
- }
- ],
- "description": "Library for handling version information and constraints",
- "support": {
- "issues": "https://github.com/phar-io/version/issues",
- "source": "https://github.com/phar-io/version/tree/3.2.1"
- },
- "time": "2022-02-21T01:04:05+00:00"
- },
- {
- "name": "php-forge/support",
- "version": "0.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/php-forge/support.git",
- "reference": "93422a4eb618960452a76b2a30840c658a2037bc"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-forge/support/zipball/93422a4eb618960452a76b2a30840c658a2037bc",
- "reference": "93422a4eb618960452a76b2a30840c658a2037bc",
- "shasum": ""
- },
- "require": {
- "php": "^8.1",
- "phpunit/phpunit": "^10.5"
- },
- "require-dev": {
- "maglnet/composer-require-checker": "^4.7",
- "roave/infection-static-analysis-plugin": "^1.34",
- "symplify/easy-coding-standard": "^12.1",
- "vimeo/psalm": "^5.20"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "1.0.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "PHPForge\\Support\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "Support library tests for PHP",
- "keywords": [
- "php",
- "php-forge",
- "support",
- "testing",
- "tests"
- ],
- "support": {
- "issues": "https://github.com/php-forge/support/issues",
- "source": "https://github.com/php-forge/support/tree/0.1.0"
- },
- "time": "2024-01-21T10:27:18+00:00"
- },
- {
- "name": "phpdocumentor/reflection-common",
- "version": "2.2.0",
- "source": {
- "type": "git",
- "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
- "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
- "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
- "shasum": ""
- },
- "require": {
- "php": "^7.2 || ^8.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-2.x": "2.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "phpDocumentor\\Reflection\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Jaap van Otterdijk",
- "email": "opensource@ijaap.nl"
- }
- ],
- "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
- "homepage": "http://www.phpdoc.org",
- "keywords": [
- "FQSEN",
- "phpDocumentor",
- "phpdoc",
- "reflection",
- "static analysis"
- ],
- "support": {
- "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
- "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x"
- },
- "time": "2020-06-27T09:03:43+00:00"
- },
- {
- "name": "phpdocumentor/reflection-docblock",
- "version": "6.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
- "reference": "2f5cbed597cb261d1ea458f3da3a9ad32e670b1e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/2f5cbed597cb261d1ea458f3da3a9ad32e670b1e",
- "reference": "2f5cbed597cb261d1ea458f3da3a9ad32e670b1e",
- "shasum": ""
- },
- "require": {
- "doctrine/deprecations": "^1.1",
- "ext-filter": "*",
- "php": "^7.4 || ^8.0",
- "phpdocumentor/reflection-common": "^2.2",
- "phpdocumentor/type-resolver": "^2.0",
- "phpstan/phpdoc-parser": "^2.0",
- "webmozart/assert": "^1.9.1 || ^2"
- },
- "require-dev": {
- "mockery/mockery": "~1.3.5 || ~1.6.0",
- "phpstan/extension-installer": "^1.1",
- "phpstan/phpstan": "^1.8",
- "phpstan/phpstan-mockery": "^1.1",
- "phpstan/phpstan-webmozart-assert": "^1.2",
- "phpunit/phpunit": "^9.5",
- "psalm/phar": "^5.26",
- "shipmonk/dead-code-detector": "^0.5.1"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "phpDocumentor\\Reflection\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Mike van Riel",
- "email": "me@mikevanriel.com"
- },
- {
- "name": "Jaap van Otterdijk",
- "email": "opensource@ijaap.nl"
- }
- ],
- "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
- "support": {
- "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
- "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/6.0.1"
- },
- "time": "2026-01-20T15:30:42+00:00"
- },
- {
- "name": "phpdocumentor/type-resolver",
- "version": "2.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/phpDocumentor/TypeResolver.git",
- "reference": "327a05bbee54120d4786a0dc67aad30226ad4cf9"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/327a05bbee54120d4786a0dc67aad30226ad4cf9",
- "reference": "327a05bbee54120d4786a0dc67aad30226ad4cf9",
- "shasum": ""
- },
- "require": {
- "doctrine/deprecations": "^1.0",
- "php": "^7.4 || ^8.0",
- "phpdocumentor/reflection-common": "^2.0",
- "phpstan/phpdoc-parser": "^2.0"
- },
- "require-dev": {
- "ext-tokenizer": "*",
- "phpbench/phpbench": "^1.2",
- "phpstan/extension-installer": "^1.4",
- "phpstan/phpstan": "^2.1",
- "phpstan/phpstan-phpunit": "^2.0",
- "phpunit/phpunit": "^9.5",
- "psalm/phar": "^4"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-1.x": "1.x-dev",
- "dev-2.x": "2.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "phpDocumentor\\Reflection\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Mike van Riel",
- "email": "me@mikevanriel.com"
- }
- ],
- "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
- "support": {
- "issues": "https://github.com/phpDocumentor/TypeResolver/issues",
- "source": "https://github.com/phpDocumentor/TypeResolver/tree/2.0.0"
- },
- "time": "2026-01-06T21:53:42+00:00"
- },
- {
- "name": "phpstan/phpdoc-parser",
- "version": "2.3.1",
- "source": {
- "type": "git",
- "url": "https://github.com/phpstan/phpdoc-parser.git",
- "reference": "16dbf9937da8d4528ceb2145c9c7c0bd29e26374"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/16dbf9937da8d4528ceb2145c9c7c0bd29e26374",
- "reference": "16dbf9937da8d4528ceb2145c9c7c0bd29e26374",
- "shasum": ""
- },
- "require": {
- "php": "^7.4 || ^8.0"
- },
- "require-dev": {
- "doctrine/annotations": "^2.0",
- "nikic/php-parser": "^5.3.0",
- "php-parallel-lint/php-parallel-lint": "^1.2",
- "phpstan/extension-installer": "^1.0",
- "phpstan/phpstan": "^2.0",
- "phpstan/phpstan-phpunit": "^2.0",
- "phpstan/phpstan-strict-rules": "^2.0",
- "phpunit/phpunit": "^9.6",
- "symfony/process": "^5.2"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "PHPStan\\PhpDocParser\\": [
- "src/"
- ]
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "PHPDoc parser with support for nullable, intersection and generic types",
- "support": {
- "issues": "https://github.com/phpstan/phpdoc-parser/issues",
- "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.1"
- },
- "time": "2026-01-12T11:33:04+00:00"
- },
- {
- "name": "phpunit/php-code-coverage",
- "version": "10.1.16",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "7e308268858ed6baedc8704a304727d20bc07c77"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77",
- "reference": "7e308268858ed6baedc8704a304727d20bc07c77",
- "shasum": ""
- },
- "require": {
- "ext-dom": "*",
- "ext-libxml": "*",
- "ext-xmlwriter": "*",
- "nikic/php-parser": "^4.19.1 || ^5.1.0",
- "php": ">=8.1",
- "phpunit/php-file-iterator": "^4.1.0",
- "phpunit/php-text-template": "^3.0.1",
- "sebastian/code-unit-reverse-lookup": "^3.0.0",
- "sebastian/complexity": "^3.2.0",
- "sebastian/environment": "^6.1.0",
- "sebastian/lines-of-code": "^2.0.2",
- "sebastian/version": "^4.0.1",
- "theseer/tokenizer": "^1.2.3"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.1"
- },
- "suggest": {
- "ext-pcov": "PHP extension that provides line coverage",
- "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "10.1.x-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
- }
- ],
- "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
- "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
- "keywords": [
- "coverage",
- "testing",
- "xunit"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
- "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
- "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2024-08-22T04:31:57+00:00"
- },
- {
- "name": "phpunit/php-file-iterator",
- "version": "4.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
- "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c",
- "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "4.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
- }
- ],
- "description": "FilterIterator implementation that filters files based on a list of suffixes.",
- "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
- "keywords": [
- "filesystem",
- "iterator"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
- "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
- "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2023-08-31T06:24:48+00:00"
- },
- {
- "name": "phpunit/php-invoker",
- "version": "4.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/php-invoker.git",
- "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
- "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "ext-pcntl": "*",
- "phpunit/phpunit": "^10.0"
- },
- "suggest": {
- "ext-pcntl": "*"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "4.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
- }
- ],
- "description": "Invoke callables with a timeout",
- "homepage": "https://github.com/sebastianbergmann/php-invoker/",
- "keywords": [
- "process"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
- "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2023-02-03T06:56:09+00:00"
- },
- {
- "name": "phpunit/php-text-template",
- "version": "3.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/php-text-template.git",
- "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748",
- "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "3.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
- }
- ],
- "description": "Simple template engine.",
- "homepage": "https://github.com/sebastianbergmann/php-text-template/",
- "keywords": [
- "template"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
- "security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
- "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2023-08-31T14:07:24+00:00"
- },
- {
- "name": "phpunit/php-timer",
- "version": "6.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/php-timer.git",
- "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d",
- "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "6.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
- }
- ],
- "description": "Utility class for timing",
- "homepage": "https://github.com/sebastianbergmann/php-timer/",
- "keywords": [
- "timer"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/php-timer/issues",
- "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2023-02-03T06:57:52+00:00"
- },
- {
- "name": "phpunit/phpunit",
- "version": "10.5.60",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "f2e26f52f80ef77832e359205f216eeac00e320c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f2e26f52f80ef77832e359205f216eeac00e320c",
- "reference": "f2e26f52f80ef77832e359205f216eeac00e320c",
- "shasum": ""
- },
- "require": {
- "ext-dom": "*",
- "ext-json": "*",
- "ext-libxml": "*",
- "ext-mbstring": "*",
- "ext-xml": "*",
- "ext-xmlwriter": "*",
- "myclabs/deep-copy": "^1.13.4",
- "phar-io/manifest": "^2.0.4",
- "phar-io/version": "^3.2.1",
- "php": ">=8.1",
- "phpunit/php-code-coverage": "^10.1.16",
- "phpunit/php-file-iterator": "^4.1.0",
- "phpunit/php-invoker": "^4.0.0",
- "phpunit/php-text-template": "^3.0.1",
- "phpunit/php-timer": "^6.0.0",
- "sebastian/cli-parser": "^2.0.1",
- "sebastian/code-unit": "^2.0.0",
- "sebastian/comparator": "^5.0.4",
- "sebastian/diff": "^5.1.1",
- "sebastian/environment": "^6.1.0",
- "sebastian/exporter": "^5.1.4",
- "sebastian/global-state": "^6.0.2",
- "sebastian/object-enumerator": "^5.0.0",
- "sebastian/recursion-context": "^5.0.1",
- "sebastian/type": "^4.0.0",
- "sebastian/version": "^4.0.1"
- },
- "suggest": {
- "ext-soap": "To be able to generate mocks based on WSDL files"
- },
- "bin": [
- "phpunit"
- ],
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "10.5-dev"
- }
- },
- "autoload": {
- "files": [
- "src/Framework/Assert/Functions.php"
- ],
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
- }
- ],
- "description": "The PHP Unit Testing framework.",
- "homepage": "https://phpunit.de/",
- "keywords": [
- "phpunit",
- "testing",
- "xunit"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/phpunit/issues",
- "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.60"
- },
- "funding": [
- {
- "url": "https://phpunit.de/sponsors.html",
- "type": "custom"
- },
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- },
- {
- "url": "https://liberapay.com/sebastianbergmann",
- "type": "liberapay"
- },
- {
- "url": "https://thanks.dev/u/gh/sebastianbergmann",
- "type": "thanks_dev"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
- "type": "tidelift"
- }
- ],
- "time": "2025-12-06T07:50:42+00:00"
- },
- {
- "name": "psr/http-factory",
- "version": "1.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/http-factory.git",
- "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
- "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1",
- "psr/http-message": "^1.0 || ^2.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Psr\\Http\\Message\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "https://www.php-fig.org/"
- }
- ],
- "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
- "keywords": [
- "factory",
- "http",
- "message",
- "psr",
- "psr-17",
- "psr-7",
- "request",
- "response"
- ],
- "support": {
- "source": "https://github.com/php-fig/http-factory"
- },
- "time": "2024-04-15T12:06:14+00:00"
- },
- {
- "name": "psr/http-message",
- "version": "2.0",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/http-message.git",
- "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
- "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
- "shasum": ""
- },
- "require": {
- "php": "^7.2 || ^8.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.0.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Psr\\Http\\Message\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "https://www.php-fig.org/"
- }
- ],
- "description": "Common interface for HTTP messages",
- "homepage": "https://github.com/php-fig/http-message",
- "keywords": [
- "http",
- "http-message",
- "psr",
- "psr-7",
- "request",
- "response"
- ],
- "support": {
- "source": "https://github.com/php-fig/http-message/tree/2.0"
- },
- "time": "2023-04-04T09:54:51+00:00"
- },
- {
- "name": "revolt/event-loop",
- "version": "v1.0.8",
- "source": {
- "type": "git",
- "url": "https://github.com/revoltphp/event-loop.git",
- "reference": "b6fc06dce8e9b523c9946138fa5e62181934f91c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/b6fc06dce8e9b523c9946138fa5e62181934f91c",
- "reference": "b6fc06dce8e9b523c9946138fa5e62181934f91c",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "ext-json": "*",
- "jetbrains/phpstorm-stubs": "^2019.3",
- "phpunit/phpunit": "^9",
- "psalm/phar": "^5.15"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Revolt\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Cees-Jan Kiewiet",
- "email": "ceesjank@gmail.com"
- },
- {
- "name": "Christian Lück",
- "email": "christian@clue.engineering"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- }
- ],
- "description": "Rock-solid event loop for concurrent PHP applications.",
- "keywords": [
- "async",
- "asynchronous",
- "concurrency",
- "event",
- "event-loop",
- "non-blocking",
- "scheduler"
- ],
- "support": {
- "issues": "https://github.com/revoltphp/event-loop/issues",
- "source": "https://github.com/revoltphp/event-loop/tree/v1.0.8"
- },
- "time": "2025-08-27T21:33:23+00:00"
- },
- {
- "name": "sebastian/cli-parser",
- "version": "2.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/cli-parser.git",
- "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084",
- "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "2.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
- }
- ],
- "description": "Library for parsing CLI options",
- "homepage": "https://github.com/sebastianbergmann/cli-parser",
- "support": {
- "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
- "security": "https://github.com/sebastianbergmann/cli-parser/security/policy",
- "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2024-03-02T07:12:49+00:00"
- },
- {
- "name": "sebastian/code-unit",
- "version": "2.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/code-unit.git",
- "reference": "a81fee9eef0b7a76af11d121767abc44c104e503"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503",
- "reference": "a81fee9eef0b7a76af11d121767abc44c104e503",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "2.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
- }
- ],
- "description": "Collection of value objects that represent the PHP code units",
- "homepage": "https://github.com/sebastianbergmann/code-unit",
- "support": {
- "issues": "https://github.com/sebastianbergmann/code-unit/issues",
- "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2023-02-03T06:58:43+00:00"
- },
- {
- "name": "sebastian/code-unit-reverse-lookup",
- "version": "3.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
- "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
- "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "3.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- }
- ],
- "description": "Looks up which function or method a line of code belongs to",
- "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
- "support": {
- "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
- "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2023-02-03T06:59:15+00:00"
- },
- {
- "name": "sebastian/comparator",
- "version": "5.0.4",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "e8e53097718d2b53cfb2aa859b06a41abf58c62e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e8e53097718d2b53cfb2aa859b06a41abf58c62e",
- "reference": "e8e53097718d2b53cfb2aa859b06a41abf58c62e",
- "shasum": ""
- },
- "require": {
- "ext-dom": "*",
- "ext-mbstring": "*",
- "php": ">=8.1",
- "sebastian/diff": "^5.0",
- "sebastian/exporter": "^5.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.5"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "5.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- },
- {
- "name": "Jeff Welch",
- "email": "whatthejeff@gmail.com"
- },
- {
- "name": "Volker Dusch",
- "email": "github@wallbash.com"
- },
- {
- "name": "Bernhard Schussek",
- "email": "bschussek@2bepublished.at"
- }
- ],
- "description": "Provides the functionality to compare PHP values for equality",
- "homepage": "https://github.com/sebastianbergmann/comparator",
- "keywords": [
- "comparator",
- "compare",
- "equality"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/comparator/issues",
- "security": "https://github.com/sebastianbergmann/comparator/security/policy",
- "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.4"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- },
- {
- "url": "https://liberapay.com/sebastianbergmann",
- "type": "liberapay"
- },
- {
- "url": "https://thanks.dev/u/gh/sebastianbergmann",
- "type": "thanks_dev"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator",
- "type": "tidelift"
- }
- ],
- "time": "2025-09-07T05:25:07+00:00"
- },
- {
- "name": "sebastian/complexity",
- "version": "3.2.0",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/complexity.git",
- "reference": "68ff824baeae169ec9f2137158ee529584553799"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799",
- "reference": "68ff824baeae169ec9f2137158ee529584553799",
- "shasum": ""
- },
- "require": {
- "nikic/php-parser": "^4.18 || ^5.0",
- "php": ">=8.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "3.2-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
- }
- ],
- "description": "Library for calculating the complexity of PHP code units",
- "homepage": "https://github.com/sebastianbergmann/complexity",
- "support": {
- "issues": "https://github.com/sebastianbergmann/complexity/issues",
- "security": "https://github.com/sebastianbergmann/complexity/security/policy",
- "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2023-12-21T08:37:17+00:00"
- },
- {
- "name": "sebastian/diff",
- "version": "5.1.1",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/diff.git",
- "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e",
- "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.0",
- "symfony/process": "^6.4"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "5.1-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- },
- {
- "name": "Kore Nordmann",
- "email": "mail@kore-nordmann.de"
- }
- ],
- "description": "Diff implementation",
- "homepage": "https://github.com/sebastianbergmann/diff",
- "keywords": [
- "diff",
- "udiff",
- "unidiff",
- "unified diff"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/diff/issues",
- "security": "https://github.com/sebastianbergmann/diff/security/policy",
- "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2024-03-02T07:15:17+00:00"
- },
- {
- "name": "sebastian/environment",
- "version": "6.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/environment.git",
- "reference": "8074dbcd93529b357029f5cc5058fd3e43666984"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984",
- "reference": "8074dbcd93529b357029f5cc5058fd3e43666984",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.0"
- },
- "suggest": {
- "ext-posix": "*"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "6.1-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- }
- ],
- "description": "Provides functionality to handle HHVM/PHP environments",
- "homepage": "https://github.com/sebastianbergmann/environment",
- "keywords": [
- "Xdebug",
- "environment",
- "hhvm"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/environment/issues",
- "security": "https://github.com/sebastianbergmann/environment/security/policy",
- "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2024-03-23T08:47:14+00:00"
- },
- {
- "name": "sebastian/exporter",
- "version": "5.1.4",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/exporter.git",
- "reference": "0735b90f4da94969541dac1da743446e276defa6"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/0735b90f4da94969541dac1da743446e276defa6",
- "reference": "0735b90f4da94969541dac1da743446e276defa6",
- "shasum": ""
- },
- "require": {
- "ext-mbstring": "*",
- "php": ">=8.1",
- "sebastian/recursion-context": "^5.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.5"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "5.1-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- },
- {
- "name": "Jeff Welch",
- "email": "whatthejeff@gmail.com"
- },
- {
- "name": "Volker Dusch",
- "email": "github@wallbash.com"
- },
- {
- "name": "Adam Harvey",
- "email": "aharvey@php.net"
- },
- {
- "name": "Bernhard Schussek",
- "email": "bschussek@gmail.com"
- }
- ],
- "description": "Provides the functionality to export PHP variables for visualization",
- "homepage": "https://www.github.com/sebastianbergmann/exporter",
- "keywords": [
- "export",
- "exporter"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/exporter/issues",
- "security": "https://github.com/sebastianbergmann/exporter/security/policy",
- "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.4"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- },
- {
- "url": "https://liberapay.com/sebastianbergmann",
- "type": "liberapay"
- },
- {
- "url": "https://thanks.dev/u/gh/sebastianbergmann",
- "type": "thanks_dev"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter",
- "type": "tidelift"
- }
- ],
- "time": "2025-09-24T06:09:11+00:00"
- },
- {
- "name": "sebastian/global-state",
- "version": "6.0.2",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/global-state.git",
- "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
- "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1",
- "sebastian/object-reflector": "^3.0",
- "sebastian/recursion-context": "^5.0"
- },
- "require-dev": {
- "ext-dom": "*",
- "phpunit/phpunit": "^10.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "6.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- }
- ],
- "description": "Snapshotting of global state",
- "homepage": "https://www.github.com/sebastianbergmann/global-state",
- "keywords": [
- "global state"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/global-state/issues",
- "security": "https://github.com/sebastianbergmann/global-state/security/policy",
- "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2024-03-02T07:19:19+00:00"
- },
- {
- "name": "sebastian/lines-of-code",
- "version": "2.0.2",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/lines-of-code.git",
- "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0",
- "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0",
- "shasum": ""
- },
- "require": {
- "nikic/php-parser": "^4.18 || ^5.0",
- "php": ">=8.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "2.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
- }
- ],
- "description": "Library for counting the lines of code in PHP source code",
- "homepage": "https://github.com/sebastianbergmann/lines-of-code",
- "support": {
- "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
- "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
- "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2023-12-21T08:38:20+00:00"
- },
- {
- "name": "sebastian/object-enumerator",
- "version": "5.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/object-enumerator.git",
- "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906",
- "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1",
- "sebastian/object-reflector": "^3.0",
- "sebastian/recursion-context": "^5.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "5.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- }
- ],
- "description": "Traverses array structures and object graphs to enumerate all referenced objects",
- "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
- "support": {
- "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
- "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2023-02-03T07:08:32+00:00"
- },
- {
- "name": "sebastian/object-reflector",
- "version": "3.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/object-reflector.git",
- "reference": "24ed13d98130f0e7122df55d06c5c4942a577957"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957",
- "reference": "24ed13d98130f0e7122df55d06c5c4942a577957",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "3.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- }
- ],
- "description": "Allows reflection of object attributes, including inherited and non-public ones",
- "homepage": "https://github.com/sebastianbergmann/object-reflector/",
- "support": {
- "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
- "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2023-02-03T07:06:18+00:00"
- },
- {
- "name": "sebastian/recursion-context",
- "version": "5.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/recursion-context.git",
- "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/47e34210757a2f37a97dcd207d032e1b01e64c7a",
- "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.5"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "5.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- },
- {
- "name": "Jeff Welch",
- "email": "whatthejeff@gmail.com"
- },
- {
- "name": "Adam Harvey",
- "email": "aharvey@php.net"
- }
- ],
- "description": "Provides functionality to recursively process PHP variables",
- "homepage": "https://github.com/sebastianbergmann/recursion-context",
- "support": {
- "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
- "security": "https://github.com/sebastianbergmann/recursion-context/security/policy",
- "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.1"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- },
- {
- "url": "https://liberapay.com/sebastianbergmann",
- "type": "liberapay"
- },
- {
- "url": "https://thanks.dev/u/gh/sebastianbergmann",
- "type": "thanks_dev"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context",
- "type": "tidelift"
- }
- ],
- "time": "2025-08-10T07:50:56+00:00"
- },
- {
- "name": "sebastian/type",
- "version": "4.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/type.git",
- "reference": "462699a16464c3944eefc02ebdd77882bd3925bf"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf",
- "reference": "462699a16464c3944eefc02ebdd77882bd3925bf",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "4.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
- }
- ],
- "description": "Collection of value objects that represent the types of the PHP type system",
- "homepage": "https://github.com/sebastianbergmann/type",
- "support": {
- "issues": "https://github.com/sebastianbergmann/type/issues",
- "source": "https://github.com/sebastianbergmann/type/tree/4.0.0"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2023-02-03T07:10:45+00:00"
- },
- {
- "name": "sebastian/version",
- "version": "4.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/version.git",
- "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17",
- "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "4.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
- }
- ],
- "description": "Library that helps with managing the version number of Git-hosted PHP projects",
- "homepage": "https://github.com/sebastianbergmann/version",
- "support": {
- "issues": "https://github.com/sebastianbergmann/version/issues",
- "source": "https://github.com/sebastianbergmann/version/tree/4.0.1"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2023-02-07T11:34:05+00:00"
- },
- {
- "name": "spatie/array-to-xml",
- "version": "3.4.4",
- "source": {
- "type": "git",
- "url": "https://github.com/spatie/array-to-xml.git",
- "reference": "88b2f3852a922dd73177a68938f8eb2ec70c7224"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/88b2f3852a922dd73177a68938f8eb2ec70c7224",
- "reference": "88b2f3852a922dd73177a68938f8eb2ec70c7224",
- "shasum": ""
- },
- "require": {
- "ext-dom": "*",
- "php": "^8.0"
- },
- "require-dev": {
- "mockery/mockery": "^1.2",
- "pestphp/pest": "^1.21",
- "spatie/pest-plugin-snapshots": "^1.1"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "3.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Spatie\\ArrayToXml\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Freek Van der Herten",
- "email": "freek@spatie.be",
- "homepage": "https://freek.dev",
- "role": "Developer"
- }
- ],
- "description": "Convert an array to xml",
- "homepage": "https://github.com/spatie/array-to-xml",
- "keywords": [
- "array",
- "convert",
- "xml"
- ],
- "support": {
- "source": "https://github.com/spatie/array-to-xml/tree/3.4.4"
- },
- "funding": [
- {
- "url": "https://spatie.be/open-source/support-us",
- "type": "custom"
- },
- {
- "url": "https://github.com/spatie",
- "type": "github"
- }
- ],
- "time": "2025-12-15T09:00:41+00:00"
- },
- {
- "name": "symplify/easy-coding-standard",
- "version": "12.6.2",
- "source": {
- "type": "git",
- "url": "https://github.com/easy-coding-standard/easy-coding-standard.git",
- "reference": "7a6798aa424f0ecafb1542b6f5207c5a99704d3d"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/easy-coding-standard/easy-coding-standard/zipball/7a6798aa424f0ecafb1542b6f5207c5a99704d3d",
- "reference": "7a6798aa424f0ecafb1542b6f5207c5a99704d3d",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "conflict": {
- "friendsofphp/php-cs-fixer": "<3.46",
- "phpcsstandards/php_codesniffer": "<3.8",
- "symplify/coding-standard": "<12.1"
- },
- "suggest": {
- "ext-dom": "Needed to support checkstyle output format in class CheckstyleOutputFormatter"
- },
- "bin": [
- "bin/ecs"
- ],
- "type": "library",
- "autoload": {
- "files": [
- "bootstrap.php"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "Use Coding Standard with 0-knowledge of PHP-CS-Fixer and PHP_CodeSniffer",
- "keywords": [
- "Code style",
- "automation",
- "fixer",
- "static analysis"
- ],
- "support": {
- "issues": "https://github.com/easy-coding-standard/easy-coding-standard/issues",
- "source": "https://github.com/easy-coding-standard/easy-coding-standard/tree/12.6.2"
- },
- "funding": [
- {
- "url": "https://www.paypal.me/rectorphp",
- "type": "custom"
- },
- {
- "url": "https://github.com/tomasvotruba",
- "type": "github"
- }
- ],
- "time": "2025-10-29T08:51:50+00:00"
- },
- {
- "name": "theseer/tokenizer",
- "version": "1.3.1",
- "source": {
- "type": "git",
- "url": "https://github.com/theseer/tokenizer.git",
- "reference": "b7489ce515e168639d17feec34b8847c326b0b3c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c",
- "reference": "b7489ce515e168639d17feec34b8847c326b0b3c",
- "shasum": ""
- },
- "require": {
- "ext-dom": "*",
- "ext-tokenizer": "*",
- "ext-xmlwriter": "*",
- "php": "^7.2 || ^8.0"
- },
- "type": "library",
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Arne Blankerts",
- "email": "arne@blankerts.de",
- "role": "Developer"
- }
- ],
- "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
- "support": {
- "issues": "https://github.com/theseer/tokenizer/issues",
- "source": "https://github.com/theseer/tokenizer/tree/1.3.1"
- },
- "funding": [
- {
- "url": "https://github.com/theseer",
- "type": "github"
- }
- ],
- "time": "2025-11-17T20:03:58+00:00"
- },
- {
- "name": "vimeo/psalm",
- "version": "6.14.3",
- "source": {
- "type": "git",
- "url": "https://github.com/vimeo/psalm.git",
- "reference": "d0b040a91f280f071c1abcb1b77ce3822058725a"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/vimeo/psalm/zipball/d0b040a91f280f071c1abcb1b77ce3822058725a",
- "reference": "d0b040a91f280f071c1abcb1b77ce3822058725a",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^3",
- "amphp/byte-stream": "^2",
- "amphp/parallel": "^2.3",
- "composer-runtime-api": "^2",
- "composer/semver": "^1.4 || ^2.0 || ^3.0",
- "composer/xdebug-handler": "^2.0 || ^3.0",
- "danog/advanced-json-rpc": "^3.1",
- "dnoegel/php-xdg-base-dir": "^0.1.1",
- "ext-ctype": "*",
- "ext-dom": "*",
- "ext-json": "*",
- "ext-libxml": "*",
- "ext-mbstring": "*",
- "ext-simplexml": "*",
- "ext-tokenizer": "*",
- "felixfbecker/language-server-protocol": "^1.5.3",
- "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1 || ^1.0.0",
- "netresearch/jsonmapper": "^5.0",
- "nikic/php-parser": "^5.0.0",
- "php": "~8.1.31 || ~8.2.27 || ~8.3.16 || ~8.4.3 || ~8.5.0",
- "sebastian/diff": "^4.0 || ^5.0 || ^6.0 || ^7.0",
- "spatie/array-to-xml": "^2.17.0 || ^3.0",
- "symfony/console": "^6.0 || ^7.0 || ^8.0",
- "symfony/filesystem": "~6.3.12 || ~6.4.3 || ^7.0.3 || ^8.0",
- "symfony/polyfill-php84": "^1.31.0"
- },
- "provide": {
- "psalm/psalm": "self.version"
- },
- "require-dev": {
- "amphp/phpunit-util": "^3",
- "bamarni/composer-bin-plugin": "^1.4",
- "brianium/paratest": "^6.9",
- "danog/class-finder": "^0.4.8",
- "dg/bypass-finals": "^1.5",
- "ext-curl": "*",
- "mockery/mockery": "^1.5",
- "nunomaduro/mock-final-classes": "^1.1",
- "php-parallel-lint/php-parallel-lint": "^1.2",
- "phpstan/phpdoc-parser": "^1.6",
- "phpunit/phpunit": "^9.6",
- "psalm/plugin-mockery": "^1.1",
- "psalm/plugin-phpunit": "^0.19",
- "slevomat/coding-standard": "^8.4",
- "squizlabs/php_codesniffer": "^3.6",
- "symfony/process": "^6.0 || ^7.0 || ^8.0"
- },
- "suggest": {
- "ext-curl": "In order to send data to shepherd",
- "ext-igbinary": "^2.0.5 is required, used to serialize caching data"
- },
- "bin": [
- "psalm",
- "psalm-language-server",
- "psalm-plugin",
- "psalm-refactor",
- "psalm-review",
- "psalter"
- ],
- "type": "project",
- "extra": {
- "branch-alias": {
- "dev-1.x": "1.x-dev",
- "dev-2.x": "2.x-dev",
- "dev-3.x": "3.x-dev",
- "dev-4.x": "4.x-dev",
- "dev-5.x": "5.x-dev",
- "dev-6.x": "6.x-dev",
- "dev-master": "7.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Psalm\\": "src/Psalm/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Matthew Brown"
- },
- {
- "name": "Daniil Gentili",
- "email": "daniil@daniil.it"
- }
- ],
- "description": "A static analysis tool for finding errors in PHP applications",
- "keywords": [
- "code",
- "inspection",
- "php",
- "static analysis"
- ],
- "support": {
- "docs": "https://psalm.dev/docs",
- "issues": "https://github.com/vimeo/psalm/issues",
- "source": "https://github.com/vimeo/psalm"
- },
- "time": "2025-12-23T15:36:48+00:00"
- },
- {
- "name": "webmozart/assert",
- "version": "1.12.1",
- "source": {
- "type": "git",
- "url": "https://github.com/webmozarts/assert.git",
- "reference": "9be6926d8b485f55b9229203f962b51ed377ba68"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68",
- "reference": "9be6926d8b485f55b9229203f962b51ed377ba68",
- "shasum": ""
- },
- "require": {
- "ext-ctype": "*",
- "ext-date": "*",
- "ext-filter": "*",
- "php": "^7.2 || ^8.0"
- },
- "suggest": {
- "ext-intl": "",
- "ext-simplexml": "",
- "ext-spl": ""
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.10-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Webmozart\\Assert\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Bernhard Schussek",
- "email": "bschussek@gmail.com"
- }
- ],
- "description": "Assertions to validate method input/output with nice error messages.",
- "keywords": [
- "assert",
- "check",
- "validate"
- ],
- "support": {
- "issues": "https://github.com/webmozarts/assert/issues",
- "source": "https://github.com/webmozarts/assert/tree/1.12.1"
- },
- "time": "2025-10-29T15:56:20+00:00"
- },
- {
- "name": "webmozart/glob",
- "version": "4.7.0",
- "source": {
- "type": "git",
- "url": "https://github.com/webmozarts/glob.git",
- "reference": "8a2842112d6916e61e0e15e316465b611f3abc17"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/webmozarts/glob/zipball/8a2842112d6916e61e0e15e316465b611f3abc17",
- "reference": "8a2842112d6916e61e0e15e316465b611f3abc17",
- "shasum": ""
- },
- "require": {
- "php": "^7.3 || ^8.0.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^9.5",
- "symfony/filesystem": "^5.3"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "4.1-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Webmozart\\Glob\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Bernhard Schussek",
- "email": "bschussek@gmail.com"
- }
- ],
- "description": "A PHP implementation of Ant's glob.",
- "support": {
- "issues": "https://github.com/webmozarts/glob/issues",
- "source": "https://github.com/webmozarts/glob/tree/4.7.0"
- },
- "time": "2024-03-07T20:33:40+00:00"
- },
- {
- "name": "xepozz/internal-mocker",
- "version": "1.4.1",
- "source": {
- "type": "git",
- "url": "https://github.com/xepozz/internal-mocker.git",
- "reference": "cb5f8017843a2020c72acf940e43d904f58ac582"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/xepozz/internal-mocker/zipball/cb5f8017843a2020c72acf940e43d904f58ac582",
- "reference": "cb5f8017843a2020c72acf940e43d904f58ac582",
- "shasum": ""
- },
- "require": {
- "yiisoft/var-dumper": "^1.2"
- },
- "require-dev": {
- "phpunit/phpunit": "^9 || ^10 || ^11"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Xepozz\\InternalMocker\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "authors": [
- {
- "name": "Dmitrii Derepko",
- "email": "xepozz@list.ru"
- }
- ],
- "support": {
- "issues": "https://github.com/xepozz/internal-mocker/issues",
- "source": "https://github.com/xepozz/internal-mocker/tree/1.4.1"
- },
- "time": "2025-01-24T09:58:26+00:00"
- },
- {
- "name": "yiisoft/arrays",
- "version": "3.2.1",
- "source": {
- "type": "git",
- "url": "https://github.com/yiisoft/arrays.git",
- "reference": "8efada90e4fd540b3da476779bc1b7bd9319b62f"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/yiisoft/arrays/zipball/8efada90e4fd540b3da476779bc1b7bd9319b62f",
- "reference": "8efada90e4fd540b3da476779bc1b7bd9319b62f",
- "shasum": ""
- },
- "require": {
- "php": "8.1 - 8.5",
- "yiisoft/strings": "^2.6"
- },
- "require-dev": {
- "bamarni/composer-bin-plugin": "^1.8.2",
- "phpbench/phpbench": "^1.4.1",
- "phpunit/phpunit": "^10.5.48",
- "rector/rector": "^2.1.2",
- "spatie/phpunit-watcher": "^1.24"
- },
- "type": "library",
- "extra": {
- "bamarni-bin": {
- "bin-links": true,
- "forward-command": true,
- "target-directory": "tools"
- }
- },
- "autoload": {
- "psr-4": {
- "Yiisoft\\Arrays\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "description": "Yii Array Helper",
- "homepage": "https://www.yiiframework.com/",
- "keywords": [
- "array",
- "helper",
- "yii"
- ],
- "support": {
- "chat": "https://t.me/yii3en",
- "forum": "https://forum.yiiframework.com/",
- "irc": "ircs://irc.libera.chat:6697/yii",
- "issues": "https://github.com/yiisoft/arrays/issues?state=open",
- "source": "https://github.com/yiisoft/arrays",
- "wiki": "https://www.yiiframework.com/wiki/"
- },
- "funding": [
- {
- "url": "https://github.com/sponsors/yiisoft",
- "type": "github"
- },
- {
- "url": "https://opencollective.com/yiisoft",
- "type": "opencollective"
- }
- ],
- "time": "2025-11-26T12:25:21+00:00"
- },
- {
- "name": "yiisoft/strings",
- "version": "2.7.0",
- "source": {
- "type": "git",
- "url": "https://github.com/yiisoft/strings.git",
- "reference": "9bc7fea56374619cccd4587848029fe97f98bb33"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/yiisoft/strings/zipball/9bc7fea56374619cccd4587848029fe97f98bb33",
- "reference": "9bc7fea56374619cccd4587848029fe97f98bb33",
- "shasum": ""
- },
- "require": {
- "ext-mbstring": "*",
- "php": "8.1 - 8.5"
- },
- "require-dev": {
- "bamarni/composer-bin-plugin": "^1.8.2",
- "maglnet/composer-require-checker": "^4.7.1",
- "phpbench/phpbench": "^1.4.1",
- "phpunit/phpunit": "^10.5.48",
- "rector/rector": "^2.1.2",
- "spatie/phpunit-watcher": "^1.24"
- },
- "type": "library",
- "extra": {
- "bamarni-bin": {
- "bin-links": true,
- "forward-command": true,
- "target-directory": "tools"
- }
- },
- "autoload": {
- "psr-4": {
- "Yiisoft\\Strings\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "description": "Yii Strings Helper",
- "homepage": "https://www.yiiframework.com/",
- "keywords": [
- "helper",
- "string",
- "yii"
- ],
- "support": {
- "chat": "https://t.me/yii3en",
- "forum": "https://www.yiiframework.com/forum/",
- "irc": "ircs://irc.libera.chat:6697/yii",
- "issues": "https://github.com/yiisoft/strings/issues?state=open",
- "source": "https://github.com/yiisoft/strings",
- "wiki": "https://www.yiiframework.com/wiki/"
- },
- "funding": [
- {
- "url": "https://github.com/sponsors/yiisoft",
- "type": "github"
- },
- {
- "url": "https://opencollective.com/yiisoft",
- "type": "opencollective"
- }
- ],
- "time": "2025-11-23T18:00:58+00:00"
- },
- {
- "name": "yiisoft/var-dumper",
- "version": "1.7.1",
- "source": {
- "type": "git",
- "url": "https://github.com/yiisoft/var-dumper.git",
- "reference": "0860637f99fddfbeb98976bcc716b2aabc94ff85"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/yiisoft/var-dumper/zipball/0860637f99fddfbeb98976bcc716b2aabc94ff85",
- "reference": "0860637f99fddfbeb98976bcc716b2aabc94ff85",
- "shasum": ""
- },
- "require": {
- "ext-json": "*",
- "ext-mbstring": "*",
- "ext-tokenizer": "*",
- "php": "8.0 - 8.5",
- "yiisoft/arrays": "^1.0 || ^2.0 || ^3.0"
- },
- "require-dev": {
- "bamarni/composer-bin-plugin": "^1.8.3",
- "maglnet/composer-require-checker": "^4.4",
- "phpunit/phpunit": "^9.6.22",
- "rector/rector": "^2.0.10",
- "spatie/phpunit-watcher": "^1.23.6"
- },
- "suggest": {
- "ext-sockets": "Send dumps to a server through UDP/TCP protocols"
- },
- "type": "library",
- "extra": {
- "bamarni-bin": {
- "bin-links": true,
- "forward-command": true,
- "target-directory": "tools"
- }
- },
- "autoload": {
- "files": [
- "src/functions.php"
- ],
- "psr-4": {
- "Yiisoft\\VarDumper\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "description": "Enhances functionality of var_dump() and var_export(). It is dealing with recursive references, may highlight syntax and export closures.",
- "homepage": "https://www.yiiframework.com/",
- "keywords": [
- "framework",
- "helper",
- "var-dumper",
- "yii"
- ],
- "support": {
- "chat": "https://t.me/yii3en",
- "forum": "https://www.yiiframework.com/forum/",
- "irc": "ircs://irc.libera.chat:6697/yii",
- "issues": "https://github.com/yiisoft/var-dumper/issues?state=open",
- "source": "https://github.com/yiisoft/var-dumper",
- "wiki": "https://www.yiiframework.com/wiki/"
- },
- "funding": [
- {
- "url": "https://github.com/sponsors/yiisoft",
- "type": "github"
- },
- {
- "url": "https://opencollective.com/yiisoft",
- "type": "opencollective"
- }
- ],
- "time": "2025-12-01T13:24:08+00:00"
- }
- ],
- "aliases": [],
- "minimum-stability": "stable",
- "stability-flags": {},
- "prefer-stable": false,
- "prefer-lowest": false,
- "platform": {
- "ext-ctype": "*",
- "ext-mbstring": "*",
- "php": "^8.1",
- "composer-plugin-api": "^2.0"
- },
- "platform-dev": {},
- "plugin-api-version": "2.9.0"
-}
diff --git a/docs/development.md b/docs/development.md
index c06e046..4897c34 100644
--- a/docs/development.md
+++ b/docs/development.md
@@ -14,12 +14,12 @@ composer install
The project exposes a small set of Composer scripts for validation.
-| Script | Command | Purpose |
-| --- | --- | --- |
-| `test` | `composer run test` | Run the PHPUnit test suite |
-| `psalm` | `composer run psalm` | Run static analysis |
-| `easy-coding-standard` | `composer run easy-coding-standard` | Run ECS coding standards |
-| `check-dependencies` | `composer run check-dependencies` | Verify declared runtime dependencies |
+| Script | Command | Purpose |
+| ---------------------- | ----------------------------------- | ------------------------------------ |
+| `test` | `composer run test` | Run the PHPUnit test suite |
+| `psalm` | `composer run psalm` | Run static analysis |
+| `easy-coding-standard` | `composer run easy-coding-standard` | Run ECS coding standards |
+| `check-dependencies` | `composer run check-dependencies` | Verify declared runtime dependencies |
## Notes
diff --git a/ecs.php b/ecs.php
index 78342b8..4f78988 100644
--- a/ecs.php
+++ b/ecs.php
@@ -2,46 +2,94 @@
declare(strict_types=1);
-use PhpCsFixer\Fixer\ClassNotation\ClassDefinitionFixer;
-use PhpCsFixer\Fixer\ClassNotation\OrderedClassElementsFixer;
-use PhpCsFixer\Fixer\ClassNotation\OrderedTraitsFixer;
-use PhpCsFixer\Fixer\Import\NoUnusedImportsFixer;
+use PhpCsFixer\Fixer\ClassNotation\{ClassDefinitionFixer, OrderedClassElementsFixer, OrderedTraitsFixer};
+use PhpCsFixer\Fixer\Import\{NoUnusedImportsFixer, OrderedImportsFixer};
+use PhpCsFixer\Fixer\LanguageConstruct\NullableTypeDeclarationFixer;
+use PhpCsFixer\Fixer\Phpdoc\PhpdocTypesOrderFixer;
+use PhpCsFixer\Fixer\PhpUnit\PhpUnitTestCaseStaticMethodCallsFixer;
+use PhpCsFixer\Fixer\StringNotation\SingleQuoteFixer;
use Symplify\EasyCodingStandard\Config\ECSConfig;
-use Symplify\EasyCodingStandard\ValueObject\Set\SetList;
-return function (ECSConfig $ecsConfig): void {
- $ecsConfig->paths(
+return ECSConfig::configure()
+ ->withConfiguredRule(
+ ClassDefinitionFixer::class,
+ [
+ 'space_before_parenthesis' => true,
+ ],
+ )
+ ->withConfiguredRule(
+ NullableTypeDeclarationFixer::class,
+ [
+ 'syntax' => 'union',
+ ],
+ )
+ ->withConfiguredRule(
+ OrderedClassElementsFixer::class,
+ [
+ 'order' => [
+ 'use_trait',
+ 'constant_public',
+ 'constant_protected',
+ 'constant_private',
+ 'case',
+ 'property_public',
+ 'property_protected',
+ 'property_private',
+ 'construct',
+ 'destruct',
+ 'magic',
+ 'method_public_abstract',
+ 'method_protected_abstract',
+ 'method_public',
+ 'method_protected',
+ 'method_private',
+ ],
+ 'sort_algorithm' => 'alpha',
+ ],
+ )
+ ->withConfiguredRule(
+ OrderedImportsFixer::class,
+ [
+ 'imports_order' => [
+ 'class',
+ 'function',
+ 'const',
+ ],
+ 'sort_algorithm' => 'alpha',
+ ],
+ )
+ ->withConfiguredRule(
+ PhpdocTypesOrderFixer::class,
+ [
+ 'sort_algorithm' => 'none',
+ 'null_adjustment' => 'always_last',
+ ],
+ )
+ ->withConfiguredRule(
+ PhpUnitTestCaseStaticMethodCallsFixer::class,
+ [
+ 'call_type' => 'self',
+ ],
+ )
+ ->withFileExtensions(['php'])
+ ->withPaths(
[
__DIR__ . '/src',
__DIR__ . '/tests',
- ]
- );
-
- // this way you add a single rule
- $ecsConfig->rules(
+ ],
+ )
+ ->withPhpCsFixerSets(perCS30: true)
+ ->withPreparedSets(
+ cleanCode: true,
+ comments: true,
+ docblocks: true,
+ namespaces: true,
+ strict: true,
+ )
+ ->withRules(
[
- OrderedClassElementsFixer::class,
- OrderedTraitsFixer::class,
NoUnusedImportsFixer::class,
+ OrderedTraitsFixer::class,
+ SingleQuoteFixer::class,
]
);
-
- // this way you can add sets - group of rules
- $ecsConfig->sets(
- [
- // run and fix, one by one
- SetList::DOCBLOCK,
- SetList::NAMESPACES,
- SetList::COMMENTS,
- SetList::PSR_12,
- ]
- );
-
- // this way configures a rule
- $ecsConfig->ruleWithConfiguration(
- ClassDefinitionFixer::class,
- [
- 'space_before_parenthesis' => true,
- ],
- );
-};
diff --git a/infection.json5 b/infection.json5
new file mode 100644
index 0000000..1d33ec4
--- /dev/null
+++ b/infection.json5
@@ -0,0 +1,12 @@
+{
+ $schema: "./vendor/infection/infection/resources/schema.json",
+ logs: {
+ text: "php://stderr",
+ stryker: {
+ report: "main",
+ },
+ },
+ source: {
+ directories: ["src"],
+ },
+}
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
new file mode 100644
index 0000000..0d3e4ae
--- /dev/null
+++ b/phpstan-baseline.neon
@@ -0,0 +1,175 @@
+parameters:
+ ignoreErrors:
+ -
+ message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#'
+ identifier: empty.notAllowed
+ count: 3
+ path: src/Asset/AbstractAssetManager.php
+
+ -
+ message: '#^Only booleans are allowed in an if condition, string given\.$#'
+ identifier: if.condNotBoolean
+ count: 1
+ path: src/Asset/AbstractAssetManager.php
+
+ -
+ message: '#^Only booleans are allowed in an if condition, int given\.$#'
+ identifier: if.condNotBoolean
+ count: 1
+ path: src/Config/Config.php
+
+ -
+ message: '#^Unsafe call to private method Foxy\\Converter\\SemverUtil\:\:cleanWildcard\(\) through static\:\:\.$#'
+ identifier: staticClassAccess.privateMethod
+ count: 1
+ path: src/Converter/SemverUtil.php
+
+ -
+ message: '#^Only booleans are allowed in a negated boolean, mixed given\.$#'
+ identifier: booleanNot.exprNotBoolean
+ count: 1
+ path: src/Fallback/AssetFallback.php
+
+ -
+ message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#'
+ identifier: ternary.shortNotAllowed
+ count: 1
+ path: src/Fallback/AssetFallback.php
+
+ -
+ message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#'
+ identifier: empty.notAllowed
+ count: 1
+ path: src/Fallback/ComposerFallback.php
+
+ -
+ message: '#^Only booleans are allowed in a negated boolean, mixed given\.$#'
+ identifier: booleanNot.exprNotBoolean
+ count: 4
+ path: src/Fallback/ComposerFallback.php
+
+ -
+ message: '#^Only booleans are allowed in \|\|, mixed given on the left side\.$#'
+ identifier: booleanOr.leftNotBoolean
+ count: 3
+ path: src/Fallback/ComposerFallback.php
+
+ -
+ message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#'
+ identifier: ternary.shortNotAllowed
+ count: 3
+ path: src/Fallback/ComposerFallback.php
+
+ -
+ message: '#^Only booleans are allowed in an if condition, mixed given\.$#'
+ identifier: if.condNotBoolean
+ count: 1
+ path: src/Foxy.php
+
+ -
+ message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#'
+ identifier: empty.notAllowed
+ count: 2
+ path: src/Json/JsonFormatter.php
+
+ -
+ message: '#^Variable \$matches in empty\(\) always exists and is not falsy\.$#'
+ identifier: empty.variable
+ count: 1
+ path: src/Json/JsonFormatter.php
+
+ -
+ message: '#^Only booleans are allowed in &&, Foxy\\Fallback\\FallbackInterface\|null given on the right side\.$#'
+ identifier: booleanAnd.rightNotBoolean
+ count: 1
+ path: src/Solver/Solver.php
+
+ -
+ message: '#^Only booleans are allowed in a negated boolean, mixed given\.$#'
+ identifier: booleanNot.exprNotBoolean
+ count: 1
+ path: src/Solver/Solver.php
+
+ -
+ message: '#^Only booleans are allowed in \|\|, mixed given on the left side\.$#'
+ identifier: booleanOr.leftNotBoolean
+ count: 1
+ path: src/Util/ConsoleUtil.php
+
+ -
+ message: '#^Only booleans are allowed in \|\|, mixed given on the right side\.$#'
+ identifier: booleanOr.rightNotBoolean
+ count: 1
+ path: src/Util/ConsoleUtil.php
+
+ -
+ message: '#^Only booleans are allowed in an if condition, string given\.$#'
+ identifier: if.condNotBoolean
+ count: 2
+ path: tests/Config/ConfigTest.php
+
+ -
+ message: '#^Constructor of class Foxy\\Tests\\Fixtures\\Asset\\StubAssetManager has an unused parameter \$config\.$#'
+ identifier: constructor.unusedParameter
+ count: 1
+ path: tests/Fixtures/Asset/StubAssetManager.php
+
+ -
+ message: '#^Constructor of class Foxy\\Tests\\Fixtures\\Asset\\StubAssetManager has an unused parameter \$executor\.$#'
+ identifier: constructor.unusedParameter
+ count: 1
+ path: tests/Fixtures/Asset/StubAssetManager.php
+
+ -
+ message: '#^Constructor of class Foxy\\Tests\\Fixtures\\Asset\\StubAssetManager has an unused parameter \$fs\.$#'
+ identifier: constructor.unusedParameter
+ count: 1
+ path: tests/Fixtures/Asset/StubAssetManager.php
+
+ -
+ message: '#^Constructor of class Foxy\\Tests\\Fixtures\\Asset\\StubAssetManager has an unused parameter \$io\.$#'
+ identifier: constructor.unusedParameter
+ count: 1
+ path: tests/Fixtures/Asset/StubAssetManager.php
+
+ -
+ message: '#^PHPDoc tag @var with type Composer\\Installer\\PackageEvent\|PHPUnit\\Framework\\MockObject\\MockObject is not subtype of native type PHPUnit\\Framework\\MockObject\\MockObject\.$#'
+ identifier: varTag.nativeType
+ count: 1
+ path: tests/FoxyTest.php
+
+ -
+ message: '#^PHPDoc tag @var with type Foxy\\Solver\\SolverInterface\|PHPUnit\\Framework\\MockObject\\MockObject is not subtype of native type PHPUnit\\Framework\\MockObject\\MockObject\.$#'
+ identifier: varTag.nativeType
+ count: 1
+ path: tests/FoxyTest.php
+
+ -
+ message: '#^Class Composer\\Repository\\RepositoryManager constructor invoked with 2 parameters, 3\-5 required\.$#'
+ identifier: arguments.count
+ count: 1
+ path: tests/Solver/SolverTest.php
+
+ -
+ message: '#^PHPDoc tag @var with type Composer\\Package\\PackageInterface\|PHPUnit\\Framework\\MockObject\\MockObject is not subtype of native type PHPUnit\\Framework\\MockObject\\MockObject\.$#'
+ identifier: varTag.nativeType
+ count: 1
+ path: tests/Solver/SolverTest.php
+
+ -
+ message: '#^PHPDoc tag @var with type Composer\\Package\\PackageInterface\|PHPUnit\\Framework\\MockObject\\MockObject is not subtype of native type PHPUnit\\Framework\\MockObject\\MockObject\.$#'
+ identifier: varTag.nativeType
+ count: 4
+ path: tests/Util/AssetUtilTest.php
+
+ -
+ message: '#^PHPDoc tag @var with type Foxy\\Asset\\AbstractAssetManager\|PHPUnit\\Framework\\MockObject\\MockObject is not subtype of native type PHPUnit\\Framework\\MockObject\\MockObject\.$#'
+ identifier: varTag.nativeType
+ count: 2
+ path: tests/Util/AssetUtilTest.php
+
+ -
+ message: '#^PHPDoc tag @var with type Composer\\IO\\IOInterface is not subtype of native type PHPUnit\\Framework\\MockObject\\MockObject\.$#'
+ identifier: varTag.nativeType
+ count: 1
+ path: tests/Util/ConsoleUtilTest.php
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 0000000..39a2613
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,22 @@
+includes:
+ - phpstan-baseline.neon
+ # - phar://phpstan.phar/conf/bleedingEdge.neon
+
+parameters:
+ level: 2
+
+ paths:
+ - src
+ - tests
+
+ tmpDir: %currentWorkingDirectory%/runtime
+
+ # Enable strict advanced checks
+ # checkImplicitMixed: true
+ # checkBenevolentUnionTypes: true
+ # checkUninitializedProperties: true
+ # checkMissingCallableSignature: true
+ # checkTooWideReturnTypesInProtectedAndPublicMethods: true
+ # reportAnyTypeWideningInVarTag: true
+ # reportPossiblyNonexistentConstantArrayOffset: true
+ # reportPossiblyNonexistentGeneralArrayOffset: true
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 73e0a53..bb962a2 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -1,35 +1,29 @@
-
- ./tests/
+ tests
- ./src
+ ./src
-
- .php-cs-fixer.dist.php
- ./tests
- ./resources
- ./vendor
-
diff --git a/rector.php b/rector.php
new file mode 100644
index 0000000..c8db3d7
--- /dev/null
+++ b/rector.php
@@ -0,0 +1,36 @@
+parallel();
+
+ $rectorConfig->importNames();
+
+ $rectorConfig->paths(
+ [
+ __DIR__ . '/src',
+ __DIR__ . '/tests',
+ ],
+ );
+
+ $rectorConfig->sets(
+ [
+ Rector\Set\ValueObject\SetList::PHP_81,
+ Rector\Set\ValueObject\LevelSetList::UP_TO_PHP_81,
+ Rector\Set\ValueObject\SetList::TYPE_DECLARATION,
+ ],
+ );
+
+ $rectorConfig->skip(
+ [
+ Rector\TypeDeclaration\Rector\Class_\TypedPropertyFromCreateMockAssignRector::class,
+ ],
+ );
+
+ $rectorConfig->rules(
+ [
+ Rector\CodeQuality\Rector\BooleanAnd\SimplifyEmptyArrayCheckRector::class,
+ ],
+ );
+};
diff --git a/resources/doc/config.md b/resources/doc/config.md
index 7055dd5..98983b2 100644
--- a/resources/doc/config.md
+++ b/resources/doc/config.md
@@ -1,5 +1,4 @@
-Configuration
-=============
+# Configuration
## Manipulate the configuration
@@ -49,6 +48,7 @@ The accepted value types are:
- JSON array or object
**Example:**
+
```json
{
"config": {
@@ -62,6 +62,7 @@ The accepted value types are:
Can be overridden by `FOXY__ENABLED="false"` environment variable.
**Example:**
+
```json
{
"config": {
@@ -91,6 +92,7 @@ All keys starting with the prefix `manager-` can accept a unique value, but it w
a map containing the value for each manager defined by her name.
**Example:**
+
```json
{
"config": {
@@ -116,6 +118,7 @@ a map containing the value for each manager defined by her name.
You can enable or disable the plugin with the option `config.foxy.enabled` [`boolean`, default: `true`].
**Example:**
+
```json
{
"config": {
@@ -137,8 +140,8 @@ You can choose the asset manager with the option `config.foxy.manager` [`string`
- `pnpm`
- `yarn`
-
**Example:**
+
```json
{
"config": {
@@ -155,6 +158,7 @@ You can validate the version of the asset manager with the option
`config.foxy.manager-version` [`string`, default: `null`].
**Example:**
+
```json
{
"config": {
@@ -171,6 +175,7 @@ You can define the custom path of the binary of the asset manager with the optio
`config.foxy.manager-bin` [`string`, default: `null`].
**Example:**
+
```json
{
"config": {
@@ -187,6 +192,7 @@ You can add custom options for the asset manager binary for the install and upda
option `config.foxy.manager-options` [`string`, default: `null`].
**Example:**
+
```json
{
"config": {
@@ -208,6 +214,7 @@ You can add custom options for the asset manager binary for the install command
option `config.foxy.manager-install-options` [`string`, default: `null`].
**Example:**
+
```json
{
"config": {
@@ -230,6 +237,7 @@ You can add custom options for the asset manager binary for the update command w
option `config.foxy.manager-update-options` [`string`, default: `null`].
**Example:**
+
```json
{
"config": {
@@ -247,6 +255,7 @@ You can define the execution timeout of the asset manager with the
option `config.foxy.manager-timeout` [`int`, default: `PHP_INT_MAX`].
**Example:**
+
```json
{
"config": {
@@ -263,6 +272,7 @@ You can enable or disable the fallback of the asset package file with the option
`config.foxy.fallback-asset` [`boolean`, default: `true`].
**Example:**
+
```json
{
"config": {
@@ -273,12 +283,13 @@ You can enable or disable the fallback of the asset package file with the option
}
```
-### Enable/disable the fallback for the Composer lock file and its dependencies
+### Enable/disable the fallback for the Composer lockfile and its dependencies
-You can enable or disable the fallback of the Composer lock file and its dependencies with the option
+You can enable or disable the fallback of the Composer lockfile and its dependencies with the option
`config.foxy.fallback-composer` [`boolean`, default: `true`].
**Example:**
+
```json
{
"config": {
@@ -295,6 +306,7 @@ You can enable or disable the running of the asset manager with the option
`config.foxy.run-asset-manager` [`boolean`, default: `true`].
**Example:**
+
```json
{
"config": {
@@ -316,6 +328,7 @@ You can define the custom path of the mock package of PHP library with the optio
`config.foxy.composer-asset-dir` [`string`, default: `null`].
**Example:**
+
```json
{
"config": {
@@ -329,7 +342,7 @@ You can define the custom path of the mock package of PHP library with the optio
### Enable/disable manually the PHP packages with an asset package definition
By default, Foxy looks in the `composer.json` file of the PHP dependencies, if the mock package needs
-to be added into NPM or Yarn. However, some public PHP package already uses the `package.json` file
+to be added into npm or Yarn. However, some public PHP package already uses the `package.json` file
to handle their asset dependencies, but Foxy is not enabled for this package. In this case, you can
manually enable the PHP packages to be scanned in your project.
@@ -340,6 +353,7 @@ You can define the patterns to enable or disable the packages with the option
`config.foxy.enable-packages` [`array`, default: `array()`].
**Example:**
+
```json
{
"config": {
@@ -357,14 +371,12 @@ You can define the patterns to enable or disable the packages with the option
If you do not deactivate any packages, you can use a simple array.
**Example:**
+
```json
{
"config": {
"foxy": {
- "enable-packages": [
- "/^bar\/*/",
- "foo/*"
- ]
+ "enable-packages": ["/^bar\/*/", "foo/*"]
}
}
}
@@ -375,6 +387,7 @@ If you do not deactivate any packages, you can use a simple array.
You can define the custom directory for `package.json` file with the option `root-package-json-dir` [`string`, default: `null`].
**Example:**
+
```json
{
"config": {
@@ -386,6 +399,7 @@ You can define the custom directory for `package.json` file with the option `roo
```
> **Notes:**
+>
> - This path affects reading, writing, and merging the real `package.json` file, and the working directory for the asset manager.
> - Relative paths are resolved from the current working directory. Absolute paths are supported.
> - Filesystem roots such as `/` or `C:\` are preserved.
diff --git a/resources/doc/events.md b/resources/doc/events.md
index 234abaa..a32c2a0 100644
--- a/resources/doc/events.md
+++ b/resources/doc/events.md
@@ -1,5 +1,4 @@
-Events
-======
+# Events
Foxy triggers events with the event dispatcher system of Composer allowing you to extend Foxy's
capabilities. To do this, you must create a Composer plugin requiring Foxy in addition to the
diff --git a/resources/doc/faqs.md b/resources/doc/faqs.md
index d22e2e9..a3083ad 100644
--- a/resources/doc/faqs.md
+++ b/resources/doc/faqs.md
@@ -1,16 +1,13 @@
-FAQs
-====
+# FAQs
-What version required of Composer?
-----------------------------------
+## What version of Composer is required?
See the documentation: [Installation](index.md#installation).
-Why this plugin?
-----------------
+## Why this plugin?
It is certain that each language has its own dependency management system, and that it is highly recommended to use
-each package manager. NPM or Yarn works very well when the asset dependencies are managed only in the PHP project,
+each package manager. Npm or Yarn works very well when the asset dependencies are managed only in the PHP project,
but when you create PHP libraries that using assets, there is no way to automatically add asset dependencies,
and most importantly, no validation of versions can be done automatically. You must tell the developers
the list of asset dependencies that using by your PHP library, and you must ask him to add manually the asset
@@ -23,50 +20,48 @@ less possible, to use correctly all tools such as Babel, Scss, Less, etc ...
Foxy focuses solely on automation of the validation, addition, updating and deleting of the dependencies in
the definition file of the asset package, while restoring the project state, as well as PHP dependencies if
-NPM or Yarn terminates with an error.
+npm or Yarn terminates with an error.
-What is the difference between Foxy and Fxp Composer Asset Plugin?
-------------------------------------------------------------------
+## What is the difference between Foxy and Fxp Composer Asset Plugin?
When [Fxp Composer Asset Plugin](https://github.com/fxpio/composer-asset-plugin) has been created,
-it lacked some important functionality to NPM and Bower as a true lock file, the access to
+it lacked some important functionality to npm and Bower as a true lockfile, the access to
private repositories, the management of organizations (scope), and the assets was limited to a simple
download of the packages. The solution was to use the SAT solver, the VCS Repositories and the
-Composer lock file to manage the asset dependencies of the PHP libraries. However, there are 3 major
+Composer lockfile to manage the asset dependencies of the PHP libraries. However, there are 3 major
disadvantages to this approach:
1. The plugin must be installed in global mode
-2. Nodejs must be used more and more to compile some libraries
-3. The use of VCS Repositories coupled with the SAT Solver architecture of Composer is much less
- efficient than NPM, despite the optimizations of the plugin to avoid the imports
+2. Node.js must be used more and more to compile some libraries
+3. The use of VCS Repositories coupled with the SAT Solver architecture of Composer is much less efficient than npm,
+ despite the optimizations of the plugin to avoid the imports
-Now, Bower has been depreciated, NPM has a true lock file (since 5.x), as well as the possibility
-of using the private repositories, Yarn arrived with his big performances, and more and more javascript
-library requires a compilation because they use Babel, Typescript, Sass, Less, etc...
+Now, Bower has been depreciated, npm has a true lockfile (since 5.x), as well as the possibility
+of using the private repositories, Yarn arrived with his big performances, and more and more JavaScript
+library requires a compilation because they use Babel, TypeScript, Sass, Less, etc...
-Nodejs filling its gaps, and becoming more and more required, a plugin could finally perform the reverse operation,
-retaining the benefits of Fxp Composer Asset Plugin and NPM. So, conversely, Foxy creates package mocks for NPM
+Node.js filling its gaps, and becoming increasingly required, a plugin could finally perform the reverse operation,
+retaining the benefits of Fxp Composer Asset Plugin and npm. So, conversely, Foxy creates package mocks for npm
in local directory, containing only the `package.json` file from the PHP library, and adding the path of the
mock package to the project's `package.json` file. The entire validation and installation process is left
-to NPM or Yarn. However, the plugin manages the fallback if there is an error of the asset manager.
+to npm or Yarn. However, the plugin manages the fallback if there is an error of the asset manager.
To conclude, given that there is not a backward compatibility, and that it is impossible to have a version
of the plugin installed globally, and another version installed in the project - because Composer will
install the plugin in the project, but will only use the plugin installed globally - the Fxp Composer Asset
Plugin was become Foxy.
-How does the plugin work?
--------------------------
+## How does the plugin work?
-Foxy creates the mocks of Composer packages for NPM in local directory, containing only the `package.json`
+Foxy creates the mocks of Composer packages for npm in local directory, containing only the `package.json`
file from the PHP library, and adding the package path to the `package.json` file of the project.
-The name of the Composer package is converted to a format compatible with NPM, using the NPM scope
+The name of the Composer package is converted to a format compatible with npm, using the npm scope
`@composer-asset` and replacing the separation slash `/` between the vendor and the package name by
2 dashes `--`, giving consequently, the following format `@composer-asset/--`
-(this scope is reserved by Foxy in the registry of NPM and in Github).
+(this scope is reserved by Foxy in the registry of npm and in GitHub).
-NPM will install in the `node_modules/@composer-asset` folder an updated copy of each Composer package mock
+npm will install in the `node_modules/@composer-asset` folder an updated copy of each Composer package mock
that is located by default in the folder `vendor/foxy/composer-asset`.
For more details, the plugin work in this order:
@@ -75,42 +70,38 @@ For more details, the plugin work in this order:
2. Saving the status of project
3. Installing/updating of the PHP dependencies by Composer
4. Retrieving the entire list of installed packages
-5. Retains only PHP dependencies with the `foxy/foxy` dependency in the `require` or `require-dev` section of
- the `composer.json` file and with the presence of the `package.json` file
-6. Checking the lock file of asset manager
-7. Comparing the difference between the installed asset dependencies and the new asset dependencies, to determine
+5. Retains only PHP dependencies that include `foxy/foxy` dependency in `require` or `require-dev` and that contain a
+ `package.json` file
+6. Comparing the difference between the installed asset dependencies and the new asset dependencies, to determine
whether the dependency must be installed, updated, or removed
-8. Creating, updating, or deleting of the mock asset libraries in local directory, containing only the
+7. Creating, updating, or deleting of the mock asset libraries in local directory, containing only the
`package.json` file of the PHP library, with a formatted name as:
`@composer-asset/--`
-9. Adding, updating, or deleting the mock asset library in the `package.json` file of the project
-10. Running the install or update command of asset manager
-11. Restoring the `package.json` file with the previous dependencies if the asset manager terminates with an error
-12. Restoring the `composer.lock` file and all PHP dependencies if the asset manager terminates with an error
+8. Adding, updating, or deleting the mock asset library in the `package.json` file of the project
+9. Running the install or update command of asset manager
+10. Restoring the `package.json` file with the previous dependencies if the asset manager terminates with an error
+11. Restoring the `composer.lock` file and all PHP dependencies if the asset manager terminates with an error
-Is Foxy useful if my asset dependencies are defined only in my project?
------------------------------------------------------------------------
+## Is Foxy useful if my asset dependencies are defined only in my project?
Foxy is mainly focused on automating of the asset management of the PHP libraries, avoiding potentially conflicting
manual management.
Given that Foxy makes it possible to ensure that the entire management process is valid whether it is for Composer
-and NPM or Yarn, you can use Foxy even if all of your asset dependencies are only defined in the `package.json` file
+and npm or Yarn, you can use Foxy even if all of your asset dependencies are only defined in the `package.json` file
of your project. However, the value added by Foxy in this configuration will be low, and will be limited to the
management of the fallback of the PHP dependencies if there is an error of the asset manager.
-NPM/Yarn does not find the mock of the Composer dependencies
-------------------------------------------------------------
+## npm/Yarn does not find the mock of the Composer dependencies
The advantage of Foxy, is that it allows you to keep the workflows of each tool. However, Foxy creates PHP
-package mocks for NPM, and in this case, Composer must be launched before NPM or Yarn. After, nothing prevents
+package mocks for npm, and in this case, Composer must be launched before npm or Yarn. After, nothing prevents
you to using all available commands of your favorite asset manager.
-Why Foxy does nothing with the '--dry-run' option?
---------------------------------------------------
+## Why Foxy does nothing with the '--dry-run' option?
-Foxy can work with Composer's `--dry-run` option, but chose to do nothing. Given that the PHP dependencies
-are not installed, updated or deleted, Foxy can not update the `package.json` file, and so, NPM can not
+Foxy can work with Composer's `--dry-run` option, but chooses to do nothing. Given that the PHP dependencies
+are not installed, updated or deleted, Foxy cannot update the `package.json` file, and so, npm can not
check the new constraints, if any. To sum up, this amounts to running the commands
`composer update --dry-run` followed by `npm update --dry-run`.
@@ -118,7 +109,6 @@ However, with the Foxy's fallbacks, this behavior is automatically reproduced, b
dependencies, and restoring the `package.json` file, the `composer.lock` file, and all the PHP dependencies
if the asset manager finishes with an error.
-How to increase the PHP memory limit?
--------------------------------------
+## How to increase the PHP memory limit?
See the official documentation of Composer: [Memory limits errors](https://getcomposer.org/doc/articles/troubleshooting.md#memory-limit-errors).
diff --git a/resources/doc/index.md b/resources/doc/index.md
index 78d0658..5867f03 100644
--- a/resources/doc/index.md
+++ b/resources/doc/index.md
@@ -1,5 +1,4 @@
-Getting started
-===============
+# Getting started
1. [Introduction](index.md#introduction)
2. [Required dependencies](index.md#required-dependencies)
@@ -15,9 +14,9 @@ Foxy is a Composer plug-in that aggregates npm-packages from Composer packages.
This makes it possible (and automates the process of) installing and updating npm-packages that ship with your Composer packages, leveraging the native (`bun`, `npm`, `yarn`, or `pnpm`) package manager to do the heavy lifting.
-For this approach to work well, you should think of an npm-package in a Composer package not just as an "artifact", but as an actual npm-package *embedded* in your Composer package.
+For this approach to work well, you should think of an npm-package in a Composer package not just as an "artifact", but as an actual npm-package _embedded_ in your Composer package.
-Importantly, you should name it and *version* it, independently of your Composer version number - like you would normally do with a stand-alone npm-package.
+Importantly, you should name it and _version_ it, independently of your Composer version number - like you would normally do with a stand-alone npm-package.
Note that, for npm-packages with no version number, Foxy will default to the Composer version, as a fallback only: versioning your npm-package explicitly is much safer in terms of correctly versioning breaking/non-breaking changes to any client-side APIs exposed by the embedded npm-package.
diff --git a/resources/doc/usage.md b/resources/doc/usage.md
index 13046e1..7ff2716 100644
--- a/resources/doc/usage.md
+++ b/resources/doc/usage.md
@@ -1,10 +1,10 @@
-Usage
-=====
+# Usage
To use Foxy, whether for a PHP library or a PHP project, you must add the Foxy dependency in
the `require` section of the Composer file.
**composer.json:**
+
```json
{
"require": {
@@ -16,11 +16,12 @@ the `require` section of the Composer file.
And create the `package.json` file to add your asset dependencies.
**package.json:**
+
```json
{
- "dependencies": {
- "@foo/bar": "latest"
- }
+ "dependencies": {
+ "@foo/bar": "latest"
+ }
}
```
@@ -35,6 +36,7 @@ In the case if you use Foxy in a PHP library, you can render Foxy optional by ad
the `require-dev` section of the Composer file.
**composer.json:**
+
```json
{
"require-dev": {
@@ -54,6 +56,7 @@ However, if you want enable the Foxy for your library, but without required depe
you can use the extra option `extra.foxy` in your `composer.json` file:
**composer.json:**
+
```json
{
"extra": {
diff --git a/runtime/.gitignore b/runtime/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/runtime/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/src/Asset/AbstractAssetManager.php b/src/Asset/AbstractAssetManager.php
index 6d96018..669301c 100644
--- a/src/Asset/AbstractAssetManager.php
+++ b/src/Asset/AbstractAssetManager.php
@@ -2,26 +2,14 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Asset;
use Composer\IO\IOInterface;
use Composer\Package\RootPackageInterface;
use Composer\Semver\VersionParser;
-use Composer\Util\Filesystem;
-use Composer\Util\Platform;
-use Composer\Util\ProcessExecutor;
+use Composer\Util\{Filesystem, Platform, ProcessExecutor};
use Foxy\Config\Config;
-use Foxy\Converter\SemverConverter;
-use Foxy\Converter\VersionConverterInterface;
+use Foxy\Converter\{SemverConverter, VersionConverterInterface};
use Foxy\Exception\RuntimeException;
use Foxy\Fallback\FallbackInterface;
use Foxy\Json\JsonFile;
@@ -29,22 +17,20 @@
use function is_dir;
use function is_string;
use function ltrim;
+use function preg_match;
use function rtrim;
use function sprintf;
use function trim;
use const DIRECTORY_SEPARATOR;
-/**
- * Abstract Manager.
- *
- * @author François Pluchino
- */
abstract class AbstractAssetManager implements AssetManagerInterface
{
final public const NODE_MODULES_PATH = './node_modules';
+
protected bool $updatable = true;
- private null|string $version = '';
+
+ private string|null $version = '';
public function __construct(
protected IOInterface $io,
@@ -52,19 +38,39 @@ public function __construct(
protected ProcessExecutor $executor,
protected Filesystem $fs,
protected FallbackInterface|null $fallback = null,
- protected VersionConverterInterface|null $versionConverter = null
+ protected VersionConverterInterface|null $versionConverter = null,
) {
$this->versionConverter ??= new SemverConverter();
}
- public function isAvailable(): bool
- {
- return null !== $this->getVersion();
- }
+ /**
+ * Get the command to install the asset dependencies.
+ */
+ abstract protected function getInstallCommand(): string;
- public function getPackageName(): string
+ /**
+ * Get the command to update the asset dependencies.
+ */
+ abstract protected function getUpdateCommand(): string;
+
+ /**
+ * Get the command to retrieve the version.
+ */
+ abstract protected function getVersionCommand(): string;
+
+ public function addDependencies(RootPackageInterface $rootPackage, array $dependencies): AssetPackageInterface
{
- return 'package.json';
+ $assetPackage = new AssetPackage(
+ $rootPackage,
+ new JsonFile($this->getPackageJsonPath(), null, $this->io),
+ );
+ $assetPackage->removeUnusedDependencies($dependencies);
+ $alreadyInstalledDependencies = $assetPackage->addNewDependencies($dependencies);
+
+ $this->actionWhenComposerDependenciesAreAlreadyInstalled($alreadyInstalledDependencies);
+ $this->io->write('Merging Composer dependencies in the asset package ');
+
+ return $assetPackage->write();
}
public function getPackageJsonPath(): string
@@ -72,28 +78,24 @@ public function getPackageJsonPath(): string
return rtrim($this->getRootPackageDir(), '/\\') . DIRECTORY_SEPARATOR . $this->getPackageName();
}
- public function hasLockFile(): bool
+ public function getPackageName(): string
{
- return file_exists($this->getLockFilePath());
+ return 'package.json';
}
- public function isInstalled(): bool
+ public function hasLockFile(): bool
{
- return is_dir($this->getNodeModulesPath()) && file_exists($this->getPackageJsonPath());
+ return file_exists($this->getLockFilePath());
}
- public function setFallback(FallbackInterface $fallback): static
+ public function isAvailable(): bool
{
- $this->fallback = $fallback;
-
- return $this;
+ return null !== $this->getVersion();
}
- public function setUpdatable($updatable): static
+ public function isInstalled(): bool
{
- $this->updatable = $updatable;
-
- return $this;
+ return is_dir($this->getNodeModulesPath()) && file_exists($this->getPackageJsonPath());
}
public function isUpdatable(): bool
@@ -106,48 +108,6 @@ public function isValidForUpdate(): bool
return true;
}
- public function validate(): void
- {
- $version = $this->getVersion();
- /** @var string $constraintVersion */
- $constraintVersion = $this->config->get('manager-version');
-
- if (null === $version) {
- throw new RuntimeException(sprintf('The binary of "%s" must be installed', $this->getName()));
- }
-
- if ($constraintVersion) {
- $parser = new VersionParser();
- $constraint = $parser->parseConstraints($constraintVersion);
-
- if (!$constraint->matches($parser->parseConstraints($version))) {
- throw new RuntimeException(
- sprintf(
- 'The installed %s version "%s" doesn\'t match with the constraint version "%s"',
- $this->getName(),
- $version,
- $constraintVersion
- )
- );
- }
- }
- }
-
- public function addDependencies(RootPackageInterface $rootPackage, array $dependencies): AssetPackageInterface
- {
- $assetPackage = new AssetPackage(
- $rootPackage,
- new JsonFile($this->getPackageJsonPath(), null, $this->io)
- );
- $assetPackage->removeUnusedDependencies($dependencies);
- $alreadyInstalledDependencies = $assetPackage->addNewDependencies($dependencies);
-
- $this->actionWhenComposerDependenciesAreAlreadyInstalled($alreadyInstalledDependencies);
- $this->io->write('Merging Composer dependencies in the asset package ');
-
- return $assetPackage->write();
- }
-
public function run(): int
{
if (true !== $this->config->get('run-asset-manager')) {
@@ -202,12 +162,53 @@ public function run(): int
return $res;
} finally {
- if ($changedDir && null !== $originalDir) {
- if (chdir($originalDir) === false) {
- throw new RuntimeException(
- sprintf('Unable to restore working directory to "%s".', $originalDir)
- );
- }
+ if ($changedDir && null !== $originalDir && chdir($originalDir) === false) {
+ throw new RuntimeException(
+ sprintf('Unable to restore working directory to "%s".', $originalDir),
+ );
+ }
+ }
+
+ return 0;
+ }
+
+ public function setFallback(FallbackInterface $fallback): static
+ {
+ $this->fallback = $fallback;
+
+ return $this;
+ }
+
+ public function setUpdatable($updatable): static
+ {
+ $this->updatable = $updatable;
+
+ return $this;
+ }
+
+ public function validate(): void
+ {
+ $version = $this->getVersion();
+ /** @var string $constraintVersion */
+ $constraintVersion = $this->config->get('manager-version');
+
+ if (null === $version) {
+ throw new RuntimeException(sprintf('The binary of "%s" must be installed', $this->getName()));
+ }
+
+ if ($constraintVersion) {
+ $parser = new VersionParser();
+ $constraint = $parser->parseConstraints($constraintVersion);
+
+ if (!$constraint->matches($parser->parseConstraints($version))) {
+ throw new RuntimeException(
+ sprintf(
+ 'The installed %s version "%s" doesn\'t match with the constraint version "%s"',
+ $this->getName(),
+ $version,
+ $constraintVersion,
+ ),
+ );
}
}
}
@@ -224,6 +225,36 @@ protected function actionWhenComposerDependenciesAreAlreadyInstalled(array $name
// do nothing by default
}
+ /**
+ * Build the command with binary and command options.
+ *
+ * @param string $defaultBin The default binary of command if option isn't defined.
+ * @param string $action The command action to retrieve the options in config.
+ * @param array|string $command The command.
+ */
+ protected function buildCommand(string $defaultBin, string $action, array|string $command): string
+ {
+ $bin = $this->config->get('manager-bin', $defaultBin);
+ $bin = Platform::isWindows() ? str_replace('/', '\\', (string) $bin) : $bin;
+ $gOptions = trim((string) $this->config->get('manager-options', ''));
+ $options = trim((string) $this->config->get('manager-' . $action . '-options', ''));
+
+ /** @psalm-var string|string[] $command */
+ return (string) $bin . ' ' . implode(' ', (array) $command)
+ . (empty($gOptions) ? '' : ' ' . $gOptions)
+ . (empty($options) ? '' : ' ' . $options);
+ }
+
+ protected function getLockFilePath(): string
+ {
+ return rtrim($this->getRootPackageDir(), '/\\') . DIRECTORY_SEPARATOR . $this->getLockPackageName();
+ }
+
+ protected function getNodeModulesPath(): string
+ {
+ return rtrim($this->getRootPackageDir(), '/\\') . DIRECTORY_SEPARATOR . ltrim(self::NODE_MODULES_PATH, './');
+ }
+
protected function getRootPackageDir(): string
{
$rootPackageDir = $this->config->get('root-package-json-dir');
@@ -233,7 +264,7 @@ protected function getRootPackageDir(): string
if ('' === $rootPackageDir) {
$rootPackageDir = DIRECTORY_SEPARATOR;
- } elseif (1 === \preg_match('/^[A-Za-z]:$/', $rootPackageDir)) {
+ } elseif (1 === preg_match('/^[A-Za-z]:$/', $rootPackageDir)) {
$rootPackageDir .= DIRECTORY_SEPARATOR;
}
@@ -259,67 +290,24 @@ protected function getRootPackageDir(): string
return $currentDir;
}
- protected function getLockFilePath(): string
- {
- return rtrim($this->getRootPackageDir(), '/\\') . DIRECTORY_SEPARATOR . $this->getLockPackageName();
- }
-
- protected function getNodeModulesPath(): string
- {
- return rtrim($this->getRootPackageDir(), '/\\') . DIRECTORY_SEPARATOR . ltrim(self::NODE_MODULES_PATH, './');
- }
-
- /**
- * Build the command with binary and command options.
- *
- * @param string $defaultBin The default binary of command if option isn't defined.
- * @param string $action The command action to retrieve the options in config.
- * @param array|string $command The command.
- */
- protected function buildCommand(string $defaultBin, string $action, array|string $command): string
- {
- $bin = $this->config->get('manager-bin', $defaultBin);
- $bin = Platform::isWindows() ? str_replace('/', '\\', (string) $bin) : $bin;
- $gOptions = trim((string) $this->config->get('manager-options', ''));
- $options = trim((string) $this->config->get('manager-' . $action . '-options', ''));
-
- /** @psalm-var string|string[] $command */
- return (string) $bin . ' ' . implode(' ', (array) $command)
- . (empty($gOptions) ? '' : ' ' . $gOptions)
- . (empty($options) ? '' : ' ' . $options);
- }
-
protected function getVersion(): string|null
{
if ($this->version === '' && $this->versionConverter !== null) {
$this->executor->execute($this->getVersionCommand(), $version);
- $this->version = '' !== trim((string) $version) ? $this->versionConverter->convertVersion(trim((string) $version)) : null;
+ $this->version = '' !== trim((string) $version)
+ ? $this->versionConverter->convertVersion(trim((string) $version))
+ : null;
}
return $this->version;
}
- /**
- * Get the command to retrieve the version.
- */
- abstract protected function getVersionCommand(): string;
-
- /**
- * Get the command to install the asset dependencies.
- */
- abstract protected function getInstallCommand(): string;
-
- /**
- * Get the command to update the asset dependencies.
- */
- abstract protected function getUpdateCommand(): string;
-
private function isAbsolutePath(string $path): bool
{
if ('/' === $path[0] || '\\' === $path[0]) {
return true;
}
- return (bool) \preg_match('/^[A-Za-z]:[\\\\\/]/', $path);
+ return (bool) preg_match('/^[A-Za-z]:[\\\\\/]/', $path);
}
}
diff --git a/src/Asset/AssetManagerFinder.php b/src/Asset/AssetManagerFinder.php
index 6f0c9dc..a7dfda1 100644
--- a/src/Asset/AssetManagerFinder.php
+++ b/src/Asset/AssetManagerFinder.php
@@ -2,24 +2,12 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Asset;
use Foxy\Exception\RuntimeException;
-/**
- * Asset Manager finder.
- *
- * @author François Pluchino
- */
+use function sprintf;
+
final class AssetManagerFinder
{
/**
diff --git a/src/Asset/AssetManagerInterface.php b/src/Asset/AssetManagerInterface.php
index 93abb73..617b269 100644
--- a/src/Asset/AssetManagerInterface.php
+++ b/src/Asset/AssetManagerInterface.php
@@ -2,37 +2,31 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Asset;
use Composer\Package\RootPackageInterface;
use Foxy\Exception\RuntimeException;
use Foxy\Fallback\FallbackInterface;
-/**
- * Interface of asset manager.
- *
- * @author François Pluchino
- */
interface AssetManagerInterface
{
/**
- * Get the name of asset manager.
+ * Add the asset dependencies in asset package file.
+ *
+ * @param RootPackageInterface $rootPackage The composer root package
+ * @param array $dependencies The asset local dependencies
*/
- public function getName(): string;
+ public function addDependencies(RootPackageInterface $rootPackage, array $dependencies): AssetPackageInterface;
/**
- * Check if the asset manager is available.
+ * Get the filename of the lock file.
*/
- public function isAvailable(): bool;
+ public function getLockPackageName(): string;
+
+ /**
+ * Get the name of asset manager.
+ */
+ public function getName(): string;
/**
* Get the filename of the asset package.
@@ -45,23 +39,14 @@ public function getPackageName(): string;
public function hasLockFile(): bool;
/**
- * Check if the asset dependencies are installed or not.
- */
- public function isInstalled(): bool;
-
- /**
- * Set the fallback.
- *
- * @param FallbackInterface $fallback The fallback
+ * Check if the asset manager is available.
*/
- public function setFallback(FallbackInterface $fallback): self;
+ public function isAvailable(): bool;
/**
- * Define if the asset manager can be use the update command.
- *
- * @param bool $updatable The value
+ * Check if the asset dependencies are installed or not.
*/
- public function setUpdatable(bool $updatable): self;
+ public function isInstalled(): bool;
/**
* Check if the asset manager can be use the update command or not.
@@ -74,28 +59,29 @@ public function isUpdatable(): bool;
public function isValidForUpdate(): bool;
/**
- * Get the filename of the lock file.
+ * Run the asset manager to install/update the asset dependencies.
*/
- public function getLockPackageName(): string;
+ public function run(): int;
/**
- * Validate the version of asset manager.
+ * Set the fallback.
*
- * @throws RuntimeException When the binary isn't installed
- * @throws RuntimeException When the version doesn't match
+ * @param FallbackInterface $fallback The fallback
*/
- public function validate(): void;
+ public function setFallback(FallbackInterface $fallback): self;
/**
- * Add the asset dependencies in asset package file.
+ * Define if the asset manager can be use the update command.
*
- * @param RootPackageInterface $rootPackage The composer root package
- * @param array $dependencies The asset local dependencies
+ * @param bool $updatable The value
*/
- public function addDependencies(RootPackageInterface $rootPackage, array $dependencies): AssetPackageInterface;
+ public function setUpdatable(bool $updatable): self;
/**
- * Run the asset manager to install/update the asset dependencies.
+ * Validate the version of asset manager.
+ *
+ * @throws RuntimeException When the binary isn't installed
+ * @throws RuntimeException When the version doesn't match
*/
- public function run(): int;
+ public function validate(): void;
}
diff --git a/src/Asset/AssetPackage.php b/src/Asset/AssetPackage.php
index f6d6c93..73289a3 100644
--- a/src/Asset/AssetPackage.php
+++ b/src/Asset/AssetPackage.php
@@ -2,40 +2,35 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Asset;
use Composer\Json\JsonFile;
use Composer\Package\RootPackageInterface;
+use Exception;
+use Seld\JsonLint\ParsingException;
+
+use function count;
+use function dirname;
+use function is_array;
-/**
- * Asset package.
- *
- * @author François Pluchino
- */
final class AssetPackage implements AssetPackageInterface
{
+ public const COMPOSER_PREFIX = '@composer-asset/';
+
public const SECTION_DEPENDENCIES = 'dependencies';
+
public const SECTION_DEV_DEPENDENCIES = 'devDependencies';
- public const COMPOSER_PREFIX = '@composer-asset/';
- protected array $package = [];
+
+ private array $package = [];
/**
* @param RootPackageInterface $rootPackage The composer root package
- * @param JsonFile $jsonFile The json file
+ * @param JsonFile $jsonFile The JSON file
+ *
+ * @throws ParsingException
*/
- public function __construct(RootPackageInterface $rootPackage, protected JsonFile $jsonFile)
+ public function __construct(RootPackageInterface $rootPackage, private readonly JsonFile $jsonFile)
{
- $this->jsonFile = $jsonFile;
-
if ($jsonFile->exists()) {
$this->setPackage((array) $jsonFile->read());
}
@@ -43,44 +38,6 @@ public function __construct(RootPackageInterface $rootPackage, protected JsonFil
$this->injectRequiredKeys($rootPackage);
}
- public function write(): self
- {
- $this->jsonFile->write($this->package);
-
- return $this;
- }
-
- public function setPackage(array $package): self
- {
- $this->package = $package;
-
- return $this;
- }
-
- public function getPackage(): array
- {
- return $this->package;
- }
-
- public function getInstalledDependencies(): array
- {
- $installedAssets = [];
-
- if (isset($this->package[self::SECTION_DEPENDENCIES]) && \is_array($this->package[self::SECTION_DEPENDENCIES])) {
- /**
- * @var string $dependency
- * @var string $version
- */
- foreach ($this->package[self::SECTION_DEPENDENCIES] as $dependency => $version) {
- if (str_starts_with($dependency, self::COMPOSER_PREFIX)) {
- $installedAssets[$dependency] = $version;
- }
- }
- }
-
- return $installedAssets;
- }
-
/**
* Add new dependencies.
*
@@ -105,7 +62,7 @@ public function addNewDependencies(array $dependencies): array
if (isset($installedAssets[$name])) {
$existingPackages[] = $name;
} else {
- $this->package[self::SECTION_DEPENDENCIES][$name] = 'file:./' . \dirname($path);
+ $this->package[self::SECTION_DEPENDENCIES][$name] = 'file:./' . dirname($path);
}
}
@@ -115,6 +72,30 @@ public function addNewDependencies(array $dependencies): array
return $existingPackages;
}
+ public function getInstalledDependencies(): array
+ {
+ $installedAssets = [];
+
+ if (isset($this->package[self::SECTION_DEPENDENCIES]) && is_array($this->package[self::SECTION_DEPENDENCIES])) {
+ /**
+ * @var string $dependency
+ * @var string $version
+ */
+ foreach ($this->package[self::SECTION_DEPENDENCIES] as $dependency => $version) {
+ if (str_starts_with($dependency, self::COMPOSER_PREFIX)) {
+ $installedAssets[$dependency] = $version;
+ }
+ }
+ }
+
+ return $installedAssets;
+ }
+
+ public function getPackage(): array
+ {
+ return $this->package;
+ }
+
/**
* @psalm-suppress MixedArrayAccess
*/
@@ -130,14 +111,31 @@ public function removeUnusedDependencies(array $dependencies): self
return $this;
}
+ public function setPackage(array $package): self
+ {
+ $this->package = $package;
+
+ return $this;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function write(): self
+ {
+ $this->jsonFile->write($this->package);
+
+ return $this;
+ }
+
/**
* Inject the required keys for asset package defined in root composer package.
*
* @param RootPackageInterface $rootPackage The composer root package
*/
- protected function injectRequiredKeys(RootPackageInterface $rootPackage): void
+ private function injectRequiredKeys(RootPackageInterface $rootPackage): void
{
- if (!isset($this->package['license']) && \count($rootPackage->getLicense()) > 0) {
+ if (!isset($this->package['license']) && count($rootPackage->getLicense()) > 0) {
$license = current($rootPackage->getLicense());
if ('proprietary' === $license) {
@@ -155,9 +153,9 @@ protected function injectRequiredKeys(RootPackageInterface $rootPackage): void
*
* @param string $section The package section
*/
- protected function orderPackages(string $section): void
+ private function orderPackages(string $section): void
{
- if (isset($this->package[$section]) && \is_array($this->package[$section])) {
+ if (isset($this->package[$section]) && is_array($this->package[$section])) {
ksort($this->package[$section], SORT_STRING);
}
}
diff --git a/src/Asset/AssetPackageInterface.php b/src/Asset/AssetPackageInterface.php
index b6b1c45..9a916be 100644
--- a/src/Asset/AssetPackageInterface.php
+++ b/src/Asset/AssetPackageInterface.php
@@ -2,35 +2,25 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Asset;
-/**
- * Interface of asset package.
- *
- * @author François Pluchino
- */
interface AssetPackageInterface
{
/**
- * Write the asset package in file.
+ * Add the new asset dependencies and return the names of already installed asset dependencies.
+ *
+ * @param array $dependencies The asset dependencies
+ *
+ * @return array The asset package name of the already asset dependencies
*/
- public function write(): self;
+ public function addNewDependencies(array $dependencies): array;
/**
- * Set the asset package.
+ * Get the installed asset dependencies.
*
- * @param array $package The asset package
+ * @return array The installed asset dependencies
*/
- public function setPackage(array $package): self;
+ public function getInstalledDependencies(): array;
/**
* Get the asset package.
@@ -38,25 +28,21 @@ public function setPackage(array $package): self;
public function getPackage(): array;
/**
- * Get the installed asset dependencies.
+ * Remove the unused asset dependencies.
*
- * @return array The installed asset dependencies
+ * @param array $dependencies All asset dependencies
*/
- public function getInstalledDependencies(): array;
+ public function removeUnusedDependencies(array $dependencies): self;
/**
- * Add the new asset dependencies and return the names of already installed asset dependencies.
- *
- * @param array $dependencies The asset dependencies
+ * Set the asset package.
*
- * @return array The asset package name of the already asset dependencies
+ * @param array $package The asset package
*/
- public function addNewDependencies(array $dependencies): array;
+ public function setPackage(array $package): self;
/**
- * Remove the unused asset dependencies.
- *
- * @param array $dependencies All asset dependencies
+ * Write the asset package in file.
*/
- public function removeUnusedDependencies(array $dependencies): self;
+ public function write(): self;
}
diff --git a/src/Asset/BunManager.php b/src/Asset/BunManager.php
index 9b2429e..ef8dea9 100644
--- a/src/Asset/BunManager.php
+++ b/src/Asset/BunManager.php
@@ -2,34 +2,20 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Asset;
use Composer\Util\Platform;
-/**
- * Bun Manager.
- *
- * @author Wilmer Arambula (terabytesfotw@gmail.com)
- */
final class BunManager extends AbstractAssetManager
{
- public function getName(): string
+ public function getLockPackageName(): string
{
- return 'bun';
+ return 'yarn.lock';
}
- public function getLockPackageName(): string
+ public function getName(): string
{
- return 'yarn.lock';
+ return 'bun';
}
public function isInstalled(): bool
@@ -37,24 +23,24 @@ public function isInstalled(): bool
return parent::isInstalled() && file_exists($this->getLockFilePath());
}
- protected function getVersionCommand(): string
+ protected function getInstallCommand(): string
{
$command = Platform::isWindows() ? 'bun.exe' : 'bun';
- return $this->buildCommand($command, 'version', '--version');
+ return $this->buildCommand($command, 'install', 'install -y');
}
- protected function getInstallCommand(): string
+ protected function getUpdateCommand(): string
{
$command = Platform::isWindows() ? 'bun.exe' : 'bun';
- return $this->buildCommand($command, 'install', 'install -y');
+ return $this->buildCommand($command, 'update', 'update -y');
}
- protected function getUpdateCommand(): string
+ protected function getVersionCommand(): string
{
$command = Platform::isWindows() ? 'bun.exe' : 'bun';
- return $this->buildCommand($command, 'update', 'update -y');
+ return $this->buildCommand($command, 'version', '--version');
}
}
diff --git a/src/Asset/NpmManager.php b/src/Asset/NpmManager.php
index 94c3c46..bdf9dff 100644
--- a/src/Asset/NpmManager.php
+++ b/src/Asset/NpmManager.php
@@ -2,37 +2,25 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Asset;
-/**
- * NPM Manager.
- *
- * @author François Pluchino
- */
final class NpmManager extends AbstractAssetManager
{
- public function getName(): string
+ public function getLockPackageName(): string
{
- return 'npm';
+ return 'package-lock.json';
}
- public function getLockPackageName(): string
+ public function getName(): string
{
- return 'package-lock.json';
+ return 'npm';
}
- protected function getVersionCommand(): string
+ protected function actionWhenComposerDependenciesAreAlreadyInstalled(array $names): void
{
- return $this->buildCommand('npm', 'version', '--version');
+ foreach ($names as $name) {
+ $this->fs->remove(self::NODE_MODULES_PATH . '/' . $name);
+ }
}
protected function getInstallCommand(): string
@@ -45,10 +33,8 @@ protected function getUpdateCommand(): string
return $this->buildCommand('npm', 'update', 'update');
}
- protected function actionWhenComposerDependenciesAreAlreadyInstalled(array $names): void
+ protected function getVersionCommand(): string
{
- foreach ($names as $name) {
- $this->fs->remove(self::NODE_MODULES_PATH . '/' . $name);
- }
+ return $this->buildCommand('npm', 'version', '--version');
}
}
diff --git a/src/Asset/PnpmManager.php b/src/Asset/PnpmManager.php
index 8a60e81..65837ec 100644
--- a/src/Asset/PnpmManager.php
+++ b/src/Asset/PnpmManager.php
@@ -2,42 +2,23 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Asset;
-/**
- * Pnpm Manager.
- *
- * @author Steffen Dietz
- */
final class PnpmManager extends AbstractAssetManager
{
- public function getName(): string
- {
- return 'pnpm';
- }
-
public function getLockPackageName(): string
{
return 'pnpm-lock.yaml';
}
- public function isInstalled(): bool
+ public function getName(): string
{
- return parent::isInstalled() && file_exists($this->getLockFilePath());
+ return 'pnpm';
}
- protected function getVersionCommand(): string
+ public function isInstalled(): bool
{
- return $this->buildCommand('pnpm', 'version', '--version');
+ return parent::isInstalled() && file_exists($this->getLockFilePath());
}
protected function getInstallCommand(): string
@@ -49,4 +30,9 @@ protected function getUpdateCommand(): string
{
return $this->buildCommand('pnpm', 'update', 'update');
}
+
+ protected function getVersionCommand(): string
+ {
+ return $this->buildCommand('pnpm', 'version', '--version');
+ }
}
diff --git a/src/Asset/YarnManager.php b/src/Asset/YarnManager.php
index b779be6..cf13ede 100644
--- a/src/Asset/YarnManager.php
+++ b/src/Asset/YarnManager.php
@@ -2,34 +2,20 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Asset;
use Composer\Semver\VersionParser;
-/**
- * Yarn Manager.
- *
- * @author François Pluchino
- */
final class YarnManager extends AbstractAssetManager
{
- public function getName(): string
+ public function getLockPackageName(): string
{
- return 'yarn';
+ return 'yarn.lock';
}
- public function getLockPackageName(): string
+ public function getName(): string
{
- return 'yarn.lock';
+ return 'yarn';
}
public function isInstalled(): bool
@@ -48,11 +34,6 @@ public function isValidForUpdate(): bool
return 0 === $this->executor->execute($cmd);
}
- protected function getVersionCommand(): string
- {
- return $this->buildCommand('yarn', 'version', '--version');
- }
-
protected function getInstallCommand(): string
{
return $this->buildCommand('yarn', 'install', $this->mergeInteractiveCommand(['install']));
@@ -65,13 +46,18 @@ protected function getUpdateCommand(): string
return $this->buildCommand('yarn', 'update', $this->mergeInteractiveCommand([$commandName]));
}
+ protected function getVersionCommand(): string
+ {
+ return $this->buildCommand('yarn', 'version', '--version');
+ }
+
private function isYarnNext(): bool
{
$version = $this->getVersion();
$parser = new VersionParser();
$constraint = $parser->parseConstraints('>=2.0.0');
- return $version !== null ? $constraint->matches($parser->parseConstraints($version)) : false;
+ return $version !== null && $constraint->matches($parser->parseConstraints($version));
}
private function mergeInteractiveCommand(array $command): array
diff --git a/src/Config/Config.php b/src/Config/Config.php
index a3ba67f..072ad05 100644
--- a/src/Config/Config.php
+++ b/src/Config/Config.php
@@ -2,24 +2,22 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Config;
use Foxy\Exception\RuntimeException;
-/**
- * Helper of package config.
- *
- * @author François Pluchino
- */
+use function array_key_exists;
+use function ctype_digit;
+use function in_array;
+use function is_array;
+use function json_decode;
+use function json_last_error;
+use function sprintf;
+use function str_replace;
+use function str_starts_with;
+use function strtoupper;
+use function trim;
+
class Config
{
private array $cacheEnv = [];
@@ -28,24 +26,7 @@ class Config
* @param array $config The config.
* @param array $defaults The default values.
*/
- public function __construct(private array $config, private array $defaults = [])
- {
- $this->config = $config;
- $this->defaults = $defaults;
- }
-
- /**
- * Get the array config value.
- *
- * @param string $key The config key.
- * @param array $default The default value.
- */
- public function getArray(string $key, array $default = []): array
- {
- $value = $this->get($key, null);
-
- return is_array($value) ? $value : $default;
- }
+ public function __construct(private readonly array $config, private readonly array $defaults = []) {}
/**
* Get the config value.
@@ -55,7 +36,7 @@ public function getArray(string $key, array $default = []): array
*/
public function get(string $key, mixed $default = null): mixed
{
- if (\array_key_exists($key, $this->cacheEnv)) {
+ if (array_key_exists($key, $this->cacheEnv)) {
return $this->cacheEnv[$key];
}
@@ -68,11 +49,34 @@ public function get(string $key, mixed $default = null): mixed
$defaultValue = $this->getDefaultValue($key, $default);
- return \array_key_exists($key, $this->config)
+ return array_key_exists($key, $this->config)
? $this->getByManager($key, $this->config[$key], $defaultValue)
: $defaultValue;
}
+ /**
+ * Get the array config value.
+ *
+ * @param string $key The config key.
+ * @param array $default The default value.
+ */
+ public function getArray(string $key, array $default = []): array
+ {
+ $value = $this->get($key);
+
+ return is_array($value) ? $value : $default;
+ }
+
+ /**
+ * Convert the value of environment variable into a boolean.
+ *
+ * @param string $value The value of environment variable.
+ */
+ private function convertBoolean(string $value): bool
+ {
+ return in_array($value, ['true', '1', 'yes', 'y'], true);
+ }
+
/**
* Convert the config key into environment variable.
*
@@ -105,39 +109,7 @@ private function convertEnvValue(string $value, string $environmentVariable): ar
}
/**
- * Check if the value of environment variable is a boolean.
- *
- * @param string $value The value of environment variable.
- */
- private function isBoolean(string $value): bool
- {
- $value = strtolower($value);
-
- return \in_array($value, ['true', 'false', '1', '0', 'yes', 'no', 'y', 'n'], true);
- }
-
- /**
- * Convert the value of environment variable into a boolean.
- *
- * @param string $value The value of environment variable.
- */
- private function convertBoolean(string $value): bool
- {
- return \in_array($value, ['true', '1', 'yes', 'y'], true);
- }
-
- /**
- * Check if the value of environment variable is a integer.
- *
- * @param string $value The value of environment variable.
- */
- private function isInteger(string $value): bool
- {
- return ctype_digit(trim($value, '-'));
- }
-
- /**
- * Convert the value of environment variable into a integer.
+ * Convert the value of environment variable into an integer.
*
* @param string $value The value of environment variable.
*/
@@ -146,16 +118,6 @@ private function convertInteger(string $value): int
return (int) $value;
}
- /**
- * Check if the value of environment variable is a string JSON.
- *
- * @param string $value The value of environment variable.
- */
- private function isJson(string $value): bool
- {
- return str_starts_with($value, '{') || str_starts_with($value, '[');
- }
-
/**
* Convert the value of environment variable into a json array.
*
@@ -168,13 +130,34 @@ private function convertJson(string $value, string $environmentVariable): array
if (json_last_error()) {
throw new RuntimeException(
- sprintf('The "%s" environment variable isn\'t a valid JSON', $environmentVariable)
+ sprintf('The "%s" environment variable isn\'t a valid JSON', $environmentVariable),
);
}
return is_array($value) ? $value : [];
}
+ /**
+ * Get the value defined by the manager name in the key.
+ *
+ * @param string $key The config key.
+ * @param mixed $value The value.
+ * @param mixed $default The default value.
+ */
+ private function getByManager(string $key, mixed $value, mixed $default = null): mixed
+ {
+ if (str_starts_with($key, 'manager-') && is_array($value)) {
+ /** @var int|string $manager */
+ $manager = $this->get('manager', '');
+
+ $value = array_key_exists($manager, $value)
+ ? $value[$manager]
+ : $default;
+ }
+
+ return $value;
+ }
+
/**
* Get the configured default value or custom default value.
*
@@ -183,7 +166,7 @@ private function convertJson(string $value, string $environmentVariable): array
*/
private function getDefaultValue(string $key, mixed $default = null): mixed
{
- $value = null === $default && \array_key_exists($key, $this->defaults)
+ $value = null === $default && array_key_exists($key, $this->defaults)
? $this->defaults[$key]
: $default;
@@ -191,23 +174,34 @@ private function getDefaultValue(string $key, mixed $default = null): mixed
}
/**
- * Get the value defined by the manager name in the key.
+ * Check if the value of environment variable is a boolean.
*
- * @param string $key The config key.
- * @param mixed $value The value.
- * @param mixed $default The default value.
+ * @param string $value The value of environment variable.
*/
- private function getByManager(string $key, mixed $value, mixed $default = null): mixed
+ private function isBoolean(string $value): bool
{
- if (str_starts_with($key, 'manager-') && \is_array($value)) {
- /** @var int|string $manager */
- $manager = $this->get('manager', '');
+ $value = strtolower($value);
- $value = \array_key_exists($manager, $value)
- ? $value[$manager]
- : $default;
- }
+ return in_array($value, ['true', 'false', '1', '0', 'yes', 'no', 'y', 'n'], true);
+ }
- return $value;
+ /**
+ * Check if the value of environment variable is an integer.
+ *
+ * @param string $value The value of environment variable.
+ */
+ private function isInteger(string $value): bool
+ {
+ return ctype_digit(trim($value, '-'));
+ }
+
+ /**
+ * Check if the value of environment variable is a string JSON.
+ *
+ * @param string $value The value of environment variable.
+ */
+ private function isJson(string $value): bool
+ {
+ return str_starts_with($value, '{') || str_starts_with($value, '[');
}
}
diff --git a/src/Config/ConfigBuilder.php b/src/Config/ConfigBuilder.php
index b3a6903..64ff1dc 100644
--- a/src/Config/ConfigBuilder.php
+++ b/src/Config/ConfigBuilder.php
@@ -2,26 +2,17 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Config;
use Composer\Composer;
use Composer\IO\IOInterface;
use Composer\Json\JsonFile;
+use Seld\JsonLint\ParsingException;
+
+use function array_merge;
+use function is_array;
+use function is_string;
-/**
- * Plugin Config builder.
- *
- * @author François Pluchino
- */
abstract class ConfigBuilder
{
/**
@@ -30,6 +21,8 @@ abstract class ConfigBuilder
* @param Composer $composer The composer.
* @param array $defaults The default values.
* @param IOInterface|null $io The composer input/output.
+ *
+ * @throws ParsingException
*/
public static function build(Composer $composer, array $defaults = [], IOInterface|null $io = null): Config
{
@@ -38,18 +31,32 @@ public static function build(Composer $composer, array $defaults = [], IOInterfa
return new Config($config, $defaults);
}
+ /**
+ * Get the home directory of composer.
+ *
+ * @param Composer $composer The composer
+ */
+ private static function getComposerHome(Composer $composer): string
+ {
+ $composerHome = $composer->getConfig()->get('home');
+
+ return is_string($composerHome) ? $composerHome : '';
+ }
+
/**
* Get the base of data.
*
* @param Composer $composer The composer.
* @param IOInterface|null $io The composer input/output.
+ *
+ * @throws ParsingException
*/
private static function getConfigBase(Composer $composer, IOInterface|null $io = null): array
{
$globalPackageConfig = self::getGlobalConfig($composer, 'composer', $io);
$globalConfig = self::getGlobalConfig($composer, 'config', $io);
$packageConfig = $composer->getPackage()->getConfig();
- $packageConfig = isset($packageConfig['foxy']) && \is_array($packageConfig['foxy'])
+ $packageConfig = isset($packageConfig['foxy']) && is_array($packageConfig['foxy'])
? $packageConfig['foxy']
: [];
@@ -62,6 +69,8 @@ private static function getConfigBase(Composer $composer, IOInterface|null $io =
* @param Composer $composer The composer.
* @param string $filename The filename.
* @param IOInterface|null $io The composer input/output.
+ *
+ * @throws ParsingException
*/
private static function getGlobalConfig(Composer $composer, string $filename, IOInterface|null $io = null): array
{
@@ -73,7 +82,7 @@ private static function getGlobalConfig(Composer $composer, string $filename, IO
/** @var array $data */
$data = $file->read();
- if (isset($data['config']['foxy']) && \is_array($data['config']['foxy'])) {
+ if (isset($data['config']['foxy']) && is_array($data['config']['foxy'])) {
$config = $data['config']['foxy'];
if ($io instanceof IOInterface && $io->isDebug()) {
@@ -84,16 +93,4 @@ private static function getGlobalConfig(Composer $composer, string $filename, IO
return $config;
}
-
- /**
- * Get the home directory of composer.
- *
- * @param Composer $composer The composer
- */
- private static function getComposerHome(Composer $composer): string
- {
- $composerHome = $composer->getConfig()->get('home');
-
- return is_string($composerHome) ? $composerHome : '';
- }
}
diff --git a/src/Converter/SemverConverter.php b/src/Converter/SemverConverter.php
index cbb70bc..175456b 100644
--- a/src/Converter/SemverConverter.php
+++ b/src/Converter/SemverConverter.php
@@ -2,33 +2,26 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Converter;
-/**
- * Converter for Semver syntax version to composer syntax version.
- *
- * @author François Pluchino
- */
+use function in_array;
+use function preg_match;
+use function str_replace;
+use function str_starts_with;
+use function strlen;
+use function substr;
+
final class SemverConverter implements VersionConverterInterface
{
public function convertVersion(string|null $version = null): string
{
- if (\in_array($version, [null, '', 'latest'], true)) {
+ if (in_array($version, [null, '', 'latest'], true)) {
return ('latest' === $version ? 'default || ' : '') . '*';
}
$version = str_replace('–', '-', $version);
- $prefix = preg_match('/^[a-z]/', $version) && !str_starts_with($version, 'dev-') ? substr($version, 0, 1) : '';
- $version = substr($version, \strlen($prefix));
+ $prefix = preg_match('/^[a-z]/', $version) && !str_starts_with($version, 'dev-') ? $version[0] : '';
+ $version = substr($version, strlen($prefix));
$version = SemverUtil::convertVersionMetadata($version);
$version = SemverUtil::convertDateVersion($version);
diff --git a/src/Converter/SemverUtil.php b/src/Converter/SemverUtil.php
index c564f53..33807c6 100644
--- a/src/Converter/SemverUtil.php
+++ b/src/Converter/SemverUtil.php
@@ -2,24 +2,13 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Converter;
use Composer\Package\Version\VersionParser;
-/**
- * Utils for semver converter.
- *
- * @author François Pluchino
- */
+use function in_array;
+use function strlen;
+
abstract class SemverUtil
{
/**
@@ -81,22 +70,6 @@ public static function createPattern(string $pattern): string
return '/^(' . $numVer . '|' . $numVer2 . '|' . $numVer3 . ')' . $pattern . '/';
}
- /**
- * Clean the wildcard in version.
- *
- * @param string $version The version.
- *
- * @return string The cleaned version.
- */
- private static function cleanWildcard(string $version): string
- {
- while (str_contains($version, '.x.x')) {
- $version = str_replace('.x.x', '.x', $version);
- }
-
- return $version;
- }
-
/**
* Clean the raw version.
*
@@ -112,41 +85,53 @@ private static function cleanWildcard(string $version): string
*/
private static function cleanVersion(string $version, array $matches): array
{
- $end = substr($version, \strlen((string) $matches[1][0][0]));
+ $end = substr($version, strlen((string) $matches[1][0][0]));
$version = $matches[1][0][0] . '-';
$matches = [];
+
if (preg_match('/^([-+])/', $end, $matches)) {
$end = substr($end, 1);
}
$matches = [];
+
preg_match('/^[a-z]+/', $end, $matches);
+
$type = isset($matches[0]) ? self::normalizeStability($matches[0]) : '';
- $end = substr($end, \strlen($type));
+ $end = substr($end, strlen($type));
return [$type, $version, $end];
}
/**
- * Normalize the stability.
+ * Clean the wildcard in version.
*
- * @param string $stability The stability.
+ * @param string $version The version.
*
- * @return string The normalized stability.
+ * @return string The cleaned version.
*/
- private static function normalizeStability(string $stability): string
+ private static function cleanWildcard(string $version): string
{
- $stability = strtolower($stability);
+ while (str_contains($version, '.x.x')) {
+ $version = str_replace('.x.x', '.x', $version);
+ }
- return match ($stability) {
- 'a' => 'alpha',
- 'b', 'pre' => 'beta',
- 'build' => 'patch',
- 'rc' => 'RC',
- 'dev', 'snapshot' => 'dev',
- default => VersionParser::normalizeStability($stability),
- };
+ return $version;
+ }
+
+ /**
+ * Convert the minor version of date.
+ *
+ * @param string $minor The minor version.
+ */
+ private static function convertDateMinorVersion(string $minor): string
+ {
+ $split = explode('.', $minor);
+ $minor = (int) $split[0];
+ $revision = isset($split[1]) ? (int) $split[1] : 0;
+
+ return '.' . sprintf('%03d', $minor) . sprintf('%03d', $revision);
}
/**
@@ -163,27 +148,33 @@ private static function matchVersion(string $version, string $type): array
{
$type = match ($type) {
'dev', 'snapshot' => 'dev',
- default => \in_array($type, ['alpha', 'beta', 'RC'], true) ? $type : 'patch',
+ default => in_array($type, ['alpha', 'beta', 'RC'], true) ? $type : 'patch',
};
- $patchVersion = !\in_array($type, ['dev'], true);
-
+ $patchVersion = $type !== 'dev';
$version .= $type;
return [$version, $patchVersion];
}
/**
- * Convert the minor version of date.
+ * Normalize the stability.
*
- * @param string $minor The minor version.
+ * @param string $stability The stability.
+ *
+ * @return string The normalized stability.
*/
- private static function convertDateMinorVersion(string $minor): string
+ private static function normalizeStability(string $stability): string
{
- $split = explode('.', $minor);
- $minor = (int) $split[0];
- $revision = isset($split[1]) ? (int) $split[1] : 0;
+ $stability = strtolower($stability);
- return '.' . sprintf('%03d', $minor) . sprintf('%03d', $revision);
+ return match ($stability) {
+ 'a' => 'alpha',
+ 'b', 'pre' => 'beta',
+ 'build' => 'patch',
+ 'rc' => 'RC',
+ 'dev', 'snapshot' => 'dev',
+ default => VersionParser::normalizeStability($stability),
+ };
}
}
diff --git a/src/Converter/VersionConverterInterface.php b/src/Converter/VersionConverterInterface.php
index 2577f48..c69f895 100644
--- a/src/Converter/VersionConverterInterface.php
+++ b/src/Converter/VersionConverterInterface.php
@@ -2,22 +2,8 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Converter;
-/**
- * Interface for the converter for asset syntax version to composer syntax version.
- *
- * @author François Pluchino
- */
interface VersionConverterInterface
{
/**
diff --git a/src/Event/AbstractSolveEvent.php b/src/Event/AbstractSolveEvent.php
index 162951c..034b94f 100644
--- a/src/Event/AbstractSolveEvent.php
+++ b/src/Event/AbstractSolveEvent.php
@@ -2,25 +2,11 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Event;
use Composer\EventDispatcher\Event;
use Composer\Package\PackageInterface;
-/**
- * Abstract event for solve event.
- *
- * @author François Pluchino
- */
abstract class AbstractSolveEvent extends Event
{
/**
@@ -32,7 +18,7 @@ abstract class AbstractSolveEvent extends Event
*/
public function __construct(string $name, private readonly string $assetDir, private readonly array $packages = [])
{
- parent::__construct($name, [], []);
+ parent::__construct($name);
}
/**
diff --git a/src/Event/GetAssetsEvent.php b/src/Event/GetAssetsEvent.php
index 6054ae3..82028f4 100644
--- a/src/Event/GetAssetsEvent.php
+++ b/src/Event/GetAssetsEvent.php
@@ -2,25 +2,11 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Event;
use Composer\Package\PackageInterface;
use Foxy\FoxyEvents;
-/**
- * Get assets event.
- *
- * @author François Pluchino
- */
final class GetAssetsEvent extends AbstractSolveEvent
{
/**
@@ -33,18 +19,6 @@ final class GetAssetsEvent extends AbstractSolveEvent
public function __construct(string $assetDir, array $packages, private array $assets = [])
{
parent::__construct(FoxyEvents::GET_ASSETS, $assetDir, $packages);
-
- $this->assets = $assets;
- }
-
- /**
- * Check if the asset package is present.
- *
- * @param string $name The asset package name
- */
- public function hasAsset(string $name): bool
- {
- return isset($this->assets[$name]);
}
/**
@@ -57,7 +31,7 @@ public function hasAsset(string $name): bool
*
* For the Composer package `foo/bar`.
*
- * $event->addAsset('@composer-asset/foo--bar', 'file:./vendor/foxy/composer-asset/foo/bar');
+ * $event->addAsset('@composer-asset/foo--bar', 'file:./vendor/php-forge/foxy/composer-asset/foo/bar');
*/
public function addAsset(string $name, string $path): self
{
@@ -73,4 +47,14 @@ public function getAssets(): array
{
return $this->assets;
}
+
+ /**
+ * Check if the asset package is present.
+ *
+ * @param string $name The asset package name
+ */
+ public function hasAsset(string $name): bool
+ {
+ return isset($this->assets[$name]);
+ }
}
diff --git a/src/Event/PostSolveEvent.php b/src/Event/PostSolveEvent.php
index b9b5876..6f03d9e 100644
--- a/src/Event/PostSolveEvent.php
+++ b/src/Event/PostSolveEvent.php
@@ -2,25 +2,11 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Event;
use Composer\Package\PackageInterface;
use Foxy\FoxyEvents;
-/**
- * Post solve event.
- *
- * @author François Pluchino
- */
final class PostSolveEvent extends AbstractSolveEvent
{
/**
@@ -30,7 +16,7 @@ final class PostSolveEvent extends AbstractSolveEvent
*
* @psalm-param PackageInterface[] $packages All installed Composer packages.
*/
- public function __construct($assetDir, array $packages, private readonly int $runResult)
+ public function __construct(string $assetDir, array $packages, private readonly int $runResult)
{
parent::__construct(FoxyEvents::POST_SOLVE, $assetDir, $packages);
}
diff --git a/src/Event/PreSolveEvent.php b/src/Event/PreSolveEvent.php
index 2632be1..f9c6acb 100644
--- a/src/Event/PreSolveEvent.php
+++ b/src/Event/PreSolveEvent.php
@@ -2,25 +2,11 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Event;
use Composer\Package\PackageInterface;
use Foxy\FoxyEvents;
-/**
- * Pre solve event.
- *
- * @author François Pluchino
- */
final class PreSolveEvent extends AbstractSolveEvent
{
/**
diff --git a/src/Exception/ExceptionInterface.php b/src/Exception/ExceptionInterface.php
index b3b31b3..7366b1d 100644
--- a/src/Exception/ExceptionInterface.php
+++ b/src/Exception/ExceptionInterface.php
@@ -2,22 +2,6 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Exception;
-/**
- * The interface of exception.
- *
- * @author François Pluchino
- */
-interface ExceptionInterface
-{
-}
+interface ExceptionInterface {}
diff --git a/src/Exception/RuntimeException.php b/src/Exception/RuntimeException.php
index e68f1bf..84c1b0e 100644
--- a/src/Exception/RuntimeException.php
+++ b/src/Exception/RuntimeException.php
@@ -2,22 +2,6 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Exception;
-/**
- * The Runtime Exception.
- *
- * @author François Pluchino
- */
-class RuntimeException extends \RuntimeException implements ExceptionInterface
-{
-}
+class RuntimeException extends \RuntimeException implements ExceptionInterface {}
diff --git a/src/Fallback/AssetFallback.php b/src/Fallback/AssetFallback.php
index e644436..ba2a257 100644
--- a/src/Fallback/AssetFallback.php
+++ b/src/Fallback/AssetFallback.php
@@ -2,56 +2,29 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Fallback;
use Composer\IO\IOInterface;
use Composer\Util\Filesystem;
use Foxy\Config\Config;
use Foxy\Exception\RuntimeException;
+use Throwable;
-/**
- * Asset fallback.
- *
- * @author François Pluchino
- */
final class AssetFallback implements FallbackInterface
{
- protected Filesystem $fs;
- protected string|null $originalContent = null;
+ private readonly Filesystem $fs;
+
+ private string|null $originalContent = null;
public function __construct(
- protected IOInterface $io,
- protected Config $config,
- protected string $path,
- Filesystem|null $fs = null
+ private readonly IOInterface $io,
+ private readonly Config $config,
+ private readonly string $path,
+ Filesystem|null $fs = null,
) {
$this->fs = $fs ?: new Filesystem();
}
- public function save(): self
- {
- if (file_exists($this->path) && is_file($this->path)) {
- $content = file_get_contents($this->path);
-
- if (false === $content) {
- throw new RuntimeException(sprintf('Unable to read fallback asset file "%s".', $this->path));
- }
-
- $this->originalContent = $content;
- }
-
- return $this;
- }
-
public function restore(): void
{
if (!$this->config->get('fallback-asset')) {
@@ -62,11 +35,11 @@ public function restore(): void
try {
$this->fs->remove($this->path);
- } catch (\Throwable $exception) {
+ } catch (Throwable $exception) {
throw new RuntimeException(
sprintf('Unable to remove fallback asset file "%s".', $this->path),
0,
- $exception
+ $exception,
);
}
@@ -78,4 +51,19 @@ public function restore(): void
}
}
}
+
+ public function save(): self
+ {
+ if (file_exists($this->path) && is_file($this->path)) {
+ $content = file_get_contents($this->path);
+
+ if (false === $content) {
+ throw new RuntimeException(sprintf('Unable to read fallback asset file "%s".', $this->path));
+ }
+
+ $this->originalContent = $content;
+ }
+
+ return $this;
+ }
}
diff --git a/src/Fallback/ComposerFallback.php b/src/Fallback/ComposerFallback.php
index aa4a654..7e1ffa5 100644
--- a/src/Fallback/ComposerFallback.php
+++ b/src/Fallback/ComposerFallback.php
@@ -2,38 +2,25 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Fallback;
-use Composer\Composer;
-use Composer\Factory;
+use Composer\{Composer, Factory};
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Installer;
use Composer\IO\IOInterface;
use Composer\Util\Filesystem;
+use Exception;
use Foxy\Config\Config;
-use Foxy\Util\ConsoleUtil;
-use Foxy\Util\LockerUtil;
-use Foxy\Util\PackageUtil;
+use Foxy\Util\{ConsoleUtil, LockerUtil, PackageUtil};
+use LogicException;
use Symfony\Component\Console\Input\InputInterface;
-/**
- * Composer fallback.
- *
- * @author François Pluchino
- */
+use function is_array;
+
final class ComposerFallback implements FallbackInterface
{
- protected Filesystem $fs;
- protected array $lock = [];
+ private readonly Filesystem $fs;
+ private array $lock = [];
/**
* @param Composer $composer The composer.
@@ -44,16 +31,38 @@ final class ComposerFallback implements FallbackInterface
* @param Installer|null $installer The installer.
*/
public function __construct(
- protected Composer $composer,
- protected IOInterface $io,
- protected Config $config,
- protected InputInterface $input,
+ private readonly Composer $composer,
+ private readonly IOInterface $io,
+ private readonly Config $config,
+ private readonly InputInterface $input,
Filesystem|null $fs = null,
- protected Installer|null $installer = null
+ private readonly Installer|null $installer = null,
) {
$this->fs = $fs ?: new Filesystem();
}
+ /**
+ * @throws Exception
+ */
+ public function restore(): void
+ {
+ if (!$this->config->get('fallback-composer')) {
+ return;
+ }
+
+ $this->io->write('Fallback to previous state for Composer ');
+ $hasLock = $this->restoreLockData();
+
+ if ($hasLock) {
+ $this->restorePreviousLockFile();
+ } else {
+ /** @var string $vendorDir */
+ $vendorDir = $this->composer->getConfig()->get('vendor-dir');
+
+ $this->fs->remove($vendorDir);
+ }
+ }
+
public function save(): self
{
$rm = $this->composer->getRepositoryManager();
@@ -64,36 +73,36 @@ public function save(): self
try {
$lock = $locker->getLockData();
$this->lock = PackageUtil::loadLockPackages($lock);
- } catch (\LogicException) {
+ } catch (LogicException) {
$this->lock = [];
}
return $this;
}
- public function restore(): void
+ /**
+ * Get the installer.
+ */
+ private function getInstaller(): Installer
{
- if (!$this->config->get('fallback-composer')) {
- return;
- }
-
- $this->io->write('Fallback to previous state for Composer ');
- $hasLock = $this->restoreLockData();
-
- if ($hasLock) {
- $this->restorePreviousLockFile();
- } else {
- /** @var string $vendorDir */
- $vendorDir = $this->composer->getConfig()->get('vendor-dir');
+ return $this->installer ?? Installer::create($this->io, $this->composer);
+ }
- $this->fs->remove($vendorDir);
- }
+ /**
+ * Get the lock value.
+ *
+ * @param string $key The key.
+ * @param mixed $default The default value.
+ */
+ private function getLockValue(string $key, mixed $default = null): mixed
+ {
+ return $this->lock[$key] ?? $default;
}
/**
* Restore the data of lock file.
*/
- protected function restoreLockData(): bool
+ private function restoreLockData(): bool
{
/** @psalm-suppress MixedArgument */
$this->composer->getLocker()->setLockData(
@@ -106,20 +115,22 @@ protected function restoreLockData(): bool
$this->getLockValue('stability-flags', []),
$this->getLockValue('prefer-stable', false),
$this->getLockValue('prefer-lowest', false),
- $this->getLockValue('platform-overrides', [])
+ $this->getLockValue('platform-overrides', []),
);
$isLocked = $this->composer->getLocker()->isLocked();
$lockData = $isLocked ? $this->composer->getLocker()->getLockData() : null;
- $hasPackage = \is_array($lockData) && isset($lockData['packages']) && !empty($lockData['packages']);
+ $hasPackage = is_array($lockData) && isset($lockData['packages']) && !empty($lockData['packages']);
return $isLocked && $hasPackage;
}
/**
* Restore the PHP dependencies with the previous lock file.
+ *
+ * @throws Exception
*/
- protected function restorePreviousLockFile(): void
+ private function restorePreviousLockFile(): void
{
$config = $this->composer->getConfig();
[$preferSource, $preferDist] = ConsoleUtil::getPreferredInstallOptions($config, $this->input);
@@ -148,23 +159,4 @@ protected function restorePreviousLockFile(): void
$dispatcher->setRunScripts(!$this->input->getOption('no-scripts'));
}
-
- /**
- * Get the lock value.
- *
- * @param string $key The key.
- * @param mixed $default The default value.
- */
- private function getLockValue(string $key, mixed $default = null): mixed
- {
- return $this->lock[$key] ?? $default;
- }
-
- /**
- * Get the installer.
- */
- private function getInstaller(): Installer
- {
- return $this->installer ?? Installer::create($this->io, $this->composer);
- }
}
diff --git a/src/Fallback/FallbackInterface.php b/src/Fallback/FallbackInterface.php
index d19b792..9d04a82 100644
--- a/src/Fallback/FallbackInterface.php
+++ b/src/Fallback/FallbackInterface.php
@@ -2,31 +2,17 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Fallback;
-/**
- * Interface of fallback.
- *
- * @author François Pluchino
- */
interface FallbackInterface
{
/**
- * Save the state.
+ * Restore the state.
*/
- public function save(): self;
+ public function restore(): void;
/**
- * Restore the state.
+ * Save the state.
*/
- public function restore(): void;
+ public function save(): self;
}
diff --git a/src/Foxy.php b/src/Foxy.php
index 9ebba5f..d0ac6a3 100644
--- a/src/Foxy.php
+++ b/src/Foxy.php
@@ -2,70 +2,49 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy;
use Composer\Composer;
use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\EventDispatcher\EventSubscriberInterface;
-use Composer\Installer\PackageEvent;
-use Composer\Installer\PackageEvents;
+use Composer\Installer\{PackageEvent, PackageEvents};
use Composer\IO\IOInterface;
use Composer\Plugin\PluginInterface;
-use Composer\Script\Event;
-use Composer\Script\ScriptEvents;
-use Composer\Util\Filesystem;
-use Composer\Util\ProcessExecutor;
-use Foxy\Asset\AbstractAssetManager;
-use Foxy\Asset\AssetManagerFinder;
-use Foxy\Asset\AssetManagerInterface;
-use Foxy\Config\Config;
-use Foxy\Config\ConfigBuilder;
+use Composer\Script\{Event, ScriptEvents};
+use Composer\Util\{Filesystem, ProcessExecutor};
+use Foxy\Asset\{AbstractAssetManager, AssetManagerFinder, AssetManagerInterface};
+use Foxy\Asset\{BunManager, NpmManager, PnpmManager, YarnManager};
+use Foxy\Config\{Config, ConfigBuilder};
use Foxy\Exception\RuntimeException;
-use Foxy\Fallback\AssetFallback;
-use Foxy\Fallback\ComposerFallback;
-use Foxy\Solver\Solver;
-use Foxy\Solver\SolverInterface;
-use Foxy\Util\ComposerUtil;
-use Foxy\Util\ConsoleUtil;
-
-/**
- * Composer plugin.
- *
- * @author François Pluchino
- *
- * @psalm-suppress MissingConstructor
- */
+use Foxy\Fallback\{AssetFallback, ComposerFallback};
+use Foxy\Solver\{Solver, SolverInterface};
+use Foxy\Util\{ComposerUtil, ConsoleUtil};
+use Seld\JsonLint\ParsingException;
+
final class Foxy implements PluginInterface, EventSubscriberInterface
{
final public const REQUIRED_COMPOSER_VERSION = '^2.0.0';
- private Config $config;
- private AssetManagerInterface $assetManager;
+
private AssetFallback $assetFallback;
- private ComposerFallback $composerFallback;
- private SolverInterface $solver;
- private bool $initialized = false;
+
+ private AssetManagerInterface $assetManager;
/**
* The list of the classes of asset managers.
*
* @psalm-var list>
*/
- private static $assetManagers = [
- Asset\BunManager::class,
- Asset\NpmManager::class,
- Asset\PnpmManager::class,
- Asset\YarnManager::class,
+ private static array $assetManagers = [
+ BunManager::class,
+ NpmManager::class,
+ PnpmManager::class,
+ YarnManager::class,
];
+ private ComposerFallback $composerFallback;
+
+ private Config $config;
+
/**
* The default values of config.
*/
@@ -90,16 +69,13 @@ final class Foxy implements PluginInterface, EventSubscriberInterface
'enable-packages' => [],
];
- public static function getSubscribedEvents(): array
- {
- return [
- ComposerUtil::getInitEventName() => [['init', 100]],
- PackageEvents::POST_PACKAGE_INSTALL => [['initOnInstall', 100]],
- ScriptEvents::POST_INSTALL_CMD => [['solveAssets', 100]],
- ScriptEvents::POST_UPDATE_CMD => [['solveAssets', 100]],
- ];
- }
+ private bool $initialized = false;
+
+ private SolverInterface $solver;
+ /**
+ * @throws ParsingException
+ */
public function activate(Composer $composer, IOInterface $io): void
{
ComposerUtil::validateVersion(self::REQUIRED_COMPOSER_VERSION, Composer::VERSION);
@@ -127,23 +103,14 @@ public function deactivate(Composer $composer, IOInterface $io): void
// Do nothing
}
- public function uninstall(Composer $composer, IOInterface $io): void
- {
- // Do nothing
- }
-
- /**
- * Init the plugin just after the first installation.
- *
- * @param PackageEvent $event The package event
- */
- public function initOnInstall(PackageEvent $event): void
+ public static function getSubscribedEvents(): array
{
- $operation = $event->getOperation();
-
- if ($operation instanceof InstallOperation && 'php-forge/foxy' === $operation->getPackage()->getName()) {
- $this->init();
- }
+ return [
+ ComposerUtil::getInitEventName() => [['init', 100]],
+ PackageEvents::POST_PACKAGE_INSTALL => [['initOnInstall', 100]],
+ ScriptEvents::POST_INSTALL_CMD => [['solveAssets', 100]],
+ ScriptEvents::POST_UPDATE_CMD => [['solveAssets', 100]],
+ ];
}
/**
@@ -162,6 +129,20 @@ public function init(): void
}
}
+ /**
+ * Init the plugin just after the first installation.
+ *
+ * @param PackageEvent $event The package event
+ */
+ public function initOnInstall(PackageEvent $event): void
+ {
+ $operation = $event->getOperation();
+
+ if ($operation instanceof InstallOperation && 'php-forge/foxy' === $operation->getPackage()->getName()) {
+ $this->init();
+ }
+ }
+
/**
* Set the solver.
*
@@ -183,6 +164,11 @@ public function solveAssets(Event $event): void
$this->solver->solve($event->getComposer(), $event->getIO());
}
+ public function uninstall(Composer $composer, IOInterface $io): void
+ {
+ // Do nothing
+ }
+
/**
* Get the asset manager.
*
@@ -193,11 +179,11 @@ public function solveAssets(Event $event): void
*
* @throws RuntimeException When the asset manager is not found.
*/
- protected function getAssetManager(
+ private function getAssetManager(
IOInterface $io,
Config $config,
ProcessExecutor $executor,
- Filesystem $fs
+ Filesystem $fs,
): AssetManagerInterface {
$amf = new AssetManagerFinder();
diff --git a/src/FoxyEvents.php b/src/FoxyEvents.php
index 898fcb3..fbc172d 100644
--- a/src/FoxyEvents.php
+++ b/src/FoxyEvents.php
@@ -2,31 +2,10 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy;
-/**
- * Events of Foxy.
- *
- * @author François Pluchino
- */
abstract class FoxyEvents
{
- /**
- * The "PRE_SOLVE" event is triggered before the `solve` action of asset packages.
- *
- * @Event("Foxy\Event\PreSolveEvent")
- */
- final public const PRE_SOLVE = 'foxy.pre-solve';
-
/**
* The "GET_ASSETS" event is triggered before the `solve` action of asset packages
* and during the retrieves the map of the asset packages.
@@ -42,4 +21,11 @@ abstract class FoxyEvents
* @Event("Foxy\Event\PostSolveEvent")
*/
final public const POST_SOLVE = 'foxy.post-solve';
+
+ /**
+ * The "PRE_SOLVE" event is triggered before the `solve` action of asset packages.
+ *
+ * @Event("Foxy\Event\PreSolveEvent")
+ */
+ final public const PRE_SOLVE = 'foxy.pre-solve';
}
diff --git a/src/Json/JsonFile.php b/src/Json/JsonFile.php
index 07cb210..dfbc914 100644
--- a/src/Json/JsonFile.php
+++ b/src/Json/JsonFile.php
@@ -2,37 +2,33 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Json;
use Foxy\Exception\RuntimeException;
-/**
- * The JSON file.
- *
- * @author François Pluchino
- */
final class JsonFile extends \Composer\Json\JsonFile
{
/**
* @psalm-var string[]
*/
private array $arrayKeys = [];
- private int|null $indent = null;
+
/**
* @psalm-var string[]
*/
private static array $encodeArrayKeys = [];
+
private static int $encodeIndent = JsonFormatter::DEFAULT_INDENT;
+ private int|null $indent = null;
+
+ public static function encode(mixed $data, int $options = 448, string $indent = self::INDENT_DEFAULT): string
+ {
+ $result = parent::encode($data, $options);
+
+ return JsonFormatter::format($result, self::$encodeArrayKeys, self::$encodeIndent, false);
+ }
+
/**
* Get the list of keys to be retained with an array representation if they are empty.
*
@@ -48,7 +44,7 @@ public function getArrayKeys(): array
}
/**
- * Get the indent for this json file.
+ * Get the indent for this JSON file.
*/
public function getIndent(): int
{
@@ -72,19 +68,15 @@ public function read(): array
public function write(array $hash, int $options = 448): void
{
self::$encodeArrayKeys = $this->getArrayKeys();
+
self::$encodeIndent = JsonFormatter::DEFAULT_INDENT;
+
parent::write($hash, $options);
+
self::$encodeArrayKeys = [];
self::$encodeIndent = JsonFormatter::DEFAULT_INDENT;
}
- public static function encode(mixed $data, int $options = 448, string $indent = self::INDENT_DEFAULT): string
- {
- $result = parent::encode($data, $options, self::INDENT_DEFAULT);
-
- return JsonFormatter::format($result, self::$encodeArrayKeys, self::$encodeIndent, false);
- }
-
/**
* Parse the original content.
*/
@@ -100,6 +92,7 @@ private function parseOriginalContent(): void
throw new RuntimeException(sprintf('Unable to read json file "%s".', $path));
}
}
+
$this->arrayKeys = JsonFormatter::getArrayKeys($content);
$this->indent = JsonFormatter::getIndent($content);
}
diff --git a/src/Json/JsonFormatter.php b/src/Json/JsonFormatter.php
index 42197cb..8defa30 100644
--- a/src/Json/JsonFormatter.php
+++ b/src/Json/JsonFormatter.php
@@ -2,28 +2,63 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Json;
-/**
- * Formats JSON strings with a custom indent.
- *
- * @author François Pluchino
- */
+use JsonException;
+
+use function array_walk_recursive;
+use function in_array;
+use function is_string;
+use function json_decode;
+use function json_encode;
+use function mb_convert_encoding;
+use function pack;
+use function preg_match;
+use function preg_match_all;
+use function preg_replace;
+use function preg_replace_callback;
+use function str_repeat;
+use function str_replace;
+use function strlen;
+use function trim;
+
final class JsonFormatter
{
- public const DEFAULT_INDENT = 4;
public const ARRAY_KEYS_REGEX = '/["\']([\w\d_\-.]+)["\']\s*:\s*\[\s*\]/';
+
+ public const DEFAULT_INDENT = 4;
+
public const INDENT_REGEX = '/^[{\[][\r\n]([ ]+)["\']/';
+ /**
+ * Format the data in JSON.
+ *
+ * @param string $json The original JSON.
+ * @param array $arrayKeys The list of keys to be retained with an array representation if they are empty.
+ * @param int $indent The space count for indent.
+ * @param bool $formatJson Check if the JSON must be formatted.
+ *
+ * @psalm-param string[] $arrayKeys The list of keys to be retained with an array representation if they are empty.
+ *
+ * @throws JsonException
+ */
+ public static function format(
+ string $json,
+ array $arrayKeys = [],
+ int $indent = self::DEFAULT_INDENT,
+ bool $formatJson = true,
+ ): string {
+ if ($formatJson) {
+ $json = self::formatInternal($json, true, true);
+ }
+
+ if (4 !== $indent) {
+ $json = str_replace(' ', str_repeat(' ', $indent), $json);
+ }
+
+ return self::replaceArrayByMap($json, $arrayKeys);
+ }
+
/**
* Get the list of keys to be retained with an array representation if they are empty.
*
@@ -46,63 +81,38 @@ public static function getArrayKeys(string $content): array
public static function getIndent(string $content): int
{
$indent = self::DEFAULT_INDENT;
- \preg_match(self::INDENT_REGEX, \trim($content), $matches);
+ preg_match(self::INDENT_REGEX, trim($content), $matches);
if (!empty($matches)) {
- $indent = \strlen($matches[1]);
+ $indent = strlen($matches[1]);
}
return $indent;
}
- /**
- * Format the data in JSON.
- *
- * @param string $json The original JSON.
- * @param array $arrayKeys The list of keys to be retained with an array representation if they are empty.
- * @param int $indent The space count for indent.
- * @param bool $formatJson Check if the json must be formatted.
- *
- * @psalm-param string[] $arrayKeys The list of keys to be retained with an array representation if they are empty.
- */
- public static function format(
- string $json,
- array $arrayKeys = [],
- $indent = self::DEFAULT_INDENT,
- $formatJson = true
- ): string {
- if ($formatJson) {
- $json = self::formatInternal($json, true, true);
- }
-
- if (4 !== $indent) {
- $json = \str_replace(' ', \str_repeat(' ', $indent), $json);
- }
-
- return self::replaceArrayByMap($json, $arrayKeys);
- }
-
/**
* Format the data in JSON.
*
* @param bool $unescapeUnicode Un escape unicode.
* @param bool $unescapeSlashes Un escape slashes.
+ *
+ * @throws JsonException
*/
private static function formatInternal(string $json, bool $unescapeUnicode, bool $unescapeSlashes): string
{
- $array = \json_decode($json, true);
-
- if (!is_array($array)) {
+ if ($json === '') {
return $json;
}
+ $array = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
+
if ($unescapeUnicode) {
- \array_walk_recursive($array, function (mixed &$item): void {
- if (\is_string($item)) {
- $item = \preg_replace_callback(
+ array_walk_recursive($array, static function (mixed &$item): void {
+ if (is_string($item)) {
+ $item = preg_replace_callback(
'/\\\\u([0-9a-fA-F]{4})/',
- static function (mixed $match) {
- $result = \mb_convert_encoding(\pack('H*', $match[1]), 'UTF-8', 'UCS-2BE');
+ static function (mixed $match): string|array {
+ $result = mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE');
return $result !== false ? $result : '';
},
$item,
@@ -112,14 +122,14 @@ static function (mixed $match) {
}
if ($unescapeSlashes) {
- \array_walk_recursive($array, function (mixed &$item): void {
- if (\is_string($item)) {
- $item = \str_replace('\\/', '/', $item);
+ array_walk_recursive($array, static function (mixed &$item): void {
+ if (is_string($item)) {
+ $item = str_replace('\\/', '/', $item);
}
});
}
- return \json_encode($array, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
+ return json_encode($array, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
/**
@@ -132,13 +142,13 @@ static function (mixed $match) {
*/
private static function replaceArrayByMap(string $json, array $arrayKeys): string
{
- \preg_match_all(self::ARRAY_KEYS_REGEX, $json, $matches, PREG_SET_ORDER);
+ preg_match_all(self::ARRAY_KEYS_REGEX, $json, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
- if (!\in_array($match[1], $arrayKeys, true)) {
- $replace = \preg_replace('/\[\s*\]/', '{}', $match[0]);
+ if (!in_array($match[1], $arrayKeys, true)) {
+ $replace = preg_replace('/\[\s*\]/', '{}', $match[0]);
if (null !== $replace) {
- $json = \str_replace($match[0], $replace, $json);
+ $json = str_replace($match[0], $replace, $json);
}
}
}
diff --git a/src/Solver/Solver.php b/src/Solver/Solver.php
index 6e0d4e8..24a69ea 100644
--- a/src/Solver/Solver.php
+++ b/src/Solver/Solver.php
@@ -2,15 +2,6 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Solver;
use Composer\Composer;
@@ -18,20 +9,20 @@
use Composer\Json\JsonFile;
use Composer\Package\PackageInterface;
use Composer\Util\Filesystem;
+use Exception;
use Foxy\Asset\AssetManagerInterface;
use Foxy\Config\Config;
-use Foxy\Event\GetAssetsEvent;
-use Foxy\Event\PostSolveEvent;
-use Foxy\Event\PreSolveEvent;
+use Foxy\Event\{GetAssetsEvent, PostSolveEvent, PreSolveEvent};
+use Foxy\Exception\RuntimeException;
use Foxy\Fallback\FallbackInterface;
use Foxy\FoxyEvents;
use Foxy\Util\AssetUtil;
-/**
- * Solver of asset dependencies.
- *
- * @author François Pluchino
- */
+use function basename;
+use function copy;
+use function mkdir;
+use function rtrim;
+
final class Solver implements SolverInterface
{
/**
@@ -40,12 +31,11 @@ final class Solver implements SolverInterface
* @param FallbackInterface|null $composerFallback The composer fallback instance.
*/
public function __construct(
- protected AssetManagerInterface $assetManager,
- protected Config $config,
- protected Filesystem $fs,
- protected FallbackInterface|null $composerFallback = null
- ) {
- }
+ private readonly AssetManagerInterface $assetManager,
+ private readonly Config $config,
+ private readonly Filesystem $fs,
+ private readonly FallbackInterface|null $composerFallback = null,
+ ) {}
public function setUpdatable($updatable): self
{
@@ -54,6 +44,9 @@ public function setUpdatable($updatable): self
return $this;
}
+ /**
+ * @throws Exception
+ */
public function solve(Composer $composer, IOInterface $io): void
{
if (!$this->config->get('enabled')) {
@@ -76,20 +69,22 @@ public function solve(Composer $composer, IOInterface $io): void
if ($res > 0 && $this->composerFallback) {
$this->composerFallback->restore();
- throw new \RuntimeException('The asset manager ended with an error');
+ throw new RuntimeException('The asset manager ended with an error');
}
}
/**
* Get the package of asset dependencies.
*
- * @param Composer $composer The composer instance.
+ * @param Composer $composer The composer instance.
* @param string $assetDir The asset directory.
* @param array $packages The package dependencies.
*
* @psalm-param PackageInterface[] $packages The package dependencies.
+ *
+ * @throws Exception
*/
- protected function getAssets(Composer $composer, string $assetDir, array $packages): array
+ private function getAssets(Composer $composer, string $assetDir, array $packages): array
{
$installationManager = $composer->getInstallationManager();
$configPackages = $this->config->getArray('enable-packages');
@@ -118,15 +113,17 @@ protected function getAssets(Composer $composer, string $assetDir, array $packag
* @param string $filename The filename of asset package.
*
* @psalm-return string[] The package name and the relative package path from the current directory
+ *
+ * @throws Exception
*/
- protected function getMockPackagePath(PackageInterface $package, string $assetDir, string $filename): array
+ private function getMockPackagePath(PackageInterface $package, string $assetDir, string $filename): array
{
$packageName = AssetUtil::getName($package);
- $packagePath = \rtrim($assetDir, '/') . '/' . $package->getName();
- $newFilename = $packagePath . '/' . \basename($filename);
+ $packagePath = rtrim($assetDir, '/') . '/' . $package->getName();
+ $newFilename = $packagePath . '/' . basename($filename);
- \mkdir($packagePath, 0777, true);
- \copy($filename, $newFilename);
+ mkdir($packagePath, 0777, true);
+ copy($filename, $newFilename);
$jsonFile = new JsonFile($newFilename);
$packageValue = AssetUtil::formatPackage($package, $packageName, (array) $jsonFile->read());
diff --git a/src/Solver/SolverInterface.php b/src/Solver/SolverInterface.php
index 49f2670..cc47ef8 100644
--- a/src/Solver/SolverInterface.php
+++ b/src/Solver/SolverInterface.php
@@ -2,25 +2,11 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Solver;
use Composer\Composer;
use Composer\IO\IOInterface;
-/**
- * Interface of solver.
- *
- * @author François Pluchino
- */
interface SolverInterface
{
/**
diff --git a/src/Util/AssetUtil.php b/src/Util/AssetUtil.php
index f835992..7a97570 100644
--- a/src/Util/AssetUtil.php
+++ b/src/Util/AssetUtil.php
@@ -2,15 +2,6 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Util;
use Composer\Installer\InstallationManager;
@@ -18,14 +9,47 @@
use Composer\Package\PackageInterface;
use Foxy\Asset\AssetManagerInterface;
use Foxy\Asset\AssetPackage;
+use JsonException;
+
+use function count;
+use function explode;
+use function file_exists;
+use function file_get_contents;
+use function fnmatch;
+use function is_int;
+use function is_string;
+use function json_decode;
+use function preg_match;
+use function realpath;
+use function str_replace;
-/**
- * Helper for Foxy.
- *
- * @author François Pluchino
- */
final class AssetUtil
{
+ /**
+ * Format the asset package.
+ *
+ * @param PackageInterface $package The composer package instance.
+ * @param string $packageName The package name of asset.
+ * @param array $packageValue The package value of asset.
+ */
+ public static function formatPackage(PackageInterface $package, string $packageName, array $packageValue): array
+ {
+ $packageValue['name'] = $packageName;
+
+ if (!isset($packageValue['version'])) {
+ $extra = $package->getExtra();
+ $version = $package->getPrettyVersion();
+
+ if (str_starts_with($version, 'dev-') && isset($extra['branch-alias'][$version])) {
+ $version = $extra['branch-alias'][$version];
+ }
+
+ $packageValue['version'] = self::formatVersion(str_replace('-dev', '', (string) $version));
+ }
+
+ return $packageValue;
+ }
+
/**
* Get the name for the asset dependency.
*
@@ -33,7 +57,7 @@ final class AssetUtil
*/
public static function getName(PackageInterface $package): string
{
- return AssetPackage::COMPOSER_PREFIX . \str_replace(['/'], '--', $package->getName());
+ return AssetPackage::COMPOSER_PREFIX . str_replace(['/'], '--', $package->getName());
}
/**
@@ -43,12 +67,14 @@ public static function getName(PackageInterface $package): string
* @param AssetManagerInterface $assetManager The asset manager.
* @param PackageInterface $package The package instance.
* @param array $configPackages The packages defined in config.
+ *
+ * @throws JsonException
*/
public static function getPath(
InstallationManager $installationManager,
AssetManagerInterface $assetManager,
PackageInterface $package,
- array $configPackages = []
+ array $configPackages = [],
): string|null {
$path = null;
@@ -61,12 +87,12 @@ public static function getPath(
$composerJsonPath = $installPath . '/composer.json';
}
- if (null !== $composerJsonPath && \file_exists($composerJsonPath)) {
+ if (null !== $composerJsonPath && file_exists($composerJsonPath)) {
/** @var array[] $composerJson */
- $composerJson = \json_decode(\file_get_contents($composerJsonPath), true);
+ $composerJson = json_decode(file_get_contents($composerJsonPath), true, 512, JSON_THROW_ON_ERROR);
$rootPackageDir = $composerJson['config']['foxy']['root-package-json-dir'] ?? null;
- if (null !== $installPath && \is_string($rootPackageDir)) {
+ if (null !== $installPath && is_string($rootPackageDir)) {
$installPath .= '/' . $rootPackageDir;
}
}
@@ -74,30 +100,13 @@ public static function getPath(
if (null !== $installPath) {
$filename = $installPath . '/' . $assetManager->getPackageName();
- $path = \file_exists($filename) ? \str_replace('\\', '/', \realpath($filename)) : null;
+ $path = file_exists($filename) ? str_replace('\\', '/', realpath($filename)) : null;
}
}
return $path;
}
- /**
- * Check if the package is available for Foxy.
- *
- * @param PackageInterface $package The package instance.
- * @param array $configPackages The packages defined in config.
- */
- public static function isAsset(PackageInterface $package, array $configPackages = []): bool
- {
- $projectConfig = self::getProjectActivation($package, $configPackages);
- $enabled = false !== $projectConfig;
-
- return $enabled && (self::hasExtraActivation($package)
- || self::hasPluginDependency($package->getRequires())
- || self::hasPluginDependency($package->getDevRequires())
- || true === $projectConfig);
- }
-
/**
* Check if foxy is enabled in extra section of package.
*
@@ -113,9 +122,9 @@ public static function hasExtraActivation(PackageInterface $package): bool
/**
* Check if the package contains assets.
*
- * @param Link[] $requires The require links.
+ * @param Link[] $requires The requirement links.
*
- * @psalm-param Link[] $requires The require links.
+ * @psalm-param Link[] $requires The requirement links.
*/
public static function hasPluginDependency(array $requires): bool
{
@@ -133,39 +142,31 @@ public static function hasPluginDependency(array $requires): bool
}
/**
- * Check if the package is enabled by the project config.
+ * Check if the package is available for Foxy.
*
* @param PackageInterface $package The package instance.
* @param array $configPackages The packages defined in config.
*/
- public static function isProjectActivation(PackageInterface $package, array $configPackages): bool
+ public static function isAsset(PackageInterface $package, array $configPackages = []): bool
{
- return true === self::getProjectActivation($package, $configPackages);
+ $projectConfig = self::getProjectActivation($package, $configPackages);
+ $enabled = false !== $projectConfig;
+
+ return $enabled && (self::hasExtraActivation($package)
+ || self::hasPluginDependency($package->getRequires())
+ || self::hasPluginDependency($package->getDevRequires())
+ || true === $projectConfig);
}
/**
- * Format the asset package.
+ * Check if the package is enabled by the project config.
*
- * @param PackageInterface $package The composer package instance.
- * @param string $packageName The package name of asset.
- * @param array $packageValue The package value of asset.
+ * @param PackageInterface $package The package instance.
+ * @param array $configPackages The packages defined in config.
*/
- public static function formatPackage(PackageInterface $package, string $packageName, array $packageValue): array
+ public static function isProjectActivation(PackageInterface $package, array $configPackages): bool
{
- $packageValue['name'] = $packageName;
-
- if (!isset($packageValue['version'])) {
- $extra = $package->getExtra();
- $version = $package->getPrettyVersion();
-
- if (str_starts_with($version, 'dev-') && isset($extra['branch-alias'][$version])) {
- $version = $extra['branch-alias'][$version];
- }
-
- $packageValue['version'] = self::formatVersion(\str_replace('-dev', '', (string) $version));
- }
-
- return $packageValue;
+ return true === self::getProjectActivation($package, $configPackages);
}
/**
@@ -175,10 +176,10 @@ public static function formatPackage(PackageInterface $package, string $packageN
*/
private static function formatVersion(string $version): string
{
- $version = \str_replace(['x', 'X', '*'], '0', $version);
- $exp = \explode('.', $version);
+ $version = str_replace(['x', 'X', '*'], '0', $version);
+ $exp = explode('.', $version);
- if (($size = \count($exp)) < 3) {
+ if (($size = count($exp)) < 3) {
for ($i = $size; $i < 3; ++$i) {
$exp[] = '0';
}
@@ -204,14 +205,14 @@ private static function getProjectActivation(PackageInterface $package, array $c
* @var array $configPackages
*/
foreach ($configPackages as $pattern => $activation) {
- if (\is_int($pattern) && \is_string($activation)) {
+ if (is_int($pattern) && is_string($activation)) {
$pattern = $activation;
$activation = true;
}
if (
- \is_string($pattern) &&
- ((str_starts_with($pattern, '/') && \preg_match($pattern, $name)) || \fnmatch($pattern, $name))
+ is_string($pattern)
+ && ((str_starts_with($pattern, '/') && preg_match($pattern, $name)) || fnmatch($pattern, $name))
) {
$value = $activation;
diff --git a/src/Util/ComposerUtil.php b/src/Util/ComposerUtil.php
index 499110e..db088ad 100644
--- a/src/Util/ComposerUtil.php
+++ b/src/Util/ComposerUtil.php
@@ -2,26 +2,12 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Util;
use Composer\Installer\InstallerEvents;
use Composer\Semver\Semver;
use Foxy\Exception\RuntimeException;
-/**
- * Helper for Composer.
- *
- * @author François Pluchino
- */
final class ComposerUtil
{
/**
diff --git a/src/Util/ConsoleUtil.php b/src/Util/ConsoleUtil.php
index 4342b7c..131dc7e 100644
--- a/src/Util/ConsoleUtil.php
+++ b/src/Util/ConsoleUtil.php
@@ -2,23 +2,12 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Util;
use Composer\Config;
use Composer\IO\IOInterface;
-use Symfony\Component\Console\Input\ArgvInput;
-use Symfony\Component\Console\Input\InputInterface;
-
-use const PHP_VERSION_ID;
+use ReflectionClass;
+use Symfony\Component\Console\Input\{ArgvInput, InputInterface};
/**
* Helper for console.
@@ -34,15 +23,10 @@ final class ConsoleUtil
*/
public static function getInput(IOInterface $io): InputInterface
{
- $ref = new \ReflectionClass($io);
+ $ref = new ReflectionClass($io);
if ($ref->hasProperty('input')) {
$prop = $ref->getProperty('input');
-
- if (PHP_VERSION_ID < 80500) {
- $prop->setAccessible(true);
- }
-
$input = $prop->getValue($io);
if ($input instanceof InputInterface) {
diff --git a/src/Util/LockerUtil.php b/src/Util/LockerUtil.php
index bb07974..2f154f3 100644
--- a/src/Util/LockerUtil.php
+++ b/src/Util/LockerUtil.php
@@ -2,15 +2,6 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Util;
use Composer\Installer\InstallationManager;
@@ -18,11 +9,6 @@
use Composer\Json\JsonFile;
use Composer\Package\Locker;
-/**
- * Helper for Locker.
- *
- * @author François Pluchino
- */
final class LockerUtil
{
/**
@@ -31,7 +17,7 @@ final class LockerUtil
public static function getLocker(
IOInterface $io,
InstallationManager $im,
- string $composerFile
+ string $composerFile,
): Locker {
$lockFile = str_replace('.json', '.lock', $composerFile);
diff --git a/src/Util/PackageUtil.php b/src/Util/PackageUtil.php
index 5adc2e9..a337d91 100644
--- a/src/Util/PackageUtil.php
+++ b/src/Util/PackageUtil.php
@@ -2,40 +2,45 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Util;
use Composer\Package\AliasPackage;
use Composer\Package\Loader\ArrayLoader;
-/**
- * Helper for package.
- *
- * @author François Pluchino
- */
final class PackageUtil
{
/**
- * Load all packages in the lock data of locker.
+ * Convert the package aliases of the locker load data.
*
* @param array $lockData The lock data of locker.
*
* @return array The lock data.
*/
- public static function loadLockPackages(array $lockData): array
+ public static function convertLockAlias(array $lockData): array
{
- $loader = new ArrayLoader();
- $lockData = self::loadLockPackage($loader, $lockData);
- $lockData = self::loadLockPackage($loader, $lockData, true);
- return self::convertLockAlias($lockData);
+ $loadDatawithaliases = $lockData['aliases'] ?? [];
+
+ if ($loadDatawithaliases === []) {
+ return $lockData;
+ }
+
+ $alias = [];
+
+ /**
+ * @psalm-var array{
+ * array{alias: string, alias_normalized: string, version: string, package: string}
+ * } $loadDatawithaliases
+ */
+ foreach ($loadDatawithaliases as $config) {
+ $alias[$config['package']][$config['version']] = [
+ 'alias' => $config['alias'],
+ 'alias_normalized' => $config['alias_normalized'],
+ ];
+ }
+
+ $lockData['aliases'] = $alias;
+
+ return $lockData;
}
/**
@@ -72,36 +77,17 @@ public static function loadLockPackage(ArrayLoader $loader, array $lockData, boo
}
/**
- * Convert the package aliases of the locker load data.
+ * Load all packages in the lock data of locker.
*
* @param array $lockData The lock data of locker.
*
* @return array The lock data.
*/
- public static function convertLockAlias(array $lockData): array
+ public static function loadLockPackages(array $lockData): array
{
- $loadDatawithaliases = $lockData['aliases'] ?? [];
-
- if ($loadDatawithaliases === []) {
- return $lockData;
- }
-
- $alias = [];
-
- /**
- * @psalm-var array{
- * array{alias: string, alias_normalized: string, version: string, package: string}
- * } $loadDatawithaliases
- */
- foreach ($loadDatawithaliases as $config) {
- $alias[$config['package']][$config['version']] = [
- 'alias' => $config['alias'],
- 'alias_normalized' => $config['alias_normalized'],
- ];
- }
-
- $lockData['aliases'] = $alias;
-
- return $lockData;
+ $loader = new ArrayLoader();
+ $lockData = self::loadLockPackage($loader, $lockData);
+ $lockData = self::loadLockPackage($loader, $lockData, true);
+ return self::convertLockAlias($lockData);
}
}
diff --git a/tests/Asset/AssetManager.php b/tests/Asset/AssetManager.php
index 1efdcc5..bc5ea0b 100644
--- a/tests/Asset/AssetManager.php
+++ b/tests/Asset/AssetManager.php
@@ -2,200 +2,69 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Asset;
use Composer\IO\IOInterface;
use Composer\Json\JsonFile;
use Composer\Package\RootPackageInterface;
-use Composer\Util\Filesystem;
-use Composer\Util\ProcessExecutor;
-use Foxy\Asset\AbstractAssetManager;
-use Foxy\Asset\AssetManagerInterface;
+use Composer\Util\{Filesystem, ProcessExecutor};
+use Foxy\Asset\{AbstractAssetManager, AssetManagerInterface, AssetPackageInterface};
use Foxy\Config\Config;
+use Foxy\Exception\RuntimeException;
use Foxy\Fallback\FallbackInterface;
-use Foxy\Tests\Fixtures\Util\ProcessExecutorMock;
-use Foxy\Tests\Fixtures\Util\ThrowingProcessExecutorMock;
+use Foxy\Tests\Fixtures\Util\{ProcessExecutorMock, ThrowingProcessExecutorMock};
use PHPUnit\Framework\Attributes\RequiresOperatingSystemFamily;
-use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\MockObject\{Exception, MockObject};
+use PHPUnit\Framework\TestCase;
use Xepozz\InternalMocker\MockerState;
+use function chdir;
use function file_get_contents;
use function file_put_contents;
+use function getcwd;
use const DIRECTORY_SEPARATOR;
-/**
- * Abstract class for asset manager tests.
- *
- * @author François Pluchino
- */
-abstract class AssetManager extends \PHPUnit\Framework\TestCase
+abstract class AssetManager extends TestCase
{
protected Config|null $config = null;
- protected IOInterface|null $io = null;
- protected ProcessExecutorMock|ThrowingProcessExecutorMock|null $executor = null;
- protected Filesystem|MockObject|null $fs = null;
- protected \Symfony\Component\Filesystem\Filesystem|null $sfs = null;
- protected FallbackInterface|MockObject|null $fallback = null;
- protected AssetManagerInterface|null $manager = null;
- protected string|null $oldCwd = '';
- protected string|null $cwd = '';
-
- protected function setUp(): void
- {
- parent::setUp();
-
- $this->config = new Config([]);
- $this->io = $this->createMock(IOInterface::class);
- $this->executor = new ProcessExecutorMock($this->io);
- $this->fs = $this->createMock(Filesystem::class);
- $this->sfs = new \Symfony\Component\Filesystem\Filesystem();
- $this->fallback = $this->createMock(FallbackInterface::class);
- $this->manager = $this->getManager();
- $this->oldCwd = getcwd();
- $this->cwd = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('foxy_asset_manager_test_', true);
- $this->sfs->mkdir($this->cwd);
-
- \chdir($this->cwd);
- }
- protected function tearDown(): void
- {
- parent::tearDown();
-
- \chdir($this->oldCwd);
-
- $this->sfs->remove($this->cwd);
- $this->config = null;
- $this->io = null;
- $this->executor = null;
- $this->fs = null;
- $this->sfs = null;
- $this->fallback = null;
- $this->manager = null;
- $this->oldCwd = null;
- $this->cwd = null;
- }
-
- public function testGetName(): void
- {
- $this->assertSame($this->getValidName(), $this->manager->getName());
- }
-
- public function testGetLockPackageName(): void
- {
- $this->assertSame($this->getValidLockPackageName(), $this->manager->getLockPackageName());
- }
-
- public function testGetPackageName(): void
- {
- $this->assertSame('package.json', $this->manager->getPackageName());
- }
-
- public function testHasLockFile(): void
- {
- $this->assertFalse($this->manager->hasLockFile());
- }
-
- public function testHasLockFileWithRootPackageDirAsRoot(): void
- {
- $this->config = new Config([], ['root-package-json-dir' => DIRECTORY_SEPARATOR]);
- $this->manager = $this->getManager();
-
- MockerState::addCondition('Foxy\\Asset', 'getcwd', [], $this->cwd);
-
- $this->assertInstanceOf(AbstractAssetManager::class, $this->manager);
- /** @var AbstractAssetManager $manager */
- $manager = $this->manager;
-
- $this->assertSame(
- DIRECTORY_SEPARATOR . $manager->getPackageName(),
- $manager->getPackageJsonPath()
- );
- $this->assertFalse($this->manager->hasLockFile());
- }
-
- #[RequiresOperatingSystemFamily('Windows')]
- public function testGetPackageJsonPathWithWindowsRootPackageDir(): void
- {
- $this->config = new Config([], ['root-package-json-dir' => 'C:\\']);
- $this->manager = $this->getManager();
-
- $this->assertInstanceOf(AbstractAssetManager::class, $this->manager);
- /** @var AbstractAssetManager $manager */
- $manager = $this->manager;
-
- $this->assertSame('C:\\package.json', $manager->getPackageJsonPath());
- }
+ protected string|null $cwd = '';
- public function testIsInstalled(): void
- {
- $this->assertFalse($this->manager->isInstalled());
- }
+ protected ProcessExecutorMock|ThrowingProcessExecutorMock|null $executor = null;
- public function testIsUpdatable(): void
- {
- $this->assertFalse($this->manager->isUpdatable());
- }
+ protected FallbackInterface|MockObject|null $fallback = null;
- public function testSetUpdatable(): void
- {
- $res = $this->manager->setUpdatable(false);
+ protected Filesystem|MockObject|null $fs = null;
- $this->assertInstanceOf(AssetManagerInterface::class, $res);
- }
+ protected IOInterface|null $io = null;
- public function testValidateWithoutInstalledManager(): void
- {
- $this->expectException(\Foxy\Exception\RuntimeException::class);
- $this->expectExceptionMessageMatches('/The binary of "(\w+)" must be installed/');
+ protected AssetManagerInterface|null $manager = null;
- $this->manager->validate();
- }
+ protected string|null $oldCwd = '';
- public function testValidateWithInstalledManagerAndWithoutValidVersion(): void
- {
- $this->expectException(\Foxy\Exception\RuntimeException::class);
- $this->expectExceptionMessageMatches(
- '/The installed (\w+) version "42.0.0" doesn\'t match with the constraint version ">=50.0"/'
- );
+ protected \Symfony\Component\Filesystem\Filesystem|null $sfs = null;
- $this->config = new Config([], ['manager-version' => '>=50.0']);
- $this->manager = $this->getManager();
+ abstract protected function getManager(): AssetManagerInterface;
- $this->executor->addExpectedValues(0, '42.0.0');
+ abstract protected function getValidInstallCommand(): string;
- $this->manager->validate();
- }
+ abstract protected function getValidLockPackageName(): string;
- public function testValidateWithInstalledManagerAndWithValidVersion(): void
- {
- $this->config = new Config([], ['manager-version' => '>=41.0']);
- $this->manager = $this->getManager();
+ abstract protected function getValidName(): string;
- $this->executor->addExpectedValues(0, '42.0.0');
+ abstract protected function getValidUpdateCommand(): string;
- $this->manager->validate();
- $this->assertSame('>=41.0', $this->config->get('manager-version'));
- }
+ abstract protected function getValidVersionCommand(): string;
- public function testValidateWithInstalledManagerAndWithoutValidationVersion(): void
+ public static function getRunData(): array
{
- $this->executor->addExpectedValues(0, '42.0.0');
-
- $this->manager->validate();
- $this->assertNull($this->config->get('manager-version'));
+ return [[0, 'install'], [0, 'update'], [1, 'install'], [1, 'update']];
}
+ /**
+ * @throws Exception
+ */
public function testAddDependenciesForInstallCommand(): void
{
$expectedPackage = [
@@ -209,21 +78,31 @@ public function testAddDependenciesForInstallCommand(): void
'@composer-asset/new--dependency' => 'path/new/dependency/package.json',
];
- /** @var MockObject|RootPackageInterface $rootPackage */
$rootPackage = $this->createMock(RootPackageInterface::class);
+ $rootPackage->expects(self::any())->method('getLicense')->willReturn([]);
- $rootPackage->expects($this->any())->method('getLicense')->willReturn([]);
-
- $this->assertFalse($this->manager->isInstalled());
- $this->assertFalse($this->manager->isUpdatable());
+ self::assertFalse(
+ $this->manager->isInstalled(),
+ );
+ self::assertFalse(
+ $this->manager->isUpdatable(),
+ );
$assetPackage = $this->manager->addDependencies($rootPackage, $allDependencies);
- $this->assertInstanceOf(\Foxy\Asset\AssetPackageInterface::class, $assetPackage);
-
- $this->assertEquals($expectedPackage, $assetPackage->getPackage());
+ self::assertInstanceOf(
+ AssetPackageInterface::class,
+ $assetPackage,
+ );
+ self::assertSame(
+ $expectedPackage,
+ $assetPackage->getPackage(),
+ );
}
+ /**
+ * @throws Exception
+ */
public function testAddDependenciesForUpdateCommand(): void
{
$this->actionForTestAddDependenciesForUpdateCommand();
@@ -247,33 +126,52 @@ public function testAddDependenciesForUpdateCommand(): void
$jsonFile = new JsonFile($this->cwd . '/package.json');
- /** @var MockObject|RootPackageInterface $rootPackage */
$rootPackage = $this->createMock(RootPackageInterface::class);
-
- $rootPackage->expects($this->any())->method('getLicense')->willReturn([]);
+ $rootPackage->expects(self::any())->method('getLicense')->willReturn([]);
$nodeModulePath = $this->cwd . ltrim(AbstractAssetManager::NODE_MODULES_PATH, '.');
$jsonFile->write($package);
- $this->assertFileExists($jsonFile->getPath());
+ self::assertFileExists(
+ $jsonFile->getPath(),
+ );
+
$this->sfs->mkdir($nodeModulePath);
- $this->assertFileExists($nodeModulePath);
+
+ self::assertFileExists(
+ $nodeModulePath,
+ );
$lockFilePath = $this->cwd . DIRECTORY_SEPARATOR . $this->manager->getLockPackageName();
file_put_contents($lockFilePath, '{}');
- $this->assertFileExists($lockFilePath);
- $this->assertTrue($this->manager->isInstalled());
- $this->assertTrue($this->manager->isUpdatable());
+ self::assertFileExists(
+ $lockFilePath,
+ );
+ self::assertTrue(
+ $this->manager->isInstalled(),
+ );
+ self::assertTrue(
+ $this->manager->isUpdatable(),
+ );
$assetPackage = $this->manager->addDependencies($rootPackage, $allDependencies);
- $this->assertInstanceOf(\Foxy\Asset\AssetPackageInterface::class, $assetPackage);
- $this->assertEquals($expectedPackage, $assetPackage->getPackage());
+ self::assertInstanceOf(
+ AssetPackageInterface::class,
+ $assetPackage,
+ );
+ self::assertSame(
+ $expectedPackage,
+ $assetPackage->getPackage(),
+ );
}
+ /**
+ * @throws Exception
+ */
public function testAddDependenciesUsesRootPackageJsonDir(): void
{
$rootPackageDir = $this->cwd . DIRECTORY_SEPARATOR . 'root-package';
@@ -298,40 +196,142 @@ public function testAddDependenciesUsesRootPackageJsonDir(): void
'@composer-asset/new--dependency' => 'path/new/dependency/package.json',
];
- /** @var MockObject|RootPackageInterface $rootPackage */
$rootPackage = $this->createMock(RootPackageInterface::class);
+ $rootPackage->expects(self::any())->method('getLicense')->willReturn([]);
- $rootPackage->expects($this->any())->method('getLicense')->willReturn([]);
$this->manager->addDependencies($rootPackage, $dependencies);
- $this->assertSame($cwdPackageContent, file_get_contents($cwdPackagePath));
+ self::assertSame(
+ $cwdPackageContent,
+ file_get_contents($cwdPackagePath),
+ );
$updatedContent = (string) file_get_contents($rootPackagePath);
- $this->assertStringContainsString(
+ self::assertStringContainsString(
'"@composer-asset/new--dependency": "file:./path/new/dependency"',
- $updatedContent
+ $updatedContent,
);
- $this->assertMatchesRegularExpression(
+ self::assertMatchesRegularExpression(
'/\n {4}"dependencies": \{/',
$updatedContent,
);
- $this->assertMatchesRegularExpression(
+ self::assertMatchesRegularExpression(
'/\n {8}"@composer-asset\/new--dependency": "file:\.\/path\/new\/dependency"/',
- $updatedContent
+ $updatedContent,
);
}
- public function testRunWithDisableOption(): void
+ public function testGetLockPackageName(): void
{
- $this->config = new Config([], ['run-asset-manager' => false]);
+ self::assertSame(
+ $this->getValidLockPackageName(),
+ $this->manager->getLockPackageName(),
+ );
+ }
- $this->assertSame(0, $this->getManager()->run());
+ public function testGetName(): void
+ {
+ self::assertSame(
+ $this->getValidName(),
+ $this->manager->getName(),
+ );
}
- public static function getRunData(): array
+ #[RequiresOperatingSystemFamily('Windows')]
+ public function testGetPackageJsonPathWithWindowsRootPackageDir(): void
{
- return [[0, 'install'], [0, 'update'], [1, 'install'], [1, 'update']];
+ $this->config = new Config([], ['root-package-json-dir' => 'C:\\']);
+ $this->manager = $this->getManager();
+
+ self::assertInstanceOf(
+ AbstractAssetManager::class,
+ $this->manager,
+ );
+
+ /** @var AbstractAssetManager $manager */
+ $manager = $this->manager;
+
+ self::assertSame(
+ 'C:\\package.json',
+ $manager->getPackageJsonPath(),
+ );
+ }
+
+ public function testGetPackageName(): void
+ {
+ self::assertSame(
+ 'package.json',
+ $this->manager->getPackageName(),
+ );
+ }
+
+ public function testHasLockFile(): void
+ {
+ self::assertFalse(
+ $this->manager->hasLockFile(),
+ );
+ }
+
+ public function testHasLockFileWithoutRootPackageDirAndGetcwdFailure(): void
+ {
+ $this->config = new Config([]);
+ $this->manager = $this->getManager();
+
+ MockerState::addCondition('Foxy\\Asset', 'getcwd', [], false);
+
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('Unable to get the current working directory.');
+
+ $this->manager->hasLockFile();
+ }
+
+ public function testHasLockFileWithRelativeRootPackageDirAndGetcwdFailure(): void
+ {
+ $this->config = new Config([], ['root-package-json-dir' => 'root-package']);
+ $this->manager = $this->getManager();
+
+ MockerState::addCondition('Foxy\\Asset', 'getcwd', [], false);
+
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('Unable to get the current working directory.');
+
+ $this->manager->hasLockFile();
+ }
+
+ public function testHasLockFileWithRootPackageDirAsRoot(): void
+ {
+ $this->config = new Config([], ['root-package-json-dir' => DIRECTORY_SEPARATOR]);
+ $this->manager = $this->getManager();
+
+ MockerState::addCondition('Foxy\\Asset', 'getcwd', [], $this->cwd);
+
+ self::assertInstanceOf(AbstractAssetManager::class, $this->manager);
+
+ /** @var AbstractAssetManager $manager */
+ $manager = $this->manager;
+
+ self::assertSame(
+ DIRECTORY_SEPARATOR . $manager->getPackageName(),
+ $manager->getPackageJsonPath(),
+ );
+ self::assertFalse(
+ $this->manager->hasLockFile(),
+ );
+ }
+
+ public function testIsInstalled(): void
+ {
+ self::assertFalse(
+ $this->manager->isInstalled(),
+ );
+ }
+
+ public function testIsUpdatable(): void
+ {
+ self::assertFalse(
+ $this->manager->isUpdatable(),
+ );
}
/**
@@ -354,28 +354,46 @@ public function testRunForInstallCommand(int $expectedRes, string $action): void
$nodeModulePath = $this->cwd . ltrim(AbstractAssetManager::NODE_MODULES_PATH, '.');
$this->sfs->mkdir($nodeModulePath);
- $this->assertFileExists($nodeModulePath);
+
+ self::assertFileExists(
+ $nodeModulePath,
+ );
$lockFilePath = $this->cwd . DIRECTORY_SEPARATOR . $this->manager->getLockPackageName();
file_put_contents($lockFilePath, '{}');
- $this->assertFileExists($lockFilePath);
- $this->assertTrue($this->manager->isInstalled());
- $this->assertTrue($this->manager->isUpdatable());
+ self::assertFileExists(
+ $lockFilePath,
+ );
+ self::assertTrue(
+ $this->manager->isInstalled(),
+ );
+ self::assertTrue(
+ $this->manager->isUpdatable(),
+ );
}
if (0 === $expectedRes) {
- $this->fallback->expects($this->never())->method('restore');
+ $this->fallback->expects(self::never())->method('restore');
} else {
- $this->fallback->expects($this->once())->method('restore');
+ $this->fallback->expects(self::once())->method('restore');
}
$this->executor->addExpectedValues($expectedRes, 'ASSET MANAGER OUTPUT');
- $this->assertSame($expectedRes, $this->getManager()->run());
- $this->assertSame($expectedCommand, $this->executor->getLastCommand());
- $this->assertSame('ASSET MANAGER OUTPUT', $this->executor->getLastOutput());
+ self::assertSame(
+ $expectedRes,
+ $this->getManager()->run(),
+ );
+ self::assertSame(
+ $expectedCommand,
+ $this->executor->getLastCommand(),
+ );
+ self::assertSame(
+ 'ASSET MANAGER OUTPUT',
+ $this->executor->getLastOutput(),
+ );
}
public function testRunRestoresTimeoutWhenExecutorThrows(): void
@@ -393,18 +411,24 @@ public function testRunRestoresTimeoutWhenExecutorThrows(): void
try {
$this->manager->run();
- $this->fail('Expected a runtime exception when execute fails.');
+ self::fail('Expected a runtime exception when execute fails.');
} catch (\RuntimeException $exception) {
- $this->assertSame('Process execution failed.', $exception->getMessage());
+ self::assertSame(
+ 'Process execution failed.',
+ $exception->getMessage(),
+ );
}
- $this->assertSame($expectedTimeout, ProcessExecutor::getTimeout());
+ self::assertSame(
+ $expectedTimeout,
+ ProcessExecutor::getTimeout(),
+ );
} finally {
ProcessExecutor::setTimeout($originalTimeout);
}
}
- public function testSpecifyCustomDirectoryFromPackageJson(): void
+ public function testRunWithChdirFailure(): void
{
$rootPackageDir = $this->cwd . DIRECTORY_SEPARATOR . 'root-package';
$this->sfs->mkdir($rootPackageDir);
@@ -416,39 +440,70 @@ public function testSpecifyCustomDirectoryFromPackageJson(): void
);
$this->manager = $this->getManager();
- $this->assertSame($rootPackageDir, $this->config->get('root-package-json-dir'));
- $this->assertSame(0, $this->getManager()->run());
- $this->assertSame($originalCwd, getcwd());
+ MockerState::addCondition('Foxy\\Asset', 'chdir', [$rootPackageDir], false);
+
+ try {
+ $this->getManager()->run();
+ self::fail('Expected a runtime exception when chdir fails.');
+ } catch (RuntimeException $exception) {
+ self::assertSame(
+ sprintf('Unable to change working directory to "%s".', $rootPackageDir),
+ $exception->getMessage(),
+ );
+ self::assertSame(
+ $originalCwd,
+ getcwd(),
+ );
+ }
}
- public function testSpecifyCustomDirectoryFromPackageJsonException(): void
+ public function testRunWithChdirRestoreFailure(): void
{
+ $rootPackageDir = $this->cwd . DIRECTORY_SEPARATOR . 'root-package';
+ $this->sfs->mkdir($rootPackageDir);
$originalCwd = getcwd();
- $expectedPath = $this->cwd . DIRECTORY_SEPARATOR . 'path/to/invalid';
$this->config = new Config(
[],
- ['run-asset-manager' => true, 'root-package-json-dir' => 'path/to/invalid'],
+ ['run-asset-manager' => true, 'root-package-json-dir' => $rootPackageDir],
);
$this->manager = $this->getManager();
+ MockerState::addCondition('Foxy\\Asset', 'chdir', [$rootPackageDir], true);
+ MockerState::addCondition('Foxy\\Asset', 'chdir', [$originalCwd], false);
+
+ $this->executor->addExpectedValues(0, 'ASSET MANAGER OUTPUT');
+
try {
- $this->getManager()->run();
- $this->fail('Expected a runtime exception for invalid root package directory.');
- } catch (\Foxy\Exception\RuntimeException $exception) {
- $this->assertSame(
- sprintf('The root package directory "%s" doesn\'t exist.', $expectedPath),
- $exception->getMessage()
+ $this->manager->run();
+ self::fail('Expected a runtime exception when restoring chdir fails.');
+ } catch (RuntimeException $exception) {
+ self::assertSame(
+ sprintf('Unable to restore working directory to "%s".', $originalCwd),
+ $exception->getMessage(),
+ );
+ self::assertSame(
+ $originalCwd,
+ getcwd(),
);
- $this->assertSame($originalCwd, getcwd());
}
}
+ public function testRunWithDisableOption(): void
+ {
+ $this->config = new Config([], ['run-asset-manager' => false]);
+
+ self::assertSame(
+ 0,
+ $this->getManager()->run(),
+ );
+ }
+
public function testRunWithGetcwdFailure(): void
{
$rootPackageDir = $this->cwd . DIRECTORY_SEPARATOR . 'root-package';
$this->sfs->mkdir($rootPackageDir);
- $originalCwd = \getcwd();
+ $originalCwd = getcwd();
$this->config = new Config(
[],
@@ -460,105 +515,126 @@ public function testRunWithGetcwdFailure(): void
try {
$this->getManager()->run();
- $this->fail('Expected a runtime exception when getcwd fails.');
- } catch (\Foxy\Exception\RuntimeException $exception) {
- $this->assertSame('Unable to get the current working directory.', $exception->getMessage());
- $this->assertSame($originalCwd, \getcwd());
+ self::fail('Expected a runtime exception when getcwd fails.');
+ } catch (RuntimeException $exception) {
+ self::assertSame(
+ 'Unable to get the current working directory.',
+ $exception->getMessage(),
+ );
+ self::assertSame(
+ $originalCwd,
+ getcwd(),
+ );
}
}
- public function testHasLockFileWithRelativeRootPackageDirAndGetcwdFailure(): void
+ public function testSetUpdatable(): void
{
- $this->config = new Config([], ['root-package-json-dir' => 'root-package']);
- $this->manager = $this->getManager();
-
- MockerState::addCondition('Foxy\\Asset', 'getcwd', [], false);
-
- $this->expectException(\Foxy\Exception\RuntimeException::class);
- $this->expectExceptionMessage('Unable to get the current working directory.');
+ $res = $this->manager->setUpdatable(false);
- $this->manager->hasLockFile();
+ self::assertInstanceOf(
+ AssetManagerInterface::class,
+ $res,
+ );
}
- public function testHasLockFileWithoutRootPackageDirAndGetcwdFailure(): void
+ public function testSpecifyCustomDirectoryFromPackageJson(): void
{
- $this->config = new Config([]);
- $this->manager = $this->getManager();
-
- MockerState::addCondition('Foxy\\Asset', 'getcwd', [], false);
+ $rootPackageDir = $this->cwd . DIRECTORY_SEPARATOR . 'root-package';
+ $this->sfs->mkdir($rootPackageDir);
+ $originalCwd = getcwd();
- $this->expectException(\Foxy\Exception\RuntimeException::class);
- $this->expectExceptionMessage('Unable to get the current working directory.');
+ $this->config = new Config(
+ [],
+ ['run-asset-manager' => true, 'root-package-json-dir' => $rootPackageDir],
+ );
+ $this->manager = $this->getManager();
- $this->manager->hasLockFile();
+ self::assertSame(
+ $rootPackageDir,
+ $this->config->get('root-package-json-dir'),
+ );
+ self::assertSame(
+ 0,
+ $this->getManager()->run(),
+ );
+ self::assertSame(
+ $originalCwd,
+ getcwd(),
+ );
}
- public function testRunWithChdirFailure(): void
+ public function testSpecifyCustomDirectoryFromPackageJsonException(): void
{
- $rootPackageDir = $this->cwd . DIRECTORY_SEPARATOR . 'root-package';
- $this->sfs->mkdir($rootPackageDir);
- $originalCwd = \getcwd();
+ $originalCwd = getcwd();
+ $expectedPath = $this->cwd . DIRECTORY_SEPARATOR . 'path/to/invalid';
$this->config = new Config(
[],
- ['run-asset-manager' => true, 'root-package-json-dir' => $rootPackageDir],
+ ['run-asset-manager' => true, 'root-package-json-dir' => 'path/to/invalid'],
);
$this->manager = $this->getManager();
- MockerState::addCondition('Foxy\\Asset', 'chdir', [$rootPackageDir], false);
-
try {
$this->getManager()->run();
- $this->fail('Expected a runtime exception when chdir fails.');
- } catch (\Foxy\Exception\RuntimeException $exception) {
- $this->assertSame(
- sprintf('Unable to change working directory to "%s".', $rootPackageDir),
- $exception->getMessage()
+ self::fail('Expected a runtime exception for invalid root package directory.');
+ } catch (RuntimeException $exception) {
+ self::assertSame(
+ sprintf('The root package directory "%s" doesn\'t exist.', $expectedPath),
+ $exception->getMessage(),
+ );
+ self::assertSame(
+ $originalCwd,
+ getcwd(),
);
- $this->assertSame($originalCwd, \getcwd());
}
}
- public function testRunWithChdirRestoreFailure(): void
+ public function testValidateWithInstalledManagerAndWithoutValidationVersion(): void
{
- $rootPackageDir = $this->cwd . DIRECTORY_SEPARATOR . 'root-package';
- $this->sfs->mkdir($rootPackageDir);
- $originalCwd = \getcwd();
+ $this->executor->addExpectedValues(0, '42.0.0');
+ $this->manager->validate();
- $this->config = new Config(
- [],
- ['run-asset-manager' => true, 'root-package-json-dir' => $rootPackageDir],
+ self::assertNull(
+ $this->config->get('manager-version'),
);
- $this->manager = $this->getManager();
+ }
- MockerState::addCondition('Foxy\\Asset', 'chdir', [$rootPackageDir], true);
- MockerState::addCondition('Foxy\\Asset', 'chdir', [$originalCwd], false);
+ public function testValidateWithInstalledManagerAndWithoutValidVersion(): void
+ {
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessageMatches(
+ '/The installed (\w+) version "42.0.0" doesn\'t match with the constraint version ">=50.0"/',
+ );
- $this->executor->addExpectedValues(0, 'ASSET MANAGER OUTPUT');
+ $this->config = new Config([], ['manager-version' => '>=50.0']);
- try {
- $this->manager->run();
- $this->fail('Expected a runtime exception when restoring chdir fails.');
- } catch (\Foxy\Exception\RuntimeException $exception) {
- $this->assertSame(
- sprintf('Unable to restore working directory to "%s".', $originalCwd),
- $exception->getMessage()
- );
- $this->assertSame($originalCwd, \getcwd());
- }
+ $this->manager = $this->getManager();
+ $this->executor->addExpectedValues(0, '42.0.0');
+ $this->manager->validate();
}
- abstract protected function getManager(): AssetManagerInterface;
-
- abstract protected function getValidName(): string;
+ public function testValidateWithInstalledManagerAndWithValidVersion(): void
+ {
+ $this->config = new Config([], ['manager-version' => '>=41.0']);
- abstract protected function getValidLockPackageName(): string;
+ $this->manager = $this->getManager();
+ $this->executor->addExpectedValues(0, '42.0.0');
+ $this->manager->validate();
- abstract protected function getValidVersionCommand(): string;
+ self::assertSame(
+ '>=41.0',
+ $this->config->get('manager-version'),
+ );
+ }
- abstract protected function getValidInstallCommand(): string;
+ public function testValidateWithoutInstalledManager(): void
+ {
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessageMatches('/The binary of "(\w+)" must be installed/');
- abstract protected function getValidUpdateCommand(): string;
+ $this->manager->validate();
+ }
protected function actionForTestAddDependenciesForUpdateCommand(): void
{
@@ -572,4 +648,43 @@ protected function actionForTestRunForInstallCommand(string $action): void
{
// do nothing by default
}
+
+ /**
+ * @throws Exception
+ */
+ protected function setUp(): void
+ {
+ parent::setUp();
+
+ $this->config = new Config([]);
+ $this->io = $this->createMock(IOInterface::class);
+ $this->executor = new ProcessExecutorMock($this->io);
+ $this->fs = $this->createMock(Filesystem::class);
+ $this->sfs = new \Symfony\Component\Filesystem\Filesystem();
+ $this->fallback = $this->createMock(FallbackInterface::class);
+ $this->manager = $this->getManager();
+ $this->oldCwd = getcwd();
+ $this->cwd = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('foxy_asset_manager_test_', true);
+ $this->sfs->mkdir($this->cwd);
+
+ chdir($this->cwd);
+ }
+
+ protected function tearDown(): void
+ {
+ parent::tearDown();
+
+ chdir($this->oldCwd);
+
+ $this->sfs->remove($this->cwd);
+ $this->config = null;
+ $this->io = null;
+ $this->executor = null;
+ $this->fs = null;
+ $this->sfs = null;
+ $this->fallback = null;
+ $this->manager = null;
+ $this->oldCwd = null;
+ $this->cwd = null;
+ }
}
diff --git a/tests/Asset/AssetManagerFinderTest.php b/tests/Asset/AssetManagerFinderTest.php
index 985c0bb..c22ceed 100644
--- a/tests/Asset/AssetManagerFinderTest.php
+++ b/tests/Asset/AssetManagerFinderTest.php
@@ -2,98 +2,92 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Asset;
-use Foxy\Asset\AssetManagerFinder;
+use Foxy\Asset\{AssetManagerFinder, AssetManagerInterface};
+use Foxy\Exception\RuntimeException;
use PHPUnit\Framework\TestCase;
-/**
- * Asset manager finder tests.
- *
- * @author François Pluchino
- *
- * @internal
- */
final class AssetManagerFinderTest extends TestCase
{
- public function testFindManagerWithValidManager(): void
+ public function testFindManagerWithAutoManagerAndAvailableManagerByAvailability(): void
{
- $am = $this->createMock(\Foxy\Asset\AssetManagerInterface::class);
+ $am = $this->createMock(AssetManagerInterface::class);
- $am->expects($this->once())->method('getName')->willReturn('foo');
+ $am->expects(self::once())->method('getName')->willReturn('foo');
+ $am->expects(self::once())->method('hasLockFile')->willReturn(false);
+ $am->expects(self::once())->method('isAvailable')->willReturn(true);
$amf = new AssetManagerFinder([$am]);
- $res = $amf->findManager('foo');
- $this->assertSame($am, $res);
+ $res = $amf->findManager();
+
+ self::assertSame(
+ $am,
+ $res,
+ );
}
- public function testFindManagerWithInvalidManager(): void
+ public function testFindManagerWithAutoManagerAndAvailableManagerByLockFile(): void
{
- $this->expectException(\Foxy\Exception\RuntimeException::class);
- $this->expectExceptionMessage('The asset manager "bar" doesn\'t exist');
-
- $am = $this->createMock(\Foxy\Asset\AssetManagerInterface::class);
+ $am = $this->createMock(AssetManagerInterface::class);
- $am->expects($this->once())->method('getName')->willReturn('foo');
+ $am->expects(self::once())->method('getName')->willReturn('foo');
+ $am->expects(self::once())->method('hasLockFile')->willReturn(true);
+ $am->expects(self::never())->method('isAvailable');
$amf = new AssetManagerFinder([$am]);
- $amf->findManager('bar');
+ $res = $amf->findManager();
+
+ self::assertSame(
+ $am,
+ $res,
+ );
}
- public function testFindManagerWithAutoManagerAndAvailableManagerByLockFile(): void
+ public function testFindManagerWithAutoManagerAndNoAvailableManager(): void
{
- $am = $this->createMock(\Foxy\Asset\AssetManagerInterface::class);
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('No asset manager is found');
- $am->expects($this->once())->method('getName')->willReturn('foo');
- $am->expects($this->once())->method('hasLockFile')->willReturn(true);
- $am->expects($this->never())->method('isAvailable');
+ $am = $this->getMockBuilder(AssetManagerInterface::class)->getMock();
- $amf = new AssetManagerFinder([$am]);
+ $am->expects(self::atLeastOnce())->method('getName')->willReturn('foo');
+ $am->expects(self::once())->method('hasLockFile')->willReturn(false);
+ $am->expects(self::once())->method('isAvailable')->willReturn(false);
- $res = $amf->findManager(null);
+ $amf = new AssetManagerFinder([$am]);
- $this->assertSame($am, $res);
+ $amf->findManager();
}
- public function testFindManagerWithAutoManagerAndAvailableManagerByAvailability(): void
+ public function testFindManagerWithInvalidManager(): void
{
- $am = $this->createMock(\Foxy\Asset\AssetManagerInterface::class);
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('The asset manager "bar" doesn\'t exist');
- $am->expects($this->once())->method('getName')->willReturn('foo');
- $am->expects($this->once())->method('hasLockFile')->willReturn(false);
- $am->expects($this->once())->method('isAvailable')->willReturn(true);
+ $am = $this->createMock(AssetManagerInterface::class);
- $amf = new AssetManagerFinder([$am]);
+ $am->expects(self::once())->method('getName')->willReturn('foo');
- $res = $amf->findManager(null);
+ $amf = new AssetManagerFinder([$am]);
- $this->assertSame($am, $res);
+ $amf->findManager('bar');
}
- public function testFindManagerWithAutoManagerAndNoAvailableManager(): void
+ public function testFindManagerWithValidManager(): void
{
- $this->expectException(\Foxy\Exception\RuntimeException::class);
- $this->expectExceptionMessage('No asset manager is found');
-
- $am = $this->getMockBuilder(\Foxy\Asset\AssetManagerInterface::class)->getMock();
+ $am = $this->createMock(AssetManagerInterface::class);
- $am->expects($this->atLeastOnce())->method('getName')->willReturn('foo');
- $am->expects($this->once())->method('hasLockFile')->willReturn(false);
- $am->expects($this->once())->method('isAvailable')->willReturn(false);
+ $am->expects(self::once())->method('getName')->willReturn('foo');
$amf = new AssetManagerFinder([$am]);
+ $res = $amf->findManager('foo');
- $amf->findManager(null);
+ self::assertSame(
+ $am,
+ $res,
+ );
}
}
diff --git a/tests/Asset/AssetPackageTest.php b/tests/Asset/AssetPackageTest.php
index 381e9be..ecdeb6f 100644
--- a/tests/Asset/AssetPackageTest.php
+++ b/tests/Asset/AssetPackageTest.php
@@ -2,89 +2,28 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Asset;
use Composer\Json\JsonFile;
use Composer\Package\RootPackageInterface;
+use Exception;
use Foxy\Asset\AssetPackage;
+use JsonException;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
+use Seld\JsonLint\ParsingException;
use Symfony\Component\Filesystem\Filesystem;
-/**
- * Asset package tests.
- *
- * @author François Pluchino
- *
- * @internal
- */
-final class AssetPackageTest extends \PHPUnit\Framework\TestCase
+use function file_put_contents;
+
+use const DIRECTORY_SEPARATOR;
+
+final class AssetPackageTest extends TestCase
{
protected string|null $cwd = '';
- protected Filesystem|null $sfs = null;
- protected MockObject|RootPackageInterface|null $rootPackage = null;
protected JsonFile|MockObject|null $jsonFile = null;
-
- protected function setUp(): void
- {
- parent::setUp();
-
- $this->cwd = sys_get_temp_dir() . \DIRECTORY_SEPARATOR . uniqid('foxy_asset_package_test_', true);
- $this->sfs = new Filesystem();
- $this->rootPackage = $this->createMock(RootPackageInterface::class);
- $this->jsonFile = $this->getMockBuilder(JsonFile::class)
- ->disableOriginalConstructor()
- ->onlyMethods(['exists', 'getPath', 'read', 'write'])
- ->getMock()
- ;
-
- $this->rootPackage->expects($this->any())->method('getLicense')->willReturn([]);
-
- $this->sfs->mkdir($this->cwd);
- }
-
- protected function tearDown(): void
- {
- parent::tearDown();
-
- $this->sfs->remove($this->cwd);
- $this->jsonFile = null;
- $this->rootPackage = null;
- $this->sfs = null;
- $this->cwd = null;
- }
-
- public function testGetPackageWithExistingFile(): void
- {
- $package = ['name' => '@foo/bar'];
- $contentString = json_encode($package);
- $this->addPackageFile($package, $contentString);
-
- $assetPackage = new AssetPackage($this->rootPackage, $this->jsonFile);
-
- $this->assertSame($package, $assetPackage->getPackage());
- }
-
- public function testWrite(): void
- {
- $package = ['name' => '@foo/bar'];
-
- $this->jsonFile->expects($this->once())->method('exists')->willReturn(false);
- $this->jsonFile->expects($this->once())->method('write')->with($package);
-
- $assetPackage = new AssetPackage($this->rootPackage, $this->jsonFile);
-
- $assetPackage->setPackage($package);
- $assetPackage->write();
- }
+ protected MockObject|RootPackageInterface|null $rootPackage = null;
+ protected Filesystem|null $sfs = null;
public static function getDataRequiredKeys(): array
{
@@ -124,21 +63,54 @@ public static function getDataRequiredKeys(): array
}
/**
- * @dataProvider getDataRequiredKeys
+ * @throws JsonException|ParsingException
*/
- public function testInjectionOfRequiredKeys(array $expected, array $package, string $license): void
+ public function testAddNewDependencies(): void
{
- $this->addPackageFile($package);
-
- $this->rootPackage = $this->createMock(RootPackageInterface::class);
+ $expected = [
+ 'dependencies' => [
+ '@bar/foo' => '^1.0.0',
+ '@composer-asset/baz--bar' => 'file:./path/baz/bar',
+ '@composer-asset/foo--bar' => 'file:./path/foo/bar',
+ '@composer-asset/new--dependency' => 'file:./path/new/dependency',
+ ],
+ ];
+ $expectedExisting = [
+ '@composer-asset/foo--bar',
+ '@composer-asset/baz--bar',
+ ];
+ $package = [
+ 'dependencies' => [
+ '@composer-asset/foo--bar' => 'file:./path/foo/bar',
+ '@bar/foo' => '^1.0.0',
+ '@composer-asset/baz--bar' => 'file:./path/baz/bar',
+ ],
+ ];
+ $dependencies = [
+ '@composer-asset/foo--bar' => 'path/foo/bar/package.json',
+ '@composer-asset/baz--bar' => 'path/baz/bar/package.json',
+ '@composer-asset/new--dependency' => 'path/new/dependency/package.json',
+ ];
- $this->rootPackage->expects($this->any())->method('getLicense')->willReturn([$license]);
+ $this->addPackageFile($package);
$assetPackage = new AssetPackage($this->rootPackage, $this->jsonFile);
+ $existing = $assetPackage->addNewDependencies($dependencies);
- $this->assertEquals($expected, $assetPackage->getPackage());
+ self::assertSame(
+ $expected,
+ $assetPackage->getPackage(),
+ );
+ self::assertSame(
+ $expectedExisting,
+ $existing,
+ );
}
+ /**
+ * @throws ParsingException
+ * @throws JsonException
+ */
public function testGetInstalledDependencies(): void
{
$expected = [
@@ -157,43 +129,57 @@ public function testGetInstalledDependencies(): void
$assetPackage = new AssetPackage($this->rootPackage, $this->jsonFile);
- $this->assertEquals($expected, $assetPackage->getInstalledDependencies());
+ self::assertSame(
+ $expected,
+ $assetPackage->getInstalledDependencies(),
+ );
}
- public function testAddNewDependencies(): void
+ /**
+ * @throws ParsingException
+ * @throws JsonException
+ */
+ public function testGetPackageWithExistingFile(): void
{
- $expected = [
- 'dependencies' => [
- '@bar/foo' => '^1.0.0',
- '@composer-asset/baz--bar' => 'file:./path/baz/bar',
- '@composer-asset/foo--bar' => 'file:./path/foo/bar',
- '@composer-asset/new--dependency' => 'file:./path/new/dependency',
- ],
- ];
- $expectedExisting = ['@composer-asset/foo--bar', '@composer-asset/baz--bar'];
+ $package = ['name' => '@foo/bar'];
- $package = [
- 'dependencies' => [
- '@composer-asset/foo--bar' => 'file:./path/foo/bar',
- '@bar/foo' => '^1.0.0',
- '@composer-asset/baz--bar' => 'file:./path/baz/bar',
- ],
- ];
- $dependencies = [
- '@composer-asset/foo--bar' => 'path/foo/bar/package.json',
- '@composer-asset/baz--bar' => 'path/baz/bar/package.json',
- '@composer-asset/new--dependency' => 'path/new/dependency/package.json',
- ];
+ $contentString = json_encode($package, JSON_THROW_ON_ERROR);
+ $this->addPackageFile($package, $contentString);
+
+ $assetPackage = new AssetPackage($this->rootPackage, $this->jsonFile);
+
+ self::assertSame(
+ $package,
+ $assetPackage->getPackage(),
+ );
+ }
+
+ /**
+ * @dataProvider getDataRequiredKeys
+ *
+ * @throws JsonException|ParsingException
+ */
+ public function testInjectionOfRequiredKeys(array $expected, array $package, string $license): void
+ {
$this->addPackageFile($package);
+ $this->rootPackage = $this->createMock(RootPackageInterface::class);
+
+ $this->rootPackage->expects(self::any())->method('getLicense')->willReturn([$license]);
+
$assetPackage = new AssetPackage($this->rootPackage, $this->jsonFile);
- $existing = $assetPackage->addNewDependencies($dependencies);
- $this->assertSame($expected, $assetPackage->getPackage());
- $this->assertSame($expectedExisting, $existing);
+ self::assertSame(
+ $expected,
+ $assetPackage->getPackage(),
+ );
}
+ /**
+ * @throws ParsingException
+ * @throws JsonException
+ */
public function testRemoveUnusedDependencies(): void
{
$expected = [
@@ -215,9 +201,29 @@ public function testRemoveUnusedDependencies(): void
$this->addPackageFile($package);
$assetPackage = new AssetPackage($this->rootPackage, $this->jsonFile);
+
$assetPackage->removeUnusedDependencies($dependencies);
- $this->assertEquals($expected, $assetPackage->getPackage());
+ self::assertSame(
+ $expected,
+ $assetPackage->getPackage(),
+ );
+ }
+
+ /**
+ * @throws Exception|ParsingException
+ */
+ public function testWrite(): void
+ {
+ $package = ['name' => '@foo/bar'];
+
+ $this->jsonFile->expects(self::once())->method('exists')->willReturn(false);
+ $this->jsonFile->expects(self::once())->method('write')->with($package);
+
+ $assetPackage = new AssetPackage($this->rootPackage, $this->jsonFile);
+
+ $assetPackage->setPackage($package);
+ $assetPackage->write();
}
/**
@@ -225,16 +231,49 @@ public function testRemoveUnusedDependencies(): void
*
* @param array $package The package.
* @param string|null $contentString The string content of package.
+ *
+ * @throws JsonException
*/
- protected function addPackageFile(array $package, $contentString = null): void
+ protected function addPackageFile(array $package, string|null $contentString = null): void
{
$filename = $this->cwd . '/package.json';
- $contentString ??= json_encode($package);
+ $contentString ??= json_encode($package, JSON_THROW_ON_ERROR);
+
+ $this->jsonFile->expects(self::any())->method('exists')->willReturn(true);
+ $this->jsonFile->expects(self::any())->method('getPath')->willReturn($filename);
+ $this->jsonFile->expects(self::any())->method('read')->willReturn($package);
+
+ file_put_contents($filename, $contentString);
+ }
+
+ protected function setUp(): void
+ {
+ parent::setUp();
+
+ $this->cwd = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('foxy_asset_package_test_', true);
- $this->jsonFile->expects($this->any())->method('exists')->willReturn(true);
- $this->jsonFile->expects($this->any())->method('getPath')->willReturn($filename);
- $this->jsonFile->expects($this->any())->method('read')->willReturn($package);
+ $this->sfs = new Filesystem();
- \file_put_contents($filename, $contentString);
+ $this->rootPackage = $this->createMock(RootPackageInterface::class);
+ $this->jsonFile = $this
+ ->getMockBuilder(JsonFile::class)
+ ->disableOriginalConstructor()
+ ->onlyMethods(['exists', 'getPath', 'read', 'write'])
+ ->getMock()
+ ;
+ $this->rootPackage->expects(self::any())->method('getLicense')->willReturn([]);
+
+ $this->sfs->mkdir($this->cwd);
+ }
+
+ protected function tearDown(): void
+ {
+ parent::tearDown();
+
+ $this->sfs->remove($this->cwd);
+ $this->jsonFile = null;
+ $this->rootPackage = null;
+ $this->sfs = null;
+ $this->cwd = null;
}
}
diff --git a/tests/Asset/BunAssetManagerTest.php b/tests/Asset/BunAssetManagerTest.php
index ec5ee7c..3ddf39a 100644
--- a/tests/Asset/BunAssetManagerTest.php
+++ b/tests/Asset/BunAssetManagerTest.php
@@ -2,27 +2,11 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Asset;
use Composer\Util\Platform;
use Foxy\Asset\BunManager;
-/**
- * Pnpm asset manager tests.
- *
- * @author Steffen Dietz
- *
- * @internal
- */
final class BunAssetManagerTest extends AssetManager
{
protected function getManager(): BunManager
@@ -30,9 +14,9 @@ protected function getManager(): BunManager
return new BunManager($this->io, $this->config, $this->executor, $this->fs, $this->fallback);
}
- protected function getValidName(): string
+ protected function getValidInstallCommand(): string
{
- return 'bun';
+ return Platform::isWindows() ? 'bun.exe install -y' : 'bun install -y';
}
protected function getValidLockPackageName(): string
@@ -40,18 +24,18 @@ protected function getValidLockPackageName(): string
return 'yarn.lock';
}
- protected function getValidVersionCommand(): string
+ protected function getValidName(): string
{
- return Platform::isWindows() ? 'bun.exe --version' : 'bun --version';
+ return 'bun';
}
- protected function getValidInstallCommand(): string
+ protected function getValidUpdateCommand(): string
{
- return Platform::isWindows() ? 'bun.exe install -y' : 'bun install -y';
+ return Platform::isWindows() ? 'bun.exe update -y' : 'bun update -y';
}
- protected function getValidUpdateCommand(): string
+ protected function getValidVersionCommand(): string
{
- return Platform::isWindows() ? 'bun.exe update -y' : 'bun update -y';
+ return Platform::isWindows() ? 'bun.exe --version' : 'bun --version';
}
}
diff --git a/tests/Asset/NpmAssetManagerTest.php b/tests/Asset/NpmAssetManagerTest.php
index a7ab14a..264ed8d 100644
--- a/tests/Asset/NpmAssetManagerTest.php
+++ b/tests/Asset/NpmAssetManagerTest.php
@@ -2,26 +2,10 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Asset;
use Foxy\Asset\NpmManager;
-/**
- * NPM asset manager tests.
- *
- * @author François Pluchino
- *
- * @internal
- */
final class NpmAssetManagerTest extends AssetManager
{
protected function getManager(): NpmManager
@@ -29,9 +13,9 @@ protected function getManager(): NpmManager
return new NpmManager($this->io, $this->config, $this->executor, $this->fs, $this->fallback);
}
- protected function getValidName(): string
+ protected function getValidInstallCommand(): string
{
- return 'npm';
+ return 'npm install';
}
protected function getValidLockPackageName(): string
@@ -39,18 +23,18 @@ protected function getValidLockPackageName(): string
return 'package-lock.json';
}
- protected function getValidVersionCommand(): string
+ protected function getValidName(): string
{
- return 'npm --version';
+ return 'npm';
}
- protected function getValidInstallCommand(): string
+ protected function getValidUpdateCommand(): string
{
- return 'npm install';
+ return 'npm update';
}
- protected function getValidUpdateCommand(): string
+ protected function getValidVersionCommand(): string
{
- return 'npm update';
+ return 'npm --version';
}
}
diff --git a/tests/Asset/PnpmAssetManagerTest.php b/tests/Asset/PnpmAssetManagerTest.php
index 738c514..67bbd02 100644
--- a/tests/Asset/PnpmAssetManagerTest.php
+++ b/tests/Asset/PnpmAssetManagerTest.php
@@ -2,26 +2,10 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Asset;
use Foxy\Asset\PnpmManager;
-/**
- * Pnpm asset manager tests.
- *
- * @author Steffen Dietz
- *
- * @internal
- */
final class PnpmAssetManagerTest extends AssetManager
{
protected function getManager(): PnpmManager
@@ -29,9 +13,9 @@ protected function getManager(): PnpmManager
return new PnpmManager($this->io, $this->config, $this->executor, $this->fs, $this->fallback);
}
- protected function getValidName(): string
+ protected function getValidInstallCommand(): string
{
- return 'pnpm';
+ return 'pnpm install';
}
protected function getValidLockPackageName(): string
@@ -39,18 +23,18 @@ protected function getValidLockPackageName(): string
return 'pnpm-lock.yaml';
}
- protected function getValidVersionCommand(): string
+ protected function getValidName(): string
{
- return 'pnpm --version';
+ return 'pnpm';
}
- protected function getValidInstallCommand(): string
+ protected function getValidUpdateCommand(): string
{
- return 'pnpm install';
+ return 'pnpm update';
}
- protected function getValidUpdateCommand(): string
+ protected function getValidVersionCommand(): string
{
- return 'pnpm update';
+ return 'pnpm --version';
}
}
diff --git a/tests/Asset/YarnAssetManagerTest.php b/tests/Asset/YarnAssetManagerTest.php
index f3e2dfc..156e53c 100644
--- a/tests/Asset/YarnAssetManagerTest.php
+++ b/tests/Asset/YarnAssetManagerTest.php
@@ -2,26 +2,10 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Asset;
use Foxy\Asset\YarnManager;
-/**
- * Yarn asset manager tests.
- *
- * @author François Pluchino
- *
- * @internal
- */
final class YarnAssetManagerTest extends AssetManager
{
public function actionForTestRunForInstallCommand($action): void
@@ -35,14 +19,20 @@ public function actionForTestRunForInstallCommand($action): void
}
}
+ protected function actionForTestAddDependenciesForUpdateCommand(): void
+ {
+ $this->executor->addExpectedValues(0, '1.0.0');
+ $this->executor->addExpectedValues(0, 'CHECK OUTPUT');
+ }
+
protected function getManager(): YarnManager
{
return new YarnManager($this->io, $this->config, $this->executor, $this->fs, $this->fallback);
}
- protected function getValidName(): string
+ protected function getValidInstallCommand(): string
{
- return 'yarn';
+ return 'yarn install --non-interactive';
}
protected function getValidLockPackageName(): string
@@ -50,14 +40,9 @@ protected function getValidLockPackageName(): string
return 'yarn.lock';
}
- protected function getValidVersionCommand(): string
- {
- return 'yarn --version';
- }
-
- protected function getValidInstallCommand(): string
+ protected function getValidName(): string
{
- return 'yarn install --non-interactive';
+ return 'yarn';
}
protected function getValidUpdateCommand(): string
@@ -65,9 +50,8 @@ protected function getValidUpdateCommand(): string
return 'yarn upgrade --non-interactive';
}
- protected function actionForTestAddDependenciesForUpdateCommand(): void
+ protected function getValidVersionCommand(): string
{
- $this->executor->addExpectedValues(0, '1.0.0');
- $this->executor->addExpectedValues(0, 'CHECK OUTPUT');
+ return 'yarn --version';
}
}
diff --git a/tests/Asset/YarnNextAssetManagerTest.php b/tests/Asset/YarnNextAssetManagerTest.php
index bb660c6..5594819 100644
--- a/tests/Asset/YarnNextAssetManagerTest.php
+++ b/tests/Asset/YarnNextAssetManagerTest.php
@@ -2,26 +2,10 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Asset;
use Foxy\Asset\YarnManager;
-/**
- * Yarn Next asset manager tests.
- *
- * @author François Pluchino
- *
- * @internal
- */
final class YarnNextAssetManagerTest extends AssetManager
{
public function actionForTestRunForInstallCommand($action): void
@@ -33,14 +17,20 @@ public function actionForTestRunForInstallCommand($action): void
}
}
+ protected function actionForTestAddDependenciesForUpdateCommand(): void
+ {
+ $this->executor->addExpectedValues(0, '2.0.0');
+ $this->executor->addExpectedValues(0, 'CHECK OUTPUT');
+ }
+
protected function getManager(): YarnManager
{
return new YarnManager($this->io, $this->config, $this->executor, $this->fs, $this->fallback);
}
- protected function getValidName(): string
+ protected function getValidInstallCommand(): string
{
- return 'yarn';
+ return 'yarn install';
}
protected function getValidLockPackageName(): string
@@ -48,14 +38,9 @@ protected function getValidLockPackageName(): string
return 'yarn.lock';
}
- protected function getValidVersionCommand(): string
- {
- return 'yarn --version';
- }
-
- protected function getValidInstallCommand(): string
+ protected function getValidName(): string
{
- return 'yarn install';
+ return 'yarn';
}
protected function getValidUpdateCommand(): string
@@ -63,9 +48,8 @@ protected function getValidUpdateCommand(): string
return 'yarn up';
}
- protected function actionForTestAddDependenciesForUpdateCommand(): void
+ protected function getValidVersionCommand(): string
{
- $this->executor->addExpectedValues(0, '2.0.0');
- $this->executor->addExpectedValues(0, 'CHECK OUTPUT');
+ return 'yarn --version';
}
}
diff --git a/tests/Config/ConfigTest.php b/tests/Config/ConfigTest.php
index cd9ae95..0585606 100644
--- a/tests/Config/ConfigTest.php
+++ b/tests/Config/ConfigTest.php
@@ -2,47 +2,35 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Config;
-use Composer\Composer;
-use Composer\Config;
+use Composer\{Composer, Config};
use Composer\IO\IOInterface;
use Composer\Package\RootPackageInterface;
+use Exception;
use Foxy\Config\ConfigBuilder;
+use Foxy\Exception\RuntimeException;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
+use Seld\JsonLint\ParsingException;
+
+use function getenv;
+use function putenv;
+use function sprintf;
+use function str_starts_with;
+use function strpos;
+use function substr;
-/**
- * Tests for config.
- *
- * @author François Pluchino
- *
- * @internal
- */
-final class ConfigTest extends \PHPUnit\Framework\TestCase
+final class ConfigTest extends TestCase
{
private Composer|MockObject|null $composer = null;
private Config|MockObject|null $composerConfig = null;
private IOInterface|MockObject|null $io = null;
private MockObject|RootPackageInterface|null $package = null;
- protected function setUp(): void
+ public static function getDataForGetArrayConfig(): array
{
- $this->composer = $this->createMock(Composer::class);
- $this->composerConfig = $this->createMock(Config::class);
- $this->io = $this->createMock(IOInterface::class);
- $this->package = $this->createMock(RootPackageInterface::class);
-
- $this->composer->expects($this->any())->method('getPackage')->willReturn($this->package);
- $this->composer->expects($this->any())->method('getConfig')->willReturn($this->composerConfig);
+ return [['foo', [], []], ['foo', [42], [42]], ['foo', [42], [], ['foo' => [42]]]];
}
public static function getDataForGetConfig(): array
@@ -68,6 +56,26 @@ public static function getDataForGetConfig(): array
];
}
+ /**
+ * @dataProvider getDataForGetArrayConfig
+ *
+ * @param string $key The key.
+ * @param array $expected The expected value.
+ * @param array $default The default value.
+ * @param array $defaults The configured default values.
+ *
+ * @throws ParsingException
+ */
+ public function testGetArrayConfig(string $key, array $expected, array $default, array $defaults = []): void
+ {
+ $config = ConfigBuilder::build($this->composer, $defaults, $this->io);
+
+ self::assertSame(
+ $expected,
+ $config->getArray($key, $default),
+ );
+ }
+
/**
* @dataProvider getDataForGetConfig
*
@@ -76,17 +84,19 @@ public static function getDataForGetConfig(): array
* @param mixed $default The default value.
* @param string|null $env The env variable.
* @param array $defaults The configured default values.
+ *
+ * @throws ParsingException
*/
public function testGetConfig(
string $key,
mixed $expected,
mixed $default = null,
string|null $env = null,
- array $defaults = []
+ array $defaults = [],
): void {
// add env variables
if (null !== $env) {
- \putenv($env);
+ putenv($env);
}
$globalLogComposer = true;
@@ -94,11 +104,11 @@ public function testGetConfig(
$globalPath = realpath(__DIR__ . '/../Fixtures/package/global');
- $this->composerConfig->expects($this->any())->method('has')->with('home')->willReturn(true);
- $this->composerConfig->expects($this->any())->method('get')->with('home')->willReturn($globalPath);
+ $this->composerConfig->expects(self::any())->method('has')->with('home')->willReturn(true);
+ $this->composerConfig->expects(self::any())->method('get')->with('home')->willReturn($globalPath);
$this->package
- ->expects($this->any())
+ ->expects(self::any())
->method('getConfig')
->willReturn(
[
@@ -118,25 +128,25 @@ public function testGetConfig(
],
);
- if (\str_starts_with($key, 'global-')) {
- $this->io->expects($this->atLeast(2))->method('isDebug')->willReturn(true);
+ if (str_starts_with($key, 'global-')) {
+ $this->io->expects(self::atLeast(2))->method('isDebug')->willReturn(true);
$globalLogComposer = false;
$globalLogConfig = false;
$this->io
- ->expects($this->atLeastOnce())
+ ->expects(self::atLeastOnce())
->method('writeError')
->willReturnCallback(
static function ($message) use ($globalPath, &$globalLogComposer, &$globalLogConfig): void {
- if (\sprintf('Loading Foxy config in file %s/composer.json', $globalPath)) {
+ if (sprintf('Loading Foxy config in file %s/composer.json', $globalPath)) {
$globalLogComposer = true;
}
- if (\sprintf('Loading Foxy config in file %s/config.json', $globalPath)) {
+ if (sprintf('Loading Foxy config in file %s/config.json', $globalPath)) {
$globalLogConfig = true;
}
- }
+ },
);
}
@@ -145,63 +155,70 @@ static function ($message) use ($globalPath, &$globalLogComposer, &$globalLogCon
// remove env variables
if (null !== $env) {
- $envKey = \substr($env, 0, \strpos($env, '='));
-
- \putenv($envKey);
+ $envKey = substr($env, 0, strpos($env, '='));
+ putenv($envKey);
- $this->assertFalse(\getenv($envKey));
+ self::assertFalse(
+ getenv($envKey),
+ );
}
- $this->assertTrue($globalLogComposer);
- $this->assertTrue($globalLogConfig);
- $this->assertSame($expected, $value);
- // test cache
- $this->assertSame($expected, $config->get($key, $default));
- }
-
- public static function getDataForGetArrayConfig(): array
- {
- return [['foo', [], []], ['foo', [42], [42]], ['foo', [42], [], ['foo' => [42]]]];
+ self::assertTrue(
+ $globalLogComposer,
+ );
+ self::assertTrue(
+ $globalLogConfig,
+ );
+ self::assertSame(
+ $expected,
+ $value,
+ );
+ self::assertSame(
+ $expected,
+ $config->get($key, $default),
+ );
}
/**
- * @dataProvider getDataForGetArrayConfig
- *
- * @param string $key The key.
- * @param array $expected The expected value.
- * @param array $default The default value.
- * @param array $defaults The configured default values.
+ * @throws Exception|ParsingException
*/
- public function testGetArrayConfig(string $key, array $expected, array $default, array $defaults = []): void
- {
- $config = ConfigBuilder::build($this->composer, $defaults, $this->io);
-
- $this->assertSame($expected, $config->getArray($key, $default));
- }
-
public function testGetEnvConfigWithInvalidJson(): void
{
- $this->expectException(\Foxy\Exception\RuntimeException::class);
+ $this->expectException(RuntimeException::class);
$this->expectExceptionMessage('The "FOXY__ENV_JSON" environment variable isn\'t a valid JSON');
- \putenv('FOXY__ENV_JSON="{"foo"}"');
+ putenv('FOXY__ENV_JSON="{"foo"}"');
$config = ConfigBuilder::build($this->composer, [], $this->io);
$ex = null;
try {
$config->get('env-json');
- } catch (\Exception $e) {
+ } catch (Exception $e) {
$ex = $e;
}
- \putenv('FOXY__ENV_JSON');
- $this->assertFalse(\getenv('FOXY__ENV_JSON'));
+ putenv('FOXY__ENV_JSON');
+
+ self::assertFalse(
+ getenv('FOXY__ENV_JSON'),
+ );
if (null === $ex) {
- throw new \Exception('The expected exception was not thrown');
+ throw new Exception('The expected exception was not thrown');
}
throw $ex;
}
+
+ protected function setUp(): void
+ {
+ $this->composer = $this->createMock(Composer::class);
+ $this->composerConfig = $this->createMock(Config::class);
+ $this->io = $this->createMock(IOInterface::class);
+ $this->package = $this->createMock(RootPackageInterface::class);
+
+ $this->composer->expects(self::any())->method('getPackage')->willReturn($this->package);
+ $this->composer->expects(self::any())->method('getConfig')->willReturn($this->composerConfig);
+ }
}
diff --git a/tests/Converter/SemverConverterTest.php b/tests/Converter/SemverConverterTest.php
index 196b879..5dc4575 100644
--- a/tests/Converter/SemverConverterTest.php
+++ b/tests/Converter/SemverConverterTest.php
@@ -2,54 +2,18 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Converter;
-use Foxy\Converter\SemverConverter;
-use Foxy\Converter\VersionConverterInterface;
+use Foxy\Converter\{SemverConverter, VersionConverterInterface};
use PHPUnit\Framework\TestCase;
-/**
- * Tests for the conversion of Semver syntax to composer syntax.
- *
- * @author François Pluchino
- *
- * @internal
- */
+use function ctype_alpha;
+use function in_array;
+
final class SemverConverterTest extends TestCase
{
private VersionConverterInterface|null $converter = null;
- protected function setUp(): void
- {
- $this->converter = new SemverConverter();
- }
-
- protected function tearDown(): void
- {
- $this->converter = null;
- }
-
- /**
- * @dataProvider getTestVersions
- */
- public function testConverter(string|null $semver, string $composer): void
- {
- $this->assertEquals($composer, $this->converter->convertVersion($semver));
-
- if (!\ctype_alpha((string) $semver) && !\in_array($semver, [null, ''], true)) {
- $this->assertEquals('v' . $composer, $this->converter->convertVersion('v' . $semver));
- }
- }
-
public static function getTestVersions(): array
{
return [
@@ -100,4 +64,32 @@ public static function getTestVersions(): array
['', '*'],
];
}
+
+ /**
+ * @dataProvider getTestVersions
+ */
+ public function testConverter(string|null $semver, string $composer): void
+ {
+ self::assertSame(
+ $composer,
+ $this->converter->convertVersion($semver),
+ );
+
+ if (!ctype_alpha((string) $semver) && !in_array($semver, [null, ''], true)) {
+ self::assertSame(
+ 'v' . $composer,
+ $this->converter->convertVersion('v' . $semver),
+ );
+ }
+ }
+
+ protected function setUp(): void
+ {
+ $this->converter = new SemverConverter();
+ }
+
+ protected function tearDown(): void
+ {
+ $this->converter = null;
+ }
}
diff --git a/tests/Event/GetAssetsEventTest.php b/tests/Event/GetAssetsEventTest.php
index d976bb1..b40babf 100644
--- a/tests/Event/GetAssetsEventTest.php
+++ b/tests/Event/GetAssetsEventTest.php
@@ -2,26 +2,10 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Event;
use Foxy\Event\GetAssetsEvent;
-/**
- * Tests for get assets event.
- *
- * @author François Pluchino
- *
- * @internal
- */
final class GetAssetsEventTest extends SolveEvent
{
private array $assets = ['@composer-asset/foo--bar' => 'file:./vendor/foxy/composer-asset/foo/bar'];
@@ -31,30 +15,31 @@ public function getEvent(): GetAssetsEvent
return new GetAssetsEvent($this->assetDir, $this->packages, $this->assets);
}
- public function testHasAsset(): void
- {
- $event = $this->getEvent();
-
- $this->assertTrue($event->hasAsset('@composer-asset/foo--bar'));
- }
-
public function testAddAsset(): void
{
$assetPackageName = '@composer-asset/bar--foo';
$assetPackagePath = 'file:./vendor/foxy/composer-asset/bar/foo';
$event = $this->getEvent();
- $this->assertFalse($event->hasAsset($assetPackageName));
+ self::assertFalse(
+ $event->hasAsset($assetPackageName),
+ );
$event->addAsset($assetPackageName, $assetPackagePath);
- $this->assertTrue($event->hasAsset($assetPackageName));
+ self::assertTrue(
+ $event->hasAsset($assetPackageName),
+ );
}
public function testGetAssets(): void
{
$event = $this->getEvent();
- $this->assertSame($this->assets, $event->getAssets());
+
+ self::assertSame(
+ $this->assets,
+ $event->getAssets(),
+ );
$expectedAssets = [
'@composer-asset/foo--bar' => 'file:./vendor/foxy/composer-asset/foo/bar',
@@ -63,6 +48,18 @@ public function testGetAssets(): void
$event->addAsset('@composer-asset/bar--foo', 'file:./vendor/foxy/composer-asset/bar/foo');
- $this->assertSame($expectedAssets, $event->getAssets());
+ self::assertSame(
+ $expectedAssets,
+ $event->getAssets(),
+ );
+ }
+
+ public function testHasAsset(): void
+ {
+ $event = $this->getEvent();
+
+ self::assertTrue(
+ $event->hasAsset('@composer-asset/foo--bar'),
+ );
}
}
diff --git a/tests/Event/PostSolveEventTest.php b/tests/Event/PostSolveEventTest.php
index 96a4c1c..8400d4f 100644
--- a/tests/Event/PostSolveEventTest.php
+++ b/tests/Event/PostSolveEventTest.php
@@ -2,26 +2,10 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Event;
use Foxy\Event\PostSolveEvent;
-/**
- * Tests for post solve event.
- *
- * @author François Pluchino
- *
- * @internal
- */
final class PostSolveEventTest extends SolveEvent
{
public function getEvent(): PostSolveEvent
@@ -33,6 +17,9 @@ public function testGetRunResult(): void
{
$event = $this->getEvent();
- $this->assertSame(42, $event->getRunResult());
+ self::assertSame(
+ 42,
+ $event->getRunResult(),
+ );
}
}
diff --git a/tests/Event/PreSolveEventTest.php b/tests/Event/PreSolveEventTest.php
index 5e5eef1..9ad55b7 100644
--- a/tests/Event/PreSolveEventTest.php
+++ b/tests/Event/PreSolveEventTest.php
@@ -2,26 +2,10 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Event;
use Foxy\Event\PreSolveEvent;
-/**
- * Tests for pre solve event.
- *
- * @author François Pluchino
- *
- * @internal
- */
final class PreSolveEventTest extends SolveEvent
{
public function getEvent(): PreSolveEvent
diff --git a/tests/Event/SolveEvent.php b/tests/Event/SolveEvent.php
index d1baec2..add9977 100644
--- a/tests/Event/SolveEvent.php
+++ b/tests/Event/SolveEvent.php
@@ -2,61 +2,52 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Event;
use Composer\Package\PackageInterface;
use Foxy\Event\AbstractSolveEvent;
+use PHPUnit\Framework\MockObject\Exception;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
+
+use const DIRECTORY_SEPARATOR;
-/**
- * Tests for solve events.
- *
- * @author François Pluchino
- */
-abstract class SolveEvent extends \PHPUnit\Framework\TestCase
+abstract class SolveEvent extends TestCase
{
protected string $assetDir = '';
protected PackageInterface|MockObject|array|null $packages = null;
- protected function setUp(): void
- {
- $this->assetDir = sys_get_temp_dir() . \DIRECTORY_SEPARATOR . uniqid('foxy_event_test_', true);
- $this->packages = [$this->createMock(PackageInterface::class)];
- }
-
- protected function tearDown(): void
- {
- $this->assetDir = '';
- $this->packages = null;
- }
-
/**
* Get the event instance.
- *
- * @return AbstractSolveEvent
*/
- abstract public function getEvent();
+ abstract public function getEvent(): AbstractSolveEvent;
public function testGetAssetDir(): void
{
$event = $this->getEvent();
- $this->assertSame($this->assetDir, $event->getAssetDir());
+ self::assertSame($this->assetDir, $event->getAssetDir());
}
public function testGetPackages(): void
{
$event = $this->getEvent();
- $this->assertSame($this->packages, $event->getPackages());
+ self::assertSame($this->packages, $event->getPackages());
+ }
+
+ /**
+ * @throws Exception
+ */
+ protected function setUp(): void
+ {
+ $this->assetDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('foxy_event_test_', true);
+ $this->packages = [$this->createMock(PackageInterface::class)];
+ }
+
+ protected function tearDown(): void
+ {
+ $this->assetDir = '';
+ $this->packages = null;
}
}
diff --git a/tests/Fallback/AssetFallbackTest.php b/tests/Fallback/AssetFallbackTest.php
index 12871b1..15dde15 100644
--- a/tests/Fallback/AssetFallbackTest.php
+++ b/tests/Fallback/AssetFallbackTest.php
@@ -2,15 +2,6 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Fallback;
use Composer\IO\IOInterface;
@@ -19,56 +10,27 @@
use Foxy\Exception\RuntimeException;
use Foxy\Fallback\AssetFallback;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
use Xepozz\InternalMocker\MockerState;
-/**
- * Tests for composer fallback.
- *
- * @author François Pluchino
- *
- * @internal
- */
-final class AssetFallbackTest extends \PHPUnit\Framework\TestCase
+use function chdir;
+use function file_put_contents;
+
+use const DIRECTORY_SEPARATOR;
+
+final class AssetFallbackTest extends TestCase
{
protected AssetFallback|null $assetFallback = null;
private Config|null $config = null;
- private IOInterface|MockObject|null $io = null;
+ private string|null $cwd = '';
private Filesystem|MockObject|null $fs = null;
- private \Symfony\Component\Filesystem\Filesystem|null $sfs = null;
+ private IOInterface|MockObject|null $io = null;
private string|null $oldCwd = '';
- private string|null $cwd = '';
-
- protected function setUp(): void
- {
- parent::setUp();
-
- $this->oldCwd = getcwd();
- $this->cwd = sys_get_temp_dir() . \DIRECTORY_SEPARATOR . uniqid('foxy_asset_fallback_test_', true);
- $this->config = new Config(['fallback-asset' => true]);
- $this->io = $this->createMock(IOInterface::class);
- $this->fs = $this->createMock(Filesystem::class);
- $this->sfs = new \Symfony\Component\Filesystem\Filesystem();
- $this->sfs->mkdir($this->cwd);
-
- \chdir($this->cwd);
-
- $this->assetFallback = new AssetFallback($this->io, $this->config, 'package.json', $this->fs);
- }
+ private \Symfony\Component\Filesystem\Filesystem|null $sfs = null;
- protected function tearDown(): void
+ public static function getRestoreData(): array
{
- parent::tearDown();
-
- \chdir($this->oldCwd);
-
- $this->sfs->remove($this->cwd);
- $this->config = null;
- $this->io = null;
- $this->fs = null;
- $this->sfs = null;
- $this->assetFallback = null;
- $this->oldCwd = null;
- $this->cwd = null;
+ return [[true], [false]];
}
public static function getSaveData(): array
@@ -77,30 +39,81 @@ public static function getSaveData(): array
}
/**
- * @dataProvider getSaveData
+ * @dataProvider getRestoreData
*/
- public function testSave(bool $withPackageFile): void
+ public function testRestore(bool $withPackageFile): void
{
+ $content = '{}';
+ $path = $this->cwd . '/package.json';
+
if ($withPackageFile) {
- \file_put_contents($this->cwd . '/package.json', '{}');
+ file_put_contents($path, $content);
}
- $this->assertInstanceOf(AssetFallback::class, $this->assetFallback->save());
+ $this->io->expects(self::once())->method('write');
+
+ $this->fs->expects(self::once())->method('remove')->with('package.json');
+
+ $this->assetFallback->save();
+ $this->assetFallback->restore();
+
+ if ($withPackageFile) {
+ self::assertFileExists($path);
+ self::assertSame($content, file_get_contents($path));
+ } else {
+ self::assertFileDoesNotExist($path);
+ }
}
- public function testSaveThrowsWhenFileCannotBeRead(): void
+ public function testRestoreThrowsWhenRemoveFails(): void
{
$path = $this->cwd . '/package.json';
+ file_put_contents($path, '{}');
- \file_put_contents($path, '{}');
- $this->assertFileExists($path);
+ $this->io->expects(self::once())->method('write');
- MockerState::addCondition('Foxy\\Fallback', 'file_get_contents', ['package.json', false, null, 0, null], false);
+ $this->fs
+ ->expects(self::once())
+ ->method('remove')
+ ->with('package.json')
+ ->willThrowException(new RuntimeException('Remove failed.'));
+
+ $this->assetFallback->save();
$this->expectException(RuntimeException::class);
- $this->expectExceptionMessage('Unable to read fallback asset file "package.json".');
+ $this->expectExceptionMessage('Unable to remove fallback asset file "package.json".');
+
+ try {
+ $this->assetFallback->restore();
+ } catch (RuntimeException $exception) {
+ $previous = $exception->getPrevious();
+
+ self::assertInstanceOf(\RuntimeException::class, $previous);
+ self::assertSame('Remove failed.', $previous->getMessage());
+
+ throw $exception;
+ }
+ }
+
+ public function testRestoreThrowsWhenWriteFails(): void
+ {
+ $content = '{}';
+ $path = $this->cwd . '/package.json';
+
+ file_put_contents($path, $content);
+
+ $this->io->expects(self::once())->method('write');
+
+ $this->fs->expects(self::once())->method('remove')->with('package.json');
$this->assetFallback->save();
+
+ MockerState::addCondition('Foxy\\Fallback', 'file_put_contents', ['package.json', $content, 0, null], false);
+
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('Unable to write fallback asset file "package.json".');
+
+ $this->assetFallback->restore();
}
public function testRestoreWithDisableOption(): void
@@ -108,93 +121,70 @@ public function testRestoreWithDisableOption(): void
$config = new Config(['fallback-asset' => false]);
$assetFallback = new AssetFallback($this->io, $config, 'package.json', $this->fs);
- $this->io->expects($this->never())->method('write');
+ $this->io->expects(self::never())->method('write');
- $this->fs->expects($this->never())->method('remove');
+ $this->fs->expects(self::never())->method('remove');
$assetFallback->restore();
}
- public static function getRestoreData(): array
- {
- return [[true], [false]];
- }
-
/**
- * @dataProvider getRestoreData
+ * @dataProvider getSaveData
*/
- public function testRestore(bool $withPackageFile): void
+ public function testSave(bool $withPackageFile): void
{
- $content = '{}';
- $path = $this->cwd . '/package.json';
-
if ($withPackageFile) {
- file_put_contents($path, $content);
+ file_put_contents($this->cwd . '/package.json', '{}');
}
- $this->io->expects($this->once())->method('write');
-
- $this->fs->expects($this->once())->method('remove')->with('package.json');
-
- $this->assetFallback->save();
- $this->assetFallback->restore();
-
- if ($withPackageFile) {
- $this->assertFileExists($path);
- $this->assertSame($content, file_get_contents($path));
- } else {
- $this->assertFileDoesNotExist($path);
- }
+ self::assertInstanceOf(AssetFallback::class, $this->assetFallback->save());
}
- public function testRestoreThrowsWhenWriteFails(): void
+ public function testSaveThrowsWhenFileCannotBeRead(): void
{
- $content = '{}';
$path = $this->cwd . '/package.json';
- \file_put_contents($path, $content);
-
- $this->io->expects($this->once())->method('write');
-
- $this->fs->expects($this->once())->method('remove')->with('package.json');
+ file_put_contents($path, '{}');
+ self::assertFileExists($path);
- $this->assetFallback->save();
-
- MockerState::addCondition('Foxy\\Fallback', 'file_put_contents', ['package.json', $content, 0, null], false);
+ MockerState::addCondition('Foxy\\Fallback', 'file_get_contents', ['package.json', false, null, 0, null], false);
$this->expectException(RuntimeException::class);
- $this->expectExceptionMessage('Unable to write fallback asset file "package.json".');
+ $this->expectExceptionMessage('Unable to read fallback asset file "package.json".');
- $this->assetFallback->restore();
+ $this->assetFallback->save();
}
- public function testRestoreThrowsWhenRemoveFails(): void
+ protected function setUp(): void
{
- $path = $this->cwd . '/package.json';
- \file_put_contents($path, '{}');
-
- $this->io->expects($this->once())->method('write');
+ parent::setUp();
- $this->fs
- ->expects($this->once())
- ->method('remove')
- ->with('package.json')
- ->willThrowException(new \RuntimeException('Remove failed.'));
+ $this->oldCwd = getcwd();
+ $this->cwd = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('foxy_asset_fallback_test_', true);
+ $this->config = new Config(['fallback-asset' => true]);
+ $this->io = $this->createMock(IOInterface::class);
+ $this->fs = $this->createMock(Filesystem::class);
+ $this->sfs = new \Symfony\Component\Filesystem\Filesystem();
+ $this->sfs->mkdir($this->cwd);
- $this->assetFallback->save();
+ chdir($this->cwd);
- $this->expectException(RuntimeException::class);
- $this->expectExceptionMessage('Unable to remove fallback asset file "package.json".');
+ $this->assetFallback = new AssetFallback($this->io, $this->config, 'package.json', $this->fs);
+ }
- try {
- $this->assetFallback->restore();
- } catch (RuntimeException $exception) {
- $previous = $exception->getPrevious();
+ protected function tearDown(): void
+ {
+ parent::tearDown();
- $this->assertInstanceOf(\RuntimeException::class, $previous);
- $this->assertSame('Remove failed.', $previous->getMessage());
+ chdir($this->oldCwd);
- throw $exception;
- }
+ $this->sfs->remove($this->cwd);
+ $this->config = null;
+ $this->io = null;
+ $this->fs = null;
+ $this->sfs = null;
+ $this->assetFallback = null;
+ $this->oldCwd = null;
+ $this->cwd = null;
}
}
diff --git a/tests/Fallback/ComposerFallbackTest.php b/tests/Fallback/ComposerFallbackTest.php
index 2b5ae87..fe6a1f1 100644
--- a/tests/Fallback/ComposerFallbackTest.php
+++ b/tests/Fallback/ComposerFallbackTest.php
@@ -2,15 +2,6 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Fallback;
use Composer\Composer;
@@ -20,81 +11,37 @@
use Composer\IO\IOInterface;
use Composer\Repository\RepositoryManager;
use Composer\Util\Filesystem;
+use Exception;
use Foxy\Config\Config;
use Foxy\Fallback\ComposerFallback;
use Foxy\Util\LockerUtil;
+use JsonException;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Input\InputInterface;
-/**
- * Tests for composer fallback.
- *
- * @author François Pluchino
- *
- * @internal
- */
-final class ComposerFallbackTest extends \PHPUnit\Framework\TestCase
+use function chdir;
+use function count;
+use function file_put_contents;
+
+use const DIRECTORY_SEPARATOR;
+
+final class ComposerFallbackTest extends TestCase
{
- private Config|null $config = null;
private Composer|MockObject|null $composer = null;
- private IOInterface|MockObject|null $io = null;
- private InputInterface|MockObject|null $input = null;
+ private ComposerFallback|null $composerFallback = null;
+ private Config|null $config = null;
+ private string|null $cwd = '';
private Filesystem|MockObject|null $fs = null;
+ private InputInterface|MockObject|null $input = null;
private Installer|MockObject|null $installer = null;
- private \Symfony\Component\Filesystem\Filesystem|null $sfs = null;
+ private IOInterface|MockObject|null $io = null;
private string|null $oldCwd = '';
- private string|null $cwd = '';
- private ComposerFallback|null $composerFallback = null;
-
- protected function setUp(): void
- {
- parent::setUp();
-
- $this->oldCwd = getcwd();
- $this->cwd = sys_get_temp_dir() . \DIRECTORY_SEPARATOR . uniqid('foxy_composer_fallback_test_', true);
- $this->config = new Config(['fallback-composer' => true]);
- $this->composer = $this->createMock(Composer::class);
- $this->io = $this->createMock(IOInterface::class);
- $this->input = $this->createMock(InputInterface::class);
- $this->fs = $this->createMock(Filesystem::class);
- /** @var Installer|MockObject */
- $this->installer = $this
- ->getMockBuilder(Installer::class)
- ->disableOriginalConstructor()
- ->onlyMethods(['run'])
- ->getMock();
- $this->sfs = new \Symfony\Component\Filesystem\Filesystem();
- $this->sfs->mkdir($this->cwd);
-
- \chdir($this->cwd);
-
- $this->composerFallback = new ComposerFallback(
- $this->composer,
- $this->io,
- $this->config,
- $this->input,
- $this->fs,
- $this->installer
- );
- }
+ private \Symfony\Component\Filesystem\Filesystem|null $sfs = null;
- protected function tearDown(): void
+ public static function getRestoreData(): array
{
- parent::tearDown();
-
- \chdir($this->oldCwd);
-
- $this->sfs->remove($this->cwd);
- $this->config = null;
- $this->composer = null;
- $this->io = null;
- $this->input = null;
- $this->fs = null;
- $this->installer = null;
- $this->sfs = null;
- $this->composerFallback = null;
- $this->oldCwd = null;
- $this->cwd = null;
+ return [[[]], [[['name' => 'foo/bar', 'version' => '1.0.0.0']]]];
}
public static function getSaveData(): array
@@ -102,45 +49,10 @@ public static function getSaveData(): array
return [[true], [false]];
}
- /**
- * @dataProvider getSaveData
- */
- public function testSave(bool $withLockFile): void
- {
- $rm = $this->createMock(RepositoryManager::class);
-
- $this->composer->expects($this->any())->method('getRepositoryManager')->willReturn($rm);
-
- $im = $this->createMock(InstallationManager::class);
-
- $this->composer->expects($this->any())->method('getInstallationManager')->willReturn($im);
-
- \file_put_contents($this->cwd . '/composer.json', '{}');
-
- if ($withLockFile) {
- \file_put_contents($this->cwd . '/composer.lock', json_encode(['content-hash' => 'HASH_VALUE']));
- }
-
- $this->assertInstanceOf(ComposerFallback::class, $this->composerFallback->save());
- }
-
- public function testRestoreWithDisableOption(): void
- {
- $config = new Config(['fallback-composer' => false]);
- $composerFallback = new ComposerFallback($this->composer, $this->io, $config, $this->input);
-
- $this->io->expects($this->never())->method('write');
-
- $composerFallback->restore();
- }
-
- public static function getRestoreData(): array
- {
- return [[[]], [[['name' => 'foo/bar', 'version' => '1.0.0.0']]]];
- }
-
/**
* @dataProvider getRestoreData
+ *
+ * @throws Exception|JsonException
*/
public function testRestore(array $packages): void
{
@@ -149,8 +61,8 @@ public function testRestore(array $packages): void
$lockFile = 'composer.lock';
$vendorDir = $this->cwd . '/vendor/';
- \file_put_contents($this->cwd . '/' . $composerFile, $composerContent);
- \file_put_contents(
+ file_put_contents($this->cwd . '/' . $composerFile, $composerContent);
+ file_put_contents(
$this->cwd . '/' . $lockFile,
json_encode(
[
@@ -158,52 +70,143 @@ public function testRestore(array $packages): void
'packages' => $packages,
'packages-dev' => [],
'prefer-stable' => true,
- ]
- )
+ ],
+ JSON_THROW_ON_ERROR,
+ ),
);
$this->input
- ->expects($this->any())
+ ->expects(self::any())
->method('getOption')
- ->willReturnCallback(fn ($option) => 'verbose' === $option ? false : null);
+ ->willReturnCallback(fn($option): bool|null => 'verbose' === $option ? false : null);
$ed = $this->createMock(EventDispatcher::class);
- $this->composer->expects($this->any())->method('getEventDispatcher')->willReturn($ed);
+ $this->composer->expects(self::any())->method('getEventDispatcher')->willReturn($ed);
$rm = $this->createMock(RepositoryManager::class);
- $this->composer->expects($this->any())->method('getRepositoryManager')->willReturn($rm);
+ $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($rm);
$im = $this->createMock(InstallationManager::class);
- $this->composer->expects($this->any())->method('getInstallationManager')->willReturn($im);
- $this->io->expects($this->once())->method('write');
+ $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($im);
+ $this->io->expects(self::once())->method('write');
$locker = LockerUtil::getLocker($this->io, $im, $composerFile);
- $this->composer->expects($this->atLeastOnce())->method('getLocker')->willReturn($locker);
+ $this->composer->expects(self::atLeastOnce())->method('getLocker')->willReturn($locker);
$config = $this->getMockBuilder(\Composer\Config::class)
->disableOriginalConstructor()
->onlyMethods(['get'])
->getMock();
- $this->composer->expects($this->atLeastOnce())->method('getConfig')->willReturn($config);
+ $this->composer->expects(self::atLeastOnce())->method('getConfig')->willReturn($config);
$config
- ->expects($this->atLeastOnce())
+ ->expects(self::atLeastOnce())
->method('get')
- ->willReturnCallback(fn ($key, $default = null) => 'vendor-dir' === $key ? $vendorDir : $default);
+ ->willReturnCallback(fn($key, $default = null) => 'vendor-dir' === $key ? $vendorDir : $default);
- if (0 === \count($packages)) {
- $this->fs->expects($this->once())->method('remove')->with($vendorDir);
+ if (0 === count($packages)) {
+ $this->fs->expects(self::once())->method('remove')->with($vendorDir);
} else {
- $this->fs->expects($this->never())->method('remove');
- $this->installer->expects($this->once())->method('run');
+ $this->fs->expects(self::never())->method('remove');
+ $this->installer->expects(self::once())->method('run');
}
$this->composerFallback->save();
$this->composerFallback->restore();
}
+
+ /**
+ * @throws Exception
+ */
+ public function testRestoreWithDisableOption(): void
+ {
+ $config = new Config(['fallback-composer' => false]);
+ $composerFallback = new ComposerFallback($this->composer, $this->io, $config, $this->input);
+
+ $this->io->expects(self::never())->method('write');
+
+ $composerFallback->restore();
+ }
+
+ /**
+ * @dataProvider getSaveData
+ *
+ * @throws JsonException
+ */
+ public function testSave(bool $withLockFile): void
+ {
+ $rm = $this->createMock(RepositoryManager::class);
+
+ $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($rm);
+
+ $im = $this->createMock(InstallationManager::class);
+
+ $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($im);
+
+ file_put_contents($this->cwd . '/composer.json', '{}');
+
+ if ($withLockFile) {
+ file_put_contents(
+ "{$this->cwd}/composer.lock",
+ json_encode(['content-hash' => 'HASH_VALUE'], JSON_THROW_ON_ERROR),
+ );
+ }
+
+ self::assertInstanceOf(ComposerFallback::class, $this->composerFallback->save());
+ }
+
+ protected function setUp(): void
+ {
+ parent::setUp();
+
+ $this->oldCwd = getcwd();
+ $this->cwd = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('foxy_composer_fallback_test_', true);
+ $this->config = new Config(['fallback-composer' => true]);
+ $this->composer = $this->createMock(Composer::class);
+ $this->io = $this->createMock(IOInterface::class);
+ $this->input = $this->createMock(InputInterface::class);
+ $this->fs = $this->createMock(Filesystem::class);
+ $this->installer = $this
+ ->getMockBuilder(Installer::class)
+ ->disableOriginalConstructor()
+ ->onlyMethods(['run'])
+ ->getMock();
+ $this->sfs = new \Symfony\Component\Filesystem\Filesystem();
+ $this->sfs->mkdir($this->cwd);
+
+ chdir($this->cwd);
+
+ $this->composerFallback = new ComposerFallback(
+ $this->composer,
+ $this->io,
+ $this->config,
+ $this->input,
+ $this->fs,
+ $this->installer,
+ );
+ }
+
+ protected function tearDown(): void
+ {
+ parent::tearDown();
+
+ chdir($this->oldCwd);
+
+ $this->sfs->remove($this->cwd);
+ $this->config = null;
+ $this->composer = null;
+ $this->io = null;
+ $this->input = null;
+ $this->fs = null;
+ $this->installer = null;
+ $this->sfs = null;
+ $this->composerFallback = null;
+ $this->oldCwd = null;
+ $this->cwd = null;
+ }
}
diff --git a/tests/Fixtures/Asset/StubAssetManager.php b/tests/Fixtures/Asset/StubAssetManager.php
index 1dade63..a449081 100644
--- a/tests/Fixtures/Asset/StubAssetManager.php
+++ b/tests/Fixtures/Asset/StubAssetManager.php
@@ -6,38 +6,34 @@
use Composer\IO\IOInterface;
use Composer\Package\RootPackageInterface;
-use Composer\Util\Filesystem;
-use Composer\Util\ProcessExecutor;
-use Foxy\Asset\AssetManagerInterface;
-use Foxy\Asset\AssetPackageInterface;
+use Composer\Util\{Filesystem, ProcessExecutor};
+use Foxy\Asset\{AssetManagerInterface, AssetPackageInterface};
use Foxy\Config\Config;
+use Foxy\Exception\RuntimeException;
use Foxy\Fallback\FallbackInterface;
-use RuntimeException;
-
-/**
- * Stub of AssetManagerInterface for tests.
- *
- * @copyright Copyright (C) 2026 Terabytesoftw.
- * @license https://opensource.org/license/mit/ MIT License
- */
+
final class StubAssetManager implements AssetManagerInterface
{
public function __construct(
IOInterface $io,
Config $config,
ProcessExecutor $executor,
- Filesystem $fs
- ) {
+ Filesystem $fs,
+ ) {}
+
+ public function addDependencies(RootPackageInterface $rootPackage, array $dependencies): AssetPackageInterface
+ {
+ throw new RuntimeException('Not used in this test.');
}
- public function getName(): string
+ public function getLockPackageName(): string
{
- return 'stub';
+ return 'stub-lock.json';
}
- public function isAvailable(): bool
+ public function getName(): string
{
- return true;
+ return 'stub';
}
public function getPackageName(): string
@@ -50,19 +46,14 @@ public function hasLockFile(): bool
return false;
}
- public function isInstalled(): bool
- {
- return false;
- }
-
- public function setFallback(FallbackInterface $fallback): self
+ public function isAvailable(): bool
{
- return $this;
+ return true;
}
- public function setUpdatable(bool $updatable): self
+ public function isInstalled(): bool
{
- return $this;
+ return false;
}
public function isUpdatable(): bool
@@ -75,22 +66,20 @@ public function isValidForUpdate(): bool
return false;
}
- public function getLockPackageName(): string
+ public function run(): int
{
- return 'stub-lock.json';
+ return 0;
}
- public function validate(): void
+ public function setFallback(FallbackInterface $fallback): self
{
+ return $this;
}
- public function addDependencies(RootPackageInterface $rootPackage, array $dependencies): AssetPackageInterface
+ public function setUpdatable(bool $updatable): self
{
- throw new RuntimeException('Not used in this test.');
+ return $this;
}
- public function run(): int
- {
- return 0;
- }
+ public function validate(): void {}
}
diff --git a/tests/Fixtures/Util/AbstractProcessExecutorMock.php b/tests/Fixtures/Util/AbstractProcessExecutorMock.php
index e193d49..0b26698 100644
--- a/tests/Fixtures/Util/AbstractProcessExecutorMock.php
+++ b/tests/Fixtures/Util/AbstractProcessExecutorMock.php
@@ -2,40 +2,30 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Fixtures\Util;
use Composer\Util\ProcessExecutor;
-/**
- * Mock of ProcessExecutor.
- *
- * @author François Pluchino
- */
+use function count;
+
abstract class AbstractProcessExecutorMock extends ProcessExecutor
{
- /**
- * @var array
- */
- private $expectedValues = [];
+ private array $executedCommands = [];
- /**
- * @var array
- */
- private $executedCommands = [];
+ private array $expectedValues = [];
+
+ private int $position = 0;
/**
- * @var int
+ * @param int $returnedCode The returned code
+ * @param null $output The output
*/
- private $position = 0;
+ public function addExpectedValues(int $returnedCode = 0, $output = null): static
+ {
+ $this->expectedValues[] = [$returnedCode, $output];
+
+ return $this;
+ }
public function doExecute($command, &$output = null, string|null $cwd = null): int
{
@@ -48,94 +38,67 @@ public function doExecute($command, &$output = null, string|null $cwd = null): i
return $returnedCode;
}
- /**
- * @param int $returnedCode The returned code
- * @param null $output The output
- *
- * @return self
- */
- public function addExpectedValues($returnedCode = 0, $output = null)
- {
- $this->expectedValues[] = [$returnedCode, $output];
-
- return $this;
- }
-
/**
* Get the executed command.
*
* @param int $position The position of executed command
- *
- * @return string|null
*/
- public function getExecutedCommand($position)
+ public function getExecutedCommand(int $position): int|string|null
{
return $this->getExecutedValue($position, 0);
}
/**
- * Get the executed returned code.
+ * Get the executed command.
*
* @param int $position The position of executed command
- *
- * @return int|null
*/
- public function getExecutedReturnedCode($position)
+ public function getExecutedOutput(int $position): int|string|null
{
- return $this->getExecutedValue($position, 1);
+ return $this->getExecutedValue($position, 2);
}
/**
- * Get the executed command.
+ * Get the executed returned code.
*
* @param int $position The position of executed command
- *
- * @return string|null
*/
- public function getExecutedOutput($position)
+ public function getExecutedReturnedCode(int $position): int|string|null
{
- return $this->getExecutedValue($position, 2);
+ return $this->getExecutedValue($position, 1);
}
/**
* Get the last executed command.
- *
- * @return string|null
*/
- public function getLastCommand()
+ public function getLastCommand(): int|string|null
{
- return $this->getExecutedCommand(\count($this->executedCommands) - 1);
+ return $this->getExecutedCommand(count($this->executedCommands) - 1);
}
/**
- * Get the last executed returned code.
- *
- * @return int|null
+ * Get the last executed output.
*/
- public function getLastReturnedCode()
+ public function getLastOutput(): int|string|null
{
- return $this->getExecutedReturnedCode(\count($this->executedCommands) - 1);
+ return $this->getExecutedOutput(count($this->executedCommands) - 1);
}
/**
- * Get the last executed output.
- *
- * @return string|null
+ * Get the last executed returned code.
*/
- public function getLastOutput()
+ public function getLastReturnedCode(): int|string|null
{
- return $this->getExecutedOutput(\count($this->executedCommands) - 1);
+ return $this->getExecutedReturnedCode(count($this->executedCommands) - 1);
}
/**
* Get the value of the executed command.
*
* @param int $position The position
- * @param int $index The index of value
- *
- * @return int|string|null
+ * @param int $index The index of value
*/
- private function getExecutedValue($position, int $index)
+ private function getExecutedValue(int $position, int $index): int|string|null
{
return isset($this->executedCommands[$position])
? $this->executedCommands[$position][$index]
diff --git a/tests/Fixtures/Util/ProcessExecutorMock.php b/tests/Fixtures/Util/ProcessExecutorMock.php
index 41ab712..168ba51 100644
--- a/tests/Fixtures/Util/ProcessExecutorMock.php
+++ b/tests/Fixtures/Util/ProcessExecutorMock.php
@@ -2,39 +2,12 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Fixtures\Util;
-use Composer\Composer;
-use Composer\Util\ProcessExecutor;
-
-/*
- * Mock of ProcessExecutor.
- *
- * @author François Pluchino
- */
-if (version_compare(Composer::VERSION, '2.3.0', '<')) {
- class ProcessExecutorMock extends AbstractProcessExecutorMock
- {
- public function execute($command, &$output = null, $cwd = null): int
- {
- return $this->doExecute($command, $output, $cwd);
- }
- }
-} else {
- class ProcessExecutorMock extends AbstractProcessExecutorMock
+class ProcessExecutorMock extends AbstractProcessExecutorMock
+{
+ public function execute($command, &$output = null, string|null $cwd = null): int
{
- public function execute($command, &$output = null, string|null $cwd = null): int
- {
- return $this->doExecute($command, $output, $cwd);
- }
+ return $this->doExecute($command, $output, $cwd);
}
}
diff --git a/tests/Fixtures/Util/ProcessExecutorMockTest.php b/tests/Fixtures/Util/ProcessExecutorMockTest.php
index e01e2cb..b205d08 100644
--- a/tests/Fixtures/Util/ProcessExecutorMockTest.php
+++ b/tests/Fixtures/Util/ProcessExecutorMockTest.php
@@ -2,76 +2,60 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Foxy\Tests\Json;
-
-use Foxy\Tests\Fixtures\Util\ProcessExecutorMock;
-
-/**
- * Tests for the process executor mock.
- *
- * @author François Pluchino
- *
- * @internal
- */
-final class ProcessExecutorMockTest extends \PHPUnit\Framework\TestCase
+namespace Foxy\Tests\Fixtures\Util;
+
+use PHPUnit\Framework\TestCase;
+
+final class ProcessExecutorMockTest extends TestCase
{
- public function testExecuteWithoutExpectedValues(): void
+ public function testExecuteWithExpectedValues(): void
{
$executor = new ProcessExecutorMock();
+ $executor->addExpectedValues(0, 'TEST');
+ $executor->addExpectedValues(42, 'TEST 2');
+
$executor->execute('run', $output);
+ $executor->execute('run2', $output2);
- $this->assertSame('run', $executor->getExecutedCommand(0));
- $this->assertEquals(0, $executor->getExecutedReturnedCode(0));
- $this->assertNull($executor->getExecutedOutput(0));
+ self::assertSame('run', $executor->getExecutedCommand(0));
+ self::assertSame(0, $executor->getExecutedReturnedCode(0));
+ self::assertSame('TEST', $executor->getExecutedOutput(0));
- $this->assertNull($executor->getExecutedCommand(1));
- $this->assertNull($executor->getExecutedReturnedCode(1));
- $this->assertNull($executor->getExecutedOutput(1));
+ self::assertSame('run2', $executor->getExecutedCommand(1));
+ self::assertSame(42, $executor->getExecutedReturnedCode(1));
+ self::assertSame('TEST 2', $executor->getExecutedOutput(1));
- $this->assertSame('run', $executor->getLastCommand());
- $this->assertEquals(0, $executor->getLastReturnedCode());
- $this->assertNull($executor->getLastOutput());
+ self::assertNull($executor->getExecutedCommand(2));
+ self::assertNull($executor->getExecutedReturnedCode(2));
+ self::assertNull($executor->getExecutedOutput(2));
- $this->assertNull($output);
+ self::assertSame('run2', $executor->getLastCommand());
+ self::assertSame(42, $executor->getLastReturnedCode());
+ self::assertSame('TEST 2', $executor->getLastOutput());
+
+ self::assertSame('TEST', $output);
+ self::assertSame('TEST 2', $output2);
}
- public function testExecuteWithExpectedValues(): void
+ public function testExecuteWithoutExpectedValues(): void
{
$executor = new ProcessExecutorMock();
- $executor->addExpectedValues(0, 'TEST');
- $executor->addExpectedValues(42, 'TEST 2');
-
$executor->execute('run', $output);
- $executor->execute('run2', $output2);
-
- $this->assertSame('run', $executor->getExecutedCommand(0));
- $this->assertSame(0, $executor->getExecutedReturnedCode(0));
- $this->assertSame('TEST', $executor->getExecutedOutput(0));
- $this->assertSame('run2', $executor->getExecutedCommand(1));
- $this->assertSame(42, $executor->getExecutedReturnedCode(1));
- $this->assertSame('TEST 2', $executor->getExecutedOutput(1));
+ self::assertSame('run', $executor->getExecutedCommand(0));
+ self::assertEquals(0, $executor->getExecutedReturnedCode(0));
+ self::assertNull($executor->getExecutedOutput(0));
- $this->assertNull($executor->getExecutedCommand(2));
- $this->assertNull($executor->getExecutedReturnedCode(2));
- $this->assertNull($executor->getExecutedOutput(2));
+ self::assertNull($executor->getExecutedCommand(1));
+ self::assertNull($executor->getExecutedReturnedCode(1));
+ self::assertNull($executor->getExecutedOutput(1));
- $this->assertSame('run2', $executor->getLastCommand());
- $this->assertSame(42, $executor->getLastReturnedCode());
- $this->assertSame('TEST 2', $executor->getLastOutput());
+ self::assertSame('run', $executor->getLastCommand());
+ self::assertEquals(0, $executor->getLastReturnedCode());
+ self::assertNull($executor->getLastOutput());
- $this->assertSame('TEST', $output);
- $this->assertSame('TEST 2', $output2);
+ self::assertNull($output);
}
}
diff --git a/tests/Fixtures/Util/ThrowingProcessExecutorMock.php b/tests/Fixtures/Util/ThrowingProcessExecutorMock.php
index f5b8bf1..136e54a 100644
--- a/tests/Fixtures/Util/ThrowingProcessExecutorMock.php
+++ b/tests/Fixtures/Util/ThrowingProcessExecutorMock.php
@@ -2,29 +2,15 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Fixtures\Util;
use Composer\Util\ProcessExecutor;
+use Foxy\Exception\RuntimeException;
-/**
- * Mock of ProcessExecutor that always throws.
- *
- * @copyright Copyright (C) 2026 Terabytesoftw.
- * @license https://opensource.org/license/mit/ MIT License
- */
final class ThrowingProcessExecutorMock extends ProcessExecutor
{
public function execute($command, &$output = null, string|null $cwd = null): int
{
- throw new \RuntimeException('Process execution failed.');
+ throw new RuntimeException('Process execution failed.');
}
}
diff --git a/tests/Fixtures/package/global/theme/foo/bar/package.json b/tests/Fixtures/package/global/theme/foo/bar/package.json
index 2c63c08..0967ef4 100644
--- a/tests/Fixtures/package/global/theme/foo/bar/package.json
+++ b/tests/Fixtures/package/global/theme/foo/bar/package.json
@@ -1,2 +1 @@
-{
-}
+{}
diff --git a/tests/FoxyTest.php b/tests/FoxyTest.php
index dc58bb2..4dc2b5c 100644
--- a/tests/FoxyTest.php
+++ b/tests/FoxyTest.php
@@ -2,118 +2,103 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests;
use Composer\Composer;
use Composer\Config;
use Composer\DependencyResolver\Operation\InstallOperation;
-use Composer\Installer\InstallationManager;
-use Composer\Installer\PackageEvent;
+use Composer\Installer\{InstallationManager, PackageEvent};
use Composer\IO\IOInterface;
-use Composer\Package\Package;
-use Composer\Package\RootPackageInterface;
+use Composer\Package\{Package, RootPackageInterface};
use Composer\Repository\RepositoryManager;
use Composer\Script\Event;
+use Foxy\Exception\RuntimeException;
+use Foxy\Fallback\AssetFallback;
use Foxy\Foxy;
use Foxy\Solver\SolverInterface;
use Foxy\Tests\Fixtures\Asset\StubAssetManager;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
+use ReflectionClass;
+use ReflectionException;
+use Seld\JsonLint\ParsingException;
+
+use function getcwd;
use const PHP_VERSION_ID;
-final class FoxyTest extends \PHPUnit\Framework\TestCase
+final class FoxyTest extends TestCase
{
private Composer|MockObject $composer;
private Config $composerConfig;
private IOInterface $io;
private RootPackageInterface|MockObject $package;
- protected function setUp(): void
- {
- $this->composer = $this->createMock(Composer::class);
- $this->composerConfig = $this->createMock(Config::class);
- $this->io = $this->createMock(IOInterface::class);
- $this->package = $this->createMock(RootPackageInterface::class);
-
- $this->composer
- ->expects($this->any())
- ->method('getPackage')
- ->willReturn($this->package);
-
- $this->composer
- ->expects($this->any())
- ->method('getConfig')
- ->willReturn($this->composerConfig);
-
- $rm = $this->createMock(RepositoryManager::class);
-
- $this->composer
- ->expects($this->any())
- ->method('getRepositoryManager')
- ->willReturn($rm);
-
- $im = $this->createMock(InstallationManager::class);
-
- $this->composer
- ->expects($this->any())
- ->method('getInstallationManager')
- ->willReturn($im)
- ;
- }
-
- public function testGetSubscribedEvents(): void
+ public static function getSolveAssetsData(): array
{
- $this->assertCount(4, Foxy::getSubscribedEvents());
+ return [['solve_event_install', false], ['solve_event_update', true]];
}
+ /**
+ * @throws ParsingException
+ */
public function testActivate(): void
{
$foxy = new Foxy();
$foxy->activate($this->composer, $this->io);
$foxy->init();
- $this->assertTrue(true);
+ self::assertTrue(true);
}
- public function testDeactivate(): void
+ /**
+ * @throws ParsingException
+ */
+ public function testActivateBuildsAssetFallbackWithResolvedRootPackagePath(): void
{
+ $this->package
+ ->expects(self::any())
+ ->method('getConfig')
+ ->willReturn(['foxy' => ['manager' => 'npm', 'root-package-json-dir' => 'root-package']]);
+
$foxy = new Foxy();
- $foxy->deactivate($this->composer, $this->io);
+ $foxy->activate($this->composer, $this->io);
- $this->assertTrue(true);
- }
+ $foxyReflection = new ReflectionClass($foxy);
+ $assetFallbackProperty = $foxyReflection->getProperty('assetFallback');
+ $assetFallback = $assetFallbackProperty->getValue($foxy);
- public function testUninstall(): void
- {
- $foxy = new Foxy();
- $foxy->uninstall($this->composer, $this->io);
+ self::assertInstanceOf(AssetFallback::class, $assetFallback);
- $this->assertTrue(true);
+ $fallbackReflection = new ReflectionClass($assetFallback);
+
+ $pathProperty = $fallbackReflection->getProperty('path');
+ $expectedPath = rtrim((string) getcwd(), '/\\')
+ . DIRECTORY_SEPARATOR
+ . 'root-package'
+ . DIRECTORY_SEPARATOR
+ . 'package.json';
+
+ self::assertSame($expectedPath, $pathProperty->getValue($assetFallback));
}
+ /**
+ * @throws ParsingException
+ */
public function testActivateOnInstall(): void
{
$package = $this->createMock(Package::class);
- $package->expects($this->once())->method('getName')->willReturn('php-forge/foxy');
+ $package->expects(self::once())->method('getName')->willReturn('php-forge/foxy');
$operation = $this->createMock(InstallOperation::class);
- $operation->expects($this->once())->method('getPackage')->willReturn($package);
+ $operation->expects(self::once())->method('getPackage')->willReturn($package);
/** @var MockObject|PackageEvent $event */
$event = $this->createMock(PackageEvent::class);
- $event->expects($this->once())->method('getOperation')->willReturn($operation);
+ $event->expects(self::once())->method('getOperation')->willReturn($operation);
$foxy = new Foxy();
@@ -121,69 +106,20 @@ public function testActivateOnInstall(): void
$foxy->initOnInstall($event);
}
- public function testActivateWithInvalidManager(): void
- {
- $this->expectException(\Foxy\Exception\RuntimeException::class);
- $this->expectExceptionMessage('The asset manager "invalid_manager" doesn\'t exist');
-
- $this->package
- ->expects($this->any())
- ->method('getConfig')
- ->willReturn(['foxy' => ['manager' => 'invalid_manager']]);
-
- $foxy = new Foxy();
- $foxy->activate($this->composer, $this->io);
- }
-
- public function testActivateBuildsAssetFallbackWithResolvedRootPackagePath(): void
- {
- $this->package
- ->expects($this->any())
- ->method('getConfig')
- ->willReturn(['foxy' => ['manager' => 'npm', 'root-package-json-dir' => 'root-package']]);
-
- $foxy = new Foxy();
- $foxy->activate($this->composer, $this->io);
-
- $foxyReflection = new \ReflectionClass($foxy);
- $assetFallbackProperty = $foxyReflection->getProperty('assetFallback');
-
- if (PHP_VERSION_ID < 80500) {
- $assetFallbackProperty->setAccessible(true);
- }
-
- $assetFallback = $assetFallbackProperty->getValue($foxy);
-
- $this->assertInstanceOf(\Foxy\Fallback\AssetFallback::class, $assetFallback);
-
- $fallbackReflection = new \ReflectionClass($assetFallback);
- $pathProperty = $fallbackReflection->getProperty('path');
-
- if (PHP_VERSION_ID < 80500) {
- $pathProperty->setAccessible(true);
- }
-
- $expectedPath = rtrim((string) \getcwd(), '/\\')
- . DIRECTORY_SEPARATOR
- . 'root-package'
- . DIRECTORY_SEPARATOR
- . 'package.json';
-
- $this->assertSame($expectedPath, $pathProperty->getValue($assetFallback));
- }
-
+ /**
+ * @throws ParsingException|ReflectionException
+ */
public function testActivateUsesPackageNameForNonAbstractAssetManager(): void
{
$this->package
- ->expects($this->any())
+ ->expects(self::any())
->method('getConfig')
->willReturn(['foxy' => ['manager' => 'stub']]);
- $foxyReflection = new \ReflectionClass(Foxy::class);
+ $foxyReflection = new ReflectionClass(Foxy::class);
$assetManagersProperty = $foxyReflection->getProperty('assetManagers');
if (PHP_VERSION_ID < 80500) {
- $assetManagersProperty->setAccessible(true);
}
$originalAssetManagers = $assetManagersProperty->getValue();
@@ -196,28 +132,48 @@ public function testActivateUsesPackageNameForNonAbstractAssetManager(): void
$assetFallbackProperty = $foxyReflection->getProperty('assetFallback');
if (PHP_VERSION_ID < 80500) {
- $assetFallbackProperty->setAccessible(true);
}
$assetFallback = $assetFallbackProperty->getValue($foxy);
- $fallbackReflection = new \ReflectionClass($assetFallback);
+ $fallbackReflection = new ReflectionClass($assetFallback);
$pathProperty = $fallbackReflection->getProperty('path');
- if (PHP_VERSION_ID < 80500) {
- $pathProperty->setAccessible(true);
- }
-
- $this->assertSame('stub-package.json', $pathProperty->getValue($assetFallback));
+ self::assertSame('stub-package.json', $pathProperty->getValue($assetFallback));
} finally {
$assetManagersProperty->setValue(null, $originalAssetManagers);
}
}
- public static function getSolveAssetsData(): array
+ /**
+ * @throws ParsingException
+ */
+ public function testActivateWithInvalidManager(): void
{
- return [['solve_event_install', false], ['solve_event_update', true]];
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('The asset manager "invalid_manager" doesn\'t exist');
+
+ $this->package
+ ->expects(self::any())
+ ->method('getConfig')
+ ->willReturn(['foxy' => ['manager' => 'invalid_manager']]);
+
+ $foxy = new Foxy();
+ $foxy->activate($this->composer, $this->io);
+ }
+
+ public function testDeactivate(): void
+ {
+ $foxy = new Foxy();
+ $foxy->deactivate($this->composer, $this->io);
+
+ self::assertTrue(true);
+ }
+
+ public function testGetSubscribedEvents(): void
+ {
+ self::assertCount(4, Foxy::getSubscribedEvents());
}
/**
@@ -230,12 +186,53 @@ public function testSolveAssets(string $eventName, bool $expectedUpdatable): voi
/** @var MockObject|SolverInterface $solver */
$solver = $this->createMock(SolverInterface::class);
- $solver->expects($this->once())->method('setUpdatable')->with($expectedUpdatable);
- $solver->expects($this->once())->method('solve')->with($this->composer, $this->io);
+ $solver->expects(self::once())->method('setUpdatable')->with($expectedUpdatable);
+ $solver->expects(self::once())->method('solve')->with($this->composer, $this->io);
$foxy = new Foxy();
$foxy->setSolver($solver);
$foxy->solveAssets($event);
}
+
+ public function testUninstall(): void
+ {
+ $foxy = new Foxy();
+ $foxy->uninstall($this->composer, $this->io);
+
+ self::assertTrue(true);
+ }
+
+ protected function setUp(): void
+ {
+ $this->composer = $this->createMock(Composer::class);
+ $this->composerConfig = $this->createMock(Config::class);
+ $this->io = $this->createMock(IOInterface::class);
+ $this->package = $this->createMock(RootPackageInterface::class);
+
+ $this->composer
+ ->expects(self::any())
+ ->method('getPackage')
+ ->willReturn($this->package);
+
+ $this->composer
+ ->expects(self::any())
+ ->method('getConfig')
+ ->willReturn($this->composerConfig);
+
+ $rm = $this->createMock(RepositoryManager::class);
+
+ $this->composer
+ ->expects(self::any())
+ ->method('getRepositoryManager')
+ ->willReturn($rm);
+
+ $im = $this->createMock(InstallationManager::class);
+
+ $this->composer
+ ->expects(self::any())
+ ->method('getInstallationManager')
+ ->willReturn($im)
+ ;
+ }
}
diff --git a/tests/Json/JsonFileTest.php b/tests/Json/JsonFileTest.php
index f4d6ca6..f041ca2 100644
--- a/tests/Json/JsonFileTest.php
+++ b/tests/Json/JsonFileTest.php
@@ -2,66 +2,44 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Json;
+use Exception;
use Foxy\Exception\RuntimeException;
use Foxy\Json\JsonFile;
-use PHPForge\Support\Assert;
+use PHPForge\Support\LineEndingNormalizer;
+use PHPUnit\Framework\TestCase;
+use Seld\JsonLint\ParsingException;
use Symfony\Component\Filesystem\Filesystem;
use Xepozz\InternalMocker\MockerState;
-/**
- * Tests for json file.
- *
- * @author François Pluchino
- *
- * @internal
- */
-final class JsonFileTest extends \PHPUnit\Framework\TestCase
+use function chdir;
+use function file_get_contents;
+
+use const DIRECTORY_SEPARATOR;
+
+final class JsonFileTest extends TestCase
{
- private Filesystem|null $sfs = null;
- private string|null $oldCwd = '';
private string|null $cwd = '';
+ private string|null $oldCwd = '';
+ private Filesystem|null $sfs = null;
- protected function setUp(): void
+ public function testGetArrayKeysThrowsWhenFileCannotBeRead(): void
{
- parent::setUp();
-
- $this->oldCwd = getcwd();
- $this->cwd = sys_get_temp_dir() . \DIRECTORY_SEPARATOR . uniqid('foxy_asset_json_file_test_', true);
- $this->sfs = new Filesystem();
- $this->sfs->mkdir($this->cwd);
-
- \chdir($this->cwd);
- }
+ $filename = './package.json';
- protected function tearDown(): void
- {
- parent::tearDown();
+ file_put_contents($filename, '{}');
- \chdir($this->oldCwd);
+ self::assertFileExists($filename);
- $this->sfs->remove($this->cwd);
- $this->sfs = null;
- $this->oldCwd = null;
- $this->cwd = null;
- }
+ MockerState::addCondition('Foxy\\Json', 'file_get_contents', [$filename, false, null, 0, null], false);
- public function testGetArrayKeysWithoutFile(): void
- {
- $filename = './package.json';
$jsonFile = new JsonFile($filename);
- $this->assertSame([], $jsonFile->getArrayKeys());
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessageMatches('/Unable to read json file ".+package\.json"\./');
+
+ $jsonFile->getArrayKeys();
}
public function testGetArrayKeysWithExistingFile(): void
@@ -76,37 +54,23 @@ public function testGetArrayKeysWithExistingFile(): void
JSON;
$filename = './package.json';
- file_put_contents($filename, $content);
- $this->assertFileExists($filename);
- $jsonFile = new JsonFile($filename);
-
- $this->assertSame($expected, $jsonFile->getArrayKeys());
- }
-
- public function testGetArrayKeysThrowsWhenFileCannotBeRead(): void
- {
- $filename = './package.json';
-
- file_put_contents($filename, '{}');
- $this->assertFileExists($filename);
+ file_put_contents($filename, $content);
- MockerState::addCondition('Foxy\\Json', 'file_get_contents', [$filename, false, null, 0, null], false);
+ self::assertFileExists($filename);
$jsonFile = new JsonFile($filename);
- $this->expectException(RuntimeException::class);
- $this->expectExceptionMessageMatches('/Unable to read json file ".+package\.json"\./');
-
- $jsonFile->getArrayKeys();
+ self::assertSame($expected, $jsonFile->getArrayKeys());
}
- public function testGetIndentWithoutFile(): void
+ public function testGetArrayKeysWithoutFile(): void
{
$filename = './package.json';
+
$jsonFile = new JsonFile($filename);
- $this->assertSame(4, $jsonFile->getIndent());
+ self::assertSame([], $jsonFile->getArrayKeys());
}
public function testGetIndentWithExistingFile(): void
@@ -118,70 +82,70 @@ public function testGetIndentWithExistingFile(): void
JSON;
$filename = './package.json';
+
file_put_contents($filename, $content);
- $this->assertFileExists($filename);
+
+ self::assertFileExists($filename);
$jsonFile = new JsonFile($filename);
- $this->assertSame(2, $jsonFile->getIndent());
+ self::assertSame(2, $jsonFile->getIndent());
}
- public function testWriteWithoutFile(): void
+ public function testGetIndentWithoutFile(): void
{
- $expected = << 'test'];
-
$jsonFile = new JsonFile($filename);
- $jsonFile->write($data);
- $this->assertFileExists($filename);
- $content = file_get_contents($filename);
-
- Assert::equalsWithoutLE($expected, $content);
+ self::assertSame(4, $jsonFile->getIndent());
}
- public function testWriteWithExistingFile(): void
+ /**
+ * @throws Exception|ParsingException
+ */
+ public function testWriteForcesFourSpacesIndentWithExistingTwoSpaceFile(): void
{
$expected = <<assertFileExists($filename);
+
+ self::assertFileExists($filename);
$jsonFile = new JsonFile($filename);
- $data = (array) $jsonFile->read();
+
+ $data = $jsonFile->read();
+
$data['private'] = true;
+
$jsonFile->write($data);
- $this->assertFileExists($filename);
+ self::assertFileExists($filename);
+
$content = file_get_contents($filename);
- Assert::equalsWithoutLE($expected, $content);
+ self::assertSame(
+ LineEndingNormalizer::normalize($expected),
+ LineEndingNormalizer::normalize($content),
+ );
}
+ /**
+ * @throws Exception|ParsingException
+ */
public function testWritePreservesNestedEmptyArraysWithoutSpaces(): void
{
$content = '{"name":"test","workspaces":[],"overrides":{"pkg":{"files":[]}},"dependencies":{}}';
@@ -190,52 +154,123 @@ public function testWritePreservesNestedEmptyArraysWithoutSpaces(): void
file_put_contents($filename, $content);
- $this->assertFileExists($filename);
+ self::assertFileExists($filename);
$jsonFile = new JsonFile($filename);
- $data = (array) $jsonFile->read();
+
+ $data = $jsonFile->read();
+
$data['private'] = true;
$jsonFile->write($data);
- $this->assertFileExists($filename);
+ self::assertFileExists($filename);
$content = file_get_contents($filename);
- $this->assertStringContainsString('"workspaces": []', $content);
- $this->assertStringContainsString('"files": []', $content);
- $this->assertStringContainsString('"dependencies": {}', $content);
- $this->assertMatchesRegularExpression('/^ {4}"dependencies": \{\}/m', $content);
+ self::assertStringContainsString('"workspaces": []', $content);
+ self::assertStringContainsString('"files": []', $content);
+ self::assertStringContainsString('"dependencies": {}', $content);
+ self::assertMatchesRegularExpression('/^ {4}"dependencies": \{\}/m', $content);
}
- public function testWriteForcesFourSpacesIndentWithExistingTwoSpaceFile(): void
+ /**
+ * @throws Exception|ParsingException
+ */
+ public function testWriteWithExistingFile(): void
{
$expected = <<assertFileExists($filename);
+
+ self::assertFileExists($filename);
$jsonFile = new JsonFile($filename);
- $data = (array) $jsonFile->read();
+
+ $data = $jsonFile->read();
+
$data['private'] = true;
+
+ $jsonFile->write($data);
+
+ self::assertFileExists($filename);
+
+ $content = file_get_contents($filename);
+
+ self::assertSame(
+ LineEndingNormalizer::normalize($expected),
+ LineEndingNormalizer::normalize($content),
+ );
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function testWriteWithoutFile(): void
+ {
+ $expected = << 'test'];
+
+ $jsonFile = new JsonFile($filename);
+
$jsonFile->write($data);
- $this->assertFileExists($filename);
+ self::assertFileExists($filename);
+
$content = file_get_contents($filename);
- Assert::equalsWithoutLE($expected, $content);
+ self::assertSame(
+ LineEndingNormalizer::normalize($expected),
+ LineEndingNormalizer::normalize($content),
+ );
+ }
+
+ protected function setUp(): void
+ {
+ parent::setUp();
+
+ $this->oldCwd = getcwd();
+ $this->cwd = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('foxy_asset_json_file_test_', true);
+ $this->sfs = new Filesystem();
+ $this->sfs->mkdir($this->cwd);
+
+ chdir($this->cwd);
+ }
+
+ protected function tearDown(): void
+ {
+ parent::tearDown();
+
+ chdir($this->oldCwd);
+
+ $this->sfs->remove($this->cwd);
+ $this->sfs = null;
+ $this->oldCwd = null;
+ $this->cwd = null;
}
}
diff --git a/tests/Json/JsonFormatterTest.php b/tests/Json/JsonFormatterTest.php
index d7a6bfa..1ec578b 100644
--- a/tests/Json/JsonFormatterTest.php
+++ b/tests/Json/JsonFormatterTest.php
@@ -2,29 +2,18 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Json;
use Foxy\Json\JsonFormatter;
-use PHPForge\Support\Assert;
-
-/**
- * Tests for json formatter.
- *
- * @author François Pluchino
- *
- * @internal
- */
-final class JsonFormatterTest extends \PHPUnit\Framework\TestCase
+use JsonException;
+use PHPForge\Support\LineEndingNormalizer;
+use PHPUnit\Framework\TestCase;
+
+final class JsonFormatterTest extends TestCase
{
+ /**
+ * @throws JsonException
+ */
public function testFormat(): void
{
$expected = << [],
'dependencies' => ['@foo/bar' => '^1.0.0'], 'devDependencies' => [],
];
- $content = json_encode($data);
- Assert::equalsWithoutLE($expected, JsonFormatter::format($content, ['contributors'], 2));
+ $content = json_encode($data, JSON_THROW_ON_ERROR);
+
+ self::assertSame(
+ LineEndingNormalizer::normalize($expected),
+ LineEndingNormalizer::normalize(JsonFormatter::format($content, ['contributors'], 2)),
+ );
}
+ /**
+ * @throws JsonException
+ */
public function testFormatWithEmptyContent(): void
{
- $this->assertEmpty(JsonFormatter::format('', [], 2));
+ self::assertEmpty(
+ JsonFormatter::format('', [], 2),
+ );
}
public function testGetArrayKeys(): void
@@ -64,7 +62,10 @@ public function testGetArrayKeys(): void
JSON;
$expected = ['contributors'];
- $this->assertSame($expected, JsonFormatter::getArrayKeys($content));
+ self::assertSame(
+ $expected,
+ JsonFormatter::getArrayKeys($content),
+ );
}
public function testGetArrayKeysWithoutSpacesBeforeArray(): void
@@ -72,7 +73,10 @@ public function testGetArrayKeysWithoutSpacesBeforeArray(): void
$content = '{"name":"test","workspaces":[]}';
$expected = ['workspaces'];
- $this->assertSame($expected, JsonFormatter::getArrayKeys($content));
+ self::assertSame(
+ $expected,
+ JsonFormatter::getArrayKeys($content),
+ );
}
public function testGetIndent(): void
@@ -84,34 +88,51 @@ public function testGetIndent(): void
}
JSON;
- $this->assertSame(2, JsonFormatter::getIndent($content));
+ self::assertSame(
+ 2,
+ JsonFormatter::getIndent($content),
+ );
}
- public function testUnescapeUnicode(): void
+ /**
+ * @throws JsonException
+ */
+ public function testUnescapeSlashes(): void
{
- $data = ['name' => '\u0048\u0065\u006c\u006c\u006f'];
- $content = json_encode($data);
+ $data = ['url' => 'https:\/\/example.com'];
+
+ $content = json_encode($data, JSON_THROW_ON_ERROR);
$expected = << 'https:\/\/example.com'];
- $content = json_encode($data);
+ $data = ['name' => '\u0048\u0065\u006c\u006c\u006f'];
+
+ $content = json_encode($data, JSON_THROW_ON_ERROR);
$expected = <<
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Solver;
use Composer\Composer;
use Composer\EventDispatcher\EventDispatcher;
use Composer\Installer\InstallationManager;
use Composer\IO\IOInterface;
-use Composer\Package\Link;
-use Composer\Package\PackageInterface;
-use Composer\Package\RootPackageInterface;
-use Composer\Repository\InstalledArrayRepository;
-use Composer\Repository\RepositoryManager;
-use Composer\Repository\WritableRepositoryInterface;
+use Composer\Package\{Link, PackageInterface, RootPackageInterface};
+use Composer\Repository\{InstalledArrayRepository, RepositoryManager, WritableRepositoryInterface};
use Composer\Semver\Constraint\Constraint;
-use Composer\Util\Filesystem;
-use Composer\Util\HttpDownloader;
+use Composer\Util\{Filesystem, HttpDownloader};
+use Exception;
use Foxy\Asset\AssetManagerInterface;
use Foxy\Config\Config;
use Foxy\Fallback\FallbackInterface;
-use Foxy\Solver\Solver;
-use Foxy\Solver\SolverInterface;
+use Foxy\Solver\{Solver, SolverInterface};
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
+
+use function chdir;
+use function class_exists;
+use function dirname;
+use function file_put_contents;
-/**
- * Tests for solver.
- *
- * @author François Pluchino
- *
- * @internal
- */
-class SolverTest extends \PHPUnit\Framework\TestCase
+use const DIRECTORY_SEPARATOR;
+
+class SolverTest extends TestCase
{
- private Config|null $config = null;
private Composer|MockObject|null $composer = null;
private \Composer\Config|MockObject|null $composerConfig = null;
- private MockObject|WritableRepositoryInterface|null $localRepo = null;
- private IOInterface|MockObject|null $io = null;
+ private FallbackInterface|MockObject|null $composerFallback = null;
+ private Config|null $config = null;
+ private string|null $cwd = '';
private Filesystem|MockObject|null $fs = null;
private InstallationManager|MockObject|null $im = null;
- private \Symfony\Component\Filesystem\Filesystem|MockObject|null $sfs = null;
- private MockObject|RootPackageInterface|null $package = null;
+ private IOInterface|MockObject|null $io = null;
+ private MockObject|WritableRepositoryInterface|null $localRepo = null;
private AssetManagerInterface|MockObject|null $manager = null;
- private FallbackInterface|MockObject|null $composerFallback = null;
private string|null $oldCwd = '';
- private string|null $cwd = '';
+ private MockObject|RootPackageInterface|null $package = null;
+ private \Symfony\Component\Filesystem\Filesystem|MockObject|null $sfs = null;
private SolverInterface|null $solver = null;
+ public static function getSolveData(): array
+ {
+ return [[0], [1]];
+ }
+
+ public function testSetUpdatable(): void
+ {
+ $this->manager->expects(self::once())->method('setUpdatable')->with(false);
+ $this->solver->setUpdatable(false);
+ }
+
+ /**
+ * @dataProvider getSolveData
+ *
+ * @param int $resRunManager The result value of the run command of asset manager
+ *
+ * @throws Exception
+ */
+ public function testSolve(int $resRunManager): void
+ {
+ /** @var MockObject|PackageInterface $requirePackage */
+ $requirePackage = $this->createMock(PackageInterface::class);
+
+ $requirePackage->expects(self::any())->method('getPrettyVersion')->willReturn('1.0.0');
+ $requirePackage->expects(self::any())->method('getName')->willReturn('foo/bar');
+ $requirePackage
+ ->expects(self::any())
+ ->method('getRequires')
+ ->willReturn([new Link('root/package', 'php-forge/foxy', new Constraint('=', '1.0.0'))]);
+ $requirePackage->expects(self::any())->method('getDevRequires')->willReturn([]);
+
+ $this->addInstalledPackages([$requirePackage]);
+
+ $requirePackagePath = $this->cwd . '/vendor/foo/bar';
+
+ $this->im->expects(self::once())->method('getInstallPath')->willReturn($requirePackagePath);
+ $this->manager->expects(self::exactly(2))->method('getPackageName')->willReturn('package.json');
+ $this->manager->expects(self::once())->method('addDependencies');
+ $this->manager->expects(self::once())->method('run')->willReturn($resRunManager);
+
+ if (0 === $resRunManager) {
+ $this->composerFallback->expects(self::never())->method('restore');
+ } else {
+ $this->composerFallback->expects(self::once())->method('restore');
+
+ $this->expectException('RuntimeException');
+ $this->expectExceptionMessage('The asset manager ended with an error');
+ }
+
+ $requirePackageFilename = $requirePackagePath . DIRECTORY_SEPARATOR . $this->manager->getPackageName();
+
+ $this->sfs->mkdir(dirname($requirePackageFilename));
+
+ file_put_contents($requirePackageFilename, '{}');
+
+ $this->solver->solve($this->composer, $this->io);
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function testSolveWithDisableOption(): void
+ {
+ $config = new Config(['enabled' => false]);
+ $solver = new Solver($this->manager, $config, $this->fs);
+
+ $this->manager->expects(self::never())->method('run');
+
+ $solver->solve($this->composer, $this->io);
+ }
+
protected function setUp(): void
{
parent::setUp();
$this->oldCwd = getcwd();
- $this->cwd = sys_get_temp_dir() . \DIRECTORY_SEPARATOR . uniqid('foxy_solver_test_', true);
+ $this->cwd = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('foxy_solver_test_', true);
$this->config = new Config(['enabled' => true, 'composer-asset-dir' => $this->cwd . '/composer-asset-dir']);
$this->composer = $this->createMock(Composer::class);
$this->composerConfig = $this->createMock(\Composer\Config::class);
@@ -75,11 +133,11 @@ protected function setUp(): void
$this->composerFallback = $this->createMock(FallbackInterface::class);
$this->sfs->mkdir($this->cwd);
- \chdir($this->cwd);
+ chdir($this->cwd);
$this->localRepo = $this->createMock(InstalledArrayRepository::class);
- if (\class_exists(HttpDownloader::class)) {
+ if (class_exists(HttpDownloader::class)) {
$rm = new RepositoryManager($this->io, $this->composerConfig, new HttpDownloader($this->io, $this->composerConfig));
$rm->setLocalRepository($this->localRepo);
} else {
@@ -87,21 +145,21 @@ protected function setUp(): void
$rm->setLocalRepository($this->localRepo);
}
- $this->composer->expects($this->any())->method('getRepositoryManager')->willReturn($rm);
- $this->composer->expects($this->any())->method('getInstallationManager')->willReturn($this->im);
- $this->composer->expects($this->any())->method('getPackage')->willReturn($this->package);
- $this->composer->expects($this->any())->method('getConfig')->willReturn($this->composerConfig);
+ $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($rm);
+ $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($this->im);
+ $this->composer->expects(self::any())->method('getPackage')->willReturn($this->package);
+ $this->composer->expects(self::any())->method('getConfig')->willReturn($this->composerConfig);
$this->composer
- ->expects($this->any())
+ ->expects(self::any())
->method('getEventDispatcher')
->willReturn(new EventDispatcher($this->composer, $this->io));
$sfs = $this->sfs;
$this->fs
- ->expects($this->any())
+ ->expects(self::any())
->method('findShortestPath')
- ->willReturnCallback(fn ($from, $to) => rtrim($sfs->makePathRelative($to, $from), '/'));
+ ->willReturnCallback(fn(string $from, string $to): string => rtrim($sfs->makePathRelative($to, $from), '/'));
$this->solver = new Solver($this->manager, $this->config, $this->fs, $this->composerFallback);
}
@@ -128,72 +186,6 @@ protected function tearDown(): void
$this->cwd = null;
}
- public function testSetUpdatable(): void
- {
- $this->manager->expects($this->once())->method('setUpdatable')->with(false);
- $this->solver->setUpdatable(false);
- }
-
- public function testSolveWithDisableOption(): void
- {
- $config = new Config(['enabled' => false]);
- $solver = new Solver($this->manager, $config, $this->fs);
-
- $this->manager->expects($this->never())->method('run');
-
- $solver->solve($this->composer, $this->io);
- }
-
- public static function getSolveData(): array
- {
- return [[0], [1]];
- }
-
- /**
- * @dataProvider getSolveData
- *
- * @param int $resRunManager The result value of the run command of asset manager
- */
- public function testSolve(int $resRunManager): void
- {
- /** @var MockObject|PackageInterface $requirePackage */
- $requirePackage = $this->createMock(PackageInterface::class);
-
- $requirePackage->expects($this->any())->method('getPrettyVersion')->willReturn('1.0.0');
- $requirePackage->expects($this->any())->method('getName')->willReturn('foo/bar');
- $requirePackage
- ->expects($this->any())
- ->method('getRequires')
- ->willReturn([new Link('root/package', 'php-forge/foxy', new Constraint('=', '1.0.0'))]);
- $requirePackage->expects($this->any())->method('getDevRequires')->willReturn([]);
-
- $this->addInstalledPackages([$requirePackage]);
-
- $requirePackagePath = $this->cwd . '/vendor/foo/bar';
-
- $this->im->expects($this->once())->method('getInstallPath')->willReturn($requirePackagePath);
- $this->manager->expects($this->exactly(2))->method('getPackageName')->willReturn('package.json');
- $this->manager->expects($this->once())->method('addDependencies');
- $this->manager->expects($this->once())->method('run')->willReturn($resRunManager);
-
- if (0 === $resRunManager) {
- $this->composerFallback->expects($this->never())->method('restore');
- } else {
- $this->composerFallback->expects($this->once())->method('restore');
-
- $this->expectException('RuntimeException');
- $this->expectExceptionMessage('The asset manager ended with an error');
- }
-
- $requirePackageFilename = $requirePackagePath . \DIRECTORY_SEPARATOR . $this->manager->getPackageName();
-
- $this->sfs->mkdir(\dirname($requirePackageFilename));
-
- \file_put_contents($requirePackageFilename, '{}');
-
- $this->solver->solve($this->composer, $this->io);
- }
-
/**
* Add the installed packages in local repository.
*
@@ -201,6 +193,6 @@ public function testSolve(int $resRunManager): void
*/
private function addInstalledPackages(array $packages = []): void
{
- $this->localRepo->expects($this->any())->method('getCanonicalPackages')->willReturn($packages);
+ $this->localRepo->expects(self::any())->method('getCanonicalPackages')->willReturn($packages);
}
}
diff --git a/tests/Support/InternalMockerExtension.php b/tests/Support/InternalMockerExtension.php
index fc43b5f..e386264 100644
--- a/tests/Support/InternalMockerExtension.php
+++ b/tests/Support/InternalMockerExtension.php
@@ -2,45 +2,38 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Support;
-use PHPUnit\Event\Test\PreparationStarted;
-use PHPUnit\Event\Test\PreparationStartedSubscriber;
-use PHPUnit\Event\TestSuite\Started;
-use PHPUnit\Event\TestSuite\StartedSubscriber;
-use PHPUnit\Runner\Extension\Extension;
-use PHPUnit\Runner\Extension\Facade;
-use PHPUnit\Runner\Extension\ParameterCollection;
+use PHPUnit\Event\Test\{Finished, FinishedSubscriber};
+use PHPUnit\Event\Test\{PreparationStarted, PreparationStartedSubscriber};
+use PHPUnit\Event\TestSuite\{Started, StartedSubscriber};
+use PHPUnit\Runner\Extension\{Extension, Facade, ParameterCollection};
use PHPUnit\TextUI\Configuration\Configuration;
-use Xepozz\InternalMocker\Mocker;
-use Xepozz\InternalMocker\MockerState;
+use Xepozz\InternalMocker\{Mocker, MockerState};
final class InternalMockerExtension implements Extension
{
public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void
{
$facade->registerSubscribers(
- new class () implements StartedSubscriber {
+ new class implements StartedSubscriber {
public function notify(Started $event): void
{
InternalMockerExtension::load();
}
},
- new class () implements PreparationStartedSubscriber {
+ new class implements PreparationStartedSubscriber {
public function notify(PreparationStarted $event): void
{
MockerState::resetState();
}
},
+ new class implements FinishedSubscriber {
+ public function notify(Finished $event): void
+ {
+ MockerState::resetState();
+ }
+ },
);
}
diff --git a/tests/Util/AssetUtilTest.php b/tests/Util/AssetUtilTest.php
index dfe1d97..db7ab12 100644
--- a/tests/Util/AssetUtilTest.php
+++ b/tests/Util/AssetUtilTest.php
@@ -2,82 +2,79 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Util;
use Composer\Installer\InstallationManager;
-use Composer\Package\Link;
-use Composer\Package\PackageInterface;
+use Composer\Package\{Link, PackageInterface};
use Composer\Semver\Constraint\Constraint;
-use Foxy\Asset\AbstractAssetManager;
-use Foxy\Asset\AssetManagerInterface;
+use Foxy\Asset\{AbstractAssetManager, AssetManagerInterface};
use Foxy\Util\AssetUtil;
+use JsonException;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
use Symfony\Component\Filesystem\Filesystem;
-/**
- * Tests for asset util.
- *
- * @author François Pluchino
- *
- * @internal
- */
-final class AssetUtilTest extends \PHPUnit\Framework\TestCase
+use function count;
+use function file_put_contents;
+use function realpath;
+use function str_replace;
+
+use const DIRECTORY_SEPARATOR;
+
+final class AssetUtilTest extends TestCase
{
- private Filesystem|null $sfs;
private string|null $cwd;
+ private Filesystem|null $sfs;
- protected function setUp(): void
+ public static function getExtraData(): array
{
- parent::setUp();
-
- $this->cwd = sys_get_temp_dir() . \DIRECTORY_SEPARATOR . uniqid('foxy_asset_util_test_', true);
- $this->sfs = new Filesystem();
- $this->sfs->mkdir($this->cwd);
+ return [[false, false], [true, false], [false, true], [true, true]];
}
- protected function tearDown(): void
+ public static function getFormatPackageData(): array
{
- parent::tearDown();
-
- $this->sfs->remove($this->cwd);
- $this->sfs = null;
- $this->cwd = null;
+ return [
+ ['1.0.0', null, '1.0.0'],
+ ['1.0.1', '1.0.0', '1.0.0'],
+ ['1.0.0.x-dev', null, '1.0.0'],
+ ['1.0.0.x', null, '1.0.0'],
+ ['1.0.0.1', null, '1.0.0'],
+ ['dev-master', null, '1.0.0', '1-dev'],
+ ['dev-master', null, '1.0.0', '1.0-dev'],
+ ['dev-master', null, '1.0.0', '1.0.0-dev'],
+ ['dev-master', null, '1.0.0', '1.x-dev'],
+ ['dev-master', null, '1.0.0', '1.0.x-dev'],
+ ['dev-master', null, '1.0.0', '1.*-dev'],
+ ['dev-master', null, '1.0.0', '1.0.*-dev'],
+ ];
}
- public function testGetName(): void
+ public static function getIsProjectActivationData(): array
{
- $package = $this->createMock(PackageInterface::class);
- $package->expects($this->once())->method('getName')->willReturn('foo/bar');
-
- $this->assertSame('@composer-asset/foo--bar', AssetUtil::getName($package));
+ return [
+ ['full/qualified', true],
+ ['full-disable/qualified', false],
+ ['foo/bar', true],
+ ['baz/foo', false],
+ ['baz/foo-test', false],
+ ['bar/test', true],
+ ['other/package', false],
+ ['test-string/package', true],
+ ];
}
- public function testGetPathWithoutRequiredFoxy(): void
+ public static function getIsProjectActivationWithWildcardData(): array
{
- $installationManager = $this->createMock(InstallationManager::class);
-
- $installationManager->expects($this->never())->method('getInstallPath');
-
- $assetManager = $this->createMock(AbstractAssetManager::class);
-
- /** @var MockObject|PackageInterface $package */
- $package = $this->createMock(PackageInterface::class);
-
- $package->expects($this->once())->method('getRequires')->willReturn([]);
- $package->expects($this->once())->method('getDevRequires')->willReturn([]);
-
- $res = AssetUtil::getPath($installationManager, $assetManager, $package);
-
- $this->assertNull($res);
+ return [
+ ['full/qualified', true],
+ ['full-disable/qualified', false],
+ ['foo/bar', true],
+ ['baz/foo', false],
+ ['baz/foo-test', false],
+ ['bar/test', true],
+ ['other/package', true],
+ ['test-string/package', true],
+ ];
}
public static function getRequiresData(): array
@@ -107,16 +104,64 @@ public static function getRequiresData(): array
}
/**
- * @dataProvider getRequiresData
+ * @dataProvider getFormatPackageData
+ */
+ public function testFormatPackage(
+ string $packageVersion,
+ string|null $assetVersion,
+ string $expectedAssetVersion,
+ string|null $branchAlias = null,
+ ): void {
+ $packageName = '@composer-asset/foo--bar';
+
+ /** @var MockObject|PackageInterface $package */
+ $package = $this->createMock(PackageInterface::class);
+
+ $assetPackage = [];
+
+ if (null !== $assetVersion) {
+ $assetPackage['version'] = $assetVersion;
+
+ $package->expects(self::never())->method('getPrettyVersion');
+ $package->expects(self::never())->method('getExtra');
+ } else {
+ $extra = [];
+
+ if (null !== $branchAlias) {
+ $extra['branch-alias'][$packageVersion] = $branchAlias;
+ }
+
+ $package->expects(self::once())->method('getPrettyVersion')->willReturn($packageVersion);
+ $package->expects(self::once())->method('getExtra')->willReturn($extra);
+ }
+
+ $expected = ['name' => $packageName, 'version' => $expectedAssetVersion];
+
+ $res = AssetUtil::formatPackage($package, $packageName, $assetPackage);
+
+ self::assertEquals($expected, $res);
+ }
+
+ public function testGetName(): void
+ {
+ $package = $this->createMock(PackageInterface::class);
+ $package->expects(self::once())->method('getName')->willReturn('foo/bar');
+
+ self::assertSame('@composer-asset/foo--bar', AssetUtil::getName($package));
+ }
+
+ /**
+ * @dataProvider getExtraData
*
- * @param Link[] $requires
- * @param Link[] $devRequires
+ * @throws JsonException
*/
- public function testGetPathWithRequiredFoxy(array $requires, array $devRequires, bool $fileExists = false): void
+ public function testGetPathWithExtraActivation(bool $withExtra, bool $fileExists = false): void
{
$installationManager = $this->createMock(InstallationManager::class);
- $installationManager->expects($this->once())->method('getInstallPath')->willReturn($this->cwd);
+ if ($withExtra && $fileExists) {
+ $installationManager->expects(self::once())->method('getInstallPath')->willReturn($this->cwd);
+ }
/** @var AbstractAssetManager|MockObject $assetManager */
$assetManager = $this
@@ -126,44 +171,60 @@ public function testGetPathWithRequiredFoxy(array $requires, array $devRequires,
$package = $this->createMock(PackageInterface::class);
- $package->expects($this->once())->method('getRequires')->willReturn($requires);
-
- if (0 === \count($devRequires)) {
- $package->expects($this->never())->method('getDevRequires');
- } else {
- $package->expects($this->once())->method('getDevRequires')->willReturn($devRequires);
- }
+ $package->expects(self::any())->method('getRequires')->willReturn([]);
+ $package->expects(self::any())->method('getDevRequires')->willReturn([]);
+ $package->expects(self::atLeastOnce())->method('getExtra')->willReturn(['foxy' => $withExtra]);
if ($fileExists) {
- $expectedFilename = $this->cwd . \DIRECTORY_SEPARATOR . $assetManager->getPackageName();
+ $expectedFilename = $this->cwd . DIRECTORY_SEPARATOR . $assetManager->getPackageName();
- \file_put_contents($expectedFilename, '{}');
+ file_put_contents($expectedFilename, '{}');
- $expectedFilename = \str_replace('\\', '/', \realpath($expectedFilename));
+ $expectedFilename = $withExtra ? str_replace('\\', '/', realpath($expectedFilename)) : null;
} else {
$expectedFilename = null;
}
$res = AssetUtil::getPath($installationManager, $assetManager, $package);
- $this->assertSame($expectedFilename, $res);
+ self::assertSame($expectedFilename, $res);
}
- public static function getExtraData(): array
+ /**
+ * @throws JsonException
+ */
+ public function testGetPathWithoutRequiredFoxy(): void
{
- return [[false, false], [true, false], [false, true], [true, true]];
+ $installationManager = $this->createMock(InstallationManager::class);
+
+ $installationManager->expects(self::never())->method('getInstallPath');
+
+ $assetManager = $this->createMock(AbstractAssetManager::class);
+
+ /** @var MockObject|PackageInterface $package */
+ $package = $this->createMock(PackageInterface::class);
+
+ $package->expects(self::once())->method('getRequires')->willReturn([]);
+ $package->expects(self::once())->method('getDevRequires')->willReturn([]);
+
+ $res = AssetUtil::getPath($installationManager, $assetManager, $package);
+
+ self::assertNull($res);
}
/**
- * @dataProvider getExtraData
+ * @dataProvider getRequiresData
+ *
+ * @param Link[] $requires
+ * @param Link[] $devRequires
+ *
+ * @throws JsonException
*/
- public function testGetPathWithExtraActivation(bool $withExtra, bool $fileExists = false): void
+ public function testGetPathWithRequiredFoxy(array $requires, array $devRequires, bool $fileExists = false): void
{
$installationManager = $this->createMock(InstallationManager::class);
- if ($withExtra && $fileExists) {
- $installationManager->expects($this->once())->method('getInstallPath')->willReturn($this->cwd);
- }
+ $installationManager->expects(self::once())->method('getInstallPath')->willReturn($this->cwd);
/** @var AbstractAssetManager|MockObject $assetManager */
$assetManager = $this
@@ -173,59 +234,79 @@ public function testGetPathWithExtraActivation(bool $withExtra, bool $fileExists
$package = $this->createMock(PackageInterface::class);
- $package->expects($this->any())->method('getRequires')->willReturn([]);
- $package->expects($this->any())->method('getDevRequires')->willReturn([]);
- $package->expects($this->atLeastOnce())->method('getExtra')->willReturn(['foxy' => $withExtra]);
+ $package->expects(self::once())->method('getRequires')->willReturn($requires);
+
+ if (0 === count($devRequires)) {
+ $package->expects(self::never())->method('getDevRequires');
+ } else {
+ $package->expects(self::once())->method('getDevRequires')->willReturn($devRequires);
+ }
if ($fileExists) {
- $expectedFilename = $this->cwd . \DIRECTORY_SEPARATOR . $assetManager->getPackageName();
+ $expectedFilename = $this->cwd . DIRECTORY_SEPARATOR . $assetManager->getPackageName();
- \file_put_contents($expectedFilename, '{}');
+ file_put_contents($expectedFilename, '{}');
- $expectedFilename = $withExtra ? \str_replace('\\', '/', \realpath($expectedFilename)) : null;
+ $expectedFilename = str_replace('\\', '/', realpath($expectedFilename));
} else {
$expectedFilename = null;
}
$res = AssetUtil::getPath($installationManager, $assetManager, $package);
- $this->assertSame($expectedFilename, $res);
+ self::assertSame($expectedFilename, $res);
+ }
+
+ /**
+ * @throws JsonException
+ */
+ public function testGetPathWithRootPackageDir(): void
+ {
+ $installationManager = $this->createMock(InstallationManager::class);
+ $installationManager
+ ->expects(self::once())
+ ->method('getInstallPath')
+ ->willReturn('tests/Fixtures/package/global');
+
+ $assetManager = $this->createMock(AssetManagerInterface::class);
+ $assetManager->expects(self::once())->method('getPackageName')->willReturn('foo/bar');
+
+ $package = $this->createMock(PackageInterface::class);
+ $package->expects(self::once())->method('getName')->willReturn('foo/bar');
+ $package->expects(self::once())->method('getRequires')->willReturn([]);
+ $package->expects(self::once())->method('getDevRequires')->willReturn([]);
+
+ $configPackages = [
+ '/^foo\/bar$/' => true,
+ ];
+
+ $expectedPath = 'tests/Fixtures/package/global/theme/foo/bar';
+
+ $res = AssetUtil::getPath($installationManager, $assetManager, $package, $configPackages);
+
+ self::assertStringContainsString($expectedPath, $res);
}
public function testHasNoPluginDependency(): void
{
- $this->assertFalse(
- AssetUtil::hasPluginDependency([new Link('root/package', 'foo/bar', new Constraint('=', '1.0.0'))])
+ self::assertFalse(
+ AssetUtil::hasPluginDependency([new Link('root/package', 'foo/bar', new Constraint('=', '1.0.0'))]),
);
}
public function testHasPluginDependency(): void
{
- $this->assertTrue(
+ self::assertTrue(
AssetUtil::hasPluginDependency(
[
new Link('root/package', 'foo/bar', new Constraint('=', '1.0.0')),
new Link('root/package', 'php-forge/foxy', new Constraint('=', '1.0.0')),
new Link('root/package', 'bar/foo', new Constraint('=', '1.0.0')),
],
- )
+ ),
);
}
- public static function getIsProjectActivationData(): array
- {
- return [
- ['full/qualified', true],
- ['full-disable/qualified', false],
- ['foo/bar', true],
- ['baz/foo', false],
- ['baz/foo-test', false],
- ['bar/test', true],
- ['other/package', false],
- ['test-string/package', true],
- ];
- }
-
/**
* @dataProvider getIsProjectActivationData
*/
@@ -243,25 +324,11 @@ public function testIsProjectActivation(string $packageName, bool $expected): vo
/** @var MockObject|PackageInterface $package */
$package = $this->createMock(PackageInterface::class);
- $package->expects($this->once())->method('getName')->willReturn($packageName);
+ $package->expects(self::once())->method('getName')->willReturn($packageName);
$res = AssetUtil::isProjectActivation($package, $enablePackages);
- $this->assertSame($expected, $res);
- }
-
- public static function getIsProjectActivationWithWildcardData(): array
- {
- return [
- ['full/qualified', true],
- ['full-disable/qualified', false],
- ['foo/bar', true],
- ['baz/foo', false],
- ['baz/foo-test', false],
- ['bar/test', true],
- ['other/package', true],
- ['test-string/package', true],
- ];
+ self::assertSame($expected, $res);
}
/**
@@ -278,94 +345,28 @@ public function testIsProjectActivationWithWildcardPattern(string $packageName,
/** @var MockObject|PackageInterface $package */
$package = $this->createMock(PackageInterface::class);
- $package->expects($this->once())->method('getName')->willReturn($packageName);
+ $package->expects(self::once())->method('getName')->willReturn($packageName);
$res = AssetUtil::isProjectActivation($package, $enablePackages);
- $this->assertSame($expected, $res);
+ self::assertSame($expected, $res);
}
- public static function getFormatPackageData(): array
+ protected function setUp(): void
{
- return [
- ['1.0.0', null, '1.0.0'],
- ['1.0.1', '1.0.0', '1.0.0'],
- ['1.0.0.x-dev', null, '1.0.0'],
- ['1.0.0.x', null, '1.0.0'],
- ['1.0.0.1', null, '1.0.0'],
- ['dev-master', null, '1.0.0', '1-dev'],
- ['dev-master', null, '1.0.0', '1.0-dev'],
- ['dev-master', null, '1.0.0', '1.0.0-dev'],
- ['dev-master', null, '1.0.0', '1.x-dev'],
- ['dev-master', null, '1.0.0', '1.0.x-dev'],
- ['dev-master', null, '1.0.0', '1.*-dev'],
- ['dev-master', null, '1.0.0', '1.0.*-dev'],
- ];
- }
-
- /**
- * @dataProvider getFormatPackageData
- */
- public function testFormatPackage(
- string $packageVersion,
- string|null $assetVersion,
- string $expectedAssetVersion,
- string|null $branchAlias = null
- ): void {
- $packageName = '@composer-asset/foo--bar';
-
- /** @var MockObject|PackageInterface $package */
- $package = $this->createMock(PackageInterface::class);
-
- $assetPackage = [];
-
- if (null !== $assetVersion) {
- $assetPackage['version'] = $assetVersion;
-
- $package->expects($this->never())->method('getPrettyVersion');
- $package->expects($this->never())->method('getExtra');
- } else {
- $extra = [];
-
- if (null !== $branchAlias) {
- $extra['branch-alias'][$packageVersion] = $branchAlias;
- }
-
- $package->expects($this->once())->method('getPrettyVersion')->willReturn($packageVersion);
- $package->expects($this->once())->method('getExtra')->willReturn($extra);
- }
-
- $expected = ['name' => $packageName, 'version' => $expectedAssetVersion];
-
- $res = AssetUtil::formatPackage($package, $packageName, $assetPackage);
+ parent::setUp();
- $this->assertEquals($expected, $res);
+ $this->cwd = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('foxy_asset_util_test_', true);
+ $this->sfs = new Filesystem();
+ $this->sfs->mkdir($this->cwd);
}
- public function testGetPathWithRootPackageDir(): void
+ protected function tearDown(): void
{
- $installationManager = $this->createMock(InstallationManager::class);
- $installationManager
- ->expects($this->once())
- ->method('getInstallPath')
- ->willReturn('tests/Fixtures/package/global');
-
- $assetManager = $this->createMock(AssetManagerInterface::class);
- $assetManager->expects($this->once())->method('getPackageName')->willReturn('foo/bar');
-
- $package = $this->createMock(PackageInterface::class);
- $package->expects($this->once())->method('getName')->willReturn('foo/bar');
- $package->expects($this->once())->method('getRequires')->willReturn([]);
- $package->expects($this->once())->method('getDevRequires')->willReturn([]);
-
- $configPackages = [
- '/^foo\/bar$/' => true,
- ];
-
- $expectedPath = 'tests/Fixtures/package/global/theme/foo/bar';
-
- $res = AssetUtil::getPath($installationManager, $assetManager, $package, $configPackages);
+ parent::tearDown();
- $this->assertStringContainsString($expectedPath, $res);
+ $this->sfs->remove($this->cwd);
+ $this->sfs = null;
+ $this->cwd = null;
}
}
diff --git a/tests/Util/ComposerUtilTest.php b/tests/Util/ComposerUtilTest.php
index 6c4f9ff..c9fed9c 100644
--- a/tests/Util/ComposerUtilTest.php
+++ b/tests/Util/ComposerUtilTest.php
@@ -2,27 +2,13 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Util;
+use Foxy\Exception\RuntimeException;
use Foxy\Util\ComposerUtil;
+use PHPUnit\Framework\TestCase;
-/**
- * Tests for composer util.
- *
- * @author François Pluchino
- *
- * @internal
- */
-final class ComposerUtilTest extends \PHPUnit\Framework\TestCase
+final class ComposerUtilTest extends TestCase
{
public static function getValidateVersionData(): array
{
@@ -45,11 +31,11 @@ public static function getValidateVersionData(): array
public function testValidateVersion(string $composerVersion, string $requiredVersion, bool $valid): void
{
if ($valid) {
- $this->assertTrue(true, 'Composer\'s version is valid');
+ self::assertTrue(true, 'Composer\'s version is valid');
} else {
- $this->expectException(\Foxy\Exception\RuntimeException::class);
+ $this->expectException(RuntimeException::class);
$this->expectExceptionMessageMatches(
- '/Foxy requires the Composer\'s minimum version "([\d\.^|, ]+)", current version is "([\d\.]+)"/'
+ '/Foxy requires the Composer\'s minimum version "([\d\.^|, ]+)", current version is "([\d\.]+)"/',
);
}
diff --git a/tests/Util/ConsoleUtilTest.php b/tests/Util/ConsoleUtilTest.php
index 85d8829..3c88093 100644
--- a/tests/Util/ConsoleUtilTest.php
+++ b/tests/Util/ConsoleUtilTest.php
@@ -2,35 +2,28 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Util;
use Composer\Config;
-use Composer\IO\ConsoleIO;
-use Composer\IO\IOInterface;
+use Composer\IO\{ConsoleIO, IOInterface};
use Foxy\Util\ConsoleUtil;
+use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Helper\HelperSet;
-use Symfony\Component\Console\Input\ArgvInput;
-use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\{ArgvInput, InputInterface};
use Symfony\Component\Console\Output\NullOutput;
-/**
- * Tests for console util.
- *
- * @author François Pluchino
- *
- * @internal
- */
-final class ConsoleUtilTest extends \PHPUnit\Framework\TestCase
+final class ConsoleUtilTest extends TestCase
{
+ public static function getPreferredInstallOptionsData(): array
+ {
+ return [
+ [false, false, 'auto', false],
+ [false, true, 'auto', true],
+ [true, false, 'source', false],
+ [false, true, 'dist', false],
+ ];
+ }
+
public function testGetInput(): void
{
$input = new ArgvInput();
@@ -38,7 +31,7 @@ public function testGetInput(): void
$helperSet = new HelperSet();
$io = new ConsoleIO($input, $output, $helperSet);
- $this->assertSame($input, ConsoleUtil::getInput($io));
+ self::assertSame($input, ConsoleUtil::getInput($io));
}
public function testGetInputWithoutValidInput(): void
@@ -46,17 +39,7 @@ public function testGetInputWithoutValidInput(): void
/** @var IOInterface $io */
$io = $this->createMock(IOInterface::class);
- $this->assertInstanceOf(ArgvInput::class, ConsoleUtil::getInput($io));
- }
-
- public static function getPreferredInstallOptionsData(): array
- {
- return [
- [false, false, 'auto', false],
- [false, true, 'auto', true],
- [true, false, 'source', false],
- [false, true, 'dist', false],
- ];
+ self::assertInstanceOf(ArgvInput::class, ConsoleUtil::getInput($io));
}
/**
@@ -66,22 +49,22 @@ public function testGetPreferredInstallOptions(
bool $expectedPreferSource,
bool $expectedPreferDist,
string $preferedInstall,
- bool $inputPrefer
+ bool $inputPrefer,
): void {
$config = $this->createMock(Config::class);
$input = $this->createMock(InputInterface::class);
- $config->expects($this->once())->method('get')->with('preferred-install')->willReturn($preferedInstall);
+ $config->expects(self::once())->method('get')->with('preferred-install')->willReturn($preferedInstall);
if ($inputPrefer) {
- $input->expects($this->atLeastOnce())
+ $input->expects(self::atLeastOnce())
->method('getOption')
- ->willReturnCallback(static fn ($option) => !('prefer-source' === $option))
+ ->willReturnCallback(static fn($option): bool => !('prefer-source' === $option))
;
}
$res = ConsoleUtil::getPreferredInstallOptions($config, $input);
- $this->assertEquals([$expectedPreferSource, $expectedPreferDist], $res);
+ self::assertEquals([$expectedPreferSource, $expectedPreferDist], $res);
}
}
diff --git a/tests/Util/PackageUtilTest.php b/tests/Util/PackageUtilTest.php
index c6af8e5..0a2c64e 100644
--- a/tests/Util/PackageUtilTest.php
+++ b/tests/Util/PackageUtilTest.php
@@ -2,70 +2,22 @@
declare(strict_types=1);
-/*
- * This file is part of the Foxy package.
- *
- * (c) François Pluchino
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
namespace Foxy\Tests\Util;
use Composer\Package\CompletePackage;
use Foxy\Util\PackageUtil;
+use PHPUnit\Framework\TestCase;
-/**
- * Tests for package util.
- *
- * @author François Pluchino
- *
- * @internal
- */
-final class PackageUtilTest extends \PHPUnit\Framework\TestCase
+final class PackageUtilTest extends TestCase
{
- public function testLoadLockPackages(): void
- {
- $lockData = [
- 'packages' => [
- ['name' => 'foo/bar', 'version' => '1.0.0.0'],
- ],
- 'packages-dev' => [
- ['name' => 'bar/foo', 'version' => '1.0.0.0'],
- ],
- ];
-
- $package = new CompletePackage('foo/bar', '1.0.0.0', '1.0.0.0');
- $package->setType('library');
-
- $packageDev = new CompletePackage('bar/foo', '1.0.0.0', '1.0.0.0');
- $packageDev->setType('library');
-
- $expectedPackages = [$package];
- $expectedDevPackages = [$packageDev];
-
- $lockDataLoaded = PackageUtil::loadLockPackages($lockData);
-
- $this->assertArrayHasKey('packages', $lockDataLoaded);
- $this->assertArrayHasKey('packages-dev', $lockDataLoaded);
- $this->assertEquals($lockDataLoaded['packages'], $expectedPackages);
- $this->assertEquals($lockDataLoaded['packages-dev'], $expectedDevPackages);
- }
-
- public function testLoadLockPackagesWithoutPackages(): void
- {
- $this->assertSame([], PackageUtil::loadLockPackages([]));
- }
-
public function testConvertLockAlias(): void
{
$lockData = [
'aliases' => [
[
'alias' => '1.0.0',
- 'alias_normalized' =>
- '1.0.0.0',
+ 'alias_normalized'
+ => '1.0.0.0',
'version' => 'dev-feature/1.0-test',
'package' => 'foo/bar',
],
@@ -95,7 +47,40 @@ public function testConvertLockAlias(): void
$convertedAliases = PackageUtil::convertLockAlias($lockData);
- $this->assertArrayHasKey('aliases', $convertedAliases);
- $this->assertEquals($convertedAliases['aliases'], $expectedAliases);
+ self::assertArrayHasKey('aliases', $convertedAliases);
+ self::assertEquals($expectedAliases, $convertedAliases['aliases']);
+ }
+
+ public function testLoadLockPackages(): void
+ {
+ $lockData = [
+ 'packages' => [
+ ['name' => 'foo/bar', 'version' => '1.0.0.0'],
+ ],
+ 'packages-dev' => [
+ ['name' => 'bar/foo', 'version' => '1.0.0.0'],
+ ],
+ ];
+
+ $package = new CompletePackage('foo/bar', '1.0.0.0', '1.0.0.0');
+ $package->setType('library');
+
+ $packageDev = new CompletePackage('bar/foo', '1.0.0.0', '1.0.0.0');
+ $packageDev->setType('library');
+
+ $expectedPackages = [$package];
+ $expectedDevPackages = [$packageDev];
+
+ $lockDataLoaded = PackageUtil::loadLockPackages($lockData);
+
+ self::assertArrayHasKey('packages', $lockDataLoaded);
+ self::assertArrayHasKey('packages-dev', $lockDataLoaded);
+ self::assertEquals($expectedPackages, $lockDataLoaded['packages']);
+ self::assertEquals($expectedDevPackages, $lockDataLoaded['packages-dev']);
+ }
+
+ public function testLoadLockPackagesWithoutPackages(): void
+ {
+ self::assertSame([], PackageUtil::loadLockPackages([]));
}
}