* It was broken because input source maps point to the most specific selector.
* We were tracking by least specific before.
* It is a more or less a hack since at 'stringify' stage we already lost info about original declaration.
However it works well so it's gonna be done in 3.1 (see #396).
Rebuilder.prototype.track = function (value, metadata) {
if (metadata)
- this.trackMetadata(metadata);
+ this.trackMetadata(metadata, value);
var parts = value.split('\n');
this.line += parts.length - 1;
this.column = parts.length > 1 ? 0 : (this.column + parts.pop().length);
};
-Rebuilder.prototype.trackMetadata = function (metadata) {
+Rebuilder.prototype.trackMetadata = function (metadata, value) {
var original = this.inputMapTracker.isTracking(metadata) ?
- this.inputMapTracker.originalPositionFor(metadata) :
+ this.inputMapTracker.originalPositionFor(metadata, value) :
{};
this.outputMap.addMapping({
.setTimeout(self.timeout);
}
+function originalPositionIn(trackedSource, sourceInfo, token) {
+ // FIXME: we should rather track original positions in tokenizer
+ // here it is a bit too late do do it reliably hance the hack
+ var originalPosition;
+ var maxRange = token.replace(/[>\+~]/g, ' $1 ').length;
+ var position = {
+ line: sourceInfo.line,
+ column: sourceInfo.column + maxRange
+ };
+
+ while (maxRange-- > 0) {
+ position.column--;
+ originalPosition = trackedSource.originalPositionFor(position);
+
+ if (originalPosition)
+ break;
+ }
+
+ return originalPosition;
+}
+
InputSourceMapStore.prototype.track = function (data, whenDone) {
return typeof this.options.sourceMap == 'string' ?
fromString(this, data, whenDone) :
return !!this.maps[sourceInfo.source];
};
-InputSourceMapStore.prototype.originalPositionFor = function (sourceInfo) {
- return this.maps[sourceInfo.source].originalPositionFor(sourceInfo);
+InputSourceMapStore.prototype.originalPositionFor = function (sourceInfo, token) {
+ return originalPositionIn(this.maps[sourceInfo.source], sourceInfo, token);
};
module.exports = InputSourceMapStore;
{
source: 'test/data/source-maps/styles.less',
line: 1,
- column: 0,
+ column: 4,
name: null
}
);
sourceMap.originalPositionFor({ line: 1, column: 1 }),
{
source: 'test/data/source-maps/sub/styles.less',
- line: 1,
- column: 0,
+ line: 2,
+ column: 2,
name: null
}
);
--- /dev/null
+section > div a {
+ color: red;
+}
+/*# sourceMappingURL=once.css.map */
\ No newline at end of file
--- /dev/null
+{"version":3,"sources":["once.less"],"names":[],"mappings":"AAAA,OACE,MAAM;EACJ,UAAA","file":"once.css"}
\ No newline at end of file
--- /dev/null
+section {
+ > div a {
+ color:red;
+ }
+}
--- /dev/null
+body > nav a {
+ color: red;
+}
+/*# sourceMappingURL=twice.css.map */
\ No newline at end of file
--- /dev/null
+{"version":3,"sources":["twice.less"],"names":[],"mappings":"AAAA,IACE,MACE;EACE,UAAA","file":"twice.css"}
\ No newline at end of file
--- /dev/null
+body {
+ > nav {
+ a {
+ color:red;
+ }
+ }
+}
div > a {
color: blue;
}
-/*# sourceMappingURL=styles.css.map */
+/*# sourceMappingURL=styles.css.map */
\ No newline at end of file
-{"version":3,"sources":["styles.less"],"names":[],"mappings":"AAAA,GACE;EACE,WAAA","file":"styles.css"}
\ No newline at end of file
+{"version":3,"sources":["styles.less"],"names":[],"mappings":"AAAA,GAAI;EACF,WAAA","file":"styles.css"}
\ No newline at end of file
--- /dev/null
+div > a {
+ color: blue;
+}
generatedLine: 1,
generatedColumn: 0,
originalLine: 1,
- originalColumn: 0,
+ originalColumn: 4,
source: 'styles.less',
name: null
};
var mapping = {
generatedLine: 1,
generatedColumn: 6,
- originalLine: 3,
- originalColumn: 4,
+ originalLine: 2,
+ originalColumn: 2,
source: 'styles.less',
name: null
};
generatedLine: 1,
generatedColumn: 0,
originalLine: 1,
- originalColumn: 0,
+ originalColumn: 4,
source: 'styles.less',
name: null
};
var mapping = {
generatedLine: 1,
generatedColumn: 6,
- originalLine: 3,
- originalColumn: 4,
+ originalLine: 2,
+ originalColumn: 2,
source: 'styles.less',
name: null
};
generatedLine: 1,
generatedColumn: 0,
originalLine: 1,
- originalColumn: 0,
+ originalColumn: 4,
source: 'styles.less',
name: null
};
var mapping = {
generatedLine: 1,
generatedColumn: 6,
- originalLine: 3,
- originalColumn: 4,
+ originalLine: 2,
+ originalColumn: 2,
source: 'styles.less',
name: null
};
generatedLine: 1,
generatedColumn: 14,
originalLine: 1,
- originalColumn: 0,
+ originalColumn: 4,
source: 'styles.less',
name: null
};
var mapping = {
generatedLine: 1,
generatedColumn: 20,
- originalLine: 3,
- originalColumn: 4,
+ originalLine: 2,
+ originalColumn: 2,
source: 'styles.less',
name: null
};
});
assert.equal(2, fromCSS.length);
}
+ },
+ 'nested once': {
+ 'topic': new CleanCSS({ sourceMap: true }).minify('@import url(test/data/source-maps/nested/once.css);'),
+ 'should have 2 mappings': function (minified) {
+ assert.equal(minified.sourceMap._mappings.length, 2);
+ },
+ 'should have "section > div a" mapping': function (minified) {
+ var mapping = {
+ generatedLine: 1,
+ generatedColumn: 0,
+ originalLine: 2,
+ originalColumn: 8,
+ source: 'once.less',
+ name: null
+ };
+ assert.deepEqual(mapping, minified.sourceMap._mappings[0]);
+ },
+ 'should have "color:red" mapping': function (minified) {
+ var mapping = {
+ generatedLine: 1,
+ generatedColumn: 14,
+ originalLine: 3,
+ originalColumn: 4,
+ source: 'once.less',
+ name: null
+ };
+ assert.deepEqual(mapping, minified.sourceMap._mappings[1]);
+ }
+ },
+ 'nested twice': {
+ 'topic': new CleanCSS({ sourceMap: true }).minify('@import url(test/data/source-maps/nested/twice.css);'),
+ 'should have 2 mappings': function (minified) {
+ assert.equal(minified.sourceMap._mappings.length, 2);
+ },
+ 'should have "body > nav a" mapping': function (minified) {
+ var mapping = {
+ generatedLine: 1,
+ generatedColumn: 0,
+ originalLine: 3,
+ originalColumn: 4,
+ source: 'twice.less',
+ name: null
+ };
+ assert.deepEqual(mapping, minified.sourceMap._mappings[0]);
+ },
+ 'should have "color:red" mapping': function (minified) {
+ var mapping = {
+ generatedLine: 1,
+ generatedColumn: 11,
+ originalLine: 4,
+ originalColumn: 6,
+ source: 'twice.less',
+ name: null
+ };
+ assert.deepEqual(mapping, minified.sourceMap._mappings[1]);
+ }
}
})
.addBatch({