@soda-gql/typegen 0.10.1 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +164 -152
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -71
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +90 -71
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +164 -152
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.d.mts
CHANGED
|
@@ -4,6 +4,71 @@ import { DocumentNode } from "graphql";
|
|
|
4
4
|
import { Result } from "neverthrow";
|
|
5
5
|
import { ResolvedSodaGqlConfig } from "@soda-gql/config";
|
|
6
6
|
|
|
7
|
+
//#region packages/typegen/src/errors.d.ts
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Error codes specific to typegen operations.
|
|
11
|
+
*/
|
|
12
|
+
type TypegenErrorCode = "TYPEGEN_CODEGEN_REQUIRED" | "TYPEGEN_SCHEMA_LOAD_FAILED" | "TYPEGEN_BUILD_FAILED" | "TYPEGEN_EMIT_FAILED" | "TYPEGEN_BUNDLE_FAILED" | "TYPEGEN_FRAGMENT_MISSING_KEY";
|
|
13
|
+
/**
|
|
14
|
+
* Typegen-specific error type.
|
|
15
|
+
*/
|
|
16
|
+
type TypegenSpecificError = {
|
|
17
|
+
readonly code: "TYPEGEN_CODEGEN_REQUIRED";
|
|
18
|
+
readonly message: string;
|
|
19
|
+
readonly outdir: string;
|
|
20
|
+
} | {
|
|
21
|
+
readonly code: "TYPEGEN_SCHEMA_LOAD_FAILED";
|
|
22
|
+
readonly message: string;
|
|
23
|
+
readonly schemaNames: readonly string[];
|
|
24
|
+
readonly cause?: unknown;
|
|
25
|
+
} | {
|
|
26
|
+
readonly code: "TYPEGEN_BUILD_FAILED";
|
|
27
|
+
readonly message: string;
|
|
28
|
+
readonly cause?: unknown;
|
|
29
|
+
} | {
|
|
30
|
+
readonly code: "TYPEGEN_EMIT_FAILED";
|
|
31
|
+
readonly message: string;
|
|
32
|
+
readonly path: string;
|
|
33
|
+
readonly cause?: unknown;
|
|
34
|
+
} | {
|
|
35
|
+
readonly code: "TYPEGEN_BUNDLE_FAILED";
|
|
36
|
+
readonly message: string;
|
|
37
|
+
readonly path: string;
|
|
38
|
+
readonly cause?: unknown;
|
|
39
|
+
} | {
|
|
40
|
+
readonly code: "TYPEGEN_FRAGMENT_MISSING_KEY";
|
|
41
|
+
readonly message: string;
|
|
42
|
+
readonly fragments: readonly {
|
|
43
|
+
readonly canonicalId: string;
|
|
44
|
+
readonly typename: string;
|
|
45
|
+
readonly schemaLabel: string;
|
|
46
|
+
}[];
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Union of all typegen errors (specific + builder errors).
|
|
50
|
+
*/
|
|
51
|
+
type TypegenError = TypegenSpecificError | BuilderError;
|
|
52
|
+
/**
|
|
53
|
+
* Error constructor helpers for concise error creation.
|
|
54
|
+
*/
|
|
55
|
+
declare const typegenErrors: {
|
|
56
|
+
readonly codegenRequired: (outdir: string) => TypegenSpecificError;
|
|
57
|
+
readonly schemaLoadFailed: (schemaNames: readonly string[], cause?: unknown) => TypegenSpecificError;
|
|
58
|
+
readonly buildFailed: (message: string, cause?: unknown) => TypegenSpecificError;
|
|
59
|
+
readonly emitFailed: (path: string, message: string, cause?: unknown) => TypegenSpecificError;
|
|
60
|
+
readonly bundleFailed: (path: string, message: string, cause?: unknown) => TypegenSpecificError;
|
|
61
|
+
readonly fragmentMissingKey: (fragments: readonly {
|
|
62
|
+
canonicalId: string;
|
|
63
|
+
typename: string;
|
|
64
|
+
schemaLabel: string;
|
|
65
|
+
}[]) => TypegenSpecificError;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Format TypegenError for console output (human-readable).
|
|
69
|
+
*/
|
|
70
|
+
declare const formatTypegenError: (error: TypegenError) => string;
|
|
71
|
+
//#endregion
|
|
7
72
|
//#region packages/typegen/src/emitter.d.ts
|
|
8
73
|
|
|
9
74
|
/**
|
|
@@ -25,12 +90,10 @@ type PrebuiltTypesEmitterOptions = {
|
|
|
25
90
|
*/
|
|
26
91
|
readonly outdir: string;
|
|
27
92
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
93
|
+
* Relative import path to _internal-injects.ts from types.prebuilt.ts.
|
|
94
|
+
* Example: "./_internal-injects"
|
|
30
95
|
*/
|
|
31
|
-
readonly
|
|
32
|
-
readonly scalars: string;
|
|
33
|
-
}>;
|
|
96
|
+
readonly injectsModulePath: string;
|
|
34
97
|
};
|
|
35
98
|
/**
|
|
36
99
|
* Result of emitting prebuilt types.
|
|
@@ -68,85 +131,41 @@ type PrebuiltTypesEmitResult = {
|
|
|
68
131
|
* }
|
|
69
132
|
* ```
|
|
70
133
|
*/
|
|
71
|
-
declare const emitPrebuiltTypes: (options: PrebuiltTypesEmitterOptions) => Promise<Result<PrebuiltTypesEmitResult, BuilderError>>;
|
|
72
|
-
//#endregion
|
|
73
|
-
//#region packages/typegen/src/errors.d.ts
|
|
74
|
-
/**
|
|
75
|
-
* Error codes specific to typegen operations.
|
|
76
|
-
*/
|
|
77
|
-
type TypegenErrorCode = "TYPEGEN_CODEGEN_REQUIRED" | "TYPEGEN_SCHEMA_LOAD_FAILED" | "TYPEGEN_BUILD_FAILED" | "TYPEGEN_EMIT_FAILED" | "TYPEGEN_BUNDLE_FAILED";
|
|
78
|
-
/**
|
|
79
|
-
* Typegen-specific error type.
|
|
80
|
-
*/
|
|
81
|
-
type TypegenSpecificError = {
|
|
82
|
-
readonly code: "TYPEGEN_CODEGEN_REQUIRED";
|
|
83
|
-
readonly message: string;
|
|
84
|
-
readonly outdir: string;
|
|
85
|
-
} | {
|
|
86
|
-
readonly code: "TYPEGEN_SCHEMA_LOAD_FAILED";
|
|
87
|
-
readonly message: string;
|
|
88
|
-
readonly schemaNames: readonly string[];
|
|
89
|
-
readonly cause?: unknown;
|
|
90
|
-
} | {
|
|
91
|
-
readonly code: "TYPEGEN_BUILD_FAILED";
|
|
92
|
-
readonly message: string;
|
|
93
|
-
readonly cause?: unknown;
|
|
94
|
-
} | {
|
|
95
|
-
readonly code: "TYPEGEN_EMIT_FAILED";
|
|
96
|
-
readonly message: string;
|
|
97
|
-
readonly path: string;
|
|
98
|
-
readonly cause?: unknown;
|
|
99
|
-
} | {
|
|
100
|
-
readonly code: "TYPEGEN_BUNDLE_FAILED";
|
|
101
|
-
readonly message: string;
|
|
102
|
-
readonly path: string;
|
|
103
|
-
readonly cause?: unknown;
|
|
104
|
-
};
|
|
105
|
-
/**
|
|
106
|
-
* Union of all typegen errors (specific + builder errors).
|
|
107
|
-
*/
|
|
108
|
-
type TypegenError = TypegenSpecificError | BuilderError;
|
|
109
|
-
/**
|
|
110
|
-
* Error constructor helpers for concise error creation.
|
|
111
|
-
*/
|
|
112
|
-
declare const typegenErrors: {
|
|
113
|
-
readonly codegenRequired: (outdir: string) => TypegenSpecificError;
|
|
114
|
-
readonly schemaLoadFailed: (schemaNames: readonly string[], cause?: unknown) => TypegenSpecificError;
|
|
115
|
-
readonly buildFailed: (message: string, cause?: unknown) => TypegenSpecificError;
|
|
116
|
-
readonly emitFailed: (path: string, message: string, cause?: unknown) => TypegenSpecificError;
|
|
117
|
-
readonly bundleFailed: (path: string, message: string, cause?: unknown) => TypegenSpecificError;
|
|
118
|
-
};
|
|
119
|
-
/**
|
|
120
|
-
* Format TypegenError for console output (human-readable).
|
|
121
|
-
*/
|
|
122
|
-
declare const formatTypegenError: (error: TypegenError) => string;
|
|
134
|
+
declare const emitPrebuiltTypes: (options: PrebuiltTypesEmitterOptions) => Promise<Result<PrebuiltTypesEmitResult, BuilderError | TypegenError>>;
|
|
123
135
|
//#endregion
|
|
124
136
|
//#region packages/typegen/src/prebuilt-generator.d.ts
|
|
125
137
|
type PrebuiltGeneratorOptions = {
|
|
126
138
|
/**
|
|
127
|
-
* Relative import path to the
|
|
128
|
-
* Example: "
|
|
139
|
+
* Relative import path to the internal module.
|
|
140
|
+
* Example: "./_internal" (from index.prebuilt.ts to _internal.ts)
|
|
141
|
+
*/
|
|
142
|
+
readonly internalModulePath: string;
|
|
143
|
+
/**
|
|
144
|
+
* Relative import path to the injects module.
|
|
145
|
+
* Example: "./_internal-injects" (from index.prebuilt.ts to _internal-injects.ts)
|
|
129
146
|
*/
|
|
130
|
-
readonly
|
|
147
|
+
readonly injectsModulePath: string;
|
|
131
148
|
/**
|
|
132
|
-
* Per-schema injection config
|
|
149
|
+
* Per-schema injection config.
|
|
150
|
+
* Maps schema name to whether it has an adapter.
|
|
133
151
|
*/
|
|
134
152
|
readonly injection?: Map<string, {
|
|
135
|
-
readonly
|
|
153
|
+
readonly hasAdapter?: boolean;
|
|
136
154
|
}>;
|
|
137
155
|
};
|
|
138
156
|
type PrebuiltGeneratedModule = {
|
|
139
|
-
/** The generated code for
|
|
157
|
+
/** The generated code for index.prebuilt.ts */
|
|
140
158
|
readonly indexCode: string;
|
|
141
|
-
/** The generated code for prebuilt/types.ts (placeholder) */
|
|
142
|
-
readonly typesCode: string;
|
|
143
159
|
};
|
|
144
160
|
/**
|
|
145
|
-
* Generate the prebuilt module code.
|
|
161
|
+
* Generate the prebuilt index module code.
|
|
146
162
|
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
163
|
+
* Generates index.prebuilt.ts with prebuilt gql composers using
|
|
164
|
+
* createPrebuiltGqlElementComposer. The generated module uses
|
|
165
|
+
* lightweight imports for type serialization compatibility:
|
|
166
|
+
* - Adapters from _internal-injects.ts
|
|
167
|
+
* - Runtime values from _internal.ts
|
|
168
|
+
* - AnyGqlContext instead of heavy Context type inference
|
|
150
169
|
*/
|
|
151
170
|
declare const generatePrebuiltModule: (schemas: Map<string, DocumentNode>, options: PrebuiltGeneratorOptions) => PrebuiltGeneratedModule;
|
|
152
171
|
//#endregion
|
|
@@ -221,10 +240,10 @@ type RunTypegenOptions = {
|
|
|
221
240
|
*
|
|
222
241
|
* This function:
|
|
223
242
|
* 1. Loads schemas from the generated CJS bundle
|
|
224
|
-
* 2. Generates
|
|
243
|
+
* 2. Generates index.prebuilt.ts using generatePrebuiltModule
|
|
225
244
|
* 3. Creates a BuilderService and builds the artifact
|
|
226
245
|
* 4. Extracts field selections from the artifact
|
|
227
|
-
* 5. Emits
|
|
246
|
+
* 5. Emits types.prebuilt.ts using emitPrebuiltTypes
|
|
228
247
|
* 6. Bundles the prebuilt module
|
|
229
248
|
*
|
|
230
249
|
* @param options - Typegen options including config
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/errors.ts","../src/emitter.ts","../src/prebuilt-generator.ts","../src/types.ts","../src/runner.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -7,6 +7,78 @@ import { err, ok } from "neverthrow";
|
|
|
7
7
|
import { existsSync, readFileSync } from "node:fs";
|
|
8
8
|
import { build } from "esbuild";
|
|
9
9
|
|
|
10
|
+
//#region packages/typegen/src/errors.ts
|
|
11
|
+
/**
|
|
12
|
+
* Error constructor helpers for concise error creation.
|
|
13
|
+
*/
|
|
14
|
+
const typegenErrors = {
|
|
15
|
+
codegenRequired: (outdir) => ({
|
|
16
|
+
code: "TYPEGEN_CODEGEN_REQUIRED",
|
|
17
|
+
message: `Generated graphql-system module not found at '${outdir}'. Run 'soda-gql codegen' first.`,
|
|
18
|
+
outdir
|
|
19
|
+
}),
|
|
20
|
+
schemaLoadFailed: (schemaNames, cause) => ({
|
|
21
|
+
code: "TYPEGEN_SCHEMA_LOAD_FAILED",
|
|
22
|
+
message: `Failed to load schemas: ${schemaNames.join(", ")}`,
|
|
23
|
+
schemaNames,
|
|
24
|
+
cause
|
|
25
|
+
}),
|
|
26
|
+
buildFailed: (message, cause) => ({
|
|
27
|
+
code: "TYPEGEN_BUILD_FAILED",
|
|
28
|
+
message,
|
|
29
|
+
cause
|
|
30
|
+
}),
|
|
31
|
+
emitFailed: (path, message, cause) => ({
|
|
32
|
+
code: "TYPEGEN_EMIT_FAILED",
|
|
33
|
+
message,
|
|
34
|
+
path,
|
|
35
|
+
cause
|
|
36
|
+
}),
|
|
37
|
+
bundleFailed: (path, message, cause) => ({
|
|
38
|
+
code: "TYPEGEN_BUNDLE_FAILED",
|
|
39
|
+
message,
|
|
40
|
+
path,
|
|
41
|
+
cause
|
|
42
|
+
}),
|
|
43
|
+
fragmentMissingKey: (fragments) => ({
|
|
44
|
+
code: "TYPEGEN_FRAGMENT_MISSING_KEY",
|
|
45
|
+
message: `${fragments.length} fragment(s) missing required 'key' property for prebuilt types`,
|
|
46
|
+
fragments
|
|
47
|
+
})
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Format TypegenError for console output (human-readable).
|
|
51
|
+
*/
|
|
52
|
+
const formatTypegenError = (error) => {
|
|
53
|
+
const lines = [];
|
|
54
|
+
lines.push(`Error [${error.code}]: ${error.message}`);
|
|
55
|
+
switch (error.code) {
|
|
56
|
+
case "TYPEGEN_CODEGEN_REQUIRED":
|
|
57
|
+
lines.push(` Output directory: ${error.outdir}`);
|
|
58
|
+
lines.push(" Hint: Run 'soda-gql codegen' to generate the graphql-system module first.");
|
|
59
|
+
break;
|
|
60
|
+
case "TYPEGEN_SCHEMA_LOAD_FAILED":
|
|
61
|
+
lines.push(` Schemas: ${error.schemaNames.join(", ")}`);
|
|
62
|
+
break;
|
|
63
|
+
case "TYPEGEN_EMIT_FAILED":
|
|
64
|
+
case "TYPEGEN_BUNDLE_FAILED":
|
|
65
|
+
lines.push(` Path: ${error.path}`);
|
|
66
|
+
break;
|
|
67
|
+
case "TYPEGEN_FRAGMENT_MISSING_KEY":
|
|
68
|
+
lines.push(" Fragments missing 'key' property:");
|
|
69
|
+
for (const fragment of error.fragments) {
|
|
70
|
+
lines.push(` - ${fragment.canonicalId} (${fragment.typename} on ${fragment.schemaLabel})`);
|
|
71
|
+
}
|
|
72
|
+
lines.push(" Hint: Add a 'key' property to each fragment for prebuilt type resolution.");
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
if ("cause" in error && error.cause) {
|
|
76
|
+
lines.push(` Caused by: ${error.cause}`);
|
|
77
|
+
}
|
|
78
|
+
return lines.join("\n");
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
//#endregion
|
|
10
82
|
//#region packages/typegen/src/emitter.ts
|
|
11
83
|
/**
|
|
12
84
|
* Prebuilt types emitter.
|
|
@@ -36,11 +108,16 @@ import { build } from "esbuild";
|
|
|
36
108
|
* Group field selections by schema.
|
|
37
109
|
* Uses the schemaLabel from each selection to group them correctly.
|
|
38
110
|
*
|
|
111
|
+
* In strict mode, all fragments must have a 'key' property. Fragments
|
|
112
|
+
* without keys will cause an error.
|
|
113
|
+
*
|
|
39
114
|
* @returns Result containing grouped selections and warnings, or error if schema not found
|
|
115
|
+
* or fragments are missing keys
|
|
40
116
|
*/
|
|
41
117
|
const groupBySchema = (fieldSelections, schemas) => {
|
|
42
118
|
const grouped = new Map();
|
|
43
119
|
const warnings = [];
|
|
120
|
+
const missingKeyFragments = [];
|
|
44
121
|
for (const schemaName of Object.keys(schemas)) {
|
|
45
122
|
grouped.set(schemaName, {
|
|
46
123
|
fragments: [],
|
|
@@ -62,6 +139,11 @@ const groupBySchema = (fieldSelections, schemas) => {
|
|
|
62
139
|
};
|
|
63
140
|
if (selection.type === "fragment") {
|
|
64
141
|
if (!selection.key) {
|
|
142
|
+
missingKeyFragments.push({
|
|
143
|
+
canonicalId,
|
|
144
|
+
typename: selection.typename,
|
|
145
|
+
schemaLabel: selection.schemaLabel
|
|
146
|
+
});
|
|
65
147
|
continue;
|
|
66
148
|
}
|
|
67
149
|
try {
|
|
@@ -98,23 +180,15 @@ const groupBySchema = (fieldSelections, schemas) => {
|
|
|
98
180
|
}
|
|
99
181
|
}
|
|
100
182
|
}
|
|
183
|
+
if (missingKeyFragments.length > 0) {
|
|
184
|
+
return err(typegenErrors.fragmentMissingKey(missingKeyFragments));
|
|
185
|
+
}
|
|
101
186
|
return ok({
|
|
102
187
|
grouped,
|
|
103
188
|
warnings
|
|
104
189
|
});
|
|
105
190
|
};
|
|
106
191
|
/**
|
|
107
|
-
* Calculate relative import path from one file to another.
|
|
108
|
-
*/
|
|
109
|
-
const toImportSpecifier$1 = (from, to) => {
|
|
110
|
-
const fromDir = dirname(from);
|
|
111
|
-
let relativePath = relative(fromDir, to);
|
|
112
|
-
if (!relativePath.startsWith(".")) {
|
|
113
|
-
relativePath = `./${relativePath}`;
|
|
114
|
-
}
|
|
115
|
-
return relativePath.replace(/\.ts$/, "");
|
|
116
|
-
};
|
|
117
|
-
/**
|
|
118
192
|
* Extract input object names from a GraphQL TypeNode.
|
|
119
193
|
*/
|
|
120
194
|
const extractInputObjectsFromType = (schema, typeNode, inputObjects) => {
|
|
@@ -210,8 +284,8 @@ const generateInputObjectTypeDefinitions = (schema, schemaName, inputNames) => {
|
|
|
210
284
|
/**
|
|
211
285
|
* Generate the TypeScript code for prebuilt types.
|
|
212
286
|
*/
|
|
213
|
-
const generateTypesCode = (grouped, schemas,
|
|
214
|
-
const
|
|
287
|
+
const generateTypesCode = (grouped, schemas, injectsModulePath) => {
|
|
288
|
+
const schemaNames = Object.keys(schemas);
|
|
215
289
|
const lines = [
|
|
216
290
|
"/**",
|
|
217
291
|
" * Prebuilt type registry.",
|
|
@@ -225,12 +299,10 @@ const generateTypesCode = (grouped, schemas, injects, outdir) => {
|
|
|
225
299
|
"",
|
|
226
300
|
"import type { PrebuiltTypeRegistry } from \"@soda-gql/core\";"
|
|
227
301
|
];
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
lines.push(`import type { scalar as scalar_${schemaName} } from "${relativePath}";`);
|
|
231
|
-
}
|
|
302
|
+
const scalarImports = schemaNames.map((name) => `scalar_${name}`).join(", ");
|
|
303
|
+
lines.push(`import type { ${scalarImports} } from "${injectsModulePath}";`);
|
|
232
304
|
lines.push("");
|
|
233
|
-
for (const schemaName of
|
|
305
|
+
for (const schemaName of schemaNames) {
|
|
234
306
|
lines.push(`type ScalarInput_${schemaName}<T extends keyof typeof scalar_${schemaName}> = ` + `typeof scalar_${schemaName}[T]["$type"]["input"];`);
|
|
235
307
|
lines.push(`type ScalarOutput_${schemaName}<T extends keyof typeof scalar_${schemaName}> = ` + `typeof scalar_${schemaName}[T]["$type"]["output"];`);
|
|
236
308
|
}
|
|
@@ -291,14 +363,14 @@ const generateTypesCode = (grouped, schemas, injects, outdir) => {
|
|
|
291
363
|
* ```
|
|
292
364
|
*/
|
|
293
365
|
const emitPrebuiltTypes = async (options) => {
|
|
294
|
-
const { schemas, fieldSelections, outdir,
|
|
366
|
+
const { schemas, fieldSelections, outdir, injectsModulePath } = options;
|
|
295
367
|
const groupResult = groupBySchema(fieldSelections, schemas);
|
|
296
368
|
if (groupResult.isErr()) {
|
|
297
369
|
return err(groupResult.error);
|
|
298
370
|
}
|
|
299
371
|
const { grouped, warnings } = groupResult.value;
|
|
300
|
-
const code = generateTypesCode(grouped, schemas,
|
|
301
|
-
const typesPath = join(outdir, "
|
|
372
|
+
const code = generateTypesCode(grouped, schemas, injectsModulePath);
|
|
373
|
+
const typesPath = join(outdir, "types.prebuilt.ts");
|
|
302
374
|
try {
|
|
303
375
|
await writeFile(typesPath, code, "utf-8");
|
|
304
376
|
return ok({
|
|
@@ -310,143 +382,91 @@ const emitPrebuiltTypes = async (options) => {
|
|
|
310
382
|
}
|
|
311
383
|
};
|
|
312
384
|
|
|
313
|
-
//#endregion
|
|
314
|
-
//#region packages/typegen/src/errors.ts
|
|
315
|
-
/**
|
|
316
|
-
* Error constructor helpers for concise error creation.
|
|
317
|
-
*/
|
|
318
|
-
const typegenErrors = {
|
|
319
|
-
codegenRequired: (outdir) => ({
|
|
320
|
-
code: "TYPEGEN_CODEGEN_REQUIRED",
|
|
321
|
-
message: `Generated graphql-system module not found at '${outdir}'. Run 'soda-gql codegen' first.`,
|
|
322
|
-
outdir
|
|
323
|
-
}),
|
|
324
|
-
schemaLoadFailed: (schemaNames, cause) => ({
|
|
325
|
-
code: "TYPEGEN_SCHEMA_LOAD_FAILED",
|
|
326
|
-
message: `Failed to load schemas: ${schemaNames.join(", ")}`,
|
|
327
|
-
schemaNames,
|
|
328
|
-
cause
|
|
329
|
-
}),
|
|
330
|
-
buildFailed: (message, cause) => ({
|
|
331
|
-
code: "TYPEGEN_BUILD_FAILED",
|
|
332
|
-
message,
|
|
333
|
-
cause
|
|
334
|
-
}),
|
|
335
|
-
emitFailed: (path, message, cause) => ({
|
|
336
|
-
code: "TYPEGEN_EMIT_FAILED",
|
|
337
|
-
message,
|
|
338
|
-
path,
|
|
339
|
-
cause
|
|
340
|
-
}),
|
|
341
|
-
bundleFailed: (path, message, cause) => ({
|
|
342
|
-
code: "TYPEGEN_BUNDLE_FAILED",
|
|
343
|
-
message,
|
|
344
|
-
path,
|
|
345
|
-
cause
|
|
346
|
-
})
|
|
347
|
-
};
|
|
348
|
-
/**
|
|
349
|
-
* Format TypegenError for console output (human-readable).
|
|
350
|
-
*/
|
|
351
|
-
const formatTypegenError = (error) => {
|
|
352
|
-
const lines = [];
|
|
353
|
-
lines.push(`Error [${error.code}]: ${error.message}`);
|
|
354
|
-
switch (error.code) {
|
|
355
|
-
case "TYPEGEN_CODEGEN_REQUIRED":
|
|
356
|
-
lines.push(` Output directory: ${error.outdir}`);
|
|
357
|
-
lines.push(" Hint: Run 'soda-gql codegen' to generate the graphql-system module first.");
|
|
358
|
-
break;
|
|
359
|
-
case "TYPEGEN_SCHEMA_LOAD_FAILED":
|
|
360
|
-
lines.push(` Schemas: ${error.schemaNames.join(", ")}`);
|
|
361
|
-
break;
|
|
362
|
-
case "TYPEGEN_EMIT_FAILED":
|
|
363
|
-
case "TYPEGEN_BUNDLE_FAILED":
|
|
364
|
-
lines.push(` Path: ${error.path}`);
|
|
365
|
-
break;
|
|
366
|
-
}
|
|
367
|
-
if ("cause" in error && error.cause) {
|
|
368
|
-
lines.push(` Caused by: ${error.cause}`);
|
|
369
|
-
}
|
|
370
|
-
return lines.join("\n");
|
|
371
|
-
};
|
|
372
|
-
|
|
373
385
|
//#endregion
|
|
374
386
|
//#region packages/typegen/src/prebuilt-generator.ts
|
|
375
387
|
/**
|
|
376
|
-
* Generate the prebuilt module code.
|
|
388
|
+
* Generate the prebuilt index module code.
|
|
377
389
|
*
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
*
|
|
390
|
+
* Generates index.prebuilt.ts with prebuilt gql composers using
|
|
391
|
+
* createPrebuiltGqlElementComposer. The generated module uses
|
|
392
|
+
* lightweight imports for type serialization compatibility:
|
|
393
|
+
* - Adapters from _internal-injects.ts
|
|
394
|
+
* - Runtime values from _internal.ts
|
|
395
|
+
* - AnyGqlContext instead of heavy Context type inference
|
|
381
396
|
*/
|
|
382
397
|
const generatePrebuiltModule = (schemas, options) => {
|
|
383
398
|
const schemaNames = Array.from(schemas.keys());
|
|
384
|
-
const
|
|
385
|
-
const
|
|
386
|
-
for (const name of schemaNames) {
|
|
387
|
-
typeImports.push(`Schema_${name}`, `FragmentBuilders_${name}`, `Context_${name}`);
|
|
388
|
-
runtimeImports.push(`__schema_${name}`, `__inputTypeMethods_${name}`, `__directiveMethods_${name}`);
|
|
389
|
-
const hasAdapter = options.injection?.get(name)?.adapterImportPath !== undefined;
|
|
390
|
-
if (hasAdapter) {
|
|
391
|
-
typeImports.push(`Adapter_${name}`);
|
|
392
|
-
runtimeImports.push(`__adapter_${name}`);
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
const gqlEntries = [];
|
|
399
|
+
const injection = options.injection ?? new Map();
|
|
400
|
+
const adapterImports = [];
|
|
396
401
|
for (const name of schemaNames) {
|
|
397
|
-
const
|
|
398
|
-
if (
|
|
399
|
-
|
|
400
|
-
if (hasAdapter) {
|
|
401
|
-
gqlEntries.push(` ${name}: createPrebuiltGqlElementComposer<Schema_${name}, PrebuiltTypes_${name}, FragmentBuilders_${name}, typeof __directiveMethods_${name}, Context_${name}, Adapter_${name}>(__schema_${name}, { adapter: __adapter_${name}, inputTypeMethods: __inputTypeMethods_${name}, directiveMethods: __directiveMethods_${name} })`);
|
|
402
|
-
} else {
|
|
403
|
-
gqlEntries.push(` ${name}: createPrebuiltGqlElementComposer<Schema_${name}, PrebuiltTypes_${name}, FragmentBuilders_${name}, typeof __directiveMethods_${name}, Context_${name}>(__schema_${name}, { inputTypeMethods: __inputTypeMethods_${name}, directiveMethods: __directiveMethods_${name} })`);
|
|
402
|
+
const config = injection.get(name);
|
|
403
|
+
if (config?.hasAdapter) {
|
|
404
|
+
adapterImports.push(`adapter_${name}`);
|
|
404
405
|
}
|
|
405
406
|
}
|
|
407
|
+
const internalImports = schemaNames.flatMap((name) => [
|
|
408
|
+
`__schema_${name}`,
|
|
409
|
+
`__inputTypeMethods_${name}`,
|
|
410
|
+
`__directiveMethods_${name}`
|
|
411
|
+
]);
|
|
412
|
+
const gqlEntries = schemaNames.map((name) => {
|
|
413
|
+
const config = injection.get(name);
|
|
414
|
+
const adapterArg = config?.hasAdapter ? `adapter: adapter_${name},` : "";
|
|
415
|
+
return ` ${name}: createPrebuiltGqlElementComposer<
|
|
416
|
+
AnyGraphqlSchema,
|
|
417
|
+
PrebuiltTypes_${name},
|
|
418
|
+
Record<string, unknown>,
|
|
419
|
+
StandardDirectives,
|
|
420
|
+
AnyGqlContext
|
|
421
|
+
>(
|
|
422
|
+
__schema_${name} as AnyGraphqlSchema,
|
|
423
|
+
{
|
|
424
|
+
inputTypeMethods: __inputTypeMethods_${name},
|
|
425
|
+
directiveMethods: __directiveMethods_${name},
|
|
426
|
+
${adapterArg}
|
|
427
|
+
}
|
|
428
|
+
)`;
|
|
429
|
+
});
|
|
430
|
+
const injectsImportSpecifiers = adapterImports.length > 0 ? adapterImports.join(", ") : "";
|
|
431
|
+
const injectsImportLine = injectsImportSpecifiers ? `import { ${injectsImportSpecifiers} } from "${options.injectsModulePath}";` : "";
|
|
406
432
|
const indexCode = `\
|
|
407
433
|
/**
|
|
408
434
|
* Prebuilt GQL module for bundler-compatible type resolution.
|
|
409
435
|
*
|
|
410
|
-
* This module
|
|
411
|
-
* from PrebuiltTypes instead of
|
|
436
|
+
* This module creates prebuilt composers using createPrebuiltGqlElementComposer
|
|
437
|
+
* that look up types from PrebuiltTypes instead of complex inference.
|
|
438
|
+
*
|
|
439
|
+
* Uses lightweight imports:
|
|
440
|
+
* - Adapters from _internal-injects.ts
|
|
441
|
+
* - Runtime values from _internal.ts
|
|
442
|
+
* - AnyGqlContext instead of heavy Context type inference
|
|
412
443
|
*
|
|
413
444
|
* @module
|
|
414
445
|
* @generated by @soda-gql/typegen
|
|
415
446
|
*/
|
|
416
447
|
|
|
417
|
-
import { createPrebuiltGqlElementComposer } from "@soda-gql/core";
|
|
418
448
|
import {
|
|
419
|
-
|
|
420
|
-
type
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
${
|
|
426
|
-
};
|
|
449
|
+
createPrebuiltGqlElementComposer,
|
|
450
|
+
type AnyGqlContext,
|
|
451
|
+
type AnyGraphqlSchema,
|
|
452
|
+
type StandardDirectives,
|
|
453
|
+
} from "@soda-gql/core";
|
|
454
|
+
${injectsImportLine}
|
|
455
|
+
import { ${internalImports.join(", ")} } from "${options.internalModulePath}";
|
|
456
|
+
import type { ${schemaNames.map((name) => `PrebuiltTypes_${name}`).join(", ")} } from "./types.prebuilt";
|
|
427
457
|
|
|
428
|
-
// Re-export types from main module
|
|
429
|
-
export type { ${typeImports.join(", ")} };
|
|
430
|
-
`;
|
|
431
|
-
const typesCode = `\
|
|
432
458
|
/**
|
|
433
|
-
* Prebuilt type
|
|
434
|
-
*
|
|
435
|
-
* This file contains placeholder types that will be populated by typegen
|
|
436
|
-
* when running \`soda-gql typegen\` command.
|
|
459
|
+
* Prebuilt GQL composers with strict type resolution from PrebuiltTypeRegistry.
|
|
437
460
|
*
|
|
438
|
-
*
|
|
439
|
-
*
|
|
461
|
+
* These composers have the same runtime behavior as the base composers,
|
|
462
|
+
* but their return types are resolved from the prebuilt type registry
|
|
463
|
+
* instead of using complex type inference.
|
|
440
464
|
*/
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
${schemaNames.map((name) => `// Placeholder for ${name} schema - populated by typegen\nexport type PrebuiltTypes_${name} = EmptyPrebuiltTypeRegistry;`).join("\n\n")}
|
|
465
|
+
export const gql = {
|
|
466
|
+
${gqlEntries.join(",\n")}
|
|
467
|
+
};
|
|
445
468
|
`;
|
|
446
|
-
return {
|
|
447
|
-
indexCode,
|
|
448
|
-
typesCode
|
|
449
|
-
};
|
|
469
|
+
return { indexCode };
|
|
450
470
|
};
|
|
451
471
|
|
|
452
472
|
//#endregion
|
|
@@ -456,10 +476,10 @@ ${schemaNames.map((name) => `// Placeholder for ${name} schema - populated by ty
|
|
|
456
476
|
*
|
|
457
477
|
* Orchestrates the prebuilt type generation process:
|
|
458
478
|
* 1. Load schemas from generated CJS bundle
|
|
459
|
-
* 2. Generate
|
|
479
|
+
* 2. Generate index.prebuilt.ts
|
|
460
480
|
* 3. Build artifact to evaluate elements
|
|
461
481
|
* 4. Extract field selections
|
|
462
|
-
* 5. Emit
|
|
482
|
+
* 5. Emit types.prebuilt.ts
|
|
463
483
|
* 6. Bundle prebuilt module
|
|
464
484
|
*
|
|
465
485
|
* @module
|
|
@@ -549,10 +569,10 @@ const loadSchemaDocuments = (schemasConfig) => {
|
|
|
549
569
|
*
|
|
550
570
|
* This function:
|
|
551
571
|
* 1. Loads schemas from the generated CJS bundle
|
|
552
|
-
* 2. Generates
|
|
572
|
+
* 2. Generates index.prebuilt.ts using generatePrebuiltModule
|
|
553
573
|
* 3. Creates a BuilderService and builds the artifact
|
|
554
574
|
* 4. Extracts field selections from the artifact
|
|
555
|
-
* 5. Emits
|
|
575
|
+
* 5. Emits types.prebuilt.ts using emitPrebuiltTypes
|
|
556
576
|
* 6. Bundles the prebuilt module
|
|
557
577
|
*
|
|
558
578
|
* @param options - Typegen options including config
|
|
@@ -572,23 +592,19 @@ const runTypegen = async (options) => {
|
|
|
572
592
|
return err(typegenErrors.schemaLoadFailed(schemaNames, schemasResult.error));
|
|
573
593
|
}
|
|
574
594
|
const schemas = schemasResult.value;
|
|
575
|
-
const prebuiltDir = join(outdir, "prebuilt");
|
|
576
|
-
await mkdir(prebuiltDir, { recursive: true });
|
|
577
595
|
const schemaDocuments = loadSchemaDocuments(config.schemas);
|
|
578
|
-
const
|
|
596
|
+
const prebuiltIndexPath = join(outdir, "index.prebuilt.ts");
|
|
597
|
+
const internalModulePath = toImportSpecifier(prebuiltIndexPath, join(outdir, "_internal.ts"), importSpecifierOptions);
|
|
598
|
+
const injectsModulePath = toImportSpecifier(prebuiltIndexPath, join(outdir, "_internal-injects.ts"), importSpecifierOptions);
|
|
579
599
|
const injection = new Map();
|
|
580
600
|
for (const [schemaName, schemaConfig] of Object.entries(config.schemas)) {
|
|
581
|
-
|
|
582
|
-
injection.set(schemaName, { adapterImportPath: toImportSpecifier(join(outdir, "index.ts"), schemaConfig.inject.adapter, importSpecifierOptions) });
|
|
583
|
-
} else {
|
|
584
|
-
injection.set(schemaName, {});
|
|
585
|
-
}
|
|
601
|
+
injection.set(schemaName, { hasAdapter: !!schemaConfig.inject.adapter });
|
|
586
602
|
}
|
|
587
603
|
const prebuilt = generatePrebuiltModule(schemaDocuments, {
|
|
588
|
-
|
|
604
|
+
internalModulePath,
|
|
605
|
+
injectsModulePath,
|
|
589
606
|
injection
|
|
590
607
|
});
|
|
591
|
-
const prebuiltIndexPath = join(prebuiltDir, "index.ts");
|
|
592
608
|
try {
|
|
593
609
|
await writeModule(prebuiltIndexPath, prebuilt.indexCode);
|
|
594
610
|
} catch (error) {
|
|
@@ -605,15 +621,11 @@ const runTypegen = async (options) => {
|
|
|
605
621
|
}
|
|
606
622
|
const fieldSelectionsResult = extractFieldSelections(intermediateElements);
|
|
607
623
|
const { selections: fieldSelections, warnings: extractWarnings } = fieldSelectionsResult;
|
|
608
|
-
const injects = {};
|
|
609
|
-
for (const [schemaName, schemaConfig] of Object.entries(config.schemas)) {
|
|
610
|
-
injects[schemaName] = { scalars: schemaConfig.inject.scalars };
|
|
611
|
-
}
|
|
612
624
|
const emitResult = await emitPrebuiltTypes({
|
|
613
625
|
schemas,
|
|
614
626
|
fieldSelections,
|
|
615
627
|
outdir,
|
|
616
|
-
|
|
628
|
+
injectsModulePath
|
|
617
629
|
});
|
|
618
630
|
if (emitResult.isErr()) {
|
|
619
631
|
return err(emitResult.error);
|