@kubohiroya/turbowarp-structured-data 0.5.1 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +13 -0
- package/README.md +14 -1
- package/dist/structured-data.js +14237 -6205
- package/docs/index.html +35 -1
- package/docs/schemas/block-editor-fixed-inputs.schema.json +20 -0
- package/docs/source-forms.ja.md +20 -0
- package/docs/stage2-release-verification.ja.md +28 -0
- package/package.json +18 -9
- package/schemas/block-editor-fixed-inputs.schema.json +20 -0
- package/src/editor-schema.ts +16 -0
- package/src/extension.ts +34 -4
- package/src/fixed-input-editors.ts +67 -0
- package/src/fixed-input-schema.ts +16 -0
- package/src/source-editor.ts +57 -0
- package/templates/README.ja.md +13 -0
- package/templates/README.md +13 -0
package/docs/index.html
CHANGED
|
@@ -9,8 +9,17 @@
|
|
|
9
9
|
code{background:#f3f3f3;padding:.1em .3em;border-radius:.25em}
|
|
10
10
|
pre{background:#f6f8fa;padding:1rem;overflow:auto;border-radius:.5rem}
|
|
11
11
|
</style>
|
|
12
|
+
<style id="block-reference-style">
|
|
13
|
+
#extension-block-reference{max-width:72rem;margin:2rem auto;padding:1rem;line-height:1.6;overflow-wrap:anywhere}
|
|
14
|
+
#extension-block-reference .block-reference-entry{display:block;scroll-margin-top:6rem;margin:2rem 0;padding:1rem;border:1px solid currentColor;border-radius:.5rem}
|
|
15
|
+
#extension-block-reference .block-reference-table{overflow-x:auto}
|
|
16
|
+
#extension-block-reference table{border-collapse:collapse;width:100%}
|
|
17
|
+
#extension-block-reference th,#extension-block-reference td{text-align:left;vertical-align:top;border:1px solid currentColor;padding:.5rem}
|
|
18
|
+
#extension-block-reference code{white-space:pre-wrap}
|
|
19
|
+
#extension-block-reference a:focus-visible{outline:3px solid currentColor;outline-offset:3px}
|
|
20
|
+
</style>
|
|
12
21
|
</head>
|
|
13
|
-
<body>
|
|
22
|
+
<body><p lang="en" class="complete-block-reference-link"><a href="#extension-block-reference">Complete block reference (16 blocks)</a></p>
|
|
14
23
|
<h1>Structured Data</h1>
|
|
15
24
|
<p>Named structured data with safe JSON/YAML codecs and deterministic path operations.</p>
|
|
16
25
|
|
|
@@ -22,5 +31,30 @@
|
|
|
22
31
|
|
|
23
32
|
<h2>Development</h2>
|
|
24
33
|
<p>See the repository README and architecture documentation for build, test, release, and compatibility details.</p>
|
|
34
|
+
<!-- BEGIN COMPLETE BLOCK REFERENCE -->
|
|
35
|
+
<section lang="en" id="extension-block-reference" aria-labelledby="block-reference-title">
|
|
36
|
+
<h2 id="block-reference-title">Structured Data: complete block reference</h2>
|
|
37
|
+
<p>All 16 blocks are documented below, including compatibility blocks and blocks available through optional features. Select a block to read its behavior, arguments, default values, and menu choices. Each block has a permanent link.</p>
|
|
38
|
+
<nav aria-label="Block reference"><ul><li><a href="#block-parseJson"><code>parse JSON [TEXT] as [NAME]</code></a></li>
|
|
39
|
+
<li><a href="#block-parseYaml"><code>parse YAML [TEXT] as [NAME]</code></a></li>
|
|
40
|
+
<li><a href="#block-toJson"><code>to JSON [NAME]</code></a></li>
|
|
41
|
+
<li><a href="#block-toYaml"><code>to YAML [NAME]</code></a></li>
|
|
42
|
+
<li><a href="#block-hasStructuredData"><code>structured data [NAME] exists?</code></a></li>
|
|
43
|
+
<li><a href="#block-deleteStructuredData"><code>delete structured data [NAME]</code></a></li>
|
|
44
|
+
<li><a href="#block-getJsonAtPath"><code>get JSON from [NAME] at path [PATH]</code></a></li>
|
|
45
|
+
<li><a href="#block-hasPath"><code>structured data [NAME] has path [PATH]?</code></a></li>
|
|
46
|
+
<li><a href="#block-setJsonAtPath"><code>set [NAME] at path [PATH] to JSON [VALUE]</code></a></li>
|
|
47
|
+
<li><a href="#block-deleteAtPath"><code>delete path [PATH] from [NAME]</code></a></li>
|
|
48
|
+
<li><a href="#block-keysAtPath"><code>keys in [NAME] at path [PATH]</code></a></li>
|
|
49
|
+
<li><a href="#block-lengthAtPath"><code>length of array in [NAME] at path [PATH]</code></a></li>
|
|
50
|
+
<li><a href="#block-forEachAtPath"><code>for each in [NAME] at path [PATH] max [MAX]</code></a></li>
|
|
51
|
+
<li><a href="#block-currentKey"><code>current key</code></a></li>
|
|
52
|
+
<li><a href="#block-currentIndex"><code>current index</code></a></li>
|
|
53
|
+
<li><a href="#block-currentValueJson"><code>current value JSON</code></a></li>
|
|
54
|
+
</ul></nav>
|
|
55
|
+
<article id="block-parseJson" class="block-reference-entry"><h3><code>parse JSON [TEXT] as [NAME]</code></h3><p>Parse JSON text into the target-local structured data namespace.</p><p>Block type: COMMAND. Opcode: <code>parseJson</code>. <a href="#block-parseJson">Permanent link</a></p><div class="block-reference-table"><table><thead><tr><th>Argument</th><th>Type</th><th>Default value</th><th>Menu choices</th></tr></thead><tbody><tr><th scope="row"><code>TEXT</code></th><td>STRING</td><td><code>{"name":"TurboWarp"}</code></td><td></td></tr><tr><th scope="row"><code>NAME</code></th><td>STRING</td><td><code>data</code></td><td></td></tr></tbody></table></div></article><article id="block-parseYaml" class="block-reference-entry"><h3><code>parse YAML [TEXT] as [NAME]</code></h3><p>Parse safe YAML text into the target-local structured data namespace.</p><p>Block type: COMMAND. Opcode: <code>parseYaml</code>. <a href="#block-parseYaml">Permanent link</a></p><div class="block-reference-table"><table><thead><tr><th>Argument</th><th>Type</th><th>Default value</th><th>Menu choices</th></tr></thead><tbody><tr><th scope="row"><code>TEXT</code></th><td>STRING</td><td><code>name: TurboWarp</code></td><td></td></tr><tr><th scope="row"><code>NAME</code></th><td>STRING</td><td><code>data</code></td><td></td></tr></tbody></table></div></article><article id="block-toJson" class="block-reference-entry"><h3><code>to JSON [NAME]</code></h3><p>Render named structured data as canonical JSON.</p><p>Block type: REPORTER. Opcode: <code>toJson</code>. <a href="#block-toJson">Permanent link</a></p><div class="block-reference-table"><table><thead><tr><th>Argument</th><th>Type</th><th>Default value</th><th>Menu choices</th></tr></thead><tbody><tr><th scope="row"><code>NAME</code></th><td>STRING</td><td><code>data</code></td><td></td></tr></tbody></table></div></article><article id="block-toYaml" class="block-reference-entry"><h3><code>to YAML [NAME]</code></h3><p>Render named structured data as deterministic YAML.</p><p>Block type: REPORTER. Opcode: <code>toYaml</code>. <a href="#block-toYaml">Permanent link</a></p><div class="block-reference-table"><table><thead><tr><th>Argument</th><th>Type</th><th>Default value</th><th>Menu choices</th></tr></thead><tbody><tr><th scope="row"><code>NAME</code></th><td>STRING</td><td><code>data</code></td><td></td></tr></tbody></table></div></article><article id="block-hasStructuredData" class="block-reference-entry"><h3><code>structured data [NAME] exists?</code></h3><p>Report whether the current target has named structured data.</p><p>Block type: BOOLEAN. Opcode: <code>hasStructuredData</code>. <a href="#block-hasStructuredData">Permanent link</a></p><div class="block-reference-table"><table><thead><tr><th>Argument</th><th>Type</th><th>Default value</th><th>Menu choices</th></tr></thead><tbody><tr><th scope="row"><code>NAME</code></th><td>STRING</td><td><code>data</code></td><td></td></tr></tbody></table></div></article><article id="block-deleteStructuredData" class="block-reference-entry"><h3><code>delete structured data [NAME]</code></h3><p>Delete named structured data from the current target.</p><p>Block type: COMMAND. Opcode: <code>deleteStructuredData</code>. <a href="#block-deleteStructuredData">Permanent link</a></p><div class="block-reference-table"><table><thead><tr><th>Argument</th><th>Type</th><th>Default value</th><th>Menu choices</th></tr></thead><tbody><tr><th scope="row"><code>NAME</code></th><td>STRING</td><td><code>data</code></td><td></td></tr></tbody></table></div></article><article id="block-getJsonAtPath" class="block-reference-entry"><h3><code>get JSON from [NAME] at path [PATH]</code></h3><p>Return a named value at a path as JSON.</p><p>Block type: REPORTER. Opcode: <code>getJsonAtPath</code>. <a href="#block-getJsonAtPath">Permanent link</a></p><div class="block-reference-table"><table><thead><tr><th>Argument</th><th>Type</th><th>Default value</th><th>Menu choices</th></tr></thead><tbody><tr><th scope="row"><code>NAME</code></th><td>STRING</td><td><code>data</code></td><td></td></tr><tr><th scope="row"><code>PATH</code></th><td>STRING</td><td><code>$.name</code></td><td></td></tr></tbody></table></div></article><article id="block-hasPath" class="block-reference-entry"><h3><code>structured data [NAME] has path [PATH]?</code></h3><p>Report whether a path exists in named structured data.</p><p>Block type: BOOLEAN. Opcode: <code>hasPath</code>. <a href="#block-hasPath">Permanent link</a></p><div class="block-reference-table"><table><thead><tr><th>Argument</th><th>Type</th><th>Default value</th><th>Menu choices</th></tr></thead><tbody><tr><th scope="row"><code>NAME</code></th><td>STRING</td><td><code>data</code></td><td></td></tr><tr><th scope="row"><code>PATH</code></th><td>STRING</td><td><code>$.name</code></td><td></td></tr></tbody></table></div></article><article id="block-setJsonAtPath" class="block-reference-entry"><h3><code>set [NAME] at path [PATH] to JSON [VALUE]</code></h3><p>Immutably update a named value and replace its binding.</p><p>Block type: COMMAND. Opcode: <code>setJsonAtPath</code>. <a href="#block-setJsonAtPath">Permanent link</a></p><div class="block-reference-table"><table><thead><tr><th>Argument</th><th>Type</th><th>Default value</th><th>Menu choices</th></tr></thead><tbody><tr><th scope="row"><code>NAME</code></th><td>STRING</td><td><code>data</code></td><td></td></tr><tr><th scope="row"><code>PATH</code></th><td>STRING</td><td><code>$.name</code></td><td></td></tr><tr><th scope="row"><code>VALUE</code></th><td>STRING</td><td><code>"Scratch"</code></td><td></td></tr></tbody></table></div></article><article id="block-deleteAtPath" class="block-reference-entry"><h3><code>delete path [PATH] from [NAME]</code></h3><p>Immutably delete a path and replace its named binding.</p><p>Block type: COMMAND. Opcode: <code>deleteAtPath</code>. <a href="#block-deleteAtPath">Permanent link</a></p><div class="block-reference-table"><table><thead><tr><th>Argument</th><th>Type</th><th>Default value</th><th>Menu choices</th></tr></thead><tbody><tr><th scope="row"><code>NAME</code></th><td>STRING</td><td><code>data</code></td><td></td></tr><tr><th scope="row"><code>PATH</code></th><td>STRING</td><td><code>$.name</code></td><td></td></tr></tbody></table></div></article><article id="block-keysAtPath" class="block-reference-entry"><h3><code>keys in [NAME] at path [PATH]</code></h3><p>Return sorted object keys as JSON.</p><p>Block type: REPORTER. Opcode: <code>keysAtPath</code>. <a href="#block-keysAtPath">Permanent link</a></p><div class="block-reference-table"><table><thead><tr><th>Argument</th><th>Type</th><th>Default value</th><th>Menu choices</th></tr></thead><tbody><tr><th scope="row"><code>NAME</code></th><td>STRING</td><td><code>data</code></td><td></td></tr><tr><th scope="row"><code>PATH</code></th><td>STRING</td><td><code>$</code></td><td></td></tr></tbody></table></div></article><article id="block-lengthAtPath" class="block-reference-entry"><h3><code>length of array in [NAME] at path [PATH]</code></h3><p>Return the array length.</p><p>Block type: REPORTER. Opcode: <code>lengthAtPath</code>. <a href="#block-lengthAtPath">Permanent link</a></p><div class="block-reference-table"><table><thead><tr><th>Argument</th><th>Type</th><th>Default value</th><th>Menu choices</th></tr></thead><tbody><tr><th scope="row"><code>NAME</code></th><td>STRING</td><td><code>data</code></td><td></td></tr><tr><th scope="row"><code>PATH</code></th><td>STRING</td><td><code>$</code></td><td></td></tr></tbody></table></div></article><article id="block-forEachAtPath" class="block-reference-entry"><h3><code>for each in [NAME] at path [PATH] max [MAX]</code></h3><p>Iterate named data deterministically with a static maximum.</p><p>Block type: LOOP. Opcode: <code>forEachAtPath</code>. <a href="#block-forEachAtPath">Permanent link</a></p><div class="block-reference-table"><table><thead><tr><th>Argument</th><th>Type</th><th>Default value</th><th>Menu choices</th></tr></thead><tbody><tr><th scope="row"><code>NAME</code></th><td>STRING</td><td><code>data</code></td><td></td></tr><tr><th scope="row"><code>PATH</code></th><td>STRING</td><td><code>$</code></td><td></td></tr><tr><th scope="row"><code>MAX</code></th><td>NUMBER</td><td><code>100</code></td><td></td></tr></tbody></table></div><!-- BEGIN FIXED INPUT HELP --><p id="fixed-input-forEachAtPath-MAX" class="fixed-input-editor">MVP機能を有効にした場合だけ、MAXを整数1〜1000で編集します。入力途中・空白・非finiteな新値は保存できません。NAMEとPATHは変更しません。 GUIのDialogsとFixedInputsは起動時の既定OFFです。両方を有効にして再読込すると固定フォームが使えます。未変更のraw値を保存し直さず、接続reporterは評価しません。</p><!-- END FIXED INPUT HELP --></article><article id="block-currentKey" class="block-reference-entry"><h3><code>current key</code></h3><p>Return the current object key or array index string.</p><p>Block type: REPORTER. Opcode: <code>currentKey</code>. <a href="#block-currentKey">Permanent link</a></p><p>This block has no arguments.</p></article><article id="block-currentIndex" class="block-reference-entry"><h3><code>current index</code></h3><p>Return the zero-based iteration number.</p><p>Block type: REPORTER. Opcode: <code>currentIndex</code>. <a href="#block-currentIndex">Permanent link</a></p><p>This block has no arguments.</p></article><article id="block-currentValueJson" class="block-reference-entry"><h3><code>current value JSON</code></h3><p>Return the current iteration value as JSON.</p><p>Block type: REPORTER. Opcode: <code>currentValueJson</code>. <a href="#block-currentValueJson">Permanent link</a></p><p>This block has no arguments.</p></article>
|
|
56
|
+
<p><a href="https://github.com/kubohiroya/turbowarp-structured-data/blob/main/README.md">Repository guide and examples</a></p>
|
|
57
|
+
</section>
|
|
58
|
+
<!-- END COMPLETE BLOCK REFERENCE -->
|
|
25
59
|
</body>
|
|
26
60
|
</html>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://kubohiroya.github.io/turbowarp-structured-data/schemas/block-editor-fixed-inputs.schema.json",
|
|
4
|
+
"$defs": {
|
|
5
|
+
"forEachAtPath": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"MAX": {
|
|
9
|
+
"type": "integer",
|
|
10
|
+
"minimum": 1,
|
|
11
|
+
"maximum": 1000
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"required": [
|
|
15
|
+
"MAX"
|
|
16
|
+
],
|
|
17
|
+
"additionalProperties": true
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# 段階2 Source/Form編集
|
|
2
|
+
|
|
3
|
+
この文書はローカル実装時の契約を示す。npm公開は実施しない。
|
|
4
|
+
|
|
5
|
+
- 対象: parseJson.TEXT / parseYaml.TEXT / setJsonAtPath.VALUE
|
|
6
|
+
- 契約: json-value
|
|
7
|
+
- Schema正本: 共通エディター src/json-value.ts。Schema文書はcanonical-schema、bundleは正本参照とprovenanceを保持する。
|
|
8
|
+
- owner受理条件: src/codecs.ts / core.ts の各ブロックと同じparse関数。JSON/YAML文書の256KiB、深さ64、ノード50000制限、YAML alias・重複キー・未知tag拒否を維持。setJsonAtPath.VALUEは従来のparseJson契約を維持。Named data名/path候補は段階4。
|
|
9
|
+
|
|
10
|
+
UIはSourceとFormを切り替える。無変更・cancel・編集後の元の値への復帰は入力文字列をそのまま保持する。Formの部分編集でも未知キー・null・空文字・配列の順序と重複・未編集箇所の表記を維持する。既定値の暗黙補完、variant/formatの暗黙移行、runtime正規化後の値の書き戻しは行わない。不正なsourceもSourceとして開き修復できるが、ownerに拒否される候補は保存できない。
|
|
11
|
+
|
|
12
|
+
利用条件は、GUI起動時に `blockEditorDialogs=1` と `blockEditorSourceForms=1` の両方を指定し、信頼した拡張をunsandboxedで読み込むこと。`Scratch.gui.blockEditors` はunsandboxed拡張APIにのみ提供される。既存のsandbox実行権限や拡張の既定の読み込み方法は変更しない。sandboxed実行では従来のブロックを使用し、編集capabilityがないためフォーム登録を省略する。
|
|
13
|
+
|
|
14
|
+
登録入口はoptionalな `Scratch.gui.blockEditors.registerSourceEditor`。GUIの起動時固定 `blockEditorSourceForms` は既定OFF、既存 `blockEditorDialogs` が前提となる。旧GUIやcapabilityを持たないhostでは登録を行わず、既存ブロックのAPI・引数・実行挙動は維持する。`dispose()` またはruntime破棄で登録を解除する。既存のruntime処理を実行せず、pure parser/validatorで保存候補の同じsourceを検査する。複数入力のブロックは単一editor definitionとして一度に検査・commitする。
|
|
15
|
+
|
|
16
|
+
依存: 共通エディターの新 `./schema` 型・json-value契約と新prepared save経路、およびGUIのcapabilityが必要。ローカル検証は独立cloneから新共通artifactへaliasする。遠隔配布用のpin・lockは最終共通artifactのSHA確定後に揃える。架空のSHAを記載しない。
|
|
17
|
+
|
|
18
|
+
受け入れ基準: 全対象inputの登録、既存受理との互換、Source修復、不正保存の拒否、no-opでundoを作らないこと、部分編集でraw値を維持すること、runtime破棄時の解除、既存APIのテスト・型検査・buildを確認する。原文不変・部分編集・拒否は `tests/source-editor.test.ts` から実際の共通serviceと接続して検証する。
|
|
19
|
+
|
|
20
|
+
ロールバック: 起動時 `blockEditorSourceForms` をOFFに戻してGUIを再起動する。登録capabilityを外すと新フォームは使用されず、既存のブロックと保存済みsourceは引き続き実行できる。Schema自体の編集・実行時の値からの動的Schema・値候補との接続は別工程。
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# 段階2の安定版検証記録
|
|
2
|
+
|
|
3
|
+
公開予定版: `@kubohiroya/turbowarp-structured-data@0.6.0`。JSON/YAML のTEXTとpath操作のVALUEを接続し、既存サイズ・深度・node・alias制限を維持します。
|
|
4
|
+
|
|
5
|
+
| opcode | 入力 |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| parseJson | TEXT |
|
|
8
|
+
| parseYaml | TEXT |
|
|
9
|
+
| setJsonAtPath | VALUE |
|
|
10
|
+
|
|
11
|
+
正本は共通 `src/json-value.ts` と既存 `src/codecs.ts` / `src/core.ts` のpure検証です。JSON/YAMLのroot型・配列・object・scalarを明示操作で編集します。runtimeの任意Schemaとの連動は追加しません。
|
|
12
|
+
|
|
13
|
+
共通依存は `76fa1d50a3c188082ceef723ea018a9d8769ea6e`(`@kubohiroya/turbowarp-extension-data-editor` 0.2.0)へGitの完全SHAで固定しています。manifest・lock・build許可・fresh実解決を揃え、直接・AJV経由のfast-uriを3.1.8へ統一しています。古い共有aliasの実解決を安定版の検証として流用していません。
|
|
14
|
+
|
|
15
|
+
`react-dom@18.3.1` は実際のRJSF registration回帰テストに必要なdev依存として追加しました。拡張のruntimeコードはGUIのoptional APIを使い、ReactDOMを拡張bundleへ追加しません。
|
|
16
|
+
|
|
17
|
+
Node v22.23.3 / pnpm 11.11.0で、空の専用storeからscripts有効の `pnpm install --frozen-lockfile` を実施しました。Git prepareから得た共通packageにはsrcが含まれず、build-infoは上記SHAと一致します。
|
|
18
|
+
|
|
19
|
+
- 全テスト 40件、型検査、全lint、build、文書/リポジトリ検査、pack検査が成功しました。
|
|
20
|
+
- production auditはcritical/high/moderate/lowすべて0件です。
|
|
21
|
+
- dist 2件は2回のbuildでSHA-256が一致し、異なるcheckout pathのfresh fixtureと作業cloneでも全件のbytesが一致しました。
|
|
22
|
+
- Vite8を使う場合の生成region行にはpackage storeのpathが入るため、そのマーカー行だけを省きます。licenseコメントと実行コードは保持します。Vite7のrepoにはこの追加処理を適用しません。
|
|
23
|
+
|
|
24
|
+
過去の段階2ローカル全体659件・実GUI5ケース(各8手順)は別の保存済み記録です。今回の数は当該repoのfresh full結果であり、繰り返し実行を合算していません。GitHub CIの結果はPRで別途確認します。
|
|
25
|
+
|
|
26
|
+
GUIの起動時固定・既定OFFの `blockEditorSourceForms` と `blockEditorDialogs` の両方、および信頼した拡張のunsandboxed読込を必要とします。旧API、ブロックのopcode/入力、raw保存形式を保持し、無変更・Cancelでは元の入力を維持します。検査した候補だけを保存し、複数入力はatomicに保存します。Schema自体の編集・動的Schema・既存候補への新規項目追加はこの段階に含みません。
|
|
27
|
+
|
|
28
|
+
ロールバックはflagをOFFにして再読込します。コードを戻す場合はconsumer→producer→共通の逆順でrevertし、manifest・lock・実解決を一体で戻します。以前の公開版 `@kubohiroya/turbowarp-structured-data@0.5.1` へ固定できます。保存形式を自動移行しません。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubohiroya/turbowarp-structured-data",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Named structured data with JSON/YAML codecs and deterministic path operations for TurboWarp.",
|
|
5
5
|
"author": "Hiroya Kubo <hiroya@cuc.ac.jp>",
|
|
6
6
|
"license": "MPL-2.0",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"dist/",
|
|
28
28
|
"docs/",
|
|
29
29
|
"src/",
|
|
30
|
+
"schemas/",
|
|
30
31
|
"templates/",
|
|
31
32
|
"README.md",
|
|
32
33
|
"README.ja.md",
|
|
@@ -47,8 +48,8 @@
|
|
|
47
48
|
"build": "vite build",
|
|
48
49
|
"lint": "eslint src tests scripts vite.config.ts eslint.config.ts",
|
|
49
50
|
"test": "vitest run",
|
|
50
|
-
"docs": "node scripts/generate-readme.ts",
|
|
51
|
-
"docs:check": "node scripts/generate-readme.ts --check",
|
|
51
|
+
"docs": "node scripts/generate-readme.ts && node scripts/generate-fixed-input-docs.mjs",
|
|
52
|
+
"docs:check": "node scripts/generate-readme.ts --check && node scripts/generate-fixed-input-docs.mjs --check",
|
|
52
53
|
"template:readme": "node scripts/apply-readme-template.ts",
|
|
53
54
|
"repo:check": "node scripts/check-repo.ts",
|
|
54
55
|
"pack:check": "npm pack --dry-run --ignore-scripts",
|
|
@@ -57,21 +58,29 @@
|
|
|
57
58
|
},
|
|
58
59
|
"devDependencies": {
|
|
59
60
|
"@eslint/js": "^9.39.5",
|
|
60
|
-
"@kubohiroya/turbowarp-extension-manifest": "0.3.
|
|
61
|
-
"@kubohiroya/turbowarp-named-data": "0.1
|
|
62
|
-
"@kubohiroya/vite-plugin-turbowarp-extension": "0.
|
|
61
|
+
"@kubohiroya/turbowarp-extension-manifest": "0.3.2",
|
|
62
|
+
"@kubohiroya/turbowarp-named-data": "0.3.1",
|
|
63
|
+
"@kubohiroya/vite-plugin-turbowarp-extension": "0.6.1",
|
|
63
64
|
"@types/node": "^24.13.3",
|
|
64
65
|
"eslint": "^9.39.5",
|
|
65
66
|
"jiti": "^2.7.0",
|
|
66
67
|
"typescript": "^5.9.3",
|
|
67
68
|
"typescript-eslint": "^8.66.0",
|
|
68
69
|
"vite": "^8.2.2",
|
|
69
|
-
"vitest": "^5.0.0"
|
|
70
|
+
"vitest": "^5.0.0",
|
|
71
|
+
"react-dom": "18.3.1"
|
|
70
72
|
},
|
|
71
73
|
"dependencies": {
|
|
72
|
-
"yaml": "^2.9.1"
|
|
74
|
+
"yaml": "^2.9.1",
|
|
75
|
+
"@kubohiroya/turbowarp-extension-data-editor": "0.2.1"
|
|
73
76
|
},
|
|
74
77
|
"peerDependencies": {
|
|
75
|
-
"@kubohiroya/turbowarp-named-data": "
|
|
78
|
+
"@kubohiroya/turbowarp-named-data": "0.3.1"
|
|
79
|
+
},
|
|
80
|
+
"gitHead": "7429d0707e0c46099fa89d09f456a43a29919395",
|
|
81
|
+
"x-turbowarp-source": {
|
|
82
|
+
"revision": "7429d0707e0c46099fa89d09f456a43a29919395",
|
|
83
|
+
"revisionRole": "base-commit",
|
|
84
|
+
"sourceState": "local-release-overlay"
|
|
76
85
|
}
|
|
77
86
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://kubohiroya.github.io/turbowarp-structured-data/schemas/block-editor-fixed-inputs.schema.json",
|
|
4
|
+
"$defs": {
|
|
5
|
+
"forEachAtPath": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"MAX": {
|
|
9
|
+
"type": "integer",
|
|
10
|
+
"minimum": 1,
|
|
11
|
+
"maximum": 1000
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"required": [
|
|
15
|
+
"MAX"
|
|
16
|
+
],
|
|
17
|
+
"additionalProperties": true
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type {SourceEditorOptions} from '@kubohiroya/turbowarp-extension-data-editor/schema';
|
|
2
|
+
import {extensionConfig} from './config.js';
|
|
3
|
+
import {sourceBinding} from './source-editor.js';
|
|
4
|
+
import {jsonValueSchemaBundle} from '@kubohiroya/turbowarp-extension-data-editor/schema';
|
|
5
|
+
import {parseJsonDocument, parseYamlDocument} from './codecs.js';
|
|
6
|
+
import {parseJson} from './core.js';
|
|
7
|
+
const definitions = [
|
|
8
|
+
{editorId: 'json-document-source', opcodes: ['parseJson'], bindings: [sourceBinding('TEXT', jsonValueSchemaBundle, parseJsonDocument)]},
|
|
9
|
+
{editorId: 'yaml-document-source', opcodes: ['parseYaml'], bindings: [sourceBinding('TEXT', jsonValueSchemaBundle, parseYamlDocument, parseYamlDocument, 'yaml')]},
|
|
10
|
+
{editorId: 'json-path-value-source', opcodes: ['setJsonAtPath'], bindings: [sourceBinding('VALUE', jsonValueSchemaBundle, parseJson)]}
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
export const sourceEditorDefinitions: readonly SourceEditorOptions[] = definitions.map(({editorId, opcodes, bindings}) => ({
|
|
14
|
+
apiVersion: 1, extensionId: extensionConfig.id, editorId, opcodes: opcodes.map(opcode => `${extensionConfig.id}_${opcode}`), bindings,
|
|
15
|
+
validationContext: () => ({consumerId: extensionConfig.id, nowMs: Date.now(), settings: null})
|
|
16
|
+
}));
|
package/src/extension.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {fixedInputEditorDefinitions, registerFixedInputEditors} from './fixed-input-editors.js';
|
|
2
|
+
import {sourceEditorDefinitions} from './editor-schema.js';
|
|
3
|
+
import {registerSourceEditors} from './source-editor.js';
|
|
1
4
|
import definitions from './block-definitions.json';
|
|
2
5
|
import {
|
|
3
6
|
bindNamedDataRegistryLifecycle,
|
|
@@ -72,6 +75,10 @@ const blockDefinitions = definitions.blocks as readonly BlockDefinition[];
|
|
|
72
75
|
|
|
73
76
|
export class StructuredDataExtension implements TurboWarpExtension {
|
|
74
77
|
private readonly enabled: boolean;
|
|
78
|
+
private disposed = false;
|
|
79
|
+
private readonly releaseRuntimeListeners: () => void;
|
|
80
|
+
private readonly unregisterSourceEditors: () => void;
|
|
81
|
+
private readonly unregisterFixedInputEditors: () => void;
|
|
75
82
|
private registries = new WeakMap<object, Map<string, StructuredDataBinding>>();
|
|
76
83
|
private iterationStacks = new WeakMap<object, ActiveIteration[]>();
|
|
77
84
|
private nextRevision = 1;
|
|
@@ -85,6 +92,18 @@ export class StructuredDataExtension implements TurboWarpExtension {
|
|
|
85
92
|
namedDataEnabled = isNamedDataRegistryMvpEnabled()
|
|
86
93
|
) {
|
|
87
94
|
this.enabled = enabled;
|
|
95
|
+
this.unregisterSourceEditors = registerSourceEditors(Scratch, enabled ? sourceEditorDefinitions : []);
|
|
96
|
+
const runtime = Scratch.vm?.runtime;
|
|
97
|
+
const onDispose = () => {void this.dispose();};
|
|
98
|
+
const onStop = () => this.clearRuntimeState();
|
|
99
|
+
this.releaseRuntimeListeners = () => {
|
|
100
|
+
runtime?.off?.('RUNTIME_DISPOSED', onDispose);
|
|
101
|
+
runtime?.off?.('PROJECT_STOP_ALL', onStop);
|
|
102
|
+
};
|
|
103
|
+
let unregisterFixed = () => {};
|
|
104
|
+
try {
|
|
105
|
+
unregisterFixed = registerFixedInputEditors(Scratch, enabled ? fixedInputEditorDefinitions : []);
|
|
106
|
+
this.unregisterFixedInputEditors = unregisterFixed;
|
|
88
107
|
if (namedDataEnabled) {
|
|
89
108
|
this.namedDataProvider = new StructuredDataNamedDataProvider({
|
|
90
109
|
get: (target, name) => this.registries.get(target)?.get(name)
|
|
@@ -100,12 +119,18 @@ export class StructuredDataExtension implements TurboWarpExtension {
|
|
|
100
119
|
runtime,
|
|
101
120
|
this.namedDataRegistry
|
|
102
121
|
);
|
|
103
|
-
runtime.on?.('RUNTIME_DISPOSED',
|
|
104
|
-
void this.dispose();
|
|
105
|
-
});
|
|
122
|
+
runtime.on?.('RUNTIME_DISPOSED', onDispose);
|
|
106
123
|
}
|
|
107
124
|
}
|
|
108
|
-
|
|
125
|
+
runtime?.on?.('PROJECT_STOP_ALL', onStop);
|
|
126
|
+
} catch (error) {
|
|
127
|
+
this.releaseRuntimeListeners();
|
|
128
|
+
unregisterFixed();
|
|
129
|
+
this.unregisterSourceEditors();
|
|
130
|
+
this.unbindNamedDataRegistryLifecycle?.();
|
|
131
|
+
void this.namedDataRegistration?.unregister().catch(() => {});
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
109
134
|
}
|
|
110
135
|
|
|
111
136
|
public getNamedDataProvider(): StructuredDataNamedDataProvider | undefined {
|
|
@@ -117,6 +142,11 @@ export class StructuredDataExtension implements TurboWarpExtension {
|
|
|
117
142
|
}
|
|
118
143
|
|
|
119
144
|
public async dispose(): Promise<void> {
|
|
145
|
+
if (this.disposed) return;
|
|
146
|
+
this.disposed = true;
|
|
147
|
+
this.releaseRuntimeListeners();
|
|
148
|
+
this.unregisterFixedInputEditors();
|
|
149
|
+
this.unregisterSourceEditors();
|
|
120
150
|
await this.namedDataRegistration?.unregister();
|
|
121
151
|
this.unbindNamedDataRegistryLifecycle?.();
|
|
122
152
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import {parseFixedNumberInput} from '@kubohiroya/turbowarp-extension-data-editor';
|
|
2
|
+
import type {FixedInputEditorOptions} from '@kubohiroya/turbowarp-extension-data-editor';
|
|
3
|
+
import {extensionConfig} from './config.js';
|
|
4
|
+
import {fixedInputSchemaBundle} from './fixed-input-schema.js';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export const fixedInputEditorDefinitions: readonly FixedInputEditorOptions[] = [{
|
|
8
|
+
apiVersion: 1, extensionId: extensionConfig.id, editorId: 'forEachAtPath-fixed-inputs',
|
|
9
|
+
opcodes: [`${extensionConfig.id}_forEachAtPath`],
|
|
10
|
+
contractId: 'turbowarp-structured-data:forEachAtPath.MAX', contractRevision: 'fixed-inputs-v1',
|
|
11
|
+
bindings: [{argument: 'MAX', schemaBundle: fixedInputSchemaBundle,
|
|
12
|
+
control: {kind: 'number', label: 'MAX'},
|
|
13
|
+
read(value) {
|
|
14
|
+
if (typeof value !== 'string' && typeof value !== 'number') throw new TypeError('Expected a literal maximum.');
|
|
15
|
+
if (typeof value === 'string' && value.trim() === '') throw new TypeError('Blank maximum stays readonly.');
|
|
16
|
+
// Existing nonempty finite Number aliases may project; no-op saving retains the exact raw token.
|
|
17
|
+
const number = Number(value);
|
|
18
|
+
if (!Number.isFinite(number)) throw new TypeError('Maximum must be finite.');
|
|
19
|
+
return number;
|
|
20
|
+
},
|
|
21
|
+
encode(value) {
|
|
22
|
+
const parsed = parseFixedNumberInput(value);
|
|
23
|
+
if (parsed.kind !== 'valid') throw new TypeError('Expected a finite numeric token.');
|
|
24
|
+
return parsed.token;
|
|
25
|
+
},
|
|
26
|
+
validateCandidate(value) {
|
|
27
|
+
const parsed = parseFixedNumberInput(value);
|
|
28
|
+
return parsed.kind === 'valid' && Number.isInteger(parsed.value) && parsed.value >= 1 && parsed.value <= 1000 ? []
|
|
29
|
+
: [{path: '/inputs/MAX', message: 'Maximum must be an integer from 1 to 1000.'}];
|
|
30
|
+
}
|
|
31
|
+
}],
|
|
32
|
+
validationContext: () => ({consumerId: extensionConfig.id, nowMs: Date.now(), settings: null})
|
|
33
|
+
}];
|
|
34
|
+
|
|
35
|
+
interface RuntimeLifetime {
|
|
36
|
+
on?: (event: string, listener: () => void) => void;
|
|
37
|
+
off?: (event: string, listener: () => void) => void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Register metadata only; the GUI startup capability owns editor activation. */
|
|
41
|
+
export function registerFixedInputEditors(
|
|
42
|
+
scratch: unknown, definitions: readonly FixedInputEditorOptions[], runtimeOverride?: RuntimeLifetime
|
|
43
|
+
): () => void {
|
|
44
|
+
const host = scratch as {gui?: {blockEditors?: {apiVersion?: number;
|
|
45
|
+
registerFixedInputEditor?: (options: FixedInputEditorOptions) => () => void}};
|
|
46
|
+
vm?: {runtime?: RuntimeLifetime}};
|
|
47
|
+
const api = host.gui?.blockEditors;
|
|
48
|
+
if (!definitions.length || api?.apiVersion !== 1 || typeof api.registerFixedInputEditor !== 'function') return () => {};
|
|
49
|
+
const runtime = runtimeOverride ?? host.vm?.runtime;
|
|
50
|
+
const removers: (() => void)[] = [];
|
|
51
|
+
let active = true;
|
|
52
|
+
const dispose = () => {
|
|
53
|
+
if (!active) return;
|
|
54
|
+
active = false;
|
|
55
|
+
runtime?.off?.('RUNTIME_DISPOSED', dispose);
|
|
56
|
+
for (const remove of removers.splice(0).reverse()) remove();
|
|
57
|
+
};
|
|
58
|
+
try {
|
|
59
|
+
for (const definition of definitions) {
|
|
60
|
+
const remove = api.registerFixedInputEditor.call(api, definition);
|
|
61
|
+
if (typeof remove !== 'function') throw new TypeError('Invalid fixed input registration disposer.');
|
|
62
|
+
removers.push(remove);
|
|
63
|
+
}
|
|
64
|
+
runtime?.on?.('RUNTIME_DISPOSED', dispose);
|
|
65
|
+
} catch (error) {dispose(); throw error;}
|
|
66
|
+
return dispose;
|
|
67
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type {SchemaBundle} from '@kubohiroya/turbowarp-extension-data-editor/schema';
|
|
2
|
+
import document from '../schemas/block-editor-fixed-inputs.schema.json';
|
|
3
|
+
|
|
4
|
+
const source = {repository: 'turbowarp-structured-data', path: 'schemas/block-editor-fixed-inputs.schema.json',
|
|
5
|
+
symbol: '#/$defs/forEachAtPath/properties/MAX'};
|
|
6
|
+
|
|
7
|
+
/** The on-disk owner Schema is canonical; this is its single-field projection. */
|
|
8
|
+
export const fixedInputSchemaBundle: SchemaBundle = {
|
|
9
|
+
identity: {ownerId: 'turbowarp-structured-data', contractId: 'forEachAtPath.MAX', revision: 'fixed-inputs-v1', variantId: 'default'},
|
|
10
|
+
dialect: '2020-12',
|
|
11
|
+
root: {retrievalUri: 'https://kubohiroya.github.io/turbowarp-structured-data/schemas/forEachAtPath-MAX.schema.json',
|
|
12
|
+
document: document.$defs.forEachAtPath.properties.MAX, artifact: {role: 'canonical-schema', source}},
|
|
13
|
+
resources: [],
|
|
14
|
+
provenance: {canonicalSources: [source, {repository: 'turbowarp-structured-data', path: 'src/core.ts', symbol: 'iterationEntries'}],
|
|
15
|
+
generatedFiles: [{repository: 'turbowarp-structured-data', path: 'docs/schemas/block-editor-fixed-inputs.schema.json'}], referenceSchemas: [], generationSources: [{repository: 'turbowarp-structured-data', path: 'scripts/generate-fixed-input-docs.mjs'}]}
|
|
16
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import {compileSchemaBundle, validateSchemaInput} from '@kubohiroya/turbowarp-extension-data-editor/schema';
|
|
2
|
+
import type {SchemaBundle, SchemaDocument, SchemaJsonValue, SourceBinding, SourceEditorOptions} from '@kubohiroya/turbowarp-extension-data-editor/schema';
|
|
3
|
+
|
|
4
|
+
export function canonicalBundle(ownerId: string, contractId: string, document: SchemaDocument, ownerSource: {path: string; symbol: string}): SchemaBundle {
|
|
5
|
+
const path = `schemas/${contractId}.schema.json`;
|
|
6
|
+
const source = {repository: ownerId, path};
|
|
7
|
+
return {
|
|
8
|
+
identity: {ownerId, contractId, revision: 'source-forms-v1', variantId: 'default'},
|
|
9
|
+
dialect: '2020-12',
|
|
10
|
+
root: {retrievalUri: `https://kubohiroya.github.io/${ownerId}/schemas/${contractId}.schema.json`, document,
|
|
11
|
+
artifact: {role: 'canonical-schema', source}},
|
|
12
|
+
resources: [], provenance: {canonicalSources: [source, {repository: ownerId, ...ownerSource}], generatedFiles: [], referenceSchemas: [], generationSources: []}
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function sourceBinding(argument: string, bundle: SchemaBundle,
|
|
17
|
+
read: (source: string) => unknown, check: (source: string) => unknown = read,
|
|
18
|
+
format: 'json' | 'yaml' = 'json', uiSchema?: SourceBinding['variants'][number]['uiSchema']): SourceBinding {
|
|
19
|
+
const compiled = compileSchemaBundle(bundle);
|
|
20
|
+
return {
|
|
21
|
+
argument,
|
|
22
|
+
variants: [{variantId: 'default', format, schemaBundle: bundle, ...(uiSchema ? {uiSchema} : {})}],
|
|
23
|
+
decode(source) {return {source, format, variantId: 'default', data: read(source) as SchemaJsonValue};},
|
|
24
|
+
validateSource(source, context) {
|
|
25
|
+
if (compiled.kind !== 'compiled') return {source, result: {kind: 'schema-error', diagnostics: [{code: 'source-schema-invalid'}]}};
|
|
26
|
+
try {
|
|
27
|
+
const data = read(source) as SchemaJsonValue;
|
|
28
|
+
return {source, result: validateSchemaInput(compiled.validator, data, {context,
|
|
29
|
+
ownerValidate: () => {
|
|
30
|
+
try {check(source); return {kind: 'valid', issues: []};}
|
|
31
|
+
catch {return {kind: 'invalid', issues: [{dataPath: '', ruleId: 'source-owner-invalid'}]};}
|
|
32
|
+
}})};
|
|
33
|
+
} catch {return {source, result: {kind: 'invalid', diagnostics: [{code: 'source-decode-invalid'}]}};}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** The optional capability keeps legacy hosts and the startup flag safely inactive. */
|
|
39
|
+
export function registerSourceEditors(scratch: unknown, definitions: readonly SourceEditorOptions[]): () => void {
|
|
40
|
+
const host = scratch as {gui?: {blockEditors?: {apiVersion?: number; registerSourceEditor?: (options: SourceEditorOptions) => () => void}};
|
|
41
|
+
vm?: {runtime?: {on?: (event: string, listener: () => void) => void; off?: (event: string, listener: () => void) => void}}};
|
|
42
|
+
const api = host.gui?.blockEditors;
|
|
43
|
+
if (api?.apiVersion !== 1 || typeof api.registerSourceEditor !== 'function') return () => {};
|
|
44
|
+
const removers: (() => void)[] = [];
|
|
45
|
+
let active = true;
|
|
46
|
+
const dispose = () => {
|
|
47
|
+
if (!active) return;
|
|
48
|
+
active = false;
|
|
49
|
+
host.vm?.runtime?.off?.('RUNTIME_DISPOSED', dispose);
|
|
50
|
+
for (const remove of removers.splice(0).reverse()) remove();
|
|
51
|
+
};
|
|
52
|
+
try {
|
|
53
|
+
for (const definition of definitions) removers.push(api.registerSourceEditor.call(api, definition));
|
|
54
|
+
host.vm?.runtime?.on?.('RUNTIME_DISPOSED', dispose);
|
|
55
|
+
} catch (error) {dispose(); throw error;}
|
|
56
|
+
return dispose;
|
|
57
|
+
}
|
package/templates/README.ja.md
CHANGED
|
@@ -181,3 +181,16 @@ release consistency checkでは、exact-version README/CDN例に加え、`docs
|
|
|
181
181
|
|
|
182
182
|
third-party componentを含む場合は
|
|
183
183
|
[`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md)に記載します。
|
|
184
|
+
|
|
185
|
+
## 固定引数の編集フォーム(S3-4)
|
|
186
|
+
|
|
187
|
+
共通エディターの起動時フラグ `blockEditorFixedInputs` とDialogsがONのGUIでは、`forEachAtPath` の `MAX` だけを固定フォームとして登録します。旧GUI・フラグOFFでは追加登録を行いません。Schemaの正本は `schemas/block-editor-fixed-inputs.schema.json#/$defs/forEachAtPath/properties/MAX`、codecと登録は `src/fixed-input-editors.ts` です。既存raw値・未変更alias・未知enumは無操作保存で書き換えず、reporterを評価しません。明示変更だけを検査し、他の引数やブロック宣言、保存形式を変更しません。
|
|
188
|
+
|
|
189
|
+
MAXは整数1〜1000です。新しい入力には共通の有限数値token規則も適用し、途中入力を保存しません。MVP flagがOFFなら登録せず、NAME/PATH・staticLiteral由来の接続可否を変更しません。
|
|
190
|
+
|
|
191
|
+
登録はoptional API(apiVersion:1)に限定し、RUNTIME_DISPOSED/明示disposeで解除します。起動フラグOFF+再読込で従来経路へ切り戻せます。依存を戻す場合はmanifest/lock/実解決を一組で復旧します。npm公開や後続段階の動的候補は含みません。
|
|
192
|
+
|
|
193
|
+
Schemaが記述する契約の根拠は実getInfoの宣言と既存の純粋なruntime変換です。SchemaBundleのretrievalUriはこのローカル文書の識別子であり、URL配信済み・HTTP取得によるref解決を意味しません。Schemaは同梱文書だけでcompileします。
|
|
194
|
+
既存MAXの非空finiteなNumber alias(例`001`・`+1`・`0x10`)はNumberによる表示投影だけを行い、無変更rawを保存し直しません。空白・非finite・投影不能値はreadonlyとし、0/defaultを補いません。新しい入力にはこれらaliasを許可せずNP-finite-new-input-v1を適用します。
|
|
195
|
+
|
|
196
|
+
登録は拡張インスタンスの構築時に存在する任意の editor API を使用します。後からの API 追加や差し替えには自動追従しません。起動設定を変更した場合は GUI を再読み込みし、拡張インスタンスを再構築してください。
|
package/templates/README.md
CHANGED
|
@@ -196,3 +196,16 @@ site and `blockIconURI` remains a `data:image/svg+xml;base64,...` URI.
|
|
|
196
196
|
|
|
197
197
|
Third-party components, when present, are listed in
|
|
198
198
|
[`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md).
|
|
199
|
+
|
|
200
|
+
## 固定引数の編集フォーム(S3-4)
|
|
201
|
+
|
|
202
|
+
共通エディターの起動時フラグ `blockEditorFixedInputs` とDialogsがONのGUIでは、`forEachAtPath` の `MAX` だけを固定フォームとして登録します。旧GUI・フラグOFFでは追加登録を行いません。Schemaの正本は `schemas/block-editor-fixed-inputs.schema.json#/$defs/forEachAtPath/properties/MAX`、codecと登録は `src/fixed-input-editors.ts` です。既存raw値・未変更alias・未知enumは無操作保存で書き換えず、reporterを評価しません。明示変更だけを検査し、他の引数やブロック宣言、保存形式を変更しません。
|
|
203
|
+
|
|
204
|
+
MAXは整数1〜1000です。新しい入力には共通の有限数値token規則も適用し、途中入力を保存しません。MVP flagがOFFなら登録せず、NAME/PATH・staticLiteral由来の接続可否を変更しません。
|
|
205
|
+
|
|
206
|
+
登録はoptional API(apiVersion:1)に限定し、RUNTIME_DISPOSED/明示disposeで解除します。起動フラグOFF+再読込で従来経路へ切り戻せます。依存を戻す場合はmanifest/lock/実解決を一組で復旧します。npm公開や後続段階の動的候補は含みません。
|
|
207
|
+
|
|
208
|
+
Schemaが記述する契約の根拠は実getInfoの宣言と既存の純粋なruntime変換です。SchemaBundleのretrievalUriはこのローカル文書の識別子であり、URL配信済み・HTTP取得によるref解決を意味しません。Schemaは同梱文書だけでcompileします。
|
|
209
|
+
既存MAXの非空finiteなNumber alias(例`001`・`+1`・`0x10`)はNumberによる表示投影だけを行い、無変更rawを保存し直しません。空白・非finite・投影不能値はreadonlyとし、0/defaultを補いません。新しい入力にはこれらaliasを許可せずNP-finite-new-input-v1を適用します。
|
|
210
|
+
|
|
211
|
+
Registration uses the optional editor API available when the extension instance is constructed. Adding or replacing that API later is not followed automatically; reload the GUI and reconstruct the extension instance after changing the startup configuration.
|