@rohal12/spindle 0.52.4 → 0.52.6
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/dist/pkg/format.js +1 -1
- package/dist/pkg/headless.js +1502 -1521
- package/dist/pkg/macro-registry.json +255 -0
- package/package.json +1 -1
- package/src/class-registry.ts +6 -182
- package/src/components/macros/Button.tsx +2 -4
- package/src/components/macros/Checkbox.tsx +6 -13
- package/src/components/macros/Computed.tsx +38 -55
- package/src/components/macros/Cycle.tsx +1 -0
- package/src/components/macros/Dialog.tsx +7 -8
- package/src/components/macros/Do.tsx +2 -1
- package/src/components/macros/For.tsx +27 -78
- package/src/components/macros/Goto.tsx +6 -9
- package/src/components/macros/Include.tsx +10 -57
- package/src/components/macros/Listbox.tsx +1 -0
- package/src/components/macros/MacroError.tsx +37 -0
- package/src/components/macros/MacroLink.tsx +9 -24
- package/src/components/macros/Meter.tsx +19 -37
- package/src/components/macros/Numberbox.tsx +5 -32
- package/src/components/macros/PassageDisplay.tsx +37 -47
- package/src/components/macros/Print.tsx +1 -0
- package/src/components/macros/Radiobutton.tsx +8 -38
- package/src/components/macros/Repeat.tsx +3 -3
- package/src/components/macros/Set.tsx +3 -29
- package/src/components/macros/Switch.tsx +36 -37
- package/src/components/macros/Textarea.tsx +2 -28
- package/src/components/macros/Textbox.tsx +2 -29
- package/src/components/macros/Type.tsx +3 -3
- package/src/components/macros/Unset.tsx +17 -40
- package/src/components/macros/Watch.tsx +23 -91
- package/src/components/macros/WidgetInvocation.tsx +9 -71
- package/src/components/macros/detached-body.tsx +2 -2
- package/src/components/macros/input-macro.ts +48 -0
- package/src/components/macros/locals-scope.tsx +60 -0
- package/src/components/macros/macro-args.ts +280 -0
- package/src/components/macros/option-utils.ts +7 -12
- package/src/define-macro.ts +47 -30
- package/src/execute-mutation.ts +17 -97
- package/src/hooks/use-render-options.ts +26 -0
- package/src/markup/render.tsx +2 -4
- package/src/registry.ts +48 -0
- package/src/saves/save-manager.ts +190 -259
- package/src/saves/storage.ts +229 -402
- package/src/store.ts +244 -310
- package/src/structural.ts +388 -0
- package/types/index.d.ts +69 -6
- package/types/tooling.d.ts +33 -1
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
"name": "set",
|
|
4
4
|
"block": false,
|
|
5
5
|
"subMacros": [],
|
|
6
|
+
"parameters": [
|
|
7
|
+
{
|
|
8
|
+
"name": "code",
|
|
9
|
+
"type": "expression",
|
|
10
|
+
"required": true
|
|
11
|
+
}
|
|
12
|
+
],
|
|
6
13
|
"source": "builtin"
|
|
7
14
|
},
|
|
8
15
|
{
|
|
@@ -11,6 +18,13 @@
|
|
|
11
18
|
"subMacros": [],
|
|
12
19
|
"interpolate": true,
|
|
13
20
|
"merged": true,
|
|
21
|
+
"parameters": [
|
|
22
|
+
{
|
|
23
|
+
"name": "expression",
|
|
24
|
+
"type": "expression",
|
|
25
|
+
"required": true
|
|
26
|
+
}
|
|
27
|
+
],
|
|
14
28
|
"source": "builtin"
|
|
15
29
|
},
|
|
16
30
|
{
|
|
@@ -18,6 +32,22 @@
|
|
|
18
32
|
"block": false,
|
|
19
33
|
"subMacros": [],
|
|
20
34
|
"merged": true,
|
|
35
|
+
"parameters": [
|
|
36
|
+
{
|
|
37
|
+
"name": "target",
|
|
38
|
+
"type": "variable",
|
|
39
|
+
"required": true
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "=",
|
|
43
|
+
"type": "separator"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "expression",
|
|
47
|
+
"type": "expression",
|
|
48
|
+
"required": true
|
|
49
|
+
}
|
|
50
|
+
],
|
|
21
51
|
"source": "builtin"
|
|
22
52
|
},
|
|
23
53
|
{
|
|
@@ -26,6 +56,22 @@
|
|
|
26
56
|
"subMacros": [],
|
|
27
57
|
"interpolate": true,
|
|
28
58
|
"merged": true,
|
|
59
|
+
"parameters": [
|
|
60
|
+
{
|
|
61
|
+
"name": "current",
|
|
62
|
+
"type": "expression",
|
|
63
|
+
"required": true
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "max",
|
|
67
|
+
"type": "expression",
|
|
68
|
+
"required": true
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"name": "label",
|
|
72
|
+
"type": "string"
|
|
73
|
+
}
|
|
74
|
+
],
|
|
29
75
|
"source": "builtin"
|
|
30
76
|
},
|
|
31
77
|
{
|
|
@@ -42,6 +88,22 @@
|
|
|
42
88
|
"subMacros": [],
|
|
43
89
|
"interpolate": true,
|
|
44
90
|
"merged": true,
|
|
91
|
+
"parameters": [
|
|
92
|
+
{
|
|
93
|
+
"name": "variables",
|
|
94
|
+
"type": "names",
|
|
95
|
+
"required": true
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"name": "of",
|
|
99
|
+
"type": "separator"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"name": "list",
|
|
103
|
+
"type": "expression",
|
|
104
|
+
"required": true
|
|
105
|
+
}
|
|
106
|
+
],
|
|
45
107
|
"source": "builtin"
|
|
46
108
|
},
|
|
47
109
|
{
|
|
@@ -55,6 +117,13 @@
|
|
|
55
117
|
"block": true,
|
|
56
118
|
"subMacros": [],
|
|
57
119
|
"interpolate": true,
|
|
120
|
+
"parameters": [
|
|
121
|
+
{
|
|
122
|
+
"name": "delay",
|
|
123
|
+
"type": "delay",
|
|
124
|
+
"required": true
|
|
125
|
+
}
|
|
126
|
+
],
|
|
58
127
|
"source": "builtin"
|
|
59
128
|
},
|
|
60
129
|
{
|
|
@@ -62,6 +131,13 @@
|
|
|
62
131
|
"block": true,
|
|
63
132
|
"subMacros": [],
|
|
64
133
|
"interpolate": true,
|
|
134
|
+
"parameters": [
|
|
135
|
+
{
|
|
136
|
+
"name": "label",
|
|
137
|
+
"type": "text",
|
|
138
|
+
"required": true
|
|
139
|
+
}
|
|
140
|
+
],
|
|
65
141
|
"source": "builtin"
|
|
66
142
|
},
|
|
67
143
|
{
|
|
@@ -69,6 +145,17 @@
|
|
|
69
145
|
"block": true,
|
|
70
146
|
"subMacros": [],
|
|
71
147
|
"interpolate": true,
|
|
148
|
+
"parameters": [
|
|
149
|
+
{
|
|
150
|
+
"name": "text",
|
|
151
|
+
"type": "string",
|
|
152
|
+
"required": true
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"name": "passage",
|
|
156
|
+
"type": "string"
|
|
157
|
+
}
|
|
158
|
+
],
|
|
72
159
|
"source": "builtin"
|
|
73
160
|
},
|
|
74
161
|
{
|
|
@@ -79,6 +166,13 @@
|
|
|
79
166
|
"default"
|
|
80
167
|
],
|
|
81
168
|
"merged": true,
|
|
169
|
+
"parameters": [
|
|
170
|
+
{
|
|
171
|
+
"name": "expression",
|
|
172
|
+
"type": "expression",
|
|
173
|
+
"required": true
|
|
174
|
+
}
|
|
175
|
+
],
|
|
82
176
|
"source": "builtin"
|
|
83
177
|
},
|
|
84
178
|
{
|
|
@@ -101,6 +195,13 @@
|
|
|
101
195
|
"block": true,
|
|
102
196
|
"subMacros": [],
|
|
103
197
|
"interpolate": true,
|
|
198
|
+
"parameters": [
|
|
199
|
+
{
|
|
200
|
+
"name": "delay",
|
|
201
|
+
"type": "delay",
|
|
202
|
+
"required": true
|
|
203
|
+
}
|
|
204
|
+
],
|
|
104
205
|
"source": "builtin"
|
|
105
206
|
},
|
|
106
207
|
{
|
|
@@ -162,6 +263,17 @@
|
|
|
162
263
|
"block": true,
|
|
163
264
|
"subMacros": [],
|
|
164
265
|
"interpolate": true,
|
|
266
|
+
"parameters": [
|
|
267
|
+
{
|
|
268
|
+
"name": "label",
|
|
269
|
+
"type": "text",
|
|
270
|
+
"required": true
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
"name": "noclose",
|
|
274
|
+
"type": "flag"
|
|
275
|
+
}
|
|
276
|
+
],
|
|
165
277
|
"source": "builtin"
|
|
166
278
|
},
|
|
167
279
|
{
|
|
@@ -182,6 +294,17 @@
|
|
|
182
294
|
"subMacros": [],
|
|
183
295
|
"interpolate": true,
|
|
184
296
|
"merged": true,
|
|
297
|
+
"parameters": [
|
|
298
|
+
{
|
|
299
|
+
"name": "inline",
|
|
300
|
+
"type": "flag"
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"name": "passage",
|
|
304
|
+
"type": "expression",
|
|
305
|
+
"required": true
|
|
306
|
+
}
|
|
307
|
+
],
|
|
185
308
|
"source": "builtin"
|
|
186
309
|
},
|
|
187
310
|
{
|
|
@@ -195,12 +318,26 @@
|
|
|
195
318
|
"block": false,
|
|
196
319
|
"subMacros": [],
|
|
197
320
|
"merged": true,
|
|
321
|
+
"parameters": [
|
|
322
|
+
{
|
|
323
|
+
"name": "passage",
|
|
324
|
+
"type": "expression",
|
|
325
|
+
"required": true
|
|
326
|
+
}
|
|
327
|
+
],
|
|
198
328
|
"source": "builtin"
|
|
199
329
|
},
|
|
200
330
|
{
|
|
201
331
|
"name": "unset",
|
|
202
332
|
"block": false,
|
|
203
333
|
"subMacros": [],
|
|
334
|
+
"parameters": [
|
|
335
|
+
{
|
|
336
|
+
"name": "variable",
|
|
337
|
+
"type": "variable",
|
|
338
|
+
"required": true
|
|
339
|
+
}
|
|
340
|
+
],
|
|
204
341
|
"source": "builtin"
|
|
205
342
|
},
|
|
206
343
|
{
|
|
@@ -208,6 +345,17 @@
|
|
|
208
345
|
"block": false,
|
|
209
346
|
"subMacros": [],
|
|
210
347
|
"storeVar": true,
|
|
348
|
+
"parameters": [
|
|
349
|
+
{
|
|
350
|
+
"name": "variable",
|
|
351
|
+
"type": "variable",
|
|
352
|
+
"required": true
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
"name": "placeholder",
|
|
356
|
+
"type": "string"
|
|
357
|
+
}
|
|
358
|
+
],
|
|
211
359
|
"source": "builtin"
|
|
212
360
|
},
|
|
213
361
|
{
|
|
@@ -215,6 +363,17 @@
|
|
|
215
363
|
"block": false,
|
|
216
364
|
"subMacros": [],
|
|
217
365
|
"storeVar": true,
|
|
366
|
+
"parameters": [
|
|
367
|
+
{
|
|
368
|
+
"name": "variable",
|
|
369
|
+
"type": "variable",
|
|
370
|
+
"required": true
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
"name": "placeholder",
|
|
374
|
+
"type": "string"
|
|
375
|
+
}
|
|
376
|
+
],
|
|
218
377
|
"source": "builtin"
|
|
219
378
|
},
|
|
220
379
|
{
|
|
@@ -222,6 +381,17 @@
|
|
|
222
381
|
"block": false,
|
|
223
382
|
"subMacros": [],
|
|
224
383
|
"storeVar": true,
|
|
384
|
+
"parameters": [
|
|
385
|
+
{
|
|
386
|
+
"name": "variable",
|
|
387
|
+
"type": "variable",
|
|
388
|
+
"required": true
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
"name": "placeholder",
|
|
392
|
+
"type": "string"
|
|
393
|
+
}
|
|
394
|
+
],
|
|
225
395
|
"source": "builtin"
|
|
226
396
|
},
|
|
227
397
|
{
|
|
@@ -229,6 +399,17 @@
|
|
|
229
399
|
"block": false,
|
|
230
400
|
"subMacros": [],
|
|
231
401
|
"storeVar": true,
|
|
402
|
+
"parameters": [
|
|
403
|
+
{
|
|
404
|
+
"name": "variable",
|
|
405
|
+
"type": "variable",
|
|
406
|
+
"required": true
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
"name": "label",
|
|
410
|
+
"type": "text"
|
|
411
|
+
}
|
|
412
|
+
],
|
|
232
413
|
"source": "builtin"
|
|
233
414
|
},
|
|
234
415
|
{
|
|
@@ -236,6 +417,22 @@
|
|
|
236
417
|
"block": false,
|
|
237
418
|
"subMacros": [],
|
|
238
419
|
"storeVar": true,
|
|
420
|
+
"parameters": [
|
|
421
|
+
{
|
|
422
|
+
"name": "variable",
|
|
423
|
+
"type": "variable",
|
|
424
|
+
"required": true
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
"name": "value",
|
|
428
|
+
"type": "text",
|
|
429
|
+
"required": true
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
"name": "label",
|
|
433
|
+
"type": "text"
|
|
434
|
+
}
|
|
435
|
+
],
|
|
239
436
|
"source": "builtin"
|
|
240
437
|
},
|
|
241
438
|
{
|
|
@@ -245,6 +442,13 @@
|
|
|
245
442
|
"option"
|
|
246
443
|
],
|
|
247
444
|
"storeVar": true,
|
|
445
|
+
"parameters": [
|
|
446
|
+
{
|
|
447
|
+
"name": "variable",
|
|
448
|
+
"type": "variable",
|
|
449
|
+
"required": true
|
|
450
|
+
}
|
|
451
|
+
],
|
|
248
452
|
"source": "builtin"
|
|
249
453
|
},
|
|
250
454
|
{
|
|
@@ -252,6 +456,13 @@
|
|
|
252
456
|
"block": true,
|
|
253
457
|
"subMacros": [],
|
|
254
458
|
"storeVar": true,
|
|
459
|
+
"parameters": [
|
|
460
|
+
{
|
|
461
|
+
"name": "variable",
|
|
462
|
+
"type": "variable",
|
|
463
|
+
"required": true
|
|
464
|
+
}
|
|
465
|
+
],
|
|
255
466
|
"source": "builtin"
|
|
256
467
|
},
|
|
257
468
|
{
|
|
@@ -271,12 +482,56 @@
|
|
|
271
482
|
"name": "watch",
|
|
272
483
|
"block": false,
|
|
273
484
|
"subMacros": [],
|
|
485
|
+
"parameters": [
|
|
486
|
+
{
|
|
487
|
+
"name": "condition",
|
|
488
|
+
"type": "string",
|
|
489
|
+
"required": true
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
"name": "options",
|
|
493
|
+
"type": "options",
|
|
494
|
+
"parameters": [
|
|
495
|
+
{
|
|
496
|
+
"name": "goto",
|
|
497
|
+
"type": "string"
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
"name": "dialog",
|
|
501
|
+
"type": "string"
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
"name": "run",
|
|
505
|
+
"type": "string"
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
"name": "name",
|
|
509
|
+
"type": "string"
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
"name": "priority",
|
|
513
|
+
"type": "number"
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
"name": "once",
|
|
517
|
+
"type": "flag"
|
|
518
|
+
}
|
|
519
|
+
]
|
|
520
|
+
}
|
|
521
|
+
],
|
|
274
522
|
"source": "builtin"
|
|
275
523
|
},
|
|
276
524
|
{
|
|
277
525
|
"name": "unwatch",
|
|
278
526
|
"block": false,
|
|
279
527
|
"subMacros": [],
|
|
528
|
+
"parameters": [
|
|
529
|
+
{
|
|
530
|
+
"name": "name",
|
|
531
|
+
"type": "text",
|
|
532
|
+
"required": true
|
|
533
|
+
}
|
|
534
|
+
],
|
|
280
535
|
"source": "builtin"
|
|
281
536
|
}
|
|
282
537
|
]
|
package/package.json
CHANGED
package/src/class-registry.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
// Class registry for preserving class instances across clone/save/load cycles.
|
|
2
2
|
|
|
3
|
+
import { setOwn } from './structural';
|
|
4
|
+
import { hasOwn } from './utils/namespace';
|
|
5
|
+
|
|
6
|
+
// Copying and comparing story values live with the structural diff
|
|
7
|
+
export { deepClone, deepEqual, type DeepCloneOptions } from './structural';
|
|
8
|
+
|
|
3
9
|
type Constructor = new (...args: any[]) => any;
|
|
4
10
|
|
|
5
11
|
const registry = new Map<string, Constructor>();
|
|
@@ -33,188 +39,6 @@ export function clearRegistry(): void {
|
|
|
33
39
|
ctorToName.clear();
|
|
34
40
|
}
|
|
35
41
|
|
|
36
|
-
// --- Deep Clone ---
|
|
37
|
-
|
|
38
|
-
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
39
|
-
if (typeof value !== 'object' || value === null) return false;
|
|
40
|
-
const proto = Object.getPrototypeOf(value);
|
|
41
|
-
return proto === Object.prototype || proto === null;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Set an own enumerable property. A "__proto__" key is defined as an own
|
|
46
|
-
* property (as JSON.parse does) instead of replacing the prototype.
|
|
47
|
-
*/
|
|
48
|
-
function setOwn(target: object, key: string, value: unknown): void {
|
|
49
|
-
if (key === '__proto__') {
|
|
50
|
-
Object.defineProperty(target, key, {
|
|
51
|
-
value,
|
|
52
|
-
enumerable: true,
|
|
53
|
-
writable: true,
|
|
54
|
-
configurable: true,
|
|
55
|
-
});
|
|
56
|
-
} else {
|
|
57
|
-
(target as Record<string, unknown>)[key] = value;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export interface DeepCloneOptions {
|
|
62
|
-
/**
|
|
63
|
-
* Return instances of unregistered classes (DOM nodes, promises, other
|
|
64
|
-
* library objects) by reference instead of copying their own keys into a
|
|
65
|
-
* plain object, which would lose their prototype and identity.
|
|
66
|
-
*/
|
|
67
|
-
keepUnregistered?: boolean;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export function deepClone<T>(value: T, options: DeepCloneOptions = {}): T {
|
|
71
|
-
const seen = new Map<object, object>();
|
|
72
|
-
|
|
73
|
-
function clone(val: unknown): unknown {
|
|
74
|
-
if (val === null || typeof val !== 'object') return val;
|
|
75
|
-
|
|
76
|
-
const obj = val as object;
|
|
77
|
-
if (seen.has(obj)) return seen.get(obj);
|
|
78
|
-
|
|
79
|
-
if (val instanceof Date) return new Date(val.getTime()) as unknown;
|
|
80
|
-
if (val instanceof RegExp)
|
|
81
|
-
return new RegExp(val.source, val.flags) as unknown;
|
|
82
|
-
|
|
83
|
-
if (Array.isArray(val)) {
|
|
84
|
-
const arr: unknown[] = [];
|
|
85
|
-
seen.set(obj, arr);
|
|
86
|
-
for (let i = 0; i < val.length; i++) {
|
|
87
|
-
arr[i] = clone(val[i]);
|
|
88
|
-
}
|
|
89
|
-
return arr;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (val instanceof Map) {
|
|
93
|
-
const copy = new Map();
|
|
94
|
-
seen.set(obj, copy);
|
|
95
|
-
for (const [k, v] of val) {
|
|
96
|
-
copy.set(clone(k), clone(v));
|
|
97
|
-
}
|
|
98
|
-
return copy;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (val instanceof Set) {
|
|
102
|
-
const copy = new Set();
|
|
103
|
-
seen.set(obj, copy);
|
|
104
|
-
for (const v of val) {
|
|
105
|
-
copy.add(clone(v));
|
|
106
|
-
}
|
|
107
|
-
return copy;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Registered class instance
|
|
111
|
-
const name = registeredClassName(obj);
|
|
112
|
-
if (name !== undefined) {
|
|
113
|
-
const copy = Object.create(Object.getPrototypeOf(obj)) as Record<
|
|
114
|
-
string,
|
|
115
|
-
unknown
|
|
116
|
-
>;
|
|
117
|
-
seen.set(obj, copy);
|
|
118
|
-
for (const key of Object.keys(obj)) {
|
|
119
|
-
setOwn(copy, key, clone((obj as Record<string, unknown>)[key]));
|
|
120
|
-
}
|
|
121
|
-
return copy;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Plain object (or unregistered class — treat as plain). A plain object
|
|
125
|
-
// keeps its prototype, which may be null.
|
|
126
|
-
const plain = isPlainObject(val);
|
|
127
|
-
if (!plain && options.keepUnregistered) return val;
|
|
128
|
-
const copy = (
|
|
129
|
-
plain ? Object.create(Object.getPrototypeOf(obj) as object | null) : {}
|
|
130
|
-
) as Record<string, unknown>;
|
|
131
|
-
seen.set(obj, copy);
|
|
132
|
-
for (const key of Object.keys(obj)) {
|
|
133
|
-
setOwn(copy, key, clone((obj as Record<string, unknown>)[key]));
|
|
134
|
-
}
|
|
135
|
-
return copy;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return clone(value) as T;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// --- Deep Equal ---
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Structural equality over the value types deepClone() supports: primitives,
|
|
145
|
-
* arrays, plain objects, class instances, Date, RegExp, Map and Set (nested
|
|
146
|
-
* at any depth). Map and Set entries are compared in insertion order. Arrays
|
|
147
|
-
* are compared by length and index, so a hole equals an undefined element
|
|
148
|
-
* (deepClone() and save/load turn holes into undefined elements).
|
|
149
|
-
*/
|
|
150
|
-
export function deepEqual(a: unknown, b: unknown): boolean {
|
|
151
|
-
return equal(a, b, new Map());
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* `assumed` holds the pairs already being compared: meeting one again (a
|
|
156
|
-
* cycle) assumes it equal. Every object may pair with several others, since
|
|
157
|
-
* cycles of different lengths can still unfold to the same value.
|
|
158
|
-
*/
|
|
159
|
-
function equal(
|
|
160
|
-
a: unknown,
|
|
161
|
-
b: unknown,
|
|
162
|
-
assumed: Map<object, Set<object>>,
|
|
163
|
-
): boolean {
|
|
164
|
-
if (Object.is(a, b)) return true;
|
|
165
|
-
if (
|
|
166
|
-
a === null ||
|
|
167
|
-
b === null ||
|
|
168
|
-
typeof a !== 'object' ||
|
|
169
|
-
typeof b !== 'object'
|
|
170
|
-
) {
|
|
171
|
-
return false;
|
|
172
|
-
}
|
|
173
|
-
if (Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) return false;
|
|
174
|
-
const pairs = assumed.get(a);
|
|
175
|
-
if (pairs?.has(b)) return true;
|
|
176
|
-
if (pairs) pairs.add(b);
|
|
177
|
-
else assumed.set(a, new Set([b]));
|
|
178
|
-
|
|
179
|
-
if (a instanceof Date) return Object.is(a.getTime(), (b as Date).getTime());
|
|
180
|
-
if (a instanceof RegExp) return String(a) === String(b);
|
|
181
|
-
if (a instanceof Map || a instanceof Set) {
|
|
182
|
-
const bc = b as Map<unknown, unknown> | Set<unknown>;
|
|
183
|
-
if (a.size !== bc.size) return false;
|
|
184
|
-
const ai = a.entries();
|
|
185
|
-
const bi = bc.entries();
|
|
186
|
-
for (
|
|
187
|
-
let x = ai.next(), y = bi.next();
|
|
188
|
-
!x.done;
|
|
189
|
-
x = ai.next(), y = bi.next()
|
|
190
|
-
) {
|
|
191
|
-
if (!equal(x.value, y.value, assumed)) return false;
|
|
192
|
-
}
|
|
193
|
-
return true;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (Array.isArray(a)) {
|
|
197
|
-
const bc = b as unknown[];
|
|
198
|
-
if (a.length !== bc.length) return false;
|
|
199
|
-
for (let i = 0; i < a.length; i++) {
|
|
200
|
-
if (!equal(a[i], bc[i], assumed)) return false;
|
|
201
|
-
}
|
|
202
|
-
return true;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const ao = a as Record<string, unknown>;
|
|
206
|
-
const bo = b as Record<string, unknown>;
|
|
207
|
-
const keys = Object.keys(ao);
|
|
208
|
-
if (keys.length !== Object.keys(bo).length) return false;
|
|
209
|
-
for (const key of keys) {
|
|
210
|
-
if (!hasOwn(bo, key) || !equal(ao[key], bo[key], assumed)) return false;
|
|
211
|
-
}
|
|
212
|
-
return true;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const hasOwn = (obj: object, key: string): boolean =>
|
|
216
|
-
Object.prototype.hasOwnProperty.call(obj, key);
|
|
217
|
-
|
|
218
42
|
// --- Serialize ---
|
|
219
43
|
|
|
220
44
|
const CLASS_TAG = '__spindle_class__';
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { defineMacro } from '../../define-macro';
|
|
2
|
-
import { readWholeQuoted } from './arg-utils';
|
|
3
2
|
import { useDetachedBody } from './detached-body';
|
|
4
3
|
|
|
5
4
|
defineMacro({
|
|
6
5
|
name: 'button',
|
|
7
6
|
block: true,
|
|
8
7
|
interpolate: true,
|
|
8
|
+
parameters: [{ name: 'label', type: 'text', required: true }],
|
|
9
9
|
render({ rawArgs, children = [] }, ctx) {
|
|
10
|
-
const
|
|
11
|
-
readWholeQuoted(rawArgs.trim()) ?? rawArgs.replace(/^["']|["']$/g, '');
|
|
12
|
-
const label = ctx.resolve?.(text) ?? rawArgs;
|
|
10
|
+
const label = ctx.resolve?.(ctx.args.label ?? '') ?? rawArgs;
|
|
13
11
|
const runBody = useDetachedBody();
|
|
14
12
|
|
|
15
13
|
// Run the body outside the passage tree: all macro side effects ({set},
|
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
import { defineMacro } from '../../define-macro';
|
|
2
|
-
import { readWholeQuoted, stripLooseQuotes } from './arg-utils';
|
|
3
|
-
|
|
4
|
-
export function parseCheckboxLabel(rawArgs: string): string {
|
|
5
|
-
// `s`: a quoted label may span lines. Its trailing whitespace is trimmed
|
|
6
|
-
// here, not by the regex: `(.+?)\s*$` tries every position of a run of
|
|
7
|
-
// spaces in the label, taking time quadratic in its length.
|
|
8
|
-
const match = rawArgs.match(/^\s*["']?\$?[\w.]+["']?\s+(.+)$/s);
|
|
9
|
-
if (!match) return '';
|
|
10
|
-
const rest = match[1]!.trimEnd() || match[1]!;
|
|
11
|
-
return readWholeQuoted(rest) ?? stripLooseQuotes(rest);
|
|
12
|
-
}
|
|
13
2
|
|
|
14
3
|
defineMacro({
|
|
15
4
|
name: 'checkbox',
|
|
16
5
|
storeVar: true,
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
parameters: [
|
|
7
|
+
{ name: 'variable', type: 'variable', required: true },
|
|
8
|
+
{ name: 'label', type: 'text' },
|
|
9
|
+
],
|
|
10
|
+
render(_props, ctx) {
|
|
11
|
+
const label = ctx.args.label ?? '';
|
|
19
12
|
|
|
20
13
|
ctx.useAction({
|
|
21
14
|
type: 'checkbox',
|