summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Zhineng <[email protected]>2025-05-12 19:01:57 +0800
committerLi Zhineng <[email protected]>2025-05-12 19:01:57 +0800
commit12ebfe678ed2554fb5902c60d99a53414bec0ad1 (patch)
tree1fdd790e309ed347f8fd92413cd1d9e0dfe197ea
downloadvehicle-license-china-12ebfe678ed2554fb5902c60d99a53414bec0ad1.tar.gz
vehicle-license-china-12ebfe678ed2554fb5902c60d99a53414bec0ad1.zip
first commit
-rw-r--r--.gitignore1
-rw-r--r--composer.json28
-rw-r--r--composer.lock1611
-rw-r--r--phpunit.xml.dist26
-rw-r--r--src/RegistrationNumber.php253
-rw-r--r--src/RegistrationNumberException.php10
-rw-r--r--tests/RegistrationNumberTest.php141
7 files changed, 2070 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..48b8bf9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+vendor/
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..1dcc38e
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,28 @@
+{
+ "name": "lizhineng/vehicle-license-china",
+ "description": "Vehicle license library for China.",
+ "type": "library",
+ "license": "MIT",
+ "autoload": {
+ "psr-4": {
+ "Zhineng\\VehicleLicenseChina\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Zhineng\\VehicleLicenseChina\\Tests": "tests/"
+ }
+ },
+ "authors": [
+ {
+ "name": "Li Zhineng",
+ "email": "[email protected]"
+ }
+ ],
+ "require": {
+ "php": "^8.4"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12"
+ }
+}
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 0000000..0c70849
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,1611 @@
+{
+ "_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": "7334ae29067edbf4d3450f1d032914c9",
+ "packages": [],
+ "packages-dev": [
+ {
+ "name": "myclabs/deep-copy",
+ "version": "1.13.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/myclabs/DeepCopy.git",
+ "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c",
+ "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c",
+ "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.1"
+ },
+ "funding": [
+ {
+ "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-04-29T12:36:36+00:00"
+ },
+ {
+ "name": "nikic/php-parser",
+ "version": "v5.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nikic/PHP-Parser.git",
+ "reference": "447a020a1f875a434d62f2a401f53b82a396e494"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494",
+ "reference": "447a020a1f875a434d62f2a401f53b82a396e494",
+ "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.0-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.4.0"
+ },
+ "time": "2024-12-30T11:07:19+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": "[email protected]",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "[email protected]",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "[email protected]",
+ "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": "[email protected]",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "[email protected]",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "[email protected]",
+ "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": "phpunit/php-code-coverage",
+ "version": "12.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "448f2c504d86dbff3949dcd02c95aa85db2c7617"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/448f2c504d86dbff3949dcd02c95aa85db2c7617",
+ "reference": "448f2c504d86dbff3949dcd02c95aa85db2c7617",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "ext-xmlwriter": "*",
+ "nikic/php-parser": "^5.4.0",
+ "php": ">=8.3",
+ "phpunit/php-file-iterator": "^6.0",
+ "phpunit/php-text-template": "^5.0",
+ "sebastian/complexity": "^5.0",
+ "sebastian/environment": "^8.0",
+ "sebastian/lines-of-code": "^4.0",
+ "sebastian/version": "^6.0",
+ "theseer/tokenizer": "^1.2.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.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": "12.2.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "[email protected]",
+ "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/12.2.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/phpunit/php-code-coverage",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-05-04T05:25:05+00:00"
+ },
+ {
+ "name": "phpunit/php-file-iterator",
+ "version": "6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "961bc913d42fe24a257bfff826a5068079ac7782"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/961bc913d42fe24a257bfff826a5068079ac7782",
+ "reference": "961bc913d42fe24a257bfff826a5068079ac7782",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.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": "[email protected]",
+ "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/6.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:58:37+00:00"
+ },
+ {
+ "name": "phpunit/php-invoker",
+ "version": "6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-invoker.git",
+ "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406",
+ "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "ext-pcntl": "*",
+ "phpunit/phpunit": "^12.0"
+ },
+ "suggest": {
+ "ext-pcntl": "*"
+ },
+ "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": "[email protected]",
+ "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",
+ "security": "https://github.com/sebastianbergmann/php-invoker/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-invoker/tree/6.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:58:58+00:00"
+ },
+ {
+ "name": "phpunit/php-text-template",
+ "version": "5.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53",
+ "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.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": "[email protected]",
+ "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/5.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:59:16+00:00"
+ },
+ {
+ "name": "phpunit/php-timer",
+ "version": "8.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc",
+ "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "8.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "[email protected]",
+ "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",
+ "security": "https://github.com/sebastianbergmann/php-timer/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-timer/tree/8.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:59:38+00:00"
+ },
+ {
+ "name": "phpunit/phpunit",
+ "version": "12.1.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "f93ef2198df8d54b3195bcee381a33be51d8705e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f93ef2198df8d54b3195bcee381a33be51d8705e",
+ "reference": "f93ef2198df8d54b3195bcee381a33be51d8705e",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-xml": "*",
+ "ext-xmlwriter": "*",
+ "myclabs/deep-copy": "^1.13.1",
+ "phar-io/manifest": "^2.0.4",
+ "phar-io/version": "^3.2.1",
+ "php": ">=8.3",
+ "phpunit/php-code-coverage": "^12.2.1",
+ "phpunit/php-file-iterator": "^6.0.0",
+ "phpunit/php-invoker": "^6.0.0",
+ "phpunit/php-text-template": "^5.0.0",
+ "phpunit/php-timer": "^8.0.0",
+ "sebastian/cli-parser": "^4.0.0",
+ "sebastian/comparator": "^7.0.1",
+ "sebastian/diff": "^7.0.0",
+ "sebastian/environment": "^8.0.0",
+ "sebastian/exporter": "^7.0.0",
+ "sebastian/global-state": "^8.0.0",
+ "sebastian/object-enumerator": "^7.0.0",
+ "sebastian/type": "^6.0.2",
+ "sebastian/version": "^6.0.0",
+ "staabm/side-effects-detector": "^1.0.5"
+ },
+ "bin": [
+ "phpunit"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "12.1-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": "[email protected]",
+ "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/12.1.5"
+ },
+ "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-05-11T06:44:52+00:00"
+ },
+ {
+ "name": "sebastian/cli-parser",
+ "version": "4.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/cli-parser.git",
+ "reference": "6d584c727d9114bcdc14c86711cd1cad51778e7c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/6d584c727d9114bcdc14c86711cd1cad51778e7c",
+ "reference": "6d584c727d9114bcdc14c86711cd1cad51778e7c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.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": "[email protected]",
+ "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/4.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:53:50+00:00"
+ },
+ {
+ "name": "sebastian/comparator",
+ "version": "7.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/comparator.git",
+ "reference": "b478f34614f934e0291598d0c08cbaba9644bee5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/b478f34614f934e0291598d0c08cbaba9644bee5",
+ "reference": "b478f34614f934e0291598d0c08cbaba9644bee5",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-mbstring": "*",
+ "php": ">=8.3",
+ "sebastian/diff": "^7.0",
+ "sebastian/exporter": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "suggest": {
+ "ext-bcmath": "For comparing BcMath\\Number objects"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "[email protected]"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "[email protected]"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "[email protected]"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "[email protected]"
+ }
+ ],
+ "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/7.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-03-07T07:00:32+00:00"
+ },
+ {
+ "name": "sebastian/complexity",
+ "version": "5.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/complexity.git",
+ "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb",
+ "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^5.0",
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.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": "[email protected]",
+ "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/5.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:55:25+00:00"
+ },
+ {
+ "name": "sebastian/diff",
+ "version": "7.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/diff.git",
+ "reference": "7ab1ea946c012266ca32390913653d844ecd085f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f",
+ "reference": "7ab1ea946c012266ca32390913653d844ecd085f",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0",
+ "symfony/process": "^7.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "[email protected]"
+ },
+ {
+ "name": "Kore Nordmann",
+ "email": "[email protected]"
+ }
+ ],
+ "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/7.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:55:46+00:00"
+ },
+ {
+ "name": "sebastian/environment",
+ "version": "8.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/environment.git",
+ "reference": "8afe311eca49171bf95405cc0078be9a3821f9f2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8afe311eca49171bf95405cc0078be9a3821f9f2",
+ "reference": "8afe311eca49171bf95405cc0078be9a3821f9f2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "suggest": {
+ "ext-posix": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "8.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "[email protected]"
+ }
+ ],
+ "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/8.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:56:08+00:00"
+ },
+ {
+ "name": "sebastian/exporter",
+ "version": "7.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/exporter.git",
+ "reference": "76432aafc58d50691a00d86d0632f1217a47b688"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/76432aafc58d50691a00d86d0632f1217a47b688",
+ "reference": "76432aafc58d50691a00d86d0632f1217a47b688",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mbstring": "*",
+ "php": ">=8.3",
+ "sebastian/recursion-context": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "[email protected]"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "[email protected]"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "[email protected]"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "[email protected]"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "[email protected]"
+ }
+ ],
+ "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/7.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:56:42+00:00"
+ },
+ {
+ "name": "sebastian/global-state",
+ "version": "8.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/global-state.git",
+ "reference": "570a2aeb26d40f057af686d63c4e99b075fb6cbc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/570a2aeb26d40f057af686d63c4e99b075fb6cbc",
+ "reference": "570a2aeb26d40f057af686d63c4e99b075fb6cbc",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3",
+ "sebastian/object-reflector": "^5.0",
+ "sebastian/recursion-context": "^7.0"
+ },
+ "require-dev": {
+ "ext-dom": "*",
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "8.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "[email protected]"
+ }
+ ],
+ "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/8.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:56:59+00:00"
+ },
+ {
+ "name": "sebastian/lines-of-code",
+ "version": "4.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/lines-of-code.git",
+ "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/97ffee3bcfb5805568d6af7f0f893678fc076d2f",
+ "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^5.0",
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.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": "[email protected]",
+ "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/4.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:57:28+00:00"
+ },
+ {
+ "name": "sebastian/object-enumerator",
+ "version": "7.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+ "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894",
+ "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3",
+ "sebastian/object-reflector": "^5.0",
+ "sebastian/recursion-context": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "[email protected]"
+ }
+ ],
+ "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",
+ "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy",
+ "source": "https://github.com/sebastianbergmann/object-enumerator/tree/7.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:57:48+00:00"
+ },
+ {
+ "name": "sebastian/object-reflector",
+ "version": "5.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-reflector.git",
+ "reference": "4bfa827c969c98be1e527abd576533293c634f6a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a",
+ "reference": "4bfa827c969c98be1e527abd576533293c634f6a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.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": "[email protected]"
+ }
+ ],
+ "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",
+ "security": "https://github.com/sebastianbergmann/object-reflector/security/policy",
+ "source": "https://github.com/sebastianbergmann/object-reflector/tree/5.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:58:17+00:00"
+ },
+ {
+ "name": "sebastian/recursion-context",
+ "version": "7.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
+ "reference": "c405ae3a63e01b32eb71577f8ec1604e39858a7c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/c405ae3a63e01b32eb71577f8ec1604e39858a7c",
+ "reference": "c405ae3a63e01b32eb71577f8ec1604e39858a7c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "[email protected]"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "[email protected]"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "[email protected]"
+ }
+ ],
+ "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/7.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T05:00:01+00:00"
+ },
+ {
+ "name": "sebastian/type",
+ "version": "6.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/type.git",
+ "reference": "1d7cd6e514384c36d7a390347f57c385d4be6069"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/1d7cd6e514384c36d7a390347f57c385d4be6069",
+ "reference": "1d7cd6e514384c36d7a390347f57c385d4be6069",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.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": "[email protected]",
+ "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",
+ "security": "https://github.com/sebastianbergmann/type/security/policy",
+ "source": "https://github.com/sebastianbergmann/type/tree/6.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-03-18T13:37:31+00:00"
+ },
+ {
+ "name": "sebastian/version",
+ "version": "6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/version.git",
+ "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c",
+ "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "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": "[email protected]",
+ "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",
+ "security": "https://github.com/sebastianbergmann/version/security/policy",
+ "source": "https://github.com/sebastianbergmann/version/tree/6.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T05:00:38+00:00"
+ },
+ {
+ "name": "staabm/side-effects-detector",
+ "version": "1.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/staabm/side-effects-detector.git",
+ "reference": "d8334211a140ce329c13726d4a715adbddd0a163"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163",
+ "reference": "d8334211a140ce329c13726d4a715adbddd0a163",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": "^7.4 || ^8.0"
+ },
+ "require-dev": {
+ "phpstan/extension-installer": "^1.4.3",
+ "phpstan/phpstan": "^1.12.6",
+ "phpunit/phpunit": "^9.6.21",
+ "symfony/var-dumper": "^5.4.43",
+ "tomasvotruba/type-coverage": "1.0.0",
+ "tomasvotruba/unused-public": "1.0.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "lib/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "A static analysis tool to detect side effects in PHP code",
+ "keywords": [
+ "static analysis"
+ ],
+ "support": {
+ "issues": "https://github.com/staabm/side-effects-detector/issues",
+ "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/staabm",
+ "type": "github"
+ }
+ ],
+ "time": "2024-10-20T05:08:20+00:00"
+ },
+ {
+ "name": "theseer/tokenizer",
+ "version": "1.2.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/theseer/tokenizer.git",
+ "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+ "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+ "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": "[email protected]",
+ "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.2.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theseer",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-03T12:36:25+00:00"
+ }
+ ],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": {},
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": {
+ "php": "^8.4"
+ },
+ "platform-dev": {},
+ "plugin-api-version": "2.6.0"
+}
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000..80faffc
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
+ bootstrap="vendor/autoload.php"
+ cacheDirectory=".phpunit.cache"
+ executionOrder="depends,defects"
+ requireCoverageMetadata="true"
+ beStrictAboutCoverageMetadata="true"
+ beStrictAboutOutputDuringTests="true"
+ displayDetailsOnPhpunitDeprecations="true"
+ failOnPhpunitDeprecation="true"
+ failOnRisky="true"
+ failOnWarning="true"
+ colors="true">
+ <testsuites>
+ <testsuite name="Vehicle license China test suite">
+ <directory>tests</directory>
+ </testsuite>
+ </testsuites>
+
+ <source ignoreIndirectDeprecations="true" restrictNotices="true" restrictWarnings="true">
+ <include>
+ <directory>src</directory>
+ </include>
+ </source>
+</phpunit>
diff --git a/src/RegistrationNumber.php b/src/RegistrationNumber.php
new file mode 100644
index 0000000..6e729e3
--- /dev/null
+++ b/src/RegistrationNumber.php
@@ -0,0 +1,253 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Zhineng\VehicleLicenseChina;
+
+final readonly class RegistrationNumber
+{
+ /**
+ * Pairs of region name and authority codes.
+ *
+ * @var string[][]
+ */
+ private const array AUTHORITIES = [
+ '京' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ ],
+ '津' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ ],
+ '冀' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'R', 'T',
+ ],
+ '晋' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'H', 'J', 'K', 'L', 'M',
+ ],
+ '蒙' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M',
+ ],
+ '辽' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N',
+ 'P',
+ ],
+ '吉' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K',
+ ],
+ '黑' => [
+ 'A', 'L', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N',
+ 'P', 'R',
+ ],
+ '沪' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ ],
+ '苏' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N',
+ ],
+ '浙' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L',
+ ],
+ '皖' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N',
+ 'P', 'R', 'S',
+ ],
+ '闽' => [
+ 'A', 'K', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J',
+ ],
+ '赣' => [
+ 'A', 'M', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L',
+ ],
+ '鲁' => [
+ 'A', 'B', 'U', 'C', 'D', 'E', 'F', 'Y', 'G', 'V', 'H', 'J', 'K',
+ 'L', 'M', 'N', 'P', 'Q', 'R', 'S',
+ 'W', // Reserved for internal
+ ],
+ '豫' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N',
+ 'P', 'Q', 'R', 'S', 'U',
+ ],
+ '鄂' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N',
+ 'P', 'Q', 'R', 'S',
+ ],
+ '湘' => [
+ 'A', 'S', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M',
+ 'N', 'U',
+ ],
+ '粤' => [
+ 'A', 'B', 'C', 'D', 'E', 'X', 'Y', 'F', 'G', 'H', 'J', 'K', 'L',
+ 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'Z', // Reserved for internal
+ ],
+ '桂' => [
+ 'A', 'B', 'C', 'H', 'D', 'E', 'F', 'G', 'J', 'K', 'L', 'M', 'N',
+ 'P', 'R',
+ ],
+ '琼' => [
+ 'A', 'B', 'C', 'D', 'E', 'F',
+ ],
+ '渝' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ ],
+ '川' => [
+ 'A', 'G', 'B', 'C', 'D', 'E', 'F', 'H', 'J', 'K', 'L', 'M', 'Q',
+ 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ ],
+ '贵' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J',
+ ],
+ '云' => [
+ 'A', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P',
+ 'Q', 'R', 'S',
+ ],
+ '藏' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ ],
+ '陕' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'V',
+ ],
+ '甘' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N',
+ 'P',
+ ],
+ '青' => [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ ],
+ '宁' => [
+ 'A', 'B', 'C', 'E',
+ ],
+ '新' => [
+ 'A', 'B', 'C', 'E', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N',
+ 'P', 'Q', 'R',
+ ],
+ ];
+
+ /**
+ * @var string[]
+ */
+ private const array CLEAN_ENERGY_FIRST_LETTERS = [
+ 'D', 'A', 'B', 'C', 'E',
+ 'F', 'G', 'H', 'J', 'K',
+ ];
+
+ private function __construct(
+ public string $registrationNumber
+ ) {
+ //
+ }
+
+ public static function make(string $registrationNumber): static
+ {
+ static::validateAuthority($registrationNumber);
+ static::validateSequence($registrationNumber);
+
+ return new self($registrationNumber);
+ }
+
+ private static function validateAuthority(string $registrationNumber): void
+ {
+ $region = mb_substr($registrationNumber, 0, 1);
+ $authorities = self::AUTHORITIES[$region] ?? [];
+
+ if ($authorities === []) {
+ static::notValid($registrationNumber);
+ }
+
+ $code = mb_substr($registrationNumber, 1, 1);
+
+ if ($code === 'O') {
+ return;
+ }
+
+ if (! in_array($code, $authorities)) {
+ static::notValid($registrationNumber);
+ }
+ }
+
+ private static function validateSequence(string $registrationNumber): void
+ {
+ $sequence = mb_strtoupper(mb_substr($registrationNumber, 2));
+
+ $valid = match (mb_strlen($sequence)) {
+ 4, 5 => static::checkSequenceForGeneral($sequence),
+ 6 => static::checkSequenceForCleanEnergy($sequence),
+ default => static::notValid($registrationNumber),
+ };
+
+ if (! $valid) {
+ static::notValid($registrationNumber);
+ }
+ }
+
+ private static function checkSequenceForGeneral(string $sequence): bool
+ {
+ $letters = 0;
+
+ for ($i = 0; $i < strlen($sequence); $i++) {
+ $codepoint = mb_ord($sequence[$i]);
+
+ if ($codepoint === false) {
+ return false;
+ }
+
+ if ($codepoint >= ord('A') && $codepoint <= ord('Z')) {
+ if ($codepoint === ord('O') || $codepoint === ord('I')) {
+ return false;
+ }
+
+ $letters++;
+ } else if ($codepoint < ord('0') || $codepoint > ord('9')) {
+ return false;
+ }
+ }
+
+ return $letters <= 2;
+ }
+
+ private static function checkSequenceForCleanEnergy(string $sequence): bool
+ {
+ $sequence = mb_strtoupper($sequence);
+ $first = mb_substr($sequence, 0, 1);
+
+ if (! in_array($first, self::CLEAN_ENERGY_FIRST_LETTERS)) {
+ return false;
+ }
+
+ $second = mb_substr($sequence, 1, 1);
+ $second = mb_ord($second);
+
+ if ($second === false) {
+ return false;
+ }
+
+ if (($second < ord('A') || $second > ord('Z'))
+ && ($second < ord('0') || $second > ord('9'))) {
+ return false;
+ }
+
+ if ($second === ord('O') || $second === ord('I')) {
+ return false;
+ }
+
+ for ($i = 2; $i < strlen($sequence); $i++) {
+ $codepoint = mb_ord($sequence[$i]);
+
+ if ($codepoint < ord('0') || $codepoint > ord('9')) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static function notValid(string $registrationNumber): never
+ {
+ throw new RegistrationNumberException(sprintf(
+ 'The registration number "%s" is invalid.', $registrationNumber
+ ));
+ }
+}
diff --git a/src/RegistrationNumberException.php b/src/RegistrationNumberException.php
new file mode 100644
index 0000000..afd4448
--- /dev/null
+++ b/src/RegistrationNumberException.php
@@ -0,0 +1,10 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Zhineng\VehicleLicenseChina;
+
+final class RegistrationNumberException extends \Exception
+{
+ //
+}
diff --git a/tests/RegistrationNumberTest.php b/tests/RegistrationNumberTest.php
new file mode 100644
index 0000000..dfb3dd3
--- /dev/null
+++ b/tests/RegistrationNumberTest.php
@@ -0,0 +1,141 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Zhineng\VehicleLicenseChina\Tests;
+
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\TestCase;
+use Zhineng\VehicleLicenseChina\RegistrationNumber;
+use Zhineng\VehicleLicenseChina\RegistrationNumberException;
+
+#[CoversClass(RegistrationNumber::class)]
+final class RegistrationNumberTest extends TestCase
+{
+ #[DataProvider('provide_valid_registration_numbers')]
+ #[DataProvider('provide_valid_clean_energy_registration_numbers')]
+ public function test_valid_registration_number(string $registrationNumber): void
+ {
+ $instance = RegistrationNumber::make($registrationNumber);
+ $this->assertSame($registrationNumber, $instance->registrationNumber);
+ }
+
+ #[DataProvider('provide_invalid_registration_numbers')]
+ #[DataProvider('provide_invalid_clean_energy_registration_numbers')]
+ public function test_invalid_registration_number(string $registrationNumber): void
+ {
+ $this->expectException(RegistrationNumberException::class);
+ $this->expectExceptionMessage(sprintf('The registration number "%s" is invalid.', $registrationNumber));
+ RegistrationNumber::make($registrationNumber);
+ }
+
+ /**
+ * @return string[]
+ */
+ public static function provide_valid_registration_numbers(): array
+ {
+ return [
+ ['粤E1234'],
+ ['粤EA123'],
+ ['粤E1A23'],
+ ['粤E12A3'],
+ ['粤E123A'],
+ ['粤EAB12'],
+ ['粤E12AB'],
+ ['粤E1AB2'],
+ ['粤E1A2B'],
+ ['粤EA12B'],
+ ['粤EA1B2'],
+ ['粤E12345'],
+ ['粤EA1234'],
+ ['粤E1A234'],
+ ['粤E12A34'],
+ ['粤E123A4'],
+ ['粤E1234A'],
+
+ // Authority code "O" (the 2nd character) is for internal
+ ['粤O12345'],
+
+ // Authority code "Z" (the 2nd character) is for internal in Guangdong province
+ ['粤Z12345'],
+
+ // Authority code "W" (the 2nd character) is for internal in Shandong province
+ ['鲁W12345'],
+ ];
+ }
+
+ /**
+ * @return string[]
+ */
+ public static function provide_valid_clean_energy_registration_numbers(): array
+ {
+ return [
+ ['粤ED12345'],
+ ['粤EDA1234'],
+
+ // Authority code "O" (the 2nd character) is for internal
+ ['粤OD12345'],
+
+ // Authority code "Z" (the 2nd character) is for internal in Guangdong province
+ ['粤ZD12345'],
+
+ // Authority code "W" (the 2nd character) is for internal in Shandong province
+ ['鲁WD12345'],
+ ];
+ }
+
+ /**
+ * @return string[]
+ */
+ public static function provide_invalid_registration_numbers(): array
+ {
+ return [
+ ['假E12345'],
+ ['粤I12345'],
+ ['粤EABC1'],
+ ['粤E123+'],
+ ['粤E1234+'],
+ ['粤EABC12'],
+
+ // Sequence could not contain "O" or "I"
+ ['粤EO123'],
+ ['粤E1O23'],
+ ['粤E12O3'],
+ ['粤E123O'],
+ ['粤EI123'],
+ ['粤E1I23'],
+ ['粤E12I3'],
+ ['粤E123I'],
+ ['粤EO1234'],
+ ['粤E1O234'],
+ ['粤E12O34'],
+ ['粤E123O4'],
+ ['粤E1234O'],
+ ['粤EI1234'],
+ ['粤E1I234'],
+ ['粤E12I34'],
+ ['粤E123I4'],
+ ['粤E1234I'],
+ ];
+ }
+
+ /**
+ * @return string[]
+ */
+ public static function provide_invalid_clean_energy_registration_numbers(): array
+ {
+ return [
+ ['粤ED1A234'],
+ ['粤ED12A34'],
+ ['粤ED123A4'],
+ ['粤ED1234A'],
+ ['粤EZ12345'],
+ ['粤ED1234+'],
+
+ // Sequence could not contain "O" or "I"
+ ['粤EDO1234'],
+ ['粤EDI1234'],
+ ];
+ }
+}