@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
|
@@ -1,10 +1,46 @@
|
|
|
1
|
+
import { detectEnumPrefix, stripEnumPrefix, } from "../shared/enum-prefix-detector.js";
|
|
2
|
+
import { getSourceLocationOrDefault } from "../shared/source-location.js";
|
|
3
|
+
import { toScreamingSnakeCase } from "../shared/string-utils.js";
|
|
1
4
|
import { convertTsTypeToGraphQLType } from "../shared/type-converter.js";
|
|
2
|
-
import {
|
|
5
|
+
import { isEligibleField } from "../type-extractor/converter/field-eligibility.js";
|
|
3
6
|
import { createReferenceType, } from "../type-extractor/types/index.js";
|
|
4
|
-
import { collectInlineEnumsFromResolvers, collectInlineEnumsFromTypes, } from "./inline-enum-collector.js";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
import { collectInlineEnumsFromPayloads, collectInlineEnumsFromResolvers, collectInlineEnumsFromTypes, } from "./inline-enum-collector.js";
|
|
8
|
+
import { collectInlineUnionsFromPayloads, collectInlineUnionsFromResolvers, collectInlineUnionsFromTypes, } from "./inline-union-collector.js";
|
|
9
|
+
import { validateOneOfMembers, validateUnionMembers, validateUnionMemberTypenames, } from "./inline-union-validator.js";
|
|
10
|
+
import { buildFieldContext, generateAutoTypeName, isInputTypeName, } from "./naming-convention.js";
|
|
11
|
+
import { forEachResolverField } from "./resolver-field-iterator.js";
|
|
12
|
+
import { createFieldNameSet, findTypenameProperty, } from "./typename-types.js";
|
|
13
|
+
function extractNestedInlineObjectsRecursively(params) {
|
|
14
|
+
const { properties, currentPath, sourceLocation, buildContext, preserveDocumentation, results, } = params;
|
|
15
|
+
for (const prop of properties) {
|
|
16
|
+
if (prop.tsType.kind === "inlineObject" &&
|
|
17
|
+
prop.tsType.inlineObjectProperties) {
|
|
18
|
+
const nestedPath = [...currentPath, prop.name];
|
|
19
|
+
const nestedContext = buildContext(nestedPath);
|
|
20
|
+
// Use property's source location if available for more accurate diagnostics
|
|
21
|
+
const nestedSourceLocation = prop.sourceLocation ?? sourceLocation;
|
|
22
|
+
results.push({
|
|
23
|
+
properties: prop.tsType.inlineObjectProperties,
|
|
24
|
+
context: nestedContext,
|
|
25
|
+
sourceLocation: nestedSourceLocation,
|
|
26
|
+
nullable: prop.tsType.nullable,
|
|
27
|
+
description: preserveDocumentation
|
|
28
|
+
? prop.tsType.inlineObjectDescription
|
|
29
|
+
: null,
|
|
30
|
+
deprecated: preserveDocumentation
|
|
31
|
+
? prop.tsType.inlineObjectDeprecated
|
|
32
|
+
: null,
|
|
33
|
+
});
|
|
34
|
+
extractNestedInlineObjectsRecursively({
|
|
35
|
+
properties: prop.tsType.inlineObjectProperties,
|
|
36
|
+
currentPath: nestedPath,
|
|
37
|
+
sourceLocation: nestedSourceLocation,
|
|
38
|
+
buildContext,
|
|
39
|
+
preserveDocumentation,
|
|
40
|
+
results,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
8
44
|
}
|
|
9
45
|
function getContextKey(context) {
|
|
10
46
|
switch (context.kind) {
|
|
@@ -14,6 +50,8 @@ function getContextKey(context) {
|
|
|
14
50
|
return `inputField:${context.parentTypeName}:${context.fieldPath.join(".")}`;
|
|
15
51
|
case "resolverArg":
|
|
16
52
|
return `resolverArg:${context.resolverType}:${context.parentTypeName ?? ""}:${context.fieldName}:${context.argName}:${context.fieldPath.join(".")}`;
|
|
53
|
+
case "resolverPayload":
|
|
54
|
+
return `resolverPayload:${context.resolverType}:${context.parentTypeName ?? ""}:${context.fieldName}:${context.fieldPath.join(".")}`;
|
|
17
55
|
}
|
|
18
56
|
}
|
|
19
57
|
function mapContextKindToGeneratedFromContext(kind) {
|
|
@@ -24,6 +62,8 @@ function mapContextKindToGeneratedFromContext(kind) {
|
|
|
24
62
|
return "inputField";
|
|
25
63
|
case "resolverArg":
|
|
26
64
|
return "resolverArg";
|
|
65
|
+
case "resolverPayload":
|
|
66
|
+
return "resolverPayload";
|
|
27
67
|
}
|
|
28
68
|
}
|
|
29
69
|
function buildGeneratedFromInfo(context) {
|
|
@@ -40,11 +80,19 @@ function collectInlineObjectsFromType(typeInfo) {
|
|
|
40
80
|
const results = [];
|
|
41
81
|
const isInput = isInputTypeName(typeInfo.metadata.name);
|
|
42
82
|
for (const field of typeInfo.fields) {
|
|
43
|
-
collectInlineObjectsFromField(
|
|
83
|
+
collectInlineObjectsFromField({
|
|
84
|
+
field,
|
|
85
|
+
parentTypeName: typeInfo.metadata.name,
|
|
86
|
+
parentPath: [],
|
|
87
|
+
isInput,
|
|
88
|
+
sourceFile: typeInfo.metadata.sourceFile,
|
|
89
|
+
results,
|
|
90
|
+
});
|
|
44
91
|
}
|
|
45
92
|
return results;
|
|
46
93
|
}
|
|
47
|
-
function collectInlineObjectsFromField(
|
|
94
|
+
function collectInlineObjectsFromField(params) {
|
|
95
|
+
const { field, parentTypeName, parentPath, isInput, sourceFile, results } = params;
|
|
48
96
|
const tsType = field.tsType;
|
|
49
97
|
if (tsType.kind !== "inlineObject" || !tsType.inlineObjectProperties) {
|
|
50
98
|
return;
|
|
@@ -61,78 +109,31 @@ function collectInlineObjectsFromField(field, parentTypeName, parentPath, isInpu
|
|
|
61
109
|
parentTypeName,
|
|
62
110
|
fieldPath,
|
|
63
111
|
};
|
|
112
|
+
const sourceLocation = getSourceLocationOrDefault(field.sourceLocation, sourceFile);
|
|
64
113
|
results.push({
|
|
65
114
|
properties: tsType.inlineObjectProperties,
|
|
66
115
|
context,
|
|
67
|
-
sourceLocation
|
|
68
|
-
file: sourceFile,
|
|
69
|
-
line: 1,
|
|
70
|
-
column: 1,
|
|
71
|
-
},
|
|
116
|
+
sourceLocation,
|
|
72
117
|
nullable: tsType.nullable,
|
|
118
|
+
description: tsType.inlineObjectDescription,
|
|
119
|
+
deprecated: tsType.inlineObjectDeprecated,
|
|
73
120
|
});
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
: {
|
|
85
|
-
kind: "objectField",
|
|
86
|
-
parentTypeName,
|
|
87
|
-
fieldPath: nestedPath,
|
|
88
|
-
};
|
|
89
|
-
extractNestedInlineObjects(prop.tsType.inlineObjectProperties, nestedContext, nestedPath, parentTypeName, isInput, sourceFile, prop.sourceLocation, results);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
function extractNestedInlineObjects(properties, context, currentPath, parentTypeName, isInput, sourceFile, parentSourceLocation, results) {
|
|
94
|
-
results.push({
|
|
95
|
-
properties,
|
|
96
|
-
context,
|
|
97
|
-
sourceLocation: parentSourceLocation ?? {
|
|
98
|
-
file: sourceFile,
|
|
99
|
-
line: 1,
|
|
100
|
-
column: 1,
|
|
101
|
-
},
|
|
102
|
-
nullable: false,
|
|
121
|
+
extractNestedInlineObjectsRecursively({
|
|
122
|
+
properties: tsType.inlineObjectProperties,
|
|
123
|
+
currentPath: fieldPath,
|
|
124
|
+
sourceLocation,
|
|
125
|
+
buildContext: (nestedPath) => isInput
|
|
126
|
+
? { kind: "inputField", parentTypeName, fieldPath: nestedPath }
|
|
127
|
+
: { kind: "objectField", parentTypeName, fieldPath: nestedPath },
|
|
128
|
+
preserveDocumentation: true,
|
|
129
|
+
results,
|
|
103
130
|
});
|
|
104
|
-
for (const prop of properties) {
|
|
105
|
-
if (prop.tsType.kind === "inlineObject" &&
|
|
106
|
-
prop.tsType.inlineObjectProperties) {
|
|
107
|
-
const nestedPath = [...currentPath, prop.name];
|
|
108
|
-
const nestedContext = isInput
|
|
109
|
-
? {
|
|
110
|
-
kind: "inputField",
|
|
111
|
-
parentTypeName,
|
|
112
|
-
fieldPath: nestedPath,
|
|
113
|
-
}
|
|
114
|
-
: {
|
|
115
|
-
kind: "objectField",
|
|
116
|
-
parentTypeName,
|
|
117
|
-
fieldPath: nestedPath,
|
|
118
|
-
};
|
|
119
|
-
extractNestedInlineObjects(prop.tsType.inlineObjectProperties, nestedContext, nestedPath, parentTypeName, isInput, sourceFile, prop.sourceLocation, results);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
131
|
}
|
|
123
132
|
function collectInlineObjectsFromResolvers(resolversResult) {
|
|
124
133
|
const results = [];
|
|
125
|
-
|
|
126
|
-
collectInlineObjectsFromResolverArgs(field,
|
|
127
|
-
}
|
|
128
|
-
for (const field of resolversResult.mutationFields.fields) {
|
|
129
|
-
collectInlineObjectsFromResolverArgs(field, "mutation", null, results);
|
|
130
|
-
}
|
|
131
|
-
for (const ext of resolversResult.typeExtensions) {
|
|
132
|
-
for (const field of ext.fields) {
|
|
133
|
-
collectInlineObjectsFromResolverArgs(field, "field", ext.targetTypeName, results);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
134
|
+
forEachResolverField(resolversResult, ({ field, resolverType, parentTypeName }) => {
|
|
135
|
+
collectInlineObjectsFromResolverArgs(field, resolverType, parentTypeName, results);
|
|
136
|
+
});
|
|
136
137
|
return results;
|
|
137
138
|
}
|
|
138
139
|
function collectInlineObjectsFromResolverArgs(field, resolverType, parentTypeName, results) {
|
|
@@ -154,44 +155,78 @@ function collectInlineObjectsFromResolverArgs(field, resolverType, parentTypeNam
|
|
|
154
155
|
context,
|
|
155
156
|
sourceLocation: field.sourceLocation,
|
|
156
157
|
nullable: arg.type.nullable,
|
|
158
|
+
description: null,
|
|
159
|
+
deprecated: null,
|
|
157
160
|
});
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (prop.tsType.kind === "inlineObject" &&
|
|
164
|
-
prop.tsType.inlineObjectProperties) {
|
|
165
|
-
const nestedPath = [...currentPath, prop.name];
|
|
166
|
-
const nestedContext = {
|
|
161
|
+
extractNestedInlineObjectsRecursively({
|
|
162
|
+
properties: arg.inlineObjectProperties,
|
|
163
|
+
currentPath: [],
|
|
164
|
+
sourceLocation: field.sourceLocation,
|
|
165
|
+
buildContext: (nestedPath) => ({
|
|
167
166
|
kind: "resolverArg",
|
|
168
167
|
resolverType,
|
|
169
|
-
fieldName,
|
|
170
|
-
argName,
|
|
168
|
+
fieldName: field.name,
|
|
169
|
+
argName: arg.name,
|
|
171
170
|
parentTypeName,
|
|
172
171
|
fieldPath: nestedPath,
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
sourceLocation,
|
|
178
|
-
nullable: prop.tsType.nullable,
|
|
179
|
-
});
|
|
180
|
-
extractNestedInlineObjectsFromArg(prop.tsType.inlineObjectProperties, resolverType, fieldName, argName, parentTypeName, nestedPath, sourceLocation, results);
|
|
181
|
-
}
|
|
172
|
+
}),
|
|
173
|
+
preserveDocumentation: false,
|
|
174
|
+
results,
|
|
175
|
+
});
|
|
182
176
|
}
|
|
183
177
|
}
|
|
178
|
+
function collectInlinePayloadsFromResolvers(resolversResult) {
|
|
179
|
+
const results = [];
|
|
180
|
+
forEachResolverField(resolversResult, ({ field, resolverType, parentTypeName }) => {
|
|
181
|
+
collectInlinePayloadFromReturnType(field, resolverType, parentTypeName, results);
|
|
182
|
+
});
|
|
183
|
+
return results;
|
|
184
|
+
}
|
|
185
|
+
function collectInlinePayloadFromReturnType(field, resolverType, parentTypeName, results) {
|
|
186
|
+
if (!field.returnTypeInlineObjectProperties)
|
|
187
|
+
return;
|
|
188
|
+
const context = {
|
|
189
|
+
kind: "resolverPayload",
|
|
190
|
+
resolverType,
|
|
191
|
+
fieldName: field.name,
|
|
192
|
+
parentTypeName,
|
|
193
|
+
fieldPath: [],
|
|
194
|
+
};
|
|
195
|
+
results.push({
|
|
196
|
+
properties: field.returnTypeInlineObjectProperties,
|
|
197
|
+
context,
|
|
198
|
+
sourceLocation: field.sourceLocation,
|
|
199
|
+
nullable: field.type.nullable,
|
|
200
|
+
description: field.returnTypeInlineObjectDescription,
|
|
201
|
+
deprecated: field.returnTypeInlineObjectDeprecated,
|
|
202
|
+
});
|
|
203
|
+
extractNestedInlineObjectsRecursively({
|
|
204
|
+
properties: field.returnTypeInlineObjectProperties,
|
|
205
|
+
currentPath: [],
|
|
206
|
+
sourceLocation: field.sourceLocation,
|
|
207
|
+
buildContext: (nestedPath) => ({
|
|
208
|
+
kind: "resolverPayload",
|
|
209
|
+
resolverType,
|
|
210
|
+
fieldName: field.name,
|
|
211
|
+
parentTypeName,
|
|
212
|
+
fieldPath: nestedPath,
|
|
213
|
+
}),
|
|
214
|
+
preserveDocumentation: true,
|
|
215
|
+
results,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
184
218
|
function generateAutoType(params) {
|
|
185
|
-
const { inlineObj, generatedTypeNames, enumTypeNames } = params;
|
|
219
|
+
const { inlineObj, generatedTypeNames, enumTypeNames, unionTypeNames } = params;
|
|
186
220
|
const name = generateAutoTypeName(inlineObj.context);
|
|
187
221
|
const isInput = inlineObj.context.kind === "inputField" ||
|
|
188
222
|
inlineObj.context.kind === "resolverArg";
|
|
189
223
|
const fields = [];
|
|
190
224
|
const diagnostics = [];
|
|
191
225
|
for (const prop of inlineObj.properties) {
|
|
192
|
-
const eligibility =
|
|
193
|
-
|
|
194
|
-
:
|
|
226
|
+
const eligibility = isEligibleField({
|
|
227
|
+
fieldName: prop.name,
|
|
228
|
+
kind: isInput ? "input" : "object",
|
|
229
|
+
});
|
|
195
230
|
if (!eligibility.eligible) {
|
|
196
231
|
diagnostics.push({
|
|
197
232
|
code: "SKIPPED_FIELD",
|
|
@@ -205,6 +240,7 @@ function generateAutoType(params) {
|
|
|
205
240
|
prop,
|
|
206
241
|
generatedTypeNames,
|
|
207
242
|
enumTypeNames,
|
|
243
|
+
unionTypeNames,
|
|
208
244
|
parentContext: inlineObj.context,
|
|
209
245
|
});
|
|
210
246
|
fields.push({
|
|
@@ -222,50 +258,51 @@ function generateAutoType(params) {
|
|
|
222
258
|
kind: isInput ? "InputObject" : "Object",
|
|
223
259
|
fields,
|
|
224
260
|
enumValues: null,
|
|
261
|
+
unionMembers: null,
|
|
225
262
|
needsStringEnumMapping: false,
|
|
226
263
|
sourceLocation: inlineObj.sourceLocation,
|
|
227
264
|
generatedFrom: buildGeneratedFromInfo(inlineObj.context),
|
|
228
|
-
description:
|
|
265
|
+
description: inlineObj.description,
|
|
266
|
+
resolveTypeFieldPattern: null,
|
|
229
267
|
},
|
|
230
268
|
diagnostics,
|
|
231
269
|
};
|
|
232
270
|
}
|
|
271
|
+
function tryResolveNestedType(prop, parentContext, typeNamesMap) {
|
|
272
|
+
const nestedPath = [...parentContext.fieldPath, prop.name];
|
|
273
|
+
const nestedContext = {
|
|
274
|
+
...parentContext,
|
|
275
|
+
fieldPath: nestedPath,
|
|
276
|
+
};
|
|
277
|
+
const contextKey = getContextKey(nestedContext);
|
|
278
|
+
const resolvedTypeName = typeNamesMap.get(contextKey);
|
|
279
|
+
if (resolvedTypeName) {
|
|
280
|
+
return {
|
|
281
|
+
typeName: resolvedTypeName,
|
|
282
|
+
nullable: prop.tsType.nullable || prop.optional,
|
|
283
|
+
list: false,
|
|
284
|
+
listItemNullable: null,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
233
289
|
function resolveFieldType(params) {
|
|
234
|
-
const { prop, generatedTypeNames, enumTypeNames, parentContext } = params;
|
|
290
|
+
const { prop, generatedTypeNames, enumTypeNames, unionTypeNames, parentContext, } = params;
|
|
235
291
|
if (prop.tsType.kind === "inlineObject" &&
|
|
236
292
|
prop.tsType.inlineObjectProperties) {
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
fieldPath: nestedPath,
|
|
241
|
-
};
|
|
242
|
-
const contextKey = getContextKey(nestedContext);
|
|
243
|
-
const resolvedTypeName = generatedTypeNames.get(contextKey);
|
|
244
|
-
if (resolvedTypeName) {
|
|
245
|
-
return {
|
|
246
|
-
typeName: resolvedTypeName,
|
|
247
|
-
nullable: prop.tsType.nullable || prop.optional,
|
|
248
|
-
list: false,
|
|
249
|
-
listItemNullable: null,
|
|
250
|
-
};
|
|
251
|
-
}
|
|
293
|
+
const result = tryResolveNestedType(prop, parentContext, generatedTypeNames);
|
|
294
|
+
if (result)
|
|
295
|
+
return result;
|
|
252
296
|
}
|
|
253
297
|
if (prop.tsType.kind === "inlineEnum" && prop.tsType.inlineEnumMembers) {
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
return {
|
|
263
|
-
typeName: resolvedTypeName,
|
|
264
|
-
nullable: prop.tsType.nullable || prop.optional,
|
|
265
|
-
list: false,
|
|
266
|
-
listItemNullable: null,
|
|
267
|
-
};
|
|
268
|
-
}
|
|
298
|
+
const result = tryResolveNestedType(prop, parentContext, enumTypeNames);
|
|
299
|
+
if (result)
|
|
300
|
+
return result;
|
|
301
|
+
}
|
|
302
|
+
if (prop.tsType.kind === "union" && prop.tsType.members) {
|
|
303
|
+
const result = tryResolveNestedType(prop, parentContext, unionTypeNames);
|
|
304
|
+
if (result)
|
|
305
|
+
return result;
|
|
269
306
|
}
|
|
270
307
|
return convertTsTypeToGraphQLType(prop.tsType, prop.optional);
|
|
271
308
|
}
|
|
@@ -279,7 +316,7 @@ function updateExtractedTypes(extractedTypes, params) {
|
|
|
279
316
|
});
|
|
280
317
|
}
|
|
281
318
|
function updateField(field, params, parentTypeName, isInput) {
|
|
282
|
-
const { generatedTypeNames, enumTypeNames } = params;
|
|
319
|
+
const { generatedTypeNames, enumTypeNames, unionTypeNames } = params;
|
|
283
320
|
const context = buildFieldContext(parentTypeName, [field.name], isInput);
|
|
284
321
|
const contextKey = getContextKey(context);
|
|
285
322
|
// Handle inline objects
|
|
@@ -327,6 +364,19 @@ function updateField(field, params, parentTypeName, isInput) {
|
|
|
327
364
|
};
|
|
328
365
|
}
|
|
329
366
|
}
|
|
367
|
+
// Handle inline union types
|
|
368
|
+
if (field.tsType.kind === "union" && field.tsType.members) {
|
|
369
|
+
const resolvedTypeName = unionTypeNames.get(contextKey);
|
|
370
|
+
if (resolvedTypeName) {
|
|
371
|
+
return {
|
|
372
|
+
...field,
|
|
373
|
+
tsType: createReferenceType({
|
|
374
|
+
name: resolvedTypeName,
|
|
375
|
+
nullable: field.tsType.nullable,
|
|
376
|
+
}),
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
}
|
|
330
380
|
return field;
|
|
331
381
|
}
|
|
332
382
|
function updateResolversResult(resolversResult, params) {
|
|
@@ -345,9 +395,51 @@ function updateResolversResult(resolversResult, params) {
|
|
|
345
395
|
};
|
|
346
396
|
}
|
|
347
397
|
function updateResolverField(field, params, resolverType, parentTypeName) {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
398
|
+
const { generatedTypeNames, enumTypeNames, unionTypeNames } = params;
|
|
399
|
+
let updatedType = field.type;
|
|
400
|
+
// Create payload context once for all inline return type checks
|
|
401
|
+
const hasInlinePayload = field.returnTypeInlineObjectProperties ||
|
|
402
|
+
field.returnTypeInlineEnumMembers ||
|
|
403
|
+
field.returnTypeInlineUnionMembers;
|
|
404
|
+
if (hasInlinePayload) {
|
|
405
|
+
const payloadContext = {
|
|
406
|
+
kind: "resolverPayload",
|
|
407
|
+
resolverType,
|
|
408
|
+
fieldName: field.name,
|
|
409
|
+
parentTypeName,
|
|
410
|
+
fieldPath: [],
|
|
411
|
+
};
|
|
412
|
+
const payloadContextKey = getContextKey(payloadContext);
|
|
413
|
+
// These are mutually exclusive - a return type can only be one of:
|
|
414
|
+
// inline object, inline enum, or inline union
|
|
415
|
+
if (field.returnTypeInlineObjectProperties) {
|
|
416
|
+
// Handle inline payload objects in return type
|
|
417
|
+
const resolvedTypeName = generatedTypeNames.get(payloadContextKey);
|
|
418
|
+
if (resolvedTypeName) {
|
|
419
|
+
updatedType = { ...field.type, typeName: resolvedTypeName };
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
else if (field.returnTypeInlineEnumMembers) {
|
|
423
|
+
// Handle inline enum in return type
|
|
424
|
+
const resolvedTypeName = enumTypeNames.get(payloadContextKey);
|
|
425
|
+
if (resolvedTypeName) {
|
|
426
|
+
updatedType = { ...field.type, typeName: resolvedTypeName };
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
else if (field.returnTypeInlineUnionMembers) {
|
|
430
|
+
// Handle inline union in return type
|
|
431
|
+
const resolvedTypeName = unionTypeNames.get(payloadContextKey);
|
|
432
|
+
if (resolvedTypeName) {
|
|
433
|
+
updatedType = { ...field.type, typeName: resolvedTypeName };
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
if (!field.args) {
|
|
438
|
+
return {
|
|
439
|
+
...field,
|
|
440
|
+
type: updatedType,
|
|
441
|
+
};
|
|
442
|
+
}
|
|
351
443
|
const updatedArgs = field.args.map((arg) => {
|
|
352
444
|
const context = {
|
|
353
445
|
kind: "resolverArg",
|
|
@@ -384,10 +476,24 @@ function updateResolverField(field, params, resolverType, parentTypeName) {
|
|
|
384
476
|
};
|
|
385
477
|
}
|
|
386
478
|
}
|
|
479
|
+
// Handle inline unions (OneOf input objects)
|
|
480
|
+
if (arg.inlineUnionMembers) {
|
|
481
|
+
const resolvedTypeName = unionTypeNames.get(contextKey);
|
|
482
|
+
if (resolvedTypeName) {
|
|
483
|
+
return {
|
|
484
|
+
...arg,
|
|
485
|
+
type: {
|
|
486
|
+
...arg.type,
|
|
487
|
+
typeName: resolvedTypeName,
|
|
488
|
+
},
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
}
|
|
387
492
|
return arg;
|
|
388
493
|
});
|
|
389
494
|
return {
|
|
390
495
|
...field,
|
|
496
|
+
type: updatedType,
|
|
391
497
|
args: updatedArgs,
|
|
392
498
|
};
|
|
393
499
|
}
|
|
@@ -400,39 +506,45 @@ function buildGeneratedTypeNamesMap(inlineObjects) {
|
|
|
400
506
|
}
|
|
401
507
|
return map;
|
|
402
508
|
}
|
|
403
|
-
function toScreamingSnakeCase(value) {
|
|
404
|
-
return value
|
|
405
|
-
.replace(/[-\s]+/g, "_")
|
|
406
|
-
.replace(/([a-z])([A-Z])/g, "$1_$2")
|
|
407
|
-
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
|
|
408
|
-
.toUpperCase();
|
|
409
|
-
}
|
|
410
509
|
function convertInlineEnumMembers(params) {
|
|
411
510
|
const { members, enumName, sourceLocation } = params;
|
|
412
511
|
let needsStringEnumMapping = false;
|
|
413
512
|
const enumValues = [];
|
|
414
513
|
const diagnostics = [];
|
|
415
|
-
const
|
|
514
|
+
const convertedMembers = [];
|
|
416
515
|
for (const member of members) {
|
|
417
516
|
const convertedName = toScreamingSnakeCase(member.value);
|
|
418
|
-
|
|
517
|
+
convertedMembers.push({ convertedName, member });
|
|
518
|
+
}
|
|
519
|
+
const prefixDetectionResult = detectEnumPrefix({
|
|
520
|
+
enumName,
|
|
521
|
+
memberValues: convertedMembers.map((m) => m.convertedName),
|
|
522
|
+
});
|
|
523
|
+
const finalNameToOriginals = new Map();
|
|
524
|
+
for (const { convertedName, member } of convertedMembers) {
|
|
525
|
+
let finalName = convertedName;
|
|
526
|
+
if (prefixDetectionResult.shouldStrip && prefixDetectionResult.prefix) {
|
|
527
|
+
finalName = stripEnumPrefix(convertedName, prefixDetectionResult.prefix);
|
|
528
|
+
needsStringEnumMapping = true;
|
|
529
|
+
}
|
|
530
|
+
else if (convertedName !== member.value) {
|
|
419
531
|
needsStringEnumMapping = true;
|
|
420
532
|
}
|
|
421
|
-
const originals =
|
|
533
|
+
const originals = finalNameToOriginals.get(finalName) ?? [];
|
|
422
534
|
originals.push(member.value);
|
|
423
|
-
|
|
535
|
+
finalNameToOriginals.set(finalName, originals);
|
|
424
536
|
enumValues.push({
|
|
425
|
-
name:
|
|
537
|
+
name: finalName,
|
|
426
538
|
originalValue: member.value,
|
|
427
539
|
description: member.description,
|
|
428
540
|
deprecated: member.deprecated,
|
|
429
541
|
});
|
|
430
542
|
}
|
|
431
|
-
for (const [
|
|
543
|
+
for (const [finalName, originals] of finalNameToOriginals) {
|
|
432
544
|
if (originals.length > 1) {
|
|
433
545
|
diagnostics.push({
|
|
434
546
|
code: "DUPLICATE_ENUM_VALUE_AFTER_CONVERSION",
|
|
435
|
-
message: `Enum '${enumName}' has duplicate value '${
|
|
547
|
+
message: `Enum '${enumName}' has duplicate value '${finalName}' after conversion (from '${originals.join("' and '")}')`,
|
|
436
548
|
severity: "error",
|
|
437
549
|
location: sourceLocation,
|
|
438
550
|
});
|
|
@@ -452,10 +564,12 @@ function generateAutoEnumType(inlineEnum, typeName) {
|
|
|
452
564
|
kind: "Enum",
|
|
453
565
|
fields: null,
|
|
454
566
|
enumValues,
|
|
567
|
+
unionMembers: null,
|
|
455
568
|
needsStringEnumMapping,
|
|
456
569
|
sourceLocation: inlineEnum.sourceLocation,
|
|
457
570
|
generatedFrom: buildGeneratedFromInfo(inlineEnum.context),
|
|
458
571
|
description: inlineEnum.externalEnumDescription,
|
|
572
|
+
resolveTypeFieldPattern: null,
|
|
459
573
|
},
|
|
460
574
|
diagnostics,
|
|
461
575
|
};
|
|
@@ -491,21 +605,404 @@ function buildEnumTypeNamesMap(inlineEnums) {
|
|
|
491
605
|
uniqueInlineEnums,
|
|
492
606
|
};
|
|
493
607
|
}
|
|
608
|
+
function buildUnionTypeNamesMap(inlineUnions) {
|
|
609
|
+
const unionTypeNames = new Map();
|
|
610
|
+
for (const inlineUnion of inlineUnions) {
|
|
611
|
+
const contextKey = getContextKey(inlineUnion.context);
|
|
612
|
+
const typeName = generateAutoTypeName(inlineUnion.context);
|
|
613
|
+
unionTypeNames.set(contextKey, typeName);
|
|
614
|
+
}
|
|
615
|
+
return unionTypeNames;
|
|
616
|
+
}
|
|
617
|
+
function processOneOfInputObjects(params) {
|
|
618
|
+
const { inlineUnions, knownTypeNames, typeMap, unionTypeNames } = params;
|
|
619
|
+
const types = [];
|
|
620
|
+
const diagnostics = [];
|
|
621
|
+
for (const inlineUnion of inlineUnions) {
|
|
622
|
+
const contextKey = getContextKey(inlineUnion.context);
|
|
623
|
+
const typeName = generateAutoTypeName(inlineUnion.context);
|
|
624
|
+
const validationResult = validateOneOfMembers({
|
|
625
|
+
members: inlineUnion.members,
|
|
626
|
+
typeName,
|
|
627
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
628
|
+
typeMap,
|
|
629
|
+
});
|
|
630
|
+
diagnostics.push(...validationResult.diagnostics);
|
|
631
|
+
if (!validationResult.valid) {
|
|
632
|
+
continue;
|
|
633
|
+
}
|
|
634
|
+
const fields = generateOneOfFields({
|
|
635
|
+
members: inlineUnion.members,
|
|
636
|
+
knownTypeNames,
|
|
637
|
+
});
|
|
638
|
+
types.push({
|
|
639
|
+
name: typeName,
|
|
640
|
+
kind: "OneOfInputObject",
|
|
641
|
+
fields,
|
|
642
|
+
enumValues: null,
|
|
643
|
+
unionMembers: null,
|
|
644
|
+
needsStringEnumMapping: false,
|
|
645
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
646
|
+
generatedFrom: buildGeneratedFromInfo(inlineUnion.context),
|
|
647
|
+
description: null,
|
|
648
|
+
resolveTypeFieldPattern: null,
|
|
649
|
+
});
|
|
650
|
+
unionTypeNames.set(contextKey, typeName);
|
|
651
|
+
}
|
|
652
|
+
return { types, diagnostics };
|
|
653
|
+
}
|
|
654
|
+
function processUnionTypes(params) {
|
|
655
|
+
const { inlineUnions, knownTypeNames, generatedTypeNames, enumTypeNames, unionTypeNames, typeMap, } = params;
|
|
656
|
+
const types = [];
|
|
657
|
+
const diagnostics = [];
|
|
658
|
+
const generatedTypenameTypes = new Map();
|
|
659
|
+
for (const inlineUnion of inlineUnions) {
|
|
660
|
+
const contextKey = getContextKey(inlineUnion.context);
|
|
661
|
+
const typeName = generateAutoTypeName(inlineUnion.context);
|
|
662
|
+
const validationResult = validateUnionMembers({
|
|
663
|
+
members: inlineUnion.members,
|
|
664
|
+
typeName,
|
|
665
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
666
|
+
typeMap,
|
|
667
|
+
});
|
|
668
|
+
diagnostics.push(...validationResult.diagnostics);
|
|
669
|
+
if (!validationResult.valid) {
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
let resolveTypeFieldPattern = null;
|
|
673
|
+
if (inlineUnion.context.kind === "resolverPayload") {
|
|
674
|
+
const typenameValidationResult = validateUnionMemberTypenames({
|
|
675
|
+
members: inlineUnion.members,
|
|
676
|
+
unionTypeName: typeName,
|
|
677
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
678
|
+
typeMap,
|
|
679
|
+
});
|
|
680
|
+
diagnostics.push(...typenameValidationResult.diagnostics);
|
|
681
|
+
if (!typenameValidationResult.valid) {
|
|
682
|
+
continue;
|
|
683
|
+
}
|
|
684
|
+
if (typenameValidationResult.allMembersHaveTypename) {
|
|
685
|
+
resolveTypeFieldPattern = determineFieldPattern(typenameValidationResult.memberTypenames);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
const memberNames = resolveMemberNames({
|
|
689
|
+
members: inlineUnion.members,
|
|
690
|
+
knownTypeNames,
|
|
691
|
+
generatedTypeNames,
|
|
692
|
+
enumTypeNames,
|
|
693
|
+
parentContext: inlineUnion.context,
|
|
694
|
+
unionTypeNames,
|
|
695
|
+
types,
|
|
696
|
+
diagnostics,
|
|
697
|
+
generatedTypenameTypes,
|
|
698
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
699
|
+
});
|
|
700
|
+
types.push({
|
|
701
|
+
name: typeName,
|
|
702
|
+
kind: "Union",
|
|
703
|
+
fields: null,
|
|
704
|
+
enumValues: null,
|
|
705
|
+
unionMembers: memberNames,
|
|
706
|
+
needsStringEnumMapping: false,
|
|
707
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
708
|
+
generatedFrom: buildGeneratedFromInfo(inlineUnion.context),
|
|
709
|
+
description: null,
|
|
710
|
+
resolveTypeFieldPattern,
|
|
711
|
+
});
|
|
712
|
+
unionTypeNames.set(contextKey, typeName);
|
|
713
|
+
}
|
|
714
|
+
return { types, diagnostics };
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* Determine the field pattern for resolveType based on the typename fields used by members.
|
|
718
|
+
*/
|
|
719
|
+
function determineFieldPattern(memberTypenames) {
|
|
720
|
+
const fieldNames = new Set();
|
|
721
|
+
for (const info of memberTypenames.values()) {
|
|
722
|
+
fieldNames.add(info.fieldName);
|
|
723
|
+
}
|
|
724
|
+
if (fieldNames.size === 0) {
|
|
725
|
+
return { usedFieldNames: createFieldNameSet(["__typename"]) };
|
|
726
|
+
}
|
|
727
|
+
return { usedFieldNames: fieldNames };
|
|
728
|
+
}
|
|
729
|
+
function processInlineUnions(params) {
|
|
730
|
+
const { inlineUnions, knownTypeNames, generatedTypeNames, enumTypeNames, unionTypeNames, extractedTypes, } = params;
|
|
731
|
+
const typeMap = new Map();
|
|
732
|
+
for (const typeInfo of extractedTypes) {
|
|
733
|
+
typeMap.set(typeInfo.metadata.name, typeInfo);
|
|
734
|
+
}
|
|
735
|
+
const inputUnions = inlineUnions.filter((u) => u.isInputContext);
|
|
736
|
+
const outputUnions = inlineUnions.filter((u) => !u.isInputContext);
|
|
737
|
+
const oneOfResult = processOneOfInputObjects({
|
|
738
|
+
inlineUnions: inputUnions,
|
|
739
|
+
knownTypeNames,
|
|
740
|
+
typeMap,
|
|
741
|
+
unionTypeNames,
|
|
742
|
+
});
|
|
743
|
+
const unionResult = processUnionTypes({
|
|
744
|
+
inlineUnions: outputUnions,
|
|
745
|
+
knownTypeNames,
|
|
746
|
+
generatedTypeNames,
|
|
747
|
+
enumTypeNames,
|
|
748
|
+
unionTypeNames,
|
|
749
|
+
typeMap,
|
|
750
|
+
});
|
|
751
|
+
return {
|
|
752
|
+
types: [...oneOfResult.types, ...unionResult.types],
|
|
753
|
+
diagnostics: [...oneOfResult.diagnostics, ...unionResult.diagnostics],
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
function generateOneOfFields(params) {
|
|
757
|
+
const { members, knownTypeNames } = params;
|
|
758
|
+
const fields = [];
|
|
759
|
+
for (const member of members) {
|
|
760
|
+
const memberType = member.memberType;
|
|
761
|
+
if (memberType.kind === "inlineObject" &&
|
|
762
|
+
memberType.inlineObjectProperties) {
|
|
763
|
+
for (const prop of memberType.inlineObjectProperties) {
|
|
764
|
+
const fieldType = convertTsTypeToGraphQLType(prop.tsType, prop.optional);
|
|
765
|
+
fields.push({
|
|
766
|
+
name: prop.name,
|
|
767
|
+
type: {
|
|
768
|
+
...fieldType,
|
|
769
|
+
nullable: true,
|
|
770
|
+
},
|
|
771
|
+
description: prop.description,
|
|
772
|
+
deprecated: prop.deprecated,
|
|
773
|
+
directives: prop.directives,
|
|
774
|
+
defaultValue: prop.defaultValue,
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
else if (memberType.kind === "reference" && memberType.name) {
|
|
779
|
+
if (knownTypeNames.has(memberType.name)) {
|
|
780
|
+
const camelCaseName = memberType.name.charAt(0).toLowerCase() + memberType.name.slice(1);
|
|
781
|
+
fields.push({
|
|
782
|
+
name: camelCaseName,
|
|
783
|
+
type: {
|
|
784
|
+
typeName: memberType.name,
|
|
785
|
+
nullable: true,
|
|
786
|
+
list: false,
|
|
787
|
+
listItemNullable: null,
|
|
788
|
+
},
|
|
789
|
+
description: null,
|
|
790
|
+
deprecated: null,
|
|
791
|
+
directives: null,
|
|
792
|
+
defaultValue: null,
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
return fields;
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Extract __typename or $typeName property value from inline object properties.
|
|
801
|
+
* Returns null if neither is found or neither is a valid string literal.
|
|
802
|
+
* __typename takes priority over $typeName if both are present.
|
|
803
|
+
*/
|
|
804
|
+
function extractTypenameFromInlineObject(properties) {
|
|
805
|
+
const found = findTypenameProperty(properties, (p) => p.name);
|
|
806
|
+
if (!found) {
|
|
807
|
+
return null;
|
|
808
|
+
}
|
|
809
|
+
const { property, fieldName } = found;
|
|
810
|
+
const { tsType } = property;
|
|
811
|
+
if (tsType.kind === "literal" && tsType.name !== null) {
|
|
812
|
+
return { typeName: tsType.name, fieldName };
|
|
813
|
+
}
|
|
814
|
+
return null;
|
|
815
|
+
}
|
|
816
|
+
function resolveMemberNames(params) {
|
|
817
|
+
const { members, generatedTypeNames, parentContext, types, generatedTypenameTypes, diagnostics, sourceLocation, } = params;
|
|
818
|
+
const memberNames = [];
|
|
819
|
+
for (let i = 0; i < members.length; i++) {
|
|
820
|
+
const member = members[i];
|
|
821
|
+
const memberType = member.memberType;
|
|
822
|
+
if (memberType.kind === "reference" && memberType.name) {
|
|
823
|
+
memberNames.push(memberType.name);
|
|
824
|
+
}
|
|
825
|
+
else if (memberType.kind === "inlineObject" &&
|
|
826
|
+
memberType.inlineObjectProperties) {
|
|
827
|
+
// Only extract __typename or $typeName for resolverPayload context
|
|
828
|
+
// For other contexts (resolverArg, objectField, inputField), these fields
|
|
829
|
+
// should be treated as regular fields, not as type discriminators
|
|
830
|
+
const extractedInfo = parentContext.kind === "resolverPayload"
|
|
831
|
+
? extractTypenameFromInlineObject(memberType.inlineObjectProperties)
|
|
832
|
+
: null;
|
|
833
|
+
let memberTypeName;
|
|
834
|
+
let contextKey;
|
|
835
|
+
if (extractedInfo !== null) {
|
|
836
|
+
memberTypeName = extractedInfo.typeName;
|
|
837
|
+
const nestedContext = {
|
|
838
|
+
...parentContext,
|
|
839
|
+
fieldPath: [...parentContext.fieldPath, extractedInfo.typeName],
|
|
840
|
+
};
|
|
841
|
+
contextKey = getContextKey(nestedContext);
|
|
842
|
+
}
|
|
843
|
+
else {
|
|
844
|
+
const nestedContext = {
|
|
845
|
+
...parentContext,
|
|
846
|
+
fieldPath: [...parentContext.fieldPath, `member${i}`],
|
|
847
|
+
};
|
|
848
|
+
memberTypeName = generateAutoTypeName(nestedContext);
|
|
849
|
+
contextKey = getContextKey(nestedContext);
|
|
850
|
+
}
|
|
851
|
+
// Only filter out __typename or $typeName for resolverPayload context
|
|
852
|
+
// For other contexts, these are regular fields that should be preserved
|
|
853
|
+
const typenameFieldToFilter = extractedInfo?.fieldName ?? null;
|
|
854
|
+
const fields = memberType.inlineObjectProperties
|
|
855
|
+
.filter((prop) => parentContext.kind !== "resolverPayload" ||
|
|
856
|
+
prop.name !== typenameFieldToFilter)
|
|
857
|
+
.map((prop) => {
|
|
858
|
+
const fieldType = convertTsTypeToGraphQLType(prop.tsType, prop.optional);
|
|
859
|
+
return {
|
|
860
|
+
name: prop.name,
|
|
861
|
+
type: fieldType,
|
|
862
|
+
description: prop.description,
|
|
863
|
+
deprecated: prop.deprecated,
|
|
864
|
+
directives: prop.directives,
|
|
865
|
+
defaultValue: prop.defaultValue,
|
|
866
|
+
};
|
|
867
|
+
});
|
|
868
|
+
// Check if this typename was already seen with a different field structure
|
|
869
|
+
if (extractedInfo !== null) {
|
|
870
|
+
const existingFields = generatedTypenameTypes.get(extractedInfo.typeName);
|
|
871
|
+
if (existingFields !== undefined) {
|
|
872
|
+
// Compare field structures
|
|
873
|
+
if (!areFieldStructuresEqual(existingFields, fields)) {
|
|
874
|
+
diagnostics.push({
|
|
875
|
+
code: "TYPENAME_FIELD_STRUCTURE_MISMATCH",
|
|
876
|
+
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.`,
|
|
877
|
+
severity: "error",
|
|
878
|
+
location: sourceLocation,
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
// Skip generating duplicate type and avoid adding duplicate union member
|
|
882
|
+
if (!memberNames.includes(memberTypeName)) {
|
|
883
|
+
memberNames.push(memberTypeName);
|
|
884
|
+
}
|
|
885
|
+
continue;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
const nestedContext = {
|
|
889
|
+
...parentContext,
|
|
890
|
+
fieldPath: [
|
|
891
|
+
...parentContext.fieldPath,
|
|
892
|
+
extractedInfo?.typeName ?? `member${i}`,
|
|
893
|
+
],
|
|
894
|
+
};
|
|
895
|
+
types.push({
|
|
896
|
+
name: memberTypeName,
|
|
897
|
+
kind: "Object",
|
|
898
|
+
fields,
|
|
899
|
+
enumValues: null,
|
|
900
|
+
unionMembers: null,
|
|
901
|
+
needsStringEnumMapping: false,
|
|
902
|
+
sourceLocation: {
|
|
903
|
+
file: "",
|
|
904
|
+
line: 1,
|
|
905
|
+
column: 1,
|
|
906
|
+
},
|
|
907
|
+
generatedFrom: buildGeneratedFromInfo(nestedContext),
|
|
908
|
+
description: memberType.inlineObjectDescription,
|
|
909
|
+
resolveTypeFieldPattern: null,
|
|
910
|
+
});
|
|
911
|
+
generatedTypeNames.set(contextKey, memberTypeName);
|
|
912
|
+
if (extractedInfo !== null) {
|
|
913
|
+
generatedTypenameTypes.set(extractedInfo.typeName, fields);
|
|
914
|
+
}
|
|
915
|
+
memberNames.push(memberTypeName);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
return memberNames;
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* Compare two field structures for equality.
|
|
922
|
+
* Returns true if both have the same fields with the same types.
|
|
923
|
+
*/
|
|
924
|
+
function areFieldStructuresEqual(fields1, fields2) {
|
|
925
|
+
if (fields1.length !== fields2.length) {
|
|
926
|
+
return false;
|
|
927
|
+
}
|
|
928
|
+
const sorted1 = [...fields1].sort((a, b) => a.name.localeCompare(b.name));
|
|
929
|
+
const sorted2 = [...fields2].sort((a, b) => a.name.localeCompare(b.name));
|
|
930
|
+
for (let i = 0; i < sorted1.length; i++) {
|
|
931
|
+
const f1 = sorted1[i];
|
|
932
|
+
const f2 = sorted2[i];
|
|
933
|
+
if (f1.name !== f2.name) {
|
|
934
|
+
return false;
|
|
935
|
+
}
|
|
936
|
+
if (!areGraphQLTypesEqual(f1.type, f2.type)) {
|
|
937
|
+
return false;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
return true;
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Compare two GraphQL type references for equality.
|
|
944
|
+
*/
|
|
945
|
+
function areGraphQLTypesEqual(type1, type2) {
|
|
946
|
+
if (type1.typeName !== type2.typeName) {
|
|
947
|
+
return false;
|
|
948
|
+
}
|
|
949
|
+
if (type1.nullable !== type2.nullable) {
|
|
950
|
+
return false;
|
|
951
|
+
}
|
|
952
|
+
if (type1.list !== type2.list) {
|
|
953
|
+
return false;
|
|
954
|
+
}
|
|
955
|
+
if (type1.listItemNullable !== type2.listItemNullable) {
|
|
956
|
+
return false;
|
|
957
|
+
}
|
|
958
|
+
return true;
|
|
959
|
+
}
|
|
494
960
|
export function generateAutoTypes(input) {
|
|
495
961
|
const inlineObjectsFromTypes = [];
|
|
496
962
|
for (const typeInfo of input.extractedTypes) {
|
|
497
963
|
inlineObjectsFromTypes.push(...collectInlineObjectsFromType(typeInfo));
|
|
498
964
|
}
|
|
499
965
|
const inlineObjectsFromResolvers = collectInlineObjectsFromResolvers(input.resolversResult);
|
|
966
|
+
const inlinePayloadsFromResolvers = collectInlinePayloadsFromResolvers(input.resolversResult);
|
|
500
967
|
const allInlineObjects = [
|
|
501
968
|
...inlineObjectsFromTypes,
|
|
502
969
|
...inlineObjectsFromResolvers,
|
|
970
|
+
...inlinePayloadsFromResolvers,
|
|
503
971
|
];
|
|
504
972
|
const generatedTypeNames = buildGeneratedTypeNamesMap(allInlineObjects);
|
|
505
973
|
const inlineEnumsFromTypes = collectInlineEnumsFromTypes(input.extractedTypes);
|
|
506
|
-
const inlineEnumsFromResolvers = collectInlineEnumsFromResolvers(
|
|
507
|
-
|
|
974
|
+
const inlineEnumsFromResolvers = collectInlineEnumsFromResolvers({
|
|
975
|
+
resolversResult: input.resolversResult,
|
|
976
|
+
});
|
|
977
|
+
const inlineEnumsFromPayloads = collectInlineEnumsFromPayloads({
|
|
978
|
+
resolversResult: input.resolversResult,
|
|
979
|
+
});
|
|
980
|
+
const allInlineEnums = [
|
|
981
|
+
...inlineEnumsFromTypes,
|
|
982
|
+
...inlineEnumsFromResolvers,
|
|
983
|
+
...inlineEnumsFromPayloads,
|
|
984
|
+
];
|
|
508
985
|
const { enumTypeNames, uniqueInlineEnums } = buildEnumTypeNamesMap(allInlineEnums);
|
|
986
|
+
// Collect inline unions from types, resolvers, and payloads
|
|
987
|
+
const inlineUnionsFromTypes = collectInlineUnionsFromTypes({
|
|
988
|
+
extractedTypes: input.extractedTypes,
|
|
989
|
+
knownTypeNames: input.knownTypeNames,
|
|
990
|
+
});
|
|
991
|
+
const inlineUnionsFromResolvers = collectInlineUnionsFromResolvers({
|
|
992
|
+
resolversResult: input.resolversResult,
|
|
993
|
+
knownTypeNames: input.knownTypeNames,
|
|
994
|
+
});
|
|
995
|
+
const inlineUnionsFromPayloads = collectInlineUnionsFromPayloads({
|
|
996
|
+
resolversResult: input.resolversResult,
|
|
997
|
+
knownTypeNames: input.knownTypeNames,
|
|
998
|
+
});
|
|
999
|
+
const allInlineUnions = [
|
|
1000
|
+
...inlineUnionsFromTypes,
|
|
1001
|
+
...inlineUnionsFromResolvers,
|
|
1002
|
+
...inlineUnionsFromPayloads,
|
|
1003
|
+
];
|
|
1004
|
+
// Build union type names map before generating auto types
|
|
1005
|
+
const unionTypeNames = buildUnionTypeNamesMap(allInlineUnions);
|
|
509
1006
|
const autoGeneratedTypes = [];
|
|
510
1007
|
const diagnostics = [];
|
|
511
1008
|
for (const inlineObj of allInlineObjects) {
|
|
@@ -513,6 +1010,7 @@ export function generateAutoTypes(input) {
|
|
|
513
1010
|
inlineObj,
|
|
514
1011
|
generatedTypeNames,
|
|
515
1012
|
enumTypeNames,
|
|
1013
|
+
unionTypeNames,
|
|
516
1014
|
});
|
|
517
1015
|
autoGeneratedTypes.push(result.type);
|
|
518
1016
|
diagnostics.push(...result.diagnostics);
|
|
@@ -524,9 +1022,21 @@ export function generateAutoTypes(input) {
|
|
|
524
1022
|
autoGeneratedTypes.push(result.type);
|
|
525
1023
|
diagnostics.push(...result.diagnostics);
|
|
526
1024
|
}
|
|
1025
|
+
// Process inline unions
|
|
1026
|
+
const { types: unionTypes, diagnostics: unionDiagnostics } = processInlineUnions({
|
|
1027
|
+
inlineUnions: allInlineUnions,
|
|
1028
|
+
knownTypeNames: input.knownTypeNames,
|
|
1029
|
+
generatedTypeNames,
|
|
1030
|
+
enumTypeNames,
|
|
1031
|
+
unionTypeNames,
|
|
1032
|
+
extractedTypes: input.extractedTypes,
|
|
1033
|
+
});
|
|
1034
|
+
autoGeneratedTypes.push(...unionTypes);
|
|
1035
|
+
diagnostics.push(...unionDiagnostics);
|
|
527
1036
|
const updateParams = {
|
|
528
1037
|
generatedTypeNames,
|
|
529
1038
|
enumTypeNames,
|
|
1039
|
+
unionTypeNames,
|
|
530
1040
|
};
|
|
531
1041
|
const updatedExtractedTypes = updateExtractedTypes(input.extractedTypes, updateParams);
|
|
532
1042
|
const updatedResolversResult = updateResolversResult(input.resolversResult, updateParams);
|