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