@eddeee888/gcg-typescript-resolver-files 0.0.0-pr6-20221024131652
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/.eslintrc.json +18 -0
- package/CHANGELOG.md +7 -0
- package/README.md +3 -0
- package/jest.config.ts +16 -0
- package/package.json +4 -0
- package/project.json +35 -0
- package/src/index.ts +1 -0
- package/src/plugin.ts +46 -0
- package/src/run/addResolversIndexFile.ts +98 -0
- package/src/run/fixExistingResolvers.ts +84 -0
- package/src/run/handleGraphQLObjectType.ts +37 -0
- package/src/run/handleGraphQLRootObjectType.ts +52 -0
- package/src/run/handleGraphQLUninionType.ts +36 -0
- package/src/run/index.ts +1 -0
- package/src/run/run.ts +28 -0
- package/src/types.ts +38 -0
- package/src/utils.ts +26 -0
- package/tsconfig.json +19 -0
- package/tsconfig.lib.json +11 -0
- package/tsconfig.spec.json +20 -0
package/.eslintrc.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": ["../../.eslintrc.json"],
|
|
3
|
+
"ignorePatterns": ["!**/*"],
|
|
4
|
+
"overrides": [
|
|
5
|
+
{
|
|
6
|
+
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
|
7
|
+
"rules": {}
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"files": ["*.ts", "*.tsx"],
|
|
11
|
+
"rules": {}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"files": ["*.js", "*.jsx"],
|
|
15
|
+
"rules": {}
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
package/CHANGELOG.md
ADDED
package/README.md
ADDED
package/jest.config.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
export default {
|
|
3
|
+
displayName: 'typescript-resolver-files',
|
|
4
|
+
preset: '../../jest.preset.js',
|
|
5
|
+
globals: {
|
|
6
|
+
'ts-jest': {
|
|
7
|
+
tsconfig: '<rootDir>/tsconfig.spec.json',
|
|
8
|
+
},
|
|
9
|
+
},
|
|
10
|
+
testEnvironment: 'node',
|
|
11
|
+
transform: {
|
|
12
|
+
'^.+\\.[tj]sx?$': 'ts-jest',
|
|
13
|
+
},
|
|
14
|
+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
|
15
|
+
coverageDirectory: '../../coverage/packages/typescript-resolver-files',
|
|
16
|
+
};
|
package/package.json
ADDED
package/project.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "typescript-resolver-files",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "packages/typescript-resolver-files/src",
|
|
5
|
+
"projectType": "library",
|
|
6
|
+
"targets": {
|
|
7
|
+
"build": {
|
|
8
|
+
"executor": "@nrwl/js:tsc",
|
|
9
|
+
"outputs": ["{options.outputPath}"],
|
|
10
|
+
"options": {
|
|
11
|
+
"outputPath": "dist/packages/typescript-resolver-files",
|
|
12
|
+
"tsConfig": "packages/typescript-resolver-files/tsconfig.lib.json",
|
|
13
|
+
"packageJson": "packages/typescript-resolver-files/package.json",
|
|
14
|
+
"main": "packages/typescript-resolver-files/src/index.ts",
|
|
15
|
+
"assets": ["packages/typescript-resolver-files/*.md"]
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"lint": {
|
|
19
|
+
"executor": "@nrwl/linter:eslint",
|
|
20
|
+
"outputs": ["{options.outputFile}"],
|
|
21
|
+
"options": {
|
|
22
|
+
"lintFilePatterns": ["packages/typescript-resolver-files/**/*.ts"]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"test": {
|
|
26
|
+
"executor": "@nrwl/jest:jest",
|
|
27
|
+
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
|
28
|
+
"options": {
|
|
29
|
+
"jestConfig": "packages/typescript-resolver-files/jest.config.ts",
|
|
30
|
+
"passWithNoTests": true
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"tags": []
|
|
35
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { plugin } from './plugin';
|
package/src/plugin.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import { PluginFunction } from '@graphql-codegen/plugin-helpers';
|
|
3
|
+
import { mkdir, writeFile } from 'fs/promises';
|
|
4
|
+
import { run } from './run';
|
|
5
|
+
import { RunResult } from './types';
|
|
6
|
+
|
|
7
|
+
interface PluginConfig {
|
|
8
|
+
resolverTypesPath: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const plugin: PluginFunction<PluginConfig> = async (
|
|
12
|
+
schema,
|
|
13
|
+
_documents,
|
|
14
|
+
config,
|
|
15
|
+
info
|
|
16
|
+
) => {
|
|
17
|
+
// TODO: check if there's a better way to handle output dir
|
|
18
|
+
const baseOutputDir = info?.outputFile;
|
|
19
|
+
if (!baseOutputDir) {
|
|
20
|
+
throw new Error('Output folder is invalid');
|
|
21
|
+
}
|
|
22
|
+
const { resolverTypesPath: relativeResolverTypesPathFromBaseOutputDir } =
|
|
23
|
+
config;
|
|
24
|
+
const resolverTypesPath = path.join(
|
|
25
|
+
baseOutputDir,
|
|
26
|
+
relativeResolverTypesPathFromBaseOutputDir
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const result: RunResult = {
|
|
30
|
+
dirs: [],
|
|
31
|
+
files: {},
|
|
32
|
+
};
|
|
33
|
+
run({ schema, baseOutputDir, resolverTypesPath }, result);
|
|
34
|
+
|
|
35
|
+
// Write dirs and files
|
|
36
|
+
await Promise.all(
|
|
37
|
+
result.dirs.map(async (dir) => await mkdir(dir, { recursive: true }))
|
|
38
|
+
);
|
|
39
|
+
await Promise.all(
|
|
40
|
+
Object.entries(result.files).map(
|
|
41
|
+
async ([filePath, file]) => await writeFile(filePath, file.content)
|
|
42
|
+
)
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
return { content: '' };
|
|
46
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import type { RootObjectType, RunResult } from '../types';
|
|
3
|
+
import { printImportModule, relativeModulePath } from '../utils';
|
|
4
|
+
|
|
5
|
+
interface AddResolversIndexFileParams {
|
|
6
|
+
baseOutputDir: string;
|
|
7
|
+
resolverTypesPath: string;
|
|
8
|
+
}
|
|
9
|
+
export const addResolversIndexFile = (
|
|
10
|
+
{ baseOutputDir, resolverTypesPath }: AddResolversIndexFileParams,
|
|
11
|
+
result: RunResult
|
|
12
|
+
): void => {
|
|
13
|
+
const filename = path.join(baseOutputDir, 'index.ts');
|
|
14
|
+
|
|
15
|
+
const relativePathToResolverTypes = relativeModulePath(
|
|
16
|
+
baseOutputDir,
|
|
17
|
+
resolverTypesPath
|
|
18
|
+
);
|
|
19
|
+
const pathToResolverModule = printImportModule(relativePathToResolverTypes);
|
|
20
|
+
|
|
21
|
+
const resolversDetails = Object.entries(result.files).reduce<{
|
|
22
|
+
importLines: string[];
|
|
23
|
+
queryFields: string[];
|
|
24
|
+
mutationFields: string[];
|
|
25
|
+
subscriptionFields: string[];
|
|
26
|
+
objectTypes: string[];
|
|
27
|
+
}>(
|
|
28
|
+
(res, [filepath, file]) => {
|
|
29
|
+
if (file.__filetype === 'file') {
|
|
30
|
+
return res;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const pathToModule = printImportModule(
|
|
34
|
+
relativeModulePath(baseOutputDir, filepath)
|
|
35
|
+
);
|
|
36
|
+
res.importLines.push(
|
|
37
|
+
`import { ${file.mainImportIdentifier} } from '${pathToModule}'`
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
if (!file.meta.belongsToRootObject) {
|
|
41
|
+
res.objectTypes.push(file.mainImportIdentifier);
|
|
42
|
+
return res;
|
|
43
|
+
}
|
|
44
|
+
const rootObjectMap: Record<RootObjectType, () => void> = {
|
|
45
|
+
Query: () => res.queryFields.push(file.mainImportIdentifier),
|
|
46
|
+
Mutation: () => res.mutationFields.push(file.mainImportIdentifier),
|
|
47
|
+
Subscription: () =>
|
|
48
|
+
res.subscriptionFields.push(file.mainImportIdentifier),
|
|
49
|
+
};
|
|
50
|
+
rootObjectMap[file.meta.belongsToRootObject]();
|
|
51
|
+
|
|
52
|
+
return res;
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
importLines: [],
|
|
56
|
+
queryFields: [],
|
|
57
|
+
mutationFields: [],
|
|
58
|
+
subscriptionFields: [],
|
|
59
|
+
objectTypes: [],
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const resolversIdentifier = 'resolvers';
|
|
64
|
+
const resolversTypeName = 'Resolvers'; // Generated type from typescript-resolvers plugin
|
|
65
|
+
|
|
66
|
+
const queries =
|
|
67
|
+
resolversDetails.queryFields.length > 0
|
|
68
|
+
? `Query: { ${resolversDetails.queryFields
|
|
69
|
+
.map((field) => field)
|
|
70
|
+
.join(',\n')} },`
|
|
71
|
+
: '';
|
|
72
|
+
const mutations =
|
|
73
|
+
resolversDetails.mutationFields.length > 0
|
|
74
|
+
? `Mutation: { ${resolversDetails.mutationFields
|
|
75
|
+
.map((field) => field)
|
|
76
|
+
.join(',\n')} },`
|
|
77
|
+
: '';
|
|
78
|
+
const suscriptions =
|
|
79
|
+
resolversDetails.subscriptionFields.length > 0
|
|
80
|
+
? `Subscription: { ${resolversDetails.subscriptionFields
|
|
81
|
+
.map((field) => field)
|
|
82
|
+
.join(',\n')} },`
|
|
83
|
+
: '';
|
|
84
|
+
|
|
85
|
+
result.files[filename] = {
|
|
86
|
+
__filetype: 'file',
|
|
87
|
+
content: `/* This file was automatically generated. DO NOT UPDATE MANUALLY. */
|
|
88
|
+
import type { ${resolversTypeName} } from '${pathToResolverModule}';
|
|
89
|
+
${resolversDetails.importLines.map((line) => line).join(';\n')}
|
|
90
|
+
export const ${resolversIdentifier}: ${resolversTypeName} = {
|
|
91
|
+
${queries}
|
|
92
|
+
${mutations}
|
|
93
|
+
${suscriptions}
|
|
94
|
+
${resolversDetails.objectTypes.map((type) => type).join(',\n')}
|
|
95
|
+
}`,
|
|
96
|
+
mainImportIdentifier: 'resolvers',
|
|
97
|
+
};
|
|
98
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { Project } from 'ts-morph';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import type { ResolverFile, RunResult } from '../types';
|
|
5
|
+
|
|
6
|
+
export const fixExistingResolvers = (result: RunResult) => {
|
|
7
|
+
const existingResolverFiles = Object.entries(result.files).reduce<
|
|
8
|
+
Record<string, ResolverFile>
|
|
9
|
+
>((res, [filePath, file]) => {
|
|
10
|
+
if (existsSync(filePath) && file.__filetype === 'resolver') {
|
|
11
|
+
res[filePath] = file;
|
|
12
|
+
}
|
|
13
|
+
return res;
|
|
14
|
+
}, {});
|
|
15
|
+
|
|
16
|
+
const project = new Project();
|
|
17
|
+
project.addSourceFilesAtPaths(Object.keys(existingResolverFiles));
|
|
18
|
+
const sourceFiles = project.getSourceFiles();
|
|
19
|
+
sourceFiles.forEach((sourceFile) => {
|
|
20
|
+
const normalisedRelativePath = path.relative(
|
|
21
|
+
process.cwd(),
|
|
22
|
+
sourceFile.getFilePath()
|
|
23
|
+
);
|
|
24
|
+
const file = existingResolverFiles[normalisedRelativePath];
|
|
25
|
+
if (!file) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`Unable to find resolver file: ${normalisedRelativePath}`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// TODO: Check missing import
|
|
32
|
+
// ...
|
|
33
|
+
|
|
34
|
+
// Check expected identifier
|
|
35
|
+
let isExpectedIdentifierExportedInVariableStatement = false;
|
|
36
|
+
const variableStatementWithExpectedIdentifier =
|
|
37
|
+
sourceFile.getVariableStatement((statement) => {
|
|
38
|
+
let hasExpectedIdentifier = false;
|
|
39
|
+
statement
|
|
40
|
+
.getDeclarationList()
|
|
41
|
+
.getDeclarations()
|
|
42
|
+
.forEach((declarationNode) => {
|
|
43
|
+
if (declarationNode.getName() === file.mainImportIdentifier) {
|
|
44
|
+
hasExpectedIdentifier = true;
|
|
45
|
+
if (statement.isExported()) {
|
|
46
|
+
isExpectedIdentifierExportedInVariableStatement = true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (!hasExpectedIdentifier) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
if (!variableStatementWithExpectedIdentifier) {
|
|
58
|
+
// Did not find variable statement with expected identifier, add it to the end with a warning
|
|
59
|
+
sourceFile.addStatements(
|
|
60
|
+
'/* WARNING: The following resolver was missing from this file. Make sure it is properly implemented or there could be runtime errors. */'
|
|
61
|
+
);
|
|
62
|
+
sourceFile.addStatements(file.meta.resolverVariableStatement);
|
|
63
|
+
} else if (
|
|
64
|
+
variableStatementWithExpectedIdentifier &&
|
|
65
|
+
!isExpectedIdentifierExportedInVariableStatement
|
|
66
|
+
) {
|
|
67
|
+
// If has identifier but not exported
|
|
68
|
+
// Add export keyword to statement
|
|
69
|
+
const isExpectedIdentifierExported = Boolean(
|
|
70
|
+
sourceFile.getExportedDeclarations().get(file.mainImportIdentifier)
|
|
71
|
+
);
|
|
72
|
+
if (!isExpectedIdentifierExported) {
|
|
73
|
+
variableStatementWithExpectedIdentifier.setIsExported(true);
|
|
74
|
+
}
|
|
75
|
+
// else, if identifier's been exported do nothing
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Overwrite existing files with fixes
|
|
79
|
+
result.files[normalisedRelativePath] = {
|
|
80
|
+
...file,
|
|
81
|
+
content: sourceFile.getText(),
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import type { GraphQLObjectType } from 'graphql';
|
|
3
|
+
import type { HandleGraphQLType } from '../types';
|
|
4
|
+
import { printImportModule, relativeModulePath } from '../utils';
|
|
5
|
+
|
|
6
|
+
export const handleGraphQLObjectType: HandleGraphQLType<GraphQLObjectType> = (
|
|
7
|
+
type,
|
|
8
|
+
{ baseOutputDir, resolverTypesPath },
|
|
9
|
+
result
|
|
10
|
+
) => {
|
|
11
|
+
const fieldFilePath = path.join(baseOutputDir, `${type.name}.ts`);
|
|
12
|
+
if (result.files[fieldFilePath]) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
`Unexpected duplication in field filename. Type: ${type.name}, file: ${fieldFilePath}`
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const resolverTypeName = `${type.name}Resolvers`; // Generated type from typescript-resolvers plugin
|
|
19
|
+
const relativePathToResolverTypes = relativeModulePath(
|
|
20
|
+
baseOutputDir,
|
|
21
|
+
resolverTypesPath
|
|
22
|
+
);
|
|
23
|
+
const pathToResolverModule = printImportModule(relativePathToResolverTypes);
|
|
24
|
+
const resolverVariableStatement = `export const ${type.name}: ${resolverTypeName} = {
|
|
25
|
+
/* Implement ${type.name} resolver logic here */
|
|
26
|
+
};`;
|
|
27
|
+
result.files[fieldFilePath] = {
|
|
28
|
+
__filetype: 'resolver',
|
|
29
|
+
content: `import type { ${resolverTypeName} } from '${pathToResolverModule}';
|
|
30
|
+
${resolverVariableStatement}`,
|
|
31
|
+
mainImportIdentifier: type.name,
|
|
32
|
+
meta: {
|
|
33
|
+
belongsToRootObject: null,
|
|
34
|
+
resolverVariableStatement,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import type { GraphQLObjectType } from 'graphql';
|
|
3
|
+
import type { HandleGraphQLType } from '../types';
|
|
4
|
+
import {
|
|
5
|
+
isRootObjectType,
|
|
6
|
+
printImportModule,
|
|
7
|
+
relativeModulePath,
|
|
8
|
+
} from '../utils';
|
|
9
|
+
|
|
10
|
+
export const handleGraphQLRootObjectType: HandleGraphQLType<
|
|
11
|
+
GraphQLObjectType
|
|
12
|
+
> = (type, { baseOutputDir, resolverTypesPath }, result) => {
|
|
13
|
+
const typeName = type.name;
|
|
14
|
+
if (!isRootObjectType(typeName)) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const fields = type.getFields();
|
|
19
|
+
const outputDir = path.join(baseOutputDir, typeName);
|
|
20
|
+
|
|
21
|
+
result.dirs.push(outputDir);
|
|
22
|
+
|
|
23
|
+
Object.keys(fields).forEach((fieldName) => {
|
|
24
|
+
const fieldFilePath = path.join(outputDir, `${fieldName}.ts`);
|
|
25
|
+
if (result.files[fieldFilePath]) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`Unexpected duplication in field filename. Type: ${typeName}, file: ${fieldFilePath}`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const resolverTypeName = `${typeName}Resolvers`; // Generated type from typescript-resolvers plugin
|
|
32
|
+
const relativePathToResolverTypes = relativeModulePath(
|
|
33
|
+
outputDir,
|
|
34
|
+
resolverTypesPath
|
|
35
|
+
);
|
|
36
|
+
const pathToResolverModule = printImportModule(relativePathToResolverTypes);
|
|
37
|
+
const resolverVariableStatement = `export const ${fieldName}: ${resolverTypeName}['${fieldName}'] = async (_parent, _arg, _ctx) => {
|
|
38
|
+
/* Implement ${typeName}.${fieldName} resolver logic here */
|
|
39
|
+
};`;
|
|
40
|
+
|
|
41
|
+
result.files[fieldFilePath] = {
|
|
42
|
+
__filetype: 'resolver',
|
|
43
|
+
content: `import type { ${resolverTypeName} } from '${pathToResolverModule}';
|
|
44
|
+
${resolverVariableStatement}`,
|
|
45
|
+
mainImportIdentifier: fieldName,
|
|
46
|
+
meta: {
|
|
47
|
+
belongsToRootObject: typeName,
|
|
48
|
+
resolverVariableStatement,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import type { GraphQLUnionType } from 'graphql';
|
|
3
|
+
import type { HandleGraphQLType } from '../types';
|
|
4
|
+
import { printImportModule, relativeModulePath } from '../utils';
|
|
5
|
+
|
|
6
|
+
export const handleGraphQLUninionType: HandleGraphQLType<GraphQLUnionType> = (
|
|
7
|
+
type,
|
|
8
|
+
{ baseOutputDir, resolverTypesPath },
|
|
9
|
+
result
|
|
10
|
+
) => {
|
|
11
|
+
const typeName = type.name;
|
|
12
|
+
const fieldFilePath = path.join(baseOutputDir, `${typeName}.ts`);
|
|
13
|
+
if (result.files[fieldFilePath]) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
`Unexpected duplication in field filename. Type: ${typeName}, file: ${fieldFilePath}`
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const resolverTypeName = `${typeName}Resolvers`; // Generated type from typescript-resolvers plugin
|
|
20
|
+
const relativePathToResolverTypes = relativeModulePath(
|
|
21
|
+
baseOutputDir,
|
|
22
|
+
resolverTypesPath
|
|
23
|
+
);
|
|
24
|
+
const pathToResolverModule = printImportModule(relativePathToResolverTypes);
|
|
25
|
+
const resolverVariableStatement = `export const ${typeName}: ${resolverTypeName} = { __resolveType: (parent) => parent.__typename };`;
|
|
26
|
+
result.files[fieldFilePath] = {
|
|
27
|
+
__filetype: 'resolver',
|
|
28
|
+
content: `import type { ${resolverTypeName} } from '${pathToResolverModule}';
|
|
29
|
+
${resolverVariableStatement}`,
|
|
30
|
+
mainImportIdentifier: typeName,
|
|
31
|
+
meta: {
|
|
32
|
+
belongsToRootObject: null,
|
|
33
|
+
resolverVariableStatement,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
};
|
package/src/run/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { run } from './run';
|
package/src/run/run.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { isObjectType, isUnionType } from 'graphql';
|
|
2
|
+
import type { RunConfig, RunResult } from '../types';
|
|
3
|
+
import { isRootObjectType } from '../utils';
|
|
4
|
+
import { handleGraphQLRootObjectType } from './handleGraphQLRootObjectType';
|
|
5
|
+
import { handleGraphQLObjectType } from './handleGraphQLObjectType';
|
|
6
|
+
import { handleGraphQLUninionType } from './handleGraphQLUninionType';
|
|
7
|
+
import { addResolversIndexFile } from './addResolversIndexFile';
|
|
8
|
+
import { fixExistingResolvers } from './fixExistingResolvers';
|
|
9
|
+
|
|
10
|
+
export const run = (config: RunConfig, result: RunResult): void => {
|
|
11
|
+
Object.entries(config.schema.getTypeMap())
|
|
12
|
+
.filter(([schemaType]) => !schemaType.startsWith('__')) // There are a few internal types with `__` prefixes. We don't want them.
|
|
13
|
+
.forEach(([schemaType, namedType]) => {
|
|
14
|
+
if (isObjectType(namedType) && isRootObjectType(schemaType)) {
|
|
15
|
+
handleGraphQLRootObjectType(namedType, config, result);
|
|
16
|
+
} else if (isObjectType(namedType) && !isRootObjectType(schemaType)) {
|
|
17
|
+
handleGraphQLObjectType(namedType, config, result);
|
|
18
|
+
} else if (isUnionType(namedType)) {
|
|
19
|
+
handleGraphQLUninionType(namedType, config, result);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Check to see which resolver file exists already
|
|
24
|
+
fixExistingResolvers(result);
|
|
25
|
+
|
|
26
|
+
// Put all resolvers into a barrel file
|
|
27
|
+
addResolversIndexFile(config, result);
|
|
28
|
+
};
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { GraphQLSchema } from 'graphql';
|
|
2
|
+
|
|
3
|
+
interface BaseVirtualFile {
|
|
4
|
+
__filetype: string;
|
|
5
|
+
content: string;
|
|
6
|
+
mainImportIdentifier: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface StandardFile extends BaseVirtualFile {
|
|
10
|
+
__filetype: 'file';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ResolverFile extends BaseVirtualFile {
|
|
14
|
+
__filetype: 'resolver';
|
|
15
|
+
meta: {
|
|
16
|
+
belongsToRootObject: RootObjectType | null;
|
|
17
|
+
resolverVariableStatement: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface RunConfig {
|
|
22
|
+
baseOutputDir: string;
|
|
23
|
+
resolverTypesPath: string;
|
|
24
|
+
schema: GraphQLSchema;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface RunResult {
|
|
28
|
+
dirs: string[];
|
|
29
|
+
files: Record<string, StandardFile | ResolverFile>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type RootObjectType = 'Query' | 'Mutation' | 'Subscription';
|
|
33
|
+
|
|
34
|
+
export type HandleGraphQLType<T> = (
|
|
35
|
+
type: T,
|
|
36
|
+
params: RunConfig,
|
|
37
|
+
result: RunResult
|
|
38
|
+
) => void;
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import type { RootObjectType } from './types';
|
|
3
|
+
|
|
4
|
+
export const printImportModule = (moduleName: string) => {
|
|
5
|
+
if (moduleName.endsWith('.ts')) {
|
|
6
|
+
return moduleName.split('.').slice(0, -1).join('.');
|
|
7
|
+
}
|
|
8
|
+
return moduleName;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const isRootObjectType = (
|
|
12
|
+
typeName: string
|
|
13
|
+
): typeName is RootObjectType =>
|
|
14
|
+
typeName === 'Query' ||
|
|
15
|
+
typeName === 'Mutation' ||
|
|
16
|
+
typeName === 'Subscription';
|
|
17
|
+
|
|
18
|
+
export const relativeModulePath = (from: string, to: string) => {
|
|
19
|
+
const rawPath = path.relative(from, to);
|
|
20
|
+
|
|
21
|
+
if (!rawPath.startsWith('../') || !rawPath.startsWith('./')) {
|
|
22
|
+
return `./${rawPath}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return rawPath;
|
|
26
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"files": [],
|
|
4
|
+
"include": [],
|
|
5
|
+
"references": [
|
|
6
|
+
{
|
|
7
|
+
"path": "./tsconfig.lib.json"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"path": "./tsconfig.spec.json"
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"compilerOptions": {
|
|
14
|
+
"forceConsistentCasingInFileNames": true,
|
|
15
|
+
"strict": true,
|
|
16
|
+
"noImplicitReturns": true,
|
|
17
|
+
"noFallthroughCasesInSwitch": true
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "../../dist/out-tsc",
|
|
5
|
+
"module": "commonjs",
|
|
6
|
+
"types": ["jest", "node"]
|
|
7
|
+
},
|
|
8
|
+
"include": [
|
|
9
|
+
"jest.config.ts",
|
|
10
|
+
"**/*.test.ts",
|
|
11
|
+
"**/*.spec.ts",
|
|
12
|
+
"**/*.test.tsx",
|
|
13
|
+
"**/*.spec.tsx",
|
|
14
|
+
"**/*.test.js",
|
|
15
|
+
"**/*.spec.js",
|
|
16
|
+
"**/*.test.jsx",
|
|
17
|
+
"**/*.spec.jsx",
|
|
18
|
+
"**/*.d.ts"
|
|
19
|
+
]
|
|
20
|
+
}
|