|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator; |
|
var util = require('./util'); |
|
|
|
|
|
|
|
var REGEX_NEWLINE = /(\r?\n)/; |
|
|
|
|
|
var NEWLINE_CODE = 10; |
|
|
|
|
|
|
|
|
|
var isSourceNode = "$$$isSourceNode$$$"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function SourceNode(aLine, aColumn, aSource, aChunks, aName) { |
|
this.children = []; |
|
this.sourceContents = {}; |
|
this.line = aLine == null ? null : aLine; |
|
this.column = aColumn == null ? null : aColumn; |
|
this.source = aSource == null ? null : aSource; |
|
this.name = aName == null ? null : aName; |
|
this[isSourceNode] = true; |
|
if (aChunks != null) this.add(aChunks); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SourceNode.fromStringWithSourceMap = |
|
function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer, aRelativePath) { |
|
|
|
|
|
var node = new SourceNode(); |
|
|
|
|
|
|
|
|
|
|
|
var remainingLines = aGeneratedCode.split(REGEX_NEWLINE); |
|
var remainingLinesIndex = 0; |
|
var shiftNextLine = function() { |
|
var lineContents = getNextLine(); |
|
|
|
var newLine = getNextLine() || ""; |
|
return lineContents + newLine; |
|
|
|
function getNextLine() { |
|
return remainingLinesIndex < remainingLines.length ? |
|
remainingLines[remainingLinesIndex++] : undefined; |
|
} |
|
}; |
|
|
|
|
|
var lastGeneratedLine = 1, lastGeneratedColumn = 0; |
|
|
|
|
|
|
|
|
|
var lastMapping = null; |
|
|
|
aSourceMapConsumer.eachMapping(function (mapping) { |
|
if (lastMapping !== null) { |
|
|
|
|
|
if (lastGeneratedLine < mapping.generatedLine) { |
|
|
|
addMappingWithCode(lastMapping, shiftNextLine()); |
|
lastGeneratedLine++; |
|
lastGeneratedColumn = 0; |
|
|
|
} else { |
|
|
|
|
|
|
|
var nextLine = remainingLines[remainingLinesIndex] || ''; |
|
var code = nextLine.substr(0, mapping.generatedColumn - |
|
lastGeneratedColumn); |
|
remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn - |
|
lastGeneratedColumn); |
|
lastGeneratedColumn = mapping.generatedColumn; |
|
addMappingWithCode(lastMapping, code); |
|
|
|
lastMapping = mapping; |
|
return; |
|
} |
|
} |
|
|
|
|
|
|
|
while (lastGeneratedLine < mapping.generatedLine) { |
|
node.add(shiftNextLine()); |
|
lastGeneratedLine++; |
|
} |
|
if (lastGeneratedColumn < mapping.generatedColumn) { |
|
var nextLine = remainingLines[remainingLinesIndex] || ''; |
|
node.add(nextLine.substr(0, mapping.generatedColumn)); |
|
remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn); |
|
lastGeneratedColumn = mapping.generatedColumn; |
|
} |
|
lastMapping = mapping; |
|
}, this); |
|
|
|
if (remainingLinesIndex < remainingLines.length) { |
|
if (lastMapping) { |
|
|
|
addMappingWithCode(lastMapping, shiftNextLine()); |
|
} |
|
|
|
node.add(remainingLines.splice(remainingLinesIndex).join("")); |
|
} |
|
|
|
|
|
aSourceMapConsumer.sources.forEach(function (sourceFile) { |
|
var content = aSourceMapConsumer.sourceContentFor(sourceFile); |
|
if (content != null) { |
|
if (aRelativePath != null) { |
|
sourceFile = util.join(aRelativePath, sourceFile); |
|
} |
|
node.setSourceContent(sourceFile, content); |
|
} |
|
}); |
|
|
|
return node; |
|
|
|
function addMappingWithCode(mapping, code) { |
|
if (mapping === null || mapping.source === undefined) { |
|
node.add(code); |
|
} else { |
|
var source = aRelativePath |
|
? util.join(aRelativePath, mapping.source) |
|
: mapping.source; |
|
node.add(new SourceNode(mapping.originalLine, |
|
mapping.originalColumn, |
|
source, |
|
code, |
|
mapping.name)); |
|
} |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SourceNode.prototype.add = function SourceNode_add(aChunk) { |
|
if (Array.isArray(aChunk)) { |
|
aChunk.forEach(function (chunk) { |
|
this.add(chunk); |
|
}, this); |
|
} |
|
else if (aChunk[isSourceNode] || typeof aChunk === "string") { |
|
if (aChunk) { |
|
this.children.push(aChunk); |
|
} |
|
} |
|
else { |
|
throw new TypeError( |
|
"Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk |
|
); |
|
} |
|
return this; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { |
|
if (Array.isArray(aChunk)) { |
|
for (var i = aChunk.length-1; i >= 0; i--) { |
|
this.prepend(aChunk[i]); |
|
} |
|
} |
|
else if (aChunk[isSourceNode] || typeof aChunk === "string") { |
|
this.children.unshift(aChunk); |
|
} |
|
else { |
|
throw new TypeError( |
|
"Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk |
|
); |
|
} |
|
return this; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SourceNode.prototype.walk = function SourceNode_walk(aFn) { |
|
var chunk; |
|
for (var i = 0, len = this.children.length; i < len; i++) { |
|
chunk = this.children[i]; |
|
if (chunk[isSourceNode]) { |
|
chunk.walk(aFn); |
|
} |
|
else { |
|
if (chunk !== '') { |
|
aFn(chunk, { source: this.source, |
|
line: this.line, |
|
column: this.column, |
|
name: this.name }); |
|
} |
|
} |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SourceNode.prototype.join = function SourceNode_join(aSep) { |
|
var newChildren; |
|
var i; |
|
var len = this.children.length; |
|
if (len > 0) { |
|
newChildren = []; |
|
for (i = 0; i < len-1; i++) { |
|
newChildren.push(this.children[i]); |
|
newChildren.push(aSep); |
|
} |
|
newChildren.push(this.children[i]); |
|
this.children = newChildren; |
|
} |
|
return this; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { |
|
var lastChild = this.children[this.children.length - 1]; |
|
if (lastChild[isSourceNode]) { |
|
lastChild.replaceRight(aPattern, aReplacement); |
|
} |
|
else if (typeof lastChild === 'string') { |
|
this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); |
|
} |
|
else { |
|
this.children.push(''.replace(aPattern, aReplacement)); |
|
} |
|
return this; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SourceNode.prototype.setSourceContent = |
|
function SourceNode_setSourceContent(aSourceFile, aSourceContent) { |
|
this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SourceNode.prototype.walkSourceContents = |
|
function SourceNode_walkSourceContents(aFn) { |
|
for (var i = 0, len = this.children.length; i < len; i++) { |
|
if (this.children[i][isSourceNode]) { |
|
this.children[i].walkSourceContents(aFn); |
|
} |
|
} |
|
|
|
var sources = Object.keys(this.sourceContents); |
|
for (var i = 0, len = sources.length; i < len; i++) { |
|
aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]); |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
SourceNode.prototype.toString = function SourceNode_toString() { |
|
var str = ""; |
|
this.walk(function (chunk) { |
|
str += chunk; |
|
}); |
|
return str; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { |
|
var generated = { |
|
code: "", |
|
line: 1, |
|
column: 0 |
|
}; |
|
var map = new SourceMapGenerator(aArgs); |
|
var sourceMappingActive = false; |
|
var lastOriginalSource = null; |
|
var lastOriginalLine = null; |
|
var lastOriginalColumn = null; |
|
var lastOriginalName = null; |
|
this.walk(function (chunk, original) { |
|
generated.code += chunk; |
|
if (original.source !== null |
|
&& original.line !== null |
|
&& original.column !== null) { |
|
if(lastOriginalSource !== original.source |
|
|| lastOriginalLine !== original.line |
|
|| lastOriginalColumn !== original.column |
|
|| lastOriginalName !== original.name) { |
|
map.addMapping({ |
|
source: original.source, |
|
original: { |
|
line: original.line, |
|
column: original.column |
|
}, |
|
generated: { |
|
line: generated.line, |
|
column: generated.column |
|
}, |
|
name: original.name |
|
}); |
|
} |
|
lastOriginalSource = original.source; |
|
lastOriginalLine = original.line; |
|
lastOriginalColumn = original.column; |
|
lastOriginalName = original.name; |
|
sourceMappingActive = true; |
|
} else if (sourceMappingActive) { |
|
map.addMapping({ |
|
generated: { |
|
line: generated.line, |
|
column: generated.column |
|
} |
|
}); |
|
lastOriginalSource = null; |
|
sourceMappingActive = false; |
|
} |
|
for (var idx = 0, length = chunk.length; idx < length; idx++) { |
|
if (chunk.charCodeAt(idx) === NEWLINE_CODE) { |
|
generated.line++; |
|
generated.column = 0; |
|
|
|
if (idx + 1 === length) { |
|
lastOriginalSource = null; |
|
sourceMappingActive = false; |
|
} else if (sourceMappingActive) { |
|
map.addMapping({ |
|
source: original.source, |
|
original: { |
|
line: original.line, |
|
column: original.column |
|
}, |
|
generated: { |
|
line: generated.line, |
|
column: generated.column |
|
}, |
|
name: original.name |
|
}); |
|
} |
|
} else { |
|
generated.column++; |
|
} |
|
} |
|
}); |
|
this.walkSourceContents(function (sourceFile, sourceContent) { |
|
map.setSourceContent(sourceFile, sourceContent); |
|
}); |
|
|
|
return { code: generated.code, map: map }; |
|
}; |
|
|
|
exports.SourceNode = SourceNode; |
|
|