diff --git a/packages/babel-core/package.json b/packages/babel-core/package.json
index ea945a5ab950..c47dd20ceef8 100644
--- a/packages/babel-core/package.json
+++ b/packages/babel-core/package.json
@@ -48,7 +48,7 @@
"./src/transformation/util/clone-deep.ts": "./src/transformation/util/clone-deep-browser.ts"
},
"dependencies": {
- "@ampproject/remapping": "^2.0.0",
+ "@ampproject/remapping": "^2.1.0",
"@babel/code-frame": "workspace:^",
"@babel/generator": "workspace:^",
"@babel/helper-compilation-targets": "workspace:^",
diff --git a/packages/babel-core/src/transformation/file/merge-map.ts b/packages/babel-core/src/transformation/file/merge-map.ts
index 614c743f9e58..1742db173f67 100644
--- a/packages/babel-core/src/transformation/file/merge-map.ts
+++ b/packages/babel-core/src/transformation/file/merge-map.ts
@@ -6,24 +6,20 @@ export default function mergeSourceMap(
map: SourceMap,
source: string,
): SourceMap {
- const outputSources = map.sources;
-
- let result;
- if (outputSources.length > 1) {
- // When there are multiple output sources, we can't always be certain which
- // source represents the file we just transformed.
- const index = outputSources.indexOf(source);
-
- // If we can't find the source, we fall back to the legacy behavior of
- // outputting an empty sourcemap.
- if (index === -1) {
- result = emptyMap(inputMap);
- } else {
- result = mergeMultiSource(inputMap, map, index);
+ const result = remapping(rootless(map), (s, ctx) => {
+ if (s === source) {
+ // We empty the source location, which will prevent the sourcemap from
+ // becoming relative to the input's location. Eg, if we're transforming a
+ // file 'foo/bar.js', and it is a transformation of a `baz.js` file in the
+ // same directory, the expected output is just `baz.js`. Without this step,
+ // it would become `foo/baz.js`.
+ ctx.source = "";
+
+ return rootless(inputMap);
}
- } else {
- result = mergeSingleSource(inputMap, map);
- }
+
+ return null;
+ });
if (typeof inputMap.sourceRoot === "string") {
result.sourceRoot = inputMap.sourceRoot;
@@ -31,52 +27,6 @@ export default function mergeSourceMap(
return result;
}
-// A single source transformation is the default, and easiest to handle.
-function mergeSingleSource(inputMap: SourceMap, map: SourceMap): SourceMap {
- return remapping([rootless(map), rootless(inputMap)], () => null);
-}
-
-// Transformation generated an output from multiple source files. When this
-// happens, it's ambiguous which source was the transformed file, and which
-// source is from the transformation process. We use remapping's multisource
-// behavior, returning the input map when we encounter the transformed file.
-function mergeMultiSource(inputMap: SourceMap, map: SourceMap, index: number) {
- // We empty the source index, which will prevent the sourcemap from becoming
- // relative the the input's location. Eg, if we're transforming a file
- // 'foo/bar.js', and it is a transformation of a `baz.js` file in the same
- // directory, the expected output is just `baz.js`. Without this step, it
- // would become `foo/baz.js`.
- map.sources[index] = "";
-
- let count = 0;
- return remapping(rootless(map), () => {
- if (count++ === index) return rootless(inputMap);
- return null;
- });
-}
-
-// Legacy behavior of the old merger was to output a sourcemap without any
-// mappings but with copied sourcesContent. This only happens if there are
-// multiple output files and it's ambiguous which one is the transformed file.
-function emptyMap(inputMap: SourceMap) {
- const inputSources = inputMap.sources;
-
- const sources = [];
- const sourcesContent = inputMap.sourcesContent?.filter((content, i) => {
- if (typeof content !== "string") return false;
-
- sources.push(inputSources[i]);
- return true;
- });
-
- return {
- ...inputMap,
- sources,
- sourcesContent,
- mappings: "",
- };
-}
-
function rootless(map: SourceMap): SourceMap {
return {
...map,
diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/input.js b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/input.js
new file mode 100644
index 000000000000..298b7dfa0cb8
--- /dev/null
+++ b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/input.js
@@ -0,0 +1,5 @@
+foo(1);
+function foo(bar) {
+ throw new Error('Intentional.');
+}
+//# sourceMappingURL=input.js.map
diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/input.js.map b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/input.js.map
new file mode 100644
index 000000000000..4f1791f12c23
--- /dev/null
+++ b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/input.js.map
@@ -0,0 +1,9 @@
+{
+ "version": 3,
+ "sources": ["input.tsx"],
+ "names": [],
+ "mappings": "AAAA,GAAG,CAAC,CAAC,CAAC,CAAC;AACP,SAAS,GAAG,CAAC,GAAW;IACpB,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;AACpC,CAAC",
+ "sourcesContent": [
+ "foo(1);\nfunction foo(bar: number): never {\n throw new Error('Intentional.');\n}"
+ ]
+}
diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/options.json b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/options.json
new file mode 100644
index 000000000000..6466aed13cd6
--- /dev/null
+++ b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/options.json
@@ -0,0 +1,4 @@
+{
+ "inputSourceMap": true,
+ "plugins": ["./plugin.js"]
+}
diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/output.js b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/output.js
new file mode 100644
index 000000000000..b0630eb937f4
--- /dev/null
+++ b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/output.js
@@ -0,0 +1,2 @@
+"bar";
+"baz";
diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/plugin.js b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/plugin.js
new file mode 100644
index 000000000000..1d9b56675062
--- /dev/null
+++ b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/plugin.js
@@ -0,0 +1,52 @@
+module.exports = function (babel) {
+ const { types: t } = babel;
+
+ return {
+ visitor: {
+ Program(path) {
+ const { file } = this;
+ const { sourceFileName } = file.opts.generatorOpts;
+
+ // This injects the sourcesContent, though I don't imagine anyone's
+ // doing it.
+ file.code = {
+ [sourceFileName]: file.code,
+ 'bar.js': '',
+ 'baz.js': 'baz();',
+ };
+ },
+
+ CallExpression(path) {
+ const callee = path.node;
+ const { loc } = callee;
+
+ // This filename will cause a second source file to be generated in the
+ // output sourcemap.
+ loc.filename = "bar.js";
+ loc.start.column = 1;
+ loc.end.column = 4;
+
+ const node = t.stringLiteral('bar');
+ node.loc = loc;
+ path.replaceWith(node);
+ },
+
+ Function(path) {
+ const callee = path.node;
+ const { loc } = callee;
+
+ // This filename will cause a second source file to be generated in the
+ // output sourcemap.
+ loc.filename = "baz.js";
+ loc.start.column = 0;
+ loc.start.line = 1;
+ loc.end.column = 3;
+ loc.end.line = 1;
+
+ const node = t.stringLiteral('baz');
+ node.loc = loc;
+ path.replaceWith(node);
+ },
+ },
+ };
+};
diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/source-map.json b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/source-map.json
new file mode 100644
index 000000000000..3063977828b6
--- /dev/null
+++ b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources-complete-replace/source-map.json
@@ -0,0 +1,13 @@
+{
+ "mappings": "AAAC;ACAD,K",
+ "names": [],
+ "sources": [
+ "bar.js",
+ "baz.js"
+ ],
+ "sourcesContent": [
+ "",
+ "baz();"
+ ],
+ "version": 3
+}
diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources/plugin.js b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources/plugin.js
index b9fd011c05bf..a5470426bf56 100644
--- a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources/plugin.js
+++ b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-multiple-output-sources/plugin.js
@@ -20,7 +20,7 @@ module.exports = function (babel) {
path.replaceWith(node);
// This injects the sourcesContent, though I don't imagine anyone's
- // doing it.
+ // doing it.
file.code = {
[sourceFileName]: file.code,
'test.js': '',
diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/input.js b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/input.js
new file mode 100644
index 000000000000..298b7dfa0cb8
--- /dev/null
+++ b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/input.js
@@ -0,0 +1,5 @@
+foo(1);
+function foo(bar) {
+ throw new Error('Intentional.');
+}
+//# sourceMappingURL=input.js.map
diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/input.js.map b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/input.js.map
new file mode 100644
index 000000000000..4f1791f12c23
--- /dev/null
+++ b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/input.js.map
@@ -0,0 +1,9 @@
+{
+ "version": 3,
+ "sources": ["input.tsx"],
+ "names": [],
+ "mappings": "AAAA,GAAG,CAAC,CAAC,CAAC,CAAC;AACP,SAAS,GAAG,CAAC,GAAW;IACpB,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;AACpC,CAAC",
+ "sourcesContent": [
+ "foo(1);\nfunction foo(bar: number): never {\n throw new Error('Intentional.');\n}"
+ ]
+}
diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/options.json b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/options.json
new file mode 100644
index 000000000000..6466aed13cd6
--- /dev/null
+++ b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/options.json
@@ -0,0 +1,4 @@
+{
+ "inputSourceMap": true,
+ "plugins": ["./plugin.js"]
+}
diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/output.js b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/output.js
new file mode 100644
index 000000000000..e4b5496b38df
--- /dev/null
+++ b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/output.js
@@ -0,0 +1 @@
+"bar";
diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/plugin.js b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/plugin.js
new file mode 100644
index 000000000000..a6d943636079
--- /dev/null
+++ b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/plugin.js
@@ -0,0 +1,38 @@
+module.exports = function (babel) {
+ const { types: t } = babel;
+
+ return {
+ visitor: {
+ Program(path) {
+ const { file } = this;
+ const { sourceFileName } = file.opts.generatorOpts;
+
+ // This injects the sourcesContent, though I don't imagine anyone's
+ // doing it.
+ file.code = {
+ [sourceFileName]: file.code,
+ 'test.js': '',
+ };
+ },
+
+ CallExpression(path) {
+ const callee = path.node;
+ const { loc } = callee;
+
+ // This filename will cause a second source file to be generated in the
+ // output sourcemap.
+ loc.filename = "test.js";
+ loc.start.column = 1;
+ loc.end.column = 4;
+
+ const node = t.stringLiteral('bar');
+ node.loc = loc;
+ path.replaceWith(node);
+ },
+
+ Function(path) {
+ path.remove();
+ },
+ },
+ };
+};
diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/source-map.json b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/source-map.json
new file mode 100644
index 000000000000..3259064134d2
--- /dev/null
+++ b/packages/babel-core/test/fixtures/transformation/source-maps/input-source-map-sources-complete-replace/source-map.json
@@ -0,0 +1,7 @@
+{
+ "mappings": "AAAC",
+ "names": [],
+ "sources": ["test.js"],
+ "sourcesContent": [""],
+ "version": 3
+}
diff --git a/yarn.lock b/yarn.lock
index bd558cd6df86..462cd873a908 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5,13 +5,12 @@ __metadata:
version: 5
cacheKey: 8
-"@ampproject/remapping@npm:^2.0.0":
- version: 2.0.2
- resolution: "@ampproject/remapping@npm:2.0.2"
+"@ampproject/remapping@npm:^2.0.0, @ampproject/remapping@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "@ampproject/remapping@npm:2.1.0"
dependencies:
- "@jridgewell/trace-mapping": ^0.2.2
- sourcemap-codec: 1.4.8
- checksum: 5759df3715f0291cbf97099a9bb7202201a1a267e232ee1505418c768b9ae7281cd550b1da563a12808a06529eb1298744a6cabde21ac354fc8450044c7f2213
+ "@jridgewell/trace-mapping": ^0.3.0
+ checksum: 10ff0d4a559f930082f1a4c1b68dc521d5b1a75e0b8ab4829e9eedf6621386893e4a008f0db6c716f64db5d8eed49c0abcfbf3bd6ff11d5a00312454a9351ed4
languageName: node
linkType: hard
@@ -323,7 +322,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@babel/core@workspace:packages/babel-core"
dependencies:
- "@ampproject/remapping": ^2.0.0
+ "@ampproject/remapping": ^2.1.0
"@babel/code-frame": "workspace:^"
"@babel/generator": "workspace:^"
"@babel/helper-compilation-targets": "workspace:^"
@@ -4091,13 +4090,20 @@ __metadata:
languageName: node
linkType: hard
-"@jridgewell/trace-mapping@npm:^0.2.2":
- version: 0.2.5
- resolution: "@jridgewell/trace-mapping@npm:0.2.5"
+"@jridgewell/sourcemap-codec@npm:^1.4.10":
+ version: 1.4.10
+ resolution: "@jridgewell/sourcemap-codec@npm:1.4.10"
+ checksum: 247229218edbe165dcf0a5ae0c4b81bff1b5438818bb09221f756681fe158597fdf25c2a803f9260453b299c98c7e01ddebeb1555cda3157d987cd22c08605ef
+ languageName: node
+ linkType: hard
+
+"@jridgewell/trace-mapping@npm:^0.3.0":
+ version: 0.3.2
+ resolution: "@jridgewell/trace-mapping@npm:0.3.2"
dependencies:
"@jridgewell/resolve-uri": ^3.0.3
- sourcemap-codec: 1.4.8
- checksum: 7ac0a2992f4a8d16c1cbe03bccbcfbd1e96bf5071b0a794dd97904a7588cc248b73e8091fabcb13dac8f40bc51297ee4ef98a6a870ca5a4dfb8e2dcbf6f33956
+ "@jridgewell/sourcemap-codec": ^1.4.10
+ checksum: b58be6b4133cbcb20bfd28c9ca843b8db9efa0bf1d7e0e9e26b2228dace94ad53161c996ab1d762d7c3955dfc398a7734e7b84a2493ae36b451f232234fbb257
languageName: node
linkType: hard
@@ -14168,7 +14174,7 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
-"sourcemap-codec@npm:1.4.8, sourcemap-codec@npm:^1.4.4":
+"sourcemap-codec@npm:^1.4.4":
version: 1.4.8
resolution: "sourcemap-codec@npm:1.4.8"
checksum: b57981c05611afef31605732b598ccf65124a9fcb03b833532659ac4d29ac0f7bfacbc0d6c5a28a03e84c7510e7e556d758d0bb57786e214660016fb94279316