ドラフト ECMA-426 / 2025年11月13日

ソースマップ形式仕様

この仕様について

https://tc39.es/ecma426/ の文書は、最も正確かつ最新のソースマップ仕様です。最新の公開スナップショットの内容に加え、次のスナップショットに含まれる変更も反映されています。

この仕様への貢献

この仕様はGitHub上で開発されています。仕様の開発には以下の方法で貢献できます:

この文書の作成方法について詳しくは コロフォン を参照してください。

はじめに

本Ecma規格は、トランスパイルされたソースコードを元のソースへマッピングするためのソースマップ形式を定義します。

ソースマップ形式の目標は以下の通りです:

オリジナルソースマップ形式(v1)は、Closure Inspectorで最適化されたJavaScriptコードのソースレベルのデバッグを可能にするためにJoseph Schorrによって作成されました(この形式自体は言語非依存です)。しかし、ソースマップを利用するプロジェクトの規模が拡大するにつれて、フォーマットの冗長性が問題となり始めました。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 第1版 プロジェクト編集者

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 暗黙の完了

この仕様で宣言されるすべての 抽象操作 は、アルゴリズムで宣言された戻り型を含む、正常完了またはthrow完了を返すものと暗黙的にみなされます。例えば、次のような抽象操作は:

4.1.1.1 GetTheAnswer ( input )

抽象操作GetTheAnswerは引数input整数)を受け取り、整数を返します。

これは以下と同等です:

4.1.1.2 GetTheAnswer2 ( input )

抽象操作GetTheAnswer2は引数input整数)を受け取り、正常完了を含む整数、またはthrow完了のいずれかを返します。

本仕様で完了レコードを返す抽象操作への呼び出しは、明示的にCompletionでラップされていない限り、暗黙的にReturnIfAbruptマクロでラップされるものとします。例:

  1. resultGetTheAnswer(value)を代入する。
  2. secondCompletion(GetTheAnswer(value))を代入する。

は以下と同等です:

  1. resultReturnIfAbrupt(GetTheAnswer(value))を代入する。
  2. secondCompletion(GetTheAnswer(value))を代入する。

4.1.2 オプションエラー

アルゴリズムがオプションでエラーを報告する場合、実装は次のいずれかの挙動が選択できます:

  • アルゴリズムの残りを継続して実行する。
  • (たとえばブラウザコンソールで)ユーザーにエラーを報告し、アルゴリズムの残りを継続して実行する。
  • ThrowCompletionを返す。

実装はオプションエラーごとに異なる挙動を選択できます。

4.2 文法表記

この仕様はECMA-262(文法表記)で定義される文法表記慣習に従い、以下に記す留意点があります:

  • 本仕様で定義される文法の終端記号は個々のコードポイントです。これはECMA-262の字句文法に類似し、ECMA-262の構文文法とは異なります。
  • 本仕様は文法パラメータ先読み制約を使用せず、文法定義の複雑さを低減しています。

5 用語と定義

この文書の目的では、以下の用語と定義が適用されます。

生成コード

コンパイラまたはトランスパイラによって生成されたコード。

オリジナルソース

コンパイラやトランスパイラを通していないソースコード。

ソースマップURL

URL生成コードからソースマップの場所を参照します。

カラム(column)

生成コードの行内で0始まりのインデックスを持つオフセット。JavaScriptとCSSのソースマップについてはUTF-16コード単位として、WebAssemblyソースマップについてはバイナリ内容(1行に表現)でのバイトインデックスとして算出します。

つまり"A"(LATIN CAPITAL LETTER A)は1コード単位、"🔥"(FIRE)は2コード単位で計測されます。他のコンテンツタイプのソースマップではこれと異なる場合があります。

6 base64 VLQ

base64 VLQbase64でエンコードされた可変長数量であり、最上位ビット(6ビット目)が継続ビットとして使われ、"数字"は文字列において下位から順にエンコードされ、最初の数字の最下位ビットが符号ビットとして使われます。

注1
base64 VLQエンコーディングで表現可能な値は、現時点では32ビット数量に制限されています(より大きな値の利用例が提示されるまで)。このため、32ビットを超える値は無効となり、実装はそれらを拒否する場合があります。符号ビットもこの制限に含まれますが、継続ビットは含みません。
注2
文字列"iB"は2つの数字からなるbase64 VLQを表します。最初の数字"i"はビットパターン0b100010をエンコードしており、これは継続ビットが1(VLQは継続)、符号ビットが0(非負)、値ビットが0b0001です。2つ目の数字Bはビットパターン0b000001をエンコードしており、継続ビットが0、符号ビットなし、値ビットが0b00001です。このVLQ文字列のデコード結果は数値17です。
注3
文字列"V"は1つの数字からなる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

構文指示操作VLQSignedValueは引数を取らず、整数を返します。次の生成規則に対して分割定義されます:

Vlq :: VlqDigitList
  1. unsignedに、VLQUnsignedValueVlqDigitList)を代入する。
  2. もしunsigned modulo 2 = 1なら、signは-1とする。
  3. それ以外なら、signは1とする。
  4. valuefloor(unsigned / 2)を代入する。
  5. もしvalueが0かつsignが-1なら、-231を返す。
  6. もしvalueが231以上なら、エラーを投げる。
  7. sign × valueを返す。
ステップ6のチェックは、unsignedVLQUnsignedValueVlqDigitList)の値であり、Vlqの値でないため必要です。

6.2 VLQUnsignedValue

構文指示操作VLQUnsignedValueは引数を取らず非負の整数を返します。次の生成規則に対して分割定義されます:

Vlq :: VlqDigitList
  1. valueに、VLQUnsignedValueVlqDigitList)を代入する。
  2. もしvalueが232以上なら、エラーを投げる。
  3. valueを返す。
VlqDigitList :: ContinuationDigit VlqDigitList
  1. leftに、VLQUnsignedValueContinuationDigit)を代入する。
  2. rightに、VLQUnsignedValueVlqDigitList)を代入する。
  3. 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. この生成規則によりマッチされた文字をdigitとする。
  2. 整数であるdigitに対応する値を、IETF RFC 4648で定義されるbase64エンコーディングに従いvalueとする。
  3. アサートvalue < 32。
  4. 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. この生成規則によりマッチされた文字をdigitとする。
  2. 整数であるdigitに対応する値を、IETF RFC 4648で定義されるbase64エンコーディングに従いvalueとする。
  3. アサート:32 ≤ value < 64。
  4. value - 32を返す。

7 JSON値ユーティリティ

この仕様のアルゴリズムはECMA-262の内部仕様上で定義されていますが、非JavaScriptプラットフォームでも簡単に実装できるよう設計されています。本節では、JSON値を扱うためのユーティリティを提供し、ECMA-262の詳細を抽象化します。

JSON値は、JSONオブジェクトJSON配列文字列数値真偽値、またはnullです。

JSONオブジェクトは、各プロパティについて:

JSON配列は、以下の条件を満たすJSONオブジェクトです:

7.1 ParseJSON ( string )

抽象操作ParseJSONは引数string(文字列)を受け取り、JSON値を返します。処理手順:

  1. resultCall(%JSON.parse%, null, « string » )を代入する。
  2. AssertresultJSON値であること。
  3. resultを返す。
編集者注
この抽象操作はECMA-262自体によって公開される予定です:tc39/ecma262#3540

7.2 JSONObjectGet ( object, key )

抽象操作JSONObjectGetはobjectJSONオブジェクト)とkey(文字列)を受け取り、JSON値またはmissingを返します。指定したkeyに対応する値を返します。手順:

  1. もしobjectkeyの独自プロパティを持たない場合、missingを返す。
  2. propobjectkeyの独自プロパティを代入する。
  3. prop[[Value]]属性を返す。

7.3 JSONArrayIterate ( array )

抽象操作JSONArrayIterateはarrayJSON配列)を受け取り、ListJSON値のリスト)を返します。「For each」による反復用に全ての要素が入ったListを返します。手順:

  1. lengthJSONObjectGet(array, "length")を設定する。
  2. アサートlengthは非負の整数値である。
  3. listに新しい空のListを設定する。
  4. iに0を設定する。
  5. i < (length) の間繰り返す:
    1. valueJSONObjectGet(array, ToString(𝔽(i)))を設定する。
    2. アサートvaluemissingでない。
    3. valuelistに追加する。
    4. ii+1に設定する。
  6. listを返す。

7.4 StringSplit ( string, separators )

抽象操作StringSplitはstring(文字列)、separators(文字列のList)を受け取り、区切り文字のいずれかで分割した部分文字列のListを返します。同時に複数の区切り文字が一致する場合は、separatorsで先に現れるものが優先されます。手順:

  1. partsに新しい空のリストを設定する。
  2. strLenstringの長さを設定する。
  3. lastStartに0を設定する。
  4. iに0を設定する。
  5. i < strLen の間繰り返す:
    1. matchedfalseを設定する。
    2. separatorsの各String sepについて:
      1. sepLensepの長さを設定する。
      2. candidateに、substring(string, i, min(i + sepLen, strLen)) を設定する。
      3. もしcandidatesep かつ matchedfalseなら:
        1. chunksubstring(string, lastStart, i) を設定する。
        2. chunkpartsに追加する。
        3. lastStarti + sepLenを設定する。
        4. ii + sepLenを設定する。
        5. matchedtrueを設定する。
    3. もしmatchedfalseなら、ii + 1を設定する。
  6. chunksubstring(string, lastStart, strLen) を設定する。
  7. chunkpartsに追加する。
  8. partsを返す。

8 位置型

8.1 位置レコード

位置レコードは、非負の行番号と非負のカラム番号からなるタプルです:

表1: 位置レコードのフィールド
フィールド名 値の型
[[Line]] 非負の整数型Number
[[Column]] 非負の整数型Number

8.2 元位置レコード

元位置レコードは、デコードソースレコード、非負の行、非負のカラム番号からなるタプルです。位置レコードに似ていますが、具体的なオリジナルソースファイル上のソース位置を記述します。

表2: 元位置レコードのフィールド
フィールド名 値の型
[[Source]] デコードソースレコード
[[Line]] 非負の整数型Number
[[Column]] 非負の整数型Number

8.3 ComparePositions ( first, second )

抽象操作ComparePositionsはfirst位置レコードまたは元位置レコード)、second(同じ型)を受け取り、lesserequal、またはgreaterを返します。firstsecondより前か同じか後かによってそれぞれ返します。なお、元位置レコード[[Source]]フィールドは無視されます。手順:

  1. もしfirst.[[Line]] < second.[[Line]]であれば、lesserを返す。
  2. もしfirst.[[Line]] > second.[[Line]]であれば、greaterを返す。
  3. アサート: first.[[Line]]second.[[Line]]と等しい。
  4. もしfirst.[[Column]] < second.[[Column]]であれば、lesserを返す。
  5. もしfirst.[[Column]] > second.[[Column]]であれば、greaterを返す。
  6. 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]
}

9.1 ソースマップのデコード

デコード済みソースマップレコードは以下のフィールドを持ちます:

表3: デコード済みソースマップレコードのフィールド
フィールド名 値の型
[[File]] String または null
[[Sources]] Listデコード済みソースレコードの)
[[Mappings]] Listデコード済みマッピングレコードの)

デコード済みソースレコードは以下のフィールドを持ちます:

表4: デコード済みソースレコードのフィールド
フィールド名 値の型
[[URL]] URL または null
[[Content]] String または null
[[Ignored]] Boolean

9.1.1 ParseSourceMap ( string, baseURL )

抽象演算 ParseSourceMap は引数 string(String型)と baseURLURL型)を取り、デコード済みソースマップレコードを返します。呼び出された際に以下の手順を実行します:

  1. jsonParseJSON(string) を代入する。
  2. jsonJSONオブジェクト でなければ、エラーを投げる。
  3. JSONObjectGet(json, "sections") が missing でなければ、
    1. DecodeIndexSourceMap(json, baseURL) を返す。
  4. DecodeSourceMap(json, baseURL) を返す。

9.1.2 DecodeSourceMap ( json, baseURL )

抽象演算 DecodeSourceMap は引数 jsonJSONオブジェクト型)と baseURLURL型)を取り、デコード済みソースマップレコードを返します。呼び出された際に以下の手順を実行します:

  1. JSONObjectGet(json, "version") が 3𝔽 でなければ、(任意で)エラー報告を行う
  2. mappingsFieldJSONObjectGet(json, "mappings") を代入する。
  3. mappingsField String型でなければ、エラーを投げる。
  4. JSONObjectGet(json, "sources") が JSON配列 でなければ、エラーを投げる。
  5. fileFieldGetOptionalString(json, "file") を代入する。
  6. sourceRootFieldGetOptionalString(json, "sourceRoot") を代入する。
  7. sourcesFieldGetOptionalListOfOptionalStrings(json, "sources") を代入する。
  8. sourcesContentFieldGetOptionalListOfOptionalStrings(json, "sourcesContent") を代入する。
  9. ignoreListFieldGetOptionalListOfArrayIndexes(json, "ignoreList") を代入する。
  10. sourcesDecodeSourceMapSources(baseURL, sourceRootField, sourcesField, sourcesContentField, ignoreListField) を代入する。
  11. namesFieldGetOptionalListOfStrings(json, "names") を代入する。
  12. mappingsDecodeMappings(mappingsField, namesField, sources) を代入する。
  13. mappingsを昇順でソートする。デコード済みマッピングレコード aデコード済みマッピングレコード b より小さいのは、ComparePositions(a.[[GeneratedPosition]], b.[[GeneratedPosition]]) が lesser の場合である。
  14. デコード済みソースマップレコード { [[File]]: fileField, [[Sources]]: sources, [[Mappings]]: mappings } を返す。

9.1.2.1 GetOptionalString ( object, key )

抽象演算 GetOptionalString は引数 objectJSONオブジェクト型)と key(String型)を取り、Stringまたはnullを返します。呼び出された際に以下の手順を実行します:

  1. valueJSONObjectGet(object, key) を代入する。
  2. valueString型であれば value を返す。
  3. valuemissing でなければ、(任意で)エラー報告を行う
  4. null を返す。

9.1.2.2 GetOptionalListOfStrings ( object, key )

抽象演算 GetOptionalListOfStrings は引数 objectJSONオブジェクト型)と key(String型)を取り、StringのListを返します。呼び出された際に以下の手順を実行します:

  1. list に新しい空の List を代入する。
  2. valuesJSONObjectGet(object, key) を代入する。
  3. valuesmissing であれば list を返す。
  4. valuesJSON配列 でなければ、
    1. (任意で)エラー報告を行う
    2. list を返す。
  5. JSONArrayIterate(values) の各要素 item について、
    1. itemString型なら
      1. itemlist に追加する。
    2. それ以外なら、
      1. (任意で)エラー報告を行う
      2. ""list に追加する。
  6. list を返す。

9.1.2.3 GetOptionalListOfOptionalStrings ( object, key )

抽象演算 GetOptionalListOfOptionalStrings は引数 objectJSONオブジェクト型)と key(String型)を取り、StringまたはnullListを返します。呼び出された際に以下の手順を実行します:

  1. list に新しい空の List を代入する。
  2. valuesJSONObjectGet(object, key) を代入する。
  3. valuesmissing であれば list を返す。
  4. valuesJSON配列 でなければ、
    1. (任意で)エラー報告を行う
    2. list を返す。
  5. JSONArrayIterate(values) の各要素 item について、
    1. itemString型なら
      1. itemlist に追加する。
    2. それ以外なら、
      1. itemnull なら (任意で)エラー報告を行う
      2. nulllist に追加する。
  6. list を返す。

9.1.2.4 GetOptionalListOfArrayIndexes ( object, key )

抽象演算 GetOptionalListOfArrayIndexes は引数 object(Object型)と key(String型)を取り、非負の整数Listを返します。呼び出された際に以下の手順を実行します:

  1. list に新しい空の List を代入する。
  2. valuesJSONObjectGet(object, key) を代入する。
  3. valuesmissing であれば list を返す。
  4. valuesJSON配列 でなければ、
    1. (任意で)エラー報告を行う
    2. list を返す。
  5. JSONArrayIterate(values) の各要素 item について、
    1. item整数値であり、item+0𝔽 かつ item+0𝔽 なら、
      1. (item) を list に追加する。
    2. それ以外なら、
      1. itemnull なら (任意で)エラー報告を行う
      2. nulllist に追加する。
  6. list を返す。

9.2 マッピングの構造

mappingsフィールドのデータは以下のように分割されます:

  • 生成ファイル内の各行はセミコロン(;)で区切られています。
  • 各セグメントはカンマ(,)で区切られています。
  • 各セグメントは、可変長の1個、4個、または5個のフィールドで構成されます。

各セグメントのフィールドは以下の通りです:

  1. このセグメントが表す生成コード内の行のゼロ始まりカラム。最初のセグメントの最初のフィールド、または新しい生成行(;の後)の最初のセグメントの場合、このフィールドは全体をbase64 VLQで表します。それ以外の場合は、前回のこのフィールドからの相対値としてbase64 VLQ値を保持します。これは以降のフィールドとは異なり、前回値が行ごとにリセットされるため注意。
  2. 存在する場合、sourcesリストへのゼロ始まりのインデックス。通常前回のこのフィールドからの相対値base64 VLQですが、最初の出現時は全体の値で表現されます。
  3. 存在する場合、元のソース内のゼロ始まりの行。通常前回のこのフィールドからの相対値base64 VLQですが、最初の出現時は全体の値で表現されます。sourceフィールドがある場合必須。
  4. 存在する場合、元のソース内の行のゼロ始まりカラム。通常前回のこのフィールドからの相対値base64 VLQですが、最初の出現時は全体の値で表現されます。sourceフィールドがある場合必須。
  5. 存在する場合、このセグメントに紐づくnamesリストのゼロ始まりのインデックス。通常前回のこのフィールドからの相対値base64 VLQですが、最初の出現時は全体の値で表現されます。
注1
この符号化の目的はソースマップサイズの縮小です。VLQ符号化により、Googleカレンダーでのテスト時、Source Map Revision 2 Proposalと比較してソースマップが50%縮小されました。
注2
フィールドが1個だけのセグメントは、対応する元ソースが存在せず、コンパイラ等で生成された生成コードとしてマッピングされていない部分を表します。フィールド4つは対応名が存在しないマッピング済みコード、フィールド5つは対応名もマッピングされているコードです。
注3
fileオフセット値の使用も検討されましたが、プラットフォーム特有の改行による不一致を避けるため行/columnデータによる設計となりました。

デコード済みマッピングレコードは以下のフィールドを持ちます:

表5: デコード済みマッピングレコードのフィールド
フィールド名 値の型
[[GeneratedPosition]] Position Record
[[OriginalPosition]] Original Position Recordまたはnull
[[Name]] Stringまたはnull

9.2.1 マッピングの文法

mappingsの文字列は以下の文法に従う必要があります:

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

デコードマッピング状態レコードは以下のフィールドを持ちます:

表6: デコードマッピング状態レコードのフィールド
フィールド名 値の型
[[GeneratedLine]] 非負の整数
[[GeneratedColumn]] 非負の整数
[[SourceIndex]] 非負の整数
[[OriginalLine]] 非負の整数
[[OriginalColumn]] 非負の整数
[[NameIndex]] 非負の整数

9.2.1.1 DecodeMappingsField

構文指示付き演算DecodeMappingsFieldは、引数stateデコードマッピング状態レコード)、mappingsListデコード済みマッピングレコード))、namesList(String))、sourcesListデコード済みソースレコード))を受け取り、以下の生成規則ごとに定義されます:

LineList : Line ; LineList
  1. DecodeMappingsFieldLineに対し、引数statemappingsnamessourcesで実行する。
  2. state.[[GeneratedLine]]state.[[GeneratedLine]] + 1 に設定する。
  3. state.[[GeneratedColumn]] を 0 に設定する。
  4. DecodeMappingsFieldLineListに対し、引数statemappingsnamessourcesで実行する。
Line : [empty]
  1. return。
MappingList : Mapping , MappingList
  1. DecodeMappingsFieldMappingに対し、引数statemappingsnamessourcesで実行する。
  2. DecodeMappingsFieldMappingListに対し、引数statemappingsnamessourcesで実行する。
Mapping : GeneratedColumn
  1. DecodeMappingsFieldGeneratedColumnに対し、引数statemappingsnamessourcesで実行する。
  2. もしstate.[[GeneratedColumn]]<0なら、
    1. (任意で)エラー報告を行う
    2. return。
  3. positionを新しいPosition Record{[[Line]]: state.[[GeneratedLine]], [[Column]]: state.[[GeneratedColumn]]}とする。
  4. decodedMappingを新しいDecodedMappingRecord{[[GeneratedPosition]]: position, [[OriginalPosition]]: null, [[Name]]: null}とする。
  5. mappingsdecodedMappingを追加する。
Mapping : GeneratedColumn OriginalSource OriginalLine OriginalColumn Nameopt
  1. DecodeMappingsFieldGeneratedColumnに対し、引数statemappingsnamessourcesで実行する。
  2. もしstate.[[GeneratedColumn]]<0なら、
    1. (任意で)エラー報告を行う
    2. return。
  3. generatedPositionを新しいPosition Record{[[Line]]: state.[[GeneratedLine]], [[Column]]: state.[[GeneratedColumn]]}とする。
  4. DecodeMappingsFieldOriginalSourceに対し、引数statemappingsnamessourcesで実行する。
  5. DecodeMappingsFieldOriginalLineに対し、引数statemappingsnamessourcesで実行する。
  6. DecodeMappingsFieldOriginalColumnに対し、引数statemappingsnamessourcesで実行する。
  7. もしstate.[[SourceIndex]]<0またはstate.[[SourceIndex]]sourcesの要素数、またはstate.[[OriginalLine]]<0またはstate.[[OriginalColumn]]<0の場合、
    1. (任意で)エラー報告を行う
    2. originalPositionnullにする。
  8. それ以外の場合は、
    1. originalPositionを新しいOriginal Position Record{[[Source]]: sources[state.[[SourceIndex]]], [[Line]]: state.[[OriginalLine]], [[Column]]: state.[[OriginalColumn]]}とする。
  9. namenullにする。
  10. Nameがあれば、
    1. DecodeMappingsFieldNameに対し、引数statemappingsnamessourcesで実行する。
    2. もしstate.[[NameIndex]]<0またはstate.[[NameIndex]]namesの要素数なら、(任意で)エラー報告を行う
    3. それ以外の場合は、namenames[state.[[NameIndex]]]にする。
  11. decodedMappingを新しいDecodedMappingRecord{[[GeneratedPosition]]: generatedPosition, [[OriginalPosition]]: originalPosition, [[Name]]: name}とする。
  12. mappingsdecodedMappingを追加する。
GeneratedColumn : Vlq
  1. relativeColumnVLQSignedValueVlq)で求める。
  2. state.[[GeneratedColumn]]state.[[GeneratedColumn]]+relativeColumnに設定する。
OriginalSource : Vlq
  1. relativeSourceIndexVLQSignedValueVlq)で求める。
  2. state.[[SourceIndex]]state.[[SourceIndex]]+relativeSourceIndexに設定する。
OriginalLine : Vlq
  1. relativeLineVLQSignedValueVlq)で求める。
  2. state.[[OriginalLine]]state.[[OriginalLine]]+relativeLineに設定する。
OriginalColumn : Vlq
  1. relativeColumnVLQSignedValueVlq)で求める。
  2. state.[[OriginalColumn]]state.[[OriginalColumn]]+relativeColumnに設定する。
Name : Vlq
  1. relativeNameVLQSignedValueVlq)で求める。
  2. state.[[NameIndex]]state.[[NameIndex]]+relativeNameに設定する。

9.2.2 DecodeMappings ( rawMappings, names, sources )

抽象操作DecodeMappingsは、引数rawMappings(String型)、names(StringのList)、sourcesDecoded Source RecordsList)を受け取り、Decoded Mapping RecordListを返します。呼び出すと、以下の手順を実行します:

  1. mappingsを新しい空のListとする。
  2. mappingsNodeを、rawMappingsMappingsFieldgoal symbolとして)で構文解析したときのルートParse Nodeとする。
  3. 構文解析に失敗した場合、
    1. (任意で)エラー報告を行う
    2. mappingsを返す。
  4. stateを、全フィールドが0の新しいDecode Mapping State Recordとする。
  5. DecodeMappingsFieldmappingsNodeに対して引数state, mappings, names, sourcesで実行する。
  6. mappingsを返す。

9.2.3 生成されたJavaScriptコードのマッピング

生成コードの位置でmappingエントリーとなりうるものは、ECMAScript字句文法に則り、入力要素で定義されます。マッピングエントリは次のいずれかを指す必要があります:

  • IdentifierNamePrivateIdentifierPunctuatorDivPunctuatorRightBracePunctuatorNumericLiteralRegularExpressionLiteralで一致したソーステキストの最初のコードポイント。
  • CommentHashbangCommentStringLiteralTemplateTemplateSubstitutionTailWhiteSpaceLineTerminatorで一致したソーステキストのいずれかのコードポイント。

9.2.4 生成JavaScriptコードの名前

ソースマップ生成ツールは、次の場合、JavaScriptトークンについて[[Name]]フィールドを持つmappingエントリを生成するべきです:

  • 元ソースの言語構造が意味的に生成されたJavaScriptコードに対応する。
  • 元ソースの言語構造が名前を持つ。

その場合、mappingエントリの[[Name]]元ソース言語構造の名前となります。非nullな[[Name]]を持つmapping名前付きマッピングと呼ばれます。

注1
ミニファイアによる関数名や変数名の変更、即時実行関数式からの関数名の削除などのケース。

以下の列挙は、ECMAScript構文文法の生成規則と、その右辺のトークン・非終端で、ソースマップ生成ツールが名前付きマッピングを出力すべきものです。これらのトークンのために作成されるmappingエントリは、9.2.3に従います。

この列挙は「最低限」として扱います。一般に、ソースマップ生成ツールは追加の名前付きマッピングを自由に生成して構いません。

注2
この列挙には、生成ツールが「may(推奨)」として名前付きマッピングを出力するケースも含まれています。既存ツールが名前付きマッピングを出力・要求する現実を反映しています。重複した名前付きマッピングはほぼコストゼロです:namesへのインデックスは互いに相対で符号化されるので、同一名への連続したマッピングは0(A)として符号化されます。
  • LexicalDeclarationVariableStatementFormalParameterListに含まれるBindingIdentifier

  • FunctionDeclarationFunctionExpressionAsyncFunctionDeclarationAsyncFunctionExpressionGeneratorDeclarationGeneratorExpressionAsyncGeneratorDeclarationAsyncGeneratorExpressionに存在する場合はBindingIdentifier、存在しない場合はFormalParametersの直前の開き括弧(

    ソースマップ生成ツールはBindingIdentifierの有無に関わらず、開き括弧にも名前付きマッピングを出力してもよい。

  • ArrowFunctionまたはAsyncArrowFunctionの場合:

    • ArrowFunctionが単一BindingIdentifierArrowParametersとなる場合またはAsyncArrowFunctionAsyncArrowBindingIdentifierとなる場合の=>トークン。

      注3
      これは(async)アロー関数が単一パラメータかつ括弧で囲まれていないケースを指します。
    • ArrowFunctionまたはAsyncArrowFunctionArrowFormalParametersで生成される場合の開き括弧(

      ソースマップ生成ツールは前のケースとの一貫性のため、=>トークンにも追加で名前付きマッピングを出力しても良い。

  • MethodDefinitionClassElementName(ジェネレータ、asyncメソッド、asyncジェネレータ、アクセサ含む)。MethodDefinition内でClassElementName"constructor"なら[[Name]]は元のクラス名(該当する場合)とする。

    ソースマップ生成ツールは開き括弧(にも追加で名前付きマッピングを出力してもよい。

  • ソースマップ生成ツールはExpression内のIdentifierReferenceに対して名前付きマッピングを出力してもよい。

9.3 ソースの解決

sourceRootを前に付加した後でも、sourcesが絶対URLでない場合は、HTMLドキュメント内のscriptのsrc属性を解決するように、ソースマップを基準に相対的に解決されます。

9.3.1 DecodeSourceMapSources ( baseURL, sourceRoot, sources, sourcesContent, ignoreList )

抽象操作DecodeSourceMapSourcesは、引数baseURLURL型)、sourceRoot(Stringまたはnull)、sources(StringまたはnullList)、sourcesContent(StringまたはnullList)、ignoreList(非負の整数List)を受け取り、Decoded Source Recordを返します。呼び出し時には次の手順を実行します:

  1. decodedSourcesを新しい空のListとする。
  2. sourcesContentCountsourcesContentの要素数とする。
  3. sourceUrlPrefix""とする。
  4. もしsourceRootnullなら、
    1. もしsourceRootがU+002F(SOLIDUS)で終わっている場合、
      1. sourceUrlPrefixsourceRootを設定する。
    2. それ以外の場合、
      1. sourceUrlPrefixsourceRoot"/"文字列連結した値を設定する。
  5. indexを0とする。
  6. index < sourcesの長さの間、繰り返す:
    1. sourcesources[index]とする。
    2. decodedSourceDecoded Source Record{ [[URL]]: null, [[Content]]: null, [[Ignored]]: false }とする。
    3. もしsourcenullなら、
      1. sourcesourceUrlPrefixsource文字列連結した値を設定する。
      2. sourceURLURL解析sourcebaseURLから得る。
      3. もしsourceURLfailureなら(任意で)エラー報告を行う。
      4. そうでなければ、decodedSource.[[URL]]sourceURLを設定する。
    4. もしignoreListindexを含む場合、decodedSource.[[Ignored]]trueを設定する。
    5. もしsourcesContentCount > indexの場合、decodedSource.[[Content]]sourcesContent[index]を設定する。
    6. decodedSourcedecodedSourcesに追加する。
  7. decodedSourcesを返す。
複数の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フィールドは、以下のフィールドを持つオブジェクトの配列です:

sectionsは開始位置でソートされ、各sectionが表す部分は重なってはいけません。

10.1 DecodeIndexSourceMap ( json, baseURL )

抽象演算DecodeIndexSourceMapは、引数json(Object型)とbaseURLURL型)を受け取り、Decoded Source Map Recordを返します。呼び出し時に行う手順は次のとおりです:

  1. sectionsFieldJSONObjectGet(json, "sections")とする。
  2. アサートsectionsFieldmissingではない。
  3. sectionsFieldJSON配列でなければ、エラーを投げる。
  4. JSONObjectGet(json, "version")が3𝔽でなければ、(任意)エラー報告をする。
  5. fileFieldGetOptionalString(json, "file")とする。
  6. sourceMapDecoded Source Map Record{[[File]]: fileField, [[Sources]]: « », [[Mappings]]: « »}とする。
  7. previousOffsetPositionnullとする。
  8. previousLastMappingnullとする。
  9. JSONArrayIterate(sectionsField)の各sectionについて:
    1. sectionJSONオブジェクトでなければ、(任意)エラー報告をする。
    2. そうでなければ:
      1. offsetJSONObjectGet(section, "offset")とする。
      2. offsetJSONオブジェクトでなければ、エラーを投げる。
      3. offsetLineJSONObjectGet(offset, "line")とする。
      4. offsetColumnJSONObjectGet(offset, "column")とする。
      5. offsetLine整数値でなければ、(任意)エラー報告し、offsetLine+0𝔽にする。
      6. offsetColumn整数値でなければ、(任意)エラー報告し、offsetColumn+0𝔽にする。
      7. offsetPositionを新しいPosition Record{[[Line]]: offsetLine, [[Column]]: offsetColumn}とする。
      8. もしpreviousOffsetPositionnullなら、ComparePositions(offsetPosition, previousOffsetPosition)がlesserなら(任意)エラー報告
      9. もしpreviousLastMappingnullなら、ComparePositions(offsetPosition, previousLastMapping.[[GeneratedPosition]])がlesserなら(任意)エラー報告
        ※この部分はインデックスソースマップのsectionsフィールドが順序付きかつ重複しないことをチェックします。実際は順序だけを確認する実装もありえます。
      10. mapFieldJSONObjectGet(section, "map")とする。
      11. mapFieldJSONオブジェクトでなければ、エラーを投げる。
      12. decodedSectionCompletionCompletion(DecodeSourceMap(json, baseURL))とする。
      13. decodedSectionCompletionthrow completionなら(任意)エラー報告
      14. そうでなければ:
        1. decodedSectiondecodedSectionCompletion.[[Value]]とする。
        2. decodedSection.[[Sources]]の各additionalSourceについて:
          1. もしsourceMap.[[Sources]]に含まれていなければ追加する。
        3. offsetMappingsを新しい空のListとする。
        4. decodedSection.[[Mappings]]の各mappingについて:
          1. もしmapping.[[GeneratedPosition]].[[Line]]==0なら、mapping.[[GeneratedPosition]].[[Column]] += offsetColumn
          2. mapping.[[GeneratedPosition]].[[Line]] += offsetLine
          3. mappingoffsetMappingsに追加する。
        5. sourceMap.[[Mappings]]を、リスト連結sourceMap.[[Mappings]]offsetMappingsに設定する。
        6. previousOffsetPositionoffsetPositionにする。
        7. もしoffsetMappingsが空でなければpreviousLastMappingoffsetMappingsの最後の要素にする。
    3. sourceMapを返す。
実装によっては、マッピングを連結せず各sectionを個別に保存しバイナリサーチするなどの方法も選択できます。

11 ソースマップの取得

11.1 生成コードとソースマップのリンク

ソースマップフォーマットは言語非依存・プラットフォーム非依存を目指していますが、WebサーバでホストされるJavaScriptという典型的な利用ケースのため、どのように参照するかを定義すると有用です。

出力にソースマップを紐付ける方法は2つあります。1つめはサーバがHTTPヘッダーを追加する必要があり、2つめはソース内でアノテーションを追加する方法です。

ソースマップはWHATWG URLとしてURL経由でリンクされます。特に、URIに許されていない文字はパーセントエンコードされる必要があり、data URIも利用可能です。data URIとsourcesContentを組み合わせると完全に自己完結したソースマップが実現できます。

HTTP sourcemapヘッダーはソースアノテーションより優先され、双方が存在する場合はヘッダーのURLがソースマップファイルの解決に使われます。

ソースマップURLの取得方法に関わらず、次の手続きで解決します。

ソースマップURLが絶対パスでない場合、生成コードソースオリジンを基準とし、ソースオリジンは以下で判定されます:

  • 生成ソースがscript要素(src属性あり)と関連しておらず、生成コード内に//# sourceURLコメントがある場合、そのコメントをソースオリジンとして扱う。

    従来は//@ sourceURLでしたが、//@ sourceMappingURLと同様に両方許容されますが//#が推奨されます。
  • 生成コードがscript要素に紐付けられていてその要素がsrc属性を持つ場合、script要素のsrc属性がソースオリジンになる。
  • 生成コードがscript要素に紐付けられ、script要素がsrc属性を持たない場合は、ページのオリジンがソースオリジンとなる。
  • 生成コードがeval()関数やnew Function()で文字列として評価される場合は、ページのオリジンがソースオリジンとなる。

11.1.1 HTTPヘッダーによるリンク

ファイルがHTTP(S)でsourcemapヘッダー付きで配信される場合、ヘッダーの値がリンクされるソースマップのURLになります。

sourcemap: <url>
従来の文書改訂ではヘッダー名x-sourcemapを推奨していましたが、現在は非推奨でsourcemapの利用が期待されます。

11.1.2 インラインアノテーションによるリンク

生成コードsourceMappingURLという名のコメントまたは言語/フォーマットに応じた同等の仕組みを含み、そこにソースマップのURLを記載すべきです。この仕様ではJavaScript、CSS、WebAssemblyについてコメントの記述例を示します。他の言語も類似の慣例に従うべきです。

言語ごとにsourceMappingURLコメント検出方法は複数あり、実装ごとに複雑度が低い方法を選べます。すべての抽出方法で同一結果となる場合、生成コード一意的にソースマップへリンクされていると見なします。

ツールが一意的にソースマップへリンクされたソースファイルを1つ以上消費し、出力ファイルでもソースマップへリンクする場合は、一意的でなければなりません。

注1

以下のJavaScriptコードはソースマップへリンクしていますが、一意的ではありません:

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

このコードからソースマップURL構文解析で抽出するとnullとなり、構文解析しない抽出ではfoo.js.mapとなります。

注2

複数のソースマップURL抽出方法が異なる結果を返す場合、セキュリティやプライバシー上の課題につながることがあります。どのソースマップがロードされる可能性があるか検出したい実装は、両アルゴリズムを必ず適用することが強く推奨されます。

この課題に対する修正は現在検討中で、将来標準に取り込まれる見込みです。今後は、コメント(またはコメント的なもの)にU+0060(`)、U+0022(")、U+0027(')、U+002A U+002F(*/)などが含まれていればアルゴリズムを早期終了する方式が採用される見込みです。

11.1.2.1 JavaScriptExtractSourceMapURL ( source )

抽象演算JavaScriptExtractSourceMapURLは引数source(String型)を受け取り、Stringまたはnullを返します。JavaScriptソースからソースマップURLを抽出します。実装は構文解析あり構文解析なしの2通り。

ソースマップURL構文解析ありで抽出:

  1. tokensListとして、sourceECMA-262字句文法で構文解析したトークン群とする。
  2. tokensの各非終端tokenを逆順で:
    1. tokenSingleLineCommentでもMultiLineCommentでもなければnullを返す。
    2. commenttokenの内容とする。
    3. sourceMapURLMatchSourceMapURL(comment)の結果とする。
    4. sourceMapURLがStringならそれを返す。
  3. nullを返す。

ソースマップURL構文解析なしで抽出:

  1. linesStringSplit(source, «"\u000D\u000A", "\u000A", "\u000D", "\u2028", "\u2029"»)を設定する。
  2. 注:上記の正規表現はLineTerminatorSequence生成規則と一致する。
  3. lastURLnullを設定する。
  4. linesの各StringlineStrについて、次を行う:
    1. lineStringToCodePoints(lineStr)を設定する。
    2. positionを0に設定する。
    3. lineLengthlineの長さに設定する。
    4. 繰り返し、position < lineLengthの場合:
      1. firstline[position]を設定する。
      2. positionposition + 1を設定する。
      3. もしfirstがU+002F (SOLIDUS) かつ position < lineLength なら:
        1. secondline[position]を設定する。
        2. positionposition + 1を設定する。
        3. もしsecondがU+002F (SOLIDUS) なら:
          1. commentsubstring(lineStr, position, lineLength)を設定する。
          2. sourceMapURLMatchSourceMapURL(comment)を設定する。
          3. もしsourceMapURLStringなら、lastURLsourceMapURLを設定する。
          4. positionlineLengthに設定する。
        4. それ以外でsecondがU+002A (ASTERISK) なら:
          1. commentCpを新しい空のListに設定する。
          2. 繰り返し、position + 1 < lineLength の間:
            1. c1line[position]を設定する。
            2. positionposition + 1を設定する。
            3. c2line[position]を設定する。
            4. もしc1がU+002A (ASTERISK) かつ c2がU+002F (SOLIDUS) なら:
              1. positionposition + 1を設定する。
              2. sourceMapURLMatchSourceMapURL(CodePointsToString(commentCp))を設定する。
              3. もしsourceMapURLStringなら、lastURLsourceMapURLを設定する。
            5. commentCpc1を追加する。
        5. それ以外の場合:
          1. lastURLnullに設定する。
      4. それ以外でfirstがECMAScript WhiteSpaceでない場合:
        1. lastURLnullに設定する。
      5. 注:非コメントのコード文字を発見したら、lastURLnullにリセットする。
  5. lastURLを返す。
注1
上のアルゴリズムはソース行を逆順でたどり、sourceMappingURLコメントを含む行取得後早期終了できるよう設計されています。
注2

上のアルゴリズムは以下のJavaScript実装と等価です:

const JS_NEWLINE = /^/m;

// この正規表現は下記いずれかに常に一致:
// - 一行コメント
// - 「一行」複数行コメント
// - 閉じられない複数行コメント
// - 行末空白
// - コード文字
// ループ内でそれぞれ区別します。
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 {
      // 行末空白または未終了コメント
      // Assert: JS_COMMENT.lastIndex === line.length
    }
  }
}
return lastURL;

11.1.2.1.1 MatchSourceMapURL ( comment )

抽象演算MatchSourceMapURLは引数comment(String型)を受け取り、noneまたはStringを返します。呼び出し時は以下の手順:

  1. patternRegExpCreate("^[@#]\s*sourceMappingURL=(\S*?)\s*$", "")とする。
  2. matchRegExpExec(pattern, comment)とする。
  3. matchnullでなければ、Get(match, "1")を返す。
  4. noneを返す。
このアノテーションの接頭辞は最初は//@でしたが、IEの条件付きコンパイルと競合するため//#に変更されました。

ソースマップ生成ツールは//#のみ出力すべきですが、利用側は//@//#の両方を受け入れるべきです。

11.1.2.2 CSSExtractSourceMapURL ( source )

抽象演算CSSExtractSourceMapURLは引数source(String型)を受け取り、Stringまたはnullを返します。CSSソースからソースマップURLを抽出します。

CSSからのソースマップURL抽出は、CSSは/* ... */型コメントのみをサポートする点以外はJavaScriptと同様です。

11.1.2.3 WebAssemblyExtractSourceMapURL ( bytes )

抽象演算WebAssemblyExtractSourceMapURLは引数bytesData Block型)を受け取り、Stringまたはnullを返します。WebAssemblyバイナリソースからソースマップURLを抽出します。

  1. modulemodule_decode(bytes)で取得。
  2. moduleWebAssemblyエラーならnull
  3. moduleの各custom sectioncustomSectionについて:
    1. namecustomSectionnameとする。
    2. CodePointsToString(name)が"sourceMappingURL"なら:
      1. valuecustomSectionbytesとする。
      2. CodePointsToString(value)を返す。
  4. nullを返す。

WebAssemblyはテキスト形式ではなく、コメントもサポートしないため一意的な抽出方法のみ対応しています。URLWebAssembly名としてエンコードされ、custom sectionの内容として配置されます。WebAssemblyコードを生成するツールはsourceMappingURL名のcustom sectionを2つ以上生成してはなりません。

11.2 ソースマップの取得処理

11.2.1 FetchSourceMap ( url )

抽象演算FetchSourceMapは引数urlURL型)を受け取り、Promiseを返します。呼び出し時の手順:

  1. promiseCapabilityNewPromiseCapability(%Promise%)で作成。
  2. requestを新しいrequestとし、そのrequest URLurlにする。
  3. processResponseConsumeBodyを(response,bodyBytes)引数の新規Abstract Closureで、promiseCapabilityurlをキャプチャ。呼び出し時の手順:
    1. bodyBytesnullfailureなら:
      1. Call(promiseCapability.[[Reject]], undefined, «新しいTypeError»)。
      2. Return。
    2. urlschemeHTTP(S) schemeであり、byte sequence)]}'prefixなら:
      1. byte-sequence-length≠0かつbodyBytes[0]がHTTP newline byteでない間:
        1. bodyBytesの0番目要素を削除。
    3. bodyStringCompletion(UTF-8 decode of bodyBytes)で取得。
    4. IfAbruptRejectPromise(bodyString, promiseCapability)。
    5. jsonValueCompletion(ParseJSON(bodyString))で取得。
    6. IfAbruptRejectPromise(jsonValue, promiseCapability)。
    7. Call(promiseCapability.[[Resolve]], undefined, «jsonValue»)。
  4. fetchrequestprocessResponseConsumeBody引数付きで実行。
  5. promiseCapability.[[Promise]]を返す。

歴史的理由によりHTTP(S)越しでソースマップを配信する際、ソースマップの先頭に)]}'で始まる行が追加される場合があります。

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

これは下記とみなされます:

{"version": 3, ...}

12 ソースマップレコードの操作

ソースマップをデコードした後、ソースマップ利用者は得られたデコード済みソースマップレコードを使い、デバッグ等の用途で位置情報を検索できます。本節はソースマップ利用者が典型的にサポートする操作の動作について説明します。

GetOriginalPositions操作は、生成コードの位置に対応する元ソースの位置を問い合わせるために用います。たとえば、デバッガではユーザーのマウスクリックなどに基づき生成コードから元ソースへナビゲートできます。

12.1 GetOriginalPositions ( sourceMapRecord, generatedPosition )

抽象操作GetOriginalPositionsは、引数sourceMapRecordデコード済みソースマップレコード型)とgeneratedPositionPosition Record型)を受け取り、Original Position RecordsListを返します。呼び出し時の手順:

  1. mappingssourceMapRecord.[[Mappings]]とする。
  2. lastnullとする。
  3. originalPositionsを新しい空のListとする。
  4. mappingsの各mappingを逆順で:
    1. lastnullの場合:
      1. ComparePositions(mapping.[[GeneratedPosition]], generatedPosition)の結果がlesserまたはequalならlastmappingを設定。
  5. lastnullでなければ:
    1. mappingsの各mappingについて:
      1. ComparePositions(last.[[GeneratedPosition]], mapping.[[GeneratedPosition]])の結果がequalならmapping.[[OriginalPosition]]originalPositionsに追加。
  6. originalPositionsを返す。

Annex A (informative) 慣例

ソースマップの取扱いや生成時には次の慣例に従うべきです。

A.1 ソースマップ命名規則

一般的に、ソースマップは生成されたファイル名に.map拡張子をつけ同名で作成されます。例:page.jsの場合、page.js.mapというソースマップが生成されます。

A.2 evalコードの名前付き生成コードへのリンク

evalコードにソースマップを利用するための既存の慣例があり、次の形式を取ります:

//# sourceURL=foo.js

これはGive your eval a name with //@ sourceURLで説明されています。

Annex B (informative) 注釈

B.1 言語非依存のスタックマッピング

ソース言語の知識なしでのスタックトレースマッピングは本書では対象外です。

B.2 多段階マッピング

DSL(テンプレート)からの生成やTypeScript → JavaScript → minified JavaScriptといった複数段の変換を経た最終ソースマップが生成されるケースが一般的になっています。この問題は二通りで対応可能です。一つは単純ですが情報損失が発生する方法で、中間ステップをデバッグ用途では無視し、翻訳過程の位置情報を無視して(中間変換を「元ソース」とみなす)、または位置情報を引き継いで(中間変換は隠される)扱う方法です。より完全な方法は多段階のマッピングをサポートするものです。元ソース側もソースマップ参照を持つ場合、ユーザーはそれも利用可能です。

ただし、JavaScript以外で「ソースマップ参照」が何なのかは未定義です。特に、JavaScript形式の一行コメントをサポートしない言語でソースマップ参照がどんな形式になるかは不明です。

Annex C (informative) 他仕様で定義されている用語

本書で使われている用語・アルゴリズムのうち、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) 参考文献

  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. 可変長数量, Wikipedia, available at <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/

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.