[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/lib/lessphp/SourceMap/ -> Generator.php (source)

   1  <?php
   2  
   3  /**

   4   * Source map generator

   5   *

   6   * @package Less

   7   * @subpackage Output

   8   */
   9  class Less_SourceMap_Generator extends Less_Configurable {
  10  
  11      /**

  12       * What version of source map does the generator generate?

  13       */
  14      const VERSION = 3;
  15  
  16      /**

  17       * Array of default options

  18       *

  19       * @var array

  20       */
  21      protected $defaultOptions = array(
  22              // an optional source root, useful for relocating source files

  23              // on a server or removing repeated values in the 'sources' entry.

  24              // This value is prepended to the individual entries in the 'source' field.

  25              'sourceRoot'            => '',
  26  
  27              // an optional name of the generated code that this source map is associated with.

  28              'sourceMapFilename'        => null,
  29  
  30              // url of the map

  31              'sourceMapURL'            => null,
  32  
  33              // absolute path to a file to write the map to

  34              'sourceMapWriteTo'        => null,
  35  
  36              // output source contents?

  37              'outputSourceFiles'        => false,
  38  
  39              // base path for filename normalization

  40              'sourceMapBasepath'        => ''
  41      );
  42  
  43      /**

  44       * The base64 VLQ encoder

  45       *

  46       * @var Less_SourceMap_Base64VLQ

  47       */
  48      protected $encoder;
  49  
  50      /**

  51       * Array of mappings

  52       *

  53       * @var array

  54       */
  55      protected $mappings = array();
  56  
  57      /**

  58       * The root node

  59       *

  60       * @var Less_Tree_Ruleset

  61       */
  62      protected $root;
  63  
  64      /**

  65       * Array of contents map

  66       *

  67       * @var array

  68       */
  69      protected $contentsMap = array();
  70  
  71      /**

  72       * File to content map

  73       *

  74       * @var array

  75       */
  76      protected $sources = array();
  77  
  78      /**

  79       * Constructor

  80       *

  81       * @param Less_Tree_Ruleset $root The root node

  82       * @param array $options Array of options

  83       */
  84  	public function __construct(Less_Tree_Ruleset $root, $contentsMap, $options = array()){
  85          $this->root = $root;
  86          $this->contentsMap = $contentsMap;
  87          $this->encoder = new Less_SourceMap_Base64VLQ();
  88  
  89          $this->SetOptions($options);
  90  
  91  
  92          // fix windows paths

  93          if( isset($this->options['sourceMapBasepath']) ){
  94              $this->options['sourceMapBasepath'] = str_replace('\\', '/', $this->options['sourceMapBasepath']);
  95          }
  96      }
  97  
  98      /**

  99       * Generates the CSS

 100       *

 101       * @return string

 102       */
 103  	public function generateCSS(){
 104          $output = new Less_Output_Mapped($this->contentsMap, $this);
 105  
 106          // catch the output

 107          $this->root->genCSS($output);
 108  
 109  
 110          $sourceMapUrl                = $this->getOption('sourceMapURL');
 111          $sourceMapFilename            = $this->getOption('sourceMapFilename');
 112          $sourceMapContent            = $this->generateJson();
 113          $sourceMapWriteTo            = $this->getOption('sourceMapWriteTo');
 114  
 115          if( !$sourceMapUrl && $sourceMapFilename ){
 116              $sourceMapUrl = $this->normalizeFilename($sourceMapFilename);
 117          }
 118  
 119          // write map to a file

 120          if( $sourceMapWriteTo ){
 121              $this->saveMap($sourceMapWriteTo, $sourceMapContent);
 122          }
 123  
 124          // inline the map

 125          if( !$sourceMapUrl ){
 126              $sourceMapUrl = sprintf('data:application/json,%s', Less_Functions::encodeURIComponent($sourceMapContent));
 127          }
 128  
 129          if( $sourceMapUrl ){
 130              $output->add( sprintf('/*# sourceMappingURL=%s */', $sourceMapUrl) );
 131          }
 132  
 133          return $output->toString();
 134      }
 135  
 136      /**

 137       * Saves the source map to a file

 138       *

 139       * @param string $file The absolute path to a file

 140       * @param string $content The content to write

 141       * @throws Exception If the file could not be saved

 142       */
 143  	protected function saveMap($file, $content){
 144          $dir = dirname($file);
 145          // directory does not exist

 146          if( !is_dir($dir) ){
 147              // FIXME: create the dir automatically?

 148              throw new Exception(sprintf('The directory "%s" does not exist. Cannot save the source map.', $dir));
 149          }
 150          // FIXME: proper saving, with dir write check!

 151          if(file_put_contents($file, $content) === false){
 152              throw new Exception(sprintf('Cannot save the source map to "%s"', $file));
 153          }
 154          return true;
 155      }
 156  
 157      /**

 158       * Normalizes the filename

 159       *

 160       * @param string $filename

 161       * @return string

 162       */
 163  	protected function normalizeFilename($filename){
 164          $filename = str_replace('\\', '/', $filename);
 165          $basePath = $this->getOption('sourceMapBasepath');
 166  
 167          if( $basePath && ($pos = strpos($filename, $basePath)) !== false ){
 168              $filename = substr($filename, $pos + strlen($basePath));
 169              if(strpos($filename, '\\') === 0 || strpos($filename, '/') === 0){
 170                  $filename = substr($filename, 1);
 171              }
 172          }
 173          return sprintf('%s%s', $this->getOption('sourceMapRootpath'), $filename);
 174      }
 175  
 176      /**

 177       * Adds a mapping

 178       *

 179       * @param integer $generatedLine The line number in generated file

 180       * @param integer $generatedColumn The column number in generated file

 181       * @param integer $originalLine The line number in original file

 182       * @param integer $originalColumn The column number in original file

 183       * @param string $sourceFile The original source file

 184       */
 185  	public function addMapping($generatedLine, $generatedColumn, $originalLine, $originalColumn, $sourceFile){
 186          $this->mappings[] = array(
 187              'generated_line' => $generatedLine,
 188              'generated_column' => $generatedColumn,
 189              'original_line' => $originalLine,
 190              'original_column' => $originalColumn,
 191              'source_file' => $sourceFile
 192          );
 193  
 194  
 195          $norm_file = $this->normalizeFilename($sourceFile);
 196  
 197          $this->sources[$norm_file] = $sourceFile;
 198      }
 199  
 200  
 201      /**

 202       * Generates the JSON source map

 203       *

 204       * @return string

 205       * @see https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#

 206       */
 207  	protected function generateJson(){
 208  
 209          $sourceMap = array();
 210          $mappings = $this->generateMappings();
 211  
 212          // File version (always the first entry in the object) and must be a positive integer.

 213          $sourceMap['version'] = self::VERSION;
 214  
 215  
 216          // An optional name of the generated code that this source map is associated with.

 217          $file = $this->getOption('sourceMapFilename');
 218          if( $file ){
 219              $sourceMap['file'] = $file;
 220          }
 221  
 222  
 223          // 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.

 224          $root = $this->getOption('sourceRoot');
 225          if( $root ){
 226              $sourceMap['sourceRoot'] = $root;
 227          }
 228  
 229  
 230          // A list of original sources used by the 'mappings' entry.

 231          $sourceMap['sources'] = array_keys($this->sources);
 232  
 233  
 234  
 235          // A list of symbol names used by the 'mappings' entry.

 236          $sourceMap['names'] = array();
 237  
 238          // A string with the encoded mapping data.

 239          $sourceMap['mappings'] = $mappings;
 240  
 241          if( $this->getOption('outputSourceFiles') ){
 242              // An optional list of source content, useful when the 'source' can't be hosted.

 243              // The contents are listed in the same order as the sources above.

 244              // 'null' may be used if some original sources should be retrieved by name.

 245              $sourceMap['sourcesContent'] = $this->getSourcesContent();
 246          }
 247  
 248          // less.js compat fixes

 249          if( count($sourceMap['sources']) && empty($sourceMap['sourceRoot']) ){
 250              unset($sourceMap['sourceRoot']);
 251          }
 252  
 253          return json_encode($sourceMap);
 254      }
 255  
 256      /**

 257       * Returns the sources contents

 258       *

 259       * @return array|null

 260       */
 261  	protected function getSourcesContent(){
 262          if(empty($this->sources)){
 263              return;
 264          }
 265          $content = array();
 266          foreach($this->sources as $sourceFile){
 267              $content[] = file_get_contents($sourceFile);
 268          }
 269          return $content;
 270      }
 271  
 272      /**

 273       * Generates the mappings string

 274       *

 275       * @return string

 276       */
 277  	public function generateMappings(){
 278  
 279          if( !count($this->mappings) ){
 280              return '';
 281          }
 282  
 283          // group mappings by generated line number.

 284          $groupedMap = $groupedMapEncoded = array();
 285          foreach($this->mappings as $m){
 286              $groupedMap[$m['generated_line']][] = $m;
 287          }
 288          ksort($groupedMap);
 289  
 290          $lastGeneratedLine = $lastOriginalIndex = $lastOriginalLine = $lastOriginalColumn = 0;
 291  
 292          foreach($groupedMap as $lineNumber => $line_map){
 293              while(++$lastGeneratedLine < $lineNumber){
 294                  $groupedMapEncoded[] = ';';
 295              }
 296  
 297              $lineMapEncoded = array();
 298              $lastGeneratedColumn = 0;
 299  
 300              foreach($line_map as $m){
 301                  $mapEncoded = $this->encoder->encode($m['generated_column'] - $lastGeneratedColumn);
 302                  $lastGeneratedColumn = $m['generated_column'];
 303  
 304                  // find the index

 305                  if( $m['source_file'] ){
 306                      $index = $this->findFileIndex($this->normalizeFilename($m['source_file']));
 307                      if( $index !== false ){
 308                          $mapEncoded .= $this->encoder->encode($index - $lastOriginalIndex);
 309                          $lastOriginalIndex = $index;
 310  
 311                          // lines are stored 0-based in SourceMap spec version 3

 312                          $mapEncoded .= $this->encoder->encode($m['original_line'] - 1 - $lastOriginalLine);
 313                          $lastOriginalLine = $m['original_line'] - 1;
 314  
 315                          $mapEncoded .= $this->encoder->encode($m['original_column'] - $lastOriginalColumn);
 316                          $lastOriginalColumn = $m['original_column'];
 317                      }
 318                  }
 319  
 320                  $lineMapEncoded[] = $mapEncoded;
 321              }
 322  
 323              $groupedMapEncoded[] = implode(',', $lineMapEncoded) . ';';
 324          }
 325  
 326          return rtrim(implode($groupedMapEncoded), ';');
 327      }
 328  
 329      /**

 330       * Finds the index for the filename

 331       *

 332       * @param string $filename

 333       * @return integer|false

 334       */
 335  	protected function findFileIndex($filename){
 336          return array_search($filename, array_keys($this->sources));
 337      }
 338  
 339  }


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1