TurboWarp カスタム機能拡張

文字列の切り貼りなしで、本物のデータを。

JSONやYAMLを一度読み込んで名前を付ければ、あとはそのまま扱えます。項目を1つ読む、値を1つ書き換える、リストを順に処理する、そして結果をテキストに戻す。文字列の分割や、複数のリストの同期に悩む必要はありません。

parse YAML speed: 4 as cfg
set cfg at path $.speed to JSON 6
to JSON cfg {"speed":6}

01 · はじめに

3ステップで準備完了。

Structured Dataは明示的に有効にして使うプレビュー機能です。拡張を読み込む前に起動時フラグを設定したときだけブロックが表示されるので、既存のプロジェクトに意図せず影響することはありません。

1

機能フラグをオンにする

TurboWarpを動かしているページ(ブラウザーのコンソールや独自のホストページなど)で、拡張を読み込む前に globalThis.STRUCTURED_DATA_MVP = true を実行します。

2

拡張を読み込む

下のURLをカスタム拡張機能として追加し、 サンドボックスなしで実行するを選びます。

3

最初の値を読み込む

parse JSON [ ] as [data] または parse YAML [ ] as [data] をスクリプトに置いてクリックします。これで名前 data に値が入ります。

バージョン固定の拡張URL
https://cdn.jsdelivr.net/npm/@kubohiroya/turbowarp-structured-data@0.6.2/dist/structured-data.js

サンドボックスなしの実行が必要です。スプライトとステージがそれぞれ自分の名前付きの値を持ち、繰り返しが実行中のスクリプトを追跡するため、TurboWarp VMへの直接アクセスが必要です。この拡張はネットワーク通信をせず、実行中のプロジェクト以外には何も保存しません。拡張ファイルは信頼できる配布元からのみ読み込んでください。

02 · しくみ

一度読み込み、名前で扱い、必要なときだけテキストに。

テキストを読み込むと、名前付きの値がスプライトの中に保持され、求めたときだけテキストに戻ります。その間、すべてのブロックはオブジェクト、配列、数値、文字列、真偽値、 null という実際の構造をそのまま扱います。

名前付きの値の一生
JSON / YAML テキスト 変数、リストの項目、ファイル、Webの応答など
名前付きの値 $.path で読む・確かめる・書く・消す・繰り返す
JSON / YAML テキスト キーの順序が一定で、保存や送信にそのまま使える

名前はスプライトごと

スプライト1の config とステージの config は別の値です。同じ名前でもう一度読み込むと、値が置き換わります。

値は停止するまで

名前付きの値はプロジェクトの実行中だけ存在します。停止ボタンで消え、プロジェクトファイルにも保存されません。後で使う場合は元のテキストを変数に残してください。

設定値を読む

ブロック
parse JSON [{"level":{"speed":4}}] as [cfg]
get JSON from [cfg] at path [$.level.speed]
→ 4

数値やテキストを入れる場所なら、どこでもこのレポーターを使えます。

書き換えて保存する

ブロック
set [save] at path [$.score] to JSON [120]
set [save] at path [$.name] to JSON ["Mio"]
[saved text] を (to JSON [save]) にする

値はJSONなので、文字列には引用符が必要です。Mio ではなく "Mio"。

読む前に確かめる

ブロック
もし <structured data [save] has path [$.items]?> なら(length of array in [save] at path [$.items]) と言う

先に確かめれば、データやパスがないことによるエラーを避けられます。

03 · パス

ちょうど1か所を指す。

パスは値全体を表す $ から始まり、キーまたは添字を1つずつたどります。どのパスも必ず1か所だけを指すように、あえて単純にしてあります。意図した以上の場所をブロックが変更することはありません。

パス 指す場所
$ 値全体。
$.player.name キー player の中のキー name。ドットで書けるキーは英字・数字・_ からなり、数字で始まらないものです。
$.items[0] 配列 items の最初の項目。添字は0から数えます。
$["キー.ドット 入り"] 空白・ドット・日本語を含む任意のキー。引用符と角かっこで囲みます。

set と delete path でできること

  • set は値全体の置き換え、既存の配列項目の置き換え、既存オブジェクトのキーの追加・置き換えができます。
  • 配列の項目を削除すると、後ろの項目が1つずつ前に詰まります。
  • 変更は完全に成功したときだけ反映されます。失敗したブロックは値を変えません。

できないこと

  • 存在しない親のオブジェクトや配列の自動作成。
  • 配列の末尾より後ろへの追加。
  • $ の削除(代わりに delete structured data を使います)。
  • ワイルドカード、スライス、フィルター、再帰検索、式。

04 · 繰り返し

すべての項目を、決まった順番で。

for each in [ ] at path [ ] max [ ] は、配列の項目またはオブジェクトのキーごとに中のブロックを1回ずつ実行します。ループの中では3つのレポーターで現在位置がわかります。

ブロック
parse JSON [{"items":["apple","pear"]}] as [shop]
for each in [shop] at path [$.items] max [100]
  ((current index) と (current value JSON)) と言う
→ 0"apple"   1"pear"
レポーター ループの中で返す値
current key オブジェクトのキー、または配列の添字(文字列)。
current index 0から始まる回数。
current value JSON 現在の項目(JSON)。

いつも同じ順番

配列は添字順、オブジェクトはUnicodeのコードポイント順にソートしたキーの順です。元のテキストの書き方に結果が左右されません。

max は安全のための上限

1〜1000の整数を指定します(既定は100)。項目数がこれを超えると、黙って一部を飛ばすのではなくエラーになります。

入れ子にできる

ループの中に別のループを置けます。レポーターは常に、実行中のいちばん内側のループを表します。

05 · ブロックの選び方

やりたいことからブロックを選ぶ。

どのブロックも NAME で値を指定します。各引数と既定値は Complete block reference(英語)にあります。

やりたいこと 使うブロック
テキストを名前付きの値として読み込む parse JSON [ ] as [ ]、parse YAML [ ] as [ ]
値全体をテキストに戻す to JSON [ ]、to YAML [ ]
名前付きの値の有無を調べる・消す structured data [ ] exists?、delete structured data [ ]
1か所を読む・確かめる get JSON from [ ] at path [ ]、structured data [ ] has path [ ]?
1か所を変更する set [ ] at path [ ] to JSON [ ]、delete path [ ] from [ ]
コレクションを調べる keys in [ ] at path [ ](ソート済み、JSON配列)、length of array in [ ] at path [ ]
項目ごとに繰り返す for each in [ ] at path [ ] max [ ] と current key、current index、current value JSON

06 · 制限と安全性

入力は厳格に、出力は予測どおりに。

Structured Dataは純粋なデータだけを受け付け、推測せずにはっきりと失敗します。大きな入力や特殊な入力でプロジェクトが固まったり、意味が変わったりするのを防ぎます。

サイズの上限

1回の読み込みで、テキストは256 KiBまで、入れ子は64段まで、値の総数は50,000個までです。

安全なYAML

エイリアス、未知のタグ、重複キー、文字列以外のキー、未対応のスカラー型、パーサーの警告は拒否します。

安定した出力

to JSON と to YAML は常にキーをソートします。同じデータからは同じテキストが得られるので、比較・保存・送信が簡単です。

07 · オプションの連携機能

編集フォームと共有Named Data。

以下の機能は既定でオフで、通常の利用には必要ありません。対応したTurboWarpビルドやホストでのみ有効にしてください。

Source/Formエディター

GUIの起動オプション blockEditorDialogs=1 と blockEditorSourceForms=1 を指定すると、parse JSON、 parse YAML、set … to JSON のJSON/YAML入力を、ソーステキストとフォームを切り替えられるエディターで編集できます。変更していないテキストは書いたとおりに保たれ、ブロックが拒否する入力は保存できません。

max の固定入力エディター

blockEditorDialogs と blockEditorFixedInputs の両方をオンにして再読み込みすると、for each の max を1〜1000の整数で編集するフォームが使えます。入力途中・空白・有限でない新しい値は保存できず、NAMEとPATHは変更しません。既存の値は編集しない限り書き換えず、接続したレポーターは評価しません。

Named Dataプロバイダー

globalThis.NAMED_DATA_REGISTRY_MVP = true を設定すると、名前付きの値が共有の Named Data レジストリを通じて structured データとして他の拡張にも提供されます。 __TW_NAMED_DATA_FEATURE_FLAGS__ = {NAMED_DATA_SCHEMA_REF: true} を加えると、Schemaの識別情報も受け渡します。

08 · 困ったとき

ブロックが期待どおりに動かないとき。

多くの問題は、起動時フラグ、JSONの引用符、停止による値の消去が原因です。ブロックが失敗すると下の安定したエラーコードのいずれかを報告し、名前付きの値は元のまま残ります。

パレットが空になっている

先に globalThis.STRUCTURED_DATA_MVP = true を設定してから、拡張を読み込み直してください。フラグは起動時に1回だけ読み取られます。

文字列が引用符付きで返ってくる

get JSON はJSONを返すため、文字列 Mio は "Mio" として返ります。保存するときも引用符を付けます: set … to JSON ["Mio"]。

停止後に「DATA_NOT_FOUND」

停止するとすべての名前付きの値が消えます。緑の旗が押されたときのスクリプトでもう一度読み込んでください。

別のスプライトからデータが見えない

名前は読み込みを実行したスプライトまたはステージに属します。必要なスプライトごとに読み込むか、JSONテキストを全体用の変数で受け渡してください。

set で「PATH_NOT_FOUND」

set は存在しない親を作りません。先に親を作ってから(例: $.player を {} に)、$.player.name を設定します。

「ITERATION_LIMIT_EXCEEDED」

コレクションが max より大きいためです。max を(1000まで)増やすか、データのより小さな部分を対象にしてください。

エラーコード 意味
INVALID_JSON / INVALID_YAMLテキストを解析できないか、許可されていないYAMLの機能を使っています。
PARSE_LIMIT_EXCEEDEDテキストのサイズ、深さ、値の数が上限を超えています。
INVALID_NAME名前が空か、空白だけです。
DATA_NOT_FOUNDこのスプライトにその名前の値がありません。
INVALID_PATHパスが対応している書き方になっていません。
PATH_NOT_FOUNDパス、またはその親が存在しません。
TYPE_MISMATCH配列を期待した場所に数値があるなど、型が異なります。
INDEX_OUT_OF_RANGE配列の添字が末尾を超えています。
ITERATION_LIMIT_EXCEEDEDコレクションの項目数が max を超えています。
ITERATION_CONTEXT_REQUIREDcurrent … レポーターを for each ループの外で使いました。