firebase-contract 0.1.0-rc.1 → 0.1.0-rc.10

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 (82) hide show
  1. package/README.md +191 -83
  2. package/dist/lib/_internal/compiler/compiler.d.ts +11 -4
  3. package/dist/lib/_internal/compiler/compiler.d.ts.map +1 -1
  4. package/dist/lib/_internal/compiler/compiler.js +257 -25
  5. package/dist/lib/_internal/compiler/header-vars.d.ts +41 -0
  6. package/dist/lib/_internal/compiler/header-vars.d.ts.map +1 -0
  7. package/dist/lib/_internal/compiler/header-vars.js +117 -0
  8. package/dist/lib/_internal/generators/api/api-dto-generator.d.ts +0 -5
  9. package/dist/lib/_internal/generators/api/api-dto-generator.d.ts.map +1 -1
  10. package/dist/lib/_internal/generators/api/api-dto-generator.js +36 -14
  11. package/dist/lib/_internal/generators/api/api-types-generator.d.ts +0 -5
  12. package/dist/lib/_internal/generators/api/api-types-generator.d.ts.map +1 -1
  13. package/dist/lib/_internal/generators/api/api-types-generator.js +29 -18
  14. package/dist/lib/_internal/generators/api/api-validation-generator.d.ts +0 -4
  15. package/dist/lib/_internal/generators/api/api-validation-generator.d.ts.map +1 -1
  16. package/dist/lib/_internal/generators/api/api-validation-generator.js +38 -9
  17. package/dist/lib/_internal/generators/api/task-payload-generator.d.ts +0 -6
  18. package/dist/lib/_internal/generators/api/task-payload-generator.d.ts.map +1 -1
  19. package/dist/lib/_internal/generators/api/task-payload-generator.js +33 -17
  20. package/dist/lib/_internal/generators/config/config-generator.d.ts.map +1 -1
  21. package/dist/lib/_internal/generators/config/config-generator.js +2 -1
  22. package/dist/lib/_internal/generators/data-connect/adapter-generator.d.ts.map +1 -1
  23. package/dist/lib/_internal/generators/data-connect/adapter-generator.js +3 -2
  24. package/dist/lib/_internal/generators/data-connect/graphql-generator.d.ts +0 -7
  25. package/dist/lib/_internal/generators/data-connect/graphql-generator.d.ts.map +1 -1
  26. package/dist/lib/_internal/generators/data-connect/graphql-generator.js +7 -5
  27. package/dist/lib/_internal/generators/data-connect/operations-generator.d.ts +0 -7
  28. package/dist/lib/_internal/generators/data-connect/operations-generator.d.ts.map +1 -1
  29. package/dist/lib/_internal/generators/data-connect/operations-generator.js +9 -8
  30. package/dist/lib/_internal/generators/firestore/firestore-projection-generator.d.ts.map +1 -1
  31. package/dist/lib/_internal/generators/firestore/firestore-projection-generator.js +6 -3
  32. package/dist/lib/_internal/generators/firestore/firestore-split-generator.d.ts +1 -1
  33. package/dist/lib/_internal/generators/firestore/firestore-split-generator.d.ts.map +1 -1
  34. package/dist/lib/_internal/generators/firestore/firestore-split-generator.js +5 -4
  35. package/dist/lib/_internal/generators/firestore/firestore-type-generator.d.ts.map +1 -1
  36. package/dist/lib/_internal/generators/firestore/firestore-type-generator.js +2 -1
  37. package/dist/lib/_internal/generators/generator.d.ts +38 -0
  38. package/dist/lib/_internal/generators/generator.d.ts.map +1 -1
  39. package/dist/lib/_internal/generators/generator.js +7 -1
  40. package/dist/lib/_internal/generators/id/id-codec-generator.d.ts.map +1 -1
  41. package/dist/lib/_internal/generators/id/id-codec-generator.js +4 -3
  42. package/dist/lib/_internal/generators/index.d.ts +2 -5
  43. package/dist/lib/_internal/generators/index.d.ts.map +1 -1
  44. package/dist/lib/_internal/generators/index.js +4 -15
  45. package/dist/lib/_internal/generators/sql/sql-migration-generator.d.ts +2 -1
  46. package/dist/lib/_internal/generators/sql/sql-migration-generator.d.ts.map +1 -1
  47. package/dist/lib/_internal/generators/sql/sql-migration-generator.js +13 -5
  48. package/dist/lib/_internal/generators/support/header.d.ts.map +1 -1
  49. package/dist/lib/_internal/generators/support/header.js +2 -0
  50. package/dist/lib/_internal/generators/support/naming.d.ts +1 -0
  51. package/dist/lib/_internal/generators/support/naming.d.ts.map +1 -1
  52. package/dist/lib/_internal/generators/support/naming.js +3 -0
  53. package/dist/lib/_internal/generators/support/split-variant.d.ts +9 -0
  54. package/dist/lib/_internal/generators/support/split-variant.d.ts.map +1 -0
  55. package/dist/lib/_internal/generators/support/split-variant.js +13 -0
  56. package/dist/lib/_internal/generators/support/templates.d.ts +36 -0
  57. package/dist/lib/_internal/generators/support/templates.d.ts.map +1 -0
  58. package/dist/lib/_internal/generators/support/templates.js +50 -0
  59. package/dist/lib/_internal/generators/typescript/typescript-generator.d.ts.map +1 -1
  60. package/dist/lib/_internal/generators/typescript/typescript-generator.js +6 -3
  61. package/dist/lib/_internal/generators/typescript/typescript-split-generator.d.ts +1 -1
  62. package/dist/lib/_internal/generators/typescript/typescript-split-generator.d.ts.map +1 -1
  63. package/dist/lib/_internal/generators/typescript/typescript-split-generator.js +4 -3
  64. package/dist/lib/_internal/generators/union/union-generator.d.ts.map +1 -1
  65. package/dist/lib/_internal/generators/union/union-generator.js +6 -5
  66. package/dist/lib/_internal/generators/zod/zod-generator.d.ts.map +1 -1
  67. package/dist/lib/_internal/generators/zod/zod-generator.js +6 -3
  68. package/dist/lib/_internal/generators/zod/zod-split-generator.d.ts +1 -1
  69. package/dist/lib/_internal/generators/zod/zod-split-generator.d.ts.map +1 -1
  70. package/dist/lib/_internal/generators/zod/zod-split-generator.js +4 -3
  71. package/dist/lib/_internal/ir/build-ir.d.ts.map +1 -1
  72. package/dist/lib/_internal/ir/build-ir.js +2 -0
  73. package/dist/lib/_internal/ir/ir.d.ts +2 -0
  74. package/dist/lib/_internal/ir/ir.d.ts.map +1 -1
  75. package/dist/lib/_internal/parser/parse.d.ts.map +1 -1
  76. package/dist/lib/_internal/parser/parse.js +194 -17
  77. package/dist/lib/_internal/parser/raw-document.d.ts +46 -7
  78. package/dist/lib/_internal/parser/raw-document.d.ts.map +1 -1
  79. package/dist/lib/cli/commands/generate.js +1 -1
  80. package/dist/lib/cli/commands/init.d.ts.map +1 -1
  81. package/dist/lib/cli/commands/init.js +5 -0
  82. package/package.json +1 -1
package/README.md CHANGED
@@ -32,36 +32,94 @@ Provides the `firebase-contract` (alias `fbc`) CLI and a programmatic API.
32
32
  ```bash
33
33
  fbc init # scaffold contract.yml + firebase-contract.json
34
34
  fbc validate # parse, resolve imports, semantically validate
35
- fbc generate # run every `generate:` target declared in the contract graph
35
+ fbc generate # run every generator declared across the contract graph
36
36
  fbc inspect # print the normalized IR (debugging)
37
37
  ```
38
38
 
39
39
  ### One-command generation
40
40
 
41
- Each contract file can declare its own outputs in a `generate:` section —
42
- out dirs are relative to that yml file:
41
+ Each contract file declares the generators it uses in a top-level
42
+ `generators:` block — a name plus an output template. Declaring a
43
+ **document-scoped** generator (typescript, zod, …) runs it once for
44
+ that yml; **api-scoped** generators (api-types, api-validation, api-dto,
45
+ task-payloads) run for the entries that opt in (see below):
46
+
47
+ ```yaml
48
+ # contract.yml (root)
49
+ project:
50
+ aliases:
51
+ "#contracts/*": libs/contracts/src/* # out templates may target aliases
52
+ generators:
53
+ - { generator: typescript, out: "#contracts", split: true }
54
+ - { generator: api-types, out: "#contracts/api-types/{api-name}" }
55
+ imports:
56
+ - ./apps/shop/data-connect/schema.yml
57
+ ```
43
58
 
44
59
  ```yaml
45
60
  # apps/shop/data-connect/schema.yml
46
- generate:
47
- - { out: src, generators: [data-connect-graphql-split] }
48
- - { out: ., generators: [sql-migrations] }
61
+ generators:
62
+ - { generator: data-connect-graphql, out: src, split: true }
63
+ - { generator: sql-migrations, out: . }
49
64
  ```
50
65
 
66
+ - `out` resolves relative to the declaring yml; `#alias/...` prefixes resolve
67
+ through the **root** yml's `project.aliases` (relative to the root).
68
+ - Api-scoped templates may use `{api-name}` (kebab-cased name) and `{path}`
69
+ (REST path with `{param}` segments dropped).
70
+ - Entries reference declarations by name — nearest first (same yml → root).
71
+
72
+ #### Output settings: `file`, `split`, `options`, `header`
73
+
74
+ Every declaration (and any entry-level application) can reshape the output —
75
+ the defaults reproduce each generator's built-in layout, so omitting them
76
+ changes nothing:
77
+
51
78
  ```yaml
52
- # contract.yml (root)
53
- generate:
54
- - out: libs/contracts/src
55
- generators: [typescript-split, zod-split, firestore-split, id-codecs]
56
- imports:
57
- - ./apps/shop/data-connect/schema.yml
79
+ generators:
80
+ - generator: api-dto
81
+ out: "src/entries/{path}/dto"
82
+ file: "{api-name}.dto.ts" # file-name template (default shown)
83
+ split: true # one file per api (api-dto's default)
84
+ - generator: api-types
85
+ out: "#contracts/api-types"
86
+ file: "{api-name}.types.ts" # override the bundled default with per-api files
87
+ split: true
88
+ options:
89
+ typesImport: "../types" # where `import type { … } from '…'` points
90
+ - generator: typescript
91
+ out: "#contracts"
92
+ file: models.ts # rename a single-file/barrel output
93
+ split: true # document scope: per-table split layout
58
94
  ```
59
95
 
60
- `fbc generate contract.yml` then materializes **all** targets across the whole
61
- import graph in one run. Passing `-o`/`-g` switches to single-target mode
96
+ - **`file`** — output file name. Api scope: a template (`{api-name}`/`{path}`
97
+ allowed when `split: true`). Document scope: renames the single output file,
98
+ or the barrel of a split layout.
99
+ - **`split`** — api scope: `true` emits one file per api (the `file` template
100
+ must contain a placeholder), `false` bundles everything into one `file`.
101
+ Document scope: `true` selects the generator's per-item split layout
102
+ (typescript, zod, firestore, data-connect-graphql, data-connect-operations)
103
+ and errors for generators without one.
104
+ - **`options`** — free-form string map passed through to the generator.
105
+ Currently: `typesImport` (api-types, task-payloads, data-connect-operations)
106
+ overrides the `./types` import path.
107
+ - **`header`** — per-generator banner override: `default` for the built-in
108
+ AUTO-GENERATED banner, any text for a custom comment, `""` to suppress the
109
+ banner for this generator. Wins over the contract-level `header:` and the
110
+ CLI `--header` flag.
111
+ - Defaults per generator: `api-types` → `api-types.ts` bundled, `api-validation`
112
+ → `api-validation.ts` bundled, `task-payloads` → `task-payloads.ts` bundled,
113
+ `api-dto` → `{api-name}.dto.ts` split.
114
+ - Entry-level settings override the declaration, which overrides the
115
+ generator's default (same nearest-first rule as `out`).
116
+
117
+ `fbc generate contract.yml` materializes **all** declared outputs across the
118
+ whole import graph in one run. Passing `-o`/`-g` switches to single-target mode
62
119
  (`fbc generate <entry> -o <dir> -g typescript,zod`), and
63
120
  `firebase-contract.json` (`entry`, `outDir`, `generators`) can hold defaults.
64
121
 
122
+
65
123
  ### Generated-file headers
66
124
 
67
125
  By default no banner is emitted. Opt in per run or per contract:
@@ -75,6 +133,34 @@ fbc generate --header "Managed by fbc" # custom text (multi-line ok)
75
133
  header: default # or any text; the CLI --header flag wins
76
134
  ```
77
135
 
136
+ Header text (contract `header:`, per-generator `header`, CLI `--header`)
137
+ supports `${...}` template variables:
138
+
139
+ | Variable | Value |
140
+ | --- | --- |
141
+ | `${rootContractPath}` | entry (root) yml path, relative to the root yml's directory |
142
+ | `${currentContractPath}` | the yml the output is generated from |
143
+ | `${allContractPath}` | import chain root → current, joined with ` -> ` |
144
+ | `${generatedAt}` | date the file was **first** generated (carried over on regenerate) |
145
+ | `${updatedAt}` | date the content **last changed** |
146
+
147
+ A regenerate that produces identical content keeps both dates and reproduces
148
+ the file byte-for-byte, so `--check` stays drift-free; when content changes,
149
+ `generatedAt` is carried over from the existing file and only `updatedAt`
150
+ moves. Date tokens accept an optional format — `${updatedAt:yyyy-mm-dd HH:mm:ss}`
151
+ — with runs `yyyy`/`yy`, `MM`, `dd`, `HH`, `ss`, and `mm` meaning month before
152
+ any hour token / minute after one (both `yyyy-mm-dd` and `HH:mm` read
153
+ naturally). Default: `yyyy-MM-dd`.
154
+
155
+ The `default` banner includes the source and dates:
156
+
157
+ ```
158
+ // AUTO-GENERATED by firebase-contract. Do not edit by hand.
159
+ // Source: ${currentContractPath}
160
+ // Generated: ${generatedAt} / Updated: ${updatedAt}
161
+ // Regenerate with: fbc generate
162
+ ```
163
+
78
164
  Comment syntax adapts per file type (`//` for TS, `#` for GraphQL/YAML-ish,
79
165
  `--` for SQL).
80
166
 
@@ -162,24 +248,24 @@ models:
162
248
 
163
249
  | option | meaning |
164
250
  | ----------------------------------- | -------------------------------------------------------- |
165
- | `type` | scalar name, or an enum/model name |
166
- | `optional` | value may be absent (`field?`) |
167
- | `list` | value is an array of `type` |
168
- | `id` | marks the (single) primary identifier |
169
- | `unique` | field-level unique → `@unique` |
170
- | `relation` | model-typed field is a foreign-key relation (see below) |
171
- | `col` | Data Connect column dataType (Int64 PKs default to `bigserial`) |
172
- | `default` | `@default(expr: …)` on the DC column |
173
- | `literal` | pin to one literal value (union discriminant tags) |
174
- | `nullable` | value may be `null` (`.nullable()` / `\| null`) |
175
- | `description` | doc comment carried into generated output |
176
- | `jsdoc` | render the description as a JSDoc block (Firestore fields) |
251
+ | `type` | document | scalar name, or an enum/model name |
252
+ | `optional` | document | value may be absent (`field?`) |
253
+ | `list` | document | value is an array of `type` |
254
+ | `id` | document | marks the (single) primary identifier |
255
+ | `unique` | document | field-level unique → `@unique` |
256
+ | `relation` | document | model-typed field is a foreign-key relation (see below) |
257
+ | `col` | document | Data Connect column dataType (Int64 PKs default to `bigserial`) |
258
+ | `default` | document | `@default(expr: …)` on the DC column |
259
+ | `literal` | document | pin to one literal value (union discriminant tags) |
260
+ | `nullable` | document | value may be `null` (`.nullable()` / `\| null`) |
261
+ | `description` | document | doc comment carried into generated output |
262
+ | `jsdoc` | document | render the description as a JSDoc block (Firestore fields) |
177
263
  | **constraints** → | |
178
- | `min` / `max` | numeric bounds |
179
- | `minLength` / `maxLength` | string/array length bounds |
180
- | `nonempty` | non-empty string/array |
181
- | `pattern` | regex the string must match |
182
- | `email` / `url` | string format |
264
+ | `min` / `max` | document | numeric bounds |
265
+ | `minLength` / `maxLength` | document | string/array length bounds |
266
+ | `nonempty` | document | non-empty string/array |
267
+ | `pattern` | document | regex the string must match |
268
+ | `email` / `url` | document | string format |
183
269
 
184
270
  Constraints flow into the Zod schemas, the API request validation, and the
185
271
  class-validator DTOs.
@@ -188,14 +274,14 @@ class-validator DTOs.
188
274
 
189
275
  | option | meaning |
190
276
  | ------------ | ------------------------------------------------------------------ |
191
- | `key` | composite primary key field names (else the `id: true` field) |
192
- | `table` | table name override (default: snake_case pluralization) |
193
- | `gqlName` | GraphQL type name override |
194
- | `fsName` | Firestore-side rename (avoid collisions with table models) |
195
- | `directives` | `multi` = each type-level directive on its own line |
196
- | `footer` | trailing comment block after the closing `}` in the schema file |
197
- | `indexes` | composite `@index`/`@unique` (`{ fields, name?, unique?, expand? }` — `expand` renders args one per line) |
198
- | `sql` | raw SQL constraints (see [SQL migrations](#sql-migrations)) |
277
+ | `key` | document | composite primary key field names (else the `id: true` field) |
278
+ | `table` | document | table name override (default: snake_case pluralization) |
279
+ | `gqlName` | document | GraphQL type name override |
280
+ | `fsName` | document | Firestore-side rename (avoid collisions with table models) |
281
+ | `directives` | document | `multi` = each type-level directive on its own line |
282
+ | `footer` | document | trailing comment block after the closing `}` in the schema file |
283
+ | `indexes` | document | composite `@index`/`@unique` (`{ fields, name?, unique?, expand? }` — `expand` renders args one per line) |
284
+ | `sql` | document | raw SQL constraints (see [SQL migrations](#sql-migrations)) |
199
285
 
200
286
  ### Embedded vs relation
201
287
 
@@ -273,14 +359,14 @@ Everything below exists to reproduce real hand-written `.gql` files byte-for-byt
273
359
 
274
360
  | option | meaning |
275
361
  | --- | --- |
276
- | `gqlName` | rendered operation name (the yml key stays unique across services) |
277
- | `footer` | trailing `# …` comment block after the operation |
278
- | `raw` | emit the operation body verbatim (multi-model queries, `_or` keyset cursors — field checks are skipped) |
279
- | `single: id \| key` | single-row lookup (`product(id: $id)` / `product(key: { … })`) |
280
- | `keyArg` / `keyVars` | update/delete key argument form and variable renames |
281
- | `whereAnd: true` | render conditions as an `_and: [ … ]` array |
282
- | `entityDir` | override the `operations/<entity>/` output directory |
283
- | `style` | formatting hints: `signature`, `args`, `data`, `orderBy`, `auth`, `key`, `and`, `where` (`inline`/`multi`/`compact`/`bare`) |
362
+ | `gqlName` | document | rendered operation name (the yml key stays unique across services) |
363
+ | `footer` | document | trailing `# …` comment block after the operation |
364
+ | `raw` | document | emit the operation body verbatim (multi-model queries, `_or` keyset cursors — field checks are skipped) |
365
+ | `single: id \| document | key` | single-row lookup (`product(id: $id)` / `product(key: { … })`) |
366
+ | `keyArg` / `keyVars` | document | update/delete key argument form and variable renames |
367
+ | `whereAnd: true` | document | render conditions as an `_and: [ … ]` array |
368
+ | `entityDir` | document | override the `operations/<entity>/` output directory |
369
+ | `style` | document | formatting hints: `signature`, `args`, `data`, `orderBy`, `auth`, `key`, `and`, `where` (`inline`/`multi`/`compact`/`bare`) |
284
370
 
285
371
  Inputs support `var` (variable rename), `required` (override optionality),
286
372
  `literal` (fixed value, no variable), `flat` (write the FK column directly),
@@ -296,11 +382,13 @@ name as long as their connector sets don't overlap.
296
382
 
297
383
  ## API endpoints
298
384
 
299
- Model application endpoints (Cloud Task / callable / https / pubsub). Generates
300
- request/response types (`api-types`), request-validation Zod (`api-validation`),
301
- class-validator DTOs (`api-dto`), and — for `task`/`pubsub` — payload contracts
302
- (`task-payloads`). A payload references a model or declares inline fields; a void
303
- response maps to `void`.
385
+ Model application endpoints in three kind-implied sections — `apis:` (https /
386
+ callable, keyed by REST path), `tasks:` (Cloud Tasks), and `events:` (Pub/Sub).
387
+ The api-scoped generators — request/response types (`api-types`),
388
+ request-validation Zod (`api-validation`), class-validator DTOs (`api-dto`),
389
+ and payload contracts (`task-payloads`) — run for the entries that opt in via
390
+ the section `defaults` or the entry's own `generators:`. A payload references a
391
+ model or declares inline fields; a void response maps to `void`.
304
392
 
305
393
  ```yaml
306
394
  envelopes:
@@ -310,9 +398,10 @@ envelopes:
310
398
  opId: string
311
399
  enqueuedAt: int
312
400
 
313
- apis:
401
+ tasks: # Cloud Tasks (kind implied)
402
+ defaults:
403
+ generators: [task-payloads] # section default: applies to entries below
314
404
  createCatalog:
315
- kind: task # product | callable | https | pubsub
316
405
  envelope: RetryTaskPayload # wraps the product data
317
406
  maxAttempts: 3
318
407
  request:
@@ -322,17 +411,31 @@ apis:
322
411
  response:
323
412
  void: true
324
413
 
414
+ events: # Pub/Sub (kind implied)
325
415
  generateAiResponse:
326
- kind: pubsub
327
416
  topic: ai-review-generate-response
328
417
  timeoutSeconds: 540
329
-
330
- getShopBySlug:
331
- kind: callable
418
+ generators: [task-payloads]
419
+
420
+ apis: # https/callable, keyed by REST path
421
+ defaults:
422
+ generators: [api-types, api-validation]
423
+ /shops/{slug}:
424
+ operationId: getShopBySlug
425
+ kind: callable # https (default) | callable
332
426
  request: { fields: { slug: { type: string, nonempty: true } } }
333
427
  response: { model: Shop }
428
+ generators: # entry-level wins over section defaults;
429
+ - api-types # an inline out overrides the declared template
430
+ - { generator: api-dto, out: "src/entries/{path}" }
334
431
  ```
335
432
 
433
+ Generator application resolves in two tiers — the section `defaults`
434
+ (`apis:/tasks:/events:` → `defaults.generators`) and the entry's own
435
+ `generators:` (which replaces the defaults). `apis:` keys must be REST paths
436
+ (`/...` or `METHOD /...` so the same route can appear once per verb) with an
437
+ `operationId`; tasks and Pub/Sub events live in their own sections.
438
+
336
439
  For `createCatalog` this yields `CreateCatalogTaskData`, `CreateCatalogTaskPayload =
337
440
  RetryTaskPayload<CreateCatalogTaskData>`, and `CREATE_CATALOG_MAX_ATTEMPTS`, plus the
338
441
  request types, Zod schema, and DTO.
@@ -368,7 +471,7 @@ Emits Zod schemas + inferred types, mirroring a hand-written Firestore schema
368
471
  library. (The simpler `firestore-types` generator just re-types *every* model
369
472
  with the Firestore `Timestamp` and does not denormalize.)
370
473
 
371
- With `firestore-split`, fields whose Zod chain is **identical** to the Data
474
+ With `firestore` + `split: true`, fields whose Zod chain is **identical** to the Data
372
475
  Connect schema are reused via `.pick()` — only representation changes are
373
476
  restated:
374
477
 
@@ -446,14 +549,19 @@ project:
446
549
  idCodec:
447
550
  minLength: 8
448
551
  alphabet: <your-shuffled-sqids-alphabet>
552
+ aliases:
553
+ "#contracts/*": libs/contracts/src/*
449
554
  ```
450
555
 
451
556
  - `services` (`name`/`database`) feed the `FIRESTORE_DATABASES` constants in the
452
- `firestore-split` barrel.
557
+ split `firestore` barrel.
453
558
  - `idCodec` pins the Sqids settings as a contract constant; when present, the
454
559
  `id-codecs` generator also emits a self-contained `id-core.ts` (the
455
560
  encode/decode primitives), so nothing about id encoding lives outside the
456
561
  contract.
562
+ - `aliases` maps `#alias/...` out-template prefixes to paths relative to the
563
+ **root** yml, so imported contracts can target shared libs without relative
564
+ path gymnastics (longest prefix wins).
457
565
  - `codebases` / service `location` + `connectors` are consumed by the optional
458
566
  `config` generator (preview), which emits per-service `dataconnect.yaml`,
459
567
  per-connector `connector.yaml`, and the `FIRESTORE_DATABASES` /
@@ -465,32 +573,32 @@ project:
465
573
 
466
574
  # Generators
467
575
 
468
- | name | output | notes |
469
- | ------------------------ | ----------------------------- | ------------------------------------------------------ |
470
- | `typescript` | `types.ts` | interfaces + const/union enums |
471
- | `typescript-split` | `types/<table>.ts` + `types.ts` barrel | one file per table; enums/embedded objects co-located |
472
- | `zod` | `schemas.ts` | `z.object` schemas (constraints, `z.lazy` model refs) |
473
- | `zod-split` | `schemas/<table>.ts` + `schemas.ts` barrel | split variant of `zod` |
474
- | `data-connect-graphql` | `schema.gql` | `type … @table(name, key)`; `@col`/`@unique`/`@index`/`@default` |
475
- | `data-connect-graphql-split` | `schema/<table>.gql` | same schema, one file per table (enums co-located) |
476
- | `data-connect-operations`| `<connector>/operations.gql` + `.ts` | queries/mutations (where ops, orderBy, limit, aggregate, exprs, inc), per connector |
477
- | `data-connect-operations-split` | `<connector>/operations/<entity>/{queries,mutations}.gql` | real Data Connect repo layout; shared types stay in `typescript`/`zod` outputs |
478
- | `data-connect-adapter` | `data-connect-adapters.ts` | convert `Any` rows ⇄ logical types |
479
- | `firestore-types` | `firestore-types.ts` | naive TS types with Firestore `Timestamp` (all models) |
480
- | `firestore` | `firestore.ts` | Firestore projection Zod schemas (derived, denormalized) |
481
- | `firestore-split` | `firestore/<collection>.ts` + `firestore.ts` barrel | one file per projection; `_meta_` under `firestore/_/`; DC-schema `.pick()` reuse; `FIRESTORE_DATABASES` constants in the barrel |
482
- | `api-types` | `api-types.ts` | endpoint request/response types |
483
- | `api-validation` | `api-validation.ts` | endpoint request-validation Zod |
484
- | `api-dto` | `api-dtos.ts` | class-validator DTO classes |
485
- | `task-payloads` | `task-payloads.ts` | envelopes + `*TaskData`/`*TaskPayload` + constants |
486
- | `sql-migrations` | `migrations/constraints.sql` | composite FK / CHECK / index SQL |
487
- | `id-codecs` | `id-codecs.ts` (+ `id-core.ts`) | typed per-entity id encode/decode wrappers; emits the Sqids primitives when `project.idCodec` is set |
488
- | `unions` | `unions.ts` | Zod discriminated unions + TS union types |
489
- | `config` | `dataconnect.yaml`, `connector.yaml`, `constants.ts` | DC configs + sync constants (preview — see [Project config](#project-config)) |
576
+ | name | scope | output | notes |
577
+ | ------------------------ | -------- | ----------------------------- | ------------------------------------------------------ |
578
+ | `typescript` | document | `types.ts`; `split: true` → `types/<table>.ts` + barrel | interfaces + const/union enums; split co-locates enums/embedded objects per table |
579
+ | `zod` | document | `schemas.ts`; `split: true` → `schemas/<table>.ts` + barrel | `z.object` schemas (constraints, `z.lazy` model refs) |
580
+ | `data-connect-graphql` | document | `schema.gql`; `split: true` → `schema/<table>.gql` | `type … @table(name, key)`; `@col`/`@unique`/`@index`/`@default` |
581
+ | `data-connect-operations`| document | `<connector>/operations.gql` + `.ts`; `split: true` → `<connector>/operations/<entity>/{queries,mutations}.gql` | queries/mutations (where ops, orderBy, limit, aggregate, exprs, inc), per connector; split matches the real Data Connect repo layout |
582
+ | `data-connect-adapter` | document | `data-connect-adapters.ts` | convert `Any` rows ⇄ logical types |
583
+ | `firestore-types` | document | `firestore-types.ts` | naive TS types with Firestore `Timestamp` (all models) |
584
+ | `firestore` | document | `firestore.ts`; `split: true` → `firestore/<collection>.ts` + barrel | Firestore projection Zod schemas (derived, denormalized); split adds `_meta_` under `firestore/_/`, DC-schema `.pick()` reuse, `FIRESTORE_DATABASES` constants in the barrel |
585
+ | `api-types` | api | `api-types.ts` | endpoint request/response types |
586
+ | `api-validation` | api | `api-validation.ts` | endpoint request-validation Zod |
587
+ | `api-dto` | api | `<operation>.dto.ts` per api | class-validator DTO classes (NestJS `dto/` convention) |
588
+ | `task-payloads` | api | `task-payloads.ts` | envelopes + `*TaskData`/`*TaskPayload` + constants |
589
+ | `sql-migrations` | document | `migrations/constraints.sql` | composite FK / CHECK / index SQL — idempotent (`IF NOT EXISTS` / `duplicate_object` guard), safe to re-apply whole |
590
+ | `id-codecs` | document | `id-codecs.ts` (+ `id-core.ts`) | typed per-entity id encode/decode wrappers; emits the Sqids primitives when `project.idCodec` is set |
591
+ | `unions` | document | `unions.ts` | Zod discriminated unions + TS union types |
592
+ | `config` | document | `dataconnect.yaml`, `connector.yaml`, `constants.ts` | DC configs + sync constants (preview — see [Project config](#project-config)) |
490
593
 
491
594
  Each generator emits nothing when its section is absent, so a small contract
492
595
  produces a small output. Select a subset with `-g`.
493
596
 
597
+ **Scope** decides how a `generators:` declaration takes effect: `document`
598
+ generators run once for the yml that declares them; `api` generators run only
599
+ for the entries that apply them (section `defaults.generators` → entry
600
+ `generators:`, entry wins).
601
+
494
602
  ### The `Any` boundary
495
603
 
496
604
  Data Connect stores JSON and embedded objects as the `Any` scalar, erasing the
@@ -518,7 +626,7 @@ const result = generate('contract.yml', {
518
626
  write: true,
519
627
  })
520
628
 
521
- // Every `generate:` target declared across the import graph:
629
+ // Every generator declared across the import graph:
522
630
  const all = generateAll('contract.yml', { write: true })
523
631
  ```
524
632
 
@@ -4,6 +4,7 @@ import { RawContract } from '../parser/raw-document.js';
4
4
  import { ModuleLoader } from '../resolver/module-loader.js';
5
5
  import { GeneratedFile, GeneratorContext } from '../generators/generator.js';
6
6
  import { GeneratorRegistry } from '../generators/registry.js';
7
+ import { HeaderPathVars } from './header-vars.js';
7
8
  export interface CompileOptions {
8
9
  /** Override module loading (defaults to the file system). */
9
10
  loader?: ModuleLoader;
@@ -29,6 +30,10 @@ export interface GenerateOptions extends CompileOptions {
29
30
  /** When true, write the generated files to disk. */
30
31
  write?: boolean;
31
32
  context?: GeneratorContext;
33
+ /** Header `${...}` path values; defaults to entry-only (root = current = entry). */
34
+ headerVars?: HeaderPathVars;
35
+ /** Clock for `${generatedAt}`/`${updatedAt}` stamping (tests); defaults to now. */
36
+ now?: Date;
32
37
  }
33
38
  export interface GenerateTargetResult {
34
39
  /** The contract file that declared this target. */
@@ -43,16 +48,18 @@ export interface GenerateAllResult {
43
48
  ok: boolean;
44
49
  }
45
50
  /**
46
- * Run every `generate:` target declared across the entry contract and its
47
- * (transitive) imports — the one-command flow: each contract file states where
48
- * its own outputs go, and `fbc generate <root>` materializes all of them.
49
- * Output dirs resolve relative to the declaring yml file.
51
+ * Run every generator declared across the entry contract and its (transitive)
52
+ * imports — the one-command flow: each contract file declares its generators
53
+ * (`generators:` + section defaults / entry applications) and
54
+ * `fbc generate <root>` materializes all of them. Output dirs resolve relative
55
+ * to the declaring yml (or the root yml for `#alias/...` templates).
50
56
  */
51
57
  export declare const generateAll: (entryPath: string, options?: {
52
58
  registry?: GeneratorRegistry;
53
59
  write?: boolean;
54
60
  context?: GeneratorContext;
55
61
  loader?: ModuleLoader;
62
+ now?: Date;
56
63
  }) => GenerateAllResult;
57
64
  export interface FileDrift {
58
65
  /** Files whose on-disk content differs from the generated content. */
@@ -1 +1 @@
1
- {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../../../src/lib/_internal/compiler/compiler.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAoB,MAAM,mBAAmB,CAAA;AAEhE,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAEvD,OAAO,EAAkB,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAG3E,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAE5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAE7D,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,MAAM,CAAC,EAAE,YAAY,CAAA;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,EAAE,CAAA;IACN,SAAS,EAAE,WAAW,EAAE,CAAA;IACxB,WAAW,EAAE,UAAU,EAAE,CAAA;CAC1B;AAED;;;;;GAKG;AACH,eAAO,MAAM,OAAO,GAAI,WAAW,MAAM,EAAE,UAAS,cAAmB,KAAG,aAUzE,CAAA;AAED,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,MAAM,EAAE,MAAM,CAAA;IACd,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B,oDAAoD;IACpD,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,OAAO,CAAC,EAAE,gBAAgB,CAAA;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,KAAK,EAAE,aAAa,EAAE,CAAA;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,oBAAoB,EAAE,CAAA;IAC/B,WAAW,EAAE,UAAU,EAAE,CAAA;IACzB,EAAE,EAAE,OAAO,CAAA;CACZ;AAED;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GACtB,WAAW,MAAM,EACjB,UAAS;IAAE,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAAC,MAAM,CAAC,EAAE,YAAY,CAAA;CAAO,KACjH,iBA8BF,CAAA;AAED,MAAM,WAAW,SAAS;IACxB,sEAAsE;IACtE,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,mEAAmE;IACnE,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,OAAO,aAAa,EAAE,KAAG,SAUlD,CAAA;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,EAAE,CAAA;IACN,WAAW,EAAE,UAAU,EAAE,CAAA;IACzB,oFAAoF;IACpF,KAAK,EAAE,aAAa,EAAE,CAAA;IACtB,0DAA0D;IAC1D,EAAE,EAAE,OAAO,CAAA;CACZ;AAED;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,WAAW,MAAM,EAAE,SAAS,eAAe,KAAG,cAuCtE,CAAA"}
1
+ {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../../../src/lib/_internal/compiler/compiler.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAoB,MAAM,mBAAmB,CAAA;AAEhE,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAChC,OAAO,EAAU,WAAW,EAAqC,MAAM,2BAA2B,CAAA;AAElG,OAAO,EAAkB,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAG3E,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAI5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,EAEL,cAAc,EAGf,MAAM,kBAAkB,CAAA;AAEzB,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,MAAM,CAAC,EAAE,YAAY,CAAA;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,EAAE,CAAA;IACN,SAAS,EAAE,WAAW,EAAE,CAAA;IACxB,WAAW,EAAE,UAAU,EAAE,CAAA;CAC1B;AAED;;;;;GAKG;AACH,eAAO,MAAM,OAAO,GAAI,WAAW,MAAM,EAAE,UAAS,cAAmB,KAAG,aAUzE,CAAA;AAED,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,MAAM,EAAE,MAAM,CAAA;IACd,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B,oDAAoD;IACpD,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,OAAO,CAAC,EAAE,gBAAgB,CAAA;IAC1B,oFAAoF;IACpF,UAAU,CAAC,EAAE,cAAc,CAAA;IAC3B,mFAAmF;IACnF,GAAG,CAAC,EAAE,IAAI,CAAA;CACX;AAED,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,KAAK,EAAE,aAAa,EAAE,CAAA;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,oBAAoB,EAAE,CAAA;IAC/B,WAAW,EAAE,UAAU,EAAE,CAAA;IACzB,EAAE,EAAE,OAAO,CAAA;CACZ;AA6MD;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,GACtB,WAAW,MAAM,EACjB,UAAS;IACP,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,OAAO,CAAC,EAAE,gBAAgB,CAAA;IAC1B,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,GAAG,CAAC,EAAE,IAAI,CAAA;CACN,KACL,iBA0FF,CAAA;AAED,MAAM,WAAW,SAAS;IACxB,sEAAsE;IACtE,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,mEAAmE;IACnE,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,OAAO,aAAa,EAAE,KAAG,SAUlD,CAAA;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,EAAE,CAAA;IACN,WAAW,EAAE,UAAU,EAAE,CAAA;IACzB,oFAAoF;IACpF,KAAK,EAAE,aAAa,EAAE,CAAA;IACtB,0DAA0D;IAC1D,EAAE,EAAE,OAAO,CAAA;CACZ;AAED;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,WAAW,MAAM,EAAE,SAAS,eAAe,KAAG,cAgEtE,CAAA"}