@varavel/vdl-plugin-sdk 0.0.0
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 -0
- package/dist/ir.cjs +420 -0
- package/dist/ir.cjs.map +1 -0
- package/dist/ir.d.cts +213 -0
- package/dist/ir.d.cts.map +1 -0
- package/dist/ir.d.ts +213 -0
- package/dist/ir.d.ts.map +1 -0
- package/dist/ir.js +388 -0
- package/dist/ir.js.map +1 -0
- package/package.json +55 -0
- package/src/ir.ts +978 -0
package/src/ir.ts
ADDED
|
@@ -0,0 +1,978 @@
|
|
|
1
|
+
// Code generated by VDL v0.4.0-alpha.5. DO NOT EDIT.
|
|
2
|
+
// If you edit this file, it will be overwritten the next time it is generated.
|
|
3
|
+
//
|
|
4
|
+
// For more information about VDL, visit https://vdl.varavel.com
|
|
5
|
+
|
|
6
|
+
/* eslint-disable */
|
|
7
|
+
/* tslint:disable */
|
|
8
|
+
// biome-ignore-all lint: Generated by VDL
|
|
9
|
+
|
|
10
|
+
// -----------------------------------------------------------------------------
|
|
11
|
+
// Enumerations
|
|
12
|
+
// -----------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Underlying storage kind used by an enum
|
|
16
|
+
*/
|
|
17
|
+
export type EnumValueType = "string" | "int";
|
|
18
|
+
|
|
19
|
+
export const EnumValueTypeList: EnumValueType[] = ["string", "int"];
|
|
20
|
+
|
|
21
|
+
export function isEnumValueType(value: unknown): value is EnumValueType {
|
|
22
|
+
return EnumValueTypeList.includes(value as EnumValueType);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Kind discriminator for LiteralValue.
|
|
27
|
+
*
|
|
28
|
+
* LiteralValue is used for fully resolved literal data in:
|
|
29
|
+
*
|
|
30
|
+
* - constant values
|
|
31
|
+
* - annotation arguments
|
|
32
|
+
*/
|
|
33
|
+
export type LiteralKind =
|
|
34
|
+
| "string"
|
|
35
|
+
| "int"
|
|
36
|
+
| "float"
|
|
37
|
+
| "bool"
|
|
38
|
+
| "object"
|
|
39
|
+
| "array";
|
|
40
|
+
|
|
41
|
+
export const LiteralKindList: LiteralKind[] = [
|
|
42
|
+
"string",
|
|
43
|
+
"int",
|
|
44
|
+
"float",
|
|
45
|
+
"bool",
|
|
46
|
+
"object",
|
|
47
|
+
"array",
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
export function isLiteralKind(value: unknown): value is LiteralKind {
|
|
51
|
+
return LiteralKindList.includes(value as LiteralKind);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Primitive scalar type names
|
|
56
|
+
*/
|
|
57
|
+
export type PrimitiveType = "string" | "int" | "float" | "bool" | "datetime";
|
|
58
|
+
|
|
59
|
+
export const PrimitiveTypeList: PrimitiveType[] = [
|
|
60
|
+
"string",
|
|
61
|
+
"int",
|
|
62
|
+
"float",
|
|
63
|
+
"bool",
|
|
64
|
+
"datetime",
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
export function isPrimitiveType(value: unknown): value is PrimitiveType {
|
|
68
|
+
return PrimitiveTypeList.includes(value as PrimitiveType);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Kind discriminator for TypeRef
|
|
73
|
+
*/
|
|
74
|
+
export type TypeKind =
|
|
75
|
+
| "primitive"
|
|
76
|
+
| "type"
|
|
77
|
+
| "enum"
|
|
78
|
+
| "array"
|
|
79
|
+
| "map"
|
|
80
|
+
| "object";
|
|
81
|
+
|
|
82
|
+
export const TypeKindList: TypeKind[] = [
|
|
83
|
+
"primitive",
|
|
84
|
+
"type",
|
|
85
|
+
"enum",
|
|
86
|
+
"array",
|
|
87
|
+
"map",
|
|
88
|
+
"object",
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
export function isTypeKind(value: unknown): value is TypeKind {
|
|
92
|
+
return TypeKindList.includes(value as TypeKind);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// -----------------------------------------------------------------------------
|
|
96
|
+
// Domain Types
|
|
97
|
+
// -----------------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Annotation Annotation metadata preserved in IR.
|
|
101
|
+
*
|
|
102
|
+
* `name` is the annotation identifier without the `@` prefix.
|
|
103
|
+
* `argument`, when present, is fully resolved as a LiteralValue.
|
|
104
|
+
*/
|
|
105
|
+
export type Annotation = {
|
|
106
|
+
position: Position;
|
|
107
|
+
name: string;
|
|
108
|
+
argument?: LiteralValue;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export function hydrateAnnotation(input: Annotation): Annotation {
|
|
112
|
+
const hydratedPosition = hydratePosition(input.position);
|
|
113
|
+
const hydratedName = input.name;
|
|
114
|
+
const hydratedArgument = input.argument
|
|
115
|
+
? hydrateLiteralValue(input.argument)
|
|
116
|
+
: input.argument;
|
|
117
|
+
return {
|
|
118
|
+
position: hydratedPosition,
|
|
119
|
+
name: hydratedName,
|
|
120
|
+
argument: hydratedArgument,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function validateAnnotation(
|
|
125
|
+
input: unknown,
|
|
126
|
+
path = "Annotation",
|
|
127
|
+
): string | null {
|
|
128
|
+
if (input === null || input === undefined || typeof input !== "object") {
|
|
129
|
+
return `${path}: expected object, got ${typeof input}`;
|
|
130
|
+
}
|
|
131
|
+
const obj = input as Record<string, unknown>;
|
|
132
|
+
|
|
133
|
+
if (obj.position === undefined || obj.position === null) {
|
|
134
|
+
return `${path}.position: required field is missing`;
|
|
135
|
+
}
|
|
136
|
+
{
|
|
137
|
+
const err = validatePosition(obj.position, `${path}.position`);
|
|
138
|
+
if (err !== null) return err;
|
|
139
|
+
}
|
|
140
|
+
if (obj.argument !== undefined && obj.argument !== null) {
|
|
141
|
+
{
|
|
142
|
+
const err = validateLiteralValue(obj.argument, `${path}.argument`);
|
|
143
|
+
if (err !== null) return err;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* ConstantDef Fully resolved constant definition.
|
|
151
|
+
*
|
|
152
|
+
* `typeRef` is explicit or inferred by analysis.
|
|
153
|
+
* `value` contains the fully resolved literal payload.
|
|
154
|
+
*/
|
|
155
|
+
export type ConstantDef = {
|
|
156
|
+
position: Position;
|
|
157
|
+
name: string;
|
|
158
|
+
doc?: string;
|
|
159
|
+
annotations: Annotation[];
|
|
160
|
+
typeRef: TypeRef;
|
|
161
|
+
value: LiteralValue;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export function hydrateConstantDef(input: ConstantDef): ConstantDef {
|
|
165
|
+
const hydratedPosition = hydratePosition(input.position);
|
|
166
|
+
const hydratedName = input.name;
|
|
167
|
+
const hydratedDoc = input.doc ? input.doc : input.doc;
|
|
168
|
+
const hydratedAnnotations = input.annotations.map((el) =>
|
|
169
|
+
hydrateAnnotation(el),
|
|
170
|
+
);
|
|
171
|
+
const hydratedTypeRef = hydrateTypeRef(input.typeRef);
|
|
172
|
+
const hydratedValue = hydrateLiteralValue(input.value);
|
|
173
|
+
return {
|
|
174
|
+
position: hydratedPosition,
|
|
175
|
+
name: hydratedName,
|
|
176
|
+
doc: hydratedDoc,
|
|
177
|
+
annotations: hydratedAnnotations,
|
|
178
|
+
typeRef: hydratedTypeRef,
|
|
179
|
+
value: hydratedValue,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function validateConstantDef(
|
|
184
|
+
input: unknown,
|
|
185
|
+
path = "ConstantDef",
|
|
186
|
+
): string | null {
|
|
187
|
+
if (input === null || input === undefined || typeof input !== "object") {
|
|
188
|
+
return `${path}: expected object, got ${typeof input}`;
|
|
189
|
+
}
|
|
190
|
+
const obj = input as Record<string, unknown>;
|
|
191
|
+
|
|
192
|
+
if (obj.position === undefined || obj.position === null) {
|
|
193
|
+
return `${path}.position: required field is missing`;
|
|
194
|
+
}
|
|
195
|
+
{
|
|
196
|
+
const err = validatePosition(obj.position, `${path}.position`);
|
|
197
|
+
if (err !== null) return err;
|
|
198
|
+
}
|
|
199
|
+
if (obj.annotations === undefined || obj.annotations === null) {
|
|
200
|
+
return `${path}.annotations: required field is missing`;
|
|
201
|
+
}
|
|
202
|
+
{
|
|
203
|
+
if (!Array.isArray(obj.annotations)) {
|
|
204
|
+
return `${path}.annotations: expected array, got ${typeof obj.annotations}`;
|
|
205
|
+
}
|
|
206
|
+
for (let i = 0; i < obj.annotations.length; i++) {
|
|
207
|
+
{
|
|
208
|
+
const err = validateAnnotation(
|
|
209
|
+
obj.annotations[i],
|
|
210
|
+
`${path}.annotations[${i}]`,
|
|
211
|
+
);
|
|
212
|
+
if (err !== null) return err;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (obj.typeRef === undefined || obj.typeRef === null) {
|
|
217
|
+
return `${path}.typeRef: required field is missing`;
|
|
218
|
+
}
|
|
219
|
+
{
|
|
220
|
+
const err = validateTypeRef(obj.typeRef, `${path}.typeRef`);
|
|
221
|
+
if (err !== null) return err;
|
|
222
|
+
}
|
|
223
|
+
if (obj.value === undefined || obj.value === null) {
|
|
224
|
+
return `${path}.value: required field is missing`;
|
|
225
|
+
}
|
|
226
|
+
{
|
|
227
|
+
const err = validateLiteralValue(obj.value, `${path}.value`);
|
|
228
|
+
if (err !== null) return err;
|
|
229
|
+
}
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* EnumDef Flattened enum definition.
|
|
235
|
+
*
|
|
236
|
+
* All enum spreads are already expanded into `members`.
|
|
237
|
+
*/
|
|
238
|
+
export type EnumDef = {
|
|
239
|
+
position: Position;
|
|
240
|
+
name: string;
|
|
241
|
+
doc?: string;
|
|
242
|
+
annotations: Annotation[];
|
|
243
|
+
enumType: EnumValueType;
|
|
244
|
+
members: EnumMember[];
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
export function hydrateEnumDef(input: EnumDef): EnumDef {
|
|
248
|
+
const hydratedPosition = hydratePosition(input.position);
|
|
249
|
+
const hydratedName = input.name;
|
|
250
|
+
const hydratedDoc = input.doc ? input.doc : input.doc;
|
|
251
|
+
const hydratedAnnotations = input.annotations.map((el) =>
|
|
252
|
+
hydrateAnnotation(el),
|
|
253
|
+
);
|
|
254
|
+
const hydratedEnumType = input.enumType;
|
|
255
|
+
const hydratedMembers = input.members.map((el) => hydrateEnumMember(el));
|
|
256
|
+
return {
|
|
257
|
+
position: hydratedPosition,
|
|
258
|
+
name: hydratedName,
|
|
259
|
+
doc: hydratedDoc,
|
|
260
|
+
annotations: hydratedAnnotations,
|
|
261
|
+
enumType: hydratedEnumType,
|
|
262
|
+
members: hydratedMembers,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export function validateEnumDef(
|
|
267
|
+
input: unknown,
|
|
268
|
+
path = "EnumDef",
|
|
269
|
+
): string | null {
|
|
270
|
+
if (input === null || input === undefined || typeof input !== "object") {
|
|
271
|
+
return `${path}: expected object, got ${typeof input}`;
|
|
272
|
+
}
|
|
273
|
+
const obj = input as Record<string, unknown>;
|
|
274
|
+
|
|
275
|
+
if (obj.position === undefined || obj.position === null) {
|
|
276
|
+
return `${path}.position: required field is missing`;
|
|
277
|
+
}
|
|
278
|
+
{
|
|
279
|
+
const err = validatePosition(obj.position, `${path}.position`);
|
|
280
|
+
if (err !== null) return err;
|
|
281
|
+
}
|
|
282
|
+
if (obj.annotations === undefined || obj.annotations === null) {
|
|
283
|
+
return `${path}.annotations: required field is missing`;
|
|
284
|
+
}
|
|
285
|
+
{
|
|
286
|
+
if (!Array.isArray(obj.annotations)) {
|
|
287
|
+
return `${path}.annotations: expected array, got ${typeof obj.annotations}`;
|
|
288
|
+
}
|
|
289
|
+
for (let i = 0; i < obj.annotations.length; i++) {
|
|
290
|
+
{
|
|
291
|
+
const err = validateAnnotation(
|
|
292
|
+
obj.annotations[i],
|
|
293
|
+
`${path}.annotations[${i}]`,
|
|
294
|
+
);
|
|
295
|
+
if (err !== null) return err;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (obj.enumType === undefined || obj.enumType === null) {
|
|
300
|
+
return `${path}.enumType: required field is missing`;
|
|
301
|
+
}
|
|
302
|
+
{
|
|
303
|
+
if (!isEnumValueType(obj.enumType)) {
|
|
304
|
+
return `${path}.enumType: invalid enum value '${obj.enumType}' for EnumValueType`;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (obj.members === undefined || obj.members === null) {
|
|
308
|
+
return `${path}.members: required field is missing`;
|
|
309
|
+
}
|
|
310
|
+
{
|
|
311
|
+
if (!Array.isArray(obj.members)) {
|
|
312
|
+
return `${path}.members: expected array, got ${typeof obj.members}`;
|
|
313
|
+
}
|
|
314
|
+
for (let i = 0; i < obj.members.length; i++) {
|
|
315
|
+
{
|
|
316
|
+
const err = validateEnumMember(obj.members[i], `${path}.members[${i}]`);
|
|
317
|
+
if (err !== null) return err;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* EnumMember Enum member definition
|
|
326
|
+
*/
|
|
327
|
+
export type EnumMember = {
|
|
328
|
+
position: Position;
|
|
329
|
+
name: string;
|
|
330
|
+
value: LiteralValue;
|
|
331
|
+
doc?: string;
|
|
332
|
+
annotations: Annotation[];
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
export function hydrateEnumMember(input: EnumMember): EnumMember {
|
|
336
|
+
const hydratedPosition = hydratePosition(input.position);
|
|
337
|
+
const hydratedName = input.name;
|
|
338
|
+
const hydratedValue = hydrateLiteralValue(input.value);
|
|
339
|
+
const hydratedDoc = input.doc ? input.doc : input.doc;
|
|
340
|
+
const hydratedAnnotations = input.annotations.map((el) =>
|
|
341
|
+
hydrateAnnotation(el),
|
|
342
|
+
);
|
|
343
|
+
return {
|
|
344
|
+
position: hydratedPosition,
|
|
345
|
+
name: hydratedName,
|
|
346
|
+
value: hydratedValue,
|
|
347
|
+
doc: hydratedDoc,
|
|
348
|
+
annotations: hydratedAnnotations,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export function validateEnumMember(
|
|
353
|
+
input: unknown,
|
|
354
|
+
path = "EnumMember",
|
|
355
|
+
): string | null {
|
|
356
|
+
if (input === null || input === undefined || typeof input !== "object") {
|
|
357
|
+
return `${path}: expected object, got ${typeof input}`;
|
|
358
|
+
}
|
|
359
|
+
const obj = input as Record<string, unknown>;
|
|
360
|
+
|
|
361
|
+
if (obj.position === undefined || obj.position === null) {
|
|
362
|
+
return `${path}.position: required field is missing`;
|
|
363
|
+
}
|
|
364
|
+
{
|
|
365
|
+
const err = validatePosition(obj.position, `${path}.position`);
|
|
366
|
+
if (err !== null) return err;
|
|
367
|
+
}
|
|
368
|
+
if (obj.value === undefined || obj.value === null) {
|
|
369
|
+
return `${path}.value: required field is missing`;
|
|
370
|
+
}
|
|
371
|
+
{
|
|
372
|
+
const err = validateLiteralValue(obj.value, `${path}.value`);
|
|
373
|
+
if (err !== null) return err;
|
|
374
|
+
}
|
|
375
|
+
if (obj.annotations === undefined || obj.annotations === null) {
|
|
376
|
+
return `${path}.annotations: required field is missing`;
|
|
377
|
+
}
|
|
378
|
+
{
|
|
379
|
+
if (!Array.isArray(obj.annotations)) {
|
|
380
|
+
return `${path}.annotations: expected array, got ${typeof obj.annotations}`;
|
|
381
|
+
}
|
|
382
|
+
for (let i = 0; i < obj.annotations.length; i++) {
|
|
383
|
+
{
|
|
384
|
+
const err = validateAnnotation(
|
|
385
|
+
obj.annotations[i],
|
|
386
|
+
`${path}.annotations[${i}]`,
|
|
387
|
+
);
|
|
388
|
+
if (err !== null) return err;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Field Flattened object/type field definition
|
|
397
|
+
*/
|
|
398
|
+
export type Field = {
|
|
399
|
+
position: Position;
|
|
400
|
+
name: string;
|
|
401
|
+
doc?: string;
|
|
402
|
+
optional: boolean;
|
|
403
|
+
annotations: Annotation[];
|
|
404
|
+
typeRef: TypeRef;
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
export function hydrateField(input: Field): Field {
|
|
408
|
+
const hydratedPosition = hydratePosition(input.position);
|
|
409
|
+
const hydratedName = input.name;
|
|
410
|
+
const hydratedDoc = input.doc ? input.doc : input.doc;
|
|
411
|
+
const hydratedOptional = input.optional;
|
|
412
|
+
const hydratedAnnotations = input.annotations.map((el) =>
|
|
413
|
+
hydrateAnnotation(el),
|
|
414
|
+
);
|
|
415
|
+
const hydratedTypeRef = hydrateTypeRef(input.typeRef);
|
|
416
|
+
return {
|
|
417
|
+
position: hydratedPosition,
|
|
418
|
+
name: hydratedName,
|
|
419
|
+
doc: hydratedDoc,
|
|
420
|
+
optional: hydratedOptional,
|
|
421
|
+
annotations: hydratedAnnotations,
|
|
422
|
+
typeRef: hydratedTypeRef,
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
export function validateField(input: unknown, path = "Field"): string | null {
|
|
427
|
+
if (input === null || input === undefined || typeof input !== "object") {
|
|
428
|
+
return `${path}: expected object, got ${typeof input}`;
|
|
429
|
+
}
|
|
430
|
+
const obj = input as Record<string, unknown>;
|
|
431
|
+
|
|
432
|
+
if (obj.position === undefined || obj.position === null) {
|
|
433
|
+
return `${path}.position: required field is missing`;
|
|
434
|
+
}
|
|
435
|
+
{
|
|
436
|
+
const err = validatePosition(obj.position, `${path}.position`);
|
|
437
|
+
if (err !== null) return err;
|
|
438
|
+
}
|
|
439
|
+
if (obj.annotations === undefined || obj.annotations === null) {
|
|
440
|
+
return `${path}.annotations: required field is missing`;
|
|
441
|
+
}
|
|
442
|
+
{
|
|
443
|
+
if (!Array.isArray(obj.annotations)) {
|
|
444
|
+
return `${path}.annotations: expected array, got ${typeof obj.annotations}`;
|
|
445
|
+
}
|
|
446
|
+
for (let i = 0; i < obj.annotations.length; i++) {
|
|
447
|
+
{
|
|
448
|
+
const err = validateAnnotation(
|
|
449
|
+
obj.annotations[i],
|
|
450
|
+
`${path}.annotations[${i}]`,
|
|
451
|
+
);
|
|
452
|
+
if (err !== null) return err;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (obj.typeRef === undefined || obj.typeRef === null) {
|
|
457
|
+
return `${path}.typeRef: required field is missing`;
|
|
458
|
+
}
|
|
459
|
+
{
|
|
460
|
+
const err = validateTypeRef(obj.typeRef, `${path}.typeRef`);
|
|
461
|
+
if (err !== null) return err;
|
|
462
|
+
}
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* IrSchema IrSchema is the generator-facing representation of a VDL program.
|
|
468
|
+
*
|
|
469
|
+
* This model is intentionally "flat" and "resolved":
|
|
470
|
+
*
|
|
471
|
+
* - spreads are already expanded
|
|
472
|
+
* - references are already resolved
|
|
473
|
+
* - collections are in deterministic order
|
|
474
|
+
*
|
|
475
|
+
* A code generator should be able to consume IrSchema directly, without needing
|
|
476
|
+
* to re-run parser or semantic-analysis logic.
|
|
477
|
+
*/
|
|
478
|
+
export type IrSchema = {
|
|
479
|
+
entryPoint: string;
|
|
480
|
+
constants: ConstantDef[];
|
|
481
|
+
enums: EnumDef[];
|
|
482
|
+
types: TypeDef[];
|
|
483
|
+
docs: TopLevelDoc[];
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
export function hydrateIrSchema(input: IrSchema): IrSchema {
|
|
487
|
+
const hydratedEntryPoint = input.entryPoint;
|
|
488
|
+
const hydratedConstants = input.constants.map((el) => hydrateConstantDef(el));
|
|
489
|
+
const hydratedEnums = input.enums.map((el) => hydrateEnumDef(el));
|
|
490
|
+
const hydratedTypes = input.types.map((el) => hydrateTypeDef(el));
|
|
491
|
+
const hydratedDocs = input.docs.map((el) => hydrateTopLevelDoc(el));
|
|
492
|
+
return {
|
|
493
|
+
entryPoint: hydratedEntryPoint,
|
|
494
|
+
constants: hydratedConstants,
|
|
495
|
+
enums: hydratedEnums,
|
|
496
|
+
types: hydratedTypes,
|
|
497
|
+
docs: hydratedDocs,
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
export function validateIrSchema(
|
|
502
|
+
input: unknown,
|
|
503
|
+
path = "IrSchema",
|
|
504
|
+
): string | null {
|
|
505
|
+
if (input === null || input === undefined || typeof input !== "object") {
|
|
506
|
+
return `${path}: expected object, got ${typeof input}`;
|
|
507
|
+
}
|
|
508
|
+
const obj = input as Record<string, unknown>;
|
|
509
|
+
|
|
510
|
+
if (obj.constants === undefined || obj.constants === null) {
|
|
511
|
+
return `${path}.constants: required field is missing`;
|
|
512
|
+
}
|
|
513
|
+
{
|
|
514
|
+
if (!Array.isArray(obj.constants)) {
|
|
515
|
+
return `${path}.constants: expected array, got ${typeof obj.constants}`;
|
|
516
|
+
}
|
|
517
|
+
for (let i = 0; i < obj.constants.length; i++) {
|
|
518
|
+
{
|
|
519
|
+
const err = validateConstantDef(
|
|
520
|
+
obj.constants[i],
|
|
521
|
+
`${path}.constants[${i}]`,
|
|
522
|
+
);
|
|
523
|
+
if (err !== null) return err;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
if (obj.enums === undefined || obj.enums === null) {
|
|
528
|
+
return `${path}.enums: required field is missing`;
|
|
529
|
+
}
|
|
530
|
+
{
|
|
531
|
+
if (!Array.isArray(obj.enums)) {
|
|
532
|
+
return `${path}.enums: expected array, got ${typeof obj.enums}`;
|
|
533
|
+
}
|
|
534
|
+
for (let i = 0; i < obj.enums.length; i++) {
|
|
535
|
+
{
|
|
536
|
+
const err = validateEnumDef(obj.enums[i], `${path}.enums[${i}]`);
|
|
537
|
+
if (err !== null) return err;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
if (obj.types === undefined || obj.types === null) {
|
|
542
|
+
return `${path}.types: required field is missing`;
|
|
543
|
+
}
|
|
544
|
+
{
|
|
545
|
+
if (!Array.isArray(obj.types)) {
|
|
546
|
+
return `${path}.types: expected array, got ${typeof obj.types}`;
|
|
547
|
+
}
|
|
548
|
+
for (let i = 0; i < obj.types.length; i++) {
|
|
549
|
+
{
|
|
550
|
+
const err = validateTypeDef(obj.types[i], `${path}.types[${i}]`);
|
|
551
|
+
if (err !== null) return err;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
if (obj.docs === undefined || obj.docs === null) {
|
|
556
|
+
return `${path}.docs: required field is missing`;
|
|
557
|
+
}
|
|
558
|
+
{
|
|
559
|
+
if (!Array.isArray(obj.docs)) {
|
|
560
|
+
return `${path}.docs: expected array, got ${typeof obj.docs}`;
|
|
561
|
+
}
|
|
562
|
+
for (let i = 0; i < obj.docs.length; i++) {
|
|
563
|
+
{
|
|
564
|
+
const err = validateTopLevelDoc(obj.docs[i], `${path}.docs[${i}]`);
|
|
565
|
+
if (err !== null) return err;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
return null;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* LiteralValue Fully resolved literal value.
|
|
574
|
+
*
|
|
575
|
+
* The selected payload is determined by `kind`:
|
|
576
|
+
*
|
|
577
|
+
* - `string` -> `stringValue`
|
|
578
|
+
* - `int` -> `intValue`
|
|
579
|
+
* - `float` -> `floatValue`
|
|
580
|
+
* - `bool` -> `boolValue`
|
|
581
|
+
* - `object` -> `objectEntries`
|
|
582
|
+
* - `array` -> `arrayItems`
|
|
583
|
+
*/
|
|
584
|
+
export type LiteralValue = {
|
|
585
|
+
position: Position;
|
|
586
|
+
kind: LiteralKind;
|
|
587
|
+
stringValue?: string;
|
|
588
|
+
intValue?: number;
|
|
589
|
+
floatValue?: number;
|
|
590
|
+
boolValue?: boolean;
|
|
591
|
+
objectEntries?: ObjectEntry[];
|
|
592
|
+
arrayItems?: LiteralValue[];
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
export function hydrateLiteralValue(input: LiteralValue): LiteralValue {
|
|
596
|
+
const hydratedPosition = hydratePosition(input.position);
|
|
597
|
+
const hydratedKind = input.kind;
|
|
598
|
+
const hydratedStringValue = input.stringValue
|
|
599
|
+
? input.stringValue
|
|
600
|
+
: input.stringValue;
|
|
601
|
+
const hydratedIntValue = input.intValue ? input.intValue : input.intValue;
|
|
602
|
+
const hydratedFloatValue = input.floatValue
|
|
603
|
+
? input.floatValue
|
|
604
|
+
: input.floatValue;
|
|
605
|
+
const hydratedBoolValue = input.boolValue ? input.boolValue : input.boolValue;
|
|
606
|
+
const hydratedObjectEntries = input.objectEntries
|
|
607
|
+
? input.objectEntries.map((el) => hydrateObjectEntry(el))
|
|
608
|
+
: input.objectEntries;
|
|
609
|
+
const hydratedArrayItems = input.arrayItems
|
|
610
|
+
? input.arrayItems.map((el) => hydrateLiteralValue(el))
|
|
611
|
+
: input.arrayItems;
|
|
612
|
+
return {
|
|
613
|
+
position: hydratedPosition,
|
|
614
|
+
kind: hydratedKind,
|
|
615
|
+
stringValue: hydratedStringValue,
|
|
616
|
+
intValue: hydratedIntValue,
|
|
617
|
+
floatValue: hydratedFloatValue,
|
|
618
|
+
boolValue: hydratedBoolValue,
|
|
619
|
+
objectEntries: hydratedObjectEntries,
|
|
620
|
+
arrayItems: hydratedArrayItems,
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
export function validateLiteralValue(
|
|
625
|
+
input: unknown,
|
|
626
|
+
path = "LiteralValue",
|
|
627
|
+
): string | null {
|
|
628
|
+
if (input === null || input === undefined || typeof input !== "object") {
|
|
629
|
+
return `${path}: expected object, got ${typeof input}`;
|
|
630
|
+
}
|
|
631
|
+
const obj = input as Record<string, unknown>;
|
|
632
|
+
|
|
633
|
+
if (obj.position === undefined || obj.position === null) {
|
|
634
|
+
return `${path}.position: required field is missing`;
|
|
635
|
+
}
|
|
636
|
+
{
|
|
637
|
+
const err = validatePosition(obj.position, `${path}.position`);
|
|
638
|
+
if (err !== null) return err;
|
|
639
|
+
}
|
|
640
|
+
if (obj.kind === undefined || obj.kind === null) {
|
|
641
|
+
return `${path}.kind: required field is missing`;
|
|
642
|
+
}
|
|
643
|
+
{
|
|
644
|
+
if (!isLiteralKind(obj.kind)) {
|
|
645
|
+
return `${path}.kind: invalid enum value '${obj.kind}' for LiteralKind`;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
if (obj.objectEntries !== undefined && obj.objectEntries !== null) {
|
|
649
|
+
{
|
|
650
|
+
if (!Array.isArray(obj.objectEntries)) {
|
|
651
|
+
return `${path}.objectEntries: expected array, got ${typeof obj.objectEntries}`;
|
|
652
|
+
}
|
|
653
|
+
for (let i = 0; i < obj.objectEntries.length; i++) {
|
|
654
|
+
{
|
|
655
|
+
const err = validateObjectEntry(
|
|
656
|
+
obj.objectEntries[i],
|
|
657
|
+
`${path}.objectEntries[${i}]`,
|
|
658
|
+
);
|
|
659
|
+
if (err !== null) return err;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
if (obj.arrayItems !== undefined && obj.arrayItems !== null) {
|
|
665
|
+
{
|
|
666
|
+
if (!Array.isArray(obj.arrayItems)) {
|
|
667
|
+
return `${path}.arrayItems: expected array, got ${typeof obj.arrayItems}`;
|
|
668
|
+
}
|
|
669
|
+
for (let i = 0; i < obj.arrayItems.length; i++) {
|
|
670
|
+
{
|
|
671
|
+
const err = validateLiteralValue(
|
|
672
|
+
obj.arrayItems[i],
|
|
673
|
+
`${path}.arrayItems[${i}]`,
|
|
674
|
+
);
|
|
675
|
+
if (err !== null) return err;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
return null;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* ObjectEntry Key/value pair inside an object LiteralValue payload
|
|
685
|
+
*/
|
|
686
|
+
export type ObjectEntry = {
|
|
687
|
+
position: Position;
|
|
688
|
+
key: string;
|
|
689
|
+
value: LiteralValue;
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
export function hydrateObjectEntry(input: ObjectEntry): ObjectEntry {
|
|
693
|
+
const hydratedPosition = hydratePosition(input.position);
|
|
694
|
+
const hydratedKey = input.key;
|
|
695
|
+
const hydratedValue = hydrateLiteralValue(input.value);
|
|
696
|
+
return {
|
|
697
|
+
position: hydratedPosition,
|
|
698
|
+
key: hydratedKey,
|
|
699
|
+
value: hydratedValue,
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
export function validateObjectEntry(
|
|
704
|
+
input: unknown,
|
|
705
|
+
path = "ObjectEntry",
|
|
706
|
+
): string | null {
|
|
707
|
+
if (input === null || input === undefined || typeof input !== "object") {
|
|
708
|
+
return `${path}: expected object, got ${typeof input}`;
|
|
709
|
+
}
|
|
710
|
+
const obj = input as Record<string, unknown>;
|
|
711
|
+
|
|
712
|
+
if (obj.position === undefined || obj.position === null) {
|
|
713
|
+
return `${path}.position: required field is missing`;
|
|
714
|
+
}
|
|
715
|
+
{
|
|
716
|
+
const err = validatePosition(obj.position, `${path}.position`);
|
|
717
|
+
if (err !== null) return err;
|
|
718
|
+
}
|
|
719
|
+
if (obj.value === undefined || obj.value === null) {
|
|
720
|
+
return `${path}.value: required field is missing`;
|
|
721
|
+
}
|
|
722
|
+
{
|
|
723
|
+
const err = validateLiteralValue(obj.value, `${path}.value`);
|
|
724
|
+
if (err !== null) return err;
|
|
725
|
+
}
|
|
726
|
+
return null;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* Position It represents a position within a file and is used for error
|
|
731
|
+
* reporting, diagnostics, plugins, and tooling support.
|
|
732
|
+
*/
|
|
733
|
+
export type Position = {
|
|
734
|
+
file: string;
|
|
735
|
+
line: number;
|
|
736
|
+
column: number;
|
|
737
|
+
};
|
|
738
|
+
|
|
739
|
+
export function hydratePosition(input: Position): Position {
|
|
740
|
+
const hydratedFile = input.file;
|
|
741
|
+
const hydratedLine = input.line;
|
|
742
|
+
const hydratedColumn = input.column;
|
|
743
|
+
return {
|
|
744
|
+
file: hydratedFile,
|
|
745
|
+
line: hydratedLine,
|
|
746
|
+
column: hydratedColumn,
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
export function validatePosition(
|
|
751
|
+
_input: unknown,
|
|
752
|
+
_path = "Position",
|
|
753
|
+
): string | null {
|
|
754
|
+
return null;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
/**
|
|
758
|
+
* TopLevelDoc Standalone documentation block.
|
|
759
|
+
*
|
|
760
|
+
* Used for top-level docstrings that are not attached to a type/enum/constant.
|
|
761
|
+
*/
|
|
762
|
+
export type TopLevelDoc = {
|
|
763
|
+
position: Position;
|
|
764
|
+
content: string;
|
|
765
|
+
};
|
|
766
|
+
|
|
767
|
+
export function hydrateTopLevelDoc(input: TopLevelDoc): TopLevelDoc {
|
|
768
|
+
const hydratedPosition = hydratePosition(input.position);
|
|
769
|
+
const hydratedContent = input.content;
|
|
770
|
+
return {
|
|
771
|
+
position: hydratedPosition,
|
|
772
|
+
content: hydratedContent,
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
export function validateTopLevelDoc(
|
|
777
|
+
input: unknown,
|
|
778
|
+
path = "TopLevelDoc",
|
|
779
|
+
): string | null {
|
|
780
|
+
if (input === null || input === undefined || typeof input !== "object") {
|
|
781
|
+
return `${path}: expected object, got ${typeof input}`;
|
|
782
|
+
}
|
|
783
|
+
const obj = input as Record<string, unknown>;
|
|
784
|
+
|
|
785
|
+
if (obj.position === undefined || obj.position === null) {
|
|
786
|
+
return `${path}.position: required field is missing`;
|
|
787
|
+
}
|
|
788
|
+
{
|
|
789
|
+
const err = validatePosition(obj.position, `${path}.position`);
|
|
790
|
+
if (err !== null) return err;
|
|
791
|
+
}
|
|
792
|
+
return null;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
/**
|
|
796
|
+
* TypeDef Flattened type definition.
|
|
797
|
+
*
|
|
798
|
+
* All spreads are already expanded. The unified `typeRef` describes what this
|
|
799
|
+
* type IS, a primitive, custom reference, map, array, or object with fields.
|
|
800
|
+
*/
|
|
801
|
+
export type TypeDef = {
|
|
802
|
+
position: Position;
|
|
803
|
+
name: string;
|
|
804
|
+
doc?: string;
|
|
805
|
+
annotations: Annotation[];
|
|
806
|
+
typeRef: TypeRef;
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
export function hydrateTypeDef(input: TypeDef): TypeDef {
|
|
810
|
+
const hydratedPosition = hydratePosition(input.position);
|
|
811
|
+
const hydratedName = input.name;
|
|
812
|
+
const hydratedDoc = input.doc ? input.doc : input.doc;
|
|
813
|
+
const hydratedAnnotations = input.annotations.map((el) =>
|
|
814
|
+
hydrateAnnotation(el),
|
|
815
|
+
);
|
|
816
|
+
const hydratedTypeRef = hydrateTypeRef(input.typeRef);
|
|
817
|
+
return {
|
|
818
|
+
position: hydratedPosition,
|
|
819
|
+
name: hydratedName,
|
|
820
|
+
doc: hydratedDoc,
|
|
821
|
+
annotations: hydratedAnnotations,
|
|
822
|
+
typeRef: hydratedTypeRef,
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
export function validateTypeDef(
|
|
827
|
+
input: unknown,
|
|
828
|
+
path = "TypeDef",
|
|
829
|
+
): string | null {
|
|
830
|
+
if (input === null || input === undefined || typeof input !== "object") {
|
|
831
|
+
return `${path}: expected object, got ${typeof input}`;
|
|
832
|
+
}
|
|
833
|
+
const obj = input as Record<string, unknown>;
|
|
834
|
+
|
|
835
|
+
if (obj.position === undefined || obj.position === null) {
|
|
836
|
+
return `${path}.position: required field is missing`;
|
|
837
|
+
}
|
|
838
|
+
{
|
|
839
|
+
const err = validatePosition(obj.position, `${path}.position`);
|
|
840
|
+
if (err !== null) return err;
|
|
841
|
+
}
|
|
842
|
+
if (obj.annotations === undefined || obj.annotations === null) {
|
|
843
|
+
return `${path}.annotations: required field is missing`;
|
|
844
|
+
}
|
|
845
|
+
{
|
|
846
|
+
if (!Array.isArray(obj.annotations)) {
|
|
847
|
+
return `${path}.annotations: expected array, got ${typeof obj.annotations}`;
|
|
848
|
+
}
|
|
849
|
+
for (let i = 0; i < obj.annotations.length; i++) {
|
|
850
|
+
{
|
|
851
|
+
const err = validateAnnotation(
|
|
852
|
+
obj.annotations[i],
|
|
853
|
+
`${path}.annotations[${i}]`,
|
|
854
|
+
);
|
|
855
|
+
if (err !== null) return err;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
if (obj.typeRef === undefined || obj.typeRef === null) {
|
|
860
|
+
return `${path}.typeRef: required field is missing`;
|
|
861
|
+
}
|
|
862
|
+
{
|
|
863
|
+
const err = validateTypeRef(obj.typeRef, `${path}.typeRef`);
|
|
864
|
+
if (err !== null) return err;
|
|
865
|
+
}
|
|
866
|
+
return null;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
/**
|
|
870
|
+
* TypeRef Normalized type reference used by fields and constants.
|
|
871
|
+
*
|
|
872
|
+
* `kind` selects which payload fields are meaningful. Generators should inspect
|
|
873
|
+
* `kind` first, then read the related payload fields.
|
|
874
|
+
*/
|
|
875
|
+
export type TypeRef = {
|
|
876
|
+
kind: TypeKind;
|
|
877
|
+
primitiveName?: PrimitiveType;
|
|
878
|
+
typeName?: string;
|
|
879
|
+
enumName?: string;
|
|
880
|
+
enumType?: EnumValueType;
|
|
881
|
+
arrayType?: TypeRef;
|
|
882
|
+
arrayDims?: number;
|
|
883
|
+
mapType?: TypeRef;
|
|
884
|
+
objectFields?: Field[];
|
|
885
|
+
};
|
|
886
|
+
|
|
887
|
+
export function hydrateTypeRef(input: TypeRef): TypeRef {
|
|
888
|
+
const hydratedKind = input.kind;
|
|
889
|
+
const hydratedPrimitiveName = input.primitiveName
|
|
890
|
+
? input.primitiveName
|
|
891
|
+
: input.primitiveName;
|
|
892
|
+
const hydratedTypeName = input.typeName ? input.typeName : input.typeName;
|
|
893
|
+
const hydratedEnumName = input.enumName ? input.enumName : input.enumName;
|
|
894
|
+
const hydratedEnumType = input.enumType ? input.enumType : input.enumType;
|
|
895
|
+
const hydratedArrayType = input.arrayType
|
|
896
|
+
? hydrateTypeRef(input.arrayType)
|
|
897
|
+
: input.arrayType;
|
|
898
|
+
const hydratedArrayDims = input.arrayDims ? input.arrayDims : input.arrayDims;
|
|
899
|
+
const hydratedMapType = input.mapType
|
|
900
|
+
? hydrateTypeRef(input.mapType)
|
|
901
|
+
: input.mapType;
|
|
902
|
+
const hydratedObjectFields = input.objectFields
|
|
903
|
+
? input.objectFields.map((el) => hydrateField(el))
|
|
904
|
+
: input.objectFields;
|
|
905
|
+
return {
|
|
906
|
+
kind: hydratedKind,
|
|
907
|
+
primitiveName: hydratedPrimitiveName,
|
|
908
|
+
typeName: hydratedTypeName,
|
|
909
|
+
enumName: hydratedEnumName,
|
|
910
|
+
enumType: hydratedEnumType,
|
|
911
|
+
arrayType: hydratedArrayType,
|
|
912
|
+
arrayDims: hydratedArrayDims,
|
|
913
|
+
mapType: hydratedMapType,
|
|
914
|
+
objectFields: hydratedObjectFields,
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
export function validateTypeRef(
|
|
919
|
+
input: unknown,
|
|
920
|
+
path = "TypeRef",
|
|
921
|
+
): string | null {
|
|
922
|
+
if (input === null || input === undefined || typeof input !== "object") {
|
|
923
|
+
return `${path}: expected object, got ${typeof input}`;
|
|
924
|
+
}
|
|
925
|
+
const obj = input as Record<string, unknown>;
|
|
926
|
+
|
|
927
|
+
if (obj.kind === undefined || obj.kind === null) {
|
|
928
|
+
return `${path}.kind: required field is missing`;
|
|
929
|
+
}
|
|
930
|
+
{
|
|
931
|
+
if (!isTypeKind(obj.kind)) {
|
|
932
|
+
return `${path}.kind: invalid enum value '${obj.kind}' for TypeKind`;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
if (obj.primitiveName !== undefined && obj.primitiveName !== null) {
|
|
936
|
+
{
|
|
937
|
+
if (!isPrimitiveType(obj.primitiveName)) {
|
|
938
|
+
return `${path}.primitiveName: invalid enum value '${obj.primitiveName}' for PrimitiveType`;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
if (obj.enumType !== undefined && obj.enumType !== null) {
|
|
943
|
+
{
|
|
944
|
+
if (!isEnumValueType(obj.enumType)) {
|
|
945
|
+
return `${path}.enumType: invalid enum value '${obj.enumType}' for EnumValueType`;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
if (obj.arrayType !== undefined && obj.arrayType !== null) {
|
|
950
|
+
{
|
|
951
|
+
const err = validateTypeRef(obj.arrayType, `${path}.arrayType`);
|
|
952
|
+
if (err !== null) return err;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
if (obj.mapType !== undefined && obj.mapType !== null) {
|
|
956
|
+
{
|
|
957
|
+
const err = validateTypeRef(obj.mapType, `${path}.mapType`);
|
|
958
|
+
if (err !== null) return err;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
if (obj.objectFields !== undefined && obj.objectFields !== null) {
|
|
962
|
+
{
|
|
963
|
+
if (!Array.isArray(obj.objectFields)) {
|
|
964
|
+
return `${path}.objectFields: expected array, got ${typeof obj.objectFields}`;
|
|
965
|
+
}
|
|
966
|
+
for (let i = 0; i < obj.objectFields.length; i++) {
|
|
967
|
+
{
|
|
968
|
+
const err = validateField(
|
|
969
|
+
obj.objectFields[i],
|
|
970
|
+
`${path}.objectFields[${i}]`,
|
|
971
|
+
);
|
|
972
|
+
if (err !== null) return err;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
return null;
|
|
978
|
+
}
|