source-map
Advanced tools
Comparing version 0.1.40 to 0.1.41
# Change Log | ||
## 0.1.41 | ||
* Fix a bug with getting the source content of relative sources with a "./" | ||
prefix. See issue #145 and [Bug 1090768](bugzil.la/1090768). | ||
* Add the `SourceMapConsumer.prototype.computeColumnSpans` method to compute the | ||
column span of each mapping. | ||
* Add the `SourceMapConsumer.prototype.allGeneratedPositionsFor` method to find | ||
all generated positions associated with a given original source and line. | ||
## 0.1.40 | ||
@@ -4,0 +15,0 @@ |
@@ -26,8 +26,8 @@ /* -*- Mode: js; js-indent-level: 2; -*- */ | ||
// | ||
// 2. We did not find the exact element, but we can return the next | ||
// closest element that is less than that element. | ||
// 2. We did not find the exact element, but we can return the index of | ||
// the next closest element that is less than that element. | ||
// | ||
// 3. We did not find the exact element, and there is no next-closest | ||
// element which is less than the one we are searching for, so we | ||
// return null. | ||
// return -1. | ||
var mid = Math.floor((aHigh - aLow) / 2) + aLow; | ||
@@ -37,3 +37,3 @@ var cmp = aCompare(aNeedle, aHaystack[mid], true); | ||
// Found the element we are looking for. | ||
return aHaystack[mid]; | ||
return mid; | ||
} | ||
@@ -48,3 +48,3 @@ else if (cmp > 0) { | ||
// (termination case 2). | ||
return aHaystack[mid]; | ||
return mid; | ||
} | ||
@@ -59,5 +59,3 @@ else { | ||
// we are in termination case (2) or (3) and return the appropriate thing. | ||
return aLow < 0 | ||
? null | ||
: aHaystack[aLow]; | ||
return aLow < 0 ? -1 : aLow; | ||
} | ||
@@ -68,6 +66,6 @@ } | ||
* This is an implementation of binary search which will always try and return | ||
* the next lowest value checked if there is no exact hit. This is because | ||
* mappings between original and generated line/col pairs are single points, | ||
* and there is an implicit region between each of them, so a miss just means | ||
* that you aren't on the very start of a region. | ||
* the index of next lowest value checked if there is no exact hit. This is | ||
* because mappings between original and generated line/col pairs are single | ||
* points, and there is an implicit region between each of them, so a miss | ||
* just means that you aren't on the very start of a region. | ||
* | ||
@@ -81,7 +79,8 @@ * @param aNeedle The element you are looking for. | ||
exports.search = function search(aNeedle, aHaystack, aCompare) { | ||
return aHaystack.length > 0 | ||
? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare) | ||
: null; | ||
if (aHaystack.length === 0) { | ||
return -1; | ||
} | ||
return recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare) | ||
}; | ||
}); |
@@ -69,2 +69,7 @@ /* -*- Mode: js; js-indent-level: 2; -*- */ | ||
// Some source maps produce relative source paths like "./foo.js" instead of | ||
// "foo.js". Normalize these first so that future comparisons will succeed. | ||
// See bugzil.la/1090768. | ||
sources = sources.map(util.normalize); | ||
// Pass `true` below to allow duplicate names and sources. While source maps | ||
@@ -295,2 +300,29 @@ // are intended to be compressed and deduplicated, the TypeScript compiler | ||
/** | ||
* Compute the last column for each generated mapping. The last column is | ||
* inclusive. | ||
*/ | ||
SourceMapConsumer.prototype.computeColumnSpans = | ||
function SourceMapConsumer_computeColumnSpans() { | ||
for (var index = 0; index < this._generatedMappings.length; ++index) { | ||
var mapping = this._generatedMappings[index]; | ||
// Mappings do not contain a field for the last generated columnt. We | ||
// can come up with an optimistic estimate, however, by assuming that | ||
// mappings are contiguous (i.e. given two consecutive mappings, the | ||
// first mapping ends where the second one starts). | ||
if (index + 1 < this._generatedMappings.length) { | ||
var nextMapping = this._generatedMappings[index + 1]; | ||
if (mapping.generatedLine === nextMapping.generatedLine) { | ||
mapping.lastGeneratedColumn = nextMapping.generatedColumn - 1; | ||
continue; | ||
} | ||
} | ||
// The last mapping for each line spans the entire line. | ||
mapping.lastGeneratedColumn = Infinity; | ||
} | ||
}; | ||
/** | ||
* Returns the original source, line, and column information for the generated | ||
@@ -317,19 +349,23 @@ * source's line and column positions provided. The only argument is an object | ||
var mapping = this._findMapping(needle, | ||
this._generatedMappings, | ||
"generatedLine", | ||
"generatedColumn", | ||
util.compareByGeneratedPositions); | ||
var index = this._findMapping(needle, | ||
this._generatedMappings, | ||
"generatedLine", | ||
"generatedColumn", | ||
util.compareByGeneratedPositions); | ||
if (mapping && mapping.generatedLine === needle.generatedLine) { | ||
var source = util.getArg(mapping, 'source', null); | ||
if (source != null && this.sourceRoot != null) { | ||
source = util.join(this.sourceRoot, source); | ||
if (index >= 0) { | ||
var mapping = this._generatedMappings[index]; | ||
if (mapping.generatedLine === needle.generatedLine) { | ||
var source = util.getArg(mapping, 'source', null); | ||
if (source != null && this.sourceRoot != null) { | ||
source = util.join(this.sourceRoot, source); | ||
} | ||
return { | ||
source: source, | ||
line: util.getArg(mapping, 'originalLine', null), | ||
column: util.getArg(mapping, 'originalColumn', null), | ||
name: util.getArg(mapping, 'name', null) | ||
}; | ||
} | ||
return { | ||
source: source, | ||
line: util.getArg(mapping, 'originalLine', null), | ||
column: util.getArg(mapping, 'originalColumn', null), | ||
name: util.getArg(mapping, 'name', null) | ||
}; | ||
} | ||
@@ -412,12 +448,15 @@ | ||
var mapping = this._findMapping(needle, | ||
this._originalMappings, | ||
"originalLine", | ||
"originalColumn", | ||
util.compareByOriginalPositions); | ||
var index = this._findMapping(needle, | ||
this._originalMappings, | ||
"originalLine", | ||
"originalColumn", | ||
util.compareByOriginalPositions); | ||
if (mapping) { | ||
if (index >= 0) { | ||
var mapping = this._originalMappings[index]; | ||
return { | ||
line: util.getArg(mapping, 'generatedLine', null), | ||
column: util.getArg(mapping, 'generatedColumn', null) | ||
column: util.getArg(mapping, 'generatedColumn', null), | ||
lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) | ||
}; | ||
@@ -428,6 +467,60 @@ } | ||
line: null, | ||
column: null | ||
column: null, | ||
lastColumn: null | ||
}; | ||
}; | ||
/** | ||
* Returns all generated line and column information for the original source | ||
* and line provided. The only argument is an object with the following | ||
* properties: | ||
* | ||
* - source: The filename of the original source. | ||
* - line: The line number in the original source. | ||
* | ||
* and an array of objects is returned, each with the following properties: | ||
* | ||
* - line: The line number in the generated source, or null. | ||
* - column: The column number in the generated source, or null. | ||
*/ | ||
SourceMapConsumer.prototype.allGeneratedPositionsFor = | ||
function SourceMapConsumer_allGeneratedPositionsFor(aArgs) { | ||
// When there is no exact match, SourceMapConsumer.prototype._findMapping | ||
// returns the index of the closest mapping less than the needle. By | ||
// setting needle.originalColumn to Infinity, we thus find the last | ||
// mapping for the given line, provided such a mapping exists. | ||
var needle = { | ||
source: util.getArg(aArgs, 'source'), | ||
originalLine: util.getArg(aArgs, 'line'), | ||
originalColumn: Infinity | ||
}; | ||
if (this.sourceRoot != null) { | ||
needle.source = util.relative(this.sourceRoot, needle.source); | ||
} | ||
var mappings = []; | ||
var index = this._findMapping(needle, | ||
this._originalMappings, | ||
"originalLine", | ||
"originalColumn", | ||
util.compareByOriginalPositions); | ||
if (index >= 0) { | ||
var mapping = this._originalMappings[index]; | ||
while (mapping && mapping.originalLine === needle.originalLine) { | ||
mappings.push({ | ||
line: util.getArg(mapping, 'generatedLine', null), | ||
column: util.getArg(mapping, 'generatedColumn', null), | ||
lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) | ||
}); | ||
mapping = this._originalMappings[--index]; | ||
} | ||
} | ||
return mappings.reverse(); | ||
}; | ||
SourceMapConsumer.GENERATED_ORDER = 1; | ||
@@ -434,0 +527,0 @@ SourceMapConsumer.ORIGINAL_ORDER = 2; |
{ | ||
"name": "source-map", | ||
"description": "Generates and consumes source maps", | ||
"version": "0.1.40", | ||
"version": "0.1.41", | ||
"homepage": "https://github.com/mozilla/source-map", | ||
@@ -32,3 +32,4 @@ "author": "Nick Fitzgerald <nfitzgerald@mozilla.com>", | ||
"Adam Kirkton <akirkton@truefitinnovation.com>", | ||
"Chris Montgomery <christopher.montgomery@dowjones.com>" | ||
"Chris Montgomery <christopher.montgomery@dowjones.com>", | ||
"J. Ryan Stinnett <jryans@gmail.com>" | ||
], | ||
@@ -35,0 +36,0 @@ "repository": { |
@@ -178,2 +178,7 @@ # Source Map | ||
#### SourceMapConsumer.prototype.computeColumnSpans() | ||
Compute the last column for each generated mapping. The last column is | ||
inclusive. | ||
#### SourceMapConsumer.prototype.originalPositionFor(generatedPosition) | ||
@@ -220,2 +225,18 @@ | ||
#### SourceMapConsumer.prototype.allGeneratedPositionsFor(originalPosition) | ||
Returns all generated line and column information for the original source | ||
and line provided. The only argument is an object with the following | ||
properties: | ||
* `source`: The filename of the original source. | ||
* `line`: The line number in the original source. | ||
and an array of objects is returned, each with the following properties: | ||
* `line`: The line number in the generated source, or null. | ||
* `column`: The column number in the generated source, or null. | ||
#### SourceMapConsumer.prototype.sourceContentFor(source) | ||
@@ -222,0 +243,0 @@ |
@@ -26,3 +26,3 @@ /* -*- Mode: js; js-indent-level: 2; -*- */ | ||
assert.equal(binarySearch.search(needle, haystack, numberCompare), 20); | ||
assert.equal(haystack[binarySearch.search(needle, haystack, numberCompare)], 20); | ||
}; | ||
@@ -38,3 +38,3 @@ | ||
assert.equal(binarySearch.search(needle, haystack, numberCompare), null); | ||
assert.equal(binarySearch.search(needle, haystack, numberCompare), -1); | ||
}; | ||
@@ -46,3 +46,3 @@ | ||
assert.equal(binarySearch.search(needle, haystack, numberCompare), 4); | ||
assert.equal(haystack[binarySearch.search(needle, haystack, numberCompare)], 4); | ||
}; | ||
@@ -54,5 +54,5 @@ | ||
assert.equal(binarySearch.search(needle, haystack, numberCompare), 18); | ||
assert.equal(haystack[binarySearch.search(needle, haystack, numberCompare)], 18); | ||
}; | ||
}); |
@@ -255,2 +255,21 @@ /* -*- Mode: js; js-indent-level: 2; -*- */ | ||
exports['test that we can get the original source content with relative source paths'] = function (assert, util) { | ||
var map = new SourceMapConsumer(util.testMapRelativeSources); | ||
var sources = map.sources; | ||
assert.equal(map.sourceContentFor(sources[0]), ' ONE.foo = function (bar) {\n return baz(bar);\n };'); | ||
assert.equal(map.sourceContentFor(sources[1]), ' TWO.inc = function (n) {\n return n + 1;\n };'); | ||
assert.equal(map.sourceContentFor("one.js"), ' ONE.foo = function (bar) {\n return baz(bar);\n };'); | ||
assert.equal(map.sourceContentFor("two.js"), ' TWO.inc = function (n) {\n return n + 1;\n };'); | ||
assert.throws(function () { | ||
map.sourceContentFor(""); | ||
}, Error); | ||
assert.throws(function () { | ||
map.sourceContentFor("/the/root/three.js"); | ||
}, Error); | ||
assert.throws(function () { | ||
map.sourceContentFor("three.js"); | ||
}, Error); | ||
}; | ||
exports['test sourceRoot + generatedPositionFor'] = function (assert, util) { | ||
@@ -294,2 +313,154 @@ var map = new SourceMapGenerator({ | ||
exports['test allGeneratedPositionsFor'] = function (assert, util) { | ||
var map = new SourceMapGenerator({ | ||
file: 'generated.js' | ||
}); | ||
map.addMapping({ | ||
original: { line: 1, column: 1 }, | ||
generated: { line: 2, column: 2 }, | ||
source: 'foo.coffee' | ||
}); | ||
map.addMapping({ | ||
original: { line: 1, column: 1 }, | ||
generated: { line: 2, column: 2 }, | ||
source: 'bar.coffee' | ||
}); | ||
map.addMapping({ | ||
original: { line: 2, column: 1 }, | ||
generated: { line: 3, column: 2 }, | ||
source: 'bar.coffee' | ||
}); | ||
map.addMapping({ | ||
original: { line: 2, column: 2 }, | ||
generated: { line: 3, column: 3 }, | ||
source: 'bar.coffee' | ||
}); | ||
map.addMapping({ | ||
original: { line: 3, column: 1 }, | ||
generated: { line: 4, column: 2 }, | ||
source: 'bar.coffee' | ||
}); | ||
map = new SourceMapConsumer(map.toString()); | ||
var mappings = map.allGeneratedPositionsFor({ | ||
line: 2, | ||
source: 'bar.coffee' | ||
}); | ||
assert(mappings.length, 2); | ||
assert(mappings[0].line, 3); | ||
assert(mappings[0].column, 2); | ||
assert(mappings[1].line, 3); | ||
assert(mappings[1].column, 3); | ||
}; | ||
exports['test allGeneratedPositionsFor for line with no mappings'] = function (assert, util) { | ||
var map = new SourceMapGenerator({ | ||
file: 'generated.js' | ||
}); | ||
map.addMapping({ | ||
original: { line: 1, column: 1 }, | ||
generated: { line: 2, column: 2 }, | ||
source: 'foo.coffee' | ||
}); | ||
map.addMapping({ | ||
original: { line: 1, column: 1 }, | ||
generated: { line: 2, column: 2 }, | ||
source: 'bar.coffee' | ||
}); | ||
map.addMapping({ | ||
original: { line: 3, column: 1 }, | ||
generated: { line: 4, column: 2 }, | ||
source: 'bar.coffee' | ||
}); | ||
map = new SourceMapConsumer(map.toString()); | ||
var mappings = map.allGeneratedPositionsFor({ | ||
line: 2, | ||
source: 'bar.coffee' | ||
}); | ||
assert.equal(mappings.length, 0); | ||
}; | ||
exports['test allGeneratedPositionsFor source map with no mappings'] = function (assert, util) { | ||
var map = new SourceMapGenerator({ | ||
file: 'generated.js' | ||
}); | ||
map = new SourceMapConsumer(map.toString()); | ||
var mappings = map.allGeneratedPositionsFor({ | ||
line: 2, | ||
source: 'bar.coffee' | ||
}); | ||
assert.equal(mappings.length, 0); | ||
}; | ||
exports['test computeColumnSpans'] = function (assert, util) { | ||
var map = new SourceMapGenerator({ | ||
file: 'generated.js' | ||
}); | ||
map.addMapping({ | ||
original: { line: 1, column: 1 }, | ||
generated: { line: 1, column: 1 }, | ||
source: 'foo.coffee' | ||
}); | ||
map.addMapping({ | ||
original: { line: 2, column: 1 }, | ||
generated: { line: 2, column: 1 }, | ||
source: 'foo.coffee' | ||
}); | ||
map.addMapping({ | ||
original: { line: 2, column: 2 }, | ||
generated: { line: 2, column: 10 }, | ||
source: 'foo.coffee' | ||
}); | ||
map.addMapping({ | ||
original: { line: 2, column: 3 }, | ||
generated: { line: 2, column: 20 }, | ||
source: 'foo.coffee' | ||
}); | ||
map.addMapping({ | ||
original: { line: 3, column: 1 }, | ||
generated: { line: 3, column: 1 }, | ||
source: 'foo.coffee' | ||
}); | ||
map.addMapping({ | ||
original: { line: 3, column: 2 }, | ||
generated: { line: 3, column: 2 }, | ||
source: 'foo.coffee' | ||
}); | ||
map = new SourceMapConsumer(map.toString()); | ||
map.computeColumnSpans(); | ||
var mappings = map.allGeneratedPositionsFor({ | ||
line: 1, | ||
source: 'foo.coffee' | ||
}); | ||
assert.equal(mappings.length, 1); | ||
assert.equal(mappings[0].lastColumn, Infinity); | ||
var mappings = map.allGeneratedPositionsFor({ | ||
line: 2, | ||
source: 'foo.coffee' | ||
}); | ||
assert.equal(mappings.length, 3); | ||
assert.equal(mappings[0].lastColumn, 9); | ||
assert.equal(mappings[1].lastColumn, 19); | ||
assert.equal(mappings[2].lastColumn, Infinity); | ||
var mappings = map.allGeneratedPositionsFor({ | ||
line: 3, | ||
source: 'foo.coffee' | ||
}); | ||
assert.equal(mappings.length, 2); | ||
assert.equal(mappings[0].lastColumn, 1); | ||
assert.equal(mappings[1].lastColumn, Infinity); | ||
}; | ||
exports['test sourceRoot + originalPositionFor'] = function (assert, util) { | ||
@@ -296,0 +467,0 @@ var map = new SourceMapGenerator({ |
@@ -74,2 +74,18 @@ /* -*- Mode: js; js-indent-level: 2; -*- */ | ||
}; | ||
exports.testMapRelativeSources = { | ||
version: 3, | ||
file: 'min.js', | ||
names: ['bar', 'baz', 'n'], | ||
sources: ['./one.js', './two.js'], | ||
sourcesContent: [ | ||
' ONE.foo = function (bar) {\n' + | ||
' return baz(bar);\n' + | ||
' };', | ||
' TWO.inc = function (n) {\n' + | ||
' return n + 1;\n' + | ||
' };' | ||
], | ||
sourceRoot: '/the/root', | ||
mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA' | ||
}; | ||
exports.emptyMap = { | ||
@@ -76,0 +92,0 @@ version: 3, |
196806
4631
471