@kubohiroya/turbowarp-extension-data-editor 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -6
- package/dist/build-info.json +7 -2
- package/dist/descendants.js +11 -2
- 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 +7 -0
- package/dist/index.js +4 -0
- package/dist/json-value.d.ts +4 -0
- package/dist/json-value.js +12 -0
- package/dist/prepared-save.d.ts +5 -0
- package/dist/prepared-save.js +47 -0
- package/dist/prepared-types.d.ts +13 -0
- package/dist/prepared-types.js +1 -0
- package/dist/react.css +42 -0
- package/dist/react.d.ts +3 -0
- package/dist/react.js +10 -1
- package/dist/registry.d.ts +6 -0
- package/dist/registry.js +98 -48
- package/dist/rjsf.d.ts +48 -1
- package/dist/rjsf.js +92 -8
- package/dist/schema-compose.d.ts +6 -0
- package/dist/schema-compose.js +103 -0
- package/dist/schema-engine.d.ts +18 -0
- package/dist/schema-engine.js +298 -0
- package/dist/schema-json.d.ts +10 -0
- package/dist/schema-json.js +68 -0
- package/dist/schema-types.d.ts +161 -0
- package/dist/schema-types.js +2 -0
- package/dist/schema-view.d.ts +7 -0
- package/dist/schema-view.js +102 -0
- package/dist/schema.d.ts +10 -0
- package/dist/schema.js +87 -0
- package/dist/session.d.ts +3 -1
- package/dist/session.js +220 -9
- package/dist/source-document.d.ts +3 -0
- package/dist/source-document.js +415 -0
- package/dist/source-editor.d.ts +13 -0
- package/dist/source-editor.js +235 -0
- package/dist/source-schema-hints.d.ts +3 -0
- package/dist/source-schema-hints.js +13 -0
- package/dist/source-types.d.ts +47 -0
- package/dist/source-types.js +1 -0
- package/dist/source-view.d.ts +3 -0
- package/dist/source-view.js +318 -0
- package/dist/turbowarp/bridge.d.ts +2 -1
- package/dist/turbowarp/bridge.js +34 -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 +7 -4
- package/dist/view.js +4 -0
- package/dist/webpack4/index.js +24 -5
- package/dist/webpack4/metafile.json +9886 -8710
- package/dist/webpack4/react.js +11 -2
- package/dist/webpack4/react.js.map +2 -2
- package/dist/webpack4/rjsf.js +15205 -20951
- package/dist/webpack4/rjsf.js.map +4 -4
- package/dist/webpack4/schema.js +20 -0
- package/dist/webpack4/shared-75QIWLZY.js +8375 -0
- package/dist/webpack4/shared-75QIWLZY.js.map +7 -0
- package/dist/webpack4/shared-BKTRZUZH.js +42 -0
- package/dist/webpack4/{shared-KIFRVTSM.js.map → shared-BKTRZUZH.js.map} +1 -1
- package/dist/webpack4/shared-FYUILHED.js +1 -0
- package/dist/webpack4/shared-FYUILHED.js.map +7 -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/{shared-KIFRVTSM.js → shared-RN7GOT65.js} +2 -41
- package/dist/webpack4/shared-RN7GOT65.js.map +7 -0
- package/dist/webpack4/turbowarp.js +912 -9
- package/dist/webpack4/turbowarp.js.map +4 -4
- package/docs/README.md +1 -0
- package/docs/block-editor-e2e.md +98 -16
- package/docs/ci-success-gate.md +84 -0
- package/docs/editor/issue-12-public-validation/README.md +61 -0
- package/docs/editor/issue-12-public-validation/dark-invalid.png +0 -0
- package/docs/editor/issue-12-public-validation/dark-styles.json +173 -0
- package/docs/editor/issue-12-public-validation/dark-valid.png +0 -0
- package/docs/editor/issue-12-public-validation/deployment-target.json +5 -0
- package/docs/editor/issue-12-public-validation/deployment-wait.json +7 -0
- package/docs/editor/issue-12-public-validation/light-invalid.png +0 -0
- package/docs/editor/issue-12-public-validation/light-styles.json +173 -0
- package/docs/editor/issue-12-public-validation/light-valid.png +0 -0
- package/docs/editor/issue-12-public-validation/provenance.json +88 -0
- package/docs/editor/issue-12-public-validation/results.json +677 -0
- package/docs/editor/issue-12-public-validation/summary.json +206 -0
- package/docs/fixed-input-contracts.md +77 -0
- package/docs/github-pages.md +48 -41
- package/docs/package-distribution.md +2 -2
- package/docs/schema-stage1-browser.json +10 -0
- package/docs/schema-stage1-contracts.json +242 -0
- package/docs/schema-stage1-dependencies.json +202 -0
- package/docs/schema-stage1-git-artifact-20261018.ja.md +17 -0
- package/docs/schema-stage1-profile-compat.json +30 -0
- package/docs/schema-stage1-review-fixes-20261018.ja.md +36 -0
- package/docs/schema-stage1-verification.json +541 -0
- package/docs/schema-stage1.ja.md +80 -0
- package/docs/schema.md +43 -0
- package/docs/source-forms.ja.md +19 -0
- package/docs/stage-2-publication.ja.md +35 -0
- package/docs/template-fixture-separation.ja.md +43 -0
- package/package.json +18 -3
- package/webpack4.cjs +1 -1
- package/dist/webpack4/shared-CQB3NG2A.js +0 -1
- package/dist/webpack4/shared-WHOAW2VF.js +0 -957
- package/dist/webpack4/shared-WHOAW2VF.js.map +0 -7
- /package/dist/webpack4/{shared-CQB3NG2A.js.map → schema.js.map} +0 -0
|
@@ -1,12 +1,23 @@
|
|
|
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,
|
|
6
13
|
DEFAULT_DESCENDANT_LIMITS,
|
|
7
14
|
DESCENDANT_EDITING_CAPABILITY,
|
|
8
15
|
supportsDescendantEditing
|
|
9
|
-
} from "./shared-
|
|
16
|
+
} from "./shared-BKTRZUZH.js";
|
|
17
|
+
import {
|
|
18
|
+
snapshotJson
|
|
19
|
+
} from "./shared-75QIWLZY.js";
|
|
20
|
+
import "./shared-RN7GOT65.js";
|
|
10
21
|
|
|
11
22
|
// dist/turbowarp/subtree.js
|
|
12
23
|
var collectBlockEditorSubtree = ({ ScratchBlocks, reference, inspect, generation }) => {
|
|
@@ -66,17 +77,827 @@ var collectBlockEditorSubtree = ({ ScratchBlocks, reference, inspect, generation
|
|
|
66
77
|
};
|
|
67
78
|
var subtree_default = collectBlockEditorSubtree;
|
|
68
79
|
|
|
69
|
-
// dist/turbowarp/
|
|
80
|
+
// dist/turbowarp/fixed-fields.js
|
|
70
81
|
var owns = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
|
|
71
|
-
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 }) => {
|
|
72
878
|
let disposed = false;
|
|
73
879
|
let committing = false;
|
|
74
880
|
let revision = 0;
|
|
75
881
|
let identity = 0;
|
|
76
882
|
let generation = 1;
|
|
883
|
+
let externalRevision = 0;
|
|
884
|
+
let fixedTransaction = null;
|
|
77
885
|
let lastTarget = vm.editingTarget;
|
|
78
886
|
const versions = /* @__PURE__ */ new Map();
|
|
79
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
|
+
};
|
|
80
901
|
let notifyInvalidations = () => {
|
|
81
902
|
};
|
|
82
903
|
const identities = /* @__PURE__ */ new WeakMap();
|
|
@@ -89,6 +910,16 @@ var createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableDes
|
|
|
89
910
|
if (event && event.isUiEvent)
|
|
90
911
|
return;
|
|
91
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++;
|
|
92
923
|
if (enableDescendants && event) {
|
|
93
924
|
const ids = /* @__PURE__ */ new Set([event.blockId, ...event.ids || []]);
|
|
94
925
|
for (const id of ids)
|
|
@@ -97,6 +928,7 @@ var createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableDes
|
|
|
97
928
|
}
|
|
98
929
|
if (!committing)
|
|
99
930
|
notifyInvalidations();
|
|
931
|
+
notifyFixedScopes();
|
|
100
932
|
};
|
|
101
933
|
const renew = () => {
|
|
102
934
|
generation++;
|
|
@@ -122,6 +954,8 @@ var createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableDes
|
|
|
122
954
|
if (!block || block.isInFlyout || block.isShadow())
|
|
123
955
|
return null;
|
|
124
956
|
const descriptor = registry.resolve(block.type);
|
|
957
|
+
if (typeof registry.resolveFixed === "function" && registry.resolveFixed(block.type))
|
|
958
|
+
return null;
|
|
125
959
|
const vmBlock = target.blocks.getBlock(block.id);
|
|
126
960
|
if (!structural && !descriptor || !block.isEditable() && (!structural || descriptor) || !vmBlock || vmBlock.opcode !== block.type)
|
|
127
961
|
return null;
|
|
@@ -278,7 +1112,7 @@ var createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableDes
|
|
|
278
1112
|
return changes.map((change) => {
|
|
279
1113
|
const record = change && records.get(change.blockId);
|
|
280
1114
|
const key = change && JSON.stringify([change.blockId, change.argument]);
|
|
281
|
-
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)) {
|
|
282
1116
|
throw new TypeError("Only distinct standard text shadow changes are supported.");
|
|
283
1117
|
}
|
|
284
1118
|
seen.add(key);
|
|
@@ -292,10 +1126,17 @@ var createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableDes
|
|
|
292
1126
|
const host = {
|
|
293
1127
|
isCommitting: () => committing,
|
|
294
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;
|
|
295
1133
|
const result = inspect(reference);
|
|
296
1134
|
return result ? result.snapshot : null;
|
|
297
1135
|
},
|
|
298
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
|
+
}
|
|
299
1140
|
const current = inspect(expected);
|
|
300
1141
|
if (!current || JSON.stringify(current.snapshot) !== JSON.stringify(expected)) {
|
|
301
1142
|
throw new BlockEditorConflictError();
|
|
@@ -305,6 +1146,8 @@ var createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableDes
|
|
|
305
1146
|
invalidate: renew,
|
|
306
1147
|
dispose: () => {
|
|
307
1148
|
disposed = true;
|
|
1149
|
+
notifyFixedScopes();
|
|
1150
|
+
fixedScopeListeners.clear();
|
|
308
1151
|
notifyInvalidations();
|
|
309
1152
|
invalidations.clear();
|
|
310
1153
|
workspace.removeChangeListener(invalidate);
|
|
@@ -338,6 +1181,42 @@ var createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableDes
|
|
|
338
1181
|
}
|
|
339
1182
|
};
|
|
340
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
|
+
}
|
|
341
1220
|
return host;
|
|
342
1221
|
};
|
|
343
1222
|
var host_default = createBlockEditorHost;
|
|
@@ -495,14 +1374,21 @@ var createBlockEditorErrorSession = (reference, error) => {
|
|
|
495
1374
|
var error_session_default = createBlockEditorErrorSession;
|
|
496
1375
|
|
|
497
1376
|
// dist/turbowarp/bridge.js
|
|
498
|
-
var
|
|
499
|
-
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 }) => {
|
|
500
1385
|
const host = host_default({
|
|
501
1386
|
ScratchBlocks,
|
|
502
1387
|
workspace,
|
|
503
1388
|
vm,
|
|
504
1389
|
registry: service.registry,
|
|
505
1390
|
enableDescendants: descendants,
|
|
1391
|
+
enableFixedInputs: fixedInputs,
|
|
506
1392
|
onError
|
|
507
1393
|
});
|
|
508
1394
|
const decorations = /* @__PURE__ */ new Map();
|
|
@@ -510,6 +1396,7 @@ var createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label, c
|
|
|
510
1396
|
let timer = null;
|
|
511
1397
|
let activeSession = null;
|
|
512
1398
|
let openingSnapshot = null;
|
|
1399
|
+
let openingFixedDeclaration = null;
|
|
513
1400
|
let stopWaiting = null;
|
|
514
1401
|
const endSession = () => {
|
|
515
1402
|
const session = activeSession;
|
|
@@ -532,11 +1419,17 @@ var createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label, c
|
|
|
532
1419
|
}
|
|
533
1420
|
};
|
|
534
1421
|
const checkSession = () => {
|
|
1422
|
+
var _a;
|
|
535
1423
|
if (host.isCommitting())
|
|
536
1424
|
return;
|
|
537
1425
|
if (!activeSession || !openingSnapshot || !["editing", "saving"].includes(activeSession.getState().status))
|
|
538
1426
|
return;
|
|
539
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
|
+
}
|
|
540
1433
|
if (!current || JSON.stringify(current) !== JSON.stringify(openingSnapshot))
|
|
541
1434
|
endSession();
|
|
542
1435
|
};
|
|
@@ -544,6 +1437,8 @@ var createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label, c
|
|
|
544
1437
|
if (disposed || !vm.editingTarget || !canOpen() || !service.registry.resolve(block.type))
|
|
545
1438
|
return false;
|
|
546
1439
|
const snapshot = host.readBlock({ targetId: vm.editingTarget.id, blockId: block.id });
|
|
1440
|
+
if (fixedDeclaration(service.registry, snapshot))
|
|
1441
|
+
return supportsFixedInputEditing(host);
|
|
547
1442
|
return snapshot && Object.values(snapshot.arguments).every((slot) => slot.kind === "literal");
|
|
548
1443
|
};
|
|
549
1444
|
const open = (block) => {
|
|
@@ -558,6 +1453,7 @@ var createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label, c
|
|
|
558
1453
|
ScratchBlocks.hideChaff();
|
|
559
1454
|
activeSession = session;
|
|
560
1455
|
openingSnapshot = typeof session.getNodes === "function" ? host.descendants.readSubtree(session.reference) : host.readBlock(session.reference);
|
|
1456
|
+
openingFixedDeclaration = fixedDeclaration(service.registry, openingSnapshot) || null;
|
|
561
1457
|
const labels = {};
|
|
562
1458
|
const appearances = /* @__PURE__ */ Object.create(null);
|
|
563
1459
|
if (typeof session.getNodes === "function") {
|
|
@@ -574,6 +1470,7 @@ var createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label, c
|
|
|
574
1470
|
onError(error);
|
|
575
1471
|
activeSession = error_session_default(reference, error);
|
|
576
1472
|
openingSnapshot = null;
|
|
1473
|
+
openingFixedDeclaration = null;
|
|
577
1474
|
onOpen(activeSession);
|
|
578
1475
|
}
|
|
579
1476
|
};
|
|
@@ -622,7 +1519,12 @@ var createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label, c
|
|
|
622
1519
|
timer = setTimeout(refresh, 0);
|
|
623
1520
|
};
|
|
624
1521
|
const unregister = service.subscribe(() => {
|
|
625
|
-
if (
|
|
1522
|
+
if (openingFixedDeclaration && activeSession) {
|
|
1523
|
+
if (service.registry.resolveFixed(openingSnapshot.opcode) !== openingFixedDeclaration) {
|
|
1524
|
+
host.invalidate();
|
|
1525
|
+
endSession();
|
|
1526
|
+
}
|
|
1527
|
+
} else if (!activeSession || typeof activeSession.getNodes !== "function") {
|
|
626
1528
|
host.invalidate();
|
|
627
1529
|
endSession();
|
|
628
1530
|
}
|
|
@@ -661,6 +1563,7 @@ function attachTurboWarpBlockEditors(options) {
|
|
|
661
1563
|
const bridge = bridge_default({
|
|
662
1564
|
...options,
|
|
663
1565
|
descendants: options.descendants === true,
|
|
1566
|
+
fixedInputs: options.fixedInputs === true,
|
|
664
1567
|
onError: (_a = options.onError) !== null && _a !== void 0 ? _a : console.error
|
|
665
1568
|
});
|
|
666
1569
|
let disposed = false;
|