From f851335ca931656a63be8e9a7eaec5d6c8d8d522 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Tue, 10 Nov 2020 09:46:27 -0700 Subject: [PATCH] update libraries --- composer.lock | 674 +++--- vendor/composer/ClassLoader.php | 6 +- vendor/composer/InstalledVersions.php | 268 +++ vendor/composer/autoload_classmap.php | 1 + vendor/composer/autoload_real.php | 4 +- vendor/composer/autoload_static.php | 1 + vendor/composer/installed.json | 622 +++--- vendor/composer/installed.php | 83 + vendor/composer/platform_check.php | 27 + vendor/composer/semver/CHANGELOG.md | 24 + vendor/composer/semver/README.md | 2 +- .../semver/src/Constraint/Constraint.php | 6 +- .../semver/src/Constraint/EmptyConstraint.php | 2 +- .../semver/src/Constraint/MultiConstraint.php | 6 +- vendor/composer/semver/src/Semver.php | 4 +- vendor/composer/semver/src/VersionParser.php | 101 +- .../workflows/release-on-milestone-closed.yml | 18 +- .../laminas-zendframework-bridge/CHANGELOG.md | 23 + .../composer.json | 4 - .../src/Autoloader.php | 2 +- vendor/scssphp/scssphp/README.md | 11 +- vendor/scssphp/scssphp/bin/pscss | 48 +- vendor/scssphp/scssphp/composer.json | 25 +- vendor/scssphp/scssphp/scss.inc.php | 2 + vendor/scssphp/scssphp/src/Block.php | 2 +- vendor/scssphp/scssphp/src/Compiler.php | 1837 +++++++++++------ .../src/Exception/SassScriptException.php | 32 + vendor/scssphp/scssphp/src/Formatter.php | 43 +- .../scssphp/scssphp/src/Formatter/Compact.php | 4 + .../scssphp/src/Formatter/Compressed.php | 1 - .../scssphp/src/Formatter/Crunched.php | 5 +- .../scssphp/scssphp/src/Formatter/Debug.php | 5 +- .../scssphp/src/Formatter/Expanded.php | 1 - .../scssphp/scssphp/src/Formatter/Nested.php | 5 +- .../scssphp/src/Formatter/OutputBlock.php | 2 +- vendor/scssphp/scssphp/src/Node/Number.php | 654 ++++-- vendor/scssphp/scssphp/src/OutputStyle.php | 9 + vendor/scssphp/scssphp/src/Parser.php | 770 +++++-- .../scssphp/src/SourceMap/Base64VLQ.php | 2 - .../src/SourceMap/SourceMapGenerator.php | 27 +- vendor/scssphp/scssphp/src/Type.php | 3 + vendor/scssphp/scssphp/src/Util.php | 82 +- vendor/scssphp/scssphp/src/Version.php | 2 +- 43 files changed, 3782 insertions(+), 1668 deletions(-) create mode 100644 vendor/composer/InstalledVersions.php create mode 100644 vendor/composer/installed.php create mode 100644 vendor/composer/platform_check.php create mode 100644 vendor/scssphp/scssphp/src/Exception/SassScriptException.php create mode 100644 vendor/scssphp/scssphp/src/OutputStyle.php diff --git a/composer.lock b/composer.lock index 08a052a0..8a67a8b8 100644 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "composer/semver", - "version": "1.5.1", + "version": "1.7.1", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de" + "reference": "38276325bd896f90dfcfe30029aa5db40df387a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de", - "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de", + "url": "https://api.github.com/repos/composer/semver/zipball/38276325bd896f90dfcfe30029aa5db40df387a7", + "reference": "38276325bd896f90dfcfe30029aa5db40df387a7", "shasum": "" }, "require": { @@ -65,7 +65,26 @@ "validation", "versioning" ], - "time": "2020-01-13T12:06:48+00:00" + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/1.7.1" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2020-09-27T13:13:07+00:00" }, { "name": "laminas/laminas-xml", @@ -115,20 +134,28 @@ "security", "xml" ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-xml/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-xml/issues", + "rss": "https://github.com/laminas/laminas-xml/releases.atom", + "source": "https://github.com/laminas/laminas-xml" + }, "time": "2019-12-31T18:05:42+00:00" }, { "name": "laminas/laminas-zendframework-bridge", - "version": "1.1.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/laminas/laminas-zendframework-bridge.git", - "reference": "4939c81f63a8a4968c108c440275c94955753b19" + "reference": "6ede70583e101030bcace4dcddd648f760ddf642" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/4939c81f63a8a4968c108c440275c94955753b19", - "reference": "4939c81f63a8a4968c108c440275c94955753b19", + "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/6ede70583e101030bcace4dcddd648f760ddf642", + "reference": "6ede70583e101030bcace4dcddd648f760ddf642", "shasum": "" }, "require": { @@ -140,10 +167,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev", - "dev-develop": "1.1.x-dev" - }, "laminas": { "module": "Laminas\\ZendFrameworkBridge" } @@ -167,13 +190,19 @@ "laminas", "zf" ], + "support": { + "forum": "https://discourse.laminas.dev/", + "issues": "https://github.com/laminas/laminas-zendframework-bridge/issues", + "rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom", + "source": "https://github.com/laminas/laminas-zendframework-bridge" + }, "funding": [ { "url": "https://funding.communitybridge.org/projects/laminas-project", "type": "community_bridge" } ], - "time": "2020-08-18T16:34:51+00:00" + "time": "2020-09-14T14:23:00+00:00" }, { "name": "p3k/picofeed", @@ -229,20 +258,24 @@ ], "description": "Modern library to handle RSS/Atom feeds", "homepage": "https://github.com/aaronpk/picoFeed", + "support": { + "issues": "https://github.com/aaronpk/picofeed/issues", + "source": "https://github.com/aaronpk/picofeed/tree/v0.1.40" + }, "time": "2020-04-25T17:48:36+00:00" }, { "name": "scssphp/scssphp", - "version": "1.2", + "version": "v1.4.0", "source": { "type": "git", "url": "https://github.com/scssphp/scssphp.git", - "reference": "ce970268a912dabbfaa0eff65dbc5e4a2a6cb757" + "reference": "f7c9088320e218ca42e4ef0074259a1ba24ec93a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scssphp/scssphp/zipball/ce970268a912dabbfaa0eff65dbc5e4a2a6cb757", - "reference": "ce970268a912dabbfaa0eff65dbc5e4a2a6cb757", + "url": "https://api.github.com/repos/scssphp/scssphp/zipball/f7c9088320e218ca42e4ef0074259a1ba24ec93a", + "reference": "f7c9088320e218ca42e4ef0074259a1ba24ec93a", "shasum": "" }, "require": { @@ -251,9 +284,10 @@ "php": ">=5.6.0" }, "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3", - "sass/sass-spec": "2020.08.10", + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3 || ^9.4", + "sass/sass-spec": "2020.10.29", "squizlabs/php_codesniffer": "~3.5", + "symfony/phpunit-bridge": "^5.1", "twbs/bootstrap": "~4.3", "zurb/foundation": "~6.5" }, @@ -291,7 +325,11 @@ "scss", "stylesheet" ], - "time": "2020-08-26T20:47:29+00:00" + "support": { + "issues": "https://github.com/scssphp/scssphp/issues", + "source": "https://github.com/scssphp/scssphp/tree/v1.4.0" + }, + "time": "2020-11-07T20:53:41+00:00" } ], "packages-dev": [ @@ -352,6 +390,10 @@ "gherkin", "parser" ], + "support": { + "issues": "https://github.com/Behat/Gherkin/issues", + "source": "https://github.com/Behat/Gherkin/tree/master" + }, "time": "2020-03-17T14:03:26+00:00" }, { @@ -444,20 +486,24 @@ "functional testing", "unit testing" ], + "support": { + "issues": "https://github.com/Codeception/Codeception/issues", + "source": "https://github.com/Codeception/Codeception/tree/2.5.6" + }, "time": "2019-04-24T11:28:19+00:00" }, { "name": "codeception/phpunit-wrapper", - "version": "7.8.0", + "version": "7.8.1", "source": { "type": "git", "url": "https://github.com/Codeception/phpunit-wrapper.git", - "reference": "bc847bd4f8f6d09012543e2a856f19fe4ecdcf3a" + "reference": "bc6f37d770ec00c4c7c78a1cac2b8ac0f9c9eec5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/bc847bd4f8f6d09012543e2a856f19fe4ecdcf3a", - "reference": "bc847bd4f8f6d09012543e2a856f19fe4ecdcf3a", + "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/bc6f37d770ec00c4c7c78a1cac2b8ac0f9c9eec5", + "reference": "bc6f37d770ec00c4c7c78a1cac2b8ac0f9c9eec5", "shasum": "" }, "require": { @@ -473,7 +519,7 @@ "type": "library", "autoload": { "psr-4": { - "Codeception\\PHPUnit\\": "src\\" + "Codeception\\PHPUnit\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -487,7 +533,11 @@ } ], "description": "PHPUnit classes used by Codeception", - "time": "2019-12-23T06:55:58+00:00" + "support": { + "issues": "https://github.com/Codeception/phpunit-wrapper/issues", + "source": "https://github.com/Codeception/phpunit-wrapper/tree/7.8.1" + }, + "time": "2020-10-11T18:23:48+00:00" }, { "name": "codeception/stub", @@ -517,6 +567,10 @@ "MIT" ], "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", + "support": { + "issues": "https://github.com/Codeception/Stub/issues", + "source": "https://github.com/Codeception/Stub/tree/master" + }, "time": "2019-03-02T15:35:10+00:00" }, { @@ -573,6 +627,10 @@ "constructor", "instantiate" ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.3.x" + }, "funding": [ { "url": "https://www.doctrine-project.org/sponsorship.html", @@ -647,6 +705,11 @@ "selenium", "webdriver" ], + "support": { + "forum": "https://www.facebook.com/groups/phpwebdriver/", + "issues": "https://github.com/facebook/php-webdriver/issues", + "source": "https://github.com/facebook/php-webdriver" + }, "abandoned": "php-webdriver/webdriver", "time": "2019-06-13T08:02:18+00:00" }, @@ -698,6 +761,11 @@ "faker", "fixtures" ], + "support": { + "issues": "https://github.com/fzaninotto/Faker/issues", + "source": "https://github.com/fzaninotto/Faker/tree/v1.9.1" + }, + "abandoned": true, "time": "2019-12-12T13:22:17+00:00" }, { @@ -765,27 +833,31 @@ "rest", "web service" ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/6.5" + }, "time": "2020-06-16T21:01:06+00:00" }, { "name": "guzzlehttp/promises", - "version": "v1.3.1", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + "reference": "60d379c243457e073cff02bc323a2a86cb355631" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "url": "https://api.github.com/repos/guzzle/promises/zipball/60d379c243457e073cff02bc323a2a86cb355631", + "reference": "60d379c243457e073cff02bc323a2a86cb355631", "shasum": "" }, "require": { - "php": ">=5.5.0" + "php": ">=5.5" }, "require-dev": { - "phpunit/phpunit": "^4.0" + "symfony/phpunit-bridge": "^4.4 || ^5.1" }, "type": "library", "extra": { @@ -816,20 +888,24 @@ "keywords": [ "promise" ], - "time": "2016-12-20T10:07:11+00:00" + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.4.0" + }, + "time": "2020-09-30T07:37:28+00:00" }, { "name": "guzzlehttp/psr7", - "version": "1.6.1", + "version": "1.7.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "239400de7a173fe9901b9ac7c06497751f00727a" + "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", - "reference": "239400de7a173fe9901b9ac7c06497751f00727a", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/53330f47520498c0ae1f61f7e2c90f55690c06a3", + "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3", "shasum": "" }, "require": { @@ -842,15 +918,15 @@ }, "require-dev": { "ext-zlib": "*", - "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" }, "suggest": { - "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6-dev" + "dev-master": "1.7-dev" } }, "autoload": { @@ -887,7 +963,11 @@ "uri", "url" ], - "time": "2019-07-01T23:21:34+00:00" + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.7.0" + }, + "time": "2020-09-30T07:37:11+00:00" }, { "name": "myclabs/deep-copy", @@ -935,6 +1015,10 @@ "object", "object graph" ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.x" + }, "funding": [ { "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", @@ -943,51 +1027,6 @@ ], "time": "2020-06-29T13:22:24+00:00" }, - { - "name": "paragonie/random_compat", - "version": "v9.99.99", - "source": { - "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", - "shasum": "" - }, - "require": { - "php": "^7" - }, - "require-dev": { - "phpunit/phpunit": "4.*|5.*", - "vimeo/psalm": "^1" - }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Paragon Initiative Enterprises", - "email": "security@paragonie.com", - "homepage": "https://paragonie.com" - } - ], - "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", - "keywords": [ - "csprng", - "polyfill", - "pseudorandom", - "random" - ], - "time": "2018-07-02T15:55:56+00:00" - }, { "name": "phar-io/manifest", "version": "1.0.3", @@ -1041,6 +1080,10 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/master" + }, "time": "2018-07-08T19:23:20+00:00" }, { @@ -1088,6 +1131,10 @@ } ], "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/master" + }, "time": "2018-07-08T19:19:57+00:00" }, { @@ -1137,6 +1184,10 @@ "reflection", "static analysis" ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/master" + }, "time": "2020-04-27T09:25:28+00:00" }, { @@ -1189,6 +1240,10 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/release/4.x" + }, "time": "2019-12-28T18:55:12+00:00" }, { @@ -1236,6 +1291,10 @@ } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/0.7.2" + }, "time": "2019-08-22T18:11:29+00:00" }, { @@ -1299,6 +1358,10 @@ "spy", "stub" ], + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/v1.10.3" + }, "time": "2020-03-05T15:02:03+00:00" }, { @@ -1362,6 +1425,10 @@ "testing", "xunit" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/master" + }, "time": "2018-10-31T16:06:48+00:00" }, { @@ -1412,6 +1479,10 @@ "filesystem", "iterator" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/2.0.2" + }, "time": "2018-09-13T20:33:42+00:00" }, { @@ -1453,6 +1524,10 @@ "keywords": [ "template" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" + }, "time": "2015-06-21T13:50:34+00:00" }, { @@ -1502,6 +1577,10 @@ "keywords": [ "timer" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/master" + }, "time": "2019-06-07T04:22:29+00:00" }, { @@ -1551,6 +1630,10 @@ "keywords": [ "tokenizer" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", + "source": "https://github.com/sebastianbergmann/php-token-stream/tree/3.1.1" + }, "abandoned": true, "time": "2019-09-17T06:23:10+00:00" }, @@ -1636,6 +1719,10 @@ "testing", "xunit" ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/7.5.20" + }, "time": "2020-01-08T08:45:45+00:00" }, { @@ -1685,6 +1772,10 @@ "container-interop", "psr" ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/master" + }, "time": "2017-02-14T16:28:37+00:00" }, { @@ -1735,6 +1826,9 @@ "request", "response" ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, "time": "2016-08-06T14:39:51+00:00" }, { @@ -1775,6 +1869,10 @@ } ], "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, "time": "2019-03-08T08:55:37+00:00" }, { @@ -1820,6 +1918,10 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/master" + }, "time": "2017-03-04T06:30:41+00:00" }, { @@ -1884,6 +1986,10 @@ "compare", "equality" ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/master" + }, "time": "2018-07-12T15:12:46+00:00" }, { @@ -1940,6 +2046,10 @@ "unidiff", "unified diff" ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/master" + }, "time": "2019-02-04T06:01:07+00:00" }, { @@ -1993,6 +2103,10 @@ "environment", "hhvm" ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/4.2.3" + }, "time": "2019-11-20T08:46:58+00:00" }, { @@ -2060,6 +2174,10 @@ "export", "exporter" ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/master" + }, "time": "2019-09-14T09:02:43+00:00" }, { @@ -2111,6 +2229,10 @@ "keywords": [ "global state" ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/2.0.0" + }, "time": "2017-04-27T15:39:26+00:00" }, { @@ -2158,6 +2280,10 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/master" + }, "time": "2017-08-03T12:35:26+00:00" }, { @@ -2203,6 +2329,10 @@ ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/master" + }, "time": "2017-03-29T09:07:27+00:00" }, { @@ -2256,6 +2386,10 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/master" + }, "time": "2017-03-03T06:23:57+00:00" }, { @@ -2298,6 +2432,10 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/master" + }, "time": "2018-10-04T04:07:39+00:00" }, { @@ -2341,20 +2479,24 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/master" + }, "time": "2016-10-03T07:35:21+00:00" }, { "name": "symfony/browser-kit", - "version": "v4.4.11", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "f53310646af9901292488b2ff36e26ea10f545f5" + "reference": "99b640fd5d06877e3242ba0393b40a7877dfe534" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/f53310646af9901292488b2ff36e26ea10f545f5", - "reference": "f53310646af9901292488b2ff36e26ea10f545f5", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/99b640fd5d06877e3242ba0393b40a7877dfe534", + "reference": "99b640fd5d06877e3242ba0393b40a7877dfe534", "shasum": "" }, "require": { @@ -2371,11 +2513,6 @@ "symfony/process": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\BrowserKit\\": "" @@ -2400,6 +2537,9 @@ ], "description": "Symfony BrowserKit Component", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/browser-kit/tree/v4.4.16" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -2414,20 +2554,20 @@ "type": "tidelift" } ], - "time": "2020-05-22T17:28:00+00:00" + "time": "2020-10-24T11:50:19+00:00" }, { "name": "symfony/console", - "version": "v4.4.11", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "55d07021da933dd0d633ffdab6f45d5b230c7e02" + "reference": "20f73dd143a5815d475e0838ff867bce1eebd9d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/55d07021da933dd0d633ffdab6f45d5b230c7e02", - "reference": "55d07021da933dd0d633ffdab6f45d5b230c7e02", + "url": "https://api.github.com/repos/symfony/console/zipball/20f73dd143a5815d475e0838ff867bce1eebd9d5", + "reference": "20f73dd143a5815d475e0838ff867bce1eebd9d5", "shasum": "" }, "require": { @@ -2462,11 +2602,6 @@ "symfony/process": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Console\\": "" @@ -2491,6 +2626,9 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/console/tree/v4.4.16" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -2505,31 +2643,26 @@ "type": "tidelift" } ], - "time": "2020-07-06T13:18:39+00:00" + "time": "2020-10-24T11:50:19+00:00" }, { "name": "symfony/css-selector", - "version": "v4.4.11", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "bf17dc9f6ce144e41f786c32435feea4d8e11dcc" + "reference": "719506cffda9dba80c75d94ac50f1a2561520e4f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/bf17dc9f6ce144e41f786c32435feea4d8e11dcc", - "reference": "bf17dc9f6ce144e41f786c32435feea4d8e11dcc", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/719506cffda9dba80c75d94ac50f1a2561520e4f", + "reference": "719506cffda9dba80c75d94ac50f1a2561520e4f", "shasum": "" }, "require": { "php": ">=7.1.3" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\CssSelector\\": "" @@ -2558,6 +2691,9 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v4.4.16" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -2572,20 +2708,20 @@ "type": "tidelift" } ], - "time": "2020-07-05T09:39:30+00:00" + "time": "2020-10-24T11:50:19+00:00" }, { "name": "symfony/dom-crawler", - "version": "v4.4.11", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "72b3a65ddd5052cf6d65eac6669748ed311f39bf" + "reference": "30ad9ac96a01913195bf0328d48e29d54fa53e6e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/72b3a65ddd5052cf6d65eac6669748ed311f39bf", - "reference": "72b3a65ddd5052cf6d65eac6669748ed311f39bf", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/30ad9ac96a01913195bf0328d48e29d54fa53e6e", + "reference": "30ad9ac96a01913195bf0328d48e29d54fa53e6e", "shasum": "" }, "require": { @@ -2604,11 +2740,6 @@ "symfony/css-selector": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\DomCrawler\\": "" @@ -2633,6 +2764,9 @@ ], "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dom-crawler/tree/v4.4.16" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -2647,20 +2781,20 @@ "type": "tidelift" } ], - "time": "2020-07-23T08:31:43+00:00" + "time": "2020-10-24T11:50:19+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.4.11", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "6140fc7047dafc5abbe84ba16a34a86c0b0229b8" + "reference": "4204f13d2d0b7ad09454f221bb2195fccdf1fe98" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/6140fc7047dafc5abbe84ba16a34a86c0b0229b8", - "reference": "6140fc7047dafc5abbe84ba16a34a86c0b0229b8", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/4204f13d2d0b7ad09454f221bb2195fccdf1fe98", + "reference": "4204f13d2d0b7ad09454f221bb2195fccdf1fe98", "shasum": "" }, "require": { @@ -2678,6 +2812,7 @@ "psr/log": "~1.0", "symfony/config": "^3.4|^4.0|^5.0", "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/error-handler": "~3.4|~4.4", "symfony/expression-language": "^3.4|^4.0|^5.0", "symfony/http-foundation": "^3.4|^4.0|^5.0", "symfony/service-contracts": "^1.1|^2", @@ -2688,11 +2823,6 @@ "symfony/http-kernel": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\EventDispatcher\\": "" @@ -2717,6 +2847,9 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.16" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -2731,7 +2864,7 @@ "type": "tidelift" } ], - "time": "2020-06-18T17:59:13+00:00" + "time": "2020-10-24T11:50:19+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -2793,6 +2926,9 @@ "interoperability", "standards" ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.9" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -2811,27 +2947,22 @@ }, { "name": "symfony/finder", - "version": "v4.4.11", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "2727aa35fddfada1dd37599948528e9b152eb742" + "reference": "26f63b8d4e92f2eecd90f6791a563ebb001abe31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/2727aa35fddfada1dd37599948528e9b152eb742", - "reference": "2727aa35fddfada1dd37599948528e9b152eb742", + "url": "https://api.github.com/repos/symfony/finder/zipball/26f63b8d4e92f2eecd90f6791a563ebb001abe31", + "reference": "26f63b8d4e92f2eecd90f6791a563ebb001abe31", "shasum": "" }, "require": { "php": ">=7.1.3" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Finder\\": "" @@ -2856,6 +2987,9 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v4.4.16" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -2870,24 +3004,24 @@ "type": "tidelift" } ], - "time": "2020-07-05T09:39:30+00:00" + "time": "2020-10-24T11:50:19+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.18.1", + "version": "v1.20.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "1c302646f6efc070cd46856e600e5e0684d6b454" + "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454", - "reference": "1c302646f6efc070cd46856e600e5e0684d6b454", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f4ba089a5b6366e453971d3aad5fe8e897b37f41", + "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "suggest": { "ext-ctype": "For best performance" @@ -2895,7 +3029,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.18-dev" + "dev-main": "1.20-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2932,6 +3066,9 @@ "polyfill", "portable" ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.20.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -2946,26 +3083,25 @@ "type": "tidelift" } ], - "time": "2020-07-14T12:35:20+00:00" + "time": "2020-10-23T14:02:19+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.18.1", + "version": "v1.20.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "5dcab1bc7146cf8c1beaa4502a3d9be344334251" + "reference": "3b75acd829741c768bc8b1f84eb33265e7cc5117" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/5dcab1bc7146cf8c1beaa4502a3d9be344334251", - "reference": "5dcab1bc7146cf8c1beaa4502a3d9be344334251", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/3b75acd829741c768bc8b1f84eb33265e7cc5117", + "reference": "3b75acd829741c768bc8b1f84eb33265e7cc5117", "shasum": "" }, "require": { - "php": ">=5.3.3", + "php": ">=7.1", "symfony/polyfill-intl-normalizer": "^1.10", - "symfony/polyfill-php70": "^1.10", "symfony/polyfill-php72": "^1.10" }, "suggest": { @@ -2974,7 +3110,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.18-dev" + "dev-main": "1.20-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3017,6 +3153,9 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.20.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3031,24 +3170,24 @@ "type": "tidelift" } ], - "time": "2020-08-04T06:02:08+00:00" + "time": "2020-10-23T14:02:19+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.18.1", + "version": "v1.20.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e" + "reference": "727d1096295d807c309fb01a851577302394c897" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e", - "reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/727d1096295d807c309fb01a851577302394c897", + "reference": "727d1096295d807c309fb01a851577302394c897", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "suggest": { "ext-intl": "For best performance" @@ -3056,7 +3195,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.18-dev" + "dev-main": "1.20-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3098,6 +3237,9 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.20.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3112,24 +3254,24 @@ "type": "tidelift" } ], - "time": "2020-07-14T12:35:20+00:00" + "time": "2020-10-23T14:02:19+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.18.1", + "version": "v1.20.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a" + "reference": "39d483bdf39be819deabf04ec872eb0b2410b531" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/a6977d63bf9a0ad4c65cd352709e230876f9904a", - "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/39d483bdf39be819deabf04ec872eb0b2410b531", + "reference": "39d483bdf39be819deabf04ec872eb0b2410b531", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "suggest": { "ext-mbstring": "For best performance" @@ -3137,7 +3279,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.18-dev" + "dev-main": "1.20-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3175,6 +3317,9 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.20.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3189,106 +3334,29 @@ "type": "tidelift" } ], - "time": "2020-07-14T12:35:20+00:00" - }, - { - "name": "symfony/polyfill-php70", - "version": "v1.18.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "0dd93f2c578bdc9c72697eaa5f1dd25644e618d3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/0dd93f2c578bdc9c72697eaa5f1dd25644e618d3", - "reference": "0dd93f2c578bdc9c72697eaa5f1dd25644e618d3", - "shasum": "" - }, - "require": { - "paragonie/random_compat": "~1.0|~2.0|~9.99", - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.18-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php70\\": "" - }, - "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.0+ 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-07-14T12:35:20+00:00" + "time": "2020-10-23T14:02:19+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.18.1", + "version": "v1.20.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "639447d008615574653fb3bc60d1986d7172eaae" + "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/639447d008615574653fb3bc60d1986d7172eaae", - "reference": "639447d008615574653fb3bc60d1986d7172eaae", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cede45fcdfabdd6043b3592e83678e42ec69e930", + "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.18-dev" + "dev-main": "1.20-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3325,6 +3393,9 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.20.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3339,29 +3410,29 @@ "type": "tidelift" } ], - "time": "2020-07-14T12:35:20+00:00" + "time": "2020-10-23T14:02:19+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.18.1", + "version": "v1.20.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca" + "reference": "8ff431c517be11c78c48a39a66d37431e26a6bed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fffa1a52a023e782cdcc221d781fe1ec8f87fcca", - "reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/8ff431c517be11c78c48a39a66d37431e26a6bed", + "reference": "8ff431c517be11c78c48a39a66d37431e26a6bed", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.18-dev" + "dev-main": "1.20-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3401,6 +3472,9 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.20.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3415,29 +3489,29 @@ "type": "tidelift" } ], - "time": "2020-07-14T12:35:20+00:00" + "time": "2020-10-23T14:02:19+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.18.1", + "version": "v1.20.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981" + "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/d87d5766cbf48d72388a9f6b85f280c8ad51f981", - "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/e70aa8b064c5b72d3df2abd5ab1e90464ad009de", + "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de", "shasum": "" }, "require": { - "php": ">=7.0.8" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.18-dev" + "dev-main": "1.20-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3481,6 +3555,9 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.20.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3495,31 +3572,26 @@ "type": "tidelift" } ], - "time": "2020-07-14T12:35:20+00:00" + "time": "2020-10-23T14:02:19+00:00" }, { "name": "symfony/process", - "version": "v4.4.11", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "65e70bab62f3da7089a8d4591fb23fbacacb3479" + "reference": "2f4b049fb80ca5e9874615a2a85dc2a502090f05" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/65e70bab62f3da7089a8d4591fb23fbacacb3479", - "reference": "65e70bab62f3da7089a8d4591fb23fbacacb3479", + "url": "https://api.github.com/repos/symfony/process/zipball/2f4b049fb80ca5e9874615a2a85dc2a502090f05", + "reference": "2f4b049fb80ca5e9874615a2a85dc2a502090f05", "shasum": "" }, "require": { "php": ">=7.1.3" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Process\\": "" @@ -3544,6 +3616,9 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v4.4.16" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3558,7 +3633,7 @@ "type": "tidelift" } ], - "time": "2020-07-23T08:31:43+00:00" + "time": "2020-10-24T11:50:19+00:00" }, { "name": "symfony/service-contracts", @@ -3620,6 +3695,9 @@ "interoperability", "standards" ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v1.1.9" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3638,16 +3716,16 @@ }, { "name": "symfony/yaml", - "version": "v4.4.11", + "version": "v4.4.16", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "c2d2cc66e892322cfcc03f8f12f8340dbd7a3f8a" + "reference": "543cb4dbd45ed803f08a9a65f27fb149b5dd20c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/c2d2cc66e892322cfcc03f8f12f8340dbd7a3f8a", - "reference": "c2d2cc66e892322cfcc03f8f12f8340dbd7a3f8a", + "url": "https://api.github.com/repos/symfony/yaml/zipball/543cb4dbd45ed803f08a9a65f27fb149b5dd20c2", + "reference": "543cb4dbd45ed803f08a9a65f27fb149b5dd20c2", "shasum": "" }, "require": { @@ -3664,11 +3742,6 @@ "symfony/console": "For validating YAML files using the lint command" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Yaml\\": "" @@ -3693,6 +3766,9 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v4.4.16" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3707,7 +3783,7 @@ "type": "tidelift" } ], - "time": "2020-05-20T08:37:50+00:00" + "time": "2020-10-24T11:50:19+00:00" }, { "name": "theseer/tokenizer", @@ -3747,6 +3823,10 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/master" + }, "time": "2019-06-13T22:48:21+00:00" }, { @@ -3796,6 +3876,10 @@ "check", "validate" ], + "support": { + "issues": "https://github.com/webmozart/assert/issues", + "source": "https://github.com/webmozart/assert/tree/master" + }, "time": "2020-07-08T17:02:28+00:00" } ], @@ -3814,5 +3898,5 @@ "platform-overrides": { "php": "7.1.3" }, - "plugin-api-version": "1.1.0" + "plugin-api-version": "2.0.0" } diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php index fce8549f..1a58957d 100644 --- a/vendor/composer/ClassLoader.php +++ b/vendor/composer/ClassLoader.php @@ -37,8 +37,8 @@ namespace Composer\Autoload; * * @author Fabien Potencier * @author Jordi Boggiano - * @see http://www.php-fig.org/psr/psr-0/ - * @see http://www.php-fig.org/psr/psr-4/ + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ */ class ClassLoader { @@ -60,7 +60,7 @@ class ClassLoader public function getPrefixes() { if (!empty($this->prefixesPsr0)) { - return call_user_func_array('array_merge', $this->prefixesPsr0); + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); } return array(); diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php new file mode 100644 index 00000000..42a61bd8 --- /dev/null +++ b/vendor/composer/InstalledVersions.php @@ -0,0 +1,268 @@ + + array ( + 'pretty_version' => '1.10.x-dev', + 'version' => '1.10.9999999.9999999-dev', + 'aliases' => + array ( + ), + 'reference' => 'a8bd391b7886f2330ce1f9906e46522125c69e47', + 'name' => 'getgrav/grav-plugin-admin', + ), + 'versions' => + array ( + 'composer/semver' => + array ( + 'pretty_version' => '1.7.1', + 'version' => '1.7.1.0', + 'aliases' => + array ( + ), + 'reference' => '38276325bd896f90dfcfe30029aa5db40df387a7', + ), + 'getgrav/grav-plugin-admin' => + array ( + 'pretty_version' => '1.10.x-dev', + 'version' => '1.10.9999999.9999999-dev', + 'aliases' => + array ( + ), + 'reference' => 'a8bd391b7886f2330ce1f9906e46522125c69e47', + ), + 'laminas/laminas-xml' => + array ( + 'pretty_version' => '1.2.0', + 'version' => '1.2.0.0', + 'aliases' => + array ( + ), + 'reference' => '879cc66d1bba6a37705e98074f52a6960c220020', + ), + 'laminas/laminas-zendframework-bridge' => + array ( + 'pretty_version' => '1.1.1', + 'version' => '1.1.1.0', + 'aliases' => + array ( + ), + 'reference' => '6ede70583e101030bcace4dcddd648f760ddf642', + ), + 'miniflux/picofeed' => + array ( + 'replaced' => + array ( + 0 => '0.1.35', + ), + ), + 'p3k/picofeed' => + array ( + 'pretty_version' => 'v0.1.40', + 'version' => '0.1.40.0', + 'aliases' => + array ( + ), + 'reference' => '356fd66d48779193b10ac28532cb4a4e11bb801c', + ), + 'scssphp/scssphp' => + array ( + 'pretty_version' => 'v1.4.0', + 'version' => '1.4.0.0', + 'aliases' => + array ( + ), + 'reference' => 'f7c9088320e218ca42e4ef0074259a1ba24ec93a', + ), + 'zendframework/zendxml' => + array ( + 'replaced' => + array ( + 0 => '1.2.0', + ), + ), + ), +); + + + + + + + +public static function getInstalledPackages() +{ +return array_keys(self::$installed['versions']); +} + + + + + + + + + +public static function isInstalled($packageName) +{ +return isset(self::$installed['versions'][$packageName]); +} + + + + + + + + + + + + + + +public static function satisfies(VersionParser $parser, $packageName, $constraint) +{ +$constraint = $parser->parseConstraints($constraint); +$provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + +return $provided->matches($constraint); +} + + + + + + + + + + +public static function getVersionRanges($packageName) +{ +if (!isset(self::$installed['versions'][$packageName])) { +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + +$ranges = array(); +if (isset(self::$installed['versions'][$packageName]['pretty_version'])) { +$ranges[] = self::$installed['versions'][$packageName]['pretty_version']; +} +if (array_key_exists('aliases', self::$installed['versions'][$packageName])) { +$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['aliases']); +} +if (array_key_exists('replaced', self::$installed['versions'][$packageName])) { +$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['replaced']); +} +if (array_key_exists('provided', self::$installed['versions'][$packageName])) { +$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['provided']); +} + +return implode(' || ', $ranges); +} + + + + + +public static function getVersion($packageName) +{ +if (!isset(self::$installed['versions'][$packageName])) { +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + +if (!isset(self::$installed['versions'][$packageName]['version'])) { +return null; +} + +return self::$installed['versions'][$packageName]['version']; +} + + + + + +public static function getPrettyVersion($packageName) +{ +if (!isset(self::$installed['versions'][$packageName])) { +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + +if (!isset(self::$installed['versions'][$packageName]['pretty_version'])) { +return null; +} + +return self::$installed['versions'][$packageName]['pretty_version']; +} + + + + + +public static function getReference($packageName) +{ +if (!isset(self::$installed['versions'][$packageName])) { +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + +if (!isset(self::$installed['versions'][$packageName]['reference'])) { +return null; +} + +return self::$installed['versions'][$packageName]['reference']; +} + + + + + +public static function getRootPackage() +{ +return self::$installed['root']; +} + + + + + + + +public static function getRawData() +{ +return self::$installed; +} + + + + + + + + + + + + + + + + + + + +public static function reload($data) +{ +self::$installed = $data; +} +} diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 11ac7076..cefb86c0 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -6,5 +6,6 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 'Grav\\Plugin\\AdminPlugin' => $baseDir . '/admin.php', ); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 13a2247a..d105c854 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -22,13 +22,15 @@ class ComposerAutoloaderInitb286bbda7f18d999afbef65014afb574 return self::$loader; } + require __DIR__ . '/platform_check.php'; + spl_autoload_register(array('ComposerAutoloaderInitb286bbda7f18d999afbef65014afb574', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); spl_autoload_unregister(array('ComposerAutoloaderInitb286bbda7f18d999afbef65014afb574', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); if ($useStaticLoader) { - require_once __DIR__ . '/autoload_static.php'; + require __DIR__ . '/autoload_static.php'; call_user_func(\Composer\Autoload\ComposerStaticInitb286bbda7f18d999afbef65014afb574::getInitializer($loader)); } else { diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 27ccd277..11d1885b 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -64,6 +64,7 @@ class ComposerStaticInitb286bbda7f18d999afbef65014afb574 ); public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'Grav\\Plugin\\AdminPlugin' => __DIR__ . '/../..' . '/admin.php', ); diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 0b0b0bb4..fc379681 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -1,299 +1,333 @@ -[ - { - "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" +{ + "packages": [ + { + "name": "composer/semver", + "version": "1.7.1", + "version_normalized": "1.7.1.0", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "38276325bd896f90dfcfe30029aa5db40df387a7" }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/38276325bd896f90dfcfe30029aa5db40df387a7", + "reference": "38276325bd896f90dfcfe30029aa5db40df387a7", + "shasum": "" }, - { - "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": "laminas/laminas-xml", - "version": "1.2.0", - "version_normalized": "1.2.0.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-xml.git", - "reference": "879cc66d1bba6a37705e98074f52a6960c220020" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-xml/zipball/879cc66d1bba6a37705e98074f52a6960c220020", - "reference": "879cc66d1bba6a37705e98074f52a6960c220020", - "shasum": "" - }, - "require": { - "laminas/laminas-zendframework-bridge": "^1.0", - "php": "^5.6 || ^7.0" - }, - "replace": { - "zendframework/zendxml": "self.version" - }, - "require-dev": { - "laminas/laminas-coding-standard": "~1.0.0", - "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.4" - }, - "time": "2019-12-31T18:05:42+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev", - "dev-develop": "1.3.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Laminas\\Xml\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Utility library for XML usage, best practices, and security in PHP", - "homepage": "https://laminas.dev", - "keywords": [ - "laminas", - "security", - "xml" - ] - }, - { - "name": "laminas/laminas-zendframework-bridge", - "version": "1.1.0", - "version_normalized": "1.1.0.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-zendframework-bridge.git", - "reference": "4939c81f63a8a4968c108c440275c94955753b19" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/4939c81f63a8a4968c108c440275c94955753b19", - "reference": "4939c81f63a8a4968c108c440275c94955753b19", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3", - "squizlabs/php_codesniffer": "^3.5" - }, - "time": "2020-08-18T16:34:51+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev", - "dev-develop": "1.1.x-dev" + "require": { + "php": "^5.3.2 || ^7.0" }, - "laminas": { - "module": "Laminas\\ZendFrameworkBridge" - } - }, - "installation-source": "dist", - "autoload": { - "files": [ - "src/autoload.php" + "require-dev": { + "phpunit/phpunit": "^4.5 || ^5.0.5" + }, + "time": "2020-09-27T13:13:07+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" ], - "psr-4": { - "Laminas\\ZendFrameworkBridge\\": "src//" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Alias legacy ZF class names to Laminas Project equivalents.", - "keywords": [ - "ZendFramework", - "autoloading", - "laminas", - "zf" - ], - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ] - }, - { - "name": "p3k/picofeed", - "version": "v0.1.40", - "version_normalized": "0.1.40.0", - "source": { - "type": "git", - "url": "https://github.com/aaronpk/picofeed.git", - "reference": "356fd66d48779193b10ac28532cb4a4e11bb801c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/aaronpk/picofeed/zipball/356fd66d48779193b10ac28532cb4a4e11bb801c", - "reference": "356fd66d48779193b10ac28532cb4a4e11bb801c", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-iconv": "*", - "ext-libxml": "*", - "ext-simplexml": "*", - "ext-xml": "*", - "laminas/laminas-xml": "^1.2", - "php": ">=5.3.0" - }, - "replace": { - "miniflux/picofeed": "0.1.35" - }, - "require-dev": { - "phpdocumentor/reflection-docblock": "2.0.4", - "phpunit/phpunit": "4.8.26", - "symfony/yaml": "2.8.7" - }, - "suggest": { - "ext-curl": "PicoFeed will use cURL if present" - }, - "time": "2020-04-25T17:48:36+00:00", - "bin": [ - "picofeed" - ], - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-0": { - "PicoFeed": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Frédéric Guillot" - } - ], - "description": "Modern library to handle RSS/Atom feeds", - "homepage": "https://github.com/aaronpk/picoFeed" - }, - { - "name": "scssphp/scssphp", - "version": "1.2", - "version_normalized": "1.2.0.0", - "source": { - "type": "git", - "url": "https://github.com/scssphp/scssphp.git", - "reference": "ce970268a912dabbfaa0eff65dbc5e4a2a6cb757" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/scssphp/scssphp/zipball/ce970268a912dabbfaa0eff65dbc5e4a2a6cb757", - "reference": "ce970268a912dabbfaa0eff65dbc5e4a2a6cb757", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "ext-json": "*", - "php": ">=5.6.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3", - "sass/sass-spec": "2020.08.10", - "squizlabs/php_codesniffer": "~3.5", - "twbs/bootstrap": "~4.3", - "zurb/foundation": "~6.5" - }, - "time": "2020-08-26T20:47:29+00:00", - "bin": [ - "bin/pscss" - ], - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "ScssPhp\\ScssPhp\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Anthon Pang", - "email": "apang@softwaredevelopment.ca", - "homepage": "https://github.com/robocoder" + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/1.7.1" }, - { - "name": "Cédric Morin", - "email": "cedric@yterium.com", - "homepage": "https://github.com/Cerdic" - } - ], - "description": "scssphp is a compiler for SCSS written in PHP.", - "homepage": "http://scssphp.github.io/scssphp/", - "keywords": [ - "css", - "less", - "sass", - "scss", - "stylesheet" - ] - } -] + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "install-path": "./semver" + }, + { + "name": "laminas/laminas-xml", + "version": "1.2.0", + "version_normalized": "1.2.0.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-xml.git", + "reference": "879cc66d1bba6a37705e98074f52a6960c220020" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-xml/zipball/879cc66d1bba6a37705e98074f52a6960c220020", + "reference": "879cc66d1bba6a37705e98074f52a6960c220020", + "shasum": "" + }, + "require": { + "laminas/laminas-zendframework-bridge": "^1.0", + "php": "^5.6 || ^7.0" + }, + "replace": { + "zendframework/zendxml": "self.version" + }, + "require-dev": { + "laminas/laminas-coding-standard": "~1.0.0", + "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.4" + }, + "time": "2019-12-31T18:05:42+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev", + "dev-develop": "1.3.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Laminas\\Xml\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Utility library for XML usage, best practices, and security in PHP", + "homepage": "https://laminas.dev", + "keywords": [ + "laminas", + "security", + "xml" + ], + "install-path": "../laminas/laminas-xml" + }, + { + "name": "laminas/laminas-zendframework-bridge", + "version": "1.1.1", + "version_normalized": "1.1.1.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-zendframework-bridge.git", + "reference": "6ede70583e101030bcace4dcddd648f760ddf642" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/6ede70583e101030bcace4dcddd648f760ddf642", + "reference": "6ede70583e101030bcace4dcddd648f760ddf642", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3", + "squizlabs/php_codesniffer": "^3.5" + }, + "time": "2020-09-14T14:23:00+00:00", + "type": "library", + "extra": { + "laminas": { + "module": "Laminas\\ZendFrameworkBridge" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/autoload.php" + ], + "psr-4": { + "Laminas\\ZendFrameworkBridge\\": "src//" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Alias legacy ZF class names to Laminas Project equivalents.", + "keywords": [ + "ZendFramework", + "autoloading", + "laminas", + "zf" + ], + "support": { + "forum": "https://discourse.laminas.dev/", + "issues": "https://github.com/laminas/laminas-zendframework-bridge/issues", + "rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom", + "source": "https://github.com/laminas/laminas-zendframework-bridge" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "install-path": "../laminas/laminas-zendframework-bridge" + }, + { + "name": "p3k/picofeed", + "version": "v0.1.40", + "version_normalized": "0.1.40.0", + "source": { + "type": "git", + "url": "https://github.com/aaronpk/picofeed.git", + "reference": "356fd66d48779193b10ac28532cb4a4e11bb801c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aaronpk/picofeed/zipball/356fd66d48779193b10ac28532cb4a4e11bb801c", + "reference": "356fd66d48779193b10ac28532cb4a4e11bb801c", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "laminas/laminas-xml": "^1.2", + "php": ">=5.3.0" + }, + "replace": { + "miniflux/picofeed": "0.1.35" + }, + "require-dev": { + "phpdocumentor/reflection-docblock": "2.0.4", + "phpunit/phpunit": "4.8.26", + "symfony/yaml": "2.8.7" + }, + "suggest": { + "ext-curl": "PicoFeed will use cURL if present" + }, + "time": "2020-04-25T17:48:36+00:00", + "bin": [ + "picofeed" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "PicoFeed": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frédéric Guillot" + } + ], + "description": "Modern library to handle RSS/Atom feeds", + "homepage": "https://github.com/aaronpk/picoFeed", + "install-path": "../p3k/picofeed" + }, + { + "name": "scssphp/scssphp", + "version": "v1.4.0", + "version_normalized": "1.4.0.0", + "source": { + "type": "git", + "url": "https://github.com/scssphp/scssphp.git", + "reference": "f7c9088320e218ca42e4ef0074259a1ba24ec93a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/scssphp/scssphp/zipball/f7c9088320e218ca42e4ef0074259a1ba24ec93a", + "reference": "f7c9088320e218ca42e4ef0074259a1ba24ec93a", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "php": ">=5.6.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3 || ^9.4", + "sass/sass-spec": "2020.10.29", + "squizlabs/php_codesniffer": "~3.5", + "symfony/phpunit-bridge": "^5.1", + "twbs/bootstrap": "~4.3", + "zurb/foundation": "~6.5" + }, + "time": "2020-11-07T20:53:41+00:00", + "bin": [ + "bin/pscss" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "ScssPhp\\ScssPhp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anthon Pang", + "email": "apang@softwaredevelopment.ca", + "homepage": "https://github.com/robocoder" + }, + { + "name": "Cédric Morin", + "email": "cedric@yterium.com", + "homepage": "https://github.com/Cerdic" + } + ], + "description": "scssphp is a compiler for SCSS written in PHP.", + "homepage": "http://scssphp.github.io/scssphp/", + "keywords": [ + "css", + "less", + "sass", + "scss", + "stylesheet" + ], + "support": { + "issues": "https://github.com/scssphp/scssphp/issues", + "source": "https://github.com/scssphp/scssphp/tree/v1.4.0" + }, + "install-path": "../scssphp/scssphp" + } + ], + "dev": false +} diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php new file mode 100644 index 00000000..6cc8e5bb --- /dev/null +++ b/vendor/composer/installed.php @@ -0,0 +1,83 @@ + + array ( + 'pretty_version' => '1.10.x-dev', + 'version' => '1.10.9999999.9999999-dev', + 'aliases' => + array ( + ), + 'reference' => 'a8bd391b7886f2330ce1f9906e46522125c69e47', + 'name' => 'getgrav/grav-plugin-admin', + ), + 'versions' => + array ( + 'composer/semver' => + array ( + 'pretty_version' => '1.7.1', + 'version' => '1.7.1.0', + 'aliases' => + array ( + ), + 'reference' => '38276325bd896f90dfcfe30029aa5db40df387a7', + ), + 'getgrav/grav-plugin-admin' => + array ( + 'pretty_version' => '1.10.x-dev', + 'version' => '1.10.9999999.9999999-dev', + 'aliases' => + array ( + ), + 'reference' => 'a8bd391b7886f2330ce1f9906e46522125c69e47', + ), + 'laminas/laminas-xml' => + array ( + 'pretty_version' => '1.2.0', + 'version' => '1.2.0.0', + 'aliases' => + array ( + ), + 'reference' => '879cc66d1bba6a37705e98074f52a6960c220020', + ), + 'laminas/laminas-zendframework-bridge' => + array ( + 'pretty_version' => '1.1.1', + 'version' => '1.1.1.0', + 'aliases' => + array ( + ), + 'reference' => '6ede70583e101030bcace4dcddd648f760ddf642', + ), + 'miniflux/picofeed' => + array ( + 'replaced' => + array ( + 0 => '0.1.35', + ), + ), + 'p3k/picofeed' => + array ( + 'pretty_version' => 'v0.1.40', + 'version' => '0.1.40.0', + 'aliases' => + array ( + ), + 'reference' => '356fd66d48779193b10ac28532cb4a4e11bb801c', + ), + 'scssphp/scssphp' => + array ( + 'pretty_version' => 'v1.4.0', + 'version' => '1.4.0.0', + 'aliases' => + array ( + ), + 'reference' => 'f7c9088320e218ca42e4ef0074259a1ba24ec93a', + ), + 'zendframework/zendxml' => + array ( + 'replaced' => + array ( + 0 => '1.2.0', + ), + ), + ), +); diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php new file mode 100644 index 00000000..90bca239 --- /dev/null +++ b/vendor/composer/platform_check.php @@ -0,0 +1,27 @@ += 70103)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.1.3". You are running ' . PHP_VERSION . '.'; +} + +$missingExtensions = array(); +extension_loaded('ctype') || $missingExtensions[] = 'ctype'; +extension_loaded('dom') || $missingExtensions[] = 'dom'; +extension_loaded('iconv') || $missingExtensions[] = 'iconv'; +extension_loaded('json') || $missingExtensions[] = 'json'; +extension_loaded('libxml') || $missingExtensions[] = 'libxml'; +extension_loaded('simplexml') || $missingExtensions[] = 'simplexml'; +extension_loaded('xml') || $missingExtensions[] = 'xml'; + +if ($missingExtensions) { + $issues[] = 'Your Composer dependencies require the following PHP extensions to be installed: ' . implode(', ', $missingExtensions); +} + +if ($issues) { + echo 'Composer detected issues in your platform:' . "\n\n" . implode("\n", $issues); + exit(104); +} diff --git a/vendor/composer/semver/CHANGELOG.md b/vendor/composer/semver/CHANGELOG.md index ee0c2ef3..c2dbd3fb 100644 --- a/vendor/composer/semver/CHANGELOG.md +++ b/vendor/composer/semver/CHANGELOG.md @@ -3,6 +3,26 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +### [1.7.1] 2020-09-27 + + * Fixed: accidental validation of broken constraints combining ^/~ and wildcards, and -dev suffix allowing weird cases + * Fixed: normalization of beta0 and such which was dropping the 0 + +### [1.7.0] 2020-09-09 + + * Added: support for `x || @dev`, not very useful but seen in the wild and failed to validate with 1.5.2/1.6.0 + * Added: support for `foobar-dev` being equal to `dev-foobar`, dev-foobar is the official way to write it but we need to support the other for BC and convenience + +### [1.6.0] 2020-09-08 + + * Added: support for constraints like `^2.x-dev` and `~2.x-dev`, not very useful but seen in the wild and failed to validate with 1.5.2 + * Fixed: invalid aliases will no longer throw, unless explicitly validated by Composer in the root package + +### [1.5.2] 2020-09-08 + + * Fixed: handling of some invalid -dev versions which were seen as valid + * Fixed: some doctypes + ### [1.5.1] 2020-01-13 * Fixed: Parsing of aliased version was not validating the alias to be a valid version @@ -66,6 +86,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Namespace: `Composer\Test\Package\LinkConstraint` -> `Composer\Test\Semver\Constraint` * Changed: code style using php-cs-fixer. +[1.7.1]: https://github.com/composer/semver/compare/1.7.0...1.7.1 +[1.7.0]: https://github.com/composer/semver/compare/1.6.0...1.7.0 +[1.6.0]: https://github.com/composer/semver/compare/1.5.2...1.6.0 +[1.5.2]: https://github.com/composer/semver/compare/1.5.1...1.5.2 [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 diff --git a/vendor/composer/semver/README.md b/vendor/composer/semver/README.md index 143daa0d..409b9dcb 100644 --- a/vendor/composer/semver/README.md +++ b/vendor/composer/semver/README.md @@ -46,7 +46,7 @@ The `Composer\Semver\Comparator` class provides the following methods for compar * equalTo($v1, $v2) * notEqualTo($v1, $v2) -Each function takes two version strings as arguments. For example: +Each function takes two version strings as arguments and returns a boolean. For example: ```php use Composer\Semver\Comparator; diff --git a/vendor/composer/semver/src/Constraint/Constraint.php b/vendor/composer/semver/src/Constraint/Constraint.php index c8c90f02..0f28d643 100644 --- a/vendor/composer/semver/src/Constraint/Constraint.php +++ b/vendor/composer/semver/src/Constraint/Constraint.php @@ -54,7 +54,7 @@ class Constraint implements ConstraintInterface self::OP_NE => '!=', ); - /** @var string */ + /** @var int */ protected $operator; /** @var string */ @@ -134,7 +134,7 @@ class Constraint implements ConstraintInterface * @param string $a * @param string $b * @param string $operator - * @param bool $compareBranches + * @param bool $compareBranches * * @throws \InvalidArgumentException if invalid operator is given. * @@ -167,7 +167,7 @@ class Constraint implements ConstraintInterface /** * @param Constraint $provider - * @param bool $compareBranches + * @param bool $compareBranches * * @return bool */ diff --git a/vendor/composer/semver/src/Constraint/EmptyConstraint.php b/vendor/composer/semver/src/Constraint/EmptyConstraint.php index cb89cd26..a082b809 100644 --- a/vendor/composer/semver/src/Constraint/EmptyConstraint.php +++ b/vendor/composer/semver/src/Constraint/EmptyConstraint.php @@ -30,7 +30,7 @@ class EmptyConstraint implements ConstraintInterface } /** - * @param $prettyString + * @param string $prettyString */ public function setPrettyString($prettyString) { diff --git a/vendor/composer/semver/src/Constraint/MultiConstraint.php b/vendor/composer/semver/src/Constraint/MultiConstraint.php index f8a60e4e..91128530 100644 --- a/vendor/composer/semver/src/Constraint/MultiConstraint.php +++ b/vendor/composer/semver/src/Constraint/MultiConstraint.php @@ -19,7 +19,7 @@ class MultiConstraint implements ConstraintInterface /** @var ConstraintInterface[] */ protected $constraints; - /** @var string */ + /** @var string|null */ protected $prettyString; /** @var bool */ @@ -27,7 +27,7 @@ class MultiConstraint implements ConstraintInterface /** * @param ConstraintInterface[] $constraints A set of constraints - * @param bool $conjunctive Whether the constraints should be treated as conjunctive or disjunctive + * @param bool $conjunctive Whether the constraints should be treated as conjunctive or disjunctive */ public function __construct(array $constraints, $conjunctive = true) { @@ -86,7 +86,7 @@ class MultiConstraint implements ConstraintInterface } /** - * @param string $prettyString + * @param string|null $prettyString */ public function setPrettyString($prettyString) { diff --git a/vendor/composer/semver/src/Semver.php b/vendor/composer/semver/src/Semver.php index 3ab2b68a..4f312d73 100644 --- a/vendor/composer/semver/src/Semver.php +++ b/vendor/composer/semver/src/Semver.php @@ -45,7 +45,7 @@ class Semver /** * Return all versions that satisfy given constraints. * - * @param array $versions + * @param array $versions * @param string $constraints * * @return array @@ -85,7 +85,7 @@ class Semver /** * @param array $versions - * @param int $direction + * @param int $direction * * @return array */ diff --git a/vendor/composer/semver/src/VersionParser.php b/vendor/composer/semver/src/VersionParser.php index 9a7d0dbb..5af0fa30 100644 --- a/vendor/composer/semver/src/VersionParser.php +++ b/vendor/composer/semver/src/VersionParser.php @@ -38,8 +38,8 @@ class VersionParser */ 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'); + /** @var string */ + private static $stabilitiesRegex = 'stable|RC|beta|alpha|dev'; /** * Returns the stability of a version. @@ -102,18 +102,21 @@ class VersionParser public function normalize($version, $fullVersion = null) { $version = trim($version); + $origVersion = $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]; } + // strip off stability flag + if (preg_match('{@(?:' . self::$stabilitiesRegex . ')$}i', $version, $match)) { + $version = substr($version, 0, strlen($version) - strlen($match[0])); + } + // match master-like branches if (preg_match('{^(?:dev-)?(?:master|trunk|default)$}i', $version)) { return '9999999-dev'; @@ -148,7 +151,7 @@ class VersionParser if ('stable' === $matches[$index]) { return $version; } - $version .= '-' . $this->expandStability($matches[$index]) . (!empty($matches[$index + 1]) ? ltrim($matches[$index + 1], '.-') : ''); + $version .= '-' . $this->expandStability($matches[$index]) . (isset($matches[$index + 1]) && '' !== $matches[$index + 1] ? ltrim($matches[$index + 1], '.-') : ''); } if (!empty($matches[$index + 2])) { @@ -161,19 +164,25 @@ class VersionParser // match dev branches if (preg_match('{(.*?)[.-]?dev$}i', $version, $match)) { try { - return $this->normalizeBranch($match[1]); + $normalized = $this->normalizeBranch($match[1]); + // a branch ending with -dev is only valid if it is numeric + // if it gets prefixed with dev- it means the branch name should + // have had a dev- prefix already when passed to normalize + if (strpos($normalized, 'dev-') === false) { + return $normalized; + } } catch (\Exception $e) { } } $extraMessage = ''; - if (preg_match('{ +as +' . preg_quote($version) . '$}', $fullVersion)) { + if (preg_match('{ +as +' . preg_quote($version) . '(?:@(?:'.self::$stabilitiesRegex.'))?$}', $fullVersion)) { $extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version'; - } elseif (preg_match('{^' . preg_quote($version) . ' +as +}', $fullVersion)) { + } elseif (preg_match('{^' . preg_quote($version) . '(?:@(?:'.self::$stabilitiesRegex.'))? +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); + throw new \UnexpectedValueException('Invalid version string "' . $origVersion . '"' . $extraMessage); } /** @@ -230,14 +239,6 @@ class VersionParser { $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(); @@ -300,18 +301,29 @@ class VersionParser */ private function parseConstraint($constraint) { - if (preg_match('{^([^,\s]+?)@(' . implode('|', self::$stabilities) . ')$}i', $constraint, $match)) { + // strip off aliasing + if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $constraint, $match)) { $constraint = $match[1]; + } + + // strip @stability flags, and keep it for later use + if (preg_match('{^([^,\s]*?)@(' . self::$stabilitiesRegex . ')$}i', $constraint, $match)) { + $constraint = '' !== $match[1] ? $match[1] : '*'; if ($match[2] !== 'stable') { $stabilityModifier = $match[2]; } } + // get rid of #refs as those are used by composer only + if (preg_match('{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i', $constraint, $match)) { + $constraint = $match[1]; + } + if (preg_match('{^v?[xX*](\.[xX*])*$}i', $constraint)) { return array(new EmptyConstraint()); } - $versionRegex = 'v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.(\d++))?' . self::$modifierRegex . '(?:\+[^\s]+)?'; + $versionRegex = 'v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.(\d++))?(?:' . self::$modifierRegex . '|\.([xX*][.-]?dev))(?:\+[^\s]+)?'; // Tilde Range // @@ -337,9 +349,14 @@ class VersionParser $position = 1; } + // when matching 2.x-dev or 3.0.x-dev we have to shift the second or third number, despite no second/third number matching above + if (!empty($matches[8])) { + $position++; + } + // Calculate the stability suffix $stabilitySuffix = ''; - if (empty($matches[5]) && empty($matches[7])) { + if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) { $stabilitySuffix .= '-dev'; } @@ -375,7 +392,7 @@ class VersionParser // Calculate the stability suffix $stabilitySuffix = ''; - if (empty($matches[5]) && empty($matches[7])) { + if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) { $stabilitySuffix .= '-dev'; } @@ -428,7 +445,7 @@ class VersionParser if (preg_match('{^(?P' . $versionRegex . ') +- +(?P' . $versionRegex . ')($)}i', $constraint, $matches)) { // Calculate the stability suffix $lowStabilitySuffix = ''; - if (empty($matches[6]) && empty($matches[8])) { + if (empty($matches[6]) && empty($matches[8]) && empty($matches[9])) { $lowStabilitySuffix = '-dev'; } @@ -439,12 +456,16 @@ class VersionParser return ($x === 0 || $x === '0') ? false : empty($x); }; - if ((!$empty($matches[11]) && !$empty($matches[12])) || !empty($matches[14]) || !empty($matches[16])) { + if ((!$empty($matches[12]) && !$empty($matches[13])) || !empty($matches[15]) || !empty($matches[17]) || !empty($matches[18])) { $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'; + $highMatch = array('', $matches[11], $matches[12], $matches[13], $matches[14]); + + // validate to version + $this->normalize($matches['to']); + + $highVersion = $this->manipulateVersionString($highMatch, $empty($matches[12]) ? 1 : 2, 1) . '-dev'; $upperBound = new Constraint('<', $highVersion); } @@ -457,11 +478,23 @@ class VersionParser // Basic Comparators if (preg_match('{^(<>|!=|>=?|<=?|==?)?\s*(.*)}', $constraint, $matches)) { try { - $version = $this->normalize($matches[2]); + try { + $version = $this->normalize($matches[2]); + } catch (\UnexpectedValueException $e) { + // recover from an invalid constraint like foobar-dev which should be dev-foobar + // except if the constraint uses a known operator, in which case it must be a parse error + if (substr($matches[2], -4) === '-dev' && preg_match('{^[0-9a-zA-Z-./]+$}', $matches[2])) { + $version = $this->normalize('dev-'.substr($matches[2], 0, -4)); + } else { + throw $e; + } + } - if (!empty($stabilityModifier) && self::parseStability($version) === 'stable') { + $op = $matches[1] ?: '='; + + if ($op !== '==' && $op !== '=' && !empty($stabilityModifier) && self::parseStability($version) === 'stable') { $version .= '-' . $stabilityModifier; - } elseif ('<' === $matches[1] || '>=' === $matches[1]) { + } elseif ('<' === $op || '>=' === $op) { if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) { if (strpos($matches[2], 'dev-') !== 0) { $version .= '-dev'; @@ -487,12 +520,12 @@ class VersionParser * * 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 + * @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 + * @return string|null The new version */ private function manipulateVersionString($matches, $position, $increment = 0, $pad = '0') { diff --git a/vendor/laminas/laminas-zendframework-bridge/.github/workflows/release-on-milestone-closed.yml b/vendor/laminas/laminas-zendframework-bridge/.github/workflows/release-on-milestone-closed.yml index 9d8f7ebd..6066f8b2 100644 --- a/vendor/laminas/laminas-zendframework-bridge/.github/workflows/release-on-milestone-closed.yml +++ b/vendor/laminas/laminas-zendframework-bridge/.github/workflows/release-on-milestone-closed.yml @@ -1,4 +1,8 @@ -# https://help.github.com/en/categories/automating-your-workflow-with-github-actions +# Alternate workflow example. +# This one is identical to the one in release-on-milestone.yml, with one change: +# the Release step uses the ORGANIZATION_ADMIN_TOKEN instead, to allow it to +# trigger a release workflow event. This is useful if you have other actions +# that intercept that event. name: "Automatic Releases" @@ -21,7 +25,7 @@ jobs: with: command-name: "laminas:automatic-releases:release" env: - "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }} + "GITHUB_TOKEN": ${{ secrets.ORGANIZATION_ADMIN_TOKEN }} "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} @@ -55,3 +59,13 @@ jobs: "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} + + - name: "Create new milestones" + uses: "laminas/automatic-releases@v1" + with: + command-name: "laminas:automatic-releases:create-milestones" + env: + "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }} + "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} + "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} + "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} diff --git a/vendor/laminas/laminas-zendframework-bridge/CHANGELOG.md b/vendor/laminas/laminas-zendframework-bridge/CHANGELOG.md index 87f4b0fa..fee5e07a 100644 --- a/vendor/laminas/laminas-zendframework-bridge/CHANGELOG.md +++ b/vendor/laminas/laminas-zendframework-bridge/CHANGELOG.md @@ -2,6 +2,29 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. +## 1.1.1 - 2020-09-14 + +### Fixed + +- [#71](https://github.com/laminas/laminas-zendframework-bridge/pull/71) fixes detection of the vendor directory when the `COMPOSER_VENDOR_DIR` env variable is missing or empty. Previously, this could lead to scenarios where a non-existent path was used for finding the bridge autoloader. + + +----- + +### Release Notes for [1.1.1](https://github.com/laminas/laminas-zendframework-bridge/milestone/5) + + + +### 1.1.1 + +- Total issues resolved: **0** +- Total pull requests resolved: **1** +- Total contributors: **1** + +#### Bug + + - [71: Verify `COMPOSER_VENDOR_DIR` in conditional](https://github.com/laminas/laminas-zendframework-bridge/pull/71) thanks to @aaronbushnell + ## 1.1.0 - 2020-08-18 ### Added diff --git a/vendor/laminas/laminas-zendframework-bridge/composer.json b/vendor/laminas/laminas-zendframework-bridge/composer.json index 74e87cb9..34af15a4 100644 --- a/vendor/laminas/laminas-zendframework-bridge/composer.json +++ b/vendor/laminas/laminas-zendframework-bridge/composer.json @@ -42,10 +42,6 @@ } }, "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev", - "dev-develop": "1.1.x-dev" - }, "laminas": { "module": "Laminas\\ZendFrameworkBridge" } diff --git a/vendor/laminas/laminas-zendframework-bridge/src/Autoloader.php b/vendor/laminas/laminas-zendframework-bridge/src/Autoloader.php index dd7dae37..6048766a 100644 --- a/vendor/laminas/laminas-zendframework-bridge/src/Autoloader.php +++ b/vendor/laminas/laminas-zendframework-bridge/src/Autoloader.php @@ -66,7 +66,7 @@ class Autoloader */ private static function getClassLoader() { - if (file_exists(getenv('COMPOSER_VENDOR_DIR') . '/autoload.php')) { + if (getenv('COMPOSER_VENDOR_DIR') && file_exists(getenv('COMPOSER_VENDOR_DIR') . '/autoload.php')) { return include getenv('COMPOSER_VENDOR_DIR') . '/autoload.php'; } diff --git a/vendor/scssphp/scssphp/README.md b/vendor/scssphp/scssphp/README.md index cd5fce1d..54557344 100644 --- a/vendor/scssphp/scssphp/README.md +++ b/vendor/scssphp/scssphp/README.md @@ -1,7 +1,7 @@ # scssphp ### -[![Build](https://travis-ci.org/scssphp/scssphp.svg?branch=master)](https://travis-ci.org/scssphp/scssphp) +![Build](https://github.com/scssphp/scssphp/workflows/CI/badge.svg) [![License](https://poser.pugx.org/scssphp/scssphp/license)](https://packagist.org/packages/scssphp/scssphp) `scssphp` is a compiler for SCSS written in PHP. @@ -23,7 +23,7 @@ There are several tests in the `tests/` directory: * `FailingTest.php` contains tests reported in Github issues that demonstrate compatibility bugs. * `InputTest.php` compiles every `.scss` file in the `tests/inputs` directory then compares to the respective `.css` file in the `tests/outputs` directory. -* `ScssTest.php` extracts (ruby) `scss` tests from the `tests/scss_test.rb` file. +* `SassSpecTest.php` extracts tests from the `sass/sass-spec` repository. When changing any of the tests in `tests/inputs`, the tests will most likely fail because the output has changed. Once you verify that the output is correct @@ -31,11 +31,12 @@ you can run the following command to rebuild all the tests: BUILD=1 vendor/bin/phpunit tests -This will compile all the tests, and save results into `tests/outputs`. +This will compile all the tests, and save results into `tests/outputs`. It also +updates the list of excluded specs from sass-spec. -To enable the `scss` compatibility tests: +To enable the full `sass-spec` compatibility tests: - TEST_SCSS_COMPAT=1 vendor/bin/phpunit tests + TEST_SASS_SPEC=1 vendor/bin/phpunit tests ## Coding Standard diff --git a/vendor/scssphp/scssphp/bin/pscss b/vendor/scssphp/scssphp/bin/pscss index d48af2f8..8b2e4660 100755 --- a/vendor/scssphp/scssphp/bin/pscss +++ b/vendor/scssphp/scssphp/bin/pscss @@ -20,6 +20,8 @@ if (version_compare(PHP_VERSION, '5.6') < 0) { include __DIR__ . '/../scss.inc.php'; use ScssPhp\ScssPhp\Compiler; +use ScssPhp\ScssPhp\Exception\SassException; +use ScssPhp\ScssPhp\OutputStyle; use ScssPhp\ScssPhp\Parser; use ScssPhp\ScssPhp\Version; @@ -28,8 +30,6 @@ $loadPaths = null; $dumpTree = false; $inputFile = null; $changeDir = false; -$debugInfo = false; -$lineNumbers = false; $encoding = false; $sourceMap = false; @@ -71,14 +71,14 @@ Options include: --help Show this message [-h, -?] --continue-on-error [deprecated] Ignored - --debug-info Annotate selectors with CSS referring to the source file and line number [-g] + --debug-info [deprecated] Ignored [-g] --dump-tree Dump formatted parse tree [-T] --iso8859-1 Use iso8859-1 encoding instead of default utf-8 - --line-numbers Annotate selectors with comments referring to the source file and line number [--line-comments] + --line-numbers [deprecated] Ignored [--line-comments] --load-path=PATH Set import path [-I] --precision=N [deprecated] Ignored. (default 10) [-p] --sourcemap Create source map file - --style=FORMAT Set the output format (compact, compressed, crunched, expanded, or nested) [-s, -t] + --style=FORMAT Set the output style (compressed or expanded) [-s, -t] --version Print the version [-v] EOT; @@ -95,8 +95,9 @@ EOT; continue; } + // Keep parsing it to avoid BC breaks for scripts using it if ($argv[$i] === '-g' || $argv[$i] === '--debug-info') { - $debugInfo = true; + // TODO report it as a warning ? continue; } @@ -105,8 +106,9 @@ EOT; continue; } + // Keep parsing it to avoid BC breaks for scripts using it if ($argv[$i] === '--line-numbers' || $argv[$i] === '--line-comments') { - $lineNumbers = true; + // TODO report it as a warning ? continue; } @@ -151,14 +153,6 @@ EOT; if ($inputFile) { $data = file_get_contents($inputFile); - - $newWorkingDir = dirname(realpath($inputFile)); - $oldWorkingDir = getcwd(); - - if ($oldWorkingDir !== $newWorkingDir) { - $changeDir = chdir($newWorkingDir); - $inputFile = basename($inputFile); - } } else { $data = ''; @@ -177,20 +171,17 @@ if ($dumpTree) { $scss = new Compiler(); -if ($debugInfo) { - $scss->setLineNumberStyle(Compiler::DEBUG_INFO); -} - -if ($lineNumbers) { - $scss->setLineNumberStyle(Compiler::LINE_COMMENTS); -} - if ($loadPaths) { $scss->setImportPaths(explode(PATH_SEPARATOR, $loadPaths)); } if ($style) { - $scss->setFormatter('ScssPhp\\ScssPhp\\Formatter\\' . ucfirst($style)); + if ($style === OutputStyle::COMPRESSED || $style === OutputStyle::EXPANDED) { + $scss->setOutputStyle($style); + } else { + fwrite(STDERR, "WARNING: the $style style is deprecated.\n"); + $scss->setFormatter('ScssPhp\\ScssPhp\\Formatter\\' . ucfirst($style)); + } } if ($sourceMap) { @@ -201,8 +192,9 @@ if ($encoding) { $scss->setEncoding($encoding); } -echo $scss->compile($data, $inputFile); - -if ($changeDir) { - chdir($oldWorkingDir); +try { + echo $scss->compile($data, $inputFile); +} catch (SassException $e) { + fwrite(STDERR, $e->getMessage()."\n"); + exit(1); } diff --git a/vendor/scssphp/scssphp/composer.json b/vendor/scssphp/scssphp/composer.json index 7f420edf..2c95c9f0 100644 --- a/vendor/scssphp/scssphp/composer.json +++ b/vendor/scssphp/scssphp/composer.json @@ -31,9 +31,10 @@ "ext-ctype": "*" }, "require-dev": { - "sass/sass-spec": "2020.08.10", + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3 || ^9.4", + "sass/sass-spec": "2020.10.29", "squizlabs/php_codesniffer": "~3.5", - "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3", + "symfony/phpunit-bridge": "^5.1", "twbs/bootstrap": "~4.3", "zurb/foundation": "~6.5" }, @@ -42,31 +43,23 @@ "type": "package", "package": { "name": "sass/sass-spec", - "version": "2020.08.10", + "version": "2020.10.29", "source": { "type": "git", "url": "https://github.com/sass/sass-spec.git", - "reference": "73222792c42a516d62e2e25c3f5d9e35f5567030" + "reference": "07094dab93a598795e8b04caec6ceae67a43f504" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sass/sass-spec/zipball/73222792c42a516d62e2e25c3f5d9e35f5567030", - "reference": "73222792c42a516d62e2e25c3f5d9e35f5567030", + "url": "https://api.github.com/repos/sass/sass-spec/zipball/07094dab93a598795e8b04caec6ceae67a43f504", + "reference": "07094dab93a598795e8b04caec6ceae67a43f504", "shasum": "" } } } ], - "minimum-stability": "dev", "bin": ["bin/pscss"], - "archive": { - "exclude": [ - "/Makefile", - "/.gitattributes", - "/.gitignore", - "/.travis.yml", - "/phpunit.xml.dist", - "/tests" - ] + "config": { + "sort-packages": true } } diff --git a/vendor/scssphp/scssphp/scss.inc.php b/vendor/scssphp/scssphp/scss.inc.php index abbd9d21..dd6fb030 100644 --- a/vendor/scssphp/scssphp/scss.inc.php +++ b/vendor/scssphp/scssphp/scss.inc.php @@ -6,12 +6,14 @@ if (version_compare(PHP_VERSION, '5.6') < 0) { if (! class_exists('ScssPhp\ScssPhp\Version', false)) { include_once __DIR__ . '/src/Base/Range.php'; + include_once __DIR__ . '/src/OutputStyle.php'; include_once __DIR__ . '/src/Block.php'; include_once __DIR__ . '/src/Cache.php'; include_once __DIR__ . '/src/Colors.php'; include_once __DIR__ . '/src/Compiler.php'; include_once __DIR__ . '/src/Compiler/Environment.php'; include_once __DIR__ . '/src/Exception/SassException.php'; + include_once __DIR__ . '/src/Exception/SassScriptException.php'; include_once __DIR__ . '/src/Exception/CompilerException.php'; include_once __DIR__ . '/src/Exception/ParserException.php'; include_once __DIR__ . '/src/Exception/RangeException.php'; diff --git a/vendor/scssphp/scssphp/src/Block.php b/vendor/scssphp/scssphp/src/Block.php index aaeba715..f7f4571e 100644 --- a/vendor/scssphp/scssphp/src/Block.php +++ b/vendor/scssphp/scssphp/src/Block.php @@ -50,7 +50,7 @@ class Block public $sourceColumn; /** - * @var array + * @var array|null */ public $selectors; diff --git a/vendor/scssphp/scssphp/src/Compiler.php b/vendor/scssphp/scssphp/src/Compiler.php index 6aedb2db..94d8eacb 100644 --- a/vendor/scssphp/scssphp/src/Compiler.php +++ b/vendor/scssphp/scssphp/src/Compiler.php @@ -13,17 +13,14 @@ namespace ScssPhp\ScssPhp; use ScssPhp\ScssPhp\Base\Range; -use ScssPhp\ScssPhp\Block; -use ScssPhp\ScssPhp\Cache; -use ScssPhp\ScssPhp\Colors; use ScssPhp\ScssPhp\Compiler\Environment; use ScssPhp\ScssPhp\Exception\CompilerException; +use ScssPhp\ScssPhp\Exception\SassScriptException; +use ScssPhp\ScssPhp\Formatter\Compressed; +use ScssPhp\ScssPhp\Formatter\Expanded; use ScssPhp\ScssPhp\Formatter\OutputBlock; -use ScssPhp\ScssPhp\Node; +use ScssPhp\ScssPhp\Node\Number; use ScssPhp\ScssPhp\SourceMap\SourceMapGenerator; -use ScssPhp\ScssPhp\Type; -use ScssPhp\ScssPhp\Parser; -use ScssPhp\ScssPhp\Util; /** * The scss compiler and parser. @@ -59,12 +56,30 @@ use ScssPhp\ScssPhp\Util; */ class Compiler { + /** + * @deprecated + */ const LINE_COMMENTS = 1; + /** + * @deprecated + */ const DEBUG_INFO = 2; + /** + * @deprecated + */ const WITH_RULE = 1; + /** + * @deprecated + */ const WITH_MEDIA = 2; + /** + * @deprecated + */ const WITH_SUPPORTS = 4; + /** + * @deprecated + */ const WITH_ALL = 7; const SOURCE_MAP_NONE = 0; @@ -72,7 +87,7 @@ class Compiler const SOURCE_MAP_FILE = 2; /** - * @var array + * @var array */ protected static $operatorNames = [ '+' => 'add', @@ -88,11 +103,10 @@ class Compiler '<=' => 'lte', '>=' => 'gte', - '<=>' => 'cmp', ]; /** - * @var array + * @var array */ protected static $namespaces = [ 'special' => '%', @@ -102,7 +116,9 @@ class Compiler public static $true = [Type::T_KEYWORD, 'true']; public static $false = [Type::T_KEYWORD, 'false']; + /** @deprecated */ public static $NaN = [Type::T_KEYWORD, 'NaN']; + /** @deprecated */ public static $Infinity = [Type::T_KEYWORD, 'Infinity']; public static $null = [Type::T_NULL]; public static $nullString = [Type::T_STRING, '', []]; @@ -114,58 +130,155 @@ class Compiler public static $with = [Type::T_KEYWORD, 'with']; public static $without = [Type::T_KEYWORD, 'without']; - protected $importPaths = ['']; + /** + * @var array + */ + protected $importPaths = []; + /** + * @var array + */ protected $importCache = []; + /** + * @var string[] + */ protected $importedFiles = []; protected $userFunctions = []; protected $registeredVars = []; + /** + * @var array + */ protected $registeredFeatures = [ 'extend-selector-pseudoclass' => false, 'at-error' => true, - 'units-level-3' => false, + 'units-level-3' => true, 'global-variable-shadowing' => false, ]; + /** + * @var string|null + */ protected $encoding = null; + /** + * @deprecated + */ protected $lineNumberStyle = null; + /** + * @var int|SourceMapGenerator + * @phpstan-var self::SOURCE_MAP_*|SourceMapGenerator + */ protected $sourceMap = self::SOURCE_MAP_NONE; protected $sourceMapOptions = []; /** * @var string|\ScssPhp\ScssPhp\Formatter */ - protected $formatter = 'ScssPhp\ScssPhp\Formatter\Nested'; + protected $formatter = Expanded::class; + /** + * @var Environment + */ protected $rootEnv; + /** + * @var OutputBlock|null + */ protected $rootBlock; /** * @var \ScssPhp\ScssPhp\Compiler\Environment */ protected $env; + /** + * @var OutputBlock|null + */ protected $scope; + /** + * @var Environment|null + */ protected $storeEnv; + /** + * @var bool|null + */ protected $charsetSeen; + /** + * @var array + */ protected $sourceNames; + /** + * @var Cache|null + */ protected $cache; + /** + * @var int + */ protected $indentLevel; + /** + * @var array[] + */ protected $extends; + /** + * @var array + */ protected $extendsMap; + /** + * @var array + */ protected $parsedFiles; + /** + * @var Parser|null + */ protected $parser; + /** + * @var int|null + */ protected $sourceIndex; + /** + * @var int|null + */ protected $sourceLine; + /** + * @var int|null + */ protected $sourceColumn; + /** + * @var resource + */ protected $stderr; + /** + * @var bool|null + */ protected $shouldEvaluate; + /** + * @var null + * @deprecated + */ protected $ignoreErrors; + /** + * @var bool + */ protected $ignoreCallStackMessage = false; + /** + * @var array[] + */ protected $callStack = []; + /** + * The directory of the currently processed file + * + * @var string + */ + private $currentDirectory; + + /** + * The directory of the input file + * + * @var string + */ + private $rootDirectory; + /** * Constructor * @@ -186,7 +299,7 @@ class Compiler /** * Get compiler options * - * @return array + * @return array */ public function getCompileOptions() { @@ -207,6 +320,8 @@ class Compiler * Set an alternative error output stream, for testing purpose only * * @param resource $handle + * + * @return void */ public function setErrorOuput($handle) { @@ -259,46 +374,66 @@ class Compiler $this->shouldEvaluate = null; $this->ignoreCallStackMessage = false; - $this->parser = $this->parserFactory($path); - $tree = $this->parser->parse($code); - $this->parser = null; - - $this->formatter = new $this->formatter(); - $this->rootBlock = null; - $this->rootEnv = $this->pushEnv($tree); - - $this->injectVariables($this->registeredVars); - $this->compileRoot($tree); - $this->popEnv(); - - $sourceMapGenerator = null; - - if ($this->sourceMap) { - if (\is_object($this->sourceMap) && $this->sourceMap instanceof SourceMapGenerator) { - $sourceMapGenerator = $this->sourceMap; - $this->sourceMap = self::SOURCE_MAP_FILE; - } elseif ($this->sourceMap !== self::SOURCE_MAP_NONE) { - $sourceMapGenerator = new SourceMapGenerator($this->sourceMapOptions); - } + if (!\is_null($path) && is_file($path)) { + $this->currentDirectory = dirname(realpath($path) ?: $path); + } else { + $this->currentDirectory = getcwd(); } + $this->rootDirectory = $this->currentDirectory; - $out = $this->formatter->format($this->scope, $sourceMapGenerator); + try { + $this->parser = $this->parserFactory($path); + $tree = $this->parser->parse($code); + $this->parser = null; - if (! empty($out) && $this->sourceMap && $this->sourceMap !== self::SOURCE_MAP_NONE) { - $sourceMap = $sourceMapGenerator->generateJson(); - $sourceMapUrl = null; + $this->formatter = new $this->formatter(); + $this->rootBlock = null; + $this->rootEnv = $this->pushEnv($tree); - switch ($this->sourceMap) { - case self::SOURCE_MAP_INLINE: - $sourceMapUrl = sprintf('data:application/json,%s', Util::encodeURIComponent($sourceMap)); - break; + $this->injectVariables($this->registeredVars); + $this->compileRoot($tree); + $this->popEnv(); - case self::SOURCE_MAP_FILE: - $sourceMapUrl = $sourceMapGenerator->saveMap($sourceMap); - break; + $sourceMapGenerator = null; + + if ($this->sourceMap) { + if (\is_object($this->sourceMap) && $this->sourceMap instanceof SourceMapGenerator) { + $sourceMapGenerator = $this->sourceMap; + $this->sourceMap = self::SOURCE_MAP_FILE; + } elseif ($this->sourceMap !== self::SOURCE_MAP_NONE) { + $sourceMapGenerator = new SourceMapGenerator($this->sourceMapOptions); + } } - $out .= sprintf('/*# sourceMappingURL=%s */', $sourceMapUrl); + $out = $this->formatter->format($this->scope, $sourceMapGenerator); + + $prefix = ''; + + if (!$this->charsetSeen) { + if (strlen($out) !== Util::mbStrlen($out)) { + $prefix = '@charset "UTF-8";' . "\n"; + $out = $prefix . $out; + } + } + + if (! empty($out) && $this->sourceMap && $this->sourceMap !== self::SOURCE_MAP_NONE) { + $sourceMap = $sourceMapGenerator->generateJson($prefix); + $sourceMapUrl = null; + + switch ($this->sourceMap) { + case self::SOURCE_MAP_INLINE: + $sourceMapUrl = sprintf('data:application/json,%s', Util::encodeURIComponent($sourceMap)); + break; + + case self::SOURCE_MAP_FILE: + $sourceMapUrl = $sourceMapGenerator->saveMap($sourceMap); + break; + } + + $out .= sprintf('/*# sourceMappingURL=%s */', $sourceMapUrl); + } + } catch (SassScriptException $e) { + throw $this->error($e->getMessage()); } if ($this->cache && isset($cacheKey) && isset($compileOptions)) { @@ -366,6 +501,8 @@ class Compiler * @param array $target * @param array $origin * @param array|null $block + * + * @return void */ protected function pushExtends($target, $origin, $block) { @@ -416,6 +553,8 @@ class Compiler * Compile root * * @param \ScssPhp\ScssPhp\Block $rootBlock + * + * @return void */ protected function compileRoot(Block $rootBlock) { @@ -428,6 +567,8 @@ class Compiler /** * Report missing selectors + * + * @return void */ protected function missingSelectors() { @@ -456,6 +597,8 @@ class Compiler * * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block * @param string $parentKey + * + * @return void */ protected function flattenSelectors(OutputBlock $block, $parentKey = null) { @@ -552,6 +695,8 @@ class Compiler * @param array $out * @param integer $from * @param boolean $initial + * + * @return void */ protected function matchExtends($selector, &$out, $from = 0, $initial = true) { @@ -705,6 +850,8 @@ class Compiler * * @param array $out * @param array $extended + * + * @return void */ protected function pushOrMergeExtentedSelector(&$out, $extended) { @@ -796,7 +943,7 @@ class Compiler $buffer = $matches[2]; $parser = $this->parserFactory(__METHOD__); - if ($parser->parseSelector($buffer, $subSelectors)) { + if ($parser->parseSelector($buffer, $subSelectors, false)) { foreach ($subSelectors as $ksub => $subSelector) { $subExtended = []; $this->matchExtends($subSelector, $subExtended, 0, false); @@ -956,6 +1103,8 @@ class Compiler * Compile media * * @param \ScssPhp\ScssPhp\Block $media + * + * @return void */ protected function compileMedia(Block $media) { @@ -1003,30 +1152,6 @@ class Compiler $wrapped->children = $media->children; $media->children = [[Type::T_BLOCK, $wrapped]]; - - if (isset($this->lineNumberStyle)) { - $annotation = $this->makeOutputBlock(Type::T_COMMENT); - $annotation->depth = 0; - - $file = $this->sourceNames[$media->sourceIndex]; - $line = $media->sourceLine; - - switch ($this->lineNumberStyle) { - case static::LINE_COMMENTS: - $annotation->lines[] = '/* line ' . $line - . ($file ? ', ' . $file : '') - . ' */'; - break; - - case static::DEBUG_INFO: - $annotation->lines[] = '@media -sass-debug-info{' - . ($file ? 'filename{font-family:"' . $file . '"}' : '') - . 'line{font-family:' . $line . '}}'; - break; - } - - $this->scope->children[] = $annotation; - } } $this->compileChildrenNoReturn($media->children, $this->scope); @@ -1062,18 +1187,31 @@ class Compiler * * @param \ScssPhp\ScssPhp\Block|array $block * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * + * @return void */ protected function compileDirective($directive, OutputBlock $out) { if (\is_array($directive)) { - $s = '@' . $directive[0]; + $directiveName = $this->compileDirectiveName($directive[0]); + $s = '@' . $directiveName; if (! empty($directive[1])) { $s .= ' ' . $this->compileValue($directive[1]); } + // sass-spec compliance on newline after directives, a bit tricky :/ + $appendNewLine = (! empty($directive[2]) || strpos($s, "\n")) ? "\n" : ""; + if (\is_array($directive[0]) && empty($directive[1])) { + $appendNewLine = "\n"; + } - $this->appendRootDirective($s . ';', $out); + if (empty($directive[3])) { + $this->appendRootDirective($s . ';' . $appendNewLine, $out, [Type::T_COMMENT, Type::T_DIRECTIVE]); + } else { + $this->appendOutputLine($out, Type::T_DIRECTIVE, $s . ';'); + } } else { + $directive->name = $this->compileDirectiveName($directive->name); $s = '@' . $directive->name; if (! empty($directive->value)) { @@ -1088,10 +1226,28 @@ class Compiler } } + /** + * directive names can include some interpolation + * + * @param string|array $directiveName + * @return array|string + * @throws CompilerException + */ + protected function compileDirectiveName($directiveName) + { + if (is_string($directiveName)) { + return $directiveName; + } + + return $this->compileValue($directiveName); + } + /** * Compile at-root * * @param \ScssPhp\ScssPhp\Block $block + * + * @return void */ protected function compileAtRoot(Block $block) { @@ -1148,7 +1304,7 @@ class Compiler * @param array $with * @param array $without * - * @return mixed + * @return OutputBlock */ protected function filterScopeWithWithout($scope, $with, $without) { @@ -1221,7 +1377,7 @@ class Compiler * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $scope * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $previousScope * - * @return mixed + * @return OutputBlock */ protected function completeScope($scope, $previousScope) { @@ -1317,11 +1473,13 @@ class Compiler /** * Filter env stack * - * @param array $envs + * @param Environment[] $envs * @param array $with * @param array $without * - * @return \ScssPhp\ScssPhp\Compiler\Environment + * @return Environment + * + * @phpstan-param non-empty-array $envs */ protected function filterWithWithout($envs, $with, $without) { @@ -1360,7 +1518,7 @@ class Compiler if ($block->type === Type::T_DIRECTIVE) { if (isset($block->name)) { - return $this->testWithWithout($block->name, $with, $without); + return $this->testWithWithout($this->compileDirectiveName($block->name), $with, $without); } elseif (isset($block->selectors) && preg_match(',@(\w+),ims', json_encode($block->selectors), $m)) { return $this->testWithWithout($m[1], $with, $without); } else { @@ -1376,7 +1534,7 @@ class Compiler $s = reset($s); } - if (\is_object($s) && $s instanceof Node\Number) { + if (\is_object($s) && $s instanceof Number) { return $this->testWithWithout('keyframes', $with, $without); } } @@ -1414,6 +1572,8 @@ class Compiler * * @param \ScssPhp\ScssPhp\Block $block * @param array $selectors + * + * @return void */ protected function compileKeyframeBlock(Block $block, $selectors) { @@ -1442,6 +1602,8 @@ class Compiler * * @param \ScssPhp\ScssPhp\Block $block * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * + * @return void */ protected function compileNestedPropertiesBlock(Block $block, OutputBlock $out) { @@ -1476,6 +1638,8 @@ class Compiler * * @param \ScssPhp\ScssPhp\Block $block * @param array $selectors + * + * @return void */ protected function compileNestedBlock(Block $block, $selectors) { @@ -1486,7 +1650,7 @@ class Compiler // wrap assign children in a block // except for @font-face - if ($block->type !== Type::T_DIRECTIVE || $block->name !== 'font-face') { + if ($block->type !== Type::T_DIRECTIVE || $this->compileDirectiveName($block->name) !== 'font-face') { // need wrapping? $needWrapping = false; @@ -1537,6 +1701,8 @@ class Compiler * @see Compiler::compileChild() * * @param \ScssPhp\ScssPhp\Block $block + * + * @return void */ protected function compileBlock(Block $block) { @@ -1545,30 +1711,6 @@ class Compiler $out = $this->makeOutputBlock(null); - if (isset($this->lineNumberStyle) && \count($env->selectors) && \count($block->children)) { - $annotation = $this->makeOutputBlock(Type::T_COMMENT); - $annotation->depth = 0; - - $file = $this->sourceNames[$block->sourceIndex]; - $line = $block->sourceLine; - - switch ($this->lineNumberStyle) { - case static::LINE_COMMENTS: - $annotation->lines[] = '/* line ' . $line - . ($file ? ', ' . $file : '') - . ' */'; - break; - - case static::DEBUG_INFO: - $annotation->lines[] = '@media -sass-debug-info{' - . ($file ? 'filename{font-family:"' . $file . '"}' : '') - . 'line{font-family:' . $line . '}}'; - break; - } - - $this->scope->children[] = $annotation; - } - $this->scope->children[] = $out; if (\count($block->children)) { @@ -1600,7 +1742,7 @@ class Compiler * @param array $value * @param boolean $pushEnv * - * @return array|mixed|string + * @return string */ protected function compileCommentValue($value, $pushEnv = false) { @@ -1634,6 +1776,8 @@ class Compiler * Compile root level comment * * @param array $block + * + * @return void */ protected function compileComment($block) { @@ -1662,7 +1806,7 @@ class Compiler $buffer = $this->collapseSelectors($selectors); $parser = $this->parserFactory(__METHOD__); - if ($parser->parseSelector($buffer, $newSelectors)) { + if ($parser->parseSelector($buffer, $newSelectors, true)) { $selectors = array_map([$this, 'evalSelector'], $newSelectors); } } @@ -1695,8 +1839,8 @@ class Compiler if (\is_array($p) && ($p[0] === Type::T_INTERPOLATE || $p[0] === Type::T_STRING)) { $p = $this->compileValue($p); - // force re-evaluation - if (strpos($p, '&') !== false || strpos($p, ',') !== false) { + // force re-evaluation if self char or non standard char + if (preg_match(',[^\w-],', $p)) { $this->shouldEvaluate = true; } } elseif ( @@ -1908,6 +2052,11 @@ class Compiler return false; } + /** + * @param string $name + * + * @return void + */ protected function pushCallStack($name = '') { $this->callStack[] = [ @@ -1927,6 +2076,9 @@ class Compiler } } + /** + * @return void + */ protected function popCallStack() { array_pop($this->callStack); @@ -1961,13 +2113,15 @@ class Compiler } /** - * Compile children and throw exception if unexpected @return + * Compile children and throw exception if unexpected `@return` * * @param array $stms * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out * @param \ScssPhp\ScssPhp\Block $selfParent * @param string $traceName * + * @return void + * * @throws \Exception */ protected function compileChildrenNoReturn($stms, OutputBlock $out, $selfParent = null, $traceName = '') @@ -1997,7 +2151,7 @@ class Compiler /** - * evaluate media query : compile internal value keeping the structure inchanged + * evaluate media query : compile internal value keeping the structure unchanged * * @param array $queryList * @@ -2346,7 +2500,7 @@ class Compiler } /** - * @param $rawPath + * @param array $rawPath * @return string * @throws CompilerException */ @@ -2354,12 +2508,12 @@ class Compiler { $path = $this->compileValue($rawPath); - // case url() without quotes : supress \r \n remaining in the path + // case url() without quotes : suppress \r \n remaining in the path // if this is a real string there can not be CR or LF char if (strpos($path, 'url(') === 0) { $path = str_replace(array("\r", "\n"), array('', ' '), $path); } else { - // if this is a file name in a string, spaces shoudl be escaped + // if this is a file name in a string, spaces should be escaped $path = $this->reduce($rawPath); $path = $this->escapeImportPathString($path); $path = $this->compileValue($path); @@ -2397,9 +2551,11 @@ class Compiler * Append a root directive like @import or @charset as near as the possible from the source code * (keeping before comments, @import and @charset coming before in the source code) * - * @param string $line - * @param @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out - * @param array $allowed + * @param string $line + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * @param array $allowed + * + * @return void */ protected function appendRootDirective($line, $out, $allowed = [Type::T_COMMENT]) { @@ -2448,6 +2604,8 @@ class Compiler * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out * @param string $type * @param string|mixed $line + * + * @return void */ protected function appendOutputLine(OutputBlock $out, $type, $line) { @@ -2482,7 +2640,7 @@ class Compiler * @param array $child * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out * - * @return array + * @return array|Number|null */ protected function compileChild($child, OutputBlock $out) { @@ -2626,7 +2784,7 @@ class Compiler $divider = $this->reduce($divider, true); } - if (\intval($divider->dimension) && ! \count($divider->units)) { + if ($divider instanceof Number && \intval($divider->getDimension()) && $divider->unitless()) { $revert = false; } } @@ -2650,7 +2808,7 @@ class Compiler $divider = $this->reduce($divider, true); } - if (\intval($divider->dimension) && ! \count($divider->units)) { + if ($divider instanceof Number && \intval($divider->getDimension()) && $divider->unitless()) { $revert = false; } } @@ -2763,17 +2921,11 @@ class Compiler $ret = $this->compileChildren($each->children, $out); if ($ret) { - if ($ret[0] !== Type::T_CONTROL) { - $store = $this->env->store; - $this->popEnv(); - $this->backPropagateEnv($store, $each->vars); + $store = $this->env->store; + $this->popEnv(); + $this->backPropagateEnv($store, $each->vars); - return $ret; - } - - if ($ret[1]) { - break; - } + return $ret; } } $store = $this->env->store; @@ -2789,13 +2941,7 @@ class Compiler $ret = $this->compileChildren($while->children, $out); if ($ret) { - if ($ret[0] !== Type::T_CONTROL) { - return $ret; - } - - if ($ret[1]) { - break; - } + return $ret; } } break; @@ -2806,21 +2952,21 @@ class Compiler $start = $this->reduce($for->start, true); $end = $this->reduce($for->end, true); - if (! $start instanceof Node\Number) { + if (! $start instanceof Number) { throw $this->error('%s is not a number', $start[0]); } - if (! $end instanceof Node\Number) { + if (! $end instanceof Number) { throw $this->error('%s is not a number', $end[0]); } - if (! ($start[2] == $end[2] || $end->unitless())) { - throw $this->error('Incompatible units: "%s" && "%s".', $start->unitStr(), $end->unitStr()); - } + $start->assertSameUnitOrUnitless($end); - $unit = $start[2]; - $start = $start[1]; - $end = $end[1]; + $numeratorUnits = $start->getNumeratorUnits(); + $denominatorUnits = $start->getDenominatorUnits(); + + $start = $start->getDimension(); + $end = $end->getDimension(); $d = $start < $end ? 1 : -1; @@ -2834,23 +2980,17 @@ class Compiler break; } - $this->set($for->var, new Node\Number($start, $unit)); + $this->set($for->var, new Number($start, $numeratorUnits, $denominatorUnits)); $start += $d; $ret = $this->compileChildren($for->children, $out); if ($ret) { - if ($ret[0] !== Type::T_CONTROL) { - $store = $this->env->store; - $this->popEnv(); - $this->backPropagateEnv($store, [$for->var]); + $store = $this->env->store; + $this->popEnv(); + $this->backPropagateEnv($store, [$for->var]); - return $ret; - } - - if ($ret[1]) { - break; - } + return $ret; } } @@ -2860,12 +3000,6 @@ class Compiler break; - case Type::T_BREAK: - return [Type::T_CONTROL, true]; - - case Type::T_CONTINUE: - return [Type::T_CONTROL, false]; - case Type::T_RETURN: return $this->reduce($child[1], true); @@ -2980,7 +3114,7 @@ class Compiler case Type::T_DEBUG: list(, $value) = $child; - $fname = $this->sourceNames[$this->sourceIndex]; + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); $line = $this->sourceLine; $value = $this->compileDebugValue($value); @@ -2990,7 +3124,7 @@ class Compiler case Type::T_WARN: list(, $value) = $child; - $fname = $this->sourceNames[$this->sourceIndex]; + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); $line = $this->sourceLine; $value = $this->compileDebugValue($value); @@ -3000,15 +3134,12 @@ class Compiler case Type::T_ERROR: list(, $value) = $child; - $fname = $this->sourceNames[$this->sourceIndex]; + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); $line = $this->sourceLine; $value = $this->compileValue($this->reduce($value, true)); throw $this->error("File $fname on line $line ERROR: $value\n"); - case Type::T_CONTROL: - throw $this->error('@break/@continue not permitted in this scope'); - default: throw $this->error("unknown child type: $child[0]"); } @@ -3018,14 +3149,21 @@ class Compiler * Reduce expression to string * * @param array $exp + * @param bool $keepParens * * @return array */ - protected function expToString($exp) + protected function expToString($exp, $keepParens = false) { - list(, $op, $left, $right, /* $inParens */, $whiteLeft, $whiteRight) = $exp; + list(, $op, $left, $right, $inParens, $whiteLeft, $whiteRight) = $exp; - $content = [$this->reduce($left)]; + $content = []; + + if ($keepParens && $inParens) { + $content[] = '('; + } + + $content[] = $this->reduce($left); if ($whiteLeft) { $content[] = ' '; @@ -3039,13 +3177,17 @@ class Compiler $content[] = $this->reduce($right); + if ($keepParens && $inParens) { + $content[] = ')'; + } + return [Type::T_STRING, '', $content]; } /** * Is truthy? * - * @param array $value + * @param array|Number $value * * @return boolean */ @@ -3093,10 +3235,10 @@ class Compiler /** * Reduce value * - * @param array $value + * @param array|Number $value * @param boolean $inExp * - * @return null|string|array|\ScssPhp\ScssPhp\Node\Number + * @return null|string|array|Number */ protected function reduce($value, $inExp = false) { @@ -3119,8 +3261,8 @@ class Compiler // special case: looks like css shorthand if ( - $opName == 'div' && ! $inParens && ! $inExp && isset($right[2]) && - (($right[0] !== Type::T_NUMBER && $right[2] != '') || + $opName == 'div' && ! $inParens && ! $inExp && + (($right[0] !== Type::T_NUMBER && isset($right[2]) && $right[2] != '') || ($right[0] === Type::T_NUMBER && ! $right->unitless())) ) { return $this->expToString($value); @@ -3150,50 +3292,6 @@ class Compiler \is_callable([$this, $fn]) && $genOp = true) ) { - $coerceUnit = false; - - if ( - ! isset($genOp) && - $left[0] === Type::T_NUMBER && $right[0] === Type::T_NUMBER - ) { - $coerceUnit = true; - - switch ($opName) { - case 'mul': - $targetUnit = $left[2]; - - foreach ($right[2] as $unit => $exp) { - $targetUnit[$unit] = (isset($targetUnit[$unit]) ? $targetUnit[$unit] : 0) + $exp; - } - break; - - case 'div': - $targetUnit = $left[2]; - - foreach ($right[2] as $unit => $exp) { - $targetUnit[$unit] = (isset($targetUnit[$unit]) ? $targetUnit[$unit] : 0) - $exp; - } - break; - - case 'mod': - $targetUnit = $left[2]; - break; - - default: - $targetUnit = $left->unitless() ? $right[2] : $left[2]; - } - - $baseUnitLeft = $left->isNormalizable(); - $baseUnitRight = $right->isNormalizable(); - - if ($baseUnitLeft && $baseUnitRight && $baseUnitLeft === $baseUnitRight) { - $left = $left->normalize(); - $right = $right->normalize(); - } elseif ($coerceUnit) { - $left = new Node\Number($left[1], []); - } - } - $shouldEval = $inParens || $inExp; if (isset($passOp)) { @@ -3203,10 +3301,6 @@ class Compiler } if (isset($out)) { - if ($coerceUnit && $out[0] === Type::T_NUMBER) { - $out = $out->coerce($targetUnit); - } - return $out; } } @@ -3219,13 +3313,13 @@ class Compiler $inExp = $inExp || $this->shouldEval($exp); $exp = $this->reduce($exp); - if ($exp[0] === Type::T_NUMBER) { + if ($exp instanceof Number) { switch ($op) { case '+': - return new Node\Number($exp[1], $exp[2]); + return $exp; case '-': - return new Node\Number(-$exp[1], $exp[2]); + return $exp->unaryMinus(); } } @@ -3303,7 +3397,7 @@ class Compiler * @param string $name * @param array $argValues * - * @return array|null + * @return array|Number */ protected function fncall($functionReference, $argValues) { @@ -3345,6 +3439,18 @@ class Compiler case 'user': case 'native': list(,,$name, $fn, $prototype) = $functionReference; + + // special cases of css valid functions min/max + $name = strtolower($name); + if (\in_array($name, ['min', 'max'])) { + $cssFunction = $this->cssValidArg( + [Type::T_FUNCTION_CALL, $name, $argValues], + ['min', 'max', 'calc', 'env', 'var'] + ); + if ($cssFunction !== false) { + return $cssFunction; + } + } $returnValue = $this->callNativeFunction($name, $fn, $prototype, $argValues); if (! isset($returnValue)) { @@ -3358,10 +3464,96 @@ class Compiler } } + protected function cssValidArg($arg, $allowed_function = [], $inFunction = false) + { + switch ($arg[0]) { + case Type::T_INTERPOLATE: + return [Type::T_KEYWORD, $this->CompileValue($arg)]; + + case Type::T_FUNCTION: + if (! \in_array($arg[1], $allowed_function)) { + return false; + } + if ($arg[2][0] === Type::T_LIST) { + foreach ($arg[2][2] as $k => $subarg) { + $arg[2][2][$k] = $this->cssValidArg($subarg, $allowed_function, $arg[1]); + if ($arg[2][2][$k] === false) { + return false; + } + } + } + return $arg; + + case Type::T_FUNCTION_CALL: + if (! \in_array($arg[1], $allowed_function)) { + return false; + } + $cssArgs = []; + foreach ($arg[2] as $argValue) { + if ($argValue === static::$null) { + return false; + } + $cssArg = $this->cssValidArg($argValue[1], $allowed_function, $arg[1]); + if (empty($argValue[0]) && $cssArg !== false) { + $cssArgs[] = [$argValue[0], $cssArg]; + } else { + return false; + } + } + + return $this->fncall([Type::T_FUNCTION, $arg[1], [Type::T_LIST, ',', []]], $cssArgs); + + case Type::T_STRING: + case Type::T_KEYWORD: + if (!$inFunction or !\in_array($inFunction, ['calc', 'env', 'var'])) { + return false; + } + return $this->stringifyFncallArgs($arg); + + case Type::T_NUMBER: + return $this->stringifyFncallArgs($arg); + + case Type::T_LIST: + if (!$inFunction) { + return false; + } + if (empty($arg['enclosing']) and $arg[1] === '') { + foreach ($arg[2] as $k => $subarg) { + $arg[2][$k] = $this->cssValidArg($subarg, $allowed_function, $inFunction); + if ($arg[2][$k] === false) { + return false; + } + } + $arg[0] = Type::T_STRING; + return $arg; + } + return false; + + case Type::T_EXPRESSION: + if (! \in_array($arg[1], ['+', '-', '/', '*'])) { + return false; + } + $arg[2] = $this->cssValidArg($arg[2], $allowed_function, $inFunction); + $arg[3] = $this->cssValidArg($arg[3], $allowed_function, $inFunction); + if ($arg[2] === false || $arg[3] === false) { + return false; + } + return $this->expToString($arg, true); + + case Type::T_VARIABLE: + case Type::T_SELF: + default: + return false; + } + } + + /** * Reformat fncall arguments to proper css function output + * * @param $arg - * @return array|\ArrayAccess|Node\Number|string|null + * + * @return array|\ArrayAccess|Number|string|null */ protected function stringifyFncallArgs($arg) { @@ -3383,7 +3575,7 @@ class Compiler break; case Type::T_FUNCTION_CALL: - $name = $arg[1]; + $name = strtolower($arg[1]); if (in_array($name, ['max', 'min', 'calc'])) { $args = $arg[2]; @@ -3451,9 +3643,9 @@ class Compiler /** * Normalize value * - * @param array $value + * @param array|Number $value * - * @return array + * @return array|Number */ public function normalizeValue($value) { @@ -3480,9 +3672,6 @@ class Compiler case Type::T_STRING: return [$value[0], '"', [$this->compileStringContent($value)]]; - case Type::T_NUMBER: - return $value->normalize(); - case Type::T_INTERPOLATE: return [Type::T_KEYWORD, $this->compileValue($value)]; @@ -3494,74 +3683,66 @@ class Compiler /** * Add numbers * - * @param array $left - * @param array $right + * @param Number $left + * @param Number $right * - * @return \ScssPhp\ScssPhp\Node\Number + * @return Number */ - protected function opAddNumberNumber($left, $right) + protected function opAddNumberNumber(Number $left, Number $right) { - return new Node\Number($left[1] + $right[1], $left[2]); + return $left->plus($right); } /** * Multiply numbers * - * @param array $left - * @param array $right + * @param Number $left + * @param Number $right * - * @return \ScssPhp\ScssPhp\Node\Number + * @return Number */ - protected function opMulNumberNumber($left, $right) + protected function opMulNumberNumber(Number $left, Number $right) { - return new Node\Number($left[1] * $right[1], $left[2]); + return $left->times($right); } /** * Subtract numbers * - * @param array $left - * @param array $right + * @param Number $left + * @param Number $right * - * @return \ScssPhp\ScssPhp\Node\Number + * @return Number */ - protected function opSubNumberNumber($left, $right) + protected function opSubNumberNumber(Number $left, Number $right) { - return new Node\Number($left[1] - $right[1], $left[2]); + return $left->minus($right); } /** * Divide numbers * - * @param array $left - * @param array $right + * @param Number $left + * @param Number $right * - * @return array|\ScssPhp\ScssPhp\Node\Number + * @return Number */ - protected function opDivNumberNumber($left, $right) + protected function opDivNumberNumber(Number $left, Number $right) { - if ($right[1] == 0) { - return ($left[1] == 0) ? static::$NaN : static::$Infinity; - } - - return new Node\Number($left[1] / $right[1], $left[2]); + return $left->dividedBy($right); } /** * Mod numbers * - * @param array $left - * @param array $right + * @param Number $left + * @param Number $right * - * @return \ScssPhp\ScssPhp\Node\Number + * @return Number */ - protected function opModNumberNumber($left, $right) + protected function opModNumberNumber(Number $left, Number $right) { - if ($right[1] == 0) { - return static::$NaN; - } - - return new Node\Number($left[1] % $right[1], $left[2]); + return $left->modulo($right); } /** @@ -3600,11 +3781,11 @@ class Compiler /** * Boolean and * - * @param array $left - * @param array $right + * @param array|Number $left + * @param array|Number $right * @param boolean $shouldEval * - * @return array|null + * @return array|Number|null */ protected function opAnd($left, $right, $shouldEval) { @@ -3628,11 +3809,11 @@ class Compiler /** * Boolean or * - * @param array $left - * @param array $right + * @param array|Number $left + * @param array|Number $right * @param boolean $shouldEval * - * @return array|null + * @return array|Number|null */ protected function opOr($left, $right, $shouldEval) { @@ -3664,6 +3845,15 @@ class Compiler */ protected function opColorColor($op, $left, $right) { + if ($op !== '==' && $op !== '!=') { + $warning = "Color arithmetic is deprecated and will be an error in future versions.\n" + . "Consider using Sass's color functions instead."; + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); + $line = $this->sourceLine; + + fwrite($this->stderr, "DEPRECATION WARNING: $warning\n on line $line of $fname\n\n"); + } + $out = [Type::T_COLOR]; foreach ([1, 2, 3] as $i) { @@ -3724,13 +3914,21 @@ class Compiler * * @param string $op * @param array $left - * @param array $right + * @param Number $right * * @return array */ - protected function opColorNumber($op, $left, $right) + protected function opColorNumber($op, $left, Number $right) { - $value = $right[1]; + if ($op === '==') { + return static::$false; + } + + if ($op === '!=') { + return static::$true; + } + + $value = $right->getDimension(); return $this->opColorColor( $op, @@ -3743,14 +3941,22 @@ class Compiler * Compare number and color * * @param string $op - * @param array $left + * @param Number $left * @param array $right * * @return array */ - protected function opNumberColor($op, $left, $right) + protected function opNumberColor($op, Number $left, $right) { - $value = $left[1]; + if ($op === '==') { + return static::$false; + } + + if ($op === '!=') { + return static::$true; + } + + $value = $left->getDimension(); return $this->opColorColor( $op, @@ -3762,8 +3968,8 @@ class Compiler /** * Compare number1 == number2 * - * @param array $left - * @param array $right + * @param array|Number $left + * @param array|Number $right * * @return array */ @@ -3783,8 +3989,8 @@ class Compiler /** * Compare number1 != number2 * - * @param array $left - * @param array $right + * @param array|Number $left + * @param array|Number $right * * @return array */ @@ -3802,70 +4008,81 @@ class Compiler } /** - * Compare number1 >= number2 + * Compare number1 == number2 * - * @param array $left - * @param array $right + * @param Number $left + * @param Number $right * * @return array */ - protected function opGteNumberNumber($left, $right) + protected function opEqNumberNumber(Number $left, Number $right) { - return $this->toBool($left[1] >= $right[1]); + return $this->toBool($left->equals($right)); + } + + /** + * Compare number1 != number2 + * + * @param Number $left + * @param Number $right + * + * @return array + */ + protected function opNeqNumberNumber(Number $left, Number $right) + { + return $this->toBool(!$left->equals($right)); + } + + /** + * Compare number1 >= number2 + * + * @param Number $left + * @param Number $right + * + * @return array + */ + protected function opGteNumberNumber(Number $left, Number $right) + { + return $this->toBool($left->greaterThanOrEqual($right)); } /** * Compare number1 > number2 * - * @param array $left - * @param array $right + * @param Number $left + * @param Number $right * * @return array */ - protected function opGtNumberNumber($left, $right) + protected function opGtNumberNumber(Number $left, Number $right) { - return $this->toBool($left[1] > $right[1]); + return $this->toBool($left->greaterThan($right)); } /** * Compare number1 <= number2 * - * @param array $left - * @param array $right + * @param Number $left + * @param Number $right * * @return array */ - protected function opLteNumberNumber($left, $right) + protected function opLteNumberNumber(Number $left, Number $right) { - return $this->toBool($left[1] <= $right[1]); + return $this->toBool($left->lessThanOrEqual($right)); } /** * Compare number1 < number2 * - * @param array $left - * @param array $right + * @param Number $left + * @param Number $right * * @return array */ - protected function opLtNumberNumber($left, $right) + protected function opLtNumberNumber(Number $left, Number $right) { - return $this->toBool($left[1] < $right[1]); - } - - /** - * Three-way comparison, aka spaceship operator - * - * @param array $left - * @param array $right - * - * @return \ScssPhp\ScssPhp\Node\Number - */ - protected function opCmpNumberNumber($left, $right) - { - $n = $left[1] - $right[1]; - - return new Node\Number($n ? $n / abs($n) : 0, ''); + return $this->toBool($left->lessThan($right)); } /** @@ -3882,6 +4099,48 @@ class Compiler return $thing ? static::$true : static::$false; } + /** + * Escape non printable chars in strings output as in dart-sass + * @param string $string + * @return string + */ + public function escapeNonPrintableChars($string, $inKeyword = false) + { + static $replacement = []; + if (empty($replacement[$inKeyword])) { + for ($i = 0; $i < 32; $i++) { + if ($i !== 9 || $inKeyword) { + $replacement[$inKeyword][chr($i)] = '\\' . dechex($i) . ($inKeyword ? ' ' : chr(0)); + } + } + } + $string = str_replace(array_keys($replacement[$inKeyword]), array_values($replacement[$inKeyword]), $string); + // chr(0) is not a possible char from the input, so any chr(0) comes from our escaping replacement + if (strpos($string, chr(0)) !== false) { + if (substr($string, -1) === chr(0)) { + $string = substr($string, 0, -1); + } + $string = str_replace( + [chr(0) . '\\',chr(0) . ' '], + [ '\\', ' '], + $string + ); + if (strpos($string, chr(0)) !== false) { + $parts = explode(chr(0), $string); + $string = array_shift($parts); + while (count($parts)) { + $next = array_shift($parts); + if (strpos("0123456789abcdefABCDEF" . chr(9), $next[0]) !== false) { + $string .= " "; + } + $string .= $next; + } + } + } + + return $string; + } + /** * Compiles a primitive value into a CSS property value. * @@ -3895,9 +4154,9 @@ class Compiler * * @api * - * @param array $value + * @param array|Number|string $value * - * @return string|array + * @return string */ public function compileValue($value) { @@ -3905,6 +4164,9 @@ class Compiler switch ($value[0]) { case Type::T_KEYWORD: + if (is_string($value[1])) { + $value[1] = $this->escapeNonPrintableChars($value[1], true); + } return $value[1]; case Type::T_COLOR: @@ -3929,7 +4191,7 @@ class Compiler } if (is_numeric($alpha)) { - $a = new Node\Number($alpha, ''); + $a = new Number($alpha, ''); } else { $a = $alpha; } @@ -3964,19 +4226,25 @@ class Compiler $content = $this->compileStringContent($value); if ($value[1]) { + $content = str_replace('\\', '\\\\', $content); + + $content = $this->escapeNonPrintableChars($content); + // force double quote as string quote for the output in certain cases if ( $value[1] === "'" && - strpos($content, '"') === false && - strpbrk($content, '{}') !== false + (strpos($content, '"') === false or strpos($content, "'") !== false) && + strpbrk($content, '{}\\\'') !== false ) { $value[1] = '"'; + } elseif ( + $value[1] === '"' && + (strpos($content, '"') !== false and strpos($content, "'") === false) + ) { + $value[1] = "'"; } - $content = str_replace( - array('\\a', "\n", "\f" , '\\' , "\r" , $value[1]), - array("\r" , ' ' , '\\f', '\\\\', '\\a', '\\' . $value[1]), - $content - ); + + $content = str_replace($value[1], '\\' . $value[1], $content); } return $value[1] . $content . $value[1]; @@ -4027,10 +4295,26 @@ class Compiler $filtered = []; + $same_string_quote = null; foreach ($items as $item) { + if (\is_null($same_string_quote)) { + $same_string_quote = false; + if ($item[0] === Type::T_STRING) { + $same_string_quote = $item[1]; + foreach ($items as $ii) { + if ($ii[0] !== Type::T_STRING) { + $same_string_quote = false; + break; + } + } + } + } if ($item[0] === Type::T_NULL) { continue; } + if ($same_string_quote === '"' && $item[0] === Type::T_STRING && $item[1]) { + $item[1] = $same_string_quote; + } $compiled = $this->compileValue($item); @@ -4124,7 +4408,7 @@ class Compiler break; case Type::T_STRING: - $reduced = [Type::T_KEYWORD, $this->compileStringContent($reduced)]; + $reduced = [Type::T_STRING, '', [$this->compileStringContent($reduced)]]; break; case Type::T_NULL: @@ -4399,9 +4683,11 @@ class Compiler /** * Convert env linked list to stack * - * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param Environment $env * - * @return array + * @return Environment[] + * + * @phpstan-return non-empty-array */ protected function compactEnv(Environment $env) { @@ -4415,9 +4701,11 @@ class Compiler /** * Convert env stack to singly linked list * - * @param array $envs + * @param Environment[] $envs * - * @return \ScssPhp\ScssPhp\Compiler\Environment + * @return Environment + * + * @phpstan-param non-empty-array $envs */ protected function extractEnv($envs) { @@ -4453,6 +4741,8 @@ class Compiler /** * Pop environment + * + * @return void */ protected function popEnv() { @@ -4463,8 +4753,10 @@ class Compiler /** * Propagate vars from a just poped Env (used in @each and @for) * - * @param array $store - * @param null|array $excludedVars + * @param array $store + * @param null|string[] $excludedVars + * + * @return void */ protected function backPropagateEnv($store, $excludedVars = null) { @@ -4493,6 +4785,8 @@ class Compiler * @param boolean $shadow * @param \ScssPhp\ScssPhp\Compiler\Environment $env * @param mixed $valueUnreduced + * + * @return void */ protected function set($name, $value, $shadow = false, Environment $env = null, $valueUnreduced = null) { @@ -4516,6 +4810,8 @@ class Compiler * @param mixed $value * @param \ScssPhp\ScssPhp\Compiler\Environment $env * @param mixed $valueUnreduced + * + * @return void */ protected function setExisting($name, $value, Environment $env, $valueUnreduced = null) { @@ -4574,6 +4870,8 @@ class Compiler * @param mixed $value * @param \ScssPhp\ScssPhp\Compiler\Environment $env * @param mixed $valueUnreduced + * + * @return void */ protected function setRaw($name, $value, Environment $env, $valueUnreduced = null) { @@ -4670,6 +4968,8 @@ class Compiler * Inject variables * * @param array $args + * + * @return void */ protected function injectVariables(array $args) { @@ -4698,6 +4998,8 @@ class Compiler * @api * * @param array $variables + * + * @return void */ public function setVariables(array $variables) { @@ -4710,6 +5012,8 @@ class Compiler * @api * * @param string $name + * + * @return void */ public function unsetVariable($name) { @@ -4734,6 +5038,8 @@ class Compiler * @api * * @param string $path + * + * @return void */ public function addParsedFile($path) { @@ -4760,6 +5066,8 @@ class Compiler * @api * * @param string|callable $path + * + * @return void */ public function addImportPath($path) { @@ -4773,7 +5081,9 @@ class Compiler * * @api * - * @param string|array $path + * @param string|array $path + * + * @return void */ public function setImportPaths($path) { @@ -4787,6 +5097,8 @@ class Compiler * * @param integer $numberPrecision * + * @return void + * * @deprecated The number precision is not configurable anymore. The default is enough for all browsers. */ public function setNumberPrecision($numberPrecision) @@ -4795,15 +5107,49 @@ class Compiler . 'The default is enough for all browsers.', E_USER_DEPRECATED); } + /** + * Sets the output style. + * + * @api + * + * @param string $style One of the OutputStyle constants + * + * @phpstan-param OutputStyle::* $style + */ + public function setOutputStyle($style) + { + switch ($style) { + case OutputStyle::EXPANDED: + $this->formatter = Expanded::class; + break; + + case OutputStyle::COMPRESSED: + $this->formatter = Compressed::class; + break; + + default: + throw new \InvalidArgumentException(sprintf('Invalid output style "%s".', $style)); + } + } + /** * Set formatter * * @api * * @param string $formatterName + * + * @return void + * + * @deprecated Use {@see setOutputStyle} instead. */ public function setFormatter($formatterName) { + if (!\in_array($formatterName, [Expanded::class, Compressed::class], true)) { + @trigger_error('Formatters other than Expanded and Compressed are deprecated.', E_USER_DEPRECATED); + } + @trigger_error('The method "setFormatter" is deprecated. Use "setOutputStyle" instead.', E_USER_DEPRECATED); + $this->formatter = $formatterName; } @@ -4813,10 +5159,15 @@ class Compiler * @api * * @param string $lineNumberStyle + * + * @return void + * + * @deprecated The line number output is not supported anymore. Use source maps instead. */ public function setLineNumberStyle($lineNumberStyle) { - $this->lineNumberStyle = $lineNumberStyle; + @trigger_error('The line number output is not supported anymore. ' + . 'Use source maps instead.', E_USER_DEPRECATED); } /** @@ -4825,6 +5176,10 @@ class Compiler * @api * * @param integer $sourceMap + * + * @return void + * + * @phpstan-param self::SOURCE_MAP_* $sourceMap */ public function setSourceMap($sourceMap) { @@ -4837,6 +5192,8 @@ class Compiler * @api * * @param array $sourceMapOptions + * + * @return void */ public function setSourceMapOptions($sourceMapOptions) { @@ -4850,7 +5207,9 @@ class Compiler * * @param string $name * @param callable $func - * @param array $prototype + * @param array|null $prototype + * + * @return void */ public function registerFunction($name, $func, $prototype = null) { @@ -4863,6 +5222,8 @@ class Compiler * @api * * @param string $name + * + * @return void */ public function unregisterFunction($name) { @@ -4875,9 +5236,15 @@ class Compiler * @api * * @param string $name + * + * @return void + * + * @deprecated Registering additional features is deprecated. */ public function addFeature($name) { + @trigger_error('Registering additional features is deprecated.', E_USER_DEPRECATED); + $this->registeredFeatures[$name] = true; } @@ -4886,10 +5253,12 @@ class Compiler * * @param string $path * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * + * @return void */ protected function importFile($path, OutputBlock $out) { - $this->pushCallStack('import ' . $path); + $this->pushCallStack('import ' . $this->getPrettyPath($path)); // see if tree is cached $realPath = realpath($path); @@ -4905,11 +5274,11 @@ class Compiler $this->importCache[$realPath] = $tree; } - $pi = pathinfo($path); + $currentDirectory = $this->currentDirectory; + $this->currentDirectory = dirname($path); - array_unshift($this->importPaths, $pi['dirname']); $this->compileChildrenNoReturn($tree->children, $out); - array_shift($this->importPaths); + $this->currentDirectory = $currentDirectory; $this->popCallStack(); } @@ -4924,43 +5293,38 @@ class Compiler */ public function findImport($url) { - $urls = []; - - $hasExtension = preg_match('/[.]s?css$/', $url); - // for "normal" scss imports (ignore vanilla css and external requests) - if (! preg_match('~\.css$|^https?://|^//~', $url)) { - $isPartial = (strpos(basename($url), '_') === 0); + // Callback importers are still called for BC. + if (preg_match('~\.css$|^https?://|^//~', $url)) { + foreach ($this->importPaths as $dir) { + if (\is_string($dir)) { + continue; + } - // try both normal and the _partial filename - $urls = [$url . ($hasExtension ? '' : '.scss')]; + if (\is_callable($dir)) { + // check custom callback for import path + $file = \call_user_func($dir, $url); - if (! $isPartial) { - $urls[] = preg_replace('~[^/]+$~', '_\0', $url) . ($hasExtension ? '' : '.scss'); + if (! \is_null($file)) { + return $file; + } + } } + return null; + } - if (! $hasExtension) { - $urls[] = "$url/index.scss"; - $urls[] = "$url/_index.scss"; - // allow to find a plain css file, *if* no scss or partial scss is found - $urls[] .= $url . '.css'; - } + $relativePath = $this->resolveImportPath($url, $this->currentDirectory); + + if (!\is_null($relativePath)) { + return $relativePath; } foreach ($this->importPaths as $dir) { if (\is_string($dir)) { - // check urls for normal import paths - foreach ($urls as $full) { - $separator = ( - ! empty($dir) && - substr($dir, -1) !== '/' && - substr($full, 0, 1) !== '/' - ) ? '/' : ''; - $full = $dir . $separator . $full; + $path = $this->resolveImportPath($url, $dir); - if (is_file($file = $full)) { - return $file; - } + if (!\is_null($path)) { + return $path; } } elseif (\is_callable($dir)) { // check custom callback for import path @@ -4972,13 +5336,124 @@ class Compiler } } - if ($urls) { - if (! $hasExtension || preg_match('/[.]scss$/', $url)) { - throw $this->error("`$url` file not found for @import"); - } + throw $this->error("`$url` file not found for @import"); + } + + private function resolveImportPath($url, $baseDir) + { + $path = rtrim($baseDir, '/').'/'.ltrim($url, '/'); + + $hasExtension = preg_match('/.scss$/', $url); + + if ($hasExtension) { + return $this->checkImportPathConflicts($this->tryImportPath($path)); } - return null; + $result = $this->checkImportPathConflicts($this->tryImportPathWithExtensions($path)); + + if (!\is_null($result)) { + return $result; + } + + return $this->tryImportPathAsDirectory($path); + } + + /** + * @param string[] $paths + * + * @return string|null + */ + private function checkImportPathConflicts(array $paths) + { + if (\count($paths) === 0) { + return null; + } + + if (\count($paths) === 1) { + return $paths[0]; + } + + $formattedPrettyPaths = []; + + foreach ($paths as $path) { + $formattedPrettyPaths[] = ' ' . $this->getPrettyPath($path); + } + + throw $this->error("It's not clear which file to import. Found:\n" . implode("\n", $formattedPrettyPaths)); + } + + /** + * @param string $path + * + * @return string[] + */ + private function tryImportPathWithExtensions($path) + { + $result = $this->tryImportPath($path.'.scss'); + + if ($result) { + return $result; + } + + return $this->tryImportPath($path.'.css'); + } + + /** + * @param string $path + * + * @return string[] + */ + private function tryImportPath($path) + { + $partial = dirname($path).'/_'.basename($path); + + $candidates = []; + + if (is_file($partial)) { + $candidates[] = $partial; + } + + if (is_file($path)) { + $candidates[] = $path; + } + + return $candidates; + } + + /** + * @param string $path + * + * @return string|null + */ + private function tryImportPathAsDirectory($path) + { + if (!is_dir($path)) { + return null; + } + + return $this->checkImportPathConflicts($this->tryImportPathWithExtensions($path.'/index')); + } + + /** + * @param string $path + * + * @return string + */ + private function getPrettyPath($path) + { + $normalizedPath = $path; + $normalizedRootDirectory = $this->rootDirectory.'/'; + + if (\DIRECTORY_SEPARATOR === '\\') { + $normalizedRootDirectory = str_replace('\\', '/', $normalizedRootDirectory); + $normalizedPath = str_replace('\\', '/', $path); + } + + if (0 === strpos($normalizedPath, $normalizedRootDirectory)) { + return substr($normalizedPath, \strlen($normalizedRootDirectory)); + } + + return $path; } /** @@ -4987,6 +5462,8 @@ class Compiler * @api * * @param string $encoding + * + * @return void */ public function setEncoding($encoding) { @@ -5066,7 +5543,7 @@ class Compiler $column = $this->sourceColumn; $loc = isset($this->sourceNames[$this->sourceIndex]) - ? $this->sourceNames[$this->sourceIndex] . " on line $line, at column $column" + ? $this->getPrettyPath($this->sourceNames[$this->sourceIndex]) . " on line $line, at column $column" : "line: $line, column: $column"; $msg = "$msg: $loc"; @@ -5132,7 +5609,7 @@ class Compiler if ($all || (isset($call['n']) && $call['n'])) { $msg = '#' . $ncall++ . ' ' . $call['n'] . ' '; $msg .= (isset($this->sourceNames[$call[Parser::SOURCE_INDEX]]) - ? $this->sourceNames[$call[Parser::SOURCE_INDEX]] + ? $this->getPrettyPath($this->sourceNames[$call[Parser::SOURCE_INDEX]]) : '(unknown file)'); $msg .= ' on line ' . $call[Parser::SOURCE_LINE]; @@ -5176,7 +5653,7 @@ class Compiler * @param Object $func * @param array $argValues * - * @return array $returnValue + * @return array */ protected function callScssFunction($func, $argValues) { @@ -5220,7 +5697,7 @@ class Compiler * @param array $prototype * @param array $args * - * @return array + * @return array|Number|null */ protected function callNativeFunction($name, $function, $prototype, $args) { @@ -5232,7 +5709,7 @@ class Compiler } @list($sorted, $kwargs) = $sorted_kwargs; - if ($name !== 'if' && $name !== 'call') { + if ($name !== 'if') { $inExp = true; if ($name === 'join') { @@ -5262,6 +5739,18 @@ class Compiler */ protected function getBuiltinFunction($name) { + $libName = self::normalizeNativeFunctionName($name); + return [$this, $libName]; + } + + /** + * Normalize native function name + * @param string $name + * @return string + */ + public static function normalizeNativeFunctionName($name) + { + $name = str_replace("-", "_", $name); $libName = 'lib' . preg_replace_callback( '/_(.)/', function ($m) { @@ -5269,8 +5758,17 @@ class Compiler }, ucfirst($name) ); + return $libName; + } - return [$this, $libName]; + /** + * Check if a function is a native built-in scss function, for css parsing + * @param string $name + * @return bool + */ + public static function isNativeFunction($name) + { + return method_exists(Compiler::class, self::normalizeNativeFunctionName($name)); } /** @@ -5644,7 +6142,7 @@ class Compiler * * @param mixed $value * - * @return array|\ScssPhp\ScssPhp\Node\Number + * @return array|Number */ protected function coerceValue($value) { @@ -5661,7 +6159,7 @@ class Compiler } if (is_numeric($value)) { - return new Node\Number($value, ''); + return new Number($value, ''); } if ($value === '') { @@ -5681,9 +6179,9 @@ class Compiler /** * Coerce something to map * - * @param array $item + * @param array|Number $item * - * @return array + * @return array|Number */ protected function coerceMap($item) { @@ -5759,9 +6257,9 @@ class Compiler /** * Coerce color for expression * - * @param array $value + * @param array|Number $value * - * @return array|null + * @return array|Number */ protected function coerceForExpression($value) { @@ -5775,7 +6273,8 @@ class Compiler /** * Coerce value to color * - * @param array $value + * @param array|Number $value + * @param bool $inRGBFunction * * @return array|null */ @@ -5866,7 +6365,7 @@ class Compiler if ($color[3] === 255) { $color[3] = 1; // fully opaque } else { - $color[3] = round($color[3] / 255, Node\Number::PRECISION); + $color[3] = round($color[3] / 255, Number::PRECISION); } } @@ -5889,8 +6388,8 @@ class Compiler } /** - * @param integer|\ScssPhp\ScssPhp\Node\Number $value - * @param boolean $isAlpha + * @param integer|Number $value + * @param boolean $isAlpha * * @return integer|mixed */ @@ -5908,36 +6407,27 @@ class Compiler * @param integer|float $min * @param integer|float $max * @param boolean $isInt - * @param boolean $clamp - * @param boolean $modulo * * @return integer|mixed */ - protected function compileColorPartValue($value, $min, $max, $isInt = true, $clamp = true, $modulo = false) + protected function compileColorPartValue($value, $min, $max, $isInt = true) { if (! is_numeric($value)) { if (\is_array($value)) { $reduced = $this->reduce($value); - if (\is_object($reduced) && $value->type === Type::T_NUMBER) { + if ($reduced instanceof Number) { $value = $reduced; } } - if (\is_object($value) && $value->type === Type::T_NUMBER) { - $num = $value->dimension; - - if (\count($value->units)) { - $unit = array_keys($value->units); - $unit = reset($unit); - - switch ($unit) { - case '%': - $num *= $max / 100; - break; - default: - break; - } + if ($value instanceof Number) { + if ($value->unitless()) { + $num = $value->getDimension(); + } elseif ($value->hasUnit('%')) { + $num = $max * $value->getDimension() / 100; + } else { + throw $this->error('Expected %s to have no units or "%%".', $value); } $value = $num; @@ -5951,18 +6441,7 @@ class Compiler $value = round($value); } - if ($clamp) { - $value = min($max, max($min, $value)); - } - - if ($modulo) { - $value = $value % $max; - - // still negative? - while ($value < $min) { - $value += $max; - } - } + $value = min($max, max($min, $value)); return $value; } @@ -5973,9 +6452,9 @@ class Compiler /** * Coerce value to string * - * @param array $value + * @param array|Number $value * - * @return array|null + * @return array */ protected function coerceString($value) { @@ -5986,21 +6465,51 @@ class Compiler return [Type::T_STRING, '', [$this->compileValue($value)]]; } + /** + * Assert value is a string (or keyword) + * + * @api + * + * @param array|Number $value + * @param string $varName + * + * @return array + * + * @throws \Exception + */ + public function assertString($value, $varName = null) + { + // case of url(...) parsed a a function + if ($value[0] === Type::T_FUNCTION) { + $value = $this->coerceString($value); + } + + if (! \in_array($value[0], [Type::T_STRING, Type::T_KEYWORD])) { + $value = $this->compileValue($value); + $var_display = ($varName ? " \${$varName}:" : ''); + throw $this->error("Error:{$var_display} $value is not a string."); + } + + $value = $this->coerceString($value); + + return $value; + } + /** * Coerce value to a percentage * - * @param array $value + * @param array|Number $value * * @return integer|float */ protected function coercePercent($value) { - if ($value[0] === Type::T_NUMBER) { - if (! empty($value[2]['%'])) { - return $value[1] / 100; + if ($value instanceof Number) { + if ($value->hasUnit('%')) { + return $value->getDimension() / 100; } - return $value[1]; + return $value->getDimension(); } return 0; @@ -6011,7 +6520,7 @@ class Compiler * * @api * - * @param array $value + * @param array|Number $value * * @return array * @@ -6033,7 +6542,7 @@ class Compiler * * @api * - * @param array $value + * @param array|Number $value * * @return array * @@ -6053,7 +6562,7 @@ class Compiler * * @api * - * @param array $value + * @param array|Number $value * * @return array * @@ -6073,21 +6582,49 @@ class Compiler * * @api * - * @param array $value + * @param array|Number $value + * @param string $varName * - * @return integer|float + * @return Number * * @throws \Exception */ - public function assertNumber($value) + public function assertNumber($value, $varName = null) { - if ($value[0] !== Type::T_NUMBER) { - throw $this->error('expecting number, %s received', $value[0]); + if (!$value instanceof Number) { + $value = $this->compileValue($value); + $var_display = ($varName ? " \${$varName}:" : ''); + throw $this->error("Error:{$var_display} $value is not a number."); } - return $value[1]; + return $value; } + /** + * Assert value is a integer + * + * @api + * + * @param array|Number $value + * @param string $varName + * + * @return integer + * + * @throws \Exception + */ + public function assertInteger($value, $varName = null) + { + + $value = $this->assertNumber($value, $varName)->getDimension(); + if (round($value - \intval($value), Number::PRECISION) > 0) { + $var_display = ($varName ? " \${$varName}:" : ''); + throw $this->error("Error:{$var_display} $value is not an integer."); + } + + return intval($value); + } + + /** * Make sure a color's components don't go out of bounds * @@ -6217,13 +6754,13 @@ class Compiler // Built in functions - protected static $libCall = ['name', 'args...']; + protected static $libCall = ['function', 'args...']; protected function libCall($args, $kwargs) { - $functionReference = $this->reduce(array_shift($args), true); + $functionReference = array_shift($args); if (in_array($functionReference[0], [Type::T_STRING, Type::T_KEYWORD])) { - $name = $this->compileStringContent($this->coerceString($this->reduce($functionReference, true))); + $name = $this->compileStringContent($this->coerceString($functionReference)); $warning = "DEPRECATION WARNING: Passing a string to call() is deprecated and will be illegal\n" . "in Sass 4.0. Use call(function-reference($name)) instead."; fwrite($this->stderr, "$warning\n\n"); @@ -6261,11 +6798,11 @@ class Compiler ]; protected function libGetFunction($args) { - $name = $this->compileStringContent($this->coerceString($this->reduce(array_shift($args), true))); + $name = $this->compileStringContent($this->coerceString(array_shift($args))); $isCss = false; if (count($args)) { - $isCss = $this->reduce(array_shift($args), true); + $isCss = array_shift($args); $isCss = (($isCss === static::$true) ? true : false); } @@ -6306,8 +6843,25 @@ class Compiler return static::$null; } + // Numbers are represented with value objects, for which the PHP equality operator does not + // match the Sass rules (and we cannot overload it). As they are the only type of values + // represented with a value object for now, they require a special case. + if ($value instanceof Number) { + $key = 0; + foreach ($list[2] as $item) { + $key++; + $itemValue = $this->normalizeValue($item); + + if ($itemValue instanceof Number && $value->equals($itemValue)) { + return new Number($key, ''); + } + } + return static::$null; + } + $values = []; + foreach ($list[2] as $item) { $values[] = $this->normalizeValue($item); } @@ -6381,14 +6935,21 @@ class Compiler return $this->libRgb($args, $kwargs, 'rgba'); } - // helper function for adjust_color, change_color, and scale_color + /** + * Helper function for adjust_color, change_color, and scale_color + * + * @param array $args + * @param callable $fn + * + * @return array + */ protected function alterColor($args, $fn) { $color = $this->assertColor($args[0]); foreach ([1 => 1, 2 => 2, 3 => 3, 7 => 4] as $iarg => $irgba) { if (isset($args[$iarg])) { - $val = $this->assertNumber($args[$iarg]); + $val = $this->assertNumber($args[$iarg])->getDimension(); if (! isset($color[$irgba])) { $color[$irgba] = (($irgba < 4) ? 0 : 1); @@ -6403,7 +6964,7 @@ class Compiler foreach ([4 => 1, 5 => 2, 6 => 3] as $iarg => $ihsl) { if (! empty($args[$iarg])) { - $val = $this->assertNumber($args[$iarg]); + $val = $this->assertNumber($args[$iarg])->getDimension(); $hsl[$ihsl] = \call_user_func($fn, $hsl[$ihsl], $val, $iarg); } } @@ -6487,7 +7048,7 @@ class Compiler $color = $this->coerceColor($args[0]); if (\is_null($color)) { - $this->throwError('Error: argument `$color` of `ie-hex-str($color)` must be a color'); + throw $this->error('Error: argument `$color` of `ie-hex-str($color)` must be a color'); } $color[4] = isset($color[4]) ? round(255 * $color[4]) : 255; @@ -6501,7 +7062,7 @@ class Compiler $color = $this->coerceColor($args[0]); if (\is_null($color)) { - $this->throwError('Error: argument `$color` of `red($color)` must be a color'); + throw $this->error('Error: argument `$color` of `red($color)` must be a color'); } return $color[1]; @@ -6513,7 +7074,7 @@ class Compiler $color = $this->coerceColor($args[0]); if (\is_null($color)) { - $this->throwError('Error: argument `$color` of `green($color)` must be a color'); + throw $this->error('Error: argument `$color` of `green($color)` must be a color'); } return $color[2]; @@ -6525,7 +7086,7 @@ class Compiler $color = $this->coerceColor($args[0]); if (\is_null($color)) { - $this->throwError('Error: argument `$color` of `blue($color)` must be a color'); + throw $this->error('Error: argument `$color` of `blue($color)` must be a color'); } return $color[3]; @@ -6547,7 +7108,7 @@ class Compiler { $value = $args[0]; - if ($value[0] === Type::T_NUMBER) { + if ($value instanceof Number) { return null; } @@ -6611,10 +7172,6 @@ class Compiler $args_to_check = $kwargs['channels'][2]; } - $hue = $this->compileColorPartValue($args[0], 0, 360, false, false, true); - $saturation = $this->compileColorPartValue($args[1], 0, 100, false); - $lightness = $this->compileColorPartValue($args[2], 0, 100, false); - foreach ($kwargs as $k => $arg) { if (in_array($arg[0], [Type::T_FUNCTION_CALL]) && in_array($arg[1], ['min', 'max'])) { return null; @@ -6628,7 +7185,6 @@ class Compiler } $args[$k] = $this->stringifyFncallArgs($arg); - $hue = ''; } if ( @@ -6640,22 +7196,31 @@ class Compiler } } + $hue = $this->reduce($args[0]); + $saturation = $this->reduce($args[1]); + $lightness = $this->reduce($args[2]); $alpha = null; if (\count($args) === 4) { $alpha = $this->compileColorPartValue($args[3], 0, 100, false); - if (! is_numeric($hue) || ! is_numeric($saturation) || ! is_numeric($lightness) || ! is_numeric($alpha)) { + if (!$hue instanceof Number || !$saturation instanceof Number || ! $lightness instanceof Number || ! is_numeric($alpha)) { return [Type::T_STRING, '', [$funcName . '(', $args[0], ', ', $args[1], ', ', $args[2], ', ', $args[3], ')']]; } } else { - if (! is_numeric($hue) || ! is_numeric($saturation) || ! is_numeric($lightness)) { + if (!$hue instanceof Number || !$saturation instanceof Number || ! $lightness instanceof Number) { return [Type::T_STRING, '', [$funcName . '(', $args[0], ', ', $args[1], ', ', $args[2], ')']]; } } - $color = $this->toRGB($hue, $saturation, $lightness); + $hueValue = $hue->getDimension() % 360; + + while ($hueValue < 0) { + $hueValue += 360; + } + + $color = $this->toRGB($hueValue, max(0, min($saturation->getDimension(), 100)), max(0, min($lightness->getDimension(), 100))); if (! \is_null($alpha)) { $color[4] = $alpha; @@ -6679,7 +7244,7 @@ class Compiler $color = $this->assertColor($args[0]); $hsl = $this->toHSL($color[1], $color[2], $color[3]); - return new Node\Number($hsl[1], 'deg'); + return new Number($hsl[1], 'deg'); } protected static $libSaturation = ['color']; @@ -6688,7 +7253,7 @@ class Compiler $color = $this->assertColor($args[0]); $hsl = $this->toHSL($color[1], $color[2], $color[3]); - return new Node\Number($hsl[2], '%'); + return new Number($hsl[2], '%'); } protected static $libLightness = ['color']; @@ -6697,7 +7262,7 @@ class Compiler $color = $this->assertColor($args[0]); $hsl = $this->toHSL($color[1], $color[2], $color[3]); - return new Node\Number($hsl[3], '%'); + return new Number($hsl[3], '%'); } protected function adjustHsl($color, $idx, $amount) @@ -6717,7 +7282,7 @@ class Compiler protected function libAdjustHue($args) { $color = $this->assertColor($args[0]); - $degrees = $this->assertNumber($args[1]); + $degrees = $this->assertNumber($args[1])->getDimension(); return $this->adjustHsl($color, 1, $degrees); } @@ -6745,7 +7310,7 @@ class Compiler { $value = $args[0]; - if ($value[0] === Type::T_NUMBER) { + if ($value instanceof Number) { return null; } @@ -6774,7 +7339,7 @@ class Compiler { $value = $args[0]; - if ($value[0] === Type::T_NUMBER) { + if ($value instanceof Number) { return null; } @@ -6798,7 +7363,7 @@ class Compiler $weight = $this->coercePercent($weight); } - if ($value[0] === Type::T_NUMBER) { + if ($value instanceof Number) { return null; } @@ -6809,7 +7374,7 @@ class Compiler $inverted[3] = 255 - $inverted[3]; if ($weight < 1) { - return $this->libMix([$inverted, $color, [Type::T_NUMBER, $weight]]); + return $this->libMix([$inverted, $color, new Number($weight, '')]); } return $inverted; @@ -6871,6 +7436,7 @@ class Compiler $value = $args[0]; if ($value[0] === Type::T_STRING && ! empty($value[1])) { + $value[1] = '"'; return $value; } @@ -6880,118 +7446,86 @@ class Compiler protected static $libPercentage = ['number']; protected function libPercentage($args) { - return new Node\Number($this->coercePercent($args[0]) * 100, '%'); + $num = $this->assertNumber($args[0], 'number'); + $num->assertNoUnits('number'); + + return new Number($num->getDimension() * 100, '%'); } protected static $libRound = ['number']; protected function libRound($args) { - $num = $args[0]; + $num = $this->assertNumber($args[0], 'number'); - return new Node\Number(round($num[1]), $num[2]); + return new Number(round($num->getDimension()), $num->getNumeratorUnits(), $num->getDenominatorUnits()); } protected static $libFloor = ['number']; protected function libFloor($args) { - $num = $args[0]; + $num = $this->assertNumber($args[0], 'number'); - return new Node\Number(floor($num[1]), $num[2]); + return new Number(floor($num->getDimension()), $num->getNumeratorUnits(), $num->getDenominatorUnits()); } protected static $libCeil = ['number']; protected function libCeil($args) { - $num = $args[0]; + $num = $this->assertNumber($args[0], 'number'); - return new Node\Number(ceil($num[1]), $num[2]); + return new Number(ceil($num->getDimension()), $num->getNumeratorUnits(), $num->getDenominatorUnits()); } protected static $libAbs = ['number']; protected function libAbs($args) { - $num = $args[0]; + $num = $this->assertNumber($args[0], 'number'); - return new Node\Number(abs($num[1]), $num[2]); + return new Number(abs($num->getDimension()), $num->getNumeratorUnits(), $num->getDenominatorUnits()); } protected function libMin($args) { - $numbers = $this->getNormalizedNumbers($args); - $minOriginal = null; - $minNormalized = null; + /** + * @var Number|null + */ + $min = null; - foreach ($numbers as $key => $pair) { - list($original, $normalized) = $pair; + foreach ($args as $arg) { + $number = $this->assertNumber($arg); - if (\is_null($normalized) || \is_null($minNormalized)) { - if (\is_null($minOriginal) || $original[1] <= $minOriginal[1]) { - $minOriginal = $original; - $minNormalized = $normalized; - } - } elseif ($normalized[1] <= $minNormalized[1]) { - $minOriginal = $original; - $minNormalized = $normalized; + if (\is_null($min) || $min->greaterThan($number)) { + $min = $number; } } - return $minOriginal; + if (!\is_null($min)) { + return $min; + } + + throw $this->error('At least one argument must be passed.'); } protected function libMax($args) { - $numbers = $this->getNormalizedNumbers($args); - $maxOriginal = null; - $maxNormalized = null; + /** + * @var Number|null + */ + $max = null; - foreach ($numbers as $key => $pair) { - list($original, $normalized) = $pair; + foreach ($args as $arg) { + $number = $this->assertNumber($arg); - if (\is_null($normalized) || \is_null($maxNormalized)) { - if (\is_null($maxOriginal) || $original[1] >= $maxOriginal[1]) { - $maxOriginal = $original; - $maxNormalized = $normalized; - } - } elseif ($normalized[1] >= $maxNormalized[1]) { - $maxOriginal = $original; - $maxNormalized = $normalized; + if (\is_null($max) || $max->lessThan($number)) { + $max = $number; } } - return $maxOriginal; - } - - /** - * Helper to normalize args containing numbers - * - * @param array $args - * - * @return array - */ - protected function getNormalizedNumbers($args) - { - $unit = null; - $originalUnit = null; - $numbers = []; - - foreach ($args as $key => $item) { - if ($item[0] !== Type::T_NUMBER) { - throw $this->error('%s is not a number', $item[0]); - } - - $number = $item->normalize(); - - if (empty($unit)) { - $unit = $number[2]; - $originalUnit = $item->unitStr(); - } elseif ($number[1] && $unit !== $number[2] && ! empty($number[2])) { - throw $this->error('Incompatible units: "%s" and "%s".', $originalUnit, $item->unitStr()); - } - - $numbers[$key] = [$args[$key], empty($number[2]) ? null : $number]; + if (!\is_null($max)) { + return $max; } - return $numbers; + throw $this->error('At least one argument must be passed.'); } protected static $libLength = ['list']; @@ -7009,9 +7543,13 @@ class Compiler return 'comma'; } + if (! \in_array($args[0][0], [Type::T_LIST, Type::T_MAP])) { + return 'space'; + } + $list = $this->coerceList($args[0]); - if (\count($list[2]) <= 1) { + if (\count($list[2]) <= 1 && empty($list['enclosing'])) { return 'space'; } @@ -7026,7 +7564,7 @@ class Compiler protected function libNth($args) { $list = $this->coerceList($args[0], ',', false); - $n = $this->assertNumber($args[1]); + $n = $this->assertNumber($args[1])->getDimension(); if ($n > 0) { $n--; @@ -7041,7 +7579,7 @@ class Compiler protected function libSetNth($args) { $list = $this->coerceList($args[0]); - $n = $this->assertNumber($args[1]); + $n = $this->assertNumber($args[1])->getDimension(); if ($n > 0) { $n--; @@ -7187,6 +7725,13 @@ class Compiler return false; } + /** + * @param array $list1 + * @param array|Number|null $sep + * + * @return string + * @throws CompilerException + */ protected function listSeparatorForJoin($list1, $sep) { if (! isset($sep)) { @@ -7277,21 +7822,28 @@ class Compiler $lists = []; $firstList = array_shift($args); - foreach ($firstList[2] as $key => $item) { - $list = [Type::T_LIST, '', [$item]]; + $result = [Type::T_LIST, ',', $lists]; + if (! \is_null($firstList)) { + foreach ($firstList[2] as $key => $item) { + $list = [Type::T_LIST, '', [$item]]; - foreach ($args as $arg) { - if (isset($arg[2][$key])) { - $list[2][] = $arg[2][$key]; - } else { - break 2; + foreach ($args as $arg) { + if (isset($arg[2][$key])) { + $list[2][] = $arg[2][$key]; + } else { + break 2; + } } + + $lists[] = $list; } - $lists[] = $list; + $result[2] = $lists; + } else { + $result['enclosing'] = 'parent'; } - return [Type::T_LIST, ',', $lists]; + return $result; } protected static $libTypeOf = ['value']; @@ -7332,7 +7884,7 @@ class Compiler { $num = $args[0]; - if ($num[0] === Type::T_NUMBER) { + if ($num instanceof Number) { return [Type::T_STRING, '"', [$num->unitStr()]]; } @@ -7344,7 +7896,7 @@ class Compiler { $value = $args[0]; - return $value[0] === Type::T_NUMBER && $value->unitless(); + return $value instanceof Number && $value->unitless(); } protected static $libComparable = [ @@ -7356,44 +7908,55 @@ class Compiler list($number1, $number2) = $args; if ( - ! isset($number1[0]) || $number1[0] !== Type::T_NUMBER || - ! isset($number2[0]) || $number2[0] !== Type::T_NUMBER + ! $number1 instanceof Number || + ! $number2 instanceof Number ) { throw $this->error('Invalid argument(s) for "comparable"'); } - $number1 = $number1->normalize(); - $number2 = $number2->normalize(); - - return $number1[2] === $number2[2] || $number1->unitless() || $number2->unitless(); + return $number1->isComparableTo($number2); } protected static $libStrIndex = ['string', 'substring']; protected function libStrIndex($args) { - $string = $this->coerceString($args[0]); + $string = $this->assertString($args[0], 'string'); $stringContent = $this->compileStringContent($string); - $substring = $this->coerceString($args[1]); + $substring = $this->assertString($args[1], 'substring'); $substringContent = $this->compileStringContent($substring); - $result = strpos($stringContent, $substringContent); + if (! \strlen($substringContent)) { + $result = 0; + } else { + $result = Util::mbStrpos($stringContent, $substringContent); + } - return $result === false ? static::$null : new Node\Number($result + 1, ''); + return $result === false ? static::$null : new Number($result + 1, ''); } protected static $libStrInsert = ['string', 'insert', 'index']; protected function libStrInsert($args) { - $string = $this->coerceString($args[0]); + $string = $this->assertString($args[0], 'string'); $stringContent = $this->compileStringContent($string); - $insert = $this->coerceString($args[1]); + $insert = $this->assertString($args[1], 'insert'); $insertContent = $this->compileStringContent($insert); - list(, $index) = $args[2]; + $index = $this->assertInteger($args[2], 'index'); + if ($index > 0) { + $index = $index - 1; + } + if ($index < 0) { + $index = Util::mbStrlen($stringContent) + 1 + $index; + } - $string[2] = [substr_replace($stringContent, $insertContent, $index - 1, 0)]; + $string[2] = [ + Util::mbSubstr($stringContent, 0, $index), + $insertContent, + Util::mbSubstr($stringContent, $index) + ]; return $string; } @@ -7401,10 +7964,10 @@ class Compiler protected static $libStrLength = ['string']; protected function libStrLength($args) { - $string = $this->coerceString($args[0]); + $string = $this->assertString($args[0], 'string'); $stringContent = $this->compileStringContent($string); - return new Node\Number(\strlen($stringContent), ''); + return new Number(Util::mbStrlen($stringContent), ''); } protected static $libStrSlice = ['string', 'start-at', 'end-at:-1']; @@ -7439,7 +8002,7 @@ class Compiler $string = $this->coerceString($args[0]); $stringContent = $this->compileStringContent($string); - $string[2] = [\function_exists('mb_strtolower') ? mb_strtolower($stringContent) : strtolower($stringContent)]; + $string[2] = [$this->stringTransformAsciiOnly($stringContent, 'strtolower')]; return $string; } @@ -7450,11 +8013,38 @@ class Compiler $string = $this->coerceString($args[0]); $stringContent = $this->compileStringContent($string); - $string[2] = [\function_exists('mb_strtoupper') ? mb_strtoupper($stringContent) : strtoupper($stringContent)]; + $string[2] = [$this->stringTransformAsciiOnly($stringContent, 'strtoupper')]; return $string; } + /** + * Apply a filter on a string content, only on ascii chars + * let extended chars untouched + * + * @param string $stringContent + * @param string $filter + * @return string + */ + protected function stringTransformAsciiOnly($stringContent, $filter) + { + $mblength = Util::mbStrlen($stringContent); + if ($mblength === strlen($stringContent)) { + return $filter($stringContent); + } + $filteredString = ""; + for ($i = 0; $i < $mblength; $i++) { + $char = Util::mbSubstr($stringContent, $i, 1); + if (strlen($char) > 1) { + $filteredString .= $char; + } else { + $filteredString .= $filter($char); + } + } + + return $filteredString; + } + protected static $libFeatureExists = ['feature']; protected function libFeatureExists($args) { @@ -7530,24 +8120,25 @@ class Compiler return [Type::T_STRING, '', ['counter(' . implode(',', $list) . ')']]; } - protected static $libRandom = ['limit:1']; + protected static $libRandom = ['limit:null']; protected function libRandom($args) { - if (isset($args[0])) { - $n = $this->assertNumber($args[0]); + if (isset($args[0]) & $args[0] !== static::$null) { + $n = $this->assertNumber($args[0])->getDimension(); if ($n < 1) { throw $this->error("\$limit must be greater than or equal to 1"); } - if ($n - \intval($n) > 0) { + if (round($n - \intval($n), Number::PRECISION) > 0) { throw $this->error("Expected \$limit to be an integer but got $n for `random`"); } - return new Node\Number(mt_rand(1, \intval($n)), ''); + return new Number(mt_rand(1, \intval($n)), ''); } - return new Node\Number(mt_rand(1, mt_getrandmax()), ''); + $max = mt_getrandmax(); + return new Number(mt_rand(0, $max - 1) / $max, ''); } protected function libUniqueId() @@ -7615,7 +8206,7 @@ class Compiler * * @return array|boolean */ - protected function getSelectorArg($arg) + protected function getSelectorArg($arg, $varname = null, $allowParent = false) { static $parser = null; @@ -7623,19 +8214,60 @@ class Compiler $parser = $this->parserFactory(__METHOD__); } + if (! $this->checkSelectorArgType($arg)) { + $var_display = ($varname ? ' $' . $varname . ':' : ''); + $var_value = $this->compileValue($arg); + throw $this->error("Error:{$var_display} $var_value is not a valid selector: it must be a string," + . " a list of strings, or a list of lists of strings"); + } + $arg = $this->libUnquote([$arg]); $arg = $this->compileValue($arg); $parsedSelector = []; - if ($parser->parseSelector($arg, $parsedSelector)) { + if ($parser->parseSelector($arg, $parsedSelector, true)) { $selector = $this->evalSelectors($parsedSelector); $gluedSelector = $this->glueFunctionSelectors($selector); + if (! $allowParent) { + foreach ($gluedSelector as $selector) { + foreach ($selector as $s) { + if (in_array(static::$selfSelector, $s)) { + $var_display = ($varname ? ' $' . $varname . ':' : ''); + throw $this->error("Error:{$var_display} Parent selectors aren't allowed here."); + } + } + } + } + return $gluedSelector; } - return false; + $var_display = ($varname ? ' $' . $varname . ':' : ''); + throw $this->error("Error:{$var_display} expected more input, invalid selector."); + } + + /** + * Check variable type for getSelectorArg() function + * @param array $arg + * @param int $maxDepth + * @return bool + */ + protected function checkSelectorArgType($arg, $maxDepth = 2) + { + if ($arg[0] === Type::T_LIST && $maxDepth > 0) { + foreach ($arg[2] as $elt) { + if (! $this->checkSelectorArgType($elt, $maxDepth - 1)) { + return false; + } + } + return true; + } + if (!in_array($arg[0], [Type::T_STRING, Type::T_KEYWORD])) { + return false; + } + return true; } /** @@ -7657,8 +8289,8 @@ class Compiler { list($super, $sub) = $args; - $super = $this->getSelectorArg($super); - $sub = $this->getSelectorArg($sub); + $super = $this->getSelectorArg($super, 'super'); + $sub = $this->getSelectorArg($sub, 'sub'); return $this->isSuperSelector($super, $sub); } @@ -7674,14 +8306,32 @@ class Compiler protected function isSuperSelector($super, $sub) { // one and only one selector for each arg - if (! $super || \count($super) !== 1) { + if (! $super) { throw $this->error('Invalid super selector for isSuperSelector()'); } - if (! $sub || \count($sub) !== 1) { + if (! $sub) { throw $this->error('Invalid sub selector for isSuperSelector()'); } + if (count($sub) > 1) { + foreach ($sub as $s) { + if (! $this->isSuperSelector($super, [$s])) { + return false; + } + } + return true; + } + + if (count($super) > 1) { + foreach ($super as $s) { + if ($this->isSuperSelector([$s], $sub)) { + return true; + } + } + return false; + } + $super = reset($super); $sub = reset($sub); @@ -7764,7 +8414,10 @@ class Compiler throw $this->error('selector-append() needs at least 1 argument'); } - $selectors = array_map([$this, 'getSelectorArg'], $args); + $selectors = []; + foreach ($args as $arg) { + $selectors[] = $this->getSelectorArg($arg, 'selector'); + } return $this->formatOutputSelector($this->selectorAppend($selectors)); } @@ -7828,9 +8481,9 @@ class Compiler { list($selectors, $extendee, $extender) = $args; - $selectors = $this->getSelectorArg($selectors); - $extendee = $this->getSelectorArg($extendee); - $extender = $this->getSelectorArg($extender); + $selectors = $this->getSelectorArg($selectors, 'selector'); + $extendee = $this->getSelectorArg($extendee, 'extendee'); + $extender = $this->getSelectorArg($extender, 'extender'); if (! $selectors || ! $extendee || ! $extender) { throw $this->error('selector-extend() invalid arguments'); @@ -7849,9 +8502,9 @@ class Compiler { list($selectors, $original, $replacement) = $args; - $selectors = $this->getSelectorArg($selectors); - $original = $this->getSelectorArg($original); - $replacement = $this->getSelectorArg($replacement); + $selectors = $this->getSelectorArg($selectors, 'selector'); + $original = $this->getSelectorArg($original, 'original'); + $replacement = $this->getSelectorArg($replacement, 'replacement'); if (! $selectors || ! $original || ! $replacement) { throw $this->error('selector-replace() invalid arguments'); @@ -7920,7 +8573,11 @@ class Compiler throw $this->error('selector-nest() needs at least 1 argument'); } - $selectorsMap = array_map([$this, 'getSelectorArg'], $args); + $selectorsMap = []; + foreach ($args as $arg) { + $selectorsMap[] = $this->getSelectorArg($arg, 'selector', true); + } + $envs = []; foreach ($selectorsMap as $selectors) { @@ -7944,7 +8601,7 @@ class Compiler protected function libSelectorParse($args) { $selectors = reset($args); - $selectors = $this->getSelectorArg($selectors); + $selectors = $this->getSelectorArg($selectors, 'selector'); return $this->formatOutputSelector($selectors); } @@ -7954,8 +8611,8 @@ class Compiler { list($selectors1, $selectors2) = $args; - $selectors1 = $this->getSelectorArg($selectors1); - $selectors2 = $this->getSelectorArg($selectors2); + $selectors1 = $this->getSelectorArg($selectors1, 'selectors1'); + $selectors2 = $this->getSelectorArg($selectors2, 'selectors2'); if (! $selectors1 || ! $selectors2) { throw $this->error('selector-unify() invalid arguments'); @@ -8094,7 +8751,7 @@ class Compiler * @param array $part * @param array $compound * - * @return array|boolean + * @return array|false */ protected function matchPartInCompound($part, $compound) { @@ -8189,7 +8846,7 @@ class Compiler * @param string $tag1 * @param string $tag2 * - * @return array|boolean + * @return array|false */ protected function checkCompatibleTags($tag1, $tag2) { @@ -8231,7 +8888,7 @@ class Compiler protected function libSimpleSelectors($args) { $selector = reset($args); - $selector = $this->getSelectorArg($selector); + $selector = $this->getSelectorArg($selector, 'selector'); // remove selectors list layer, keeping the first one $selector = reset($selector); diff --git a/vendor/scssphp/scssphp/src/Exception/SassScriptException.php b/vendor/scssphp/scssphp/src/Exception/SassScriptException.php new file mode 100644 index 00000000..19356a7a --- /dev/null +++ b/vendor/scssphp/scssphp/src/Exception/SassScriptException.php @@ -0,0 +1,32 @@ +sourceMapGenerator) { - $this->sourceMapGenerator->addMapping( - $this->currentLine, - $this->currentColumn, - $this->currentBlock->sourceLine, - //columns from parser are off by one - $this->currentBlock->sourceColumn > 0 ? $this->currentBlock->sourceColumn - 1 : 0, - $this->currentBlock->sourceName - ); - $lines = explode("\n", $str); - $lineCount = \count($lines); - $this->currentLine += $lineCount - 1; - $lastLine = array_pop($lines); - $this->currentColumn = ($lineCount === 1 ? $this->currentColumn : 0) + \strlen($lastLine); + foreach ($lines as $line) { + // If the written line starts is empty, adding a mapping would add it for + // a non-existent column as we are at the end of the line + if ($line !== '') { + $this->sourceMapGenerator->addMapping( + $this->currentLine, + $this->currentColumn, + $this->currentBlock->sourceLine, + //columns from parser are off by one + $this->currentBlock->sourceColumn > 0 ? $this->currentBlock->sourceColumn - 1 : 0, + $this->currentBlock->sourceName + ); + } + + $this->currentLine++; + $this->currentColumn = 0; + } + + if ($lastLine !== '') { + $this->sourceMapGenerator->addMapping( + $this->currentLine, + $this->currentColumn, + $this->currentBlock->sourceLine, + //columns from parser are off by one + $this->currentBlock->sourceColumn > 0 ? $this->currentBlock->sourceColumn - 1 : 0, + $this->currentBlock->sourceName + ); + } + + $this->currentColumn = \strlen($lastLine); } echo $str; diff --git a/vendor/scssphp/scssphp/src/Formatter/Compact.php b/vendor/scssphp/scssphp/src/Formatter/Compact.php index 98009b41..249920ef 100644 --- a/vendor/scssphp/scssphp/src/Formatter/Compact.php +++ b/vendor/scssphp/scssphp/src/Formatter/Compact.php @@ -18,6 +18,8 @@ use ScssPhp\ScssPhp\Formatter; * Compact formatter * * @author Leaf Corcoran + * + * @deprecated since 1.4.0. Use the Compressed formatter instead. */ class Compact extends Formatter { @@ -26,6 +28,8 @@ class Compact extends Formatter */ public function __construct() { + @trigger_error('The Compact formatter is deprecated since 1.4.0. Use the Compressed formatter instead.', E_USER_DEPRECATED); + $this->indentLevel = 0; $this->indentChar = ''; $this->break = ''; diff --git a/vendor/scssphp/scssphp/src/Formatter/Compressed.php b/vendor/scssphp/scssphp/src/Formatter/Compressed.php index 3fdb97a4..d666a665 100644 --- a/vendor/scssphp/scssphp/src/Formatter/Compressed.php +++ b/vendor/scssphp/scssphp/src/Formatter/Compressed.php @@ -13,7 +13,6 @@ namespace ScssPhp\ScssPhp\Formatter; use ScssPhp\ScssPhp\Formatter; -use ScssPhp\ScssPhp\Formatter\OutputBlock; /** * Compressed formatter diff --git a/vendor/scssphp/scssphp/src/Formatter/Crunched.php b/vendor/scssphp/scssphp/src/Formatter/Crunched.php index 137cdffb..91c31443 100644 --- a/vendor/scssphp/scssphp/src/Formatter/Crunched.php +++ b/vendor/scssphp/scssphp/src/Formatter/Crunched.php @@ -13,12 +13,13 @@ namespace ScssPhp\ScssPhp\Formatter; use ScssPhp\ScssPhp\Formatter; -use ScssPhp\ScssPhp\Formatter\OutputBlock; /** * Crunched formatter * * @author Anthon Pang + * + * @deprecated since 1.4.0. Use the Compressed formatter instead. */ class Crunched extends Formatter { @@ -27,6 +28,8 @@ class Crunched extends Formatter */ public function __construct() { + @trigger_error('The Crunched formatter is deprecated since 1.4.0. Use the Compressed formatter instead.', E_USER_DEPRECATED); + $this->indentLevel = 0; $this->indentChar = ' '; $this->break = ''; diff --git a/vendor/scssphp/scssphp/src/Formatter/Debug.php b/vendor/scssphp/scssphp/src/Formatter/Debug.php index 5c539a2d..c676601b 100644 --- a/vendor/scssphp/scssphp/src/Formatter/Debug.php +++ b/vendor/scssphp/scssphp/src/Formatter/Debug.php @@ -13,12 +13,13 @@ namespace ScssPhp\ScssPhp\Formatter; use ScssPhp\ScssPhp\Formatter; -use ScssPhp\ScssPhp\Formatter\OutputBlock; /** * Debug formatter * * @author Anthon Pang + * + * @deprecated since 1.4.0. */ class Debug extends Formatter { @@ -27,6 +28,8 @@ class Debug extends Formatter */ public function __construct() { + @trigger_error('The Debug formatter is deprecated since 1.4.0.', E_USER_DEPRECATED); + $this->indentLevel = 0; $this->indentChar = ''; $this->break = "\n"; diff --git a/vendor/scssphp/scssphp/src/Formatter/Expanded.php b/vendor/scssphp/scssphp/src/Formatter/Expanded.php index 3d5344cf..b7cbde18 100644 --- a/vendor/scssphp/scssphp/src/Formatter/Expanded.php +++ b/vendor/scssphp/scssphp/src/Formatter/Expanded.php @@ -13,7 +13,6 @@ namespace ScssPhp\ScssPhp\Formatter; use ScssPhp\ScssPhp\Formatter; -use ScssPhp\ScssPhp\Formatter\OutputBlock; /** * Expanded formatter diff --git a/vendor/scssphp/scssphp/src/Formatter/Nested.php b/vendor/scssphp/scssphp/src/Formatter/Nested.php index 046ecc85..3249c182 100644 --- a/vendor/scssphp/scssphp/src/Formatter/Nested.php +++ b/vendor/scssphp/scssphp/src/Formatter/Nested.php @@ -13,13 +13,14 @@ namespace ScssPhp\ScssPhp\Formatter; use ScssPhp\ScssPhp\Formatter; -use ScssPhp\ScssPhp\Formatter\OutputBlock; use ScssPhp\ScssPhp\Type; /** * Nested formatter * * @author Leaf Corcoran + * + * @deprecated since 1.4.0. Use the Expanded formatter instead. */ class Nested extends Formatter { @@ -33,6 +34,8 @@ class Nested extends Formatter */ public function __construct() { + @trigger_error('The Nested formatter is deprecated since 1.4.0. Use the Expanded formatter instead.', E_USER_DEPRECATED); + $this->indentLevel = 0; $this->indentChar = ' '; $this->break = "\n"; diff --git a/vendor/scssphp/scssphp/src/Formatter/OutputBlock.php b/vendor/scssphp/scssphp/src/Formatter/OutputBlock.php index 8dcba7c9..fe0321bd 100644 --- a/vendor/scssphp/scssphp/src/Formatter/OutputBlock.php +++ b/vendor/scssphp/scssphp/src/Formatter/OutputBlock.php @@ -45,7 +45,7 @@ class OutputBlock public $children; /** - * @var \ScssPhp\ScssPhp\Formatter\OutputBlock + * @var OutputBlock|null */ public $parent; diff --git a/vendor/scssphp/scssphp/src/Node/Number.php b/vendor/scssphp/scssphp/src/Node/Number.php index 0f2099f5..166de50d 100644 --- a/vendor/scssphp/scssphp/src/Node/Number.php +++ b/vendor/scssphp/scssphp/src/Node/Number.php @@ -13,6 +13,7 @@ namespace ScssPhp\ScssPhp\Node; use ScssPhp\ScssPhp\Compiler; +use ScssPhp\ScssPhp\Exception\SassScriptException; use ScssPhp\ScssPhp\Node; use ScssPhp\ScssPhp\Type; @@ -76,74 +77,67 @@ class Number extends Node implements \ArrayAccess /** * @var integer|float */ - public $dimension; + private $dimension; /** - * @var array + * @var string[] + * @phpstan-var list */ - public $units; + private $numeratorUnits; + + /** + * @var string[] + * @phpstan-var list + */ + private $denominatorUnits; /** * Initialize number * - * @param mixed $dimension - * @param mixed $initialUnit + * @param integer|float $dimension + * @param string[]|string $numeratorUnits + * @param string[] $denominatorUnits + * + * @phpstan-param list|string $numeratorUnits + * @phpstan-param list $denominatorUnits */ - public function __construct($dimension, $initialUnit) + public function __construct($dimension, $numeratorUnits, array $denominatorUnits = []) { - $this->type = Type::T_NUMBER; + if (is_string($numeratorUnits)) { + $numeratorUnits = $numeratorUnits ? [$numeratorUnits] : []; + } elseif (isset($numeratorUnits['numerator_units'], $numeratorUnits['denominator_units'])) { + // TODO get rid of this once `$number[2]` is not used anymore + $denominatorUnits = $numeratorUnits['denominator_units']; + $numeratorUnits = $numeratorUnits['numerator_units']; + } + $this->dimension = $dimension; - $this->units = \is_array($initialUnit) - ? $initialUnit - : ($initialUnit ? [$initialUnit => 1] - : []); + $this->numeratorUnits = $numeratorUnits; + $this->denominatorUnits = $denominatorUnits; } /** - * Coerce number to target units - * - * @param array $units - * - * @return \ScssPhp\ScssPhp\Node\Number + * @return float|int */ - public function coerce($units) + public function getDimension() { - if ($this->unitless()) { - return new Number($this->dimension, $units); - } - - $dimension = $this->dimension; - - if (\count($units)) { - $baseUnit = array_keys($units); - $baseUnit = reset($baseUnit); - $baseUnit = $this->findBaseUnit($baseUnit); - if ($baseUnit && isset(static::$unitTable[$baseUnit])) { - foreach (static::$unitTable[$baseUnit] as $unit => $conv) { - $from = isset($this->units[$unit]) ? $this->units[$unit] : 0; - $to = isset($units[$unit]) ? $units[$unit] : 0; - $factor = pow($conv, $from - $to); - $dimension /= $factor; - } - } - } - - return new Number($dimension, $units); + return $this->dimension; } /** - * Normalize number - * - * @return \ScssPhp\ScssPhp\Node\Number + * @return string[] */ - public function normalize() + public function getNumeratorUnits() { - $dimension = $this->dimension; - $units = []; + return $this->numeratorUnits; + } - $this->normalizeUnits($dimension, $units); - - return new Number($dimension, $units); + /** + * @return string[] + */ + public function getDenominatorUnits() + { + return $this->denominatorUnits; } /** @@ -187,13 +181,13 @@ class Number extends Node implements \ArrayAccess return $this->sourceIndex; case 0: - return $this->type; + return Type::T_NUMBER; case 1: return $this->dimension; case 2: - return $this->units; + return array('numerator_units' => $this->numeratorUnits, 'denominator_units' => $this->denominatorUnits); } } @@ -202,17 +196,7 @@ class Number extends Node implements \ArrayAccess */ public function offsetSet($offset, $value) { - if ($offset === 1) { - $this->dimension = $value; - } elseif ($offset === 2) { - $this->units = $value; - } elseif ($offset == -1) { - $this->sourceIndex = $value; - } elseif ($offset == -2) { - $this->sourceLine = $value; - } elseif ($offset == -3) { - $this->sourceColumn = $value; - } + throw new \BadMethodCallException('Number is immutable'); } /** @@ -220,17 +204,7 @@ class Number extends Node implements \ArrayAccess */ public function offsetUnset($offset) { - if ($offset === 1) { - $this->dimension = null; - } elseif ($offset === 2) { - $this->units = null; - } elseif ($offset === -1) { - $this->sourceIndex = null; - } elseif ($offset === -2) { - $this->sourceLine = null; - } elseif ($offset === -3) { - $this->sourceColumn = null; - } + throw new \BadMethodCallException('Number is immutable'); } /** @@ -240,36 +214,19 @@ class Number extends Node implements \ArrayAccess */ public function unitless() { - return ! array_sum($this->units); + return \count($this->numeratorUnits) === 0 && \count($this->denominatorUnits) === 0; } /** - * Test if a number can be normalized in a base unit - * ie if its units are homogeneous + * Checks whether the number has exactly this unit * - * @return boolean + * @param string $unit + * + * @return bool */ - public function isNormalizable() + public function hasUnit($unit) { - if ($this->unitless()) { - return false; - } - - $baseUnit = null; - - foreach ($this->units as $unit => $exp) { - $b = $this->findBaseUnit($unit); - - if (\is_null($baseUnit)) { - $baseUnit = $b; - } - - if (\is_null($b) or $b !== $baseUnit) { - return false; - } - } - - return $baseUnit; + return \count($this->numeratorUnits) === 1 && \count($this->denominatorUnits) === 0 && $this->numeratorUnits[0] === $unit; } /** @@ -279,22 +236,234 @@ class Number extends Node implements \ArrayAccess */ public function unitStr() { - $numerators = []; - $denominators = []; - - foreach ($this->units as $unit => $unitSize) { - if ($unitSize > 0) { - $numerators = array_pad($numerators, \count($numerators) + $unitSize, $unit); - continue; - } - - if ($unitSize < 0) { - $denominators = array_pad($denominators, \count($denominators) - $unitSize, $unit); - continue; - } + if ($this->unitless()) { + return ''; } - return implode('*', $numerators) . (\count($denominators) ? '/' . implode('*', $denominators) : ''); + return self::getUnitString($this->numeratorUnits, $this->denominatorUnits); + } + + /** + * @param string|null $varName + * + * @return void + */ + public function assertNoUnits($varName = null) + { + if ($this->unitless()) { + return; + } + + throw SassScriptException::forArgument(sprintf('Expected %s to have no units', $this), $varName); + } + + /** + * @param Number $other + * + * @return void + */ + public function assertSameUnitOrUnitless(Number $other) + { + if ($other->unitless()) { + return; + } + + if ($this->numeratorUnits === $other->numeratorUnits && $this->denominatorUnits === $other->denominatorUnits) { + return; + } + + throw new SassScriptException(sprintf( + 'Incompatible units %s and %s.', + self::getUnitString($this->numeratorUnits, $this->denominatorUnits), + self::getUnitString($other->numeratorUnits, $other->denominatorUnits) + )); + } + + /** + * @param Number $other + * + * @return bool + */ + public function isComparableTo(Number $other) + { + if ($this->unitless() || $other->unitless()) { + return true; + } + + try { + $this->greaterThan($other); + return true; + } catch (SassScriptException $e) { + return false; + } + } + + /** + * @param Number $other + * + * @return bool + */ + public function lessThan(Number $other) + { + return $this->coerceUnits($other, function ($num1, $num2) { + return $num1 < $num2; + }); + } + + /** + * @param Number $other + * + * @return bool + */ + public function lessThanOrEqual(Number $other) + { + return $this->coerceUnits($other, function ($num1, $num2) { + return $num1 <= $num2; + }); + } + + /** + * @param Number $other + * + * @return bool + */ + public function greaterThan(Number $other) + { + return $this->coerceUnits($other, function ($num1, $num2) { + return $num1 > $num2; + }); + } + + /** + * @param Number $other + * + * @return bool + */ + public function greaterThanOrEqual(Number $other) + { + return $this->coerceUnits($other, function ($num1, $num2) { + return $num1 >= $num2; + }); + } + + /** + * @param Number $other + * + * @return Number + */ + public function plus(Number $other) + { + return $this->coerceNumber($other, function ($num1, $num2) { + return $num1 + $num2; + }); + } + + /** + * @param Number $other + * + * @return Number + */ + public function minus(Number $other) + { + return $this->coerceNumber($other, function ($num1, $num2) { + return $num1 - $num2; + }); + } + + /** + * @return Number + */ + public function unaryMinus() + { + return new Number(-$this->dimension, $this->numeratorUnits, $this->denominatorUnits); + } + + /** + * @param Number $other + * + * @return Number + */ + public function modulo(Number $other) + { + return $this->coerceNumber($other, function ($num1, $num2) { + if ($num2 == 0) { + return NAN; + } + + $result = fmod($num1, $num2); + + if ($result == 0) { + return 0; + } + + if ($num2 < 0 xor $num1 < 0) { + $result += $num2; + } + + return $result; + }); + } + + /** + * @param Number $other + * + * @return Number + */ + public function times(Number $other) + { + return $this->multiplyUnits($this->dimension * $other->dimension, $this->numeratorUnits, $this->denominatorUnits, $other->numeratorUnits, $other->denominatorUnits); + } + + /** + * @param Number $other + * + * @return Number + */ + public function dividedBy(Number $other) + { + if ($other->dimension == 0) { + if ($this->dimension == 0) { + $value = NAN; + } elseif ($this->dimension > 0) { + $value = INF; + } else { + $value = -INF; + } + } else { + $value = $this->dimension / $other->dimension; + } + + return $this->multiplyUnits($value, $this->numeratorUnits, $this->denominatorUnits, $other->denominatorUnits, $other->numeratorUnits); + } + + /** + * @param Number $other + * + * @return bool + */ + public function equals(Number $other) + { + // Unitless numbers are convertable to unit numbers, but not equal, so we special-case unitless here. + if ($this->unitless() !== $other->unitless()) { + return false; + } + + // In Sass, neither NaN nor Infinity are equal to themselves, while PHP defines INF==INF + if (is_nan($this->dimension) || is_nan($other->dimension) || !is_finite($this->dimension) || !is_finite($other->dimension)) { + return false; + } + + if ($this->unitless()) { + return round($this->dimension, self::PRECISION) == round($other->dimension, self::PRECISION); + } + + try { + return $this->coerceUnits($other, function ($num1, $num2) { + return round($num1,self::PRECISION) == round($num2, self::PRECISION); + }); + } catch (SassScriptException $e) { + return false; + } } /** @@ -308,35 +477,29 @@ class Number extends Node implements \ArrayAccess { $dimension = round($this->dimension, self::PRECISION); - $units = array_filter($this->units, function ($unitSize) { - return $unitSize; - }); - - if (\count($units) > 1 && array_sum($units) === 0) { - $dimension = $this->dimension; - $units = []; - - $this->normalizeUnits($dimension, $units); - - $dimension = round($dimension, self::PRECISION); - $units = array_filter($units, function ($unitSize) { - return $unitSize; - }); + if (is_nan($dimension)) { + return 'NaN'; } - $unitSize = array_sum($units); + if ($dimension === INF) { + return 'Infinity'; + } - if ($compiler && ($unitSize > 1 || $unitSize < 0 || \count($units) > 1)) { - $this->units = $units; + if ($dimension === -INF) { + return '-Infinity'; + } + + if ($compiler) { $unit = $this->unitStr(); + } elseif (isset($this->numeratorUnits[0])) { + $unit = $this->numeratorUnits[0]; } else { - reset($units); - $unit = key($units); + $unit = ''; } $dimension = number_format($dimension, self::PRECISION, '.', ''); - return (self::PRECISION ? rtrim(rtrim($dimension, '0'), '.') : $dimension) . $unit; + return rtrim(rtrim($dimension, '0'), '.') . $unit; } /** @@ -348,48 +511,227 @@ class Number extends Node implements \ArrayAccess } /** - * Normalize units + * @param Number $other + * @param callable $operation * - * @param integer|float $dimension - * @param array $units - * @param string $baseUnit + * @return Number + * + * @phpstan-param callable(int|float, int|float): (int|float) $operation */ - private function normalizeUnits(&$dimension, &$units, $baseUnit = null) + private function coerceNumber(Number $other, $operation) { - $dimension = $this->dimension; - $units = []; + $result = $this->coerceUnits($other, $operation); - foreach ($this->units as $unit => $exp) { - if (! $baseUnit) { - $baseUnit = $this->findBaseUnit($unit); - } - - if ($baseUnit && isset(static::$unitTable[$baseUnit][$unit])) { - $factor = pow(static::$unitTable[$baseUnit][$unit], $exp); - - $unit = $baseUnit; - $dimension /= $factor; - } - - $units[$unit] = $exp + (isset($units[$unit]) ? $units[$unit] : 0); + if (!$this->unitless()) { + return new Number($result, $this->numeratorUnits, $this->denominatorUnits); } + + return new Number($result, $other->numeratorUnits, $other->denominatorUnits); } /** - * Find the base unit family for a given unit + * @param Number $other + * @param callable $operation * - * @param string $unit + * @return mixed * - * @return string|null + * @phpstan-template T + * @phpstan-param callable(int|float, int|float): T $operation + * @phpstan-return T */ - private function findBaseUnit($unit) + private function coerceUnits(Number $other, $operation) { - foreach (static::$unitTable as $baseUnit => $unitVariants) { - if (isset($unitVariants[$unit])) { - return $baseUnit; + if (!$this->unitless()) { + $num1 = $this->dimension; + $num2 = $other->valueInUnits($this->numeratorUnits, $this->denominatorUnits); + } else { + $num1 = $this->valueInUnits($other->numeratorUnits, $other->denominatorUnits); + $num2 = $other->dimension; + } + + return \call_user_func($operation, $num1, $num2); + } + + /** + * @param string[] $numeratorUnits + * @param string[] $denominatorUnits + * + * @return int|float + * + * @phpstan-param list $numeratorUnits + * @phpstan-param list $denominatorUnits + */ + private function valueInUnits(array $numeratorUnits, array $denominatorUnits) + { + if ( + $this->unitless() + || (\count($numeratorUnits) === 0 && \count($denominatorUnits) === 0) + || ($this->numeratorUnits === $numeratorUnits && $this->denominatorUnits === $denominatorUnits) + ) { + return $this->dimension; + } + + $value = $this->dimension; + $oldNumerators = $this->numeratorUnits; + + foreach ($numeratorUnits as $newNumerator) { + foreach ($oldNumerators as $key => $oldNumerator) { + $conversionFactor = self::getConversionFactor($newNumerator, $oldNumerator); + + if (\is_null($conversionFactor)) { + continue; + } + + $value *= $conversionFactor; + unset($oldNumerators[$key]); + continue 2; + } + + throw new SassScriptException(sprintf( + 'Incompatible units %s and %s.', + self::getUnitString($this->numeratorUnits, $this->denominatorUnits), + self::getUnitString($numeratorUnits, $denominatorUnits) + )); + } + + $oldDenominators = $this->denominatorUnits; + + foreach ($denominatorUnits as $newDenominator) { + foreach ($oldDenominators as $key => $oldDenominator) { + $conversionFactor = self::getConversionFactor($newDenominator, $oldDenominator); + + if (\is_null($conversionFactor)) { + continue; + } + + $value /= $conversionFactor; + unset($oldDenominators[$key]); + continue 2; + } + + throw new SassScriptException(sprintf( + 'Incompatible units %s and %s.', + self::getUnitString($this->numeratorUnits, $this->denominatorUnits), + self::getUnitString($numeratorUnits, $denominatorUnits) + )); + } + + if (\count($oldNumerators) || \count($oldDenominators)) { + throw new SassScriptException(sprintf( + 'Incompatible units %s and %s.', + self::getUnitString($this->numeratorUnits, $this->denominatorUnits), + self::getUnitString($numeratorUnits, $denominatorUnits) + )); + } + + return $value; + } + + /** + * @param int|float $value + * @param string[] $numerators1 + * @param string[] $denominators1 + * @param string[] $numerators2 + * @param string[] $denominators2 + * + * @return Number + * + * @phpstan-param list $numerators1 + * @phpstan-param list $denominators1 + * @phpstan-param list $numerators2 + * @phpstan-param list $denominators2 + */ + private function multiplyUnits($value, array $numerators1, array $denominators1, array $numerators2, array $denominators2) + { + $newNumerators = array(); + + foreach ($numerators1 as $numerator) { + foreach ($denominators2 as $key => $denominator) { + $conversionFactor = self::getConversionFactor($numerator, $denominator); + + if (\is_null($conversionFactor)) { + continue; + } + + $value /= $conversionFactor; + unset($denominators2[$key]); + continue 2; + } + + $newNumerators[] = $numerator; + } + + foreach ($numerators2 as $numerator) { + foreach ($denominators1 as $key => $denominator) { + $conversionFactor = self::getConversionFactor($numerator, $denominator); + + if (\is_null($conversionFactor)) { + continue; + } + + $value /= $conversionFactor; + unset($denominators1[$key]); + continue 2; + } + + $newNumerators[] = $numerator; + } + + $newDenominators = array_values(array_merge($denominators1, $denominators2)); + + return new Number($value, $newNumerators, $newDenominators); + } + + /** + * Returns the number of [unit1]s per [unit2]. + * + * Equivalently, `1unit1 * conversionFactor(unit1, unit2) = 1unit2`. + * + * @param string $unit1 + * @param string $unit2 + * + * @return float|int|null + */ + private static function getConversionFactor($unit1, $unit2) + { + if ($unit1 === $unit2) { + return 1; + } + + foreach (static::$unitTable as $unitVariants) { + if (isset($unitVariants[$unit1]) && isset($unitVariants[$unit2])) { + return $unitVariants[$unit1] / $unitVariants[$unit2]; } } return null; } + + /** + * Returns unit(s) as the product of numerator units divided by the product of denominator units + * + * @param string[] $numerators + * @param string[] $denominators + * + * @phpstan-param list $numerators + * @phpstan-param list $denominators + * + * @return string + */ + private static function getUnitString(array $numerators, array $denominators) + { + if (!\count($numerators)) { + if (\count($denominators) === 0) { + return 'no units'; + } + + if (\count($denominators) === 1) { + return $denominators[0] . '^-1'; + } + + return '(' . implode('*', $denominators) . ')^-1'; + } + + return implode('*', $numerators) . (\count($denominators) ? '/' . implode('*', $denominators) : ''); + } } diff --git a/vendor/scssphp/scssphp/src/OutputStyle.php b/vendor/scssphp/scssphp/src/OutputStyle.php new file mode 100644 index 00000000..c284639c --- /dev/null +++ b/vendor/scssphp/scssphp/src/OutputStyle.php @@ -0,0 +1,9 @@ + */ protected static $precedence = [ '=' => 0, @@ -39,7 +34,6 @@ class Parser 'and' => 2, '==' => 3, '!=' => 3, - '<=>' => 3, '<=' => 4, '>=' => 4, '<' => 4, @@ -51,24 +45,65 @@ class Parser '%' => 6, ]; + /** + * @var string + */ protected static $commentPattern; + /** + * @var string + */ protected static $operatorPattern; + /** + * @var string + */ protected static $whitePattern; + /** + * @var Cache|null + */ protected $cache; private $sourceName; private $sourceIndex; + /** + * @var array + */ private $sourcePositions; + /** + * @var array|null + */ private $charset; + /** + * The current offset in the buffer + * + * @var int + */ private $count; + /** + * @var Block + */ private $env; + /** + * @var bool + */ private $inParens; + /** + * @var bool + */ private $eatWhiteDefault; + /** + * @var bool + */ private $discardComments; private $allowVars; + /** + * @var string + */ private $buffer; private $utf8; + /** + * @var string|null + */ private $encoding; private $patternModifiers; private $commentsSeen; @@ -80,12 +115,13 @@ class Parser * * @api * - * @param string $sourceName - * @param integer $sourceIndex - * @param string $encoding - * @param \ScssPhp\ScssPhp\Cache $cache + * @param string $sourceName + * @param integer $sourceIndex + * @param string|null $encoding + * @param Cache|null $cache + * @param bool $cssOnly */ - public function __construct($sourceName, $sourceIndex = 0, $encoding = 'utf-8', $cache = null, $cssOnly = false) + public function __construct($sourceName, $sourceIndex = 0, $encoding = 'utf-8', Cache $cache = null, $cssOnly = false) { $this->sourceName = $sourceName ?: '(stdin)'; $this->sourceIndex = $sourceIndex; @@ -98,7 +134,7 @@ class Parser $this->cssOnly = $cssOnly; if (empty(static::$operatorPattern)) { - static::$operatorPattern = '([*\/%+-]|[!=]\=|\>\=?|\<\=\>|\<\=?|and|or)'; + static::$operatorPattern = '([*\/%+-]|[!=]\=|\>\=?|\<\=?|and|or)'; $commentSingle = '\/\/'; $commentMultiLeft = '\/\*'; @@ -110,9 +146,7 @@ class Parser : '/' . $commentSingle . '[^\n]*\s*|(' . static::$commentPattern . ')\s*|\s+/AisS'; } - if ($cache) { - $this->cache = $cache; - } + $this->cache = $cache; } /** @@ -134,9 +168,30 @@ class Parser * * @param string $msg * - * @throws \ScssPhp\ScssPhp\Exception\ParserException + * @throws ParserException + * + * @deprecated use "parseError" and throw the exception in the caller instead. */ public function throwParseError($msg = 'parse error') + { + @trigger_error( + 'The method "throwParseError" is deprecated. Use "parseError" and throw the exception in the caller instead', + E_USER_DEPRECATED + ); + + throw $this->parseError($msg); + } + + /** + * Creates a parser error + * + * @api + * + * @param string $msg + * + * @return ParserException + */ + public function parseError($msg = 'parse error') { list($line, $column) = $this->getSourcePosition($this->count); @@ -150,7 +205,7 @@ class Parser $e = new ParserException("$msg: failed at `$m[1]` $loc"); $e->setSourcePosition([$this->sourceName, $line, $column]); - throw $e; + return $e; } $this->restoreEncoding(); @@ -158,7 +213,7 @@ class Parser $e = new ParserException("$msg: $loc"); $e->setSourcePosition([$this->sourceName, $line, $column]); - throw $e; + return $e; } /** @@ -168,7 +223,7 @@ class Parser * * @param string $buffer * - * @return \ScssPhp\ScssPhp\Block + * @return Block */ public function parse($buffer) { @@ -209,11 +264,11 @@ class Parser } if ($this->count !== \strlen($this->buffer)) { - $this->throwParseError(); + throw $this->parseError(); } if (! empty($this->env->parent)) { - $this->throwParseError('unclosed block'); + throw $this->parseError('unclosed block'); } if ($this->charset) { @@ -248,6 +303,7 @@ class Parser $this->buffer = (string) $buffer; $this->saveEncoding(); + $this->extractLineNumbers($this->buffer); $list = $this->valueList($out); @@ -263,10 +319,11 @@ class Parser * * @param string $buffer * @param string|array $out + * @param bool $shouldValidate * * @return boolean */ - public function parseSelector($buffer, &$out) + public function parseSelector($buffer, &$out, $shouldValidate = true) { $this->count = 0; $this->env = null; @@ -275,11 +332,21 @@ class Parser $this->buffer = (string) $buffer; $this->saveEncoding(); + $this->extractLineNumbers($this->buffer); + + // discard space/comments at the start + $this->discardComments = true; + $this->whitespace(); + $this->discardComments = false; $selector = $this->selectors($out); $this->restoreEncoding(); + if ($shouldValidate && $this->count !== strlen($buffer)) { + throw $this->parseError("`" . substr($buffer, $this->count) . "` is not a valid Selector in `$buffer`"); + } + return $selector; } @@ -302,6 +369,7 @@ class Parser $this->buffer = (string) $buffer; $this->saveEncoding(); + $this->extractLineNumbers($this->buffer); $isMediaQuery = $this->mediaQueryList($out); @@ -364,9 +432,7 @@ class Parser $this->matchChar(')')) || true) && $this->matchChar('{', false) ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); $atRoot = $this->pushSpecialBlock(Type::T_AT_ROOT, $s); $atRoot->selector = $selector; @@ -396,9 +462,7 @@ class Parser ($this->argumentDef($args) || true) && $this->matchChar('{', false) ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); $mixin = $this->pushSpecialBlock(Type::T_MIXIN, $s); $mixin->name = $mixinName; @@ -421,9 +485,7 @@ class Parser ($this->end() || $this->matchChar('{') && $hasBlock = true)) || $this->matchChar('{') && $hasBlock = true) ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); $child = [ Type::T_INCLUDE, @@ -450,9 +512,7 @@ class Parser $this->valueList($importPath) && $this->end() ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); $this->append([Type::T_SCSSPHP_IMPORT_ONCE, $importPath], $s); @@ -467,6 +527,12 @@ class Parser $importPath[0] !== Type::T_FUNCTION_CALL && $this->end() ) { + if ($this->cssOnly) { + $this->assertPlainCssValid([Type::T_IMPORT, $importPath], $s); + $this->append([Type::T_COMMENT, rtrim(substr($this->buffer, $s, $this->count - $s))]); + return true; + } + $this->append([Type::T_IMPORT, $importPath], $s); return true; @@ -480,7 +546,9 @@ class Parser $this->end() ) { if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); + $this->assertPlainCssValid([Type::T_IMPORT, $importPath], $s); + $this->append([Type::T_COMMENT, rtrim(substr($this->buffer, $s, $this->count - $s))]); + return true; } $this->append([Type::T_IMPORT, $importPath], $s); @@ -495,9 +563,7 @@ class Parser $this->selectors($selectors) && $this->end() ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); // check for '!flag' $optional = $this->stripOptionalFlag($selectors); @@ -514,9 +580,7 @@ class Parser $this->argumentDef($args) && $this->matchChar('{', false) ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); $func = $this->pushSpecialBlock(Type::T_FUNCTION, $s); $func->name = $fnName; @@ -527,44 +591,12 @@ class Parser $this->seek($s); - if ( - $this->literal('@break', 6) && - $this->end() - ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } - - $this->append([Type::T_BREAK], $s); - - return true; - } - - $this->seek($s); - - if ( - $this->literal('@continue', 9) && - $this->end() - ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } - - $this->append([Type::T_CONTINUE], $s); - - return true; - } - - $this->seek($s); - if ( $this->literal('@return', 7) && ($this->valueList($retVal) || true) && $this->end() ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); $this->append([Type::T_RETURN, isset($retVal) ? $retVal : [Type::T_NULL]], $s); @@ -580,9 +612,7 @@ class Parser $this->valueList($list) && $this->matchChar('{', false) ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); $each = $this->pushSpecialBlock(Type::T_EACH, $s); @@ -602,9 +632,7 @@ class Parser $this->expression($cond) && $this->matchChar('{', false) ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); while ( $cond[0] === Type::T_LIST && @@ -633,9 +661,7 @@ class Parser $this->expression($end) && $this->matchChar('{', false) ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); $for = $this->pushSpecialBlock(Type::T_FOR, $s); $for->var = $varName[1]; @@ -650,12 +676,9 @@ class Parser if ( $this->literal('@if', 3) && - $this->functionCallArgumentsList($cond, false) && - $this->matchChar('{', false) + $this->functionCallArgumentsList($cond, false, '{', false) ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); $if = $this->pushSpecialBlock(Type::T_IF, $s); @@ -678,12 +701,9 @@ class Parser if ( $this->literal('@debug', 6) && - $this->functionCallArgumentsList($value, false) && - $this->end() + $this->functionCallArgumentsList($value, false) ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); $this->append([Type::T_DEBUG, $value], $s); @@ -694,12 +714,9 @@ class Parser if ( $this->literal('@warn', 5) && - $this->functionCallArgumentsList($value, false) && - $this->end() + $this->functionCallArgumentsList($value, false) ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); $this->append([Type::T_WARN, $value], $s); @@ -710,12 +727,9 @@ class Parser if ( $this->literal('@error', 6) && - $this->functionCallArgumentsList($value, false) && - $this->end() + $this->functionCallArgumentsList($value, false) ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); $this->append([Type::T_ERROR, $value], $s); @@ -732,9 +746,7 @@ class Parser $this->matchChar(')') && $this->end()) ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); $this->append([Type::T_MIXIN_CONTENT, isset($argContent) ? $argContent : null], $s); @@ -753,8 +765,7 @@ class Parser $else = $this->pushSpecialBlock(Type::T_ELSE, $s); } elseif ( $this->literal('if', 2) && - $this->valueList($cond) && - $this->matchChar('{', false) + $this->functionCallArgumentsList($cond, false, '{', false) ) { $else = $this->pushSpecialBlock(Type::T_ELSEIF, $s); $else->cond = $cond; @@ -811,9 +822,14 @@ class Parser // doesn't match built in directive, do generic one if ( $this->matchChar('@', false) && - $this->keyword($dirName) && + $this->mixedKeyword($dirName) && $this->directiveValue($dirValue, '{') ) { + if (count($dirName) === 1 && is_string(reset($dirName))) { + $dirName = reset($dirName); + } else { + $dirName = [Type::T_STRING, '', $dirName]; + } if ($dirName === 'media') { $directive = $this->pushSpecialBlock(Type::T_MEDIA, $s); } else { @@ -822,6 +838,7 @@ class Parser } if (isset($dirValue)) { + ! $this->cssOnly || ($dirValue = $this->assertPlainCssValid($dirValue)); $directive->value = $dirValue; } @@ -833,11 +850,36 @@ class Parser // maybe it's a generic blockless directive if ( $this->matchChar('@', false) && - $this->keyword($dirName) && - $this->directiveValue($dirValue) && - $this->end() + $this->mixedKeyword($dirName) && + ! $this->isKnownGenericDirective($dirName) && + ($this->end(false) || ($this->directiveValue($dirValue, '') && $this->end(false))) ) { - $this->append([Type::T_DIRECTIVE, [$dirName, $dirValue]], $s); + if (\count($dirName) === 1 && \is_string(\reset($dirName))) { + $dirName = \reset($dirName); + } else { + $dirName = [Type::T_STRING, '', $dirName]; + } + if ( + ! empty($this->env->parent) && + $this->env->type && + ! \in_array($this->env->type, [Type::T_DIRECTIVE, Type::T_MEDIA]) + ) { + $plain = \trim(\substr($this->buffer, $s, $this->count - $s)); + throw $this->parseError( + "Unknown directive `{$plain}` not allowed in `" . $this->env->type . "` block" + ); + } + // blockless directives with a blank line after keeps their blank lines after + // sass-spec compliance purpose + $s = $this->count; + $hasBlankLine = false; + if ($this->match('\s*?\n\s*\n', $out, false)) { + $hasBlankLine = true; + $this->seek($s); + } + $isNotRoot = ! empty($this->env->parent); + $this->append([Type::T_DIRECTIVE, [$dirName, $dirValue, $hasBlankLine, $isNotRoot]], $s); + $this->whitespace(); return true; } @@ -853,11 +895,7 @@ class Parser ! in_array($this->env->type, [Type::T_DIRECTIVE, Type::T_MEDIA])); } // custom properties : right part is static - if ( - ($this->customProperty($name) || - ($inCssSelector && $this->propertyName($name))) && - $this->matchChar(':', false) - ) { + if (($this->customProperty($name) ) && $this->matchChar(':', false)) { $start = $this->count; // but can be complex and finish with ; or } @@ -924,9 +962,7 @@ class Parser $this->valueList($value) && $this->end() ) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); // check for '!flag' $assignmentFlags = $this->stripAssignmentFlags($value); @@ -947,11 +983,7 @@ class Parser $this->selectors($selectors) && $this->matchChar('{', false) ) { - if ($this->cssOnly) { - if ($inCssSelector) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } - } + ! $this->cssOnly || ! $inCssSelector || $this->assertPlainCssValid(false); $this->pushBlock($selectors, $s); @@ -974,7 +1006,7 @@ class Parser if ($this->valueList($value)) { if (empty($this->env->parent)) { - $this->throwParseError('expected "{"'); + throw $this->parseError('expected "{"'); } $this->append([Type::T_ASSIGN, $name, $value], $s); @@ -982,9 +1014,7 @@ class Parser } if ($this->matchChar('{', false)) { - if ($this->cssOnly) { - $this->throwParseError('SCSS syntax not allowed in CSS file'); - } + ! $this->cssOnly || $this->assertPlainCssValid(false); $propBlock = $this->pushSpecialBlock(Type::T_NESTED_PROPERTY, $s); $propBlock->prefix = $name; @@ -1048,10 +1078,10 @@ class Parser /** * Push block onto parse tree * - * @param array $selectors + * @param array|null $selectors * @param integer $pos * - * @return \ScssPhp\ScssPhp\Block + * @return Block */ protected function pushBlock($selectors, $pos = 0) { @@ -1097,7 +1127,7 @@ class Parser * @param string $type * @param integer $pos * - * @return \ScssPhp\ScssPhp\Block + * @return Block */ protected function pushSpecialBlock($type, $pos) { @@ -1110,7 +1140,7 @@ class Parser /** * Pop scope and return last block * - * @return \ScssPhp\ScssPhp\Block + * @return Block * * @throws \Exception */ @@ -1126,7 +1156,7 @@ class Parser $block = $this->env; if (empty($block->parent)) { - $this->throwParseError('unexpected }'); + throw $this->parseError('unexpected }'); } if ($block->type == Type::T_AT_ROOT) { @@ -1172,6 +1202,208 @@ class Parser $this->count = $where; } + /** + * Assert a parsed part is plain CSS Valid + * + * @param array|false $parsed + * @param int $startPos + * @throws ParserException + */ + protected function assertPlainCssValid($parsed, $startPos = null) + { + $type = ''; + if ($parsed) { + $type = $parsed[0]; + $parsed = $this->isPlainCssValidElement($parsed); + } + if (! $parsed) { + if (! \is_null($startPos)) { + $plain = rtrim(substr($this->buffer, $startPos, $this->count - $startPos)); + $message = "Error : `{$plain}` isn't allowed in plain CSS"; + } else { + $message = 'Error: SCSS syntax not allowed in CSS file'; + } + if ($type) { + $message .= " ($type)"; + } + throw $this->parseError($message); + } + + return $parsed; + } + + /** + * Check a parsed element is plain CSS Valid + * @param array $parsed + * @return bool|array + */ + protected function isPlainCssValidElement($parsed, $allowExpression = false) + { + // keep string as is + if (is_string($parsed)) { + return $parsed; + } + + if ( + \in_array($parsed[0], [Type::T_FUNCTION, Type::T_FUNCTION_CALL]) && + !\in_array($parsed[1], [ + 'alpha', + 'attr', + 'calc', + 'cubic-bezier', + 'env', + 'grayscale', + 'hsl', + 'hsla', + 'invert', + 'linear-gradient', + 'min', + 'max', + 'radial-gradient', + 'repeating-linear-gradient', + 'repeating-radial-gradient', + 'rgb', + 'rgba', + 'rotate', + 'saturate', + 'var', + ]) && + Compiler::isNativeFunction($parsed[1]) + ) { + return false; + } + + switch ($parsed[0]) { + case Type::T_BLOCK: + case Type::T_KEYWORD: + case Type::T_NULL: + case Type::T_NUMBER: + case Type::T_MEDIA: + return $parsed; + + case Type::T_COMMENT: + if (isset($parsed[2])) { + return false; + } + return $parsed; + + case Type::T_DIRECTIVE: + if (\is_array($parsed[1])) { + $parsed[1][1] = $this->isPlainCssValidElement($parsed[1][1]); + if (! $parsed[1][1]) { + return false; + } + } + + return $parsed; + + case Type::T_IMPORT: + if ($parsed[1][0] === Type::T_LIST) { + return false; + } + $parsed[1] = $this->isPlainCssValidElement($parsed[1]); + if ($parsed[1] === false) { + return false; + } + return $parsed; + + case Type::T_STRING: + foreach ($parsed[2] as $k => $substr) { + if (\is_array($substr)) { + $parsed[2][$k] = $this->isPlainCssValidElement($substr); + if (! $parsed[2][$k]) { + return false; + } + } + } + return $parsed; + + case Type::T_LIST: + if (!empty($parsed['enclosing'])) { + return false; + } + foreach ($parsed[2] as $k => $listElement) { + $parsed[2][$k] = $this->isPlainCssValidElement($listElement); + if (! $parsed[2][$k]) { + return false; + } + } + return $parsed; + + case Type::T_ASSIGN: + foreach ([1, 2, 3] as $k) { + if (! empty($parsed[$k])) { + $parsed[$k] = $this->isPlainCssValidElement($parsed[$k]); + if (! $parsed[$k]) { + return false; + } + } + } + return $parsed; + + case Type::T_EXPRESSION: + list( ,$op, $lhs, $rhs, $inParens, $whiteBefore, $whiteAfter) = $parsed; + if (! $allowExpression && ! \in_array($op, ['and', 'or', '/'])) { + return false; + } + $lhs = $this->isPlainCssValidElement($lhs, true); + if (! $lhs) { + return false; + } + $rhs = $this->isPlainCssValidElement($rhs, true); + if (! $rhs) { + return false; + } + + return [ + Type::T_STRING, + '', [ + $this->inParens ? '(' : '', + $lhs, + ($whiteBefore ? ' ' : '') . $op . ($whiteAfter ? ' ' : ''), + $rhs, + $this->inParens ? ')' : '' + ] + ]; + + case Type::T_UNARY: + $parsed[2] = $this->isPlainCssValidElement($parsed[2]); + if (! $parsed[2]) { + return false; + } + return $parsed; + + case Type::T_FUNCTION: + $argsList = $parsed[2]; + foreach ($argsList[2] as $argElement) { + if (! $this->isPlainCssValidElement($argElement)) { + return false; + } + } + return $parsed; + + case Type::T_FUNCTION_CALL: + $parsed[0] = Type::T_FUNCTION; + $argsList = [Type::T_LIST, ',', []]; + foreach ($parsed[2] as $arg) { + if ($arg[0] || ! empty($arg[2])) { + // no named arguments possible in a css function call + // nor ... argument + return false; + } + $arg = $this->isPlainCssValidElement($arg[1], $parsed[1] === 'calc'); + if (! $arg) { + return false; + } + $argsList[2][] = $arg; + } + $parsed[2] = $argsList; + return $parsed; + } + + return false; + } + /** * Match string looking for either ending delim, escape, or string interpolation * @@ -1360,6 +1592,10 @@ class Parser } else { // comment that are ignored and not kept in the output css $this->count += \strlen($m[0]); + // silent comments are not allowed in plain CSS files + ! $this->cssOnly + || ! \strlen(trim($m[0])) + || $this->assertPlainCssValid(false, $this->count - \strlen($m[0])); } $gotWhite = true; @@ -1383,12 +1619,14 @@ class Parser /** * Append statement to current block * - * @param array $statement + * @param array|null $statement * @param integer $pos */ protected function append($statement, $pos = null) { if (! \is_null($statement)) { + ! $this->cssOnly || ($statement = $this->assertPlainCssValid($statement, $pos)); + if (! \is_null($pos)) { list($line, $column) = $this->getSourcePosition($pos); @@ -1714,6 +1952,53 @@ class Parser return false; } + /** + * Check if a generic directive is known to be able to allow almost any syntax or not + * @param mixed $directiveName + * @return bool + */ + protected function isKnownGenericDirective($directiveName) + { + if (\is_array($directiveName) && \is_string(reset($directiveName))) { + $directiveName = reset($directiveName); + } + if (! \is_string($directiveName)) { + return false; + } + if ( + \in_array($directiveName, [ + 'at-root', + 'media', + 'mixin', + 'include', + 'scssphp-import-once', + 'import', + 'extend', + 'function', + 'break', + 'continue', + 'return', + 'each', + 'while', + 'for', + 'if', + 'debug', + 'warn', + 'error', + 'content', + 'else', + 'charset', + 'supports', + // Todo + 'use', + 'forward', + ]) + ) { + return true; + } + return false; + } + /** * Parse directive value list that considers $vars as keyword * @@ -1738,8 +2023,13 @@ class Parser $this->seek($s); - if ($endChar && $this->openString($endChar, $out)) { - if ($this->matchChar($endChar, false)) { + if (\is_string($endChar) && $this->openString($endChar ? $endChar : ';', $out, null, null, true, ";}{")) { + if ($endChar && $this->matchChar($endChar, false)) { + return true; + } + $ss = $this->count; + if (!$endChar && $this->end()) { + $this->seek($ss); return true; } } @@ -1793,25 +2083,31 @@ class Parser * and not of the value list * * @param $out - * @param bool $mandatoryParenthesis + * @param bool $mandatoryEnclos + * @param null|string $charAfter + * @param null|bool $eatWhiteSp * @return bool */ - protected function functionCallArgumentsList(&$out, $mandatoryParenthesis = true) + protected function functionCallArgumentsList(&$out, $mandatoryEnclos = true, $charAfter = null, $eatWhiteSp = null) { $s = $this->count; if ( $this->matchChar('(') && $this->valueList($out) && - $this->matchChar(')') + $this->matchChar(')') && + ($charAfter ? $this->matchChar($charAfter, $eatWhiteSp) : $this->end()) ) { return true; } - if (! $mandatoryParenthesis) { + if (! $mandatoryEnclos) { $this->seek($s); - if ($this->valueList($out)) { + if ( + $this->valueList($out) && + ($charAfter ? $this->matchChar($charAfter, $eatWhiteSp) : $this->end()) + ) { return true; } } @@ -1836,10 +2132,10 @@ class Parser /** * Parse generic list * - * @param array $out - * @param callable $parseItem - * @param string $delim - * @param boolean $flatten + * @param array $out + * @param string $parseItem The name of the method used to parse items + * @param string $delim + * @param boolean $flatten * * @return boolean */ @@ -2094,12 +2390,17 @@ class Parser break; } + if ($op === '-' && ! $whiteAfter && $rhs[0] === Type::T_KEYWORD) { + break; + } + // peek and see if rhs belongs to next operator if ($this->peek($operators, $next) && static::$precedence[$next[1]] > static::$precedence[$op]) { $rhs = $this->expHelper($rhs, static::$precedence[$next[1]]); } $lhs = [Type::T_EXPRESSION, $op, $lhs, $rhs, $this->inParens, $whiteBefore, $whiteAfter]; + $ss = $this->count; $whiteBefore = isset($this->buffer[$this->count - 1]) && ctype_space($this->buffer[$this->count - 1]); @@ -2288,11 +2589,15 @@ class Parser // unicode range with wildcards if ( $this->literal('U+', 2) && - $this->match('([0-9A-F]+\?*)(-([0-9A-F]+))?', $m, false) + $this->match('\?+|([0-9A-F]+(\?+|(-[0-9A-F]+))?)', $m, false) ) { - $out = [Type::T_KEYWORD, 'U+' . $m[0]]; + $unicode = explode('-', $m[0]); + if (strlen(reset($unicode)) <= 6 && strlen(end($unicode)) <= 6) { + $out = [Type::T_KEYWORD, 'U+' . $m[0]]; - return true; + return true; + } + $this->count -= strlen($m[0]) + 2; } if ($this->keyword($keyword, false)) { @@ -2519,7 +2824,7 @@ class Parser $sss = $this->count; if (! $this->matchChar(')')) { - $this->throwParseError('... has to be after the final argument'); + throw $this->parseError('... has to be after the final argument'); } $arg[2] = true; @@ -2648,7 +2953,7 @@ class Parser * * @return boolean */ - protected function string(&$out) + protected function string(&$out, $keepDelimWithInterpolation = false) { $s = $this->count; @@ -2681,7 +2986,7 @@ class Parser $content[] = '#{'; // ignore it } } elseif ($m[2] === "\r") { - $content[] = '\\a'; + $content[] = chr(10); // TODO : warning # DEPRECATION WARNING on line x, column y of zzz: # Unescaped multiline strings are deprecated and will be removed in a future version of Sass. @@ -2700,7 +3005,7 @@ class Parser } elseif ($this->matchEscapeCharacter($c)) { $content[] = $c; } else { - $this->throwParseError('Unterminated escape sequence'); + throw $this->parseError('Unterminated escape sequence'); } } else { $this->count -= \strlen($delim); @@ -2711,7 +3016,7 @@ class Parser $this->eatWhiteDefault = $oldWhite; if ($this->literal($delim, \strlen($delim))) { - if ($hasInterpolation) { + if ($hasInterpolation && ! $keepDelimWithInterpolation) { $delim = '"'; } @@ -2725,8 +3030,9 @@ class Parser return false; } - protected function matchEscapeCharacter(&$out) + protected function matchEscapeCharacter(&$out, $inKeywords = false) { + $s = $this->count; if ($this->match('[a-f0-9]', $m, false)) { $hex = $m[0]; @@ -2738,10 +3044,16 @@ class Parser } } + // CSS allows Unicode escape sequences to be followed by a delimiter space + // (necessary in some cases for shorter sequences to disambiguate their end) + $this->matchChar(' ', false); + $value = hexdec($hex); - if ($value == 0 || ($value >= 0xD800 && $value <= 0xDFFF) || $value >= 0x10FFFF) { - $out = "\u{FFFD}"; + if (!$inKeywords && ($value == 0 || ($value >= 0xD800 && $value <= 0xDFFF) || $value >= 0x10FFFF)) { + $out = "\xEF\xBF\xBD"; // "\u{FFFD}" but with a syntax supported on PHP 5 + } elseif ($value < 0x20) { + $out = Util::mbChr($value); } else { $out = Util::mbChr($value); } @@ -2750,6 +3062,10 @@ class Parser } if ($this->match('.', $m, false)) { + if ($inKeywords && in_array($m[0], ["'",'"','@','&',' ','\\',':','/','%'])) { + $this->seek($s); + return false; + } $out = $m[0]; return true; @@ -2807,24 +3123,26 @@ class Parser * * @param string $end * @param array $out - * @param string $nestingOpen - * @param string $nestingClose - * @param boolean $trimEnd + * @param string $nestOpen + * @param string $nestClose + * @param boolean $rtrim + * @param string $disallow * * @return boolean */ - protected function openString($end, &$out, $nestingOpen = null, $nestingClose = null, $trimEnd = true) + protected function openString($end, &$out, $nestOpen = null, $nestClose = null, $rtrim = true, $disallow = null) { $oldWhite = $this->eatWhiteDefault; $this->eatWhiteDefault = false; - if ($nestingOpen && ! $nestingClose) { - $nestingClose = $end; + if ($nestOpen && ! $nestClose) { + $nestClose = $end; } - $patt = '(.*?)([\'"]|#\{|' + $patt = ($disallow ? '[^' . $this->pregQuote($disallow) . ']' : '.'); + $patt = '(' . $patt . '*?)([\'"]|#\{|' . $this->pregQuote($end) . '|' - . (($nestingClose && $nestingClose !== $end) ? $this->pregQuote($nestingClose) . '|' : '') + . (($nestClose && $nestClose !== $end) ? $this->pregQuote($nestClose) . '|' : '') . static::$commentPattern . ')'; $nestingLevel = 0; @@ -2835,8 +3153,8 @@ class Parser if (isset($m[1]) && $m[1] !== '') { $content[] = $m[1]; - if ($nestingOpen) { - $nestingLevel += substr_count($m[1], $nestingOpen); + if ($nestOpen) { + $nestingLevel += substr_count($m[1], $nestOpen); } } @@ -2848,11 +3166,11 @@ class Parser break; } - if ($tok === $nestingClose) { + if ($tok === $nestClose) { $nestingLevel--; } - if (($tok === "'" || $tok === '"') && $this->string($str)) { + if (($tok === "'" || $tok === '"') && $this->string($str, true)) { $content[] = $str; continue; } @@ -2873,7 +3191,7 @@ class Parser } // trim the end - if ($trimEnd && \is_string(end($content))) { + if ($rtrim && \is_string(end($content))) { $content[\count($content) - 1] = rtrim(end($content)); } @@ -2909,7 +3227,10 @@ class Parser } else { if ($lookWhite) { $left = ($s > 0 && preg_match('/\s/', $this->buffer[$s - 1])) ? ' ' : ''; - $right = preg_match('/\s/', $this->buffer[$this->count]) ? ' ' : ''; + $right = ( + ! empty($this->buffer[$this->count]) && + preg_match('/\s/', $this->buffer[$this->count]) + ) ? ' ' : ''; } else { $left = $right = false; } @@ -3052,8 +3373,8 @@ class Parser /** * Parse comma separated selector list * - * @param array $out - * @param boolean $subSelector + * @param array $out + * @param string|boolean $subSelector * * @return boolean */ @@ -3088,8 +3409,8 @@ class Parser /** * Parse whitespace separated selector list * - * @param array $out - * @param boolean $subSelector + * @param array $out + * @param string|boolean $subSelector * * @return boolean */ @@ -3097,6 +3418,9 @@ class Parser { $selector = []; + $discardComments = $this->discardComments; + $this->discardComments = true; + for (;;) { $s = $this->count; @@ -3114,18 +3438,15 @@ class Parser if ($this->selectorSingle($part, $subSelector)) { $selector[] = $part; - $this->match('\s+', $m); - continue; - } - - if ($this->match('\/[^\/]+\/', $m, true)) { - $selector[] = [$m[0]]; + $this->whitespace(); continue; } break; } + $this->discardComments = $discardComments; + if (! $selector) { return false; } @@ -3142,8 +3463,8 @@ class Parser * div[yes=no]#something.hello.world:nth-child(-2n+1)%placeholder * }} * - * @param array $out - * @param boolean $subSelector + * @param array $out + * @param string|boolean $subSelector * * @return boolean */ @@ -3181,6 +3502,7 @@ class Parser case '&': $parts[] = Compiler::$selfSelector; $this->count++; + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); continue 2; case '.': @@ -3205,6 +3527,7 @@ class Parser if ($this->placeholder($placeholder)) { $parts[] = '%'; $parts[] = $placeholder; + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); continue; } @@ -3214,6 +3537,7 @@ class Parser if ($char === '#') { if ($this->interpolation($inter)) { $parts[] = $inter; + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); continue; } @@ -3280,7 +3604,7 @@ class Parser $this->seek($ss); } } elseif ( - $this->matchChar('(') && + $this->matchChar('(', true) && ($this->openString(')', $str, '(') || true) && $this->matchChar(')') ) { @@ -3395,17 +3719,51 @@ class Parser */ protected function keyword(&$word, $eatWhitespace = null) { + $s = $this->count; $match = $this->match( $this->utf8 - ? '(([\pL\w\x{00A0}-\x{10FFFF}_\-\*!"\']|[\\\\].)([\pL\w\x{00A0}-\x{10FFFF}\-_"\']|[\\\\].)*)' - : '(([\w_\-\*!"\']|[\\\\].)([\w\-_"\']|[\\\\].)*)', + ? '(([\pL\w\x{00A0}-\x{10FFFF}_\-\*!"\']|\\\\[a-f0-9]{6} ?|\\\\[a-f0-9]{1,5}(?![a-f0-9]) ?|[\\\\].)([\pL\w\x{00A0}-\x{10FFFF}\-_"\']|\\\\[a-f0-9]{6} ?|\\\\[a-f0-9]{1,5}(?![a-f0-9]) ?|[\\\\].)*)' + : '(([\w_\-\*!"\']|\\\\[a-f0-9]{6} ?|\\\\[a-f0-9]{1,5}(?![a-f0-9]) ?|[\\\\].)([\w\-_"\']|\\\\[a-f0-9]{6} ?|\\\\[a-f0-9]{1,5}(?![a-f0-9]) ?|[\\\\].)*)', $m, - $eatWhitespace + false ); if ($match) { $word = $m[1]; + // handling of escaping in keyword : get the escaped char + if (strpos($word, '\\') !== false) { + $send = $this->count; + $escapedWord = []; + $this->seek($s); + $previousEscape = false; + while ($this->count < $send) { + $char = $this->buffer[$this->count]; + $this->count++; + if ( + $this->count < $send + && $char === '\\' + && !$previousEscape + && $this->matchEscapeCharacter($out, true) + ) { + $escapedWord[] = $out; + } else { + if ($previousEscape) { + $previousEscape = false; + } elseif ($char === '\\') { + $previousEscape = true; + } + $escapedWord[] = $char; + } + } + + $word = implode('', $escapedWord); + } + + if (is_null($eatWhitespace) ? $this->eatWhiteDefault : $eatWhitespace) { + $this->whitespace(); + } + return true; } @@ -3471,15 +3829,28 @@ class Parser */ protected function url(&$out) { - //if ($this->match('(url\(\s*(["\']?)([^)]+)\2\s*\))', $m)) { - if ( - $this->literal('url(', 4) && - ($this->string($out) || $this->openString(')', $out)) && - $this->matchChar(')') - ) { - $out = [Type::T_STRING, '', ['url(', $out, ')']]; + if ($this->literal('url(', 4)) { + $s = $this->count; - return true; + if ( + ($this->string($out) || $this->spaceList($out)) && + $this->matchChar(')') + ) { + $out = [Type::T_STRING, '', ['url(', $out, ')']]; + + return true; + } + + $this->seek($s); + + if ( + $this->openString(')', $out) && + $this->matchChar(')') + ) { + $out = [Type::T_STRING, '', ['url(', $out, ')']]; + + return true; + } } return false; @@ -3487,12 +3858,13 @@ class Parser /** * Consume an end of statement delimiter + * @param bool $eatWhitespace * * @return boolean */ - protected function end() + protected function end($eatWhitespace = null) { - if ($this->matchChar(';')) { + if ($this->matchChar(';', $eatWhitespace)) { return true; } diff --git a/vendor/scssphp/scssphp/src/SourceMap/Base64VLQ.php b/vendor/scssphp/scssphp/src/SourceMap/Base64VLQ.php index 9083d785..11acfbc8 100644 --- a/vendor/scssphp/scssphp/src/SourceMap/Base64VLQ.php +++ b/vendor/scssphp/scssphp/src/SourceMap/Base64VLQ.php @@ -12,8 +12,6 @@ namespace ScssPhp\ScssPhp\SourceMap; -use ScssPhp\ScssPhp\SourceMap\Base64; - /** * Base 64 VLQ * diff --git a/vendor/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php b/vendor/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php index d01f7cca..2d956351 100644 --- a/vendor/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php +++ b/vendor/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php @@ -154,14 +154,16 @@ class SourceMapGenerator /** * Generates the JSON source map * + * @param string $prefix A prefix added in the output file, which needs to shift mappings + * * @return string * * @see https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit# */ - public function generateJson() + public function generateJson($prefix = '') { $sourceMap = []; - $mappings = $this->generateMappings(); + $mappings = $this->generateMappings($prefix); // File version (always the first entry in the object) and must be a positive integer. $sourceMap['version'] = self::VERSION; @@ -232,14 +234,21 @@ class SourceMapGenerator /** * Generates the mappings string * + * @param string $prefix A prefix added in the output file, which needs to shift mappings + * * @return string */ - public function generateMappings() + public function generateMappings($prefix = '') { if (! \count($this->mappings)) { return ''; } + $prefixLines = substr_count($prefix, "\n"); + $lastPrefixNewLine = strrpos($prefix, "\n"); + $lastPrefixLineStart = false === $lastPrefixNewLine ? 0 : $lastPrefixNewLine + 1; + $prefixColumn = strlen($prefix) - $lastPrefixLineStart; + $this->sourceKeys = array_flip(array_keys($this->sources)); // group mappings by generated line number. @@ -254,6 +263,12 @@ class SourceMapGenerator $lastGeneratedLine = $lastOriginalIndex = $lastOriginalLine = $lastOriginalColumn = 0; foreach ($groupedMap as $lineNumber => $lineMap) { + if ($lineNumber > 1) { + // The prefix only impacts the column for the first line of the original output + $prefixColumn = 0; + } + $lineNumber += $prefixLines; + while (++$lastGeneratedLine < $lineNumber) { $groupedMapEncoded[] = ';'; } @@ -262,8 +277,10 @@ class SourceMapGenerator $lastGeneratedColumn = 0; foreach ($lineMap as $m) { - $mapEncoded = $this->encoder->encode($m['generated_column'] - $lastGeneratedColumn); - $lastGeneratedColumn = $m['generated_column']; + $generatedColumn = $m['generated_column'] + $prefixColumn; + + $mapEncoded = $this->encoder->encode($generatedColumn - $lastGeneratedColumn); + $lastGeneratedColumn = $generatedColumn; // find the index if ($m['source_file']) { diff --git a/vendor/scssphp/scssphp/src/Type.php b/vendor/scssphp/scssphp/src/Type.php index 97ebb0d5..549b08ed 100644 --- a/vendor/scssphp/scssphp/src/Type.php +++ b/vendor/scssphp/scssphp/src/Type.php @@ -22,11 +22,14 @@ class Type const T_ASSIGN = 'assign'; const T_AT_ROOT = 'at-root'; const T_BLOCK = 'block'; + /** @deprecated */ const T_BREAK = 'break'; const T_CHARSET = 'charset'; const T_COLOR = 'color'; const T_COMMENT = 'comment'; + /** @deprecated */ const T_CONTINUE = 'continue'; + /** @deprecated */ const T_CONTROL = 'control'; const T_CUSTOM_PROPERTY = 'custom'; const T_DEBUG = 'debug'; diff --git a/vendor/scssphp/scssphp/src/Util.php b/vendor/scssphp/scssphp/src/Util.php index 8fc154cb..d32e0c34 100644 --- a/vendor/scssphp/scssphp/src/Util.php +++ b/vendor/scssphp/scssphp/src/Util.php @@ -82,8 +82,8 @@ class Util */ public static function mbChr($code) { - // Use the native implementation if available. - if (\function_exists('mb_chr')) { + // Use the native implementation if available, but not on PHP 7.2 as mb_chr(0) is buggy there + if (\PHP_VERSION_ID > 70300 && \function_exists('mb_chr')) { return mb_chr($code, 'UTF-8'); } @@ -100,4 +100,82 @@ class Util return $s; } + + /** + * mb_strlen() wrapper + * + * @param string $string + * @return int + */ + public static function mbStrlen($string) + { + // Use the native implementation if available. + if (\function_exists('mb_strlen')) { + return mb_strlen($string, 'UTF-8'); + } + + if (\function_exists('iconv_strlen')) { + return @iconv_strlen($string, 'UTF-8'); + } + + return strlen($string); + } + + /** + * mb_substr() wrapper + * @param string $string + * @param int $start + * @param null|int $length + * @return string + */ + public static function mbSubstr($string, $start, $length = null) + { + // Use the native implementation if available. + if (\function_exists('mb_substr')) { + return mb_substr($string, $start, $length, 'UTF-8'); + } + + if (\function_exists('iconv_substr')) { + if ($start < 0) { + $start = static::mbStrlen($string) + $start; + if ($start < 0) { + $start = 0; + } + } + + if (null === $length) { + $length = 2147483647; + } elseif ($length < 0) { + $length = static::mbStrlen($string) + $length - $start; + if ($length < 0) { + return ''; + } + } + + return (string)iconv_substr($string, $start, $length, 'UTF-8'); + } + + return substr($string, $start, $length); + } + + /** + * mb_strpos wrapper + * @param string $haystack + * @param string $needle + * @param int $offset + * + * @return int|false + */ + public static function mbStrpos($haystack, $needle, $offset = 0) + { + if (\function_exists('mb_strpos')) { + return mb_strpos($haystack, $needle, $offset, 'UTF-8'); + } + + if (\function_exists('iconv_strpos')) { + return iconv_strpos($haystack, $needle, $offset, 'UTF-8'); + } + + return strpos($haystack, $needle, $offset); + } } diff --git a/vendor/scssphp/scssphp/src/Version.php b/vendor/scssphp/scssphp/src/Version.php index acb30046..cd3e190f 100644 --- a/vendor/scssphp/scssphp/src/Version.php +++ b/vendor/scssphp/scssphp/src/Version.php @@ -19,5 +19,5 @@ namespace ScssPhp\ScssPhp; */ class Version { - const VERSION = '1.2'; + const VERSION = '1.3'; }