]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blobdiff - vendor/oyejorge/less.php/lib/Less/SourceMap/Generator.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / vendor / oyejorge / less.php / lib / Less / SourceMap / Generator.php
diff --git a/vendor/oyejorge/less.php/lib/Less/SourceMap/Generator.php b/vendor/oyejorge/less.php/lib/Less/SourceMap/Generator.php
new file mode 100644 (file)
index 0000000..cc9e65f
--- /dev/null
@@ -0,0 +1,365 @@
+<?php\r
+\r
+/**\r
+ * Source map generator\r
+ *\r
+ * @package Less\r
+ * @subpackage Output\r
+ */\r
+class Less_SourceMap_Generator extends Less_Configurable {\r
+\r
+       /**\r
+        * What version of source map does the generator generate?\r
+        */\r
+       const VERSION = 3;\r
+\r
+       /**\r
+        * Array of default options\r
+        *\r
+        * @var array\r
+        */\r
+       protected $defaultOptions = array(\r
+                       // an optional source root, useful for relocating source files\r
+                       // on a server or removing repeated values in the 'sources' entry.\r
+                       // This value is prepended to the individual entries in the 'source' field.\r
+                       'sourceRoot'                    => '',\r
+\r
+                       // an optional name of the generated code that this source map is associated with.\r
+                       'sourceMapFilename'             => null,\r
+\r
+                       // url of the map\r
+                       'sourceMapURL'                  => null,\r
+\r
+                       // absolute path to a file to write the map to\r
+                       'sourceMapWriteTo'              => null,\r
+\r
+                       // output source contents?\r
+                       'outputSourceFiles'             => false,\r
+\r
+                       // base path for filename normalization\r
+                       'sourceMapRootpath'             => '',\r
+\r
+                       // base path for filename normalization\r
+                       'sourceMapBasepath'   => ''\r
+       );\r
+\r
+       /**\r
+        * The base64 VLQ encoder\r
+        *\r
+        * @var Less_SourceMap_Base64VLQ\r
+        */\r
+       protected $encoder;\r
+\r
+       /**\r
+        * Array of mappings\r
+        *\r
+        * @var array\r
+        */\r
+       protected $mappings = array();\r
+\r
+       /**\r
+        * The root node\r
+        *\r
+        * @var Less_Tree_Ruleset\r
+        */\r
+       protected $root;\r
+\r
+       /**\r
+        * Array of contents map\r
+        *\r
+        * @var array\r
+        */\r
+       protected $contentsMap = array();\r
+\r
+       /**\r
+        * File to content map\r
+        *\r
+        * @var array\r
+        */\r
+       protected $sources = array();\r
+       protected $source_keys = array();\r
+\r
+       /**\r
+        * Constructor\r
+        *\r
+        * @param Less_Tree_Ruleset $root The root node\r
+        * @param array $options Array of options\r
+        */\r
+       public function __construct(Less_Tree_Ruleset $root, $contentsMap, $options = array()){\r
+               $this->root = $root;\r
+               $this->contentsMap = $contentsMap;\r
+               $this->encoder = new Less_SourceMap_Base64VLQ();\r
+\r
+               $this->SetOptions($options);\r
+               \r
+               $this->options['sourceMapRootpath'] = $this->fixWindowsPath($this->options['sourceMapRootpath'], true);\r
+               $this->options['sourceMapBasepath'] = $this->fixWindowsPath($this->options['sourceMapBasepath'], true);\r
+       }\r
+\r
+       /**\r
+        * Generates the CSS\r
+        *\r
+        * @return string\r
+        */\r
+       public function generateCSS(){\r
+               $output = new Less_Output_Mapped($this->contentsMap, $this);\r
+\r
+               // catch the output\r
+               $this->root->genCSS($output);\r
+\r
+\r
+               $sourceMapUrl                           = $this->getOption('sourceMapURL');\r
+               $sourceMapFilename                      = $this->getOption('sourceMapFilename');\r
+               $sourceMapContent                       = $this->generateJson();\r
+               $sourceMapWriteTo                       = $this->getOption('sourceMapWriteTo');\r
+\r
+               if( !$sourceMapUrl && $sourceMapFilename ){\r
+                       $sourceMapUrl = $this->normalizeFilename($sourceMapFilename);\r
+               }\r
+\r
+               // write map to a file\r
+               if( $sourceMapWriteTo ){\r
+                       $this->saveMap($sourceMapWriteTo, $sourceMapContent);\r
+               }\r
+\r
+               // inline the map\r
+               if( !$sourceMapUrl ){\r
+                       $sourceMapUrl = sprintf('data:application/json,%s', Less_Functions::encodeURIComponent($sourceMapContent));\r
+               }\r
+\r
+               if( $sourceMapUrl ){\r
+                       $output->add( sprintf('/*# sourceMappingURL=%s */', $sourceMapUrl) );\r
+               }\r
+\r
+               return $output->toString();\r
+       }\r
+\r
+       /**\r
+        * Saves the source map to a file\r
+        *\r
+        * @param string $file The absolute path to a file\r
+        * @param string $content The content to write\r
+        * @throws Exception If the file could not be saved\r
+        */\r
+       protected function saveMap($file, $content){\r
+               $dir = dirname($file);\r
+               // directory does not exist\r
+               if( !is_dir($dir) ){\r
+                       // FIXME: create the dir automatically?\r
+                       throw new Exception(sprintf('The directory "%s" does not exist. Cannot save the source map.', $dir));\r
+               }\r
+               // FIXME: proper saving, with dir write check!\r
+               if(file_put_contents($file, $content) === false){\r
+                       throw new Exception(sprintf('Cannot save the source map to "%s"', $file));\r
+               }\r
+               return true;\r
+       }\r
+\r
+       /**\r
+        * Normalizes the filename\r
+        *\r
+        * @param string $filename\r
+        * @return string\r
+        */\r
+       protected function normalizeFilename($filename){\r
+\r
+               $filename = $this->fixWindowsPath($filename);\r
+\r
+               $rootpath = $this->getOption('sourceMapRootpath');\r
+               $basePath = $this->getOption('sourceMapBasepath');\r
+\r
+               // "Trim" the 'sourceMapBasepath' from the output filename.\r
+               if (strpos($filename, $basePath) === 0) {\r
+                       $filename = substr($filename, strlen($basePath));\r
+               }\r
+\r
+               // Remove extra leading path separators.\r
+               if(strpos($filename, '\\') === 0 || strpos($filename, '/') === 0){\r
+                       $filename = substr($filename, 1);\r
+               }\r
+\r
+               return $rootpath . $filename;\r
+       }\r
+\r
+       /**\r
+        * Adds a mapping\r
+        *\r
+        * @param integer $generatedLine The line number in generated file\r
+        * @param integer $generatedColumn The column number in generated file\r
+        * @param integer $originalLine The line number in original file\r
+        * @param integer $originalColumn The column number in original file\r
+        * @param string $sourceFile The original source file\r
+        */\r
+       public function addMapping($generatedLine, $generatedColumn, $originalLine, $originalColumn, $fileInfo ){\r
+\r
+               $this->mappings[] = array(\r
+                       'generated_line' => $generatedLine,\r
+                       'generated_column' => $generatedColumn,\r
+                       'original_line' => $originalLine,\r
+                       'original_column' => $originalColumn,\r
+                       'source_file' => $fileInfo['currentUri']\r
+               );\r
+\r
+               $this->sources[$fileInfo['currentUri']] = $fileInfo['filename'];\r
+       }\r
+\r
+\r
+       /**\r
+        * Generates the JSON source map\r
+        *\r
+        * @return string\r
+        * @see https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#\r
+        */\r
+       protected function generateJson(){\r
+\r
+               $sourceMap = array();\r
+               $mappings = $this->generateMappings();\r
+\r
+               // File version (always the first entry in the object) and must be a positive integer.\r
+               $sourceMap['version'] = self::VERSION;\r
+\r
+\r
+               // An optional name of the generated code that this source map is associated with.\r
+               $file = $this->getOption('sourceMapFilename');\r
+               if( $file ){\r
+                       $sourceMap['file'] = $file;\r
+               }\r
+\r
+\r
+               // 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.\r
+               $root = $this->getOption('sourceRoot');\r
+               if( $root ){\r
+                       $sourceMap['sourceRoot'] = $root;\r
+               }\r
+\r
+\r
+               // A list of original sources used by the 'mappings' entry.\r
+               $sourceMap['sources'] = array();\r
+               foreach($this->sources as $source_uri => $source_filename){\r
+                       $sourceMap['sources'][] = $this->normalizeFilename($source_filename);\r
+               }\r
+\r
+\r
+               // A list of symbol names used by the 'mappings' entry.\r
+               $sourceMap['names'] = array();\r
+\r
+               // A string with the encoded mapping data.\r
+               $sourceMap['mappings'] = $mappings;\r
+\r
+               if( $this->getOption('outputSourceFiles') ){\r
+                       // An optional list of source content, useful when the 'source' can't be hosted.\r
+                       // The contents are listed in the same order as the sources above.\r
+                       // 'null' may be used if some original sources should be retrieved by name.\r
+                       $sourceMap['sourcesContent'] = $this->getSourcesContent();\r
+               }\r
+\r
+               // less.js compat fixes\r
+               if( count($sourceMap['sources']) && empty($sourceMap['sourceRoot']) ){\r
+                       unset($sourceMap['sourceRoot']);\r
+               }\r
+\r
+               return json_encode($sourceMap);\r
+       }\r
+\r
+       /**\r
+        * Returns the sources contents\r
+        *\r
+        * @return array|null\r
+        */\r
+       protected function getSourcesContent(){\r
+               if(empty($this->sources)){\r
+                       return;\r
+               }\r
+               $content = array();\r
+               foreach($this->sources as $sourceFile){\r
+                       $content[] = file_get_contents($sourceFile);\r
+               }\r
+               return $content;\r
+       }\r
+\r
+       /**\r
+        * Generates the mappings string\r
+        *\r
+        * @return string\r
+        */\r
+       public function generateMappings(){\r
+\r
+               if( !count($this->mappings) ){\r
+                       return '';\r
+               }\r
+\r
+               $this->source_keys = array_flip(array_keys($this->sources));\r
+\r
+\r
+               // group mappings by generated line number.\r
+               $groupedMap = $groupedMapEncoded = array();\r
+               foreach($this->mappings as $m){\r
+                       $groupedMap[$m['generated_line']][] = $m;\r
+               }\r
+               ksort($groupedMap);\r
+\r
+               $lastGeneratedLine = $lastOriginalIndex = $lastOriginalLine = $lastOriginalColumn = 0;\r
+\r
+               foreach($groupedMap as $lineNumber => $line_map){\r
+                       while(++$lastGeneratedLine < $lineNumber){\r
+                               $groupedMapEncoded[] = ';';\r
+                       }\r
+\r
+                       $lineMapEncoded = array();\r
+                       $lastGeneratedColumn = 0;\r
+\r
+                       foreach($line_map as $m){\r
+                               $mapEncoded = $this->encoder->encode($m['generated_column'] - $lastGeneratedColumn);\r
+                               $lastGeneratedColumn = $m['generated_column'];\r
+\r
+                               // find the index\r
+                               if( $m['source_file'] ){\r
+                                       $index = $this->findFileIndex($m['source_file']);\r
+                                       if( $index !== false ){\r
+                                               $mapEncoded .= $this->encoder->encode($index - $lastOriginalIndex);\r
+                                               $lastOriginalIndex = $index;\r
+\r
+                                               // lines are stored 0-based in SourceMap spec version 3\r
+                                               $mapEncoded .= $this->encoder->encode($m['original_line'] - 1 - $lastOriginalLine);\r
+                                               $lastOriginalLine = $m['original_line'] - 1;\r
+\r
+                                               $mapEncoded .= $this->encoder->encode($m['original_column'] - $lastOriginalColumn);\r
+                                               $lastOriginalColumn = $m['original_column'];\r
+                                       }\r
+                               }\r
+\r
+                               $lineMapEncoded[] = $mapEncoded;\r
+                       }\r
+\r
+                       $groupedMapEncoded[] = implode(',', $lineMapEncoded) . ';';\r
+               }\r
+\r
+               return rtrim(implode($groupedMapEncoded), ';');\r
+       }\r
+\r
+       /**\r
+        * Finds the index for the filename\r
+        *\r
+        * @param string $filename\r
+        * @return integer|false\r
+        */\r
+       protected function findFileIndex($filename){\r
+               return $this->source_keys[$filename];\r
+       }\r
+\r
+       /**\r
+        * fix windows paths\r
+        * @param  string $path\r
+        * @return string      \r
+        */\r
+       public function fixWindowsPath($path, $addEndSlash = false){\r
+               $slash = ($addEndSlash) ? '/' : '';\r
+               if( !empty($path) ){\r
+                       $path = str_replace('\\', '/', $path);\r
+                       $path = rtrim($path,'/') . $slash;\r
+               }\r
+\r
+               return $path;\r
+       }\r
+\r
+}
\ No newline at end of file