firebase-contract 0.1.0-rc.1 → 0.1.0-rc.11
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 +191 -83
- package/dist/lib/_internal/compiler/compiler.d.ts +11 -4
- package/dist/lib/_internal/compiler/compiler.d.ts.map +1 -1
- package/dist/lib/_internal/compiler/compiler.js +257 -25
- package/dist/lib/_internal/compiler/header-vars.d.ts +41 -0
- package/dist/lib/_internal/compiler/header-vars.d.ts.map +1 -0
- package/dist/lib/_internal/compiler/header-vars.js +117 -0
- package/dist/lib/_internal/generators/api/api-dto-generator.d.ts +0 -5
- package/dist/lib/_internal/generators/api/api-dto-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/api/api-dto-generator.js +29 -14
- package/dist/lib/_internal/generators/api/api-types-generator.d.ts +0 -5
- package/dist/lib/_internal/generators/api/api-types-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/api/api-types-generator.js +39 -22
- package/dist/lib/_internal/generators/api/api-validation-generator.d.ts +0 -4
- package/dist/lib/_internal/generators/api/api-validation-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/api/api-validation-generator.js +38 -9
- package/dist/lib/_internal/generators/api/task-payload-generator.d.ts +0 -6
- package/dist/lib/_internal/generators/api/task-payload-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/api/task-payload-generator.js +34 -18
- package/dist/lib/_internal/generators/config/config-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/config/config-generator.js +2 -1
- package/dist/lib/_internal/generators/data-connect/adapter-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/data-connect/adapter-generator.js +3 -2
- 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 +7 -5
- 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 +9 -8
- package/dist/lib/_internal/generators/firestore/firestore-projection-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/firestore/firestore-projection-generator.js +6 -3
- 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 +5 -4
- package/dist/lib/_internal/generators/firestore/firestore-type-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/firestore/firestore-type-generator.js +2 -1
- package/dist/lib/_internal/generators/generator.d.ts +38 -0
- package/dist/lib/_internal/generators/generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/generator.js +7 -1
- package/dist/lib/_internal/generators/id/id-codec-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/id/id-codec-generator.js +4 -3
- 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 +13 -5
- package/dist/lib/_internal/generators/support/header.d.ts.map +1 -1
- package/dist/lib/_internal/generators/support/header.js +2 -0
- 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/naming.d.ts +1 -0
- package/dist/lib/_internal/generators/support/naming.d.ts.map +1 -1
- package/dist/lib/_internal/generators/support/naming.js +3 -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/templates.d.ts +36 -0
- package/dist/lib/_internal/generators/support/templates.d.ts.map +1 -0
- package/dist/lib/_internal/generators/support/templates.js +50 -0
- package/dist/lib/_internal/generators/typescript/typescript-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/typescript/typescript-generator.js +6 -3
- 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 -3
- package/dist/lib/_internal/generators/union/union-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/union/union-generator.js +6 -5
- package/dist/lib/_internal/generators/zod/zod-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/zod/zod-generator.js +6 -3
- 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 -3
- package/dist/lib/_internal/ir/build-ir.d.ts.map +1 -1
- package/dist/lib/_internal/ir/build-ir.js +2 -0
- package/dist/lib/_internal/ir/ir.d.ts +2 -0
- package/dist/lib/_internal/ir/ir.d.ts.map +1 -1
- package/dist/lib/_internal/parser/parse.d.ts.map +1 -1
- package/dist/lib/_internal/parser/parse.js +194 -17
- package/dist/lib/_internal/parser/raw-document.d.ts +46 -7
- package/dist/lib/_internal/parser/raw-document.d.ts.map +1 -1
- package/dist/lib/cli/commands/generate.js +1 -1
- package/dist/lib/cli/commands/init.d.ts.map +1 -1
- package/dist/lib/cli/commands/init.js +5 -0
- 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
|
|
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
|
|
42
|
-
|
|
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
|
-
|
|
47
|
-
- {
|
|
48
|
-
- {
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
-
|
|
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
|
-
|
|
61
|
-
|
|
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
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
(`
|
|
303
|
-
|
|
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
|
-
|
|
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
|
-
|
|
331
|
-
|
|
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
|
|
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
|
|
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`
|
|
471
|
-
| `
|
|
472
|
-
| `
|
|
473
|
-
| `
|
|
474
|
-
| `data-connect-
|
|
475
|
-
| `
|
|
476
|
-
| `
|
|
477
|
-
| `
|
|
478
|
-
| `
|
|
479
|
-
| `
|
|
480
|
-
| `
|
|
481
|
-
| `
|
|
482
|
-
| `
|
|
483
|
-
| `
|
|
484
|
-
| `
|
|
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
|
|
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
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
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,
|
|
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"}
|