@kubohiroya/turbowarp-extension-data-editor 0.2.0 → 0.2.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.
Files changed (64) hide show
  1. package/README.md +9 -6
  2. package/dist/build-info.json +4 -4
  3. package/dist/fixed-input-branches.d.ts +12 -0
  4. package/dist/fixed-input-branches.js +180 -0
  5. package/dist/fixed-input-editor.d.ts +39 -0
  6. package/dist/fixed-input-editor.js +538 -0
  7. package/dist/fixed-input-schema.d.ts +15 -0
  8. package/dist/fixed-input-schema.js +21 -0
  9. package/dist/fixed-input-snapshot.d.ts +7 -0
  10. package/dist/fixed-input-snapshot.js +180 -0
  11. package/dist/fixed-input-types.d.ts +138 -0
  12. package/dist/fixed-input-types.js +23 -0
  13. package/dist/fixed-input-view.d.ts +14 -0
  14. package/dist/fixed-input-view.js +168 -0
  15. package/dist/index.d.ts +6 -0
  16. package/dist/index.js +4 -0
  17. package/dist/react.css +42 -0
  18. package/dist/react.d.ts +3 -0
  19. package/dist/react.js +10 -1
  20. package/dist/registry.d.ts +4 -0
  21. package/dist/registry.js +45 -7
  22. package/dist/rjsf.d.ts +24 -1
  23. package/dist/rjsf.js +22 -2
  24. package/dist/schema.d.ts +2 -0
  25. package/dist/schema.js +1 -0
  26. package/dist/session.d.ts +3 -1
  27. package/dist/session.js +205 -7
  28. package/dist/turbowarp/bridge.d.ts +2 -1
  29. package/dist/turbowarp/bridge.js +34 -5
  30. package/dist/turbowarp/fixed-fields.d.ts +82 -0
  31. package/dist/turbowarp/fixed-fields.js +311 -0
  32. package/dist/turbowarp/fixed-transaction.d.ts +18 -0
  33. package/dist/turbowarp/fixed-transaction.js +460 -0
  34. package/dist/turbowarp/host.d.ts +3 -8
  35. package/dist/turbowarp/host.js +68 -1
  36. package/dist/turbowarp.d.ts +4 -0
  37. package/dist/turbowarp.js +1 -1
  38. package/dist/types.d.ts +5 -0
  39. package/dist/view.js +4 -0
  40. package/dist/webpack4/index.js +22 -5
  41. package/dist/webpack4/metafile.json +588 -319
  42. package/dist/webpack4/react.js +9 -1
  43. package/dist/webpack4/react.js.map +2 -2
  44. package/dist/webpack4/rjsf.js +249 -34
  45. package/dist/webpack4/rjsf.js.map +4 -4
  46. package/dist/webpack4/schema.js +6 -3
  47. package/dist/webpack4/{shared-KQOUMWJ4.js → shared-75QIWLZY.js} +1129 -1244
  48. package/dist/webpack4/{shared-KQOUMWJ4.js.map → shared-75QIWLZY.js.map} +4 -4
  49. package/dist/webpack4/shared-FYUILHED.js +1 -0
  50. package/dist/webpack4/shared-GQLPPRT2.js +210 -0
  51. package/dist/webpack4/shared-GQLPPRT2.js.map +7 -0
  52. package/dist/webpack4/shared-P2JBRZFP.js +2206 -0
  53. package/dist/webpack4/shared-P2JBRZFP.js.map +7 -0
  54. package/dist/webpack4/turbowarp.js +910 -9
  55. package/dist/webpack4/turbowarp.js.map +4 -4
  56. package/docs/fixed-input-contracts.md +77 -0
  57. package/docs/stage-2-publication.ja.md +6 -0
  58. package/package.json +8 -1
  59. package/dist/webpack4/shared-CQB3NG2A.js +0 -1
  60. package/dist/webpack4/shared-MRPGBJIH.js +0 -75
  61. package/dist/webpack4/shared-MRPGBJIH.js.map +0 -7
  62. package/dist/webpack4/shared-N6YQE2X6.js +0 -1029
  63. package/dist/webpack4/shared-N6YQE2X6.js.map +0 -7
  64. /package/dist/webpack4/{shared-CQB3NG2A.js.map → shared-FYUILHED.js.map} +0 -0
package/README.md CHANGED
@@ -103,10 +103,10 @@ pnpm test
103
103
  `pnpm test` は型宣言を含むビルド後、コアと標準フォームのテストを実行します。
104
104
  パッケージは ESM です。ブラウザには ES2022 の組み込み API が必要です。
105
105
  標準フォームの React / ReactDOM peer は 16.14 / 17 / 18。GUI は既存の 16.14 を共有します。
106
- 初回の実験版は `@kubohiroya/turbowarp-extension-data-editor@0.1.0` です。固定SchemaのSource/Form編集を追加する今回の配布版は `0.2.0` です。
106
+ 初回の実験版は `@kubohiroya/turbowarp-extension-data-editor@0.1.0` です。固定SchemaのSource/Form編集は `0.2.0` で追加しました。今回の配布版 `0.2.1` は、既定OFFの固定入力契約・標準field transaction・固定フォームとGUI接続も含みます。
107
107
 
108
108
  ```sh
109
- npm install --save-exact @kubohiroya/turbowarp-extension-data-editor@0.2.0
109
+ npm install --save-exact @kubohiroya/turbowarp-extension-data-editor@0.2.1
110
110
  ```
111
111
 
112
112
  配布物・改名時の互換性・公開手順は[パッケージ配布](docs/package-distribution.md)を参照してください。
@@ -117,9 +117,8 @@ npm install --save-exact @kubohiroya/turbowarp-extension-data-editor@0.2.0
117
117
  [GUIの起動・制約・検証手順](docs/block-editor.md) に従ってください。
118
118
  既存の拡張アイコンをクリックすると、標準モーダルで下書きを編集できます。
119
119
 
120
- 現在の GUI 適用範囲は、配置済みブロックの通常の text shadow に保存された JSON/YAML 文字列です。
121
- reporter、メニュー、独自 validator 付きフィールドは書き換えません。
122
- `.sb3` の実保存と標準 `project_url` 経路での再読込を確認済みです。OS のファイル選択による再読込、アイコンがないブロックへの追加表示、翻訳・全テーマは後続の確認項目です。
120
+ 既存のSOURCE経路は、配置済みブロックの通常の text shadow に保存された JSON/YAML 文字列を扱います。この経路でreporter、メニュー、独自validator付きfieldを書き換えません。固定入力経路は対応hostと明示opt-inで静的menu・数値・色を扱い、reporterや動的menuを評価・置換しません。
121
+ `.sb3` の保存、`project_url` とOSのファイル選択による再読込、日英表示とテーマの検証手順・実行範囲は[GUI接続E2E](docs/block-editor-e2e.md)と[固定入力の契約](docs/fixed-input-contracts.md)を参照してください。
123
122
 
124
123
  ## フラグとロールバック
125
124
 
@@ -143,10 +142,14 @@ GUI の `src/lib/tw-feature-flags.js` で起動時固定の `blockEditorDialogs`
143
142
 
144
143
  同期owner検証には`/schema`の`validateSchemaInput`を利用できます。明示bundleフォームは`/rjsf`の`createSchemaBundleEditor` / `registerSchemaBundle`で登録します。context providerは呼出しごとに時刻・設定を渡します。表示上の対応範囲と既存APIの扱いは[Schema基盤](docs/schema.md)を参照してください。
145
144
 
146
- 現在のowner横断検証は**14契約・8 package**です。[Template分離後の再検証手順](docs/template-fixture-separation.ja.md#current-verification)で、Templateを含まないisolation indexと2つの検証commandを確認してください。段階2では、この14本番契約と新規予定の9固定契約を区別して計画します。旧16契約・9 packageの結果と当時の開始条件は[段階1の履歴](docs/schema-stage1.ja.md)として保持します。
145
+ 既存SOURCE契約の導入時に採取した横断検証記録は**14契約・8 package**です。[Template分離後の再検証手順](docs/template-fixture-separation.ja.md#current-verification)で、Templateを含まないisolation indexと2つの検証commandを確認してください。この導入時記録では14本番契約と9固定契約を区別しています。固定入力の実装・GUI接続は末尾の契約節を参照してください。旧16契約・9 packageの結果と当時の開始条件は[段階1の履歴](docs/schema-stage1.ja.md)として保持します。
147
146
 
148
147
  ## Optional editing examples
149
148
 
150
149
  Repository examples are opt-in teaching code, not template blocks or additional package exports. See [the JSON/YAML document example](examples/document-properties.mjs) and [its guide](examples/README.ja.md). Each extension owns its actual data contract.
151
150
 
152
151
  Prepared source editing is an optional host capability. See [the source/form contract](docs/source-forms.ja.md) for fixed-schema bindings, atomic saves, compatibility, and rollback.
152
+
153
+ ## 固定入力とGUI接続(S3-1〜S3-3)
154
+
155
+ 固定入力の型・Schema検査・同期prepared契約を追加しています。`createBlockEditorService({fixedInputs: true})`の明示時だけ新しい登録APIを提供し、対応hostがない場合は開けません。lower-level hostの`enableFixedInputs: true`で標準fieldの読取・原子的保存を利用できます。固定フォームとGUIの既定OFFフラグ接続も含みます。各拡張は正本Schema・codec・登録を所有します。[固定入力の契約](docs/fixed-input-contracts.md)を参照してください。配布物には元Git SHAと版更新を含むworking-tree release overlayの区分を記録しています。
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@kubohiroya/turbowarp-extension-data-editor",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "repository": "https://github.com/kubohiroya/turbowarp-extension-data-editor",
5
- "revision": "76fa1d50a3c188082ceef723ea018a9d8769ea6e",
6
- "sourceState": "commit",
7
- "sourceSha256": "912efc0438710958698527aa5c26a33b0b1c2da280f91d36b048f6f2389a48f0",
5
+ "revision": "485f0e550e622235624b5e9176820161aeeba252",
6
+ "sourceState": "working-tree",
7
+ "sourceSha256": "175674eaaffce60dd9ebcf4c31f0f02a3bbd9dc6b8659ab3101ea6d8bceeea2f",
8
8
  "capabilities": {
9
9
  "preparedSource": 1
10
10
  }
@@ -0,0 +1,12 @@
1
+ import type { FixedBlockSnapshot, FixedInputBranchCase, FixedInputBranchRule, FixedInputBranchState, FixedInputDeclaration, FixedInputDependency } from './fixed-input-types.js';
2
+ import type { ArgumentSlot, LiteralArgumentChange, ValidationIssue } from './types.js';
3
+ /** Capture finite JSON policy once; callbacks and getters are never part of host authority. */
4
+ export declare function captureFixedBranchRules(value: unknown, dependencies: readonly FixedInputDependency[], readOnlyArguments: readonly string[]): readonly FixedInputBranchRule[];
5
+ export interface ResolvedFixedBranch extends FixedInputBranchState {
6
+ readonly rule: FixedInputBranchRule;
7
+ readonly selected?: FixedInputBranchCase;
8
+ }
9
+ /** Resolve only captured literal metadata. Reporters and unavailable fields are never evaluated. */
10
+ export declare function resolveFixedBranches(declaration: FixedInputDeclaration, snapshot: FixedBlockSnapshot, arguments_?: Readonly<Record<string, ArgumentSlot>>): readonly ResolvedFixedBranch[];
11
+ /** Shared session/host gate. Schema and owner validation remain the prepared factory's responsibility. */
12
+ export declare function validateFixedBranchChanges(declaration: FixedInputDeclaration, snapshot: FixedBlockSnapshot, changes: readonly LiteralArgumentChange[]): readonly ValidationIssue[];
@@ -0,0 +1,180 @@
1
+ import { snapshotJson } from './schema-json.js';
2
+ const fail = () => { throw new TypeError('Invalid fixed branch declaration.'); };
3
+ const names = (value) => {
4
+ if (!Array.isArray(value) || !value.length || value.some(item => typeof item !== 'string' || !item) ||
5
+ new Set(value).size !== value.length)
6
+ return fail();
7
+ return Object.freeze(value);
8
+ };
9
+ const object = (value) => {
10
+ if (!value || typeof value !== 'object' || Array.isArray(value))
11
+ return fail();
12
+ return value;
13
+ };
14
+ const normalize = (value, rule) => {
15
+ var _a, _b;
16
+ const text = ((_a = rule.normalize) === null || _a === void 0 ? void 0 : _a.trim) ? value.trim() : value;
17
+ return ((_b = rule.normalize) === null || _b === void 0 ? void 0 : _b.lowercase) ? text.toLowerCase() : text;
18
+ };
19
+ /** Capture finite JSON policy once; callbacks and getters are never part of host authority. */
20
+ export function captureFixedBranchRules(value, dependencies, readOnlyArguments) {
21
+ if (value === undefined)
22
+ return Object.freeze([]);
23
+ const captured = snapshotJson(value);
24
+ if (!Array.isArray(captured))
25
+ return fail();
26
+ const selectors = new Set();
27
+ const occupied = new Set();
28
+ const result = [];
29
+ for (const item of captured) {
30
+ const rule = object(item);
31
+ if (typeof rule.selector !== 'string' || selectors.has(rule.selector))
32
+ return fail();
33
+ const group = dependencies.find(dependency => dependency.selector === rule.selector);
34
+ if (!group)
35
+ return fail();
36
+ for (const argument of [group.selector, ...group.dependents]) {
37
+ if (occupied.has(argument) || dependencies.some(other => other !== group &&
38
+ (other.selector === argument || other.dependents.includes(argument))))
39
+ return fail();
40
+ occupied.add(argument);
41
+ }
42
+ selectors.add(rule.selector);
43
+ let normalization;
44
+ if (rule.normalize !== undefined) {
45
+ const input = object(rule.normalize);
46
+ if (Object.keys(input).some(key => key !== 'trim' && key !== 'lowercase') ||
47
+ Object.values(input).some(value => typeof value !== 'boolean'))
48
+ return fail();
49
+ normalization = Object.freeze({ ...input });
50
+ }
51
+ const shell = { selector: rule.selector, cases: [], ...(normalization ? { normalize: normalization } : {}) };
52
+ if (!Array.isArray(rule.cases) || !rule.cases.length)
53
+ return fail();
54
+ const values = new Set();
55
+ const cases = [];
56
+ for (const input of rule.cases) {
57
+ const branch = object(input);
58
+ const caseValues = names(branch.values);
59
+ const normalized = caseValues.map(value => normalize(value, shell));
60
+ if (normalized.some(value => !value || values.has(value)))
61
+ return fail();
62
+ for (const value of normalized)
63
+ values.add(value);
64
+ if (new Set(normalized).size !== normalized.length)
65
+ return fail();
66
+ if (!Array.isArray(branch.activeDependents))
67
+ return fail();
68
+ const active = branch.activeDependents.length ? names(branch.activeDependents) : Object.freeze([]);
69
+ if (active.some(argument => !group.dependents.includes(argument)))
70
+ return fail();
71
+ const requirements = [];
72
+ if (branch.requireOnSelectorChange !== undefined) {
73
+ if (!Array.isArray(branch.requireOnSelectorChange))
74
+ return fail();
75
+ const required = new Set();
76
+ for (const input of branch.requireOnSelectorChange) {
77
+ const requirement = object(input);
78
+ if (typeof requirement.argument !== 'string' || !readOnlyArguments.includes(requirement.argument) ||
79
+ required.has(requirement.argument) || (requirement.rule !== 'literal' && requirement.rule !== 'nonempty-string'))
80
+ return fail();
81
+ required.add(requirement.argument);
82
+ requirements.push(Object.freeze({ argument: requirement.argument, rule: requirement.rule }));
83
+ }
84
+ }
85
+ cases.push(Object.freeze({ values: caseValues, activeDependents: active,
86
+ ...(branch.requireOnSelectorChange === undefined ? {} : { requireOnSelectorChange: Object.freeze(requirements) }) }));
87
+ }
88
+ result.push(Object.freeze({ ...shell, cases: Object.freeze(cases) }));
89
+ }
90
+ return Object.freeze(result);
91
+ }
92
+ /** Resolve only captured literal metadata. Reporters and unavailable fields are never evaluated. */
93
+ export function resolveFixedBranches(declaration, snapshot, arguments_ = snapshot.arguments) {
94
+ var _a;
95
+ return Object.freeze(((_a = declaration.branchRules) !== null && _a !== void 0 ? _a : []).map(rule => {
96
+ const metadata = snapshot.fixedContext.inputs[rule.selector];
97
+ const slot = arguments_[rule.selector];
98
+ let status;
99
+ if (!metadata || metadata.source === 'missing')
100
+ status = 'missing';
101
+ else if (metadata.source === 'reporter' || (slot === null || slot === void 0 ? void 0 : slot.kind) === 'reporter')
102
+ status = 'reporter';
103
+ else if ((metadata.source !== 'field' && metadata.source !== 'shadow') || metadata.role !== 'editable')
104
+ status = 'unsupported';
105
+ else if ((slot === null || slot === void 0 ? void 0 : slot.kind) !== 'literal' || typeof slot.value !== 'string')
106
+ status = 'unknown';
107
+ else {
108
+ const value = normalize(slot.value, rule);
109
+ const selected = rule.cases.find(branch => branch.values.some(item => normalize(item, rule) === value));
110
+ if (selected)
111
+ return Object.freeze({ selector: rule.selector, rule, selected,
112
+ status: slot.value === selected.values[0] ? 'known' : 'alias', value: selected.values[0] });
113
+ status = 'unknown';
114
+ }
115
+ return Object.freeze({ selector: rule.selector, rule, status });
116
+ }));
117
+ }
118
+ const writableLiteral = (snapshot, arguments_, name) => {
119
+ var _a;
120
+ const metadata = snapshot.fixedContext.inputs[name];
121
+ return ((_a = arguments_[name]) === null || _a === void 0 ? void 0 : _a.kind) === 'literal' && (metadata === null || metadata === void 0 ? void 0 : metadata.role) === 'editable' &&
122
+ (metadata.source === 'field' || metadata.source === 'shadow');
123
+ };
124
+ const diagnostic = (declaration, code, argument) => Object.freeze({
125
+ message: `Fixed branch validation failed: ${code}; contract=${JSON.stringify(declaration.contractId)}.`,
126
+ path: `/${argument.replace(/~/g, '~0').replace(/\//g, '~1')}`
127
+ });
128
+ /** Shared session/host gate. Schema and owner validation remain the prepared factory's responsibility. */
129
+ export function validateFixedBranchChanges(declaration, snapshot, changes) {
130
+ var _a;
131
+ const issues = [];
132
+ const finalArguments = { ...snapshot.arguments };
133
+ const changed = new Set();
134
+ const seen = new Set();
135
+ for (const change of changes) {
136
+ if (seen.has(change.argument) || !['string', 'number', 'boolean'].includes(typeof change.value) || !declaration.editableArguments.includes(change.argument) ||
137
+ !writableLiteral(snapshot, snapshot.arguments, change.argument)) {
138
+ issues.push(diagnostic(declaration, 'disallowed-change', change.argument));
139
+ continue;
140
+ }
141
+ seen.add(change.argument);
142
+ const original = snapshot.arguments[change.argument];
143
+ if ((original === null || original === void 0 ? void 0 : original.kind) === 'literal' && Object.is(original.value, change.value))
144
+ continue;
145
+ changed.add(change.argument);
146
+ Object.defineProperty(finalArguments, change.argument, { value: { kind: 'literal', value: change.value }, enumerable: true, configurable: true });
147
+ }
148
+ const resolved = resolveFixedBranches(declaration, snapshot, finalArguments);
149
+ for (const group of declaration.dependencies) {
150
+ if (![group.selector, ...group.dependents].some(name => changed.has(name)))
151
+ continue;
152
+ const branch = resolved.find(item => item.selector === group.selector);
153
+ if (!(branch === null || branch === void 0 ? void 0 : branch.selected)) {
154
+ issues.push(diagnostic(declaration, branch ? 'selector-unavailable' : 'fixed-dependency-validation-unavailable', group.selector));
155
+ continue;
156
+ }
157
+ for (const argument of group.dependents) {
158
+ if (changed.has(argument) && !branch.selected.activeDependents.includes(argument)) {
159
+ issues.push(diagnostic(declaration, 'inactive-change', argument));
160
+ }
161
+ }
162
+ if (!changed.has(group.selector))
163
+ continue;
164
+ for (const argument of branch.selected.activeDependents) {
165
+ if (!writableLiteral(snapshot, finalArguments, argument))
166
+ issues.push(diagnostic(declaration, 'dependency-unverifiable', argument));
167
+ }
168
+ for (const requirement of (_a = branch.selected.requireOnSelectorChange) !== null && _a !== void 0 ? _a : []) {
169
+ const metadata = snapshot.fixedContext.inputs[requirement.argument];
170
+ const slot = finalArguments[requirement.argument];
171
+ if (!metadata || metadata.role !== 'readonly' || (metadata.source !== 'field' && metadata.source !== 'shadow') || (slot === null || slot === void 0 ? void 0 : slot.kind) !== 'literal') {
172
+ issues.push(diagnostic(declaration, 'dependency-unverifiable', requirement.argument));
173
+ }
174
+ else if (requirement.rule === 'nonempty-string' && (typeof slot.value !== 'string' || !slot.value.trim())) {
175
+ issues.push(diagnostic(declaration, 'dependency-invalid', requirement.argument));
176
+ }
177
+ }
178
+ }
179
+ return Object.freeze(issues);
180
+ }
@@ -0,0 +1,39 @@
1
+ import type { FixedBlockSnapshot, FixedInputBranchRule, FixedInputControl, FixedInputDeclaration, FixedInputEditorDefinition, FixedPreparedSave } from './fixed-input-types.js';
2
+ import type { SchemaBundle, SchemaValidationContext } from './schema-types.js';
3
+ import type { EditorDefinition, JsonObject, JsonValue, LiteralValue, ValidationIssue } from './types.js';
4
+ export interface FixedInputBinding<C = null> {
5
+ readonly argument: string;
6
+ readonly schemaBundle: SchemaBundle;
7
+ readonly control?: FixedInputControl;
8
+ /** Produce a JSON editing projection. Throw to retain the raw literal as readonly. */
9
+ read(value: LiteralValue): JsonValue;
10
+ /** Construct the exact literal candidate once. A numeric buffer supplies its validated string token, which must be returned unchanged. Neither this nor validation may be asynchronous. */
11
+ encode(value: JsonValue, context: SchemaValidationContext<C>): LiteralValue;
12
+ /** Check the exact candidate. Messages from this callback are never rendered verbatim. */
13
+ validateCandidate(candidate: LiteralValue, context: SchemaValidationContext<C>, snapshot: FixedBlockSnapshot): readonly ValidationIssue[];
14
+ }
15
+ export interface FixedInputBranchPolicy<C = null> extends Omit<FixedInputBranchRule, 'cases'> {
16
+ readonly cases: readonly (FixedInputBranchRule['cases'][number] & {
17
+ readonly bindings?: readonly FixedInputBinding<C>[];
18
+ })[];
19
+ }
20
+ export interface FixedInputEditorOptions<C = null> {
21
+ readonly apiVersion: 1;
22
+ readonly extensionId: string;
23
+ readonly editorId: string;
24
+ readonly opcodes: readonly string[];
25
+ readonly contractId: string;
26
+ readonly contractRevision: string;
27
+ readonly readOnlyArguments?: readonly string[];
28
+ readonly dependencies?: FixedInputDeclaration['dependencies'];
29
+ readonly branchPolicies?: readonly FixedInputBranchPolicy<C>[];
30
+ readonly bindings: readonly FixedInputBinding<C>[];
31
+ readonly validationContext: () => SchemaValidationContext<C>;
32
+ }
33
+ /** Capture exactly the callbacks and declaration values subsequently registered. */
34
+ export declare function captureFixedInputEditorDefinition<C = null>(value: FixedInputEditorDefinition<C>): FixedInputEditorDefinition<C>;
35
+ export declare function isFixedInputEditor(definition: EditorDefinition): definition is FixedInputEditorDefinition<unknown>;
36
+ /** Capture a synchronous callback result without invoking getters, iterators, or toJSON. */
37
+ export declare function captureFixedPreparedSave<C = null>(definition: FixedInputEditorDefinition<C>, draft: JsonObject, snapshot: FixedBlockSnapshot): FixedPreparedSave<C>;
38
+ /** Fixed inputs are additive: legacy callbacks cannot accidentally save their drafts. */
39
+ export declare function createFixedInputEditor<C = null>(options: FixedInputEditorOptions<C>): FixedInputEditorDefinition<C>;