diff --git a/lib/sourcemap.js b/lib/sourcemap.js index 178a20887..b8378bb24 100644 --- a/lib/sourcemap.js +++ b/lib/sourcemap.js @@ -76,12 +76,21 @@ async function SourceMap(options) { } function add(source, gen_line, gen_col, orig_line, orig_col, name) { + var generatedPos = { line: gen_line + options.dest_line_diff, column: gen_col }; if (orig_map) { var info = orig_map.originalPositionFor({ line: orig_line, column: orig_col }); if (info.source === null) { + if (generatedPos.column !== 0) { + generator.addMapping({ + generated: generatedPos, + original: null, + source: null, + name: null + }); + } return; } source = info.source; @@ -90,7 +99,7 @@ async function SourceMap(options) { name = info.name || name; } generator.addMapping({ - generated : { line: gen_line + options.dest_line_diff, column: gen_col }, + generated : generatedPos, original : { line: orig_line + options.orig_line_diff, column: orig_col }, source : source, name : name diff --git a/test/mocha/input-sourcemaps.js b/test/mocha/input-sourcemaps.js index 55d624cb9..e0bffb435 100644 --- a/test/mocha/input-sourcemaps.js +++ b/test/mocha/input-sourcemaps.js @@ -2,7 +2,7 @@ import assert from "assert"; import { minify } from "../../main.js"; import source_map from "source-map" -const { SourceMapConsumer } = source_map +const { SourceMapConsumer, SourceMapGenerator } = source_map describe("input sourcemaps", function() { var transpilemap, map; @@ -65,4 +65,52 @@ describe("input sourcemaps", function() { assert.ok(pos.line <= 2, msg); }) }); + + it("Should preserve unmapped segments in output source map", async function() { + var generator = new SourceMapGenerator(); + + generator.addMapping({ + source: "source.ts", + generated: {line: 1, column: 0}, + original: {line: 1, column: 0}, + }); + generator.addMapping({ + source: null, + generated: {line: 1, column: 37}, + original: null, + }); + + generator.addMapping({ + source: "source.ts", + generated: {line: 1, column: 50}, + original: {line: 2, column: 0}, + }); + + generator.setSourceContent("source.ts", + `function say(msg) {console.log(msg)};say('hello');\nprocess.exit(1);`) + + // Everything except the "say('hello');" part is mapped to "source.ts". The "say" + // function call is not mapped to any original source location. e.g. this can + // happen when a code transformer inserts generated code in between existing code. + var inputFile = "function say(msg) {console.log(msg)};say('hello');process.exit(1);"; + var result = await minify(inputFile, { + sourceMap: { + content: JSON.parse(generator.toString()), + url: 'inline' + } + }); + + var transformedMap = await new SourceMapConsumer(result.map); + var hasMappedSource = true; + + for (let i = 0; i < result.code.length; i++) { + var info = transformedMap.originalPositionFor({line: 1, column: i}); + hasMappedSource = hasMappedSource && !!info.source; + } + + assert.equal(hasMappedSource, false, "Expected transformed source map to preserve the " + + "mapping without original source location"); + + assert.doesNotThrow(() => SourceMapGenerator.fromSourceMap(transformedMap)); + }); });