> ## Documentation Index
> Fetch the complete documentation index at: https://docs.makkii.jp/llms.txt
> Use this file to discover all available pages before exploring further.

# 非短縮ビルドのソースマップ

> 複数ファイルをgame環境で実行し、停止位置とエラーを元ファイルへ戻す

<Note>
  このページは公開版v0.2.0に対応します。ソース・型・WASMを同じ版で使用してください。0.2.0のマップは非短縮リンク結果のみを対象にし、最適化後のマップは返しません。
</Note>

## 対応する経路

ゲーム向けの複数ファイルは、`compiler.build(project, {environment:"game", minify:false})`で一つのLuaにまとめ、その`code`をgame環境のVehicleへloadします。元ソースのrequireはビルドで解決するため、実行環境の`require`はnilのままです。

成功時の`map`にはSource Map v3形式のJSON文字列が入り、元ファイルに相当する`source`名と原文の`sourcesContent`を含みます。`code`と`map`は必ず同じビルド結果の組で保持してください。後から生成Luaを編集したりminifyしたりすると、このマップは使えません。

`lib.util`というモジュールは`lib/util.lua`として表示されます。ambientの注入元も`sim/value.lua`のような名前で含まれます。SDKがその名前のファイルをディスクから開くわけではありません。

## 元ファイルでブレークポイントを指定する

ホストは次の順番で接続します。

1. 非短縮ビルドに成功し、`code`と`map`があることを確認します。
2. `code`を`@mapped-program.lua`など一定のチャンク名でloadします。
3. マップから、元のファイル名・行に**完全に一致する**生成行を取り出します。
4. その生成行とチャンク名を`vm.setBreakpoints()`へ渡します。
5. 停止したstackの生成位置を同じマップで逆引きし、元のファイル・行として表示します。

例えば、`lib/util.lua`の3行目が生成Luaの5行目なら、VMには`{source:"@mapped-program.lua", line:5}`を設定します。VMが返す5行目を、画面では元の3行目へ戻します。

一致する元行がない場合は、近い行へ勝手に移動せず「対応なし」として扱います。コメントや空行にマップがあっても、その行でLuaが実際に停止できるとは限りません。

## 実行できるNodeの例

SDKリポジトリの`examples/consumer/source-map.mjs`は、通常のSource Map consumerである`@jridgewell/trace-mapping`を使います。SDKとこのパッケージを利用先のNodeプロジェクトへ導入し、同じファイルを実行してください。SDKの公開前は、対応する検証済みtarballを使用します。

この例は次を実際に確認します。

* game設定のまま複数モジュールをビルドし、元ファイルの行で停止します。
* 呼び出し元の位置を戻し、1ステップ進めてから再開します。
* 出力6と、同じプログラムをresetした後の出力8を確認します。
* 戻り値として公開された関数の実行エラーを、元のファイルの3行目へ戻します。
* 短縮ビルドには古いリンクマップが付かないことを確認します。

`eachMapping()`で元位置に完全一致する生成行を集め、`originalPositionFor()`で停止位置を逆引きする方法です。SDK自体のnpm実行時依存へSource Map consumerを追加する必要はありません。位置変換を行うホストだけが利用します。

[実行例のソース](https://github.com/Stormcat-Works/storm-lua-engine/blob/v0.2.0/examples/consumer/source-map.mjs)

## 対応精度と合成行

現在のマップは**行単位・列0**です。元ソースをそのまま転写した範囲を対応付けます。リンカーが作る変数宣言や`do/end`などの補助行は、架空の原文へ割り当てず「対応なし」にします。

1行に複数の文や展開境界がある場合、列ごとに別の元位置を選べるマップではありません。非短縮のデバッグ用ソースでは、意味のある文を行で分けると位置を確認しやすくなります。LFとCRLF、およびコメント・文字列の日本語も、元ソース内容とともに扱います。

Source Mapの内部の行と列は0始まりですが、利用するJS consumerのAPIでは行が1始まり、列が0始まりの場合があります。SDKのbreakpointとstackの行も1始まりです。使用するconsumerの規約を確認し、二重に1を足さないでください。

runtime errorを戻す際も、エラーがどの生成チャンクを指すか確認します。認識できないエラー形式やマップがない位置は、元ファイルの位置を推測せず、そのまま表示します。

## lint・前処理・最適化との違い

`analyze(project)`は元のモジュールを直接解析し、モジュール名と位置を返します。通常のlintのために、先に一つのファイルへ結合する必要はありません。

ホストが解析前にコメントブロックを削除するなどの前処理を行う場合、その前処理の行対応は別途必要です。前処理後の位置を、編集画面の元テキストへ正しく戻してください。

`build({minify:true})`は最適化後のマップを返しません。非短縮マップを付け替えるだけでは正しい位置へ戻せません。また、位置情報があることと、最適化で消えた変数や元の実行順序を復元できることは別です。

[Compilerの操作](/storm-lua-engine/compiler) · [実行時requireと複数load](/storm-lua-engine/source-loading)
