⬇️ N°4824 rollback scssphp/scssphp update (won't be done in this branch !)

This commit is contained in:
Pierre Goiffon
2022-05-02 09:15:48 +02:00
parent c4ae94fd4c
commit 0de15d040f
61 changed files with 2573 additions and 8636 deletions

View File

@@ -14,7 +14,7 @@
"nikic/php-parser": "~4.13.2",
"pear/archive_tar": "~1.4.14",
"pelago/emogrifier": "~3.1.0",
"scssphp/scssphp": "~1.10.2",
"scssphp/scssphp": "1.0.6",
"swiftmailer/swiftmailer": "~6.3.0",
"symfony/console": "~3.4.47",
"symfony/dotenv": "~3.4.47",

29
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "781e902cab2de8cfdfefbb4a62cc1b01",
"content-hash": "2e22d4aefde79b10575e4de746f22f32",
"packages": [
{
"name": "combodo/tcpdf",
@@ -817,16 +817,16 @@
},
{
"name": "scssphp/scssphp",
"version": "v1.10.2",
"version": "1.0.6",
"source": {
"type": "git",
"url": "https://github.com/scssphp/scssphp.git",
"reference": "387f4f4abf5d99f16be16314c5ab856f81c82f46"
"reference": "5b3c9d704950d8f9637f5110c36c281ec47dc13c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/scssphp/scssphp/zipball/387f4f4abf5d99f16be16314c5ab856f81c82f46",
"reference": "387f4f4abf5d99f16be16314c5ab856f81c82f46",
"url": "https://api.github.com/repos/scssphp/scssphp/zipball/5b3c9d704950d8f9637f5110c36c281ec47dc13c",
"reference": "5b3c9d704950d8f9637f5110c36c281ec47dc13c",
"shasum": ""
},
"require": {
@@ -835,20 +835,11 @@
"php": ">=5.6.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.4",
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3 || ^9.4",
"sass/sass-spec": "*",
"squizlabs/php_codesniffer": "~3.5",
"symfony/phpunit-bridge": "^5.1",
"thoughtbot/bourbon": "^7.0",
"twbs/bootstrap": "~5.0",
"twbs/bootstrap4": "4.6.1",
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3",
"squizlabs/php_codesniffer": "~2.5",
"twbs/bootstrap": "~4.3",
"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/pscss"
],
@@ -885,9 +876,9 @@
],
"support": {
"issues": "https://github.com/scssphp/scssphp/issues",
"source": "https://github.com/scssphp/scssphp/tree/v1.10.2"
"source": "https://github.com/scssphp/scssphp/tree/master"
},
"time": "2022-03-02T21:15:09+00:00"
"time": "2019-12-12T05:00:52+00:00"
},
{
"name": "swiftmailer/swiftmailer",

View File

@@ -766,29 +766,13 @@ return array(
'ScalarOqlExpression' => $baseDir . '/core/oql/oqlquery.class.inc.php',
'ScssPhp\\ScssPhp\\Base\\Range' => $vendorDir . '/scssphp/scssphp/src/Base/Range.php',
'ScssPhp\\ScssPhp\\Block' => $vendorDir . '/scssphp/scssphp/src/Block.php',
'ScssPhp\\ScssPhp\\Block\\AtRootBlock' => $vendorDir . '/scssphp/scssphp/src/Block/AtRootBlock.php',
'ScssPhp\\ScssPhp\\Block\\CallableBlock' => $vendorDir . '/scssphp/scssphp/src/Block/CallableBlock.php',
'ScssPhp\\ScssPhp\\Block\\ContentBlock' => $vendorDir . '/scssphp/scssphp/src/Block/ContentBlock.php',
'ScssPhp\\ScssPhp\\Block\\DirectiveBlock' => $vendorDir . '/scssphp/scssphp/src/Block/DirectiveBlock.php',
'ScssPhp\\ScssPhp\\Block\\EachBlock' => $vendorDir . '/scssphp/scssphp/src/Block/EachBlock.php',
'ScssPhp\\ScssPhp\\Block\\ElseBlock' => $vendorDir . '/scssphp/scssphp/src/Block/ElseBlock.php',
'ScssPhp\\ScssPhp\\Block\\ElseifBlock' => $vendorDir . '/scssphp/scssphp/src/Block/ElseifBlock.php',
'ScssPhp\\ScssPhp\\Block\\ForBlock' => $vendorDir . '/scssphp/scssphp/src/Block/ForBlock.php',
'ScssPhp\\ScssPhp\\Block\\IfBlock' => $vendorDir . '/scssphp/scssphp/src/Block/IfBlock.php',
'ScssPhp\\ScssPhp\\Block\\MediaBlock' => $vendorDir . '/scssphp/scssphp/src/Block/MediaBlock.php',
'ScssPhp\\ScssPhp\\Block\\NestedPropertyBlock' => $vendorDir . '/scssphp/scssphp/src/Block/NestedPropertyBlock.php',
'ScssPhp\\ScssPhp\\Block\\WhileBlock' => $vendorDir . '/scssphp/scssphp/src/Block/WhileBlock.php',
'ScssPhp\\ScssPhp\\Cache' => $vendorDir . '/scssphp/scssphp/src/Cache.php',
'ScssPhp\\ScssPhp\\Colors' => $vendorDir . '/scssphp/scssphp/src/Colors.php',
'ScssPhp\\ScssPhp\\CompilationResult' => $vendorDir . '/scssphp/scssphp/src/CompilationResult.php',
'ScssPhp\\ScssPhp\\Compiler' => $vendorDir . '/scssphp/scssphp/src/Compiler.php',
'ScssPhp\\ScssPhp\\Compiler\\CachedResult' => $vendorDir . '/scssphp/scssphp/src/Compiler/CachedResult.php',
'ScssPhp\\ScssPhp\\Compiler\\Environment' => $vendorDir . '/scssphp/scssphp/src/Compiler/Environment.php',
'ScssPhp\\ScssPhp\\Exception\\CompilerException' => $vendorDir . '/scssphp/scssphp/src/Exception/CompilerException.php',
'ScssPhp\\ScssPhp\\Exception\\ParserException' => $vendorDir . '/scssphp/scssphp/src/Exception/ParserException.php',
'ScssPhp\\ScssPhp\\Exception\\RangeException' => $vendorDir . '/scssphp/scssphp/src/Exception/RangeException.php',
'ScssPhp\\ScssPhp\\Exception\\SassException' => $vendorDir . '/scssphp/scssphp/src/Exception/SassException.php',
'ScssPhp\\ScssPhp\\Exception\\SassScriptException' => $vendorDir . '/scssphp/scssphp/src/Exception/SassScriptException.php',
'ScssPhp\\ScssPhp\\Exception\\ServerException' => $vendorDir . '/scssphp/scssphp/src/Exception/ServerException.php',
'ScssPhp\\ScssPhp\\Formatter' => $vendorDir . '/scssphp/scssphp/src/Formatter.php',
'ScssPhp\\ScssPhp\\Formatter\\Compact' => $vendorDir . '/scssphp/scssphp/src/Formatter/Compact.php',
@@ -798,22 +782,15 @@ return array(
'ScssPhp\\ScssPhp\\Formatter\\Expanded' => $vendorDir . '/scssphp/scssphp/src/Formatter/Expanded.php',
'ScssPhp\\ScssPhp\\Formatter\\Nested' => $vendorDir . '/scssphp/scssphp/src/Formatter/Nested.php',
'ScssPhp\\ScssPhp\\Formatter\\OutputBlock' => $vendorDir . '/scssphp/scssphp/src/Formatter/OutputBlock.php',
'ScssPhp\\ScssPhp\\Logger\\LoggerInterface' => $vendorDir . '/scssphp/scssphp/src/Logger/LoggerInterface.php',
'ScssPhp\\ScssPhp\\Logger\\QuietLogger' => $vendorDir . '/scssphp/scssphp/src/Logger/QuietLogger.php',
'ScssPhp\\ScssPhp\\Logger\\StreamLogger' => $vendorDir . '/scssphp/scssphp/src/Logger/StreamLogger.php',
'ScssPhp\\ScssPhp\\Node' => $vendorDir . '/scssphp/scssphp/src/Node.php',
'ScssPhp\\ScssPhp\\Node\\Number' => $vendorDir . '/scssphp/scssphp/src/Node/Number.php',
'ScssPhp\\ScssPhp\\OutputStyle' => $vendorDir . '/scssphp/scssphp/src/OutputStyle.php',
'ScssPhp\\ScssPhp\\Parser' => $vendorDir . '/scssphp/scssphp/src/Parser.php',
'ScssPhp\\ScssPhp\\SourceMap\\Base64' => $vendorDir . '/scssphp/scssphp/src/SourceMap/Base64.php',
'ScssPhp\\ScssPhp\\SourceMap\\Base64VLQ' => $vendorDir . '/scssphp/scssphp/src/SourceMap/Base64VLQ.php',
'ScssPhp\\ScssPhp\\SourceMap\\SourceMapGenerator' => $vendorDir . '/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php',
'ScssPhp\\ScssPhp\\Type' => $vendorDir . '/scssphp/scssphp/src/Type.php',
'ScssPhp\\ScssPhp\\Util' => $vendorDir . '/scssphp/scssphp/src/Util.php',
'ScssPhp\\ScssPhp\\Util\\Path' => $vendorDir . '/scssphp/scssphp/src/Util/Path.php',
'ScssPhp\\ScssPhp\\ValueConverter' => $vendorDir . '/scssphp/scssphp/src/ValueConverter.php',
'ScssPhp\\ScssPhp\\Version' => $vendorDir . '/scssphp/scssphp/src/Version.php',
'ScssPhp\\ScssPhp\\Warn' => $vendorDir . '/scssphp/scssphp/src/Warn.php',
'SearchMenuNode' => $baseDir . '/application/menunode.class.inc.php',
'SecurityException' => $baseDir . '/core/coreexception.class.inc.php',
'SeparatorPopupMenuItem' => $baseDir . '/application/applicationextension.inc.php',

View File

@@ -1036,29 +1036,13 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
'ScalarOqlExpression' => __DIR__ . '/../..' . '/core/oql/oqlquery.class.inc.php',
'ScssPhp\\ScssPhp\\Base\\Range' => __DIR__ . '/..' . '/scssphp/scssphp/src/Base/Range.php',
'ScssPhp\\ScssPhp\\Block' => __DIR__ . '/..' . '/scssphp/scssphp/src/Block.php',
'ScssPhp\\ScssPhp\\Block\\AtRootBlock' => __DIR__ . '/..' . '/scssphp/scssphp/src/Block/AtRootBlock.php',
'ScssPhp\\ScssPhp\\Block\\CallableBlock' => __DIR__ . '/..' . '/scssphp/scssphp/src/Block/CallableBlock.php',
'ScssPhp\\ScssPhp\\Block\\ContentBlock' => __DIR__ . '/..' . '/scssphp/scssphp/src/Block/ContentBlock.php',
'ScssPhp\\ScssPhp\\Block\\DirectiveBlock' => __DIR__ . '/..' . '/scssphp/scssphp/src/Block/DirectiveBlock.php',
'ScssPhp\\ScssPhp\\Block\\EachBlock' => __DIR__ . '/..' . '/scssphp/scssphp/src/Block/EachBlock.php',
'ScssPhp\\ScssPhp\\Block\\ElseBlock' => __DIR__ . '/..' . '/scssphp/scssphp/src/Block/ElseBlock.php',
'ScssPhp\\ScssPhp\\Block\\ElseifBlock' => __DIR__ . '/..' . '/scssphp/scssphp/src/Block/ElseifBlock.php',
'ScssPhp\\ScssPhp\\Block\\ForBlock' => __DIR__ . '/..' . '/scssphp/scssphp/src/Block/ForBlock.php',
'ScssPhp\\ScssPhp\\Block\\IfBlock' => __DIR__ . '/..' . '/scssphp/scssphp/src/Block/IfBlock.php',
'ScssPhp\\ScssPhp\\Block\\MediaBlock' => __DIR__ . '/..' . '/scssphp/scssphp/src/Block/MediaBlock.php',
'ScssPhp\\ScssPhp\\Block\\NestedPropertyBlock' => __DIR__ . '/..' . '/scssphp/scssphp/src/Block/NestedPropertyBlock.php',
'ScssPhp\\ScssPhp\\Block\\WhileBlock' => __DIR__ . '/..' . '/scssphp/scssphp/src/Block/WhileBlock.php',
'ScssPhp\\ScssPhp\\Cache' => __DIR__ . '/..' . '/scssphp/scssphp/src/Cache.php',
'ScssPhp\\ScssPhp\\Colors' => __DIR__ . '/..' . '/scssphp/scssphp/src/Colors.php',
'ScssPhp\\ScssPhp\\CompilationResult' => __DIR__ . '/..' . '/scssphp/scssphp/src/CompilationResult.php',
'ScssPhp\\ScssPhp\\Compiler' => __DIR__ . '/..' . '/scssphp/scssphp/src/Compiler.php',
'ScssPhp\\ScssPhp\\Compiler\\CachedResult' => __DIR__ . '/..' . '/scssphp/scssphp/src/Compiler/CachedResult.php',
'ScssPhp\\ScssPhp\\Compiler\\Environment' => __DIR__ . '/..' . '/scssphp/scssphp/src/Compiler/Environment.php',
'ScssPhp\\ScssPhp\\Exception\\CompilerException' => __DIR__ . '/..' . '/scssphp/scssphp/src/Exception/CompilerException.php',
'ScssPhp\\ScssPhp\\Exception\\ParserException' => __DIR__ . '/..' . '/scssphp/scssphp/src/Exception/ParserException.php',
'ScssPhp\\ScssPhp\\Exception\\RangeException' => __DIR__ . '/..' . '/scssphp/scssphp/src/Exception/RangeException.php',
'ScssPhp\\ScssPhp\\Exception\\SassException' => __DIR__ . '/..' . '/scssphp/scssphp/src/Exception/SassException.php',
'ScssPhp\\ScssPhp\\Exception\\SassScriptException' => __DIR__ . '/..' . '/scssphp/scssphp/src/Exception/SassScriptException.php',
'ScssPhp\\ScssPhp\\Exception\\ServerException' => __DIR__ . '/..' . '/scssphp/scssphp/src/Exception/ServerException.php',
'ScssPhp\\ScssPhp\\Formatter' => __DIR__ . '/..' . '/scssphp/scssphp/src/Formatter.php',
'ScssPhp\\ScssPhp\\Formatter\\Compact' => __DIR__ . '/..' . '/scssphp/scssphp/src/Formatter/Compact.php',
@@ -1068,22 +1052,15 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
'ScssPhp\\ScssPhp\\Formatter\\Expanded' => __DIR__ . '/..' . '/scssphp/scssphp/src/Formatter/Expanded.php',
'ScssPhp\\ScssPhp\\Formatter\\Nested' => __DIR__ . '/..' . '/scssphp/scssphp/src/Formatter/Nested.php',
'ScssPhp\\ScssPhp\\Formatter\\OutputBlock' => __DIR__ . '/..' . '/scssphp/scssphp/src/Formatter/OutputBlock.php',
'ScssPhp\\ScssPhp\\Logger\\LoggerInterface' => __DIR__ . '/..' . '/scssphp/scssphp/src/Logger/LoggerInterface.php',
'ScssPhp\\ScssPhp\\Logger\\QuietLogger' => __DIR__ . '/..' . '/scssphp/scssphp/src/Logger/QuietLogger.php',
'ScssPhp\\ScssPhp\\Logger\\StreamLogger' => __DIR__ . '/..' . '/scssphp/scssphp/src/Logger/StreamLogger.php',
'ScssPhp\\ScssPhp\\Node' => __DIR__ . '/..' . '/scssphp/scssphp/src/Node.php',
'ScssPhp\\ScssPhp\\Node\\Number' => __DIR__ . '/..' . '/scssphp/scssphp/src/Node/Number.php',
'ScssPhp\\ScssPhp\\OutputStyle' => __DIR__ . '/..' . '/scssphp/scssphp/src/OutputStyle.php',
'ScssPhp\\ScssPhp\\Parser' => __DIR__ . '/..' . '/scssphp/scssphp/src/Parser.php',
'ScssPhp\\ScssPhp\\SourceMap\\Base64' => __DIR__ . '/..' . '/scssphp/scssphp/src/SourceMap/Base64.php',
'ScssPhp\\ScssPhp\\SourceMap\\Base64VLQ' => __DIR__ . '/..' . '/scssphp/scssphp/src/SourceMap/Base64VLQ.php',
'ScssPhp\\ScssPhp\\SourceMap\\SourceMapGenerator' => __DIR__ . '/..' . '/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php',
'ScssPhp\\ScssPhp\\Type' => __DIR__ . '/..' . '/scssphp/scssphp/src/Type.php',
'ScssPhp\\ScssPhp\\Util' => __DIR__ . '/..' . '/scssphp/scssphp/src/Util.php',
'ScssPhp\\ScssPhp\\Util\\Path' => __DIR__ . '/..' . '/scssphp/scssphp/src/Util/Path.php',
'ScssPhp\\ScssPhp\\ValueConverter' => __DIR__ . '/..' . '/scssphp/scssphp/src/ValueConverter.php',
'ScssPhp\\ScssPhp\\Version' => __DIR__ . '/..' . '/scssphp/scssphp/src/Version.php',
'ScssPhp\\ScssPhp\\Warn' => __DIR__ . '/..' . '/scssphp/scssphp/src/Warn.php',
'SearchMenuNode' => __DIR__ . '/../..' . '/application/menunode.class.inc.php',
'SecurityException' => __DIR__ . '/../..' . '/core/coreexception.class.inc.php',
'SeparatorPopupMenuItem' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',

View File

@@ -853,17 +853,17 @@
},
{
"name": "scssphp/scssphp",
"version": "v1.10.2",
"version_normalized": "1.10.2.0",
"version": "1.0.6",
"version_normalized": "1.0.6.0",
"source": {
"type": "git",
"url": "https://github.com/scssphp/scssphp.git",
"reference": "387f4f4abf5d99f16be16314c5ab856f81c82f46"
"reference": "5b3c9d704950d8f9637f5110c36c281ec47dc13c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/scssphp/scssphp/zipball/387f4f4abf5d99f16be16314c5ab856f81c82f46",
"reference": "387f4f4abf5d99f16be16314c5ab856f81c82f46",
"url": "https://api.github.com/repos/scssphp/scssphp/zipball/5b3c9d704950d8f9637f5110c36c281ec47dc13c",
"reference": "5b3c9d704950d8f9637f5110c36c281ec47dc13c",
"shasum": ""
},
"require": {
@@ -872,21 +872,12 @@
"php": ">=5.6.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.4",
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3 || ^9.4",
"sass/sass-spec": "*",
"squizlabs/php_codesniffer": "~3.5",
"symfony/phpunit-bridge": "^5.1",
"thoughtbot/bourbon": "^7.0",
"twbs/bootstrap": "~5.0",
"twbs/bootstrap4": "4.6.1",
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3",
"squizlabs/php_codesniffer": "~2.5",
"twbs/bootstrap": "~4.3",
"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"
},
"time": "2022-03-02T21:15:09+00:00",
"time": "2019-12-12T05:00:52+00:00",
"bin": [
"bin/pscss"
],
@@ -924,7 +915,7 @@
],
"support": {
"issues": "https://github.com/scssphp/scssphp/issues",
"source": "https://github.com/scssphp/scssphp/tree/v1.10.2"
"source": "https://github.com/scssphp/scssphp/tree/master"
},
"install-path": "../scssphp/scssphp"
},

View File

@@ -5,7 +5,7 @@
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '8c60e05b1a1d7e135bcf0cbf0d1bf337a623ff15',
'reference' => 'c4ae94fd4ca204c8d94f19a0f58f24492d015d9b',
'name' => '__root__',
'dev' => true,
),
@@ -16,7 +16,7 @@
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '8c60e05b1a1d7e135bcf0cbf0d1bf337a623ff15',
'reference' => 'c4ae94fd4ca204c8d94f19a0f58f24492d015d9b',
'dev_requirement' => false,
),
'combodo/tcpdf' => array(
@@ -176,12 +176,12 @@
),
),
'scssphp/scssphp' => array(
'pretty_version' => 'v1.10.2',
'version' => '1.10.2.0',
'pretty_version' => '1.0.6',
'version' => '1.0.6.0',
'type' => 'library',
'install_path' => __DIR__ . '/../scssphp/scssphp',
'aliases' => array(),
'reference' => '387f4f4abf5d99f16be16314c5ab856f81c82f46',
'reference' => '5b3c9d704950d8f9637f5110c36c281ec47dc13c',
'dev_requirement' => false,
),
'swiftmailer/swiftmailer' => array(

View File

@@ -1,12 +1,12 @@
# scssphp
### <https://scssphp.github.io/scssphp>
### <http://scssphp.github.io/scssphp>
![Build](https://github.com/scssphp/scssphp/workflows/CI/badge.svg)
[![Build](https://travis-ci.org/scssphp/scssphp.svg?branch=master)](http://travis-ci.org/scssphp/scssphp)
[![License](https://poser.pugx.org/scssphp/scssphp/license)](https://packagist.org/packages/scssphp/scssphp)
`scssphp` is a compiler for SCSS written in PHP.
Checkout the homepage, <https://scssphp.github.io/scssphp>, for directions on how to use.
Checkout the homepage, <http://scssphp.github.io/scssphp>, for directions on how to use.
## Running Tests
@@ -23,7 +23,8 @@ 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.
* `SassSpecTest.php` extracts tests from the `sass/sass-spec` repository.
* `ScssTest.php` extracts (ruby) `scss` tests from the `tests/scss_test.rb` file.
* `ServerTest.php` contains functional tests for the `Server` class.
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,41 +32,16 @@ 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`. It also
updates the list of excluded specs from sass-spec.
This will compile all the tests, and save results into `tests/outputs`.
To enable the full `sass-spec` compatibility tests:
To enable the `scss` compatibility tests:
TEST_SASS_SPEC=1 vendor/bin/phpunit tests
TEST_SCSS_COMPAT=1 vendor/bin/phpunit tests
## Coding Standard
`scssphp` source conforms to [PSR12](https://www.php-fig.org/psr/psr-12/).
`scssphp` source conforms to [PSR2](http://www.php-fig.org/psr/psr-2/).
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
## 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.
vendor/bin/phpcs --standard=PSR2 bin src tests

View File

@@ -1,10 +1,9 @@
#!/usr/bin/env php
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -20,26 +19,26 @@ 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;
$style = null;
$loadPaths = [];
$loadPaths = null;
$precision = null;
$dumpTree = false;
$inputFile = null;
$changeDir = false;
$debugInfo = false;
$lineNumbers = false;
$ignoreErrors = false;
$encoding = false;
$sourceMap = false;
$embedSources = false;
$embedSourceMap = false;
/**
* Parse argument
*
* @param int $i
* @param string[] $options
* @param integer $i
* @param array $options
*
* @return string|null
*/
@@ -62,29 +61,25 @@ function parseArgument(&$i, $options) {
}
}
$arguments = [];
for ($i = 1; $i < $argc; $i++) {
if ($argv[$i] === '-?' || $argv[$i] === '-h' || $argv[$i] === '--help') {
$exe = $argv[0];
$HELP = <<<EOT
Usage: $exe [options] [input-file] [output-file]
Usage: $exe [options] [input-file]
Options include:
--help Show this message [-h, -?]
--continue-on-error [deprecated] Ignored
--debug-info [deprecated] Ignored [-g]
--dump-tree [deprecated] Dump formatted parse tree [-T]
--continue-on-error Continue compilation (as best as possible) when error encountered
--debug-info Annotate selectors with CSS referring to the source file and line number [-g]
--dump-tree Dump formatted parse tree [-T]
--iso8859-1 Use iso8859-1 encoding instead of default utf-8
--line-numbers [deprecated] Ignored [--line-comments]
--line-numbers Annotate selectors with comments referring to the source file and line number [--line-comments]
--load-path=PATH Set import path [-I]
--precision=N [deprecated] Ignored. (default 10) [-p]
--precision=N Set decimal number precision (default 10) [-p]
--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 format (compact, compressed, crunched, expanded, or nested) [-s, -t]
--version Print the version [-v]
EOT;
@@ -95,15 +90,13 @@ EOT;
exit(Version::VERSION . "\n");
}
// Keep parsing --continue-on-error to avoid BC breaks for scripts using it
if ($argv[$i] === '--continue-on-error') {
// TODO report it as a warning ?
$ignoreErrors = true;
continue;
}
// Keep parsing it to avoid BC breaks for scripts using it
if ($argv[$i] === '-g' || $argv[$i] === '--debug-info') {
// TODO report it as a warning ?
$debugInfo = true;
continue;
}
@@ -112,9 +105,8 @@ EOT;
continue;
}
// Keep parsing it to avoid BC breaks for scripts using it
if ($argv[$i] === '--line-numbers' || $argv[$i] === '--line-comments') {
// TODO report it as a warning ?
$lineNumbers = true;
continue;
}
@@ -123,16 +115,6 @@ EOT;
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') {
$dumpTree = true;
continue;
@@ -148,25 +130,34 @@ EOT;
$value = parseArgument($i, array('-I', '--load-path'));
if (isset($value)) {
$loadPaths[] = $value;
$loadPaths = $value;
continue;
}
// Keep parsing --precision to avoid BC breaks for scripts using it
$value = parseArgument($i, array('-p', '--precision'));
if (isset($value)) {
// TODO report it as a warning ?
$precision = $value;
continue;
}
$arguments[] = $argv[$i];
if (file_exists($argv[$i])) {
$inputFile = $argv[$i];
continue;
}
}
if (isset($arguments[0]) && file_exists($arguments[0])) {
$inputFile = $arguments[0];
if ($inputFile) {
$data = file_get_contents($inputFile);
$newWorkingDir = dirname(realpath($inputFile));
$oldWorkingDir = getcwd();
if ($oldWorkingDir !== $newWorkingDir) {
$changeDir = chdir($newWorkingDir);
$inputFile = basename($inputFile);
}
} else {
$data = '';
@@ -180,65 +171,45 @@ if ($dumpTree) {
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();
}
$scss = new Compiler();
if ($debugInfo) {
$scss->setLineNumberStyle(Compiler::DEBUG_INFO);
}
if ($lineNumbers) {
$scss->setLineNumberStyle(Compiler::LINE_COMMENTS);
}
if ($ignoreErrors) {
$scss->setIgnoreErrors($ignoreErrors);
}
if ($loadPaths) {
$scss->setImportPaths($loadPaths);
$scss->setImportPaths(explode(PATH_SEPARATOR, $loadPaths));
}
if ($precision) {
$scss->setNumberPrecision($precision);
}
if ($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));
}
$scss->setFormatter('ScssPhp\\ScssPhp\\Formatter\\' . ucfirst($style));
}
$outputFile = isset($arguments[1]) ? $arguments[1] : null;
$sourceMapFile = null;
if ($sourceMap) {
$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);
$scss->setSourceMap(Compiler::SOURCE_MAP_INLINE);
}
if ($encoding) {
$scss->setEncoding($encoding);
}
try {
$result = $scss->compileString($data, $inputFile);
} catch (SassException $e) {
fwrite(STDERR, 'Error: '.$e->getMessage()."\n");
exit(1);
}
echo $scss->compile($data, $inputFile);
if ($outputFile) {
file_put_contents($outputFile, $result->getCss());
if ($sourceMapFile !== null && $result->getSourceMap() !== null) {
file_put_contents($sourceMapFile, $result->getSourceMap());
}
} else {
echo $result->getCss();
if ($changeDir) {
chdir($oldWorkingDir);
}

View File

@@ -30,82 +30,22 @@
"ext-json": "*",
"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": {
"bamarni/composer-bin-plugin": "^1.4",
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3 || ^9.4",
"sass/sass-spec": "*",
"squizlabs/php_codesniffer": "~3.5",
"symfony/phpunit-bridge": "^5.1",
"thoughtbot/bourbon": "^7.0",
"twbs/bootstrap": "~5.0",
"twbs/bootstrap4": "4.6.1",
"squizlabs/php_codesniffer": "~2.5",
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3",
"twbs/bootstrap": "~4.3",
"zurb/foundation": "~6.5"
},
"repositories": [
{
"type": "package",
"package": {
"name": "sass/sass-spec",
"version": "2022.02.24",
"source": {
"type": "git",
"url": "https://github.com/sass/sass-spec.git",
"reference": "f41b9bfb9a3013392f2136c79f7f3356f15fb8ba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sass/sass-spec/zipball/f41b9bfb9a3013392f2136c79f7f3356f15fb8ba",
"reference": "f41b9bfb9a3013392f2136c79f7f3356f15fb8ba",
"shasum": ""
}
}
},
{
"type": "package",
"package": {
"name": "thoughtbot/bourbon",
"version": "v7.0.0",
"source": {
"type": "git",
"url": "https://github.com/thoughtbot/bourbon.git",
"reference": "fbe338ee6807e7f7aa996d82c8a16f248bb149b3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thoughtbot/bourbon/zipball/fbe338ee6807e7f7aa996d82c8a16f248bb149b3",
"reference": "fbe338ee6807e7f7aa996d82c8a16f248bb149b3",
"shasum": ""
}
}
},
{
"type": "package",
"package": {
"name": "twbs/bootstrap4",
"version": "v4.6.1",
"source": {
"type": "git",
"url": "https://github.com/twbs/bootstrap.git",
"reference": "043a03c95a2ad6738f85b65e53b9dbdfb03b8d10"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twbs/bootstrap/zipball/043a03c95a2ad6738f85b65e53b9dbdfb03b8d10",
"reference": "043a03c95a2ad6738f85b65e53b9dbdfb03b8d10",
"shasum": ""
}
}
}
],
"minimum-stability": "dev",
"bin": ["bin/pscss"],
"config": {
"sort-packages": true,
"allow-plugins": {
"bamarni/composer-bin-plugin": true
}
"archive": {
"exclude": [
"/Makefile",
"/.gitattributes",
"/.gitignore",
"/.travis.yml",
"/phpunit.xml.dist",
"/tests"
]
}
}

View File

@@ -1,12 +0,0 @@
<?xml version="1.0"?>
<ruleset name="PSR12 (adapted for PHP 5.6+)">
<rule ref="PSR12">
<!-- Ignore this PHP 7.1+ sniff as long as we support PHP 5.6+ -->
<exclude name="PSR12.Properties.ConstantVisibility.NotFound"/>
<!-- This sniff doesn't ignore comment blocks -->
<!--
<exclude name="Generic.Files.LineLength"/>
-->
</rule>
</ruleset>

View File

@@ -1,21 +1,34 @@
<?php
if (version_compare(PHP_VERSION, '5.6') < 0) {
throw new \Exception('scssphp requires PHP 5.6 or above');
}
if (! class_exists('ScssPhp\ScssPhp\Version')) {
spl_autoload_register(function ($class) {
if (0 !== strpos($class, 'ScssPhp\ScssPhp\\')) {
// Not a ScssPhp class
return;
}
$subClass = substr($class, strlen('ScssPhp\ScssPhp\\'));
$path = __DIR__ . '/src/' . str_replace('\\', '/', $subClass) . '.php';
if (file_exists($path)) {
require $path;
}
});
if (! class_exists('ScssPhp\ScssPhp\Version', false)) {
include_once __DIR__ . '/src/Base/Range.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/CompilerException.php';
include_once __DIR__ . '/src/Exception/ParserException.php';
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.php';
include_once __DIR__ . '/src/Version.php';
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2015-2020 Leaf Corcoran
* @copyright 2015-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,26 +15,17 @@ namespace ScssPhp\ScssPhp\Base;
* Range
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
class Range
{
/**
* @var float|int
*/
public $first;
/**
* @var float|int
*/
public $last;
/**
* Initialize range
*
* @param int|float $first
* @param int|float $last
* @param integer|float $first
* @param integer|float $last
*/
public function __construct($first, $last)
{
@@ -46,9 +36,9 @@ class Range
/**
* Test for inclusion in range
*
* @param int|float $value
* @param integer|float $value
*
* @return bool
* @return boolean
*/
public function includes($value)
{

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,18 +15,16 @@ namespace ScssPhp\ScssPhp;
* Block
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
class Block
{
/**
* @var string|null
* @var string
*/
public $type;
/**
* @var Block|null
* @var \ScssPhp\ScssPhp\Block
*/
public $parent;
@@ -37,22 +34,22 @@ class Block
public $sourceName;
/**
* @var int
* @var integer
*/
public $sourceIndex;
/**
* @var int
* @var integer
*/
public $sourceLine;
/**
* @var int
* @var integer
*/
public $sourceColumn;
/**
* @var array|null
* @var array
*/
public $selectors;
@@ -67,7 +64,7 @@ class Block
public $children;
/**
* @var Block|null
* @var \ScssPhp\ScssPhp\Block
*/
public $selfParent;
}

View File

@@ -1,37 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class AtRootBlock extends Block
{
/**
* @var array|null
*/
public $selector;
/**
* @var array|null
*/
public $with;
public function __construct()
{
$this->type = Type::T_AT_ROOT;
}
}

View File

@@ -1,45 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Compiler\Environment;
/**
* @internal
*/
class CallableBlock extends Block
{
/**
* @var string
*/
public $name;
/**
* @var array|null
*/
public $args;
/**
* @var Environment|null
*/
public $parentEnv;
/**
* @param string $type
*/
public function __construct($type)
{
$this->type = $type;
}
}

View File

@@ -1,38 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Compiler\Environment;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class ContentBlock extends Block
{
/**
* @var array|null
*/
public $child;
/**
* @var Environment|null
*/
public $scope;
public function __construct()
{
$this->type = Type::T_INCLUDE;
}
}

View File

@@ -1,37 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class DirectiveBlock extends Block
{
/**
* @var string|array
*/
public $name;
/**
* @var string|array|null
*/
public $value;
public function __construct()
{
$this->type = Type::T_DIRECTIVE;
}
}

View File

@@ -1,37 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class EachBlock extends Block
{
/**
* @var string[]
*/
public $vars = [];
/**
* @var array
*/
public $list;
public function __construct()
{
$this->type = Type::T_EACH;
}
}

View File

@@ -1,27 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class ElseBlock extends Block
{
public function __construct()
{
$this->type = Type::T_ELSE;
}
}

View File

@@ -1,32 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class ElseifBlock extends Block
{
/**
* @var array
*/
public $cond;
public function __construct()
{
$this->type = Type::T_ELSEIF;
}
}

View File

@@ -1,47 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class ForBlock extends Block
{
/**
* @var string
*/
public $var;
/**
* @var array
*/
public $start;
/**
* @var array
*/
public $end;
/**
* @var bool
*/
public $until;
public function __construct()
{
$this->type = Type::T_FOR;
}
}

View File

@@ -1,37 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class IfBlock extends Block
{
/**
* @var array
*/
public $cond;
/**
* @var array<ElseifBlock|ElseBlock>
*/
public $cases = [];
public function __construct()
{
$this->type = Type::T_IF;
}
}

View File

@@ -1,37 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class MediaBlock extends Block
{
/**
* @var string|array|null
*/
public $value;
/**
* @var array|null
*/
public $queryList;
public function __construct()
{
$this->type = Type::T_MEDIA;
}
}

View File

@@ -1,37 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class NestedPropertyBlock extends Block
{
/**
* @var bool
*/
public $hasValue;
/**
* @var array
*/
public $prefix;
public function __construct()
{
$this->type = Type::T_NESTED_PROPERTY;
}
}

View File

@@ -1,32 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class WhileBlock extends Block
{
/**
* @var array
*/
public $cond;
public function __construct()
{
$this->type = Type::T_WHILE;
}
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -13,7 +12,6 @@
namespace ScssPhp\ScssPhp;
use Exception;
use ScssPhp\ScssPhp\Version;
/**
* The scss cache manager.
@@ -24,60 +22,37 @@ use ScssPhp\ScssPhp\Version;
* taking in account options that affects the result
*
* The cache manager is agnostic about data format and only the operation is expected to be described by string
*
*/
/**
* SCSS cache
*
* @author Cedric Morin <cedric@yterium.com>
*
* @internal
* @author Cedric Morin
*/
class Cache
{
const CACHE_VERSION = 1;
/**
* directory used for storing data
*
* @var string|false
*/
// directory used for storing data
public static $cacheDir = false;
/**
* prefix for the storing data
*
* @var string
*/
// prefix for the storing data
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
*
* @var bool|string
*/
// force a refresh : 'once' for refreshing the first hit on a cache only, true to never use the cache in this hit
public static $forceRefresh = false;
/**
* specifies the number of seconds after which data cached will be seen as 'garbage' and potentially cleaned up
*
* @var int
*/
// specifies the number of seconds after which data cached will be seen as 'garbage' and potentially cleaned up
public static $gcLifetime = 604800;
/**
* array of already refreshed cache if $forceRefresh==='once'
*
* @var array<string, bool>
*/
// array of already refreshed cache if $forceRefresh==='once'
protected static $refreshed = [];
/**
* Constructor
*
* @param array $options
*
* @phpstan-param array{cacheDir?: string, prefix?: string, forceRefresh?: string} $options
*/
public function __construct($options)
{
@@ -109,10 +84,10 @@ class Cache
* Get the cached result of $operation on $what,
* which is known as dependant from the content of $options
*
* @param string $operation parse, compile...
* @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 int|null $lastModified last modified timestamp
* @param string $operation parse, compile...
* @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 integer $lastModified last modified timestamp
*
* @return mixed
*
@@ -122,20 +97,18 @@ class Cache
{
$fileCache = self::$cacheDir . self::cacheName($operation, $what, $options);
if (
((self::$forceRefresh === false) || (self::$forceRefresh === 'once' &&
if (((self::$forceRefresh === false) || (self::$forceRefresh === 'once' &&
isset(self::$refreshed[$fileCache]))) && file_exists($fileCache)
) {
$cacheTime = filemtime($fileCache);
if (
(\is_null($lastModified) || $cacheTime > $lastModified) &&
if ((is_null($lastModified) || $cacheTime > $lastModified) &&
$cacheTime + self::$gcLifetime > time()
) {
$c = file_get_contents($fileCache);
$c = unserialize($c);
if (\is_array($c) && isset($c['value'])) {
if (is_array($c) && isset($c['value'])) {
return $c['value'];
}
}
@@ -152,8 +125,6 @@ class Cache
* @param mixed $what
* @param mixed $value
* @param array $options
*
* @return void
*/
public function setCache($operation, $what, $value, $options = [])
{
@@ -161,7 +132,6 @@ class Cache
$c = ['value' => $value];
$c = serialize($c);
file_put_contents($fileCache, $c);
if (self::$forceRefresh === 'once') {
@@ -183,7 +153,6 @@ class Cache
{
$t = [
'version' => self::CACHE_VERSION,
'scssphpVersion' => Version::VERSION,
'operation' => $operation,
'what' => $what,
'options' => $options
@@ -200,8 +169,6 @@ class Cache
/**
* Check that the cache dir exists and is writeable
*
* @return void
*
* @throws \Exception
*/
public static function checkCacheDir()
@@ -210,7 +177,9 @@ class Cache
self::$cacheDir = rtrim(self::$cacheDir, '/') . '/';
if (! is_dir(self::$cacheDir)) {
throw new Exception('Cache directory doesn\'t exist: ' . self::$cacheDir);
if (! mkdir(self::$cacheDir)) {
throw new Exception('Cache directory couldn\'t be created: ' . self::$cacheDir);
}
}
if (! is_writable(self::$cacheDir)) {
@@ -220,8 +189,6 @@ class Cache
/**
* Delete unused cached files
*
* @return void
*/
public static function cleanCache()
{

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,8 +15,6 @@ namespace ScssPhp\ScssPhp;
* CSS Colors
*
* @author Leaf Corcoran <leafot@gmail.com>
*
* @internal
*/
class Colors
{
@@ -26,13 +23,12 @@ class Colors
*
* @see http://www.w3.org/TR/css3-color
*
* @var array<string, string>
* @var array
*/
protected static $cssColors = [
'aliceblue' => '240,248,255',
'antiquewhite' => '250,235,215',
'aqua' => '0,255,255',
'cyan' => '0,255,255',
'aquamarine' => '127,255,212',
'azure' => '240,255,255',
'beige' => '245,245,220',
@@ -50,12 +46,13 @@ class Colors
'cornflowerblue' => '100,149,237',
'cornsilk' => '255,248,220',
'crimson' => '220,20,60',
'cyan' => '0,255,255',
'darkblue' => '0,0,139',
'darkcyan' => '0,139,139',
'darkgoldenrod' => '184,134,11',
'darkgray' => '169,169,169',
'darkgrey' => '169,169,169',
'darkgreen' => '0,100,0',
'darkgrey' => '169,169,169',
'darkkhaki' => '189,183,107',
'darkmagenta' => '139,0,139',
'darkolivegreen' => '85,107,47',
@@ -78,15 +75,14 @@ class Colors
'floralwhite' => '255,250,240',
'forestgreen' => '34,139,34',
'fuchsia' => '255,0,255',
'magenta' => '255,0,255',
'gainsboro' => '220,220,220',
'ghostwhite' => '248,248,255',
'gold' => '255,215,0',
'goldenrod' => '218,165,32',
'gray' => '128,128,128',
'grey' => '128,128,128',
'green' => '0,128,0',
'greenyellow' => '173,255,47',
'grey' => '128,128,128',
'honeydew' => '240,255,240',
'hotpink' => '255,105,180',
'indianred' => '205,92,92',
@@ -102,8 +98,8 @@ class Colors
'lightcyan' => '224,255,255',
'lightgoldenrodyellow' => '250,250,210',
'lightgray' => '211,211,211',
'lightgrey' => '211,211,211',
'lightgreen' => '144,238,144',
'lightgrey' => '211,211,211',
'lightpink' => '255,182,193',
'lightsalmon' => '255,160,122',
'lightseagreen' => '32,178,170',
@@ -115,6 +111,7 @@ class Colors
'lime' => '0,255,0',
'limegreen' => '50,205,50',
'linen' => '250,240,230',
'magenta' => '255,0,255',
'maroon' => '128,0,0',
'mediumaquamarine' => '102,205,170',
'mediumblue' => '0,0,205',
@@ -148,6 +145,7 @@ class Colors
'plum' => '221,160,221',
'powderblue' => '176,224,230',
'purple' => '128,0,128',
'rebeccapurple' => '102,51,153',
'red' => '255,0,0',
'rosybrown' => '188,143,143',
'royalblue' => '65,105,225',
@@ -169,6 +167,7 @@ class Colors
'teal' => '0,128,128',
'thistle' => '216,191,216',
'tomato' => '255,99,71',
'transparent' => '0,0,0,0',
'turquoise' => '64,224,208',
'violet' => '238,130,238',
'wheat' => '245,222,179',
@@ -176,8 +175,6 @@ class Colors
'whitesmoke' => '245,245,245',
'yellow' => '255,255,0',
'yellowgreen' => '154,205,50',
'rebeccapurple' => '102,51,153',
'transparent' => '0,0,0,0',
];
/**
@@ -185,11 +182,11 @@ class Colors
*
* @param string $colorName
*
* @return int[]|null
* @return array|null
*/
public static function colorNameToRGBa($colorName)
{
if (\is_string($colorName) && isset(static::$cssColors[$colorName])) {
if (is_string($colorName) && isset(static::$cssColors[$colorName])) {
$rgba = explode(',', static::$cssColors[$colorName]);
// only case with opacity is transparent, with opacity=0, so we can intval on opacity also
@@ -204,10 +201,10 @@ class Colors
/**
* Reverse conversion : from RGBA to a color name if possible
*
* @param int $r
* @param int $g
* @param int $b
* @param int|float $a
* @param integer $r
* @param integer $g
* @param integer $b
* @param integer $a
*
* @return string|null
*/
@@ -220,26 +217,28 @@ class Colors
}
if ($a < 1) {
# specific case we dont' revert according to spec
#if (! $a && ! $r && ! $g && ! $b) {
# return 'transparent';
#}
return null;
}
if (\is_null($reverseColorTable)) {
if (is_null($reverseColorTable)) {
$reverseColorTable = [];
foreach (static::$cssColors as $name => $rgb_str) {
$rgb_str = explode(',', $rgb_str);
if (
\count($rgb_str) == 3 &&
! isset($reverseColorTable[\intval($rgb_str[0])][\intval($rgb_str[1])][\intval($rgb_str[2])])
) {
$reverseColorTable[\intval($rgb_str[0])][\intval($rgb_str[1])][\intval($rgb_str[2])] = $name;
if (count($rgb_str) == 3) {
$reverseColorTable[intval($rgb_str[0])][intval($rgb_str[1])][intval($rgb_str[2])] = $name;
}
}
}
if (isset($reverseColorTable[\intval($r)][\intval($g)][\intval($b)])) {
return $reverseColorTable[\intval($r)][\intval($g)][\intval($b)];
if (isset($reverseColorTable[intval($r)][intval($g)][intval($b)])) {
return $reverseColorTable[intval($r)][intval($g)][intval($b)];
}
return null;

View File

@@ -1,69 +0,0 @@
<?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

@@ -1,77 +0,0 @@
<?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

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,41 +15,19 @@ namespace ScssPhp\ScssPhp\Compiler;
* Compiler environment
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
class Environment
{
/**
* @var \ScssPhp\ScssPhp\Block|null
* @var \ScssPhp\ScssPhp\Block
*/
public $block;
/**
* @var \ScssPhp\ScssPhp\Compiler\Environment|null
* @var \ScssPhp\ScssPhp\Compiler\Environment
*/
public $parent;
/**
* @var Environment|null
*/
public $declarationScopeParent;
/**
* @var Environment|null
*/
public $parentStore;
/**
* @var array|null
*/
public $selectors;
/**
* @var string|null
*/
public $marker;
/**
* @var array
*/
@@ -62,7 +39,7 @@ class Environment
public $storeUnreduced;
/**
* @var int
* @var integer
*/
public $depth;
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,9 +15,7 @@ namespace ScssPhp\ScssPhp\Exception;
* Compiler exception
*
* @author Oleksandr Savchenko <traveltino@gmail.com>
*
* @internal
*/
class CompilerException extends \Exception implements SassException
class CompilerException extends \Exception
{
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,43 +15,7 @@ namespace ScssPhp\ScssPhp\Exception;
* Parser Exception
*
* @author Oleksandr Savchenko <traveltino@gmail.com>
*
* @internal
*/
class ParserException extends \Exception implements SassException
class ParserException extends \Exception
{
/**
* @var array|null
* @phpstan-var array{string, int, int}|null
*/
private $sourcePosition;
/**
* Get source position
*
* @api
*
* @return array|null
* @phpstan-return array{string, int, int}|null
*/
public function getSourcePosition()
{
return $this->sourcePosition;
}
/**
* Set source position
*
* @api
*
* @param array $sourcePosition
*
* @return void
*
* @phpstan-param array{string, int, int} $sourcePosition
*/
public function setSourcePosition($sourcePosition)
{
$this->sourcePosition = $sourcePosition;
}
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,9 +15,7 @@ namespace ScssPhp\ScssPhp\Exception;
* Range exception
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
class RangeException extends \Exception implements SassException
class RangeException extends \Exception
{
}

View File

@@ -1,7 +0,0 @@
<?php
namespace ScssPhp\ScssPhp\Exception;
interface SassException
{
}

View File

@@ -1,32 +0,0 @@
<?php
namespace ScssPhp\ScssPhp\Exception;
/**
* An exception thrown by SassScript.
*
* This class does not implement SassException on purpose, as it should
* never be returned to the outside code. The compilation will catch it
* and replace it with a SassException reporting the location of the
* error.
*/
class SassScriptException extends \Exception
{
/**
* Creates a SassScriptException with support for an argument name.
*
* This helper ensures a consistent handling of argument names in the
* error message, without duplicating it.
*
* @param string $message
* @param string|null $name The argument name, without $
*
* @return SassScriptException
*/
public static function forArgument($message, $name = null)
{
$varDisplay = !\is_null($name) ? "\${$name}: " : '';
return new self($varDisplay . $message);
}
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -12,15 +11,11 @@
namespace ScssPhp\ScssPhp\Exception;
@trigger_error(sprintf('The "%s" class is deprecated.', ServerException::class), E_USER_DEPRECATED);
/**
* Server Exception
*
* @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
{
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -19,13 +18,11 @@ use ScssPhp\ScssPhp\SourceMap\SourceMapGenerator;
* Base formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*
* @internal
*/
abstract class Formatter
{
/**
* @var int
* @var integer
*/
public $indentLevel;
@@ -60,7 +57,7 @@ abstract class Formatter
public $assignSeparator;
/**
* @var bool
* @var boolean
*/
public $keepSemicolons;
@@ -70,17 +67,17 @@ abstract class Formatter
protected $currentBlock;
/**
* @var int
* @var integer
*/
protected $currentLine;
/**
* @var int
* @var integer
*/
protected $currentColumn;
/**
* @var \ScssPhp\ScssPhp\SourceMap\SourceMapGenerator|null
* @var \ScssPhp\ScssPhp\SourceMap\SourceMapGenerator
*/
protected $sourceMapGenerator;
@@ -121,33 +118,16 @@ abstract class Formatter
return rtrim($name) . $this->assignSeparator . $value . ';';
}
/**
* Return custom property assignment
* differs in that you have to keep spaces in the value as is
*
* @api
*
* @param string $name
* @param mixed $value
*
* @return string
*/
public function customProperty($name, $value)
{
return rtrim($name) . trim($this->assignSeparator) . $value . ';';
}
/**
* Output lines inside a block
*
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
*
* @return void
*/
protected function blockLines(OutputBlock $block)
{
$inner = $this->indentStr();
$glue = $this->break . $inner;
$glue = $this->break . $inner;
$this->write($inner . implode($glue, $block->lines));
@@ -160,13 +140,9 @@ abstract class Formatter
* Output block selectors
*
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
*
* @return void
*/
protected function blockSelectors(OutputBlock $block)
{
assert(! empty($block->selectors));
$inner = $this->indentStr();
$this->write($inner
@@ -178,8 +154,6 @@ abstract class Formatter
* Output block children
*
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
*
* @return void
*/
protected function blockChildren(OutputBlock $block)
{
@@ -192,8 +166,6 @@ abstract class Formatter
* Output non-empty block
*
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
*
* @return void
*/
protected function block(OutputBlock $block)
{
@@ -239,7 +211,7 @@ abstract class Formatter
*
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
*
* @return bool
* @return boolean
*/
protected function testEmptyChildren($block)
{
@@ -286,18 +258,9 @@ abstract class Formatter
ob_start();
try {
$this->block($block);
} catch (\Exception $e) {
ob_end_clean();
throw $e;
} catch (\Throwable $e) {
ob_end_clean();
throw $e;
}
$this->block($block);
$out = ob_get_clean();
assert($out !== false);
return $out;
}
@@ -306,8 +269,6 @@ abstract class Formatter
* Output content
*
* @param string $str
*
* @return void
*/
protected function write($str)
{
@@ -321,8 +282,7 @@ abstract class Formatter
* Maybe Strip semi-colon appended by property(); it's a separator, not a terminator
* will be striped for real before a closing, otherwise displayed unchanged starting the next write
*/
if (
! $this->keepSemicolons &&
if (! $this->keepSemicolons &&
$str &&
(strpos($str, ';') !== false) &&
(substr($str, -1) === ';')
@@ -333,43 +293,22 @@ abstract class Formatter
}
if ($this->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);
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 !== '') {
assert($this->currentBlock->sourceLine !== null);
assert($this->currentBlock->sourceName !== null);
$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 !== '') {
assert($this->currentBlock->sourceLine !== null);
assert($this->currentBlock->sourceName !== null);
$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);
$this->currentColumn = ($lineCount === 1 ? $this->currentColumn : 0) + strlen($lastLine);
}
echo $str;

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -18,10 +17,6 @@ use ScssPhp\ScssPhp\Formatter;
* Compact formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*
* @deprecated since 1.4.0. Use the Compressed formatter instead.
*
* @internal
*/
class Compact extends Formatter
{
@@ -30,8 +25,6 @@ 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 = '';

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -13,13 +12,12 @@
namespace ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter\OutputBlock;
/**
* Compressed formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*
* @internal
*/
class Compressed extends Formatter
{
@@ -50,6 +48,8 @@ class Compressed extends Formatter
foreach ($block->lines as $index => $line) {
if (substr($line, 0, 2) === '/*' && substr($line, 2, 1) !== '!') {
unset($block->lines[$index]);
} elseif (substr($line, 0, 3) === '/*!') {
$block->lines[$index] = '/*' . substr($line, 3);
}
}
@@ -67,8 +67,6 @@ class Compressed extends Formatter
*/
protected function blockSelectors(OutputBlock $block)
{
assert(! empty($block->selectors));
$inner = $this->indentStr();
$this->write(

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -13,15 +12,12 @@
namespace ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter\OutputBlock;
/**
* Crunched formatter
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @deprecated since 1.4.0. Use the Compressed formatter instead.
*
* @internal
*/
class Crunched extends Formatter
{
@@ -30,8 +26,6 @@ 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 = '';
@@ -71,8 +65,6 @@ class Crunched extends Formatter
*/
protected function blockSelectors(OutputBlock $block)
{
assert(! empty($block->selectors));
$inner = $this->indentStr();
$this->write(

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -13,15 +12,12 @@
namespace ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter\OutputBlock;
/**
* Debug formatter
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @deprecated since 1.4.0.
*
* @internal
*/
class Debug extends Formatter
{
@@ -30,8 +26,6 @@ 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";

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -13,13 +12,12 @@
namespace ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter\OutputBlock;
/**
* Expanded formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*
* @internal
*/
class Expanded extends Formatter
{
@@ -57,9 +55,7 @@ class Expanded extends Formatter
foreach ($block->lines as $index => $line) {
if (substr($line, 0, 2) === '/*') {
$replacedLine = preg_replace('/\r\n?|\n|\f/', $this->break, $line);
assert($replacedLine !== null);
$block->lines[$index] = $replacedLine;
$block->lines[$index] = preg_replace('/[\r\n]+/', $glue, $line);
}
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -13,21 +12,18 @@
namespace ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter\OutputBlock;
use ScssPhp\ScssPhp\Type;
/**
* Nested formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*
* @deprecated since 1.4.0. Use the Expanded formatter instead.
*
* @internal
*/
class Nested extends Formatter
{
/**
* @var int
* @var integer
*/
private $depth;
@@ -36,8 +32,6 @@ 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";
@@ -64,13 +58,12 @@ class Nested extends Formatter
protected function blockLines(OutputBlock $block)
{
$inner = $this->indentStr();
$glue = $this->break . $inner;
$glue = $this->break . $inner;
foreach ($block->lines as $index => $line) {
if (substr($line, 0, 2) === '/*') {
$replacedLine = preg_replace('/\r\n?|\n|\f/', $this->break, $line);
assert($replacedLine !== null);
$block->lines[$index] = $replacedLine;
$block->lines[$index] = preg_replace('/[\r\n]+/', $glue, $line);
}
}
@@ -97,7 +90,7 @@ class Nested extends Formatter
$previousHasSelector = false;
}
$isMediaOrDirective = \in_array($block->type, [Type::T_DIRECTIVE, Type::T_MEDIA]);
$isMediaOrDirective = in_array($block->type, [Type::T_DIRECTIVE, Type::T_MEDIA]);
$isSupport = ($block->type === Type::T_DIRECTIVE
&& $block->selectors && strpos(implode('', $block->selectors), '@supports') !== false);
@@ -105,8 +98,7 @@ class Nested extends Formatter
array_pop($depths);
$this->depth--;
if (
! $this->depth && ($block->depth <= 1 || (! $this->indentLevel && $block->type === Type::T_COMMENT)) &&
if (! $this->depth && ($block->depth <= 1 || (! $this->indentLevel && $block->type === Type::T_COMMENT)) &&
(($block->selectors && ! $isMediaOrDirective) || $previousHasSelector)
) {
$downLevel = $this->break;
@@ -127,12 +119,10 @@ class Nested extends Formatter
if ($block->depth > end($depths)) {
if (! $previousEmpty || $this->depth < 1) {
$this->depth++;
$depths[] = $block->depth;
} else {
// keep the current depth unchanged but take the block depth as a new reference for following blocks
array_pop($depths);
$depths[] = $block->depth;
}
}
@@ -223,7 +213,7 @@ class Nested extends Formatter
*
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
*
* @return bool
* @return boolean
*/
private function hasFlatChild($block)
{

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,53 +15,51 @@ namespace ScssPhp\ScssPhp\Formatter;
* Output block
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
class OutputBlock
{
/**
* @var string|null
* @var string
*/
public $type;
/**
* @var int
* @var integer
*/
public $depth;
/**
* @var array|null
* @var array
*/
public $selectors;
/**
* @var string[]
* @var array
*/
public $lines;
/**
* @var OutputBlock[]
* @var array
*/
public $children;
/**
* @var OutputBlock|null
* @var \ScssPhp\ScssPhp\Formatter\OutputBlock
*/
public $parent;
/**
* @var string|null
* @var string
*/
public $sourceName;
/**
* @var int|null
* @var integer
*/
public $sourceLine;
/**
* @var int|null
* @var integer
*/
public $sourceColumn;
}

View File

@@ -1,48 +0,0 @@
<?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

@@ -1,27 +0,0 @@
<?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

@@ -1,60 +0,0 @@
<?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

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,8 +15,6 @@ namespace ScssPhp\ScssPhp;
* Base node
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
abstract class Node
{
@@ -27,17 +24,17 @@ abstract class Node
public $type;
/**
* @var int
* @var integer
*/
public $sourceIndex;
/**
* @var int|null
* @var integer
*/
public $sourceLine;
/**
* @var int|null
* @var integer
*/
public $sourceColumn;
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -12,13 +11,9 @@
namespace ScssPhp\ScssPhp\Node;
use ScssPhp\ScssPhp\Base\Range;
use ScssPhp\ScssPhp\Compiler;
use ScssPhp\ScssPhp\Exception\RangeException;
use ScssPhp\ScssPhp\Exception\SassScriptException;
use ScssPhp\ScssPhp\Node;
use ScssPhp\ScssPhp\Type;
use ScssPhp\ScssPhp\Util;
/**
* Dimension + optional units
@@ -30,26 +25,20 @@ use ScssPhp\ScssPhp\Util;
* }}
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @template-implements \ArrayAccess<int, mixed>
*/
class Number extends Node implements \ArrayAccess
{
const PRECISION = 10;
/**
* @var int
* @deprecated use {Number::PRECISION} instead to read the precision. Configuring it is not supported anymore.
* @var integer
*/
public static $precision = self::PRECISION;
static public $precision = 10;
/**
* @see http://www.w3.org/TR/2012/WD-css3-values-20120308/
*
* @var array
* @phpstan-var array<string, array<string, float|int>>
*/
protected static $unitTable = [
static protected $unitTable = [
'in' => [
'in' => 1,
'pc' => 6,
@@ -75,93 +64,91 @@ class Number extends Node implements \ArrayAccess
],
'dpi' => [
'dpi' => 1,
'dpcm' => 1 / 2.54,
'dppx' => 1 / 96,
'dpcm' => 2.54,
'dppx' => 96,
],
];
/**
* @var int|float
* @var integer|float
*/
private $dimension;
public $dimension;
/**
* @var string[]
* @phpstan-var list<string>
* @var array
*/
private $numeratorUnits;
/**
* @var string[]
* @phpstan-var list<string>
*/
private $denominatorUnits;
public $units;
/**
* Initialize number
*
* @param int|float $dimension
* @param string[]|string $numeratorUnits
* @param string[] $denominatorUnits
*
* @phpstan-param list<string>|string $numeratorUnits
* @phpstan-param list<string> $denominatorUnits
* @param mixed $dimension
* @param mixed $initialUnit
*/
public function __construct($dimension, $numeratorUnits, array $denominatorUnits = [])
public function __construct($dimension, $initialUnit)
{
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->type = Type::T_NUMBER;
$this->dimension = $dimension;
$this->units = is_array($initialUnit)
? $initialUnit
: ($initialUnit ? [$initialUnit => 1]
: []);
}
/**
* Coerce number to target units
*
* @param array $units
*
* @return \ScssPhp\ScssPhp\Node\Number
*/
public function coerce($units)
{
if ($this->unitless()) {
return new Number($this->dimension, $units);
}
$this->dimension = $dimension;
$this->numeratorUnits = $numeratorUnits;
$this->denominatorUnits = $denominatorUnits;
$dimension = $this->dimension;
foreach (static::$unitTable['in'] 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 float|int
* Normalize number
*
* @return \ScssPhp\ScssPhp\Node\Number
*/
public function getDimension()
public function normalize()
{
return $this->dimension;
$dimension = $this->dimension;
$units = [];
$this->normalizeUnits($dimension, $units, 'in');
return new Number($dimension, $units);
}
/**
* @return string[]
* {@inheritdoc}
*/
public function getNumeratorUnits()
{
return $this->numeratorUnits;
}
/**
* @return string[]
*/
public function getDenominatorUnits()
{
return $this->denominatorUnits;
}
/**
* @return bool
*/
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
if ($offset === -3) {
return ! \is_null($this->sourceColumn);
return ! is_null($this->sourceColumn);
}
if ($offset === -2) {
return ! \is_null($this->sourceLine);
return ! is_null($this->sourceLine);
}
if (
$offset === -1 ||
if ($offset === -1 ||
$offset === 0 ||
$offset === 1 ||
$offset === 2
@@ -173,9 +160,8 @@ class Number extends Node implements \ArrayAccess
}
/**
* @return mixed
* {@inheritdoc}
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
switch ($offset) {
@@ -189,54 +175,60 @@ class Number extends Node implements \ArrayAccess
return $this->sourceIndex;
case 0:
return Type::T_NUMBER;
return $this->type;
case 1:
return $this->dimension;
case 2:
return array('numerator_units' => $this->numeratorUnits, 'denominator_units' => $this->denominatorUnits);
return $this->units;
}
}
/**
* @return void
* {@inheritdoc}
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
throw new \BadMethodCallException('Number is immutable');
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;
}
}
/**
* @return void
* {@inheritdoc}
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
throw new \BadMethodCallException('Number is immutable');
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;
}
}
/**
* Returns true if the number is unitless
*
* @return bool
* @return boolean
*/
public function unitless()
{
return \count($this->numeratorUnits) === 0 && \count($this->denominatorUnits) === 0;
}
/**
* Checks whether the number has exactly this unit
*
* @param string $unit
*
* @return bool
*/
public function hasUnit($unit)
{
return \count($this->numeratorUnits) === 1 && \count($this->denominatorUnits) === 0 && $this->numeratorUnits[0] === $unit;
return ! array_sum($this->units);
}
/**
@@ -246,289 +238,22 @@ class Number extends Node implements \ArrayAccess
*/
public function unitStr()
{
if ($this->unitless()) {
return '';
}
$numerators = [];
$denominators = [];
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
*
* @return void
*/
public function assertNoUnits($varName = null)
{
if ($this->unitless()) {
return;
}
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);
}
/**
* @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)
));
}
/**
* 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
*
* @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;
foreach ($this->units as $unit => $unitSize) {
if ($unitSize > 0) {
$numerators = array_pad($numerators, count($numerators) + $unitSize, $unit);
continue;
}
$result = fmod($num1, $num2);
if ($result == 0) {
return 0;
if ($unitSize < 0) {
$denominators = array_pad($denominators, count($denominators) + $unitSize, $unit);
continue;
}
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;
}
return implode('*', $numerators) . (count($denominators) ? '/' . implode('*', $denominators) : '');
}
/**
@@ -540,31 +265,35 @@ class Number extends Node implements \ArrayAccess
*/
public function output(Compiler $compiler = null)
{
$dimension = round($this->dimension, self::PRECISION);
$dimension = round($this->dimension, static::$precision);
if (is_nan($dimension)) {
return 'NaN';
$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, 'in');
$dimension = round($dimension, static::$precision);
$units = array_filter($units, function ($unitSize) {
return $unitSize;
});
}
if ($dimension === INF) {
return 'Infinity';
$unitSize = array_sum($units);
if ($compiler && ($unitSize > 1 || $unitSize < 0 || count($units) > 1)) {
$compiler->throwError((string) $dimension . $this->unitStr() . " isn't a valid CSS value.");
}
if ($dimension === -INF) {
return '-Infinity';
}
reset($units);
$unit = key($units);
$dimension = number_format($dimension, static::$precision, '.', '');
if ($compiler) {
$unit = $this->unitStr();
} elseif (isset($this->numeratorUnits[0])) {
$unit = $this->numeratorUnits[0];
} else {
$unit = '';
}
$dimension = number_format($dimension, self::PRECISION, '.', '');
return rtrim(rtrim($dimension, '0'), '.') . $unit;
return (static::$precision ? rtrim(rtrim($dimension, '0'), '.') : $dimension) . $unit;
}
/**
@@ -576,229 +305,26 @@ class Number extends Node implements \ArrayAccess
}
/**
* @param Number $other
* @param callable $operation
* Normalize units
*
* @return Number
*
* @phpstan-param callable(int|float, int|float): (int|float) $operation
* @param integer|float $dimension
* @param array $units
* @param string $baseUnit
*/
private function coerceNumber(Number $other, $operation)
private function normalizeUnits(&$dimension, &$units, $baseUnit = 'in')
{
$result = $this->coerceUnits($other, $operation);
$dimension = $this->dimension;
$units = [];
if (!$this->unitless()) {
return new Number($result, $this->numeratorUnits, $this->denominatorUnits);
}
foreach ($this->units as $unit => $exp) {
if (isset(static::$unitTable[$baseUnit][$unit])) {
$factor = pow(static::$unitTable[$baseUnit][$unit], $exp);
return new Number($result, $other->numeratorUnits, $other->denominatorUnits);
}
/**
* @param Number $other
* @param callable $operation
*
* @return mixed
*
* @phpstan-template T
* @phpstan-param callable(int|float, int|float): T $operation
* @phpstan-return T
*/
private function coerceUnits(Number $other, $operation)
{
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<string> $numeratorUnits
* @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)
{
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;
$unit = $baseUnit;
$dimension /= $factor;
}
throw new SassScriptException(sprintf(
'Incompatible units %s and %s.',
self::getUnitString($this->numeratorUnits, $this->denominatorUnits),
self::getUnitString($numeratorUnits, $denominatorUnits)
));
$units[$unit] = $exp + (isset($units[$unit]) ? $units[$unit] : 0);
}
$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<string> $numerators1
* @phpstan-param list<string> $denominators1
* @phpstan-param list<string> $numerators2
* @phpstan-param list<string> $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<string> $numerators
* @phpstan-param list<string> $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) : '');
}
}

View File

@@ -1,9 +0,0 @@
<?php
namespace ScssPhp\ScssPhp;
final class OutputStyle
{
const EXPANDED = 'expanded';
const COMPRESSED = 'compressed';
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,13 +15,11 @@ namespace ScssPhp\ScssPhp\SourceMap;
* Base 64 Encode/Decode
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
class Base64
{
/**
* @var array<int, string>
* @var array
*/
private static $encodingMap = [
0 => 'A',
@@ -92,7 +89,7 @@ class Base64
];
/**
* @var array<string|int, int>
* @var array
*/
private static $decodingMap = [
'A' => 0,
@@ -164,7 +161,7 @@ class Base64
/**
* Convert to base64
*
* @param int $value
* @param integer $value
*
* @return string
*/
@@ -178,7 +175,7 @@ class Base64
*
* @param string $value
*
* @return int
* @return integer
*/
public static function decode($value)
{

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -12,6 +11,8 @@
namespace ScssPhp\ScssPhp\SourceMap;
use ScssPhp\ScssPhp\SourceMap\Base64;
/**
* Base 64 VLQ
*
@@ -34,8 +35,6 @@ namespace ScssPhp\ScssPhp\SourceMap;
*
* @author John Lenz <johnlenz@google.com>
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
class Base64VLQ
{
@@ -51,7 +50,7 @@ class Base64VLQ
/**
* Returns the VLQ encoded value.
*
* @param int $value
* @param integer $value
*
* @return string
*/
@@ -62,9 +61,7 @@ class Base64VLQ
do {
$digit = $vlq & self::VLQ_BASE_MASK;
//$vlq >>>= self::VLQ_BASE_SHIFT; // unsigned right shift
$vlq = (($vlq >> 1) & PHP_INT_MAX) >> (self::VLQ_BASE_SHIFT - 1);
$vlq >>= self::VLQ_BASE_SHIFT;
if ($vlq > 0) {
$digit |= self::VLQ_CONTINUATION_BIT;
@@ -80,9 +77,9 @@ class Base64VLQ
* Decodes VLQValue.
*
* @param string $str
* @param int $index
* @param integer $index
*
* @return int
* @return integer
*/
public static function decode($str, &$index)
{
@@ -107,9 +104,9 @@ class Base64VLQ
* 1 becomes 2 (10 binary), -1 becomes 3 (11 binary)
* 2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
*
* @param int $value
* @param integer $value
*
* @return int
* @return integer
*/
private static function toVLQSigned($value)
{
@@ -126,16 +123,14 @@ class Base64VLQ
* 2 (10 binary) becomes 1, 3 (11 binary) becomes -1
* 4 (100 binary) becomes 2, 5 (101 binary) becomes -2
*
* @param int $value
* @param integer $value
*
* @return int
* @return integer
*/
private static function fromVLQSigned($value)
{
$negate = ($value & 1) === 1;
//$value >>>= 1; // unsigned right shift
$value = ($value >> 1) & PHP_INT_MAX;
$value = ($value >> 1) & ~(1<<(8 * PHP_INT_SIZE - 1)); // unsigned right shift
if (! $negate) {
return $value;

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -21,8 +20,6 @@ use ScssPhp\ScssPhp\Exception\CompilerException;
*
* @author Josh Schmidt <oyejorge@gmail.com>
* @author Nicolas FRANÇOIS <nicolas.francois@frog-labs.com>
*
* @internal
*/
class SourceMapGenerator
{
@@ -35,7 +32,6 @@ class SourceMapGenerator
* Array of default options
*
* @var array
* @phpstan-var array{sourceRoot: string, sourceMapFilename: string|null, sourceMapURL: string|null, sourceMapWriteTo: string|null, outputSourceFiles: bool, sourceMapRootpath: string, sourceMapBasepath: string}
*/
protected $defaultOptions = [
// an optional source root, useful for relocating source files
@@ -73,7 +69,6 @@ class SourceMapGenerator
* Array of mappings
*
* @var array
* @phpstan-var list<array{generated_line: int, generated_column: int, original_line: int, original_column: int, source_file: string}>
*/
protected $mappings = [];
@@ -87,40 +82,30 @@ class SourceMapGenerator
/**
* File to content map
*
* @var array<string, string>
* @var array
*/
protected $sources = [];
/**
* @var array<string, int>
*/
protected $sourceKeys = [];
/**
* @var array
* @phpstan-var array{sourceRoot: string, sourceMapFilename: string|null, sourceMapURL: string|null, sourceMapWriteTo: string|null, outputSourceFiles: bool, sourceMapRootpath: string, sourceMapBasepath: string}
*/
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 = [])
{
$this->options = array_replace($this->defaultOptions, $options);
$this->options = array_merge($this->defaultOptions, $options);
$this->encoder = new Base64VLQ();
}
/**
* Adds a mapping
*
* @param int $generatedLine The line number in generated file
* @param int $generatedColumn The column number in generated file
* @param int $originalLine The line number in original file
* @param int $originalColumn The column number in original file
* @param string $sourceFile The original source file
*
* @return void
* @param integer $generatedLine The line number in generated file
* @param integer $generatedColumn The column number in generated file
* @param integer $originalLine The line number in original file
* @param integer $originalColumn The column number in original file
* @param string $sourceFile The original source file
*/
public function addMapping($generatedLine, $generatedColumn, $originalLine, $originalColumn, $sourceFile)
{
@@ -140,16 +125,14 @@ class SourceMapGenerator
*
* @param string $content The content to write
*
* @return string|null
* @return string
*
* @throws \ScssPhp\ScssPhp\Exception\CompilerException If the file could not be saved
* @deprecated
*/
public function saveMap($content)
{
$file = $this->options['sourceMapWriteTo'];
assert($file !== null);
$dir = \dirname($file);
$dir = dirname($file);
// directory does not exist
if (! is_dir($dir)) {
@@ -170,16 +153,14 @@ 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($prefix = '')
public function generateJson()
{
$sourceMap = [];
$mappings = $this->generateMappings($prefix);
$mappings = $this->generateMappings();
// File version (always the first entry in the object) and must be a positive integer.
$sourceMap['version'] = self::VERSION;
@@ -202,7 +183,7 @@ class SourceMapGenerator
// A list of original sources used by the 'mappings' entry.
$sourceMap['sources'] = [];
foreach ($this->sources as $sourceFilename) {
foreach ($this->sources as $sourceUri => $sourceFilename) {
$sourceMap['sources'][] = $this->normalizeFilename($sourceFilename);
}
@@ -220,25 +201,17 @@ class SourceMapGenerator
}
// less.js compat fixes
if (\count($sourceMap['sources']) && empty($sourceMap['sourceRoot'])) {
if (count($sourceMap['sources']) && empty($sourceMap['sourceRoot'])) {
unset($sourceMap['sourceRoot']);
}
$jsonSourceMap = json_encode($sourceMap, JSON_UNESCAPED_SLASHES);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \RuntimeException(json_last_error_msg());
}
assert($jsonSourceMap !== false);
return $jsonSourceMap;
return json_encode($sourceMap, JSON_UNESCAPED_SLASHES);
}
/**
* Returns the sources contents
*
* @return string[]|null
* @return array|null
*/
protected function getSourcesContent()
{
@@ -258,21 +231,14 @@ 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($prefix = '')
public function generateMappings()
{
if (! \count($this->mappings)) {
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.
@@ -283,16 +249,9 @@ class SourceMapGenerator
}
ksort($groupedMap);
$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[] = ';';
}
@@ -301,10 +260,8 @@ class SourceMapGenerator
$lastGeneratedColumn = 0;
foreach ($lineMap as $m) {
$generatedColumn = $m['generated_column'] + $prefixColumn;
$mapEncoded = $this->encoder->encode($generatedColumn - $lastGeneratedColumn);
$lastGeneratedColumn = $generatedColumn;
$mapEncoded = $this->encoder->encode($m['generated_column'] - $lastGeneratedColumn);
$lastGeneratedColumn = $m['generated_column'];
// find the index
if ($m['source_file']) {
@@ -335,7 +292,7 @@ class SourceMapGenerator
*
* @param string $filename
*
* @return int|false
* @return integer|false
*/
protected function findFileIndex($filename)
{
@@ -356,8 +313,8 @@ class SourceMapGenerator
$basePath = $this->options['sourceMapBasepath'];
// "Trim" the 'sourceMapBasepath' from the output filename.
if (\strlen($basePath) && strpos($filename, $basePath) === 0) {
$filename = substr($filename, \strlen($basePath));
if (strlen($basePath) && strpos($filename, $basePath) === 0) {
$filename = substr($filename, strlen($basePath));
}
// Remove extra leading path separators.
@@ -371,8 +328,8 @@ class SourceMapGenerator
/**
* Fix windows paths
*
* @param string $path
* @param bool $addEndSlash
* @param string $path
* @param boolean $addEndSlash
*
* @return string
*/

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -19,190 +18,52 @@ namespace ScssPhp\ScssPhp;
*/
class Type
{
/**
* @internal
*/
const T_ASSIGN = 'assign';
/**
* @internal
*/
const T_AT_ROOT = 'at-root';
/**
* @internal
*/
const T_BLOCK = 'block';
/**
* @deprecated
* @internal
*/
const T_BREAK = 'break';
/**
* @internal
*/
const T_CHARSET = 'charset';
const T_COLOR = 'color';
/**
* @internal
*/
const T_COMMENT = 'comment';
/**
* @deprecated
* @internal
*/
const T_CONTINUE = 'continue';
/**
* @deprecated
* @internal
*/
const T_CONTROL = 'control';
/**
* @internal
*/
const T_CUSTOM_PROPERTY = 'custom';
/**
* @internal
*/
const T_DEBUG = 'debug';
/**
* @internal
*/
const T_DIRECTIVE = 'directive';
/**
* @internal
*/
const T_EACH = 'each';
/**
* @internal
*/
const T_ELSE = 'else';
/**
* @internal
*/
const T_ELSEIF = 'elseif';
/**
* @internal
*/
const T_ERROR = 'error';
/**
* @internal
*/
const T_EXPRESSION = 'exp';
/**
* @internal
*/
const T_EXTEND = 'extend';
/**
* @internal
*/
const T_FOR = 'for';
const T_FUNCTION = 'function';
/**
* @internal
*/
const T_FUNCTION_REFERENCE = 'function-reference';
/**
* @internal
*/
const T_FUNCTION_CALL = 'fncall';
/**
* @internal
*/
const T_HSL = 'hsl';
/**
* @internal
*/
const T_HWB = 'hwb';
/**
* @internal
*/
const T_IF = 'if';
/**
* @internal
*/
const T_IMPORT = 'import';
/**
* @internal
*/
const T_INCLUDE = 'include';
/**
* @internal
*/
const T_INTERPOLATE = 'interpolate';
/**
* @internal
*/
const T_INTERPOLATED = 'interpolated';
/**
* @internal
*/
const T_KEYWORD = 'keyword';
const T_LIST = 'list';
const T_MAP = 'map';
/**
* @internal
*/
const T_MEDIA = 'media';
/**
* @internal
*/
const T_MEDIA_EXPRESSION = 'mediaExp';
/**
* @internal
*/
const T_MEDIA_TYPE = 'mediaType';
/**
* @internal
*/
const T_MEDIA_VALUE = 'mediaValue';
/**
* @internal
*/
const T_MIXIN = 'mixin';
/**
* @internal
*/
const T_MIXIN_CONTENT = 'mixin_content';
/**
* @internal
*/
const T_NESTED_PROPERTY = 'nestedprop';
/**
* @internal
*/
const T_NOT = 'not';
const T_NULL = 'null';
const T_NUMBER = 'number';
/**
* @internal
*/
const T_RETURN = 'return';
/**
* @internal
*/
const T_ROOT = 'root';
/**
* @internal
*/
const T_SCSSPHP_IMPORT_ONCE = 'scssphp-import-once';
/**
* @internal
*/
const T_SELF = 'self';
const T_STRING = 'string';
/**
* @internal
*/
const T_UNARY = 'unary';
/**
* @internal
*/
const T_VARIABLE = 'var';
/**
* @internal
*/
const T_WARN = 'warn';
/**
* @internal
*/
const T_WHILE = 'while';
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -14,14 +13,11 @@ namespace ScssPhp\ScssPhp;
use ScssPhp\ScssPhp\Base\Range;
use ScssPhp\ScssPhp\Exception\RangeException;
use ScssPhp\ScssPhp\Node\Number;
/**
* Utility functions
* Utilty functions
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
class Util
{
@@ -29,10 +25,10 @@ class Util
* Asserts that `value` falls within `range` (inclusive), leaving
* room for slight floating-point errors.
*
* @param string $name The name of the value. Used in the error message.
* @param Range $range Range of values.
* @param array|Number $value The value to check.
* @param string $unit The unit of the value. Used in error reporting.
* @param string $name The name of the value. Used in the error message.
* @param \ScssPhp\ScssPhp\Base\Range $range Range of values.
* @param array $value The value to check.
* @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.
*
@@ -43,10 +39,6 @@ class Util
$val = $value[1];
$grace = new Range(-0.00001, 0.00001);
if (! \is_numeric($val)) {
throw new RangeException("$name {$val} is not a number.");
}
if ($range->includes($val)) {
return $val;
}
@@ -75,110 +67,4 @@ class Util
return strtr(rawurlencode($string), $revert);
}
/**
* mb_chr() wrapper
*
* @param int $code
*
* @return string
*/
public static function mbChr($code)
{
// 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');
}
if (0x80 > $code %= 0x200000) {
$s = \chr($code);
} elseif (0x800 > $code) {
$s = \chr(0xC0 | $code >> 6) . \chr(0x80 | $code & 0x3F);
} elseif (0x10000 > $code) {
$s = \chr(0xE0 | $code >> 12) . \chr(0x80 | $code >> 6 & 0x3F) . \chr(0x80 | $code & 0x3F);
} else {
$s = \chr(0xF0 | $code >> 18) . \chr(0x80 | $code >> 12 & 0x3F)
. \chr(0x80 | $code >> 6 & 0x3F) . \chr(0x80 | $code & 0x3F);
}
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 (int) @iconv_strlen($string, 'UTF-8');
}
throw new \LogicException('Either mbstring (recommended) or iconv is necessary to use Scssphp.');
}
/**
* 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');
}
throw new \LogicException('Either mbstring (recommended) or iconv is necessary to use Scssphp.');
}
/**
* 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');
}
throw new \LogicException('Either mbstring (recommended) or iconv is necessary to use Scssphp.');
}
}

View File

@@ -1,77 +0,0 @@
<?php
namespace ScssPhp\ScssPhp\Util;
/**
* @internal
*/
class Path
{
/**
* @param string $path
*
* @return bool
*/
public static function isAbsolute($path)
{
if ($path === '') {
return false;
}
if ($path[0] === '/') {
return true;
}
if (\DIRECTORY_SEPARATOR !== '\\') {
return false;
}
if ($path[0] === '\\') {
return true;
}
if (\strlen($path) < 3) {
return false;
}
if ($path[1] !== ':') {
return false;
}
if ($path[2] !== '/' && $path[2] !== '\\') {
return false;
}
if (!preg_match('/^[A-Za-z]$/', $path[0])) {
return false;
}
return true;
}
/**
* @param string $part1
* @param string $part2
*
* @return string
*/
public static function join($part1, $part2)
{
if ($part1 === '' || self::isAbsolute($part2)) {
return $part2;
}
if ($part2 === '') {
return $part1;
}
$last = $part1[\strlen($part1) - 1];
$separator = \DIRECTORY_SEPARATOR;
if ($last === '/' || $last === \DIRECTORY_SEPARATOR) {
$separator = '';
}
return $part1 . $separator . $part2;
}
}

View File

@@ -1,95 +0,0 @@
<?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

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -19,5 +18,5 @@ namespace ScssPhp\ScssPhp;
*/
class Version
{
const VERSION = '1.10.2';
const VERSION = 'v1.0.6';
}

View File

@@ -1,84 +0,0 @@
<?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);
}
}