forked from stylus/stylus
-
Notifications
You must be signed in to change notification settings - Fork 1
/
renderer.js
143 lines (123 loc) · 2.97 KB
/
renderer.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*!
* Stylus - Renderer
* Copyright(c) 2010 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Parser = require('./parser')
, Compiler = require('./visitor/compiler')
, Evaluator = require('./visitor/evaluator')
, utils = require('./utils')
, nodes = require('./nodes');
/**
* Initialize a new `Renderer` with the given `str` and `options`.
*
* @param {String} str
* @param {Object} options
* @api public
*/
var Renderer = module.exports = function Renderer(str, options) {
options = options || {};
options.globals = {};
options.functions = {};
options.imports = [__dirname + '/functions'];
options.paths = options.paths || [];
options.filename = options.filename || 'stylus';
this.options = options;
this.str = str;
};
/**
* Parse and evaluate AST, then callback `fn(err, css, js)`.
*
* @param {Function} fn
* @api public
*/
Renderer.prototype.render = function(fn){
var parser = this.parser = new Parser(this.str, this.options);
try {
nodes.filename = this.options.filename;
var ast = parser.parse();
this.evaluator = new Evaluator(ast, this.options);
ast = this.evaluator.evaluate();
var compiler = new Compiler(ast, this.options)
, css = compiler.compile()
, js = compiler.js;
fn(null, css, js);
} catch (err) {
var options = {};
options.input = err.input || this.str;
options.filename = err.filename || this.options.filename;
options.lineno = err.lineno || parser.lexer.lineno;
fn(utils.formatException(err, options));
}
};
/**
* Set option `key` to `val`.
*
* @param {String} key
* @param {Mixed} val
* @return {Renderer} for chaining
* @api public
*/
Renderer.prototype.set = function(key, val){
this.options[key] = val;
return this;
};
/**
* Include the given `path` to the lookup paths array.
*
* @param {String} path
* @return {Renderer} for chaining
* @api public
*/
Renderer.prototype.include = function(path){
this.options.paths.push(path);
return this;
};
/**
* Use the given `fn`.
*
* This allows for plugins to alter the renderer in
* any way they wish, exposing paths etc.
*
* @param {Function}
* @return {Renderer} for chaining
* @api public
*/
Renderer.prototype.use = function(fn){
fn.call(this, this);
return this;
};
/**
* Define function or global var with the given `name`. Optionally
* the function may accept full expressions, by setting `raw`
* to `true`.
*
* @param {String} name
* @param {Function|Node} fn
* @return {Renderer} for chaining
* @api public
*/
Renderer.prototype.define = function(name, fn, raw){
if (fn.nodeName) {
this.options.globals[name] = fn;
return this;
}
// function
this.options.functions[name] = fn;
if (undefined != raw) fn.raw = raw;
return this;
};
/**
* Import the given `file`.
*
* @param {String} file
* @return {Renderer} for chaining
* @api public
*/
Renderer.prototype.import = function(file){
this.options.imports.push(file);
return this;
};