less 3.0.0-pre.2 → 3.0.1

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 (205) hide show
  1. package/.eslintrc.json +88 -0
  2. package/.github/stale.yml +17 -0
  3. package/.project +17 -0
  4. package/.settings/org.eclipse.buildship.core.prefs +2 -0
  5. package/.travis.yml +22 -3
  6. package/.vscode/launch.json +14 -0
  7. package/CHANGELOG.md +27 -0
  8. package/Gruntfile.js +191 -86
  9. package/README.md +5 -7
  10. package/appveyor.yml +9 -10
  11. package/bin/lessc +37 -50
  12. package/dist/less.js +1357 -1269
  13. package/dist/less.min.js +7 -7
  14. package/lib/less/contexts.js +20 -16
  15. package/lib/less/default-options.js +65 -0
  16. package/lib/less/environment/abstract-file-manager.js +13 -14
  17. package/lib/less/environment/abstract-plugin-loader.js +45 -36
  18. package/lib/less/environment/environment.js +5 -0
  19. package/lib/less/functions/boolean.js +15 -0
  20. package/lib/less/functions/color.js +54 -24
  21. package/lib/less/functions/data-uri.js +5 -2
  22. package/lib/less/functions/function-registry.js +1 -1
  23. package/lib/less/functions/index.js +2 -1
  24. package/lib/less/functions/number.js +2 -2
  25. package/lib/less/functions/string.js +2 -2
  26. package/lib/less/functions/svg.js +4 -4
  27. package/lib/less/import-manager.js +41 -29
  28. package/lib/less/index.js +28 -3
  29. package/lib/less/less-error.js +112 -13
  30. package/lib/less/parse.js +18 -15
  31. package/lib/less/parser/parser-input.js +4 -4
  32. package/lib/less/parser/parser.js +208 -114
  33. package/lib/less/plugin-manager.js +8 -33
  34. package/lib/less/render.js +6 -2
  35. package/lib/less/source-map-builder.js +3 -0
  36. package/lib/less/source-map-output.js +13 -8
  37. package/lib/less/transform-tree.js +2 -2
  38. package/lib/less/tree/anonymous.js +4 -1
  39. package/lib/less/tree/atrule.js +7 -6
  40. package/lib/less/tree/call.js +25 -3
  41. package/lib/less/tree/color.js +2 -2
  42. package/lib/less/tree/debug-info.js +1 -1
  43. package/lib/less/tree/declaration.js +6 -5
  44. package/lib/less/tree/dimension.js +4 -1
  45. package/lib/less/tree/extend.js +2 -2
  46. package/lib/less/tree/import.js +17 -9
  47. package/lib/less/tree/index.js +3 -7
  48. package/lib/less/tree/js-eval-node.js +1 -1
  49. package/lib/less/tree/media.js +3 -14
  50. package/lib/less/tree/mixin-definition.js +3 -3
  51. package/lib/less/tree/node.js +9 -6
  52. package/lib/less/tree/operation.js +1 -1
  53. package/lib/less/tree/property.js +70 -0
  54. package/lib/less/tree/quoted.js +11 -10
  55. package/lib/less/tree/ruleset.js +115 -71
  56. package/lib/less/tree/selector.js +38 -23
  57. package/lib/less/tree/unit.js +1 -1
  58. package/lib/less/tree/value.js +6 -1
  59. package/lib/less/tree/{ruleset-call.js → variable-call.js} +5 -5
  60. package/lib/less/tree/variable.js +6 -6
  61. package/lib/less/utils.js +40 -0
  62. package/lib/less/visitors/extend-visitor.js +14 -14
  63. package/lib/less/visitors/import-visitor.js +2 -2
  64. package/lib/less/visitors/join-selector-visitor.js +1 -1
  65. package/lib/less/visitors/to-css-visitor.js +51 -84
  66. package/lib/less/visitors/visitor.js +15 -15
  67. package/lib/less-browser/bootstrap.js +21 -5
  68. package/lib/less-browser/cache.js +2 -2
  69. package/lib/less-browser/error-reporting.js +5 -5
  70. package/lib/less-browser/file-manager.js +27 -35
  71. package/lib/less-browser/index.js +12 -17
  72. package/lib/less-browser/plugin-loader.js +8 -45
  73. package/lib/less-browser/utils.js +1 -1
  74. package/lib/less-node/file-manager.js +99 -69
  75. package/lib/less-node/fs.js +1 -1
  76. package/lib/less-node/image-size.js +2 -2
  77. package/lib/less-node/index.js +7 -57
  78. package/lib/less-node/lessc-helper.js +38 -38
  79. package/lib/less-node/plugin-loader.js +18 -79
  80. package/lib/less-node/url-file-manager.js +1 -1
  81. package/lib/less-rhino/index.js +29 -44
  82. package/package.json +16 -9
  83. package/test/browser/common.js +54 -18
  84. package/test/browser/css/plugin/plugin.css +3 -0
  85. package/test/browser/jasmine-jsreporter.js +4 -4
  86. package/test/browser/less/plugin/plugin.js +7 -0
  87. package/test/browser/less/plugin/plugin.less +4 -0
  88. package/test/browser/less.js +11685 -13
  89. package/test/browser/runner-browser-options.js +6 -1
  90. package/test/browser/runner-filemanagerPlugin-options.js +3 -2
  91. package/test/browser/runner-legacy-options.js +2 -1
  92. package/test/browser/runner-main-options.js +0 -1
  93. package/test/browser/runner-modify-vars-spec.js +2 -2
  94. package/test/browser/test-runner-template.tmpl +38 -14
  95. package/test/copy-bom.js +1 -1
  96. package/test/css/calc.css +5 -0
  97. package/test/css/comments2.css +1 -1
  98. package/test/css/compression/compression.css +1 -1
  99. package/test/css/css-grid.css +11 -0
  100. package/test/css/debug/linenumbers-all.css +0 -1
  101. package/test/css/debug/linenumbers-comments.css +0 -1
  102. package/test/css/debug/linenumbers-mediaquery.css +0 -1
  103. package/test/css/functions.css +16 -3
  104. package/test/css/import-module.css +9 -0
  105. package/test/css/import.css +0 -1
  106. package/test/css/legacy/legacy.css +1 -1
  107. package/test/css/merge.css +5 -4
  108. package/test/css/plugin-module.css +1 -0
  109. package/test/css/plugin.css +20 -0
  110. package/test/css/property-accessors.css +49 -0
  111. package/test/css/{css.css → strict-math/css.css} +0 -0
  112. package/test/css/{mixins-args.css → strict-math/mixins-args.css} +0 -0
  113. package/test/css/{parens.css → strict-math/parens.css} +0 -0
  114. package/test/import-module/one/1.less +3 -0
  115. package/test/import-module/one/two/2.less +3 -0
  116. package/test/import-module/one/two/three/3.less +3 -0
  117. package/test/import-module/package.json +11 -0
  118. package/test/index.js +55 -49
  119. package/test/less/calc.less +7 -0
  120. package/test/less/css-grid.less +15 -0
  121. package/test/less/detached-rulesets.less +2 -2
  122. package/test/less/errors/color-invalid-hex-code.less +1 -0
  123. package/test/less/errors/color-invalid-hex-code.txt +1 -1
  124. package/test/less/errors/color-invalid-hex-code2.less +1 -0
  125. package/test/less/errors/color-invalid-hex-code2.txt +1 -1
  126. package/test/less/errors/import-missing.txt +1 -1
  127. package/test/less/errors/plugin/plugin-error-2.js +5 -0
  128. package/test/less/errors/plugin/plugin-error-3.js +5 -0
  129. package/test/less/errors/plugin/plugin-error.js +1 -0
  130. package/test/less/errors/plugin-1.less +1 -0
  131. package/test/less/errors/plugin-1.txt +2 -0
  132. package/test/less/errors/plugin-2.less +1 -0
  133. package/test/less/errors/plugin-2.txt +5 -0
  134. package/test/less/errors/plugin-3.less +1 -0
  135. package/test/less/errors/plugin-3.txt +5 -0
  136. package/test/less/functions.less +18 -0
  137. package/test/less/import-module.less +3 -0
  138. package/test/less/import.less +0 -2
  139. package/test/less/legacy/legacy.less +1 -1
  140. package/test/less/media.less +2 -2
  141. package/test/less/merge.less +6 -3
  142. package/test/less/plugin/plugin-collection.js +9 -0
  143. package/test/less/plugin/plugin-local.js +2 -2
  144. package/test/less/plugin/plugin-scope1.js +3 -0
  145. package/test/less/plugin/plugin-scope2.js +3 -0
  146. package/test/less/plugin/plugin-simple.js +7 -0
  147. package/test/less/plugin/plugin-tree-nodes.js +33 -31
  148. package/test/less/plugin-module.less +7 -0
  149. package/test/less/plugin.less +33 -3
  150. package/test/less/property-accessors.less +67 -0
  151. package/test/less/root-registry/file.less +1 -0
  152. package/test/less/root-registry/root.less +3 -0
  153. package/test/less/{css.less → strict-math/css.less} +0 -0
  154. package/test/less/{mixins-args.less → strict-math/mixins-args.less} +0 -0
  155. package/test/less/{parens.less → strict-math/parens.less} +0 -0
  156. package/test/less-bom/calc.less +7 -0
  157. package/test/less-bom/css-grid.less +15 -0
  158. package/test/less-bom/detached-rulesets.less +2 -2
  159. package/test/less-bom/errors/color-invalid-hex-code.less +1 -0
  160. package/test/less-bom/errors/color-invalid-hex-code.txt +1 -1
  161. package/test/less-bom/errors/color-invalid-hex-code2.less +1 -0
  162. package/test/less-bom/errors/color-invalid-hex-code2.txt +1 -1
  163. package/test/less-bom/errors/import-missing.txt +1 -1
  164. package/test/less-bom/errors/plugin/plugin-error-2.js +5 -0
  165. package/test/less-bom/errors/plugin/plugin-error-3.js +5 -0
  166. package/test/less-bom/errors/plugin/plugin-error.js +1 -0
  167. package/test/less-bom/errors/plugin-1.less +1 -0
  168. package/test/less-bom/errors/plugin-1.txt +2 -0
  169. package/test/less-bom/errors/plugin-2.less +1 -0
  170. package/test/less-bom/errors/plugin-2.txt +5 -0
  171. package/test/less-bom/errors/plugin-3.less +1 -0
  172. package/test/less-bom/errors/plugin-3.txt +5 -0
  173. package/test/less-bom/functions.less +18 -0
  174. package/test/less-bom/import-module.less +3 -0
  175. package/test/less-bom/import.less +0 -2
  176. package/test/less-bom/legacy/legacy.less +1 -1
  177. package/test/less-bom/media.less +2 -2
  178. package/test/less-bom/merge.less +6 -3
  179. package/test/less-bom/plugin/plugin-collection.js +9 -0
  180. package/test/less-bom/plugin/plugin-local.js +2 -2
  181. package/test/less-bom/plugin/plugin-scope1.js +3 -0
  182. package/test/less-bom/plugin/plugin-scope2.js +3 -0
  183. package/test/less-bom/plugin/plugin-simple.js +7 -0
  184. package/test/less-bom/plugin/plugin-tree-nodes.js +33 -31
  185. package/test/less-bom/plugin-module.less +7 -0
  186. package/test/less-bom/plugin.less +33 -3
  187. package/test/less-bom/property-accessors.less +67 -0
  188. package/test/less-bom/root-registry/file.less +1 -0
  189. package/test/less-bom/root-registry/root.less +3 -0
  190. package/test/less-bom/{css.less → strict-math/css.less} +0 -0
  191. package/test/less-bom/{mixins-args.less → strict-math/mixins-args.less} +0 -0
  192. package/test/less-bom/{parens.less → strict-math/parens.less} +0 -0
  193. package/test/less-test.js +75 -17
  194. package/test/modify-vars.js +1 -1
  195. package/test/plugins/visitor/index.js +1 -1
  196. package/.jscsrc +0 -73
  197. package/.jshintrc +0 -11
  198. package/lib/less/tree/alpha.js +0 -28
  199. package/lib/less/tree/directive.js +0 -12
  200. package/lib/less/tree/rule.js +0 -12
  201. package/test/less/errors/functions-2-alpha.less +0 -2
  202. package/test/less/errors/functions-2-alpha.txt +0 -3
  203. package/test/less-bom/errors/functions-2-alpha.less +0 -2
  204. package/test/less-bom/errors/functions-2-alpha.txt +0 -3
  205. package/test/sourcemaps/maps/import-map.map +0 -1
@@ -14,11 +14,11 @@ var PluginManager = function(less) {
14
14
  };
15
15
 
16
16
  var pm, PluginManagerFactory = function(less, newFactory) {
17
- if (newFactory || !pm) {
18
- pm = new PluginManager(less);
19
- }
20
- return pm;
21
- };
17
+ if (newFactory || !pm) {
18
+ pm = new PluginManager(less);
19
+ }
20
+ return pm;
21
+ };
22
22
 
23
23
  /**
24
24
  * Adds all the plugins in the array
@@ -36,13 +36,13 @@ PluginManager.prototype.addPlugins = function(plugins) {
36
36
  * @param plugin
37
37
  * @param {String} filename
38
38
  */
39
- PluginManager.prototype.addPlugin = function(plugin, filename) {
39
+ PluginManager.prototype.addPlugin = function(plugin, filename, functionRegistry) {
40
40
  this.installedPlugins.push(plugin);
41
41
  if (filename) {
42
42
  this.pluginCache[filename] = plugin;
43
43
  }
44
44
  if (plugin.install) {
45
- plugin.install(this.less, this);
45
+ plugin.install(this.less, this, functionRegistry || this.less.functions.functionRegistry);
46
46
  }
47
47
  };
48
48
  /**
@@ -53,37 +53,12 @@ PluginManager.prototype.get = function(filename) {
53
53
  return this.pluginCache[filename];
54
54
  };
55
55
 
56
- // Object.getPrototypeOf shim for visitor upgrade
57
- if (!Object.getPrototypeOf) {
58
- Object.getPrototypeOf = function getPrototypeOf(object) {
59
- return object.constructor ? object.constructor.prototype : void 0;
60
- };
61
- }
62
-
63
- function upgradeVisitors(visitor, oldType, newType) {
64
-
65
- if (visitor['visit' + oldType] && !visitor['visit' + newType]) {
66
- visitor['visit' + newType] = visitor['visit' + oldType];
67
- }
68
- if (visitor['visit' + oldType + 'Out'] && !visitor['visit' + newType + 'Out']) {
69
- visitor['visit' + newType + 'Out'] = visitor['visit' + oldType + 'Out'];
70
- }
71
- }
72
56
  /**
73
57
  * Adds a visitor. The visitor object has options on itself to determine
74
58
  * when it should run.
75
59
  * @param visitor
76
60
  */
77
61
  PluginManager.prototype.addVisitor = function(visitor) {
78
- var proto;
79
- // 2.x to 3.x visitor compatibility
80
- try {
81
- proto = Object.getPrototypeOf(visitor);
82
- upgradeVisitors(proto, 'Directive', 'AtRule');
83
- upgradeVisitors(proto, 'Rule', 'Declaration');
84
- }
85
- catch(e) {}
86
-
87
62
  this.visitors.push(visitor);
88
63
  };
89
64
  /**
@@ -176,5 +151,5 @@ PluginManager.prototype.getFileManagers = function() {
176
151
  return this.fileManagers;
177
152
  };
178
153
 
179
- //
154
+ //
180
155
  module.exports = PluginManagerFactory;
@@ -1,10 +1,14 @@
1
- var PromiseConstructor;
1
+ var PromiseConstructor,
2
+ utils = require('./utils');
2
3
 
3
4
  module.exports = function(environment, ParseTree, ImportManager) {
4
5
  var render = function (input, options, callback) {
5
6
  if (typeof options === 'function') {
6
7
  callback = options;
7
- options = {};
8
+ options = utils.defaults(this.options, {});
9
+ }
10
+ else {
11
+ options = utils.defaults(this.options, options || {});
8
12
  }
9
13
 
10
14
  if (!callback) {
@@ -26,6 +26,9 @@ module.exports = function (SourceMapOutput, environment) {
26
26
  if (this.options.sourceMapInputFilename) {
27
27
  this.sourceMapInputFilename = sourceMapOutput.normalizeFilename(this.options.sourceMapInputFilename);
28
28
  }
29
+ if (this.options.sourceMapBasepath !== undefined && this.sourceMapURL !== undefined) {
30
+ this.sourceMapURL = sourceMapOutput.removeBasepath(this.sourceMapURL);
31
+ }
29
32
  return css + this.getCSSAppendage();
30
33
  };
31
34
 
@@ -28,21 +28,26 @@ module.exports = function (environment) {
28
28
  this._column = 0;
29
29
  };
30
30
 
31
- SourceMapOutput.prototype.normalizeFilename = function(filename) {
32
- filename = filename.replace(/\\/g, '/');
33
-
34
- if (this._sourceMapBasepath && filename.indexOf(this._sourceMapBasepath) === 0) {
35
- filename = filename.substring(this._sourceMapBasepath.length);
36
- if (filename.charAt(0) === '\\' || filename.charAt(0) === '/') {
37
- filename = filename.substring(1);
31
+ SourceMapOutput.prototype.removeBasepath = function(path) {
32
+ if (this._sourceMapBasepath && path.indexOf(this._sourceMapBasepath) === 0) {
33
+ path = path.substring(this._sourceMapBasepath.length);
34
+ if (path.charAt(0) === '\\' || path.charAt(0) === '/') {
35
+ path = path.substring(1);
38
36
  }
39
37
  }
38
+
39
+ return path;
40
+ };
41
+
42
+ SourceMapOutput.prototype.normalizeFilename = function(filename) {
43
+ filename = filename.replace(/\\/g, '/');
44
+ filename = this.removeBasepath(filename);
40
45
  return (this._sourceMapRootpath || "") + filename;
41
46
  };
42
47
 
43
48
  SourceMapOutput.prototype.add = function(chunk, fileInfo, index, mapLines) {
44
49
 
45
- //ignore adding empty strings
50
+ // ignore adding empty strings
46
51
  if (!chunk) {
47
52
  return;
48
53
  }
@@ -25,8 +25,8 @@ module.exports = function(root, options) {
25
25
  variables = Object.keys(variables).map(function (k) {
26
26
  var value = variables[k];
27
27
 
28
- if (! (value instanceof tree.Value)) {
29
- if (! (value instanceof tree.Expression)) {
28
+ if (!(value instanceof tree.Value)) {
29
+ if (!(value instanceof tree.Expression)) {
30
30
  value = new tree.Expression([value]);
31
31
  }
32
32
  value = new tree.Value([value]);
@@ -21,6 +21,9 @@ Anonymous.prototype.isRulesetLike = function() {
21
21
  return this.rulesetLike;
22
22
  };
23
23
  Anonymous.prototype.genCSS = function (context, output) {
24
- output.add(this.value, this._fileInfo, this._index, this.mapLines);
24
+ this.nodeVisible = Boolean(this.value);
25
+ if (this.nodeVisible) {
26
+ output.add(this.value, this._fileInfo, this._index, this.mapLines);
27
+ }
25
28
  };
26
29
  module.exports = Anonymous;
@@ -1,12 +1,13 @@
1
1
  var Node = require("./node"),
2
2
  Selector = require("./selector"),
3
- Ruleset = require("./ruleset");
3
+ Ruleset = require("./ruleset"),
4
+ Anonymous = require('./anonymous');
4
5
 
5
6
  var AtRule = function (name, value, rules, index, currentFileInfo, debugInfo, isRooted, visibilityInfo) {
6
7
  var i;
7
8
 
8
9
  this.name = name;
9
- this.value = value;
10
+ this.value = (value instanceof Node) ? value : (value ? new Anonymous(value) : value);
10
11
  if (rules) {
11
12
  if (Array.isArray(rules)) {
12
13
  this.rules = rules;
@@ -60,11 +61,11 @@ AtRule.prototype.genCSS = function (context, output) {
60
61
  AtRule.prototype.eval = function (context) {
61
62
  var mediaPathBackup, mediaBlocksBackup, value = this.value, rules = this.rules;
62
63
 
63
- //media stored inside other atrule should not bubble over it
64
- //backpup media bubbling information
64
+ // media stored inside other atrule should not bubble over it
65
+ // backpup media bubbling information
65
66
  mediaPathBackup = context.mediaPath;
66
67
  mediaBlocksBackup = context.mediaBlocks;
67
- //deleted media bubbling information
68
+ // deleted media bubbling information
68
69
  context.mediaPath = [];
69
70
  context.mediaBlocks = [];
70
71
 
@@ -76,7 +77,7 @@ AtRule.prototype.eval = function (context) {
76
77
  rules = [rules[0].eval(context)];
77
78
  rules[0].root = true;
78
79
  }
79
- //restore media bubbling information
80
+ // restore media bubbling information
80
81
  context.mediaPath = mediaPathBackup;
81
82
  context.mediaBlocks = mediaBlocksBackup;
82
83
 
@@ -1,4 +1,5 @@
1
1
  var Node = require("./node"),
2
+ Anonymous = require("./anonymous"),
2
3
  FunctionCaller = require("../functions/function-caller");
3
4
  //
4
5
  // A function call node.
@@ -6,6 +7,7 @@ var Node = require("./node"),
6
7
  var Call = function (name, args, index, currentFileInfo) {
7
8
  this.name = name;
8
9
  this.args = args;
10
+ this.mathOn = name === 'calc' ? false : true;
9
11
  this._index = index;
10
12
  this._fileInfo = currentFileInfo;
11
13
  };
@@ -28,8 +30,16 @@ Call.prototype.accept = function (visitor) {
28
30
  // The function should receive the value, not the variable.
29
31
  //
30
32
  Call.prototype.eval = function (context) {
31
- var args = this.args.map(function (a) { return a.eval(context); }),
32
- result, funcCaller = new FunctionCaller(this.name, context, this.getIndex(), this.fileInfo());
33
+
34
+ /**
35
+ * Turn off math for calc(), and switch back on for evaluating nested functions
36
+ */
37
+ var currentMathContext = context.mathOn;
38
+ context.mathOn = this.mathOn;
39
+ var args = this.args.map(function (a) { return a.eval(context); });
40
+ context.mathOn = currentMathContext;
41
+
42
+ var result, funcCaller = new FunctionCaller(this.name, context, this.getIndex(), this.fileInfo());
33
43
 
34
44
  if (funcCaller.isValid()) {
35
45
  try {
@@ -46,11 +56,23 @@ Call.prototype.eval = function (context) {
46
56
  };
47
57
  }
48
58
 
49
- if (result != null) {
59
+ if (result !== null && result !== undefined) {
60
+ // Results that that are not nodes are cast as Anonymous nodes
61
+ // Falsy values or booleans are returned as empty nodes
62
+ if (!(result instanceof Node)) {
63
+ if (!result || result === true) {
64
+ result = new Anonymous(null);
65
+ }
66
+ else {
67
+ result = new Anonymous(result.toString());
68
+ }
69
+
70
+ }
50
71
  result._index = this._index;
51
72
  result._fileInfo = this._fileInfo;
52
73
  return result;
53
74
  }
75
+
54
76
  }
55
77
 
56
78
  return new Call(this.name, args, this.getIndex(), this.fileInfo());
@@ -132,7 +132,7 @@ Color.prototype.toHSL = function () {
132
132
  }
133
133
  return { h: h * 360, s: s, l: l, a: a };
134
134
  };
135
- //Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
135
+ // Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
136
136
  Color.prototype.toHSV = function () {
137
137
  var r = this.rgb[0] / 255,
138
138
  g = this.rgb[1] / 255,
@@ -152,7 +152,7 @@ Color.prototype.toHSV = function () {
152
152
  if (max === min) {
153
153
  h = 0;
154
154
  } else {
155
- switch(max) {
155
+ switch (max) {
156
156
  case r: h = (g - b) / d + (g < b ? 6 : 0); break;
157
157
  case g: h = (b - r) / d + 2; break;
158
158
  case b: h = (r - g) / d + 4; break;
@@ -1,7 +1,7 @@
1
1
  var debugInfo = function(context, ctx, lineSeparator) {
2
2
  var result = "";
3
3
  if (context.dumpLineNumbers && !context.compress) {
4
- switch(context.dumpLineNumbers) {
4
+ switch (context.dumpLineNumbers) {
5
5
  case 'comments':
6
6
  result = debugInfo.asComment(ctx);
7
7
  break;
@@ -1,10 +1,11 @@
1
1
  var Node = require("./node"),
2
2
  Value = require("./value"),
3
- Keyword = require("./keyword");
3
+ Keyword = require("./keyword"),
4
+ Anonymous = require("./anonymous");
4
5
 
5
6
  var Declaration = function (name, value, important, merge, index, currentFileInfo, inline, variable) {
6
7
  this.name = name;
7
- this.value = (value instanceof Node) ? value : new Value([value]); //value instanceof tree.Value || value instanceof tree.Ruleset ??
8
+ this.value = (value instanceof Node) ? value : new Value([value ? new Anonymous(value) : null]);
8
9
  this.important = important ? ' ' + important.trim() : '';
9
10
  this.merge = merge;
10
11
  this._index = index;
@@ -32,7 +33,7 @@ Declaration.prototype.genCSS = function (context, output) {
32
33
  try {
33
34
  this.value.genCSS(context, output);
34
35
  }
35
- catch(e) {
36
+ catch (e) {
36
37
  e.index = this._index;
37
38
  e.filename = this._fileInfo.filename;
38
39
  throw e;
@@ -58,7 +59,7 @@ Declaration.prototype.eval = function (context) {
58
59
 
59
60
  if (!this.variable && evaldValue.type === "DetachedRuleset") {
60
61
  throw { message: "Rulesets cannot be evaluated on a property.",
61
- index: this.getIndex(), filename: this.fileInfo().filename };
62
+ index: this.getIndex(), filename: this.fileInfo().filename };
62
63
  }
63
64
  var important = this.important,
64
65
  importantResult = context.importantScope.pop();
@@ -73,7 +74,7 @@ Declaration.prototype.eval = function (context) {
73
74
  this.getIndex(), this.fileInfo(), this.inline,
74
75
  variable);
75
76
  }
76
- catch(e) {
77
+ catch (e) {
77
78
  if (typeof e.index !== 'number') {
78
79
  e.index = this.getIndex();
79
80
  e.filename = this.fileInfo().filename;
@@ -8,6 +8,9 @@ var Node = require("./node"),
8
8
  //
9
9
  var Dimension = function (value, unit) {
10
10
  this.value = parseFloat(value);
11
+ if (isNaN(this.value)) {
12
+ throw new Error("Dimension is not a number.");
13
+ }
11
14
  this.unit = (unit && unit instanceof Unit) ? unit :
12
15
  new Unit(unit ? [unit] : undefined);
13
16
  this.setParent(this.unit, this);
@@ -58,7 +61,7 @@ Dimension.prototype.genCSS = function (context, output) {
58
61
  // we default to the first Dimension's unit,
59
62
  // so `1px + 2` will yield `3px`.
60
63
  Dimension.prototype.operate = function (context, op, other) {
61
- /*jshint noempty:false */
64
+ /* jshint noempty:false */
62
65
  var value = this._operate(context, op, this.value, other.value),
63
66
  unit = this.unit.clone();
64
67
 
@@ -11,7 +11,7 @@ var Extend = function Extend(selector, option, index, currentFileInfo, visibilit
11
11
  this.copyVisibilityInfo(visibilityInfo);
12
12
  this.allowRoot = true;
13
13
 
14
- switch(option) {
14
+ switch (option) {
15
15
  case "all":
16
16
  this.allowBefore = true;
17
17
  this.allowAfter = true;
@@ -36,7 +36,7 @@ Extend.prototype.eval = function (context) {
36
36
  Extend.prototype.clone = function (context) {
37
37
  return new Extend(this.selector, this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo());
38
38
  };
39
- //it concatenates (joins) all selectors in selector array
39
+ // it concatenates (joins) all selectors in selector array
40
40
  Extend.prototype.findSelfSelectors = function (selectors) {
41
41
  var selfElements = [],
42
42
  i,
@@ -4,7 +4,8 @@ var Node = require("./node"),
4
4
  Quoted = require("./quoted"),
5
5
  Ruleset = require("./ruleset"),
6
6
  Anonymous = require("./anonymous"),
7
- utils = require("../utils");
7
+ utils = require("../utils"),
8
+ LessError = require("../less-error");
8
9
 
9
10
  //
10
11
  // CSS @import node
@@ -30,7 +31,7 @@ var Import = function (path, features, options, index, currentFileInfo, visibili
30
31
  this.css = !this.options.less || this.options.inline;
31
32
  } else {
32
33
  var pathValue = this.getPath();
33
- if (pathValue && /[#\.\&\?\/]css([\?;].*)?$/.test(pathValue)) {
34
+ if (pathValue && /[#\.\&\?]css([\?;].*)?$/.test(pathValue)) {
34
35
  this.css = true;
35
36
  }
36
37
  }
@@ -116,8 +117,8 @@ Import.prototype.eval = function (context) {
116
117
  if (this.options.reference || this.blocksVisibility()) {
117
118
  if (result.length || result.length === 0) {
118
119
  result.forEach(function (node) {
119
- node.addVisibilityBlock();
120
- }
120
+ node.addVisibilityBlock();
121
+ }
121
122
  );
122
123
  } else {
123
124
  result.addVisibilityBlock();
@@ -131,12 +132,19 @@ Import.prototype.doEval = function (context) {
131
132
 
132
133
  if (this.options.isPlugin) {
133
134
  if (this.root && this.root.eval) {
134
- this.root.eval(context);
135
+ try {
136
+ this.root.eval(context);
137
+ }
138
+ catch (e) {
139
+ e.message = "Plugin error during evaluation";
140
+ throw new LessError(e, this.root.imports, this.root.filename);
141
+ }
135
142
  }
136
143
  registry = context.frames[0] && context.frames[0].functionRegistry;
137
144
  if ( registry && this.root && this.root.functions ) {
138
145
  registry.addMultiple( this.root.functions );
139
146
  }
147
+
140
148
  return [];
141
149
  }
142
150
 
@@ -150,10 +158,10 @@ Import.prototype.doEval = function (context) {
150
158
  }
151
159
  if (this.options.inline) {
152
160
  var contents = new Anonymous(this.root, 0,
153
- {
154
- filename: this.importedFilename,
155
- reference: this.path._fileInfo && this.path._fileInfo.reference
156
- }, true, true);
161
+ {
162
+ filename: this.importedFilename,
163
+ reference: this.path._fileInfo && this.path._fileInfo.reference
164
+ }, true, true);
157
165
 
158
166
  return this.features ? new Media([contents], this.features.value) : [contents];
159
167
  } else if (this.css) {
@@ -1,17 +1,15 @@
1
- var tree = {};
1
+ var tree = Object.create(null);
2
2
 
3
3
  tree.Node = require('./node');
4
- tree.Alpha = require('./alpha');
5
4
  tree.Color = require('./color');
6
5
  tree.AtRule = require('./atrule');
7
- // Backwards compatibility
8
- tree.Directive = require('./directive');
9
6
  tree.DetachedRuleset = require('./detached-ruleset');
10
7
  tree.Operation = require('./operation');
11
8
  tree.Dimension = require('./dimension');
12
9
  tree.Unit = require('./unit');
13
10
  tree.Keyword = require('./keyword');
14
11
  tree.Variable = require('./variable');
12
+ tree.Property = require('./property');
15
13
  tree.Ruleset = require('./ruleset');
16
14
  tree.Element = require('./element');
17
15
  tree.Attribute = require('./attribute');
@@ -20,8 +18,6 @@ tree.Selector = require('./selector');
20
18
  tree.Quoted = require('./quoted');
21
19
  tree.Expression = require('./expression');
22
20
  tree.Declaration = require('./declaration');
23
- // Backwards compatibility
24
- tree.Rule = require('./rule');
25
21
  tree.Call = require('./call');
26
22
  tree.URL = require('./url');
27
23
  tree.Import = require('./import');
@@ -40,6 +36,6 @@ tree.Media = require('./media');
40
36
  tree.UnicodeDescriptor = require('./unicode-descriptor');
41
37
  tree.Negative = require('./negative');
42
38
  tree.Extend = require('./extend');
43
- tree.RulesetCall = require('./ruleset-call');
39
+ tree.VariableCall = require('./variable-call');
44
40
 
45
41
  module.exports = tree;
@@ -31,7 +31,7 @@ JsEvalNode.prototype.evaluateJavaScript = function (expression, context) {
31
31
  var variables = context.frames[0].variables();
32
32
  for (var k in variables) {
33
33
  if (variables.hasOwnProperty(k)) {
34
- /*jshint loopfunc:true */
34
+ /* jshint loopfunc:true */
35
35
  evalContext[k.slice(1)] = {
36
36
  value: variables[k].value,
37
37
  toJS: function () {
@@ -23,7 +23,7 @@ var Media = function (value, features, index, currentFileInfo, visibilityInfo) {
23
23
  };
24
24
  Media.prototype = new AtRule();
25
25
  Media.prototype.type = "Media";
26
- Media.prototype.isRulesetLike = true;
26
+ Media.prototype.isRulesetLike = function() { return true; };
27
27
  Media.prototype.accept = function (visitor) {
28
28
  if (this.features) {
29
29
  this.features = visitor.visit(this.features);
@@ -48,19 +48,8 @@ Media.prototype.eval = function (context) {
48
48
  this.rules[0].debugInfo = this.debugInfo;
49
49
  media.debugInfo = this.debugInfo;
50
50
  }
51
- var strictMathBypass = false;
52
- if (!context.strictMath) {
53
- strictMathBypass = true;
54
- context.strictMath = true;
55
- }
56
- try {
57
- media.features = this.features.eval(context);
58
- }
59
- finally {
60
- if (strictMathBypass) {
61
- context.strictMath = false;
62
- }
63
- }
51
+
52
+ media.features = this.features.eval(context);
64
53
 
65
54
  context.mediaPath.push(media);
66
55
  context.mediaBlocks.push(media);
@@ -43,7 +43,7 @@ Definition.prototype.accept = function (visitor) {
43
43
  }
44
44
  };
45
45
  Definition.prototype.evalParams = function (context, mixinEnv, args, evaldArguments) {
46
- /*jshint boss:true */
46
+ /* jshint boss:true */
47
47
  var frame = new Ruleset(null, null),
48
48
  varargs, arg,
49
49
  params = utils.copyArray(this.params),
@@ -156,7 +156,7 @@ Definition.prototype.evalCall = function (context, args, important) {
156
156
  Definition.prototype.matchCondition = function (args, context) {
157
157
  if (this.condition && !this.condition.eval(
158
158
  new contexts.Eval(context,
159
- [this.evalParams(context, /* the parameter variables*/
159
+ [this.evalParams(context, /* the parameter variables */
160
160
  new contexts.Eval(context, this.frames ? this.frames.concat(context.frames) : context.frames), args, [])]
161
161
  .concat(this.frames || []) // the parent namespace/mixin frames
162
162
  .concat(context.frames)))) { // the current environment frames
@@ -174,7 +174,7 @@ Definition.prototype.matchArgs = function (args, context) {
174
174
  }
175
175
  }, 0);
176
176
 
177
- if (! this.variadic) {
177
+ if (!this.variadic) {
178
178
  if (requiredArgsCnt < this.required) {
179
179
  return false;
180
180
  }
@@ -2,6 +2,8 @@ var Node = function() {
2
2
  this.parent = null;
3
3
  this.visibilityBlocks = undefined;
4
4
  this.nodeVisible = undefined;
5
+ this.rootNode = null;
6
+ this.parsed = null;
5
7
 
6
8
  var self = this;
7
9
  Object.defineProperty(this, "currentFileInfo", {
@@ -31,6 +33,7 @@ Node.prototype.getIndex = function() {
31
33
  Node.prototype.fileInfo = function() {
32
34
  return this._fileInfo || (this.parent && this.parent.fileInfo()) || {};
33
35
  };
36
+ Node.prototype.isRulesetLike = function() { return false; };
34
37
  Node.prototype.toCSS = function (context) {
35
38
  var strs = [];
36
39
  this.genCSS(context, {
@@ -60,8 +63,8 @@ Node.prototype._operate = function (context, op, a, b) {
60
63
  };
61
64
  Node.prototype.fround = function(context, value) {
62
65
  var precision = context && context.numPrecision;
63
- //add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999....) are properly rounded...
64
- return (precision == null) ? value : Number((value + 2e-16).toFixed(precision));
66
+ // add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999...) are properly rounded:
67
+ return (precision) ? Number((value + 2e-16).toFixed(precision)) : value;
65
68
  };
66
69
  Node.compare = function (a, b) {
67
70
  /* returns:
@@ -121,13 +124,13 @@ Node.prototype.removeVisibilityBlock = function () {
121
124
  }
122
125
  this.visibilityBlocks = this.visibilityBlocks - 1;
123
126
  };
124
- //Turns on node visibility - if called node will be shown in output regardless
125
- //of whether it comes from import by reference or not
127
+ // Turns on node visibility - if called node will be shown in output regardless
128
+ // of whether it comes from import by reference or not
126
129
  Node.prototype.ensureVisibility = function () {
127
130
  this.nodeVisible = true;
128
131
  };
129
- //Turns off node visibility - if called node will NOT be shown in output regardless
130
- //of whether it comes from import by reference or not
132
+ // Turns off node visibility - if called node will NOT be shown in output regardless
133
+ // of whether it comes from import by reference or not
131
134
  Node.prototype.ensureInvisibility = function () {
132
135
  this.nodeVisible = false;
133
136
  };
@@ -25,7 +25,7 @@ Operation.prototype.eval = function (context) {
25
25
  }
26
26
  if (!a.operate) {
27
27
  throw { type: "Operation",
28
- message: "Operation on an invalid type" };
28
+ message: "Operation on an invalid type" };
29
29
  }
30
30
 
31
31
  return a.operate(context, this.op, b);
@@ -0,0 +1,70 @@
1
+ var Node = require("./node"),
2
+ Declaration = require("./declaration");
3
+
4
+ var Property = function (name, index, currentFileInfo) {
5
+ this.name = name;
6
+ this._index = index;
7
+ this._fileInfo = currentFileInfo;
8
+ };
9
+ Property.prototype = new Node();
10
+ Property.prototype.type = "Property";
11
+ Property.prototype.eval = function (context) {
12
+ var property, name = this.name;
13
+ // TODO: shorten this reference
14
+ var mergeRules = context.pluginManager.less.visitors.ToCSSVisitor.prototype._mergeRules;
15
+
16
+ if (this.evaluating) {
17
+ throw { type: 'Name',
18
+ message: "Recursive property reference for " + name,
19
+ filename: this.fileInfo().filename,
20
+ index: this.getIndex() };
21
+ }
22
+
23
+ this.evaluating = true;
24
+
25
+ property = this.find(context.frames, function (frame) {
26
+
27
+ var v, vArr = frame.property(name);
28
+ if (vArr) {
29
+ for (var i = 0; i < vArr.length; i++) {
30
+ v = vArr[i];
31
+
32
+ vArr[i] = new Declaration(v.name,
33
+ v.value,
34
+ v.important,
35
+ v.merge,
36
+ v.index,
37
+ v.currentFileInfo,
38
+ v.inline,
39
+ v.variable
40
+ );
41
+ }
42
+ mergeRules(vArr);
43
+
44
+ v = vArr[vArr.length - 1];
45
+ if (v.important) {
46
+ var importantScope = context.importantScope[context.importantScope.length - 1];
47
+ importantScope.important = v.important;
48
+ }
49
+ v = v.value.eval(context);
50
+ return v;
51
+ }
52
+ });
53
+ if (property) {
54
+ this.evaluating = false;
55
+ return property;
56
+ } else {
57
+ throw { type: 'Name',
58
+ message: "Property '" + name + "' is undefined",
59
+ filename: this.currentFileInfo.filename,
60
+ index: this.index };
61
+ }
62
+ };
63
+ Property.prototype.find = function (obj, fun) {
64
+ for (var i = 0, r; i < obj.length; i++) {
65
+ r = fun.call(obj, obj[i]);
66
+ if (r) { return r; }
67
+ }
68
+ return null;
69
+ };
70
+ module.exports = Property;