firebase-contract 0.1.0-rc.0 → 0.1.0-rc.1
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/dist/lib/_internal/compiler/compiler.d.ts +12 -0
- package/dist/lib/_internal/compiler/compiler.d.ts.map +1 -1
- package/dist/lib/_internal/compiler/compiler.js +18 -1
- package/dist/lib/_internal/generators/support/split.d.ts +7 -0
- package/dist/lib/_internal/generators/support/split.d.ts.map +1 -1
- package/dist/lib/_internal/generators/support/split.js +22 -0
- package/dist/lib/_internal/generators/typescript/typescript-split-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/typescript/typescript-split-generator.js +4 -3
- package/dist/lib/_internal/generators/zod/zod-split-generator.d.ts.map +1 -1
- package/dist/lib/_internal/generators/zod/zod-split-generator.js +4 -3
- package/dist/lib/cli/commands/generate.d.ts.map +1 -1
- package/dist/lib/cli/commands/generate.js +26 -3
- package/dist/lib/cli/index.js +0 -0
- package/package.json +1 -1
|
@@ -54,6 +54,18 @@ export declare const generateAll: (entryPath: string, options?: {
|
|
|
54
54
|
context?: GeneratorContext;
|
|
55
55
|
loader?: ModuleLoader;
|
|
56
56
|
}) => GenerateAllResult;
|
|
57
|
+
export interface FileDrift {
|
|
58
|
+
/** Files whose on-disk content differs from the generated content. */
|
|
59
|
+
changed: string[];
|
|
60
|
+
/** Files that generation produces but do not exist on disk yet. */
|
|
61
|
+
missing: string[];
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Compare generated files against what is currently on disk — the dry-run
|
|
65
|
+
* behind `fbc generate --check`, catching "the contract changed but the
|
|
66
|
+
* committed outputs were not regenerated" drift without touching the tree.
|
|
67
|
+
*/
|
|
68
|
+
export declare const diffFiles: (files: GeneratedFile[]) => FileDrift;
|
|
57
69
|
export interface GenerateResult {
|
|
58
70
|
ir: Ir;
|
|
59
71
|
diagnostics: Diagnostic[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../../../src/lib/_internal/compiler/compiler.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAoB,MAAM,mBAAmB,CAAA;AAEhE,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAEvD,OAAO,EAAkB,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAG3E,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAE5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAE7D,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,MAAM,CAAC,EAAE,YAAY,CAAA;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,EAAE,CAAA;IACN,SAAS,EAAE,WAAW,EAAE,CAAA;IACxB,WAAW,EAAE,UAAU,EAAE,CAAA;CAC1B;AAED;;;;;GAKG;AACH,eAAO,MAAM,OAAO,GAAI,WAAW,MAAM,EAAE,UAAS,cAAmB,KAAG,aAUzE,CAAA;AAED,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,MAAM,EAAE,MAAM,CAAA;IACd,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B,oDAAoD;IACpD,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,OAAO,CAAC,EAAE,gBAAgB,CAAA;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,KAAK,EAAE,aAAa,EAAE,CAAA;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,oBAAoB,EAAE,CAAA;IAC/B,WAAW,EAAE,UAAU,EAAE,CAAA;IACzB,EAAE,EAAE,OAAO,CAAA;CACZ;AAED;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GACtB,WAAW,MAAM,EACjB,UAAS;IAAE,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAAC,MAAM,CAAC,EAAE,YAAY,CAAA;CAAO,KACjH,iBA8BF,CAAA;AAED,MAAM,WAAW,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,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAEvD,OAAO,EAAkB,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAG3E,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAE5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAE7D,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,MAAM,CAAC,EAAE,YAAY,CAAA;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,EAAE,CAAA;IACN,SAAS,EAAE,WAAW,EAAE,CAAA;IACxB,WAAW,EAAE,UAAU,EAAE,CAAA;CAC1B;AAED;;;;;GAKG;AACH,eAAO,MAAM,OAAO,GAAI,WAAW,MAAM,EAAE,UAAS,cAAmB,KAAG,aAUzE,CAAA;AAED,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,MAAM,EAAE,MAAM,CAAA;IACd,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B,oDAAoD;IACpD,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,OAAO,CAAC,EAAE,gBAAgB,CAAA;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,KAAK,EAAE,aAAa,EAAE,CAAA;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,oBAAoB,EAAE,CAAA;IAC/B,WAAW,EAAE,UAAU,EAAE,CAAA;IACzB,EAAE,EAAE,OAAO,CAAA;CACZ;AAED;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GACtB,WAAW,MAAM,EACjB,UAAS;IAAE,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAAC,MAAM,CAAC,EAAE,YAAY,CAAA;CAAO,KACjH,iBA8BF,CAAA;AAED,MAAM,WAAW,SAAS;IACxB,sEAAsE;IACtE,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,mEAAmE;IACnE,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,OAAO,aAAa,EAAE,KAAG,SAUlD,CAAA;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,EAAE,CAAA;IACN,WAAW,EAAE,UAAU,EAAE,CAAA;IACzB,oFAAoF;IACpF,KAAK,EAAE,aAAa,EAAE,CAAA;IACtB,0DAA0D;IAC1D,EAAE,EAAE,OAAO,CAAA;CACZ;AAED;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,WAAW,MAAM,EAAE,SAAS,eAAe,KAAG,cAuCtE,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
3
|
import { error, hasErrors } from '../diagnostics.js';
|
|
4
4
|
import { buildIr } from '../ir/build-ir.js';
|
|
@@ -62,6 +62,23 @@ export const generateAll = (entryPath, options = {}) => {
|
|
|
62
62
|
}
|
|
63
63
|
return { targets, diagnostics: collected, ok };
|
|
64
64
|
};
|
|
65
|
+
/**
|
|
66
|
+
* Compare generated files against what is currently on disk — the dry-run
|
|
67
|
+
* behind `fbc generate --check`, catching "the contract changed but the
|
|
68
|
+
* committed outputs were not regenerated" drift without touching the tree.
|
|
69
|
+
*/
|
|
70
|
+
export const diffFiles = (files) => {
|
|
71
|
+
const drift = { changed: [], missing: [] };
|
|
72
|
+
for (const file of files) {
|
|
73
|
+
if (!existsSync(file.path)) {
|
|
74
|
+
drift.missing.push(file.path);
|
|
75
|
+
}
|
|
76
|
+
else if (readFileSync(file.path, 'utf8') !== file.content) {
|
|
77
|
+
drift.changed.push(file.path);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return drift;
|
|
81
|
+
};
|
|
65
82
|
/**
|
|
66
83
|
* Compile then emit code. Generation is skipped when compilation produced any
|
|
67
84
|
* error, so generators never see an invalid IR. The CLI is a thin wrapper over
|
|
@@ -15,6 +15,13 @@ export interface HostedDeps {
|
|
|
15
15
|
* declarations can be emitted top-down without forward references.
|
|
16
16
|
*/
|
|
17
17
|
export declare const collectDeps: (ir: Ir, roots: IrModel[]) => HostedDeps;
|
|
18
|
+
/**
|
|
19
|
+
* Assign a unique module basename to every table. Two models may share a
|
|
20
|
+
* physical table name across services (e.g. both declare
|
|
21
|
+
* `reconciliation_operations`); the first keeps the table-derived name and
|
|
22
|
+
* later ones fall back to their model name so files never overwrite each other.
|
|
23
|
+
*/
|
|
24
|
+
export declare const assignModuleNames: (tables: IrModel[]) => Map<string, string>;
|
|
18
25
|
export interface SplitGroups {
|
|
19
26
|
tables: IrModel[];
|
|
20
27
|
/** enum name → hosting table model name */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"split.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/support/split.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,EAAE,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAIvD,qEAAqE;AACrE,eAAO,MAAM,OAAO,GAAI,OAAO,OAAO,KAAG,OAAiE,CAAA;AAE1G,eAAO,MAAM,WAAW,GAAI,OAAO,OAAO,KAAG,MAAyD,CAAA;AAEtG,eAAO,MAAM,SAAS,GAAI,OAAO,MAAM,KAAG,MAA6C,CAAA;AAavF,MAAM,WAAW,UAAU;IACzB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,8DAA8D;IAC9D,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAED;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,IAAI,EAAE,EAAE,OAAO,OAAO,EAAE,KAAG,UAuBtD,CAAA;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,OAAO,EAAE,CAAA;IACjB,2CAA2C;IAC3C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,qDAAqD;IACrD,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,oDAAoD;IACpD,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,8CAA8C;IAC9C,cAAc,EAAE,MAAM,EAAE,CAAA;CACzB;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,GAAI,IAAI,EAAE,KAAG,WAepC,CAAA"}
|
|
1
|
+
{"version":3,"file":"split.d.ts","sourceRoot":"","sources":["../../../../../src/lib/_internal/generators/support/split.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,EAAE,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAIvD,qEAAqE;AACrE,eAAO,MAAM,OAAO,GAAI,OAAO,OAAO,KAAG,OAAiE,CAAA;AAE1G,eAAO,MAAM,WAAW,GAAI,OAAO,OAAO,KAAG,MAAyD,CAAA;AAEtG,eAAO,MAAM,SAAS,GAAI,OAAO,MAAM,KAAG,MAA6C,CAAA;AAavF,MAAM,WAAW,UAAU;IACzB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,8DAA8D;IAC9D,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAED;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,IAAI,EAAE,EAAE,OAAO,OAAO,EAAE,KAAG,UAuBtD,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,OAAO,EAAE,KAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAavE,CAAA;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,OAAO,EAAE,CAAA;IACjB,2CAA2C;IAC3C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,qDAAqD;IACrD,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,oDAAoD;IACpD,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,8CAA8C;IAC9C,cAAc,EAAE,MAAM,EAAE,CAAA;CACzB;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,GAAI,IAAI,EAAE,KAAG,WAepC,CAAA"}
|
|
@@ -49,6 +49,28 @@ export const collectDeps = (ir, roots) => {
|
|
|
49
49
|
visit(root);
|
|
50
50
|
return { enums, models };
|
|
51
51
|
};
|
|
52
|
+
/**
|
|
53
|
+
* Assign a unique module basename to every table. Two models may share a
|
|
54
|
+
* physical table name across services (e.g. both declare
|
|
55
|
+
* `reconciliation_operations`); the first keeps the table-derived name and
|
|
56
|
+
* later ones fall back to their model name so files never overwrite each other.
|
|
57
|
+
*/
|
|
58
|
+
export const assignModuleNames = (tables) => {
|
|
59
|
+
const used = new Set();
|
|
60
|
+
const names = new Map();
|
|
61
|
+
for (const table of tables) {
|
|
62
|
+
let name = kebabCase(tableNameOf(table));
|
|
63
|
+
if (used.has(name))
|
|
64
|
+
name = kebabCase(pluralize(snakeCase(table.name)));
|
|
65
|
+
let candidate = name;
|
|
66
|
+
let suffix = 2;
|
|
67
|
+
while (used.has(candidate))
|
|
68
|
+
candidate = `${name}-${suffix++}`;
|
|
69
|
+
used.add(candidate);
|
|
70
|
+
names.set(table.name, candidate);
|
|
71
|
+
}
|
|
72
|
+
return names;
|
|
73
|
+
};
|
|
52
74
|
/**
|
|
53
75
|
* Assign every enum and embedded model to the first table model that
|
|
54
76
|
* (transitively) references it; the rest become shared leftovers.
|
|
@@ -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,
|
|
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"}
|
|
@@ -2,7 +2,7 @@ import { findEnum, findModel } from '../../ir/ir.js';
|
|
|
2
2
|
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
|
-
import {
|
|
5
|
+
import { assignModuleNames, collectDeps, splitGroups } from '../support/split.js';
|
|
6
6
|
const SCALAR_TS = {
|
|
7
7
|
string: 'string',
|
|
8
8
|
int: 'number',
|
|
@@ -95,6 +95,7 @@ export const createTypeScriptSplitGenerator = () => ({
|
|
|
95
95
|
description: 'TypeScript interfaces, one file per table (types/<table>.ts + types.ts barrel)',
|
|
96
96
|
generate(ir, context) {
|
|
97
97
|
const groups = splitGroups(ir);
|
|
98
|
+
const moduleNames = assignModuleNames(groups.tables);
|
|
98
99
|
const files = [];
|
|
99
100
|
const fileOf = new Map(); // symbol -> module basename (no ext)
|
|
100
101
|
const sharedNeeded = usesJson(ir.models) || groups.leftoverEnums.length > 0 || groups.leftoverModels.length > 0;
|
|
@@ -105,7 +106,7 @@ export const createTypeScriptSplitGenerator = () => ({
|
|
|
105
106
|
for (const name of groups.leftoverModels)
|
|
106
107
|
fileOf.set(name, '_shared');
|
|
107
108
|
for (const table of groups.tables) {
|
|
108
|
-
const moduleName =
|
|
109
|
+
const moduleName = moduleNames.get(table.name) ?? table.name;
|
|
109
110
|
fileOf.set(table.name, moduleName);
|
|
110
111
|
for (const [name, home] of groups.enumHome)
|
|
111
112
|
if (home === table.name)
|
|
@@ -156,7 +157,7 @@ export const createTypeScriptSplitGenerator = () => ({
|
|
|
156
157
|
emit('_shared', enums, models, usesJson(ir.models));
|
|
157
158
|
}
|
|
158
159
|
for (const table of groups.tables) {
|
|
159
|
-
const moduleName =
|
|
160
|
+
const moduleName = moduleNames.get(table.name) ?? table.name;
|
|
160
161
|
const deps = collectDeps(ir, [table]);
|
|
161
162
|
const enums = deps.enums
|
|
162
163
|
.filter(name => groups.enumHome.get(name) === table.name)
|
|
@@ -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,
|
|
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"}
|
|
@@ -3,7 +3,7 @@ import { zodConstraints } from '../support/constraints.js';
|
|
|
3
3
|
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
|
-
import {
|
|
6
|
+
import { assignModuleNames, collectDeps, splitGroups } from '../support/split.js';
|
|
7
7
|
const SCALAR_ZOD = {
|
|
8
8
|
string: 'z.string()',
|
|
9
9
|
int: 'z.number().int()',
|
|
@@ -66,6 +66,7 @@ export const createZodSplitGenerator = () => ({
|
|
|
66
66
|
description: 'Zod schemas, one file per table (schemas/<table>.ts + schemas.ts barrel)',
|
|
67
67
|
generate(ir, context) {
|
|
68
68
|
const groups = splitGroups(ir);
|
|
69
|
+
const moduleNames = assignModuleNames(groups.tables);
|
|
69
70
|
const files = [];
|
|
70
71
|
const fileOf = new Map();
|
|
71
72
|
for (const name of groups.leftoverEnums)
|
|
@@ -73,7 +74,7 @@ export const createZodSplitGenerator = () => ({
|
|
|
73
74
|
for (const name of groups.leftoverModels)
|
|
74
75
|
fileOf.set(name, '_shared');
|
|
75
76
|
for (const table of groups.tables) {
|
|
76
|
-
const moduleName =
|
|
77
|
+
const moduleName = moduleNames.get(table.name) ?? table.name;
|
|
77
78
|
fileOf.set(table.name, moduleName);
|
|
78
79
|
for (const [name, home] of groups.enumHome)
|
|
79
80
|
if (home === table.name)
|
|
@@ -117,7 +118,7 @@ export const createZodSplitGenerator = () => ({
|
|
|
117
118
|
emit('_shared', enums, models);
|
|
118
119
|
}
|
|
119
120
|
for (const table of groups.tables) {
|
|
120
|
-
const moduleName =
|
|
121
|
+
const moduleName = moduleNames.get(table.name) ?? table.name;
|
|
121
122
|
const deps = collectDeps(ir, [table]);
|
|
122
123
|
const enums = deps.enums
|
|
123
124
|
.filter(name => groups.enumHome.get(name) === table.name)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../../src/lib/cli/commands/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../../src/lib/cli/commands/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AA4BnC,eAAO,MAAM,gBAAgB,GAAI,SAAS,OAAO,KAAG,IAgFnD,CAAA"}
|
|
@@ -1,8 +1,20 @@
|
|
|
1
|
-
import { generate, generateAll } from '../../_internal/compiler/compiler.js';
|
|
1
|
+
import { diffFiles, generate, generateAll } from '../../_internal/compiler/compiler.js';
|
|
2
2
|
import { DEFAULT_HEADER, toHeaderComment } from '../../_internal/generators/support/header.js';
|
|
3
3
|
import { countBySeverity, formatDiagnostics } from '../../_internal/format-diagnostics.js';
|
|
4
4
|
import { createDefaultRegistry } from '../../_internal/generators/index.js';
|
|
5
5
|
import { loadConfig } from '../config.js';
|
|
6
|
+
const reportDrift = (changed, missing) => {
|
|
7
|
+
if (changed.length === 0 && missing.length === 0) {
|
|
8
|
+
console.log('✔ no drift — on-disk files match the contract');
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
console.error('✖ drift detected — regenerate and commit the outputs (fbc generate):');
|
|
12
|
+
for (const path of changed)
|
|
13
|
+
console.error(` changed: ${path}`);
|
|
14
|
+
for (const path of missing)
|
|
15
|
+
console.error(` missing: ${path}`);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
};
|
|
6
18
|
export const registerGenerate = (program) => {
|
|
7
19
|
program
|
|
8
20
|
.command('generate')
|
|
@@ -11,6 +23,7 @@ export const registerGenerate = (program) => {
|
|
|
11
23
|
.option('-o, --out-dir <dir>', 'output directory')
|
|
12
24
|
.option('-g, --generators <list>', 'comma-separated generator names')
|
|
13
25
|
.option('--header [text]', 'prepend a comment header to generated files (bare --header = default banner; omitted = contract `header:` or none)')
|
|
26
|
+
.option('--check', 'verify the on-disk files match what would be generated; exits 1 on drift (writes nothing)')
|
|
14
27
|
.action((entryArg, flags) => {
|
|
15
28
|
const config = loadConfig();
|
|
16
29
|
const entry = entryArg ?? config.entry ?? 'contract.yml';
|
|
@@ -23,7 +36,7 @@ export const registerGenerate = (program) => {
|
|
|
23
36
|
// graph — the one-command flow. Flags switch back to single-target mode.
|
|
24
37
|
const explicit = flags.outDir !== undefined || flags.generators !== undefined || config.outDir !== undefined || config.generators !== undefined;
|
|
25
38
|
if (!explicit) {
|
|
26
|
-
const all = generateAll(entry, { registry, write:
|
|
39
|
+
const all = generateAll(entry, { registry, write: !flags.check, ...(context ? { context } : {}) });
|
|
27
40
|
if (all.targets.length > 0 || !all.ok) {
|
|
28
41
|
if (all.diagnostics.length > 0) {
|
|
29
42
|
console.log(formatDiagnostics(all.diagnostics));
|
|
@@ -33,6 +46,11 @@ export const registerGenerate = (program) => {
|
|
|
33
46
|
console.error(`\n✖ generation aborted: ${errors} error(s)`);
|
|
34
47
|
process.exit(1);
|
|
35
48
|
}
|
|
49
|
+
if (flags.check) {
|
|
50
|
+
const drift = diffFiles(all.targets.flatMap(target => target.files));
|
|
51
|
+
reportDrift(drift.changed, drift.missing);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
36
54
|
let total = 0;
|
|
37
55
|
for (const target of all.targets) {
|
|
38
56
|
total += target.files.length;
|
|
@@ -47,7 +65,7 @@ export const registerGenerate = (program) => {
|
|
|
47
65
|
outDir,
|
|
48
66
|
generators,
|
|
49
67
|
registry,
|
|
50
|
-
write:
|
|
68
|
+
write: !flags.check,
|
|
51
69
|
...(context ? { context } : {}),
|
|
52
70
|
});
|
|
53
71
|
if (result.diagnostics.length > 0) {
|
|
@@ -58,6 +76,11 @@ export const registerGenerate = (program) => {
|
|
|
58
76
|
console.error(`\n✖ generation aborted: ${errors} error(s)`);
|
|
59
77
|
process.exit(1);
|
|
60
78
|
}
|
|
79
|
+
if (flags.check) {
|
|
80
|
+
const drift = diffFiles(result.files);
|
|
81
|
+
reportDrift(drift.changed, drift.missing);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
61
84
|
for (const file of result.files) {
|
|
62
85
|
console.log(`generated ${file.path}`);
|
|
63
86
|
}
|
package/dist/lib/cli/index.js
CHANGED
|
File without changes
|