@gqlkit-ts/cli 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auto-type-generator/auto-type-generator.d.ts +10 -4
- package/dist/auto-type-generator/auto-type-generator.d.ts.map +1 -1
- package/dist/auto-type-generator/auto-type-generator.js +640 -133
- package/dist/auto-type-generator/auto-type-generator.js.map +1 -1
- package/dist/auto-type-generator/index.d.ts +8 -1
- package/dist/auto-type-generator/index.d.ts.map +1 -1
- package/dist/auto-type-generator/index.js +3 -0
- package/dist/auto-type-generator/index.js.map +1 -1
- package/dist/auto-type-generator/inline-enum-collector.d.ts +13 -5
- package/dist/auto-type-generator/inline-enum-collector.d.ts.map +1 -1
- package/dist/auto-type-generator/inline-enum-collector.js +107 -71
- package/dist/auto-type-generator/inline-enum-collector.js.map +1 -1
- package/dist/auto-type-generator/inline-object-traverser.d.ts +20 -0
- package/dist/auto-type-generator/inline-object-traverser.d.ts.map +1 -0
- package/dist/auto-type-generator/inline-object-traverser.js +22 -0
- package/dist/auto-type-generator/inline-object-traverser.js.map +1 -0
- package/dist/auto-type-generator/inline-union-collector.d.ts +29 -0
- package/dist/auto-type-generator/inline-union-collector.d.ts.map +1 -0
- package/dist/auto-type-generator/inline-union-collector.js +216 -0
- package/dist/auto-type-generator/inline-union-collector.js.map +1 -0
- package/dist/auto-type-generator/inline-union-types.d.ts +29 -0
- package/dist/auto-type-generator/inline-union-types.d.ts.map +1 -0
- package/dist/auto-type-generator/inline-union-types.js +2 -0
- package/dist/auto-type-generator/inline-union-types.js.map +1 -0
- package/dist/auto-type-generator/inline-union-validator.d.ts +76 -0
- package/dist/auto-type-generator/inline-union-validator.d.ts.map +1 -0
- package/dist/auto-type-generator/inline-union-validator.js +329 -0
- package/dist/auto-type-generator/inline-union-validator.js.map +1 -0
- package/dist/auto-type-generator/naming-convention.d.ts +18 -1
- package/dist/auto-type-generator/naming-convention.d.ts.map +1 -1
- package/dist/auto-type-generator/naming-convention.js +16 -0
- package/dist/auto-type-generator/naming-convention.js.map +1 -1
- package/dist/auto-type-generator/resolve-type-generator.d.ts +20 -0
- package/dist/auto-type-generator/resolve-type-generator.d.ts.map +1 -0
- package/dist/auto-type-generator/resolve-type-generator.js +2 -0
- package/dist/auto-type-generator/resolve-type-generator.js.map +1 -0
- package/dist/auto-type-generator/resolver-field-iterator.d.ts +13 -0
- package/dist/auto-type-generator/resolver-field-iterator.d.ts.map +1 -0
- package/dist/auto-type-generator/resolver-field-iterator.js +22 -0
- package/dist/auto-type-generator/resolver-field-iterator.js.map +1 -0
- package/dist/auto-type-generator/typename-extractor.d.ts +26 -0
- package/dist/auto-type-generator/typename-extractor.d.ts.map +1 -0
- package/dist/auto-type-generator/typename-extractor.js +142 -0
- package/dist/auto-type-generator/typename-extractor.js.map +1 -0
- package/dist/auto-type-generator/typename-resolve-type-generator.d.ts +35 -0
- package/dist/auto-type-generator/typename-resolve-type-generator.d.ts.map +1 -0
- package/dist/auto-type-generator/typename-resolve-type-generator.js +177 -0
- package/dist/auto-type-generator/typename-resolve-type-generator.js.map +1 -0
- package/dist/auto-type-generator/typename-types.d.ts +43 -0
- package/dist/auto-type-generator/typename-types.d.ts.map +1 -0
- package/dist/auto-type-generator/typename-types.js +37 -0
- package/dist/auto-type-generator/typename-types.js.map +1 -0
- package/dist/auto-type-generator/typename-validator.d.ts +37 -0
- package/dist/auto-type-generator/typename-validator.d.ts.map +1 -0
- package/dist/auto-type-generator/typename-validator.js +206 -0
- package/dist/auto-type-generator/typename-validator.js.map +1 -0
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/docs.d.ts +51 -0
- package/dist/commands/docs.d.ts.map +1 -0
- package/dist/commands/docs.js +154 -0
- package/dist/commands/docs.js.map +1 -0
- package/dist/gen-orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/gen-orchestrator/orchestrator.js +13 -6
- package/dist/gen-orchestrator/orchestrator.js.map +1 -1
- package/dist/resolver-extractor/extract-resolvers.d.ts +19 -1
- package/dist/resolver-extractor/extract-resolvers.d.ts.map +1 -1
- package/dist/resolver-extractor/extractor/define-api-extractor.d.ts +5 -0
- package/dist/resolver-extractor/extractor/define-api-extractor.d.ts.map +1 -1
- package/dist/resolver-extractor/extractor/define-api-extractor.js +14 -61
- package/dist/resolver-extractor/extractor/define-api-extractor.js.map +1 -1
- package/dist/resolver-extractor/index.d.ts +0 -1
- package/dist/resolver-extractor/index.d.ts.map +1 -1
- package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts +1 -0
- package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts.map +1 -1
- package/dist/resolver-extractor/validator/abstract-resolver-validator.js +9 -5
- package/dist/resolver-extractor/validator/abstract-resolver-validator.js.map +1 -1
- package/dist/schema-generator/emitter/code-emitter.d.ts.map +1 -1
- package/dist/schema-generator/emitter/code-emitter.js +20 -0
- package/dist/schema-generator/emitter/code-emitter.js.map +1 -1
- package/dist/schema-generator/generate-schema.d.ts +1 -0
- package/dist/schema-generator/generate-schema.d.ts.map +1 -1
- package/dist/schema-generator/generate-schema.js +72 -3
- package/dist/schema-generator/generate-schema.js.map +1 -1
- package/dist/schema-generator/integrator/result-integrator.d.ts +14 -2
- package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -1
- package/dist/schema-generator/integrator/result-integrator.js +54 -1
- package/dist/schema-generator/integrator/result-integrator.js.map +1 -1
- package/dist/schema-generator/resolver-collector/resolver-collector.d.ts +2 -0
- package/dist/schema-generator/resolver-collector/resolver-collector.d.ts.map +1 -1
- package/dist/schema-generator/resolver-collector/resolver-collector.js +22 -0
- package/dist/schema-generator/resolver-collector/resolver-collector.js.map +1 -1
- package/dist/shared/enum-prefix-detector.d.ts +63 -0
- package/dist/shared/enum-prefix-detector.d.ts.map +1 -0
- package/dist/shared/enum-prefix-detector.js +80 -0
- package/dist/shared/enum-prefix-detector.js.map +1 -0
- package/dist/shared/ignore-fields-detector.d.ts +26 -0
- package/dist/shared/ignore-fields-detector.d.ts.map +1 -0
- package/dist/shared/ignore-fields-detector.js +83 -0
- package/dist/shared/ignore-fields-detector.js.map +1 -0
- package/dist/shared/ignore-fields-validator.d.ts +29 -0
- package/dist/shared/ignore-fields-validator.d.ts.map +1 -0
- package/dist/shared/ignore-fields-validator.js +43 -0
- package/dist/shared/ignore-fields-validator.js.map +1 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/source-location.d.ts +5 -0
- package/dist/shared/source-location.d.ts.map +1 -1
- package/dist/shared/source-location.js +7 -0
- package/dist/shared/source-location.js.map +1 -1
- package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -1
- package/dist/type-extractor/converter/graphql-converter.js +21 -7
- package/dist/type-extractor/converter/graphql-converter.js.map +1 -1
- package/dist/type-extractor/extractor/field-type-resolver.js +42 -3
- package/dist/type-extractor/extractor/field-type-resolver.js.map +1 -1
- package/dist/type-extractor/extractor/type-extractor.d.ts.map +1 -1
- package/dist/type-extractor/extractor/type-extractor.js +88 -23
- package/dist/type-extractor/extractor/type-extractor.js.map +1 -1
- package/dist/type-extractor/types/diagnostics.d.ts +1 -1
- package/dist/type-extractor/types/diagnostics.d.ts.map +1 -1
- package/dist/type-extractor/types/ts-type-reference-factory.d.ts +10 -2
- package/dist/type-extractor/types/ts-type-reference-factory.d.ts.map +1 -1
- package/dist/type-extractor/types/ts-type-reference-factory.js +8 -2
- package/dist/type-extractor/types/ts-type-reference-factory.js.map +1 -1
- package/dist/type-extractor/types/typescript.d.ts +4 -0
- package/dist/type-extractor/types/typescript.d.ts.map +1 -1
- package/docs/coding-agents.md +64 -0
- package/docs/configuration.md +6 -20
- package/docs/getting-started.md +15 -12
- package/docs/index.md +36 -22
- package/docs/integration/apollo.md +8 -40
- package/docs/integration/drizzle.md +6 -10
- package/docs/integration/prisma.md +196 -0
- package/docs/integration/yoga.md +8 -40
- package/docs/schema/abstract-resolvers.md +117 -0
- package/docs/schema/directives.md +5 -0
- package/docs/schema/documentation.md +5 -0
- package/docs/schema/enums.md +99 -0
- package/docs/schema/fields.md +64 -0
- package/docs/schema/index.md +21 -0
- package/docs/schema/inputs.md +115 -15
- package/docs/schema/interfaces.md +31 -1
- package/docs/schema/objects.md +40 -0
- package/docs/schema/queries-mutations.md +136 -22
- package/docs/schema/scalars.md +5 -0
- package/docs/schema/unions.md +208 -1
- package/docs/what-is-gqlkit.md +13 -8
- package/package.json +6 -4
- package/src/auto-type-generator/auto-type-generator.ts +946 -201
- package/src/auto-type-generator/index.ts +42 -0
- package/src/auto-type-generator/inline-enum-collector.ts +187 -139
- package/src/auto-type-generator/inline-object-traverser.ts +49 -0
- package/src/auto-type-generator/inline-union-collector.ts +402 -0
- package/src/auto-type-generator/inline-union-types.ts +33 -0
- package/src/auto-type-generator/inline-union-validator.ts +482 -0
- package/src/auto-type-generator/naming-convention.ts +38 -1
- package/src/auto-type-generator/resolve-type-generator.ts +21 -0
- package/src/auto-type-generator/resolver-field-iterator.ts +39 -0
- package/src/auto-type-generator/typename-extractor.ts +230 -0
- package/src/auto-type-generator/typename-resolve-type-generator.ts +281 -0
- package/src/auto-type-generator/typename-types.ts +66 -0
- package/src/auto-type-generator/typename-validator.ts +326 -0
- package/src/cli.ts +2 -0
- package/src/commands/docs.ts +211 -0
- package/src/gen-orchestrator/orchestrator.ts +20 -6
- package/src/resolver-extractor/extract-resolvers.ts +19 -0
- package/src/resolver-extractor/extractor/define-api-extractor.ts +23 -89
- package/src/resolver-extractor/index.ts +0 -6
- package/src/resolver-extractor/validator/abstract-resolver-validator.ts +16 -8
- package/src/schema-generator/emitter/code-emitter.ts +34 -0
- package/src/schema-generator/generate-schema.ts +99 -2
- package/src/schema-generator/integrator/result-integrator.ts +70 -1
- package/src/schema-generator/resolver-collector/resolver-collector.ts +34 -0
- package/src/shared/enum-prefix-detector.ts +99 -0
- package/src/shared/ignore-fields-detector.ts +109 -0
- package/src/shared/ignore-fields-validator.ts +66 -0
- package/src/shared/index.ts +2 -0
- package/src/shared/source-location.ts +11 -0
- package/src/type-extractor/converter/graphql-converter.ts +31 -7
- package/src/type-extractor/extractor/field-type-resolver.ts +48 -3
- package/src/type-extractor/extractor/type-extractor.ts +103 -26
- package/src/type-extractor/types/diagnostics.ts +12 -2
- package/src/type-extractor/types/ts-type-reference-factory.ts +18 -5
- package/src/type-extractor/types/typescript.ts +4 -0
- package/dist/resolver-extractor/validator/only-validator.d.ts +0 -61
- package/dist/resolver-extractor/validator/only-validator.d.ts.map +0 -1
- package/dist/resolver-extractor/validator/only-validator.js +0 -76
- package/dist/resolver-extractor/validator/only-validator.js.map +0 -1
- package/src/resolver-extractor/validator/only-validator.ts +0 -158
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExtractedTypeInfo,
|
|
3
|
+
FieldDefinition,
|
|
4
|
+
InlineObjectProperty,
|
|
5
|
+
} from "../type-extractor/types/index.js";
|
|
6
|
+
import {
|
|
7
|
+
findTypenameProperty,
|
|
8
|
+
type TypenameFieldInfo,
|
|
9
|
+
} from "./typename-types.js";
|
|
10
|
+
|
|
11
|
+
export type { TypenameFieldInfo } from "./typename-types.js";
|
|
12
|
+
|
|
13
|
+
export interface MemberTypenameInfo {
|
|
14
|
+
readonly memberTypeName: string | null;
|
|
15
|
+
readonly memberIndex: number;
|
|
16
|
+
readonly typenameInfo: TypenameFieldInfo | null;
|
|
17
|
+
readonly isInlineObject: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface TypenameExtractionResult {
|
|
21
|
+
readonly abstractTypeName: string;
|
|
22
|
+
readonly abstractTypeKind: "union" | "interface";
|
|
23
|
+
readonly members: ReadonlyArray<MemberTypenameInfo>;
|
|
24
|
+
readonly allMembersHaveTypename: boolean;
|
|
25
|
+
readonly hasInlineObjects: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ExtractTypenamesParams {
|
|
29
|
+
readonly abstractType: ExtractedTypeInfo;
|
|
30
|
+
readonly typeMap: ReadonlyMap<string, ExtractedTypeInfo>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function extractTypenameFromFields(
|
|
34
|
+
fields: ReadonlyArray<FieldDefinition>,
|
|
35
|
+
): TypenameFieldInfo | null {
|
|
36
|
+
const found = findTypenameProperty(fields, (f) => f.name);
|
|
37
|
+
if (!found) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const { property: field, fieldName } = found;
|
|
42
|
+
|
|
43
|
+
if (field.optional) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const { tsType } = field;
|
|
48
|
+
if (tsType.nullable || tsType.kind !== "literal" || tsType.name === null) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return { typeName: tsType.name, fieldName };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function extractTypenameFromInlineObjectProperties(
|
|
56
|
+
properties: ReadonlyArray<InlineObjectProperty>,
|
|
57
|
+
): TypenameFieldInfo | null {
|
|
58
|
+
const found = findTypenameProperty(properties, (p) => p.propertyName);
|
|
59
|
+
if (!found) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const { property, fieldName } = found;
|
|
64
|
+
const { propertyType: tsType } = property;
|
|
65
|
+
|
|
66
|
+
if (tsType.nullable || tsType.kind !== "literal" || tsType.name === null) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return { typeName: tsType.name, fieldName };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function extractUnionMemberTypenames(
|
|
74
|
+
params: ExtractTypenamesParams,
|
|
75
|
+
): TypenameExtractionResult {
|
|
76
|
+
const { abstractType, typeMap } = params;
|
|
77
|
+
const members: MemberTypenameInfo[] = [];
|
|
78
|
+
let allMembersHaveTypename = true;
|
|
79
|
+
|
|
80
|
+
const unionMembers = abstractType.unionMembers ?? [];
|
|
81
|
+
const inlineObjectMembers = abstractType.inlineObjectMembers ?? [];
|
|
82
|
+
const hasInlineObjects = inlineObjectMembers.length > 0;
|
|
83
|
+
|
|
84
|
+
let memberIndex = 0;
|
|
85
|
+
|
|
86
|
+
for (const memberName of unionMembers) {
|
|
87
|
+
const memberType = typeMap.get(memberName);
|
|
88
|
+
|
|
89
|
+
if (!memberType) {
|
|
90
|
+
members.push({
|
|
91
|
+
memberTypeName: memberName,
|
|
92
|
+
memberIndex,
|
|
93
|
+
typenameInfo: null,
|
|
94
|
+
isInlineObject: false,
|
|
95
|
+
});
|
|
96
|
+
allMembersHaveTypename = false;
|
|
97
|
+
memberIndex++;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const typenameInfo = extractTypenameFromFields(memberType.fields);
|
|
102
|
+
|
|
103
|
+
if (typenameInfo === null) {
|
|
104
|
+
allMembersHaveTypename = false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
members.push({
|
|
108
|
+
memberTypeName: memberName,
|
|
109
|
+
memberIndex,
|
|
110
|
+
typenameInfo,
|
|
111
|
+
isInlineObject: false,
|
|
112
|
+
});
|
|
113
|
+
memberIndex++;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
for (const inlineObjectMember of inlineObjectMembers) {
|
|
117
|
+
const typenameInfo = extractTypenameFromInlineObjectProperties(
|
|
118
|
+
inlineObjectMember.properties,
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
if (typenameInfo === null) {
|
|
122
|
+
allMembersHaveTypename = false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
members.push({
|
|
126
|
+
memberTypeName: null,
|
|
127
|
+
memberIndex,
|
|
128
|
+
typenameInfo,
|
|
129
|
+
isInlineObject: true,
|
|
130
|
+
});
|
|
131
|
+
memberIndex++;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
abstractTypeName: abstractType.metadata.name,
|
|
136
|
+
abstractTypeKind: "union",
|
|
137
|
+
members,
|
|
138
|
+
allMembersHaveTypename,
|
|
139
|
+
hasInlineObjects,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function extractInterfaceImplementerTypenames(
|
|
144
|
+
params: ExtractTypenamesParams,
|
|
145
|
+
implementers: ReadonlyArray<ExtractedTypeInfo>,
|
|
146
|
+
): TypenameExtractionResult {
|
|
147
|
+
const { abstractType } = params;
|
|
148
|
+
const members: MemberTypenameInfo[] = [];
|
|
149
|
+
let allMembersHaveTypename = true;
|
|
150
|
+
const hasInlineObjects = false;
|
|
151
|
+
|
|
152
|
+
for (let i = 0; i < implementers.length; i++) {
|
|
153
|
+
const implementer = implementers[i]!;
|
|
154
|
+
const typenameInfo = extractTypenameFromFields(implementer.fields);
|
|
155
|
+
|
|
156
|
+
if (typenameInfo === null) {
|
|
157
|
+
allMembersHaveTypename = false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
members.push({
|
|
161
|
+
memberTypeName: implementer.metadata.name,
|
|
162
|
+
memberIndex: i,
|
|
163
|
+
typenameInfo,
|
|
164
|
+
isInlineObject: false,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
abstractTypeName: abstractType.metadata.name,
|
|
170
|
+
abstractTypeKind: "interface",
|
|
171
|
+
members,
|
|
172
|
+
allMembersHaveTypename,
|
|
173
|
+
hasInlineObjects,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function extractTypenames(
|
|
178
|
+
params: ExtractTypenamesParams,
|
|
179
|
+
): TypenameExtractionResult | null {
|
|
180
|
+
const { abstractType, typeMap } = params;
|
|
181
|
+
|
|
182
|
+
if (abstractType.metadata.kind === "union") {
|
|
183
|
+
return extractUnionMemberTypenames(params);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (abstractType.metadata.kind === "graphqlInterface") {
|
|
187
|
+
const implementers: ExtractedTypeInfo[] = [];
|
|
188
|
+
for (const typeInfo of typeMap.values()) {
|
|
189
|
+
if (
|
|
190
|
+
typeInfo.implementedInterfaces?.includes(abstractType.metadata.name)
|
|
191
|
+
) {
|
|
192
|
+
implementers.push(typeInfo);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (implementers.length === 0) {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return extractInterfaceImplementerTypenames(params, implementers);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export interface CollectTypenameExtractionsParams {
|
|
207
|
+
readonly extractedTypes: ReadonlyArray<ExtractedTypeInfo>;
|
|
208
|
+
readonly typeMap: ReadonlyMap<string, ExtractedTypeInfo>;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function collectTypenameExtractions(
|
|
212
|
+
params: CollectTypenameExtractionsParams,
|
|
213
|
+
): ReadonlyArray<TypenameExtractionResult> {
|
|
214
|
+
const { extractedTypes, typeMap } = params;
|
|
215
|
+
const results: TypenameExtractionResult[] = [];
|
|
216
|
+
|
|
217
|
+
for (const typeInfo of extractedTypes) {
|
|
218
|
+
if (
|
|
219
|
+
typeInfo.metadata.kind === "union" ||
|
|
220
|
+
typeInfo.metadata.kind === "graphqlInterface"
|
|
221
|
+
) {
|
|
222
|
+
const result = extractTypenames({ abstractType: typeInfo, typeMap });
|
|
223
|
+
if (result !== null) {
|
|
224
|
+
results.push(result);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return results;
|
|
230
|
+
}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExtractedTypeInfo,
|
|
3
|
+
InlineObjectMember,
|
|
4
|
+
InlineObjectProperty,
|
|
5
|
+
} from "../type-extractor/types/index.js";
|
|
6
|
+
import type {
|
|
7
|
+
AutoGeneratedField,
|
|
8
|
+
AutoGeneratedType,
|
|
9
|
+
} from "./auto-type-generator.js";
|
|
10
|
+
import type { ResolveTypeFieldPattern } from "./resolve-type-generator.js";
|
|
11
|
+
import {
|
|
12
|
+
collectTypenameExtractions,
|
|
13
|
+
type TypenameExtractionResult,
|
|
14
|
+
} from "./typename-extractor.js";
|
|
15
|
+
import type { TypenameFieldName } from "./typename-types.js";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Pattern for resolveType generation from typename fields.
|
|
19
|
+
* Uses the common ResolveTypeFieldPattern for usedFieldNames,
|
|
20
|
+
* with an optional memberFieldMap for mixed patterns.
|
|
21
|
+
*/
|
|
22
|
+
export interface ResolveTypePattern extends ResolveTypeFieldPattern {
|
|
23
|
+
readonly memberFieldMap: ReadonlyMap<string, TypenameFieldName> | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface TypenameAutoResolveTypeInfo {
|
|
27
|
+
readonly abstractTypeName: string;
|
|
28
|
+
readonly abstractTypeKind: "union" | "interface";
|
|
29
|
+
readonly resolveTypePattern: ResolveTypePattern;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface GeneratedInlineObjectType {
|
|
33
|
+
readonly typeName: string;
|
|
34
|
+
readonly abstractTypeName: string;
|
|
35
|
+
readonly memberIndex: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface CollectTypenameResolveTypesParams {
|
|
39
|
+
readonly extractedTypes: ReadonlyArray<ExtractedTypeInfo>;
|
|
40
|
+
readonly typeMap: ReadonlyMap<string, ExtractedTypeInfo>;
|
|
41
|
+
readonly manualResolveTypeNames: ReadonlySet<string>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface CollectTypenameResolveTypesResult {
|
|
45
|
+
readonly autoResolveTypes: ReadonlyArray<TypenameAutoResolveTypeInfo>;
|
|
46
|
+
readonly autoResolveTypeNames: ReadonlySet<string>;
|
|
47
|
+
readonly generatedObjectTypes: ReadonlyArray<AutoGeneratedType>;
|
|
48
|
+
readonly generatedInlineObjectTypes: ReadonlyArray<GeneratedInlineObjectType>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function determineResolveTypePattern(
|
|
52
|
+
extraction: TypenameExtractionResult,
|
|
53
|
+
): ResolveTypePattern | null {
|
|
54
|
+
if (!extraction.allMembersHaveTypename) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const members = extraction.members;
|
|
59
|
+
if (members.length === 0) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const usedFieldNames = new Set<TypenameFieldName>();
|
|
64
|
+
|
|
65
|
+
for (const member of members) {
|
|
66
|
+
if (member.typenameInfo === null) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
usedFieldNames.add(member.typenameInfo.fieldName);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (usedFieldNames.size === 1) {
|
|
73
|
+
return { usedFieldNames, memberFieldMap: null };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const memberFieldMap = new Map<string, TypenameFieldName>();
|
|
77
|
+
for (const member of members) {
|
|
78
|
+
if (member.typenameInfo && member.memberTypeName) {
|
|
79
|
+
memberFieldMap.set(member.memberTypeName, member.typenameInfo.fieldName);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return { usedFieldNames, memberFieldMap };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function primitiveToGraphQLScalar(primitive: string): string {
|
|
87
|
+
switch (primitive) {
|
|
88
|
+
case "string":
|
|
89
|
+
return "String";
|
|
90
|
+
case "number":
|
|
91
|
+
return "Float";
|
|
92
|
+
case "boolean":
|
|
93
|
+
return "Boolean";
|
|
94
|
+
default:
|
|
95
|
+
return "String";
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function convertInlineObjectPropertyToField(
|
|
100
|
+
property: InlineObjectProperty,
|
|
101
|
+
): AutoGeneratedField | null {
|
|
102
|
+
if (
|
|
103
|
+
property.propertyName === "__typename" ||
|
|
104
|
+
property.propertyName === "$typeName"
|
|
105
|
+
) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const tsType = property.propertyType;
|
|
110
|
+
let typeName: string;
|
|
111
|
+
const nullable = tsType.nullable;
|
|
112
|
+
let list = false;
|
|
113
|
+
let listItemNullable: boolean | null = null;
|
|
114
|
+
|
|
115
|
+
if (tsType.kind === "array" && tsType.elementType) {
|
|
116
|
+
list = true;
|
|
117
|
+
listItemNullable = tsType.elementType.nullable;
|
|
118
|
+
const elementName = tsType.elementType.name ?? "String";
|
|
119
|
+
typeName =
|
|
120
|
+
tsType.elementType.kind === "primitive"
|
|
121
|
+
? primitiveToGraphQLScalar(elementName)
|
|
122
|
+
: elementName;
|
|
123
|
+
} else if (tsType.kind === "reference" && tsType.name) {
|
|
124
|
+
typeName = tsType.name;
|
|
125
|
+
} else if (tsType.kind === "primitive" && tsType.name) {
|
|
126
|
+
typeName = primitiveToGraphQLScalar(tsType.name);
|
|
127
|
+
} else if (tsType.kind === "scalar" && tsType.scalarInfo) {
|
|
128
|
+
typeName = tsType.scalarInfo.scalarName;
|
|
129
|
+
} else {
|
|
130
|
+
typeName = "String";
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
name: property.propertyName,
|
|
135
|
+
type: {
|
|
136
|
+
typeName,
|
|
137
|
+
nullable,
|
|
138
|
+
list,
|
|
139
|
+
listItemNullable,
|
|
140
|
+
},
|
|
141
|
+
description: property.description,
|
|
142
|
+
deprecated: property.deprecated,
|
|
143
|
+
directives: null,
|
|
144
|
+
defaultValue: null,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function generateObjectTypeFromInlineObject(
|
|
149
|
+
inlineObjectMember: InlineObjectMember,
|
|
150
|
+
typeName: string,
|
|
151
|
+
abstractTypeName: string,
|
|
152
|
+
sourceFile: string,
|
|
153
|
+
): AutoGeneratedType {
|
|
154
|
+
const fields: AutoGeneratedField[] = [];
|
|
155
|
+
|
|
156
|
+
for (const property of inlineObjectMember.properties) {
|
|
157
|
+
const field = convertInlineObjectPropertyToField(property);
|
|
158
|
+
if (field !== null) {
|
|
159
|
+
fields.push(field);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
name: typeName,
|
|
165
|
+
kind: "Object",
|
|
166
|
+
fields,
|
|
167
|
+
enumValues: null,
|
|
168
|
+
unionMembers: null,
|
|
169
|
+
needsStringEnumMapping: false,
|
|
170
|
+
sourceLocation: { file: sourceFile, line: 1, column: 1 },
|
|
171
|
+
generatedFrom: {
|
|
172
|
+
parentTypeName: abstractTypeName,
|
|
173
|
+
fieldPath: [],
|
|
174
|
+
context: "typeField",
|
|
175
|
+
},
|
|
176
|
+
description: null,
|
|
177
|
+
resolveTypeFieldPattern: null,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function collectGeneratedObjectTypes(
|
|
182
|
+
extraction: TypenameExtractionResult,
|
|
183
|
+
extractedType: ExtractedTypeInfo,
|
|
184
|
+
): {
|
|
185
|
+
generatedObjectTypes: AutoGeneratedType[];
|
|
186
|
+
generatedInlineObjectTypes: GeneratedInlineObjectType[];
|
|
187
|
+
} {
|
|
188
|
+
const generatedObjectTypes: AutoGeneratedType[] = [];
|
|
189
|
+
const generatedInlineObjectTypes: GeneratedInlineObjectType[] = [];
|
|
190
|
+
|
|
191
|
+
if (!extraction.hasInlineObjects) {
|
|
192
|
+
return { generatedObjectTypes, generatedInlineObjectTypes };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const inlineObjectMembers = extractedType.inlineObjectMembers ?? [];
|
|
196
|
+
const namedMemberCount = extractedType.unionMembers?.length ?? 0;
|
|
197
|
+
|
|
198
|
+
for (const member of extraction.members) {
|
|
199
|
+
if (!member.isInlineObject || member.typenameInfo === null) {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const inlineIndex = member.memberIndex - namedMemberCount;
|
|
204
|
+
const inlineObjectMember = inlineObjectMembers[inlineIndex];
|
|
205
|
+
|
|
206
|
+
if (!inlineObjectMember) {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const typeName = member.typenameInfo.typeName;
|
|
211
|
+
|
|
212
|
+
const objectType = generateObjectTypeFromInlineObject(
|
|
213
|
+
inlineObjectMember,
|
|
214
|
+
typeName,
|
|
215
|
+
extraction.abstractTypeName,
|
|
216
|
+
extractedType.metadata.sourceFile,
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
generatedObjectTypes.push(objectType);
|
|
220
|
+
generatedInlineObjectTypes.push({
|
|
221
|
+
typeName,
|
|
222
|
+
abstractTypeName: extraction.abstractTypeName,
|
|
223
|
+
memberIndex: member.memberIndex,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return { generatedObjectTypes, generatedInlineObjectTypes };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export function collectTypenameResolveTypes(
|
|
231
|
+
params: CollectTypenameResolveTypesParams,
|
|
232
|
+
): CollectTypenameResolveTypesResult {
|
|
233
|
+
const { extractedTypes, typeMap, manualResolveTypeNames } = params;
|
|
234
|
+
|
|
235
|
+
const extractions = collectTypenameExtractions({
|
|
236
|
+
extractedTypes,
|
|
237
|
+
typeMap,
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
const autoResolveTypes: TypenameAutoResolveTypeInfo[] = [];
|
|
241
|
+
const autoResolveTypeNames = new Set<string>();
|
|
242
|
+
const allGeneratedObjectTypes: AutoGeneratedType[] = [];
|
|
243
|
+
const allGeneratedInlineObjectTypes: GeneratedInlineObjectType[] = [];
|
|
244
|
+
|
|
245
|
+
const typeInfoMap = new Map(extractedTypes.map((t) => [t.metadata.name, t]));
|
|
246
|
+
|
|
247
|
+
for (const extraction of extractions) {
|
|
248
|
+
if (manualResolveTypeNames.has(extraction.abstractTypeName)) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const extractedType = typeInfoMap.get(extraction.abstractTypeName);
|
|
253
|
+
if (extractedType && extraction.hasInlineObjects) {
|
|
254
|
+
const { generatedObjectTypes, generatedInlineObjectTypes } =
|
|
255
|
+
collectGeneratedObjectTypes(extraction, extractedType);
|
|
256
|
+
allGeneratedObjectTypes.push(...generatedObjectTypes);
|
|
257
|
+
allGeneratedInlineObjectTypes.push(...generatedInlineObjectTypes);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const pattern = determineResolveTypePattern(extraction);
|
|
261
|
+
if (pattern === null) {
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
autoResolveTypes.push({
|
|
266
|
+
abstractTypeName: extraction.abstractTypeName,
|
|
267
|
+
abstractTypeKind: extraction.abstractTypeKind,
|
|
268
|
+
resolveTypePattern: pattern,
|
|
269
|
+
});
|
|
270
|
+
autoResolveTypeNames.add(extraction.abstractTypeName);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return {
|
|
274
|
+
autoResolveTypes: autoResolveTypes.sort((a, b) =>
|
|
275
|
+
a.abstractTypeName.localeCompare(b.abstractTypeName),
|
|
276
|
+
),
|
|
277
|
+
autoResolveTypeNames,
|
|
278
|
+
generatedObjectTypes: allGeneratedObjectTypes,
|
|
279
|
+
generatedInlineObjectTypes: allGeneratedInlineObjectTypes,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common types for typename-related functionality.
|
|
3
|
+
* These types are shared across typename-extractor, typename-validator,
|
|
4
|
+
* typename-resolve-type-generator, and inline-union-validator.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* All recognized field names for type discrimination.
|
|
9
|
+
* - "__typename" is the standard GraphQL introspection field
|
|
10
|
+
* - "$typeName" is a gqlkit-specific alternative that won't appear in the schema
|
|
11
|
+
*
|
|
12
|
+
* To add a new typename field:
|
|
13
|
+
* 1. Add the field name to this array
|
|
14
|
+
* 2. Update findTypenameProperty priority if needed
|
|
15
|
+
*/
|
|
16
|
+
export const TYPENAME_FIELD_NAMES = ["__typename", "$typeName"] as const;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The field name used for type discrimination.
|
|
20
|
+
*/
|
|
21
|
+
export type TypenameFieldName = (typeof TYPENAME_FIELD_NAMES)[number];
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A set of typename field names used in a resolve type pattern.
|
|
25
|
+
*/
|
|
26
|
+
export type TypenameFieldNameSet = ReadonlySet<TypenameFieldName>;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Create a TypenameFieldNameSet from field names.
|
|
30
|
+
*/
|
|
31
|
+
export function createFieldNameSet(
|
|
32
|
+
fieldNames: ReadonlyArray<TypenameFieldName>,
|
|
33
|
+
): TypenameFieldNameSet {
|
|
34
|
+
return new Set(fieldNames);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Information about a typename field extracted from a type definition.
|
|
39
|
+
*/
|
|
40
|
+
export interface TypenameFieldInfo {
|
|
41
|
+
readonly typeName: string;
|
|
42
|
+
readonly fieldName: TypenameFieldName;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Find __typename or $typeName property from a list of properties.
|
|
47
|
+
* __typename takes priority over $typeName.
|
|
48
|
+
*/
|
|
49
|
+
export function findTypenameProperty<T>(
|
|
50
|
+
properties: ReadonlyArray<T>,
|
|
51
|
+
getName: (p: T) => string,
|
|
52
|
+
): { property: T; fieldName: TypenameFieldName } | null {
|
|
53
|
+
const typenameProperty = properties.find((p) => getName(p) === "__typename");
|
|
54
|
+
if (typenameProperty) {
|
|
55
|
+
return { property: typenameProperty, fieldName: "__typename" };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const dollarTypenameProperty = properties.find(
|
|
59
|
+
(p) => getName(p) === "$typeName",
|
|
60
|
+
);
|
|
61
|
+
if (dollarTypenameProperty) {
|
|
62
|
+
return { property: dollarTypenameProperty, fieldName: "$typeName" };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return null;
|
|
66
|
+
}
|