phan 설치

This commit is contained in:
2020-05-01 15:26:54 +09:00
parent a529eba693
commit 51c96b4d04
991 changed files with 239131 additions and 14 deletions
+109 -11
View File
@@ -2,41 +2,139 @@
/**
* This configuration will be read and overlaid on top of the
* default configuration. Command line arguments will be applied
* default configuration. Command-line arguments will be applied
* after this file is read.
*/
return [
// Supported values: '7.0', '7.1', '7.2', null.
// If this is set to null,
// Supported values: `'5.6'`, `'7.0'`, `'7.1'`, `'7.2'`, `'7.3'`,
// `'7.4'`, `null`.
// If this is set to `null`,
// then Phan assumes the PHP version which is closest to the minor version
// of the php executable used to execute phan.
"target_php_version" => '7.2',
// of the php executable used to execute Phan.
//
// Note that the **only** effect of choosing `'5.6'` is to infer
// that functions removed in php 7.0 exist.
// (See `backward_compatibility_checks` for additional options)
"target_php_version" => '7.4',
'backward_compatibility_checks ' => false,
'ignore_undeclared_variables_in_global_scope' => false,
'minimum_severity'=>\Phan\Issue::SEVERITY_LOW,
'file_list' => [
'f_config/config.php',
'hwe/MYDB.php',
'hwe/lib.php',
'hwe/a_bestGeneral.php',
'hwe/a_emperior.php',
'hwe/a_emperior2.php',
'hwe/a_emperior_detail.php',
'hwe/a_genList.php',
'hwe/a_hallOfFame.php',
'hwe/a_history.php',
'hwe/a_kingdomList.php',
'hwe/a_npcList.php',
'hwe/a_status.php',
'hwe/a_traffic.php',
'hwe/a_vote.php',
'hwe/battle_simulator.php',
'hwe/b_auction.php',
'hwe/b_battleCenter.php',
'hwe/b_betting.php',
'hwe/b_chiefcenter.php',
'hwe/b_currentCity.php',
'hwe/b_dipcenter.php',
'hwe/b_diplomacy.php',
'hwe/b_genList.php',
'hwe/b_myBossInfo.php',
'hwe/b_myCityInfo.php',
'hwe/b_myGenInfo.php',
'hwe/b_myKingdomInfo.php',
'hwe/b_myPage.php',
'hwe/b_processing.php',
'hwe/b_tournament.php',
'hwe/b_troop.php',
'hwe/c_auction.php',
'hwe/c_die_immediately.php',
'hwe/c_dipcenter.php',
'hwe/c_tournament.php',
'hwe/c_vacation.php',
'hwe/c_vote.php',
'hwe/func.php',
'hwe/func_auction.php',
'hwe/func_command.php',
'hwe/func_converter.php',
'hwe/func_diplomacy.php',
'hwe/func_gamerule.php',
'hwe/func_history.php',
'hwe/func_legacy.php',
'hwe/func_map.php',
'hwe/func_message.php',
'hwe/func_process_chief.php',
'hwe/func_process.php',
'hwe/func_string.php',
'hwe/func_template.php',
'hwe/func_time_event.php',
'hwe/func_tournament.php',
'hwe/index.php',
'hwe/install.php',
'hwe/install_db.php',
'hwe/join.php',
'hwe/join_post.php',
'hwe/j_adjust_icon.php',
'hwe/j_autoreset.php',
'hwe/j_basic_info.php',
'hwe/j_betting.php',
'hwe/j_board_article_add.php',
'hwe/j_board_comment_add.php',
'hwe/j_board_get_articles.php',
'hwe/j_chief_turn.php',
'hwe/j_diplomacy_destroy_letter.php',
'hwe/j_diplomacy_get_letter.php',
'hwe/j_diplomacy_respond_letter.php',
'hwe/j_diplomacy_rollback_letter.php',
'hwe/j_diplomacy_send_letter.php',
'hwe/j_general_set_permission.php',
'hwe/j_general_turn.php',
'hwe/j_getChiefTurn.php',
'hwe/j_get_city_list.php',
'hwe/j_get_general_list.php',
'hwe/j_get_nation_general_list.php',
'hwe/j_get_reserved_command.php',
'hwe/j_get_select_npc_token.php',
'hwe/j_image_upload.php',
'hwe/j_install.php',
'hwe/j_install_db.php',
'hwe/j_load_scenarios.php',
'hwe/j_map.php',
'hwe/j_map_history.php',
'hwe/j_msg_contact_list.php',
'hwe/j_msg_decide_opt.php',
'hwe/j_msg_delete.php',
'hwe/j_msg_get_old.php',
'hwe/j_msg_get_recent.php',
'hwe/j_msg_submit.php',
'hwe/j_myBossInfo.php',
'hwe/j_select_npc.php',
'hwe/j_server_basic_info.php',
'hwe/j_set_chief_command.php',
'hwe/j_set_general_command.php',
'hwe/j_simulate_battle.php',
'hwe/j_troop.php',
'hwe/lib.php',
'hwe/process_war.php',
'hwe/func.php'
'hwe/select_npc.php',
'hwe/t_board.php',
'hwe/t_diplomacy.php',
'hwe/_119.php',
'hwe/_119_b.php',
'hwe/_admin1.php',
'hwe/_admin1_submit.php',
'hwe/_admin2.php',
'hwe/_admin2_submit.php',
'hwe/_admin4.php',
'hwe/_admin4_submit.php',
'hwe/_admin5.php',
'hwe/_admin5_submit.php',
'hwe/_admin6.php',
'hwe/_admin7.php',
'hwe/_admin8.php',
'hwe/_admin_force_rehall.php',
],
// A list of directories that should be parsed for class and
+2 -1
View File
@@ -25,7 +25,8 @@
"symfony/lock": "^4.1",
"ezyang/htmlpurifier": "^4.10",
"xemlock/htmlpurifier-html5": "^0.1.7",
"catfan/medoo": "^1.5"
"catfan/medoo": "^1.5",
"phan/phan": "^2.7"
},
"autoload": {
"psr-4": {
Generated
+1055 -2
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "b5b5695ed0b1b04fa672f99972d8caad",
"content-hash": "7343763bee946f23e755edecd14d6b2c",
"packages": [
{
"name": "brandonwamboldt/utilphp",
@@ -112,6 +112,117 @@
],
"time": "2019-12-19T05:04:34+00:00"
},
{
"name": "composer/semver",
"version": "1.5.1",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de",
"reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.5 || ^5.0.5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.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"
],
"time": "2020-01-13T12:06:48+00:00"
},
{
"name": "composer/xdebug-handler",
"version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/composer/xdebug-handler.git",
"reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/1ab9842d69e64fb3a01be6b656501032d1b78cb7",
"reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0 || ^8.0",
"psr/log": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8"
},
"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"
],
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
}
],
"time": "2020-03-01T12:26:26+00:00"
},
{
"name": "ezyang/htmlpurifier",
"version": "v4.12.0",
@@ -159,6 +270,47 @@
],
"time": "2019-10-28T03:44:26+00:00"
},
{
"name": "felixfbecker/advanced-json-rpc",
"version": "v3.1.1",
"source": {
"type": "git",
"url": "https://github.com/felixfbecker/php-advanced-json-rpc.git",
"reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/0ed363f8de17d284d479ec813c9ad3f6834b5c40",
"reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40",
"shasum": ""
},
"require": {
"netresearch/jsonmapper": "^1.0 || ^2.0",
"php": ">=7.0",
"phpdocumentor/reflection-docblock": "^4.0.0 || ^5.0.0"
},
"require-dev": {
"phpunit/phpunit": "^6.0.0"
},
"type": "library",
"autoload": {
"psr-4": {
"AdvancedJsonRpc\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"ISC"
],
"authors": [
{
"name": "Felix Becker",
"email": "felix.b@outlook.com"
}
],
"description": "A more advanced JSONRPC implementation",
"time": "2020-03-11T15:21:41+00:00"
},
{
"name": "firephp/firephp-core",
"version": "v0.4.0",
@@ -439,6 +591,47 @@
],
"time": "2016-12-28T00:14:17+00:00"
},
{
"name": "microsoft/tolerant-php-parser",
"version": "v0.0.20",
"source": {
"type": "git",
"url": "https://github.com/microsoft/tolerant-php-parser.git",
"reference": "c5e2bf5d8c9f4f27eef1370bd39ea2d1f374eeb4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/microsoft/tolerant-php-parser/zipball/c5e2bf5d8c9f4f27eef1370bd39ea2d1f374eeb4",
"reference": "c5e2bf5d8c9f4f27eef1370bd39ea2d1f374eeb4",
"shasum": ""
},
"require": {
"php": ">=7.0"
},
"require-dev": {
"phpunit/phpunit": "^6.4"
},
"type": "library",
"autoload": {
"psr-4": {
"Microsoft\\PhpParser\\": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Rob Lourens",
"email": "roblou@microsoft.com"
}
],
"description": "Tolerant PHP-to-AST parser designed for IDE usage scenarios",
"time": "2020-02-18T02:57:19+00:00"
},
{
"name": "monolog/monolog",
"version": "1.25.3",
@@ -517,6 +710,52 @@
],
"time": "2019-12-20T14:15:16+00:00"
},
{
"name": "netresearch/jsonmapper",
"version": "v2.1.0",
"source": {
"type": "git",
"url": "https://github.com/cweiske/jsonmapper.git",
"reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/e0f1e33a71587aca81be5cffbb9746510e1fe04e",
"reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-pcre": "*",
"ext-reflection": "*",
"ext-spl": "*",
"php": ">=5.6"
},
"require-dev": {
"phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.4 || ~7.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",
"time": "2020-04-16T18:48:43+00:00"
},
{
"name": "pguardiario/phpuri",
"version": "1.0",
@@ -541,6 +780,80 @@
"description": "A php library for converting relative urls to absolute.",
"time": "2015-05-24T09:13:17+00:00"
},
{
"name": "phan/phan",
"version": "2.7.1",
"source": {
"type": "git",
"url": "https://github.com/phan/phan.git",
"reference": "67c51bb1593e5c30271fc16d691b82e318b90b77"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phan/phan/zipball/67c51bb1593e5c30271fc16d691b82e318b90b77",
"reference": "67c51bb1593e5c30271fc16d691b82e318b90b77",
"shasum": ""
},
"require": {
"composer/semver": "^1.4",
"composer/xdebug-handler": "^1.3.2",
"ext-filter": "*",
"ext-json": "*",
"ext-tokenizer": "*",
"felixfbecker/advanced-json-rpc": "^3.0.4",
"microsoft/tolerant-php-parser": "0.0.20",
"netresearch/jsonmapper": "^1.6.0|^2.0",
"php": "^7.1.0",
"sabre/event": "^5.0",
"symfony/console": "^2.3|^3.0|^4.0|^5.0",
"symfony/polyfill-mbstring": "^1.11.0",
"symfony/polyfill-php72": "^1.15"
},
"require-dev": {
"brianium/paratest": "^4.0.0",
"phpunit/phpunit": "^7.5.0"
},
"suggest": {
"ext-ast": "Needed for parsing ASTs (unless --use-fallback-parser is used). 1.0.1+ is needed, 1.0.6+ is recommended.",
"ext-iconv": "Either iconv or mbstring is needed to ensure issue messages are valid utf-8",
"ext-igbinary": "Improves performance of polyfill when ext-ast is unavailable",
"ext-mbstring": "Either iconv or mbstring is needed to ensure issue messages are valid utf-8",
"ext-tokenizer": "Needed for fallback/polyfill parser support and file/line-based suppressions."
},
"bin": [
"phan",
"phan_client",
"tocheckstyle"
],
"type": "project",
"autoload": {
"psr-4": {
"Phan\\": "src/Phan"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Tyson Andre"
},
{
"name": "Rasmus Lerdorf"
},
{
"name": "Andrew S. Morrison"
}
],
"description": "A static analyzer for PHP",
"keywords": [
"analyzer",
"php",
"static"
],
"time": "2020-04-12T01:25:29+00:00"
},
{
"name": "php-extended/php-system",
"version": "1.4.0",
@@ -625,6 +938,203 @@
],
"time": "2018-06-07T06:04:58+00:00"
},
{
"name": "phpdocumentor/reflection-common",
"version": "2.1.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
"reference": "6568f4687e5b41b054365f9ae03fcb1ed5f2069b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/6568f4687e5b41b054365f9ae03fcb1ed5f2069b",
"reference": "6568f4687e5b41b054365f9ae03fcb1ed5f2069b",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "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"
],
"time": "2020-04-27T09:25:28+00:00"
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "5.1.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e",
"reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e",
"shasum": ""
},
"require": {
"ext-filter": "^7.1",
"php": "^7.2",
"phpdocumentor/reflection-common": "^2.0",
"phpdocumentor/type-resolver": "^1.0",
"webmozart/assert": "^1"
},
"require-dev": {
"doctrine/instantiator": "^1",
"mockery/mockery": "^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": "account@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.",
"time": "2020-02-22T12:28:44+00:00"
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "7462d5f123dfc080dfdf26897032a6513644fc95"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/7462d5f123dfc080dfdf26897032a6513644fc95",
"reference": "7462d5f123dfc080dfdf26897032a6513644fc95",
"shasum": ""
},
"require": {
"php": "^7.2",
"phpdocumentor/reflection-common": "^2.0"
},
"require-dev": {
"ext-tokenizer": "^7.2",
"mockery/mockery": "~1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.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",
"time": "2020-02-18T18:59:58+00:00"
},
{
"name": "psr/container",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/container.git",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://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"
],
"time": "2017-02-14T16:28:37+00:00"
},
{
"name": "psr/http-message",
"version": "1.0.1",
@@ -762,6 +1272,66 @@
"description": "A polyfill for getallheaders.",
"time": "2019-03-08T08:55:37+00:00"
},
{
"name": "sabre/event",
"version": "5.1.0",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/event.git",
"reference": "d00a17507af0e7544cfe17096372f5d733e3b276"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/event/zipball/d00a17507af0e7544cfe17096372f5d733e3b276",
"reference": "d00a17507af0e7544cfe17096372f5d733e3b276",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2.16.1",
"phpunit/phpunit": "^7 || ^8"
},
"type": "library",
"autoload": {
"psr-4": {
"Sabre\\Event\\": "lib/"
},
"files": [
"lib/coroutine.php",
"lib/Loop/functions.php",
"lib/Promise/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
}
],
"description": "sabre/event is a library for lightweight event-based programming",
"homepage": "http://sabre.io/event/",
"keywords": [
"EventEmitter",
"async",
"coroutine",
"eventloop",
"events",
"hooks",
"plugin",
"promise",
"reactor",
"signal"
],
"time": "2020-01-31T18:52:29+00:00"
},
{
"name": "scssphp/scssphp",
"version": "1.0.6",
@@ -866,6 +1436,96 @@
],
"time": "2014-06-16T22:40:22+00:00"
},
{
"name": "symfony/console",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "5fa1caadc8cdaa17bcfb25219f3b53fe294a9935"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/5fa1caadc8cdaa17bcfb25219f3b53fe294a9935",
"reference": "5fa1caadc8cdaa17bcfb25219f3b53fe294a9935",
"shasum": ""
},
"require": {
"php": "^7.2.5",
"symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php73": "^1.8",
"symfony/service-contracts": "^1.1|^2"
},
"conflict": {
"symfony/dependency-injection": "<4.4",
"symfony/event-dispatcher": "<4.4",
"symfony/lock": "<4.4",
"symfony/process": "<4.4"
},
"provide": {
"psr/log-implementation": "1.0"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "^4.4|^5.0",
"symfony/dependency-injection": "^4.4|^5.0",
"symfony/event-dispatcher": "^4.4|^5.0",
"symfony/lock": "^4.4|^5.0",
"symfony/process": "^4.4|^5.0",
"symfony/var-dumper": "^4.4|^5.0"
},
"suggest": {
"psr/log": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/lock": "",
"symfony/process": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0-dev"
}
},
"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": "Symfony Console Component",
"homepage": "https://symfony.com",
"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": "2020-03-30T11:42:42+00:00"
},
{
"name": "symfony/lock",
"version": "v4.4.3",
@@ -932,6 +1592,350 @@
],
"time": "2020-01-04T13:00:46+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.15.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/4719fa9c18b0464d399f1a63bf624b42b6fa8d14",
"reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.15-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
},
"files": [
"bootstrap.php"
]
},
"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"
],
"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": "2020-02-27T09:26:54+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.15.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac",
"reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.15-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
},
"files": [
"bootstrap.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": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"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": "2020-03-09T19:04:49+00:00"
},
{
"name": "symfony/polyfill-php72",
"version": "v1.15.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
"reference": "37b0976c78b94856543260ce09b460a7bc852747"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/37b0976c78b94856543260ce09b460a7bc852747",
"reference": "37b0976c78b94856543260ce09b460a7bc852747",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.15-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Php72\\": ""
},
"files": [
"bootstrap.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": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"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": "2020-02-27T09:26:54+00:00"
},
{
"name": "symfony/polyfill-php73",
"version": "v1.15.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php73.git",
"reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7",
"reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.15-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Php73\\": ""
},
"files": [
"bootstrap.php"
],
"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"
],
"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": "2020-02-27T09:26:54+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v2.0.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "144c5e51266b281231e947b51223ba14acf1a749"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/144c5e51266b281231e947b51223ba14acf1a749",
"reference": "144c5e51266b281231e947b51223ba14acf1a749",
"shasum": ""
},
"require": {
"php": "^7.2.5",
"psr/container": "^1.0"
},
"suggest": {
"symfony/service-implementation": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Service\\": ""
}
},
"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"
],
"time": "2019-11-18T17:27:11+00:00"
},
{
"name": "vlucas/valitron",
"version": "v1.4.7",
@@ -981,6 +1985,54 @@
],
"time": "2019-08-29T19:49:43+00:00"
},
{
"name": "webmozart/assert",
"version": "1.8.0",
"source": {
"type": "git",
"url": "https://github.com/webmozart/assert.git",
"reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozart/assert/zipball/ab2cb0b3b559010b75981b1bdce728da3ee90ad6",
"reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6",
"shasum": ""
},
"require": {
"php": "^5.3.3 || ^7.0",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
"vimeo/psalm": "<3.9.1"
},
"require-dev": {
"phpunit/phpunit": "^4.8.36 || ^7.5.13"
},
"type": "library",
"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"
],
"time": "2020-04-18T12:12:48+00:00"
},
{
"name": "xemlock/htmlpurifier-html5",
"version": "v0.1.11",
@@ -1043,5 +2095,6 @@
"platform-dev": [],
"platform-overrides": {
"php": "7.3"
}
},
"plugin-api-version": "1.1.0"
}
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env sh
dir=$(cd "${0%[/\\]*}" > /dev/null; cd "../phan/phan" && pwd)
if [ -d /proc/cygdrive ]; then
case $(which php) in
$(readlink -n /proc/cygdrive)/*)
# We are in Cygwin using Windows php, so the path must be translated
dir=$(cygpath -m "$dir");
;;
esac
fi
"${dir}/phan" "$@"
+4
View File
@@ -0,0 +1,4 @@
@ECHO OFF
setlocal DISABLEDELAYEDEXPANSION
SET BIN_TARGET=%~dp0/../phan/phan/phan
php "%BIN_TARGET%" %*
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env sh
dir=$(cd "${0%[/\\]*}" > /dev/null; cd "../phan/phan" && pwd)
if [ -d /proc/cygdrive ]; then
case $(which php) in
$(readlink -n /proc/cygdrive)/*)
# We are in Cygwin using Windows php, so the path must be translated
dir=$(cygpath -m "$dir");
;;
esac
fi
"${dir}/phan_client" "$@"
+4
View File
@@ -0,0 +1,4 @@
@ECHO OFF
setlocal DISABLEDELAYEDEXPANSION
SET BIN_TARGET=%~dp0/../phan/phan/phan_client
php "%BIN_TARGET%" %*
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env sh
dir=$(cd "${0%[/\\]*}" > /dev/null; cd "../phan/phan" && pwd)
if [ -d /proc/cygdrive ]; then
case $(which php) in
$(readlink -n /proc/cygdrive)/*)
# We are in Cygwin using Windows php, so the path must be translated
dir=$(cygpath -m "$dir");
;;
esac
fi
"${dir}/tocheckstyle" "$@"
+4
View File
@@ -0,0 +1,4 @@
@ECHO OFF
setlocal DISABLEDELAYEDEXPANSION
SET BIN_TARGET=%~dp0/../phan/phan/tocheckstyle
php "%BIN_TARGET%" %*
+1
View File
@@ -43,6 +43,7 @@ return array(
'HTMLPurifier_HTMLModule_HTML5_SafeScripting' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/SafeScripting.php',
'HTMLPurifier_HTMLModule_HTML5_Scripting' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Scripting.php',
'HTMLPurifier_HTMLModule_HTML5_Text' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Text.php',
'JsonException' => $vendorDir . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
'MeekroDB' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php',
'MeekroDBEval' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php',
'MeekroDBException' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php',
+7
View File
@@ -6,10 +6,17 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',
'2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
'2b9d0f43f9552984cfa82fee95491826' => $vendorDir . '/sabre/event/lib/coroutine.php',
'd81bab31d3feb45bfe2f283ea3c8fdf7' => $vendorDir . '/sabre/event/lib/Loop/functions.php',
'a1cce3d26cc15c00fcd0b3354bd72c88' => $vendorDir . '/sabre/event/lib/Promise/functions.php',
'25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
'5b154887902198b16314243c6e0e3e19' => $vendorDir . '/pguardiario/phpuri/phpuri.php',
'870dc64919afa8b0f700701bb2c6a783' => $baseDir . '/f_config/config.php',
+1
View File
@@ -7,5 +7,6 @@ $baseDir = dirname($vendorDir);
return array(
'utilphp\\' => array($vendorDir . '/brandonwamboldt/utilphp/src'),
'JsonMapper' => array($vendorDir . '/netresearch/jsonmapper/src'),
'HTMLPurifier' => array($vendorDir . '/ezyang/htmlpurifier/library'),
);
+15
View File
@@ -7,18 +7,33 @@ $baseDir = dirname($vendorDir);
return array(
'sammo\\' => array($baseDir . '/src/sammo'),
'phpDocumentor\\Reflection\\' => array($vendorDir . '/phpdocumentor/reflection-common/src', $vendorDir . '/phpdocumentor/reflection-docblock/src', $vendorDir . '/phpdocumentor/type-resolver/src'),
'kakao\\' => array($baseDir . '/src/kakao'),
'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'),
'Valitron\\' => array($vendorDir . '/vlucas/valitron/src/Valitron'),
'Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'),
'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
'Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'),
'Symfony\\Component\\Lock\\' => array($vendorDir . '/symfony/lock'),
'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'),
'ScssPhp\\ScssPhp\\' => array($vendorDir . '/scssphp/scssphp/src'),
'Sabre\\Event\\' => array($vendorDir . '/sabre/event/lib'),
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
'PhpExtended\\Tail\\' => array($vendorDir . '/php-extended/php-tail/src'),
'PhpExtended\\System\\' => array($vendorDir . '/php-extended/php-system/src'),
'Phan\\' => array($vendorDir . '/phan/phan/src/Phan'),
'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
'Microsoft\\PhpParser\\' => array($vendorDir . '/microsoft/tolerant-php-parser/src'),
'Medoo\\' => array($vendorDir . '/catfan/medoo/src'),
'League\\Plates\\' => array($vendorDir . '/league/plates/src'),
'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
'Composer\\XdebugHandler\\' => array($vendorDir . '/composer/xdebug-handler/src'),
'Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'),
'AdvancedJsonRpc\\' => array($vendorDir . '/felixfbecker/advanced-json-rpc/lib'),
);
+3
View File
@@ -13,6 +13,9 @@ class ComposerAutoloaderInit67b09c83b85c3bc0027caefe5bba171a
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
+104
View File
@@ -7,10 +7,17 @@ namespace Composer\Autoload;
class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
{
public static $files = array (
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php',
'2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
'2b9d0f43f9552984cfa82fee95491826' => __DIR__ . '/..' . '/sabre/event/lib/coroutine.php',
'd81bab31d3feb45bfe2f283ea3c8fdf7' => __DIR__ . '/..' . '/sabre/event/lib/Loop/functions.php',
'a1cce3d26cc15c00fcd0b3354bd72c88' => __DIR__ . '/..' . '/sabre/event/lib/Promise/functions.php',
'25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
'5b154887902198b16314243c6e0e3e19' => __DIR__ . '/..' . '/pguardiario/phpuri/phpuri.php',
'870dc64919afa8b0f700701bb2c6a783' => __DIR__ . '/../..' . '/f_config/config.php',
@@ -21,29 +28,47 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
array (
'sammo\\' => 6,
),
'p' =>
array (
'phpDocumentor\\Reflection\\' => 25,
),
'k' =>
array (
'kakao\\' => 6,
),
'W' =>
array (
'Webmozart\\Assert\\' => 17,
),
'V' =>
array (
'Valitron\\' => 9,
),
'S' =>
array (
'Symfony\\Polyfill\\Php73\\' => 23,
'Symfony\\Polyfill\\Php72\\' => 23,
'Symfony\\Polyfill\\Mbstring\\' => 26,
'Symfony\\Polyfill\\Ctype\\' => 23,
'Symfony\\Contracts\\Service\\' => 26,
'Symfony\\Component\\Lock\\' => 23,
'Symfony\\Component\\Console\\' => 26,
'ScssPhp\\ScssPhp\\' => 16,
'Sabre\\Event\\' => 12,
),
'P' =>
array (
'Psr\\Log\\' => 8,
'Psr\\Http\\Message\\' => 17,
'Psr\\Container\\' => 14,
'PhpExtended\\Tail\\' => 17,
'PhpExtended\\System\\' => 19,
'Phan\\' => 5,
),
'M' =>
array (
'Monolog\\' => 8,
'Microsoft\\PhpParser\\' => 20,
'Medoo\\' => 6,
),
'L' =>
@@ -56,6 +81,15 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
'GuzzleHttp\\Promise\\' => 19,
'GuzzleHttp\\' => 11,
),
'C' =>
array (
'Composer\\XdebugHandler\\' => 23,
'Composer\\Semver\\' => 16,
),
'A' =>
array (
'AdvancedJsonRpc\\' => 16,
),
);
public static $prefixDirsPsr4 = array (
@@ -63,22 +97,60 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
array (
0 => __DIR__ . '/../..' . '/src/sammo',
),
'phpDocumentor\\Reflection\\' =>
array (
0 => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src',
1 => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src',
2 => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src',
),
'kakao\\' =>
array (
0 => __DIR__ . '/../..' . '/src/kakao',
),
'Webmozart\\Assert\\' =>
array (
0 => __DIR__ . '/..' . '/webmozart/assert/src',
),
'Valitron\\' =>
array (
0 => __DIR__ . '/..' . '/vlucas/valitron/src/Valitron',
),
'Symfony\\Polyfill\\Php73\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php73',
),
'Symfony\\Polyfill\\Php72\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php72',
),
'Symfony\\Polyfill\\Mbstring\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
),
'Symfony\\Polyfill\\Ctype\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
),
'Symfony\\Contracts\\Service\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/service-contracts',
),
'Symfony\\Component\\Lock\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/lock',
),
'Symfony\\Component\\Console\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/console',
),
'ScssPhp\\ScssPhp\\' =>
array (
0 => __DIR__ . '/..' . '/scssphp/scssphp/src',
),
'Sabre\\Event\\' =>
array (
0 => __DIR__ . '/..' . '/sabre/event/lib',
),
'Psr\\Log\\' =>
array (
0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
@@ -87,6 +159,10 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
array (
0 => __DIR__ . '/..' . '/psr/http-message/src',
),
'Psr\\Container\\' =>
array (
0 => __DIR__ . '/..' . '/psr/container/src',
),
'PhpExtended\\Tail\\' =>
array (
0 => __DIR__ . '/..' . '/php-extended/php-tail/src',
@@ -95,10 +171,18 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
array (
0 => __DIR__ . '/..' . '/php-extended/php-system/src',
),
'Phan\\' =>
array (
0 => __DIR__ . '/..' . '/phan/phan/src/Phan',
),
'Monolog\\' =>
array (
0 => __DIR__ . '/..' . '/monolog/monolog/src/Monolog',
),
'Microsoft\\PhpParser\\' =>
array (
0 => __DIR__ . '/..' . '/microsoft/tolerant-php-parser/src',
),
'Medoo\\' =>
array (
0 => __DIR__ . '/..' . '/catfan/medoo/src',
@@ -119,6 +203,18 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
array (
0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src',
),
'Composer\\XdebugHandler\\' =>
array (
0 => __DIR__ . '/..' . '/composer/xdebug-handler/src',
),
'Composer\\Semver\\' =>
array (
0 => __DIR__ . '/..' . '/composer/semver/src',
),
'AdvancedJsonRpc\\' =>
array (
0 => __DIR__ . '/..' . '/felixfbecker/advanced-json-rpc/lib',
),
);
public static $prefixesPsr0 = array (
@@ -129,6 +225,13 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
0 => __DIR__ . '/..' . '/brandonwamboldt/utilphp/src',
),
),
'J' =>
array (
'JsonMapper' =>
array (
0 => __DIR__ . '/..' . '/netresearch/jsonmapper/src',
),
),
'H' =>
array (
'HTMLPurifier' =>
@@ -176,6 +279,7 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
'HTMLPurifier_HTMLModule_HTML5_SafeScripting' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/SafeScripting.php',
'HTMLPurifier_HTMLModule_HTML5_Scripting' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Scripting.php',
'HTMLPurifier_HTMLModule_HTML5_Text' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Text.php',
'JsonException' => __DIR__ . '/..' . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
'MeekroDB' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php',
'MeekroDBEval' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php',
'MeekroDBException' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php',
+1088
View File
@@ -109,6 +109,121 @@
"sqlite"
]
},
{
"name": "composer/semver",
"version": "1.5.1",
"version_normalized": "1.5.1.0",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de",
"reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.5 || ^5.0.5"
},
"time": "2020-01-13T12:06:48+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"installation-source": "dist",
"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"
]
},
{
"name": "composer/xdebug-handler",
"version": "1.4.1",
"version_normalized": "1.4.1.0",
"source": {
"type": "git",
"url": "https://github.com/composer/xdebug-handler.git",
"reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/1ab9842d69e64fb3a01be6b656501032d1b78cb7",
"reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0 || ^8.0",
"psr/log": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8"
},
"time": "2020-03-01T12:26:26+00:00",
"type": "library",
"installation-source": "dist",
"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"
],
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
}
]
},
{
"name": "ezyang/htmlpurifier",
"version": "v4.12.0",
@@ -158,6 +273,49 @@
"html"
]
},
{
"name": "felixfbecker/advanced-json-rpc",
"version": "v3.1.1",
"version_normalized": "3.1.1.0",
"source": {
"type": "git",
"url": "https://github.com/felixfbecker/php-advanced-json-rpc.git",
"reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/0ed363f8de17d284d479ec813c9ad3f6834b5c40",
"reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40",
"shasum": ""
},
"require": {
"netresearch/jsonmapper": "^1.0 || ^2.0",
"php": ">=7.0",
"phpdocumentor/reflection-docblock": "^4.0.0 || ^5.0.0"
},
"require-dev": {
"phpunit/phpunit": "^6.0.0"
},
"time": "2020-03-11T15:21:41+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"AdvancedJsonRpc\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"ISC"
],
"authors": [
{
"name": "Felix Becker",
"email": "felix.b@outlook.com"
}
],
"description": "A more advanced JSONRPC implementation"
},
{
"name": "firephp/firephp-core",
"version": "v0.4.0",
@@ -448,6 +606,49 @@
"views"
]
},
{
"name": "microsoft/tolerant-php-parser",
"version": "v0.0.20",
"version_normalized": "0.0.20.0",
"source": {
"type": "git",
"url": "https://github.com/microsoft/tolerant-php-parser.git",
"reference": "c5e2bf5d8c9f4f27eef1370bd39ea2d1f374eeb4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/microsoft/tolerant-php-parser/zipball/c5e2bf5d8c9f4f27eef1370bd39ea2d1f374eeb4",
"reference": "c5e2bf5d8c9f4f27eef1370bd39ea2d1f374eeb4",
"shasum": ""
},
"require": {
"php": ">=7.0"
},
"require-dev": {
"phpunit/phpunit": "^6.4"
},
"time": "2020-02-18T02:57:19+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Microsoft\\PhpParser\\": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Rob Lourens",
"email": "roblou@microsoft.com"
}
],
"description": "Tolerant PHP-to-AST parser designed for IDE usage scenarios"
},
{
"name": "monolog/monolog",
"version": "1.25.3",
@@ -528,6 +729,54 @@
"psr-3"
]
},
{
"name": "netresearch/jsonmapper",
"version": "v2.1.0",
"version_normalized": "2.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/cweiske/jsonmapper.git",
"reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/e0f1e33a71587aca81be5cffbb9746510e1fe04e",
"reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-pcre": "*",
"ext-reflection": "*",
"ext-spl": "*",
"php": ">=5.6"
},
"require-dev": {
"phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.4 || ~7.0",
"squizlabs/php_codesniffer": "~3.5"
},
"time": "2020-04-16T18:48:43+00:00",
"type": "library",
"installation-source": "dist",
"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"
},
{
"name": "pguardiario/phpuri",
"version": "1.0",
@@ -554,6 +803,82 @@
"notification-url": "https://packagist.org/downloads/",
"description": "A php library for converting relative urls to absolute."
},
{
"name": "phan/phan",
"version": "2.7.1",
"version_normalized": "2.7.1.0",
"source": {
"type": "git",
"url": "https://github.com/phan/phan.git",
"reference": "67c51bb1593e5c30271fc16d691b82e318b90b77"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phan/phan/zipball/67c51bb1593e5c30271fc16d691b82e318b90b77",
"reference": "67c51bb1593e5c30271fc16d691b82e318b90b77",
"shasum": ""
},
"require": {
"composer/semver": "^1.4",
"composer/xdebug-handler": "^1.3.2",
"ext-filter": "*",
"ext-json": "*",
"ext-tokenizer": "*",
"felixfbecker/advanced-json-rpc": "^3.0.4",
"microsoft/tolerant-php-parser": "0.0.20",
"netresearch/jsonmapper": "^1.6.0|^2.0",
"php": "^7.1.0",
"sabre/event": "^5.0",
"symfony/console": "^2.3|^3.0|^4.0|^5.0",
"symfony/polyfill-mbstring": "^1.11.0",
"symfony/polyfill-php72": "^1.15"
},
"require-dev": {
"brianium/paratest": "^4.0.0",
"phpunit/phpunit": "^7.5.0"
},
"suggest": {
"ext-ast": "Needed for parsing ASTs (unless --use-fallback-parser is used). 1.0.1+ is needed, 1.0.6+ is recommended.",
"ext-iconv": "Either iconv or mbstring is needed to ensure issue messages are valid utf-8",
"ext-igbinary": "Improves performance of polyfill when ext-ast is unavailable",
"ext-mbstring": "Either iconv or mbstring is needed to ensure issue messages are valid utf-8",
"ext-tokenizer": "Needed for fallback/polyfill parser support and file/line-based suppressions."
},
"time": "2020-04-12T01:25:29+00:00",
"bin": [
"phan",
"phan_client",
"tocheckstyle"
],
"type": "project",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Phan\\": "src/Phan"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Tyson Andre"
},
{
"name": "Rasmus Lerdorf"
},
{
"name": "Andrew S. Morrison"
}
],
"description": "A static analyzer for PHP",
"keywords": [
"analyzer",
"php",
"static"
]
},
{
"name": "php-extended/php-system",
"version": "1.4.0",
@@ -642,6 +967,211 @@
"tail"
]
},
{
"name": "phpdocumentor/reflection-common",
"version": "2.1.0",
"version_normalized": "2.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
"reference": "6568f4687e5b41b054365f9ae03fcb1ed5f2069b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/6568f4687e5b41b054365f9ae03fcb1ed5f2069b",
"reference": "6568f4687e5b41b054365f9ae03fcb1ed5f2069b",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"time": "2020-04-27T09:25:28+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"installation-source": "dist",
"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"
]
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "5.1.0",
"version_normalized": "5.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e",
"reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e",
"shasum": ""
},
"require": {
"ext-filter": "^7.1",
"php": "^7.2",
"phpdocumentor/reflection-common": "^2.0",
"phpdocumentor/type-resolver": "^1.0",
"webmozart/assert": "^1"
},
"require-dev": {
"doctrine/instantiator": "^1",
"mockery/mockery": "^1"
},
"time": "2020-02-22T12:28:44+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.x-dev"
}
},
"installation-source": "dist",
"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": "account@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."
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.1.0",
"version_normalized": "1.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "7462d5f123dfc080dfdf26897032a6513644fc95"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/7462d5f123dfc080dfdf26897032a6513644fc95",
"reference": "7462d5f123dfc080dfdf26897032a6513644fc95",
"shasum": ""
},
"require": {
"php": "^7.2",
"phpdocumentor/reflection-common": "^2.0"
},
"require-dev": {
"ext-tokenizer": "^7.2",
"mockery/mockery": "~1"
},
"time": "2020-02-18T18:59:58+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"installation-source": "dist",
"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"
},
{
"name": "psr/container",
"version": "1.0.0",
"version_normalized": "1.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/container.git",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2017-02-14T16:28:37+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://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"
]
},
{
"name": "psr/http-message",
"version": "1.0.1",
@@ -785,6 +1315,68 @@
],
"description": "A polyfill for getallheaders."
},
{
"name": "sabre/event",
"version": "5.1.0",
"version_normalized": "5.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/event.git",
"reference": "d00a17507af0e7544cfe17096372f5d733e3b276"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/event/zipball/d00a17507af0e7544cfe17096372f5d733e3b276",
"reference": "d00a17507af0e7544cfe17096372f5d733e3b276",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2.16.1",
"phpunit/phpunit": "^7 || ^8"
},
"time": "2020-01-31T18:52:29+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Sabre\\Event\\": "lib/"
},
"files": [
"lib/coroutine.php",
"lib/Loop/functions.php",
"lib/Promise/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
}
],
"description": "sabre/event is a library for lightweight event-based programming",
"homepage": "http://sabre.io/event/",
"keywords": [
"EventEmitter",
"async",
"coroutine",
"eventloop",
"events",
"hooks",
"plugin",
"promise",
"reactor",
"signal"
]
},
{
"name": "scssphp/scssphp",
"version": "1.0.6",
@@ -893,6 +1485,98 @@
"pdo"
]
},
{
"name": "symfony/console",
"version": "v5.0.8",
"version_normalized": "5.0.8.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "5fa1caadc8cdaa17bcfb25219f3b53fe294a9935"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/5fa1caadc8cdaa17bcfb25219f3b53fe294a9935",
"reference": "5fa1caadc8cdaa17bcfb25219f3b53fe294a9935",
"shasum": ""
},
"require": {
"php": "^7.2.5",
"symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php73": "^1.8",
"symfony/service-contracts": "^1.1|^2"
},
"conflict": {
"symfony/dependency-injection": "<4.4",
"symfony/event-dispatcher": "<4.4",
"symfony/lock": "<4.4",
"symfony/process": "<4.4"
},
"provide": {
"psr/log-implementation": "1.0"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "^4.4|^5.0",
"symfony/dependency-injection": "^4.4|^5.0",
"symfony/event-dispatcher": "^4.4|^5.0",
"symfony/lock": "^4.4|^5.0",
"symfony/process": "^4.4|^5.0",
"symfony/var-dumper": "^4.4|^5.0"
},
"suggest": {
"psr/log": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/lock": "",
"symfony/process": ""
},
"time": "2020-03-30T11:42:42+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0-dev"
}
},
"installation-source": "dist",
"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": "Symfony Console Component",
"homepage": "https://symfony.com",
"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"
}
]
},
{
"name": "symfony/lock",
"version": "v4.4.3",
@@ -961,6 +1645,360 @@
"semaphore"
]
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.15.0",
"version_normalized": "1.15.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/4719fa9c18b0464d399f1a63bf624b42b6fa8d14",
"reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-ctype": "For best performance"
},
"time": "2020-02-27T09:26:54+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.15-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
},
"files": [
"bootstrap.php"
]
},
"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"
],
"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"
}
]
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.15.0",
"version_normalized": "1.15.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac",
"reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"time": "2020-03-09T19:04:49+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.15-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
},
"files": [
"bootstrap.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": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"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"
}
]
},
{
"name": "symfony/polyfill-php72",
"version": "v1.15.0",
"version_normalized": "1.15.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
"reference": "37b0976c78b94856543260ce09b460a7bc852747"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/37b0976c78b94856543260ce09b460a7bc852747",
"reference": "37b0976c78b94856543260ce09b460a7bc852747",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"time": "2020-02-27T09:26:54+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.15-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Php72\\": ""
},
"files": [
"bootstrap.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": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"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"
}
]
},
{
"name": "symfony/polyfill-php73",
"version": "v1.15.0",
"version_normalized": "1.15.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php73.git",
"reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7",
"reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"time": "2020-02-27T09:26:54+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.15-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Php73\\": ""
},
"files": [
"bootstrap.php"
],
"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"
],
"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"
}
]
},
{
"name": "symfony/service-contracts",
"version": "v2.0.1",
"version_normalized": "2.0.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "144c5e51266b281231e947b51223ba14acf1a749"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/144c5e51266b281231e947b51223ba14acf1a749",
"reference": "144c5e51266b281231e947b51223ba14acf1a749",
"shasum": ""
},
"require": {
"php": "^7.2.5",
"psr/container": "^1.0"
},
"suggest": {
"symfony/service-implementation": ""
},
"time": "2019-11-18T17:27:11+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Service\\": ""
}
},
"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"
]
},
{
"name": "vlucas/valitron",
"version": "v1.4.7",
@@ -1012,6 +2050,56 @@
"validator"
]
},
{
"name": "webmozart/assert",
"version": "1.8.0",
"version_normalized": "1.8.0.0",
"source": {
"type": "git",
"url": "https://github.com/webmozart/assert.git",
"reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozart/assert/zipball/ab2cb0b3b559010b75981b1bdce728da3ee90ad6",
"reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6",
"shasum": ""
},
"require": {
"php": "^5.3.3 || ^7.0",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
"vimeo/psalm": "<3.9.1"
},
"require-dev": {
"phpunit/phpunit": "^4.8.36 || ^7.5.13"
},
"time": "2020-04-18T12:12:48+00:00",
"type": "library",
"installation-source": "dist",
"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"
]
},
{
"name": "xemlock/htmlpurifier-html5",
"version": "v0.1.11",
+78
View File
@@ -0,0 +1,78 @@
# Change Log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
### [1.5.1] 2020-01-13
* Fixed: Parsing of aliased version was not validating the alias to be a valid version
### [1.5.0] 2019-03-19
* Added: some support for date versions (e.g. 201903) in `~` operator
* Fixed: support for stabilities in `~` operator was inconsistent
### [1.4.2] 2016-08-30
* Fixed: collapsing of complex constraints lead to buggy constraints
### [1.4.1] 2016-06-02
* Changed: branch-like requirements no longer strip build metadata - [composer/semver#38](https://github.com/composer/semver/pull/38).
### [1.4.0] 2016-03-30
* Added: getters on MultiConstraint - [composer/semver#35](https://github.com/composer/semver/pull/35).
### [1.3.0] 2016-02-25
* Fixed: stability parsing - [composer/composer#1234](https://github.com/composer/composer/issues/4889).
* Changed: collapse contiguous constraints when possible.
### [1.2.0] 2015-11-10
* Changed: allow multiple numerical identifiers in 'pre-release' version part.
* Changed: add more 'v' prefix support.
### [1.1.0] 2015-11-03
* Changed: dropped redundant `test` namespace.
* Changed: minor adjustment in datetime parsing normalization.
* Changed: `ConstraintInterface` relaxed, setPrettyString is not required anymore.
* Changed: `AbstractConstraint` marked deprecated, will be removed in 2.0.
* Changed: `Constraint` is now extensible.
### [1.0.0] 2015-09-21
* Break: `VersionConstraint` renamed to `Constraint`.
* Break: `SpecificConstraint` renamed to `AbstractConstraint`.
* Break: `LinkConstraintInterface` renamed to `ConstraintInterface`.
* Break: `VersionParser::parseNameVersionPairs` was removed.
* Changed: `VersionParser::parseConstraints` allows (but ignores) build metadata now.
* Changed: `VersionParser::parseConstraints` allows (but ignores) prefixing numeric versions with a 'v' now.
* Changed: Fixed namespace(s) of test files.
* Changed: `Comparator::compare` no longer throws `InvalidArgumentException`.
* Changed: `Constraint` now throws `InvalidArgumentException`.
### [0.1.0] 2015-07-23
* Added: `Composer\Semver\Comparator`, various methods to compare versions.
* Added: various documents such as README.md, LICENSE, etc.
* Added: configuration files for Git, Travis, php-cs-fixer, phpunit.
* Break: the following namespaces were renamed:
- Namespace: `Composer\Package\Version` -> `Composer\Semver`
- Namespace: `Composer\Package\LinkConstraint` -> `Composer\Semver\Constraint`
- Namespace: `Composer\Test\Package\Version` -> `Composer\Test\Semver`
- Namespace: `Composer\Test\Package\LinkConstraint` -> `Composer\Test\Semver\Constraint`
* Changed: code style using php-cs-fixer.
[1.5.1]: https://github.com/composer/semver/compare/1.5.0...1.5.1
[1.5.0]: https://github.com/composer/semver/compare/1.4.2...1.5.0
[1.4.2]: https://github.com/composer/semver/compare/1.4.1...1.4.2
[1.4.1]: https://github.com/composer/semver/compare/1.4.0...1.4.1
[1.4.0]: https://github.com/composer/semver/compare/1.3.0...1.4.0
[1.3.0]: https://github.com/composer/semver/compare/1.2.0...1.3.0
[1.2.0]: https://github.com/composer/semver/compare/1.1.0...1.2.0
[1.1.0]: https://github.com/composer/semver/compare/1.0.0...1.1.0
[1.0.0]: https://github.com/composer/semver/compare/0.1.0...1.0.0
[0.1.0]: https://github.com/composer/semver/compare/5e0b9a4da...0.1.0
+19
View File
@@ -0,0 +1,19 @@
Copyright (C) 2015 Composer
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+70
View File
@@ -0,0 +1,70 @@
composer/semver
===============
Semver library that offers utilities, version constraint parsing and validation.
Originally written as part of [composer/composer](https://github.com/composer/composer),
now extracted and made available as a stand-alone library.
[![Build Status](https://travis-ci.org/composer/semver.svg?branch=master)](https://travis-ci.org/composer/semver)
Installation
------------
Install the latest version with:
```bash
$ composer require composer/semver
```
Requirements
------------
* PHP 5.3.2 is required but using the latest version of PHP is highly recommended.
Version Comparison
------------------
For details on how versions are compared, refer to the [Versions](https://getcomposer.org/doc/articles/versions.md)
article in the documentation section of the [getcomposer.org](https://getcomposer.org) website.
Basic usage
-----------
### Comparator
The `Composer\Semver\Comparator` class provides the following methods for comparing versions:
* greaterThan($v1, $v2)
* greaterThanOrEqualTo($v1, $v2)
* lessThan($v1, $v2)
* lessThanOrEqualTo($v1, $v2)
* equalTo($v1, $v2)
* notEqualTo($v1, $v2)
Each function takes two version strings as arguments. For example:
```php
use Composer\Semver\Comparator;
Comparator::greaterThan('1.25.0', '1.24.0'); // 1.25.0 > 1.24.0
```
### Semver
The `Composer\Semver\Semver` class provides the following methods:
* satisfies($version, $constraints)
* satisfiedBy(array $versions, $constraint)
* sort($versions)
* rsort($versions)
License
-------
composer/semver is licensed under the MIT License, see the LICENSE file for details.
+57
View File
@@ -0,0 +1,57 @@
{
"name": "composer/semver",
"description": "Semver library that offers utilities, version constraint parsing and validation.",
"type": "library",
"license": "MIT",
"keywords": [
"semver",
"semantic",
"versioning",
"validation"
],
"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"
}
],
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/semver/issues"
},
"require": {
"php": "^5.3.2 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.5 || ^5.0.5"
},
"autoload": {
"psr-4": {
"Composer\\Semver\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Composer\\Semver\\": "tests"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"scripts": {
"test": "phpunit"
}
}
+111
View File
@@ -0,0 +1,111 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver;
use Composer\Semver\Constraint\Constraint;
class Comparator
{
/**
* Evaluates the expression: $version1 > $version2.
*
* @param string $version1
* @param string $version2
*
* @return bool
*/
public static function greaterThan($version1, $version2)
{
return self::compare($version1, '>', $version2);
}
/**
* Evaluates the expression: $version1 >= $version2.
*
* @param string $version1
* @param string $version2
*
* @return bool
*/
public static function greaterThanOrEqualTo($version1, $version2)
{
return self::compare($version1, '>=', $version2);
}
/**
* Evaluates the expression: $version1 < $version2.
*
* @param string $version1
* @param string $version2
*
* @return bool
*/
public static function lessThan($version1, $version2)
{
return self::compare($version1, '<', $version2);
}
/**
* Evaluates the expression: $version1 <= $version2.
*
* @param string $version1
* @param string $version2
*
* @return bool
*/
public static function lessThanOrEqualTo($version1, $version2)
{
return self::compare($version1, '<=', $version2);
}
/**
* Evaluates the expression: $version1 == $version2.
*
* @param string $version1
* @param string $version2
*
* @return bool
*/
public static function equalTo($version1, $version2)
{
return self::compare($version1, '==', $version2);
}
/**
* Evaluates the expression: $version1 != $version2.
*
* @param string $version1
* @param string $version2
*
* @return bool
*/
public static function notEqualTo($version1, $version2)
{
return self::compare($version1, '!=', $version2);
}
/**
* Evaluates the expression: $version1 $operator $version2.
*
* @param string $version1
* @param string $operator
* @param string $version2
*
* @return bool
*/
public static function compare($version1, $operator, $version2)
{
$constraint = new Constraint($operator, $version2);
return $constraint->matches(new Constraint('==', $version1));
}
}
@@ -0,0 +1,63 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
trigger_error('The ' . __NAMESPACE__ . '\AbstractConstraint abstract class is deprecated, there is no replacement for it, it will be removed in the next major version.', E_USER_DEPRECATED);
/**
* Base constraint class.
*/
abstract class AbstractConstraint implements ConstraintInterface
{
/** @var string */
protected $prettyString;
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider)
{
if ($provider instanceof $this) {
// see note at bottom of this class declaration
return $this->matchSpecific($provider);
}
// turn matching around to find a match
return $provider->matches($this);
}
/**
* @param string $prettyString
*/
public function setPrettyString($prettyString)
{
$this->prettyString = $prettyString;
}
/**
* @return string
*/
public function getPrettyString()
{
if ($this->prettyString) {
return $this->prettyString;
}
return $this->__toString();
}
// implementations must implement a method of this format:
// not declared abstract here because type hinting violates parameter coherence (TODO right word?)
// public function matchSpecific(<SpecificConstraintType> $provider);
}
+215
View File
@@ -0,0 +1,215 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
/**
* Defines a constraint.
*/
class Constraint implements ConstraintInterface
{
/* operator integer values */
const OP_EQ = 0;
const OP_LT = 1;
const OP_LE = 2;
const OP_GT = 3;
const OP_GE = 4;
const OP_NE = 5;
/**
* Operator to integer translation table.
*
* @var array
*/
private static $transOpStr = array(
'=' => self::OP_EQ,
'==' => self::OP_EQ,
'<' => self::OP_LT,
'<=' => self::OP_LE,
'>' => self::OP_GT,
'>=' => self::OP_GE,
'<>' => self::OP_NE,
'!=' => self::OP_NE,
);
/**
* Integer to operator translation table.
*
* @var array
*/
private static $transOpInt = array(
self::OP_EQ => '==',
self::OP_LT => '<',
self::OP_LE => '<=',
self::OP_GT => '>',
self::OP_GE => '>=',
self::OP_NE => '!=',
);
/** @var string */
protected $operator;
/** @var string */
protected $version;
/** @var string */
protected $prettyString;
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider)
{
if ($provider instanceof $this) {
return $this->matchSpecific($provider);
}
// turn matching around to find a match
return $provider->matches($this);
}
/**
* @param string $prettyString
*/
public function setPrettyString($prettyString)
{
$this->prettyString = $prettyString;
}
/**
* @return string
*/
public function getPrettyString()
{
if ($this->prettyString) {
return $this->prettyString;
}
return $this->__toString();
}
/**
* Get all supported comparison operators.
*
* @return array
*/
public static function getSupportedOperators()
{
return array_keys(self::$transOpStr);
}
/**
* Sets operator and version to compare with.
*
* @param string $operator
* @param string $version
*
* @throws \InvalidArgumentException if invalid operator is given.
*/
public function __construct($operator, $version)
{
if (!isset(self::$transOpStr[$operator])) {
throw new \InvalidArgumentException(sprintf(
'Invalid operator "%s" given, expected one of: %s',
$operator,
implode(', ', self::getSupportedOperators())
));
}
$this->operator = self::$transOpStr[$operator];
$this->version = $version;
}
/**
* @param string $a
* @param string $b
* @param string $operator
* @param bool $compareBranches
*
* @throws \InvalidArgumentException if invalid operator is given.
*
* @return bool
*/
public function versionCompare($a, $b, $operator, $compareBranches = false)
{
if (!isset(self::$transOpStr[$operator])) {
throw new \InvalidArgumentException(sprintf(
'Invalid operator "%s" given, expected one of: %s',
$operator,
implode(', ', self::getSupportedOperators())
));
}
$aIsBranch = 'dev-' === substr($a, 0, 4);
$bIsBranch = 'dev-' === substr($b, 0, 4);
if ($aIsBranch && $bIsBranch) {
return $operator === '==' && $a === $b;
}
// when branches are not comparable, we make sure dev branches never match anything
if (!$compareBranches && ($aIsBranch || $bIsBranch)) {
return false;
}
return version_compare($a, $b, $operator);
}
/**
* @param Constraint $provider
* @param bool $compareBranches
*
* @return bool
*/
public function matchSpecific(Constraint $provider, $compareBranches = false)
{
$noEqualOp = str_replace('=', '', self::$transOpInt[$this->operator]);
$providerNoEqualOp = str_replace('=', '', self::$transOpInt[$provider->operator]);
$isEqualOp = self::OP_EQ === $this->operator;
$isNonEqualOp = self::OP_NE === $this->operator;
$isProviderEqualOp = self::OP_EQ === $provider->operator;
$isProviderNonEqualOp = self::OP_NE === $provider->operator;
// '!=' operator is match when other operator is not '==' operator or version is not match
// these kinds of comparisons always have a solution
if ($isNonEqualOp || $isProviderNonEqualOp) {
return (!$isEqualOp && !$isProviderEqualOp)
|| $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
}
// an example for the condition is <= 2.0 & < 1.0
// these kinds of comparisons always have a solution
if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) {
return true;
}
if ($this->versionCompare($provider->version, $this->version, self::$transOpInt[$this->operator], $compareBranches)) {
// special case, e.g. require >= 1.0 and provide < 1.0
// 1.0 >= 1.0 but 1.0 is outside of the provided interval
return !($provider->version === $this->version
&& self::$transOpInt[$provider->operator] === $providerNoEqualOp
&& self::$transOpInt[$this->operator] !== $noEqualOp);
}
return false;
}
/**
* @return string
*/
public function __toString()
{
return self::$transOpInt[$this->operator] . ' ' . $this->version;
}
}
@@ -0,0 +1,32 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
interface ConstraintInterface
{
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider);
/**
* @return string
*/
public function getPrettyString();
/**
* @return string
*/
public function __toString();
}
@@ -0,0 +1,59 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
/**
* Defines the absence of a constraint.
*/
class EmptyConstraint implements ConstraintInterface
{
/** @var string */
protected $prettyString;
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider)
{
return true;
}
/**
* @param $prettyString
*/
public function setPrettyString($prettyString)
{
$this->prettyString = $prettyString;
}
/**
* @return string
*/
public function getPrettyString()
{
if ($this->prettyString) {
return $this->prettyString;
}
return (string) $this;
}
/**
* @return string
*/
public function __toString()
{
return '[]';
}
}
@@ -0,0 +1,120 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
/**
* Defines a conjunctive or disjunctive set of constraints.
*/
class MultiConstraint implements ConstraintInterface
{
/** @var ConstraintInterface[] */
protected $constraints;
/** @var string */
protected $prettyString;
/** @var bool */
protected $conjunctive;
/**
* @param ConstraintInterface[] $constraints A set of constraints
* @param bool $conjunctive Whether the constraints should be treated as conjunctive or disjunctive
*/
public function __construct(array $constraints, $conjunctive = true)
{
$this->constraints = $constraints;
$this->conjunctive = $conjunctive;
}
/**
* @return ConstraintInterface[]
*/
public function getConstraints()
{
return $this->constraints;
}
/**
* @return bool
*/
public function isConjunctive()
{
return $this->conjunctive;
}
/**
* @return bool
*/
public function isDisjunctive()
{
return !$this->conjunctive;
}
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider)
{
if (false === $this->conjunctive) {
foreach ($this->constraints as $constraint) {
if ($constraint->matches($provider)) {
return true;
}
}
return false;
}
foreach ($this->constraints as $constraint) {
if (!$constraint->matches($provider)) {
return false;
}
}
return true;
}
/**
* @param string $prettyString
*/
public function setPrettyString($prettyString)
{
$this->prettyString = $prettyString;
}
/**
* @return string
*/
public function getPrettyString()
{
if ($this->prettyString) {
return $this->prettyString;
}
return (string) $this;
}
/**
* @return string
*/
public function __toString()
{
$constraints = array();
foreach ($this->constraints as $constraint) {
$constraints[] = (string) $constraint;
}
return '[' . implode($this->conjunctive ? ' ' : ' || ', $constraints) . ']';
}
}
+127
View File
@@ -0,0 +1,127 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver;
use Composer\Semver\Constraint\Constraint;
class Semver
{
const SORT_ASC = 1;
const SORT_DESC = -1;
/** @var VersionParser */
private static $versionParser;
/**
* Determine if given version satisfies given constraints.
*
* @param string $version
* @param string $constraints
*
* @return bool
*/
public static function satisfies($version, $constraints)
{
if (null === self::$versionParser) {
self::$versionParser = new VersionParser();
}
$versionParser = self::$versionParser;
$provider = new Constraint('==', $versionParser->normalize($version));
$parsedConstraints = $versionParser->parseConstraints($constraints);
return $parsedConstraints->matches($provider);
}
/**
* Return all versions that satisfy given constraints.
*
* @param array $versions
* @param string $constraints
*
* @return array
*/
public static function satisfiedBy(array $versions, $constraints)
{
$versions = array_filter($versions, function ($version) use ($constraints) {
return Semver::satisfies($version, $constraints);
});
return array_values($versions);
}
/**
* Sort given array of versions.
*
* @param array $versions
*
* @return array
*/
public static function sort(array $versions)
{
return self::usort($versions, self::SORT_ASC);
}
/**
* Sort given array of versions in reverse.
*
* @param array $versions
*
* @return array
*/
public static function rsort(array $versions)
{
return self::usort($versions, self::SORT_DESC);
}
/**
* @param array $versions
* @param int $direction
*
* @return array
*/
private static function usort(array $versions, $direction)
{
if (null === self::$versionParser) {
self::$versionParser = new VersionParser();
}
$versionParser = self::$versionParser;
$normalized = array();
// Normalize outside of usort() scope for minor performance increase.
// Creates an array of arrays: [[normalized, key], ...]
foreach ($versions as $key => $version) {
$normalized[] = array($versionParser->normalize($version), $key);
}
usort($normalized, function (array $left, array $right) use ($direction) {
if ($left[0] === $right[0]) {
return 0;
}
if (Comparator::lessThan($left[0], $right[0])) {
return -$direction;
}
return $direction;
});
// Recreate input array, using the original indexes which are now in sorted order.
$sorted = array();
foreach ($normalized as $item) {
$sorted[] = $versions[$item[1]];
}
return $sorted;
}
}
+545
View File
@@ -0,0 +1,545 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver;
use Composer\Semver\Constraint\ConstraintInterface;
use Composer\Semver\Constraint\EmptyConstraint;
use Composer\Semver\Constraint\MultiConstraint;
use Composer\Semver\Constraint\Constraint;
/**
* Version parser.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class VersionParser
{
/**
* Regex to match pre-release data (sort of).
*
* Due to backwards compatibility:
* - Instead of enforcing hyphen, an underscore, dot or nothing at all are also accepted.
* - Only stabilities as recognized by Composer are allowed to precede a numerical identifier.
* - Numerical-only pre-release identifiers are not supported, see tests.
*
* |--------------|
* [major].[minor].[patch] -[pre-release] +[build-metadata]
*
* @var string
*/
private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)((?:[.-]?\d+)*+)?)?([.-]?dev)?';
/** @var array */
private static $stabilities = array('stable', 'RC', 'beta', 'alpha', 'dev');
/**
* Returns the stability of a version.
*
* @param string $version
*
* @return string
*/
public static function parseStability($version)
{
$version = preg_replace('{#.+$}i', '', $version);
if (strpos($version, 'dev-') === 0 || '-dev' === substr($version, -4)) {
return 'dev';
}
preg_match('{' . self::$modifierRegex . '(?:\+.*)?$}i', strtolower($version), $match);
if (!empty($match[3])) {
return 'dev';
}
if (!empty($match[1])) {
if ('beta' === $match[1] || 'b' === $match[1]) {
return 'beta';
}
if ('alpha' === $match[1] || 'a' === $match[1]) {
return 'alpha';
}
if ('rc' === $match[1]) {
return 'RC';
}
}
return 'stable';
}
/**
* @param string $stability
*
* @return string
*/
public static function normalizeStability($stability)
{
$stability = strtolower($stability);
return $stability === 'rc' ? 'RC' : $stability;
}
/**
* Normalizes a version string to be able to perform comparisons on it.
*
* @param string $version
* @param string $fullVersion optional complete version string to give more context
*
* @throws \UnexpectedValueException
*
* @return string
*/
public function normalize($version, $fullVersion = null)
{
$version = trim($version);
if (null === $fullVersion) {
$fullVersion = $version;
}
// strip off aliasing
if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $version, $match)) {
// verify that the alias is a version without constraint
$this->normalize($match[2]);
$version = $match[1];
}
// match master-like branches
if (preg_match('{^(?:dev-)?(?:master|trunk|default)$}i', $version)) {
return '9999999-dev';
}
// if requirement is branch-like, use full name
if (stripos($version, 'dev-') === 0) {
return 'dev-' . substr($version, 4);
}
// strip off build metadata
if (preg_match('{^([^,\s+]++)\+[^\s]++$}', $version, $match)) {
$version = $match[1];
}
// match classical versioning
if (preg_match('{^v?(\d{1,5})(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
$version = $matches[1]
. (!empty($matches[2]) ? $matches[2] : '.0')
. (!empty($matches[3]) ? $matches[3] : '.0')
. (!empty($matches[4]) ? $matches[4] : '.0');
$index = 5;
// match date(time) based versioning
} elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)' . self::$modifierRegex . '$}i', $version, $matches)) {
$version = preg_replace('{\D}', '.', $matches[1]);
$index = 2;
}
// add version modifiers if a version was matched
if (isset($index)) {
if (!empty($matches[$index])) {
if ('stable' === $matches[$index]) {
return $version;
}
$version .= '-' . $this->expandStability($matches[$index]) . (!empty($matches[$index + 1]) ? ltrim($matches[$index + 1], '.-') : '');
}
if (!empty($matches[$index + 2])) {
$version .= '-dev';
}
return $version;
}
// match dev branches
if (preg_match('{(.*?)[.-]?dev$}i', $version, $match)) {
try {
return $this->normalizeBranch($match[1]);
} catch (\Exception $e) {
}
}
$extraMessage = '';
if (preg_match('{ +as +' . preg_quote($version) . '$}', $fullVersion)) {
$extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version';
} elseif (preg_match('{^' . preg_quote($version) . ' +as +}', $fullVersion)) {
$extraMessage = ' in "' . $fullVersion . '", the alias source must be an exact version, if it is a branch name you should prefix it with dev-';
}
throw new \UnexpectedValueException('Invalid version string "' . $version . '"' . $extraMessage);
}
/**
* Extract numeric prefix from alias, if it is in numeric format, suitable for version comparison.
*
* @param string $branch Branch name (e.g. 2.1.x-dev)
*
* @return string|false Numeric prefix if present (e.g. 2.1.) or false
*/
public function parseNumericAliasPrefix($branch)
{
if (preg_match('{^(?P<version>(\d++\\.)*\d++)(?:\.x)?-dev$}i', $branch, $matches)) {
return $matches['version'] . '.';
}
return false;
}
/**
* Normalizes a branch name to be able to perform comparisons on it.
*
* @param string $name
*
* @return string
*/
public function normalizeBranch($name)
{
$name = trim($name);
if (in_array($name, array('master', 'trunk', 'default'))) {
return $this->normalize($name);
}
if (preg_match('{^v?(\d++)(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?$}i', $name, $matches)) {
$version = '';
for ($i = 1; $i < 5; ++$i) {
$version .= isset($matches[$i]) ? str_replace(array('*', 'X'), 'x', $matches[$i]) : '.x';
}
return str_replace('x', '9999999', $version) . '-dev';
}
return 'dev-' . $name;
}
/**
* Parses a constraint string into MultiConstraint and/or Constraint objects.
*
* @param string $constraints
*
* @return ConstraintInterface
*/
public function parseConstraints($constraints)
{
$prettyConstraint = $constraints;
if (preg_match('{^([^,\s]*?)@(' . implode('|', self::$stabilities) . ')$}i', $constraints, $match)) {
$constraints = empty($match[1]) ? '*' : $match[1];
}
if (preg_match('{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i', $constraints, $match)) {
$constraints = $match[1];
}
$orConstraints = preg_split('{\s*\|\|?\s*}', trim($constraints));
$orGroups = array();
foreach ($orConstraints as $constraints) {
$andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraints);
if (count($andConstraints) > 1) {
$constraintObjects = array();
foreach ($andConstraints as $constraint) {
foreach ($this->parseConstraint($constraint) as $parsedConstraint) {
$constraintObjects[] = $parsedConstraint;
}
}
} else {
$constraintObjects = $this->parseConstraint($andConstraints[0]);
}
if (1 === count($constraintObjects)) {
$constraint = $constraintObjects[0];
} else {
$constraint = new MultiConstraint($constraintObjects);
}
$orGroups[] = $constraint;
}
if (1 === count($orGroups)) {
$constraint = $orGroups[0];
} elseif (2 === count($orGroups)
// parse the two OR groups and if they are contiguous we collapse
// them into one constraint
&& $orGroups[0] instanceof MultiConstraint
&& $orGroups[1] instanceof MultiConstraint
&& 2 === count($orGroups[0]->getConstraints())
&& 2 === count($orGroups[1]->getConstraints())
&& ($a = (string) $orGroups[0])
&& strpos($a, '[>=') === 0 && (false !== ($posA = strpos($a, '<', 4)))
&& ($b = (string) $orGroups[1])
&& strpos($b, '[>=') === 0 && (false !== ($posB = strpos($b, '<', 4)))
&& substr($a, $posA + 2, -1) === substr($b, 4, $posB - 5)
) {
$constraint = new MultiConstraint(array(
new Constraint('>=', substr($a, 4, $posA - 5)),
new Constraint('<', substr($b, $posB + 2, -1)),
));
} else {
$constraint = new MultiConstraint($orGroups, false);
}
$constraint->setPrettyString($prettyConstraint);
return $constraint;
}
/**
* @param string $constraint
*
* @throws \UnexpectedValueException
*
* @return array
*/
private function parseConstraint($constraint)
{
if (preg_match('{^([^,\s]+?)@(' . implode('|', self::$stabilities) . ')$}i', $constraint, $match)) {
$constraint = $match[1];
if ($match[2] !== 'stable') {
$stabilityModifier = $match[2];
}
}
if (preg_match('{^v?[xX*](\.[xX*])*$}i', $constraint)) {
return array(new EmptyConstraint());
}
$versionRegex = 'v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.(\d++))?' . self::$modifierRegex . '(?:\+[^\s]+)?';
// Tilde Range
//
// Like wildcard constraints, unsuffixed tilde constraints say that they must be greater than the previous
// version, to ensure that unstable instances of the current version are allowed. However, if a stability
// suffix is added to the constraint, then a >= match on the current version is used instead.
if (preg_match('{^~>?' . $versionRegex . '$}i', $constraint, $matches)) {
if (strpos($constraint, '~>') === 0) {
throw new \UnexpectedValueException(
'Could not parse version constraint ' . $constraint . ': ' .
'Invalid operator "~>", you probably meant to use the "~" operator'
);
}
// Work out which position in the version we are operating at
if (isset($matches[4]) && '' !== $matches[4] && null !== $matches[4]) {
$position = 4;
} elseif (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
$position = 3;
} elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
$position = 2;
} else {
$position = 1;
}
// Calculate the stability suffix
$stabilitySuffix = '';
if (empty($matches[5]) && empty($matches[7])) {
$stabilitySuffix .= '-dev';
}
$lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
$lowerBound = new Constraint('>=', $lowVersion);
// For upper bound, we increment the position of one more significance,
// but highPosition = 0 would be illegal
$highPosition = max(1, $position - 1);
$highVersion = $this->manipulateVersionString($matches, $highPosition, 1) . '-dev';
$upperBound = new Constraint('<', $highVersion);
return array(
$lowerBound,
$upperBound,
);
}
// Caret Range
//
// Allows changes that do not modify the left-most non-zero digit in the [major, minor, patch] tuple.
// In other words, this allows patch and minor updates for versions 1.0.0 and above, patch updates for
// versions 0.X >=0.1.0, and no updates for versions 0.0.X
if (preg_match('{^\^' . $versionRegex . '($)}i', $constraint, $matches)) {
// Work out which position in the version we are operating at
if ('0' !== $matches[1] || '' === $matches[2] || null === $matches[2]) {
$position = 1;
} elseif ('0' !== $matches[2] || '' === $matches[3] || null === $matches[3]) {
$position = 2;
} else {
$position = 3;
}
// Calculate the stability suffix
$stabilitySuffix = '';
if (empty($matches[5]) && empty($matches[7])) {
$stabilitySuffix .= '-dev';
}
$lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
$lowerBound = new Constraint('>=', $lowVersion);
// For upper bound, we increment the position of one more significance,
// but highPosition = 0 would be illegal
$highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
$upperBound = new Constraint('<', $highVersion);
return array(
$lowerBound,
$upperBound,
);
}
// X Range
//
// Any of X, x, or * may be used to "stand in" for one of the numeric values in the [major, minor, patch] tuple.
// A partial version range is treated as an X-Range, so the special character is in fact optional.
if (preg_match('{^v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.[xX*])++$}', $constraint, $matches)) {
if (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
$position = 3;
} elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
$position = 2;
} else {
$position = 1;
}
$lowVersion = $this->manipulateVersionString($matches, $position) . '-dev';
$highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
if ($lowVersion === '0.0.0.0-dev') {
return array(new Constraint('<', $highVersion));
}
return array(
new Constraint('>=', $lowVersion),
new Constraint('<', $highVersion),
);
}
// Hyphen Range
//
// Specifies an inclusive set. If a partial version is provided as the first version in the inclusive range,
// then the missing pieces are replaced with zeroes. If a partial version is provided as the second version in
// the inclusive range, then all versions that start with the supplied parts of the tuple are accepted, but
// nothing that would be greater than the provided tuple parts.
if (preg_match('{^(?P<from>' . $versionRegex . ') +- +(?P<to>' . $versionRegex . ')($)}i', $constraint, $matches)) {
// Calculate the stability suffix
$lowStabilitySuffix = '';
if (empty($matches[6]) && empty($matches[8])) {
$lowStabilitySuffix = '-dev';
}
$lowVersion = $this->normalize($matches['from']);
$lowerBound = new Constraint('>=', $lowVersion . $lowStabilitySuffix);
$empty = function ($x) {
return ($x === 0 || $x === '0') ? false : empty($x);
};
if ((!$empty($matches[11]) && !$empty($matches[12])) || !empty($matches[14]) || !empty($matches[16])) {
$highVersion = $this->normalize($matches['to']);
$upperBound = new Constraint('<=', $highVersion);
} else {
$highMatch = array('', $matches[10], $matches[11], $matches[12], $matches[13]);
$highVersion = $this->manipulateVersionString($highMatch, $empty($matches[11]) ? 1 : 2, 1) . '-dev';
$upperBound = new Constraint('<', $highVersion);
}
return array(
$lowerBound,
$upperBound,
);
}
// Basic Comparators
if (preg_match('{^(<>|!=|>=?|<=?|==?)?\s*(.*)}', $constraint, $matches)) {
try {
$version = $this->normalize($matches[2]);
if (!empty($stabilityModifier) && self::parseStability($version) === 'stable') {
$version .= '-' . $stabilityModifier;
} elseif ('<' === $matches[1] || '>=' === $matches[1]) {
if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) {
if (strpos($matches[2], 'dev-') !== 0) {
$version .= '-dev';
}
}
}
return array(new Constraint($matches[1] ?: '=', $version));
} catch (\Exception $e) {
}
}
$message = 'Could not parse version constraint ' . $constraint;
if (isset($e)) {
$message .= ': ' . $e->getMessage();
}
throw new \UnexpectedValueException($message);
}
/**
* Increment, decrement, or simply pad a version number.
*
* Support function for {@link parseConstraint()}
*
* @param array $matches Array with version parts in array indexes 1,2,3,4
* @param int $position 1,2,3,4 - which segment of the version to increment/decrement
* @param int $increment
* @param string $pad The string to pad version parts after $position
*
* @return string The new version
*/
private function manipulateVersionString($matches, $position, $increment = 0, $pad = '0')
{
for ($i = 4; $i > 0; --$i) {
if ($i > $position) {
$matches[$i] = $pad;
} elseif ($i === $position && $increment) {
$matches[$i] += $increment;
// If $matches[$i] was 0, carry the decrement
if ($matches[$i] < 0) {
$matches[$i] = $pad;
--$position;
// Return null on a carry overflow
if ($i === 1) {
return null;
}
}
}
}
return $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . $matches[4];
}
/**
* Expand shorthand stability string to long version.
*
* @param string $stability
*
* @return string
*/
private function expandStability($stability)
{
$stability = strtolower($stability);
switch ($stability) {
case 'a':
return 'alpha';
case 'b':
return 'beta';
case 'p':
case 'pl':
return 'patch';
case 'rc':
return 'RC';
default:
return $stability;
}
}
}
+70
View File
@@ -0,0 +1,70 @@
## [Unreleased]
## [1.4.1] - 2020-03-01
* Fixed: restart fails if an ini file is empty.
## [1.4.0] - 2019-11-06
* Added: support for `NO_COLOR` environment variable: https://no-color.org
* Added: color support for Hyper terminal: https://github.com/zeit/hyper
* Fixed: correct capitalization of Xdebug (apparently).
* Fixed: improved handling for uopz extension.
## [1.3.3] - 2019-05-27
* Fixed: add environment changes to `$_ENV` if it is being used.
## [1.3.2] - 2019-01-28
* Fixed: exit call being blocked by uopz extension, resulting in application code running twice.
## [1.3.1] - 2018-11-29
* Fixed: fail restart if `passthru` has been disabled in `disable_functions`.
* Fixed: fail restart if an ini file cannot be opened, otherwise settings will be missing.
## [1.3.0] - 2018-08-31
* Added: `setPersistent` method to use environment variables for the restart.
* Fixed: improved debugging by writing output to stderr.
* Fixed: no restart when `php_ini_scanned_files` is not functional and is needed.
## [1.2.1] - 2018-08-23
* Fixed: fatal error with apc, when using `apc.mmap_file_mask`.
## [1.2.0] - 2018-08-16
* Added: debug information using `XDEBUG_HANDLER_DEBUG`.
* Added: fluent interface for setters.
* Added: `PhpConfig` helper class for calling PHP sub-processes.
* Added: `PHPRC` original value to restart stettings, for use in a restarted process.
* Changed: internal procedure to disable ini-scanning, using `-n` command-line option.
* Fixed: replaced `escapeshellarg` usage to avoid locale problems.
* Fixed: improved color-option handling to respect double-dash delimiter.
* Fixed: color-option handling regression from main script changes.
* Fixed: improved handling when checking main script.
* Fixed: handling for standard input, that never actually did anything.
* Fixed: fatal error when ctype extension is not available.
## [1.1.0] - 2018-04-11
* Added: `getRestartSettings` method for calling PHP processes in a restarted process.
* Added: API definition and @internal class annotations.
* Added: protected `requiresRestart` method for extending classes.
* Added: `setMainScript` method for applications that change the working directory.
* Changed: private `tmpIni` variable to protected for extending classes.
* Fixed: environment variables not available in $_SERVER when restored in the restart.
* Fixed: relative path problems caused by Phar::interceptFileFuncs.
* Fixed: incorrect handling when script file cannot be found.
## [1.0.0] - 2018-03-08
* Added: PSR3 logging for optional status output.
* Added: existing ini settings are merged to catch command-line overrides.
* Added: code, tests and other artefacts to decouple from Composer.
* Break: the following class was renamed:
- `Composer\XdebugHandler` -> `Composer\XdebugHandler\XdebugHandler`
[Unreleased]: https://github.com/composer/xdebug-handler/compare/1.4.1...HEAD
[1.4.1]: https://github.com/composer/xdebug-handler/compare/1.4.0...1.4.1
[1.4.0]: https://github.com/composer/xdebug-handler/compare/1.3.3...1.4.0
[1.3.3]: https://github.com/composer/xdebug-handler/compare/1.3.2...1.3.3
[1.3.2]: https://github.com/composer/xdebug-handler/compare/1.3.1...1.3.2
[1.3.1]: https://github.com/composer/xdebug-handler/compare/1.3.0...1.3.1
[1.3.0]: https://github.com/composer/xdebug-handler/compare/1.2.1...1.3.0
[1.2.1]: https://github.com/composer/xdebug-handler/compare/1.2.0...1.2.1
[1.2.0]: https://github.com/composer/xdebug-handler/compare/1.1.0...1.2.0
[1.1.0]: https://github.com/composer/xdebug-handler/compare/1.0.0...1.1.0
[1.0.0]: https://github.com/composer/xdebug-handler/compare/d66f0d15cb57...1.0.0
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Composer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+288
View File
@@ -0,0 +1,288 @@
# composer/xdebug-handler
[![packagist](https://img.shields.io/packagist/v/composer/xdebug-handler.svg)](https://packagist.org/packages/composer/xdebug-handler)
[![linux build](https://img.shields.io/travis/composer/xdebug-handler/master.svg?label=linux+build)](https://travis-ci.org/composer/xdebug-handler)
[![windows build](https://img.shields.io/appveyor/ci/Seldaek/xdebug-handler/master.svg?label=windows+build)](https://ci.appveyor.com/project/Seldaek/xdebug-handler)
![license](https://img.shields.io/github/license/composer/xdebug-handler.svg)
![php](https://img.shields.io/packagist/php-v/composer/xdebug-handler.svg?colorB=8892BF&label=php)
Restart a CLI process without loading the Xdebug extension.
Originally written as part of [composer/composer](https://github.com/composer/composer),
now extracted and made available as a stand-alone library.
## Installation
Install the latest version with:
```bash
$ composer require composer/xdebug-handler
```
## Requirements
* PHP 5.3.2 minimum, although functionality is disabled below PHP 5.4.0. Using the latest PHP version is highly recommended.
## Basic Usage
```php
use Composer\XdebugHandler\XdebugHandler;
$xdebug = new XdebugHandler('myapp');
$xdebug->check();
unset($xdebug);
```
The constructor takes two parameters:
#### _$envPrefix_
This is used to create distinct environment variables and is upper-cased and prepended to default base values. The above example enables the use of:
- `MYAPP_ALLOW_XDEBUG=1` to override automatic restart and allow Xdebug
- `MYAPP_ORIGINAL_INIS` to obtain ini file locations in a restarted process
#### _$colorOption_
This optional value is added to the restart command-line and is needed to force color output in a piped child process. Only long-options are supported, for example `--ansi` or `--colors=always` etc.
If the original command-line contains an argument that pattern matches this value (for example `--no-ansi`, `--colors=never`) then _$colorOption_ is ignored.
If the pattern match ends with `=auto` (for example `--colors=auto`), the argument is replaced by _$colorOption_. Otherwise it is added at either the end of the command-line, or preceding the first double-dash `--` delimiter.
## Advanced Usage
* [How it works](#how-it-works)
* [Limitations](#limitations)
* [Helper methods](#helper-methods)
* [Setter methods](#setter-methods)
* [Process configuration](#process-configuration)
* [Troubleshooting](#troubleshooting)
* [Extending the library](#extending-the-library)
### How it works
A temporary ini file is created from the loaded (and scanned) ini files, with any references to the Xdebug extension commented out. Current ini settings are merged, so that most ini settings made on the command-line or by the application are included (see [Limitations](#limitations))
* `MYAPP_ALLOW_XDEBUG` is set with internal data to flag and use in the restart.
* The command-line and environment are [configured](#process-configuration) for the restart.
* The application is restarted in a new process using `passthru`.
* The restart settings are stored in the environment.
* `MYAPP_ALLOW_XDEBUG` is unset.
* The application runs and exits.
* The main process exits with the exit code from the restarted process.
### Limitations
There are a few things to be aware of when running inside a restarted process.
* Extensions set on the command-line will not be loaded.
* Ini file locations will be reported as per the restart - see [getAllIniFiles()](#getallinifiles).
* Php sub-processes may be loaded with Xdebug enabled - see [Process configuration](#process-configuration).
### Helper methods
These static methods provide information from the current process, regardless of whether it has been restarted or not.
#### _getAllIniFiles()_
Returns an array of the original ini file locations. Use this instead of calling `php_ini_loaded_file` and `php_ini_scanned_files`, which will report the wrong values in a restarted process.
```php
use Composer\XdebugHandler\XdebugHandler;
$files = XdebugHandler::getAllIniFiles();
# $files[0] always exists, it could be an empty string
$loadedIni = array_shift($files);
$scannedInis = $files;
```
These locations are also available in the `MYAPP_ORIGINAL_INIS` environment variable. This is a path-separated string comprising the location returned from `php_ini_loaded_file`, which could be empty, followed by locations parsed from calling `php_ini_scanned_files`.
#### _getRestartSettings()_
Returns an array of settings that can be used with PHP [sub-processes](#sub-processes), or null if the process was not restarted.
```php
use Composer\XdebugHandler\XdebugHandler;
$settings = XdebugHandler::getRestartSettings();
/**
* $settings: array (if the current process was restarted,
* or called with the settings from a previous restart), or null
*
* 'tmpIni' => the temporary ini file used in the restart (string)
* 'scannedInis' => if there were any scanned inis (bool)
* 'scanDir' => the original PHP_INI_SCAN_DIR value (false|string)
* 'phprc' => the original PHPRC value (false|string)
* 'inis' => the original inis from getAllIniFiles (array)
* 'skipped' => the skipped version from getSkippedVersion (string)
*/
```
#### _getSkippedVersion()_
Returns the Xdebug version string that was skipped by the restart, or an empty value if there was no restart (or Xdebug is still loaded, perhaps by an extending class restarting for a reason other than removing Xdebug).
```php
use Composer\XdebugHandler\XdebugHandler;
$version = XdebugHandler::getSkippedVersion();
# $version: '2.6.0' (for example), or an empty string
```
### Setter methods
These methods implement a fluent interface and must be called before the main `check()` method.
#### _setLogger($logger)_
Enables the output of status messages to an external PSR3 logger. All messages are reported with either `DEBUG` or `WARNING` log levels. For example (showing the level and message):
```
// Restart overridden
DEBUG Checking MYAPP_ALLOW_XDEBUG
DEBUG The Xdebug extension is loaded (2.5.0)
DEBUG No restart (MYAPP_ALLOW_XDEBUG=1)
// Failed restart
DEBUG Checking MYAPP_ALLOW_XDEBUG
DEBUG The Xdebug extension is loaded (2.5.0)
WARNING No restart (Unable to create temp ini file at: ...)
```
Status messages can also be output with `XDEBUG_HANDLER_DEBUG`. See [Troubleshooting](#troubleshooting).
#### _setMainScript($script)_
Sets the location of the main script to run in the restart. This is only needed in more esoteric use-cases, or if the `argv[0]` location is inaccessible. The script name `--` is supported for standard input.
#### _setPersistent()_
Configures the restart using [persistent settings](#persistent-settings), so that Xdebug is not loaded in any sub-process.
Use this method if your application invokes one or more PHP sub-process and the Xdebug extension is not needed. This avoids the overhead of implementing specific [sub-process](#sub-processes) strategies.
Alternatively, this method can be used to set up a default _Xdebug-free_ environment which can be changed if a sub-process requires Xdebug, then restored afterwards:
```php
function SubProcessWithXdebug()
{
$phpConfig = new Composer\XdebugHandler\PhpConfig();
# Set the environment to the original configuration
$phpConfig->useOriginal();
# run the process with Xdebug loaded
...
# Restore Xdebug-free environment
$phpConfig->usePersistent();
}
```
### Process configuration
The library offers two strategies to invoke a new PHP process without loading Xdebug, using either _standard_ or _persistent_ settings. Note that this is only important if the application calls a PHP sub-process.
#### Standard settings
Uses command-line options to remove Xdebug from the new process only.
* The -n option is added to the command-line. This tells PHP not to scan for additional inis.
* The temporary ini is added to the command-line with the -c option.
>_If the new process calls a PHP sub-process, Xdebug will be loaded in that sub-process (unless it implements xdebug-handler, in which case there will be another restart)._
This is the default strategy used in the restart.
#### Persistent settings
Uses environment variables to remove Xdebug from the new process and persist these settings to any sub-process.
* `PHP_INI_SCAN_DIR` is set to an empty string. This tells PHP not to scan for additional inis.
* `PHPRC` is set to the temporary ini.
>_If the new process calls a PHP sub-process, Xdebug will not be loaded in that sub-process._
This strategy can be used in the restart by calling [setPersistent()](#setpersistent).
#### Sub-processes
The `PhpConfig` helper class makes it easy to invoke a PHP sub-process (with or without Xdebug loaded), regardless of whether there has been a restart.
Each of its methods returns an array of PHP options (to add to the command-line) and sets up the environment for the required strategy. The [getRestartSettings()](#getrestartsettings) method is used internally.
* `useOriginal()` - Xdebug will be loaded in the new process.
* `useStandard()` - Xdebug will **not** be loaded in the new process - see [standard settings](#standard-settings).
* `userPersistent()` - Xdebug will **not** be loaded in the new process - see [persistent settings](#persistent-settings)
If there was no restart, an empty options array is returned and the environment is not changed.
```php
use Composer\XdebugHandler\PhpConfig;
$config = new PhpConfig;
$options = $config->useOriginal();
# $options: empty array
# environment: PHPRC and PHP_INI_SCAN_DIR set to original values
$options = $config->useStandard();
# $options: [-n, -c, tmpIni]
# environment: PHPRC and PHP_INI_SCAN_DIR set to original values
$options = $config->usePersistent();
# $options: empty array
# environment: PHPRC=tmpIni, PHP_INI_SCAN_DIR=''
```
### Troubleshooting
The following environment settings can be used to troubleshoot unexpected behavior:
* `XDEBUG_HANDLER_DEBUG=1` Outputs status messages to `STDERR`, if it is defined, irrespective of any PSR3 logger. Each message is prefixed `xdebug-handler[pid]`, where pid is the process identifier.
* `XDEBUG_HANDLER_DEBUG=2` As above, but additionally saves the temporary ini file and reports its location in a status message.
### Extending the library
The API is defined by classes and their accessible elements that are not annotated as @internal. The main class has two protected methods that can be overridden to provide additional functionality:
#### _requiresRestart($isLoaded)_
By default the process will restart if Xdebug is loaded. Extending this method allows an application to decide, by returning a boolean (or equivalent) value. It is only called if `MYAPP_ALLOW_XDEBUG` is empty, so it will not be called in the restarted process (where this variable contains internal data), or if the restart has been overridden.
Note that the [setMainScript()](#setmainscriptscript) and [setPersistent()](#setpersistent) setters can be used here, if required.
#### _restart($command)_
An application can extend this to modify the temporary ini file, its location given in the `tmpIni` property. New settings can be safely appended to the end of the data, which is `PHP_EOL` terminated.
Note that the `$command` parameter is the escaped command-line string that will be used for the new process and must be treated accordingly.
Remember to finish with `parent::restart($command)`.
#### Example
This example demonstrates two ways to extend basic functionality:
* To avoid the overhead of spinning up a new process, the restart is skipped if a simple help command is requested.
* The application needs write-access to phar files, so it will force a restart if `phar.readonly` is set (regardless of whether Xdebug is loaded) and change this value in the temporary ini file.
```php
use Composer\XdebugHandler\XdebugHandler;
use MyApp\Command;
class MyRestarter extends XdebugHandler
{
private $required;
protected function requiresRestart($isLoaded)
{
if (Command::isHelp()) {
# No need to disable Xdebug for this
return false;
}
$this->required = (bool) ini_get('phar.readonly');
return $isLoaded || $this->required;
}
protected function restart($command)
{
if ($this->required) {
# Add required ini setting to tmpIni
$content = file_get_contents($this->tmpIni);
$content .= 'phar.readonly=0'.PHP_EOL;
file_put_contents($this->tmpIni, $content);
}
parent::restart($command);
}
}
```
## License
composer/xdebug-handler is licensed under the MIT License, see the LICENSE file for details.
+40
View File
@@ -0,0 +1,40 @@
{
"name": "composer/xdebug-handler",
"description": "Restarts a process without Xdebug.",
"type": "library",
"license": "MIT",
"keywords": [
"xdebug",
"performance"
],
"authors": [
{
"name": "John Stevenson",
"email": "john-stevenson@blueyonder.co.uk"
}
],
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/xdebug-handler/issues"
},
"require": {
"php": "^5.3.2 || ^7.0 || ^8.0",
"psr/log": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8"
},
"autoload": {
"psr-4": {
"Composer\\XdebugHandler\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Composer\\XdebugHandler\\": "tests"
}
},
"scripts": {
"test": "phpunit"
}
}
+73
View File
@@ -0,0 +1,73 @@
<?php
/*
* This file is part of composer/xdebug-handler.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\XdebugHandler;
/**
* @author John Stevenson <john-stevenson@blueyonder.co.uk>
*/
class PhpConfig
{
/**
* Use the original PHP configuration
*
* @return array PHP cli options
*/
public function useOriginal()
{
$this->getDataAndReset();
return array();
}
/**
* Use standard restart settings
*
* @return array PHP cli options
*/
public function useStandard()
{
if ($data = $this->getDataAndReset()) {
return array('-n', '-c', $data['tmpIni']);
}
return array();
}
/**
* Use environment variables to persist settings
*
* @return array PHP cli options
*/
public function usePersistent()
{
if ($data = $this->getDataAndReset()) {
Process::setEnv('PHPRC', $data['tmpIni']);
Process::setEnv('PHP_INI_SCAN_DIR', '');
}
return array();
}
/**
* Returns restart data if available and resets the environment
*
* @return array|null
*/
private function getDataAndReset()
{
if ($data = XdebugHandler::getRestartSettings()) {
Process::setEnv('PHPRC', $data['phprc']);
Process::setEnv('PHP_INI_SCAN_DIR', $data['scanDir']);
}
return $data;
}
}
+181
View File
@@ -0,0 +1,181 @@
<?php
/*
* This file is part of composer/xdebug-handler.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\XdebugHandler;
/**
* Provides utility functions to prepare a child process command-line and set
* environment variables in that process.
*
* @author John Stevenson <john-stevenson@blueyonder.co.uk>
* @internal
*/
class Process
{
/**
* Returns an array of parameters, including a color option if required
*
* A color option is needed because child process output is piped.
*
* @param array $args The script parameters
* @param string $colorOption The long option to force color output
*
* @return array
*/
public static function addColorOption(array $args, $colorOption)
{
if (!$colorOption
|| in_array($colorOption, $args)
|| !preg_match('/^--([a-z]+$)|(^--[a-z]+=)/', $colorOption, $matches)) {
return $args;
}
if (isset($matches[2])) {
// Handle --color(s)= options
if (false !== ($index = array_search($matches[2].'auto', $args))) {
$args[$index] = $colorOption;
return $args;
} elseif (preg_grep('/^'.$matches[2].'/', $args)) {
return $args;
}
} elseif (in_array('--no-'.$matches[1], $args)) {
return $args;
}
// Check for NO_COLOR variable (https://no-color.org/)
if (false !== getenv('NO_COLOR')) {
return $args;
}
if (false !== ($index = array_search('--', $args))) {
// Position option before double-dash delimiter
array_splice($args, $index, 0, $colorOption);
} else {
$args[] = $colorOption;
}
return $args;
}
/**
* Escapes a string to be used as a shell argument.
*
* From https://github.com/johnstevenson/winbox-args
* MIT Licensed (c) John Stevenson <john-stevenson@blueyonder.co.uk>
*
* @param string $arg The argument to be escaped
* @param bool $meta Additionally escape cmd.exe meta characters
* @param bool $module The argument is the module to invoke
*
* @return string The escaped argument
*/
public static function escape($arg, $meta = true, $module = false)
{
if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
return "'".str_replace("'", "'\\''", $arg)."'";
}
$quote = strpbrk($arg, " \t") !== false || $arg === '';
$arg = preg_replace('/(\\\\*)"/', '$1$1\\"', $arg, -1, $dquotes);
if ($meta) {
$meta = $dquotes || preg_match('/%[^%]+%/', $arg);
if (!$meta) {
$quote = $quote || strpbrk($arg, '^&|<>()') !== false;
} elseif ($module && !$dquotes && $quote) {
$meta = false;
}
}
if ($quote) {
$arg = '"'.preg_replace('/(\\\\*)$/', '$1$1', $arg).'"';
}
if ($meta) {
$arg = preg_replace('/(["^&|<>()%])/', '^$1', $arg);
}
return $arg;
}
/**
* Returns true if the output stream supports colors
*
* This is tricky on Windows, because Cygwin, Msys2 etc emulate pseudo
* terminals via named pipes, so we can only check the environment.
*
* @param mixed $output A valid CLI output stream
*
* @return bool
*/
public static function supportsColor($output)
{
if ('Hyper' === getenv('TERM_PROGRAM')) {
return true;
}
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
return (function_exists('sapi_windows_vt100_support')
&& sapi_windows_vt100_support($output))
|| false !== getenv('ANSICON')
|| 'ON' === getenv('ConEmuANSI')
|| 'xterm' === getenv('TERM');
}
if (function_exists('stream_isatty')) {
return stream_isatty($output);
}
if (function_exists('posix_isatty')) {
return posix_isatty($output);
}
$stat = fstat($output);
// Check if formatted mode is S_IFCHR
return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
}
/**
* Makes putenv environment changes available in $_SERVER and $_ENV
*
* @param string $name
* @param string|false $value A false value unsets the variable
*
* @return bool Whether the environment variable was set
*/
public static function setEnv($name, $value = false)
{
$unset = false === $value;
if (!putenv($unset ? $name : $name.'='.$value)) {
return false;
}
if ($unset) {
unset($_SERVER[$name]);
} else {
$_SERVER[$name] = $value;
}
// Update $_ENV if it is being used
if (false !== stripos((string) ini_get('variables_order'), 'E')) {
if ($unset) {
unset($_ENV[$name]);
} else {
$_ENV[$name] = $value;
}
}
return true;
}
}
+163
View File
@@ -0,0 +1,163 @@
<?php
/*
* This file is part of composer/xdebug-handler.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\XdebugHandler;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
/**
* @author John Stevenson <john-stevenson@blueyonder.co.uk>
* @internal
*/
class Status
{
const ENV_RESTART = 'XDEBUG_HANDLER_RESTART';
const CHECK = 'Check';
const ERROR = 'Error';
const INFO = 'Info';
const NORESTART = 'NoRestart';
const RESTART = 'Restart';
const RESTARTING = 'Restarting';
const RESTARTED = 'Restarted';
private $debug;
private $envAllowXdebug;
private $loaded;
private $logger;
private $time;
/**
* Constructor
*
* @param string $envAllowXdebug Prefixed _ALLOW_XDEBUG name
* @param bool $debug Whether debug output is required
*/
public function __construct($envAllowXdebug, $debug)
{
$start = getenv(self::ENV_RESTART);
Process::setEnv(self::ENV_RESTART);
$this->time = $start ? round((microtime(true) - $start) * 1000) : 0;
$this->envAllowXdebug = $envAllowXdebug;
$this->debug = $debug && defined('STDERR');
}
/**
* @param LoggerInterface $logger
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
/**
* Calls a handler method to report a message
*
* @param string $op The handler constant
* @param null|string $data Data required by the handler
*/
public function report($op, $data)
{
if ($this->logger || $this->debug) {
call_user_func(array($this, 'report'.$op), $data);
}
}
/**
* Outputs a status message
*
* @param string $text
* @param string $level
*/
private function output($text, $level = null)
{
if ($this->logger) {
$this->logger->log($level ?: LogLevel::DEBUG, $text);
}
if ($this->debug) {
fwrite(STDERR, sprintf('xdebug-handler[%d] %s', getmypid(), $text.PHP_EOL));
}
}
private function reportCheck($loaded)
{
$this->loaded = $loaded;
$this->output('Checking '.$this->envAllowXdebug);
}
private function reportError($error)
{
$this->output(sprintf('No restart (%s)', $error), LogLevel::WARNING);
}
private function reportInfo($info)
{
$this->output($info);
}
private function reportNoRestart()
{
$this->output($this->getLoadedMessage());
if ($this->loaded) {
$text = sprintf('No restart (%s)', $this->getEnvAllow());
if (!getenv($this->envAllowXdebug)) {
$text .= ' Allowed by application';
}
$this->output($text);
}
}
private function reportRestart()
{
$this->output($this->getLoadedMessage());
Process::setEnv(self::ENV_RESTART, (string) microtime(true));
}
private function reportRestarted()
{
$loaded = $this->getLoadedMessage();
$text = sprintf('Restarted (%d ms). %s', $this->time, $loaded);
$level = $this->loaded ? LogLevel::WARNING : null;
$this->output($text, $level);
}
private function reportRestarting($command)
{
$text = sprintf('Process restarting (%s)', $this->getEnvAllow());
$this->output($text);
$text = 'Running '.$command;
$this->output($text);
}
/**
* Returns the _ALLOW_XDEBUG environment variable as name=value
*
* @return string
*/
private function getEnvAllow()
{
return $this->envAllowXdebug.'='.getenv($this->envAllowXdebug);
}
/**
* Returns the Xdebug status and version
*
* @return string
*/
private function getLoadedMessage()
{
$loaded = $this->loaded ? sprintf('loaded (%s)', $this->loaded) : 'not loaded';
return 'The Xdebug extension is '.$loaded;
}
}
+565
View File
@@ -0,0 +1,565 @@
<?php
/*
* This file is part of composer/xdebug-handler.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\XdebugHandler;
use Psr\Log\LoggerInterface;
/**
* @author John Stevenson <john-stevenson@blueyonder.co.uk>
*/
class XdebugHandler
{
const SUFFIX_ALLOW = '_ALLOW_XDEBUG';
const SUFFIX_INIS = '_ORIGINAL_INIS';
const RESTART_ID = 'internal';
const RESTART_SETTINGS = 'XDEBUG_HANDLER_SETTINGS';
const DEBUG = 'XDEBUG_HANDLER_DEBUG';
/** @var string|null */
protected $tmpIni;
private static $inRestart;
private static $name;
private static $skipped;
private $cli;
private $colorOption;
private $debug;
private $envAllowXdebug;
private $envOriginalInis;
private $loaded;
private $persistent;
private $script;
/** @var Status|null */
private $statusWriter;
/**
* Constructor
*
* The $envPrefix is used to create distinct environment variables. It is
* uppercased and prepended to the default base values. For example 'myapp'
* would result in MYAPP_ALLOW_XDEBUG and MYAPP_ORIGINAL_INIS.
*
* @param string $envPrefix Value used in environment variables
* @param string $colorOption Command-line long option to force color output
* @throws \RuntimeException If a parameter is invalid
*/
public function __construct($envPrefix, $colorOption = '')
{
if (!is_string($envPrefix) || empty($envPrefix) || !is_string($colorOption)) {
throw new \RuntimeException('Invalid constructor parameter');
}
self::$name = strtoupper($envPrefix);
$this->envAllowXdebug = self::$name.self::SUFFIX_ALLOW;
$this->envOriginalInis = self::$name.self::SUFFIX_INIS;
$this->colorOption = $colorOption;
if (extension_loaded('xdebug')) {
$ext = new \ReflectionExtension('xdebug');
$this->loaded = $ext->getVersion() ?: 'unknown';
}
if ($this->cli = PHP_SAPI === 'cli') {
$this->debug = getenv(self::DEBUG);
}
$this->statusWriter = new Status($this->envAllowXdebug, (bool) $this->debug);
}
/**
* Activates status message output to a PSR3 logger
*
* @param LoggerInterface $logger
*
* @return $this
*/
public function setLogger(LoggerInterface $logger)
{
$this->statusWriter->setLogger($logger);
return $this;
}
/**
* Sets the main script location if it cannot be called from argv
*
* @param string $script
*
* @return $this
*/
public function setMainScript($script)
{
$this->script = $script;
return $this;
}
/**
* Persist the settings to keep Xdebug out of sub-processes
*
* @return $this
*/
public function setPersistent()
{
$this->persistent = true;
return $this;
}
/**
* Checks if Xdebug is loaded and the process needs to be restarted
*
* This behaviour can be disabled by setting the MYAPP_ALLOW_XDEBUG
* environment variable to 1. This variable is used internally so that
* the restarted process is created only once.
*/
public function check()
{
$this->notify(Status::CHECK, $this->loaded);
$envArgs = explode('|', (string) getenv($this->envAllowXdebug));
if (empty($envArgs[0]) && $this->requiresRestart((bool) $this->loaded)) {
// Restart required
$this->notify(Status::RESTART);
if ($this->prepareRestart()) {
$command = $this->getCommand();
$this->notify(Status::RESTARTING, $command);
$this->restart($command);
}
return;
}
if (self::RESTART_ID === $envArgs[0] && count($envArgs) === 5) {
// Restarting, so unset environment variable and use saved values
$this->notify(Status::RESTARTED);
Process::setEnv($this->envAllowXdebug);
self::$inRestart = true;
if (!$this->loaded) {
// Skipped version is only set if Xdebug is not loaded
self::$skipped = $envArgs[1];
}
// Put restart settings in the environment
$this->setEnvRestartSettings($envArgs);
return;
}
$this->notify(Status::NORESTART);
if ($settings = self::getRestartSettings()) {
// Called with existing settings, so sync our settings
$this->syncSettings($settings);
}
}
/**
* Returns an array of php.ini locations with at least one entry
*
* The equivalent of calling php_ini_loaded_file then php_ini_scanned_files.
* The loaded ini location is the first entry and may be empty.
*
* @return array
*/
public static function getAllIniFiles()
{
if (!empty(self::$name)) {
$env = getenv(self::$name.self::SUFFIX_INIS);
if (false !== $env) {
return explode(PATH_SEPARATOR, $env);
}
}
$paths = array((string) php_ini_loaded_file());
if ($scanned = php_ini_scanned_files()) {
$paths = array_merge($paths, array_map('trim', explode(',', $scanned)));
}
return $paths;
}
/**
* Returns an array of restart settings or null
*
* Settings will be available if the current process was restarted, or
* called with the settings from an existing restart.
*
* @return array|null
*/
public static function getRestartSettings()
{
$envArgs = explode('|', (string) getenv(self::RESTART_SETTINGS));
if (count($envArgs) !== 6
|| (!self::$inRestart && php_ini_loaded_file() !== $envArgs[0])) {
return;
}
return array(
'tmpIni' => $envArgs[0],
'scannedInis' => (bool) $envArgs[1],
'scanDir' => '*' === $envArgs[2] ? false : $envArgs[2],
'phprc' => '*' === $envArgs[3] ? false : $envArgs[3],
'inis' => explode(PATH_SEPARATOR, $envArgs[4]),
'skipped' => $envArgs[5],
);
}
/**
* Returns the Xdebug version that triggered a successful restart
*
* @return string
*/
public static function getSkippedVersion()
{
return (string) self::$skipped;
}
/**
* Returns true if Xdebug is loaded, or as directed by an extending class
*
* @param bool $isLoaded Whether Xdebug is loaded
*
* @return bool
*/
protected function requiresRestart($isLoaded)
{
return $isLoaded;
}
/**
* Allows an extending class to access the tmpIni
*
* @param string $command
*/
protected function restart($command)
{
$this->doRestart($command);
}
/**
* Executes the restarted command then deletes the tmp ini
*
* @param string $command
*/
private function doRestart($command)
{
passthru($command, $exitCode);
$this->notify(Status::INFO, 'Restarted process exited '.$exitCode);
if ($this->debug === '2') {
$this->notify(Status::INFO, 'Temp ini saved: '.$this->tmpIni);
} else {
@unlink($this->tmpIni);
}
exit($exitCode);
}
/**
* Returns true if everything was written for the restart
*
* If any of the following fails (however unlikely) we must return false to
* stop potential recursion:
* - tmp ini file creation
* - environment variable creation
*
* @return bool
*/
private function prepareRestart()
{
$error = '';
$iniFiles = self::getAllIniFiles();
$scannedInis = count($iniFiles) > 1;
$tmpDir = sys_get_temp_dir();
if (!$this->cli) {
$error = 'Unsupported SAPI: '.PHP_SAPI;
} elseif (!defined('PHP_BINARY')) {
$error = 'PHP version is too old: '.PHP_VERSION;
} elseif (!$this->checkConfiguration($info)) {
$error = $info;
} elseif (!$this->checkScanDirConfig()) {
$error = 'PHP version does not report scanned inis: '.PHP_VERSION;
} elseif (!$this->checkMainScript()) {
$error = 'Unable to access main script: '.$this->script;
} elseif (!$this->writeTmpIni($iniFiles, $tmpDir, $error)) {
$error = $error ?: 'Unable to create temp ini file at: '.$tmpDir;
} elseif (!$this->setEnvironment($scannedInis, $iniFiles)) {
$error = 'Unable to set environment variables';
}
if ($error) {
$this->notify(Status::ERROR, $error);
}
return empty($error);
}
/**
* Returns true if the tmp ini file was written
*
* @param array $iniFiles All ini files used in the current process
* @param string $tmpDir The system temporary directory
* @param string $error Set by method if ini file cannot be read
*
* @return bool
*/
private function writeTmpIni(array $iniFiles, $tmpDir, &$error)
{
if (!$this->tmpIni = @tempnam($tmpDir, '')) {
return false;
}
// $iniFiles has at least one item and it may be empty
if (empty($iniFiles[0])) {
array_shift($iniFiles);
}
$content = '';
$regex = '/^\s*(zend_extension\s*=.*xdebug.*)$/mi';
foreach ($iniFiles as $file) {
// Check for inaccessible ini files
if (($data = @file_get_contents($file)) === false) {
$error = 'Unable to read ini: '.$file;
return false;
}
$content .= preg_replace($regex, ';$1', $data).PHP_EOL;
}
// Merge loaded settings into our ini content, if it is valid
if ($config = parse_ini_string($content)) {
$loaded = ini_get_all(null, false);
$content .= $this->mergeLoadedConfig($loaded, $config);
}
// Work-around for https://bugs.php.net/bug.php?id=75932
$content .= 'opcache.enable_cli=0'.PHP_EOL;
return @file_put_contents($this->tmpIni, $content);
}
/**
* Returns the restart command line
*
* @return string
*/
private function getCommand()
{
$php = array(PHP_BINARY);
$args = array_slice($_SERVER['argv'], 1);
if (!$this->persistent) {
// Use command-line options
array_push($php, '-n', '-c', $this->tmpIni);
}
if (defined('STDOUT') && Process::supportsColor(STDOUT)) {
$args = Process::addColorOption($args, $this->colorOption);
}
$args = array_merge($php, array($this->script), $args);
$cmd = Process::escape(array_shift($args), true, true);
foreach ($args as $arg) {
$cmd .= ' '.Process::escape($arg);
}
return $cmd;
}
/**
* Returns true if the restart environment variables were set
*
* No need to update $_SERVER since this is set in the restarted process.
*
* @param bool $scannedInis Whether there were scanned ini files
* @param array $iniFiles All ini files used in the current process
*
* @return bool
*/
private function setEnvironment($scannedInis, array $iniFiles)
{
$scanDir = getenv('PHP_INI_SCAN_DIR');
$phprc = getenv('PHPRC');
// Make original inis available to restarted process
if (!putenv($this->envOriginalInis.'='.implode(PATH_SEPARATOR, $iniFiles))) {
return false;
}
if ($this->persistent) {
// Use the environment to persist the settings
if (!putenv('PHP_INI_SCAN_DIR=') || !putenv('PHPRC='.$this->tmpIni)) {
return false;
}
}
// Flag restarted process and save values for it to use
$envArgs = array(
self::RESTART_ID,
$this->loaded,
(int) $scannedInis,
false === $scanDir ? '*' : $scanDir,
false === $phprc ? '*' : $phprc,
);
return putenv($this->envAllowXdebug.'='.implode('|', $envArgs));
}
/**
* Logs status messages
*
* @param string $op Status handler constant
* @param null|string $data Optional data
*/
private function notify($op, $data = null)
{
$this->statusWriter->report($op, $data);
}
/**
* Returns default, changed and command-line ini settings
*
* @param array $loadedConfig All current ini settings
* @param array $iniConfig Settings from user ini files
*
* @return string
*/
private function mergeLoadedConfig(array $loadedConfig, array $iniConfig)
{
$content = '';
foreach ($loadedConfig as $name => $value) {
// Value will either be null, string or array (HHVM only)
if (!is_string($value)
|| strpos($name, 'xdebug') === 0
|| $name === 'apc.mmap_file_mask') {
continue;
}
if (!isset($iniConfig[$name]) || $iniConfig[$name] !== $value) {
// Double-quote escape each value
$content .= $name.'="'.addcslashes($value, '\\"').'"'.PHP_EOL;
}
}
return $content;
}
/**
* Returns true if the script name can be used
*
* @return bool
*/
private function checkMainScript()
{
if (null !== $this->script) {
// Allow an application to set -- for standard input
return file_exists($this->script) || '--' === $this->script;
}
if (file_exists($this->script = $_SERVER['argv'][0])) {
return true;
}
// Use a backtrace to resolve Phar and chdir issues
$options = PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : false;
$trace = debug_backtrace($options);
if (($main = end($trace)) && isset($main['file'])) {
return file_exists($this->script = $main['file']);
}
return false;
}
/**
* Adds restart settings to the environment
*
* @param string $envArgs
*/
private function setEnvRestartSettings($envArgs)
{
$settings = array(
php_ini_loaded_file(),
$envArgs[2],
$envArgs[3],
$envArgs[4],
getenv($this->envOriginalInis),
self::$skipped,
);
Process::setEnv(self::RESTART_SETTINGS, implode('|', $settings));
}
/**
* Syncs settings and the environment if called with existing settings
*
* @param array $settings
*/
private function syncSettings(array $settings)
{
if (false === getenv($this->envOriginalInis)) {
// Called by another app, so make original inis available
Process::setEnv($this->envOriginalInis, implode(PATH_SEPARATOR, $settings['inis']));
}
self::$skipped = $settings['skipped'];
$this->notify(Status::INFO, 'Process called with existing restart settings');
}
/**
* Returns true if there are scanned inis and PHP is able to report them
*
* php_ini_scanned_files will fail when PHP_CONFIG_FILE_SCAN_DIR is empty.
* Fixed in 7.1.13 and 7.2.1
*
* @return bool
*/
private function checkScanDirConfig()
{
return !(getenv('PHP_INI_SCAN_DIR')
&& !PHP_CONFIG_FILE_SCAN_DIR
&& (PHP_VERSION_ID < 70113
|| PHP_VERSION_ID === 70200));
}
/**
* Returns true if there are no known configuration issues
*
* @param string $info Set by method
*/
private function checkConfiguration(&$info)
{
if (false !== strpos(ini_get('disable_functions'), 'passthru')) {
$info = 'passthru function is disabled';
return false;
}
if (extension_loaded('uopz') && !ini_get('uopz.disable')) {
// uopz works at opcode level and disables exit calls
if (function_exists('uopz_allow_exit')) {
@uopz_allow_exit(true);
} else {
$info = 'uopz extension is not compatible';
return false;
}
}
return true;
}
}
+43
View File
@@ -0,0 +1,43 @@
language: php
php:
- '7.0'
- '7.2'
env:
global:
- FORCE_COLOR=1
cache:
directories:
- $HOME/.composer/cache
- $HOME/.npm
install:
- composer install --prefer-dist
script:
- vendor/bin/phpunit --coverage-clover=coverage.xml --whitelist lib --bootstrap vendor/autoload.php tests
after_success:
- bash <(curl -s https://codecov.io/bash)
jobs:
include:
- stage: release
language: node_js
node_js: '8'
install:
- npm ci
script:
- npm run semantic-release
after_success: false
stages:
- test
- name: release
if: branch = master AND type = push AND fork = false
branches:
except:
- /^v\d+\.\d+\.\d+$/
+15
View File
@@ -0,0 +1,15 @@
ISC License
Copyright (c) 2016, Felix Frederick Becker
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+32
View File
@@ -0,0 +1,32 @@
{
"name": "felixfbecker/advanced-json-rpc",
"description": "A more advanced JSONRPC implementation",
"type": "library",
"license": "ISC",
"authors": [
{
"name": "Felix Becker",
"email": "felix.b@outlook.com"
}
],
"autoload": {
"psr-4": {
"AdvancedJsonRpc\\": "lib/"
}
},
"autoload-dev": {
"psr-4": {
"AdvancedJsonRpc\\Tests\\": "tests/"
}
},
"require": {
"php": ">=7.0",
"netresearch/jsonmapper": "^1.0 || ^2.0",
"phpdocumentor/reflection-docblock": "^4.0.0 || ^5.0.0"
},
"require-dev": {
"phpunit/phpunit": "^6.0.0"
},
"minimum-stability": "dev",
"prefer-stable": true
}
+172
View File
@@ -0,0 +1,172 @@
<?php
declare(strict_types = 1);
namespace AdvancedJsonRpc;
use Sabre\Event\Loop;
use JsonMapper;
use JsonMapper_Exception;
use phpDocumentor\Reflection\DocBlockFactory;
use phpDocumentor\Reflection\Types;
use ReflectionException;
use ReflectionMethod;
use ReflectionNamedType;
class Dispatcher
{
/**
* @var object
*/
private $target;
/**
* @var string
*/
private $delimiter;
/**
* method => ReflectionMethod[]
*
* @var ReflectionMethod
*/
private $methods;
/**
* @var \phpDocumentor\Reflection\DocBlockFactory
*/
private $docBlockFactory;
/**
* @var \phpDocumentor\Reflection\Types\ContextFactory
*/
private $contextFactory;
/**
* @param object $target The target object that should receive the method calls
* @param string $delimiter A delimiter for method calls on properties, for example someProperty->someMethod
*/
public function __construct($target, $delimiter = '->')
{
$this->target = $target;
$this->delimiter = $delimiter;
$this->docBlockFactory = DocBlockFactory::createInstance();
$this->contextFactory = new Types\ContextFactory();
$this->mapper = new JsonMapper();
}
/**
* Calls the appropriate method handler for an incoming Message
*
* @param string|object $msg The incoming message
* @return mixed
*/
public function dispatch($msg)
{
if (is_string($msg)) {
$msg = json_decode($msg);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Error(json_last_error_msg(), ErrorCode::PARSE_ERROR);
}
}
// Find out the object and function that should be called
$obj = $this->target;
$parts = explode($this->delimiter, $msg->method);
// The function to call is always the last part of the method
$fn = array_pop($parts);
// For namespaced methods like textDocument/didOpen, call the didOpen method on the $textDocument property
// For simple methods like initialize, shutdown, exit, this loop will simply not be entered and $obj will be
// the target
foreach ($parts as $part) {
if (!isset($obj->$part)) {
throw new Error("Method {$msg->method} is not implemented", ErrorCode::METHOD_NOT_FOUND);
}
$obj = $obj->$part;
}
if (!isset($this->methods[$msg->method])) {
try {
$method = new ReflectionMethod($obj, $fn);
$this->methods[$msg->method] = $method;
} catch (ReflectionException $e) {
throw new Error($e->getMessage(), ErrorCode::METHOD_NOT_FOUND, null, $e);
}
}
$method = $this->methods[$msg->method];
$parameters = $method->getParameters();
if ($method->getDocComment()) {
$docBlock = $this->docBlockFactory->create(
$method->getDocComment(),
$this->contextFactory->createFromReflector($method->getDeclaringClass())
);
$paramTags = $docBlock->getTagsByName('param');
}
$args = [];
if (isset($msg->params)) {
// Find out the position
if (is_array($msg->params)) {
$args = $msg->params;
} else if (is_object($msg->params)) {
foreach ($parameters as $pos => $parameter) {
$value = null;
foreach(get_object_vars($msg->params) as $key => $val) {
if ($parameter->name === $key) {
$value = $val;
break;
}
}
$args[$pos] = $value;
}
} else {
throw new Error('Params must be structured or omitted', ErrorCode::INVALID_REQUEST);
}
foreach ($args as $position => $value) {
try {
// If the type is structured (array or object), map it with JsonMapper
if (is_object($value)) {
// Does the parameter have a type hint?
$param = $parameters[$position];
if ($param->hasType()) {
$paramType = $param->getType();
if ($paramType instanceof ReflectionNamedType) {
// We have object data to map and want the class name.
// This should not include the `?` if the type was nullable.
$class = $paramType->getName();
} else {
// Fallback for php 7.0, which is still supported (and doesn't have nullable).
$class = (string)$paramType;
}
$value = $this->mapper->map($value, new $class());
}
} else if (is_array($value) && isset($docBlock)) {
// Get the array type from the DocBlock
$type = $paramTags[$position]->getType();
// For union types, use the first one that is a class array (often it is SomeClass[]|null)
if ($type instanceof Types\Compound) {
for ($i = 0; $t = $type->get($i); $i++) {
if (
$t instanceof Types\Array_
&& $t->getValueType() instanceof Types\Object_
&& (string)$t->getValueType() !== 'object'
) {
$class = (string)$t->getValueType()->getFqsen();
$value = $this->mapper->mapArray($value, [], $class);
break;
}
}
} else if ($type instanceof Types\Array_) {
$class = (string)$type->getValueType()->getFqsen();
$value = $this->mapper->mapArray($value, [], $class);
} else {
throw new Error('Type is not matching @param tag', ErrorCode::INVALID_PARAMS);
}
}
} catch (JsonMapper_Exception $e) {
throw new Error($e->getMessage(), ErrorCode::INVALID_PARAMS, null, $e);
}
$args[$position] = $value;
}
}
ksort($args);
$result = $obj->$fn(...$args);
return $result;
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
declare(strict_types = 1);
namespace AdvancedJsonRpc;
use Exception;
use Throwable;
class Error extends Exception
{
/**
* A Number that indicates the error type that occurred. This MUST be an integer.
*
* @var int
*/
public $code;
/**
* A String providing a short description of the error. The message SHOULD be limited to a concise single sentence.
*
* @var string
*/
public $message;
/**
* A Primitive or Structured value that contains additional information about the error. This may be omitted. The
* value of this member is defined by the Server (e.g. detailed error information, nested errors etc.).
*
* @var mixed
*/
public $data;
public function __construct(string $message, int $code, $data = null, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
$this->data = $data;
}
}
+48
View File
@@ -0,0 +1,48 @@
<?php
declare(strict_types = 1);
namespace AdvancedJsonRpc;
/**
* The error codes from and including -32768 to -32000 are reserved for pre-defined errors. Any code within this range,
* but not defined explicitly below is reserved for future use. The error codes are nearly the same as those suggested
* for XML-RPC at the following url: http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php
* The remainder of the space is available for application defined errors.
*/
abstract class ErrorCode
{
/**
* Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.
*/
const PARSE_ERROR = -32700;
/**
* The JSON sent is not a valid Request object.
*/
const INVALID_REQUEST = -32600;
/**
* The method does not exist / is not available.
*/
const METHOD_NOT_FOUND = -32601;
/**
* Invalid method parameter(s).
*/
const INVALID_PARAMS = -32602;
/**
* Internal JSON-RPC error.
*/
const INTERNAL_ERROR = -32603;
/**
* Reserved for implementation-defined server-errors.
*/
const SERVER_ERROR_START = -32099;
/**
* Reserved for implementation-defined server-errors.
*/
const SERVER_ERROR_END = -32000;
}
@@ -0,0 +1,40 @@
<?php
declare(strict_types = 1);
namespace AdvancedJsonRpc;
/**
* When a rpc call is made, the Server MUST reply with a Response, except for in the case of Notifications. The Response
* is expressed as a single JSON Object, with the following members:
*/
class ErrorResponse extends Response
{
/**
* This member is REQUIRED on error. This member MUST NOT exist if there was no error triggered during invocation.
* The value for this member MUST be an Object as defined in section 5.1.
*
* @var \AdvancedJsonRpc\Error
*/
public $error;
/**
* A message is considered a Response if it has an ID and either a result or an error
*
* @param object $msg A decoded message body
* @return bool
*/
public static function isErrorResponse($msg): bool
{
return is_object($msg) && isset($msg->id) && isset($msg->error);
}
/**
* @param int|string $id
* @param \AdvancedJsonRpc\Error $error
*/
public function __construct($id, Error $error)
{
parent::__construct($id);
$this->error = $error;
}
}
+52
View File
@@ -0,0 +1,52 @@
<?php
declare(strict_types = 1);
namespace AdvancedJsonRpc;
/**
* Base message
*/
abstract class Message
{
/**
* A String specifying the version of the JSON-RPC protocol. MUST be exactly "2.0".
*
* @var string
*/
public $jsonrpc = '2.0';
/**
* Returns the appropriate Message subclass
*
* @param string $msg
* @return Message
*/
public static function parse(string $msg): Message
{
$decoded = json_decode($msg);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Error(json_last_error_msg(), ErrorCode::PARSE_ERROR);
}
if (Notification::isNotification($decoded)) {
$obj = new Notification($decoded->method, $decoded->params ?? null);
} else if (Request::isRequest($decoded)) {
$obj = new Request($decoded->id, $decoded->method, $decoded->params ?? null);
} else if (SuccessResponse::isSuccessResponse($decoded)) {
$obj = new SuccessResponse($decoded->id, $decoded->result);
} else if (ErrorResponse::isErrorResponse($decoded)) {
$obj = new ErrorResponse($decoded->id, new Error($decoded->error->message, $decoded->error->code, $decoded->error->data ?? null));
} else {
throw new Error('Invalid message', ErrorCode::INVALID_REQUEST);
}
return $obj;
}
public function __toString(): string
{
$encoded = json_encode($this);
if ($encoded === false) {
throw new Error(json_last_error_msg(), ErrorCode::INTERNAL_ERROR);
}
return $encoded;
}
}
@@ -0,0 +1,56 @@
<?php
declare(strict_types = 1);
namespace AdvancedJsonRpc;
/**
* A Notification is a Request object without an "id" member. A Request object that is a Notification signifies the
* Client's lack of interest in the corresponding Response object, and as such no Response object needs to be returned
* to the client. The Server MUST NOT reply to a Notification, including those that are within a batch request.
* Notifications are not confirmable by definition, since they do not have a Response object to be returned. As such,
* the Client would not be aware of any errors (like e.g. "Invalid params","Internal error").
*/
class Notification extends Message
{
/**
* A String containing the name of the method to be invoked. Method names that begin with the word rpc followed by a
* period character (U+002E or ASCII 46) are reserved for rpc-internal methods and extensions and MUST NOT be used
* for anything else.
*
* @var string
*/
public $method;
/**
* A Structured value that holds the parameter values to be used during the invocation of the method. This member
* MAY be omitted. If present, parameters for the rpc call MUST be provided as a Structured value. Either
* by-position through an Array or by-name through an Object. by-position: params MUST be an Array, containing the
* values in the Server expected order. by-name: params MUST be an Object, with member names that match the Server
* expected parameter names. The absence of expected names MAY result in an error being generated. The names MUST
* match exactly, including case, to the method's expected parameters.
*
* @var object|array|null
*/
public $params;
/**
* A message is considered a Notification if it has a method but no ID.
*
* @param object $msg A decoded message body
* @return bool
*/
public static function isNotification($msg): bool
{
return is_object($msg) && !property_exists($msg, 'id') && isset($msg->method);
}
/**
* @param string $method
* @param mixed $params
*/
public function __construct(string $method, $params = null)
{
$this->method = $method;
$this->params = $params;
}
}
+63
View File
@@ -0,0 +1,63 @@
<?php
declare(strict_types = 1);
namespace AdvancedJsonRpc;
/**
* A rpc call is represented by sending a Request object to a Server
*/
class Request extends Message
{
/**
* An identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is
* not included it is assumed to be a notification. The value SHOULD normally not be NULL and Numbers SHOULD NOT
* contain fractional parts.
*
* @var int|string
*/
public $id;
/**
* A String containing the name of the method to be invoked. Method names that begin with the word rpc followed by a
* period character (U+002E or ASCII 46) are reserved for rpc-internal methods and extensions and MUST NOT be used
* for anything else.
*
* @var string
*/
public $method;
/**
* A Structured value that holds the parameter values to be used during the invocation of the method. This member
* MAY be omitted. If present, parameters for the rpc call MUST be provided as a Structured value. Either
* by-position through an Array or by-name through an Object. by-position: params MUST be an Array, containing the
* values in the Server expected order. by-name: params MUST be an Object, with member names that match the Server
* expected parameter names. The absence of expected names MAY result in an error being generated. The names MUST
* match exactly, including case, to the method's expected parameters.
*
* @var object|array|null
*/
public $params;
/**
* A message is considered a Request if it has an ID and a method.
*
* @param object $msg A decoded message body
* @return bool
*/
public static function isRequest($msg): bool
{
return is_object($msg) && property_exists($msg, 'id') && isset($msg->method);
}
/**
* @param string|int $id
* @param string $method
* @param object|array $params
*/
public function __construct($id, string $method, $params = null)
{
$this->id = $id;
$this->method = $method;
$this->params = $params;
}
}
+40
View File
@@ -0,0 +1,40 @@
<?php
declare(strict_types = 1);
namespace AdvancedJsonRpc;
/**
* When a rpc call is made, the Server MUST reply with a Response, except for in the case of Notifications. The Response
* is expressed as a single JSON Object, with the following members:
*/
abstract class Response extends Message
{
/**
* This member is REQUIRED. It MUST be the same as the value of the id member in the Request Object. If there was an
* error in detecting the id in the Request object (e.g. Parse error/Invalid Request), it MUST be Null.
*
* @var int|string
*/
public $id;
/**
* A message is considered a Response if it has an ID and either a result or an error
*
* @param object $msg A decoded message body
* @return bool
*/
public static function isResponse($msg): bool
{
return is_object($msg) && property_exists($msg, 'id') && (property_exists($msg, 'result') || isset($msg->error));
}
/**
* @param int|string $id
* @param mixed $result
* @param ResponseError $error
*/
public function __construct($id)
{
$this->id = $id;
}
}
@@ -0,0 +1,40 @@
<?php
declare(strict_types = 1);
namespace AdvancedJsonRpc;
/**
* When a rpc call is made, the Server MUST reply with a Response, except for in the case of Notifications. The Response
* is expressed as a single JSON Object, with the following members:
*/
class SuccessResponse extends Response
{
/**
* This member is REQUIRED on success. This member MUST NOT exist if there was an error invoking the method. The
* value of this member is determined by the method invoked on the Server.
*
* @var mixed
*/
public $result;
/**
* A message is considered a SuccessResponse if it has an ID and either a result
*
* @param object $msg A decoded message body
* @return bool
*/
public static function isSuccessResponse($msg): bool
{
return is_object($msg) && property_exists($msg, 'id') && property_exists($msg, 'result');
}
/**
* @param int|string $id
* @param mixed $result
*/
public function __construct($id, $result)
{
parent::__construct($id);
$this->result = $result;
}
}
+17
View File
@@ -0,0 +1,17 @@
Copyright (c) Microsoft Corporation
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,22 @@
Microsoft/tolerant-php-parser
THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
Do Not Translate or Localize
This project incorporates components from the projects listed below. The original copyright notices and the licenses under which Microsoft received such components are set forth below. Microsoft reserves all rights not expressly granted herein, whether by implication, estoppel or otherwise.
1. php/php-langspec (https://github.com/php/php-langspec)
%% php/php-langspec NOTICES AND INFORMATION BEGIN HERE
=========================================
Facebook has dedicated all copyright to this specification to the public
domain worldwide under the CC0 Public Domain Dedication located at
<http://creativecommons.org/publicdomain/zero/1.0/>.
The first draft of this specification was initially written in 2014 by
Facebook, Inc.
This specification is distributed without any warranty.
=========================================
END OF php/php-langspec NOTICES AND INFORMATION
+21
View File
@@ -0,0 +1,21 @@
{
"name": "microsoft/tolerant-php-parser",
"description": "Tolerant PHP-to-AST parser designed for IDE usage scenarios",
"type": "library",
"require": {
"php": ">=7.0"
},
"require-dev": {
"phpunit/phpunit": "^6.4"
},
"license": "MIT",
"authors": [
{
"name": "Rob Lourens",
"email": "roblou@microsoft.com"
}
],
"autoload": {
"psr-4": { "Microsoft\\PhpParser\\": ["src/"] }
}
}
+8
View File
@@ -0,0 +1,8 @@
parameters:
level: 2
paths:
- src/
ignoreErrors:
# phpstan issue, see: https://github.com/phpstan/phpstan/issues/1306
- "/Variable .unaryExpression might not be defined./"
- "/Variable .prefix might not be defined./"
@@ -0,0 +1,116 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser;
class CharacterCodes {
const _0 = 0x30;
const _1 = 0x31;
const _2 = 0x32;
const _3 = 0x33;
const _4 = 0x34;
const _5 = 0x35;
const _6 = 0x36;
const _7 = 0x37;
const _8 = 0x38;
const _9 = 0x39;
const a = 0x61;
const b = 0x62;
const c = 0x63;
const d = 0x64;
const e = 0x65;
const f = 0x66;
const g = 0x67;
const h = 0x68;
const i = 0x69;
const j = 0x6A;
const k = 0x6B;
const l = 0x6C;
const m = 0x6D;
const n = 0x6E;
const o = 0x6F;
const p = 0x70;
const q = 0x71;
const r = 0x72;
const s = 0x73;
const t = 0x74;
const u = 0x75;
const v = 0x76;
const w = 0x77;
const x = 0x78;
const y = 0x79;
const z = 0x7A;
const A = 0x41;
const B = 0x42;
const C = 0x43;
const D = 0x44;
const E = 0x45;
const F = 0x46;
const G = 0x47;
const H = 0x48;
const I = 0x49;
const J = 0x4A;
const K = 0x4B;
const L = 0x4C;
const M = 0x4D;
const N = 0x4E;
const O = 0x4F;
const P = 0x50;
const Q = 0x51;
const R = 0x52;
const S = 0x53;
const T = 0x54;
const U = 0x55;
const V = 0x56;
const W = 0x57;
const X = 0x58;
const Y = 0x59;
const Z = 0x5a;
const _underscore = 0x5F; // _
const _dollar = 0x24; // $
const _ampersand = 0x26; // &
const _asterisk = 0x2A; // *
const _at = 0x40; // @
const _backslash = 0x5C; // \
const _backtick = 0x60; // `
const _bar = 0x7C; // |
const _caret = 0x5E; // ^
const _closeBrace = 0x7D; // }
const _closeBracket = 0x5D; // ]
const _closeParen = 0x29; // )
const _colon = 0x3A; // :
const _comma = 0x2C; // ;
const _dot = 0x2E; // .
const _doubleQuote = 0x22; // "
const _equals = 0x3D; // =
const _exclamation = 0x21; // !
const _greaterThan = 0x3E; // >
const _hash = 0x23; // #
const _lessThan = 0x3C; // <
const _minus = 0x2D; // -
const _openBrace = 0x7B; // {
const _openBracket = 0x5B; // [
const _openParen = 0x28; // (
const _percent = 0x25; // %
const _plus = 0x2B; // +
const _question = 0x3F; // ?
const _semicolon = 0x3B; // ;
const _singleQuote = 0x27; // '
const _slash = 0x2F; // /
const _tilde = 0x7E; // ~
const _backspace = 0x08; // \b
const _formFeed = 0x0C; // \f
const _byteOrderMark = 0xFEFF;
const _space = 0x20;
const _newline = 0x0A; // \n
const _return = 0x0D; // \r
const _tab = 0x09; // \t
const _verticalTab = 0x0B; // \v
}
+12
View File
@@ -0,0 +1,12 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser;
/**
* Represents Classes, Interfaces and Traits.
*/
interface ClassLike {}
+28
View File
@@ -0,0 +1,28 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser;
class Diagnostic {
/** @var int */
public $kind;
/** @var string */
public $message;
/** @var int */
public $start;
/** @var int */
public $length;
public function __construct(int $kind, string $message, int $start, int $length) {
$this->kind = $kind;
$this->message = $message;
$this->start = $start;
$this->length = $length;
}
}
@@ -0,0 +1,12 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser;
class DiagnosticKind {
const Error = 0;
const Warning = 1;
}
@@ -0,0 +1,110 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser;
use Microsoft\PhpParser\Node;
class DiagnosticsProvider {
/**
* @var string[] maps the token kind to the corresponding name
*/
private static $tokenKindToText;
/**
* @param int $kind (must be a valid token kind)
* @return string
*/
public static function getTextForTokenKind($kind) {
return self::$tokenKindToText[$kind];
}
/**
* This is called when this class is loaded, at the bottom of this file.
* @return void
*/
public static function initTokenKindToText() {
self::$tokenKindToText = \array_flip(\array_merge(
TokenStringMaps::OPERATORS_AND_PUNCTUATORS,
TokenStringMaps::KEYWORDS,
TokenStringMaps::RESERVED_WORDS
));
}
/**
* Returns the diagnostic for $node, or null.
* @param \Microsoft\PhpParser\Node|\Microsoft\PhpParser\Token $node
* @return Diagnostic|null
*/
public static function checkDiagnostics($node) {
if ($node instanceof Token) {
if (\get_class($node) === Token::class) {
return null;
}
return self::checkDiagnosticForUnexpectedToken($node);
}
if ($node instanceof Node) {
return $node->getDiagnosticForNode();
}
return null;
}
/**
* @param Token $token
* @return Diagnostic|null
*/
private static function checkDiagnosticForUnexpectedToken($token) {
if ($token instanceof SkippedToken) {
// TODO - consider also attaching parse context information to skipped tokens
// this would allow us to provide more helpful error messages that inform users what to do
// about the problem rather than simply pointing out the mistake.
return new Diagnostic(
DiagnosticKind::Error,
"Unexpected '" .
(self::$tokenKindToText[$token->kind]
?? Token::getTokenKindNameFromValue($token->kind)) .
"'",
$token->start,
$token->getEndPosition() - $token->start
);
} elseif ($token instanceof MissingToken) {
return new Diagnostic(
DiagnosticKind::Error,
"'" .
(self::$tokenKindToText[$token->kind]
?? Token::getTokenKindNameFromValue($token->kind)) .
"' expected.",
$token->start,
$token->getEndPosition() - $token->start
);
}
return null;
}
/**
* Traverses AST to generate diagnostics.
* @param \Microsoft\PhpParser\Node $n
* @return Diagnostic[]
*/
public static function getDiagnostics(Node $n) : array {
$diagnostics = [];
/**
* @param \Microsoft\PhpParser\Node|\Microsoft\PhpParser\Token $node
*/
$n->walkDescendantNodesAndTokens(function($node) use (&$diagnostics) {
if (($diagnostic = self::checkDiagnostics($node)) !== null) {
$diagnostics[] = $diagnostic;
}
});
return $diagnostics;
}
}
DiagnosticsProvider::initTokenKindToText();
@@ -0,0 +1,142 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser;
/**
* FilePositionMap can be used to get the line number for a large number of nodes (starting from 1).
* It works the most efficiently when the requested node is close to the previously requested node.
*
* Other designs that weren't chosen:
* - Precomputing all of the start/end offsets when initializing was slower - Some offsets weren't needed, and walking the tree was slower.
* - Caching line numbers for previously requested offsets wasn't really necessary, since offsets are usually close together and weren't requested repeatedly.
*/
class FilePositionMap {
/** @var string the full file contents */
private $fileContents;
/** @var int - Precomputed strlen($file_contents) */
private $fileContentsLength;
/** @var int the 0-based byte offset of the most recent request for a line number. */
private $currentOffset;
/** @var int the 1-based line number for $this->currentOffset (updated whenever currentOffset is updated) */
private $lineForCurrentOffset;
public function __construct(string $file_contents) {
$this->fileContents = $file_contents;
$this->fileContentsLength = \strlen($file_contents);
$this->currentOffset = 0;
$this->lineForCurrentOffset = 1;
}
/**
* @param Node $node the node to get the start line for.
* TODO deprecate and merge this and getTokenStartLine into getStartLine
* if https://github.com/Microsoft/tolerant-php-parser/issues/166 is fixed,
* (i.e. if there is a consistent way to get the start offset)
*/
public function getNodeStartLine(Node $node) : int {
return $this->getLineNumberForOffset($node->getStart());
}
/**
* @param Token $token the token to get the start line for.
*/
public function getTokenStartLine(Token $token) : int {
return $this->getLineNumberForOffset($token->start);
}
/**
* @param Node|Token $node
*/
public function getStartLine($node) : int {
if ($node instanceof Token) {
$offset = $node->start;
} else {
$offset = $node->getStart();
}
return $this->getLineNumberForOffset($offset);
}
/**
* @param Node|Token $node
* Similar to getStartLine but includes the column
*/
public function getStartLineCharacterPositionForOffset($node) : LineCharacterPosition {
if ($node instanceof Token) {
$offset = $node->start;
} else {
$offset = $node->getStart();
}
return $this->getLineCharacterPositionForOffset($offset);
}
/** @param Node|Token $node */
public function getEndLine($node) : int {
return $this->getLineNumberForOffset($node->getEndPosition());
}
/**
* @param Node|Token $node
* Similar to getStartLine but includes the column
*/
public function getEndLineCharacterPosition($node) : LineCharacterPosition {
return $this->getLineCharacterPositionForOffset($node->getEndPosition());
}
/**
* @param int $offset
* Similar to getStartLine but includes both the line and the column
*/
public function getLineCharacterPositionForOffset(int $offset) : LineCharacterPosition {
$line = $this->getLineNumberForOffset($offset);
$character = $this->getColumnForOffset($offset);
return new LineCharacterPosition($line, $character);
}
/**
* @param int $offset - A 0-based byte offset
* @return int - gets the 1-based line number for $offset
*/
public function getLineNumberForOffset(int $offset) : int {
if ($offset < 0) {
$offset = 0;
} elseif ($offset > $this->fileContentsLength) {
$offset = $this->fileContentsLength;
}
$currentOffset = $this->currentOffset;
if ($offset > $currentOffset) {
$this->lineForCurrentOffset += \substr_count($this->fileContents, "\n", $currentOffset, $offset - $currentOffset);
$this->currentOffset = $offset;
} elseif ($offset < $currentOffset) {
$this->lineForCurrentOffset -= \substr_count($this->fileContents, "\n", $offset, $currentOffset - $offset);
$this->currentOffset = $offset;
}
return $this->lineForCurrentOffset;
}
/**
* @param int $offset - A 0-based byte offset
* @return int - gets the 1-based column number for $offset
*/
public function getColumnForOffset(int $offset) : int {
$length = $this->fileContentsLength;
if ($offset <= 1) {
return 1;
} elseif ($offset > $length) {
$offset = $length;
}
// Postcondition: offset >= 1, ($lastNewlinePos < $offset)
// If there was no previous newline, lastNewlinePos = 0
// Start strrpos check from the character before the current character,
// in case the current character is a newline.
$lastNewlinePos = \strrpos($this->fileContents, "\n", -$length + $offset - 1);
return 1 + $offset - ($lastNewlinePos === false ? 0 : $lastNewlinePos + 1);
}
}
@@ -0,0 +1,13 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser;
/**
* Interface for recognizing functions easily.
* Each Node that implements this interface can be considered a function.
*/
interface FunctionLike {}
@@ -0,0 +1,17 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser;
class LineCharacterPosition {
public $line;
public $character;
public function __construct(int $line, int $character) {
$this->line = $line;
$this->character = $character;
}
}
@@ -0,0 +1,20 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser;
class MissingToken extends Token {
public function __construct(int $kind, int $fullStart) {
parent::__construct($kind, $fullStart, $fullStart, 0);
}
public function jsonSerialize() {
return array_merge(
["error" => $this->getTokenKindNameFromValue(TokenKind::MissingToken)],
parent::jsonSerialize()
);
}
}
@@ -0,0 +1,11 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser;
interface NamespacedNameInterface {
public function getNamespacedName() : ResolvedName;
}
@@ -0,0 +1,50 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser;
use Microsoft\PhpParser\Node\NamespaceUseClause;
use Microsoft\PhpParser\Node\NamespaceUseGroupClause;
use Microsoft\PhpParser\Node\QualifiedName;
use Microsoft\PhpParser\Node\Statement\NamespaceDefinition;
use Microsoft\PhpParser\Node\Statement\NamespaceUseDeclaration;
trait NamespacedNameTrait {
public abstract function getNamespaceDefinition();
public abstract function getFileContents() : string;
public abstract function getNameParts() : array;
/**
* Gets resolved name from current namespace. Note that this is not necessarily the *actual* name
* that is resolved during compilation or at runtime. For that, see QualifiedName::getResolvedName().
*
* @return ResolvedName
*/
public function getNamespacedName() : ResolvedName {
$namespaceDefinition = $this->getNamespaceDefinition();
$content = $this->getFileContents();
if ($namespaceDefinition === null) {
// global namespace -> strip namespace\ prefix
return ResolvedName::buildName($this->getNameParts(), $content);
}
if ($namespaceDefinition->name !== null) {
$resolvedName = ResolvedName::buildName($namespaceDefinition->name->nameParts, $content);
} else {
$resolvedName = ResolvedName::buildName([], $content);
}
if (
!($this instanceof QualifiedName && (
($this->parent instanceof NamespaceDefinition) ||
($this->parent instanceof NamespaceUseDeclaration) ||
($this->parent instanceof NamespaceUseClause) ||
($this->parent instanceof NamespaceUseGroupClause)))
) {
$resolvedName->addNameParts($this->getNameParts(), $content);
}
return $resolvedName;
}
}
+698
View File
@@ -0,0 +1,698 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser;
use Microsoft\PhpParser\Node\NamespaceUseClause;
use Microsoft\PhpParser\Node\NamespaceUseGroupClause;
use Microsoft\PhpParser\Node\SourceFileNode;
use Microsoft\PhpParser\Node\Statement\NamespaceDefinition;
use Microsoft\PhpParser\Node\Statement\NamespaceUseDeclaration;
abstract class Node implements \JsonSerializable {
const CHILD_NAMES = [];
/** @var array[] Map from node class to array of child keys */
private static $childNames = [];
/** @var Node|null */
public $parent;
public function getNodeKindName() : string {
// Use strrpos (rather than explode) to avoid creating a temporary array.
return substr(static::class, strrpos(static::class, "\\") + 1);
}
/**
* Gets start position of Node, not including leading comments and whitespace.
* @return int
* @throws \Exception
*/
public function getStart() : int {
$child = $this->getChildNodesAndTokens()->current();
if ($child instanceof Node) {
return $child->getStart();
} elseif ($child instanceof Token) {
return $child->start;
}
throw new \Exception("Unknown type in AST");
}
/**
* Gets start position of Node, including leading comments and whitespace
* @return int
* @throws \Exception
*/
public function getFullStart() : int {
foreach($this::CHILD_NAMES as $name) {
if (($child = $this->$name) !== null) {
if (\is_array($child)) {
if(!isset($child[0])) {
continue;
}
$child = $child[0];
}
if ($child instanceof Node) {
return $child->getFullStart();
}
if ($child instanceof Token) {
return $child->fullStart;
}
throw new \Exception("Unknown type in AST: " . \gettype($child));
}
};
throw new \RuntimeException("Could not resolve full start position");
}
/**
* Gets parent of current node (returns null if has no parent)
* @return null|Node
*/
public function getParent() {
return $this->parent;
}
/**
* Gets first ancestor that is an instance of one of the provided classes.
* Returns null if there is no match.
*
* @param string ...$classNames
* @return Node|null
*/
public function getFirstAncestor(...$classNames) {
$ancestor = $this;
while (($ancestor = $ancestor->parent) !== null) {
foreach ($classNames as $className) {
if ($ancestor instanceof $className) {
return $ancestor;
}
}
}
return null;
}
/**
* Gets first child that is an instance of one of the provided classes.
* Returns null if there is no match.
*
* @param array ...$classNames
* @return Node|null
*/
public function getFirstChildNode(...$classNames) {
foreach ($this::CHILD_NAMES as $name) {
$val = $this->$name;
foreach ($classNames as $className) {
if (\is_array($val)) {
foreach ($val as $child) {
if ($child instanceof $className) {
return $child;
}
}
continue;
} elseif ($val instanceof $className) {
return $val;
}
}
}
return null;
}
/**
* Gets first descendant node that is an instance of one of the provided classes.
* Returns null if there is no match.
*
* @param array ...$classNames
* @return Node|null
*/
public function getFirstDescendantNode(...$classNames) {
foreach ($this->getDescendantNodes() as $descendant) {
foreach ($classNames as $className) {
if ($descendant instanceof $className) {
return $descendant;
}
}
}
return null;
}
/**
* Gets root of the syntax tree (returns self if has no parents)
* @return SourceFileNode (expect root to be SourceFileNode unless the tree was manipulated)
*/
public function getRoot() : Node {
$node = $this;
while ($node->parent !== null) {
$node = $node->parent;
}
return $node;
}
/**
* Gets generator containing all descendant Nodes and Tokens.
*
* @param callable|null $shouldDescendIntoChildrenFn
* @return \Generator|Node[]|Token[]
*/
public function getDescendantNodesAndTokens(callable $shouldDescendIntoChildrenFn = null) {
// TODO - write unit tests to prove invariants
// (concatenating all descendant Tokens should produce document, concatenating all Nodes should produce document)
foreach ($this->getChildNodesAndTokens() as $child) {
// Check possible types of $child, most frequent first
if ($child instanceof Node) {
yield $child;
if ($shouldDescendIntoChildrenFn === null || $shouldDescendIntoChildrenFn($child)) {
yield from $child->getDescendantNodesAndTokens($shouldDescendIntoChildrenFn);
}
} elseif ($child instanceof Token) {
yield $child;
}
}
}
/**
* Iterate over all descendant Nodes and Tokens, calling $callback.
* This can often be faster than getDescendantNodesAndTokens
* if you just need to call something and don't need a generator.
*
* @param callable $callback a callback that accepts Node|Token
* @param callable|null $shouldDescendIntoChildrenFn
* @return void
*/
public function walkDescendantNodesAndTokens(callable $callback, callable $shouldDescendIntoChildrenFn = null) {
// TODO - write unit tests to prove invariants
// (concatenating all descendant Tokens should produce document, concatenating all Nodes should produce document)
foreach (static::CHILD_NAMES as $name) {
$child = $this->$name;
// Check possible types of $child, most frequent first
if ($child instanceof Token) {
$callback($child);
} elseif ($child instanceof Node) {
$callback($child);
if ($shouldDescendIntoChildrenFn === null || $shouldDescendIntoChildrenFn($child)) {
$child->walkDescendantNodesAndTokens($callback, $shouldDescendIntoChildrenFn);
}
} elseif (\is_array($child)) {
foreach ($child as $childElement) {
if ($childElement instanceof Token) {
$callback($childElement);
} elseif ($childElement instanceof Node) {
$callback($childElement);
if ($shouldDescendIntoChildrenFn === null || $shouldDescendIntoChildrenFn($childElement)) {
$childElement->walkDescendantNodesAndTokens($callback, $shouldDescendIntoChildrenFn);
}
}
}
}
}
}
/**
* Gets a generator containing all descendant Nodes.
* @param callable|null $shouldDescendIntoChildrenFn
* @return \Generator|Node[]
*/
public function getDescendantNodes(callable $shouldDescendIntoChildrenFn = null) {
foreach ($this->getChildNodes() as $child) {
yield $child;
if ($shouldDescendIntoChildrenFn === null || $shouldDescendIntoChildrenFn($child)) {
yield from $child->getDescendantNodes($shouldDescendIntoChildrenFn);
}
}
}
/**
* Gets generator containing all descendant Tokens.
* @param callable|null $shouldDescendIntoChildrenFn
* @return \Generator|Token[]
*/
public function getDescendantTokens(callable $shouldDescendIntoChildrenFn = null) {
foreach ($this->getChildNodesAndTokens() as $child) {
if ($child instanceof Node) {
if ($shouldDescendIntoChildrenFn == null || $shouldDescendIntoChildrenFn($child)) {
yield from $child->getDescendantTokens($shouldDescendIntoChildrenFn);
}
} elseif ($child instanceof Token) {
yield $child;
}
}
}
/**
* Gets generator containing all child Nodes and Tokens (direct descendants).
* Does not return null elements.
*
* @return \Generator|Token[]|Node[]
*/
public function getChildNodesAndTokens() : \Generator {
foreach ($this::CHILD_NAMES as $name) {
$val = $this->$name;
if (\is_array($val)) {
foreach ($val as $child) {
if ($child !== null) {
yield $name => $child;
}
}
continue;
}
if ($val !== null) {
yield $name => $val;
}
}
}
/**
* Gets generator containing all child Nodes (direct descendants)
* @return \Generator|Node[]
*/
public function getChildNodes() : \Generator {
foreach ($this::CHILD_NAMES as $name) {
$val = $this->$name;
if (\is_array($val)) {
foreach ($val as $child) {
if ($child instanceof Node) {
yield $child;
}
}
continue;
} elseif ($val instanceof Node) {
yield $val;
}
}
}
/**
* Gets generator containing all child Tokens (direct descendants)
*
* @return \Generator|Token[]
*/
public function getChildTokens() {
foreach ($this::CHILD_NAMES as $name) {
$val = $this->$name;
if (\is_array($val)) {
foreach ($val as $child) {
if ($child instanceof Token) {
yield $child;
}
}
continue;
} elseif ($val instanceof Token) {
yield $val;
}
}
}
/**
* Gets array of declared child names (cached).
*
* This is used as an optimization when iterating over nodes: For direct iteration
* PHP will create a properties hashtable on the object, thus doubling memory usage.
* We avoid this by iterating over just the names instead.
*
* @return string[]
*/
public function getChildNames() {
return $this::CHILD_NAMES;
}
/**
* Gets width of a Node (not including comment / whitespace trivia)
*
* @return int
*/
public function getWidth() : int {
$first = $this->getStart();
$last = $this->getEndPosition();
return $last - $first;
}
/**
* Gets width of a Node (including comment / whitespace trivia)
*
* @return int
*/
public function getFullWidth() : int {
$first = $this->getFullStart();
$last = $this->getEndPosition();
return $last - $first;
}
/**
* Gets string representing Node text (not including leading comment + whitespace trivia)
* @return string
*/
public function getText() : string {
$start = $this->getStart();
$end = $this->getEndPosition();
$fileContents = $this->getFileContents();
return \substr($fileContents, $start, $end - $start);
}
/**
* Gets full text of Node (including leading comment + whitespace trivia)
* @return string
*/
public function getFullText() : string {
$start = $this->getFullStart();
$end = $this->getEndPosition();
$fileContents = $this->getFileContents();
return \substr($fileContents, $start, $end - $start);
}
/**
* Gets string representing Node's leading comment and whitespace text.
* @return string
*/
public function getLeadingCommentAndWhitespaceText() : string {
// TODO re-tokenize comments and whitespace
$fileContents = $this->getFileContents();
foreach ($this->getDescendantTokens() as $token) {
return $token->getLeadingCommentsAndWhitespaceText($fileContents);
}
return '';
}
protected function getChildrenKvPairs() {
$result = array();
foreach ($this::CHILD_NAMES as $name) {
$result[$name] = $this->$name;
}
return $result;
}
public function jsonSerialize() {
$kindName = $this->getNodeKindName();
return ["$kindName" => $this->getChildrenKvPairs()];
}
/**
* Get the end index of a Node.
* @return int
* @throws \Exception
*/
public function getEndPosition() {
// TODO test invariant - start of next node is end of previous node
for ($i = \count($childKeys = $this::CHILD_NAMES) - 1; $i >= 0; $i--) {
$lastChildKey = $childKeys[$i];
$lastChild = $this->$lastChildKey;
if (\is_array($lastChild)) {
$lastChild = \end($lastChild);
}
if ($lastChild instanceof Token) {
return $lastChild->fullStart + $lastChild->length;
} elseif ($lastChild instanceof Node) {
return $lastChild->getEndPosition();
}
}
throw new \Exception("Unhandled node type");
}
public function getFileContents() : string {
// TODO consider renaming to getSourceText
return $this->getRoot()->fileContents;
}
public function getUri() : string {
return $this->getRoot()->uri;
}
public function getLastChild() {
$a = iterator_to_array($this->getChildNodesAndTokens());
return \end($a);
}
/**
* Searches descendants to find a Node at the given position.
*
* @param int $pos
* @return Node
*/
public function getDescendantNodeAtPosition(int $pos) {
foreach ($this->getChildNodes() as $child) {
if ($child->containsPosition($pos)) {
$node = $child->getDescendantNodeAtPosition($pos);
if (!is_null($node)) {
return $node;
}
}
}
return $this;
}
/**
* Returns true if the given Node or Token contains the given position.
* @param int $pos
* @return bool
*/
private function containsPosition(int $pos): bool {
return $this->getStart() <= $pos && $pos <= $this->getEndPosition();
}
/**
* Gets leading PHP Doc Comment text corresponding to the current Node.
* Returns last doc comment in leading comment / whitespace trivia,
* and returns null if there is no preceding doc comment.
*
* @return string|null
*/
public function getDocCommentText() {
$leadingTriviaText = $this->getLeadingCommentAndWhitespaceText();
$leadingTriviaTokens = PhpTokenizer::getTokensArrayFromContent(
$leadingTriviaText, ParseContext::SourceElements, $this->getFullStart(), false
);
for ($i = \count($leadingTriviaTokens) - 1; $i >= 0; $i--) {
$token = $leadingTriviaTokens[$i];
if ($token->kind === TokenKind::DocCommentToken) {
return $token->getText($this->getFileContents());
}
}
return null;
}
public function __toString() {
return $this->getText();
}
/**
* @return array|ResolvedName[][]
* @throws \Exception
*/
public function getImportTablesForCurrentScope() {
$namespaceDefinition = $this->getNamespaceDefinition();
// Use declarations can exist in either the global scope, or inside namespace declarations.
// http://php.net/manual/en/language.namespaces.importing.php#language.namespaces.importing.scope
//
// The only code allowed before a namespace declaration is a declare statement, and sub-namespaces are
// additionally unaffected by by import rules of higher-level namespaces. Therefore, we can make the assumption
// that we need not travel up the spine any further once we've found the current namespace.
// http://php.net/manual/en/language.namespaces.definition.php
if ($namespaceDefinition instanceof NamespaceDefinition) {
$topLevelNamespaceStatements = $namespaceDefinition->compoundStatementOrSemicolon instanceof Token
? $namespaceDefinition->parent->statementList // we need to start from the namespace definition.
: $namespaceDefinition->compoundStatementOrSemicolon->statements;
$namespaceFullStart = $namespaceDefinition->getFullStart();
} else {
$topLevelNamespaceStatements = $this->getRoot()->statementList;
$namespaceFullStart = 0;
}
$nodeFullStart = $this->getFullStart();
// TODO optimize performance
// Currently we rebuild the import tables on every call (and therefore every name resolution operation)
// It is likely that a consumer will attempt many consecutive name resolution requests within the same file.
// Therefore, we can consider optimizing on the basis of the "most recently used" import table set.
// The idea: Keep a single set of import tables cached based on a unique root node id, and invalidate
// cache whenever we attempt to resolve a qualified name with a different root node.
//
// In order to make this work, it will probably make sense to change the way we parse namespace definitions.
// https://github.com/Microsoft/tolerant-php-parser/issues/81
//
// Currently the namespace definition only includes a compound statement or semicolon token as one if it's children.
// Instead, we should move to a model where we parse future statements as a child rather than as a separate
// statement. This would enable us to retrieve all the information we would need to find the fully qualified
// name by simply traveling up the spine to find the first ancestor of type NamespaceDefinition.
$namespaceImportTable = $functionImportTable = $constImportTable = [];
$contents = $this->getFileContents();
foreach ($topLevelNamespaceStatements as $useDeclaration) {
if ($useDeclaration->getFullStart() <= $namespaceFullStart) {
continue;
}
if ($useDeclaration->getFullStart() > $nodeFullStart) {
break;
} elseif (!($useDeclaration instanceof NamespaceUseDeclaration)) {
continue;
}
// TODO fix getValues
foreach ((isset($useDeclaration->useClauses) ? $useDeclaration->useClauses->getValues() : []) as $useClause) {
$namespaceNamePartsPrefix = $useClause->namespaceName !== null ? $useClause->namespaceName->nameParts : [];
if ($useClause->groupClauses !== null && $useClause instanceof NamespaceUseClause) {
// use A\B\C\{D\E}; namespace import: ["E" => [A,B,C,D,E]]
// use A\B\C\{D\E as F}; namespace import: ["F" => [A,B,C,D,E]]
// use function A\B\C\{A, B} function import: ["A" => [A,B,C,A], "B" => [A,B,C]]
// use function A\B\C\{const A} const import: ["A" => [A,B,C,A]]
foreach ($useClause->groupClauses->children as $groupClause) {
if (!($groupClause instanceof NamespaceUseGroupClause)) {
continue;
}
$namespaceNameParts = \array_merge($namespaceNamePartsPrefix, $groupClause->namespaceName->nameParts);
$functionOrConst = $groupClause->functionOrConst ?? $useDeclaration->functionOrConst;
$alias = $groupClause->namespaceAliasingClause === null
? $groupClause->namespaceName->getLastNamePart()->getText($contents)
: $groupClause->namespaceAliasingClause->name->getText($contents);
$this->addToImportTable(
$alias, $functionOrConst, $namespaceNameParts, $contents,
$namespaceImportTable, $functionImportTable, $constImportTable
);
}
} else {
// use A\B\C; namespace import: ["C" => [A,B,C]]
// use A\B\C as D; namespace import: ["D" => [A,B,C]]
// use function A\B\C as D function import: ["D" => [A,B,C]]
// use A\B, C\D; namespace import: ["B" => [A,B], "D" => [C,D]]
$alias = $useClause->namespaceAliasingClause === null
? $useClause->namespaceName->getLastNamePart()->getText($contents)
: $useClause->namespaceAliasingClause->name->getText($contents);
$functionOrConst = $useDeclaration->functionOrConst;
$namespaceNameParts = $namespaceNamePartsPrefix;
$this->addToImportTable(
$alias, $functionOrConst, $namespaceNameParts, $contents,
$namespaceImportTable, $functionImportTable, $constImportTable
);
}
}
}
return [$namespaceImportTable, $functionImportTable, $constImportTable];
}
/**
* Gets corresponding NamespaceDefinition for Node. Returns null if in global namespace.
*
* @return NamespaceDefinition|null
*/
public function getNamespaceDefinition() {
$namespaceDefinition = $this instanceof NamespaceDefinition
? $this
: $this->getFirstAncestor(NamespaceDefinition::class, SourceFileNode::class);
if ($namespaceDefinition instanceof NamespaceDefinition && !($namespaceDefinition->parent instanceof SourceFileNode)) {
$namespaceDefinition = $namespaceDefinition->getFirstAncestor(SourceFileNode::class);
}
if ($namespaceDefinition === null) {
// TODO provide a way to throw errors without crashing consumer
throw new \Exception("Invalid tree - SourceFileNode must always exist at root of tree.");
}
$fullStart = $this->getFullStart();
$lastNamespaceDefinition = null;
if ($namespaceDefinition instanceof SourceFileNode) {
foreach ($namespaceDefinition->getChildNodes() as $childNode) {
if ($childNode instanceof NamespaceDefinition && $childNode->getFullStart() < $fullStart) {
$lastNamespaceDefinition = $childNode;
}
}
}
if ($lastNamespaceDefinition !== null && $lastNamespaceDefinition->compoundStatementOrSemicolon instanceof Token) {
$namespaceDefinition = $lastNamespaceDefinition;
} elseif ($namespaceDefinition instanceof SourceFileNode) {
$namespaceDefinition = null;
}
return $namespaceDefinition;
}
public function getPreviousSibling() {
// TODO make more efficient
$parent = $this->parent;
if ($parent === null) {
return null;
}
$prevSibling = null;
foreach ($parent::CHILD_NAMES as $name) {
$val = $parent->$name;
if (\is_array($val)) {
foreach ($val as $sibling) {
if ($sibling === $this) {
return $prevSibling;
} elseif ($sibling instanceof Node) {
$prevSibling = $sibling;
}
}
continue;
} elseif ($val instanceof Node) {
if ($val === $this) {
return $prevSibling;
}
$prevSibling = $val;
}
}
return null;
}
/**
* Add the alias and resolved name to the corresponding namespace, function, or const import table.
* If the alias already exists, it will get replaced by the most recent using.
*
* TODO - worth throwing an error here in stead?
*/
private function addToImportTable($alias, $functionOrConst, $namespaceNameParts, $contents, & $namespaceImportTable, & $functionImportTable, & $constImportTable):array
{
if ($alias !== null) {
if ($functionOrConst === null) {
// namespaces are case-insensitive
// $alias = \strtolower($alias);
$namespaceImportTable[$alias] = ResolvedName::buildName($namespaceNameParts, $contents);
return array($namespaceImportTable, $functionImportTable, $constImportTable);
} elseif ($functionOrConst->kind === TokenKind::FunctionKeyword) {
// functions are case-insensitive
// $alias = \strtolower($alias);
$functionImportTable[$alias] = ResolvedName::buildName($namespaceNameParts, $contents);
return array($namespaceImportTable, $functionImportTable, $constImportTable);
} elseif ($functionOrConst->kind === TokenKind::ConstKeyword) {
// constants are case-sensitive
$constImportTable[$alias] = ResolvedName::buildName($namespaceNameParts, $contents);
return array($namespaceImportTable, $functionImportTable, $constImportTable);
}
return array($namespaceImportTable, $functionImportTable, $constImportTable);
}
return array($namespaceImportTable, $functionImportTable, $constImportTable);
}
/**
* This is overridden in subclasses
* @return Diagnostic|null - Callers should use DiagnosticsProvider::getDiagnostics instead
* @internal
*/
public function getDiagnosticForNode() {
return null;
}
}
@@ -0,0 +1,32 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node\DelimitedList\UseVariableNameList;
use Microsoft\PhpParser\Token;
class AnonymousFunctionUseClause extends Node {
/** @var Token */
public $useKeyword;
/** @var Token */
public $openParen;
/** @var UseVariableNameList */
public $useVariableNameList;
/** @var Token */
public $closeParen;
const CHILD_NAMES = [
'useKeyword',
'openParen',
'useVariableNameList',
'closeParen'
];
}
@@ -0,0 +1,36 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
class ArrayElement extends Node {
/** @var Expression|null */
public $elementKey;
/** @var Token|null */
public $arrowToken;
/** @var Token|null */
public $byRef;
/** @var Token|null if this is set for PHP 7.4's array spread operator, then other preceding tokens aren't */
public $dotDotDot;
/** @var Expression */
public $elementValue;
const CHILD_NAMES = [
'elementKey',
'arrowToken',
'byRef',
'dotDotDot',
'elementValue'
];
}
@@ -0,0 +1,28 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
class CaseStatementNode extends Node {
/** @var Token */
public $caseKeyword;
/** @var Expression */
public $expression;
/** @var Token */
public $defaultLabelTerminator;
/** @var StatementNode[] */
public $statementList;
const CHILD_NAMES = [
'caseKeyword',
'expression',
'defaultLabelTerminator',
'statementList'
];
}
@@ -0,0 +1,43 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
class CatchClause extends Node {
/** @var Token */
public $catch;
/** @var Token */
public $openParen;
/** @var QualifiedName */
public $qualifiedName;
/**
* @var QualifiedName[]|Token[] Remaining tokens and qualified names in the catch clause
* (e.g. `catch (FirstException|SecondException $x)` would contain
* the representation of `|SecondException`)
*
* TODO: In the next backwards incompatible release, replace qualifiedName with qualifiedNameList?
*/
public $otherQualifiedNameList;
/** @var Token */
public $variableName;
/** @var Token */
public $closeParen;
/** @var StatementNode */
public $compoundStatement;
const CHILD_NAMES = [
'catch',
'openParen',
'qualifiedName',
'otherQualifiedNameList',
'variableName',
'closeParen',
'compoundStatement'
];
}
@@ -0,0 +1,23 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
class ClassBaseClause extends Node {
/** @var Token */
public $extendsKeyword;
/** @var QualifiedName */
public $baseClass;
const CHILD_NAMES = [
'extendsKeyword',
'baseClass'
];
}
@@ -0,0 +1,32 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
class ClassConstDeclaration extends Node {
/** @var Token[] */
public $modifiers;
/** @var Token */
public $constKeyword;
/** @var DelimitedList\ConstElementList */
public $constElements;
/** @var Token */
public $semicolon;
const CHILD_NAMES = [
'modifiers',
'constKeyword',
'constElements',
'semicolon'
];
}
@@ -0,0 +1,23 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
class ClassInterfaceClause extends Node {
/** @var Token */
public $implementsKeyword;
/** @var DelimitedList\QualifiedNameList|null */
public $interfaceNameList;
const CHILD_NAMES = [
'implementsKeyword',
'interfaceNameList'
];
}
@@ -0,0 +1,27 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
class ClassMembersNode extends Node {
/** @var Token */
public $openBrace;
/** @var Node[] */
public $classMemberDeclarations;
/** @var Token */
public $closeBrace;
const CHILD_NAMES = [
'openBrace',
'classMemberDeclarations',
'closeBrace'
];
}
@@ -0,0 +1,39 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\NamespacedNameInterface;
use Microsoft\PhpParser\NamespacedNameTrait;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
class ConstElement extends Node implements NamespacedNameInterface {
use NamespacedNameTrait;
/** @var Token */
public $name;
/** @var Token */
public $equalsToken;
/** @var Expression */
public $assignment;
const CHILD_NAMES = [
'name',
'equalsToken',
'assignment'
];
public function getNameParts() : array {
return [$this->name];
}
public function getName() {
return $this->name->getText($this->getFileContents());
}
}
@@ -0,0 +1,25 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
class DeclareDirective extends Node {
/** @var Token */
public $name;
/** @var Token */
public $equals;
/** @var Token */
public $literal;
const CHILD_NAMES = [
'name',
'equals',
'literal'
];
}
@@ -0,0 +1,25 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
class DefaultStatementNode extends Node {
/** @var Token */
public $defaultKeyword;
/** @var Token */
public $defaultLabelTerminator;
/** @var StatementNode[] */
public $statementList;
const CHILD_NAMES = [
'defaultKeyword',
'defaultLabelTerminator',
'statementList'
];
}
@@ -0,0 +1,51 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
use Microsoft\PhpParser\TokenKind;
abstract class DelimitedList extends Node {
/** @var Token[]|Node[] */
public $children;
const CHILD_NAMES = [
'children'
];
const DELIMITERS = [TokenKind::CommaToken, TokenKind::BarToken, TokenKind::SemicolonToken];
public function getElements() : \Generator {
foreach ($this->children as $child) {
if ($child instanceof Node) {
yield $child;
} elseif ($child instanceof Token && !\in_array($child->kind, self::DELIMITERS)) {
yield $child;
}
}
}
public function getValues() {
foreach ($this->children as $idx=>$value) {
if ($idx % 2 == 0) {
yield $value;
}
}
}
public function addElement($node) {
if ($node === null) {
return;
}
if ($this->children === null) {
$this->children = [$node];
return;
}
$this->children[] = $node;
}
}
@@ -0,0 +1,12 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Node\DelimitedList;
class ArgumentExpressionList extends DelimitedList {
}
@@ -0,0 +1,12 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Node\DelimitedList;
class ArrayElementList extends DelimitedList {
}
@@ -0,0 +1,12 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Node\DelimitedList;
class ConstElementList extends DelimitedList {
}
@@ -0,0 +1,12 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Node\DelimitedList;
class ExpressionList extends DelimitedList {
}
@@ -0,0 +1,12 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Node\DelimitedList;
class ListExpressionList extends DelimitedList {
}
@@ -0,0 +1,12 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Node\DelimitedList;
class NamespaceUseClauseList extends DelimitedList {
}
@@ -0,0 +1,12 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Node\DelimitedList;
class NamespaceUseGroupClauseList extends DelimitedList {
}
@@ -0,0 +1,12 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Node\DelimitedList;
class ParameterDeclarationList extends DelimitedList {
}
@@ -0,0 +1,12 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Node\DelimitedList;
class QualifiedNameList extends DelimitedList {
}
@@ -0,0 +1,12 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Node\DelimitedList;
class QualifiedNameParts extends DelimitedList {
}
@@ -0,0 +1,12 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Node\DelimitedList;
class StaticVariableNameList extends DelimitedList {
}
@@ -0,0 +1,12 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Node\DelimitedList;
class TraitSelectOrAliasClauseList extends DelimitedList {
}
@@ -0,0 +1,12 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Node\DelimitedList;
class UseVariableNameList extends DelimitedList {
}
@@ -0,0 +1,12 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Node\DelimitedList;
class VariableNameList extends DelimitedList {
}
@@ -0,0 +1,25 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
class ElseClauseNode extends Node {
/** @var Token */
public $elseKeyword;
/** @var Token */
public $colon;
/** @var StatementNode|StatementNode[] */
public $statements;
const CHILD_NAMES = [
'elseKeyword',
'colon',
'statements'
];
}
@@ -0,0 +1,34 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
class ElseIfClauseNode extends Node {
/** @var Token */
public $elseIfKeyword;
/** @var Token */
public $openParen;
/** @var Expression */
public $expression;
/** @var Token */
public $closeParen;
/** @var Token|null */
public $colon;
/** @var StatementNode|StatementNode[] */
public $statements;
const CHILD_NAMES = [
'elseIfKeyword',
'openParen',
'expression',
'closeParen',
'colon',
'statements'
];
}
@@ -0,0 +1,12 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node;
abstract class Expression extends Node {
}
@@ -0,0 +1,46 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\FunctionLike;
use Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Node\FunctionBody;
use Microsoft\PhpParser\Node\FunctionHeader;
use Microsoft\PhpParser\Node\FunctionReturnType;
use Microsoft\PhpParser\Node\FunctionUseClause;
use Microsoft\PhpParser\Token;
class AnonymousFunctionCreationExpression extends Expression implements FunctionLike {
/** @var Token|null */
public $staticModifier;
use FunctionHeader, FunctionUseClause, FunctionReturnType, FunctionBody;
const CHILD_NAMES = [
'staticModifier',
// FunctionHeader
'functionKeyword',
'byRefToken',
'name',
'openParen',
'parameters',
'closeParen',
// FunctionUseClause
'anonymousFunctionUseClause',
// FunctionReturnType
'colonToken',
'questionToken',
'returnType',
'otherReturnTypes',
// FunctionBody
'compoundStatementOrSemicolon'
];
}
@@ -0,0 +1,27 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Token;
class ArgumentExpression extends Expression {
/** @var Token|null */
public $byRefToken; // TODO removed in newer versions of PHP. Also only accept variable, not expression if byRef
/** @var Token|null */
public $dotDotDotToken;
/** @var Expression */
public $expression;
const CHILD_NAMES = [
'byRefToken',
'dotDotDotToken',
'expression'
];
}
@@ -0,0 +1,33 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Token;
class ArrayCreationExpression extends Expression {
/** @var Token|null */
public $arrayKeyword;
/** @var Token */
public $openParenOrBracket;
/** @var DelimitedList\ArrayElementList */
public $arrayElements;
/** @var Token */
public $closeParenOrBracket;
const CHILD_NAMES = [
'arrayKeyword',
'openParenOrBracket',
'arrayElements',
'closeParenOrBracket'
];
}
@@ -0,0 +1,49 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\FunctionLike;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Node\FunctionHeader;
use Microsoft\PhpParser\Node\FunctionReturnType;
use Microsoft\PhpParser\Token;
class ArrowFunctionCreationExpression extends Expression implements FunctionLike {
/** @var Token|null */
public $staticModifier;
use FunctionHeader, FunctionReturnType;
/** @var Token `=>` */
public $arrowToken;
/** @var Node|Token */
public $resultExpression;
const CHILD_NAMES = [
'staticModifier',
// FunctionHeader
'functionKeyword',
'byRefToken',
'name',
'openParen',
'parameters',
'closeParen',
// FunctionReturnType
'colonToken',
'questionToken',
'returnType',
'otherReturnTypes',
// body
'arrowToken',
'resultExpression',
];
}
@@ -0,0 +1,32 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Token;
class AssignmentExpression extends BinaryExpression {
/** @var Expression */
public $leftOperand;
/** @var Token */
public $operator;
/** @var Token */
public $byRef;
/** @var Expression */
public $rightOperand;
const CHILD_NAMES = [
'leftOperand',
'operator',
'byRef',
'rightOperand'
];
}
@@ -0,0 +1,28 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Token;
class BinaryExpression extends Expression {
/** @var Expression */
public $leftOperand;
/** @var Token */
public $operator;
/** @var Expression */
public $rightOperand;
const CHILD_NAMES = [
'leftOperand',
'operator',
'rightOperand'
];
}
@@ -0,0 +1,27 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Token;
class BracedExpression extends Expression {
/** @var Token */
public $openBrace;
/** @var Expression */
public $expression;
/** @var Token */
public $closeBrace;
const CHILD_NAMES = [
'openBrace',
'expression',
'closeBrace'
];
}

Some files were not shown because too many files have changed in this diff Show More