firebase-contract 0.1.0-rc.9 → 0.1.1

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.
Files changed (78) hide show
  1. package/README.md +140 -63
  2. package/dist/lib/_internal/compiler/compiler.d.ts.map +1 -1
  3. package/dist/lib/_internal/compiler/compiler.js +50 -21
  4. package/dist/lib/_internal/generators/api/api-dto-generator.d.ts.map +1 -1
  5. package/dist/lib/_internal/generators/api/api-dto-generator.js +1 -8
  6. package/dist/lib/_internal/generators/api/api-types-generator.d.ts.map +1 -1
  7. package/dist/lib/_internal/generators/api/api-types-generator.js +11 -5
  8. package/dist/lib/_internal/generators/api/task-payload-generator.js +3 -3
  9. package/dist/lib/_internal/generators/data-connect/graphql-generator.d.ts +0 -7
  10. package/dist/lib/_internal/generators/data-connect/graphql-generator.d.ts.map +1 -1
  11. package/dist/lib/_internal/generators/data-connect/graphql-generator.js +5 -4
  12. package/dist/lib/_internal/generators/data-connect/operations-generator.d.ts +0 -7
  13. package/dist/lib/_internal/generators/data-connect/operations-generator.d.ts.map +1 -1
  14. package/dist/lib/_internal/generators/data-connect/operations-generator.js +9 -8
  15. package/dist/lib/_internal/generators/firestore/firestore-projection-generator.d.ts.map +1 -1
  16. package/dist/lib/_internal/generators/firestore/firestore-projection-generator.js +7 -22
  17. package/dist/lib/_internal/generators/firestore/firestore-split-generator.d.ts +1 -1
  18. package/dist/lib/_internal/generators/firestore/firestore-split-generator.d.ts.map +1 -1
  19. package/dist/lib/_internal/generators/firestore/firestore-split-generator.js +69 -47
  20. package/dist/lib/_internal/generators/generator.d.ts +2 -0
  21. package/dist/lib/_internal/generators/generator.d.ts.map +1 -1
  22. package/dist/lib/_internal/generators/index.d.ts +2 -5
  23. package/dist/lib/_internal/generators/index.d.ts.map +1 -1
  24. package/dist/lib/_internal/generators/index.js +4 -15
  25. package/dist/lib/_internal/generators/support/jsdoc.d.ts +3 -0
  26. package/dist/lib/_internal/generators/support/jsdoc.d.ts.map +1 -0
  27. package/dist/lib/_internal/generators/support/jsdoc.js +9 -0
  28. package/dist/lib/_internal/generators/support/split-variant.d.ts +9 -0
  29. package/dist/lib/_internal/generators/support/split-variant.d.ts.map +1 -0
  30. package/dist/lib/_internal/generators/support/split-variant.js +13 -0
  31. package/dist/lib/_internal/generators/support/split.d.ts +1 -1
  32. package/dist/lib/_internal/generators/support/split.d.ts.map +1 -1
  33. package/dist/lib/_internal/generators/support/split.js +3 -2
  34. package/dist/lib/_internal/generators/typescript/render.d.ts +15 -0
  35. package/dist/lib/_internal/generators/typescript/render.d.ts.map +1 -0
  36. package/dist/lib/_internal/generators/typescript/render.js +92 -0
  37. package/dist/lib/_internal/generators/typescript/typescript-generator.d.ts +2 -1
  38. package/dist/lib/_internal/generators/typescript/typescript-generator.d.ts.map +1 -1
  39. package/dist/lib/_internal/generators/typescript/typescript-generator.js +12 -78
  40. package/dist/lib/_internal/generators/typescript/typescript-split-generator.d.ts +1 -1
  41. package/dist/lib/_internal/generators/typescript/typescript-split-generator.d.ts.map +1 -1
  42. package/dist/lib/_internal/generators/typescript/typescript-split-generator.js +5 -85
  43. package/dist/lib/_internal/generators/zod/render.d.ts +12 -0
  44. package/dist/lib/_internal/generators/zod/render.d.ts.map +1 -0
  45. package/dist/lib/_internal/generators/zod/render.js +59 -0
  46. package/dist/lib/_internal/generators/zod/zod-generator.d.ts +2 -1
  47. package/dist/lib/_internal/generators/zod/zod-generator.d.ts.map +1 -1
  48. package/dist/lib/_internal/generators/zod/zod-generator.js +11 -55
  49. package/dist/lib/_internal/generators/zod/zod-split-generator.d.ts +1 -1
  50. package/dist/lib/_internal/generators/zod/zod-split-generator.d.ts.map +1 -1
  51. package/dist/lib/_internal/generators/zod/zod-split-generator.js +4 -56
  52. package/dist/lib/_internal/ir/build-ir.d.ts.map +1 -1
  53. package/dist/lib/_internal/ir/build-ir.js +93 -8
  54. package/dist/lib/_internal/ir/ir.d.ts +18 -5
  55. package/dist/lib/_internal/ir/ir.d.ts.map +1 -1
  56. package/dist/lib/_internal/ir/ir.js +1 -0
  57. package/dist/lib/_internal/parser/parse.d.ts +5 -3
  58. package/dist/lib/_internal/parser/parse.d.ts.map +1 -1
  59. package/dist/lib/_internal/parser/parse.js +103 -14
  60. package/dist/lib/_internal/parser/raw-document.d.ts +18 -2
  61. package/dist/lib/_internal/parser/raw-document.d.ts.map +1 -1
  62. package/dist/lib/_internal/resolver/import-resolver.js +1 -1
  63. package/dist/lib/_internal/validation/rules.d.ts +39 -0
  64. package/dist/lib/_internal/validation/rules.d.ts.map +1 -1
  65. package/dist/lib/_internal/validation/rules.js +133 -1
  66. package/dist/lib/cli/commands/generate.d.ts.map +1 -1
  67. package/dist/lib/cli/commands/generate.js +6 -4
  68. package/dist/lib/cli/commands/index.d.ts.map +1 -1
  69. package/dist/lib/cli/commands/index.js +2 -0
  70. package/dist/lib/cli/commands/init.d.ts.map +1 -1
  71. package/dist/lib/cli/commands/init.js +2 -18
  72. package/dist/lib/cli/commands/where.d.ts +3 -0
  73. package/dist/lib/cli/commands/where.d.ts.map +1 -0
  74. package/dist/lib/cli/commands/where.js +57 -0
  75. package/dist/lib/cli/config.d.ts +3 -2
  76. package/dist/lib/cli/config.d.ts.map +1 -1
  77. package/dist/lib/cli/config.js +3 -0
  78. 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
- for (const k of ['signature', 'args', 'data', 'orderBy', 'auth', 'key', 'and', 'where']) {
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
- // `connector: app` (single) or `connectors: [app, api]` (multiple).
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.meta !== undefined)
559
- doc.meta = Boolean(raw.meta);
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}; semantic problems are left
650
- * for validation.
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 version = typeof doc.version === 'number' ? doc.version : 1;
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
- meta?: boolean;
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":"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"}
1
+ {"version":3,"file":"raw-document.d.ts","sourceRoot":"","sources":["../../../../src/lib/_internal/parser/raw-document.ts"],"names":[],"mappings":"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"}
@@ -46,7 +46,7 @@ export const resolveImports = (entryPath, loader) => {
46
46
  }
47
47
  let document;
48
48
  try {
49
- document = parseContract(content, id);
49
+ document = parseContract(content, id, diagnostics);
50
50
  }
51
51
  catch (thrown) {
52
52
  collectFrom(thrown);
@@ -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;AAC9D,OAAO,EAAa,EAAE,EAAgB,MAAM,aAAa,CAAA;AAEzD;;;;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,eAAO,MAAM,aAAa,EAAE,cAAc,EAYzC,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"}