1<?php
2
3/*
4 * This file is part of the Assetic package, an OpenSky project.
5 *
6 * (c) 2010-2014 OpenSky Project Inc
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Assetic\Filter;
13
14use Assetic\Asset\AssetInterface;
15use Assetic\Exception\FilterException;
16use Assetic\Factory\AssetFactory;
17use Assetic\Util\FilesystemUtils;
18
19/**
20 * Loads STYL files.
21 *
22 * @link http://learnboost.github.com/stylus/
23 * @author Konstantin Kudryashov <ever.zet@gmail.com>
24 */
25class StylusFilter extends BaseNodeFilter implements DependencyExtractorInterface
26{
27    private $nodeBin;
28    private $compress;
29    private $useNib;
30
31    /**
32     * Constructs filter.
33     *
34     * @param string $nodeBin   The path to the node binary
35     * @param array  $nodePaths An array of node paths
36     */
37    public function __construct($nodeBin = '/usr/bin/node', array $nodePaths = array())
38    {
39        $this->nodeBin = $nodeBin;
40        $this->setNodePaths($nodePaths);
41    }
42
43    /**
44     * Enable output compression.
45     *
46     * @param boolean $compress
47     */
48    public function setCompress($compress)
49    {
50        $this->compress = $compress;
51    }
52
53    /**
54     * Enable the use of Nib
55     *
56     * @param boolean $useNib
57     */
58    public function setUseNib($useNib)
59    {
60        $this->useNib = $useNib;
61    }
62
63    /**
64     * {@inheritdoc}
65     */
66    public function filterLoad(AssetInterface $asset)
67    {
68        static $format = <<<'EOF'
69var stylus = require('stylus');
70var sys    = require(process.binding('natives').util ? 'util' : 'sys');
71
72stylus(%s, %s)%s.render(function(e, css){
73    if (e) {
74        throw e;
75    }
76
77    sys.print(css);
78    process.exit(0);
79});
80
81EOF;
82
83        // parser options
84        $parserOptions = array();
85        if ($dir = $asset->getSourceDirectory()) {
86            $parserOptions['paths'] = array($dir);
87            $parserOptions['filename'] = basename($asset->getSourcePath());
88        }
89
90        if (null !== $this->compress) {
91            $parserOptions['compress'] = $this->compress;
92        }
93
94        $pb = $this->createProcessBuilder();
95
96        $pb->add($this->nodeBin)->add($input = FilesystemUtils::createTemporaryFile('stylus'));
97        file_put_contents($input, sprintf($format,
98            json_encode($asset->getContent()),
99            json_encode($parserOptions),
100            $this->useNib ? '.use(require(\'nib\')())' : ''
101        ));
102
103        $proc = $pb->getProcess();
104        $code = $proc->run();
105        unlink($input);
106
107        if (0 !== $code) {
108            throw FilterException::fromProcess($proc)->setInput($asset->getContent());
109        }
110
111        $asset->setContent($proc->getOutput());
112    }
113
114    /**
115     * {@inheritdoc}
116     */
117    public function filterDump(AssetInterface $asset)
118    {
119    }
120
121    public function getChildren(AssetFactory $factory, $content, $loadPath = null)
122    {
123        // todo
124        return array();
125    }
126}
127