@gqlkit-ts/cli 0.3.0 → 0.4.0

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 (82) 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/config/types.d.ts +13 -0
  6. package/dist/config/types.d.ts.map +1 -1
  7. package/dist/config-loader/loader.d.ts +3 -0
  8. package/dist/config-loader/loader.d.ts.map +1 -1
  9. package/dist/config-loader/loader.js +1 -0
  10. package/dist/config-loader/loader.js.map +1 -1
  11. package/dist/config-loader/validator.d.ts.map +1 -1
  12. package/dist/config-loader/validator.js +23 -0
  13. package/dist/config-loader/validator.js.map +1 -1
  14. package/dist/gen-orchestrator/orchestrator.d.ts.map +1 -1
  15. package/dist/gen-orchestrator/orchestrator.js +19 -6
  16. package/dist/gen-orchestrator/orchestrator.js.map +1 -1
  17. package/dist/resolver-extractor/extractor/define-api-extractor.js +4 -4
  18. package/dist/resolver-extractor/extractor/define-api-extractor.js.map +1 -1
  19. package/dist/schema-generator/builder/ast-builder.d.ts +2 -2
  20. package/dist/schema-generator/builder/ast-builder.d.ts.map +1 -1
  21. package/dist/schema-generator/builder/ast-builder.js +12 -34
  22. package/dist/schema-generator/builder/ast-builder.js.map +1 -1
  23. package/dist/schema-generator/emitter/code-emitter.d.ts +3 -1
  24. package/dist/schema-generator/emitter/code-emitter.d.ts.map +1 -1
  25. package/dist/schema-generator/emitter/code-emitter.js +22 -12
  26. package/dist/schema-generator/emitter/code-emitter.js.map +1 -1
  27. package/dist/schema-generator/emitter/sdl-emitter.d.ts +0 -4
  28. package/dist/schema-generator/emitter/sdl-emitter.d.ts.map +1 -1
  29. package/dist/schema-generator/emitter/sdl-emitter.js +0 -4
  30. package/dist/schema-generator/emitter/sdl-emitter.js.map +1 -1
  31. package/dist/schema-generator/generate-schema.d.ts +2 -0
  32. package/dist/schema-generator/generate-schema.d.ts.map +1 -1
  33. package/dist/schema-generator/generate-schema.js +13 -4
  34. package/dist/schema-generator/generate-schema.js.map +1 -1
  35. package/dist/schema-generator/integrator/result-integrator.d.ts +10 -12
  36. package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -1
  37. package/dist/schema-generator/integrator/result-integrator.js +18 -55
  38. package/dist/schema-generator/integrator/result-integrator.js.map +1 -1
  39. package/dist/shared/branded-type-detector.d.ts +43 -0
  40. package/dist/shared/branded-type-detector.d.ts.map +1 -0
  41. package/dist/shared/branded-type-detector.js +146 -0
  42. package/dist/shared/branded-type-detector.js.map +1 -0
  43. package/dist/shared/string-utils.d.ts +2 -0
  44. package/dist/shared/string-utils.d.ts.map +1 -0
  45. package/dist/shared/string-utils.js +8 -0
  46. package/dist/shared/string-utils.js.map +1 -0
  47. package/dist/type-extractor/converter/field-eligibility.d.ts +8 -6
  48. package/dist/type-extractor/converter/field-eligibility.d.ts.map +1 -1
  49. package/dist/type-extractor/converter/field-eligibility.js +7 -28
  50. package/dist/type-extractor/converter/field-eligibility.js.map +1 -1
  51. package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -1
  52. package/dist/type-extractor/converter/graphql-converter.js +6 -11
  53. package/dist/type-extractor/converter/graphql-converter.js.map +1 -1
  54. package/dist/type-extractor/extractor/field-type-resolver.d.ts.map +1 -1
  55. package/dist/type-extractor/extractor/field-type-resolver.js +39 -4
  56. package/dist/type-extractor/extractor/field-type-resolver.js.map +1 -1
  57. package/dist/type-extractor/types/diagnostics.d.ts +1 -1
  58. package/dist/type-extractor/types/diagnostics.d.ts.map +1 -1
  59. package/dist/type-extractor/validator/type-validator.d.ts +1 -1
  60. package/dist/type-extractor/validator/type-validator.d.ts.map +1 -1
  61. package/dist/type-extractor/validator/type-validator.js +2 -10
  62. package/dist/type-extractor/validator/type-validator.js.map +1 -1
  63. package/docs/configuration.md +9 -0
  64. package/package.json +1 -1
  65. package/src/auto-type-generator/auto-type-generator.ts +23 -26
  66. package/src/config/types.ts +15 -0
  67. package/src/config-loader/loader.ts +4 -0
  68. package/src/config-loader/validator.ts +33 -0
  69. package/src/gen-orchestrator/orchestrator.ts +30 -11
  70. package/src/resolver-extractor/extractor/define-api-extractor.ts +5 -5
  71. package/src/schema-generator/builder/ast-builder.ts +52 -81
  72. package/src/schema-generator/emitter/code-emitter.ts +48 -11
  73. package/src/schema-generator/emitter/sdl-emitter.ts +0 -4
  74. package/src/schema-generator/generate-schema.ts +13 -15
  75. package/src/schema-generator/integrator/result-integrator.ts +37 -78
  76. package/src/shared/branded-type-detector.ts +182 -0
  77. package/src/shared/string-utils.ts +7 -0
  78. package/src/type-extractor/converter/field-eligibility.ts +13 -29
  79. package/src/type-extractor/converter/graphql-converter.ts +6 -16
  80. package/src/type-extractor/extractor/field-type-resolver.ts +49 -4
  81. package/src/type-extractor/types/diagnostics.ts +1 -0
  82. package/src/type-extractor/validator/type-validator.ts +2 -15
@@ -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 {
@@ -48,13 +48,13 @@ import type {
48
48
  } from "../integrator/result-integrator.js";
49
49
 
50
50
  export interface BuildDocumentOptions {
51
- readonly sourceRoot?: string;
51
+ readonly sourceRoot: string | null;
52
52
  }
53
53
 
54
54
  function appendSourceLocation(
55
55
  description: string | null,
56
56
  sourceFile: string | null,
57
- sourceRoot: string | undefined,
57
+ sourceRoot: string | null,
58
58
  ): string | null {
59
59
  if (!sourceRoot || !sourceFile) {
60
60
  return description;
@@ -113,7 +113,7 @@ function buildOneOfDirective(): ConstDirectiveNode {
113
113
 
114
114
  function buildDirectiveArgumentValue(
115
115
  value: DirectiveArgumentValue,
116
- expectedTypeName?: string,
116
+ expectedTypeName: string | null,
117
117
  ): ConstValueNode {
118
118
  switch (value.kind) {
119
119
  case "string":
@@ -159,7 +159,7 @@ function buildDirectiveArgumentValue(
159
159
  fields: value.fields.map((f) => ({
160
160
  kind: Kind.OBJECT_FIELD as const,
161
161
  name: buildNameNode(f.name),
162
- value: buildDirectiveArgumentValue(f.value),
162
+ value: buildDirectiveArgumentValue(f.value, null),
163
163
  })),
164
164
  };
165
165
  }
@@ -167,7 +167,7 @@ function buildDirectiveArgumentValue(
167
167
 
168
168
  function buildDirectiveArgument(
169
169
  arg: DirectiveArgument,
170
- expectedTypeName?: string,
170
+ expectedTypeName: string | null,
171
171
  ): ConstArgumentNode {
172
172
  return {
173
173
  kind: Kind.ARGUMENT,
@@ -178,7 +178,7 @@ function buildDirectiveArgument(
178
178
 
179
179
  function buildCustomDirective(
180
180
  directive: DirectiveInfo,
181
- directiveDefMap?: Map<string, DirectiveDefinitionInfo>,
181
+ directiveDefMap: Map<string, DirectiveDefinitionInfo> | null,
182
182
  ): ConstDirectiveNode {
183
183
  const def = directiveDefMap?.get(directive.name);
184
184
  const argTypeMap = new Map<string, string>();
@@ -189,7 +189,7 @@ function buildCustomDirective(
189
189
  }
190
190
 
191
191
  const args = directive.args.map((arg) =>
192
- buildDirectiveArgument(arg, argTypeMap.get(arg.name)),
192
+ buildDirectiveArgument(arg, argTypeMap.get(arg.name) ?? null),
193
193
  );
194
194
 
195
195
  return {
@@ -202,7 +202,7 @@ function buildCustomDirective(
202
202
  function buildDirectives(
203
203
  directives: ReadonlyArray<DirectiveInfo> | null,
204
204
  deprecated: DeprecationInfo | null,
205
- directiveDefMap?: Map<string, DirectiveDefinitionInfo>,
205
+ directiveDefMap: Map<string, DirectiveDefinitionInfo> | null,
206
206
  ): ConstDirectiveNode[] {
207
207
  const result: ConstDirectiveNode[] = [];
208
208
 
@@ -278,7 +278,12 @@ function buildInputValueDefinitionNode(
278
278
  ? { description: buildStringValueNode(inputValue.description) }
279
279
  : {}),
280
280
  ...(inputValue.defaultValue
281
- ? { defaultValue: buildDirectiveArgumentValue(inputValue.defaultValue) }
281
+ ? {
282
+ defaultValue: buildDirectiveArgumentValue(
283
+ inputValue.defaultValue,
284
+ null,
285
+ ),
286
+ }
282
287
  : {}),
283
288
  ...(directives.length > 0 ? { directives } : {}),
284
289
  };
@@ -290,7 +295,7 @@ function sortByName<T extends { name: string }>(items: ReadonlyArray<T>): T[] {
290
295
 
291
296
  function buildBaseFieldDefinitionNode(
292
297
  field: BaseField,
293
- directiveDefMap?: Map<string, DirectiveDefinitionInfo>,
298
+ directiveDefMap: Map<string, DirectiveDefinitionInfo> | null,
294
299
  ): FieldDefinitionNode {
295
300
  const directives = buildDirectives(
296
301
  field.directives,
@@ -311,8 +316,8 @@ function buildBaseFieldDefinitionNode(
311
316
 
312
317
  function buildFieldDefinitionNode(
313
318
  field: ExtensionField,
314
- sourceRoot?: string,
315
- directiveDefMap?: Map<string, DirectiveDefinitionInfo>,
319
+ sourceRoot: string | null,
320
+ directiveDefMap: Map<string, DirectiveDefinitionInfo> | null,
316
321
  ): FieldDefinitionNode {
317
322
  const directives = buildDirectives(
318
323
  field.directives,
@@ -338,11 +343,14 @@ function buildFieldDefinitionNode(
338
343
  };
339
344
  }
340
345
 
341
- function buildObjectTypeDefinitionNode(
346
+ function buildTypeDefinitionNode(
342
347
  baseType: BaseType,
343
- sourceRoot?: string,
344
- directiveDefMap?: Map<string, DirectiveDefinitionInfo>,
345
- ): ObjectTypeDefinitionNode {
348
+ kind:
349
+ | typeof Kind.OBJECT_TYPE_DEFINITION
350
+ | typeof Kind.INTERFACE_TYPE_DEFINITION,
351
+ sourceRoot: string | null,
352
+ directiveDefMap: Map<string, DirectiveDefinitionInfo> | null,
353
+ ): ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode {
346
354
  const sortedFields = baseType.fields ? sortByName(baseType.fields) : [];
347
355
  const directives = buildDirectives(
348
356
  baseType.directives,
@@ -364,7 +372,7 @@ function buildObjectTypeDefinitionNode(
364
372
  : undefined;
365
373
 
366
374
  return {
367
- kind: Kind.OBJECT_TYPE_DEFINITION,
375
+ kind,
368
376
  name: buildNameNode(baseType.name),
369
377
  fields: sortedFields.map((f) =>
370
378
  buildBaseFieldDefinitionNode(f, directiveDefMap),
@@ -372,49 +380,12 @@ function buildObjectTypeDefinitionNode(
372
380
  ...(description ? { description: buildStringValueNode(description) } : {}),
373
381
  ...(directives.length > 0 ? { directives } : {}),
374
382
  ...(interfaces ? { interfaces } : {}),
375
- };
376
- }
377
-
378
- function buildInterfaceTypeDefinitionNode(
379
- baseType: BaseType,
380
- sourceRoot?: string,
381
- directiveDefMap?: Map<string, DirectiveDefinitionInfo>,
382
- ): InterfaceTypeDefinitionNode {
383
- const sortedFields = baseType.fields ? sortByName(baseType.fields) : [];
384
- const directives = buildDirectives(
385
- baseType.directives,
386
- baseType.deprecated,
387
- directiveDefMap,
388
- );
389
-
390
- const description = appendSourceLocation(
391
- baseType.description,
392
- baseType.sourceFile,
393
- sourceRoot,
394
- );
395
-
396
- const interfaces =
397
- baseType.implementedInterfaces && baseType.implementedInterfaces.length > 0
398
- ? [...baseType.implementedInterfaces]
399
- .sort((a, b) => a.localeCompare(b))
400
- .map(buildNamedTypeNode)
401
- : undefined;
402
-
403
- return {
404
- kind: Kind.INTERFACE_TYPE_DEFINITION,
405
- name: buildNameNode(baseType.name),
406
- fields: sortedFields.map((f) =>
407
- buildBaseFieldDefinitionNode(f, directiveDefMap),
408
- ),
409
- ...(description ? { description: buildStringValueNode(description) } : {}),
410
- ...(directives.length > 0 ? { directives } : {}),
411
- ...(interfaces ? { interfaces } : {}),
412
- };
383
+ } as ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode;
413
384
  }
414
385
 
415
386
  function buildUnionTypeDefinitionNode(
416
387
  baseType: BaseType,
417
- sourceRoot?: string,
388
+ sourceRoot: string | null,
418
389
  ): UnionTypeDefinitionNode {
419
390
  const sortedMembers = baseType.unionMembers
420
391
  ? [...baseType.unionMembers].sort((a, b) => a.localeCompare(b))
@@ -454,7 +425,7 @@ function buildEnumValueDefinitionNode(
454
425
 
455
426
  function buildEnumTypeDefinitionNode(
456
427
  baseType: BaseType,
457
- sourceRoot?: string,
428
+ sourceRoot: string | null,
458
429
  ): EnumTypeDefinitionNode {
459
430
  const enumValues = baseType.enumValues ?? [];
460
431
 
@@ -474,7 +445,7 @@ function buildEnumTypeDefinitionNode(
474
445
 
475
446
  function buildScalarTypeDefinitionNode(
476
447
  name: string,
477
- description?: string,
448
+ description: string | null,
478
449
  ): ScalarTypeDefinitionNode {
479
450
  return {
480
451
  kind: Kind.SCALAR_TYPE_DEFINITION,
@@ -485,7 +456,7 @@ function buildScalarTypeDefinitionNode(
485
456
 
486
457
  function buildInputFieldDefinitionNode(
487
458
  field: BaseField,
488
- directiveDefMap?: Map<string, DirectiveDefinitionInfo>,
459
+ directiveDefMap: Map<string, DirectiveDefinitionInfo> | null,
489
460
  ): InputValueDefinitionNode {
490
461
  const directives = buildDirectives(
491
462
  field.directives,
@@ -501,7 +472,7 @@ function buildInputFieldDefinitionNode(
501
472
  ? { description: buildStringValueNode(field.description) }
502
473
  : {}),
503
474
  ...(field.defaultValue
504
- ? { defaultValue: buildDirectiveArgumentValue(field.defaultValue) }
475
+ ? { defaultValue: buildDirectiveArgumentValue(field.defaultValue, null) }
505
476
  : {}),
506
477
  ...(directives.length > 0 ? { directives } : {}),
507
478
  };
@@ -509,8 +480,8 @@ function buildInputFieldDefinitionNode(
509
480
 
510
481
  function buildInputObjectTypeDefinitionNode(
511
482
  inputType: InputType,
512
- sourceRoot?: string,
513
- directiveDefMap?: Map<string, DirectiveDefinitionInfo>,
483
+ sourceRoot: string | null,
484
+ directiveDefMap: Map<string, DirectiveDefinitionInfo> | null,
514
485
  ): InputObjectTypeDefinitionNode {
515
486
  const sortedFields = sortByName(inputType.fields);
516
487
 
@@ -538,8 +509,8 @@ function buildInputObjectTypeDefinitionNode(
538
509
 
539
510
  function buildObjectTypeExtensionNode(
540
511
  typeExtension: TypeExtension,
541
- sourceRoot?: string,
542
- directiveDefMap?: Map<string, DirectiveDefinitionInfo>,
512
+ sourceRoot: string | null,
513
+ directiveDefMap: Map<string, DirectiveDefinitionInfo> | null,
543
514
  ): ObjectTypeExtensionNode {
544
515
  const sortedFields = sortByName(typeExtension.fields);
545
516
  return {
@@ -553,8 +524,8 @@ function buildObjectTypeExtensionNode(
553
524
 
554
525
  function buildInterfaceTypeExtensionNode(
555
526
  typeExtension: TypeExtension,
556
- sourceRoot?: string,
557
- directiveDefMap?: Map<string, DirectiveDefinitionInfo>,
527
+ sourceRoot: string | null,
528
+ directiveDefMap: Map<string, DirectiveDefinitionInfo> | null,
558
529
  ): InterfaceTypeExtensionNode {
559
530
  const sortedFields = sortByName(typeExtension.fields);
560
531
  return {
@@ -600,9 +571,9 @@ function buildDirectiveDefinitionNode(
600
571
 
601
572
  export function buildDocumentNode(
602
573
  integratedResult: IntegratedResult,
603
- options?: BuildDocumentOptions,
574
+ options: BuildDocumentOptions,
604
575
  ): DocumentNode {
605
- const sourceRoot = options?.sourceRoot;
576
+ const sourceRoot = options.sourceRoot;
606
577
  const definitions: DefinitionNode[] = [];
607
578
 
608
579
  // Build directive definition map for argument type lookup
@@ -628,19 +599,9 @@ export function buildDocumentNode(
628
599
  );
629
600
  for (const scalar of sortedScalars) {
630
601
  definitions.push(
631
- buildScalarTypeDefinitionNode(
632
- scalar.scalarName,
633
- scalar.description ?? undefined,
634
- ),
602
+ buildScalarTypeDefinitionNode(scalar.scalarName, scalar.description),
635
603
  );
636
604
  }
637
- } else if (integratedResult.customScalarNames) {
638
- const sortedScalarNames = [...integratedResult.customScalarNames].sort(
639
- (a, b) => a.localeCompare(b),
640
- );
641
- for (const scalarName of sortedScalarNames) {
642
- definitions.push(buildScalarTypeDefinitionNode(scalarName));
643
- }
644
605
  }
645
606
 
646
607
  const sortedBaseTypes = [...integratedResult.baseTypes].sort((a, b) =>
@@ -650,11 +611,21 @@ export function buildDocumentNode(
650
611
  for (const baseType of sortedBaseTypes) {
651
612
  if (baseType.kind === "Interface") {
652
613
  definitions.push(
653
- buildInterfaceTypeDefinitionNode(baseType, sourceRoot, directiveDefMap),
614
+ buildTypeDefinitionNode(
615
+ baseType,
616
+ Kind.INTERFACE_TYPE_DEFINITION,
617
+ sourceRoot,
618
+ directiveDefMap,
619
+ ),
654
620
  );
655
621
  } else if (baseType.kind === "Object") {
656
622
  definitions.push(
657
- buildObjectTypeDefinitionNode(baseType, sourceRoot, directiveDefMap),
623
+ buildTypeDefinitionNode(
624
+ baseType,
625
+ Kind.OBJECT_TYPE_DEFINITION,
626
+ sourceRoot,
627
+ directiveDefMap,
628
+ ),
658
629
  );
659
630
  } else if (baseType.kind === "Union") {
660
631
  definitions.push(buildUnionTypeDefinitionNode(baseType, sourceRoot));
@@ -1,6 +1,7 @@
1
1
  import path from "node:path";
2
2
  import type { AutoGeneratedResolveType } from "../../auto-type-generator/resolve-type-generator.js";
3
3
  import { TYPENAME_FIELD_NAMES } from "../../auto-type-generator/typename-types.js";
4
+ import type { ImportExtension } from "../../config/types.js";
4
5
  import { toPosixPath } from "../../shared/index.js";
5
6
  import type { CollectedScalarType } from "../../type-extractor/collector/scalar-collector.js";
6
7
  import {
@@ -23,7 +24,7 @@ const GENERATED_FILE_HEADER =
23
24
 
24
25
  function formatDocumentNodeAsCode(
25
26
  integratedResult: IntegratedResult,
26
- options?: BuildDocumentOptions,
27
+ options: BuildDocumentOptions,
27
28
  ): string {
28
29
  const doc = buildDocumentNode(integratedResult, options);
29
30
 
@@ -32,7 +33,7 @@ function formatDocumentNodeAsCode(
32
33
 
33
34
  export function emitTypeDefsCode(
34
35
  integratedResult: IntegratedResult,
35
- options?: BuildDocumentOptions,
36
+ options: BuildDocumentOptions,
36
37
  ): string {
37
38
  const documentNodeCode = formatDocumentNodeAsCode(integratedResult, options);
38
39
 
@@ -44,13 +45,31 @@ export const typeDefs: DocumentNode = ${documentNodeCode} as DocumentNode;
44
45
  `;
45
46
  }
46
47
 
47
- function computeRelativeImportPath(fromDir: string, toFile: string): string {
48
+ function applyExtension(
49
+ relativePath: string,
50
+ importExtension: ImportExtension,
51
+ ): string {
52
+ switch (importExtension) {
53
+ case "js":
54
+ return relativePath.replace(/\.ts$/, ".js");
55
+ case "ts":
56
+ return relativePath;
57
+ case "none":
58
+ return relativePath.replace(/\.ts$/, "");
59
+ }
60
+ }
61
+
62
+ function computeRelativeImportPath(
63
+ fromDir: string,
64
+ toFile: string,
65
+ importExtension: ImportExtension,
66
+ ): string {
48
67
  const relativePath = toPosixPath(path.relative(fromDir, toFile));
49
- const withoutExt = relativePath.replace(/\.ts$/, ".js");
50
- if (!withoutExt.startsWith(".")) {
51
- return `./${withoutExt}`;
68
+ const withExt = applyExtension(relativePath, importExtension);
69
+ if (!withExt.startsWith(".")) {
70
+ return `./${withExt}`;
52
71
  }
53
- return withoutExt;
72
+ return withExt;
54
73
  }
55
74
 
56
75
  interface ScalarTypeImport {
@@ -94,6 +113,7 @@ function collectScalarTypeImports(
94
113
  function buildScalarTypeImports(
95
114
  scalarTypeImports: ScalarTypeImport[],
96
115
  outputDir: string,
116
+ importExtension: ImportExtension,
97
117
  ): string[] {
98
118
  const importsByFile = new Map<string, string[]>();
99
119
 
@@ -108,7 +128,11 @@ function buildScalarTypeImports(
108
128
 
109
129
  for (const sourceFile of sortedFiles) {
110
130
  const typeNames = importsByFile.get(sourceFile) ?? [];
111
- const importPath = computeRelativeImportPath(outputDir, sourceFile);
131
+ const importPath = computeRelativeImportPath(
132
+ outputDir,
133
+ sourceFile,
134
+ importExtension,
135
+ );
112
136
  imports.push(
113
137
  `import type { ${typeNames.sort().join(", ")} } from "${importPath}";`,
114
138
  );
@@ -172,13 +196,18 @@ function collectResolverImportsByFile(
172
196
  function buildResolverImports(
173
197
  importsByFile: Map<string, Set<string>>,
174
198
  outputDir: string,
199
+ importExtension: ImportExtension,
175
200
  ): string[] {
176
201
  const imports: string[] = [];
177
202
  const sortedFiles = [...importsByFile.keys()].sort();
178
203
 
179
204
  for (const sourceFile of sortedFiles) {
180
205
  const valueNames = importsByFile.get(sourceFile) ?? new Set<string>();
181
- const importPath = computeRelativeImportPath(outputDir, sourceFile);
206
+ const importPath = computeRelativeImportPath(
207
+ outputDir,
208
+ sourceFile,
209
+ importExtension,
210
+ );
182
211
  const sortedValues = [...valueNames].sort();
183
212
 
184
213
  if (sortedValues.length > 0) {
@@ -331,6 +360,7 @@ interface EmitResolversCodeParams {
331
360
  readonly customScalars: ReadonlyArray<CollectedScalarType>;
332
361
  readonly numericEnums: ReadonlyArray<NumericEnumInfo>;
333
362
  readonly stringEnumMappings: ReadonlyArray<StringEnumMappingInfo>;
363
+ readonly importExtension: ImportExtension;
334
364
  }
335
365
 
336
366
  export function emitResolversCode(params: EmitResolversCodeParams): string {
@@ -340,6 +370,7 @@ export function emitResolversCode(params: EmitResolversCodeParams): string {
340
370
  customScalars,
341
371
  numericEnums,
342
372
  stringEnumMappings,
373
+ importExtension,
343
374
  } = params;
344
375
  const hasCustomScalars = customScalars.length > 0;
345
376
  const imports: string[] = [];
@@ -349,11 +380,17 @@ export function emitResolversCode(params: EmitResolversCodeParams): string {
349
380
  }
350
381
 
351
382
  const importsByFile = collectResolverImportsByFile(resolverInfo);
352
- imports.push(...buildResolverImports(importsByFile, outputDir));
383
+ imports.push(
384
+ ...buildResolverImports(importsByFile, outputDir, importExtension),
385
+ );
353
386
 
354
387
  if (hasCustomScalars) {
355
388
  const scalarTypeImports = collectScalarTypeImports(customScalars);
356
- const scalarImports = buildScalarTypeImports(scalarTypeImports, outputDir);
389
+ const scalarImports = buildScalarTypeImports(
390
+ scalarTypeImports,
391
+ outputDir,
392
+ importExtension,
393
+ );
357
394
  imports.push(...scalarImports);
358
395
  }
359
396
 
@@ -3,10 +3,6 @@ import { type DocumentNode, print } from "graphql";
3
3
  const GENERATED_FILE_HEADER =
4
4
  "# This file is auto-generated by gqlkit. DO NOT EDIT.";
5
5
 
6
- /**
7
- * DocumentNode を SDL 形式の文字列に変換する。
8
- * graphql パッケージの print() 関数を使用して SDL を生成する。
9
- */
10
6
  export function emitSdlContent(documentNode: DocumentNode): string {
11
7
  const sdl = print(documentNode);
12
8
  return `${GENERATED_FILE_HEADER}\n\n${sdl}`;