less 2.0.8 → 2.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/lib/less/js/Makefile +8 -2
  2. data/lib/less/js/benchmark/less-benchmark.js +1 -1
  3. data/lib/less/js/bin/lessc +17 -11
  4. data/lib/less/js/build/amd.js +6 -0
  5. data/lib/less/js/dist/less-1.1.5.min.js +1 -8
  6. data/lib/less/js/dist/less-1.1.6.js +3004 -0
  7. data/lib/less/js/dist/less-1.1.6.min.js +9 -0
  8. data/lib/less/js/dist/less-1.2.0.js +3293 -0
  9. data/lib/less/js/dist/less-1.2.0.min.js +9 -0
  10. data/lib/less/js/dist/less-1.2.1.js +3318 -0
  11. data/lib/less/js/dist/less-1.2.1.min.js +9 -0
  12. data/lib/less/js/lib/less/browser.js +33 -28
  13. data/lib/less/js/lib/less/colors.js +151 -0
  14. data/lib/less/js/lib/less/cssmin.js +355 -0
  15. data/lib/less/js/lib/less/functions.js +49 -6
  16. data/lib/less/js/lib/less/index.js +21 -18
  17. data/lib/less/js/lib/less/parser.js +230 -92
  18. data/lib/less/js/lib/less/rhino.js +3 -1
  19. data/lib/less/js/lib/less/tree.js +6 -2
  20. data/lib/less/js/lib/less/tree/call.js +6 -3
  21. data/lib/less/js/lib/less/tree/condition.js +42 -0
  22. data/lib/less/js/lib/less/tree/dimension.js +15 -0
  23. data/lib/less/js/lib/less/tree/directive.js +8 -2
  24. data/lib/less/js/lib/less/tree/element.js +14 -2
  25. data/lib/less/js/lib/less/tree/expression.js +1 -1
  26. data/lib/less/js/lib/less/tree/import.js +13 -11
  27. data/lib/less/js/lib/less/tree/keyword.js +11 -1
  28. data/lib/less/js/lib/less/tree/mixin.js +31 -13
  29. data/lib/less/js/lib/less/tree/paren.js +16 -0
  30. data/lib/less/js/lib/less/tree/quoted.js +1 -1
  31. data/lib/less/js/lib/less/tree/rule.js +7 -3
  32. data/lib/less/js/lib/less/tree/ruleset.js +7 -4
  33. data/lib/less/js/lib/less/tree/selector.js +5 -0
  34. data/lib/less/js/lib/less/tree/variable.js +4 -2
  35. data/lib/less/js/package.json +1 -1
  36. data/lib/less/js/test/css/colors.css +10 -0
  37. data/lib/less/js/test/css/comments.css +9 -5
  38. data/lib/less/js/test/css/css-3.css +4 -2
  39. data/lib/less/js/test/css/css-escapes.css +1 -1
  40. data/lib/less/js/test/css/css.css +8 -4
  41. data/lib/less/js/test/css/functions.css +13 -0
  42. data/lib/less/js/test/css/import.css +10 -3
  43. data/lib/less/js/test/css/media.css +8 -2
  44. data/lib/less/js/test/css/mixins-args.css +5 -2
  45. data/lib/less/js/test/css/mixins-guards.css +58 -0
  46. data/lib/less/js/test/css/mixins-important.css +17 -0
  47. data/lib/less/js/test/css/mixins.css +2 -1
  48. data/lib/less/js/test/css/operations.css +3 -0
  49. data/lib/less/js/test/css/parens.css +1 -1
  50. data/lib/less/js/test/css/rulesets.css +6 -2
  51. data/lib/less/js/test/css/scope.css +6 -6
  52. data/lib/less/js/test/css/selectors.css +8 -4
  53. data/lib/less/js/test/css/strings.css +6 -4
  54. data/lib/less/js/test/css/variables.css +3 -0
  55. data/lib/less/js/test/css/whitespace.css +5 -3
  56. data/lib/less/js/test/less-test.js +1 -1
  57. data/lib/less/js/test/less/colors.less +13 -0
  58. data/lib/less/js/test/less/comments.less +8 -6
  59. data/lib/less/js/test/less/functions.less +15 -1
  60. data/lib/less/js/test/less/import.less +3 -1
  61. data/lib/less/js/test/less/import/import-test-e.less +2 -0
  62. data/lib/less/js/test/less/media.less +6 -0
  63. data/lib/less/js/test/less/mixins-args.less +6 -0
  64. data/lib/less/js/test/less/mixins-guards.less +94 -0
  65. data/lib/less/js/test/less/mixins-important.less +18 -0
  66. data/lib/less/js/test/less/operations.less +4 -0
  67. data/lib/less/js/test/less/strings.less +2 -0
  68. data/lib/less/js/test/less/variables.less +4 -0
  69. data/lib/less/version.rb +1 -1
  70. metadata +28 -12
@@ -3,7 +3,9 @@ var name;
3
3
  function loadStyleSheet(sheet, callback, reload, remaining) {
4
4
  var sheetName = name.slice(0, name.lastIndexOf('/') + 1) + sheet.href;
5
5
  var input = readFile(sheetName);
6
- var parser = new less.Parser();
6
+ var parser = new less.Parser({
7
+ paths: [sheet.href.replace(/[\w\.-]+$/, '')]
8
+ });
7
9
  parser.parse(input, function (e, root) {
8
10
  if (e) {
9
11
  print("Error: " + e);
@@ -1,13 +1,17 @@
1
- require('./tree').find = function (obj, fun) {
1
+ (function (tree) {
2
+
3
+ tree.find = function (obj, fun) {
2
4
  for (var i = 0, r; i < obj.length; i++) {
3
5
  if (r = fun.call(obj, obj[i])) { return r }
4
6
  }
5
7
  return null;
6
8
  };
7
- require('./tree').jsify = function (obj) {
9
+ tree.jsify = function (obj) {
8
10
  if (Array.isArray(obj.value) && (obj.value.length > 1)) {
9
11
  return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']';
10
12
  } else {
11
13
  return obj.toCSS(false);
12
14
  }
13
15
  };
16
+
17
+ })(require('./tree'));
@@ -3,10 +3,11 @@
3
3
  //
4
4
  // A function call node.
5
5
  //
6
- tree.Call = function (name, args, index) {
6
+ tree.Call = function (name, args, index, filename) {
7
7
  this.name = name;
8
8
  this.args = args;
9
9
  this.index = index;
10
+ this.filename = filename;
10
11
  };
11
12
  tree.Call.prototype = {
12
13
  //
@@ -28,8 +29,10 @@ tree.Call.prototype = {
28
29
  try {
29
30
  return tree.functions[this.name].apply(tree.functions, args);
30
31
  } catch (e) {
31
- throw { message: "error evaluating function `" + this.name + "`",
32
- index: this.index };
32
+ throw { type: e.type || "Runtime",
33
+ message: "error evaluating function `" + this.name + "`" +
34
+ (e.message ? ': ' + e.message : ''),
35
+ index: this.index, filename: this.filename };
33
36
  }
34
37
  } else { // 2.
35
38
  return new(tree.Anonymous)(this.name +
@@ -0,0 +1,42 @@
1
+ (function (tree) {
2
+
3
+ tree.Condition = function (op, l, r, i, negate) {
4
+ this.op = op.trim();
5
+ this.lvalue = l;
6
+ this.rvalue = r;
7
+ this.index = i;
8
+ this.negate = negate;
9
+ };
10
+ tree.Condition.prototype.eval = function (env) {
11
+ var a = this.lvalue.eval(env),
12
+ b = this.rvalue.eval(env);
13
+
14
+ var i = this.index, result;
15
+
16
+ var result = (function (op) {
17
+ switch (op) {
18
+ case 'and':
19
+ return a && b;
20
+ case 'or':
21
+ return a || b;
22
+ default:
23
+ if (a.compare) {
24
+ result = a.compare(b);
25
+ } else if (b.compare) {
26
+ result = b.compare(a);
27
+ } else {
28
+ throw { type: "Type",
29
+ message: "Unable to perform comparison",
30
+ index: i };
31
+ }
32
+ switch (result) {
33
+ case -1: return op === '<' || op === '=<';
34
+ case 0: return op === '=' || op === '>=' || op === '=<';
35
+ case 1: return op === '>' || op === '>=';
36
+ }
37
+ }
38
+ })(this.op);
39
+ return this.negate ? !result : result;
40
+ };
41
+
42
+ })(require('../tree'));
@@ -28,6 +28,21 @@ tree.Dimension.prototype = {
28
28
  return new(tree.Dimension)
29
29
  (tree.operate(op, this.value, other.value),
30
30
  this.unit || other.unit);
31
+ },
32
+
33
+ // TODO: Perform unit conversion before comparing
34
+ compare: function (other) {
35
+ if (other instanceof tree.Dimension) {
36
+ if (other.value > this.value) {
37
+ return -1;
38
+ } else if (other.value < this.value) {
39
+ return 1;
40
+ } else {
41
+ return 0;
42
+ }
43
+ } else {
44
+ return -1;
45
+ }
31
46
  }
32
47
  };
33
48
 
@@ -1,18 +1,23 @@
1
1
  (function (tree) {
2
2
 
3
- tree.Directive = function (name, value) {
3
+ tree.Directive = function (name, value, features) {
4
4
  this.name = name;
5
+ this.features = features && new(tree.Value)(features);
6
+
5
7
  if (Array.isArray(value)) {
6
8
  this.ruleset = new(tree.Ruleset)([], value);
9
+ this.ruleset.allowImports = true;
7
10
  } else {
8
11
  this.value = value;
9
12
  }
10
13
  };
11
14
  tree.Directive.prototype = {
12
15
  toCSS: function (ctx, env) {
16
+ var features = this.features ? ' ' + this.features.toCSS(env) : '';
17
+
13
18
  if (this.ruleset) {
14
19
  this.ruleset.root = true;
15
- return this.name + (env.compress ? '{' : ' {\n ') +
20
+ return this.name + features + (env.compress ? '{' : ' {\n ') +
16
21
  this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') +
17
22
  (env.compress ? '}': '\n}\n');
18
23
  } else {
@@ -20,6 +25,7 @@ tree.Directive.prototype = {
20
25
  }
21
26
  },
22
27
  eval: function (env) {
28
+ this.features = this.features && this.features.eval(env);
23
29
  env.frames.unshift(this);
24
30
  this.ruleset = this.ruleset && this.ruleset.eval(env);
25
31
  env.frames.shift();
@@ -3,11 +3,23 @@
3
3
  tree.Element = function (combinator, value, index) {
4
4
  this.combinator = combinator instanceof tree.Combinator ?
5
5
  combinator : new(tree.Combinator)(combinator);
6
- this.value = value ? value.trim() : "";
6
+
7
+ if (typeof(value) === 'string') {
8
+ this.value = value.trim();
9
+ } else if (value) {
10
+ this.value = value;
11
+ } else {
12
+ this.value = "";
13
+ }
7
14
  this.index = index;
8
15
  };
16
+ tree.Element.prototype.eval = function (env) {
17
+ return new(tree.Element)(this.combinator,
18
+ this.value.eval ? this.value.eval(env) : this.value,
19
+ this.index);
20
+ };
9
21
  tree.Element.prototype.toCSS = function (env) {
10
- return this.combinator.toCSS(env || {}) + this.value;
22
+ return this.combinator.toCSS(env || {}) + (this.value.toCSS ? this.value.toCSS(env) : this.value);
11
23
  };
12
24
 
13
25
  tree.Combinator = function (value) {
@@ -15,7 +15,7 @@ tree.Expression.prototype = {
15
15
  },
16
16
  toCSS: function (env) {
17
17
  return this.value.map(function (e) {
18
- return e.toCSS(env);
18
+ return e.toCSS ? e.toCSS(env) : '';
19
19
  }).join(' ');
20
20
  }
21
21
  };
@@ -11,10 +11,12 @@
11
11
  // `import,push`, we also pass it a callback, which it'll call once
12
12
  // the file has been fetched, and parsed.
13
13
  //
14
- tree.Import = function (path, imports) {
14
+ tree.Import = function (path, imports, features, index) {
15
15
  var that = this;
16
16
 
17
+ this.index = index;
17
18
  this._path = path;
19
+ this.features = features && new(tree.Value)(features);
18
20
 
19
21
  // The '.less' extension is optional
20
22
  if (path instanceof tree.Quoted) {
@@ -27,11 +29,9 @@ tree.Import = function (path, imports) {
27
29
 
28
30
  // Only pre-compile .less files
29
31
  if (! this.css) {
30
- imports.push(this.path, function (root) {
31
- if (! root) {
32
- throw new(Error)("Error parsing " + that.path);
33
- }
34
- that.root = root;
32
+ imports.push(this.path, function (e, root) {
33
+ if (e) { e.index = index }
34
+ that.root = root || new(tree.Ruleset)([], []);
35
35
  });
36
36
  }
37
37
  };
@@ -46,20 +46,22 @@ tree.Import = function (path, imports) {
46
46
  // ruleset.
47
47
  //
48
48
  tree.Import.prototype = {
49
- toCSS: function () {
49
+ toCSS: function (env) {
50
+ var features = this.features ? ' ' + this.features.toCSS(env) : '';
51
+
50
52
  if (this.css) {
51
- return "@import " + this._path.toCSS() + ';\n';
53
+ return "@import " + this._path.toCSS() + features + ';\n';
52
54
  } else {
53
55
  return "";
54
56
  }
55
57
  },
56
58
  eval: function (env) {
57
- var ruleset;
59
+ var ruleset, features = this.features && this.features.eval(env);
58
60
 
59
61
  if (this.css) {
60
62
  return this;
61
63
  } else {
62
- ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0));
64
+ ruleset = new(tree.Ruleset)([], this.root.rules.slice(0));
63
65
 
64
66
  for (var i = 0; i < ruleset.rules.length; i++) {
65
67
  if (ruleset.rules[i] instanceof tree.Import) {
@@ -69,7 +71,7 @@ tree.Import.prototype = {
69
71
  [i, 1].concat(ruleset.rules[i].eval(env)));
70
72
  }
71
73
  }
72
- return ruleset.rules;
74
+ return this.features ? new(tree.Directive)('@media', ruleset.rules, this.features.value) : ruleset.rules;
73
75
  }
74
76
  }
75
77
  };
@@ -3,7 +3,17 @@
3
3
  tree.Keyword = function (value) { this.value = value };
4
4
  tree.Keyword.prototype = {
5
5
  eval: function () { return this },
6
- toCSS: function () { return this.value }
6
+ toCSS: function () { return this.value },
7
+ compare: function (other) {
8
+ if (other instanceof tree.Keyword) {
9
+ return other.value === this.value ? 0 : 1;
10
+ } else {
11
+ return -1;
12
+ }
13
+ }
7
14
  };
8
15
 
16
+ tree.True = new(tree.Keyword)('true');
17
+ tree.False = new(tree.Keyword)('false');
18
+
9
19
  })(require('../tree'));
@@ -1,10 +1,12 @@
1
1
  (function (tree) {
2
2
 
3
3
  tree.mixin = {};
4
- tree.mixin.Call = function (elements, args, index) {
4
+ tree.mixin.Call = function (elements, args, index, filename, important) {
5
5
  this.selector = new(tree.Selector)(elements);
6
6
  this.arguments = args;
7
7
  this.index = index;
8
+ this.filename = filename;
9
+ this.important = important;
8
10
  };
9
11
  tree.mixin.Call.prototype = {
10
12
  eval: function (env) {
@@ -17,34 +19,37 @@ tree.mixin.Call.prototype = {
17
19
  if (mixins[m].match(args, env)) {
18
20
  try {
19
21
  Array.prototype.push.apply(
20
- rules, mixins[m].eval(env, this.arguments).rules);
22
+ rules, mixins[m].eval(env, this.arguments, this.important).rules);
21
23
  match = true;
22
24
  } catch (e) {
23
- throw { message: e.message, index: e.index, stack: e.stack, call: this.index };
25
+ throw { message: e.message, index: e.index, filename: this.filename, stack: e.stack, call: this.index };
24
26
  }
25
27
  }
26
28
  }
27
29
  if (match) {
28
30
  return rules;
29
31
  } else {
30
- throw { message: 'No matching definition was found for `' +
32
+ throw { type: 'Runtime',
33
+ message: 'No matching definition was found for `' +
31
34
  this.selector.toCSS().trim() + '(' +
32
35
  this.arguments.map(function (a) {
33
36
  return a.toCSS();
34
37
  }).join(', ') + ")`",
35
- index: this.index };
38
+ index: this.index, filename: this.filename };
36
39
  }
37
40
  }
38
41
  }
39
- throw { message: this.selector.toCSS().trim() + " is undefined",
40
- index: this.index };
42
+ throw { type: 'Name',
43
+ message: this.selector.toCSS().trim() + " is undefined",
44
+ index: this.index, filename: this.filename };
41
45
  }
42
46
  };
43
47
 
44
- tree.mixin.Definition = function (name, params, rules) {
48
+ tree.mixin.Definition = function (name, params, rules, condition) {
45
49
  this.name = name;
46
50
  this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])];
47
51
  this.params = params;
52
+ this.condition = condition;
48
53
  this.arity = params.length;
49
54
  this.rules = rules;
50
55
  this._lookups = {};
@@ -62,33 +67,46 @@ tree.mixin.Definition.prototype = {
62
67
  find: function () { return this.parent.find.apply(this, arguments) },
63
68
  rulesets: function () { return this.parent.rulesets.apply(this) },
64
69
 
65
- eval: function (env, args) {
66
- var frame = new(tree.Ruleset)(null, []), context, _arguments = [];
70
+ evalParams: function (env, args) {
71
+ var frame = new(tree.Ruleset)(null, []);
67
72
 
68
73
  for (var i = 0, val; i < this.params.length; i++) {
69
74
  if (this.params[i].name) {
70
75
  if (val = (args && args[i]) || this.params[i].value) {
71
76
  frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env)));
72
77
  } else {
73
- throw { message: "wrong number of arguments for " + this.name +
78
+ throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
74
79
  ' (' + args.length + ' for ' + this.arity + ')' };
75
80
  }
76
81
  }
77
82
  }
83
+ return frame;
84
+ },
85
+ eval: function (env, args, important) {
86
+ var frame = this.evalParams(env, args), context, _arguments = [], rules;
87
+
78
88
  for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) {
79
89
  _arguments.push(args[i] || this.params[i].value);
80
90
  }
81
91
  frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
82
92
 
83
- return new(tree.Ruleset)(null, this.rules.slice(0)).eval({
93
+ rules = important ?
94
+ this.rules.map(function (r) {
95
+ return new(tree.Rule)(r.name, r.value, '!important', r.index);
96
+ }) : this.rules.slice(0);
97
+
98
+ return new(tree.Ruleset)(null, rules).eval({
84
99
  frames: [this, frame].concat(this.frames, env.frames)
85
100
  });
86
101
  },
87
102
  match: function (args, env) {
88
- var argsLength = (args && args.length) || 0, len;
103
+ var argsLength = (args && args.length) || 0, len, frame;
89
104
 
90
105
  if (argsLength < this.required) { return false }
91
106
  if ((this.required > 0) && (argsLength > this.params.length)) { return false }
107
+ if (this.condition && !this.condition.eval({
108
+ frames: [this.evalParams(env, args)].concat(env.frames)
109
+ })) { return false }
92
110
 
93
111
  len = Math.min(argsLength, this.arity);
94
112
 
@@ -0,0 +1,16 @@
1
+
2
+ (function (tree) {
3
+
4
+ tree.Paren = function (node) {
5
+ this.value = node;
6
+ };
7
+ tree.Paren.prototype = {
8
+ toCSS: function (env) {
9
+ return '(' + this.value.toCSS(env) + ')';
10
+ },
11
+ eval: function (env) {
12
+ return new(tree.Paren)(this.value.eval(env));
13
+ }
14
+ };
15
+
16
+ })(require('../tree'));
@@ -20,7 +20,7 @@ tree.Quoted.prototype = {
20
20
  return new(tree.JavaScript)(exp, that.index, true).eval(env).value;
21
21
  }).replace(/@\{([\w-]+)\}/g, function (_, name) {
22
22
  var v = new(tree.Variable)('@' + name, that.index).eval(env);
23
- return v.value || v.toCSS();
23
+ return ('value' in v) ? v.value : v.toCSS();
24
24
  });
25
25
  return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index);
26
26
  }
@@ -1,10 +1,11 @@
1
1
  (function (tree) {
2
2
 
3
- tree.Rule = function (name, value, important, index) {
3
+ tree.Rule = function (name, value, important, index, inline) {
4
4
  this.name = name;
5
5
  this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);
6
6
  this.important = important ? ' ' + important.trim() : '';
7
7
  this.index = index;
8
+ this.inline = inline || false;
8
9
 
9
10
  if (name.charAt(0) === '@') {
10
11
  this.variable = true;
@@ -15,12 +16,15 @@ tree.Rule.prototype.toCSS = function (env) {
15
16
  else {
16
17
  return this.name + (env.compress ? ':' : ': ') +
17
18
  this.value.toCSS(env) +
18
- this.important + ";";
19
+ this.important + (this.inline ? "" : ";");
19
20
  }
20
21
  };
21
22
 
22
23
  tree.Rule.prototype.eval = function (context) {
23
- return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index);
24
+ return new(tree.Rule)(this.name,
25
+ this.value.eval(context),
26
+ this.important,
27
+ this.index, this.inline);
24
28
  };
25
29
 
26
30
  tree.Shorthand = function (a, b) {