houdini 0.17.8 → 0.17.10
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 +33 -0
- package/build/cmd-cjs/index.js +124 -38
- package/build/cmd-esm/index.js +124 -38
- package/build/codegen-cjs/index.js +112 -36
- package/build/codegen-esm/index.js +112 -36
- package/build/lib/config.d.ts +3 -0
- package/build/lib-cjs/index.js +31 -12
- package/build/lib-esm/index.js +31 -12
- package/build/runtime/cache/cache.d.ts +1 -1
- package/build/runtime/cache/lists.d.ts +1 -1
- package/build/runtime/lib/config.d.ts +10 -2
- package/build/runtime/lib/types.d.ts +1 -0
- package/build/runtime-cjs/cache/cache.d.ts +1 -1
- package/build/runtime-cjs/cache/cache.js +6 -6
- package/build/runtime-cjs/cache/lists.d.ts +1 -1
- package/build/runtime-cjs/cache/lists.js +15 -6
- package/build/runtime-cjs/cache/tests/list.test.js +160 -70
- package/build/runtime-cjs/lib/config.d.ts +10 -2
- package/build/runtime-cjs/lib/types.d.ts +1 -0
- package/build/runtime-esm/cache/cache.d.ts +1 -1
- package/build/runtime-esm/cache/cache.js +6 -6
- package/build/runtime-esm/cache/lists.d.ts +1 -1
- package/build/runtime-esm/cache/lists.js +15 -6
- package/build/runtime-esm/cache/tests/list.test.js +160 -70
- package/build/runtime-esm/lib/config.d.ts +10 -2
- package/build/runtime-esm/lib/types.d.ts +1 -0
- package/build/test-cjs/index.js +122 -36
- package/build/test-esm/index.js +122 -36
- package/build/vite-cjs/index.js +122 -36
- package/build/vite-esm/index.js +122 -36
- package/package.json +16 -1
- package/.turbo/turbo-compile.log +0 -5
- package/.turbo/turbo-typedefs.log +0 -5
- package/CHANGELOG.md +0 -367
- package/src/cmd/generate.ts +0 -54
- package/src/cmd/index.ts +0 -60
- package/src/cmd/init.ts +0 -637
- package/src/cmd/pullSchema.ts +0 -40
- package/src/codegen/generators/artifacts/artifacts.test.ts +0 -2978
- package/src/codegen/generators/artifacts/fieldKey.ts +0 -60
- package/src/codegen/generators/artifacts/index.ts +0 -330
- package/src/codegen/generators/artifacts/indexFile.ts +0 -24
- package/src/codegen/generators/artifacts/inputs.ts +0 -81
- package/src/codegen/generators/artifacts/operations.ts +0 -263
- package/src/codegen/generators/artifacts/pagination.test.ts +0 -664
- package/src/codegen/generators/artifacts/policy.test.ts +0 -298
- package/src/codegen/generators/artifacts/selection.ts +0 -208
- package/src/codegen/generators/artifacts/utils.test.ts +0 -118
- package/src/codegen/generators/artifacts/utils.ts +0 -108
- package/src/codegen/generators/definitions/enums.test.ts +0 -61
- package/src/codegen/generators/definitions/enums.ts +0 -68
- package/src/codegen/generators/definitions/index.ts +0 -11
- package/src/codegen/generators/definitions/schema.test.ts +0 -227
- package/src/codegen/generators/index.ts +0 -6
- package/src/codegen/generators/indexFile/index.ts +0 -63
- package/src/codegen/generators/indexFile/indexFile.test.ts +0 -72
- package/src/codegen/generators/persistedQueries/index.ts +0 -55
- package/src/codegen/generators/persistedQueries/persistedQuery.test.ts +0 -26
- package/src/codegen/generators/runtime/index.test.ts +0 -74
- package/src/codegen/generators/runtime/index.ts +0 -64
- package/src/codegen/generators/runtime/runtime.test.ts +0 -25
- package/src/codegen/generators/typescript/addReferencedInputTypes.ts +0 -77
- package/src/codegen/generators/typescript/index.ts +0 -412
- package/src/codegen/generators/typescript/inlineType.ts +0 -409
- package/src/codegen/generators/typescript/typeReference.ts +0 -44
- package/src/codegen/generators/typescript/types.ts +0 -81
- package/src/codegen/generators/typescript/typescript.test.ts +0 -1434
- package/src/codegen/index.ts +0 -406
- package/src/codegen/transforms/addID.test.ts +0 -93
- package/src/codegen/transforms/addID.ts +0 -86
- package/src/codegen/transforms/composeQueries.test.ts +0 -50
- package/src/codegen/transforms/composeQueries.ts +0 -154
- package/src/codegen/transforms/fragmentVariables.test.ts +0 -636
- package/src/codegen/transforms/fragmentVariables.ts +0 -417
- package/src/codegen/transforms/index.ts +0 -7
- package/src/codegen/transforms/list.ts +0 -485
- package/src/codegen/transforms/lists.test.ts +0 -530
- package/src/codegen/transforms/paginate.test.ts +0 -1481
- package/src/codegen/transforms/paginate.ts +0 -750
- package/src/codegen/transforms/schema.test.ts +0 -136
- package/src/codegen/transforms/schema.ts +0 -104
- package/src/codegen/transforms/typename.test.ts +0 -125
- package/src/codegen/transforms/typename.ts +0 -55
- package/src/codegen/utils/commonjs.ts +0 -26
- package/src/codegen/utils/flattenSelections.ts +0 -179
- package/src/codegen/utils/graphql.test.ts +0 -35
- package/src/codegen/utils/graphql.ts +0 -79
- package/src/codegen/utils/index.ts +0 -5
- package/src/codegen/utils/moduleExport.ts +0 -27
- package/src/codegen/utils/murmur.ts +0 -79
- package/src/codegen/validators/index.ts +0 -4
- package/src/codegen/validators/noIDAlias.test.ts +0 -71
- package/src/codegen/validators/noIDAlias.ts +0 -39
- package/src/codegen/validators/plugins.ts +0 -25
- package/src/codegen/validators/typeCheck.test.ts +0 -904
- package/src/codegen/validators/typeCheck.ts +0 -1031
- package/src/codegen/validators/uniqueNames.test.ts +0 -59
- package/src/codegen/validators/uniqueNames.ts +0 -39
- package/src/lib/cleanupFiles.ts +0 -20
- package/src/lib/config.test.ts +0 -13
- package/src/lib/config.ts +0 -943
- package/src/lib/constants.ts +0 -11
- package/src/lib/error.ts +0 -24
- package/src/lib/fs.ts +0 -285
- package/src/lib/graphql.test.ts +0 -211
- package/src/lib/graphql.ts +0 -200
- package/src/lib/imports.ts +0 -82
- package/src/lib/index.ts +0 -17
- package/src/lib/introspection.ts +0 -39
- package/src/lib/parse.test.ts +0 -75
- package/src/lib/parse.ts +0 -23
- package/src/lib/path.ts +0 -49
- package/src/lib/pipeline.ts +0 -17
- package/src/lib/types.ts +0 -34
- package/src/lib/walk.ts +0 -104
- package/src/runtime/cache/cache.ts +0 -1023
- package/src/runtime/cache/gc.ts +0 -56
- package/src/runtime/cache/index.ts +0 -3
- package/src/runtime/cache/lists.ts +0 -502
- package/src/runtime/cache/storage.ts +0 -574
- package/src/runtime/cache/stuff.ts +0 -77
- package/src/runtime/cache/subscription.ts +0 -329
- package/src/runtime/cache/tests/availability.test.ts +0 -408
- package/src/runtime/cache/tests/gc.test.ts +0 -319
- package/src/runtime/cache/tests/keys.test.ts +0 -36
- package/src/runtime/cache/tests/list.test.ts +0 -3747
- package/src/runtime/cache/tests/readwrite.test.ts +0 -1201
- package/src/runtime/cache/tests/scalars.test.ts +0 -218
- package/src/runtime/cache/tests/storage.test.ts +0 -426
- package/src/runtime/cache/tests/subscriptions.test.ts +0 -1757
- package/src/runtime/index.ts +0 -29
- package/src/runtime/lib/config.ts +0 -201
- package/src/runtime/lib/constants.ts +0 -17
- package/src/runtime/lib/deepEquals.ts +0 -32
- package/src/runtime/lib/errors.ts +0 -8
- package/src/runtime/lib/index.ts +0 -8
- package/src/runtime/lib/log.ts +0 -69
- package/src/runtime/lib/network.ts +0 -303
- package/src/runtime/lib/networkUtils.ts +0 -151
- package/src/runtime/lib/scalars.test.ts +0 -877
- package/src/runtime/lib/scalars.ts +0 -195
- package/src/runtime/lib/types.ts +0 -194
- package/src/test/index.ts +0 -294
- package/src/vite/ast.ts +0 -107
- package/src/vite/houdini.ts +0 -113
- package/src/vite/imports.ts +0 -129
- package/src/vite/index.ts +0 -55
- package/src/vite/schema.ts +0 -80
package/src/codegen/index.ts
DELETED
|
@@ -1,406 +0,0 @@
|
|
|
1
|
-
import * as graphql from 'graphql'
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
Config,
|
|
5
|
-
runPipeline as run,
|
|
6
|
-
LogLevel,
|
|
7
|
-
find_graphql,
|
|
8
|
-
parseJS,
|
|
9
|
-
HoudiniError,
|
|
10
|
-
Plugin,
|
|
11
|
-
fs,
|
|
12
|
-
CollectedGraphQLDocument,
|
|
13
|
-
path,
|
|
14
|
-
} from '../lib'
|
|
15
|
-
import { ArtifactKind } from '../runtime/lib/types'
|
|
16
|
-
import * as generators from './generators'
|
|
17
|
-
import * as transforms from './transforms'
|
|
18
|
-
import * as validators from './validators'
|
|
19
|
-
|
|
20
|
-
// the main entry point of the compile script
|
|
21
|
-
export default async function compile(config: Config) {
|
|
22
|
-
// grab the graphql documents
|
|
23
|
-
const documents = await collectDocuments(config)
|
|
24
|
-
|
|
25
|
-
// push the documents through the pipeline
|
|
26
|
-
await runPipeline(config, documents)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// the compiler's job can be broken down into a few different tasks after the documents have been collected:
|
|
30
|
-
// - validate their structure
|
|
31
|
-
// - perform a series of transformations
|
|
32
|
-
// - write the corresponding artifacts to disk
|
|
33
|
-
export async function runPipeline(config: Config, docs: CollectedGraphQLDocument[]) {
|
|
34
|
-
// we need to create the runtime folder structure
|
|
35
|
-
config.createDirectories()
|
|
36
|
-
|
|
37
|
-
// reset the newSchema accumulator
|
|
38
|
-
config.newSchema = ''
|
|
39
|
-
|
|
40
|
-
// reset the newDocuments accumulator
|
|
41
|
-
config.newDocuments = ''
|
|
42
|
-
|
|
43
|
-
// we need to hold onto some stats for the generated artifacts
|
|
44
|
-
const artifactStats = {
|
|
45
|
-
total: [],
|
|
46
|
-
changed: [],
|
|
47
|
-
new: [],
|
|
48
|
-
deleted: [],
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// collect any plugins that need to do something after generating
|
|
52
|
-
const generatePlugins = config.plugins.filter((plugin) => plugin.generate)
|
|
53
|
-
|
|
54
|
-
// run the generate command before we print "🎩 Generating runtime..." because we don't know upfront artifactStats.
|
|
55
|
-
let error: Error | null = null
|
|
56
|
-
try {
|
|
57
|
-
await run(
|
|
58
|
-
config,
|
|
59
|
-
[
|
|
60
|
-
// validators
|
|
61
|
-
validators.typeCheck,
|
|
62
|
-
validators.uniqueNames,
|
|
63
|
-
validators.noIDAlias,
|
|
64
|
-
validators.plugins,
|
|
65
|
-
|
|
66
|
-
// transforms
|
|
67
|
-
transforms.internalSchema,
|
|
68
|
-
transforms.addID,
|
|
69
|
-
transforms.typename,
|
|
70
|
-
// list transform must go before fragment variables
|
|
71
|
-
// so that the mutation fragments are defined before they get mixed in
|
|
72
|
-
transforms.list,
|
|
73
|
-
// paginate transform needs to go before fragmentVariables
|
|
74
|
-
// so that the variable definitions get hashed
|
|
75
|
-
transforms.paginate,
|
|
76
|
-
transforms.fragmentVariables,
|
|
77
|
-
transforms.composeQueries,
|
|
78
|
-
|
|
79
|
-
// generators
|
|
80
|
-
|
|
81
|
-
// the runtime is a static thing most of the time. It only needs to be regenerated if
|
|
82
|
-
// the user is upgrading versions or the client path changed
|
|
83
|
-
generators.runtime,
|
|
84
|
-
generators.indexFile,
|
|
85
|
-
generators.artifacts(artifactStats),
|
|
86
|
-
generators.typescript,
|
|
87
|
-
generators.persistOutput,
|
|
88
|
-
generators.definitions,
|
|
89
|
-
|
|
90
|
-
// these have to go after the artifacts so that plugins can import them
|
|
91
|
-
...generatePlugins.map(
|
|
92
|
-
(plugin) => async (config: Config, docs: CollectedGraphQLDocument[]) =>
|
|
93
|
-
await plugin.generate!({
|
|
94
|
-
config,
|
|
95
|
-
documents: docs,
|
|
96
|
-
plugin_root: config.pluginDirectory(plugin.name),
|
|
97
|
-
})
|
|
98
|
-
),
|
|
99
|
-
],
|
|
100
|
-
docs
|
|
101
|
-
)
|
|
102
|
-
} catch (e) {
|
|
103
|
-
error = e as Error
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/// Summary
|
|
107
|
-
|
|
108
|
-
// count the number of unchanged
|
|
109
|
-
const unchanged =
|
|
110
|
-
artifactStats.total.length -
|
|
111
|
-
artifactStats.changed.length -
|
|
112
|
-
artifactStats.new.length -
|
|
113
|
-
artifactStats.deleted.length
|
|
114
|
-
|
|
115
|
-
// If triggered from the plugin, we show logs ONLY if there are changes.
|
|
116
|
-
const printMessage = !config.pluginMode || unchanged !== artifactStats.total.length
|
|
117
|
-
if (!printMessage || config.logLevel === LogLevel.Quiet) {
|
|
118
|
-
if (error) {
|
|
119
|
-
throw error
|
|
120
|
-
}
|
|
121
|
-
return
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (!config.pluginMode) {
|
|
125
|
-
console.log('🎩 Generating runtime...')
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (error) {
|
|
129
|
-
throw error
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// print a line showing that the process is finished (wo document)
|
|
133
|
-
if (artifactStats.total.length === 0) {
|
|
134
|
-
console.log(`💡 No operation found. If that's unexpected, please check your config.`)
|
|
135
|
-
}
|
|
136
|
-
// print summaries of the changes
|
|
137
|
-
else if ([LogLevel.Summary, LogLevel.ShortSummary].includes(config.logLevel)) {
|
|
138
|
-
// if we have any unchanged artifacts
|
|
139
|
-
if (unchanged > 0 && printMessage && !config.pluginMode) {
|
|
140
|
-
console.log(`📃 Unchanged: ${unchanged}`)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
logStyled('CREATED', artifactStats.new, config.logLevel, config.pluginMode)
|
|
144
|
-
logStyled('UPDATED', artifactStats.changed, config.logLevel, config.pluginMode)
|
|
145
|
-
logStyled('DELETED', artifactStats.deleted, config.logLevel, config.pluginMode)
|
|
146
|
-
}
|
|
147
|
-
// print the status of every file
|
|
148
|
-
else if (config.logLevel === LogLevel.Full) {
|
|
149
|
-
for (const artifact of artifactStats.total) {
|
|
150
|
-
// figure out the emoji to use
|
|
151
|
-
let emoji = '📃'
|
|
152
|
-
if (artifactStats.changed.includes(artifact)) {
|
|
153
|
-
emoji = '✏️'
|
|
154
|
-
} else if (artifactStats.new.includes(artifact)) {
|
|
155
|
-
emoji = '✨'
|
|
156
|
-
} else if (artifactStats.deleted.includes(artifact)) {
|
|
157
|
-
emoji = '🧹'
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// log the name
|
|
161
|
-
console.log(`${emoji} ${artifact}`)
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
async function collectDocuments(config: Config): Promise<CollectedGraphQLDocument[]> {
|
|
167
|
-
// the first step we have to do is grab a list of every file in the source tree
|
|
168
|
-
let sourceFiles = await config.sourceFiles()
|
|
169
|
-
|
|
170
|
-
// the list of documents we found
|
|
171
|
-
const documents: DiscoveredDoc[] = []
|
|
172
|
-
|
|
173
|
-
const extractors: Record<string, Plugin['extract_documents'][]> = {
|
|
174
|
-
'.graphql': [],
|
|
175
|
-
'.gql': [],
|
|
176
|
-
'.js': [],
|
|
177
|
-
'.ts': [],
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// a config's set of plugins defines a priority list of ways to extract a document from a file
|
|
181
|
-
// build up a mapping from extension to a list functions that extract documents
|
|
182
|
-
for (const plugin of config.plugins) {
|
|
183
|
-
if (plugin.extensions && plugin.extract_documents) {
|
|
184
|
-
for (const extension of plugin.extensions) {
|
|
185
|
-
extractors[extension] = [...(extractors[extension] || []), plugin.extract_documents]
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// add the default extractors at the end of the appropriate lists
|
|
191
|
-
const graphql_extractor = (filepath: string, content: string) => [content]
|
|
192
|
-
const javascript_extractor = (filepath: string, content: string) =>
|
|
193
|
-
processJSFile(config, content)
|
|
194
|
-
extractors['.ts'].push(javascript_extractor)
|
|
195
|
-
extractors['.js'].push(javascript_extractor)
|
|
196
|
-
extractors['.graphql'].push(graphql_extractor)
|
|
197
|
-
extractors['.gql'].push(graphql_extractor)
|
|
198
|
-
|
|
199
|
-
// wait for every file to be processed
|
|
200
|
-
await Promise.all(
|
|
201
|
-
sourceFiles.map(async (filepath) => {
|
|
202
|
-
// read the file
|
|
203
|
-
const contents = await fs.readFile(filepath)
|
|
204
|
-
if (!contents) {
|
|
205
|
-
return
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// look for extractors for the given extension
|
|
209
|
-
const extension = path.extname(filepath)
|
|
210
|
-
|
|
211
|
-
// if we don't recognize the extension but were told to include it as a
|
|
212
|
-
// source file, there is likely something wrong. maybe a missing plugin?
|
|
213
|
-
if (!extractors[extension]) {
|
|
214
|
-
throw new HoudiniError({
|
|
215
|
-
filepath,
|
|
216
|
-
message:
|
|
217
|
-
'Encountered a file extension that could not be processed: ' + extension,
|
|
218
|
-
description: 'Please verify you are not missing a plugin.',
|
|
219
|
-
})
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// make sure any errors include the filepath
|
|
223
|
-
try {
|
|
224
|
-
// if the file ends with .svelte, we need to look for graphql template tags
|
|
225
|
-
for (const extractor of extractors[extension]) {
|
|
226
|
-
if (!extractor) {
|
|
227
|
-
continue
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
const found = await extractor(filepath, contents)
|
|
231
|
-
if (found.length > 0) {
|
|
232
|
-
documents.push(...found.map((document) => ({ filepath, document })))
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
} catch (err) {
|
|
236
|
-
throw new HoudiniError({ ...(err as HoudiniError), filepath })
|
|
237
|
-
}
|
|
238
|
-
})
|
|
239
|
-
)
|
|
240
|
-
|
|
241
|
-
return await Promise.all(
|
|
242
|
-
documents.map(async ({ document, filepath }) => {
|
|
243
|
-
try {
|
|
244
|
-
return await processGraphQLDocument(config, filepath, document)
|
|
245
|
-
} catch (e) {
|
|
246
|
-
throw new HoudiniError({ filepath, message: (e as unknown as Error).message })
|
|
247
|
-
}
|
|
248
|
-
})
|
|
249
|
-
)
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
export type DiscoveredDoc = {
|
|
253
|
-
filepath: string
|
|
254
|
-
document: string
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
async function processJSFile(config: Config, contents: string): Promise<string[]> {
|
|
258
|
-
const documents: string[] = []
|
|
259
|
-
|
|
260
|
-
// parse the contents as js
|
|
261
|
-
try {
|
|
262
|
-
var program = (await parseJS(contents))!.script
|
|
263
|
-
} catch (e) {
|
|
264
|
-
console.log(contents)
|
|
265
|
-
throw e
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// look for a graphql template tag
|
|
269
|
-
await find_graphql(config, program, {
|
|
270
|
-
tag({ tagContent }) {
|
|
271
|
-
documents.push(tagContent)
|
|
272
|
-
},
|
|
273
|
-
})
|
|
274
|
-
|
|
275
|
-
// we found every document in the file
|
|
276
|
-
return documents
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
async function processGraphQLDocument(
|
|
280
|
-
config: Config,
|
|
281
|
-
filepath: string,
|
|
282
|
-
document: string
|
|
283
|
-
): Promise<CollectedGraphQLDocument> {
|
|
284
|
-
const parsedDoc = graphql.parse(document)
|
|
285
|
-
|
|
286
|
-
// look for the operation
|
|
287
|
-
const operations = parsedDoc.definitions.filter(
|
|
288
|
-
({ kind }) => kind === graphql.Kind.OPERATION_DEFINITION
|
|
289
|
-
)
|
|
290
|
-
// there are no operations, so its a fragment
|
|
291
|
-
const fragments = parsedDoc.definitions.filter(
|
|
292
|
-
({ kind }) => kind === graphql.Kind.FRAGMENT_DEFINITION
|
|
293
|
-
)
|
|
294
|
-
// if there is more than one operation, throw an error
|
|
295
|
-
if (operations.length > 1) {
|
|
296
|
-
throw new HoudiniError({
|
|
297
|
-
filepath,
|
|
298
|
-
message: 'Operation documents can only have one operation',
|
|
299
|
-
})
|
|
300
|
-
}
|
|
301
|
-
// we are looking at a fragment document
|
|
302
|
-
else {
|
|
303
|
-
// if there is more than one fragment, throw an error
|
|
304
|
-
if (fragments.length > 1) {
|
|
305
|
-
throw new HoudiniError({
|
|
306
|
-
filepath,
|
|
307
|
-
message: 'Fragment documents can only have one fragment',
|
|
308
|
-
})
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// figure out the document kind
|
|
313
|
-
let kind = ArtifactKind.Fragment
|
|
314
|
-
if (operations.length === 1) {
|
|
315
|
-
// the document kind depends on the artifact
|
|
316
|
-
|
|
317
|
-
// query
|
|
318
|
-
if (operations[0].kind === 'OperationDefinition' && operations[0].operation === 'query') {
|
|
319
|
-
kind = ArtifactKind.Query
|
|
320
|
-
}
|
|
321
|
-
// mutation
|
|
322
|
-
else if (
|
|
323
|
-
operations[0].kind === 'OperationDefinition' &&
|
|
324
|
-
operations[0].operation === 'mutation'
|
|
325
|
-
) {
|
|
326
|
-
kind = ArtifactKind.Mutation
|
|
327
|
-
}
|
|
328
|
-
// subscription
|
|
329
|
-
else if (
|
|
330
|
-
operations[0].kind === 'OperationDefinition' &&
|
|
331
|
-
operations[0].operation === 'subscription'
|
|
332
|
-
) {
|
|
333
|
-
kind = ArtifactKind.Subscription
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// add it to the list
|
|
338
|
-
return {
|
|
339
|
-
name: config.documentName(parsedDoc),
|
|
340
|
-
kind,
|
|
341
|
-
document: parsedDoc,
|
|
342
|
-
filename: filepath,
|
|
343
|
-
originalDocument: parsedDoc,
|
|
344
|
-
generateArtifact: true,
|
|
345
|
-
generateStore: true,
|
|
346
|
-
originalString: document,
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
function logStyled(
|
|
351
|
-
kind: 'CREATED' | 'UPDATED' | 'DELETED',
|
|
352
|
-
stat: string[],
|
|
353
|
-
logLevel: LogLevel,
|
|
354
|
-
plugin: boolean
|
|
355
|
-
) {
|
|
356
|
-
if (stat.length > 0) {
|
|
357
|
-
// Let's prepare the one liner in the plugin mode, of a bit more in other lol level.
|
|
358
|
-
const msg: string[] = []
|
|
359
|
-
|
|
360
|
-
// in plugin mode, it will be very short, let's put a hat first.
|
|
361
|
-
if (plugin) {
|
|
362
|
-
msg.push(`🎩 `)
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
if (kind === 'CREATED') {
|
|
366
|
-
msg.push(`✨ `)
|
|
367
|
-
if (!plugin) {
|
|
368
|
-
msg.push(`New: ${stat.length}`)
|
|
369
|
-
}
|
|
370
|
-
} else if (kind === 'UPDATED') {
|
|
371
|
-
msg.push(`✏️ `)
|
|
372
|
-
if (!plugin) {
|
|
373
|
-
msg.push(`Changed: ${stat.length}`)
|
|
374
|
-
}
|
|
375
|
-
} else if (kind === 'DELETED') {
|
|
376
|
-
msg.push(`🧹 `)
|
|
377
|
-
if (!plugin) {
|
|
378
|
-
msg.push(`Deleted: ${stat.length}`)
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
// let's do a summary for x elements
|
|
383
|
-
const nbToDisplay = 5
|
|
384
|
-
|
|
385
|
-
// format for plugin
|
|
386
|
-
if (plugin) {
|
|
387
|
-
msg.push(`${stat.slice(0, nbToDisplay).join(', ')}`)
|
|
388
|
-
if (stat.length > 5) {
|
|
389
|
-
msg.push(`, ... ${stat.length - nbToDisplay} more`)
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
console.log(msg.join(''))
|
|
394
|
-
|
|
395
|
-
// Format for not plugin & Summary mode
|
|
396
|
-
if (!plugin && logLevel === LogLevel.Summary) {
|
|
397
|
-
for (const artifact of stat.slice(0, nbToDisplay)) {
|
|
398
|
-
console.log(` ${artifact}`)
|
|
399
|
-
}
|
|
400
|
-
// if there are more than 5 just tell them how many
|
|
401
|
-
if (stat.length > nbToDisplay) {
|
|
402
|
-
console.log(` ... ${stat.length - nbToDisplay} more`)
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { test, expect } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import { runPipeline } from '../../codegen'
|
|
4
|
-
import { testConfig, mockCollectedDoc } from '../../test'
|
|
5
|
-
|
|
6
|
-
test('adds ids to selection sets of objects with them', async function () {
|
|
7
|
-
const docs = [
|
|
8
|
-
mockCollectedDoc(
|
|
9
|
-
`
|
|
10
|
-
query Friends {
|
|
11
|
-
user {
|
|
12
|
-
firstName
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
`
|
|
16
|
-
),
|
|
17
|
-
]
|
|
18
|
-
|
|
19
|
-
// run the pipeline
|
|
20
|
-
const config = testConfig()
|
|
21
|
-
await runPipeline(config, docs)
|
|
22
|
-
|
|
23
|
-
expect(docs[0].document).toMatchInlineSnapshot(`
|
|
24
|
-
query Friends {
|
|
25
|
-
user {
|
|
26
|
-
firstName
|
|
27
|
-
id
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
`)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
test("doesn't add id if there isn't one", async function () {
|
|
35
|
-
const docs = [
|
|
36
|
-
mockCollectedDoc(
|
|
37
|
-
`
|
|
38
|
-
query Friends {
|
|
39
|
-
ghost {
|
|
40
|
-
legends {
|
|
41
|
-
name
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
`
|
|
46
|
-
),
|
|
47
|
-
]
|
|
48
|
-
|
|
49
|
-
// run the pipeline
|
|
50
|
-
const config = testConfig()
|
|
51
|
-
await runPipeline(config, docs)
|
|
52
|
-
|
|
53
|
-
expect(docs[0].document).toMatchInlineSnapshot(`
|
|
54
|
-
query Friends {
|
|
55
|
-
ghost {
|
|
56
|
-
legends {
|
|
57
|
-
name
|
|
58
|
-
}
|
|
59
|
-
name
|
|
60
|
-
aka
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
`)
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
test('adds custom id fields to selection sets of objects with them', async function () {
|
|
68
|
-
const docs = [
|
|
69
|
-
mockCollectedDoc(
|
|
70
|
-
`
|
|
71
|
-
query Friends {
|
|
72
|
-
ghost {
|
|
73
|
-
name
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
`
|
|
77
|
-
),
|
|
78
|
-
]
|
|
79
|
-
|
|
80
|
-
// run the pipeline
|
|
81
|
-
const config = testConfig()
|
|
82
|
-
await runPipeline(config, docs)
|
|
83
|
-
|
|
84
|
-
expect(docs[0].document).toMatchInlineSnapshot(`
|
|
85
|
-
query Friends {
|
|
86
|
-
ghost {
|
|
87
|
-
name
|
|
88
|
-
aka
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
`)
|
|
93
|
-
})
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import * as graphql from 'graphql'
|
|
2
|
-
|
|
3
|
-
import { Config, parentTypeFromAncestors, CollectedGraphQLDocument } from '../../lib'
|
|
4
|
-
import { unwrapType } from '../utils'
|
|
5
|
-
|
|
6
|
-
// typename adds __typename to the selection set of any unions or interfaces
|
|
7
|
-
export default async function addID(
|
|
8
|
-
config: Config,
|
|
9
|
-
documents: CollectedGraphQLDocument[]
|
|
10
|
-
): Promise<void> {
|
|
11
|
-
// visit every document
|
|
12
|
-
for (const doc of documents) {
|
|
13
|
-
// update the document (graphql.visit is pure)
|
|
14
|
-
doc.document = graphql.visit(doc.document, {
|
|
15
|
-
Field(node, key, parent, path, ancestors): graphql.ASTNode | undefined {
|
|
16
|
-
// if we are looking at a leaf type
|
|
17
|
-
if (!node.selectionSet) {
|
|
18
|
-
return
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// figure out the parent type
|
|
22
|
-
const type = parentTypeFromAncestors(
|
|
23
|
-
config.schema,
|
|
24
|
-
doc.filename,
|
|
25
|
-
ancestors.slice(0, -1)
|
|
26
|
-
)
|
|
27
|
-
// look up the field definition in the parent type
|
|
28
|
-
const field = type.getFields()[node.name.value]
|
|
29
|
-
|
|
30
|
-
// look up the field in the parent
|
|
31
|
-
const fieldType = unwrapType(config, field.type).type
|
|
32
|
-
|
|
33
|
-
// if there is no selection set, don't worry about it
|
|
34
|
-
if (node.selectionSet?.selections.length > 0) {
|
|
35
|
-
// if the type does not have an id field ignore it
|
|
36
|
-
if (!graphql.isObjectType(fieldType) && !graphql.isInterfaceType(fieldType)) {
|
|
37
|
-
return
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// look up the key fields for a given type
|
|
41
|
-
const keyFields = config.keyFieldsForType(fieldType.name)
|
|
42
|
-
|
|
43
|
-
// if there is no id field of the type
|
|
44
|
-
if (keyFields.find((key) => !fieldType.getFields()[key])) {
|
|
45
|
-
return
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// add the id fields for the given type
|
|
49
|
-
const selections = [...node.selectionSet.selections]
|
|
50
|
-
|
|
51
|
-
for (const keyField of keyFields) {
|
|
52
|
-
// if there is already a selection for id, ignore it
|
|
53
|
-
if (
|
|
54
|
-
node.selectionSet.selections.find(
|
|
55
|
-
(selection) =>
|
|
56
|
-
selection.kind === 'Field' &&
|
|
57
|
-
!selection.alias &&
|
|
58
|
-
selection.name.value === keyField
|
|
59
|
-
)
|
|
60
|
-
) {
|
|
61
|
-
continue
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// add a selection for the field to the selection set
|
|
65
|
-
selections.push({
|
|
66
|
-
kind: graphql.Kind.FIELD,
|
|
67
|
-
name: {
|
|
68
|
-
kind: graphql.Kind.NAME,
|
|
69
|
-
value: keyField,
|
|
70
|
-
},
|
|
71
|
-
})
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// add the __typename selection to the field's selection set
|
|
75
|
-
return {
|
|
76
|
-
...node,
|
|
77
|
-
selectionSet: {
|
|
78
|
-
...node.selectionSet,
|
|
79
|
-
selections,
|
|
80
|
-
},
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
})
|
|
85
|
-
}
|
|
86
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import * as graphql from 'graphql'
|
|
2
|
-
import { expect, test } from 'vitest'
|
|
3
|
-
|
|
4
|
-
import { CollectedGraphQLDocument } from '../../lib'
|
|
5
|
-
import { pipelineTest, testConfig } from '../../test'
|
|
6
|
-
|
|
7
|
-
const start = [
|
|
8
|
-
`
|
|
9
|
-
query Foo {
|
|
10
|
-
version
|
|
11
|
-
...A
|
|
12
|
-
}
|
|
13
|
-
`,
|
|
14
|
-
`
|
|
15
|
-
fragment A on User {
|
|
16
|
-
firstName
|
|
17
|
-
...B
|
|
18
|
-
}
|
|
19
|
-
`,
|
|
20
|
-
`
|
|
21
|
-
fragment B on User {
|
|
22
|
-
firstName
|
|
23
|
-
}
|
|
24
|
-
`,
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
test(
|
|
28
|
-
'include fragment definitions',
|
|
29
|
-
pipelineTest(testConfig(), start, true, function (docs: CollectedGraphQLDocument[]) {
|
|
30
|
-
// we only care about the Foo document
|
|
31
|
-
const fooDoc = docs.find((doc) => doc.name === 'Foo')!
|
|
32
|
-
|
|
33
|
-
// make sure there are at least three definitions
|
|
34
|
-
expect(fooDoc.document.definitions).toHaveLength(3)
|
|
35
|
-
|
|
36
|
-
// make sure that there is one for each fragment
|
|
37
|
-
const fragmentADef = fooDoc.document.definitions.find(
|
|
38
|
-
(definition) =>
|
|
39
|
-
definition.kind === graphql.Kind.FRAGMENT_DEFINITION &&
|
|
40
|
-
definition.name.value === 'A'
|
|
41
|
-
)
|
|
42
|
-
const fragmentBDef = fooDoc.document.definitions.find(
|
|
43
|
-
(definition) =>
|
|
44
|
-
definition.kind === graphql.Kind.FRAGMENT_DEFINITION &&
|
|
45
|
-
definition.name.value === 'B'
|
|
46
|
-
)
|
|
47
|
-
expect(fragmentADef).toBeDefined()
|
|
48
|
-
expect(fragmentBDef).toBeDefined()
|
|
49
|
-
})
|
|
50
|
-
)
|