@soda-gql/typegen 0.10.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/index.cjs ADDED
@@ -0,0 +1,652 @@
1
+ let node_fs_promises = require("node:fs/promises");
2
+ let node_path = require("node:path");
3
+ let __soda_gql_builder = require("@soda-gql/builder");
4
+ let __soda_gql_core = require("@soda-gql/core");
5
+ let graphql = require("graphql");
6
+ let neverthrow = require("neverthrow");
7
+ let node_fs = require("node:fs");
8
+ let esbuild = require("esbuild");
9
+
10
+ //#region packages/typegen/src/emitter.ts
11
+ /**
12
+ * Prebuilt types emitter.
13
+ *
14
+ * Generates TypeScript type definitions for PrebuiltTypes registry
15
+ * from field selection data and schema.
16
+ *
17
+ * ## Error Handling Strategy
18
+ *
19
+ * The emitter uses a partial failure approach for type calculation errors:
20
+ *
21
+ * **Recoverable errors** (result in warnings, element skipped):
22
+ * - Type calculation failures (e.g., `calculateFieldsType` throws)
23
+ * - Input type generation failures (e.g., `generateInputType` throws)
24
+ * - These are caught per-element, logged as warnings, and the element is omitted
25
+ *
26
+ * **Fatal errors** (result in error result):
27
+ * - `SCHEMA_NOT_FOUND`: Selection references non-existent schema
28
+ * - `WRITE_FAILED`: Cannot write output file to disk
29
+ *
30
+ * This allows builds to succeed with partial type coverage when some elements
31
+ * have issues, while providing visibility into problems via warnings.
32
+ *
33
+ * @module
34
+ */
35
+ /**
36
+ * Group field selections by schema.
37
+ * Uses the schemaLabel from each selection to group them correctly.
38
+ *
39
+ * @returns Result containing grouped selections and warnings, or error if schema not found
40
+ */
41
+ const groupBySchema = (fieldSelections, schemas) => {
42
+ const grouped = new Map();
43
+ const warnings = [];
44
+ for (const schemaName of Object.keys(schemas)) {
45
+ grouped.set(schemaName, {
46
+ fragments: [],
47
+ operations: [],
48
+ inputObjects: new Set()
49
+ });
50
+ }
51
+ for (const [canonicalId, selection] of fieldSelections) {
52
+ const schemaName = selection.schemaLabel;
53
+ const schema = schemas[schemaName];
54
+ const group = grouped.get(schemaName);
55
+ if (!schema || !group) {
56
+ return (0, neverthrow.err)(__soda_gql_builder.builderErrors.schemaNotFound(schemaName, canonicalId));
57
+ }
58
+ const outputFormatters = { scalarOutput: (name) => `ScalarOutput_${schemaName}<"${name}">` };
59
+ const inputFormatters = {
60
+ scalarInput: (name) => `ScalarInput_${schemaName}<"${name}">`,
61
+ inputObject: (name) => `Input_${schemaName}_${name}`
62
+ };
63
+ if (selection.type === "fragment") {
64
+ if (!selection.key) {
65
+ continue;
66
+ }
67
+ try {
68
+ const usedInputObjects = collectUsedInputObjectsFromSpecifiers(schema, selection.variableDefinitions);
69
+ for (const inputName of usedInputObjects) {
70
+ group.inputObjects.add(inputName);
71
+ }
72
+ const outputType = (0, __soda_gql_core.calculateFieldsType)(schema, selection.fields, outputFormatters);
73
+ const hasVariables = Object.keys(selection.variableDefinitions).length > 0;
74
+ const inputType = hasVariables ? (0, __soda_gql_core.generateInputTypeFromSpecifiers)(schema, selection.variableDefinitions, { formatters: inputFormatters }) : "void";
75
+ group.fragments.push({
76
+ key: selection.key,
77
+ inputType,
78
+ outputType
79
+ });
80
+ } catch (error) {
81
+ warnings.push(`[prebuilt] Failed to calculate type for fragment "${selection.key}": ${error instanceof Error ? error.message : String(error)}`);
82
+ }
83
+ } else if (selection.type === "operation") {
84
+ try {
85
+ const usedInputObjects = collectUsedInputObjects(schema, selection.variableDefinitions);
86
+ for (const inputName of usedInputObjects) {
87
+ group.inputObjects.add(inputName);
88
+ }
89
+ const outputType = (0, __soda_gql_core.calculateFieldsType)(schema, selection.fields, outputFormatters);
90
+ const inputType = (0, __soda_gql_core.generateInputType)(schema, selection.variableDefinitions, inputFormatters);
91
+ group.operations.push({
92
+ key: selection.operationName,
93
+ inputType,
94
+ outputType
95
+ });
96
+ } catch (error) {
97
+ warnings.push(`[prebuilt] Failed to calculate type for operation "${selection.operationName}": ${error instanceof Error ? error.message : String(error)}`);
98
+ }
99
+ }
100
+ }
101
+ return (0, neverthrow.ok)({
102
+ grouped,
103
+ warnings
104
+ });
105
+ };
106
+ /**
107
+ * Calculate relative import path from one file to another.
108
+ */
109
+ const toImportSpecifier$1 = (from, to) => {
110
+ const fromDir = (0, node_path.dirname)(from);
111
+ let relativePath = (0, node_path.relative)(fromDir, to);
112
+ if (!relativePath.startsWith(".")) {
113
+ relativePath = `./${relativePath}`;
114
+ }
115
+ return relativePath.replace(/\.ts$/, "");
116
+ };
117
+ /**
118
+ * Extract input object names from a GraphQL TypeNode.
119
+ */
120
+ const extractInputObjectsFromType = (schema, typeNode, inputObjects) => {
121
+ switch (typeNode.kind) {
122
+ case graphql.Kind.NON_NULL_TYPE:
123
+ extractInputObjectsFromType(schema, typeNode.type, inputObjects);
124
+ break;
125
+ case graphql.Kind.LIST_TYPE:
126
+ extractInputObjectsFromType(schema, typeNode.type, inputObjects);
127
+ break;
128
+ case graphql.Kind.NAMED_TYPE: {
129
+ const name = typeNode.name.value;
130
+ if (!schema.scalar[name] && !schema.enum[name] && schema.input[name]) {
131
+ inputObjects.add(name);
132
+ }
133
+ break;
134
+ }
135
+ }
136
+ };
137
+ /**
138
+ * Recursively collect nested input objects from schema definitions.
139
+ * Takes a set of initial input names and expands to include all nested inputs.
140
+ */
141
+ const collectNestedInputObjects = (schema, initialInputNames) => {
142
+ const inputObjects = new Set(initialInputNames);
143
+ const collectNested = (inputName, seen) => {
144
+ if (seen.has(inputName)) {
145
+ return;
146
+ }
147
+ seen.add(inputName);
148
+ const inputDef = schema.input[inputName];
149
+ if (!inputDef) {
150
+ return;
151
+ }
152
+ for (const field of Object.values(inputDef.fields)) {
153
+ if (field.kind === "input" && !inputObjects.has(field.name)) {
154
+ inputObjects.add(field.name);
155
+ collectNested(field.name, seen);
156
+ }
157
+ }
158
+ };
159
+ for (const inputName of Array.from(initialInputNames)) {
160
+ collectNested(inputName, new Set());
161
+ }
162
+ return inputObjects;
163
+ };
164
+ /**
165
+ * Collect all input object types used in variable definitions.
166
+ * Recursively collects nested input objects from the schema.
167
+ */
168
+ const collectUsedInputObjects = (schema, variableDefinitions) => {
169
+ const directInputs = new Set();
170
+ for (const varDef of variableDefinitions) {
171
+ extractInputObjectsFromType(schema, varDef.type, directInputs);
172
+ }
173
+ return collectNestedInputObjects(schema, directInputs);
174
+ };
175
+ /**
176
+ * Collect all input object types used in InputTypeSpecifiers.
177
+ * Recursively collects nested input objects from the schema.
178
+ */
179
+ const collectUsedInputObjectsFromSpecifiers = (schema, specifiers) => {
180
+ const directInputs = new Set();
181
+ for (const specifier of Object.values(specifiers)) {
182
+ if (specifier.kind === "input" && schema.input[specifier.name]) {
183
+ directInputs.add(specifier.name);
184
+ }
185
+ }
186
+ return collectNestedInputObjects(schema, directInputs);
187
+ };
188
+ /**
189
+ * Generate type definitions for input objects.
190
+ */
191
+ const generateInputObjectTypeDefinitions = (schema, schemaName, inputNames) => {
192
+ const lines = [];
193
+ const defaultDepth = schema.__defaultInputDepth ?? 3;
194
+ const depthOverrides = schema.__inputDepthOverrides ?? {};
195
+ const formatters = {
196
+ scalarInput: (name) => `ScalarInput_${schemaName}<"${name}">`,
197
+ inputObject: (name) => `Input_${schemaName}_${name}`
198
+ };
199
+ const sortedNames = Array.from(inputNames).sort();
200
+ for (const inputName of sortedNames) {
201
+ const typeString = (0, __soda_gql_core.generateInputObjectType)(schema, inputName, {
202
+ defaultDepth,
203
+ depthOverrides,
204
+ formatters
205
+ });
206
+ lines.push(`type Input_${schemaName}_${inputName} = ${typeString};`);
207
+ }
208
+ return lines;
209
+ };
210
+ /**
211
+ * Generate the TypeScript code for prebuilt types.
212
+ */
213
+ const generateTypesCode = (grouped, schemas, injects, outdir) => {
214
+ const typesFilePath = (0, node_path.join)(outdir, "prebuilt", "types.ts");
215
+ const lines = [
216
+ "/**",
217
+ " * Prebuilt type registry.",
218
+ " *",
219
+ " * This file is auto-generated by @soda-gql/typegen.",
220
+ " * Do not edit manually.",
221
+ " *",
222
+ " * @module",
223
+ " * @generated",
224
+ " */",
225
+ "",
226
+ "import type { PrebuiltTypeRegistry } from \"@soda-gql/core\";"
227
+ ];
228
+ for (const [schemaName, inject] of Object.entries(injects)) {
229
+ const relativePath = toImportSpecifier$1(typesFilePath, inject.scalars);
230
+ lines.push(`import type { scalar as scalar_${schemaName} } from "${relativePath}";`);
231
+ }
232
+ lines.push("");
233
+ for (const schemaName of Object.keys(injects)) {
234
+ lines.push(`type ScalarInput_${schemaName}<T extends keyof typeof scalar_${schemaName}> = ` + `typeof scalar_${schemaName}[T]["$type"]["input"];`);
235
+ lines.push(`type ScalarOutput_${schemaName}<T extends keyof typeof scalar_${schemaName}> = ` + `typeof scalar_${schemaName}[T]["$type"]["output"];`);
236
+ }
237
+ lines.push("");
238
+ for (const [schemaName, { fragments, operations, inputObjects }] of grouped) {
239
+ const schema = schemas[schemaName];
240
+ if (inputObjects.size > 0 && schema) {
241
+ lines.push("// Input object types");
242
+ const inputTypeLines = generateInputObjectTypeDefinitions(schema, schemaName, inputObjects);
243
+ lines.push(...inputTypeLines);
244
+ lines.push("");
245
+ }
246
+ const fragmentEntries = fragments.sort((a, b) => a.key.localeCompare(b.key)).map((f) => ` readonly "${f.key}": { readonly input: ${f.inputType}; readonly output: ${f.outputType} };`);
247
+ const operationEntries = operations.sort((a, b) => a.key.localeCompare(b.key)).map((o) => ` readonly "${o.key}": { readonly input: ${o.inputType}; readonly output: ${o.outputType} };`);
248
+ lines.push(`export type PrebuiltTypes_${schemaName} = {`);
249
+ lines.push(" readonly fragments: {");
250
+ if (fragmentEntries.length > 0) {
251
+ lines.push(...fragmentEntries);
252
+ }
253
+ lines.push(" };");
254
+ lines.push(" readonly operations: {");
255
+ if (operationEntries.length > 0) {
256
+ lines.push(...operationEntries);
257
+ }
258
+ lines.push(" };");
259
+ lines.push("} satisfies PrebuiltTypeRegistry;");
260
+ lines.push("");
261
+ }
262
+ return lines.join("\n");
263
+ };
264
+ /**
265
+ * Emit prebuilt types to the prebuilt/types.ts file.
266
+ *
267
+ * This function uses a partial failure strategy: if type calculation fails for
268
+ * individual elements (e.g., due to invalid field selections or missing schema
269
+ * types), those elements are skipped and warnings are collected rather than
270
+ * failing the entire emission. This allows builds to succeed even when some
271
+ * elements have issues, while still reporting problems via warnings.
272
+ *
273
+ * @param options - Emitter options including schemas, field selections, and output directory
274
+ * @returns Result containing output path and warnings, or error if a hard failure occurs
275
+ *
276
+ * @example
277
+ * ```typescript
278
+ * const result = await emitPrebuiltTypes({
279
+ * schemas: { mySchema: schema },
280
+ * fieldSelections,
281
+ * outdir: "./generated",
282
+ * injects: { mySchema: { scalars: "./scalars.ts" } },
283
+ * });
284
+ *
285
+ * if (result.isOk()) {
286
+ * console.log(`Generated: ${result.value.path}`);
287
+ * if (result.value.warnings.length > 0) {
288
+ * console.warn("Warnings:", result.value.warnings);
289
+ * }
290
+ * }
291
+ * ```
292
+ */
293
+ const emitPrebuiltTypes = async (options) => {
294
+ const { schemas, fieldSelections, outdir, injects } = options;
295
+ const groupResult = groupBySchema(fieldSelections, schemas);
296
+ if (groupResult.isErr()) {
297
+ return (0, neverthrow.err)(groupResult.error);
298
+ }
299
+ const { grouped, warnings } = groupResult.value;
300
+ const code = generateTypesCode(grouped, schemas, injects, outdir);
301
+ const typesPath = (0, node_path.join)(outdir, "prebuilt", "types.ts");
302
+ try {
303
+ await (0, node_fs_promises.writeFile)(typesPath, code, "utf-8");
304
+ return (0, neverthrow.ok)({
305
+ path: typesPath,
306
+ warnings
307
+ });
308
+ } catch (error) {
309
+ return (0, neverthrow.err)(__soda_gql_builder.builderErrors.writeFailed(typesPath, `Failed to write prebuilt types: ${error instanceof Error ? error.message : String(error)}`, error));
310
+ }
311
+ };
312
+
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
+ //#endregion
374
+ //#region packages/typegen/src/prebuilt-generator.ts
375
+ /**
376
+ * Generate the prebuilt module code.
377
+ *
378
+ * This generates:
379
+ * - prebuilt/index.ts: Uses createPrebuiltGqlElementComposer with types from PrebuiltTypes
380
+ * - prebuilt/types.ts: Placeholder types that typegen will populate
381
+ */
382
+ const generatePrebuiltModule = (schemas, options) => {
383
+ const schemaNames = Array.from(schemas.keys());
384
+ const typeImports = [];
385
+ const runtimeImports = [];
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 = [];
396
+ for (const name of schemaNames) {
397
+ const document = schemas.get(name);
398
+ if (!document) continue;
399
+ const hasAdapter = options.injection?.get(name)?.adapterImportPath !== undefined;
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} })`);
404
+ }
405
+ }
406
+ const indexCode = `\
407
+ /**
408
+ * Prebuilt GQL module for bundler-compatible type resolution.
409
+ *
410
+ * This module uses createPrebuiltGqlElementComposer which looks up types
411
+ * from PrebuiltTypes instead of using complex type inference.
412
+ *
413
+ * @module
414
+ * @generated by @soda-gql/typegen
415
+ */
416
+
417
+ import { createPrebuiltGqlElementComposer } from "@soda-gql/core";
418
+ import {
419
+ ${runtimeImports.join(",\n ")},
420
+ type ${typeImports.join(",\n type ")},
421
+ } from "${options.mainModulePath}";
422
+ import type { ${schemaNames.map((name) => `PrebuiltTypes_${name}`).join(", ")} } from "./types";
423
+
424
+ export const gql = {
425
+ ${gqlEntries.join(",\n")}
426
+ };
427
+
428
+ // Re-export types from main module
429
+ export type { ${typeImports.join(", ")} };
430
+ `;
431
+ const typesCode = `\
432
+ /**
433
+ * Prebuilt type registry.
434
+ *
435
+ * This file contains placeholder types that will be populated by typegen
436
+ * when running \`soda-gql typegen\` command.
437
+ *
438
+ * @module
439
+ * @generated by @soda-gql/typegen
440
+ */
441
+
442
+ import type { EmptyPrebuiltTypeRegistry } from "@soda-gql/core";
443
+
444
+ ${schemaNames.map((name) => `// Placeholder for ${name} schema - populated by typegen\nexport type PrebuiltTypes_${name} = EmptyPrebuiltTypeRegistry;`).join("\n\n")}
445
+ `;
446
+ return {
447
+ indexCode,
448
+ typesCode
449
+ };
450
+ };
451
+
452
+ //#endregion
453
+ //#region packages/typegen/src/runner.ts
454
+ /**
455
+ * Main typegen runner.
456
+ *
457
+ * Orchestrates the prebuilt type generation process:
458
+ * 1. Load schemas from generated CJS bundle
459
+ * 2. Generate prebuilt/index.ts
460
+ * 3. Build artifact to evaluate elements
461
+ * 4. Extract field selections
462
+ * 5. Emit prebuilt/types.ts
463
+ * 6. Bundle prebuilt module
464
+ *
465
+ * @module
466
+ */
467
+ const extensionMap = {
468
+ ".ts": ".js",
469
+ ".tsx": ".js",
470
+ ".mts": ".mjs",
471
+ ".cts": ".cjs",
472
+ ".js": ".js",
473
+ ".mjs": ".mjs",
474
+ ".cjs": ".cjs"
475
+ };
476
+ const toImportSpecifier = (fromPath, targetPath, options) => {
477
+ const fromDir = (0, node_path.dirname)(fromPath);
478
+ const normalized = (0, node_path.relative)(fromDir, targetPath).replace(/\\/g, "/");
479
+ const sourceExt = (0, node_path.extname)(targetPath);
480
+ if (!options?.includeExtension) {
481
+ if (normalized.length === 0) {
482
+ return `./${targetPath.slice(0, -sourceExt.length).split("/").pop()}`;
483
+ }
484
+ const withPrefix$1 = normalized.startsWith(".") ? normalized : `./${normalized}`;
485
+ const currentExt$1 = (0, node_path.extname)(withPrefix$1);
486
+ return currentExt$1 ? withPrefix$1.slice(0, -currentExt$1.length) : withPrefix$1;
487
+ }
488
+ const runtimeExt = extensionMap[sourceExt] ?? sourceExt;
489
+ if (normalized.length === 0) {
490
+ const base = runtimeExt !== sourceExt ? targetPath.slice(0, -sourceExt.length).split("/").pop() : targetPath.split("/").pop();
491
+ return `./${base}${runtimeExt}`;
492
+ }
493
+ const withPrefix = normalized.startsWith(".") ? normalized : `./${normalized}`;
494
+ if (!runtimeExt) {
495
+ return withPrefix;
496
+ }
497
+ if (withPrefix.endsWith(runtimeExt)) {
498
+ return withPrefix;
499
+ }
500
+ const currentExt = (0, node_path.extname)(withPrefix);
501
+ const withoutExt = currentExt ? withPrefix.slice(0, -currentExt.length) : withPrefix;
502
+ return `${withoutExt}${runtimeExt}`;
503
+ };
504
+ /**
505
+ * Bundle the prebuilt module to CJS format.
506
+ */
507
+ const bundlePrebuiltModule = async (sourcePath) => {
508
+ const sourceExt = (0, node_path.extname)(sourcePath);
509
+ const baseName = sourcePath.slice(0, -sourceExt.length);
510
+ const cjsPath = `${baseName}.cjs`;
511
+ await (0, esbuild.build)({
512
+ entryPoints: [sourcePath],
513
+ outfile: cjsPath,
514
+ format: "cjs",
515
+ platform: "node",
516
+ bundle: true,
517
+ external: ["@soda-gql/core", "@soda-gql/runtime"],
518
+ sourcemap: false,
519
+ minify: false,
520
+ treeShaking: false
521
+ });
522
+ return { cjsPath };
523
+ };
524
+ /**
525
+ * Write a TypeScript module to disk.
526
+ */
527
+ const writeModule = async (path, content) => {
528
+ await (0, node_fs_promises.mkdir)((0, node_path.dirname)(path), { recursive: true });
529
+ await (0, node_fs_promises.writeFile)(path, content, "utf-8");
530
+ };
531
+ /**
532
+ * Load GraphQL schema documents from schema paths.
533
+ * This is needed for generatePrebuiltModule which expects DocumentNode.
534
+ */
535
+ const loadSchemaDocuments = (schemasConfig) => {
536
+ const documents = new Map();
537
+ for (const [name, schemaConfig] of Object.entries(schemasConfig)) {
538
+ const schemaPaths = Array.isArray(schemaConfig.schema) ? schemaConfig.schema : [schemaConfig.schema];
539
+ let combinedSource = "";
540
+ for (const schemaPath of schemaPaths) {
541
+ combinedSource += `${(0, node_fs.readFileSync)(schemaPath, "utf-8")}\n`;
542
+ }
543
+ documents.set(name, (0, graphql.parse)(combinedSource));
544
+ }
545
+ return documents;
546
+ };
547
+ /**
548
+ * Run the typegen process.
549
+ *
550
+ * This function:
551
+ * 1. Loads schemas from the generated CJS bundle
552
+ * 2. Generates prebuilt/index.ts using generatePrebuiltModule
553
+ * 3. Creates a BuilderService and builds the artifact
554
+ * 4. Extracts field selections from the artifact
555
+ * 5. Emits prebuilt/types.ts using emitPrebuiltTypes
556
+ * 6. Bundles the prebuilt module
557
+ *
558
+ * @param options - Typegen options including config
559
+ * @returns Result containing success data or error
560
+ */
561
+ const runTypegen = async (options) => {
562
+ const { config } = options;
563
+ const outdir = (0, node_path.resolve)(config.outdir);
564
+ const cjsPath = (0, node_path.join)(outdir, "index.cjs");
565
+ const importSpecifierOptions = { includeExtension: config.styles.importExtension };
566
+ if (!(0, node_fs.existsSync)(cjsPath)) {
567
+ return (0, neverthrow.err)(typegenErrors.codegenRequired(outdir));
568
+ }
569
+ const schemaNames = Object.keys(config.schemas);
570
+ const schemasResult = (0, __soda_gql_builder.loadSchemasFromBundle)(cjsPath, schemaNames);
571
+ if (schemasResult.isErr()) {
572
+ return (0, neverthrow.err)(typegenErrors.schemaLoadFailed(schemaNames, schemasResult.error));
573
+ }
574
+ const schemas = schemasResult.value;
575
+ const prebuiltDir = (0, node_path.join)(outdir, "prebuilt");
576
+ await (0, node_fs_promises.mkdir)(prebuiltDir, { recursive: true });
577
+ const schemaDocuments = loadSchemaDocuments(config.schemas);
578
+ const mainModulePath = toImportSpecifier((0, node_path.join)(prebuiltDir, "index.ts"), (0, node_path.join)(outdir, "index.ts"), importSpecifierOptions);
579
+ const injection = new Map();
580
+ for (const [schemaName, schemaConfig] of Object.entries(config.schemas)) {
581
+ if (schemaConfig.inject.adapter) {
582
+ injection.set(schemaName, { adapterImportPath: toImportSpecifier((0, node_path.join)(outdir, "index.ts"), schemaConfig.inject.adapter, importSpecifierOptions) });
583
+ } else {
584
+ injection.set(schemaName, {});
585
+ }
586
+ }
587
+ const prebuilt = generatePrebuiltModule(schemaDocuments, {
588
+ mainModulePath,
589
+ injection
590
+ });
591
+ const prebuiltIndexPath = (0, node_path.join)(prebuiltDir, "index.ts");
592
+ try {
593
+ await writeModule(prebuiltIndexPath, prebuilt.indexCode);
594
+ } catch (error) {
595
+ return (0, neverthrow.err)(typegenErrors.emitFailed(prebuiltIndexPath, `Failed to write prebuilt index: ${error instanceof Error ? error.message : String(error)}`, error));
596
+ }
597
+ const builderService = (0, __soda_gql_builder.createBuilderService)({ config });
598
+ const artifactResult = await builderService.buildAsync();
599
+ if (artifactResult.isErr()) {
600
+ return (0, neverthrow.err)(typegenErrors.buildFailed(`Builder failed: ${artifactResult.error.message}`, artifactResult.error));
601
+ }
602
+ const intermediateElements = builderService.getIntermediateElements();
603
+ if (!intermediateElements) {
604
+ return (0, neverthrow.err)(typegenErrors.buildFailed("No intermediate elements available after build", undefined));
605
+ }
606
+ const fieldSelectionsResult = (0, __soda_gql_builder.extractFieldSelections)(intermediateElements);
607
+ 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
+ const emitResult = await emitPrebuiltTypes({
613
+ schemas,
614
+ fieldSelections,
615
+ outdir,
616
+ injects
617
+ });
618
+ if (emitResult.isErr()) {
619
+ return (0, neverthrow.err)(emitResult.error);
620
+ }
621
+ const { path: prebuiltTypesPath, warnings: emitWarnings } = emitResult.value;
622
+ try {
623
+ await bundlePrebuiltModule(prebuiltIndexPath);
624
+ } catch (error) {
625
+ return (0, neverthrow.err)(typegenErrors.bundleFailed(prebuiltIndexPath, `Failed to bundle prebuilt module: ${error instanceof Error ? error.message : String(error)}`, error));
626
+ }
627
+ let fragmentCount = 0;
628
+ let operationCount = 0;
629
+ for (const selection of fieldSelections.values()) {
630
+ if (selection.type === "fragment" && selection.key) {
631
+ fragmentCount++;
632
+ } else if (selection.type === "operation") {
633
+ operationCount++;
634
+ }
635
+ }
636
+ const allWarnings = [...extractWarnings, ...emitWarnings];
637
+ return (0, neverthrow.ok)({
638
+ prebuiltIndexPath,
639
+ prebuiltTypesPath,
640
+ fragmentCount,
641
+ operationCount,
642
+ warnings: allWarnings
643
+ });
644
+ };
645
+
646
+ //#endregion
647
+ exports.emitPrebuiltTypes = emitPrebuiltTypes;
648
+ exports.formatTypegenError = formatTypegenError;
649
+ exports.generatePrebuiltModule = generatePrebuiltModule;
650
+ exports.runTypegen = runTypegen;
651
+ exports.typegenErrors = typegenErrors;
652
+ //# sourceMappingURL=index.cjs.map