Draft ECMA-426 / April 24, 2025

Source map format specification

About this Specification

The document at https://tc39.es/ecma426/ is the most accurate and up-to-date source map specification. It contains the content of the most recently published snapshot plus any modifications that will be included in the next snapshot.

Contributing to this Specification

This specification is developed on GitHub. There are a number of ways to contribute to the development of this specification:

Refer to the colophon for more information on how this document is created.

Introduction

This Ecma Standard defines the Source map format, used for mapping transpiled source code back to the original sources.

The source map format has the following goals:

The original source map format (v1) was created by Joseph Schorr for use by Closure Inspector to enable source-level debugging of optimized JavaScript code (although the format itself is language agnostic). However, as the size of the projects using source maps expanded, the verbosity of the format started to become a problem. The v2 format (Source Map Revision 2 Proposal) was created by trading some simplicity and flexibility to reduce the overall size of the source map. Even with the changes made with the v2 version of the format, the source map file size was limiting its usefulness. The v3 format is based on suggestions made by Pavel Podivilov (Google).

The source map format does not have version numbers anymore, and it is instead hard-coded to always be "3".

In 2023-2024, the source map format was developed into a more precise Ecma standard, with significant contributions from many people. Further iteration on the source map format is expected to come from TC39-TG4.

Asumu Takikawa, Nicolò Ribaudo, Jon Kuperman
ECMA-426, 1st edition, Project Editors

1 Scope

This Standard defines the source map format, used by different types of developer tools to improve the debugging experience of code compiled to JavaScript, WebAssembly, and CSS.

2 Conformance

A conforming source map document is a JSON document that conforms to the structure detailed in this specification.

A conforming source map generator should generate documents which are conforming source map documents, and can be decoded by the algorithms in this specification without reporting any errors (even those which are specified as optional).

A conforming source map consumer should implement the algorithms specified in this specification for retrieving (where applicable) and decoding source map documents. A conforming consumer is permitted to ignore errors or report them without terminating where the specification indicates that an algorithm may optionally report an error.

3 References

The following documents are referred to in the text in such a way that some or all of their content constitutes requirements of this document. For dated references, only the edition cited applies. For undated references, the latest edition of the referenced document (including any amendments) applies.

3.1 Normative References

ECMA-262, ECMAScript® Language Specification.
https://tc39.es/ecma262/

ECMA-404, The JSON Data Interchange Format.
https://www.ecma-international.org/publications-and-standards/standards/ecma-404/

3.2 Informative References

IETF RFC 4648, The Base16, Base32, and Base64 Data Encodings.
https://datatracker.ietf.org/doc/html/rfc4648

WebAssembly Core Specification.
https://www.w3.org/TR/wasm-core-2/

WHATWG Encoding.
https://encoding.spec.whatwg.org/

WHATWG Fetch.
https://fetch.spec.whatwg.org/

WHATWG Infra.
https://infra.spec.whatwg.org/

WHATWG URL.
https://url.spec.whatwg.org/

4 Notational Conventions

This specification follows the same notational conventions as defined by ECMA-262 (Notational conventions), with the extensions defined in this section.

4.1 Algorithm Conventions

4.1.1 Implicit Completions

All abstract operations declared in this specification are implicitly assumed to either return a normal completion containing the algorithm's declared return type, or a throw completion. For example, an abstract operation declared as

4.1.1.1 GetTheAnswer ( input )

The abstract operation GetTheAnswer takes argument input (an integer) and returns an integer.

is equivalent to:

4.1.1.2 GetTheAnswer2 ( input )

The abstract operation GetTheAnswer2 takes argument input (an integer) and returns either a normal completion containing an integer or a throw completion.

All calls to abstract operations that return completion records are implicitly assumed to be wrapped by a ReturnIfAbrupt macro, unless they are explicitly wrapped by an explicit Completion call. For example:

  1. Let result be GetTheAnswer(value).
  2. Let second be Completion(GetTheAnswer(value)).

is equivalent to:

  1. Let result be ReturnIfAbrupt(GetTheAnswer(value)).
  2. Let second be Completion(GetTheAnswer(value)).

4.1.2 Optional Errors

Whenever an algorithm is to optionally report an error, an implementation may choose one of the following behaviours:

  • Continue executing the rest of the algorithm.
  • Report an error to the user (for example, in the browser console), and continue executing the rest of the algorithm.
  • Return a ThrowCompletion.

An implementation can choose different behaviours for different optional errors.

4.2 Grammar Notation

This specification follows the same grammar notation convention as defined by ECMA-262 (Grammar Notation), with the following caveats:

5 Terms and Definitions

For the purposes of this document, the following terms and definitions apply.

generated code

code which is generated by the compiler or transpiler.

original source

source code which has not been passed through a compiler or transpiler.

source map URL

URL referencing the location of a source map from the generated code.

column

zero-based indexed offset within a line of the generated code, computed as UTF-16 code units for JavaScript and CSS source maps, and as byte indices in the binary content (represented as a single line) for WebAssembly source maps.

Note
That means that "A" (LATIN CAPITAL LETTER A) measures as 1 code unit, and "🔥" (FIRE) measures as 2 code units. Source maps for other content types may diverge from this.
original scope

a lexical scope in an original source file.

generated range

a code range in generated code. The term range is chosen deliberately: A range does not necessarily correspond to a lexical JavaScript/WASM scope, e.g. when function bodies were inlined by a compiler.

6 base64 VLQ

A base64 VLQ is a base64-encoded variable-length quantity, where the most significant bit (the 6th bit) is used as the continuation bit, and the "digits" are encoded into the string least significant first, and where the least significant bit of the first digit is used as the sign bit.

Note 1
The values that can be represented by the base64 VLQ encoding are limited to 32-bit quantities until some use case for larger values is presented. This means that values exceeding 32-bits are invalid and implementations may reject them. The sign bit is counted towards the limit, but the continuation bits are not.
Note 2
The string "iB" represents a base64 VLQ with two digits. The first digit "i" encodes the bit pattern 0x100010, which has a continuation bit of 1 (the VLQ continues), a sign bit of 0 (non-negative), and the value bits 0x0001. The second digit B encodes the bit pattern 0x000001, which has a continuation bit of 0, no sign bit, and value bits 0x00001. The decoding of this VLQ string is the number 17.
Note 3
The string "V" represents a base64 VLQ with one digit. The digit "V" encodes the bit pattern 0x010101, which has a continuation bit of 0 (no continuation), a sign bit of 1 (negative), and the value bits 0x1010. The decoding of this VLQ string is the number -10.

A base64 VLQ adheres to the following lexical grammar:

Vlq :: VlqDigitList VlqDigitList :: TerminalDigit ContinuationDigit VlqDigitList TerminalDigit :: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f ContinuationDigit :: g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 + /

6.1 VLQSignedValue

The syntax-directed operation VLQSignedValue takes no arguments and returns an integer. It is defined piecewise over the following productions:

Vlq :: VlqDigitList
  1. Let unsigned be the VLQUnsignedValue of VlqDigitList.
  2. If unsigned modulo 2 = 1, let sign be -1.
  3. Else, let sign be 1.
  4. Let value be floor(unsigned / 2).
  5. If value is 0 and sign is -1, return -231.
  6. If value is ≥ 231, throw an error.
  7. Return sign × value.
Note
The check in step 6 is needed because unsigned is the VLQUnsignedValue of VlqDigitList, not of Vlq.

6.2 VLQUnsignedValue

The syntax-directed operation VLQUnsignedValue takes no arguments and returns an non-negative integer. It is defined piecewise over the following productions:

Vlq :: VlqDigitList
  1. Let value be the VLQUnsignedValue of VlqDigitList.
  2. If value is ≥ 232, throw an error.
  3. Return value.
VlqDigitList :: ContinuationDigit VlqDigitList
  1. Let left be the VLQUnsignedValue of ContinuationDigit.
  2. Let right be the VLQUnsignedValue of VlqDigitList.
  3. Return left + right × 25.
TerminalDigit :: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f
  1. Let digit be the character matched by this production.
  2. Let value be the integer corresponding to digit, according to the base64 encoding as defined by IETF RFC 4648.
  3. Assert: value < 32.
  4. Return value.
ContinuationDigit :: g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 + /
  1. Let digit be the character matched by this production.
  2. Let value be the integer corresponding to digit, according to the base64 encoding as defined by IETF RFC 4648.
  3. Assert: 32 ≤ value < 64.
  4. Return value - 32.

7 JSON values utilities

While this specification's algorithms are defined on top of ECMA-262 internals, it is meant to be easily implementable by non-JavaScript platforms. This section contains utilities for working with JSON values, abstracting away ECMA-262 details from the rest of the document.

A JSON value is either a JSON object, a JSON array, a String, a Number, a Boolean, or null.

A JSON object is an Object such that each of its properties:

A JSON array is a JSON object such that:

7.1 ParseJSON ( string )

The abstract operation ParseJSON takes argument string (a String) and returns a JSON value. It performs the following steps when called:

  1. Let result be Call(%JSON.parse%, null, « string »).
  2. Assert: result is a JSON value.
  3. Return result.
Editor's Note
This abstract operation is in the process of being exposed by ECMA-262 itself, at tc39/ecma262#3540.

7.2 JSONObjectGet ( object, key )

The abstract operation JSONObjectGet takes arguments object (a JSON object) and key (a String) and returns a JSON value or missing. It returns the value associated with the specified key in object. It performs the following steps when called:

  1. If object does not have an own property with key key, return missing.
  2. Let prop be object's own property whose key is key.
  3. Return prop's [[Value]] attribute.

7.3 JSONArrayIterate ( array )

The abstract operation JSONArrayIterate takes argument array (a JSON array) and returns a List of JSON values. It returns a List containing all elements of array, so that it can be iterated by algorithms using "For each". It performs the following steps when called:

  1. Let length be JSONObjectGet(array, "length").
  2. Assert: length is a non-negative integral Number.
  3. Let list be a new empty List.
  4. Let i be 0.
  5. Repeat, while i < (length),
    1. Let value be JSONObjectGet(array, ToString(𝔽(i))).
    2. Assert: value is not missing.
    3. Append value to list.
    4. Set i to i + 1.
  6. Return list.

7.4 StringSplit ( string, separators )

The abstract operation StringSplit takes arguments string (a String) and separators (a List of String) and returns a List of Strings. It splits the string in substrings separated by any of the elements of separators. If multiple separators match, those appearing first in separators have higher priority. It performs the following steps when called:

  1. Let parts be a new empty List.
  2. Let strLen be the length of string.
  3. Let lastStart be 0.
  4. Let i be 0.
  5. Repeat, while i < strLen,
    1. Let matched be false.
    2. For each String sep of separators, do
      1. Let sepLen be the length of sep.
      2. Let candidate be the substring of string from i to min(i + sepLen, strLen).
      3. If candidate = sep and matched is false, then
        1. Let chunk be the substring of string from lastStart to i.
        2. Append chunk to parts.
        3. Set lastStart to i + sepLen.
        4. Set i to i + sepLen.
        5. Set matched to true.
    3. If matched is false, set i to i + 1.
  6. Let chunk be the substring of string from lastStart to strLen.
  7. Append chunk to parts.
  8. Return parts.

8 Position types

8.1 Position Record

A Position Record is a tuple of a non-negative line and non-negative column number:

Table 1: Position Record Fields
Field Name Value Type
[[Line]] a non-negative integral Number
[[Column]] a non-negative integral Number

8.2 Original Position Record

A Original Position Record is a tuple of a Decoded Source Record, a non-negative line and non-negative column number. It is similar to a Position Record but describes a source position in a concrete original source file.

Table 2: Original Position Record Fields
Field Name Value Type
[[Source]] a Decoded Source Record
[[Line]] a non-negative integral Number
[[Column]] a non-negative integral Number

8.3 ComparePositions ( first, second )

The abstract operation ComparePositions takes arguments first (a Position Record or a Original Position Record) and second (a Position Record or a Original Position Record) and returns lesser, equal or greater. It returns lesser, equal or greater depending whether first occurs before, is equal or occurs after second respectively. The [[Source]] field of Original Position Records are ignored. It performs the following steps when called:

  1. If first.[[Line]] < second.[[Line]], return lesser.
  2. If first.[[Line]] > second.[[Line]], return greater.
  3. Assert: first.[[Line]] is equal to second.[[Line]].
  4. If first.[[Column]] < second.[[Column]], return lesser.
  5. If first.[[Column]] > second.[[Column]], return greater.
  6. Return equal.

9 Source map format

A source map is a JSON document containing a top-level JSON object with the following structure:

{
  "version" : 3,
  "file": "out.js",
  "sourceRoot": "",
  "sources": ["foo.js", "bar.js"],
  "sourcesContent": [null, null],
  "names": ["src", "maps", "are", "fun"],
  "mappings": "A,AAAB;;ABCDE"
  "ignoreList": [0]
}

9.1 Decoding source maps

A Decoded Source Map Record has the following fields:

Table 3: Fields of Decoded Source Map Records
Field Name Value Type
[[File]] a String or null
[[Sources]] a List of Decoded Source Records
[[Mappings]] a List of Decoded Mapping Records
[[Ranges]] a List of Generated Range Records

A Decoded Source Record has the following fields:

Table 4: Fields of Decoded Source Records
Field Name Value Type
[[URL]] a URL or null
[[Content]] a String or null
[[Ignored]] a Boolean
[[Scope]] a Original Scope Record or null

9.1.1 ParseSourceMap ( string, baseURL )

The abstract operation ParseSourceMap takes arguments string (a String) and baseURL (an URL) and returns a Decoded Source Map Record. It performs the following steps when called:

  1. Let json be ParseJSON(string).
  2. If json is not a JSON object, throw an error.
  3. If JSONObjectGet(json, "sections") is not missing, then
    1. Return DecodeIndexSourceMap(json, baseURL).
  4. Return DecodeSourceMap(json, baseURL).

9.1.2 DecodeSourceMap ( json, baseURL )

The abstract operation DecodeSourceMap takes arguments json (a JSON object) and baseURL (an URL) and returns a Decoded Source Map Record. It performs the following steps when called:

  1. If JSONObjectGet(json, "version") is not 3𝔽, optionally report an error.
  2. Let mappingsField be JSONObjectGet(json, "mappings").
  3. If mappingsField is not a String, throw an error.
  4. If JSONObjectGet(json, "sources") is not a JSON array, throw an error.
  5. Let fileField be GetOptionalString(json, "file").
  6. Let sourceRootField be GetOptionalString(json, "sourceRoot").
  7. Let sourcesField be GetOptionalListOfOptionalStrings(json, "sources").
  8. Let sourcesContentField be GetOptionalListOfOptionalStrings(json, "sourcesContent").
  9. Let ignoreListField be GetOptionalListOfArrayIndexes(json, "ignoreList").
  10. Let namesField be GetOptionalListOfStrings(json, "names").
  11. Let scopesField be GetOptionalString(json, "scopes").
  12. Let scopesAndRanges be DecodeScopesInfo(scopesField, namesField).
  13. Let sources be DecodeSourceMapSources(baseURL, sourceRootField, sourcesField, sourcesContentField, ignoreListField, scopesAndRanges.[[Scopes]]).
  14. Let mappings be DecodeMappings(mappingsField, namesField, sources).
  15. Return the Decoded Source Map Record { [[File]]: fileField, [[Sources]]: sources, [[Mappings]]: mappings, [[Ranges]]: scopesAndRanges.[[Ranges]] }.

9.1.2.1 GetOptionalString ( object, key )

The abstract operation GetOptionalString takes arguments object (a JSON object) and key (a String) and returns a String or null. It performs the following steps when called:

  1. Let value be JSONObjectGet(object, key).
  2. If value is a String, return value.
  3. If value is not missing, optionally report an error.
  4. Return null.

9.1.2.2 GetOptionalListOfStrings ( object, key )

The abstract operation GetOptionalListOfStrings takes arguments object (a JSON object) and key (a String) and returns a List of Strings. It performs the following steps when called:

  1. Let list be a new empty List.
  2. Let values be JSONObjectGet(object, key).
  3. If values is missing, return list.
  4. If values is not a JSON array, then
    1. Optionally report an error.
    2. Return list.
  5. For each element item of JSONArrayIterate(values), do
    1. If item is a String, then
      1. Append item to list.
    2. Else,
      1. Optionally report an error.
      2. Append "" to list.
  6. Return list.

9.1.2.3 GetOptionalListOfOptionalStrings ( object, key )

The abstract operation GetOptionalListOfOptionalStrings takes arguments object (a JSON object) and key (a String) and returns a List of either Strings or null. It performs the following steps when called:

  1. Let list be a new empty List.
  2. Let values be JSONObjectGet(object, key).
  3. If values is missing, return list.
  4. If values is not a JSON array, then
    1. Optionally report an error.
    2. Return list.
  5. For each element item of JSONArrayIterate(values), do
    1. If item is a String, then
      1. Append item to list.
    2. Else,
      1. If itemnull, optionally report an error.
      2. Append null to list.
  6. Return list.

9.1.2.4 GetOptionalListOfArrayIndexes ( object, key )

The abstract operation GetOptionalListOfArrayIndexes takes arguments object (an Object) and key (a String) and returns a List of non-negative integers. It performs the following steps when called:

  1. Let list be a new empty List.
  2. Let values be JSONObjectGet(object, key).
  3. If values is missing, return list.
  4. If values is not a JSON array, then
    1. Optionally report an error.
    2. Return list.
  5. For each element item of JSONArrayIterate(values), do
    1. If item is an integral Number, item+0𝔽, and item+0𝔽, then
      1. Append (item) to list.
    2. Else,
      1. If itemnull, optionally report an error.
      2. Append null to list.
  6. Return list.

9.2 Mappings structure

The mappings field data is broken down as follows:

  • each group representing a line in the generated file is separated by a semicolon (;)
  • each segment is separated by a comma (,)
  • each segment is made up of 1, 4, or 5 variable length fields.

The fields in each segment are:

  1. The zero-based starting column of the line in the generated code that the segment represents. If this is the first field of the first segment, or the first segment following a new generated line (;), then this field holds the whole base64 VLQ. Otherwise, this field contains a base64 VLQ that is relative to the previous occurrence of this field. Note that this is different from the subsequent fields below because the previous value is reset after every generated line.
  2. If present, the zero-based index into the sources list. This field contains a base64 VLQ relative to the previous occurrence of this field, unless it is the first occurrence of this field, in which case the whole value is represented.
  3. If present, the zero-based starting line in the original source. This field contains a base64 VLQ relative to the previous occurrence of this field, unless it is the first occurrence of this field, in which case the whole value is represented. Shall be present if there is a source field.
  4. If present, the zero-based starting column of the line in the original source. This field contains a base64 VLQ relative to the previous occurrence of this field, unless it is the first occurrence of this field, in which case the whole value is represented. Shall be present if there is a source field.
  5. If present, the zero-based index into the names list associated with this segment. This field contains a base64 VLQ relative to the previous occurrence of this field, unless it is the first occurrence of this field, in which case the whole value is represented.
Note 1
The purpose of this encoding is to reduce the source map size. VLQ encoding reduced source maps by 50% relative to the Source Map Revision 2 Proposal in tests performed using Google Calendar.
Note 2
Segments with one field are intended to represent generated code that is unmapped because there is no corresponding original source code, such as code that is generated by a compiler. Segments with four fields represent mapped code where a corresponding name does not exist. Segments with five fields represent mapped code that also has a mapped name.
Note 3
Using file offsets was considered but rejected in favor of using line/column data to avoid becoming misaligned with the original due to platform-specific line endings.

A Decoded Mapping Record has the following fields:

Table 5: Fields of Decoded Mapping Records
Field Name Value Type
[[GeneratedPosition]] a Position Record
[[OriginalPosition]] a Original Position Record or null
[[Name]] a String or null

9.2.1 Mappings grammar

The mappings String must adhere to the following grammar:

MappingsField : LineList LineList : Line Line ; LineList Line : MappingListopt MappingList : Mapping Mapping , MappingList Mapping : GeneratedColumn GeneratedColumn OriginalSource OriginalLine OriginalColumn Nameopt GeneratedColumn : Vlq OriginalSource : Vlq OriginalLine : Vlq OriginalColumn : Vlq Name : Vlq

A Decode Mapping State Record has the following fields:

Table 6: Fields of Decode Mapping State Records
Field Name Value Type
[[GeneratedLine]] a non-negative integer
[[GeneratedColumn]] a non-negative integer
[[SourceIndex]] a non-negative integer
[[OriginalLine]] a non-negative integer
[[OriginalColumn]] a non-negative integer
[[NameIndex]] a non-negative integer

9.2.1.1 DecodeMappingsField

The syntax-directed operation DecodeMappingsField takes arguments state (a Decode Mapping State Record), mappings (a List of Decoded Mapping Records), names (a List of Strings), and sources (a List of Decoded Source Records). It is defined piecewise over the following productions:

LineList : Line ; LineList
  1. Perform DecodeMappingsField of Line with arguments state, mappings, names and sources.
  2. Set state.[[GeneratedLine]] to state.[[GeneratedLine]] + 1.
  3. Set state.[[GeneratedColumn]] to 0.
  4. Perform DecodeMappingsField of LineList with arguments state, mappings, names and sources.
MappingList : Mapping , MappingList
  1. Perform DecodeMappingsField of Mapping with arguments state, mappings, names and sources.
  2. Perform DecodeMappingsField of MappingList with arguments state, mappings, names and sources.
Mapping : GeneratedColumn
  1. Perform DecodeMappingsField of GeneratedColumn with arguments state, mappings, names and sources.
  2. If state.[[GeneratedColumn]] < 0, then
    1. Optionally report an error.
    2. Return.
  3. Let position be a new Position Record { [[Line]]: state.[[GeneratedLine]], [[Column]]: state.[[GeneratedColumn]] }.
  4. Let decodedMapping be a new DecodedMappingRecord { [[GeneratedPosition]]: position, [[OriginalPosition]]: null, [[Name]]: null }.
  5. Append decodedMapping to mappings.
Mapping : GeneratedColumn OriginalSource OriginalLine OriginalColumn Nameopt
  1. Perform DecodeMappingsField of GeneratedColumn with arguments state, mappings, names and sources.
  2. If state.[[GeneratedColumn]] < 0, then
    1. Optionally report an error.
    2. Return.
  3. Let generatedPosition be a new Position Record { [[Line]]: state.[[GeneratedLine]], [[Column]]: state.[[GeneratedColumn]] }.
  4. Perform DecodeMappingsField of OriginalSource with arguments state, mappings, names and sources.
  5. Perform DecodeMappingsField of OriginalLine with arguments state, mappings, names and sources.
  6. Perform DecodeMappingsField of OriginalColumn with arguments state, mappings, names and sources.
  7. If state.[[SourceIndex]] < 0 or state.[[SourceIndex]] ≥ the number of elements of sources or state.[[OriginalLine]] < 0 or state.[[OriginalColumn]] < 0, then
    1. Optionally report an error.
    2. Let originalPosition be null.
  8. Else,
    1. Let originalPosition be a new Original Position Record { [[Source]]: sources[state.[[SourceIndex]]], [[Line]]: state.[[OriginalLine]], [[Column]]: state.[[OriginalColumn]] }.
  9. Let name be null.
  10. If Name is present, then
    1. Perform DecodeMappingsField of Name with arguments state, mappings, names and sources.
    2. If state.[[NameIndex]] < 0 or state.[[NameIndex]] ≥ the number of elements of sources, optionally report an error.
    3. Else, set name to names[state.[[NameIndex]]].
  11. Let decodedMapping be a new DecodedMappingRecord { [[GeneratedPosition]]: generatedPosition, [[OriginalPosition]]: originalPosition, [[Name]]: name }.
  12. Append decodedMapping to mappings.
GeneratedColumn : Vlq
  1. Let relativeColumn be the VLQSignedValue of Vlq.
  2. Set state.[[GeneratedColumn]] to state.[[GeneratedColumn]] + relativeColumn.
OriginalSource : Vlq
  1. Let relativeSourceIndex be the VLQSignedValue of Vlq.
  2. Set state.[[SourceIndex]] to state.[[SourceIndex]] + relativeSourceIndex.
OriginalLine : Vlq
  1. Let relativeLine be the VLQSignedValue of Vlq.
  2. Set state.[[OriginalLine]] to state.[[OriginalLine]] + relativeLine.
OriginalColumn : Vlq
  1. Let relativeColumn be the VLQSignedValue of Vlq.
  2. Set state.[[OriginalColumn]] to state.[[OriginalColumn]] + relativeColumn.
Name : Vlq
  1. Let relativeName be the VLQSignedValue of Vlq.
  2. Set state.[[NameIndex]] to state.[[NameIndex]] + relativeName.

9.2.2 DecodeMappings ( rawMappings, names, sources )

The abstract operation DecodeMappings takes arguments rawMappings (a String), names (a List of Strings), and sources (a List of Decoded Source Records) and returns a List of Decoded Mapping Record. It performs the following steps when called:

  1. Let mappings be a new empty List.
  2. Let mappingsNode be the root Parse Node when parsing rawMappings using MappingsField as the goal symbol.
  3. If parsing failed, then
    1. Optionally report an error.
    2. Return mappings.
  4. Let state be a new Decode Mapping State Record with all fields set to 0.
  5. Perform DecodeMappingsField of mappingsNode with arguments state, mappings, names and sources.
  6. Return mappings.

9.2.3 Mappings for generated JavaScript code

Generated code positions that may have mapping entries are defined in terms of input elements, as per the ECMAScript Lexical Grammar. Mapping entries shall point to either:

9.2.4 Names for generated JavaScript code

Source map generators should create a mapping entry with a [[Name]] field for a JavaScript token, if:

Then the [[Name]] of the mapping entry should be the name of the original source language construct. A mapping with a non-null [[Name]] is called a named mapping.

Note 1
A minifier renaming functions and variables or removing function names from immediately invoked function expressions.

The following enumeration lists productions of the ECMAScript Syntactic Grammar and the respective token or non-terminal (on the right-hand side of the production) for which source map generators should emit a named mapping. The mapping entry created for such tokens shall follow section 9.2.3.

The enumeration should be understood as the "minimum". In general, source map generators are free to emit any additional named mappings.

Note 2
The enumeration also lists tokens where generators "may" emit named mappings in addition to the tokens where they "should". These reflect the reality where existing tooling emits or expects named mappings. The duplicated named mapping is comparably cheap: Indices into names are encoded relative to each other so subsequent mappings to the same name are encoded as 0 (A).

9.3 Scopes structure

The scope information is split across two data structures: original scopes and generated ranges. Original scopes describe the scope tree for original sources. Generated ranges describe where these scopes are found in the generated code. The scope information includes location information, for both original scopes and generated ranges, the type and name of a scope, as well as the original names of variables and how to retrieve their values in the generated code.

The scopes field is a comma (,) separated list of items. Each item is a list of base64 VLQs. The first base64 VLQ in each item is a tag that specifies which item is described by the rest of the VLQs. Items encode the original scope and generated range trees in prefix order.

9.3.1 Original Scope Record

A original scope is described by a Original Scope Record:

Table 7: Original Scope Record Fields
Field Name Value Meaning
[[Start]] a Position Record The line and column (inclusive) where this scope starts.
[[End]] a Position Record The line and column (exclusive) where this scope ends.
[[Name]] a String or null The original name of this scope. E.g. the original class or function name.
[[Kind]] a String or null Debuggers may use [[Kind]] to label this scope in a scope view UI. It is purely informative for users.
[[IsStackFrame]] a Boolean Signifies whether this scope is something that can be called, e.g. a function or method.
[[Variables]] a List of Strings The original variable names declared in this scope.
[[Children]] a List of Original Scope Records The child scopes of this scope.

A root Original Scope Record describes the lexical scope tree of a original source file.

Note
In case the original source language is JavaScript or JavaScript-like, source map generators are encouraged to use the terms Block, Function, Script/Module and Global for the [[Kind]] field where it makes sense.

9.3.2 Generated Range Record

A generated range is described by a Generated Range Record:

Table 8: Generated Range Record Fields
Field Name Value Meaning
[[Start]] a Position Record The line and column (inclusive) where this range starts.
[[End]] a Position Record The line and column (exclusive) where this range ends.
[[Definition]] a Original Scope Record or null The corresponding original scope
[[IsStackFrame]] a Boolean Whether this generated range is a JavaScript/Wasm function.
[[IsHidden]] a Boolean Whether this generated range is a compiler/transpiler inserted JavaScript/Wasm function even though [[Definition]] is not null. E.g. a original block scope was transpiled to a JS function. If [[IsHidden]] is true, then [[IsStackFrame]] must also be true.
[[Bindings]] a List of either Strings or null A list of JavaScript expressions that when evaluated in this generated range, evaluates to the value of the corresponding variable. null indicates that the variable is unavailable in this range.
[[SubRangeBindings]] a List of Sub-Range Binding Records Variables that require different expression throughout this range to retrieve its value specify [[SubRangeBindings]].
[[CallSite]] a Original Position Record or null The presence of [[CallSite]] signifies that this generated range represents an inlined original scope body. [[Definition]] must contain a valid reference and the Original Scope Record behind [[Definition]] must have the value true in it's [[IsStackFrame]] field.
[[Children]] a List of Generated Range Records The child ranges of this range.

A root Decoded Generated Record describes a distinct part of the generated code. Each Generated Range Record may be associated with a Original Scope Record as indicated by the presence of the [[Definition]] field.

[[Bindings]] are intended for debuggers to retrieve the values of original variables. The length of [[Bindings]] must be equal to [[Variables]] of the corresponding Original Scope Record. Given an index i, the JavaScript expression [[Binding]][i], when evaluated inside the generated range, retrieves the value for the original variable [[Variables]][i].

If a variable requires different expressions across a generated range, then [[SubRangeBindings]] can be used. [[SubRangeBinding]] splits the generated range into multiple sub-ranges, but just for a specific variable. Note that the same can be achieved with splitting the whole generated range, but at the cost of duplicating all of the information.

If a variable utilizes [[SubRangeBindings]] then the expression for the first sub-range is found in [[Bindings]] and the rest in [[SubRangeBindings]].

Note
Let range be a Generated Range Record that starts at "0:0" (line 0, column 0) and ends at "0:30". The corresponding Original Scope Record contains a single variable "foo". The value of "foo" can be retrieved via the expression "a" in the range ["0:0", "0:10"). "foo" is unavailable in the range ["0:10", "0:20") and in the range ["0:20", "0:30") the expression "b" must be used. Then range looks like:

          {
            [[Start]]: { [[Line]]: 0, [[Column]]: 0 },
            [[End]]: { [[Line]]: 0, [[Column]]: 30 },
            [[Definition]]: { ... }
            [[Bindings]]: ["a"]
            [[SubRangeBindings]]: [
              {
                [[From]]: { [[Line]]: 0, [[Column]]: 10 },
                [[Binding]]: *null*,
              },
              {
                [[From]]: { [[Line]]: 0, [[Column]]: 20 },
                [[Binding]]: "b",
              },
            ],
          }
        

A non-null [[CallSite]] field marks the generated range as an inlined scope. If the [[CallSite]] field of a generated range is not null, then:

  • [[Definition]] must not be null.
  • [[Definition]].[[IsStackFrame]] must be true.
  • [[IsStackFrame]] must be false.

9.3.2.1 The Sub-Range Binding Record

The Sub-Range Binding Record describe a variable that requires different JavaScript expressions in different parts of a generated range to retrieve the variables value.

Table 9: Sub-Range Binding Record Fields
Field Name Value Meaning
[[Variable]] a String The variable for which these expressions must be used to retrieve its value. [[Variable]] must be contained in the [[Definition]].[[Variables]] List. That is it must be valid variable in the corresponding Original Scope Record.
[[Bindings]] a List of Binding Records A list of position and expression tuples that describe from which position a specific expression must be used to retrieve this variables' value.

9.3.2.2 The Binding Record

The Binding Record describes a JavaScript expression that must be used for the given position to retrieve a specific variables' value.

Table 10: Binding Record Fields
Field Name Value Meaning
[[From]] a Position Record Use [[Binding]] from this position until either the next [[From]] or the ranges' end position to retrieve this variables' value.
[[Binding]] a String The expression to use to retrieve this variables' value.

9.3.3 Scopes grammar

The scopes field is described by the following context-sensitive grammar starting at the Scopes goal symbol:

Scopes : OriginalScopeTreeList TopLevelItemList OriginalScopeTreeList , TopLevelItemList OriginalScopeTreeList : OriginalScopeTreeItem OriginalScopeTreeList , OriginalScopeTreeItem OriginalScopeTreeItem : OriginalScopeTree [empty] TopLevelItemList : TopLevelItem TopLevelItemList , TopLevelItem TopLevelItem : GeneratedRangeTree UnknownItem

The number of OriginalScopeTreeItems in the OriginalScopeTreeList is expected to match the length of the sources field. The n-th OriginalScopeTreeItem describes the scope tree of the n-th authored source file in the sources field. If no scope information is available for a particular source URL, an empty item can be used.

Note

A source map with three authored sources where only the first and third source file have scope information available would be encoded as:

          "scopes": "<OriginalScopeTree>,,<OriginalScopeTree>,<GeneratedRangeTree>"
        

9.3.3.1 Original scope grammar

Each original scope consists of:

In grammar form:

OriginalScopeTree : OriginalScopeStart OriginalScopeVariablesItemopt OriginalScopeItemListopt , OriginalScopeEnd OriginalScopeVariablesItem : , OriginalScopeVariables OriginalScopeItemList : , OriginalScopeItem OriginalScopeItemList , OriginalScopeItem OriginalScopeItem : OriginalScopeTree UnknownItem OriginalScopeStart : B ScopeFlags ScopeLine ScopeColumn ScopeNameopt ScopeKindopt OriginalScopeEnd : C ScopeLine ScopeColumn OriginalScopeVariables : D ScopeVariableList ScopeVariableList : ScopeVariable ScopeVariableList ScopeVariable ScopeFlags : Vlq ScopeLine : Vlq ScopeColumn : Vlq ScopeName : Vlq ScopeKind : Vlq ScopeVariable : Vlq

The VLQUnsignedValue of ScopeFlags encodes the presence of ScopeName and ScopeKind and marks the scope as a function:

Table 11: ScopeFlags bits
Bit Mask Meaning
0x1 Set if ScopeName is present.
0x2 Set if ScopeKind is present.
0x4 Mark this scope as something callable. That is the [[IsStackFrame]] field is set to true.

9.3.3.2 Generated range grammar

Each generated range consists of:

In grammar form:

GeneratedRangeTree : GeneratedRangeStart GeneratedRangeBindingsItemopt GeneratedRangeCallSiteItemopt GeneratedRangeItemListopt , GeneratedRangeEnd GeneratedRangeBindingsItem : , GeneratedRangeBindings GeneratedRangeCallSiteItem : , GeneratedRangeCallSite GeneratedRangeItemList : , GeneratedRangeItem GeneratedRangeItemList , GeneratedRangeItem GeneratedRangeItem : GeneratedSubRangeBinding GeneratedRangeTree UnknownItem GeneratedRangeStart : E RangeFlags RangeLineopt RangeColumn RangeDefinitionopt GeneratedRangeEnd : F RangeLineopt RangeColumn GeneratedRangeBindings : G RangeBindingsList RangeBindingsList : RangeBinding RangeBindingsList RangeBinding GeneratedSubRangeBinding : H VariableIndex BindingFromList BindingFromList : BindingFrom BindingFromList BindingFrom BindingFrom : BindingLine BindingColumn Vlq GeneratedRangeCallSite : I CallSiteSourceIdx CallSiteLine CallSiteColumn RangeFlags : Vlq RangeLine : Vlq RangeColumn : Vlq RangeDefinition : Vlq RangeBinding : Vlq VariableIndex : Vlq BindingLine : Vlq BindingColumn : Vlq CallSiteSourceIdx : Vlq CallSiteLine : Vlq CallSiteColumn : Vlq

The VLQUnsignedValue of RangeFlags encodes the presence of RangeLine and RangeDefinition. All used bits:

Table 12: RangeFlags bits
Bit Mask Meaning
0x1 Set if RangeLine is present.
0x2 Set if RangeDefinition is present.
0x4 If set, then this range as a JavaScript/WASM function in the generated code. This includes methods, accessors, arrow functions, constructors, etc. Any JavaScript language construct that can be called and will result in a stack frame. If set, the [[IsStackFrame]] field is set to true.
0x8 Only valid if the 0x4 ([[IsStackFrame]]) is also set. Marks this range as a outlined function. E.g. a transpiler translated a block scope into a function. Any call to this range should be hidden in translated stack traces.

9.3.3.3 Unknown item grammar

Complying implementations are expected to decode but ignore items with unknown tags. This allows the specification to add new items in the future, without breaking existing decoders.

UnknownItem : Tag Tag UnknownVlqList Tag : Vlq but not A B C D E F G H I UnknownVlqList : Vlq UnknownVlqList Vlq Note
The specification reserves all tags for future use. Vendors wanting to experiment are encouraged to use high enough tag numbers for vendor specific items.

9.3.4 Decoding scopes

The scopes grammar defined in 9.3.3 is context-sensitive and heavily utilizes relative numbers to reduce the bytes required for the encoded scope information. As such, the grammar alone is not enough to describe how a Scopes parse node is turned into Original Scope Records and Generated Range Records.

9.3.4.1 Scope Info Record

The Scope Info Record is a specification type and is the result of decoding the scopes field.

Table 13: Scope Info Record Fields
Field Name Value Type
[[Scopes]] a List of either Original Scope Records or null
[[Ranges]] a List of Generated Range Records

9.3.4.2 Decode Scope State Record

The Decode Scope State Record is a specification type that tracks absolute values of decoded fields.

Table 14: Decode Scope State Record Fields
Field Name Value Meaning / Production
[[FlatOriginalScopes]] a List of Original Scope Records This is a list of Original Scope Records in order as seen while decoding. This is equivalent to a prefix walk of the [[Scopes]] field in the Scope Info Record. The RangeDefinition is an index into this List.
[[ScopeLine]] a non-negative Number ScopeLine
[[ScopeColumn]] a non-negative Number ScopeColumn
[[ScopeNameIndex]] a non-negative Number ScopeName
[[ScopeKindIndex]] a non-negative Number ScopeKind
[[ScopeVariableIndex]] a non-negative Number ScopeVariable
[[RangeLine]] a non-negative Number RangeLine
[[RangeColumn]] a non-negative Number RangeColumn
[[RangeDefinitionIndex]] a non-negative Number RangeDefinition
[[SubRangeLine]] a non-negative Number BindingLine
[[SubRangeColumn]] a non-negative Number BindingColumn

9.3.4.3 DecodeScopesInfo ( scopes, names )

The abstract operation DecodeScopesInfo takes arguments scopes (a String or null) and names (a List of Strings) and returns a Scope Info Record. It performs the following steps when called:

  1. Let result be a new Scope Info Record { [[Scopes]]: « », [[Records]]: « » }.
  2. If scopes is null, return result.
  3. Let parsedScopes be the root Parse Node when parsing scopes using Scopes as the goal symbol.
  4. If parsing failed, then
    1. Optionally report an error.
    2. Return result.
  5. Let state be a new Decode Scope State Record { [[FlatScopes]]: « », [[ScopeLine]]: 0, [[ScopeColumn]]: 0, [[ScopeNameIndex]]: 0, [[ScopeKindIndex]]: 0, [[ScopeVariableIndex]]: 0, [[RangeLine]]: 0, [[RangeColumn]]: 0, [[RangeDefinitionIndex]]: 0, [[SubRangeLine]]: 0, [[SubRangeColumn]]: 0 }.
  6. Perform DecodeScopesInfoItem of parsedScopes with arguments result, state and names.
  7. Return result.

9.3.4.3.1 DecodeScopesInfoItem

The syntax-directed operation DecodeScopesInfoItem takes arguments info (a Scope Info Record), state (a Decode Scope State Record), and names (a List of Strings). It is defined piecewise over the following productions:

Scopes : OriginalScopeTreeList , TopLevelItemList
  1. Perform DecodeScopesInfoItem of OriginalScopeTreeList with arguments info, state and names.
  2. Perform DecodeScopesInfoItem of TopLevelItemList with arguments info, state and names.
OriginalScopeTreeList : OriginalScopeTreeList , OriginalScopeTreeItem
  1. Perform DecodeScopesInfoItem of OriginalScopeTreeList with arguments info, state and names.
  2. Perform DecodeScopesInfoItem of OriginalScopeTreeItem with arguments info, state and names.
OriginalScopeTreeItem : OriginalScopeTree
  1. Set state.[[ScopeLine]] to 0.
  2. Set state.[[ScopeColumn]] to 0.
  3. Let scope be DecodeOriginalScope(OriginalScopeTree, state, names).
  4. Append scope to info.[[Scopes]].
OriginalScopeTreeItem : [empty]
  1. Append null to info.[[Scopes]].
TopLevelItemList : TopLevelItemList , TopLevelItem
  1. Perform DecodeScopesInfoItem of TopLevelItemList with arguments info, state and names.
  2. Perform DecodeScopesInfoItem of TopLevelItem with arguments info, state and names.
TopLevelItem : GeneratedRangeTree
  1. Let range be DecodeGeneratedRange(GeneratedRangeTree, state, names).
  2. Append range to info.[[Ranges]].

9.3.4.4 DecodeOriginalScope ( scopeTree, state, names )

The abstract operation DecodeOriginalScope takes arguments scopeTree (a OriginalScopeTree Parse Node), state (a Decode Scope State Record), and names (a List of Strings) and returns a Original Scope Record. It performs the following steps when called:

  1. Let scope be a new Original Scope Record with all fields default initialized.
  2. Perform DecodeOriginalScopeItem of scopeTree with arguments scope, state and names.
  3. Append scope to state.[[FlatScopes]].
  4. Return scope.

9.3.4.4.1 DecodeOriginalScopeItem

The syntax-directed operation DecodeOriginalScopeItem takes arguments scope (a Original Scope Record), state (a Decode Scope State Record), and names (a List of Strings). It is defined piecewise over the following productions:

OriginalScopeTree : OriginalScopeStart OriginalScopeVariablesItemopt OriginalScopeItemListopt , OriginalScopeEnd
  1. Perform DecodeOriginalScopeItem of OriginalScopeStart with arguments scope, state and names.
  2. If OriginalScopeVariablesItem is present, perform DecodeOriginalScopeItem of OriginalScopeVariablesItem with arguments scope, state and names.
  3. If OriginalScopeItemList is present, perform DecodeOriginalScopeItem of OriginalScopeItemList with arguments scope, state and names.
  4. Perform DecodeOriginalScopeItem of OriginalScopeEnd with arguments scope, state and names.
OriginalScopeStart : B ScopeFlags ScopeLine ScopeColumn ScopeNameopt ScopeKindopt
  1. Perform DecodeOriginalScopeItem of ScopeLine with arguments scope, state and names.
  2. Set scope.[[Start]].[[Line]] to state.[[ScopeLine]].
  3. Perform DecodeOriginalScopeItem of ScopeColumn with arguments scope, state and names.
  4. Set scope.[[Start]].[[Column]] to state.[[ScopeColumn]].
  5. Let flags be the VLQUnsignedValue of ScopeFlags.
  6. Assert: ScopeName is present if and only if, flags & 0x1 = 0x1.
  7. If ScopeName is present, perform DecodeOriginalScopeItem of ScopeName with arguments scope, state and names.
  8. Assert: ScopeKind is present if and only if, flags & 0x2 = 0x2.
  9. If ScopeKind is present, perform DecodeOriginalScopeItem of ScopeKind with arguments scope, state and names.
  10. If flags & 0x4 = 0x4, set scope.[[IsStackFrame]] to true.
ScopeVariableList : ScopeVariableList ScopeVariable
  1. Perform DecodeOriginalScopeItem of ScopeVariableList with arguments scope, state and names.
  2. Perform DecodeOriginalScopeItem of ScopeVariable with arguments scope, state and names.
OriginalScopeItemList : OriginalScopeItemList , OriginalScopeItem
  1. Perform DecodeOriginalScopeItem of OriginalScopeItemList with arguments scope, state and names.
  2. Perform DecodeOriginalScopeItem of OriginalScopeItem with arguments scope, state and names.
OriginalScopeItem : OriginalScopeTree
  1. Let childScope be DecodeOriginalScope(OriginalScopeTree, state, names).
  2. Append childScope to scope.[[Children]].
OriginalScopeEnd : C ScopeLine ScopeColumn
  1. Perform DecodeOriginalScopeItem of ScopeLine with arguments scope, state and names.
  2. Set scope.[[End]].[[Line]] to state.[[ScopeLine]].
  3. Perform DecodeOriginalScopeItem of ScopeColumn with arguments scope, state and names.
  4. Set scope.[[End]].[[Column]] to state.[[ScopeColumn]].
ScopeLine : Vlq
  1. Let relativeLine be the VLQUnsignedValue of Vlq.
  2. Set state.[[ScopeLine]] to state.[[ScopeLine]] + relativeLine.
  3. If relativeLine > 0, set state.[[ScopeColumn]] to 0.
Note
Step 3 makes it so ScopeColumn is encoded relative if the preceding OriginalScopeStart or OriginalScopeEnd is on the same line (i.e. relativeLine is 0), or absolute otherwise.
ScopeColumn : Vlq
  1. Let relativeColumn be the VLQUnsignedValue of Vlq.
  2. Set state.[[ScopeColumn]] to state.[[ScopeColumn]] + relativeColumn.
ScopeName : Vlq
  1. Let relativeName be the VLQSignedValue of Vlq.
  2. Set state.[[ScopeNameIndex]] to state.[[ScopeNameIndex]] + relativeName.
  3. Set scope.[[Name]] to names[state.[[ScopeNameIndex]]].
ScopeKind : Vlq
  1. Let relativeKind be the VLQSignedValue of Vlq.
  2. Set state.[[ScopeKindIndex]] to state.[[ScopeKindIndex]] + relativeKind.
  3. Set scope.[[Kind]] to names[state.[[ScopeKindIndex]]].
ScopeVariable : Vlq
  1. Let relativeVariable be the VLQSignedValue of Vlq.
  2. Set state.[[ScopeVariableIndex]] to state.[[ScopeVariableIndex]] + relativeVariable.
  3. Append names[state.[[ScopeVariableIndex]]] to scope.[[Variables]].

9.3.4.5 DecodeGeneratedRange ( rangeTree, state, names )

The abstract operation DecodeGeneratedRange takes arguments rangeTree (a GeneratedRangeTree Parse Node), state (a Decode Scope State Record), and names (a List of Strings) and returns a Generated Range Record. It performs the following steps when called:

  1. Let range be a new Generated Range Record with all fields default initialized.
  2. Perform DecodeGeneratedRangeItem of rangeTree with arguments range, state and names.
  3. Return range.

9.3.4.5.1 DecodeGeneratedRangeItem

The syntax-directed operation DecodeGeneratedRangeItem takes arguments range (a Generated Range Record), state (a Decode Scope State Record), and names (a List of Strings). It is defined piecewise over the following productions:

GeneratedRangeTree : GeneratedRangeStart GeneratedRangeBindingsItemopt GeneratedRangeCallSiteItemopt GeneratedRangeItemListopt , GeneratedRangeEnd
  1. Perform DecodeGeneratedRangeItem of GeneratedRangeStart with arguments range, state and names.
  2. If GeneratedRangeBindingsItem is present, perform DecodeGeneratedRangeItem of GeneratedRangeBindingsItem with arguments range, state and names.
  3. If GeneratedRangeCallSiteItem is present, perform DecodeGeneratedRangeItem of GeneratedRangeCallSiteItem with arguments range, state and names.
  4. If GeneratedRangeItemList is present, perform DecodeGeneratedRangeItem of GeneratedRangeItemList with arguments range, state and names.
  5. Perform DecodeGeneratedRangeItem of GeneratedRangeEnd with arguments range, state and names.
GeneratedRangeItemList : GeneratedRangeItemList , GeneratedRangeItem
  1. Perform DecodeGeneratedRangeItem of GeneratedRangeItemList with arguments range, state and names.
  2. Perform DecodeGeneratedRangeItem of GeneratedRangeItem with arguments range, state and names.
GeneratedRangeItem : GeneratedRangeTree
  1. Let childRange be DecodeGeneratedRange(GeneratedRangeTree, state, names).
  2. Append childRange to range.[[Children]].
GeneratedRangeStart : E RangeFlags RangeLineopt RangeColumn RangeDefinitionopt
  1. Let flags be the VLQUnsignedValue of RangeFlags.
  2. Assert: RangeLine is present if and only if, flags & 0x1 = 0x1.
  3. If RangeLine is present, perform DecodeGeneratedRangeItem of RangeLine with arguments range, state and names.
  4. Set range.[[Start]].[[Line]] to state.[[RangeLine]].
  5. Perform DecodeGeneratedRangeItem of RangeColumn with arguments range, state and names.
  6. Set range.[[Start]].[[Column]] to state.[[RangeColumn]].
  7. Assert: RangeDefinition is present if and only if, _flags & 0x2 = 0x2.
  8. If RangeDefinition is present, perform DecodeGeneratedRangeItem of RangeDefinition with arguments range, state and names.
  9. If flags & 0x4 = 0x4, set range.[[IsStackFrame]] to true.
  10. If flags & 0x8 = 0x8, set range.[[IsHidden]] to true.
GeneratedRangeEnd : F RangeLineopt RangeColumn
  1. If RangeLine is present, perform DecodeGeneratedRangeItem of RangeLine with arguments range, state and names.
  2. Set range.[[End]].[[Line]] to state.[[RangeLine]].
  3. Perform DecodeGeneratedRangeItem of RangeColumn with arguments range, state and names.
  4. Set range.[[End]].[[Column]] to state.[[RangeColumn]].
RangeBindingsList : RangeBindingsList RangeBinding
  1. Perform DecodeGeneratedRangeItem of RangeBindingsList with arguments range, state and names.
  2. Perform DecodeGeneratedRangeItem of RangeBindingsList with arguments range, state and names.
GeneratedSubRangeBinding : H VariableIndex BindingFromList
  1. Set state.[[SubRangeLine]] to range.[[Start]].[[Line]].
  2. Set state.[[SubRangeColumn]] to range.[[Start]].[[Column]].
  3. Let variableIndex be the VLQUnsignedValue of VariableIndex.
  4. Let variable be range.[[Definition]].[[Variables]][variableIndex].
  5. Let subRangeBinding be a new Sub-Range Binding Record { [[Variable]]: variable, [[Binding]]: « » }.
  6. Perform DecodeSubRangeBinding of BindingFromList with arguments subRangeBinding, state and names.
  7. Append subRangeBinding to range.[[SubRangeBindings]].
Note 1
Sub-range "from" positions are encoded relative to each other. Step 1 and 1 make it so that the first sub-range is relative to the ranges' start position.
GeneratedRangeCallSite : I CallSiteSourceIdx CallSiteLine CallSiteColumn
  1. Let sourceIndex be the VLQUnsignedValue of CallSiteSourceIdx.
  2. Let line be the VLQUnsignedValue of CallSiteLine.
  3. Let column be the VLQUnsignedValue of CallSiteColumn.
  4. Set range.[[CallSite]] to a new Original Position Record { [[SourceIndex]]: sourceIndex, [[Line]]: line, [[Column]]: column }.
RangeLine : Vlq
  1. Let relativeLine be the VLQUnsignedValue of Vlq.
  2. Set state.[[RangeLine]] to state.[[RangeLine]] + relativeLine.
  3. If relativeLine > 0, set state.[[RangeColumn]] to 0.
Note 2
Step 3 makes it so RangeColumn is encoded relative if the preceding GeneratedRangeStart or GeneratedRangeEnd is on the same line (i.e. relativeLine is 0), or absolute otherwise.
RangeColumn : Vlq
  1. Let relativeColumn be the VLQUnsignedValue of Vlq.
  2. Set state.[[RangeColumn]] to state.[[RangeColumn]] + relativeColumn.
RangeDefinition : Vlq
  1. Let relativeDefinition be the VLQSignedValue of Vlq.
  2. Set state.[[RangeDefinitionIndex]] to state.[[RangeDefinitionIndex]] + relativeDefinition.
  3. Set range.[[Definition]] to state.[[FlatOriginalScopes]][state.[[RangeDefinitionIndex]]].
RangeBinding : Vlq
  1. Let binding be the VLQSignedValue of Vlq.
  2. If binding ≥ 0, append names[binding] to range.[[Bindings]].
  3. Else, append null to range.[[Bindings]].

9.3.4.5.2 DecodeSubRangeBinding

The syntax-directed operation DecodeSubRangeBinding takes arguments subRangeBinding (a Sub-Range Binding Record), state (a Decode Scope State Record), and names (a List of Strings). It is defined piecewise over the following productions:

BindingFromList : BindingFromList BindingFrom
  1. Perform DecodeSubRangeBinding of BindingFromList with arguments subRangeBinding, state and names.
  2. Perform DecodeSubRangeBinding of BindingFrom with arguments subRangeBinding, state and names.
BindingFrom : BindingLine BindingColumn Vlq
  1. Perform DecodeSubRangeBinding of BindingLine with arguments subRangeBinding, state and names.
  2. Perform DecodeSubRangeBinding of BindingColumn with arguments subRangeBinding, state and names.
  3. Let expressionIndex be the VLQUnsignedValue of Vlq.
  4. If expressionIndex ≥ 0, let expression be names[expressionIndex].
  5. Else, let expression be null.
  6. Let binding be a new Binding Record { [[From]]: { [[Line]]: state.[[SubRangeLine]], [[Column]]: state.[[SubRangeColumn]] }, [[Binding]]: expression }.
  7. Append binding to subRangeBinding.[[Bindings]].
BindingLine : Vlq
  1. Let relativeLine be the VLQUnsignedValue of Vlq.
  2. Set state.[[SubRangeLine]] to state.[[SubRangeLine]] + relativeLine.
  3. If relativeLine > 0, set state.[[SubRangeColumn]] to 0.
BindingColumn : Vlq
  1. Let relativeColumn be the VLQUnsignedValue of Vlq.
  2. Set state.[[SubRangeColumn]] to state.[[SubRangeColumn]] + relativeColumn.

9.4 Resolving sources

If the sources are not absolute URLs after prepending the sourceRoot, the sources are resolved relative to the source map (like resolving the script src attribute in an HTML document).

9.4.1 DecodeSourceMapSources ( baseURL, sourceRoot, sources, sourcesContent, ignoreList, scopes )

The abstract operation DecodeSourceMapSources takes arguments baseURL (an URL), sourceRoot (a String or null), sources (a List of either Strings or null), sourcesContent (a List of either Strings or null), ignoreList (a List of non-negative integers), and scopes (a List of either Original Scope Records or null) and returns a Decoded Source Record. It performs the following steps when called:

  1. Let decodedSources be a new empty List.
  2. Let sourcesContentCount be the the number of elements in sourcesContent.
  3. Let sourceUrlPrefix be "".
  4. If sourceRootnull, then
    1. If sourceRoot ends with the code point U+002F (SOLIDUS), then
      1. Set sourceUrlPrefix to sourceRoot.
    2. Else,
      1. Set sourceUrlPrefix to the string-concatenation of sourceRoot and "/".
  5. Let index be 0.
  6. Repeat, while index < sources' length,
    1. Let source be sources[index].
    2. Let decodedSource be the Decoded Source Record { [[URL]]: null, [[Content]]: null, [[Ignored]]: false, [[Scope]]: null }.
    3. If sourcenull, then
      1. Set source to the string-concatenation of sourceUrlPrefix and source.
      2. Let sourceURL be the result of URL parsing source with baseURL.
      3. If sourceURL is failure, optionally report an error.
      4. Else, set decodedSource.[[URL]] to sourceURL.
    4. If ignoreList contains index, set decodedSource.[[Ignored]] to true.
    5. If sourcesContentCount > index, set decodedSource.[[Content]] to sourcesContent[index].
    6. If index ≥ 0 and _index < scopes' length, then
      1. Set decodedSource.[[Scope]] to scopes.[index].
    7. Append decodedSource to decodedSources.
  7. Return decodedSources.
Note
Implementations that support showing source contents but do not support showing multiple sources with the same URL and different content will arbitrarily choose one of the various contents corresponding to the given URL.

9.5 Extensions

Source map consumers shall ignore any additional unrecognized properties, rather than causing the source map to be rejected, so that additional features can be added to this format without breaking existing users.

10 Index source map

To support concatenating generated code and other common post-processing, an alternate representation of a source map is supported:

{
  "version" : 3,
  "file": "app.js",
  "sections": [
    {
      "offset": {"line": 0, "column": 0},
      "map": {
        "version" : 3,
        "file": "section.js",
        "sources": ["foo.js", "bar.js"],
        "names": ["src", "maps", "are", "fun"],
        "mappings": "AAAA,E;;ABCDE"
      }
    },
    {
      "offset": {"line": 100, "column": 10},
      "map": {
        "version" : 3,
        "file": "another_section.js",
        "sources": ["more.js"],
        "names": ["more", "is", "better"],
        "mappings": "AAAA,E;AACA,C;ABCDE"
      }
    }
  ]
}

The index map follows the form of the standard map. Like the regular source map, the file format is JSON with a top-level object. It shares the version and file field from the regular source map, but gains a new sections field.

The sections field is an array of objects with the following fields:

The sections shall be sorted by starting position and the represented sections shall not overlap.

10.1 DecodeIndexSourceMap ( json, baseURL )

The abstract operation DecodeIndexSourceMap takes arguments json (an Object) and baseURL (an URL) and returns a Decoded Source Map Record. It performs the following steps when called:

  1. Let sectionsField be JSONObjectGet(json, "sections").
  2. Assert: sectionsField is not missing.
  3. If sectionsField is not a JSON array, throw an error.
  4. If JSONObjectGet(json, "version") is not 3𝔽, optionally report an error.
  5. Let fileField be GetOptionalString(json, "file").
  6. Let sourceMap be the Decoded Source Map Record { [[File]]: fileField, [[Sources]]: « », [[Mappings]]: « » }.
  7. Let previousOffsetPosition be null.
  8. Let previousLastMapping be null.
  9. For each JSON value section of JSONArrayIterate(sectionsField), do
    1. If section is not a JSON object, then
      1. Optionally report an error.
    2. Else,
      1. Let offset be JSONObjectGet(section, "offset").
      2. If offset is not a JSON object, throw an error.
      3. Let offsetLine be JSONObjectGet(offset, "line").
      4. Let offsetColumn be JSONObjectGet(offset, "column").
      5. If offsetLine is not an integral Number, then
        1. Optionally report an error.
        2. Set offsetLine to +0𝔽.
      6. If offsetColumn is not an integral Number, then
        1. Optionally report an error.
        2. Set offsetColumn to +0𝔽.
      7. Let offsetPosition be a new Position Record { [[Line]]: offsetLine, [[Column]]: offsetColumn }.
      8. If previousOffsetPositionnull, then
        1. If ComparePositions(offsetPosition, previousOffsetPosition) is lesser, optionally report an error.
      9. If previousLastMappingnull, then
        1. If ComparePositions(offsetPosition, previousLastMapping.[[GeneratedPosition]]) is lesser, optionally report an error.
        2. NOTE: This part of the decoding algorithm checks that entries of the sections field of index source maps are ordered and do not overlap. While it is expected that generators should not produce index source maps with overlapping sections, source map consumers may, for example, only check the simpler condition that the section offsets are ordered.
      10. Let mapField be JSONObjectGet(section, "map").
      11. If mapField is not a JSON object, throw an error.
      12. Let decodedSectionCompletion be Completion(DecodeSourceMap(json, baseURL)).
      13. If decodedSectionCompletion is a throw completion, then
        1. Optionally report an error.
      14. Else,
        1. Let decodedSection be decodedSectionCompletion.[[Value]].
        2. For each Decoded Source Record additionalSource of decodedSection.[[Sources]], do
          1. If sourceMap.[[Sources]] does not contain additionalSource, then
            1. Append additionalSource to sourceMap.[[Sources]].
        3. Let offsetMappings be a new empty List.
        4. For each Decoded Mapping Record mapping of decodedSection.[[Mappings]], do
          1. If mapping.[[GeneratedPosition]].[[Line]] = 0, then
            1. Set mapping.[[GeneratedPosition]].[[Column]] to mapping.[[GeneratedPosition]].[[Column]] + offsetColumn.
          2. Set mapping.[[GeneratedPosition]].[[Line]] to mapping.[[GeneratedPosition]].[[Line]] + offsetLine.
          3. Append mapping to offsetMappings.
        5. Set sourceMap.[[Mappings]] to the list-concatenation of sourceMap.[[Mappings]] and offsetMappings.
        6. Set previousOffsetPosition to offsetPosition.
        7. Let sortedMappings be a copy of offsetMappings, sorted in ascending order, with a Decoded Mapping Record a being less than a Decoded Mapping Record b if ComparePositions(a.[[GeneratedPosition]], b.[[GeneratedPosition]]) is lesser.
        8. If sortedMappings is not empty, set previousLastMapping to the last element of sortedMappings.
    3. Return sourceMap.
Note
Implementations may choose to represent index source map sections without appending the mappings together, for example, by storing each section separately and conducting a binary search.

11 Retrieving source maps

11.1 Linking generated code to source maps

While the source map format is intended to be language and platform agnostic, it is useful to define how to reference to them for the expected use-case of web server-hosted JavaScript.

There are two possible ways to link source maps to the output. The first requires server support in order to add an HTTP header and the second requires an annotation in the source.

Source maps are linked through URLs as defined in WHATWG URL; in particular, characters outside the set permitted to appear in URIs shall be percent-encoded and it may be a data URI. Using a data URI along with sourcesContent allows for a completely self-contained source map.

The HTTP sourcemap header has precedence over a source annotation, and if both are present, the header URL should be used to resolve the source map file.

Regardless of the method used to retrieve the source map URL the same process is used to resolve it, which is as follows.

When the source map URL is not absolute, then it is relative to the generated code's source origin. The source origin is determined by one of the following cases:

  • If the generated source is not associated with a script element that has a src attribute and there exists a //# sourceURL comment in the generated code, that comment should be used to determine the source origin.

    Note
    Previously, this was //@ sourceURL, as with //@ sourceMappingURL, it is reasonable to accept both but //# is preferred.
  • If the generated code is associated with a script element and the script element has a src attribute, the src attribute of the script element will be the source origin.
  • If the generated code is associated with a script element and the script element does not have a src attribute, then the source origin will be the page's origin.
  • If the generated code is being evaluated as a string with the eval() function or via new Function(), then the source origin will be the page's origin.

11.1.1 Linking through HTTP headers

If a file is served through HTTP(S) with a sourcemap header, the value of the header is the URL of the linked source map.

sourcemap: <url>
Note
Previous revisions of this document recommended a header name of x-sourcemap. This is now deprecated; sourcemap is now expected.

11.1.2 Linking through inline annotations

The generated code should include a comment, or the equivalent construct depending on its language or format, named sourceMappingURL and that contains the URL of the source map. This specification defines how the comment should look like for JavaScript, CSS, and WebAssembly. Other languages should follow a similar convention.

For a given language there can be multiple ways of detecting the sourceMappingURL comment, to allow for different implementations to choose what is less complex for them. The generated code unambiguously links to a source map if the result of all the extraction methods is the same.

If a tool consumes one or more source files that unambiguously links to a source map and it produces an output file that links to a source map, it shall do so unambiguously.

Note 1

The following JavaScript code links to a source map, but it does not do so unambiguously:

let a = `
//# sourceMappingURL=foo.js.map
//`

Extracting a source map URL from it through parsing gives null, while without parsing gives foo.js.map.

Note 2

Having multiple ways to extract a source map URL, that can lead to different results, can have negative security and privacy implications. Implementations that need to detect which source maps are potentially going to be loaded are strongly encouraged to always apply both algorithms, rather than just assuming that they will give the same result.

A fix to this problem is being worked on, and is expected to be included in a future version of the standard. It will likely involve early returning from the below algorithms whenever there is a comment (or comment-like) that contains the characters U+0060 (`), U+0022 ("), or U+0027 ('), or the the sequence U+002A U+002F (*/).

11.1.2.1 JavaScriptExtractSourceMapURL ( source )

The abstract operation JavaScriptExtractSourceMapURL takes argument source (a String) and returns a String or null. It extracts a source map URL from a JavaScript source. It has two possible implementations: either through parsing or without parsing.

To extract a source map URL through parsing:

  1. Let tokens be the List of tokens obtained by parsing source according to ECMA-262's lexical grammar.
  2. For each nonterminal token in tokens, in reverse order, do
    1. If token is not SingleLineComment or MultiLineComment, return null.
    2. Let comment be the content of token.
    3. Let sourceMapURL be MatchSourceMapURL(comment).
    4. If sourceMapURL is a String, return sourceMapURL.
  3. Return null.

To extract a source map URL without parsing:

  1. Let lines be StringSplit(source, « "\u000D\u000A", "\u000A", "\u000D", "\u2028", "\u2029" »).
  2. NOTE: The regular expression above matches the LineTerminatorSequence production.
  3. Let lastURL be null.
  4. For each String lineStr in lines, do
    1. Let line be StringToCodePoints(lineStr).
    2. Let position be 0.
    3. Let lineLength be the length of line.
    4. Repeat, while position < lineLength,
      1. Let first be line[position].
      2. Set position to position + 1.
      3. If first is U+002F (SOLIDUS) and position < lineLength, then
        1. Let second be line[position].
        2. Set position to position + 1.
        3. If second is U+002F (SOLIDUS), then
          1. Let comment be the substring of lineStr from position to lineLength.
          2. Let sourceMapURL be MatchSourceMapURL(comment).
          3. If sourceMapURL is a String, set lastURL to sourceMapURL.
          4. Set position to lineLength.
        4. Else if second is U+002A (ASTERISK), then
          1. Let commentCp be a new empty List.
          2. Repeat, while position + 1 < lineLength,
            1. Let c1 be line[position].
            2. Set position to position + 1.
            3. Let c2 be line[position].
            4. If c1 is U+002A (ASTERISK) and c2 is U+002F (SOLIDUS), then
              1. Set position to position + 1.
              2. Let sourceMapURL be MatchSourceMapURL(CodePointsToString(commentCp)).
              3. If sourceMapURL is a String, set lastURL to sourceMapURL.
            5. Append c1 to commentCp.
        5. Else,
          1. Set lastURL to null.
      4. Else if first is not an ECMAScript WhiteSpace, then
        1. Set lastURL to null.
      5. NOTE: We reset lastURL to null whenever we find a non-comment code character.
  5. Return lastURL.
Note 1
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.
Note 2

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;

11.1.2.1.1 MatchSourceMapURL ( comment )

The abstract operation MatchSourceMapURL takes argument comment (a String) and returns either none or a String. It performs the following steps when called:

  1. Let pattern be RegExpCreate("^[@#]\s*sourceMappingURL=(\S*?)\s*$", "").
  2. Let match be RegExpExec(pattern, comment).
  3. If match is not null, return Get(match, "1").
  4. Return none.
Note
The prefix for this annotation 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 //#.

11.1.2.2 CSSExtractSourceMapURL ( source )

The abstract operation CSSExtractSourceMapURL takes argument source (a String) and returns a String or null. It extracts a source map URL from a CSS source.

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

11.1.2.3 WebAssemblyExtractSourceMapURL ( bytes )

The abstract operation WebAssemblyExtractSourceMapURL takes argument bytes (a Data Block) and returns a String or null. It extracts a source map URL from a WebAssembly binary source.

  1. Let module be module_decode(bytes).
  2. If module is WebAssembly error, return null.
  3. For each custom section customSection of module, do
    1. Let name be the name of customSection.
    2. If CodePointsToString(name) is "sourceMappingURL", then
      1. Let value be the bytes of customSection.
      2. Return CodePointsToString(value).
  4. 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.

11.2 Fetching source maps

11.2.1 FetchSourceMap ( url )

The abstract operation FetchSourceMap takes argument url (an URL) and returns a Promise. It performs the following steps when called:

  1. Let promiseCapability be NewPromiseCapability(%Promise%).
  2. Let request be a new request whose request URL is url.
  3. Let processResponseConsumeBody be a new Abstract Closure with parameters (response, bodyBytes) that captures promiseCapability and url, and performs the following steps when called:
    1. If bodyBytes is null or failure, then
      1. Perform Call(promiseCapability.[[Reject]], undefined, « a new TypeError »).
      2. Return.
    2. If url's scheme is an HTTP(S) scheme and the byte sequence `)]}'` is a byte-sequence-prefix of bodyBytes, then
      1. Repeat, while bodyBytes's byte-sequence-length ≠ 0 and bodyBytes[0] is not an HTTP newline byte,
        1. Remove the 0th element from bodyBytes.
    3. Let bodyString be Completion(UTF-8 decode of bodyBytes).
    4. IfAbruptRejectPromise(bodyString, promiseCapability).
    5. Let jsonValue be Completion(ParseJSON(bodyString)).
    6. IfAbruptRejectPromise(jsonValue, promiseCapability).
    7. Perform Call(promiseCapability.[[Resolve]], undefined, « jsonValue »).
  4. Perform fetch request with processResponseConsumeBody set to processResponseConsumeBody.
  5. Return promiseCapability.[[Promise]].
Note

For historic reasons, when delivering source maps over HTTP(S), servers may prepend a line starting with the string )]}' to the source map.

)]}'garbage here
{"version": 3, ...}

is interpreted as

{"version": 3, ...}

Annex A (informative) Conventions

The following conventions should be followed when working with source maps or when generating them.

A.1 Source map naming

Commonly, a source map will have the same name as the generated file but with a .map extension. For example, for page.js a source map named page.js.map would be generated.

A.2 Linking eval'd code to named generated code

There is an existing convention that should be supported for the use of source maps with eval'd code, it has the following form:

//# sourceURL=foo.js

It is described in Give your eval a name with //@ sourceURL.

Annex B (informative) Notes

B.1 Language neutral stack mapping

Stack tracing mapping without knowledge of the source language is not covered by this document.

B.2 Multi-level mapping

It is getting more common to have tools generate sources from some DSL (templates) or compile TypeScript → JavaScript → minified JavaScript, resulting in multiple translations before the final source map is created. This problem can be handled in one of two ways. The easy but lossy way is to ignore the intermediate steps in the process for the purposes of debugging, the source location information from the translation is either ignored (the intermediate translation is considered the “Original Source”) or the source location information is carried through (the intermediate translation hidden). The more complete way is to support multiple levels of mapping: if the Original Source also has a source map reference, the user is given the choice of using that as well.

However, it is unclear what a "source map reference" looks like in anything other than JavaScript. More specifically, what a source map reference looks like in a language that doesn't support JavaScript-style single-line comments.

Annex C (informative) Terms defined in other specifications

This section lists all terms and algorithms used by this document defined by external specifications other than ECMA-262.

WebAssembly Core Specification <https://www.w3.org/TR/wasm-core-2/>
custom section, module_decode, WebAssembly error, WebAssembly names
WHATWG Encoding <https://encoding.spec.whatwg.org/>
UTF-8 decode
WHATWG Fetch <https://fetch.spec.whatwg.org/>
fetch, HTTP newline byte, processResponseConsumeBody, request, request URL
WHATWG Infra <https://infra.spec.whatwg.org/>
byte sequence, byte-sequence-prefix, byte-sequence-length,
WHATWG URL <https://url.spec.whatwg.org/>
HTTP(S) scheme, scheme, URL, URL parsing

Annex D (informative) Bibliography

  1. IETF RFC 4648, The Base16, Base32, and Base64 Data Encodings, available at <https://datatracker.ietf.org/doc/html/rfc4648>
  2. ECMA-262, ECMAScript® Language Specification, available at <https://tc39.es/ecma262/>
  3. ECMA-404, The JSON Data Interchange Format, available at <https://www.ecma-international.org/publications-and-standards/standards/ecma-404/>
  4. WebAssembly Core Specification, available at <https://www.w3.org/TR/wasm-core-2/>
  5. WHATWG Encoding, available at <https://encoding.spec.whatwg.org/>
  6. WHATWG Fetch, available at <https://fetch.spec.whatwg.org/>
  7. WHATWG Infra, available at <https://infra.spec.whatwg.org/>
  8. WHATWG URL, available at <https://url.spec.whatwg.org/>
  9. Give your eval a name with //@ sourceURL, Firebug (2009), available at <http://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/>
  10. Source Map Revision 2 Proposal, John Lenz (2010), available at <https://docs.google.com/document/d/1xi12LrcqjqIHTtZzrzZKmQ3lbTv9mKrN076UB-j3UZQ/>
  11. Variable-length quantity, Wikipedia, available at <https://en.wikipedia.org/wiki/Variable-length_quantity>

Annex E (informative) Colophon

This specification is authored on GitHub in a plaintext source format called Ecmarkup. Ecmarkup is an HTML and Markdown dialect that provides a framework and toolset for authoring ECMAScript specifications in plaintext and processing the specification into a full-featured HTML rendering that follows the editorial conventions for this document. Ecmarkup builds on and integrates a number of other formats and technologies including Grammarkdown for defining syntax and Ecmarkdown for authoring algorithm steps. PDF renderings of this specification are produced by printing the HTML rendering to a PDF.

The first edition of this specification was authored using Bikeshed, a different plaintext source format based on HTML and Markdown.

Pre-standard versions of this document were authored using Google Docs.

Copyright & Software License

Ecma International

Rue du Rhone 114

CH-1204 Geneva

Tel: +41 22 849 6000

Fax: +41 22 849 6001

Web: https://ecma-international.org/

Copyright Notice

© 2025 Ecma International

This draft document may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published, and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this section are included on all such copies and derivative works. However, this document itself may not be modified in any way, including by removing the copyright notice or references to Ecma International, except as needed for the purpose of developing any document or deliverable produced by Ecma International.

This disclaimer is valid only prior to final version of this document. After approval all rights on the standard are reserved by Ecma International.

The limited permissions are granted through the standardization phase and will not be revoked by Ecma International or its successors or assigns during this time.

This document and the information contained herein is provided on an "AS IS" basis and ECMA INTERNATIONAL DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY OWNERSHIP RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Software License

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.