stylus-source 0.15.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/.DS_Store +0 -0
  2. data/README.md +3 -0
  3. data/lib/.DS_Store +0 -0
  4. data/lib/node_modules/cssom/.idea/CSSOM.iml +9 -0
  5. data/lib/node_modules/cssom/.idea/dictionaries/nv.xml +3 -0
  6. data/lib/node_modules/cssom/.idea/encodings.xml +5 -0
  7. data/lib/node_modules/cssom/.idea/misc.xml +17 -0
  8. data/lib/node_modules/cssom/.idea/modules.xml +9 -0
  9. data/lib/node_modules/cssom/.idea/projectCodeStyle.xml +82 -0
  10. data/lib/node_modules/cssom/.idea/vcs.xml +8 -0
  11. data/lib/node_modules/cssom/.idea/workspace.xml +467 -0
  12. data/lib/node_modules/cssom/.livereload +19 -0
  13. data/lib/node_modules/cssom/Jakefile +37 -0
  14. data/lib/node_modules/cssom/README.mdown +33 -0
  15. data/lib/node_modules/cssom/Rakefile +23 -0
  16. data/lib/node_modules/cssom/docs/.livereload +19 -0
  17. data/lib/node_modules/cssom/docs/bar.css +3 -0
  18. data/lib/node_modules/cssom/docs/demo.css +0 -0
  19. data/lib/node_modules/cssom/docs/foo.css +4 -0
  20. data/lib/node_modules/cssom/docs/parse.html +170 -0
  21. data/lib/node_modules/cssom/docs/parse2.html +431 -0
  22. data/lib/node_modules/cssom/index.html +100 -0
  23. data/lib/node_modules/cssom/lib/CSSImportRule.js +34 -0
  24. data/lib/node_modules/cssom/lib/CSSMediaRule.js +38 -0
  25. data/lib/node_modules/cssom/lib/CSSOM.js +3 -0
  26. data/lib/node_modules/cssom/lib/CSSRule.js +38 -0
  27. data/lib/node_modules/cssom/lib/CSSStyleDeclaration.js +130 -0
  28. data/lib/node_modules/cssom/lib/CSSStyleRule.js +187 -0
  29. data/lib/node_modules/cssom/lib/CSSStyleSheet.js +85 -0
  30. data/lib/node_modules/cssom/lib/MediaList.js +61 -0
  31. data/lib/node_modules/cssom/lib/StyleSheet.js +15 -0
  32. data/lib/node_modules/cssom/lib/clone.js +69 -0
  33. data/lib/node_modules/cssom/lib/index.js +10 -0
  34. data/lib/node_modules/cssom/lib/parse.js +195 -0
  35. data/lib/node_modules/cssom/media.html +17 -0
  36. data/lib/node_modules/cssom/package.json +30 -0
  37. data/lib/node_modules/cssom/plugins/toHTML.js +32 -0
  38. data/lib/node_modules/cssom/server/index.html +22 -0
  39. data/lib/node_modules/cssom/server/index.js +21 -0
  40. data/lib/node_modules/cssom/shorthands.html +21 -0
  41. data/lib/node_modules/cssom/test/CSSStyleDeclaration.test.js +35 -0
  42. data/lib/node_modules/cssom/test/CSSStyleRule.test.js +12 -0
  43. data/lib/node_modules/cssom/test/CSSStyleSheet.test.js +16 -0
  44. data/lib/node_modules/cssom/test/MediaList.test.js +21 -0
  45. data/lib/node_modules/cssom/test/clone.test.js +38 -0
  46. data/lib/node_modules/cssom/test/fixtures/dummy.css +3 -0
  47. data/lib/node_modules/cssom/test/helper.js +97 -0
  48. data/lib/node_modules/cssom/test/index.html +42 -0
  49. data/lib/node_modules/cssom/test/parse.test.js +346 -0
  50. data/lib/node_modules/cssom/test/vendor/qunit.css +189 -0
  51. data/lib/node_modules/cssom/test/vendor/qunit.js +1341 -0
  52. data/lib/node_modules/growl/History.md +16 -0
  53. data/lib/node_modules/growl/Readme.md +74 -0
  54. data/lib/node_modules/growl/lib/growl.js +82 -0
  55. data/lib/node_modules/growl/package.json +6 -0
  56. data/lib/node_modules/growl/test.js +17 -0
  57. data/lib/stylus/colors.js +156 -0
  58. data/lib/stylus/convert/css.js +130 -0
  59. data/lib/stylus/errors.js +58 -0
  60. data/lib/stylus/functions/image.js +120 -0
  61. data/lib/stylus/functions/index.js +722 -0
  62. data/lib/stylus/functions/index.styl +123 -0
  63. data/lib/stylus/functions/url.js +98 -0
  64. data/lib/stylus/lexer.js +728 -0
  65. data/lib/stylus/middleware.js +223 -0
  66. data/lib/stylus/nodes/arguments.js +65 -0
  67. data/lib/stylus/nodes/binop.js +54 -0
  68. data/lib/stylus/nodes/block.js +99 -0
  69. data/lib/stylus/nodes/boolean.js +103 -0
  70. data/lib/stylus/nodes/call.js +57 -0
  71. data/lib/stylus/nodes/charset.js +42 -0
  72. data/lib/stylus/nodes/comment.js +32 -0
  73. data/lib/stylus/nodes/each.js +56 -0
  74. data/lib/stylus/nodes/expression.js +168 -0
  75. data/lib/stylus/nodes/fontface.js +55 -0
  76. data/lib/stylus/nodes/function.js +104 -0
  77. data/lib/stylus/nodes/group.js +79 -0
  78. data/lib/stylus/nodes/hsla.js +256 -0
  79. data/lib/stylus/nodes/ident.js +127 -0
  80. data/lib/stylus/nodes/if.js +55 -0
  81. data/lib/stylus/nodes/import.js +30 -0
  82. data/lib/stylus/nodes/index.js +52 -0
  83. data/lib/stylus/nodes/jsliteral.js +32 -0
  84. data/lib/stylus/nodes/keyframes.js +78 -0
  85. data/lib/stylus/nodes/literal.js +92 -0
  86. data/lib/stylus/nodes/media.js +42 -0
  87. data/lib/stylus/nodes/node.js +209 -0
  88. data/lib/stylus/nodes/null.js +72 -0
  89. data/lib/stylus/nodes/page.js +43 -0
  90. data/lib/stylus/nodes/params.js +72 -0
  91. data/lib/stylus/nodes/property.js +72 -0
  92. data/lib/stylus/nodes/return.js +44 -0
  93. data/lib/stylus/nodes/rgba.js +335 -0
  94. data/lib/stylus/nodes/root.js +50 -0
  95. data/lib/stylus/nodes/selector.js +57 -0
  96. data/lib/stylus/nodes/string.js +120 -0
  97. data/lib/stylus/nodes/ternary.js +51 -0
  98. data/lib/stylus/nodes/unaryop.js +46 -0
  99. data/lib/stylus/nodes/unit.js +207 -0
  100. data/lib/stylus/parser.js +1514 -0
  101. data/lib/stylus/renderer.js +157 -0
  102. data/lib/stylus/source.rb +7 -0
  103. data/lib/stylus/stack/frame.js +66 -0
  104. data/lib/stylus/stack/index.js +146 -0
  105. data/lib/stylus/stack/scope.js +53 -0
  106. data/lib/stylus/stylus.js +102 -0
  107. data/lib/stylus/token.js +53 -0
  108. data/lib/stylus/utils.js +237 -0
  109. data/lib/stylus/visitor/compiler.js +472 -0
  110. data/lib/stylus/visitor/evaluator.js +1070 -0
  111. data/lib/stylus/visitor/index.js +31 -0
  112. data/stylus-source.gemspec +15 -0
  113. metadata +158 -0
@@ -0,0 +1,123 @@
1
+
2
+ vendors = moz webkit official
3
+
4
+ // stringify the given arg
5
+
6
+ -string(arg)
7
+ type(arg) + ' ' + arg
8
+
9
+ // require a color
10
+
11
+ require-color(color)
12
+ unless color is a 'color'
13
+ error('RGB or HSL value expected, got a ' + -string(color))
14
+
15
+ // require a unit
16
+
17
+ require-unit(n)
18
+ unless n is a 'unit'
19
+ error('unit expected, got a ' + -string(n))
20
+
21
+ // require a string
22
+
23
+ require-string(str)
24
+ unless str is a 'string' or str is a 'ident'
25
+ error('string expected, got a ' + -string(str))
26
+
27
+ // apply js Math function
28
+
29
+ math(n, fn)
30
+ require-unit(n)
31
+ require-string(fn)
32
+ -math(n, fn)
33
+
34
+ // adjust the given color's property by amount
35
+
36
+ adjust(color, prop, amount)
37
+ require-color(color)
38
+ require-string(prop)
39
+ require-unit(amount)
40
+ -adjust(color, prop, amount)
41
+
42
+ // Math functions
43
+
44
+ abs(n) { math(n, 'abs') }
45
+ ceil(n) { math(n, 'ceil') }
46
+ floor(n) { math(n, 'floor') }
47
+ round(n) { math(n, 'round') }
48
+ sin(n) { math(n, 'sin') }
49
+ cos(n) { math(n, 'cos') }
50
+ min(a, b) { a < b ? a : b }
51
+ max(a, b) { a > b ? a : b }
52
+ PI = -math-prop('PI')
53
+
54
+ // return the sum of the given numbers
55
+
56
+ sum(nums)
57
+ sum = 0
58
+ sum += n for n in nums
59
+
60
+ // return the average of the given numbers
61
+
62
+ avg(nums)
63
+ sum(nums) / length(nums)
64
+
65
+ // color components
66
+
67
+ alpha(color) { component(hsl(color), 'alpha') }
68
+ hue(color) { component(hsl(color), 'hue') }
69
+ saturation(color) { component(hsl(color), 'saturation') }
70
+ lightness(color) { component(hsl(color), 'lightness') }
71
+
72
+ // check if n is an odd number
73
+
74
+ odd(n)
75
+ 1 == n % 2
76
+
77
+ // check if n is an even number
78
+
79
+ even(n)
80
+ 0 == n % 2
81
+
82
+ // check if color is light
83
+
84
+ light(color)
85
+ lightness(color) >= 50%
86
+
87
+ // check if color is dark
88
+
89
+ dark(color)
90
+ lightness(color) < 50%
91
+
92
+ // desaturate color by amount
93
+
94
+ desaturate(color, amount)
95
+ adjust(color, 'saturation', - amount)
96
+
97
+ // saturate color by amount
98
+
99
+ saturate(color, amount)
100
+ adjust(color, 'saturation', amount)
101
+
102
+ // darken by the given amount
103
+
104
+ darken(color, amount)
105
+ adjust(color, 'lightness', - amount)
106
+
107
+ // lighten by the given amount
108
+
109
+ lighten(color, amount)
110
+ adjust(color, 'lightness', amount)
111
+
112
+ // return the last value in the given expr
113
+
114
+ last(expr)
115
+ expr[length(expr) - 1]
116
+
117
+ // join values with the given delimiter
118
+
119
+ join(delim, vals...)
120
+ buf = ''
121
+ vals = vals[0] if length(vals) == 1
122
+ for val, i in vals
123
+ buf += i ? delim + val : val
@@ -0,0 +1,98 @@
1
+
2
+ /*!
3
+ * Stylus - plugin - url
4
+ * Copyright(c) 2010 LearnBoost <dev@learnboost.com>
5
+ * MIT Licensed
6
+ */
7
+
8
+ /**
9
+ * Module dependencies.
10
+ */
11
+
12
+ var Compiler = require('../visitor/compiler')
13
+ , nodes = require('../nodes')
14
+ , parse = require('url').parse
15
+ , extname = require('path').extname
16
+ , utils = require('../utils')
17
+ , fs = require('fs');
18
+
19
+ /**
20
+ * Mime table.
21
+ */
22
+
23
+ var mimes = {
24
+ '.gif': 'image/gif'
25
+ , '.png': 'image/png'
26
+ , '.jpg': 'image/jpeg'
27
+ , '.jpeg': 'image/jpeg'
28
+ , '.svg': 'image/svg+xml'
29
+ };
30
+
31
+ /**
32
+ * Return a url() function with the given `options`.
33
+ *
34
+ * Options:
35
+ *
36
+ * - `limit` bytesize limit defaulting to 30Kb
37
+ * - `paths` image resolution path(s), merged with general lookup paths
38
+ *
39
+ * Examples:
40
+ *
41
+ * stylus(str)
42
+ * .set('filename', __dirname + '/css/test.styl')
43
+ * .define('url', stylus.url({ paths: [__dirname + '/public'] }))
44
+ * .render(function(err, css){ ... })
45
+ *
46
+ * @param {Object} options
47
+ * @return {Function}
48
+ * @api public
49
+ */
50
+
51
+ module.exports = function(options) {
52
+ options = options || {};
53
+
54
+ var sizeLimit = options.limit || 30000
55
+ , _paths = options.paths || [];
56
+
57
+ function url(url){
58
+ // Compile the url
59
+ var compiler = new Compiler(url);
60
+ compiler.isURL = true;
61
+ var url = url.nodes.map(function(node){
62
+ return compiler.visit(node);
63
+ }).join('');
64
+
65
+ // Parse literal
66
+ var url = parse(url)
67
+ , ext = extname(url.pathname)
68
+ , mime = mimes[ext]
69
+ , literal = new nodes.Literal('url("' + url.href + '")')
70
+ , paths = _paths.concat(this.paths)
71
+ , founds
72
+ , buf;
73
+
74
+ // Not supported
75
+ if (!mime) return literal;
76
+
77
+ // Absolute
78
+ if (url.protocol) return literal;
79
+
80
+ // Lookup
81
+ found = utils.lookup(url.pathname, paths);
82
+
83
+ // Failed to lookup
84
+ if (!found) return literal;
85
+
86
+ // Read data
87
+ buf = fs.readFileSync(found);
88
+
89
+ // To large
90
+ if (buf.length > sizeLimit) return literal;
91
+
92
+ // Encode
93
+ return new nodes.Literal('url("data:' + mime + ';base64,' + buf.toString('base64') + '")');
94
+ };
95
+
96
+ url.raw = true;
97
+ return url;
98
+ };
@@ -0,0 +1,728 @@
1
+
2
+ /*!
3
+ * Stylus - Lexer
4
+ * Copyright(c) 2010 LearnBoost <dev@learnboost.com>
5
+ * MIT Licensed
6
+ */
7
+
8
+ /**
9
+ * Module dependencies.
10
+ */
11
+
12
+ var Token = require('./token')
13
+ , nodes = require('./nodes')
14
+ , errors = require('./errors');
15
+
16
+ /**
17
+ * Operator aliases.
18
+ */
19
+
20
+ var alias = {
21
+ 'and': '&&'
22
+ , 'or': '||'
23
+ , 'is': '=='
24
+ , 'isnt': '!='
25
+ , 'is not': '!='
26
+ , ':=': '?='
27
+ };
28
+
29
+ /**
30
+ * Units.
31
+ */
32
+
33
+ var units = [
34
+ 'em'
35
+ , 'ex'
36
+ , 'px'
37
+ , 'mm'
38
+ , 'cm'
39
+ , 'in'
40
+ , 'pt'
41
+ , 'pc'
42
+ , 'deg'
43
+ , 'rad'
44
+ , 'grad'
45
+ , 'ms'
46
+ , 's'
47
+ , 'Hz'
48
+ , 'kHz'
49
+ , 'rem'
50
+ , '%'].join('|');
51
+
52
+ /**
53
+ * Unit RegExp.
54
+ */
55
+
56
+ var unit = new RegExp('^(-)?(\\d+\\.\\d+|\\d+|\\.\\d+)(' + units + ')? *');
57
+
58
+ /**
59
+ * Initialize a new `Lexer` with the given `str` and `options`.
60
+ *
61
+ * @param {String} str
62
+ * @param {Object} options
63
+ * @api private
64
+ */
65
+
66
+ var Lexer = module.exports = function Lexer(str, options) {
67
+ options = options || {};
68
+ this.str = str.replace(/\r\n?/g, '\n');
69
+ this.stash = [];
70
+ this.indentStack = [];
71
+ this.indentRe = null;
72
+ this.lineno = 1;
73
+ };
74
+
75
+ /**
76
+ * Lexer prototype.
77
+ */
78
+
79
+ Lexer.prototype = {
80
+
81
+ /**
82
+ * Custom inspect.
83
+ */
84
+
85
+ inspect: function(){
86
+ var tok
87
+ , tmp = this.str
88
+ , buf = [];
89
+ while ('eos' != (tok = this.next()).type) {
90
+ buf.push(tok.inspect());
91
+ }
92
+ this.str = tmp;
93
+ this.prevIndents = 0;
94
+ return buf.concat(tok.inspect()).join('\n');
95
+ },
96
+
97
+ /**
98
+ * Lookahead `n` tokens.
99
+ *
100
+ * @param {Number} n
101
+ * @return {Object}
102
+ * @api private
103
+ */
104
+
105
+ lookahead: function(n){
106
+ var fetch = n - this.stash.length;
107
+ while (fetch-- > 0) this.stash.push(this.advance());
108
+ return this.stash[--n];
109
+ },
110
+
111
+ /**
112
+ * Consume the given `len`.
113
+ *
114
+ * @param {Number|Array} len
115
+ * @api private
116
+ */
117
+
118
+ skip: function(len){
119
+ this.str = this.str.substr(Array.isArray(len)
120
+ ? len[0].length
121
+ : len);
122
+ },
123
+
124
+ /**
125
+ * Fetch next token including those stashed by peek.
126
+ *
127
+ * @return {Token}
128
+ * @api private
129
+ */
130
+
131
+ next: function() {
132
+ var tok = this.stashed() || this.advance();
133
+ switch (tok.type) {
134
+ case 'newline':
135
+ case 'indent':
136
+ ++this.lineno;
137
+ break;
138
+ case 'outdent':
139
+ if ('outdent' != this.prev.type) ++this.lineno;
140
+ }
141
+ this.prev = tok;
142
+ tok.lineno = this.lineno;
143
+ return tok;
144
+ },
145
+
146
+ /**
147
+ * Fetch next token.
148
+ *
149
+ * @return {Token}
150
+ * @api private
151
+ */
152
+
153
+ advance: function() {
154
+ return this.eos()
155
+ || this.null()
156
+ || this.sep()
157
+ || this.keyword()
158
+ || this.urlchars()
159
+ || this.atrule()
160
+ || this.media()
161
+ || this.comment()
162
+ || this.newline()
163
+ || this.escaped()
164
+ || this.important()
165
+ || this.literal()
166
+ || this.function()
167
+ || this.brace()
168
+ || this.paren()
169
+ || this.color()
170
+ || this.string()
171
+ || this.unit()
172
+ || this.namedop()
173
+ || this.boolean()
174
+ || this.ident()
175
+ || this.op()
176
+ || this.space()
177
+ || this.selector();
178
+ },
179
+
180
+ /**
181
+ * Lookahead a single token.
182
+ *
183
+ * @return {Token}
184
+ * @api private
185
+ */
186
+
187
+ peek: function() {
188
+ return this.lookahead(1);
189
+ },
190
+
191
+ /**
192
+ * Return the next possibly stashed token.
193
+ *
194
+ * @return {Token}
195
+ * @api private
196
+ */
197
+
198
+ stashed: function() {
199
+ return this.stash.shift();
200
+ },
201
+
202
+ /**
203
+ * EOS | trailing outdents.
204
+ */
205
+
206
+ eos: function() {
207
+ if (this.str.length) return;
208
+ if (this.indentStack.length) {
209
+ this.indentStack.shift();
210
+ return new Token('outdent');
211
+ } else {
212
+ return new Token('eos');
213
+ }
214
+ },
215
+
216
+ /**
217
+ * url char
218
+ */
219
+
220
+ urlchars: function() {
221
+ var captures;
222
+ if (!this.isURL) return;
223
+ if (captures = /^[\/:@.;?&=*!,<>#%0-9]+/.exec(this.str)) {
224
+ this.skip(captures);
225
+ return new Token('literal', new nodes.Literal(captures[0]));
226
+ }
227
+ },
228
+
229
+ /**
230
+ * ';' ' '*
231
+ */
232
+
233
+ sep: function() {
234
+ var captures;
235
+ if (captures = /^; */.exec(this.str)) {
236
+ this.skip(captures);
237
+ return new Token(';');
238
+ }
239
+ },
240
+
241
+ /**
242
+ * ' '+
243
+ */
244
+
245
+ space: function() {
246
+ var captures;
247
+ if (captures = /^( +)/.exec(this.str)) {
248
+ this.skip(captures);
249
+ return new Token('space');
250
+ }
251
+ },
252
+
253
+ /**
254
+ * '\\' . ' '*
255
+ */
256
+
257
+ escaped: function() {
258
+ var captures;
259
+ if (captures = /^\\(.) */.exec(this.str)) {
260
+ var c = captures[1];
261
+ this.skip(captures);
262
+ return new Token('ident', new nodes.Literal(c));
263
+ }
264
+ },
265
+
266
+ /**
267
+ * '@css' ' '* '{' .* '}' ' '*
268
+ */
269
+
270
+ literal: function() {
271
+ // HACK attack !!!
272
+ var captures;
273
+ if (captures = /^@css *\{/.exec(this.str)) {
274
+ this.skip(captures);
275
+ var c
276
+ , braces = 1
277
+ , css = '';
278
+ while (c = this.str[0]) {
279
+ this.str = this.str.substr(1);
280
+ switch (c) {
281
+ case '{': ++braces; break;
282
+ case '}': --braces; break;
283
+ }
284
+ css += c;
285
+ if (!braces) break;
286
+ }
287
+ css = css.replace(/\s*}$/, '');
288
+ return new Token('literal', new nodes.Literal(css));
289
+ }
290
+ },
291
+
292
+ /**
293
+ * '!important' ' '*
294
+ */
295
+
296
+ important: function() {
297
+ var captures;
298
+ if (captures = /^!important */.exec(this.str)) {
299
+ this.skip(captures);
300
+ return new Token('ident', new nodes.Literal('!important'));
301
+ }
302
+ },
303
+
304
+ /**
305
+ * '{' | '}'
306
+ */
307
+
308
+ brace: function() {
309
+ var captures;
310
+ if (captures = /^([{}])/.exec(this.str)) {
311
+ this.skip(1);
312
+ var brace = captures[1];
313
+ return new Token(brace, brace);
314
+ }
315
+ },
316
+
317
+ /**
318
+ * '(' | ')' ' '*
319
+ */
320
+
321
+ paren: function() {
322
+ var captures;
323
+ if (captures = /^([()]) */.exec(this.str)) {
324
+ var paren = captures[1];
325
+ this.skip(captures);
326
+ if (')' == paren) this.isURL = false;
327
+ return new Token(paren, paren);
328
+ }
329
+ },
330
+
331
+ /**
332
+ * 'null'
333
+ */
334
+
335
+ null: function() {
336
+ var captures;
337
+ if (captures = /^(null)\b */.exec(this.str)) {
338
+ this.skip(captures);
339
+ return new Token('null', nodes.null);
340
+ }
341
+ },
342
+
343
+ /**
344
+ * 'if'
345
+ * | 'else'
346
+ * | 'unless'
347
+ * | 'return'
348
+ * | 'for'
349
+ * | 'in'
350
+ */
351
+
352
+ keyword: function() {
353
+ var captures;
354
+ if (captures = /^(return|if|else|unless|for|in)\b */.exec(this.str)) {
355
+ var keyword = captures[1];
356
+ this.skip(captures);
357
+ return new Token(keyword, keyword);
358
+ }
359
+ },
360
+
361
+ /**
362
+ * 'not'
363
+ * | 'and'
364
+ * | 'or'
365
+ * | 'is'
366
+ * | 'is not'
367
+ * | 'isnt'
368
+ * | 'is a'
369
+ * | 'is defined'
370
+ */
371
+
372
+ namedop: function() {
373
+ var captures;
374
+ if (captures = /^(not|and|or|is a|is defined|isnt|is not|is)\b( *)/.exec(this.str)) {
375
+ var op = captures[1];
376
+ this.skip(captures);
377
+ op = alias[op] || op;
378
+ var tok = new Token(op, op);
379
+ tok.space = captures[2];
380
+ return tok;
381
+ }
382
+ },
383
+
384
+ /**
385
+ * ','
386
+ * | '+'
387
+ * | '+='
388
+ * | '-'
389
+ * | '-='
390
+ * | '*'
391
+ * | '*='
392
+ * | '/'
393
+ * | '/='
394
+ * | '%'
395
+ * | '%='
396
+ * | '**'
397
+ * | '!'
398
+ * | '&'
399
+ * | '&&'
400
+ * | '||'
401
+ * | '>'
402
+ * | '>='
403
+ * | '<'
404
+ * | '<='
405
+ * | '='
406
+ * | '=='
407
+ * | '!='
408
+ * | '!'
409
+ * | '~'
410
+ * | '?='
411
+ * | ':='
412
+ * | '?'
413
+ * | ':'
414
+ * | '['
415
+ * | ']'
416
+ * | '..'
417
+ * | '...'
418
+ */
419
+
420
+ op: function() {
421
+ var captures;
422
+ if (captures = /^([.]{2,3}|&&|\|\||[!<>=?:]=|\*\*|[-+*\/%]=?|[,=?:!~<>&\[\]])( *)/.exec(this.str)) {
423
+ var op = captures[1];
424
+ this.skip(captures);
425
+ op = alias[op] || op;
426
+ var tok = new Token(op, op);
427
+ tok.space = captures[2];
428
+ return tok;
429
+ }
430
+ },
431
+
432
+ /**
433
+ * '@media' ([^{\n]+)
434
+ */
435
+
436
+ media: function() {
437
+ var captures;
438
+ if (captures = /^@media *([^{\n]+)/.exec(this.str)) {
439
+ this.skip(captures);
440
+ return new Token('media', captures[1].trim());
441
+ }
442
+ },
443
+
444
+ /**
445
+ * '@' ('import' | 'keyframes' | 'charset' | 'page' | 'font-face')
446
+ */
447
+
448
+ atrule: function() {
449
+ var captures;
450
+ if (captures = /^@(import|(?:-(\w+)-)?keyframes|charset|font-face|page) */.exec(this.str)) {
451
+ this.skip(captures);
452
+ var vendor = captures[2]
453
+ , type = captures[1];
454
+ if (vendor) type = 'keyframes';
455
+ return new Token(type, vendor);
456
+ }
457
+ },
458
+
459
+ /**
460
+ * '//' *
461
+ */
462
+
463
+ comment: function() {
464
+ // Single line
465
+ if ('/' == this.str[0] && '/' == this.str[1]) {
466
+ var end = this.str.indexOf('\n');
467
+ if (-1 == end) end = this.str.length;
468
+ this.skip(end);
469
+ return this.advance();
470
+ }
471
+
472
+ // Multi-line
473
+ if ('/' == this.str[0] && '*' == this.str[1]) {
474
+ var end = this.str.indexOf('*/');
475
+ if (-1 == end) end = this.str.length;
476
+ var str = this.str.substr(0, end + 2)
477
+ , lines = str.split('\n').length - 1
478
+ , suppress = true;
479
+ this.lineno += lines;
480
+ this.skip(end + 2);
481
+ // output
482
+ if ('!' == str[2]) {
483
+ str = str.replace('*!', '*');
484
+ suppress = false;
485
+ }
486
+ return new Token('comment', new nodes.Comment(str, suppress));
487
+ }
488
+ },
489
+
490
+ /**
491
+ * 'true' | 'false'
492
+ */
493
+
494
+ boolean: function() {
495
+ var captures;
496
+ if (captures = /^(true|false)\b( *)/.exec(this.str)) {
497
+ var val = nodes.Boolean('true' == captures[1]);
498
+ this.skip(captures);
499
+ var tok = new Token('boolean', val);
500
+ tok.space = captures[2];
501
+ return tok;
502
+ }
503
+ },
504
+
505
+ /**
506
+ * -?[a-zA-Z$] [-\w\d$]* '('
507
+ */
508
+
509
+ function: function() {
510
+ var captures;
511
+ if (captures = /^(-?[a-zA-Z$][-\w\d$]*)\(( *)/.exec(this.str)) {
512
+ var name = captures[1];
513
+ this.skip(captures);
514
+ this.isURL = 'url' == name;
515
+ var tok = new Token('function', new nodes.Ident(name));
516
+ tok.space = captures[2];
517
+ return tok;
518
+ }
519
+ },
520
+
521
+ /**
522
+ * -?[_a-zA-Z$] [-\w\d$]*
523
+ */
524
+
525
+ ident: function() {
526
+ var captures;
527
+ if (captures = /^(@)?(-?[_a-zA-Z$][-\w\d$]*)/.exec(this.str)) {
528
+ var at = captures[1]
529
+ , name = captures[2]
530
+ , id = new nodes.Ident(name);
531
+ this.skip(captures);
532
+ id.property = !! at;
533
+ return new Token('ident', id);
534
+ }
535
+ },
536
+
537
+ /**
538
+ * '\n' ' '+
539
+ */
540
+
541
+ newline: function() {
542
+ var captures, re;
543
+
544
+ // we have established the indentation regexp
545
+ if (this.indentRe){
546
+ captures = this.indentRe.exec(this.str);
547
+ // figure out if we are using tabs or spaces
548
+ } else {
549
+ // try tabs
550
+ re = /^\n([\t]*) */;
551
+ captures = re.exec(this.str);
552
+
553
+ // nope, try spaces
554
+ if (captures && !captures[1].length) {
555
+ re = /^\n( *)/;
556
+ captures = re.exec(this.str);
557
+ }
558
+
559
+ // established
560
+ if (captures && captures[1].length) this.indentRe = re;
561
+ }
562
+
563
+
564
+ if (captures) {
565
+ var tok
566
+ , indents = captures[1].length;
567
+
568
+ this.skip(captures);
569
+ if (this.str[0] === ' ' || this.str[0] === '\t') {
570
+ throw new errors.SyntaxError('Invalid indentation. You can use tabs or spaces to indent, but not both.');
571
+ }
572
+
573
+ // Reset state
574
+ this.isVariable = false;
575
+
576
+ // Blank line
577
+ if ('\n' == this.str[0]) {
578
+ ++this.lineno;
579
+ return this.advance();
580
+ }
581
+
582
+ // Outdent
583
+ if (this.indentStack.length && indents < this.indentStack[0]) {
584
+ while (this.indentStack.length && this.indentStack[0] > indents) {
585
+ this.stash.push(new Token('outdent'));
586
+ this.indentStack.shift();
587
+ }
588
+ tok = this.stash.pop();
589
+ // Indent
590
+ } else if (indents && indents != this.indentStack[0]) {
591
+ this.indentStack.unshift(indents);
592
+ tok = new Token('indent');
593
+ // Newline
594
+ } else {
595
+ tok = new Token('newline');
596
+ }
597
+
598
+ return tok;
599
+ }
600
+ },
601
+
602
+ /**
603
+ * '-'? (digit+ | digit* '.' digit+) unit
604
+ */
605
+
606
+ unit: function() {
607
+ var captures;
608
+ if (captures = unit.exec(this.str)) {
609
+ this.skip(captures);
610
+ var n = parseFloat(captures[2]);
611
+ if ('-' == captures[1]) n = -n;
612
+ var node = new nodes.Unit(n, captures[3]);
613
+ return new Token('unit', node);
614
+ }
615
+ },
616
+
617
+ /**
618
+ * '"' [^"]+ '"' | "'"" [^']+ "'"
619
+ */
620
+
621
+ string: function() {
622
+ var captures;
623
+ if (captures = /^("[^"]*"|'[^']*') */.exec(this.str)) {
624
+ var str = captures[1];
625
+ this.skip(captures);
626
+ str = str.slice(1,-1).replace(/\\n/g, '\n');
627
+ return new Token('string', new nodes.String(str));
628
+ }
629
+ },
630
+
631
+ /**
632
+ * #rrggbbaa | #rrggbb | #rgba | #rgb
633
+ */
634
+
635
+ color: function() {
636
+ return this.rrggbbaa()
637
+ || this.rrggbb()
638
+ || this.rgba()
639
+ || this.rgb()
640
+ },
641
+
642
+ /**
643
+ * #rgb
644
+ */
645
+
646
+ rgb: function() {
647
+ var captures;
648
+ if (captures = /^#([a-fA-F0-9]{3}) */.exec(this.str)) {
649
+ this.skip(captures);
650
+ var rgb = captures[1]
651
+ , r = parseInt(rgb[0] + rgb[0], 16)
652
+ , g = parseInt(rgb[1] + rgb[1], 16)
653
+ , b = parseInt(rgb[2] + rgb[2], 16)
654
+ , color = new nodes.RGBA(r, g, b, 1);
655
+ color.raw = captures[0];
656
+ return new Token('color', color);
657
+ }
658
+ },
659
+
660
+ /**
661
+ * #rgba
662
+ */
663
+
664
+ rgba: function() {
665
+ var captures;
666
+ if (captures = /^#([a-fA-F0-9]{4}) */.exec(this.str)) {
667
+ this.skip(captures);
668
+ var rgb = captures[1]
669
+ , r = parseInt(rgb[0] + rgb[0], 16)
670
+ , g = parseInt(rgb[1] + rgb[1], 16)
671
+ , b = parseInt(rgb[2] + rgb[2], 16)
672
+ , a = parseInt(rgb[3] + rgb[3], 16)
673
+ , color = new nodes.RGBA(r, g, b, a/255);
674
+ color.raw = captures[0];
675
+ return new Token('color', color);
676
+ }
677
+ },
678
+
679
+ /**
680
+ * #rrggbb
681
+ */
682
+
683
+ rrggbb: function() {
684
+ var captures;
685
+ if (captures = /^#([a-fA-F0-9]{6}) */.exec(this.str)) {
686
+ this.skip(captures);
687
+ var rgb = captures[1]
688
+ , r = parseInt(rgb.substr(0, 2), 16)
689
+ , g = parseInt(rgb.substr(2, 2), 16)
690
+ , b = parseInt(rgb.substr(4, 2), 16)
691
+ , color = new nodes.RGBA(r, g, b, 1);
692
+ color.raw = captures[0];
693
+ return new Token('color', color);
694
+ }
695
+ },
696
+
697
+ /**
698
+ * #rrggbbaa
699
+ */
700
+
701
+ rrggbbaa: function() {
702
+ var captures;
703
+ if (captures = /^#([a-fA-F0-9]{8}) */.exec(this.str)) {
704
+ this.skip(captures);
705
+ var rgb = captures[1]
706
+ , r = parseInt(rgb.substr(0, 2), 16)
707
+ , g = parseInt(rgb.substr(2, 2), 16)
708
+ , b = parseInt(rgb.substr(4, 2), 16)
709
+ , a = parseInt(rgb.substr(6, 2), 16)
710
+ , color = new nodes.RGBA(r, g, b, a/255);
711
+ color.raw = captures[0];
712
+ return new Token('color', color);
713
+ }
714
+ },
715
+
716
+ /**
717
+ * [^\n,;]+
718
+ */
719
+
720
+ selector: function() {
721
+ var captures;
722
+ if (captures = /^[^{\n,]+/.exec(this.str)) {
723
+ var selector = captures[0];
724
+ this.skip(captures);
725
+ return new Token('selector', selector);
726
+ }
727
+ }
728
+ };