From 74cac9ceea23a192b67d08eac303363a6b11a76b Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Wed, 26 Jan 2022 23:40:21 -0500 Subject: [PATCH 1/3] Switch to @ampproject/remapping to merge source maps --- packages/babel-core/package.json | 7 +- .../src/transformation/file/merge-map.ts | 314 +----------------- yarn.lock | 52 ++- 3 files changed, 57 insertions(+), 316 deletions(-) diff --git a/packages/babel-core/package.json b/packages/babel-core/package.json index f311840da8f8..e918c7c6c8b7 100644 --- a/packages/babel-core/package.json +++ b/packages/babel-core/package.json @@ -48,6 +48,7 @@ "./src/transformation/util/clone-deep.ts": "./src/transformation/util/clone-deep-browser.ts" }, "dependencies": { + "@ampproject/remapping": "^2.0.0", "@babel/code-frame": "workspace:^", "@babel/generator": "workspace:^", "@babel/helper-compilation-targets": "workspace:^", @@ -61,8 +62,7 @@ "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.1.2", - "semver": "condition:BABEL_8_BREAKING ? ^7.3.4 : ^6.3.0", - "source-map": "^0.5.0" + "semver": "condition:BABEL_8_BREAKING ? ^7.3.4 : ^6.3.0" }, "devDependencies": { "@babel/helper-transform-fixture-test-runner": "workspace:^", @@ -71,7 +71,8 @@ "@types/debug": "^4.1.0", "@types/resolve": "^1.3.2", "@types/semver": "^5.4.0", - "@types/source-map": "^0.5.0" + "@types/source-map": "^0.5.0", + "source-map": "0.6.1" }, "conditions": { "BABEL_8_BREAKING": [ diff --git a/packages/babel-core/src/transformation/file/merge-map.ts b/packages/babel-core/src/transformation/file/merge-map.ts index 4ffdb0d5b9df..7abcd957064f 100644 --- a/packages/babel-core/src/transformation/file/merge-map.ts +++ b/packages/babel-core/src/transformation/file/merge-map.ts @@ -1,321 +1,25 @@ type SourceMap = any; -import sourceMap from "source-map"; +import remapping from "@ampproject/remapping"; export default function mergeSourceMap( inputMap: SourceMap, map: SourceMap, ): SourceMap { - const input = buildMappingData(inputMap); - const output = buildMappingData(map); + const result = remapping([rootless(map), rootless(inputMap)], () => null); - const mergedGenerator = new sourceMap.SourceMapGenerator(); - for (const { source } of input.sources) { - if (typeof source.content === "string") { - mergedGenerator.setSourceContent(source.path, source.content); - } - } - - if (output.sources.length === 1) { - const defaultSource = output.sources[0]; - - const insertedMappings = new Map(); - - // Process each generated range in the input map, e.g. each range over the - // code that Babel was originally given. - eachInputGeneratedRange(input, (generated, original, source) => { - // Then pick out each range over Babel's _output_ that corresponds with - // the given range on the code given to Babel. - eachOverlappingGeneratedOutputRange(defaultSource, generated, item => { - // It's possible that multiple input ranges will overlap the same - // generated range. Since sourcemap don't traditionally represent - // generated locations with multiple original locations, we explicitly - // skip generated locations once we've seen them the first time. - const key = makeMappingKey(item); - if (insertedMappings.has(key)) return; - insertedMappings.set(key, item); - - mergedGenerator.addMapping({ - source: source.path, - original: { - line: original.line, - column: original.columnStart, - }, - generated: { - line: item.line, - column: item.columnStart, - }, - name: original.name, - }); - }); - }); - - // Since mappings are manipulated using single locations, but are interpreted - // as ranges, the insertions above may not actually have their ending - // locations mapped yet. Here be go through each one and ensure that it has - // a well-defined ending location, if one wasn't already created by the start - // of a different range. - for (const item of insertedMappings.values()) { - if (item.columnEnd === Infinity) { - continue; - } - - const clearItem = { - line: item.line, - columnStart: item.columnEnd, - }; - - const key = makeMappingKey(clearItem); - if (insertedMappings.has(key)) { - continue; - } - - // Insert mappings with no original position to terminate any mappings - // that were found above, so that they don't expand beyond their correct - // range. - // @ts-expect-error todo(flow->ts) original and source field are missing - mergedGenerator.addMapping({ - generated: { - line: clearItem.line, - column: clearItem.columnStart, - }, - }); - } - } - - const result = mergedGenerator.toJSON(); - // addMapping expects a relative path, and setSourceContent expects an - // absolute path. To avoid this whole confusion, we leave the root out - // entirely, and add it at the end here. - if (typeof input.sourceRoot === "string") { - result.sourceRoot = input.sourceRoot; + if (typeof inputMap.sourceRoot === "string") { + result.sourceRoot = inputMap.sourceRoot; } return result; } -function makeMappingKey(item: { line: number; columnStart: number }) { - return `${item.line}/${item.columnStart}`; -} - -function eachOverlappingGeneratedOutputRange( - outputFile: ResolvedFileMappings, - inputGeneratedRange: ResolvedGeneratedRange, - callback: (range: ResolvedGeneratedRange) => unknown, -) { - // Find the Babel-generated mappings that overlap with this range in the - // input sourcemap. Generated locations within the input sourcemap - // correspond with the original locations in the map Babel generates. - const overlappingOriginal = filterApplicableOriginalRanges( - outputFile, - inputGeneratedRange, - ); - - for (const { generated } of overlappingOriginal) { - for (const item of generated) { - callback(item); - } - } -} - -function filterApplicableOriginalRanges( - { mappings }: ResolvedFileMappings, - { line, columnStart, columnEnd }: ResolvedGeneratedRange, -): OriginalMappings { - // The mapping array is sorted by original location, so we can - // binary-search it for the overlapping ranges. - return filterSortedArray(mappings, ({ original: outOriginal }) => { - if (line > outOriginal.line) return -1; - if (line < outOriginal.line) return 1; - - if (columnStart >= outOriginal.columnEnd) return -1; - if (columnEnd <= outOriginal.columnStart) return 1; - - return 0; - }); -} - -function eachInputGeneratedRange( - map: ResolvedMappings, - callback: ( - c: ResolvedGeneratedRange, - b: ResolvedOriginalRange, - a: ResolvedSource, - ) => unknown, -) { - for (const { source, mappings } of map.sources) { - for (const { original, generated } of mappings) { - for (const item of generated) { - callback(item, original, source); - } - } - } -} - -type ResolvedMappings = { - file: string | undefined | null; - sourceRoot: string | undefined | null; - sources: Array; -}; - -type ResolvedFileMappings = { - source: ResolvedSource; - mappings: OriginalMappings; -}; - -type OriginalMappings = Array<{ - original: ResolvedOriginalRange; - generated: Array; -}>; - -type ResolvedSource = { - path: string; - content: string | null; -}; - -type ResolvedOriginalRange = { - line: number; - columnStart: number; - columnEnd: number; - name: string | null; -}; - -type ResolvedGeneratedRange = { - line: number; - columnStart: number; - columnEnd: number; -}; - -function buildMappingData(map: SourceMap): ResolvedMappings { - const consumer = new sourceMap.SourceMapConsumer({ +function rootless(map: SourceMap): SourceMap { + return { ...map, - // This is a bit hack. .addMapping expects source values to be relative, - // but eachMapping returns mappings with absolute paths. To avoid that - // incompatibility, we leave the sourceRoot out here and add it to the - // final map at the end instead. + // This is a bit hack. Remapping will create absolute sources in our + // sourcemap, but we want to maintain sources relative to the sourceRoot. + // We'll re-add the sourceRoot after remapping. sourceRoot: null, - }); - - const sources = new Map(); - const mappings = new Map(); - - let last = null; - - consumer.computeColumnSpans(); - - consumer.eachMapping( - m => { - if (m.originalLine === null) return; - - let source = sources.get(m.source); - if (!source) { - source = { - path: m.source, - content: consumer.sourceContentFor(m.source, true), - }; - sources.set(m.source, source); - } - - let sourceData = mappings.get(source); - if (!sourceData) { - sourceData = { - source, - mappings: [], - }; - mappings.set(source, sourceData); - } - - const obj = { - line: m.originalLine, - columnStart: m.originalColumn, - columnEnd: Infinity, - name: m.name, - }; - - if ( - last && - last.source === source && - last.mapping.line === m.originalLine - ) { - last.mapping.columnEnd = m.originalColumn; - } - - last = { - source, - mapping: obj, - }; - - sourceData.mappings.push({ - original: obj, - generated: consumer - .allGeneratedPositionsFor({ - source: m.source, - line: m.originalLine, - column: m.originalColumn, - }) - .map(item => ({ - line: item.line, - columnStart: item.column, - // source-map's lastColumn is inclusive, not exclusive, so we need - // to add 1 to it. - columnEnd: item.lastColumn + 1, - })), - }); - }, - null, - sourceMap.SourceMapConsumer.ORIGINAL_ORDER, - ); - - return { - file: map.file, - sourceRoot: map.sourceRoot, - sources: Array.from(mappings.values()), }; } - -function findInsertionLocation( - array: Array, - callback: (item: T) => number, -): number { - let left = 0; - let right = array.length; - while (left < right) { - const mid = Math.floor((left + right) / 2); - const item = array[mid]; - - const result = callback(item); - if (result === 0) { - left = mid; - break; - } - if (result >= 0) { - right = mid; - } else { - left = mid + 1; - } - } - - // Ensure the value is the start of any set of matches. - let i = left; - if (i < array.length) { - while (i >= 0 && callback(array[i]) >= 0) { - i--; - } - return i + 1; - } - - return i; -} - -function filterSortedArray( - array: Array, - callback: (item: T) => number, -): Array { - const start = findInsertionLocation(array, callback); - - const results = []; - for (let i = start; i < array.length && callback(array[i]) === 0; i++) { - results.push(array[i]); - } - - return results; -} diff --git a/yarn.lock b/yarn.lock index 2e93232e7b7e..928232e4d2ea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,6 +5,17 @@ __metadata: version: 5 cacheKey: 8 +"@ampproject/remapping@npm:^2.0.0": + version: 2.0.0 + resolution: "@ampproject/remapping@npm:2.0.0" + dependencies: + "@jridgewell/resolve-uri": ^3.0.3 + "@jridgewell/trace-mapping": ^0.2.0 + sourcemap-codec: 1.4.8 + checksum: 01165f814ffb39acb385be8f5e9debdd94faf5b582efca167df87b74a3240b96aada76a13875a479127beb3543dfe26cfab41867e88c98f528c1a72e433b4896 + languageName: node + linkType: hard + "@assemblyscript/loader@npm:^0.10.1": version: 0.10.1 resolution: "@assemblyscript/loader@npm:0.10.1" @@ -313,6 +324,7 @@ __metadata: version: 0.0.0-use.local resolution: "@babel/core@workspace:packages/babel-core" dependencies: + "@ampproject/remapping": ^2.0.0 "@babel/code-frame": "workspace:^" "@babel/generator": "workspace:^" "@babel/helper-compilation-targets": "workspace:^" @@ -334,7 +346,7 @@ __metadata: gensync: ^1.0.0-beta.2 json5: ^2.1.2 semver: "condition:BABEL_8_BREAKING ? ^7.3.4 : ^6.3.0" - source-map: ^0.5.0 + source-map: 0.6.1 languageName: unknown linkType: soft @@ -4035,6 +4047,23 @@ __metadata: languageName: node linkType: hard +"@jridgewell/resolve-uri@npm:^3.0.3": + version: 3.0.3 + resolution: "@jridgewell/resolve-uri@npm:3.0.3" + checksum: ec9053d53cc2f86d9560b6e457b1597db876cd2e96efc919c7ced9fc6b0186c8c23a58488150770557270f04d8ea7edd642efab3cb405e653285822ef840fbce + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:^0.2.0": + version: 0.2.0 + resolution: "@jridgewell/trace-mapping@npm:0.2.0" + dependencies: + "@jridgewell/resolve-uri": ^3.0.3 + sourcemap-codec: 1.4.8 + checksum: 378284cb50374953437cd4e3b1e9bd9a8973f2f5d62d155ee646da9d7bcaaad8988087c6bfc54970ff730adb8a75fb06585d51544d53d7afccec61d20e5edaa7 + languageName: node + linkType: hard + "@mdn/browser-compat-data@npm:^4.0.10": version: 4.0.10 resolution: "@mdn/browser-compat-data@npm:4.0.10" @@ -14103,6 +14132,13 @@ fsevents@^1.2.7: languageName: node linkType: hard +"source-map@npm:0.6.1, source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.1": + version: 0.6.1 + resolution: "source-map@npm:0.6.1" + checksum: 59ce8640cf3f3124f64ac289012c2b8bd377c238e316fb323ea22fbfe83da07d81e000071d7242cad7a23cd91c7de98e4df8830ec3f133cb6133a5f6e9f67bc2 + languageName: node + linkType: hard + "source-map@npm:^0.5.0, source-map@npm:^0.5.3, source-map@npm:^0.5.6, source-map@npm:~0.5.1, source-map@npm:~0.5.3": version: 0.5.7 resolution: "source-map@npm:0.5.7" @@ -14110,13 +14146,6 @@ fsevents@^1.2.7: languageName: node linkType: hard -"source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.1": - version: 0.6.1 - resolution: "source-map@npm:0.6.1" - checksum: 59ce8640cf3f3124f64ac289012c2b8bd377c238e316fb323ea22fbfe83da07d81e000071d7242cad7a23cd91c7de98e4df8830ec3f133cb6133a5f6e9f67bc2 - languageName: node - linkType: hard - "source-map@npm:^0.7.3, source-map@npm:~0.7.2": version: 0.7.3 resolution: "source-map@npm:0.7.3" @@ -14124,6 +14153,13 @@ fsevents@^1.2.7: languageName: node linkType: hard +"sourcemap-codec@npm:1.4.8": + version: 1.4.8 + resolution: "sourcemap-codec@npm:1.4.8" + checksum: b57981c05611afef31605732b598ccf65124a9fcb03b833532659ac4d29ac0f7bfacbc0d6c5a28a03e84c7510e7e556d758d0bb57786e214660016fb94279316 + languageName: node + linkType: hard + "sourcemap-codec@npm:^1.4.4": version: 1.4.6 resolution: "sourcemap-codec@npm:1.4.6" From a2004708c8e5720ee93e92ac70b2b3f6a1fb6504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Thu, 27 Jan 2022 15:50:10 +0100 Subject: [PATCH 2/3] `yarn dedupe` --- yarn.lock | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 928232e4d2ea..0607029cd557 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14153,20 +14153,13 @@ fsevents@^1.2.7: languageName: node linkType: hard -"sourcemap-codec@npm:1.4.8": +"sourcemap-codec@npm:1.4.8, sourcemap-codec@npm:^1.4.4": version: 1.4.8 resolution: "sourcemap-codec@npm:1.4.8" checksum: b57981c05611afef31605732b598ccf65124a9fcb03b833532659ac4d29ac0f7bfacbc0d6c5a28a03e84c7510e7e556d758d0bb57786e214660016fb94279316 languageName: node linkType: hard -"sourcemap-codec@npm:^1.4.4": - version: 1.4.6 - resolution: "sourcemap-codec@npm:1.4.6" - checksum: c8797dbe3767e6741f0d65e740ea5e1f7cb23395d6311d9202b827de8f85b862e106450c888f25a06b2ba11c638b58c2bf71ea81eb597e6f35de568a425a6836 - languageName: node - linkType: hard - "sparkles@npm:^1.0.0": version: 1.0.1 resolution: "sparkles@npm:1.0.1" From 5ce885d6d8567de88282fdcff008b1ae236280f1 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 27 Jan 2022 23:21:27 -0500 Subject: [PATCH 3/3] Update sourcemaps --- .../out-files/script2.js | 2 +- packages/babel-core/test/api.js | 2 +- .../source-maps/input-source-map-complex/source-map.json | 8 +++----- .../source-maps/input-source-map-external/source-map.json | 2 +- .../source-maps/input-source-map/source-map.json | 2 +- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/babel-cli/test/fixtures/babel/filename-sourcemap --out-file --source-maps inline/out-files/script2.js b/packages/babel-cli/test/fixtures/babel/filename-sourcemap --out-file --source-maps inline/out-files/script2.js index d1ac8b1f1154..a80bc98be5c3 100644 --- a/packages/babel-cli/test/fixtures/babel/filename-sourcemap --out-file --source-maps inline/out-files/script2.js +++ b/packages/babel-cli/test/fixtures/babel/filename-sourcemap --out-file --source-maps inline/out-files/script2.js @@ -4,4 +4,4 @@ arr.map(function (x) { return x * MULTIPLIER; }); -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm9yaWdpbmFsLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsR0FBQSxDQUFBLEdBQUEsQ0FBQSxVQUFBLENBQUE7QUFBQSxTQUFVLENBQUEsR0FBQSxVQUFWO0FBQUEsQ0FBQSIsImZpbGUiOiJzY3JpcHQyLmpzIiwic291cmNlc0NvbnRlbnQiOlsidmFyIGZvbyA9ICgpID0+IDQ7Il19 +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm9yaWdpbmFsLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUE7QUFBQSxTQUFVLGNBQVY7QUFBQSIsImZpbGUiOiJzY3JpcHQyLmpzIiwic291cmNlc0NvbnRlbnQiOlsidmFyIGZvbyA9ICgpID0+IDQ7Il19 diff --git a/packages/babel-core/test/api.js b/packages/babel-core/test/api.js index 4bd3419b008e..1b21b376d88e 100644 --- a/packages/babel-core/test/api.js +++ b/packages/babel-core/test/api.js @@ -540,7 +540,7 @@ describe("api", function () { column: 4, }), ).toEqual({ - name: null, + name: "Foo", source: "stdout", line: 1, column: 6, diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-complex/source-map.json b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-complex/source-map.json index 113580ce04f8..055be8f4671b 100644 --- a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-complex/source-map.json +++ b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-complex/source-map.json @@ -1,10 +1,8 @@ { "version": 3, - "sources": [ - "HelloWorld.vue" - ], - "names": [], - "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAsFA;AACA,EAAA,IAAA,EAAA,YADA;;AAEA,EAAA,IAAA,GAAA;AACA,WAAA;AACA,MAAA,GAAA,EAAA;AADA,KAAA;AAGA;;AANA,C", + "sources": ["HelloWorld.vue"], + "names": ["name", "data", "msg"], + "mappings": ";;;;;;AAsFA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAAA;AACAA,oBADA;;AAEAC;AACA;AACAC;AADA;AAGA;;AANA,C", "sourceRoot": "src/components", "sourcesContent": [ "\n\n\n\n\n\n" diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-external/source-map.json b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-external/source-map.json index 63c01db5fede..a9b75096cbb4 100644 --- a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-external/source-map.json +++ b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-external/source-map.json @@ -1,5 +1,5 @@ { - "mappings": "AAAA,IAAA,GAAA,GAAU,Y;SAAM,C;AAAC,CAAjB", + "mappings": "AAAA,UAAU,Y;SAAM,C;AAAC,CAAjB", "names": [], "sources": ["original.js"], "sourcesContent": ["var foo = () => 4;"], diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map/source-map.json b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map/source-map.json index 63c01db5fede..a9b75096cbb4 100644 --- a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map/source-map.json +++ b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map/source-map.json @@ -1,5 +1,5 @@ { - "mappings": "AAAA,IAAA,GAAA,GAAU,Y;SAAM,C;AAAC,CAAjB", + "mappings": "AAAA,UAAU,Y;SAAM,C;AAAC,CAAjB", "names": [], "sources": ["original.js"], "sourcesContent": ["var foo = () => 4;"],