Updated SCSS compiler to v1.5

This commit is contained in:
Matias Griese
2021-05-18 18:32:32 +03:00
parent 6e5839ded6
commit a01170576a
44 changed files with 2707 additions and 915 deletions

View File

@@ -1,6 +1,8 @@
# v1.10.15 # v1.10.15
## mm/dd/2021 ## mm/dd/2021
1. [](#new)
* Updated SCSS compiler to v1.5
1. [](#improved) 1. [](#improved)
* Updated node modules dev dependencies * Updated node modules dev dependencies
* Package.json scripts cleanup * Package.json scripts cleanup

122
composer.lock generated
View File

@@ -188,16 +188,16 @@
}, },
{ {
"name": "scssphp/scssphp", "name": "scssphp/scssphp",
"version": "v1.4.1", "version": "v1.5.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/scssphp/scssphp.git", "url": "https://github.com/scssphp/scssphp.git",
"reference": "ba86c963b94ec7ebd6e19d90cdab90d89667dbf7" "reference": "6fe16f169f55f5e793474fb210aac0a4481619e5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/scssphp/scssphp/zipball/ba86c963b94ec7ebd6e19d90cdab90d89667dbf7", "url": "https://api.github.com/repos/scssphp/scssphp/zipball/6fe16f169f55f5e793474fb210aac0a4481619e5",
"reference": "ba86c963b94ec7ebd6e19d90cdab90d89667dbf7", "reference": "6fe16f169f55f5e793474fb210aac0a4481619e5",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -206,13 +206,19 @@
"php": ">=5.6.0" "php": ">=5.6.0"
}, },
"require-dev": { "require-dev": {
"bamarni/composer-bin-plugin": "^1.4",
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3 || ^9.4", "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3 || ^9.4",
"sass/sass-spec": "2020.12.29", "sass/sass-spec": "*",
"squizlabs/php_codesniffer": "~3.5", "squizlabs/php_codesniffer": "~3.5",
"symfony/phpunit-bridge": "^5.1", "symfony/phpunit-bridge": "^5.1",
"twbs/bootstrap": "~4.3", "twbs/bootstrap": "~5.0",
"twbs/bootstrap4": "4.6.0",
"zurb/foundation": "~6.5" "zurb/foundation": "~6.5"
}, },
"suggest": {
"ext-iconv": "Can be used as fallback when ext-mbstring is not available",
"ext-mbstring": "For best performance, mbstring should be installed as it is faster than ext-iconv"
},
"bin": [ "bin": [
"bin/pscss" "bin/pscss"
], ],
@@ -249,9 +255,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/scssphp/scssphp/issues", "issues": "https://github.com/scssphp/scssphp/issues",
"source": "https://github.com/scssphp/scssphp/tree/v1.4.1" "source": "https://github.com/scssphp/scssphp/tree/v1.5.2"
}, },
"time": "2021-01-04T13:23:23+00:00" "time": "2021-05-18T00:05:58+00:00"
} }
], ],
"packages-dev": [ "packages-dev": [
@@ -814,16 +820,16 @@
}, },
{ {
"name": "guzzlehttp/psr7", "name": "guzzlehttp/psr7",
"version": "1.8.1", "version": "1.8.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/psr7.git", "url": "https://github.com/guzzle/psr7.git",
"reference": "35ea11d335fd638b5882ff1725228b3d35496ab1" "reference": "dc960a912984efb74d0a90222870c72c87f10c91"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/35ea11d335fd638b5882ff1725228b3d35496ab1", "url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91",
"reference": "35ea11d335fd638b5882ff1725228b3d35496ab1", "reference": "dc960a912984efb74d0a90222870c72c87f10c91",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -883,9 +889,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/psr7/issues", "issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/1.8.1" "source": "https://github.com/guzzle/psr7/tree/1.8.2"
}, },
"time": "2021-03-21T16:25:00+00:00" "time": "2021-04-26T09:17:50+00:00"
}, },
{ {
"name": "myclabs/deep-copy", "name": "myclabs/deep-copy",
@@ -2470,16 +2476,16 @@
}, },
{ {
"name": "symfony/browser-kit", "name": "symfony/browser-kit",
"version": "v4.4.20", "version": "v4.4.22",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/browser-kit.git", "url": "https://github.com/symfony/browser-kit.git",
"reference": "cfa8d92f95294747e3abc04969efee51ed374424" "reference": "4c8b42b4aae93517e8f67d68c5cbe69413e3e3c1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/cfa8d92f95294747e3abc04969efee51ed374424", "url": "https://api.github.com/repos/symfony/browser-kit/zipball/4c8b42b4aae93517e8f67d68c5cbe69413e3e3c1",
"reference": "cfa8d92f95294747e3abc04969efee51ed374424", "reference": "4c8b42b4aae93517e8f67d68c5cbe69413e3e3c1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2521,7 +2527,7 @@
"description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/browser-kit/tree/v4.4.20" "source": "https://github.com/symfony/browser-kit/tree/v4.4.22"
}, },
"funding": [ "funding": [
{ {
@@ -2537,20 +2543,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-02-18T10:52:56+00:00" "time": "2021-04-08T07:40:10+00:00"
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v4.4.21", "version": "v4.4.23",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "1ba4560dbbb9fcf5ae28b61f71f49c678086cf23" "reference": "1ab187ac21d41d7d34a4f529091a1f5d0bb2924f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/1ba4560dbbb9fcf5ae28b61f71f49c678086cf23", "url": "https://api.github.com/repos/symfony/console/zipball/1ab187ac21d41d7d34a4f529091a1f5d0bb2924f",
"reference": "1ba4560dbbb9fcf5ae28b61f71f49c678086cf23", "reference": "1ab187ac21d41d7d34a4f529091a1f5d0bb2924f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2610,7 +2616,7 @@
"description": "Eases the creation of beautiful and testable command line interfaces", "description": "Eases the creation of beautiful and testable command line interfaces",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v4.4.21" "source": "https://github.com/symfony/console/tree/v4.4.23"
}, },
"funding": [ "funding": [
{ {
@@ -2626,20 +2632,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-03-26T09:23:24+00:00" "time": "2021-05-10T12:53:15+00:00"
}, },
{ {
"name": "symfony/css-selector", "name": "symfony/css-selector",
"version": "v4.4.20", "version": "v4.4.22",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/css-selector.git", "url": "https://github.com/symfony/css-selector.git",
"reference": "f907d3e53ecb2a5fad8609eb2f30525287a734c8" "reference": "01c77324d1d47efbfd7891f62a7c256c69330115"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/f907d3e53ecb2a5fad8609eb2f30525287a734c8", "url": "https://api.github.com/repos/symfony/css-selector/zipball/01c77324d1d47efbfd7891f62a7c256c69330115",
"reference": "f907d3e53ecb2a5fad8609eb2f30525287a734c8", "reference": "01c77324d1d47efbfd7891f62a7c256c69330115",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2675,7 +2681,7 @@
"description": "Converts CSS selectors to XPath expressions", "description": "Converts CSS selectors to XPath expressions",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/css-selector/tree/v4.4.20" "source": "https://github.com/symfony/css-selector/tree/v4.4.22"
}, },
"funding": [ "funding": [
{ {
@@ -2691,7 +2697,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-01-27T09:09:26+00:00" "time": "2021-04-07T15:47:03+00:00"
}, },
{ {
"name": "symfony/dom-crawler", "name": "symfony/dom-crawler",
@@ -2930,16 +2936,16 @@
}, },
{ {
"name": "symfony/finder", "name": "symfony/finder",
"version": "v4.4.20", "version": "v4.4.23",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/finder.git", "url": "https://github.com/symfony/finder.git",
"reference": "2543795ab1570df588b9bbd31e1a2bd7037b94f6" "reference": "67b77716f517e3f864759232e1201e7aa2ab0e82"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/2543795ab1570df588b9bbd31e1a2bd7037b94f6", "url": "https://api.github.com/repos/symfony/finder/zipball/67b77716f517e3f864759232e1201e7aa2ab0e82",
"reference": "2543795ab1570df588b9bbd31e1a2bd7037b94f6", "reference": "67b77716f517e3f864759232e1201e7aa2ab0e82",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2971,7 +2977,7 @@
"description": "Finds files and directories via an intuitive fluent interface", "description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/finder/tree/v4.4.20" "source": "https://github.com/symfony/finder/tree/v4.4.23"
}, },
"funding": [ "funding": [
{ {
@@ -2987,7 +2993,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-02-12T10:48:09+00:00" "time": "2021-05-09T09:13:09+00:00"
}, },
{ {
"name": "symfony/polyfill-ctype", "name": "symfony/polyfill-ctype",
@@ -3404,16 +3410,16 @@
}, },
{ {
"name": "symfony/process", "name": "symfony/process",
"version": "v4.4.20", "version": "v4.4.22",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/process.git", "url": "https://github.com/symfony/process.git",
"reference": "7e950b6366d4da90292c2e7fa820b3c1842b965a" "reference": "f5481b22729d465acb1cea3455fc04ce84b0148b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/7e950b6366d4da90292c2e7fa820b3c1842b965a", "url": "https://api.github.com/repos/symfony/process/zipball/f5481b22729d465acb1cea3455fc04ce84b0148b",
"reference": "7e950b6366d4da90292c2e7fa820b3c1842b965a", "reference": "f5481b22729d465acb1cea3455fc04ce84b0148b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -3445,7 +3451,7 @@
"description": "Executes commands in sub-processes", "description": "Executes commands in sub-processes",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/process/tree/v4.4.20" "source": "https://github.com/symfony/process/tree/v4.4.22"
}, },
"funding": [ "funding": [
{ {
@@ -3461,25 +3467,25 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-01-27T09:09:26+00:00" "time": "2021-04-07T16:22:29+00:00"
}, },
{ {
"name": "symfony/service-contracts", "name": "symfony/service-contracts",
"version": "v2.2.0", "version": "v2.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/service-contracts.git", "url": "https://github.com/symfony/service-contracts.git",
"reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1" "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/d15da7ba4957ffb8f1747218be9e1a121fd298a1", "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb",
"reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1", "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.2.5", "php": ">=7.2.5",
"psr/container": "^1.0" "psr/container": "^1.1"
}, },
"suggest": { "suggest": {
"symfony/service-implementation": "" "symfony/service-implementation": ""
@@ -3487,7 +3493,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.2-dev" "dev-main": "2.4-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/contracts", "name": "symfony/contracts",
@@ -3524,7 +3530,7 @@
"standards" "standards"
], ],
"support": { "support": {
"source": "https://github.com/symfony/service-contracts/tree/master" "source": "https://github.com/symfony/service-contracts/tree/v2.4.0"
}, },
"funding": [ "funding": [
{ {
@@ -3540,20 +3546,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2020-09-07T11:33:47+00:00" "time": "2021-04-01T10:43:52+00:00"
}, },
{ {
"name": "symfony/yaml", "name": "symfony/yaml",
"version": "v4.4.21", "version": "v4.4.22",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/yaml.git", "url": "https://github.com/symfony/yaml.git",
"reference": "3871c720871029f008928244e56cf43497da7e9d" "reference": "1c2fd24147961525eaefb65b11987cab75adab59"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/3871c720871029f008928244e56cf43497da7e9d", "url": "https://api.github.com/repos/symfony/yaml/zipball/1c2fd24147961525eaefb65b11987cab75adab59",
"reference": "3871c720871029f008928244e56cf43497da7e9d", "reference": "1c2fd24147961525eaefb65b11987cab75adab59",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -3595,7 +3601,7 @@
"description": "Loads and dumps YAML files", "description": "Loads and dumps YAML files",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/yaml/tree/v4.4.21" "source": "https://github.com/symfony/yaml/tree/v4.4.22"
}, },
"funding": [ "funding": [
{ {
@@ -3611,7 +3617,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-03-05T17:58:50+00:00" "time": "2021-04-23T12:09:37+00:00"
}, },
{ {
"name": "theseer/tokenizer", "name": "theseer/tokenizer",

View File

@@ -29,7 +29,7 @@ private static $installed = array (
'aliases' => 'aliases' =>
array ( array (
), ),
'reference' => '1acb94e85744589877484a13af715394b3558bd2', 'reference' => '6e5839ded659cc193765e47cfdb9ccfeb31d8050',
'name' => 'getgrav/grav-plugin-admin', 'name' => 'getgrav/grav-plugin-admin',
), ),
'versions' => 'versions' =>
@@ -41,7 +41,7 @@ private static $installed = array (
'aliases' => 'aliases' =>
array ( array (
), ),
'reference' => '1acb94e85744589877484a13af715394b3558bd2', 'reference' => '6e5839ded659cc193765e47cfdb9ccfeb31d8050',
), ),
'laminas/laminas-xml' => 'laminas/laminas-xml' =>
array ( array (
@@ -79,12 +79,12 @@ private static $installed = array (
), ),
'scssphp/scssphp' => 'scssphp/scssphp' =>
array ( array (
'pretty_version' => 'v1.4.1', 'pretty_version' => 'v1.5.2',
'version' => '1.4.1.0', 'version' => '1.5.2.0',
'aliases' => 'aliases' =>
array ( array (
), ),
'reference' => 'ba86c963b94ec7ebd6e19d90cdab90d89667dbf7', 'reference' => '6fe16f169f55f5e793474fb210aac0a4481619e5',
), ),
'symfony/polyfill-php72' => 'symfony/polyfill-php72' =>
array ( array (

View File

@@ -191,17 +191,17 @@
}, },
{ {
"name": "scssphp/scssphp", "name": "scssphp/scssphp",
"version": "v1.4.1", "version": "v1.5.2",
"version_normalized": "1.4.1.0", "version_normalized": "1.5.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/scssphp/scssphp.git", "url": "https://github.com/scssphp/scssphp.git",
"reference": "ba86c963b94ec7ebd6e19d90cdab90d89667dbf7" "reference": "6fe16f169f55f5e793474fb210aac0a4481619e5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/scssphp/scssphp/zipball/ba86c963b94ec7ebd6e19d90cdab90d89667dbf7", "url": "https://api.github.com/repos/scssphp/scssphp/zipball/6fe16f169f55f5e793474fb210aac0a4481619e5",
"reference": "ba86c963b94ec7ebd6e19d90cdab90d89667dbf7", "reference": "6fe16f169f55f5e793474fb210aac0a4481619e5",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -210,14 +210,20 @@
"php": ">=5.6.0" "php": ">=5.6.0"
}, },
"require-dev": { "require-dev": {
"bamarni/composer-bin-plugin": "^1.4",
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3 || ^9.4", "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3 || ^9.4",
"sass/sass-spec": "2020.12.29", "sass/sass-spec": "*",
"squizlabs/php_codesniffer": "~3.5", "squizlabs/php_codesniffer": "~3.5",
"symfony/phpunit-bridge": "^5.1", "symfony/phpunit-bridge": "^5.1",
"twbs/bootstrap": "~4.3", "twbs/bootstrap": "~5.0",
"twbs/bootstrap4": "4.6.0",
"zurb/foundation": "~6.5" "zurb/foundation": "~6.5"
}, },
"time": "2021-01-04T13:23:23+00:00", "suggest": {
"ext-iconv": "Can be used as fallback when ext-mbstring is not available",
"ext-mbstring": "For best performance, mbstring should be installed as it is faster than ext-iconv"
},
"time": "2021-05-18T00:05:58+00:00",
"bin": [ "bin": [
"bin/pscss" "bin/pscss"
], ],
@@ -255,7 +261,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/scssphp/scssphp/issues", "issues": "https://github.com/scssphp/scssphp/issues",
"source": "https://github.com/scssphp/scssphp/tree/v1.4.1" "source": "https://github.com/scssphp/scssphp/tree/v1.5.2"
}, },
"install-path": "../scssphp/scssphp" "install-path": "../scssphp/scssphp"
} }

View File

@@ -6,7 +6,7 @@
'aliases' => 'aliases' =>
array ( array (
), ),
'reference' => '1acb94e85744589877484a13af715394b3558bd2', 'reference' => '6e5839ded659cc193765e47cfdb9ccfeb31d8050',
'name' => 'getgrav/grav-plugin-admin', 'name' => 'getgrav/grav-plugin-admin',
), ),
'versions' => 'versions' =>
@@ -18,7 +18,7 @@
'aliases' => 'aliases' =>
array ( array (
), ),
'reference' => '1acb94e85744589877484a13af715394b3558bd2', 'reference' => '6e5839ded659cc193765e47cfdb9ccfeb31d8050',
), ),
'laminas/laminas-xml' => 'laminas/laminas-xml' =>
array ( array (
@@ -56,12 +56,12 @@
), ),
'scssphp/scssphp' => 'scssphp/scssphp' =>
array ( array (
'pretty_version' => 'v1.4.1', 'pretty_version' => 'v1.5.2',
'version' => '1.4.1.0', 'version' => '1.5.2.0',
'aliases' => 'aliases' =>
array ( array (
), ),
'reference' => 'ba86c963b94ec7ebd6e19d90cdab90d89667dbf7', 'reference' => '6fe16f169f55f5e793474fb210aac0a4481619e5',
), ),
'symfony/polyfill-php72' => 'symfony/polyfill-php72' =>
array ( array (

View File

@@ -45,3 +45,27 @@ To enable the full `sass-spec` compatibility tests:
Run the following command from the root directory to check the code for "sniffs". Run the following command from the root directory to check the code for "sniffs".
vendor/bin/phpcs --standard=PSR12 --extensions=php bin src tests *.php vendor/bin/phpcs --standard=PSR12 --extensions=php bin src tests *.php
## Static Analysis
`scssphp` uses [phpstan](https://phpstan.org/) for static analysis.
Run the following command from the root directory to analyse the codebase:
make phpstan
As most of the codebase is composed of legacy code which cannot be type-checked
fully, the setup contains a baseline file with all errors we want to ignore. In
particular, we ignore all errors related to not specifying the types inside arrays
when these arrays correspond to the representation of Sass values and Sass AST nodes
in the parser and compiler.
When contributing, the proper process to deal with static analysis is the following:
1. Make your change in the codebase
2. Run `make phpstan`
3. Fix errors reported by phpstan when possible
4. Repeat step 2 and 3 until nothing gets fixed anymore at step 3
5. Run `make phpstan-baseline` to regenerate the phpstan baseline
Additions to the baseline will be reviewed to avoid ignoring errors that should have
been fixed.

View File

@@ -32,6 +32,8 @@ $inputFile = null;
$changeDir = false; $changeDir = false;
$encoding = false; $encoding = false;
$sourceMap = false; $sourceMap = false;
$embedSources = false;
$embedSourceMap = false;
/** /**
* Parse argument * Parse argument
@@ -60,24 +62,28 @@ function parseArgument(&$i, $options) {
} }
} }
$arguments = [];
for ($i = 1; $i < $argc; $i++) { for ($i = 1; $i < $argc; $i++) {
if ($argv[$i] === '-?' || $argv[$i] === '-h' || $argv[$i] === '--help') { if ($argv[$i] === '-?' || $argv[$i] === '-h' || $argv[$i] === '--help') {
$exe = $argv[0]; $exe = $argv[0];
$HELP = <<<EOT $HELP = <<<EOT
Usage: $exe [options] [input-file] Usage: $exe [options] [input-file] [output-file]
Options include: Options include:
--help Show this message [-h, -?] --help Show this message [-h, -?]
--continue-on-error [deprecated] Ignored --continue-on-error [deprecated] Ignored
--debug-info [deprecated] Ignored [-g] --debug-info [deprecated] Ignored [-g]
--dump-tree Dump formatted parse tree [-T] --dump-tree [deprecated] Dump formatted parse tree [-T]
--iso8859-1 Use iso8859-1 encoding instead of default utf-8 --iso8859-1 Use iso8859-1 encoding instead of default utf-8
--line-numbers [deprecated] Ignored [--line-comments] --line-numbers [deprecated] Ignored [--line-comments]
--load-path=PATH Set import path [-I] --load-path=PATH Set import path [-I]
--precision=N [deprecated] Ignored. (default 10) [-p] --precision=N [deprecated] Ignored. (default 10) [-p]
--sourcemap Create source map file --sourcemap Create source map file
--embed-sources Embed source file contents in source maps
--embed-source-map Embed the source map contents in CSS (default if writing to stdout)
--style=FORMAT Set the output style (compressed or expanded) [-s, -t] --style=FORMAT Set the output style (compressed or expanded) [-s, -t]
--version Print the version [-v] --version Print the version [-v]
@@ -117,6 +123,16 @@ EOT;
continue; continue;
} }
if ($argv[$i] === '--embed-sources') {
$embedSources = true;
continue;
}
if ($argv[$i] === '--embed-source-map') {
$embedSourceMap = true;
continue;
}
if ($argv[$i] === '-T' || $argv[$i] === '--dump-tree') { if ($argv[$i] === '-T' || $argv[$i] === '--dump-tree') {
$dumpTree = true; $dumpTree = true;
continue; continue;
@@ -144,14 +160,12 @@ EOT;
continue; continue;
} }
if (file_exists($argv[$i])) { $arguments[] = $argv[$i];
$inputFile = $argv[$i];
continue;
}
} }
if ($inputFile) { if (isset($arguments[0]) && file_exists($arguments[0])) {
$inputFile = $arguments[0];
$data = file_get_contents($inputFile); $data = file_get_contents($inputFile);
} else { } else {
$data = ''; $data = '';
@@ -166,6 +180,8 @@ if ($dumpTree) {
print_r(json_decode(json_encode($parser->parse($data)), true)); print_r(json_decode(json_encode($parser->parse($data)), true));
fwrite(STDERR, 'Warning: the --dump-tree option is deprecated. Use proper debugging tools instead.');
exit(); exit();
} }
@@ -184,8 +200,26 @@ if ($style) {
} }
} }
$outputFile = isset($arguments[1]) ? $arguments[1] : null;
$sourceMapFile = null;
if ($sourceMap) { if ($sourceMap) {
$scss->setSourceMap(Compiler::SOURCE_MAP_INLINE); $sourceMapOptions = array(
'outputSourceFiles' => $embedSources,
);
if ($embedSourceMap || $outputFile === null) {
$scss->setSourceMap(Compiler::SOURCE_MAP_INLINE);
} else {
$sourceMapFile = $outputFile . '.map';
$sourceMapOptions['sourceMapWriteTo'] = $sourceMapFile;
$sourceMapOptions['sourceMapURL'] = basename($sourceMapFile);
$sourceMapOptions['sourceMapBasepath'] = getcwd();
$sourceMapOptions['sourceMapFilename'] = basename($outputFile);
$scss->setSourceMap(Compiler::SOURCE_MAP_FILE);
}
$scss->setSourceMapOptions($sourceMapOptions);
} }
if ($encoding) { if ($encoding) {
@@ -193,8 +227,18 @@ if ($encoding) {
} }
try { try {
echo $scss->compile($data, $inputFile); $result = $scss->compileString($data, $inputFile);
} catch (SassException $e) { } catch (SassException $e) {
fwrite(STDERR, $e->getMessage()."\n"); fwrite(STDERR, 'Error: '.$e->getMessage()."\n");
exit(1); exit(1);
} }
if ($outputFile) {
file_put_contents($outputFile, $result->getCss());
if ($sourceMapFile !== null && $result->getSourceMap() !== null) {
file_put_contents($sourceMapFile, $result->getSourceMap());
}
} else {
echo $result->getCss();
}

View File

@@ -30,12 +30,18 @@
"ext-json": "*", "ext-json": "*",
"ext-ctype": "*" "ext-ctype": "*"
}, },
"suggest": {
"ext-mbstring": "For best performance, mbstring should be installed as it is faster than ext-iconv",
"ext-iconv": "Can be used as fallback when ext-mbstring is not available"
},
"require-dev": { "require-dev": {
"bamarni/composer-bin-plugin": "^1.4",
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3 || ^9.4", "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3 || ^9.4",
"sass/sass-spec": "2020.12.29", "sass/sass-spec": "*",
"squizlabs/php_codesniffer": "~3.5", "squizlabs/php_codesniffer": "~3.5",
"symfony/phpunit-bridge": "^5.1", "symfony/phpunit-bridge": "^5.1",
"twbs/bootstrap": "~4.3", "twbs/bootstrap": "~5.0",
"twbs/bootstrap4": "4.6.0",
"zurb/foundation": "~6.5" "zurb/foundation": "~6.5"
}, },
"repositories": [ "repositories": [
@@ -43,16 +49,34 @@
"type": "package", "type": "package",
"package": { "package": {
"name": "sass/sass-spec", "name": "sass/sass-spec",
"version": "2020.12.29", "version": "2021.05.10",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sass/sass-spec.git", "url": "https://github.com/sass/sass-spec.git",
"reference": "d975d33146fb679a6b359ceca329012f02e4a794" "reference": "b9bf24a936528f333fb30ee59ca550c6da551c11"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sass/sass-spec/zipball/d975d33146fb679a6b359ceca329012f02e4a794", "url": "https://api.github.com/repos/sass/sass-spec/zipball/b9bf24a936528f333fb30ee59ca550c6da551c11",
"reference": "d975d33146fb679a6b359ceca329012f02e4a794", "reference": "b9bf24a936528f333fb30ee59ca550c6da551c11",
"shasum": ""
}
}
},
{
"type": "package",
"package": {
"name": "twbs/bootstrap4",
"version": "v4.6.0",
"source": {
"type": "git",
"url": "https://github.com/twbs/bootstrap.git",
"reference": "6ffb0b48e455430f8a5359ed689ad64c1143fac2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twbs/bootstrap/zipball/6ffb0b48e455430f8a5359ed689ad64c1143fac2",
"reference": "6ffb0b48e455430f8a5359ed689ad64c1143fac2",
"shasum": "" "shasum": ""
} }
} }

View File

@@ -4,36 +4,18 @@ if (version_compare(PHP_VERSION, '5.6') < 0) {
throw new \Exception('scssphp requires PHP 5.6 or above'); throw new \Exception('scssphp requires PHP 5.6 or above');
} }
if (! class_exists('ScssPhp\ScssPhp\Version', false)) { if (! class_exists('ScssPhp\ScssPhp\Version')) {
include_once __DIR__ . '/src/Base/Range.php'; spl_autoload_register(function ($class) {
include_once __DIR__ . '/src/OutputStyle.php'; if (0 !== strpos($class, 'ScssPhp\ScssPhp\\')) {
include_once __DIR__ . '/src/Block.php'; // Not a ScssPhp class
include_once __DIR__ . '/src/Cache.php'; return;
include_once __DIR__ . '/src/Colors.php'; }
include_once __DIR__ . '/src/Compiler.php';
include_once __DIR__ . '/src/Compiler/Environment.php'; $subClass = substr($class, strlen('ScssPhp\ScssPhp\\'));
include_once __DIR__ . '/src/Exception/SassException.php'; $path = __DIR__ . '/src/' . str_replace('\\', '/', $subClass) . '.php';
include_once __DIR__ . '/src/Exception/SassScriptException.php';
include_once __DIR__ . '/src/Exception/CompilerException.php'; if (file_exists($path)) {
include_once __DIR__ . '/src/Exception/ParserException.php'; require $path;
include_once __DIR__ . '/src/Exception/RangeException.php'; }
include_once __DIR__ . '/src/Exception/ServerException.php'; });
include_once __DIR__ . '/src/Formatter.php';
include_once __DIR__ . '/src/Formatter/Compact.php';
include_once __DIR__ . '/src/Formatter/Compressed.php';
include_once __DIR__ . '/src/Formatter/Crunched.php';
include_once __DIR__ . '/src/Formatter/Debug.php';
include_once __DIR__ . '/src/Formatter/Expanded.php';
include_once __DIR__ . '/src/Formatter/Nested.php';
include_once __DIR__ . '/src/Formatter/OutputBlock.php';
include_once __DIR__ . '/src/Node.php';
include_once __DIR__ . '/src/Node/Number.php';
include_once __DIR__ . '/src/Parser.php';
include_once __DIR__ . '/src/SourceMap/Base64.php';
include_once __DIR__ . '/src/SourceMap/Base64VLQ.php';
include_once __DIR__ . '/src/SourceMap/SourceMapGenerator.php';
include_once __DIR__ . '/src/Type.php';
include_once __DIR__ . '/src/Util/Path.php';
include_once __DIR__ . '/src/Util.php';
include_once __DIR__ . '/src/Version.php';
} }

View File

@@ -16,10 +16,19 @@ namespace ScssPhp\ScssPhp\Base;
* Range * Range
* *
* @author Anthon Pang <anthon.pang@gmail.com> * @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/ */
class Range class Range
{ {
/**
* @var float|int
*/
public $first; public $first;
/**
* @var float|int
*/
public $last; public $last;
/** /**

View File

@@ -16,6 +16,8 @@ namespace ScssPhp\ScssPhp;
* Block * Block
* *
* @author Anthon Pang <anthon.pang@gmail.com> * @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/ */
class Block class Block
{ {
@@ -65,7 +67,7 @@ class Block
public $children; public $children;
/** /**
* @var \ScssPhp\ScssPhp\Block * @var \ScssPhp\ScssPhp\Block|null
*/ */
public $selfParent; public $selfParent;
} }

View File

@@ -30,30 +30,54 @@ use ScssPhp\ScssPhp\Version;
* SCSS cache * SCSS cache
* *
* @author Cedric Morin <cedric@yterium.com> * @author Cedric Morin <cedric@yterium.com>
*
* @internal
*/ */
class Cache class Cache
{ {
const CACHE_VERSION = 1; const CACHE_VERSION = 1;
// directory used for storing data /**
* directory used for storing data
*
* @var string|false
*/
public static $cacheDir = false; public static $cacheDir = false;
// prefix for the storing data /**
* prefix for the storing data
*
* @var string
*/
public static $prefix = 'scssphp_'; public static $prefix = 'scssphp_';
// force a refresh : 'once' for refreshing the first hit on a cache only, true to never use the cache in this hit /**
* force a refresh : 'once' for refreshing the first hit on a cache only, true to never use the cache in this hit
*
* @var bool|string
*/
public static $forceRefresh = false; public static $forceRefresh = false;
// specifies the number of seconds after which data cached will be seen as 'garbage' and potentially cleaned up /**
* specifies the number of seconds after which data cached will be seen as 'garbage' and potentially cleaned up
*
* @var int
*/
public static $gcLifetime = 604800; public static $gcLifetime = 604800;
// array of already refreshed cache if $forceRefresh==='once' /**
* array of already refreshed cache if $forceRefresh==='once'
*
* @var array<string, bool>
*/
protected static $refreshed = []; protected static $refreshed = [];
/** /**
* Constructor * Constructor
* *
* @param array $options * @param array $options
*
* @phpstan-param array{cacheDir?: string, prefix?: string, forceRefresh?: string} $options
*/ */
public function __construct($options) public function __construct($options)
{ {
@@ -85,10 +109,10 @@ class Cache
* Get the cached result of $operation on $what, * Get the cached result of $operation on $what,
* which is known as dependant from the content of $options * which is known as dependant from the content of $options
* *
* @param string $operation parse, compile... * @param string $operation parse, compile...
* @param mixed $what content key (e.g., filename to be treated) * @param mixed $what content key (e.g., filename to be treated)
* @param array $options any option that affect the operation result on the content * @param array $options any option that affect the operation result on the content
* @param integer $lastModified last modified timestamp * @param int|null $lastModified last modified timestamp
* *
* @return mixed * @return mixed
* *
@@ -128,6 +152,8 @@ class Cache
* @param mixed $what * @param mixed $what
* @param mixed $value * @param mixed $value
* @param array $options * @param array $options
*
* @return void
*/ */
public function setCache($operation, $what, $value, $options = []) public function setCache($operation, $what, $value, $options = [])
{ {
@@ -174,6 +200,8 @@ class Cache
/** /**
* Check that the cache dir exists and is writeable * Check that the cache dir exists and is writeable
* *
* @return void
*
* @throws \Exception * @throws \Exception
*/ */
public static function checkCacheDir() public static function checkCacheDir()
@@ -192,6 +220,8 @@ class Cache
/** /**
* Delete unused cached files * Delete unused cached files
*
* @return void
*/ */
public static function cleanCache() public static function cleanCache()
{ {

View File

@@ -16,6 +16,8 @@ namespace ScssPhp\ScssPhp;
* CSS Colors * CSS Colors
* *
* @author Leaf Corcoran <leafot@gmail.com> * @author Leaf Corcoran <leafot@gmail.com>
*
* @internal
*/ */
class Colors class Colors
{ {
@@ -24,13 +26,13 @@ class Colors
* *
* @see http://www.w3.org/TR/css3-color * @see http://www.w3.org/TR/css3-color
* *
* @var array * @var array<string, string>
*/ */
protected static $cssColors = [ protected static $cssColors = [
'aliceblue' => '240,248,255', 'aliceblue' => '240,248,255',
'antiquewhite' => '250,235,215', 'antiquewhite' => '250,235,215',
'cyan' => '0,255,255',
'aqua' => '0,255,255', 'aqua' => '0,255,255',
'cyan' => '0,255,255',
'aquamarine' => '127,255,212', 'aquamarine' => '127,255,212',
'azure' => '240,255,255', 'azure' => '240,255,255',
'beige' => '245,245,220', 'beige' => '245,245,220',
@@ -75,8 +77,8 @@ class Colors
'firebrick' => '178,34,34', 'firebrick' => '178,34,34',
'floralwhite' => '255,250,240', 'floralwhite' => '255,250,240',
'forestgreen' => '34,139,34', 'forestgreen' => '34,139,34',
'magenta' => '255,0,255',
'fuchsia' => '255,0,255', 'fuchsia' => '255,0,255',
'magenta' => '255,0,255',
'gainsboro' => '220,220,220', 'gainsboro' => '220,220,220',
'ghostwhite' => '248,248,255', 'ghostwhite' => '248,248,255',
'gold' => '255,215,0', 'gold' => '255,215,0',
@@ -183,7 +185,7 @@ class Colors
* *
* @param string $colorName * @param string $colorName
* *
* @return array|null * @return int[]|null
*/ */
public static function colorNameToRGBa($colorName) public static function colorNameToRGBa($colorName)
{ {
@@ -205,7 +207,7 @@ class Colors
* @param integer $r * @param integer $r
* @param integer $g * @param integer $g
* @param integer $b * @param integer $b
* @param integer $a * @param integer|float $a
* *
* @return string|null * @return string|null
*/ */

View File

@@ -0,0 +1,69 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp;
class CompilationResult
{
/**
* @var string
*/
private $css;
/**
* @var string|null
*/
private $sourceMap;
/**
* @var string[]
*/
private $includedFiles;
/**
* @param string $css
* @param string|null $sourceMap
* @param string[] $includedFiles
*/
public function __construct($css, $sourceMap, array $includedFiles)
{
$this->css = $css;
$this->sourceMap = $sourceMap;
$this->includedFiles = $includedFiles;
}
/**
* @return string
*/
public function getCss()
{
return $this->css;
}
/**
* @return string[]
*/
public function getIncludedFiles()
{
return $this->includedFiles;
}
/**
* The sourceMap content, if it was generated
*
* @return null|string
*/
public function getSourceMap()
{
return $this->sourceMap;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,77 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Compiler;
use ScssPhp\ScssPhp\CompilationResult;
/**
* @internal
*/
class CachedResult
{
/**
* @var CompilationResult
*/
private $result;
/**
* @var array<string, int>
*/
private $parsedFiles;
/**
* @var array
* @phpstan-var list<array{currentDir: string|null, path: string, filePath: string}>
*/
private $resolvedImports;
/**
* @param CompilationResult $result
* @param array<string, int> $parsedFiles
* @param array $resolvedImports
*
* @phpstan-param list<array{currentDir: string|null, path: string, filePath: string}> $resolvedImports
*/
public function __construct(CompilationResult $result, array $parsedFiles, array $resolvedImports)
{
$this->result = $result;
$this->parsedFiles = $parsedFiles;
$this->resolvedImports = $resolvedImports;
}
/**
* @return CompilationResult
*/
public function getResult()
{
return $this->result;
}
/**
* @return array<string, int>
*/
public function getParsedFiles()
{
return $this->parsedFiles;
}
/**
* @return array
*
* @phpstan-return list<array{currentDir: string|null, path: string, filePath: string}>
*/
public function getResolvedImports()
{
return $this->resolvedImports;
}
}

View File

@@ -16,16 +16,18 @@ namespace ScssPhp\ScssPhp\Compiler;
* Compiler environment * Compiler environment
* *
* @author Anthon Pang <anthon.pang@gmail.com> * @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/ */
class Environment class Environment
{ {
/** /**
* @var \ScssPhp\ScssPhp\Block * @var \ScssPhp\ScssPhp\Block|null
*/ */
public $block; public $block;
/** /**
* @var \ScssPhp\ScssPhp\Compiler\Environment * @var \ScssPhp\ScssPhp\Compiler\Environment|null
*/ */
public $parent; public $parent;

View File

@@ -16,6 +16,8 @@ namespace ScssPhp\ScssPhp\Exception;
* Compiler exception * Compiler exception
* *
* @author Oleksandr Savchenko <traveltino@gmail.com> * @author Oleksandr Savchenko <traveltino@gmail.com>
*
* @internal
*/ */
class CompilerException extends \Exception implements SassException class CompilerException extends \Exception implements SassException
{ {

View File

@@ -16,6 +16,8 @@ namespace ScssPhp\ScssPhp\Exception;
* Parser Exception * Parser Exception
* *
* @author Oleksandr Savchenko <traveltino@gmail.com> * @author Oleksandr Savchenko <traveltino@gmail.com>
*
* @internal
*/ */
class ParserException extends \Exception implements SassException class ParserException extends \Exception implements SassException
{ {

View File

@@ -16,6 +16,8 @@ namespace ScssPhp\ScssPhp\Exception;
* Range exception * Range exception
* *
* @author Anthon Pang <anthon.pang@gmail.com> * @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/ */
class RangeException extends \Exception implements SassException class RangeException extends \Exception implements SassException
{ {

View File

@@ -12,10 +12,14 @@
namespace ScssPhp\ScssPhp\Exception; namespace ScssPhp\ScssPhp\Exception;
@trigger_error(sprintf('The "%s" class is deprecated.', ServerException::class), E_USER_DEPRECATED);
/** /**
* Server Exception * Server Exception
* *
* @author Anthon Pang <anthon.pang@gmail.com> * @author Anthon Pang <anthon.pang@gmail.com>
*
* @deprecated The Scssphp server should define its own exception instead.
*/ */
class ServerException extends \Exception implements SassException class ServerException extends \Exception implements SassException
{ {

View File

@@ -19,6 +19,8 @@ use ScssPhp\ScssPhp\SourceMap\SourceMapGenerator;
* Base formatter * Base formatter
* *
* @author Leaf Corcoran <leafot@gmail.com> * @author Leaf Corcoran <leafot@gmail.com>
*
* @internal
*/ */
abstract class Formatter abstract class Formatter
{ {
@@ -78,7 +80,7 @@ abstract class Formatter
protected $currentColumn; protected $currentColumn;
/** /**
* @var \ScssPhp\ScssPhp\SourceMap\SourceMapGenerator * @var \ScssPhp\ScssPhp\SourceMap\SourceMapGenerator|null
*/ */
protected $sourceMapGenerator; protected $sourceMapGenerator;
@@ -139,6 +141,8 @@ abstract class Formatter
* Output lines inside a block * Output lines inside a block
* *
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
*
* @return void
*/ */
protected function blockLines(OutputBlock $block) protected function blockLines(OutputBlock $block)
{ {
@@ -156,9 +160,13 @@ abstract class Formatter
* Output block selectors * Output block selectors
* *
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
*
* @return void
*/ */
protected function blockSelectors(OutputBlock $block) protected function blockSelectors(OutputBlock $block)
{ {
assert(! empty($block->selectors));
$inner = $this->indentStr(); $inner = $this->indentStr();
$this->write($inner $this->write($inner
@@ -170,6 +178,8 @@ abstract class Formatter
* Output block children * Output block children
* *
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
*
* @return void
*/ */
protected function blockChildren(OutputBlock $block) protected function blockChildren(OutputBlock $block)
{ {
@@ -182,6 +192,8 @@ abstract class Formatter
* Output non-empty block * Output non-empty block
* *
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
*
* @return void
*/ */
protected function block(OutputBlock $block) protected function block(OutputBlock $block)
{ {
@@ -285,6 +297,8 @@ abstract class Formatter
* Output content * Output content
* *
* @param string $str * @param string $str
*
* @return void
*/ */
protected function write($str) protected function write($str)
{ {

View File

@@ -20,6 +20,8 @@ use ScssPhp\ScssPhp\Formatter;
* @author Leaf Corcoran <leafot@gmail.com> * @author Leaf Corcoran <leafot@gmail.com>
* *
* @deprecated since 1.4.0. Use the Compressed formatter instead. * @deprecated since 1.4.0. Use the Compressed formatter instead.
*
* @internal
*/ */
class Compact extends Formatter class Compact extends Formatter
{ {

View File

@@ -18,6 +18,8 @@ use ScssPhp\ScssPhp\Formatter;
* Compressed formatter * Compressed formatter
* *
* @author Leaf Corcoran <leafot@gmail.com> * @author Leaf Corcoran <leafot@gmail.com>
*
* @internal
*/ */
class Compressed extends Formatter class Compressed extends Formatter
{ {
@@ -67,6 +69,8 @@ class Compressed extends Formatter
*/ */
protected function blockSelectors(OutputBlock $block) protected function blockSelectors(OutputBlock $block)
{ {
assert(! empty($block->selectors));
$inner = $this->indentStr(); $inner = $this->indentStr();
$this->write( $this->write(

View File

@@ -20,6 +20,8 @@ use ScssPhp\ScssPhp\Formatter;
* @author Anthon Pang <anthon.pang@gmail.com> * @author Anthon Pang <anthon.pang@gmail.com>
* *
* @deprecated since 1.4.0. Use the Compressed formatter instead. * @deprecated since 1.4.0. Use the Compressed formatter instead.
*
* @internal
*/ */
class Crunched extends Formatter class Crunched extends Formatter
{ {
@@ -69,6 +71,8 @@ class Crunched extends Formatter
*/ */
protected function blockSelectors(OutputBlock $block) protected function blockSelectors(OutputBlock $block)
{ {
assert(! empty($block->selectors));
$inner = $this->indentStr(); $inner = $this->indentStr();
$this->write( $this->write(

View File

@@ -20,6 +20,8 @@ use ScssPhp\ScssPhp\Formatter;
* @author Anthon Pang <anthon.pang@gmail.com> * @author Anthon Pang <anthon.pang@gmail.com>
* *
* @deprecated since 1.4.0. * @deprecated since 1.4.0.
*
* @internal
*/ */
class Debug extends Formatter class Debug extends Formatter
{ {

View File

@@ -18,6 +18,8 @@ use ScssPhp\ScssPhp\Formatter;
* Expanded formatter * Expanded formatter
* *
* @author Leaf Corcoran <leafot@gmail.com> * @author Leaf Corcoran <leafot@gmail.com>
*
* @internal
*/ */
class Expanded extends Formatter class Expanded extends Formatter
{ {

View File

@@ -21,6 +21,8 @@ use ScssPhp\ScssPhp\Type;
* @author Leaf Corcoran <leafot@gmail.com> * @author Leaf Corcoran <leafot@gmail.com>
* *
* @deprecated since 1.4.0. Use the Expanded formatter instead. * @deprecated since 1.4.0. Use the Expanded formatter instead.
*
* @internal
*/ */
class Nested extends Formatter class Nested extends Formatter
{ {

View File

@@ -16,6 +16,8 @@ namespace ScssPhp\ScssPhp\Formatter;
* Output block * Output block
* *
* @author Anthon Pang <anthon.pang@gmail.com> * @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/ */
class OutputBlock class OutputBlock
{ {
@@ -30,17 +32,17 @@ class OutputBlock
public $depth; public $depth;
/** /**
* @var array * @var array|null
*/ */
public $selectors; public $selectors;
/** /**
* @var array * @var string[]
*/ */
public $lines; public $lines;
/** /**
* @var array * @var OutputBlock[]
*/ */
public $children; public $children;
@@ -50,17 +52,17 @@ class OutputBlock
public $parent; public $parent;
/** /**
* @var string * @var string|null
*/ */
public $sourceName; public $sourceName;
/** /**
* @var integer * @var integer|null
*/ */
public $sourceLine; public $sourceLine;
/** /**
* @var integer * @var integer|null
*/ */
public $sourceColumn; public $sourceColumn;
} }

View File

@@ -0,0 +1,48 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Logger;
/**
* Interface implemented by loggers for warnings and debug messages.
*
* The official Sass implementation recommends that loggers report the
* messages immediately rather than waiting for the end of the
* compilation, to provide a better debugging experience when the
* compilation does not end (error or infinite loop after the warning
* for instance).
*/
interface LoggerInterface
{
/**
* Emits a warning with the given message.
*
* If $deprecation is true, it indicates that this is a deprecation
* warning. Implementations should surface all this information to
* the end user.
*
* @param string $message
* @param bool $deprecation
*
* @return void
*/
public function warn($message, $deprecation = false);
/**
* Emits a debugging message.
*
* @param string $message
*
* @return void
*/
public function debug($message);
}

View File

@@ -0,0 +1,27 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Logger;
/**
* A logger that silently ignores all messages.
*/
class QuietLogger implements LoggerInterface
{
public function warn($message, $deprecation = false)
{
}
public function debug($message)
{
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Logger;
/**
* A logger that prints to a PHP stream (for instance stderr)
*/
class StreamLogger implements LoggerInterface
{
private $stream;
private $closeOnDestruct;
/**
* @param resource $stream A stream resource
* @param bool $closeOnDestruct If true, takes ownership of the stream and close it on destruct to avoid leaks.
*/
public function __construct($stream, $closeOnDestruct = false)
{
$this->stream = $stream;
$this->closeOnDestruct = $closeOnDestruct;
}
/**
* @internal
*/
public function __destruct()
{
if ($this->closeOnDestruct) {
fclose($this->stream);
}
}
/**
* @inheritDoc
*/
public function warn($message, $deprecation = false)
{
$prefix = ($deprecation ? 'DEPRECATION ' : '') . 'WARNING: ';
fwrite($this->stream, $prefix . $message . "\n\n");
}
/**
* @inheritDoc
*/
public function debug($message)
{
fwrite($this->stream, $message . "\n");
}
}

View File

@@ -16,6 +16,8 @@ namespace ScssPhp\ScssPhp;
* Base node * Base node
* *
* @author Anthon Pang <anthon.pang@gmail.com> * @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/ */
abstract class Node abstract class Node
{ {
@@ -30,12 +32,12 @@ abstract class Node
public $sourceIndex; public $sourceIndex;
/** /**
* @var integer * @var int|null
*/ */
public $sourceLine; public $sourceLine;
/** /**
* @var integer * @var int|null
*/ */
public $sourceColumn; public $sourceColumn;
} }

View File

@@ -12,10 +12,13 @@
namespace ScssPhp\ScssPhp\Node; namespace ScssPhp\ScssPhp\Node;
use ScssPhp\ScssPhp\Base\Range;
use ScssPhp\ScssPhp\Compiler; use ScssPhp\ScssPhp\Compiler;
use ScssPhp\ScssPhp\Exception\RangeException;
use ScssPhp\ScssPhp\Exception\SassScriptException; use ScssPhp\ScssPhp\Exception\SassScriptException;
use ScssPhp\ScssPhp\Node; use ScssPhp\ScssPhp\Node;
use ScssPhp\ScssPhp\Type; use ScssPhp\ScssPhp\Type;
use ScssPhp\ScssPhp\Util;
/** /**
* Dimension + optional units * Dimension + optional units
@@ -27,6 +30,8 @@ use ScssPhp\ScssPhp\Type;
* }} * }}
* *
* @author Anthon Pang <anthon.pang@gmail.com> * @author Anthon Pang <anthon.pang@gmail.com>
*
* @template-implements \ArrayAccess<int, mixed>
*/ */
class Number extends Node implements \ArrayAccess class Number extends Node implements \ArrayAccess
{ {
@@ -42,6 +47,7 @@ class Number extends Node implements \ArrayAccess
* @see http://www.w3.org/TR/2012/WD-css3-values-20120308/ * @see http://www.w3.org/TR/2012/WD-css3-values-20120308/
* *
* @var array * @var array
* @phpstan-var array<string, array<string, float|int>>
*/ */
protected static $unitTable = [ protected static $unitTable = [
'in' => [ 'in' => [
@@ -243,6 +249,23 @@ class Number extends Node implements \ArrayAccess
return self::getUnitString($this->numeratorUnits, $this->denominatorUnits); return self::getUnitString($this->numeratorUnits, $this->denominatorUnits);
} }
/**
* @param float|int $min
* @param float|int $max
* @param string|null $name
*
* @return float|int
* @throws SassScriptException
*/
public function valueInRange($min, $max, $name = null)
{
try {
return Util::checkRange('', new Range($min, $max), $this);
} catch (RangeException $e) {
throw SassScriptException::forArgument(sprintf('Expected %s to be within %s%s and %s%3$s', $this, $min, $this->unitStr(), $max), $name);
}
}
/** /**
* @param string|null $varName * @param string|null $varName
* *
@@ -254,7 +277,22 @@ class Number extends Node implements \ArrayAccess
return; return;
} }
throw SassScriptException::forArgument(sprintf('Expected %s to have no units', $this), $varName); throw SassScriptException::forArgument(sprintf('Expected %s to have no units.', $this), $varName);
}
/**
* @param string $unit
* @param string|null $varName
*
* @return void
*/
public function assertUnit($unit, $varName = null)
{
if ($this->hasUnit($unit)) {
return;
}
throw SassScriptException::forArgument(sprintf('Expected %s to have unit "%s".', $this, $unit), $varName);
} }
/** /**
@@ -279,6 +317,29 @@ class Number extends Node implements \ArrayAccess
)); ));
} }
/**
* Returns a copy of this number, converted to the units represented by $newNumeratorUnits and $newDenominatorUnits.
*
* This does not throw an error if this number is unitless and
* $newNumeratorUnits/$newDenominatorUnits are not empty, or vice versa. Instead,
* it treats all unitless numbers as convertible to and from all units without
* changing the value.
*
* @param string[] $newNumeratorUnits
* @param string[] $newDenominatorUnits
*
* @return Number
*
* @phpstan-param list<string> $newNumeratorUnits
* @phpstan-param list<string> $newDenominatorUnits
*
* @throws SassScriptException if this number's units are not compatible with $newNumeratorUnits and $newDenominatorUnits
*/
public function coerce(array $newNumeratorUnits, array $newDenominatorUnits)
{
return new Number($this->valueInUnits($newNumeratorUnits, $newDenominatorUnits), $newNumeratorUnits, $newDenominatorUnits);
}
/** /**
* @param Number $other * @param Number $other
* *
@@ -560,6 +621,8 @@ class Number extends Node implements \ArrayAccess
* *
* @phpstan-param list<string> $numeratorUnits * @phpstan-param list<string> $numeratorUnits
* @phpstan-param list<string> $denominatorUnits * @phpstan-param list<string> $denominatorUnits
*
* @throws SassScriptException if this number's units are not compatible with $numeratorUnits and $denominatorUnits
*/ */
private function valueInUnits(array $numeratorUnits, array $denominatorUnits) private function valueInUnits(array $numeratorUnits, array $denominatorUnits)
{ {

View File

@@ -13,11 +13,15 @@
namespace ScssPhp\ScssPhp; namespace ScssPhp\ScssPhp;
use ScssPhp\ScssPhp\Exception\ParserException; use ScssPhp\ScssPhp\Exception\ParserException;
use ScssPhp\ScssPhp\Logger\LoggerInterface;
use ScssPhp\ScssPhp\Logger\QuietLogger;
/** /**
* Parser * Parser
* *
* @author Leaf Corcoran <leafot@gmail.com> * @author Leaf Corcoran <leafot@gmail.com>
*
* @internal
*/ */
class Parser class Parser
{ {
@@ -80,7 +84,7 @@ class Parser
*/ */
private $count; private $count;
/** /**
* @var Block * @var Block|null
*/ */
private $env; private $env;
/** /**
@@ -110,18 +114,24 @@ class Parser
private $cssOnly; private $cssOnly;
/**
* @var LoggerInterface
*/
private $logger;
/** /**
* Constructor * Constructor
* *
* @api * @api
* *
* @param string $sourceName * @param string|null $sourceName
* @param integer $sourceIndex * @param integer $sourceIndex
* @param string|null $encoding * @param string|null $encoding
* @param Cache|null $cache * @param Cache|null $cache
* @param bool $cssOnly * @param bool $cssOnly
* @param LoggerInterface|null $logger
*/ */
public function __construct($sourceName, $sourceIndex = 0, $encoding = 'utf-8', Cache $cache = null, $cssOnly = false) public function __construct($sourceName, $sourceIndex = 0, $encoding = 'utf-8', Cache $cache = null, $cssOnly = false, LoggerInterface $logger = null)
{ {
$this->sourceName = $sourceName ?: '(stdin)'; $this->sourceName = $sourceName ?: '(stdin)';
$this->sourceIndex = $sourceIndex; $this->sourceIndex = $sourceIndex;
@@ -132,6 +142,7 @@ class Parser
$this->commentsSeen = []; $this->commentsSeen = [];
$this->allowVars = true; $this->allowVars = true;
$this->cssOnly = $cssOnly; $this->cssOnly = $cssOnly;
$this->logger = $logger ?: new QuietLogger();
if (empty(static::$operatorPattern)) { if (empty(static::$operatorPattern)) {
static::$operatorPattern = '([*\/%+-]|[!=]\=|\>\=?|\<\=?|and|or)'; static::$operatorPattern = '([*\/%+-]|[!=]\=|\>\=?|\<\=?|and|or)';
@@ -168,6 +179,8 @@ class Parser
* *
* @param string $msg * @param string $msg
* *
* @phpstan-return never-return
*
* @throws ParserException * @throws ParserException
* *
* @deprecated use "parseError" and throw the exception in the caller instead. * @deprecated use "parseError" and throw the exception in the caller instead.
@@ -514,6 +527,10 @@ class Parser
) { ) {
! $this->cssOnly || $this->assertPlainCssValid(false, $s); ! $this->cssOnly || $this->assertPlainCssValid(false, $s);
list($line, $column) = $this->getSourcePosition($s);
$file = $this->sourceName;
$this->logger->warn("The \"@scssphp-import-once\" directive is deprecated and will be removed in ScssPhp 2.0, in \"$file\", line $line, column $column.", true);
$this->append([Type::T_SCSSPHP_IMPORT_ONCE, $importPath], $s); $this->append([Type::T_SCSSPHP_IMPORT_ONCE, $importPath], $s);
return true; return true;
@@ -973,11 +990,6 @@ class Parser
$this->seek($s); $this->seek($s);
// misc
if ($this->literal('-->', 3)) {
return true;
}
// opening css block // opening css block
if ( if (
$this->selectors($selectors) && $this->selectors($selectors) &&
@@ -1065,10 +1077,7 @@ class Parser
} }
// extra stuff // extra stuff
if ( if ($this->matchChar(';')) {
$this->matchChar(';') ||
$this->literal('<!--', 4)
) {
return true; return true;
} }
@@ -1187,7 +1196,7 @@ class Parser
} }
$r = '/' . $regex . '/' . $this->patternModifiers; $r = '/' . $regex . '/' . $this->patternModifiers;
$result = preg_match($r, $this->buffer, $out, null, $from); $result = preg_match($r, $this->buffer, $out, 0, $from);
return $result; return $result;
} }
@@ -1255,6 +1264,7 @@ class Parser
'grayscale', 'grayscale',
'hsl', 'hsl',
'hsla', 'hsla',
'hwb',
'invert', 'invert',
'linear-gradient', 'linear-gradient',
'min', 'min',
@@ -1459,7 +1469,7 @@ class Parser
{ {
$r = '/' . $regex . '/' . $this->patternModifiers; $r = '/' . $regex . '/' . $this->patternModifiers;
if (! preg_match($r, $this->buffer, $out, null, $this->count)) { if (! preg_match($r, $this->buffer, $out, 0, $this->count)) {
return false; return false;
} }
@@ -1540,7 +1550,7 @@ class Parser
{ {
$gotWhite = false; $gotWhite = false;
while (preg_match(static::$whitePattern, $this->buffer, $m, null, $this->count)) { while (preg_match(static::$whitePattern, $this->buffer, $m, 0, $this->count)) {
if (isset($m[1]) && empty($this->commentsSeen[$this->count])) { if (isset($m[1]) && empty($this->commentsSeen[$this->count])) {
// comment that are kept in the output CSS // comment that are kept in the output CSS
$comment = []; $comment = [];
@@ -1568,6 +1578,9 @@ class Parser
$comment[] = [Type::T_COMMENT, substr($this->buffer, $p, $this->count - $p), $out]; $comment[] = [Type::T_COMMENT, substr($this->buffer, $p, $this->count - $p), $out];
} else { } else {
list($line, $column) = $this->getSourcePosition($this->count);
$file = $this->sourceName;
$this->logger->warn("Unterminated interpolations in multiline comments are deprecated and will be removed in ScssPhp 2.0, in \"$file\", line $line, column $column.", true);
$comment[] = substr($this->buffer, $this->count, 2); $comment[] = substr($this->buffer, $this->count, 2);
$this->count += 2; $this->count += 2;
@@ -1585,7 +1598,14 @@ class Parser
} else { } else {
$comment[] = $c; $comment[] = $c;
$staticComment = substr($this->buffer, $startCommentCount, $endCommentCount - $startCommentCount); $staticComment = substr($this->buffer, $startCommentCount, $endCommentCount - $startCommentCount);
$this->appendComment([Type::T_COMMENT, $staticComment, [Type::T_STRING, '', $comment]]); $commentStatement = [Type::T_COMMENT, $staticComment, [Type::T_STRING, '', $comment]];
list($line, $column) = $this->getSourcePosition($startCommentCount);
$commentStatement[self::SOURCE_LINE] = $line;
$commentStatement[self::SOURCE_COLUMN] = $column;
$commentStatement[self::SOURCE_INDEX] = $this->sourceIndex;
$this->appendComment($commentStatement);
} }
$this->commentsSeen[$startCommentCount] = true; $this->commentsSeen[$startCommentCount] = true;
@@ -3303,7 +3323,7 @@ class Parser
} }
// match comment hack // match comment hack
if (preg_match(static::$whitePattern, $this->buffer, $m, null, $this->count)) { if (preg_match(static::$whitePattern, $this->buffer, $m, 0, $this->count)) {
if (! empty($m[0])) { if (! empty($m[0])) {
$parts[] = $m[0]; $parts[] = $m[0];
$this->count += \strlen($m[0]); $this->count += \strlen($m[0]);
@@ -4074,11 +4094,20 @@ class Parser
} }
/** /**
* Save internal encoding * Save internal encoding of mbstring
*
* When mbstring.func_overload is used to replace the standard PHP string functions,
* this method configures the internal encoding to a single-byte one so that the
* behavior matches the normal behavior of PHP string functions while using the parser.
* The existing internal encoding is saved and will be restored when calling {@see restoreEncoding}.
*
* If mbstring.func_overload is not used (or does not override string functions), this method is a no-op.
*
* @return void
*/ */
private function saveEncoding() private function saveEncoding()
{ {
if (\extension_loaded('mbstring')) { if (\PHP_VERSION_ID < 80000 && \extension_loaded('mbstring') && (2 & (int) ini_get('mbstring.func_overload')) > 0) {
$this->encoding = mb_internal_encoding(); $this->encoding = mb_internal_encoding();
mb_internal_encoding('iso-8859-1'); mb_internal_encoding('iso-8859-1');
@@ -4087,6 +4116,8 @@ class Parser
/** /**
* Restore internal encoding * Restore internal encoding
*
* @return void
*/ */
private function restoreEncoding() private function restoreEncoding()
{ {

View File

@@ -16,11 +16,13 @@ namespace ScssPhp\ScssPhp\SourceMap;
* Base 64 Encode/Decode * Base 64 Encode/Decode
* *
* @author Anthon Pang <anthon.pang@gmail.com> * @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/ */
class Base64 class Base64
{ {
/** /**
* @var array * @var array<int, string>
*/ */
private static $encodingMap = [ private static $encodingMap = [
0 => 'A', 0 => 'A',
@@ -90,7 +92,7 @@ class Base64
]; ];
/** /**
* @var array * @var array<string|int, int>
*/ */
private static $decodingMap = [ private static $decodingMap = [
'A' => 0, 'A' => 0,

View File

@@ -34,6 +34,8 @@ namespace ScssPhp\ScssPhp\SourceMap;
* *
* @author John Lenz <johnlenz@google.com> * @author John Lenz <johnlenz@google.com>
* @author Anthon Pang <anthon.pang@gmail.com> * @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/ */
class Base64VLQ class Base64VLQ
{ {

View File

@@ -21,6 +21,8 @@ use ScssPhp\ScssPhp\Exception\CompilerException;
* *
* @author Josh Schmidt <oyejorge@gmail.com> * @author Josh Schmidt <oyejorge@gmail.com>
* @author Nicolas FRANÇOIS <nicolas.francois@frog-labs.com> * @author Nicolas FRANÇOIS <nicolas.francois@frog-labs.com>
*
* @internal
*/ */
class SourceMapGenerator class SourceMapGenerator
{ {
@@ -33,6 +35,7 @@ class SourceMapGenerator
* Array of default options * Array of default options
* *
* @var array * @var array
* @phpstan-var array{sourceRoot: string, sourceMapFilename: string|null, sourceMapURL: string|null, sourceMapWriteTo: string|null, outputSourceFiles: bool, sourceMapRootpath: string, sourceMapBasepath: string}
*/ */
protected $defaultOptions = [ protected $defaultOptions = [
// an optional source root, useful for relocating source files // an optional source root, useful for relocating source files
@@ -70,6 +73,7 @@ class SourceMapGenerator
* Array of mappings * Array of mappings
* *
* @var array * @var array
* @phpstan-var list<array{generated_line: int, generated_column: int, original_line: int, original_column: int, source_file: string}>
*/ */
protected $mappings = []; protected $mappings = [];
@@ -83,16 +87,24 @@ class SourceMapGenerator
/** /**
* File to content map * File to content map
* *
* @var array * @var array<string, string>
*/ */
protected $sources = []; protected $sources = [];
/**
* @var array<string, int>
*/
protected $sourceKeys = []; protected $sourceKeys = [];
/** /**
* @var array * @var array
* @phpstan-var array{sourceRoot: string, sourceMapFilename: string|null, sourceMapURL: string|null, sourceMapWriteTo: string|null, outputSourceFiles: bool, sourceMapRootpath: string, sourceMapBasepath: string}
*/ */
private $options; private $options;
/**
* @phpstan-param array{sourceRoot?: string, sourceMapFilename?: string|null, sourceMapURL?: string|null, sourceMapWriteTo?: string|null, outputSourceFiles?: bool, sourceMapRootpath?: string, sourceMapBasepath?: string} $options
*/
public function __construct(array $options = []) public function __construct(array $options = [])
{ {
$this->options = array_merge($this->defaultOptions, $options); $this->options = array_merge($this->defaultOptions, $options);
@@ -107,6 +119,8 @@ class SourceMapGenerator
* @param integer $originalLine The line number in original file * @param integer $originalLine The line number in original file
* @param integer $originalColumn The column number in original file * @param integer $originalColumn The column number in original file
* @param string $sourceFile The original source file * @param string $sourceFile The original source file
*
* @return void
*/ */
public function addMapping($generatedLine, $generatedColumn, $originalLine, $originalColumn, $sourceFile) public function addMapping($generatedLine, $generatedColumn, $originalLine, $originalColumn, $sourceFile)
{ {
@@ -129,6 +143,7 @@ class SourceMapGenerator
* @return string * @return string
* *
* @throws \ScssPhp\ScssPhp\Exception\CompilerException If the file could not be saved * @throws \ScssPhp\ScssPhp\Exception\CompilerException If the file could not be saved
* @deprecated
*/ */
public function saveMap($content) public function saveMap($content)
{ {
@@ -214,7 +229,7 @@ class SourceMapGenerator
/** /**
* Returns the sources contents * Returns the sources contents
* *
* @return array|null * @return string[]|null
*/ */
protected function getSourcesContent() protected function getSourcesContent()
{ {

View File

@@ -45,6 +45,7 @@ class Type
const T_FUNCTION_REFERENCE = 'function-reference'; const T_FUNCTION_REFERENCE = 'function-reference';
const T_FUNCTION_CALL = 'fncall'; const T_FUNCTION_CALL = 'fncall';
const T_HSL = 'hsl'; const T_HSL = 'hsl';
const T_HWB = 'hwb';
const T_IF = 'if'; const T_IF = 'if';
const T_IMPORT = 'import'; const T_IMPORT = 'import';
const T_INCLUDE = 'include'; const T_INCLUDE = 'include';

View File

@@ -14,11 +14,14 @@ namespace ScssPhp\ScssPhp;
use ScssPhp\ScssPhp\Base\Range; use ScssPhp\ScssPhp\Base\Range;
use ScssPhp\ScssPhp\Exception\RangeException; use ScssPhp\ScssPhp\Exception\RangeException;
use ScssPhp\ScssPhp\Node\Number;
/** /**
* Utilty functions * Utility functions
* *
* @author Anthon Pang <anthon.pang@gmail.com> * @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/ */
class Util class Util
{ {
@@ -26,10 +29,10 @@ class Util
* Asserts that `value` falls within `range` (inclusive), leaving * Asserts that `value` falls within `range` (inclusive), leaving
* room for slight floating-point errors. * room for slight floating-point errors.
* *
* @param string $name The name of the value. Used in the error message. * @param string $name The name of the value. Used in the error message.
* @param \ScssPhp\ScssPhp\Base\Range $range Range of values. * @param Range $range Range of values.
* @param array $value The value to check. * @param array|Number $value The value to check.
* @param string $unit The unit of the value. Used in error reporting. * @param string $unit The unit of the value. Used in error reporting.
* *
* @return mixed `value` adjusted to fall within range, if it was outside by a floating-point margin. * @return mixed `value` adjusted to fall within range, if it was outside by a floating-point margin.
* *
@@ -115,10 +118,10 @@ class Util
} }
if (\function_exists('iconv_strlen')) { if (\function_exists('iconv_strlen')) {
return @iconv_strlen($string, 'UTF-8'); return (int) @iconv_strlen($string, 'UTF-8');
} }
return strlen($string); throw new \LogicException('Either mbstring (recommended) or iconv is necessary to use Scssphp.');
} }
/** /**
@@ -155,7 +158,7 @@ class Util
return (string)iconv_substr($string, $start, $length, 'UTF-8'); return (string)iconv_substr($string, $start, $length, 'UTF-8');
} }
return substr($string, $start, $length); throw new \LogicException('Either mbstring (recommended) or iconv is necessary to use Scssphp.');
} }
/** /**
@@ -176,6 +179,6 @@ class Util
return iconv_strpos($haystack, $needle, $offset, 'UTF-8'); return iconv_strpos($haystack, $needle, $offset, 'UTF-8');
} }
return strpos($haystack, $needle, $offset); throw new \LogicException('Either mbstring (recommended) or iconv is necessary to use Scssphp.');
} }
} }

View File

@@ -0,0 +1,95 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp;
use ScssPhp\ScssPhp\Node\Number;
final class ValueConverter
{
// Prevent instantiating it
private function __construct()
{
}
/**
* Parses a value from a Scss source string.
*
* The returned value is guaranteed to be supported by the
* Compiler methods for registering custom variables. No other
* guarantee about it is provided. It should be considered
* opaque values by the caller.
*
* @param string $source
*
* @return mixed
*/
public static function parseValue($source)
{
$parser = new Parser(__CLASS__);
if (!$parser->parseValue($source, $value)) {
throw new \InvalidArgumentException(sprintf('Invalid value source "%s".', $source));
}
return $value;
}
/**
* Converts a PHP value to a Sass value
*
* The returned value is guaranteed to be supported by the
* Compiler methods for registering custom variables. No other
* guarantee about it is provided. It should be considered
* opaque values by the caller.
*
* @param mixed $value
*
* @return mixed
*/
public static function fromPhp($value)
{
if ($value instanceof Number) {
return $value;
}
if (is_array($value) && isset($value[0]) && \in_array($value[0], [Type::T_NULL, Type::T_COLOR, Type::T_KEYWORD, Type::T_LIST, Type::T_MAP, Type::T_STRING])) {
return $value;
}
if ($value === null) {
return Compiler::$null;
}
if ($value === true) {
return Compiler::$true;
}
if ($value === false) {
return Compiler::$false;
}
if ($value === '') {
return Compiler::$emptyString;
}
if (\is_int($value) || \is_float($value)) {
return new Number($value, '');
}
if (\is_string($value)) {
return [Type::T_STRING, '"', [$value]];
}
throw new \InvalidArgumentException(sprintf('Cannot convert the value of type "%s" to a Sass value.', gettype($value)));
}
}

View File

@@ -19,5 +19,5 @@ namespace ScssPhp\ScssPhp;
*/ */
class Version class Version
{ {
const VERSION = '1.4.1'; const VERSION = '1.5.2';
} }

84
vendor/scssphp/scssphp/src/Warn.php vendored Normal file
View File

@@ -0,0 +1,84 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp;
final class Warn
{
/**
* @var callable|null
* @phpstan-var (callable(string, bool): void)|null
*/
private static $callback;
/**
* Prints a warning message associated with the current `@import` or function call.
*
* This may only be called within a custom function or importer callback.
*
* @param string $message
*
* @return void
*/
public static function warning($message)
{
self::reportWarning($message, false);
}
/**
* Prints a deprecation warning message associated with the current `@import` or function call.
*
* This may only be called within a custom function or importer callback.
*
* @param string $message
*
* @return void
*/
public static function deprecation($message)
{
self::reportWarning($message, true);
}
/**
* @param callable|null $callback
*
* @return callable|null The previous warn callback
*
* @phpstan-param (callable(string, bool): void)|null $callback
*
* @phpstan-return (callable(string, bool): void)|null
*
* @internal
*/
public static function setCallback(callable $callback = null)
{
$previousCallback = self::$callback;
self::$callback = $callback;
return $previousCallback;
}
/**
* @param string $message
* @param bool $deprecation
*
* @return void
*/
private static function reportWarning($message, $deprecation)
{
if (self::$callback === null) {
throw new \BadMethodCallException('The warning Reporter may only be called within a custom function or importer callback.');
}
\call_user_func(self::$callback, $message, $deprecation);
}
}