@eddeee888/gcg-typescript-resolver-files 0.18.0 → 0.18.2
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/defineConfig.d.ts +1 -1
- package/dist/defineConfig.js +8 -0
- package/package.json +7 -3
- package/CHANGELOG.md +0 -816
- package/DEVELOPMENT.md +0 -49
- package/dist/tsconfig.lib.tsbuildinfo +0 -1
- package/eslint.config.mjs +0 -22
- package/project.json +0 -8
- package/src/addVirtualTypesFileToTsMorphProject/addVirtualTypesFileToTsMorphProject.ts +0 -109
- package/src/addVirtualTypesFileToTsMorphProject/index.ts +0 -1
- package/src/defineConfig.spec.ts +0 -76
- package/src/defineConfig.ts +0 -37
- package/src/generateResolverFiles/addExternalResolverImport.ts +0 -185
- package/src/generateResolverFiles/addObjectTypeResolversPropertyAssignmentNodesIfNotImplemented.spec.ts +0 -1174
- package/src/generateResolverFiles/addObjectTypeResolversPropertyAssignmentNodesIfNotImplemented.ts +0 -144
- package/src/generateResolverFiles/addResolverMainFiles.ts +0 -343
- package/src/generateResolverFiles/ensureEnumTypeResolversAreGenerated.ts +0 -51
- package/src/generateResolverFiles/generateResolverFiles.ts +0 -148
- package/src/generateResolverFiles/getImportStatementWithExpectedNamedImport.spec.ts +0 -127
- package/src/generateResolverFiles/getImportStatementWithExpectedNamedImport.ts +0 -25
- package/src/generateResolverFiles/getVariableStatementWithExpectedIdentifier.spec.ts +0 -147
- package/src/generateResolverFiles/getVariableStatementWithExpectedIdentifier.ts +0 -34
- package/src/generateResolverFiles/handleGraphQLEnumType.ts +0 -100
- package/src/generateResolverFiles/handleGraphQLInterfaceType.ts +0 -70
- package/src/generateResolverFiles/handleGraphQLObjectType.ts +0 -171
- package/src/generateResolverFiles/handleGraphQLRootObjectTypeField.ts +0 -105
- package/src/generateResolverFiles/handleGraphQLScalarType.ts +0 -81
- package/src/generateResolverFiles/handleGraphQLUnionType.ts +0 -68
- package/src/generateResolverFiles/index.ts +0 -2
- package/src/generateResolverFiles/postProcessFiles.ts +0 -287
- package/src/generateResolverFiles/types.ts +0 -203
- package/src/generateResolverFiles/visitNamedType.ts +0 -66
- package/src/generateTypeDefsFiles/generateTypeDefsContent.ts +0 -15
- package/src/generateTypeDefsFiles/generateTypeDefsFiles.ts +0 -100
- package/src/generateTypeDefsFiles/index.ts +0 -1
- package/src/getGraphQLObjectTypeResolversToGenerate/getGraphQLObjectTypeResolversToGenerate.ts +0 -361
- package/src/getGraphQLObjectTypeResolversToGenerate/getNodePropertyMap.spec.ts +0 -115
- package/src/getGraphQLObjectTypeResolversToGenerate/getNodePropertyMap.ts +0 -88
- package/src/getGraphQLObjectTypeResolversToGenerate/index.ts +0 -1
- package/src/index.ts +0 -3
- package/src/normalizeAddConfigPath/index.ts +0 -1
- package/src/normalizeAddConfigPath/normalizeAddConfigPath.ts +0 -29
- package/src/parseGraphQLSchema/index.ts +0 -2
- package/src/parseGraphQLSchema/normalizeResolverName.ts +0 -28
- package/src/parseGraphQLSchema/parseGraphQLSchema.ts +0 -531
- package/src/parseGraphQLSchema/parseLocationForOutputDir.ts +0 -76
- package/src/parseSources/index.ts +0 -1
- package/src/parseSources/parseSources.ts +0 -83
- package/src/parseTypeMappers/collectTypeMappersFromSourceFile.spec.ts +0 -789
- package/src/parseTypeMappers/collectTypeMappersFromSourceFile.ts +0 -197
- package/src/parseTypeMappers/index.ts +0 -1
- package/src/parseTypeMappers/parseTypeMappers.ts +0 -75
- package/src/preset.ts +0 -317
- package/src/utils/cwd.ts +0 -8
- package/src/utils/fmt.ts +0 -16
- package/src/utils/index.ts +0 -12
- package/src/utils/isMatchResolverNamePattern.ts +0 -27
- package/src/utils/isNativeNamedType.ts +0 -21
- package/src/utils/isRootObjectType.ts +0 -8
- package/src/utils/isWhitelistedModule.spec.ts +0 -71
- package/src/utils/isWhitelistedModule.ts +0 -21
- package/src/utils/logger.ts +0 -14
- package/src/utils/normalizeImportExtension.spec.ts +0 -42
- package/src/utils/normalizeImportExtension.ts +0 -16
- package/src/utils/normalizeRelativePath.ts +0 -6
- package/src/utils/parseLocationForWhitelistedModule.spec.ts +0 -130
- package/src/utils/parseLocationForWhitelistedModule.ts +0 -38
- package/src/utils/printImportLine.spec.ts +0 -150
- package/src/utils/printImportLine.ts +0 -78
- package/src/utils/relativeModulePath.ts +0 -7
- package/src/validateAndMergeParsedConfigs/index.ts +0 -1
- package/src/validateAndMergeParsedConfigs/validateAndMergeParsedConfigs.spec.ts +0 -211
- package/src/validateAndMergeParsedConfigs/validateAndMergeParsedConfigs.ts +0 -92
- package/src/validatePresetConfig/index.ts +0 -1
- package/src/validatePresetConfig/validatePresetConfig.spec.ts +0 -706
- package/src/validatePresetConfig/validatePresetConfig.ts +0 -571
- package/tsconfig.json +0 -14
- package/tsconfig.lib.json +0 -18
- package/tsconfig.spec.json +0 -20
- package/vite.config.ts +0 -24
package/src/getGraphQLObjectTypeResolversToGenerate/getGraphQLObjectTypeResolversToGenerate.ts
DELETED
|
@@ -1,361 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type InterfaceDeclaration,
|
|
3
|
-
type TypeAliasDeclaration,
|
|
4
|
-
type ClassDeclaration,
|
|
5
|
-
type ExportSpecifier,
|
|
6
|
-
type SourceFile,
|
|
7
|
-
type Project,
|
|
8
|
-
type Identifier,
|
|
9
|
-
SyntaxKind,
|
|
10
|
-
Node,
|
|
11
|
-
} from 'ts-morph';
|
|
12
|
-
import type {
|
|
13
|
-
TypeMapperDetails,
|
|
14
|
-
TypeMappersMap,
|
|
15
|
-
} from '../parseTypeMappers/index.js';
|
|
16
|
-
import {
|
|
17
|
-
type NodePropertyMap,
|
|
18
|
-
getNodePropertyMap,
|
|
19
|
-
} from './getNodePropertyMap.js';
|
|
20
|
-
import type { ParsedGraphQLSchemaMeta } from '../parseGraphQLSchema/index.js';
|
|
21
|
-
import type { GeneratedTypesFileMeta } from '../generateResolverFiles/index.js';
|
|
22
|
-
|
|
23
|
-
export type GraphQLObjectTypeResolversToGenerate = Record<
|
|
24
|
-
string,
|
|
25
|
-
Record<string, { resolverName: string; resolverDeclaration: string }>
|
|
26
|
-
>;
|
|
27
|
-
|
|
28
|
-
export const getGraphQLObjectTypeResolversToGenerate = ({
|
|
29
|
-
mode,
|
|
30
|
-
tsMorphProject,
|
|
31
|
-
typesSourceFile,
|
|
32
|
-
typeMappersMap,
|
|
33
|
-
userDefinedSchemaObjectTypeMap,
|
|
34
|
-
generatedTypesFileMeta,
|
|
35
|
-
}: {
|
|
36
|
-
mode: 'smart' | 'fast';
|
|
37
|
-
tsMorphProject: Project;
|
|
38
|
-
typesSourceFile: SourceFile;
|
|
39
|
-
typeMappersMap: TypeMappersMap;
|
|
40
|
-
userDefinedSchemaObjectTypeMap: ParsedGraphQLSchemaMeta['userDefinedSchemaTypeMap']['object'];
|
|
41
|
-
generatedTypesFileMeta: GeneratedTypesFileMeta;
|
|
42
|
-
}): GraphQLObjectTypeResolversToGenerate => {
|
|
43
|
-
const typeMappersEntries = Object.entries(typeMappersMap);
|
|
44
|
-
if (typeMappersEntries.length === 0) {
|
|
45
|
-
return {};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* `generatedTypesFileMeta.generatedResolverTypes.userDefined` is `schemaType` -> `generatedResolverTypes`
|
|
50
|
-
* We will be parsing `types.generated.ts` file for the `generatedResolverTypes`
|
|
51
|
-
* So, we need to invert `generatedTypesFileMeta.generatedResolverTypes.userDefined` to get `generatedResolverTypes` -> `schemaType`
|
|
52
|
-
* e.g.
|
|
53
|
-
*
|
|
54
|
-
* generatedTypesFileMeta.generatedResolverTypes.userDefined = {
|
|
55
|
-
* User: {
|
|
56
|
-
* name: 'UserResolvers'
|
|
57
|
-
* }
|
|
58
|
-
* }
|
|
59
|
-
*
|
|
60
|
-
* after transformation:
|
|
61
|
-
*
|
|
62
|
-
* generatedSchemaTypeNameMap = {
|
|
63
|
-
* UserResolvers: 'User'
|
|
64
|
-
* }
|
|
65
|
-
*/
|
|
66
|
-
const generatedSchemaTypeNameMap = Object.entries(
|
|
67
|
-
generatedTypesFileMeta.generatedResolverTypes.userDefined
|
|
68
|
-
).reduce<Record<string, string>>(
|
|
69
|
-
(res, [schemaType, generatedSchemaTypeName]) => {
|
|
70
|
-
res[generatedSchemaTypeName.name] = schemaType;
|
|
71
|
-
return res;
|
|
72
|
-
},
|
|
73
|
-
{}
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
if (mode === 'fast') {
|
|
77
|
-
// 1. Get property map of all schema types
|
|
78
|
-
const resolverTypesMap: Record<
|
|
79
|
-
string, // Schema type
|
|
80
|
-
{ node: Node; properties: NodePropertyMap }
|
|
81
|
-
> = {};
|
|
82
|
-
|
|
83
|
-
const syntaxList = typesSourceFile.getChildAtIndex(0); // Assumption: There is a root node in this file that contain all exports
|
|
84
|
-
if (!syntaxList) {
|
|
85
|
-
throw new Error(
|
|
86
|
-
`Root node of generated types file doesn't exist. This likely means the file is empty. This shouldn't happen.`
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
// Assumption: All resolvers exports are 1 level below root node i.e. we can use syntaxList.getChildren()
|
|
90
|
-
for (const node of syntaxList.getChildren()) {
|
|
91
|
-
if (
|
|
92
|
-
node.isKind(SyntaxKind.TypeAliasDeclaration) ||
|
|
93
|
-
node.isKind(SyntaxKind.InterfaceDeclaration)
|
|
94
|
-
) {
|
|
95
|
-
const identifierName = node.getNameNode().getText(); // e.g. UserResolvers, BookResolvers
|
|
96
|
-
const schemaType = generatedSchemaTypeNameMap[identifierName]; // schemaType examples: User, Book
|
|
97
|
-
|
|
98
|
-
if (schemaType && typeMappersMap[schemaType]) {
|
|
99
|
-
resolverTypesMap[schemaType] = {
|
|
100
|
-
node,
|
|
101
|
-
properties: getNodePropertyMap({ node }),
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// 3. Find resolvers to generate and add reason
|
|
108
|
-
const result: GraphQLObjectTypeResolversToGenerate = {};
|
|
109
|
-
typeMappersEntries.forEach(([_, { schemaType, mapper }]) => {
|
|
110
|
-
const resolverType = resolverTypesMap[schemaType];
|
|
111
|
-
if (!resolverType) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const mapperOriginalDeclarationNode =
|
|
116
|
-
mustGetMapperOriginalDeclarationNode({
|
|
117
|
-
tsMorphProject,
|
|
118
|
-
mapper,
|
|
119
|
-
});
|
|
120
|
-
const mapperPropsMap = getNodePropertyMap({
|
|
121
|
-
node: mapperOriginalDeclarationNode,
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
Object.values(resolverType.properties).forEach((resolverTypeProp) => {
|
|
125
|
-
result[schemaType] = result[schemaType] || {};
|
|
126
|
-
const resolverTypePropName = resolverTypeProp.name;
|
|
127
|
-
|
|
128
|
-
const mapperPropIdentifier = `${mapper.name}.${resolverTypePropName}`;
|
|
129
|
-
const schemaTypePropIdentifier = `${schemaType}.${resolverTypePropName}`;
|
|
130
|
-
|
|
131
|
-
// 1. Generated resolvers types may have one or more of these meta resolvers
|
|
132
|
-
// A mapper would most likely never have these resolvers, so we skip them
|
|
133
|
-
// Otherwise, these resolvers will always be generated
|
|
134
|
-
const metaResolvers: Record<string, boolean> = {
|
|
135
|
-
__isTypeOf: true,
|
|
136
|
-
__resolveReference: true,
|
|
137
|
-
};
|
|
138
|
-
if (metaResolvers[resolverTypePropName]) {
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const mapperProp = mapperPropsMap[resolverTypePropName];
|
|
143
|
-
// 2. If mapper does not have a field in resolver type, add missing resolver
|
|
144
|
-
if (!mapperProp) {
|
|
145
|
-
result[schemaType][resolverTypePropName] = {
|
|
146
|
-
resolverName: resolverTypePropName,
|
|
147
|
-
resolverDeclaration: `async (_parent, _arg, _ctx) => { /* ${schemaTypePropIdentifier} resolver is required because ${schemaTypePropIdentifier} exists but ${mapperPropIdentifier} does not */ }`,
|
|
148
|
-
};
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// 3. If mapper and resolver props have the same name, compare their types
|
|
153
|
-
const sourceType = mapperProp.type;
|
|
154
|
-
|
|
155
|
-
// A resolver type may look like this:
|
|
156
|
-
// `book?: Resolver<Maybe<ResolversTypes['Book']>, ParentType, ContextType>;`
|
|
157
|
-
const targetType = resolverTypeProp.type // type is `Resolver<Maybe<ResolversTypes['Book']>, ParentType, ContextType> | undefined` because book resolver is optional
|
|
158
|
-
.getNonNullableType() // removing nullable, it becomes `Resolver<Maybe<ResolversTypes['Book']>, ParentType, ContextType>`
|
|
159
|
-
.getAliasTypeArguments()[0]; // first type argument is `Maybe<ResolversTypes['Book']>`
|
|
160
|
-
|
|
161
|
-
if (sourceType.isAssignableTo(targetType)) {
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
result[schemaType][resolverTypePropName] = {
|
|
166
|
-
resolverName: resolverTypePropName,
|
|
167
|
-
resolverDeclaration: `({ ${resolverTypePropName} }, _arg, _ctx) => {
|
|
168
|
-
/* ${schemaTypePropIdentifier} resolver is required because ${schemaTypePropIdentifier} and ${mapperPropIdentifier} are not compatible */
|
|
169
|
-
return ${resolverTypePropName}
|
|
170
|
-
}`,
|
|
171
|
-
};
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
return result;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// 1. Get property map of all schema types
|
|
179
|
-
const schemaResolversTypePropertyMap: Record<string, NodePropertyMap> = {};
|
|
180
|
-
|
|
181
|
-
const populateSchemaTypeResolversPropertyMap = (
|
|
182
|
-
node: TypeAliasDeclaration | InterfaceDeclaration
|
|
183
|
-
): void => {
|
|
184
|
-
const identifier = node.getNameNode();
|
|
185
|
-
const identifierName = identifier.getText();
|
|
186
|
-
|
|
187
|
-
const schemaType = generatedSchemaTypeNameMap[identifierName];
|
|
188
|
-
|
|
189
|
-
if (schemaType && userDefinedSchemaObjectTypeMap[schemaType]) {
|
|
190
|
-
schemaResolversTypePropertyMap[schemaType] = getNodePropertyMap({ node });
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
typesSourceFile
|
|
194
|
-
.getDescendantsOfKind(SyntaxKind.TypeAliasDeclaration)
|
|
195
|
-
.forEach(populateSchemaTypeResolversPropertyMap);
|
|
196
|
-
|
|
197
|
-
typesSourceFile
|
|
198
|
-
.getDescendantsOfKind(SyntaxKind.InterfaceDeclaration)
|
|
199
|
-
.forEach(populateSchemaTypeResolversPropertyMap);
|
|
200
|
-
|
|
201
|
-
// 3. Find resolvers to generate and add reason
|
|
202
|
-
const result: GraphQLObjectTypeResolversToGenerate = {};
|
|
203
|
-
typeMappersEntries.forEach(([_, { schemaType, mapper }]) => {
|
|
204
|
-
const matchedSchemaTypePropertyMap =
|
|
205
|
-
schemaResolversTypePropertyMap[schemaType];
|
|
206
|
-
if (!matchedSchemaTypePropertyMap) {
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const originalDeclarationNode = mustGetMapperOriginalDeclarationNode({
|
|
211
|
-
tsMorphProject,
|
|
212
|
-
mapper,
|
|
213
|
-
});
|
|
214
|
-
const typeMapperPropertyMap = getNodePropertyMap({
|
|
215
|
-
node: originalDeclarationNode,
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
Object.values(matchedSchemaTypePropertyMap).forEach(
|
|
219
|
-
(schemaTypeProperty) => {
|
|
220
|
-
const typeMapperProperty =
|
|
221
|
-
typeMapperPropertyMap[schemaTypeProperty.name];
|
|
222
|
-
|
|
223
|
-
const typeMapperPropertyIdentifier = `${mapper.name}.${schemaTypeProperty.name}`;
|
|
224
|
-
const schemaTypePropertyIdentifier = `${schemaType}.${schemaTypeProperty.name}`;
|
|
225
|
-
|
|
226
|
-
// Generated resolvers types may have one or more of these meta resolvers
|
|
227
|
-
// A mapper would most likely never have these resolvers, so we skip them
|
|
228
|
-
// Otherwise, these resolvers will always be generated
|
|
229
|
-
const metaResolvers: Record<string, boolean> = {
|
|
230
|
-
__isTypeOf: true,
|
|
231
|
-
__resolveReference: true,
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
if (metaResolvers[schemaTypeProperty.name]) {
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
result[schemaType] = result[schemaType] || {};
|
|
239
|
-
|
|
240
|
-
// If mapper does not have a field in schema type, add missing resolver
|
|
241
|
-
if (!typeMapperProperty) {
|
|
242
|
-
result[schemaType][schemaTypeProperty.name] = {
|
|
243
|
-
resolverName: schemaTypeProperty.name,
|
|
244
|
-
resolverDeclaration: `async (_parent, _arg, _ctx) => { /* ${schemaTypePropertyIdentifier} resolver is required because ${schemaTypePropertyIdentifier} exists but ${typeMapperPropertyIdentifier} does not */ }`,
|
|
245
|
-
};
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* FIXME: TypeScript's `isTypeAssignableTo` should be used to check if the mapper type vs resolver return type is compatible.
|
|
251
|
-
* The current challenge is to:
|
|
252
|
-
* - Switch from using the schema type to resolver return type e.g. `User` -> `UserResolver`
|
|
253
|
-
* - Take the ReturnType of the resolver function type e.g. `Resolver<ResolversTypes['UserRole'], ParentType, ContextType>`
|
|
254
|
-
*
|
|
255
|
-
* For now, the workaround now is to generate all resolvers with matching names,
|
|
256
|
-
* then use TS diagnostics to see if there's error when trying to merge the two keys.
|
|
257
|
-
*
|
|
258
|
-
* Note: this happens only when mappers are used
|
|
259
|
-
*/
|
|
260
|
-
result[schemaType][schemaTypeProperty.name] = {
|
|
261
|
-
resolverName: schemaTypeProperty.name,
|
|
262
|
-
resolverDeclaration: `({ ${schemaTypeProperty.name} }, _arg, _ctx) => {
|
|
263
|
-
/* ${schemaTypePropertyIdentifier} resolver is required because ${schemaTypePropertyIdentifier} and ${typeMapperPropertyIdentifier} are not compatible */
|
|
264
|
-
return ${schemaTypeProperty.name}
|
|
265
|
-
}`,
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
);
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
return result;
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
const mustGetMapperOriginalDeclarationNode = ({
|
|
277
|
-
tsMorphProject,
|
|
278
|
-
mapper,
|
|
279
|
-
}: {
|
|
280
|
-
tsMorphProject: Project;
|
|
281
|
-
mapper: TypeMapperDetails['mapper'];
|
|
282
|
-
}): Node => {
|
|
283
|
-
const typeMapperFile = tsMorphProject.getSourceFile(mapper.filename);
|
|
284
|
-
if (!typeMapperFile) {
|
|
285
|
-
throw new Error(
|
|
286
|
-
`Unable to find ${typeMapperFile} file after parsing. This shouldn't happen.`
|
|
287
|
-
);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Finding `firstDescendantThatIsMapper` here is a bit of the duplicated traversing logic in `collectTypeMappersFromSourceFile`.
|
|
292
|
-
* However, in `collectTypeMappersFromSourceFile`, we find the mappers details.
|
|
293
|
-
* And here, we actually do look for the mapper nodes and run analysis on it.
|
|
294
|
-
*
|
|
295
|
-
* Previously, we were parsing the node property map in `collectTypeMappersFromSourceFile`
|
|
296
|
-
* but for some reason `isAssignableTo` has issue comparing types, so we have to move the static analysis here for now.
|
|
297
|
-
*/
|
|
298
|
-
const firstDescendantThatIsMapper = (():
|
|
299
|
-
| GetOriginalDeclarationNodeParams
|
|
300
|
-
| undefined => {
|
|
301
|
-
for (const descendant of typeMapperFile.getDescendants()) {
|
|
302
|
-
const typedNode = descendant.isKind(mapper.kind);
|
|
303
|
-
if (typedNode) {
|
|
304
|
-
let identifierNode = descendant.getNameNode();
|
|
305
|
-
if (descendant.isKind(SyntaxKind.ExportSpecifier)) {
|
|
306
|
-
const aliasNode = descendant.getAliasNode();
|
|
307
|
-
if (aliasNode) {
|
|
308
|
-
identifierNode = aliasNode;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
if (identifierNode?.getText() === mapper.name) {
|
|
313
|
-
return {
|
|
314
|
-
declarationNode: descendant,
|
|
315
|
-
identifierNode,
|
|
316
|
-
};
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
return;
|
|
321
|
-
})();
|
|
322
|
-
|
|
323
|
-
if (!firstDescendantThatIsMapper) {
|
|
324
|
-
throw new Error(
|
|
325
|
-
`Unable to find ${mapper.name} node after parsing. This shouldn't happen.`
|
|
326
|
-
);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return getOriginalDeclarationNode(firstDescendantThatIsMapper);
|
|
330
|
-
};
|
|
331
|
-
|
|
332
|
-
interface GetOriginalDeclarationNodeParams {
|
|
333
|
-
declarationNode:
|
|
334
|
-
| InterfaceDeclaration
|
|
335
|
-
| TypeAliasDeclaration
|
|
336
|
-
| ExportSpecifier
|
|
337
|
-
| ClassDeclaration;
|
|
338
|
-
identifierNode: Identifier;
|
|
339
|
-
}
|
|
340
|
-
const getOriginalDeclarationNode = ({
|
|
341
|
-
declarationNode,
|
|
342
|
-
identifierNode,
|
|
343
|
-
}: GetOriginalDeclarationNodeParams): Node => {
|
|
344
|
-
if (
|
|
345
|
-
declarationNode.isKind(SyntaxKind.ExportSpecifier) ||
|
|
346
|
-
declarationNode.isKind(SyntaxKind.ClassDeclaration)
|
|
347
|
-
) {
|
|
348
|
-
return identifierNode.getDefinitionNodes()[0];
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// InterfaceDeclaration
|
|
352
|
-
if (declarationNode.isKind(SyntaxKind.InterfaceDeclaration)) {
|
|
353
|
-
return declarationNode;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
// TypeAliasDeclaration
|
|
357
|
-
const typeNode = declarationNode.getTypeNodeOrThrow();
|
|
358
|
-
return Node.isTypeReference(typeNode)
|
|
359
|
-
? identifierNode.getDefinitionNodes()[0] // If type alias is a reference, go to definition using `getDefinitionNodes`
|
|
360
|
-
: declarationNode;
|
|
361
|
-
};
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { Project, Node } from 'ts-morph';
|
|
2
|
-
import { getNodePropertyMap } from './getNodePropertyMap.js';
|
|
3
|
-
|
|
4
|
-
describe('getNodePropertyMap', () => {
|
|
5
|
-
it('correctly resolves property map of a typical types.generated.ts', () => {
|
|
6
|
-
const project = new Project();
|
|
7
|
-
const sourceFile = project.createSourceFile(
|
|
8
|
-
'/path/to/types.generated.ts',
|
|
9
|
-
`
|
|
10
|
-
export type Maybe<T> = T | null;
|
|
11
|
-
export type Scalars = {
|
|
12
|
-
ID: { input: string; output: string; }
|
|
13
|
-
String: { input: string; output: string; }
|
|
14
|
-
Boolean: { input: boolean; output: boolean; }
|
|
15
|
-
Int: { input: number; output: number; }
|
|
16
|
-
Float: { input: number; output: number; }
|
|
17
|
-
DateTime: { input: Date; output: Date | string | number; }
|
|
18
|
-
};
|
|
19
|
-
export type User = {
|
|
20
|
-
__typename: 'User';
|
|
21
|
-
accountGitHub?: Maybe<Scalars['String']['output']>;
|
|
22
|
-
accountGoogle?: Maybe<Scalars['String']['output']>;
|
|
23
|
-
createdAt: Scalars['DateTime']['output'];
|
|
24
|
-
fullName: Scalars['String']['output'];
|
|
25
|
-
id: Scalars['ID']['output'];
|
|
26
|
-
role: UserRole;
|
|
27
|
-
};
|
|
28
|
-
export type UserRole = 'ADMIN' | 'USER';`
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
const userDeclarationNode = sourceFile.getFirstDescendant(
|
|
32
|
-
(node) => Node.isTypeAliasDeclaration(node) && node.getName() === 'User'
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
const nodePropertyMap = getNodePropertyMap({ node: userDeclarationNode });
|
|
36
|
-
|
|
37
|
-
expect(nodePropertyMap.__typename.name).toBe('__typename');
|
|
38
|
-
|
|
39
|
-
expect(nodePropertyMap.accountGitHub.name).toBe('accountGitHub');
|
|
40
|
-
|
|
41
|
-
expect(nodePropertyMap.accountGoogle.name).toBe('accountGoogle');
|
|
42
|
-
|
|
43
|
-
expect(nodePropertyMap.createdAt.name).toBe('createdAt');
|
|
44
|
-
|
|
45
|
-
expect(nodePropertyMap.fullName.name).toBe('fullName');
|
|
46
|
-
|
|
47
|
-
expect(nodePropertyMap.id.name).toBe('id');
|
|
48
|
-
|
|
49
|
-
expect(nodePropertyMap.role.name).toBe('role');
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('correctly resolves property map a class', () => {
|
|
53
|
-
const project = new Project();
|
|
54
|
-
const sourceFile = project.createSourceFile(
|
|
55
|
-
'/path/to/types.ts',
|
|
56
|
-
`
|
|
57
|
-
export type UserRole = 'ADMIN' | 'USER';
|
|
58
|
-
export class User {
|
|
59
|
-
#_id: string;
|
|
60
|
-
private word: string;
|
|
61
|
-
protected word2: string;
|
|
62
|
-
|
|
63
|
-
name: string;
|
|
64
|
-
role: UserRole;
|
|
65
|
-
|
|
66
|
-
get id(): string {
|
|
67
|
-
return this.#_id;
|
|
68
|
-
}
|
|
69
|
-
}`
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
const userDeclarationNode = sourceFile.getFirstDescendant(
|
|
73
|
-
(node) => Node.isClassDeclaration(node) && node.getName() === 'User'
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
const nodePropertyMap = getNodePropertyMap({ node: userDeclarationNode });
|
|
77
|
-
|
|
78
|
-
expect(nodePropertyMap._id).toBe(undefined);
|
|
79
|
-
expect(nodePropertyMap.id).toBe(undefined);
|
|
80
|
-
expect(nodePropertyMap.word).toBe(undefined);
|
|
81
|
-
expect(nodePropertyMap.word2).toBe(undefined);
|
|
82
|
-
|
|
83
|
-
expect(nodePropertyMap.name.name).toBe('name');
|
|
84
|
-
|
|
85
|
-
expect(nodePropertyMap.role.name).toBe('role');
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('correctly resolves property map a type alias mapper', () => {
|
|
89
|
-
const project = new Project();
|
|
90
|
-
const sourceFile = project.createSourceFile(
|
|
91
|
-
'/path/to/mappers.ts',
|
|
92
|
-
`
|
|
93
|
-
type UserRole = 'Admin' | 'User';
|
|
94
|
-
export type UserMapper = {
|
|
95
|
-
id: number;
|
|
96
|
-
name: string;
|
|
97
|
-
role: UserRole;
|
|
98
|
-
}`
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
const node = sourceFile.getFirstDescendant(
|
|
102
|
-
(descendant) =>
|
|
103
|
-
Node.isTypeAliasDeclaration(descendant) &&
|
|
104
|
-
descendant.getName() === 'UserMapper'
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
const nodePropertyMap = getNodePropertyMap({ node });
|
|
108
|
-
|
|
109
|
-
expect(nodePropertyMap.id.name).toBe('id');
|
|
110
|
-
|
|
111
|
-
expect(nodePropertyMap.name.name).toBe('name');
|
|
112
|
-
|
|
113
|
-
expect(nodePropertyMap.role.name).toBe('role');
|
|
114
|
-
});
|
|
115
|
-
});
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type ClassDeclaration,
|
|
3
|
-
type Node,
|
|
4
|
-
type Type,
|
|
5
|
-
SyntaxKind,
|
|
6
|
-
} from 'ts-morph';
|
|
7
|
-
|
|
8
|
-
type NodePropertyMapValue = {
|
|
9
|
-
name: string;
|
|
10
|
-
type: Type;
|
|
11
|
-
};
|
|
12
|
-
export type NodePropertyMap = Record<string, NodePropertyMapValue>;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Function to get properties of a Node in a map
|
|
16
|
-
* If unable to find, returns empty object
|
|
17
|
-
*/
|
|
18
|
-
export const getNodePropertyMap = ({
|
|
19
|
-
node,
|
|
20
|
-
}: {
|
|
21
|
-
node: Node | undefined;
|
|
22
|
-
}): NodePropertyMap => {
|
|
23
|
-
if (!node) {
|
|
24
|
-
return {};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const properties = ((): NodePropertyMapValue[] => {
|
|
28
|
-
if (node.isKind(SyntaxKind.ClassDeclaration)) {
|
|
29
|
-
const result: NodePropertyMapValue[] = [];
|
|
30
|
-
collectClassNodeProperties(node, result);
|
|
31
|
-
return result;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return node
|
|
35
|
-
.getType()
|
|
36
|
-
.getProperties()
|
|
37
|
-
.map((prop) => {
|
|
38
|
-
return {
|
|
39
|
-
name: prop.getName(),
|
|
40
|
-
type: prop.getTypeAtLocation(node),
|
|
41
|
-
};
|
|
42
|
-
});
|
|
43
|
-
})();
|
|
44
|
-
|
|
45
|
-
const nodePropertyMap = properties.reduce<NodePropertyMap>(
|
|
46
|
-
(res, { name, type }) => {
|
|
47
|
-
res[name] = {
|
|
48
|
-
name,
|
|
49
|
-
type,
|
|
50
|
-
};
|
|
51
|
-
return res;
|
|
52
|
-
},
|
|
53
|
-
{}
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
return nodePropertyMap;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const collectClassNodeProperties = (
|
|
60
|
-
classNode: ClassDeclaration,
|
|
61
|
-
result: NodePropertyMapValue[]
|
|
62
|
-
): void => {
|
|
63
|
-
const baseClass = classNode.getBaseClass();
|
|
64
|
-
if (baseClass) {
|
|
65
|
-
collectClassNodeProperties(baseClass, result);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
classNode.getInstanceProperties().forEach((prop) => {
|
|
69
|
-
if (
|
|
70
|
-
prop.hasModifier(SyntaxKind.PrivateKeyword) ||
|
|
71
|
-
prop.hasModifier(SyntaxKind.ProtectedKeyword)
|
|
72
|
-
) {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
if (prop.getName().startsWith('#')) {
|
|
76
|
-
// ecma script private field is skipped
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
if (classNode.getGetAccessor(prop.getName())) {
|
|
80
|
-
// getter is skipped
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
result.push({
|
|
84
|
-
name: prop.getName(),
|
|
85
|
-
type: prop.getType(),
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './getGraphQLObjectTypeResolversToGenerate.js';
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './normalizeAddConfigPath.js';
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import * as path from 'path';
|
|
2
|
-
import type { AddPluginConfig } from '@graphql-codegen/add';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* normalizeAddConfigPath
|
|
6
|
-
*
|
|
7
|
-
* Function to turn the add config keys into normalized path a.k.a. path from baseOutputDir
|
|
8
|
-
* This helps us detects targeted file being given in different formats e.g. './types.generated.ts' vs 'types.generated.ts'
|
|
9
|
-
*/
|
|
10
|
-
export const normalizeAddConfigPath = ({
|
|
11
|
-
add,
|
|
12
|
-
baseOutputDir,
|
|
13
|
-
}: {
|
|
14
|
-
add?: Record<string, AddPluginConfig>;
|
|
15
|
-
baseOutputDir: string;
|
|
16
|
-
}): Record<string, AddPluginConfig> | undefined => {
|
|
17
|
-
if (!add) {
|
|
18
|
-
return undefined;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const normalizedPathAdd = Object.entries(add).reduce<
|
|
22
|
-
Record<string, AddPluginConfig>
|
|
23
|
-
>((res, [originalFilePath, config]) => {
|
|
24
|
-
res[path.posix.join(baseOutputDir, originalFilePath)] = config;
|
|
25
|
-
return res;
|
|
26
|
-
}, {});
|
|
27
|
-
|
|
28
|
-
return normalizedPathAdd;
|
|
29
|
-
};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { RootObjectType } from '../utils/index.js';
|
|
2
|
-
|
|
3
|
-
export interface NormalizedResolverName {
|
|
4
|
-
base: string;
|
|
5
|
-
withModule: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Function to get format resolver name based on its definition in the schema
|
|
10
|
-
* - Root object type resolver e.g Query.me, Mutation.updateUser
|
|
11
|
-
* - Object type e.g. User, Profile
|
|
12
|
-
*
|
|
13
|
-
* Returns an object with 2 key/value pairs:
|
|
14
|
-
* - base: resolver name without module. This is used by to match up with config.externalResolvers.
|
|
15
|
-
* - withModule: resolver name with module. This is used to identify the resolver INTERNAL unique path used in main resolver files.
|
|
16
|
-
*/
|
|
17
|
-
export const normalizeResolverName = (
|
|
18
|
-
moduleName: string,
|
|
19
|
-
name: string,
|
|
20
|
-
rootObject: RootObjectType | null
|
|
21
|
-
): NormalizedResolverName => {
|
|
22
|
-
const baseResolverName = !rootObject ? name : `${rootObject}.${name}`;
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
base: baseResolverName,
|
|
26
|
-
withModule: `${moduleName}.${baseResolverName}`,
|
|
27
|
-
};
|
|
28
|
-
};
|