Draft ECMA-426 / May 28, 2026 Source map format specification
简介
本 Ecma 标准定义了源映射格式,该格式用于将转译后的源代码映射回原始源 。
源映射格式具有以下目标:
支持源代码级调试,允许双向映射
支持服务器端堆栈跟踪反混淆
原始源 映射格式(v1)由 Joseph Schorr 创建,供 Closure Inspector 使用,以实现优化后的 JavaScript 代码的源代码级调试(尽管该格式本身与语言无关)。然而,随着使用源映射的项目规模扩大,该格式的冗长性开始成为问题。v2 格式(Source Map Revision 2 Proposal )通过牺牲一些简单性和灵活性来减小源映射的总体大小。即使在 v2 版本格式所作更改之后,源映射文件大小仍限制了其有用性。v3 格式基于 Pavel Podivilov (Google) 提出的建议。
源映射格式不再具有版本号,而是被硬编码为始终为 "3"。
在 2023-2024 年,源映射格式被发展为更精确的 Ecma 标准,并得到了许多人的重要贡献。对源映射格式的进一步迭代预计将来自 TC39-TG4。
Asumu Takikawa, Nicolò Ribaudo, Jon Kuperman
ECMA-426,第 1st 版,项目编辑
1 范围
本标准定义了源映射格式,该格式由不同类型的开发者工具使用,用于改善编译到 JavaScript、WebAssembly 和 CSS 的代码的调试体验。
2 符合性
符合要求的源映射文档是一个 JSON 文档,它符合本规范中详述的结构。
符合要求的源映射生成器应该生成符合要求的源映射文档,并且这些文档可以由本规范中的算法解码,而不报告任何错误(即使是被规定为可选的错误)。
符合要求的源映射消费者应该实现本规范中指定的用于获取(在适用情况下)和解码源映射文档的算法。在规范指出算法可以可选地报告错误 的情况下,符合要求的消费者被允许忽略错误,或在不终止的情况下报告错误。
3 引用
以下文档以这样的方式在正文中被引用:其部分或全部内容构成本文档的要求。对于有日期的引用,仅适用所引用的版本。对于无日期的引用,适用被引用文档的最新版本(包括任何修订)。
3.1 规范性引用
ECMA-262,ECMAScript® 语言规范 。
https://tc39.es/ecma262/
ECMA-404,JSON 数据交换格式 。
https://www.ecma-international.org/publications-and-standards/standards/ecma-404/
3.2 资料性引用
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 Fetch 。
https://fetch.spec.whatwg.org/
WHATWG Infra 。
https://infra.spec.whatwg.org/
WHATWG URL 。
https://url.spec.whatwg.org/
4 记号约定
本规范遵循 ECMA-262(记号约定) 中定义的相同记号约定,并带有本节中定义的扩展。
4.1 算法约定
4.1.1 隐式完成
本规范中声明的所有抽象操作都被隐式假定为要么返回一个包含算法声明返回类型的正常完成,要么返回一个抛出完成。例如,声明为如下形式的抽象操作
4.1.1.1 GetTheAnswer ( input )
The abstract operation GetTheAnswer takes argument input (整数) and returns 整数.
等价于:
4.1.1.2 GetTheAnswer2 ( input )
The abstract operation GetTheAnswer2 takes argument input (整数) and returns 包含整数的正常完成或抛出完成.
所有对返回完成记录的抽象操作的调用都被隐式假定为由 ECMA-262 的 ? 完成记录解包简写 包裹,除非它们由显式的 Completion 调用包裹。例如:
令 result 为 GetTheAnswer (value )。 令 second 为 Completion (GetTheAnswer (value ))。
等价于:
令 result 为 ? GetTheAnswer (value )。 令 second 为 Completion (GetTheAnswer (value ))。
4.1.2 可选错误
每当算法要可选地报告错误 时,实现可以选择以下行为之一:
实现可以针对不同的可选错误选择不同的行为。
4.2 语法记号
本规范遵循 ECMA-262(语法记号) 中定义的相同语法记号约定,并带有以下注意事项:
本规范中定义的语法的终结符号是单个码点。这类似于 ECMA-262 的词法语法 ,而不是 ECMA-262 的句法语法 。
本规范不使用语法参数 或前瞻限制 ,以减少语法定义的复杂性。
5 术语和定义
就本文档而言,适用以下术语和定义。
生成代码
由编译器或转译器生成的代码。
原始源
尚未经过编译器或转译器处理的源代码。
源映射 URL
引用从生成代码 到源映射的位置的 URL 。
列
生成代码 的一行中的从零开始的索引偏移;对于 JavaScript 和 CSS 源映射按 UTF-16 码元计算,对于 WebAssembly 源映射按二进制内容(表示为单行)中的字节索引计算。
Note 这意味着 "A"(LATIN CAPITAL LETTER A)计为 1 个码元,而 "🔥"(FIRE)计为 2 个码元。其他内容类型的源映射可能与此不同。
6 base64 VLQ
base64 VLQ 是一种以 base64 编码的可变长度数量 ,其中最高有效位(第 6 位)用作继续位,并且“数字”按最低有效位优先编码到字符串中,同时第一个数字的最低有效位用作符号位。
Note 1 base64 VLQ 编码可表示的值被限制为 32 位数量,直到出现更大值的用例。这意味着超过 32 位的值是无效的,实现可以拒绝它们。符号位计入该限制,但继续位不计入。
Note 2
字符串 "iB" 表示一个具有两个数字的 base64 VLQ。第一个数字 "i" 编码位模式 0b100010,其继续位为 1(VLQ 继续),符号位为 0(非负),值位为 0b0001。第二个数字 B 编码位模式 0b000001,其继续位为 0,没有符号位,值位为 0b00001。此 VLQ 字符串的解码结果是数字 17。
Note 3
字符串 "V" 表示一个具有一个数字的 base64 VLQ。数字 "V" 编码位模式 0b010101,其继续位为 0(不继续),符号位为 1(负),值位为 0b1010。此 VLQ 字符串的解码结果是数字 -10。
base64 VLQ 遵循以下词法语法:
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 整数. It is defined piecewise over the following productions:
Vlq :: VlqDigitList
令 unsigned 为 VlqDigitList 的 VLQUnsignedValue 。 如果 unsigned modulo 2 = 1,则令 sign 为 -1。 否则,令 sign 为 1。 令 value 为 floor (unsigned / 2)。 如果 value 是 0 且 sign 是 -1,则返回 -231 。 如果 value ≥ 231 ,则抛出错误。 返回 sign × value 。
Note
6.2 VLQUnsignedValue
The syntax-directed operation VLQUnsignedValue takes no arguments and returns 非负整数. It is defined piecewise over the following productions:
Vlq :: VlqDigitList
令 value 为 VlqDigitList 的 VLQUnsignedValue 。 如果 value ≥ 232 ,则抛出错误。 返回 value 。
VlqDigitList ::
ContinuationDigit
VlqDigitList
令 left 为 ContinuationDigit 的 VLQUnsignedValue 。 令 right 为 VlqDigitList 的 VLQUnsignedValue 。 返回 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
令 digit 为此产生式匹配的字符。 令 value 为根据 IETF RFC 4648 定义的 base64 编码,与 digit 对应的整数。 断言:value < 32。 返回 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
+
/
令 digit 为此产生式匹配的字符。 令 value 为根据 IETF RFC 4648 定义的 base64 编码,与 digit 对应的整数。 断言:32 ≤ value < 64。 返回 value - 32。
7 JSON 值实用工具
虽然本规范的算法是在 ECMA-262 内部机制之上定义的,但它旨在易于由非 JavaScript 平台实现。本节包含用于处理 JSON 值 的实用工具,从文档其余部分中抽象掉 ECMA-262 细节。
JSON 值 要么是 JSON 对象 、JSON 数组 、String 、Number 、Boolean ,要么是 null 。
JSON 对象 是满足其每个属性均符合以下条件的 Object:
是数据属性,
具有 String 键,
具有 JSON 值 值。
JSON 数组 是满足以下条件的 JSON 对象 :
它具有一个键为 "length" 且值为 Number 的属性,
其所有其他属性的键都是整数索引。
7.1 ParseJSON ( string )
The abstract operation ParseJSON takes argument string (String) and returns JSON 值 . It performs the following steps when called:
令 result 为 Call (%JSON.parse% , null , « string »)。 断言:result 是 JSON 值 。 返回 result 。
Editor's Note
此抽象操作正在由 ECMA-262 本身暴露,见
tc39/ecma262#3540 。
7.2 JSONObjectGet ( object , key )
The abstract operation JSONObjectGet takes arguments object (JSON 对象 ) and key (String) and returns JSON 值 或 missing . It performs the following steps when called:
如果 object 没有键为 key 的自有属性,则返回 missing 。 令 prop 为 object 的键为 key 的自有属性。 返回 prop 的 [[Value]] 特性。
7.3 JSONArrayIterate ( array )
The abstract operation JSONArrayIterate takes argument array (JSON 数组 ) and returns JSON 值 的 List . It performs the following steps when called:
令 length 为 JSONObjectGet (array , "length" )。 断言:length 是非负整数 Number。 令 list 为一个新的空 List 。 令 i 为 0。 重复,当 i < ℝ (length ) 时,令 value 为 JSONObjectGet (array , ToString (𝔽 (i )))。 断言:value 不是 missing 。 将 value 追加到 list 。 将 i 设为 i + 1。 返回 list 。
7.4 StringSplit ( string , separators )
The abstract operation StringSplit takes arguments string (String) and separators (非空 Strings 的 List ) and returns Strings 的 List . It performs the following steps when called:
令 parts 为一个新的空 List 。 令 strLen 为 string 的长度。 令 lastStart 为 0。 令 i 为 0。 重复,当 i < strLen 时,令 matched 为 false 。 对于 separators 的每个 String sep ,执行令 sepLen 为 sep 的长度。 令 candidate 为 string 从 i 到 min (i + sepLen , strLen ) 的子字符串。 如果 candidate = sep 且 matched 是 false ,则令 chunk 为 string 从 lastStart 到 i 的子字符串。 将 chunk 追加到 parts 。 将 lastStart 设为 i + sepLen 。 将 i 设为 i + sepLen 。 将 matched 设为 true 。 如果 matched 是 false ,则将 i 设为 i + 1。 令 chunk 为 string 从 lastStart 到 strLen 的子字符串。 将 chunk 追加到 parts 。 返回 parts 。
8 位置类型
8.1 Position Record
Position Record 是由非负行号和非负列 号组成的元组:
Table 1: Position Record 字段
字段名
值类型
[[Line]]
非负整数 Number
[[Column]]
非负整数 Number
8.2 Original Position Record
Original Position Record 是由 Decoded Source Record 、非负行号和非负列 号组成的元组。它类似于 Position Record ,但描述具体原始源 文件中的源位置。
Table 2: Original Position Record 字段
8.3 ComparePositions ( first , second )
The abstract operation ComparePositions takes arguments first (Position Record 或 Original Position Record ) and second (Position Record 或 Original Position Record ) and returns lesser 、equal 或 greater . It performs the following steps when called:
如果 first .[[Line]] < second .[[Line]] ,则返回 lesser 。 如果 first .[[Line]] > second .[[Line]] ,则返回 greater 。 断言:first .[[Line]] 等于 second .[[Line]] 。 如果 first .[[Column]] < second .[[Column]] ,则返回 lesser 。 如果 first .[[Column]] > second .[[Column]] ,则返回 greater 。 返回 equal 。
9 源映射格式
源映射是一个 JSON 文档,包含具有以下结构的顶层 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 字段 是此源映射关联的生成代码 的可选名称。它是否可以是 URL 、相对路径名或仅是基本名称并未指定。源映射生成器可以根据其使用上下文选择适当的解释。
sourceRoot 字段 是一个可选的源根字符串,用于在服务器上重新定位源文件,或移除 sources 条目中的重复值。此值会被前置到 sources 字段 中的各个条目。
sources 字段 是 mappings 字段 使用的原始源 列 表。每个条目要么是作为(可能相对的)URL 的字符串,要么在源名称未知时为 null 。
sourcesContent 字段 是源内容(即原始源 )字符串的可选列 表,用于源无法被托管时。这些内容按 sources 字段 中的相同顺序列 出。如果某些原始源 应该按名称获取,则条目可以为 null 。
names 字段 是一个可选的符号名称列 表,可以由 mappings 字段 使用。
mappings 字段 是包含编码映射数据的字符串(参见 9.2 节)。
ignoreList 字段 是应被视为第三方代码的文件索引的可选列 表,例如框架代码或打包器生成代码 。这允许开发者工具避免显示或单步进入开发者很可能不想看到的代码,而无需开发者预先配置。它引用 sources 字段 ,并列 出源映射中所有已知第三方源的索引。如果不存在 ignoreList,某些浏览器也可以使用已弃用的 x_google_ignoreList 字段。
9.1 解码源映射
Decoded Source Map Record 具有以下字段:
Table 3: Decoded Source Map Records 的字段
Decoded Source Record 具有以下字段:
Table 4: Decoded Source Records 的字段
字段名
值类型
[[URL]]
URL 或 null
[[Content]]
String 或 null
[[Ignored]]
Boolean
9.1.1 ParseSourceMap ( string , baseURL )
The abstract operation ParseSourceMap takes arguments string (String) and baseURL (URL ) and returns Decoded Source Map Record . It performs the following steps when called:
令 json 为 ParseJSON (string )。 如果 json 不是 JSON 对象 ,则抛出错误。 如果 JSONObjectGet (json , "sections" ) 不是 missing ,则返回 DecodeIndexSourceMap (json , baseURL )。 返回 DecodeSourceMap (json , baseURL )。
9.1.2 DecodeSourceMap ( json , baseURL )
The abstract operation DecodeSourceMap takes arguments json (JSON 对象 ) and baseURL (URL ) and returns Decoded Source Map Record . It performs the following steps when called:
如果 JSONObjectGet (json , "version" ) 不是 3 𝔽 ,则可选地报告错误 。 令 mappingsField 为 JSONObjectGet (json , "mappings" )。 如果 mappingsField 不是 String,则抛出错误。 如果 JSONObjectGet (json , "sources" ) 不是 JSON 数组 ,则抛出错误。 令 fileField 为 GetOptionalString (json , "file" )。 令 sourceRootField 为 GetOptionalString (json , "sourceRoot" )。 令 sourcesField 为 GetOptionalListOfOptionalStrings (json , "sources" )。 令 sourcesContentField 为 GetOptionalListOfOptionalStrings (json , "sourcesContent" )。 令 ignoreListField 为 GetOptionalListOfArrayIndexes (json , "ignoreList" )。 令 sources 为 DecodeSourceMapSources (baseURL , sourceRootField , sourcesField , sourcesContentField , ignoreListField )。 令 namesField 为 GetOptionalListOfStrings (json , "names" )。 令 mappings 为 DecodeMappings (mappingsField , namesField , sources )。 按升序对 mappings 排序,其中如果 ComparePositions (a .[[GeneratedPosition]] , b .[[GeneratedPosition]] ) 是 lesser ,则 Decoded Mapping Record a 小于 Decoded Mapping Record b 。 返回 Decoded Source Map Record { [[File]] : fileField , [[Sources]] : sources , [[Mappings]] : mappings }。
9.1.2.1 GetOptionalString ( object , key )
The abstract operation GetOptionalString takes arguments object (JSON 对象 ) and key (String) and returns String 或 null . It performs the following steps when called:
令 value 为 JSONObjectGet (object , key )。 如果 value 是 String,则返回 value 。 如果 value 不是 missing ,则可选地报告错误 。 返回 null 。
9.1.2.2 GetOptionalListOfStrings ( object , key )
The abstract operation GetOptionalListOfStrings takes arguments object (JSON 对象 ) and key (String) and returns Strings 的 List . It performs the following steps when called:
令 list 为一个新的空 List 。 令 values 为 JSONObjectGet (object , key )。 如果 values 是 missing ,则返回 list 。 如果 values 不是 JSON 数组 ,则可选地报告错误 。返回 list 。 对于 JSONArrayIterate (values ) 的每个元素 item ,执行如果 item 是 String,则将 item 追加到 list 。 否则,可选地报告错误 。将 "" 追加到 list 。 返回 list 。
9.1.2.3 GetOptionalListOfOptionalStrings ( object , key )
The abstract operation GetOptionalListOfOptionalStrings takes arguments object (JSON 对象 ) and key (String) and returns Strings 或 null 的 List . It performs the following steps when called:
令 list 为一个新的空 List 。 令 values 为 JSONObjectGet (object , key )。 如果 values 是 missing ,则返回 list 。 如果 values 不是 JSON 数组 ,则可选地报告错误 。返回 list 。 对于 JSONArrayIterate (values ) 的每个元素 item ,执行如果 item 是 String,则将 item 追加到 list 。 否则,如果 item ≠ null ,则可选地报告错误 。 将 null 追加到 list 。 返回 list 。
9.1.2.4 GetOptionalListOfArrayIndexes ( object , key )
The abstract operation GetOptionalListOfArrayIndexes takes arguments object (Object) and key (String) and returns 非负整数的 List . It performs the following steps when called:
令 list 为一个新的空 List 。 令 values 为 JSONObjectGet (object , key )。 如果 values 是 missing ,则返回 list 。 如果 values 不是 JSON 数组 ,则可选地报告错误 。返回 list 。 对于 JSONArrayIterate (values ) 的每个元素 item ,执行如果 item 是整数 Number,且 item ≥ +0 𝔽 ,则将 ℝ (item ) 追加到 list 。 否则,可选地报告错误 。 返回 list 。
9.2 Mappings 结构
mappings 字段 数据按如下方式分解:
表示生成文件中一行的每个组由分号(;)分隔
每个段由逗号(,)分隔
每个段由 1 个、4 个或 5 个可变长度字段组成。
每个段中的字段是:
该段所表示的生成代码 行中的从零开始的起始列 。如果这是第一个段的第一个字段,或跟在新生成行(;)之后的第一个段,则此字段保存整个 base64 VLQ 。否则,此字段包含一个相对于该字段上一次出现的 base64 VLQ 。请注意,这不同于下面的后续字段,因为前一个值会在每个生成行之后重置。
如果存在,则为 sources 列 表中的从零开始的索引。此字段包含一个相对于该字段上一次出现的 base64 VLQ ,除非它是该字段的第一次出现,在这种情况下表示的是完整值。
如果存在,则为原始源 中的从零开始的起始行。此字段包含一个相对于该字段上一次出现的 base64 VLQ ,除非它是该字段的第一次出现,在这种情况下表示的是完整值。如果存在 source 字段,则应存在该字段。
如果存在,则为原始源 中该行的从零开始的起始列 。此字段包含一个相对于该字段上一次出现的 base64 VLQ ,除非它是该字段的第一次出现,在这种情况下表示的是完整值。如果存在 source 字段,则应存在该字段。
如果存在,则为与此段关联的 names 列 表中的从零开始的索引。此字段包含一个相对于该字段上一次出现的 base64 VLQ ,除非它是该字段的第一次出现,在这种情况下表示的是完整值。
Note 1 此编码的目的是减小源映射大小。在使用 Google Calendar 进行的测试中,相对于
Source Map Revision 2 Proposal ,VLQ 编码使源映射减少了 50%。
Note 2 具有一个字段的段旨在表示没有对应
原始源 代码的未映射
生成代码 ,例如由编译器生成的代码。具有四个字段的段表示不存在对应名称的已映射代码。具有五个字段的段表示还具有映射名称的已映射代码。
Note 3 曾考虑使用 file 偏移,但最终拒绝,转而使用行/列 数据,以避免由于平台特定的行尾而与原始内容失去对齐。
Decoded Mapping Record 具有以下字段:
Table 5: Decoded Mapping Records 的字段
9.2.1 Mappings 语法
mappings String 必须遵循以下语法:
MappingsField :
LineList
LineList :
Line
Line
;
LineList
Line :
MappingList opt
MappingList :
Mapping
Mapping
,
MappingList
Mapping :
GeneratedColumn
GeneratedColumn
OriginalSource
OriginalLine
OriginalColumn
Name opt
GeneratedColumn :
Vlq
OriginalSource :
Vlq
OriginalLine :
Vlq
OriginalColumn :
Vlq
Name :
Vlq
Decode Mapping State Record 具有以下字段:
Table 6: Decode Mapping State Records 的字段
字段名
值类型
[[GeneratedLine]]
非负整数
[[GeneratedColumn]]
非负整数
[[SourceIndex]]
非负整数
[[OriginalLine]]
非负整数
[[OriginalColumn]]
非负整数
[[NameIndex]]
非负整数
9.2.1.1 DecodeMappingsField
The syntax-directed operation DecodeMappingsField takes arguments state (Decode Mapping State Record ), mappings (Decoded Mapping Records 的 List ), names (Strings 的 List ), and sources (Decoded Source Records 的 List ). It is defined piecewise over the following productions:
LineList :
Line
;
LineList
使用参数 state 、mappings 、names 和 sources ,执行 Line 的 DecodeMappingsField 。 将 state .[[GeneratedLine]] 设为 state .[[GeneratedLine]] + 1。 将 state .[[GeneratedColumn]] 设为 0。 使用参数 state 、mappings 、names 和 sources ,执行 LineList 的 DecodeMappingsField 。
Line : [empty]
返回。
MappingList :
Mapping
,
MappingList
使用参数 state 、mappings 、names 和 sources ,执行 Mapping 的 DecodeMappingsField 。 使用参数 state 、mappings 、names 和 sources ,执行 MappingList 的 DecodeMappingsField 。
Mapping :
GeneratedColumn
使用参数 state 、mappings 、names 和 sources ,执行 GeneratedColumn 的 DecodeMappingsField 。 如果 state .[[GeneratedColumn]] < 0,则可选地报告错误 。返回。 令 position 为新的 Position Record { [[Line]] : state .[[GeneratedLine]] , [[Column]] : state .[[GeneratedColumn]] }。 令 decodedMapping 为新的 DecodedMappingRecord { [[GeneratedPosition]] : position , [[OriginalPosition]] : null , [[Name]] : null }。 将 decodedMapping 追加到 mappings 。
Mapping :
GeneratedColumn
OriginalSource
OriginalLine
OriginalColumn
Name opt
使用参数 state 、mappings 、names 和 sources ,执行 GeneratedColumn 的 DecodeMappingsField 。 如果 state .[[GeneratedColumn]] < 0,则可选地报告错误 。返回。 令 generatedPosition 为新的 Position Record { [[Line]] : state .[[GeneratedLine]] , [[Column]] : state .[[GeneratedColumn]] }。 使用参数 state 、mappings 、names 和 sources ,执行 OriginalSource 的 DecodeMappingsField 。 使用参数 state 、mappings 、names 和 sources ,执行 OriginalLine 的 DecodeMappingsField 。 使用参数 state 、mappings 、names 和 sources ,执行 OriginalColumn 的 DecodeMappingsField 。 如果 state .[[SourceIndex]] < 0,或 state .[[SourceIndex]] ≥ sources 的元素数量,或 state .[[OriginalLine]] < 0,或 state .[[OriginalColumn]] < 0,则可选地报告错误 。令 originalPosition 为 null 。 否则,令 originalPosition 为新的 Original Position Record { [[Source]] : sources [state .[[SourceIndex]] ], [[Line]] : state .[[OriginalLine]] , [[Column]] : state .[[OriginalColumn]] }。 令 name 为 null 。 如果 Name 存在,则使用参数 state 、mappings 、names 和 sources ,执行 Name 的 DecodeMappingsField 。 如果 state .[[NameIndex]] < 0,或 state .[[NameIndex]] ≥ names 的元素数量,则可选地报告错误 。 否则,将 name 设为 names [state .[[NameIndex]] ]。 令 decodedMapping 为新的 DecodedMappingRecord { [[GeneratedPosition]] : generatedPosition , [[OriginalPosition]] : originalPosition , [[Name]] : name }。 将 decodedMapping 追加到 mappings 。
GeneratedColumn :
Vlq
令 relativeColumn 为 Vlq 的 VLQSignedValue 。 将 state .[[GeneratedColumn]] 设为 state .[[GeneratedColumn]] + relativeColumn 。
OriginalSource :
Vlq
令 relativeSourceIndex 为 Vlq 的 VLQSignedValue 。 将 state .[[SourceIndex]] 设为 state .[[SourceIndex]] + relativeSourceIndex 。
OriginalLine :
Vlq
令 relativeLine 为 Vlq 的 VLQSignedValue 。 将 state .[[OriginalLine]] 设为 state .[[OriginalLine]] + relativeLine 。
OriginalColumn :
Vlq
令 relativeColumn 为 Vlq 的 VLQSignedValue 。 将 state .[[OriginalColumn]] 设为 state .[[OriginalColumn]] + relativeColumn 。
Name :
Vlq
令 relativeName 为 Vlq 的 VLQSignedValue 。 将 state .[[NameIndex]] 设为 state .[[NameIndex]] + relativeName 。
9.2.2 DecodeMappings ( rawMappings , names , sources )
The abstract operation DecodeMappings takes arguments rawMappings (String), names (Strings 的 List ), and sources (Decoded Source Records 的 List ) and returns Decoded Mapping Record 的 List . It performs the following steps when called:
令 mappings 为一个新的空 List 。 令 mappingsNode 为使用 MappingsField 作为目标符号解析 rawMappings 时得到的根 Parse Node 。 如果解析失败,则可选地报告错误 。返回 mappings 。 令 state 为一个新的 Decode Mapping State Record ,其所有字段均设为 0。 使用参数 state 、mappings 、names 和 sources ,执行 mappingsNode 的 DecodeMappingsField 。 返回 mappings 。
9.2.3 生成的 JavaScript 代码的映射
可以具有映射 条目的生成代码 位置,是按照 ECMAScript 词法语法 中的输入元素 来定义的。映射条目应指向:
9.2.4 生成的 JavaScript 代码的名称
如果满足以下条件,源映射生成器应该为 JavaScript token 创建一个具有 [[Name]] 字段的映射 条目:
原始源 语言构造在语义上映射到生成的 JavaScript 代码。
原始源 语言构造具有名称。
那么该映射 条目的 [[Name]] 应该是原始源 语言构造的名称。具有非空 [[Name]] 的映射 称为命名映射 。
Note 1
缩小器重命名函数和变量,或从立即调用函数表达式中移除函数名称。
以下枚举列 出了 ECMAScript 句法语法 的产生式,以及源映射生成器应该为其发出命名映射的相应 token 或非终结符(产生式右侧)。为此类 token 创建的映射 条目应遵循 9.2.3 节。
该枚举应该被理解为“最低要求”。一般而言,源映射生成器可以自由发出任何额外的命名映射。
Note 2
该枚举还
列 出了生成器“可以”发出命名映射的 token,以及它们“应该”发出命名映射的 token。这些反映了现有工具发出或期望命名映射的现实情况。重复的命名映射成本相对较低:names 的索引是相对于彼此编码的,因此到同一名称的后续映射会编码为 0(
A)。
9.3 解析源
如果在前置 sourceRoot 之后 sources 不是绝对 URL ,则 sources 会相对于源映射进行解析(类似于解析 HTML 文档中的 script src 属性)。
9.3.1 DecodeSourceMapSources ( baseURL , sourceRoot , sources , sourcesContent , ignoreList )
The abstract operation DecodeSourceMapSources takes arguments baseURL (URL ), sourceRoot (String 或 null ), sources (Strings 或 null 的 List ), sourcesContent (Strings 或 null 的 List ), and ignoreList (非负整数的 List ) and returns Decoded Source Record 的 List . It performs the following steps when called:
令 decodedSources 为一个新的空 List 。 令 sourcesContentCount 为 sourcesContent 中的元素数量。 令 sourceUrlPrefix 为 "" 。 如果 sourceRoot ≠ null ,则如果 sourceRoot 以码点 U+002F (SOLIDUS) 结尾,则将 sourceUrlPrefix 设为 sourceRoot 。 否则,将 sourceUrlPrefix 设为 sourceRoot 和 "/" 的字符串拼接。 令 index 为 0。 重复,当 index < sources 的长度时,令 source 为 sources [index ]。 令 decodedSource 为 Decoded Source Record { [[URL]] : null , [[Content]] : null , [[Ignored]] : false }。 如果 source ≠ null ,则将 source 设为 sourceUrlPrefix 和 source 的字符串拼接。 令 sourceURL 为使用 baseURL 对 source 进行 URL parsing 的结果。 如果 sourceURL 是 failure ,则可选地报告错误 。 否则,将 decodedSource .[[URL]] 设为 sourceURL 。 如果 ignoreList 包含 index ,则将 decodedSource .[[Ignored]] 设为 true 。 如果 sourcesContentCount > index ,则将 decodedSource .[[Content]] 设为 sourcesContent [index ]。 将 decodedSource 追加到 decodedSources 。 将 index 设为 index + 1。 返回 decodedSources 。
Note 支持显示源内容但不支持显示具有相同
URL 且内容不同的多个源的实现,将任意选择与给定
URL 对应的多个内容之一。
9.4 扩展
源映射消费者应忽略任何额外的未识别属性,而不是导致源映射被拒绝,以便可以向此格式添加额外特性而不会破坏现有用户。
10 索引源映射
为支持连接生成代码 和其他常见的后处理,支持源映射的另一种表示形式:
{
"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 和 file 字段 ,但新增了 sections 字段 。
sections 字段 是一个对象数组,其对象具有以下字段:
offset 字段 是一个具有两个字段 line 和 column 的对象,它们表示被引用的源映射所表示的生成代码 中的偏移。
map 字段 是一个嵌入的完整源映射对象。嵌入映射不会继承包含它的索引映射中的任何值。
sections 应按起始位置排序,并且所表示的 sections 不应重叠。
10.1 DecodeIndexSourceMap ( json , baseURL )
The abstract operation DecodeIndexSourceMap takes arguments json (Object) and baseURL (URL ) and returns Decoded Source Map Record . It performs the following steps when called:
令 sectionsField 为 JSONObjectGet (json , "sections" )。 断言:sectionsField 不是 missing 。 如果 sectionsField 不是 JSON 数组 ,则抛出错误。 如果 JSONObjectGet (json , "version" ) 不是 3 𝔽 ,则可选地报告错误 。 令 fileField 为 GetOptionalString (json , "file" )。 令 sourceMap 为 Decoded Source Map Record { [[File]] : fileField , [[Sources]] : « », [[Mappings]] : « » }。 令 previousOffsetPosition 为 null 。 令 previousLastMapping 为 null 。 对于 JSONArrayIterate (sectionsField ) 的每个 JSON 值 section ,执行如果 section 不是 JSON 对象 ,则可选地报告错误 。 否则,令 offset 为 JSONObjectGet (section , "offset" )。 如果 offset 不是 JSON 对象 ,则抛出错误。 令 offsetLine 为 JSONObjectGet (offset , "line" )。 令 offsetColumn 为 JSONObjectGet (offset , "column" )。 如果 offsetLine 不是整数 Number,则可选地报告错误 。将 offsetLine 设为 +0 𝔽 。 如果 offsetColumn 不是整数 Number,则可选地报告错误 。将 offsetColumn 设为 +0 𝔽 。 令 offsetPosition 为新的 Position Record { [[Line]] : offsetLine , [[Column]] : offsetColumn }。 如果 previousOffsetPosition ≠ null ,则如果 ComparePositions (offsetPosition , previousOffsetPosition ) 是 lesser ,则可选地报告错误 。 如果 previousLastMapping ≠ null ,则如果 ComparePositions (offsetPosition , previousLastMapping .[[GeneratedPosition]] ) 是 lesser ,则可选地报告错误 。 注:解码算法的这一部分检查索引源映射的 sections 字段 条目是否有序且不重叠。虽然期望生成器不应生成具有重叠 sections 的索引源映射,但源映射消费者例如可以只检查更简单的条件,即 section 偏移是有序的。 令 mapField 为 JSONObjectGet (section , "map" )。 如果 mapField 不是 JSON 对象 ,则抛出错误。 令 decodedSectionCompletion 为 Completion (DecodeSourceMap (json , baseURL ))。 如果 decodedSectionCompletion 是抛出完成,则可选地报告错误 。 否则,令 decodedSection 为 decodedSectionCompletion .[[Value]] 。 对于 decodedSection .[[Sources]] 的每个 Decoded Source Record additionalSource ,执行如果 sourceMap .[[Sources]] 不包含 additionalSource ,则将 additionalSource 追加到 sourceMap .[[Sources]] 。 令 offsetMappings 为一个新的空 List 。 对于 decodedSection .[[Mappings]] 的每个 Decoded Mapping Record mapping ,执行如果 mapping .[[GeneratedPosition]] .[[Line]] = 0,则将 mapping .[[GeneratedPosition]] .[[Column]] 设为 mapping .[[GeneratedPosition]] .[[Column]] + offsetColumn 。 将 mapping .[[GeneratedPosition]] .[[Line]] 设为 mapping .[[GeneratedPosition]] .[[Line]] + offsetLine 。 将 mapping 追加到 offsetMappings 。 将 sourceMap .[[Mappings]] 设为 sourceMap .[[Mappings]] 和 offsetMappings 的列 表拼接。 将 previousOffsetPosition 设为 offsetPosition 。 如果 offsetMappings 非空,则将 previousLastMapping 设为 offsetMappings 的最后一个元素。 返回 sourceMap 。
Note
实现可以选择表示索引源映射 sections 而不把 mappings 追加在一起,例如通过单独存储每个 section 并执行二分搜索。
11 获取源映射
11.1 将生成代码链接到源映射
虽然源映射格式旨在与语言和平台无关,但为 Web 服务器托管的 JavaScript 这一预期用例定义如何引用它们是有用的。
有两种可能的方法将源映射链接到输出。第一种需要服务器支持以添加 HTTP 标头,第二种需要源中的注释。
源映射通过 WHATWG URL 中定义的 URL 进行链接;特别是,不属于允许出现在 URI 中的字符集的字符应被百分比编码,并且它可以是 data URI。将 data URI 与 sourcesContent 结合使用允许完全自包含的源映射。
HTTP sourcemap 标头优先于源注释,如果两者都存在,则应该使用标头 URL 来解析源映射文件。
无论使用哪种方法获取源映射 URL ,都会使用相同的过程来解析它,过程如下。
当源映射 URL 不是绝对 URL 时,则它相对于生成代码 的源起点 。源起点 由以下情况之一确定:
11.1.2 通过内联注释链接
生成代码 应该包含一个名为 sourceMappingURL 的注释,或根据其语言或格式的等效构造,并且该注释包含源映射的 URL 。本规范定义了该注释对于 JavaScript、CSS 和 WebAssembly 应该是什么样子。其他语言应该遵循类似约定。
对于给定语言,可能有多种检测 sourceMappingURL 注释的方法,以允许不同实现选择对它们来说较不复杂的方法。如果所有提取方法的结果相同,则生成代码 无歧义地链接到源映射 。
如果工具消费一个或多个无歧义地链接到源映射 的源文件,并产生一个链接到源映射的输出文件,则它应当无歧义地 这样做。
Note
以下 JavaScript 代码链接到源映射,但并非无歧义地 这样做:
let a = `
//# sourceMappingURL=foo.js.map
// `
通过解析 从中提取源映射 URL 会得到 foo.js.map,而不通过解析 则会得到 null 。
令 module 为 module_decode (bytes )。 如果 module 是 WebAssembly error ,则返回 null 。 对 module 的每个 custom section customSection ,执行令 name 为 customSection 的 name。 如果 CodePointsToString (name ) 是 "sourceMappingURL" ,则令 value 为 customSection 的 bytes。 返回 CodePointsToString (value )。 返回 null 。
由于 WebAssembly 不是文本格式且不支持注释,因此它支持单一的无歧义提取方法。URL 被编码为 WebAssembly 名称,并放置为自定义节的内容。对于生成 WebAssembly 代码的工具来说,生成两个或更多具有 sourceMappingURL 名称的自定义节是无效的。
11.2 获取源映射
11.2.1 FetchSourceMap ( url )
The abstract operation FetchSourceMap takes argument url (URL ) and returns Promise. It performs the following steps when called:
令 promiseCapability 为 NewPromiseCapability (%Promise% )。 令 request 为一个新的 request ,其 request URL 为 url 。 令 processResponseConsumeBody 为一个新的 Abstract Closure ,其参数为 (response , bodyBytes ),捕获 promiseCapability 和 url ,并在被调用时执行以下步骤:如果 bodyBytes 是 null 或 failure ,则执行 Call (promiseCapability .[[Reject]] , undefined , « 新的 TypeError »)。 返回。 如果 url 的 scheme 是 HTTP(S) scheme ,且字节序列 `)]}'` 是 bodyBytes 的 byte-sequence-prefix ,则重复,当 bodyBytes 的 byte-sequence-length ≠ 0 且 bodyBytes [0] 不是 HTTP newline byte 时,从 bodyBytes 中移除第 0 个元素。 令 bodyString 为 UTF-8 decode of bodyBytes 的 Completion 。 IfAbruptRejectPromise (bodyString , promiseCapability )。令 jsonValue 为 Completion (ParseJSON (bodyString ))。 IfAbruptRejectPromise (jsonValue , promiseCapability )。执行 Call (promiseCapability .[[Resolve]] , undefined , « jsonValue »)。 使用 processResponseConsumeBody 设为 processResponseConsumeBody 来执行 fetch request 。 返回 promiseCapability .[[Promise]] 。
Note
出于历史原因,当通过 HTTP(S) 交付源映射时,服务器可以在源映射前置一行以字符串 )]}' 开头的内容。
)] } 'garbage here
{ "version" : 3 , ...}
会被解释为
{ "version" : 3 , ...}
12 源映射记录上的操作
解码源映射后,源映射消费者可以使用所得的 Decoded Source Map Records 来查找用于调试或其他用例的位置信息。本节描述源映射消费者可能支持的典型操作的行为。
GetOriginalPositions 操作可以用于查询原始源 中与生成代码 中的某个位置对应的位置。例如,这可用于调试器中根据用户鼠标点击从生成代码 导航到原始源 。
12.1 GetOriginalPositions ( sourceMapRecord , generatedPosition )
The abstract operation GetOriginalPositions takes arguments sourceMapRecord (Decoded Source Map Record ) and generatedPosition (Position Record ) and returns Original Position Records 的 List . It performs the following steps when called:
令 mappings 为 sourceMapRecord .[[Mappings]] 。 令 last 为 null 。 令 originalPositions 为一个新的空 List 。 对 mappings 的每个元素 mapping ,按反向 List 顺序执行如果 last 是 null ,则如果执行 ComparePositions (mapping .[[GeneratedPosition]] , generatedPosition ) 的结果是 lesser 或 equal ,则将 last 设为 mapping 。 如果 last 不是 null ,则对 mappings 的每个元素 mapping ,执行如果执行 ComparePositions (last .[[GeneratedPosition]] , mapping .[[GeneratedPosition]] ) 的结果是 equal ,则将 mapping .[[OriginalPosition]] 追加到 originalPositions 。 返回 originalPositions 。
Annex A (informative) 约定
在处理源映射或生成源映射时,应遵循以下约定。
A.1 源映射命名
通常,源映射将具有与生成文件相同的名称,但带有 .map 扩展名。例如,对于 page.js,会生成名为 page.js.map 的源映射。
A.2 将 eval'd 代码链接到命名的生成代码
对于将源映射与 eval'd 代码一起使用,有一个应被支持的现有约定,其形式如下:
它在 Give your eval a name with //@ sourceURL 中描述。
Annex B (informative) 注释
B.1 语言中立的堆栈映射
不了解源语言的堆栈跟踪映射不在本文档涵盖 范围内。
B.2 多级映射
工具从某些 DSL(模板)生成源,或编译 TypeScript → JavaScript → 压缩 JavaScript,从而在最终源映射创建之前产生多次转换,这种情况正变得越来越常见。这个问题可以用两种方式之一处理。简单但有损的方式是为了调试目的忽略过程中的中间步骤,来自转换的源位置信息要么被忽略(中间转换被视为“原始源 ”),要么被贯穿携带(中间转换被隐藏)。更完整的方式是支持多级映射:如果原始源 也有源映射引用,则给予用户也使用它的选择。
然而,尚不清楚“源映射引用”在 JavaScript 以外的任何内容中是什么样子。更具体地说,在不支持 JavaScript 风格单行注释的语言中,源映射引用是什么样子。
Annex C (informative) 其他规范中定义的术语
本节列 出了本文档使用的、由 ECMA-262 以外的外部规范定义的所有术语和算法。
WebAssembly 核心规范 <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) 参考文献
IETF RFC 4648,Base16、Base32 和 Base64 数据编码 ,可访问 <https://datatracker.ietf.org/doc/html/rfc4648 >
ECMA-262,ECMAScript® 语言规范 ,可访问 <https://tc39.es/ecma262/ >
ECMA-404,JSON 数据交换格式 ,可访问 <https://www.ecma-international.org/publications-and-standards/standards/ecma-404/ >
WebAssembly 核心规范 ,可访问 <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/ >
Give your eval a name with //@ sourceURL ,Firebug (2009),可访问 <http://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/ >
Source Map Revision 2 Proposal ,John Lenz (2010),可访问 <https://docs.google.com/document/d/1xi12LrcqjqIHTtZzrzZKmQ3lbTv9mKrN076UB-j3UZQ/ >
可变长度数量 ,Wikipedia,可访问 <https://en.wikipedia.org/wiki/Variable-length_quantity >
Annex E (informative) 版权页说明
本规范在 GitHub 上以名为 Ecmarkup 的纯文本源格式编写。Ecmarkup 是一种 HTML 和 Markdown 方言,它提供了一个框架和工具集,用于以纯文本编写 ECMAScript 规范,并将规范处理为符合本文档编辑约定的功能完整的 HTML 渲染。Ecmarkup 构建在许多其他格式和技术之上并与其集成,包括用于定义语法的 Grammarkdown ,以及用于编写算法步骤的 Ecmarkdown 。本规范的 PDF 渲染是通过将 HTML 渲染打印为 PDF 产生的。
本规范第一版使用 Bikeshed 编写,这是一种基于 HTML 和 Markdown 的不同纯文本源格式。
本文档的标准化前版本使用 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
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.
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:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
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.
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.