@cedarjs/internal 4.0.0-canary.13809 → 4.0.0-canary.13811
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/cjs/generate/generate.d.ts.map +1 -1
- package/dist/cjs/generate/generate.js +1 -1
- package/dist/cjs/generate/gqlormSchema.d.ts +78 -2
- package/dist/cjs/generate/gqlormSchema.d.ts.map +1 -1
- package/dist/cjs/generate/gqlormSchema.js +417 -10
- package/dist/cjs/generate/watch.js +17 -10
- package/dist/generate/generate.d.ts.map +1 -1
- package/dist/generate/generate.js +1 -1
- package/dist/generate/gqlormSchema.d.ts +78 -2
- package/dist/generate/gqlormSchema.d.ts.map +1 -1
- package/dist/generate/gqlormSchema.js +411 -10
- package/dist/generate/watch.js +15 -8
- package/package.json +10 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/generate/generate.ts"],"names":[],"mappings":";AAWA,eAAO,MAAM,QAAQ;;;;;;
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/generate/generate.ts"],"names":[],"mappings":";AAWA,eAAO,MAAM,QAAQ;;;;;;EA2CpB,CAAA;AAED,eAAO,MAAM,GAAG,qBAoCf,CAAA"}
|
|
@@ -36,7 +36,7 @@ const generate = async () => {
|
|
|
36
36
|
const { typeDefFiles, errors: generateTypeDefsErrors } = await (0, import_typeDefinitions.generateTypeDefs)();
|
|
37
37
|
const clientPresetFiles = [];
|
|
38
38
|
const { possibleTypesFiles, errors: generatePossibleTypesErrors } = await (0, import_possibleTypes.generatePossibleTypes)();
|
|
39
|
-
const { files: gqlormFiles, errors: gqlormErrors } =
|
|
39
|
+
const { files: gqlormFiles, errors: gqlormErrors } = await (0, import_gqlormSchema.generateGqlormArtifacts)();
|
|
40
40
|
if (config.graphql.trustedDocuments) {
|
|
41
41
|
const preset = await (0, import_clientPreset.generateClientPreset)();
|
|
42
42
|
clientPresetFiles.push(...preset.clientPresetFiles);
|
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
import type * as DMMF from '@prisma/dmmf';
|
|
2
2
|
type ModelSchema = Record<string, string[]>;
|
|
3
|
+
interface FrontendFieldInfo {
|
|
4
|
+
name: string;
|
|
5
|
+
tsType: string;
|
|
6
|
+
}
|
|
7
|
+
interface FrontendModelInfo {
|
|
8
|
+
modelName: string;
|
|
9
|
+
camelName: string;
|
|
10
|
+
fields: FrontendFieldInfo[];
|
|
11
|
+
}
|
|
12
|
+
export interface BackendFieldInfo {
|
|
13
|
+
name: string;
|
|
14
|
+
graphqlType: string;
|
|
15
|
+
isRequired: boolean;
|
|
16
|
+
isId: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface BackendModelInfo {
|
|
19
|
+
modelName: string;
|
|
20
|
+
camelName: string;
|
|
21
|
+
pluralName: string;
|
|
22
|
+
fields: BackendFieldInfo[];
|
|
23
|
+
idField: BackendFieldInfo | undefined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Map a DMMF field type to its GraphQL SDL equivalent.
|
|
27
|
+
*
|
|
28
|
+
* Enum fields (kind === 'enum') are mapped to String. Unknown scalar types
|
|
29
|
+
* fall back to String.
|
|
30
|
+
*/
|
|
31
|
+
export declare function mapDmmfTypeToGraphql(type: string, kind: string): string;
|
|
32
|
+
export declare function buildFrontendModelInfo(dmmf: DMMF.Document): FrontendModelInfo[];
|
|
33
|
+
export declare function generateWebGqlormModelsContent(models: FrontendModelInfo[]): string;
|
|
3
34
|
/**
|
|
4
35
|
* Build a ModelSchema from a Prisma DMMF document.
|
|
5
36
|
*
|
|
@@ -7,12 +38,57 @@ type ModelSchema = Record<string, string[]>;
|
|
|
7
38
|
* with a mock DMMF object.
|
|
8
39
|
*/
|
|
9
40
|
export declare function buildModelSchema(dmmf: DMMF.Document): ModelSchema;
|
|
41
|
+
/**
|
|
42
|
+
* Build enriched model information from the DMMF, applying the same visibility
|
|
43
|
+
* rules as `buildModelSchema()` but also collecting type, nullability, and
|
|
44
|
+
* @id flag per field.
|
|
45
|
+
*
|
|
46
|
+
* **Note:** This function silently excludes sensitive fields without emitting
|
|
47
|
+
* warnings. It is designed to run after `buildModelSchema()` (which emits the
|
|
48
|
+
* warnings). In `generateGqlormArtifacts()` the call order is guaranteed, but
|
|
49
|
+
* callers using this function standalone should be aware that no warnings will
|
|
50
|
+
* be printed for auto-hidden sensitive fields.
|
|
51
|
+
*
|
|
52
|
+
* This is a pure function — safe for testing.
|
|
53
|
+
*/
|
|
54
|
+
export declare function buildBackendModelInfo(dmmf: DMMF.Document): BackendModelInfo[];
|
|
55
|
+
/**
|
|
56
|
+
* Scan all SDL files in the given directory and return the set of GraphQL type
|
|
57
|
+
* names that are already defined by user-authored SDLs.
|
|
58
|
+
*
|
|
59
|
+
* This prevents gqlorm from generating duplicate type definitions that would
|
|
60
|
+
* cause merge conflicts in `makeMergedSchema`.
|
|
61
|
+
*/
|
|
62
|
+
export declare function getExistingSdlTypeNames(graphqlDir: string): Set<string>;
|
|
63
|
+
/**
|
|
64
|
+
* Generate the full TypeScript source for `.cedar/gqlorm/backend.ts`.
|
|
65
|
+
*
|
|
66
|
+
* The generated file exports:
|
|
67
|
+
* - `schema`: a gql DocumentNode with type defs and Query fields
|
|
68
|
+
* - `createGqlormResolvers(db: GqlormDb)`: a factory function that takes a
|
|
69
|
+
* Prisma client-like object and returns a resolvers object
|
|
70
|
+
*
|
|
71
|
+
* The file does NOT import `db` directly. Instead, the Babel inject plugin
|
|
72
|
+
* imports `db` from `src/lib/db` in `graphql.ts` (where that alias resolves
|
|
73
|
+
* correctly) and passes it to `createGqlormResolvers`.
|
|
74
|
+
*
|
|
75
|
+
* The generated `GqlormDb` interface is scoped to exactly the visible models
|
|
76
|
+
* and fields — no hidden/sensitive fields, no @gqlorm hide models, no
|
|
77
|
+
* dependency on the generated Prisma client path or @prisma/client.
|
|
78
|
+
*/
|
|
79
|
+
export declare function generateGqlormBackendContent(models: BackendModelInfo[]): string;
|
|
10
80
|
/**
|
|
11
81
|
* Generate gqlorm artifacts from the Prisma schema.
|
|
12
82
|
*
|
|
13
83
|
* Reads the project's Prisma schema via DMMF, applies visibility rules
|
|
14
|
-
* (@gqlorm directives + sensitivity heuristics), and writes
|
|
15
|
-
*
|
|
84
|
+
* (@gqlorm directives + sensitivity heuristics), and writes:
|
|
85
|
+
*
|
|
86
|
+
* 1. `.cedar/gqlorm-schema.json` — the frontend ModelSchema (field names only)
|
|
87
|
+
* 2. `.cedar/gqlorm/backend.ts` — auto-generated GraphQL types and resolvers
|
|
88
|
+
* for models that don't already have manually-written SDL files
|
|
89
|
+
*
|
|
90
|
+
* Cedar targets Node.js 24, which strips TypeScript types natively without any
|
|
91
|
+
* flags, so backend.ts can be imported directly at runtime
|
|
16
92
|
*
|
|
17
93
|
* Returns the same `{ files, errors }` shape used by other generators so it
|
|
18
94
|
* can be integrated into `generate.ts` without special handling.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gqlormSchema.d.ts","sourceRoot":"","sources":["../../../src/generate/gqlormSchema.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,IAAI,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"gqlormSchema.d.ts","sourceRoot":"","sources":["../../../src/generate/gqlormSchema.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,IAAI,MAAM,cAAc,CAAA;AA8BzC,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;AAE3C,UAAU,iBAAiB;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;CACf;AAED,UAAU,iBAAiB;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,iBAAiB,EAAE,CAAA;CAC5B;AAMD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,OAAO,CAAA;IACnB,IAAI,EAAE,OAAO,CAAA;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,gBAAgB,EAAE,CAAA;IAC1B,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAAA;CACtC;AAqDD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAMvE;AAoGD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,IAAI,CAAC,QAAQ,GAClB,iBAAiB,EAAE,CAiDrB;AAED,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,iBAAiB,EAAE,GAC1B,MAAM,CA2CR;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,GAAG,WAAW,CAkDjE;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,GAAG,gBAAgB,EAAE,CA2D7E;AAkBD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CA6BvE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,gBAAgB,EAAE,GACzB,MAAM,CA0IR;AAMD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC;IACvD,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;CAC9C,CAAC,CAgFD"}
|
|
@@ -28,15 +28,35 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
29
|
var gqlormSchema_exports = {};
|
|
30
30
|
__export(gqlormSchema_exports, {
|
|
31
|
+
buildBackendModelInfo: () => buildBackendModelInfo,
|
|
32
|
+
buildFrontendModelInfo: () => buildFrontendModelInfo,
|
|
31
33
|
buildModelSchema: () => buildModelSchema,
|
|
32
|
-
generateGqlormArtifacts: () => generateGqlormArtifacts
|
|
34
|
+
generateGqlormArtifacts: () => generateGqlormArtifacts,
|
|
35
|
+
generateGqlormBackendContent: () => generateGqlormBackendContent,
|
|
36
|
+
generateWebGqlormModelsContent: () => generateWebGqlormModelsContent,
|
|
37
|
+
getExistingSdlTypeNames: () => getExistingSdlTypeNames,
|
|
38
|
+
mapDmmfTypeToGraphql: () => mapDmmfTypeToGraphql
|
|
33
39
|
});
|
|
34
40
|
module.exports = __toCommonJS(gqlormSchema_exports);
|
|
35
41
|
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
36
42
|
var import_node_path = __toESM(require("node:path"), 1);
|
|
37
43
|
var import_project_config = require("@cedarjs/project-config");
|
|
38
|
-
|
|
39
|
-
const
|
|
44
|
+
var import_cedarPluralize = require("@cedarjs/utils/cedarPluralize");
|
|
45
|
+
const INTERNAL_MODEL_NAMES = /* @__PURE__ */ new Set([
|
|
46
|
+
"RW_DataMigration",
|
|
47
|
+
"Cedar_DataMigration"
|
|
48
|
+
]);
|
|
49
|
+
const SENSITIVE_PATTERNS = [
|
|
50
|
+
"password",
|
|
51
|
+
"secret",
|
|
52
|
+
"token",
|
|
53
|
+
"hash",
|
|
54
|
+
"salt",
|
|
55
|
+
"apikey",
|
|
56
|
+
"secretkey",
|
|
57
|
+
"encryptionkey",
|
|
58
|
+
"privatekey"
|
|
59
|
+
];
|
|
40
60
|
function hasDirective(doc, directive) {
|
|
41
61
|
if (!doc) {
|
|
42
62
|
return false;
|
|
@@ -56,6 +76,172 @@ function emitSensitivityWarning(modelName, fieldName) {
|
|
|
56
76
|
`
|
|
57
77
|
);
|
|
58
78
|
}
|
|
79
|
+
const DMMF_TYPE_TO_GRAPHQL = {
|
|
80
|
+
String: "String",
|
|
81
|
+
Int: "Int",
|
|
82
|
+
Float: "Float",
|
|
83
|
+
BigInt: "BigInt",
|
|
84
|
+
Boolean: "Boolean",
|
|
85
|
+
DateTime: "DateTime",
|
|
86
|
+
Json: "JSON",
|
|
87
|
+
Decimal: "String",
|
|
88
|
+
Bytes: "String"
|
|
89
|
+
};
|
|
90
|
+
function mapDmmfTypeToGraphql(type, kind) {
|
|
91
|
+
if (kind === "enum") {
|
|
92
|
+
return "String";
|
|
93
|
+
}
|
|
94
|
+
return DMMF_TYPE_TO_GRAPHQL[type] ?? "String";
|
|
95
|
+
}
|
|
96
|
+
function graphqlTypeToTsType(graphqlType) {
|
|
97
|
+
switch (graphqlType) {
|
|
98
|
+
case "Int":
|
|
99
|
+
case "Float":
|
|
100
|
+
case "BigInt":
|
|
101
|
+
return "number";
|
|
102
|
+
case "Boolean":
|
|
103
|
+
return "boolean";
|
|
104
|
+
default:
|
|
105
|
+
return "string";
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function graphqlTypeToTsInterfaceType(graphqlType, isRequired) {
|
|
109
|
+
let tsType;
|
|
110
|
+
switch (graphqlType) {
|
|
111
|
+
case "Int":
|
|
112
|
+
case "Float":
|
|
113
|
+
case "BigInt":
|
|
114
|
+
tsType = "number";
|
|
115
|
+
break;
|
|
116
|
+
case "Boolean":
|
|
117
|
+
tsType = "boolean";
|
|
118
|
+
break;
|
|
119
|
+
case "DateTime":
|
|
120
|
+
tsType = "Date";
|
|
121
|
+
break;
|
|
122
|
+
default:
|
|
123
|
+
tsType = "string";
|
|
124
|
+
}
|
|
125
|
+
return isRequired ? tsType : `${tsType} | null`;
|
|
126
|
+
}
|
|
127
|
+
function dmmfTypeToFrontendTsType(type, kind, isRequired) {
|
|
128
|
+
let tsType;
|
|
129
|
+
if (kind === "enum") {
|
|
130
|
+
tsType = "string";
|
|
131
|
+
} else {
|
|
132
|
+
switch (type) {
|
|
133
|
+
case "String":
|
|
134
|
+
tsType = "string";
|
|
135
|
+
break;
|
|
136
|
+
case "Int":
|
|
137
|
+
case "Float":
|
|
138
|
+
tsType = "number";
|
|
139
|
+
break;
|
|
140
|
+
case "BigInt":
|
|
141
|
+
tsType = "bigint";
|
|
142
|
+
break;
|
|
143
|
+
case "Boolean":
|
|
144
|
+
tsType = "boolean";
|
|
145
|
+
break;
|
|
146
|
+
case "DateTime":
|
|
147
|
+
tsType = "string";
|
|
148
|
+
break;
|
|
149
|
+
case "Json":
|
|
150
|
+
tsType = "unknown";
|
|
151
|
+
break;
|
|
152
|
+
case "Bytes":
|
|
153
|
+
case "Decimal":
|
|
154
|
+
tsType = "string";
|
|
155
|
+
break;
|
|
156
|
+
default:
|
|
157
|
+
tsType = "unknown";
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (isRequired) {
|
|
161
|
+
return tsType;
|
|
162
|
+
}
|
|
163
|
+
return `${tsType} | null`;
|
|
164
|
+
}
|
|
165
|
+
function buildFrontendModelInfo(dmmf) {
|
|
166
|
+
const models = [];
|
|
167
|
+
for (const model of dmmf.datamodel.models) {
|
|
168
|
+
if (INTERNAL_MODEL_NAMES.has(model.name)) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (hasDirective(model.documentation, "hide")) {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
const fields = [];
|
|
175
|
+
for (const field of model.fields) {
|
|
176
|
+
if (field.kind !== "scalar" && field.kind !== "enum") {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (hasDirective(field.documentation, "hide")) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
const isShown = hasDirective(field.documentation, "show");
|
|
183
|
+
if (!isShown && isSensitiveField(field.name)) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
fields.push({
|
|
187
|
+
name: field.name,
|
|
188
|
+
tsType: dmmfTypeToFrontendTsType(
|
|
189
|
+
field.type,
|
|
190
|
+
field.kind,
|
|
191
|
+
field.isRequired
|
|
192
|
+
)
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
if (fields.length > 0) {
|
|
196
|
+
models.push({
|
|
197
|
+
modelName: model.name,
|
|
198
|
+
camelName: model.name.charAt(0).toLowerCase() + model.name.slice(1),
|
|
199
|
+
fields
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return models;
|
|
204
|
+
}
|
|
205
|
+
function generateWebGqlormModelsContent(models) {
|
|
206
|
+
if (models.length === 0) {
|
|
207
|
+
return [
|
|
208
|
+
"// Auto-generated by Cedar \u2014 do not edit",
|
|
209
|
+
"// Regenerated on every codegen run. Source: api/db/schema.prisma",
|
|
210
|
+
"",
|
|
211
|
+
"declare module '@cedarjs/gqlorm/types/orm' {",
|
|
212
|
+
" interface GqlormTypeMap {}",
|
|
213
|
+
"}",
|
|
214
|
+
""
|
|
215
|
+
].join("\n");
|
|
216
|
+
}
|
|
217
|
+
const lines = [
|
|
218
|
+
"// Auto-generated by Cedar \u2014 do not edit",
|
|
219
|
+
"// Regenerated on every codegen run. Source: api/db/schema.prisma",
|
|
220
|
+
"",
|
|
221
|
+
"declare namespace GqlormScalar {"
|
|
222
|
+
];
|
|
223
|
+
for (const model of models) {
|
|
224
|
+
lines.push(` interface ${model.modelName} {`);
|
|
225
|
+
for (const field of model.fields) {
|
|
226
|
+
lines.push(` ${field.name}: ${field.tsType}`);
|
|
227
|
+
}
|
|
228
|
+
lines.push(" }");
|
|
229
|
+
lines.push("");
|
|
230
|
+
}
|
|
231
|
+
lines.push("}");
|
|
232
|
+
lines.push("");
|
|
233
|
+
lines.push("declare module '@cedarjs/gqlorm/types/orm' {");
|
|
234
|
+
lines.push(" interface GqlormTypeMap {");
|
|
235
|
+
lines.push(" models: {");
|
|
236
|
+
for (const model of models) {
|
|
237
|
+
lines.push(` ${model.camelName}: GqlormScalar.${model.modelName}`);
|
|
238
|
+
}
|
|
239
|
+
lines.push(" }");
|
|
240
|
+
lines.push(" }");
|
|
241
|
+
lines.push("}");
|
|
242
|
+
lines.push("");
|
|
243
|
+
return lines.join("\n");
|
|
244
|
+
}
|
|
59
245
|
function buildModelSchema(dmmf) {
|
|
60
246
|
const schema = {};
|
|
61
247
|
for (const model of dmmf.datamodel.models) {
|
|
@@ -90,6 +276,185 @@ function buildModelSchema(dmmf) {
|
|
|
90
276
|
}
|
|
91
277
|
return schema;
|
|
92
278
|
}
|
|
279
|
+
function buildBackendModelInfo(dmmf) {
|
|
280
|
+
const models = [];
|
|
281
|
+
for (const model of dmmf.datamodel.models) {
|
|
282
|
+
if (INTERNAL_MODEL_NAMES.has(model.name)) {
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
if (hasDirective(model.documentation, "hide")) {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
const fields = [];
|
|
289
|
+
for (const field of model.fields) {
|
|
290
|
+
if (field.kind !== "scalar" && field.kind !== "enum") {
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (hasDirective(field.documentation, "hide")) {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
const isShown = hasDirective(field.documentation, "show");
|
|
297
|
+
if (!isShown && isSensitiveField(field.name)) {
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
fields.push({
|
|
301
|
+
name: field.name,
|
|
302
|
+
graphqlType: mapDmmfTypeToGraphql(field.type, field.kind),
|
|
303
|
+
isRequired: field.isRequired,
|
|
304
|
+
isId: field.isId
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
if (fields.length > 0) {
|
|
308
|
+
const camelName = model.name.charAt(0).toLowerCase() + model.name.slice(1);
|
|
309
|
+
const pluralName = (0, import_cedarPluralize.pluralize)(camelName);
|
|
310
|
+
models.push({
|
|
311
|
+
modelName: model.name,
|
|
312
|
+
camelName,
|
|
313
|
+
pluralName,
|
|
314
|
+
fields,
|
|
315
|
+
idField: fields.find((f) => f.isId)
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return models;
|
|
320
|
+
}
|
|
321
|
+
const TYPE_DEF_REGEX = /\btype\s+([A-Z]\w*)\s*\{/g;
|
|
322
|
+
const STRUCTURAL_TYPE_NAMES = /* @__PURE__ */ new Set(["Query", "Mutation", "Subscription"]);
|
|
323
|
+
function getExistingSdlTypeNames(graphqlDir) {
|
|
324
|
+
const typeNames = /* @__PURE__ */ new Set();
|
|
325
|
+
if (!import_node_fs.default.existsSync(graphqlDir)) {
|
|
326
|
+
return typeNames;
|
|
327
|
+
}
|
|
328
|
+
const sdlFiles = import_node_fs.default.readdirSync(graphqlDir).filter((file) => {
|
|
329
|
+
return /\.sdl\.(ts|js)$/.test(file) && !file.startsWith("__gqlorm__");
|
|
330
|
+
});
|
|
331
|
+
for (const file of sdlFiles) {
|
|
332
|
+
const content = import_node_fs.default.readFileSync(import_node_path.default.join(graphqlDir, file), "utf-8");
|
|
333
|
+
let match;
|
|
334
|
+
TYPE_DEF_REGEX.lastIndex = 0;
|
|
335
|
+
while ((match = TYPE_DEF_REGEX.exec(content)) !== null) {
|
|
336
|
+
const name = match[1];
|
|
337
|
+
if (!STRUCTURAL_TYPE_NAMES.has(name)) {
|
|
338
|
+
typeNames.add(name);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return typeNames;
|
|
343
|
+
}
|
|
344
|
+
function generateGqlormBackendContent(models) {
|
|
345
|
+
if (models.length === 0) {
|
|
346
|
+
return "";
|
|
347
|
+
}
|
|
348
|
+
const lines = [
|
|
349
|
+
"// This file is auto-generated by Cedar gqlorm codegen.",
|
|
350
|
+
"// Do not edit \u2014 it will be overwritten on every codegen run.",
|
|
351
|
+
"// To hide a model from gqlorm, add /// @gqlorm hide in schema.prisma.",
|
|
352
|
+
"",
|
|
353
|
+
"import gql from 'graphql-tag'",
|
|
354
|
+
"",
|
|
355
|
+
"// Generated minimal interface \u2014 only visible models and fields, only the",
|
|
356
|
+
"// operations used by this file. No @gqlorm hide models, no sensitive fields.",
|
|
357
|
+
"// Scoped to avoid any dependency on the generated Prisma client path or",
|
|
358
|
+
"// @prisma/client (which is an empty shim in Prisma v7).",
|
|
359
|
+
"interface GqlormDb {"
|
|
360
|
+
];
|
|
361
|
+
for (const model of models) {
|
|
362
|
+
const selectType = model.fields.map((f) => `${f.name}: true`).join("; ");
|
|
363
|
+
lines.push(` ${model.camelName}: {`);
|
|
364
|
+
lines.push(" findMany(args: {");
|
|
365
|
+
lines.push(` select: { ${selectType} }`);
|
|
366
|
+
lines.push(" }): Promise<");
|
|
367
|
+
lines.push(" Array<{");
|
|
368
|
+
for (const field of model.fields) {
|
|
369
|
+
const tsType = graphqlTypeToTsInterfaceType(
|
|
370
|
+
field.graphqlType,
|
|
371
|
+
field.isRequired
|
|
372
|
+
);
|
|
373
|
+
lines.push(` ${field.name}: ${tsType}`);
|
|
374
|
+
}
|
|
375
|
+
lines.push(" }>");
|
|
376
|
+
lines.push(" >");
|
|
377
|
+
if (model.idField) {
|
|
378
|
+
const idTsType = graphqlTypeToTsType(model.idField.graphqlType);
|
|
379
|
+
lines.push(" findUnique(args: {");
|
|
380
|
+
lines.push(` where: { ${model.idField.name}: ${idTsType} }`);
|
|
381
|
+
lines.push(` select: { ${selectType} }`);
|
|
382
|
+
lines.push(" }): Promise<{");
|
|
383
|
+
for (const field of model.fields) {
|
|
384
|
+
const tsType = graphqlTypeToTsInterfaceType(
|
|
385
|
+
field.graphqlType,
|
|
386
|
+
field.isRequired
|
|
387
|
+
);
|
|
388
|
+
lines.push(` ${field.name}: ${tsType}`);
|
|
389
|
+
}
|
|
390
|
+
lines.push(" } | null>");
|
|
391
|
+
}
|
|
392
|
+
lines.push(" }");
|
|
393
|
+
}
|
|
394
|
+
lines.push("}");
|
|
395
|
+
lines.push("");
|
|
396
|
+
lines.push("export const schema = gql`");
|
|
397
|
+
for (const model of models) {
|
|
398
|
+
lines.push(` type ${model.modelName} {`);
|
|
399
|
+
for (const field of model.fields) {
|
|
400
|
+
const nullMark = field.isRequired ? "!" : "";
|
|
401
|
+
lines.push(` ${field.name}: ${field.graphqlType}${nullMark}`);
|
|
402
|
+
}
|
|
403
|
+
lines.push(" }");
|
|
404
|
+
lines.push("");
|
|
405
|
+
}
|
|
406
|
+
lines.push(" type Query {");
|
|
407
|
+
for (const model of models) {
|
|
408
|
+
lines.push(` ${model.pluralName}: [${model.modelName}!]! @skipAuth`);
|
|
409
|
+
if (model.idField) {
|
|
410
|
+
const idNullMark = model.idField.isRequired ? "!" : "";
|
|
411
|
+
lines.push(
|
|
412
|
+
` ${model.camelName}(${model.idField.name}: ${model.idField.graphqlType}${idNullMark}): ${model.modelName} @skipAuth`
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
lines.push(" }");
|
|
417
|
+
lines.push("`");
|
|
418
|
+
lines.push("");
|
|
419
|
+
lines.push(
|
|
420
|
+
"// db is passed in from graphql.ts by the Babel inject plugin, which imports it"
|
|
421
|
+
);
|
|
422
|
+
lines.push(
|
|
423
|
+
"// from 'src/lib/db' in a context where that alias resolves correctly."
|
|
424
|
+
);
|
|
425
|
+
lines.push("export function createGqlormResolvers(db: GqlormDb) {");
|
|
426
|
+
lines.push(" return {");
|
|
427
|
+
lines.push(" Query: {");
|
|
428
|
+
for (let i = 0; i < models.length; i++) {
|
|
429
|
+
const model = models[i];
|
|
430
|
+
const selectObj = model.fields.map((f) => `${f.name}: true`).join(", ");
|
|
431
|
+
lines.push(` ${model.pluralName}: () => {`);
|
|
432
|
+
lines.push(` return db.${model.camelName}.findMany({`);
|
|
433
|
+
lines.push(` select: { ${selectObj} },`);
|
|
434
|
+
lines.push(" })");
|
|
435
|
+
lines.push(" },");
|
|
436
|
+
if (model.idField) {
|
|
437
|
+
const idFieldName = model.idField.name;
|
|
438
|
+
const tsType = graphqlTypeToTsType(model.idField.graphqlType);
|
|
439
|
+
lines.push(
|
|
440
|
+
` ${model.camelName}: (_root: unknown, { ${idFieldName} }: { ${idFieldName}: ${tsType} }) => {`
|
|
441
|
+
);
|
|
442
|
+
lines.push(` return db.${model.camelName}.findUnique({`);
|
|
443
|
+
lines.push(` where: { ${idFieldName} },`);
|
|
444
|
+
lines.push(` select: { ${selectObj} },`);
|
|
445
|
+
lines.push(" })");
|
|
446
|
+
lines.push(" },");
|
|
447
|
+
}
|
|
448
|
+
if (i < models.length - 1) {
|
|
449
|
+
lines.push("");
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
lines.push(" },");
|
|
453
|
+
lines.push(" }");
|
|
454
|
+
lines.push("}");
|
|
455
|
+
lines.push("");
|
|
456
|
+
return lines.join("\n");
|
|
457
|
+
}
|
|
93
458
|
async function generateGqlormArtifacts() {
|
|
94
459
|
const files = [];
|
|
95
460
|
const errors = [];
|
|
@@ -98,14 +463,50 @@ async function generateGqlormArtifacts() {
|
|
|
98
463
|
const mod = await import("@prisma/internals");
|
|
99
464
|
const { getDMMF } = mod.default || mod;
|
|
100
465
|
const dmmf = await getDMMF({ datamodel: schemas });
|
|
466
|
+
const paths = (0, import_project_config.getPaths)();
|
|
467
|
+
const generatedBase = paths.generated.base;
|
|
101
468
|
const modelSchema = buildModelSchema(dmmf);
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
469
|
+
const frontendModels = buildFrontendModelInfo(dmmf);
|
|
470
|
+
const schemaOutputPath = import_node_path.default.join(generatedBase, "gqlorm-schema.json");
|
|
471
|
+
const webTypesOutputPath = import_node_path.default.join(
|
|
472
|
+
generatedBase,
|
|
473
|
+
"types",
|
|
474
|
+
"includes",
|
|
475
|
+
"web-gqlorm-models.d.ts"
|
|
476
|
+
);
|
|
477
|
+
import_node_fs.default.mkdirSync(import_node_path.default.dirname(schemaOutputPath), { recursive: true });
|
|
478
|
+
import_node_fs.default.writeFileSync(schemaOutputPath, JSON.stringify(modelSchema, null, 2));
|
|
479
|
+
files.push(schemaOutputPath);
|
|
480
|
+
import_node_fs.default.mkdirSync(import_node_path.default.dirname(webTypesOutputPath), { recursive: true });
|
|
481
|
+
import_node_fs.default.writeFileSync(
|
|
482
|
+
webTypesOutputPath,
|
|
483
|
+
generateWebGqlormModelsContent(frontendModels)
|
|
105
484
|
);
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
485
|
+
files.push(webTypesOutputPath);
|
|
486
|
+
const backendOutputDir = import_node_path.default.join(generatedBase, "gqlorm");
|
|
487
|
+
const backendOutputPath = import_node_path.default.join(backendOutputDir, "backend.ts");
|
|
488
|
+
if ((0, import_project_config.getConfig)().experimental?.gqlorm?.enabled) {
|
|
489
|
+
const graphqlDir = paths.api.graphql;
|
|
490
|
+
const existingTypes = getExistingSdlTypeNames(graphqlDir);
|
|
491
|
+
const allModels = buildBackendModelInfo(dmmf);
|
|
492
|
+
const gqlormModels = allModels.filter(
|
|
493
|
+
(m) => !existingTypes.has(m.modelName)
|
|
494
|
+
);
|
|
495
|
+
if (gqlormModels.length > 0) {
|
|
496
|
+
const backendContent = generateGqlormBackendContent(gqlormModels);
|
|
497
|
+
import_node_fs.default.mkdirSync(backendOutputDir, { recursive: true });
|
|
498
|
+
import_node_fs.default.writeFileSync(backendOutputPath, backendContent);
|
|
499
|
+
files.push(backendOutputPath);
|
|
500
|
+
} else {
|
|
501
|
+
if (import_node_fs.default.existsSync(backendOutputPath)) {
|
|
502
|
+
import_node_fs.default.unlinkSync(backendOutputPath);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
} else {
|
|
506
|
+
if (import_node_fs.default.existsSync(backendOutputPath)) {
|
|
507
|
+
import_node_fs.default.unlinkSync(backendOutputPath);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
109
510
|
} catch (error) {
|
|
110
511
|
errors.push({
|
|
111
512
|
message: "Failed to generate gqlorm schema artifacts",
|
|
@@ -116,6 +517,12 @@ async function generateGqlormArtifacts() {
|
|
|
116
517
|
}
|
|
117
518
|
// Annotate the CommonJS export names for ESM import in node:
|
|
118
519
|
0 && (module.exports = {
|
|
520
|
+
buildBackendModelInfo,
|
|
521
|
+
buildFrontendModelInfo,
|
|
119
522
|
buildModelSchema,
|
|
120
|
-
generateGqlormArtifacts
|
|
523
|
+
generateGqlormArtifacts,
|
|
524
|
+
generateGqlormBackendContent,
|
|
525
|
+
generateWebGqlormModelsContent,
|
|
526
|
+
getExistingSdlTypeNames,
|
|
527
|
+
mapDmmfTypeToGraphql
|
|
121
528
|
});
|
|
@@ -23,7 +23,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
mod
|
|
24
24
|
));
|
|
25
25
|
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
26
|
-
var
|
|
26
|
+
var import_node_path = __toESM(require("node:path"), 1);
|
|
27
27
|
var import_ansis = __toESM(require("ansis"), 1);
|
|
28
28
|
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
29
29
|
var import_project_config = require("@cedarjs/project-config");
|
|
@@ -32,18 +32,22 @@ var import_files = require("../files.js");
|
|
|
32
32
|
var import_routes = require("../routes.js");
|
|
33
33
|
var import_clientPreset = require("./clientPreset.js");
|
|
34
34
|
var import_generate = require("./generate.js");
|
|
35
|
+
var import_gqlormSchema = require("./gqlormSchema.js");
|
|
35
36
|
var import_graphqlCodeGen = require("./graphqlCodeGen.js");
|
|
36
37
|
var import_graphqlSchema = require("./graphqlSchema.js");
|
|
37
38
|
var import_typeDefinitions = require("./typeDefinitions.js");
|
|
38
39
|
const rwjsPaths = (0, import_project_config.getPaths)();
|
|
39
|
-
const generatedDirName =
|
|
40
|
-
const watcher = import_chokidar.default.watch(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
const generatedDirName = import_node_path.default.basename(rwjsPaths.generated.base);
|
|
41
|
+
const watcher = import_chokidar.default.watch(
|
|
42
|
+
["(web|api)/src/**/*.{ts,js,jsx,tsx}", "api/db/**/*.prisma"],
|
|
43
|
+
{
|
|
44
|
+
persistent: true,
|
|
45
|
+
ignored: ["node_modules", generatedDirName],
|
|
46
|
+
ignoreInitial: true,
|
|
47
|
+
cwd: rwjsPaths.base,
|
|
48
|
+
awaitWriteFinish: true
|
|
49
|
+
}
|
|
50
|
+
);
|
|
47
51
|
const action = {
|
|
48
52
|
add: "Created",
|
|
49
53
|
unlink: "Deleted",
|
|
@@ -83,7 +87,7 @@ Created ${files.length} in ${Date.now() - start} ms`);
|
|
|
83
87
|
return;
|
|
84
88
|
}
|
|
85
89
|
const eventTigger = eventName;
|
|
86
|
-
const absPath =
|
|
90
|
+
const absPath = import_node_path.default.join(rwjsPaths.base, p);
|
|
87
91
|
const start = Date.now();
|
|
88
92
|
const finished = (type) => import_cliLogger.cliLogger.debug(
|
|
89
93
|
action[eventTigger],
|
|
@@ -118,6 +122,9 @@ Created ${files.length} in ${Date.now() - start} ms`);
|
|
|
118
122
|
await (0, import_graphqlSchema.generateGraphQLSchema)();
|
|
119
123
|
await (0, import_graphqlCodeGen.generateTypeDefGraphQLApi)();
|
|
120
124
|
finished("GraphQL Schema");
|
|
125
|
+
} else if (absPath.startsWith(import_node_path.default.join(rwjsPaths.base, "api/db/")) && absPath.endsWith(".prisma")) {
|
|
126
|
+
await (0, import_gqlormSchema.generateGqlormArtifacts)();
|
|
127
|
+
finished("Prisma Schema");
|
|
121
128
|
}
|
|
122
129
|
if (routesWarningMessage) {
|
|
123
130
|
console.warn(routesWarningMessage);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/generate/generate.ts"],"names":[],"mappings":";AAWA,eAAO,MAAM,QAAQ;;;;;;
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/generate/generate.ts"],"names":[],"mappings":";AAWA,eAAO,MAAM,QAAQ;;;;;;EA2CpB,CAAA;AAED,eAAO,MAAM,GAAG,qBAoCf,CAAA"}
|
|
@@ -12,7 +12,7 @@ const generate = async () => {
|
|
|
12
12
|
const { typeDefFiles, errors: generateTypeDefsErrors } = await generateTypeDefs();
|
|
13
13
|
const clientPresetFiles = [];
|
|
14
14
|
const { possibleTypesFiles, errors: generatePossibleTypesErrors } = await generatePossibleTypes();
|
|
15
|
-
const { files: gqlormFiles, errors: gqlormErrors } =
|
|
15
|
+
const { files: gqlormFiles, errors: gqlormErrors } = await generateGqlormArtifacts();
|
|
16
16
|
if (config.graphql.trustedDocuments) {
|
|
17
17
|
const preset = await generateClientPreset();
|
|
18
18
|
clientPresetFiles.push(...preset.clientPresetFiles);
|
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
import type * as DMMF from '@prisma/dmmf';
|
|
2
2
|
type ModelSchema = Record<string, string[]>;
|
|
3
|
+
interface FrontendFieldInfo {
|
|
4
|
+
name: string;
|
|
5
|
+
tsType: string;
|
|
6
|
+
}
|
|
7
|
+
interface FrontendModelInfo {
|
|
8
|
+
modelName: string;
|
|
9
|
+
camelName: string;
|
|
10
|
+
fields: FrontendFieldInfo[];
|
|
11
|
+
}
|
|
12
|
+
export interface BackendFieldInfo {
|
|
13
|
+
name: string;
|
|
14
|
+
graphqlType: string;
|
|
15
|
+
isRequired: boolean;
|
|
16
|
+
isId: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface BackendModelInfo {
|
|
19
|
+
modelName: string;
|
|
20
|
+
camelName: string;
|
|
21
|
+
pluralName: string;
|
|
22
|
+
fields: BackendFieldInfo[];
|
|
23
|
+
idField: BackendFieldInfo | undefined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Map a DMMF field type to its GraphQL SDL equivalent.
|
|
27
|
+
*
|
|
28
|
+
* Enum fields (kind === 'enum') are mapped to String. Unknown scalar types
|
|
29
|
+
* fall back to String.
|
|
30
|
+
*/
|
|
31
|
+
export declare function mapDmmfTypeToGraphql(type: string, kind: string): string;
|
|
32
|
+
export declare function buildFrontendModelInfo(dmmf: DMMF.Document): FrontendModelInfo[];
|
|
33
|
+
export declare function generateWebGqlormModelsContent(models: FrontendModelInfo[]): string;
|
|
3
34
|
/**
|
|
4
35
|
* Build a ModelSchema from a Prisma DMMF document.
|
|
5
36
|
*
|
|
@@ -7,12 +38,57 @@ type ModelSchema = Record<string, string[]>;
|
|
|
7
38
|
* with a mock DMMF object.
|
|
8
39
|
*/
|
|
9
40
|
export declare function buildModelSchema(dmmf: DMMF.Document): ModelSchema;
|
|
41
|
+
/**
|
|
42
|
+
* Build enriched model information from the DMMF, applying the same visibility
|
|
43
|
+
* rules as `buildModelSchema()` but also collecting type, nullability, and
|
|
44
|
+
* @id flag per field.
|
|
45
|
+
*
|
|
46
|
+
* **Note:** This function silently excludes sensitive fields without emitting
|
|
47
|
+
* warnings. It is designed to run after `buildModelSchema()` (which emits the
|
|
48
|
+
* warnings). In `generateGqlormArtifacts()` the call order is guaranteed, but
|
|
49
|
+
* callers using this function standalone should be aware that no warnings will
|
|
50
|
+
* be printed for auto-hidden sensitive fields.
|
|
51
|
+
*
|
|
52
|
+
* This is a pure function — safe for testing.
|
|
53
|
+
*/
|
|
54
|
+
export declare function buildBackendModelInfo(dmmf: DMMF.Document): BackendModelInfo[];
|
|
55
|
+
/**
|
|
56
|
+
* Scan all SDL files in the given directory and return the set of GraphQL type
|
|
57
|
+
* names that are already defined by user-authored SDLs.
|
|
58
|
+
*
|
|
59
|
+
* This prevents gqlorm from generating duplicate type definitions that would
|
|
60
|
+
* cause merge conflicts in `makeMergedSchema`.
|
|
61
|
+
*/
|
|
62
|
+
export declare function getExistingSdlTypeNames(graphqlDir: string): Set<string>;
|
|
63
|
+
/**
|
|
64
|
+
* Generate the full TypeScript source for `.cedar/gqlorm/backend.ts`.
|
|
65
|
+
*
|
|
66
|
+
* The generated file exports:
|
|
67
|
+
* - `schema`: a gql DocumentNode with type defs and Query fields
|
|
68
|
+
* - `createGqlormResolvers(db: GqlormDb)`: a factory function that takes a
|
|
69
|
+
* Prisma client-like object and returns a resolvers object
|
|
70
|
+
*
|
|
71
|
+
* The file does NOT import `db` directly. Instead, the Babel inject plugin
|
|
72
|
+
* imports `db` from `src/lib/db` in `graphql.ts` (where that alias resolves
|
|
73
|
+
* correctly) and passes it to `createGqlormResolvers`.
|
|
74
|
+
*
|
|
75
|
+
* The generated `GqlormDb` interface is scoped to exactly the visible models
|
|
76
|
+
* and fields — no hidden/sensitive fields, no @gqlorm hide models, no
|
|
77
|
+
* dependency on the generated Prisma client path or @prisma/client.
|
|
78
|
+
*/
|
|
79
|
+
export declare function generateGqlormBackendContent(models: BackendModelInfo[]): string;
|
|
10
80
|
/**
|
|
11
81
|
* Generate gqlorm artifacts from the Prisma schema.
|
|
12
82
|
*
|
|
13
83
|
* Reads the project's Prisma schema via DMMF, applies visibility rules
|
|
14
|
-
* (@gqlorm directives + sensitivity heuristics), and writes
|
|
15
|
-
*
|
|
84
|
+
* (@gqlorm directives + sensitivity heuristics), and writes:
|
|
85
|
+
*
|
|
86
|
+
* 1. `.cedar/gqlorm-schema.json` — the frontend ModelSchema (field names only)
|
|
87
|
+
* 2. `.cedar/gqlorm/backend.ts` — auto-generated GraphQL types and resolvers
|
|
88
|
+
* for models that don't already have manually-written SDL files
|
|
89
|
+
*
|
|
90
|
+
* Cedar targets Node.js 24, which strips TypeScript types natively without any
|
|
91
|
+
* flags, so backend.ts can be imported directly at runtime
|
|
16
92
|
*
|
|
17
93
|
* Returns the same `{ files, errors }` shape used by other generators so it
|
|
18
94
|
* can be integrated into `generate.ts` without special handling.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gqlormSchema.d.ts","sourceRoot":"","sources":["../../src/generate/gqlormSchema.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,IAAI,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"gqlormSchema.d.ts","sourceRoot":"","sources":["../../src/generate/gqlormSchema.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,IAAI,MAAM,cAAc,CAAA;AA8BzC,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;AAE3C,UAAU,iBAAiB;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;CACf;AAED,UAAU,iBAAiB;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,iBAAiB,EAAE,CAAA;CAC5B;AAMD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,OAAO,CAAA;IACnB,IAAI,EAAE,OAAO,CAAA;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,gBAAgB,EAAE,CAAA;IAC1B,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAAA;CACtC;AAqDD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAMvE;AAoGD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,IAAI,CAAC,QAAQ,GAClB,iBAAiB,EAAE,CAiDrB;AAED,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,iBAAiB,EAAE,GAC1B,MAAM,CA2CR;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,GAAG,WAAW,CAkDjE;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,GAAG,gBAAgB,EAAE,CA2D7E;AAkBD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CA6BvE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,gBAAgB,EAAE,GACzB,MAAM,CA0IR;AAMD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC;IACvD,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;CAC9C,CAAC,CAgFD"}
|
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { getPaths, getPrismaSchemas } from "@cedarjs/project-config";
|
|
4
|
-
|
|
5
|
-
const
|
|
3
|
+
import { getConfig, getPaths, getPrismaSchemas } from "@cedarjs/project-config";
|
|
4
|
+
import { pluralize } from "@cedarjs/utils/cedarPluralize";
|
|
5
|
+
const INTERNAL_MODEL_NAMES = /* @__PURE__ */ new Set([
|
|
6
|
+
"RW_DataMigration",
|
|
7
|
+
"Cedar_DataMigration"
|
|
8
|
+
]);
|
|
9
|
+
const SENSITIVE_PATTERNS = [
|
|
10
|
+
"password",
|
|
11
|
+
"secret",
|
|
12
|
+
"token",
|
|
13
|
+
"hash",
|
|
14
|
+
"salt",
|
|
15
|
+
"apikey",
|
|
16
|
+
"secretkey",
|
|
17
|
+
"encryptionkey",
|
|
18
|
+
"privatekey"
|
|
19
|
+
];
|
|
6
20
|
function hasDirective(doc, directive) {
|
|
7
21
|
if (!doc) {
|
|
8
22
|
return false;
|
|
@@ -22,6 +36,172 @@ function emitSensitivityWarning(modelName, fieldName) {
|
|
|
22
36
|
`
|
|
23
37
|
);
|
|
24
38
|
}
|
|
39
|
+
const DMMF_TYPE_TO_GRAPHQL = {
|
|
40
|
+
String: "String",
|
|
41
|
+
Int: "Int",
|
|
42
|
+
Float: "Float",
|
|
43
|
+
BigInt: "BigInt",
|
|
44
|
+
Boolean: "Boolean",
|
|
45
|
+
DateTime: "DateTime",
|
|
46
|
+
Json: "JSON",
|
|
47
|
+
Decimal: "String",
|
|
48
|
+
Bytes: "String"
|
|
49
|
+
};
|
|
50
|
+
function mapDmmfTypeToGraphql(type, kind) {
|
|
51
|
+
if (kind === "enum") {
|
|
52
|
+
return "String";
|
|
53
|
+
}
|
|
54
|
+
return DMMF_TYPE_TO_GRAPHQL[type] ?? "String";
|
|
55
|
+
}
|
|
56
|
+
function graphqlTypeToTsType(graphqlType) {
|
|
57
|
+
switch (graphqlType) {
|
|
58
|
+
case "Int":
|
|
59
|
+
case "Float":
|
|
60
|
+
case "BigInt":
|
|
61
|
+
return "number";
|
|
62
|
+
case "Boolean":
|
|
63
|
+
return "boolean";
|
|
64
|
+
default:
|
|
65
|
+
return "string";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function graphqlTypeToTsInterfaceType(graphqlType, isRequired) {
|
|
69
|
+
let tsType;
|
|
70
|
+
switch (graphqlType) {
|
|
71
|
+
case "Int":
|
|
72
|
+
case "Float":
|
|
73
|
+
case "BigInt":
|
|
74
|
+
tsType = "number";
|
|
75
|
+
break;
|
|
76
|
+
case "Boolean":
|
|
77
|
+
tsType = "boolean";
|
|
78
|
+
break;
|
|
79
|
+
case "DateTime":
|
|
80
|
+
tsType = "Date";
|
|
81
|
+
break;
|
|
82
|
+
default:
|
|
83
|
+
tsType = "string";
|
|
84
|
+
}
|
|
85
|
+
return isRequired ? tsType : `${tsType} | null`;
|
|
86
|
+
}
|
|
87
|
+
function dmmfTypeToFrontendTsType(type, kind, isRequired) {
|
|
88
|
+
let tsType;
|
|
89
|
+
if (kind === "enum") {
|
|
90
|
+
tsType = "string";
|
|
91
|
+
} else {
|
|
92
|
+
switch (type) {
|
|
93
|
+
case "String":
|
|
94
|
+
tsType = "string";
|
|
95
|
+
break;
|
|
96
|
+
case "Int":
|
|
97
|
+
case "Float":
|
|
98
|
+
tsType = "number";
|
|
99
|
+
break;
|
|
100
|
+
case "BigInt":
|
|
101
|
+
tsType = "bigint";
|
|
102
|
+
break;
|
|
103
|
+
case "Boolean":
|
|
104
|
+
tsType = "boolean";
|
|
105
|
+
break;
|
|
106
|
+
case "DateTime":
|
|
107
|
+
tsType = "string";
|
|
108
|
+
break;
|
|
109
|
+
case "Json":
|
|
110
|
+
tsType = "unknown";
|
|
111
|
+
break;
|
|
112
|
+
case "Bytes":
|
|
113
|
+
case "Decimal":
|
|
114
|
+
tsType = "string";
|
|
115
|
+
break;
|
|
116
|
+
default:
|
|
117
|
+
tsType = "unknown";
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (isRequired) {
|
|
121
|
+
return tsType;
|
|
122
|
+
}
|
|
123
|
+
return `${tsType} | null`;
|
|
124
|
+
}
|
|
125
|
+
function buildFrontendModelInfo(dmmf) {
|
|
126
|
+
const models = [];
|
|
127
|
+
for (const model of dmmf.datamodel.models) {
|
|
128
|
+
if (INTERNAL_MODEL_NAMES.has(model.name)) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (hasDirective(model.documentation, "hide")) {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
const fields = [];
|
|
135
|
+
for (const field of model.fields) {
|
|
136
|
+
if (field.kind !== "scalar" && field.kind !== "enum") {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (hasDirective(field.documentation, "hide")) {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
const isShown = hasDirective(field.documentation, "show");
|
|
143
|
+
if (!isShown && isSensitiveField(field.name)) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
fields.push({
|
|
147
|
+
name: field.name,
|
|
148
|
+
tsType: dmmfTypeToFrontendTsType(
|
|
149
|
+
field.type,
|
|
150
|
+
field.kind,
|
|
151
|
+
field.isRequired
|
|
152
|
+
)
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
if (fields.length > 0) {
|
|
156
|
+
models.push({
|
|
157
|
+
modelName: model.name,
|
|
158
|
+
camelName: model.name.charAt(0).toLowerCase() + model.name.slice(1),
|
|
159
|
+
fields
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return models;
|
|
164
|
+
}
|
|
165
|
+
function generateWebGqlormModelsContent(models) {
|
|
166
|
+
if (models.length === 0) {
|
|
167
|
+
return [
|
|
168
|
+
"// Auto-generated by Cedar \u2014 do not edit",
|
|
169
|
+
"// Regenerated on every codegen run. Source: api/db/schema.prisma",
|
|
170
|
+
"",
|
|
171
|
+
"declare module '@cedarjs/gqlorm/types/orm' {",
|
|
172
|
+
" interface GqlormTypeMap {}",
|
|
173
|
+
"}",
|
|
174
|
+
""
|
|
175
|
+
].join("\n");
|
|
176
|
+
}
|
|
177
|
+
const lines = [
|
|
178
|
+
"// Auto-generated by Cedar \u2014 do not edit",
|
|
179
|
+
"// Regenerated on every codegen run. Source: api/db/schema.prisma",
|
|
180
|
+
"",
|
|
181
|
+
"declare namespace GqlormScalar {"
|
|
182
|
+
];
|
|
183
|
+
for (const model of models) {
|
|
184
|
+
lines.push(` interface ${model.modelName} {`);
|
|
185
|
+
for (const field of model.fields) {
|
|
186
|
+
lines.push(` ${field.name}: ${field.tsType}`);
|
|
187
|
+
}
|
|
188
|
+
lines.push(" }");
|
|
189
|
+
lines.push("");
|
|
190
|
+
}
|
|
191
|
+
lines.push("}");
|
|
192
|
+
lines.push("");
|
|
193
|
+
lines.push("declare module '@cedarjs/gqlorm/types/orm' {");
|
|
194
|
+
lines.push(" interface GqlormTypeMap {");
|
|
195
|
+
lines.push(" models: {");
|
|
196
|
+
for (const model of models) {
|
|
197
|
+
lines.push(` ${model.camelName}: GqlormScalar.${model.modelName}`);
|
|
198
|
+
}
|
|
199
|
+
lines.push(" }");
|
|
200
|
+
lines.push(" }");
|
|
201
|
+
lines.push("}");
|
|
202
|
+
lines.push("");
|
|
203
|
+
return lines.join("\n");
|
|
204
|
+
}
|
|
25
205
|
function buildModelSchema(dmmf) {
|
|
26
206
|
const schema = {};
|
|
27
207
|
for (const model of dmmf.datamodel.models) {
|
|
@@ -56,6 +236,185 @@ function buildModelSchema(dmmf) {
|
|
|
56
236
|
}
|
|
57
237
|
return schema;
|
|
58
238
|
}
|
|
239
|
+
function buildBackendModelInfo(dmmf) {
|
|
240
|
+
const models = [];
|
|
241
|
+
for (const model of dmmf.datamodel.models) {
|
|
242
|
+
if (INTERNAL_MODEL_NAMES.has(model.name)) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
if (hasDirective(model.documentation, "hide")) {
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
const fields = [];
|
|
249
|
+
for (const field of model.fields) {
|
|
250
|
+
if (field.kind !== "scalar" && field.kind !== "enum") {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
if (hasDirective(field.documentation, "hide")) {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
const isShown = hasDirective(field.documentation, "show");
|
|
257
|
+
if (!isShown && isSensitiveField(field.name)) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
fields.push({
|
|
261
|
+
name: field.name,
|
|
262
|
+
graphqlType: mapDmmfTypeToGraphql(field.type, field.kind),
|
|
263
|
+
isRequired: field.isRequired,
|
|
264
|
+
isId: field.isId
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
if (fields.length > 0) {
|
|
268
|
+
const camelName = model.name.charAt(0).toLowerCase() + model.name.slice(1);
|
|
269
|
+
const pluralName = pluralize(camelName);
|
|
270
|
+
models.push({
|
|
271
|
+
modelName: model.name,
|
|
272
|
+
camelName,
|
|
273
|
+
pluralName,
|
|
274
|
+
fields,
|
|
275
|
+
idField: fields.find((f) => f.isId)
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return models;
|
|
280
|
+
}
|
|
281
|
+
const TYPE_DEF_REGEX = /\btype\s+([A-Z]\w*)\s*\{/g;
|
|
282
|
+
const STRUCTURAL_TYPE_NAMES = /* @__PURE__ */ new Set(["Query", "Mutation", "Subscription"]);
|
|
283
|
+
function getExistingSdlTypeNames(graphqlDir) {
|
|
284
|
+
const typeNames = /* @__PURE__ */ new Set();
|
|
285
|
+
if (!fs.existsSync(graphqlDir)) {
|
|
286
|
+
return typeNames;
|
|
287
|
+
}
|
|
288
|
+
const sdlFiles = fs.readdirSync(graphqlDir).filter((file) => {
|
|
289
|
+
return /\.sdl\.(ts|js)$/.test(file) && !file.startsWith("__gqlorm__");
|
|
290
|
+
});
|
|
291
|
+
for (const file of sdlFiles) {
|
|
292
|
+
const content = fs.readFileSync(path.join(graphqlDir, file), "utf-8");
|
|
293
|
+
let match;
|
|
294
|
+
TYPE_DEF_REGEX.lastIndex = 0;
|
|
295
|
+
while ((match = TYPE_DEF_REGEX.exec(content)) !== null) {
|
|
296
|
+
const name = match[1];
|
|
297
|
+
if (!STRUCTURAL_TYPE_NAMES.has(name)) {
|
|
298
|
+
typeNames.add(name);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return typeNames;
|
|
303
|
+
}
|
|
304
|
+
function generateGqlormBackendContent(models) {
|
|
305
|
+
if (models.length === 0) {
|
|
306
|
+
return "";
|
|
307
|
+
}
|
|
308
|
+
const lines = [
|
|
309
|
+
"// This file is auto-generated by Cedar gqlorm codegen.",
|
|
310
|
+
"// Do not edit \u2014 it will be overwritten on every codegen run.",
|
|
311
|
+
"// To hide a model from gqlorm, add /// @gqlorm hide in schema.prisma.",
|
|
312
|
+
"",
|
|
313
|
+
"import gql from 'graphql-tag'",
|
|
314
|
+
"",
|
|
315
|
+
"// Generated minimal interface \u2014 only visible models and fields, only the",
|
|
316
|
+
"// operations used by this file. No @gqlorm hide models, no sensitive fields.",
|
|
317
|
+
"// Scoped to avoid any dependency on the generated Prisma client path or",
|
|
318
|
+
"// @prisma/client (which is an empty shim in Prisma v7).",
|
|
319
|
+
"interface GqlormDb {"
|
|
320
|
+
];
|
|
321
|
+
for (const model of models) {
|
|
322
|
+
const selectType = model.fields.map((f) => `${f.name}: true`).join("; ");
|
|
323
|
+
lines.push(` ${model.camelName}: {`);
|
|
324
|
+
lines.push(" findMany(args: {");
|
|
325
|
+
lines.push(` select: { ${selectType} }`);
|
|
326
|
+
lines.push(" }): Promise<");
|
|
327
|
+
lines.push(" Array<{");
|
|
328
|
+
for (const field of model.fields) {
|
|
329
|
+
const tsType = graphqlTypeToTsInterfaceType(
|
|
330
|
+
field.graphqlType,
|
|
331
|
+
field.isRequired
|
|
332
|
+
);
|
|
333
|
+
lines.push(` ${field.name}: ${tsType}`);
|
|
334
|
+
}
|
|
335
|
+
lines.push(" }>");
|
|
336
|
+
lines.push(" >");
|
|
337
|
+
if (model.idField) {
|
|
338
|
+
const idTsType = graphqlTypeToTsType(model.idField.graphqlType);
|
|
339
|
+
lines.push(" findUnique(args: {");
|
|
340
|
+
lines.push(` where: { ${model.idField.name}: ${idTsType} }`);
|
|
341
|
+
lines.push(` select: { ${selectType} }`);
|
|
342
|
+
lines.push(" }): Promise<{");
|
|
343
|
+
for (const field of model.fields) {
|
|
344
|
+
const tsType = graphqlTypeToTsInterfaceType(
|
|
345
|
+
field.graphqlType,
|
|
346
|
+
field.isRequired
|
|
347
|
+
);
|
|
348
|
+
lines.push(` ${field.name}: ${tsType}`);
|
|
349
|
+
}
|
|
350
|
+
lines.push(" } | null>");
|
|
351
|
+
}
|
|
352
|
+
lines.push(" }");
|
|
353
|
+
}
|
|
354
|
+
lines.push("}");
|
|
355
|
+
lines.push("");
|
|
356
|
+
lines.push("export const schema = gql`");
|
|
357
|
+
for (const model of models) {
|
|
358
|
+
lines.push(` type ${model.modelName} {`);
|
|
359
|
+
for (const field of model.fields) {
|
|
360
|
+
const nullMark = field.isRequired ? "!" : "";
|
|
361
|
+
lines.push(` ${field.name}: ${field.graphqlType}${nullMark}`);
|
|
362
|
+
}
|
|
363
|
+
lines.push(" }");
|
|
364
|
+
lines.push("");
|
|
365
|
+
}
|
|
366
|
+
lines.push(" type Query {");
|
|
367
|
+
for (const model of models) {
|
|
368
|
+
lines.push(` ${model.pluralName}: [${model.modelName}!]! @skipAuth`);
|
|
369
|
+
if (model.idField) {
|
|
370
|
+
const idNullMark = model.idField.isRequired ? "!" : "";
|
|
371
|
+
lines.push(
|
|
372
|
+
` ${model.camelName}(${model.idField.name}: ${model.idField.graphqlType}${idNullMark}): ${model.modelName} @skipAuth`
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
lines.push(" }");
|
|
377
|
+
lines.push("`");
|
|
378
|
+
lines.push("");
|
|
379
|
+
lines.push(
|
|
380
|
+
"// db is passed in from graphql.ts by the Babel inject plugin, which imports it"
|
|
381
|
+
);
|
|
382
|
+
lines.push(
|
|
383
|
+
"// from 'src/lib/db' in a context where that alias resolves correctly."
|
|
384
|
+
);
|
|
385
|
+
lines.push("export function createGqlormResolvers(db: GqlormDb) {");
|
|
386
|
+
lines.push(" return {");
|
|
387
|
+
lines.push(" Query: {");
|
|
388
|
+
for (let i = 0; i < models.length; i++) {
|
|
389
|
+
const model = models[i];
|
|
390
|
+
const selectObj = model.fields.map((f) => `${f.name}: true`).join(", ");
|
|
391
|
+
lines.push(` ${model.pluralName}: () => {`);
|
|
392
|
+
lines.push(` return db.${model.camelName}.findMany({`);
|
|
393
|
+
lines.push(` select: { ${selectObj} },`);
|
|
394
|
+
lines.push(" })");
|
|
395
|
+
lines.push(" },");
|
|
396
|
+
if (model.idField) {
|
|
397
|
+
const idFieldName = model.idField.name;
|
|
398
|
+
const tsType = graphqlTypeToTsType(model.idField.graphqlType);
|
|
399
|
+
lines.push(
|
|
400
|
+
` ${model.camelName}: (_root: unknown, { ${idFieldName} }: { ${idFieldName}: ${tsType} }) => {`
|
|
401
|
+
);
|
|
402
|
+
lines.push(` return db.${model.camelName}.findUnique({`);
|
|
403
|
+
lines.push(` where: { ${idFieldName} },`);
|
|
404
|
+
lines.push(` select: { ${selectObj} },`);
|
|
405
|
+
lines.push(" })");
|
|
406
|
+
lines.push(" },");
|
|
407
|
+
}
|
|
408
|
+
if (i < models.length - 1) {
|
|
409
|
+
lines.push("");
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
lines.push(" },");
|
|
413
|
+
lines.push(" }");
|
|
414
|
+
lines.push("}");
|
|
415
|
+
lines.push("");
|
|
416
|
+
return lines.join("\n");
|
|
417
|
+
}
|
|
59
418
|
async function generateGqlormArtifacts() {
|
|
60
419
|
const files = [];
|
|
61
420
|
const errors = [];
|
|
@@ -64,14 +423,50 @@ async function generateGqlormArtifacts() {
|
|
|
64
423
|
const mod = await import("@prisma/internals");
|
|
65
424
|
const { getDMMF } = mod.default || mod;
|
|
66
425
|
const dmmf = await getDMMF({ datamodel: schemas });
|
|
426
|
+
const paths = getPaths();
|
|
427
|
+
const generatedBase = paths.generated.base;
|
|
67
428
|
const modelSchema = buildModelSchema(dmmf);
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
429
|
+
const frontendModels = buildFrontendModelInfo(dmmf);
|
|
430
|
+
const schemaOutputPath = path.join(generatedBase, "gqlorm-schema.json");
|
|
431
|
+
const webTypesOutputPath = path.join(
|
|
432
|
+
generatedBase,
|
|
433
|
+
"types",
|
|
434
|
+
"includes",
|
|
435
|
+
"web-gqlorm-models.d.ts"
|
|
436
|
+
);
|
|
437
|
+
fs.mkdirSync(path.dirname(schemaOutputPath), { recursive: true });
|
|
438
|
+
fs.writeFileSync(schemaOutputPath, JSON.stringify(modelSchema, null, 2));
|
|
439
|
+
files.push(schemaOutputPath);
|
|
440
|
+
fs.mkdirSync(path.dirname(webTypesOutputPath), { recursive: true });
|
|
441
|
+
fs.writeFileSync(
|
|
442
|
+
webTypesOutputPath,
|
|
443
|
+
generateWebGqlormModelsContent(frontendModels)
|
|
71
444
|
);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
445
|
+
files.push(webTypesOutputPath);
|
|
446
|
+
const backendOutputDir = path.join(generatedBase, "gqlorm");
|
|
447
|
+
const backendOutputPath = path.join(backendOutputDir, "backend.ts");
|
|
448
|
+
if (getConfig().experimental?.gqlorm?.enabled) {
|
|
449
|
+
const graphqlDir = paths.api.graphql;
|
|
450
|
+
const existingTypes = getExistingSdlTypeNames(graphqlDir);
|
|
451
|
+
const allModels = buildBackendModelInfo(dmmf);
|
|
452
|
+
const gqlormModels = allModels.filter(
|
|
453
|
+
(m) => !existingTypes.has(m.modelName)
|
|
454
|
+
);
|
|
455
|
+
if (gqlormModels.length > 0) {
|
|
456
|
+
const backendContent = generateGqlormBackendContent(gqlormModels);
|
|
457
|
+
fs.mkdirSync(backendOutputDir, { recursive: true });
|
|
458
|
+
fs.writeFileSync(backendOutputPath, backendContent);
|
|
459
|
+
files.push(backendOutputPath);
|
|
460
|
+
} else {
|
|
461
|
+
if (fs.existsSync(backendOutputPath)) {
|
|
462
|
+
fs.unlinkSync(backendOutputPath);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
} else {
|
|
466
|
+
if (fs.existsSync(backendOutputPath)) {
|
|
467
|
+
fs.unlinkSync(backendOutputPath);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
75
470
|
} catch (error) {
|
|
76
471
|
errors.push({
|
|
77
472
|
message: "Failed to generate gqlorm schema artifacts",
|
|
@@ -81,6 +476,12 @@ async function generateGqlormArtifacts() {
|
|
|
81
476
|
return { files, errors };
|
|
82
477
|
}
|
|
83
478
|
export {
|
|
479
|
+
buildBackendModelInfo,
|
|
480
|
+
buildFrontendModelInfo,
|
|
84
481
|
buildModelSchema,
|
|
85
|
-
generateGqlormArtifacts
|
|
482
|
+
generateGqlormArtifacts,
|
|
483
|
+
generateGqlormBackendContent,
|
|
484
|
+
generateWebGqlormModelsContent,
|
|
485
|
+
getExistingSdlTypeNames,
|
|
486
|
+
mapDmmfTypeToGraphql
|
|
86
487
|
};
|
package/dist/generate/watch.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import fs from "node:fs";
|
|
3
|
-
import path from "path";
|
|
3
|
+
import path from "node:path";
|
|
4
4
|
import ansis from "ansis";
|
|
5
5
|
import chokidar from "chokidar";
|
|
6
6
|
import { getPaths } from "@cedarjs/project-config";
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { warningForDuplicateRoutes } from "../routes.js";
|
|
15
15
|
import { generateClientPreset } from "./clientPreset.js";
|
|
16
16
|
import { generate } from "./generate.js";
|
|
17
|
+
import { generateGqlormArtifacts } from "./gqlormSchema.js";
|
|
17
18
|
import {
|
|
18
19
|
generateTypeDefGraphQLApi,
|
|
19
20
|
generateTypeDefGraphQLWeb
|
|
@@ -29,13 +30,16 @@ import {
|
|
|
29
30
|
} from "./typeDefinitions.js";
|
|
30
31
|
const rwjsPaths = getPaths();
|
|
31
32
|
const generatedDirName = path.basename(rwjsPaths.generated.base);
|
|
32
|
-
const watcher = chokidar.watch(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
const watcher = chokidar.watch(
|
|
34
|
+
["(web|api)/src/**/*.{ts,js,jsx,tsx}", "api/db/**/*.prisma"],
|
|
35
|
+
{
|
|
36
|
+
persistent: true,
|
|
37
|
+
ignored: ["node_modules", generatedDirName],
|
|
38
|
+
ignoreInitial: true,
|
|
39
|
+
cwd: rwjsPaths.base,
|
|
40
|
+
awaitWriteFinish: true
|
|
41
|
+
}
|
|
42
|
+
);
|
|
39
43
|
const action = {
|
|
40
44
|
add: "Created",
|
|
41
45
|
unlink: "Deleted",
|
|
@@ -110,6 +114,9 @@ Created ${files.length} in ${Date.now() - start} ms`);
|
|
|
110
114
|
await generateGraphQLSchema();
|
|
111
115
|
await generateTypeDefGraphQLApi();
|
|
112
116
|
finished("GraphQL Schema");
|
|
117
|
+
} else if (absPath.startsWith(path.join(rwjsPaths.base, "api/db/")) && absPath.endsWith(".prisma")) {
|
|
118
|
+
await generateGqlormArtifacts();
|
|
119
|
+
finished("Prisma Schema");
|
|
113
120
|
}
|
|
114
121
|
if (routesWarningMessage) {
|
|
115
122
|
console.warn(routesWarningMessage);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cedarjs/internal",
|
|
3
|
-
"version": "4.0.0-canary.
|
|
3
|
+
"version": "4.0.0-canary.13811+d81274ecc8",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/cedarjs/cedar.git",
|
|
@@ -159,12 +159,13 @@
|
|
|
159
159
|
"@babel/plugin-transform-react-jsx": "7.28.6",
|
|
160
160
|
"@babel/plugin-transform-typescript": "^7.26.8",
|
|
161
161
|
"@babel/traverse": "7.29.0",
|
|
162
|
-
"@cedarjs/babel-config": "4.0.0-canary.
|
|
163
|
-
"@cedarjs/cli-helpers": "4.0.0-canary.
|
|
164
|
-
"@cedarjs/graphql-server": "4.0.0-canary.
|
|
165
|
-
"@cedarjs/project-config": "4.0.0-canary.
|
|
166
|
-
"@cedarjs/router": "4.0.0-canary.
|
|
167
|
-
"@cedarjs/structure": "4.0.0-canary.
|
|
162
|
+
"@cedarjs/babel-config": "4.0.0-canary.13811",
|
|
163
|
+
"@cedarjs/cli-helpers": "4.0.0-canary.13811",
|
|
164
|
+
"@cedarjs/graphql-server": "4.0.0-canary.13811",
|
|
165
|
+
"@cedarjs/project-config": "4.0.0-canary.13811",
|
|
166
|
+
"@cedarjs/router": "4.0.0-canary.13811",
|
|
167
|
+
"@cedarjs/structure": "4.0.0-canary.13811",
|
|
168
|
+
"@cedarjs/utils": "4.0.0-canary.13811",
|
|
168
169
|
"@graphql-codegen/add": "6.0.0",
|
|
169
170
|
"@graphql-codegen/cli": "6.2.1",
|
|
170
171
|
"@graphql-codegen/client-preset": "5.2.4",
|
|
@@ -197,7 +198,7 @@
|
|
|
197
198
|
},
|
|
198
199
|
"devDependencies": {
|
|
199
200
|
"@arethetypeswrong/cli": "0.18.2",
|
|
200
|
-
"@cedarjs/framework-tools": "4.0.0-canary.
|
|
201
|
+
"@cedarjs/framework-tools": "4.0.0-canary.13811",
|
|
201
202
|
"concurrently": "9.2.1",
|
|
202
203
|
"graphql-tag": "2.12.6",
|
|
203
204
|
"publint": "0.3.18",
|
|
@@ -210,5 +211,5 @@
|
|
|
210
211
|
"publishConfig": {
|
|
211
212
|
"access": "public"
|
|
212
213
|
},
|
|
213
|
-
"gitHead": "
|
|
214
|
+
"gitHead": "d81274ecc8944eaa7a99249911420771a860bae5"
|
|
214
215
|
}
|