LessFilter.php

Namespace

Assetic\Filter

File

drupal/core/vendor/kriswallsmith/assetic/src/Assetic/Filter/LessFilter.php
View source
<?php

/*
 * This file is part of the Assetic package, an OpenSky project.
 *
 * (c) 2010-2013 OpenSky Project Inc
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace Assetic\Filter;

use Assetic\Asset\AssetInterface;
use Assetic\Exception\FilterException;
use Assetic\Factory\AssetFactory;
use Assetic\Util\LessUtils;

/**
 * Loads LESS files.
 *
 * @link http://lesscss.org/
 * @author Kris Wallsmith <kris.wallsmith@gmail.com>
 */
class LessFilter extends BaseNodeFilter implements DependencyExtractorInterface {
  private $nodeBin;

  /**
   * @var array
   */
  private $treeOptions;

  /**
   * @var array
   */
  private $parserOptions;

  /**
   * Load Paths
   *
   * A list of paths which less will search for includes.
   *
   * @var array
   */
  protected $loadPaths = array();

  /**
   * Constructor.
   *
   * @param string $nodeBin   The path to the node binary
   * @param array  $nodePaths An array of node paths
   */
  public function __construct($nodeBin = '/usr/bin/node', array $nodePaths = array()) {
    $this->nodeBin = $nodeBin;
    $this
      ->setNodePaths($nodePaths);
    $this->treeOptions = array();
    $this->parserOptions = array();
  }

  /**
   * @param bool $compress
   */
  public function setCompress($compress) {
    $this
      ->addTreeOption('compress', $compress);
  }
  public function setLoadPaths(array $loadPaths) {
    $this->loadPaths = $loadPaths;
  }

  /**
   * Adds a path where less will search for includes
   *
   * @param string $path Load path (absolute)
   */
  public function addLoadPath($path) {
    $this->loadPaths[] = $path;
  }

  /**
   * @param string $code
   * @param string $value
   */
  public function addTreeOption($code, $value) {
    $this->treeOptions[$code] = $value;
  }

  /**
   * @param string $code
   * @param string $value
   */
  public function addParserOption($code, $value) {
    $this->parserOptions[$code] = $value;
  }
  public function filterLoad(AssetInterface $asset) {
    static $format = <<<'EOF'
var less = require('less');
var sys  = require(process.binding('natives').util ? 'util' : 'sys');

new(less.Parser)(%s).parse(%s, function(e, tree) {
    if (e) {
        less.writeError(e);
        process.exit(2);
    }

    try {
        sys.print(tree.toCSS(%s));
    } catch (e) {
        less.writeError(e);
        process.exit(3);
    }
});

EOF;
    $root = $asset
      ->getSourceRoot();
    $path = $asset
      ->getSourcePath();

    // parser options
    $parserOptions = $this->parserOptions;
    if ($root && $path) {
      $parserOptions['paths'] = array(
        dirname($root . '/' . $path),
      );
      $parserOptions['filename'] = basename($path);
    }
    foreach ($this->loadPaths as $loadPath) {
      $parserOptions['paths'][] = $loadPath;
    }
    $pb = $this
      ->createProcessBuilder();
    $pb
      ->add($this->nodeBin)
      ->add($input = tempnam(sys_get_temp_dir(), 'assetic_less'));
    file_put_contents($input, sprintf($format, json_encode($parserOptions), json_encode($asset
      ->getContent()), json_encode($this->treeOptions)));
    $proc = $pb
      ->getProcess();
    $code = $proc
      ->run();
    unlink($input);
    if (0 !== $code) {
      throw FilterException::fromProcess($proc)
        ->setInput($asset
        ->getContent());
    }
    $asset
      ->setContent($proc
      ->getOutput());
  }
  public function filterDump(AssetInterface $asset) {
  }

  /**
   * @todo support for @import-once
   * @todo support for @import (less) "lib.css"
   */
  public function getChildren(AssetFactory $factory, $content, $loadPath = null) {
    $loadPaths = $this->loadPaths;
    if (null !== $loadPath) {
      $loadPaths[] = $loadPath;
    }
    if (empty($loadPaths)) {
      return array();
    }
    $children = array();
    foreach (LessUtils::extractImports($content) as $reference) {
      if ('.css' === substr($reference, -4)) {

        // skip normal css imports
        // todo: skip imports with media queries
        continue;
      }
      if ('.less' !== substr($reference, -5)) {
        $reference .= '.less';
      }
      foreach ($loadPaths as $loadPath) {
        if (file_exists($file = $loadPath . '/' . $reference)) {
          $coll = $factory
            ->createAsset($file, array(), array(
            'root' => $loadPath,
          ));
          foreach ($coll as $leaf) {
            $leaf
              ->ensureFilter($this);
            $children[] = $leaf;
            goto next_reference;
          }
        }
      }
      next_reference:
    }
    return $children;
  }

}

Classes

Namesort descending Description
LessFilter Loads LESS files.