1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | var Parser = require('./parser')
|
13 | , EventEmitter = require('events').EventEmitter
|
14 | , Evaluator = require('./visitor/evaluator')
|
15 | , Normalizer = require('./visitor/normalizer')
|
16 | , events = new EventEmitter
|
17 | , utils = require('./utils')
|
18 | , nodes = require('./nodes')
|
19 | , join = require('path').join;
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | module.exports = Renderer;
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | function Renderer(str, options) {
|
36 | options = options || {};
|
37 | options.globals = options.globals || {};
|
38 | options.functions = options.functions || {};
|
39 | options.use = options.use || [];
|
40 | options.use = Array.isArray(options.use) ? options.use : [options.use];
|
41 | options.imports = [join(__dirname, 'functions')];
|
42 | options.paths = options.paths || [];
|
43 | options.filename = options.filename || 'stylus';
|
44 | options.Evaluator = options.Evaluator || Evaluator;
|
45 | this.options = options;
|
46 | this.str = str;
|
47 | this.events = events;
|
48 | };
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 | Renderer.prototype.__proto__ = EventEmitter.prototype;
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 | module.exports.events = events;
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 | Renderer.prototype.render = function(fn){
|
70 | var parser = this.parser = new Parser(this.str, this.options);
|
71 |
|
72 |
|
73 | for (var i = 0, len = this.options.use.length; i < len; i++) {
|
74 | this.use(this.options.use[i]);
|
75 | }
|
76 |
|
77 | try {
|
78 | nodes.filename = this.options.filename;
|
79 |
|
80 | var ast = parser.parse();
|
81 |
|
82 |
|
83 | this.evaluator = new this.options.Evaluator(ast, this.options);
|
84 | this.nodes = nodes;
|
85 | this.evaluator.renderer = this;
|
86 | ast = this.evaluator.evaluate();
|
87 |
|
88 |
|
89 | var normalizer = new Normalizer(ast, this.options);
|
90 | ast = normalizer.normalize();
|
91 |
|
92 |
|
93 | var compiler = this.options.sourcemap
|
94 | ? new (require('./visitor/sourcemapper'))(ast, this.options)
|
95 | : new (require('./visitor/compiler'))(ast, this.options)
|
96 | , css = compiler.compile();
|
97 |
|
98 |
|
99 | if (this.options.sourcemap) this.sourcemap = compiler.map.toJSON();
|
100 |
|
101 | var listeners = this.listeners('end');
|
102 | if (fn) listeners.push(fn);
|
103 | for (var i = 0, len = listeners.length; i < len; i++) {
|
104 | var ret = listeners[i](null, css);
|
105 | if (ret) css = ret;
|
106 | }
|
107 | if (!fn) return css;
|
108 | } catch (err) {
|
109 | var options = {};
|
110 | options.input = err.input || this.str;
|
111 | options.filename = err.filename || this.options.filename;
|
112 | options.lineno = err.lineno || parser.lexer.prev.lineno;
|
113 | options.column = err.column || parser.lexer.prev.column;
|
114 | if (!fn) throw utils.formatException(err, options);
|
115 | fn(utils.formatException(err, options));
|
116 | }
|
117 | };
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 | Renderer.prototype.deps = function(filename){
|
128 | if (filename) this.options.filename = filename;
|
129 |
|
130 | var DepsResolver = require('./visitor/deps-resolver')
|
131 | , parser = new Parser(this.str, this.options);
|
132 |
|
133 | try {
|
134 | nodes.filename = this.options.filename;
|
135 |
|
136 | var ast = parser.parse()
|
137 | , resolver = new DepsResolver(ast, this.options);
|
138 |
|
139 |
|
140 | return resolver.resolve();
|
141 | } catch (err) {
|
142 | var options = {};
|
143 | options.input = err.input || this.str;
|
144 | options.filename = err.filename || this.options.filename;
|
145 | options.lineno = err.lineno || parser.lexer.prev.lineno;
|
146 | options.column = err.column || parser.lexer.prev.column;
|
147 | throw utils.formatException(err, options);
|
148 | }
|
149 | };
|
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 |
|
159 |
|
160 | Renderer.prototype.set = function(key, val){
|
161 | this.options[key] = val;
|
162 | return this;
|
163 | };
|
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 | Renderer.prototype.get = function(key){
|
174 | return this.options[key];
|
175 | };
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 | Renderer.prototype.include = function(path){
|
186 | this.options.paths.push(path);
|
187 | return this;
|
188 | };
|
189 |
|
190 |
|
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 | Renderer.prototype.use = function(fn){
|
202 | fn.call(this, this);
|
203 | return this;
|
204 | };
|
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 | Renderer.prototype.define = function(name, fn, raw){
|
218 | fn = utils.coerce(fn, raw);
|
219 |
|
220 | if (fn.nodeName) {
|
221 | this.options.globals[name] = fn;
|
222 | return this;
|
223 | }
|
224 |
|
225 |
|
226 | this.options.functions[name] = fn;
|
227 | if (undefined != raw) fn.raw = raw;
|
228 | return this;
|
229 | };
|
230 |
|
231 |
|
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 | Renderer.prototype.import = function(file){
|
240 | this.options.imports.push(file);
|
241 | return this;
|
242 | };
|
243 |
|
244 |
|