diff --git a/lib/internal/source_map/source_map_cache.js b/lib/internal/source_map/source_map_cache.js index 603685290ad85f..c930abee2aec81 100644 --- a/lib/internal/source_map/source_map_cache.js +++ b/lib/internal/source_map/source_map_cache.js @@ -5,9 +5,12 @@ const { JSONParse, ObjectFreeze, RegExpPrototypeExec, + RegExpPrototypeSymbolMatch, SafeMap, StringPrototypeCodePointAt, + StringPrototypeIndexOf, StringPrototypeSplit, + StringPrototypeSubstring, } = primordials; // See https://tc39.es/ecma426/ for SourceMap V3 specification. @@ -37,8 +40,8 @@ const getModuleSourceMapCache = getLazy(() => { // source url magic comments. const generatedSourceMapCache = new SafeMap(); const kLeadingProtocol = /^\w+:\/\//; -const kSourceMappingURLMagicComment = /\/[*/]#\s+sourceMappingURL=(?[^\s]+)/g; -const kSourceURLMagicComment = /\/[*/]#\s+sourceURL=(?[^\s]+)/g; +const kSourceMappingURLMagicComment = /\/[*/]#\s+sourceMappingURL=[^\s]+/g; +const kSourceURLMagicComment = /\/[*/]#\s+sourceURL=[^\s]+/g; const { isAbsolute } = require('path'); const { fileURLToPath, pathToFileURL, URL, URLParse } = require('internal/url'); @@ -99,17 +102,12 @@ function setSourceMapsSupport(enabled, options = kEmptyObject) { * @returns {string | null} source url or null if not present */ function extractSourceURLMagicComment(content) { - let match; - let matchSourceURL; - // A while loop is used here to get the last occurrence of sourceURL. - // This is needed so that we don't match sourceURL in string literals. - while ((match = RegExpPrototypeExec(kSourceURLMagicComment, content))) { - matchSourceURL = match; - } - if (matchSourceURL == null) { + const matches = RegExpPrototypeSymbolMatch(kSourceURLMagicComment, content); + if (matches == null || matches.length === 0) { return null; } - let sourceURL = matchSourceURL.groups.sourceURL; + const match = matches[matches.length - 1]; + let sourceURL = StringPrototypeSubstring(match, StringPrototypeIndexOf(match, '=') + 1); if (sourceURL != null && RegExpPrototypeExec(kLeadingProtocol, sourceURL) === null) { sourceURL = pathToFileURL(sourceURL).href; } @@ -125,17 +123,12 @@ function extractSourceURLMagicComment(content) { * @returns {string | null} source map url or null if not present */ function extractSourceMapURLMagicComment(content) { - let match; - let lastMatch; - // A while loop is used here to get the last occurrence of sourceMappingURL. - // This is needed so that we don't match sourceMappingURL in string literals. - while ((match = RegExpPrototypeExec(kSourceMappingURLMagicComment, content))) { - lastMatch = match; - } - if (lastMatch == null) { + const matches = RegExpPrototypeSymbolMatch(kSourceMappingURLMagicComment, content); + if (matches == null || matches.length === 0) { return null; } - return lastMatch.groups.sourceMappingURL; + const match = matches[matches.length - 1]; + return StringPrototypeSubstring(match, StringPrototypeIndexOf(match, '=') + 1); } /** diff --git a/test/fixtures/source-map/output/source_map_eval.snapshot b/test/fixtures/source-map/output/source_map_eval.snapshot index ff636e44063aa7..9446bc7e2666b4 100644 --- a/test/fixtures/source-map/output/source_map_eval.snapshot +++ b/test/fixtures/source-map/output/source_map_eval.snapshot @@ -1,10 +1,10 @@ -*/synthesized/workspace/tabs-source-url.coffee:26 +*/synthesized/workspace/tabs-source-url.coffee:32 alert "I knew it!" ^ ReferenceError: alert is not defined - at Object.eval (*/synthesized/workspace/tabs-source-url.coffee:26:2) + at Object.eval (*/synthesized/workspace/tabs-source-url.coffee:32:2) at eval (*/synthesized/workspace/tabs-source-url.coffee:1:14) at Object. (*/test/fixtures/source-map/output/source_map_eval.js:11:1) diff --git a/test/fixtures/source-map/tabs-source-url.coffee b/test/fixtures/source-map/tabs-source-url.coffee index 7e73a605d32fc9..8127fb6dda61a3 100644 --- a/test/fixtures/source-map/tabs-source-url.coffee +++ b/test/fixtures/source-map/tabs-source-url.coffee @@ -21,6 +21,12 @@ math = race = (winner, runners...) -> print winner, runners +# Multiple sourceMappingURL comments +## sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFicy1zb3VyY2UtdXJsLmpzIiwic + +# sourceMappingURL inside strings +sourceMappingURL = "//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFicy1zb3VyY2UtdXJsLmpzIiwic" + # Existence: if true alert "I knew it!" diff --git a/test/fixtures/source-map/tabs-source-url.js b/test/fixtures/source-map/tabs-source-url.js index a4b43806a5f2f5..079f28d8c038ea 100644 --- a/test/fixtures/source-map/tabs-source-url.js +++ b/test/fixtures/source-map/tabs-source-url.js @@ -1,7 +1,7 @@ // Generated by CoffeeScript 2.5.1 (function() { // Assignment: - var cubes, list, math, num, number, opposite, race, square; + var cubes, list, math, num, number, opposite, race, sourceMappingURL, square; number = 42; @@ -34,6 +34,12 @@ return print(winner, runners); }; + // Multiple sourceMappingURL comments + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFicy1zb3VyY2UtdXJsLmpzIiwic + + // sourceMappingURL inside strings + sourceMappingURL = "//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFicy1zb3VyY2UtdXJsLmpzIiwic"; + // Existence: if (true) { alert("I knew it!"); @@ -57,5 +63,5 @@ }).call(this); -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFicy1zb3VyY2UtdXJsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidGFicy1zb3VyY2UtdXJsLmNvZmZlZSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQWE7RUFBQTtBQUFBLE1BQUEsS0FBQSxFQUFBLElBQUEsRUFBQSxJQUFBLEVBQUEsR0FBQSxFQUFBLE1BQUEsRUFBQSxRQUFBLEVBQUEsSUFBQSxFQUFBOztFQUNiLE1BQUEsR0FBVzs7RUFDWCxRQUFBLEdBQVc7O0VBR1gsSUFBZ0IsUUFBaEI7O0lBQUEsTUFBQSxHQUFTLENBQUMsR0FBVjtHQUxhOzs7RUFRYixNQUFBLEdBQVMsUUFBQSxDQUFDLENBQUQsQ0FBQTtXQUFPLENBQUEsR0FBSTtFQUFYLEVBUkk7OztFQVdiLElBQUEsR0FBTyxDQUFDLENBQUQsRUFBSSxDQUFKLEVBQU8sQ0FBUCxFQUFVLENBQVYsRUFBYSxDQUFiLEVBWE07OztFQWNiLElBQUEsR0FDQztJQUFBLElBQUEsRUFBUSxJQUFJLENBQUMsSUFBYjtJQUNBLE1BQUEsRUFBUSxNQURSO0lBRUEsSUFBQSxFQUFRLFFBQUEsQ0FBQyxDQUFELENBQUE7YUFBTyxDQUFBLEdBQUksTUFBQSxDQUFPLENBQVA7SUFBWDtFQUZSLEVBZlk7OztFQW9CYixJQUFBLEdBQU8sUUFBQSxDQUFDLE1BQUQsRUFBQSxHQUFTLE9BQVQsQ0FBQTtXQUNOLEtBQUEsQ0FBTSxNQUFOLEVBQWMsT0FBZDtFQURNLEVBcEJNOzs7RUF3QmIsSUFBRyxJQUFIO0lBQ0MsS0FBQSxDQUFNLFlBQU4sRUFERDtHQXhCYTs7O0VBNEJiLEtBQUE7O0FBQVM7SUFBQSxLQUFBLHNDQUFBOzttQkFBQSxJQUFJLENBQUMsSUFBTCxDQUFVLEdBQVY7SUFBQSxDQUFBOzs7O0VBNUJJOzs7O0FBQUEiLCJzb3VyY2VzQ29udGVudCI6WyIjIEFzc2lnbm1lbnQ6XG5udW1iZXIgICA9IDQyXG5vcHBvc2l0ZSA9IHRydWVcblxuIyBDb25kaXRpb25zOlxubnVtYmVyID0gLTQyIGlmIG9wcG9zaXRlXG5cbiMgRnVuY3Rpb25zOlxuc3F1YXJlID0gKHgpIC0+IHggKiB4XG5cbiMgQXJyYXlzOlxubGlzdCA9IFsxLCAyLCAzLCA0LCA1XVxuXG4jIE9iamVjdHM6XG5tYXRoID1cblx0cm9vdDogICBNYXRoLnNxcnRcblx0c3F1YXJlOiBzcXVhcmVcblx0Y3ViZTogICAoeCkgLT4geCAqIHNxdWFyZSB4XG5cbiMgU3BsYXRzOlxucmFjZSA9ICh3aW5uZXIsIHJ1bm5lcnMuLi4pIC0+XG5cdHByaW50IHdpbm5lciwgcnVubmVyc1xuXG4jIEV4aXN0ZW5jZTpcbmlmIHRydWVcblx0YWxlcnQgXCJJIGtuZXcgaXQhXCJcblxuIyBBcnJheSBjb21wcmVoZW5zaW9uczpcbmN1YmVzID0gKG1hdGguY3ViZSBudW0gZm9yIG51bSBpbiBsaXN0KVxuXG4jIFRvIHJlcHJvZHVjZTpcbiMgY2QgdGVzdC9maXh0dXJlcy9zb3VyY2UtbWFwXG4jIG5weCAtLXBhY2thZ2U9Y29mZmVlc2NyaXB0QDIuNS4xIC0tIGNvZmZlZSAtTSAtLWNvbXBpbGUgdGFicy1zb3VyY2UtdXJsLmNvZmZlZVxuIyBzZWQgLWkgLWUgXCJzLyQocHdkIHwgc2VkIC1lIFwicy9cXC8vXFxcXFxcXFxcXC8vZ1wiKS8uXFxcXC9zeW50aGVzaXplZFxcXFwvd29ya3NwYWNlL2dcIiB0YWJzLXNvdXJjZS11cmwuanNcbiJdfQ== +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFicy1zb3VyY2UtdXJsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidGFicy1zb3VyY2UtdXJsLmNvZmZlZSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQWE7RUFBQTtBQUFBLE1BQUEsS0FBQSxFQUFBLElBQUEsRUFBQSxJQUFBLEVBQUEsR0FBQSxFQUFBLE1BQUEsRUFBQSxRQUFBLEVBQUEsSUFBQSxFQUFBLGdCQUFBLEVBQUE7O0VBQ2IsTUFBQSxHQUFXOztFQUNYLFFBQUEsR0FBVzs7RUFHWCxJQUFnQixRQUFoQjs7SUFBQSxNQUFBLEdBQVMsQ0FBQyxHQUFWO0dBTGE7OztFQVFiLE1BQUEsR0FBUyxRQUFBLENBQUMsQ0FBRCxDQUFBO1dBQU8sQ0FBQSxHQUFJO0VBQVgsRUFSSTs7O0VBV2IsSUFBQSxHQUFPLENBQUMsQ0FBRCxFQUFJLENBQUosRUFBTyxDQUFQLEVBQVUsQ0FBVixFQUFhLENBQWIsRUFYTTs7O0VBY2IsSUFBQSxHQUNDO0lBQUEsSUFBQSxFQUFRLElBQUksQ0FBQyxJQUFiO0lBQ0EsTUFBQSxFQUFRLE1BRFI7SUFFQSxJQUFBLEVBQVEsUUFBQSxDQUFDLENBQUQsQ0FBQTthQUFPLENBQUEsR0FBSSxNQUFBLENBQU8sQ0FBUDtJQUFYO0VBRlIsRUFmWTs7O0VBb0JiLElBQUEsR0FBTyxRQUFBLENBQUMsTUFBRCxFQUFBLEdBQVMsT0FBVCxDQUFBO1dBQ04sS0FBQSxDQUFNLE1BQU4sRUFBYyxPQUFkO0VBRE0sRUFwQk07Ozs7OztFQTJCYixnQkFBQSxHQUFtQiw4R0EzQk47OztFQThCYixJQUFHLElBQUg7SUFDQyxLQUFBLENBQU0sWUFBTixFQUREO0dBOUJhOzs7RUFrQ2IsS0FBQTs7QUFBUztJQUFBLEtBQUEsc0NBQUE7O21CQUFBLElBQUksQ0FBQyxJQUFMLENBQVUsR0FBVjtJQUFBLENBQUE7Ozs7RUFsQ0k7Ozs7QUFBQSIsInNvdXJjZXNDb250ZW50IjpbIiMgQXNzaWdubWVudDpcclxubnVtYmVyICAgPSA0MlxyXG5vcHBvc2l0ZSA9IHRydWVcclxuXHJcbiMgQ29uZGl0aW9uczpcclxubnVtYmVyID0gLTQyIGlmIG9wcG9zaXRlXHJcblxyXG4jIEZ1bmN0aW9uczpcclxuc3F1YXJlID0gKHgpIC0+IHggKiB4XHJcblxyXG4jIEFycmF5czpcclxubGlzdCA9IFsxLCAyLCAzLCA0LCA1XVxyXG5cclxuIyBPYmplY3RzOlxyXG5tYXRoID1cclxuXHRyb290OiAgIE1hdGguc3FydFxyXG5cdHNxdWFyZTogc3F1YXJlXHJcblx0Y3ViZTogICAoeCkgLT4geCAqIHNxdWFyZSB4XHJcblxyXG4jIFNwbGF0czpcclxucmFjZSA9ICh3aW5uZXIsIHJ1bm5lcnMuLi4pIC0+XHJcblx0cHJpbnQgd2lubmVyLCBydW5uZXJzXHJcblxyXG4jIE11bHRpcGxlIHNvdXJjZU1hcHBpbmdVUkwgY29tbWVudHNcclxuIyMgc291cmNlTWFwcGluZ1VSTD1kYXRhOmFwcGxpY2F0aW9uL2pzb247YmFzZTY0LGV5SjJaWEp6YVc5dUlqb3pMQ0ptYVd4bElqb2lkR0ZpY3kxemIzVnlZMlV0ZFhKc0xtcHpJaXdpY1xyXG5cclxuIyBzb3VyY2VNYXBwaW5nVVJMIGluc2lkZSBzdHJpbmdzXHJcbnNvdXJjZU1hcHBpbmdVUkwgPSBcIi8vIyBzb3VyY2VNYXBwaW5nVVJMPWRhdGE6YXBwbGljYXRpb24vanNvbjtiYXNlNjQsZXlKMlpYSnphVzl1SWpvekxDSm1hV3hsSWpvaWRHRmljeTF6YjNWeVkyVXRkWEpzTG1weklpd2ljXCJcclxuXHJcbiMgRXhpc3RlbmNlOlxyXG5pZiB0cnVlXHJcblx0YWxlcnQgXCJJIGtuZXcgaXQhXCJcclxuXHJcbiMgQXJyYXkgY29tcHJlaGVuc2lvbnM6XHJcbmN1YmVzID0gKG1hdGguY3ViZSBudW0gZm9yIG51bSBpbiBsaXN0KVxyXG5cclxuIyBUbyByZXByb2R1Y2U6XHJcbiMgY2QgdGVzdC9maXh0dXJlcy9zb3VyY2UtbWFwXHJcbiMgbnB4IC0tcGFja2FnZT1jb2ZmZWVzY3JpcHRAMi41LjEgLS0gY29mZmVlIC1NIC0tY29tcGlsZSB0YWJzLXNvdXJjZS11cmwuY29mZmVlXHJcbiMgc2VkIC1pIC1lIFwicy8kKHB3ZCB8IHNlZCAtZSBcInMvXFwvL1xcXFxcXFxcXFwvL2dcIikvLlxcXFwvc3ludGhlc2l6ZWRcXFxcL3dvcmtzcGFjZS9nXCIgdGFicy1zb3VyY2UtdXJsLmpzXHJcbiJdfQ== //# sourceURL=./synthesized/workspace/tabs-source-url.coffee \ No newline at end of file