4
* This file is part of the Assetic package, an OpenSky project.
6
* (c) 2010-2013 OpenSky Project Inc
8
* For the full copyright and license information, please view the LICENSE
9
* file that was distributed with this source code.
12
namespace Assetic\Filter;
14
use Assetic\Asset\AssetInterface;
15
use Assetic\Exception\FilterException;
16
use Assetic\Factory\AssetFactory;
17
use Assetic\Util\LessUtils;
22
* @link http://lesscss.org/
23
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
25
class LessFilter extends BaseNodeFilter implements DependencyExtractorInterface
37
private $parserOptions;
42
* A list of paths which less will search for includes.
46
protected $loadPaths = array();
51
* @param string $nodeBin The path to the node binary
52
* @param array $nodePaths An array of node paths
54
public function __construct($nodeBin = '/usr/bin/node', array $nodePaths = array())
56
$this->nodeBin = $nodeBin;
57
$this->setNodePaths($nodePaths);
58
$this->treeOptions = array();
59
$this->parserOptions = array();
63
* @param bool $compress
65
public function setCompress($compress)
67
$this->addTreeOption('compress', $compress);
70
public function setLoadPaths(array $loadPaths)
72
$this->loadPaths = $loadPaths;
76
* Adds a path where less will search for includes
78
* @param string $path Load path (absolute)
80
public function addLoadPath($path)
82
$this->loadPaths[] = $path;
87
* @param string $value
89
public function addTreeOption($code, $value)
91
$this->treeOptions[$code] = $value;
96
* @param string $value
98
public function addParserOption($code, $value)
100
$this->parserOptions[$code] = $value;
103
public function filterLoad(AssetInterface $asset)
105
static $format = <<<'EOF'
106
var less = require('less');
107
var sys = require(process.binding('natives').util ? 'util' : 'sys');
109
new(less.Parser)(%s).parse(%s, function(e, tree) {
116
sys.print(tree.toCSS(%s));
125
$root = $asset->getSourceRoot();
126
$path = $asset->getSourcePath();
129
$parserOptions = $this->parserOptions;
130
if ($root && $path) {
131
$parserOptions['paths'] = array(dirname($root.'/'.$path));
132
$parserOptions['filename'] = basename($path);
135
foreach ($this->loadPaths as $loadPath) {
136
$parserOptions['paths'][] = $loadPath;
139
$pb = $this->createProcessBuilder();
141
$pb->add($this->nodeBin)->add($input = tempnam(sys_get_temp_dir(), 'assetic_less'));
142
file_put_contents($input, sprintf($format,
143
json_encode($parserOptions),
144
json_encode($asset->getContent()),
145
json_encode($this->treeOptions)
148
$proc = $pb->getProcess();
149
$code = $proc->run();
153
throw FilterException::fromProcess($proc)->setInput($asset->getContent());
156
$asset->setContent($proc->getOutput());
159
public function filterDump(AssetInterface $asset)
164
* @todo support for import-once
165
* @todo support for import (less) "lib.css"
167
public function getChildren(AssetFactory $factory, $content, $loadPath = null)
169
$loadPaths = $this->loadPaths;
170
if (null !== $loadPath) {
171
$loadPaths[] = $loadPath;
174
if (empty($loadPaths)) {
179
foreach (LessUtils::extractImports($content) as $reference) {
180
if ('.css' === substr($reference, -4)) {
181
// skip normal css imports
182
// todo: skip imports with media queries
186
if ('.less' !== substr($reference, -5)) {
187
$reference .= '.less';
190
foreach ($loadPaths as $loadPath) {
191
if (file_exists($file = $loadPath.'/'.$reference)) {
192
$coll = $factory->createAsset($file, array(), array('root' => $loadPath));
193
foreach ($coll as $leaf) {
194
$leaf->ensureFilter($this);