?ue/p1-90`https://tc39.es/ecma426/ 上的文档是最准确且最新的源映射规范。它包含最近发布的快照的内容,以及将被包含在下一个快照中的任何修改。
本规范在 GitHub 上开发。可以通过多种方式为本规范的开发作贡献:
有关本文档如何创建的更多信息,请参见
本 Ecma 标准定义了源映射格式,该格式用于将转译后的源代码映射回
源映射格式具有以下目标:
源映射格式不再具有版本号,而是被硬编码为始终为 “3”。
在 2023-2024 年,源映射格式被发展为更精确的 Ecma 标准,并得到了许多人的重要贡献。对源映射格式的进一步迭代预计将来自 TC39-TG4。
Asumu Takikawa, Nicolò Ribaudo, Jon Kuperman
ECMA-426,第 1st 版,项目编辑
本标准定义了源映射格式,该格式由不同类型的开发者工具使用,用于改善编译到 JavaScript、WebAssembly 和 CSS 的代码的调试体验。
符合要求的源映射文档是一个 JSON 文档,它符合本规范中详述的结构。
符合要求的源映射生成器应该生成符合要求的源映射文档,并且这些文档可以由本规范中的算法解码,而不报告任何错误(即使是被规定为可选的错误)。
符合要求的源映射消费者应该实现本规范中指定的用于获取(在适用情况下)和解码源映射文档的算法。在规范指出算法可以
以下文档以这样的方式在正文中被引用:其部分或全部内容构成本文档的要求。对于有日期的引用,仅适用所引用的版本。对于无日期的引用,适用被引用文档的最新版本(包括任何修订)。
ECMA-262,ECMAScript® 语言规范。
https://tc39.es/ecma262/
ECMA-404,JSON 数据交换格式。
https://www.ecma-international.org/publications-and-standards/standards/ecma-404/
IETF RFC 4648,Base16、Base32 和 Base64 数据编码。
https://datatracker.ietf.org/doc/html/rfc4648
WebAssembly 核心规范。
https://www.w3.org/TR/wasm-core-2/
WHATWG Encoding。
https://encoding.spec.whatwg.org/
WHATWG
https://fetch.spec.whatwg.org/
WHATWG Infra。
https://infra.spec.whatwg.org/
WHATWG
https://url.spec.whatwg.org/
本规范遵循 ECMA-262(记号约定)中定义的相同记号约定,并带有本节中定义的扩展。
本规范中声明的所有抽象操作都被隐式假定为要么返回一个包含算法声明返回类型的正常完成,要么返回一个抛出完成。例如,声明为如下形式的抽象操作
4.1.1.1 GetTheAnswer ( input: 整数, ): 整数
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS.
等价于:
4.1.1.2 GetTheAnswer2 ( input: 整数, ): 包含整数的正常完成或抛出完成
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS.
所有对返回完成记录的抽象操作的调用都被隐式假定为由 ECMA-262 的 ? 完成记录解包简写包裹,除非它们由显式的
1. 令 _result_ 为 GetTheAnswer(_value_)。
1. 令 _second_ 为 Completion(GetTheAnswer(_value_))。
等价于:
1. 令 _result_ 为 ? GetTheAnswer(_value_)。
1. 令 _second_ 为 Completion(GetTheAnswer(_value_))。
每当算法要可选地报告错误时,实现可以选择以下行为之一:
实现可以针对不同的可选错误选择不同的行为。
本规范遵循 ECMA-262(语法记号)中定义的相同语法记号约定,并带有以下注意事项:
就本文档而言,适用以下术语和定义。
base64 VLQ 是一种以
"iB" 表示一个具有两个数字的 base64 VLQ。第一个数字 "i" 编码位模式 0b100010,其继续位为 1(VLQ 继续),符号位为 0(非负),值位为 0b0001。第二个数字 B 编码位模式 0b000001,其继续位为 0,没有符号位,值位为 0b00001。此 VLQ 字符串的解码结果是数字 17。
"V" 表示一个具有一个数字的 base64 VLQ。数字 "V" 编码位模式 0b010101,其继续位为 0(不继续),符号位为 1(负),值位为 0b1010。此 VLQ 字符串的解码结果是数字 -10。
base64 VLQ 遵循以下词法语法:
The
1. 令 _unsigned_ 为 |VlqDigitList| 的 VLQUnsignedValue。
1. 如果 _unsigned_ modulo 2 = 1,则令 _sign_ 为 -1。
1. 否则,令 _sign_ 为 1。
1. 令 _value_ 为 floor(_unsigned_ / 2)。
1. 如果 _value_ 是 0 且 _sign_ 是 -1,则返回 -231。
1. [id="step-VLQSignedValue-boundary-check"] 如果 _value_ ≥ 231,则抛出错误。
1. 返回 _sign_ × _value_。
The
1. 令 _value_ 为 |VlqDigitList| 的 VLQUnsignedValue。
1. 如果 _value_ ≥ 232,则抛出错误。
1. 返回 _value_。
1. 令 _left_ 为 |ContinuationDigit| 的 VLQUnsignedValue。
1. 令 _right_ 为 |VlqDigitList| 的 VLQUnsignedValue。
1. 返回 _left_ + _right_ × 25。
1. 令 _digit_ 为此产生式匹配的字符。
1. 令 _value_ 为根据 IETF RFC 4648 定义的 base64 编码,与 _digit_ 对应的整数。
1. 断言:_value_ < 32。
1. 返回 _value_。
1. 令 _digit_ 为此产生式匹配的字符。
1. 令 _value_ 为根据 IETF RFC 4648 定义的 base64 编码,与 _digit_ 对应的整数。
1. 断言:32 ≤ _value_ < 64。
1. 返回 _value_ - 32。
虽然本规范的算法是在 ECMA-262 内部机制之上定义的,但它旨在易于由非 JavaScript 平台实现。本节包含用于处理
JSON 值要么是
JSON 对象是满足其每个属性均符合以下条件的 Object:
JSON 数组是满足以下条件的
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS. It performs the following steps when called:
1. 令 _result_ 为 Call(%JSON.parse% , *null*, « _string_ »)。 1. 断言:_result_ 是 JSON 值。 1. 返回 _result_。
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS. It performs the following steps when called:
1. 如果 _object_ 没有键为 _key_ 的自有属性,则返回 ~missing~。
1. 令 _prop_ 为 _object_ 的键为 _key_ 的自有属性。
1. 返回 _prop_ 的 [[Value]] 特性。
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS. It performs the following steps when called:
1. 令 _length_ 为 JSONObjectGet(_array_, *"length"*)。
1. 断言:_length_ 是非负整数 Number。
1. 令 _list_ 为一个新的空 List。
1. 令 _i_ 为 0。
1. 重复,当 _i_ < ℝ(_length_) 时,
1. 令 _value_ 为 JSONObjectGet(_array_, ToString(𝔽(_i_)))。
1. 断言:_value_ 不是 ~missing~。
1. 将 _value_ 追加到 _list_。
1. 将 _i_ 设为 _i_ + 1。
1. 返回 _list_。
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS. It performs the following steps when called:
1. 令 _parts_ 为一个新的空 List。
1. 令 _strLen_ 为 _string_ 的长度。
1. 令 _lastStart_ 为 0。
1. 令 _i_ 为 0。
1. 重复,当 _i_ < _strLen_ 时,
1. 令 _matched_ 为 *false*。
1. 对于 _separators_ 的每个 String _sep_,执行
1. 令 _sepLen_ 为 _sep_ 的长度。
1. 令 _candidate_ 为 _string_ 从 _i_ 到 min(_i_ + _sepLen_, _strLen_) 的子字符串。
1. 如果 _candidate_ = _sep_ 且 _matched_ 是 *false*,则
1. 令 _chunk_ 为 _string_ 从 _lastStart_ 到 _i_ 的子字符串。
1. 将 _chunk_ 追加到 _parts_。
1. 将 _lastStart_ 设为 _i_ + _sepLen_。
1. 将 _i_ 设为 _i_ + _sepLen_。
1. 将 _matched_ 设为 *true*。
1. 如果 _matched_ 是 *false*,则将 _i_ 设为 _i_ + 1。
1. 令 _chunk_ 为 _string_ 从 _lastStart_ 到 _strLen_ 的子字符串。
1. 将 _chunk_ 追加到 _parts_。
1. 返回 _parts_。
Position Record 是由非负行号和非负
| 字段名 | 值类型 |
|---|---|
| [[Line]] | 非负整数 Number |
| [[Column]] | 非负整数 Number |
Original Position Record 是由
| 字段名 | 值类型 |
|---|---|
| [[Source]] | |
| [[Line]] | 非负整数 Number |
| [[Column]] | 非负整数 Number |
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS. It performs the following steps when called:
1. 如果 _first_.[[Line]] < _second_.[[Line]],则返回 ~lesser~。
1. 如果 _first_.[[Line]] > _second_.[[Line]],则返回 ~greater~。
1. 断言:_first_.[[Line]] 等于 _second_.[[Line]]。
1. 如果 _first_.[[Column]] < _second_.[[Column]],则返回 ~lesser~。
1. 如果 _first_.[[Column]] > _second_.[[Column]],则返回 ~greater~。
1. 返回 ~equal~。
源映射是一个 JSON 文档,包含具有以下结构的顶层
{
"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]
}
version 字段应始终是整数形式的数字 3。如果该字段具有任何其他值,则源映射可以被拒绝。file 字段是此源映射关联的sourceRoot 字段是一个可选的源根字符串,用于在服务器上重新定位源文件,或移除 sources 条目中的重复值。此值会被前置到 sources 字段是 sourcesContent 字段是源内容(即names 字段是一个可选的符号名称mappings 字段是包含编码映射数据的字符串(参见 ignoreList 字段是应被视为第三方代码的文件索引的可选ignoreList,某些浏览器也可以使用已弃用的 x_google_ignoreList 字段。Decoded Source Map Record 具有以下字段:
| 字段名 | 值类型 |
|---|---|
| [[File]] | String 或 |
| [[Sources]] | |
| [[Mappings]] |
Decoded Source Record 具有以下字段:
| 字段名 | 值类型 |
|---|---|
| [[URL]] | |
| [[Content]] | String 或 |
| [[Ignored]] | Boolean |
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS. It performs the following steps when called:
1. 令 _json_ 为 ParseJSON(_string_)。
1. 如果 _json_ 不是 JSON 对象,则抛出错误。
1. 如果 JSONObjectGet(_json_, *"sections"*) 不是 ~missing~,则
1. 返回 DecodeIndexSourceMap(_json_, _baseURL_)。
1. 返回 DecodeSourceMap(_json_, _baseURL_)。
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS. It performs the following steps when called:
1. 如果 JSONObjectGet(_json_, *"version"*) 不是 *3*𝔽,则可选地报告错误。
1. 令 _mappingsField_ 为 JSONObjectGet(_json_, *"mappings"*)。
1. 如果 _mappingsField_ 不是 String,则抛出错误。
1. 如果 JSONObjectGet(_json_, *"sources"*) 不是 JSON 数组,则抛出错误。
1. 令 _fileField_ 为 GetOptionalString(_json_, *"file"*)。
1. 令 _sourceRootField_ 为 GetOptionalString(_json_, *"sourceRoot"*)。
1. 令 _sourcesField_ 为 GetOptionalListOfOptionalStrings(_json_, *"sources"*)。
1. 令 _sourcesContentField_ 为 GetOptionalListOfOptionalStrings(_json_, *"sourcesContent"*)。
1. 令 _ignoreListField_ 为 GetOptionalListOfArrayIndexes(_json_, *"ignoreList"*)。
1. 令 _sources_ 为 DecodeSourceMapSources(_baseURL_, _sourceRootField_, _sourcesField_, _sourcesContentField_, _ignoreListField_)。
1. 令 _namesField_ 为 GetOptionalListOfStrings(_json_, *"names"*)。
1. 令 _mappings_ 为 DecodeMappings(_mappingsField_, _namesField_, _sources_)。
1. [declared="a,b"] 按升序对 _mappings_ 排序,其中如果 ComparePositions(_a_.[[GeneratedPosition]], _b_.[[GeneratedPosition]]) 是 ~lesser~,则 Decoded Mapping Record _a_ 小于 Decoded Mapping Record _b_。
1. 返回 Decoded Source Map Record { [[File]]: _fileField_, [[Sources]]: _sources_, [[Mappings]]: _mappings_ }。
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS. It performs the following steps when called:
1. 令 _value_ 为 JSONObjectGet(_object_, _key_)。
1. 如果 _value_ 是 String,则返回 _value_。
1. 如果 _value_ 不是 ~missing~,则可选地报告错误。
1. 返回 *null*。
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS. It performs the following steps when called:
1. 令 _list_ 为一个新的空 List。
1. 令 _values_ 为 JSONObjectGet(_object_, _key_)。
1. 如果 _values_ 是 ~missing~,则返回 _list_。
1. 如果 _values_ 不是 JSON 数组,则
1. 可选地报告错误。
1. 返回 _list_。
1. 对于 JSONArrayIterate(_values_) 的每个元素 _item_,执行
1. 如果 _item_ 是 String,则
1. 将 _item_ 追加到 _list_。
1. 否则,
1. 可选地报告错误。
1. 将空字符串追加到 *list*。
1. 返回 _list_。
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS. It performs the following steps when called:
1. 令 _list_ 为一个新的空 List。
1. 令 _values_ 为 JSONObjectGet(_object_, _key_)。
1. 如果 _values_ 是 ~missing~,则返回 _list_。
1. 如果 _values_ 不是 JSON 数组,则
1. 可选地报告错误。
1. 返回 _list_。
1. 对于 JSONArrayIterate(_values_) 的每个元素 _item_,执行
1. 如果 _item_ 是 String,则
1. 将 _item_ 追加到 _list_。
1. 否则,
1. 如果 _item_ ≠ *null*,则可选地报告错误。
1. 将 *null* 追加到 _list_。
1. 返回 _list_。
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS. It performs the following steps when called:
1. 令 _list_ 为一个新的空 List。
1. 令 _values_ 为 JSONObjectGet(_object_, _key_)。
1. 如果 _values_ 是 ~missing~,则返回 _list_。
1. 如果 _values_ 不是 JSON 数组,则
1. 可选地报告错误。
1. 返回 _list_。
1. 对于 JSONArrayIterate(_values_) 的每个元素 _item_,执行
1. 如果 _item_ 是整数 Number,且 _item_ ≥ *+0*𝔽,则
1. 将 ℝ(_item_) 追加到 _list_。
1. 否则,
1. 可选地报告错误。
1. 返回 _list_。
;)分隔,)分隔每个段中的字段是:
;)之后的第一个段,则此字段保存整个 Decoded Mapping Record 具有以下字段:
| 字段名 | 值类型 |
|---|---|
| [[GeneratedPosition]] | |
| [[OriginalPosition]] | |
| [[Name]] | String 或 |
mappings String 必须遵循以下语法:
Decode Mapping State Record 具有以下字段:
| 字段名 | 值类型 |
|---|---|
| [[GeneratedLine]] | 非负整数 |
| [[GeneratedColumn]] | 非负整数 |
| [[SourceIndex]] | 非负整数 |
| [[OriginalLine]] | 非负整数 |
| [[OriginalColumn]] | 非负整数 |
| [[NameIndex]] | 非负整数 |
The
1. 使用参数 _state_、_mappings_、_names_ 和 _sources_,执行 |Line| 的 DecodeMappingsField。
1. 将 _state_.[[GeneratedLine]] 设为 _state_.[[GeneratedLine]] + 1。
1. 将 _state_.[[GeneratedColumn]] 设为 0。
1. 使用参数 _state_、_mappings_、_names_ 和 _sources_,执行 |LineList| 的 DecodeMappingsField。
1. 返回。
1. 使用参数 _state_、_mappings_、_names_ 和 _sources_,执行 |Mapping| 的 DecodeMappingsField。
1. 使用参数 _state_、_mappings_、_names_ 和 _sources_,执行 |MappingList| 的 DecodeMappingsField。
1. 使用参数 _state_、_mappings_、_names_ 和 _sources_,执行 |GeneratedColumn| 的 DecodeMappingsField。
1. 如果 _state_.[[GeneratedColumn]] < 0,则
1. 可选地报告错误。
1. 返回。
1. 令 _position_ 为新的 Position Record { [[Line]]: _state_.[[GeneratedLine]], [[Column]]: _state_.[[GeneratedColumn]] }。
1. 令 _decodedMapping_ 为新的 DecodedMappingRecord { [[GeneratedPosition]]: _position_, [[OriginalPosition]]: *null*, [[Name]]: *null* }。
1. 将 _decodedMapping_ 追加到 _mappings_。
1. 使用参数 _state_、_mappings_、_names_ 和 _sources_,执行 |GeneratedColumn| 的 DecodeMappingsField。
1. 如果 _state_.[[GeneratedColumn]] < 0,则
1. 可选地报告错误。
1. 返回。
1. 令 _generatedPosition_ 为新的 Position Record { [[Line]]: _state_.[[GeneratedLine]], [[Column]]: _state_.[[GeneratedColumn]] }。
1. 使用参数 _state_、_mappings_、_names_ 和 _sources_,执行 |OriginalSource| 的 DecodeMappingsField。
1. 使用参数 _state_、_mappings_、_names_ 和 _sources_,执行 |OriginalLine| 的 DecodeMappingsField。
1. 使用参数 _state_、_mappings_、_names_ 和 _sources_,执行 |OriginalColumn| 的 DecodeMappingsField。
1. 如果 _state_.[[SourceIndex]] < 0,或 _state_.[[SourceIndex]] ≥ _sources_ 的元素数量,或 _state_.[[OriginalLine]] < 0,或 _state_.[[OriginalColumn]] < 0,则
1. 可选地报告错误。
1. 令 _originalPosition_ 为 *null*。
1. 否则,
1. 令 _originalPosition_ 为新的 Original Position Record { [[Source]]: _sources_[_state_.[[SourceIndex]]], [[Line]]: _state_.[[OriginalLine]], [[Column]]: _state_.[[OriginalColumn]] }。
1. 令 _name_ 为 *null*。
1. 如果 |Name| 存在,则
1. 使用参数 _state_、_mappings_、_names_ 和 _sources_,执行 |Name| 的 DecodeMappingsField。
1. 如果 _state_.[[NameIndex]] < 0,或 _state_.[[NameIndex]] ≥ _names_ 的元素数量,则可选地报告错误。
1. 否则,将 _name_ 设为 _names_[_state_.[[NameIndex]]]。
1. 令 _decodedMapping_ 为新的 DecodedMappingRecord { [[GeneratedPosition]]: _generatedPosition_, [[OriginalPosition]]: _originalPosition_, [[Name]]: _name_ }。
1. 将 _decodedMapping_ 追加到 _mappings_。
1. 令 _relativeColumn_ 为 |Vlq| 的 VLQSignedValue。
1. 将 _state_.[[GeneratedColumn]] 设为 _state_.[[GeneratedColumn]] + _relativeColumn_。
1. 令 _relativeSourceIndex_ 为 |Vlq| 的 VLQSignedValue。
1. 将 _state_.[[SourceIndex]] 设为 _state_.[[SourceIndex]] + _relativeSourceIndex_。
1. 令 _relativeLine_ 为 |Vlq| 的 VLQSignedValue。
1. 将 _state_.[[OriginalLine]] 设为 _state_.[[OriginalLine]] + _relativeLine_。
1. 令 _relativeColumn_ 为 |Vlq| 的 VLQSignedValue。
1. 将 _state_.[[OriginalColumn]] 设为 _state_.[[OriginalColumn]] + _relativeColumn_。
1. 令 _relativeName_ 为 |Vlq| 的 VLQSignedValue。
1. 将 _state_.[[NameIndex]] 设为 _state_.[[NameIndex]] + _relativeName_。
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS. It performs the following steps when called:
1. 令 _mappings_ 为一个新的空 List。
1. 令 _mappingsNode_ 为使用 |MappingsField| 作为目标符号解析 _rawMappings_ 时得到的根 Parse Node。
1. 如果解析失败,则
1. 可选地报告错误。
1. 返回 _mappings_。
1. 令 _state_ 为一个新的 Decode Mapping State Record,其所有字段均设为 0。
1. 使用参数 _state_、_mappings_、_names_ 和 _sources_,执行 _mappingsNode_ 的 DecodeMappingsField。
1. 返回 _mappings_。
可以具有
如果满足以下条件,源映射生成器应该为 JavaScript token 创建一个具有 [[Name]] 字段的
那么该
以下枚举
该枚举应该被理解为“最低要求”。一般而言,源映射生成器可以自由发出任何额外的命名映射。
A)。
(。
无论
对于
当 => token。
当 (。
为与前一种情况保持一致,源映射生成器可以选择额外地在 => token 上发出命名映射。
源映射生成器可以选择额外地在左括号 ( 上发出命名映射。
源映射生成器可以为
如果在前置 sourceRoot 之后 sources 不是绝对 src 属性)。
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS. It performs the following steps when called:
1. 令 _decodedSources_ 为一个新的空 List。
1. 令 _sourcesContentCount_ 为 _sourcesContent_ 中的元素数量。
1. 令 *sourceUrlPrefix* 为空字符串。
1. 如果 _sourceRoot_ ≠ *null*,则
1. 如果 _sourceRoot_ 以码点 U+002F (SOLIDUS) 结尾,则
1. 将 _sourceUrlPrefix_ 设为 _sourceRoot_。
1. 否则,
1. 将 _sourceUrlPrefix_ 设为 _sourceRoot_ 和 *"/"* 的字符串拼接。
1. 令 _index_ 为 0。
1. 重复,当 _index_ < _sources_ 的长度时,
1. 令 _source_ 为 _sources_[_index_]。
1. 令 _decodedSource_ 为 Decoded Source Record { [[URL]]: *null*, [[Content]]: *null*, [[Ignored]]: *false* }。
1. 如果 _source_ ≠ *null*,则
1. 将 _source_ 设为 _sourceUrlPrefix_ 和 _source_ 的字符串拼接。
1. 令 _sourceURL_ 为使用 _baseURL_ 对 _source_ 进行 URL parsing 的结果。
1. 如果 _sourceURL_ 是 ~failure~,则可选地报告错误。
1. 否则,将 _decodedSource_.[[URL]] 设为 _sourceURL_。
1. 如果 _ignoreList_ 包含 _index_,则将 _decodedSource_.[[Ignored]] 设为 *true*。
1. 如果 _sourcesContentCount_ > _index_,则将 _decodedSource_.[[Content]] 设为 _sourcesContent_[_index_]。
1. 将 _decodedSource_ 追加到 _decodedSources_。
1. 将 _index_ 设为 _index_ + 1。
1. 返回 _decodedSources_。
源映射消费者应忽略任何额外的未识别属性,而不是导致源映射被拒绝,以便可以向此格式添加额外特性而不会破坏现有用户。
为支持连接
{
"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"
}
}
]
}
索引映射遵循标准映射的形式。与常规源映射一样,其文件格式是具有顶层对象的 JSON。它与常规源映射共享 version 和
sections 字段是一个对象数组,其对象具有以下字段:
offset 字段是一个具有两个字段 line 和 column 的对象,它们表示被引用的源映射所表示的map 字段是一个嵌入的完整源映射对象。嵌入映射不会继承包含它的索引映射中的任何值。sections 应按起始位置排序,并且所表示的 sections 不应重叠。
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS. It performs the following steps when called:
1. 令 _sectionsField_ 为 JSONObjectGet(_json_, *"sections"*)。
1. 断言:_sectionsField_ 不是 ~missing~。
1. 如果 _sectionsField_ 不是 JSON 数组,则抛出错误。
1. 如果 JSONObjectGet(_json_, *"version"*) 不是 *3*𝔽,则可选地报告错误。
1. 令 _fileField_ 为 GetOptionalString(_json_, *"file"*)。
1. 令 _sourceMap_ 为 Decoded Source Map Record { [[File]]: _fileField_, [[Sources]]: « », [[Mappings]]: « » }。
1. 令 _previousOffsetPosition_ 为 *null*。
1. 令 _previousLastMapping_ 为 *null*。
1. 对于 JSONArrayIterate(_sectionsField_) 的每个 JSON 值 _section_,执行
1. 如果 _section_ 不是 JSON 对象,则
1. 可选地报告错误。
1. 否则,
1. 令 _offset_ 为 JSONObjectGet(_section_, *"offset"*)。
1. 如果 _offset_ 不是 JSON 对象,则抛出错误。
1. 令 _offsetLine_ 为 JSONObjectGet(_offset_, *"line"*)。
1. 令 _offsetColumn_ 为 JSONObjectGet(_offset_, *"column"*)。
1. 如果 _offsetLine_ 不是整数 Number,则
1. 可选地报告错误。
1. 将 _offsetLine_ 设为 *+0*𝔽。
1. 如果 _offsetColumn_ 不是整数 Number,则
1. 可选地报告错误。
1. 将 _offsetColumn_ 设为 *+0*𝔽。
1. 令 _offsetPosition_ 为新的 Position Record { [[Line]]: _offsetLine_, [[Column]]: _offsetColumn_ }。
1. 如果 _previousOffsetPosition_ ≠ *null*,则
1. 如果 ComparePositions(_offsetPosition_, _previousOffsetPosition_) 是 ~lesser~,则可选地报告错误。
1. 如果 _previousLastMapping_ ≠ *null*,则
1. 如果 ComparePositions(_offsetPosition_, _previousLastMapping_.[[GeneratedPosition]]) 是 ~lesser~,则可选地报告错误。
1. 注:解码算法的这一部分检查索引源映射的 sections 字段条目是否有序且不重叠。虽然期望生成器不应生成具有重叠 sections 的索引源映射,但源映射消费者例如可以只检查更简单的条件,即 section 偏移是有序的。
1. 令 _mapField_ 为 JSONObjectGet(_section_, *"map"*)。
1. 如果 _mapField_ 不是 JSON 对象,则抛出错误。
1. 令 _decodedSectionCompletion_ 为 Completion(DecodeSourceMap(_json_, _baseURL_))。
1. 如果 _decodedSectionCompletion_ 是抛出完成,则
1. 可选地报告错误。
1. 否则,
1. 令 _decodedSection_ 为 _decodedSectionCompletion_.[[Value]]。
1. 对于 _decodedSection_.[[Sources]] 的每个 Decoded Source Record _additionalSource_,执行
1. 如果 _sourceMap_.[[Sources]] 不包含 _additionalSource_,则
1. 将 _additionalSource_ 追加到 _sourceMap_.[[Sources]]。
1. 令 _offsetMappings_ 为一个新的空 List。
1. 对于 _decodedSection_.[[Mappings]] 的每个 Decoded Mapping Record _mapping_,执行
1. 如果 _mapping_.[[GeneratedPosition]].[[Line]] = 0,则
1. 将 _mapping_.[[GeneratedPosition]].[[Column]] 设为 _mapping_.[[GeneratedPosition]].[[Column]] + _offsetColumn_。
1. 将 _mapping_.[[GeneratedPosition]].[[Line]] 设为 _mapping_.[[GeneratedPosition]].[[Line]] + _offsetLine_。
1. 将 _mapping_ 追加到 _offsetMappings_。
1. 将 _sourceMap_.[[Mappings]] 设为 _sourceMap_.[[Mappings]] 和 _offsetMappings_ 的列表拼接。
1. 将 _previousOffsetPosition_ 设为 _offsetPosition_。
1. 如果 _offsetMappings_ 非空,则将 _previousLastMapping_ 设为 _offsetMappings_ 的最后一个元素。
1. 返回 _sourceMap_。
虽然源映射格式旨在与语言和平台无关,但为 Web 服务器托管的 JavaScript 这一预期用例定义如何引用它们是有用的。
有两种可能的方法将源映射链接到输出。第一种需要服务器支持以添加 HTTP 标头,第二种需要源中的注释。
源映射通过
HTTP sourcemap 标头优先于源注释,如果两者都存在,则应该使用标头
无论使用哪种方法获取
当
如果生成源未关联到具有 src 属性的 script 元素,并且//# sourceURL 注释,则应该使用该注释来确定
//@ sourceURL,与 //@ sourceMappingURL 一样,接受两者是合理的,但首选 //#。
src 属性,则 script 元素的 src 属性将是src 属性,则eval() 函数或通过 new Function() 求值,则如果文件通过 HTTP(S) 提供并带有 sourcemap 标头,则该标头的值是被链接源映射的
sourcemap: <url>
x-sourcemap 作为标头名称。现在已弃用;现在预期使用 sourcemap。
sourceMappingURL 的注释,或根据其语言或格式的等效构造,并且该注释包含源映射的
对于给定语言,可能有多种检测 sourceMappingURL 注释的方法,以允许不同实现选择对它们来说较不复杂的方法。如果所有提取方法的结果相同,则
如果工具消费一个或多个
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS.
要通过解析提取
1. 令 _tokens_ 为根据ECMA-262 的词法文法 解析 _source_ 所获得的输入元素 列表。 1. 按逆序遍历 _tokens_ 的每个非终结符 _token_,执行: 1. 如果 _token_ 不是 |SingleLineComment|、|WhiteSpace| 或 |LineTerminatorSequence|,则返回 *null*。 1. 令 _comment_ 为 _token_ 的内容。 1. 令 _sourceMapURL_ 为 MatchSourceMapURL(_comment_)。 1. 如果 _sourceMapURL_ 是一个字符串,则返回 _sourceMapURL_。 1. 返回 *null*。
要不通过解析提取
1. 令 _lines_ 为 StringSplit(_source_, « *"\u000D\u000A"*, *"\u000A"*, *"\u000D"*, *"\u2028"*, *"\u2029"* »)。
1. 注意:上述字符串列表与 |LineTerminatorSequence| 产生式匹配。
1. 按列表逆序遍历 _lines_ 中的每个字符串 _lineStr_,执行:
1. 令 _line_ 为 StringToCodePoints(_lineStr_)。
1. 令 _position_ 为 0。
1. 令 _lineLength_ 为 _line_ 的长度。
1. 当 _position_ < _lineLength_ 时,重复执行:
1. 令 _first_ 为 _line_[_position_]。
1. 如果 _first_ 是 U+002F(斜线),且 _position_ + 1 < _lineLength_,则:
1. 将 _position_ 设置为 _position_ + 1。
1. 令 _second_ 为 _line_[_position_]。
1. 如果 _second_ 是 U+002F(斜线),则:
1. 将 _position_ 设置为 _position_ + 1。
1. 令 _comment_ 为 _lineStr_ 中从 _position_ 到 _lineLength_ 的子字符串。
1. 如果 _comment_ 包含码点 U+0022(引号)、U+0027(撇号)或 U+0060(重音符)中的任意一个,则:
1. 返回 *null*。
1. 如果 _comment_ 包含码点 U+002A(星号),且其后紧跟码点 U+002F(斜线),则:
1. 返回 *null*。
1. 令 _sourceMapURL_ 为 MatchSourceMapURL(_comment_)。
1. 如果 _sourceMapURL_ 是一个字符串,则返回 _sourceMapURL_。
1. 将 _position_ 设置为 _lineLength_。
1. 否则:
1. 返回 *null*。
1. 否则,如果 _first_ 是 ECMAScript |WhiteSpace|,则:
1. 将 _position_ 设置为 _position_ + 1。
1. 否则:
1. 返回 *null*。
1. 返回 *null*。
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS. It performs the following steps when called:
1. 令 _pattern_ 为 RegExpCreate(*"^[@#]\\s\*sourceMappingURL=(\\S\*?)\\s\*$"*, *""*)。
1. 令 _match_ 为 RegExpExec(_pattern_, _comment_)。
1. 如果 _match_ 不是 *null*,则返回 Get(_match_, *"1"*)。
1. 返回 ~none~。
//@,然而这与 Internet Explorer 的条件编译冲突,因此改为 //#。源映射生成器应只发出 //#,而源映射消费者应接受 //@ 和 //# 两者。
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS.
从 CSS 中提取/* ... */ 风格的注释。
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS.
1. 令 _module_ 为 module_decode(_bytes_)。
1. 如果 _module_ 是 WebAssembly error,则返回 *null*。
1. 对 _module_ 的每个 custom section _customSection_,执行
1. 令 _name_ 为 _customSection_ 的 `name`。
1. 如果 CodePointsToString(_name_) 是 *"sourceMappingURL"*,则
1. 令 _value_ 为 _customSection_ 的 `bytes`。
1. 返回 CodePointsToString(_value_)。
1. 返回 *null*。
由于 WebAssembly 不是文本格式且不支持注释,因此它支持单一的无歧义提取方法。sourceMappingURL 名称的自定义节是无效的。
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS. It performs the following steps when called:
1. 令 _promiseCapability_ 为 NewPromiseCapability(%Promise%)。
1. 令 _request_ 为一个新的 request,其 request URL 为 _url_。
1. 令 _processResponseConsumeBody_ 为一个新的 Abstract Closure,其参数为 (_response_, _bodyBytes_),捕获 _promiseCapability_ 和 _url_,并在被调用时执行以下步骤:
1. 如果 _bodyBytes_ 是 *null* 或 ~failure~,则
1. 执行 Call(_promiseCapability_.[[Reject]], *undefined*, « 新的 *TypeError* »)。
1. 返回。
1. 如果 _url_ 的 scheme 是 HTTP(S) scheme,且字节序列 \``)]}'`\` 是 _bodyBytes_ 的 byte-sequence-prefix,则
1. 重复,当 _bodyBytes_ 的 byte-sequence-length ≠ 0 且 _bodyBytes_[0] 不是 HTTP newline byte 时,
1. 从 _bodyBytes_ 中移除第 0 个元素。
1. 令 _bodyString_ 为 UTF-8 decode of _bodyBytes_ 的 Completion。
1. IfAbruptRejectPromise(_bodyString_, _promiseCapability_)。
1. 令 _jsonValue_ 为 Completion(ParseJSON(_bodyString_))。
1. IfAbruptRejectPromise(_jsonValue_, _promiseCapability_)。
1. 执行 Call(_promiseCapability_.[[Resolve]], *undefined*, « _jsonValue_ »)。
1. 使用 processResponseConsumeBody 设为 _processResponseConsumeBody_ 来执行 fetch _request_。
1. 返回 _promiseCapability_.[[Promise]]。
出于历史原因,当通过 HTTP(S) 交付源映射时,服务器可以在源映射前置一行以字符串 )]}' 开头的内容。
)]}'garbage here
{"version": 3, ...}
会被解释为
{"version": 3, ...}
解码源映射后,源映射消费者可以使用所得的
GetOriginalPositions 操作可以用于查询
The abstract operation UNKNOWN takes UNPARSEABLE ARGUMENTS. It performs the following steps when called:
1. 令 _mappings_ 为 _sourceMapRecord_.[[Mappings]]。
1. 令 _last_ 为 *null*。
1. 令 _originalPositions_ 为一个新的空 List。
1. 对 _mappings_ 的每个元素 _mapping_,按反向 List 顺序执行
1. 如果 _last_ 是 *null*,则
1. 如果执行 ComparePositions(_mapping_.[[GeneratedPosition]], _generatedPosition_) 的结果是 ~lesser~ 或 ~equal~,则
1. 将 _last_ 设为 _mapping_。
1. 如果 _last_ 不是 *null*,则
1. 对 _mappings_ 的每个元素 _mapping_,执行
1. 如果执行 ComparePositions(_last_.[[GeneratedPosition]], _mapping_.[[GeneratedPosition]]) 的结果是 ~equal~,则
1. 将 _mapping_.[[OriginalPosition]] 追加到 _originalPositions_。
1. 返回 _originalPositions_。
在处理源映射或生成源映射时,应遵循以下约定。
通常,源映射将具有与生成文件相同的名称,但带有 .map 扩展名。例如,对于 page.js,会生成名为 page.js.map 的源映射。
对于将源映射与 eval'd 代码一起使用,有一个应被支持的现有约定,其形式如下:
//# sourceURL=foo.js
不了解源语言的堆栈跟踪映射不在本文档
工具从某些 DSL(模板)生成源,或编译 TypeScript → JavaScript → 压缩 JavaScript,从而在最终源映射创建之前产生多次转换,这种情况正变得越来越常见。这个问题可以用两种方式之一处理。简单但有损的方式是为了调试目的忽略过程中的中间步骤,来自转换的源位置信息要么被忽略(中间转换被视为“
然而,尚不清楚“source map reference”在 JavaScript 以外的任何内容中是什么样子。更具体地说,在不支持 JavaScript 风格单行注释的语言中,源映射引用是什么样子。
本节
本规范在 GitHub 上以名为 Ecmarkup 的纯文本源格式编写。Ecmarkup 是一种 HTML 和 Markdown 方言,它提供了一个框架和工具集,用于以纯文本编写 ECMAScript 规范,并将规范处理为符合本文档编辑约定的功能完整的 HTML 渲染。Ecmarkup 构建在许多其他格式和技术之上并与其集成,包括用于定义语法的 Grammarkdown,以及用于编写算法步骤的 Ecmarkdown。本规范的 PDF 渲染是通过将 HTML 渲染打印为 PDF 产生的。
本规范第一版使用 Bikeshed 编写,这是一种基于 HTML 和 Markdown 的不同纯文本源格式。
本文档的标准化前版本使用 Google Docs 编写。
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
© 2026 Ecma International
By obtaining and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions.
This document may be copied, published and distributed to others, and certain derivative works of it may be prepared, copied, published, and distributed, in whole or in part, provided that the above copyright notice and this Copyright License and Disclaimer are included on all such copies and derivative works. The only derivative works that are permissible under this Copyright License and Disclaimer are:
(i) works which incorporate all or portion of this document for the purpose of providing commentary or explanation (such as an annotated version of the document),
(ii) works which incorporate all or portion of this document for the purpose of incorporating features that provide accessibility,
(iii) translations of this document into languages other than English and into different formats and
(iv) works by making use of this specification in standard conformant products by implementing (e.g. by copy and paste wholly or partly) the functionality therein.
However, the content of this document itself may not be modified in any way, including by removing the copyright notice or references to Ecma International, except as required to translate it into languages other than English or into a different format.
The official version of an Ecma International document is the English language version on the Ecma International website. In the event of discrepancies between a translated version and the official version, the official version shall govern.
The limited permissions granted above are perpetual and will not be revoked by Ecma International or its successors or assigns.
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.
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:
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.