firebase-contract 0.1.0-rc.6 → 0.1.0-rc.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +47 -3
  2. package/dist/lib/_internal/compiler/compiler.d.ts.map +1 -1
  3. package/dist/lib/_internal/compiler/compiler.js +77 -21
  4. package/dist/lib/_internal/generators/api/api-dto-generator.d.ts +0 -5
  5. package/dist/lib/_internal/generators/api/api-dto-generator.d.ts.map +1 -1
  6. package/dist/lib/_internal/generators/api/api-dto-generator.js +20 -12
  7. package/dist/lib/_internal/generators/api/api-types-generator.d.ts +0 -5
  8. package/dist/lib/_internal/generators/api/api-types-generator.d.ts.map +1 -1
  9. package/dist/lib/_internal/generators/api/api-types-generator.js +21 -14
  10. package/dist/lib/_internal/generators/api/api-validation-generator.d.ts +0 -4
  11. package/dist/lib/_internal/generators/api/api-validation-generator.d.ts.map +1 -1
  12. package/dist/lib/_internal/generators/api/api-validation-generator.js +11 -5
  13. package/dist/lib/_internal/generators/api/task-payload-generator.d.ts +0 -6
  14. package/dist/lib/_internal/generators/api/task-payload-generator.d.ts.map +1 -1
  15. package/dist/lib/_internal/generators/api/task-payload-generator.js +28 -16
  16. package/dist/lib/_internal/generators/config/config-generator.d.ts.map +1 -1
  17. package/dist/lib/_internal/generators/config/config-generator.js +2 -1
  18. package/dist/lib/_internal/generators/data-connect/adapter-generator.d.ts.map +1 -1
  19. package/dist/lib/_internal/generators/data-connect/adapter-generator.js +2 -1
  20. package/dist/lib/_internal/generators/data-connect/graphql-generator.d.ts.map +1 -1
  21. package/dist/lib/_internal/generators/data-connect/graphql-generator.js +2 -1
  22. package/dist/lib/_internal/generators/data-connect/operations-generator.js +1 -1
  23. package/dist/lib/_internal/generators/firestore/firestore-projection-generator.d.ts.map +1 -1
  24. package/dist/lib/_internal/generators/firestore/firestore-projection-generator.js +2 -1
  25. package/dist/lib/_internal/generators/firestore/firestore-split-generator.d.ts.map +1 -1
  26. package/dist/lib/_internal/generators/firestore/firestore-split-generator.js +2 -1
  27. package/dist/lib/_internal/generators/firestore/firestore-type-generator.d.ts.map +1 -1
  28. package/dist/lib/_internal/generators/firestore/firestore-type-generator.js +2 -1
  29. package/dist/lib/_internal/generators/generator.d.ts +20 -0
  30. package/dist/lib/_internal/generators/generator.d.ts.map +1 -1
  31. package/dist/lib/_internal/generators/id/id-codec-generator.d.ts.map +1 -1
  32. package/dist/lib/_internal/generators/id/id-codec-generator.js +2 -1
  33. package/dist/lib/_internal/generators/sql/sql-migration-generator.d.ts.map +1 -1
  34. package/dist/lib/_internal/generators/sql/sql-migration-generator.js +2 -1
  35. package/dist/lib/_internal/generators/support/templates.d.ts +36 -0
  36. package/dist/lib/_internal/generators/support/templates.d.ts.map +1 -0
  37. package/dist/lib/_internal/generators/support/templates.js +50 -0
  38. package/dist/lib/_internal/generators/typescript/typescript-generator.d.ts.map +1 -1
  39. package/dist/lib/_internal/generators/typescript/typescript-generator.js +2 -1
  40. package/dist/lib/_internal/generators/typescript/typescript-split-generator.d.ts.map +1 -1
  41. package/dist/lib/_internal/generators/typescript/typescript-split-generator.js +2 -1
  42. package/dist/lib/_internal/generators/union/union-generator.d.ts.map +1 -1
  43. package/dist/lib/_internal/generators/union/union-generator.js +2 -1
  44. package/dist/lib/_internal/generators/zod/zod-generator.d.ts.map +1 -1
  45. package/dist/lib/_internal/generators/zod/zod-generator.js +2 -1
  46. package/dist/lib/_internal/generators/zod/zod-split-generator.d.ts.map +1 -1
  47. package/dist/lib/_internal/generators/zod/zod-split-generator.js +2 -1
  48. package/dist/lib/_internal/parser/parse.d.ts.map +1 -1
  49. package/dist/lib/_internal/parser/parse.js +53 -9
  50. package/dist/lib/_internal/parser/raw-document.d.ts +13 -1
  51. package/dist/lib/_internal/parser/raw-document.d.ts.map +1 -1
  52. package/package.json +1 -1
package/README.md CHANGED
@@ -69,6 +69,50 @@ generators:
69
69
  (REST path with `{param}` segments dropped).
70
70
  - Entries reference declarations by name — nearest first (same yml → root).
71
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
+
78
+ ```yaml
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: switches to typescript-split
94
+ ```
95
+
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 for `-split` variants.
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` swaps to the generator's `-split` variant
102
+ (`typescript` → `typescript-split`, …) and errors when none exists.
103
+ - **`options`** — free-form string map passed through to the generator.
104
+ Currently: `typesImport` (api-types, task-payloads, data-connect-operations)
105
+ overrides the `./types` import path.
106
+ - **`header`** — per-generator banner override: `default` for the built-in
107
+ AUTO-GENERATED banner, any text for a custom comment, `""` to suppress the
108
+ banner for this generator. Wins over the contract-level `header:` and the
109
+ CLI `--header` flag.
110
+ - Defaults per generator: `api-types` → `api-types.ts` bundled, `api-validation`
111
+ → `api-validation.ts` bundled, `task-payloads` → `task-payloads.ts` bundled,
112
+ `api-dto` → `{api-name}.dto.ts` split.
113
+ - Entry-level settings override the declaration, which overrides the
114
+ generator's default (same nearest-first rule as `out`).
115
+
72
116
  `fbc generate contract.yml` materializes **all** declared outputs across the
73
117
  whole import graph in one run. Passing `-o`/`-g` switches to single-target mode
74
118
  (`fbc generate <entry> -o <dir> -g typescript,zod`), and
@@ -360,8 +404,8 @@ apis: # https/callable, keyed by REST path
360
404
  Generator application resolves in two tiers — the section `defaults`
361
405
  (`apis:/tasks:/events:` → `defaults.generators`) and the entry's own
362
406
  `generators:` (which replaces the defaults). `apis:` keys must be REST paths
363
- (`/...`) with an `operationId`; tasks and Pub/Sub events live in their own
364
- sections.
407
+ (`/...` or `METHOD /...` so the same route can appear once per verb) with an
408
+ `operationId`; tasks and Pub/Sub events live in their own sections.
365
409
 
366
410
  For `createCatalog` this yields `CreateCatalogTaskData`, `CreateCatalogTaskPayload =
367
411
  RetryTaskPayload<CreateCatalogTaskData>`, and `CREATE_CATALOG_MAX_ATTEMPTS`, plus the
@@ -516,7 +560,7 @@ project:
516
560
  | `firestore-split` | document | `firestore/<collection>.ts` + `firestore.ts` barrel | one file per projection; `_meta_` under `firestore/_/`; DC-schema `.pick()` reuse; `FIRESTORE_DATABASES` constants in the barrel |
517
561
  | `api-types` | api | `api-types.ts` | endpoint request/response types |
518
562
  | `api-validation` | api | `api-validation.ts` | endpoint request-validation Zod |
519
- | `api-dto` | api | `api-dtos.ts` | class-validator DTO classes |
563
+ | `api-dto` | api | `<operation>.dto.ts` per api | class-validator DTO classes (NestJS `dto/` convention) |
520
564
  | `task-payloads` | api | `task-payloads.ts` | envelopes + `*TaskData`/`*TaskPayload` + constants |
521
565
  | `sql-migrations` | document | `migrations/constraints.sql` | composite FK / CHECK / index SQL |
522
566
  | `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 |
@@ -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,EAAU,WAAW,EAAqC,MAAM,2BAA2B,CAAA;AAElG,OAAO,EAAkB,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAG3E,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAG5E,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;AAwJD;;;;;;GAMG;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,iBA0CF,CAAA;AAED,MAAM,WAAW,SAAS;IACxB,sEAAsE;IACtE,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,mEAAmE;IACnE,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,OAAO,aAAa,EAAE,KAAG,SAUlD,CAAA;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,EAAE,CAAA;IACN,WAAW,EAAE,UAAU,EAAE,CAAA;IACzB,oFAAoF;IACpF,KAAK,EAAE,aAAa,EAAE,CAAA;IACtB,0DAA0D;IAC1D,EAAE,EAAE,OAAO,CAAA;CACZ;AAED;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,WAAW,MAAM,EAAE,SAAS,eAAe,KAAG,cAuCtE,CAAA"}
1
+ {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../../../src/lib/_internal/compiler/compiler.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAoB,MAAM,mBAAmB,CAAA;AAEhE,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAChC,OAAO,EAAU,WAAW,EAAqC,MAAM,2BAA2B,CAAA;AAElG,OAAO,EAAkB,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAG3E,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAI5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;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;AAmND;;;;;;GAMG;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,iBAuDF,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"}
@@ -7,7 +7,7 @@ import { createFsLoader } from '../resolver/module-loader.js';
7
7
  import { validateIr } from '../validation/validate.js';
8
8
  import { createDefaultRegistry } from '../generators/index.js';
9
9
  import { toHeaderComment } from '../generators/support/header.js';
10
- import { kebabCase } from '../generators/support/naming.js';
10
+ import { API_PLACEHOLDER_RE, expandApiPlaceholders } from '../generators/support/templates.js';
11
11
  /**
12
12
  * Run the front end of the pipeline: resolve imports, build the IR, and run
13
13
  * semantic validation. Generators are intentionally not involved here — the CLI
@@ -25,7 +25,6 @@ export const compile = (entryPath, options = {}) => {
25
25
  diagnostics: [...importDiagnostics, ...buildDiagnostics, ...validationDiagnostics],
26
26
  };
27
27
  };
28
- const OUT_PLACEHOLDER_RE = /\{(api-name|path)\}/;
29
28
  /** `apis:/tasks:/events:` section a raw api belongs to (drives the section defaults lookup). */
30
29
  const sectionOf = (api) => {
31
30
  if (api.kind === 'task')
@@ -34,25 +33,16 @@ const sectionOf = (api) => {
34
33
  return 'events';
35
34
  return 'apis';
36
35
  };
37
- /** Drop `{param}` segments from a REST path and join the rest (`/ai-models/{id}` → `ai-models`). */
38
- const pathSegments = (apiPath) => apiPath
39
- .split('/')
40
- .filter(segment => segment.length > 0 && !(segment.startsWith('{') && segment.endsWith('}')))
41
- .join('/');
42
36
  const expandOutTemplate = (template, api, diagnostics, source) => {
43
- if (!OUT_PLACEHOLDER_RE.test(template))
37
+ if (!API_PLACEHOLDER_RE.test(template))
44
38
  return template;
45
39
  if (!api) {
46
40
  diagnostics.push(error('INVALID_OUT_TEMPLATE', `"${template}" uses api placeholders but the generator is document-scoped (${source})`));
47
41
  return undefined;
48
42
  }
49
- let out = template.replaceAll('{api-name}', kebabCase(api.name));
50
- if (out.includes('{path}')) {
51
- if (!api.path) {
52
- diagnostics.push(error('INVALID_OUT_TEMPLATE', `"${template}" uses {path} but api "${api.name}" has no REST path (${source})`));
53
- return undefined;
54
- }
55
- out = out.replaceAll('{path}', pathSegments(api.path));
43
+ const out = expandApiPlaceholders(template, api);
44
+ if (out === undefined) {
45
+ diagnostics.push(error('INVALID_OUT_TEMPLATE', `"${template}" uses {path} but api "${api.name}" has no REST path (${source})`));
56
46
  }
57
47
  return out;
58
48
  };
@@ -101,6 +91,30 @@ const buildGeneratorJobs = (doc, rootDoc, registry, diagnostics) => {
101
91
  diagnostics.push(error('UNKNOWN_GENERATOR_DECL', `Api "${apiName}" applies generator "${use.generator}" but no declaration with an "out" was found (${doc.filePath})`));
102
92
  continue;
103
93
  }
94
+ // Output settings resolve nearest-first: entry use → declaration → the
95
+ // generator's built-in default (applied by the generator itself).
96
+ const generator = registry.get(use.generator);
97
+ const output = {};
98
+ const file = use.file ?? decl?.file;
99
+ const split = use.split ?? decl?.split ?? generator?.defaultOutput?.split;
100
+ const options = use.options ?? decl?.options;
101
+ const header = use.header ?? decl?.header;
102
+ if (file !== undefined)
103
+ output.file = file;
104
+ if (split !== undefined)
105
+ output.split = split;
106
+ if (options !== undefined)
107
+ output.options = options;
108
+ // Split mode needs a per-api file name; bundled mode cannot expand one.
109
+ const effectiveFile = file ?? generator?.defaultOutput?.file;
110
+ if (effectiveFile !== undefined && split === false && API_PLACEHOLDER_RE.test(effectiveFile)) {
111
+ diagnostics.push(error('INVALID_OUT_TEMPLATE', `file "${effectiveFile}" uses api placeholders but split is false for generator "${use.generator}" — set a plain file name (${doc.filePath})`));
112
+ continue;
113
+ }
114
+ if (effectiveFile !== undefined && split === true && !API_PLACEHOLDER_RE.test(effectiveFile)) {
115
+ diagnostics.push(error('INVALID_OUT_TEMPLATE', `split is true for generator "${use.generator}" but file "${effectiveFile}" has no {api-name}/{path} placeholder, so per-api files would overwrite each other (${doc.filePath})`));
116
+ continue;
117
+ }
104
118
  const api = { name: apiName, ...(rawApi.path !== undefined ? { path: rawApi.path } : {}) };
105
119
  const expanded = expandOutTemplate(template, api, diagnostics, doc.filePath);
106
120
  if (expanded === undefined)
@@ -108,13 +122,15 @@ const buildGeneratorJobs = (doc, rootDoc, registry, diagnostics) => {
108
122
  const outDir = resolveOutDir(expanded, doc, rootDoc, diagnostics);
109
123
  if (outDir === undefined)
110
124
  continue;
111
- const key = `${use.generator}\u0000${outDir}`;
125
+ const key = [use.generator, outDir, file ?? '', String(split ?? ''), JSON.stringify(options ?? null), header ?? '\u0001'].join('\u0000');
112
126
  const existing = grouped.get(key);
113
127
  if (existing) {
114
128
  existing.apiNames?.push(apiName);
115
129
  }
116
130
  else {
117
- const job = { source: doc.filePath, generatorName: use.generator, outDir, apiNames: [apiName] };
131
+ const job = { source: doc.filePath, generatorName: use.generator, outDir, apiNames: [apiName], output };
132
+ if (header !== undefined)
133
+ job.header = header;
118
134
  grouped.set(key, job);
119
135
  jobs.push(job);
120
136
  }
@@ -128,13 +144,47 @@ const buildGeneratorJobs = (doc, rootDoc, registry, diagnostics) => {
128
144
  }
129
145
  if ((generator.scope ?? 'document') === 'api')
130
146
  continue; // applied via entries, not by declaration
147
+ // Document-scoped `split` toggles between a generator and its `-split`
148
+ // variant (e.g. typescript ⇄ typescript-split) instead of reshaping output.
149
+ let generatorName = decl.generator;
150
+ if (decl.split === true && !generatorName.endsWith('-split')) {
151
+ const splitName = `${generatorName}-split`;
152
+ if (registry.get(splitName)) {
153
+ generatorName = splitName;
154
+ }
155
+ else {
156
+ diagnostics.push(error('UNSUPPORTED_SPLIT', `Generator "${decl.generator}" has no split variant (${doc.filePath})`));
157
+ continue;
158
+ }
159
+ }
160
+ else if (decl.split === false && generatorName.endsWith('-split')) {
161
+ const baseName = generatorName.slice(0, -'-split'.length);
162
+ if (registry.get(baseName))
163
+ generatorName = baseName;
164
+ }
165
+ const output = {};
166
+ if (decl.file !== undefined) {
167
+ if (API_PLACEHOLDER_RE.test(decl.file)) {
168
+ diagnostics.push(error('INVALID_OUT_TEMPLATE', `file "${decl.file}" uses api placeholders but generator "${decl.generator}" is document-scoped (${doc.filePath})`));
169
+ continue;
170
+ }
171
+ output.file = decl.file;
172
+ }
173
+ if (decl.options !== undefined)
174
+ output.options = decl.options;
131
175
  const expanded = expandOutTemplate(decl.out, undefined, diagnostics, doc.filePath);
132
176
  if (expanded === undefined)
133
177
  continue;
134
178
  const outDir = resolveOutDir(expanded, doc, rootDoc, diagnostics);
135
179
  if (outDir === undefined)
136
180
  continue;
137
- jobs.push({ source: doc.filePath, generatorName: decl.generator, outDir });
181
+ jobs.push({
182
+ source: doc.filePath,
183
+ generatorName,
184
+ outDir,
185
+ ...(Object.keys(output).length > 0 ? { output } : {}),
186
+ ...(decl.header !== undefined ? { header: decl.header } : {}),
187
+ });
138
188
  }
139
189
  return jobs;
140
190
  };
@@ -164,13 +214,19 @@ export const generateAll = (entryPath, options = {}) => {
164
214
  }
165
215
  }
166
216
  };
167
- const runTarget = (doc, outDir, generators, apiNames) => {
217
+ const runTarget = (doc, outDir, generators, apiNames, output, header) => {
168
218
  const result = generate(doc.filePath, {
169
219
  outDir,
170
220
  generators,
171
221
  registry,
172
222
  write: options.write,
173
- context: { ...options.context, ...(apiNames ? { apiNames } : {}) },
223
+ context: {
224
+ ...options.context,
225
+ ...(apiNames ? { apiNames } : {}),
226
+ ...(output ? { output } : {}),
227
+ // Per-generator header beats the CLI/contract-level one ('' disables it).
228
+ ...(header !== undefined ? { header: toHeaderComment(header) } : {}),
229
+ },
174
230
  ...(options.loader ? { loader: options.loader } : {}),
175
231
  });
176
232
  mergeDiagnostics(result.diagnostics);
@@ -182,7 +238,7 @@ export const generateAll = (entryPath, options = {}) => {
182
238
  // Declaration/application DSL (`generators:` + section defaults / entry `generators:`).
183
239
  const jobDiagnostics = [];
184
240
  for (const job of buildGeneratorJobs(doc, rootDoc, registry, jobDiagnostics)) {
185
- runTarget(doc, job.outDir, [job.generatorName], job.apiNames);
241
+ runTarget(doc, job.outDir, [job.generatorName], job.apiNames, job.output, job.header);
186
242
  }
187
243
  mergeDiagnostics(jobDiagnostics);
188
244
  if (hasErrors(jobDiagnostics))
@@ -1,8 +1,3 @@
1
1
  import { Generator } from '../generator.js';
2
- /**
3
- * Generates class-validator DTO classes for API endpoint requests, mirroring the
4
- * hand-written NestJS DTOs (decorators derived from field type +
5
- * constraints). Complements the Zod request schemas for a NestJS ValidationPipe.
6
- */
7
2
  export declare const createApiDtoGenerator: () => Generator;
8
3
  //# sourceMappingURL=api-dto-generator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"api-dto-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/api/api-dto-generator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,SAAS,EAAgC,MAAM,iBAAiB,CAAA;AA0GxF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,QAAO,SAmBvC,CAAA"}
1
+ {"version":3,"file":"api-dto-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/api/api-dto-generator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,SAAS,EAAgC,MAAM,iBAAiB,CAAA;AAoHxF,eAAO,MAAM,qBAAqB,QAAO,SAuBvC,CAAA"}
@@ -3,6 +3,7 @@ import { pascalCase, singleQuote } from '../support/naming.js';
3
3
  import { isRelation, relationFkName } from '../support/relations.js';
4
4
  import { selectApis } from '../generator.js';
5
5
  import { headerBlocks } from '../support/header.js';
6
+ import { emitApiFiles, resolveOutput } from '../support/templates.js';
6
7
  const SCALAR_TS = {
7
8
  string: 'string',
8
9
  int: 'number',
@@ -126,23 +127,30 @@ const renderDto = (ir, api, used) => {
126
127
  * hand-written NestJS DTOs (decorators derived from field type +
127
128
  * constraints). Complements the Zod request schemas for a NestJS ValidationPipe.
128
129
  */
130
+ // Default mirrors the NestJS convention: one `dto/create-thing.dto.ts` per
131
+ // endpoint next to its controller (the out template decides the directory).
132
+ const DEFAULT_OUTPUT = { file: '{api-name}.dto.ts', split: true };
129
133
  export const createApiDtoGenerator = () => ({
130
134
  name: 'api-dto',
131
135
  scope: 'api',
132
136
  description: 'class-validator DTO classes for API requests',
137
+ defaultOutput: DEFAULT_OUTPUT,
133
138
  generate(ir, context) {
134
- // DTO は HTTP リクエストボディ用 — task / pubsub のペイロードは task-payloads が担う。
139
+ // DTOs cover HTTP request bodies — task / pubsub payloads belong to task-payloads.
135
140
  const httpApis = selectApis(ir.apis, context).filter(api => api.kind === 'https' || api.kind === 'callable');
136
- if (httpApis.length === 0) {
137
- return [];
138
- }
139
- const used = new Set();
140
- const dtoBlocks = httpApis.map(api => renderDto(ir, api, used));
141
- const blocks = [...headerBlocks(context)];
142
- if (used.size > 0) {
143
- blocks.push(`import { ${[...used].sort().join(', ')} } from 'class-validator'`);
144
- }
145
- blocks.push(...dtoBlocks);
146
- return [{ path: 'api-dtos.ts', content: `${blocks.join('\n\n')}\n` }];
141
+ const output = resolveOutput(context, DEFAULT_OUTPUT);
142
+ return emitApiFiles(httpApis, output, subset => {
143
+ if (subset.length === 0) {
144
+ return undefined;
145
+ }
146
+ const used = new Set();
147
+ const dtos = subset.map(api => renderDto(ir, api, used));
148
+ const blocks = [...headerBlocks(context)];
149
+ if (used.size > 0) {
150
+ blocks.push(`import { ${[...used].sort().join(', ')} } from 'class-validator'`);
151
+ }
152
+ blocks.push(...dtos);
153
+ return `${blocks.join('\n\n')}\n`;
154
+ });
147
155
  },
148
156
  });
@@ -1,8 +1,3 @@
1
1
  import { Generator } from '../generator.js';
2
- /**
3
- * Generates request/response TypeScript types for each API endpoint. A payload
4
- * can reference an existing model or declare inline fields; a void response maps
5
- * to `void`. This mirrors the shared producer/consumer contract pattern.
6
- */
7
2
  export declare const createApiTypesGenerator: () => Generator;
8
3
  //# sourceMappingURL=api-types-generator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"api-types-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/api/api-types-generator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,SAAS,EAAgC,MAAM,iBAAiB,CAAA;AA8ExF;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,QAAO,SA0BzC,CAAA"}
1
+ {"version":3,"file":"api-types-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/api/api-types-generator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,SAAS,EAAgC,MAAM,iBAAiB,CAAA;AAsFxF,eAAO,MAAM,uBAAuB,QAAO,SA+BzC,CAAA"}
@@ -2,6 +2,7 @@ import { pascalCase } from '../support/naming.js';
2
2
  import { isRelation, relationFkName, relationFkType } from '../support/relations.js';
3
3
  import { selectApis } from '../generator.js';
4
4
  import { headerBlocks } from '../support/header.js';
5
+ import { emitApiFiles, resolveOutput } from '../support/templates.js';
5
6
  const SCALAR_TS = {
6
7
  string: 'string',
7
8
  int: 'number',
@@ -82,28 +83,34 @@ const apiComment = (api) => {
82
83
  * can reference an existing model or declare inline fields; a void response maps
83
84
  * to `void`. This mirrors the shared producer/consumer contract pattern.
84
85
  */
86
+ const DEFAULT_OUTPUT = { file: 'api-types.ts', split: false };
85
87
  export const createApiTypesGenerator = () => ({
86
88
  name: 'api-types',
87
89
  description: 'API request/response TypeScript types',
88
90
  scope: 'api',
91
+ defaultOutput: DEFAULT_OUTPUT,
89
92
  generate(ir, context) {
90
93
  const apis = selectApis(ir.apis, context);
91
94
  if (apis.length === 0) {
92
95
  return [];
93
96
  }
94
- const blocks = [...headerBlocks(context)];
95
- const imports = collectImports(ir, apis);
96
- if (imports.length > 0) {
97
- blocks.push(`import type { ${imports.join(', ')} } from './types'`);
98
- }
99
- for (const api of apis) {
100
- const pascal = pascalCase(api.name);
101
- blocks.push([
102
- apiComment(api),
103
- renderPayloadType(ir, api.request, `${pascal}Request`),
104
- renderPayloadType(ir, api.response, `${pascal}Response`),
105
- ].join('\n'));
106
- }
107
- return [{ path: 'api-types.ts', content: `${blocks.join('\n\n')}\n` }];
97
+ const output = resolveOutput(context, DEFAULT_OUTPUT);
98
+ const typesImport = output.options['typesImport'] ?? './types';
99
+ return emitApiFiles(apis, output, subset => {
100
+ const blocks = [...headerBlocks(context)];
101
+ const imports = collectImports(ir, subset);
102
+ if (imports.length > 0) {
103
+ blocks.push(`import type { ${imports.join(', ')} } from '${typesImport}'`);
104
+ }
105
+ for (const api of subset) {
106
+ const pascal = pascalCase(api.name);
107
+ blocks.push([
108
+ apiComment(api),
109
+ renderPayloadType(ir, api.request, `${pascal}Request`),
110
+ renderPayloadType(ir, api.response, `${pascal}Response`),
111
+ ].join('\n'));
112
+ }
113
+ return `${blocks.join('\n\n')}\n`;
114
+ });
108
115
  },
109
116
  });
@@ -1,7 +1,3 @@
1
1
  import { Generator } from '../generator.js';
2
- /**
3
- * Generates Zod schemas that validate each endpoint's *request*. Model-backed
4
- * requests are expanded to the model's fields so the schema is self-contained.
5
- */
6
2
  export declare const createApiValidationGenerator: () => Generator;
7
3
  //# sourceMappingURL=api-validation-generator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"api-validation-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/api/api-validation-generator.ts"],"names":[],"mappings":"AAIA,OAAO,EAAiB,SAAS,EAAgC,MAAM,iBAAiB,CAAA;AAuExF;;;GAGG;AACH,eAAO,MAAM,4BAA4B,QAAO,SAe9C,CAAA"}
1
+ {"version":3,"file":"api-validation-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/api/api-validation-generator.ts"],"names":[],"mappings":"AAIA,OAAO,EAAiB,SAAS,EAAgC,MAAM,iBAAiB,CAAA;AA8ExF,eAAO,MAAM,4BAA4B,QAAO,SAmB9C,CAAA"}
@@ -4,6 +4,7 @@ import { isRelation, relationFkName, relationFkType } from '../support/relations
4
4
  import { zodConstraints } from '../support/constraints.js';
5
5
  import { selectApis } from '../generator.js';
6
6
  import { headerBlocks } from '../support/header.js';
7
+ import { emitApiFiles, resolveOutput } from '../support/templates.js';
7
8
  const SCALAR_ZOD = {
8
9
  string: 'z.string()',
9
10
  int: 'z.number().int()',
@@ -78,19 +79,24 @@ const renderRequestSchema = (ir, api) => {
78
79
  * Generates Zod schemas that validate each endpoint's *request*. Model-backed
79
80
  * requests are expanded to the model's fields so the schema is self-contained.
80
81
  */
82
+ const DEFAULT_OUTPUT = { file: 'api-validation.ts', split: false };
81
83
  export const createApiValidationGenerator = () => ({
82
84
  name: 'api-validation',
83
85
  description: 'API request-validation Zod schemas',
84
86
  scope: 'api',
87
+ defaultOutput: DEFAULT_OUTPUT,
85
88
  generate(ir, context) {
86
89
  const apis = selectApis(ir.apis, context);
87
90
  if (apis.length === 0) {
88
91
  return [];
89
92
  }
90
- const blocks = [...headerBlocks(context), "import { z } from 'zod'"];
91
- for (const api of apis) {
92
- blocks.push(renderRequestSchema(ir, api));
93
- }
94
- return [{ path: 'api-validation.ts', content: `${blocks.join('\n\n')}\n` }];
93
+ const output = resolveOutput(context, DEFAULT_OUTPUT);
94
+ return emitApiFiles(apis, output, subset => {
95
+ const blocks = [...headerBlocks(context), "import { z } from 'zod'"];
96
+ for (const api of subset) {
97
+ blocks.push(renderRequestSchema(ir, api));
98
+ }
99
+ return `${blocks.join('\n\n')}\n`;
100
+ });
95
101
  },
96
102
  });
@@ -1,9 +1,3 @@
1
1
  import { Generator } from '../generator.js';
2
- /**
3
- * Generates Cloud Task / Pub/Sub payload contracts: a generic envelope type per
4
- * declared envelope (`RetryTaskPayload<T> = T & { … }`), plus per-task
5
- * `<Name>TaskData` + `<Name>TaskPayload` and delivery constants (max attempts,
6
- * timeout, topic) — the shared payload contracts an app otherwise hand-writes.
7
- */
8
2
  export declare const createTaskPayloadGenerator: () => Generator;
9
3
  //# sourceMappingURL=task-payload-generator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"task-payload-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/api/task-payload-generator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,SAAS,EAAgC,MAAM,iBAAiB,CAAA;AAyExF;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,QAAO,SAsB5C,CAAA"}
1
+ {"version":3,"file":"task-payload-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/api/task-payload-generator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,SAAS,EAAgC,MAAM,iBAAiB,CAAA;AAkFxF,eAAO,MAAM,0BAA0B,QAAO,SAgC5C,CAAA"}
@@ -3,6 +3,7 @@ import { constantCase, pascalCase, singleQuote } from '../support/naming.js';
3
3
  import { isRelation, relationFkName, relationFkType } from '../support/relations.js';
4
4
  import { selectApis } from '../generator.js';
5
5
  import { headerBlocks } from '../support/header.js';
6
+ import { emitApiFiles, resolveOutput } from '../support/templates.js';
6
7
  const SCALAR_TS = {
7
8
  string: 'string',
8
9
  int: 'number',
@@ -75,26 +76,37 @@ const collectImports = (ir, tasks) => {
75
76
  * `<Name>TaskData` + `<Name>TaskPayload` and delivery constants (max attempts,
76
77
  * timeout, topic) — the shared payload contracts an app otherwise hand-writes.
77
78
  */
79
+ const DEFAULT_OUTPUT = { file: 'task-payloads.ts', split: false };
78
80
  export const createTaskPayloadGenerator = () => ({
79
81
  name: 'task-payloads',
80
82
  scope: 'api',
81
83
  description: 'Cloud Task/Pub-Sub payload envelopes, data/payload types, and constants',
84
+ defaultOutput: DEFAULT_OUTPUT,
82
85
  generate(ir, context) {
83
- const tasks = selectApis(ir.apis, context).filter(isTask);
84
- if (ir.envelopes.length === 0 && tasks.length === 0) {
85
- return [];
86
- }
87
- const blocks = [...headerBlocks(context)];
88
- const imports = collectImports(ir, tasks);
89
- if (imports.length > 0) {
90
- blocks.push(`import type { ${imports.join(', ')} } from './types'`);
91
- }
92
- for (const env of ir.envelopes) {
93
- blocks.push(renderEnvelope(env));
94
- }
95
- for (const api of tasks) {
96
- blocks.push(renderTask(ir, api));
97
- }
98
- return [{ path: 'task-payloads.ts', content: `${blocks.join('\n\n')}\n` }];
86
+ const output = resolveOutput(context, DEFAULT_OUTPUT);
87
+ const typesImport = output.options['typesImport'] ?? './types';
88
+ return emitApiFiles(selectApis(ir.apis, context), output, subset => {
89
+ const tasks = subset.filter(isTask);
90
+ // Bundled mode keeps the envelope-only output; split mode inlines only
91
+ // the envelopes each per-task file actually references.
92
+ const envelopes = output.split
93
+ ? ir.envelopes.filter(env => tasks.some(api => api.task?.envelope === env.name))
94
+ : ir.envelopes;
95
+ if (envelopes.length === 0 && tasks.length === 0) {
96
+ return undefined;
97
+ }
98
+ const blocks = [...headerBlocks(context)];
99
+ const imports = collectImports(ir, tasks);
100
+ if (imports.length > 0) {
101
+ blocks.push(`import type { ${imports.join(', ')} } from '${typesImport}'`);
102
+ }
103
+ for (const env of envelopes) {
104
+ blocks.push(renderEnvelope(env));
105
+ }
106
+ for (const api of tasks) {
107
+ blocks.push(renderTask(ir, api));
108
+ }
109
+ return `${blocks.join('\n\n')}\n`;
110
+ });
99
111
  },
100
112
  });
@@ -1 +1 @@
1
- {"version":3,"file":"config-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/config/config-generator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAqD5E;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,QAAO,SAuBvC,CAAA"}
1
+ {"version":3,"file":"config-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/config/config-generator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAsD5E;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,QAAO,SAuBvC,CAAA"}
@@ -1,5 +1,6 @@
1
1
  import { constantCase, singleQuote } from '../support/naming.js';
2
2
  import { headerFor } from '../support/header.js';
3
+ import { outputFile } from '../support/templates.js';
3
4
  const DEFAULT_LOCATION = 'asia-northeast1';
4
5
  const dataconnectYaml = (service) => {
5
6
  const connectorDirs = service.connectors.map(c => `./connectors/${c}`);
@@ -64,7 +65,7 @@ export const createConfigGenerator = () => ({
64
65
  }
65
66
  }
66
67
  if (project.services.length > 0 || project.codebases.length > 0) {
67
- files.push({ path: 'constants.ts', content: constantsTs(project, headerFor(context)) });
68
+ files.push({ path: outputFile(context, 'constants.ts'), content: constantsTs(project, headerFor(context)) });
68
69
  }
69
70
  return files;
70
71
  },
@@ -1 +1 @@
1
- {"version":3,"file":"adapter-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/data-connect/adapter-generator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAsI5E;;;;GAIG;AACH,eAAO,MAAM,iCAAiC,QAAO,SAmBnD,CAAA"}
1
+ {"version":3,"file":"adapter-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/data-connect/adapter-generator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAuI5E;;;;GAIG;AACH,eAAO,MAAM,iCAAiC,QAAO,SAmBnD,CAAA"}
@@ -1,6 +1,7 @@
1
1
  import { camelCase } from '../support/naming.js';
2
2
  import { headerBlocks } from '../support/header.js';
3
3
  import { isRelation, relationFkName, relationFkType } from '../support/relations.js';
4
+ import { outputFile } from '../support/templates.js';
4
5
  const SCALAR_TS = {
5
6
  string: 'string',
6
7
  int: 'number',
@@ -137,6 +138,6 @@ export const createDataConnectAdapterGenerator = () => ({
137
138
  blocks.push(renderRowInterface(model, ir));
138
139
  blocks.push(renderAdapter(model));
139
140
  }
140
- return [{ path: 'data-connect-adapters.ts', content: `${blocks.join('\n\n')}\n` }];
141
+ return [{ path: outputFile(context, 'data-connect-adapters.ts'), content: `${blocks.join('\n\n')}\n` }];
141
142
  },
142
143
  });
@@ -1 +1 @@
1
- {"version":3,"file":"graphql-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/data-connect/graphql-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AA8I5E;;;;GAIG;AACH,eAAO,MAAM,iCAAiC,QAAO,SA+BnD,CAAA;AAaF;;;;;GAKG;AACH,eAAO,MAAM,sCAAsC,QAAO,SAmCxD,CAAA"}
1
+ {"version":3,"file":"graphql-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/data-connect/graphql-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AA+I5E;;;;GAIG;AACH,eAAO,MAAM,iCAAiC,QAAO,SA+BnD,CAAA;AAaF;;;;;GAKG;AACH,eAAO,MAAM,sCAAsC,QAAO,SAmCxD,CAAA"}
@@ -1,6 +1,7 @@
1
1
  import { headerBlocks } from '../support/header.js';
2
2
  import { constantCase, pluralize, snakeCase } from '../support/naming.js';
3
3
  import { isRelation } from '../support/relations.js';
4
+ import { outputFile } from '../support/templates.js';
4
5
  // Data Connect built-in scalars. `json` and embedded model objects are stored
5
6
  // as `Any` — the logical type is preserved in a comment and restored by the
6
7
  // Data Connect adapter generator.
@@ -151,7 +152,7 @@ export const createDataConnectGraphqlGenerator = () => ({
151
152
  if (model.footer)
152
153
  blocks.push(commentLines(model.footer, '').join('\n'));
153
154
  }
154
- return [{ path: 'schema.gql', content: `${blocks.join('\n\n')}\n` }];
155
+ return [{ path: outputFile(context, 'schema.gql'), content: `${blocks.join('\n\n')}\n` }];
155
156
  },
156
157
  });
157
158
  const renderEnumGql = (irEnum, rename) => {
@@ -487,7 +487,7 @@ export const createDataConnectOperationsGenerator = () => ({
487
487
  for (const [connector, entries] of groupByConnector(resolvable)) {
488
488
  const dir = connector ? `${connector}/` : '';
489
489
  // types.ts lives at the output root; connector files sit one level deeper.
490
- const typesImport = connector ? '../types' : './types';
490
+ const typesImport = context?.output?.options?.['typesImport'] ?? (connector ? '../types' : './types');
491
491
  files.push({ path: `${dir}operations.gql`, content: renderGqlFile(ir, entries, context) });
492
492
  files.push({ path: `${dir}operations-types.ts`, content: renderTsFile(ir, entries, typesImport, context) });
493
493
  }
@@ -1 +1 @@
1
- {"version":3,"file":"firestore-projection-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/firestore/firestore-projection-generator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAuF5E;;;;;;;GAOG;AACH,eAAO,MAAM,kCAAkC,QAAO,SAgBpD,CAAA"}
1
+ {"version":3,"file":"firestore-projection-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/firestore/firestore-projection-generator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAwF5E;;;;;;;GAOG;AACH,eAAO,MAAM,kCAAkC,QAAO,SAgBpD,CAAA"}
@@ -2,6 +2,7 @@ import { findModel } from '../../ir/ir.js';
2
2
  import { singleQuote } from '../support/naming.js';
3
3
  import { isRelation, relationFkName } from '../support/relations.js';
4
4
  import { headerBlocks } from '../support/header.js';
5
+ import { outputFile } from '../support/templates.js';
5
6
  // Firestore stores timestamps as dates and represents relations as resolved
6
7
  // (hashids-encoded) string ids, regardless of the Data Connect id's type.
7
8
  const SCALAR_ZOD = {
@@ -107,6 +108,6 @@ export const createFirestoreProjectionGenerator = () => ({
107
108
  for (const doc of ir.firestore) {
108
109
  blocks.push(renderDoc(ir, doc));
109
110
  }
110
- return [{ path: 'firestore.ts', content: `${blocks.join('\n\n')}\n` }];
111
+ return [{ path: outputFile(context, 'firestore.ts'), content: `${blocks.join('\n\n')}\n` }];
111
112
  },
112
113
  });
@@ -1 +1 @@
1
- {"version":3,"file":"firestore-split-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/firestore/firestore-split-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAwO5E;;;;;;;GAOG;AACH,eAAO,MAAM,6BAA6B,QAAO,SAqI/C,CAAA"}
1
+ {"version":3,"file":"firestore-split-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/firestore/firestore-split-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAyO5E;;;;;;;GAOG;AACH,eAAO,MAAM,6BAA6B,QAAO,SAqI/C,CAAA"}
@@ -4,6 +4,7 @@ import { headerBlocks } from '../support/header.js';
4
4
  import { camelCase, constantCase, pluralize, singleQuote } from '../support/naming.js';
5
5
  import { isRelation, relationFkName } from '../support/relations.js';
6
6
  import { collectDeps, kebabCase, tableNameOf } from '../support/split.js';
7
+ import { outputFile } from '../support/templates.js';
7
8
  // Projection-level scalars: timestamps become dates, ids/relations become
8
9
  // resolved (hashids-encoded) string ids.
9
10
  const SCALAR_FS = {
@@ -369,7 +370,7 @@ export const createFirestoreSplitGenerator = () => ({
369
370
  if (ir.firestore.some(doc => doc.meta))
370
371
  exportLines.push(`export * from './firestore/_'`);
371
372
  barrel.push(['// Zod schema / TypeScript 型のエクスポート', ...exportLines].join('\n'));
372
- files.push({ path: 'firestore.ts', content: `${barrel.join('\n\n')}\n` });
373
+ files.push({ path: outputFile(context, 'firestore.ts'), content: `${barrel.join('\n\n')}\n` });
373
374
  return files;
374
375
  },
375
376
  });
@@ -1 +1 @@
1
- {"version":3,"file":"firestore-type-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/firestore/firestore-type-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAI5E,MAAM,WAAW,yBAAyB;IACxC,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AA0DD;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,GAAI,UAAS,yBAA8B,KAAG,SAiCtF,CAAA"}
1
+ {"version":3,"file":"firestore-type-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/firestore/firestore-type-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAK5E,MAAM,WAAW,yBAAyB;IACxC,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AA0DD;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,GAAI,UAAS,yBAA8B,KAAG,SAiCtF,CAAA"}
@@ -1,5 +1,6 @@
1
1
  import { headerBlocks } from '../support/header.js';
2
2
  import { isRelation, relationFkName, relationFkType } from '../support/relations.js';
3
+ import { outputFile } from '../support/templates.js';
3
4
  const scalarMap = () => ({
4
5
  string: 'string',
5
6
  int: 'number',
@@ -75,7 +76,7 @@ export const createFirestoreTypeGenerator = (options = {}) => {
75
76
  const fields = model.fields.map(field => renderField(field, scalars, ir)).join('\n');
76
77
  blocks.push(`${doc}export interface ${model.name} {\n${fields}\n}`);
77
78
  }
78
- return [{ path: 'firestore-types.ts', content: `${blocks.join('\n\n')}\n` }];
79
+ return [{ path: outputFile(context, 'firestore-types.ts'), content: `${blocks.join('\n\n')}\n` }];
79
80
  },
80
81
  };
81
82
  };
@@ -13,6 +13,21 @@ export interface GeneratorContext {
13
13
  * entries opt into a generator via section defaults / entry `generators:`.
14
14
  */
15
15
  apiNames?: string[];
16
+ /**
17
+ * Resolved output settings (declaration → entry override → generator
18
+ * default). Generators fall back to their own `defaultOutput` when absent
19
+ * (e.g. direct programmatic `generate()` calls).
20
+ */
21
+ output?: GeneratorOutputSettings;
22
+ }
23
+ /** How an api-scoped generator materializes files — all declarable in YAML. */
24
+ export interface GeneratorOutputSettings {
25
+ /** File name template; `{api-name}` / `{path}` allowed when `split` is true. */
26
+ file?: string;
27
+ /** true: one file per api. false: one bundled file per job. */
28
+ split?: boolean;
29
+ /** Free-form generator-specific tweaks (e.g. api-types `typesImport`). */
30
+ options?: Record<string, string>;
16
31
  }
17
32
  /**
18
33
  * A code generator turns the IR into one or more output files. Implementations
@@ -30,6 +45,11 @@ export interface Generator {
30
45
  * block runs it once for that yml.
31
46
  */
32
47
  readonly scope?: 'api' | 'document';
48
+ /** Built-in output defaults (api-scoped generators); overridable per declaration. */
49
+ readonly defaultOutput?: {
50
+ file: string;
51
+ split: boolean;
52
+ };
33
53
  generate(ir: Ir, context?: GeneratorContext): GeneratedFile[];
34
54
  }
35
55
  /** Narrow `ir.apis` to the compiler-selected subset (no-op without a filter). */
@@ -1 +1 @@
1
- {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../../../src/lib/_internal/generators/generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAEhC,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,UAAU,CAAA;IACnC,QAAQ,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,aAAa,EAAE,CAAA;CAC9D;AAED,iFAAiF;AACjF,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM,CAAC,EAAE,EAAE,UAAU,gBAAgB,KAAG,CAAC,EAI/F,CAAA"}
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../../../src/lib/_internal/generators/generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAEhC,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB;;;;OAIG;IACH,MAAM,CAAC,EAAE,uBAAuB,CAAA;CACjC;AAED,+EAA+E;AAC/E,MAAM,WAAW,uBAAuB;IACtC,gFAAgF;IAChF,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,+DAA+D;IAC/D,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC;AAED;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,UAAU,CAAA;IACnC,qFAAqF;IACrF,QAAQ,CAAC,aAAa,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAA;IACzD,QAAQ,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,aAAa,EAAE,CAAA;CAC9D;AAED,iFAAiF;AACjF,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM,CAAC,EAAE,EAAE,UAAU,gBAAgB,KAAG,CAAC,EAI/F,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"id-codec-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/id/id-codec-generator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAG5E,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AA2GD;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,UAAS,uBAA4B,KAAG,SA8B9E,CAAA"}
1
+ {"version":3,"file":"id-codec-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/id/id-codec-generator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAI5E,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AA2GD;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,UAAS,uBAA4B,KAAG,SA8B9E,CAAA"}
@@ -1,5 +1,6 @@
1
1
  import { pascalCase } from '../support/naming.js';
2
2
  import { headerBlocks } from '../support/header.js';
3
+ import { outputFile } from '../support/templates.js';
3
4
  const idFieldOf = (model) => {
4
5
  const ids = model.fields.filter(field => field.isId);
5
6
  return ids.length === 1 ? ids[0] : undefined;
@@ -129,7 +130,7 @@ export const createIdCodecGenerator = (options = {}) => {
129
130
  for (const { model, field } of entries) {
130
131
  blocks.push(renderCodec(model, field));
131
132
  }
132
- const files = [{ path: 'id-codecs.ts', content: `${blocks.join('\n\n')}\n` }];
133
+ const files = [{ path: outputFile(context, 'id-codecs.ts'), content: `${blocks.join('\n\n')}\n` }];
133
134
  // Emit the primitives too when the contract pins the Sqids settings.
134
135
  if (ir.project?.idCodec && core === './id-core') {
135
136
  files.push({ path: 'id-core.ts', content: idCoreFile(ir.project.idCodec) });
@@ -1 +1 @@
1
- {"version":3,"file":"sql-migration-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/sql/sql-migration-generator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AA+B5E;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,QAAO,SAY7C,CAAA"}
1
+ {"version":3,"file":"sql-migration-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/sql/sql-migration-generator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAgC5E;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,QAAO,SAY7C,CAAA"}
@@ -1,5 +1,6 @@
1
1
  import { pluralize, snakeCase } from '../support/naming.js';
2
2
  import { headerBlocks } from '../support/header.js';
3
+ import { outputFile } from '../support/templates.js';
3
4
  const tableName = (model) => model.table ?? pluralize(snakeCase(model.name));
4
5
  const renderModelSql = (model) => {
5
6
  const sql = model.sql;
@@ -39,6 +40,6 @@ export const createSqlMigrationGenerator = () => ({
39
40
  }
40
41
  const banner = headerBlocks(context, header => header.replace(/^\/\/ ?/gm, '-- '));
41
42
  const content = `${[...banner, blocks.join('\n')].join('\n\n')}\n`;
42
- return [{ path: 'migrations/constraints.sql', content }];
43
+ return [{ path: outputFile(context, 'migrations/constraints.sql'), content }];
43
44
  },
44
45
  });
@@ -0,0 +1,36 @@
1
+ /** Shared output-settings resolution + placeholder expansion for generators. Pure functions only. */
2
+ import { GeneratedFile, GeneratorContext } from '../generator.js';
3
+ export declare const API_PLACEHOLDER_RE: RegExp;
4
+ /** Drop `{param}` segments from a REST path and join the rest (`/ai-models/{id}` → `ai-models`). */
5
+ export declare const pathSegments: (apiPath: string) => string;
6
+ /**
7
+ * Expand `{api-name}` / `{path}` in an output template for one api. Returns
8
+ * undefined when `{path}` is used but the api has no REST path.
9
+ */
10
+ export declare const expandApiPlaceholders: (template: string, api: {
11
+ name: string;
12
+ path?: string;
13
+ }) => string | undefined;
14
+ /** Output settings after merging the compiler-resolved values over the generator's defaults. */
15
+ export interface ResolvedOutput {
16
+ file: string;
17
+ split: boolean;
18
+ options: Record<string, string>;
19
+ }
20
+ export declare const resolveOutput: (context: GeneratorContext | undefined, defaults: {
21
+ file: string;
22
+ split: boolean;
23
+ }) => ResolvedOutput;
24
+ /** `file` override for generators with a single (or barrel) output file. */
25
+ export declare const outputFile: (context: GeneratorContext | undefined, fallback: string) => string;
26
+ /**
27
+ * Materialize api-scoped output according to the resolved settings: `split`
28
+ * emits one file per api (expanding `{api-name}`/`{path}` in `file`), otherwise
29
+ * one bundled file named `file`. `render` returns the full content for the
30
+ * given api subset, or undefined to emit nothing for it.
31
+ */
32
+ export declare const emitApiFiles: <A extends {
33
+ name: string;
34
+ path?: string;
35
+ }>(apis: A[], output: ResolvedOutput, render: (subset: A[]) => string | undefined) => GeneratedFile[];
36
+ //# sourceMappingURL=templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/support/templates.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAGjE,eAAO,MAAM,kBAAkB,QAAwB,CAAA;AAEvD,oGAAoG;AACpG,eAAO,MAAM,YAAY,GAAI,SAAS,MAAM,KAAG,MAIjC,CAAA;AAEd;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAAI,UAAU,MAAM,EAAE,KAAK;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,KAAG,MAAM,GAAG,SAOvG,CAAA;AAED,gGAAgG;AAChG,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAChC;AAED,eAAO,MAAM,aAAa,GACxB,SAAS,gBAAgB,GAAG,SAAS,EACrC,UAAU;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,KACzC,cAID,CAAA;AAEF,4EAA4E;AAC5E,eAAO,MAAM,UAAU,GAAI,SAAS,gBAAgB,GAAG,SAAS,EAAE,UAAU,MAAM,KAAG,MAClD,CAAA;AAEnC;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EACpE,MAAM,CAAC,EAAE,EACT,QAAQ,cAAc,EACtB,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK,MAAM,GAAG,SAAS,KAC1C,aAAa,EAcf,CAAA"}
@@ -0,0 +1,50 @@
1
+ import { kebabCase } from './naming.js';
2
+ export const API_PLACEHOLDER_RE = /\{(api-name|path)\}/;
3
+ /** Drop `{param}` segments from a REST path and join the rest (`/ai-models/{id}` → `ai-models`). */
4
+ export const pathSegments = (apiPath) => apiPath
5
+ .split('/')
6
+ .filter(segment => segment.length > 0 && !(segment.startsWith('{') && segment.endsWith('}')))
7
+ .join('/');
8
+ /**
9
+ * Expand `{api-name}` / `{path}` in an output template for one api. Returns
10
+ * undefined when `{path}` is used but the api has no REST path.
11
+ */
12
+ export const expandApiPlaceholders = (template, api) => {
13
+ let out = template.replaceAll('{api-name}', kebabCase(api.name));
14
+ if (out.includes('{path}')) {
15
+ if (!api.path)
16
+ return undefined;
17
+ out = out.replaceAll('{path}', pathSegments(api.path));
18
+ }
19
+ return out;
20
+ };
21
+ export const resolveOutput = (context, defaults) => ({
22
+ file: context?.output?.file ?? defaults.file,
23
+ split: context?.output?.split ?? defaults.split,
24
+ options: context?.output?.options ?? {},
25
+ });
26
+ /** `file` override for generators with a single (or barrel) output file. */
27
+ export const outputFile = (context, fallback) => context?.output?.file ?? fallback;
28
+ /**
29
+ * Materialize api-scoped output according to the resolved settings: `split`
30
+ * emits one file per api (expanding `{api-name}`/`{path}` in `file`), otherwise
31
+ * one bundled file named `file`. `render` returns the full content for the
32
+ * given api subset, or undefined to emit nothing for it.
33
+ */
34
+ export const emitApiFiles = (apis, output, render) => {
35
+ if (!output.split) {
36
+ const content = render(apis);
37
+ return content === undefined ? [] : [{ path: output.file, content }];
38
+ }
39
+ const files = [];
40
+ for (const api of apis) {
41
+ const content = render([api]);
42
+ if (content === undefined)
43
+ continue;
44
+ const path = expandApiPlaceholders(output.file, api);
45
+ if (path === undefined)
46
+ continue;
47
+ files.push({ path, content });
48
+ }
49
+ return files;
50
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"typescript-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/typescript/typescript-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAK5E,MAAM,WAAW,0BAA0B;IACzC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;CAC9B;AA+ED;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,GAAI,UAAS,0BAA+B,KAAG,SAyBpF,CAAA"}
1
+ {"version":3,"file":"typescript-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/typescript/typescript-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAM5E,MAAM,WAAW,0BAA0B;IACzC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;CAC9B;AA+ED;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,GAAI,UAAS,0BAA+B,KAAG,SAyBpF,CAAA"}
@@ -1,6 +1,7 @@
1
1
  import { headerBlocks } from '../support/header.js';
2
2
  import { constantCase, singleQuote } from '../support/naming.js';
3
3
  import { isRelation, relationFkName, relationFkType } from '../support/relations.js';
4
+ import { outputFile } from '../support/templates.js';
4
5
  const SCALAR_TS = {
5
6
  string: 'string',
6
7
  int: 'number',
@@ -93,7 +94,7 @@ export const createTypeScriptGenerator = (options = {}) => {
93
94
  const fields = model.fields.map(field => renderField(field, ir)).join('\n');
94
95
  blocks.push(`${doc}export interface ${model.name} {\n${fields}\n}`);
95
96
  }
96
- return [{ path: 'types.ts', content: `${blocks.join('\n\n')}\n` }];
97
+ return [{ path: outputFile(context, 'types.ts'), content: `${blocks.join('\n\n')}\n` }];
97
98
  },
98
99
  };
99
100
  };
@@ -1 +1 @@
1
- {"version":3,"file":"typescript-split-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/typescript/typescript-split-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AA2F5E;;;;;;GAMG;AACH,eAAO,MAAM,8BAA8B,QAAO,SA0EhD,CAAA"}
1
+ {"version":3,"file":"typescript-split-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/typescript/typescript-split-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AA4F5E;;;;;;GAMG;AACH,eAAO,MAAM,8BAA8B,QAAO,SA0EhD,CAAA"}
@@ -3,6 +3,7 @@ import { headerBlocks } from '../support/header.js';
3
3
  import { constantCase, singleQuote } from '../support/naming.js';
4
4
  import { isRelation, relationFkName, relationFkType } from '../support/relations.js';
5
5
  import { assignModuleNames, collectDeps, splitGroups } from '../support/split.js';
6
+ import { outputFile } from '../support/templates.js';
6
7
  const SCALAR_TS = {
7
8
  string: 'string',
8
9
  int: 'number',
@@ -170,7 +171,7 @@ export const createTypeScriptSplitGenerator = () => ({
170
171
  emit(moduleName, enums, [...models, table], false);
171
172
  }
172
173
  const exports = files.map(file => `export * from './${file.path.replace(/^types\//, 'types/').replace(/\.ts$/, '')}'`);
173
- files.push({ path: 'types.ts', content: `${[...headerBlocks(context), exports.join('\n')].join('\n\n')}\n` });
174
+ files.push({ path: outputFile(context, 'types.ts'), content: `${[...headerBlocks(context), exports.join('\n')].join('\n\n')}\n` });
174
175
  return files;
175
176
  },
176
177
  });
@@ -1 +1 @@
1
- {"version":3,"file":"union-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/union/union-generator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAgB5E;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,QAAO,SAkBtC,CAAA"}
1
+ {"version":3,"file":"union-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/union/union-generator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAiB5E;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,QAAO,SAkBtC,CAAA"}
@@ -1,5 +1,6 @@
1
1
  import { singleQuote } from '../support/naming.js';
2
2
  import { headerBlocks } from '../support/header.js';
3
+ import { outputFile } from '../support/templates.js';
3
4
  const schemaName = (name) => `${name}Schema`;
4
5
  const renderUnion = (union) => {
5
6
  const variantSchemas = union.variants.map(schemaName).join(', ');
@@ -32,6 +33,6 @@ export const createUnionGenerator = () => ({
32
33
  for (const union of ir.unions) {
33
34
  blocks.push(renderUnion(union));
34
35
  }
35
- return [{ path: 'unions.ts', content: `${blocks.join('\n\n')}\n` }];
36
+ return [{ path: outputFile(context, 'unions.ts'), content: `${blocks.join('\n\n')}\n` }];
36
37
  },
37
38
  });
@@ -1 +1 @@
1
- {"version":3,"file":"zod-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/zod/zod-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAoD5E;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO,SAwBpC,CAAA"}
1
+ {"version":3,"file":"zod-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/zod/zod-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAqD5E;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO,SAwBpC,CAAA"}
@@ -2,6 +2,7 @@ import { headerBlocks } from '../support/header.js';
2
2
  import { singleQuote } from '../support/naming.js';
3
3
  import { isRelation, relationFkName, relationFkType } from '../support/relations.js';
4
4
  import { zodConstraints } from '../support/constraints.js';
5
+ import { outputFile } from '../support/templates.js';
5
6
  const SCALAR_ZOD = {
6
7
  string: 'z.string()',
7
8
  int: 'z.number().int()',
@@ -63,6 +64,6 @@ export const createZodGenerator = () => ({
63
64
  blocks.push(`export const ${schemaName(model.name)} = z.object({\n${fields}\n})\n` +
64
65
  `export type ${model.name} = z.infer<typeof ${schemaName(model.name)}>`);
65
66
  }
66
- return [{ path: 'schemas.ts', content: `${blocks.join('\n\n')}\n` }];
67
+ return [{ path: outputFile(context, 'schemas.ts'), content: `${blocks.join('\n\n')}\n` }];
67
68
  },
68
69
  });
@@ -1 +1 @@
1
- {"version":3,"file":"zod-split-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/zod/zod-split-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAkE5E;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,QAAO,SAmEzC,CAAA"}
1
+ {"version":3,"file":"zod-split-generator.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/zod/zod-split-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,SAAS,EAAoB,MAAM,iBAAiB,CAAA;AAmE5E;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,QAAO,SAmEzC,CAAA"}
@@ -4,6 +4,7 @@ import { headerBlocks } from '../support/header.js';
4
4
  import { singleQuote } from '../support/naming.js';
5
5
  import { isRelation, relationFkName, relationFkType } from '../support/relations.js';
6
6
  import { assignModuleNames, collectDeps, splitGroups } from '../support/split.js';
7
+ import { outputFile } from '../support/templates.js';
7
8
  const SCALAR_ZOD = {
8
9
  string: 'z.string()',
9
10
  int: 'z.number().int()',
@@ -131,7 +132,7 @@ export const createZodSplitGenerator = () => ({
131
132
  emit(moduleName, enums, [...models, table]);
132
133
  }
133
134
  const exports = files.map(file => `export * from './${file.path.replace(/\.ts$/, '')}'`);
134
- files.push({ path: 'schemas.ts', content: `${[...headerBlocks(context), exports.join('\n')].join('\n\n')}\n` });
135
+ files.push({ path: outputFile(context, 'schemas.ts'), content: `${[...headerBlocks(context), exports.join('\n')].join('\n\n')}\n` });
135
136
  return files;
136
137
  },
137
138
  });
@@ -1 +1 @@
1
- {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../../../src/lib/_internal/parser/parse.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,WAAW,EAaZ,MAAM,mBAAmB,CAAA;AA2hB1B;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,EAAE,UAAU,MAAM,KAAG,WA4MjE,CAAA"}
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../../../src/lib/_internal/parser/parse.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,WAAW,EAaZ,MAAM,mBAAmB,CAAA;AA4jB1B;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,EAAE,UAAU,MAAM,KAAG,WAmNjE,CAAA"}
@@ -396,15 +396,33 @@ const normalizeApiPayload = (raw, filePath, path) => {
396
396
  }
397
397
  return payload;
398
398
  };
399
+ const normalizeGeneratorOptions = (raw, filePath, path) => {
400
+ if (!isObject(raw)) {
401
+ return fail(`"${path}" must be a mapping of string options`, filePath, path);
402
+ }
403
+ const options = {};
404
+ for (const [key, value] of Object.entries(raw)) {
405
+ options[key] = String(value);
406
+ }
407
+ return options;
408
+ };
399
409
  const normalizeGeneratorUse = (raw, filePath, path) => {
400
410
  if (typeof raw === 'string')
401
411
  return { generator: raw };
402
412
  if (!isObject(raw) || typeof raw.generator !== 'string') {
403
- return fail(`"${path}" must be a generator name or { generator, out? }`, filePath, path);
413
+ return fail(`"${path}" must be a generator name or { generator, out?, file?, split?, options?, header? }`, filePath, path);
404
414
  }
405
415
  const use = { generator: raw.generator };
406
416
  if (raw.out !== undefined)
407
417
  use.out = String(raw.out);
418
+ if (raw.file !== undefined)
419
+ use.file = String(raw.file);
420
+ if (raw.split !== undefined)
421
+ use.split = Boolean(raw.split);
422
+ if (raw.options !== undefined)
423
+ use.options = normalizeGeneratorOptions(raw.options, filePath, `${path}.options`);
424
+ if (raw.header !== undefined)
425
+ use.header = String(raw.header);
408
426
  return use;
409
427
  };
410
428
  const normalizeGeneratorUses = (raw, filePath, path) => {
@@ -423,9 +441,15 @@ const normalizeSectionDefaults = (raw, filePath, section) => {
423
441
  return [];
424
442
  return normalizeGeneratorUses(raw.generators, filePath, `${section}.${SECTION_DEFAULTS_KEY}.generators`);
425
443
  };
444
+ /** `METHOD /path` keys let the same route appear once per verb (`PUT /x` + `DELETE /x`). */
445
+ const METHOD_PREFIXED_KEY_RE = /^([A-Z]+) (\/.*)$/;
446
+ /** True when an `apis:` key is a route form this parser accepts (`/path` or `METHOD /path`). */
447
+ const isPathApiKey = (key) => key.startsWith('/') || METHOD_PREFIXED_KEY_RE.test(key);
426
448
  /**
427
- * Path-keyed api entry (`apis:` section, key starts with `/`): kind defaults to
428
- * `https` (or `callable` when declared), `operationId` names the generated types.
449
+ * Path-keyed api entry (`apis:` section, key `/path` or `METHOD /path`): kind
450
+ * defaults to `https` (or `callable` when declared), `operationId` names the
451
+ * generated types. A method prefix in the key wins over a `method:` field —
452
+ * declaring both with different values is an error.
429
453
  */
430
454
  const normalizePathApi = (raw, filePath, pathKey) => {
431
455
  if (!isObject(raw)) {
@@ -438,9 +462,19 @@ const normalizePathApi = (raw, filePath, pathKey) => {
438
462
  if (kind !== 'https' && kind !== 'callable') {
439
463
  return fail(`Api "${pathKey}" kind must be https|callable (tasks/events have their own sections)`, filePath, `apis.${pathKey}.kind`);
440
464
  }
441
- const api = { kind, path: pathKey };
442
- if (raw.method !== undefined)
465
+ const prefixed = METHOD_PREFIXED_KEY_RE.exec(pathKey);
466
+ const keyMethod = prefixed?.[1];
467
+ const routePath = prefixed?.[2] ?? pathKey;
468
+ const api = { kind, path: routePath };
469
+ if (keyMethod !== undefined) {
470
+ if (raw.method !== undefined && String(raw.method) !== keyMethod) {
471
+ return fail(`Api "${pathKey}" declares method "${String(raw.method)}" but the key says "${keyMethod}"`, filePath, `apis.${pathKey}.method`);
472
+ }
473
+ api.method = keyMethod;
474
+ }
475
+ else if (raw.method !== undefined) {
443
476
  api.method = String(raw.method);
477
+ }
444
478
  if (raw.description !== undefined)
445
479
  api.description = String(raw.description);
446
480
  api.request = normalizeApiPayload(raw.request, filePath, `apis.${pathKey}.request`);
@@ -711,13 +745,13 @@ export const parseContract = (content, filePath) => {
711
745
  if (key === SECTION_DEFAULTS_KEY) {
712
746
  sectionDefaults.apis = normalizeSectionDefaults(raw, filePath, 'apis');
713
747
  }
714
- else if (key.startsWith('/')) {
715
- // Path-keyed REST form: the key is the route, `operationId` names the api.
748
+ else if (isPathApiKey(key)) {
749
+ // Path-keyed REST form (`/path` or `METHOD /path`); `operationId` names the api.
716
750
  const { name, api } = normalizePathApi(raw, filePath, key);
717
751
  addApi(name, api, 'apis');
718
752
  }
719
753
  else {
720
- fail(`"apis" keys must be REST paths starting with "/" (tasks/events have their own sections): "${key}"`, filePath, `apis.${key}`);
754
+ fail(`"apis" keys must be REST paths ("/path" or "METHOD /path"; tasks/events have their own sections): "${key}"`, filePath, `apis.${key}`);
721
755
  }
722
756
  }
723
757
  }
@@ -805,7 +839,17 @@ export const parseContract = (content, filePath) => {
805
839
  if (typeof entry.out !== 'string') {
806
840
  return fail(`generators[${i}] needs a string "out"`, filePath, `generators[${i}].out`);
807
841
  }
808
- return { generator: entry.generator, out: entry.out };
842
+ const decl = { generator: entry.generator, out: entry.out };
843
+ if (entry.file !== undefined)
844
+ decl.file = String(entry.file);
845
+ if (entry.split !== undefined)
846
+ decl.split = Boolean(entry.split);
847
+ if (entry.options !== undefined) {
848
+ decl.options = normalizeGeneratorOptions(entry.options, filePath, `generators[${i}].options`);
849
+ }
850
+ if (entry.header !== undefined)
851
+ decl.header = String(entry.header);
852
+ return decl;
809
853
  });
810
854
  }
811
855
  if (Object.keys(sectionDefaults).length > 0) {
@@ -177,11 +177,23 @@ export interface RawGeneratorDecl {
177
177
  * resolved through the root document's `project.aliases`.
178
178
  */
179
179
  out: string;
180
+ /** File name template (api-scoped; `{api-name}`/`{path}` allowed with split). */
181
+ file?: string;
182
+ /** true: one file per api. false: one bundled file. Default: the generator's own. */
183
+ split?: boolean;
184
+ /** Free-form generator-specific tweaks (string values). */
185
+ options?: Record<string, string>;
186
+ /** Header override for this generator (`default` = built-in banner, `''` = none). */
187
+ header?: string;
180
188
  }
181
- /** Generator application on a section default or an entry (name ref + optional out override). */
189
+ /** Generator application on a section default or an entry (name ref + optional overrides). */
182
190
  export interface RawGeneratorUse {
183
191
  generator: string;
184
192
  out?: string;
193
+ file?: string;
194
+ split?: boolean;
195
+ options?: Record<string, string>;
196
+ header?: string;
185
197
  }
186
198
  /** Per-section generator defaults (`apis:/tasks:/events:` → `defaults.generators`). */
187
199
  export interface RawSectionDefaults {
@@ -1 +1 @@
1
- {"version":3,"file":"raw-document.d.ts","sourceRoot":"","sources":["../../../../src/lib/_internal/parser/raw-document.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"raw-document.d.ts","sourceRoot":"","sources":["../../../../src/lib/_internal/parser/raw-document.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-contract",
3
- "version": "0.1.0-rc.6",
3
+ "version": "0.1.0-rc.7",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "firebase-contract": "./dist/lib/cli/index.js",