@gqlkit-ts/cli 0.6.0 → 0.7.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/auto-type-generator/auto-type-generator.d.ts +7 -0
- package/dist/auto-type-generator/auto-type-generator.d.ts.map +1 -1
- package/dist/auto-type-generator/auto-type-generator.js +375 -55
- package/dist/auto-type-generator/auto-type-generator.js.map +1 -1
- package/dist/auto-type-generator/discriminator-field-validator.d.ts +26 -0
- package/dist/auto-type-generator/discriminator-field-validator.d.ts.map +1 -0
- package/dist/auto-type-generator/discriminator-field-validator.js +242 -0
- package/dist/auto-type-generator/discriminator-field-validator.js.map +1 -0
- package/dist/auto-type-generator/discriminator-naming.d.ts +11 -0
- package/dist/auto-type-generator/discriminator-naming.d.ts.map +1 -0
- package/dist/auto-type-generator/discriminator-naming.js +15 -0
- package/dist/auto-type-generator/discriminator-naming.js.map +1 -0
- package/dist/auto-type-generator/discriminator-resolve-type-generator.d.ts +44 -0
- package/dist/auto-type-generator/discriminator-resolve-type-generator.d.ts.map +1 -0
- package/dist/auto-type-generator/discriminator-resolve-type-generator.js +77 -0
- package/dist/auto-type-generator/discriminator-resolve-type-generator.js.map +1 -0
- package/dist/auto-type-generator/index.d.ts +3 -0
- package/dist/auto-type-generator/index.d.ts.map +1 -1
- package/dist/auto-type-generator/index.js +3 -0
- package/dist/auto-type-generator/index.js.map +1 -1
- package/dist/auto-type-generator/inline-enum-collector.d.ts.map +1 -1
- package/dist/auto-type-generator/inline-enum-collector.js +14 -7
- package/dist/auto-type-generator/inline-enum-collector.js.map +1 -1
- package/dist/auto-type-generator/inline-object-converter.d.ts +12 -0
- package/dist/auto-type-generator/inline-object-converter.d.ts.map +1 -0
- package/dist/auto-type-generator/inline-object-converter.js +72 -0
- package/dist/auto-type-generator/inline-object-converter.js.map +1 -0
- package/dist/auto-type-generator/inline-object-traverser.d.ts +2 -1
- package/dist/auto-type-generator/inline-object-traverser.d.ts.map +1 -1
- package/dist/auto-type-generator/inline-object-traverser.js +22 -4
- package/dist/auto-type-generator/inline-object-traverser.js.map +1 -1
- package/dist/auto-type-generator/inline-union-collector.d.ts.map +1 -1
- package/dist/auto-type-generator/inline-union-collector.js +20 -6
- package/dist/auto-type-generator/inline-union-collector.js.map +1 -1
- package/dist/auto-type-generator/inline-union-types.d.ts +2 -0
- package/dist/auto-type-generator/inline-union-types.d.ts.map +1 -1
- package/dist/auto-type-generator/inline-union-validator.js +3 -3
- package/dist/auto-type-generator/inline-union-validator.js.map +1 -1
- package/dist/auto-type-generator/intersection-flattener.d.ts +44 -0
- package/dist/auto-type-generator/intersection-flattener.d.ts.map +1 -0
- package/dist/auto-type-generator/intersection-flattener.js +398 -0
- package/dist/auto-type-generator/intersection-flattener.js.map +1 -0
- package/dist/auto-type-generator/naming-convention.d.ts +21 -0
- package/dist/auto-type-generator/naming-convention.d.ts.map +1 -1
- package/dist/auto-type-generator/naming-convention.js +145 -1
- package/dist/auto-type-generator/naming-convention.js.map +1 -1
- package/dist/auto-type-generator/typename-extractor.d.ts +2 -0
- package/dist/auto-type-generator/typename-extractor.d.ts.map +1 -1
- package/dist/auto-type-generator/typename-extractor.js +11 -3
- package/dist/auto-type-generator/typename-extractor.js.map +1 -1
- package/dist/auto-type-generator/typename-resolve-type-generator.d.ts +2 -0
- package/dist/auto-type-generator/typename-resolve-type-generator.d.ts.map +1 -1
- package/dist/auto-type-generator/typename-resolve-type-generator.js +12 -84
- package/dist/auto-type-generator/typename-resolve-type-generator.js.map +1 -1
- package/dist/auto-type-generator/typename-types.d.ts +4 -0
- package/dist/auto-type-generator/typename-types.d.ts.map +1 -1
- package/dist/auto-type-generator/typename-types.js +6 -0
- package/dist/auto-type-generator/typename-types.js.map +1 -1
- package/dist/auto-type-generator/typename-validator.d.ts.map +1 -1
- package/dist/auto-type-generator/typename-validator.js +4 -3
- package/dist/auto-type-generator/typename-validator.js.map +1 -1
- package/dist/commands/gen.d.ts.map +1 -1
- package/dist/commands/gen.js +2 -1
- package/dist/commands/gen.js.map +1 -1
- package/dist/config/types.d.ts +7 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config-loader/index.d.ts +1 -1
- package/dist/config-loader/index.d.ts.map +1 -1
- package/dist/config-loader/index.js.map +1 -1
- package/dist/config-loader/loader.d.ts +6 -0
- package/dist/config-loader/loader.d.ts.map +1 -1
- package/dist/config-loader/loader.js +1 -0
- package/dist/config-loader/loader.js.map +1 -1
- package/dist/config-loader/validator.d.ts.map +1 -1
- package/dist/config-loader/validator.js +84 -1
- package/dist/config-loader/validator.js.map +1 -1
- package/dist/gen-orchestrator/orchestrator.d.ts +2 -1
- package/dist/gen-orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/gen-orchestrator/orchestrator.js +15 -2
- package/dist/gen-orchestrator/orchestrator.js.map +1 -1
- package/dist/resolver-extractor/extractor/define-api-extractor.d.ts.map +1 -1
- package/dist/resolver-extractor/extractor/define-api-extractor.js +4 -0
- package/dist/resolver-extractor/extractor/define-api-extractor.js.map +1 -1
- package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts +2 -0
- package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts.map +1 -1
- package/dist/resolver-extractor/validator/abstract-resolver-validator.js +16 -3
- package/dist/resolver-extractor/validator/abstract-resolver-validator.js.map +1 -1
- package/dist/schema-generator/emitter/code-emitter.d.ts.map +1 -1
- package/dist/schema-generator/emitter/code-emitter.js +13 -1
- package/dist/schema-generator/emitter/code-emitter.js.map +1 -1
- package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.d.ts +18 -0
- package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.d.ts.map +1 -0
- package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.js +89 -0
- package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.js.map +1 -0
- package/dist/schema-generator/generate-schema.d.ts +2 -0
- package/dist/schema-generator/generate-schema.d.ts.map +1 -1
- package/dist/schema-generator/generate-schema.js +69 -10
- package/dist/schema-generator/generate-schema.js.map +1 -1
- package/dist/schema-generator/integrator/result-integrator.d.ts +4 -0
- package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -1
- package/dist/schema-generator/integrator/result-integrator.js +18 -2
- package/dist/schema-generator/integrator/result-integrator.js.map +1 -1
- package/dist/schema-generator/resolver-collector/resolver-collector.d.ts +2 -0
- package/dist/schema-generator/resolver-collector/resolver-collector.d.ts.map +1 -1
- package/dist/schema-generator/resolver-collector/resolver-collector.js +4 -0
- package/dist/schema-generator/resolver-collector/resolver-collector.js.map +1 -1
- package/dist/shared/constants.d.ts.map +1 -1
- package/dist/shared/constants.js +14 -1
- package/dist/shared/constants.js.map +1 -1
- package/dist/shared/enum-prefix-detector.d.ts.map +1 -1
- package/dist/shared/enum-prefix-detector.js +78 -8
- package/dist/shared/enum-prefix-detector.js.map +1 -1
- package/dist/shared/inline-object-utils.js +1 -1
- package/dist/shared/inline-object-utils.js.map +1 -1
- package/dist/shared/type-converter.d.ts.map +1 -1
- package/dist/shared/type-converter.js +55 -0
- package/dist/shared/type-converter.js.map +1 -1
- package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -1
- package/dist/type-extractor/converter/graphql-converter.js +11 -1
- package/dist/type-extractor/converter/graphql-converter.js.map +1 -1
- package/dist/type-extractor/extractor/field-type-resolver.d.ts +18 -0
- package/dist/type-extractor/extractor/field-type-resolver.d.ts.map +1 -1
- package/dist/type-extractor/extractor/field-type-resolver.js +218 -16
- package/dist/type-extractor/extractor/field-type-resolver.js.map +1 -1
- package/dist/type-extractor/extractor/type-extractor.d.ts +1 -0
- package/dist/type-extractor/extractor/type-extractor.d.ts.map +1 -1
- package/dist/type-extractor/extractor/type-extractor.js +127 -14
- package/dist/type-extractor/extractor/type-extractor.js.map +1 -1
- package/dist/type-extractor/extractor/type-name-collector.d.ts.map +1 -1
- package/dist/type-extractor/extractor/type-name-collector.js +19 -4
- package/dist/type-extractor/extractor/type-name-collector.js.map +1 -1
- package/dist/type-extractor/types/diagnostics.d.ts +1 -1
- package/dist/type-extractor/types/diagnostics.d.ts.map +1 -1
- package/dist/type-extractor/types/index.d.ts +1 -1
- package/dist/type-extractor/types/index.d.ts.map +1 -1
- package/dist/type-extractor/types/index.js +1 -1
- package/dist/type-extractor/types/index.js.map +1 -1
- package/dist/type-extractor/types/ts-type-reference-factory.d.ts +7 -1
- package/dist/type-extractor/types/ts-type-reference-factory.d.ts.map +1 -1
- package/dist/type-extractor/types/ts-type-reference-factory.js +18 -3
- package/dist/type-extractor/types/ts-type-reference-factory.js.map +1 -1
- package/dist/type-extractor/types/typescript.d.ts +3 -1
- package/dist/type-extractor/types/typescript.d.ts.map +1 -1
- package/dist/type-extractor/validator/type-validator.d.ts.map +1 -1
- package/dist/type-extractor/validator/type-validator.js +6 -1
- package/dist/type-extractor/validator/type-validator.js.map +1 -1
- package/docs/configuration.md +19 -0
- package/docs/index.md +1 -0
- package/docs/integration/ai-sdk.md +189 -0
- package/docs/schema/unions.md +117 -0
- package/package.json +2 -2
- package/src/auto-type-generator/auto-type-generator.ts +576 -58
- package/src/auto-type-generator/discriminator-field-validator.ts +368 -0
- package/src/auto-type-generator/discriminator-naming.ts +24 -0
- package/src/auto-type-generator/discriminator-resolve-type-generator.ts +136 -0
- package/src/auto-type-generator/index.ts +17 -0
- package/src/auto-type-generator/inline-enum-collector.ts +19 -4
- package/src/auto-type-generator/inline-object-converter.ts +100 -0
- package/src/auto-type-generator/inline-object-traverser.ts +33 -7
- package/src/auto-type-generator/inline-union-collector.ts +26 -4
- package/src/auto-type-generator/inline-union-types.ts +2 -0
- package/src/auto-type-generator/inline-union-validator.ts +3 -3
- package/src/auto-type-generator/intersection-flattener.ts +554 -0
- package/src/auto-type-generator/naming-convention.ts +205 -1
- package/src/auto-type-generator/typename-extractor.ts +17 -3
- package/src/auto-type-generator/typename-resolve-type-generator.ts +19 -108
- package/src/auto-type-generator/typename-types.ts +7 -0
- package/src/auto-type-generator/typename-validator.ts +4 -3
- package/src/commands/gen.ts +9 -2
- package/src/config/types.ts +10 -0
- package/src/config-loader/index.ts +1 -0
- package/src/config-loader/loader.ts +11 -0
- package/src/config-loader/validator.ts +100 -1
- package/src/gen-orchestrator/orchestrator.ts +19 -2
- package/src/resolver-extractor/extractor/define-api-extractor.ts +4 -0
- package/src/resolver-extractor/validator/abstract-resolver-validator.ts +20 -6
- package/src/schema-generator/emitter/code-emitter.ts +26 -1
- package/src/schema-generator/emitter/discriminator-resolve-type-emitter.ts +125 -0
- package/src/schema-generator/generate-schema.ts +100 -13
- package/src/schema-generator/integrator/result-integrator.ts +25 -1
- package/src/schema-generator/resolver-collector/resolver-collector.ts +7 -0
- package/src/shared/constants.ts +15 -1
- package/src/shared/enum-prefix-detector.ts +96 -8
- package/src/shared/inline-object-utils.ts +1 -1
- package/src/shared/type-converter.ts +63 -0
- package/src/type-extractor/converter/graphql-converter.ts +17 -1
- package/src/type-extractor/extractor/field-type-resolver.ts +266 -16
- package/src/type-extractor/extractor/type-extractor.ts +148 -11
- package/src/type-extractor/extractor/type-name-collector.ts +19 -4
- package/src/type-extractor/types/diagnostics.ts +10 -1
- package/src/type-extractor/types/index.ts +2 -1
- package/src/type-extractor/types/ts-type-reference-factory.ts +24 -3
- package/src/type-extractor/types/typescript.ts +6 -2
- package/src/type-extractor/validator/type-validator.ts +6 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { dirname, relative, resolve } from "node:path";
|
|
2
2
|
import type ts from "typescript";
|
|
3
3
|
import type {
|
|
4
|
+
ResolvedDiscriminatorFieldsMap,
|
|
4
5
|
ResolvedOutputConfig,
|
|
5
6
|
ResolvedScalarMapping,
|
|
6
7
|
} from "../config-loader/index.js";
|
|
@@ -61,6 +62,7 @@ export interface GenerationConfig {
|
|
|
61
62
|
readonly configDir: string | null;
|
|
62
63
|
readonly customScalars: ReadonlyArray<ResolvedScalarMapping> | null;
|
|
63
64
|
readonly tsconfigPath: string | null;
|
|
65
|
+
readonly discriminatorFields: ResolvedDiscriminatorFieldsMap;
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
export interface GeneratedFile {
|
|
@@ -82,6 +84,7 @@ interface TypesResult {
|
|
|
82
84
|
detectedScalars: ReadonlyArray<ScalarMetadataInfo>;
|
|
83
85
|
collectedScalars: ReadonlyArray<CollectedScalarType>;
|
|
84
86
|
scalarMappingTable: ScalarBaseTypeMappingTable | null;
|
|
87
|
+
discoveredTypeNames: ReadonlySet<string>;
|
|
85
88
|
}
|
|
86
89
|
|
|
87
90
|
interface ResolversResult {
|
|
@@ -251,6 +254,7 @@ function extractTypesCore(params: ExtractTypesCoreParams): TypesResult {
|
|
|
251
254
|
detectedScalars: extractionResult.detectedScalars,
|
|
252
255
|
collectedScalars,
|
|
253
256
|
scalarMappingTable,
|
|
257
|
+
discoveredTypeNames: extractionResult.discoveredTypeNames,
|
|
254
258
|
};
|
|
255
259
|
}
|
|
256
260
|
|
|
@@ -632,6 +636,18 @@ function extractTypesStep(ctx: PipelineContext): PipelineContext {
|
|
|
632
636
|
return { ...ctx, typesResult };
|
|
633
637
|
}
|
|
634
638
|
|
|
639
|
+
function augmentKnownTypeNamesStep(ctx: PipelineContext): PipelineContext {
|
|
640
|
+
if (ctx.aborted || !ctx.typesResult || !ctx.knownTypeNames) return ctx;
|
|
641
|
+
|
|
642
|
+
if (ctx.typesResult.discoveredTypeNames.size === 0) return ctx;
|
|
643
|
+
|
|
644
|
+
const augmented = new Set(ctx.knownTypeNames);
|
|
645
|
+
for (const name of ctx.typesResult.discoveredTypeNames) {
|
|
646
|
+
augmented.add(name);
|
|
647
|
+
}
|
|
648
|
+
return { ...ctx, knownTypeNames: augmented };
|
|
649
|
+
}
|
|
650
|
+
|
|
635
651
|
function extractResolversStep(ctx: PipelineContext): PipelineContext {
|
|
636
652
|
if (
|
|
637
653
|
ctx.aborted ||
|
|
@@ -723,8 +739,7 @@ function generateSchemaStep(ctx: PipelineContext): {
|
|
|
723
739
|
|
|
724
740
|
const { customScalarNames } = ctx.scalarConfig;
|
|
725
741
|
const allCustomScalarNames = [
|
|
726
|
-
...customScalarNames,
|
|
727
|
-
...ctx.typesResult.detectedScalarNames,
|
|
742
|
+
...new Set([...customScalarNames, ...ctx.typesResult.detectedScalarNames]),
|
|
728
743
|
];
|
|
729
744
|
|
|
730
745
|
const schemaResult = generateSchema({
|
|
@@ -742,6 +757,7 @@ function generateSchemaStep(ctx: PipelineContext): {
|
|
|
742
757
|
sourceRoot: ctx.config.cwd,
|
|
743
758
|
knownTypeNames: ctx.knownTypeNames,
|
|
744
759
|
importExtension: ctx.config.output.importExtension,
|
|
760
|
+
discriminatorFields: ctx.config.discriminatorFields,
|
|
745
761
|
});
|
|
746
762
|
|
|
747
763
|
const newDiagnostics = [...ctx.diagnostics, ...schemaResult.diagnostics];
|
|
@@ -796,6 +812,7 @@ export async function executeGeneration(
|
|
|
796
812
|
ctx = collectTypeNamesStep(ctx);
|
|
797
813
|
ctx = prepareScalarConfigStep(ctx);
|
|
798
814
|
ctx = extractTypesStep(ctx);
|
|
815
|
+
ctx = augmentKnownTypeNamesStep(ctx);
|
|
799
816
|
ctx = extractResolversStep(ctx);
|
|
800
817
|
ctx = extractDirectivesStep(ctx);
|
|
801
818
|
ctx = validateExtractionStep(ctx);
|
|
@@ -620,6 +620,8 @@ export function extractDefineApiResolvers(
|
|
|
620
620
|
sourceFiles,
|
|
621
621
|
scalarMappingTable,
|
|
622
622
|
scalarMappingContext: "input",
|
|
623
|
+
discoveredTypes: null,
|
|
624
|
+
diagnostics: [],
|
|
623
625
|
};
|
|
624
626
|
const outputContext: FieldTypeResolverContext = {
|
|
625
627
|
checker,
|
|
@@ -630,6 +632,8 @@ export function extractDefineApiResolvers(
|
|
|
630
632
|
sourceFiles,
|
|
631
633
|
scalarMappingTable,
|
|
632
634
|
scalarMappingContext: "output",
|
|
635
|
+
discoveredTypes: null,
|
|
636
|
+
diagnostics: [],
|
|
633
637
|
};
|
|
634
638
|
|
|
635
639
|
for (const filePath of files) {
|
|
@@ -17,6 +17,8 @@ export interface ValidateAbstractResolversOptions {
|
|
|
17
17
|
readonly abstractResolvers: ReadonlyArray<AbstractResolverInfo>;
|
|
18
18
|
readonly baseTypes: ReadonlyArray<BaseType>;
|
|
19
19
|
readonly typenameAutoResolveTypeNames?: ReadonlySet<string>;
|
|
20
|
+
/** Mapping from TypeScript type alias names to auto-generated GraphQL union names */
|
|
21
|
+
readonly tsAliasToGraphQLNameMap: ReadonlyMap<string, string>;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
export interface ValidateAbstractResolversResult {
|
|
@@ -207,7 +209,22 @@ export function validateAbstractResolvers(
|
|
|
207
209
|
typeMap.set(baseType.name, baseType);
|
|
208
210
|
}
|
|
209
211
|
|
|
210
|
-
|
|
212
|
+
// Remap resolver target type names using TS alias → GraphQL name mapping
|
|
213
|
+
// e.g., defineResolveType<ItemPart> where ItemPart is a TS alias
|
|
214
|
+
// maps to the auto-generated union name "ContainerItems"
|
|
215
|
+
// Only remap resolveType resolvers — isTypeOf targets object types, not unions
|
|
216
|
+
const resolvers = options.abstractResolvers.map((resolver) => {
|
|
217
|
+
if (resolver.kind !== "resolveType") return resolver;
|
|
218
|
+
const mappedName = options.tsAliasToGraphQLNameMap.get(
|
|
219
|
+
resolver.targetTypeName,
|
|
220
|
+
);
|
|
221
|
+
if (mappedName !== undefined) {
|
|
222
|
+
return { ...resolver, targetTypeName: mappedName };
|
|
223
|
+
}
|
|
224
|
+
return resolver;
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
for (const resolver of resolvers) {
|
|
211
228
|
const targetType = typeMap.get(resolver.targetTypeName);
|
|
212
229
|
|
|
213
230
|
if (!targetType) {
|
|
@@ -241,14 +258,11 @@ export function validateAbstractResolvers(
|
|
|
241
258
|
}
|
|
242
259
|
}
|
|
243
260
|
|
|
244
|
-
const duplicateDiagnostics = detectDuplicateResolvers(
|
|
245
|
-
options.abstractResolvers,
|
|
246
|
-
typeMap,
|
|
247
|
-
);
|
|
261
|
+
const duplicateDiagnostics = detectDuplicateResolvers(resolvers, typeMap);
|
|
248
262
|
diagnostics.push(...duplicateDiagnostics);
|
|
249
263
|
|
|
250
264
|
const missingResolverWarnings = detectMissingAbstractTypeResolvers({
|
|
251
|
-
resolvers
|
|
265
|
+
resolvers,
|
|
252
266
|
typeMap,
|
|
253
267
|
typenameAutoResolveTypeNames:
|
|
254
268
|
options.typenameAutoResolveTypeNames ?? new Set(),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import type { DiscriminatorResolveTypeInfo } from "../../auto-type-generator/discriminator-resolve-type-generator.js";
|
|
2
3
|
import type { AutoGeneratedResolveType } from "../../auto-type-generator/resolve-type-generator.js";
|
|
3
4
|
import { TYPENAME_FIELD_NAMES } from "../../auto-type-generator/typename-types.js";
|
|
4
5
|
import type { ImportExtension } from "../../config/types.js";
|
|
@@ -19,6 +20,7 @@ import type {
|
|
|
19
20
|
ResolverInfo,
|
|
20
21
|
TypeResolvers,
|
|
21
22
|
} from "../resolver-collector/resolver-collector.js";
|
|
23
|
+
import { buildDiscriminatorResolveTypeEntry } from "./discriminator-resolve-type-emitter.js";
|
|
22
24
|
|
|
23
25
|
const GENERATED_FILE_HEADER =
|
|
24
26
|
"// This file is auto-generated by gqlkit. DO NOT EDIT.";
|
|
@@ -374,11 +376,22 @@ function getResolveTypeExpression(
|
|
|
374
376
|
return expressions.join(" ?? ");
|
|
375
377
|
}
|
|
376
378
|
|
|
379
|
+
function buildResolveTypeObjType(
|
|
380
|
+
fieldPattern: AutoGeneratedResolveType["fieldPattern"],
|
|
381
|
+
): string {
|
|
382
|
+
const fields = TYPENAME_FIELD_NAMES.filter((name) =>
|
|
383
|
+
fieldPattern.usedFieldNames.has(name),
|
|
384
|
+
).map((name) => `${name}: string`);
|
|
385
|
+
|
|
386
|
+
return `{ ${fields.join("; ")} }`;
|
|
387
|
+
}
|
|
388
|
+
|
|
377
389
|
function buildAutoResolveTypeEntry(
|
|
378
390
|
autoResolveType: AutoGeneratedResolveType,
|
|
379
391
|
): string {
|
|
380
392
|
const expression = getResolveTypeExpression(autoResolveType.fieldPattern);
|
|
381
|
-
|
|
393
|
+
const objType = buildResolveTypeObjType(autoResolveType.fieldPattern);
|
|
394
|
+
return ` ${autoResolveType.unionTypeName}: {\n __resolveType: (obj: ${objType}) => ${expression},\n },`;
|
|
382
395
|
}
|
|
383
396
|
|
|
384
397
|
function buildTypeEntries(
|
|
@@ -406,10 +419,16 @@ function buildTypeEntries(
|
|
|
406
419
|
resolverInfo.autoGeneratedResolveTypes.map((r) => [r.unionTypeName, r]),
|
|
407
420
|
);
|
|
408
421
|
|
|
422
|
+
const discriminatorResolveTypeByUnion = new Map<
|
|
423
|
+
string,
|
|
424
|
+
DiscriminatorResolveTypeInfo
|
|
425
|
+
>(resolverInfo.discriminatorResolveTypes.map((r) => [r.unionTypeName, r]));
|
|
426
|
+
|
|
409
427
|
const allTypeNames = new Set<string>([
|
|
410
428
|
...typesWithFields.keys(),
|
|
411
429
|
...abstractResolversByType.keys(),
|
|
412
430
|
...autoResolveTypeByUnion.keys(),
|
|
431
|
+
...discriminatorResolveTypeByUnion.keys(),
|
|
413
432
|
]);
|
|
414
433
|
const sortedTypeNames = [...allTypeNames].sort();
|
|
415
434
|
|
|
@@ -417,6 +436,8 @@ function buildTypeEntries(
|
|
|
417
436
|
const typeWithFields = typesWithFields.get(typeName);
|
|
418
437
|
const abstractResolver = abstractResolversByType.get(typeName) ?? null;
|
|
419
438
|
const autoResolveType = autoResolveTypeByUnion.get(typeName);
|
|
439
|
+
const discriminatorResolveType =
|
|
440
|
+
discriminatorResolveTypeByUnion.get(typeName);
|
|
420
441
|
|
|
421
442
|
if (typeWithFields !== undefined) {
|
|
422
443
|
typeEntries.push(
|
|
@@ -424,6 +445,10 @@ function buildTypeEntries(
|
|
|
424
445
|
);
|
|
425
446
|
} else if (abstractResolver !== null) {
|
|
426
447
|
typeEntries.push(buildAbstractOnlyTypeEntry(abstractResolver));
|
|
448
|
+
} else if (discriminatorResolveType !== undefined) {
|
|
449
|
+
typeEntries.push(
|
|
450
|
+
buildDiscriminatorResolveTypeEntry(discriminatorResolveType),
|
|
451
|
+
);
|
|
427
452
|
} else if (autoResolveType !== undefined) {
|
|
428
453
|
typeEntries.push(buildAutoResolveTypeEntry(autoResolveType));
|
|
429
454
|
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DiscriminatorResolveTypeInfo,
|
|
3
|
+
DiscriminatorValueMapping,
|
|
4
|
+
} from "../../auto-type-generator/discriminator-resolve-type-generator.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Groups value mappings by their value at a given field index.
|
|
8
|
+
* Null values at the field index mean the member doesn't have that field,
|
|
9
|
+
* so the member should be resolved directly at the current switch level.
|
|
10
|
+
*/
|
|
11
|
+
function groupMappingsByFieldValue(
|
|
12
|
+
mappings: ReadonlyArray<DiscriminatorValueMapping>,
|
|
13
|
+
fieldIndex: number,
|
|
14
|
+
): Map<string | null, DiscriminatorValueMapping[]> {
|
|
15
|
+
const groups = new Map<string | null, DiscriminatorValueMapping[]>();
|
|
16
|
+
for (const mapping of mappings) {
|
|
17
|
+
const value = mapping.values[fieldIndex] ?? null;
|
|
18
|
+
const group = groups.get(value) ?? [];
|
|
19
|
+
group.push(mapping);
|
|
20
|
+
groups.set(value, group);
|
|
21
|
+
}
|
|
22
|
+
return groups;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Builds a switch statement body for a given field level, recursing for nested fields.
|
|
27
|
+
* Returns an array of code lines (without leading indentation for the switch itself).
|
|
28
|
+
*/
|
|
29
|
+
function buildSwitchBody(
|
|
30
|
+
mappings: ReadonlyArray<DiscriminatorValueMapping>,
|
|
31
|
+
fieldNames: ReadonlyArray<string>,
|
|
32
|
+
fieldIndex: number,
|
|
33
|
+
indent: string,
|
|
34
|
+
): string[] {
|
|
35
|
+
const fieldName = fieldNames[fieldIndex]!;
|
|
36
|
+
const groups = groupMappingsByFieldValue(mappings, fieldIndex);
|
|
37
|
+
const lines: string[] = [];
|
|
38
|
+
|
|
39
|
+
lines.push(`${indent}switch (obj.${fieldName}) {`);
|
|
40
|
+
|
|
41
|
+
for (const [value, groupMappings] of groups) {
|
|
42
|
+
// Null value means the member doesn't have this field — resolved at the parent level
|
|
43
|
+
if (value === null) {
|
|
44
|
+
for (const mapping of groupMappings) {
|
|
45
|
+
lines.push(
|
|
46
|
+
`${indent} case "${mapping.values[fieldIndex - 1]!}": return "${mapping.memberGraphQLTypeName}";`,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const nextFieldIndex = fieldIndex + 1;
|
|
53
|
+
const hasMoreFields = nextFieldIndex < fieldNames.length;
|
|
54
|
+
|
|
55
|
+
// Check if all mappings in this group can be resolved directly
|
|
56
|
+
// (either no more fields, or only one mapping, or all remaining values are null)
|
|
57
|
+
const canResolveDirectly =
|
|
58
|
+
groupMappings.length === 1 &&
|
|
59
|
+
(!hasMoreFields || groupMappings[0]!.values[nextFieldIndex] === null);
|
|
60
|
+
|
|
61
|
+
if (!hasMoreFields || canResolveDirectly) {
|
|
62
|
+
// Single mapping or no more fields: emit direct return
|
|
63
|
+
if (groupMappings.length === 1) {
|
|
64
|
+
lines.push(
|
|
65
|
+
`${indent} case "${value}": return "${groupMappings[0]!.memberGraphQLTypeName}";`,
|
|
66
|
+
);
|
|
67
|
+
} else {
|
|
68
|
+
// Multiple mappings at the leaf level — shouldn't happen with unique tuples
|
|
69
|
+
for (const mapping of groupMappings) {
|
|
70
|
+
lines.push(
|
|
71
|
+
`${indent} case "${value}": return "${mapping.memberGraphQLTypeName}";`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
// Need nested switch for remaining fields
|
|
77
|
+
lines.push(`${indent} case "${value}":`);
|
|
78
|
+
const nestedLines = buildSwitchBody(
|
|
79
|
+
groupMappings,
|
|
80
|
+
fieldNames,
|
|
81
|
+
nextFieldIndex,
|
|
82
|
+
`${indent} `,
|
|
83
|
+
);
|
|
84
|
+
lines.push(...nestedLines);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
lines.push(`${indent} default: return undefined;`);
|
|
89
|
+
lines.push(`${indent}}`);
|
|
90
|
+
|
|
91
|
+
return lines;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function buildObjTypeAnnotation(fieldNames: ReadonlyArray<string>): string {
|
|
95
|
+
const fields = fieldNames.map((name) => `${name}: string`);
|
|
96
|
+
return `{ ${fields.join("; ")} }`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Builds a resolver map entry for a discriminator-based __resolveType.
|
|
101
|
+
*
|
|
102
|
+
* For single discriminator field:
|
|
103
|
+
* TypeName: {
|
|
104
|
+
* __resolveType: (obj: { field: string }) => {
|
|
105
|
+
* switch (obj.field) {
|
|
106
|
+
* case "val": return "MemberType";
|
|
107
|
+
* default: return undefined;
|
|
108
|
+
* }
|
|
109
|
+
* },
|
|
110
|
+
* },
|
|
111
|
+
*
|
|
112
|
+
* For multiple discriminator fields, generates nested switch statements.
|
|
113
|
+
*/
|
|
114
|
+
export function buildDiscriminatorResolveTypeEntry(
|
|
115
|
+
info: DiscriminatorResolveTypeInfo,
|
|
116
|
+
): string {
|
|
117
|
+
const { unionTypeName, fieldNames, valueMappings } = info;
|
|
118
|
+
const objType = buildObjTypeAnnotation(fieldNames);
|
|
119
|
+
const baseIndent = " ";
|
|
120
|
+
|
|
121
|
+
const switchLines = buildSwitchBody(valueMappings, fieldNames, 0, baseIndent);
|
|
122
|
+
const switchBody = switchLines.join("\n");
|
|
123
|
+
|
|
124
|
+
return ` ${unionTypeName}: {\n __resolveType: (obj: ${objType}) => {\n${switchBody}\n },\n },`;
|
|
125
|
+
}
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
+
collectDiscriminatorResolveTypes,
|
|
2
3
|
collectTypenameExtractions,
|
|
3
4
|
collectTypenameResolveTypes,
|
|
5
|
+
flattenIntersectionMembers,
|
|
4
6
|
generateAutoTypes,
|
|
7
|
+
validateDiscriminatorFields,
|
|
5
8
|
validateNameCollisions,
|
|
6
9
|
validateSchemaTypenames,
|
|
7
10
|
validateTypenames,
|
|
8
11
|
} from "../auto-type-generator/index.js";
|
|
9
12
|
import type { ImportExtension } from "../config/types.js";
|
|
13
|
+
import type { ResolvedDiscriminatorFieldsMap } from "../config-loader/index.js";
|
|
10
14
|
import type { ExtractResolversResult } from "../resolver-extractor/index.js";
|
|
11
15
|
import type { DirectiveDefinitionInfo } from "../shared/directive-definition-extractor.js";
|
|
12
16
|
import type { CollectedScalarType } from "../type-extractor/collector/scalar-collector.js";
|
|
@@ -35,6 +39,7 @@ export interface GenerateSchemaInput {
|
|
|
35
39
|
readonly sourceRoot: string | null;
|
|
36
40
|
readonly knownTypeNames: ReadonlySet<string> | null;
|
|
37
41
|
readonly importExtension: ImportExtension;
|
|
42
|
+
readonly discriminatorFields: ResolvedDiscriminatorFieldsMap;
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
export interface GenerateSchemaResult {
|
|
@@ -67,6 +72,7 @@ export function generateSchema(
|
|
|
67
72
|
extractedTypes,
|
|
68
73
|
resolversResult,
|
|
69
74
|
knownTypeNames: knownTypeNames ?? new Set(),
|
|
75
|
+
discriminatorFields: input.discriminatorFields,
|
|
70
76
|
});
|
|
71
77
|
|
|
72
78
|
const autoTypeErrors = autoTypeResult.diagnostics.filter(
|
|
@@ -105,11 +111,52 @@ export function generateSchema(
|
|
|
105
111
|
};
|
|
106
112
|
}
|
|
107
113
|
|
|
114
|
+
// Flatten intersection-expanded inline object members for discriminator unions.
|
|
115
|
+
// TypeScript distributes intersections over unions, creating duplicate members
|
|
116
|
+
// that must be merged before discriminator field validation.
|
|
117
|
+
const flattenedExtractedTypes = flattenIntersectionMembers({
|
|
118
|
+
extractedTypes: autoTypeResult.updatedExtractedTypes,
|
|
119
|
+
discriminatorFields: input.discriminatorFields,
|
|
120
|
+
});
|
|
121
|
+
|
|
108
122
|
// Re-convert to GraphQL types using updated extracted types
|
|
109
123
|
// This resolves __INLINE_OBJECT__ references to auto-generated type names
|
|
110
|
-
const updatedConversionResult = convertToGraphQL(
|
|
111
|
-
|
|
124
|
+
const updatedConversionResult = convertToGraphQL(flattenedExtractedTypes);
|
|
125
|
+
const typeMap = new Map(
|
|
126
|
+
flattenedExtractedTypes.map((t) => [t.metadata.name, t]),
|
|
112
127
|
);
|
|
128
|
+
|
|
129
|
+
// Validate discriminator fields against extracted types
|
|
130
|
+
const inlineDiscriminatorUnionNames = new Set(
|
|
131
|
+
autoTypeResult.inlineDiscriminatorResolveTypes.map(
|
|
132
|
+
(rt) => rt.unionTypeName,
|
|
133
|
+
),
|
|
134
|
+
);
|
|
135
|
+
const discriminatorValidationResult = validateDiscriminatorFields({
|
|
136
|
+
discriminatorFields: input.discriminatorFields,
|
|
137
|
+
extractedTypes: flattenedExtractedTypes,
|
|
138
|
+
typeMap,
|
|
139
|
+
inlineDiscriminatorUnionNames,
|
|
140
|
+
});
|
|
141
|
+
const discriminatorErrors = discriminatorValidationResult.diagnostics.filter(
|
|
142
|
+
(d) => d.severity === "error",
|
|
143
|
+
);
|
|
144
|
+
if (discriminatorErrors.length > 0) {
|
|
145
|
+
return {
|
|
146
|
+
typeDefsCode: "",
|
|
147
|
+
sdlContent: "",
|
|
148
|
+
resolversCode: "",
|
|
149
|
+
diagnostics: discriminatorValidationResult.diagnostics,
|
|
150
|
+
hasErrors: true,
|
|
151
|
+
prunedTypes: null,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const discriminatorWarnings =
|
|
156
|
+
discriminatorValidationResult.diagnostics.filter(
|
|
157
|
+
(d) => d.severity === "warning",
|
|
158
|
+
);
|
|
159
|
+
|
|
113
160
|
const updatedTypesResult: ExtractTypesResult = {
|
|
114
161
|
types: updatedConversionResult.types,
|
|
115
162
|
diagnostics: {
|
|
@@ -126,29 +173,48 @@ export function generateSchema(
|
|
|
126
173
|
(d) => d.severity === "warning",
|
|
127
174
|
),
|
|
128
175
|
...autoTypeResult.diagnostics.filter((d) => d.severity === "warning"),
|
|
176
|
+
...discriminatorWarnings,
|
|
129
177
|
],
|
|
130
178
|
},
|
|
131
179
|
};
|
|
132
180
|
|
|
133
|
-
const typeMap = new Map(
|
|
134
|
-
autoTypeResult.updatedExtractedTypes.map((t) => [t.metadata.name, t]),
|
|
135
|
-
);
|
|
136
|
-
|
|
137
181
|
const manualResolveTypeNames = new Set(
|
|
138
182
|
autoTypeResult.updatedResolversResult.abstractTypeResolvers
|
|
139
183
|
.filter((r) => r.kind === "resolveType")
|
|
140
184
|
.map((r) => r.targetTypeName),
|
|
141
185
|
);
|
|
142
186
|
|
|
187
|
+
// Collect discriminator resolve types from validated entries
|
|
188
|
+
const discriminatorResolveTypesResult = collectDiscriminatorResolveTypes({
|
|
189
|
+
validatedEntries: discriminatorValidationResult.validatedEntries,
|
|
190
|
+
manualResolveTypeNames,
|
|
191
|
+
extractedTypes: flattenedExtractedTypes,
|
|
192
|
+
typeMap,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// Merge inline discriminator resolveTypes from auto-type generation
|
|
196
|
+
// (for inline unions flattened by discriminator fields, e.g. UIMessagePart<...>[])
|
|
197
|
+
const mergedDiscriminatorResolveTypes = [
|
|
198
|
+
...discriminatorResolveTypesResult.discriminatorResolveTypes,
|
|
199
|
+
...autoTypeResult.inlineDiscriminatorResolveTypes,
|
|
200
|
+
];
|
|
201
|
+
// discriminatorResolveTypeNames are derived by integrate() from the merged list
|
|
202
|
+
|
|
203
|
+
const discriminatorFieldUnionNames = new Set(
|
|
204
|
+
input.discriminatorFields.keys(),
|
|
205
|
+
);
|
|
206
|
+
|
|
143
207
|
const typenameResolveTypesResult = collectTypenameResolveTypes({
|
|
144
|
-
extractedTypes:
|
|
208
|
+
extractedTypes: flattenedExtractedTypes,
|
|
145
209
|
typeMap,
|
|
146
210
|
manualResolveTypeNames,
|
|
211
|
+
discriminatorFieldUnionNames,
|
|
147
212
|
});
|
|
148
213
|
|
|
149
214
|
const typenameExtractions = collectTypenameExtractions({
|
|
150
|
-
extractedTypes:
|
|
215
|
+
extractedTypes: flattenedExtractedTypes,
|
|
151
216
|
typeMap,
|
|
217
|
+
discriminatorFieldUnionNames,
|
|
152
218
|
});
|
|
153
219
|
|
|
154
220
|
const typenameValidationDiagnostics: Diagnostic[] = [];
|
|
@@ -167,7 +233,7 @@ export function generateSchema(
|
|
|
167
233
|
}
|
|
168
234
|
|
|
169
235
|
const schemaTypenameValidationResult = validateSchemaTypenames({
|
|
170
|
-
objectTypes:
|
|
236
|
+
objectTypes: flattenedExtractedTypes,
|
|
171
237
|
typeMap,
|
|
172
238
|
});
|
|
173
239
|
typenameValidationDiagnostics.push(
|
|
@@ -188,20 +254,38 @@ export function generateSchema(
|
|
|
188
254
|
const generatedInlineObjectTypes =
|
|
189
255
|
typenameResolveTypesResult.generatedInlineObjectTypes;
|
|
190
256
|
|
|
257
|
+
// Collect all generated object types that need to be added as union members
|
|
258
|
+
// (both typename-based and discriminator-based inline objects)
|
|
259
|
+
const discriminatorGeneratedObjectTypes =
|
|
260
|
+
discriminatorResolveTypesResult.generatedObjectTypes;
|
|
261
|
+
|
|
191
262
|
const updatedTypesForIntegration: ExtractTypesResult =
|
|
192
|
-
generatedInlineObjectTypes.length > 0
|
|
263
|
+
generatedInlineObjectTypes.length > 0 ||
|
|
264
|
+
discriminatorGeneratedObjectTypes.length > 0
|
|
193
265
|
? {
|
|
194
266
|
types: updatedTypesResult.types.map((type) => {
|
|
195
267
|
if (type.kind !== "Union") {
|
|
196
268
|
return type;
|
|
197
269
|
}
|
|
198
|
-
const
|
|
270
|
+
const typenameInlineTypes = generatedInlineObjectTypes.filter(
|
|
199
271
|
(g) => g.abstractTypeName === type.name,
|
|
200
272
|
);
|
|
201
|
-
|
|
273
|
+
const discriminatorInlineTypes =
|
|
274
|
+
discriminatorGeneratedObjectTypes.filter(
|
|
275
|
+
(g) =>
|
|
276
|
+
g.generatedFrom !== null &&
|
|
277
|
+
g.generatedFrom.parentTypeName === type.name,
|
|
278
|
+
);
|
|
279
|
+
if (
|
|
280
|
+
typenameInlineTypes.length === 0 &&
|
|
281
|
+
discriminatorInlineTypes.length === 0
|
|
282
|
+
) {
|
|
202
283
|
return type;
|
|
203
284
|
}
|
|
204
|
-
const newMembers =
|
|
285
|
+
const newMembers = [
|
|
286
|
+
...typenameInlineTypes.map((g) => g.typeName),
|
|
287
|
+
...discriminatorInlineTypes.map((g) => g.name),
|
|
288
|
+
];
|
|
205
289
|
return {
|
|
206
290
|
...type,
|
|
207
291
|
unionMembers: [
|
|
@@ -217,6 +301,7 @@ export function generateSchema(
|
|
|
217
301
|
const allAutoGeneratedTypes = [
|
|
218
302
|
...autoTypeResult.autoGeneratedTypes,
|
|
219
303
|
...typenameResolveTypesResult.generatedObjectTypes,
|
|
304
|
+
...discriminatorGeneratedObjectTypes,
|
|
220
305
|
];
|
|
221
306
|
|
|
222
307
|
const integratedResult = integrate({
|
|
@@ -227,6 +312,8 @@ export function generateSchema(
|
|
|
227
312
|
directiveDefinitions,
|
|
228
313
|
autoGeneratedTypes: allAutoGeneratedTypes,
|
|
229
314
|
typenameAutoResolveTypes: typenameResolveTypesResult.autoResolveTypes,
|
|
315
|
+
discriminatorResolveTypes: mergedDiscriminatorResolveTypes,
|
|
316
|
+
tsAliasToGraphQLNameMap: autoTypeResult.tsAliasToGraphQLNameMap,
|
|
230
317
|
});
|
|
231
318
|
|
|
232
319
|
let documentNode = buildDocumentNode(integratedResult, { sourceRoot });
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DiscriminatorResolveTypeInfo } from "../../auto-type-generator/discriminator-resolve-type-generator.js";
|
|
1
2
|
import type {
|
|
2
3
|
AutoGeneratedType,
|
|
3
4
|
ResolveTypeFieldPattern,
|
|
@@ -141,6 +142,7 @@ export interface IntegratedResult {
|
|
|
141
142
|
readonly abstractTypeResolvers: ReadonlyArray<AbstractResolverInfo>;
|
|
142
143
|
readonly autoGeneratedUnions: ReadonlyArray<AutoGeneratedUnionInfo>;
|
|
143
144
|
readonly typenameAutoResolveTypes: ReadonlyArray<TypenameAutoResolveTypeInfo>;
|
|
145
|
+
readonly discriminatorResolveTypes: ReadonlyArray<DiscriminatorResolveTypeInfo>;
|
|
144
146
|
readonly numericEnums: ReadonlyArray<NumericEnumInfo>;
|
|
145
147
|
readonly stringEnumMappings: ReadonlyArray<StringEnumMappingInfo>;
|
|
146
148
|
readonly hasQuery: boolean;
|
|
@@ -276,6 +278,8 @@ export interface IntegrateParams {
|
|
|
276
278
|
readonly directiveDefinitions: ReadonlyArray<DirectiveDefinitionInfo> | null;
|
|
277
279
|
readonly autoGeneratedTypes: ReadonlyArray<AutoGeneratedType> | null;
|
|
278
280
|
readonly typenameAutoResolveTypes: ReadonlyArray<TypenameAutoResolveTypeInfo> | null;
|
|
281
|
+
readonly discriminatorResolveTypes: ReadonlyArray<DiscriminatorResolveTypeInfo> | null;
|
|
282
|
+
readonly tsAliasToGraphQLNameMap: ReadonlyMap<string, string> | null;
|
|
279
283
|
}
|
|
280
284
|
|
|
281
285
|
export function integrate(params: IntegrateParams): IntegratedResult {
|
|
@@ -287,6 +291,8 @@ export function integrate(params: IntegrateParams): IntegratedResult {
|
|
|
287
291
|
directiveDefinitions,
|
|
288
292
|
autoGeneratedTypes,
|
|
289
293
|
typenameAutoResolveTypes,
|
|
294
|
+
discriminatorResolveTypes,
|
|
295
|
+
tsAliasToGraphQLNameMap,
|
|
290
296
|
} = params;
|
|
291
297
|
const directiveTypeAliasNames = new Set(
|
|
292
298
|
directiveDefinitions?.map((d) => d.typeAliasName) ?? [],
|
|
@@ -527,15 +533,32 @@ export function integrate(params: IntegrateParams): IntegratedResult {
|
|
|
527
533
|
...autoGeneratedUnions
|
|
528
534
|
.filter((u) => u.hasAutoResolveType)
|
|
529
535
|
.map((u) => u.name),
|
|
536
|
+
...(discriminatorResolveTypes?.map((t) => t.unionTypeName) ?? []),
|
|
530
537
|
]);
|
|
531
538
|
|
|
539
|
+
const aliasMap = tsAliasToGraphQLNameMap ?? new Map<string, string>();
|
|
540
|
+
|
|
532
541
|
const abstractResolverValidation = validateAbstractResolvers({
|
|
533
542
|
abstractResolvers: resolversResult.abstractTypeResolvers,
|
|
534
543
|
baseTypes,
|
|
535
544
|
typenameAutoResolveTypeNames,
|
|
545
|
+
tsAliasToGraphQLNameMap: aliasMap,
|
|
536
546
|
});
|
|
537
547
|
diagnostics.push(...abstractResolverValidation.diagnostics);
|
|
538
548
|
|
|
549
|
+
// Remap abstract resolver target type names from TS aliases to GraphQL names
|
|
550
|
+
// Only remap resolveType resolvers — isTypeOf targets object types, not unions
|
|
551
|
+
const remappedAbstractResolvers =
|
|
552
|
+
aliasMap.size > 0
|
|
553
|
+
? resolversResult.abstractTypeResolvers.map((resolver) => {
|
|
554
|
+
if (resolver.kind !== "resolveType") return resolver;
|
|
555
|
+
const mappedName = aliasMap.get(resolver.targetTypeName);
|
|
556
|
+
return mappedName !== undefined
|
|
557
|
+
? { ...resolver, targetTypeName: mappedName }
|
|
558
|
+
: resolver;
|
|
559
|
+
})
|
|
560
|
+
: resolversResult.abstractTypeResolvers;
|
|
561
|
+
|
|
539
562
|
const knownTypeNames = new Set([
|
|
540
563
|
...baseTypes.map((t) => t.name),
|
|
541
564
|
...inputTypes.map((t) => t.name),
|
|
@@ -733,9 +756,10 @@ export function integrate(params: IntegrateParams): IntegratedResult {
|
|
|
733
756
|
directiveDefinitions && directiveDefinitions.length > 0
|
|
734
757
|
? directiveDefinitions
|
|
735
758
|
: null,
|
|
736
|
-
abstractTypeResolvers:
|
|
759
|
+
abstractTypeResolvers: remappedAbstractResolvers,
|
|
737
760
|
autoGeneratedUnions,
|
|
738
761
|
typenameAutoResolveTypes: typenameAutoResolveTypes ?? [],
|
|
762
|
+
discriminatorResolveTypes: discriminatorResolveTypes ?? [],
|
|
739
763
|
numericEnums,
|
|
740
764
|
stringEnumMappings,
|
|
741
765
|
hasQuery,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DiscriminatorResolveTypeInfo } from "../../auto-type-generator/discriminator-resolve-type-generator.js";
|
|
1
2
|
import type { AutoGeneratedResolveType } from "../../auto-type-generator/resolve-type-generator.js";
|
|
2
3
|
import type { AbstractResolverInfo } from "../../resolver-extractor/extractor/define-api-extractor.js";
|
|
3
4
|
import type {
|
|
@@ -30,6 +31,7 @@ export interface ResolverInfo {
|
|
|
30
31
|
readonly sourceFiles: ReadonlyArray<string>;
|
|
31
32
|
readonly abstractTypeResolvers: ReadonlyArray<AbstractTypeResolverInfo>;
|
|
32
33
|
readonly autoGeneratedResolveTypes: ReadonlyArray<AutoGeneratedResolveType>;
|
|
34
|
+
readonly discriminatorResolveTypes: ReadonlyArray<DiscriminatorResolveTypeInfo>;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
function getResolverValueName(typeName: string): string {
|
|
@@ -148,10 +150,15 @@ export function collectResolverInfo(
|
|
|
148
150
|
|
|
149
151
|
const sourceFiles = [...sourceFilesSet].sort((a, b) => a.localeCompare(b));
|
|
150
152
|
|
|
153
|
+
const discriminatorResolveTypes = [
|
|
154
|
+
...integratedResult.discriminatorResolveTypes,
|
|
155
|
+
].sort((a, b) => a.unionTypeName.localeCompare(b.unionTypeName));
|
|
156
|
+
|
|
151
157
|
return {
|
|
152
158
|
types,
|
|
153
159
|
sourceFiles,
|
|
154
160
|
abstractTypeResolvers,
|
|
155
161
|
autoGeneratedResolveTypes,
|
|
162
|
+
discriminatorResolveTypes,
|
|
156
163
|
};
|
|
157
164
|
}
|
package/src/shared/constants.ts
CHANGED
|
@@ -39,6 +39,19 @@ const TS_ANONYMOUS_TYPE_SYMBOL = "__type";
|
|
|
39
39
|
*/
|
|
40
40
|
const TS_ARRAY_TYPE_SYMBOL = "Array";
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Object literal type symbol name.
|
|
44
|
+
*
|
|
45
|
+
* TypeScript uses `__object` as the internal symbol name for object literal
|
|
46
|
+
* expressions (value-space). This differs from `__type` which is used for
|
|
47
|
+
* anonymous object types in type-space.
|
|
48
|
+
*
|
|
49
|
+
* This commonly occurs when a type is derived via `typeof` from a variable
|
|
50
|
+
* initialized with an object literal, especially when the value comes from
|
|
51
|
+
* an external library.
|
|
52
|
+
*/
|
|
53
|
+
const TS_OBJECT_LITERAL_TYPE_SYMBOL = "__object";
|
|
54
|
+
|
|
42
55
|
/**
|
|
43
56
|
* Checks if a symbol name represents a TypeScript internal/anonymous type
|
|
44
57
|
* that should not be used directly as a GraphQL type name.
|
|
@@ -49,7 +62,8 @@ const TS_ARRAY_TYPE_SYMBOL = "Array";
|
|
|
49
62
|
export function isInternalTypeSymbol(symbolName: string): boolean {
|
|
50
63
|
return (
|
|
51
64
|
symbolName === TS_ANONYMOUS_TYPE_SYMBOL ||
|
|
52
|
-
symbolName === TS_ARRAY_TYPE_SYMBOL
|
|
65
|
+
symbolName === TS_ARRAY_TYPE_SYMBOL ||
|
|
66
|
+
symbolName === TS_OBJECT_LITERAL_TYPE_SYMBOL
|
|
53
67
|
);
|
|
54
68
|
}
|
|
55
69
|
|