graphql-data-generator 0.1.0

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/esm/proxy.js ADDED
@@ -0,0 +1,589 @@
1
+ import { Kind, Location, parse } from "graphql";
2
+ import { absurd } from "./util.js";
3
+ let getDefaultPatch = (__typename) => undefined;
4
+ export const withGetDefaultPatch = (newGetDefaultPatch, fn) => {
5
+ const prev = getDefaultPatch;
6
+ getDefaultPatch = newGetDefaultPatch;
7
+ try {
8
+ return fn();
9
+ }
10
+ finally {
11
+ getDefaultPatch = prev;
12
+ }
13
+ };
14
+ const builtInScalars = ["Int", "Float", "String", "Boolean", "ID"];
15
+ const resolveType = (definitions, path) => {
16
+ let definition;
17
+ let type;
18
+ let parent;
19
+ let kind = "field";
20
+ const parts = path.split(/(\.\$|\.)/);
21
+ for (let i = 0; i < parts.length; i++) {
22
+ if (parts[i] === "." || parts[i] === ".$") {
23
+ kind = parts[i] === "." ? "field" : "argument";
24
+ i++;
25
+ if (i === parts.length)
26
+ break;
27
+ }
28
+ const name = parts[i];
29
+ if (!definition) {
30
+ definition = definitions.find((d) => "name" in d && d.name?.value === name);
31
+ if (!definition && builtInScalars.includes(name)) {
32
+ definition = {
33
+ kind: Kind.SCALAR_TYPE_DEFINITION,
34
+ name: { kind: Kind.NAME, value: name },
35
+ };
36
+ }
37
+ type = {
38
+ kind: Kind.NON_NULL_TYPE,
39
+ type: { kind: Kind.NAMED_TYPE, name: { kind: Kind.NAME, value: name } },
40
+ };
41
+ }
42
+ else {
43
+ parent = definition.name.value;
44
+ type = undefined;
45
+ if (kind === "field") {
46
+ const field = "fields" in definition
47
+ ? definition.fields?.find((f) => f.name.value === name)
48
+ : undefined;
49
+ if (!field) {
50
+ throw new Error(`Could not find field ${name} on ${"name" in definition ? definition.name?.value : "<unknown>"}`);
51
+ }
52
+ type = field.type;
53
+ }
54
+ else {
55
+ const argument = "arguments" in definition
56
+ ? definition.arguments?.find((a) => a.name.value === name)
57
+ : "variableDefinitions" in definition
58
+ ? definition.variableDefinitions?.find((v) => v.variable.name.value === name)
59
+ : undefined;
60
+ if (!argument) {
61
+ throw new Error(`Could not find argument ${name} on ${"name" in definition ? definition.name?.value : "<unknown>"}`);
62
+ }
63
+ type = argument.type;
64
+ }
65
+ while (parts[i + 2]?.match(/^\d$/)) {
66
+ if (type.kind === Kind.NON_NULL_TYPE)
67
+ type = type.type;
68
+ if (type.kind !== Kind.LIST_TYPE)
69
+ throw new Error("Expected list type");
70
+ type = type.type;
71
+ i += 2;
72
+ }
73
+ let t = type;
74
+ while (t.kind !== Kind.NAMED_TYPE)
75
+ t = t.type;
76
+ const namedType = t;
77
+ definition = definitions.find((d) => "name" in d ? d.name?.value === namedType.name.value : false);
78
+ if (!definition && builtInScalars.includes(namedType.name.value)) {
79
+ definition = {
80
+ kind: Kind.SCALAR_TYPE_DEFINITION,
81
+ name: { kind: Kind.NAME, value: namedType.name.value },
82
+ };
83
+ }
84
+ if (!definition) {
85
+ throw new Error(`Could not find type ${name}${parent ? ` on ${parent}` : ""}`);
86
+ }
87
+ }
88
+ if (!definition) {
89
+ throw new Error(`Could not find type ${name}${parent ? ` on ${parent}` : ""}`);
90
+ }
91
+ }
92
+ return { parent, definition, type: type };
93
+ };
94
+ const resolveConcreteType = (definitions, definition, patch, prev) => {
95
+ const objectDefintions = definitions.filter((d) => d.kind === Kind.OBJECT_TYPE_DEFINITION);
96
+ const interfaceDefintions = definitions.filter((d) => d.kind === Kind.INTERFACE_TYPE_DEFINITION);
97
+ let options = [];
98
+ const interfaces = [definition];
99
+ while (interfaces.length) {
100
+ const interfaceDefinition = interfaces.pop();
101
+ for (const objectDefintion of objectDefintions) {
102
+ if (objectDefintion.interfaces?.some((i) => i.name.value === interfaceDefinition.name.value) ||
103
+ ("types" in interfaceDefinition &&
104
+ interfaceDefinition.types?.some((t) => t.name.value === objectDefintion.name.value)))
105
+ options.push(objectDefintion);
106
+ }
107
+ // TODO: is this a thing...?
108
+ for (const secondOrderInterfaceDefinition of interfaceDefintions) {
109
+ if (secondOrderInterfaceDefinition.interfaces?.some((i) => i.name.value === interfaceDefinition.name.value))
110
+ interfaces.push(secondOrderInterfaceDefinition);
111
+ }
112
+ }
113
+ if (options.length === 1)
114
+ return options[0];
115
+ for (const field in patch) {
116
+ options = options.filter((o) => o.fields?.some((f) => f.name.value === field));
117
+ if (options.length === 1)
118
+ return options[0];
119
+ }
120
+ if (prev && typeof prev === "object" && "__typename" in prev) {
121
+ const match = options.find((o) => o.name.value === prev.__typename);
122
+ if (match)
123
+ return match;
124
+ }
125
+ if (options.length === 0) {
126
+ throw new Error(`Could not find concrete type for ${definition.name.value}`);
127
+ }
128
+ return options[0];
129
+ };
130
+ const resolveValue = (definitions, scalars, type, ctx) => {
131
+ if (type.kind !== Kind.NON_NULL_TYPE)
132
+ return null;
133
+ if (type.type.kind === Kind.LIST_TYPE)
134
+ return [];
135
+ type = type.type;
136
+ const fieldTypeDefinitions = definitions.filter((d) => "name" in d &&
137
+ d.name?.value === type.name.value);
138
+ if (fieldTypeDefinitions.length &&
139
+ fieldTypeDefinitions.every((d) => d.kind === Kind.ENUM_TYPE_DEFINITION)) {
140
+ return fieldTypeDefinitions.find((d) => d.kind === Kind.ENUM_TYPE_DEFINITION && (d.values?.length ?? 0) > 0)?.values?.[0].name.value;
141
+ }
142
+ if (fieldTypeDefinitions.every((d) => d.kind === Kind.SCALAR_TYPE_DEFINITION)) {
143
+ if (!(type.name.value in scalars)) {
144
+ throw new Error(`Missing scalar ${type.name.value}`);
145
+ }
146
+ const scalar = scalars[type.name.value];
147
+ const value = typeof scalar === "function" ? scalar(ctx.hostType) : scalar;
148
+ return value;
149
+ }
150
+ if (fieldTypeDefinitions.length === 1 &&
151
+ (fieldTypeDefinitions[0].kind === Kind.OBJECT_TYPE_DEFINITION ||
152
+ fieldTypeDefinitions[0].kind === Kind.INTERFACE_TYPE_DEFINITION ||
153
+ fieldTypeDefinitions[0].kind === Kind.INPUT_OBJECT_TYPE_DEFINITION)) {
154
+ // const childPatches = ctx.patches.map((p) => p[ctx.prop as keyof typeof p])
155
+ // .filter((v) => !!v && typeof v === "object") as Patch<T[keyof T]>[];
156
+ const base = _proxy(definitions, scalars, fieldTypeDefinitions[0].name.value, [], { selectionSet: ctx.selectionSet });
157
+ const rawDefaultPatch = getDefaultPatch(type.name.value);
158
+ const defaultPatch = typeof rawDefaultPatch === "function"
159
+ ? rawDefaultPatch(base)
160
+ : rawDefaultPatch;
161
+ if (defaultPatch) {
162
+ return _proxy(definitions, scalars, fieldTypeDefinitions[0].name.value, [base, defaultPatch]);
163
+ }
164
+ return base;
165
+ }
166
+ throw new Error(`Unhandled default kind ${fieldTypeDefinitions.map((d) => d.kind)}`);
167
+ };
168
+ const gqlprint = (value) => {
169
+ if (typeof value !== "object" || !value)
170
+ return value;
171
+ // deno-lint-ignore no-explicit-any
172
+ if (Array.isArray(value))
173
+ return value.map(gqlprint);
174
+ const obj = {};
175
+ for (const field in value) {
176
+ if (field === "loc" && value[field] instanceof Location) {
177
+ continue;
178
+ }
179
+ // deno-lint-ignore no-explicit-any
180
+ obj[field] = gqlprint(value[field]);
181
+ }
182
+ return obj;
183
+ };
184
+ const getSelectionField = (definitions, selectionSet, selection, typename) => {
185
+ for (const s of selectionSet.selections) {
186
+ switch (s.kind) {
187
+ case Kind.FIELD:
188
+ if ((s.alias?.value ?? s.name.value) === selection)
189
+ return s;
190
+ break;
191
+ case Kind.FRAGMENT_SPREAD: {
192
+ const definition = definitions.find((d) => "name" in d && d.name?.value === s.name.value &&
193
+ d.kind === Kind.FRAGMENT_DEFINITION);
194
+ if (!definition) {
195
+ throw new Error(`Could not find fragment ${s.name.value}`);
196
+ }
197
+ return getSelectionField(definitions, definition.selectionSet, selection, typename);
198
+ }
199
+ case Kind.INLINE_FRAGMENT: {
200
+ if (!s.typeCondition || !typename ||
201
+ s.typeCondition.name.value === typename) {
202
+ return getSelectionField(definitions, s.selectionSet, selection, typename);
203
+ }
204
+ }
205
+ }
206
+ }
207
+ };
208
+ const getSelectionSetSelection = (definitions, selectionSet, selection, typename) => {
209
+ for (const s of selectionSet.selections) {
210
+ switch (s.kind) {
211
+ case Kind.FIELD:
212
+ if ((s.alias?.value ?? s.name.value) === selection) {
213
+ return s.selectionSet;
214
+ }
215
+ break;
216
+ case Kind.FRAGMENT_SPREAD: {
217
+ const definition = definitions.find((d) => "name" in d && d.name?.value === s.name.value &&
218
+ d.kind === Kind.FRAGMENT_DEFINITION);
219
+ if (!definition) {
220
+ throw new Error(`Could not find fragment ${s.name.value}`);
221
+ }
222
+ return getSelectionSetSelection(definitions, definition.selectionSet, selection, typename);
223
+ }
224
+ case Kind.INLINE_FRAGMENT: {
225
+ if (!s.typeCondition || !typename ||
226
+ s.typeCondition.name.value === typename) {
227
+ return getSelectionSetSelection(definitions, s.selectionSet, selection, typename);
228
+ }
229
+ }
230
+ }
231
+ }
232
+ };
233
+ const selectionSetToKeys = (definitions, selectionSet, typename) => {
234
+ const keys = [];
235
+ for (const s of selectionSet.selections) {
236
+ switch (s.kind) {
237
+ case Kind.FIELD:
238
+ keys.push(s.alias?.value ?? s.name.value);
239
+ break;
240
+ case Kind.FRAGMENT_SPREAD: {
241
+ const definition = definitions.find((d) => "name" in d && d.name?.value === s.name.value &&
242
+ d.kind === Kind.FRAGMENT_DEFINITION);
243
+ if (!definition) {
244
+ throw new Error(`Could not find fragment ${s.name.value}`);
245
+ }
246
+ keys.push(...selectionSetToKeys(definitions, definition.selectionSet, typename));
247
+ break;
248
+ }
249
+ case Kind.INLINE_FRAGMENT: {
250
+ if (!s.typeCondition || !typename ||
251
+ s.typeCondition.name.value === typename) {
252
+ keys.push(...selectionSetToKeys(definitions, s.selectionSet, typename));
253
+ }
254
+ }
255
+ }
256
+ }
257
+ return keys;
258
+ };
259
+ const _proxy = (definitions, scalars, path, patches, { prev, resolvedType = resolveType(definitions, path), selectionSet, } = {}) => {
260
+ const { parent = path, definition } = resolvedType;
261
+ let type = resolvedType.type;
262
+ if (!prev && patches.length) {
263
+ prev = _proxy(definitions, scalars, path, patches.slice(0, -1), {
264
+ selectionSet,
265
+ });
266
+ }
267
+ const rawPatch = patches.length > 0 ? patches[patches.length - 1] : undefined;
268
+ const patch = typeof rawPatch === "function"
269
+ ? prev ? rawPatch(prev) : undefined
270
+ : rawPatch;
271
+ if (type.kind !== Kind.NON_NULL_TYPE) {
272
+ if (!patches.length)
273
+ return (prev ?? null);
274
+ }
275
+ else
276
+ type = type.type;
277
+ if (type.kind === Kind.LIST_TYPE) {
278
+ if (!patches.length)
279
+ return (prev ?? []);
280
+ const value = (patches.at(-1) ?? []);
281
+ const previousArray = (prev ?? []);
282
+ const lastIndex = Math.max(previousArray.length - 1, 0);
283
+ const nextIndex = previousArray.length;
284
+ const length = typeof value.length === "number" ? value.length : Math.max(previousArray.length, ...Object.keys(value).map((v) => {
285
+ const i = parseInt(v);
286
+ if (!Number.isNaN(i))
287
+ return i + 1;
288
+ if (v === "last")
289
+ return lastIndex + 1;
290
+ if (v === "next")
291
+ return nextIndex + 1;
292
+ if (v === "length")
293
+ return 0;
294
+ throw new Error(`Unhandled array index ${v}`);
295
+ }));
296
+ const arr = [];
297
+ for (let i = 0; i < length; i++) {
298
+ arr[i] = _proxy(definitions, scalars, `${path}.${i}`, [
299
+ value[i],
300
+ i === lastIndex ? value.last : undefined,
301
+ i === nextIndex ? value.next : undefined,
302
+ ].filter((v) => v != null), {
303
+ prev: previousArray[i],
304
+ resolvedType: { ...resolvedType, type: type.type },
305
+ selectionSet,
306
+ });
307
+ }
308
+ return arr;
309
+ }
310
+ if (!definition)
311
+ throw new Error(`Could not find definition '${path}'`);
312
+ switch (definition.kind) {
313
+ case Kind.INPUT_OBJECT_TYPE_DEFINITION:
314
+ case Kind.OBJECT_TYPE_DEFINITION: {
315
+ const getProp = (target, prop) => {
316
+ if (prop === "toJSON")
317
+ return;
318
+ if (prop === "__typename")
319
+ return definition.name.value;
320
+ if (prop in target || typeof prop === "symbol") {
321
+ return target[prop];
322
+ }
323
+ const selectionField = selectionSet && typeof prop === "string"
324
+ ? getSelectionField(definitions, selectionSet, prop)
325
+ : undefined;
326
+ const unaliased = selectionField ? selectionField.name.value : prop;
327
+ const field = definition.fields?.find((f) => f.name.value === unaliased);
328
+ if (!field)
329
+ return target[prop];
330
+ // Get from patch
331
+ if (patches.length > 0 && patch && prop in patch) {
332
+ const rawValue = patch[prop];
333
+ const value = typeof rawValue === "function"
334
+ ? rawValue(prev)
335
+ : rawValue;
336
+ if (value && typeof value === "object") {
337
+ const nonNullFieldType = field.type.kind === Kind.NON_NULL_TYPE
338
+ ? field.type.type
339
+ : field.type;
340
+ if (nonNullFieldType.kind === Kind.LIST_TYPE) {
341
+ return target[prop] = _proxy(definitions, scalars, `${path}.${prop}`, [value], {
342
+ prev: prev?.[prop],
343
+ selectionSet: selectionSet
344
+ ? getSelectionSetSelection(definitions, selectionSet, prop)
345
+ : undefined,
346
+ });
347
+ }
348
+ const childPatches = patches.map((p) => p[prop]).filter((v) => !!v && typeof v === "object");
349
+ return target[prop] = _proxy(definitions, scalars, `${path}.${prop}`, childPatches, {
350
+ prev: prev?.[prop],
351
+ selectionSet: selectionSet
352
+ ? getSelectionSetSelection(definitions, selectionSet, prop)
353
+ : undefined,
354
+ });
355
+ }
356
+ if (value !== undefined) {
357
+ return target[prop] = value;
358
+ }
359
+ }
360
+ // Get from prev proxy if available; we check if prop in prev for
361
+ // typename changes due to interfaces (we don't predict typename ahead
362
+ // of time, since that's tedious...; could maybe use a custom Array that
363
+ // keeps a reference to the full array after slices)
364
+ if (prev && prop in prev) {
365
+ return target[prop] = prev[prop];
366
+ }
367
+ // Otherwise generate it from type
368
+ return target[prop] = resolveValue(definitions, scalars, field.type, {
369
+ hostType: definition.name.value,
370
+ prop,
371
+ selectionSet: selectionSet
372
+ ? getSelectionSetSelection(definitions, selectionSet, prop)
373
+ : undefined,
374
+ });
375
+ };
376
+ const keys = [
377
+ ...(definition.kind === Kind.OBJECT_TYPE_DEFINITION
378
+ ? ["__typename"]
379
+ : []),
380
+ ...(selectionSet
381
+ ? selectionSetToKeys(definitions, selectionSet, definition.name.value)
382
+ : definition.fields?.map((f) => f.name.value) ?? []),
383
+ ];
384
+ return new Proxy({}, {
385
+ get: getProp,
386
+ set: (target, prop, value) => {
387
+ target[prop] = value;
388
+ return true;
389
+ },
390
+ ownKeys: () => keys,
391
+ has: (target, prop) => typeof prop === "string" ? keys.includes(prop) : prop in target,
392
+ getOwnPropertyDescriptor: (target, prop) => prop === "__typename" ||
393
+ (typeof prop === "string" ? keys.includes(prop) : false)
394
+ ? ({
395
+ enumerable: true,
396
+ configurable: true,
397
+ writable: false,
398
+ value: getProp(target, prop),
399
+ })
400
+ : Object.getOwnPropertyDescriptor(target, prop),
401
+ });
402
+ }
403
+ case Kind.UNION_TYPE_DEFINITION:
404
+ case Kind.INTERFACE_TYPE_DEFINITION: {
405
+ // When creating prev, we need hint the desired type...
406
+ const concreteType = resolveConcreteType(definitions, definition, patch, prev);
407
+ return _proxy(definitions, scalars, concreteType.name.value, patches, {
408
+ prev,
409
+ selectionSet,
410
+ });
411
+ }
412
+ case Kind.OPERATION_DEFINITION: {
413
+ const mockPrev = prev;
414
+ const { variables: _1, data: _2, error: _3, errors: _4, ...prevExtra } = mockPrev ?? {};
415
+ const mockPatch = patch;
416
+ const { variables: _5, data: _6, error: _7, errors: _8, ...patchExtra } = mockPatch ?? {};
417
+ const mock = { ...prevExtra, ...patchExtra, data: null };
418
+ // const patch = patches[patches.length - 1] as Patch<Mock> | undefined;
419
+ const variablePatch = typeof mockPatch?.variables === "function"
420
+ ? mockPatch.variables(mockPrev)
421
+ : mockPatch?.variables;
422
+ for (const variableDefinition of definition.variableDefinitions ?? []) {
423
+ const name = variableDefinition.variable.name.value;
424
+ if (patch) {
425
+ if (variablePatch && name in variablePatch) {
426
+ const rawValue = variablePatch[name];
427
+ const value = typeof rawValue === "function"
428
+ ? rawValue(mockPrev.variables)
429
+ : rawValue;
430
+ if (value && typeof value === "object") {
431
+ let namedVariableType = variableDefinition.type;
432
+ while (namedVariableType.kind !== Kind.NAMED_TYPE) {
433
+ namedVariableType = namedVariableType.type;
434
+ }
435
+ if (!mock.variables)
436
+ mock.variables = {};
437
+ mock.variables[name] = _proxy(definitions, scalars, `${path}.$${name}`, [value], {
438
+ prev: mockPrev?.variables?.[name],
439
+ resolvedType: {
440
+ parent: `${path}Variables`,
441
+ type: variableDefinition.type,
442
+ definition: resolveType(definitions, namedVariableType.name.value).definition,
443
+ },
444
+ });
445
+ continue;
446
+ }
447
+ if (value !== undefined) {
448
+ if (!mock.variables)
449
+ mock.variables = {};
450
+ mock.variables[name] = value;
451
+ continue;
452
+ }
453
+ }
454
+ if (variableDefinition.defaultValue) {
455
+ if (!mock.variables)
456
+ mock.variables = {};
457
+ mock.variables[name] = constToValue(variableDefinition.defaultValue);
458
+ continue;
459
+ }
460
+ }
461
+ if (mockPrev?.variables && name in mockPrev.variables) {
462
+ if (!mock.variables)
463
+ mock.variables = {};
464
+ mock.variables[name] = mockPrev.variables[name];
465
+ continue;
466
+ }
467
+ const result = resolveValue(definitions, scalars, variableDefinition.type, { hostType: `${path}Variables`, prop: name });
468
+ if (result != null) {
469
+ if (!mock.variables)
470
+ mock.variables = {};
471
+ mock.variables[name] = result;
472
+ }
473
+ }
474
+ const dataPatch = typeof mockPatch?.data === "function"
475
+ ? mockPatch.data(mockPrev)
476
+ : mockPatch?.data;
477
+ for (const selection of definition.selectionSet.selections ?? []) {
478
+ switch (selection.kind) {
479
+ case Kind.FIELD: {
480
+ const prop = selection.alias?.value ?? selection.name.value;
481
+ const rawValue = dataPatch?.[prop];
482
+ const value = typeof rawValue === "function"
483
+ ? rawValue(mockPrev?.data)
484
+ : rawValue;
485
+ if (!mock.data)
486
+ mock.data = {};
487
+ // Query, Mutation, Subscription
488
+ const operationKey = definition.operation[0].toUpperCase() +
489
+ definition.operation.slice(1);
490
+ mock.data[prop] = _proxy(definitions, scalars, `${operationKey}.${selection.name.value}`, value != null ? [value] : [], {
491
+ prev: mockPrev?.data?.[prop],
492
+ selectionSet: selection.selectionSet,
493
+ });
494
+ continue;
495
+ }
496
+ case Kind.FRAGMENT_SPREAD:
497
+ case Kind.INLINE_FRAGMENT:
498
+ throw new Error(`Unhandled selection kind ${selection.kind}`);
499
+ default:
500
+ absurd(selection);
501
+ }
502
+ }
503
+ if (patch) {
504
+ if ("error" in patch) {
505
+ const value = typeof patch.error === "function"
506
+ ? patch.error(mockPrev)
507
+ : patch.error;
508
+ // TODO: what if an actual error patch is passed?
509
+ mock.error = value;
510
+ }
511
+ if ("errors" in patch) {
512
+ const rawErrors = typeof patch.errors === "function"
513
+ ? patch.errors(mockPrev)
514
+ : patch.errors;
515
+ if (Array.isArray(rawErrors) && rawErrors.length) {
516
+ mock.errors = rawErrors;
517
+ }
518
+ }
519
+ }
520
+ return mock;
521
+ }
522
+ case Kind.SCALAR_TYPE_DEFINITION: {
523
+ const patch = patches[patches.length - 1];
524
+ if (patch != null)
525
+ return patch;
526
+ if (prev != null)
527
+ return prev;
528
+ if (!(definition.name.value in scalars)) {
529
+ throw new Error(`Missing scalar ${definition.name.value}`);
530
+ }
531
+ const scalar = scalars[definition.name.value];
532
+ const value = typeof scalar === "function" ? scalar(parent) : scalar;
533
+ return value;
534
+ }
535
+ default:
536
+ throw new Error(`Unhandled definition kind '${definition.kind}'`);
537
+ }
538
+ };
539
+ export const proxy = (definitions, scalars, type, ...patches) => _proxy(definitions, scalars, type, patches);
540
+ const constToValue = (value) => {
541
+ switch (value.kind) {
542
+ case Kind.INT:
543
+ return parseInt(value.value);
544
+ case Kind.FLOAT:
545
+ return parseFloat(value.value);
546
+ case Kind.STRING:
547
+ return value.value;
548
+ case Kind.BOOLEAN:
549
+ return value.value;
550
+ case Kind.NULL:
551
+ return null;
552
+ case Kind.ENUM:
553
+ return value.value;
554
+ case Kind.LIST:
555
+ return value.values.map(constToValue);
556
+ case Kind.OBJECT:
557
+ return Object.fromEntries(value.fields.map((f) => [f.name.value, constToValue(f.value)]));
558
+ default:
559
+ absurd(value);
560
+ }
561
+ };
562
+ export const operation = (definitions, scalars, query, ...patches) => {
563
+ const document = parse(query);
564
+ const operations = document.definitions.filter((d) => d.kind === Kind.OPERATION_DEFINITION);
565
+ if (operations.length !== 1) {
566
+ throw new Error(`Expected 1 operation, got ${operations.length}`);
567
+ }
568
+ const operation = operations[0];
569
+ if (!operation.name?.value)
570
+ throw new Error("Expected operation to be named");
571
+ const { variables, data, error, errors, ...extra } = _proxy([...definitions, ...document.definitions], scalars, operation.name.value, patches);
572
+ const mock = {
573
+ request: { query },
574
+ result: {},
575
+ ...extra,
576
+ };
577
+ if (variables)
578
+ mock.request.variables = variables;
579
+ if (error) {
580
+ mock.error = error instanceof Error
581
+ ? error
582
+ : Object.assign(new Error(), error);
583
+ }
584
+ else if (data)
585
+ mock.result.data = data;
586
+ if (errors)
587
+ mock.result.errors = errors;
588
+ return mock;
589
+ };
package/esm/types.d.ts ADDED
@@ -0,0 +1,37 @@
1
+ import type { GraphQLError } from "graphql";
2
+ export type ContravariantEmpty = Record<string, never>;
3
+ export type CovariantEmpty = object;
4
+ type ArrayPatch<T> = Patch<T>[] | ({
5
+ [K in number]?: Patch<T>;
6
+ } & {
7
+ length?: number;
8
+ /** Append a value to the array. */
9
+ next?: Patch<T>;
10
+ /** Patch the last value in the array. */
11
+ last?: Patch<T>;
12
+ });
13
+ type ObjectPatch<T> = {
14
+ [K in keyof T]?: (T[K] extends object | null | undefined ? Patch<T[K]> : T[K]) | ((previous: T) => (T[K] extends object | null | undefined ? Patch<T[K]> : T[K]) | undefined | null);
15
+ };
16
+ export type Patch<T> = T extends (infer U)[] ? ArrayPatch<U> : ObjectPatch<T>;
17
+ export type DeepPartial<T> = T extends (infer U)[] ? DeepPartial<U>[] : T extends object ? {
18
+ [P in keyof T]?: DeepPartial<T[P]>;
19
+ } : T;
20
+ export type OperationMock<Data extends Record<string, unknown> = Record<string, unknown>, Variables = Record<string, unknown> | never> = {
21
+ request: {
22
+ query: string;
23
+ variables?: Variables;
24
+ };
25
+ result: {
26
+ data?: Data;
27
+ errors?: GraphQLError[];
28
+ };
29
+ error?: Error;
30
+ };
31
+ export type SimpleOperationMock<Data extends Record<string, unknown> = Record<string, unknown>, Variables = Record<string, unknown> | never> = {
32
+ data: Data;
33
+ variables?: Variables;
34
+ error?: Error;
35
+ errors?: GraphQLError[];
36
+ };
37
+ export {};
package/esm/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/esm/util.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ export declare const raise: (error: Error | string) => never;
2
+ export declare const formatCode: (input: string) => Promise<string>;
3
+ export declare const absurd: (v: never) => never;
4
+ type StripFunctions<T> = {
5
+ [K in keyof T]: T[K] extends (...args: any[]) => any ? never : T[K] extends object ? StripFunctions<T[K]> : T[K];
6
+ };
7
+ type NonNever<T> = Pick<T, {
8
+ [K in keyof T]: T[K] extends never ? never : K;
9
+ }[keyof T]>;
10
+ export declare const toObject: <T>(obj: T) => NonNever<StripFunctions<T>>;
11
+ export {};
package/esm/util.js ADDED
@@ -0,0 +1,47 @@
1
+ import { exec } from "node:child_process";
2
+ export const raise = (error) => {
3
+ if (typeof error === "string") {
4
+ const err = new Error(error);
5
+ Error.captureStackTrace(err, raise);
6
+ throw err;
7
+ }
8
+ throw error;
9
+ };
10
+ export const formatCode = async (input) => {
11
+ try {
12
+ return await new Promise((resolve, reject) => {
13
+ const process = exec("deno fmt -", (error, stdout, stderr) => {
14
+ if (error)
15
+ return reject(error);
16
+ if (stderr)
17
+ return reject(new Error(stderr));
18
+ resolve(stdout);
19
+ });
20
+ process.stdin?.write(input);
21
+ process.stdin?.end();
22
+ });
23
+ }
24
+ catch {
25
+ return input;
26
+ }
27
+ };
28
+ export const absurd = (v) => {
29
+ const error = new Error(`Unexpected value: ${v}`);
30
+ Error.captureStackTrace(error, absurd);
31
+ throw error;
32
+ };
33
+ export const toObject = (obj) => {
34
+ if (typeof obj !== "object" || !obj) {
35
+ return obj;
36
+ }
37
+ if (Array.isArray(obj)) {
38
+ return obj.map(toObject);
39
+ }
40
+ const clone = {};
41
+ for (const key in obj) {
42
+ if (typeof obj[key] !== "function") {
43
+ clone[key] = toObject(obj[key]);
44
+ }
45
+ }
46
+ return clone;
47
+ };