less 2.1.2 → 2.4.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 (148) hide show
  1. package/.idea/inspectionProfiles/Project_Default.xml +1 -0
  2. package/.idea/jsLinters/jscs.xml +4 -0
  3. package/.idea/jsLinters/jshint.xml +58 -4
  4. package/.idea/workspace.xml +499 -760
  5. package/.jscsrc +73 -0
  6. package/.jshintrc +0 -2
  7. package/.travis.yml +1 -0
  8. package/CHANGELOG.md +59 -0
  9. package/Gruntfile.js +37 -3
  10. package/appveyor.yml +5 -0
  11. package/bin/lessc +383 -316
  12. package/bower.json +1 -1
  13. package/dist/less.js +1638 -1244
  14. package/dist/less.min.js +7 -7
  15. package/lib/less/contexts.js +3 -3
  16. package/lib/less/data/unit-conversions.js +3 -3
  17. package/lib/less/environment/abstract-file-manager.js +8 -8
  18. package/lib/less/environment/environment.js +2 -2
  19. package/lib/less/functions/color-blending.js +3 -3
  20. package/lib/less/functions/color.js +20 -12
  21. package/lib/less/functions/data-uri.js +26 -18
  22. package/lib/less/functions/math.js +1 -1
  23. package/lib/less/functions/number.js +2 -2
  24. package/lib/less/functions/string.js +3 -1
  25. package/lib/less/functions/svg.js +12 -15
  26. package/lib/less/functions/types.js +33 -10
  27. package/lib/less/import-manager.js +14 -9
  28. package/lib/less/index.js +2 -1
  29. package/lib/less/less-error.js +1 -1
  30. package/lib/less/logger.js +2 -2
  31. package/lib/less/parse-tree.js +48 -42
  32. package/lib/less/parse.js +68 -0
  33. package/lib/less/parser/parser-input.js +6 -5
  34. package/lib/less/parser/parser.js +76 -29
  35. package/lib/less/plugin-manager.js +30 -3
  36. package/lib/less/render.js +11 -37
  37. package/lib/less/source-map-builder.js +4 -0
  38. package/lib/less/source-map-output.js +6 -6
  39. package/lib/less/transform-tree.js +4 -4
  40. package/lib/less/tree/anonymous.js +1 -1
  41. package/lib/less/tree/assignment.js +0 -1
  42. package/lib/less/tree/call.js +1 -1
  43. package/lib/less/tree/color.js +6 -6
  44. package/lib/less/tree/condition.js +9 -5
  45. package/lib/less/tree/debug-info.js +6 -2
  46. package/lib/less/tree/dimension.js +5 -5
  47. package/lib/less/tree/directive.js +25 -6
  48. package/lib/less/tree/element.js +1 -1
  49. package/lib/less/tree/expression.js +2 -2
  50. package/lib/less/tree/extend.js +3 -3
  51. package/lib/less/tree/import.js +2 -2
  52. package/lib/less/tree/index.js +1 -0
  53. package/lib/less/tree/javascript.js +2 -2
  54. package/lib/less/tree/media.js +20 -19
  55. package/lib/less/tree/mixin-call.js +5 -6
  56. package/lib/less/tree/mixin-definition.js +33 -11
  57. package/lib/less/tree/quoted.js +3 -3
  58. package/lib/less/tree/rule.js +3 -4
  59. package/lib/less/tree/ruleset.js +290 -177
  60. package/lib/less/tree/selector.js +3 -2
  61. package/lib/less/tree/unit.js +2 -0
  62. package/lib/less/tree/url.js +5 -2
  63. package/lib/less/tree/value.js +2 -2
  64. package/lib/less/tree/variable.js +1 -1
  65. package/lib/less/visitors/extend-visitor.js +72 -36
  66. package/lib/less/visitors/import-sequencer.js +20 -14
  67. package/lib/less/visitors/import-visitor.js +15 -12
  68. package/lib/less/visitors/to-css-visitor.js +41 -9
  69. package/lib/less-browser/add-default-options.js +5 -1
  70. package/lib/less-browser/bootstrap.js +10 -8
  71. package/lib/less-browser/cache.js +3 -3
  72. package/lib/less-browser/file-manager.js +96 -96
  73. package/lib/less-browser/index.js +206 -205
  74. package/lib/less-browser/log-listener.js +2 -2
  75. package/lib/less-browser/utils.js +6 -6
  76. package/lib/less-node/file-manager.js +58 -30
  77. package/lib/less-node/image-size.js +34 -0
  78. package/lib/less-node/index.js +6 -3
  79. package/lib/less-node/lessc-helper.js +3 -2
  80. package/lib/less-node/plugin-loader.js +3 -3
  81. package/lib/less-node/url-file-manager.js +6 -3
  82. package/lib/less-rhino/index.js +15 -13
  83. package/lib/source-map/source-map-0.1.31.js +1 -1
  84. package/package.json +10 -7
  85. package/test/browser/common.js +13 -11
  86. package/test/browser/css/relative-urls/urls.css +1 -0
  87. package/test/browser/css/urls.css +6 -3
  88. package/test/browser/jasmine-jsreporter.js +2 -3
  89. package/test/browser/less/nested-gradient-with-svg-gradient/mixin-consumer.less +5 -0
  90. package/test/browser/less/nested-gradient-with-svg-gradient/svg-gradient-mixin.less +15 -0
  91. package/test/browser/less/relative-urls/urls.less +1 -0
  92. package/test/browser/less/urls.less +1 -0
  93. package/test/browser/runner-browser-options.js +23 -23
  94. package/test/browser/runner-errors-options.js +0 -1
  95. package/test/browser/runner-errors-spec.js +1 -2
  96. package/test/browser/runner-global-vars-spec.js +1 -1
  97. package/test/browser/runner-legacy-options.js +0 -1
  98. package/test/browser/runner-main-options.js +5 -5
  99. package/test/browser/runner-main-spec.js +1 -1
  100. package/test/browser/runner-no-js-errors-spec.js +0 -1
  101. package/test/browser/runner-production-options.js +0 -1
  102. package/test/browser/runner-relative-urls-options.js +0 -1
  103. package/test/browser/runner-rootpath-options.js +0 -1
  104. package/test/browser/runner-rootpath-relative-options.js +0 -1
  105. package/test/browser/runner-strict-units-options.js +0 -1
  106. package/test/copy-bom.js +72 -0
  107. package/test/css/comments.css +1 -0
  108. package/test/css/css-3.css +2 -0
  109. package/test/css/functions.css +10 -0
  110. package/test/css/import-interpolation.css +7 -0
  111. package/test/css/import-reference.css +25 -0
  112. package/test/css/include-path/include-path.css +6 -0
  113. package/test/css/mixins-important.css +12 -0
  114. package/test/css/selectors.css +15 -1
  115. package/test/css/static-urls/urls.css +1 -0
  116. package/test/css/url-args/urls.css +3 -3
  117. package/test/css/urls.css +13 -4
  118. package/test/css/variables.css +7 -1
  119. package/test/data/image.svg +3 -0
  120. package/test/index.js +15 -10
  121. package/test/less/comments.less +1 -0
  122. package/test/less/css-3.less +3 -0
  123. package/test/less/css-guards.less +2 -1
  124. package/test/less/errors/detached-ruleset-2.txt +1 -1
  125. package/test/less/errors/import-missing.txt +1 -1
  126. package/test/less/errors/parens-error-1.txt +1 -1
  127. package/test/less/errors/parens-error-2.txt +1 -1
  128. package/test/less/errors/parens-error-3.txt +1 -1
  129. package/test/less/errors/single-character.less +1 -0
  130. package/test/less/errors/single-character.txt +2 -0
  131. package/test/less/functions.less +18 -0
  132. package/test/less/import/import-interpolation.less +1 -0
  133. package/test/less/import/import-reference.less +38 -0
  134. package/test/less/import/imports/logo.less +1 -0
  135. package/test/less/import-reference.less +3 -1
  136. package/test/less/import.less +2 -0
  137. package/test/less/include-path/include-path.less +6 -0
  138. package/test/less/mixins-important.less +28 -0
  139. package/test/less/nested-gradient-with-svg-gradient/mixin-consumer.less +5 -0
  140. package/test/less/nested-gradient-with-svg-gradient/svg-gradient-mixin.less +15 -0
  141. package/test/less/selectors.less +29 -4
  142. package/test/less/sourcemaps-empty/empty.less +0 -0
  143. package/test/less/sourcemaps-empty/var-defs.less +1 -0
  144. package/test/less/urls.less +10 -1
  145. package/test/less/variables.less +17 -3
  146. package/test/less-test.js +133 -52
  147. package/test/modify-vars.js +14 -12
  148. package/test/browser/less.js +0 -9473
package/bin/lessc CHANGED
@@ -3,8 +3,15 @@
3
3
  var path = require('path'),
4
4
  fs = require('../lib/less-node/fs'),
5
5
  os = require('os'),
6
+ errno,
6
7
  mkdirp;
7
8
 
9
+ try {
10
+ errno = require('errno');
11
+ } catch (err) {
12
+ errno = null;
13
+ }
14
+
8
15
  var less = require('../lib/less-node'),
9
16
  pluginLoader = new less.PluginLoader(less),
10
17
  plugin,
@@ -27,8 +34,8 @@ var silent = false,
27
34
  ieCompat: true,
28
35
  strictMath: false,
29
36
  strictUnits: false,
30
- globalVariables: '',
31
- modifyVariables: '',
37
+ globalVars: null,
38
+ modifyVars: null,
32
39
  urlArgs: '',
33
40
  plugins: plugins
34
41
  };
@@ -52,16 +59,16 @@ var checkArgFunc = function(arg, option) {
52
59
  var checkBooleanArg = function(arg) {
53
60
  var onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg);
54
61
  if (!onOff) {
55
- console.log(" unable to parse "+arg+" as a boolean. use one of on/t/true/y/yes/off/f/false/n/no");
62
+ console.log(" unable to parse " + arg + " as a boolean. use one of on/t/true/y/yes/off/f/false/n/no");
56
63
  continueProcessing = false;
57
64
  return false;
58
65
  }
59
66
  return Boolean(onOff[2]);
60
67
  };
61
68
 
62
- var parseVariableOption = function(option) {
69
+ var parseVariableOption = function(option, variables) {
63
70
  var parts = option.split('=', 2);
64
- return '@' + parts[0] + ': ' + parts[1] + ';\n';
71
+ variables[parts[0]] = parts[1];
65
72
  };
66
73
 
67
74
  var warningMessages = "";
@@ -73,351 +80,411 @@ function printUsage() {
73
80
  continueProcessing = false;
74
81
  }
75
82
 
76
- args = args.filter(function (arg) {
77
- var match;
83
+ // self executing function so we can return
84
+ (function() {
85
+ args = args.filter(function (arg) {
86
+ var match;
78
87
 
79
- match = arg.match(/^-I(.+)$/);
80
- if (match) {
81
- options.paths.push(match[1]);
82
- return false;
83
- }
88
+ match = arg.match(/^-I(.+)$/);
89
+ if (match) {
90
+ options.paths.push(match[1]);
91
+ return false;
92
+ }
84
93
 
85
- match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i);
86
- if (match) { arg = match[1]; }
87
- else { return arg; }
88
-
89
- switch (arg) {
90
- case 'v':
91
- case 'version':
92
- console.log("lessc " + less.version.join('.') + " (Less Compiler) [JavaScript]");
93
- continueProcessing = false;
94
- break;
95
- case 'verbose':
96
- verbose = true;
97
- break;
98
- case 's':
99
- case 'silent':
100
- silent = true;
101
- break;
102
- case 'l':
103
- case 'lint':
104
- options.lint = true;
105
- break;
106
- case 'strict-imports':
107
- options.strictImports = true;
108
- break;
109
- case 'h':
110
- case 'help':
111
- printUsage();
112
- break;
113
- case 'x':
114
- case 'compress':
115
- options.compress = true;
116
- break;
117
- case 'insecure':
118
- options.insecure = true;
119
- break;
120
- case 'M':
121
- case 'depends':
122
- options.depends = true;
123
- break;
124
- case 'max-line-len':
125
- if (checkArgFunc(arg, match[2])) {
126
- options.maxLineLen = parseInt(match[2], 10);
127
- if (options.maxLineLen <= 0) {
128
- options.maxLineLen = -1;
129
- }
130
- }
131
- break;
132
- case 'no-color':
133
- options.color = false;
134
- break;
135
- case 'no-ie-compat':
136
- options.ieCompat = false;
137
- break;
138
- case 'no-js':
139
- options.javascriptEnabled = false;
140
- break;
141
- case 'include-path':
142
- if (checkArgFunc(arg, match[2])) {
143
- options.paths = match[2].split(os.type().match(/Windows/) ? ';' : ':')
144
- .map(function(p) {
145
- if (p) {
146
- return path.resolve(process.cwd(), p);
147
- }
148
- });
149
- }
150
- break;
151
- case 'line-numbers':
152
- if (checkArgFunc(arg, match[2])) {
153
- options.dumpLineNumbers = match[2];
154
- }
155
- break;
156
- case 'source-map':
157
- options.sourceMap = true;
158
- if (match[2]) {
159
- sourceMapOptions.sourceMapFullFilename = match[2];
160
- }
161
- break;
162
- case 'source-map-rootpath':
163
- if (checkArgFunc(arg, match[2])) {
164
- sourceMapOptions.sourceMapRootpath = match[2];
165
- }
166
- break;
167
- case 'source-map-basepath':
168
- if (checkArgFunc(arg, match[2])) {
169
- sourceMapOptions.sourceMapBasepath = match[2];
170
- }
171
- break;
172
- case 'source-map-map-inline':
173
- sourceMapFileInline = true;
174
- options.sourceMap = true;
175
- break;
176
- case 'source-map-less-inline':
177
- sourceMapOptions.outputSourceFiles = true;
178
- break;
179
- case 'source-map-url':
180
- if (checkArgFunc(arg, match[2])) {
181
- sourceMapOptions.sourceMapURL = match[2];
182
- }
183
- break;
184
- case 'rp':
185
- case 'rootpath':
186
- if (checkArgFunc(arg, match[2])) {
187
- options.rootpath = match[2].replace(/\\/g, '/');
188
- }
189
- break;
190
- case "ru":
191
- case "relative-urls":
192
- options.relativeUrls = true;
193
- break;
194
- case "sm":
195
- case "strict-math":
196
- if (checkArgFunc(arg, match[2])) {
197
- options.strictMath = checkBooleanArg(match[2]);
198
- }
199
- break;
200
- case "su":
201
- case "strict-units":
202
- if (checkArgFunc(arg, match[2])) {
203
- options.strictUnits = checkBooleanArg(match[2]);
204
- }
205
- break;
206
- case "global-var":
207
- if (checkArgFunc(arg, match[2])) {
208
- options.globalVariables += parseVariableOption(match[2]);
209
- }
210
- break;
211
- case "modify-var":
212
- if (checkArgFunc(arg, match[2])) {
213
- options.modifyVariables += parseVariableOption(match[2]);
214
- }
215
- break;
216
- case 'url-args':
217
- if (checkArgFunc(arg, match[2])) {
218
- options.urlArgs = match[2];
219
- }
220
- break;
221
- case 'plugin':
222
- var splitupArg = match[2].match(/^([^=]+)(=(.*))?/),
223
- name = splitupArg[1],
224
- pluginOptions = splitupArg[3];
225
-
226
- plugin = pluginLoader.tryLoadPlugin(name, pluginOptions);
227
- if (plugin) {
228
- plugins.push(plugin);
229
- } else {
230
- console.log("Unable to load plugin " + name + " please make sure that it is installed under or at the same level as less");
231
- console.log();
232
- printUsage();
233
- currentErrorcode = 1;
234
- }
235
- break;
236
- default:
237
- plugin = pluginLoader.tryLoadPlugin("less-plugin-" + arg, match[2]);
238
- if (plugin) {
239
- plugins.push(plugin);
240
- } else {
241
- console.log("Unable to interpret argument " + arg + " - if it is a plugin (less-plugin-" + arg + "), make sure that it is installed under or at the same level as less");
242
- console.log();
94
+ match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i);
95
+ if (match) {
96
+ arg = match[1];
97
+ } else {
98
+ return arg;
99
+ }
100
+
101
+ switch (arg) {
102
+ case 'v':
103
+ case 'version':
104
+ console.log("lessc " + less.version.join('.') + " (Less Compiler) [JavaScript]");
105
+ continueProcessing = false;
106
+ break;
107
+ case 'verbose':
108
+ verbose = true;
109
+ break;
110
+ case 's':
111
+ case 'silent':
112
+ silent = true;
113
+ break;
114
+ case 'l':
115
+ case 'lint':
116
+ options.lint = true;
117
+ break;
118
+ case 'strict-imports':
119
+ options.strictImports = true;
120
+ break;
121
+ case 'h':
122
+ case 'help':
243
123
  printUsage();
244
- currentErrorcode = 1;
245
- }
246
- break;
247
- }
248
- });
124
+ break;
125
+ case 'x':
126
+ case 'compress':
127
+ options.compress = true;
128
+ break;
129
+ case 'insecure':
130
+ options.insecure = true;
131
+ break;
132
+ case 'M':
133
+ case 'depends':
134
+ options.depends = true;
135
+ break;
136
+ case 'max-line-len':
137
+ if (checkArgFunc(arg, match[2])) {
138
+ options.maxLineLen = parseInt(match[2], 10);
139
+ if (options.maxLineLen <= 0) {
140
+ options.maxLineLen = -1;
141
+ }
142
+ }
143
+ break;
144
+ case 'no-color':
145
+ options.color = false;
146
+ break;
147
+ case 'no-ie-compat':
148
+ options.ieCompat = false;
149
+ break;
150
+ case 'no-js':
151
+ options.javascriptEnabled = false;
152
+ break;
153
+ case 'include-path':
154
+ if (checkArgFunc(arg, match[2])) {
155
+ options.paths = match[2].split(os.type().match(/Windows/) ? ';' : ':')
156
+ .map(function(p) {
157
+ if (p) {
158
+ return path.resolve(process.cwd(), p);
159
+ }
160
+ });
161
+ }
162
+ break;
163
+ case 'line-numbers':
164
+ if (checkArgFunc(arg, match[2])) {
165
+ options.dumpLineNumbers = match[2];
166
+ }
167
+ break;
168
+ case 'source-map':
169
+ options.sourceMap = true;
170
+ if (match[2]) {
171
+ sourceMapOptions.sourceMapFullFilename = match[2];
172
+ }
173
+ break;
174
+ case 'source-map-rootpath':
175
+ if (checkArgFunc(arg, match[2])) {
176
+ sourceMapOptions.sourceMapRootpath = match[2];
177
+ }
178
+ break;
179
+ case 'source-map-basepath':
180
+ if (checkArgFunc(arg, match[2])) {
181
+ sourceMapOptions.sourceMapBasepath = match[2];
182
+ }
183
+ break;
184
+ case 'source-map-map-inline':
185
+ sourceMapFileInline = true;
186
+ options.sourceMap = true;
187
+ break;
188
+ case 'source-map-less-inline':
189
+ sourceMapOptions.outputSourceFiles = true;
190
+ break;
191
+ case 'source-map-url':
192
+ if (checkArgFunc(arg, match[2])) {
193
+ sourceMapOptions.sourceMapURL = match[2];
194
+ }
195
+ break;
196
+ case 'rp':
197
+ case 'rootpath':
198
+ if (checkArgFunc(arg, match[2])) {
199
+ options.rootpath = match[2].replace(/\\/g, '/');
200
+ }
201
+ break;
202
+ case "ru":
203
+ case "relative-urls":
204
+ options.relativeUrls = true;
205
+ break;
206
+ case "sm":
207
+ case "strict-math":
208
+ if (checkArgFunc(arg, match[2])) {
209
+ options.strictMath = checkBooleanArg(match[2]);
210
+ }
211
+ break;
212
+ case "su":
213
+ case "strict-units":
214
+ if (checkArgFunc(arg, match[2])) {
215
+ options.strictUnits = checkBooleanArg(match[2]);
216
+ }
217
+ break;
218
+ case "global-var":
219
+ if (checkArgFunc(arg, match[2])) {
220
+ if (!options.globalVars) {
221
+ options.globalVars = {};
222
+ }
223
+ parseVariableOption(match[2], options.globalVars);
224
+ }
225
+ break;
226
+ case "modify-var":
227
+ if (checkArgFunc(arg, match[2])) {
228
+ if (!options.modifyVars) {
229
+ options.modifyVars = {};
230
+ }
249
231
 
250
- if (!continueProcessing) {
251
- return;
252
- }
232
+ parseVariableOption(match[2], options.modifyVars);
233
+ }
234
+ break;
235
+ case 'url-args':
236
+ if (checkArgFunc(arg, match[2])) {
237
+ options.urlArgs = match[2];
238
+ }
239
+ break;
240
+ case 'plugin':
241
+ var splitupArg = match[2].match(/^([^=]+)(=(.*))?/),
242
+ name = splitupArg[1],
243
+ pluginOptions = splitupArg[3];
244
+
245
+ plugin = pluginLoader.tryLoadPlugin(name, pluginOptions);
246
+ if (plugin) {
247
+ plugins.push(plugin);
248
+ } else {
249
+ console.log("Unable to load plugin " + name +
250
+ " please make sure that it is installed under or at the same level as less");
251
+ console.log();
252
+ printUsage();
253
+ currentErrorcode = 1;
254
+ }
255
+ break;
256
+ default:
257
+ plugin = pluginLoader.tryLoadPlugin("less-plugin-" + arg, match[2]);
258
+ if (plugin) {
259
+ plugins.push(plugin);
260
+ } else {
261
+ console.log("Unable to interpret argument " + arg +
262
+ " - if it is a plugin (less-plugin-" + arg + "), make sure that it is installed under or at" +
263
+ " the same level as less");
264
+ console.log();
265
+ printUsage();
266
+ currentErrorcode = 1;
267
+ }
268
+ break;
269
+ }
270
+ });
253
271
 
254
- var input = args[1];
255
- if (input && input != '-') {
256
- input = path.resolve(process.cwd(), input);
257
- }
258
- var output = args[2];
259
- var outputbase = args[2];
260
- if (output) {
261
- output = path.resolve(process.cwd(), output);
262
- if (warningMessages) {
263
- console.log(warningMessages);
272
+ if (!continueProcessing) {
273
+ return;
264
274
  }
265
- }
266
275
 
267
- if (options.sourceMap) {
268
-
269
- sourceMapOptions.sourceMapInputFilename = input;
270
- if (!sourceMapOptions.sourceMapFullFilename) {
271
- if (!output && !sourceMapFileInline) {
272
- console.log("the sourcemap option only has an optional filename if the css filename is given");
273
- console.log("consider adding --source-map-map-inline which embeds the sourcemap into the css");
274
- return;
276
+ var input = args[1];
277
+ if (input && input != '-') {
278
+ input = path.resolve(process.cwd(), input);
279
+ }
280
+ var output = args[2];
281
+ var outputbase = args[2];
282
+ if (output) {
283
+ output = path.resolve(process.cwd(), output);
284
+ if (warningMessages) {
285
+ console.log(warningMessages);
275
286
  }
276
- // its in the same directory, so always just the basename
277
- sourceMapOptions.sourceMapOutputFilename = path.basename(output);
278
- sourceMapOptions.sourceMapFullFilename = output + ".map";
279
- // its in the same directory, so always just the basename
280
- sourceMapOptions.sourceMapFilename = path.basename(sourceMapOptions.sourceMapFullFilename);
281
- } else if (options.sourceMap && !sourceMapFileInline) {
282
- var mapFilename = path.resolve(process.cwd(), sourceMapOptions.sourceMapFullFilename),
283
- mapDir = path.dirname(mapFilename),
284
- outputDir = path.dirname(output);
285
- // find the path from the map to the output file
286
- sourceMapOptions.sourceMapOutputFilename = path.join(
287
- path.relative(mapDir, outputDir), path.basename(output));
288
-
289
- // make the sourcemap filename point to the sourcemap relative to the css file output directory
290
- sourceMapOptions.sourceMapFilename = path.join(
291
- path.relative(outputDir, mapDir), path.basename(sourceMapOptions.sourceMapFullFilename));
292
287
  }
293
- }
294
288
 
295
- if (sourceMapOptions.sourceMapBasepath === undefined) {
296
- sourceMapOptions.sourceMapBasepath = input ? path.dirname(input) : process.cwd();
297
- }
298
-
299
- if (sourceMapOptions.sourceMapRootpath === undefined) {
300
- var pathToMap = path.dirname(sourceMapFileInline ? output : sourceMapOptions.sourceMapFullFilename),
301
- pathToInput = path.dirname(sourceMapOptions.sourceMapInputFilename);
302
- sourceMapOptions.sourceMapRootpath = path.relative(pathToMap, pathToInput);
303
- }
304
-
305
-
306
- if (! input) {
307
- console.log("lessc: no input files");
308
- console.log("");
309
- printUsage();
310
- currentErrorcode = 1;
311
- return;
312
- }
289
+ if (options.sourceMap) {
313
290
 
314
- var ensureDirectory = function (filepath) {
315
- var dir = path.dirname(filepath),
316
- cmd,
317
- existsSync = fs.existsSync || path.existsSync;
318
- if (!existsSync(dir)) {
319
- if (mkdirp === undefined) {
320
- try {mkdirp = require('mkdirp');}
321
- catch(e) { mkdirp = null; }
291
+ sourceMapOptions.sourceMapInputFilename = input;
292
+ if (!sourceMapOptions.sourceMapFullFilename) {
293
+ if (!output && !sourceMapFileInline) {
294
+ console.log("the sourcemap option only has an optional filename if the css filename is given");
295
+ console.log("consider adding --source-map-map-inline which embeds the sourcemap into the css");
296
+ return;
297
+ }
298
+ // its in the same directory, so always just the basename
299
+ sourceMapOptions.sourceMapOutputFilename = path.basename(output);
300
+ sourceMapOptions.sourceMapFullFilename = output + ".map";
301
+ // its in the same directory, so always just the basename
302
+ sourceMapOptions.sourceMapFilename = path.basename(sourceMapOptions.sourceMapFullFilename);
303
+ } else if (options.sourceMap && !sourceMapFileInline) {
304
+ var mapFilename = path.resolve(process.cwd(), sourceMapOptions.sourceMapFullFilename),
305
+ mapDir = path.dirname(mapFilename),
306
+ outputDir = path.dirname(output);
307
+ // find the path from the map to the output file
308
+ sourceMapOptions.sourceMapOutputFilename = path.join(
309
+ path.relative(mapDir, outputDir), path.basename(output));
310
+
311
+ // make the sourcemap filename point to the sourcemap relative to the css file output directory
312
+ sourceMapOptions.sourceMapFilename = path.join(
313
+ path.relative(outputDir, mapDir), path.basename(sourceMapOptions.sourceMapFullFilename));
322
314
  }
323
- cmd = mkdirp && mkdirp.sync || fs.mkdirSync;
324
- cmd(dir);
325
315
  }
326
- };
327
316
 
328
- if (options.depends) {
329
- if (!outputbase) {
330
- console.log("option --depends requires an output path to be specified");
331
- return;
317
+ if (sourceMapOptions.sourceMapBasepath === undefined) {
318
+ sourceMapOptions.sourceMapBasepath = input ? path.dirname(input) : process.cwd();
332
319
  }
333
- process.stdout.write(outputbase + ": ");
334
- }
335
320
 
336
- if (!sourceMapFileInline) {
337
- var writeSourceMap = function(output) {
338
- var filename = sourceMapOptions.sourceMapFullFilename;
339
- ensureDirectory(filename);
340
- fs.writeFileSync(filename, output, 'utf8');
341
- };
342
- }
321
+ if (sourceMapOptions.sourceMapRootpath === undefined) {
322
+ var pathToMap = path.dirname(sourceMapFileInline ? output : sourceMapOptions.sourceMapFullFilename),
323
+ pathToInput = path.dirname(sourceMapOptions.sourceMapInputFilename);
324
+ sourceMapOptions.sourceMapRootpath = path.relative(pathToMap, pathToInput);
325
+ }
343
326
 
344
- var parseLessFile = function (e, data) {
345
- if (e) {
346
- console.log("lessc: " + e.message);
327
+ if (! input) {
328
+ console.log("lessc: no input files");
329
+ console.log("");
330
+ printUsage();
347
331
  currentErrorcode = 1;
348
332
  return;
349
333
  }
350
334
 
351
- data = options.globalVariables + data + '\n' + options.modifyVariables;
352
-
353
- options.paths = [path.dirname(input)].concat(options.paths);
354
- options.filename = input;
335
+ var ensureDirectory = function (filepath) {
336
+ var dir = path.dirname(filepath),
337
+ cmd,
338
+ existsSync = fs.existsSync || path.existsSync;
339
+ if (!existsSync(dir)) {
340
+ if (mkdirp === undefined) {
341
+ try {mkdirp = require('mkdirp');}
342
+ catch(e) { mkdirp = null; }
343
+ }
344
+ cmd = mkdirp && mkdirp.sync || fs.mkdirSync;
345
+ cmd(dir);
346
+ }
347
+ };
355
348
 
356
- if (options.lint) {
357
- options.sourceMap = false;
349
+ if (options.depends) {
350
+ if (!outputbase) {
351
+ console.log("option --depends requires an output path to be specified");
352
+ return;
353
+ }
354
+ process.stdout.write(outputbase + ": ");
358
355
  }
359
- sourceMapOptions.sourceMapFileInline = sourceMapFileInline;
360
356
 
361
- if (options.sourceMap) {
362
- options.sourceMap = sourceMapOptions;
357
+ if (!sourceMapFileInline) {
358
+ var writeSourceMap = function(output, onDone) {
359
+ var filename = sourceMapOptions.sourceMapFullFilename;
360
+ ensureDirectory(filename);
361
+ fs.writeFile(filename, output, 'utf8', function (err) {
362
+ if (err) {
363
+ var description = "Error: ";
364
+ if (errno && errno.errno[err.errno]) {
365
+ description += errno.errno[err.errno].description;
366
+ } else {
367
+ description += err.code + " " + err.message;
368
+ }
369
+ less.logger.error('lessc: failed to create file ' + filename);
370
+ less.logger.error(description);
371
+ } else {
372
+ less.logger.info('lessc: wrote ' + filename);
373
+ }
374
+ onDone();
375
+ });
376
+ };
363
377
  }
364
378
 
365
- less.logger.addListener({
366
- info: function(msg) {
367
- if (verbose) {
368
- console.log(msg);
369
- }
370
- },
371
- warn: function(msg) {
372
- if (!silent) {
373
- console.warn(msg);
374
- }
375
- },
376
- error: function(msg) {
377
- console.log(msg);
379
+ var writeSourceMapIfNeeded = function(output, onDone) {
380
+ if (options.sourceMap && !sourceMapFileInline) {
381
+ writeSourceMap(output, onDone);
382
+ } else {
383
+ onDone();
378
384
  }
379
- });
385
+ };
380
386
 
381
- less.render(data, options)
382
- .then(function(result) {
383
- if(!options.lint) {
384
- if (output) {
385
- ensureDirectory(output);
386
- fs.writeFileSync(output, result.css, 'utf8');
387
+ var writeOutput = function(output, result, onSuccess) {
388
+ if (output) {
389
+ ensureDirectory(output);
390
+ fs.writeFile(output, result.css, {encoding: 'utf8'}, function (err) {
391
+ if (err) {
392
+ var description = "Error: ";
393
+ if (errno && errno.errno[err.errno]) {
394
+ description += errno.errno[err.errno].description;
395
+ } else {
396
+ description += err.code + " " + err.message;
397
+ }
398
+ less.logger.error('lessc: failed to create file ' + output);
399
+ less.logger.error(description);
400
+ } else {
387
401
  less.logger.info('lessc: wrote ' + output);
388
- } else if (!options.depends) {
389
- process.stdout.write(result.css);
402
+ onSuccess();
390
403
  }
391
- if (options.sourceMap && !sourceMapFileInline) {
392
- writeSourceMap(result.map);
404
+ });
405
+ } else if (!options.depends) {
406
+ process.stdout.write(result.css);
407
+ onSuccess();
408
+ }
409
+ };
410
+
411
+ var logDependencies = function(options, result) {
412
+ if (options.depends) {
413
+ var depends = "";
414
+ for (var i = 0; i < result.imports.length; i++) {
415
+ depends += result.imports[i] + " ";
416
+ }
417
+ console.log(depends);
418
+ }
419
+ };
420
+
421
+ var parseLessFile = function (e, data) {
422
+ if (e) {
423
+ console.log("lessc: " + e.message);
424
+ currentErrorcode = 1;
425
+ return;
426
+ }
427
+
428
+ data = data.replace(/^\uFEFF/, '');
429
+
430
+ options.paths = [path.dirname(input)].concat(options.paths);
431
+ options.filename = input;
432
+
433
+ if (options.lint) {
434
+ options.sourceMap = false;
435
+ }
436
+ sourceMapOptions.sourceMapFileInline = sourceMapFileInline;
437
+
438
+ if (options.sourceMap) {
439
+ options.sourceMap = sourceMapOptions;
440
+ }
441
+
442
+ less.logger.addListener({
443
+ info: function(msg) {
444
+ if (verbose) {
445
+ console.log(msg);
393
446
  }
394
- if (options.depends) {
395
- var depends = "";
396
- for(var i = 0; i < result.imports.length; i++) {
397
- depends += result.imports[i] + " ";
398
- }
399
- console.log(depends);
447
+ },
448
+ warn: function(msg) {
449
+ // do not show warning if outputting css to the console or the silent option is used
450
+ if (!silent && output) {
451
+ console.warn(msg);
400
452
  }
453
+ },
454
+ error: function(msg) {
455
+ console.log(msg);
401
456
  }
402
- },
403
- function(err) {
404
- less.writeError(err, options);
405
- currentErrorcode = 1;
406
457
  });
407
- };
408
458
 
409
- if (input != '-') {
410
- fs.readFile(input, 'utf8', parseLessFile);
411
- } else {
412
- process.stdin.resume();
413
- process.stdin.setEncoding('utf8');
459
+ less.render(data, options)
460
+ .then(function(result) {
461
+ if (!options.lint) {
462
+ writeOutput(output, result, function() {
463
+ writeSourceMapIfNeeded(result.map, function() {
464
+ logDependencies(options, result);
465
+ });
466
+ });
467
+ }
468
+ },
469
+ function(err) {
470
+ less.writeError(err, options);
471
+ currentErrorcode = 1;
472
+ });
473
+ };
474
+
475
+ if (input != '-') {
476
+ fs.readFile(input, 'utf8', parseLessFile);
477
+ } else {
478
+ process.stdin.resume();
479
+ process.stdin.setEncoding('utf8');
414
480
 
415
- var buffer = '';
416
- process.stdin.on('data', function(data) {
417
- buffer += data;
418
- });
481
+ var buffer = '';
482
+ process.stdin.on('data', function(data) {
483
+ buffer += data;
484
+ });
419
485
 
420
- process.stdin.on('end', function() {
421
- parseLessFile(false, buffer);
422
- });
423
- }
486
+ process.stdin.on('end', function() {
487
+ parseLessFile(false, buffer);
488
+ });
489
+ }
490
+ })();