typia 3.8.3 → 3.8.4

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.
@@ -1,539 +1,539 @@
1
- import { Atomic } from "../typings/Atomic";
2
- import { ClassProperties } from "../typings/ClassProperties";
3
-
4
- import { ArrayUtil } from "../utils/ArrayUtil";
5
-
6
- import { IMetadata } from "./IMetadata";
7
- import { IMetadataObject } from "./IMetadataObject";
8
- import { MetadataConstant } from "./MetadataConstant";
9
- import { MetadataObject } from "./MetadataObject";
10
- import { MetadataProperty } from "./MetadataProperty";
11
-
12
- export class Metadata {
13
- public readonly any: boolean;
14
- public readonly required: boolean;
15
- public readonly optional: boolean;
16
- public readonly nullable: boolean;
17
- public readonly functional: boolean;
18
-
19
- public readonly resolved: Metadata | null;
20
- public readonly atomics: Atomic.Literal[];
21
- public readonly constants: MetadataConstant[];
22
- public readonly templates: Metadata[][];
23
-
24
- public readonly rest: Metadata | null;
25
- public readonly arrays: Metadata[];
26
- public readonly tuples: Metadata[][];
27
- public readonly objects: MetadataObject[];
28
-
29
- public readonly natives: string[];
30
- public readonly sets: Metadata[];
31
- public readonly maps: Metadata.Entry[];
32
-
33
- /**
34
- * @internal
35
- */
36
- private name_: string | undefined = undefined;
37
-
38
- /**
39
- * @internal
40
- */
41
- private parent_resolved_: boolean = false;
42
-
43
- /**
44
- * @internal
45
- */
46
- public union_index?: number;
47
-
48
- /* -----------------------------------------------------------
49
- CONSTRUCTORS
50
- ----------------------------------------------------------- */
51
- /**
52
- * @hidden
53
- */
54
- private constructor(props: ClassProperties<Metadata>) {
55
- this.any = props.any;
56
- this.required = props.required;
57
- this.optional = props.optional;
58
- this.nullable = props.nullable;
59
- this.functional = props.functional;
60
-
61
- this.resolved = props.resolved;
62
- this.atomics = props.atomics;
63
- this.constants = props.constants;
64
- this.templates = props.templates;
65
-
66
- this.rest = props.rest;
67
- this.arrays = props.arrays;
68
- this.tuples = props.tuples;
69
- this.objects = props.objects;
70
-
71
- this.natives = props.natives;
72
- this.sets = props.sets;
73
- this.maps = props.maps;
74
- }
75
-
76
- /**
77
- * @internal
78
- */
79
- public static create(props: ClassProperties<Metadata>): Metadata {
80
- return new Metadata(props);
81
- }
82
-
83
- /**
84
- * @internal
85
- */
86
- public static initialize(parentResolved: boolean = false): Metadata {
87
- const meta: Metadata = this.create({
88
- any: false,
89
- nullable: false,
90
- required: true,
91
- optional: false,
92
- functional: false,
93
-
94
- resolved: null,
95
- constants: [],
96
- atomics: [],
97
- templates: [],
98
- arrays: [],
99
- tuples: [],
100
- objects: [],
101
-
102
- rest: null,
103
- natives: [],
104
- sets: [],
105
- maps: [],
106
- });
107
- meta.parent_resolved_ = parentResolved;
108
- return meta;
109
- }
110
-
111
- public toJSON(): IMetadata {
112
- return {
113
- any: this.any,
114
- required: this.required,
115
- optional: this.optional,
116
- nullable: this.nullable,
117
- functional: this.functional,
118
-
119
- atomics: this.atomics.slice(),
120
- constants: JSON.parse(JSON.stringify(this.constants)),
121
- templates: this.templates.map((tpl) =>
122
- tpl.map((meta) => meta.toJSON()),
123
- ),
124
- resolved: this.resolved ? this.resolved.toJSON() : null,
125
-
126
- rest: this.rest ? this.rest.toJSON() : null,
127
- arrays: this.arrays.map((meta) => meta.toJSON()),
128
- tuples: this.tuples.map((meta) =>
129
- meta.map((meta) => meta.toJSON()),
130
- ),
131
- objects: this.objects.map((obj) => obj.name),
132
-
133
- natives: this.natives.slice(),
134
- sets: this.sets.map((meta) => meta.toJSON()),
135
- maps: this.maps.map((entry) => ({
136
- key: entry.key.toJSON(),
137
- value: entry.value.toJSON(),
138
- })),
139
- };
140
- }
141
-
142
- public static from(meta: IMetadata, objects: IMetadataObject[]): Metadata {
143
- const dict: Map<string, MetadataObject> = new Map();
144
- for (const obj of objects)
145
- dict.set(obj.name, MetadataObject._From_without_properties(obj));
146
-
147
- for (const obj of objects) {
148
- const initialized = dict.get(obj.name)!;
149
- initialized.properties.push(
150
- ...obj.properties.map((prop) =>
151
- MetadataProperty._From(prop, dict),
152
- ),
153
- );
154
- }
155
- return this._From(meta, dict);
156
- }
157
-
158
- /**
159
- * @internal
160
- */
161
- public static _From(
162
- meta: IMetadata,
163
- objects: Map<string, MetadataObject>,
164
- ): Metadata {
165
- return this.create({
166
- any: meta.any,
167
- required: meta.required,
168
- optional: meta.optional,
169
- nullable: meta.nullable,
170
- functional: meta.functional,
171
-
172
- constants: JSON.parse(JSON.stringify(meta.constants)),
173
- atomics: meta.atomics.slice(),
174
- templates: meta.templates.map((tpl) =>
175
- tpl.map((meta) => this._From(meta, objects)),
176
- ),
177
- resolved: meta.resolved ? this._From(meta.resolved, objects) : null,
178
-
179
- rest: meta.rest ? this._From(meta.rest, objects) : null,
180
- arrays: meta.arrays.map((meta) => this._From(meta, objects)),
181
- tuples: meta.tuples.map((tuple) =>
182
- tuple.map((meta) => this._From(meta, objects)),
183
- ),
184
- objects: meta.objects.map((name) => {
185
- const found = objects.get(name);
186
- if (found === undefined)
187
- throw new Error(
188
- `Error on Metadata.from(): failed to find object "${name}".`,
189
- );
190
- return found;
191
- }),
192
-
193
- natives: meta.natives.slice(),
194
- sets: meta.sets.map((meta) => this._From(meta, objects)),
195
- maps: meta.maps.map((entry) => ({
196
- key: this._From(entry.key, objects),
197
- value: this._From(entry.value, objects),
198
- })),
199
- });
200
- }
201
-
202
- /* -----------------------------------------------------------
203
- ACCESSORS
204
- ----------------------------------------------------------- */
205
- public getName(): string {
206
- this.name_ ||= getName(this);
207
- return this.name_;
208
- }
209
-
210
- public empty(): boolean {
211
- return this.bucket() === 0 || this.size() === 0;
212
- }
213
- public size(): number {
214
- return (
215
- (this.resolved ? 1 : 0) +
216
- (this.functional ? 1 : 0) +
217
- this.templates.length +
218
- this.atomics.length +
219
- this.constants
220
- .map((c) => c.values.length)
221
- .reduce((x, y) => x + y, 0) +
222
- (this.rest ? this.rest.size() : 0) +
223
- this.arrays.length +
224
- this.tuples.length +
225
- this.objects.length +
226
- this.natives.length +
227
- this.sets.length +
228
- this.maps.length
229
- );
230
- }
231
- public bucket(): number {
232
- return (
233
- (this.resolved ? 1 : 0) +
234
- (this.functional ? 1 : 0) +
235
- (this.templates.length ? 1 : 0) +
236
- (this.atomics.length ? 1 : 0) +
237
- (this.constants.length ? 1 : 0) +
238
- (this.rest ? this.rest.size() : 0) +
239
- (this.arrays.length ? 1 : 0) +
240
- (this.tuples.length ? 1 : 0) +
241
- (this.objects.length ? 1 : 0) +
242
- (this.natives.length ? 1 : 0) +
243
- (this.sets.length ? 1 : 0) +
244
- (this.maps.length ? 1 : 0)
245
- );
246
- }
247
- public isConstant(): boolean {
248
- return this.bucket() === (this.constants.length ? 1 : 0);
249
- }
250
-
251
- /**
252
- * @internal
253
- */
254
- public isUnionBucket(): boolean {
255
- const size: number = this.bucket();
256
- const emended: number = this.constants.length ? size - 1 : size;
257
- return emended > 1;
258
- }
259
-
260
- /**
261
- * @internal
262
- */
263
- public getSoleLiteral(): string | null {
264
- if (
265
- this.size() === 1 &&
266
- this.constants.length === 1 &&
267
- this.constants[0]!.type === "string" &&
268
- this.constants[0]!.values.length === 1
269
- )
270
- return this.constants[0]!.values[0] as string;
271
- else return null;
272
- }
273
-
274
- /**
275
- * @internal
276
- */
277
- public isSoleLiteral(): boolean {
278
- return this.getSoleLiteral() !== null;
279
- }
280
-
281
- /**
282
- * @internal
283
- */
284
- public isParentResolved(): boolean {
285
- return this.parent_resolved_;
286
- }
287
- }
288
- export namespace Metadata {
289
- export const intersects = (
290
- x: Metadata,
291
- y: Metadata,
292
- deep: boolean,
293
- ): boolean => {
294
- // CHECK ANY & OPTIONAL
295
- if (x.any || y.any) return true;
296
- if (x.required === false && false === y.required) return true;
297
- if (x.nullable === true && true === y.nullable) return true;
298
-
299
- //----
300
- // INSTANCES
301
- //----
302
- // ARRAYS AND OBJECTS
303
- if (deep === true) {
304
- for (const xa of x.arrays)
305
- for (const ya of y.arrays)
306
- if (intersects(xa, ya, deep)) {
307
- return true;
308
- }
309
- for (const xo of x.objects)
310
- for (const yo of y.objects)
311
- if (MetadataObject.intersects(xo, yo)) {
312
- return true;
313
- }
314
- } else {
315
- if (x.arrays.length && y.arrays.length) return true;
316
- if (x.objects.length && y.objects.length) return true;
317
- }
318
-
319
- // TUPLES
320
- for (const xt of x.tuples)
321
- for (const yt of y.tuples)
322
- if (xt.length === 0 || yt.length === 0)
323
- return xt.length === 0 && yt.length === 0;
324
- else if (
325
- xt
326
- .slice(0, Math.min(xt.length, yt.length))
327
- .some((xv, i) => intersects(xv, yt[i]!, deep))
328
- )
329
- return true;
330
-
331
- //----
332
- // VALUES
333
- //----
334
- // ATOMICS
335
- for (const atomic of x.atomics)
336
- if (y.atomics.includes(atomic)) return true;
337
-
338
- // CONSTANTS
339
- for (const constant of x.constants) {
340
- const opposite: MetadataConstant | undefined = y.constants.find(
341
- (elem) => elem.type === constant.type,
342
- );
343
- if (opposite === undefined) continue;
344
-
345
- const values: Set<any> = new Set([
346
- ...constant.values,
347
- ...opposite.values,
348
- ]);
349
- if (values.size !== constant.values.length + opposite.values.length)
350
- return true;
351
- }
352
-
353
- // FUNCTIONAL
354
- if (x.functional === true && y.functional === true) return true;
355
-
356
- return false;
357
- };
358
-
359
- export const covers = (x: Metadata, y: Metadata): boolean => {
360
- // CHECK ANY
361
- if (x.any) return true;
362
- else if (y.any) return false;
363
-
364
- //----
365
- // INSTANCES
366
- //----
367
- // ARRAYS
368
- for (const ya of y.arrays)
369
- if (x.arrays.some((xa) => covers(xa, ya) === true) === false)
370
- return false;
371
-
372
- // OBJECTS
373
- for (const yo of y.objects)
374
- if (x.objects.some((xo) => MetadataObject.covers(xo, yo)) === false)
375
- return false;
376
-
377
- // TUPLES
378
- for (const yt of y.tuples)
379
- if (
380
- yt.length !== 0 &&
381
- x.tuples.some(
382
- (xt) =>
383
- xt.length >= yt.length &&
384
- xt
385
- .slice(yt.length)
386
- .every((xv, i) => covers(xv, yt[i]!)),
387
- ) === false
388
- )
389
- return false;
390
-
391
- // NATIVES
392
-
393
- // SETS
394
- for (const ys of y.sets)
395
- if (x.sets.some((xs) => covers(xs, ys)) === false) return false;
396
-
397
- //----
398
- // VALUES
399
- //----
400
- // ATOMICS
401
- if (y.atomics.some((atomic) => x.atomics.includes(atomic) === false))
402
- return false;
403
-
404
- // CONSTANTS
405
- for (const yc of y.constants) {
406
- const xc: MetadataConstant | undefined = x.constants.find(
407
- (elem) => elem.type === yc.type,
408
- );
409
- if (xc === undefined) return false;
410
- else if (
411
- (yc.values as number[]).some(
412
- (yv) => xc.values.includes(yv as never) === false,
413
- )
414
- )
415
- return false;
416
- }
417
-
418
- // FUNCTIONAL
419
- if (x.functional === false && y.functional) return false;
420
-
421
- // SUCCESS
422
- return true;
423
- };
424
-
425
- export const merge = (x: Metadata, y: Metadata): Metadata => {
426
- const output: Metadata = Metadata.create({
427
- any: x.any || y.any,
428
- nullable: x.nullable || y.nullable,
429
- required: x.required && y.required,
430
- optional: x.optional || y.optional,
431
- functional: x.functional || y.functional,
432
-
433
- resolved:
434
- x.resolved !== null && y.resolved !== null
435
- ? merge(x.resolved, y.resolved)
436
- : x.resolved || y.resolved,
437
- atomics: [...new Set([...x.atomics, ...y.atomics])],
438
- constants: [...x.constants],
439
- templates: x.templates.slice(),
440
-
441
- rest:
442
- x.rest !== null && y.rest !== null
443
- ? merge(x.rest, y.rest)
444
- : x.rest ?? y.rest,
445
- arrays: x.arrays.slice(),
446
- tuples: x.tuples.slice(),
447
- objects: x.objects.slice(),
448
-
449
- natives: [...new Set([...x.natives, ...y.natives])],
450
- sets: x.sets.slice(),
451
- maps: x.maps.slice(),
452
- });
453
- for (const constant of y.constants) {
454
- const target: MetadataConstant = ArrayUtil.take(
455
- output.constants,
456
- (elem) => elem.type === constant.type,
457
- () => ({
458
- type: constant.type,
459
- values: [],
460
- }),
461
- );
462
- for (const value of constant.values)
463
- ArrayUtil.add(target.values, value);
464
- }
465
- for (const array of y.arrays)
466
- ArrayUtil.set(output.arrays, array, (elem) => elem.getName());
467
- for (const obj of y.objects)
468
- ArrayUtil.set(output.objects, obj, (elem) => elem.name);
469
-
470
- if (x.rest !== null)
471
- ArrayUtil.set(output.arrays, x.rest, (elem) => elem.getName());
472
- if (y.rest !== null)
473
- ArrayUtil.set(output.arrays, y.rest, (elem) => elem.getName());
474
-
475
- return output;
476
- };
477
- }
478
-
479
- const getName = (metadata: Metadata): string => {
480
- if (metadata.any === true) return "any";
481
-
482
- const elements: string[] = [];
483
-
484
- // OPTIONAL
485
- if (metadata.nullable === true) elements.push("null");
486
- if (metadata.required === false) elements.push("undefined");
487
-
488
- // ATOMIC
489
- for (const type of metadata.atomics) {
490
- elements.push(type);
491
- }
492
- for (const constant of metadata.constants)
493
- for (const value of constant.values)
494
- elements.push(JSON.stringify(value));
495
- for (const template of metadata.templates)
496
- elements.push(
497
- "`" +
498
- template
499
- .map((child) =>
500
- child.isConstant() && child.size() === 1
501
- ? child.constants[0]!.values[0]!
502
- : `$\{${child.getName()}\}`,
503
- )
504
- .join("")
505
- .split("`")
506
- .join("\\`") +
507
- "`",
508
- );
509
-
510
- // NATIVES
511
- for (const native of metadata.natives) elements.push(native);
512
- for (const set of metadata.sets) elements.push(`Set<${set.getName()}>`);
513
- for (const map of metadata.maps)
514
- elements.push(`Map<${map.key.getName()}, ${map.value.getName()}>`);
515
-
516
- // ARRAY
517
- if (metadata.rest !== null) elements.push(`...${metadata.rest.getName()}`);
518
- for (const tuple of metadata.tuples)
519
- elements.push(`[${tuple.map((elem) => elem.getName()).join(", ")}]`);
520
- for (const array of metadata.arrays)
521
- elements.push(`Array<${array.getName()}>`);
522
-
523
- // OBJECT
524
- for (const object of metadata.objects) elements.push(object.name);
525
- if (metadata.resolved !== null) elements.push(metadata.resolved.getName());
526
-
527
- // RETURNS
528
- if (elements.length === 0) return "unknown";
529
- else if (elements.length === 1) return elements[0]!;
530
-
531
- elements.sort();
532
- return `(${elements.join(" | ")})`;
533
- };
534
- export namespace Metadata {
535
- export interface Entry {
536
- key: Metadata;
537
- value: Metadata;
538
- }
539
- }
1
+ import { Atomic } from "../typings/Atomic";
2
+ import { ClassProperties } from "../typings/ClassProperties";
3
+
4
+ import { ArrayUtil } from "../utils/ArrayUtil";
5
+
6
+ import { IMetadata } from "./IMetadata";
7
+ import { IMetadataObject } from "./IMetadataObject";
8
+ import { MetadataConstant } from "./MetadataConstant";
9
+ import { MetadataObject } from "./MetadataObject";
10
+ import { MetadataProperty } from "./MetadataProperty";
11
+
12
+ export class Metadata {
13
+ public readonly any: boolean;
14
+ public readonly required: boolean;
15
+ public readonly optional: boolean;
16
+ public readonly nullable: boolean;
17
+ public readonly functional: boolean;
18
+
19
+ public readonly resolved: Metadata | null;
20
+ public readonly atomics: Atomic.Literal[];
21
+ public readonly constants: MetadataConstant[];
22
+ public readonly templates: Metadata[][];
23
+
24
+ public readonly rest: Metadata | null;
25
+ public readonly arrays: Metadata[];
26
+ public readonly tuples: Metadata[][];
27
+ public readonly objects: MetadataObject[];
28
+
29
+ public readonly natives: string[];
30
+ public readonly sets: Metadata[];
31
+ public readonly maps: Metadata.Entry[];
32
+
33
+ /**
34
+ * @internal
35
+ */
36
+ private name_: string | undefined = undefined;
37
+
38
+ /**
39
+ * @internal
40
+ */
41
+ private parent_resolved_: boolean = false;
42
+
43
+ /**
44
+ * @internal
45
+ */
46
+ public union_index?: number;
47
+
48
+ /* -----------------------------------------------------------
49
+ CONSTRUCTORS
50
+ ----------------------------------------------------------- */
51
+ /**
52
+ * @hidden
53
+ */
54
+ private constructor(props: ClassProperties<Metadata>) {
55
+ this.any = props.any;
56
+ this.required = props.required;
57
+ this.optional = props.optional;
58
+ this.nullable = props.nullable;
59
+ this.functional = props.functional;
60
+
61
+ this.resolved = props.resolved;
62
+ this.atomics = props.atomics;
63
+ this.constants = props.constants;
64
+ this.templates = props.templates;
65
+
66
+ this.rest = props.rest;
67
+ this.arrays = props.arrays;
68
+ this.tuples = props.tuples;
69
+ this.objects = props.objects;
70
+
71
+ this.natives = props.natives;
72
+ this.sets = props.sets;
73
+ this.maps = props.maps;
74
+ }
75
+
76
+ /**
77
+ * @internal
78
+ */
79
+ public static create(props: ClassProperties<Metadata>): Metadata {
80
+ return new Metadata(props);
81
+ }
82
+
83
+ /**
84
+ * @internal
85
+ */
86
+ public static initialize(parentResolved: boolean = false): Metadata {
87
+ const meta: Metadata = this.create({
88
+ any: false,
89
+ nullable: false,
90
+ required: true,
91
+ optional: false,
92
+ functional: false,
93
+
94
+ resolved: null,
95
+ constants: [],
96
+ atomics: [],
97
+ templates: [],
98
+ arrays: [],
99
+ tuples: [],
100
+ objects: [],
101
+
102
+ rest: null,
103
+ natives: [],
104
+ sets: [],
105
+ maps: [],
106
+ });
107
+ meta.parent_resolved_ = parentResolved;
108
+ return meta;
109
+ }
110
+
111
+ public toJSON(): IMetadata {
112
+ return {
113
+ any: this.any,
114
+ required: this.required,
115
+ optional: this.optional,
116
+ nullable: this.nullable,
117
+ functional: this.functional,
118
+
119
+ atomics: this.atomics.slice(),
120
+ constants: JSON.parse(JSON.stringify(this.constants)),
121
+ templates: this.templates.map((tpl) =>
122
+ tpl.map((meta) => meta.toJSON()),
123
+ ),
124
+ resolved: this.resolved ? this.resolved.toJSON() : null,
125
+
126
+ rest: this.rest ? this.rest.toJSON() : null,
127
+ arrays: this.arrays.map((meta) => meta.toJSON()),
128
+ tuples: this.tuples.map((meta) =>
129
+ meta.map((meta) => meta.toJSON()),
130
+ ),
131
+ objects: this.objects.map((obj) => obj.name),
132
+
133
+ natives: this.natives.slice(),
134
+ sets: this.sets.map((meta) => meta.toJSON()),
135
+ maps: this.maps.map((entry) => ({
136
+ key: entry.key.toJSON(),
137
+ value: entry.value.toJSON(),
138
+ })),
139
+ };
140
+ }
141
+
142
+ public static from(meta: IMetadata, objects: IMetadataObject[]): Metadata {
143
+ const dict: Map<string, MetadataObject> = new Map();
144
+ for (const obj of objects)
145
+ dict.set(obj.name, MetadataObject._From_without_properties(obj));
146
+
147
+ for (const obj of objects) {
148
+ const initialized = dict.get(obj.name)!;
149
+ initialized.properties.push(
150
+ ...obj.properties.map((prop) =>
151
+ MetadataProperty._From(prop, dict),
152
+ ),
153
+ );
154
+ }
155
+ return this._From(meta, dict);
156
+ }
157
+
158
+ /**
159
+ * @internal
160
+ */
161
+ public static _From(
162
+ meta: IMetadata,
163
+ objects: Map<string, MetadataObject>,
164
+ ): Metadata {
165
+ return this.create({
166
+ any: meta.any,
167
+ required: meta.required,
168
+ optional: meta.optional,
169
+ nullable: meta.nullable,
170
+ functional: meta.functional,
171
+
172
+ constants: JSON.parse(JSON.stringify(meta.constants)),
173
+ atomics: meta.atomics.slice(),
174
+ templates: meta.templates.map((tpl) =>
175
+ tpl.map((meta) => this._From(meta, objects)),
176
+ ),
177
+ resolved: meta.resolved ? this._From(meta.resolved, objects) : null,
178
+
179
+ rest: meta.rest ? this._From(meta.rest, objects) : null,
180
+ arrays: meta.arrays.map((meta) => this._From(meta, objects)),
181
+ tuples: meta.tuples.map((tuple) =>
182
+ tuple.map((meta) => this._From(meta, objects)),
183
+ ),
184
+ objects: meta.objects.map((name) => {
185
+ const found = objects.get(name);
186
+ if (found === undefined)
187
+ throw new Error(
188
+ `Error on Metadata.from(): failed to find object "${name}".`,
189
+ );
190
+ return found;
191
+ }),
192
+
193
+ natives: meta.natives.slice(),
194
+ sets: meta.sets.map((meta) => this._From(meta, objects)),
195
+ maps: meta.maps.map((entry) => ({
196
+ key: this._From(entry.key, objects),
197
+ value: this._From(entry.value, objects),
198
+ })),
199
+ });
200
+ }
201
+
202
+ /* -----------------------------------------------------------
203
+ ACCESSORS
204
+ ----------------------------------------------------------- */
205
+ public getName(): string {
206
+ this.name_ ||= getName(this);
207
+ return this.name_;
208
+ }
209
+
210
+ public empty(): boolean {
211
+ return this.bucket() === 0 || this.size() === 0;
212
+ }
213
+ public size(): number {
214
+ return (
215
+ (this.resolved ? 1 : 0) +
216
+ (this.functional ? 1 : 0) +
217
+ this.templates.length +
218
+ this.atomics.length +
219
+ this.constants
220
+ .map((c) => c.values.length)
221
+ .reduce((x, y) => x + y, 0) +
222
+ (this.rest ? this.rest.size() : 0) +
223
+ this.arrays.length +
224
+ this.tuples.length +
225
+ this.objects.length +
226
+ this.natives.length +
227
+ this.sets.length +
228
+ this.maps.length
229
+ );
230
+ }
231
+ public bucket(): number {
232
+ return (
233
+ (this.resolved ? 1 : 0) +
234
+ (this.functional ? 1 : 0) +
235
+ (this.templates.length ? 1 : 0) +
236
+ (this.atomics.length ? 1 : 0) +
237
+ (this.constants.length ? 1 : 0) +
238
+ (this.rest ? this.rest.size() : 0) +
239
+ (this.arrays.length ? 1 : 0) +
240
+ (this.tuples.length ? 1 : 0) +
241
+ (this.objects.length ? 1 : 0) +
242
+ (this.natives.length ? 1 : 0) +
243
+ (this.sets.length ? 1 : 0) +
244
+ (this.maps.length ? 1 : 0)
245
+ );
246
+ }
247
+ public isConstant(): boolean {
248
+ return this.bucket() === (this.constants.length ? 1 : 0);
249
+ }
250
+
251
+ /**
252
+ * @internal
253
+ */
254
+ public isUnionBucket(): boolean {
255
+ const size: number = this.bucket();
256
+ const emended: number = this.constants.length ? size - 1 : size;
257
+ return emended > 1;
258
+ }
259
+
260
+ /**
261
+ * @internal
262
+ */
263
+ public getSoleLiteral(): string | null {
264
+ if (
265
+ this.size() === 1 &&
266
+ this.constants.length === 1 &&
267
+ this.constants[0]!.type === "string" &&
268
+ this.constants[0]!.values.length === 1
269
+ )
270
+ return this.constants[0]!.values[0] as string;
271
+ else return null;
272
+ }
273
+
274
+ /**
275
+ * @internal
276
+ */
277
+ public isSoleLiteral(): boolean {
278
+ return this.getSoleLiteral() !== null;
279
+ }
280
+
281
+ /**
282
+ * @internal
283
+ */
284
+ public isParentResolved(): boolean {
285
+ return this.parent_resolved_;
286
+ }
287
+ }
288
+ export namespace Metadata {
289
+ export const intersects = (
290
+ x: Metadata,
291
+ y: Metadata,
292
+ deep: boolean,
293
+ ): boolean => {
294
+ // CHECK ANY & OPTIONAL
295
+ if (x.any || y.any) return true;
296
+ if (x.required === false && false === y.required) return true;
297
+ if (x.nullable === true && true === y.nullable) return true;
298
+
299
+ //----
300
+ // INSTANCES
301
+ //----
302
+ // ARRAYS AND OBJECTS
303
+ if (deep === true) {
304
+ for (const xa of x.arrays)
305
+ for (const ya of y.arrays)
306
+ if (intersects(xa, ya, deep)) {
307
+ return true;
308
+ }
309
+ for (const xo of x.objects)
310
+ for (const yo of y.objects)
311
+ if (MetadataObject.intersects(xo, yo)) {
312
+ return true;
313
+ }
314
+ } else {
315
+ if (x.arrays.length && y.arrays.length) return true;
316
+ if (x.objects.length && y.objects.length) return true;
317
+ }
318
+
319
+ // TUPLES
320
+ for (const xt of x.tuples)
321
+ for (const yt of y.tuples)
322
+ if (xt.length === 0 || yt.length === 0)
323
+ return xt.length === 0 && yt.length === 0;
324
+ else if (
325
+ xt
326
+ .slice(0, Math.min(xt.length, yt.length))
327
+ .some((xv, i) => intersects(xv, yt[i]!, deep))
328
+ )
329
+ return true;
330
+
331
+ //----
332
+ // VALUES
333
+ //----
334
+ // ATOMICS
335
+ for (const atomic of x.atomics)
336
+ if (y.atomics.includes(atomic)) return true;
337
+
338
+ // CONSTANTS
339
+ for (const constant of x.constants) {
340
+ const opposite: MetadataConstant | undefined = y.constants.find(
341
+ (elem) => elem.type === constant.type,
342
+ );
343
+ if (opposite === undefined) continue;
344
+
345
+ const values: Set<any> = new Set([
346
+ ...constant.values,
347
+ ...opposite.values,
348
+ ]);
349
+ if (values.size !== constant.values.length + opposite.values.length)
350
+ return true;
351
+ }
352
+
353
+ // FUNCTIONAL
354
+ if (x.functional === true && y.functional === true) return true;
355
+
356
+ return false;
357
+ };
358
+
359
+ export const covers = (x: Metadata, y: Metadata): boolean => {
360
+ // CHECK ANY
361
+ if (x.any) return true;
362
+ else if (y.any) return false;
363
+
364
+ //----
365
+ // INSTANCES
366
+ //----
367
+ // ARRAYS
368
+ for (const ya of y.arrays)
369
+ if (x.arrays.some((xa) => covers(xa, ya) === true) === false)
370
+ return false;
371
+
372
+ // OBJECTS
373
+ for (const yo of y.objects)
374
+ if (x.objects.some((xo) => MetadataObject.covers(xo, yo)) === false)
375
+ return false;
376
+
377
+ // TUPLES
378
+ for (const yt of y.tuples)
379
+ if (
380
+ yt.length !== 0 &&
381
+ x.tuples.some(
382
+ (xt) =>
383
+ xt.length >= yt.length &&
384
+ xt
385
+ .slice(yt.length)
386
+ .every((xv, i) => covers(xv, yt[i]!)),
387
+ ) === false
388
+ )
389
+ return false;
390
+
391
+ // NATIVES
392
+
393
+ // SETS
394
+ for (const ys of y.sets)
395
+ if (x.sets.some((xs) => covers(xs, ys)) === false) return false;
396
+
397
+ //----
398
+ // VALUES
399
+ //----
400
+ // ATOMICS
401
+ if (y.atomics.some((atomic) => x.atomics.includes(atomic) === false))
402
+ return false;
403
+
404
+ // CONSTANTS
405
+ for (const yc of y.constants) {
406
+ const xc: MetadataConstant | undefined = x.constants.find(
407
+ (elem) => elem.type === yc.type,
408
+ );
409
+ if (xc === undefined) return false;
410
+ else if (
411
+ (yc.values as number[]).some(
412
+ (yv) => xc.values.includes(yv as never) === false,
413
+ )
414
+ )
415
+ return false;
416
+ }
417
+
418
+ // FUNCTIONAL
419
+ if (x.functional === false && y.functional) return false;
420
+
421
+ // SUCCESS
422
+ return true;
423
+ };
424
+
425
+ export const merge = (x: Metadata, y: Metadata): Metadata => {
426
+ const output: Metadata = Metadata.create({
427
+ any: x.any || y.any,
428
+ nullable: x.nullable || y.nullable,
429
+ required: x.required && y.required,
430
+ optional: x.optional || y.optional,
431
+ functional: x.functional || y.functional,
432
+
433
+ resolved:
434
+ x.resolved !== null && y.resolved !== null
435
+ ? merge(x.resolved, y.resolved)
436
+ : x.resolved || y.resolved,
437
+ atomics: [...new Set([...x.atomics, ...y.atomics])],
438
+ constants: [...x.constants],
439
+ templates: x.templates.slice(),
440
+
441
+ rest:
442
+ x.rest !== null && y.rest !== null
443
+ ? merge(x.rest, y.rest)
444
+ : x.rest ?? y.rest,
445
+ arrays: x.arrays.slice(),
446
+ tuples: x.tuples.slice(),
447
+ objects: x.objects.slice(),
448
+
449
+ natives: [...new Set([...x.natives, ...y.natives])],
450
+ sets: x.sets.slice(),
451
+ maps: x.maps.slice(),
452
+ });
453
+ for (const constant of y.constants) {
454
+ const target: MetadataConstant = ArrayUtil.take(
455
+ output.constants,
456
+ (elem) => elem.type === constant.type,
457
+ () => ({
458
+ type: constant.type,
459
+ values: [],
460
+ }),
461
+ );
462
+ for (const value of constant.values)
463
+ ArrayUtil.add(target.values, value);
464
+ }
465
+ for (const array of y.arrays)
466
+ ArrayUtil.set(output.arrays, array, (elem) => elem.getName());
467
+ for (const obj of y.objects)
468
+ ArrayUtil.set(output.objects, obj, (elem) => elem.name);
469
+
470
+ if (x.rest !== null)
471
+ ArrayUtil.set(output.arrays, x.rest, (elem) => elem.getName());
472
+ if (y.rest !== null)
473
+ ArrayUtil.set(output.arrays, y.rest, (elem) => elem.getName());
474
+
475
+ return output;
476
+ };
477
+ }
478
+
479
+ const getName = (metadata: Metadata): string => {
480
+ if (metadata.any === true) return "any";
481
+
482
+ const elements: string[] = [];
483
+
484
+ // OPTIONAL
485
+ if (metadata.nullable === true) elements.push("null");
486
+ if (metadata.required === false) elements.push("undefined");
487
+
488
+ // ATOMIC
489
+ for (const type of metadata.atomics) {
490
+ elements.push(type);
491
+ }
492
+ for (const constant of metadata.constants)
493
+ for (const value of constant.values)
494
+ elements.push(JSON.stringify(value));
495
+ for (const template of metadata.templates)
496
+ elements.push(
497
+ "`" +
498
+ template
499
+ .map((child) =>
500
+ child.isConstant() && child.size() === 1
501
+ ? child.constants[0]!.values[0]!
502
+ : `$\{${child.getName()}\}`,
503
+ )
504
+ .join("")
505
+ .split("`")
506
+ .join("\\`") +
507
+ "`",
508
+ );
509
+
510
+ // NATIVES
511
+ for (const native of metadata.natives) elements.push(native);
512
+ for (const set of metadata.sets) elements.push(`Set<${set.getName()}>`);
513
+ for (const map of metadata.maps)
514
+ elements.push(`Map<${map.key.getName()}, ${map.value.getName()}>`);
515
+
516
+ // ARRAY
517
+ if (metadata.rest !== null) elements.push(`...${metadata.rest.getName()}`);
518
+ for (const tuple of metadata.tuples)
519
+ elements.push(`[${tuple.map((elem) => elem.getName()).join(", ")}]`);
520
+ for (const array of metadata.arrays)
521
+ elements.push(`Array<${array.getName()}>`);
522
+
523
+ // OBJECT
524
+ for (const object of metadata.objects) elements.push(object.name);
525
+ if (metadata.resolved !== null) elements.push(metadata.resolved.getName());
526
+
527
+ // RETURNS
528
+ if (elements.length === 0) return "unknown";
529
+ else if (elements.length === 1) return elements[0]!;
530
+
531
+ elements.sort();
532
+ return `(${elements.join(" | ")})`;
533
+ };
534
+ export namespace Metadata {
535
+ export interface Entry {
536
+ key: Metadata;
537
+ value: Metadata;
538
+ }
539
+ }