Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SourceMapConsumer.fromSourceMap #78

Merged
merged 4 commits into from Sep 24, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/source-map/binary-search.js
Expand Up @@ -30,7 +30,7 @@ define(function (require, exports, module) {
// element which is less than the one we are searching for, so we
// return null.
var mid = Math.floor((aHigh - aLow) / 2) + aLow;
var cmp = aCompare(aNeedle, aHaystack[mid]);
var cmp = aCompare(aNeedle, aHaystack[mid], true);
if (cmp === 0) {
// Found the element we are looking for.
return aHaystack[mid];
Expand Down
62 changes: 29 additions & 33 deletions lib/source-map/source-map-consumer.js
Expand Up @@ -100,6 +100,32 @@ define(function (require, exports, module) {
this._parseMappings(mappings, sourceRoot);
}

/**
* Create a SourceMapConsumer from a SourceMapGenerator.
*
* @param SourceMapGenerator aSourceMap
* The source map that will be consumed.
* @returns SourceMapConsumer
*/
SourceMapConsumer.fromSourceMap =
function SourceMapConsumer_fromSourceMap(aSourceMap) {
var smc = Object.create(SourceMapConsumer.prototype);

smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true);
smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true);
smc.sourceRoot = aSourceMap._sourceRoot;
smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(),
smc.sourceRoot);
smc.file = aSourceMap._file;

smc._generatedMappings = aSourceMap._mappings.slice()
.sort(util.compareByGeneratedPositions);
smc._originalMappings = aSourceMap._mappings.slice()
.sort(util.compareByOriginalPositions);

return smc;
};

/**
* The version of the source mapping spec that we are consuming.
*/
Expand Down Expand Up @@ -195,37 +221,7 @@ define(function (require, exports, module) {
}
}

this._originalMappings.sort(this._compareOriginalPositions);
};

/**
* Comparator between two mappings where the original positions are compared.
*/
SourceMapConsumer.prototype._compareOriginalPositions =
function SourceMapConsumer_compareOriginalPositions(mappingA, mappingB) {
if (mappingA.source > mappingB.source) {
return 1;
}
else if (mappingA.source < mappingB.source) {
return -1;
}
else {
var cmp = mappingA.originalLine - mappingB.originalLine;
return cmp === 0
? mappingA.originalColumn - mappingB.originalColumn
: cmp;
}
};

/**
* Comparator between two mappings where the generated positions are compared.
*/
SourceMapConsumer.prototype._compareGeneratedPositions =
function SourceMapConsumer_compareGeneratedPositions(mappingA, mappingB) {
var cmp = mappingA.generatedLine - mappingB.generatedLine;
return cmp === 0
? mappingA.generatedColumn - mappingB.generatedColumn
: cmp;
this._originalMappings.sort(util.compareByOriginalPositions);
};

/**
Expand Down Expand Up @@ -278,7 +274,7 @@ define(function (require, exports, module) {
this._generatedMappings,
"generatedLine",
"generatedColumn",
this._compareGeneratedPositions);
util.compareByGeneratedPositions);

if (mapping) {
var source = util.getArg(mapping, 'source', null);
Expand Down Expand Up @@ -372,7 +368,7 @@ define(function (require, exports, module) {
this._originalMappings,
"originalLine",
"originalColumn",
this._compareOriginalPositions);
util.compareByOriginalPositions);

if (mapping) {
return {
Expand Down
81 changes: 36 additions & 45 deletions lib/source-map/source-map-generator.js
Expand Up @@ -107,8 +107,10 @@ define(function (require, exports, module) {
}

this._mappings.push({
generated: generated,
original: original,
generatedLine: generated.line,
generatedColumn: generated.column,
originalLine: original != null && original.line,
originalColumn: original != null && original.column,
source: source,
name: name
});
Expand Down Expand Up @@ -169,11 +171,11 @@ define(function (require, exports, module) {

// Find mappings for the "aSourceFile"
this._mappings.forEach(function (mapping) {
if (mapping.source === aSourceFile && mapping.original) {
if (mapping.source === aSourceFile && mapping.originalLine) {
// Check if it can be mapped by the source map, then update the mapping.
var original = aSourceMapConsumer.originalPositionFor({
line: mapping.original.line,
column: mapping.original.column
line: mapping.originalLine,
column: mapping.originalColumn
});
if (original.source !== null) {
// Copy mapping
Expand All @@ -182,8 +184,8 @@ define(function (require, exports, module) {
} else {
mapping.source = original.source;
}
mapping.original.line = original.line;
mapping.original.column = original.column;
mapping.originalLine = original.line;
mapping.originalColumn = original.column;
if (original.name !== null && mapping.name !== null) {
// Only use the identifier name if it's an identifier
// in both SourceMaps
Expand Down Expand Up @@ -251,24 +253,6 @@ define(function (require, exports, module) {
}
};

function cmpLocation(loc1, loc2) {
var cmp = (loc1 && loc1.line) - (loc2 && loc2.line);
return cmp ? cmp : (loc1 && loc1.column) - (loc2 && loc2.column);
}

function strcmp(str1, str2) {
str1 = str1 || '';
str2 = str2 || '';
return (str1 > str2) - (str1 < str2);
}

function cmpMapping(mappingA, mappingB) {
return cmpLocation(mappingA.generated, mappingB.generated) ||
cmpLocation(mappingA.original, mappingB.original) ||
strcmp(mappingA.source, mappingB.source) ||
strcmp(mappingA.name, mappingB.name);
}

/**
* Serialize the accumulated mappings in to the stream of base 64 VLQs
* specified by the source map format.
Expand All @@ -289,44 +273,44 @@ define(function (require, exports, module) {
// via the ';' separators) will be all messed up. Note: it might be more
// performant to maintain the sorting as we insert them, rather than as we
// serialize them, but the big O is the same either way.
this._mappings.sort(cmpMapping);
this._mappings.sort(util.compareByGeneratedPositions);

for (var i = 0, len = this._mappings.length; i < len; i++) {
mapping = this._mappings[i];

if (mapping.generated.line !== previousGeneratedLine) {
if (mapping.generatedLine !== previousGeneratedLine) {
previousGeneratedColumn = 0;
while (mapping.generated.line !== previousGeneratedLine) {
while (mapping.generatedLine !== previousGeneratedLine) {
result += ';';
previousGeneratedLine++;
}
}
else {
if (i > 0) {
if (!cmpMapping(mapping, this._mappings[i - 1])) {
if (!util.compareByGeneratedPositions(mapping, this._mappings[i - 1])) {
continue;
}
result += ',';
}
}

result += base64VLQ.encode(mapping.generated.column
result += base64VLQ.encode(mapping.generatedColumn
- previousGeneratedColumn);
previousGeneratedColumn = mapping.generated.column;
previousGeneratedColumn = mapping.generatedColumn;

if (mapping.source && mapping.original) {
if (mapping.source) {
result += base64VLQ.encode(this._sources.indexOf(mapping.source)
- previousSource);
previousSource = this._sources.indexOf(mapping.source);

// lines are stored 0-based in SourceMap spec version 3
result += base64VLQ.encode(mapping.original.line - 1
result += base64VLQ.encode(mapping.originalLine - 1
- previousOriginalLine);
previousOriginalLine = mapping.original.line - 1;
previousOriginalLine = mapping.originalLine - 1;

result += base64VLQ.encode(mapping.original.column
result += base64VLQ.encode(mapping.originalColumn
- previousOriginalColumn);
previousOriginalColumn = mapping.original.column;
previousOriginalColumn = mapping.originalColumn;

if (mapping.name) {
result += base64VLQ.encode(this._names.indexOf(mapping.name)
Expand All @@ -339,6 +323,20 @@ define(function (require, exports, module) {
return result;
};

SourceMapGenerator.prototype._generateSourcesContent =
function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) {
return aSources.map(function (source) {
if (aSourceRoot) {
source = util.relative(aSourceRoot, source);
}
var key = util.toSetString(source);
return Object.prototype.hasOwnProperty.call(this._sourcesContents,
key)
? this._sourcesContents[key]
: null;
}, this);
};

/**
* Externalize the source map.
*/
Expand All @@ -355,16 +353,9 @@ define(function (require, exports, module) {
map.sourceRoot = this._sourceRoot;
}
if (this._sourcesContents) {
map.sourcesContent = map.sources.map(function (source) {
if (map.sourceRoot) {
source = util.relative(map.sourceRoot, source);
}
return Object.prototype.hasOwnProperty.call(
this._sourcesContents, util.toSetString(source))
? this._sourcesContents[util.toSetString(source)]
: null;
}, this);
map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot);
}

return map;
};

Expand Down
22 changes: 13 additions & 9 deletions lib/source-map/source-node.js
Expand Up @@ -193,7 +193,9 @@ define(function (require, exports, module) {
* @param aFn The traversal function.
*/
SourceNode.prototype.walk = function SourceNode_walk(aFn) {
this.children.forEach(function (chunk) {
var chunk;
for (var i = 0, len = this.children.length; i < len; i++) {
chunk = this.children[i];
if (chunk instanceof SourceNode) {
chunk.walk(aFn);
}
Expand All @@ -205,7 +207,7 @@ define(function (require, exports, module) {
name: this.name });
}
}
}, this);
}
};

/**
Expand Down Expand Up @@ -271,14 +273,16 @@ define(function (require, exports, module) {
*/
SourceNode.prototype.walkSourceContents =
function SourceNode_walkSourceContents(aFn) {
this.children.forEach(function (chunk) {
if (chunk instanceof SourceNode) {
chunk.walkSourceContents(aFn);
for (var i = 0, len = this.children.length; i < len; i++) {
if (this.children[i] instanceof SourceNode) {
this.children[i].walkSourceContents(aFn);
}
}, this);
Object.keys(this.sourceContents).forEach(function (sourceFileKey) {
aFn(util.fromSetString(sourceFileKey), this.sourceContents[sourceFileKey]);
}, this);
}

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]]);
}
};

/**
Expand Down
87 changes: 87 additions & 0 deletions lib/source-map/util.js
Expand Up @@ -115,4 +115,91 @@ define(function (require, exports, module) {
}
exports.relative = relative;

function strcmp(aStr1, aStr2) {
var s1 = aStr1 || "";
var s2 = aStr2 || "";
return (s1 > s2) - (s1 < s2);
}

/**
* Comparator between two mappings where the original positions are compared.
*
* Optionally pass in `true` as `onlyCompareGenerated` to consider two
* mappings with the same original source/line/column, but different generated
* line and column the same. Useful when searching for a mapping with a
* stubbed out mapping.
*/
function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) {
var cmp;

cmp = strcmp(mappingA.source, mappingB.source);
if (cmp) {
return cmp;
}

cmp = mappingA.originalLine - mappingB.originalLine;
if (cmp) {
return cmp;
}

cmp = mappingA.originalColumn - mappingB.originalColumn;
if (cmp || onlyCompareOriginal) {
return cmp;
}

cmp = strcmp(mappingA.name, mappingB.name);
if (cmp) {
return cmp;
}

cmp = mappingA.generatedLine - mappingB.generatedLine;
if (cmp) {
return cmp;
}

return mappingA.generatedColumn - mappingB.generatedColumn;
};
exports.compareByOriginalPositions = compareByOriginalPositions;

/**
* Comparator between two mappings where the generated positions are
* compared.
*
* Optionally pass in `true` as `onlyCompareGenerated` to consider two
* mappings with the same generated line and column, but different
* source/name/original line and column the same. Useful when searching for a
* mapping with a stubbed out mapping.
*/
function compareByGeneratedPositions(mappingA, mappingB, onlyCompareGenerated) {
var cmp;

cmp = mappingA.generatedLine - mappingB.generatedLine;
if (cmp) {
return cmp;
}

cmp = mappingA.generatedColumn - mappingB.generatedColumn;
if (cmp || onlyCompareGenerated) {
return cmp;
}

cmp = strcmp(mappingA.source, mappingB.source);
if (cmp) {
return cmp;
}

cmp = mappingA.originalLine - mappingB.originalLine;
if (cmp) {
return cmp;
}

cmp = mappingA.originalColumn - mappingB.originalColumn;
if (cmp) {
return cmp;
}

return strcmp(mappingA.name, mappingB.name);
};
exports.compareByGeneratedPositions = compareByGeneratedPositions;

});