less 2.0.7 → 2.0.8beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.travis.yml +4 -1
  2. data/less.gemspec +2 -1
  3. data/lib/less/js/Makefile +13 -0
  4. data/lib/less/js/benchmark/less-benchmark.js +1 -3
  5. data/lib/less/js/bin/lessc +30 -7
  6. data/lib/less/js/build/require-rhino.js +7 -0
  7. data/lib/less/js/dist/less-1.1.5.js +2805 -0
  8. data/lib/less/js/dist/less-1.1.5.min.js +16 -0
  9. data/lib/less/js/dist/less-rhino-1.1.3.js +2460 -0
  10. data/lib/less/js/dist/less-rhino-1.1.5.js +2481 -0
  11. data/lib/less/js/lib/less/browser.js +8 -2
  12. data/lib/less/js/lib/less/functions.js +12 -1
  13. data/lib/less/js/lib/less/index.js +19 -18
  14. data/lib/less/js/lib/less/parser.js +41 -22
  15. data/lib/less/js/lib/less/rhino.js +60 -0
  16. data/lib/less/js/lib/less/tree/alpha.js +1 -1
  17. data/lib/less/js/lib/less/tree/anonymous.js +1 -1
  18. data/lib/less/js/lib/less/tree/assignment.js +17 -0
  19. data/lib/less/js/lib/less/tree/call.js +1 -1
  20. data/lib/less/js/lib/less/tree/color.js +9 -6
  21. data/lib/less/js/lib/less/tree/comment.js +1 -1
  22. data/lib/less/js/lib/less/tree/dimension.js +1 -1
  23. data/lib/less/js/lib/less/tree/directive.js +1 -1
  24. data/lib/less/js/lib/less/tree/element.js +3 -2
  25. data/lib/less/js/lib/less/tree/expression.js +1 -1
  26. data/lib/less/js/lib/less/tree/import.js +3 -3
  27. data/lib/less/js/lib/less/tree/javascript.js +1 -1
  28. data/lib/less/js/lib/less/tree/keyword.js +1 -1
  29. data/lib/less/js/lib/less/tree/mixin.js +1 -1
  30. data/lib/less/js/lib/less/tree/operation.js +1 -1
  31. data/lib/less/js/lib/less/tree/quoted.js +1 -1
  32. data/lib/less/js/lib/less/tree/rule.js +1 -1
  33. data/lib/less/js/lib/less/tree/ruleset.js +3 -3
  34. data/lib/less/js/lib/less/tree/selector.js +13 -4
  35. data/lib/less/js/lib/less/tree/url.js +2 -2
  36. data/lib/less/js/lib/less/tree/value.js +1 -1
  37. data/lib/less/js/lib/less/tree/variable.js +1 -1
  38. data/lib/less/js/lib/less/tree.js +2 -2
  39. data/lib/less/js/package.json +1 -1
  40. data/lib/less/js/test/css/colors.css +6 -0
  41. data/lib/less/js/test/css/css-3.css +14 -0
  42. data/lib/less/js/test/css/css.css +3 -0
  43. data/lib/less/js/test/css/ie-filters.css +5 -0
  44. data/lib/less/js/test/css/import.css +2 -0
  45. data/lib/less/js/test/css/mixins.css +20 -0
  46. data/lib/less/js/test/less/colors.less +6 -0
  47. data/lib/less/js/test/less/css-3.less +10 -0
  48. data/lib/less/js/test/less/css.less +4 -0
  49. data/lib/less/js/test/less/ie-filters.less +8 -0
  50. data/lib/less/js/test/less/import.less +1 -0
  51. data/lib/less/js/test/less/mixins.less +20 -0
  52. data/lib/less/js/test/less-test.js +2 -4
  53. data/lib/less/loader.rb +18 -30
  54. data/lib/less/version.rb +1 -1
  55. metadata +64 -55
@@ -0,0 +1,2481 @@
1
+ //
2
+ // Stub out `require` in rhino
3
+ //
4
+ function require(arg) {
5
+ return less[arg.split('/')[1]];
6
+ };
7
+
8
+
9
+ // ecma-5.js
10
+ //
11
+ // -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
12
+ // -- tlrobinson Tom Robinson
13
+ // dantman Daniel Friesen
14
+
15
+ //
16
+ // Array
17
+ //
18
+ if (!Array.isArray) {
19
+ Array.isArray = function(obj) {
20
+ return Object.prototype.toString.call(obj) === "[object Array]" ||
21
+ (obj instanceof Array);
22
+ };
23
+ }
24
+ if (!Array.prototype.forEach) {
25
+ Array.prototype.forEach = function(block, thisObject) {
26
+ var len = this.length >>> 0;
27
+ for (var i = 0; i < len; i++) {
28
+ if (i in this) {
29
+ block.call(thisObject, this[i], i, this);
30
+ }
31
+ }
32
+ };
33
+ }
34
+ if (!Array.prototype.map) {
35
+ Array.prototype.map = function(fun /*, thisp*/) {
36
+ var len = this.length >>> 0;
37
+ var res = new Array(len);
38
+ var thisp = arguments[1];
39
+
40
+ for (var i = 0; i < len; i++) {
41
+ if (i in this) {
42
+ res[i] = fun.call(thisp, this[i], i, this);
43
+ }
44
+ }
45
+ return res;
46
+ };
47
+ }
48
+ if (!Array.prototype.filter) {
49
+ Array.prototype.filter = function (block /*, thisp */) {
50
+ var values = [];
51
+ var thisp = arguments[1];
52
+ for (var i = 0; i < this.length; i++) {
53
+ if (block.call(thisp, this[i])) {
54
+ values.push(this[i]);
55
+ }
56
+ }
57
+ return values;
58
+ };
59
+ }
60
+ if (!Array.prototype.reduce) {
61
+ Array.prototype.reduce = function(fun /*, initial*/) {
62
+ var len = this.length >>> 0;
63
+ var i = 0;
64
+
65
+ // no value to return if no initial value and an empty array
66
+ if (len === 0 && arguments.length === 1) throw new TypeError();
67
+
68
+ if (arguments.length >= 2) {
69
+ var rv = arguments[1];
70
+ } else {
71
+ do {
72
+ if (i in this) {
73
+ rv = this[i++];
74
+ break;
75
+ }
76
+ // if array contains no values, no initial value to return
77
+ if (++i >= len) throw new TypeError();
78
+ } while (true);
79
+ }
80
+ for (; i < len; i++) {
81
+ if (i in this) {
82
+ rv = fun.call(null, rv, this[i], i, this);
83
+ }
84
+ }
85
+ return rv;
86
+ };
87
+ }
88
+ if (!Array.prototype.indexOf) {
89
+ Array.prototype.indexOf = function (value /*, fromIndex */ ) {
90
+ var length = this.length;
91
+ var i = arguments[1] || 0;
92
+
93
+ if (!length) return -1;
94
+ if (i >= length) return -1;
95
+ if (i < 0) i += length;
96
+
97
+ for (; i < length; i++) {
98
+ if (!Object.prototype.hasOwnProperty.call(this, i)) { continue }
99
+ if (value === this[i]) return i;
100
+ }
101
+ return -1;
102
+ };
103
+ }
104
+
105
+ //
106
+ // Object
107
+ //
108
+ if (!Object.keys) {
109
+ Object.keys = function (object) {
110
+ var keys = [];
111
+ for (var name in object) {
112
+ if (Object.prototype.hasOwnProperty.call(object, name)) {
113
+ keys.push(name);
114
+ }
115
+ }
116
+ return keys;
117
+ };
118
+ }
119
+
120
+ //
121
+ // String
122
+ //
123
+ if (!String.prototype.trim) {
124
+ String.prototype.trim = function () {
125
+ return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
126
+ };
127
+ }
128
+ var less, tree;
129
+
130
+ if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") {
131
+ // Rhino
132
+ // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88
133
+ less = {};
134
+ tree = less.tree = {};
135
+ less.mode = 'rhino';
136
+ } else if (typeof(window) === 'undefined') {
137
+ // Node.js
138
+ less = exports,
139
+ tree = require('./tree');
140
+ less.mode = 'rhino';
141
+ } else {
142
+ // Browser
143
+ if (typeof(window.less) === 'undefined') { window.less = {} }
144
+ less = window.less,
145
+ tree = window.less.tree = {};
146
+ less.mode = 'browser';
147
+ }
148
+ //
149
+ // less.js - parser
150
+ //
151
+ // A relatively straight-forward predictive parser.
152
+ // There is no tokenization/lexing stage, the input is parsed
153
+ // in one sweep.
154
+ //
155
+ // To make the parser fast enough to run in the browser, several
156
+ // optimization had to be made:
157
+ //
158
+ // - Matching and slicing on a huge input is often cause of slowdowns.
159
+ // The solution is to chunkify the input into smaller strings.
160
+ // The chunks are stored in the `chunks` var,
161
+ // `j` holds the current chunk index, and `current` holds
162
+ // the index of the current chunk in relation to `input`.
163
+ // This gives us an almost 4x speed-up.
164
+ //
165
+ // - In many cases, we don't need to match individual tokens;
166
+ // for example, if a value doesn't hold any variables, operations
167
+ // or dynamic references, the parser can effectively 'skip' it,
168
+ // treating it as a literal.
169
+ // An example would be '1px solid #000' - which evaluates to itself,
170
+ // we don't need to know what the individual components are.
171
+ // The drawback, of course is that you don't get the benefits of
172
+ // syntax-checking on the CSS. This gives us a 50% speed-up in the parser,
173
+ // and a smaller speed-up in the code-gen.
174
+ //
175
+ //
176
+ // Token matching is done with the `$` function, which either takes
177
+ // a terminal string or regexp, or a non-terminal function to call.
178
+ // It also takes care of moving all the indices forwards.
179
+ //
180
+ //
181
+ less.Parser = function Parser(env) {
182
+ var input, // LeSS input string
183
+ i, // current index in `input`
184
+ j, // current chunk
185
+ temp, // temporarily holds a chunk's state, for backtracking
186
+ memo, // temporarily holds `i`, when backtracking
187
+ furthest, // furthest index the parser has gone to
188
+ chunks, // chunkified input
189
+ current, // index of current chunk, in `input`
190
+ parser;
191
+
192
+ var that = this;
193
+
194
+ // This function is called after all files
195
+ // have been imported through `@import`.
196
+ var finish = function () {};
197
+
198
+ var imports = this.imports = {
199
+ paths: env && env.paths || [], // Search paths, when importing
200
+ queue: [], // Files which haven't been imported yet
201
+ files: {}, // Holds the imported parse trees
202
+ mime: env && env.mime, // MIME type of .less files
203
+ push: function (path, callback) {
204
+ var that = this;
205
+ this.queue.push(path);
206
+
207
+ //
208
+ // Import a file asynchronously
209
+ //
210
+ less.Parser.importer(path, this.paths, function (root) {
211
+ that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue
212
+ that.files[path] = root; // Store the root
213
+
214
+ callback(root);
215
+
216
+ if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing
217
+ }, env);
218
+ }
219
+ };
220
+
221
+ function save() { temp = chunks[j], memo = i, current = i }
222
+ function restore() { chunks[j] = temp, i = memo, current = i }
223
+
224
+ function sync() {
225
+ if (i > current) {
226
+ chunks[j] = chunks[j].slice(i - current);
227
+ current = i;
228
+ }
229
+ }
230
+ //
231
+ // Parse from a token, regexp or string, and move forward if match
232
+ //
233
+ function $(tok) {
234
+ var match, args, length, c, index, endIndex, k, mem;
235
+
236
+ //
237
+ // Non-terminal
238
+ //
239
+ if (tok instanceof Function) {
240
+ return tok.call(parser.parsers);
241
+ //
242
+ // Terminal
243
+ //
244
+ // Either match a single character in the input,
245
+ // or match a regexp in the current chunk (chunk[j]).
246
+ //
247
+ } else if (typeof(tok) === 'string') {
248
+ match = input.charAt(i) === tok ? tok : null;
249
+ length = 1;
250
+ sync ();
251
+ } else {
252
+ sync ();
253
+
254
+ if (match = tok.exec(chunks[j])) {
255
+ length = match[0].length;
256
+ } else {
257
+ return null;
258
+ }
259
+ }
260
+
261
+ // The match is confirmed, add the match length to `i`,
262
+ // and consume any extra white-space characters (' ' || '\n')
263
+ // which come after that. The reason for this is that LeSS's
264
+ // grammar is mostly white-space insensitive.
265
+ //
266
+ if (match) {
267
+ mem = i += length;
268
+ endIndex = i + chunks[j].length - length;
269
+
270
+ while (i < endIndex) {
271
+ c = input.charCodeAt(i);
272
+ if (! (c === 32 || c === 10 || c === 9)) { break }
273
+ i++;
274
+ }
275
+ chunks[j] = chunks[j].slice(length + (i - mem));
276
+ current = i;
277
+
278
+ if (chunks[j].length === 0 && j < chunks.length - 1) { j++ }
279
+
280
+ if(typeof(match) === 'string') {
281
+ return match;
282
+ } else {
283
+ return match.length === 1 ? match[0] : match;
284
+ }
285
+ }
286
+ }
287
+
288
+ // Same as $(), but don't change the state of the parser,
289
+ // just return the match.
290
+ function peek(tok) {
291
+ if (typeof(tok) === 'string') {
292
+ return input.charAt(i) === tok;
293
+ } else {
294
+ if (tok.test(chunks[j])) {
295
+ return true;
296
+ } else {
297
+ return false;
298
+ }
299
+ }
300
+ }
301
+
302
+ this.env = env = env || {};
303
+
304
+ // The optimization level dictates the thoroughness of the parser,
305
+ // the lower the number, the less nodes it will create in the tree.
306
+ // This could matter for debugging, or if you want to access
307
+ // the individual nodes in the tree.
308
+ this.optimization = ('optimization' in this.env) ? this.env.optimization : 1;
309
+
310
+ this.env.filename = this.env.filename || null;
311
+
312
+ //
313
+ // The Parser
314
+ //
315
+ return parser = {
316
+
317
+ imports: imports,
318
+ //
319
+ // Parse an input string into an abstract syntax tree,
320
+ // call `callback` when done.
321
+ //
322
+ parse: function (str, callback) {
323
+ var root, start, end, zone, line, lines, buff = [], c, error = null;
324
+
325
+ i = j = current = furthest = 0;
326
+ chunks = [];
327
+ input = str.replace(/\r\n/g, '\n');
328
+
329
+ // Split the input into chunks.
330
+ chunks = (function (chunks) {
331
+ var j = 0,
332
+ skip = /[^"'`\{\}\/\(\)]+/g,
333
+ comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,
334
+ level = 0,
335
+ match,
336
+ chunk = chunks[0],
337
+ inParam,
338
+ inString;
339
+
340
+ for (var i = 0, c, cc; i < input.length; i++) {
341
+ skip.lastIndex = i;
342
+ if (match = skip.exec(input)) {
343
+ if (match.index === i) {
344
+ i += match[0].length;
345
+ chunk.push(match[0]);
346
+ }
347
+ }
348
+ c = input.charAt(i);
349
+ comment.lastIndex = i;
350
+
351
+ if (!inString && !inParam && c === '/') {
352
+ cc = input.charAt(i + 1);
353
+ if (cc === '/' || cc === '*') {
354
+ if (match = comment.exec(input)) {
355
+ if (match.index === i) {
356
+ i += match[0].length;
357
+ chunk.push(match[0]);
358
+ c = input.charAt(i);
359
+ }
360
+ }
361
+ }
362
+ }
363
+
364
+ if (c === '{' && !inString && !inParam) { level ++;
365
+ chunk.push(c);
366
+ } else if (c === '}' && !inString && !inParam) { level --;
367
+ chunk.push(c);
368
+ chunks[++j] = chunk = [];
369
+ } else if (c === '(' && !inString && !inParam) {
370
+ chunk.push(c);
371
+ inParam = true;
372
+ } else if (c === ')' && !inString && inParam) {
373
+ chunk.push(c);
374
+ inParam = false;
375
+ } else {
376
+ if (c === '"' || c === "'" || c === '`') {
377
+ if (! inString) {
378
+ inString = c;
379
+ } else {
380
+ inString = inString === c ? false : inString;
381
+ }
382
+ }
383
+ chunk.push(c);
384
+ }
385
+ }
386
+ if (level > 0) {
387
+ throw {
388
+ type: 'Syntax',
389
+ message: "Missing closing `}`",
390
+ filename: env.filename
391
+ };
392
+ }
393
+
394
+ return chunks.map(function (c) { return c.join('') });;
395
+ })([[]]);
396
+
397
+ // Start with the primary rule.
398
+ // The whole syntax tree is held under a Ruleset node,
399
+ // with the `root` property set to true, so no `{}` are
400
+ // output. The callback is called when the input is parsed.
401
+ root = new(tree.Ruleset)([], $(this.parsers.primary));
402
+ root.root = true;
403
+
404
+ root.toCSS = (function (evaluate) {
405
+ var line, lines, column;
406
+
407
+ return function (options, variables) {
408
+ var frames = [];
409
+
410
+ options = options || {};
411
+ //
412
+ // Allows setting variables with a hash, so:
413
+ //
414
+ // `{ color: new(tree.Color)('#f01') }` will become:
415
+ //
416
+ // new(tree.Rule)('@color',
417
+ // new(tree.Value)([
418
+ // new(tree.Expression)([
419
+ // new(tree.Color)('#f01')
420
+ // ])
421
+ // ])
422
+ // )
423
+ //
424
+ if (typeof(variables) === 'object' && !Array.isArray(variables)) {
425
+ variables = Object.keys(variables).map(function (k) {
426
+ var value = variables[k];
427
+
428
+ if (! (value instanceof tree.Value)) {
429
+ if (! (value instanceof tree.Expression)) {
430
+ value = new(tree.Expression)([value]);
431
+ }
432
+ value = new(tree.Value)([value]);
433
+ }
434
+ return new(tree.Rule)('@' + k, value, false, 0);
435
+ });
436
+ frames = [new(tree.Ruleset)(null, variables)];
437
+ }
438
+
439
+ try {
440
+ var css = evaluate.call(this, { frames: frames })
441
+ .toCSS([], { compress: options.compress || false });
442
+ } catch (e) {
443
+ lines = input.split('\n');
444
+ line = getLine(e.index);
445
+
446
+ for (var n = e.index, column = -1;
447
+ n >= 0 && input.charAt(n) !== '\n';
448
+ n--) { column++ }
449
+
450
+ throw {
451
+ type: e.type,
452
+ message: e.message,
453
+ filename: env.filename,
454
+ index: e.index,
455
+ line: typeof(line) === 'number' ? line + 1 : null,
456
+ callLine: e.call && (getLine(e.call) + 1),
457
+ callExtract: lines[getLine(e.call)],
458
+ stack: e.stack,
459
+ column: column,
460
+ extract: [
461
+ lines[line - 1],
462
+ lines[line],
463
+ lines[line + 1]
464
+ ]
465
+ };
466
+ }
467
+ if (options.compress) {
468
+ return css.replace(/(\s)+/g, "$1");
469
+ } else {
470
+ return css;
471
+ }
472
+
473
+ function getLine(index) {
474
+ return index ? (input.slice(0, index).match(/\n/g) || "").length : null;
475
+ }
476
+ };
477
+ })(root.eval);
478
+
479
+ // If `i` is smaller than the `input.length - 1`,
480
+ // it means the parser wasn't able to parse the whole
481
+ // string, so we've got a parsing error.
482
+ //
483
+ // We try to extract a \n delimited string,
484
+ // showing the line where the parse error occured.
485
+ // We split it up into two parts (the part which parsed,
486
+ // and the part which didn't), so we can color them differently.
487
+ if (i < input.length - 1) {
488
+ i = furthest;
489
+ lines = input.split('\n');
490
+ line = (input.slice(0, i).match(/\n/g) || "").length + 1;
491
+
492
+ for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ }
493
+
494
+ error = {
495
+ name: "ParseError",
496
+ message: "Syntax Error on line " + line,
497
+ index: i,
498
+ filename: env.filename,
499
+ line: line,
500
+ column: column,
501
+ extract: [
502
+ lines[line - 2],
503
+ lines[line - 1],
504
+ lines[line]
505
+ ]
506
+ };
507
+ }
508
+
509
+ if (this.imports.queue.length > 0) {
510
+ finish = function () { callback(error, root) };
511
+ } else {
512
+ callback(error, root);
513
+ }
514
+ },
515
+
516
+ //
517
+ // Here in, the parsing rules/functions
518
+ //
519
+ // The basic structure of the syntax tree generated is as follows:
520
+ //
521
+ // Ruleset -> Rule -> Value -> Expression -> Entity
522
+ //
523
+ // Here's some LESS code:
524
+ //
525
+ // .class {
526
+ // color: #fff;
527
+ // border: 1px solid #000;
528
+ // width: @w + 4px;
529
+ // > .child {...}
530
+ // }
531
+ //
532
+ // And here's what the parse tree might look like:
533
+ //
534
+ // Ruleset (Selector '.class', [
535
+ // Rule ("color", Value ([Expression [Color #fff]]))
536
+ // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
537
+ // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]]))
538
+ // Ruleset (Selector [Element '>', '.child'], [...])
539
+ // ])
540
+ //
541
+ // In general, most rules will try to parse a token with the `$()` function, and if the return
542
+ // value is truly, will return a new node, of the relevant type. Sometimes, we need to check
543
+ // first, before parsing, that's when we use `peek()`.
544
+ //
545
+ parsers: {
546
+ //
547
+ // The `primary` rule is the *entry* and *exit* point of the parser.
548
+ // The rules here can appear at any level of the parse tree.
549
+ //
550
+ // The recursive nature of the grammar is an interplay between the `block`
551
+ // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,
552
+ // as represented by this simplified grammar:
553
+ //
554
+ // primary → (ruleset | rule)+
555
+ // ruleset → selector+ block
556
+ // block → '{' primary '}'
557
+ //
558
+ // Only at one point is the primary rule not called from the
559
+ // block rule: at the root level.
560
+ //
561
+ primary: function () {
562
+ var node, root = [];
563
+
564
+ while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) ||
565
+ $(this.mixin.call) || $(this.comment) || $(this.directive))
566
+ || $(/^[\s\n]+/)) {
567
+ node && root.push(node);
568
+ }
569
+ return root;
570
+ },
571
+
572
+ // We create a Comment node for CSS comments `/* */`,
573
+ // but keep the LeSS comments `//` silent, by just skipping
574
+ // over them.
575
+ comment: function () {
576
+ var comment;
577
+
578
+ if (input.charAt(i) !== '/') return;
579
+
580
+ if (input.charAt(i + 1) === '/') {
581
+ return new(tree.Comment)($(/^\/\/.*/), true);
582
+ } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) {
583
+ return new(tree.Comment)(comment);
584
+ }
585
+ },
586
+
587
+ //
588
+ // Entities are tokens which can be found inside an Expression
589
+ //
590
+ entities: {
591
+ //
592
+ // A string, which supports escaping " and '
593
+ //
594
+ // "milky way" 'he\'s the one!'
595
+ //
596
+ quoted: function () {
597
+ var str, j = i, e;
598
+
599
+ if (input.charAt(j) === '~') { j++, e = true } // Escaped strings
600
+ if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return;
601
+
602
+ e && $('~');
603
+
604
+ if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) {
605
+ return new(tree.Quoted)(str[0], str[1] || str[2], e);
606
+ }
607
+ },
608
+
609
+ //
610
+ // A catch-all word, such as:
611
+ //
612
+ // black border-collapse
613
+ //
614
+ keyword: function () {
615
+ var k;
616
+ if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { return new(tree.Keyword)(k) }
617
+ },
618
+
619
+ //
620
+ // A function call
621
+ //
622
+ // rgb(255, 0, 255)
623
+ //
624
+ // We also try to catch IE's `alpha()`, but let the `alpha` parser
625
+ // deal with the details.
626
+ //
627
+ // The arguments are parsed with the `entities.arguments` parser.
628
+ //
629
+ call: function () {
630
+ var name, args, index = i;
631
+
632
+ if (! (name = /^([\w-]+|%)\(/.exec(chunks[j]))) return;
633
+
634
+ name = name[1].toLowerCase();
635
+
636
+ if (name === 'url') { return null }
637
+ else { i += name.length }
638
+
639
+ if (name === 'alpha') { return $(this.alpha) }
640
+
641
+ $('('); // Parse the '(' and consume whitespace.
642
+
643
+ args = $(this.entities.arguments);
644
+
645
+ if (! $(')')) return;
646
+
647
+ if (name) { return new(tree.Call)(name, args, index) }
648
+ },
649
+ arguments: function () {
650
+ var args = [], arg;
651
+
652
+ while (arg = $(this.expression)) {
653
+ args.push(arg);
654
+ if (! $(',')) { break }
655
+ }
656
+ return args;
657
+ },
658
+ literal: function () {
659
+ return $(this.entities.dimension) ||
660
+ $(this.entities.color) ||
661
+ $(this.entities.quoted);
662
+ },
663
+
664
+ //
665
+ // Parse url() tokens
666
+ //
667
+ // We use a specific rule for urls, because they don't really behave like
668
+ // standard function calls. The difference is that the argument doesn't have
669
+ // to be enclosed within a string, so it can't be parsed as an Expression.
670
+ //
671
+ url: function () {
672
+ var value;
673
+
674
+ if (input.charAt(i) !== 'u' || !$(/^url\(/)) return;
675
+ value = $(this.entities.quoted) || $(this.entities.variable) ||
676
+ $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || "";
677
+ if (! $(')')) throw new(Error)("missing closing ) for url()");
678
+
679
+ return new(tree.URL)((value.value || value.data || value instanceof tree.Variable)
680
+ ? value : new(tree.Anonymous)(value), imports.paths);
681
+ },
682
+
683
+ dataURI: function () {
684
+ var obj;
685
+
686
+ if ($(/^data:/)) {
687
+ obj = {};
688
+ obj.mime = $(/^[^\/]+\/[^,;)]+/) || '';
689
+ obj.charset = $(/^;\s*charset=[^,;)]+/) || '';
690
+ obj.base64 = $(/^;\s*base64/) || '';
691
+ obj.data = $(/^,\s*[^)]+/);
692
+
693
+ if (obj.data) { return obj }
694
+ }
695
+ },
696
+
697
+ //
698
+ // A Variable entity, such as `@fink`, in
699
+ //
700
+ // width: @fink + 2px
701
+ //
702
+ // We use a different parser for variable definitions,
703
+ // see `parsers.variable`.
704
+ //
705
+ variable: function () {
706
+ var name, index = i;
707
+
708
+ if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) {
709
+ return new(tree.Variable)(name, index);
710
+ }
711
+ },
712
+
713
+ //
714
+ // A Hexadecimal color
715
+ //
716
+ // #4F3C2F
717
+ //
718
+ // `rgb` and `hsl` colors are parsed through the `entities.call` parser.
719
+ //
720
+ color: function () {
721
+ var rgb;
722
+
723
+ if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) {
724
+ return new(tree.Color)(rgb[1]);
725
+ }
726
+ },
727
+
728
+ //
729
+ // A Dimension, that is, a number and a unit
730
+ //
731
+ // 0.5em 95%
732
+ //
733
+ dimension: function () {
734
+ var value, c = input.charCodeAt(i);
735
+ if ((c > 57 || c < 45) || c === 47) return;
736
+
737
+ if (value = $(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) {
738
+ return new(tree.Dimension)(value[1], value[2]);
739
+ }
740
+ },
741
+
742
+ //
743
+ // JavaScript code to be evaluated
744
+ //
745
+ // `window.location.href`
746
+ //
747
+ javascript: function () {
748
+ var str, j = i, e;
749
+
750
+ if (input.charAt(j) === '~') { j++, e = true } // Escaped strings
751
+ if (input.charAt(j) !== '`') { return }
752
+
753
+ e && $('~');
754
+
755
+ if (str = $(/^`([^`]*)`/)) {
756
+ return new(tree.JavaScript)(str[1], i, e);
757
+ }
758
+ }
759
+ },
760
+
761
+ //
762
+ // The variable part of a variable definition. Used in the `rule` parser
763
+ //
764
+ // @fink:
765
+ //
766
+ variable: function () {
767
+ var name;
768
+
769
+ if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] }
770
+ },
771
+
772
+ //
773
+ // A font size/line-height shorthand
774
+ //
775
+ // small/12px
776
+ //
777
+ // We need to peek first, or we'll match on keywords and dimensions
778
+ //
779
+ shorthand: function () {
780
+ var a, b;
781
+
782
+ if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return;
783
+
784
+ if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) {
785
+ return new(tree.Shorthand)(a, b);
786
+ }
787
+ },
788
+
789
+ //
790
+ // Mixins
791
+ //
792
+ mixin: {
793
+ //
794
+ // A Mixin call, with an optional argument list
795
+ //
796
+ // #mixins > .square(#fff);
797
+ // .rounded(4px, black);
798
+ // .button;
799
+ //
800
+ // The `while` loop is there because mixins can be
801
+ // namespaced, but we only support the child and descendant
802
+ // selector for now.
803
+ //
804
+ call: function () {
805
+ var elements = [], e, c, args, index = i, s = input.charAt(i);
806
+
807
+ if (s !== '.' && s !== '#') { return }
808
+
809
+ while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) {
810
+ elements.push(new(tree.Element)(c, e, i));
811
+ c = $('>');
812
+ }
813
+ $('(') && (args = $(this.entities.arguments)) && $(')');
814
+
815
+ if (elements.length > 0 && ($(';') || peek('}'))) {
816
+ return new(tree.mixin.Call)(elements, args, index);
817
+ }
818
+ },
819
+
820
+ //
821
+ // A Mixin definition, with a list of parameters
822
+ //
823
+ // .rounded (@radius: 2px, @color) {
824
+ // ...
825
+ // }
826
+ //
827
+ // Until we have a finer grained state-machine, we have to
828
+ // do a look-ahead, to make sure we don't have a mixin call.
829
+ // See the `rule` function for more information.
830
+ //
831
+ // We start by matching `.rounded (`, and then proceed on to
832
+ // the argument list, which has optional default values.
833
+ // We store the parameters in `params`, with a `value` key,
834
+ // if there is a value, such as in the case of `@radius`.
835
+ //
836
+ // Once we've got our params list, and a closing `)`, we parse
837
+ // the `{...}` block.
838
+ //
839
+ definition: function () {
840
+ var name, params = [], match, ruleset, param, value;
841
+
842
+ if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') ||
843
+ peek(/^[^{]*(;|})/)) return;
844
+
845
+ if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) {
846
+ name = match[1];
847
+
848
+ while (param = $(this.entities.variable) || $(this.entities.literal)
849
+ || $(this.entities.keyword)) {
850
+ // Variable
851
+ if (param instanceof tree.Variable) {
852
+ if ($(':')) {
853
+ if (value = $(this.expression)) {
854
+ params.push({ name: param.name, value: value });
855
+ } else {
856
+ throw new(Error)("Expected value");
857
+ }
858
+ } else {
859
+ params.push({ name: param.name });
860
+ }
861
+ } else {
862
+ params.push({ value: param });
863
+ }
864
+ if (! $(',')) { break }
865
+ }
866
+ if (! $(')')) throw new(Error)("Expected )");
867
+
868
+ ruleset = $(this.block);
869
+
870
+ if (ruleset) {
871
+ return new(tree.mixin.Definition)(name, params, ruleset);
872
+ }
873
+ }
874
+ }
875
+ },
876
+
877
+ //
878
+ // Entities are the smallest recognized token,
879
+ // and can be found inside a rule's value.
880
+ //
881
+ entity: function () {
882
+ return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) ||
883
+ $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) ||
884
+ $(this.comment);
885
+ },
886
+
887
+ //
888
+ // A Rule terminator. Note that we use `peek()` to check for '}',
889
+ // because the `block` rule will be expecting it, but we still need to make sure
890
+ // it's there, if ';' was ommitted.
891
+ //
892
+ end: function () {
893
+ return $(';') || peek('}');
894
+ },
895
+
896
+ //
897
+ // IE's alpha function
898
+ //
899
+ // alpha(opacity=88)
900
+ //
901
+ alpha: function () {
902
+ var value;
903
+
904
+ if (! $(/^\(opacity=/i)) return;
905
+ if (value = $(/^\d+/) || $(this.entities.variable)) {
906
+ if (! $(')')) throw new(Error)("missing closing ) for alpha()");
907
+ return new(tree.Alpha)(value);
908
+ }
909
+ },
910
+
911
+ //
912
+ // A Selector Element
913
+ //
914
+ // div
915
+ // + h1
916
+ // #socks
917
+ // input[type="text"]
918
+ //
919
+ // Elements are the building blocks for Selectors,
920
+ // they are made out of a `Combinator` (see combinator rule),
921
+ // and an element name, such as a tag a class, or `*`.
922
+ //
923
+ element: function () {
924
+ var e, t, c;
925
+
926
+ c = $(this.combinator);
927
+ e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) ||
928
+ $('*') || $(this.attribute) || $(/^\([^)@]+\)/);
929
+
930
+ if (e) { return new(tree.Element)(c, e, i) }
931
+
932
+ if (c.value && c.value.charAt(0) === '&') {
933
+ return new(tree.Element)(c, null, i);
934
+ }
935
+ },
936
+
937
+ //
938
+ // Combinators combine elements together, in a Selector.
939
+ //
940
+ // Because our parser isn't white-space sensitive, special care
941
+ // has to be taken, when parsing the descendant combinator, ` `,
942
+ // as it's an empty space. We have to check the previous character
943
+ // in the input, to see if it's a ` ` character. More info on how
944
+ // we deal with this in *combinator.js*.
945
+ //
946
+ combinator: function () {
947
+ var match, c = input.charAt(i);
948
+
949
+ if (c === '>' || c === '+' || c === '~') {
950
+ i++;
951
+ while (input.charAt(i) === ' ') { i++ }
952
+ return new(tree.Combinator)(c);
953
+ } else if (c === '&') {
954
+ match = '&';
955
+ i++;
956
+ if(input.charAt(i) === ' ') {
957
+ match = '& ';
958
+ }
959
+ while (input.charAt(i) === ' ') { i++ }
960
+ return new(tree.Combinator)(match);
961
+ } else if (c === ':' && input.charAt(i + 1) === ':') {
962
+ i += 2;
963
+ while (input.charAt(i) === ' ') { i++ }
964
+ return new(tree.Combinator)('::');
965
+ } else if (input.charAt(i - 1) === ' ') {
966
+ return new(tree.Combinator)(" ");
967
+ } else {
968
+ return new(tree.Combinator)(null);
969
+ }
970
+ },
971
+
972
+ //
973
+ // A CSS Selector
974
+ //
975
+ // .class > div + h1
976
+ // li a:hover
977
+ //
978
+ // Selectors are made out of one or more Elements, see above.
979
+ //
980
+ selector: function () {
981
+ var sel, e, elements = [], c, match;
982
+
983
+ while (e = $(this.element)) {
984
+ c = input.charAt(i);
985
+ elements.push(e)
986
+ if (c === '{' || c === '}' || c === ';' || c === ',') { break }
987
+ }
988
+
989
+ if (elements.length > 0) { return new(tree.Selector)(elements) }
990
+ },
991
+ tag: function () {
992
+ return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*');
993
+ },
994
+ attribute: function () {
995
+ var attr = '', key, val, op;
996
+
997
+ if (! $('[')) return;
998
+
999
+ if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) {
1000
+ if ((op = $(/^[|~*$^]?=/)) &&
1001
+ (val = $(this.entities.quoted) || $(/^[\w-]+/))) {
1002
+ attr = [key, op, val.toCSS ? val.toCSS() : val].join('');
1003
+ } else { attr = key }
1004
+ }
1005
+
1006
+ if (! $(']')) return;
1007
+
1008
+ if (attr) { return "[" + attr + "]" }
1009
+ },
1010
+
1011
+ //
1012
+ // The `block` rule is used by `ruleset` and `mixin.definition`.
1013
+ // It's a wrapper around the `primary` rule, with added `{}`.
1014
+ //
1015
+ block: function () {
1016
+ var content;
1017
+
1018
+ if ($('{') && (content = $(this.primary)) && $('}')) {
1019
+ return content;
1020
+ }
1021
+ },
1022
+
1023
+ //
1024
+ // div, .class, body > p {...}
1025
+ //
1026
+ ruleset: function () {
1027
+ var selectors = [], s, rules, match;
1028
+ save();
1029
+
1030
+ while (s = $(this.selector)) {
1031
+ selectors.push(s);
1032
+ $(this.comment);
1033
+ if (! $(',')) { break }
1034
+ $(this.comment);
1035
+ }
1036
+
1037
+ if (selectors.length > 0 && (rules = $(this.block))) {
1038
+ return new(tree.Ruleset)(selectors, rules);
1039
+ } else {
1040
+ // Backtrack
1041
+ furthest = i;
1042
+ restore();
1043
+ }
1044
+ },
1045
+ rule: function () {
1046
+ var name, value, c = input.charAt(i), important, match;
1047
+ save();
1048
+
1049
+ if (c === '.' || c === '#' || c === '&') { return }
1050
+
1051
+ if (name = $(this.variable) || $(this.property)) {
1052
+ if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) {
1053
+ i += match[0].length - 1;
1054
+ value = new(tree.Anonymous)(match[1]);
1055
+ } else if (name === "font") {
1056
+ value = $(this.font);
1057
+ } else {
1058
+ value = $(this.value);
1059
+ }
1060
+ important = $(this.important);
1061
+
1062
+ if (value && $(this.end)) {
1063
+ return new(tree.Rule)(name, value, important, memo);
1064
+ } else {
1065
+ furthest = i;
1066
+ restore();
1067
+ }
1068
+ }
1069
+ },
1070
+
1071
+ //
1072
+ // An @import directive
1073
+ //
1074
+ // @import "lib";
1075
+ //
1076
+ // Depending on our environemnt, importing is done differently:
1077
+ // In the browser, it's an XHR request, in Node, it would be a
1078
+ // file-system operation. The function used for importing is
1079
+ // stored in `import`, which we pass to the Import constructor.
1080
+ //
1081
+ "import": function () {
1082
+ var path;
1083
+ if ($(/^@import\s+/) &&
1084
+ (path = $(this.entities.quoted) || $(this.entities.url)) &&
1085
+ $(';')) {
1086
+ return new(tree.Import)(path, imports);
1087
+ }
1088
+ },
1089
+
1090
+ //
1091
+ // A CSS Directive
1092
+ //
1093
+ // @charset "utf-8";
1094
+ //
1095
+ directive: function () {
1096
+ var name, value, rules, types;
1097
+
1098
+ if (input.charAt(i) !== '@') return;
1099
+
1100
+ if (value = $(this['import'])) {
1101
+ return value;
1102
+ } else if (name = $(/^@media|@page/) || $(/^@(?:-webkit-|-moz-)?keyframes/)) {
1103
+ types = ($(/^[^{]+/) || '').trim();
1104
+ if (rules = $(this.block)) {
1105
+ return new(tree.Directive)(name + " " + types, rules);
1106
+ }
1107
+ } else if (name = $(/^@[-a-z]+/)) {
1108
+ if (name === '@font-face') {
1109
+ if (rules = $(this.block)) {
1110
+ return new(tree.Directive)(name, rules);
1111
+ }
1112
+ } else if ((value = $(this.entity)) && $(';')) {
1113
+ return new(tree.Directive)(name, value);
1114
+ }
1115
+ }
1116
+ },
1117
+ font: function () {
1118
+ var value = [], expression = [], weight, shorthand, font, e;
1119
+
1120
+ while (e = $(this.shorthand) || $(this.entity)) {
1121
+ expression.push(e);
1122
+ }
1123
+ value.push(new(tree.Expression)(expression));
1124
+
1125
+ if ($(',')) {
1126
+ while (e = $(this.expression)) {
1127
+ value.push(e);
1128
+ if (! $(',')) { break }
1129
+ }
1130
+ }
1131
+ return new(tree.Value)(value);
1132
+ },
1133
+
1134
+ //
1135
+ // A Value is a comma-delimited list of Expressions
1136
+ //
1137
+ // font-family: Baskerville, Georgia, serif;
1138
+ //
1139
+ // In a Rule, a Value represents everything after the `:`,
1140
+ // and before the `;`.
1141
+ //
1142
+ value: function () {
1143
+ var e, expressions = [], important;
1144
+
1145
+ while (e = $(this.expression)) {
1146
+ expressions.push(e);
1147
+ if (! $(',')) { break }
1148
+ }
1149
+
1150
+ if (expressions.length > 0) {
1151
+ return new(tree.Value)(expressions);
1152
+ }
1153
+ },
1154
+ important: function () {
1155
+ if (input.charAt(i) === '!') {
1156
+ return $(/^! *important/);
1157
+ }
1158
+ },
1159
+ sub: function () {
1160
+ var e;
1161
+
1162
+ if ($('(') && (e = $(this.expression)) && $(')')) {
1163
+ return e;
1164
+ }
1165
+ },
1166
+ multiplication: function () {
1167
+ var m, a, op, operation;
1168
+ if (m = $(this.operand)) {
1169
+ while ((op = ($('/') || $('*'))) && (a = $(this.operand))) {
1170
+ operation = new(tree.Operation)(op, [operation || m, a]);
1171
+ }
1172
+ return operation || m;
1173
+ }
1174
+ },
1175
+ addition: function () {
1176
+ var m, a, op, operation;
1177
+ if (m = $(this.multiplication)) {
1178
+ while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) &&
1179
+ (a = $(this.multiplication))) {
1180
+ operation = new(tree.Operation)(op, [operation || m, a]);
1181
+ }
1182
+ return operation || m;
1183
+ }
1184
+ },
1185
+
1186
+ //
1187
+ // An operand is anything that can be part of an operation,
1188
+ // such as a Color, or a Variable
1189
+ //
1190
+ operand: function () {
1191
+ var negate, p = input.charAt(i + 1);
1192
+
1193
+ if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') }
1194
+ var o = $(this.sub) || $(this.entities.dimension) ||
1195
+ $(this.entities.color) || $(this.entities.variable) ||
1196
+ $(this.entities.call);
1197
+ return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o])
1198
+ : o;
1199
+ },
1200
+
1201
+ //
1202
+ // Expressions either represent mathematical operations,
1203
+ // or white-space delimited Entities.
1204
+ //
1205
+ // 1px solid black
1206
+ // @var * 2
1207
+ //
1208
+ expression: function () {
1209
+ var e, delim, entities = [], d;
1210
+
1211
+ while (e = $(this.addition) || $(this.entity)) {
1212
+ entities.push(e);
1213
+ }
1214
+ if (entities.length > 0) {
1215
+ return new(tree.Expression)(entities);
1216
+ }
1217
+ },
1218
+ property: function () {
1219
+ var name;
1220
+
1221
+ if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) {
1222
+ return name[1];
1223
+ }
1224
+ }
1225
+ }
1226
+ };
1227
+ };
1228
+
1229
+ if (less.mode === 'browser' || less.mode === 'rhino') {
1230
+ //
1231
+ // Used by `@import` directives
1232
+ //
1233
+ less.Parser.importer = function (path, paths, callback, env) {
1234
+ if (path.charAt(0) !== '/' && paths.length > 0) {
1235
+ path = paths[0] + path;
1236
+ }
1237
+ // We pass `true` as 3rd argument, to force the reload of the import.
1238
+ // This is so we can get the syntax tree as opposed to just the CSS output,
1239
+ // as we need this to evaluate the current stylesheet.
1240
+ loadStyleSheet({ href: path, title: path, type: env.mime }, callback, true);
1241
+ };
1242
+ }
1243
+
1244
+ (function (tree) {
1245
+
1246
+ tree.functions = {
1247
+ rgb: function (r, g, b) {
1248
+ return this.rgba(r, g, b, 1.0);
1249
+ },
1250
+ rgba: function (r, g, b, a) {
1251
+ var rgb = [r, g, b].map(function (c) { return number(c) }),
1252
+ a = number(a);
1253
+ return new(tree.Color)(rgb, a);
1254
+ },
1255
+ hsl: function (h, s, l) {
1256
+ return this.hsla(h, s, l, 1.0);
1257
+ },
1258
+ hsla: function (h, s, l, a) {
1259
+ h = (number(h) % 360) / 360;
1260
+ s = number(s); l = number(l); a = number(a);
1261
+
1262
+ var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
1263
+ var m1 = l * 2 - m2;
1264
+
1265
+ return this.rgba(hue(h + 1/3) * 255,
1266
+ hue(h) * 255,
1267
+ hue(h - 1/3) * 255,
1268
+ a);
1269
+
1270
+ function hue(h) {
1271
+ h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
1272
+ if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
1273
+ else if (h * 2 < 1) return m2;
1274
+ else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6;
1275
+ else return m1;
1276
+ }
1277
+ },
1278
+ hue: function (color) {
1279
+ return new(tree.Dimension)(Math.round(color.toHSL().h));
1280
+ },
1281
+ saturation: function (color) {
1282
+ return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%');
1283
+ },
1284
+ lightness: function (color) {
1285
+ return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%');
1286
+ },
1287
+ alpha: function (color) {
1288
+ return new(tree.Dimension)(color.toHSL().a);
1289
+ },
1290
+ saturate: function (color, amount) {
1291
+ var hsl = color.toHSL();
1292
+
1293
+ hsl.s += amount.value / 100;
1294
+ hsl.s = clamp(hsl.s);
1295
+ return hsla(hsl);
1296
+ },
1297
+ desaturate: function (color, amount) {
1298
+ var hsl = color.toHSL();
1299
+
1300
+ hsl.s -= amount.value / 100;
1301
+ hsl.s = clamp(hsl.s);
1302
+ return hsla(hsl);
1303
+ },
1304
+ lighten: function (color, amount) {
1305
+ var hsl = color.toHSL();
1306
+
1307
+ hsl.l += amount.value / 100;
1308
+ hsl.l = clamp(hsl.l);
1309
+ return hsla(hsl);
1310
+ },
1311
+ darken: function (color, amount) {
1312
+ var hsl = color.toHSL();
1313
+
1314
+ hsl.l -= amount.value / 100;
1315
+ hsl.l = clamp(hsl.l);
1316
+ return hsla(hsl);
1317
+ },
1318
+ fadein: function (color, amount) {
1319
+ var hsl = color.toHSL();
1320
+
1321
+ hsl.a += amount.value / 100;
1322
+ hsl.a = clamp(hsl.a);
1323
+ return hsla(hsl);
1324
+ },
1325
+ fadeout: function (color, amount) {
1326
+ var hsl = color.toHSL();
1327
+
1328
+ hsl.a -= amount.value / 100;
1329
+ hsl.a = clamp(hsl.a);
1330
+ return hsla(hsl);
1331
+ },
1332
+ fade: function (color, amount) {
1333
+ var hsl = color.toHSL();
1334
+
1335
+ hsl.a = amount.value / 100;
1336
+ hsl.a = clamp(hsl.a);
1337
+ return hsla(hsl);
1338
+ },
1339
+ spin: function (color, amount) {
1340
+ var hsl = color.toHSL();
1341
+ var hue = (hsl.h + amount.value) % 360;
1342
+
1343
+ hsl.h = hue < 0 ? 360 + hue : hue;
1344
+
1345
+ return hsla(hsl);
1346
+ },
1347
+ //
1348
+ // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
1349
+ // http://sass-lang.com
1350
+ //
1351
+ mix: function (color1, color2, weight) {
1352
+ var p = weight.value / 100.0;
1353
+ var w = p * 2 - 1;
1354
+ var a = color1.toHSL().a - color2.toHSL().a;
1355
+
1356
+ var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
1357
+ var w2 = 1 - w1;
1358
+
1359
+ var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,
1360
+ color1.rgb[1] * w1 + color2.rgb[1] * w2,
1361
+ color1.rgb[2] * w1 + color2.rgb[2] * w2];
1362
+
1363
+ var alpha = color1.alpha * p + color2.alpha * (1 - p);
1364
+
1365
+ return new(tree.Color)(rgb, alpha);
1366
+ },
1367
+ greyscale: function (color) {
1368
+ return this.desaturate(color, new(tree.Dimension)(100));
1369
+ },
1370
+ e: function (str) {
1371
+ return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str);
1372
+ },
1373
+ escape: function (str) {
1374
+ return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29"));
1375
+ },
1376
+ '%': function (quoted /* arg, arg, ...*/) {
1377
+ var args = Array.prototype.slice.call(arguments, 1),
1378
+ str = quoted.value;
1379
+
1380
+ for (var i = 0; i < args.length; i++) {
1381
+ str = str.replace(/%[sda]/i, function(token) {
1382
+ var value = token.match(/s/i) ? args[i].value : args[i].toCSS();
1383
+ return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
1384
+ });
1385
+ }
1386
+ str = str.replace(/%%/g, '%');
1387
+ return new(tree.Quoted)('"' + str + '"', str);
1388
+ },
1389
+ round: function (n) {
1390
+ if (n instanceof tree.Dimension) {
1391
+ return new(tree.Dimension)(Math.round(number(n)), n.unit);
1392
+ } else if (typeof(n) === 'number') {
1393
+ return Math.round(n);
1394
+ } else {
1395
+ throw {
1396
+ error: "RuntimeError",
1397
+ message: "math functions take numbers as parameters"
1398
+ };
1399
+ }
1400
+ },
1401
+ argb: function (color) {
1402
+ return new(tree.Anonymous)(color.toARGB());
1403
+
1404
+ }
1405
+ };
1406
+
1407
+ function hsla(hsla) {
1408
+ return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a);
1409
+ }
1410
+
1411
+ function number(n) {
1412
+ if (n instanceof tree.Dimension) {
1413
+ return parseFloat(n.unit == '%' ? n.value / 100 : n.value);
1414
+ } else if (typeof(n) === 'number') {
1415
+ return n;
1416
+ } else {
1417
+ throw {
1418
+ error: "RuntimeError",
1419
+ message: "color functions take numbers as parameters"
1420
+ };
1421
+ }
1422
+ }
1423
+
1424
+ function clamp(val) {
1425
+ return Math.min(1, Math.max(0, val));
1426
+ }
1427
+
1428
+ })(require('./tree'));
1429
+ (function (tree) {
1430
+
1431
+ tree.Alpha = function (val) {
1432
+ this.value = val;
1433
+ };
1434
+ tree.Alpha.prototype = {
1435
+ toCSS: function () {
1436
+ return "alpha(opacity=" +
1437
+ (this.value.toCSS ? this.value.toCSS() : this.value) + ")";
1438
+ },
1439
+ eval: function (env) {
1440
+ if (this.value.eval) { this.value = this.value.eval(env) }
1441
+ return this;
1442
+ }
1443
+ };
1444
+
1445
+ })(require('../tree'));
1446
+ (function (tree) {
1447
+
1448
+ tree.Anonymous = function (string) {
1449
+ this.value = string.value || string;
1450
+ };
1451
+ tree.Anonymous.prototype = {
1452
+ toCSS: function () {
1453
+ return this.value;
1454
+ },
1455
+ eval: function () { return this }
1456
+ };
1457
+
1458
+ })(require('../tree'));
1459
+ (function (tree) {
1460
+
1461
+ //
1462
+ // A function call node.
1463
+ //
1464
+ tree.Call = function (name, args, index) {
1465
+ this.name = name;
1466
+ this.args = args;
1467
+ this.index = index;
1468
+ };
1469
+ tree.Call.prototype = {
1470
+ //
1471
+ // When evaluating a function call,
1472
+ // we either find the function in `tree.functions` [1],
1473
+ // in which case we call it, passing the evaluated arguments,
1474
+ // or we simply print it out as it appeared originally [2].
1475
+ //
1476
+ // The *functions.js* file contains the built-in functions.
1477
+ //
1478
+ // The reason why we evaluate the arguments, is in the case where
1479
+ // we try to pass a variable to a function, like: `saturate(@color)`.
1480
+ // The function should receive the value, not the variable.
1481
+ //
1482
+ eval: function (env) {
1483
+ var args = this.args.map(function (a) { return a.eval(env) });
1484
+
1485
+ if (this.name in tree.functions) { // 1.
1486
+ try {
1487
+ return tree.functions[this.name].apply(tree.functions, args);
1488
+ } catch (e) {
1489
+ throw { message: "error evaluating function `" + this.name + "`",
1490
+ index: this.index };
1491
+ }
1492
+ } else { // 2.
1493
+ return new(tree.Anonymous)(this.name +
1494
+ "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")");
1495
+ }
1496
+ },
1497
+
1498
+ toCSS: function (env) {
1499
+ return this.eval(env).toCSS();
1500
+ }
1501
+ };
1502
+
1503
+ })(require('../tree'));
1504
+ (function (tree) {
1505
+ //
1506
+ // RGB Colors - #ff0014, #eee
1507
+ //
1508
+ tree.Color = function (rgb, a) {
1509
+ //
1510
+ // The end goal here, is to parse the arguments
1511
+ // into an integer triplet, such as `128, 255, 0`
1512
+ //
1513
+ // This facilitates operations and conversions.
1514
+ //
1515
+ if (Array.isArray(rgb)) {
1516
+ this.rgb = rgb;
1517
+ } else if (rgb.length == 6) {
1518
+ this.rgb = rgb.match(/.{2}/g).map(function (c) {
1519
+ return parseInt(c, 16);
1520
+ });
1521
+ } else {
1522
+ this.rgb = rgb.split('').map(function (c) {
1523
+ return parseInt(c + c, 16);
1524
+ });
1525
+ }
1526
+ this.alpha = typeof(a) === 'number' ? a : 1;
1527
+ };
1528
+ tree.Color.prototype = {
1529
+ eval: function () { return this },
1530
+
1531
+ //
1532
+ // If we have some transparency, the only way to represent it
1533
+ // is via `rgba`. Otherwise, we use the hex representation,
1534
+ // which has better compatibility with older browsers.
1535
+ // Values are capped between `0` and `255`, rounded and zero-padded.
1536
+ //
1537
+ toCSS: function () {
1538
+ if (this.alpha < 1.0) {
1539
+ return "rgba(" + this.rgb.map(function (c) {
1540
+ return Math.round(c);
1541
+ }).concat(this.alpha).join(', ') + ")";
1542
+ } else {
1543
+ return '#' + this.rgb.map(function (i) {
1544
+ i = Math.round(i);
1545
+ i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
1546
+ return i.length === 1 ? '0' + i : i;
1547
+ }).join('');
1548
+ }
1549
+ },
1550
+
1551
+ //
1552
+ // Operations have to be done per-channel, if not,
1553
+ // channels will spill onto each other. Once we have
1554
+ // our result, in the form of an integer triplet,
1555
+ // we create a new Color node to hold the result.
1556
+ //
1557
+ operate: function (op, other) {
1558
+ var result = [];
1559
+
1560
+ if (! (other instanceof tree.Color)) {
1561
+ other = other.toColor();
1562
+ }
1563
+
1564
+ for (var c = 0; c < 3; c++) {
1565
+ result[c] = tree.operate(op, this.rgb[c], other.rgb[c]);
1566
+ }
1567
+ return new(tree.Color)(result, this.alpha + other.alpha);
1568
+ },
1569
+
1570
+ toHSL: function () {
1571
+ var r = this.rgb[0] / 255,
1572
+ g = this.rgb[1] / 255,
1573
+ b = this.rgb[2] / 255,
1574
+ a = this.alpha;
1575
+
1576
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
1577
+ var h, s, l = (max + min) / 2, d = max - min;
1578
+
1579
+ if (max === min) {
1580
+ h = s = 0;
1581
+ } else {
1582
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
1583
+
1584
+ switch (max) {
1585
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
1586
+ case g: h = (b - r) / d + 2; break;
1587
+ case b: h = (r - g) / d + 4; break;
1588
+ }
1589
+ h /= 6;
1590
+ }
1591
+ return { h: h * 360, s: s, l: l, a: a };
1592
+ },
1593
+ toARGB: function () {
1594
+ var argb = [Math.round(this.alpha * 255)].concat(this.rgb);
1595
+ return '#' + argb.map(function (i) {
1596
+ i = Math.round(i);
1597
+ i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
1598
+ return i.length === 1 ? '0' + i : i;
1599
+ }).join('');
1600
+ }
1601
+ };
1602
+
1603
+
1604
+ })(require('../tree'));
1605
+ (function (tree) {
1606
+
1607
+ tree.Comment = function (value, silent) {
1608
+ this.value = value;
1609
+ this.silent = !!silent;
1610
+ };
1611
+ tree.Comment.prototype = {
1612
+ toCSS: function (env) {
1613
+ return env.compress ? '' : this.value;
1614
+ },
1615
+ eval: function () { return this }
1616
+ };
1617
+
1618
+ })(require('../tree'));
1619
+ (function (tree) {
1620
+
1621
+ //
1622
+ // A number with a unit
1623
+ //
1624
+ tree.Dimension = function (value, unit) {
1625
+ this.value = parseFloat(value);
1626
+ this.unit = unit || null;
1627
+ };
1628
+
1629
+ tree.Dimension.prototype = {
1630
+ eval: function () { return this },
1631
+ toColor: function () {
1632
+ return new(tree.Color)([this.value, this.value, this.value]);
1633
+ },
1634
+ toCSS: function () {
1635
+ var css = this.value + this.unit;
1636
+ return css;
1637
+ },
1638
+
1639
+ // In an operation between two Dimensions,
1640
+ // we default to the first Dimension's unit,
1641
+ // so `1px + 2em` will yield `3px`.
1642
+ // In the future, we could implement some unit
1643
+ // conversions such that `100cm + 10mm` would yield
1644
+ // `101cm`.
1645
+ operate: function (op, other) {
1646
+ return new(tree.Dimension)
1647
+ (tree.operate(op, this.value, other.value),
1648
+ this.unit || other.unit);
1649
+ }
1650
+ };
1651
+
1652
+ })(require('../tree'));
1653
+ (function (tree) {
1654
+
1655
+ tree.Directive = function (name, value) {
1656
+ this.name = name;
1657
+ if (Array.isArray(value)) {
1658
+ this.ruleset = new(tree.Ruleset)([], value);
1659
+ } else {
1660
+ this.value = value;
1661
+ }
1662
+ };
1663
+ tree.Directive.prototype = {
1664
+ toCSS: function (ctx, env) {
1665
+ if (this.ruleset) {
1666
+ this.ruleset.root = true;
1667
+ return this.name + (env.compress ? '{' : ' {\n ') +
1668
+ this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') +
1669
+ (env.compress ? '}': '\n}\n');
1670
+ } else {
1671
+ return this.name + ' ' + this.value.toCSS() + ';\n';
1672
+ }
1673
+ },
1674
+ eval: function (env) {
1675
+ env.frames.unshift(this);
1676
+ this.ruleset = this.ruleset && this.ruleset.eval(env);
1677
+ env.frames.shift();
1678
+ return this;
1679
+ },
1680
+ variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
1681
+ find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
1682
+ rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }
1683
+ };
1684
+
1685
+ })(require('../tree'));
1686
+ (function (tree) {
1687
+
1688
+ tree.Element = function (combinator, value, index) {
1689
+ this.combinator = combinator instanceof tree.Combinator ?
1690
+ combinator : new(tree.Combinator)(combinator);
1691
+ this.value = value ? value.trim() : "";
1692
+ this.index = index;
1693
+ };
1694
+ tree.Element.prototype.toCSS = function (env) {
1695
+ return this.combinator.toCSS(env || {}) + this.value;
1696
+ };
1697
+
1698
+ tree.Combinator = function (value) {
1699
+ if (value === ' ') {
1700
+ this.value = ' ';
1701
+ } else if (value === '& ') {
1702
+ this.value = '& ';
1703
+ } else {
1704
+ this.value = value ? value.trim() : "";
1705
+ }
1706
+ };
1707
+ tree.Combinator.prototype.toCSS = function (env) {
1708
+ return {
1709
+ '' : '',
1710
+ ' ' : ' ',
1711
+ '&' : '',
1712
+ '& ' : ' ',
1713
+ ':' : ' :',
1714
+ '::': '::',
1715
+ '+' : env.compress ? '+' : ' + ',
1716
+ '~' : env.compress ? '~' : ' ~ ',
1717
+ '>' : env.compress ? '>' : ' > '
1718
+ }[this.value];
1719
+ };
1720
+
1721
+ })(require('../tree'));
1722
+ (function (tree) {
1723
+
1724
+ tree.Expression = function (value) { this.value = value };
1725
+ tree.Expression.prototype = {
1726
+ eval: function (env) {
1727
+ if (this.value.length > 1) {
1728
+ return new(tree.Expression)(this.value.map(function (e) {
1729
+ return e.eval(env);
1730
+ }));
1731
+ } else if (this.value.length === 1) {
1732
+ return this.value[0].eval(env);
1733
+ } else {
1734
+ return this;
1735
+ }
1736
+ },
1737
+ toCSS: function (env) {
1738
+ return this.value.map(function (e) {
1739
+ return e.toCSS(env);
1740
+ }).join(' ');
1741
+ }
1742
+ };
1743
+
1744
+ })(require('../tree'));
1745
+ (function (tree) {
1746
+ //
1747
+ // CSS @import node
1748
+ //
1749
+ // The general strategy here is that we don't want to wait
1750
+ // for the parsing to be completed, before we start importing
1751
+ // the file. That's because in the context of a browser,
1752
+ // most of the time will be spent waiting for the server to respond.
1753
+ //
1754
+ // On creation, we push the import path to our import queue, though
1755
+ // `import,push`, we also pass it a callback, which it'll call once
1756
+ // the file has been fetched, and parsed.
1757
+ //
1758
+ tree.Import = function (path, imports) {
1759
+ var that = this;
1760
+
1761
+ this._path = path;
1762
+
1763
+ // The '.less' extension is optional
1764
+ if (path instanceof tree.Quoted) {
1765
+ this.path = /\.(le?|c)ss(\?.*)?$/.test(path.value) ? path.value : path.value + '.less';
1766
+ } else {
1767
+ this.path = path.value.value || path.value;
1768
+ }
1769
+
1770
+ this.css = /css(\?.*)?$/.test(this.path);
1771
+
1772
+ // Only pre-compile .less files
1773
+ if (! this.css) {
1774
+ imports.push(this.path, function (root) {
1775
+ if (! root) {
1776
+ throw new(Error)("Error parsing " + that.path);
1777
+ }
1778
+ that.root = root;
1779
+ });
1780
+ }
1781
+ };
1782
+
1783
+ //
1784
+ // The actual import node doesn't return anything, when converted to CSS.
1785
+ // The reason is that it's used at the evaluation stage, so that the rules
1786
+ // it imports can be treated like any other rules.
1787
+ //
1788
+ // In `eval`, we make sure all Import nodes get evaluated, recursively, so
1789
+ // we end up with a flat structure, which can easily be imported in the parent
1790
+ // ruleset.
1791
+ //
1792
+ tree.Import.prototype = {
1793
+ toCSS: function () {
1794
+ if (this.css) {
1795
+ return "@import " + this._path.toCSS() + ';\n';
1796
+ } else {
1797
+ return "";
1798
+ }
1799
+ },
1800
+ eval: function (env) {
1801
+ var ruleset;
1802
+
1803
+ if (this.css) {
1804
+ return this;
1805
+ } else {
1806
+ ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0));
1807
+
1808
+ for (var i = 0; i < ruleset.rules.length; i++) {
1809
+ if (ruleset.rules[i] instanceof tree.Import) {
1810
+ Array.prototype
1811
+ .splice
1812
+ .apply(ruleset.rules,
1813
+ [i, 1].concat(ruleset.rules[i].eval(env)));
1814
+ }
1815
+ }
1816
+ return ruleset.rules;
1817
+ }
1818
+ }
1819
+ };
1820
+
1821
+ })(require('../tree'));
1822
+ (function (tree) {
1823
+
1824
+ tree.JavaScript = function (string, index, escaped) {
1825
+ this.escaped = escaped;
1826
+ this.expression = string;
1827
+ this.index = index;
1828
+ };
1829
+ tree.JavaScript.prototype = {
1830
+ eval: function (env) {
1831
+ var result,
1832
+ that = this,
1833
+ context = {};
1834
+
1835
+ var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) {
1836
+ return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env));
1837
+ });
1838
+
1839
+ try {
1840
+ expression = new(Function)('return (' + expression + ')');
1841
+ } catch (e) {
1842
+ throw { message: "JavaScript evaluation error: `" + expression + "`" ,
1843
+ index: this.index };
1844
+ }
1845
+
1846
+ for (var k in env.frames[0].variables()) {
1847
+ context[k.slice(1)] = {
1848
+ value: env.frames[0].variables()[k].value,
1849
+ toJS: function () {
1850
+ return this.value.eval(env).toCSS();
1851
+ }
1852
+ };
1853
+ }
1854
+
1855
+ try {
1856
+ result = expression.call(context);
1857
+ } catch (e) {
1858
+ throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" ,
1859
+ index: this.index };
1860
+ }
1861
+ if (typeof(result) === 'string') {
1862
+ return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index);
1863
+ } else if (Array.isArray(result)) {
1864
+ return new(tree.Anonymous)(result.join(', '));
1865
+ } else {
1866
+ return new(tree.Anonymous)(result);
1867
+ }
1868
+ }
1869
+ };
1870
+
1871
+ })(require('../tree'));
1872
+
1873
+ (function (tree) {
1874
+
1875
+ tree.Keyword = function (value) { this.value = value };
1876
+ tree.Keyword.prototype = {
1877
+ eval: function () { return this },
1878
+ toCSS: function () { return this.value }
1879
+ };
1880
+
1881
+ })(require('../tree'));
1882
+ (function (tree) {
1883
+
1884
+ tree.mixin = {};
1885
+ tree.mixin.Call = function (elements, args, index) {
1886
+ this.selector = new(tree.Selector)(elements);
1887
+ this.arguments = args;
1888
+ this.index = index;
1889
+ };
1890
+ tree.mixin.Call.prototype = {
1891
+ eval: function (env) {
1892
+ var mixins, args, rules = [], match = false;
1893
+
1894
+ for (var i = 0; i < env.frames.length; i++) {
1895
+ if ((mixins = env.frames[i].find(this.selector)).length > 0) {
1896
+ args = this.arguments && this.arguments.map(function (a) { return a.eval(env) });
1897
+ for (var m = 0; m < mixins.length; m++) {
1898
+ if (mixins[m].match(args, env)) {
1899
+ try {
1900
+ Array.prototype.push.apply(
1901
+ rules, mixins[m].eval(env, this.arguments).rules);
1902
+ match = true;
1903
+ } catch (e) {
1904
+ throw { message: e.message, index: e.index, stack: e.stack, call: this.index };
1905
+ }
1906
+ }
1907
+ }
1908
+ if (match) {
1909
+ return rules;
1910
+ } else {
1911
+ throw { message: 'No matching definition was found for `' +
1912
+ this.selector.toCSS().trim() + '(' +
1913
+ this.arguments.map(function (a) {
1914
+ return a.toCSS();
1915
+ }).join(', ') + ")`",
1916
+ index: this.index };
1917
+ }
1918
+ }
1919
+ }
1920
+ throw { message: this.selector.toCSS().trim() + " is undefined",
1921
+ index: this.index };
1922
+ }
1923
+ };
1924
+
1925
+ tree.mixin.Definition = function (name, params, rules) {
1926
+ this.name = name;
1927
+ this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])];
1928
+ this.params = params;
1929
+ this.arity = params.length;
1930
+ this.rules = rules;
1931
+ this._lookups = {};
1932
+ this.required = params.reduce(function (count, p) {
1933
+ if (!p.name || (p.name && !p.value)) { return count + 1 }
1934
+ else { return count }
1935
+ }, 0);
1936
+ this.parent = tree.Ruleset.prototype;
1937
+ this.frames = [];
1938
+ };
1939
+ tree.mixin.Definition.prototype = {
1940
+ toCSS: function () { return "" },
1941
+ variable: function (name) { return this.parent.variable.call(this, name) },
1942
+ variables: function () { return this.parent.variables.call(this) },
1943
+ find: function () { return this.parent.find.apply(this, arguments) },
1944
+ rulesets: function () { return this.parent.rulesets.apply(this) },
1945
+
1946
+ eval: function (env, args) {
1947
+ var frame = new(tree.Ruleset)(null, []), context, _arguments = [];
1948
+
1949
+ for (var i = 0, val; i < this.params.length; i++) {
1950
+ if (this.params[i].name) {
1951
+ if (val = (args && args[i]) || this.params[i].value) {
1952
+ frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env)));
1953
+ } else {
1954
+ throw { message: "wrong number of arguments for " + this.name +
1955
+ ' (' + args.length + ' for ' + this.arity + ')' };
1956
+ }
1957
+ }
1958
+ }
1959
+ for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) {
1960
+ _arguments.push(args[i] || this.params[i].value);
1961
+ }
1962
+ frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
1963
+
1964
+ return new(tree.Ruleset)(null, this.rules.slice(0)).eval({
1965
+ frames: [this, frame].concat(this.frames, env.frames)
1966
+ });
1967
+ },
1968
+ match: function (args, env) {
1969
+ var argsLength = (args && args.length) || 0, len;
1970
+
1971
+ if (argsLength < this.required) { return false }
1972
+ if ((this.required > 0) && (argsLength > this.params.length)) { return false }
1973
+
1974
+ len = Math.min(argsLength, this.arity);
1975
+
1976
+ for (var i = 0; i < len; i++) {
1977
+ if (!this.params[i].name) {
1978
+ if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {
1979
+ return false;
1980
+ }
1981
+ }
1982
+ }
1983
+ return true;
1984
+ }
1985
+ };
1986
+
1987
+ })(require('../tree'));
1988
+ (function (tree) {
1989
+
1990
+ tree.Operation = function (op, operands) {
1991
+ this.op = op.trim();
1992
+ this.operands = operands;
1993
+ };
1994
+ tree.Operation.prototype.eval = function (env) {
1995
+ var a = this.operands[0].eval(env),
1996
+ b = this.operands[1].eval(env),
1997
+ temp;
1998
+
1999
+ if (a instanceof tree.Dimension && b instanceof tree.Color) {
2000
+ if (this.op === '*' || this.op === '+') {
2001
+ temp = b, b = a, a = temp;
2002
+ } else {
2003
+ throw { name: "OperationError",
2004
+ message: "Can't substract or divide a color from a number" };
2005
+ }
2006
+ }
2007
+ return a.operate(this.op, b);
2008
+ };
2009
+
2010
+ tree.operate = function (op, a, b) {
2011
+ switch (op) {
2012
+ case '+': return a + b;
2013
+ case '-': return a - b;
2014
+ case '*': return a * b;
2015
+ case '/': return a / b;
2016
+ }
2017
+ };
2018
+
2019
+ })(require('../tree'));
2020
+ (function (tree) {
2021
+
2022
+ tree.Quoted = function (str, content, escaped, i) {
2023
+ this.escaped = escaped;
2024
+ this.value = content || '';
2025
+ this.quote = str.charAt(0);
2026
+ this.index = i;
2027
+ };
2028
+ tree.Quoted.prototype = {
2029
+ toCSS: function () {
2030
+ if (this.escaped) {
2031
+ return this.value;
2032
+ } else {
2033
+ return this.quote + this.value + this.quote;
2034
+ }
2035
+ },
2036
+ eval: function (env) {
2037
+ var that = this;
2038
+ var value = this.value.replace(/`([^`]+)`/g, function (_, exp) {
2039
+ return new(tree.JavaScript)(exp, that.index, true).eval(env).value;
2040
+ }).replace(/@\{([\w-]+)\}/g, function (_, name) {
2041
+ var v = new(tree.Variable)('@' + name, that.index).eval(env);
2042
+ return v.value || v.toCSS();
2043
+ });
2044
+ return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index);
2045
+ }
2046
+ };
2047
+
2048
+ })(require('../tree'));
2049
+ (function (tree) {
2050
+
2051
+ tree.Rule = function (name, value, important, index) {
2052
+ this.name = name;
2053
+ this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);
2054
+ this.important = important ? ' ' + important.trim() : '';
2055
+ this.index = index;
2056
+
2057
+ if (name.charAt(0) === '@') {
2058
+ this.variable = true;
2059
+ } else { this.variable = false }
2060
+ };
2061
+ tree.Rule.prototype.toCSS = function (env) {
2062
+ if (this.variable) { return "" }
2063
+ else {
2064
+ return this.name + (env.compress ? ':' : ': ') +
2065
+ this.value.toCSS(env) +
2066
+ this.important + ";";
2067
+ }
2068
+ };
2069
+
2070
+ tree.Rule.prototype.eval = function (context) {
2071
+ return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index);
2072
+ };
2073
+
2074
+ tree.Shorthand = function (a, b) {
2075
+ this.a = a;
2076
+ this.b = b;
2077
+ };
2078
+
2079
+ tree.Shorthand.prototype = {
2080
+ toCSS: function (env) {
2081
+ return this.a.toCSS(env) + "/" + this.b.toCSS(env);
2082
+ },
2083
+ eval: function () { return this }
2084
+ };
2085
+
2086
+ })(require('../tree'));
2087
+ (function (tree) {
2088
+
2089
+ tree.Ruleset = function (selectors, rules) {
2090
+ this.selectors = selectors;
2091
+ this.rules = rules;
2092
+ this._lookups = {};
2093
+ };
2094
+ tree.Ruleset.prototype = {
2095
+ eval: function (env) {
2096
+ var ruleset = new(tree.Ruleset)(this.selectors, this.rules.slice(0));
2097
+
2098
+ ruleset.root = this.root;
2099
+
2100
+ // push the current ruleset to the frames stack
2101
+ env.frames.unshift(ruleset);
2102
+
2103
+ // Evaluate imports
2104
+ if (ruleset.root) {
2105
+ for (var i = 0; i < ruleset.rules.length; i++) {
2106
+ if (ruleset.rules[i] instanceof tree.Import) {
2107
+ Array.prototype.splice
2108
+ .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env)));
2109
+ }
2110
+ }
2111
+ }
2112
+
2113
+ // Store the frames around mixin definitions,
2114
+ // so they can be evaluated like closures when the time comes.
2115
+ for (var i = 0; i < ruleset.rules.length; i++) {
2116
+ if (ruleset.rules[i] instanceof tree.mixin.Definition) {
2117
+ ruleset.rules[i].frames = env.frames.slice(0);
2118
+ }
2119
+ }
2120
+
2121
+ // Evaluate mixin calls.
2122
+ for (var i = 0; i < ruleset.rules.length; i++) {
2123
+ if (ruleset.rules[i] instanceof tree.mixin.Call) {
2124
+ Array.prototype.splice
2125
+ .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env)));
2126
+ }
2127
+ }
2128
+
2129
+ // Evaluate everything else
2130
+ for (var i = 0, rule; i < ruleset.rules.length; i++) {
2131
+ rule = ruleset.rules[i];
2132
+
2133
+ if (! (rule instanceof tree.mixin.Definition)) {
2134
+ ruleset.rules[i] = rule.eval ? rule.eval(env) : rule;
2135
+ }
2136
+ }
2137
+
2138
+ // Pop the stack
2139
+ env.frames.shift();
2140
+
2141
+ return ruleset;
2142
+ },
2143
+ match: function (args) {
2144
+ return !args || args.length === 0;
2145
+ },
2146
+ variables: function () {
2147
+ if (this._variables) { return this._variables }
2148
+ else {
2149
+ return this._variables = this.rules.reduce(function (hash, r) {
2150
+ if (r instanceof tree.Rule && r.variable === true) {
2151
+ hash[r.name] = r;
2152
+ }
2153
+ return hash;
2154
+ }, {});
2155
+ }
2156
+ },
2157
+ variable: function (name) {
2158
+ return this.variables()[name];
2159
+ },
2160
+ rulesets: function () {
2161
+ if (this._rulesets) { return this._rulesets }
2162
+ else {
2163
+ return this._rulesets = this.rules.filter(function (r) {
2164
+ return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition);
2165
+ });
2166
+ }
2167
+ },
2168
+ find: function (selector, self) {
2169
+ self = self || this;
2170
+ var rules = [], rule, match,
2171
+ key = selector.toCSS();
2172
+
2173
+ if (key in this._lookups) { return this._lookups[key] }
2174
+
2175
+ this.rulesets().forEach(function (rule) {
2176
+ if (rule !== self) {
2177
+ for (var j = 0; j < rule.selectors.length; j++) {
2178
+ if (match = selector.match(rule.selectors[j])) {
2179
+ if (selector.elements.length > rule.selectors[j].elements.length) {
2180
+ Array.prototype.push.apply(rules, rule.find(
2181
+ new(tree.Selector)(selector.elements.slice(1)), self));
2182
+ } else {
2183
+ rules.push(rule);
2184
+ }
2185
+ break;
2186
+ }
2187
+ }
2188
+ }
2189
+ });
2190
+ return this._lookups[key] = rules;
2191
+ },
2192
+ //
2193
+ // Entry point for code generation
2194
+ //
2195
+ // `context` holds an array of arrays.
2196
+ //
2197
+ toCSS: function (context, env) {
2198
+ var css = [], // The CSS output
2199
+ rules = [], // node.Rule instances
2200
+ rulesets = [], // node.Ruleset instances
2201
+ paths = [], // Current selectors
2202
+ selector, // The fully rendered selector
2203
+ rule;
2204
+
2205
+ if (! this.root) {
2206
+ if (context.length === 0) {
2207
+ paths = this.selectors.map(function (s) { return [s] });
2208
+ } else {
2209
+ this.joinSelectors( paths, context, this.selectors );
2210
+ }
2211
+ }
2212
+
2213
+ // Compile rules and rulesets
2214
+ for (var i = 0; i < this.rules.length; i++) {
2215
+ rule = this.rules[i];
2216
+
2217
+ if (rule.rules || (rule instanceof tree.Directive)) {
2218
+ rulesets.push(rule.toCSS(paths, env));
2219
+ } else if (rule instanceof tree.Comment) {
2220
+ if (!rule.silent) {
2221
+ if (this.root) {
2222
+ rulesets.push(rule.toCSS(env));
2223
+ } else {
2224
+ rules.push(rule.toCSS(env));
2225
+ }
2226
+ }
2227
+ } else {
2228
+ if (rule.toCSS && !rule.variable) {
2229
+ rules.push(rule.toCSS(env));
2230
+ } else if (rule.value && !rule.variable) {
2231
+ rules.push(rule.value.toString());
2232
+ }
2233
+ }
2234
+ }
2235
+
2236
+ rulesets = rulesets.join('');
2237
+
2238
+ // If this is the root node, we don't render
2239
+ // a selector, or {}.
2240
+ // Otherwise, only output if this ruleset has rules.
2241
+ if (this.root) {
2242
+ css.push(rules.join(env.compress ? '' : '\n'));
2243
+ } else {
2244
+ if (rules.length > 0) {
2245
+ selector = paths.map(function (p) {
2246
+ return p.map(function (s) {
2247
+ return s.toCSS(env);
2248
+ }).join('').trim();
2249
+ }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', '));
2250
+ css.push(selector,
2251
+ (env.compress ? '{' : ' {\n ') +
2252
+ rules.join(env.compress ? '' : '\n ') +
2253
+ (env.compress ? '}' : '\n}\n'));
2254
+ }
2255
+ }
2256
+ css.push(rulesets);
2257
+
2258
+ return css.join('') + (env.compress ? '\n' : '');
2259
+ },
2260
+
2261
+ joinSelectors: function (paths, context, selectors) {
2262
+ for (var s = 0; s < selectors.length; s++) {
2263
+ this.joinSelector(paths, context, selectors[s]);
2264
+ }
2265
+ },
2266
+
2267
+ joinSelector: function (paths, context, selector) {
2268
+ var before = [], after = [], beforeElements = [],
2269
+ afterElements = [], hasParentSelector = false, el;
2270
+
2271
+ for (var i = 0; i < selector.elements.length; i++) {
2272
+ el = selector.elements[i];
2273
+ if (el.combinator.value.charAt(0) === '&') {
2274
+ hasParentSelector = true;
2275
+ }
2276
+ if (hasParentSelector) afterElements.push(el);
2277
+ else beforeElements.push(el);
2278
+ }
2279
+
2280
+ if (! hasParentSelector) {
2281
+ afterElements = beforeElements;
2282
+ beforeElements = [];
2283
+ }
2284
+
2285
+ if (beforeElements.length > 0) {
2286
+ before.push(new(tree.Selector)(beforeElements));
2287
+ }
2288
+
2289
+ if (afterElements.length > 0) {
2290
+ after.push(new(tree.Selector)(afterElements));
2291
+ }
2292
+
2293
+ for (var c = 0; c < context.length; c++) {
2294
+ paths.push(before.concat(context[c]).concat(after));
2295
+ }
2296
+ }
2297
+ };
2298
+ })(require('../tree'));
2299
+ (function (tree) {
2300
+
2301
+ tree.Selector = function (elements) {
2302
+ this.elements = elements;
2303
+ if (this.elements[0].combinator.value === "") {
2304
+ this.elements[0].combinator.value = ' ';
2305
+ }
2306
+ };
2307
+ tree.Selector.prototype.match = function (other) {
2308
+ var len = this.elements.length,
2309
+ olen = other.elements.length,
2310
+ max = Math.min(len, olen);
2311
+
2312
+ if (len < olen) {
2313
+ return false;
2314
+ } else {
2315
+ for (var i = 0; i < max; i++) {
2316
+ if (this.elements[i].value !== other.elements[i].value) {
2317
+ return false;
2318
+ }
2319
+ }
2320
+ }
2321
+ return true;
2322
+ };
2323
+ tree.Selector.prototype.toCSS = function (env) {
2324
+ if (this._css) { return this._css }
2325
+
2326
+ return this._css = this.elements.map(function (e) {
2327
+ if (typeof(e) === 'string') {
2328
+ return ' ' + e.trim();
2329
+ } else {
2330
+ return e.toCSS(env);
2331
+ }
2332
+ }).join('');
2333
+ };
2334
+
2335
+ })(require('../tree'));
2336
+ (function (tree) {
2337
+
2338
+ tree.URL = function (val, paths) {
2339
+ if (val.data) {
2340
+ this.attrs = val;
2341
+ } else {
2342
+ // Add the base path if the URL is relative and we are in the browser
2343
+ if (!/^(?:https?:\/\/|file:\/\/|data:)?/.test(val.value) && paths.length > 0 && typeof(window) !== 'undefined') {
2344
+ val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value);
2345
+ }
2346
+ this.value = val;
2347
+ this.paths = paths;
2348
+ }
2349
+ };
2350
+ tree.URL.prototype = {
2351
+ toCSS: function () {
2352
+ return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data
2353
+ : this.value.toCSS()) + ")";
2354
+ },
2355
+ eval: function (ctx) {
2356
+ return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths);
2357
+ }
2358
+ };
2359
+
2360
+ })(require('../tree'));
2361
+ (function (tree) {
2362
+
2363
+ tree.Value = function (value) {
2364
+ this.value = value;
2365
+ this.is = 'value';
2366
+ };
2367
+ tree.Value.prototype = {
2368
+ eval: function (env) {
2369
+ if (this.value.length === 1) {
2370
+ return this.value[0].eval(env);
2371
+ } else {
2372
+ return new(tree.Value)(this.value.map(function (v) {
2373
+ return v.eval(env);
2374
+ }));
2375
+ }
2376
+ },
2377
+ toCSS: function (env) {
2378
+ return this.value.map(function (e) {
2379
+ return e.toCSS(env);
2380
+ }).join(env.compress ? ',' : ', ');
2381
+ }
2382
+ };
2383
+
2384
+ })(require('../tree'));
2385
+ (function (tree) {
2386
+
2387
+ tree.Variable = function (name, index) { this.name = name, this.index = index };
2388
+ tree.Variable.prototype = {
2389
+ eval: function (env) {
2390
+ var variable, v, name = this.name;
2391
+
2392
+ if (name.indexOf('@@') == 0) {
2393
+ name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value;
2394
+ }
2395
+
2396
+ if (variable = tree.find(env.frames, function (frame) {
2397
+ if (v = frame.variable(name)) {
2398
+ return v.value.eval(env);
2399
+ }
2400
+ })) { return variable }
2401
+ else {
2402
+ throw { message: "variable " + name + " is undefined",
2403
+ index: this.index };
2404
+ }
2405
+ }
2406
+ };
2407
+
2408
+ })(require('../tree'));
2409
+ require('./tree').find = function (obj, fun) {
2410
+ for (var i = 0, r; i < obj.length; i++) {
2411
+ if (r = fun.call(obj, obj[i])) { return r }
2412
+ }
2413
+ return null;
2414
+ };
2415
+ require('./tree').jsify = function (obj) {
2416
+ if (Array.isArray(obj.value) && (obj.value.length > 1)) {
2417
+ return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']';
2418
+ } else {
2419
+ return obj.toCSS(false);
2420
+ }
2421
+ };
2422
+ var name;
2423
+
2424
+ function loadStyleSheet(sheet, callback, reload, remaining) {
2425
+ var sheetName = name.slice(0, name.lastIndexOf('/') + 1) + sheet.href;
2426
+ var input = readFile(sheetName);
2427
+ var parser = new less.Parser();
2428
+ parser.parse(input, function (e, root) {
2429
+ if (e) {
2430
+ print("Error: " + e);
2431
+ quit(1);
2432
+ }
2433
+ callback(root, sheet, { local: false, lastModified: 0, remaining: remaining });
2434
+ });
2435
+
2436
+ // callback({}, sheet, { local: true, remaining: remaining });
2437
+ }
2438
+
2439
+ function writeFile(filename, content) {
2440
+ var fstream = new java.io.FileWriter(filename);
2441
+ var out = new java.io.BufferedWriter(fstream);
2442
+ out.write(content);
2443
+ out.close();
2444
+ }
2445
+
2446
+ // Command line integration via Rhino
2447
+ (function (args) {
2448
+ name = args[0];
2449
+ var output = args[1];
2450
+
2451
+ if (!name) {
2452
+ print('No files present in the fileset; Check your pattern match in build.xml');
2453
+ quit(1);
2454
+ }
2455
+ path = name.split("/");path.pop();path=path.join("/")
2456
+
2457
+ var input = readFile(name);
2458
+
2459
+ if (!input) {
2460
+ print('lesscss: couldn\'t open file ' + name);
2461
+ quit(1);
2462
+ }
2463
+
2464
+ var result;
2465
+ var parser = new less.Parser();
2466
+ parser.parse(input, function (e, root) {
2467
+ if (e) {
2468
+ quit(1);
2469
+ } else {
2470
+ result = root.toCSS();
2471
+ if (output) {
2472
+ writeFile(output, result);
2473
+ print("Written to " + output);
2474
+ } else {
2475
+ print(result);
2476
+ }
2477
+ quit(0);
2478
+ }
2479
+ });
2480
+ print("done");
2481
+ }(arguments));