@kubohiroya/turbowarp-extension-data-editor 0.8.0 → 0.8.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 +1 -1
- package/README.md +1 -1
- package/dist/build-info.json +3 -3
- package/dist/turbowarp/appearance.d.ts +7 -6
- package/dist/turbowarp/bridge.d.ts +14 -19
- package/dist/turbowarp/bridge.js +21 -16
- package/dist/turbowarp/error-session.d.ts +3 -17
- package/dist/turbowarp/error-session.js +2 -2
- package/dist/turbowarp/fixed-fields.d.ts +62 -77
- package/dist/turbowarp/fixed-fields.js +6 -6
- package/dist/turbowarp/fixed-transaction.d.ts +23 -18
- package/dist/turbowarp/fixed-transaction.js +13 -13
- package/dist/turbowarp/host.d.ts +2 -18
- package/dist/turbowarp/host.js +9 -6
- package/dist/turbowarp/icon.d.ts +1 -8
- package/dist/turbowarp/icon.js +6 -6
- package/dist/turbowarp/native-types.d.ts +136 -0
- package/dist/turbowarp/native-types.js +1 -0
- package/dist/turbowarp/subtree.d.ts +12 -9
- package/dist/turbowarp/subtree.js +3 -2
- package/dist/webpack4/metafile.json +14 -14
- package/dist/webpack4/turbowarp.js +36 -29
- package/dist/webpack4/turbowarp.js.map +2 -2
- package/docs/ci-success-gate.md +2 -2
- package/docs/common-layout.ja.md +4 -4
- package/docs/descendants.md +2 -2
- package/docs/dialog-window.md +2 -2
- package/docs/schema-stage1.ja.md +3 -3
- package/docs/template-fixture-separation.ja.md +5 -5
- package/package.json +4 -4
- package/webpack4.cjs +19 -20
package/README.ja.md
CHANGED
|
@@ -153,7 +153,7 @@ npm install --save-exact @kubohiroya/turbowarp-extension-data-editor@0.2.2
|
|
|
153
153
|
|
|
154
154
|
## Optional editing examples
|
|
155
155
|
|
|
156
|
-
Repository examples are opt-in teaching code, not template blocks or additional package exports. See [the JSON/YAML document example](examples/document-properties.
|
|
156
|
+
Repository examples are opt-in teaching code, not template blocks or additional package exports. See [the JSON/YAML document example](examples/document-properties.ts) and [its guide](examples/README.ja.md). Each extension owns its actual data contract.
|
|
157
157
|
|
|
158
158
|
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.
|
|
159
159
|
|
package/README.md
CHANGED
|
@@ -151,7 +151,7 @@ The cross-repository validation record collected when introducing the existing S
|
|
|
151
151
|
|
|
152
152
|
## Optional editing examples
|
|
153
153
|
|
|
154
|
-
Repository examples are opt-in teaching code, not template blocks or additional package exports. See [the JSON/YAML document example](examples/document-properties.
|
|
154
|
+
Repository examples are opt-in teaching code, not template blocks or additional package exports. See [the JSON/YAML document example](examples/document-properties.ts) and [its guide (Japanese)](examples/README.ja.md). Each extension owns its actual data contract.
|
|
155
155
|
|
|
156
156
|
Prepared source editing is an optional host capability. See [the source/form contract (Japanese)](docs/source-forms.ja.md) for fixed-schema bindings, atomic saves, compatibility, and rollback.
|
|
157
157
|
|
package/dist/build-info.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubohiroya/turbowarp-extension-data-editor",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"repository": "https://github.com/kubohiroya/turbowarp-extension-data-editor",
|
|
5
|
-
"revision": "
|
|
5
|
+
"revision": "74d367a8de1980343240d4ded4de0f1ec37ed8e1",
|
|
6
6
|
"sourceState": "commit",
|
|
7
|
-
"sourceSha256": "
|
|
7
|
+
"sourceSha256": "194e2b4516115bd108da3a367228e037aa1405a8a24e0325d46af2eaa51f326d",
|
|
8
8
|
"capabilities": {
|
|
9
9
|
"preparedSource": 1
|
|
10
10
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
declare
|
|
3
|
-
name
|
|
4
|
-
colour
|
|
5
|
-
tint
|
|
6
|
-
iconURI
|
|
1
|
+
import type { NativeBlock, NativeScratchBlocks } from './native-types.js';
|
|
2
|
+
declare const readBlockEditorAppearance: (block: NativeBlock | null, ScratchBlocks: NativeScratchBlocks, editableArguments?: readonly string[]) => {
|
|
3
|
+
name?: string;
|
|
4
|
+
colour?: string;
|
|
5
|
+
tint?: string;
|
|
6
|
+
iconURI?: string;
|
|
7
7
|
};
|
|
8
|
+
export default readBlockEditorAppearance;
|
|
@@ -1,22 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}): {
|
|
1
|
+
import type { TurboWarpBlockEditorOptions } from '../turbowarp.js';
|
|
2
|
+
import type { BlockEditorHost, BlockReference } from '../types.js';
|
|
3
|
+
import type { EditorRegistry } from '../registry.js';
|
|
4
|
+
declare const openBlockEditorSession: ({ registry, reference, host, descendants }: {
|
|
5
|
+
registry: EditorRegistry;
|
|
6
|
+
reference: BlockReference;
|
|
7
|
+
host: BlockEditorHost;
|
|
8
|
+
descendants: boolean;
|
|
9
|
+
}) => import("../descendants.js").DescendantSession | import("../session.js").EditorSession | undefined;
|
|
10
|
+
declare const createBlockEditorBridge: ({ ScratchBlocks: nativeBlocks, workspace: nativeWorkspace, vm: nativeVM, service, label, canOpen, onOpen, onError, descendants, fixedInputs }: TurboWarpBlockEditorOptions & {
|
|
11
|
+
onError(error: unknown): void;
|
|
12
|
+
}) => {
|
|
14
13
|
refresh: () => void;
|
|
15
14
|
dispose: () => void;
|
|
16
15
|
};
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
reference: any;
|
|
20
|
-
host: any;
|
|
21
|
-
descendants: any;
|
|
22
|
-
}): any;
|
|
16
|
+
export default createBlockEditorBridge;
|
|
17
|
+
export { openBlockEditorSession };
|
package/dist/turbowarp/bridge.js
CHANGED
|
@@ -17,7 +17,10 @@ const openBlockEditorSession = ({ registry, reference, host, descendants }) => {
|
|
|
17
17
|
return descendants && supportsDescendantEditing(host) ?
|
|
18
18
|
registry.openDescendants(reference, host) : registry.open(reference, host);
|
|
19
19
|
};
|
|
20
|
-
const createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label, canOpen, onOpen, onError, descendants = false, fixedInputs = false }) => {
|
|
20
|
+
const createBlockEditorBridge = ({ ScratchBlocks: nativeBlocks, workspace: nativeWorkspace, vm: nativeVM, service, label, canOpen, onOpen, onError, descendants = false, fixedInputs = false }) => {
|
|
21
|
+
const ScratchBlocks = nativeBlocks;
|
|
22
|
+
const workspace = nativeWorkspace;
|
|
23
|
+
const vm = nativeVM;
|
|
21
24
|
const host = createBlockEditorHost({ ScratchBlocks,
|
|
22
25
|
workspace,
|
|
23
26
|
vm,
|
|
@@ -40,7 +43,7 @@ const createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label,
|
|
|
40
43
|
}
|
|
41
44
|
};
|
|
42
45
|
let disposed = false;
|
|
43
|
-
let timer
|
|
46
|
+
let timer;
|
|
44
47
|
let activeSession = null;
|
|
45
48
|
let openingSnapshot = null;
|
|
46
49
|
let openingFixedDeclaration = null;
|
|
@@ -49,7 +52,7 @@ const createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label,
|
|
|
49
52
|
const session = activeSession;
|
|
50
53
|
if (!session)
|
|
51
54
|
return;
|
|
52
|
-
if (typeof session.invalidate === 'function') {
|
|
55
|
+
if ('invalidate' in session && typeof session.invalidate === 'function') {
|
|
53
56
|
session.invalidate();
|
|
54
57
|
return;
|
|
55
58
|
}
|
|
@@ -61,42 +64,43 @@ const createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label,
|
|
|
61
64
|
stopWaiting = session.subscribe(() => {
|
|
62
65
|
if (session.getState().status === 'saving')
|
|
63
66
|
return;
|
|
64
|
-
stopWaiting();
|
|
67
|
+
stopWaiting === null || stopWaiting === void 0 ? void 0 : stopWaiting();
|
|
65
68
|
stopWaiting = null;
|
|
66
69
|
session.dispose();
|
|
67
70
|
});
|
|
68
71
|
}
|
|
69
72
|
};
|
|
70
73
|
const checkSession = () => {
|
|
71
|
-
var _a;
|
|
74
|
+
var _a, _b;
|
|
72
75
|
// The host owns rollback. Its synchronous transaction must retain the draft on failure.
|
|
73
76
|
if (host.isCommitting())
|
|
74
77
|
return;
|
|
75
78
|
if (!activeSession || !openingSnapshot ||
|
|
76
79
|
!['editing', 'saving'].includes(activeSession.getState().status))
|
|
77
80
|
return;
|
|
78
|
-
const current =
|
|
81
|
+
const current = 'getNodes' in activeSession ?
|
|
79
82
|
host.descendants.readSubtree(activeSession.reference) : host.readBlock(activeSession.reference);
|
|
80
83
|
if (openingFixedDeclaration) {
|
|
81
84
|
// Same-target external edits conflict at save while the session retains its draft.
|
|
82
85
|
// Project/target/registration replacement ends the session and drops that draft.
|
|
83
|
-
if (!current || ((
|
|
84
|
-
|
|
86
|
+
if (!current || (!('fixedContext' in current) || !('fixedContext' in openingSnapshot) ||
|
|
87
|
+
((_a = current.fixedContext) === null || _a === void 0 ? void 0 : _a.generation) !== ((_b = openingSnapshot.fixedContext) === null || _b === void 0 ? void 0 : _b.generation)) ||
|
|
88
|
+
fixedDeclaration(service.registry, 'opcode' in current ? current : null) !== openingFixedDeclaration)
|
|
85
89
|
endSession();
|
|
86
90
|
return;
|
|
87
91
|
}
|
|
88
92
|
if (!current || JSON.stringify(current) !== JSON.stringify(openingSnapshot))
|
|
89
93
|
endSession();
|
|
90
94
|
};
|
|
91
|
-
const available = block => {
|
|
95
|
+
const available = (block) => {
|
|
92
96
|
if (disposed || !vm.editingTarget || !canOpen() || !service.registry.resolve(block.type))
|
|
93
97
|
return false;
|
|
94
98
|
const snapshot = host.readBlock({ targetId: vm.editingTarget.id, blockId: block.id });
|
|
95
99
|
if (fixedDeclaration(service.registry, snapshot))
|
|
96
100
|
return supportsFixedInputEditing(host);
|
|
97
|
-
return snapshot && Object.values(snapshot.arguments).every(slot => slot.kind === 'literal');
|
|
101
|
+
return snapshot !== null && Object.values(snapshot.arguments).every(slot => slot.kind === 'literal');
|
|
98
102
|
};
|
|
99
|
-
const open = block => {
|
|
103
|
+
const open = (block) => {
|
|
100
104
|
var _a, _b;
|
|
101
105
|
clearHover();
|
|
102
106
|
if (activeSession && ['editing', 'saving'].includes(activeSession.getState().status))
|
|
@@ -109,15 +113,15 @@ const createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label,
|
|
|
109
113
|
if (session) {
|
|
110
114
|
ScratchBlocks.hideChaff();
|
|
111
115
|
activeSession = session;
|
|
112
|
-
openingSnapshot =
|
|
116
|
+
openingSnapshot = 'getNodes' in session ?
|
|
113
117
|
host.descendants.readSubtree(session.reference) : host.readBlock(session.reference);
|
|
114
|
-
openingFixedDeclaration = fixedDeclaration(service.registry, openingSnapshot) || null;
|
|
118
|
+
openingFixedDeclaration = fixedDeclaration(service.registry, openingSnapshot && 'opcode' in openingSnapshot ? openingSnapshot : null) || null;
|
|
115
119
|
const labels = {};
|
|
116
120
|
const appearances = Object.create(null);
|
|
117
121
|
const rootAppearance = readBlockEditorAppearance(block, ScratchBlocks, (_a = service.registry.resolve(block.type)) === null || _a === void 0 ? void 0 : _a.editableArguments);
|
|
118
122
|
appearances[reference.blockId] = rootAppearance;
|
|
119
123
|
labels[reference.blockId] = rootAppearance.name || block.type;
|
|
120
|
-
if (
|
|
124
|
+
if ('getNodes' in session) {
|
|
121
125
|
for (const node of session.getNodes()) {
|
|
122
126
|
const source = workspace.getBlockById(node.reference.blockId);
|
|
123
127
|
const appearance = readBlockEditorAppearance(source, ScratchBlocks, (_b = service.registry.resolve(node.opcode)) === null || _b === void 0 ? void 0 : _b.editableArguments);
|
|
@@ -205,12 +209,13 @@ const createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label,
|
|
|
205
209
|
const unregister = service.subscribe(() => {
|
|
206
210
|
// Aggregate sessions observe relevant registry changes themselves.
|
|
207
211
|
if (openingFixedDeclaration && activeSession) {
|
|
208
|
-
if (
|
|
212
|
+
if (openingSnapshot && 'opcode' in openingSnapshot &&
|
|
213
|
+
service.registry.resolveFixed(openingSnapshot.opcode) !== openingFixedDeclaration) {
|
|
209
214
|
host.invalidate();
|
|
210
215
|
endSession();
|
|
211
216
|
}
|
|
212
217
|
}
|
|
213
|
-
else if (!activeSession ||
|
|
218
|
+
else if (!activeSession || !('getNodes' in activeSession)) {
|
|
214
219
|
host.invalidate();
|
|
215
220
|
endSession();
|
|
216
221
|
}
|
|
@@ -1,18 +1,4 @@
|
|
|
1
|
+
import type { BlockReference } from '../types.js';
|
|
2
|
+
import type { BlockEditorFailureSession } from '../turbowarp.js';
|
|
3
|
+
declare const createBlockEditorErrorSession: (reference: BlockReference, error: unknown) => BlockEditorFailureSession;
|
|
1
4
|
export default createBlockEditorErrorSession;
|
|
2
|
-
declare function createBlockEditorErrorSession(reference: any, error: any): Readonly<{
|
|
3
|
-
reference: any;
|
|
4
|
-
getState: () => {
|
|
5
|
-
status: string;
|
|
6
|
-
canSave: boolean;
|
|
7
|
-
issues: never[];
|
|
8
|
-
error: any;
|
|
9
|
-
};
|
|
10
|
-
subscribe: (listener: any) => () => boolean;
|
|
11
|
-
mount: () => () => void;
|
|
12
|
-
save: () => Promise<{
|
|
13
|
-
status: string;
|
|
14
|
-
error: any;
|
|
15
|
-
}>;
|
|
16
|
-
cancel: () => boolean;
|
|
17
|
-
dispose: () => true;
|
|
18
|
-
}>;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const createBlockEditorErrorSession = (reference, error) => {
|
|
3
3
|
let status = 'editing';
|
|
4
4
|
const listeners = new Set();
|
|
5
|
-
const finish = next => {
|
|
5
|
+
const finish = (next) => {
|
|
6
6
|
if (status !== 'editing')
|
|
7
7
|
return false;
|
|
8
8
|
status = next;
|
|
@@ -14,7 +14,7 @@ const createBlockEditorErrorSession = (reference, error) => {
|
|
|
14
14
|
return Object.freeze({
|
|
15
15
|
reference,
|
|
16
16
|
getState: () => ({ status, canSave: false, issues: [], error }),
|
|
17
|
-
subscribe: listener => {
|
|
17
|
+
subscribe: (listener) => {
|
|
18
18
|
listeners.add(listener);
|
|
19
19
|
return () => listeners.delete(listener);
|
|
20
20
|
},
|
|
@@ -1,82 +1,67 @@
|
|
|
1
|
+
import type { FixedInputMetadata } from '../fixed-input-types.js';
|
|
2
|
+
import type { ArgumentSlot } from '../types.js';
|
|
3
|
+
import type { Identify, NativeBlock, NativeField, NativeFieldClass, NativeScratchBlocks, NativeTarget, VMBlock } from './native-types.js';
|
|
4
|
+
export interface FieldBinding {
|
|
5
|
+
block: NativeBlock;
|
|
6
|
+
field: NativeField;
|
|
7
|
+
fieldName: string;
|
|
8
|
+
value: string;
|
|
9
|
+
vmBlock: VMBlock;
|
|
10
|
+
kind: 'text' | 'number' | 'menu' | 'color';
|
|
11
|
+
Class: NativeFieldClass;
|
|
12
|
+
prototype: object;
|
|
13
|
+
allowedValues: readonly string[] | null | undefined;
|
|
14
|
+
restoreValue: NativeField['setValue'];
|
|
15
|
+
rawState: PropertyState[];
|
|
16
|
+
restoreHandles(): void;
|
|
17
|
+
restoreDom(): void;
|
|
18
|
+
restoreState?: ReturnType<typeof colorState>;
|
|
19
|
+
}
|
|
20
|
+
interface Inspection {
|
|
21
|
+
slot: ArgumentSlot;
|
|
22
|
+
metadata: FixedInputMetadata;
|
|
23
|
+
signatureParts: unknown[];
|
|
24
|
+
binding?: FieldBinding;
|
|
25
|
+
}
|
|
26
|
+
type PropertyState = [name: string, descriptor: PropertyDescriptor | undefined];
|
|
1
27
|
/** Freeze native method identities once when the host attaches, before opening editors. */
|
|
2
|
-
export function initializeFixedFields(ScratchBlocks:
|
|
28
|
+
export declare function initializeFixedFields(ScratchBlocks: NativeScratchBlocks): void;
|
|
29
|
+
declare const colorState: (block: NativeBlock, field: NativeField) => {
|
|
30
|
+
colors: unknown[];
|
|
31
|
+
hsv: unknown[][];
|
|
32
|
+
blockProperties: PropertyState[];
|
|
33
|
+
};
|
|
3
34
|
/** Native objects stay local; only primitive metadata is returned in snapshots. */
|
|
4
|
-
export function inspectFixedArgument({ ScratchBlocks, block, vmBlock, target, argument, role, identify, extensionId }: {
|
|
5
|
-
ScratchBlocks:
|
|
6
|
-
block:
|
|
7
|
-
vmBlock:
|
|
8
|
-
target:
|
|
9
|
-
argument:
|
|
10
|
-
role:
|
|
11
|
-
identify:
|
|
12
|
-
extensionId:
|
|
13
|
-
}):
|
|
14
|
-
slot: {
|
|
15
|
-
kind: string;
|
|
16
|
-
value: string | number | boolean;
|
|
17
|
-
} | {
|
|
18
|
-
kind: string;
|
|
19
|
-
value?: never;
|
|
20
|
-
};
|
|
21
|
-
metadata: {
|
|
22
|
-
role: any;
|
|
23
|
-
source: any;
|
|
24
|
-
identity: string;
|
|
25
|
-
reason: any;
|
|
26
|
-
};
|
|
27
|
-
signatureParts: any[];
|
|
28
|
-
} | {
|
|
29
|
-
slot: {
|
|
30
|
-
kind: string;
|
|
31
|
-
value?: never;
|
|
32
|
-
};
|
|
33
|
-
metadata: {
|
|
34
|
-
role: any;
|
|
35
|
-
source: string;
|
|
36
|
-
identity: string;
|
|
37
|
-
field?: never;
|
|
38
|
-
};
|
|
39
|
-
signatureParts: any[];
|
|
40
|
-
} | {
|
|
41
|
-
signatureParts: any[];
|
|
42
|
-
binding?: {
|
|
43
|
-
restoreState?: {
|
|
44
|
-
colors: any[];
|
|
45
|
-
hsv: any[][];
|
|
46
|
-
blockProperties: any;
|
|
47
|
-
};
|
|
48
|
-
block: any;
|
|
49
|
-
field: any;
|
|
50
|
-
fieldName: any;
|
|
51
|
-
value: string;
|
|
52
|
-
vmBlock: any;
|
|
53
|
-
kind: string;
|
|
54
|
-
Class: any;
|
|
55
|
-
prototype: any;
|
|
56
|
-
allowedValues: readonly string[] | null | undefined;
|
|
57
|
-
restoreValue: any;
|
|
58
|
-
rawState: any;
|
|
59
|
-
restoreHandles: any;
|
|
60
|
-
restoreDom: any;
|
|
61
|
-
};
|
|
62
|
-
slot: {
|
|
63
|
-
kind: string;
|
|
64
|
-
value: string | number;
|
|
65
|
-
};
|
|
66
|
-
metadata: {
|
|
67
|
-
role: any;
|
|
68
|
-
source: string;
|
|
69
|
-
identity: string;
|
|
70
|
-
field: {
|
|
71
|
-
blockId: any;
|
|
72
|
-
name: any;
|
|
73
|
-
type: string | undefined;
|
|
74
|
-
};
|
|
75
|
-
};
|
|
76
|
-
} | null;
|
|
35
|
+
export declare function inspectFixedArgument({ ScratchBlocks, block, vmBlock, target, argument, role, identify, extensionId }: {
|
|
36
|
+
ScratchBlocks: NativeScratchBlocks;
|
|
37
|
+
block: NativeBlock;
|
|
38
|
+
vmBlock: VMBlock;
|
|
39
|
+
target: NativeTarget;
|
|
40
|
+
argument: string;
|
|
41
|
+
role: FixedInputMetadata['role'];
|
|
42
|
+
identify: Identify;
|
|
43
|
+
extensionId: string;
|
|
44
|
+
}): Inspection | null;
|
|
77
45
|
/** Validate the exact saved primitive; native setters must not silently normalize it. */
|
|
78
|
-
export function prepareFixedChange(binding:
|
|
46
|
+
export declare function prepareFixedChange(binding: FieldBinding, value: unknown): {
|
|
47
|
+
next: string;
|
|
48
|
+
block: NativeBlock;
|
|
49
|
+
field: NativeField;
|
|
50
|
+
fieldName: string;
|
|
51
|
+
value: string;
|
|
52
|
+
vmBlock: VMBlock;
|
|
53
|
+
kind: "text" | "number" | "menu" | "color";
|
|
54
|
+
Class: NativeFieldClass;
|
|
55
|
+
prototype: object;
|
|
56
|
+
allowedValues: readonly string[] | null | undefined;
|
|
57
|
+
restoreValue: NativeField["setValue"];
|
|
58
|
+
rawState: PropertyState[];
|
|
59
|
+
restoreHandles(): void;
|
|
60
|
+
restoreDom(): void;
|
|
61
|
+
restoreState?: ReturnType<typeof colorState>;
|
|
62
|
+
};
|
|
79
63
|
/** Capture a later external value without invoking replacement field methods. */
|
|
80
|
-
export function captureFixedFieldState(binding:
|
|
64
|
+
export declare function captureFixedFieldState(binding: FieldBinding): FieldBinding;
|
|
81
65
|
/** Restore raw text and the standard color field's additional block/UI state. */
|
|
82
|
-
export function restoreFixedField(binding:
|
|
66
|
+
export declare function restoreFixedField(binding: FieldBinding): void;
|
|
67
|
+
export {};
|
|
@@ -3,7 +3,7 @@ const own = (object, key) => {
|
|
|
3
3
|
const descriptor = object && Object.getOwnPropertyDescriptor(object, key);
|
|
4
4
|
return descriptor && 'value' in descriptor ? descriptor.value : undefined;
|
|
5
5
|
};
|
|
6
|
-
const primitive = value => typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
|
|
6
|
+
const primitive = (value) => typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
|
|
7
7
|
const token = /^-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?$/u;
|
|
8
8
|
// Inspect data properties without invoking custom field accessors or menu providers.
|
|
9
9
|
const inherited = (object, name) => {
|
|
@@ -41,7 +41,7 @@ const safeField = (field, Class) => {
|
|
|
41
41
|
if (currentPrototype !== entry.prototype)
|
|
42
42
|
return false;
|
|
43
43
|
for (const [name, expected] of entry.own) {
|
|
44
|
-
const actual = Object.getOwnPropertyDescriptor(
|
|
44
|
+
const actual = Object.getOwnPropertyDescriptor(entry.prototype, name);
|
|
45
45
|
if (Boolean(actual) !== Boolean(expected) ||
|
|
46
46
|
(actual && (!('value' in actual) || !expected || !('value' in expected) || actual.value !== expected.value)))
|
|
47
47
|
return false;
|
|
@@ -71,7 +71,7 @@ const safeField = (field, Class) => {
|
|
|
71
71
|
}
|
|
72
72
|
return false;
|
|
73
73
|
};
|
|
74
|
-
const arrayData = value => {
|
|
74
|
+
const arrayData = (value) => {
|
|
75
75
|
if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype)
|
|
76
76
|
return null;
|
|
77
77
|
const result = [];
|
|
@@ -83,7 +83,7 @@ const arrayData = value => {
|
|
|
83
83
|
}
|
|
84
84
|
return result;
|
|
85
85
|
};
|
|
86
|
-
const staticValues = field => {
|
|
86
|
+
const staticValues = (field) => {
|
|
87
87
|
const items = arrayData(own(field, 'menuGenerator_'));
|
|
88
88
|
if (!items || items.length === 0)
|
|
89
89
|
return null;
|
|
@@ -156,7 +156,7 @@ export function inspectFixedArgument({ ScratchBlocks, block, vmBlock, target, ar
|
|
|
156
156
|
return { slot: { kind: 'reporter' }, metadata: { role, source: 'reporter', identity: JSON.stringify(sourceIdentity) },
|
|
157
157
|
signatureParts: sourceIdentity };
|
|
158
158
|
}
|
|
159
|
-
|
|
159
|
+
const owner = direct ? block : connected;
|
|
160
160
|
if (!owner) {
|
|
161
161
|
if (vmBlock.fields && owns(vmBlock.fields, argument))
|
|
162
162
|
return null;
|
|
@@ -204,7 +204,7 @@ export function inspectFixedArgument({ ScratchBlocks, block, vmBlock, target, ar
|
|
|
204
204
|
}
|
|
205
205
|
if (names.length !== 1)
|
|
206
206
|
return unavailable('unsupported', 'The menu shadow does not have one standard field.');
|
|
207
|
-
|
|
207
|
+
name = names[0];
|
|
208
208
|
}
|
|
209
209
|
else
|
|
210
210
|
return unavailable('unsupported', 'The shadow field family is unsupported.');
|
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
import type { FixedInputEditorHost } from '../fixed-input-types.js';
|
|
2
|
+
import type { EditorRegistry } from '../registry.js';
|
|
3
|
+
import type { Identify, NativeChange, NativeScratchBlocks, NativeVM, NativeWorkspace } from './native-types.js';
|
|
4
|
+
interface FixedPortOptions {
|
|
5
|
+
ScratchBlocks: NativeScratchBlocks;
|
|
6
|
+
workspace: NativeWorkspace;
|
|
7
|
+
vm: NativeVM;
|
|
8
|
+
registry: EditorRegistry;
|
|
9
|
+
identify: Identify;
|
|
10
|
+
getState(): {
|
|
11
|
+
disposed: boolean;
|
|
12
|
+
revision: number;
|
|
13
|
+
generation: number;
|
|
14
|
+
externalRevision: number;
|
|
15
|
+
};
|
|
16
|
+
begin(): void;
|
|
17
|
+
markEvent(event: NativeChange): void;
|
|
18
|
+
finish(succeeded: boolean): void;
|
|
19
|
+
onError(error: unknown): void;
|
|
20
|
+
subscribeScope(listener: () => void): () => void;
|
|
21
|
+
}
|
|
22
|
+
export default function createFixedInputPort({ ScratchBlocks, workspace, vm, registry, identify, getState, begin, markEvent, finish, onError, subscribeScope }: FixedPortOptions): FixedInputEditorHost;
|
|
23
|
+
export {};
|
|
@@ -4,7 +4,7 @@ import { initializeFixedFields, inspectFixedArgument, prepareFixedChange, restor
|
|
|
4
4
|
import { snapshotJson } from '../schema-json.js';
|
|
5
5
|
import { validateFixedBranchChanges } from '../fixed-input-branches.js';
|
|
6
6
|
const own = (object, name) => {
|
|
7
|
-
const descriptor = object
|
|
7
|
+
const descriptor = object ? Object.getOwnPropertyDescriptor(object, name) : undefined;
|
|
8
8
|
if (!descriptor || !Object.prototype.hasOwnProperty.call(descriptor, 'value')) {
|
|
9
9
|
throw new TypeError('Expected an own data property.');
|
|
10
10
|
}
|
|
@@ -21,9 +21,10 @@ const inheritedData = (object, key) => {
|
|
|
21
21
|
}
|
|
22
22
|
return undefined;
|
|
23
23
|
};
|
|
24
|
-
const ensureNativeHistory = stack => {
|
|
24
|
+
const ensureNativeHistory = (stack) => {
|
|
25
|
+
var _a;
|
|
25
26
|
if (!Array.isArray(stack) || !Object.isExtensible(stack) ||
|
|
26
|
-
Object.getOwnPropertySymbols(stack).length || !Object.getOwnPropertyDescriptor(stack, 'length').writable) {
|
|
27
|
+
Object.getOwnPropertySymbols(stack).length || !((_a = Object.getOwnPropertyDescriptor(stack, 'length')) === null || _a === void 0 ? void 0 : _a.writable)) {
|
|
27
28
|
throw new TypeError('Unsupported undo history.');
|
|
28
29
|
}
|
|
29
30
|
if (Object.getOwnPropertyNames(stack).length !== stack.length + 1)
|
|
@@ -35,7 +36,7 @@ const ensureNativeHistory = stack => {
|
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
};
|
|
38
|
-
const copyHistory = stack => {
|
|
39
|
+
const copyHistory = (stack) => {
|
|
39
40
|
const copy = [];
|
|
40
41
|
for (let index = 0; index < stack.length; index++)
|
|
41
42
|
copy.push(own(stack, String(index)));
|
|
@@ -46,11 +47,11 @@ const replaceHistory = (stack, values) => {
|
|
|
46
47
|
for (const value of values)
|
|
47
48
|
Array.prototype.push.call(stack, value);
|
|
48
49
|
};
|
|
49
|
-
|
|
50
|
+
function conflict() { throw new BlockEditorConflictError(); }
|
|
50
51
|
const aborted = Object.getOwnPropertyDescriptor(AbortSignal.prototype, 'aborted').get;
|
|
51
|
-
const isAborted = signal => aborted.call(signal);
|
|
52
|
+
const isAborted = (signal) => aborted.call(signal);
|
|
52
53
|
const optionalOwn = (object, name) => {
|
|
53
|
-
const descriptor = object
|
|
54
|
+
const descriptor = object ? Object.getOwnPropertyDescriptor(object, name) : undefined;
|
|
54
55
|
if (descriptor && !Object.prototype.hasOwnProperty.call(descriptor, 'value')) {
|
|
55
56
|
throw new TypeError('VM state must contain data properties.');
|
|
56
57
|
}
|
|
@@ -79,7 +80,7 @@ const untouchedState = (block, vmBlock, target, bindings, identify) => {
|
|
|
79
80
|
}
|
|
80
81
|
const seen = new Set();
|
|
81
82
|
const records = [];
|
|
82
|
-
const capture = item => {
|
|
83
|
+
const capture = (item) => {
|
|
83
84
|
if (!item || seen.has(item))
|
|
84
85
|
return;
|
|
85
86
|
seen.add(item);
|
|
@@ -112,8 +113,7 @@ const untouchedState = (block, vmBlock, target, bindings, identify) => {
|
|
|
112
113
|
});
|
|
113
114
|
return JSON.stringify([records, connections, statementConnections]);
|
|
114
115
|
};
|
|
115
|
-
const sameDeclaration = (left, right) => JSON.stringify(captureFixedInputDeclaration(left)) ===
|
|
116
|
-
JSON.stringify(captureFixedInputDeclaration(right));
|
|
116
|
+
const sameDeclaration = (left, right) => JSON.stringify(captureFixedInputDeclaration(left)) === JSON.stringify(captureFixedInputDeclaration(right));
|
|
117
117
|
// Fixed inputs deliberately use a separate transaction from the legacy TEXT adapter.
|
|
118
118
|
export default function createFixedInputPort({ ScratchBlocks, workspace, vm, registry, identify, getState, begin, markEvent, finish, onError, subscribeScope }) {
|
|
119
119
|
initializeFixedFields(ScratchBlocks);
|
|
@@ -162,7 +162,7 @@ export default function createFixedInputPort({ ScratchBlocks, workspace, vm, reg
|
|
|
162
162
|
} }, reference, declaration);
|
|
163
163
|
return { snapshot, bindings, declaration, target, block, vmBlock, state, untouched, runtime: vm.runtime };
|
|
164
164
|
};
|
|
165
|
-
const commit = request => {
|
|
165
|
+
const commit = (request) => {
|
|
166
166
|
var _a;
|
|
167
167
|
const expectedInput = own(request, 'expected');
|
|
168
168
|
const changesInput = own(request, 'changes');
|
|
@@ -238,7 +238,7 @@ export default function createFixedInputPort({ ScratchBlocks, workspace, vm, reg
|
|
|
238
238
|
ensureNativeHistory(redoStack);
|
|
239
239
|
const configuredMaxUndo = inheritedData(workspace, 'MAX_UNDO');
|
|
240
240
|
const maxUndo = configuredMaxUndo === undefined ? Infinity : configuredMaxUndo;
|
|
241
|
-
if (maxUndo !== Infinity && (!Number.isSafeInteger(maxUndo) || maxUndo < 0)) {
|
|
241
|
+
if (typeof maxUndo !== 'number' || (maxUndo !== Infinity && (!Number.isSafeInteger(maxUndo) || maxUndo < 0))) {
|
|
242
242
|
throw new TypeError('Unsupported undo configuration.');
|
|
243
243
|
}
|
|
244
244
|
const undo = copyHistory(undoStack);
|
|
@@ -290,7 +290,7 @@ export default function createFixedInputPort({ ScratchBlocks, workspace, vm, reg
|
|
|
290
290
|
const fields = edited.vmBlock.fields;
|
|
291
291
|
const field = fields && fields[edited.fieldName];
|
|
292
292
|
externalWrites.set(edited.field, { binding: captureFixedFieldState(edited),
|
|
293
|
-
|
|
293
|
+
field, descriptors: field && Object.getOwnPropertyDescriptors(field) });
|
|
294
294
|
}
|
|
295
295
|
activeEvent = previous;
|
|
296
296
|
}
|
package/dist/turbowarp/host.d.ts
CHANGED
|
@@ -1,19 +1,3 @@
|
|
|
1
|
+
import type { TurboWarpHostOptions, TurboWarpBlockEditorHost } from '../turbowarp.js';
|
|
2
|
+
declare const createBlockEditorHost: ({ ScratchBlocks: nativeBlocks, workspace: nativeWorkspace, vm: nativeVM, registry, enableDescendants, enableFixedInputs, onError }: TurboWarpHostOptions) => TurboWarpBlockEditorHost;
|
|
1
3
|
export default createBlockEditorHost;
|
|
2
|
-
declare function createBlockEditorHost({ ScratchBlocks, workspace, vm, registry, enableDescendants, enableFixedInputs, onError }: {
|
|
3
|
-
ScratchBlocks: any;
|
|
4
|
-
workspace: any;
|
|
5
|
-
vm: any;
|
|
6
|
-
registry: any;
|
|
7
|
-
enableDescendants?: boolean | undefined;
|
|
8
|
-
enableFixedInputs?: boolean | undefined;
|
|
9
|
-
onError?: ((...data: any[]) => void) | undefined;
|
|
10
|
-
}): {
|
|
11
|
-
isCommitting: () => boolean;
|
|
12
|
-
readBlock: (reference: any) => any;
|
|
13
|
-
commit: ({ expected, changes }: {
|
|
14
|
-
expected: any;
|
|
15
|
-
changes: any;
|
|
16
|
-
}) => void;
|
|
17
|
-
invalidate: () => void;
|
|
18
|
-
dispose: () => void;
|
|
19
|
-
};
|
package/dist/turbowarp/host.js
CHANGED
|
@@ -3,7 +3,10 @@ import collectBlockEditorSubtree from './subtree.js';
|
|
|
3
3
|
import createFixedInputPort from './fixed-transaction.js';
|
|
4
4
|
const owns = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
|
|
5
5
|
// Adapt only standard, unvalidated text shadows; never evaluate connected reporters.
|
|
6
|
-
const createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableDescendants = false, enableFixedInputs = false, onError = console.error }) => {
|
|
6
|
+
const createBlockEditorHost = ({ ScratchBlocks: nativeBlocks, workspace: nativeWorkspace, vm: nativeVM, registry, enableDescendants = false, enableFixedInputs = false, onError = console.error }) => {
|
|
7
|
+
const ScratchBlocks = nativeBlocks;
|
|
8
|
+
const workspace = nativeWorkspace;
|
|
9
|
+
const vm = nativeVM;
|
|
7
10
|
let disposed = false;
|
|
8
11
|
let committing = false;
|
|
9
12
|
let revision = 0;
|
|
@@ -30,12 +33,12 @@ const createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableD
|
|
|
30
33
|
};
|
|
31
34
|
let notifyInvalidations = () => { };
|
|
32
35
|
const identities = new WeakMap();
|
|
33
|
-
const identify = object => {
|
|
36
|
+
const identify = (object) => {
|
|
34
37
|
if (!identities.has(object))
|
|
35
38
|
identities.set(object, ++identity);
|
|
36
39
|
return identities.get(object);
|
|
37
40
|
};
|
|
38
|
-
const invalidate = event => {
|
|
41
|
+
const invalidate = (event) => {
|
|
39
42
|
if (event && event.isUiEvent)
|
|
40
43
|
return;
|
|
41
44
|
revision++;
|
|
@@ -163,7 +166,7 @@ const createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableD
|
|
|
163
166
|
vmBlock
|
|
164
167
|
};
|
|
165
168
|
};
|
|
166
|
-
const collect = reference => collectBlockEditorSubtree({ ScratchBlocks, reference, inspect, generation });
|
|
169
|
+
const collect = (reference) => collectBlockEditorSubtree({ ScratchBlocks, reference, inspect, generation });
|
|
167
170
|
notifyInvalidations = () => {
|
|
168
171
|
if (committing)
|
|
169
172
|
return;
|
|
@@ -171,7 +174,7 @@ const createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableD
|
|
|
171
174
|
let matches = false;
|
|
172
175
|
try {
|
|
173
176
|
const current = collect(item.reference);
|
|
174
|
-
matches = current && JSON.stringify(current.snapshot) === JSON.stringify(item.snapshot);
|
|
177
|
+
matches = current !== null && JSON.stringify(current.snapshot) === JSON.stringify(item.snapshot);
|
|
175
178
|
}
|
|
176
179
|
catch (error) {
|
|
177
180
|
// A malformed replacement graph invalidates an already open session too.
|
|
@@ -201,7 +204,7 @@ const createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableD
|
|
|
201
204
|
Events.disable();
|
|
202
205
|
committing = true;
|
|
203
206
|
try {
|
|
204
|
-
if (signal && signal.aborted)
|
|
207
|
+
if (!target || (signal && signal.aborted))
|
|
205
208
|
throw new BlockEditorConflictError();
|
|
206
209
|
for (const item of prepared) {
|
|
207
210
|
item.field.setValue(item.next);
|