@carbonenginejs/runtime-utils 0.1.1 → 0.1.3
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/LICENSE +21 -21
- package/NOTICE +23 -23
- package/README.md +69 -69
- package/THIRD-PARTY-NOTICES.md +64 -64
- package/docs/README.md +74 -73
- package/docs/architecture.md +101 -101
- package/docs/concepts/foundation-consolidation.md +85 -85
- package/docs/concepts/model-lifecycle.md +111 -0
- package/docs/const-kb.md +85 -87
- package/docs/core-types/DECORATOR-TODOS.md +25 -25
- package/docs/core-types/README.md +229 -168
- package/docs/reference/api.md +105 -102
- package/docs/reference/classes/README.md +135 -135
- package/package.json +139 -139
- package/src/arrays.js +5 -5
- package/src/audio/audioFormats.js +34 -34
- package/src/audio/index.js +1 -1
- package/src/box3.js +331 -331
- package/src/bytes.js +56 -56
- package/src/compression.js +56 -56
- package/src/constants/index.js +7 -7
- package/src/constants/trinity.js +13 -13
- package/src/constants.js +15 -15
- package/src/curve.js +79 -79
- package/src/d3d/dxgiFormats.js +46 -46
- package/src/d3d/index.js +2 -2
- package/src/d3d/primitiveTopology.js +11 -11
- package/src/document/CjsCarbonDocument.js +212 -212
- package/src/document/CjsClassRegistry.js +373 -373
- package/src/document/CjsDocumentDehydrator.js +142 -142
- package/src/document/CjsDocumentHydrator.js +156 -156
- package/src/document/CjsStructRegistry.js +348 -348
- package/src/document/hydrationAdapter.js +129 -129
- package/src/document/index.js +6 -6
- package/src/errors/CjsError.js +286 -286
- package/src/errors/index.js +5 -5
- package/src/geometry/box.js +22 -22
- package/src/geometry/cylinder.js +22 -22
- package/src/geometry/helpers/earcut.js +1 -1
- package/src/geometry/helpers/misc.js +3 -3
- package/src/geometry/index.js +8 -8
- package/src/geometry/json.js +67 -67
- package/src/geometry/lathe.js +44 -44
- package/src/geometry/plane.js +14 -14
- package/src/geometry/shape.js +4 -4
- package/src/geometry/sphere.js +24 -24
- package/src/geometry/torus.js +14 -14
- package/src/graphics/colorSpaces.js +22 -22
- package/src/graphics/index.js +4 -4
- package/src/graphics/pixelFormats.js +158 -158
- package/src/graphics/textureDimensions.js +22 -22
- package/src/graphics/trinityEnums.js +87 -87
- package/src/index.js +62 -62
- package/src/is.js +108 -46
- package/src/json.js +23 -23
- package/src/lifecycle/CjsLifecycleState.js +77 -77
- package/src/lifecycle/index.js +1 -1
- package/src/lne3.js +70 -70
- package/src/lookup.js +48 -48
- package/src/mat3.js +51 -51
- package/src/mat4.js +699 -699
- package/src/math/index.js +25 -25
- package/src/math/scalar.js +63 -63
- package/src/media/index.js +1 -1
- package/src/media/mediaTypes.js +50 -50
- package/src/mesh.js +424 -424
- package/src/model/CjsEventEmitter.js +333 -333
- package/src/model/CjsModel.js +1589 -1544
- package/src/model/CjsModelState.js +72 -72
- package/src/model/index.js +4 -4
- package/src/model/sourceRecordUtils.js +54 -54
- package/src/noise.js +310 -310
- package/src/num.js +827 -827
- package/src/object.js +39 -39
- package/src/path.js +53 -53
- package/src/pln.js +125 -125
- package/src/pool.js +9 -9
- package/src/quat.js +144 -144
- package/src/ray3.js +188 -188
- package/src/renderContext/formats.js +145 -145
- package/src/renderContext/index.js +5 -5
- package/src/renderContext/presentation.js +125 -125
- package/src/renderContext/resources.js +27 -27
- package/src/renderContext/upscaling.js +22 -22
- package/src/renderContext/window.js +20 -20
- package/src/runtime/CjsRuntimeState.js +50 -50
- package/src/schema/CjsSchema.js +555 -318
- package/src/schema/index.js +4 -4
- package/src/shader/index.js +1 -1
- package/src/shader/shaderStages.js +37 -37
- package/src/sph3.js +181 -181
- package/src/tangent.js +288 -288
- package/src/text.js +40 -40
- package/src/tri3.js +98 -98
- package/src/types/carbonTypes.js +635 -635
- package/src/types/index.js +2 -2
- package/src/utils.js +58 -58
- package/src/validation.js +46 -46
- package/src/vec2.js +229 -229
- package/src/vec3.js +1188 -1172
- package/src/vec4.js +347 -347
- package/src/vertex.js +108 -108
- package/src/webgpu/index.js +1 -1
- package/src/webgpu/textureFormats.js +121 -121
package/src/model/CjsModel.js
CHANGED
|
@@ -1,1544 +1,1589 @@
|
|
|
1
|
-
import { coerceCarbonMathInto, exportCarbonValue, normalizeCarbonValue } from "../types/index.js";
|
|
2
|
-
import { CjsSchema } from "../schema/index.js";
|
|
3
|
-
import { getRuntimeState } from "../runtime/CjsRuntimeState.js";
|
|
4
|
-
import { CjsModelState } from "./CjsModelState.js";
|
|
5
|
-
import { CjsEventEmitter } from "./CjsEventEmitter.js";
|
|
6
|
-
|
|
7
|
-
const MAX_UPDATE_PASSES = 32;
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Shared base for schema-backed CarbonEngineJS runtime classes.
|
|
11
|
-
*
|
|
12
|
-
* Source fields are exported; runtime caches and bookkeeping are not.
|
|
13
|
-
*/
|
|
14
|
-
export class CjsModel extends CjsEventEmitter
|
|
15
|
-
{
|
|
16
|
-
/**
|
|
17
|
-
*
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
{
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
*
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
*
|
|
333
|
-
*
|
|
334
|
-
* @
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
*
|
|
370
|
-
*
|
|
371
|
-
* `
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
* @
|
|
378
|
-
* @
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
*
|
|
569
|
-
*
|
|
570
|
-
*
|
|
571
|
-
*
|
|
572
|
-
*
|
|
573
|
-
* @
|
|
574
|
-
* @
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
});
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
if (
|
|
649
|
-
{
|
|
650
|
-
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
const
|
|
710
|
-
if (
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
if (
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
if (
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
if (
|
|
915
|
-
|
|
916
|
-
if (
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
return
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
//
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
if (
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
const
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
);
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
}
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
{
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
if (
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
const
|
|
1207
|
-
|
|
1208
|
-
{
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
{
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
if (
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
const result = [];
|
|
1252
|
-
for (let i = 0; i < value.length; i++)
|
|
1253
|
-
{
|
|
1254
|
-
const item = value[i];
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
?
|
|
1268
|
-
:
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
}
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
{
|
|
1296
|
-
const
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
{
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
{
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
{
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
{
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
{
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
}
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
{
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
{
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
{
|
|
1520
|
-
|
|
1521
|
-
const
|
|
1522
|
-
if (
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
if (
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1
|
+
import { coerceCarbonMathInto, exportCarbonValue, normalizeCarbonValue } from "../types/index.js";
|
|
2
|
+
import { CjsSchema } from "../schema/index.js";
|
|
3
|
+
import { getRuntimeState } from "../runtime/CjsRuntimeState.js";
|
|
4
|
+
import { CjsModelState } from "./CjsModelState.js";
|
|
5
|
+
import { CjsEventEmitter } from "./CjsEventEmitter.js";
|
|
6
|
+
|
|
7
|
+
const MAX_UPDATE_PASSES = 32;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Shared base for schema-backed CarbonEngineJS runtime classes.
|
|
11
|
+
*
|
|
12
|
+
* Source fields are exported; runtime caches and bookkeeping are not.
|
|
13
|
+
*/
|
|
14
|
+
export class CjsModel extends CjsEventEmitter
|
|
15
|
+
{
|
|
16
|
+
/**
|
|
17
|
+
* Identifies this class as a schema-backed model.
|
|
18
|
+
*
|
|
19
|
+
* Declared statically so CjsSchema can recognise a model class from a field
|
|
20
|
+
* declaration alone, without importing CjsModel - which it cannot do, since
|
|
21
|
+
* this module already imports CjsSchema. Mirrors `CjsResource.isResource`.
|
|
22
|
+
*/
|
|
23
|
+
static isModel = true;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Creates a schema-backed model with initialized runtime state.
|
|
27
|
+
*/
|
|
28
|
+
constructor()
|
|
29
|
+
{
|
|
30
|
+
super();
|
|
31
|
+
const className = CjsSchema.getClassName(this.constructor);
|
|
32
|
+
if (!className)
|
|
33
|
+
{
|
|
34
|
+
throw new TypeError("CjsModel subclasses require an explicit CjsSchema className.");
|
|
35
|
+
}
|
|
36
|
+
initializeModelState(this);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Exports the model's schema fields to a new plain object.
|
|
41
|
+
*
|
|
42
|
+
* @param {object} [options={}]
|
|
43
|
+
* @returns {object}
|
|
44
|
+
*/
|
|
45
|
+
GetValues(options = {})
|
|
46
|
+
{
|
|
47
|
+
return CjsModel.get(this, {}, options);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Applies a plain value bag through the canonical schema-backed setter.
|
|
52
|
+
*
|
|
53
|
+
* @param {object} [values={}]
|
|
54
|
+
* @param {object} [options={}]
|
|
55
|
+
* @returns {Set<string>|boolean} The changed fields, or a boolean result.
|
|
56
|
+
*/
|
|
57
|
+
SetValues(values = {}, options = {})
|
|
58
|
+
{
|
|
59
|
+
return CjsModel.set(this, values, options);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Copies the exported fields of another model into this model.
|
|
64
|
+
*
|
|
65
|
+
* @param {CjsModel} value
|
|
66
|
+
* @param {object} [options={}]
|
|
67
|
+
* @returns {CjsModel} This model.
|
|
68
|
+
*/
|
|
69
|
+
Copy(value, options = {})
|
|
70
|
+
{
|
|
71
|
+
return CjsModel.copy(this, value, options);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Constructs a new model of this instance's class from its schema values.
|
|
76
|
+
*
|
|
77
|
+
* @param {object} [options={}]
|
|
78
|
+
* @returns {CjsModel}
|
|
79
|
+
*/
|
|
80
|
+
Clone(options = {})
|
|
81
|
+
{
|
|
82
|
+
return this.constructor.clone(this, options);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Deep-merges ordered value sources and applies the result once.
|
|
87
|
+
*
|
|
88
|
+
* Plain objects merge recursively; arrays, typed arrays, and other values
|
|
89
|
+
* replace the preceding value.
|
|
90
|
+
*
|
|
91
|
+
* @param {Array<Object|CjsModel>} [values=[]]
|
|
92
|
+
* @param {object} [options={}]
|
|
93
|
+
* @returns {Set<string>|boolean} The result returned by {@link CjsModel.set}.
|
|
94
|
+
*/
|
|
95
|
+
Merge(values = [], options = {})
|
|
96
|
+
{
|
|
97
|
+
return CjsModel.merge(this, values, options);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Applies pending changes: drives the OnModified hook until the model
|
|
102
|
+
* settles, clears the dirty mark, and emits one final modified event.
|
|
103
|
+
*
|
|
104
|
+
* Calling this IS the "I made changes, apply please" contract: it always
|
|
105
|
+
* runs at least one hook pass, dirty or not, so direct/untracked
|
|
106
|
+
* mutations (the cooperative-pipeline reality) can be applied
|
|
107
|
+
* explicitly. Class Update/per-frame methods typically gate on
|
|
108
|
+
* `__state.IsDirty()` before calling.
|
|
109
|
+
*
|
|
110
|
+
* @param {object} [options={}]
|
|
111
|
+
* @param {string|Iterable<string>} [options.property] Fields the caller changed directly; their declared flag/rebuild tokens are added first.
|
|
112
|
+
* @param {string|Iterable<string>} [options.properties] Alias of `property`.
|
|
113
|
+
* @param {*} [options.source=this] Origin forwarded to the hook and event (binding feedback control).
|
|
114
|
+
* @param {boolean} [options.skipEvents=false] Prevents the final modified event.
|
|
115
|
+
* @returns {boolean} False when the hook rejected the update (dirty is retained).
|
|
116
|
+
* @throws {Error} If local changes do not settle within the update-pass limit.
|
|
117
|
+
*/
|
|
118
|
+
UpdateValues(options = {})
|
|
119
|
+
{
|
|
120
|
+
addExplicitUpdateProperties(this, options.property ?? options.properties);
|
|
121
|
+
if (this.__state.updating) return true;
|
|
122
|
+
|
|
123
|
+
const source = options.source ?? this;
|
|
124
|
+
this.__state.updating = true;
|
|
125
|
+
|
|
126
|
+
try
|
|
127
|
+
{
|
|
128
|
+
for (let pass = 0; ; pass++)
|
|
129
|
+
{
|
|
130
|
+
if (pass >= MAX_UPDATE_PASSES)
|
|
131
|
+
{
|
|
132
|
+
throw new Error(`${CjsSchema.getClassName(this.constructor)}.UpdateValues exceeded ${MAX_UPDATE_PASSES} local settle passes.`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
this.__state.dirty = false;
|
|
136
|
+
|
|
137
|
+
if (this.OnModified({ ...options, source }) === false)
|
|
138
|
+
{
|
|
139
|
+
this.__state.dirty = true;
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (!this.__state.dirty) break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch (err)
|
|
147
|
+
{
|
|
148
|
+
this.__state.dirty = true;
|
|
149
|
+
throw err;
|
|
150
|
+
}
|
|
151
|
+
finally
|
|
152
|
+
{
|
|
153
|
+
this.__state.updating = false;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (options.skipEvents !== true && this.__state.suppressEvents === 0)
|
|
157
|
+
{
|
|
158
|
+
this.EmitEvent("modified", this, { source });
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* The settle hook: reproduces the meaningful consequences of the
|
|
166
|
+
* corresponding Carbon INotify::OnModified implementation.
|
|
167
|
+
*
|
|
168
|
+
* Invoked only by UpdateValues. Receives the mutation options bag
|
|
169
|
+
* (source, caller context, skipEvents, ...). There is no changed-property
|
|
170
|
+
* list - the pipeline is cooperative and cannot guarantee one - so
|
|
171
|
+
* overrides are written broad-safe: consult own state, compare cached
|
|
172
|
+
* derivations, and rely on `__state.flags`/`__state.rebuild` tokens for
|
|
173
|
+
* targeted signals. Returning `false` rejects the update and retains the
|
|
174
|
+
* dirty mark.
|
|
175
|
+
*
|
|
176
|
+
* @param {object} [options={}]
|
|
177
|
+
* @returns {boolean} Whether the update may complete.
|
|
178
|
+
*/
|
|
179
|
+
OnModified(options = {})
|
|
180
|
+
{
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Visits this model and its schema-backed child models without revisiting cycles.
|
|
186
|
+
*
|
|
187
|
+
* In pre-order traversal, returning `false` prunes that model's descendants.
|
|
188
|
+
* Visitor return values are ignored in post-order traversal.
|
|
189
|
+
*
|
|
190
|
+
* @param {function(CjsModel): (boolean|void)} visitor
|
|
191
|
+
* @param {object} [options={}]
|
|
192
|
+
* @param {Set<CjsModel>} [options.visited] Existing cycle-detection set.
|
|
193
|
+
* @param {"pre"|"post"} [options.order="pre"]
|
|
194
|
+
* @param {boolean} [options.reverse=false] Reverses field and list-item order.
|
|
195
|
+
* @param {boolean} [options.ownedOnly=false] Traverses only owned relationships.
|
|
196
|
+
* @returns {CjsModel} This model.
|
|
197
|
+
* @throws {TypeError} If `visitor` is not a function.
|
|
198
|
+
*/
|
|
199
|
+
Traverse(visitor, options = {})
|
|
200
|
+
{
|
|
201
|
+
if (typeof visitor !== "function")
|
|
202
|
+
{
|
|
203
|
+
throw new TypeError("CjsModel.Traverse requires a visitor function.");
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const visited = options.visited instanceof Set ? options.visited : new Set();
|
|
207
|
+
const order = options.order === "post" ? "post" : "pre";
|
|
208
|
+
const reverse = options.reverse === true;
|
|
209
|
+
|
|
210
|
+
const visit = model =>
|
|
211
|
+
{
|
|
212
|
+
if (!(model instanceof CjsModel) || visited.has(model)) return;
|
|
213
|
+
visited.add(model);
|
|
214
|
+
|
|
215
|
+
let descend = true;
|
|
216
|
+
if (order === "pre") descend = visitor(model) !== false;
|
|
217
|
+
|
|
218
|
+
if (descend)
|
|
219
|
+
{
|
|
220
|
+
// Only the fields declared to hold child models, precomputed per
|
|
221
|
+
// class - not every field, type-tested per value per visit.
|
|
222
|
+
const children = CjsSchema.getSchema(model.constructor).children;
|
|
223
|
+
const start = reverse ? children.length - 1 : 0;
|
|
224
|
+
const end = reverse ? -1 : children.length;
|
|
225
|
+
const step = reverse ? -1 : 1;
|
|
226
|
+
|
|
227
|
+
for (let i = start; i !== end; i += step)
|
|
228
|
+
{
|
|
229
|
+
const child = children[i];
|
|
230
|
+
if (options.ownedOnly === true && !child.owned) continue;
|
|
231
|
+
const value = model[child.name];
|
|
232
|
+
|
|
233
|
+
if (Array.isArray(value))
|
|
234
|
+
{
|
|
235
|
+
const itemStart = reverse ? value.length - 1 : 0;
|
|
236
|
+
const itemEnd = reverse ? -1 : value.length;
|
|
237
|
+
for (let j = itemStart; j !== itemEnd; j += step) visit(value[j]);
|
|
238
|
+
}
|
|
239
|
+
else
|
|
240
|
+
{
|
|
241
|
+
visit(value);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (order === "post") visitor(model);
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
visit(this);
|
|
250
|
+
return this;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Collects unique resources reported by this model graph into an array.
|
|
255
|
+
*
|
|
256
|
+
* Every model in the graph is visited: reporting resources does not hide a
|
|
257
|
+
* model's descendants, because an under-reported dependency set would let
|
|
258
|
+
* readiness checks pass while a child's resources were still loading.
|
|
259
|
+
*
|
|
260
|
+
* Resources held in schema fields are collected automatically - they are
|
|
261
|
+
* already declared, as `@type.objectRef("TriGeometryRes")` and friends, so
|
|
262
|
+
* restating them in a hook would be the hand-written relay chain this
|
|
263
|
+
* traversal exists to replace.
|
|
264
|
+
*
|
|
265
|
+
* `OnGetResources()` is the escape hatch for resources a model holds
|
|
266
|
+
* outside its schema, such as private fields. It takes no arguments and
|
|
267
|
+
* always returns an iterable of resources - never a bare resource and never
|
|
268
|
+
* nothing. Most models do not implement it.
|
|
269
|
+
*
|
|
270
|
+
* @param {Array<*>} [out=[]] Output array, whose contents are replaced.
|
|
271
|
+
* @returns {Array<*>} The supplied output array.
|
|
272
|
+
*/
|
|
273
|
+
GetResources(out = [])
|
|
274
|
+
{
|
|
275
|
+
const resources = new Set();
|
|
276
|
+
|
|
277
|
+
this.Traverse(model =>
|
|
278
|
+
{
|
|
279
|
+
for (const field of CjsSchema.getSchema(model.constructor).resources)
|
|
280
|
+
{
|
|
281
|
+
const value = model[field.name];
|
|
282
|
+
if (Array.isArray(value))
|
|
283
|
+
{
|
|
284
|
+
for (const item of value) AddResource(resources, item);
|
|
285
|
+
}
|
|
286
|
+
else
|
|
287
|
+
{
|
|
288
|
+
AddResource(resources, value);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (typeof model.OnGetResources === "function")
|
|
293
|
+
{
|
|
294
|
+
AddResources(resources, model.OnGetResources());
|
|
295
|
+
}
|
|
296
|
+
return true;
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
out.length = 0;
|
|
300
|
+
out.push(...resources);
|
|
301
|
+
return out;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Marks the model as changed; the next settle applies it.
|
|
306
|
+
*
|
|
307
|
+
* The cooperative-pipeline contract: anything mutating outside
|
|
308
|
+
* `SetValues` (direct writes, Object.assign, reader adapters) owes this
|
|
309
|
+
* call or an explicit `UpdateValues()`.
|
|
310
|
+
*
|
|
311
|
+
* @returns {CjsModel} This model.
|
|
312
|
+
*/
|
|
313
|
+
MarkDirty()
|
|
314
|
+
{
|
|
315
|
+
this.__state.MarkDirty();
|
|
316
|
+
return this;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Clears the dirty mark without settling. Rarely correct outside tests
|
|
321
|
+
* and teardown - the settle clears it itself.
|
|
322
|
+
*
|
|
323
|
+
* @returns {CjsModel} This model.
|
|
324
|
+
*/
|
|
325
|
+
ClearDirty()
|
|
326
|
+
{
|
|
327
|
+
this.__state.ClearDirty();
|
|
328
|
+
return this;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Checks whether a settle is owed.
|
|
333
|
+
*
|
|
334
|
+
* @returns {boolean}
|
|
335
|
+
*/
|
|
336
|
+
IsDirty()
|
|
337
|
+
{
|
|
338
|
+
return this.__state.IsDirty();
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Gets the shared schema registry and decorator facade.
|
|
343
|
+
*
|
|
344
|
+
* @returns {typeof CjsSchema}
|
|
345
|
+
*/
|
|
346
|
+
static get schema()
|
|
347
|
+
{
|
|
348
|
+
return CjsSchema;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Exports a model's schema fields into an output object.
|
|
353
|
+
*
|
|
354
|
+
* All options default off, leaving the plain output identical to the
|
|
355
|
+
* historical shape. Options propagate recursively to nested models.
|
|
356
|
+
*
|
|
357
|
+
* @param {CjsModel} value
|
|
358
|
+
* @param {object} [out={}]
|
|
359
|
+
* @param {object} [options={}]
|
|
360
|
+
* @param {boolean} [options.persistOnly] Exports only persisted fields.
|
|
361
|
+
* @param {boolean} [options.typeTags] Emits `_type` only where the concrete
|
|
362
|
+
* class is not derivable from the declared field type (the root and
|
|
363
|
+
* polymorphic slots).
|
|
364
|
+
* @param {boolean} [options.forceTypeTags] Emits `_type` on every model.
|
|
365
|
+
* @param {boolean} [options.refs] Tracks shared models: repeats export as
|
|
366
|
+
* `{ _ref }` and their first occurrence carries `_id`. Also guards
|
|
367
|
+
* against cyclic graphs.
|
|
368
|
+
* @param {boolean} [options.forceIDs] Emits `_id` on every model.
|
|
369
|
+
* @param {boolean} [options.keyedLists] Exports a list as a name-keyed
|
|
370
|
+
* object when every item is a model with a unique non-empty `name`;
|
|
371
|
+
* the redundant item `name` field is dropped in that form. Empty
|
|
372
|
+
* lists stay arrays.
|
|
373
|
+
* @param {string} [options.enumFormat] Enum-backed field emission:
|
|
374
|
+
* "values" (default, numeric), "names" (exact member-name strings),
|
|
375
|
+
* or "identity" (`[name, "OwnerClass.EnumName"]` tuples). Unknown
|
|
376
|
+
* numeric values export as raw numbers in every mode.
|
|
377
|
+
* @returns {object} The supplied output object.
|
|
378
|
+
* @throws {TypeError} If the source or output target is invalid.
|
|
379
|
+
*/
|
|
380
|
+
static get(value, out = {}, options = {})
|
|
381
|
+
{
|
|
382
|
+
if (!(value instanceof CjsModel))
|
|
383
|
+
{
|
|
384
|
+
throw new TypeError("CjsModel.get requires a CjsModel source.");
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (!out || typeof out !== "object" || Array.isArray(out) || ArrayBuffer.isView(out))
|
|
388
|
+
{
|
|
389
|
+
throw new TypeError("CjsModel.get requires an object output target.");
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (!hasAdvancedExportOptions(options))
|
|
393
|
+
{
|
|
394
|
+
for (const field of getModelFields(value))
|
|
395
|
+
{
|
|
396
|
+
out[field.name] = exportSourceValue(value[field.name], options);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return out;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return exportModelInto(value, out, null, options, createExportContext(value, options));
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Applies schema-backed values to a model and processes resulting updates.
|
|
407
|
+
*
|
|
408
|
+
* Reserved metadata keys are honored, never treated as fields: a string
|
|
409
|
+
* `values._type` must name the target's class or one of its base classes;
|
|
410
|
+
* `values._id` registers the target for `{ _ref }` resolution; a
|
|
411
|
+
* `{ _ref }` incoming field value resolves to the registered instance
|
|
412
|
+
* (shared identity) and throws when the id never resolves.
|
|
413
|
+
*
|
|
414
|
+
* @param {CjsModel} out
|
|
415
|
+
* @param {object} [values={}]
|
|
416
|
+
* @param {object} [options={}]
|
|
417
|
+
* @param {boolean} [options.markDirty=true] Tracks changed properties and notification flags.
|
|
418
|
+
* @param {boolean} [options.notify=true] Tracks schema notification flags.
|
|
419
|
+
* @param {boolean} [options.skipUpdate=false] Leaves dirty changes unsettled.
|
|
420
|
+
* @param {boolean} [options.skipEvents=false] Suppresses direct modified events.
|
|
421
|
+
* @param {boolean} [options.returnBoolean=false] Returns a boolean instead of changed fields.
|
|
422
|
+
* @param {*} [options.source=out] Origin included in update callbacks and events.
|
|
423
|
+
* @returns {Set<string>|boolean} Changed fields, or a boolean result.
|
|
424
|
+
* @throws {TypeError} If the target is not a model.
|
|
425
|
+
*/
|
|
426
|
+
static set(out, values = {}, options = {})
|
|
427
|
+
{
|
|
428
|
+
if (!(out instanceof CjsModel))
|
|
429
|
+
{
|
|
430
|
+
throw new TypeError("CjsModel.set requires a CjsModel target.");
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (!values || typeof values !== "object") return false;
|
|
434
|
+
|
|
435
|
+
if (typeof values._type === "string")
|
|
436
|
+
{
|
|
437
|
+
assertTargetTypeMatches(out, values._type, options);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// One import operation context is shared across the whole call tree so
|
|
441
|
+
// `_id` registrations and `{ _ref }` resolutions see the same identity
|
|
442
|
+
// table. The outermost call owns finalization of forward references.
|
|
443
|
+
const ownsImportContext = !options.importContext;
|
|
444
|
+
const importOptions = {
|
|
445
|
+
...options,
|
|
446
|
+
importContext: options.importContext ?? createImportContext(),
|
|
447
|
+
ownerConstructor: out.constructor
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
if (values._id !== undefined && values._id !== null)
|
|
451
|
+
{
|
|
452
|
+
importOptions.importContext.register(values._id, out);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const enumTranslations = validateEnumInputs(out, values);
|
|
456
|
+
|
|
457
|
+
const changed = new Set();
|
|
458
|
+
for (const field of getModelFields(out))
|
|
459
|
+
{
|
|
460
|
+
if (!isWritableModelField(field)) continue;
|
|
461
|
+
|
|
462
|
+
const key = findIncomingKey(values, field);
|
|
463
|
+
if (key !== null)
|
|
464
|
+
{
|
|
465
|
+
const oldValue = out[field.name];
|
|
466
|
+
const incoming = enumTranslations.has(field.name) ? enumTranslations.get(field.name) : values[key];
|
|
467
|
+
|
|
468
|
+
let didChange;
|
|
469
|
+
if (isReferenceValue(incoming))
|
|
470
|
+
{
|
|
471
|
+
didChange = applyIncomingReference(out, field, incoming, importOptions);
|
|
472
|
+
}
|
|
473
|
+
else
|
|
474
|
+
{
|
|
475
|
+
// Registered struct fields have value semantics. Constructors may
|
|
476
|
+
// install their canonical struct instance up front; populate that
|
|
477
|
+
// instance rather than replacing it with an imported object.
|
|
478
|
+
const structChanged = applyIncomingStructInPlace(oldValue, incoming, field, importOptions);
|
|
479
|
+
|
|
480
|
+
if (structChanged !== null)
|
|
481
|
+
{
|
|
482
|
+
didChange = field.io?.always === true || structChanged;
|
|
483
|
+
}
|
|
484
|
+
else
|
|
485
|
+
{
|
|
486
|
+
// Fast path: a math field with an existing compatible typed array
|
|
487
|
+
// is coerced IN PLACE (no allocation, buffer reference preserved).
|
|
488
|
+
const mathChanged = coerceCarbonMathInto(oldValue, incoming, field);
|
|
489
|
+
|
|
490
|
+
if (mathChanged !== null)
|
|
491
|
+
{
|
|
492
|
+
didChange = field.io?.always === true || mathChanged;
|
|
493
|
+
}
|
|
494
|
+
else
|
|
495
|
+
{
|
|
496
|
+
const newValue = importSourceValue(incoming, field, importOptions);
|
|
497
|
+
didChange = field.io?.always === true || !areEquivalentSourceValues(oldValue, newValue);
|
|
498
|
+
if (didChange) out[field.name] = newValue;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
if (didChange)
|
|
504
|
+
{
|
|
505
|
+
changed.add(field.name);
|
|
506
|
+
if (options.markDirty !== false)
|
|
507
|
+
{
|
|
508
|
+
out.__state.dirty = true;
|
|
509
|
+
// Write-time token adds: the knowledge of WHICH field
|
|
510
|
+
// changed lives here, so declared consequences land
|
|
511
|
+
// here (props are not tracked in state).
|
|
512
|
+
if (options.notify !== false)
|
|
513
|
+
{
|
|
514
|
+
addDeclaredFieldTokens(out, field);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (ownsImportContext)
|
|
522
|
+
{
|
|
523
|
+
importOptions.importContext.finalize();
|
|
524
|
+
importOptions.importContext.initializeCreated(importOptions);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (changed.size && options.markDirty === false)
|
|
528
|
+
{
|
|
529
|
+
if (options.skipUpdate !== true && options.skipEvents !== true && out.__state.suppressEvents === 0)
|
|
530
|
+
{
|
|
531
|
+
out.EmitEvent("modified", out, createModifiedPayload(changed, options.source ?? out));
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
else if (changed.size && options.skipUpdate !== true && !out.__state.updating)
|
|
535
|
+
{
|
|
536
|
+
out.UpdateValues(options);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
return options.returnBoolean === true ? changed.size > 0 : changed.size ? changed : false;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Copies all exported fields from one model into another.
|
|
544
|
+
*
|
|
545
|
+
* @param {CjsModel} out
|
|
546
|
+
* @param {CjsModel} value
|
|
547
|
+
* @param {object} [options={}]
|
|
548
|
+
* @returns {CjsModel} The target model.
|
|
549
|
+
* @throws {TypeError} If either argument is not a model.
|
|
550
|
+
*/
|
|
551
|
+
static copy(out, value, options = {})
|
|
552
|
+
{
|
|
553
|
+
if (!(out instanceof CjsModel))
|
|
554
|
+
{
|
|
555
|
+
throw new TypeError("CjsModel.copy requires a CjsModel target.");
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if (!(value instanceof CjsModel))
|
|
559
|
+
{
|
|
560
|
+
throw new TypeError("CjsModel.copy requires a CjsModel source.");
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
CjsModel.set(out, CjsModel.get(value, {}, options), options);
|
|
564
|
+
return out;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Deep-merges ordered value sources and applies the result with one set call.
|
|
569
|
+
*
|
|
570
|
+
* @param {CjsModel} out
|
|
571
|
+
* @param {Array<object|CjsModel>} [values=[]]
|
|
572
|
+
* @param {object} [options={}]
|
|
573
|
+
* @returns {Set<string>|boolean} The result returned by {@link CjsModel.set}.
|
|
574
|
+
* @throws {TypeError} If the target, source array, or options are invalid.
|
|
575
|
+
*/
|
|
576
|
+
static merge(out, values = [], options = {})
|
|
577
|
+
{
|
|
578
|
+
if (!(out instanceof CjsModel))
|
|
579
|
+
{
|
|
580
|
+
throw new TypeError("CjsModel.merge requires a CjsModel target.");
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
if (!Array.isArray(values))
|
|
584
|
+
{
|
|
585
|
+
throw new TypeError("CjsModel.merge requires an array of value sources.");
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
if (!options || typeof options !== "object" || Array.isArray(options) || ArrayBuffer.isView(options))
|
|
589
|
+
{
|
|
590
|
+
throw new TypeError("CjsModel.merge requires an options object.");
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
const merged = {};
|
|
594
|
+
for (const value of values) mergeValueBag(merged, value, options);
|
|
595
|
+
return CjsModel.set(out, merged, options);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Constructs, populates, initializes, and cleans an owned model graph.
|
|
600
|
+
*
|
|
601
|
+
* The invoked constructor must support zero arguments. Initial population
|
|
602
|
+
* suppresses updates and events; owned children initialize before parents.
|
|
603
|
+
*
|
|
604
|
+
* A string `values._type` selects the concrete constructor: it must name
|
|
605
|
+
* this class or a registered subclass, otherwise a TypeError is thrown. A
|
|
606
|
+
* `values._id` registers the instance in the import operation context
|
|
607
|
+
* before any field descends, so `{ _ref }` values elsewhere in the same
|
|
608
|
+
* operation — including cycles and self-references — resolve to this
|
|
609
|
+
* instance. The outermost call finalizes forward references before
|
|
610
|
+
* initialization; an unresolved `_ref` throws.
|
|
611
|
+
*
|
|
612
|
+
* @param {object} [values={}]
|
|
613
|
+
* @param {object} [options={}]
|
|
614
|
+
* @returns {CjsModel} An instance of the invoked model constructor.
|
|
615
|
+
* @throws {Error} If any owned model explicitly fails initialization.
|
|
616
|
+
*/
|
|
617
|
+
static from(values = {}, options = {})
|
|
618
|
+
{
|
|
619
|
+
if (isReferenceValue(values))
|
|
620
|
+
{
|
|
621
|
+
throw new TypeError(`${CjsSchema.getClassName(this) || this.name}.from cannot construct from a { _ref } value; references resolve only inside the owning import operation.`);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
if (values && typeof values === "object" && typeof values._type === "string")
|
|
625
|
+
{
|
|
626
|
+
const Constructor = resolveRegisteredModelClass(values._type, options);
|
|
627
|
+
if (Constructor !== this)
|
|
628
|
+
{
|
|
629
|
+
if (!(Constructor.prototype instanceof this))
|
|
630
|
+
{
|
|
631
|
+
throw new TypeError(`_type "${values._type}" is not ${CjsSchema.getClassName(this) || this.name} or one of its registered subclasses.`);
|
|
632
|
+
}
|
|
633
|
+
return Constructor.from(values, options);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
const ownsImportContext = !options.importContext;
|
|
638
|
+
const importOptions = ownsImportContext
|
|
639
|
+
? { ...options, importContext: createImportContext() }
|
|
640
|
+
: options;
|
|
641
|
+
|
|
642
|
+
const result = new this();
|
|
643
|
+
|
|
644
|
+
importOptions.importContext.registerCreated(result);
|
|
645
|
+
|
|
646
|
+
// Register-before-descent: the instance is visible to `_ref` lookups
|
|
647
|
+
// before its own fields import, so back-references and cycles work.
|
|
648
|
+
if (values && typeof values === "object" && values._id !== undefined && values._id !== null)
|
|
649
|
+
{
|
|
650
|
+
importOptions.importContext.register(values._id, result);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
result.__state.suppressEvents++;
|
|
654
|
+
try
|
|
655
|
+
{
|
|
656
|
+
result.SetValues(values, {
|
|
657
|
+
...importOptions,
|
|
658
|
+
skipEvents: true,
|
|
659
|
+
skipUpdate: true
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
if (ownsImportContext)
|
|
663
|
+
{
|
|
664
|
+
importOptions.importContext.finalize();
|
|
665
|
+
importOptions.importContext.initializeCreated({
|
|
666
|
+
...importOptions,
|
|
667
|
+
initChildren: true
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
finally
|
|
672
|
+
{
|
|
673
|
+
result.__state.suppressEvents--;
|
|
674
|
+
}
|
|
675
|
+
return result;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Constructs a model from another model-like value or a raw value bag.
|
|
680
|
+
*
|
|
681
|
+
* @param {CjsModel|object|null} value
|
|
682
|
+
* @param {object} [options={}]
|
|
683
|
+
* @returns {CjsModel} An instance of the invoked model constructor.
|
|
684
|
+
*/
|
|
685
|
+
static clone(value, options = {})
|
|
686
|
+
{
|
|
687
|
+
if (!value || typeof value.GetValues !== "function")
|
|
688
|
+
{
|
|
689
|
+
return this.from(value || {}, options);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
return this.from(value.GetValues(options), options);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
CjsSchema.define(CjsModel, { className: "CjsModel" });
|
|
698
|
+
|
|
699
|
+
export const carbon = CjsSchema.carbon;
|
|
700
|
+
export { CjsSchema };
|
|
701
|
+
export const impl = CjsSchema.impl;
|
|
702
|
+
export const io = CjsSchema.io;
|
|
703
|
+
export const jessica = CjsSchema.jessica;
|
|
704
|
+
export const schema = CjsSchema;
|
|
705
|
+
export const type = CjsSchema.type;
|
|
706
|
+
|
|
707
|
+
function mergeValueBag(out, value, options = {})
|
|
708
|
+
{
|
|
709
|
+
const source = value instanceof CjsModel ? CjsModel.get(value, {}, options) : value;
|
|
710
|
+
if (!isPlainRecord(source)) return out;
|
|
711
|
+
|
|
712
|
+
for (const [key, incoming] of Object.entries(source))
|
|
713
|
+
{
|
|
714
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
|
|
715
|
+
|
|
716
|
+
const normalized = incoming instanceof CjsModel ? CjsModel.get(incoming, {}, options) : incoming;
|
|
717
|
+
if (isPlainRecord(normalized))
|
|
718
|
+
{
|
|
719
|
+
if (!isPlainRecord(out[key])) out[key] = {};
|
|
720
|
+
mergeValueBag(out[key], normalized, options);
|
|
721
|
+
}
|
|
722
|
+
else
|
|
723
|
+
{
|
|
724
|
+
out[key] = normalized;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
return out;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
function isPlainRecord(value)
|
|
731
|
+
{
|
|
732
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || ArrayBuffer.isView(value)) return false;
|
|
733
|
+
const prototype = Object.getPrototypeOf(value);
|
|
734
|
+
return prototype === Object.prototype || prototype === null;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
function getModelFields(target)
|
|
738
|
+
{
|
|
739
|
+
const schema = CjsSchema.getSchema(target.constructor);
|
|
740
|
+
return schema.fields.map(schemaFieldToModelField);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
function initializeModelState(target)
|
|
744
|
+
{
|
|
745
|
+
// Models own their runtime-state shape: __state is a CjsModelState,
|
|
746
|
+
// created at construction before anything else (the event emitter's
|
|
747
|
+
// lazily-added `events` map lives on the same instance as an expando).
|
|
748
|
+
const existing = getRuntimeState(target);
|
|
749
|
+
if (existing instanceof CjsModelState) return existing;
|
|
750
|
+
if (existing)
|
|
751
|
+
{
|
|
752
|
+
throw new TypeError("CjsModel requires __state to be a CjsModelState.");
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
const state = new CjsModelState();
|
|
756
|
+
Object.defineProperty(target, "__state", {
|
|
757
|
+
value: state,
|
|
758
|
+
enumerable: false,
|
|
759
|
+
configurable: false,
|
|
760
|
+
writable: false
|
|
761
|
+
});
|
|
762
|
+
return state;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
function initializeOwnedGraph(root, options = {})
|
|
766
|
+
{
|
|
767
|
+
root.Traverse(value =>
|
|
768
|
+
{
|
|
769
|
+
value.__state.suppressEvents++;
|
|
770
|
+
|
|
771
|
+
try
|
|
772
|
+
{
|
|
773
|
+
if (value.__state instanceof CjsModelState)
|
|
774
|
+
{
|
|
775
|
+
// Construction: everything is new, so every declared consequence
|
|
776
|
+
// applies - all flag/rebuild tokens are added, and the object is
|
|
777
|
+
// marked for one settle.
|
|
778
|
+
addAllDeclaredTokens(value);
|
|
779
|
+
value.__state.dirty = true;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// Initialize arguments belong to the class's Carbon/adapted contract.
|
|
783
|
+
// Owned-graph traversal is coordinated here and must not occupy arg 0.
|
|
784
|
+
// A conforming Initialize performs its own final
|
|
785
|
+
// UpdateValues({ skipEvents: true }), leaving nothing dirty.
|
|
786
|
+
if (typeof value.Initialize === "function")
|
|
787
|
+
{
|
|
788
|
+
if (value.Initialize() === false)
|
|
789
|
+
{
|
|
790
|
+
throw new Error(`${CjsSchema.getClassName(value.constructor)}.from initialization failed.`);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// Settle anything Initialize did not (including the no-Initialize
|
|
795
|
+
// case): the one construction settle, events suppressed.
|
|
796
|
+
if (value.__state instanceof CjsModelState && value.__state.dirty)
|
|
797
|
+
{
|
|
798
|
+
value.UpdateValues({
|
|
799
|
+
...options,
|
|
800
|
+
source: options.source ?? value,
|
|
801
|
+
skipEvents: true
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
finally
|
|
806
|
+
{
|
|
807
|
+
value.__state.suppressEvents--;
|
|
808
|
+
}
|
|
809
|
+
}, {
|
|
810
|
+
order: "post",
|
|
811
|
+
reverse: true,
|
|
812
|
+
ownedOnly: true,
|
|
813
|
+
visited: options.visited
|
|
814
|
+
});
|
|
815
|
+
return root;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
function AddResource(target, value)
|
|
819
|
+
{
|
|
820
|
+
if (value?.isResource === true) target.add(value);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
|
|
824
|
+
function AddResources(target, values)
|
|
825
|
+
{
|
|
826
|
+
if (typeof values === "string" || typeof values?.[Symbol.iterator] !== "function")
|
|
827
|
+
{
|
|
828
|
+
throw new TypeError("CjsModel.OnGetResources must return an iterable of resources.");
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
// Empty slots are the model's own unset fields, not a contract violation.
|
|
832
|
+
for (const value of values)
|
|
833
|
+
{
|
|
834
|
+
if (value !== null && value !== undefined) target.add(value);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
function schemaFieldToModelField(field)
|
|
839
|
+
{
|
|
840
|
+
return {
|
|
841
|
+
...field,
|
|
842
|
+
jsType: field.type || field.jsType || null
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
function isWritableModelField(field)
|
|
847
|
+
{
|
|
848
|
+
const io = field?.io;
|
|
849
|
+
if (!io) return true;
|
|
850
|
+
if (io.write || io.persist || io.persistOnly) return true;
|
|
851
|
+
if (io.read && !io.write) return false;
|
|
852
|
+
return true;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
function findIncomingKey(values, field)
|
|
856
|
+
{
|
|
857
|
+
for (const key of incomingKeyCandidates(field))
|
|
858
|
+
{
|
|
859
|
+
if (Object.prototype.hasOwnProperty.call(values, key)) return key;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
return null;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
function incomingKeyCandidates(field)
|
|
866
|
+
{
|
|
867
|
+
const aliases = field.aliases === undefined
|
|
868
|
+
? field.alias === undefined ? [] : [field.alias]
|
|
869
|
+
: Array.isArray(field.aliases) ? field.aliases : [field.aliases];
|
|
870
|
+
return [field.name, ...aliases].filter(value => typeof value === "string" && value.length);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
// Adds one field's declared @io.flag / @io.rebuild tokens to their stores.
|
|
874
|
+
// Duplicate adds are no-ops (Sets). Nothing in the model layer ever clears
|
|
875
|
+
// these stores - getters clear flags, work methods clear rebuild tokens.
|
|
876
|
+
function addDeclaredFieldTokens(target, field)
|
|
877
|
+
{
|
|
878
|
+
const io = field?.io;
|
|
879
|
+
if (!io) return;
|
|
880
|
+
if (io.flag) for (const token of io.flag) target.__state.flags.add(token);
|
|
881
|
+
if (io.rebuild) for (const token of io.rebuild) target.__state.rebuild.add(token);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// Construction / broad invalidation: every declared token applies.
|
|
885
|
+
function addAllDeclaredTokens(target)
|
|
886
|
+
{
|
|
887
|
+
const fields = CjsSchema.getSchema(target.constructor)?.fields || [];
|
|
888
|
+
for (const field of fields) addDeclaredFieldTokens(target, field);
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
// Direct-mutation courtesy: a caller that knows which fields it touched
|
|
892
|
+
// (bindings) passes them so declared consequences stay precise.
|
|
893
|
+
function addExplicitUpdateProperties(target, properties)
|
|
894
|
+
{
|
|
895
|
+
if (properties === null || properties === undefined) return;
|
|
896
|
+
target.__state.dirty = true;
|
|
897
|
+
for (const property of typeof properties === "string" ? [properties] : properties)
|
|
898
|
+
{
|
|
899
|
+
const field = CjsSchema.getField(target.constructor, property);
|
|
900
|
+
if (field) addDeclaredFieldTokens(target, field);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
function createModifiedPayload(properties, source)
|
|
905
|
+
{
|
|
906
|
+
return Object.freeze({
|
|
907
|
+
properties: new Set(properties),
|
|
908
|
+
source
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
function areEquivalentSourceValues(a, b)
|
|
913
|
+
{
|
|
914
|
+
if (Object.is(a, b)) return true;
|
|
915
|
+
|
|
916
|
+
if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b))
|
|
917
|
+
{
|
|
918
|
+
if (a.constructor !== b.constructor || a.length !== b.length) return false;
|
|
919
|
+
for (let i = 0; i < a.length; i++)
|
|
920
|
+
{
|
|
921
|
+
if (!Object.is(a[i], b[i])) return false;
|
|
922
|
+
}
|
|
923
|
+
return true;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
if (Array.isArray(a) && Array.isArray(b))
|
|
927
|
+
{
|
|
928
|
+
if (a.length !== b.length) return false;
|
|
929
|
+
for (let i = 0; i < a.length; i++)
|
|
930
|
+
{
|
|
931
|
+
if (!areEquivalentSourceValues(a[i], b[i])) return false;
|
|
932
|
+
}
|
|
933
|
+
return true;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
return false;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
export function exportSourceValue(value, options = {})
|
|
940
|
+
{
|
|
941
|
+
if (value instanceof CjsModel) return value.GetValues(options);
|
|
942
|
+
return exportCarbonValue(value);
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
function hasAdvancedExportOptions(options)
|
|
946
|
+
{
|
|
947
|
+
return !!(options && (options.persistOnly || options.typeTags || options.forceTypeTags
|
|
948
|
+
|| options.refs || options.forceIDs || options.keyedLists
|
|
949
|
+
|| (options.enumFormat && options.enumFormat !== "values")));
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
// Enum-aware value handling: @schema.enum("X") resolves through the owning
|
|
953
|
+
// class's PascalCase static `Constructor.X`, lazily and leaf-first.
|
|
954
|
+
const ENUM_REVERSE_CACHE = new WeakMap();
|
|
955
|
+
|
|
956
|
+
function resolveEnumStaticForField(Constructor, field)
|
|
957
|
+
{
|
|
958
|
+
const name = field?.enum?.enumType;
|
|
959
|
+
if (!name) return null;
|
|
960
|
+
const members = Constructor?.[name];
|
|
961
|
+
if (!members || typeof members !== "object") return null;
|
|
962
|
+
return { name, members };
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
function enumMemberName(members, value)
|
|
966
|
+
{
|
|
967
|
+
let reverse = ENUM_REVERSE_CACHE.get(members);
|
|
968
|
+
if (!reverse)
|
|
969
|
+
{
|
|
970
|
+
reverse = new Map();
|
|
971
|
+
for (const key of Object.keys(members))
|
|
972
|
+
{
|
|
973
|
+
// Duplicate values: first-declared key wins.
|
|
974
|
+
if (!reverse.has(members[key])) reverse.set(members[key], key);
|
|
975
|
+
}
|
|
976
|
+
ENUM_REVERSE_CACHE.set(members, reverse);
|
|
977
|
+
}
|
|
978
|
+
return reverse.get(value);
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
function enumIdentity(Constructor, name)
|
|
982
|
+
{
|
|
983
|
+
let current = Constructor;
|
|
984
|
+
while (typeof current === "function")
|
|
985
|
+
{
|
|
986
|
+
if (Object.hasOwn(current, name))
|
|
987
|
+
{
|
|
988
|
+
return `${CjsSchema.getClassName(current) || current.name}.${name}`;
|
|
989
|
+
}
|
|
990
|
+
current = Object.getPrototypeOf(current);
|
|
991
|
+
}
|
|
992
|
+
return `${CjsSchema.getClassName(Constructor) || Constructor.name}.${name}`;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
// Returns the validated numeric member value, or undefined when the input is
|
|
996
|
+
// not a member. Accepts numeric values, exact member-name strings, and arrays
|
|
997
|
+
// (element 0 only, so identity tuples round-trip).
|
|
998
|
+
function translateEnumInput(value, members)
|
|
999
|
+
{
|
|
1000
|
+
if (Array.isArray(value))
|
|
1001
|
+
{
|
|
1002
|
+
if (!value.length) return undefined;
|
|
1003
|
+
return translateEnumInput(value[0], members);
|
|
1004
|
+
}
|
|
1005
|
+
if (typeof value === "string")
|
|
1006
|
+
{
|
|
1007
|
+
return Object.hasOwn(members, value) ? members[value] : undefined;
|
|
1008
|
+
}
|
|
1009
|
+
if (typeof value === "number")
|
|
1010
|
+
{
|
|
1011
|
+
return enumMemberName(members, value) === undefined ? undefined : value;
|
|
1012
|
+
}
|
|
1013
|
+
return undefined;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
// Atomic pre-validation: every enum-backed incoming value is checked before
|
|
1017
|
+
// any mutation; one TypeError reports every invalid property.
|
|
1018
|
+
function validateEnumInputs(out, values)
|
|
1019
|
+
{
|
|
1020
|
+
const translations = new Map();
|
|
1021
|
+
let issues = null;
|
|
1022
|
+
for (const field of getModelFields(out))
|
|
1023
|
+
{
|
|
1024
|
+
if (!isWritableModelField(field)) continue;
|
|
1025
|
+
const key = findIncomingKey(values, field);
|
|
1026
|
+
if (key === null) continue;
|
|
1027
|
+
const spec = resolveEnumStaticForField(out.constructor, field);
|
|
1028
|
+
if (!spec) continue;
|
|
1029
|
+
const raw = values[key];
|
|
1030
|
+
if (raw === null || raw === undefined || raw instanceof CjsModel) continue;
|
|
1031
|
+
const translated = translateEnumInput(raw, spec.members);
|
|
1032
|
+
if (translated === undefined)
|
|
1033
|
+
{
|
|
1034
|
+
issues = issues || [];
|
|
1035
|
+
issues.push(`${field.name}: ${JSON.stringify(raw)} is not a member of ${enumIdentity(out.constructor, spec.name)}`);
|
|
1036
|
+
}
|
|
1037
|
+
else
|
|
1038
|
+
{
|
|
1039
|
+
translations.set(field.name, translated);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
if (issues)
|
|
1043
|
+
{
|
|
1044
|
+
throw new TypeError(`Invalid enum values for ${CjsSchema.getClassName(out.constructor) || "model"} - ${issues.join("; ")}`);
|
|
1045
|
+
}
|
|
1046
|
+
return translations;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
function exportEnumFieldValue(value, spec, Constructor, options)
|
|
1050
|
+
{
|
|
1051
|
+
if (typeof value !== "number") return value;
|
|
1052
|
+
const memberName = enumMemberName(spec.members, value);
|
|
1053
|
+
if (memberName === undefined) return value;
|
|
1054
|
+
if (options.enumFormat === "names") return memberName;
|
|
1055
|
+
return [memberName, enumIdentity(Constructor, spec.name)];
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
function isPersistedModelField(field)
|
|
1059
|
+
{
|
|
1060
|
+
const io = field?.io;
|
|
1061
|
+
return !!(io && (io.persist || io.persistOnly));
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
function declaredExportClassName(fieldType)
|
|
1065
|
+
{
|
|
1066
|
+
if (!fieldType) return null;
|
|
1067
|
+
if (typeof fieldType === "string") return fieldType;
|
|
1068
|
+
if (fieldType.kind === "array" || fieldType.kind === "list")
|
|
1069
|
+
{
|
|
1070
|
+
const item = fieldType.itemType ?? null;
|
|
1071
|
+
return typeof item === "string" ? item : item?.className ?? null;
|
|
1072
|
+
}
|
|
1073
|
+
return fieldType.className ?? null;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
function createExportContext(root, options)
|
|
1077
|
+
{
|
|
1078
|
+
if (!options.refs && !options.forceIDs) return null;
|
|
1079
|
+
|
|
1080
|
+
let nextId = 1;
|
|
1081
|
+
const idByModel = new Map();
|
|
1082
|
+
const context = {
|
|
1083
|
+
emitted: new Set(),
|
|
1084
|
+
idByModel,
|
|
1085
|
+
getId(model)
|
|
1086
|
+
{
|
|
1087
|
+
let id = idByModel.get(model);
|
|
1088
|
+
if (id === undefined)
|
|
1089
|
+
{
|
|
1090
|
+
id = nextId++;
|
|
1091
|
+
idByModel.set(model, id);
|
|
1092
|
+
}
|
|
1093
|
+
return id;
|
|
1094
|
+
}
|
|
1095
|
+
};
|
|
1096
|
+
|
|
1097
|
+
if (options.refs)
|
|
1098
|
+
{
|
|
1099
|
+
// Pre-count occurrences so only genuinely shared models receive ids.
|
|
1100
|
+
const counts = new Map();
|
|
1101
|
+
(function walk(value)
|
|
1102
|
+
{
|
|
1103
|
+
if (Array.isArray(value))
|
|
1104
|
+
{
|
|
1105
|
+
for (const item of value) walk(item);
|
|
1106
|
+
return;
|
|
1107
|
+
}
|
|
1108
|
+
if (!(value instanceof CjsModel)) return;
|
|
1109
|
+
const count = (counts.get(value) ?? 0) + 1;
|
|
1110
|
+
counts.set(value, count);
|
|
1111
|
+
if (count > 1) return;
|
|
1112
|
+
for (const field of getModelFields(value))
|
|
1113
|
+
{
|
|
1114
|
+
if (options.persistOnly && !isPersistedModelField(field)) continue;
|
|
1115
|
+
walk(value[field.name]);
|
|
1116
|
+
}
|
|
1117
|
+
})(root);
|
|
1118
|
+
for (const [model, count] of counts)
|
|
1119
|
+
{
|
|
1120
|
+
if (count > 1) idByModel.set(model, nextId++);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
return context;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
function exportModelInto(model, out, declaredClassName, options, context)
|
|
1128
|
+
{
|
|
1129
|
+
if (context)
|
|
1130
|
+
{
|
|
1131
|
+
context.emitted.add(model);
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
const className = CjsSchema.getClassName(model.constructor);
|
|
1135
|
+
if (options.forceTypeTags || (options.typeTags && className && className !== declaredClassName))
|
|
1136
|
+
{
|
|
1137
|
+
out._type = className;
|
|
1138
|
+
}
|
|
1139
|
+
if (context && (options.forceIDs || context.idByModel.has(model)))
|
|
1140
|
+
{
|
|
1141
|
+
out._id = context.getId(model);
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
const enumMode = options.enumFormat && options.enumFormat !== "values";
|
|
1145
|
+
for (const field of getModelFields(model))
|
|
1146
|
+
{
|
|
1147
|
+
if (options.persistOnly && !isPersistedModelField(field)) continue;
|
|
1148
|
+
if (enumMode)
|
|
1149
|
+
{
|
|
1150
|
+
const spec = resolveEnumStaticForField(model.constructor, field);
|
|
1151
|
+
if (spec)
|
|
1152
|
+
{
|
|
1153
|
+
out[field.name] = exportEnumFieldValue(model[field.name], spec, model.constructor, options);
|
|
1154
|
+
continue;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
out[field.name] = exportAdvancedValue(
|
|
1158
|
+
model[field.name],
|
|
1159
|
+
declaredExportClassName(field.jsType || field.type || null),
|
|
1160
|
+
options,
|
|
1161
|
+
context
|
|
1162
|
+
);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
return out;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
function exportAdvancedValue(value, declaredClassName, options, context)
|
|
1169
|
+
{
|
|
1170
|
+
if (value instanceof CjsModel)
|
|
1171
|
+
{
|
|
1172
|
+
if (context && options.refs && context.emitted.has(value))
|
|
1173
|
+
{
|
|
1174
|
+
return { _ref: context.getId(value) };
|
|
1175
|
+
}
|
|
1176
|
+
return exportModelInto(value, {}, declaredClassName, options, context);
|
|
1177
|
+
}
|
|
1178
|
+
if (Array.isArray(value))
|
|
1179
|
+
{
|
|
1180
|
+
if (options.keyedLists)
|
|
1181
|
+
{
|
|
1182
|
+
const keyed = exportKeyedList(value, declaredClassName, options, context);
|
|
1183
|
+
if (keyed) return keyed;
|
|
1184
|
+
}
|
|
1185
|
+
return value.map(item => exportAdvancedValue(item, declaredClassName, options, context));
|
|
1186
|
+
}
|
|
1187
|
+
return exportCarbonValue(value);
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
function exportKeyedList(list, declaredClassName, options, context)
|
|
1191
|
+
{
|
|
1192
|
+
if (!list.length) return null;
|
|
1193
|
+
|
|
1194
|
+
const seen = new Set();
|
|
1195
|
+
for (const item of list)
|
|
1196
|
+
{
|
|
1197
|
+
if (!(item instanceof CjsModel)) return null;
|
|
1198
|
+
const name = item.name;
|
|
1199
|
+
if (typeof name !== "string" || name === "" || seen.has(name)) return null;
|
|
1200
|
+
seen.add(name);
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
const out = {};
|
|
1204
|
+
for (const item of list)
|
|
1205
|
+
{
|
|
1206
|
+
const exported = exportAdvancedValue(item, declaredClassName, options, context);
|
|
1207
|
+
if (exported && typeof exported === "object" && exported._ref === undefined)
|
|
1208
|
+
{
|
|
1209
|
+
delete exported.name;
|
|
1210
|
+
}
|
|
1211
|
+
out[item.name] = exported;
|
|
1212
|
+
}
|
|
1213
|
+
return out;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
export function importSourceValue(value, field = null, options = {})
|
|
1217
|
+
{
|
|
1218
|
+
if (value instanceof CjsModel) return value;
|
|
1219
|
+
|
|
1220
|
+
if (isReferenceValue(value))
|
|
1221
|
+
{
|
|
1222
|
+
const resolved = resolveIncomingReference(value, options);
|
|
1223
|
+
if (resolved instanceof CjsPendingReference)
|
|
1224
|
+
{
|
|
1225
|
+
throw new TypeError(`Forward { _ref: ${JSON.stringify(value._ref)} } cannot be deferred in this position.`);
|
|
1226
|
+
}
|
|
1227
|
+
return resolved;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
const schemaType = getSchemaType(options.ownerConstructor, field?.name);
|
|
1231
|
+
const declaredClassName = getSchemaClassName(schemaType, options);
|
|
1232
|
+
if (value && typeof value === "object" && !(value instanceof CjsModel) && !Array.isArray(value) && !ArrayBuffer.isView(value))
|
|
1233
|
+
{
|
|
1234
|
+
// A registered `_type` selects the concrete class in singular
|
|
1235
|
+
// schema-typed positions. Carbon contracts may be declared through
|
|
1236
|
+
// interface names with no runtime inheritance, so the declared name
|
|
1237
|
+
// is a fallback, not a constraint the concrete class must extend.
|
|
1238
|
+
const explicitClassName = isSingularSchemaKind(schemaType) && typeof value._type === "string"
|
|
1239
|
+
? getSchemaClassName(value._type, options)
|
|
1240
|
+
: null;
|
|
1241
|
+
const className = explicitClassName || declaredClassName;
|
|
1242
|
+
if (className)
|
|
1243
|
+
{
|
|
1244
|
+
return createModelValue(className, value, options);
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
if ((schemaType?.kind === "array" || schemaType?.kind === "list") && schemaType.itemType && Array.isArray(value))
|
|
1249
|
+
{
|
|
1250
|
+
const itemClassName = getSchemaClassName(schemaType.itemType, options);
|
|
1251
|
+
const result = [];
|
|
1252
|
+
for (let i = 0; i < value.length; i++)
|
|
1253
|
+
{
|
|
1254
|
+
const item = value[i];
|
|
1255
|
+
if (isReferenceValue(item))
|
|
1256
|
+
{
|
|
1257
|
+
result.push(importReferenceInto(item, options, result, i));
|
|
1258
|
+
continue;
|
|
1259
|
+
}
|
|
1260
|
+
if (!item || typeof item !== "object" || item instanceof CjsModel || ArrayBuffer.isView(item))
|
|
1261
|
+
{
|
|
1262
|
+
result.push(importSourceValue(item, null, options));
|
|
1263
|
+
continue;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
const explicitClassName = typeof item._type === "string"
|
|
1267
|
+
? getSchemaClassName(item._type, options)
|
|
1268
|
+
: null;
|
|
1269
|
+
if (explicitClassName)
|
|
1270
|
+
{
|
|
1271
|
+
result.push(createModelValue(explicitClassName, item, options));
|
|
1272
|
+
continue;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
result.push(itemClassName
|
|
1276
|
+
? createModelValue(itemClassName, item, options)
|
|
1277
|
+
: importSourceValue(item, null, options));
|
|
1278
|
+
}
|
|
1279
|
+
return result;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
// List fields also accept name-keyed object maps for unique-named items;
|
|
1283
|
+
// the map is a wholesale list replacement, mirroring array semantics.
|
|
1284
|
+
const effectiveType = field?.jsType || field?.type || schemaType;
|
|
1285
|
+
if ((effectiveType?.kind === "array" || effectiveType?.kind === "list")
|
|
1286
|
+
&& value && typeof value === "object" && !Array.isArray(value) && !ArrayBuffer.isView(value))
|
|
1287
|
+
{
|
|
1288
|
+
return importListMapValue(value, effectiveType, options);
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
if (field) return normalizeCarbonValue(value, field);
|
|
1292
|
+
if (ArrayBuffer.isView(value)) return normalizeCarbonValue(value, { jsType: { kind: "typedArray", js: value.constructor.name } });
|
|
1293
|
+
if (typeof value === "bigint") return value;
|
|
1294
|
+
if (Array.isArray(value))
|
|
1295
|
+
{
|
|
1296
|
+
const result = [];
|
|
1297
|
+
for (let i = 0; i < value.length; i++)
|
|
1298
|
+
{
|
|
1299
|
+
const item = value[i];
|
|
1300
|
+
result.push(isReferenceValue(item)
|
|
1301
|
+
? importReferenceInto(item, options, result, i)
|
|
1302
|
+
: importSourceValue(item, null, options));
|
|
1303
|
+
}
|
|
1304
|
+
return result;
|
|
1305
|
+
}
|
|
1306
|
+
if (value && typeof value === "object" && !(value instanceof CjsModel))
|
|
1307
|
+
{
|
|
1308
|
+
const result = {};
|
|
1309
|
+
for (const [key, item] of Object.entries(value))
|
|
1310
|
+
{
|
|
1311
|
+
result[key] = isReferenceValue(item)
|
|
1312
|
+
? importReferenceInto(item, options, result, key)
|
|
1313
|
+
: importSourceValue(item, null, options);
|
|
1314
|
+
}
|
|
1315
|
+
return result;
|
|
1316
|
+
}
|
|
1317
|
+
return value;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
function applyIncomingStructInPlace(current, incoming, field, options)
|
|
1321
|
+
{
|
|
1322
|
+
const schemaType = getSchemaType(options.ownerConstructor, field?.name) || field?.type || field?.jsType;
|
|
1323
|
+
if (schemaType?.kind !== "struct" || !(current instanceof CjsModel)) return null;
|
|
1324
|
+
if (incoming === null || incoming === undefined) return false;
|
|
1325
|
+
if (typeof incoming !== "object" || Array.isArray(incoming) || ArrayBuffer.isView(incoming))
|
|
1326
|
+
{
|
|
1327
|
+
throw new TypeError(`${field.name} requires an object value for registered struct ${schemaType.className || "unknown"}.`);
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
const values = incoming instanceof CjsModel ? incoming.GetValues() : incoming;
|
|
1331
|
+
const changed = current.SetValues(values, options);
|
|
1332
|
+
return changed instanceof Set ? changed.size > 0 : changed === true;
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
function importListMapValue(value, schemaType, options)
|
|
1336
|
+
{
|
|
1337
|
+
const itemClassName = schemaType.itemType ? getSchemaClassName(schemaType.itemType, options) : null;
|
|
1338
|
+
const result = [];
|
|
1339
|
+
for (const key of Object.keys(value))
|
|
1340
|
+
{
|
|
1341
|
+
const item = value[key];
|
|
1342
|
+
if (item === undefined || item === null) continue;
|
|
1343
|
+
|
|
1344
|
+
if (item instanceof CjsModel)
|
|
1345
|
+
{
|
|
1346
|
+
if (typeof item.name === "string" && item.name === "")
|
|
1347
|
+
{
|
|
1348
|
+
item.SetValues({ name: key });
|
|
1349
|
+
}
|
|
1350
|
+
result.push(item);
|
|
1351
|
+
continue;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
if (isReferenceValue(item))
|
|
1355
|
+
{
|
|
1356
|
+
// Shared items keep their own name; the map key is not restamped
|
|
1357
|
+
// onto an instance owned by another position in the graph.
|
|
1358
|
+
result.push(importReferenceInto(item, options, result, result.length));
|
|
1359
|
+
continue;
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
if (typeof item !== "object" || Array.isArray(item) || ArrayBuffer.isView(item))
|
|
1363
|
+
{
|
|
1364
|
+
throw new TypeError(`List field maps require object or model values; "${key}" cannot become a list item.`);
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
const explicitClassName = typeof item._type === "string"
|
|
1368
|
+
? getSchemaClassName(item._type, options)
|
|
1369
|
+
: null;
|
|
1370
|
+
const className = explicitClassName || itemClassName;
|
|
1371
|
+
if (!className)
|
|
1372
|
+
{
|
|
1373
|
+
throw new TypeError(`List field maps cannot resolve a model class for "${key}".`);
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
const values = item.name === undefined ? { ...item, name: key } : item;
|
|
1377
|
+
result.push(createModelValue(className, values, options));
|
|
1378
|
+
}
|
|
1379
|
+
return result;
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
function getSchemaType(Constructor, fieldName)
|
|
1383
|
+
{
|
|
1384
|
+
if (!Constructor || !fieldName) return null;
|
|
1385
|
+
return CjsSchema.getField(Constructor, fieldName)?.type || null;
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
function getSchemaClassName(schemaType, options = {})
|
|
1389
|
+
{
|
|
1390
|
+
if (!schemaType) return null;
|
|
1391
|
+
if (typeof schemaType === "string")
|
|
1392
|
+
{
|
|
1393
|
+
const Schema = options.registry || CjsModel.schema;
|
|
1394
|
+
return Schema.GetConstructor(schemaType) ? schemaType : null;
|
|
1395
|
+
}
|
|
1396
|
+
if (schemaType.kind === "model")
|
|
1397
|
+
{
|
|
1398
|
+
return schemaType.className || null;
|
|
1399
|
+
}
|
|
1400
|
+
if (schemaType.kind === "objectRef" || schemaType.kind === "struct")
|
|
1401
|
+
{
|
|
1402
|
+
const Schema = options.registry || CjsModel.schema;
|
|
1403
|
+
return schemaType.className && Schema.GetConstructor(schemaType.className)
|
|
1404
|
+
? schemaType.className
|
|
1405
|
+
: null;
|
|
1406
|
+
}
|
|
1407
|
+
return null;
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
function createModelValue(className, values, options)
|
|
1411
|
+
{
|
|
1412
|
+
const Schema = options.registry || CjsModel.schema;
|
|
1413
|
+
const Constructor = Schema.GetConstructor(className);
|
|
1414
|
+
if (!Constructor)
|
|
1415
|
+
{
|
|
1416
|
+
throw new TypeError(`No CjsModel class is registered for schema type ${className}.`);
|
|
1417
|
+
}
|
|
1418
|
+
if (Constructor !== CjsModel && !(Constructor.prototype instanceof CjsModel))
|
|
1419
|
+
{
|
|
1420
|
+
throw new TypeError(`Registered schema type ${className} is not a CjsModel.`);
|
|
1421
|
+
}
|
|
1422
|
+
if (typeof Constructor.from !== "function")
|
|
1423
|
+
{
|
|
1424
|
+
throw new TypeError(`Registered CjsModel ${className} does not provide from().`);
|
|
1425
|
+
}
|
|
1426
|
+
return Constructor.from(values, options);
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
// --- Import operation context: `_id`/`_ref` identity across one call tree ---
|
|
1430
|
+
|
|
1431
|
+
/** Represents one unresolved model reference during a single import operation. */
|
|
1432
|
+
class CjsPendingReference
|
|
1433
|
+
{
|
|
1434
|
+
|
|
1435
|
+
constructor(id, expectedClassName = null)
|
|
1436
|
+
{
|
|
1437
|
+
this.id = id;
|
|
1438
|
+
this.expectedClassName = expectedClassName;
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
function createImportContext()
|
|
1444
|
+
{
|
|
1445
|
+
const byId = new Map();
|
|
1446
|
+
const created = [];
|
|
1447
|
+
const pending = [];
|
|
1448
|
+
return {
|
|
1449
|
+
byId,
|
|
1450
|
+
registerCreated(instance)
|
|
1451
|
+
{
|
|
1452
|
+
created.push(instance);
|
|
1453
|
+
},
|
|
1454
|
+
register(id, instance)
|
|
1455
|
+
{
|
|
1456
|
+
const existing = byId.get(id);
|
|
1457
|
+
if (existing === instance) return;
|
|
1458
|
+
if (existing !== undefined)
|
|
1459
|
+
{
|
|
1460
|
+
throw new TypeError(`Duplicate _id ${JSON.stringify(id)} in imported values.`);
|
|
1461
|
+
}
|
|
1462
|
+
byId.set(id, instance);
|
|
1463
|
+
},
|
|
1464
|
+
defer(id, assign)
|
|
1465
|
+
{
|
|
1466
|
+
pending.push({ id, assign });
|
|
1467
|
+
},
|
|
1468
|
+
finalize()
|
|
1469
|
+
{
|
|
1470
|
+
const unresolved = new Set();
|
|
1471
|
+
for (const entry of pending)
|
|
1472
|
+
{
|
|
1473
|
+
const instance = byId.get(entry.id);
|
|
1474
|
+
if (instance === undefined)
|
|
1475
|
+
{
|
|
1476
|
+
unresolved.add(entry.id);
|
|
1477
|
+
continue;
|
|
1478
|
+
}
|
|
1479
|
+
entry.assign(instance);
|
|
1480
|
+
}
|
|
1481
|
+
pending.length = 0;
|
|
1482
|
+
if (unresolved.size)
|
|
1483
|
+
{
|
|
1484
|
+
throw new TypeError(`Unresolved _ref ids: ${Array.from(unresolved, id => JSON.stringify(id)).join(", ")}. Every { _ref } must match a { _id } in the same import operation.`);
|
|
1485
|
+
}
|
|
1486
|
+
},
|
|
1487
|
+
initializeCreated(options)
|
|
1488
|
+
{
|
|
1489
|
+
const visited = new Set();
|
|
1490
|
+
|
|
1491
|
+
for (let index = created.length - 1; index >= 0; index--)
|
|
1492
|
+
{
|
|
1493
|
+
initializeOwnedGraph(created[index], { ...options, visited });
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
created.length = 0;
|
|
1497
|
+
}
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
function isReferenceValue(value)
|
|
1502
|
+
{
|
|
1503
|
+
return !!value && typeof value === "object" && !Array.isArray(value)
|
|
1504
|
+
&& !ArrayBuffer.isView(value) && !(value instanceof CjsModel)
|
|
1505
|
+
&& value._ref !== undefined;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
// Resolves a `{ _ref }` immediately when the target is registered, or returns
|
|
1509
|
+
// a CjsPendingReference for the finalize pass (forward references). Resolved
|
|
1510
|
+
// references assign like direct instances: no declared-type constraint, since
|
|
1511
|
+
// Carbon contracts may be declared through interface names that have no
|
|
1512
|
+
// runtime inheritance relationship with the concrete class.
|
|
1513
|
+
function resolveIncomingReference(value, options)
|
|
1514
|
+
{
|
|
1515
|
+
const id = value._ref;
|
|
1516
|
+
const context = options.importContext;
|
|
1517
|
+
if (!context)
|
|
1518
|
+
{
|
|
1519
|
+
throw new TypeError(`Cannot resolve { _ref: ${JSON.stringify(id)} } outside an import operation; import the graph through SetValues/from so identity is tracked.`);
|
|
1520
|
+
}
|
|
1521
|
+
const resolved = context.byId.get(id);
|
|
1522
|
+
if (resolved === undefined) return new CjsPendingReference(id);
|
|
1523
|
+
return resolved;
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
// Resolves a reference into a container slot, deferring forward references to
|
|
1527
|
+
// the owning operation's finalize pass. Deferred slots hold null until then.
|
|
1528
|
+
function importReferenceInto(value, options, target, key)
|
|
1529
|
+
{
|
|
1530
|
+
const resolved = resolveIncomingReference(value, options);
|
|
1531
|
+
if (resolved instanceof CjsPendingReference)
|
|
1532
|
+
{
|
|
1533
|
+
options.importContext.defer(resolved.id, instance =>
|
|
1534
|
+
{
|
|
1535
|
+
target[key] = instance;
|
|
1536
|
+
});
|
|
1537
|
+
return null;
|
|
1538
|
+
}
|
|
1539
|
+
return resolved;
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
// Applies a `{ _ref }` incoming value to a model field, returning whether the
|
|
1543
|
+
// field changed. Forward references keep the current value until finalize.
|
|
1544
|
+
function applyIncomingReference(out, field, incoming, options)
|
|
1545
|
+
{
|
|
1546
|
+
const fieldName = field.name;
|
|
1547
|
+
const resolved = resolveIncomingReference(incoming, options);
|
|
1548
|
+
|
|
1549
|
+
if (resolved instanceof CjsPendingReference)
|
|
1550
|
+
{
|
|
1551
|
+
options.importContext.defer(resolved.id, instance =>
|
|
1552
|
+
{
|
|
1553
|
+
out[fieldName] = instance;
|
|
1554
|
+
});
|
|
1555
|
+
return true;
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
if (field.io?.always !== true && Object.is(out[fieldName], resolved)) return false;
|
|
1559
|
+
out[fieldName] = resolved;
|
|
1560
|
+
return true;
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
function resolveRegisteredModelClass(typeName, options = {})
|
|
1564
|
+
{
|
|
1565
|
+
const Schema = options.registry || CjsModel.schema;
|
|
1566
|
+
const Constructor = Schema.GetConstructor(typeName);
|
|
1567
|
+
if (!Constructor)
|
|
1568
|
+
{
|
|
1569
|
+
throw new TypeError(`No CjsModel class is registered for _type "${typeName}".`);
|
|
1570
|
+
}
|
|
1571
|
+
return Constructor;
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
function isSingularSchemaKind(schemaType)
|
|
1575
|
+
{
|
|
1576
|
+
if (!schemaType) return false;
|
|
1577
|
+
if (typeof schemaType === "string") return true;
|
|
1578
|
+
return schemaType.kind !== "array" && schemaType.kind !== "list"
|
|
1579
|
+
&& schemaType.kind !== "map" && schemaType.kind !== "set";
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
function assertTargetTypeMatches(out, typeName, options = {})
|
|
1583
|
+
{
|
|
1584
|
+
const Constructor = resolveRegisteredModelClass(typeName, options);
|
|
1585
|
+
if (!(out instanceof Constructor))
|
|
1586
|
+
{
|
|
1587
|
+
throw new TypeError(`Values with _type "${typeName}" cannot apply to a ${CjsSchema.getClassName(out.constructor) || "model"} target.`);
|
|
1588
|
+
}
|
|
1589
|
+
}
|