firebase-contract 0.1.0-rc.8 → 0.1.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/README.md +141 -64
- package/dist/lib/_internal/compiler/compiler.d.ts.map +1 -1
- package/dist/lib/_internal/compiler/compiler.js +50 -21
- package/dist/lib/_internal/generators/api/api-dto-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/api/api-dto-generator.js +1 -8
- package/dist/lib/_internal/generators/api/api-types-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/api/api-types-generator.js +11 -5
- package/dist/lib/_internal/generators/api/task-payload-generator.js +3 -3
- package/dist/lib/_internal/generators/data-connect/graphql-generator.d.ts +0 -7
- package/dist/lib/_internal/generators/data-connect/graphql-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/data-connect/graphql-generator.js +5 -4
- package/dist/lib/_internal/generators/data-connect/operations-generator.d.ts +0 -7
- package/dist/lib/_internal/generators/data-connect/operations-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/data-connect/operations-generator.js +8 -7
- package/dist/lib/_internal/generators/firestore/firestore-projection-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/firestore/firestore-projection-generator.js +7 -22
- package/dist/lib/_internal/generators/firestore/firestore-split-generator.d.ts +1 -1
- package/dist/lib/_internal/generators/firestore/firestore-split-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/firestore/firestore-split-generator.js +69 -47
- package/dist/lib/_internal/generators/generator.d.ts +2 -0
- package/dist/lib/_internal/generators/generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/index.d.ts +2 -5
- package/dist/lib/_internal/generators/index.d.ts.map +1 -1
- package/dist/lib/_internal/generators/index.js +4 -15
- package/dist/lib/_internal/generators/sql/sql-migration-generator.d.ts +2 -1
- package/dist/lib/_internal/generators/sql/sql-migration-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/sql/sql-migration-generator.js +11 -4
- package/dist/lib/_internal/generators/support/jsdoc.d.ts +3 -0
- package/dist/lib/_internal/generators/support/jsdoc.d.ts.map +1 -0
- package/dist/lib/_internal/generators/support/jsdoc.js +9 -0
- package/dist/lib/_internal/generators/support/split-variant.d.ts +9 -0
- package/dist/lib/_internal/generators/support/split-variant.d.ts.map +1 -0
- package/dist/lib/_internal/generators/support/split-variant.js +13 -0
- package/dist/lib/_internal/generators/support/split.d.ts +1 -1
- package/dist/lib/_internal/generators/support/split.d.ts.map +1 -1
- package/dist/lib/_internal/generators/support/split.js +3 -2
- package/dist/lib/_internal/generators/typescript/render.d.ts +15 -0
- package/dist/lib/_internal/generators/typescript/render.d.ts.map +1 -0
- package/dist/lib/_internal/generators/typescript/render.js +92 -0
- package/dist/lib/_internal/generators/typescript/typescript-generator.d.ts +2 -1
- package/dist/lib/_internal/generators/typescript/typescript-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/typescript/typescript-generator.js +12 -78
- package/dist/lib/_internal/generators/typescript/typescript-split-generator.d.ts +1 -1
- package/dist/lib/_internal/generators/typescript/typescript-split-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/typescript/typescript-split-generator.js +4 -84
- package/dist/lib/_internal/generators/zod/render.d.ts +12 -0
- package/dist/lib/_internal/generators/zod/render.d.ts.map +1 -0
- package/dist/lib/_internal/generators/zod/render.js +59 -0
- package/dist/lib/_internal/generators/zod/zod-generator.d.ts +2 -1
- package/dist/lib/_internal/generators/zod/zod-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/zod/zod-generator.js +11 -55
- package/dist/lib/_internal/generators/zod/zod-split-generator.d.ts +1 -1
- package/dist/lib/_internal/generators/zod/zod-split-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/zod/zod-split-generator.js +4 -56
- package/dist/lib/_internal/ir/build-ir.d.ts.map +1 -1
- package/dist/lib/_internal/ir/build-ir.js +93 -8
- package/dist/lib/_internal/ir/ir.d.ts +18 -5
- package/dist/lib/_internal/ir/ir.d.ts.map +1 -1
- package/dist/lib/_internal/ir/ir.js +1 -0
- package/dist/lib/_internal/parser/parse.d.ts +5 -3
- package/dist/lib/_internal/parser/parse.d.ts.map +1 -1
- package/dist/lib/_internal/parser/parse.js +103 -14
- package/dist/lib/_internal/parser/raw-document.d.ts +18 -2
- package/dist/lib/_internal/parser/raw-document.d.ts.map +1 -1
- package/dist/lib/_internal/resolver/import-resolver.js +1 -1
- package/dist/lib/_internal/validation/rules.d.ts +39 -0
- package/dist/lib/_internal/validation/rules.d.ts.map +1 -1
- package/dist/lib/_internal/validation/rules.js +133 -1
- package/dist/lib/cli/commands/generate.d.ts.map +1 -1
- package/dist/lib/cli/commands/generate.js +6 -4
- package/dist/lib/cli/commands/index.d.ts.map +1 -1
- package/dist/lib/cli/commands/index.js +2 -0
- package/dist/lib/cli/commands/init.d.ts.map +1 -1
- package/dist/lib/cli/commands/init.js +2 -18
- package/dist/lib/cli/commands/where.d.ts +3 -0
- package/dist/lib/cli/commands/where.d.ts.map +1 -0
- package/dist/lib/cli/commands/where.js +57 -0
- package/dist/lib/cli/config.d.ts +3 -2
- package/dist/lib/cli/config.d.ts.map +1 -1
- package/dist/lib/cli/config.js +3 -0
- package/package.json +1 -1
|
@@ -4,6 +4,27 @@ const isObject = (value) => typeof value === 'object' && value !== null && !Arra
|
|
|
4
4
|
const fail = (message, filePath, path) => {
|
|
5
5
|
throw new ContractError(message, [error('PARSE_ERROR', message, { file: filePath, path })]);
|
|
6
6
|
};
|
|
7
|
+
/**
|
|
8
|
+
* Sink for UNKNOWN_KEY diagnostics, set for the duration of one parseContract
|
|
9
|
+
* call (the parser is synchronous, so there is no reentrancy). Collected keys
|
|
10
|
+
* become errors instead of throws so a single pass reports every typo at once.
|
|
11
|
+
*/
|
|
12
|
+
let unknownKeySink;
|
|
13
|
+
/**
|
|
14
|
+
* The contract is the single source of truth, so a key the parser would
|
|
15
|
+
* silently drop is either a typo about to change meaning (`optionnal:` making a
|
|
16
|
+
* field required) or dead weight lying about what the contract expresses.
|
|
17
|
+
* Either way it is an error, not a shrug.
|
|
18
|
+
*/
|
|
19
|
+
const checkKeys = (raw, known, filePath, path) => {
|
|
20
|
+
if (!unknownKeySink)
|
|
21
|
+
return;
|
|
22
|
+
for (const key of Object.keys(raw)) {
|
|
23
|
+
if (!known.includes(key)) {
|
|
24
|
+
unknownKeySink.push(error('UNKNOWN_KEY', `Unknown key "${key}" in ${path} — remove it or fix the typo`, { file: filePath, path: `${path}.${key}` }));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
7
28
|
const normalizeField = (raw, filePath, path) => {
|
|
8
29
|
// Shorthand: `title: string` — the value is the type name.
|
|
9
30
|
if (typeof raw === 'string') {
|
|
@@ -15,6 +36,7 @@ const normalizeField = (raw, filePath, path) => {
|
|
|
15
36
|
if (typeof raw.type !== 'string') {
|
|
16
37
|
return fail(`Field "${path}" is missing a string "type"`, filePath, path);
|
|
17
38
|
}
|
|
39
|
+
checkKeys(raw, ['type', 'optional', 'nullable', 'jsdoc', 'list', 'id', 'unique', 'relation', 'default', 'description', 'min', 'max', 'minLength', 'maxLength', 'pattern', 'nonempty', 'email', 'url', 'col', 'literal'], filePath, path);
|
|
18
40
|
const field = { type: raw.type };
|
|
19
41
|
if (raw.optional !== undefined)
|
|
20
42
|
field.optional = Boolean(raw.optional);
|
|
@@ -64,11 +86,16 @@ const normalizeModel = (raw, filePath, name) => {
|
|
|
64
86
|
if (!isObject(fieldsRaw)) {
|
|
65
87
|
return fail(`Model "${name}" is missing a "fields" object`, filePath, `models.${name}.fields`);
|
|
66
88
|
}
|
|
89
|
+
checkKeys(raw, ['fields', 'description', 'key', 'table', 'gqlName', 'directives', 'footer', 'fsName', 'indexes', 'sql', 'out', 'file'], filePath, `models.${name}`);
|
|
67
90
|
const fields = {};
|
|
68
91
|
for (const [fieldName, fieldRaw] of Object.entries(fieldsRaw)) {
|
|
69
92
|
fields[fieldName] = normalizeField(fieldRaw, filePath, `models.${name}.fields.${fieldName}`);
|
|
70
93
|
}
|
|
71
94
|
const model = { fields };
|
|
95
|
+
if (raw.out !== undefined)
|
|
96
|
+
model.out = String(raw.out);
|
|
97
|
+
if (raw.file !== undefined)
|
|
98
|
+
model.file = String(raw.file);
|
|
72
99
|
if (raw.description !== undefined)
|
|
73
100
|
model.description = String(raw.description);
|
|
74
101
|
if (raw.key !== undefined)
|
|
@@ -91,6 +118,7 @@ const normalizeModel = (raw, filePath, name) => {
|
|
|
91
118
|
if (!isObject(entry)) {
|
|
92
119
|
return fail(`Model "${name}" index #${i} must be an object`, filePath, `models.${name}.indexes`);
|
|
93
120
|
}
|
|
121
|
+
checkKeys(entry, ['fields', 'name', 'unique', 'expand'], filePath, `models.${name}.indexes[${i}]`);
|
|
94
122
|
const index = {
|
|
95
123
|
fields: asStringArray(entry.fields, filePath, `models.${name}.indexes[${i}].fields`),
|
|
96
124
|
};
|
|
@@ -108,6 +136,7 @@ const normalizeModel = (raw, filePath, name) => {
|
|
|
108
136
|
return fail(`Model "${name}" sql must be an object`, filePath, `models.${name}.sql`);
|
|
109
137
|
}
|
|
110
138
|
const sqlRaw = raw.sql;
|
|
139
|
+
checkKeys(sqlRaw, ['checks', 'foreignKeys', 'indexes'], filePath, `models.${name}.sql`);
|
|
111
140
|
const sql = {};
|
|
112
141
|
if (sqlRaw.checks !== undefined)
|
|
113
142
|
sql.checks = asStringArray(sqlRaw.checks, filePath, `models.${name}.sql.checks`);
|
|
@@ -119,6 +148,7 @@ const normalizeModel = (raw, filePath, name) => {
|
|
|
119
148
|
if (!isObject(entry) || typeof entry.references !== 'string') {
|
|
120
149
|
return fail(`Model "${name}" sql.foreignKeys[${i}] needs columns + references`, filePath, `models.${name}.sql.foreignKeys`);
|
|
121
150
|
}
|
|
151
|
+
checkKeys(entry, ['columns', 'references', 'name'], filePath, `models.${name}.sql.foreignKeys[${i}]`);
|
|
122
152
|
const fk = {
|
|
123
153
|
columns: asStringArray(entry.columns, filePath, `models.${name}.sql.foreignKeys[${i}].columns`),
|
|
124
154
|
references: entry.references,
|
|
@@ -136,6 +166,7 @@ const normalizeModel = (raw, filePath, name) => {
|
|
|
136
166
|
if (!isObject(entry)) {
|
|
137
167
|
return fail(`Model "${name}" sql.indexes[${i}] must be an object`, filePath, `models.${name}.sql.indexes`);
|
|
138
168
|
}
|
|
169
|
+
checkKeys(entry, ['columns', 'name', 'unique'], filePath, `models.${name}.sql.indexes[${i}]`);
|
|
139
170
|
const idx = {
|
|
140
171
|
columns: asStringArray(entry.columns, filePath, `models.${name}.sql.indexes[${i}].columns`),
|
|
141
172
|
};
|
|
@@ -157,11 +188,13 @@ const normalizeEnum = (raw, filePath, name) => {
|
|
|
157
188
|
if (!Array.isArray(raw.values)) {
|
|
158
189
|
return fail(`Enum "${name}" is missing a "values" array`, filePath, `enums.${name}.values`);
|
|
159
190
|
}
|
|
191
|
+
checkKeys(raw, ['values', 'gqlName', 'fsName', 'fsDescription', 'description'], filePath, `enums.${name}`);
|
|
160
192
|
const values = [];
|
|
161
193
|
const valueComments = {};
|
|
162
194
|
const valueKeys = {};
|
|
163
195
|
for (const entry of raw.values) {
|
|
164
196
|
if (isObject(entry) && typeof entry.value === 'string') {
|
|
197
|
+
checkKeys(entry, ['value', 'description', 'key'], filePath, `enums.${name}.values`);
|
|
165
198
|
values.push(entry.value);
|
|
166
199
|
if (entry.description !== undefined)
|
|
167
200
|
valueComments[entry.value] = String(entry.description);
|
|
@@ -205,6 +238,7 @@ const normalizeOperation = (raw, filePath, name) => {
|
|
|
205
238
|
if (typeof raw.model !== 'string') {
|
|
206
239
|
return fail(`Operation "${name}" is missing a string "model"`, filePath, `operations.${name}.model`);
|
|
207
240
|
}
|
|
241
|
+
checkKeys(raw, ['type', 'model', 'action', 'auth', 'authReason', 'inputs', 'select', 'where', 'orderBy', 'limit', 'single', 'keyArg', 'entityDir', 'whereAnd', 'gqlName', 'footer', 'raw', 'style', 'keyVars', 'aggregate', 'exprs', 'inc', 'connectors', 'description'], filePath, `operations.${name}`);
|
|
208
242
|
const op = { type: raw.type, model: raw.model };
|
|
209
243
|
if (raw.action !== undefined)
|
|
210
244
|
op.action = String(raw.action);
|
|
@@ -220,6 +254,7 @@ const normalizeOperation = (raw, filePath, name) => {
|
|
|
220
254
|
if (typeof entry === 'string')
|
|
221
255
|
return { field: entry };
|
|
222
256
|
if (isObject(entry) && typeof entry.field === 'string') {
|
|
257
|
+
checkKeys(entry, ['field', 'required', 'description', 'var', 'flat', 'literal', 'quote', 'inc', 'asKey'], filePath, `operations.${name}.inputs`);
|
|
223
258
|
return {
|
|
224
259
|
field: entry.field,
|
|
225
260
|
...(entry.required !== undefined ? { required: Boolean(entry.required) } : {}),
|
|
@@ -244,6 +279,7 @@ const normalizeOperation = (raw, filePath, name) => {
|
|
|
244
279
|
if (typeof entry === 'string')
|
|
245
280
|
return { field: entry };
|
|
246
281
|
if (isObject(entry) && typeof entry.field === 'string') {
|
|
282
|
+
checkKeys(entry, ['field', 'select', 'description', 'alias', 'args'], filePath, path);
|
|
247
283
|
return {
|
|
248
284
|
field: entry.field,
|
|
249
285
|
...(entry.select !== undefined ? { select: normalizeSelect(entry.select, `${path}.${entry.field}`) } : {}),
|
|
@@ -266,6 +302,7 @@ const normalizeOperation = (raw, filePath, name) => {
|
|
|
266
302
|
if (typeof entry === 'string')
|
|
267
303
|
return { field: entry, op: 'eq' };
|
|
268
304
|
if (isObject(entry) && typeof entry.field === 'string') {
|
|
305
|
+
checkKeys(entry, ['field', 'op', 'required', 'description', 'var', 'literal', 'flat'], filePath, `operations.${name}.where`);
|
|
269
306
|
return {
|
|
270
307
|
field: entry.field,
|
|
271
308
|
op: entry.op !== undefined ? String(entry.op) : 'eq',
|
|
@@ -288,11 +325,13 @@ const normalizeOperation = (raw, filePath, name) => {
|
|
|
288
325
|
if (!isObject(entry) || typeof entry.field !== 'string') {
|
|
289
326
|
return fail(`Operation "${name}" orderBy entry needs a field`, filePath, `operations.${name}.orderBy`);
|
|
290
327
|
}
|
|
328
|
+
checkKeys(entry, ['field', 'dir'], filePath, `operations.${name}.orderBy`);
|
|
291
329
|
return { field: entry.field, dir: entry.dir !== undefined ? String(entry.dir).toUpperCase() : 'ASC' };
|
|
292
330
|
});
|
|
293
331
|
}
|
|
294
332
|
if (raw.limit !== undefined) {
|
|
295
333
|
if (isObject(raw.limit) && typeof raw.limit.var === 'string') {
|
|
334
|
+
checkKeys(raw.limit, ['var', 'default', 'required'], filePath, `operations.${name}.limit`);
|
|
296
335
|
op.limit = {
|
|
297
336
|
var: raw.limit.var,
|
|
298
337
|
...(raw.limit.default !== undefined ? { default: Number(raw.limit.default) } : {}),
|
|
@@ -322,7 +361,9 @@ const normalizeOperation = (raw, filePath, name) => {
|
|
|
322
361
|
return fail(`Operation "${name}" style must be a mapping`, filePath, `operations.${name}.style`);
|
|
323
362
|
}
|
|
324
363
|
const style = {};
|
|
325
|
-
|
|
364
|
+
const styleKeys = ['signature', 'args', 'data', 'orderBy', 'auth', 'key', 'and', 'where'];
|
|
365
|
+
checkKeys(raw.style, styleKeys, filePath, `operations.${name}.style`);
|
|
366
|
+
for (const k of styleKeys) {
|
|
326
367
|
if (raw.style[k] !== undefined)
|
|
327
368
|
style[k] = String(raw.style[k]);
|
|
328
369
|
}
|
|
@@ -338,6 +379,7 @@ const normalizeOperation = (raw, filePath, name) => {
|
|
|
338
379
|
if (!isObject(raw.aggregate)) {
|
|
339
380
|
return fail(`Operation "${name}" aggregate must be an object`, filePath, `operations.${name}.aggregate`);
|
|
340
381
|
}
|
|
382
|
+
checkKeys(raw.aggregate, ['count', 'sum'], filePath, `operations.${name}.aggregate`);
|
|
341
383
|
op.aggregate = {
|
|
342
384
|
count: raw.aggregate.count !== undefined ? Boolean(raw.aggregate.count) : false,
|
|
343
385
|
sum: asStringArray(raw.aggregate.sum, filePath, `operations.${name}.aggregate.sum`),
|
|
@@ -357,16 +399,13 @@ const normalizeOperation = (raw, filePath, name) => {
|
|
|
357
399
|
if (typeof entry === 'string')
|
|
358
400
|
return { field: entry };
|
|
359
401
|
if (isObject(entry) && typeof entry.field === 'string') {
|
|
402
|
+
checkKeys(entry, ['field', 'var'], filePath, `operations.${name}.inc`);
|
|
360
403
|
return { field: entry.field, ...(entry.var !== undefined ? { var: String(entry.var) } : {}) };
|
|
361
404
|
}
|
|
362
405
|
return fail(`Operation "${name}" inc entry must be a field or { field, var }`, filePath, `operations.${name}.inc`);
|
|
363
406
|
});
|
|
364
407
|
}
|
|
365
|
-
|
|
366
|
-
if (raw.connector !== undefined) {
|
|
367
|
-
op.connectors = [String(raw.connector)];
|
|
368
|
-
}
|
|
369
|
-
else if (raw.connectors !== undefined) {
|
|
408
|
+
if (raw.connectors !== undefined) {
|
|
370
409
|
op.connectors = asStringArray(raw.connectors, filePath, `operations.${name}.connectors`);
|
|
371
410
|
}
|
|
372
411
|
if (raw.description !== undefined)
|
|
@@ -379,6 +418,7 @@ const normalizeApiPayload = (raw, filePath, path) => {
|
|
|
379
418
|
if (!isObject(raw)) {
|
|
380
419
|
return fail(`"${path}" must be an object`, filePath, path);
|
|
381
420
|
}
|
|
421
|
+
checkKeys(raw, ['model', 'void', 'fields'], filePath, path);
|
|
382
422
|
const payload = {};
|
|
383
423
|
if (raw.model !== undefined)
|
|
384
424
|
payload.model = String(raw.model);
|
|
@@ -412,6 +452,7 @@ const normalizeGeneratorUse = (raw, filePath, path) => {
|
|
|
412
452
|
if (!isObject(raw) || typeof raw.generator !== 'string') {
|
|
413
453
|
return fail(`"${path}" must be a generator name or { generator, out?, file?, split?, options?, header? }`, filePath, path);
|
|
414
454
|
}
|
|
455
|
+
checkKeys(raw, ['generator', 'out', 'file', 'split', 'options', 'header'], filePath, path);
|
|
415
456
|
const use = { generator: raw.generator };
|
|
416
457
|
if (raw.out !== undefined)
|
|
417
458
|
use.out = String(raw.out);
|
|
@@ -437,6 +478,7 @@ const normalizeSectionDefaults = (raw, filePath, section) => {
|
|
|
437
478
|
if (!isObject(raw)) {
|
|
438
479
|
return fail(`"${section}.${SECTION_DEFAULTS_KEY}" must be an object`, filePath, `${section}.${SECTION_DEFAULTS_KEY}`);
|
|
439
480
|
}
|
|
481
|
+
checkKeys(raw, ['generators'], filePath, `${section}.${SECTION_DEFAULTS_KEY}`);
|
|
440
482
|
if (raw.generators === undefined)
|
|
441
483
|
return [];
|
|
442
484
|
return normalizeGeneratorUses(raw.generators, filePath, `${section}.${SECTION_DEFAULTS_KEY}.generators`);
|
|
@@ -462,6 +504,7 @@ const normalizePathApi = (raw, filePath, pathKey) => {
|
|
|
462
504
|
if (kind !== 'https' && kind !== 'callable') {
|
|
463
505
|
return fail(`Api "${pathKey}" kind must be https|callable (tasks/events have their own sections)`, filePath, `apis.${pathKey}.kind`);
|
|
464
506
|
}
|
|
507
|
+
checkKeys(raw, ['operationId', 'kind', 'method', 'description', 'request', 'response', 'generators'], filePath, `apis.${pathKey}`);
|
|
465
508
|
const prefixed = METHOD_PREFIXED_KEY_RE.exec(pathKey);
|
|
466
509
|
const keyMethod = prefixed?.[1];
|
|
467
510
|
const routePath = prefixed?.[2] ?? pathKey;
|
|
@@ -489,6 +532,7 @@ const normalizeTask = (raw, filePath, name) => {
|
|
|
489
532
|
if (!isObject(raw)) {
|
|
490
533
|
return fail(`Task "${name}" must be an object`, filePath, `tasks.${name}`);
|
|
491
534
|
}
|
|
535
|
+
checkKeys(raw, ['description', 'envelope', 'maxAttempts', 'timeoutSeconds', 'request', 'response', 'generators'], filePath, `tasks.${name}`);
|
|
492
536
|
const api = { kind: 'task' };
|
|
493
537
|
if (raw.description !== undefined)
|
|
494
538
|
api.description = String(raw.description);
|
|
@@ -510,6 +554,7 @@ const normalizeEvent = (raw, filePath, name) => {
|
|
|
510
554
|
if (!isObject(raw)) {
|
|
511
555
|
return fail(`Event "${name}" must be an object`, filePath, `events.${name}`);
|
|
512
556
|
}
|
|
557
|
+
checkKeys(raw, ['description', 'envelope', 'maxAttempts', 'timeoutSeconds', 'topic', 'request', 'response', 'generators'], filePath, `events.${name}`);
|
|
513
558
|
const api = { kind: 'pubsub' };
|
|
514
559
|
if (raw.description !== undefined)
|
|
515
560
|
api.description = String(raw.description);
|
|
@@ -535,6 +580,7 @@ const normalizeEnvelope = (raw, filePath, name) => {
|
|
|
535
580
|
if (!isObject(raw.fields)) {
|
|
536
581
|
return fail(`Envelope "${name}" is missing a "fields" object`, filePath, `envelopes.${name}.fields`);
|
|
537
582
|
}
|
|
583
|
+
checkKeys(raw, ['fields', 'description'], filePath, `envelopes.${name}`);
|
|
538
584
|
const fields = {};
|
|
539
585
|
for (const [fieldName, fieldRaw] of Object.entries(raw.fields)) {
|
|
540
586
|
fields[fieldName] = normalizeField(fieldRaw, filePath, `envelopes.${name}.fields.${fieldName}`);
|
|
@@ -548,6 +594,7 @@ const normalizeFirestoreDoc = (raw, filePath, name) => {
|
|
|
548
594
|
if (!isObject(raw)) {
|
|
549
595
|
return fail(`Firestore doc "${name}" must be an object`, filePath, `firestore.${name}`);
|
|
550
596
|
}
|
|
597
|
+
checkKeys(raw, ['from', 'collection', 'description', 'extends', 'helpers', 'include', 'pick', 'omit', 'fields'], filePath, `firestore.${name}`);
|
|
551
598
|
const doc = {};
|
|
552
599
|
if (raw.from !== undefined)
|
|
553
600
|
doc.from = String(raw.from);
|
|
@@ -555,8 +602,8 @@ const normalizeFirestoreDoc = (raw, filePath, name) => {
|
|
|
555
602
|
doc.collection = String(raw.collection);
|
|
556
603
|
if (raw.description !== undefined)
|
|
557
604
|
doc.description = String(raw.description);
|
|
558
|
-
if (raw.
|
|
559
|
-
doc.
|
|
605
|
+
if (raw.extends !== undefined)
|
|
606
|
+
doc.extends = asStringArray(raw.extends, filePath, `firestore.${name}.extends`);
|
|
560
607
|
if (raw.helpers !== undefined)
|
|
561
608
|
doc.helpers = String(raw.helpers);
|
|
562
609
|
if (raw.include !== undefined)
|
|
@@ -575,6 +622,23 @@ const normalizeFirestoreDoc = (raw, filePath, name) => {
|
|
|
575
622
|
}
|
|
576
623
|
return doc;
|
|
577
624
|
};
|
|
625
|
+
const normalizeFragment = (raw, filePath, name) => {
|
|
626
|
+
if (!isObject(raw)) {
|
|
627
|
+
return fail(`Fragment "${name}" must be an object`, filePath, `fragments.${name}`);
|
|
628
|
+
}
|
|
629
|
+
if (!isObject(raw.fields)) {
|
|
630
|
+
return fail(`Fragment "${name}" is missing a "fields" object`, filePath, `fragments.${name}.fields`);
|
|
631
|
+
}
|
|
632
|
+
checkKeys(raw, ['fields', 'description'], filePath, `fragments.${name}`);
|
|
633
|
+
const fields = {};
|
|
634
|
+
for (const [fieldName, fieldRaw] of Object.entries(raw.fields)) {
|
|
635
|
+
fields[fieldName] = normalizeField(fieldRaw, filePath, `fragments.${name}.fields.${fieldName}`);
|
|
636
|
+
}
|
|
637
|
+
const fragment = { fields };
|
|
638
|
+
if (raw.description !== undefined)
|
|
639
|
+
fragment.description = String(raw.description);
|
|
640
|
+
return fragment;
|
|
641
|
+
};
|
|
578
642
|
const normalizeUnion = (raw, filePath, name) => {
|
|
579
643
|
if (!isObject(raw)) {
|
|
580
644
|
return fail(`Union "${name}" must be an object`, filePath, `unions.${name}`);
|
|
@@ -582,6 +646,7 @@ const normalizeUnion = (raw, filePath, name) => {
|
|
|
582
646
|
if (typeof raw.discriminant !== 'string') {
|
|
583
647
|
return fail(`Union "${name}" is missing a string "discriminant"`, filePath, `unions.${name}.discriminant`);
|
|
584
648
|
}
|
|
649
|
+
checkKeys(raw, ['discriminant', 'variants', 'description'], filePath, `unions.${name}`);
|
|
585
650
|
const union = {
|
|
586
651
|
discriminant: raw.discriminant,
|
|
587
652
|
variants: asStringArray(raw.variants, filePath, `unions.${name}.variants`),
|
|
@@ -594,6 +659,7 @@ const normalizeProject = (raw, filePath) => {
|
|
|
594
659
|
if (!isObject(raw)) {
|
|
595
660
|
return fail('"project" must be an object', filePath, 'project');
|
|
596
661
|
}
|
|
662
|
+
checkKeys(raw, ['services', 'codebases', 'idCodec', 'aliases'], filePath, 'project');
|
|
597
663
|
const project = {};
|
|
598
664
|
if (raw.services !== undefined) {
|
|
599
665
|
if (!Array.isArray(raw.services)) {
|
|
@@ -603,6 +669,7 @@ const normalizeProject = (raw, filePath) => {
|
|
|
603
669
|
if (!isObject(entry) || typeof entry.name !== 'string') {
|
|
604
670
|
return fail(`project.services[${i}] needs a name`, filePath, 'project.services');
|
|
605
671
|
}
|
|
672
|
+
checkKeys(entry, ['name', 'database', 'location', 'connectors'], filePath, `project.services[${i}]`);
|
|
606
673
|
const service = { name: entry.name };
|
|
607
674
|
if (entry.database !== undefined)
|
|
608
675
|
service.database = String(entry.database);
|
|
@@ -624,6 +691,7 @@ const normalizeProject = (raw, filePath) => {
|
|
|
624
691
|
project.codebases = codebases;
|
|
625
692
|
}
|
|
626
693
|
if (isObject(raw.idCodec)) {
|
|
694
|
+
checkKeys(raw.idCodec, ['minLength', 'alphabet'], filePath, 'project.idCodec');
|
|
627
695
|
const idCodec = {};
|
|
628
696
|
if (raw.idCodec.minLength !== undefined)
|
|
629
697
|
idCodec.minLength = Number(raw.idCodec.minLength);
|
|
@@ -646,10 +714,20 @@ const normalizeProject = (raw, filePath) => {
|
|
|
646
714
|
/**
|
|
647
715
|
* Parse a single YAML contract file into a {@link RawContract}. Shorthand forms
|
|
648
716
|
* are normalized here so downstream code sees one canonical shape. Syntax and
|
|
649
|
-
* structural problems throw a {@link ContractError};
|
|
650
|
-
*
|
|
717
|
+
* structural problems throw a {@link ContractError}; unknown keys are collected
|
|
718
|
+
* into `diagnostics` as UNKNOWN_KEY errors (all of them in one pass); semantic
|
|
719
|
+
* problems are left for validation.
|
|
651
720
|
*/
|
|
652
|
-
export const parseContract = (content, filePath) => {
|
|
721
|
+
export const parseContract = (content, filePath, diagnostics) => {
|
|
722
|
+
unknownKeySink = diagnostics;
|
|
723
|
+
try {
|
|
724
|
+
return parseContractInner(content, filePath);
|
|
725
|
+
}
|
|
726
|
+
finally {
|
|
727
|
+
unknownKeySink = undefined;
|
|
728
|
+
}
|
|
729
|
+
};
|
|
730
|
+
const parseContractInner = (content, filePath) => {
|
|
653
731
|
let doc;
|
|
654
732
|
try {
|
|
655
733
|
doc = parseYamlText(content);
|
|
@@ -662,7 +740,6 @@ export const parseContract = (content, filePath) => {
|
|
|
662
740
|
// An empty file is a valid, contribution-free contract.
|
|
663
741
|
return {
|
|
664
742
|
filePath,
|
|
665
|
-
version: 1,
|
|
666
743
|
imports: [],
|
|
667
744
|
defaultConnectors: [],
|
|
668
745
|
enums: {},
|
|
@@ -672,11 +749,13 @@ export const parseContract = (content, filePath) => {
|
|
|
672
749
|
firestore: {},
|
|
673
750
|
unions: {},
|
|
674
751
|
envelopes: {},
|
|
752
|
+
fragments: {},
|
|
675
753
|
};
|
|
676
754
|
}
|
|
677
755
|
if (!isObject(doc)) {
|
|
678
756
|
return fail('Contract root must be a mapping', filePath);
|
|
679
757
|
}
|
|
758
|
+
checkKeys(doc, ['imports', 'defaults', 'header', 'project', 'generators', 'enums', 'models', 'operations', 'apis', 'tasks', 'events', 'firestore', 'unions', 'envelopes', 'fragments'], filePath, '(root)');
|
|
680
759
|
const imports = [];
|
|
681
760
|
if (doc.imports !== undefined) {
|
|
682
761
|
if (!Array.isArray(doc.imports)) {
|
|
@@ -713,6 +792,7 @@ export const parseContract = (content, filePath) => {
|
|
|
713
792
|
if (!isObject(doc.defaults)) {
|
|
714
793
|
return fail('"defaults" must be a mapping', filePath, 'defaults');
|
|
715
794
|
}
|
|
795
|
+
checkKeys(doc.defaults, ['connectors'], filePath, 'defaults');
|
|
716
796
|
defaultConnectors = asStringArray(doc.defaults.connectors, filePath, 'defaults.connectors');
|
|
717
797
|
}
|
|
718
798
|
const operations = {};
|
|
@@ -808,10 +888,17 @@ export const parseContract = (content, filePath) => {
|
|
|
808
888
|
envelopes[name] = normalizeEnvelope(raw, filePath, name);
|
|
809
889
|
}
|
|
810
890
|
}
|
|
811
|
-
const
|
|
891
|
+
const fragments = {};
|
|
892
|
+
if (doc.fragments !== undefined) {
|
|
893
|
+
if (!isObject(doc.fragments)) {
|
|
894
|
+
return fail('"fragments" must be a mapping', filePath, 'fragments');
|
|
895
|
+
}
|
|
896
|
+
for (const [name, raw] of Object.entries(doc.fragments)) {
|
|
897
|
+
fragments[name] = normalizeFragment(raw, filePath, name);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
812
900
|
const contract = {
|
|
813
901
|
filePath,
|
|
814
|
-
version,
|
|
815
902
|
imports,
|
|
816
903
|
defaultConnectors,
|
|
817
904
|
enums,
|
|
@@ -821,6 +908,7 @@ export const parseContract = (content, filePath) => {
|
|
|
821
908
|
firestore,
|
|
822
909
|
unions,
|
|
823
910
|
envelopes,
|
|
911
|
+
fragments,
|
|
824
912
|
};
|
|
825
913
|
if (doc.project !== undefined) {
|
|
826
914
|
contract.project = normalizeProject(doc.project, filePath);
|
|
@@ -839,6 +927,7 @@ export const parseContract = (content, filePath) => {
|
|
|
839
927
|
if (typeof entry.out !== 'string') {
|
|
840
928
|
return fail(`generators[${i}] needs a string "out"`, filePath, `generators[${i}].out`);
|
|
841
929
|
}
|
|
930
|
+
checkKeys(entry, ['generator', 'out', 'file', 'split', 'options', 'header'], filePath, `generators[${i}]`);
|
|
842
931
|
const decl = { generator: entry.generator, out: entry.out };
|
|
843
932
|
if (entry.file !== undefined)
|
|
844
933
|
decl.file = String(entry.file);
|
|
@@ -69,6 +69,16 @@ export interface RawModel {
|
|
|
69
69
|
fsName?: string;
|
|
70
70
|
indexes?: RawIndex[];
|
|
71
71
|
sql?: RawSqlConstraints;
|
|
72
|
+
/**
|
|
73
|
+
* Pin this value-object's split output to a fixed directory (relative to the
|
|
74
|
+
* generator `out`), e.g. `_` → `firestore/_/…`. A model with `out` is a
|
|
75
|
+
* placement-scoped value object: it is emitted only at this location by the
|
|
76
|
+
* owning split generator (firestore) and excluded from the default
|
|
77
|
+
* typescript/zod barrels. Split layouts only.
|
|
78
|
+
*/
|
|
79
|
+
out?: string;
|
|
80
|
+
/** File name for a placement-pinned value object (default: the `out` dir's index style). */
|
|
81
|
+
file?: string;
|
|
72
82
|
}
|
|
73
83
|
export interface RawOperation {
|
|
74
84
|
description?: string;
|
|
@@ -212,12 +222,18 @@ export interface RawFirestoreDoc {
|
|
|
212
222
|
pick?: string[];
|
|
213
223
|
omit?: string[];
|
|
214
224
|
fields?: Record<string, RawField>;
|
|
215
|
-
|
|
225
|
+
/** Fragments to splice into this projection (their fields are appended). */
|
|
226
|
+
extends?: string[];
|
|
216
227
|
/** Embedded models to host in this projection file even when unreferenced. */
|
|
217
228
|
include?: string[];
|
|
218
229
|
/** Verbatim TypeScript helpers emitted into the projection file. */
|
|
219
230
|
helpers?: string;
|
|
220
231
|
}
|
|
232
|
+
/** A reusable named group of fields, spliced into a consumer via `extends`. */
|
|
233
|
+
export interface RawFragment {
|
|
234
|
+
description?: string;
|
|
235
|
+
fields: Record<string, RawField>;
|
|
236
|
+
}
|
|
221
237
|
export interface RawUnion {
|
|
222
238
|
description?: string;
|
|
223
239
|
discriminant: string;
|
|
@@ -250,7 +266,6 @@ export interface RawContract {
|
|
|
250
266
|
generatorDecls?: RawGeneratorDecl[];
|
|
251
267
|
/** Section-level generator defaults (`apis:/tasks:/events:` → `defaults`). */
|
|
252
268
|
sectionDefaults?: RawSectionDefaults;
|
|
253
|
-
version: number;
|
|
254
269
|
/** Raw header text prepended to generated files (`default` = built-in banner). */
|
|
255
270
|
header?: string;
|
|
256
271
|
project?: RawProject;
|
|
@@ -265,5 +280,6 @@ export interface RawContract {
|
|
|
265
280
|
firestore: Record<string, RawFirestoreDoc>;
|
|
266
281
|
unions: Record<string, RawUnion>;
|
|
267
282
|
envelopes: Record<string, RawEnvelope>;
|
|
283
|
+
fragments: Record<string, RawFragment>;
|
|
268
284
|
}
|
|
269
285
|
//# sourceMappingURL=raw-document.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"raw-document.d.ts","sourceRoot":"","sources":["../../../../src/lib/_internal/parser/raw-document.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,wEAAwE;IACxE,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,EAAE,CAAC,EAAE,OAAO,CAAA;IACZ,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IAEpB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6FAA6F;IAC7F,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,WAAW,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACxE,OAAO,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;CACnE;AAED,MAAM,WAAW,QAAQ;IACvB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IAChC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,QAAQ,EAAE,CAAA;IACpB,GAAG,CAAC,EAAE,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"raw-document.d.ts","sourceRoot":"","sources":["../../../../src/lib/_internal/parser/raw-document.ts"],"names":[],"mappings":"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"}
|
|
@@ -28,5 +28,44 @@ export declare const apis: ValidationRule;
|
|
|
28
28
|
export declare const firestore: ValidationRule;
|
|
29
29
|
/** Union variants must be known models, each carrying the discriminant field. */
|
|
30
30
|
export declare const unions: ValidationRule;
|
|
31
|
+
/**
|
|
32
|
+
* A firestore doc's `extends` must reference a declared fragment. An unknown
|
|
33
|
+
* name would otherwise resolve to no fields and silently drop the shared
|
|
34
|
+
* columns (`extends: [metaa]` → no `_meta_`), the exact silent-coercion class
|
|
35
|
+
* the contract-is-truth rules exist to kill.
|
|
36
|
+
*/
|
|
37
|
+
export declare const fragmentRefs: ValidationRule;
|
|
38
|
+
/**
|
|
39
|
+
* Type names must be unique within every output namespace — the export surface
|
|
40
|
+
* where generated identifiers converge (a split layout still merges into one
|
|
41
|
+
* barrel, so physical files are irrelevant). Renames (`gqlName` / `fsName`)
|
|
42
|
+
* deliberately move a type between namespaces, so each namespace is checked
|
|
43
|
+
* independently against its *effective* names:
|
|
44
|
+
*
|
|
45
|
+
* - TypeScript types module: model/enum/union logical names, enum const
|
|
46
|
+
* (`CONSTANT_CASE`) and `…Key` companions, plus the reserved `Json` type
|
|
47
|
+
* - zod schemas module: logical names and their `…Schema` companions
|
|
48
|
+
* - unions module: union names/schemas plus the variant schemas it imports
|
|
49
|
+
* - firestore module: doc names, co-located enums/embedded models under
|
|
50
|
+
* `fsName ?? name`, plus the `FIRESTORE_DATABASES` runtime
|
|
51
|
+
*
|
|
52
|
+
* GraphQL names are checked separately ({@link graphqlNameCollisions}) because
|
|
53
|
+
* that namespace is scoped per data-connect-graphql declaration, not global.
|
|
54
|
+
*
|
|
55
|
+
* Same-kind duplicates are already DUPLICATE_DEFINITION at merge time; this
|
|
56
|
+
* rule closes every cross-kind and derived-identifier hole. Each colliding
|
|
57
|
+
* definition pair is reported once (the first namespace that trips).
|
|
58
|
+
*/
|
|
59
|
+
export declare const nameCollisions: ValidationRule;
|
|
60
|
+
/**
|
|
61
|
+
* GraphQL name uniqueness under `gqlName ?? name`. Unlike {@link nameCollisions}
|
|
62
|
+
* this is NOT a default rule: a GraphQL schema exists per `data-connect-graphql`
|
|
63
|
+
* declaration, scoped to the declaring yml's import subtree — distinct services
|
|
64
|
+
* may intentionally reuse a gqlName (e.g. a `T2…` logical name mapped back to
|
|
65
|
+
* the plain name inside its own service). The compiler runs this check only
|
|
66
|
+
* when the entry document itself declares a GraphQL-emitting generator, i.e.
|
|
67
|
+
* exactly at the scope the schema is generated from.
|
|
68
|
+
*/
|
|
69
|
+
export declare const graphqlNameCollisions: ValidationRule;
|
|
31
70
|
export declare const DEFAULT_RULES: ValidationRule[];
|
|
32
71
|
//# sourceMappingURL=rules.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../../src/lib/_internal/validation/rules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAkB,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../../src/lib/_internal/validation/rules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAkB,MAAM,mBAAmB,CAAA;AAG9D,OAAO,EAA2B,EAAE,EAAgB,MAAM,aAAa,CAAA;AAEvE;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,UAAU,EAAE,CAAA;AAIrD,uEAAuE;AACvE,eAAO,MAAM,eAAe,EAAE,cAU3B,CAAA;AAEH,6CAA6C;AAC7C,eAAO,MAAM,UAAU,EAAE,cAQpB,CAAA;AAEL,oCAAoC;AACpC,eAAO,MAAM,mBAAmB,EAAE,cAgB9B,CAAA;AAEJ,kFAAkF;AAClF,eAAO,MAAM,UAAU,EAAE,cAiCxB,CAAA;AAED,iFAAiF;AACjF,eAAO,MAAM,QAAQ,EAAE,cA+BnB,CAAA;AAEJ,mEAAmE;AACnE,eAAO,MAAM,mBAAmB,EAAE,cAkC9B,CAAA;AAEJ,mEAAmE;AACnE,eAAO,MAAM,cAAc,EAAE,cAU1B,CAAA;AAEH,mGAAmG;AACnG,eAAO,MAAM,UAAU,EAAE,cA+ErB,CAAA;AAEJ,uFAAuF;AACvF,eAAO,MAAM,IAAI,EAAE,cAYf,CAAA;AAEJ,wFAAwF;AACxF,eAAO,MAAM,SAAS,EAAE,cA+BpB,CAAA;AAEJ,iFAAiF;AACjF,eAAO,MAAM,MAAM,EAAE,cAoBjB,CAAA;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,cAUxB,CAAA;AAaH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,cAAc,EAAE,cA+E5B,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,EAAE,cAmBnC,CAAA;AAED,eAAO,MAAM,aAAa,EAAE,cAAc,EAczC,CAAA"}
|