Skip to content

Commit 2702322

Browse files
authored
fix faulty source map generation with variables in selectors (#3761)
* fix faulty source map generation * alternative solution * add test
1 parent 9b37be7 commit 2702322

File tree

8 files changed

+113
-89
lines changed

8 files changed

+113
-89
lines changed

packages/less/src/less/parser/parser.js

+59-68
Large diffs are not rendered by default.

packages/less/src/less/tree/ruleset.js

+7-8
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import globalFunctionRegistry from '../functions/function-registry';
1111
import defaultFunc from '../functions/default';
1212
import getDebugInfo from './debug-info';
1313
import * as utils from '../utils';
14+
import Parser from '../parser/parser';
1415

1516
const Ruleset = function(selectors, rules, strictImports, visibilityInfo) {
1617
this.selectors = selectors;
@@ -79,11 +80,11 @@ Ruleset.prototype = Object.assign(new Node(), {
7980
selector = selectors[i];
8081
toParseSelectors[i] = selector.toCSS(context);
8182
}
82-
this.parse.parseNode(
83+
const startingIndex = selectors[0].getIndex();
84+
const selectorFileInfo = selectors[0].fileInfo();
85+
new Parser(context, this.parse.importManager, selectorFileInfo, startingIndex).parseNode(
8386
toParseSelectors.join(','),
84-
["selectors"],
85-
selectors[0].getIndex(),
86-
selectors[0].fileInfo(),
87+
["selectors"],
8788
function(err, result) {
8889
if (result) {
8990
selectors = utils.flattenArray(result);
@@ -354,11 +355,9 @@ Ruleset.prototype = Object.assign(new Node(), {
354355
function transformDeclaration(decl) {
355356
if (decl.value instanceof Anonymous && !decl.parsed) {
356357
if (typeof decl.value.value === 'string') {
357-
this.parse.parseNode(
358+
new Parser(this.parse.context, this.parse.importManager, decl.fileInfo(), decl.value.getIndex()).parseNode(
358359
decl.value.value,
359-
['value', 'important'],
360-
decl.value.getIndex(),
361-
decl.fileInfo(),
360+
['value', 'important'],
362361
function(err, result) {
363362
if (err) {
364363
decl.parsed = true;

packages/less/src/less/tree/selector.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Node from './node';
22
import Element from './element';
33
import LessError from '../less-error';
44
import * as utils from '../utils';
5+
import Parser from '../parser/parser';
56

67
const Selector = function(elements, extendList, condition, index, currentFileInfo, visibilityInfo) {
78
this.extendList = extendList;
@@ -44,11 +45,9 @@ Selector.prototype = Object.assign(new Node(), {
4445
return [new Element('', '&', false, this._index, this._fileInfo)];
4546
}
4647
if (typeof els === 'string') {
47-
this.parse.parseNode(
48-
els,
48+
new Parser(this.parse.context, this.parse.importManager, this._fileInfo, this._index).parseNode(
49+
els,
4950
['selector'],
50-
this._index,
51-
this._fileInfo,
5251
function(err, result) {
5352
if (err) {
5453
throw new LessError({

packages/less/test/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ var testMap = [
6363
'sourcemaps-empty/', lessTester.testEmptySourcemap],
6464
[{math: 'strict', strictUnits: true, sourceMap: {disableSourcemapAnnotation: true}},
6565
'sourcemaps-disable-annotation/', lessTester.testSourcemapWithoutUrlAnnotation],
66+
[{math: 'strict', strictUnits: true, sourceMap: true},
67+
'sourcemaps-variable-selector/', lessTester.testSourcemapWithVariableInSelector],
6668
[{globalVars: true, banner: '/**\n * Test\n */\n'}, 'globalVars/',
6769
null, null, null, function(name, type, baseFolder) { return path.join(baseFolder, name) + '.json'; }],
6870
[{modifyVars: true}, 'modifyVars/',

packages/less/test/less-test.js

+33-9
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,29 @@ module.exports = function() {
169169
}
170170
}
171171

172+
function testSourcemapWithVariableInSelector(name, err, compiledLess, doReplacements, sourcemap, baseFolder) {
173+
if (err) {
174+
fail('ERROR: ' + (err && err.message));
175+
return;
176+
}
177+
178+
// Even if annotation is not necessary, the map file should be there.
179+
fs.readFile(path.join('test/', name) + '.json', 'utf8', function (e, expectedSourcemap) {
180+
process.stdout.write('- ' + path.join(baseFolder, name) + ': ');
181+
if (sourcemap === expectedSourcemap) {
182+
ok('OK');
183+
} else if (err) {
184+
fail('ERROR: ' + (err && err.message));
185+
if (isVerbose) {
186+
process.stdout.write('\n');
187+
process.stdout.write(err.stack + '\n');
188+
}
189+
} else {
190+
difference('FAIL', expectedSourcemap, sourcemap);
191+
}
192+
});
193+
}
194+
172195
function testImports(name, err, compiledLess, doReplacements, sourcemap, baseFolder, imports) {
173196
if (err) {
174197
fail('ERROR: ' + (err && err.message));
@@ -228,7 +251,7 @@ module.exports = function() {
228251

229252
// To fix ci fail about error format change in upstream v8 project
230253
// https://github.com/v8/v8/commit/c0fd89c3c089e888c4f4e8582e56db7066fa779b
231-
// Node 16.9.0+ include this change via https://github.com/nodejs/node/pull/39947
254+
// Node 16.9.0+ include this change via https://github.com/nodejs/node/pull/39947
232255
function testTypeErrors(name, err, compiledLess, doReplacements, sourcemap, baseFolder) {
233256
const fileSuffix = semver.gte(process.version, 'v16.9.0') ? '-2.txt' : '.txt';
234257
fs.readFile(path.join(baseFolder, name) + fileSuffix, 'utf8', function (e, expectedErr) {
@@ -254,7 +277,7 @@ module.exports = function() {
254277
// https://github.com/less/less.js/issues/3112
255278
function testJSImport() {
256279
process.stdout.write('- Testing root function registry');
257-
less.functions.functionRegistry.add('ext', function() {
280+
less.functions.functionRegistry.add('ext', function() {
258281
return new less.tree.Anonymous('file');
259282
});
260283
var expected = '@charset "utf-8";\n';
@@ -282,7 +305,7 @@ module.exports = function() {
282305
.replace(/\{pathhref\}/g, '')
283306
.replace(/\{404status\}/g, '')
284307
.replace(/\{nodepath\}/g, path.join(process.cwd(), 'node_modules', '/'))
285-
.replace(/\{pathrel\}/g, path.join(path.relative(lessFolder, p), '/'))
308+
.replace(/\{pathrel\}/g, path.join(path.relative(lessFolder, p), '/'))
286309
.replace(/\{pathesc\}/g, pathesc)
287310
.replace(/\{pathimport\}/g, pathimport)
288311
.replace(/\{pathimportesc\}/g, pathimportesc)
@@ -327,7 +350,7 @@ module.exports = function() {
327350

328351
function runTestSetInternal(baseFolder, opts, foldername, verifyFunction, nameModifier, doReplacements, getFilename) {
329352
foldername = foldername || '';
330-
353+
331354
var originalOptions = opts || {};
332355

333356
if (!doReplacements) {
@@ -497,10 +520,10 @@ module.exports = function() {
497520
}
498521

499522
/**
500-
*
501-
* @param {Object} options
502-
* @param {string} filePath
503-
* @param {Function} callback
523+
*
524+
* @param {Object} options
525+
* @param {string} filePath
526+
* @param {Function} callback
504527
*/
505528
function toCSS(options, filePath, callback) {
506529
options = options || {};
@@ -577,7 +600,7 @@ module.exports = function() {
577600
}
578601
ok(stylize('OK\n', 'green'));
579602
}
580-
);
603+
);
581604
}
582605

583606
return {
@@ -588,6 +611,7 @@ module.exports = function() {
588611
testTypeErrors: testTypeErrors,
589612
testSourcemap: testSourcemap,
590613
testSourcemapWithoutUrlAnnotation: testSourcemapWithoutUrlAnnotation,
614+
testSourcemapWithVariableInSelector: testSourcemapWithVariableInSelector,
591615
testImports: testImports,
592616
testImportRedirect: testImportRedirect,
593617
testEmptySourcemap: testEmptySourcemap,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"version":3,"sources":["testweb/sourcemaps-variable-selector/basic.less"],"names":[],"mappings":"AAEC;EACG,eAAA","file":"sourcemaps-variable-selector/basic.css"}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@import (reference) "./vars.less";
2+
3+
.@{hello}-class {
4+
font-size: @font-size;
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@foo: bar;
2+
@font-size: 12px;
3+
@hello: world;

0 commit comments

Comments
 (0)