less 4.9.1 → 5.0.0-alpha.10

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 (134) hide show
  1. package/README.md +23 -5
  2. package/V5-STATUS.md +71 -0
  3. package/bin/lessc +302 -626
  4. package/dist/less-browser-dev.js +2550 -0
  5. package/dist/less-node.cjs +480 -14561
  6. package/index.cjs +5 -2
  7. package/lib/browser-dev.js +86 -0
  8. package/lib/index.js +164 -0
  9. package/lib/lessc-helper.js +64 -0
  10. package/lib/logger.js +76 -0
  11. package/lib/options.d.ts +82 -0
  12. package/lib/options.js +227 -0
  13. package/lib/types.js +20 -0
  14. package/lib/version.js +19 -0
  15. package/package.json +36 -40
  16. package/dist/less.cjs +0 -15218
  17. package/dist/less.js +0 -15218
  18. package/dist/less.min.js +0 -11
  19. package/dist/less.min.js.map +0 -1
  20. package/lib/less/constants.js +0 -13
  21. package/lib/less/contexts.js +0 -165
  22. package/lib/less/data/colors.js +0 -150
  23. package/lib/less/data/index.js +0 -4
  24. package/lib/less/data/unit-conversions.js +0 -21
  25. package/lib/less/default-options.js +0 -89
  26. package/lib/less/deprecation.js +0 -82
  27. package/lib/less/environment/abstract-file-manager.js +0 -140
  28. package/lib/less/environment/abstract-plugin-loader.js +0 -185
  29. package/lib/less/environment/environment-api.ts +0 -21
  30. package/lib/less/environment/environment.js +0 -59
  31. package/lib/less/environment/file-manager-api.ts +0 -77
  32. package/lib/less/functions/boolean.js +0 -29
  33. package/lib/less/functions/color-blending.js +0 -85
  34. package/lib/less/functions/color.js +0 -452
  35. package/lib/less/functions/data-uri.js +0 -74
  36. package/lib/less/functions/default.js +0 -26
  37. package/lib/less/functions/function-caller.js +0 -55
  38. package/lib/less/functions/function-registry.js +0 -36
  39. package/lib/less/functions/index.js +0 -35
  40. package/lib/less/functions/list.js +0 -158
  41. package/lib/less/functions/math-helper.js +0 -22
  42. package/lib/less/functions/math.js +0 -30
  43. package/lib/less/functions/number.js +0 -95
  44. package/lib/less/functions/string.js +0 -39
  45. package/lib/less/functions/style.js +0 -29
  46. package/lib/less/functions/svg.js +0 -87
  47. package/lib/less/functions/types.js +0 -70
  48. package/lib/less/import-manager.js +0 -183
  49. package/lib/less/index.js +0 -95
  50. package/lib/less/less-error.js +0 -166
  51. package/lib/less/logger.js +0 -34
  52. package/lib/less/parse-tree.js +0 -124
  53. package/lib/less/parse.js +0 -87
  54. package/lib/less/parser/lookup-pattern.js +0 -26
  55. package/lib/less/parser/parser-input.js +0 -400
  56. package/lib/less/parser/parser.js +0 -2998
  57. package/lib/less/plugin-manager.js +0 -168
  58. package/lib/less/render.js +0 -41
  59. package/lib/less/source-map-builder.js +0 -82
  60. package/lib/less/source-map-output.js +0 -151
  61. package/lib/less/transform-tree.js +0 -102
  62. package/lib/less/tree/anonymous.js +0 -61
  63. package/lib/less/tree/assignment.js +0 -48
  64. package/lib/less/tree/atrule-syntax.js +0 -8
  65. package/lib/less/tree/atrule.js +0 -340
  66. package/lib/less/tree/attribute.js +0 -63
  67. package/lib/less/tree/call.js +0 -132
  68. package/lib/less/tree/color.js +0 -285
  69. package/lib/less/tree/combinator.js +0 -38
  70. package/lib/less/tree/comment.js +0 -48
  71. package/lib/less/tree/condition.js +0 -65
  72. package/lib/less/tree/container.js +0 -104
  73. package/lib/less/tree/debug-info.js +0 -80
  74. package/lib/less/tree/declaration.js +0 -142
  75. package/lib/less/tree/detached-ruleset.js +0 -45
  76. package/lib/less/tree/dimension.js +0 -215
  77. package/lib/less/tree/element.js +0 -93
  78. package/lib/less/tree/expression.js +0 -100
  79. package/lib/less/tree/extend.js +0 -88
  80. package/lib/less/tree/import.js +0 -299
  81. package/lib/less/tree/index.js +0 -56
  82. package/lib/less/tree/interpolated-variable.js +0 -106
  83. package/lib/less/tree/javascript.js +0 -45
  84. package/lib/less/tree/js-eval-node.js +0 -80
  85. package/lib/less/tree/keyword.js +0 -28
  86. package/lib/less/tree/media.js +0 -90
  87. package/lib/less/tree/merge-rules.js +0 -47
  88. package/lib/less/tree/mixin-call.js +0 -283
  89. package/lib/less/tree/mixin-definition.js +0 -319
  90. package/lib/less/tree/namespace-value.js +0 -95
  91. package/lib/less/tree/negative.js +0 -37
  92. package/lib/less/tree/nested-at-rule.js +0 -239
  93. package/lib/less/tree/node.js +0 -310
  94. package/lib/less/tree/operation.js +0 -81
  95. package/lib/less/tree/paren.js +0 -41
  96. package/lib/less/tree/property.js +0 -96
  97. package/lib/less/tree/query-in-parens.js +0 -64
  98. package/lib/less/tree/quoted.js +0 -131
  99. package/lib/less/tree/ruleset.js +0 -1068
  100. package/lib/less/tree/selector.js +0 -201
  101. package/lib/less/tree/unicode-descriptor.js +0 -14
  102. package/lib/less/tree/unit.js +0 -170
  103. package/lib/less/tree/url.js +0 -83
  104. package/lib/less/tree/value.js +0 -60
  105. package/lib/less/tree/variable-call.js +0 -60
  106. package/lib/less/tree/variable.js +0 -85
  107. package/lib/less/utils.js +0 -126
  108. package/lib/less/visitors/extend-visitor.js +0 -505
  109. package/lib/less/visitors/import-sequencer.js +0 -56
  110. package/lib/less/visitors/import-visitor.js +0 -203
  111. package/lib/less/visitors/index.js +0 -15
  112. package/lib/less/visitors/join-selector-visitor.js +0 -65
  113. package/lib/less/visitors/set-tree-visibility-visitor.js +0 -57
  114. package/lib/less/visitors/to-css-visitor.js +0 -332
  115. package/lib/less/visitors/visitor.js +0 -165
  116. package/lib/less-browser/add-default-options.js +0 -53
  117. package/lib/less-browser/bootstrap.js +0 -67
  118. package/lib/less-browser/browser.js +0 -65
  119. package/lib/less-browser/cache.js +0 -43
  120. package/lib/less-browser/error-reporting.js +0 -170
  121. package/lib/less-browser/file-manager.js +0 -112
  122. package/lib/less-browser/image-size.js +0 -28
  123. package/lib/less-browser/index.js +0 -284
  124. package/lib/less-browser/log-listener.js +0 -42
  125. package/lib/less-browser/plugin-loader.js +0 -24
  126. package/lib/less-browser/utils.js +0 -30
  127. package/lib/less-node/environment.js +0 -43
  128. package/lib/less-node/file-manager.js +0 -156
  129. package/lib/less-node/fs.js +0 -14
  130. package/lib/less-node/image-size.js +0 -78
  131. package/lib/less-node/index.js +0 -31
  132. package/lib/less-node/lessc-helper.js +0 -95
  133. package/lib/less-node/plugin-loader.js +0 -62
  134. package/lib/less-node/url-file-manager.js +0 -60
package/bin/lessc CHANGED
@@ -1,678 +1,354 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- /* eslint indent: [2, 2, {"SwitchCase": 1}] */
3
+ /**
4
+ * Less compiler (Jess-powered) — compiles .less files to CSS.
5
+ */
4
6
 
5
7
  import path from 'path';
6
- import os from 'os';
7
- import { createRequire } from 'module';
8
- import fs from '../lib/less-node/fs.js';
9
- import * as utils from '../lib/less/utils.js';
10
- import * as Constants from '../lib/less/constants.js';
11
- import less from '../lib/less-node/index.js';
12
-
13
- const require = createRequire(import.meta.url);
14
-
15
- var errno;
8
+ import fs from 'fs';
9
+ import less from '../lib/index.js';
10
+ import { version as versionInfo } from '../lib/version.js';
11
+ import { outputDiagnostics } from '@jesscss/compiler/diagnostics';
12
+
13
+ const args = process.argv.slice(1);
14
+ let options = { paths: [], filename: '' };
15
+ let input = null;
16
+ let output = null;
17
+ let silent = false;
18
+ let quiet = false;
19
+ let verbose = false;
20
+ let sourceMapEnabled = false;
21
+ let sourceMapExplicitFile = null;
22
+ const sourceMapOptions = {};
23
+
24
+ const unsupportedOptions = new Map([
25
+ ['--plugin', 'legacy lessc plugin flags are not supported'],
26
+ ['--depends', 'dependency-only output is not supported'],
27
+ ['--lint', 'lint-only mode is not supported'],
28
+ ['--clean-css', 'clean-css compression is not supported'],
29
+ ['--global-var', 'global variable injection is not supported'],
30
+ ['--modify-var', 'modify-var injection is not supported'],
31
+ ['--js', 'JavaScript evaluation is not supported'],
32
+ ['--no-js', 'JavaScript evaluation flags are not supported'],
33
+ ]);
34
+
35
+ function stripTerminalFormatting(value) {
36
+ return String(value)
37
+ .replace(/\x1B\]8;;[^\x1B]*(?:\x1B\\|\x07)/gu, '')
38
+ .replace(/\x1B\[[0-?]*[ -/]*[@-~]/gu, '');
39
+ }
16
40
 
17
- try {
18
- errno = require('errno');
19
- } catch (err) {
20
- errno = null;
41
+ function renderLogMessage(value) {
42
+ const message = String(value);
43
+ return options.color === false ? stripTerminalFormatting(message) : message;
21
44
  }
22
45
 
23
- var pluginManager = new less.PluginManager(less);
24
- var fileManager = new less.FileManager();
25
- var plugins = [];
26
- var queuePlugins = [];
27
- var args = process.argv.slice(1);
28
- var silent = false;
29
- var quiet = false;
30
- var verbose = false;
31
- var options = less.options;
32
- options.plugins = plugins;
33
- options.reUsePluginManager = true;
34
- var sourceMapOptions = {};
35
- var continueProcessing = true;
46
+ function captureJessDiagnostics(errors, warnings) {
47
+ const originalStdoutWrite = process.stdout.write;
48
+ const originalWrite = process.stderr.write;
49
+ let captured = '';
50
+ const captureDiagnosticWrite = function captureDiagnosticWrite(chunk, ...args) {
51
+ captured += String(chunk);
52
+ if (typeof args.at(-1) === 'function') {
53
+ args.at(-1)();
54
+ }
55
+ return true;
56
+ };
57
+ process.stdout.write = captureDiagnosticWrite;
58
+ process.stderr.write = captureDiagnosticWrite;
59
+ try {
60
+ outputDiagnostics(errors, warnings, {
61
+ suppressWarnings: quiet,
62
+ breakOnError: false,
63
+ verbose
64
+ });
65
+ } finally {
66
+ process.stdout.write = originalStdoutWrite;
67
+ process.stderr.write = originalWrite;
68
+ }
69
+ return options.color === false ? stripTerminalFormatting(captured) : captured;
70
+ }
36
71
 
37
- var checkArgFunc = function checkArgFunc(arg, option) {
38
- if (!option) {
39
- console.error(''.concat(arg, ' option requires a parameter'));
40
- continueProcessing = false;
41
- process.exitCode = 1;
72
+ function outputJessDiagnostics(errors, warnings = []) {
73
+ const relevantWarnings = quiet ? [] : warnings;
74
+ if ((!Array.isArray(errors) || errors.length === 0) && relevantWarnings.length === 0) {
42
75
  return false;
43
76
  }
44
-
77
+ process.stderr.write(captureJessDiagnostics(errors || [], relevantWarnings));
45
78
  return true;
46
- };
47
-
48
- var checkBooleanArg = function checkBooleanArg(arg) {
49
- var onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg);
79
+ }
50
80
 
51
- if (!onOff) {
52
- console.error(' unable to parse '.concat(arg, ' as a boolean. use one of on/t/true/y/yes/off/f/false/n/no'));
53
- continueProcessing = false;
54
- process.exitCode = 1;
81
+ function outputJessError(err) {
82
+ if (!Array.isArray(err?.jessErrors) || err.jessErrors.length === 0) {
55
83
  return false;
56
84
  }
85
+ outputJessDiagnostics(err.jessErrors, err.jessWarnings || []);
86
+ return true;
87
+ }
57
88
 
58
- return Boolean(onOff[2]);
59
- };
60
-
61
- var parseVariableOption = function parseVariableOption(option, variables) {
62
- var parts = option.split('=', 2);
63
- variables[parts[0]] = parts[1];
64
- };
89
+ function splitSearchPaths(value) {
90
+ return String(value || '')
91
+ .split(path.delimiter)
92
+ .filter(Boolean);
93
+ }
65
94
 
66
- var sourceMapFileInline = false;
67
- var pendingDeprecations = [];
95
+ function failUnsupportedOption(arg, reason) {
96
+ console.error(`lessc: ${arg} is not supported`);
97
+ if (reason) {
98
+ console.error(`lessc: ${reason}`);
99
+ }
100
+ console.error('lessc: run `lessc --help` for supported options.');
101
+ process.exit(1);
102
+ }
68
103
 
69
104
  function printUsage() {
70
105
  less.lesscHelper.printUsage();
71
-
72
- pluginManager.Loader.printUsage(plugins);
73
- continueProcessing = false;
106
+ process.exit(0);
74
107
  }
75
108
 
76
- function render() {
77
- if (!continueProcessing) {
78
- return;
79
- }
80
-
81
- var input = args[1];
82
-
83
- if (input && input != '-') {
84
- input = path.resolve(process.cwd(), input);
85
- }
86
-
87
- var output = args[2];
88
- var outputbase = args[2];
89
-
90
- if (output) {
91
- output = path.resolve(process.cwd(), output);
92
- }
93
-
94
- if (options.disablePluginRule && queuePlugins.length > 0) {
95
- console.error('--plugin and --disable-plugin-rule may not be used at the same time');
96
- process.exitCode = 1;
97
- return;
98
- }
99
-
100
- if (options.sourceMap) {
101
- // Validate conflicting options
102
- if (sourceMapOptions.sourceMapURL && sourceMapOptions.disableSourcemapAnnotation) {
103
- console.error('You cannot provide flag --source-map-url with --source-map-no-annotation.');
104
- console.error('Please remove one of those flags.');
105
- process.exitcode = 1;
106
- return;
109
+ function parseArgs() {
110
+ for (let i = 0; i < args.length; i++) {
111
+ const arg = args[i];
112
+ if (arg === '-h' || arg === '--help') {
113
+ printUsage();
107
114
  }
108
-
109
- // Handle explicit sourceMapFullFilename (from --source-map=filename)
110
- // Normalization of other options (sourceMapBasepath, sourceMapRootpath, etc.)
111
- // is handled automatically in parse-tree.js
112
- if (sourceMapOptions.sourceMapFullFilename && !sourceMapFileInline) {
113
- var mapFilename = path.resolve(process.cwd(), sourceMapOptions.sourceMapFullFilename);
114
- var mapDir = path.dirname(mapFilename);
115
-
116
- if (output) {
117
- var outputDir = path.dirname(output);
118
- // Set sourceMapOutputFilename relative to map directory
119
- sourceMapOptions.sourceMapOutputFilename = path.join(
120
- path.relative(mapDir, outputDir),
121
- path.basename(output)
122
- );
123
- // Set sourceMapFilename relative to output directory (for sourceMappingURL comment)
124
- sourceMapOptions.sourceMapFilename = path.join(
125
- path.relative(outputDir, mapDir),
126
- path.basename(sourceMapOptions.sourceMapFullFilename)
127
- );
128
- } else {
129
- // No output filename, just use basename
130
- sourceMapOptions.sourceMapOutputFilename = path.basename(output || 'output.css');
131
- sourceMapOptions.sourceMapFilename = path.basename(sourceMapOptions.sourceMapFullFilename);
132
- }
133
- } else if (!sourceMapOptions.sourceMapFullFilename && output && !sourceMapFileInline) {
134
- // No explicit sourcemap filename, derive from output
135
- sourceMapOptions.sourceMapOutputFilename = path.basename(output);
136
- sourceMapOptions.sourceMapFullFilename = ''.concat(output, '.map');
137
- } else if (!output && !sourceMapFileInline) {
138
- console.error('the sourcemap option only has an optional filename if the css filename is given');
139
- console.error('consider adding --source-map-map-inline which embeds the sourcemap into the css');
140
- process.exitCode = 1;
141
- return;
115
+ if (arg === '-v' || arg === '--version') {
116
+ console.log(`lessc ${versionInfo.semver} (Less Compiler) [Jess]`);
117
+ process.exit(0);
142
118
  }
143
- }
144
-
145
- if (!input) {
146
- console.error('lessc: no input files');
147
- console.error('');
148
- printUsage();
149
- process.exitCode = 1;
150
- return;
151
- }
152
-
153
- var mkdirp;
154
- var ensureDirectory = function ensureDirectory(filepath) {
155
- var dir = path.dirname(filepath);
156
- var cmd;
157
- var existsSync = fs.existsSync || path.existsSync;
158
-
159
- if (!existsSync(dir)) {
160
- if (mkdirp === undefined) {
161
- try {
162
- mkdirp = require('make-dir');
163
- } catch (e) {
164
- mkdirp = null;
165
- }
166
- }
167
-
168
- cmd = mkdirp && mkdirp.sync || fs.mkdirSync;
169
- cmd(dir);
119
+ if (arg === '-s' || arg === '--silent') {
120
+ silent = true;
121
+ continue;
170
122
  }
171
- };
172
-
173
- if (options.depends) {
174
- if (!outputbase) {
175
- console.error('option --depends requires an output path to be specified');
176
- process.exitCode = 1;
177
- return;
123
+ if (arg === '--quiet') {
124
+ quiet = true;
125
+ continue;
178
126
  }
179
-
180
- process.stdout.write(''.concat(outputbase, ': '));
181
- }
182
-
183
- if (!sourceMapFileInline) {
184
- var writeSourceMap = function writeSourceMap() {
185
- var output = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
186
- var onDone = arguments.length > 1 ? arguments[1] : undefined;
187
- var filename = sourceMapOptions.sourceMapFullFilename;
188
- ensureDirectory(filename);
189
-
190
- // To fix https://github.com/less/less.js/issues/3646
191
- output = output.toString();
192
-
193
- fs.writeFile(filename, output, 'utf8', function (err) {
194
- if (err) {
195
- var description = 'Error: ';
196
-
197
- if (errno && errno.errno[err.errno]) {
198
- description += errno.errno[err.errno].description;
199
- } else {
200
- description += ''.concat(err.code, ' ').concat(err.message);
201
- }
202
-
203
- console.error('lessc: failed to create file '.concat(filename));
204
- console.error(description);
205
- process.exitCode = 1;
206
- } else {
207
- less.logger.info('lessc: wrote '.concat(filename));
208
- }
209
-
210
- onDone();
211
- });
212
- };
213
- }
214
-
215
- var writeSourceMapIfNeeded = function writeSourceMapIfNeeded(output, onDone) {
216
- if (options.sourceMap && !sourceMapFileInline) {
217
- writeSourceMap(output, onDone);
218
- } else {
219
- onDone();
127
+ if (arg === '--verbose') {
128
+ verbose = true;
129
+ continue;
220
130
  }
221
- };
222
-
223
- var writeOutput = function writeOutput(output, result, onSuccess) {
224
- if (options.depends) {
225
- onSuccess();
226
- } else if (output) {
227
- ensureDirectory(output);
228
-
229
- fs.writeFile(output, result.css, {
230
- encoding: 'utf8'
231
- }, function (err) {
232
- if (err) {
233
- var description = 'Error: ';
234
-
235
- if (errno && errno.errno[err.errno]) {
236
- description += errno.errno[err.errno].description;
237
- } else {
238
- description += ''.concat(err.code, ' ').concat(err.message);
239
- }
240
-
241
- console.error('lessc: failed to create file '.concat(output));
242
- console.error(description);
243
- process.exitCode = 1;
244
- } else {
245
- less.logger.info('lessc: wrote '.concat(output));
246
-
247
- onSuccess();
248
- }
249
- });
250
- } else if (!options.depends) {
251
- process.stdout.write(result.css);
252
- onSuccess();
131
+ const collapseNestingMatch = arg.match(/^--collapse-nesting(?:=(.+))?$/);
132
+ if (collapseNestingMatch) {
133
+ options.collapseNesting = collapseNestingMatch[1] ?? true;
134
+ continue;
253
135
  }
254
- };
255
-
256
- var logDependencies = function logDependencies(options, result) {
257
- if (options.depends) {
258
- var depends = '';
259
-
260
- for (var i = 0; i < result.imports.length; i++) {
261
- depends += ''.concat(result.imports[i], ' ');
262
- }
263
-
264
- console.log(depends);
136
+ if (arg === '--compress' || arg === '-x') {
137
+ options.compress = true;
138
+ continue;
265
139
  }
266
- };
267
-
268
- var parseLessFile = function parseLessFile(e, data) {
269
- if (e) {
270
- console.error('lessc: '.concat(e.message));
271
- process.exitCode = 1;
272
- return;
140
+ const mathMatch = arg.match(/^--math=(.+)$/);
141
+ if (mathMatch) {
142
+ options.math = mathMatch[1];
143
+ continue;
273
144
  }
274
-
275
- data = data.replace(/^\uFEFF/, '');
276
- options.paths = [path.dirname(input)].concat(options.paths);
277
- options.filename = input;
278
-
279
- if (options.lint) {
280
- options.sourceMap = false;
145
+ // URL rewriting (forwarded to the Less plugin). `--rewrite-urls` with no
146
+ // value is Less 4.x's `all`.
147
+ const rewriteUrlsMatch = arg.match(/^--rewrite-urls(?:=(.+))?$/);
148
+ if (rewriteUrlsMatch) {
149
+ options.rewriteUrls = rewriteUrlsMatch[1] ?? 'all';
150
+ continue;
281
151
  }
282
-
283
- sourceMapOptions.sourceMapFileInline = sourceMapFileInline;
284
-
285
- if (options.sourceMap) {
286
- options.sourceMap = sourceMapOptions;
152
+ const rootpathMatch = arg.match(/^--rootpath=(.+)$/);
153
+ if (rootpathMatch) {
154
+ options.rootpath = rootpathMatch[1];
155
+ continue;
287
156
  }
288
-
289
- less.logger.addListener({
290
- info: function info(msg) {
291
- if (verbose) {
292
- console.log(msg);
293
- }
294
- },
295
- warn: function warn(msg) {
296
- // do not show warning if the silent option is used
297
- if (!silent && !quiet) {
298
- console.warn(msg);
299
- }
300
- },
301
- error: function error(msg) {
302
- if (!silent) {
303
- console.error(msg);
304
- }
305
- }
306
- });
307
-
308
- less.render(data, options).then(function (result) {
309
- if (!options.lint) {
310
- writeOutput(output, result, function () {
311
- writeSourceMapIfNeeded(result.map, function () {
312
- logDependencies(options, result);
313
- });
314
- });
157
+ const urlArgsMatch = arg.match(/^--url-args=(.+)$/);
158
+ if (urlArgsMatch) {
159
+ options.urlArgs = urlArgsMatch[1];
160
+ continue;
161
+ }
162
+ // Source maps. The `--source-map-*` sub-flags are matched before the bare
163
+ // `--source-map[=file]` (their `$`-anchored patterns don't overlap, but the
164
+ // ordering documents intent). Each sub-flag also enables source maps.
165
+ if (arg === '--source-map-inline' || arg === '--source-map-map-inline') {
166
+ sourceMapEnabled = true;
167
+ sourceMapOptions.sourceMapFileInline = true;
168
+ continue;
169
+ }
170
+ if (arg === '--source-map-include-source') {
171
+ sourceMapEnabled = true;
172
+ sourceMapOptions.outputSourceFiles = true;
173
+ continue;
174
+ }
175
+ const smRootpathMatch = arg.match(/^--source-map-rootpath=(.+)$/);
176
+ if (smRootpathMatch) {
177
+ sourceMapEnabled = true;
178
+ sourceMapOptions.sourceMapRootpath = smRootpathMatch[1];
179
+ continue;
180
+ }
181
+ const smBasepathMatch = arg.match(/^--source-map-basepath=(.+)$/);
182
+ if (smBasepathMatch) {
183
+ sourceMapEnabled = true;
184
+ sourceMapOptions.sourceMapBasepath = smBasepathMatch[1];
185
+ continue;
186
+ }
187
+ const smUrlMatch = arg.match(/^--source-map-url=(.+)$/);
188
+ if (smUrlMatch) {
189
+ sourceMapEnabled = true;
190
+ sourceMapOptions.sourceMapURL = smUrlMatch[1];
191
+ continue;
192
+ }
193
+ const sourceMapMatch = arg.match(/^--source-map(?:=(.+))?$/);
194
+ if (sourceMapMatch) {
195
+ sourceMapEnabled = true;
196
+ if (sourceMapMatch[1]) {
197
+ sourceMapExplicitFile = sourceMapMatch[1];
315
198
  }
316
- }, function (err) {
317
- if (!options.silent) {
318
- console.error(err.toString({
319
- stylize: options.color && less.lesscHelper.stylize
320
- }));
199
+ continue;
200
+ }
201
+ // Deprecated 4.x spellings (--strict-units, --strict-units=on|off, -su=on|off)
202
+ // set the deprecated `strictUnits` boolean; `createLessOptions` maps it to
203
+ // `unitMode` and warns during compile, after the logger listener is attached.
204
+ const strictUnitsMatch = arg.match(/^(?:--strict-units|-su)(?:=(on|off))?$/);
205
+ if (strictUnitsMatch) {
206
+ options.strictUnits = strictUnitsMatch[1] !== 'off';
207
+ continue;
208
+ }
209
+ const unitModeMatch = arg.match(/^--unit-mode=(.+)$/);
210
+ if (unitModeMatch) {
211
+ options.unitMode = unitModeMatch[1];
212
+ continue;
213
+ }
214
+ const optionName = arg.includes('=') ? arg.slice(0, arg.indexOf('=')) : arg;
215
+ if (unsupportedOptions.has(optionName)) {
216
+ failUnsupportedOption(optionName, unsupportedOptions.get(optionName));
217
+ }
218
+ if (arg === '-I' || arg === '--include-path') {
219
+ const match = arg.match(/^-I(.+)$/);
220
+ const paths = splitSearchPaths(match ? match[1] : args[++i]);
221
+ options.paths.push(...paths);
222
+ continue;
223
+ }
224
+ if (arg.startsWith('-I')) {
225
+ options.paths.push(...splitSearchPaths(arg.slice(2)));
226
+ continue;
227
+ }
228
+ const includeMatch = arg.match(/^--include-path=(.+)$/);
229
+ if (includeMatch) {
230
+ options.paths.push(...splitSearchPaths(includeMatch[1]));
231
+ continue;
232
+ }
233
+ if (arg === '--no-color') {
234
+ options.color = false;
235
+ continue;
236
+ }
237
+ if (arg === '-' || arg.endsWith('.less') || arg.endsWith('.css')) {
238
+ if (input === null) {
239
+ input = arg === '-' ? '-' : path.resolve(process.cwd(), arg);
240
+ } else if (output === null) {
241
+ output = path.resolve(process.cwd(), arg);
321
242
  }
322
-
323
- process.exitCode = 1;
324
- });
325
- };
326
-
327
- if (input != '-') {
328
- fs.readFile(input, 'utf8', parseLessFile);
329
- } else {
330
- process.stdin.resume();
331
- process.stdin.setEncoding('utf8');
332
- var buffer = '';
333
- process.stdin.on('data', function (data) {
334
- buffer += data;
335
- });
336
- process.stdin.on('end', function () {
337
- parseLessFile(false, buffer);
338
- });
243
+ continue;
244
+ }
245
+ if (arg.startsWith('-')) {
246
+ failUnsupportedOption(arg, 'unknown flags are not supported');
247
+ }
339
248
  }
340
249
  }
341
250
 
342
- function processPluginQueue() {
343
- var x = 0;
344
-
345
- function pluginError(name) {
346
- console.error('Unable to load plugin '.concat(name, ' please make sure that it is installed under or at the same level as less'));
347
- process.exitCode = 1;
251
+ // Assemble the `sourceMap` render option from the CLI source-map flags and
252
+ // return the sidecar `.map` path to write (null when inlined or unset). The
253
+ // engine writes the `sourceMappingURL` annotation into the CSS and returns
254
+ // `result.map`; the CLI owns writing that map to disk, mirroring Less 4.x lessc.
255
+ function resolveSourceMap() {
256
+ if (!sourceMapEnabled) {
257
+ return null;
348
258
  }
349
-
350
- function pluginFinished(plugin) {
351
- x++;
352
- plugins.push(plugin);
353
-
354
- if (x === queuePlugins.length) {
355
- render();
259
+ let mapFilePath = null;
260
+ if (sourceMapOptions.sourceMapFileInline !== true) {
261
+ if (sourceMapExplicitFile) {
262
+ mapFilePath = path.resolve(process.cwd(), sourceMapExplicitFile);
263
+ } else if (output) {
264
+ mapFilePath = `${output}.map`;
265
+ } else {
266
+ // Writing CSS to stdout leaves nowhere for a sidecar; inline the map.
267
+ sourceMapOptions.sourceMapFileInline = true;
268
+ }
269
+ }
270
+ if (mapFilePath) {
271
+ // Annotation URL (unless --source-map-url set it) points at the map relative
272
+ // to the CSS output directory — so a map written to another directory still
273
+ // resolves (dist/app.css -> ../maps/app.map), and the same-dir common case
274
+ // stays a bare basename. With no output file (stdout) there is no directory
275
+ // to resolve against, so fall back to the basename.
276
+ if (sourceMapOptions.sourceMapURL === undefined) {
277
+ sourceMapOptions.sourceMapFilename = output
278
+ ? path.relative(path.dirname(output), mapFilePath).split(path.sep).join('/')
279
+ : path.basename(mapFilePath);
280
+ }
281
+ if (output) {
282
+ sourceMapOptions.sourceMapOutputFilename = path.basename(output);
356
283
  }
357
284
  }
285
+ options.sourceMap = sourceMapOptions;
286
+ return mapFilePath;
287
+ }
358
288
 
359
- queuePlugins.forEach(function (queue) {
360
- var context = utils.clone(options);
361
- pluginManager.Loader.loadPlugin(queue.name, process.cwd(), context, less.environment, fileManager).then(function (data) {
362
- pluginFinished({
363
- fileContent: data.contents,
364
- filename: data.filename,
365
- options: queue.options
366
- });
367
- }).catch(function () {
368
- pluginError(queue.name);
369
- });
370
- });
371
- } // self executing function so we can return
289
+ async function run() {
290
+ parseArgs();
372
291
 
292
+ if (!input) {
293
+ console.error('lessc: no input files');
294
+ console.error('');
295
+ printUsage();
296
+ }
373
297
 
374
- (function () {
375
- args = args.filter(function (arg) {
376
- var match;
377
- match = arg.match(/^-I(.+)$/);
298
+ const mapFilePath = resolveSourceMap();
299
+
300
+ less.logger.addListener({
301
+ info(msg) {
302
+ if (verbose) console.log(msg);
303
+ },
304
+ warn(msg) {
305
+ if (!silent && !quiet) console.warn(renderLogMessage(msg));
306
+ },
307
+ error(msg) {
308
+ if (!silent) console.error(renderLogMessage(msg));
309
+ },
310
+ });
378
311
 
379
- if (match) {
380
- options.paths.push(match[1]);
381
- return false;
312
+ try {
313
+ let result;
314
+ if (input === '-') {
315
+ const data = await new Promise((resolve, reject) => {
316
+ let buf = '';
317
+ process.stdin.setEncoding('utf8');
318
+ process.stdin.on('data', chunk => { buf += chunk; });
319
+ process.stdin.on('end', () => resolve(buf));
320
+ process.stdin.on('error', reject);
321
+ });
322
+ result = await less.render(data, { ...options, filename: 'input.less' });
323
+ } else {
324
+ options.filename = input;
325
+ options.paths = [path.dirname(input), ...options.paths];
326
+ result = await less.renderFile(input, options);
382
327
  }
383
328
 
384
- match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i);
385
-
386
- if (match) {
387
- arg = match[1];
329
+ if (output) {
330
+ fs.mkdirSync(path.dirname(output), { recursive: true });
331
+ fs.writeFileSync(output, result.css, 'utf8');
332
+ if (!silent) outputJessDiagnostics([], result.warnings || []);
333
+ if (!silent) console.log(`lessc: wrote ${output}`);
388
334
  } else {
389
- return arg;
335
+ if (!silent) outputJessDiagnostics([], result.warnings || []);
336
+ process.stdout.write(result.css);
390
337
  }
391
338
 
392
- switch (arg) {
393
- case 'v':
394
- case 'version':
395
- console.log('lessc '.concat(less.version.join('.'), ' (Less Compiler) [JavaScript]'));
396
- continueProcessing = false;
397
- break;
398
-
399
- case 'verbose':
400
- options.verbose = verbose = true;
401
- break;
402
-
403
- case 's':
404
- case 'silent':
405
- options.silent = silent = true;
406
- break;
407
-
408
- case 'quiet':
409
- options.quiet = quiet = true;
410
- break;
411
-
412
- case 'quiet-deprecations':
413
- options.quietDeprecations = true;
414
- break;
415
-
416
- case 'l':
417
- case 'lint':
418
- options.lint = true;
419
- break;
420
-
421
- case 'strict-imports':
422
- options.strictImports = true;
423
- break;
424
-
425
- case 'h':
426
- case 'help':
427
- printUsage();
428
- break;
429
-
430
- case 'x':
431
- case 'compress':
432
- options.compress = true;
433
- break;
434
-
435
- case 'insecure':
436
- options.insecure = true;
437
- break;
438
-
439
- case 'M':
440
- case 'depends':
441
- options.depends = true;
442
- break;
443
-
444
- case 'max-line-len':
445
- if (checkArgFunc(arg, match[2])) {
446
- options.maxLineLen = parseInt(match[2], 10);
447
-
448
- if (options.maxLineLen <= 0) {
449
- options.maxLineLen = -1;
450
- }
451
- }
452
-
453
- break;
454
-
455
- case 'no-color':
456
- options.color = false;
457
- break;
458
-
459
- case 'js':
460
- options.javascriptEnabled = true;
461
- pendingDeprecations.push('Warning: Inline JavaScript (--js) is deprecated and will be removed in Less 5.x. Use Less functions or custom plugins instead. (js-eval)');
462
- break;
463
-
464
- case 'no-js':
465
- // eslint-disable-next-line max-len
466
- console.error('The "--no-js" argument is deprecated, as inline JavaScript is disabled by default. Use "--js" to enable inline JavaScript (not recommended).');
467
- break;
468
-
469
- case 'include-path':
470
- if (checkArgFunc(arg, match[2])) {
471
- // ; supported on windows.
472
- // : supported on windows and linux, excluding a drive letter like C:\ so C:\file:D:\file parses to 2
473
- options.paths = match[2].split(os.type().match(/Windows/) ? /:(?!\\)|;/ : ':').map(function (p) {
474
- if (p) {
475
- return path.resolve(process.cwd(), p);
476
- }
477
- });
478
- }
479
-
480
- break;
481
-
482
- case 'line-numbers':
483
- if (checkArgFunc(arg, match[2])) {
484
- options.dumpLineNumbers = match[2];
485
- pendingDeprecations.push('Warning: The --line-numbers option is deprecated and will be removed in Less 5.x. Use source maps instead (--source-map). (dump-line-numbers)');
486
- }
487
-
488
- break;
489
-
490
- case 'source-map':
491
- options.sourceMap = true;
492
-
493
- if (match[2]) {
494
- sourceMapOptions.sourceMapFullFilename = match[2];
495
- }
496
-
497
- break;
498
-
499
- case 'source-map-rootpath':
500
- if (checkArgFunc(arg, match[2])) {
501
- sourceMapOptions.sourceMapRootpath = match[2];
502
- }
503
-
504
- break;
505
-
506
- case 'source-map-basepath':
507
- if (checkArgFunc(arg, match[2])) {
508
- sourceMapOptions.sourceMapBasepath = match[2];
509
- }
510
-
511
- break;
512
-
513
- case 'source-map-inline':
514
- case 'source-map-map-inline':
515
- sourceMapFileInline = true;
516
- options.sourceMap = true;
517
- break;
518
-
519
- case 'source-map-include-source':
520
- case 'source-map-less-inline':
521
- sourceMapOptions.outputSourceFiles = true;
522
- break;
523
-
524
- case 'source-map-url':
525
- if (checkArgFunc(arg, match[2])) {
526
- sourceMapOptions.sourceMapURL = match[2];
527
- }
528
-
529
- break;
530
-
531
- case 'source-map-no-annotation':
532
- sourceMapOptions.disableSourcemapAnnotation = true;
533
- break;
534
-
535
- case 'rp':
536
- case 'rootpath':
537
- if (checkArgFunc(arg, match[2])) {
538
- options.rootpath = match[2].replace(/\\/g, '/');
539
- }
540
-
541
- break;
542
-
543
- case 'ie-compat':
544
- pendingDeprecations.push('Warning: The --ie-compat option is deprecated, as it has no effect on compilation.');
545
- break;
546
-
547
- case 'relative-urls':
548
- pendingDeprecations.push('Warning: The --relative-urls option has been deprecated. Use --rewrite-urls=all.');
549
- options.rewriteUrls = Constants.RewriteUrls.ALL;
550
- break;
551
-
552
- case 'ru':
553
- case 'rewrite-urls':
554
- var m = match[2];
555
-
556
- if (m) {
557
- if (m === 'local') {
558
- options.rewriteUrls = Constants.RewriteUrls.LOCAL;
559
- } else if (m === 'off') {
560
- options.rewriteUrls = Constants.RewriteUrls.OFF;
561
- } else if (m === 'all') {
562
- options.rewriteUrls = Constants.RewriteUrls.ALL;
563
- } else {
564
- console.error('Unknown rewrite-urls argument '.concat(m));
565
- continueProcessing = false;
566
- process.exitCode = 1;
567
- }
568
- } else {
569
- options.rewriteUrls = Constants.RewriteUrls.ALL;
570
- }
571
-
572
- break;
573
-
574
- case 'sm':
575
- case 'strict-math':
576
- pendingDeprecations.push('Warning: The --strict-math option has been deprecated. Use --math=strict.');
577
-
578
- if (checkArgFunc(arg, match[2])) {
579
- if (checkBooleanArg(match[2])) {
580
- options.math = Constants.Math.PARENS;
581
- }
582
- }
583
-
584
- break;
585
-
586
- case 'm':
587
- case 'math': {
588
- let m = match[2];
589
- if (checkArgFunc(arg, m)) {
590
- if (m === 'always') {
591
- pendingDeprecations.push('Warning: --math=always is deprecated and will be removed in Less 5.x. Use --math=parens-division (default) or --math=parens. (math-always)');
592
- options.math = Constants.Math.ALWAYS;
593
- } else if (m === 'parens-division') {
594
- options.math = Constants.Math.PARENS_DIVISION;
595
- } else if (m === 'parens' || m === 'strict') {
596
- options.math = Constants.Math.PARENS;
597
- } else if (m === 'strict-legacy') {
598
- pendingDeprecations.push('Warning: --math=strict-legacy has been removed. Defaulting to --math=strict.');
599
- options.math = Constants.Math.PARENS;
600
- }
601
- }
602
-
603
- break;
339
+ if (mapFilePath && result.map) {
340
+ fs.mkdirSync(path.dirname(mapFilePath), { recursive: true });
341
+ fs.writeFileSync(mapFilePath, result.map, 'utf8');
342
+ if (!silent) console.log(`lessc: wrote ${mapFilePath}`);
343
+ }
344
+ } catch (err) {
345
+ if (!silent) {
346
+ if (!outputJessError(err)) {
347
+ console.error(renderLogMessage(err.toString?.() || err.message));
604
348
  }
605
- case 'su':
606
- case 'strict-units':
607
- if (checkArgFunc(arg, match[2])) {
608
- options.strictUnits = checkBooleanArg(match[2]);
609
- }
610
-
611
- break;
612
-
613
- case 'global-var':
614
- if (checkArgFunc(arg, match[2])) {
615
- if (!options.globalVars) {
616
- options.globalVars = {};
617
- }
618
-
619
- parseVariableOption(match[2], options.globalVars);
620
- }
621
-
622
- break;
623
-
624
- case 'modify-var':
625
- if (checkArgFunc(arg, match[2])) {
626
- if (!options.modifyVars) {
627
- options.modifyVars = {};
628
- }
629
-
630
- parseVariableOption(match[2], options.modifyVars);
631
- }
632
-
633
- break;
634
-
635
- case 'url-args':
636
- if (checkArgFunc(arg, match[2])) {
637
- options.urlArgs = match[2];
638
- }
639
-
640
- break;
641
-
642
- case 'plugin':
643
- var splitupArg = match[2].match(/^([^=]+)(=(.*))?/);
644
- var name = splitupArg[1];
645
- var pluginOptions = splitupArg[3];
646
- queuePlugins.push({
647
- name: name,
648
- options: pluginOptions
649
- });
650
- break;
651
-
652
- case 'disable-plugin-rule':
653
- options.disablePluginRule = true;
654
- break;
655
-
656
- default:
657
- queuePlugins.push({
658
- name: arg,
659
- options: match[2],
660
- default: true
661
- });
662
- break;
663
349
  }
664
- });
665
-
666
- // Flush queued deprecation warnings (respects --silent, --quiet, --quiet-deprecations)
667
- if (!silent && !quiet && !options.quietDeprecations) {
668
- pendingDeprecations.forEach(function (msg) {
669
- console.warn(msg);
670
- });
350
+ process.exitCode = 1;
671
351
  }
352
+ }
672
353
 
673
- if (queuePlugins.length > 0) {
674
- processPluginQueue();
675
- } else {
676
- render();
677
- }
678
- })();
354
+ run();