-
Notifications
You must be signed in to change notification settings - Fork 10.3k
/
ts-codegen.ts
155 lines (145 loc) · 4.52 KB
/
ts-codegen.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import * as fs from "fs-extra"
import { join } from "path"
import { codegen } from "@graphql-codegen/core"
import { GraphQLSchema, Kind } from "graphql"
import type { Types } from "@graphql-codegen/plugin-helpers"
import type { TypeScriptPluginConfig } from "@graphql-codegen/typescript/config"
import type { TypeScriptDocumentsPluginConfig } from "@graphql-codegen/typescript-operations/config"
import { CodeFileLoader } from "@graphql-tools/code-file-loader"
import { loadDocuments } from "@graphql-tools/load"
import { IDefinitionMeta, IStateProgram } from "../../redux/types"
import {
filterTargetDefinitions,
sortDefinitions,
stabilizeSchema,
} from "./utils"
const OUTPUT_PATH = `src/gatsby-types.d.ts`
const NAMESPACE = `Queries`
// These override the defaults from
// https://www.graphql-code-generator.com/plugins/typescript
const DEFAULT_TYPESCRIPT_CONFIG: Readonly<TypeScriptPluginConfig> = {
// <Maybe> Type is enough
avoidOptionals: true,
// Types come from the data layer so they can't be modified
immutableTypes: true,
// TODO: Better maybeValue
maybeValue: `T | null`,
// We'll want to re-export ourselves
noExport: true,
// Recommended for .d.ts files
enumsAsTypes: true,
scalars: {
Date: `string`,
JSON: `Record<string, unknown>`,
GatsbyImageData: `import('gatsby-plugin-image').IGatsbyImageData`,
},
// import type {} syntax is nicer
useTypeImports: true,
}
const DEFAULT_TYPESCRIPT_OPERATIONS_CONFIG: Readonly<TypeScriptDocumentsPluginConfig> =
{
...DEFAULT_TYPESCRIPT_CONFIG,
exportFragmentSpreadSubTypes: true,
}
export async function writeTypeScriptTypes(
directory: IStateProgram["directory"],
schema: GraphQLSchema,
definitions: Map<string, IDefinitionMeta>
): Promise<void> {
const pluginConfig: Pick<Types.GenerateOptions, "plugins" | "pluginMap"> = {
pluginMap: {
add: require(`@graphql-codegen/add`),
typescript: require(`@graphql-codegen/typescript`),
typescriptOperations: require(`@graphql-codegen/typescript-operations`),
},
plugins: [
{
add: {
placement: `prepend`,
content: `/* eslint-disable */\n`,
},
},
{
add: {
placement: `prepend`,
content: `/* THIS FILE IS AUTOGENERATED. CHANGES WILL BE LOST ON SUBSEQUENT RUNS. */\n`,
},
},
{
add: {
placement: `prepend`,
content: `declare namespace ${NAMESPACE} {\n`,
},
},
{
typescript: DEFAULT_TYPESCRIPT_CONFIG,
},
{
typescriptOperations: DEFAULT_TYPESCRIPT_OPERATIONS_CONFIG,
},
{
add: {
placement: `append`,
content: `\n}\n`,
},
},
],
}
const filename = join(directory, OUTPUT_PATH)
let gatsbyNodeDocuments: Array<Types.DocumentFile> = []
// The loadDocuments + CodeFileLoader looks for graphql(``) functions inside the gatsby-node.ts files
// And then extracts the queries into documents
// TODO: This codepath can be made obsolete if Gatsby itself already places the queries inside gatsby-node into the `definitions`
try {
gatsbyNodeDocuments = await loadDocuments(
[`./gatsby-node.ts`, `./plugins/**/gatsby-node.ts`],
{
loaders: [
new CodeFileLoader({
// Configures https://www.graphql-tools.com/docs/graphql-tag-pluck to only check graphql function from Gatsby
pluckConfig: {
modules: [{ name: `gatsby`, identifier: `graphql` }],
},
}),
],
sort: true,
}
)
} catch (e) {
// These files might not exist, so just skip this
}
const documents: Array<Types.DocumentFile> = [
...filterTargetDefinitions(definitions).values(),
]
.sort(sortDefinitions)
.map(definitionMeta => {
return {
document: {
kind: Kind.DOCUMENT,
definitions: [definitionMeta.def],
},
hash: definitionMeta.hash.toString(),
}
})
const codegenOptions: Omit<Types.GenerateOptions, "plugins" | "pluginMap"> = {
// @ts-ignore - Incorrect types
schema: undefined,
schemaAst: stabilizeSchema(schema),
documents: documents.concat(gatsbyNodeDocuments),
filename,
config: {
namingConvention: {
typeNames: `keep`,
enumValues: `keep`,
transformUnderscore: false,
},
addUnderscoreToArgsType: true,
skipTypename: true,
},
}
const result = await codegen({
...pluginConfig,
...codegenOptions,
})
await fs.outputFile(filename, result)
}