graphql-jerky 1.0.7 → 1.0.9
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 +21 -0
- package/build/bin/jerky.cjs +34 -15
- package/build/bin/jerky.mjs +36 -17
- package/build/lib.cjs +111 -79
- package/build/lib.mjs +107 -75
- package/package.json +36 -36
package/README.md
CHANGED
|
@@ -34,6 +34,27 @@ in the same directory.
|
|
|
34
34
|
A path to a directory or file can be passed as the first parameter to limit to
|
|
35
35
|
scope of the search.
|
|
36
36
|
|
|
37
|
+
### Type extensions
|
|
38
|
+
|
|
39
|
+
Type extensions (`extend type`, `extend interface`, `extend union`,
|
|
40
|
+
`extend enum`, `extend input` and `extend scalar`) are merged into the type
|
|
41
|
+
that they extend. The extension and the definition can be in different files,
|
|
42
|
+
in any order.
|
|
43
|
+
|
|
44
|
+
```gql
|
|
45
|
+
# user.graphql
|
|
46
|
+
type Query {
|
|
47
|
+
me: User
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# post.graphql
|
|
51
|
+
extend type Query {
|
|
52
|
+
posts: [Post!]!
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
An extension of a type that is not defined causes an error.
|
|
57
|
+
|
|
37
58
|
### Options
|
|
38
59
|
|
|
39
60
|
#### --graphql
|
package/build/bin/jerky.cjs
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var fs = require('node:fs/promises');
|
|
6
|
+
var path = require('node:path');
|
|
6
7
|
var commander = require('commander');
|
|
7
|
-
var fs = require('fs/promises');
|
|
8
8
|
var lib = require('../lib.cjs');
|
|
9
9
|
|
|
10
10
|
commander.program
|
|
@@ -13,37 +13,43 @@ commander.program
|
|
|
13
13
|
.description("Schema-first GraphQL typescript code generator")
|
|
14
14
|
.argument("[schema]", "Path to schema file or directory.")
|
|
15
15
|
.option("-o, --out <destination>", "Path to write schema_gen.ts.")
|
|
16
|
+
.option("-t", "Write types to a separate file.")
|
|
17
|
+
.option("--types-out <destination>", "Path to write types_gen.ts. Types will be written in types_gen.ts if omitted and -t is used.")
|
|
16
18
|
.option("--graphql <module>", "graphql module import specifier.")
|
|
17
19
|
.option("--scalars <module>", "scalars module import specifier.")
|
|
18
20
|
.option("--resolvers <directory>", "resolvers directory path.")
|
|
19
21
|
.option("--subscribers <module>", "subscriber module import specifier.")
|
|
20
22
|
.option("--field-directives <module>", "field directives module import specifier.")
|
|
21
23
|
.option("--input-directives <module>", "input directives module import specifier.")
|
|
24
|
+
.option("--include-ast-nodes", "Include ast nodes in graphql type objects")
|
|
25
|
+
.option("--include-subscription-resolvers", "Include subscription field resolvers in graphql type objects")
|
|
22
26
|
.option("--ext <mode>", 'whether "keep", "replace", or "omit" the .ts extension in import statements.')
|
|
23
27
|
.showHelpAfterError(true);
|
|
24
28
|
commander.program.parse();
|
|
25
|
-
const { out = "schema_gen.ts", graphql = "graphql", scalars, resolvers, subscribers, fieldDirectives, inputDirectives, ext = "omit", } = commander.program.opts();
|
|
29
|
+
const { out = "schema_gen.ts", typesOut, graphql = "graphql", scalars, resolvers, subscribers, fieldDirectives, inputDirectives, ext = "omit", t: splitTypesFile, includeAstNodes, includeSubscriptionResolvers: includeSubscriptionFieldResolvers, } = commander.program.opts();
|
|
26
30
|
const [schema = "."] = commander.program.args;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (!outfile.pathname.endsWith("/")) {
|
|
31
|
+
async function normalizeOutfile(path, defaultFilename) {
|
|
32
|
+
if (!path.endsWith("/")) {
|
|
30
33
|
// test if it's a directory
|
|
31
34
|
try {
|
|
32
|
-
const stat = await fs.stat(
|
|
35
|
+
const stat = await fs.stat(path);
|
|
33
36
|
if (stat.isDirectory()) {
|
|
34
|
-
|
|
37
|
+
path += "/";
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
catch {
|
|
38
41
|
// probably doesn't exist yet
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
|
-
if (
|
|
42
|
-
|
|
44
|
+
if (path.endsWith("/")) {
|
|
45
|
+
path += defaultFilename;
|
|
43
46
|
}
|
|
44
|
-
if (!
|
|
45
|
-
|
|
47
|
+
if (!path.endsWith(".ts")) {
|
|
48
|
+
path += ".ts";
|
|
46
49
|
}
|
|
50
|
+
return path;
|
|
51
|
+
}
|
|
52
|
+
(async () => {
|
|
47
53
|
switch (ext) {
|
|
48
54
|
case "keep":
|
|
49
55
|
case "replace":
|
|
@@ -52,7 +58,7 @@ const [schema = "."] = commander.program.args;
|
|
|
52
58
|
default:
|
|
53
59
|
throw new Error(`invalid mode for --ext: ${ext}`);
|
|
54
60
|
}
|
|
55
|
-
|
|
61
|
+
const generator = lib.createGenerator(await lib.parseSchema(path.resolve(schema)), {
|
|
56
62
|
scalarsInfo: scalars ? await lib.parseScalars(scalars) : undefined,
|
|
57
63
|
fieldDirectivesInfo: fieldDirectives
|
|
58
64
|
? await lib.parseTypeResolvers("", fieldDirectives)
|
|
@@ -66,9 +72,22 @@ const [schema = "."] = commander.program.args;
|
|
|
66
72
|
: undefined,
|
|
67
73
|
graphqlModuleSpecifier: graphql,
|
|
68
74
|
extMode: ext,
|
|
69
|
-
|
|
75
|
+
includeAstNodes,
|
|
76
|
+
includeSubscriptionFieldResolvers,
|
|
77
|
+
});
|
|
78
|
+
const outfile = await normalizeOutfile(out, "schema_gen.ts");
|
|
79
|
+
if (splitTypesFile || typesOut) {
|
|
80
|
+
const typesfile = await normalizeOutfile(typesOut ?? path.dirname(outfile), "types_gen.ts");
|
|
81
|
+
await Promise.all([
|
|
82
|
+
fs.writeFile(outfile, generator.generateSchema(outfile)),
|
|
83
|
+
fs.writeFile(typesfile, generator.generateTypes(typesfile)),
|
|
84
|
+
]);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
await fs.writeFile(outfile, generator.generate(outfile));
|
|
88
|
+
}
|
|
70
89
|
})().catch((err) => {
|
|
71
|
-
console.error(err.
|
|
90
|
+
console.error(err.stack);
|
|
72
91
|
console.log();
|
|
73
92
|
if (process.argv.length === 2 ||
|
|
74
93
|
(process.argv.length === 3 && process.argv[2] === "help")) {
|
package/build/bin/jerky.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
4
5
|
import { program } from 'commander';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import 'url';
|
|
6
|
+
import { createGenerator, parseScalars as parse, parseTypeResolvers, parseResolvers as parse$1, parseSchema as parse$2 } from '../lib.mjs';
|
|
7
|
+
import 'node:url';
|
|
8
8
|
import 'graphql';
|
|
9
9
|
import 'jennifer-js';
|
|
10
10
|
import 'jennifer-js/format';
|
|
@@ -21,37 +21,43 @@ program
|
|
|
21
21
|
.description("Schema-first GraphQL typescript code generator")
|
|
22
22
|
.argument("[schema]", "Path to schema file or directory.")
|
|
23
23
|
.option("-o, --out <destination>", "Path to write schema_gen.ts.")
|
|
24
|
+
.option("-t", "Write types to a separate file.")
|
|
25
|
+
.option("--types-out <destination>", "Path to write types_gen.ts. Types will be written in types_gen.ts if omitted and -t is used.")
|
|
24
26
|
.option("--graphql <module>", "graphql module import specifier.")
|
|
25
27
|
.option("--scalars <module>", "scalars module import specifier.")
|
|
26
28
|
.option("--resolvers <directory>", "resolvers directory path.")
|
|
27
29
|
.option("--subscribers <module>", "subscriber module import specifier.")
|
|
28
30
|
.option("--field-directives <module>", "field directives module import specifier.")
|
|
29
31
|
.option("--input-directives <module>", "input directives module import specifier.")
|
|
32
|
+
.option("--include-ast-nodes", "Include ast nodes in graphql type objects")
|
|
33
|
+
.option("--include-subscription-resolvers", "Include subscription field resolvers in graphql type objects")
|
|
30
34
|
.option("--ext <mode>", 'whether "keep", "replace", or "omit" the .ts extension in import statements.')
|
|
31
35
|
.showHelpAfterError(true);
|
|
32
36
|
program.parse();
|
|
33
|
-
const { out = "schema_gen.ts", graphql = "graphql", scalars, resolvers, subscribers, fieldDirectives, inputDirectives, ext = "omit", } = program.opts();
|
|
37
|
+
const { out = "schema_gen.ts", typesOut, graphql = "graphql", scalars, resolvers, subscribers, fieldDirectives, inputDirectives, ext = "omit", t: splitTypesFile, includeAstNodes, includeSubscriptionResolvers: includeSubscriptionFieldResolvers, } = program.opts();
|
|
34
38
|
const [schema = "."] = program.args;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (!outfile.pathname.endsWith("/")) {
|
|
39
|
+
async function normalizeOutfile(path, defaultFilename) {
|
|
40
|
+
if (!path.endsWith("/")) {
|
|
38
41
|
// test if it's a directory
|
|
39
42
|
try {
|
|
40
|
-
const stat = await fs.stat(
|
|
43
|
+
const stat = await fs.stat(path);
|
|
41
44
|
if (stat.isDirectory()) {
|
|
42
|
-
|
|
45
|
+
path += "/";
|
|
43
46
|
}
|
|
44
47
|
}
|
|
45
48
|
catch {
|
|
46
49
|
// probably doesn't exist yet
|
|
47
50
|
}
|
|
48
51
|
}
|
|
49
|
-
if (
|
|
50
|
-
|
|
52
|
+
if (path.endsWith("/")) {
|
|
53
|
+
path += defaultFilename;
|
|
51
54
|
}
|
|
52
|
-
if (!
|
|
53
|
-
|
|
55
|
+
if (!path.endsWith(".ts")) {
|
|
56
|
+
path += ".ts";
|
|
54
57
|
}
|
|
58
|
+
return path;
|
|
59
|
+
}
|
|
60
|
+
(async () => {
|
|
55
61
|
switch (ext) {
|
|
56
62
|
case "keep":
|
|
57
63
|
case "replace":
|
|
@@ -60,7 +66,7 @@ const [schema = "."] = program.args;
|
|
|
60
66
|
default:
|
|
61
67
|
throw new Error(`invalid mode for --ext: ${ext}`);
|
|
62
68
|
}
|
|
63
|
-
|
|
69
|
+
const generator = createGenerator(await parse$2(path.resolve(schema)), {
|
|
64
70
|
scalarsInfo: scalars ? await parse(scalars) : undefined,
|
|
65
71
|
fieldDirectivesInfo: fieldDirectives
|
|
66
72
|
? await parseTypeResolvers("", fieldDirectives)
|
|
@@ -74,9 +80,22 @@ const [schema = "."] = program.args;
|
|
|
74
80
|
: undefined,
|
|
75
81
|
graphqlModuleSpecifier: graphql,
|
|
76
82
|
extMode: ext,
|
|
77
|
-
|
|
83
|
+
includeAstNodes,
|
|
84
|
+
includeSubscriptionFieldResolvers,
|
|
85
|
+
});
|
|
86
|
+
const outfile = await normalizeOutfile(out, "schema_gen.ts");
|
|
87
|
+
if (splitTypesFile || typesOut) {
|
|
88
|
+
const typesfile = await normalizeOutfile(typesOut ?? path.dirname(outfile), "types_gen.ts");
|
|
89
|
+
await Promise.all([
|
|
90
|
+
fs.writeFile(outfile, generator.generateSchema(outfile)),
|
|
91
|
+
fs.writeFile(typesfile, generator.generateTypes(typesfile)),
|
|
92
|
+
]);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
await fs.writeFile(outfile, generator.generate(outfile));
|
|
96
|
+
}
|
|
78
97
|
})().catch((err) => {
|
|
79
|
-
console.error(err.
|
|
98
|
+
console.error(err.stack);
|
|
80
99
|
console.log();
|
|
81
100
|
if (process.argv.length === 2 ||
|
|
82
101
|
(process.argv.length === 3 && process.argv[2] === "help")) {
|
package/build/lib.cjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var path = require('path');
|
|
4
|
-
var
|
|
3
|
+
var path = require('node:path');
|
|
4
|
+
var node_url = require('node:url');
|
|
5
5
|
var graphql = require('graphql');
|
|
6
6
|
var jen = require('jennifer-js');
|
|
7
7
|
var format = require('jennifer-js/format');
|
|
8
8
|
var partition = require('just-partition');
|
|
9
9
|
var pascalCase = require('just-pascal-case');
|
|
10
|
-
var fs = require('fs/promises');
|
|
10
|
+
var fs = require('node:fs/promises');
|
|
11
11
|
var ts = require('typescript');
|
|
12
12
|
var glob = require('glob');
|
|
13
13
|
var pm = require('picomatch');
|
|
@@ -225,12 +225,12 @@ async function findExports(source, resolveModuleFn = resolveModule) {
|
|
|
225
225
|
return exports;
|
|
226
226
|
}
|
|
227
227
|
async function parseModule(sourceOrPath) {
|
|
228
|
-
const url
|
|
229
|
-
?
|
|
228
|
+
const url = typeof sourceOrPath === "string"
|
|
229
|
+
? node_url.pathToFileURL(path.resolve(sourceOrPath))
|
|
230
230
|
: new URL(sourceOrPath.fileName);
|
|
231
|
-
const source = typeof sourceOrPath === "string" ? await parseSource(url
|
|
231
|
+
const source = typeof sourceOrPath === "string" ? await parseSource(url) : sourceOrPath;
|
|
232
232
|
return {
|
|
233
|
-
path: url
|
|
233
|
+
path: url,
|
|
234
234
|
exports: await findExports(source),
|
|
235
235
|
source,
|
|
236
236
|
};
|
|
@@ -305,7 +305,7 @@ function renderImports(base, imports, aliases, extMode = "omit") {
|
|
|
305
305
|
return jen.statements(...imports.map(([pkg, symbols]) => {
|
|
306
306
|
let mod = pkg;
|
|
307
307
|
if (mod.startsWith("file:///")) {
|
|
308
|
-
mod =
|
|
308
|
+
mod = node_url.fileURLToPath(mod);
|
|
309
309
|
}
|
|
310
310
|
if (mod.startsWith("/")) {
|
|
311
311
|
mod = path.relative(base, mod);
|
|
@@ -340,14 +340,8 @@ function renderAstNode(astNode) {
|
|
|
340
340
|
}
|
|
341
341
|
function isBuiltInDirective(name) {
|
|
342
342
|
// https://spec.graphql.org/draft/#sec-Type-System.Directives.Built-in-Directives
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
case "skip":
|
|
346
|
-
case "include":
|
|
347
|
-
case "specifiedBy":
|
|
348
|
-
return true;
|
|
349
|
-
}
|
|
350
|
-
return false;
|
|
343
|
+
// Use the list from graphql, because new versions add directives (for example, @oneOf).
|
|
344
|
+
return graphql.specifiedDirectives.some((d) => d.name === name);
|
|
351
345
|
}
|
|
352
346
|
function truthify(arr) {
|
|
353
347
|
return arr.filter(Boolean);
|
|
@@ -371,7 +365,8 @@ class GeneratorContext {
|
|
|
371
365
|
this._graphqlModuleSpecifier = options.graphqlModuleSpecifier ?? "graphql";
|
|
372
366
|
this._pkgs = new RequiredPackages();
|
|
373
367
|
this._extMode = options.extMode ?? "omit";
|
|
374
|
-
this._includeSubscriptionFieldResolvers =
|
|
368
|
+
this._includeSubscriptionFieldResolvers =
|
|
369
|
+
options.includeSubscriptionFieldResolvers ?? false;
|
|
375
370
|
}
|
|
376
371
|
_gql(name) {
|
|
377
372
|
return jen.id(this._pkgs.addRequires(this._graphqlModuleSpecifier, name));
|
|
@@ -603,7 +598,8 @@ class GeneratorContext {
|
|
|
603
598
|
const typeInterfaces = type.getInterfaces();
|
|
604
599
|
return jen.new
|
|
605
600
|
.add(this._gql("GraphQLObjectType"))
|
|
606
|
-
.call(jen.obj(jen.prop("name", jen.lit(type.name)), jen.prop("fields", this._renderFieldsThunk(type, inputFieldDirectives, includeAstNodes, !this._includeSubscriptionFieldResolvers &&
|
|
601
|
+
.call(jen.obj(jen.prop("name", jen.lit(type.name)), jen.prop("fields", this._renderFieldsThunk(type, inputFieldDirectives, includeAstNodes, !this._includeSubscriptionFieldResolvers &&
|
|
602
|
+
type.name === "Subscription")), ...truthify([
|
|
607
603
|
type.description &&
|
|
608
604
|
jen.prop("description", jen.lit(type.description)),
|
|
609
605
|
typeInterfaces.length &&
|
|
@@ -865,22 +861,22 @@ class GeneratorContext {
|
|
|
865
861
|
}
|
|
866
862
|
_getGraphQLTypeClass(type) {
|
|
867
863
|
if (type instanceof graphql.GraphQLObjectType) {
|
|
868
|
-
return
|
|
864
|
+
return "GraphQLObjectType";
|
|
869
865
|
}
|
|
870
866
|
if (type instanceof graphql.GraphQLScalarType) {
|
|
871
|
-
return
|
|
867
|
+
return "GraphQLScalarType";
|
|
872
868
|
}
|
|
873
869
|
if (type instanceof graphql.GraphQLInterfaceType) {
|
|
874
|
-
return
|
|
870
|
+
return "GraphQLInterfaceType";
|
|
875
871
|
}
|
|
876
872
|
if (type instanceof graphql.GraphQLUnionType) {
|
|
877
|
-
return
|
|
873
|
+
return "GraphQLUnionType";
|
|
878
874
|
}
|
|
879
875
|
if (type instanceof graphql.GraphQLInputObjectType) {
|
|
880
|
-
return
|
|
876
|
+
return "GraphQLInputObjectType";
|
|
881
877
|
}
|
|
882
878
|
if (type instanceof graphql.GraphQLEnumType) {
|
|
883
|
-
return
|
|
879
|
+
return "GraphQLEnumType";
|
|
884
880
|
}
|
|
885
881
|
throw new Error(`unhandled type: ${type.toString()}`);
|
|
886
882
|
}
|
|
@@ -1611,6 +1607,9 @@ function setTraceToSchema(err, name, loc) {
|
|
|
1611
1607
|
}
|
|
1612
1608
|
return err;
|
|
1613
1609
|
}
|
|
1610
|
+
function isMergableDefinitionNode(node) {
|
|
1611
|
+
return graphql.isTypeDefinitionNode(node) || node.kind === graphql.Kind.DIRECTIVE_DEFINITION;
|
|
1612
|
+
}
|
|
1614
1613
|
function namedNodesDict(nodes = []) {
|
|
1615
1614
|
return Object.fromEntries(nodes.map((node) => [node.name.value, node]));
|
|
1616
1615
|
}
|
|
@@ -1724,7 +1723,7 @@ function mergeFieldDefinitionNodes(name, a, b) {
|
|
|
1724
1723
|
console.warn(`WARNING: there is more than one declaration for ${name}.${f.name.value}${traceLine(f.loc)}${traceLine(prev.loc, "previously ")}\n`);
|
|
1725
1724
|
fields[f.name.value] = {
|
|
1726
1725
|
...prev,
|
|
1727
|
-
directives: mergeDirectiveNodes(
|
|
1726
|
+
directives: mergeDirectiveNodes(prev.directives, f.directives),
|
|
1728
1727
|
};
|
|
1729
1728
|
}
|
|
1730
1729
|
else {
|
|
@@ -1749,7 +1748,7 @@ function mergeInputValueDefinitionNodes(name, a, b) {
|
|
|
1749
1748
|
console.warn(`WARNING: there is more than one declaration for ${name}.${f.name.value}${traceLine(f.loc)}${traceLine(prev.loc, "previously ")}\n`);
|
|
1750
1749
|
fields[f.name.value] = {
|
|
1751
1750
|
...prev,
|
|
1752
|
-
directives: mergeDirectiveNodes(
|
|
1751
|
+
directives: mergeDirectiveNodes(prev.directives, f.directives),
|
|
1753
1752
|
};
|
|
1754
1753
|
}
|
|
1755
1754
|
else {
|
|
@@ -1768,18 +1767,19 @@ function mergeNamedNodes(a, b) {
|
|
|
1768
1767
|
}
|
|
1769
1768
|
return Object.values(nodes);
|
|
1770
1769
|
}
|
|
1771
|
-
function mergeDirectiveNodes(
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1770
|
+
function mergeDirectiveNodes(a, b) {
|
|
1771
|
+
// Keep each occurrence, because a repeatable directive can occur more than
|
|
1772
|
+
// once. Skip only an occurrence that is identical to one that is already
|
|
1773
|
+
// applied. buildASTSchema rejects a non-repeatable directive that occurs
|
|
1774
|
+
// more than once.
|
|
1775
|
+
const directives = Array.from(a ?? []);
|
|
1776
|
+
for (const d of b ?? []) {
|
|
1777
|
+
if (!directives.some((prev) => prev.name.value === d.name.value &&
|
|
1778
|
+
isArgumentNodesEqual(prev.arguments, d.arguments))) {
|
|
1779
|
+
directives.push(d);
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
return directives;
|
|
1783
1783
|
}
|
|
1784
1784
|
function mergeScalarTypeDefinitionNodes(a, b) {
|
|
1785
1785
|
if (a.name.value !== b.name.value) {
|
|
@@ -1787,8 +1787,10 @@ function mergeScalarTypeDefinitionNodes(a, b) {
|
|
|
1787
1787
|
}
|
|
1788
1788
|
return {
|
|
1789
1789
|
kind: graphql.Kind.SCALAR_TYPE_DEFINITION,
|
|
1790
|
+
loc: a.loc,
|
|
1790
1791
|
name: a.name,
|
|
1791
|
-
|
|
1792
|
+
description: a.description || b.description,
|
|
1793
|
+
directives: mergeDirectiveNodes(a.directives, b.directives),
|
|
1792
1794
|
};
|
|
1793
1795
|
}
|
|
1794
1796
|
function mergeObjectTypeDefinitionNodes(a, b) {
|
|
@@ -1798,7 +1800,7 @@ function mergeObjectTypeDefinitionNodes(a, b) {
|
|
|
1798
1800
|
name: a.name,
|
|
1799
1801
|
description: a.description || b.description,
|
|
1800
1802
|
interfaces: mergeNamedNodes(a.interfaces, b.interfaces),
|
|
1801
|
-
directives: mergeDirectiveNodes(a.
|
|
1803
|
+
directives: mergeDirectiveNodes(a.directives, b.directives),
|
|
1802
1804
|
fields: mergeFieldDefinitionNodes(a.name.value, a.fields, b.fields),
|
|
1803
1805
|
};
|
|
1804
1806
|
}
|
|
@@ -1809,7 +1811,7 @@ function mergeInterfaceTypeDefinitionNodes(a, b) {
|
|
|
1809
1811
|
name: a.name,
|
|
1810
1812
|
description: a.description || b.description,
|
|
1811
1813
|
interfaces: mergeNamedNodes(a.interfaces, b.interfaces),
|
|
1812
|
-
directives: mergeDirectiveNodes(a.
|
|
1814
|
+
directives: mergeDirectiveNodes(a.directives, b.directives),
|
|
1813
1815
|
fields: mergeFieldDefinitionNodes(a.name.value, a.fields, b.fields),
|
|
1814
1816
|
};
|
|
1815
1817
|
}
|
|
@@ -1819,7 +1821,7 @@ function mergeUnionTypeDefinitionNodes(a, b) {
|
|
|
1819
1821
|
loc: a.loc,
|
|
1820
1822
|
name: a.name,
|
|
1821
1823
|
description: a.description || b.description,
|
|
1822
|
-
directives: mergeDirectiveNodes(a.
|
|
1824
|
+
directives: mergeDirectiveNodes(a.directives, b.directives),
|
|
1823
1825
|
types: mergeNamedNodes(a.types, b.types),
|
|
1824
1826
|
};
|
|
1825
1827
|
}
|
|
@@ -1828,7 +1830,7 @@ function mergeEnumTypeDefinitionNodes(a, b) {
|
|
|
1828
1830
|
if (b) {
|
|
1829
1831
|
for (const v of b.values || []) {
|
|
1830
1832
|
if (v.name.value in values) {
|
|
1831
|
-
throw setTraceToSchema(new graphql.GraphQLError(`Cannot merge duplicate enum value: ${
|
|
1833
|
+
throw setTraceToSchema(new graphql.GraphQLError(`Cannot merge duplicate enum value: ${a.name.value}.${v.name.value}`), `${a.name.value}.${v.name.value}`, v.loc);
|
|
1832
1834
|
}
|
|
1833
1835
|
values[v.name.value] = v;
|
|
1834
1836
|
}
|
|
@@ -1838,7 +1840,7 @@ function mergeEnumTypeDefinitionNodes(a, b) {
|
|
|
1838
1840
|
loc: a.loc,
|
|
1839
1841
|
name: a.name,
|
|
1840
1842
|
description: a.description || b.description,
|
|
1841
|
-
directives: mergeDirectiveNodes(a.
|
|
1843
|
+
directives: mergeDirectiveNodes(a.directives, b.directives),
|
|
1842
1844
|
values: Object.values(values),
|
|
1843
1845
|
};
|
|
1844
1846
|
}
|
|
@@ -1848,26 +1850,74 @@ function mergeInputObjectTypeDefinitionNodes(a, b) {
|
|
|
1848
1850
|
loc: a.loc,
|
|
1849
1851
|
name: a.name,
|
|
1850
1852
|
description: a.description || b.description,
|
|
1851
|
-
directives: mergeDirectiveNodes(a.
|
|
1853
|
+
directives: mergeDirectiveNodes(a.directives, b.directives),
|
|
1852
1854
|
fields: mergeInputValueDefinitionNodes(a.name.value, a.fields, b.fields),
|
|
1853
1855
|
};
|
|
1854
1856
|
}
|
|
1857
|
+
const EXTENSION_DEFINITION_KINDS = {
|
|
1858
|
+
[graphql.Kind.SCALAR_TYPE_EXTENSION]: graphql.Kind.SCALAR_TYPE_DEFINITION,
|
|
1859
|
+
[graphql.Kind.OBJECT_TYPE_EXTENSION]: graphql.Kind.OBJECT_TYPE_DEFINITION,
|
|
1860
|
+
[graphql.Kind.INTERFACE_TYPE_EXTENSION]: graphql.Kind.INTERFACE_TYPE_DEFINITION,
|
|
1861
|
+
[graphql.Kind.UNION_TYPE_EXTENSION]: graphql.Kind.UNION_TYPE_DEFINITION,
|
|
1862
|
+
[graphql.Kind.ENUM_TYPE_EXTENSION]: graphql.Kind.ENUM_TYPE_DEFINITION,
|
|
1863
|
+
[graphql.Kind.INPUT_OBJECT_TYPE_EXTENSION]: graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION,
|
|
1864
|
+
};
|
|
1865
|
+
function mergeTypeDefinitionNodes(a, b) {
|
|
1866
|
+
switch (b.kind) {
|
|
1867
|
+
case graphql.Kind.SCALAR_TYPE_DEFINITION:
|
|
1868
|
+
return mergeScalarTypeDefinitionNodes(a, b);
|
|
1869
|
+
case graphql.Kind.OBJECT_TYPE_DEFINITION:
|
|
1870
|
+
return mergeObjectTypeDefinitionNodes(a, b);
|
|
1871
|
+
case graphql.Kind.INTERFACE_TYPE_DEFINITION:
|
|
1872
|
+
return mergeInterfaceTypeDefinitionNodes(a, b);
|
|
1873
|
+
case graphql.Kind.UNION_TYPE_DEFINITION:
|
|
1874
|
+
return mergeUnionTypeDefinitionNodes(a, b);
|
|
1875
|
+
case graphql.Kind.ENUM_TYPE_DEFINITION:
|
|
1876
|
+
return mergeEnumTypeDefinitionNodes(a, b);
|
|
1877
|
+
case graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION:
|
|
1878
|
+
return mergeInputObjectTypeDefinitionNodes(a, b);
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
function applyTypeExtensionNode(definitions, extension) {
|
|
1882
|
+
const name = extension.name.value;
|
|
1883
|
+
const definition = definitions[name];
|
|
1884
|
+
if (!definition) {
|
|
1885
|
+
throw setTraceToSchema(new graphql.GraphQLError(`Cannot extend type that is not defined: ${name}`), name, extension.loc);
|
|
1886
|
+
}
|
|
1887
|
+
const kind = EXTENSION_DEFINITION_KINDS[extension.kind];
|
|
1888
|
+
if (definition.kind !== kind) {
|
|
1889
|
+
throw setTraceToSchema(new graphql.GraphQLError(`Cannot extend ${definition.kind} with ${extension.kind}: ${name}`), name, extension.loc);
|
|
1890
|
+
}
|
|
1891
|
+
// An extension has the same shape as its definition, without a description.
|
|
1892
|
+
const merged = mergeTypeDefinitionNodes(definition, {
|
|
1893
|
+
...extension,
|
|
1894
|
+
kind,
|
|
1895
|
+
directives: undefined,
|
|
1896
|
+
});
|
|
1897
|
+
// The directives of an extension are added to the directives of the type.
|
|
1898
|
+
// buildASTSchema rejects a non-repeatable directive that occurs more than
|
|
1899
|
+
// once.
|
|
1900
|
+
definitions[name] = {
|
|
1901
|
+
...merged,
|
|
1902
|
+
directives: [
|
|
1903
|
+
...(definition.directives ?? []),
|
|
1904
|
+
...(extension.directives ?? []),
|
|
1905
|
+
],
|
|
1906
|
+
};
|
|
1907
|
+
}
|
|
1855
1908
|
function mergeDocumentNodes(documentNodes) {
|
|
1856
1909
|
const definitions = {};
|
|
1910
|
+
const extensions = [];
|
|
1857
1911
|
for (const documentNode of documentNodes) {
|
|
1858
1912
|
for (const definition of documentNode.definitions) {
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
case graphql.Kind.UNION_TYPE_EXTENSION:
|
|
1868
|
-
case graphql.Kind.ENUM_TYPE_EXTENSION:
|
|
1869
|
-
case graphql.Kind.INPUT_OBJECT_TYPE_EXTENSION:
|
|
1870
|
-
throw new Error(`unexpected definition kind: ${definition.kind}`);
|
|
1913
|
+
if (graphql.isTypeExtensionNode(definition)) {
|
|
1914
|
+
// Apply extensions after all definitions are known, because an
|
|
1915
|
+
// extension can occur before the definition that it extends.
|
|
1916
|
+
extensions.push(definition);
|
|
1917
|
+
continue;
|
|
1918
|
+
}
|
|
1919
|
+
if (!isMergableDefinitionNode(definition)) {
|
|
1920
|
+
throw new Error(`unexpected definition kind: ${definition.kind}`);
|
|
1871
1921
|
}
|
|
1872
1922
|
const prevDefinition = definitions[definition.name.value];
|
|
1873
1923
|
if (!prevDefinition) {
|
|
@@ -1885,30 +1935,12 @@ function mergeDocumentNodes(documentNodes) {
|
|
|
1885
1935
|
prevDefinition.description.value !== definition.description.value) {
|
|
1886
1936
|
console.warn(`WARNING: different descriptions for type ${prevDefinition.name.value}: ${JSON.stringify(prevDefinition.description.value)} and ${JSON.stringify(definition.description.value)}${traceLine(definition.description.loc)}${traceLine(prevDefinition.description.loc, "previously ")}\n`);
|
|
1887
1937
|
}
|
|
1888
|
-
|
|
1889
|
-
case graphql.Kind.SCALAR_TYPE_DEFINITION:
|
|
1890
|
-
definitions[definition.name.value] = mergeScalarTypeDefinitionNodes(prevDefinition, definition);
|
|
1891
|
-
break;
|
|
1892
|
-
case graphql.Kind.OBJECT_TYPE_DEFINITION:
|
|
1893
|
-
definitions[definition.name.value] = mergeObjectTypeDefinitionNodes(prevDefinition, definition);
|
|
1894
|
-
break;
|
|
1895
|
-
case graphql.Kind.INTERFACE_TYPE_DEFINITION:
|
|
1896
|
-
definitions[definition.name.value] =
|
|
1897
|
-
mergeInterfaceTypeDefinitionNodes(prevDefinition, definition);
|
|
1898
|
-
break;
|
|
1899
|
-
case graphql.Kind.UNION_TYPE_DEFINITION:
|
|
1900
|
-
definitions[definition.name.value] = mergeUnionTypeDefinitionNodes(prevDefinition, definition);
|
|
1901
|
-
break;
|
|
1902
|
-
case graphql.Kind.ENUM_TYPE_DEFINITION:
|
|
1903
|
-
definitions[definition.name.value] = mergeEnumTypeDefinitionNodes(prevDefinition, definition);
|
|
1904
|
-
break;
|
|
1905
|
-
case graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION:
|
|
1906
|
-
definitions[definition.name.value] =
|
|
1907
|
-
mergeInputObjectTypeDefinitionNodes(prevDefinition, definition);
|
|
1908
|
-
break;
|
|
1909
|
-
}
|
|
1938
|
+
definitions[definition.name.value] = mergeTypeDefinitionNodes(prevDefinition, definition);
|
|
1910
1939
|
}
|
|
1911
1940
|
}
|
|
1941
|
+
for (const extension of extensions) {
|
|
1942
|
+
applyTypeExtensionNode(definitions, extension);
|
|
1943
|
+
}
|
|
1912
1944
|
return {
|
|
1913
1945
|
kind: graphql.Kind.DOCUMENT,
|
|
1914
1946
|
loc: documentNodes[0].loc,
|
package/build/lib.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import path, { resolve, basename, extname, join } from 'path';
|
|
2
|
-
import { pathToFileURL, fileURLToPath } from 'url';
|
|
3
|
-
import { GraphQLNonNull, GraphQLList, GraphQLScalarType, GraphQLEnumType, GraphQLDirective, Kind, GraphQLObjectType, getNamedType, getNullableType, GraphQLInterfaceType, GraphQLUnionType, GraphQLInputObjectType, DirectiveLocation, GraphQLError, parse as parse$3, Source, buildASTSchema, validateSchema } from 'graphql';
|
|
1
|
+
import path, { resolve, basename, extname, join } from 'node:path';
|
|
2
|
+
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
3
|
+
import { GraphQLNonNull, GraphQLList, GraphQLScalarType, GraphQLEnumType, GraphQLDirective, Kind, GraphQLObjectType, getNamedType, getNullableType, GraphQLInterfaceType, GraphQLUnionType, GraphQLInputObjectType, DirectiveLocation, specifiedDirectives, isTypeExtensionNode, GraphQLError, isTypeDefinitionNode, parse as parse$3, Source, buildASTSchema, validateSchema } from 'graphql';
|
|
4
4
|
import jen$1, { jen } from 'jennifer-js';
|
|
5
5
|
import format from 'jennifer-js/format';
|
|
6
6
|
import partition from 'just-partition';
|
|
7
7
|
import pascalCase from 'just-pascal-case';
|
|
8
|
-
import fs from 'fs/promises';
|
|
8
|
+
import fs from 'node:fs/promises';
|
|
9
9
|
import ts, { getLineAndCharacterOfPosition } from 'typescript';
|
|
10
10
|
import { globIterate } from 'glob';
|
|
11
11
|
import pm from 'picomatch';
|
|
@@ -338,14 +338,8 @@ function renderAstNode(astNode) {
|
|
|
338
338
|
}
|
|
339
339
|
function isBuiltInDirective(name) {
|
|
340
340
|
// https://spec.graphql.org/draft/#sec-Type-System.Directives.Built-in-Directives
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
case "skip":
|
|
344
|
-
case "include":
|
|
345
|
-
case "specifiedBy":
|
|
346
|
-
return true;
|
|
347
|
-
}
|
|
348
|
-
return false;
|
|
341
|
+
// Use the list from graphql, because new versions add directives (for example, @oneOf).
|
|
342
|
+
return specifiedDirectives.some((d) => d.name === name);
|
|
349
343
|
}
|
|
350
344
|
function truthify(arr) {
|
|
351
345
|
return arr.filter(Boolean);
|
|
@@ -369,7 +363,8 @@ class GeneratorContext {
|
|
|
369
363
|
this._graphqlModuleSpecifier = options.graphqlModuleSpecifier ?? "graphql";
|
|
370
364
|
this._pkgs = new RequiredPackages();
|
|
371
365
|
this._extMode = options.extMode ?? "omit";
|
|
372
|
-
this._includeSubscriptionFieldResolvers =
|
|
366
|
+
this._includeSubscriptionFieldResolvers =
|
|
367
|
+
options.includeSubscriptionFieldResolvers ?? false;
|
|
373
368
|
}
|
|
374
369
|
_gql(name) {
|
|
375
370
|
return jen$1.id(this._pkgs.addRequires(this._graphqlModuleSpecifier, name));
|
|
@@ -601,7 +596,8 @@ class GeneratorContext {
|
|
|
601
596
|
const typeInterfaces = type.getInterfaces();
|
|
602
597
|
return jen$1.new
|
|
603
598
|
.add(this._gql("GraphQLObjectType"))
|
|
604
|
-
.call(jen$1.obj(jen$1.prop("name", jen$1.lit(type.name)), jen$1.prop("fields", this._renderFieldsThunk(type, inputFieldDirectives, includeAstNodes, !this._includeSubscriptionFieldResolvers &&
|
|
599
|
+
.call(jen$1.obj(jen$1.prop("name", jen$1.lit(type.name)), jen$1.prop("fields", this._renderFieldsThunk(type, inputFieldDirectives, includeAstNodes, !this._includeSubscriptionFieldResolvers &&
|
|
600
|
+
type.name === "Subscription")), ...truthify([
|
|
605
601
|
type.description &&
|
|
606
602
|
jen$1.prop("description", jen$1.lit(type.description)),
|
|
607
603
|
typeInterfaces.length &&
|
|
@@ -863,22 +859,22 @@ class GeneratorContext {
|
|
|
863
859
|
}
|
|
864
860
|
_getGraphQLTypeClass(type) {
|
|
865
861
|
if (type instanceof GraphQLObjectType) {
|
|
866
|
-
return
|
|
862
|
+
return "GraphQLObjectType";
|
|
867
863
|
}
|
|
868
864
|
if (type instanceof GraphQLScalarType) {
|
|
869
|
-
return
|
|
865
|
+
return "GraphQLScalarType";
|
|
870
866
|
}
|
|
871
867
|
if (type instanceof GraphQLInterfaceType) {
|
|
872
|
-
return
|
|
868
|
+
return "GraphQLInterfaceType";
|
|
873
869
|
}
|
|
874
870
|
if (type instanceof GraphQLUnionType) {
|
|
875
|
-
return
|
|
871
|
+
return "GraphQLUnionType";
|
|
876
872
|
}
|
|
877
873
|
if (type instanceof GraphQLInputObjectType) {
|
|
878
|
-
return
|
|
874
|
+
return "GraphQLInputObjectType";
|
|
879
875
|
}
|
|
880
876
|
if (type instanceof GraphQLEnumType) {
|
|
881
|
-
return
|
|
877
|
+
return "GraphQLEnumType";
|
|
882
878
|
}
|
|
883
879
|
throw new Error(`unhandled type: ${type.toString()}`);
|
|
884
880
|
}
|
|
@@ -1609,6 +1605,9 @@ function setTraceToSchema(err, name, loc) {
|
|
|
1609
1605
|
}
|
|
1610
1606
|
return err;
|
|
1611
1607
|
}
|
|
1608
|
+
function isMergableDefinitionNode(node) {
|
|
1609
|
+
return isTypeDefinitionNode(node) || node.kind === Kind.DIRECTIVE_DEFINITION;
|
|
1610
|
+
}
|
|
1612
1611
|
function namedNodesDict(nodes = []) {
|
|
1613
1612
|
return Object.fromEntries(nodes.map((node) => [node.name.value, node]));
|
|
1614
1613
|
}
|
|
@@ -1722,7 +1721,7 @@ function mergeFieldDefinitionNodes(name, a, b) {
|
|
|
1722
1721
|
console.warn(`WARNING: there is more than one declaration for ${name}.${f.name.value}${traceLine(f.loc)}${traceLine(prev.loc, "previously ")}\n`);
|
|
1723
1722
|
fields[f.name.value] = {
|
|
1724
1723
|
...prev,
|
|
1725
|
-
directives: mergeDirectiveNodes(
|
|
1724
|
+
directives: mergeDirectiveNodes(prev.directives, f.directives),
|
|
1726
1725
|
};
|
|
1727
1726
|
}
|
|
1728
1727
|
else {
|
|
@@ -1747,7 +1746,7 @@ function mergeInputValueDefinitionNodes(name, a, b) {
|
|
|
1747
1746
|
console.warn(`WARNING: there is more than one declaration for ${name}.${f.name.value}${traceLine(f.loc)}${traceLine(prev.loc, "previously ")}\n`);
|
|
1748
1747
|
fields[f.name.value] = {
|
|
1749
1748
|
...prev,
|
|
1750
|
-
directives: mergeDirectiveNodes(
|
|
1749
|
+
directives: mergeDirectiveNodes(prev.directives, f.directives),
|
|
1751
1750
|
};
|
|
1752
1751
|
}
|
|
1753
1752
|
else {
|
|
@@ -1766,18 +1765,19 @@ function mergeNamedNodes(a, b) {
|
|
|
1766
1765
|
}
|
|
1767
1766
|
return Object.values(nodes);
|
|
1768
1767
|
}
|
|
1769
|
-
function mergeDirectiveNodes(
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1768
|
+
function mergeDirectiveNodes(a, b) {
|
|
1769
|
+
// Keep each occurrence, because a repeatable directive can occur more than
|
|
1770
|
+
// once. Skip only an occurrence that is identical to one that is already
|
|
1771
|
+
// applied. buildASTSchema rejects a non-repeatable directive that occurs
|
|
1772
|
+
// more than once.
|
|
1773
|
+
const directives = Array.from(a ?? []);
|
|
1774
|
+
for (const d of b ?? []) {
|
|
1775
|
+
if (!directives.some((prev) => prev.name.value === d.name.value &&
|
|
1776
|
+
isArgumentNodesEqual(prev.arguments, d.arguments))) {
|
|
1777
|
+
directives.push(d);
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
return directives;
|
|
1781
1781
|
}
|
|
1782
1782
|
function mergeScalarTypeDefinitionNodes(a, b) {
|
|
1783
1783
|
if (a.name.value !== b.name.value) {
|
|
@@ -1785,8 +1785,10 @@ function mergeScalarTypeDefinitionNodes(a, b) {
|
|
|
1785
1785
|
}
|
|
1786
1786
|
return {
|
|
1787
1787
|
kind: Kind.SCALAR_TYPE_DEFINITION,
|
|
1788
|
+
loc: a.loc,
|
|
1788
1789
|
name: a.name,
|
|
1789
|
-
|
|
1790
|
+
description: a.description || b.description,
|
|
1791
|
+
directives: mergeDirectiveNodes(a.directives, b.directives),
|
|
1790
1792
|
};
|
|
1791
1793
|
}
|
|
1792
1794
|
function mergeObjectTypeDefinitionNodes(a, b) {
|
|
@@ -1796,7 +1798,7 @@ function mergeObjectTypeDefinitionNodes(a, b) {
|
|
|
1796
1798
|
name: a.name,
|
|
1797
1799
|
description: a.description || b.description,
|
|
1798
1800
|
interfaces: mergeNamedNodes(a.interfaces, b.interfaces),
|
|
1799
|
-
directives: mergeDirectiveNodes(a.
|
|
1801
|
+
directives: mergeDirectiveNodes(a.directives, b.directives),
|
|
1800
1802
|
fields: mergeFieldDefinitionNodes(a.name.value, a.fields, b.fields),
|
|
1801
1803
|
};
|
|
1802
1804
|
}
|
|
@@ -1807,7 +1809,7 @@ function mergeInterfaceTypeDefinitionNodes(a, b) {
|
|
|
1807
1809
|
name: a.name,
|
|
1808
1810
|
description: a.description || b.description,
|
|
1809
1811
|
interfaces: mergeNamedNodes(a.interfaces, b.interfaces),
|
|
1810
|
-
directives: mergeDirectiveNodes(a.
|
|
1812
|
+
directives: mergeDirectiveNodes(a.directives, b.directives),
|
|
1811
1813
|
fields: mergeFieldDefinitionNodes(a.name.value, a.fields, b.fields),
|
|
1812
1814
|
};
|
|
1813
1815
|
}
|
|
@@ -1817,7 +1819,7 @@ function mergeUnionTypeDefinitionNodes(a, b) {
|
|
|
1817
1819
|
loc: a.loc,
|
|
1818
1820
|
name: a.name,
|
|
1819
1821
|
description: a.description || b.description,
|
|
1820
|
-
directives: mergeDirectiveNodes(a.
|
|
1822
|
+
directives: mergeDirectiveNodes(a.directives, b.directives),
|
|
1821
1823
|
types: mergeNamedNodes(a.types, b.types),
|
|
1822
1824
|
};
|
|
1823
1825
|
}
|
|
@@ -1826,7 +1828,7 @@ function mergeEnumTypeDefinitionNodes(a, b) {
|
|
|
1826
1828
|
if (b) {
|
|
1827
1829
|
for (const v of b.values || []) {
|
|
1828
1830
|
if (v.name.value in values) {
|
|
1829
|
-
throw setTraceToSchema(new GraphQLError(`Cannot merge duplicate enum value: ${
|
|
1831
|
+
throw setTraceToSchema(new GraphQLError(`Cannot merge duplicate enum value: ${a.name.value}.${v.name.value}`), `${a.name.value}.${v.name.value}`, v.loc);
|
|
1830
1832
|
}
|
|
1831
1833
|
values[v.name.value] = v;
|
|
1832
1834
|
}
|
|
@@ -1836,7 +1838,7 @@ function mergeEnumTypeDefinitionNodes(a, b) {
|
|
|
1836
1838
|
loc: a.loc,
|
|
1837
1839
|
name: a.name,
|
|
1838
1840
|
description: a.description || b.description,
|
|
1839
|
-
directives: mergeDirectiveNodes(a.
|
|
1841
|
+
directives: mergeDirectiveNodes(a.directives, b.directives),
|
|
1840
1842
|
values: Object.values(values),
|
|
1841
1843
|
};
|
|
1842
1844
|
}
|
|
@@ -1846,26 +1848,74 @@ function mergeInputObjectTypeDefinitionNodes(a, b) {
|
|
|
1846
1848
|
loc: a.loc,
|
|
1847
1849
|
name: a.name,
|
|
1848
1850
|
description: a.description || b.description,
|
|
1849
|
-
directives: mergeDirectiveNodes(a.
|
|
1851
|
+
directives: mergeDirectiveNodes(a.directives, b.directives),
|
|
1850
1852
|
fields: mergeInputValueDefinitionNodes(a.name.value, a.fields, b.fields),
|
|
1851
1853
|
};
|
|
1852
1854
|
}
|
|
1855
|
+
const EXTENSION_DEFINITION_KINDS = {
|
|
1856
|
+
[Kind.SCALAR_TYPE_EXTENSION]: Kind.SCALAR_TYPE_DEFINITION,
|
|
1857
|
+
[Kind.OBJECT_TYPE_EXTENSION]: Kind.OBJECT_TYPE_DEFINITION,
|
|
1858
|
+
[Kind.INTERFACE_TYPE_EXTENSION]: Kind.INTERFACE_TYPE_DEFINITION,
|
|
1859
|
+
[Kind.UNION_TYPE_EXTENSION]: Kind.UNION_TYPE_DEFINITION,
|
|
1860
|
+
[Kind.ENUM_TYPE_EXTENSION]: Kind.ENUM_TYPE_DEFINITION,
|
|
1861
|
+
[Kind.INPUT_OBJECT_TYPE_EXTENSION]: Kind.INPUT_OBJECT_TYPE_DEFINITION,
|
|
1862
|
+
};
|
|
1863
|
+
function mergeTypeDefinitionNodes(a, b) {
|
|
1864
|
+
switch (b.kind) {
|
|
1865
|
+
case Kind.SCALAR_TYPE_DEFINITION:
|
|
1866
|
+
return mergeScalarTypeDefinitionNodes(a, b);
|
|
1867
|
+
case Kind.OBJECT_TYPE_DEFINITION:
|
|
1868
|
+
return mergeObjectTypeDefinitionNodes(a, b);
|
|
1869
|
+
case Kind.INTERFACE_TYPE_DEFINITION:
|
|
1870
|
+
return mergeInterfaceTypeDefinitionNodes(a, b);
|
|
1871
|
+
case Kind.UNION_TYPE_DEFINITION:
|
|
1872
|
+
return mergeUnionTypeDefinitionNodes(a, b);
|
|
1873
|
+
case Kind.ENUM_TYPE_DEFINITION:
|
|
1874
|
+
return mergeEnumTypeDefinitionNodes(a, b);
|
|
1875
|
+
case Kind.INPUT_OBJECT_TYPE_DEFINITION:
|
|
1876
|
+
return mergeInputObjectTypeDefinitionNodes(a, b);
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
function applyTypeExtensionNode(definitions, extension) {
|
|
1880
|
+
const name = extension.name.value;
|
|
1881
|
+
const definition = definitions[name];
|
|
1882
|
+
if (!definition) {
|
|
1883
|
+
throw setTraceToSchema(new GraphQLError(`Cannot extend type that is not defined: ${name}`), name, extension.loc);
|
|
1884
|
+
}
|
|
1885
|
+
const kind = EXTENSION_DEFINITION_KINDS[extension.kind];
|
|
1886
|
+
if (definition.kind !== kind) {
|
|
1887
|
+
throw setTraceToSchema(new GraphQLError(`Cannot extend ${definition.kind} with ${extension.kind}: ${name}`), name, extension.loc);
|
|
1888
|
+
}
|
|
1889
|
+
// An extension has the same shape as its definition, without a description.
|
|
1890
|
+
const merged = mergeTypeDefinitionNodes(definition, {
|
|
1891
|
+
...extension,
|
|
1892
|
+
kind,
|
|
1893
|
+
directives: undefined,
|
|
1894
|
+
});
|
|
1895
|
+
// The directives of an extension are added to the directives of the type.
|
|
1896
|
+
// buildASTSchema rejects a non-repeatable directive that occurs more than
|
|
1897
|
+
// once.
|
|
1898
|
+
definitions[name] = {
|
|
1899
|
+
...merged,
|
|
1900
|
+
directives: [
|
|
1901
|
+
...(definition.directives ?? []),
|
|
1902
|
+
...(extension.directives ?? []),
|
|
1903
|
+
],
|
|
1904
|
+
};
|
|
1905
|
+
}
|
|
1853
1906
|
function mergeDocumentNodes(documentNodes) {
|
|
1854
1907
|
const definitions = {};
|
|
1908
|
+
const extensions = [];
|
|
1855
1909
|
for (const documentNode of documentNodes) {
|
|
1856
1910
|
for (const definition of documentNode.definitions) {
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
case Kind.UNION_TYPE_EXTENSION:
|
|
1866
|
-
case Kind.ENUM_TYPE_EXTENSION:
|
|
1867
|
-
case Kind.INPUT_OBJECT_TYPE_EXTENSION:
|
|
1868
|
-
throw new Error(`unexpected definition kind: ${definition.kind}`);
|
|
1911
|
+
if (isTypeExtensionNode(definition)) {
|
|
1912
|
+
// Apply extensions after all definitions are known, because an
|
|
1913
|
+
// extension can occur before the definition that it extends.
|
|
1914
|
+
extensions.push(definition);
|
|
1915
|
+
continue;
|
|
1916
|
+
}
|
|
1917
|
+
if (!isMergableDefinitionNode(definition)) {
|
|
1918
|
+
throw new Error(`unexpected definition kind: ${definition.kind}`);
|
|
1869
1919
|
}
|
|
1870
1920
|
const prevDefinition = definitions[definition.name.value];
|
|
1871
1921
|
if (!prevDefinition) {
|
|
@@ -1883,30 +1933,12 @@ function mergeDocumentNodes(documentNodes) {
|
|
|
1883
1933
|
prevDefinition.description.value !== definition.description.value) {
|
|
1884
1934
|
console.warn(`WARNING: different descriptions for type ${prevDefinition.name.value}: ${JSON.stringify(prevDefinition.description.value)} and ${JSON.stringify(definition.description.value)}${traceLine(definition.description.loc)}${traceLine(prevDefinition.description.loc, "previously ")}\n`);
|
|
1885
1935
|
}
|
|
1886
|
-
|
|
1887
|
-
case Kind.SCALAR_TYPE_DEFINITION:
|
|
1888
|
-
definitions[definition.name.value] = mergeScalarTypeDefinitionNodes(prevDefinition, definition);
|
|
1889
|
-
break;
|
|
1890
|
-
case Kind.OBJECT_TYPE_DEFINITION:
|
|
1891
|
-
definitions[definition.name.value] = mergeObjectTypeDefinitionNodes(prevDefinition, definition);
|
|
1892
|
-
break;
|
|
1893
|
-
case Kind.INTERFACE_TYPE_DEFINITION:
|
|
1894
|
-
definitions[definition.name.value] =
|
|
1895
|
-
mergeInterfaceTypeDefinitionNodes(prevDefinition, definition);
|
|
1896
|
-
break;
|
|
1897
|
-
case Kind.UNION_TYPE_DEFINITION:
|
|
1898
|
-
definitions[definition.name.value] = mergeUnionTypeDefinitionNodes(prevDefinition, definition);
|
|
1899
|
-
break;
|
|
1900
|
-
case Kind.ENUM_TYPE_DEFINITION:
|
|
1901
|
-
definitions[definition.name.value] = mergeEnumTypeDefinitionNodes(prevDefinition, definition);
|
|
1902
|
-
break;
|
|
1903
|
-
case Kind.INPUT_OBJECT_TYPE_DEFINITION:
|
|
1904
|
-
definitions[definition.name.value] =
|
|
1905
|
-
mergeInputObjectTypeDefinitionNodes(prevDefinition, definition);
|
|
1906
|
-
break;
|
|
1907
|
-
}
|
|
1936
|
+
definitions[definition.name.value] = mergeTypeDefinitionNodes(prevDefinition, definition);
|
|
1908
1937
|
}
|
|
1909
1938
|
}
|
|
1939
|
+
for (const extension of extensions) {
|
|
1940
|
+
applyTypeExtensionNode(definitions, extension);
|
|
1941
|
+
}
|
|
1910
1942
|
return {
|
|
1911
1943
|
kind: Kind.DOCUMENT,
|
|
1912
1944
|
loc: documentNodes[0].loc,
|
package/package.json
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
2
|
+
"name": "graphql-jerky",
|
|
3
|
+
"version": "1.0.9",
|
|
4
|
+
"description": "Jerky is a schema-first static graphql schema lightweight code generator.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": "./build/bin/jerky.cjs",
|
|
7
|
+
"types": "./build/lib.d.ts",
|
|
8
|
+
"module": "./build/lib.mjs",
|
|
9
|
+
"main": "./build/lib.cjs",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "rollup -c",
|
|
12
|
+
"prepack": "npm run build"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"commander": "^10.0.1",
|
|
16
|
+
"glob": "^10.2.7",
|
|
17
|
+
"graphql": "^16.6.0",
|
|
18
|
+
"jennifer-js": "^1.0.0",
|
|
19
|
+
"just-partition": "^2.2.0",
|
|
20
|
+
"just-pascal-case": "^3.2.0",
|
|
21
|
+
"just-zip-it": "^3.2.0",
|
|
22
|
+
"picomatch": "^2.3.1",
|
|
23
|
+
"typescript": "^5.1.3"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@biomejs/biome": "^1.4.1",
|
|
27
|
+
"@rollup/plugin-typescript": "^11.1.1",
|
|
28
|
+
"@types/node": "^20.3.1",
|
|
29
|
+
"@types/picomatch": "^2.3.0",
|
|
30
|
+
"rollup": "^3.25.1",
|
|
31
|
+
"rollup-plugin-dts": "^5.3.0",
|
|
32
|
+
"tslib": "^2.5.3"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"build"
|
|
36
|
+
],
|
|
37
|
+
"license": "MIT"
|
|
38
38
|
}
|