less 4.4.2 → 4.5.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 (43) hide show
  1. package/Gruntfile.js +16 -17
  2. package/bin/lessc +35 -40
  3. package/dist/less.js +118 -185
  4. package/dist/less.min.js +2 -2
  5. package/dist/less.min.js.map +1 -1
  6. package/lib/less/contexts.js +0 -1
  7. package/lib/less/contexts.js.map +1 -1
  8. package/lib/less/default-options.js +22 -3
  9. package/lib/less/default-options.js.map +1 -1
  10. package/lib/less/less-error.js +2 -1
  11. package/lib/less/less-error.js.map +1 -1
  12. package/lib/less/parse-tree.js +58 -1
  13. package/lib/less/parse-tree.js.map +1 -1
  14. package/lib/less/parser/parser-input.js +2 -19
  15. package/lib/less/parser/parser-input.js.map +1 -1
  16. package/lib/less/parser/parser.js +2 -14
  17. package/lib/less/parser/parser.js.map +1 -1
  18. package/lib/less/source-map-output.js +1 -1
  19. package/lib/less/source-map-output.js.map +1 -1
  20. package/lib/less/tree/debug-info.js +29 -0
  21. package/lib/less/tree/debug-info.js.map +1 -1
  22. package/lib/less-node/lessc-helper.js +8 -7
  23. package/lib/less-node/lessc-helper.js.map +1 -1
  24. package/package.json +10 -5
  25. package/scripts/coverage-lines.js +207 -0
  26. package/scripts/coverage-report.js +158 -0
  27. package/scripts/postinstall.js +61 -0
  28. package/test/browser/common.js +22 -1
  29. package/test/browser/generator/runner.config.js +20 -24
  30. package/test/browser/generator/template.js +14 -3
  31. package/test/browser/runner-browser-options.js +5 -5
  32. package/test/index.js +293 -98
  33. package/test/less-test.js +453 -94
  34. package/test/sourcemaps/comprehensive.json +1 -0
  35. package/test/sourcemaps/sourcemaps-basepath.json +1 -0
  36. package/test/sourcemaps/sourcemaps-include-source.json +1 -0
  37. package/test/sourcemaps/sourcemaps-rootpath.json +1 -0
  38. package/test/sourcemaps/sourcemaps-url.json +1 -0
  39. package/test.less +1 -0
  40. package/lib/less/parser/chunker.js +0 -148
  41. package/lib/less/parser/chunker.js.map +0 -1
  42. package/test/browser/runner-legacy-options.js +0 -6
  43. package/test/browser/runner-legacy-spec.js +0 -3
package/Gruntfile.js CHANGED
@@ -4,7 +4,7 @@ var resolve = require('resolve');
4
4
  var path = require('path');
5
5
 
6
6
  var testFolder = path.relative(process.cwd(), path.dirname(resolve.sync('@less/test-data')));
7
- var lessFolder = path.join(testFolder, 'less');
7
+ var lessFolder = testFolder;
8
8
 
9
9
  module.exports = function(grunt) {
10
10
  grunt.option("stack", true);
@@ -85,8 +85,7 @@ module.exports = function(grunt) {
85
85
  "relative-urls",
86
86
  "rewrite-urls",
87
87
  "browser",
88
- "no-js-errors",
89
- "legacy"
88
+ "no-js-errors"
90
89
  ];
91
90
 
92
91
  function makeJob(testName) {
@@ -214,7 +213,7 @@ module.exports = function(grunt) {
214
213
  command: "node build/rollup.js --browser --out=./tmp/browser/less.min.js"
215
214
  },
216
215
  test: {
217
- command: 'ts-node test/test-es6.ts && node test/index.js'
216
+ command: 'npx ts-node test/test-es6.ts && node test/index.js'
218
217
  },
219
218
  generatebrowser: {
220
219
  command: 'node test/browser/generator/generate.js'
@@ -230,35 +229,35 @@ module.exports = function(grunt) {
230
229
  command: [
231
230
  // @TODO: make this more thorough
232
231
  // CURRENT OPTIONS
233
- `node bin/lessc --ie-compat ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
232
+ `node bin/lessc --ie-compat ${lessFolder}/tests-unit/lazy-eval/lazy-eval.less tmp/lazy-eval.css`,
234
233
  // --math
235
- `node bin/lessc --math=always ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
236
- `node bin/lessc --math=parens-division ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
237
- `node bin/lessc --math=parens ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
238
- `node bin/lessc --math=strict ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
239
- `node bin/lessc --math=strict-legacy ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
234
+ `node bin/lessc --math=always ${lessFolder}/tests-unit/lazy-eval/lazy-eval.less tmp/lazy-eval.css`,
235
+ `node bin/lessc --math=parens-division ${lessFolder}/tests-unit/lazy-eval/lazy-eval.less tmp/lazy-eval.css`,
236
+ `node bin/lessc --math=parens ${lessFolder}/tests-unit/lazy-eval/lazy-eval.less tmp/lazy-eval.css`,
237
+ `node bin/lessc --math=strict ${lessFolder}/tests-unit/lazy-eval/lazy-eval.less tmp/lazy-eval.css`,
238
+ `node bin/lessc --math=strict-legacy ${lessFolder}/tests-unit/lazy-eval/lazy-eval.less tmp/lazy-eval.css`,
240
239
 
241
240
  // DEPRECATED OPTIONS
242
241
  // --strict-math
243
- `node bin/lessc --strict-math=on ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`
242
+ `node bin/lessc --strict-math=on ${lessFolder}/tests-unit/lazy-eval/lazy-eval.less tmp/lazy-eval.css`
244
243
  ].join(" && ")
245
244
  },
246
245
  plugin: {
247
246
  command: [
248
- `node bin/lessc --clean-css="--s1 --advanced" ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
247
+ `node bin/lessc --clean-css="--s1 --advanced" ${lessFolder}/tests-unit/lazy-eval/lazy-eval.less tmp/lazy-eval.css`,
249
248
  "cd lib",
250
- `node ../bin/lessc --clean-css="--s1 --advanced" ../${lessFolder}/_main/lazy-eval.less ../tmp/lazy-eval.css`,
251
- `node ../bin/lessc --source-map=lazy-eval.css.map --autoprefix ../${lessFolder}/_main/lazy-eval.less ../tmp/lazy-eval.css`,
249
+ `node ../bin/lessc --clean-css="--s1 --advanced" ../${lessFolder}/tests-unit/lazy-eval/lazy-eval.less ../tmp/lazy-eval.css`,
250
+ `node ../bin/lessc --source-map=lazy-eval.css.map --autoprefix ../${lessFolder}/tests-unit/lazy-eval/lazy-eval.less ../tmp/lazy-eval.css`,
252
251
  "cd ..",
253
252
  // Test multiple plugins
254
- `node bin/lessc --plugin=clean-css="--s1 --advanced" --plugin=autoprefix="ie 11,Edge >= 13,Chrome >= 47,Firefox >= 45,iOS >= 9.2,Safari >= 9" ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`
253
+ `node bin/lessc --plugin=clean-css="--s1 --advanced" --plugin=autoprefix="ie 11,Edge >= 13,Chrome >= 47,Firefox >= 45,iOS >= 9.2,Safari >= 9" ${lessFolder}/tests-unit/lazy-eval/lazy-eval.less tmp/lazy-eval.css`
255
254
  ].join(" && ")
256
255
  },
257
256
  "sourcemap-test": {
258
257
  // quoted value doesn't seem to get picked up by time-grunt, or isn't output, at least; maybe just "sourcemap" is fine?
259
258
  command: [
260
- `node bin/lessc --source-map=test/sourcemaps/maps/import-map.map ${lessFolder}/_main/import.less test/sourcemaps/import.css`,
261
- `node bin/lessc --source-map ${lessFolder}/sourcemaps/basic.less test/sourcemaps/basic.css`
259
+ `node bin/lessc --source-map=test/sourcemaps/maps/import-map.map ${lessFolder}/tests-unit/import/import.less test/sourcemaps/import.css`,
260
+ `node bin/lessc --source-map ${lessFolder}/tests-config/sourcemaps/basic.less test/sourcemaps/basic.css`
262
261
  ].join(" && ")
263
262
  }
264
263
  },
package/bin/lessc CHANGED
@@ -98,53 +98,48 @@ function render() {
98
98
  }
99
99
 
100
100
  if (options.sourceMap) {
101
- sourceMapOptions.sourceMapInputFilename = input;
102
-
103
- if (!sourceMapOptions.sourceMapFullFilename) {
104
- if (!output && !sourceMapFileInline) {
105
- console.error('the sourcemap option only has an optional filename if the css filename is given');
106
- console.error('consider adding --source-map-map-inline which embeds the sourcemap into the css');
107
- process.exitCode = 1;
108
- return;
109
- } // its in the same directory, so always just the basename
110
-
111
-
112
- if (output) {
113
- sourceMapOptions.sourceMapOutputFilename = path.basename(output);
114
- sourceMapOptions.sourceMapFullFilename = ''.concat(output, '.map');
115
- } // its in the same directory, so always just the basename
116
-
117
-
118
- if ('sourceMapFullFilename' in sourceMapOptions) {
119
- sourceMapOptions.sourceMapFilename = path.basename(sourceMapOptions.sourceMapFullFilename);
120
- }
121
- } else if (options.sourceMap && !sourceMapFileInline) {
122
- var mapFilename = path.resolve(process.cwd(), sourceMapOptions.sourceMapFullFilename);
123
- var mapDir = path.dirname(mapFilename);
124
- var outputDir = path.dirname(output); // find the path from the map to the output file
125
-
126
- // eslint-disable-next-line max-len
127
- sourceMapOptions.sourceMapOutputFilename = path.join(path.relative(mapDir, outputDir), path.basename(output)); // make the sourcemap filename point to the sourcemap relative to the css file output directory
128
-
129
- sourceMapOptions.sourceMapFilename = path.join(path.relative(outputDir, mapDir), path.basename(sourceMapOptions.sourceMapFullFilename));
130
- }
131
-
101
+ // Validate conflicting options
132
102
  if (sourceMapOptions.sourceMapURL && sourceMapOptions.disableSourcemapAnnotation) {
133
103
  console.error('You cannot provide flag --source-map-url with --source-map-no-annotation.');
134
104
  console.error('Please remove one of those flags.');
135
105
  process.exitcode = 1;
136
106
  return;
137
107
  }
138
- }
139
-
140
- if (sourceMapOptions.sourceMapBasepath === undefined) {
141
- sourceMapOptions.sourceMapBasepath = input ? path.dirname(input) : process.cwd();
142
- }
143
108
 
144
- if (sourceMapOptions.sourceMapRootpath === undefined) {
145
- var pathToMap = path.dirname((sourceMapFileInline ? output : sourceMapOptions.sourceMapFullFilename) || '.');
146
- var pathToInput = path.dirname(sourceMapOptions.sourceMapInputFilename || '.');
147
- sourceMapOptions.sourceMapRootpath = path.relative(pathToMap, pathToInput);
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;
142
+ }
148
143
  }
149
144
 
150
145
  if (!input) {
package/dist/less.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Less - Leaner CSS v4.4.2
2
+ * Less - Leaner CSS v4.5.1
3
3
  * http://lesscss.org
4
4
  *
5
5
  * Copyright (c) 2009-2025, Alexis Sellier <self@cloudhead.net>
@@ -35,9 +35,28 @@
35
35
  paths: [],
36
36
  /* color output in the terminal */
37
37
  color: true,
38
- /* The strictImports controls whether the compiler will allow an @import inside of either
39
- * @media blocks or (a later addition) other selector blocks.
40
- * See: https://github.com/less/less.js/issues/656 */
38
+ /**
39
+ * @deprecated This option has confusing behavior and may be removed in a future version.
40
+ *
41
+ * When true, prevents @import statements for .less files from being evaluated inside
42
+ * selector blocks (rulesets). The imports are silently ignored and not output.
43
+ *
44
+ * Behavior:
45
+ * - @import at root level: Always processed
46
+ * - @import inside @-rules (@media, @supports, etc.): Processed (these are not selector blocks)
47
+ * - @import inside selector blocks (.class, #id, etc.): NOT processed (silently ignored)
48
+ *
49
+ * When false (default): All @import statements are processed regardless of context.
50
+ *
51
+ * Note: Despite the name "strict", this option does NOT throw an error when imports
52
+ * are used in selector blocks - it silently ignores them. This is confusing
53
+ * behavior that may catch users off guard.
54
+ *
55
+ * Note: Only affects .less file imports. CSS imports (url(...) or .css files) are
56
+ * always output as CSS @import statements regardless of this setting.
57
+ *
58
+ * @see https://github.com/less/less.js/issues/656
59
+ */
41
60
  strictImports: false,
42
61
  /* Allow Imports from Insecure HTTPS Hosts */
43
62
  insecure: false,
@@ -1237,6 +1256,8 @@
1237
1256
  var filename = e.filename || currentFilename;
1238
1257
  this.message = e.message;
1239
1258
  this.stack = e.stack;
1259
+ // Set type early so it's always available, even if fileContentMap is missing
1260
+ this.type = e.type || 'Syntax';
1240
1261
  if (fileContentMap && filename) {
1241
1262
  var input = fileContentMap.contents[filename];
1242
1263
  var loc = getLocation(e.index, input);
@@ -1244,7 +1265,6 @@
1244
1265
  var col = loc.column;
1245
1266
  var callLine = e.call && getLocation(e.call, input).line;
1246
1267
  var lines = input ? input.split('\n') : '';
1247
- this.type = e.type || 'Syntax';
1248
1268
  this.filename = filename;
1249
1269
  this.index = e.index;
1250
1270
  this.line = typeof line === 'number' ? line + 1 : null;
@@ -1520,7 +1540,6 @@
1520
1540
  'dumpLineNumbers',
1521
1541
  'compress',
1522
1542
  'syncImport',
1523
- 'chunkInput',
1524
1543
  'mime',
1525
1544
  'useFileCache',
1526
1545
  // context
@@ -2728,151 +2747,6 @@
2728
2747
  ToCSSVisitor: ToCSSVisitor
2729
2748
  };
2730
2749
 
2731
- // Split the input into chunks.
2732
- function chunker (input, fail) {
2733
- var len = input.length;
2734
- var level = 0;
2735
- var parenLevel = 0;
2736
- var lastOpening;
2737
- var lastOpeningParen;
2738
- var lastMultiComment;
2739
- var lastMultiCommentEndBrace;
2740
- var chunks = [];
2741
- var emitFrom = 0;
2742
- var chunkerCurrentIndex;
2743
- var currentChunkStartIndex;
2744
- var cc;
2745
- var cc2;
2746
- var matched;
2747
- function emitChunk(force) {
2748
- var len = chunkerCurrentIndex - emitFrom;
2749
- if (((len < 512) && !force) || !len) {
2750
- return;
2751
- }
2752
- chunks.push(input.slice(emitFrom, chunkerCurrentIndex + 1));
2753
- emitFrom = chunkerCurrentIndex + 1;
2754
- }
2755
- for (chunkerCurrentIndex = 0; chunkerCurrentIndex < len; chunkerCurrentIndex++) {
2756
- cc = input.charCodeAt(chunkerCurrentIndex);
2757
- if (((cc >= 97) && (cc <= 122)) || (cc < 34)) {
2758
- // a-z or whitespace
2759
- continue;
2760
- }
2761
- switch (cc) {
2762
- case 40: // (
2763
- parenLevel++;
2764
- lastOpeningParen = chunkerCurrentIndex;
2765
- continue;
2766
- case 41: // )
2767
- if (--parenLevel < 0) {
2768
- return fail('missing opening `(`', chunkerCurrentIndex);
2769
- }
2770
- continue;
2771
- case 59: // ;
2772
- if (!parenLevel) {
2773
- emitChunk();
2774
- }
2775
- continue;
2776
- case 123: // {
2777
- level++;
2778
- lastOpening = chunkerCurrentIndex;
2779
- continue;
2780
- case 125: // }
2781
- if (--level < 0) {
2782
- return fail('missing opening `{`', chunkerCurrentIndex);
2783
- }
2784
- if (!level && !parenLevel) {
2785
- emitChunk();
2786
- }
2787
- continue;
2788
- case 92: // \
2789
- if (chunkerCurrentIndex < len - 1) {
2790
- chunkerCurrentIndex++;
2791
- continue;
2792
- }
2793
- return fail('unescaped `\\`', chunkerCurrentIndex);
2794
- case 34:
2795
- case 39:
2796
- case 96: // ", ' and `
2797
- matched = 0;
2798
- currentChunkStartIndex = chunkerCurrentIndex;
2799
- for (chunkerCurrentIndex = chunkerCurrentIndex + 1; chunkerCurrentIndex < len; chunkerCurrentIndex++) {
2800
- cc2 = input.charCodeAt(chunkerCurrentIndex);
2801
- if (cc2 > 96) {
2802
- continue;
2803
- }
2804
- if (cc2 == cc) {
2805
- matched = 1;
2806
- break;
2807
- }
2808
- if (cc2 == 92) { // \
2809
- if (chunkerCurrentIndex == len - 1) {
2810
- return fail('unescaped `\\`', chunkerCurrentIndex);
2811
- }
2812
- chunkerCurrentIndex++;
2813
- }
2814
- }
2815
- if (matched) {
2816
- continue;
2817
- }
2818
- return fail("unmatched `".concat(String.fromCharCode(cc), "`"), currentChunkStartIndex);
2819
- case 47: // /, check for comment
2820
- if (parenLevel || (chunkerCurrentIndex == len - 1)) {
2821
- continue;
2822
- }
2823
- cc2 = input.charCodeAt(chunkerCurrentIndex + 1);
2824
- if (cc2 == 47) {
2825
- // //, find lnfeed
2826
- for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len; chunkerCurrentIndex++) {
2827
- cc2 = input.charCodeAt(chunkerCurrentIndex);
2828
- if ((cc2 <= 13) && ((cc2 == 10) || (cc2 == 13))) {
2829
- break;
2830
- }
2831
- }
2832
- }
2833
- else if (cc2 == 42) {
2834
- // /*, find */
2835
- lastMultiComment = currentChunkStartIndex = chunkerCurrentIndex;
2836
- for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len - 1; chunkerCurrentIndex++) {
2837
- cc2 = input.charCodeAt(chunkerCurrentIndex);
2838
- if (cc2 == 125) {
2839
- lastMultiCommentEndBrace = chunkerCurrentIndex;
2840
- }
2841
- if (cc2 != 42) {
2842
- continue;
2843
- }
2844
- if (input.charCodeAt(chunkerCurrentIndex + 1) == 47) {
2845
- break;
2846
- }
2847
- }
2848
- if (chunkerCurrentIndex == len - 1) {
2849
- return fail('missing closing `*/`', currentChunkStartIndex);
2850
- }
2851
- chunkerCurrentIndex++;
2852
- }
2853
- continue;
2854
- case 42: // *, check for unmatched */
2855
- if ((chunkerCurrentIndex < len - 1) && (input.charCodeAt(chunkerCurrentIndex + 1) == 47)) {
2856
- return fail('unmatched `/*`', chunkerCurrentIndex);
2857
- }
2858
- continue;
2859
- }
2860
- }
2861
- if (level !== 0) {
2862
- if ((lastMultiComment > lastOpening) && (lastMultiCommentEndBrace > lastMultiComment)) {
2863
- return fail('missing closing `}` or `*/`', lastOpening);
2864
- }
2865
- else {
2866
- return fail('missing closing `}`', lastOpening);
2867
- }
2868
- }
2869
- else if (parenLevel !== 0) {
2870
- return fail('missing closing `)`', lastOpeningParen);
2871
- }
2872
- emitChunk(true);
2873
- return chunks;
2874
- }
2875
-
2876
2750
  var getParserInput = (function () {
2877
2751
  var // Less input string
2878
2752
  input;
@@ -3187,25 +3061,10 @@
3187
3061
  // Is the first char of the dimension 0-9, '.', '+' or '-'
3188
3062
  return (c > CHARCODE_9 || c < CHARCODE_PLUS) || c === CHARCODE_FORWARD_SLASH || c === CHARCODE_COMMA;
3189
3063
  };
3190
- parserInput.start = function (str, chunkInput, failFunction) {
3064
+ parserInput.start = function (str) {
3191
3065
  input = str;
3192
3066
  parserInput.i = j = currentPos = furthest = 0;
3193
- // chunking apparently makes things quicker (but my tests indicate
3194
- // it might actually make things slower in node at least)
3195
- // and it is a non-perfect parse - it can't recognise
3196
- // unquoted urls, meaning it can't distinguish comments
3197
- // meaning comments with quotes or {}() in them get 'counted'
3198
- // and then lead to parse errors.
3199
- // In addition if the chunking chunks in the wrong place we might
3200
- // not be able to parse a parser statement in one go
3201
- // this is officially deprecated but can be switched on via an option
3202
- // in the case it causes too much performance issues.
3203
- if (chunkInput) {
3204
- chunks = chunker(str, failFunction);
3205
- }
3206
- else {
3207
- chunks = [str];
3208
- }
3067
+ chunks = [str];
3209
3068
  current = chunks[0];
3210
3069
  skipWhitespace(0);
3211
3070
  };
@@ -3392,12 +3251,7 @@
3392
3251
  var returnNodes = [];
3393
3252
  var parser = parserInput;
3394
3253
  try {
3395
- parser.start(str, false, function fail(msg, index) {
3396
- callback({
3397
- message: msg,
3398
- index: index + currentIndex
3399
- });
3400
- });
3254
+ parser.start(str);
3401
3255
  for (var x = 0, p = void 0; (p = parseList[x]); x++) {
3402
3256
  result = parsers[p]();
3403
3257
  returnNodes.push(result || null);
@@ -3470,14 +3324,7 @@
3470
3324
  // with the `root` property set to true, so no `{}` are
3471
3325
  // output. The callback is called when the input is parsed.
3472
3326
  try {
3473
- parserInput.start(str, context.chunkInput, function fail(msg, index) {
3474
- throw new LessError({
3475
- index: index,
3476
- type: 'Parse',
3477
- message: msg,
3478
- filename: fileInfo.filename
3479
- }, imports);
3480
- });
3327
+ parserInput.start(str);
3481
3328
  tree.Node.prototype.parse = this;
3482
3329
  root = new tree.Ruleset(null, this.parsers.primary());
3483
3330
  tree.Node.prototype.rootNode = root;
@@ -6014,9 +5861,25 @@
6014
5861
  }
6015
5862
  });
6016
5863
 
5864
+ /**
5865
+ * @deprecated The dumpLineNumbers option is deprecated. Use sourcemaps instead.
5866
+ * This will be removed in a future version.
5867
+ *
5868
+ * @param {Object} ctx - Context object with debugInfo
5869
+ * @returns {string} Debug info as CSS comment
5870
+ */
6017
5871
  function asComment(ctx) {
6018
5872
  return "/* line ".concat(ctx.debugInfo.lineNumber, ", ").concat(ctx.debugInfo.fileName, " */\n");
6019
5873
  }
5874
+ /**
5875
+ * @deprecated The dumpLineNumbers option is deprecated. Use sourcemaps instead.
5876
+ * This function generates Sass-compatible debug info using @media -sass-debug-info syntax.
5877
+ * This format had short-lived usage and is no longer recommended.
5878
+ * This will be removed in a future version.
5879
+ *
5880
+ * @param {Object} ctx - Context object with debugInfo
5881
+ * @returns {string} Sass-compatible debug info as @media query
5882
+ */
6020
5883
  function asMediaQuery(ctx) {
6021
5884
  var filenameWithProtocol = ctx.debugInfo.fileName;
6022
5885
  if (!/^[a-z]+:\/\//i.test(filenameWithProtocol)) {
@@ -6029,6 +5892,19 @@
6029
5892
  return "\\".concat(a);
6030
5893
  }), "}line{font-family:\\00003").concat(ctx.debugInfo.lineNumber, "}}\n");
6031
5894
  }
5895
+ /**
5896
+ * Generates debug information (line numbers) for CSS output.
5897
+ *
5898
+ * @param {Object} context - Context object with dumpLineNumbers option
5899
+ * @param {Object} ctx - Context object with debugInfo
5900
+ * @param {string} [lineSeparator] - Separator between comment and media query (for 'all' mode)
5901
+ * @returns {string} Debug info string
5902
+ *
5903
+ * @deprecated The dumpLineNumbers option is deprecated. Use sourcemaps instead.
5904
+ * All modes ('comments', 'mediaquery', 'all') are deprecated and will be removed in a future version.
5905
+ * The 'mediaquery' and 'all' modes generate Sass-compatible @media -sass-debug-info output
5906
+ * which had short-lived usage and is no longer recommended.
5907
+ */
6032
5908
  function debugInfo(context, ctx, lineSeparator) {
6033
5909
  var result = '';
6034
5910
  if (context.dumpLineNumbers && !context.compress) {
@@ -10654,7 +10530,7 @@
10654
10530
  if (options.sourceMapFilename) {
10655
10531
  this._sourceMapFilename = options.sourceMapFilename.replace(/\\/g, '/');
10656
10532
  }
10657
- this._outputFilename = options.outputFilename;
10533
+ this._outputFilename = options.outputFilename ? options.outputFilename.replace(/\\/g, '/') : options.outputFilename;
10658
10534
  this.sourceMapURL = options.sourceMapURL;
10659
10535
  if (options.sourceMapBasepath) {
10660
10536
  this._sourceMapBasepath = options.sourceMapBasepath.replace(/\\/g, '/');
@@ -10873,12 +10749,69 @@
10873
10749
  }
10874
10750
  var toCSSOptions = {
10875
10751
  compress: compress,
10752
+ // @deprecated The dumpLineNumbers option is deprecated. Use sourcemaps instead. All modes will be removed in a future version.
10876
10753
  dumpLineNumbers: options.dumpLineNumbers,
10877
10754
  strictUnits: Boolean(options.strictUnits),
10878
10755
  numPrecision: 8
10879
10756
  };
10880
10757
  if (options.sourceMap) {
10881
- sourceMapBuilder = new SourceMapBuilder(options.sourceMap);
10758
+ // Normalize sourceMap option: if it's just true, convert to object
10759
+ if (options.sourceMap === true) {
10760
+ options.sourceMap = {};
10761
+ }
10762
+ var sourceMapOpts = options.sourceMap;
10763
+ // Set sourceMapInputFilename if not set and filename is available
10764
+ if (!sourceMapOpts.sourceMapInputFilename && options.filename) {
10765
+ sourceMapOpts.sourceMapInputFilename = options.filename;
10766
+ }
10767
+ // Default sourceMapBasepath to the input file's directory if not set
10768
+ // This matches the behavior documented and implemented in bin/lessc
10769
+ if (sourceMapOpts.sourceMapBasepath === undefined && options.filename) {
10770
+ // Get directory from filename using string manipulation (works cross-platform)
10771
+ var lastSlash = Math.max(options.filename.lastIndexOf('/'), options.filename.lastIndexOf('\\'));
10772
+ if (lastSlash >= 0) {
10773
+ sourceMapOpts.sourceMapBasepath = options.filename.substring(0, lastSlash);
10774
+ }
10775
+ else {
10776
+ // No directory separator found, use current directory
10777
+ sourceMapOpts.sourceMapBasepath = '.';
10778
+ }
10779
+ }
10780
+ // Handle sourceMapFullFilename (CLI-specific: --source-map=filename)
10781
+ // This is converted to sourceMapFilename and sourceMapOutputFilename
10782
+ if (sourceMapOpts.sourceMapFullFilename && !sourceMapOpts.sourceMapFileInline) {
10783
+ // This case is handled by lessc before calling render
10784
+ // We just need to ensure sourceMapFilename is set if sourceMapFullFilename is provided
10785
+ if (!sourceMapOpts.sourceMapFilename && !sourceMapOpts.sourceMapURL) {
10786
+ // Extract just the basename for the sourceMappingURL comment
10787
+ var mapBase = sourceMapOpts.sourceMapFullFilename.split(/[/\\]/).pop();
10788
+ sourceMapOpts.sourceMapFilename = mapBase;
10789
+ }
10790
+ }
10791
+ else if (!sourceMapOpts.sourceMapFilename && !sourceMapOpts.sourceMapURL) {
10792
+ // If sourceMapFilename is not set and sourceMapURL is not set,
10793
+ // derive it from the output filename (if available) or input filename
10794
+ if (sourceMapOpts.sourceMapOutputFilename) {
10795
+ // Use output filename + .map
10796
+ sourceMapOpts.sourceMapFilename = sourceMapOpts.sourceMapOutputFilename + '.map';
10797
+ }
10798
+ else if (options.filename) {
10799
+ // Fallback to input filename + .css.map
10800
+ var inputBase = options.filename.replace(/\.[^/.]+$/, '');
10801
+ sourceMapOpts.sourceMapFilename = inputBase + '.css.map';
10802
+ }
10803
+ }
10804
+ // Default sourceMapOutputFilename if not set
10805
+ if (!sourceMapOpts.sourceMapOutputFilename) {
10806
+ if (options.filename) {
10807
+ var inputBase = options.filename.replace(/\.[^/.]+$/, '');
10808
+ sourceMapOpts.sourceMapOutputFilename = inputBase + '.css';
10809
+ }
10810
+ else {
10811
+ sourceMapOpts.sourceMapOutputFilename = 'output.css';
10812
+ }
10813
+ }
10814
+ sourceMapBuilder = new SourceMapBuilder(sourceMapOpts);
10882
10815
  result.css = sourceMapBuilder.toCSS(evaldRoot, toCSSOptions, this.imports);
10883
10816
  }
10884
10817
  else {
@@ -11195,7 +11128,7 @@
11195
11128
  return render;
11196
11129
  }
11197
11130
 
11198
- var version = "4.4.2";
11131
+ var version = "4.5.1";
11199
11132
 
11200
11133
  function parseNodeVersion(version) {
11201
11134
  var match = version.match(/^v(\d{1,2})\.(\d{1,2})\.(\d{1,2})(?:-([0-9A-Za-z-.]+))?(?:\+([0-9A-Za-z-.]+))?$/); // eslint-disable-line max-len