@gqlkit-ts/cli 0.3.0 → 0.4.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.
Files changed (86) hide show
  1. package/README.md +143 -0
  2. package/dist/auto-type-generator/auto-type-generator.d.ts.map +1 -1
  3. package/dist/auto-type-generator/auto-type-generator.js +16 -13
  4. package/dist/auto-type-generator/auto-type-generator.js.map +1 -1
  5. package/dist/commands/docs.d.ts.map +1 -1
  6. package/dist/commands/docs.js +33 -13
  7. package/dist/commands/docs.js.map +1 -1
  8. package/dist/config/types.d.ts +13 -0
  9. package/dist/config/types.d.ts.map +1 -1
  10. package/dist/config-loader/loader.d.ts +3 -0
  11. package/dist/config-loader/loader.d.ts.map +1 -1
  12. package/dist/config-loader/loader.js +1 -0
  13. package/dist/config-loader/loader.js.map +1 -1
  14. package/dist/config-loader/validator.d.ts.map +1 -1
  15. package/dist/config-loader/validator.js +23 -0
  16. package/dist/config-loader/validator.js.map +1 -1
  17. package/dist/gen-orchestrator/orchestrator.d.ts.map +1 -1
  18. package/dist/gen-orchestrator/orchestrator.js +19 -6
  19. package/dist/gen-orchestrator/orchestrator.js.map +1 -1
  20. package/dist/resolver-extractor/extractor/define-api-extractor.js +4 -4
  21. package/dist/resolver-extractor/extractor/define-api-extractor.js.map +1 -1
  22. package/dist/schema-generator/builder/ast-builder.d.ts +2 -2
  23. package/dist/schema-generator/builder/ast-builder.d.ts.map +1 -1
  24. package/dist/schema-generator/builder/ast-builder.js +12 -34
  25. package/dist/schema-generator/builder/ast-builder.js.map +1 -1
  26. package/dist/schema-generator/emitter/code-emitter.d.ts +3 -1
  27. package/dist/schema-generator/emitter/code-emitter.d.ts.map +1 -1
  28. package/dist/schema-generator/emitter/code-emitter.js +22 -12
  29. package/dist/schema-generator/emitter/code-emitter.js.map +1 -1
  30. package/dist/schema-generator/emitter/sdl-emitter.d.ts +0 -4
  31. package/dist/schema-generator/emitter/sdl-emitter.d.ts.map +1 -1
  32. package/dist/schema-generator/emitter/sdl-emitter.js +0 -4
  33. package/dist/schema-generator/emitter/sdl-emitter.js.map +1 -1
  34. package/dist/schema-generator/generate-schema.d.ts +2 -0
  35. package/dist/schema-generator/generate-schema.d.ts.map +1 -1
  36. package/dist/schema-generator/generate-schema.js +13 -4
  37. package/dist/schema-generator/generate-schema.js.map +1 -1
  38. package/dist/schema-generator/integrator/result-integrator.d.ts +10 -12
  39. package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -1
  40. package/dist/schema-generator/integrator/result-integrator.js +18 -55
  41. package/dist/schema-generator/integrator/result-integrator.js.map +1 -1
  42. package/dist/shared/branded-type-detector.d.ts +43 -0
  43. package/dist/shared/branded-type-detector.d.ts.map +1 -0
  44. package/dist/shared/branded-type-detector.js +146 -0
  45. package/dist/shared/branded-type-detector.js.map +1 -0
  46. package/dist/shared/string-utils.d.ts +2 -0
  47. package/dist/shared/string-utils.d.ts.map +1 -0
  48. package/dist/shared/string-utils.js +8 -0
  49. package/dist/shared/string-utils.js.map +1 -0
  50. package/dist/type-extractor/converter/field-eligibility.d.ts +8 -6
  51. package/dist/type-extractor/converter/field-eligibility.d.ts.map +1 -1
  52. package/dist/type-extractor/converter/field-eligibility.js +7 -28
  53. package/dist/type-extractor/converter/field-eligibility.js.map +1 -1
  54. package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -1
  55. package/dist/type-extractor/converter/graphql-converter.js +6 -11
  56. package/dist/type-extractor/converter/graphql-converter.js.map +1 -1
  57. package/dist/type-extractor/extractor/field-type-resolver.d.ts.map +1 -1
  58. package/dist/type-extractor/extractor/field-type-resolver.js +39 -4
  59. package/dist/type-extractor/extractor/field-type-resolver.js.map +1 -1
  60. package/dist/type-extractor/types/diagnostics.d.ts +1 -1
  61. package/dist/type-extractor/types/diagnostics.d.ts.map +1 -1
  62. package/dist/type-extractor/validator/type-validator.d.ts +1 -1
  63. package/dist/type-extractor/validator/type-validator.d.ts.map +1 -1
  64. package/dist/type-extractor/validator/type-validator.js +2 -10
  65. package/dist/type-extractor/validator/type-validator.js.map +1 -1
  66. package/docs/configuration.md +9 -0
  67. package/package.json +3 -3
  68. package/src/auto-type-generator/auto-type-generator.ts +23 -26
  69. package/src/commands/docs.ts +50 -24
  70. package/src/config/types.ts +15 -0
  71. package/src/config-loader/loader.ts +4 -0
  72. package/src/config-loader/validator.ts +33 -0
  73. package/src/gen-orchestrator/orchestrator.ts +30 -11
  74. package/src/resolver-extractor/extractor/define-api-extractor.ts +5 -5
  75. package/src/schema-generator/builder/ast-builder.ts +52 -81
  76. package/src/schema-generator/emitter/code-emitter.ts +48 -11
  77. package/src/schema-generator/emitter/sdl-emitter.ts +0 -4
  78. package/src/schema-generator/generate-schema.ts +13 -15
  79. package/src/schema-generator/integrator/result-integrator.ts +37 -78
  80. package/src/shared/branded-type-detector.ts +182 -0
  81. package/src/shared/string-utils.ts +7 -0
  82. package/src/type-extractor/converter/field-eligibility.ts +13 -29
  83. package/src/type-extractor/converter/graphql-converter.ts +6 -16
  84. package/src/type-extractor/extractor/field-type-resolver.ts +49 -4
  85. package/src/type-extractor/types/diagnostics.ts +1 -0
  86. package/src/type-extractor/validator/type-validator.ts +2 -15
@@ -40,6 +40,8 @@ export default defineConfig({
40
40
  schemaPath: "src/gqlkit/__generated__/schema.graphql",
41
41
  // Set to null to disable output:
42
42
  // schemaPath: null,
43
+ // Import extension in generated files (default: "js")
44
+ // importExtension: "none", // for bundlers
43
45
  },
44
46
 
45
47
  // Hooks
@@ -89,9 +91,16 @@ export default defineConfig({
89
91
  | `typeDefsPath` | `string` \| `null` | `"src/gqlkit/__generated__/typeDefs.ts"` | Path for the TypeDefs output |
90
92
  | `resolversPath` | `string` \| `null` | `"src/gqlkit/__generated__/resolvers.ts"` | Path for the resolvers output |
91
93
  | `schemaPath` | `string` \| `null` | `"src/gqlkit/__generated__/schema.graphql"` | Path for the SDL output |
94
+ | `importExtension` | `"js"` \| `"none"` \| `"ts"` | `"js"` | File extension for import statements |
92
95
 
93
96
  Set any path to `null` to disable that output.
94
97
 
98
+ The `importExtension` option controls file extensions in generated import statements:
99
+
100
+ - `"js"` (default): Converts `.ts` to `.js` (compatible with ESM + Node16)
101
+ - `"none"`: No extension (for bundlers like webpack, vite)
102
+ - `"ts"`: Keeps `.ts` extension (for Deno)
103
+
95
104
  ## Hooks
96
105
 
97
106
  Execute commands after file generation:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gqlkit-ts/cli",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Just types and functions — write TypeScript, generate GraphQL.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -60,8 +60,8 @@
60
60
  "devDependencies": {
61
61
  "@types/shell-quote": "1.7.5",
62
62
  "memfs": "4.56.10",
63
- "@gqlkit-ts/runtime": "0.2.0",
64
- "@gqlkit-ts/docs": "0.0.1"
63
+ "@gqlkit-ts/docs": "0.0.1",
64
+ "@gqlkit-ts/runtime": "0.2.0"
65
65
  },
66
66
  "scripts": {
67
67
  "build": "tsc --build && bundle-docs --target ./docs",
@@ -12,12 +12,10 @@ import {
12
12
  stripEnumPrefix,
13
13
  } from "../shared/enum-prefix-detector.js";
14
14
  import { getSourceLocationOrDefault } from "../shared/source-location.js";
15
+ import { toScreamingSnakeCase } from "../shared/string-utils.js";
15
16
  import type { DeprecationInfo } from "../shared/tsdoc-parser.js";
16
17
  import { convertTsTypeToGraphQLType } from "../shared/type-converter.js";
17
- import {
18
- isEligibleAsInputObjectField,
19
- isEligibleAsObjectField,
20
- } from "../type-extractor/converter/field-eligibility.js";
18
+ import { isEligibleField } from "../type-extractor/converter/field-eligibility.js";
21
19
  import {
22
20
  createReferenceType,
23
21
  type Diagnostic,
@@ -259,27 +257,33 @@ function collectInlineObjectsFromType(
259
257
  const isInput = isInputTypeName(typeInfo.metadata.name);
260
258
 
261
259
  for (const field of typeInfo.fields) {
262
- collectInlineObjectsFromField(
260
+ collectInlineObjectsFromField({
263
261
  field,
264
- typeInfo.metadata.name,
265
- [],
262
+ parentTypeName: typeInfo.metadata.name,
263
+ parentPath: [],
266
264
  isInput,
267
- typeInfo.metadata.sourceFile,
265
+ sourceFile: typeInfo.metadata.sourceFile,
268
266
  results,
269
- );
267
+ });
270
268
  }
271
269
 
272
270
  return results;
273
271
  }
274
272
 
273
+ interface CollectInlineObjectsFromFieldParams {
274
+ readonly field: FieldDefinition;
275
+ readonly parentTypeName: string;
276
+ readonly parentPath: ReadonlyArray<string>;
277
+ readonly isInput: boolean;
278
+ readonly sourceFile: string;
279
+ readonly results: InlineObjectWithContext[];
280
+ }
281
+
275
282
  function collectInlineObjectsFromField(
276
- field: FieldDefinition,
277
- parentTypeName: string,
278
- parentPath: ReadonlyArray<string>,
279
- isInput: boolean,
280
- sourceFile: string,
281
- results: InlineObjectWithContext[],
283
+ params: CollectInlineObjectsFromFieldParams,
282
284
  ): void {
285
+ const { field, parentTypeName, parentPath, isInput, sourceFile, results } =
286
+ params;
283
287
  const tsType = field.tsType;
284
288
 
285
289
  if (tsType.kind !== "inlineObject" || !tsType.inlineObjectProperties) {
@@ -481,9 +485,10 @@ function generateAutoType(
481
485
  const diagnostics: Diagnostic[] = [];
482
486
 
483
487
  for (const prop of inlineObj.properties) {
484
- const eligibility = isInput
485
- ? isEligibleAsInputObjectField(prop.name)
486
- : isEligibleAsObjectField(prop.name);
488
+ const eligibility = isEligibleField({
489
+ fieldName: prop.name,
490
+ kind: isInput ? "input" : "object",
491
+ });
487
492
 
488
493
  if (!eligibility.eligible) {
489
494
  diagnostics.push({
@@ -853,14 +858,6 @@ function buildGeneratedTypeNamesMap(
853
858
  return map;
854
859
  }
855
860
 
856
- function toScreamingSnakeCase(value: string): string {
857
- return value
858
- .replace(/[-\s]+/g, "_")
859
- .replace(/([a-z])([A-Z])/g, "$1_$2")
860
- .replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
861
- .toUpperCase();
862
- }
863
-
864
861
  interface ConvertInlineEnumMembersParams {
865
862
  readonly members: ReadonlyArray<InlineEnumMemberInfo>;
866
863
  readonly enumName: string;
@@ -1,10 +1,7 @@
1
1
  import { access, mkdir, readFile, symlink, writeFile } from "node:fs/promises";
2
- import { dirname, join, relative } from "node:path";
3
- import { fileURLToPath } from "node:url";
2
+ import { dirname, join, parse, relative, resolve } from "node:path";
4
3
  import { define } from "gunshi";
5
4
 
6
- const __dirname = dirname(fileURLToPath(import.meta.url));
7
- const CLI_DOCS_DIR = join(__dirname, "../../docs");
8
5
  const SKILL_NAME = "gqlkit-guide";
9
6
 
10
7
  export interface RunDocsCommandOptions {
@@ -27,6 +24,27 @@ async function exists(path: string): Promise<boolean> {
27
24
  }
28
25
  }
29
26
 
27
+ async function findNodeModulesDocsPath(
28
+ startDir: string,
29
+ ): Promise<string | null> {
30
+ let currentDir = resolve(startDir);
31
+ const root = parse(currentDir).root;
32
+
33
+ while (currentDir !== root) {
34
+ const candidate = join(currentDir, "node_modules/@gqlkit-ts/cli/docs");
35
+ if (await exists(candidate)) {
36
+ return candidate;
37
+ }
38
+ const parent = dirname(currentDir);
39
+ if (parent === currentDir) {
40
+ break;
41
+ }
42
+ currentDir = parent;
43
+ }
44
+
45
+ return null;
46
+ }
47
+
30
48
  async function detectClaudeEnvironment(dir: string): Promise<boolean> {
31
49
  const claudeMdExists = await exists(join(dir, "CLAUDE.md"));
32
50
  const claudeDirExists = await exists(join(dir, ".claude"));
@@ -124,8 +142,16 @@ async function generateToolFiles(
124
142
  await writeFile(skillMdPath, generateSkillMd());
125
143
  filesWritten.push(skillMdPath);
126
144
 
145
+ const docsPath = await findNodeModulesDocsPath(skillDir);
146
+ if (docsPath === null) {
147
+ throw new Error(
148
+ `Could not find @gqlkit-ts/cli docs directory under node_modules (starting from ${resolve(skillDir)}). ` +
149
+ "Ensure @gqlkit-ts/cli is installed.",
150
+ );
151
+ }
152
+
127
153
  const referencesPath = join(skillDir, "references");
128
- const relativePath = relative(skillDir, CLI_DOCS_DIR);
154
+ const relativePath = relative(skillDir, docsPath);
129
155
  await createSymlinkIfNotExists(referencesPath, relativePath);
130
156
  filesWritten.push(referencesPath);
131
157
 
@@ -137,13 +163,6 @@ async function generateToolFiles(
137
163
  export async function runDocsCommand(
138
164
  options: RunDocsCommandOptions,
139
165
  ): Promise<RunDocsCommandResult> {
140
- if (!(await exists(CLI_DOCS_DIR))) {
141
- console.error(
142
- `Documentation directory not found: ${CLI_DOCS_DIR}\nRun "pnpm build" to generate documentation files.`,
143
- );
144
- return { exitCode: 1, filesWritten: [] };
145
- }
146
-
147
166
  const filesWritten: string[] = [];
148
167
 
149
168
  const autoDetect = !options.claude && !options.codex;
@@ -161,20 +180,27 @@ export async function runDocsCommand(
161
180
  return { exitCode: 0, filesWritten: [] };
162
181
  }
163
182
 
164
- if (generateClaude) {
165
- await generateToolFiles(
166
- options.output,
167
- { configDir: ".claude", rulesFile: "CLAUDE.md" },
168
- filesWritten,
169
- );
170
- }
183
+ try {
184
+ if (generateClaude) {
185
+ await generateToolFiles(
186
+ options.output,
187
+ { configDir: ".claude", rulesFile: "CLAUDE.md" },
188
+ filesWritten,
189
+ );
190
+ }
171
191
 
172
- if (generateCodex) {
173
- await generateToolFiles(
174
- options.output,
175
- { configDir: ".codex", rulesFile: "AGENTS.md" },
176
- filesWritten,
192
+ if (generateCodex) {
193
+ await generateToolFiles(
194
+ options.output,
195
+ { configDir: ".codex", rulesFile: "AGENTS.md" },
196
+ filesWritten,
197
+ );
198
+ }
199
+ } catch (error) {
200
+ console.error(
201
+ error instanceof Error ? (error.stack ?? error.message) : String(error),
177
202
  );
203
+ return { exitCode: 1, filesWritten: [] };
178
204
  }
179
205
 
180
206
  return { exitCode: 0, filesWritten };
@@ -1,3 +1,11 @@
1
+ /**
2
+ * File extension mode for generated import statements.
3
+ * - "js": Convert .ts to .js (default, compatible with ESM + Node16)
4
+ * - "none": No extension (for bundlers)
5
+ * - "ts": Keep .ts extension (for Deno)
6
+ */
7
+ export type ImportExtension = "js" | "none" | "ts";
8
+
1
9
  /**
2
10
  * Output configuration for generated files.
3
11
  * All paths are relative to project root.
@@ -29,6 +37,13 @@ export interface OutputConfig {
29
37
  * @default "src/gqlkit/__generated__/schema.graphql"
30
38
  */
31
39
  readonly schemaPath?: string | null;
40
+
41
+ /**
42
+ * File extension to use in generated import statements.
43
+ * @see ImportExtension
44
+ * @default "js"
45
+ */
46
+ readonly importExtension?: ImportExtension;
32
47
  }
33
48
 
34
49
  /**
@@ -1,6 +1,7 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { createJiti } from "jiti";
4
+ import type { ImportExtension } from "../config/types.js";
4
5
  import type { Diagnostic } from "../type-extractor/types/index.js";
5
6
  import { validateConfig } from "./validator.js";
6
7
 
@@ -27,6 +28,8 @@ export interface ResolvedOutputConfig {
27
28
  readonly typeDefsPath: string | null;
28
29
  /** Schema SDL output path. Null suppresses output */
29
30
  readonly schemaPath: string | null;
31
+ /** File extension for imports. Default: "js" */
32
+ readonly importExtension: ImportExtension;
30
33
  }
31
34
 
32
35
  /**
@@ -64,6 +67,7 @@ const DEFAULT_OUTPUT_CONFIG: ResolvedOutputConfig = {
64
67
  resolversPath: DEFAULT_RESOLVERS_PATH,
65
68
  typeDefsPath: DEFAULT_TYPEDEFS_PATH,
66
69
  schemaPath: DEFAULT_SCHEMA_PATH,
70
+ importExtension: "js",
67
71
  };
68
72
 
69
73
  const DEFAULT_HOOKS_CONFIG: ResolvedHooksConfig = {
@@ -1,3 +1,4 @@
1
+ import type { ImportExtension } from "../config/types.js";
1
2
  import type { Diagnostic } from "../type-extractor/types/index.js";
2
3
  import {
3
4
  DEFAULT_RESOLVERS_PATH,
@@ -186,6 +187,31 @@ function validateTsconfigPath(
186
187
  return { resolved: value, diagnostics: [] };
187
188
  }
188
189
 
190
+ function validateImportExtension(
191
+ value: unknown,
192
+ configPath: string,
193
+ ): { resolved: ImportExtension; diagnostics: Diagnostic[] } {
194
+ if (value === undefined) {
195
+ return { resolved: "js", diagnostics: [] };
196
+ }
197
+
198
+ if (value !== "js" && value !== "none" && value !== "ts") {
199
+ return {
200
+ resolved: "js",
201
+ diagnostics: [
202
+ {
203
+ code: "CONFIG_INVALID_IMPORT_EXTENSION",
204
+ message: 'output.importExtension must be "js", "none", or "ts"',
205
+ severity: "error",
206
+ location: { file: configPath, line: 1, column: 1 },
207
+ },
208
+ ],
209
+ };
210
+ }
211
+
212
+ return { resolved: value, diagnostics: [] };
213
+ }
214
+
189
215
  function validateOutputConfig(
190
216
  output: unknown,
191
217
  configPath: string,
@@ -198,6 +224,7 @@ function validateOutputConfig(
198
224
  resolversPath: DEFAULT_RESOLVERS_PATH,
199
225
  typeDefsPath: DEFAULT_TYPEDEFS_PATH,
200
226
  schemaPath: DEFAULT_SCHEMA_PATH,
227
+ importExtension: "js",
201
228
  },
202
229
  diagnostics: [],
203
230
  };
@@ -228,10 +255,15 @@ function validateOutputConfig(
228
255
  "output.schemaPath",
229
256
  configPath,
230
257
  );
258
+ const importExtensionResult = validateImportExtension(
259
+ output["importExtension"],
260
+ configPath,
261
+ );
231
262
 
232
263
  diagnostics.push(...resolversPathResult.diagnostics);
233
264
  diagnostics.push(...typeDefsPathResult.diagnostics);
234
265
  diagnostics.push(...schemaPathResult.diagnostics);
266
+ diagnostics.push(...importExtensionResult.diagnostics);
235
267
 
236
268
  if (diagnostics.length > 0) {
237
269
  return { resolved: undefined, diagnostics };
@@ -242,6 +274,7 @@ function validateOutputConfig(
242
274
  resolversPath: resolversPathResult.resolved,
243
275
  typeDefsPath: typeDefsPathResult.resolved,
244
276
  schemaPath: schemaPathResult.resolved,
277
+ importExtension: importExtensionResult.resolved,
245
278
  },
246
279
  diagnostics: [],
247
280
  };
@@ -91,6 +91,12 @@ interface ResolversResult {
91
91
  diagnostics: Diagnostics;
92
92
  }
93
93
 
94
+ interface ScalarConfig {
95
+ readonly customScalarNames: string[];
96
+ readonly globalTypeMappings: GlobalTypeMapping[];
97
+ readonly configScalars: ConfigScalarMapping[];
98
+ }
99
+
94
100
  interface PipelineContext {
95
101
  readonly config: GenerationConfig;
96
102
  readonly sourceFiles: ReadonlyArray<string>;
@@ -101,6 +107,7 @@ interface PipelineContext {
101
107
  readonly typesResult: TypesResult | null;
102
108
  readonly resolversResult: ResolversResult | null;
103
109
  readonly directiveDefinitions: DirectiveDefinitionInfo[] | null;
110
+ readonly scalarConfig: ScalarConfig | null;
104
111
  readonly diagnostics: Diagnostic[];
105
112
  readonly aborted: boolean;
106
113
  }
@@ -449,6 +456,7 @@ function createInitialContext(config: GenerationConfig): PipelineContext {
449
456
  typesResult: null,
450
457
  resolversResult: null,
451
458
  directiveDefinitions: null,
459
+ scalarConfig: null,
452
460
  diagnostics: [],
453
461
  aborted: false,
454
462
  };
@@ -514,11 +522,7 @@ function collectTypeNamesStep(ctx: PipelineContext): PipelineContext {
514
522
  };
515
523
  }
516
524
 
517
- function prepareScalarConfig(config: GenerationConfig): {
518
- customScalarNames: string[];
519
- globalTypeMappings: GlobalTypeMapping[];
520
- configScalars: ConfigScalarMapping[];
521
- } {
525
+ function prepareScalarConfig(config: GenerationConfig): ScalarConfig {
522
526
  const customScalarNames =
523
527
  config.customScalars?.map((s) => s.graphqlName) ?? [];
524
528
 
@@ -556,18 +560,25 @@ function prepareScalarConfig(config: GenerationConfig): {
556
560
  return { customScalarNames, globalTypeMappings, configScalars };
557
561
  }
558
562
 
563
+ function prepareScalarConfigStep(ctx: PipelineContext): PipelineContext {
564
+ if (ctx.aborted) return ctx;
565
+
566
+ return { ...ctx, scalarConfig: prepareScalarConfig(ctx.config) };
567
+ }
568
+
559
569
  function extractTypesStep(ctx: PipelineContext): PipelineContext {
560
570
  if (
561
571
  ctx.aborted ||
562
572
  !ctx.program ||
563
573
  !ctx.knownTypeNames ||
564
574
  !ctx.knownTypeSymbols ||
565
- !ctx.underlyingSymbolToTypeName
575
+ !ctx.underlyingSymbolToTypeName ||
576
+ !ctx.scalarConfig
566
577
  )
567
578
  return ctx;
568
579
 
569
580
  const { customScalarNames, globalTypeMappings, configScalars } =
570
- prepareScalarConfig(ctx.config);
581
+ ctx.scalarConfig;
571
582
 
572
583
  const typesResult = extractTypesCore({
573
584
  program: ctx.program,
@@ -591,11 +602,12 @@ function extractResolversStep(ctx: PipelineContext): PipelineContext {
591
602
  !ctx.knownTypeNames ||
592
603
  !ctx.knownTypeSymbols ||
593
604
  !ctx.underlyingSymbolToTypeName ||
594
- !ctx.typesResult
605
+ !ctx.typesResult ||
606
+ !ctx.scalarConfig
595
607
  )
596
608
  return ctx;
597
609
 
598
- const { globalTypeMappings } = prepareScalarConfig(ctx.config);
610
+ const { globalTypeMappings } = ctx.scalarConfig;
599
611
 
600
612
  const resolversResult = extractResolversCore({
601
613
  program: ctx.program,
@@ -663,11 +675,16 @@ function generateSchemaStep(ctx: PipelineContext): {
663
675
  ctx: PipelineContext;
664
676
  schemaResult: ReturnType<typeof generateSchema> | null;
665
677
  } {
666
- if (ctx.aborted || !ctx.typesResult || !ctx.resolversResult) {
678
+ if (
679
+ ctx.aborted ||
680
+ !ctx.typesResult ||
681
+ !ctx.resolversResult ||
682
+ !ctx.scalarConfig
683
+ ) {
667
684
  return { ctx, schemaResult: null };
668
685
  }
669
686
 
670
- const { customScalarNames } = prepareScalarConfig(ctx.config);
687
+ const { customScalarNames } = ctx.scalarConfig;
671
688
  const allCustomScalarNames = [
672
689
  ...customScalarNames,
673
690
  ...ctx.typesResult.detectedScalarNames,
@@ -687,6 +704,7 @@ function generateSchemaStep(ctx: PipelineContext): {
687
704
  enablePruning: null,
688
705
  sourceRoot: ctx.config.cwd,
689
706
  knownTypeNames: ctx.knownTypeNames,
707
+ importExtension: ctx.config.output.importExtension,
690
708
  });
691
709
 
692
710
  const newDiagnostics = [...ctx.diagnostics, ...schemaResult.diagnostics];
@@ -739,6 +757,7 @@ export async function executeGeneration(
739
757
  ctx = await scanSourceFilesStep(ctx);
740
758
  ctx = createProgramStep(ctx);
741
759
  ctx = collectTypeNamesStep(ctx);
760
+ ctx = prepareScalarConfigStep(ctx);
742
761
  ctx = extractTypesStep(ctx);
743
762
  ctx = extractResolversStep(ctx);
744
763
  ctx = extractDirectivesStep(ctx);
@@ -200,23 +200,23 @@ function extractTypeNameFromType(
200
200
  function detectResolverFromMetadataType(
201
201
  callExpr: ts.CallExpression,
202
202
  checker: ts.TypeChecker,
203
- ): DefineApiResolverType | undefined {
203
+ ): DefineApiResolverType | null {
204
204
  const returnType = checker.getTypeAtLocation(callExpr);
205
205
 
206
206
  const metadataProp = returnType.getProperty(RESOLVER_METADATA_PROPERTY);
207
207
  if (!metadataProp) {
208
- return undefined;
208
+ return null;
209
209
  }
210
210
 
211
211
  const metadataType = checker.getTypeOfSymbol(metadataProp);
212
212
  const actualType = getActualMetadataType(metadataType);
213
213
  if (!actualType) {
214
- return undefined;
214
+ return null;
215
215
  }
216
216
 
217
217
  const kindProp = actualType.getProperty("kind");
218
218
  if (!kindProp) {
219
- return undefined;
219
+ return null;
220
220
  }
221
221
 
222
222
  const kindType = checker.getTypeOfSymbol(kindProp);
@@ -227,7 +227,7 @@ function detectResolverFromMetadataType(
227
227
  }
228
228
  }
229
229
 
230
- return undefined;
230
+ return null;
231
231
  }
232
232
 
233
233
  function isInlineTypeLiteralDeclaration(declaration: ts.Declaration): boolean {