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
@@ -40,18 +40,18 @@ contexts.Parse = function(options) {
40
40
  };
41
41
 
42
42
  var evalCopyProperties = [
43
- 'paths', // additional include paths
44
- 'compress', // whether to compress
45
- 'ieCompat', // whether to enforce IE compatibility (IE8 data-uri)
46
- 'strictMath', // whether math has to be within parenthesis
47
- 'strictUnits', // whether units need to evaluate correctly
48
- 'sourceMap', // whether to output a source map
49
- 'importMultiple', // whether we are currently importing multiple copies
50
- 'urlArgs', // whether to add args into url tokens
51
- 'javascriptEnabled',// option - whether Inline JavaScript is enabled. if undefined, defaults to false
52
- 'pluginManager', // Used as the plugin manager for the session
53
- 'importantScope' // used to bubble up !important statements
54
- ];
43
+ 'paths', // additional include paths
44
+ 'compress', // whether to compress
45
+ 'ieCompat', // whether to enforce IE compatibility (IE8 data-uri)
46
+ 'strictMath', // whether math has to be within parenthesis
47
+ 'strictUnits', // whether units need to evaluate correctly
48
+ 'sourceMap', // whether to output a source map
49
+ 'importMultiple', // whether we are currently importing multiple copies
50
+ 'urlArgs', // whether to add args into url tokens
51
+ 'javascriptEnabled', // option - whether Inline JavaScript is enabled. if undefined, defaults to false
52
+ 'pluginManager', // Used as the plugin manager for the session
53
+ 'importantScope' // used to bubble up !important statements
54
+ ];
55
55
 
56
56
  contexts.Eval = function(options, frames) {
57
57
  copyFromOriginal(options, this, evalCopyProperties);
@@ -73,7 +73,11 @@ contexts.Eval.prototype.outOfParenthesis = function () {
73
73
  this.parensStack.pop();
74
74
  };
75
75
 
76
+ contexts.Eval.prototype.mathOn = true;
76
77
  contexts.Eval.prototype.isMathOn = function () {
78
+ if (!this.mathOn) {
79
+ return false;
80
+ }
77
81
  return this.strictMath ? (this.parensStack && this.parensStack.length) : true;
78
82
  };
79
83
 
@@ -83,13 +87,13 @@ contexts.Eval.prototype.isPathRelative = function (path) {
83
87
 
84
88
  contexts.Eval.prototype.normalizePath = function( path ) {
85
89
  var
86
- segments = path.split("/").reverse(),
87
- segment;
90
+ segments = path.split("/").reverse(),
91
+ segment;
88
92
 
89
93
  path = [];
90
94
  while (segments.length !== 0 ) {
91
95
  segment = segments.pop();
92
- switch( segment ) {
96
+ switch ( segment ) {
93
97
  case ".":
94
98
  break;
95
99
  case "..":
@@ -108,4 +112,4 @@ contexts.Eval.prototype.normalizePath = function( path ) {
108
112
  return path.join("/");
109
113
  };
110
114
 
111
- //todo - do the same for the toCSS ?
115
+ // todo - do the same for the toCSS ?
@@ -0,0 +1,65 @@
1
+ // Export a new default each time
2
+ module.exports = function() {
3
+ return {
4
+ /* Outputs a makefile import dependency list to stdout. */
5
+ depends: false,
6
+
7
+ /* Compress using less built-in compression.
8
+ * This does an okay job but does not utilise all the tricks of
9
+ * dedicated css compression. */
10
+ compress: false,
11
+
12
+ /* Runs the less parser and just reports errors without any output. */
13
+ lint: false,
14
+
15
+ /* Sets available include paths.
16
+ * If the file in an @import rule does not exist at that exact location,
17
+ * less will look for it at the location(s) passed to this option.
18
+ * You might use this for instance to specify a path to a library which
19
+ * you want to be referenced simply and relatively in the less files. */
20
+ paths: [],
21
+
22
+ /* color output in the terminal */
23
+ color: true,
24
+
25
+ /* The strictImports controls whether the compiler will allow an @import inside of either
26
+ * @media blocks or (a later addition) other selector blocks.
27
+ * See: https://github.com/less/less.js/issues/656 */
28
+ strictImports: false,
29
+
30
+ /* Allow Imports from Insecure HTTPS Hosts */
31
+ insecure: false,
32
+
33
+ /* Allows you to add a path to every generated import and url in your css.
34
+ * This does not affect less import statements that are processed, just ones
35
+ * that are left in the output css. */
36
+ rootpath: '',
37
+
38
+ /* By default URLs are kept as-is, so if you import a file in a sub-directory
39
+ * that references an image, exactly the same URL will be output in the css.
40
+ * This option allows you to re-write URL's in imported files so that the
41
+ * URL is always relative to the base imported file */
42
+ relativeUrls: false,
43
+
44
+ /* Compatibility with IE8. Used for limiting data-uri length */
45
+ ieCompat: false, // true until 3.0
46
+
47
+ /* Without this option on, Less will try and process all math in your css */
48
+ strictMath: false,
49
+
50
+ /* Without this option, less attempts to guess at the output unit when it does maths. */
51
+ strictUnits: false,
52
+
53
+ /* Effectively the declaration is put at the top of your base Less file,
54
+ * meaning it can be used but it also can be overridden if this variable
55
+ * is defined in the file. */
56
+ globalVars: null,
57
+
58
+ /* As opposed to the global variable option, this puts the declaration at the
59
+ * end of your base file, meaning it will override anything defined in your Less file. */
60
+ modifyVars: null,
61
+
62
+ /* This option allows you to specify a argument to go on to every URL. */
63
+ urlArgs: ''
64
+ }
65
+ }
@@ -35,7 +35,7 @@ abstractFileManager.prototype.alwaysMakePathsAbsolute = function() {
35
35
  abstractFileManager.prototype.isPathAbsolute = function(filename) {
36
36
  return (/^(?:[a-z-]+:|\/|\\|#)/i).test(filename);
37
37
  };
38
- // TODO: pull out - this is part of Node & Browserify
38
+ // TODO: pull out / replace?
39
39
  abstractFileManager.prototype.join = function(basePath, laterPath) {
40
40
  if (!basePath) {
41
41
  return laterPath;
@@ -76,7 +76,7 @@ abstractFileManager.prototype.extractUrlParts = function extractUrlParts(url, ba
76
76
 
77
77
  var urlPartsRegex = /^((?:[a-z-]+:)?\/{2}(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i,
78
78
  urlParts = url.match(urlPartsRegex),
79
- returner = {}, directories = [], i, baseUrlParts;
79
+ returner = {}, rawDirectories = [], directories = [], i, baseUrlParts;
80
80
 
81
81
  if (!urlParts) {
82
82
  throw new Error("Could not parse sheet href - '" + url + "'");
@@ -95,27 +95,26 @@ abstractFileManager.prototype.extractUrlParts = function extractUrlParts(url, ba
95
95
  }
96
96
 
97
97
  if (urlParts[3]) {
98
- directories = urlParts[3].replace(/\\/g, "/").split("/");
98
+ rawDirectories = urlParts[3].replace(/\\/g, "/").split("/");
99
99
 
100
- // extract out . before .. so .. doesn't absorb a non-directory
101
- for (i = 0; i < directories.length; i++) {
102
- if (directories[i] === ".") {
103
- directories.splice(i, 1);
104
- i -= 1;
105
- }
106
- }
100
+ // collapse '..' and skip '.'
101
+ for (i = 0; i < rawDirectories.length; i++) {
107
102
 
108
- for (i = 0; i < directories.length; i++) {
109
- if (directories[i] === ".." && i > 0) {
110
- directories.splice(i - 1, 2);
111
- i -= 2;
103
+ if (rawDirectories[i] === "..") {
104
+ directories.pop();
105
+ }
106
+ else if (rawDirectories[i] !== ".") {
107
+ directories.push(rawDirectories[i]);
112
108
  }
109
+
113
110
  }
114
111
  }
115
112
 
116
113
  returner.hostPart = urlParts[1];
117
114
  returner.directories = directories;
115
+ returner.rawPath = (urlParts[1] || "") + rawDirectories.join("/");
118
116
  returner.path = (urlParts[1] || "") + directories.join("/");
117
+ returner.filename = urlParts[4];
119
118
  returner.fileUrl = returner.path + (urlParts[4] || "");
120
119
  returner.url = returner.fileUrl + (urlParts[5] || "");
121
120
  return returner;
@@ -12,13 +12,12 @@ function error(msg, type) {
12
12
  }
13
13
  );
14
14
  }
15
- AbstractPluginLoader.prototype.evalPlugin = function(contents, context, pluginOptions, fileInfo) {
15
+ AbstractPluginLoader.prototype.evalPlugin = function(contents, context, imports, pluginOptions, fileInfo) {
16
16
 
17
17
  var loader,
18
18
  registry,
19
19
  pluginObj,
20
20
  localModule,
21
- localExports,
22
21
  pluginManager,
23
22
  filename;
24
23
 
@@ -32,13 +31,21 @@ AbstractPluginLoader.prototype.evalPlugin = function(contents, context, pluginOp
32
31
  filename = fileInfo.filename;
33
32
  }
34
33
  }
34
+ var shortname = (new this.less.FileManager()).extractUrlParts(filename).filename;
35
+
35
36
  if (filename) {
36
37
  pluginObj = pluginManager.get(filename);
37
38
 
38
39
  if (pluginObj) {
39
- this.trySetOptions(pluginObj, filename, pluginOptions);
40
- if (pluginObj.use) {
41
- pluginObj.use(this.less);
40
+ this.trySetOptions(pluginObj, filename, shortname, pluginOptions);
41
+ try {
42
+ if (pluginObj.use) {
43
+ pluginObj.use.call(this.context, pluginObj);
44
+ }
45
+ }
46
+ catch (e) {
47
+ e.message = 'Error during @plugin call';
48
+ return new this.less.LessError(e, imports, filename);
42
49
  }
43
50
  return pluginObj;
44
51
  }
@@ -48,52 +55,54 @@ AbstractPluginLoader.prototype.evalPlugin = function(contents, context, pluginOp
48
55
  pluginManager: pluginManager,
49
56
  fileInfo: fileInfo
50
57
  };
51
- localExports = localModule.exports;
52
58
  registry = functionRegistry.create();
53
59
 
54
- try {
55
- loader = new Function("module", "require", "functions", "tree", "fileInfo", contents);
56
- pluginObj = loader(localModule, this.require, registry, this.less.tree, fileInfo);
60
+ var registerPlugin = function(obj) {
61
+ pluginObj = obj;
62
+ };
57
63
 
58
- if (!pluginObj) {
59
- pluginObj = localModule.exports;
60
- }
64
+ try {
65
+ loader = new Function("module", "require", "registerPlugin", "functions", "tree", "less", "fileInfo", contents);
66
+ loader(localModule, this.require, registerPlugin, registry, this.less.tree, this.less, fileInfo);
67
+ } catch (e) {
68
+ return new this.less.LessError(e, imports, filename);
69
+ }
61
70
 
62
- pluginObj = this.validatePlugin(pluginObj, filename);
71
+ if (!pluginObj) {
72
+ pluginObj = localModule.exports;
73
+ }
74
+ pluginObj = this.validatePlugin(pluginObj, filename, shortname);
63
75
 
64
- if (pluginObj) {
65
- // Run on first load
66
- pluginManager.addPlugin(pluginObj, fileInfo.filename);
67
- pluginObj.functions = registry.getLocalFunctions();
76
+ if (pluginObj) {
77
+ // Run on first load
78
+ pluginManager.addPlugin(pluginObj, fileInfo.filename, registry);
79
+ pluginObj.functions = registry.getLocalFunctions();
80
+ pluginObj.imports = imports;
81
+ pluginObj.filename = filename;
68
82
 
69
- this.trySetOptions(pluginObj, filename, pluginOptions);
83
+ this.trySetOptions(pluginObj, filename, shortname, pluginOptions);
70
84
 
71
- // Run every @plugin call
85
+ // Run every @plugin call
86
+ try {
72
87
  if (pluginObj.use) {
73
- pluginObj.use(this.less);
88
+ pluginObj.use.call(this.context, pluginObj);
74
89
  }
75
90
  }
76
- else {
77
- throw new SyntaxError("Not a valid plugin");
91
+ catch (e) {
92
+ e.message = 'Error during @plugin call';
93
+ return new this.less.LessError(e, imports, filename);
78
94
  }
79
95
 
80
- } catch(e) {
81
- // TODO pass the error
82
- console.log(e);
83
- return new this.less.LessError({
84
- message: "Plugin evaluation error: '" + e.name + ': ' + e.message.replace(/["]/g, "'") + "'" ,
85
- filename: filename,
86
- line: this.line,
87
- col: this.column
88
- });
96
+ }
97
+ else {
98
+ return new this.less.LessError({ message: "Not a valid plugin" });
89
99
  }
90
100
 
91
101
  return pluginObj;
92
102
 
93
103
  };
94
104
 
95
- AbstractPluginLoader.prototype.trySetOptions = function(plugin, filename, options) {
96
- var name = require('path').basename(filename);
105
+ AbstractPluginLoader.prototype.trySetOptions = function(plugin, filename, name, options) {
97
106
  if (options) {
98
107
  if (!plugin.setOptions) {
99
108
  error("Options have been provided but the plugin " + name + " does not support any options.");
@@ -102,21 +111,21 @@ AbstractPluginLoader.prototype.trySetOptions = function(plugin, filename, option
102
111
  try {
103
112
  plugin.setOptions(options);
104
113
  }
105
- catch(e) {
114
+ catch (e) {
106
115
  error("Error setting options on plugin " + name + '\n' + e.message);
107
116
  return null;
108
117
  }
109
118
  }
110
119
  };
111
120
 
112
- AbstractPluginLoader.prototype.validatePlugin = function(plugin, filename) {
121
+ AbstractPluginLoader.prototype.validatePlugin = function(plugin, filename, name) {
113
122
  if (plugin) {
114
123
  // support plugins being a function
115
124
  // so that the plugin can be more usable programmatically
116
125
  if (typeof plugin === "function") {
117
126
  plugin = new plugin();
118
127
  }
119
- var name = require('path').basename(filename);
128
+
120
129
  if (plugin.minVersion) {
121
130
  if (this.compareVersion(plugin.minVersion, this.less.version) < 0) {
122
131
  error("Plugin " + name + " requires version " + this.versionToString(plugin.minVersion));
@@ -1,3 +1,8 @@
1
+ /**
2
+ * @todo Document why this abstraction exists, and the relationship between
3
+ * environment, file managers, and plugin manager
4
+ */
5
+
1
6
  var logger = require("../logger");
2
7
  var environment = function(externalEnvironment, fileManagers) {
3
8
  this.fileManagers = fileManagers || [];
@@ -0,0 +1,15 @@
1
+
2
+ var functionRegistry = require("./function-registry"),
3
+ Anonymous = require("../tree/anonymous"),
4
+ Keyword = require("../tree/keyword");
5
+
6
+ functionRegistry.addMultiple({
7
+ boolean: function(condition) {
8
+ return condition ? Keyword.True : Keyword.False;
9
+ },
10
+
11
+ 'if': function(condition, trueValue, falseValue) {
12
+ return condition ? trueValue
13
+ : (falseValue || new Anonymous);
14
+ }
15
+ });
@@ -266,43 +266,73 @@ colorFunctions = {
266
266
  greyscale: function (color) {
267
267
  return colorFunctions.desaturate(color, new Dimension(100));
268
268
  },
269
- contrast: function (color, color1, color2, threshold) {
270
- // Return which of `color1` and `color2` has the greatest contrast with `color`
271
- // according to the standard WCAG contrast ratio calculation.
272
- // http://www.w3.org/TR/WCAG20/#contrast-ratiodef
273
- // The threshold param is no longer used, in line with SASS.
269
+ contrast: function (color, dark, light, threshold) {
274
270
  // filter: contrast(3.2);
275
271
  // should be kept as is, so check for color
276
272
  if (!color.rgb) {
277
273
  return null;
278
274
  }
279
- if (typeof color1 === 'undefined') {
280
- color1 = colorFunctions.rgba(0, 0, 0, 1.0);
275
+ if (typeof light === 'undefined') {
276
+ light = colorFunctions.rgba(255, 255, 255, 1.0);
281
277
  }
282
- if (typeof color2 === 'undefined') {
283
- color2 = colorFunctions.rgba(255, 255, 255, 1.0);
278
+ if (typeof dark === 'undefined') {
279
+ dark = colorFunctions.rgba(0, 0, 0, 1.0);
284
280
  }
285
- var contrast1, contrast2;
286
- var luma = color.luma();
287
- var luma1 = color1.luma();
288
- var luma2 = color2.luma();
289
- // Calculate contrast ratios for each color
290
- if (luma > luma1) {
291
- contrast1 = (luma + 0.05) / (luma1 + 0.05);
292
- } else {
293
- contrast1 = (luma1 + 0.05) / (luma + 0.05);
281
+ // Figure out which is actually light and dark:
282
+ if (dark.luma() > light.luma()) {
283
+ var t = light;
284
+ light = dark;
285
+ dark = t;
294
286
  }
295
- if (luma > luma2) {
296
- contrast2 = (luma + 0.05) / (luma2 + 0.05);
287
+ if (typeof threshold === 'undefined') {
288
+ threshold = 0.43;
297
289
  } else {
298
- contrast2 = (luma2 + 0.05) / (luma + 0.05);
290
+ threshold = number(threshold);
299
291
  }
300
- if (contrast1 > contrast2) {
301
- return color1;
292
+ if (color.luma() < threshold) {
293
+ return light;
302
294
  } else {
303
- return color2;
295
+ return dark;
304
296
  }
305
297
  },
298
+ // Changes made in 2.7.0 - Reverted in 3.0.0
299
+ // contrast: function (color, color1, color2, threshold) {
300
+ // // Return which of `color1` and `color2` has the greatest contrast with `color`
301
+ // // according to the standard WCAG contrast ratio calculation.
302
+ // // http://www.w3.org/TR/WCAG20/#contrast-ratiodef
303
+ // // The threshold param is no longer used, in line with SASS.
304
+ // // filter: contrast(3.2);
305
+ // // should be kept as is, so check for color
306
+ // if (!color.rgb) {
307
+ // return null;
308
+ // }
309
+ // if (typeof color1 === 'undefined') {
310
+ // color1 = colorFunctions.rgba(0, 0, 0, 1.0);
311
+ // }
312
+ // if (typeof color2 === 'undefined') {
313
+ // color2 = colorFunctions.rgba(255, 255, 255, 1.0);
314
+ // }
315
+ // var contrast1, contrast2;
316
+ // var luma = color.luma();
317
+ // var luma1 = color1.luma();
318
+ // var luma2 = color2.luma();
319
+ // // Calculate contrast ratios for each color
320
+ // if (luma > luma1) {
321
+ // contrast1 = (luma + 0.05) / (luma1 + 0.05);
322
+ // } else {
323
+ // contrast1 = (luma1 + 0.05) / (luma + 0.05);
324
+ // }
325
+ // if (luma > luma2) {
326
+ // contrast2 = (luma + 0.05) / (luma2 + 0.05);
327
+ // } else {
328
+ // contrast2 = (luma2 + 0.05) / (luma + 0.05);
329
+ // }
330
+ // if (contrast1 > contrast2) {
331
+ // return color1;
332
+ // } else {
333
+ // return color2;
334
+ // }
335
+ // },
306
336
  argb: function (color) {
307
337
  return new Anonymous(color.toARGB());
308
338
  },
@@ -1,6 +1,7 @@
1
1
  module.exports = function(environment) {
2
2
  var Quoted = require("../tree/quoted"),
3
3
  URL = require("../tree/url"),
4
+ utils = require('../utils'),
4
5
  functionRegistry = require("./function-registry"),
5
6
  fallback = function(functionThis, node) {
6
7
  return new URL(node, functionThis.index, functionThis.currentFileInfo).eval(functionThis.context);
@@ -26,8 +27,10 @@ module.exports = function(environment) {
26
27
  fragment = filePath.slice(fragmentStart);
27
28
  filePath = filePath.slice(0, fragmentStart);
28
29
  }
30
+ var context = utils.clone(this.context);
31
+ context.rawBuffer = true;
29
32
 
30
- var fileManager = environment.getFileManager(filePath, currentDirectory, this.context, environment, true);
33
+ var fileManager = environment.getFileManager(filePath, currentDirectory, context, environment, true);
31
34
 
32
35
  if (!fileManager) {
33
36
  return fallback(this, filePathNode);
@@ -53,7 +56,7 @@ module.exports = function(environment) {
53
56
  useBase64 = /;base64$/.test(mimetype);
54
57
  }
55
58
 
56
- var fileSync = fileManager.loadFileSync(filePath, currentDirectory, this.context, environment);
59
+ var fileSync = fileManager.loadFileSync(filePath, currentDirectory, context, environment);
57
60
  if (!fileSync.contents) {
58
61
  logger.warn("Skipped data-uri embedding of " + filePath + " because file not found");
59
62
  return fallback(this, filePathNode || mimetypeNode);
@@ -7,7 +7,7 @@ function makeRegistry( base ) {
7
7
  name = name.toLowerCase();
8
8
 
9
9
  if (this._data.hasOwnProperty(name)) {
10
- //TODO warn
10
+ // TODO warn
11
11
  }
12
12
  this._data[name] = func;
13
13
  },
@@ -4,7 +4,8 @@ module.exports = function(environment) {
4
4
  functionCaller: require("./function-caller")
5
5
  };
6
6
 
7
- //register functions
7
+ // register functions
8
+ require("./boolean");
8
9
  require("./default");
9
10
  require("./color");
10
11
  require("./color-blending");
@@ -5,7 +5,7 @@ var Dimension = require("../tree/dimension"),
5
5
 
6
6
  var minMax = function (isMin, args) {
7
7
  args = Array.prototype.slice.call(args);
8
- switch(args.length) {
8
+ switch (args.length) {
9
9
  case 0: throw { type: "Argument", message: "one or more arguments required" };
10
10
  }
11
11
  var i, j, current, currentUnified, referenceUnified, unit, unitStatic, unitClone,
@@ -27,7 +27,7 @@ var minMax = function (isMin, args) {
27
27
  j = values[""] !== undefined && unit !== "" && unit === unitStatic ? values[""] : values[unit];
28
28
  if (j === undefined) {
29
29
  if (unitStatic !== undefined && unit !== unitStatic) {
30
- throw{ type: "Argument", message: "incompatible types" };
30
+ throw { type: "Argument", message: "incompatible types" };
31
31
  }
32
32
  values[unit] = order.length;
33
33
  order.push(current);
@@ -19,12 +19,12 @@ functionRegistry.addMultiple({
19
19
  result = result.replace(new RegExp(pattern.value, flags ? flags.value : ''), replacement);
20
20
  return new Quoted(string.quote || '', result, string.escaped);
21
21
  },
22
- '%': function (string /* arg, arg, ...*/) {
22
+ '%': function (string /* arg, arg, ... */) {
23
23
  var args = Array.prototype.slice.call(arguments, 1),
24
24
  result = string.value;
25
25
 
26
26
  for (var i = 0; i < args.length; i++) {
27
- /*jshint loopfunc:true */
27
+ /* jshint loopfunc:true */
28
28
  result = result.replace(/%[sda]/i, function(token) {
29
29
  var value = ((args[i].type === "Quoted") &&
30
30
  token.match(/s/i)) ? args[i].value : args[i].toCSS();
@@ -15,12 +15,12 @@ module.exports = function(environment) {
15
15
  renderEnv = {compress: false},
16
16
  returner,
17
17
  directionValue = direction.toCSS(renderEnv),
18
- i, color, position, positionValue, alpha;
18
+ i, color, position, positionValue, alpha;
19
19
 
20
20
  function throwArgumentDescriptor() {
21
21
  throw { type: "Argument",
22
- message: "svg-gradient expects direction, start_color [start_position], [color position,]...," +
23
- " end_color [end_position] or direction, color list" };
22
+ message: "svg-gradient expects direction, start_color [start_position], [color position,]...," +
23
+ " end_color [end_position] or direction, color list" };
24
24
  }
25
25
 
26
26
  if (arguments.length == 2) {
@@ -61,7 +61,7 @@ module.exports = function(environment) {
61
61
  '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">' +
62
62
  '<' + gradientType + 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' + gradientDirectionSvg + '>';
63
63
 
64
- for (i = 0; i < stops.length; i+= 1) {
64
+ for (i = 0; i < stops.length; i += 1) {
65
65
  if (stops[i] instanceof Expression) {
66
66
  color = stops[i].value[0];
67
67
  position = stops[i].value[1];