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;