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.
- package/lib/functional/$dictionary.js +3 -2
- package/lib/functional/$dictionary.js.map +1 -1
- package/package.json +1 -1
- package/src/Primitive.ts +123 -123
- package/src/factories/MetadataFactory.ts +62 -62
- package/src/factories/internal/metadata/emplace_metadata_object.ts +143 -143
- package/src/factories/internal/metadata/iterate_metadata_tuple.ts +48 -48
- package/src/functional/$dictionary.ts +7 -2
- package/src/metadata/IMetadata.ts +26 -26
- package/src/metadata/Metadata.ts +539 -539
- package/src/programmers/CheckerProgrammer.ts +901 -901
- package/src/programmers/internal/application_object.ts +155 -155
- package/src/programmers/internal/application_tuple.ts +31 -31
- package/src/schemas/IJsonSchema.ts +130 -130
package/src/metadata/Metadata.ts
CHANGED
|
@@ -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
|
+
}
|