diff --git a/lib/source-map-consumer.js b/lib/source-map-consumer.js index 17ef92b1..b46d7ec1 100644 --- a/lib/source-map-consumer.js +++ b/lib/source-map-consumer.js @@ -238,6 +238,9 @@ class BasicSourceMapConsumer extends SourceMapConsumer { * found. */ _findSourceIndex(aSource) { + if (aSource == null) { + return -1; + } // In the most common usecases, we'll be constantly looking up the index for the same source // files, so we cache the index lookup to avoid constantly recomputing the full URLs. const cachedIndex = this._sourceLookupCache.get(aSource); @@ -534,6 +537,9 @@ class BasicSourceMapConsumer extends SourceMapConsumer { * available. */ sourceContentFor(aSource, nullOnMissing) { + if (aSource == null) { + return null; + } if (!this.sourcesContent) { return null; } @@ -855,6 +861,9 @@ class IndexedSourceMapConsumer extends SourceMapConsumer { * available. */ sourceContentFor(aSource, nullOnMissing) { + if (aSource == null) { + return null; + } for (let i = 0; i < this._sections.length; i++) { const section = this._sections[i]; @@ -921,7 +930,8 @@ class IndexedSourceMapConsumer extends SourceMapConsumer { if ( generatedPosition.lastColumn === Infinity && nextSection && - generatedPosition.line === nextSection.generatedOffset.generatedLine + generatedPosition.line + lineShift === + nextSection.generatedOffset.generatedLine ) { generatedPosition.lastColumn = nextSection.generatedOffset.generatedColumn - 2; @@ -964,7 +974,8 @@ class IndexedSourceMapConsumer extends SourceMapConsumer { if ( generatedPosition.lastColumn === Infinity && nextSection && - generatedPosition.line === nextSection.generatedOffset.generatedLine + generatedPosition.line + lineShift === + nextSection.generatedOffset.generatedLine ) { generatedPosition.lastColumn = nextSection.generatedOffset.generatedColumn - 2; @@ -997,7 +1008,8 @@ class IndexedSourceMapConsumer extends SourceMapConsumer { if ( mapping.lastGeneratedColumn === Infinity && nextSection && - mapping.generatedLine === nextSection.generatedOffset.generatedLine + mapping.generatedLine + lineShift === + nextSection.generatedOffset.generatedLine ) { mapping.lastGeneratedColumn = nextSection.generatedOffset.generatedColumn - 2; diff --git a/test/test-source-map-consumer.js b/test/test-source-map-consumer.js index 8cf50988..49481765 100644 --- a/test/test-source-map-consumer.js +++ b/test/test-source-map-consumer.js @@ -945,6 +945,8 @@ exports["test that we can get the original sources for the sources"] = assert.throws(function () { map.sourceContentFor("three.js"); }, Error); + assert.equal(map.sourceContentFor(null), null); + assert.equal(map.sourceContentFor(undefined), null); map.destroy(); }; @@ -1559,6 +1561,78 @@ exports["test computeColumnSpans"] = async function (assert) { map.destroy(); }; +exports["test computeColumnSpans with nonzero line offset sections (#542)"] = async function (assert) { + const section = source => ({ version: 3, sources: [source], names: [], mappings: "AAAA" }); + + const map = await new SourceMapConsumer({ + version: 3, + sections: [ + { offset: { line: 0, column: 0 }, map: section("a.js") }, + { offset: { line: 2, column: 0 }, map: section("b.js") }, + { offset: { line: 2, column: 10 }, map: section("c.js") }, + ], + }); + map.computeColumnSpans(); + + const pos = map.generatedPositionFor({ source: "b.js", line: 1, column: 0 }); + assert.equal(pos.line, 3); + assert.equal(pos.column, 0); + assert.equal(pos.lastColumn, 9); + + const all = map.allGeneratedPositionsFor({ source: "b.js", line: 1, column: 0 }); + assert.equal(all.length, 1); + assert.equal(all[0].line, 3); + assert.equal(all[0].column, 0); + assert.equal(all[0].lastColumn, 9); + + const eachMappings = []; + map.eachMapping(m => eachMappings.push(m)); + const bMapping = eachMappings.find(m => m.source === "b.js"); + assert.equal(bMapping.lastGeneratedColumn, 9); + + map.destroy(); +}; + +exports["test computeColumnSpans with first section nonzero line offset (#539)"] = async function (assert) { + const consumer = await new SourceMapConsumer({ + version: 3, + sections: [ + { + offset: { line: 4, column: 3 }, + map: { version: 3, sources: ["first.js"], names: [], mappings: "AAAA" }, + }, + { + offset: { line: 4, column: 10 }, + map: { version: 3, sources: ["second.js"], names: [], mappings: "AAAA" }, + }, + ], + }); + try { + consumer.computeColumnSpans(); + const pos = consumer.generatedPositionFor({ + source: "first.js", line: 1, column: 0, + }); + assert.equal(pos.line, 5); + assert.equal(pos.column, 3); + assert.equal(pos.lastColumn, 9); + + const all = consumer.allGeneratedPositionsFor({ + source: "first.js", line: 1, column: 0, + }); + assert.equal(all.length, 1); + assert.equal(all[0].line, 5); + assert.equal(all[0].column, 3); + assert.equal(all[0].lastColumn, 9); + + const eachMappings = []; + consumer.eachMapping(m => eachMappings.push(m)); + const firstMapping = eachMappings.find(m => m.source === "first.js"); + assert.equal(firstMapping.lastGeneratedColumn, 9); + } finally { + consumer.destroy(); + } +}; + exports["test sourceRoot + originalPositionFor"] = async function (assert) { let map = new SourceMapGenerator({ sourceRoot: "foo/bar",