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
|
@@ -1,1434 +0,0 @@
|
|
|
1
|
-
import * as recast from 'recast'
|
|
2
|
-
import * as typeScriptParser from 'recast/parsers/typescript'
|
|
3
|
-
import { test, expect, describe } from 'vitest'
|
|
4
|
-
|
|
5
|
-
import { runPipeline } from '../..'
|
|
6
|
-
import { fs } from '../../../lib'
|
|
7
|
-
import { testConfig, mockCollectedDoc } from '../../../test'
|
|
8
|
-
|
|
9
|
-
// the config to use in tests
|
|
10
|
-
const config = testConfig({
|
|
11
|
-
schema: `
|
|
12
|
-
enum MyEnum {
|
|
13
|
-
Hello
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
type Query {
|
|
17
|
-
user(id: ID, filter: UserFilter, filterList: [UserFilter!], enumArg: MyEnum): User
|
|
18
|
-
users: [User]
|
|
19
|
-
nodes: [Node!]!
|
|
20
|
-
entities: [Entity]
|
|
21
|
-
entity: Entity!
|
|
22
|
-
listOfLists: [[User]]!
|
|
23
|
-
node(id: ID!): Node
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
type Mutation {
|
|
27
|
-
doThing(
|
|
28
|
-
filter: UserFilter,
|
|
29
|
-
list: [UserFilter!]!,
|
|
30
|
-
id: ID!
|
|
31
|
-
firstName: String!
|
|
32
|
-
admin: Boolean
|
|
33
|
-
age: Int
|
|
34
|
-
weight: Float
|
|
35
|
-
): User
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
input UserFilter {
|
|
39
|
-
middle: NestedUserFilter
|
|
40
|
-
listRequired: [String!]!
|
|
41
|
-
nullList: [String]
|
|
42
|
-
recursive: UserFilter
|
|
43
|
-
enum: MyEnum
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
input NestedUserFilter {
|
|
47
|
-
id: ID!
|
|
48
|
-
firstName: String!
|
|
49
|
-
admin: Boolean
|
|
50
|
-
age: Int
|
|
51
|
-
weight: Float
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
interface Node {
|
|
55
|
-
id: ID!
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
type Cat implements Node & Animal {
|
|
59
|
-
id: ID!
|
|
60
|
-
kitty: Boolean!
|
|
61
|
-
isAnimal: Boolean!
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
interface Animal {
|
|
66
|
-
isAnimal: Boolean!
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
union Entity = User | Cat
|
|
70
|
-
|
|
71
|
-
union AnotherEntity = User | Ghost
|
|
72
|
-
|
|
73
|
-
type Ghost implements Node {
|
|
74
|
-
id: ID!
|
|
75
|
-
aka: String!
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
type User implements Node {
|
|
79
|
-
id: ID!
|
|
80
|
-
|
|
81
|
-
firstName: String!
|
|
82
|
-
nickname: String
|
|
83
|
-
parent: User
|
|
84
|
-
friends: [User]
|
|
85
|
-
enumValue: MyEnum
|
|
86
|
-
|
|
87
|
-
admin: Boolean
|
|
88
|
-
age: Int
|
|
89
|
-
weight: Float
|
|
90
|
-
}
|
|
91
|
-
`,
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
describe('typescript', function () {
|
|
95
|
-
test('fragment types', async function () {
|
|
96
|
-
// the document to test
|
|
97
|
-
const doc = mockCollectedDoc(
|
|
98
|
-
`fragment TestFragment on User { firstName nickname enumValue }`
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
// execute the generator
|
|
102
|
-
await runPipeline(config, [doc])
|
|
103
|
-
|
|
104
|
-
// look up the files in the artifact directory
|
|
105
|
-
const fileContents = await fs.readFile(config.artifactTypePath(doc.document))
|
|
106
|
-
|
|
107
|
-
// make sure they match what we expect
|
|
108
|
-
expect(
|
|
109
|
-
recast.parse(fileContents!, {
|
|
110
|
-
parser: typeScriptParser,
|
|
111
|
-
})
|
|
112
|
-
).toMatchInlineSnapshot(`
|
|
113
|
-
import { MyEnum } from "$houdini/graphql/enums";
|
|
114
|
-
|
|
115
|
-
export type TestFragment = {
|
|
116
|
-
readonly "shape"?: TestFragment$data
|
|
117
|
-
readonly "$fragments": {
|
|
118
|
-
"TestFragment": true
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
export type TestFragment$data = {
|
|
123
|
-
readonly firstName: string
|
|
124
|
-
readonly nickname: string | null
|
|
125
|
-
readonly enumValue: MyEnum | null
|
|
126
|
-
};
|
|
127
|
-
`)
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
test('nested types', async function () {
|
|
131
|
-
const fragment = `fragment TestFragment on User { firstName parent { firstName } }`
|
|
132
|
-
|
|
133
|
-
// the document to test
|
|
134
|
-
const doc = mockCollectedDoc(fragment)
|
|
135
|
-
|
|
136
|
-
// execute the generator
|
|
137
|
-
await runPipeline(config, [doc])
|
|
138
|
-
|
|
139
|
-
// look up the files in the artifact directory
|
|
140
|
-
const fileContents = await fs.readFile(config.artifactTypePath(doc.document))
|
|
141
|
-
|
|
142
|
-
// make sure they match what we expect
|
|
143
|
-
expect(
|
|
144
|
-
recast.parse(fileContents!, {
|
|
145
|
-
parser: typeScriptParser,
|
|
146
|
-
})
|
|
147
|
-
).toMatchInlineSnapshot(`
|
|
148
|
-
export type TestFragment = {
|
|
149
|
-
readonly "shape"?: TestFragment$data
|
|
150
|
-
readonly "$fragments": {
|
|
151
|
-
"TestFragment": true
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
export type TestFragment$data = {
|
|
156
|
-
readonly firstName: string
|
|
157
|
-
readonly parent: {
|
|
158
|
-
readonly firstName: string
|
|
159
|
-
} | null
|
|
160
|
-
};
|
|
161
|
-
`)
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
test('scalars', async function () {
|
|
165
|
-
// the document to test
|
|
166
|
-
const doc = mockCollectedDoc(
|
|
167
|
-
`fragment TestFragment on User { firstName admin age id weight }`
|
|
168
|
-
)
|
|
169
|
-
|
|
170
|
-
// execute the generator
|
|
171
|
-
await runPipeline(config, [doc])
|
|
172
|
-
|
|
173
|
-
// look up the files in the artifact directory
|
|
174
|
-
const fileContents = await fs.readFile(config.artifactTypePath(doc.document))
|
|
175
|
-
|
|
176
|
-
// make sure they match what we expect
|
|
177
|
-
expect(
|
|
178
|
-
recast.parse(fileContents!, {
|
|
179
|
-
parser: typeScriptParser,
|
|
180
|
-
})
|
|
181
|
-
).toMatchInlineSnapshot(`
|
|
182
|
-
export type TestFragment = {
|
|
183
|
-
readonly "shape"?: TestFragment$data
|
|
184
|
-
readonly "$fragments": {
|
|
185
|
-
"TestFragment": true
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
export type TestFragment$data = {
|
|
190
|
-
readonly firstName: string
|
|
191
|
-
readonly admin: boolean | null
|
|
192
|
-
readonly age: number | null
|
|
193
|
-
readonly id: string
|
|
194
|
-
readonly weight: number | null
|
|
195
|
-
};
|
|
196
|
-
`)
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
test('list types', async function () {
|
|
200
|
-
// the document to test
|
|
201
|
-
const doc = mockCollectedDoc(
|
|
202
|
-
`fragment TestFragment on User { firstName friends { firstName } }`
|
|
203
|
-
)
|
|
204
|
-
|
|
205
|
-
// execute the generator
|
|
206
|
-
await runPipeline(config, [doc])
|
|
207
|
-
|
|
208
|
-
// look up the files in the artifact directory
|
|
209
|
-
const fileContents = await fs.readFile(config.artifactTypePath(doc.document))
|
|
210
|
-
|
|
211
|
-
// make sure they match what we expect
|
|
212
|
-
expect(
|
|
213
|
-
recast.parse(fileContents!, {
|
|
214
|
-
parser: typeScriptParser,
|
|
215
|
-
})
|
|
216
|
-
).toMatchInlineSnapshot(`
|
|
217
|
-
export type TestFragment = {
|
|
218
|
-
readonly "shape"?: TestFragment$data
|
|
219
|
-
readonly "$fragments": {
|
|
220
|
-
"TestFragment": true
|
|
221
|
-
}
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
export type TestFragment$data = {
|
|
225
|
-
readonly firstName: string
|
|
226
|
-
readonly friends: ({
|
|
227
|
-
readonly firstName: string
|
|
228
|
-
} | null)[] | null
|
|
229
|
-
};
|
|
230
|
-
`)
|
|
231
|
-
})
|
|
232
|
-
|
|
233
|
-
test('query with no input', async function () {
|
|
234
|
-
// the document to test
|
|
235
|
-
const doc = mockCollectedDoc(`query MyQuery { user { firstName } }`)
|
|
236
|
-
|
|
237
|
-
// execute the generator
|
|
238
|
-
await runPipeline(config, [doc])
|
|
239
|
-
|
|
240
|
-
// look up the files in the artifact directory
|
|
241
|
-
const fileContents = await fs.readFile(config.artifactTypePath(doc.document))
|
|
242
|
-
|
|
243
|
-
// make sure they match what we expect
|
|
244
|
-
expect(
|
|
245
|
-
recast.parse(fileContents!, {
|
|
246
|
-
parser: typeScriptParser,
|
|
247
|
-
})
|
|
248
|
-
).toMatchInlineSnapshot(`
|
|
249
|
-
export type MyQuery = {
|
|
250
|
-
readonly "input": MyQuery$input
|
|
251
|
-
readonly "result": MyQuery$result | undefined
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
export type MyQuery$result = {
|
|
255
|
-
readonly user: {
|
|
256
|
-
readonly firstName: string
|
|
257
|
-
} | null
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
export type MyQuery$input = null;
|
|
261
|
-
`)
|
|
262
|
-
})
|
|
263
|
-
|
|
264
|
-
test('query with root list', async function () {
|
|
265
|
-
// the document with the query
|
|
266
|
-
const queryDoc = mockCollectedDoc(`
|
|
267
|
-
query MyQuery {
|
|
268
|
-
users {
|
|
269
|
-
firstName,
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
`)
|
|
273
|
-
// execute the generator
|
|
274
|
-
await runPipeline(config, [queryDoc])
|
|
275
|
-
|
|
276
|
-
// look up the files in the artifact directory
|
|
277
|
-
const fileContents = await fs.readFile(config.artifactTypePath(queryDoc.document))
|
|
278
|
-
|
|
279
|
-
// make sure they match what we expect
|
|
280
|
-
expect(
|
|
281
|
-
recast.parse(fileContents!, {
|
|
282
|
-
parser: typeScriptParser,
|
|
283
|
-
})
|
|
284
|
-
).toMatchInlineSnapshot(`
|
|
285
|
-
export type MyQuery = {
|
|
286
|
-
readonly "input": MyQuery$input
|
|
287
|
-
readonly "result": MyQuery$result | undefined
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
export type MyQuery$result = {
|
|
291
|
-
readonly users: ({
|
|
292
|
-
readonly firstName: string
|
|
293
|
-
} | null)[] | null
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
export type MyQuery$input = null;
|
|
297
|
-
`)
|
|
298
|
-
})
|
|
299
|
-
|
|
300
|
-
test('query with input', async function () {
|
|
301
|
-
// the document to test
|
|
302
|
-
const doc = mockCollectedDoc(
|
|
303
|
-
`query MyQuery($id: ID!, $enum: MyEnum) { user(id: $id, enumArg: $enum ) { firstName } }`
|
|
304
|
-
)
|
|
305
|
-
|
|
306
|
-
// execute the generator
|
|
307
|
-
await runPipeline(config, [doc])
|
|
308
|
-
|
|
309
|
-
// look up the files in the artifact directory
|
|
310
|
-
const fileContents = await fs.readFile(config.artifactTypePath(doc.document))
|
|
311
|
-
|
|
312
|
-
// make sure they match what we expect
|
|
313
|
-
expect(
|
|
314
|
-
recast.parse(fileContents!, {
|
|
315
|
-
parser: typeScriptParser,
|
|
316
|
-
})
|
|
317
|
-
).toMatchInlineSnapshot(`
|
|
318
|
-
import type { MyEnum } from "$houdini/graphql/enums";
|
|
319
|
-
|
|
320
|
-
export type MyQuery = {
|
|
321
|
-
readonly "input": MyQuery$input
|
|
322
|
-
readonly "result": MyQuery$result | undefined
|
|
323
|
-
};
|
|
324
|
-
|
|
325
|
-
export type MyQuery$result = {
|
|
326
|
-
readonly user: {
|
|
327
|
-
readonly firstName: string
|
|
328
|
-
} | null
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
export type MyQuery$input = {
|
|
332
|
-
id: string
|
|
333
|
-
enum?: MyEnum | null | undefined
|
|
334
|
-
};
|
|
335
|
-
`)
|
|
336
|
-
})
|
|
337
|
-
|
|
338
|
-
test('interface on interface', async function () {
|
|
339
|
-
// the document to test
|
|
340
|
-
const doc = mockCollectedDoc(
|
|
341
|
-
`query MyTestQuery {
|
|
342
|
-
entity {
|
|
343
|
-
... on Node {
|
|
344
|
-
id
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
}`
|
|
348
|
-
)
|
|
349
|
-
|
|
350
|
-
// execute the generator
|
|
351
|
-
await runPipeline(config, [doc])
|
|
352
|
-
|
|
353
|
-
// look up the files in the artifact directory
|
|
354
|
-
const fileContents = await fs.readFile(config.artifactTypePath(doc.document))
|
|
355
|
-
|
|
356
|
-
// make sure they match what we expect
|
|
357
|
-
expect(
|
|
358
|
-
recast.parse(fileContents!, {
|
|
359
|
-
parser: typeScriptParser,
|
|
360
|
-
})
|
|
361
|
-
).toMatchInlineSnapshot(`
|
|
362
|
-
export type MyTestQuery = {
|
|
363
|
-
readonly "input": MyTestQuery$input
|
|
364
|
-
readonly "result": MyTestQuery$result | undefined
|
|
365
|
-
};
|
|
366
|
-
|
|
367
|
-
export type MyTestQuery$result = {
|
|
368
|
-
readonly entity: {} & (({
|
|
369
|
-
readonly id: string
|
|
370
|
-
readonly __typename: "Cat"
|
|
371
|
-
}) | ({
|
|
372
|
-
readonly id: string
|
|
373
|
-
readonly __typename: "User"
|
|
374
|
-
}))
|
|
375
|
-
};
|
|
376
|
-
|
|
377
|
-
export type MyTestQuery$input = null;
|
|
378
|
-
`)
|
|
379
|
-
})
|
|
380
|
-
|
|
381
|
-
test('mutation with input list', async function () {
|
|
382
|
-
// the document to test
|
|
383
|
-
const doc = mockCollectedDoc(
|
|
384
|
-
`mutation MyMutation(
|
|
385
|
-
$filter: UserFilter,
|
|
386
|
-
$filterList: [UserFilter!]!,
|
|
387
|
-
$id: ID!
|
|
388
|
-
$firstName: String!
|
|
389
|
-
$admin: Boolean
|
|
390
|
-
$age: Int
|
|
391
|
-
$weight: Float
|
|
392
|
-
) { doThing(
|
|
393
|
-
filter: $filter,
|
|
394
|
-
list: $filterList,
|
|
395
|
-
id:$id
|
|
396
|
-
firstName:$firstName
|
|
397
|
-
admin:$admin
|
|
398
|
-
age:$age
|
|
399
|
-
weight:$weight
|
|
400
|
-
) {
|
|
401
|
-
firstName
|
|
402
|
-
}
|
|
403
|
-
}`
|
|
404
|
-
)
|
|
405
|
-
|
|
406
|
-
// execute the generator
|
|
407
|
-
await runPipeline(config, [doc])
|
|
408
|
-
|
|
409
|
-
// look up the files in the artifact directory
|
|
410
|
-
const fileContents = await fs.readFile(config.artifactTypePath(doc.document))
|
|
411
|
-
|
|
412
|
-
// make sure they match what we expect
|
|
413
|
-
expect(
|
|
414
|
-
recast.parse(fileContents!, {
|
|
415
|
-
parser: typeScriptParser,
|
|
416
|
-
})
|
|
417
|
-
).toMatchInlineSnapshot(`
|
|
418
|
-
import type { MyEnum } from "$houdini/graphql/enums";
|
|
419
|
-
|
|
420
|
-
export type MyMutation = {
|
|
421
|
-
readonly "input": MyMutation$input
|
|
422
|
-
readonly "result": MyMutation$result
|
|
423
|
-
};
|
|
424
|
-
|
|
425
|
-
export type MyMutation$result = {
|
|
426
|
-
readonly doThing: {
|
|
427
|
-
readonly firstName: string
|
|
428
|
-
} | null
|
|
429
|
-
};
|
|
430
|
-
|
|
431
|
-
type NestedUserFilter = {
|
|
432
|
-
id: string
|
|
433
|
-
firstName: string
|
|
434
|
-
admin?: boolean | null | undefined
|
|
435
|
-
age?: number | null | undefined
|
|
436
|
-
weight?: number | null | undefined
|
|
437
|
-
};
|
|
438
|
-
|
|
439
|
-
type UserFilter = {
|
|
440
|
-
middle?: NestedUserFilter | null | undefined
|
|
441
|
-
listRequired: (string)[]
|
|
442
|
-
nullList?: (string | null | undefined)[] | null | undefined
|
|
443
|
-
recursive?: UserFilter | null | undefined
|
|
444
|
-
enum?: MyEnum | null | undefined
|
|
445
|
-
};
|
|
446
|
-
|
|
447
|
-
export type MyMutation$input = {
|
|
448
|
-
filter?: UserFilter | null | undefined
|
|
449
|
-
filterList: (UserFilter)[]
|
|
450
|
-
id: string
|
|
451
|
-
firstName: string
|
|
452
|
-
admin?: boolean | null | undefined
|
|
453
|
-
age?: number | null | undefined
|
|
454
|
-
weight?: number | null | undefined
|
|
455
|
-
};
|
|
456
|
-
|
|
457
|
-
export type MyMutation$optimistic = {
|
|
458
|
-
readonly doThing?: {
|
|
459
|
-
readonly firstName?: string
|
|
460
|
-
} | null
|
|
461
|
-
};
|
|
462
|
-
`)
|
|
463
|
-
})
|
|
464
|
-
|
|
465
|
-
test("mutation optimistic response type doesn't include fragments", async function () {
|
|
466
|
-
// the document to test
|
|
467
|
-
const docs = [
|
|
468
|
-
mockCollectedDoc(
|
|
469
|
-
`mutation MyMutation {
|
|
470
|
-
doThing(
|
|
471
|
-
list: [],
|
|
472
|
-
id: "1"
|
|
473
|
-
firstName: "hello"
|
|
474
|
-
) {
|
|
475
|
-
firstName
|
|
476
|
-
...TestFragment,
|
|
477
|
-
}
|
|
478
|
-
}`
|
|
479
|
-
),
|
|
480
|
-
mockCollectedDoc(
|
|
481
|
-
`fragment TestFragment on User {
|
|
482
|
-
firstName
|
|
483
|
-
}`
|
|
484
|
-
),
|
|
485
|
-
]
|
|
486
|
-
|
|
487
|
-
// execute the generator
|
|
488
|
-
await runPipeline(config, docs)
|
|
489
|
-
|
|
490
|
-
// look up the files in the artifact directory
|
|
491
|
-
const fileContents = await fs.readFile(config.artifactTypePath(docs[0].document))
|
|
492
|
-
|
|
493
|
-
// make sure they match what we expect
|
|
494
|
-
expect(
|
|
495
|
-
recast.parse(fileContents!, {
|
|
496
|
-
parser: typeScriptParser,
|
|
497
|
-
})
|
|
498
|
-
).toMatchInlineSnapshot(`
|
|
499
|
-
export type MyMutation = {
|
|
500
|
-
readonly "input": MyMutation$input
|
|
501
|
-
readonly "result": MyMutation$result
|
|
502
|
-
};
|
|
503
|
-
|
|
504
|
-
export type MyMutation$result = {
|
|
505
|
-
readonly doThing: {
|
|
506
|
-
readonly firstName: string
|
|
507
|
-
readonly $fragments: {
|
|
508
|
-
TestFragment: true
|
|
509
|
-
}
|
|
510
|
-
} | null
|
|
511
|
-
};
|
|
512
|
-
|
|
513
|
-
export type MyMutation$input = null;
|
|
514
|
-
|
|
515
|
-
export type MyMutation$optimistic = {
|
|
516
|
-
readonly doThing?: {
|
|
517
|
-
readonly firstName?: string
|
|
518
|
-
} | null
|
|
519
|
-
};
|
|
520
|
-
`)
|
|
521
|
-
})
|
|
522
|
-
|
|
523
|
-
test('nested input objects', async function () {
|
|
524
|
-
// the document to test
|
|
525
|
-
const doc = mockCollectedDoc(
|
|
526
|
-
`query MyQuery($filter: UserFilter!) { user(filter: $filter) { firstName } }`
|
|
527
|
-
)
|
|
528
|
-
|
|
529
|
-
// execute the generator
|
|
530
|
-
await runPipeline(config, [doc])
|
|
531
|
-
|
|
532
|
-
// look up the files in the artifact directory
|
|
533
|
-
const fileContents = await fs.readFile(config.artifactTypePath(doc.document))
|
|
534
|
-
|
|
535
|
-
// make sure they match what we expect
|
|
536
|
-
expect(
|
|
537
|
-
recast.parse(fileContents!, {
|
|
538
|
-
parser: typeScriptParser,
|
|
539
|
-
})
|
|
540
|
-
).toMatchInlineSnapshot(`
|
|
541
|
-
import type { MyEnum } from "$houdini/graphql/enums";
|
|
542
|
-
|
|
543
|
-
export type MyQuery = {
|
|
544
|
-
readonly "input": MyQuery$input
|
|
545
|
-
readonly "result": MyQuery$result | undefined
|
|
546
|
-
};
|
|
547
|
-
|
|
548
|
-
export type MyQuery$result = {
|
|
549
|
-
readonly user: {
|
|
550
|
-
readonly firstName: string
|
|
551
|
-
} | null
|
|
552
|
-
};
|
|
553
|
-
|
|
554
|
-
type NestedUserFilter = {
|
|
555
|
-
id: string
|
|
556
|
-
firstName: string
|
|
557
|
-
admin?: boolean | null | undefined
|
|
558
|
-
age?: number | null | undefined
|
|
559
|
-
weight?: number | null | undefined
|
|
560
|
-
};
|
|
561
|
-
|
|
562
|
-
type UserFilter = {
|
|
563
|
-
middle?: NestedUserFilter | null | undefined
|
|
564
|
-
listRequired: (string)[]
|
|
565
|
-
nullList?: (string | null | undefined)[] | null | undefined
|
|
566
|
-
recursive?: UserFilter | null | undefined
|
|
567
|
-
enum?: MyEnum | null | undefined
|
|
568
|
-
};
|
|
569
|
-
|
|
570
|
-
export type MyQuery$input = {
|
|
571
|
-
filter: UserFilter
|
|
572
|
-
};
|
|
573
|
-
`)
|
|
574
|
-
})
|
|
575
|
-
|
|
576
|
-
test('generates index file', async function () {
|
|
577
|
-
// the document to test
|
|
578
|
-
const doc = mockCollectedDoc(
|
|
579
|
-
`query MyQuery($filter: UserFilter!) { user(filter: $filter) { firstName } }`
|
|
580
|
-
)
|
|
581
|
-
|
|
582
|
-
// execute the generator
|
|
583
|
-
await runPipeline(config, [doc])
|
|
584
|
-
|
|
585
|
-
// read the type index file
|
|
586
|
-
const fileContents = await fs.readFile(config.typeIndexPath)
|
|
587
|
-
|
|
588
|
-
expect(
|
|
589
|
-
recast.parse(fileContents!, {
|
|
590
|
-
parser: typeScriptParser,
|
|
591
|
-
})
|
|
592
|
-
).toMatchInlineSnapshot(`
|
|
593
|
-
export * from "./artifacts/MyQuery";
|
|
594
|
-
export * from "./runtime";
|
|
595
|
-
export * from "./graphql";
|
|
596
|
-
`)
|
|
597
|
-
})
|
|
598
|
-
|
|
599
|
-
test('fragment spreads', async function () {
|
|
600
|
-
// the document with the fragment
|
|
601
|
-
const fragment = mockCollectedDoc(`fragment Foo on User { firstName }`)
|
|
602
|
-
|
|
603
|
-
// the document to test
|
|
604
|
-
const query = mockCollectedDoc(`query MyQuery { user { ...Foo } }`)
|
|
605
|
-
|
|
606
|
-
// execute the generator
|
|
607
|
-
await runPipeline(config, [query, fragment])
|
|
608
|
-
|
|
609
|
-
// look up the files in the artifact directory
|
|
610
|
-
const fileContents = await fs.readFile(config.artifactTypePath(query.document))
|
|
611
|
-
|
|
612
|
-
// make sure they match what we expect
|
|
613
|
-
expect(
|
|
614
|
-
recast.parse(fileContents!, {
|
|
615
|
-
parser: typeScriptParser,
|
|
616
|
-
})
|
|
617
|
-
).toMatchInlineSnapshot(`
|
|
618
|
-
export type MyQuery = {
|
|
619
|
-
readonly "input": MyQuery$input
|
|
620
|
-
readonly "result": MyQuery$result | undefined
|
|
621
|
-
};
|
|
622
|
-
|
|
623
|
-
export type MyQuery$result = {
|
|
624
|
-
readonly user: {
|
|
625
|
-
readonly $fragments: {
|
|
626
|
-
Foo: true
|
|
627
|
-
}
|
|
628
|
-
} | null
|
|
629
|
-
};
|
|
630
|
-
|
|
631
|
-
export type MyQuery$input = null;
|
|
632
|
-
`)
|
|
633
|
-
})
|
|
634
|
-
|
|
635
|
-
test('fragment spreads no masking', async function () {
|
|
636
|
-
const withoutMasking = testConfig({ disableMasking: true })
|
|
637
|
-
|
|
638
|
-
// the document with the fragment
|
|
639
|
-
const fragment = mockCollectedDoc(`fragment Foo on User { firstName }`)
|
|
640
|
-
|
|
641
|
-
// the document to test
|
|
642
|
-
const query = mockCollectedDoc(`query MyQuery { user { ...Foo } }`)
|
|
643
|
-
|
|
644
|
-
// execute the generator
|
|
645
|
-
await runPipeline(withoutMasking, [query, fragment])
|
|
646
|
-
|
|
647
|
-
// look up the files in the artifact directory
|
|
648
|
-
const fileContents = await fs.readFile(config.artifactTypePath(query.document))
|
|
649
|
-
|
|
650
|
-
// make sure they match what we expect
|
|
651
|
-
expect(
|
|
652
|
-
recast.parse(fileContents!, {
|
|
653
|
-
parser: typeScriptParser,
|
|
654
|
-
})
|
|
655
|
-
).toMatchInlineSnapshot(`
|
|
656
|
-
export type MyQuery = {
|
|
657
|
-
readonly "input": MyQuery$input
|
|
658
|
-
readonly "result": MyQuery$result | undefined
|
|
659
|
-
};
|
|
660
|
-
|
|
661
|
-
export type MyQuery$result = {
|
|
662
|
-
readonly user: {
|
|
663
|
-
readonly firstName: string
|
|
664
|
-
readonly $fragments: {
|
|
665
|
-
Foo: true
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
};
|
|
669
|
-
|
|
670
|
-
export type MyQuery$input = null;
|
|
671
|
-
`)
|
|
672
|
-
})
|
|
673
|
-
|
|
674
|
-
test('interfaces', async function () {
|
|
675
|
-
// the document to test
|
|
676
|
-
const query = mockCollectedDoc(
|
|
677
|
-
`
|
|
678
|
-
query MyQuery {
|
|
679
|
-
nodes {
|
|
680
|
-
... on User {
|
|
681
|
-
id
|
|
682
|
-
}
|
|
683
|
-
... on Cat {
|
|
684
|
-
id
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
`
|
|
689
|
-
)
|
|
690
|
-
|
|
691
|
-
// execute the generator
|
|
692
|
-
await runPipeline(config, [query])
|
|
693
|
-
|
|
694
|
-
// look up the files in the artifact directory
|
|
695
|
-
const fileContents = await fs.readFile(config.artifactTypePath(query.document))
|
|
696
|
-
|
|
697
|
-
// make sure they match what we expect
|
|
698
|
-
expect(
|
|
699
|
-
recast.parse(fileContents!, {
|
|
700
|
-
parser: typeScriptParser,
|
|
701
|
-
})
|
|
702
|
-
).toMatchInlineSnapshot(`
|
|
703
|
-
export type MyQuery = {
|
|
704
|
-
readonly "input": MyQuery$input
|
|
705
|
-
readonly "result": MyQuery$result | undefined
|
|
706
|
-
};
|
|
707
|
-
|
|
708
|
-
export type MyQuery$result = {
|
|
709
|
-
readonly nodes: ({} & (({
|
|
710
|
-
readonly id: string
|
|
711
|
-
readonly __typename: "User"
|
|
712
|
-
}) | ({
|
|
713
|
-
readonly id: string
|
|
714
|
-
readonly __typename: "Cat"
|
|
715
|
-
})))[]
|
|
716
|
-
};
|
|
717
|
-
|
|
718
|
-
export type MyQuery$input = null;
|
|
719
|
-
`)
|
|
720
|
-
})
|
|
721
|
-
|
|
722
|
-
test('unions', async function () {
|
|
723
|
-
// the document to test
|
|
724
|
-
const query = mockCollectedDoc(
|
|
725
|
-
`
|
|
726
|
-
query MyQuery {
|
|
727
|
-
entities {
|
|
728
|
-
... on User {
|
|
729
|
-
id
|
|
730
|
-
}
|
|
731
|
-
... on Cat {
|
|
732
|
-
id
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
`
|
|
737
|
-
)
|
|
738
|
-
|
|
739
|
-
// execute the generator
|
|
740
|
-
await runPipeline(config, [query])
|
|
741
|
-
|
|
742
|
-
// look up the files in the artifact directory
|
|
743
|
-
const fileContents = await fs.readFile(config.artifactTypePath(query.document))
|
|
744
|
-
|
|
745
|
-
// make sure they match what we expect
|
|
746
|
-
expect(
|
|
747
|
-
recast.parse(fileContents!, {
|
|
748
|
-
parser: typeScriptParser,
|
|
749
|
-
})
|
|
750
|
-
).toMatchInlineSnapshot(`
|
|
751
|
-
export type MyQuery = {
|
|
752
|
-
readonly "input": MyQuery$input
|
|
753
|
-
readonly "result": MyQuery$result | undefined
|
|
754
|
-
};
|
|
755
|
-
|
|
756
|
-
export type MyQuery$result = {
|
|
757
|
-
readonly entities: ({} & (({
|
|
758
|
-
readonly id: string
|
|
759
|
-
readonly __typename: "User"
|
|
760
|
-
}) | ({
|
|
761
|
-
readonly id: string
|
|
762
|
-
readonly __typename: "Cat"
|
|
763
|
-
})) | null)[] | null
|
|
764
|
-
};
|
|
765
|
-
|
|
766
|
-
export type MyQuery$input = null;
|
|
767
|
-
`)
|
|
768
|
-
})
|
|
769
|
-
|
|
770
|
-
test('discriminated interface', async function () {
|
|
771
|
-
// the document to test
|
|
772
|
-
const query = mockCollectedDoc(
|
|
773
|
-
`
|
|
774
|
-
query MyQuery {
|
|
775
|
-
nodes {
|
|
776
|
-
id
|
|
777
|
-
... on User {
|
|
778
|
-
firstName
|
|
779
|
-
}
|
|
780
|
-
... on Cat {
|
|
781
|
-
kitty
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
`
|
|
786
|
-
)
|
|
787
|
-
|
|
788
|
-
// execute the generator
|
|
789
|
-
await runPipeline(config, [query])
|
|
790
|
-
|
|
791
|
-
// look up the files in the artifact directory
|
|
792
|
-
const fileContents = await fs.readFile(config.artifactTypePath(query.document))
|
|
793
|
-
|
|
794
|
-
// make sure they match what we expect
|
|
795
|
-
expect(
|
|
796
|
-
recast.parse(fileContents!, {
|
|
797
|
-
parser: typeScriptParser,
|
|
798
|
-
})
|
|
799
|
-
).toMatchInlineSnapshot(`
|
|
800
|
-
export type MyQuery = {
|
|
801
|
-
readonly "input": MyQuery$input
|
|
802
|
-
readonly "result": MyQuery$result | undefined
|
|
803
|
-
};
|
|
804
|
-
|
|
805
|
-
export type MyQuery$result = {
|
|
806
|
-
readonly nodes: ({
|
|
807
|
-
readonly id: string
|
|
808
|
-
} & (({
|
|
809
|
-
readonly firstName: string
|
|
810
|
-
readonly __typename: "User"
|
|
811
|
-
}) | ({
|
|
812
|
-
readonly kitty: boolean
|
|
813
|
-
readonly __typename: "Cat"
|
|
814
|
-
})))[]
|
|
815
|
-
};
|
|
816
|
-
|
|
817
|
-
export type MyQuery$input = null;
|
|
818
|
-
`)
|
|
819
|
-
})
|
|
820
|
-
|
|
821
|
-
test('intersecting interface', async function () {
|
|
822
|
-
// the document to test
|
|
823
|
-
const query = mockCollectedDoc(
|
|
824
|
-
`
|
|
825
|
-
query MyQuery {
|
|
826
|
-
entities {
|
|
827
|
-
... on Animal {
|
|
828
|
-
isAnimal
|
|
829
|
-
}
|
|
830
|
-
... on User {
|
|
831
|
-
firstName
|
|
832
|
-
}
|
|
833
|
-
... on Cat {
|
|
834
|
-
kitty
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
`
|
|
839
|
-
)
|
|
840
|
-
|
|
841
|
-
// execute the generator
|
|
842
|
-
await runPipeline(config, [query])
|
|
843
|
-
|
|
844
|
-
// look up the files in the artifact directory
|
|
845
|
-
const fileContents = await fs.readFile(config.artifactTypePath(query.document))
|
|
846
|
-
|
|
847
|
-
// make sure they match what we expect
|
|
848
|
-
expect(
|
|
849
|
-
recast.parse(fileContents!, {
|
|
850
|
-
parser: typeScriptParser,
|
|
851
|
-
})
|
|
852
|
-
).toMatchInlineSnapshot(`
|
|
853
|
-
export type MyQuery = {
|
|
854
|
-
readonly "input": MyQuery$input
|
|
855
|
-
readonly "result": MyQuery$result | undefined
|
|
856
|
-
};
|
|
857
|
-
|
|
858
|
-
export type MyQuery$result = {
|
|
859
|
-
readonly entities: ({} & (({
|
|
860
|
-
readonly isAnimal: boolean
|
|
861
|
-
readonly kitty: boolean
|
|
862
|
-
readonly __typename: "Cat"
|
|
863
|
-
}) | ({
|
|
864
|
-
readonly firstName: string
|
|
865
|
-
readonly __typename: "User"
|
|
866
|
-
})) | null)[] | null
|
|
867
|
-
};
|
|
868
|
-
|
|
869
|
-
export type MyQuery$input = null;
|
|
870
|
-
`)
|
|
871
|
-
})
|
|
872
|
-
|
|
873
|
-
test('fragment with custom scalars', async function () {
|
|
874
|
-
// define a config with a custom scalar
|
|
875
|
-
const localConfig = testConfig({
|
|
876
|
-
schema: `
|
|
877
|
-
scalar DateTime
|
|
878
|
-
|
|
879
|
-
type TodoItem {
|
|
880
|
-
text: String!
|
|
881
|
-
createdAt: DateTime!
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
type Query {
|
|
885
|
-
allItems: [TodoItem!]!
|
|
886
|
-
}
|
|
887
|
-
`,
|
|
888
|
-
scalars: {
|
|
889
|
-
DateTime: {
|
|
890
|
-
type: 'Date',
|
|
891
|
-
unmarshal(val: number): Date {
|
|
892
|
-
return new Date(val)
|
|
893
|
-
},
|
|
894
|
-
marshal(date: Date): number {
|
|
895
|
-
return date.getTime()
|
|
896
|
-
},
|
|
897
|
-
},
|
|
898
|
-
},
|
|
899
|
-
})
|
|
900
|
-
|
|
901
|
-
// the document to test
|
|
902
|
-
const query = mockCollectedDoc(`query MyQuery { allItems { createdAt } }`)
|
|
903
|
-
|
|
904
|
-
// execute the generator
|
|
905
|
-
await runPipeline(localConfig, [query])
|
|
906
|
-
|
|
907
|
-
// look up the files in the artifact directory
|
|
908
|
-
const fileContents = await fs.readFile(config.artifactTypePath(query.document))
|
|
909
|
-
|
|
910
|
-
// make sure they match what we expect
|
|
911
|
-
expect(
|
|
912
|
-
recast.parse(fileContents!, {
|
|
913
|
-
parser: typeScriptParser,
|
|
914
|
-
})
|
|
915
|
-
).toMatchInlineSnapshot(`
|
|
916
|
-
export type MyQuery = {
|
|
917
|
-
readonly "input": MyQuery$input
|
|
918
|
-
readonly "result": MyQuery$result | undefined
|
|
919
|
-
};
|
|
920
|
-
|
|
921
|
-
export type MyQuery$result = {
|
|
922
|
-
readonly allItems: ({
|
|
923
|
-
readonly createdAt: Date
|
|
924
|
-
})[]
|
|
925
|
-
};
|
|
926
|
-
|
|
927
|
-
export type MyQuery$input = null;
|
|
928
|
-
`)
|
|
929
|
-
})
|
|
930
|
-
|
|
931
|
-
test('input with custom scalars', async function () {
|
|
932
|
-
// define a config with a custom scalar
|
|
933
|
-
const localConfig = testConfig({
|
|
934
|
-
schema: `
|
|
935
|
-
scalar DateTime
|
|
936
|
-
|
|
937
|
-
type TodoItem {
|
|
938
|
-
text: String!
|
|
939
|
-
createdAt: DateTime!
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
type Query {
|
|
943
|
-
allItems(createdAt: DateTime): [TodoItem!]!
|
|
944
|
-
}
|
|
945
|
-
`,
|
|
946
|
-
scalars: {
|
|
947
|
-
DateTime: {
|
|
948
|
-
type: 'Date',
|
|
949
|
-
unmarshal(val: number): Date {
|
|
950
|
-
return new Date(val)
|
|
951
|
-
},
|
|
952
|
-
marshal(date: Date): number {
|
|
953
|
-
return date.getTime()
|
|
954
|
-
},
|
|
955
|
-
},
|
|
956
|
-
},
|
|
957
|
-
})
|
|
958
|
-
|
|
959
|
-
// the document to test
|
|
960
|
-
const query = mockCollectedDoc(
|
|
961
|
-
`query MyQuery($date: DateTime!) { allItems(createdAt: $date) { createdAt } }`
|
|
962
|
-
)
|
|
963
|
-
|
|
964
|
-
// execute the generator
|
|
965
|
-
await runPipeline(localConfig, [query])
|
|
966
|
-
|
|
967
|
-
// look up the files in the artifact directory
|
|
968
|
-
const fileContents = await fs.readFile(config.artifactTypePath(query.document))
|
|
969
|
-
|
|
970
|
-
// make sure they match what we expect
|
|
971
|
-
expect(
|
|
972
|
-
recast.parse(fileContents!, {
|
|
973
|
-
parser: typeScriptParser,
|
|
974
|
-
})
|
|
975
|
-
).toMatchInlineSnapshot(`
|
|
976
|
-
export type MyQuery = {
|
|
977
|
-
readonly "input": MyQuery$input
|
|
978
|
-
readonly "result": MyQuery$result | undefined
|
|
979
|
-
};
|
|
980
|
-
|
|
981
|
-
export type MyQuery$result = {
|
|
982
|
-
readonly allItems: ({
|
|
983
|
-
readonly createdAt: Date
|
|
984
|
-
})[]
|
|
985
|
-
};
|
|
986
|
-
|
|
987
|
-
export type MyQuery$input = {
|
|
988
|
-
date: Date
|
|
989
|
-
};
|
|
990
|
-
`)
|
|
991
|
-
})
|
|
992
|
-
|
|
993
|
-
test('can generate types for list of lists', async function () {
|
|
994
|
-
// the document to test
|
|
995
|
-
const query = mockCollectedDoc(
|
|
996
|
-
`
|
|
997
|
-
query MyQuery {
|
|
998
|
-
listOfLists {
|
|
999
|
-
firstName
|
|
1000
|
-
nickname
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
`
|
|
1004
|
-
)
|
|
1005
|
-
|
|
1006
|
-
// execute the generator
|
|
1007
|
-
await runPipeline(config, [query])
|
|
1008
|
-
|
|
1009
|
-
// look up the files in the artifact directory
|
|
1010
|
-
const fileContents = await fs.readFile(config.artifactTypePath(query.document))
|
|
1011
|
-
|
|
1012
|
-
// make sure they match what we expect
|
|
1013
|
-
expect(
|
|
1014
|
-
recast.parse(fileContents!, {
|
|
1015
|
-
parser: typeScriptParser,
|
|
1016
|
-
})
|
|
1017
|
-
).toMatchInlineSnapshot(`
|
|
1018
|
-
export type MyQuery = {
|
|
1019
|
-
readonly "input": MyQuery$input
|
|
1020
|
-
readonly "result": MyQuery$result | undefined
|
|
1021
|
-
};
|
|
1022
|
-
|
|
1023
|
-
export type MyQuery$result = {
|
|
1024
|
-
readonly listOfLists: (({
|
|
1025
|
-
readonly firstName: string
|
|
1026
|
-
readonly nickname: string | null
|
|
1027
|
-
} | null)[] | null)[]
|
|
1028
|
-
};
|
|
1029
|
-
|
|
1030
|
-
export type MyQuery$input = null;
|
|
1031
|
-
`)
|
|
1032
|
-
})
|
|
1033
|
-
|
|
1034
|
-
test('duplicate fields', async function () {
|
|
1035
|
-
// the document to test
|
|
1036
|
-
const query = mockCollectedDoc(`query MyQuery {
|
|
1037
|
-
user {
|
|
1038
|
-
parent {
|
|
1039
|
-
firstName
|
|
1040
|
-
firstName
|
|
1041
|
-
}
|
|
1042
|
-
parent {
|
|
1043
|
-
nickname
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
}`)
|
|
1047
|
-
|
|
1048
|
-
// execute the generator
|
|
1049
|
-
await runPipeline(config, [query])
|
|
1050
|
-
|
|
1051
|
-
// look up the files in the artifact directory
|
|
1052
|
-
const fileContents = await fs.readFile(config.artifactTypePath(query.document))
|
|
1053
|
-
|
|
1054
|
-
// make sure they match what we expect
|
|
1055
|
-
expect(
|
|
1056
|
-
recast.parse(fileContents!, {
|
|
1057
|
-
parser: typeScriptParser,
|
|
1058
|
-
})
|
|
1059
|
-
).toMatchInlineSnapshot(`
|
|
1060
|
-
export type MyQuery = {
|
|
1061
|
-
readonly "input": MyQuery$input
|
|
1062
|
-
readonly "result": MyQuery$result | undefined
|
|
1063
|
-
};
|
|
1064
|
-
|
|
1065
|
-
export type MyQuery$result = {
|
|
1066
|
-
readonly user: {
|
|
1067
|
-
readonly parent: {
|
|
1068
|
-
readonly firstName: string
|
|
1069
|
-
readonly nickname: string | null
|
|
1070
|
-
} | null
|
|
1071
|
-
} | null
|
|
1072
|
-
};
|
|
1073
|
-
|
|
1074
|
-
export type MyQuery$input = null;
|
|
1075
|
-
`)
|
|
1076
|
-
})
|
|
1077
|
-
|
|
1078
|
-
test('can reference list fragments', async function () {
|
|
1079
|
-
const unmaskedConfig = testConfig({ disableMasking: true, schema: config.schema })
|
|
1080
|
-
|
|
1081
|
-
// the document to test
|
|
1082
|
-
const docs = [
|
|
1083
|
-
mockCollectedDoc(`
|
|
1084
|
-
query MyQuery {
|
|
1085
|
-
users @list(name:"My_Users") {
|
|
1086
|
-
id
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
`),
|
|
1090
|
-
mockCollectedDoc(`
|
|
1091
|
-
mutation MyMutation(
|
|
1092
|
-
$filter: UserFilter,
|
|
1093
|
-
$filterList: [UserFilter!]!,
|
|
1094
|
-
$id: ID!
|
|
1095
|
-
$firstName: String!
|
|
1096
|
-
$admin: Boolean
|
|
1097
|
-
$age: Int
|
|
1098
|
-
$weight: Float
|
|
1099
|
-
) {
|
|
1100
|
-
doThing(
|
|
1101
|
-
filter: $filter,
|
|
1102
|
-
list: $filterList,
|
|
1103
|
-
id:$id
|
|
1104
|
-
firstName:$firstName
|
|
1105
|
-
admin:$admin
|
|
1106
|
-
age:$age
|
|
1107
|
-
weight:$weight
|
|
1108
|
-
) {
|
|
1109
|
-
...My_Users_remove
|
|
1110
|
-
...My_Users_insert
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
`),
|
|
1114
|
-
]
|
|
1115
|
-
|
|
1116
|
-
// execute the generator
|
|
1117
|
-
await runPipeline(unmaskedConfig, docs)
|
|
1118
|
-
|
|
1119
|
-
// look up the files in the artifact directory
|
|
1120
|
-
const fileContents = await fs.readFile(config.artifactTypePath(docs[1].document))
|
|
1121
|
-
|
|
1122
|
-
// make sure they match what we expect
|
|
1123
|
-
expect(
|
|
1124
|
-
recast.parse(fileContents!, {
|
|
1125
|
-
parser: typeScriptParser,
|
|
1126
|
-
})
|
|
1127
|
-
).toMatchInlineSnapshot(`
|
|
1128
|
-
import type { MyEnum } from "$houdini/graphql/enums";
|
|
1129
|
-
|
|
1130
|
-
export type MyMutation = {
|
|
1131
|
-
readonly "input": MyMutation$input
|
|
1132
|
-
readonly "result": MyMutation$result
|
|
1133
|
-
};
|
|
1134
|
-
|
|
1135
|
-
export type MyMutation$result = {
|
|
1136
|
-
readonly doThing: {
|
|
1137
|
-
readonly id: string
|
|
1138
|
-
readonly $fragments: {
|
|
1139
|
-
My_Users_remove: true
|
|
1140
|
-
My_Users_insert: true
|
|
1141
|
-
}
|
|
1142
|
-
} | null
|
|
1143
|
-
};
|
|
1144
|
-
|
|
1145
|
-
type NestedUserFilter = {
|
|
1146
|
-
id: string
|
|
1147
|
-
firstName: string
|
|
1148
|
-
admin?: boolean | null | undefined
|
|
1149
|
-
age?: number | null | undefined
|
|
1150
|
-
weight?: number | null | undefined
|
|
1151
|
-
};
|
|
1152
|
-
|
|
1153
|
-
type UserFilter = {
|
|
1154
|
-
middle?: NestedUserFilter | null | undefined
|
|
1155
|
-
listRequired: (string)[]
|
|
1156
|
-
nullList?: (string | null | undefined)[] | null | undefined
|
|
1157
|
-
recursive?: UserFilter | null | undefined
|
|
1158
|
-
enum?: MyEnum | null | undefined
|
|
1159
|
-
};
|
|
1160
|
-
|
|
1161
|
-
export type MyMutation$input = {
|
|
1162
|
-
filter?: UserFilter | null | undefined
|
|
1163
|
-
filterList: (UserFilter)[]
|
|
1164
|
-
id: string
|
|
1165
|
-
firstName: string
|
|
1166
|
-
admin?: boolean | null | undefined
|
|
1167
|
-
age?: number | null | undefined
|
|
1168
|
-
weight?: number | null | undefined
|
|
1169
|
-
};
|
|
1170
|
-
|
|
1171
|
-
export type MyMutation$optimistic = {
|
|
1172
|
-
readonly doThing?: {
|
|
1173
|
-
readonly id?: string
|
|
1174
|
-
} | null
|
|
1175
|
-
};
|
|
1176
|
-
`)
|
|
1177
|
-
})
|
|
1178
|
-
|
|
1179
|
-
test('disable default fragment masking', async function () {
|
|
1180
|
-
const configWithoutMasking = testConfig({
|
|
1181
|
-
disableMasking: true,
|
|
1182
|
-
schema: config.schema,
|
|
1183
|
-
})
|
|
1184
|
-
|
|
1185
|
-
const docs = [
|
|
1186
|
-
mockCollectedDoc(`
|
|
1187
|
-
query MyQuery {
|
|
1188
|
-
user {
|
|
1189
|
-
...UserBase
|
|
1190
|
-
...UserMore
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
`),
|
|
1194
|
-
mockCollectedDoc(`
|
|
1195
|
-
fragment UserBase on User {
|
|
1196
|
-
id
|
|
1197
|
-
firstName
|
|
1198
|
-
}
|
|
1199
|
-
`),
|
|
1200
|
-
mockCollectedDoc(`
|
|
1201
|
-
fragment UserMore on User {
|
|
1202
|
-
friends {
|
|
1203
|
-
...UserBase
|
|
1204
|
-
}
|
|
1205
|
-
}
|
|
1206
|
-
`),
|
|
1207
|
-
]
|
|
1208
|
-
|
|
1209
|
-
// execute the generator
|
|
1210
|
-
await runPipeline(configWithoutMasking, docs)
|
|
1211
|
-
|
|
1212
|
-
// look up the files in the artifact directory
|
|
1213
|
-
const fileContents = await fs.readFile(
|
|
1214
|
-
configWithoutMasking.artifactTypePath(docs[0].document)
|
|
1215
|
-
)
|
|
1216
|
-
|
|
1217
|
-
// make sure they match what we expect
|
|
1218
|
-
expect(
|
|
1219
|
-
recast.parse(fileContents!, {
|
|
1220
|
-
parser: typeScriptParser,
|
|
1221
|
-
})
|
|
1222
|
-
).toMatchInlineSnapshot(`
|
|
1223
|
-
export type MyQuery = {
|
|
1224
|
-
readonly "input": MyQuery$input
|
|
1225
|
-
readonly "result": MyQuery$result | undefined
|
|
1226
|
-
};
|
|
1227
|
-
|
|
1228
|
-
export type MyQuery$result = {
|
|
1229
|
-
readonly user: {
|
|
1230
|
-
readonly id: string
|
|
1231
|
-
readonly firstName: string
|
|
1232
|
-
readonly friends: ({
|
|
1233
|
-
readonly id: string
|
|
1234
|
-
readonly firstName: string
|
|
1235
|
-
readonly $fragments: {
|
|
1236
|
-
UserBase: true
|
|
1237
|
-
}
|
|
1238
|
-
} | null)[] | null
|
|
1239
|
-
readonly $fragments: {
|
|
1240
|
-
UserBase: true
|
|
1241
|
-
UserMore: true
|
|
1242
|
-
}
|
|
1243
|
-
} | null
|
|
1244
|
-
};
|
|
1245
|
-
|
|
1246
|
-
export type MyQuery$input = null;
|
|
1247
|
-
`)
|
|
1248
|
-
})
|
|
1249
|
-
|
|
1250
|
-
test('disable individual fragment masking', async function () {
|
|
1251
|
-
const configWithMasking = testConfig({
|
|
1252
|
-
disableMasking: false,
|
|
1253
|
-
schema: config.schema,
|
|
1254
|
-
})
|
|
1255
|
-
|
|
1256
|
-
const docs = [
|
|
1257
|
-
mockCollectedDoc(`
|
|
1258
|
-
query MyQuery {
|
|
1259
|
-
user {
|
|
1260
|
-
...UserBase @houdini(mask: false)
|
|
1261
|
-
...UserMore
|
|
1262
|
-
}
|
|
1263
|
-
}
|
|
1264
|
-
`),
|
|
1265
|
-
mockCollectedDoc(`
|
|
1266
|
-
fragment UserBase on User {
|
|
1267
|
-
id
|
|
1268
|
-
firstName
|
|
1269
|
-
}
|
|
1270
|
-
`),
|
|
1271
|
-
mockCollectedDoc(`
|
|
1272
|
-
fragment UserMore on User {
|
|
1273
|
-
friends {
|
|
1274
|
-
...UserBase
|
|
1275
|
-
}
|
|
1276
|
-
}
|
|
1277
|
-
`),
|
|
1278
|
-
]
|
|
1279
|
-
|
|
1280
|
-
// execute the generator
|
|
1281
|
-
await runPipeline(configWithMasking, docs)
|
|
1282
|
-
|
|
1283
|
-
// look up the files in the artifact directory
|
|
1284
|
-
const [queryFileContents, fragmentFileContents] = await Promise.all([
|
|
1285
|
-
fs.readFile(configWithMasking.artifactTypePath(docs[0].document)),
|
|
1286
|
-
fs.readFile(configWithMasking.artifactTypePath(docs[2].document)),
|
|
1287
|
-
])
|
|
1288
|
-
|
|
1289
|
-
// make sure they match what we expect
|
|
1290
|
-
expect(
|
|
1291
|
-
recast.parse(queryFileContents!, {
|
|
1292
|
-
parser: typeScriptParser,
|
|
1293
|
-
})
|
|
1294
|
-
).toMatchInlineSnapshot(`
|
|
1295
|
-
export type MyQuery = {
|
|
1296
|
-
readonly "input": MyQuery$input
|
|
1297
|
-
readonly "result": MyQuery$result | undefined
|
|
1298
|
-
};
|
|
1299
|
-
|
|
1300
|
-
export type MyQuery$result = {
|
|
1301
|
-
readonly user: {
|
|
1302
|
-
readonly id: string
|
|
1303
|
-
readonly firstName: string
|
|
1304
|
-
readonly $fragments: {
|
|
1305
|
-
UserBase: true
|
|
1306
|
-
UserMore: true
|
|
1307
|
-
}
|
|
1308
|
-
} | null
|
|
1309
|
-
};
|
|
1310
|
-
|
|
1311
|
-
export type MyQuery$input = null;
|
|
1312
|
-
`)
|
|
1313
|
-
|
|
1314
|
-
expect(
|
|
1315
|
-
recast.parse(fragmentFileContents!, {
|
|
1316
|
-
parser: typeScriptParser,
|
|
1317
|
-
})
|
|
1318
|
-
).toMatchInlineSnapshot(`
|
|
1319
|
-
export type UserMore = {
|
|
1320
|
-
readonly "shape"?: UserMore$data
|
|
1321
|
-
readonly "$fragments": {
|
|
1322
|
-
"UserMore": true
|
|
1323
|
-
}
|
|
1324
|
-
};
|
|
1325
|
-
|
|
1326
|
-
export type UserMore$data = {
|
|
1327
|
-
readonly friends: ({
|
|
1328
|
-
readonly $fragments: {
|
|
1329
|
-
UserBase: true
|
|
1330
|
-
}
|
|
1331
|
-
} | null)[] | null
|
|
1332
|
-
};
|
|
1333
|
-
`)
|
|
1334
|
-
})
|
|
1335
|
-
|
|
1336
|
-
test('enable individual fragment masking', async function () {
|
|
1337
|
-
const configWithoutMasking = testConfig({
|
|
1338
|
-
disableMasking: true,
|
|
1339
|
-
schema: config.schema,
|
|
1340
|
-
})
|
|
1341
|
-
|
|
1342
|
-
const docs = [
|
|
1343
|
-
mockCollectedDoc(`
|
|
1344
|
-
query MyQuery {
|
|
1345
|
-
user {
|
|
1346
|
-
...UserBase @houdini(mask: true)
|
|
1347
|
-
...UserMore
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
`),
|
|
1351
|
-
mockCollectedDoc(`
|
|
1352
|
-
fragment UserBase on User {
|
|
1353
|
-
id
|
|
1354
|
-
firstName
|
|
1355
|
-
}
|
|
1356
|
-
`),
|
|
1357
|
-
mockCollectedDoc(`
|
|
1358
|
-
fragment UserMore on User {
|
|
1359
|
-
friends {
|
|
1360
|
-
...UserBase
|
|
1361
|
-
}
|
|
1362
|
-
}
|
|
1363
|
-
`),
|
|
1364
|
-
]
|
|
1365
|
-
|
|
1366
|
-
// execute the generator
|
|
1367
|
-
await runPipeline(configWithoutMasking, docs)
|
|
1368
|
-
|
|
1369
|
-
// look up the files in the artifact directory
|
|
1370
|
-
const [queryFileContents, fragmentFileContents] = await Promise.all([
|
|
1371
|
-
fs.readFile(configWithoutMasking.artifactTypePath(docs[0].document)),
|
|
1372
|
-
fs.readFile(configWithoutMasking.artifactTypePath(docs[2].document)),
|
|
1373
|
-
])
|
|
1374
|
-
|
|
1375
|
-
// make sure they match what we expect
|
|
1376
|
-
expect(
|
|
1377
|
-
recast.parse(queryFileContents!, {
|
|
1378
|
-
parser: typeScriptParser,
|
|
1379
|
-
})
|
|
1380
|
-
).toMatchInlineSnapshot(`
|
|
1381
|
-
export type MyQuery = {
|
|
1382
|
-
readonly "input": MyQuery$input
|
|
1383
|
-
readonly "result": MyQuery$result | undefined
|
|
1384
|
-
};
|
|
1385
|
-
|
|
1386
|
-
export type MyQuery$result = {
|
|
1387
|
-
readonly user: {
|
|
1388
|
-
readonly friends: ({
|
|
1389
|
-
readonly id: string
|
|
1390
|
-
readonly firstName: string
|
|
1391
|
-
readonly $fragments: {
|
|
1392
|
-
UserBase: true
|
|
1393
|
-
}
|
|
1394
|
-
} | null)[] | null
|
|
1395
|
-
readonly $fragments: {
|
|
1396
|
-
UserBase: true
|
|
1397
|
-
UserMore: true
|
|
1398
|
-
}
|
|
1399
|
-
} | null
|
|
1400
|
-
};
|
|
1401
|
-
|
|
1402
|
-
export type MyQuery$input = null;
|
|
1403
|
-
`)
|
|
1404
|
-
|
|
1405
|
-
expect(
|
|
1406
|
-
recast.parse(fragmentFileContents!, {
|
|
1407
|
-
parser: typeScriptParser,
|
|
1408
|
-
})
|
|
1409
|
-
).toMatchInlineSnapshot(`
|
|
1410
|
-
export type UserMore = {
|
|
1411
|
-
readonly "shape"?: UserMore$data
|
|
1412
|
-
readonly "$fragments": {
|
|
1413
|
-
"UserMore": true
|
|
1414
|
-
}
|
|
1415
|
-
};
|
|
1416
|
-
|
|
1417
|
-
export type UserMore$data = {
|
|
1418
|
-
readonly friends: ({
|
|
1419
|
-
readonly id: string
|
|
1420
|
-
readonly firstName: string
|
|
1421
|
-
readonly $fragments: {
|
|
1422
|
-
UserBase: true
|
|
1423
|
-
}
|
|
1424
|
-
} | null)[] | null
|
|
1425
|
-
};
|
|
1426
|
-
`)
|
|
1427
|
-
})
|
|
1428
|
-
|
|
1429
|
-
test.todo('fragments on interfaces')
|
|
1430
|
-
|
|
1431
|
-
test.todo('intersections with __typename in subselection')
|
|
1432
|
-
|
|
1433
|
-
test.todo('inline fragments')
|
|
1434
|
-
})
|