@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.
Files changed (68) hide show
  1. package/README.md +9 -6
  2. package/dist/build-info.json +3 -3
  3. package/dist/fixed-input-branches.d.ts +12 -0
  4. package/dist/fixed-input-branches.js +180 -0
  5. package/dist/fixed-input-editor.d.ts +39 -0
  6. package/dist/fixed-input-editor.js +538 -0
  7. package/dist/fixed-input-schema.d.ts +15 -0
  8. package/dist/fixed-input-schema.js +21 -0
  9. package/dist/fixed-input-snapshot.d.ts +7 -0
  10. package/dist/fixed-input-snapshot.js +180 -0
  11. package/dist/fixed-input-types.d.ts +138 -0
  12. package/dist/fixed-input-types.js +23 -0
  13. package/dist/fixed-input-view.d.ts +14 -0
  14. package/dist/fixed-input-view.js +168 -0
  15. package/dist/index.d.ts +6 -0
  16. package/dist/index.js +4 -0
  17. package/dist/react.css +168 -0
  18. package/dist/react.d.ts +8 -0
  19. package/dist/react.js +19 -2
  20. package/dist/registry.d.ts +4 -0
  21. package/dist/registry.js +45 -7
  22. package/dist/rjsf-templates.d.ts +11 -0
  23. package/dist/rjsf-templates.js +129 -0
  24. package/dist/rjsf.d.ts +24 -1
  25. package/dist/rjsf.js +35 -3
  26. package/dist/schema.d.ts +2 -0
  27. package/dist/schema.js +1 -0
  28. package/dist/session.d.ts +3 -1
  29. package/dist/session.js +205 -7
  30. package/dist/turbowarp/bridge.d.ts +2 -1
  31. package/dist/turbowarp/bridge.js +37 -5
  32. package/dist/turbowarp/fixed-fields.d.ts +82 -0
  33. package/dist/turbowarp/fixed-fields.js +311 -0
  34. package/dist/turbowarp/fixed-transaction.d.ts +18 -0
  35. package/dist/turbowarp/fixed-transaction.js +460 -0
  36. package/dist/turbowarp/host.d.ts +3 -8
  37. package/dist/turbowarp/host.js +68 -1
  38. package/dist/turbowarp.d.ts +4 -0
  39. package/dist/turbowarp.js +1 -1
  40. package/dist/types.d.ts +5 -0
  41. package/dist/view.js +4 -0
  42. package/dist/webpack4/index.js +22 -5
  43. package/dist/webpack4/metafile.json +592 -299
  44. package/dist/webpack4/react.js +20 -6
  45. package/dist/webpack4/react.js.map +2 -2
  46. package/dist/webpack4/rjsf.js +450 -60
  47. package/dist/webpack4/rjsf.js.map +4 -4
  48. package/dist/webpack4/schema.js +6 -3
  49. package/dist/webpack4/{shared-KQOUMWJ4.js → shared-75QIWLZY.js} +1129 -1244
  50. package/dist/webpack4/{shared-KQOUMWJ4.js.map → shared-75QIWLZY.js.map} +4 -4
  51. package/dist/webpack4/shared-FYUILHED.js +1 -0
  52. package/dist/webpack4/shared-GQLPPRT2.js +210 -0
  53. package/dist/webpack4/shared-GQLPPRT2.js.map +7 -0
  54. package/dist/webpack4/shared-P2JBRZFP.js +2206 -0
  55. package/dist/webpack4/shared-P2JBRZFP.js.map +7 -0
  56. package/dist/webpack4/turbowarp.js +913 -9
  57. package/dist/webpack4/turbowarp.js.map +4 -4
  58. package/docs/api.md +7 -0
  59. package/docs/fixed-input-contracts.md +77 -0
  60. package/docs/package-distribution.md +5 -0
  61. package/docs/stage-2-publication.ja.md +6 -0
  62. package/package.json +2 -1
  63. package/dist/webpack4/shared-CQB3NG2A.js +0 -1
  64. package/dist/webpack4/shared-MRPGBJIH.js +0 -75
  65. package/dist/webpack4/shared-MRPGBJIH.js.map +0 -7
  66. package/dist/webpack4/shared-N6YQE2X6.js +0 -1029
  67. package/dist/webpack4/shared-N6YQE2X6.js.map +0 -7
  68. /package/dist/webpack4/{shared-CQB3NG2A.js.map → shared-FYUILHED.js.map} +0 -0
@@ -0,0 +1,311 @@
1
+ const owns = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
2
+ const own = (object, key) => {
3
+ const descriptor = object && Object.getOwnPropertyDescriptor(object, key);
4
+ return descriptor && 'value' in descriptor ? descriptor.value : undefined;
5
+ };
6
+ const primitive = value => typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
7
+ const token = /^-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?$/u;
8
+ // Inspect data properties without invoking custom field accessors or menu providers.
9
+ const inherited = (object, name) => {
10
+ for (let current = object; current; current = Object.getPrototypeOf(current)) {
11
+ const descriptor = Object.getOwnPropertyDescriptor(current, name);
12
+ if (descriptor)
13
+ return 'value' in descriptor ? descriptor.value : undefined;
14
+ }
15
+ return undefined;
16
+ };
17
+ const storage = ['text_', 'value_', 'colour_', 'validator_', 'sourceBlock_', 'hue_', 'saturation_', 'brightness_'];
18
+ const methods = ['getValue', 'getText', 'setValue', 'setText', 'getValidator', 'classValidator', 'callValidator',
19
+ 'getOptions', 'forceRerender', 'updateSliderHandles_', 'updateDom_'];
20
+ const trustedClasses = new WeakMap();
21
+ /** Freeze native method identities once when the host attaches, before opening editors. */
22
+ export function initializeFixedFields(ScratchBlocks) {
23
+ for (const key of ['FieldTextInput', 'FieldNumber', 'FieldDropdown', 'FieldColourSlider']) {
24
+ const Class = ScratchBlocks[key];
25
+ if (typeof Class !== 'function' || trustedClasses.has(Class))
26
+ continue;
27
+ const chain = [];
28
+ for (let prototype = Class.prototype; prototype && prototype !== Object.prototype; prototype = Object.getPrototypeOf(prototype)) {
29
+ chain.push({ prototype, own: methods.map(name => [name, Object.getOwnPropertyDescriptor(prototype, name)]) });
30
+ }
31
+ trustedClasses.set(Class, { prototype: Class.prototype, chain,
32
+ methods: methods.map(name => [name, inherited(Class.prototype, name)]) });
33
+ }
34
+ }
35
+ const safeField = (field, Class) => {
36
+ const trusted = Class && trustedClasses.get(Class);
37
+ if (!trusted || Class.prototype !== trusted.prototype || Object.getPrototypeOf(field) !== trusted.prototype)
38
+ return false;
39
+ let currentPrototype = trusted.prototype;
40
+ for (const entry of trusted.chain) {
41
+ if (currentPrototype !== entry.prototype)
42
+ return false;
43
+ for (const [name, expected] of entry.own) {
44
+ const actual = Object.getOwnPropertyDescriptor(currentPrototype, name);
45
+ if (Boolean(actual) !== Boolean(expected) ||
46
+ (actual && (!('value' in actual) || !expected || !('value' in expected) || actual.value !== expected.value)))
47
+ return false;
48
+ }
49
+ currentPrototype = Object.getPrototypeOf(currentPrototype);
50
+ }
51
+ if (currentPrototype !== Object.prototype && currentPrototype !== null)
52
+ return false;
53
+ for (const name of storage) {
54
+ for (let current = field; current; current = Object.getPrototypeOf(current)) {
55
+ const descriptor = Object.getOwnPropertyDescriptor(current, name);
56
+ if (!descriptor)
57
+ continue;
58
+ if (!('value' in descriptor))
59
+ return false;
60
+ break;
61
+ }
62
+ }
63
+ for (const [name, expected] of trusted.methods) {
64
+ if (owns(field, name) || inherited(field, name) !== expected)
65
+ return false;
66
+ }
67
+ for (let current = field; current; current = Object.getPrototypeOf(current)) {
68
+ const descriptor = Object.getOwnPropertyDescriptor(current, 'validator_');
69
+ if (descriptor)
70
+ return 'value' in descriptor && descriptor.value == null;
71
+ }
72
+ return false;
73
+ };
74
+ const arrayData = value => {
75
+ if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype)
76
+ return null;
77
+ const result = [];
78
+ for (let index = 0; index < value.length; index++) {
79
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
80
+ if (!descriptor || !('value' in descriptor))
81
+ return null;
82
+ result.push(descriptor.value);
83
+ }
84
+ return result;
85
+ };
86
+ const staticValues = field => {
87
+ const items = arrayData(own(field, 'menuGenerator_'));
88
+ if (!items || items.length === 0)
89
+ return null;
90
+ const values = [];
91
+ for (const item of items) {
92
+ const tuple = arrayData(item);
93
+ if (!tuple || tuple.length !== 2 || typeof tuple[0] !== 'string' || typeof tuple[1] !== 'string')
94
+ return null;
95
+ values.push(tuple[1]);
96
+ }
97
+ return Object.freeze(values);
98
+ };
99
+ const rawKeys = ['text_', 'value_', 'colour_', 'hue_', 'saturation_', 'brightness_'];
100
+ const ownState = (object, keys) => keys.map(name => [name, Object.getOwnPropertyDescriptor(object, name)]);
101
+ const restoreOwnState = (object, state) => {
102
+ for (const [name, descriptor] of state) {
103
+ if (descriptor)
104
+ Object.defineProperty(object, name, descriptor);
105
+ else
106
+ delete object[name];
107
+ }
108
+ };
109
+ const vmFieldsIdentity = (fields, identify) => Object.keys(fields || {}).sort().map(name => {
110
+ const descriptor = Object.getOwnPropertyDescriptor(fields, name);
111
+ if (!descriptor || !('value' in descriptor))
112
+ return [name, 'accessor'];
113
+ const stored = descriptor.value;
114
+ if (!stored || typeof stored !== 'object')
115
+ return [name, typeof stored, String(stored)];
116
+ return [name, identify(stored), ...Object.keys(stored).sort().map(key => {
117
+ const item = Object.getOwnPropertyDescriptor(stored, key);
118
+ if (!item || !('value' in item))
119
+ return [key, 'accessor'];
120
+ const value = item.value;
121
+ return [key, typeof value, primitive(value) ? (Object.is(value, -0) ? '-0' : String(value)) :
122
+ value && (typeof value === 'object' || typeof value === 'function') ? identify(value) : String(value)];
123
+ })];
124
+ });
125
+ const colorState = (block, field) => {
126
+ const colors = ['getColour', 'getColourSecondary', 'getColourTertiary', 'getColourQuaternary'];
127
+ return {
128
+ colors: colors.map(name => typeof block[name] === 'function' ? block[name]() : undefined),
129
+ hsv: ['hue_', 'saturation_', 'brightness_'].map(name => [name, own(field, name)]),
130
+ blockProperties: ownState(block, ['colour_', 'colourSecondary_', 'colourTertiary_', 'colourQuaternary_'])
131
+ };
132
+ };
133
+ /** Native objects stay local; only primitive metadata is returned in snapshots. */
134
+ export function inspectFixedArgument({ ScratchBlocks, block, vmBlock, target, argument, role, identify, extensionId }) {
135
+ initializeFixedFields(ScratchBlocks);
136
+ const sourceIdentity = [argument, identify(block), identify(vmBlock)];
137
+ let observedFields = [];
138
+ const unavailable = (source, reason, raw) => ({
139
+ slot: primitive(raw) ? { kind: 'literal', value: raw } : { kind: 'reporter' },
140
+ metadata: { role, source, identity: JSON.stringify([...sourceIdentity, source]), reason },
141
+ signatureParts: [...sourceIdentity, observedFields]
142
+ });
143
+ const direct = block.getField(argument);
144
+ const input = block.getInput(argument);
145
+ const connected = input && input.connection && input.connection.targetBlock();
146
+ const vmInput = vmBlock.inputs && vmBlock.inputs[argument];
147
+ if ((connected ? connected.id : null) !== (vmInput && vmInput.block ? vmInput.block : null))
148
+ return null;
149
+ if (direct && connected)
150
+ return null;
151
+ if (connected && !connected.isShadow()) {
152
+ const vmReporter = target.blocks.getBlock(connected.id);
153
+ if (!vmReporter || vmReporter.opcode !== connected.type || vmReporter.parent !== block.id)
154
+ return null;
155
+ sourceIdentity.push(identify(connected), identify(vmReporter), connected.id, connected.type);
156
+ return { slot: { kind: 'reporter' }, metadata: { role, source: 'reporter', identity: JSON.stringify(sourceIdentity) },
157
+ signatureParts: sourceIdentity };
158
+ }
159
+ let owner = direct ? block : connected;
160
+ if (!owner) {
161
+ if (vmBlock.fields && owns(vmBlock.fields, argument))
162
+ return null;
163
+ return unavailable('missing', 'The declared field or input is missing.');
164
+ }
165
+ const vmOwner = direct ? vmBlock : target.blocks.getBlock(owner.id);
166
+ if (!vmOwner || vmOwner.opcode !== owner.type)
167
+ return null;
168
+ sourceIdentity.push(identify(owner), identify(vmOwner), owner.id, owner.type);
169
+ observedFields = vmFieldsIdentity(vmOwner.fields, identify);
170
+ if (!direct && (!vmInput || vmInput.shadow !== owner.id || vmOwner.parent !== block.id))
171
+ return null;
172
+ let kind;
173
+ let name;
174
+ let Class;
175
+ if (direct) {
176
+ kind = 'menu';
177
+ name = argument;
178
+ Class = ScratchBlocks.FieldDropdown;
179
+ }
180
+ else if (owner.type === 'text') {
181
+ kind = 'text';
182
+ name = 'TEXT';
183
+ Class = ScratchBlocks.FieldTextInput;
184
+ }
185
+ else if (owner.type === 'math_number') {
186
+ kind = 'number';
187
+ name = 'NUM';
188
+ Class = ScratchBlocks.FieldNumber;
189
+ }
190
+ else if (owner.type === 'colour_picker') {
191
+ kind = 'color';
192
+ name = 'COLOUR';
193
+ Class = ScratchBlocks.FieldColourSlider;
194
+ }
195
+ else if (typeof extensionId === 'string' && owner.type.startsWith(`${extensionId}_menu_`)) {
196
+ kind = 'menu';
197
+ Class = ScratchBlocks.FieldDropdown;
198
+ const names = [];
199
+ for (const row of owner.inputList)
200
+ for (const candidate of row.fieldRow) {
201
+ const candidateName = own(candidate, 'name');
202
+ if (typeof candidateName === 'string' && candidateName)
203
+ names.push(candidateName);
204
+ }
205
+ if (names.length !== 1)
206
+ return unavailable('unsupported', 'The menu shadow does not have one standard field.');
207
+ [name] = names;
208
+ }
209
+ else
210
+ return unavailable('unsupported', 'The shadow field family is unsupported.');
211
+ const field = direct || owner.getField(name);
212
+ const stored = vmOwner.fields && vmOwner.fields[name];
213
+ if (!field || !stored)
214
+ return null;
215
+ sourceIdentity.push(identify(field), name);
216
+ const raw = own(stored, 'value');
217
+ if (!safeField(field, Class))
218
+ return unavailable('unsupported', 'The field class, methods or validator is unsupported.', raw);
219
+ const value = inherited(Class.prototype, 'getValue').call(field);
220
+ if (!Object.is(value, raw))
221
+ return null;
222
+ if (typeof value !== 'string')
223
+ return unavailable('unsupported', 'The native field value is not a string.', raw);
224
+ const allowedValues = kind === 'menu' ? staticValues(field) : undefined;
225
+ if (kind === 'menu' && !allowedValues)
226
+ return unavailable('unsupported', 'Dynamic or nonstandard menus are unsupported.', raw);
227
+ sourceIdentity.push(kind, ...(allowedValues || []));
228
+ const binding = { block: owner, field, fieldName: name, value, vmBlock: vmOwner, kind,
229
+ Class, prototype: Class.prototype, allowedValues,
230
+ restoreValue: inherited(Class.prototype, 'setValue'), rawState: ownState(field, rawKeys),
231
+ restoreHandles: inherited(Class.prototype, 'updateSliderHandles_'),
232
+ restoreDom: inherited(Class.prototype, 'updateDom_'),
233
+ ...(kind === 'color' ? { restoreState: colorState(owner, field) } : {}) };
234
+ return { slot: { kind: 'literal', value }, metadata: { role, source: direct ? 'field' : 'shadow',
235
+ identity: JSON.stringify(sourceIdentity), field: { blockId: owner.id, name, type: { text: 'FieldTextInput', number: 'FieldNumber', menu: 'FieldDropdown', color: 'FieldColourSlider' }[kind] } },
236
+ ...(role === 'editable' ? { binding } : {}), signatureParts: [...sourceIdentity, observedFields] };
237
+ }
238
+ /** Validate the exact saved primitive; native setters must not silently normalize it. */
239
+ export function prepareFixedChange(binding, value) {
240
+ if (!binding || !safeField(binding.field, binding.Class) || typeof value !== 'string') {
241
+ throw new TypeError('Only standard native string field writes are supported.');
242
+ }
243
+ if (binding.kind === 'menu') {
244
+ const currentValues = staticValues(binding.field);
245
+ if (!currentValues || currentValues.length !== binding.allowedValues.length ||
246
+ currentValues.some((item, index) => item !== binding.allowedValues[index])) {
247
+ throw new TypeError('The static menu changed before preparing the write.');
248
+ }
249
+ }
250
+ if (value !== binding.value) {
251
+ if (binding.kind === 'number' && (!token.test(value.trim()) || !Number.isFinite(Number(value)))) {
252
+ throw new TypeError('Expected a finite numeric field token.');
253
+ }
254
+ if (binding.kind === 'color' && !/^#(?:[a-f0-9]{3}|[a-f0-9]{6})$/iu.test(value)) {
255
+ throw new TypeError('Expected a hexadecimal color field token.');
256
+ }
257
+ if (binding.kind === 'menu' && !binding.allowedValues.includes(value)) {
258
+ throw new TypeError('Expected a declared static menu value.');
259
+ }
260
+ }
261
+ return { ...binding, next: value };
262
+ }
263
+ /** Capture a later external value without invoking replacement field methods. */
264
+ export function captureFixedFieldState(binding) {
265
+ if (!binding || !safeField(binding.field, binding.Class)) {
266
+ throw new TypeError('Cannot capture an unsupported native field.');
267
+ }
268
+ const value = inherited(binding.prototype, 'getValue').call(binding.field);
269
+ if (typeof value !== 'string')
270
+ throw new TypeError('Expected a native string field.');
271
+ return { ...binding, value, rawState: ownState(binding.field, rawKeys),
272
+ ...(binding.kind === 'color' ? { restoreState: colorState(binding.block, binding.field) } : {}) };
273
+ }
274
+ /** Restore raw text and the standard color field's additional block/UI state. */
275
+ export function restoreFixedField(binding) {
276
+ let failure;
277
+ try {
278
+ binding.restoreValue.call(binding.field, binding.value);
279
+ }
280
+ catch (error) {
281
+ failure = error;
282
+ }
283
+ // The standard setters can update raw data before renderer code throws.
284
+ // Restore primitive descriptors independently so renderer failure cannot retain new data.
285
+ restoreOwnState(binding.field, binding.rawState);
286
+ if (binding.restoreState) {
287
+ const colors = binding.restoreState.colors;
288
+ try {
289
+ if (colors.every(value => typeof value === 'string'))
290
+ binding.block.setColour(...colors);
291
+ }
292
+ catch (error) {
293
+ failure = failure || error;
294
+ }
295
+ restoreOwnState(binding.block, binding.restoreState.blockProperties);
296
+ try {
297
+ binding.restoreHandles.call(binding.field);
298
+ }
299
+ catch (error) {
300
+ failure = failure || error;
301
+ }
302
+ try {
303
+ binding.restoreDom.call(binding.field);
304
+ }
305
+ catch (error) {
306
+ failure = failure || error;
307
+ }
308
+ }
309
+ if (failure)
310
+ throw failure;
311
+ }
@@ -0,0 +1,18 @@
1
+ export default function createFixedInputPort({ ScratchBlocks, workspace, vm, registry, identify, getState, begin, markEvent, finish, onError, subscribeScope }: {
2
+ ScratchBlocks: any;
3
+ workspace: any;
4
+ vm: any;
5
+ registry: any;
6
+ identify: any;
7
+ getState: any;
8
+ begin: any;
9
+ markEvent: any;
10
+ finish: any;
11
+ onError: any;
12
+ subscribeScope: any;
13
+ }): Readonly<{
14
+ capability: "fixed-inputs-v1";
15
+ readBlock: (reference: any, declaration: any) => import("../fixed-input-types.js").FixedBlockSnapshot | null;
16
+ commit: (request: any) => void;
17
+ subscribeInvalidation: (reference: any, declaration: any, listener: any) => () => void;
18
+ }>;