@kubohiroya/turbowarp-extension-data-editor 0.7.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.
@@ -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: any): void;
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: any;
6
- block: any;
7
- vmBlock: any;
8
- target: any;
9
- argument: any;
10
- role: any;
11
- identify: any;
12
- extensionId: any;
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: any, value: any): any;
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: any): any;
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: any): void;
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(currentPrototype, name);
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
- let owner = direct ? block : connected;
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
- [name] = names;
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
- export default function createFixedInputPort({ ScratchBlocks, workspace, vm, registry, identify, getState, begin, markEvent, finish, onError, subscribeScope }: {
2
- ScratchBlocks: any;
3
- workspace: any;
4
- vm: any;
5
- registry: any;
6
- identify: any;
7
- getState: any;
8
- begin: any;
9
- markEvent: any;
10
- finish: any;
11
- onError: any;
12
- subscribeScope: any;
13
- }): Readonly<{
14
- capability: "fixed-inputs-v1";
15
- readBlock: (reference: any, declaration: any) => import("../fixed-input-types.js").FixedBlockSnapshot | null;
16
- commit: (request: any) => void;
17
- subscribeInvalidation: (reference: any, declaration: any, listener: any) => () => void;
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 && Object.getOwnPropertyDescriptor(object, name);
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
- const conflict = () => { throw new BlockEditorConflictError(); };
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 && Object.getOwnPropertyDescriptor(object, name);
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
- fields, field, descriptors: field && Object.getOwnPropertyDescriptors(field) });
293
+ field, descriptors: field && Object.getOwnPropertyDescriptors(field) });
294
294
  }
295
295
  activeEvent = previous;
296
296
  }
@@ -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
- };
@@ -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);
@@ -1,9 +1,2 @@
1
+ declare const bindBlockEditorIcon: ({ element, label, canOpen, onOpen, onHover, onLeave }: Parameters<typeof import("../turbowarp.js").bindBlockEditorIcon>[0]) => () => void;
1
2
  export default bindBlockEditorIcon;
2
- declare function bindBlockEditorIcon({ element, label, canOpen, onOpen, onHover, onLeave }: {
3
- element: any;
4
- label: any;
5
- canOpen: any;
6
- onOpen: any;
7
- onHover?: (() => void) | undefined;
8
- onLeave?: (() => void) | undefined;
9
- }): () => void;
@@ -4,13 +4,13 @@ const bindBlockEditorIcon = ({ element, label, canOpen, onOpen, onHover = () =>
4
4
  const previous = attributes.map(name => element.getAttribute(name));
5
5
  const oldCursor = element.style.cursor;
6
6
  let press = null;
7
- const stop = event => {
7
+ const stop = (event) => {
8
8
  if (!canOpen())
9
9
  return;
10
10
  event.stopPropagation();
11
11
  event.preventDefault();
12
12
  };
13
- const down = event => {
13
+ const down = (event) => {
14
14
  if (!canOpen() || event.button !== 0 || event.isPrimary === false)
15
15
  return;
16
16
  stop(event);
@@ -19,14 +19,14 @@ const bindBlockEditorIcon = ({ element, label, canOpen, onOpen, onHover = () =>
19
19
  if (element.setPointerCapture)
20
20
  element.setPointerCapture(event.pointerId);
21
21
  };
22
- const move = event => {
22
+ const move = (event) => {
23
23
  if (!press || press.id !== event.pointerId)
24
24
  return;
25
25
  stop(event);
26
26
  if (Math.hypot(event.clientX - press.x, event.clientY - press.y) > 4)
27
27
  press.moved = true;
28
28
  };
29
- const up = event => {
29
+ const up = (event) => {
30
30
  if (!press || press.id !== event.pointerId)
31
31
  return;
32
32
  move(event);
@@ -41,7 +41,7 @@ const bindBlockEditorIcon = ({ element, label, canOpen, onOpen, onHover = () =>
41
41
  const cancel = () => {
42
42
  press = null;
43
43
  };
44
- const key = event => {
44
+ const key = (event) => {
45
45
  if ((event.key === 'Enter' || event.key === ' ') && canOpen()) {
46
46
  stop(event);
47
47
  if (!event.repeat)
@@ -68,7 +68,7 @@ const bindBlockEditorIcon = ({ element, label, canOpen, onOpen, onHover = () =>
68
68
  for (const [type, listener] of listeners)
69
69
  element.removeEventListener(type, listener);
70
70
  attributes.forEach((name, index) => {
71
- if (previous[index] === null)
71
+ if (previous[index] == null)
72
72
  element.removeAttribute(name);
73
73
  else
74
74
  element.setAttribute(name, previous[index]);
@@ -0,0 +1,136 @@
1
+ import type { BlockSnapshot } from '../types.js';
2
+ export interface NativeField {
3
+ name?: string;
4
+ getValue(): unknown;
5
+ getText(): string;
6
+ setValue(value: string): void;
7
+ getValidator(): unknown;
8
+ }
9
+ interface ImageField extends NativeField {
10
+ fieldGroup_: SVGElement;
11
+ imageElement_: {
12
+ tooltip: unknown;
13
+ };
14
+ setTooltip(label: string): void;
15
+ }
16
+ export interface NativeFieldClass {
17
+ new (...args: never[]): NativeField;
18
+ prototype: NativeField;
19
+ }
20
+ interface Connection {
21
+ targetConnection: Connection | null;
22
+ targetBlock(): NativeBlock | null;
23
+ }
24
+ export interface NativeBlock {
25
+ id: string;
26
+ type: string;
27
+ isInFlyout?: boolean;
28
+ inputList: Array<{
29
+ name: string;
30
+ type: number;
31
+ fieldRow: NativeField[];
32
+ connection: Connection | null;
33
+ }>;
34
+ previousConnection: Connection | null;
35
+ nextConnection: Connection | null;
36
+ outputConnection: Connection | null;
37
+ isShadow(): boolean;
38
+ isEditable(): boolean;
39
+ getInput(name: string): NativeBlock['inputList'][number] | null;
40
+ getField(name: string): NativeField | null;
41
+ getParent(): NativeBlock | null;
42
+ getNextBlock(): NativeBlock | null;
43
+ getColour(): unknown;
44
+ getColourSecondary(): unknown;
45
+ getColourTertiary(): unknown;
46
+ getColourQuaternary(): unknown;
47
+ setColour(...colors: string[]): void;
48
+ }
49
+ export interface NativeChange {
50
+ type: string;
51
+ element?: string;
52
+ name?: string;
53
+ blockId?: string;
54
+ ids?: string[];
55
+ isUiEvent?: boolean;
56
+ oldValue?: unknown;
57
+ recordUndo: boolean;
58
+ }
59
+ export interface NativeScratchBlocks {
60
+ INPUT_VALUE: number;
61
+ NEXT_STATEMENT: number;
62
+ FieldImage: new (...args: never[]) => ImageField;
63
+ FieldTextInput: NativeFieldClass;
64
+ FieldNumber: NativeFieldClass;
65
+ FieldDropdown: NativeFieldClass;
66
+ FieldColourSlider: NativeFieldClass;
67
+ hideChaff(): void;
68
+ Events: {
69
+ Change: new (block: NativeBlock, element: string, name: string, before: string, after: string) => NativeChange;
70
+ recordUndo: boolean;
71
+ isEnabled(): boolean;
72
+ getGroup(): string | boolean;
73
+ setGroup(group: string | boolean): void;
74
+ disable(): void;
75
+ enable(): void;
76
+ };
77
+ }
78
+ export interface NativeWorkspace {
79
+ isFlyout?: boolean;
80
+ options: {
81
+ readOnly?: boolean;
82
+ };
83
+ isDragging?(): boolean;
84
+ getBlockById(id: string): NativeBlock | null;
85
+ getAllBlocks(ordered: boolean): NativeBlock[];
86
+ addChangeListener(listener: (event: NativeChange) => void): void;
87
+ removeChangeListener(listener: (event: NativeChange) => void): void;
88
+ undoStack_: NativeChange[];
89
+ redoStack_: NativeChange[];
90
+ fireChangeListener(event: NativeChange): void;
91
+ }
92
+ export interface VMField {
93
+ [name: string]: unknown;
94
+ id?: string;
95
+ value: unknown;
96
+ }
97
+ export interface VMBlock {
98
+ opcode: string;
99
+ parent?: string | null;
100
+ next?: string | null;
101
+ fields: Record<string, VMField>;
102
+ inputs: Record<string, {
103
+ block?: string;
104
+ shadow?: string;
105
+ }>;
106
+ mutation?: unknown;
107
+ }
108
+ export interface NativeTarget {
109
+ id: string;
110
+ blocks: {
111
+ getBlock(id: string): VMBlock | null;
112
+ blocklyListen(event: NativeChange): void;
113
+ resetCache?(): void;
114
+ };
115
+ }
116
+ export interface NativeVM {
117
+ editingTarget: NativeTarget | null;
118
+ runtime: {
119
+ emitProjectChanged(): void;
120
+ };
121
+ on(name: string, listener: () => void): void;
122
+ removeListener(name: string, listener: () => void): void;
123
+ }
124
+ export interface TextBinding {
125
+ shadow: NativeBlock;
126
+ field: NativeField;
127
+ value: string;
128
+ }
129
+ export interface BlockRecord {
130
+ block: NativeBlock;
131
+ vmBlock: VMBlock;
132
+ fields: Map<string, TextBinding>;
133
+ snapshot: BlockSnapshot;
134
+ }
135
+ export type Identify = (value: object) => number;
136
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,10 +1,13 @@
1
- export default collectBlockEditorSubtree;
2
- declare function collectBlockEditorSubtree({ ScratchBlocks, reference, inspect, generation }: {
3
- ScratchBlocks: any;
4
- reference: any;
5
- inspect: any;
6
- generation: any;
7
- }): {
8
- snapshot: any;
9
- records: Map<any, any>;
1
+ import type { SubtreeSnapshot } from '../descendant-types.js';
2
+ import type { BlockReference } from '../types.js';
3
+ import type { BlockRecord, NativeScratchBlocks } from './native-types.js';
4
+ declare const collectBlockEditorSubtree: ({ ScratchBlocks, reference, inspect, generation }: {
5
+ ScratchBlocks: NativeScratchBlocks;
6
+ reference: BlockReference;
7
+ inspect(reference: BlockReference, structural: boolean): BlockRecord | null;
8
+ generation: number;
9
+ }) => {
10
+ snapshot: SubtreeSnapshot;
11
+ records: Map<string, BlockRecord>;
10
12
  } | null;
13
+ export default collectBlockEditorSubtree;
@@ -4,9 +4,10 @@ const collectBlockEditorSubtree = ({ ScratchBlocks, reference, inspect, generati
4
4
  const nodes = [];
5
5
  const records = new Map();
6
6
  const pending = {};
7
- const invalid = message => {
7
+ function invalid(message) {
8
8
  throw new BlockEditorStructureError(message, 'invalid-structure');
9
- };
9
+ }
10
+ ;
10
11
  const visit = (id, depth) => {
11
12
  if (records.has(id)) {
12
13
  throw new BlockEditorStructureError('A statement block is connected more than once.', 'cycle');