diff options
Diffstat (limited to 'vendor/scssphp/scssphp/src/SourceMap')
-rw-r--r-- | vendor/scssphp/scssphp/src/SourceMap/Base64.php | 187 | ||||
-rw-r--r-- | vendor/scssphp/scssphp/src/SourceMap/Base64VLQ.php | 151 | ||||
-rw-r--r-- | vendor/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php | 390 |
3 files changed, 728 insertions, 0 deletions
diff --git a/vendor/scssphp/scssphp/src/SourceMap/Base64.php b/vendor/scssphp/scssphp/src/SourceMap/Base64.php new file mode 100644 index 000000000..00b6b4545 --- /dev/null +++ b/vendor/scssphp/scssphp/src/SourceMap/Base64.php @@ -0,0 +1,187 @@ +<?php + +/** + * SCSSPHP + * + * @copyright 2012-2020 Leaf Corcoran + * + * @license http://opensource.org/licenses/MIT MIT + * + * @link http://scssphp.github.io/scssphp + */ + +namespace ScssPhp\ScssPhp\SourceMap; + +/** + * Base 64 Encode/Decode + * + * @author Anthon Pang <anthon.pang@gmail.com> + * + * @internal + */ +class Base64 +{ + /** + * @var array<int, string> + */ + private static $encodingMap = [ + 0 => 'A', + 1 => 'B', + 2 => 'C', + 3 => 'D', + 4 => 'E', + 5 => 'F', + 6 => 'G', + 7 => 'H', + 8 => 'I', + 9 => 'J', + 10 => 'K', + 11 => 'L', + 12 => 'M', + 13 => 'N', + 14 => 'O', + 15 => 'P', + 16 => 'Q', + 17 => 'R', + 18 => 'S', + 19 => 'T', + 20 => 'U', + 21 => 'V', + 22 => 'W', + 23 => 'X', + 24 => 'Y', + 25 => 'Z', + 26 => 'a', + 27 => 'b', + 28 => 'c', + 29 => 'd', + 30 => 'e', + 31 => 'f', + 32 => 'g', + 33 => 'h', + 34 => 'i', + 35 => 'j', + 36 => 'k', + 37 => 'l', + 38 => 'm', + 39 => 'n', + 40 => 'o', + 41 => 'p', + 42 => 'q', + 43 => 'r', + 44 => 's', + 45 => 't', + 46 => 'u', + 47 => 'v', + 48 => 'w', + 49 => 'x', + 50 => 'y', + 51 => 'z', + 52 => '0', + 53 => '1', + 54 => '2', + 55 => '3', + 56 => '4', + 57 => '5', + 58 => '6', + 59 => '7', + 60 => '8', + 61 => '9', + 62 => '+', + 63 => '/', + ]; + + /** + * @var array<string|int, int> + */ + private static $decodingMap = [ + 'A' => 0, + 'B' => 1, + 'C' => 2, + 'D' => 3, + 'E' => 4, + 'F' => 5, + 'G' => 6, + 'H' => 7, + 'I' => 8, + 'J' => 9, + 'K' => 10, + 'L' => 11, + 'M' => 12, + 'N' => 13, + 'O' => 14, + 'P' => 15, + 'Q' => 16, + 'R' => 17, + 'S' => 18, + 'T' => 19, + 'U' => 20, + 'V' => 21, + 'W' => 22, + 'X' => 23, + 'Y' => 24, + 'Z' => 25, + 'a' => 26, + 'b' => 27, + 'c' => 28, + 'd' => 29, + 'e' => 30, + 'f' => 31, + 'g' => 32, + 'h' => 33, + 'i' => 34, + 'j' => 35, + 'k' => 36, + 'l' => 37, + 'm' => 38, + 'n' => 39, + 'o' => 40, + 'p' => 41, + 'q' => 42, + 'r' => 43, + 's' => 44, + 't' => 45, + 'u' => 46, + 'v' => 47, + 'w' => 48, + 'x' => 49, + 'y' => 50, + 'z' => 51, + 0 => 52, + 1 => 53, + 2 => 54, + 3 => 55, + 4 => 56, + 5 => 57, + 6 => 58, + 7 => 59, + 8 => 60, + 9 => 61, + '+' => 62, + '/' => 63, + ]; + + /** + * Convert to base64 + * + * @param int $value + * + * @return string + */ + public static function encode($value) + { + return self::$encodingMap[$value]; + } + + /** + * Convert from base64 + * + * @param string $value + * + * @return int + */ + public static function decode($value) + { + return self::$decodingMap[$value]; + } +} diff --git a/vendor/scssphp/scssphp/src/SourceMap/Base64VLQ.php b/vendor/scssphp/scssphp/src/SourceMap/Base64VLQ.php new file mode 100644 index 000000000..2a5210c68 --- /dev/null +++ b/vendor/scssphp/scssphp/src/SourceMap/Base64VLQ.php @@ -0,0 +1,151 @@ +<?php + +/** + * SCSSPHP + * + * @copyright 2012-2020 Leaf Corcoran + * + * @license http://opensource.org/licenses/MIT MIT + * + * @link http://scssphp.github.io/scssphp + */ + +namespace ScssPhp\ScssPhp\SourceMap; + +/** + * Base 64 VLQ + * + * Based on the Base 64 VLQ implementation in Closure Compiler: + * https://github.com/google/closure-compiler/blob/master/src/com/google/debugging/sourcemap/Base64VLQ.java + * + * Copyright 2011 The Closure Compiler Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author John Lenz <johnlenz@google.com> + * @author Anthon Pang <anthon.pang@gmail.com> + * + * @internal + */ +class Base64VLQ +{ + // A Base64 VLQ digit can represent 5 bits, so it is base-32. + const VLQ_BASE_SHIFT = 5; + + // A mask of bits for a VLQ digit (11111), 31 decimal. + const VLQ_BASE_MASK = 31; + + // The continuation bit is the 6th bit. + const VLQ_CONTINUATION_BIT = 32; + + /** + * Returns the VLQ encoded value. + * + * @param int $value + * + * @return string + */ + public static function encode($value) + { + $encoded = ''; + $vlq = self::toVLQSigned($value); + + 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); + + if ($vlq > 0) { + $digit |= self::VLQ_CONTINUATION_BIT; + } + + $encoded .= Base64::encode($digit); + } while ($vlq > 0); + + return $encoded; + } + + /** + * Decodes VLQValue. + * + * @param string $str + * @param int $index + * + * @return int + */ + public static function decode($str, &$index) + { + $result = 0; + $shift = 0; + + do { + $c = $str[$index++]; + $digit = Base64::decode($c); + $continuation = ($digit & self::VLQ_CONTINUATION_BIT) != 0; + $digit &= self::VLQ_BASE_MASK; + $result = $result + ($digit << $shift); + $shift = $shift + self::VLQ_BASE_SHIFT; + } while ($continuation); + + return self::fromVLQSigned($result); + } + + /** + * Converts from a two-complement value to a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) + * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) + * + * @param int $value + * + * @return int + */ + private static function toVLQSigned($value) + { + if ($value < 0) { + return ((-$value) << 1) + 1; + } + + return ($value << 1) + 0; + } + + /** + * Converts to a two-complement value from a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 + * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 + * + * @param int $value + * + * @return int + */ + private static function fromVLQSigned($value) + { + $negate = ($value & 1) === 1; + + //$value >>>= 1; // unsigned right shift + $value = ($value >> 1) & PHP_INT_MAX; + + if (! $negate) { + return $value; + } + + // We need to OR 0x80000000 here to ensure the 32nd bit (the sign bit) is + // always set for negative numbers. If `value` were 1, (meaning `negate` is + // true and all other bits were zeros), `value` would now be 0. -0 is just + // 0, and doesn't flip the 32nd bit as intended. All positive numbers will + // successfully flip the 32nd bit without issue, so it's a noop for them. + return -$value | 0x80000000; + } +} diff --git a/vendor/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php b/vendor/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php new file mode 100644 index 000000000..ccd4f0261 --- /dev/null +++ b/vendor/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php @@ -0,0 +1,390 @@ +<?php + +/** + * SCSSPHP + * + * @copyright 2012-2020 Leaf Corcoran + * + * @license http://opensource.org/licenses/MIT MIT + * + * @link http://scssphp.github.io/scssphp + */ + +namespace ScssPhp\ScssPhp\SourceMap; + +use ScssPhp\ScssPhp\Exception\CompilerException; + +/** + * Source Map Generator + * + * {@internal Derivative of oyejorge/less.php's lib/SourceMap/Generator.php, relicensed with permission. }} + * + * @author Josh Schmidt <oyejorge@gmail.com> + * @author Nicolas FRANÇOIS <nicolas.francois@frog-labs.com> + * + * @internal + */ +class SourceMapGenerator +{ + /** + * What version of source map does the generator generate? + */ + const VERSION = 3; + + /** + * 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 + // on a server or removing repeated values in the 'sources' entry. + // This value is prepended to the individual entries in the 'source' field. + 'sourceRoot' => '', + + // an optional name of the generated code that this source map is associated with. + 'sourceMapFilename' => null, + + // url of the map + 'sourceMapURL' => null, + + // absolute path to a file to write the map to + 'sourceMapWriteTo' => null, + + // output source contents? + 'outputSourceFiles' => false, + + // base path for filename normalization + 'sourceMapRootpath' => '', + + // base path for filename normalization + 'sourceMapBasepath' => '' + ]; + + /** + * The base64 VLQ encoder + * + * @var \ScssPhp\ScssPhp\SourceMap\Base64VLQ + */ + protected $encoder; + + /** + * 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 = []; + + /** + * Array of contents map + * + * @var array + */ + protected $contentsMap = []; + + /** + * File to content map + * + * @var array<string, string> + */ + 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->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 + */ + public function addMapping($generatedLine, $generatedColumn, $originalLine, $originalColumn, $sourceFile) + { + $this->mappings[] = [ + 'generated_line' => $generatedLine, + 'generated_column' => $generatedColumn, + 'original_line' => $originalLine, + 'original_column' => $originalColumn, + 'source_file' => $sourceFile + ]; + + $this->sources[$sourceFile] = $sourceFile; + } + + /** + * Saves the source map to a file + * + * @param string $content The content to write + * + * @return string|null + * + * @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); + + // directory does not exist + if (! is_dir($dir)) { + // FIXME: create the dir automatically? + throw new CompilerException( + sprintf('The directory "%s" does not exist. Cannot save the source map.', $dir) + ); + } + + // FIXME: proper saving, with dir write check! + if (file_put_contents($file, $content) === false) { + throw new CompilerException(sprintf('Cannot save the source map to "%s"', $file)); + } + + return $this->options['sourceMapURL']; + } + + /** + * 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 = '') + { + $sourceMap = []; + $mappings = $this->generateMappings($prefix); + + // File version (always the first entry in the object) and must be a positive integer. + $sourceMap['version'] = self::VERSION; + + // An optional name of the generated code that this source map is associated with. + $file = $this->options['sourceMapFilename']; + + if ($file) { + $sourceMap['file'] = $file; + } + + // An optional source root, useful for relocating source files on a server or removing repeated values in the + // 'sources' entry. This value is prepended to the individual entries in the 'source' field. + $root = $this->options['sourceRoot']; + + if ($root) { + $sourceMap['sourceRoot'] = $root; + } + + // A list of original sources used by the 'mappings' entry. + $sourceMap['sources'] = []; + + foreach ($this->sources as $sourceFilename) { + $sourceMap['sources'][] = $this->normalizeFilename($sourceFilename); + } + + // A list of symbol names used by the 'mappings' entry. + $sourceMap['names'] = []; + + // A string with the encoded mapping data. + $sourceMap['mappings'] = $mappings; + + if ($this->options['outputSourceFiles']) { + // An optional list of source content, useful when the 'source' can't be hosted. + // The contents are listed in the same order as the sources above. + // 'null' may be used if some original sources should be retrieved by name. + $sourceMap['sourcesContent'] = $this->getSourcesContent(); + } + + // less.js compat fixes + 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; + } + + /** + * Returns the sources contents + * + * @return string[]|null + */ + protected function getSourcesContent() + { + if (empty($this->sources)) { + return null; + } + + $content = []; + + foreach ($this->sources as $sourceFile) { + $content[] = file_get_contents($sourceFile); + } + + return $content; + } + + /** + * 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 = '') + { + 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. + $groupedMap = $groupedMapEncoded = []; + + foreach ($this->mappings as $m) { + $groupedMap[$m['generated_line']][] = $m; + } + + 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[] = ';'; + } + + $lineMapEncoded = []; + $lastGeneratedColumn = 0; + + foreach ($lineMap as $m) { + $generatedColumn = $m['generated_column'] + $prefixColumn; + + $mapEncoded = $this->encoder->encode($generatedColumn - $lastGeneratedColumn); + $lastGeneratedColumn = $generatedColumn; + + // find the index + if ($m['source_file']) { + $index = $this->findFileIndex($m['source_file']); + + if ($index !== false) { + $mapEncoded .= $this->encoder->encode($index - $lastOriginalIndex); + $lastOriginalIndex = $index; + // lines are stored 0-based in SourceMap spec version 3 + $mapEncoded .= $this->encoder->encode($m['original_line'] - 1 - $lastOriginalLine); + $lastOriginalLine = $m['original_line'] - 1; + $mapEncoded .= $this->encoder->encode($m['original_column'] - $lastOriginalColumn); + $lastOriginalColumn = $m['original_column']; + } + } + + $lineMapEncoded[] = $mapEncoded; + } + + $groupedMapEncoded[] = implode(',', $lineMapEncoded) . ';'; + } + + return rtrim(implode($groupedMapEncoded), ';'); + } + + /** + * Finds the index for the filename + * + * @param string $filename + * + * @return int|false + */ + protected function findFileIndex($filename) + { + return $this->sourceKeys[$filename]; + } + + /** + * Normalize filename + * + * @param string $filename + * + * @return string + */ + protected function normalizeFilename($filename) + { + $filename = $this->fixWindowsPath($filename); + $rootpath = $this->options['sourceMapRootpath']; + $basePath = $this->options['sourceMapBasepath']; + + // "Trim" the 'sourceMapBasepath' from the output filename. + if (\strlen($basePath) && strpos($filename, $basePath) === 0) { + $filename = substr($filename, \strlen($basePath)); + } + + // Remove extra leading path separators. + if (strpos($filename, '\\') === 0 || strpos($filename, '/') === 0) { + $filename = substr($filename, 1); + } + + return $rootpath . $filename; + } + + /** + * Fix windows paths + * + * @param string $path + * @param bool $addEndSlash + * + * @return string + */ + public function fixWindowsPath($path, $addEndSlash = false) + { + $slash = ($addEndSlash) ? '/' : ''; + + if (! empty($path)) { + $path = str_replace('\\', '/', $path); + $path = rtrim($path, '/') . $slash; + } + + return $path; + } +} |