@gqlkit-ts/cli 0.2.0 → 0.3.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.
- package/dist/auto-type-generator/auto-type-generator.d.ts +10 -4
- package/dist/auto-type-generator/auto-type-generator.d.ts.map +1 -1
- package/dist/auto-type-generator/auto-type-generator.js +640 -133
- package/dist/auto-type-generator/auto-type-generator.js.map +1 -1
- package/dist/auto-type-generator/index.d.ts +8 -1
- 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 +13 -5
- package/dist/auto-type-generator/inline-enum-collector.d.ts.map +1 -1
- package/dist/auto-type-generator/inline-enum-collector.js +107 -71
- package/dist/auto-type-generator/inline-enum-collector.js.map +1 -1
- package/dist/auto-type-generator/inline-object-traverser.d.ts +20 -0
- package/dist/auto-type-generator/inline-object-traverser.d.ts.map +1 -0
- package/dist/auto-type-generator/inline-object-traverser.js +22 -0
- package/dist/auto-type-generator/inline-object-traverser.js.map +1 -0
- package/dist/auto-type-generator/inline-union-collector.d.ts +29 -0
- package/dist/auto-type-generator/inline-union-collector.d.ts.map +1 -0
- package/dist/auto-type-generator/inline-union-collector.js +216 -0
- package/dist/auto-type-generator/inline-union-collector.js.map +1 -0
- package/dist/auto-type-generator/inline-union-types.d.ts +29 -0
- package/dist/auto-type-generator/inline-union-types.d.ts.map +1 -0
- package/dist/auto-type-generator/inline-union-types.js +2 -0
- package/dist/auto-type-generator/inline-union-types.js.map +1 -0
- package/dist/auto-type-generator/inline-union-validator.d.ts +76 -0
- package/dist/auto-type-generator/inline-union-validator.d.ts.map +1 -0
- package/dist/auto-type-generator/inline-union-validator.js +329 -0
- package/dist/auto-type-generator/inline-union-validator.js.map +1 -0
- package/dist/auto-type-generator/naming-convention.d.ts +18 -1
- package/dist/auto-type-generator/naming-convention.d.ts.map +1 -1
- package/dist/auto-type-generator/naming-convention.js +16 -0
- package/dist/auto-type-generator/naming-convention.js.map +1 -1
- package/dist/auto-type-generator/resolve-type-generator.d.ts +20 -0
- package/dist/auto-type-generator/resolve-type-generator.d.ts.map +1 -0
- package/dist/auto-type-generator/resolve-type-generator.js +2 -0
- package/dist/auto-type-generator/resolve-type-generator.js.map +1 -0
- package/dist/auto-type-generator/resolver-field-iterator.d.ts +13 -0
- package/dist/auto-type-generator/resolver-field-iterator.d.ts.map +1 -0
- package/dist/auto-type-generator/resolver-field-iterator.js +22 -0
- package/dist/auto-type-generator/resolver-field-iterator.js.map +1 -0
- package/dist/auto-type-generator/typename-extractor.d.ts +26 -0
- package/dist/auto-type-generator/typename-extractor.d.ts.map +1 -0
- package/dist/auto-type-generator/typename-extractor.js +142 -0
- package/dist/auto-type-generator/typename-extractor.js.map +1 -0
- package/dist/auto-type-generator/typename-resolve-type-generator.d.ts +35 -0
- package/dist/auto-type-generator/typename-resolve-type-generator.d.ts.map +1 -0
- package/dist/auto-type-generator/typename-resolve-type-generator.js +177 -0
- package/dist/auto-type-generator/typename-resolve-type-generator.js.map +1 -0
- package/dist/auto-type-generator/typename-types.d.ts +43 -0
- package/dist/auto-type-generator/typename-types.d.ts.map +1 -0
- package/dist/auto-type-generator/typename-types.js +37 -0
- package/dist/auto-type-generator/typename-types.js.map +1 -0
- package/dist/auto-type-generator/typename-validator.d.ts +37 -0
- package/dist/auto-type-generator/typename-validator.d.ts.map +1 -0
- package/dist/auto-type-generator/typename-validator.js +206 -0
- package/dist/auto-type-generator/typename-validator.js.map +1 -0
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/docs.d.ts +51 -0
- package/dist/commands/docs.d.ts.map +1 -0
- package/dist/commands/docs.js +154 -0
- package/dist/commands/docs.js.map +1 -0
- package/dist/gen-orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/gen-orchestrator/orchestrator.js +13 -6
- package/dist/gen-orchestrator/orchestrator.js.map +1 -1
- package/dist/resolver-extractor/extract-resolvers.d.ts +19 -1
- package/dist/resolver-extractor/extract-resolvers.d.ts.map +1 -1
- package/dist/resolver-extractor/extractor/define-api-extractor.d.ts +5 -0
- package/dist/resolver-extractor/extractor/define-api-extractor.d.ts.map +1 -1
- package/dist/resolver-extractor/extractor/define-api-extractor.js +14 -61
- package/dist/resolver-extractor/extractor/define-api-extractor.js.map +1 -1
- package/dist/resolver-extractor/index.d.ts +0 -1
- package/dist/resolver-extractor/index.d.ts.map +1 -1
- package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts +1 -0
- package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts.map +1 -1
- package/dist/resolver-extractor/validator/abstract-resolver-validator.js +9 -5
- 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 +20 -0
- package/dist/schema-generator/emitter/code-emitter.js.map +1 -1
- package/dist/schema-generator/generate-schema.d.ts +1 -0
- package/dist/schema-generator/generate-schema.d.ts.map +1 -1
- package/dist/schema-generator/generate-schema.js +72 -3
- package/dist/schema-generator/generate-schema.js.map +1 -1
- package/dist/schema-generator/integrator/result-integrator.d.ts +14 -2
- package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -1
- package/dist/schema-generator/integrator/result-integrator.js +54 -1
- 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 +22 -0
- package/dist/schema-generator/resolver-collector/resolver-collector.js.map +1 -1
- package/dist/shared/enum-prefix-detector.d.ts +63 -0
- package/dist/shared/enum-prefix-detector.d.ts.map +1 -0
- package/dist/shared/enum-prefix-detector.js +80 -0
- package/dist/shared/enum-prefix-detector.js.map +1 -0
- package/dist/shared/ignore-fields-detector.d.ts +26 -0
- package/dist/shared/ignore-fields-detector.d.ts.map +1 -0
- package/dist/shared/ignore-fields-detector.js +83 -0
- package/dist/shared/ignore-fields-detector.js.map +1 -0
- package/dist/shared/ignore-fields-validator.d.ts +29 -0
- package/dist/shared/ignore-fields-validator.d.ts.map +1 -0
- package/dist/shared/ignore-fields-validator.js +43 -0
- package/dist/shared/ignore-fields-validator.js.map +1 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/source-location.d.ts +5 -0
- package/dist/shared/source-location.d.ts.map +1 -1
- package/dist/shared/source-location.js +7 -0
- package/dist/shared/source-location.js.map +1 -1
- package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -1
- package/dist/type-extractor/converter/graphql-converter.js +21 -7
- package/dist/type-extractor/converter/graphql-converter.js.map +1 -1
- package/dist/type-extractor/extractor/field-type-resolver.js +42 -3
- package/dist/type-extractor/extractor/field-type-resolver.js.map +1 -1
- package/dist/type-extractor/extractor/type-extractor.d.ts.map +1 -1
- package/dist/type-extractor/extractor/type-extractor.js +88 -23
- package/dist/type-extractor/extractor/type-extractor.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/ts-type-reference-factory.d.ts +10 -2
- package/dist/type-extractor/types/ts-type-reference-factory.d.ts.map +1 -1
- package/dist/type-extractor/types/ts-type-reference-factory.js +8 -2
- package/dist/type-extractor/types/ts-type-reference-factory.js.map +1 -1
- package/dist/type-extractor/types/typescript.d.ts +4 -0
- package/dist/type-extractor/types/typescript.d.ts.map +1 -1
- package/docs/coding-agents.md +64 -0
- package/docs/configuration.md +6 -20
- package/docs/getting-started.md +15 -12
- package/docs/index.md +36 -22
- package/docs/integration/apollo.md +8 -40
- package/docs/integration/drizzle.md +6 -10
- package/docs/integration/prisma.md +196 -0
- package/docs/integration/yoga.md +8 -40
- package/docs/schema/abstract-resolvers.md +117 -0
- package/docs/schema/directives.md +5 -0
- package/docs/schema/documentation.md +5 -0
- package/docs/schema/enums.md +99 -0
- package/docs/schema/fields.md +64 -0
- package/docs/schema/index.md +21 -0
- package/docs/schema/inputs.md +115 -15
- package/docs/schema/interfaces.md +31 -1
- package/docs/schema/objects.md +40 -0
- package/docs/schema/queries-mutations.md +136 -22
- package/docs/schema/scalars.md +5 -0
- package/docs/schema/unions.md +208 -1
- package/docs/what-is-gqlkit.md +13 -8
- package/package.json +6 -4
- package/src/auto-type-generator/auto-type-generator.ts +946 -201
- package/src/auto-type-generator/index.ts +42 -0
- package/src/auto-type-generator/inline-enum-collector.ts +187 -139
- package/src/auto-type-generator/inline-object-traverser.ts +49 -0
- package/src/auto-type-generator/inline-union-collector.ts +402 -0
- package/src/auto-type-generator/inline-union-types.ts +33 -0
- package/src/auto-type-generator/inline-union-validator.ts +482 -0
- package/src/auto-type-generator/naming-convention.ts +38 -1
- package/src/auto-type-generator/resolve-type-generator.ts +21 -0
- package/src/auto-type-generator/resolver-field-iterator.ts +39 -0
- package/src/auto-type-generator/typename-extractor.ts +230 -0
- package/src/auto-type-generator/typename-resolve-type-generator.ts +281 -0
- package/src/auto-type-generator/typename-types.ts +66 -0
- package/src/auto-type-generator/typename-validator.ts +326 -0
- package/src/cli.ts +2 -0
- package/src/commands/docs.ts +211 -0
- package/src/gen-orchestrator/orchestrator.ts +20 -6
- package/src/resolver-extractor/extract-resolvers.ts +19 -0
- package/src/resolver-extractor/extractor/define-api-extractor.ts +23 -89
- package/src/resolver-extractor/index.ts +0 -6
- package/src/resolver-extractor/validator/abstract-resolver-validator.ts +16 -8
- package/src/schema-generator/emitter/code-emitter.ts +34 -0
- package/src/schema-generator/generate-schema.ts +99 -2
- package/src/schema-generator/integrator/result-integrator.ts +70 -1
- package/src/schema-generator/resolver-collector/resolver-collector.ts +34 -0
- package/src/shared/enum-prefix-detector.ts +99 -0
- package/src/shared/ignore-fields-detector.ts +109 -0
- package/src/shared/ignore-fields-validator.ts +66 -0
- package/src/shared/index.ts +2 -0
- package/src/shared/source-location.ts +11 -0
- package/src/type-extractor/converter/graphql-converter.ts +31 -7
- package/src/type-extractor/extractor/field-type-resolver.ts +48 -3
- package/src/type-extractor/extractor/type-extractor.ts +103 -26
- package/src/type-extractor/types/diagnostics.ts +12 -2
- package/src/type-extractor/types/ts-type-reference-factory.ts +18 -5
- package/src/type-extractor/types/typescript.ts +4 -0
- package/dist/resolver-extractor/validator/only-validator.d.ts +0 -61
- package/dist/resolver-extractor/validator/only-validator.d.ts.map +0 -1
- package/dist/resolver-extractor/validator/only-validator.js +0 -76
- package/dist/resolver-extractor/validator/only-validator.js.map +0 -1
- package/src/resolver-extractor/validator/only-validator.ts +0 -158
|
@@ -7,6 +7,11 @@ import type {
|
|
|
7
7
|
DirectiveArgumentValue,
|
|
8
8
|
DirectiveInfo,
|
|
9
9
|
} from "../shared/directive-detector.js";
|
|
10
|
+
import {
|
|
11
|
+
detectEnumPrefix,
|
|
12
|
+
stripEnumPrefix,
|
|
13
|
+
} from "../shared/enum-prefix-detector.js";
|
|
14
|
+
import { getSourceLocationOrDefault } from "../shared/source-location.js";
|
|
10
15
|
import type { DeprecationInfo } from "../shared/tsdoc-parser.js";
|
|
11
16
|
import { convertTsTypeToGraphQLType } from "../shared/type-converter.js";
|
|
12
17
|
import {
|
|
@@ -24,15 +29,38 @@ import {
|
|
|
24
29
|
type SourceLocation,
|
|
25
30
|
} from "../type-extractor/types/index.js";
|
|
26
31
|
import {
|
|
32
|
+
collectInlineEnumsFromPayloads,
|
|
27
33
|
collectInlineEnumsFromResolvers,
|
|
28
34
|
collectInlineEnumsFromTypes,
|
|
29
35
|
type InlineEnumWithContext,
|
|
30
36
|
} from "./inline-enum-collector.js";
|
|
37
|
+
import {
|
|
38
|
+
collectInlineUnionsFromPayloads,
|
|
39
|
+
collectInlineUnionsFromResolvers,
|
|
40
|
+
collectInlineUnionsFromTypes,
|
|
41
|
+
type InlineUnionWithContext,
|
|
42
|
+
} from "./inline-union-collector.js";
|
|
43
|
+
import type { InlineUnionMemberInfo } from "./inline-union-types.js";
|
|
44
|
+
import {
|
|
45
|
+
type ValidatedTypenameInfo,
|
|
46
|
+
validateOneOfMembers,
|
|
47
|
+
validateUnionMembers,
|
|
48
|
+
validateUnionMemberTypenames,
|
|
49
|
+
} from "./inline-union-validator.js";
|
|
31
50
|
import {
|
|
32
51
|
type AutoTypeNameContext,
|
|
33
52
|
buildFieldContext,
|
|
34
53
|
generateAutoTypeName,
|
|
54
|
+
isInputTypeName,
|
|
35
55
|
} from "./naming-convention.js";
|
|
56
|
+
import type { ResolveTypeFieldPattern } from "./resolve-type-generator.js";
|
|
57
|
+
import { forEachResolverField } from "./resolver-field-iterator.js";
|
|
58
|
+
import {
|
|
59
|
+
createFieldNameSet,
|
|
60
|
+
findTypenameProperty,
|
|
61
|
+
type TypenameFieldInfo,
|
|
62
|
+
type TypenameFieldName,
|
|
63
|
+
} from "./typename-types.js";
|
|
36
64
|
|
|
37
65
|
/**
|
|
38
66
|
* Information about where an auto-generated type was generated from.
|
|
@@ -40,7 +68,11 @@ import {
|
|
|
40
68
|
export interface GeneratedFromInfo {
|
|
41
69
|
readonly parentTypeName: string | null;
|
|
42
70
|
readonly fieldPath: ReadonlyArray<string>;
|
|
43
|
-
readonly context:
|
|
71
|
+
readonly context:
|
|
72
|
+
| "typeField"
|
|
73
|
+
| "inputField"
|
|
74
|
+
| "resolverArg"
|
|
75
|
+
| "resolverPayload";
|
|
44
76
|
}
|
|
45
77
|
|
|
46
78
|
/**
|
|
@@ -72,21 +104,31 @@ export interface AutoGeneratedEnumValue {
|
|
|
72
104
|
*/
|
|
73
105
|
export interface AutoGeneratedType {
|
|
74
106
|
readonly name: string;
|
|
75
|
-
readonly kind:
|
|
76
|
-
|
|
107
|
+
readonly kind:
|
|
108
|
+
| "Object"
|
|
109
|
+
| "InputObject"
|
|
110
|
+
| "Enum"
|
|
111
|
+
| "Union"
|
|
112
|
+
| "OneOfInputObject";
|
|
113
|
+
/** Fields for Object/InputObject/OneOfInputObject kinds (null for Enum/Union) */
|
|
77
114
|
readonly fields: ReadonlyArray<AutoGeneratedField> | null;
|
|
78
|
-
/** Enum values for Enum kind (null for Object/InputObject) */
|
|
115
|
+
/** Enum values for Enum kind (null for Object/InputObject/Union/OneOfInputObject) */
|
|
79
116
|
readonly enumValues: ReadonlyArray<AutoGeneratedEnumValue> | null;
|
|
117
|
+
/** Union members for Union kind (null for Object/InputObject/Enum/OneOfInputObject) */
|
|
118
|
+
readonly unionMembers: ReadonlyArray<string> | null;
|
|
80
119
|
/** True if enum needs value mapping (at least one value converted) */
|
|
81
120
|
readonly needsStringEnumMapping: boolean;
|
|
82
121
|
readonly sourceLocation: SourceLocation;
|
|
83
122
|
readonly generatedFrom: GeneratedFromInfo;
|
|
84
123
|
readonly description: string | null;
|
|
124
|
+
/** For Union types from resolverPayload context: the field pattern for resolveType */
|
|
125
|
+
readonly resolveTypeFieldPattern: ResolveTypeFieldPattern | null;
|
|
85
126
|
}
|
|
86
127
|
|
|
87
128
|
export interface AutoTypeGeneratorInput {
|
|
88
129
|
readonly extractedTypes: ReadonlyArray<ExtractedTypeInfo>;
|
|
89
130
|
readonly resolversResult: ExtractResolversResult;
|
|
131
|
+
readonly knownTypeNames: ReadonlySet<string>;
|
|
90
132
|
}
|
|
91
133
|
|
|
92
134
|
export interface AutoTypeGeneratorResult {
|
|
@@ -101,10 +143,70 @@ interface InlineObjectWithContext {
|
|
|
101
143
|
readonly context: AutoTypeNameContext;
|
|
102
144
|
readonly sourceLocation: SourceLocation;
|
|
103
145
|
readonly nullable: boolean;
|
|
146
|
+
/** TSDoc description from the inline object type alias (Requirement 7.2) */
|
|
147
|
+
readonly description: string | null;
|
|
148
|
+
/** @deprecated tag from the inline object type alias (Requirement 7.3) */
|
|
149
|
+
readonly deprecated: DeprecationInfo | null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
type ContextBuilderFn = (
|
|
153
|
+
nestedPath: ReadonlyArray<string>,
|
|
154
|
+
) => AutoTypeNameContext;
|
|
155
|
+
|
|
156
|
+
interface ExtractNestedInlineObjectsParams {
|
|
157
|
+
readonly properties: ReadonlyArray<InlineObjectPropertyDef>;
|
|
158
|
+
readonly currentPath: ReadonlyArray<string>;
|
|
159
|
+
readonly sourceLocation: SourceLocation;
|
|
160
|
+
readonly buildContext: ContextBuilderFn;
|
|
161
|
+
readonly preserveDocumentation: boolean;
|
|
162
|
+
readonly results: InlineObjectWithContext[];
|
|
104
163
|
}
|
|
105
164
|
|
|
106
|
-
function
|
|
107
|
-
|
|
165
|
+
function extractNestedInlineObjectsRecursively(
|
|
166
|
+
params: ExtractNestedInlineObjectsParams,
|
|
167
|
+
): void {
|
|
168
|
+
const {
|
|
169
|
+
properties,
|
|
170
|
+
currentPath,
|
|
171
|
+
sourceLocation,
|
|
172
|
+
buildContext,
|
|
173
|
+
preserveDocumentation,
|
|
174
|
+
results,
|
|
175
|
+
} = params;
|
|
176
|
+
|
|
177
|
+
for (const prop of properties) {
|
|
178
|
+
if (
|
|
179
|
+
prop.tsType.kind === "inlineObject" &&
|
|
180
|
+
prop.tsType.inlineObjectProperties
|
|
181
|
+
) {
|
|
182
|
+
const nestedPath = [...currentPath, prop.name];
|
|
183
|
+
const nestedContext = buildContext(nestedPath);
|
|
184
|
+
// Use property's source location if available for more accurate diagnostics
|
|
185
|
+
const nestedSourceLocation = prop.sourceLocation ?? sourceLocation;
|
|
186
|
+
|
|
187
|
+
results.push({
|
|
188
|
+
properties: prop.tsType.inlineObjectProperties,
|
|
189
|
+
context: nestedContext,
|
|
190
|
+
sourceLocation: nestedSourceLocation,
|
|
191
|
+
nullable: prop.tsType.nullable,
|
|
192
|
+
description: preserveDocumentation
|
|
193
|
+
? prop.tsType.inlineObjectDescription
|
|
194
|
+
: null,
|
|
195
|
+
deprecated: preserveDocumentation
|
|
196
|
+
? prop.tsType.inlineObjectDeprecated
|
|
197
|
+
: null,
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
extractNestedInlineObjectsRecursively({
|
|
201
|
+
properties: prop.tsType.inlineObjectProperties,
|
|
202
|
+
currentPath: nestedPath,
|
|
203
|
+
sourceLocation: nestedSourceLocation,
|
|
204
|
+
buildContext,
|
|
205
|
+
preserveDocumentation,
|
|
206
|
+
results,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
108
210
|
}
|
|
109
211
|
|
|
110
212
|
function getContextKey(context: AutoTypeNameContext): string {
|
|
@@ -115,6 +217,8 @@ function getContextKey(context: AutoTypeNameContext): string {
|
|
|
115
217
|
return `inputField:${context.parentTypeName}:${context.fieldPath.join(".")}`;
|
|
116
218
|
case "resolverArg":
|
|
117
219
|
return `resolverArg:${context.resolverType}:${context.parentTypeName ?? ""}:${context.fieldName}:${context.argName}:${context.fieldPath.join(".")}`;
|
|
220
|
+
case "resolverPayload":
|
|
221
|
+
return `resolverPayload:${context.resolverType}:${context.parentTypeName ?? ""}:${context.fieldName}:${context.fieldPath.join(".")}`;
|
|
118
222
|
}
|
|
119
223
|
}
|
|
120
224
|
|
|
@@ -128,6 +232,8 @@ function mapContextKindToGeneratedFromContext(
|
|
|
128
232
|
return "inputField";
|
|
129
233
|
case "resolverArg":
|
|
130
234
|
return "resolverArg";
|
|
235
|
+
case "resolverPayload":
|
|
236
|
+
return "resolverPayload";
|
|
131
237
|
}
|
|
132
238
|
}
|
|
133
239
|
|
|
@@ -194,100 +300,31 @@ function collectInlineObjectsFromField(
|
|
|
194
300
|
fieldPath,
|
|
195
301
|
};
|
|
196
302
|
|
|
303
|
+
const sourceLocation = getSourceLocationOrDefault(
|
|
304
|
+
field.sourceLocation,
|
|
305
|
+
sourceFile,
|
|
306
|
+
);
|
|
307
|
+
|
|
197
308
|
results.push({
|
|
198
309
|
properties: tsType.inlineObjectProperties,
|
|
199
310
|
context,
|
|
200
|
-
sourceLocation
|
|
201
|
-
file: sourceFile,
|
|
202
|
-
line: 1,
|
|
203
|
-
column: 1,
|
|
204
|
-
},
|
|
311
|
+
sourceLocation,
|
|
205
312
|
nullable: tsType.nullable,
|
|
313
|
+
description: tsType.inlineObjectDescription,
|
|
314
|
+
deprecated: tsType.inlineObjectDeprecated,
|
|
206
315
|
});
|
|
207
316
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
)
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
fieldPath: nestedPath,
|
|
219
|
-
}
|
|
220
|
-
: {
|
|
221
|
-
kind: "objectField",
|
|
222
|
-
parentTypeName,
|
|
223
|
-
fieldPath: nestedPath,
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
extractNestedInlineObjects(
|
|
227
|
-
prop.tsType.inlineObjectProperties,
|
|
228
|
-
nestedContext,
|
|
229
|
-
nestedPath,
|
|
230
|
-
parentTypeName,
|
|
231
|
-
isInput,
|
|
232
|
-
sourceFile,
|
|
233
|
-
prop.sourceLocation,
|
|
234
|
-
results,
|
|
235
|
-
);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
function extractNestedInlineObjects(
|
|
241
|
-
properties: ReadonlyArray<InlineObjectPropertyDef>,
|
|
242
|
-
context: AutoTypeNameContext,
|
|
243
|
-
currentPath: ReadonlyArray<string>,
|
|
244
|
-
parentTypeName: string,
|
|
245
|
-
isInput: boolean,
|
|
246
|
-
sourceFile: string,
|
|
247
|
-
parentSourceLocation: SourceLocation | null,
|
|
248
|
-
results: InlineObjectWithContext[],
|
|
249
|
-
): void {
|
|
250
|
-
results.push({
|
|
251
|
-
properties,
|
|
252
|
-
context,
|
|
253
|
-
sourceLocation: parentSourceLocation ?? {
|
|
254
|
-
file: sourceFile,
|
|
255
|
-
line: 1,
|
|
256
|
-
column: 1,
|
|
257
|
-
},
|
|
258
|
-
nullable: false,
|
|
317
|
+
extractNestedInlineObjectsRecursively({
|
|
318
|
+
properties: tsType.inlineObjectProperties,
|
|
319
|
+
currentPath: fieldPath,
|
|
320
|
+
sourceLocation,
|
|
321
|
+
buildContext: (nestedPath) =>
|
|
322
|
+
isInput
|
|
323
|
+
? { kind: "inputField", parentTypeName, fieldPath: nestedPath }
|
|
324
|
+
: { kind: "objectField", parentTypeName, fieldPath: nestedPath },
|
|
325
|
+
preserveDocumentation: true,
|
|
326
|
+
results,
|
|
259
327
|
});
|
|
260
|
-
|
|
261
|
-
for (const prop of properties) {
|
|
262
|
-
if (
|
|
263
|
-
prop.tsType.kind === "inlineObject" &&
|
|
264
|
-
prop.tsType.inlineObjectProperties
|
|
265
|
-
) {
|
|
266
|
-
const nestedPath = [...currentPath, prop.name];
|
|
267
|
-
const nestedContext: AutoTypeNameContext = isInput
|
|
268
|
-
? {
|
|
269
|
-
kind: "inputField",
|
|
270
|
-
parentTypeName,
|
|
271
|
-
fieldPath: nestedPath,
|
|
272
|
-
}
|
|
273
|
-
: {
|
|
274
|
-
kind: "objectField",
|
|
275
|
-
parentTypeName,
|
|
276
|
-
fieldPath: nestedPath,
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
extractNestedInlineObjects(
|
|
280
|
-
prop.tsType.inlineObjectProperties,
|
|
281
|
-
nestedContext,
|
|
282
|
-
nestedPath,
|
|
283
|
-
parentTypeName,
|
|
284
|
-
isInput,
|
|
285
|
-
sourceFile,
|
|
286
|
-
prop.sourceLocation,
|
|
287
|
-
results,
|
|
288
|
-
);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
328
|
}
|
|
292
329
|
|
|
293
330
|
function collectInlineObjectsFromResolvers(
|
|
@@ -295,24 +332,17 @@ function collectInlineObjectsFromResolvers(
|
|
|
295
332
|
): InlineObjectWithContext[] {
|
|
296
333
|
const results: InlineObjectWithContext[] = [];
|
|
297
334
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
for (const field of resolversResult.mutationFields.fields) {
|
|
303
|
-
collectInlineObjectsFromResolverArgs(field, "mutation", null, results);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
for (const ext of resolversResult.typeExtensions) {
|
|
307
|
-
for (const field of ext.fields) {
|
|
335
|
+
forEachResolverField(
|
|
336
|
+
resolversResult,
|
|
337
|
+
({ field, resolverType, parentTypeName }) => {
|
|
308
338
|
collectInlineObjectsFromResolverArgs(
|
|
309
339
|
field,
|
|
310
|
-
|
|
311
|
-
|
|
340
|
+
resolverType,
|
|
341
|
+
parentTypeName,
|
|
312
342
|
results,
|
|
313
343
|
);
|
|
314
|
-
}
|
|
315
|
-
|
|
344
|
+
},
|
|
345
|
+
);
|
|
316
346
|
|
|
317
347
|
return results;
|
|
318
348
|
}
|
|
@@ -342,65 +372,87 @@ function collectInlineObjectsFromResolverArgs(
|
|
|
342
372
|
context,
|
|
343
373
|
sourceLocation: field.sourceLocation,
|
|
344
374
|
nullable: arg.type.nullable,
|
|
375
|
+
description: null,
|
|
376
|
+
deprecated: null,
|
|
345
377
|
});
|
|
346
378
|
|
|
347
|
-
|
|
348
|
-
arg.inlineObjectProperties,
|
|
349
|
-
|
|
350
|
-
field.
|
|
351
|
-
|
|
352
|
-
parentTypeName,
|
|
353
|
-
[],
|
|
354
|
-
field.sourceLocation,
|
|
355
|
-
results,
|
|
356
|
-
);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
function extractNestedInlineObjectsFromArg(
|
|
361
|
-
properties: ReadonlyArray<InlineObjectPropertyDef>,
|
|
362
|
-
resolverType: "query" | "mutation" | "field",
|
|
363
|
-
fieldName: string,
|
|
364
|
-
argName: string,
|
|
365
|
-
parentTypeName: string | null,
|
|
366
|
-
currentPath: ReadonlyArray<string>,
|
|
367
|
-
sourceLocation: SourceLocation,
|
|
368
|
-
results: InlineObjectWithContext[],
|
|
369
|
-
): void {
|
|
370
|
-
for (const prop of properties) {
|
|
371
|
-
if (
|
|
372
|
-
prop.tsType.kind === "inlineObject" &&
|
|
373
|
-
prop.tsType.inlineObjectProperties
|
|
374
|
-
) {
|
|
375
|
-
const nestedPath = [...currentPath, prop.name];
|
|
376
|
-
const nestedContext: AutoTypeNameContext = {
|
|
379
|
+
extractNestedInlineObjectsRecursively({
|
|
380
|
+
properties: arg.inlineObjectProperties,
|
|
381
|
+
currentPath: [],
|
|
382
|
+
sourceLocation: field.sourceLocation,
|
|
383
|
+
buildContext: (nestedPath) => ({
|
|
377
384
|
kind: "resolverArg",
|
|
378
385
|
resolverType,
|
|
379
|
-
fieldName,
|
|
380
|
-
argName,
|
|
386
|
+
fieldName: field.name,
|
|
387
|
+
argName: arg.name,
|
|
381
388
|
parentTypeName,
|
|
382
389
|
fieldPath: nestedPath,
|
|
383
|
-
}
|
|
390
|
+
}),
|
|
391
|
+
preserveDocumentation: false,
|
|
392
|
+
results,
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
}
|
|
384
396
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
nullable: prop.tsType.nullable,
|
|
390
|
-
});
|
|
397
|
+
function collectInlinePayloadsFromResolvers(
|
|
398
|
+
resolversResult: ExtractResolversResult,
|
|
399
|
+
): InlineObjectWithContext[] {
|
|
400
|
+
const results: InlineObjectWithContext[] = [];
|
|
391
401
|
|
|
392
|
-
|
|
393
|
-
|
|
402
|
+
forEachResolverField(
|
|
403
|
+
resolversResult,
|
|
404
|
+
({ field, resolverType, parentTypeName }) => {
|
|
405
|
+
collectInlinePayloadFromReturnType(
|
|
406
|
+
field,
|
|
394
407
|
resolverType,
|
|
395
|
-
fieldName,
|
|
396
|
-
argName,
|
|
397
408
|
parentTypeName,
|
|
398
|
-
nestedPath,
|
|
399
|
-
sourceLocation,
|
|
400
409
|
results,
|
|
401
410
|
);
|
|
402
|
-
}
|
|
403
|
-
|
|
411
|
+
},
|
|
412
|
+
);
|
|
413
|
+
|
|
414
|
+
return results;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function collectInlinePayloadFromReturnType(
|
|
418
|
+
field: GraphQLFieldDefinition,
|
|
419
|
+
resolverType: "query" | "mutation" | "field",
|
|
420
|
+
parentTypeName: string | null,
|
|
421
|
+
results: InlineObjectWithContext[],
|
|
422
|
+
): void {
|
|
423
|
+
if (!field.returnTypeInlineObjectProperties) return;
|
|
424
|
+
|
|
425
|
+
const context: AutoTypeNameContext = {
|
|
426
|
+
kind: "resolverPayload",
|
|
427
|
+
resolverType,
|
|
428
|
+
fieldName: field.name,
|
|
429
|
+
parentTypeName,
|
|
430
|
+
fieldPath: [],
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
results.push({
|
|
434
|
+
properties: field.returnTypeInlineObjectProperties,
|
|
435
|
+
context,
|
|
436
|
+
sourceLocation: field.sourceLocation,
|
|
437
|
+
nullable: field.type.nullable,
|
|
438
|
+
description: field.returnTypeInlineObjectDescription,
|
|
439
|
+
deprecated: field.returnTypeInlineObjectDeprecated,
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
extractNestedInlineObjectsRecursively({
|
|
443
|
+
properties: field.returnTypeInlineObjectProperties,
|
|
444
|
+
currentPath: [],
|
|
445
|
+
sourceLocation: field.sourceLocation,
|
|
446
|
+
buildContext: (nestedPath) => ({
|
|
447
|
+
kind: "resolverPayload",
|
|
448
|
+
resolverType,
|
|
449
|
+
fieldName: field.name,
|
|
450
|
+
parentTypeName,
|
|
451
|
+
fieldPath: nestedPath,
|
|
452
|
+
}),
|
|
453
|
+
preserveDocumentation: true,
|
|
454
|
+
results,
|
|
455
|
+
});
|
|
404
456
|
}
|
|
405
457
|
|
|
406
458
|
interface GenerateAutoTypeResult {
|
|
@@ -412,12 +464,14 @@ interface GenerateAutoTypeParams {
|
|
|
412
464
|
readonly inlineObj: InlineObjectWithContext;
|
|
413
465
|
readonly generatedTypeNames: Map<string, string>;
|
|
414
466
|
readonly enumTypeNames: Map<string, string>;
|
|
467
|
+
readonly unionTypeNames: Map<string, string>;
|
|
415
468
|
}
|
|
416
469
|
|
|
417
470
|
function generateAutoType(
|
|
418
471
|
params: GenerateAutoTypeParams,
|
|
419
472
|
): GenerateAutoTypeResult {
|
|
420
|
-
const { inlineObj, generatedTypeNames, enumTypeNames } =
|
|
473
|
+
const { inlineObj, generatedTypeNames, enumTypeNames, unionTypeNames } =
|
|
474
|
+
params;
|
|
421
475
|
const name = generateAutoTypeName(inlineObj.context);
|
|
422
476
|
const isInput =
|
|
423
477
|
inlineObj.context.kind === "inputField" ||
|
|
@@ -445,6 +499,7 @@ function generateAutoType(
|
|
|
445
499
|
prop,
|
|
446
500
|
generatedTypeNames,
|
|
447
501
|
enumTypeNames,
|
|
502
|
+
unionTypeNames,
|
|
448
503
|
parentContext: inlineObj.context,
|
|
449
504
|
});
|
|
450
505
|
fields.push({
|
|
@@ -463,10 +518,12 @@ function generateAutoType(
|
|
|
463
518
|
kind: isInput ? "InputObject" : "Object",
|
|
464
519
|
fields,
|
|
465
520
|
enumValues: null,
|
|
521
|
+
unionMembers: null,
|
|
466
522
|
needsStringEnumMapping: false,
|
|
467
523
|
sourceLocation: inlineObj.sourceLocation,
|
|
468
524
|
generatedFrom: buildGeneratedFromInfo(inlineObj.context),
|
|
469
|
-
description:
|
|
525
|
+
description: inlineObj.description,
|
|
526
|
+
resolveTypeFieldPattern: null,
|
|
470
527
|
},
|
|
471
528
|
diagnostics,
|
|
472
529
|
};
|
|
@@ -476,49 +533,63 @@ interface ResolveFieldTypeParams {
|
|
|
476
533
|
readonly prop: InlineObjectPropertyDef;
|
|
477
534
|
readonly generatedTypeNames: Map<string, string>;
|
|
478
535
|
readonly enumTypeNames: Map<string, string>;
|
|
536
|
+
readonly unionTypeNames: Map<string, string>;
|
|
479
537
|
readonly parentContext: AutoTypeNameContext;
|
|
480
538
|
}
|
|
481
539
|
|
|
540
|
+
function tryResolveNestedType(
|
|
541
|
+
prop: InlineObjectPropertyDef,
|
|
542
|
+
parentContext: AutoTypeNameContext,
|
|
543
|
+
typeNamesMap: ReadonlyMap<string, string>,
|
|
544
|
+
): GraphQLFieldType | null {
|
|
545
|
+
const nestedPath = [...parentContext.fieldPath, prop.name];
|
|
546
|
+
const nestedContext: AutoTypeNameContext = {
|
|
547
|
+
...parentContext,
|
|
548
|
+
fieldPath: nestedPath,
|
|
549
|
+
};
|
|
550
|
+
const contextKey = getContextKey(nestedContext);
|
|
551
|
+
const resolvedTypeName = typeNamesMap.get(contextKey);
|
|
552
|
+
|
|
553
|
+
if (resolvedTypeName) {
|
|
554
|
+
return {
|
|
555
|
+
typeName: resolvedTypeName,
|
|
556
|
+
nullable: prop.tsType.nullable || prop.optional,
|
|
557
|
+
list: false,
|
|
558
|
+
listItemNullable: null,
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
return null;
|
|
562
|
+
}
|
|
563
|
+
|
|
482
564
|
function resolveFieldType(params: ResolveFieldTypeParams): GraphQLFieldType {
|
|
483
|
-
const {
|
|
565
|
+
const {
|
|
566
|
+
prop,
|
|
567
|
+
generatedTypeNames,
|
|
568
|
+
enumTypeNames,
|
|
569
|
+
unionTypeNames,
|
|
570
|
+
parentContext,
|
|
571
|
+
} = params;
|
|
484
572
|
|
|
485
573
|
if (
|
|
486
574
|
prop.tsType.kind === "inlineObject" &&
|
|
487
575
|
prop.tsType.inlineObjectProperties
|
|
488
576
|
) {
|
|
489
|
-
const
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
const resolvedTypeName = generatedTypeNames.get(contextKey);
|
|
496
|
-
if (resolvedTypeName) {
|
|
497
|
-
return {
|
|
498
|
-
typeName: resolvedTypeName,
|
|
499
|
-
nullable: prop.tsType.nullable || prop.optional,
|
|
500
|
-
list: false,
|
|
501
|
-
listItemNullable: null,
|
|
502
|
-
};
|
|
503
|
-
}
|
|
577
|
+
const result = tryResolveNestedType(
|
|
578
|
+
prop,
|
|
579
|
+
parentContext,
|
|
580
|
+
generatedTypeNames,
|
|
581
|
+
);
|
|
582
|
+
if (result) return result;
|
|
504
583
|
}
|
|
505
584
|
|
|
506
585
|
if (prop.tsType.kind === "inlineEnum" && prop.tsType.inlineEnumMembers) {
|
|
507
|
-
const
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
const
|
|
513
|
-
|
|
514
|
-
if (resolvedTypeName) {
|
|
515
|
-
return {
|
|
516
|
-
typeName: resolvedTypeName,
|
|
517
|
-
nullable: prop.tsType.nullable || prop.optional,
|
|
518
|
-
list: false,
|
|
519
|
-
listItemNullable: null,
|
|
520
|
-
};
|
|
521
|
-
}
|
|
586
|
+
const result = tryResolveNestedType(prop, parentContext, enumTypeNames);
|
|
587
|
+
if (result) return result;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
if (prop.tsType.kind === "union" && prop.tsType.members) {
|
|
591
|
+
const result = tryResolveNestedType(prop, parentContext, unionTypeNames);
|
|
592
|
+
if (result) return result;
|
|
522
593
|
}
|
|
523
594
|
|
|
524
595
|
return convertTsTypeToGraphQLType(prop.tsType, prop.optional);
|
|
@@ -527,6 +598,7 @@ function resolveFieldType(params: ResolveFieldTypeParams): GraphQLFieldType {
|
|
|
527
598
|
interface UpdateTypeNamesParams {
|
|
528
599
|
readonly generatedTypeNames: Map<string, string>;
|
|
529
600
|
readonly enumTypeNames: Map<string, string>;
|
|
601
|
+
readonly unionTypeNames: Map<string, string>;
|
|
530
602
|
}
|
|
531
603
|
|
|
532
604
|
function updateExtractedTypes(
|
|
@@ -550,7 +622,7 @@ function updateField(
|
|
|
550
622
|
parentTypeName: string,
|
|
551
623
|
isInput: boolean,
|
|
552
624
|
): FieldDefinition {
|
|
553
|
-
const { generatedTypeNames, enumTypeNames } = params;
|
|
625
|
+
const { generatedTypeNames, enumTypeNames, unionTypeNames } = params;
|
|
554
626
|
const context = buildFieldContext(parentTypeName, [field.name], isInput);
|
|
555
627
|
const contextKey = getContextKey(context);
|
|
556
628
|
|
|
@@ -606,6 +678,20 @@ function updateField(
|
|
|
606
678
|
}
|
|
607
679
|
}
|
|
608
680
|
|
|
681
|
+
// Handle inline union types
|
|
682
|
+
if (field.tsType.kind === "union" && field.tsType.members) {
|
|
683
|
+
const resolvedTypeName = unionTypeNames.get(contextKey);
|
|
684
|
+
if (resolvedTypeName) {
|
|
685
|
+
return {
|
|
686
|
+
...field,
|
|
687
|
+
tsType: createReferenceType({
|
|
688
|
+
name: resolvedTypeName,
|
|
689
|
+
nullable: field.tsType.nullable,
|
|
690
|
+
}),
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
609
695
|
return field;
|
|
610
696
|
}
|
|
611
697
|
|
|
@@ -640,9 +726,55 @@ function updateResolverField(
|
|
|
640
726
|
resolverType: "query" | "mutation" | "field",
|
|
641
727
|
parentTypeName: string | null,
|
|
642
728
|
): GraphQLFieldDefinition {
|
|
643
|
-
|
|
729
|
+
const { generatedTypeNames, enumTypeNames, unionTypeNames } = params;
|
|
644
730
|
|
|
645
|
-
|
|
731
|
+
let updatedType = field.type;
|
|
732
|
+
|
|
733
|
+
// Create payload context once for all inline return type checks
|
|
734
|
+
const hasInlinePayload =
|
|
735
|
+
field.returnTypeInlineObjectProperties ||
|
|
736
|
+
field.returnTypeInlineEnumMembers ||
|
|
737
|
+
field.returnTypeInlineUnionMembers;
|
|
738
|
+
|
|
739
|
+
if (hasInlinePayload) {
|
|
740
|
+
const payloadContext: AutoTypeNameContext = {
|
|
741
|
+
kind: "resolverPayload",
|
|
742
|
+
resolverType,
|
|
743
|
+
fieldName: field.name,
|
|
744
|
+
parentTypeName,
|
|
745
|
+
fieldPath: [],
|
|
746
|
+
};
|
|
747
|
+
const payloadContextKey = getContextKey(payloadContext);
|
|
748
|
+
|
|
749
|
+
// These are mutually exclusive - a return type can only be one of:
|
|
750
|
+
// inline object, inline enum, or inline union
|
|
751
|
+
if (field.returnTypeInlineObjectProperties) {
|
|
752
|
+
// Handle inline payload objects in return type
|
|
753
|
+
const resolvedTypeName = generatedTypeNames.get(payloadContextKey);
|
|
754
|
+
if (resolvedTypeName) {
|
|
755
|
+
updatedType = { ...field.type, typeName: resolvedTypeName };
|
|
756
|
+
}
|
|
757
|
+
} else if (field.returnTypeInlineEnumMembers) {
|
|
758
|
+
// Handle inline enum in return type
|
|
759
|
+
const resolvedTypeName = enumTypeNames.get(payloadContextKey);
|
|
760
|
+
if (resolvedTypeName) {
|
|
761
|
+
updatedType = { ...field.type, typeName: resolvedTypeName };
|
|
762
|
+
}
|
|
763
|
+
} else if (field.returnTypeInlineUnionMembers) {
|
|
764
|
+
// Handle inline union in return type
|
|
765
|
+
const resolvedTypeName = unionTypeNames.get(payloadContextKey);
|
|
766
|
+
if (resolvedTypeName) {
|
|
767
|
+
updatedType = { ...field.type, typeName: resolvedTypeName };
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
if (!field.args) {
|
|
773
|
+
return {
|
|
774
|
+
...field,
|
|
775
|
+
type: updatedType,
|
|
776
|
+
};
|
|
777
|
+
}
|
|
646
778
|
|
|
647
779
|
const updatedArgs = field.args.map((arg) => {
|
|
648
780
|
const context: AutoTypeNameContext = {
|
|
@@ -683,11 +815,26 @@ function updateResolverField(
|
|
|
683
815
|
}
|
|
684
816
|
}
|
|
685
817
|
|
|
818
|
+
// Handle inline unions (OneOf input objects)
|
|
819
|
+
if (arg.inlineUnionMembers) {
|
|
820
|
+
const resolvedTypeName = unionTypeNames.get(contextKey);
|
|
821
|
+
if (resolvedTypeName) {
|
|
822
|
+
return {
|
|
823
|
+
...arg,
|
|
824
|
+
type: {
|
|
825
|
+
...arg.type,
|
|
826
|
+
typeName: resolvedTypeName,
|
|
827
|
+
},
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
|
|
686
832
|
return arg;
|
|
687
833
|
});
|
|
688
834
|
|
|
689
835
|
return {
|
|
690
836
|
...field,
|
|
837
|
+
type: updatedType,
|
|
691
838
|
args: updatedArgs,
|
|
692
839
|
};
|
|
693
840
|
}
|
|
@@ -726,6 +873,11 @@ interface ConvertEnumMembersWithDiagnosticsResult {
|
|
|
726
873
|
readonly diagnostics: ReadonlyArray<Diagnostic>;
|
|
727
874
|
}
|
|
728
875
|
|
|
876
|
+
interface ConvertedMemberInfo {
|
|
877
|
+
readonly convertedName: string;
|
|
878
|
+
readonly member: InlineEnumMemberInfo;
|
|
879
|
+
}
|
|
880
|
+
|
|
729
881
|
function convertInlineEnumMembers(
|
|
730
882
|
params: ConvertInlineEnumMembersParams,
|
|
731
883
|
): ConvertEnumMembersWithDiagnosticsResult {
|
|
@@ -734,32 +886,46 @@ function convertInlineEnumMembers(
|
|
|
734
886
|
const enumValues: AutoGeneratedEnumValue[] = [];
|
|
735
887
|
const diagnostics: Diagnostic[] = [];
|
|
736
888
|
|
|
737
|
-
const
|
|
889
|
+
const convertedMembers: ConvertedMemberInfo[] = [];
|
|
738
890
|
|
|
739
891
|
for (const member of members) {
|
|
740
892
|
const convertedName = toScreamingSnakeCase(member.value);
|
|
893
|
+
convertedMembers.push({ convertedName, member });
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
const prefixDetectionResult = detectEnumPrefix({
|
|
897
|
+
enumName,
|
|
898
|
+
memberValues: convertedMembers.map((m) => m.convertedName),
|
|
899
|
+
});
|
|
900
|
+
|
|
901
|
+
const finalNameToOriginals = new Map<string, string[]>();
|
|
741
902
|
|
|
742
|
-
|
|
903
|
+
for (const { convertedName, member } of convertedMembers) {
|
|
904
|
+
let finalName = convertedName;
|
|
905
|
+
if (prefixDetectionResult.shouldStrip && prefixDetectionResult.prefix) {
|
|
906
|
+
finalName = stripEnumPrefix(convertedName, prefixDetectionResult.prefix);
|
|
907
|
+
needsStringEnumMapping = true;
|
|
908
|
+
} else if (convertedName !== member.value) {
|
|
743
909
|
needsStringEnumMapping = true;
|
|
744
910
|
}
|
|
745
911
|
|
|
746
|
-
const originals =
|
|
912
|
+
const originals = finalNameToOriginals.get(finalName) ?? [];
|
|
747
913
|
originals.push(member.value);
|
|
748
|
-
|
|
914
|
+
finalNameToOriginals.set(finalName, originals);
|
|
749
915
|
|
|
750
916
|
enumValues.push({
|
|
751
|
-
name:
|
|
917
|
+
name: finalName,
|
|
752
918
|
originalValue: member.value,
|
|
753
919
|
description: member.description,
|
|
754
920
|
deprecated: member.deprecated,
|
|
755
921
|
});
|
|
756
922
|
}
|
|
757
923
|
|
|
758
|
-
for (const [
|
|
924
|
+
for (const [finalName, originals] of finalNameToOriginals) {
|
|
759
925
|
if (originals.length > 1) {
|
|
760
926
|
diagnostics.push({
|
|
761
927
|
code: "DUPLICATE_ENUM_VALUE_AFTER_CONVERSION",
|
|
762
|
-
message: `Enum '${enumName}' has duplicate value '${
|
|
928
|
+
message: `Enum '${enumName}' has duplicate value '${finalName}' after conversion (from '${originals.join("' and '")}')`,
|
|
763
929
|
severity: "error",
|
|
764
930
|
location: sourceLocation,
|
|
765
931
|
});
|
|
@@ -791,10 +957,12 @@ function generateAutoEnumType(
|
|
|
791
957
|
kind: "Enum",
|
|
792
958
|
fields: null,
|
|
793
959
|
enumValues,
|
|
960
|
+
unionMembers: null,
|
|
794
961
|
needsStringEnumMapping,
|
|
795
962
|
sourceLocation: inlineEnum.sourceLocation,
|
|
796
963
|
generatedFrom: buildGeneratedFromInfo(inlineEnum.context),
|
|
797
964
|
description: inlineEnum.externalEnumDescription,
|
|
965
|
+
resolveTypeFieldPattern: null,
|
|
798
966
|
},
|
|
799
967
|
diagnostics,
|
|
800
968
|
};
|
|
@@ -850,6 +1018,534 @@ function buildEnumTypeNamesMap(
|
|
|
850
1018
|
};
|
|
851
1019
|
}
|
|
852
1020
|
|
|
1021
|
+
function buildUnionTypeNamesMap(
|
|
1022
|
+
inlineUnions: InlineUnionWithContext[],
|
|
1023
|
+
): Map<string, string> {
|
|
1024
|
+
const unionTypeNames = new Map<string, string>();
|
|
1025
|
+
|
|
1026
|
+
for (const inlineUnion of inlineUnions) {
|
|
1027
|
+
const contextKey = getContextKey(inlineUnion.context);
|
|
1028
|
+
const typeName = generateAutoTypeName(inlineUnion.context);
|
|
1029
|
+
unionTypeNames.set(contextKey, typeName);
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
return unionTypeNames;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
interface ProcessInlineUnionsParams {
|
|
1036
|
+
readonly inlineUnions: ReadonlyArray<InlineUnionWithContext>;
|
|
1037
|
+
readonly knownTypeNames: ReadonlySet<string>;
|
|
1038
|
+
readonly generatedTypeNames: Map<string, string>;
|
|
1039
|
+
readonly enumTypeNames: Map<string, string>;
|
|
1040
|
+
readonly unionTypeNames: Map<string, string>;
|
|
1041
|
+
readonly extractedTypes: ReadonlyArray<ExtractedTypeInfo>;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
interface ProcessInlineUnionsResult {
|
|
1045
|
+
readonly types: AutoGeneratedType[];
|
|
1046
|
+
readonly diagnostics: Diagnostic[];
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
interface ProcessOneOfInputObjectsParams {
|
|
1050
|
+
readonly inlineUnions: ReadonlyArray<InlineUnionWithContext>;
|
|
1051
|
+
readonly knownTypeNames: ReadonlySet<string>;
|
|
1052
|
+
readonly typeMap: ReadonlyMap<string, ExtractedTypeInfo>;
|
|
1053
|
+
readonly unionTypeNames: Map<string, string>;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
function processOneOfInputObjects(
|
|
1057
|
+
params: ProcessOneOfInputObjectsParams,
|
|
1058
|
+
): ProcessInlineUnionsResult {
|
|
1059
|
+
const { inlineUnions, knownTypeNames, typeMap, unionTypeNames } = params;
|
|
1060
|
+
const types: AutoGeneratedType[] = [];
|
|
1061
|
+
const diagnostics: Diagnostic[] = [];
|
|
1062
|
+
|
|
1063
|
+
for (const inlineUnion of inlineUnions) {
|
|
1064
|
+
const contextKey = getContextKey(inlineUnion.context);
|
|
1065
|
+
const typeName = generateAutoTypeName(inlineUnion.context);
|
|
1066
|
+
|
|
1067
|
+
const validationResult = validateOneOfMembers({
|
|
1068
|
+
members: inlineUnion.members,
|
|
1069
|
+
typeName,
|
|
1070
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
1071
|
+
typeMap,
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1074
|
+
diagnostics.push(...validationResult.diagnostics);
|
|
1075
|
+
|
|
1076
|
+
if (!validationResult.valid) {
|
|
1077
|
+
continue;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
const fields = generateOneOfFields({
|
|
1081
|
+
members: inlineUnion.members,
|
|
1082
|
+
knownTypeNames,
|
|
1083
|
+
});
|
|
1084
|
+
|
|
1085
|
+
types.push({
|
|
1086
|
+
name: typeName,
|
|
1087
|
+
kind: "OneOfInputObject",
|
|
1088
|
+
fields,
|
|
1089
|
+
enumValues: null,
|
|
1090
|
+
unionMembers: null,
|
|
1091
|
+
needsStringEnumMapping: false,
|
|
1092
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
1093
|
+
generatedFrom: buildGeneratedFromInfo(inlineUnion.context),
|
|
1094
|
+
description: null,
|
|
1095
|
+
resolveTypeFieldPattern: null,
|
|
1096
|
+
});
|
|
1097
|
+
|
|
1098
|
+
unionTypeNames.set(contextKey, typeName);
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
return { types, diagnostics };
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
interface ProcessUnionTypesParams {
|
|
1105
|
+
readonly inlineUnions: ReadonlyArray<InlineUnionWithContext>;
|
|
1106
|
+
readonly knownTypeNames: ReadonlySet<string>;
|
|
1107
|
+
readonly generatedTypeNames: Map<string, string>;
|
|
1108
|
+
readonly enumTypeNames: Map<string, string>;
|
|
1109
|
+
readonly unionTypeNames: Map<string, string>;
|
|
1110
|
+
readonly typeMap: ReadonlyMap<string, ExtractedTypeInfo>;
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
function processUnionTypes(
|
|
1114
|
+
params: ProcessUnionTypesParams,
|
|
1115
|
+
): ProcessInlineUnionsResult {
|
|
1116
|
+
const {
|
|
1117
|
+
inlineUnions,
|
|
1118
|
+
knownTypeNames,
|
|
1119
|
+
generatedTypeNames,
|
|
1120
|
+
enumTypeNames,
|
|
1121
|
+
unionTypeNames,
|
|
1122
|
+
typeMap,
|
|
1123
|
+
} = params;
|
|
1124
|
+
const types: AutoGeneratedType[] = [];
|
|
1125
|
+
const diagnostics: Diagnostic[] = [];
|
|
1126
|
+
const generatedTypenameTypes = new Map<
|
|
1127
|
+
string,
|
|
1128
|
+
ReadonlyArray<AutoGeneratedField>
|
|
1129
|
+
>();
|
|
1130
|
+
|
|
1131
|
+
for (const inlineUnion of inlineUnions) {
|
|
1132
|
+
const contextKey = getContextKey(inlineUnion.context);
|
|
1133
|
+
const typeName = generateAutoTypeName(inlineUnion.context);
|
|
1134
|
+
|
|
1135
|
+
const validationResult = validateUnionMembers({
|
|
1136
|
+
members: inlineUnion.members,
|
|
1137
|
+
typeName,
|
|
1138
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
1139
|
+
typeMap,
|
|
1140
|
+
});
|
|
1141
|
+
|
|
1142
|
+
diagnostics.push(...validationResult.diagnostics);
|
|
1143
|
+
|
|
1144
|
+
if (!validationResult.valid) {
|
|
1145
|
+
continue;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
let resolveTypeFieldPattern: AutoGeneratedType["resolveTypeFieldPattern"] =
|
|
1149
|
+
null;
|
|
1150
|
+
|
|
1151
|
+
if (inlineUnion.context.kind === "resolverPayload") {
|
|
1152
|
+
const typenameValidationResult = validateUnionMemberTypenames({
|
|
1153
|
+
members: inlineUnion.members,
|
|
1154
|
+
unionTypeName: typeName,
|
|
1155
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
1156
|
+
typeMap,
|
|
1157
|
+
});
|
|
1158
|
+
|
|
1159
|
+
diagnostics.push(...typenameValidationResult.diagnostics);
|
|
1160
|
+
|
|
1161
|
+
if (!typenameValidationResult.valid) {
|
|
1162
|
+
continue;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
if (typenameValidationResult.allMembersHaveTypename) {
|
|
1166
|
+
resolveTypeFieldPattern = determineFieldPattern(
|
|
1167
|
+
typenameValidationResult.memberTypenames,
|
|
1168
|
+
);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
const memberNames = resolveMemberNames({
|
|
1173
|
+
members: inlineUnion.members,
|
|
1174
|
+
knownTypeNames,
|
|
1175
|
+
generatedTypeNames,
|
|
1176
|
+
enumTypeNames,
|
|
1177
|
+
parentContext: inlineUnion.context,
|
|
1178
|
+
unionTypeNames,
|
|
1179
|
+
types,
|
|
1180
|
+
diagnostics,
|
|
1181
|
+
generatedTypenameTypes,
|
|
1182
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
1183
|
+
});
|
|
1184
|
+
|
|
1185
|
+
types.push({
|
|
1186
|
+
name: typeName,
|
|
1187
|
+
kind: "Union",
|
|
1188
|
+
fields: null,
|
|
1189
|
+
enumValues: null,
|
|
1190
|
+
unionMembers: memberNames,
|
|
1191
|
+
needsStringEnumMapping: false,
|
|
1192
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
1193
|
+
generatedFrom: buildGeneratedFromInfo(inlineUnion.context),
|
|
1194
|
+
description: null,
|
|
1195
|
+
resolveTypeFieldPattern,
|
|
1196
|
+
});
|
|
1197
|
+
|
|
1198
|
+
unionTypeNames.set(contextKey, typeName);
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
return { types, diagnostics };
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
/**
|
|
1205
|
+
* Determine the field pattern for resolveType based on the typename fields used by members.
|
|
1206
|
+
*/
|
|
1207
|
+
function determineFieldPattern(
|
|
1208
|
+
memberTypenames: ReadonlyMap<number, ValidatedTypenameInfo>,
|
|
1209
|
+
): ResolveTypeFieldPattern {
|
|
1210
|
+
const fieldNames = new Set<TypenameFieldName>();
|
|
1211
|
+
for (const info of memberTypenames.values()) {
|
|
1212
|
+
fieldNames.add(info.fieldName);
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
if (fieldNames.size === 0) {
|
|
1216
|
+
return { usedFieldNames: createFieldNameSet(["__typename"]) };
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
return { usedFieldNames: fieldNames };
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
function processInlineUnions(
|
|
1223
|
+
params: ProcessInlineUnionsParams,
|
|
1224
|
+
): ProcessInlineUnionsResult {
|
|
1225
|
+
const {
|
|
1226
|
+
inlineUnions,
|
|
1227
|
+
knownTypeNames,
|
|
1228
|
+
generatedTypeNames,
|
|
1229
|
+
enumTypeNames,
|
|
1230
|
+
unionTypeNames,
|
|
1231
|
+
extractedTypes,
|
|
1232
|
+
} = params;
|
|
1233
|
+
|
|
1234
|
+
const typeMap = new Map<string, ExtractedTypeInfo>();
|
|
1235
|
+
for (const typeInfo of extractedTypes) {
|
|
1236
|
+
typeMap.set(typeInfo.metadata.name, typeInfo);
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
const inputUnions = inlineUnions.filter((u) => u.isInputContext);
|
|
1240
|
+
const outputUnions = inlineUnions.filter((u) => !u.isInputContext);
|
|
1241
|
+
|
|
1242
|
+
const oneOfResult = processOneOfInputObjects({
|
|
1243
|
+
inlineUnions: inputUnions,
|
|
1244
|
+
knownTypeNames,
|
|
1245
|
+
typeMap,
|
|
1246
|
+
unionTypeNames,
|
|
1247
|
+
});
|
|
1248
|
+
|
|
1249
|
+
const unionResult = processUnionTypes({
|
|
1250
|
+
inlineUnions: outputUnions,
|
|
1251
|
+
knownTypeNames,
|
|
1252
|
+
generatedTypeNames,
|
|
1253
|
+
enumTypeNames,
|
|
1254
|
+
unionTypeNames,
|
|
1255
|
+
typeMap,
|
|
1256
|
+
});
|
|
1257
|
+
|
|
1258
|
+
return {
|
|
1259
|
+
types: [...oneOfResult.types, ...unionResult.types],
|
|
1260
|
+
diagnostics: [...oneOfResult.diagnostics, ...unionResult.diagnostics],
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
interface GenerateOneOfFieldsParams {
|
|
1265
|
+
readonly members: ReadonlyArray<InlineUnionMemberInfo>;
|
|
1266
|
+
readonly knownTypeNames: ReadonlySet<string>;
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
function generateOneOfFields(
|
|
1270
|
+
params: GenerateOneOfFieldsParams,
|
|
1271
|
+
): AutoGeneratedField[] {
|
|
1272
|
+
const { members, knownTypeNames } = params;
|
|
1273
|
+
|
|
1274
|
+
const fields: AutoGeneratedField[] = [];
|
|
1275
|
+
|
|
1276
|
+
for (const member of members) {
|
|
1277
|
+
const memberType = member.memberType;
|
|
1278
|
+
|
|
1279
|
+
if (
|
|
1280
|
+
memberType.kind === "inlineObject" &&
|
|
1281
|
+
memberType.inlineObjectProperties
|
|
1282
|
+
) {
|
|
1283
|
+
for (const prop of memberType.inlineObjectProperties) {
|
|
1284
|
+
const fieldType = convertTsTypeToGraphQLType(
|
|
1285
|
+
prop.tsType,
|
|
1286
|
+
prop.optional,
|
|
1287
|
+
);
|
|
1288
|
+
fields.push({
|
|
1289
|
+
name: prop.name,
|
|
1290
|
+
type: {
|
|
1291
|
+
...fieldType,
|
|
1292
|
+
nullable: true,
|
|
1293
|
+
},
|
|
1294
|
+
description: prop.description,
|
|
1295
|
+
deprecated: prop.deprecated,
|
|
1296
|
+
directives: prop.directives,
|
|
1297
|
+
defaultValue: prop.defaultValue,
|
|
1298
|
+
});
|
|
1299
|
+
}
|
|
1300
|
+
} else if (memberType.kind === "reference" && memberType.name) {
|
|
1301
|
+
if (knownTypeNames.has(memberType.name)) {
|
|
1302
|
+
const camelCaseName =
|
|
1303
|
+
memberType.name.charAt(0).toLowerCase() + memberType.name.slice(1);
|
|
1304
|
+
fields.push({
|
|
1305
|
+
name: camelCaseName,
|
|
1306
|
+
type: {
|
|
1307
|
+
typeName: memberType.name,
|
|
1308
|
+
nullable: true,
|
|
1309
|
+
list: false,
|
|
1310
|
+
listItemNullable: null,
|
|
1311
|
+
},
|
|
1312
|
+
description: null,
|
|
1313
|
+
deprecated: null,
|
|
1314
|
+
directives: null,
|
|
1315
|
+
defaultValue: null,
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
return fields;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
interface ResolveMemberNamesParams {
|
|
1325
|
+
readonly members: ReadonlyArray<InlineUnionMemberInfo>;
|
|
1326
|
+
readonly knownTypeNames: ReadonlySet<string>;
|
|
1327
|
+
readonly generatedTypeNames: Map<string, string>;
|
|
1328
|
+
readonly enumTypeNames: Map<string, string>;
|
|
1329
|
+
readonly parentContext: AutoTypeNameContext;
|
|
1330
|
+
readonly unionTypeNames: Map<string, string>;
|
|
1331
|
+
readonly types: AutoGeneratedType[];
|
|
1332
|
+
readonly diagnostics: Diagnostic[];
|
|
1333
|
+
readonly generatedTypenameTypes: Map<
|
|
1334
|
+
string,
|
|
1335
|
+
ReadonlyArray<AutoGeneratedField>
|
|
1336
|
+
>;
|
|
1337
|
+
readonly sourceLocation: SourceLocation;
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
/**
|
|
1341
|
+
* Extract __typename or $typeName property value from inline object properties.
|
|
1342
|
+
* Returns null if neither is found or neither is a valid string literal.
|
|
1343
|
+
* __typename takes priority over $typeName if both are present.
|
|
1344
|
+
*/
|
|
1345
|
+
function extractTypenameFromInlineObject(
|
|
1346
|
+
properties: ReadonlyArray<InlineObjectPropertyDef>,
|
|
1347
|
+
): TypenameFieldInfo | null {
|
|
1348
|
+
const found = findTypenameProperty(properties, (p) => p.name);
|
|
1349
|
+
if (!found) {
|
|
1350
|
+
return null;
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
const { property, fieldName } = found;
|
|
1354
|
+
const { tsType } = property;
|
|
1355
|
+
|
|
1356
|
+
if (tsType.kind === "literal" && tsType.name !== null) {
|
|
1357
|
+
return { typeName: tsType.name, fieldName };
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
return null;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
function resolveMemberNames(params: ResolveMemberNamesParams): string[] {
|
|
1364
|
+
const {
|
|
1365
|
+
members,
|
|
1366
|
+
generatedTypeNames,
|
|
1367
|
+
parentContext,
|
|
1368
|
+
types,
|
|
1369
|
+
generatedTypenameTypes,
|
|
1370
|
+
diagnostics,
|
|
1371
|
+
sourceLocation,
|
|
1372
|
+
} = params;
|
|
1373
|
+
|
|
1374
|
+
const memberNames: string[] = [];
|
|
1375
|
+
|
|
1376
|
+
for (let i = 0; i < members.length; i++) {
|
|
1377
|
+
const member = members[i]!;
|
|
1378
|
+
const memberType = member.memberType;
|
|
1379
|
+
|
|
1380
|
+
if (memberType.kind === "reference" && memberType.name) {
|
|
1381
|
+
memberNames.push(memberType.name);
|
|
1382
|
+
} else if (
|
|
1383
|
+
memberType.kind === "inlineObject" &&
|
|
1384
|
+
memberType.inlineObjectProperties
|
|
1385
|
+
) {
|
|
1386
|
+
// Only extract __typename or $typeName for resolverPayload context
|
|
1387
|
+
// For other contexts (resolverArg, objectField, inputField), these fields
|
|
1388
|
+
// should be treated as regular fields, not as type discriminators
|
|
1389
|
+
const extractedInfo =
|
|
1390
|
+
parentContext.kind === "resolverPayload"
|
|
1391
|
+
? extractTypenameFromInlineObject(memberType.inlineObjectProperties)
|
|
1392
|
+
: null;
|
|
1393
|
+
|
|
1394
|
+
let memberTypeName: string;
|
|
1395
|
+
let contextKey: string;
|
|
1396
|
+
|
|
1397
|
+
if (extractedInfo !== null) {
|
|
1398
|
+
memberTypeName = extractedInfo.typeName;
|
|
1399
|
+
const nestedContext: AutoTypeNameContext = {
|
|
1400
|
+
...parentContext,
|
|
1401
|
+
fieldPath: [...parentContext.fieldPath, extractedInfo.typeName],
|
|
1402
|
+
};
|
|
1403
|
+
contextKey = getContextKey(nestedContext);
|
|
1404
|
+
} else {
|
|
1405
|
+
const nestedContext: AutoTypeNameContext = {
|
|
1406
|
+
...parentContext,
|
|
1407
|
+
fieldPath: [...parentContext.fieldPath, `member${i}`],
|
|
1408
|
+
};
|
|
1409
|
+
memberTypeName = generateAutoTypeName(nestedContext);
|
|
1410
|
+
contextKey = getContextKey(nestedContext);
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
// Only filter out __typename or $typeName for resolverPayload context
|
|
1414
|
+
// For other contexts, these are regular fields that should be preserved
|
|
1415
|
+
const typenameFieldToFilter = extractedInfo?.fieldName ?? null;
|
|
1416
|
+
const fields: AutoGeneratedField[] = memberType.inlineObjectProperties
|
|
1417
|
+
.filter(
|
|
1418
|
+
(prop) =>
|
|
1419
|
+
parentContext.kind !== "resolverPayload" ||
|
|
1420
|
+
prop.name !== typenameFieldToFilter,
|
|
1421
|
+
)
|
|
1422
|
+
.map((prop) => {
|
|
1423
|
+
const fieldType = convertTsTypeToGraphQLType(
|
|
1424
|
+
prop.tsType,
|
|
1425
|
+
prop.optional,
|
|
1426
|
+
);
|
|
1427
|
+
return {
|
|
1428
|
+
name: prop.name,
|
|
1429
|
+
type: fieldType,
|
|
1430
|
+
description: prop.description,
|
|
1431
|
+
deprecated: prop.deprecated,
|
|
1432
|
+
directives: prop.directives,
|
|
1433
|
+
defaultValue: prop.defaultValue,
|
|
1434
|
+
};
|
|
1435
|
+
});
|
|
1436
|
+
|
|
1437
|
+
// Check if this typename was already seen with a different field structure
|
|
1438
|
+
if (extractedInfo !== null) {
|
|
1439
|
+
const existingFields = generatedTypenameTypes.get(
|
|
1440
|
+
extractedInfo.typeName,
|
|
1441
|
+
);
|
|
1442
|
+
if (existingFields !== undefined) {
|
|
1443
|
+
// Compare field structures
|
|
1444
|
+
if (!areFieldStructuresEqual(existingFields, fields)) {
|
|
1445
|
+
diagnostics.push({
|
|
1446
|
+
code: "TYPENAME_FIELD_STRUCTURE_MISMATCH",
|
|
1447
|
+
message: `Type with ${extractedInfo.fieldName} '${extractedInfo.typeName}' has inconsistent field structures across different union members. All types with the same ${extractedInfo.fieldName} must have identical field definitions.`,
|
|
1448
|
+
severity: "error",
|
|
1449
|
+
location: sourceLocation,
|
|
1450
|
+
});
|
|
1451
|
+
}
|
|
1452
|
+
// Skip generating duplicate type and avoid adding duplicate union member
|
|
1453
|
+
if (!memberNames.includes(memberTypeName)) {
|
|
1454
|
+
memberNames.push(memberTypeName);
|
|
1455
|
+
}
|
|
1456
|
+
continue;
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
const nestedContext: AutoTypeNameContext = {
|
|
1461
|
+
...parentContext,
|
|
1462
|
+
fieldPath: [
|
|
1463
|
+
...parentContext.fieldPath,
|
|
1464
|
+
extractedInfo?.typeName ?? `member${i}`,
|
|
1465
|
+
],
|
|
1466
|
+
};
|
|
1467
|
+
|
|
1468
|
+
types.push({
|
|
1469
|
+
name: memberTypeName,
|
|
1470
|
+
kind: "Object",
|
|
1471
|
+
fields,
|
|
1472
|
+
enumValues: null,
|
|
1473
|
+
unionMembers: null,
|
|
1474
|
+
needsStringEnumMapping: false,
|
|
1475
|
+
sourceLocation: {
|
|
1476
|
+
file: "",
|
|
1477
|
+
line: 1,
|
|
1478
|
+
column: 1,
|
|
1479
|
+
},
|
|
1480
|
+
generatedFrom: buildGeneratedFromInfo(nestedContext),
|
|
1481
|
+
description: memberType.inlineObjectDescription,
|
|
1482
|
+
resolveTypeFieldPattern: null,
|
|
1483
|
+
});
|
|
1484
|
+
|
|
1485
|
+
generatedTypeNames.set(contextKey, memberTypeName);
|
|
1486
|
+
if (extractedInfo !== null) {
|
|
1487
|
+
generatedTypenameTypes.set(extractedInfo.typeName, fields);
|
|
1488
|
+
}
|
|
1489
|
+
memberNames.push(memberTypeName);
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
return memberNames;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
/**
|
|
1497
|
+
* Compare two field structures for equality.
|
|
1498
|
+
* Returns true if both have the same fields with the same types.
|
|
1499
|
+
*/
|
|
1500
|
+
function areFieldStructuresEqual(
|
|
1501
|
+
fields1: ReadonlyArray<AutoGeneratedField>,
|
|
1502
|
+
fields2: ReadonlyArray<AutoGeneratedField>,
|
|
1503
|
+
): boolean {
|
|
1504
|
+
if (fields1.length !== fields2.length) {
|
|
1505
|
+
return false;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
const sorted1 = [...fields1].sort((a, b) => a.name.localeCompare(b.name));
|
|
1509
|
+
const sorted2 = [...fields2].sort((a, b) => a.name.localeCompare(b.name));
|
|
1510
|
+
|
|
1511
|
+
for (let i = 0; i < sorted1.length; i++) {
|
|
1512
|
+
const f1 = sorted1[i]!;
|
|
1513
|
+
const f2 = sorted2[i]!;
|
|
1514
|
+
|
|
1515
|
+
if (f1.name !== f2.name) {
|
|
1516
|
+
return false;
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
if (!areGraphQLTypesEqual(f1.type, f2.type)) {
|
|
1520
|
+
return false;
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
return true;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
/**
|
|
1528
|
+
* Compare two GraphQL type references for equality.
|
|
1529
|
+
*/
|
|
1530
|
+
function areGraphQLTypesEqual(
|
|
1531
|
+
type1: GraphQLFieldType,
|
|
1532
|
+
type2: GraphQLFieldType,
|
|
1533
|
+
): boolean {
|
|
1534
|
+
if (type1.typeName !== type2.typeName) {
|
|
1535
|
+
return false;
|
|
1536
|
+
}
|
|
1537
|
+
if (type1.nullable !== type2.nullable) {
|
|
1538
|
+
return false;
|
|
1539
|
+
}
|
|
1540
|
+
if (type1.list !== type2.list) {
|
|
1541
|
+
return false;
|
|
1542
|
+
}
|
|
1543
|
+
if (type1.listItemNullable !== type2.listItemNullable) {
|
|
1544
|
+
return false;
|
|
1545
|
+
}
|
|
1546
|
+
return true;
|
|
1547
|
+
}
|
|
1548
|
+
|
|
853
1549
|
export function generateAutoTypes(
|
|
854
1550
|
input: AutoTypeGeneratorInput,
|
|
855
1551
|
): AutoTypeGeneratorResult {
|
|
@@ -862,9 +1558,14 @@ export function generateAutoTypes(
|
|
|
862
1558
|
input.resolversResult,
|
|
863
1559
|
);
|
|
864
1560
|
|
|
1561
|
+
const inlinePayloadsFromResolvers = collectInlinePayloadsFromResolvers(
|
|
1562
|
+
input.resolversResult,
|
|
1563
|
+
);
|
|
1564
|
+
|
|
865
1565
|
const allInlineObjects = [
|
|
866
1566
|
...inlineObjectsFromTypes,
|
|
867
1567
|
...inlineObjectsFromResolvers,
|
|
1568
|
+
...inlinePayloadsFromResolvers,
|
|
868
1569
|
];
|
|
869
1570
|
|
|
870
1571
|
const generatedTypeNames = buildGeneratedTypeNamesMap(allInlineObjects);
|
|
@@ -872,14 +1573,43 @@ export function generateAutoTypes(
|
|
|
872
1573
|
const inlineEnumsFromTypes = collectInlineEnumsFromTypes(
|
|
873
1574
|
input.extractedTypes,
|
|
874
1575
|
);
|
|
875
|
-
const inlineEnumsFromResolvers = collectInlineEnumsFromResolvers(
|
|
876
|
-
input.resolversResult,
|
|
877
|
-
);
|
|
878
|
-
const
|
|
1576
|
+
const inlineEnumsFromResolvers = collectInlineEnumsFromResolvers({
|
|
1577
|
+
resolversResult: input.resolversResult,
|
|
1578
|
+
});
|
|
1579
|
+
const inlineEnumsFromPayloads = collectInlineEnumsFromPayloads({
|
|
1580
|
+
resolversResult: input.resolversResult,
|
|
1581
|
+
});
|
|
1582
|
+
const allInlineEnums = [
|
|
1583
|
+
...inlineEnumsFromTypes,
|
|
1584
|
+
...inlineEnumsFromResolvers,
|
|
1585
|
+
...inlineEnumsFromPayloads,
|
|
1586
|
+
];
|
|
879
1587
|
|
|
880
1588
|
const { enumTypeNames, uniqueInlineEnums } =
|
|
881
1589
|
buildEnumTypeNamesMap(allInlineEnums);
|
|
882
1590
|
|
|
1591
|
+
// Collect inline unions from types, resolvers, and payloads
|
|
1592
|
+
const inlineUnionsFromTypes = collectInlineUnionsFromTypes({
|
|
1593
|
+
extractedTypes: input.extractedTypes,
|
|
1594
|
+
knownTypeNames: input.knownTypeNames,
|
|
1595
|
+
});
|
|
1596
|
+
const inlineUnionsFromResolvers = collectInlineUnionsFromResolvers({
|
|
1597
|
+
resolversResult: input.resolversResult,
|
|
1598
|
+
knownTypeNames: input.knownTypeNames,
|
|
1599
|
+
});
|
|
1600
|
+
const inlineUnionsFromPayloads = collectInlineUnionsFromPayloads({
|
|
1601
|
+
resolversResult: input.resolversResult,
|
|
1602
|
+
knownTypeNames: input.knownTypeNames,
|
|
1603
|
+
});
|
|
1604
|
+
const allInlineUnions = [
|
|
1605
|
+
...inlineUnionsFromTypes,
|
|
1606
|
+
...inlineUnionsFromResolvers,
|
|
1607
|
+
...inlineUnionsFromPayloads,
|
|
1608
|
+
];
|
|
1609
|
+
|
|
1610
|
+
// Build union type names map before generating auto types
|
|
1611
|
+
const unionTypeNames = buildUnionTypeNamesMap(allInlineUnions);
|
|
1612
|
+
|
|
883
1613
|
const autoGeneratedTypes: AutoGeneratedType[] = [];
|
|
884
1614
|
const diagnostics: Diagnostic[] = [];
|
|
885
1615
|
|
|
@@ -888,6 +1618,7 @@ export function generateAutoTypes(
|
|
|
888
1618
|
inlineObj,
|
|
889
1619
|
generatedTypeNames,
|
|
890
1620
|
enumTypeNames,
|
|
1621
|
+
unionTypeNames,
|
|
891
1622
|
});
|
|
892
1623
|
autoGeneratedTypes.push(result.type);
|
|
893
1624
|
diagnostics.push(...result.diagnostics);
|
|
@@ -901,9 +1632,23 @@ export function generateAutoTypes(
|
|
|
901
1632
|
diagnostics.push(...result.diagnostics);
|
|
902
1633
|
}
|
|
903
1634
|
|
|
1635
|
+
// Process inline unions
|
|
1636
|
+
const { types: unionTypes, diagnostics: unionDiagnostics } =
|
|
1637
|
+
processInlineUnions({
|
|
1638
|
+
inlineUnions: allInlineUnions,
|
|
1639
|
+
knownTypeNames: input.knownTypeNames,
|
|
1640
|
+
generatedTypeNames,
|
|
1641
|
+
enumTypeNames,
|
|
1642
|
+
unionTypeNames,
|
|
1643
|
+
extractedTypes: input.extractedTypes,
|
|
1644
|
+
});
|
|
1645
|
+
autoGeneratedTypes.push(...unionTypes);
|
|
1646
|
+
diagnostics.push(...unionDiagnostics);
|
|
1647
|
+
|
|
904
1648
|
const updateParams: UpdateTypeNamesParams = {
|
|
905
1649
|
generatedTypeNames,
|
|
906
1650
|
enumTypeNames,
|
|
1651
|
+
unionTypeNames,
|
|
907
1652
|
};
|
|
908
1653
|
|
|
909
1654
|
const updatedExtractedTypes = updateExtractedTypes(
|