Skip to content

Commit 16aa4f6

Browse files
committed
feat(graphql-test): generator generates valid gql documents 🎉
1 parent 6e52d8e commit 16aa4f6

File tree

5 files changed

+63
-80
lines changed

5 files changed

+63
-80
lines changed

packages/graphql-test/src/functor.ts

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { fn } from '@traversable/registry'
44
import type { Seed } from './generator-seed.js'
55
import { byTag } from './generator-seed.js'
66

7+
const isNull = (x: unknown) => x === null
8+
79
export interface Index {}
810

911
export const defaultIndex = Object.create(null) satisfies Index
@@ -43,7 +45,7 @@ export const Functor: T.Functor.Ix<Index, Seed.Free, Seed.Fixpoint> = {
4345
case x[0] === byTag.DirectiveDefinition: return [x[0], x[1], x[2], x[3], x[4], fn.map(x[5], g)]
4446
case x[0] === byTag.Document: return [x[0], fn.map(x[1], g)]
4547
case x[0] === byTag.EnumTypeDefinition: return [x[0], x[1], x[2], x[3], fn.map(x[4], g)]
46-
case x[0] === byTag.Field: return [x[0], x[1], x[2], g(x[3]), fn.map(x[4], g), fn.map(x[5], g)]
48+
case x[0] === byTag.Field: return [x[0], x[1], x[2], isNull(x[3]) ? x[3] : g(x[3]), fn.map(x[4], g), fn.map(x[5], g)]
4749
case x[0] === byTag.FieldDefinition: return [x[0], x[1], x[2], g(x[3]), fn.map(x[4], g), fn.map(x[5], g)]
4850
case x[0] === byTag.FragmentDefinition: return [x[0], x[1], x[2], g(x[3]), fn.map(x[4], g)]
4951
case x[0] === byTag.FragmentSpread: return [x[0], x[1], fn.map(x[2], g)]
@@ -62,12 +64,6 @@ export const Functor: T.Functor.Ix<Index, Seed.Free, Seed.Fixpoint> = {
6264
},
6365
mapWithIndex(g) {
6466
return (x, ix) => {
65-
66-
console.debug('\n')
67-
console.group('mapWithIndex')
68-
console.debug('x:', x)
69-
console.groupEnd()
70-
7167
switch (true) {
7268
default: return x satisfies never
7369
case x[0] === byTag.Name: return x
@@ -100,7 +96,7 @@ export const Functor: T.Functor.Ix<Index, Seed.Free, Seed.Fixpoint> = {
10096
case x[0] === byTag.DirectiveDefinition: return [x[0], x[1], x[2], x[3], x[4], fn.map(x[5], (_) => g(_, ix, x))]
10197
case x[0] === byTag.Document: return [x[0], fn.map(x[1], (_) => g(_, ix, x))]
10298
case x[0] === byTag.EnumTypeDefinition: return [x[0], x[1], x[2], x[3], fn.map(x[4], (_) => g(_, ix, x))]
103-
case x[0] === byTag.Field: return [x[0], x[1], x[2], g(x[3], ix, x), fn.map(x[4], (_) => g(_, ix, x)), fn.map(x[5], (_) => g(_, ix, x))]
99+
case x[0] === byTag.Field: return [x[0], x[1], x[2], isNull(x[3]) ? x[3] : g(x[3], ix, x), fn.map(x[4], (_) => g(_, ix, x)), fn.map(x[5], (_) => g(_, ix, x))]
104100
case x[0] === byTag.FieldDefinition: return [x[0], x[1], x[2], g(x[3], ix, x), fn.map(x[4], (_) => g(_, ix, x)), fn.map(x[5], (_) => g(_, ix, x))]
105101
case x[0] === byTag.FragmentDefinition: return [x[0], x[1], x[2], g(x[3], ix, x), fn.map(x[4], (_) => g(_, ix, x))]
106102
case x[0] === byTag.FragmentSpread: return [x[0], x[1], fn.map(x[2], (_) => g(_, ix, x))]
@@ -109,16 +105,7 @@ export const Functor: T.Functor.Ix<Index, Seed.Free, Seed.Fixpoint> = {
109105
case x[0] === byTag.InputObjectTypeDefinition: return [x[0], x[1], x[2], fn.map(x[3], (_) => g(_, ix, x)), fn.map(x[4], (_) => g(_, ix, x))]
110106
case x[0] === byTag.InterfaceTypeDefinition: return [x[0], x[1], x[2], fn.map(x[3], (_) => g(_, ix, x)), fn.map(x[4], (_) => g(_, ix, x)), fn.map(x[5], (_) => g(_, ix, x))]
111107
case x[0] === byTag.ObjectTypeDefinition: return [x[0], x[1], x[2], fn.map(x[3], (_) => g(_, ix, x)), fn.map(x[4], (_) => g(_, ix, x)), fn.map(x[5], (_) => g(_, ix, x))]
112-
113-
case x[0] === byTag.OperationDefinition: return [
114-
x[0],
115-
x[1],
116-
x[2],
117-
g(x[3], ix, x),
118-
fn.map(x[4], (_) => g(_, ix, x)),
119-
fn.map(x[5], (_) => g(_, ix, x))
120-
]
121-
108+
case x[0] === byTag.OperationDefinition: return [x[0], x[1], x[2], g(x[3], ix, x), fn.map(x[4], (_) => g(_, ix, x)), fn.map(x[5], (_) => g(_, ix, x))]
122109
case x[0] === byTag.SchemaDefinition: return [x[0], x[1], x[2], x[3], fn.map(x[4], (_) => g(_, ix, x))]
123110
case x[0] === byTag.UnionTypeDefinition: return [x[0], x[1], fn.map(x[2], (_) => g(_, ix, x)), fn.map(x[3], (_) => g(_, ix, x))]
124111
case x[0] === byTag.VariableDefinition: return [x[0], x[1], g(x[2], ix, x), g(x[3], ix, x), fn.map(x[4], (_) => g(_, ix, x))]

packages/graphql-test/src/generator-seed.ts

Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,8 @@ export type bySeed = typeof bySeed
119119
export const bySeed = invert(byTag)
120120

121121
export const identifier = fc.stringMatching(new RegExp(PATTERN.identifierNoDollar, 'u')).map((x) => `${x.charAt(0).toUpperCase()}${x.slice(1)}`)
122-
export const name = fc.lorem({ maxCount: 1 })
123-
export const alias = name
122+
// export const name = fc.lorem({ maxCount: 1 })
123+
export const alias = identifier
124124
export const target = fc.constantFrom(...F.DirectiveTargets)
125125

126126
export const description = ($: Constraints) => $.noDescriptions ? fc.constant(null) : fc.oneof(
@@ -253,7 +253,7 @@ export declare namespace Seed {
253253
Field: byTag['Field'],
254254
name: string,
255255
alias: string,
256-
selectionSet: T,
256+
selectionSet: T | null,
257257
arguments: readonly T[],
258258
directives: readonly T[],
259259
]
@@ -570,7 +570,7 @@ export type Seed<T = unknown> = (
570570

571571
const NamedType = (_tie: fc.LetrecTypedTie<Seed>, _$: Constraints): fc.Arbitrary<Seed.NamedType> => fc.tuple(
572572
fc.constant(byTag['NamedType']),
573-
name,
573+
identifier,
574574
)
575575

576576
const Boolean = (_tie: fc.LetrecTypedTie<Seed>, _$: Constraints): fc.Arbitrary<Seed.Boolean> => fc.constant([byTag['Boolean']])
@@ -599,12 +599,12 @@ const ScalarTypeDefinition = (_tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc
599599

600600
const EnumValue = (_tie: fc.LetrecTypedTie<Seed>, _$: Constraints): fc.Arbitrary<Seed.EnumValue> => fc.tuple(
601601
fc.constant(byTag['EnumValue']),
602-
name,
602+
identifier,
603603
)
604604

605605
const EnumValueDefinition = (_tie: fc.LetrecTypedTie<Seed>, _$: Constraints): fc.Arbitrary<Seed.EnumValueDefinition> => fc.tuple(
606606
fc.constant(byTag['EnumValueDefinition']),
607-
name,
607+
identifier,
608608
)
609609

610610
/**
@@ -680,7 +680,7 @@ const NonNullType = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary
680680
*/
681681
const UnionTypeDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.UnionTypeDefinition> => fc.tuple(
682682
fc.constant(byTag['UnionTypeDefinition']),
683-
name,
683+
identifier,
684684
fc.uniqueArray(
685685
NamedType(tie, $),
686686
$.NamedType!
@@ -709,7 +709,7 @@ const UnionTypeDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.A
709709
*/
710710
const Variable = (_tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.Variable> => fc.tuple(
711711
fc.constant(byTag['Variable']),
712-
name,
712+
identifier,
713713
description($),
714714
)
715715

@@ -733,9 +733,9 @@ const Variable = (_tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<S
733733
*/
734734
const EnumTypeDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.EnumTypeDefinition> => fc.tuple(
735735
fc.constant(byTag['EnumTypeDefinition']),
736-
name,
736+
identifier,
737737
description($),
738-
fc.uniqueArray(name),
738+
fc.uniqueArray(identifier),
739739
fc.uniqueArray(
740740
// TODO:
741741
// ConstDirective(tie, $),
@@ -766,9 +766,11 @@ const EnumTypeDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Ar
766766
*/
767767
const Field = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.Field> => fc.tuple(
768768
fc.constant(byTag['Field']),
769-
name,
769+
identifier,
770770
alias,
771-
tie('SelectionSet'),
771+
fc.oneof(
772+
fc.constant(null), NonEmptySelectionSet(tie, $)
773+
),
772774
fc.uniqueArray(
773775
tie('Argument'),
774776
$.Argument!
@@ -801,7 +803,7 @@ const Field = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.
801803
*/
802804
const FieldDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.FieldDefinition> => fc.tuple(
803805
fc.constant(byTag['FieldDefinition']),
804-
name,
806+
identifier,
805807
description($),
806808
TypeNode(tie, $),
807809
fc.uniqueArray(
@@ -911,7 +913,7 @@ const InterfaceTypeDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints):
911913
*/
912914
const Argument = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.Argument> => fc.tuple(
913915
fc.constant(byTag['Argument']),
914-
name,
916+
identifier,
915917
ValueNode(tie, $),
916918
)
917919

@@ -935,7 +937,7 @@ const Argument = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Se
935937
*/
936938
const InputObjectTypeDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.InputObjectTypeDefinition> => fc.tuple(
937939
fc.constant(byTag['InputObjectTypeDefinition']),
938-
name,
940+
identifier,
939941
description($),
940942
fc.uniqueArray(
941943
tie('InputValueDefinition'),
@@ -971,7 +973,7 @@ const InputObjectTypeDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints)
971973
*/
972974
const InputValueDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.InputValueDefinition> => fc.tuple(
973975
fc.constant(byTag['InputValueDefinition']),
974-
name,
976+
identifier,
975977
description($),
976978
TypeNode(tie, $),
977979
ConstValueNode(tie, $),
@@ -1002,7 +1004,7 @@ const InputValueDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.
10021004
*/
10031005
const VariableDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.VariableDefinition> => fc.tuple(
10041006
fc.constant(byTag['VariableDefinition']),
1005-
name,
1007+
identifier,
10061008
TypeNode(tie, $),
10071009
ConstValueNode(tie, $),
10081010
fc.uniqueArray(
@@ -1030,7 +1032,7 @@ const VariableDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Ar
10301032
const Directive = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.Directive> => {
10311033
return fc.tuple(
10321034
fc.constant(byTag['Directive']),
1033-
name,
1035+
identifier,
10341036
fc.uniqueArray(
10351037
tie('Argument'),
10361038
$.Argument!
@@ -1060,7 +1062,7 @@ const Directive = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<S
10601062
*/
10611063
const DirectiveDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.DirectiveDefinition> => fc.tuple(
10621064
fc.constant(byTag['DirectiveDefinition']),
1063-
name,
1065+
identifier,
10641066
description($),
10651067
fc.boolean(),
10661068
fc.uniqueArray(
@@ -1093,8 +1095,8 @@ const DirectiveDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.A
10931095
*/
10941096
const FragmentDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.FragmentDefinition> => fc.tuple(
10951097
fc.constant(byTag['FragmentDefinition']),
1096-
name,
1097-
name,
1098+
identifier,
1099+
identifier,
10981100
tie('SelectionSet'),
10991101
fc.uniqueArray(
11001102
tie('Directive'),
@@ -1119,7 +1121,7 @@ const FragmentDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Ar
11191121
*/
11201122
const FragmentSpread = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.FragmentSpread> => fc.tuple(
11211123
fc.constant(byTag['FragmentSpread']),
1122-
name,
1124+
identifier,
11231125
fc.uniqueArray(
11241126
tie('Directive'),
11251127
$.Directive!
@@ -1144,14 +1146,23 @@ const FragmentSpread = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitr
11441146
*/
11451147
const InlineFragment = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.InlineFragment> => fc.tuple(
11461148
fc.constant(byTag['InlineFragment']),
1147-
name,
1148-
tie('SelectionSet'),
1149+
identifier,
1150+
NonEmptySelectionSet(tie, $),
11491151
fc.uniqueArray(
11501152
tie('Directive'),
11511153
$.Directive!
11521154
),
11531155
)
11541156

1157+
// used in OperationDefinition
1158+
const NonEmptySelectionSet = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.SelectionSet> => fc.tuple(
1159+
fc.constant(byTag['SelectionSet']),
1160+
fc.uniqueArray(
1161+
Selection(tie, $),
1162+
{ ...$.SelectionSet, minLength: 1 },
1163+
),
1164+
)
1165+
11551166
/**
11561167
* @example
11571168
* type OperationDefinition<T = unknown> = [
@@ -1174,9 +1185,9 @@ const InlineFragment = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitr
11741185
*/
11751186
const OperationDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.OperationDefinition> => fc.tuple(
11761187
fc.constant(byTag['OperationDefinition']),
1177-
name,
1188+
identifier,
11781189
operationType,
1179-
tie('SelectionSet'),
1190+
NonEmptySelectionSet(tie, $),
11801191
fc.uniqueArray(
11811192
tie('VariableDefinition'),
11821193
$.VariableDefinition!
@@ -1185,7 +1196,6 @@ const OperationDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.A
11851196
tie('Directive'),
11861197
$.Directive!
11871198
),
1188-
// tie('Directive'),
11891199
)
11901200

11911201
/**
@@ -1204,7 +1214,7 @@ const OperationDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.A
12041214
*/
12051215
const OperationTypeDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.OperationTypeDefinition> => fc.tuple(
12061216
fc.constant(byTag['OperationTypeDefinition']),
1207-
name,
1217+
identifier,
12081218
operationType,
12091219
// tie('OperationT'),
12101220
)
@@ -1247,7 +1257,7 @@ const SelectionSet = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrar
12471257
*/
12481258
const SchemaDefinition = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.SchemaDefinition> => fc.tuple(
12491259
fc.constant(byTag['SchemaDefinition']),
1250-
name,
1260+
identifier,
12511261
description($),
12521262
fc.uniqueArray(
12531263
OperationTypeDefinition(tie, $),
@@ -1304,7 +1314,7 @@ const Document = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Se
13041314
*/
13051315
const ConstArgument = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.Argument> => fc.tuple(
13061316
fc.constant(byTag['Argument']),
1307-
name,
1317+
identifier,
13081318
ConstValueNode(tie, $),
13091319
)
13101320

@@ -1324,7 +1334,7 @@ const ConstArgument = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitra
13241334
*/
13251335
const ConstDirective = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.Directive> => fc.tuple(
13261336
fc.constant(byTag['Directive']),
1327-
name,
1337+
identifier,
13281338
fc.uniqueArray(
13291339
ConstArgument(tie, $),
13301340
$.Argument!
@@ -1385,7 +1395,7 @@ const ValueNode = (_tie: fc.LetrecTypedTie<Seed>, $: Constraints) => fc.oneof(
13851395
BooleanValue(_tie, $),
13861396
NullValue(_tie, $),
13871397
EnumValue(_tie, $),
1388-
Variable(_tie, $),
1398+
// Variable(_tie, $),
13891399
// ObjectValue(),
13901400
// ListValue(),
13911401
)
@@ -1406,7 +1416,7 @@ const ValueNode = (_tie: fc.LetrecTypedTie<Seed>, $: Constraints) => fc.oneof(
14061416
*/
14071417
const ObjectField = (tie: fc.LetrecTypedTie<Seed>, $: Constraints): fc.Arbitrary<Seed.ObjectField> => fc.tuple(
14081418
fc.constant(byTag['ObjectField']),
1409-
name,
1419+
identifier,
14101420
ValueNode(tie, $),
14111421
)
14121422

packages/graphql-test/src/generator.ts

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -257,18 +257,11 @@ const SchemaMap = {
257257
kind: Kind.Document,
258258
definitions
259259
}),
260-
Directive: ([__kind, name, args]) => {
261-
262-
console.log('SchemaMap Directive, kind:', __kind)
263-
console.log('SchemaMap Directive, name:', name)
264-
console.log('SchemaMap Directive, args:', JSON.stringify(args, null, 2))
265-
266-
return {
267-
kind: Kind.Directive,
268-
name: nameNode(name),
269-
arguments: args,
270-
}
271-
},
260+
Directive: ([__kind, name, args]) => ({
261+
kind: Kind.Directive,
262+
name: nameNode(name),
263+
arguments: args,
264+
}),
272265
DirectiveDefinition: ([, name, description, repeatable, locations, args]) => ({
273266
kind: Kind.DirectiveDefinition,
274267
name: nameNode(name),
@@ -287,7 +280,7 @@ const SchemaMap = {
287280
kind: Kind.Field,
288281
name: nameNode(name),
289282
alias: nameNode(alias),
290-
...selectionSet != null && { selectionSet },
283+
...selectionSet !== null && { selectionSet },
291284
...args.length && { arguments: args },
292285
...directives.length && { directives },
293286
}),
@@ -414,14 +407,5 @@ const SchemaMap = {
414407

415408
export const SeedGenerator = Gen(Seed)
416409

417-
export const seedToSchema = fold<AST.Fixpoint>((x) => {
418-
console.log('seedToSchema, x:', x)
419-
try {
420-
return SchemaMap[bySeed[x[0]]](x as never)
421-
} catch (e) {
422-
console.error('SchemaMap[bySeed[x[0]]] is not a function')
423-
console.error('x:', x)
424-
throw e
425-
}
426-
})
410+
export const seedToSchema = fold<AST.Fixpoint>((x) => SchemaMap[bySeed[x[0]]](x as never))
427411

packages/graphql-test/test/generator.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ vi.describe('〖⛳️〗‹‹‹ ❲@traversable/graphql-test❳', () => {
2525
const [seed] = fc.sample(Builder['Document'], 1)
2626
try {
2727
const schema = seedToSchema(seed)
28-
console.log(F.toString(schema))
28+
console.log('seed:\n', JSON.stringify(seed, null, 2))
29+
console.log('schema:\n', schema)
30+
31+
console.log('SDL:\n', format(F.toString(schema)))
2932
} catch (e) {
3033
console.error('\n\nFAILED: seedToSchema', JSON.stringify(seed, null, 2), '\n\n')
3134
throw e

0 commit comments

Comments
 (0)