@kubohiroya/turbowarp-structured-data 0.4.0
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/LICENSE +373 -0
- package/README.ja.md +73 -0
- package/README.md +245 -0
- package/THIRD_PARTY_NOTICES.md +25 -0
- package/dist/extension-manifest.json +426 -0
- package/dist/structured-data.js +7071 -0
- package/docs/architecture.ja.md +32 -0
- package/docs/architecture.md +30 -0
- package/docs/index.html +26 -0
- package/docs/named-data-integration-plan.ja.md +375 -0
- package/package.json +77 -0
- package/schemas/extension-manifest.schema.json +103 -0
- package/src/block-definitions.json +98 -0
- package/src/codecs.ts +204 -0
- package/src/config.ts +31 -0
- package/src/core.ts +309 -0
- package/src/extension-manifest.ts +176 -0
- package/src/extension.ts +361 -0
- package/src/globals.d.ts +38 -0
- package/src/index.ts +8 -0
- package/src/structured-provider.ts +188 -0
- package/templates/README.ja.md +183 -0
- package/templates/README.md +198 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# アーキテクチャ
|
|
2
|
+
|
|
3
|
+
[English](architecture.md)
|
|
4
|
+
|
|
5
|
+
任意のNamed Data統合は、canonical契約とruntime共有registryを
|
|
6
|
+
`@kubohiroya/turbowarp-named-data/composition`からimportします。`structured` providerは
|
|
7
|
+
`kind: structured`、target scope、persistent登録として接続します。`PROJECT_STOP_ALL`では
|
|
8
|
+
target bindingとopen bodyをclearしますが、次のproject sessionでもprovider登録を維持します。
|
|
9
|
+
|
|
10
|
+
structured-data、document-data、binary-data、Asset Manager、HTTP Serverを名前付き参照とHTTP body供給契約で接続する段階計画は[Named Data統合計画](named-data-integration-plan.ja.md)を参照してください。
|
|
11
|
+
|
|
12
|
+
## 名前付きデータmodel
|
|
13
|
+
|
|
14
|
+
機能拡張は`WeakMap<Target, Map<Name, JsonValue>>`を所有します。nameはtrim済みの空でないstringです。spriteとstageは別namespaceです。parseはbindingをatomicに置換し、path更新は新しいJSON valueを構築して検証成功後だけbindingを置換します。`PROJECT_STOP_ALL`でregistryとiteration stackを交換するため、runtime stateはproject停止後に残りません。
|
|
15
|
+
|
|
16
|
+
JSON valueは`null`、boolean、有限number、string、array、own enumerable propertyだけを持つobjectです。opaqueな内部tokenを公開block境界へ渡しません。Scratch reporter型の制約により必要なparse、render、set value、get value、keys、current value境界だけでJSON/YAML textを使います。
|
|
17
|
+
|
|
18
|
+
## codecと上限
|
|
19
|
+
|
|
20
|
+
`src/codecs.ts`はJSONを共有core、YAMLをYAML ASTでparseします。両方とも入力256 KiB、深さ64、50,000 nodeを上限とします。YAML alias、parser warning、duplicate key、unknown tag、string以外のkey、未対応scalarはnamespace binding変更前に失敗します。
|
|
21
|
+
|
|
22
|
+
canonical JSONはobject keyを再帰的にUnicodeコードポイント順へ揃えます。YAMLも同じ順序を使い、string scalarをquoteし、identifier形式のkeyだけをquoteなしで出力します。
|
|
23
|
+
|
|
24
|
+
## pathと反復
|
|
25
|
+
|
|
26
|
+
`src/core.ts`は制限付きpathを型付きkey/index segmentへ変換し、不変get、has、set、delete、keys、length、iteration entry生成を実装します。loop entry snapshotは決定的です。active loop frameはTurboWarp threadをkeyとする別の`WeakMap`に保持し、nested loopはstackになります。
|
|
27
|
+
|
|
28
|
+
## compiler manifest v3
|
|
29
|
+
|
|
30
|
+
manifestはtarget scope、project停止までのlifetime、`jsonValue`内容を持つnamed referenceを宣言します。各opcodeはargument、result型、effect(`pure`、`state`、`control`)、error、IR v2 operationを持ちます。server adapterは同等のtarget-local slot環境を提供し、未対応manifest versionを拒否します。
|
|
31
|
+
|
|
32
|
+
`tests/fixtures/semantic-parity.json`をnamespace、codec、path、結果、error意味論のbrowser/server共通契約とします。
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
[日本語](architecture.ja.md)
|
|
4
|
+
|
|
5
|
+
The optional Named Data integration imports its canonical contract and shared runtime registry from
|
|
6
|
+
`@kubohiroya/turbowarp-named-data/composition`. The `structured` provider is registered with
|
|
7
|
+
`kind: structured`, target scope, and persistent registration. `PROJECT_STOP_ALL` clears target
|
|
8
|
+
bindings and open bodies but retains the provider registration for the next project session.
|
|
9
|
+
|
|
10
|
+
## Named data model
|
|
11
|
+
|
|
12
|
+
The extension owns a `WeakMap<Target, Map<Name, JsonValue>>`. Names are trimmed, non-empty strings. A sprite and the stage have separate namespaces. Parsing replaces a binding atomically; path updates construct a new JSON value and replace the binding only after validation succeeds. `PROJECT_STOP_ALL` replaces the registries and iteration stacks, so runtime state does not survive a project stop.
|
|
13
|
+
|
|
14
|
+
JSON values are `null`, booleans, finite numbers, strings, arrays, and objects with own enumerable properties. They never cross the public block boundary as opaque internal tokens. JSON/YAML text appears only at parse, render, set-value, get-value, keys, and current-value boundaries required by Scratch reporter types.
|
|
15
|
+
|
|
16
|
+
## Codecs and limits
|
|
17
|
+
|
|
18
|
+
`src/codecs.ts` parses JSON through the shared core and YAML through the YAML AST. Both enforce 256 KiB input, depth 64, and 50,000 nodes. YAML aliases, parser warnings, duplicate keys, unknown tags, non-string keys, and unsupported scalars fail before a namespace binding changes.
|
|
19
|
+
|
|
20
|
+
Canonical JSON recursively sorts object keys by Unicode code point. YAML uses the same ordering, quotes string scalars, and only leaves identifier-like keys unquoted.
|
|
21
|
+
|
|
22
|
+
## Paths and iteration
|
|
23
|
+
|
|
24
|
+
`src/core.ts` converts restricted string paths to typed key/index segments and implements immutable get, has, set, delete, keys, length, and iteration entry generation. Loop entry snapshots are deterministic. Active loop frames are held in a separate `WeakMap` keyed by TurboWarp thread; nested loops form a stack.
|
|
25
|
+
|
|
26
|
+
## Compiler manifest v3
|
|
27
|
+
|
|
28
|
+
The manifest declares a named reference with target scope, lifetime until project stop, and `jsonValue` contents. Each opcode provides arguments, result type, effect (`pure`, `state`, or `control`), possible errors, and its IR v2 operation. Server adapters must provide an equivalent target-local slot environment and reject unsupported manifest versions.
|
|
29
|
+
|
|
30
|
+
`tests/fixtures/semantic-parity.json` is the portable browser/server contract for namespace, codec, path, result, and error semantics.
|
package/docs/index.html
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<title>Structured Data documentation</title>
|
|
7
|
+
<style>
|
|
8
|
+
body{font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;max-width:900px;margin:0 auto;padding:2rem;line-height:1.6;color:#222}
|
|
9
|
+
code{background:#f3f3f3;padding:.1em .3em;border-radius:.25em}
|
|
10
|
+
pre{background:#f6f8fa;padding:1rem;overflow:auto;border-radius:.5rem}
|
|
11
|
+
</style>
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<h1>Structured Data</h1>
|
|
15
|
+
<p>Named structured data with safe JSON/YAML codecs and deterministic path operations.</p>
|
|
16
|
+
|
|
17
|
+
<h2>Blocks</h2>
|
|
18
|
+
<p>Parse JSON or YAML into a target-local name, update it with restricted paths, iterate with an explicit bound, and render it back to JSON or YAML.</p>
|
|
19
|
+
|
|
20
|
+
<h2>Enable the MVP</h2>
|
|
21
|
+
<p>Set <code>globalThis.STRUCTURED_DATA_MVP = true</code> in the TurboWarp page, then load <code>structured-data.js</code> with <strong>Run extension without sandbox</strong> enabled. Start with <code>parse JSON ... as ...</code> or <code>parse YAML ... as ...</code>.</p>
|
|
22
|
+
|
|
23
|
+
<h2>Development</h2>
|
|
24
|
+
<p>See the repository README and architecture documentation for build, test, release, and compatibility details.</p>
|
|
25
|
+
</body>
|
|
26
|
+
</html>
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
# Named Data統合計画
|
|
2
|
+
|
|
3
|
+
## 目的
|
|
4
|
+
|
|
5
|
+
structured-data、将来のdocument-dataとbinary-data、既存のAsset Manager、HTTP Serverを、名前付きデータ参照とHTTP body供給契約で接続する。
|
|
6
|
+
|
|
7
|
+
共通化する対象は各データ型の内部表現や編集APIではない。HTTPレスポンスへ安全に変換できる名前付きresourceの識別、metadata、解決、lifetime、error意味論を共通化する。HTTP ServerはJSON、YAML、HTML、Markdown、画像、音声その他のbinaryを、各providerのprivate stateへ依存せずresponse bodyとして利用できるようにする。
|
|
8
|
+
|
|
9
|
+
## 現状と課題
|
|
10
|
+
|
|
11
|
+
### structured-data
|
|
12
|
+
|
|
13
|
+
- targetごとの名前付きregistryにJSON valueを保持する
|
|
14
|
+
- JSON/YAMLのparseとserialize、path操作、反復を提供する
|
|
15
|
+
- registryは機能拡張内部に閉じており、別の機能拡張から名前を解決できない
|
|
16
|
+
- valueはproject停止時に破棄され、project fileへ永続化しない
|
|
17
|
+
|
|
18
|
+
### Asset Manager
|
|
19
|
+
|
|
20
|
+
- 名前付きasset registryで画像、音声、text、project assetを扱う
|
|
21
|
+
- APIではArrayBufferまたはUint8Arrayを名前付きassetとして登録できる
|
|
22
|
+
- composition APIにはnamespaceとnameを使うbinary bundle storeがある
|
|
23
|
+
- Asset Manager固有のasset操作と汎用binary resourceの責務が一部重なる
|
|
24
|
+
|
|
25
|
+
### HTTP Server
|
|
26
|
+
|
|
27
|
+
- `/@assets/<name>`で外部capabilityが提供する名前付きresourceを配信できる
|
|
28
|
+
- handler blockのresponse bodyは主にtext、HTML、JSON文字列を受け取る
|
|
29
|
+
- IR v2には再利用可能なbinary-refと、一回だけ消費できるbinary-bodyがある
|
|
30
|
+
- structured-dataやdocument-dataの名前を共通response bodyとして解決する契約がない
|
|
31
|
+
|
|
32
|
+
各機能拡張が独自registryとHTTP連携を実装すると、名前のscope、MIME type、byte上限、stream ownership、error code、停止時の解放が重複して不整合になる。
|
|
33
|
+
|
|
34
|
+
## 設計原則
|
|
35
|
+
|
|
36
|
+
1. 名前付き参照をbyte列やdata URLとしてScratch reporterへ埋め込まない。
|
|
37
|
+
2. JSON/YAML、HTML/Markdown、binaryの保存形式と編集意味論は各providerが所有する。
|
|
38
|
+
3. HTTP Serverはproviderの内部表現を参照せず、共通body resolverだけを利用する。
|
|
39
|
+
4. 暗黙変換を避け、representationとMIME typeを明示またはproviderの既定値から決定する。
|
|
40
|
+
5. requestのstream bodyと、保存済みnamed dataを別の型として扱う。
|
|
41
|
+
6. size、depth、node count、byte count、stream消費回数に上限を設ける。
|
|
42
|
+
7. 段階導入は既定OFFの起動時feature flagで行う。
|
|
43
|
+
8. browser runtimeとserver compilerで参照、error、lifetime意味論を一致させる。
|
|
44
|
+
|
|
45
|
+
## 対象モデル
|
|
46
|
+
|
|
47
|
+
| provider | 入出力形式 | 内部表現 | provider固有の操作 |
|
|
48
|
+
|---|---|---|---|
|
|
49
|
+
| structured-data | JSON、YAML | JSON value | path参照、更新、削除、key列挙、反復 |
|
|
50
|
+
| document-data | HTML、Markdown | kindを保持するdocument treeまたはAST | selector、属性、text、子node、render |
|
|
51
|
+
| binary-data | 任意のMIME | bytesまたはstream backing | size、digest、range、import、export |
|
|
52
|
+
| Asset Manager | 画像、音声、costume、backdrop、runtime text | asset binding | render、play、sprite/stage適用 |
|
|
53
|
+
|
|
54
|
+
Asset Managerはbinary-dataの置き換えではない。汎用binaryを画像や音声として利用するconsumer兼specialized providerとする。
|
|
55
|
+
|
|
56
|
+
### 共通参照
|
|
57
|
+
|
|
58
|
+
共通参照は次の論理fieldを持つ。
|
|
59
|
+
|
|
60
|
+
| field | 意味 |
|
|
61
|
+
|---|---|
|
|
62
|
+
| namespace | providerまたは用途の衝突を避ける安定ID |
|
|
63
|
+
| name | namespace内の論理名 |
|
|
64
|
+
| kind | structured、document、binary、asset |
|
|
65
|
+
| scope | targetまたはproject |
|
|
66
|
+
|
|
67
|
+
target scopeはsprite/stageごとに分離し、project scopeはHTTP公開resourceや共有assetに使用する。Scratch blockでは当面namespaceとnameを別argumentとして渡す。未検証のJSON文字列や区切り文字入りtokenを参照形式にしない。
|
|
68
|
+
|
|
69
|
+
初期namespaceはstructured、document、binary、assetを予約する。providerの二重登録、unknown namespace、kind不一致、scope不一致は安定errorとして拒否する。
|
|
70
|
+
|
|
71
|
+
### 共通metadata
|
|
72
|
+
|
|
73
|
+
| field | 規則 |
|
|
74
|
+
|---|---|
|
|
75
|
+
| mediaType | parameterを含む正規化済みMIME type |
|
|
76
|
+
| byteLength | encode前に確定できない場合は省略可能 |
|
|
77
|
+
| digest | 利用可能ならsha256とlowercase hexadecimal |
|
|
78
|
+
| revision | atomic replacementを識別し、ETag生成に利用可能 |
|
|
79
|
+
| replayable | 保存済みnamed dataでは原則true |
|
|
80
|
+
|
|
81
|
+
### HTTP body供給契約
|
|
82
|
+
|
|
83
|
+
providerはstatとopenBodyを提供する。openBodyは次を返す。
|
|
84
|
+
|
|
85
|
+
- mediaType
|
|
86
|
+
- 任意のbyteLength、digest
|
|
87
|
+
- revision
|
|
88
|
+
- Uint8ArrayまたはReadableStream
|
|
89
|
+
- 必要な場合のrelease callback
|
|
90
|
+
|
|
91
|
+
HTTP Serverはこの結果からContent-Type、可能ならContent-LengthとETagを設定する。client切断時はAbortSignalを伝播し、完了または失敗時にreleaseを高々一回呼ぶ。
|
|
92
|
+
|
|
93
|
+
| kind | representation | MIME type |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| structured | json | application/json; charset=utf-8 |
|
|
96
|
+
| structured | yaml | application/yaml; charset=utf-8 |
|
|
97
|
+
| document | html | text/html; charset=utf-8 |
|
|
98
|
+
| document | markdown | text/markdown; charset=utf-8 |
|
|
99
|
+
| binary | raw | 登録時のMIME type |
|
|
100
|
+
| asset | raw | assetのMIME type |
|
|
101
|
+
|
|
102
|
+
structured-dataとdocument-dataのencode結果はUTF-8 bytesとして渡す。binary-dataとAsset Managerはbase64やJavaScript stringへ変換せずbytesまたはstreamを渡す。
|
|
103
|
+
|
|
104
|
+
## Block API案
|
|
105
|
+
|
|
106
|
+
### 共通namespace操作
|
|
107
|
+
|
|
108
|
+
providerごとにblock色と専門用語は維持しつつ、次の表層を揃える。
|
|
109
|
+
|
|
110
|
+
- named dataが存在するか
|
|
111
|
+
- named dataを削除
|
|
112
|
+
- named dataを別名へcopy
|
|
113
|
+
- named dataのMIME type
|
|
114
|
+
- named dataのsize
|
|
115
|
+
|
|
116
|
+
copyやsizeを提供できないproviderは初期versionでblockを公開せず、偽の値を返さない。
|
|
117
|
+
|
|
118
|
+
### HTTP response
|
|
119
|
+
|
|
120
|
+
HTTP Serverに次の共通操作を追加する。
|
|
121
|
+
|
|
122
|
+
- set response body from NAMESPACE named NAME as REPRESENTATION
|
|
123
|
+
- respond with NAMESPACE data NAME as REPRESENTATION
|
|
124
|
+
|
|
125
|
+
既存のJSON、HTML等のresponse blockを維持する期間は、内部で同じresponse builderへloweringするcompatibility wrapperとする。新規compiler IRでは共通operationをcanonical formとする。
|
|
126
|
+
|
|
127
|
+
### HTTP request
|
|
128
|
+
|
|
129
|
+
request bodyは保存済み参照と同一視しない。
|
|
130
|
+
|
|
131
|
+
- current request bodyをbinary data NAMEとして保存
|
|
132
|
+
- current request bodyをJSONまたはYAMLとしてparseしNAMEへ登録
|
|
133
|
+
- current request bodyをHTMLまたはMarkdown documentとしてparseしNAMEへ登録
|
|
134
|
+
|
|
135
|
+
IRのbinary-bodyはaffine resourceとして最大一回consumeする。保存またはparseが成功した後に、再利用可能なnamed dataをatomicに登録する。失敗時に既存bindingを変更しない。
|
|
136
|
+
|
|
137
|
+
## Registryとprovider境界
|
|
138
|
+
|
|
139
|
+
共通registryは特定format拡張のprivate fieldには置かない。小さなruntime-neutral packageとして定義し、TurboWarp runtimeごとに一つのserviceを生成する。候補package名は @kubohiroya/turbowarp-named-data とする。
|
|
140
|
+
|
|
141
|
+
共通packageの責務:
|
|
142
|
+
|
|
143
|
+
- provider登録と解除
|
|
144
|
+
- namespace衝突検査
|
|
145
|
+
- target/project scopeの解決
|
|
146
|
+
- project停止時の一括release
|
|
147
|
+
- metadataとbody resolverの型
|
|
148
|
+
- stable error codeと上限policyの共通部分
|
|
149
|
+
|
|
150
|
+
共通packageはJSON path、DOM、Markdown、codec、binary永続化、HTTP routingを所有しない。
|
|
151
|
+
|
|
152
|
+
### lifetime
|
|
153
|
+
|
|
154
|
+
- target scopeはtarget identityに結び付ける
|
|
155
|
+
- project scopeはruntime identityに結び付ける
|
|
156
|
+
- PROJECT_STOP_ALLでsession-only bindingとopen bodyを解放する
|
|
157
|
+
- persistent binary backingはbindingと分離し、明示deleteまたはretention policyで管理する
|
|
158
|
+
- provider交換時は新規解決を停止し、open済みbodyのrelease完了後に解除する
|
|
159
|
+
|
|
160
|
+
## Compiler/IR統合
|
|
161
|
+
|
|
162
|
+
IR v2のbinary-refをbinary専用の例外として増殖させず、named data参照を表現できるdescriptorへ一般化する。descriptorはnamespace、name、kind、scopeと、任意のmediaType、byteLength、digestを持つ。byte payloadはIR JSONへ格納しない。
|
|
163
|
+
|
|
164
|
+
既存binary-refはkindがbinaryまたはassetのdescriptorとして読めるmigration adapterを設ける。binary-bodyはstream resourceなのでvalue descriptorへ統合しない。
|
|
165
|
+
|
|
166
|
+
target adapterはnamespace provider、representation、stream response、response size、binary-read effect、scopeの対応状況を検査する。未対応時にtextやbase64へ暗黙fallbackしない。
|
|
167
|
+
|
|
168
|
+
## Errorと安全性
|
|
169
|
+
|
|
170
|
+
共通層では少なくとも次の安定errorを定義する。
|
|
171
|
+
|
|
172
|
+
| code | 条件 |
|
|
173
|
+
|---|---|
|
|
174
|
+
| NAMED_DATA_INVALID_REF | namespace、name、kind、scopeが不正 |
|
|
175
|
+
| NAMED_DATA_PROVIDER_NOT_FOUND | namespace providerが未登録 |
|
|
176
|
+
| NAMED_DATA_NOT_FOUND | bindingが存在しない |
|
|
177
|
+
| NAMED_DATA_KIND_MISMATCH | requested kindと登録kindが異なる |
|
|
178
|
+
| NAMED_DATA_SCOPE_MISMATCH | target/project scopeが不一致 |
|
|
179
|
+
| NAMED_DATA_REPRESENTATION_UNSUPPORTED | requested representationをencodeできない |
|
|
180
|
+
| NAMED_DATA_BODY_TOO_LARGE | encodeまたはrequest保存上限を超えた |
|
|
181
|
+
| NAMED_DATA_ABORTED | client切断等で処理を中止した |
|
|
182
|
+
| NAMED_DATA_PROVIDER_RELEASED | 解放済みproviderを参照した |
|
|
183
|
+
|
|
184
|
+
安全要件:
|
|
185
|
+
|
|
186
|
+
- HTML出力を自動sanitize済みとみなさない
|
|
187
|
+
- MarkdownからHTMLへの変換はactive content policyを明記する
|
|
188
|
+
- MIME sniffingに依存せずproviderがMIME typeを確定する
|
|
189
|
+
- active contentを配信するrouteへauthorizationとCSPを設定可能にする
|
|
190
|
+
- request body、encode結果、binary rangeに個別上限を持たせる
|
|
191
|
+
- logへbody bytesや機密document内容を記録しない
|
|
192
|
+
|
|
193
|
+
## 段階的な実装計画
|
|
194
|
+
|
|
195
|
+
各項目は別Issue/小粒PRとし、依存、受け入れ基準、rollback、feature flagをIssue本文へ記載する。
|
|
196
|
+
|
|
197
|
+
### Phase 0: 契約の固定
|
|
198
|
+
|
|
199
|
+
推奨branch: docs/named-data/body-provider-contract
|
|
200
|
+
|
|
201
|
+
- common type、scope、lifetime、error、representationをschemaまたはTypeScript declarationとして固定
|
|
202
|
+
- 各repositoryのcompatibility matrixを作成
|
|
203
|
+
- browser/server共通contract fixtureを作成
|
|
204
|
+
|
|
205
|
+
受け入れ基準:
|
|
206
|
+
|
|
207
|
+
- payloadを含まない参照schemaをvalidationできる
|
|
208
|
+
- target/project scopeと全representationのfixtureがある
|
|
209
|
+
- duplicate provider、unknown namespace、unsupported representationのerror期待値がある
|
|
210
|
+
|
|
211
|
+
rollback: documentationと未使用typeだけを除けばruntime挙動が変わらない。
|
|
212
|
+
|
|
213
|
+
### Phase 1: 共通registry MVP
|
|
214
|
+
|
|
215
|
+
推奨branch: feat/named-data/registry-mvp
|
|
216
|
+
|
|
217
|
+
依存: Phase 0
|
|
218
|
+
|
|
219
|
+
- runtime単位のprovider registryとscope resolverを実装
|
|
220
|
+
- provider登録、stat、openBody、releaseを実装
|
|
221
|
+
- NAMED_DATA_REGISTRY_MVPを起動時固定、既定OFFで追加
|
|
222
|
+
|
|
223
|
+
受け入れ基準:
|
|
224
|
+
|
|
225
|
+
- private objectをScratch reporterへ返さず名前から解決できる
|
|
226
|
+
- project停止後にsession bindingとopen resourceが残らない
|
|
227
|
+
- provider失敗時にもstateが部分更新されない
|
|
228
|
+
- flag OFFで既存extensionの挙動が変わらない
|
|
229
|
+
|
|
230
|
+
rollback: flag OFFでcommon registryへの登録と解決を完全に迂回する。
|
|
231
|
+
|
|
232
|
+
### Phase 2: structured-data provider
|
|
233
|
+
|
|
234
|
+
推奨branch: feat/structured-data/named-body-provider
|
|
235
|
+
|
|
236
|
+
依存: Phase 1
|
|
237
|
+
|
|
238
|
+
- 現在のtarget-local bindingをstructured providerから参照可能にする
|
|
239
|
+
- jsonとyamlをUTF-8 bodyとして公開
|
|
240
|
+
- canonical encode、上限、atomic replacementを既存実装と共有
|
|
241
|
+
|
|
242
|
+
受け入れ基準:
|
|
243
|
+
|
|
244
|
+
- 既存serialize blockとbody resolverの結果が一致する
|
|
245
|
+
- 別targetのtarget-local bindingを参照できない
|
|
246
|
+
- encode失敗時にHTTP responseを部分送信しない
|
|
247
|
+
- browser/server parity testが通る
|
|
248
|
+
|
|
249
|
+
rollback: provider登録flagをOFFにし、既存blockだけを維持する。
|
|
250
|
+
|
|
251
|
+
### Phase 3: binary-data providerとAsset Manager adapter
|
|
252
|
+
|
|
253
|
+
推奨branch: feat/binary-data/provider-mvp
|
|
254
|
+
|
|
255
|
+
依存: Phase 1
|
|
256
|
+
|
|
257
|
+
- session-only named byte/stream registryを実装
|
|
258
|
+
- MIME type、byte length、digest、revisionを保持
|
|
259
|
+
- Asset Managerのassetをasset namespaceからread-only bodyとして公開
|
|
260
|
+
- persistent backingは別feature flagでadapter
|
|
261
|
+
|
|
262
|
+
受け入れ基準:
|
|
263
|
+
|
|
264
|
+
- base64やstringへ変換せずHTTP bodyへ渡せる
|
|
265
|
+
- asset replacement後にrevisionが変わる
|
|
266
|
+
- open中のsnapshotはreplacementの影響を受けない
|
|
267
|
+
- unsupported kindをempty bodyとして返さない
|
|
268
|
+
|
|
269
|
+
rollback: provider/adapter flagをOFFにし、既存asset registryを維持する。
|
|
270
|
+
|
|
271
|
+
### Phase 4: HTTP Server response統合
|
|
272
|
+
|
|
273
|
+
推奨branch: feat/http-server/named-response-body
|
|
274
|
+
|
|
275
|
+
依存: Phase 2、Phase 3
|
|
276
|
+
|
|
277
|
+
- named body resolverをhandlerとcompiler adapterへ注入
|
|
278
|
+
- 共通response blockとIR operationを追加
|
|
279
|
+
- Content-Type、Content-Length、ETag、abort、releaseを接続
|
|
280
|
+
- 既存format別response blockを共通builderへlowering
|
|
281
|
+
- NAMED_RESPONSE_BODYを既定OFFで追加
|
|
282
|
+
|
|
283
|
+
受け入れ基準:
|
|
284
|
+
|
|
285
|
+
- structured JSON/YAMLとbinary assetを同じ共通blockから返せる
|
|
286
|
+
- HEADはGETと同じmetadataをbodyなしで返す
|
|
287
|
+
- client切断時にabortが伝播する
|
|
288
|
+
- body bytesをlogへ記録しない
|
|
289
|
+
|
|
290
|
+
rollback: flag OFFで新block/IRを拒否し、既存response pathへ戻す。
|
|
291
|
+
|
|
292
|
+
### Phase 5: document-data MVP
|
|
293
|
+
|
|
294
|
+
推奨branch: feat/document-data/html-markdown-mvp
|
|
295
|
+
|
|
296
|
+
依存: Phase 1。HTTP統合検証はPhase 4にも依存する。
|
|
297
|
+
|
|
298
|
+
- HTMLとMarkdownのkindを保持するnamed document registryを実装
|
|
299
|
+
- parse、node操作、serializeの最小集合を定義
|
|
300
|
+
- htmlとmarkdown representationをbody providerとして公開
|
|
301
|
+
- lossy変換を明示し、既定では元kindと同じrepresentationを使う
|
|
302
|
+
|
|
303
|
+
受け入れ基準:
|
|
304
|
+
|
|
305
|
+
- 文字列連結ではなくnamed documentとして段階編集できる
|
|
306
|
+
- parse、node、serialize上限がある
|
|
307
|
+
- format変換が行われたか判別できる
|
|
308
|
+
- HTMLを自動的にsafeと表示しない
|
|
309
|
+
|
|
310
|
+
rollback: document provider flagをOFFにし、既存text responseを維持する。
|
|
311
|
+
|
|
312
|
+
### Phase 6: request body import
|
|
313
|
+
|
|
314
|
+
推奨branch: feat/http-server/named-request-import
|
|
315
|
+
|
|
316
|
+
依存: Phase 2、Phase 3、Phase 5
|
|
317
|
+
|
|
318
|
+
- affineなbinary-bodyからbinary-dataへ保存するconsumerを追加
|
|
319
|
+
- 明示的JSON、YAML、HTML、Markdown parse blockを追加
|
|
320
|
+
- consume、abort、limit、atomic registrationをruntimeとcompilerで一致させる
|
|
321
|
+
|
|
322
|
+
受け入れ基準:
|
|
323
|
+
|
|
324
|
+
- request bodyを最大一回だけconsumeできる
|
|
325
|
+
- parse/保存失敗時に既存bindingを置換しない
|
|
326
|
+
- Content-Typeを暗黙推測しない
|
|
327
|
+
- compilerが二重consumeとscope外利用を拒否する
|
|
328
|
+
|
|
329
|
+
rollback: import flagをOFFにし、既存text request body reporterを維持する。
|
|
330
|
+
|
|
331
|
+
### Phase 7: compatibility API整理
|
|
332
|
+
|
|
333
|
+
推奨branch: refactor/http-server/body-api-convergence
|
|
334
|
+
|
|
335
|
+
依存: Phase 4からPhase 6の利用実績と回帰試験
|
|
336
|
+
|
|
337
|
+
- format固有blockをwrapperとして維持するものとdeprecatedにするものへ分類
|
|
338
|
+
- manifestとdocumentationでcanonical operationを一本化
|
|
339
|
+
- default ON条件と削除versionを別Issueで承認
|
|
340
|
+
|
|
341
|
+
受け入れ基準:
|
|
342
|
+
|
|
343
|
+
- 既存projectのmigration手順と互換性表がある
|
|
344
|
+
- default ON前に全providerの回帰、負荷、abort testが通る
|
|
345
|
+
- flag OFFによる切戻し手順をrelease noteで確認できる
|
|
346
|
+
|
|
347
|
+
rollback: compatibility wrapperと旧IR loweringを一つ以上の移行期間保持する。
|
|
348
|
+
|
|
349
|
+
## 依存関係
|
|
350
|
+
|
|
351
|
+
Phase 0からPhase 1を直列に実施する。Phase 1完了後、Phase 2、Phase 3、Phase 5は並列化できる。Phase 4は最低限Phase 2とPhase 3のfixtureを使って統合検証する。Phase 6は各providerの完成後、Phase 7は運用実績取得後に着手する。
|
|
352
|
+
|
|
353
|
+
## 共通Definition of Done
|
|
354
|
+
|
|
355
|
+
- GitHub Issueにbranch、依存、受け入れ基準、rollback、feature flagを記載
|
|
356
|
+
- public type、manifest、schema、block definition、実装を一致
|
|
357
|
+
- unit、semantic parity、browser integration、server compiler testを追加
|
|
358
|
+
- repository既定のlint、format、typecheck、testを通過
|
|
359
|
+
- size、abort、lifetime、atomicity、二重consumeのnegative testを追加
|
|
360
|
+
- bodyまたは機密値をlogへ出さないことを検証
|
|
361
|
+
- scope、lifetime、MIME type、上限、error、migrationを文書化
|
|
362
|
+
- feature flag OFFで従来挙動へ戻せることを確認
|
|
363
|
+
|
|
364
|
+
## Phase 0で決める未決事項
|
|
365
|
+
|
|
366
|
+
1. common registryを独立packageにするか共有workspace packageとして開始するか
|
|
367
|
+
2. project scopeの名前がsprite clone間でどのように見えるか
|
|
368
|
+
3. namespaceとnameをScratch block上でmenuにするか自由入力にするか
|
|
369
|
+
4. structured/documentを事前bufferする最大sizeとstreaming開始条件
|
|
370
|
+
5. ETagへdigestとrevisionのどちらを使うか
|
|
371
|
+
6. binary range responseをMVPへ含めるか
|
|
372
|
+
7. persistent backingのretention、quota、project exportとの関係
|
|
373
|
+
8. HTML sanitizerをdocument-dataの別operationとするか別providerとするか
|
|
374
|
+
|
|
375
|
+
これらを暗黙の実装判断にせず、contract fixtureとIssueの受け入れ基準へ反映してからruntime変更へ進む。
|
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kubohiroya/turbowarp-structured-data",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Named structured data with JSON/YAML codecs and deterministic path operations for TurboWarp.",
|
|
5
|
+
"author": "Hiroya Kubo <hiroya@cuc.ac.jp>",
|
|
6
|
+
"license": "MPL-2.0",
|
|
7
|
+
"homepage": "https://github.com/kubohiroya/turbowarp-structured-data#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/kubohiroya/turbowarp-structured-data.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/kubohiroya/turbowarp-structured-data/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"turbowarp",
|
|
17
|
+
"scratch",
|
|
18
|
+
"extension",
|
|
19
|
+
"structured-data",
|
|
20
|
+
"json",
|
|
21
|
+
"yaml",
|
|
22
|
+
"vite",
|
|
23
|
+
"typescript"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"files": [
|
|
27
|
+
"dist/",
|
|
28
|
+
"docs/",
|
|
29
|
+
"schemas/",
|
|
30
|
+
"src/",
|
|
31
|
+
"templates/",
|
|
32
|
+
"README.md",
|
|
33
|
+
"README.ja.md",
|
|
34
|
+
"THIRD_PARTY_NOTICES.md",
|
|
35
|
+
"LICENSE"
|
|
36
|
+
],
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public",
|
|
39
|
+
"registry": "https://registry.npmjs.org/"
|
|
40
|
+
},
|
|
41
|
+
"packageManager": "pnpm@11.11.0",
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=22.18.0"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"dev": "vite build --watch",
|
|
47
|
+
"typecheck": "tsc --noEmit",
|
|
48
|
+
"build": "vite build",
|
|
49
|
+
"lint": "eslint src tests scripts vite.config.ts eslint.config.ts",
|
|
50
|
+
"test": "vitest run",
|
|
51
|
+
"docs": "node scripts/generate-readme.ts",
|
|
52
|
+
"docs:check": "node scripts/generate-readme.ts --check",
|
|
53
|
+
"template:readme": "node scripts/apply-readme-template.ts",
|
|
54
|
+
"repo:check": "node scripts/check-repo.ts",
|
|
55
|
+
"pack:check": "npm pack --dry-run --ignore-scripts",
|
|
56
|
+
"check": "pnpm run typecheck && pnpm run lint && pnpm run test && pnpm run docs:check && pnpm run check:dist && pnpm run repo:check && pnpm run pack:check",
|
|
57
|
+
"check:dist": "pnpm run build && node scripts/check-dist.ts"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@eslint/js": "^9.39.5",
|
|
61
|
+
"@kubohiroya/turbowarp-named-data": "github:kubohiroya/turbowarp-named-data#bc3be0e669f501479ef45877e5d06e27714184d2",
|
|
62
|
+
"@kubohiroya/vite-plugin-turbowarp-extension": "0.3.0",
|
|
63
|
+
"@types/node": "^24.13.3",
|
|
64
|
+
"eslint": "^9.39.5",
|
|
65
|
+
"jiti": "^2.7.0",
|
|
66
|
+
"typescript": "^5.9.3",
|
|
67
|
+
"typescript-eslint": "^8.66.0",
|
|
68
|
+
"vite": "^8.2.2",
|
|
69
|
+
"vitest": "^5.0.0"
|
|
70
|
+
},
|
|
71
|
+
"dependencies": {
|
|
72
|
+
"yaml": "^2.9.1"
|
|
73
|
+
},
|
|
74
|
+
"peerDependencies": {
|
|
75
|
+
"@kubohiroya/turbowarp-named-data": "^0.1.0"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://raw.githubusercontent.com/kubohiroya/turbowarp-structured-data/main/schemas/extension-manifest.schema.json",
|
|
4
|
+
"title": "TurboWarp Structured Data Compiler Manifest",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["formatVersion", "id", "pathSegmentType", "dataReferenceType", "blocks"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"formatVersion": {"const": 3},
|
|
10
|
+
"id": {"type": "string", "pattern": "^[a-z0-9]+$"},
|
|
11
|
+
"pathSegmentType": {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"additionalProperties": false,
|
|
14
|
+
"required": ["kind", "variants"],
|
|
15
|
+
"properties": {
|
|
16
|
+
"kind": {"const": "discriminatedUnion"},
|
|
17
|
+
"variants": {
|
|
18
|
+
"type": "array",
|
|
19
|
+
"prefixItems": [
|
|
20
|
+
{"$ref": "#/$defs/keyPathSegment"},
|
|
21
|
+
{"$ref": "#/$defs/indexPathSegment"}
|
|
22
|
+
],
|
|
23
|
+
"items": false,
|
|
24
|
+
"minItems": 2,
|
|
25
|
+
"maxItems": 2
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"dataReferenceType": {
|
|
30
|
+
"type": "object",
|
|
31
|
+
"additionalProperties": false,
|
|
32
|
+
"required": ["kind", "scope", "lifetime", "valueType"],
|
|
33
|
+
"properties": {
|
|
34
|
+
"kind": {"const": "named"},
|
|
35
|
+
"scope": {"const": "target"},
|
|
36
|
+
"lifetime": {"const": "untilProjectStop"},
|
|
37
|
+
"valueType": {"const": "jsonValue"}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"blocks": {
|
|
41
|
+
"type": "array",
|
|
42
|
+
"minItems": 1,
|
|
43
|
+
"items": {"$ref": "#/$defs/block"}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"$defs": {
|
|
47
|
+
"keyPathSegment": {
|
|
48
|
+
"type": "object",
|
|
49
|
+
"additionalProperties": false,
|
|
50
|
+
"required": ["kind", "valueType"],
|
|
51
|
+
"properties": {"kind": {"const": "key"}, "valueType": {"const": "string"}}
|
|
52
|
+
},
|
|
53
|
+
"indexPathSegment": {
|
|
54
|
+
"type": "object",
|
|
55
|
+
"additionalProperties": false,
|
|
56
|
+
"required": ["kind", "valueType"],
|
|
57
|
+
"properties": {"kind": {"const": "index"}, "valueType": {"const": "nonNegativeInteger"}}
|
|
58
|
+
},
|
|
59
|
+
"argument": {
|
|
60
|
+
"type": "object",
|
|
61
|
+
"additionalProperties": false,
|
|
62
|
+
"required": ["id", "type"],
|
|
63
|
+
"properties": {
|
|
64
|
+
"id": {"type": "string", "minLength": 1},
|
|
65
|
+
"type": {"enum": ["STRING", "NUMBER", "BOOLEAN"]},
|
|
66
|
+
"normalizesTo": {"const": "pathSegments"},
|
|
67
|
+
"staticLiteral": {"type": "boolean"},
|
|
68
|
+
"minimum": {"type": "number"},
|
|
69
|
+
"maximum": {"type": "number"}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"server": {
|
|
73
|
+
"type": "object",
|
|
74
|
+
"additionalProperties": false,
|
|
75
|
+
"required": ["supported", "irOperation"],
|
|
76
|
+
"properties": {
|
|
77
|
+
"supported": {"type": "boolean"},
|
|
78
|
+
"irOperation": {"type": "string", "pattern": "^structuredData\\.[A-Za-z][A-Za-z0-9]*$"}
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"block": {
|
|
82
|
+
"type": "object",
|
|
83
|
+
"additionalProperties": false,
|
|
84
|
+
"required": ["opcode", "blockType", "arguments", "resultType", "effect", "immutable", "errors", "server"],
|
|
85
|
+
"properties": {
|
|
86
|
+
"opcode": {"type": "string", "minLength": 1},
|
|
87
|
+
"blockType": {"enum": ["COMMAND", "REPORTER", "BOOLEAN", "LOOP"]},
|
|
88
|
+
"arguments": {"type": "array", "items": {"$ref": "#/$defs/argument"}},
|
|
89
|
+
"resultType": {"enum": ["json", "jsonText", "yamlText", "boolean", "number", "string", "void"]},
|
|
90
|
+
"effect": {"enum": ["pure", "immutable", "state", "control"]},
|
|
91
|
+
"immutable": {"type": "boolean"},
|
|
92
|
+
"errors": {
|
|
93
|
+
"type": "array",
|
|
94
|
+
"uniqueItems": true,
|
|
95
|
+
"items": {
|
|
96
|
+
"enum": ["INVALID_JSON", "INVALID_YAML", "INVALID_NAME", "DATA_NOT_FOUND", "INVALID_PATH", "PATH_NOT_FOUND", "TYPE_MISMATCH", "INDEX_OUT_OF_RANGE", "ITERATION_LIMIT_EXCEEDED", "ITERATION_CONTEXT_REQUIRED", "PARSE_LIMIT_EXCEEDED"]
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"server": {"$ref": "#/$defs/server"}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|