diff --git a/spec.emu b/spec.emu index c70105e..3685ec1 100644 --- a/spec.emu +++ b/spec.emu @@ -572,7 +572,8 @@ "sourcesContent": [null, null], "names": ["src", "maps", "are", "fun"], "mappings": "A,AAAB;;ABCDE" - "ignoreList": [0] + "ignoreList": [0], + "debugId": "" } @@ -606,6 +608,10 @@ [[File]] a String or *null* + + [[DebugId]] + a String or *null* + [[Sources]] a List of Decoded Source Records @@ -676,6 +682,7 @@ 1. If _mappingsField_ is not a String, throw an error. 1. If JSONObjectGet(_json_, *"sources"*) is not a JSON array, throw an error. 1. Let _fileField_ be GetOptionalString(_json_, *"file"*). + 1. Let _debugIdField_ be GetOptionalString(_json_, *"debugId"*). 1. Let _sourceRootField_ be GetOptionalString(_json_, *"sourceRoot"*). 1. Let _sourcesField_ be GetOptionalListOfOptionalStrings(_json_, *"sources"*). 1. Let _sourcesContentField_ be GetOptionalListOfOptionalStrings(_json_, *"sourcesContent"*). @@ -683,7 +690,7 @@ 1. Let _sources_ be DecodeSourceMapSources(_baseURL_, _sourceRootField_, _sourcesField_, _sourcesContentField_, _ignoreListField_). 1. Let _namesField_ be GetOptionalListOfStrings(_json_, *"names"*). 1. Let _mappings_ be DecodeMappings(_mappingsField_, _namesField_, _sources_). - 1. Return the Decoded Source Map Record { [[File]]: _fileField_, [[Sources]]: _sources_, [[Mappings]]: _mappings_ }. + 1. Return the Decoded Source Map Record { [[File]]: _fileField_, [[DebugId]]: _debugIdField_, [[Sources]]: _sources_, [[Mappings]]: _mappings_ }. @@ -1342,29 +1349,51 @@
description
-
It extracts a source map URL from a JavaScript source. It has two possible implementations: either through parsing or without parsing.
+
It extracts a source map URL from a JavaScript source.
+
+ + 1. Return JavaScriptExtractMagicComment(_source_, *"sourceMappingURL"*, *true*). + +
+ + +

+ JavaScriptExtractMagicComment ( + _source_: a String, + _commentType_: a String, + _supportLegacy_: a Boolean, + ): a String or *null* +

+
+
description
+
It extracts a magic comment from a JavaScript source. A magic comment is of the form //# commentType=value.
-

To extract a source map URL through parsing:

+

To extract a magic comment through parsing:

1. Let _tokens_ be the List of tokens obtained by parsing _source_ according to ECMA-262's lexical grammar. 1. For each nonterminal _token_ in _tokens_, in reverse order, do 1. If _token_ is not |SingleLineComment| or |MultiLineComment|, return *null*. 1. Let _comment_ be the content of _token_. - 1. Let _sourceMapURL_ be MatchSourceMapURL(_comment_). - 1. If _sourceMapURL_ is a String, return _sourceMapURL_. + 1. Let _commentValue_ be MatchMagicComment(_comment_, _commentType_, _supportLegacy_). + 1. If _commentValue_ is a String, return _commentValue_. 1. Return *null*. - -

To extract a source map URL without parsing:

+

To extract a magic comment without parsing:

1. Let _lines_ be StringSplit(_source_, « *"\u000D\u000A"*, *"\u000A"*, *"\u000D"*, *"\u2028"*, *"\u2029"* »). - 1. NOTE: The regular expression above matches the |LineTerminatorSequence| production. - 1. Let _lastURL_ be *null*. - 1. For each String _lineStr_ in _lines_, do + 1. NOTE: The separators above match the |LineTerminatorSequence| production. + 1. Let _lastValue_ be *null*. + 1. Let _limit_ be *null*. + 1. If _commentType_ is *"debugId"*, let _limit_ be 5. + 1. If _limit_ is not *null*, let _start_ be max(0, the number of elements of _lines_ minus _limit_). + 1. Else, let _start_ be 0. + 1. Let _linesToProcess_ be the List of elements of _lines_ from index _start_ to the end. + 1. If _commentType_ is not *"debugId"*, reverse the order of elements in _linesToProcess_. + 1. For each String _lineStr_ in _linesToProcess_, do 1. Let _line_ be StringToCodePoints(_lineStr_). 1. Let _position_ be 0. 1. Let _lineLength_ be the length of _line_. @@ -1376,8 +1405,8 @@ 1. Set _position_ to _position_ + 1. 1. If _second_ is U+002F (SOLIDUS), then 1. Let _comment_ be the substring of _lineStr_ from _position_ to _lineLength_. - 1. Let _sourceMapURL_ be MatchSourceMapURL(_comment_). - 1. If _sourceMapURL_ is a String, set _lastURL_ to _sourceMapURL_. + 1. Let _commentValue_ be MatchMagicComment(_comment_, _commentType_, _supportLegacy_). + 1. If _commentValue_ is a String, set _lastValue_ to _commentValue_. 1. Set _position_ to _lineLength_. 1. Else if _second_ is U+002A (ASTERISK), then 1. Let _commentCp_ be a new empty List. @@ -1387,74 +1416,51 @@ 1. Let _c2_ be _line_[_position_]. 1. If _c1_ is U+002A (ASTERISK) and _c2_ is U+002F (SOLIDUS), then 1. Set _position_ to _position_ + 1. - 1. Let _sourceMapURL_ be MatchSourceMapURL(CodePointsToString(_commentCp_)). - 1. If _sourceMapURL_ is a String, set _lastURL_ to _sourceMapURL_. + 1. Let _commentValue_ be MatchMagicComment(CodePointsToString(_commentCp_), _commentType_, _supportLegacy_). + 1. If _commentValue_ is a String, set _lastValue_ to _commentValue_. 1. Append _c1_ to _commentCp_. 1. Else, - 1. Set _lastURL_ to *null*. + 1. Set _lastValue_ to *null*. 1. Else if _first_ is not an ECMAScript |WhiteSpace|, then - 1. Set _lastURL_ to *null*. - 1. NOTE: We reset _lastURL_ to *null* whenever we find a non-comment code character. - 1. Return _lastURL_. + 1. Set _lastValue_ to *null*. + 1. NOTE: We reset _lastValue_ to *null* whenever we find a non-comment code character. + 1. If _commentType_ is *"debugId"* and _lastValue_ is not *null*, return _lastValue_. + 1. Return _lastValue_. - - The algorithm above has been designed so that the source lines can be iterated in reverse order, returning early after scanning through a line that contains a `sourceMappingURL` comment. - - -

The algorithm above is equivalent to the following JavaScript implementation:

- -
const JS_NEWLINE = /^/m;
-
-// This RegExp will always match one of the following:
-// - single-line comments
-// - "single-line" multi-line comments
-// - unclosed multi-line comments
-// - just trailing whitespaces
-// - a code character
-// The loop below differentiates between all these cases.
-const JS_COMMENT =
-  /\s*(?:\/\/(?<single>.*)|\/\*(?<multi>.*?)\*\/|\/\*.*|$|(?<code>[^\/]+))/uym;
-
-const PATTERN = /^[@#]\s*sourceMappingURL=(\S*?)\s*$/;
-
-let lastURL = null;
-for (const line of source.split(JS_NEWLINE)) {
-  JS_COMMENT.lastIndex = 0;
-  while (JS_COMMENT.lastIndex < line.length) {
-    let commentMatch = JS_COMMENT.exec(line).groups;
-    let comment = commentMatch.single ?? commentMatch.multi;
-    if (comment != null) {
-      let match = PATTERN.exec(comment);
-      if (match !== null) lastURL = match[1];
-    } else if (commentMatch.code != null) {
-      lastURL = null;
-    } else {
-      // We found either trailing whitespaces or an unclosed comment.
-      // Assert: JS_COMMENT.lastIndex === line.length
-    }
-  }
-}
-return lastURL;
-
- - -

- MatchSourceMapURL ( - _comment_: a String, - ): either ~none~ or a String -

-
- - 1. Let _pattern_ be RegExpCreate(*"^[@#]\\s\*sourceMappingURL=(\\S\*?)\\s\*$"*, *""*). - 1. Let _match_ be RegExpExec(_pattern_, _comment_). - 1. If _match_ is not *null*, return Get(_match_, *"1"*). - 1. Return ~none~. - +
- The prefix for this annotation was initially `//@`, however this conflicts with Internet Explorer's Conditional Compilation and was changed to `//#`. + +

+ MatchMagicComment ( + _comment_: a String, + _commentType_: a String, + _supportLegacy_: a Boolean, + ): either ~none~ or a String +

+
+ + 1. Let _prefix_ be *"^#\\s*"*. + 1. If _supportLegacy_ is *true*, set _prefix_ to *"^[@#]\\s*"*. + 1. Let _pattern_ be RegExpCreate(the string-concatenation of _prefix_, _commentType_, *"=(\\S*?)\\s*$"*, *""*). + 1. Let _match_ be RegExpExec(_pattern_, _comment_). + 1. If _match_ is not *null*, return Get(_match_, *"1"*). + 1. Return ~none~. + +
-

Source map generators shall only emit `//#`, while source map consumers shall accept both `//@` and `//#`.

-
+ +

+ JavaScriptExtractDebugId ( + _source_: a String, + ): a String or *null* +

+
+
description
+
It extracts a Debug ID comment from a JavaScript source.
+
+ + 1. Return JavaScriptExtractMagicComment(_source_, *"debugId"*, *false*). +
@@ -1470,29 +1476,24 @@ return lastURL;

Extracting source map URLs from CSS is similar to JavaScript, with the exception that CSS only supports `/* ... */`-style comments.

- +

- WebAssemblyExtractSourceMapURL ( - _bytes_: a Data Block, + CSSExtractDebugId ( + _source_: a String, ): a String or *null*

description
-
It extracts a source map URL from a WebAssembly binary source.
+
It extracts a Debug ID comment from a CSS source.
+

Extracting Debug ID comments from CSS is similar to JavaScript's JavaScriptExtractDebugId operation, with the exception that CSS only supports `/* ... */`-style comments.

- - 1. Let _module_ be module_decode(_bytes_). - 1. If _module_ is WebAssembly error, return *null*. - 1. For each custom section _customSection_ of _module_, do - 1. Let _name_ be the `name` of _customSection_. - 1. If CodePointsToString(_name_) is *"sourceMappingURL"*, then - 1. Let _value_ be the `bytes` of _customSection_. - 1. Return CodePointsToString(_value_). - 1. Return *null*. - -

Since WebAssembly is not a textual format and it does not support comments, it supports a single unambiguous extraction method. The URL is encoded as a WebAssembly name, and it's placed as the content of the custom section. It is invalid for tools that generate WebAssembly code to generate two or more custom sections with the `sourceMappingURL` name.

+ +

The prefix for sourceMappingURL annotations was initially `//@`, however this conflicts with Internet Explorer's Conditional Compilation and was changed to `//#`. Source map generators shall only emit `//#`, while source map consumers shall accept both `//@` and `//#`.

+ +

For debugId annotations, only the `//#` prefix is supported and source map generators shall only emit `//#`. Legacy `//@` is not supported for debugId comments.

+