diff --git a/lib/less/source-map-output.js b/lib/less/source-map-output.js index 4e21e24c..e0bdd362 100644 --- a/lib/less/source-map-output.js +++ b/lib/less/source-map-output.js @@ -1,10 +1,38 @@ module.exports = function (environment) { + /** + * @param source The code + * @param ignoredCharsCount Number of characters at the start of the file to ignore. + * @constructor + */ + var FileInfo = function (source, ignoredCharsCount) { + this.ignoredCharsCount = ignoredCharsCount; + this.source = source.slice(ignoredCharsCount); + this.sourceLines = this.source.split('\n'); + }; + + /** Translate absolute source offset to line/column offset. */ + FileInfo.prototype.getLocation = function (index) { + index = Math.max(0, index - this.ignoredCharsCount); + var line = 0; + for (; line < this.sourceLines.length && index >= this.sourceLines[line].length + 1; line++) { + index -= this.sourceLines[line].length + 1; // +1 for the '\n' character + } + return {line: line + 1, column: index}; + }; + var SourceMapOutput = function (options) { this._css = []; this._rootNode = options.rootNode; - this._contentsMap = options.contentsMap; - this._contentsIgnoredCharsMap = options.contentsIgnoredCharsMap; + + this._contentsInfoMap = {}; + for (var key in options.contentsMap) { + if (options.contentsMap.hasOwnProperty(key)) { + this._contentsInfoMap[key] = new FileInfo( + options.contentsMap[key], options.contentsIgnoredCharsMap[key] || 0); + } + } + if (options.sourceMapFilename) { this._sourceMapFilename = options.sourceMapFilename.replace(/\\/g, '/'); } @@ -48,39 +76,22 @@ module.exports = function (environment) { } var lines, - sourceLines, columns, - sourceColumns, i; - if (fileInfo) { - var inputSource = this._contentsMap[fileInfo.filename]; - - // remove vars/banner added to the top of the file - if (this._contentsIgnoredCharsMap[fileInfo.filename]) { - // adjust the index - index -= this._contentsIgnoredCharsMap[fileInfo.filename]; - if (index < 0) { index = 0; } - // adjust the source - inputSource = inputSource.slice(this._contentsIgnoredCharsMap[fileInfo.filename]); - } - inputSource = inputSource.substring(0, index); - sourceLines = inputSource.split("\n"); - sourceColumns = sourceLines[sourceLines.length - 1]; - } - lines = chunk.split("\n"); columns = lines[lines.length - 1]; if (fileInfo) { + var location = this._contentsInfoMap[fileInfo.filename].getLocation(index); if (!mapLines) { this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + 1, column: this._column}, - original: { line: sourceLines.length, column: sourceColumns.length}, + original: location, source: this.normalizeFilename(fileInfo.filename)}); } else { for (i = 0; i < lines.length; i++) { this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + i + 1, column: i === 0 ? this._column : 0}, - original: { line: sourceLines.length + i, column: i === 0 ? sourceColumns.length : 0}, + original: { line: location.line + i, column: i === 0 ? location.column : 0}, source: this.normalizeFilename(fileInfo.filename)}); } } @@ -105,11 +116,8 @@ module.exports = function (environment) { if (this._outputSourceFiles) { for (var filename in this._contentsMap) { - if (this._contentsMap.hasOwnProperty(filename)) { - var source = this._contentsMap[filename]; - if (this._contentsIgnoredCharsMap[filename]) { - source = source.slice(this._contentsIgnoredCharsMap[filename]); - } + if (this._contentsInfoMap.hasOwnProperty(filename)) { + var source = this._contentsInfoMap[filename].source; this._sourceMapGenerator.setSourceContent(this.normalizeFilename(filename), source); } }