@kubohiroya/turbowarp-extension-data-editor 0.2.0 → 0.2.2
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.md +9 -6
- package/dist/build-info.json +3 -3
- package/dist/fixed-input-branches.d.ts +12 -0
- package/dist/fixed-input-branches.js +180 -0
- package/dist/fixed-input-editor.d.ts +39 -0
- package/dist/fixed-input-editor.js +538 -0
- package/dist/fixed-input-schema.d.ts +15 -0
- package/dist/fixed-input-schema.js +21 -0
- package/dist/fixed-input-snapshot.d.ts +7 -0
- package/dist/fixed-input-snapshot.js +180 -0
- package/dist/fixed-input-types.d.ts +138 -0
- package/dist/fixed-input-types.js +23 -0
- package/dist/fixed-input-view.d.ts +14 -0
- package/dist/fixed-input-view.js +168 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +4 -0
- package/dist/react.css +168 -0
- package/dist/react.d.ts +8 -0
- package/dist/react.js +19 -2
- package/dist/registry.d.ts +4 -0
- package/dist/registry.js +45 -7
- package/dist/rjsf-templates.d.ts +11 -0
- package/dist/rjsf-templates.js +129 -0
- package/dist/rjsf.d.ts +24 -1
- package/dist/rjsf.js +35 -3
- package/dist/schema.d.ts +2 -0
- package/dist/schema.js +1 -0
- package/dist/session.d.ts +3 -1
- package/dist/session.js +205 -7
- package/dist/turbowarp/bridge.d.ts +2 -1
- package/dist/turbowarp/bridge.js +37 -5
- package/dist/turbowarp/fixed-fields.d.ts +82 -0
- package/dist/turbowarp/fixed-fields.js +311 -0
- package/dist/turbowarp/fixed-transaction.d.ts +18 -0
- package/dist/turbowarp/fixed-transaction.js +460 -0
- package/dist/turbowarp/host.d.ts +3 -8
- package/dist/turbowarp/host.js +68 -1
- package/dist/turbowarp.d.ts +4 -0
- package/dist/turbowarp.js +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/view.js +4 -0
- package/dist/webpack4/index.js +22 -5
- package/dist/webpack4/metafile.json +592 -299
- package/dist/webpack4/react.js +20 -6
- package/dist/webpack4/react.js.map +2 -2
- package/dist/webpack4/rjsf.js +450 -60
- package/dist/webpack4/rjsf.js.map +4 -4
- package/dist/webpack4/schema.js +6 -3
- package/dist/webpack4/{shared-KQOUMWJ4.js → shared-75QIWLZY.js} +1129 -1244
- package/dist/webpack4/{shared-KQOUMWJ4.js.map → shared-75QIWLZY.js.map} +4 -4
- package/dist/webpack4/shared-FYUILHED.js +1 -0
- package/dist/webpack4/shared-GQLPPRT2.js +210 -0
- package/dist/webpack4/shared-GQLPPRT2.js.map +7 -0
- package/dist/webpack4/shared-P2JBRZFP.js +2206 -0
- package/dist/webpack4/shared-P2JBRZFP.js.map +7 -0
- package/dist/webpack4/turbowarp.js +913 -9
- package/dist/webpack4/turbowarp.js.map +4 -4
- package/docs/api.md +7 -0
- package/docs/fixed-input-contracts.md +77 -0
- package/docs/package-distribution.md +5 -0
- package/docs/stage-2-publication.ja.md +6 -0
- package/package.json +2 -1
- package/dist/webpack4/shared-CQB3NG2A.js +0 -1
- package/dist/webpack4/shared-MRPGBJIH.js +0 -75
- package/dist/webpack4/shared-MRPGBJIH.js.map +0 -7
- package/dist/webpack4/shared-N6YQE2X6.js +0 -1029
- package/dist/webpack4/shared-N6YQE2X6.js.map +0 -7
- /package/dist/webpack4/{shared-CQB3NG2A.js.map → shared-FYUILHED.js.map} +0 -0
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import "./shared-
|
|
2
|
-
import
|
|
1
|
+
import "./shared-FYUILHED.js";
|
|
2
|
+
import {
|
|
3
|
+
FIXED_INPUTS_CAPABILITY,
|
|
4
|
+
captureFixedInputDeclaration,
|
|
5
|
+
captureFixedSnapshot,
|
|
6
|
+
sameFixedSnapshot,
|
|
7
|
+
supportsFixedInputEditing,
|
|
8
|
+
validateFixedBranchChanges
|
|
9
|
+
} from "./shared-P2JBRZFP.js";
|
|
3
10
|
import {
|
|
4
11
|
BlockEditorConflictError,
|
|
5
12
|
BlockEditorStructureError,
|
|
@@ -7,7 +14,9 @@ import {
|
|
|
7
14
|
DESCENDANT_EDITING_CAPABILITY,
|
|
8
15
|
supportsDescendantEditing
|
|
9
16
|
} from "./shared-BKTRZUZH.js";
|
|
10
|
-
import
|
|
17
|
+
import {
|
|
18
|
+
snapshotJson
|
|
19
|
+
} from "./shared-75QIWLZY.js";
|
|
11
20
|
import "./shared-RN7GOT65.js";
|
|
12
21
|
|
|
13
22
|
// dist/turbowarp/subtree.js
|
|
@@ -68,17 +77,827 @@ var collectBlockEditorSubtree = ({ ScratchBlocks, reference, inspect, generation
|
|
|
68
77
|
};
|
|
69
78
|
var subtree_default = collectBlockEditorSubtree;
|
|
70
79
|
|
|
71
|
-
// dist/turbowarp/
|
|
80
|
+
// dist/turbowarp/fixed-fields.js
|
|
72
81
|
var owns = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
|
|
73
|
-
var
|
|
82
|
+
var own = (object, key) => {
|
|
83
|
+
const descriptor = object && Object.getOwnPropertyDescriptor(object, key);
|
|
84
|
+
return descriptor && "value" in descriptor ? descriptor.value : void 0;
|
|
85
|
+
};
|
|
86
|
+
var primitive = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
87
|
+
var token = /^-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?$/u;
|
|
88
|
+
var inherited = (object, name) => {
|
|
89
|
+
for (let current = object; current; current = Object.getPrototypeOf(current)) {
|
|
90
|
+
const descriptor = Object.getOwnPropertyDescriptor(current, name);
|
|
91
|
+
if (descriptor)
|
|
92
|
+
return "value" in descriptor ? descriptor.value : void 0;
|
|
93
|
+
}
|
|
94
|
+
return void 0;
|
|
95
|
+
};
|
|
96
|
+
var storage = ["text_", "value_", "colour_", "validator_", "sourceBlock_", "hue_", "saturation_", "brightness_"];
|
|
97
|
+
var methods = [
|
|
98
|
+
"getValue",
|
|
99
|
+
"getText",
|
|
100
|
+
"setValue",
|
|
101
|
+
"setText",
|
|
102
|
+
"getValidator",
|
|
103
|
+
"classValidator",
|
|
104
|
+
"callValidator",
|
|
105
|
+
"getOptions",
|
|
106
|
+
"forceRerender",
|
|
107
|
+
"updateSliderHandles_",
|
|
108
|
+
"updateDom_"
|
|
109
|
+
];
|
|
110
|
+
var trustedClasses = /* @__PURE__ */ new WeakMap();
|
|
111
|
+
function initializeFixedFields(ScratchBlocks) {
|
|
112
|
+
for (const key of ["FieldTextInput", "FieldNumber", "FieldDropdown", "FieldColourSlider"]) {
|
|
113
|
+
const Class = ScratchBlocks[key];
|
|
114
|
+
if (typeof Class !== "function" || trustedClasses.has(Class))
|
|
115
|
+
continue;
|
|
116
|
+
const chain = [];
|
|
117
|
+
for (let prototype = Class.prototype; prototype && prototype !== Object.prototype; prototype = Object.getPrototypeOf(prototype)) {
|
|
118
|
+
chain.push({ prototype, own: methods.map((name) => [name, Object.getOwnPropertyDescriptor(prototype, name)]) });
|
|
119
|
+
}
|
|
120
|
+
trustedClasses.set(Class, {
|
|
121
|
+
prototype: Class.prototype,
|
|
122
|
+
chain,
|
|
123
|
+
methods: methods.map((name) => [name, inherited(Class.prototype, name)])
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
var safeField = (field, Class) => {
|
|
128
|
+
const trusted = Class && trustedClasses.get(Class);
|
|
129
|
+
if (!trusted || Class.prototype !== trusted.prototype || Object.getPrototypeOf(field) !== trusted.prototype)
|
|
130
|
+
return false;
|
|
131
|
+
let currentPrototype = trusted.prototype;
|
|
132
|
+
for (const entry of trusted.chain) {
|
|
133
|
+
if (currentPrototype !== entry.prototype)
|
|
134
|
+
return false;
|
|
135
|
+
for (const [name, expected] of entry.own) {
|
|
136
|
+
const actual = Object.getOwnPropertyDescriptor(currentPrototype, name);
|
|
137
|
+
if (Boolean(actual) !== Boolean(expected) || actual && (!("value" in actual) || !expected || !("value" in expected) || actual.value !== expected.value))
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
currentPrototype = Object.getPrototypeOf(currentPrototype);
|
|
141
|
+
}
|
|
142
|
+
if (currentPrototype !== Object.prototype && currentPrototype !== null)
|
|
143
|
+
return false;
|
|
144
|
+
for (const name of storage) {
|
|
145
|
+
for (let current = field; current; current = Object.getPrototypeOf(current)) {
|
|
146
|
+
const descriptor = Object.getOwnPropertyDescriptor(current, name);
|
|
147
|
+
if (!descriptor)
|
|
148
|
+
continue;
|
|
149
|
+
if (!("value" in descriptor))
|
|
150
|
+
return false;
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
for (const [name, expected] of trusted.methods) {
|
|
155
|
+
if (owns(field, name) || inherited(field, name) !== expected)
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
for (let current = field; current; current = Object.getPrototypeOf(current)) {
|
|
159
|
+
const descriptor = Object.getOwnPropertyDescriptor(current, "validator_");
|
|
160
|
+
if (descriptor)
|
|
161
|
+
return "value" in descriptor && descriptor.value == null;
|
|
162
|
+
}
|
|
163
|
+
return false;
|
|
164
|
+
};
|
|
165
|
+
var arrayData = (value) => {
|
|
166
|
+
if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype)
|
|
167
|
+
return null;
|
|
168
|
+
const result = [];
|
|
169
|
+
for (let index = 0; index < value.length; index++) {
|
|
170
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
171
|
+
if (!descriptor || !("value" in descriptor))
|
|
172
|
+
return null;
|
|
173
|
+
result.push(descriptor.value);
|
|
174
|
+
}
|
|
175
|
+
return result;
|
|
176
|
+
};
|
|
177
|
+
var staticValues = (field) => {
|
|
178
|
+
const items = arrayData(own(field, "menuGenerator_"));
|
|
179
|
+
if (!items || items.length === 0)
|
|
180
|
+
return null;
|
|
181
|
+
const values = [];
|
|
182
|
+
for (const item of items) {
|
|
183
|
+
const tuple = arrayData(item);
|
|
184
|
+
if (!tuple || tuple.length !== 2 || typeof tuple[0] !== "string" || typeof tuple[1] !== "string")
|
|
185
|
+
return null;
|
|
186
|
+
values.push(tuple[1]);
|
|
187
|
+
}
|
|
188
|
+
return Object.freeze(values);
|
|
189
|
+
};
|
|
190
|
+
var rawKeys = ["text_", "value_", "colour_", "hue_", "saturation_", "brightness_"];
|
|
191
|
+
var ownState = (object, keys) => keys.map((name) => [name, Object.getOwnPropertyDescriptor(object, name)]);
|
|
192
|
+
var restoreOwnState = (object, state) => {
|
|
193
|
+
for (const [name, descriptor] of state) {
|
|
194
|
+
if (descriptor)
|
|
195
|
+
Object.defineProperty(object, name, descriptor);
|
|
196
|
+
else
|
|
197
|
+
delete object[name];
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
var vmFieldsIdentity = (fields, identify) => Object.keys(fields || {}).sort().map((name) => {
|
|
201
|
+
const descriptor = Object.getOwnPropertyDescriptor(fields, name);
|
|
202
|
+
if (!descriptor || !("value" in descriptor))
|
|
203
|
+
return [name, "accessor"];
|
|
204
|
+
const stored = descriptor.value;
|
|
205
|
+
if (!stored || typeof stored !== "object")
|
|
206
|
+
return [name, typeof stored, String(stored)];
|
|
207
|
+
return [name, identify(stored), ...Object.keys(stored).sort().map((key) => {
|
|
208
|
+
const item = Object.getOwnPropertyDescriptor(stored, key);
|
|
209
|
+
if (!item || !("value" in item))
|
|
210
|
+
return [key, "accessor"];
|
|
211
|
+
const value = item.value;
|
|
212
|
+
return [key, typeof value, primitive(value) ? Object.is(value, -0) ? "-0" : String(value) : value && (typeof value === "object" || typeof value === "function") ? identify(value) : String(value)];
|
|
213
|
+
})];
|
|
214
|
+
});
|
|
215
|
+
var colorState = (block, field) => {
|
|
216
|
+
const colors = ["getColour", "getColourSecondary", "getColourTertiary", "getColourQuaternary"];
|
|
217
|
+
return {
|
|
218
|
+
colors: colors.map((name) => typeof block[name] === "function" ? block[name]() : void 0),
|
|
219
|
+
hsv: ["hue_", "saturation_", "brightness_"].map((name) => [name, own(field, name)]),
|
|
220
|
+
blockProperties: ownState(block, ["colour_", "colourSecondary_", "colourTertiary_", "colourQuaternary_"])
|
|
221
|
+
};
|
|
222
|
+
};
|
|
223
|
+
function inspectFixedArgument({ ScratchBlocks, block, vmBlock, target, argument, role, identify, extensionId }) {
|
|
224
|
+
initializeFixedFields(ScratchBlocks);
|
|
225
|
+
const sourceIdentity = [argument, identify(block), identify(vmBlock)];
|
|
226
|
+
let observedFields = [];
|
|
227
|
+
const unavailable = (source, reason, raw2) => ({
|
|
228
|
+
slot: primitive(raw2) ? { kind: "literal", value: raw2 } : { kind: "reporter" },
|
|
229
|
+
metadata: { role, source, identity: JSON.stringify([...sourceIdentity, source]), reason },
|
|
230
|
+
signatureParts: [...sourceIdentity, observedFields]
|
|
231
|
+
});
|
|
232
|
+
const direct = block.getField(argument);
|
|
233
|
+
const input = block.getInput(argument);
|
|
234
|
+
const connected = input && input.connection && input.connection.targetBlock();
|
|
235
|
+
const vmInput = vmBlock.inputs && vmBlock.inputs[argument];
|
|
236
|
+
if ((connected ? connected.id : null) !== (vmInput && vmInput.block ? vmInput.block : null))
|
|
237
|
+
return null;
|
|
238
|
+
if (direct && connected)
|
|
239
|
+
return null;
|
|
240
|
+
if (connected && !connected.isShadow()) {
|
|
241
|
+
const vmReporter = target.blocks.getBlock(connected.id);
|
|
242
|
+
if (!vmReporter || vmReporter.opcode !== connected.type || vmReporter.parent !== block.id)
|
|
243
|
+
return null;
|
|
244
|
+
sourceIdentity.push(identify(connected), identify(vmReporter), connected.id, connected.type);
|
|
245
|
+
return {
|
|
246
|
+
slot: { kind: "reporter" },
|
|
247
|
+
metadata: { role, source: "reporter", identity: JSON.stringify(sourceIdentity) },
|
|
248
|
+
signatureParts: sourceIdentity
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
let owner = direct ? block : connected;
|
|
252
|
+
if (!owner) {
|
|
253
|
+
if (vmBlock.fields && owns(vmBlock.fields, argument))
|
|
254
|
+
return null;
|
|
255
|
+
return unavailable("missing", "The declared field or input is missing.");
|
|
256
|
+
}
|
|
257
|
+
const vmOwner = direct ? vmBlock : target.blocks.getBlock(owner.id);
|
|
258
|
+
if (!vmOwner || vmOwner.opcode !== owner.type)
|
|
259
|
+
return null;
|
|
260
|
+
sourceIdentity.push(identify(owner), identify(vmOwner), owner.id, owner.type);
|
|
261
|
+
observedFields = vmFieldsIdentity(vmOwner.fields, identify);
|
|
262
|
+
if (!direct && (!vmInput || vmInput.shadow !== owner.id || vmOwner.parent !== block.id))
|
|
263
|
+
return null;
|
|
264
|
+
let kind;
|
|
265
|
+
let name;
|
|
266
|
+
let Class;
|
|
267
|
+
if (direct) {
|
|
268
|
+
kind = "menu";
|
|
269
|
+
name = argument;
|
|
270
|
+
Class = ScratchBlocks.FieldDropdown;
|
|
271
|
+
} else if (owner.type === "text") {
|
|
272
|
+
kind = "text";
|
|
273
|
+
name = "TEXT";
|
|
274
|
+
Class = ScratchBlocks.FieldTextInput;
|
|
275
|
+
} else if (owner.type === "math_number") {
|
|
276
|
+
kind = "number";
|
|
277
|
+
name = "NUM";
|
|
278
|
+
Class = ScratchBlocks.FieldNumber;
|
|
279
|
+
} else if (owner.type === "colour_picker") {
|
|
280
|
+
kind = "color";
|
|
281
|
+
name = "COLOUR";
|
|
282
|
+
Class = ScratchBlocks.FieldColourSlider;
|
|
283
|
+
} else if (typeof extensionId === "string" && owner.type.startsWith(`${extensionId}_menu_`)) {
|
|
284
|
+
kind = "menu";
|
|
285
|
+
Class = ScratchBlocks.FieldDropdown;
|
|
286
|
+
const names = [];
|
|
287
|
+
for (const row of owner.inputList)
|
|
288
|
+
for (const candidate of row.fieldRow) {
|
|
289
|
+
const candidateName = own(candidate, "name");
|
|
290
|
+
if (typeof candidateName === "string" && candidateName)
|
|
291
|
+
names.push(candidateName);
|
|
292
|
+
}
|
|
293
|
+
if (names.length !== 1)
|
|
294
|
+
return unavailable("unsupported", "The menu shadow does not have one standard field.");
|
|
295
|
+
[name] = names;
|
|
296
|
+
} else
|
|
297
|
+
return unavailable("unsupported", "The shadow field family is unsupported.");
|
|
298
|
+
const field = direct || owner.getField(name);
|
|
299
|
+
const stored = vmOwner.fields && vmOwner.fields[name];
|
|
300
|
+
if (!field || !stored)
|
|
301
|
+
return null;
|
|
302
|
+
sourceIdentity.push(identify(field), name);
|
|
303
|
+
const raw = own(stored, "value");
|
|
304
|
+
if (!safeField(field, Class))
|
|
305
|
+
return unavailable("unsupported", "The field class, methods or validator is unsupported.", raw);
|
|
306
|
+
const value = inherited(Class.prototype, "getValue").call(field);
|
|
307
|
+
if (!Object.is(value, raw))
|
|
308
|
+
return null;
|
|
309
|
+
if (typeof value !== "string")
|
|
310
|
+
return unavailable("unsupported", "The native field value is not a string.", raw);
|
|
311
|
+
const allowedValues = kind === "menu" ? staticValues(field) : void 0;
|
|
312
|
+
if (kind === "menu" && !allowedValues)
|
|
313
|
+
return unavailable("unsupported", "Dynamic or nonstandard menus are unsupported.", raw);
|
|
314
|
+
sourceIdentity.push(kind, ...allowedValues || []);
|
|
315
|
+
const binding = {
|
|
316
|
+
block: owner,
|
|
317
|
+
field,
|
|
318
|
+
fieldName: name,
|
|
319
|
+
value,
|
|
320
|
+
vmBlock: vmOwner,
|
|
321
|
+
kind,
|
|
322
|
+
Class,
|
|
323
|
+
prototype: Class.prototype,
|
|
324
|
+
allowedValues,
|
|
325
|
+
restoreValue: inherited(Class.prototype, "setValue"),
|
|
326
|
+
rawState: ownState(field, rawKeys),
|
|
327
|
+
restoreHandles: inherited(Class.prototype, "updateSliderHandles_"),
|
|
328
|
+
restoreDom: inherited(Class.prototype, "updateDom_"),
|
|
329
|
+
...kind === "color" ? { restoreState: colorState(owner, field) } : {}
|
|
330
|
+
};
|
|
331
|
+
return {
|
|
332
|
+
slot: { kind: "literal", value },
|
|
333
|
+
metadata: {
|
|
334
|
+
role,
|
|
335
|
+
source: direct ? "field" : "shadow",
|
|
336
|
+
identity: JSON.stringify(sourceIdentity),
|
|
337
|
+
field: { blockId: owner.id, name, type: { text: "FieldTextInput", number: "FieldNumber", menu: "FieldDropdown", color: "FieldColourSlider" }[kind] }
|
|
338
|
+
},
|
|
339
|
+
...role === "editable" ? { binding } : {},
|
|
340
|
+
signatureParts: [...sourceIdentity, observedFields]
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
function prepareFixedChange(binding, value) {
|
|
344
|
+
if (!binding || !safeField(binding.field, binding.Class) || typeof value !== "string") {
|
|
345
|
+
throw new TypeError("Only standard native string field writes are supported.");
|
|
346
|
+
}
|
|
347
|
+
if (binding.kind === "menu") {
|
|
348
|
+
const currentValues = staticValues(binding.field);
|
|
349
|
+
if (!currentValues || currentValues.length !== binding.allowedValues.length || currentValues.some((item, index) => item !== binding.allowedValues[index])) {
|
|
350
|
+
throw new TypeError("The static menu changed before preparing the write.");
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
if (value !== binding.value) {
|
|
354
|
+
if (binding.kind === "number" && (!token.test(value.trim()) || !Number.isFinite(Number(value)))) {
|
|
355
|
+
throw new TypeError("Expected a finite numeric field token.");
|
|
356
|
+
}
|
|
357
|
+
if (binding.kind === "color" && !/^#(?:[a-f0-9]{3}|[a-f0-9]{6})$/iu.test(value)) {
|
|
358
|
+
throw new TypeError("Expected a hexadecimal color field token.");
|
|
359
|
+
}
|
|
360
|
+
if (binding.kind === "menu" && !binding.allowedValues.includes(value)) {
|
|
361
|
+
throw new TypeError("Expected a declared static menu value.");
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return { ...binding, next: value };
|
|
365
|
+
}
|
|
366
|
+
function captureFixedFieldState(binding) {
|
|
367
|
+
if (!binding || !safeField(binding.field, binding.Class)) {
|
|
368
|
+
throw new TypeError("Cannot capture an unsupported native field.");
|
|
369
|
+
}
|
|
370
|
+
const value = inherited(binding.prototype, "getValue").call(binding.field);
|
|
371
|
+
if (typeof value !== "string")
|
|
372
|
+
throw new TypeError("Expected a native string field.");
|
|
373
|
+
return {
|
|
374
|
+
...binding,
|
|
375
|
+
value,
|
|
376
|
+
rawState: ownState(binding.field, rawKeys),
|
|
377
|
+
...binding.kind === "color" ? { restoreState: colorState(binding.block, binding.field) } : {}
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
function restoreFixedField(binding) {
|
|
381
|
+
let failure;
|
|
382
|
+
try {
|
|
383
|
+
binding.restoreValue.call(binding.field, binding.value);
|
|
384
|
+
} catch (error) {
|
|
385
|
+
failure = error;
|
|
386
|
+
}
|
|
387
|
+
restoreOwnState(binding.field, binding.rawState);
|
|
388
|
+
if (binding.restoreState) {
|
|
389
|
+
const colors = binding.restoreState.colors;
|
|
390
|
+
try {
|
|
391
|
+
if (colors.every((value) => typeof value === "string"))
|
|
392
|
+
binding.block.setColour(...colors);
|
|
393
|
+
} catch (error) {
|
|
394
|
+
failure = failure || error;
|
|
395
|
+
}
|
|
396
|
+
restoreOwnState(binding.block, binding.restoreState.blockProperties);
|
|
397
|
+
try {
|
|
398
|
+
binding.restoreHandles.call(binding.field);
|
|
399
|
+
} catch (error) {
|
|
400
|
+
failure = failure || error;
|
|
401
|
+
}
|
|
402
|
+
try {
|
|
403
|
+
binding.restoreDom.call(binding.field);
|
|
404
|
+
} catch (error) {
|
|
405
|
+
failure = failure || error;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
if (failure)
|
|
409
|
+
throw failure;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// dist/turbowarp/fixed-transaction.js
|
|
413
|
+
var own2 = (object, name) => {
|
|
414
|
+
const descriptor = object && Object.getOwnPropertyDescriptor(object, name);
|
|
415
|
+
if (!descriptor || !Object.prototype.hasOwnProperty.call(descriptor, "value")) {
|
|
416
|
+
throw new TypeError("Expected an own data property.");
|
|
417
|
+
}
|
|
418
|
+
return descriptor.value;
|
|
419
|
+
};
|
|
420
|
+
var inheritedData = (object, key) => {
|
|
421
|
+
for (let item = object; item; item = Object.getPrototypeOf(item)) {
|
|
422
|
+
const descriptor = Object.getOwnPropertyDescriptor(item, key);
|
|
423
|
+
if (descriptor) {
|
|
424
|
+
if (!("value" in descriptor))
|
|
425
|
+
throw new TypeError("Unsupported undo configuration.");
|
|
426
|
+
return descriptor.value;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
return void 0;
|
|
430
|
+
};
|
|
431
|
+
var ensureNativeHistory = (stack) => {
|
|
432
|
+
if (!Array.isArray(stack) || !Object.isExtensible(stack) || Object.getOwnPropertySymbols(stack).length || !Object.getOwnPropertyDescriptor(stack, "length").writable) {
|
|
433
|
+
throw new TypeError("Unsupported undo history.");
|
|
434
|
+
}
|
|
435
|
+
if (Object.getOwnPropertyNames(stack).length !== stack.length + 1)
|
|
436
|
+
throw new TypeError("Unsupported undo history.");
|
|
437
|
+
for (let index = 0; index < stack.length; index++) {
|
|
438
|
+
const descriptor = Object.getOwnPropertyDescriptor(stack, String(index));
|
|
439
|
+
if (!descriptor || !("value" in descriptor) || !descriptor.writable || !descriptor.configurable) {
|
|
440
|
+
throw new TypeError("Unsupported undo history.");
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
var copyHistory = (stack) => {
|
|
445
|
+
const copy = [];
|
|
446
|
+
for (let index = 0; index < stack.length; index++)
|
|
447
|
+
copy.push(own2(stack, String(index)));
|
|
448
|
+
return copy;
|
|
449
|
+
};
|
|
450
|
+
var replaceHistory = (stack, values) => {
|
|
451
|
+
stack.length = 0;
|
|
452
|
+
for (const value of values)
|
|
453
|
+
Array.prototype.push.call(stack, value);
|
|
454
|
+
};
|
|
455
|
+
var conflict = () => {
|
|
456
|
+
throw new BlockEditorConflictError();
|
|
457
|
+
};
|
|
458
|
+
var aborted = Object.getOwnPropertyDescriptor(AbortSignal.prototype, "aborted").get;
|
|
459
|
+
var isAborted = (signal) => aborted.call(signal);
|
|
460
|
+
var optionalOwn = (object, name) => {
|
|
461
|
+
const descriptor = object && Object.getOwnPropertyDescriptor(object, name);
|
|
462
|
+
if (descriptor && !Object.prototype.hasOwnProperty.call(descriptor, "value")) {
|
|
463
|
+
throw new TypeError("VM state must contain data properties.");
|
|
464
|
+
}
|
|
465
|
+
return descriptor && descriptor.value;
|
|
466
|
+
};
|
|
467
|
+
var stateToken = (value, identify, seen = /* @__PURE__ */ new Set()) => {
|
|
468
|
+
if (typeof value === "number")
|
|
469
|
+
return ["number", Object.is(value, -0) ? "-0" : String(value)];
|
|
470
|
+
if (value === void 0)
|
|
471
|
+
return ["undefined"];
|
|
472
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
473
|
+
return value;
|
|
474
|
+
if (typeof value !== "object" || seen.has(value) || seen.size > 64)
|
|
475
|
+
throw new TypeError("Unsupported VM state.");
|
|
476
|
+
seen.add(value);
|
|
477
|
+
const result = Object.getOwnPropertyNames(value).sort().map((key) => [key, stateToken(own2(value, key), identify, seen)]);
|
|
478
|
+
seen.delete(value);
|
|
479
|
+
return ["object", identify(value), result];
|
|
480
|
+
};
|
|
481
|
+
var untouchedState = (block, vmBlock, target, bindings, identify) => {
|
|
482
|
+
const omitted = /* @__PURE__ */ new Map();
|
|
483
|
+
for (const binding of bindings.values()) {
|
|
484
|
+
if (!omitted.has(binding.vmBlock))
|
|
485
|
+
omitted.set(binding.vmBlock, /* @__PURE__ */ new Set());
|
|
486
|
+
omitted.get(binding.vmBlock).add(binding.fieldName);
|
|
487
|
+
}
|
|
488
|
+
const seen = /* @__PURE__ */ new Set();
|
|
489
|
+
const records = [];
|
|
490
|
+
const capture = (item) => {
|
|
491
|
+
if (!item || seen.has(item))
|
|
492
|
+
return;
|
|
493
|
+
seen.add(item);
|
|
494
|
+
const fields = item.fields || {};
|
|
495
|
+
records.push([identify(item), ["id", "opcode", "parent", "next", "inputs", "mutation", "shadow", "topLevel"].map((key) => [key, stateToken(optionalOwn(item, key), identify)]), identify(fields), Object.keys(fields).sort().map((key) => {
|
|
496
|
+
var _a;
|
|
497
|
+
const field = own2(fields, key);
|
|
498
|
+
if (!((_a = omitted.get(item)) === null || _a === void 0 ? void 0 : _a.has(key)))
|
|
499
|
+
return [key, stateToken(field, identify)];
|
|
500
|
+
return [key, identify(field), Object.getOwnPropertyNames(field).sort().filter((property) => property !== "value").map((property) => [property, stateToken(own2(field, property), identify)])];
|
|
501
|
+
})]);
|
|
502
|
+
};
|
|
503
|
+
capture(vmBlock);
|
|
504
|
+
const connections = [];
|
|
505
|
+
for (const input of block.inputList) {
|
|
506
|
+
const connected = input.connection && input.connection.targetBlock();
|
|
507
|
+
connections.push([input.name || "", identify(input), input.connection ? identify(input.connection) : null, connected ? [connected.id, connected.type, identify(connected)] : null]);
|
|
508
|
+
if (connected)
|
|
509
|
+
capture(target.blocks.getBlock(connected.id));
|
|
510
|
+
}
|
|
511
|
+
const statementConnections = ["nextConnection", "previousConnection", "outputConnection"].map((name) => {
|
|
512
|
+
const connection = block[name];
|
|
513
|
+
const connected = connection && connection.targetBlock();
|
|
514
|
+
return [
|
|
515
|
+
name,
|
|
516
|
+
connection ? identify(connection) : null,
|
|
517
|
+
connection && connection.targetConnection ? identify(connection.targetConnection) : null,
|
|
518
|
+
connected ? [connected.id, connected.type, identify(connected)] : null
|
|
519
|
+
];
|
|
520
|
+
});
|
|
521
|
+
return JSON.stringify([records, connections, statementConnections]);
|
|
522
|
+
};
|
|
523
|
+
var sameDeclaration = (left, right) => JSON.stringify(captureFixedInputDeclaration(left)) === JSON.stringify(captureFixedInputDeclaration(right));
|
|
524
|
+
function createFixedInputPort({ ScratchBlocks, workspace, vm, registry, identify, getState, begin, markEvent, finish, onError, subscribeScope }) {
|
|
525
|
+
initializeFixedFields(ScratchBlocks);
|
|
526
|
+
const inspect = (reference, suppliedDeclaration) => {
|
|
527
|
+
const state = getState();
|
|
528
|
+
const target = vm.editingTarget;
|
|
529
|
+
if (state.disposed || !target || target.id !== reference.targetId || workspace.isFlyout || workspace.options.readOnly || workspace.isDragging && workspace.isDragging())
|
|
530
|
+
return null;
|
|
531
|
+
const block = workspace.getBlockById(reference.blockId);
|
|
532
|
+
if (!block || block.isInFlyout || block.isShadow() || !block.isEditable())
|
|
533
|
+
return null;
|
|
534
|
+
const descriptor = registry.resolve(block.type);
|
|
535
|
+
const declaration = registry.resolveFixed(block.type);
|
|
536
|
+
if (!descriptor || !declaration || !sameDeclaration(declaration, suppliedDeclaration))
|
|
537
|
+
return null;
|
|
538
|
+
const vmBlock = target.blocks.getBlock(block.id);
|
|
539
|
+
const nextBlock = block.nextConnection && block.nextConnection.targetBlock();
|
|
540
|
+
if (!vmBlock || (nextBlock ? nextBlock.id : null) !== (vmBlock.next || null) || vmBlock.opcode !== block.type || (block.getParent() ? block.getParent().id : null) !== (vmBlock.parent || null))
|
|
541
|
+
return null;
|
|
542
|
+
const arguments_ = /* @__PURE__ */ Object.create(null);
|
|
543
|
+
const inputs = /* @__PURE__ */ Object.create(null);
|
|
544
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
545
|
+
const signature = [state.revision, identify(target), identify(block), identify(vmBlock), identify(declaration)];
|
|
546
|
+
for (const [role, names] of [["editable", declaration.editableArguments], ["readonly", declaration.readOnlyArguments]]) {
|
|
547
|
+
for (const argument of names) {
|
|
548
|
+
const item = inspectFixedArgument({
|
|
549
|
+
ScratchBlocks,
|
|
550
|
+
block,
|
|
551
|
+
vmBlock,
|
|
552
|
+
target,
|
|
553
|
+
argument,
|
|
554
|
+
role,
|
|
555
|
+
identify,
|
|
556
|
+
extensionId: descriptor.extensionId
|
|
557
|
+
});
|
|
558
|
+
if (!item)
|
|
559
|
+
return null;
|
|
560
|
+
arguments_[argument] = item.slot;
|
|
561
|
+
inputs[argument] = item.metadata;
|
|
562
|
+
if (role === "editable" && item.binding)
|
|
563
|
+
bindings.set(argument, item.binding);
|
|
564
|
+
signature.push(argument, item.signatureParts);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
const untouched = untouchedState(block, vmBlock, target, bindings, identify);
|
|
568
|
+
signature.push(untouched);
|
|
569
|
+
const snapshot = captureFixedSnapshot({
|
|
570
|
+
targetId: target.id,
|
|
571
|
+
blockId: block.id,
|
|
572
|
+
opcode: block.type,
|
|
573
|
+
revision: JSON.stringify(signature),
|
|
574
|
+
arguments: arguments_,
|
|
575
|
+
fixedContext: {
|
|
576
|
+
contractId: declaration.contractId,
|
|
577
|
+
contractRevision: declaration.contractRevision,
|
|
578
|
+
generation: String(state.generation),
|
|
579
|
+
readOnlyArguments: declaration.readOnlyArguments,
|
|
580
|
+
dependencies: declaration.dependencies,
|
|
581
|
+
inputs
|
|
582
|
+
}
|
|
583
|
+
}, reference, declaration);
|
|
584
|
+
return { snapshot, bindings, declaration, target, block, vmBlock, state, untouched, runtime: vm.runtime };
|
|
585
|
+
};
|
|
586
|
+
const commit = (request) => {
|
|
587
|
+
var _a;
|
|
588
|
+
const expectedInput = own2(request, "expected");
|
|
589
|
+
const changesInput = own2(request, "changes");
|
|
590
|
+
const signal = own2(request, "signal");
|
|
591
|
+
try {
|
|
592
|
+
const contextInput = own2(request, "context");
|
|
593
|
+
const context = snapshotJson({
|
|
594
|
+
consumerId: own2(contextInput, "consumerId"),
|
|
595
|
+
nowMs: own2(contextInput, "nowMs"),
|
|
596
|
+
settings: own2(contextInput, "settings")
|
|
597
|
+
});
|
|
598
|
+
if (typeof context.consumerId !== "string" || !context.consumerId || typeof context.nowMs !== "number" || !Number.isFinite(context.nowMs)) {
|
|
599
|
+
throw new TypeError("Invalid fixed validation context.");
|
|
600
|
+
}
|
|
601
|
+
} catch (_b) {
|
|
602
|
+
throw new TypeError("Invalid fixed validation context.");
|
|
603
|
+
}
|
|
604
|
+
if (isAborted(signal))
|
|
605
|
+
conflict();
|
|
606
|
+
const expected = captureFixedSnapshot(expectedInput);
|
|
607
|
+
const current = inspect(expected, registry.resolveFixed(expected.opcode));
|
|
608
|
+
if (!current || !sameFixedSnapshot(expected, current.snapshot))
|
|
609
|
+
conflict();
|
|
610
|
+
const declaration = current.declaration;
|
|
611
|
+
captureFixedSnapshot(expected, expected, declaration);
|
|
612
|
+
if (!Array.isArray(changesInput))
|
|
613
|
+
throw new TypeError("Expected a fixed argument patch array.");
|
|
614
|
+
const prepared = [];
|
|
615
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
616
|
+
const seenFields = /* @__PURE__ */ new Set();
|
|
617
|
+
for (let i = 0; i < changesInput.length; i++) {
|
|
618
|
+
const change = own2(changesInput, String(i));
|
|
619
|
+
const name = own2(change, "argument");
|
|
620
|
+
const value = own2(change, "value");
|
|
621
|
+
if (typeof name !== "string" || seenNames.has(name) || !declaration.editableArguments.includes(name) || !current.bindings.has(name)) {
|
|
622
|
+
throw new TypeError("Only distinct editable standard fields may be changed.");
|
|
623
|
+
}
|
|
624
|
+
seenNames.add(name);
|
|
625
|
+
const binding = current.bindings.get(name);
|
|
626
|
+
if (seenFields.has(binding.field))
|
|
627
|
+
throw new TypeError("Duplicate field write.");
|
|
628
|
+
seenFields.add(binding.field);
|
|
629
|
+
if (Object.is(value, binding.value))
|
|
630
|
+
continue;
|
|
631
|
+
prepared.push({ ...prepareFixedChange(binding, value), argument: name });
|
|
632
|
+
}
|
|
633
|
+
if (validateFixedBranchChanges(declaration, expected, prepared.map((item) => ({ argument: item.argument, value: item.next }))).length) {
|
|
634
|
+
throw new TypeError("Fixed branch changes require a valid canonical branch policy.");
|
|
635
|
+
}
|
|
636
|
+
const guard = () => {
|
|
637
|
+
const state = getState();
|
|
638
|
+
if (isAborted(signal) || state.disposed || state.generation !== current.state.generation || state.externalRevision !== current.state.externalRevision || vm.editingTarget !== current.target || vm.runtime !== current.runtime || registry.resolveFixed(expected.opcode) !== declaration)
|
|
639
|
+
conflict();
|
|
640
|
+
};
|
|
641
|
+
guard();
|
|
642
|
+
const beforeWrite = inspect(expected, declaration);
|
|
643
|
+
if (!beforeWrite || !sameFixedSnapshot(expected, beforeWrite.snapshot))
|
|
644
|
+
conflict();
|
|
645
|
+
guard();
|
|
646
|
+
if (!prepared.length)
|
|
647
|
+
return;
|
|
648
|
+
const Events = ScratchBlocks.Events;
|
|
649
|
+
if (!Events.isEnabled() || !Events.recordUndo || Events.getGroup() || !Array.isArray(workspace.undoStack_) || !Array.isArray(workspace.redoStack_)) {
|
|
650
|
+
throw new Error("The workspace is busy or its undo API is unsupported.");
|
|
651
|
+
}
|
|
652
|
+
const undoStack = workspace.undoStack_;
|
|
653
|
+
const redoStack = workspace.redoStack_;
|
|
654
|
+
ensureNativeHistory(undoStack);
|
|
655
|
+
ensureNativeHistory(redoStack);
|
|
656
|
+
const configuredMaxUndo = inheritedData(workspace, "MAX_UNDO");
|
|
657
|
+
const maxUndo = configuredMaxUndo === void 0 ? Infinity : configuredMaxUndo;
|
|
658
|
+
if (maxUndo !== Infinity && (!Number.isSafeInteger(maxUndo) || maxUndo < 0)) {
|
|
659
|
+
throw new TypeError("Unsupported undo configuration.");
|
|
660
|
+
}
|
|
661
|
+
const undo = copyHistory(undoStack);
|
|
662
|
+
const redo = copyHistory(redoStack);
|
|
663
|
+
const oldGroup = Events.getGroup();
|
|
664
|
+
const runtime = current.runtime;
|
|
665
|
+
const dirty = runtime.emitProjectChanged;
|
|
666
|
+
const dirtyDescriptor = Object.getOwnPropertyDescriptor(runtime, "emitProjectChanged");
|
|
667
|
+
const savedVmFields = prepared.map((item) => ({
|
|
668
|
+
binding: item,
|
|
669
|
+
block: item.vmBlock,
|
|
670
|
+
name: item.fieldName,
|
|
671
|
+
fields: item.vmBlock.fields,
|
|
672
|
+
field: item.vmBlock.fields[item.fieldName],
|
|
673
|
+
descriptors: Object.getOwnPropertyDescriptors(item.vmBlock.fields[item.fieldName])
|
|
674
|
+
}));
|
|
675
|
+
let succeeded = false;
|
|
676
|
+
let failure;
|
|
677
|
+
let activeEvent = null;
|
|
678
|
+
const pendingHistory = [];
|
|
679
|
+
const externalWrites = /* @__PURE__ */ new Map();
|
|
680
|
+
const byField = new Map(prepared.map((item) => [JSON.stringify([item.block.id, item.fieldName]), item]));
|
|
681
|
+
let externalDirty = false;
|
|
682
|
+
const ownedEvents = /* @__PURE__ */ new WeakSet();
|
|
683
|
+
const originalDelivery = workspace.fireChangeListener;
|
|
684
|
+
const deliveryDescriptor = Object.getOwnPropertyDescriptor(workspace, "fireChangeListener");
|
|
685
|
+
const stableScope = () => {
|
|
686
|
+
const state = getState();
|
|
687
|
+
return state.generation === current.state.generation && vm.editingTarget === current.target && vm.runtime === runtime;
|
|
688
|
+
};
|
|
689
|
+
let begun = false;
|
|
690
|
+
try {
|
|
691
|
+
runtime.emitProjectChanged = () => {
|
|
692
|
+
if (!activeEvent || !ownedEvents.has(activeEvent) || !stableScope())
|
|
693
|
+
externalDirty = true;
|
|
694
|
+
};
|
|
695
|
+
workspace.fireChangeListener = function(event) {
|
|
696
|
+
const previous = activeEvent;
|
|
697
|
+
const external = event && !event.isUiEvent && !ownedEvents.has(event);
|
|
698
|
+
const edited = external && event.type === "change" && event.element === "field" && byField.get(JSON.stringify([event.blockId, event.name]));
|
|
699
|
+
if (edited && !externalWrites.has(edited.field)) {
|
|
700
|
+
if (Object.is(event.oldValue, edited.next))
|
|
701
|
+
event.oldValue = edited.value;
|
|
702
|
+
externalWrites.set(edited.field, null);
|
|
703
|
+
}
|
|
704
|
+
activeEvent = event;
|
|
705
|
+
try {
|
|
706
|
+
return originalDelivery.call(this, event);
|
|
707
|
+
} finally {
|
|
708
|
+
if (edited) {
|
|
709
|
+
const fields = edited.vmBlock.fields;
|
|
710
|
+
const field = fields && fields[edited.fieldName];
|
|
711
|
+
externalWrites.set(edited.field, {
|
|
712
|
+
binding: captureFixedFieldState(edited),
|
|
713
|
+
fields,
|
|
714
|
+
field,
|
|
715
|
+
descriptors: field && Object.getOwnPropertyDescriptors(field)
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
activeEvent = previous;
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
Events.setGroup(true);
|
|
722
|
+
Events.disable();
|
|
723
|
+
begin();
|
|
724
|
+
begun = true;
|
|
725
|
+
guard();
|
|
726
|
+
for (const item of prepared) {
|
|
727
|
+
guard();
|
|
728
|
+
item.field.setValue(item.next);
|
|
729
|
+
if (!Object.is(item.field.getValue(), item.next))
|
|
730
|
+
throw new Error("The field rejected its value.");
|
|
731
|
+
guard();
|
|
732
|
+
}
|
|
733
|
+
for (const item of prepared) {
|
|
734
|
+
guard();
|
|
735
|
+
const event = new Events.Change(item.block, "field", item.fieldName, item.value, item.next);
|
|
736
|
+
ownedEvents.add(event);
|
|
737
|
+
markEvent(event);
|
|
738
|
+
const recordUndo = event.recordUndo;
|
|
739
|
+
event.recordUndo = false;
|
|
740
|
+
try {
|
|
741
|
+
workspace.fireChangeListener(event);
|
|
742
|
+
} finally {
|
|
743
|
+
event.recordUndo = recordUndo;
|
|
744
|
+
}
|
|
745
|
+
if (recordUndo)
|
|
746
|
+
pendingHistory.push(event);
|
|
747
|
+
guard();
|
|
748
|
+
}
|
|
749
|
+
const after = inspect(expected, declaration);
|
|
750
|
+
if (!after || after.untouched !== current.untouched)
|
|
751
|
+
conflict();
|
|
752
|
+
const wantedArguments = { ...expected.arguments };
|
|
753
|
+
for (const item of prepared)
|
|
754
|
+
wantedArguments[item.argument] = { kind: "literal", value: item.next };
|
|
755
|
+
if (!sameFixedSnapshot({ ...expected, revision: after.snapshot.revision, arguments: wantedArguments }, after.snapshot))
|
|
756
|
+
conflict();
|
|
757
|
+
guard();
|
|
758
|
+
if (workspace.undoStack_ !== undoStack || workspace.redoStack_ !== redoStack || undoStack.length !== undo.length || redoStack.length !== redo.length || undo.some((entry, index) => undoStack[index] !== entry) || redo.some((entry, index) => redoStack[index] !== entry))
|
|
759
|
+
conflict();
|
|
760
|
+
ensureNativeHistory(undoStack);
|
|
761
|
+
ensureNativeHistory(redoStack);
|
|
762
|
+
try {
|
|
763
|
+
for (const event of pendingHistory)
|
|
764
|
+
Array.prototype.push.call(undoStack, event);
|
|
765
|
+
if (undoStack.length > maxUndo) {
|
|
766
|
+
Array.prototype.copyWithin.call(undoStack, 0, undoStack.length - maxUndo);
|
|
767
|
+
undoStack.length = maxUndo;
|
|
768
|
+
}
|
|
769
|
+
redoStack.length = 0;
|
|
770
|
+
} catch (error) {
|
|
771
|
+
replaceHistory(undoStack, undo);
|
|
772
|
+
replaceHistory(redoStack, redo);
|
|
773
|
+
throw error;
|
|
774
|
+
}
|
|
775
|
+
succeeded = true;
|
|
776
|
+
} catch (error) {
|
|
777
|
+
failure = error;
|
|
778
|
+
for (const item of begun ? prepared : []) {
|
|
779
|
+
try {
|
|
780
|
+
restoreFixedField(((_a = externalWrites.get(item.field)) === null || _a === void 0 ? void 0 : _a.binding) || item);
|
|
781
|
+
} catch (restoreError) {
|
|
782
|
+
try {
|
|
783
|
+
onError(restoreError);
|
|
784
|
+
} catch (_c) {
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
for (const saved of begun ? savedVmFields : []) {
|
|
789
|
+
const outside = externalWrites.get(saved.binding.field);
|
|
790
|
+
const fields = saved.block.fields;
|
|
791
|
+
if (!fields)
|
|
792
|
+
continue;
|
|
793
|
+
const field = outside ? outside.field : saved.field;
|
|
794
|
+
const descriptors = outside ? outside.descriptors : saved.descriptors;
|
|
795
|
+
if (!field) {
|
|
796
|
+
delete fields[saved.name];
|
|
797
|
+
continue;
|
|
798
|
+
}
|
|
799
|
+
fields[saved.name] = field;
|
|
800
|
+
for (const key of Object.keys(field))
|
|
801
|
+
if (!Object.hasOwn(descriptors, key))
|
|
802
|
+
delete field[key];
|
|
803
|
+
Object.defineProperties(field, descriptors);
|
|
804
|
+
}
|
|
805
|
+
if (begun && typeof current.target.blocks.resetCache === "function")
|
|
806
|
+
current.target.blocks.resetCache();
|
|
807
|
+
} finally {
|
|
808
|
+
try {
|
|
809
|
+
if (begun)
|
|
810
|
+
finish(succeeded);
|
|
811
|
+
} finally {
|
|
812
|
+
try {
|
|
813
|
+
if (!Events.isEnabled())
|
|
814
|
+
Events.enable();
|
|
815
|
+
} finally {
|
|
816
|
+
try {
|
|
817
|
+
Events.setGroup(oldGroup);
|
|
818
|
+
} finally {
|
|
819
|
+
if (deliveryDescriptor)
|
|
820
|
+
Object.defineProperty(workspace, "fireChangeListener", deliveryDescriptor);
|
|
821
|
+
else
|
|
822
|
+
delete workspace.fireChangeListener;
|
|
823
|
+
if (dirtyDescriptor)
|
|
824
|
+
Object.defineProperty(runtime, "emitProjectChanged", dirtyDescriptor);
|
|
825
|
+
else
|
|
826
|
+
delete runtime.emitProjectChanged;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
if (succeeded || externalDirty) {
|
|
832
|
+
try {
|
|
833
|
+
dirty.call(runtime);
|
|
834
|
+
} catch (error) {
|
|
835
|
+
try {
|
|
836
|
+
onError(error);
|
|
837
|
+
} catch (_d) {
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
if (!succeeded)
|
|
842
|
+
throw failure;
|
|
843
|
+
};
|
|
844
|
+
return Object.freeze({
|
|
845
|
+
capability: FIXED_INPUTS_CAPABILITY,
|
|
846
|
+
readBlock: (reference, declaration) => {
|
|
847
|
+
var _a;
|
|
848
|
+
return ((_a = inspect(reference, declaration)) === null || _a === void 0 ? void 0 : _a.snapshot) || null;
|
|
849
|
+
},
|
|
850
|
+
commit,
|
|
851
|
+
subscribeInvalidation: (reference, declaration, listener) => {
|
|
852
|
+
const captured = inspect(reference, declaration);
|
|
853
|
+
if (!captured || typeof subscribeScope !== "function") {
|
|
854
|
+
listener(new BlockEditorConflictError());
|
|
855
|
+
return () => {
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
let active = true;
|
|
859
|
+
const check = () => {
|
|
860
|
+
const state = getState();
|
|
861
|
+
if (!active || !state.disposed && state.generation === captured.state.generation && vm.editingTarget === captured.target && vm.runtime === captured.runtime && workspace.getBlockById(reference.blockId) === captured.block && captured.target.blocks.getBlock(reference.blockId) === captured.vmBlock && registry.resolveFixed(captured.snapshot.opcode) === captured.declaration)
|
|
862
|
+
return;
|
|
863
|
+
active = false;
|
|
864
|
+
listener(new BlockEditorConflictError());
|
|
865
|
+
};
|
|
866
|
+
const unsubscribe = subscribeScope(check);
|
|
867
|
+
return () => {
|
|
868
|
+
active = false;
|
|
869
|
+
unsubscribe();
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// dist/turbowarp/host.js
|
|
876
|
+
var owns2 = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
|
|
877
|
+
var createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableDescendants = false, enableFixedInputs = false, onError = console.error }) => {
|
|
74
878
|
let disposed = false;
|
|
75
879
|
let committing = false;
|
|
76
880
|
let revision = 0;
|
|
77
881
|
let identity = 0;
|
|
78
882
|
let generation = 1;
|
|
883
|
+
let externalRevision = 0;
|
|
884
|
+
let fixedTransaction = null;
|
|
79
885
|
let lastTarget = vm.editingTarget;
|
|
80
886
|
const versions = /* @__PURE__ */ new Map();
|
|
81
887
|
const invalidations = /* @__PURE__ */ new Set();
|
|
888
|
+
const fixedScopeListeners = /* @__PURE__ */ new Set();
|
|
889
|
+
const notifyFixedScopes = () => {
|
|
890
|
+
for (const listener of [...fixedScopeListeners]) {
|
|
891
|
+
try {
|
|
892
|
+
listener();
|
|
893
|
+
} catch (error) {
|
|
894
|
+
try {
|
|
895
|
+
onError(error);
|
|
896
|
+
} catch (_a) {
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
};
|
|
82
901
|
let notifyInvalidations = () => {
|
|
83
902
|
};
|
|
84
903
|
const identities = /* @__PURE__ */ new WeakMap();
|
|
@@ -91,6 +910,16 @@ var createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableDes
|
|
|
91
910
|
if (event && event.isUiEvent)
|
|
92
911
|
return;
|
|
93
912
|
revision++;
|
|
913
|
+
if (fixedTransaction && event && fixedTransaction.events.has(event)) {
|
|
914
|
+
fixedTransaction.revisions++;
|
|
915
|
+
if (enableDescendants) {
|
|
916
|
+
for (const id of /* @__PURE__ */ new Set([event.blockId, ...event.ids || []])) {
|
|
917
|
+
if (id)
|
|
918
|
+
fixedTransaction.versions.set(id, (fixedTransaction.versions.get(id) || 0) + 1);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
} else
|
|
922
|
+
externalRevision++;
|
|
94
923
|
if (enableDescendants && event) {
|
|
95
924
|
const ids = /* @__PURE__ */ new Set([event.blockId, ...event.ids || []]);
|
|
96
925
|
for (const id of ids)
|
|
@@ -99,6 +928,7 @@ var createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableDes
|
|
|
99
928
|
}
|
|
100
929
|
if (!committing)
|
|
101
930
|
notifyInvalidations();
|
|
931
|
+
notifyFixedScopes();
|
|
102
932
|
};
|
|
103
933
|
const renew = () => {
|
|
104
934
|
generation++;
|
|
@@ -124,6 +954,8 @@ var createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableDes
|
|
|
124
954
|
if (!block || block.isInFlyout || block.isShadow())
|
|
125
955
|
return null;
|
|
126
956
|
const descriptor = registry.resolve(block.type);
|
|
957
|
+
if (typeof registry.resolveFixed === "function" && registry.resolveFixed(block.type))
|
|
958
|
+
return null;
|
|
127
959
|
const vmBlock = target.blocks.getBlock(block.id);
|
|
128
960
|
if (!structural && !descriptor || !block.isEditable() && (!structural || descriptor) || !vmBlock || vmBlock.opcode !== block.type)
|
|
129
961
|
return null;
|
|
@@ -280,7 +1112,7 @@ var createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableDes
|
|
|
280
1112
|
return changes.map((change) => {
|
|
281
1113
|
const record = change && records.get(change.blockId);
|
|
282
1114
|
const key = change && JSON.stringify([change.blockId, change.argument]);
|
|
283
|
-
if (!record || typeof change.value !== "string" || seen.has(key) || !
|
|
1115
|
+
if (!record || typeof change.value !== "string" || seen.has(key) || !owns2(record.snapshot.arguments, change.argument) || !record.fields.has(change.argument)) {
|
|
284
1116
|
throw new TypeError("Only distinct standard text shadow changes are supported.");
|
|
285
1117
|
}
|
|
286
1118
|
seen.add(key);
|
|
@@ -294,10 +1126,17 @@ var createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableDes
|
|
|
294
1126
|
const host = {
|
|
295
1127
|
isCommitting: () => committing,
|
|
296
1128
|
readBlock: (reference) => {
|
|
1129
|
+
const block = workspace.getBlockById(reference.blockId);
|
|
1130
|
+
const declaration = block && typeof registry.resolveFixed === "function" && registry.resolveFixed(block.type);
|
|
1131
|
+
if (declaration)
|
|
1132
|
+
return host.fixedInputs ? host.fixedInputs.readBlock(reference, declaration) : null;
|
|
297
1133
|
const result = inspect(reference);
|
|
298
1134
|
return result ? result.snapshot : null;
|
|
299
1135
|
},
|
|
300
1136
|
commit: ({ expected, changes }) => {
|
|
1137
|
+
if (typeof registry.resolveFixed === "function" && registry.resolveFixed(expected.opcode)) {
|
|
1138
|
+
throw new TypeError("Fixed input editors require the fixed transaction port.");
|
|
1139
|
+
}
|
|
301
1140
|
const current = inspect(expected);
|
|
302
1141
|
if (!current || JSON.stringify(current.snapshot) !== JSON.stringify(expected)) {
|
|
303
1142
|
throw new BlockEditorConflictError();
|
|
@@ -307,6 +1146,8 @@ var createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableDes
|
|
|
307
1146
|
invalidate: renew,
|
|
308
1147
|
dispose: () => {
|
|
309
1148
|
disposed = true;
|
|
1149
|
+
notifyFixedScopes();
|
|
1150
|
+
fixedScopeListeners.clear();
|
|
310
1151
|
notifyInvalidations();
|
|
311
1152
|
invalidations.clear();
|
|
312
1153
|
workspace.removeChangeListener(invalidate);
|
|
@@ -340,6 +1181,42 @@ var createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableDes
|
|
|
340
1181
|
}
|
|
341
1182
|
};
|
|
342
1183
|
}
|
|
1184
|
+
if (enableFixedInputs === true) {
|
|
1185
|
+
host.fixedInputs = createFixedInputPort({
|
|
1186
|
+
ScratchBlocks,
|
|
1187
|
+
workspace,
|
|
1188
|
+
vm,
|
|
1189
|
+
registry,
|
|
1190
|
+
identify,
|
|
1191
|
+
onError,
|
|
1192
|
+
subscribeScope: (listener) => {
|
|
1193
|
+
fixedScopeListeners.add(listener);
|
|
1194
|
+
return () => {
|
|
1195
|
+
fixedScopeListeners.delete(listener);
|
|
1196
|
+
};
|
|
1197
|
+
},
|
|
1198
|
+
getState: () => ({ disposed, revision, generation, externalRevision }),
|
|
1199
|
+
begin: () => {
|
|
1200
|
+
committing = true;
|
|
1201
|
+
fixedTransaction = { events: /* @__PURE__ */ new WeakSet(), revisions: 0, versions: /* @__PURE__ */ new Map() };
|
|
1202
|
+
},
|
|
1203
|
+
markEvent: (event) => fixedTransaction.events.add(event),
|
|
1204
|
+
finish: (succeeded) => {
|
|
1205
|
+
if (!succeeded) {
|
|
1206
|
+
revision -= fixedTransaction.revisions;
|
|
1207
|
+
for (const [id, delta] of fixedTransaction.versions) {
|
|
1208
|
+
const remaining = (versions.get(id) || 0) - delta;
|
|
1209
|
+
if (remaining > 0)
|
|
1210
|
+
versions.set(id, remaining);
|
|
1211
|
+
else
|
|
1212
|
+
versions.delete(id);
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
fixedTransaction = null;
|
|
1216
|
+
committing = false;
|
|
1217
|
+
}
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
343
1220
|
return host;
|
|
344
1221
|
};
|
|
345
1222
|
var host_default = createBlockEditorHost;
|
|
@@ -497,14 +1374,21 @@ var createBlockEditorErrorSession = (reference, error) => {
|
|
|
497
1374
|
var error_session_default = createBlockEditorErrorSession;
|
|
498
1375
|
|
|
499
1376
|
// dist/turbowarp/bridge.js
|
|
500
|
-
var
|
|
501
|
-
var
|
|
1377
|
+
var fixedDeclaration = (registry, snapshot) => snapshot && typeof registry.resolveFixed === "function" && registry.resolveFixed(snapshot.opcode);
|
|
1378
|
+
var openBlockEditorSession = ({ registry, reference, host, descendants }) => {
|
|
1379
|
+
const snapshot = host.readBlock ? host.readBlock(reference) : null;
|
|
1380
|
+
if (fixedDeclaration(registry, snapshot))
|
|
1381
|
+
return supportsFixedInputEditing(host) ? registry.open(reference, host) : void 0;
|
|
1382
|
+
return descendants && supportsDescendantEditing(host) ? registry.openDescendants(reference, host) : registry.open(reference, host);
|
|
1383
|
+
};
|
|
1384
|
+
var createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label, canOpen, onOpen, onError, descendants = false, fixedInputs = false }) => {
|
|
502
1385
|
const host = host_default({
|
|
503
1386
|
ScratchBlocks,
|
|
504
1387
|
workspace,
|
|
505
1388
|
vm,
|
|
506
1389
|
registry: service.registry,
|
|
507
1390
|
enableDescendants: descendants,
|
|
1391
|
+
enableFixedInputs: fixedInputs,
|
|
508
1392
|
onError
|
|
509
1393
|
});
|
|
510
1394
|
const decorations = /* @__PURE__ */ new Map();
|
|
@@ -512,6 +1396,7 @@ var createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label, c
|
|
|
512
1396
|
let timer = null;
|
|
513
1397
|
let activeSession = null;
|
|
514
1398
|
let openingSnapshot = null;
|
|
1399
|
+
let openingFixedDeclaration = null;
|
|
515
1400
|
let stopWaiting = null;
|
|
516
1401
|
const endSession = () => {
|
|
517
1402
|
const session = activeSession;
|
|
@@ -534,11 +1419,17 @@ var createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label, c
|
|
|
534
1419
|
}
|
|
535
1420
|
};
|
|
536
1421
|
const checkSession = () => {
|
|
1422
|
+
var _a;
|
|
537
1423
|
if (host.isCommitting())
|
|
538
1424
|
return;
|
|
539
1425
|
if (!activeSession || !openingSnapshot || !["editing", "saving"].includes(activeSession.getState().status))
|
|
540
1426
|
return;
|
|
541
1427
|
const current = typeof activeSession.getNodes === "function" ? host.descendants.readSubtree(activeSession.reference) : host.readBlock(activeSession.reference);
|
|
1428
|
+
if (openingFixedDeclaration) {
|
|
1429
|
+
if (!current || ((_a = current.fixedContext) === null || _a === void 0 ? void 0 : _a.generation) !== openingSnapshot.fixedContext.generation || fixedDeclaration(service.registry, current) !== openingFixedDeclaration)
|
|
1430
|
+
endSession();
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
542
1433
|
if (!current || JSON.stringify(current) !== JSON.stringify(openingSnapshot))
|
|
543
1434
|
endSession();
|
|
544
1435
|
};
|
|
@@ -546,6 +1437,8 @@ var createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label, c
|
|
|
546
1437
|
if (disposed || !vm.editingTarget || !canOpen() || !service.registry.resolve(block.type))
|
|
547
1438
|
return false;
|
|
548
1439
|
const snapshot = host.readBlock({ targetId: vm.editingTarget.id, blockId: block.id });
|
|
1440
|
+
if (fixedDeclaration(service.registry, snapshot))
|
|
1441
|
+
return supportsFixedInputEditing(host);
|
|
549
1442
|
return snapshot && Object.values(snapshot.arguments).every((slot) => slot.kind === "literal");
|
|
550
1443
|
};
|
|
551
1444
|
const open = (block) => {
|
|
@@ -560,8 +1453,12 @@ var createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label, c
|
|
|
560
1453
|
ScratchBlocks.hideChaff();
|
|
561
1454
|
activeSession = session;
|
|
562
1455
|
openingSnapshot = typeof session.getNodes === "function" ? host.descendants.readSubtree(session.reference) : host.readBlock(session.reference);
|
|
1456
|
+
openingFixedDeclaration = fixedDeclaration(service.registry, openingSnapshot) || null;
|
|
563
1457
|
const labels = {};
|
|
564
1458
|
const appearances = /* @__PURE__ */ Object.create(null);
|
|
1459
|
+
const rootAppearance = appearance_default(block, ScratchBlocks);
|
|
1460
|
+
appearances[reference.blockId] = rootAppearance;
|
|
1461
|
+
labels[reference.blockId] = rootAppearance.name || block.type;
|
|
565
1462
|
if (typeof session.getNodes === "function") {
|
|
566
1463
|
for (const node of session.getNodes()) {
|
|
567
1464
|
const source = workspace.getBlockById(node.reference.blockId);
|
|
@@ -576,6 +1473,7 @@ var createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label, c
|
|
|
576
1473
|
onError(error);
|
|
577
1474
|
activeSession = error_session_default(reference, error);
|
|
578
1475
|
openingSnapshot = null;
|
|
1476
|
+
openingFixedDeclaration = null;
|
|
579
1477
|
onOpen(activeSession);
|
|
580
1478
|
}
|
|
581
1479
|
};
|
|
@@ -624,7 +1522,12 @@ var createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label, c
|
|
|
624
1522
|
timer = setTimeout(refresh, 0);
|
|
625
1523
|
};
|
|
626
1524
|
const unregister = service.subscribe(() => {
|
|
627
|
-
if (
|
|
1525
|
+
if (openingFixedDeclaration && activeSession) {
|
|
1526
|
+
if (service.registry.resolveFixed(openingSnapshot.opcode) !== openingFixedDeclaration) {
|
|
1527
|
+
host.invalidate();
|
|
1528
|
+
endSession();
|
|
1529
|
+
}
|
|
1530
|
+
} else if (!activeSession || typeof activeSession.getNodes !== "function") {
|
|
628
1531
|
host.invalidate();
|
|
629
1532
|
endSession();
|
|
630
1533
|
}
|
|
@@ -663,6 +1566,7 @@ function attachTurboWarpBlockEditors(options) {
|
|
|
663
1566
|
const bridge = bridge_default({
|
|
664
1567
|
...options,
|
|
665
1568
|
descendants: options.descendants === true,
|
|
1569
|
+
fixedInputs: options.fixedInputs === true,
|
|
666
1570
|
onError: (_a = options.onError) !== null && _a !== void 0 ? _a : console.error
|
|
667
1571
|
});
|
|
668
1572
|
let disposed = false;
|