firebase-contract 0.1.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +560 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/lib/_internal/compiler/compiler.d.ts +71 -0
- package/dist/lib/_internal/compiler/compiler.d.ts.map +1 -0
- package/dist/lib/_internal/compiler/compiler.js +104 -0
- package/dist/lib/_internal/compiler/index.d.ts +3 -0
- package/dist/lib/_internal/compiler/index.d.ts.map +1 -0
- package/dist/lib/_internal/compiler/index.js +1 -0
- package/dist/lib/_internal/diagnostics.d.ts +29 -0
- package/dist/lib/_internal/diagnostics.d.ts.map +1 -0
- package/dist/lib/_internal/diagnostics.js +26 -0
- package/dist/lib/_internal/format-diagnostics.d.ts +8 -0
- package/dist/lib/_internal/format-diagnostics.d.ts.map +1 -0
- package/dist/lib/_internal/format-diagnostics.js +10 -0
- package/dist/lib/_internal/generators/api/api-dto-generator.d.ts +8 -0
- package/dist/lib/_internal/generators/api/api-dto-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/api/api-dto-generator.js +134 -0
- package/dist/lib/_internal/generators/api/api-types-generator.d.ts +8 -0
- package/dist/lib/_internal/generators/api/api-types-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/api/api-types-generator.js +105 -0
- package/dist/lib/_internal/generators/api/api-validation-generator.d.ts +7 -0
- package/dist/lib/_internal/generators/api/api-validation-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/api/api-validation-generator.js +73 -0
- package/dist/lib/_internal/generators/api/task-payload-generator.d.ts +9 -0
- package/dist/lib/_internal/generators/api/task-payload-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/api/task-payload-generator.js +96 -0
- package/dist/lib/_internal/generators/config/config-generator.d.ts +9 -0
- package/dist/lib/_internal/generators/config/config-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/config/config-generator.js +71 -0
- package/dist/lib/_internal/generators/data-connect/adapter-generator.d.ts +8 -0
- package/dist/lib/_internal/generators/data-connect/adapter-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/data-connect/adapter-generator.js +142 -0
- package/dist/lib/_internal/generators/data-connect/graphql-generator.d.ts +15 -0
- package/dist/lib/_internal/generators/data-connect/graphql-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/data-connect/graphql-generator.js +209 -0
- package/dist/lib/_internal/generators/data-connect/operations-generator.d.ts +18 -0
- package/dist/lib/_internal/generators/data-connect/operations-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/data-connect/operations-generator.js +539 -0
- package/dist/lib/_internal/generators/firestore/firestore-projection-generator.d.ts +11 -0
- package/dist/lib/_internal/generators/firestore/firestore-projection-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/firestore/firestore-projection-generator.js +112 -0
- package/dist/lib/_internal/generators/firestore/firestore-split-generator.d.ts +11 -0
- package/dist/lib/_internal/generators/firestore/firestore-split-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/firestore/firestore-split-generator.js +375 -0
- package/dist/lib/_internal/generators/firestore/firestore-type-generator.d.ts +12 -0
- package/dist/lib/_internal/generators/firestore/firestore-type-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/firestore/firestore-type-generator.js +81 -0
- package/dist/lib/_internal/generators/generator.d.ts +23 -0
- package/dist/lib/_internal/generators/generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/generator.js +1 -0
- package/dist/lib/_internal/generators/id/id-codec-generator.d.ts +16 -0
- package/dist/lib/_internal/generators/id/id-codec-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/id/id-codec-generator.js +140 -0
- package/dist/lib/_internal/generators/index.d.ts +31 -0
- package/dist/lib/_internal/generators/index.d.ts.map +1 -0
- package/dist/lib/_internal/generators/index.js +64 -0
- package/dist/lib/_internal/generators/registry.d.ts +15 -0
- package/dist/lib/_internal/generators/registry.d.ts.map +1 -0
- package/dist/lib/_internal/generators/registry.js +24 -0
- package/dist/lib/_internal/generators/sql/sql-migration-generator.d.ts +9 -0
- package/dist/lib/_internal/generators/sql/sql-migration-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/sql/sql-migration-generator.js +44 -0
- package/dist/lib/_internal/generators/support/constraints.d.ts +8 -0
- package/dist/lib/_internal/generators/support/constraints.d.ts.map +1 -0
- package/dist/lib/_internal/generators/support/constraints.js +39 -0
- package/dist/lib/_internal/generators/support/header.d.ts +13 -0
- package/dist/lib/_internal/generators/support/header.d.ts.map +1 -0
- package/dist/lib/_internal/generators/support/header.js +17 -0
- package/dist/lib/_internal/generators/support/naming.d.ts +10 -0
- package/dist/lib/_internal/generators/support/naming.d.ts.map +1 -0
- package/dist/lib/_internal/generators/support/naming.js +30 -0
- package/dist/lib/_internal/generators/support/relations.d.ts +12 -0
- package/dist/lib/_internal/generators/support/relations.d.ts.map +1 -0
- package/dist/lib/_internal/generators/support/relations.js +11 -0
- package/dist/lib/_internal/generators/support/split.d.ts +34 -0
- package/dist/lib/_internal/generators/support/split.d.ts.map +1 -0
- package/dist/lib/_internal/generators/support/split.js +75 -0
- package/dist/lib/_internal/generators/typescript/typescript-generator.d.ts +18 -0
- package/dist/lib/_internal/generators/typescript/typescript-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/typescript/typescript-generator.js +99 -0
- package/dist/lib/_internal/generators/typescript/typescript-split-generator.d.ts +10 -0
- package/dist/lib/_internal/generators/typescript/typescript-split-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/typescript/typescript-split-generator.js +175 -0
- package/dist/lib/_internal/generators/union/union-generator.d.ts +8 -0
- package/dist/lib/_internal/generators/union/union-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/union/union-generator.js +37 -0
- package/dist/lib/_internal/generators/zod/zod-generator.d.ts +7 -0
- package/dist/lib/_internal/generators/zod/zod-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/zod/zod-generator.js +68 -0
- package/dist/lib/_internal/generators/zod/zod-split-generator.d.ts +9 -0
- package/dist/lib/_internal/generators/zod/zod-split-generator.d.ts.map +1 -0
- package/dist/lib/_internal/generators/zod/zod-split-generator.js +136 -0
- package/dist/lib/_internal/ir/build-ir.d.ts +18 -0
- package/dist/lib/_internal/ir/build-ir.d.ts.map +1 -0
- package/dist/lib/_internal/ir/build-ir.js +430 -0
- package/dist/lib/_internal/ir/ir.d.ts +393 -0
- package/dist/lib/_internal/ir/ir.d.ts.map +1 -0
- package/dist/lib/_internal/ir/ir.js +22 -0
- package/dist/lib/_internal/parser/parse.d.ts +9 -0
- package/dist/lib/_internal/parser/parse.d.ts.map +1 -0
- package/dist/lib/_internal/parser/parse.js +682 -0
- package/dist/lib/_internal/parser/raw-document.d.ts +230 -0
- package/dist/lib/_internal/parser/raw-document.d.ts.map +1 -0
- package/dist/lib/_internal/parser/raw-document.js +6 -0
- package/dist/lib/_internal/resolver/import-resolver.d.ts +25 -0
- package/dist/lib/_internal/resolver/import-resolver.d.ts.map +1 -0
- package/dist/lib/_internal/resolver/import-resolver.js +73 -0
- package/dist/lib/_internal/resolver/module-loader.d.ts +25 -0
- package/dist/lib/_internal/resolver/module-loader.d.ts.map +1 -0
- package/dist/lib/_internal/resolver/module-loader.js +62 -0
- package/dist/lib/_internal/runtime/data-connect-adapter.d.ts +25 -0
- package/dist/lib/_internal/runtime/data-connect-adapter.d.ts.map +1 -0
- package/dist/lib/_internal/runtime/data-connect-adapter.js +24 -0
- package/dist/lib/_internal/runtime/index.d.ts +3 -0
- package/dist/lib/_internal/runtime/index.d.ts.map +1 -0
- package/dist/lib/_internal/runtime/index.js +1 -0
- package/dist/lib/_internal/validation/rules.d.ts +32 -0
- package/dist/lib/_internal/validation/rules.d.ts.map +1 -0
- package/dist/lib/_internal/validation/rules.js +282 -0
- package/dist/lib/_internal/validation/validate.d.ts +9 -0
- package/dist/lib/_internal/validation/validate.d.ts.map +1 -0
- package/dist/lib/_internal/validation/validate.js +6 -0
- package/dist/lib/cli/commands/generate.d.ts +3 -0
- package/dist/lib/cli/commands/generate.d.ts.map +1 -0
- package/dist/lib/cli/commands/generate.js +66 -0
- package/dist/lib/cli/commands/index.d.ts +4 -0
- package/dist/lib/cli/commands/index.d.ts.map +1 -0
- package/dist/lib/cli/commands/index.js +11 -0
- package/dist/lib/cli/commands/init.d.ts +3 -0
- package/dist/lib/cli/commands/init.d.ts.map +1 -0
- package/dist/lib/cli/commands/init.js +72 -0
- package/dist/lib/cli/commands/inspect.d.ts +3 -0
- package/dist/lib/cli/commands/inspect.d.ts.map +1 -0
- package/dist/lib/cli/commands/inspect.js +23 -0
- package/dist/lib/cli/commands/validate.d.ts +3 -0
- package/dist/lib/cli/commands/validate.d.ts.map +1 -0
- package/dist/lib/cli/commands/validate.js +23 -0
- package/dist/lib/cli/config.d.ts +12 -0
- package/dist/lib/cli/config.d.ts.map +1 -0
- package/dist/lib/cli/config.js +20 -0
- package/dist/lib/cli/index.d.ts +3 -0
- package/dist/lib/cli/index.d.ts.map +1 -0
- package/dist/lib/cli/index.js +13 -0
- package/dist/lib/cli/version.d.ts +3 -0
- package/dist/lib/cli/version.d.ts.map +1 -0
- package/dist/lib/cli/version.js +15 -0
- package/dist/lib/modules/runtime.d.ts +2 -0
- package/dist/lib/modules/runtime.d.ts.map +1 -0
- package/dist/lib/modules/runtime.js +3 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
# firebase-contract
|
|
2
|
+
|
|
3
|
+
Treat a **YAML contract as the single source of truth** for a Firebase app and
|
|
4
|
+
generate every downstream representation from it — so shared types, enums, and
|
|
5
|
+
validation stop being hand-maintained in parallel (and stop drifting).
|
|
6
|
+
|
|
7
|
+
From one contract, generate:
|
|
8
|
+
|
|
9
|
+
- **TypeScript** types (interfaces + frozen-const enums)
|
|
10
|
+
- **Zod** validation schemas
|
|
11
|
+
- **Data Connect** GraphQL schema (`@table`, keys, directives), query/mutation
|
|
12
|
+
operations (routed per connector), and `Any`↔logical adapters
|
|
13
|
+
- **Firestore** projection schemas (denormalized read model with `_meta_`)
|
|
14
|
+
- **API** request/response types, request-validation Zod, and class-validator DTOs
|
|
15
|
+
- **Cloud Task / Pub/Sub** payload envelopes + delivery constants
|
|
16
|
+
- **SQL migrations** for constraints Data Connect can't express (composite FKs,
|
|
17
|
+
CHECK, indexes)
|
|
18
|
+
- **Per-entity id codecs** (typed encode/decode wrappers)
|
|
19
|
+
- **Discriminated unions**
|
|
20
|
+
- **Project config** (`dataconnect.yaml`, `connector.yaml`) + sync constants
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm i -D firebase-contract
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Provides the `firebase-contract` (alias `fbc`) CLI and a programmatic API.
|
|
29
|
+
|
|
30
|
+
## Quick start
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
fbc init # scaffold contract.yml + firebase-contract.json
|
|
34
|
+
fbc validate # parse, resolve imports, semantically validate
|
|
35
|
+
fbc generate # run every `generate:` target declared in the contract graph
|
|
36
|
+
fbc inspect # print the normalized IR (debugging)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### One-command generation
|
|
40
|
+
|
|
41
|
+
Each contract file can declare its own outputs in a `generate:` section —
|
|
42
|
+
out dirs are relative to that yml file:
|
|
43
|
+
|
|
44
|
+
```yaml
|
|
45
|
+
# apps/shop/data-connect/schema.yml
|
|
46
|
+
generate:
|
|
47
|
+
- { out: src, generators: [data-connect-graphql-split] }
|
|
48
|
+
- { out: ., generators: [sql-migrations] }
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```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
|
|
58
|
+
```
|
|
59
|
+
|
|
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.
|
|
64
|
+
|
|
65
|
+
### Generated-file headers
|
|
66
|
+
|
|
67
|
+
By default no banner is emitted. Opt in per run or per contract:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
fbc generate --header # default AUTO-GENERATED banner
|
|
71
|
+
fbc generate --header "Managed by fbc" # custom text (multi-line ok)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
header: default # or any text; the CLI --header flag wins
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Comment syntax adapts per file type (`//` for TS, `#` for GraphQL/YAML-ish,
|
|
79
|
+
`--` for SQL).
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
# The YAML DSL
|
|
84
|
+
|
|
85
|
+
A contract is composed of top-level sections — `enums`, `models`, `operations`,
|
|
86
|
+
`apis`, `firestore`, `unions`, `envelopes`, `project` — and `imports` that pull
|
|
87
|
+
in other contracts (relative paths or npm packages). Imports are resolved
|
|
88
|
+
transitively with cycle/duplicate detection and diamond dedup, so you can split
|
|
89
|
+
a large contract across files that mirror your repo layout.
|
|
90
|
+
|
|
91
|
+
```yaml
|
|
92
|
+
version: 1
|
|
93
|
+
imports:
|
|
94
|
+
- ./apps/shop/data-connect/schema.yml
|
|
95
|
+
- some-shared-package/contract.yml
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Enums
|
|
99
|
+
|
|
100
|
+
```yaml
|
|
101
|
+
enums:
|
|
102
|
+
ProductStatus:
|
|
103
|
+
description: Lifecycle state of a product
|
|
104
|
+
values: [DRAFT, PUBLISHED, ARCHIVED]
|
|
105
|
+
|
|
106
|
+
ShippingSpeed:
|
|
107
|
+
description: |-
|
|
108
|
+
Multi-line descriptions become multi-line comments.
|
|
109
|
+
values:
|
|
110
|
+
- { value: S, key: STANDARD } # const-object key override → STANDARD: 'S'
|
|
111
|
+
- { value: X, key: EXPRESS, description: per-value comment }
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Enum options: `description`, `gqlName` (GraphQL rendering name),
|
|
115
|
+
`fsName` / `fsDescription` (Firestore-side rename/comment — e.g. render DC's
|
|
116
|
+
`Status` as `ReviewStatus` in projections), and per-value `key` /
|
|
117
|
+
`description` overrides.
|
|
118
|
+
|
|
119
|
+
By default the TypeScript generator emits the **frozen-const** representation
|
|
120
|
+
(runtime values + `Key` and value types) — the shape you'd otherwise hand-write
|
|
121
|
+
and keep in sync with the DC enum and the Zod enum:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
export const PRODUCT_STATUS = Object.freeze({ DRAFT: 'DRAFT', PUBLISHED: 'PUBLISHED', ARCHIVED: 'ARCHIVED' } as const)
|
|
125
|
+
export type ProductStatusKey = keyof typeof PRODUCT_STATUS
|
|
126
|
+
export type ProductStatus = (typeof PRODUCT_STATUS)[ProductStatusKey]
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Pass `enumStyle: 'union'` to the TypeScript generator for a plain
|
|
130
|
+
`'OPEN' | 'DONE' | 'DISABLED'` union instead.
|
|
131
|
+
|
|
132
|
+
## Models
|
|
133
|
+
|
|
134
|
+
```yaml
|
|
135
|
+
models:
|
|
136
|
+
User:
|
|
137
|
+
fields:
|
|
138
|
+
id: { type: id, id: true }
|
|
139
|
+
name: string # shorthand — the value is the type
|
|
140
|
+
email: { type: string, email: true }
|
|
141
|
+
|
|
142
|
+
Product:
|
|
143
|
+
description: A unit of work
|
|
144
|
+
key: [catalog, productNo] # composite primary key
|
|
145
|
+
indexes:
|
|
146
|
+
- { fields: [catalog, productNo], unique: true }
|
|
147
|
+
- { fields: [status, createdAt] }
|
|
148
|
+
fields:
|
|
149
|
+
catalog: { type: Catalog, relation: true }
|
|
150
|
+
productNo: int
|
|
151
|
+
title: { type: string, nonempty: true, maxLength: 200 }
|
|
152
|
+
status: ProductStatus
|
|
153
|
+
metadata: { type: ProductMetadata, optional: true } # embedded → Any
|
|
154
|
+
createdAt: timestamp
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Scalar types
|
|
158
|
+
|
|
159
|
+
`string`, `int`, `float`, `boolean`, `timestamp`, `date`, `json`, `id`.
|
|
160
|
+
|
|
161
|
+
### Field options
|
|
162
|
+
|
|
163
|
+
| option | meaning |
|
|
164
|
+
| ----------------------------------- | -------------------------------------------------------- |
|
|
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) |
|
|
177
|
+
| **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 |
|
|
183
|
+
|
|
184
|
+
Constraints flow into the Zod schemas, the API request validation, and the
|
|
185
|
+
class-validator DTOs.
|
|
186
|
+
|
|
187
|
+
### Model options
|
|
188
|
+
|
|
189
|
+
| option | meaning |
|
|
190
|
+
| ------------ | ------------------------------------------------------------------ |
|
|
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)) |
|
|
199
|
+
|
|
200
|
+
### Embedded vs relation
|
|
201
|
+
|
|
202
|
+
A field whose `type` is another model is one of two things:
|
|
203
|
+
|
|
204
|
+
- **embedded** (default) — a nested value object. Nested in TypeScript /
|
|
205
|
+
Firestore / Zod; stored as `Any` (jsonb) in Data Connect with the logical type
|
|
206
|
+
preserved and restored by the adapter.
|
|
207
|
+
- **relation** (`relation: true`) — a foreign-key reference to another table.
|
|
208
|
+
Data Connect emits a relation (`owner: User!`, auto-creating the FK column);
|
|
209
|
+
TypeScript / Firestore / Zod expose the foreign-key id (`ownerId`).
|
|
210
|
+
|
|
211
|
+
```yaml
|
|
212
|
+
fields:
|
|
213
|
+
profile: { type: ProfileImage } # embedded → Any + adapter
|
|
214
|
+
owner: { type: User, relation: true } # relation → owner: User! / ownerId
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Data Connect operations
|
|
218
|
+
|
|
219
|
+
Query/mutation operations over a model's table. Emits `.gql` (over the
|
|
220
|
+
auto-generated `<table>_insert/update/upsert/delete` resolvers, with `@auth`
|
|
221
|
+
directives) plus TS `Variables`/`Result` types. Operations are **routed per
|
|
222
|
+
connector** — an operation may target several connectors and is emitted into
|
|
223
|
+
each, under `<connector>/operations.gql`.
|
|
224
|
+
|
|
225
|
+
```yaml
|
|
226
|
+
defaults:
|
|
227
|
+
connectors: [app] # file-level default for operations below
|
|
228
|
+
|
|
229
|
+
operations:
|
|
230
|
+
CreateShop:
|
|
231
|
+
type: mutation
|
|
232
|
+
model: Shop
|
|
233
|
+
action: insert # insert | update | upsert | delete
|
|
234
|
+
auth: NO_ACCESS # NO_ACCESS | PUBLIC | USER
|
|
235
|
+
connectors: [app, api] # emitted into both connectors
|
|
236
|
+
inputs: [type, ownerUser, name, slug, status]
|
|
237
|
+
|
|
238
|
+
IncrementSeq:
|
|
239
|
+
type: mutation
|
|
240
|
+
model: Shop
|
|
241
|
+
action: update
|
|
242
|
+
inc: [projectNoSeq] # → projectNoSeq_update: { inc: 1 }
|
|
243
|
+
exprs: { updatedAt: request.time } # → updatedAt_expr: "request.time"
|
|
244
|
+
|
|
245
|
+
SearchProducts:
|
|
246
|
+
type: query
|
|
247
|
+
model: Product
|
|
248
|
+
auth: PUBLIC
|
|
249
|
+
authReason: gated at the app layer # required when auth is PUBLIC
|
|
250
|
+
where:
|
|
251
|
+
- { field: title, op: contains } # eq | contains | lt | le | gt | ge | ne
|
|
252
|
+
- status # shorthand → { field: status, op: eq }
|
|
253
|
+
orderBy:
|
|
254
|
+
- { field: createdAt, dir: DESC }
|
|
255
|
+
limit: 20
|
|
256
|
+
select: [id, title, status]
|
|
257
|
+
|
|
258
|
+
UsageTotals:
|
|
259
|
+
type: query
|
|
260
|
+
model: UsageLog
|
|
261
|
+
where: [{ field: shop, op: eq }]
|
|
262
|
+
aggregate:
|
|
263
|
+
count: true
|
|
264
|
+
sum: [weightedAmount, inputTokens]
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Relation inputs thread through as `owner: { id: $ownerId }`, matching Data
|
|
268
|
+
Connect's relation-reference form. Composite keys become `key: { a: $a, b: $b }`.
|
|
269
|
+
|
|
270
|
+
### Fidelity options
|
|
271
|
+
|
|
272
|
+
Everything below exists to reproduce real hand-written `.gql` files byte-for-byte:
|
|
273
|
+
|
|
274
|
+
| option | meaning |
|
|
275
|
+
| --- | --- |
|
|
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`) |
|
|
284
|
+
|
|
285
|
+
Inputs support `var` (variable rename), `required` (override optionality),
|
|
286
|
+
`literal` (fixed value, no variable), `flat` (write the FK column directly),
|
|
287
|
+
`inc` (increment write), and `asKey` (pass a relation as a `Model_Key` object
|
|
288
|
+
variable — `$catalogVersion: CatalogVersion_Key`). `where` fields support dotted
|
|
289
|
+
paths through relations (`review.catalog.id` → nested `review: { catalog: { id: { eq: … } } }`),
|
|
290
|
+
`literal` comparisons, and `flat` FK reads. `select` supports nested selections,
|
|
291
|
+
aliases, arguments, and reverse joins (`comments: reviewComments_on_product`).
|
|
292
|
+
`limit` may be a number or a variable (`{ var, default?, required? }`).
|
|
293
|
+
|
|
294
|
+
Operations are namespaced **per connector**: two operations may share a rendered
|
|
295
|
+
name as long as their connector sets don't overlap.
|
|
296
|
+
|
|
297
|
+
## API endpoints
|
|
298
|
+
|
|
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`.
|
|
304
|
+
|
|
305
|
+
```yaml
|
|
306
|
+
envelopes:
|
|
307
|
+
RetryTaskPayload: # RetryTaskPayload<T> = T & { … }
|
|
308
|
+
fields:
|
|
309
|
+
identifierId: string
|
|
310
|
+
opId: string
|
|
311
|
+
enqueuedAt: int
|
|
312
|
+
|
|
313
|
+
apis:
|
|
314
|
+
createCatalog:
|
|
315
|
+
kind: task # product | callable | https | pubsub
|
|
316
|
+
envelope: RetryTaskPayload # wraps the product data
|
|
317
|
+
maxAttempts: 3
|
|
318
|
+
request:
|
|
319
|
+
fields:
|
|
320
|
+
shopId: string
|
|
321
|
+
catalogId: string
|
|
322
|
+
response:
|
|
323
|
+
void: true
|
|
324
|
+
|
|
325
|
+
generateAiResponse:
|
|
326
|
+
kind: pubsub
|
|
327
|
+
topic: ai-review-generate-response
|
|
328
|
+
timeoutSeconds: 540
|
|
329
|
+
|
|
330
|
+
getShopBySlug:
|
|
331
|
+
kind: callable
|
|
332
|
+
request: { fields: { slug: { type: string, nonempty: true } } }
|
|
333
|
+
response: { model: Shop }
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
For `createCatalog` this yields `CreateCatalogTaskData`, `CreateCatalogTaskPayload =
|
|
337
|
+
RetryTaskPayload<CreateCatalogTaskData>`, and `CREATE_CATALOG_MAX_ATTEMPTS`, plus the
|
|
338
|
+
request types, Zod schema, and DTO.
|
|
339
|
+
|
|
340
|
+
## Firestore projections
|
|
341
|
+
|
|
342
|
+
Firestore is a **denormalized read model**, not the same shape as Data Connect.
|
|
343
|
+
A projection *derives* from a DC model (`from`) and applies the projection
|
|
344
|
+
reality automatically:
|
|
345
|
+
|
|
346
|
+
- **relations → resolved string ids** (`ownerUser` → `ownerUserId: z.string()`)
|
|
347
|
+
- **timestamps → `z.date()`**, optional fields → `.nullable()`
|
|
348
|
+
- a **`_meta_`** consistency envelope is attached (opt out with `meta: false`)
|
|
349
|
+
- `pick` / `omit` select which base fields survive
|
|
350
|
+
- inline `fields` add denormalized data (flattened DAG edges, stringified JSON)
|
|
351
|
+
|
|
352
|
+
```yaml
|
|
353
|
+
firestore:
|
|
354
|
+
User:
|
|
355
|
+
from: User
|
|
356
|
+
collection: users/{userId}
|
|
357
|
+
pick: [displayName, photoURL, createdAt, updatedAt, lastLoginAt]
|
|
358
|
+
Product:
|
|
359
|
+
from: Product
|
|
360
|
+
collection: shops/{ws}/.../products/{productNo}
|
|
361
|
+
omit: [catalog, log]
|
|
362
|
+
fields:
|
|
363
|
+
parentProductNos: { type: int, list: true }
|
|
364
|
+
linkedCatalogTitle: { type: string, optional: true }
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
Emits Zod schemas + inferred types, mirroring a hand-written Firestore schema
|
|
368
|
+
library. (The simpler `firestore-types` generator just re-types *every* model
|
|
369
|
+
with the Firestore `Timestamp` and does not denormalize.)
|
|
370
|
+
|
|
371
|
+
With `firestore-split`, fields whose Zod chain is **identical** to the Data
|
|
372
|
+
Connect schema are reused via `.pick()` — only representation changes are
|
|
373
|
+
restated:
|
|
374
|
+
|
|
375
|
+
```ts
|
|
376
|
+
export const ShopSchema = DcShopSchema.pick({
|
|
377
|
+
type: true, name: true, slug: true, ownerUserId: true, status: true,
|
|
378
|
+
}).extend({
|
|
379
|
+
createdAt: z.date(),
|
|
380
|
+
updatedAt: z.date().nullable(),
|
|
381
|
+
_meta_: _Meta_Schema,
|
|
382
|
+
})
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Additional projection options:
|
|
386
|
+
|
|
387
|
+
- **override semantics** — fields declared under `fields:` use `nullable:` →
|
|
388
|
+
`.nullable()` and `optional:` → `.optional()` explicitly (base-picked fields
|
|
389
|
+
map DC-optional → `.nullable()` automatically); `default:` → `.default(…)`
|
|
390
|
+
- **`pick` order is authoritative** for the projected field order
|
|
391
|
+
- **`helpers:`** — verbatim TypeScript (e.g. small accessor functions) emitted
|
|
392
|
+
into the projection file
|
|
393
|
+
- **`include: [Model]`** — host a shared embedded schema in this file even when
|
|
394
|
+
no projected field references it
|
|
395
|
+
- FS-only enums render as frozen consts (`REVIEW_STATE` + `ReviewStateSchema`),
|
|
396
|
+
co-located with the first projection that references them
|
|
397
|
+
|
|
398
|
+
## Discriminated unions
|
|
399
|
+
|
|
400
|
+
```yaml
|
|
401
|
+
unions:
|
|
402
|
+
CatalogOperationDraft:
|
|
403
|
+
discriminant: operationType
|
|
404
|
+
variants: [AddLinkOperation, CutLinkOperation]
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
Each variant is a model whose `operationType` field is pinned with `literal:` so
|
|
408
|
+
the output is a valid `z.discriminatedUnion('operationType', [...])` plus the TS
|
|
409
|
+
union type.
|
|
410
|
+
|
|
411
|
+
## SQL migrations
|
|
412
|
+
|
|
413
|
+
Constraints Data Connect cannot express — composite foreign keys, CHECK
|
|
414
|
+
constraints, extra indexes — are declared per model and emitted as an executable
|
|
415
|
+
`migrations/constraints.sql`:
|
|
416
|
+
|
|
417
|
+
```yaml
|
|
418
|
+
models:
|
|
419
|
+
ProductLink:
|
|
420
|
+
key: [catalog, parentProductNo, childProductNo]
|
|
421
|
+
sql:
|
|
422
|
+
checks:
|
|
423
|
+
- "parent_product_no != child_product_no"
|
|
424
|
+
foreignKeys:
|
|
425
|
+
- { columns: [catalog_id, parent_product_no], references: "products(catalog_id, product_no)" }
|
|
426
|
+
indexes:
|
|
427
|
+
- { columns: [catalog_id, child_product_no] }
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
## Id codecs
|
|
431
|
+
|
|
432
|
+
For each model with an id field, the `id-codecs` generator emits typed
|
|
433
|
+
`encode<Model>Id` / `decode<Model>Id` wrappers (numeric codec for Int64 ids,
|
|
434
|
+
string codec otherwise) over generic primitives from a configurable `core`
|
|
435
|
+
module — replacing scattered untyped `encodeNumericId` calls.
|
|
436
|
+
|
|
437
|
+
## Project config
|
|
438
|
+
|
|
439
|
+
```yaml
|
|
440
|
+
project:
|
|
441
|
+
services:
|
|
442
|
+
- { name: shop, database: shop }
|
|
443
|
+
- { name: warehouse, database: warehouse }
|
|
444
|
+
codebases:
|
|
445
|
+
shp: shop
|
|
446
|
+
idCodec:
|
|
447
|
+
minLength: 8
|
|
448
|
+
alphabet: <your-shuffled-sqids-alphabet>
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
- `services` (`name`/`database`) feed the `FIRESTORE_DATABASES` constants in the
|
|
452
|
+
`firestore-split` barrel.
|
|
453
|
+
- `idCodec` pins the Sqids settings as a contract constant; when present, the
|
|
454
|
+
`id-codecs` generator also emits a self-contained `id-core.ts` (the
|
|
455
|
+
encode/decode primitives), so nothing about id encoding lives outside the
|
|
456
|
+
contract.
|
|
457
|
+
- `codebases` / service `location` + `connectors` are consumed by the optional
|
|
458
|
+
`config` generator (preview), which emits per-service `dataconnect.yaml`,
|
|
459
|
+
per-connector `connector.yaml`, and the `FIRESTORE_DATABASES` /
|
|
460
|
+
`API_CODEBASES` sync constants. It does not yet reproduce every field of a
|
|
461
|
+
real deployment config (e.g. `cloudSql` datasource details) — treat it as a
|
|
462
|
+
starting point, not a drop-in replacement.
|
|
463
|
+
|
|
464
|
+
---
|
|
465
|
+
|
|
466
|
+
# Generators
|
|
467
|
+
|
|
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)) |
|
|
490
|
+
|
|
491
|
+
Each generator emits nothing when its section is absent, so a small contract
|
|
492
|
+
produces a small output. Select a subset with `-g`.
|
|
493
|
+
|
|
494
|
+
### The `Any` boundary
|
|
495
|
+
|
|
496
|
+
Data Connect stores JSON and embedded objects as the `Any` scalar, erasing the
|
|
497
|
+
logical type. The GraphQL generator keeps the logical type in a comment
|
|
498
|
+
(`metadata: Any # logical: ProductMetadata`), and the adapter emits typed
|
|
499
|
+
converters that call `fromAny`/`toAny` from `firebase-contract/runtime`:
|
|
500
|
+
|
|
501
|
+
```
|
|
502
|
+
ProductMetadata → Data Connect: Any → generated adapter → ProductMetadata
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
# Programmatic API
|
|
508
|
+
|
|
509
|
+
```ts
|
|
510
|
+
import { compile, generate, generateAll, createDefaultRegistry } from 'firebase-contract'
|
|
511
|
+
|
|
512
|
+
const { ir, diagnostics } = compile('contract.yml')
|
|
513
|
+
|
|
514
|
+
// Single target:
|
|
515
|
+
const result = generate('contract.yml', {
|
|
516
|
+
outDir: 'generated',
|
|
517
|
+
generators: ['typescript', 'zod'], // omit for all
|
|
518
|
+
write: true,
|
|
519
|
+
})
|
|
520
|
+
|
|
521
|
+
// Every `generate:` target declared across the import graph:
|
|
522
|
+
const all = generateAll('contract.yml', { write: true })
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
# Architecture
|
|
526
|
+
|
|
527
|
+
```
|
|
528
|
+
YAML → Parser → Import Resolver → Normalized IR → Semantic Validation → Generators
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
- **Generators never see YAML.** Their only input is the IR (`src/lib/_internal/ir`).
|
|
532
|
+
- **Generators are independent** of each other and of shared mutable state.
|
|
533
|
+
- **The CLI is thin** and delegates to the compiler; it never calls a generator
|
|
534
|
+
directly.
|
|
535
|
+
- Dependency direction: `cli → compiler → {parser, resolver, ir, validation, generators}`.
|
|
536
|
+
|
|
537
|
+
All implementation lives under `src/lib/_internal` (imported via the `~internal`
|
|
538
|
+
alias); the outer layers are thin: `src/lib/cli/**` (bin), `src/lib/modules/**`
|
|
539
|
+
(public subpath exports, e.g. `firebase-contract/runtime`), and `src/index.ts`
|
|
540
|
+
(root barrel).
|
|
541
|
+
|
|
542
|
+
### Adding a generator
|
|
543
|
+
|
|
544
|
+
Implement the `Generator` interface and register it — no existing code changes:
|
|
545
|
+
|
|
546
|
+
```ts
|
|
547
|
+
import { Generator, createDefaultRegistry } from 'firebase-contract'
|
|
548
|
+
|
|
549
|
+
const openApi: Generator = {
|
|
550
|
+
name: 'openapi',
|
|
551
|
+
generate: ir => [{ path: 'openapi.json', content: toOpenApi(ir) }],
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
const registry = createDefaultRegistry().register(openApi)
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
### Adding a validation rule
|
|
558
|
+
|
|
559
|
+
Rules are independent `(ir) => Diagnostic[]` functions; pass a custom set to
|
|
560
|
+
`validateIr(ir, rules)`.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from './lib/_internal/compiler/index.js';
|
|
2
|
+
export * from './lib/_internal/ir/ir.js';
|
|
3
|
+
export * from './lib/_internal/generators/index.js';
|
|
4
|
+
export type { Diagnostic, DiagnosticSeverity } from './lib/_internal/diagnostics.js';
|
|
5
|
+
export { ContractError, hasErrors } from './lib/_internal/diagnostics.js';
|
|
6
|
+
export type { RawContract, RawModel, RawField, RawEnum } from './lib/_internal/parser/raw-document.js';
|
|
7
|
+
export { parseContract } from './lib/_internal/parser/parse.js';
|
|
8
|
+
export type { ResolveResult } from './lib/_internal/resolver/import-resolver.js';
|
|
9
|
+
export { resolveImports } from './lib/_internal/resolver/import-resolver.js';
|
|
10
|
+
export type { ModuleLoader } from './lib/_internal/resolver/module-loader.js';
|
|
11
|
+
export { createFsLoader, createMemoryLoader } from './lib/_internal/resolver/module-loader.js';
|
|
12
|
+
export { validateIr } from './lib/_internal/validation/validate.js';
|
|
13
|
+
export type { ValidationRule } from './lib/_internal/validation/rules.js';
|
|
14
|
+
export * as runtime from './lib/_internal/runtime/index.js';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,6BAA6B,CAAA;AAC3C,cAAc,oBAAoB,CAAA;AAClC,cAAc,+BAA+B,CAAA;AAE7C,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAC9E,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AAEnE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAA;AAChG,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAEzD,YAAY,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAA;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAA;AACtE,YAAY,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAA;AACvE,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAA;AAExF,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAC7D,YAAY,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAEnE,OAAO,KAAK,OAAO,MAAM,4BAA4B,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Public, programmatic API for firebase-contract.
|
|
2
|
+
// The CLI (bin: firebase-contract / fbc) is a thin wrapper over `compile`/`generate`.
|
|
3
|
+
// All implementation lives under lib/_internal; this barrel re-exports it.
|
|
4
|
+
export * from './lib/_internal/compiler/index.js';
|
|
5
|
+
export * from './lib/_internal/ir/ir.js';
|
|
6
|
+
export * from './lib/_internal/generators/index.js';
|
|
7
|
+
export { ContractError, hasErrors } from './lib/_internal/diagnostics.js';
|
|
8
|
+
export { parseContract } from './lib/_internal/parser/parse.js';
|
|
9
|
+
export { resolveImports } from './lib/_internal/resolver/import-resolver.js';
|
|
10
|
+
export { createFsLoader, createMemoryLoader } from './lib/_internal/resolver/module-loader.js';
|
|
11
|
+
export { validateIr } from './lib/_internal/validation/validate.js';
|
|
12
|
+
export * as runtime from './lib/_internal/runtime/index.js';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Diagnostic } from '../diagnostics.js';
|
|
2
|
+
import { Ir } from '../ir/ir.js';
|
|
3
|
+
import { RawContract } from '../parser/raw-document.js';
|
|
4
|
+
import { ModuleLoader } from '../resolver/module-loader.js';
|
|
5
|
+
import { GeneratedFile, GeneratorContext } from '../generators/generator.js';
|
|
6
|
+
import { GeneratorRegistry } from '../generators/registry.js';
|
|
7
|
+
export interface CompileOptions {
|
|
8
|
+
/** Override module loading (defaults to the file system). */
|
|
9
|
+
loader?: ModuleLoader;
|
|
10
|
+
}
|
|
11
|
+
export interface CompileResult {
|
|
12
|
+
ir: Ir;
|
|
13
|
+
documents: RawContract[];
|
|
14
|
+
diagnostics: Diagnostic[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Run the front end of the pipeline: resolve imports, build the IR, and run
|
|
18
|
+
* semantic validation. Generators are intentionally not involved here — the CLI
|
|
19
|
+
* and {@link generate} depend on this, keeping analysis and code emission
|
|
20
|
+
* separable and independently testable.
|
|
21
|
+
*/
|
|
22
|
+
export declare const compile: (entryPath: string, options?: CompileOptions) => CompileResult;
|
|
23
|
+
export interface GenerateOptions extends CompileOptions {
|
|
24
|
+
outDir: string;
|
|
25
|
+
/** Generator names to run; defaults to every generator in the registry. */
|
|
26
|
+
generators?: string[];
|
|
27
|
+
/** Registry to resolve generators from; defaults to the built-ins. */
|
|
28
|
+
registry?: GeneratorRegistry;
|
|
29
|
+
/** When true, write the generated files to disk. */
|
|
30
|
+
write?: boolean;
|
|
31
|
+
context?: GeneratorContext;
|
|
32
|
+
}
|
|
33
|
+
export interface GenerateTargetResult {
|
|
34
|
+
/** The contract file that declared this target. */
|
|
35
|
+
source: string;
|
|
36
|
+
outDir: string;
|
|
37
|
+
generators: string[];
|
|
38
|
+
files: GeneratedFile[];
|
|
39
|
+
}
|
|
40
|
+
export interface GenerateAllResult {
|
|
41
|
+
targets: GenerateTargetResult[];
|
|
42
|
+
diagnostics: Diagnostic[];
|
|
43
|
+
ok: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
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.
|
|
50
|
+
*/
|
|
51
|
+
export declare const generateAll: (entryPath: string, options?: {
|
|
52
|
+
registry?: GeneratorRegistry;
|
|
53
|
+
write?: boolean;
|
|
54
|
+
context?: GeneratorContext;
|
|
55
|
+
loader?: ModuleLoader;
|
|
56
|
+
}) => GenerateAllResult;
|
|
57
|
+
export interface GenerateResult {
|
|
58
|
+
ir: Ir;
|
|
59
|
+
diagnostics: Diagnostic[];
|
|
60
|
+
/** Output files with paths resolved under `outDir`. Empty when there are errors. */
|
|
61
|
+
files: GeneratedFile[];
|
|
62
|
+
/** True when no error-level diagnostics were produced. */
|
|
63
|
+
ok: boolean;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Compile then emit code. Generation is skipped when compilation produced any
|
|
67
|
+
* error, so generators never see an invalid IR. The CLI is a thin wrapper over
|
|
68
|
+
* this function.
|
|
69
|
+
*/
|
|
70
|
+
export declare const generate: (entryPath: string, options: GenerateOptions) => GenerateResult;
|
|
71
|
+
//# sourceMappingURL=compiler.d.ts.map
|
|
@@ -0,0 +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,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"}
|