graphql-data-generator 0.4.5 → 0.4.6-alpha.1
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 +54 -0
- package/esm/browser.js +3 -0
- package/esm/codegen.js +2 -1
- package/esm/defaultLoader.js +92 -0
- package/esm/index.js +6 -1
- package/esm/init.js +23 -67
- package/package.json +7 -1
- package/script/browser.js +11 -0
- package/script/codegen.js +2 -1
- package/script/defaultLoader.js +122 -0
- package/script/index.js +7 -2
- package/script/init.js +22 -89
- package/types/browser.d.ts +4 -0
- package/types/defaultLoader.d.ts +16 -0
- package/types/extendedTypes.d.ts +22 -12
- package/types/index.d.ts +2 -1
- package/types/init.d.ts +11 -4
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ tests.
|
|
|
13
13
|
- [Transforms](#transforms)
|
|
14
14
|
- [Testing](#testing)
|
|
15
15
|
- [Extra properties](#extra)
|
|
16
|
+
- [Browser usage](#browser-usage)
|
|
16
17
|
|
|
17
18
|
### Key Concepts
|
|
18
19
|
|
|
@@ -341,3 +342,56 @@ const build = init<
|
|
|
341
342
|
|
|
342
343
|
build.CreatePost({ internal: true }).internal; // true
|
|
343
344
|
```
|
|
345
|
+
|
|
346
|
+
## Browser usage
|
|
347
|
+
|
|
348
|
+
`graphql-data-generator` can be used in browser environments by providing a
|
|
349
|
+
custom `loadDocument` option to `init`. The default file-system-based loader is
|
|
350
|
+
skipped automatically when Node.js or Deno APIs are not detected.
|
|
351
|
+
|
|
352
|
+
Since browsers don't have file system access, you provide operation documents
|
|
353
|
+
directly — either as strings or pre-parsed `DocumentNode` objects:
|
|
354
|
+
|
|
355
|
+
```ts
|
|
356
|
+
import { init } from "graphql-data-generator";
|
|
357
|
+
|
|
358
|
+
const schema = `
|
|
359
|
+
type Query {
|
|
360
|
+
getUser(id: ID): User
|
|
361
|
+
}
|
|
362
|
+
type User {
|
|
363
|
+
id: ID!
|
|
364
|
+
name: String!
|
|
365
|
+
}
|
|
366
|
+
`;
|
|
367
|
+
|
|
368
|
+
const operations = {
|
|
369
|
+
GetUser: `
|
|
370
|
+
query GetUser($id: ID) {
|
|
371
|
+
getUser(id: $id) {
|
|
372
|
+
id
|
|
373
|
+
name
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
`,
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
const build = init(
|
|
380
|
+
schema,
|
|
381
|
+
{ GetUser: "GetUser" },
|
|
382
|
+
{},
|
|
383
|
+
{},
|
|
384
|
+
{ User: ["id", "name"] },
|
|
385
|
+
[],
|
|
386
|
+
{ ID: (t) => `${t}-id`, String: (t) => `${t}-string` },
|
|
387
|
+
{ loadDocument: (key) => operations[key] },
|
|
388
|
+
)(() => ({}));
|
|
389
|
+
|
|
390
|
+
build.User(); // { __typename: "User", id: "User-id", name: "User-string" }
|
|
391
|
+
build.GetUser(); // { request: { query: ..., variables: ... }, result: { data: { getUser: ... } } }
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
The `loadDocument` function receives the path string from the generated types
|
|
395
|
+
file and should return either a GraphQL string or a `DocumentNode`. This allows
|
|
396
|
+
you to load operations from any source — bundled strings, a network request, or
|
|
397
|
+
an in-memory map.
|
package/esm/browser.js
ADDED
package/esm/codegen.js
CHANGED
|
@@ -244,7 +244,8 @@ const serializeType = (type, variables = false, depth = 0) => {
|
|
|
244
244
|
case "List":
|
|
245
245
|
if (type.value.optional ||
|
|
246
246
|
(type.value.kind === "Object" &&
|
|
247
|
-
((type.value.conditionals?.length ?? 0)
|
|
247
|
+
((type.value.conditionals?.length ?? 0) +
|
|
248
|
+
(type.value.nonExhaustive?.length ? 1 : 0) -
|
|
248
249
|
(Object.keys(type.value.value).length ? 0 : 1)))) {
|
|
249
250
|
return `(${serializeType(type.value, variables, depth)})[]${type.optional ? " | null" : ""}`;
|
|
250
251
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default document loader for Node.js and Deno environments.
|
|
3
|
+
* In browser environments, this module loads successfully but the exported
|
|
4
|
+
* function throws a helpful error if called without Node/Deno APIs available.
|
|
5
|
+
*/
|
|
6
|
+
import * as dntShim from "./_dnt.shims.js";
|
|
7
|
+
import { createRequire } from "node:module";
|
|
8
|
+
import { readFileSync } from "node:fs";
|
|
9
|
+
import { dirname, resolve } from "node:path";
|
|
10
|
+
import nodeProcess from "node:process";
|
|
11
|
+
import { Kind, parse } from "graphql";
|
|
12
|
+
import { gqlPluckFromCodeStringSync } from "@graphql-tools/graphql-tag-pluck";
|
|
13
|
+
/** Check if input is already a DocumentNode. */
|
|
14
|
+
const isDocumentNode = (input) => typeof input === "object" && input !== null && "kind" in input &&
|
|
15
|
+
input.kind === Kind.DOCUMENT;
|
|
16
|
+
// deno-lint-ignore no-explicit-any
|
|
17
|
+
const isDeno = typeof dntShim.dntGlobalThis.Deno?.version?.deno === "string";
|
|
18
|
+
const isNode = typeof globalThis.process?.versions?.node === "string";
|
|
19
|
+
let _impl;
|
|
20
|
+
if (isDeno || isNode) {
|
|
21
|
+
// deno-lint-ignore no-explicit-any
|
|
22
|
+
const cwd = dntShim.dntGlobalThis.Deno?.cwd?.() ?? nodeProcess.cwd();
|
|
23
|
+
globalThis.require ??= createRequire(cwd);
|
|
24
|
+
const files = {};
|
|
25
|
+
const loadFile = (path) => {
|
|
26
|
+
if (files[path])
|
|
27
|
+
return files[path];
|
|
28
|
+
const raw = readFileSync(path, "utf-8");
|
|
29
|
+
const imports = Array.from(raw.matchAll(/#import "(.*)"/gm), ([, importPath]) => loadFile(require.resolve(importPath.startsWith(".")
|
|
30
|
+
? resolve(cwd, dirname(path), importPath)
|
|
31
|
+
: importPath, { paths: [cwd] })));
|
|
32
|
+
if (!imports.length)
|
|
33
|
+
return files[path] = raw;
|
|
34
|
+
return files[path] = [raw, ...imports].join("\n\n");
|
|
35
|
+
};
|
|
36
|
+
const cache = {};
|
|
37
|
+
_impl = (path) => {
|
|
38
|
+
const existing = cache[path];
|
|
39
|
+
if (existing) {
|
|
40
|
+
if (isDocumentNode(existing))
|
|
41
|
+
return existing;
|
|
42
|
+
return loadFile(path);
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const doc = require(require.resolve(path, { paths: [cwd] }));
|
|
46
|
+
if (isDocumentNode(doc)) {
|
|
47
|
+
cache[path] = doc;
|
|
48
|
+
return doc;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// Otherwise load it manually
|
|
53
|
+
}
|
|
54
|
+
const fileContent = loadFile(path);
|
|
55
|
+
try {
|
|
56
|
+
const sources = gqlPluckFromCodeStringSync(path, fileContent);
|
|
57
|
+
cache[path] = Object.fromEntries(sources.map((s) => {
|
|
58
|
+
const document = parse(s);
|
|
59
|
+
const firstOp = document.definitions.find((d) => d.kind === Kind.OPERATION_DEFINITION);
|
|
60
|
+
if (!firstOp) {
|
|
61
|
+
throw new Error(`Could not find an operation in ${path}`);
|
|
62
|
+
}
|
|
63
|
+
return [firstOp.name?.value, document];
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
cache[path] = parse(fileContent);
|
|
68
|
+
}
|
|
69
|
+
return loadFile(path);
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Default document loader for Node.js and Deno environments.
|
|
74
|
+
* Loads GraphQL documents from the filesystem with support for:
|
|
75
|
+
* - Direct .gql/.graphql files
|
|
76
|
+
* - #import directives
|
|
77
|
+
* - GraphQL tag plucking from JS/TS files
|
|
78
|
+
* - require() with GraphQL loaders
|
|
79
|
+
*
|
|
80
|
+
* In browser environments, throws an error directing users to pass
|
|
81
|
+
* a custom `loadDocument` option to `init`.
|
|
82
|
+
*
|
|
83
|
+
* @param path - Path to the GraphQL operation file
|
|
84
|
+
* @returns The document content as a string or pre-parsed DocumentNode
|
|
85
|
+
*/
|
|
86
|
+
export const defaultLoader = (path) => {
|
|
87
|
+
if (!_impl) {
|
|
88
|
+
throw new Error("defaultLoader requires Node.js or Deno file system APIs. " +
|
|
89
|
+
"In browser environments, pass a custom `loadDocument` option to `init`.");
|
|
90
|
+
}
|
|
91
|
+
return _impl(path);
|
|
92
|
+
};
|
package/esm/index.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import { init as _init } from "./init.js";
|
|
2
|
+
import { defaultLoader } from "./defaultLoader.js";
|
|
3
|
+
export const init = (schema, queries, mutations, subscriptions, types, inputs, scalars, options) => _init(schema, queries, mutations, subscriptions, types, inputs, scalars, {
|
|
4
|
+
loadDocument: defaultLoader,
|
|
5
|
+
...options,
|
|
6
|
+
});
|
|
2
7
|
export { codegen } from "./codegen.js";
|
|
3
8
|
export { clear, operation, proxy } from "./proxy.js";
|
|
4
9
|
export { toObject } from "./util.js";
|
package/esm/init.js
CHANGED
|
@@ -1,88 +1,44 @@
|
|
|
1
|
-
import * as dntShim from "./_dnt.shims.js";
|
|
2
|
-
import { createRequire } from "node:module";
|
|
3
|
-
import { readFileSync } from "node:fs";
|
|
4
1
|
import { Kind, parse, } from "graphql";
|
|
5
|
-
import { gqlPluckFromCodeStringSync } from "@graphql-tools/graphql-tag-pluck";
|
|
6
2
|
import { _proxy, operation, withGetDefaultPatch, } from "./proxy.js";
|
|
7
|
-
import { toObject } from "./util.js";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const files = {};
|
|
11
|
-
const loadFile = (path) => {
|
|
12
|
-
if (files[path])
|
|
13
|
-
return files[path];
|
|
14
|
-
const raw = readFileSync(path, "utf-8");
|
|
15
|
-
const imports = Array.from(raw.matchAll(/#import "(.*)"/gm), ([, importPath]) => loadFile(require.resolve(importPath.startsWith(".")
|
|
16
|
-
? resolve(dntShim.Deno.cwd(), dirname(path), importPath)
|
|
17
|
-
: importPath, { paths: [dntShim.Deno.cwd()] })));
|
|
18
|
-
if (!imports.length)
|
|
19
|
-
return files[path] = raw;
|
|
20
|
-
return files[path] = [raw, ...imports].join("\n\n");
|
|
21
|
-
};
|
|
22
|
-
const getOperationContentMap = {};
|
|
23
|
-
const getOperationContent = (path, operationName) => {
|
|
24
|
-
const existing = getOperationContentMap[path];
|
|
25
|
-
if (existing) {
|
|
26
|
-
if (existing.kind === Kind.DOCUMENT)
|
|
27
|
-
return existing;
|
|
28
|
-
return getOperationContentMap[path][operationName];
|
|
29
|
-
}
|
|
30
|
-
try {
|
|
31
|
-
// First try loading via require, depending on GQL loaders
|
|
32
|
-
const doc = require(require.resolve(path, { paths: [dntShim.Deno.cwd()] }));
|
|
33
|
-
if (doc && typeof doc === "object" && "kind" in doc && doc.kind === "Document") {
|
|
34
|
-
getOperationContentMap[path] = doc;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
// Otherwise load it manually
|
|
39
|
-
const fileContent = loadFile(path);
|
|
40
|
-
try {
|
|
41
|
-
const sources = gqlPluckFromCodeStringSync(path, fileContent);
|
|
42
|
-
getOperationContentMap[path] = Object.fromEntries(sources.map((s) => {
|
|
43
|
-
const document = parse(s);
|
|
44
|
-
const firstOp = document.definitions.find((d) => d.kind === Kind.OPERATION_DEFINITION);
|
|
45
|
-
if (!firstOp)
|
|
46
|
-
throw new Error(`Could not find an operation in ${path}`);
|
|
47
|
-
return [firstOp.name?.value, document];
|
|
48
|
-
}));
|
|
49
|
-
}
|
|
50
|
-
catch {
|
|
51
|
-
getOperationContentMap[path] = parse(fileContent);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return getOperationContent(path, operationName);
|
|
55
|
-
};
|
|
3
|
+
import { raise, toObject } from "./util.js";
|
|
4
|
+
/** Converts a string or DocumentNode to a DocumentNode. */
|
|
5
|
+
const ensureDocument = (input) => typeof input === "string" ? parse(input) : input;
|
|
56
6
|
// Helper: Unwraps non-null and list wrappers to get the named type.
|
|
57
7
|
const getNamedType = (type) => type.kind === Kind.NAMED_TYPE ? type.name.value : getNamedType(type.type);
|
|
58
8
|
// Helper: Find a type definition in the document by name.
|
|
59
9
|
const getTypeDef = (definitions, typeName) => definitions.find((def) => "name" in def && def.name?.value === typeName);
|
|
60
10
|
/**
|
|
61
11
|
* Initialize the data builder.
|
|
62
|
-
* @param schema The
|
|
12
|
+
* @param schema The schema as a string or pre-parsed DocumentNode.
|
|
63
13
|
* @param queries List of queries exported from generated types.
|
|
64
14
|
* @param mutations List of mutations exported from generated types.
|
|
65
15
|
* @param subscriptions List of subscriptions exported from generated types.
|
|
66
16
|
* @param types List of types exported from generated types.
|
|
67
17
|
* @param inputs List of types exported from generated types.
|
|
68
18
|
* @param scalars A mapping to generate scalar values. Function values will be invoked with their `__typename`.
|
|
19
|
+
* @param options.loadDocument Function to load operation documents. Defaults to the Node/Deno file loader.
|
|
20
|
+
* @param options.finalizeOperation Optional function to finalize operation mocks.
|
|
69
21
|
*/
|
|
70
22
|
export const init = (schema, queries, mutations, subscriptions, types, inputs, scalars, options) => (fn) => {
|
|
71
|
-
const doc =
|
|
23
|
+
const doc = ensureDocument(schema);
|
|
24
|
+
// Memoize document loading so each path is only loaded once
|
|
25
|
+
const documentCache = new Map();
|
|
26
|
+
const loadDocument = (path) => {
|
|
27
|
+
const cached = documentCache.get(path);
|
|
28
|
+
if (cached)
|
|
29
|
+
return cached;
|
|
30
|
+
const result = (options?.loadDocument ?? (() => raise("No loadDocument option provided. " +
|
|
31
|
+
"Use the default import from 'graphql-data-generator' for Node/Deno, " +
|
|
32
|
+
"or pass a custom loadDocument option for browser environments.")))(path);
|
|
33
|
+
const document = ensureDocument(result);
|
|
34
|
+
documentCache.set(path, document);
|
|
35
|
+
return document;
|
|
36
|
+
};
|
|
72
37
|
// Collect all fragment definitions from operation files, deduplicating by name
|
|
73
38
|
const fragmentDefinitionsMap = new Map();
|
|
74
|
-
const collectFragments = (filePath
|
|
39
|
+
const collectFragments = (filePath) => {
|
|
75
40
|
try {
|
|
76
|
-
|
|
77
|
-
let document;
|
|
78
|
-
if (operationName) {
|
|
79
|
-
document = getOperationContent(filePath, operationName);
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
// Parse the file directly to get all definitions including fragments
|
|
83
|
-
const fileContent = loadFile(filePath);
|
|
84
|
-
document = parse(fileContent);
|
|
85
|
-
}
|
|
41
|
+
const document = loadDocument(filePath);
|
|
86
42
|
for (const def of document.definitions) {
|
|
87
43
|
if (def.kind === Kind.FRAGMENT_DEFINITION) {
|
|
88
44
|
// Only add if not already seen (dedup by fragment name)
|
|
@@ -305,7 +261,7 @@ export const init = (schema, queries, mutations, subscriptions, types, inputs, s
|
|
|
305
261
|
};
|
|
306
262
|
const operationBuilder = (name, path) => {
|
|
307
263
|
const builder = (...patches) => {
|
|
308
|
-
const query =
|
|
264
|
+
const query = loadDocument(path);
|
|
309
265
|
if (transforms[name] && "default" in transforms[name]) {
|
|
310
266
|
patches = [transforms[name].default, ...patches];
|
|
311
267
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "graphql-data-generator",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.6-alpha.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/voces/graphql-data-generator.git"
|
|
@@ -19,6 +19,12 @@
|
|
|
19
19
|
"types": "./types/index.d.ts",
|
|
20
20
|
"default": "./esm/index.js"
|
|
21
21
|
},
|
|
22
|
+
"./browser": {
|
|
23
|
+
"import": "./esm/browser.js",
|
|
24
|
+
"require": "./script/browser.js",
|
|
25
|
+
"types": "./types/browser.d.ts",
|
|
26
|
+
"default": "./esm/browser.js"
|
|
27
|
+
},
|
|
22
28
|
"./plugin": {
|
|
23
29
|
"import": "./esm/plugin.cjs",
|
|
24
30
|
"require": "./script/plugin.cjs",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toObject = exports.proxy = exports.operation = exports.clear = exports.init = void 0;
|
|
4
|
+
var init_js_1 = require("./init.js");
|
|
5
|
+
Object.defineProperty(exports, "init", { enumerable: true, get: function () { return init_js_1.init; } });
|
|
6
|
+
var proxy_js_1 = require("./proxy.js");
|
|
7
|
+
Object.defineProperty(exports, "clear", { enumerable: true, get: function () { return proxy_js_1.clear; } });
|
|
8
|
+
Object.defineProperty(exports, "operation", { enumerable: true, get: function () { return proxy_js_1.operation; } });
|
|
9
|
+
Object.defineProperty(exports, "proxy", { enumerable: true, get: function () { return proxy_js_1.proxy; } });
|
|
10
|
+
var util_js_1 = require("./util.js");
|
|
11
|
+
Object.defineProperty(exports, "toObject", { enumerable: true, get: function () { return util_js_1.toObject; } });
|
package/script/codegen.js
CHANGED
|
@@ -250,7 +250,8 @@ const serializeType = (type, variables = false, depth = 0) => {
|
|
|
250
250
|
case "List":
|
|
251
251
|
if (type.value.optional ||
|
|
252
252
|
(type.value.kind === "Object" &&
|
|
253
|
-
((type.value.conditionals?.length ?? 0)
|
|
253
|
+
((type.value.conditionals?.length ?? 0) +
|
|
254
|
+
(type.value.nonExhaustive?.length ? 1 : 0) -
|
|
254
255
|
(Object.keys(type.value.value).length ? 0 : 1)))) {
|
|
255
256
|
return `(${serializeType(type.value, variables, depth)})[]${type.optional ? " | null" : ""}`;
|
|
256
257
|
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.defaultLoader = void 0;
|
|
30
|
+
/**
|
|
31
|
+
* Default document loader for Node.js and Deno environments.
|
|
32
|
+
* In browser environments, this module loads successfully but the exported
|
|
33
|
+
* function throws a helpful error if called without Node/Deno APIs available.
|
|
34
|
+
*/
|
|
35
|
+
const dntShim = __importStar(require("./_dnt.shims.js"));
|
|
36
|
+
const node_module_1 = require("node:module");
|
|
37
|
+
const node_fs_1 = require("node:fs");
|
|
38
|
+
const node_path_1 = require("node:path");
|
|
39
|
+
const node_process_1 = __importDefault(require("node:process"));
|
|
40
|
+
const graphql_1 = require("graphql");
|
|
41
|
+
const graphql_tag_pluck_1 = require("@graphql-tools/graphql-tag-pluck");
|
|
42
|
+
/** Check if input is already a DocumentNode. */
|
|
43
|
+
const isDocumentNode = (input) => typeof input === "object" && input !== null && "kind" in input &&
|
|
44
|
+
input.kind === graphql_1.Kind.DOCUMENT;
|
|
45
|
+
// deno-lint-ignore no-explicit-any
|
|
46
|
+
const isDeno = typeof dntShim.dntGlobalThis.Deno?.version?.deno === "string";
|
|
47
|
+
const isNode = typeof globalThis.process?.versions?.node === "string";
|
|
48
|
+
let _impl;
|
|
49
|
+
if (isDeno || isNode) {
|
|
50
|
+
// deno-lint-ignore no-explicit-any
|
|
51
|
+
const cwd = dntShim.dntGlobalThis.Deno?.cwd?.() ?? node_process_1.default.cwd();
|
|
52
|
+
globalThis.require ??= (0, node_module_1.createRequire)(cwd);
|
|
53
|
+
const files = {};
|
|
54
|
+
const loadFile = (path) => {
|
|
55
|
+
if (files[path])
|
|
56
|
+
return files[path];
|
|
57
|
+
const raw = (0, node_fs_1.readFileSync)(path, "utf-8");
|
|
58
|
+
const imports = Array.from(raw.matchAll(/#import "(.*)"/gm), ([, importPath]) => loadFile(require.resolve(importPath.startsWith(".")
|
|
59
|
+
? (0, node_path_1.resolve)(cwd, (0, node_path_1.dirname)(path), importPath)
|
|
60
|
+
: importPath, { paths: [cwd] })));
|
|
61
|
+
if (!imports.length)
|
|
62
|
+
return files[path] = raw;
|
|
63
|
+
return files[path] = [raw, ...imports].join("\n\n");
|
|
64
|
+
};
|
|
65
|
+
const cache = {};
|
|
66
|
+
_impl = (path) => {
|
|
67
|
+
const existing = cache[path];
|
|
68
|
+
if (existing) {
|
|
69
|
+
if (isDocumentNode(existing))
|
|
70
|
+
return existing;
|
|
71
|
+
return loadFile(path);
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const doc = require(require.resolve(path, { paths: [cwd] }));
|
|
75
|
+
if (isDocumentNode(doc)) {
|
|
76
|
+
cache[path] = doc;
|
|
77
|
+
return doc;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// Otherwise load it manually
|
|
82
|
+
}
|
|
83
|
+
const fileContent = loadFile(path);
|
|
84
|
+
try {
|
|
85
|
+
const sources = (0, graphql_tag_pluck_1.gqlPluckFromCodeStringSync)(path, fileContent);
|
|
86
|
+
cache[path] = Object.fromEntries(sources.map((s) => {
|
|
87
|
+
const document = (0, graphql_1.parse)(s);
|
|
88
|
+
const firstOp = document.definitions.find((d) => d.kind === graphql_1.Kind.OPERATION_DEFINITION);
|
|
89
|
+
if (!firstOp) {
|
|
90
|
+
throw new Error(`Could not find an operation in ${path}`);
|
|
91
|
+
}
|
|
92
|
+
return [firstOp.name?.value, document];
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
cache[path] = (0, graphql_1.parse)(fileContent);
|
|
97
|
+
}
|
|
98
|
+
return loadFile(path);
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Default document loader for Node.js and Deno environments.
|
|
103
|
+
* Loads GraphQL documents from the filesystem with support for:
|
|
104
|
+
* - Direct .gql/.graphql files
|
|
105
|
+
* - #import directives
|
|
106
|
+
* - GraphQL tag plucking from JS/TS files
|
|
107
|
+
* - require() with GraphQL loaders
|
|
108
|
+
*
|
|
109
|
+
* In browser environments, throws an error directing users to pass
|
|
110
|
+
* a custom `loadDocument` option to `init`.
|
|
111
|
+
*
|
|
112
|
+
* @param path - Path to the GraphQL operation file
|
|
113
|
+
* @returns The document content as a string or pre-parsed DocumentNode
|
|
114
|
+
*/
|
|
115
|
+
const defaultLoader = (path) => {
|
|
116
|
+
if (!_impl) {
|
|
117
|
+
throw new Error("defaultLoader requires Node.js or Deno file system APIs. " +
|
|
118
|
+
"In browser environments, pass a custom `loadDocument` option to `init`.");
|
|
119
|
+
}
|
|
120
|
+
return _impl(path);
|
|
121
|
+
};
|
|
122
|
+
exports.defaultLoader = defaultLoader;
|
package/script/index.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.toObject = exports.proxy = exports.operation = exports.clear = exports.codegen = exports.init = void 0;
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const init_js_1 = require("./init.js");
|
|
5
|
+
const defaultLoader_js_1 = require("./defaultLoader.js");
|
|
6
|
+
const init = (schema, queries, mutations, subscriptions, types, inputs, scalars, options) => (0, init_js_1.init)(schema, queries, mutations, subscriptions, types, inputs, scalars, {
|
|
7
|
+
loadDocument: defaultLoader_js_1.defaultLoader,
|
|
8
|
+
...options,
|
|
9
|
+
});
|
|
10
|
+
exports.init = init;
|
|
6
11
|
var codegen_js_1 = require("./codegen.js");
|
|
7
12
|
Object.defineProperty(exports, "codegen", { enumerable: true, get: function () { return codegen_js_1.codegen; } });
|
|
8
13
|
var proxy_js_1 = require("./proxy.js");
|
package/script/init.js
CHANGED
|
@@ -1,114 +1,47 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
3
|
exports.init = void 0;
|
|
27
|
-
const dntShim = __importStar(require("./_dnt.shims.js"));
|
|
28
|
-
const node_module_1 = require("node:module");
|
|
29
|
-
const node_fs_1 = require("node:fs");
|
|
30
4
|
const graphql_1 = require("graphql");
|
|
31
|
-
const graphql_tag_pluck_1 = require("@graphql-tools/graphql-tag-pluck");
|
|
32
5
|
const proxy_js_1 = require("./proxy.js");
|
|
33
6
|
const util_js_1 = require("./util.js");
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const files = {};
|
|
37
|
-
const loadFile = (path) => {
|
|
38
|
-
if (files[path])
|
|
39
|
-
return files[path];
|
|
40
|
-
const raw = (0, node_fs_1.readFileSync)(path, "utf-8");
|
|
41
|
-
const imports = Array.from(raw.matchAll(/#import "(.*)"/gm), ([, importPath]) => loadFile(require.resolve(importPath.startsWith(".")
|
|
42
|
-
? (0, node_path_1.resolve)(dntShim.Deno.cwd(), (0, node_path_1.dirname)(path), importPath)
|
|
43
|
-
: importPath, { paths: [dntShim.Deno.cwd()] })));
|
|
44
|
-
if (!imports.length)
|
|
45
|
-
return files[path] = raw;
|
|
46
|
-
return files[path] = [raw, ...imports].join("\n\n");
|
|
47
|
-
};
|
|
48
|
-
const getOperationContentMap = {};
|
|
49
|
-
const getOperationContent = (path, operationName) => {
|
|
50
|
-
const existing = getOperationContentMap[path];
|
|
51
|
-
if (existing) {
|
|
52
|
-
if (existing.kind === graphql_1.Kind.DOCUMENT)
|
|
53
|
-
return existing;
|
|
54
|
-
return getOperationContentMap[path][operationName];
|
|
55
|
-
}
|
|
56
|
-
try {
|
|
57
|
-
// First try loading via require, depending on GQL loaders
|
|
58
|
-
const doc = require(require.resolve(path, { paths: [dntShim.Deno.cwd()] }));
|
|
59
|
-
if (doc && typeof doc === "object" && "kind" in doc && doc.kind === "Document") {
|
|
60
|
-
getOperationContentMap[path] = doc;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
catch {
|
|
64
|
-
// Otherwise load it manually
|
|
65
|
-
const fileContent = loadFile(path);
|
|
66
|
-
try {
|
|
67
|
-
const sources = (0, graphql_tag_pluck_1.gqlPluckFromCodeStringSync)(path, fileContent);
|
|
68
|
-
getOperationContentMap[path] = Object.fromEntries(sources.map((s) => {
|
|
69
|
-
const document = (0, graphql_1.parse)(s);
|
|
70
|
-
const firstOp = document.definitions.find((d) => d.kind === graphql_1.Kind.OPERATION_DEFINITION);
|
|
71
|
-
if (!firstOp)
|
|
72
|
-
throw new Error(`Could not find an operation in ${path}`);
|
|
73
|
-
return [firstOp.name?.value, document];
|
|
74
|
-
}));
|
|
75
|
-
}
|
|
76
|
-
catch {
|
|
77
|
-
getOperationContentMap[path] = (0, graphql_1.parse)(fileContent);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return getOperationContent(path, operationName);
|
|
81
|
-
};
|
|
7
|
+
/** Converts a string or DocumentNode to a DocumentNode. */
|
|
8
|
+
const ensureDocument = (input) => typeof input === "string" ? (0, graphql_1.parse)(input) : input;
|
|
82
9
|
// Helper: Unwraps non-null and list wrappers to get the named type.
|
|
83
10
|
const getNamedType = (type) => type.kind === graphql_1.Kind.NAMED_TYPE ? type.name.value : getNamedType(type.type);
|
|
84
11
|
// Helper: Find a type definition in the document by name.
|
|
85
12
|
const getTypeDef = (definitions, typeName) => definitions.find((def) => "name" in def && def.name?.value === typeName);
|
|
86
13
|
/**
|
|
87
14
|
* Initialize the data builder.
|
|
88
|
-
* @param schema The
|
|
15
|
+
* @param schema The schema as a string or pre-parsed DocumentNode.
|
|
89
16
|
* @param queries List of queries exported from generated types.
|
|
90
17
|
* @param mutations List of mutations exported from generated types.
|
|
91
18
|
* @param subscriptions List of subscriptions exported from generated types.
|
|
92
19
|
* @param types List of types exported from generated types.
|
|
93
20
|
* @param inputs List of types exported from generated types.
|
|
94
21
|
* @param scalars A mapping to generate scalar values. Function values will be invoked with their `__typename`.
|
|
22
|
+
* @param options.loadDocument Function to load operation documents. Defaults to the Node/Deno file loader.
|
|
23
|
+
* @param options.finalizeOperation Optional function to finalize operation mocks.
|
|
95
24
|
*/
|
|
96
25
|
const init = (schema, queries, mutations, subscriptions, types, inputs, scalars, options) => (fn) => {
|
|
97
|
-
const doc = (
|
|
26
|
+
const doc = ensureDocument(schema);
|
|
27
|
+
// Memoize document loading so each path is only loaded once
|
|
28
|
+
const documentCache = new Map();
|
|
29
|
+
const loadDocument = (path) => {
|
|
30
|
+
const cached = documentCache.get(path);
|
|
31
|
+
if (cached)
|
|
32
|
+
return cached;
|
|
33
|
+
const result = (options?.loadDocument ?? (() => (0, util_js_1.raise)("No loadDocument option provided. " +
|
|
34
|
+
"Use the default import from 'graphql-data-generator' for Node/Deno, " +
|
|
35
|
+
"or pass a custom loadDocument option for browser environments.")))(path);
|
|
36
|
+
const document = ensureDocument(result);
|
|
37
|
+
documentCache.set(path, document);
|
|
38
|
+
return document;
|
|
39
|
+
};
|
|
98
40
|
// Collect all fragment definitions from operation files, deduplicating by name
|
|
99
41
|
const fragmentDefinitionsMap = new Map();
|
|
100
|
-
const collectFragments = (filePath
|
|
42
|
+
const collectFragments = (filePath) => {
|
|
101
43
|
try {
|
|
102
|
-
|
|
103
|
-
let document;
|
|
104
|
-
if (operationName) {
|
|
105
|
-
document = getOperationContent(filePath, operationName);
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
// Parse the file directly to get all definitions including fragments
|
|
109
|
-
const fileContent = loadFile(filePath);
|
|
110
|
-
document = (0, graphql_1.parse)(fileContent);
|
|
111
|
-
}
|
|
44
|
+
const document = loadDocument(filePath);
|
|
112
45
|
for (const def of document.definitions) {
|
|
113
46
|
if (def.kind === graphql_1.Kind.FRAGMENT_DEFINITION) {
|
|
114
47
|
// Only add if not already seen (dedup by fragment name)
|
|
@@ -331,7 +264,7 @@ const init = (schema, queries, mutations, subscriptions, types, inputs, scalars,
|
|
|
331
264
|
};
|
|
332
265
|
const operationBuilder = (name, path) => {
|
|
333
266
|
const builder = (...patches) => {
|
|
334
|
-
const query =
|
|
267
|
+
const query = loadDocument(path);
|
|
335
268
|
if (transforms[name] && "default" in transforms[name]) {
|
|
336
269
|
patches = [transforms[name].default, ...patches];
|
|
337
270
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DocumentInput } from "./init.js";
|
|
2
|
+
/**
|
|
3
|
+
* Default document loader for Node.js and Deno environments.
|
|
4
|
+
* Loads GraphQL documents from the filesystem with support for:
|
|
5
|
+
* - Direct .gql/.graphql files
|
|
6
|
+
* - #import directives
|
|
7
|
+
* - GraphQL tag plucking from JS/TS files
|
|
8
|
+
* - require() with GraphQL loaders
|
|
9
|
+
*
|
|
10
|
+
* In browser environments, throws an error directing users to pass
|
|
11
|
+
* a custom `loadDocument` option to `init`.
|
|
12
|
+
*
|
|
13
|
+
* @param path - Path to the GraphQL operation file
|
|
14
|
+
* @returns The document content as a string or pre-parsed DocumentNode
|
|
15
|
+
*/
|
|
16
|
+
export declare const defaultLoader: (path: string) => DocumentInput;
|
package/types/extendedTypes.d.ts
CHANGED
|
@@ -25,13 +25,6 @@ type PrefixKeys<T, Prefix extends string> = {
|
|
|
25
25
|
type MapObjectsToBuilders<T, Transforms> = {
|
|
26
26
|
[K in keyof T]: ObjectBuilder<T[K], K extends keyof Transforms ? Transforms[K] : ContravariantEmpty>;
|
|
27
27
|
};
|
|
28
|
-
export type MapObjectsToTransforms<Objects extends Record<string, Record<string, unknown>>> = {
|
|
29
|
-
[Object in keyof Objects]?: Record<string, DefaultObjectTransform<Objects[Object], Objects[Object]> | ((prev: Objects[Object], ...args: any[]) => Patch<Objects[Object]>)>;
|
|
30
|
-
};
|
|
31
|
-
type InnerMapOperationsToTransforms<Operations> = {
|
|
32
|
-
[Operation in keyof Operations]?: Record<string, InferOperationTransforms<Operations[Operation]>>;
|
|
33
|
-
};
|
|
34
|
-
export type MapOperationsToTransforms<Queries, Mutations, Subscriptions, Types, Inputs> = InnerMapOperationsToTransforms<ResolveConflicts<Queries, Mutations, Subscriptions, Types, Inputs>>;
|
|
35
28
|
type MapOperationsToBuilders<T, Transforms, Extra> = {
|
|
36
29
|
[K in keyof T]: OperationBuilder<T[K] extends {
|
|
37
30
|
data: infer U;
|
|
@@ -49,14 +42,31 @@ type DefaultOperationTransform<T> = {
|
|
|
49
42
|
variables: infer V;
|
|
50
43
|
} ? Patch<V> : never;
|
|
51
44
|
};
|
|
52
|
-
type
|
|
53
|
-
|
|
45
|
+
type AllKeysOf<T> = T extends any ? keyof T : never;
|
|
46
|
+
type ValueOf<T, K extends PropertyKey> = T extends any ? K extends keyof T ? T[K] : never : never;
|
|
47
|
+
type ExcessCheck<R, T> = Record<Exclude<keyof R, AllKeysOf<T>>, never> & {
|
|
48
|
+
[K in keyof R & AllKeysOf<T>]: R[K] extends (...args: any[]) => any ? unknown : NonNullable<ValueOf<T, K>> extends any[] ? unknown : NonNullable<R[K]> extends object ? NonNullable<ValueOf<T, K>> extends object ? ExcessCheck<NonNullable<R[K]>, NonNullable<ValueOf<T, K>>> : unknown : unknown;
|
|
49
|
+
};
|
|
50
|
+
type ObjectTransformValue<Value, Obj> = Value extends (...args: any[]) => infer R ? (prev: Obj, ...args: any[]) => Patch<Obj extends Record<string, unknown> ? Obj : never> & ExcessCheck<R, Obj> : DefaultObjectTransform<Obj extends Record<string, unknown> ? Obj : never, Obj extends Record<string, unknown> ? Obj : never> & Record<Exclude<keyof Value, AllKeysOf<Obj>>, never>;
|
|
51
|
+
type OperationTransformValue<Value, Op> = Value extends (...args: any[]) => infer R ? (b: {
|
|
52
|
+
data: Op extends {
|
|
54
53
|
data: infer U;
|
|
55
54
|
} ? U : never;
|
|
56
|
-
variables:
|
|
55
|
+
variables: Op extends {
|
|
57
56
|
variables: infer U;
|
|
58
57
|
} ? U : never;
|
|
59
|
-
}, ...args: any[]) => Patch<
|
|
60
|
-
|
|
58
|
+
}, ...args: any[]) => Patch<Op> & ExcessCheck<R, Op> : DefaultOperationTransform<Op> & Record<Exclude<keyof Value, "data" | "variables">, never>;
|
|
59
|
+
/**
|
|
60
|
+
* Self-referential constraint that ensures:
|
|
61
|
+
* 1. Top-level keys are known type/input/operation names (unknown → never)
|
|
62
|
+
* 2. Transform values don't have excess properties
|
|
63
|
+
*/
|
|
64
|
+
export type Transforms<T, Objects extends Record<string, Record<string, unknown>>, Queries, Mutations, Subscriptions, Types extends Record<string, Record<string, unknown>>, Inputs extends Record<string, Record<string, unknown>>> = {
|
|
65
|
+
[K in keyof T]: K extends keyof Objects ? {
|
|
66
|
+
[TK in keyof T[K]]: ObjectTransformValue<T[K][TK], Objects[K]>;
|
|
67
|
+
} : K extends keyof ResolveConflicts<Queries, Mutations, Subscriptions, Types, Inputs> ? {
|
|
68
|
+
[TK in keyof T[K]]: OperationTransformValue<T[K][TK], ResolveConflicts<Queries, Mutations, Subscriptions, Types, Inputs>[K]>;
|
|
69
|
+
} : never;
|
|
70
|
+
};
|
|
61
71
|
export type Build<Queries, Mutations, Subscriptions, Types, Inputs, Transforms, Extra> = MapObjectsToBuilders<Types & Inputs, Transforms> & MapOperationsToBuilders<ResolveConflicts<Queries, Mutations, Subscriptions, Types, Inputs>, Transforms, Extra>;
|
|
62
72
|
export {};
|
package/types/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { init as _init } from "./init.js";
|
|
2
|
+
export declare const init: typeof _init;
|
|
2
3
|
export type { DeepPartial, OperationMock, Patch } from "./types.js";
|
|
3
4
|
export { codegen } from "./codegen.js";
|
|
4
5
|
export { clear, operation, proxy } from "./proxy.js";
|
package/types/init.d.ts
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { DocumentNode } from "graphql";
|
|
2
|
+
import type { Build, Transforms } from "./extendedTypes.js";
|
|
2
3
|
import type { ContravariantEmpty, OperationMock } from "./types.js";
|
|
4
|
+
/** A GraphQL document can be provided as a string or a pre-parsed DocumentNode. */
|
|
5
|
+
export type DocumentInput = string | DocumentNode;
|
|
3
6
|
/**
|
|
4
7
|
* Initialize the data builder.
|
|
5
|
-
* @param schema The
|
|
8
|
+
* @param schema The schema as a string or pre-parsed DocumentNode.
|
|
6
9
|
* @param queries List of queries exported from generated types.
|
|
7
10
|
* @param mutations List of mutations exported from generated types.
|
|
8
11
|
* @param subscriptions List of subscriptions exported from generated types.
|
|
9
12
|
* @param types List of types exported from generated types.
|
|
10
13
|
* @param inputs List of types exported from generated types.
|
|
11
14
|
* @param scalars A mapping to generate scalar values. Function values will be invoked with their `__typename`.
|
|
15
|
+
* @param options.loadDocument Function to load operation documents. Defaults to the Node/Deno file loader.
|
|
16
|
+
* @param options.finalizeOperation Optional function to finalize operation mocks.
|
|
12
17
|
*/
|
|
13
18
|
export declare const init: <Query extends Record<string, {
|
|
14
19
|
data: Record<string, unknown>;
|
|
@@ -19,8 +24,10 @@ export declare const init: <Query extends Record<string, {
|
|
|
19
24
|
}>, Subscription extends Record<string, {
|
|
20
25
|
data: Record<string, unknown>;
|
|
21
26
|
variables?: Record<string, unknown>;
|
|
22
|
-
}>, Types extends Record<string, Record<string, unknown>>, Inputs extends Record<string, Record<string, unknown>>, Extra = object>(schema:
|
|
27
|
+
}>, Types extends Record<string, Record<string, unknown>>, Inputs extends Record<string, Record<string, unknown>>, Extra = object>(schema: DocumentInput, queries: { [operation in keyof Query]: string; }, mutations: { [operation in keyof Mutation]: string; }, subscriptions: { [operation in keyof Subscription]: string; }, types: { readonly [type in keyof Types]: readonly string[]; }, inputs: readonly (keyof Inputs & string)[], scalars: {
|
|
23
28
|
[name: string]: ((typeName: string, fieldName: string) => unknown) | string | number | boolean | null;
|
|
24
29
|
}, options?: {
|
|
30
|
+
/** Load an operation document from a path. Returns string or DocumentNode. */
|
|
31
|
+
loadDocument?: (path: string) => DocumentInput;
|
|
25
32
|
finalizeOperation?: <T extends OperationMock & Partial<Extra>>(operation: T) => T;
|
|
26
|
-
}) => <
|
|
33
|
+
}) => <T extends Transforms<T, Types & Inputs, Query, Mutation, Subscription, Types, Inputs>>(fn: (b: Build<Query, Mutation, Subscription, Types, Inputs, ContravariantEmpty, Extra>) => T) => Build<Query, Mutation, Subscription, Types, Inputs, T, Extra>;
|