diff --git a/lib/third-party-libs.js.flow b/lib/third-party-libs.js.flow
index 884b1e68bb..f2c81c237d 100644
--- a/lib/third-party-libs.js.flow
+++ b/lib/third-party-libs.js.flow
@@ -181,7 +181,7 @@ declare module "convert-source-map" {
fromJSON(str: string): Converter,
fromBase64(str: string): Converter,
fromComment(str: string): Converter,
- fromMapFileComment(str: string): Converter,
+ fromMapFileComment(str: string, dir: string): Converter,
fromSource(str: string): Converter,
fromMapFileSource(str: string, dir: string): Converter,
removeComments(str: string): string,
diff --git a/packages/babel-core/src/transformation/normalize-file.js b/packages/babel-core/src/transformation/normalize-file.js
index 1df42ad763..0bc88c8a0c 100644
--- a/packages/babel-core/src/transformation/normalize-file.js
+++ b/packages/babel-core/src/transformation/normalize-file.js
@@ -27,49 +27,6 @@ export default function normalizeFile(
): File {
code = `${code || ""}`;
- let inputMap = null;
- if (options.inputSourceMap !== false) {
- // If an explicit object is passed in, it overrides the processing of
- // source maps that may be in the file itself.
- if (typeof options.inputSourceMap === "object") {
- inputMap = convertSourceMap.fromObject(options.inputSourceMap);
- }
-
- if (!inputMap) {
- try {
- inputMap = convertSourceMap.fromSource(code);
-
- if (inputMap) {
- code = convertSourceMap.removeComments(code);
- }
- } catch (err) {
- debug("discarding unknown inline input sourcemap", err);
- code = convertSourceMap.removeComments(code);
- }
- }
-
- if (!inputMap) {
- if (typeof options.filename === "string") {
- try {
- inputMap = convertSourceMap.fromMapFileSource(
- code,
- path.dirname(options.filename),
- );
-
- if (inputMap) {
- code = convertSourceMap.removeMapFileComments(code);
- }
- } catch (err) {
- debug("discarding unknown file input sourcemap", err);
- code = convertSourceMap.removeMapFileComments(code);
- }
- } else {
- debug("discarding un-loadable file input sourcemap");
- code = convertSourceMap.removeMapFileComments(code);
- }
- }
- }
-
if (ast) {
if (ast.type === "Program") {
ast = t.file(ast, [], []);
@@ -84,6 +41,42 @@ export default function normalizeFile(
ast = parser(pluginPasses, options, code);
}
+ let inputMap = null;
+ if (options.inputSourceMap !== false) {
+ // If an explicit object is passed in, it overrides the processing of
+ // source maps that may be in the file itself.
+ if (typeof options.inputSourceMap === "object") {
+ inputMap = convertSourceMap.fromObject(options.inputSourceMap);
+ }
+
+ if (!inputMap) {
+ const lastComment = extractComments(INLINE_SOURCEMAP_REGEX, ast);
+ if (lastComment) {
+ try {
+ inputMap = convertSourceMap.fromComment(lastComment);
+ } catch (err) {
+ debug("discarding unknown inline input sourcemap", err);
+ }
+ }
+ }
+
+ if (!inputMap) {
+ const lastComment = extractComments(EXTERNAL_SOURCEMAP_REGEX, ast);
+ if (typeof options.filename === "string" && lastComment) {
+ try {
+ inputMap = convertSourceMap.fromMapFileComment(
+ lastComment,
+ path.dirname(options.filename),
+ );
+ } catch (err) {
+ debug("discarding unknown file input sourcemap", err);
+ }
+ } else if (lastComment) {
+ debug("discarding un-loadable file input sourcemap");
+ }
+ }
+ }
+
return new File(options, {
code,
ast,
@@ -156,3 +149,48 @@ function parser(
throw err;
}
}
+
+// These regexps are copied from the convert-source-map package,
+// but without // or /* at the beginning of the comment.
+
+// eslint-disable-next-line max-len
+const INLINE_SOURCEMAP_REGEX = /^[@#]\s+sourceMappingURL=data:(?:application|text)\/json;(?:charset[:=]\S+?;)?base64,(?:.*)$/;
+const EXTERNAL_SOURCEMAP_REGEX = /^[@#][ \t]+sourceMappingURL=([^\s'"`]+?)[ \t]*$/;
+
+function extractCommentsFromList(regex, comments, lastComment) {
+ if (comments) {
+ comments = comments.filter(({ value }) => {
+ if (regex.test(value)) {
+ lastComment = value;
+ return false;
+ }
+ return true;
+ });
+ }
+ return [comments, lastComment];
+}
+
+function extractComments(regex, ast) {
+ let lastComment = null;
+ t.traverseFast(ast, node => {
+ // $FlowIgnore destructuring with expressions is not supported
+ [node.leadingComments, lastComment] = extractCommentsFromList(
+ regex,
+ node.leadingComments,
+ lastComment,
+ );
+ // $FlowIgnore destructuring with expressions is not supported
+ [node.innerComments, lastComment] = extractCommentsFromList(
+ regex,
+ node.innerComments,
+ lastComment,
+ );
+ // $FlowIgnore destructuring with expressions is not supported
+ [node.trailingComments, lastComment] = extractCommentsFromList(
+ regex,
+ node.trailingComments,
+ lastComment,
+ );
+ });
+ return lastComment;
+}
diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/comment-inside-string/input.js b/packages/babel-core/test/fixtures/transformation/source-maps/comment-inside-string/input.js
new file mode 100644
index 0000000000..b883f5d7b9
--- /dev/null
+++ b/packages/babel-core/test/fixtures/transformation/source-maps/comment-inside-string/input.js
@@ -0,0 +1,8 @@
+// https://github.com/babel/babel/issues/9790
+const comment = `//# sourceMappingURL=${path.basename(
+ sourceMapFilename
+)}`
+
+// https://github.com/babel/babel/issues/9956
+this.shadowRoot.innerHTML = ``;
diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/comment-inside-string/options.json b/packages/babel-core/test/fixtures/transformation/source-maps/comment-inside-string/options.json
new file mode 100644
index 0000000000..0e6084f210
--- /dev/null
+++ b/packages/babel-core/test/fixtures/transformation/source-maps/comment-inside-string/options.json
@@ -0,0 +1,3 @@
+{
+ "inputSourceMap": true
+}
diff --git a/packages/babel-core/test/fixtures/transformation/source-maps/comment-inside-string/output.js b/packages/babel-core/test/fixtures/transformation/source-maps/comment-inside-string/output.js
new file mode 100644
index 0000000000..9188ec5abc
--- /dev/null
+++ b/packages/babel-core/test/fixtures/transformation/source-maps/comment-inside-string/output.js
@@ -0,0 +1,5 @@
+// https://github.com/babel/babel/issues/9790
+const comment = `//# sourceMappingURL=${path.basename(sourceMapFilename)}`; // https://github.com/babel/babel/issues/9956
+
+this.shadowRoot.innerHTML = ``;
diff --git a/packages/babel-types/src/traverse/traverseFast.js b/packages/babel-types/src/traverse/traverseFast.js
index 580628343c..e262c10ad4 100644
--- a/packages/babel-types/src/traverse/traverseFast.js
+++ b/packages/babel-types/src/traverse/traverseFast.js
@@ -7,7 +7,7 @@ import { VISITOR_KEYS } from "../definitions";
*/
export default function traverseFast(
node: Object,
- enter: (node: Node, opts?: Object) => void,
+ enter: (node: BabelNode, opts?: Object) => void,
opts?: Object,
): void {
if (!node) return;