less-js-source 1.1.3 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. data/less-js-source.gemspec +1 -1
  2. data/lib/less_js/less.js +1546 -420
  3. metadata +23 -39
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "less-js-source"
6
- s.version = '1.1.3'
6
+ s.version = '1.3.0'
7
7
  s.authors = ["Alexis Sellier"]
8
8
  s.email = ["alexis@cloudhead.io"]
9
9
  s.homepage = "http://lesscss.org"
data/lib/less_js/less.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //
2
- // LESS - Leaner CSS v1.1.3
2
+ // LESS - Leaner CSS v1.3.0
3
3
  // http://lesscss.org
4
4
  //
5
5
  // Copyright (c) 2009-2011, Alexis Sellier
@@ -13,6 +13,12 @@ function require(arg) {
13
13
  return window.less[arg.split('/')[1]];
14
14
  };
15
15
 
16
+ // amd.js
17
+ //
18
+ // Define Less as an AMD module.
19
+ if (typeof define === "function" && define.amd) {
20
+ define("less", [], function () { return less; } );
21
+ }
16
22
 
17
23
  // ecma-5.js
18
24
  //
@@ -135,13 +141,24 @@ if (!String.prototype.trim) {
135
141
  }
136
142
  var less, tree;
137
143
 
138
- if (typeof(window) === 'undefined') {
144
+ if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") {
145
+ // Rhino
146
+ // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88
147
+ if (typeof(window) === 'undefined') { less = {} }
148
+ else { less = window.less = {} }
149
+ tree = less.tree = {};
150
+ less.mode = 'rhino';
151
+ } else if (typeof(window) === 'undefined') {
152
+ // Node.js
139
153
  less = exports,
140
- tree = require('less/tree');
154
+ tree = require('./tree');
155
+ less.mode = 'node';
141
156
  } else {
157
+ // Browser
142
158
  if (typeof(window.less) === 'undefined') { window.less = {} }
143
159
  less = window.less,
144
160
  tree = window.less.tree = {};
161
+ less.mode = 'browser';
145
162
  }
146
163
  //
147
164
  // less.js - parser
@@ -197,7 +214,9 @@ less.Parser = function Parser(env) {
197
214
  paths: env && env.paths || [], // Search paths, when importing
198
215
  queue: [], // Files which haven't been imported yet
199
216
  files: {}, // Holds the imported parse trees
217
+ contents: {}, // Holds the imported file contents
200
218
  mime: env && env.mime, // MIME type of .less files
219
+ error: null, // Error in parsing/evaluating an import
201
220
  push: function (path, callback) {
202
221
  var that = this;
203
222
  this.queue.push(path);
@@ -205,11 +224,13 @@ less.Parser = function Parser(env) {
205
224
  //
206
225
  // Import a file asynchronously
207
226
  //
208
- less.Parser.importer(path, this.paths, function (root) {
227
+ less.Parser.importer(path, this.paths, function (e, root, contents) {
209
228
  that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue
210
229
  that.files[path] = root; // Store the root
230
+ that.contents[path] = contents;
211
231
 
212
- callback(root);
232
+ if (e && !that.error) { that.error = e }
233
+ callback(e, root);
213
234
 
214
235
  if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing
215
236
  }, env);
@@ -283,6 +304,20 @@ less.Parser = function Parser(env) {
283
304
  }
284
305
  }
285
306
 
307
+ function expect(arg, msg) {
308
+ var result = $(arg);
309
+ if (! result) {
310
+ error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'"
311
+ : "unexpected token"));
312
+ } else {
313
+ return result;
314
+ }
315
+ }
316
+
317
+ function error(msg, type) {
318
+ throw { index: i, type: type || 'Syntax', message: msg };
319
+ }
320
+
286
321
  // Same as $(), but don't change the state of the parser,
287
322
  // just return the match.
288
323
  function peek(tok) {
@@ -297,6 +332,54 @@ less.Parser = function Parser(env) {
297
332
  }
298
333
  }
299
334
 
335
+ function basename(pathname) {
336
+ if (less.mode === 'node') {
337
+ return require('path').basename(pathname);
338
+ } else {
339
+ return pathname.match(/[^\/]+$/)[0];
340
+ }
341
+ }
342
+
343
+ function getInput(e, env) {
344
+ if (e.filename && env.filename && (e.filename !== env.filename)) {
345
+ return parser.imports.contents[basename(e.filename)];
346
+ } else {
347
+ return input;
348
+ }
349
+ }
350
+
351
+ function getLocation(index, input) {
352
+ for (var n = index, column = -1;
353
+ n >= 0 && input.charAt(n) !== '\n';
354
+ n--) { column++ }
355
+
356
+ return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null,
357
+ column: column };
358
+ }
359
+
360
+ function LessError(e, env) {
361
+ var input = getInput(e, env),
362
+ loc = getLocation(e.index, input),
363
+ line = loc.line,
364
+ col = loc.column,
365
+ lines = input.split('\n');
366
+
367
+ this.type = e.type || 'Syntax';
368
+ this.message = e.message;
369
+ this.filename = e.filename || env.filename;
370
+ this.index = e.index;
371
+ this.line = typeof(line) === 'number' ? line + 1 : null;
372
+ this.callLine = e.call && (getLocation(e.call, input).line + 1);
373
+ this.callExtract = lines[getLocation(e.call, input).line];
374
+ this.stack = e.stack;
375
+ this.column = col;
376
+ this.extract = [
377
+ lines[line - 1],
378
+ lines[line],
379
+ lines[line + 1]
380
+ ];
381
+ }
382
+
300
383
  this.env = env = env || {};
301
384
 
302
385
  // The optimization level dictates the thoroughness of the parser,
@@ -321,19 +404,18 @@ less.Parser = function Parser(env) {
321
404
  var root, start, end, zone, line, lines, buff = [], c, error = null;
322
405
 
323
406
  i = j = current = furthest = 0;
324
- chunks = [];
325
407
  input = str.replace(/\r\n/g, '\n');
326
408
 
327
409
  // Split the input into chunks.
328
410
  chunks = (function (chunks) {
329
411
  var j = 0,
330
- skip = /[^"'`\{\}\/\(\)]+/g,
412
+ skip = /[^"'`\{\}\/\(\)\\]+/g,
331
413
  comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,
414
+ string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`\\\r\n]|\\.)*)`/g,
332
415
  level = 0,
333
416
  match,
334
417
  chunk = chunks[0],
335
- inParam,
336
- inString;
418
+ inParam;
337
419
 
338
420
  for (var i = 0, c, cc; i < input.length; i++) {
339
421
  skip.lastIndex = i;
@@ -344,9 +426,17 @@ less.Parser = function Parser(env) {
344
426
  }
345
427
  }
346
428
  c = input.charAt(i);
347
- comment.lastIndex = i;
429
+ comment.lastIndex = string.lastIndex = i;
430
+
431
+ if (match = string.exec(input)) {
432
+ if (match.index === i) {
433
+ i += match[0].length;
434
+ chunk.push(match[0]);
435
+ c = input.charAt(i);
436
+ }
437
+ }
348
438
 
349
- if (!inString && !inParam && c === '/') {
439
+ if (!inParam && c === '/') {
350
440
  cc = input.charAt(i + 1);
351
441
  if (cc === '/' || cc === '*') {
352
442
  if (match = comment.exec(input)) {
@@ -359,51 +449,46 @@ less.Parser = function Parser(env) {
359
449
  }
360
450
  }
361
451
 
362
- if (c === '{' && !inString && !inParam) { level ++;
363
- chunk.push(c);
364
- } else if (c === '}' && !inString && !inParam) { level --;
365
- chunk.push(c);
366
- chunks[++j] = chunk = [];
367
- } else if (c === '(' && !inString && !inParam) {
368
- chunk.push(c);
369
- inParam = true;
370
- } else if (c === ')' && !inString && inParam) {
371
- chunk.push(c);
372
- inParam = false;
373
- } else {
374
- if (c === '"' || c === "'" || c === '`') {
375
- if (! inString) {
376
- inString = c;
377
- } else {
378
- inString = inString === c ? false : inString;
379
- }
380
- }
381
- chunk.push(c);
452
+ switch (c) {
453
+ case '{': if (! inParam) { level ++; chunk.push(c); break }
454
+ case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break }
455
+ case '(': if (! inParam) { inParam = true; chunk.push(c); break }
456
+ case ')': if ( inParam) { inParam = false; chunk.push(c); break }
457
+ default: chunk.push(c);
382
458
  }
383
459
  }
384
460
  if (level > 0) {
385
- throw {
386
- type: 'Syntax',
387
- message: "Missing closing `}`",
461
+ error = new(LessError)({
462
+ index: i,
463
+ type: 'Parse',
464
+ message: "missing closing `}`",
388
465
  filename: env.filename
389
- };
466
+ }, env);
390
467
  }
391
468
 
392
469
  return chunks.map(function (c) { return c.join('') });;
393
470
  })([[]]);
394
471
 
472
+ if (error) {
473
+ return callback(error);
474
+ }
475
+
395
476
  // Start with the primary rule.
396
477
  // The whole syntax tree is held under a Ruleset node,
397
478
  // with the `root` property set to true, so no `{}` are
398
479
  // output. The callback is called when the input is parsed.
399
- root = new(tree.Ruleset)([], $(this.parsers.primary));
400
- root.root = true;
480
+ try {
481
+ root = new(tree.Ruleset)([], $(this.parsers.primary));
482
+ root.root = true;
483
+ } catch (e) {
484
+ return callback(new(LessError)(e, env));
485
+ }
401
486
 
402
487
  root.toCSS = (function (evaluate) {
403
488
  var line, lines, column;
404
489
 
405
490
  return function (options, variables) {
406
- var frames = [];
491
+ var frames = [], importError;
407
492
 
408
493
  options = options || {};
409
494
  //
@@ -438,39 +523,21 @@ less.Parser = function Parser(env) {
438
523
  var css = evaluate.call(this, { frames: frames })
439
524
  .toCSS([], { compress: options.compress || false });
440
525
  } catch (e) {
441
- lines = input.split('\n');
442
- line = getLine(e.index);
443
-
444
- for (var n = e.index, column = -1;
445
- n >= 0 && input.charAt(n) !== '\n';
446
- n--) { column++ }
447
-
448
- throw {
449
- type: e.type,
450
- message: e.message,
451
- filename: env.filename,
452
- index: e.index,
453
- line: typeof(line) === 'number' ? line + 1 : null,
454
- callLine: e.call && (getLine(e.call) + 1),
455
- callExtract: lines[getLine(e.call)],
456
- stack: e.stack,
457
- column: column,
458
- extract: [
459
- lines[line - 1],
460
- lines[line],
461
- lines[line + 1]
462
- ]
463
- };
526
+ throw new(LessError)(e, env);
464
527
  }
465
- if (options.compress) {
528
+
529
+ if ((importError = parser.imports.error)) { // Check if there was an error during importing
530
+ if (importError instanceof LessError) throw importError;
531
+ else throw new(LessError)(importError, env);
532
+ }
533
+
534
+ if (options.yuicompress && less.mode === 'node') {
535
+ return require('./cssmin').compressor.cssmin(css);
536
+ } else if (options.compress) {
466
537
  return css.replace(/(\s)+/g, "$1");
467
538
  } else {
468
539
  return css;
469
540
  }
470
-
471
- function getLine(index) {
472
- return index ? (input.slice(0, index).match(/\n/g) || "").length : null;
473
- }
474
541
  };
475
542
  })(root.eval);
476
543
 
@@ -490,7 +557,7 @@ less.Parser = function Parser(env) {
490
557
  for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ }
491
558
 
492
559
  error = {
493
- name: "ParseError",
560
+ type: "Parse",
494
561
  message: "Syntax Error on line " + line,
495
562
  index: i,
496
563
  filename: env.filename,
@@ -611,7 +678,15 @@ less.Parser = function Parser(env) {
611
678
  //
612
679
  keyword: function () {
613
680
  var k;
614
- if (k = $(/^[A-Za-z-]+/)) { return new(tree.Keyword)(k) }
681
+
682
+ if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) {
683
+ if (tree.colors.hasOwnProperty(k)) {
684
+ // detect named color
685
+ return new(tree.Color)(tree.colors[k].slice(1));
686
+ } else {
687
+ return new(tree.Keyword)(k);
688
+ }
689
+ }
615
690
  },
616
691
 
617
692
  //
@@ -627,7 +702,7 @@ less.Parser = function Parser(env) {
627
702
  call: function () {
628
703
  var name, args, index = i;
629
704
 
630
- if (! (name = /^([\w-]+|%)\(/.exec(chunks[j]))) return;
705
+ if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return;
631
706
 
632
707
  name = name[1].toLowerCase();
633
708
 
@@ -642,12 +717,12 @@ less.Parser = function Parser(env) {
642
717
 
643
718
  if (! $(')')) return;
644
719
 
645
- if (name) { return new(tree.Call)(name, args, index) }
720
+ if (name) { return new(tree.Call)(name, args, index, env.filename) }
646
721
  },
647
722
  arguments: function () {
648
723
  var args = [], arg;
649
724
 
650
- while (arg = $(this.expression)) {
725
+ while (arg = $(this.entities.assignment) || $(this.expression)) {
651
726
  args.push(arg);
652
727
  if (! $(',')) { break }
653
728
  }
@@ -659,6 +734,19 @@ less.Parser = function Parser(env) {
659
734
  $(this.entities.quoted);
660
735
  },
661
736
 
737
+ // Assignments are argument entities for calls.
738
+ // They are present in ie filter properties as shown below.
739
+ //
740
+ // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* )
741
+ //
742
+
743
+ assignment: function () {
744
+ var key, value;
745
+ if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) {
746
+ return new(tree.Assignment)(key, value);
747
+ }
748
+ },
749
+
662
750
  //
663
751
  // Parse url() tokens
664
752
  //
@@ -672,7 +760,8 @@ less.Parser = function Parser(env) {
672
760
  if (input.charAt(i) !== 'u' || !$(/^url\(/)) return;
673
761
  value = $(this.entities.quoted) || $(this.entities.variable) ||
674
762
  $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || "";
675
- if (! $(')')) throw new(Error)("missing closing ) for url()");
763
+
764
+ expect(')');
676
765
 
677
766
  return new(tree.URL)((value.value || value.data || value instanceof tree.Variable)
678
767
  ? value : new(tree.Anonymous)(value), imports.paths);
@@ -704,7 +793,7 @@ less.Parser = function Parser(env) {
704
793
  var name, index = i;
705
794
 
706
795
  if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) {
707
- return new(tree.Variable)(name, index);
796
+ return new(tree.Variable)(name, index, env.filename);
708
797
  }
709
798
  },
710
799
 
@@ -732,7 +821,7 @@ less.Parser = function Parser(env) {
732
821
  var value, c = input.charCodeAt(i);
733
822
  if ((c > 57 || c < 45) || c === 47) return;
734
823
 
735
- if (value = $(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) {
824
+ if (value = $(/^(-?\d*\.?\d+)(px|%|em|rem|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) {
736
825
  return new(tree.Dimension)(value[1], value[2]);
737
826
  }
738
827
  },
@@ -800,18 +889,22 @@ less.Parser = function Parser(env) {
800
889
  // selector for now.
801
890
  //
802
891
  call: function () {
803
- var elements = [], e, c, args, index = i, s = input.charAt(i);
892
+ var elements = [], e, c, args, index = i, s = input.charAt(i), important = false;
804
893
 
805
894
  if (s !== '.' && s !== '#') { return }
806
895
 
807
896
  while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) {
808
- elements.push(new(tree.Element)(c, e));
897
+ elements.push(new(tree.Element)(c, e, i));
809
898
  c = $('>');
810
899
  }
811
900
  $('(') && (args = $(this.entities.arguments)) && $(')');
812
901
 
902
+ if ($(this.important)) {
903
+ important = true;
904
+ }
905
+
813
906
  if (elements.length > 0 && ($(';') || peek('}'))) {
814
- return new(tree.mixin.Call)(elements, args, index);
907
+ return new(tree.mixin.Call)(elements, args || [], index, env.filename, important);
815
908
  }
816
909
  },
817
910
 
@@ -835,38 +928,53 @@ less.Parser = function Parser(env) {
835
928
  // the `{...}` block.
836
929
  //
837
930
  definition: function () {
838
- var name, params = [], match, ruleset, param, value;
839
-
931
+ var name, params = [], match, ruleset, param, value, cond, variadic = false;
840
932
  if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') ||
841
933
  peek(/^[^{]*(;|})/)) return;
842
934
 
935
+ save();
936
+
843
937
  if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) {
844
938
  name = match[1];
845
939
 
846
- while (param = $(this.entities.variable) || $(this.entities.literal)
847
- || $(this.entities.keyword)) {
848
- // Variable
849
- if (param instanceof tree.Variable) {
850
- if ($(':')) {
851
- if (value = $(this.expression)) {
940
+ do {
941
+ if (input.charAt(i) === '.' && $(/^\.{3}/)) {
942
+ variadic = true;
943
+ break;
944
+ } else if (param = $(this.entities.variable) || $(this.entities.literal)
945
+ || $(this.entities.keyword)) {
946
+ // Variable
947
+ if (param instanceof tree.Variable) {
948
+ if ($(':')) {
949
+ value = expect(this.expression, 'expected expression');
852
950
  params.push({ name: param.name, value: value });
951
+ } else if ($(/^\.{3}/)) {
952
+ params.push({ name: param.name, variadic: true });
953
+ variadic = true;
954
+ break;
853
955
  } else {
854
- throw new(Error)("Expected value");
956
+ params.push({ name: param.name });
855
957
  }
856
958
  } else {
857
- params.push({ name: param.name });
959
+ params.push({ value: param });
858
960
  }
859
961
  } else {
860
- params.push({ value: param });
962
+ break;
861
963
  }
862
- if (! $(',')) { break }
964
+ } while ($(','))
965
+
966
+ expect(')');
967
+
968
+ if ($(/^when/)) { // Guard
969
+ cond = expect(this.conditions, 'expected condition');
863
970
  }
864
- if (! $(')')) throw new(Error)("Expected )");
865
971
 
866
972
  ruleset = $(this.block);
867
973
 
868
974
  if (ruleset) {
869
- return new(tree.mixin.Definition)(name, params, ruleset);
975
+ return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic);
976
+ } else {
977
+ restore();
870
978
  }
871
979
  }
872
980
  }
@@ -901,7 +1009,7 @@ less.Parser = function Parser(env) {
901
1009
 
902
1010
  if (! $(/^\(opacity=/i)) return;
903
1011
  if (value = $(/^\d+/) || $(this.entities.variable)) {
904
- if (! $(')')) throw new(Error)("missing closing ) for alpha()");
1012
+ expect(')');
905
1013
  return new(tree.Alpha)(value);
906
1014
  }
907
1015
  },
@@ -919,12 +1027,21 @@ less.Parser = function Parser(env) {
919
1027
  // and an element name, such as a tag a class, or `*`.
920
1028
  //
921
1029
  element: function () {
922
- var e, t, c;
1030
+ var e, t, c, v;
923
1031
 
924
1032
  c = $(this.combinator);
925
- e = $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/);
1033
+ e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) ||
1034
+ $('*') || $(this.attribute) || $(/^\([^)@]+\)/);
1035
+
1036
+ if (! e) {
1037
+ $('(') && (v = $(this.entities.variable)) && $(')') && (e = new(tree.Paren)(v));
1038
+ }
1039
+
1040
+ if (e) { return new(tree.Element)(c, e, i) }
926
1041
 
927
- if (e) { return new(tree.Element)(c, e) }
1042
+ if (c.value && c.value.charAt(0) === '&') {
1043
+ return new(tree.Element)(c, null, i);
1044
+ }
928
1045
  },
929
1046
 
930
1047
  //
@@ -939,14 +1056,18 @@ less.Parser = function Parser(env) {
939
1056
  combinator: function () {
940
1057
  var match, c = input.charAt(i);
941
1058
 
942
- if (c === '>' || c === '&' || c === '+' || c === '~') {
1059
+ if (c === '>' || c === '+' || c === '~') {
943
1060
  i++;
944
1061
  while (input.charAt(i) === ' ') { i++ }
945
1062
  return new(tree.Combinator)(c);
946
- } else if (c === ':' && input.charAt(i + 1) === ':') {
947
- i += 2;
1063
+ } else if (c === '&') {
1064
+ match = '&';
1065
+ i++;
1066
+ if(input.charAt(i) === ' ') {
1067
+ match = '& ';
1068
+ }
948
1069
  while (input.charAt(i) === ' ') { i++ }
949
- return new(tree.Combinator)('::');
1070
+ return new(tree.Combinator)(match);
950
1071
  } else if (input.charAt(i - 1) === ' ') {
951
1072
  return new(tree.Combinator)(" ");
952
1073
  } else {
@@ -965,6 +1086,12 @@ less.Parser = function Parser(env) {
965
1086
  selector: function () {
966
1087
  var sel, e, elements = [], c, match;
967
1088
 
1089
+ if ($('(')) {
1090
+ sel = $(this.entity);
1091
+ expect(')');
1092
+ return new(tree.Selector)([new(tree.Element)('', sel, i)]);
1093
+ }
1094
+
968
1095
  while (e = $(this.element)) {
969
1096
  c = input.charAt(i);
970
1097
  elements.push(e)
@@ -1012,20 +1139,15 @@ less.Parser = function Parser(env) {
1012
1139
  var selectors = [], s, rules, match;
1013
1140
  save();
1014
1141
 
1015
- if (match = /^([.#: \w-]+)[\s\n]*\{/.exec(chunks[j])) {
1016
- i += match[0].length - 1;
1017
- selectors = [new(tree.Selector)([new(tree.Element)(null, match[1])])];
1018
- } else {
1019
- while (s = $(this.selector)) {
1020
- selectors.push(s);
1021
- $(this.comment);
1022
- if (! $(',')) { break }
1023
- $(this.comment);
1024
- }
1142
+ while (s = $(this.selector)) {
1143
+ selectors.push(s);
1144
+ $(this.comment);
1145
+ if (! $(',')) { break }
1146
+ $(this.comment);
1025
1147
  }
1026
1148
 
1027
1149
  if (selectors.length > 0 && (rules = $(this.block))) {
1028
- return new(tree.Ruleset)(selectors, rules);
1150
+ return new(tree.Ruleset)(selectors, rules, env.strictImports);
1029
1151
  } else {
1030
1152
  // Backtrack
1031
1153
  furthest = i;
@@ -1069,11 +1191,67 @@ less.Parser = function Parser(env) {
1069
1191
  // stored in `import`, which we pass to the Import constructor.
1070
1192
  //
1071
1193
  "import": function () {
1072
- var path;
1194
+ var path, features, index = i;
1073
1195
  if ($(/^@import\s+/) &&
1074
- (path = $(this.entities.quoted) || $(this.entities.url)) &&
1075
- $(';')) {
1076
- return new(tree.Import)(path, imports);
1196
+ (path = $(this.entities.quoted) || $(this.entities.url))) {
1197
+ features = $(this.mediaFeatures);
1198
+ if ($(';')) {
1199
+ return new(tree.Import)(path, imports, features, index);
1200
+ }
1201
+ }
1202
+ },
1203
+
1204
+ mediaFeature: function () {
1205
+ var e, p, nodes = [];
1206
+
1207
+ do {
1208
+ if (e = $(this.entities.keyword)) {
1209
+ nodes.push(e);
1210
+ } else if ($('(')) {
1211
+ p = $(this.property);
1212
+ e = $(this.entity);
1213
+ if ($(')')) {
1214
+ if (p && e) {
1215
+ nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true)));
1216
+ } else if (e) {
1217
+ nodes.push(new(tree.Paren)(e));
1218
+ } else {
1219
+ return null;
1220
+ }
1221
+ } else { return null }
1222
+ }
1223
+ } while (e);
1224
+
1225
+ if (nodes.length > 0) {
1226
+ return new(tree.Expression)(nodes);
1227
+ }
1228
+ },
1229
+
1230
+ mediaFeatures: function () {
1231
+ var e, features = [];
1232
+
1233
+ do {
1234
+ if (e = $(this.mediaFeature)) {
1235
+ features.push(e);
1236
+ if (! $(',')) { break }
1237
+ } else if (e = $(this.entities.variable)) {
1238
+ features.push(e);
1239
+ if (! $(',')) { break }
1240
+ }
1241
+ } while (e);
1242
+
1243
+ return features.length > 0 ? features : null;
1244
+ },
1245
+
1246
+ media: function () {
1247
+ var features, rules;
1248
+
1249
+ if ($(/^@media/)) {
1250
+ features = $(this.mediaFeatures);
1251
+
1252
+ if (rules = $(this.block)) {
1253
+ return new(tree.Media)(rules, features);
1254
+ }
1077
1255
  }
1078
1256
  },
1079
1257
 
@@ -1083,13 +1261,13 @@ less.Parser = function Parser(env) {
1083
1261
  // @charset "utf-8";
1084
1262
  //
1085
1263
  directive: function () {
1086
- var name, value, rules, types;
1264
+ var name, value, rules, types, e, nodes;
1087
1265
 
1088
1266
  if (input.charAt(i) !== '@') return;
1089
1267
 
1090
- if (value = $(this['import'])) {
1268
+ if (value = $(this['import']) || $(this.media)) {
1091
1269
  return value;
1092
- } else if (name = $(/^@media|@page|@-[-a-z]+/)) {
1270
+ } else if (name = $(/^@page|@keyframes/) || $(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/)) {
1093
1271
  types = ($(/^[^{]+/) || '').trim();
1094
1272
  if (rules = $(this.block)) {
1095
1273
  return new(tree.Directive)(name + " " + types, rules);
@@ -1156,7 +1334,7 @@ less.Parser = function Parser(env) {
1156
1334
  multiplication: function () {
1157
1335
  var m, a, op, operation;
1158
1336
  if (m = $(this.operand)) {
1159
- while ((op = ($('/') || $('*'))) && (a = $(this.operand))) {
1337
+ while (!peek(/^\/\*/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) {
1160
1338
  operation = new(tree.Operation)(op, [operation || m, a]);
1161
1339
  }
1162
1340
  return operation || m;
@@ -1172,6 +1350,35 @@ less.Parser = function Parser(env) {
1172
1350
  return operation || m;
1173
1351
  }
1174
1352
  },
1353
+ conditions: function () {
1354
+ var a, b, index = i, condition;
1355
+
1356
+ if (a = $(this.condition)) {
1357
+ while ($(',') && (b = $(this.condition))) {
1358
+ condition = new(tree.Condition)('or', condition || a, b, index);
1359
+ }
1360
+ return condition || a;
1361
+ }
1362
+ },
1363
+ condition: function () {
1364
+ var a, b, c, op, index = i, negate = false;
1365
+
1366
+ if ($(/^not/)) { negate = true }
1367
+ expect('(');
1368
+ if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
1369
+ if (op = $(/^(?:>=|=<|[<=>])/)) {
1370
+ if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
1371
+ c = new(tree.Condition)(op, a, b, index, negate);
1372
+ } else {
1373
+ error('expected expression');
1374
+ }
1375
+ } else {
1376
+ c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate);
1377
+ }
1378
+ expect(')');
1379
+ return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c;
1380
+ }
1381
+ },
1175
1382
 
1176
1383
  //
1177
1384
  // An operand is anything that can be part of an operation,
@@ -1216,106 +1423,510 @@ less.Parser = function Parser(env) {
1216
1423
  };
1217
1424
  };
1218
1425
 
1219
- if (typeof(window) !== 'undefined') {
1426
+ if (less.mode === 'browser' || less.mode === 'rhino') {
1220
1427
  //
1221
1428
  // Used by `@import` directives
1222
1429
  //
1223
1430
  less.Parser.importer = function (path, paths, callback, env) {
1224
- if (path.charAt(0) !== '/' && paths.length > 0) {
1431
+ if (!/^([a-z]+:)?\//.test(path) && paths.length > 0) {
1225
1432
  path = paths[0] + path;
1226
1433
  }
1227
1434
  // We pass `true` as 3rd argument, to force the reload of the import.
1228
1435
  // This is so we can get the syntax tree as opposed to just the CSS output,
1229
1436
  // as we need this to evaluate the current stylesheet.
1230
- loadStyleSheet({ href: path, title: path, type: env.mime }, callback, true);
1437
+ loadStyleSheet({ href: path, title: path, type: env.mime }, function (e) {
1438
+ if (e && typeof(env.errback) === "function") {
1439
+ env.errback.call(null, path, paths, callback, env);
1440
+ } else {
1441
+ callback.apply(null, arguments);
1442
+ }
1443
+ }, true);
1231
1444
  };
1232
1445
  }
1233
1446
 
1234
1447
  (function (tree) {
1235
1448
 
1236
- tree.Alpha = function (val) {
1237
- this.value = val;
1238
- };
1239
- tree.Alpha.prototype = {
1240
- toCSS: function () {
1241
- return "alpha(opacity=" +
1242
- (this.value.toCSS ? this.value.toCSS() : this.value) + ")";
1449
+ tree.functions = {
1450
+ rgb: function (r, g, b) {
1451
+ return this.rgba(r, g, b, 1.0);
1243
1452
  },
1244
- eval: function (env) {
1245
- if (this.value.eval) { this.value = this.value.eval(env) }
1246
- return this;
1247
- }
1248
- };
1453
+ rgba: function (r, g, b, a) {
1454
+ var rgb = [r, g, b].map(function (c) { return number(c) }),
1455
+ a = number(a);
1456
+ return new(tree.Color)(rgb, a);
1457
+ },
1458
+ hsl: function (h, s, l) {
1459
+ return this.hsla(h, s, l, 1.0);
1460
+ },
1461
+ hsla: function (h, s, l, a) {
1462
+ h = (number(h) % 360) / 360;
1463
+ s = number(s); l = number(l); a = number(a);
1249
1464
 
1250
- })(require('less/tree'));
1251
- (function (tree) {
1465
+ var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
1466
+ var m1 = l * 2 - m2;
1252
1467
 
1253
- tree.Anonymous = function (string) {
1254
- this.value = string.value || string;
1255
- };
1256
- tree.Anonymous.prototype = {
1257
- toCSS: function () {
1258
- return this.value;
1468
+ return this.rgba(hue(h + 1/3) * 255,
1469
+ hue(h) * 255,
1470
+ hue(h - 1/3) * 255,
1471
+ a);
1472
+
1473
+ function hue(h) {
1474
+ h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
1475
+ if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
1476
+ else if (h * 2 < 1) return m2;
1477
+ else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6;
1478
+ else return m1;
1479
+ }
1259
1480
  },
1260
- eval: function () { return this }
1261
- };
1481
+ hue: function (color) {
1482
+ return new(tree.Dimension)(Math.round(color.toHSL().h));
1483
+ },
1484
+ saturation: function (color) {
1485
+ return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%');
1486
+ },
1487
+ lightness: function (color) {
1488
+ return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%');
1489
+ },
1490
+ alpha: function (color) {
1491
+ return new(tree.Dimension)(color.toHSL().a);
1492
+ },
1493
+ saturate: function (color, amount) {
1494
+ var hsl = color.toHSL();
1262
1495
 
1263
- })(require('less/tree'));
1264
- (function (tree) {
1496
+ hsl.s += amount.value / 100;
1497
+ hsl.s = clamp(hsl.s);
1498
+ return hsla(hsl);
1499
+ },
1500
+ desaturate: function (color, amount) {
1501
+ var hsl = color.toHSL();
1265
1502
 
1266
- //
1267
- // A function call node.
1268
- //
1269
- tree.Call = function (name, args, index) {
1270
- this.name = name;
1271
- this.args = args;
1272
- this.index = index;
1273
- };
1274
- tree.Call.prototype = {
1275
- //
1276
- // When evaluating a function call,
1277
- // we either find the function in `tree.functions` [1],
1278
- // in which case we call it, passing the evaluated arguments,
1279
- // or we simply print it out as it appeared originally [2].
1280
- //
1281
- // The *functions.js* file contains the built-in functions.
1282
- //
1283
- // The reason why we evaluate the arguments, is in the case where
1284
- // we try to pass a variable to a function, like: `saturate(@color)`.
1285
- // The function should receive the value, not the variable.
1286
- //
1287
- eval: function (env) {
1288
- var args = this.args.map(function (a) { return a.eval(env) });
1503
+ hsl.s -= amount.value / 100;
1504
+ hsl.s = clamp(hsl.s);
1505
+ return hsla(hsl);
1506
+ },
1507
+ lighten: function (color, amount) {
1508
+ var hsl = color.toHSL();
1289
1509
 
1290
- if (this.name in tree.functions) { // 1.
1291
- try {
1292
- return tree.functions[this.name].apply(tree.functions, args);
1293
- } catch (e) {
1294
- throw { message: "error evaluating function `" + this.name + "`",
1295
- index: this.index };
1296
- }
1297
- } else { // 2.
1298
- return new(tree.Anonymous)(this.name +
1299
- "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")");
1300
- }
1510
+ hsl.l += amount.value / 100;
1511
+ hsl.l = clamp(hsl.l);
1512
+ return hsla(hsl);
1301
1513
  },
1514
+ darken: function (color, amount) {
1515
+ var hsl = color.toHSL();
1302
1516
 
1303
- toCSS: function (env) {
1304
- return this.eval(env).toCSS();
1305
- }
1306
- };
1517
+ hsl.l -= amount.value / 100;
1518
+ hsl.l = clamp(hsl.l);
1519
+ return hsla(hsl);
1520
+ },
1521
+ fadein: function (color, amount) {
1522
+ var hsl = color.toHSL();
1307
1523
 
1308
- })(require('less/tree'));
1309
- (function (tree) {
1310
- //
1311
- // RGB Colors - #ff0014, #eee
1312
- //
1313
- tree.Color = function (rgb, a) {
1524
+ hsl.a += amount.value / 100;
1525
+ hsl.a = clamp(hsl.a);
1526
+ return hsla(hsl);
1527
+ },
1528
+ fadeout: function (color, amount) {
1529
+ var hsl = color.toHSL();
1530
+
1531
+ hsl.a -= amount.value / 100;
1532
+ hsl.a = clamp(hsl.a);
1533
+ return hsla(hsl);
1534
+ },
1535
+ fade: function (color, amount) {
1536
+ var hsl = color.toHSL();
1537
+
1538
+ hsl.a = amount.value / 100;
1539
+ hsl.a = clamp(hsl.a);
1540
+ return hsla(hsl);
1541
+ },
1542
+ spin: function (color, amount) {
1543
+ var hsl = color.toHSL();
1544
+ var hue = (hsl.h + amount.value) % 360;
1545
+
1546
+ hsl.h = hue < 0 ? 360 + hue : hue;
1547
+
1548
+ return hsla(hsl);
1549
+ },
1314
1550
  //
1315
- // The end goal here, is to parse the arguments
1316
- // into an integer triplet, such as `128, 255, 0`
1551
+ // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
1552
+ // http://sass-lang.com
1317
1553
  //
1318
- // This facilitates operations and conversions.
1554
+ mix: function (color1, color2, weight) {
1555
+ var p = weight.value / 100.0;
1556
+ var w = p * 2 - 1;
1557
+ var a = color1.toHSL().a - color2.toHSL().a;
1558
+
1559
+ var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
1560
+ var w2 = 1 - w1;
1561
+
1562
+ var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,
1563
+ color1.rgb[1] * w1 + color2.rgb[1] * w2,
1564
+ color1.rgb[2] * w1 + color2.rgb[2] * w2];
1565
+
1566
+ var alpha = color1.alpha * p + color2.alpha * (1 - p);
1567
+
1568
+ return new(tree.Color)(rgb, alpha);
1569
+ },
1570
+ greyscale: function (color) {
1571
+ return this.desaturate(color, new(tree.Dimension)(100));
1572
+ },
1573
+ e: function (str) {
1574
+ return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str);
1575
+ },
1576
+ escape: function (str) {
1577
+ 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"));
1578
+ },
1579
+ '%': function (quoted /* arg, arg, ...*/) {
1580
+ var args = Array.prototype.slice.call(arguments, 1),
1581
+ str = quoted.value;
1582
+
1583
+ for (var i = 0; i < args.length; i++) {
1584
+ str = str.replace(/%[sda]/i, function(token) {
1585
+ var value = token.match(/s/i) ? args[i].value : args[i].toCSS();
1586
+ return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
1587
+ });
1588
+ }
1589
+ str = str.replace(/%%/g, '%');
1590
+ return new(tree.Quoted)('"' + str + '"', str);
1591
+ },
1592
+ round: function (n) {
1593
+ return this._math('round', n);
1594
+ },
1595
+ ceil: function (n) {
1596
+ return this._math('ceil', n);
1597
+ },
1598
+ floor: function (n) {
1599
+ return this._math('floor', n);
1600
+ },
1601
+ _math: function (fn, n) {
1602
+ if (n instanceof tree.Dimension) {
1603
+ return new(tree.Dimension)(Math[fn](number(n)), n.unit);
1604
+ } else if (typeof(n) === 'number') {
1605
+ return Math[fn](n);
1606
+ } else {
1607
+ throw { type: "Argument", message: "argument must be a number" };
1608
+ }
1609
+ },
1610
+ argb: function (color) {
1611
+ return new(tree.Anonymous)(color.toARGB());
1612
+
1613
+ },
1614
+ percentage: function (n) {
1615
+ return new(tree.Dimension)(n.value * 100, '%');
1616
+ },
1617
+ color: function (n) {
1618
+ if (n instanceof tree.Quoted) {
1619
+ return new(tree.Color)(n.value.slice(1));
1620
+ } else {
1621
+ throw { type: "Argument", message: "argument must be a string" };
1622
+ }
1623
+ },
1624
+ iscolor: function (n) {
1625
+ return this._isa(n, tree.Color);
1626
+ },
1627
+ isnumber: function (n) {
1628
+ return this._isa(n, tree.Dimension);
1629
+ },
1630
+ isstring: function (n) {
1631
+ return this._isa(n, tree.Quoted);
1632
+ },
1633
+ iskeyword: function (n) {
1634
+ return this._isa(n, tree.Keyword);
1635
+ },
1636
+ isurl: function (n) {
1637
+ return this._isa(n, tree.URL);
1638
+ },
1639
+ ispixel: function (n) {
1640
+ return (n instanceof tree.Dimension) && n.unit === 'px' ? tree.True : tree.False;
1641
+ },
1642
+ ispercentage: function (n) {
1643
+ return (n instanceof tree.Dimension) && n.unit === '%' ? tree.True : tree.False;
1644
+ },
1645
+ isem: function (n) {
1646
+ return (n instanceof tree.Dimension) && n.unit === 'em' ? tree.True : tree.False;
1647
+ },
1648
+ _isa: function (n, Type) {
1649
+ return (n instanceof Type) ? tree.True : tree.False;
1650
+ }
1651
+ };
1652
+
1653
+ function hsla(hsla) {
1654
+ return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a);
1655
+ }
1656
+
1657
+ function number(n) {
1658
+ if (n instanceof tree.Dimension) {
1659
+ return parseFloat(n.unit == '%' ? n.value / 100 : n.value);
1660
+ } else if (typeof(n) === 'number') {
1661
+ return n;
1662
+ } else {
1663
+ throw {
1664
+ error: "RuntimeError",
1665
+ message: "color functions take numbers as parameters"
1666
+ };
1667
+ }
1668
+ }
1669
+
1670
+ function clamp(val) {
1671
+ return Math.min(1, Math.max(0, val));
1672
+ }
1673
+
1674
+ })(require('./tree'));
1675
+ (function (tree) {
1676
+ tree.colors = {
1677
+ 'aliceblue':'#f0f8ff',
1678
+ 'antiquewhite':'#faebd7',
1679
+ 'aqua':'#00ffff',
1680
+ 'aquamarine':'#7fffd4',
1681
+ 'azure':'#f0ffff',
1682
+ 'beige':'#f5f5dc',
1683
+ 'bisque':'#ffe4c4',
1684
+ 'black':'#000000',
1685
+ 'blanchedalmond':'#ffebcd',
1686
+ 'blue':'#0000ff',
1687
+ 'blueviolet':'#8a2be2',
1688
+ 'brown':'#a52a2a',
1689
+ 'burlywood':'#deb887',
1690
+ 'cadetblue':'#5f9ea0',
1691
+ 'chartreuse':'#7fff00',
1692
+ 'chocolate':'#d2691e',
1693
+ 'coral':'#ff7f50',
1694
+ 'cornflowerblue':'#6495ed',
1695
+ 'cornsilk':'#fff8dc',
1696
+ 'crimson':'#dc143c',
1697
+ 'cyan':'#00ffff',
1698
+ 'darkblue':'#00008b',
1699
+ 'darkcyan':'#008b8b',
1700
+ 'darkgoldenrod':'#b8860b',
1701
+ 'darkgray':'#a9a9a9',
1702
+ 'darkgrey':'#a9a9a9',
1703
+ 'darkgreen':'#006400',
1704
+ 'darkkhaki':'#bdb76b',
1705
+ 'darkmagenta':'#8b008b',
1706
+ 'darkolivegreen':'#556b2f',
1707
+ 'darkorange':'#ff8c00',
1708
+ 'darkorchid':'#9932cc',
1709
+ 'darkred':'#8b0000',
1710
+ 'darksalmon':'#e9967a',
1711
+ 'darkseagreen':'#8fbc8f',
1712
+ 'darkslateblue':'#483d8b',
1713
+ 'darkslategray':'#2f4f4f',
1714
+ 'darkslategrey':'#2f4f4f',
1715
+ 'darkturquoise':'#00ced1',
1716
+ 'darkviolet':'#9400d3',
1717
+ 'deeppink':'#ff1493',
1718
+ 'deepskyblue':'#00bfff',
1719
+ 'dimgray':'#696969',
1720
+ 'dimgrey':'#696969',
1721
+ 'dodgerblue':'#1e90ff',
1722
+ 'firebrick':'#b22222',
1723
+ 'floralwhite':'#fffaf0',
1724
+ 'forestgreen':'#228b22',
1725
+ 'fuchsia':'#ff00ff',
1726
+ 'gainsboro':'#dcdcdc',
1727
+ 'ghostwhite':'#f8f8ff',
1728
+ 'gold':'#ffd700',
1729
+ 'goldenrod':'#daa520',
1730
+ 'gray':'#808080',
1731
+ 'grey':'#808080',
1732
+ 'green':'#008000',
1733
+ 'greenyellow':'#adff2f',
1734
+ 'honeydew':'#f0fff0',
1735
+ 'hotpink':'#ff69b4',
1736
+ 'indianred':'#cd5c5c',
1737
+ 'indigo':'#4b0082',
1738
+ 'ivory':'#fffff0',
1739
+ 'khaki':'#f0e68c',
1740
+ 'lavender':'#e6e6fa',
1741
+ 'lavenderblush':'#fff0f5',
1742
+ 'lawngreen':'#7cfc00',
1743
+ 'lemonchiffon':'#fffacd',
1744
+ 'lightblue':'#add8e6',
1745
+ 'lightcoral':'#f08080',
1746
+ 'lightcyan':'#e0ffff',
1747
+ 'lightgoldenrodyellow':'#fafad2',
1748
+ 'lightgray':'#d3d3d3',
1749
+ 'lightgrey':'#d3d3d3',
1750
+ 'lightgreen':'#90ee90',
1751
+ 'lightpink':'#ffb6c1',
1752
+ 'lightsalmon':'#ffa07a',
1753
+ 'lightseagreen':'#20b2aa',
1754
+ 'lightskyblue':'#87cefa',
1755
+ 'lightslategray':'#778899',
1756
+ 'lightslategrey':'#778899',
1757
+ 'lightsteelblue':'#b0c4de',
1758
+ 'lightyellow':'#ffffe0',
1759
+ 'lime':'#00ff00',
1760
+ 'limegreen':'#32cd32',
1761
+ 'linen':'#faf0e6',
1762
+ 'magenta':'#ff00ff',
1763
+ 'maroon':'#800000',
1764
+ 'mediumaquamarine':'#66cdaa',
1765
+ 'mediumblue':'#0000cd',
1766
+ 'mediumorchid':'#ba55d3',
1767
+ 'mediumpurple':'#9370d8',
1768
+ 'mediumseagreen':'#3cb371',
1769
+ 'mediumslateblue':'#7b68ee',
1770
+ 'mediumspringgreen':'#00fa9a',
1771
+ 'mediumturquoise':'#48d1cc',
1772
+ 'mediumvioletred':'#c71585',
1773
+ 'midnightblue':'#191970',
1774
+ 'mintcream':'#f5fffa',
1775
+ 'mistyrose':'#ffe4e1',
1776
+ 'moccasin':'#ffe4b5',
1777
+ 'navajowhite':'#ffdead',
1778
+ 'navy':'#000080',
1779
+ 'oldlace':'#fdf5e6',
1780
+ 'olive':'#808000',
1781
+ 'olivedrab':'#6b8e23',
1782
+ 'orange':'#ffa500',
1783
+ 'orangered':'#ff4500',
1784
+ 'orchid':'#da70d6',
1785
+ 'palegoldenrod':'#eee8aa',
1786
+ 'palegreen':'#98fb98',
1787
+ 'paleturquoise':'#afeeee',
1788
+ 'palevioletred':'#d87093',
1789
+ 'papayawhip':'#ffefd5',
1790
+ 'peachpuff':'#ffdab9',
1791
+ 'peru':'#cd853f',
1792
+ 'pink':'#ffc0cb',
1793
+ 'plum':'#dda0dd',
1794
+ 'powderblue':'#b0e0e6',
1795
+ 'purple':'#800080',
1796
+ 'red':'#ff0000',
1797
+ 'rosybrown':'#bc8f8f',
1798
+ 'royalblue':'#4169e1',
1799
+ 'saddlebrown':'#8b4513',
1800
+ 'salmon':'#fa8072',
1801
+ 'sandybrown':'#f4a460',
1802
+ 'seagreen':'#2e8b57',
1803
+ 'seashell':'#fff5ee',
1804
+ 'sienna':'#a0522d',
1805
+ 'silver':'#c0c0c0',
1806
+ 'skyblue':'#87ceeb',
1807
+ 'slateblue':'#6a5acd',
1808
+ 'slategray':'#708090',
1809
+ 'slategrey':'#708090',
1810
+ 'snow':'#fffafa',
1811
+ 'springgreen':'#00ff7f',
1812
+ 'steelblue':'#4682b4',
1813
+ 'tan':'#d2b48c',
1814
+ 'teal':'#008080',
1815
+ 'thistle':'#d8bfd8',
1816
+ 'tomato':'#ff6347',
1817
+ 'turquoise':'#40e0d0',
1818
+ 'violet':'#ee82ee',
1819
+ 'wheat':'#f5deb3',
1820
+ 'white':'#ffffff',
1821
+ 'whitesmoke':'#f5f5f5',
1822
+ 'yellow':'#ffff00',
1823
+ 'yellowgreen':'#9acd32'
1824
+ };
1825
+ })(require('./tree'));
1826
+ (function (tree) {
1827
+
1828
+ tree.Alpha = function (val) {
1829
+ this.value = val;
1830
+ };
1831
+ tree.Alpha.prototype = {
1832
+ toCSS: function () {
1833
+ return "alpha(opacity=" +
1834
+ (this.value.toCSS ? this.value.toCSS() : this.value) + ")";
1835
+ },
1836
+ eval: function (env) {
1837
+ if (this.value.eval) { this.value = this.value.eval(env) }
1838
+ return this;
1839
+ }
1840
+ };
1841
+
1842
+ })(require('../tree'));
1843
+ (function (tree) {
1844
+
1845
+ tree.Anonymous = function (string) {
1846
+ this.value = string.value || string;
1847
+ };
1848
+ tree.Anonymous.prototype = {
1849
+ toCSS: function () {
1850
+ return this.value;
1851
+ },
1852
+ eval: function () { return this }
1853
+ };
1854
+
1855
+ })(require('../tree'));
1856
+ (function (tree) {
1857
+
1858
+ tree.Assignment = function (key, val) {
1859
+ this.key = key;
1860
+ this.value = val;
1861
+ };
1862
+ tree.Assignment.prototype = {
1863
+ toCSS: function () {
1864
+ return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value);
1865
+ },
1866
+ eval: function (env) {
1867
+ if (this.value.eval) { this.value = this.value.eval(env) }
1868
+ return this;
1869
+ }
1870
+ };
1871
+
1872
+ })(require('../tree'));(function (tree) {
1873
+
1874
+ //
1875
+ // A function call node.
1876
+ //
1877
+ tree.Call = function (name, args, index, filename) {
1878
+ this.name = name;
1879
+ this.args = args;
1880
+ this.index = index;
1881
+ this.filename = filename;
1882
+ };
1883
+ tree.Call.prototype = {
1884
+ //
1885
+ // When evaluating a function call,
1886
+ // we either find the function in `tree.functions` [1],
1887
+ // in which case we call it, passing the evaluated arguments,
1888
+ // or we simply print it out as it appeared originally [2].
1889
+ //
1890
+ // The *functions.js* file contains the built-in functions.
1891
+ //
1892
+ // The reason why we evaluate the arguments, is in the case where
1893
+ // we try to pass a variable to a function, like: `saturate(@color)`.
1894
+ // The function should receive the value, not the variable.
1895
+ //
1896
+ eval: function (env) {
1897
+ var args = this.args.map(function (a) { return a.eval(env) });
1898
+
1899
+ if (this.name in tree.functions) { // 1.
1900
+ try {
1901
+ return tree.functions[this.name].apply(tree.functions, args);
1902
+ } catch (e) {
1903
+ throw { type: e.type || "Runtime",
1904
+ message: "error evaluating function `" + this.name + "`" +
1905
+ (e.message ? ': ' + e.message : ''),
1906
+ index: this.index, filename: this.filename };
1907
+ }
1908
+ } else { // 2.
1909
+ return new(tree.Anonymous)(this.name +
1910
+ "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")");
1911
+ }
1912
+ },
1913
+
1914
+ toCSS: function (env) {
1915
+ return this.eval(env).toCSS();
1916
+ }
1917
+ };
1918
+
1919
+ })(require('../tree'));
1920
+ (function (tree) {
1921
+ //
1922
+ // RGB Colors - #ff0014, #eee
1923
+ //
1924
+ tree.Color = function (rgb, a) {
1925
+ //
1926
+ // The end goal here, is to parse the arguments
1927
+ // into an integer triplet, such as `128, 255, 0`
1928
+ //
1929
+ // This facilitates operations and conversions.
1319
1930
  //
1320
1931
  if (Array.isArray(rgb)) {
1321
1932
  this.rgb = rgb;
@@ -1323,11 +1934,6 @@ tree.Color = function (rgb, a) {
1323
1934
  this.rgb = rgb.match(/.{2}/g).map(function (c) {
1324
1935
  return parseInt(c, 16);
1325
1936
  });
1326
- } else if (rgb.length == 8) {
1327
- this.alpha = parseInt(rgb.substring(0,2), 16) / 255.0;
1328
- this.rgb = rgb.substr(2).match(/.{2}/g).map(function (c) {
1329
- return parseInt(c, 16);
1330
- });
1331
1937
  } else {
1332
1938
  this.rgb = rgb.split('').map(function (c) {
1333
1939
  return parseInt(c + c, 16);
@@ -1399,11 +2005,19 @@ tree.Color.prototype = {
1399
2005
  h /= 6;
1400
2006
  }
1401
2007
  return { h: h * 360, s: s, l: l, a: a };
2008
+ },
2009
+ toARGB: function () {
2010
+ var argb = [Math.round(this.alpha * 255)].concat(this.rgb);
2011
+ return '#' + argb.map(function (i) {
2012
+ i = Math.round(i);
2013
+ i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
2014
+ return i.length === 1 ? '0' + i : i;
2015
+ }).join('');
1402
2016
  }
1403
2017
  };
1404
2018
 
1405
2019
 
1406
- })(require('less/tree'));
2020
+ })(require('../tree'));
1407
2021
  (function (tree) {
1408
2022
 
1409
2023
  tree.Comment = function (value, silent) {
@@ -1417,7 +2031,49 @@ tree.Comment.prototype = {
1417
2031
  eval: function () { return this }
1418
2032
  };
1419
2033
 
1420
- })(require('less/tree'));
2034
+ })(require('../tree'));
2035
+ (function (tree) {
2036
+
2037
+ tree.Condition = function (op, l, r, i, negate) {
2038
+ this.op = op.trim();
2039
+ this.lvalue = l;
2040
+ this.rvalue = r;
2041
+ this.index = i;
2042
+ this.negate = negate;
2043
+ };
2044
+ tree.Condition.prototype.eval = function (env) {
2045
+ var a = this.lvalue.eval(env),
2046
+ b = this.rvalue.eval(env);
2047
+
2048
+ var i = this.index, result;
2049
+
2050
+ var result = (function (op) {
2051
+ switch (op) {
2052
+ case 'and':
2053
+ return a && b;
2054
+ case 'or':
2055
+ return a || b;
2056
+ default:
2057
+ if (a.compare) {
2058
+ result = a.compare(b);
2059
+ } else if (b.compare) {
2060
+ result = b.compare(a);
2061
+ } else {
2062
+ throw { type: "Type",
2063
+ message: "Unable to perform comparison",
2064
+ index: i };
2065
+ }
2066
+ switch (result) {
2067
+ case -1: return op === '<' || op === '=<';
2068
+ case 0: return op === '=' || op === '>=' || op === '=<';
2069
+ case 1: return op === '>' || op === '>=';
2070
+ }
2071
+ }
2072
+ })(this.op);
2073
+ return this.negate ? !result : result;
2074
+ };
2075
+
2076
+ })(require('../tree'));
1421
2077
  (function (tree) {
1422
2078
 
1423
2079
  //
@@ -1448,16 +2104,33 @@ tree.Dimension.prototype = {
1448
2104
  return new(tree.Dimension)
1449
2105
  (tree.operate(op, this.value, other.value),
1450
2106
  this.unit || other.unit);
2107
+ },
2108
+
2109
+ // TODO: Perform unit conversion before comparing
2110
+ compare: function (other) {
2111
+ if (other instanceof tree.Dimension) {
2112
+ if (other.value > this.value) {
2113
+ return -1;
2114
+ } else if (other.value < this.value) {
2115
+ return 1;
2116
+ } else {
2117
+ return 0;
2118
+ }
2119
+ } else {
2120
+ return -1;
2121
+ }
1451
2122
  }
1452
2123
  };
1453
2124
 
1454
- })(require('less/tree'));
2125
+ })(require('../tree'));
1455
2126
  (function (tree) {
1456
2127
 
1457
- tree.Directive = function (name, value) {
2128
+ tree.Directive = function (name, value, features) {
1458
2129
  this.name = name;
2130
+
1459
2131
  if (Array.isArray(value)) {
1460
2132
  this.ruleset = new(tree.Ruleset)([], value);
2133
+ this.ruleset.allowImports = true;
1461
2134
  } else {
1462
2135
  this.value = value;
1463
2136
  }
@@ -1484,21 +2157,36 @@ tree.Directive.prototype = {
1484
2157
  rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }
1485
2158
  };
1486
2159
 
1487
- })(require('less/tree'));
2160
+ })(require('../tree'));
1488
2161
  (function (tree) {
1489
2162
 
1490
- tree.Element = function (combinator, value) {
2163
+ tree.Element = function (combinator, value, index) {
1491
2164
  this.combinator = combinator instanceof tree.Combinator ?
1492
2165
  combinator : new(tree.Combinator)(combinator);
1493
- this.value = value.trim();
2166
+
2167
+ if (typeof(value) === 'string') {
2168
+ this.value = value.trim();
2169
+ } else if (value) {
2170
+ this.value = value;
2171
+ } else {
2172
+ this.value = "";
2173
+ }
2174
+ this.index = index;
2175
+ };
2176
+ tree.Element.prototype.eval = function (env) {
2177
+ return new(tree.Element)(this.combinator,
2178
+ this.value.eval ? this.value.eval(env) : this.value,
2179
+ this.index);
1494
2180
  };
1495
2181
  tree.Element.prototype.toCSS = function (env) {
1496
- return this.combinator.toCSS(env || {}) + this.value;
2182
+ return this.combinator.toCSS(env || {}) + (this.value.toCSS ? this.value.toCSS(env) : this.value);
1497
2183
  };
1498
2184
 
1499
2185
  tree.Combinator = function (value) {
1500
2186
  if (value === ' ') {
1501
2187
  this.value = ' ';
2188
+ } else if (value === '& ') {
2189
+ this.value = '& ';
1502
2190
  } else {
1503
2191
  this.value = value ? value.trim() : "";
1504
2192
  }
@@ -1508,15 +2196,15 @@ tree.Combinator.prototype.toCSS = function (env) {
1508
2196
  '' : '',
1509
2197
  ' ' : ' ',
1510
2198
  '&' : '',
2199
+ '& ' : ' ',
1511
2200
  ':' : ' :',
1512
- '::': '::',
1513
2201
  '+' : env.compress ? '+' : ' + ',
1514
2202
  '~' : env.compress ? '~' : ' ~ ',
1515
2203
  '>' : env.compress ? '>' : ' > '
1516
2204
  }[this.value];
1517
2205
  };
1518
2206
 
1519
- })(require('less/tree'));
2207
+ })(require('../tree'));
1520
2208
  (function (tree) {
1521
2209
 
1522
2210
  tree.Expression = function (value) { this.value = value };
@@ -1534,12 +2222,12 @@ tree.Expression.prototype = {
1534
2222
  },
1535
2223
  toCSS: function (env) {
1536
2224
  return this.value.map(function (e) {
1537
- return e.toCSS(env);
2225
+ return e.toCSS ? e.toCSS(env) : '';
1538
2226
  }).join(' ');
1539
2227
  }
1540
2228
  };
1541
2229
 
1542
- })(require('less/tree'));
2230
+ })(require('../tree'));
1543
2231
  (function (tree) {
1544
2232
  //
1545
2233
  // CSS @import node
@@ -1553,27 +2241,27 @@ tree.Expression.prototype = {
1553
2241
  // `import,push`, we also pass it a callback, which it'll call once
1554
2242
  // the file has been fetched, and parsed.
1555
2243
  //
1556
- tree.Import = function (path, imports) {
2244
+ tree.Import = function (path, imports, features, index) {
1557
2245
  var that = this;
1558
2246
 
2247
+ this.index = index;
1559
2248
  this._path = path;
2249
+ this.features = features && new(tree.Value)(features);
1560
2250
 
1561
2251
  // The '.less' extension is optional
1562
2252
  if (path instanceof tree.Quoted) {
1563
- this.path = /\.(le?|c)ss$/.test(path.value) ? path.value : path.value + '.less';
2253
+ this.path = /\.(le?|c)ss(\?.*)?$/.test(path.value) ? path.value : path.value + '.less';
1564
2254
  } else {
1565
2255
  this.path = path.value.value || path.value;
1566
2256
  }
1567
2257
 
1568
- this.css = /css$/.test(this.path);
2258
+ this.css = /css(\?.*)?$/.test(this.path);
1569
2259
 
1570
2260
  // Only pre-compile .less files
1571
2261
  if (! this.css) {
1572
- imports.push(this.path, function (root) {
1573
- if (! root) {
1574
- throw new(Error)("Error parsing " + that.path);
1575
- }
1576
- that.root = root;
2262
+ imports.push(this.path, function (e, root) {
2263
+ if (e) { e.index = index }
2264
+ that.root = root || new(tree.Ruleset)([], []);
1577
2265
  });
1578
2266
  }
1579
2267
  };
@@ -1588,20 +2276,22 @@ tree.Import = function (path, imports) {
1588
2276
  // ruleset.
1589
2277
  //
1590
2278
  tree.Import.prototype = {
1591
- toCSS: function () {
2279
+ toCSS: function (env) {
2280
+ var features = this.features ? ' ' + this.features.toCSS(env) : '';
2281
+
1592
2282
  if (this.css) {
1593
- return "@import " + this._path.toCSS() + ';\n';
2283
+ return "@import " + this._path.toCSS() + features + ';\n';
1594
2284
  } else {
1595
2285
  return "";
1596
2286
  }
1597
2287
  },
1598
2288
  eval: function (env) {
1599
- var ruleset;
2289
+ var ruleset, features = this.features && this.features.eval(env);
1600
2290
 
1601
2291
  if (this.css) {
1602
2292
  return this;
1603
2293
  } else {
1604
- ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0));
2294
+ ruleset = new(tree.Ruleset)([], this.root.rules.slice(0));
1605
2295
 
1606
2296
  for (var i = 0; i < ruleset.rules.length; i++) {
1607
2297
  if (ruleset.rules[i] instanceof tree.Import) {
@@ -1611,12 +2301,12 @@ tree.Import.prototype = {
1611
2301
  [i, 1].concat(ruleset.rules[i].eval(env)));
1612
2302
  }
1613
2303
  }
1614
- return ruleset.rules;
2304
+ return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules;
1615
2305
  }
1616
2306
  }
1617
2307
  };
1618
2308
 
1619
- })(require('less/tree'));
2309
+ })(require('../tree'));
1620
2310
  (function (tree) {
1621
2311
 
1622
2312
  tree.JavaScript = function (string, index, escaped) {
@@ -1666,24 +2356,150 @@ tree.JavaScript.prototype = {
1666
2356
  }
1667
2357
  };
1668
2358
 
1669
- })(require('less/tree'));
2359
+ })(require('../tree'));
1670
2360
 
1671
2361
  (function (tree) {
1672
2362
 
1673
2363
  tree.Keyword = function (value) { this.value = value };
1674
2364
  tree.Keyword.prototype = {
1675
2365
  eval: function () { return this },
1676
- toCSS: function () { return this.value }
2366
+ toCSS: function () { return this.value },
2367
+ compare: function (other) {
2368
+ if (other instanceof tree.Keyword) {
2369
+ return other.value === this.value ? 0 : 1;
2370
+ } else {
2371
+ return -1;
2372
+ }
2373
+ }
2374
+ };
2375
+
2376
+ tree.True = new(tree.Keyword)('true');
2377
+ tree.False = new(tree.Keyword)('false');
2378
+
2379
+ })(require('../tree'));
2380
+ (function (tree) {
2381
+
2382
+ tree.Media = function (value, features) {
2383
+ var el = new(tree.Element)('&', null, 0),
2384
+ selectors = [new(tree.Selector)([el])];
2385
+
2386
+ this.features = new(tree.Value)(features);
2387
+ this.ruleset = new(tree.Ruleset)(selectors, value);
2388
+ this.ruleset.allowImports = true;
2389
+ };
2390
+ tree.Media.prototype = {
2391
+ toCSS: function (ctx, env) {
2392
+ var features = this.features.toCSS(env);
2393
+
2394
+ this.ruleset.root = (ctx.length === 0 || ctx[0].multiMedia);
2395
+ return '@media ' + features + (env.compress ? '{' : ' {\n ') +
2396
+ this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') +
2397
+ (env.compress ? '}': '\n}\n');
2398
+ },
2399
+ eval: function (env) {
2400
+ if (!env.mediaBlocks) {
2401
+ env.mediaBlocks = [];
2402
+ env.mediaPath = [];
2403
+ }
2404
+
2405
+ var blockIndex = env.mediaBlocks.length;
2406
+ env.mediaPath.push(this);
2407
+ env.mediaBlocks.push(this);
2408
+
2409
+ var media = new(tree.Media)([], []);
2410
+ media.features = this.features.eval(env);
2411
+
2412
+ env.frames.unshift(this.ruleset);
2413
+ media.ruleset = this.ruleset.eval(env);
2414
+ env.frames.shift();
2415
+
2416
+ env.mediaBlocks[blockIndex] = media;
2417
+ env.mediaPath.pop();
2418
+
2419
+ return env.mediaPath.length === 0 ? media.evalTop(env) :
2420
+ media.evalNested(env)
2421
+ },
2422
+ variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
2423
+ find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
2424
+ rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) },
2425
+
2426
+ evalTop: function (env) {
2427
+ var result = this;
2428
+
2429
+ // Render all dependent Media blocks.
2430
+ if (env.mediaBlocks.length > 1) {
2431
+ var el = new(tree.Element)('&', null, 0);
2432
+ var selectors = [new(tree.Selector)([el])];
2433
+ result = new(tree.Ruleset)(selectors, env.mediaBlocks);
2434
+ result.multiMedia = true;
2435
+ }
2436
+
2437
+ delete env.mediaBlocks;
2438
+ delete env.mediaPath;
2439
+
2440
+ return result;
2441
+ },
2442
+ evalNested: function (env) {
2443
+ var i, value,
2444
+ path = env.mediaPath.concat([this]);
2445
+
2446
+ // Extract the media-query conditions separated with `,` (OR).
2447
+ for (i = 0; i < path.length; i++) {
2448
+ value = path[i].features instanceof tree.Value ?
2449
+ path[i].features.value : path[i].features;
2450
+ path[i] = Array.isArray(value) ? value : [value];
2451
+ }
2452
+
2453
+ // Trace all permutations to generate the resulting media-query.
2454
+ //
2455
+ // (a, b and c) with nested (d, e) ->
2456
+ // a and d
2457
+ // a and e
2458
+ // b and c and d
2459
+ // b and c and e
2460
+ this.features = new(tree.Value)(this.permute(path).map(function (path) {
2461
+ path = path.map(function (fragment) {
2462
+ return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment);
2463
+ });
2464
+
2465
+ for(i = path.length - 1; i > 0; i--) {
2466
+ path.splice(i, 0, new(tree.Anonymous)("and"));
2467
+ }
2468
+
2469
+ return new(tree.Expression)(path);
2470
+ }));
2471
+
2472
+ // Fake a tree-node that doesn't output anything.
2473
+ return new(tree.Ruleset)([], []);
2474
+ },
2475
+ permute: function (arr) {
2476
+ if (arr.length === 0) {
2477
+ return [];
2478
+ } else if (arr.length === 1) {
2479
+ return arr[0];
2480
+ } else {
2481
+ var result = [];
2482
+ var rest = this.permute(arr.slice(1));
2483
+ for (var i = 0; i < rest.length; i++) {
2484
+ for (var j = 0; j < arr[0].length; j++) {
2485
+ result.push([arr[0][j]].concat(rest[i]));
2486
+ }
2487
+ }
2488
+ return result;
2489
+ }
2490
+ }
1677
2491
  };
1678
2492
 
1679
- })(require('less/tree'));
2493
+ })(require('../tree'));
1680
2494
  (function (tree) {
1681
2495
 
1682
2496
  tree.mixin = {};
1683
- tree.mixin.Call = function (elements, args, index) {
2497
+ tree.mixin.Call = function (elements, args, index, filename, important) {
1684
2498
  this.selector = new(tree.Selector)(elements);
1685
2499
  this.arguments = args;
1686
2500
  this.index = index;
2501
+ this.filename = filename;
2502
+ this.important = important;
1687
2503
  };
1688
2504
  tree.mixin.Call.prototype = {
1689
2505
  eval: function (env) {
@@ -1696,34 +2512,38 @@ tree.mixin.Call.prototype = {
1696
2512
  if (mixins[m].match(args, env)) {
1697
2513
  try {
1698
2514
  Array.prototype.push.apply(
1699
- rules, mixins[m].eval(env, this.arguments).rules);
2515
+ rules, mixins[m].eval(env, this.arguments, this.important).rules);
1700
2516
  match = true;
1701
2517
  } catch (e) {
1702
- throw { message: e.message, index: e.index, stack: e.stack, call: this.index };
2518
+ throw { message: e.message, index: this.index, filename: this.filename, stack: e.stack };
1703
2519
  }
1704
2520
  }
1705
2521
  }
1706
2522
  if (match) {
1707
2523
  return rules;
1708
2524
  } else {
1709
- throw { message: 'No matching definition was found for `' +
2525
+ throw { type: 'Runtime',
2526
+ message: 'No matching definition was found for `' +
1710
2527
  this.selector.toCSS().trim() + '(' +
1711
2528
  this.arguments.map(function (a) {
1712
2529
  return a.toCSS();
1713
2530
  }).join(', ') + ")`",
1714
- index: this.index };
2531
+ index: this.index, filename: this.filename };
1715
2532
  }
1716
2533
  }
1717
2534
  }
1718
- throw { message: this.selector.toCSS().trim() + " is undefined",
1719
- index: this.index };
2535
+ throw { type: 'Name',
2536
+ message: this.selector.toCSS().trim() + " is undefined",
2537
+ index: this.index, filename: this.filename };
1720
2538
  }
1721
2539
  };
1722
2540
 
1723
- tree.mixin.Definition = function (name, params, rules) {
2541
+ tree.mixin.Definition = function (name, params, rules, condition, variadic) {
1724
2542
  this.name = name;
1725
2543
  this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])];
1726
2544
  this.params = params;
2545
+ this.condition = condition;
2546
+ this.variadic = variadic;
1727
2547
  this.arity = params.length;
1728
2548
  this.rules = rules;
1729
2549
  this._lookups = {};
@@ -1741,33 +2561,56 @@ tree.mixin.Definition.prototype = {
1741
2561
  find: function () { return this.parent.find.apply(this, arguments) },
1742
2562
  rulesets: function () { return this.parent.rulesets.apply(this) },
1743
2563
 
1744
- eval: function (env, args) {
1745
- var frame = new(tree.Ruleset)(null, []), context, _arguments = [];
2564
+ evalParams: function (env, args) {
2565
+ var frame = new(tree.Ruleset)(null, []), varargs;
1746
2566
 
1747
- for (var i = 0, val; i < this.params.length; i++) {
1748
- if (this.params[i].name) {
1749
- if (val = (args && args[i]) || this.params[i].value) {
1750
- frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env)));
2567
+ for (var i = 0, val, name; i < this.params.length; i++) {
2568
+ if (name = this.params[i].name) {
2569
+ if (this.params[i].variadic && args) {
2570
+ varargs = [];
2571
+ for (var j = i; j < args.length; j++) {
2572
+ varargs.push(args[j].eval(env));
2573
+ }
2574
+ frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env)));
2575
+ } else if (val = (args && args[i]) || this.params[i].value) {
2576
+ frame.rules.unshift(new(tree.Rule)(name, val.eval(env)));
1751
2577
  } else {
1752
- throw { message: "wrong number of arguments for " + this.name +
2578
+ throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
1753
2579
  ' (' + args.length + ' for ' + this.arity + ')' };
1754
2580
  }
1755
2581
  }
1756
2582
  }
2583
+ return frame;
2584
+ },
2585
+ eval: function (env, args, important) {
2586
+ var frame = this.evalParams(env, args), context, _arguments = [], rules, start;
2587
+
1757
2588
  for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) {
1758
2589
  _arguments.push(args[i] || this.params[i].value);
1759
2590
  }
1760
2591
  frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
1761
2592
 
1762
- return new(tree.Ruleset)(null, this.rules.slice(0)).eval({
2593
+ rules = important ?
2594
+ this.rules.map(function (r) {
2595
+ return new(tree.Rule)(r.name, r.value, '!important', r.index);
2596
+ }) : this.rules.slice(0);
2597
+
2598
+ return new(tree.Ruleset)(null, rules).eval({
1763
2599
  frames: [this, frame].concat(this.frames, env.frames)
1764
2600
  });
1765
2601
  },
1766
2602
  match: function (args, env) {
1767
- var argsLength = (args && args.length) || 0, len;
2603
+ var argsLength = (args && args.length) || 0, len, frame;
2604
+
2605
+ if (! this.variadic) {
2606
+ if (argsLength < this.required) { return false }
2607
+ if (argsLength > this.params.length) { return false }
2608
+ if ((this.required > 0) && (argsLength > this.params.length)) { return false }
2609
+ }
1768
2610
 
1769
- if (argsLength < this.required) { return false }
1770
- if ((this.required > 0) && (argsLength > this.params.length)) { return false }
2611
+ if (this.condition && !this.condition.eval({
2612
+ frames: [this.evalParams(env, args)].concat(env.frames)
2613
+ })) { return false }
1771
2614
 
1772
2615
  len = Math.min(argsLength, this.arity);
1773
2616
 
@@ -1782,7 +2625,7 @@ tree.mixin.Definition.prototype = {
1782
2625
  }
1783
2626
  };
1784
2627
 
1785
- })(require('less/tree'));
2628
+ })(require('../tree'));
1786
2629
  (function (tree) {
1787
2630
 
1788
2631
  tree.Operation = function (op, operands) {
@@ -1814,7 +2657,23 @@ tree.operate = function (op, a, b) {
1814
2657
  }
1815
2658
  };
1816
2659
 
1817
- })(require('less/tree'));
2660
+ })(require('../tree'));
2661
+
2662
+ (function (tree) {
2663
+
2664
+ tree.Paren = function (node) {
2665
+ this.value = node;
2666
+ };
2667
+ tree.Paren.prototype = {
2668
+ toCSS: function (env) {
2669
+ return '(' + this.value.toCSS(env) + ')';
2670
+ },
2671
+ eval: function (env) {
2672
+ return new(tree.Paren)(this.value.eval(env));
2673
+ }
2674
+ };
2675
+
2676
+ })(require('../tree'));
1818
2677
  (function (tree) {
1819
2678
 
1820
2679
  tree.Quoted = function (str, content, escaped, i) {
@@ -1837,20 +2696,21 @@ tree.Quoted.prototype = {
1837
2696
  return new(tree.JavaScript)(exp, that.index, true).eval(env).value;
1838
2697
  }).replace(/@\{([\w-]+)\}/g, function (_, name) {
1839
2698
  var v = new(tree.Variable)('@' + name, that.index).eval(env);
1840
- return v.value || v.toCSS();
2699
+ return ('value' in v) ? v.value : v.toCSS();
1841
2700
  });
1842
2701
  return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index);
1843
2702
  }
1844
2703
  };
1845
2704
 
1846
- })(require('less/tree'));
2705
+ })(require('../tree'));
1847
2706
  (function (tree) {
1848
2707
 
1849
- tree.Rule = function (name, value, important, index) {
2708
+ tree.Rule = function (name, value, important, index, inline) {
1850
2709
  this.name = name;
1851
2710
  this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);
1852
2711
  this.important = important ? ' ' + important.trim() : '';
1853
2712
  this.index = index;
2713
+ this.inline = inline || false;
1854
2714
 
1855
2715
  if (name.charAt(0) === '@') {
1856
2716
  this.variable = true;
@@ -1861,12 +2721,15 @@ tree.Rule.prototype.toCSS = function (env) {
1861
2721
  else {
1862
2722
  return this.name + (env.compress ? ':' : ': ') +
1863
2723
  this.value.toCSS(env) +
1864
- this.important + ";";
2724
+ this.important + (this.inline ? "" : ";");
1865
2725
  }
1866
2726
  };
1867
2727
 
1868
2728
  tree.Rule.prototype.eval = function (context) {
1869
- return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index);
2729
+ return new(tree.Rule)(this.name,
2730
+ this.value.eval(context),
2731
+ this.important,
2732
+ this.index, this.inline);
1870
2733
  };
1871
2734
 
1872
2735
  tree.Shorthand = function (a, b) {
@@ -1881,25 +2744,28 @@ tree.Shorthand.prototype = {
1881
2744
  eval: function () { return this }
1882
2745
  };
1883
2746
 
1884
- })(require('less/tree'));
2747
+ })(require('../tree'));
1885
2748
  (function (tree) {
1886
2749
 
1887
- tree.Ruleset = function (selectors, rules) {
2750
+ tree.Ruleset = function (selectors, rules, strictImports) {
1888
2751
  this.selectors = selectors;
1889
2752
  this.rules = rules;
1890
2753
  this._lookups = {};
2754
+ this.strictImports = strictImports;
1891
2755
  };
1892
2756
  tree.Ruleset.prototype = {
1893
2757
  eval: function (env) {
1894
- var ruleset = new(tree.Ruleset)(this.selectors, this.rules.slice(0));
2758
+ var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) });
2759
+ var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports);
1895
2760
 
1896
2761
  ruleset.root = this.root;
2762
+ ruleset.allowImports = this.allowImports;
1897
2763
 
1898
2764
  // push the current ruleset to the frames stack
1899
2765
  env.frames.unshift(ruleset);
1900
2766
 
1901
2767
  // Evaluate imports
1902
- if (ruleset.root) {
2768
+ if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) {
1903
2769
  for (var i = 0; i < ruleset.rules.length; i++) {
1904
2770
  if (ruleset.rules[i] instanceof tree.Import) {
1905
2771
  Array.prototype.splice
@@ -1974,7 +2840,7 @@ tree.Ruleset.prototype = {
1974
2840
  if (rule !== self) {
1975
2841
  for (var j = 0; j < rule.selectors.length; j++) {
1976
2842
  if (match = selector.match(rule.selectors[j])) {
1977
- if (selector.elements.length > 1) {
2843
+ if (selector.elements.length > rule.selectors[j].elements.length) {
1978
2844
  Array.prototype.push.apply(rules, rule.find(
1979
2845
  new(tree.Selector)(selector.elements.slice(1)), self));
1980
2846
  } else {
@@ -2004,11 +2870,7 @@ tree.Ruleset.prototype = {
2004
2870
  if (context.length === 0) {
2005
2871
  paths = this.selectors.map(function (s) { return [s] });
2006
2872
  } else {
2007
- for (var s = 0; s < this.selectors.length; s++) {
2008
- for (var c = 0; c < context.length; c++) {
2009
- paths.push(context[c].concat([this.selectors[s]]));
2010
- }
2011
- }
2873
+ this.joinSelectors(paths, context, this.selectors);
2012
2874
  }
2013
2875
  }
2014
2876
 
@@ -2016,7 +2878,7 @@ tree.Ruleset.prototype = {
2016
2878
  for (var i = 0; i < this.rules.length; i++) {
2017
2879
  rule = this.rules[i];
2018
2880
 
2019
- if (rule.rules || (rule instanceof tree.Directive)) {
2881
+ if (rule.rules || (rule instanceof tree.Directive) || (rule instanceof tree.Media)) {
2020
2882
  rulesets.push(rule.toCSS(paths, env));
2021
2883
  } else if (rule instanceof tree.Comment) {
2022
2884
  if (!rule.silent) {
@@ -2048,7 +2910,8 @@ tree.Ruleset.prototype = {
2048
2910
  return p.map(function (s) {
2049
2911
  return s.toCSS(env);
2050
2912
  }).join('').trim();
2051
- }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', '));
2913
+ }).join( env.compress ? ',' : ',\n');
2914
+
2052
2915
  css.push(selector,
2053
2916
  (env.compress ? '{' : ' {\n ') +
2054
2917
  rules.join(env.compress ? '' : '\n ') +
@@ -2058,9 +2921,46 @@ tree.Ruleset.prototype = {
2058
2921
  css.push(rulesets);
2059
2922
 
2060
2923
  return css.join('') + (env.compress ? '\n' : '');
2924
+ },
2925
+
2926
+ joinSelectors: function (paths, context, selectors) {
2927
+ for (var s = 0; s < selectors.length; s++) {
2928
+ this.joinSelector(paths, context, selectors[s]);
2929
+ }
2930
+ },
2931
+
2932
+ joinSelector: function (paths, context, selector) {
2933
+ var before = [], after = [], beforeElements = [],
2934
+ afterElements = [], hasParentSelector = false, el;
2935
+
2936
+ for (var i = 0; i < selector.elements.length; i++) {
2937
+ el = selector.elements[i];
2938
+ if (el.combinator.value.charAt(0) === '&') {
2939
+ hasParentSelector = true;
2940
+ }
2941
+ if (hasParentSelector) afterElements.push(el);
2942
+ else beforeElements.push(el);
2943
+ }
2944
+
2945
+ if (! hasParentSelector) {
2946
+ afterElements = beforeElements;
2947
+ beforeElements = [];
2948
+ }
2949
+
2950
+ if (beforeElements.length > 0) {
2951
+ before.push(new(tree.Selector)(beforeElements));
2952
+ }
2953
+
2954
+ if (afterElements.length > 0) {
2955
+ after.push(new(tree.Selector)(afterElements));
2956
+ }
2957
+
2958
+ for (var c = 0; c < context.length; c++) {
2959
+ paths.push(before.concat(context[c]).concat(after));
2960
+ }
2061
2961
  }
2062
2962
  };
2063
- })(require('less/tree'));
2963
+ })(require('../tree'));
2064
2964
  (function (tree) {
2065
2965
 
2066
2966
  tree.Selector = function (elements) {
@@ -2070,11 +2970,25 @@ tree.Selector = function (elements) {
2070
2970
  }
2071
2971
  };
2072
2972
  tree.Selector.prototype.match = function (other) {
2073
- if (this.elements[0].value === other.elements[0].value) {
2074
- return true;
2075
- } else {
2973
+ var len = this.elements.length,
2974
+ olen = other.elements.length,
2975
+ max = Math.min(len, olen);
2976
+
2977
+ if (len < olen) {
2076
2978
  return false;
2979
+ } else {
2980
+ for (var i = 0; i < max; i++) {
2981
+ if (this.elements[i].value !== other.elements[i].value) {
2982
+ return false;
2983
+ }
2984
+ }
2077
2985
  }
2986
+ return true;
2987
+ };
2988
+ tree.Selector.prototype.eval = function (env) {
2989
+ return new(tree.Selector)(this.elements.map(function (e) {
2990
+ return e.eval(env);
2991
+ }));
2078
2992
  };
2079
2993
  tree.Selector.prototype.toCSS = function (env) {
2080
2994
  if (this._css) { return this._css }
@@ -2088,7 +3002,7 @@ tree.Selector.prototype.toCSS = function (env) {
2088
3002
  }).join('');
2089
3003
  };
2090
3004
 
2091
- })(require('less/tree'));
3005
+ })(require('../tree'));
2092
3006
  (function (tree) {
2093
3007
 
2094
3008
  tree.URL = function (val, paths) {
@@ -2096,7 +3010,7 @@ tree.URL = function (val, paths) {
2096
3010
  this.attrs = val;
2097
3011
  } else {
2098
3012
  // Add the base path if the URL is relative and we are in the browser
2099
- if (!/^(?:https?:\/|file:\/|data:\/)?\//.test(val.value) && paths.length > 0 && typeof(window) !== 'undefined') {
3013
+ if (typeof(window) !== 'undefined' && !/^(?:https?:\/\/|file:\/\/|data:|\/)/.test(val.value) && paths.length > 0) {
2100
3014
  val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value);
2101
3015
  }
2102
3016
  this.value = val;
@@ -2113,7 +3027,7 @@ tree.URL.prototype = {
2113
3027
  }
2114
3028
  };
2115
3029
 
2116
- })(require('less/tree'));
3030
+ })(require('../tree'));
2117
3031
  (function (tree) {
2118
3032
 
2119
3033
  tree.Value = function (value) {
@@ -2137,10 +3051,10 @@ tree.Value.prototype = {
2137
3051
  }
2138
3052
  };
2139
3053
 
2140
- })(require('less/tree'));
3054
+ })(require('../tree'));
2141
3055
  (function (tree) {
2142
3056
 
2143
- tree.Variable = function (name, index) { this.name = name, this.index = index };
3057
+ tree.Variable = function (name, index, file) { this.name = name, this.index = index, this.file = file };
2144
3058
  tree.Variable.prototype = {
2145
3059
  eval: function (env) {
2146
3060
  var variable, v, name = this.name;
@@ -2155,198 +3069,410 @@ tree.Variable.prototype = {
2155
3069
  }
2156
3070
  })) { return variable }
2157
3071
  else {
2158
- throw { message: "variable " + name + " is undefined",
3072
+ throw { type: 'Name',
3073
+ message: "variable " + name + " is undefined",
3074
+ filename: this.file,
2159
3075
  index: this.index };
2160
3076
  }
2161
3077
  }
2162
3078
  };
2163
3079
 
2164
- })(require('less/tree'));
2165
- require('less/tree').find = function (obj, fun) {
3080
+ })(require('../tree'));
3081
+ (function (tree) {
3082
+
3083
+ tree.find = function (obj, fun) {
2166
3084
  for (var i = 0, r; i < obj.length; i++) {
2167
3085
  if (r = fun.call(obj, obj[i])) { return r }
2168
3086
  }
2169
3087
  return null;
2170
3088
  };
2171
- require('less/tree').jsify = function (obj) {
3089
+ tree.jsify = function (obj) {
2172
3090
  if (Array.isArray(obj.value) && (obj.value.length > 1)) {
2173
3091
  return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']';
2174
3092
  } else {
2175
3093
  return obj.toCSS(false);
2176
3094
  }
2177
3095
  };
2178
- (function (tree) {
2179
3096
 
2180
- tree.functions = {
2181
- rgb: function (r, g, b) {
2182
- return this.rgba(r, g, b, 1.0);
2183
- },
2184
- rgba: function (r, g, b, a) {
2185
- var rgb = [r, g, b].map(function (c) { return number(c) }),
2186
- a = number(a);
2187
- return new(tree.Color)(rgb, a);
2188
- },
2189
- hsl: function (h, s, l) {
2190
- return this.hsla(h, s, l, 1.0);
2191
- },
2192
- hsla: function (h, s, l, a) {
2193
- h = (number(h) % 360) / 360;
2194
- s = number(s); l = number(l); a = number(a);
3097
+ })(require('./tree'));
3098
+ //
3099
+ // browser.js - client-side engine
3100
+ //
2195
3101
 
2196
- var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
2197
- var m1 = l * 2 - m2;
3102
+ var isFileProtocol = (location.protocol === 'file:' ||
3103
+ location.protocol === 'chrome:' ||
3104
+ location.protocol === 'chrome-extension:' ||
3105
+ location.protocol === 'resource:');
2198
3106
 
2199
- return this.rgba(hue(h + 1/3) * 255,
2200
- hue(h) * 255,
2201
- hue(h - 1/3) * 255,
2202
- a);
3107
+ less.env = less.env || (location.hostname == '127.0.0.1' ||
3108
+ location.hostname == '0.0.0.0' ||
3109
+ location.hostname == 'localhost' ||
3110
+ location.port.length > 0 ||
3111
+ isFileProtocol ? 'development'
3112
+ : 'production');
2203
3113
 
2204
- function hue(h) {
2205
- h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
2206
- if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
2207
- else if (h * 2 < 1) return m2;
2208
- else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6;
2209
- else return m1;
2210
- }
2211
- },
2212
- hue: function (color) {
2213
- return new(tree.Dimension)(Math.round(color.toHSL().h));
2214
- },
2215
- saturation: function (color) {
2216
- return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%');
2217
- },
2218
- lightness: function (color) {
2219
- return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%');
2220
- },
2221
- alpha: function (color) {
2222
- return new(tree.Dimension)(color.toHSL().a);
2223
- },
2224
- saturate: function (color, amount) {
2225
- var hsl = color.toHSL();
3114
+ // Load styles asynchronously (default: false)
3115
+ //
3116
+ // This is set to `false` by default, so that the body
3117
+ // doesn't start loading before the stylesheets are parsed.
3118
+ // Setting this to `true` can result in flickering.
3119
+ //
3120
+ less.async = false;
2226
3121
 
2227
- hsl.s += amount.value / 100;
2228
- hsl.s = clamp(hsl.s);
2229
- return hsla(hsl);
2230
- },
2231
- desaturate: function (color, amount) {
2232
- var hsl = color.toHSL();
3122
+ // Interval between watch polls
3123
+ less.poll = less.poll || (isFileProtocol ? 1000 : 1500);
2233
3124
 
2234
- hsl.s -= amount.value / 100;
2235
- hsl.s = clamp(hsl.s);
2236
- return hsla(hsl);
2237
- },
2238
- lighten: function (color, amount) {
2239
- var hsl = color.toHSL();
3125
+ //
3126
+ // Watch mode
3127
+ //
3128
+ less.watch = function () { return this.watchMode = true };
3129
+ less.unwatch = function () { return this.watchMode = false };
2240
3130
 
2241
- hsl.l += amount.value / 100;
2242
- hsl.l = clamp(hsl.l);
2243
- return hsla(hsl);
2244
- },
2245
- darken: function (color, amount) {
2246
- var hsl = color.toHSL();
3131
+ if (less.env === 'development') {
3132
+ less.optimization = 0;
2247
3133
 
2248
- hsl.l -= amount.value / 100;
2249
- hsl.l = clamp(hsl.l);
2250
- return hsla(hsl);
2251
- },
2252
- fadein: function (color, amount) {
2253
- var hsl = color.toHSL();
3134
+ if (/!watch/.test(location.hash)) {
3135
+ less.watch();
3136
+ }
3137
+ less.watchTimer = setInterval(function () {
3138
+ if (less.watchMode) {
3139
+ loadStyleSheets(function (e, root, _, sheet, env) {
3140
+ if (root) {
3141
+ createCSS(root.toCSS(), sheet, env.lastModified);
3142
+ }
3143
+ });
3144
+ }
3145
+ }, less.poll);
3146
+ } else {
3147
+ less.optimization = 3;
3148
+ }
2254
3149
 
2255
- hsl.a += amount.value / 100;
2256
- hsl.a = clamp(hsl.a);
2257
- return hsla(hsl);
2258
- },
2259
- fadeout: function (color, amount) {
2260
- var hsl = color.toHSL();
3150
+ var cache;
2261
3151
 
2262
- hsl.a -= amount.value / 100;
2263
- hsl.a = clamp(hsl.a);
2264
- return hsla(hsl);
2265
- },
2266
- spin: function (color, amount) {
2267
- var hsl = color.toHSL();
2268
- var hue = (hsl.h + amount.value) % 360;
3152
+ try {
3153
+ cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage;
3154
+ } catch (_) {
3155
+ cache = null;
3156
+ }
2269
3157
 
2270
- hsl.h = hue < 0 ? 360 + hue : hue;
3158
+ //
3159
+ // Get all <link> tags with the 'rel' attribute set to "stylesheet/less"
3160
+ //
3161
+ var links = document.getElementsByTagName('link');
3162
+ var typePattern = /^text\/(x-)?less$/;
2271
3163
 
2272
- return hsla(hsl);
2273
- },
2274
- //
2275
- // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
2276
- // http://sass-lang.com
2277
- //
2278
- mix: function (color1, color2, weight) {
2279
- var p = weight.value / 100.0;
2280
- var w = p * 2 - 1;
2281
- var a = color1.toHSL().a - color2.toHSL().a;
3164
+ less.sheets = [];
2282
3165
 
2283
- var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
2284
- var w2 = 1 - w1;
3166
+ for (var i = 0; i < links.length; i++) {
3167
+ if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
3168
+ (links[i].type.match(typePattern)))) {
3169
+ less.sheets.push(links[i]);
3170
+ }
3171
+ }
2285
3172
 
2286
- var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,
2287
- color1.rgb[1] * w1 + color2.rgb[1] * w2,
2288
- color1.rgb[2] * w1 + color2.rgb[2] * w2];
2289
3173
 
2290
- var alpha = color1.alpha * p + color2.alpha * (1 - p);
3174
+ less.refresh = function (reload) {
3175
+ var startTime, endTime;
3176
+ startTime = endTime = new(Date);
2291
3177
 
2292
- return new(tree.Color)(rgb, alpha);
2293
- },
2294
- greyscale: function (color) {
2295
- return this.desaturate(color, new(tree.Dimension)(100));
2296
- },
2297
- e: function (str) {
2298
- return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str);
2299
- },
2300
- escape: function (str) {
2301
- 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"));
2302
- },
2303
- '%': function (quoted /* arg, arg, ...*/) {
2304
- var args = Array.prototype.slice.call(arguments, 1),
2305
- str = quoted.value;
3178
+ loadStyleSheets(function (e, root, _, sheet, env) {
3179
+ if (env.local) {
3180
+ log("loading " + sheet.href + " from cache.");
3181
+ } else {
3182
+ log("parsed " + sheet.href + " successfully.");
3183
+ createCSS(root.toCSS(), sheet, env.lastModified);
3184
+ }
3185
+ log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms');
3186
+ (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms');
3187
+ endTime = new(Date);
3188
+ }, reload);
2306
3189
 
2307
- for (var i = 0; i < args.length; i++) {
2308
- str = str.replace(/%[sda]/i, function(token) {
2309
- var value = token.match(/s/i) ? args[i].value : args[i].toCSS();
2310
- return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
3190
+ loadStyles();
3191
+ };
3192
+ less.refreshStyles = loadStyles;
3193
+
3194
+ less.refresh(less.env === 'development');
3195
+
3196
+ function loadStyles() {
3197
+ var styles = document.getElementsByTagName('style');
3198
+ for (var i = 0; i < styles.length; i++) {
3199
+ if (styles[i].type.match(typePattern)) {
3200
+ new(less.Parser)().parse(styles[i].innerHTML || '', function (e, tree) {
3201
+ var css = tree.toCSS();
3202
+ var style = styles[i];
3203
+ style.type = 'text/css';
3204
+ if (style.styleSheet) {
3205
+ style.styleSheet.cssText = css;
3206
+ } else {
3207
+ style.innerHTML = css;
3208
+ }
2311
3209
  });
2312
3210
  }
2313
- str = str.replace(/%%/g, '%');
2314
- return new(tree.Quoted)('"' + str + '"', str);
2315
- },
2316
- round: function (n) {
2317
- if (n instanceof tree.Dimension) {
2318
- return new(tree.Dimension)(Math.round(number(n)), n.unit);
2319
- } else if (typeof(n) === 'number') {
2320
- return Math.round(n);
3211
+ }
3212
+ }
3213
+
3214
+ function loadStyleSheets(callback, reload) {
3215
+ for (var i = 0; i < less.sheets.length; i++) {
3216
+ loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1));
3217
+ }
3218
+ }
3219
+
3220
+ function loadStyleSheet(sheet, callback, reload, remaining) {
3221
+ var url = window.location.href.replace(/[#?].*$/, '');
3222
+ var href = sheet.href.replace(/\?.*$/, '');
3223
+ var css = cache && cache.getItem(href);
3224
+ var timestamp = cache && cache.getItem(href + ':timestamp');
3225
+ var styles = { css: css, timestamp: timestamp };
3226
+
3227
+ // Stylesheets in IE don't always return the full path
3228
+ if (! /^(https?|file):/.test(href)) {
3229
+ if (href.charAt(0) == "/") {
3230
+ href = window.location.protocol + "//" + window.location.host + href;
2321
3231
  } else {
2322
- throw {
2323
- error: "RuntimeError",
2324
- message: "math functions take numbers as parameters"
2325
- };
3232
+ href = url.slice(0, url.lastIndexOf('/') + 1) + href;
2326
3233
  }
2327
3234
  }
2328
- };
3235
+ var filename = href.match(/([^\/]+)$/)[1];
3236
+
3237
+ xhr(sheet.href, sheet.type, function (data, lastModified) {
3238
+ if (!reload && styles && lastModified &&
3239
+ (new(Date)(lastModified).valueOf() ===
3240
+ new(Date)(styles.timestamp).valueOf())) {
3241
+ // Use local copy
3242
+ createCSS(styles.css, sheet);
3243
+ callback(null, null, data, sheet, { local: true, remaining: remaining });
3244
+ } else {
3245
+ // Use remote copy (re-parse)
3246
+ try {
3247
+ new(less.Parser)({
3248
+ optimization: less.optimization,
3249
+ paths: [href.replace(/[\w\.-]+$/, '')],
3250
+ mime: sheet.type,
3251
+ filename: filename
3252
+ }).parse(data, function (e, root) {
3253
+ if (e) { return error(e, href) }
3254
+ try {
3255
+ callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining });
3256
+ removeNode(document.getElementById('less-error-message:' + extractId(href)));
3257
+ } catch (e) {
3258
+ error(e, href);
3259
+ }
3260
+ });
3261
+ } catch (e) {
3262
+ error(e, href);
3263
+ }
3264
+ }
3265
+ }, function (status, url) {
3266
+ throw new(Error)("Couldn't load " + url + " (" + status + ")");
3267
+ });
3268
+ }
2329
3269
 
2330
- function hsla(hsla) {
2331
- return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a);
3270
+ function extractId(href) {
3271
+ return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain
3272
+ .replace(/^\//, '' ) // Remove root /
3273
+ .replace(/\?.*$/, '' ) // Remove query
3274
+ .replace(/\.[^\.\/]+$/, '' ) // Remove file extension
3275
+ .replace(/[^\.\w-]+/g, '-') // Replace illegal characters
3276
+ .replace(/\./g, ':'); // Replace dots with colons(for valid id)
2332
3277
  }
2333
3278
 
2334
- function number(n) {
2335
- if (n instanceof tree.Dimension) {
2336
- return parseFloat(n.unit == '%' ? n.value / 100 : n.value);
2337
- } else if (typeof(n) === 'number') {
2338
- return n;
3279
+ function createCSS(styles, sheet, lastModified) {
3280
+ var css;
3281
+
3282
+ // Strip the query-string
3283
+ var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : '';
3284
+
3285
+ // If there is no title set, use the filename, minus the extension
3286
+ var id = 'less:' + (sheet.title || extractId(href));
3287
+
3288
+ // If the stylesheet doesn't exist, create a new node
3289
+ if ((css = document.getElementById(id)) === null) {
3290
+ css = document.createElement('style');
3291
+ css.type = 'text/css';
3292
+ css.media = sheet.media || 'screen';
3293
+ css.id = id;
3294
+ document.getElementsByTagName('head')[0].appendChild(css);
3295
+ }
3296
+
3297
+ if (css.styleSheet) { // IE
3298
+ try {
3299
+ css.styleSheet.cssText = styles;
3300
+ } catch (e) {
3301
+ throw new(Error)("Couldn't reassign styleSheet.cssText.");
3302
+ }
2339
3303
  } else {
2340
- throw {
2341
- error: "RuntimeError",
2342
- message: "color functions take numbers as parameters"
3304
+ (function (node) {
3305
+ if (css.childNodes.length > 0) {
3306
+ if (css.firstChild.nodeValue !== node.nodeValue) {
3307
+ css.replaceChild(node, css.firstChild);
3308
+ }
3309
+ } else {
3310
+ css.appendChild(node);
3311
+ }
3312
+ })(document.createTextNode(styles));
3313
+ }
3314
+
3315
+ // Don't update the local store if the file wasn't modified
3316
+ if (lastModified && cache) {
3317
+ log('saving ' + href + ' to cache.');
3318
+ cache.setItem(href, styles);
3319
+ cache.setItem(href + ':timestamp', lastModified);
3320
+ }
3321
+ }
3322
+
3323
+ function xhr(url, type, callback, errback) {
3324
+ var xhr = getXMLHttpRequest();
3325
+ var async = isFileProtocol ? false : less.async;
3326
+
3327
+ if (typeof(xhr.overrideMimeType) === 'function') {
3328
+ xhr.overrideMimeType('text/css');
3329
+ }
3330
+ xhr.open('GET', url, async);
3331
+ xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5');
3332
+ xhr.send(null);
3333
+
3334
+ if (isFileProtocol) {
3335
+ if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) {
3336
+ callback(xhr.responseText);
3337
+ } else {
3338
+ errback(xhr.status, url);
3339
+ }
3340
+ } else if (async) {
3341
+ xhr.onreadystatechange = function () {
3342
+ if (xhr.readyState == 4) {
3343
+ handleResponse(xhr, callback, errback);
3344
+ }
2343
3345
  };
3346
+ } else {
3347
+ handleResponse(xhr, callback, errback);
3348
+ }
3349
+
3350
+ function handleResponse(xhr, callback, errback) {
3351
+ if (xhr.status >= 200 && xhr.status < 300) {
3352
+ callback(xhr.responseText,
3353
+ xhr.getResponseHeader("Last-Modified"));
3354
+ } else if (typeof(errback) === 'function') {
3355
+ errback(xhr.status, url);
3356
+ }
2344
3357
  }
2345
3358
  }
2346
3359
 
2347
- function clamp(val) {
2348
- return Math.min(1, Math.max(0, val));
3360
+ function getXMLHttpRequest() {
3361
+ if (window.XMLHttpRequest) {
3362
+ return new(XMLHttpRequest);
3363
+ } else {
3364
+ try {
3365
+ return new(ActiveXObject)("MSXML2.XMLHTTP.3.0");
3366
+ } catch (e) {
3367
+ log("browser doesn't support AJAX.");
3368
+ return null;
3369
+ }
3370
+ }
3371
+ }
3372
+
3373
+ function removeNode(node) {
3374
+ return node && node.parentNode.removeChild(node);
3375
+ }
3376
+
3377
+ function log(str) {
3378
+ if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) }
3379
+ }
3380
+
3381
+ function error(e, href) {
3382
+ var id = 'less-error-message:' + extractId(href);
3383
+ var template = '<li><label>{line}</label><pre class="{class}">{content}</pre></li>';
3384
+ var elem = document.createElement('div'), timer, content, error = [];
3385
+ var filename = e.filename || href;
3386
+
3387
+ elem.id = id;
3388
+ elem.className = "less-error-message";
3389
+
3390
+ content = '<h3>' + (e.message || 'There is an error in your .less file') +
3391
+ '</h3>' + '<p>in <a href="' + filename + '">' + filename + "</a> ";
3392
+
3393
+ var errorline = function (e, i, classname) {
3394
+ if (e.extract[i]) {
3395
+ error.push(template.replace(/\{line\}/, parseInt(e.line) + (i - 1))
3396
+ .replace(/\{class\}/, classname)
3397
+ .replace(/\{content\}/, e.extract[i]));
3398
+ }
3399
+ };
3400
+
3401
+ if (e.stack) {
3402
+ content += '<br/>' + e.stack.split('\n').slice(1).join('<br/>');
3403
+ } else if (e.extract) {
3404
+ errorline(e, 0, '');
3405
+ errorline(e, 1, 'line');
3406
+ errorline(e, 2, '');
3407
+ content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':</p>' +
3408
+ '<ul>' + error.join('') + '</ul>';
3409
+ }
3410
+ elem.innerHTML = content;
3411
+
3412
+ // CSS for error messages
3413
+ createCSS([
3414
+ '.less-error-message ul, .less-error-message li {',
3415
+ 'list-style-type: none;',
3416
+ 'margin-right: 15px;',
3417
+ 'padding: 4px 0;',
3418
+ 'margin: 0;',
3419
+ '}',
3420
+ '.less-error-message label {',
3421
+ 'font-size: 12px;',
3422
+ 'margin-right: 15px;',
3423
+ 'padding: 4px 0;',
3424
+ 'color: #cc7777;',
3425
+ '}',
3426
+ '.less-error-message pre {',
3427
+ 'color: #dd6666;',
3428
+ 'padding: 4px 0;',
3429
+ 'margin: 0;',
3430
+ 'display: inline-block;',
3431
+ '}',
3432
+ '.less-error-message pre.line {',
3433
+ 'color: #ff0000;',
3434
+ '}',
3435
+ '.less-error-message h3 {',
3436
+ 'font-size: 20px;',
3437
+ 'font-weight: bold;',
3438
+ 'padding: 15px 0 5px 0;',
3439
+ 'margin: 0;',
3440
+ '}',
3441
+ '.less-error-message a {',
3442
+ 'color: #10a',
3443
+ '}',
3444
+ '.less-error-message .error {',
3445
+ 'color: red;',
3446
+ 'font-weight: bold;',
3447
+ 'padding-bottom: 2px;',
3448
+ 'border-bottom: 1px dashed red;',
3449
+ '}'
3450
+ ].join('\n'), { title: 'error-message' });
3451
+
3452
+ elem.style.cssText = [
3453
+ "font-family: Arial, sans-serif",
3454
+ "border: 1px solid #e00",
3455
+ "background-color: #eee",
3456
+ "border-radius: 5px",
3457
+ "-webkit-border-radius: 5px",
3458
+ "-moz-border-radius: 5px",
3459
+ "color: #e00",
3460
+ "padding: 15px",
3461
+ "margin-bottom: 15px"
3462
+ ].join(';');
3463
+
3464
+ if (less.env == 'development') {
3465
+ timer = setInterval(function () {
3466
+ if (document.body) {
3467
+ if (document.getElementById(id)) {
3468
+ document.body.replaceChild(elem, document.getElementById(id));
3469
+ } else {
3470
+ document.body.insertBefore(elem, document.body.firstChild);
3471
+ }
3472
+ clearInterval(timer);
3473
+ }
3474
+ }, 10);
3475
+ }
2349
3476
  }
2350
3477
 
2351
- })(require('less/tree'));
2352
- })(this);
3478
+ })(window);