firebase-contract 0.1.0-rc.15 → 0.1.0-rc.2
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 +91 -274
- package/dist/lib/_internal/compiler/compiler.d.ts +4 -11
- package/dist/lib/_internal/compiler/compiler.d.ts.map +1 -1
- package/dist/lib/_internal/compiler/compiler.js +26 -296
- package/dist/lib/_internal/generators/api/api-dto-generator.d.ts +5 -0
- package/dist/lib/_internal/generators/api/api-dto-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/api/api-dto-generator.js +14 -29
- package/dist/lib/_internal/generators/api/api-types-generator.d.ts +5 -0
- package/dist/lib/_internal/generators/api/api-types-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/api/api-types-generator.js +22 -38
- package/dist/lib/_internal/generators/api/api-validation-generator.d.ts +4 -0
- package/dist/lib/_internal/generators/api/api-validation-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/api/api-validation-generator.js +9 -38
- package/dist/lib/_internal/generators/api/task-payload-generator.d.ts +6 -0
- package/dist/lib/_internal/generators/api/task-payload-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/api/task-payload-generator.js +19 -33
- package/dist/lib/_internal/generators/config/config-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/config/config-generator.js +1 -2
- package/dist/lib/_internal/generators/data-connect/adapter-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/data-connect/adapter-generator.js +1 -2
- package/dist/lib/_internal/generators/data-connect/graphql-generator.d.ts +7 -0
- package/dist/lib/_internal/generators/data-connect/graphql-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/data-connect/graphql-generator.js +5 -7
- package/dist/lib/_internal/generators/data-connect/operations-generator.d.ts +7 -0
- package/dist/lib/_internal/generators/data-connect/operations-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/data-connect/operations-generator.js +8 -9
- package/dist/lib/_internal/generators/firestore/firestore-projection-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/firestore/firestore-projection-generator.js +23 -9
- 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 +48 -71
- package/dist/lib/_internal/generators/firestore/firestore-type-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/firestore/firestore-type-generator.js +1 -2
- package/dist/lib/_internal/generators/generator.d.ts +0 -38
- package/dist/lib/_internal/generators/generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/generator.js +1 -7
- package/dist/lib/_internal/generators/id/id-codec-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/id/id-codec-generator.js +1 -2
- package/dist/lib/_internal/generators/index.d.ts +5 -2
- package/dist/lib/_internal/generators/index.d.ts.map +1 -1
- package/dist/lib/_internal/generators/index.js +15 -4
- package/dist/lib/_internal/generators/sql/sql-migration-generator.d.ts +1 -2
- package/dist/lib/_internal/generators/sql/sql-migration-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/sql/sql-migration-generator.js +5 -13
- package/dist/lib/_internal/generators/support/header.d.ts.map +1 -1
- package/dist/lib/_internal/generators/support/header.js +0 -2
- package/dist/lib/_internal/generators/support/naming.d.ts +0 -1
- package/dist/lib/_internal/generators/support/naming.d.ts.map +1 -1
- package/dist/lib/_internal/generators/support/naming.js +0 -3
- package/dist/lib/_internal/generators/support/split.d.ts +1 -1
- package/dist/lib/_internal/generators/support/split.d.ts.map +1 -1
- package/dist/lib/_internal/generators/support/split.js +2 -3
- package/dist/lib/_internal/generators/typescript/typescript-generator.d.ts +1 -2
- package/dist/lib/_internal/generators/typescript/typescript-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/typescript/typescript-generator.js +79 -14
- 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 +85 -6
- package/dist/lib/_internal/generators/union/union-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/union/union-generator.js +1 -2
- package/dist/lib/_internal/generators/zod/zod-generator.d.ts +1 -2
- package/dist/lib/_internal/generators/zod/zod-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/zod/zod-generator.js +56 -13
- 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 +57 -6
- package/dist/lib/_internal/ir/build-ir.d.ts.map +1 -1
- package/dist/lib/_internal/ir/build-ir.js +8 -95
- package/dist/lib/_internal/ir/ir.d.ts +5 -20
- package/dist/lib/_internal/ir/ir.d.ts.map +1 -1
- package/dist/lib/_internal/ir/ir.js +0 -1
- package/dist/lib/_internal/parser/parse.d.ts +3 -5
- package/dist/lib/_internal/parser/parse.d.ts.map +1 -1
- package/dist/lib/_internal/parser/parse.js +31 -297
- package/dist/lib/_internal/parser/raw-document.d.ts +9 -64
- package/dist/lib/_internal/parser/raw-document.d.ts.map +1 -1
- package/dist/lib/_internal/resolver/import-resolver.js +1 -1
- package/dist/lib/_internal/validation/rules.d.ts +0 -32
- package/dist/lib/_internal/validation/rules.d.ts.map +1 -1
- package/dist/lib/_internal/validation/rules.js +0 -119
- package/dist/lib/cli/commands/generate.d.ts.map +1 -1
- package/dist/lib/cli/commands/generate.js +5 -7
- package/dist/lib/cli/commands/index.d.ts.map +1 -1
- package/dist/lib/cli/commands/index.js +0 -2
- package/dist/lib/cli/commands/init.d.ts.map +1 -1
- package/dist/lib/cli/commands/init.js +16 -5
- package/dist/lib/cli/config.d.ts +2 -3
- package/dist/lib/cli/config.d.ts.map +1 -1
- package/dist/lib/cli/config.js +0 -3
- package/package.json +1 -1
- package/dist/lib/_internal/compiler/header-vars.d.ts +0 -41
- package/dist/lib/_internal/compiler/header-vars.d.ts.map +0 -1
- package/dist/lib/_internal/compiler/header-vars.js +0 -117
- package/dist/lib/_internal/generators/support/jsdoc.d.ts +0 -3
- package/dist/lib/_internal/generators/support/jsdoc.d.ts.map +0 -1
- package/dist/lib/_internal/generators/support/jsdoc.js +0 -9
- package/dist/lib/_internal/generators/support/split-variant.d.ts +0 -9
- package/dist/lib/_internal/generators/support/split-variant.d.ts.map +0 -1
- package/dist/lib/_internal/generators/support/split-variant.js +0 -13
- package/dist/lib/_internal/generators/support/templates.d.ts +0 -36
- package/dist/lib/_internal/generators/support/templates.d.ts.map +0 -1
- package/dist/lib/_internal/generators/support/templates.js +0 -50
- package/dist/lib/_internal/generators/typescript/render.d.ts +0 -15
- package/dist/lib/_internal/generators/typescript/render.d.ts.map +0 -1
- package/dist/lib/_internal/generators/typescript/render.js +0 -92
- package/dist/lib/_internal/generators/zod/render.d.ts +0 -12
- package/dist/lib/_internal/generators/zod/render.d.ts.map +0 -1
- package/dist/lib/_internal/generators/zod/render.js +0 -59
- package/dist/lib/cli/commands/where.d.ts +0 -3
- package/dist/lib/cli/commands/where.d.ts.map +0 -1
- package/dist/lib/cli/commands/where.js +0 -57
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ From one contract, generate:
|
|
|
10
10
|
- **Zod** validation schemas
|
|
11
11
|
- **Data Connect** GraphQL schema (`@table`, keys, directives), query/mutation
|
|
12
12
|
operations (routed per connector), and `Any`↔logical adapters
|
|
13
|
-
- **Firestore** projection schemas (denormalized read model
|
|
13
|
+
- **Firestore** projection schemas (denormalized read model with `_meta_`)
|
|
14
14
|
- **API** request/response types, request-validation Zod, and class-validator DTOs
|
|
15
15
|
- **Cloud Task / Pub/Sub** payload envelopes + delivery constants
|
|
16
16
|
- **SQL migrations** for constraints Data Connect can't express (composite FKs,
|
|
@@ -32,101 +32,35 @@ 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 `generate:` target declared in the contract graph
|
|
36
36
|
fbc inspect # print the normalized IR (debugging)
|
|
37
|
-
fbc where <Name> # locate the yml defining a type (logical / gqlName / fsName / table)
|
|
38
37
|
```
|
|
39
38
|
|
|
40
39
|
### One-command generation
|
|
41
40
|
|
|
42
|
-
Each contract file
|
|
43
|
-
|
|
44
|
-
**document-scoped** generator (typescript, zod, …) runs it once for
|
|
45
|
-
that yml; **api-scoped** generators (api-types, api-validation, api-dto,
|
|
46
|
-
task-payloads) run for the entries that opt in (see below):
|
|
47
|
-
|
|
48
|
-
```yaml
|
|
49
|
-
# contract.yml (root)
|
|
50
|
-
project:
|
|
51
|
-
aliases:
|
|
52
|
-
"#contracts/*": libs/contracts/src/* # out templates may target aliases
|
|
53
|
-
generators:
|
|
54
|
-
- { generator: typescript, out: "#contracts", split: true }
|
|
55
|
-
- { generator: api-types, out: "#contracts/api-types/{api-name}" }
|
|
56
|
-
imports:
|
|
57
|
-
- ./apps/shop/data-connect/schema.yml
|
|
58
|
-
```
|
|
41
|
+
Each contract file can declare its own outputs in a `generate:` section —
|
|
42
|
+
out dirs are relative to that yml file:
|
|
59
43
|
|
|
60
44
|
```yaml
|
|
61
45
|
# apps/shop/data-connect/schema.yml
|
|
62
|
-
|
|
63
|
-
- {
|
|
64
|
-
- {
|
|
46
|
+
generate:
|
|
47
|
+
- { out: src, generators: [data-connect-graphql-split] }
|
|
48
|
+
- { out: ., generators: [sql-migrations] }
|
|
65
49
|
```
|
|
66
50
|
|
|
67
|
-
- `out` resolves relative to the declaring yml; `#alias/...` prefixes resolve
|
|
68
|
-
through the **root** yml's `project.aliases` (relative to the root).
|
|
69
|
-
- Api-scoped templates may use `{api-name}` (kebab-cased name) and `{path}`
|
|
70
|
-
(REST path with `{param}` segments dropped).
|
|
71
|
-
- Entries reference declarations by name — nearest first (same yml → root).
|
|
72
|
-
|
|
73
|
-
#### Output settings: `file`, `split`, `options`, `header`
|
|
74
|
-
|
|
75
|
-
Every declaration (and any entry-level application) can reshape the output —
|
|
76
|
-
the defaults reproduce each generator's built-in layout, so omitting them
|
|
77
|
-
changes nothing:
|
|
78
|
-
|
|
79
51
|
```yaml
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
-
|
|
86
|
-
out: "#contracts/api-types"
|
|
87
|
-
file: "{api-name}.types.ts" # override the bundled default with per-api files
|
|
88
|
-
split: true
|
|
89
|
-
options:
|
|
90
|
-
typesImport: "../types" # where `import type { … } from '…'` points
|
|
91
|
-
- generator: typescript
|
|
92
|
-
out: "#contracts"
|
|
93
|
-
file: models.ts # rename a single-file/barrel output
|
|
94
|
-
split: true # document scope: per-table split layout
|
|
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
|
|
95
58
|
```
|
|
96
59
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
-
|
|
101
|
-
must contain a placeholder), `false` bundles everything into one `file`.
|
|
102
|
-
Document scope: `true` selects the generator's per-item split layout
|
|
103
|
-
(typescript, zod, firestore, data-connect-graphql, data-connect-operations)
|
|
104
|
-
and errors for generators without one.
|
|
105
|
-
- **`options`** — free-form string map passed through to the generator.
|
|
106
|
-
Currently: `typesImport` (api-types, task-payloads, data-connect-operations)
|
|
107
|
-
overrides the types import path. For api-types and task-payloads this is
|
|
108
|
-
normally unnecessary: when the option is absent and a `typescript` generator
|
|
109
|
-
is declared (nearest-first: same yml → root), the import specifier is derived
|
|
110
|
-
automatically as the relative path from the output file to the declared
|
|
111
|
-
barrel — moving or renaming the barrel (`out` / `file`) re-derives it. An
|
|
112
|
-
explicit `typesImport` always wins; without a typescript declaration the
|
|
113
|
-
generator's built-in default (`./types`) applies.
|
|
114
|
-
- **`header`** — per-generator banner override: `default` for the built-in
|
|
115
|
-
AUTO-GENERATED banner, any text for a custom comment, `""` to suppress the
|
|
116
|
-
banner for this generator. Wins over the contract-level `header:` and the
|
|
117
|
-
CLI `--header` flag.
|
|
118
|
-
- Defaults per generator: `api-types` → `api-types.ts` bundled, `api-validation`
|
|
119
|
-
→ `api-validation.ts` bundled, `task-payloads` → `task-payloads.ts` bundled,
|
|
120
|
-
`api-dto` → `{api-name}.dto.ts` split.
|
|
121
|
-
- Entry-level settings override the declaration, which overrides the
|
|
122
|
-
generator's default (same nearest-first rule as `out`).
|
|
123
|
-
|
|
124
|
-
`fbc generate contract.yml` materializes **all** declared outputs across the
|
|
125
|
-
whole import graph in one run. Passing `-o`/`-g` switches to single-target mode
|
|
126
|
-
(`fbc generate <entry> -o <dir> -g typescript,zod`). `firebase-contract.json`
|
|
127
|
-
holds only a default `entry` — output routing lives in the yml `generators:`
|
|
128
|
-
declarations, so a config file can never silently override them.
|
|
129
|
-
|
|
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
|
|
62
|
+
(`fbc generate <entry> -o <dir> -g typescript,zod`), and
|
|
63
|
+
`firebase-contract.json` (`entry`, `outDir`, `generators`) can hold defaults.
|
|
130
64
|
|
|
131
65
|
### Generated-file headers
|
|
132
66
|
|
|
@@ -141,34 +75,6 @@ fbc generate --header "Managed by fbc" # custom text (multi-line ok)
|
|
|
141
75
|
header: default # or any text; the CLI --header flag wins
|
|
142
76
|
```
|
|
143
77
|
|
|
144
|
-
Header text (contract `header:`, per-generator `header`, CLI `--header`)
|
|
145
|
-
supports `${...}` template variables:
|
|
146
|
-
|
|
147
|
-
| Variable | Value |
|
|
148
|
-
| --- | --- |
|
|
149
|
-
| `${rootContractPath}` | entry (root) yml path, relative to the root yml's directory |
|
|
150
|
-
| `${currentContractPath}` | the yml the output is generated from |
|
|
151
|
-
| `${allContractPath}` | import chain root → current, joined with ` -> ` |
|
|
152
|
-
| `${generatedAt}` | date the file was **first** generated (carried over on regenerate) |
|
|
153
|
-
| `${updatedAt}` | date the content **last changed** |
|
|
154
|
-
|
|
155
|
-
A regenerate that produces identical content keeps both dates and reproduces
|
|
156
|
-
the file byte-for-byte, so `--check` stays drift-free; when content changes,
|
|
157
|
-
`generatedAt` is carried over from the existing file and only `updatedAt`
|
|
158
|
-
moves. Date tokens accept an optional format — `${updatedAt:yyyy-mm-dd HH:mm:ss}`
|
|
159
|
-
— with runs `yyyy`/`yy`, `MM`, `dd`, `HH`, `ss`, and `mm` meaning month before
|
|
160
|
-
any hour token / minute after one (both `yyyy-mm-dd` and `HH:mm` read
|
|
161
|
-
naturally). Default: `yyyy-MM-dd`.
|
|
162
|
-
|
|
163
|
-
The `default` banner includes the source and dates:
|
|
164
|
-
|
|
165
|
-
```
|
|
166
|
-
// AUTO-GENERATED by firebase-contract. Do not edit by hand.
|
|
167
|
-
// Source: ${currentContractPath}
|
|
168
|
-
// Generated: ${generatedAt} / Updated: ${updatedAt}
|
|
169
|
-
// Regenerate with: fbc generate
|
|
170
|
-
```
|
|
171
|
-
|
|
172
78
|
Comment syntax adapts per file type (`//` for TS, `#` for GraphQL/YAML-ish,
|
|
173
79
|
`--` for SQL).
|
|
174
80
|
|
|
@@ -182,33 +88,8 @@ in other contracts (relative paths or npm packages). Imports are resolved
|
|
|
182
88
|
transitively with cycle/duplicate detection and diamond dedup, so you can split
|
|
183
89
|
a large contract across files that mirror your repo layout.
|
|
184
90
|
|
|
185
|
-
**Type names are globally unique.** The namespace is flat across the whole
|
|
186
|
-
import graph: defining the same name twice — same kind (`DUPLICATE_DEFINITION`)
|
|
187
|
-
or across kinds/derived identifiers, e.g. an enum and a model both named
|
|
188
|
-
`Status`, or two enums whose `CONSTANT_CASE` consts collide (`NAME_COLLISION`)
|
|
189
|
-
— aborts generation. Uniqueness is enforced per output namespace with its
|
|
190
|
-
*effective* names, so `fsName`/`gqlName` renames legitimately reuse a name in a
|
|
191
|
-
different output: GraphQL names are checked per `data-connect-graphql` scope
|
|
192
|
-
(services may map distinct logical names onto the same gqlName), and the
|
|
193
|
-
firestore module is checked under `fsName ?? name` alongside doc names. A bare
|
|
194
|
-
type reference therefore always resolves to exactly one definition — use
|
|
195
|
-
`fbc where <Name>` to find it.
|
|
196
|
-
|
|
197
|
-
**Unknown keys are errors.** Every key the parser does not consume is an
|
|
198
|
-
`UNKNOWN_KEY` error (all reported in one pass), never silently dropped — a
|
|
199
|
-
typo like `optionnal:` must not quietly turn into a required field. There is
|
|
200
|
-
no `version:` field: nothing consumes one, so accepting it would only fake a
|
|
201
|
-
compatibility mechanism that does not exist.
|
|
202
|
-
|
|
203
|
-
**Out-of-vocabulary values are errors too.** A value outside a field's fixed
|
|
204
|
-
set is `INVALID_VALUE` rather than a silent coercion: `auth: PUBILC` does not
|
|
205
|
-
quietly become `NO_ACCESS`, `dir: Dsec` does not become `ASC`, and a mistyped
|
|
206
|
-
`action` / `single` / `keyArg` / `style.*` is not dropped. The one exception is
|
|
207
|
-
`where.op`, which is warned (`UNKNOWN_WHERE_OP`) not errored — it is emitted
|
|
208
|
-
verbatim into GraphQL and the recognized-operator list may lag Data Connect, so
|
|
209
|
-
a typo is surfaced without rejecting a valid-but-unlisted operator.
|
|
210
|
-
|
|
211
91
|
```yaml
|
|
92
|
+
version: 1
|
|
212
93
|
imports:
|
|
213
94
|
- ./apps/shop/data-connect/schema.yml
|
|
214
95
|
- some-shared-package/contract.yml
|
|
@@ -281,24 +162,24 @@ models:
|
|
|
281
162
|
|
|
282
163
|
| option | meaning |
|
|
283
164
|
| ----------------------------------- | -------------------------------------------------------- |
|
|
284
|
-
| `type` |
|
|
285
|
-
| `optional` |
|
|
286
|
-
| `list` |
|
|
287
|
-
| `id` |
|
|
288
|
-
| `unique` |
|
|
289
|
-
| `relation` |
|
|
290
|
-
| `col` |
|
|
291
|
-
| `default` |
|
|
292
|
-
| `literal` |
|
|
293
|
-
| `nullable` |
|
|
294
|
-
| `description` |
|
|
295
|
-
| `jsdoc` |
|
|
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) |
|
|
296
177
|
| **constraints** → | |
|
|
297
|
-
| `min` / `max` |
|
|
298
|
-
| `minLength` / `maxLength` |
|
|
299
|
-
| `nonempty` |
|
|
300
|
-
| `pattern` |
|
|
301
|
-
| `email` / `url` |
|
|
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 |
|
|
302
183
|
|
|
303
184
|
Constraints flow into the Zod schemas, the API request validation, and the
|
|
304
185
|
class-validator DTOs.
|
|
@@ -307,14 +188,14 @@ class-validator DTOs.
|
|
|
307
188
|
|
|
308
189
|
| option | meaning |
|
|
309
190
|
| ------------ | ------------------------------------------------------------------ |
|
|
310
|
-
| `key` |
|
|
311
|
-
| `table` |
|
|
312
|
-
| `gqlName` |
|
|
313
|
-
| `fsName` |
|
|
314
|
-
| `directives` |
|
|
315
|
-
| `footer` |
|
|
316
|
-
| `indexes` |
|
|
317
|
-
| `sql` |
|
|
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)) |
|
|
318
199
|
|
|
319
200
|
### Embedded vs relation
|
|
320
201
|
|
|
@@ -392,14 +273,14 @@ Everything below exists to reproduce real hand-written `.gql` files byte-for-byt
|
|
|
392
273
|
|
|
393
274
|
| option | meaning |
|
|
394
275
|
| --- | --- |
|
|
395
|
-
| `gqlName` |
|
|
396
|
-
| `footer` |
|
|
397
|
-
| `raw` |
|
|
398
|
-
| `single: id \|
|
|
399
|
-
| `keyArg` / `keyVars` |
|
|
400
|
-
| `whereAnd: true` |
|
|
401
|
-
| `entityDir` |
|
|
402
|
-
| `style` |
|
|
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`) |
|
|
403
284
|
|
|
404
285
|
Inputs support `var` (variable rename), `required` (override optionality),
|
|
405
286
|
`literal` (fixed value, no variable), `flat` (write the FK column directly),
|
|
@@ -415,13 +296,11 @@ name as long as their connector sets don't overlap.
|
|
|
415
296
|
|
|
416
297
|
## API endpoints
|
|
417
298
|
|
|
418
|
-
Model application endpoints
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
the section `defaults` or the entry's own `generators:`. A payload references a
|
|
424
|
-
model or declares inline fields; a void response maps to `void`.
|
|
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`.
|
|
425
304
|
|
|
426
305
|
```yaml
|
|
427
306
|
envelopes:
|
|
@@ -431,10 +310,9 @@ envelopes:
|
|
|
431
310
|
opId: string
|
|
432
311
|
enqueuedAt: int
|
|
433
312
|
|
|
434
|
-
|
|
435
|
-
defaults:
|
|
436
|
-
generators: [task-payloads] # section default: applies to entries below
|
|
313
|
+
apis:
|
|
437
314
|
createCatalog:
|
|
315
|
+
kind: task # product | callable | https | pubsub
|
|
438
316
|
envelope: RetryTaskPayload # wraps the product data
|
|
439
317
|
maxAttempts: 3
|
|
440
318
|
request:
|
|
@@ -444,31 +322,17 @@ tasks: # Cloud Tasks (kind implied)
|
|
|
444
322
|
response:
|
|
445
323
|
void: true
|
|
446
324
|
|
|
447
|
-
events: # Pub/Sub (kind implied)
|
|
448
325
|
generateAiResponse:
|
|
326
|
+
kind: pubsub
|
|
449
327
|
topic: ai-review-generate-response
|
|
450
328
|
timeoutSeconds: 540
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
defaults:
|
|
455
|
-
generators: [api-types, api-validation]
|
|
456
|
-
/shops/{slug}:
|
|
457
|
-
operationId: getShopBySlug
|
|
458
|
-
kind: callable # https (default) | callable
|
|
329
|
+
|
|
330
|
+
getShopBySlug:
|
|
331
|
+
kind: callable
|
|
459
332
|
request: { fields: { slug: { type: string, nonempty: true } } }
|
|
460
333
|
response: { model: Shop }
|
|
461
|
-
generators: # entry-level wins over section defaults;
|
|
462
|
-
- api-types # an inline out overrides the declared template
|
|
463
|
-
- { generator: api-dto, out: "src/entries/{path}" }
|
|
464
334
|
```
|
|
465
335
|
|
|
466
|
-
Generator application resolves in two tiers — the section `defaults`
|
|
467
|
-
(`apis:/tasks:/events:` → `defaults.generators`) and the entry's own
|
|
468
|
-
`generators:` (which replaces the defaults). `apis:` keys must be REST paths
|
|
469
|
-
(`/...` or `METHOD /...` so the same route can appear once per verb) with an
|
|
470
|
-
`operationId`; tasks and Pub/Sub events live in their own sections.
|
|
471
|
-
|
|
472
336
|
For `createCatalog` this yields `CreateCatalogTaskData`, `CreateCatalogTaskPayload =
|
|
473
337
|
RetryTaskPayload<CreateCatalogTaskData>`, and `CREATE_CATALOG_MAX_ATTEMPTS`, plus the
|
|
474
338
|
request types, Zod schema, and DTO.
|
|
@@ -481,9 +345,9 @@ reality automatically:
|
|
|
481
345
|
|
|
482
346
|
- **relations → resolved string ids** (`ownerUser` → `ownerUserId: z.string()`)
|
|
483
347
|
- **timestamps → `z.date()`**, optional fields → `.nullable()`
|
|
348
|
+
- a **`_meta_`** consistency envelope is attached (opt out with `meta: false`)
|
|
484
349
|
- `pick` / `omit` select which base fields survive
|
|
485
350
|
- inline `fields` add denormalized data (flattened DAG edges, stringified JSON)
|
|
486
|
-
- `extends: [<fragment>…]` splices shared fields in (see **Fragments** below)
|
|
487
351
|
|
|
488
352
|
```yaml
|
|
489
353
|
firestore:
|
|
@@ -501,13 +365,10 @@ firestore:
|
|
|
501
365
|
```
|
|
502
366
|
|
|
503
367
|
Emits Zod schemas + inferred types, mirroring a hand-written Firestore schema
|
|
504
|
-
library. (`firestore-types`
|
|
505
|
-
|
|
506
|
-
`Timestamp`, no `firestore:` section needed. Once you declare projections,
|
|
507
|
-
prefer the `firestore` generator — it is the one that understands
|
|
508
|
-
pick/omit/fsName/denormalized fields.)
|
|
368
|
+
library. (The simpler `firestore-types` generator just re-types *every* model
|
|
369
|
+
with the Firestore `Timestamp` and does not denormalize.)
|
|
509
370
|
|
|
510
|
-
With `firestore
|
|
371
|
+
With `firestore-split`, fields whose Zod chain is **identical** to the Data
|
|
511
372
|
Connect schema are reused via `.pick()` — only representation changes are
|
|
512
373
|
restated:
|
|
513
374
|
|
|
@@ -517,6 +378,7 @@ export const ShopSchema = DcShopSchema.pick({
|
|
|
517
378
|
}).extend({
|
|
518
379
|
createdAt: z.date(),
|
|
519
380
|
updatedAt: z.date().nullable(),
|
|
381
|
+
_meta_: _Meta_Schema,
|
|
520
382
|
})
|
|
521
383
|
```
|
|
522
384
|
|
|
@@ -533,46 +395,6 @@ Additional projection options:
|
|
|
533
395
|
- FS-only enums render as frozen consts (`REVIEW_STATE` + `ReviewStateSchema`),
|
|
534
396
|
co-located with the first projection that references them
|
|
535
397
|
|
|
536
|
-
### Fragments (`fragments:` + `extends:`)
|
|
537
|
-
|
|
538
|
-
A **fragment** is a named group of fields declared once and spliced into
|
|
539
|
-
consumers via `extends: [<name>…]` — the way to share a common field across
|
|
540
|
-
many projections (a consistency `_meta_` envelope, audit columns, …) without a
|
|
541
|
-
tool-imposed convention. The fragment field's name, type, and which docs carry
|
|
542
|
-
it are all yours.
|
|
543
|
-
|
|
544
|
-
The value objects a fragment references can be **pinned** to a fixed split
|
|
545
|
-
output via `out` (+ optional `file`) on the model declaration. A pinned value
|
|
546
|
-
object is *placement-scoped*: emitted only at that location (dependency-ordered,
|
|
547
|
-
with an `index.ts` barrel), imported by consumers via that directory, and
|
|
548
|
-
excluded from the default `typescript`/`zod` barrels — so it lives purely in the
|
|
549
|
-
firestore output. This is what lets a shared envelope sit under `firestore/_/`.
|
|
550
|
-
|
|
551
|
-
```yaml
|
|
552
|
-
models:
|
|
553
|
-
MetaOp:
|
|
554
|
-
out: firestore/_ # → firestore/_/_meta_.ts (+ firestore/_/index.ts)
|
|
555
|
-
file: _meta_.ts
|
|
556
|
-
fields:
|
|
557
|
-
id: { type: string }
|
|
558
|
-
Meta:
|
|
559
|
-
out: firestore/_
|
|
560
|
-
file: _meta_.ts
|
|
561
|
-
fields:
|
|
562
|
-
scope: { type: float, nullable: true }
|
|
563
|
-
op: { type: MetaOp, nullable: true }
|
|
564
|
-
|
|
565
|
-
fragments:
|
|
566
|
-
meta:
|
|
567
|
-
fields:
|
|
568
|
-
_meta_: { type: Meta }
|
|
569
|
-
|
|
570
|
-
firestore:
|
|
571
|
-
Shop:
|
|
572
|
-
from: Shop
|
|
573
|
-
extends: [meta] # appends `_meta_: MetaSchema` (imported from './_')
|
|
574
|
-
```
|
|
575
|
-
|
|
576
398
|
## Discriminated unions
|
|
577
399
|
|
|
578
400
|
```yaml
|
|
@@ -624,19 +446,14 @@ project:
|
|
|
624
446
|
idCodec:
|
|
625
447
|
minLength: 8
|
|
626
448
|
alphabet: <your-shuffled-sqids-alphabet>
|
|
627
|
-
aliases:
|
|
628
|
-
"#contracts/*": libs/contracts/src/*
|
|
629
449
|
```
|
|
630
450
|
|
|
631
451
|
- `services` (`name`/`database`) feed the `FIRESTORE_DATABASES` constants in the
|
|
632
|
-
|
|
452
|
+
`firestore-split` barrel.
|
|
633
453
|
- `idCodec` pins the Sqids settings as a contract constant; when present, the
|
|
634
454
|
`id-codecs` generator also emits a self-contained `id-core.ts` (the
|
|
635
455
|
encode/decode primitives), so nothing about id encoding lives outside the
|
|
636
456
|
contract.
|
|
637
|
-
- `aliases` maps `#alias/...` out-template prefixes to paths relative to the
|
|
638
|
-
**root** yml, so imported contracts can target shared libs without relative
|
|
639
|
-
path gymnastics (longest prefix wins).
|
|
640
457
|
- `codebases` / service `location` + `connectors` are consumed by the optional
|
|
641
458
|
`config` generator (preview), which emits per-service `dataconnect.yaml`,
|
|
642
459
|
per-connector `connector.yaml`, and the `FIRESTORE_DATABASES` /
|
|
@@ -648,32 +465,32 @@ project:
|
|
|
648
465
|
|
|
649
466
|
# Generators
|
|
650
467
|
|
|
651
|
-
| name |
|
|
652
|
-
| ------------------------ |
|
|
653
|
-
| `typescript` |
|
|
654
|
-
| `
|
|
655
|
-
| `
|
|
656
|
-
| `
|
|
657
|
-
| `data-connect-
|
|
658
|
-
| `
|
|
659
|
-
| `
|
|
660
|
-
| `
|
|
661
|
-
| `
|
|
662
|
-
| `
|
|
663
|
-
| `
|
|
664
|
-
| `
|
|
665
|
-
| `
|
|
666
|
-
| `
|
|
667
|
-
| `
|
|
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)) |
|
|
668
490
|
|
|
669
491
|
Each generator emits nothing when its section is absent, so a small contract
|
|
670
492
|
produces a small output. Select a subset with `-g`.
|
|
671
493
|
|
|
672
|
-
**Scope** decides how a `generators:` declaration takes effect: `document`
|
|
673
|
-
generators run once for the yml that declares them; `api` generators run only
|
|
674
|
-
for the entries that apply them (section `defaults.generators` → entry
|
|
675
|
-
`generators:`, entry wins).
|
|
676
|
-
|
|
677
494
|
### The `Any` boundary
|
|
678
495
|
|
|
679
496
|
Data Connect stores JSON and embedded objects as the `Any` scalar, erasing the
|
|
@@ -701,7 +518,7 @@ const result = generate('contract.yml', {
|
|
|
701
518
|
write: true,
|
|
702
519
|
})
|
|
703
520
|
|
|
704
|
-
// Every
|
|
521
|
+
// Every `generate:` target declared across the import graph:
|
|
705
522
|
const all = generateAll('contract.yml', { write: true })
|
|
706
523
|
```
|
|
707
524
|
|
|
@@ -4,7 +4,6 @@ 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';
|
|
8
7
|
export interface CompileOptions {
|
|
9
8
|
/** Override module loading (defaults to the file system). */
|
|
10
9
|
loader?: ModuleLoader;
|
|
@@ -30,10 +29,6 @@ export interface GenerateOptions extends CompileOptions {
|
|
|
30
29
|
/** When true, write the generated files to disk. */
|
|
31
30
|
write?: boolean;
|
|
32
31
|
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;
|
|
37
32
|
}
|
|
38
33
|
export interface GenerateTargetResult {
|
|
39
34
|
/** The contract file that declared this target. */
|
|
@@ -48,18 +43,16 @@ export interface GenerateAllResult {
|
|
|
48
43
|
ok: boolean;
|
|
49
44
|
}
|
|
50
45
|
/**
|
|
51
|
-
* Run every
|
|
52
|
-
* imports — the one-command flow: each contract file
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* to the declaring yml (or the root yml for `#alias/...` templates).
|
|
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.
|
|
56
50
|
*/
|
|
57
51
|
export declare const generateAll: (entryPath: string, options?: {
|
|
58
52
|
registry?: GeneratorRegistry;
|
|
59
53
|
write?: boolean;
|
|
60
54
|
context?: GeneratorContext;
|
|
61
55
|
loader?: ModuleLoader;
|
|
62
|
-
now?: Date;
|
|
63
56
|
}) => GenerateAllResult;
|
|
64
57
|
export interface FileDrift {
|
|
65
58
|
/** 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,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"}
|