graphile-export 0.0.2-beta.3 → 0.0.2-beta.31
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/CHANGELOG.md +591 -0
- package/README.md +5 -2
- package/dist/exportSchema.d.ts +7 -3
- package/dist/exportSchema.d.ts.map +1 -1
- package/dist/exportSchema.js +522 -177
- package/dist/exportSchema.js.map +1 -1
- package/dist/helpers.d.ts +4 -1
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +14 -3
- package/dist/helpers.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +10 -0
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/optimize/index.d.ts +1 -1
- package/dist/optimize/index.d.ts.map +1 -1
- package/dist/optimize/index.js +151 -25
- package/dist/optimize/index.js.map +1 -1
- package/dist/reservedWords.d.ts +2 -0
- package/dist/reservedWords.d.ts.map +1 -0
- package/dist/reservedWords.js +100 -0
- package/dist/reservedWords.js.map +1 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +15 -0
- package/dist/utils.js.map +1 -0
- package/dist/wellKnown.d.ts +0 -19
- package/dist/wellKnown.d.ts.map +1 -1
- package/dist/wellKnown.js +16 -15
- package/dist/wellKnown.js.map +1 -1
- package/package.json +23 -19
package/dist/exportSchema.js
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.canRepresentAsIdentifier = void 0;
|
|
4
|
+
exports.objectNullPrototype = objectNullPrototype;
|
|
5
|
+
exports.exportSchemaAsString = exportSchemaAsString;
|
|
6
|
+
exports.exportValueAsString = exportValueAsString;
|
|
7
|
+
exports.exportSchema = exportSchema;
|
|
4
8
|
const tslib_1 = require("tslib");
|
|
5
9
|
const promises_1 = require("node:fs/promises");
|
|
6
10
|
const node_util_1 = require("node:util");
|
|
7
11
|
const generator_1 = tslib_1.__importDefault(require("@babel/generator"));
|
|
8
12
|
const parser_1 = require("@babel/parser");
|
|
9
13
|
const template_1 = tslib_1.__importDefault(require("@babel/template"));
|
|
14
|
+
const traverse_1 = tslib_1.__importDefault(require("@babel/traverse"));
|
|
10
15
|
const t = tslib_1.__importStar(require("@babel/types"));
|
|
11
16
|
const graphql_1 = require("grafast/graphql");
|
|
17
|
+
const helpers_js_1 = require("./helpers.js");
|
|
12
18
|
const index_js_1 = require("./optimize/index.js");
|
|
19
|
+
const reservedWords_js_1 = require("./reservedWords.js");
|
|
20
|
+
const utils_js_1 = require("./utils.js");
|
|
13
21
|
const wellKnown_js_1 = require("./wellKnown.js");
|
|
14
22
|
// Cannot import sql because it's optional
|
|
15
23
|
// import { sql } from "pg-sql2";
|
|
@@ -27,7 +35,7 @@ function isSQL(thing) {
|
|
|
27
35
|
else {
|
|
28
36
|
// An approximation
|
|
29
37
|
if (typeof sql === "object" && sql !== null) {
|
|
30
|
-
return Object.getOwnPropertySymbols(thing).some((s) => s.description
|
|
38
|
+
return Object.getOwnPropertySymbols(thing).some((s) => s.description?.startsWith("pg-sql2-type"));
|
|
31
39
|
}
|
|
32
40
|
else {
|
|
33
41
|
return false;
|
|
@@ -48,6 +56,14 @@ function identifierOrLiteral(key) {
|
|
|
48
56
|
return t.stringLiteral(key);
|
|
49
57
|
}
|
|
50
58
|
}
|
|
59
|
+
function literal(key) {
|
|
60
|
+
if (typeof key === "number") {
|
|
61
|
+
return t.numericLiteral(key);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
return t.stringLiteral(key);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
51
67
|
function locationHintToIdentifierName(locationHint) {
|
|
52
68
|
let result = locationHint;
|
|
53
69
|
result = result.replace(/[[.]/g, "__").replace(/\]/g, "");
|
|
@@ -59,7 +75,10 @@ function locationHintToIdentifierName(locationHint) {
|
|
|
59
75
|
return result;
|
|
60
76
|
}
|
|
61
77
|
function getNameForThing(thing, locationHint, baseNameHint) {
|
|
62
|
-
if (
|
|
78
|
+
if (thing.$exporter$name) {
|
|
79
|
+
return thing.$exporter$name;
|
|
80
|
+
}
|
|
81
|
+
else if (typeof thing === "function") {
|
|
63
82
|
if (baseNameHint) {
|
|
64
83
|
return baseNameHint;
|
|
65
84
|
}
|
|
@@ -71,14 +90,17 @@ function getNameForThing(thing, locationHint, baseNameHint) {
|
|
|
71
90
|
}
|
|
72
91
|
else {
|
|
73
92
|
const thingConstructor = thing.constructor;
|
|
74
|
-
const thingConstructorNameRaw = thingConstructor
|
|
93
|
+
const thingConstructorNameRaw = thingConstructor?.$exporter$name ??
|
|
94
|
+
thingConstructor?.name ??
|
|
95
|
+
thingConstructor?.displayName ??
|
|
96
|
+
null;
|
|
75
97
|
const thingConstructorName = ["Array", "Object", "Set", "Map"].includes(thingConstructorNameRaw)
|
|
76
98
|
? null
|
|
77
99
|
: thingConstructorNameRaw;
|
|
78
100
|
const thingName = thing.name ?? thing.displayName ?? null;
|
|
79
101
|
const name = thingConstructorName && thingName
|
|
80
102
|
? `${thingName}${thingConstructorName}`
|
|
81
|
-
: thingName ?? thingConstructorName ?? null;
|
|
103
|
+
: (thingName ?? thingConstructorName ?? null);
|
|
82
104
|
return baseNameHint || name
|
|
83
105
|
? (baseNameHint ?? "") + (baseNameHint && name ? "-" : "") + (name ?? "")
|
|
84
106
|
: "value";
|
|
@@ -102,15 +124,6 @@ const reallyGenerate = generator_1.default;
|
|
|
102
124
|
const templateOptions = {
|
|
103
125
|
plugins: ["typescript"],
|
|
104
126
|
};
|
|
105
|
-
function isNotNullish(input) {
|
|
106
|
-
return input != null;
|
|
107
|
-
}
|
|
108
|
-
exports.isNotNullish = isNotNullish;
|
|
109
|
-
function isImportable(thing) {
|
|
110
|
-
return ((typeof thing === "object" || typeof thing === "function") &&
|
|
111
|
-
thing !== null &&
|
|
112
|
-
"$$export" in thing);
|
|
113
|
-
}
|
|
114
127
|
function isExportedFromFactory(thing) {
|
|
115
128
|
return ((typeof thing === "object" || typeof thing === "function") &&
|
|
116
129
|
thing !== null &&
|
|
@@ -120,54 +133,60 @@ const BUILTINS = ["Int", "Float", "Boolean", "ID", "String"];
|
|
|
120
133
|
function isBuiltinType(type) {
|
|
121
134
|
return type.name.startsWith("__") || BUILTINS.includes(type.name);
|
|
122
135
|
}
|
|
136
|
+
const RESERVED_VARIABLES = {
|
|
137
|
+
// Reserved variables
|
|
138
|
+
AbortController: true,
|
|
139
|
+
Array: true,
|
|
140
|
+
Buffer: true,
|
|
141
|
+
DOMException: true,
|
|
142
|
+
Error: true,
|
|
143
|
+
Event: true,
|
|
144
|
+
EventTarget: true,
|
|
145
|
+
JSON: true,
|
|
146
|
+
Math: true,
|
|
147
|
+
MessageChannel: true,
|
|
148
|
+
MessageEvent: true,
|
|
149
|
+
MessagePort: true,
|
|
150
|
+
Object: true,
|
|
151
|
+
TextDecoder: true,
|
|
152
|
+
TextEncoder: true,
|
|
153
|
+
URL: true,
|
|
154
|
+
URLSearchParams: true,
|
|
155
|
+
WebAssembly: true,
|
|
156
|
+
__dirname: true,
|
|
157
|
+
__filename: true,
|
|
158
|
+
atob: true,
|
|
159
|
+
btoa: true,
|
|
160
|
+
clearImmediate: true,
|
|
161
|
+
clearInterval: true,
|
|
162
|
+
clearTimeout: true,
|
|
163
|
+
console: true,
|
|
164
|
+
exports: true,
|
|
165
|
+
global: true,
|
|
166
|
+
module: true,
|
|
167
|
+
performance: true,
|
|
168
|
+
process: true,
|
|
169
|
+
queueMicrotask: true,
|
|
170
|
+
require: true,
|
|
171
|
+
setImmediate: true,
|
|
172
|
+
setInterval: true,
|
|
173
|
+
setTimeout: true,
|
|
174
|
+
structuredClone: true,
|
|
175
|
+
};
|
|
176
|
+
for (const reservedWord of reservedWords_js_1.reservedWords) {
|
|
177
|
+
RESERVED_VARIABLES[reservedWord] = true;
|
|
178
|
+
}
|
|
179
|
+
Object.freeze(RESERVED_VARIABLES);
|
|
123
180
|
class CodegenFile {
|
|
124
181
|
constructor(options) {
|
|
125
182
|
this.options = options;
|
|
126
|
-
this._variables = Object.assign(Object.create(null),
|
|
127
|
-
// Reserved variables
|
|
128
|
-
AbortController: true,
|
|
129
|
-
Array: true,
|
|
130
|
-
Buffer: true,
|
|
131
|
-
DOMException: true,
|
|
132
|
-
Error: true,
|
|
133
|
-
Event: true,
|
|
134
|
-
EventTarget: true,
|
|
135
|
-
JSON: true,
|
|
136
|
-
Math: true,
|
|
137
|
-
MessageChannel: true,
|
|
138
|
-
MessageEvent: true,
|
|
139
|
-
MessagePort: true,
|
|
140
|
-
Object: true,
|
|
141
|
-
TextDecoder: true,
|
|
142
|
-
TextEncoder: true,
|
|
143
|
-
URL: true,
|
|
144
|
-
URLSearchParams: true,
|
|
145
|
-
WebAssembly: true,
|
|
146
|
-
__dirname: true,
|
|
147
|
-
__filename: true,
|
|
148
|
-
atob: true,
|
|
149
|
-
btoa: true,
|
|
150
|
-
clearImmediate: true,
|
|
151
|
-
clearInterval: true,
|
|
152
|
-
clearTimeout: true,
|
|
153
|
-
console: true,
|
|
154
|
-
exports: true,
|
|
155
|
-
global: true,
|
|
156
|
-
module: true,
|
|
157
|
-
performance: true,
|
|
158
|
-
process: true,
|
|
159
|
-
queueMicrotask: true,
|
|
160
|
-
require: true,
|
|
161
|
-
setImmediate: true,
|
|
162
|
-
setInterval: true,
|
|
163
|
-
setTimeout: true,
|
|
164
|
-
structuredClone: true,
|
|
165
|
-
});
|
|
183
|
+
this._variables = Object.assign(Object.create(null), RESERVED_VARIABLES);
|
|
166
184
|
this._imports = Object.create(null);
|
|
167
185
|
this._types = Object.create(null);
|
|
168
186
|
this._directives = Object.create(null);
|
|
169
187
|
this._statements = [];
|
|
170
188
|
this._values = new Map();
|
|
189
|
+
this._funcToAstCache = new Map();
|
|
171
190
|
}
|
|
172
191
|
addStatements(statements) {
|
|
173
192
|
if (Array.isArray(statements)) {
|
|
@@ -431,6 +450,9 @@ class CodegenFile {
|
|
|
431
450
|
name: t.stringLiteral(config.name),
|
|
432
451
|
description: desc(config.description),
|
|
433
452
|
extensions: extensions(this, config.extensions, `${config.name}.extensions`, `${config.name}.extensions`),
|
|
453
|
+
isOneOf: config.isOneOf
|
|
454
|
+
? t.booleanLiteral(true)
|
|
455
|
+
: t.identifier("undefined"),
|
|
434
456
|
fields: t.arrowFunctionExpression([], this.makeInputObjectFields(config.fields, config.name)),
|
|
435
457
|
});
|
|
436
458
|
}
|
|
@@ -534,6 +556,9 @@ function canBeRegularObjectKey(key) {
|
|
|
534
556
|
return key !== "__proto__";
|
|
535
557
|
}
|
|
536
558
|
function _convertToAST(file, thing, locationHint, nameHint, depth, reference) {
|
|
559
|
+
if ((0, helpers_js_1.isForbidden)(thing)) {
|
|
560
|
+
throw new Error(`The value at ${locationHint} is forbidden from being exported; please be more specific in your EXPORTABLE factories!`);
|
|
561
|
+
}
|
|
537
562
|
const handleSubvalue = (value, tKey, key) => {
|
|
538
563
|
const existingIdentifier = getExistingIdentifier(file, value);
|
|
539
564
|
if (existingIdentifier) {
|
|
@@ -566,22 +591,25 @@ function _convertToAST(file, thing, locationHint, nameHint, depth, reference) {
|
|
|
566
591
|
return func(file, thing, locationHint, nameHint);
|
|
567
592
|
}
|
|
568
593
|
else if ((0, graphql_1.isSchema)(thing)) {
|
|
569
|
-
throw new Error(
|
|
594
|
+
throw new Error(`Attempted to export GraphQLSchema directly from \`_convertToAST\` (at ${locationHint}); this is currently unsupported.`);
|
|
570
595
|
}
|
|
571
596
|
else if (typeof thing === "object" && thing != null) {
|
|
572
597
|
const prototype = Object.getPrototypeOf(thing);
|
|
573
598
|
if (prototype !== null && prototype !== Object.prototype) {
|
|
574
|
-
|
|
599
|
+
if (thing.constructor) {
|
|
600
|
+
throw new Error(`Attempting to export an instance of a class (at ${locationHint}); you should wrap this definition in EXPORTABLE! (Class: ${thing.constructor})`);
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
throw new Error(`Attempting to export non-POJO object (at ${locationHint}); you should wrap this definition in EXPORTABLE! (Prototype: ${(0, node_util_1.inspect)(prototype)})`);
|
|
604
|
+
}
|
|
575
605
|
}
|
|
576
606
|
const propertyPairs = [];
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
607
|
+
const entries = Object.entries(thing);
|
|
608
|
+
const hasUnsafeKeys = entries.some(([key]) => !canBeRegularObjectKey(key));
|
|
609
|
+
entries.forEach(([key, value]) => {
|
|
610
|
+
const tKey = hasUnsafeKeys ? literal(key) : identifierOrLiteral(key);
|
|
580
611
|
const subvalue = handleSubvalue(value, tKey, key);
|
|
581
612
|
propertyPairs.push([tKey, subvalue]);
|
|
582
|
-
if (!canBeRegularObjectKey(key)) {
|
|
583
|
-
hasUnsafeKeys = true;
|
|
584
|
-
}
|
|
585
613
|
});
|
|
586
614
|
if (prototype === null) {
|
|
587
615
|
if (hasUnsafeKeys) {
|
|
@@ -590,20 +618,14 @@ function _convertToAST(file, thing, locationHint, nameHint, depth, reference) {
|
|
|
590
618
|
t.arrayExpression(propertyPairs.map(([key, val]) => t.arrayExpression([key, val]))),
|
|
591
619
|
]);
|
|
592
620
|
}
|
|
593
|
-
else if (propertyPairs.length === 0) {
|
|
594
|
-
return t.callExpression(t.memberExpression(t.identifier("Object"), t.identifier("create")), [t.nullLiteral()]);
|
|
595
|
-
}
|
|
596
621
|
else {
|
|
597
|
-
const obj =
|
|
598
|
-
return
|
|
599
|
-
t.callExpression(t.memberExpression(t.identifier("Object"), t.identifier("create")), [t.nullLiteral()]),
|
|
600
|
-
obj,
|
|
601
|
-
]);
|
|
622
|
+
const obj = objectNullPrototype(propertyPairs.map(([key, val]) => t.objectProperty(key, val)));
|
|
623
|
+
return obj;
|
|
602
624
|
}
|
|
603
625
|
}
|
|
604
626
|
else {
|
|
605
627
|
if (hasUnsafeKeys) {
|
|
606
|
-
throw new Error(`Unexportable key found on non-null-prototype object`);
|
|
628
|
+
throw new Error(`Unexportable key found on non-null-prototype object (at ${locationHint})`);
|
|
607
629
|
}
|
|
608
630
|
else {
|
|
609
631
|
const obj = t.objectExpression(propertyPairs.map(([key, val]) => t.objectProperty(key, val)));
|
|
@@ -639,7 +661,7 @@ const getExistingIdentifier = (file, thing) => {
|
|
|
639
661
|
const { moduleName, exportName } = (0, wellKnown_js_1.wellKnown)(file.options, thing);
|
|
640
662
|
return file.import(moduleName, exportName);
|
|
641
663
|
}
|
|
642
|
-
else if (isImportable(thing)) {
|
|
664
|
+
else if ((0, utils_js_1.isImportable)(thing)) {
|
|
643
665
|
const { moduleName, exportName } = thing.$$export;
|
|
644
666
|
return file.import(moduleName, exportName);
|
|
645
667
|
}
|
|
@@ -650,6 +672,21 @@ const getExistingIdentifier = (file, thing) => {
|
|
|
650
672
|
return file.declareType(thing);
|
|
651
673
|
}
|
|
652
674
|
};
|
|
675
|
+
function importWellKnownOrFactory(file, value, locationHint, nameHint) {
|
|
676
|
+
if ((0, utils_js_1.isImportable)(value)) {
|
|
677
|
+
return file.import(value.$$export.moduleName, value.$$export.exportName);
|
|
678
|
+
}
|
|
679
|
+
else if ((0, wellKnown_js_1.wellKnown)(file.options, value)) {
|
|
680
|
+
const { moduleName, exportName } = (0, wellKnown_js_1.wellKnown)(file.options, value);
|
|
681
|
+
return file.import(moduleName, exportName);
|
|
682
|
+
}
|
|
683
|
+
else if (isExportedFromFactory(value)) {
|
|
684
|
+
return factoryAst(file, value, locationHint, nameHint);
|
|
685
|
+
}
|
|
686
|
+
else {
|
|
687
|
+
return undefined;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
653
690
|
function convertToIdentifierViaAST(file, thing, baseNameHint, locationHint, depth = 0) {
|
|
654
691
|
const existingIdentifier = getExistingIdentifier(file, thing);
|
|
655
692
|
if (existingIdentifier) {
|
|
@@ -659,9 +696,8 @@ function convertToIdentifierViaAST(file, thing, baseNameHint, locationHint, dept
|
|
|
659
696
|
const nameHint = getNameForThing(thing, locationHint, baseNameHint);
|
|
660
697
|
const variableIdentifier = file.makeVariable(nameHint || "value");
|
|
661
698
|
file._values.set(thing, variableIdentifier);
|
|
662
|
-
const ast =
|
|
663
|
-
|
|
664
|
-
: _convertToAST(file, thing, locationHint, nameHint, depth, variableIdentifier);
|
|
699
|
+
const ast = importWellKnownOrFactory(file, thing, locationHint, nameHint) ??
|
|
700
|
+
_convertToAST(file, thing, locationHint, nameHint, depth, variableIdentifier);
|
|
665
701
|
if (ast.type === "Identifier") {
|
|
666
702
|
console.warn(`graphile-export error: AST returned an identifier '${ast.name}'; this could cause an infinite loop.`);
|
|
667
703
|
}
|
|
@@ -679,20 +715,20 @@ function objectToObjectProperties(o) {
|
|
|
679
715
|
.map(([key, value]) => t.objectProperty(identifierOrLiteral(key), value));
|
|
680
716
|
}
|
|
681
717
|
function extensions(file, extensions, locationHint, nameHint) {
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
return convertToIdentifierViaAST(file, extensions, nameHint, locationHint);
|
|
718
|
+
return isNotEmpty(extensions)
|
|
719
|
+
? convertToIdentifierViaAST(file, extensions, nameHint, locationHint)
|
|
720
|
+
: null;
|
|
686
721
|
}
|
|
687
|
-
/**
|
|
722
|
+
/**
|
|
723
|
+
* Maps to `{__proto__: null, ...}` which is similar to
|
|
724
|
+
* `Object.assign(Object.create(null), {...})`
|
|
725
|
+
*/
|
|
688
726
|
function objectNullPrototype(properties) {
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
return t.callExpression(t.memberExpression(t.identifier("Object"), t.identifier("assign")), [objectCreateNull, t.objectExpression(properties)]);
|
|
727
|
+
return t.objectExpression([
|
|
728
|
+
t.objectProperty(t.identifier("__proto__"), t.nullLiteral()),
|
|
729
|
+
...properties,
|
|
730
|
+
]);
|
|
694
731
|
}
|
|
695
|
-
exports.objectNullPrototype = objectNullPrototype;
|
|
696
732
|
/*
|
|
697
733
|
function iife(statements: t.Statement[]): t.Expression {
|
|
698
734
|
return t.callExpression(
|
|
@@ -709,24 +745,13 @@ function func(file, fn, locationHint, nameHint) {
|
|
|
709
745
|
// scope; e.g.:
|
|
710
746
|
//
|
|
711
747
|
// `(() => { const foo = 1, bar = 2; return /*>*/() => {return foo+bar}/*<*/})();`
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
}
|
|
715
|
-
else if ((0, wellKnown_js_1.wellKnown)(file.options, fn)) {
|
|
716
|
-
const { moduleName, exportName } = (0, wellKnown_js_1.wellKnown)(file.options, fn);
|
|
717
|
-
return file.import(moduleName, exportName);
|
|
718
|
-
}
|
|
719
|
-
else if (isImportable(fn)) {
|
|
720
|
-
return file.import(fn.$$export.moduleName, fn.$$export.exportName);
|
|
721
|
-
}
|
|
722
|
-
else {
|
|
723
|
-
return funcToAst(fn, locationHint, nameHint);
|
|
724
|
-
}
|
|
748
|
+
return (importWellKnownOrFactory(file, fn, locationHint, nameHint) ??
|
|
749
|
+
funcToAst(file, fn, locationHint, nameHint).ast);
|
|
725
750
|
}
|
|
726
751
|
const shouldOptimizeFactoryCalls = true;
|
|
727
752
|
function factoryAst(file, fn, locationHint, nameHint) {
|
|
728
753
|
const factory = fn.$exporter$factory;
|
|
729
|
-
const funcAST = funcToAst(factory, locationHint, nameHint);
|
|
754
|
+
const { functionWithoutOwnAttributesAST: funcAST } = funcToAst(file, factory, locationHint, nameHint);
|
|
730
755
|
const depArgs = fn.$exporter$args.map((arg, i) => {
|
|
731
756
|
if (typeof arg === "string") {
|
|
732
757
|
return t.stringLiteral(arg);
|
|
@@ -778,13 +803,79 @@ function factoryAst(file, fn, locationHint, nameHint) {
|
|
|
778
803
|
return t.callExpression(funcAST, depArgs);
|
|
779
804
|
}
|
|
780
805
|
}
|
|
781
|
-
function funcToAst(fn, locationHint, _nameHint) {
|
|
806
|
+
function funcToAst(file, fn, locationHint, _nameHint) {
|
|
807
|
+
if (file._funcToAstCache.has(fn)) {
|
|
808
|
+
return file._funcToAstCache.get(fn);
|
|
809
|
+
}
|
|
810
|
+
const path = _funcToAst(fn, locationHint, _nameHint);
|
|
811
|
+
const externalReferences = new Set();
|
|
812
|
+
const localBindings = path.scope.bindings;
|
|
813
|
+
path.traverse({
|
|
814
|
+
Identifier(path) {
|
|
815
|
+
if (t.isReferenced(path.node, path.parent) && // Is a variable reference
|
|
816
|
+
!path.scope.hasBinding(path.node.name) && // Not defined in local scope
|
|
817
|
+
!localBindings[path.node.name] // Not a parameter of the function
|
|
818
|
+
) {
|
|
819
|
+
externalReferences.add(path.node.name);
|
|
820
|
+
}
|
|
821
|
+
},
|
|
822
|
+
});
|
|
823
|
+
// Remove global things they're allowed to reference
|
|
824
|
+
externalReferences.delete("Buffer");
|
|
825
|
+
externalReferences.delete("console");
|
|
826
|
+
externalReferences.delete("process");
|
|
827
|
+
externalReferences.delete("setTimeout");
|
|
828
|
+
externalReferences.delete("setInterval");
|
|
829
|
+
if (externalReferences.size > 0) {
|
|
830
|
+
throw new Error(`The function being exported as ${locationHint} references external variables: \`${[
|
|
831
|
+
...externalReferences,
|
|
832
|
+
].join("`, `")}\`. Please ensure this function is wrapped in \`EXPORTABLE(() => ...)\`. Fn:\n${fn}`);
|
|
833
|
+
}
|
|
834
|
+
const fnExpression = path.node;
|
|
835
|
+
const ownProps = Object.entries(fn);
|
|
836
|
+
const result = (() => {
|
|
837
|
+
if (ownProps.length > 0) {
|
|
838
|
+
// Need to assign things to it
|
|
839
|
+
const properties = ownProps.map(([key, value]) => {
|
|
840
|
+
return t.objectProperty(identifierOrLiteral(key), convertToIdentifierViaAST(file, value, `${locationHint}.${key}`, `${locationHint}['${key}']`));
|
|
841
|
+
});
|
|
842
|
+
return {
|
|
843
|
+
functionWithoutOwnAttributesAST: fnExpression,
|
|
844
|
+
ast: t.callExpression(t.memberExpression(t.identifier("Object"), t.identifier("assign")), [fnExpression, t.objectExpression(properties)]),
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
else {
|
|
848
|
+
return {
|
|
849
|
+
functionWithoutOwnAttributesAST: fnExpression,
|
|
850
|
+
ast: fnExpression,
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
})();
|
|
854
|
+
file._funcToAstCache.set(fn, result);
|
|
855
|
+
return result;
|
|
856
|
+
}
|
|
857
|
+
function parseExpressionViaDoc(funcString) {
|
|
858
|
+
const doc = (0, parser_1.parse)(`const f = ${funcString}`, {
|
|
859
|
+
sourceType: "module",
|
|
860
|
+
plugins: ["typescript"],
|
|
861
|
+
});
|
|
862
|
+
let result = null;
|
|
863
|
+
(0, traverse_1.default)(doc, {
|
|
864
|
+
VariableDeclaration(path) {
|
|
865
|
+
result = path.get("declarations.0.init");
|
|
866
|
+
path.stop();
|
|
867
|
+
},
|
|
868
|
+
});
|
|
869
|
+
if (!result) {
|
|
870
|
+
throw new Error(`graphile-export internal error - failed to find the variable declaration (?!!)`);
|
|
871
|
+
}
|
|
872
|
+
return result;
|
|
873
|
+
}
|
|
874
|
+
function _funcToAst(fn, locationHint, _nameHint) {
|
|
782
875
|
const funcString = fn.toString().trim();
|
|
783
876
|
try {
|
|
784
|
-
const
|
|
785
|
-
|
|
786
|
-
plugins: ["typescript"],
|
|
787
|
-
});
|
|
877
|
+
const path = parseExpressionViaDoc(funcString);
|
|
878
|
+
const result = path.node;
|
|
788
879
|
if (result.type !== "FunctionExpression" &&
|
|
789
880
|
result.type !== "ArrowFunctionExpression") {
|
|
790
881
|
if (result.type === "ClassExpression") {
|
|
@@ -793,7 +884,7 @@ Object.defineProperty(${result.id?.name ?? "MyClass"}, '$$export', { value: { mo
|
|
|
793
884
|
}
|
|
794
885
|
throw new Error(`Expected FunctionExpression or ArrowFunctionExpression but saw ${result.type}`);
|
|
795
886
|
}
|
|
796
|
-
return
|
|
887
|
+
return path;
|
|
797
888
|
}
|
|
798
889
|
catch (e) {
|
|
799
890
|
if (e.retry === false) {
|
|
@@ -811,15 +902,13 @@ Object.defineProperty(${result.id?.name ?? "MyClass"}, '$$export', { value: { mo
|
|
|
811
902
|
const modifiedDefinition = funcString.startsWith("async ")
|
|
812
903
|
? "async function " + funcString.slice(6)
|
|
813
904
|
: "function " + funcString;
|
|
814
|
-
const
|
|
815
|
-
|
|
816
|
-
plugins: ["typescript"],
|
|
817
|
-
});
|
|
905
|
+
const path = parseExpressionViaDoc(modifiedDefinition);
|
|
906
|
+
const result = path.node;
|
|
818
907
|
if (result.type !== "FunctionExpression" &&
|
|
819
908
|
result.type !== "ArrowFunctionExpression") {
|
|
820
909
|
throw new Error(`Expected FunctionExpression or ArrowFunctionExpression but saw ${result.type}`);
|
|
821
910
|
}
|
|
822
|
-
return
|
|
911
|
+
return path;
|
|
823
912
|
}
|
|
824
913
|
catch {
|
|
825
914
|
throw new Error(`Function export error at ${locationHint} - failed to process function definition '${trimDef(fn.toString())}'\n ${String(e.stack ?? e)
|
|
@@ -836,6 +925,7 @@ function exportSchemaGraphQLJS({ config, customTypes, customDirectives, file, })
|
|
|
836
925
|
const types = customTypes.map((type) => {
|
|
837
926
|
return file.declareType(type);
|
|
838
927
|
});
|
|
928
|
+
const specifiedDirectivesAST = file.import("graphql", "specifiedDirectives");
|
|
839
929
|
file.addStatements(declareGraphQLEntity(file, schemaExportName, "GraphQLSchema", {
|
|
840
930
|
description: desc(config.description),
|
|
841
931
|
query: config.query ? file.declareType(config.query) : t.nullLiteral(),
|
|
@@ -845,17 +935,19 @@ function exportSchemaGraphQLJS({ config, customTypes, customDirectives, file, })
|
|
|
845
935
|
: null,
|
|
846
936
|
types: t.arrayExpression(types),
|
|
847
937
|
directives: customDirectives.length > 0
|
|
848
|
-
? t.arrayExpression(
|
|
938
|
+
? t.arrayExpression([
|
|
939
|
+
t.spreadElement(specifiedDirectivesAST),
|
|
940
|
+
...customDirectives.map((directive) => file.declareDirective(directive)),
|
|
941
|
+
])
|
|
849
942
|
: null,
|
|
850
943
|
extensions: extensions(file, config.extensions, "schema.extensions", "schema.extensions"),
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
//
|
|
854
|
-
enableDeferStream
|
|
855
|
-
|
|
856
|
-
|
|
944
|
+
// @ts-ignore
|
|
945
|
+
enableDeferStream:
|
|
946
|
+
// @ts-ignore
|
|
947
|
+
config.enableDeferStream != null
|
|
948
|
+
? // @ts-ignore
|
|
949
|
+
t.booleanLiteral(config.enableDeferStream)
|
|
857
950
|
: null,
|
|
858
|
-
*/
|
|
859
951
|
assumeValid: null, // TODO: t.booleanLiteral(true),
|
|
860
952
|
}));
|
|
861
953
|
}
|
|
@@ -866,19 +958,30 @@ function exportSchemaGraphQLJS({ config, customTypes, customDirectives, file, })
|
|
|
866
958
|
*/
|
|
867
959
|
function exportSchemaTypeDefs({ schema, customTypes, file, }) {
|
|
868
960
|
const typeDefsExportName = file.makeVariable("typeDefs");
|
|
869
|
-
const
|
|
961
|
+
const objectPlansProperties = Object.create(null);
|
|
962
|
+
const interfacePlansProperties = Object.create(null);
|
|
963
|
+
const unionPlansProperties = Object.create(null);
|
|
964
|
+
const inputObjectPlansProperties = Object.create(null);
|
|
965
|
+
const scalarPlansProperties = Object.create(null);
|
|
966
|
+
const enumPlansProperties = Object.create(null);
|
|
870
967
|
const schemaExportName = file.makeVariable("schema");
|
|
871
968
|
const typeDefsString = (0, graphql_1.printSchema)(schema);
|
|
872
969
|
const graphqlAST = t.templateLiteral([t.templateElement({ raw: typeDefsString.replace(/[\\`]/g, "\\$&") })], []);
|
|
873
970
|
graphqlAST.leadingComments = [
|
|
874
971
|
{ type: "CommentBlock", value: " GraphQL " },
|
|
875
972
|
];
|
|
876
|
-
const plansProperties = [];
|
|
877
973
|
customTypes.forEach((type) => {
|
|
878
974
|
if (type instanceof graphql_1.GraphQLObjectType) {
|
|
879
|
-
const typeProperties =
|
|
975
|
+
const typeProperties = Object.create(null);
|
|
976
|
+
const plansProperties = Object.create(null);
|
|
880
977
|
if (type.extensions.grafast?.assertStep) {
|
|
881
|
-
typeProperties.
|
|
978
|
+
typeProperties.assertStep = convertToIdentifierViaAST(file, type.extensions.grafast.assertStep, `${type.name}AssertStep`, `${type.name}.extensions.assertStep`);
|
|
979
|
+
}
|
|
980
|
+
if (type.isTypeOf) {
|
|
981
|
+
typeProperties.isTypeOf = convertToIdentifierViaAST(file, type.isTypeOf, `${type.name}IsTypeOf`, `${type.name}.extensions.isTypeOf`);
|
|
982
|
+
}
|
|
983
|
+
if (type.extensions.grafast?.planType) {
|
|
984
|
+
typeProperties.planType = convertToIdentifierViaAST(file, type.extensions.grafast.planType, `${type.name}PlanType`, `${type.name}.extensions.planType`);
|
|
882
985
|
}
|
|
883
986
|
for (const [fieldName, field] of Object.entries(type.toConfig().fields)) {
|
|
884
987
|
// Use shorthand if there's only a `plan` and nothing else
|
|
@@ -899,9 +1002,38 @@ function exportSchemaTypeDefs({ schema, customTypes, file, }) {
|
|
|
899
1002
|
const args = field.args
|
|
900
1003
|
? Object.entries(field.args)
|
|
901
1004
|
.map(([argName, arg]) => {
|
|
902
|
-
|
|
1005
|
+
if (arg.extensions) {
|
|
1006
|
+
const { grafast, ...rest } = arg.extensions;
|
|
1007
|
+
const extensionsAST = extensions(file, rest, `${type.name}.${fieldName}.${argName}`, `${type.name}.fields[${fieldName}].args[${argName}].extensions`);
|
|
1008
|
+
if (!extensionsAST) {
|
|
1009
|
+
if (!grafast)
|
|
1010
|
+
return null;
|
|
1011
|
+
const keys = Object.keys(grafast);
|
|
1012
|
+
if (keys.length === 1 && keys[0] === "applyPlan") {
|
|
1013
|
+
// Shorthand
|
|
1014
|
+
return t.objectProperty(identifierOrLiteral(argName), convertToIdentifierViaAST(file, grafast.applyPlan, `${type.name}.${fieldName}${argName}ApplyPlan`, `${type.name}.fields[${fieldName}].args[${argName}].applyPlan`));
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
return t.objectProperty(identifierOrLiteral(argName), t.objectExpression([
|
|
1018
|
+
...objectToObjectProperties({
|
|
1019
|
+
extensions: extensionsAST,
|
|
1020
|
+
}),
|
|
1021
|
+
...(grafast
|
|
1022
|
+
? Object.entries(grafast)
|
|
1023
|
+
.map(([k, v]) => {
|
|
1024
|
+
if (v == null)
|
|
1025
|
+
return null;
|
|
1026
|
+
return t.objectProperty(t.identifier(k), convertToIdentifierViaAST(file, grafast.applyPlan, `${type.name}.${fieldName}${argName}${k}`, `${type.name}.fields[${fieldName}].args[${argName}].extensions.grafast[${k}]`));
|
|
1027
|
+
})
|
|
1028
|
+
.filter(utils_js_1.isNotNullish)
|
|
1029
|
+
: []),
|
|
1030
|
+
]));
|
|
1031
|
+
}
|
|
1032
|
+
else {
|
|
1033
|
+
return null;
|
|
1034
|
+
}
|
|
903
1035
|
})
|
|
904
|
-
.filter(isNotNullish)
|
|
1036
|
+
.filter(utils_js_1.isNotNullish)
|
|
905
1037
|
: null;
|
|
906
1038
|
const argsAST = args && args.length ? t.objectExpression(args) : null;
|
|
907
1039
|
if (!planAST && !subscribePlanAST && !resolveAST && !subscribeAST) {
|
|
@@ -925,24 +1057,69 @@ function exportSchemaTypeDefs({ schema, customTypes, file, }) {
|
|
|
925
1057
|
subscribe: subscribeAST,
|
|
926
1058
|
args: argsAST,
|
|
927
1059
|
}));
|
|
928
|
-
|
|
1060
|
+
plansProperties[fieldName] = fieldSpec;
|
|
929
1061
|
}
|
|
930
|
-
|
|
1062
|
+
setIfNotEmpty(typeProperties, "plans", plansProperties, true);
|
|
1063
|
+
setIfNotEmpty(objectPlansProperties, type.name, typeProperties, false);
|
|
931
1064
|
}
|
|
932
1065
|
else if (type instanceof graphql_1.GraphQLInputObjectType) {
|
|
933
|
-
const typeProperties =
|
|
1066
|
+
const typeProperties = Object.create(null);
|
|
1067
|
+
const plansProperties = Object.create(null);
|
|
1068
|
+
if (type.extensions?.grafast?.baked) {
|
|
1069
|
+
typeProperties.baked = convertToIdentifierViaAST(file, type.extensions?.grafast.baked, `${type.name}.inputPlan`, `${type.name}.extensions.grafast.baked`);
|
|
1070
|
+
}
|
|
934
1071
|
for (const [fieldName, field] of Object.entries(type.toConfig().fields)) {
|
|
935
|
-
|
|
1072
|
+
if (!field.extensions)
|
|
1073
|
+
continue;
|
|
1074
|
+
const { grafast, ...rest } = field.extensions;
|
|
1075
|
+
const extensionsAST = extensions(file, rest, `${type.name}_${fieldName}Extensions`, `${type.name}.fields[${fieldName}].extensions`);
|
|
1076
|
+
if (!extensionsAST) {
|
|
1077
|
+
if (!grafast)
|
|
1078
|
+
continue;
|
|
1079
|
+
const keys = Object.keys(grafast);
|
|
1080
|
+
if (keys.length === 1 && keys[0] === "apply") {
|
|
1081
|
+
plansProperties[fieldName] = convertToIdentifierViaAST(file, grafast.apply, `${type.name}.${fieldName}Apply`, `${type.name}.fields[${fieldName}].extensions.grafast.apply`);
|
|
1082
|
+
continue;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
plansProperties[fieldName] = t.objectExpression([
|
|
1086
|
+
...objectToObjectProperties({
|
|
1087
|
+
extensions: extensionsAST,
|
|
1088
|
+
}),
|
|
1089
|
+
...(grafast
|
|
1090
|
+
? Object.entries(grafast)
|
|
1091
|
+
.map(([k, v]) => {
|
|
1092
|
+
if (v == null)
|
|
1093
|
+
return null;
|
|
1094
|
+
return t.objectProperty(t.identifier(k), convertToIdentifierViaAST(file, v, `${type.name}.${fieldName}${k}`, `${type.name}.fields[${fieldName}].extensions.grafast[${k}]`));
|
|
1095
|
+
})
|
|
1096
|
+
.filter(utils_js_1.isNotNullish)
|
|
1097
|
+
: []),
|
|
1098
|
+
]);
|
|
936
1099
|
}
|
|
937
|
-
|
|
1100
|
+
setIfNotEmpty(typeProperties, "plans", plansProperties, true);
|
|
1101
|
+
setIfNotEmpty(inputObjectPlansProperties, type.name, typeProperties, false);
|
|
938
1102
|
}
|
|
939
1103
|
else if (type instanceof graphql_1.GraphQLInterfaceType ||
|
|
940
1104
|
type instanceof graphql_1.GraphQLUnionType) {
|
|
941
1105
|
const config = type.toConfig();
|
|
942
|
-
if (config.resolveType
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
1106
|
+
if (config.resolveType ||
|
|
1107
|
+
config.extensions.grafast?.toSpecifier ||
|
|
1108
|
+
config.extensions.grafast?.planType) {
|
|
1109
|
+
const target = type instanceof graphql_1.GraphQLInterfaceType
|
|
1110
|
+
? interfacePlansProperties
|
|
1111
|
+
: unionPlansProperties;
|
|
1112
|
+
target[type.name] = t.objectExpression(objectToObjectProperties({
|
|
1113
|
+
resolveType: type.resolveType
|
|
1114
|
+
? convertToIdentifierViaAST(file, type.resolveType, `${type.name}ResolveType`, `${type.name}.resolveType`)
|
|
1115
|
+
: null,
|
|
1116
|
+
toSpecifier: type.extensions?.grafast?.toSpecifier
|
|
1117
|
+
? convertToIdentifierViaAST(file, type.extensions?.grafast?.toSpecifier, `${type.name}ToSpecifier`, `${type.name}.toSpecifier`)
|
|
1118
|
+
: null,
|
|
1119
|
+
planType: type.extensions?.grafast?.planType
|
|
1120
|
+
? convertToIdentifierViaAST(file, type.extensions?.grafast?.planType, `${type.name}PlanType`, `${type.name}.planType`)
|
|
1121
|
+
: null,
|
|
1122
|
+
}));
|
|
946
1123
|
}
|
|
947
1124
|
}
|
|
948
1125
|
else if (type instanceof graphql_1.GraphQLScalarType) {
|
|
@@ -950,36 +1127,65 @@ function exportSchemaTypeDefs({ schema, customTypes, file, }) {
|
|
|
950
1127
|
const planAST = config.extensions.grafast?.plan
|
|
951
1128
|
? convertToIdentifierViaAST(file, config.extensions?.grafast?.plan, `${type.name}Plan`, `${type.name}.extensions.grafast.plan`)
|
|
952
1129
|
: null;
|
|
953
|
-
if (planAST
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1130
|
+
if (planAST ||
|
|
1131
|
+
type.serialize !== graphql_1.GraphQLScalarType.prototype.serialize ||
|
|
1132
|
+
type.parseValue !== graphql_1.GraphQLScalarType.prototype.parseValue ||
|
|
1133
|
+
type.parseLiteral !== graphql_1.GraphQLScalarType.prototype.parseLiteral) {
|
|
1134
|
+
scalarPlansProperties[type.name] = t.objectExpression(objectToObjectProperties({
|
|
1135
|
+
serialize: type.serialize !== graphql_1.GraphQLScalarType.prototype.serialize
|
|
1136
|
+
? convertToIdentifierViaAST(file, type.serialize, `${type.name}Serialize`, `${type.name}.serialize`)
|
|
1137
|
+
: null,
|
|
1138
|
+
parseValue: type.parseValue !== graphql_1.GraphQLScalarType.prototype.parseValue
|
|
1139
|
+
? convertToIdentifierViaAST(file, type.parseValue, `${type.name}ParseValue`, `${type.name}.parseValue`)
|
|
1140
|
+
: null,
|
|
1141
|
+
parseLiteral: type.parseLiteral !== graphql_1.GraphQLScalarType.prototype.parseLiteral
|
|
1142
|
+
? convertToIdentifierViaAST(file, type.parseLiteral, `${type.name}ParseLiteral`, `${type.name}.parseLiteral`)
|
|
1143
|
+
: null,
|
|
958
1144
|
plan: planAST,
|
|
959
|
-
}))
|
|
1145
|
+
}));
|
|
960
1146
|
}
|
|
961
1147
|
}
|
|
962
1148
|
else if (type instanceof graphql_1.GraphQLEnumType) {
|
|
963
1149
|
const config = type.toConfig();
|
|
964
|
-
const
|
|
1150
|
+
const typeProperties = Object.create(null);
|
|
1151
|
+
const enumValueProperties = Object.create(null);
|
|
965
1152
|
for (const [enumValueName, enumValueConfig] of Object.entries(config.values)) {
|
|
966
1153
|
const valueAST = enumValueConfig.value !== undefined &&
|
|
967
1154
|
enumValueConfig.value !== enumValueName
|
|
968
1155
|
? convertToIdentifierViaAST(file, enumValueConfig.value, `${type.name}_${enumValueName}`, `${type.name}.values[${enumValueName}].value`)
|
|
969
1156
|
: null;
|
|
970
|
-
const
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1157
|
+
const { grafast, ...rest } = enumValueConfig.extensions ?? {};
|
|
1158
|
+
const extensionsAST = extensions(file, rest, `${type.name}_${enumValueName}Extensions`, `${type.name}.values[${enumValueName}].extensions`);
|
|
1159
|
+
if (!valueAST && !extensionsAST) {
|
|
1160
|
+
if (!grafast)
|
|
1161
|
+
continue;
|
|
1162
|
+
const keys = Object.keys(grafast);
|
|
1163
|
+
if (keys.length === 1 && keys[0] === "apply") {
|
|
1164
|
+
enumValueProperties[enumValueName] = convertToIdentifierViaAST(file, grafast.apply, `${type.name}.${enumValueName}Apply`, `${type.name}.values[${enumValueName}].extensions.grafast.apply`);
|
|
1165
|
+
continue;
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
const grafastProperties = grafast
|
|
1169
|
+
? Object.entries(grafast)
|
|
1170
|
+
.map(([k, v]) => {
|
|
1171
|
+
if (v == null)
|
|
1172
|
+
return null;
|
|
1173
|
+
return t.objectProperty(t.identifier(k), convertToIdentifierViaAST(file, v, `${type.name}.${enumValueName}${k}`, `${type.name}.values[${enumValueName}].extensions.grafast[${k}]`));
|
|
1174
|
+
})
|
|
1175
|
+
.filter(utils_js_1.isNotNullish)
|
|
1176
|
+
: [];
|
|
1177
|
+
if (valueAST || extensionsAST || grafastProperties.length) {
|
|
1178
|
+
enumValueProperties[enumValueName] = t.objectExpression([
|
|
1179
|
+
...objectToObjectProperties({
|
|
1180
|
+
value: valueAST,
|
|
1181
|
+
extensions: extensionsAST,
|
|
1182
|
+
}),
|
|
1183
|
+
...grafastProperties,
|
|
1184
|
+
]);
|
|
978
1185
|
}
|
|
979
1186
|
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
}
|
|
1187
|
+
setIfNotEmpty(typeProperties, "values", enumValueProperties, true);
|
|
1188
|
+
setIfNotEmpty(enumPlansProperties, type.name, typeProperties, false);
|
|
983
1189
|
}
|
|
984
1190
|
else {
|
|
985
1191
|
const never = type;
|
|
@@ -989,33 +1195,55 @@ function exportSchemaTypeDefs({ schema, customTypes, file, }) {
|
|
|
989
1195
|
const typeDefs = t.exportNamedDeclaration(t.variableDeclaration("const", [
|
|
990
1196
|
t.variableDeclarator(typeDefsExportName, graphqlAST),
|
|
991
1197
|
]));
|
|
992
|
-
const plans = t.exportNamedDeclaration(t.variableDeclaration("const", [
|
|
993
|
-
t.variableDeclarator(plansExportName, t.objectExpression(plansProperties)),
|
|
994
|
-
]));
|
|
995
1198
|
file.addStatements(typeDefs);
|
|
996
|
-
|
|
1199
|
+
const typeDefsEtc = {
|
|
1200
|
+
typeDefs: typeDefsExportName,
|
|
1201
|
+
};
|
|
1202
|
+
const stuff = Object.create(null);
|
|
1203
|
+
setIfNotEmpty(stuff, "objects", objectPlansProperties, [
|
|
1204
|
+
schema.getQueryType()?.name,
|
|
1205
|
+
schema.getMutationType()?.name,
|
|
1206
|
+
schema.getSubscriptionType()?.name,
|
|
1207
|
+
].filter((n) => n != null));
|
|
1208
|
+
setIfNotEmpty(stuff, "interfaces", interfacePlansProperties, true);
|
|
1209
|
+
setIfNotEmpty(stuff, "unions", unionPlansProperties, true);
|
|
1210
|
+
setIfNotEmpty(stuff, "inputObjects", inputObjectPlansProperties, true);
|
|
1211
|
+
setIfNotEmpty(stuff, "scalars", scalarPlansProperties, true);
|
|
1212
|
+
setIfNotEmpty(stuff, "enums", enumPlansProperties, true);
|
|
1213
|
+
const todos = [];
|
|
1214
|
+
for (const [key, props] of Object.entries(stuff)) {
|
|
1215
|
+
const exportName = file.makeVariable(key);
|
|
1216
|
+
// Do this afterwards so all the variables are reserved first.
|
|
1217
|
+
todos.push(() => {
|
|
1218
|
+
const plans = t.exportNamedDeclaration(t.variableDeclaration("const", [
|
|
1219
|
+
t.variableDeclarator(exportName, props),
|
|
1220
|
+
]));
|
|
1221
|
+
file.addStatements(plans);
|
|
1222
|
+
typeDefsEtc[key] = exportName;
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
// Now all variables are declared, we can populate them
|
|
1226
|
+
for (const todo of todos) {
|
|
1227
|
+
todo();
|
|
1228
|
+
}
|
|
997
1229
|
const makeGrafastSchemaAST = file.import("grafast", "makeGrafastSchema");
|
|
998
1230
|
const schemaAST = t.callExpression(makeGrafastSchemaAST, [
|
|
999
|
-
t.objectExpression(objectToObjectProperties(
|
|
1000
|
-
typeDefs: typeDefsExportName,
|
|
1001
|
-
plans: plansExportName,
|
|
1002
|
-
})),
|
|
1231
|
+
t.objectExpression(objectToObjectProperties(typeDefsEtc)),
|
|
1003
1232
|
]);
|
|
1004
1233
|
file.addStatements(t.exportNamedDeclaration(t.variableDeclaration("const", [
|
|
1005
1234
|
t.variableDeclarator(schemaExportName, schemaAST),
|
|
1006
1235
|
])));
|
|
1007
1236
|
}
|
|
1237
|
+
const specifiedDirectiveNames = graphql_1.specifiedDirectives.map((d) => d.name);
|
|
1008
1238
|
async function exportSchemaAsString(schema, options) {
|
|
1009
1239
|
const config = schema.toConfig();
|
|
1010
1240
|
const customTypes = config.types.filter((type) => !isBuiltinType(type));
|
|
1011
|
-
const customDirectives = config.directives.filter((d) => !
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
"stream",
|
|
1018
|
-
].includes(d.name));
|
|
1241
|
+
const customDirectives = config.directives.filter((d) => !specifiedDirectiveNames.includes(d.name));
|
|
1242
|
+
if (config.directives.some((d) => d.name === "defer" || d.name === "skip")) {
|
|
1243
|
+
// Ref: https://github.com/graphql/graphql-js/pull/3450
|
|
1244
|
+
// @ts-ignore
|
|
1245
|
+
config.enableDeferStream = true;
|
|
1246
|
+
}
|
|
1019
1247
|
const file = new CodegenFile(options);
|
|
1020
1248
|
const schemaExportDetails = {
|
|
1021
1249
|
schema,
|
|
@@ -1031,16 +1259,79 @@ async function exportSchemaAsString(schema, options) {
|
|
|
1031
1259
|
else {
|
|
1032
1260
|
exportSchemaGraphQLJS(schemaExportDetails);
|
|
1033
1261
|
}
|
|
1262
|
+
return exportFile(file, options);
|
|
1263
|
+
}
|
|
1264
|
+
function exportFile(file, { disableOptimize }) {
|
|
1034
1265
|
const ast = file.toAST();
|
|
1035
|
-
const optimizedAst = (0, index_js_1.optimize)(ast);
|
|
1266
|
+
const optimizedAst = disableOptimize ? ast : (0, index_js_1.optimize)(ast);
|
|
1036
1267
|
const { code } = reallyGenerate(optimizedAst, {});
|
|
1037
1268
|
return { code };
|
|
1038
1269
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
const
|
|
1042
|
-
const
|
|
1043
|
-
const
|
|
1270
|
+
async function exportValueAsString(name, value, options) {
|
|
1271
|
+
const file = new CodegenFile(options);
|
|
1272
|
+
const exportName = file.makeVariable(name);
|
|
1273
|
+
const valueAST = convertToIdentifierViaAST(file, value, name, name);
|
|
1274
|
+
file.addStatements(t.exportNamedDeclaration(t.variableDeclaration("const", [
|
|
1275
|
+
t.variableDeclarator(exportName, valueAST),
|
|
1276
|
+
])));
|
|
1277
|
+
return exportFile(file, options);
|
|
1278
|
+
}
|
|
1279
|
+
async function loadESLint() {
|
|
1280
|
+
try {
|
|
1281
|
+
return await import("eslint");
|
|
1282
|
+
}
|
|
1283
|
+
catch (e) {
|
|
1284
|
+
return null;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
async function lint(code, rawFilePath) {
|
|
1288
|
+
const eslintModule = await loadESLint();
|
|
1289
|
+
if (eslintModule == null) {
|
|
1290
|
+
console.warn(`graphile-export could not find 'eslint' so disabling additional checks`);
|
|
1291
|
+
return;
|
|
1292
|
+
}
|
|
1293
|
+
const filePath = typeof rawFilePath === "string" ? rawFilePath : rawFilePath.pathname;
|
|
1294
|
+
const { ESLint } = eslintModule;
|
|
1295
|
+
const eslint = new ESLint({
|
|
1296
|
+
overrideConfigFile: true, // Don't use external config
|
|
1297
|
+
allowInlineConfig: false, // Ignore `/* eslint-disable ... */` comments
|
|
1298
|
+
overrideConfig: {
|
|
1299
|
+
linterOptions: { reportUnusedDisableDirectives: false },
|
|
1300
|
+
languageOptions: {
|
|
1301
|
+
ecmaVersion: 2022,
|
|
1302
|
+
sourceType: "module",
|
|
1303
|
+
},
|
|
1304
|
+
rules: {
|
|
1305
|
+
"no-use-before-define": [
|
|
1306
|
+
"error",
|
|
1307
|
+
{
|
|
1308
|
+
functions: false,
|
|
1309
|
+
classes: false,
|
|
1310
|
+
// We often have cyclic dependencies between types, this is handled via callbacks, so we don't care about that.
|
|
1311
|
+
variables: false,
|
|
1312
|
+
allowNamedExports: false,
|
|
1313
|
+
},
|
|
1314
|
+
],
|
|
1315
|
+
},
|
|
1316
|
+
},
|
|
1317
|
+
});
|
|
1318
|
+
const results = await eslint.lintText(code, {
|
|
1319
|
+
warnIgnored: true,
|
|
1320
|
+
// DO NOT PASS THE `filePath`; it can result in the file being ignored!
|
|
1321
|
+
});
|
|
1322
|
+
if (results.length !== 1) {
|
|
1323
|
+
console.dir({ filePath, results });
|
|
1324
|
+
throw new Error(`Expected ESLint results to have exactly one entry`);
|
|
1325
|
+
}
|
|
1326
|
+
const [result] = results;
|
|
1327
|
+
if (result.warningCount > 0 || result.errorCount > 0) {
|
|
1328
|
+
console.log(`ESLint found problems in the export; this likely indicates some issue with \`EXPORTABLE\` calls`);
|
|
1329
|
+
const formatter = await eslint.loadFormatter("stylish");
|
|
1330
|
+
const output = formatter.format(results);
|
|
1331
|
+
console.log(output);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
async function format(toFormat, toPath, options) {
|
|
1044
1335
|
if (options.prettier) {
|
|
1045
1336
|
const prettier = await import("prettier");
|
|
1046
1337
|
const config = await prettier.resolveConfig(toPath.toString());
|
|
@@ -1048,11 +1339,65 @@ async function exportSchema(schema, toPath, options = {}) {
|
|
|
1048
1339
|
parser: "babel",
|
|
1049
1340
|
...(config ?? {}),
|
|
1050
1341
|
});
|
|
1051
|
-
|
|
1342
|
+
return formatted;
|
|
1052
1343
|
}
|
|
1053
1344
|
else {
|
|
1054
|
-
|
|
1345
|
+
return toFormat;
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
const HEADER = `/* eslint-disable graphile-export/export-instances, graphile-export/export-methods, graphile-export/exhaustive-deps */\n`;
|
|
1349
|
+
async function exportSchema(schema, toPath, options = {}) {
|
|
1350
|
+
const { code } = await exportSchemaAsString(schema, options);
|
|
1351
|
+
const toFormat = HEADER + code;
|
|
1352
|
+
const formatted = await format(toFormat, toPath, options);
|
|
1353
|
+
await (0, promises_1.writeFile)(toPath, formatted);
|
|
1354
|
+
await lint(formatted, toPath);
|
|
1355
|
+
}
|
|
1356
|
+
/**
|
|
1357
|
+
* Returns `false` for nullish values and empty objects, true otherwise.
|
|
1358
|
+
*/
|
|
1359
|
+
function isNotEmpty(value) {
|
|
1360
|
+
if (value == null)
|
|
1361
|
+
return false;
|
|
1362
|
+
if (typeof value !== "object")
|
|
1363
|
+
return true;
|
|
1364
|
+
const proto = Object.getPrototypeOf(value);
|
|
1365
|
+
if (proto !== null && proto !== Object.prototype)
|
|
1366
|
+
return true;
|
|
1367
|
+
if (Object.getOwnPropertyNames(value).length === 0 &&
|
|
1368
|
+
Object.getOwnPropertySymbols(value).length === 0) {
|
|
1369
|
+
// Empty object!
|
|
1370
|
+
return false;
|
|
1371
|
+
}
|
|
1372
|
+
return true;
|
|
1373
|
+
}
|
|
1374
|
+
function setIfNotEmpty(target, key, value, sort) {
|
|
1375
|
+
if (Object.keys(value).length > 0) {
|
|
1376
|
+
const entries = Object.entries(value);
|
|
1377
|
+
if (typeof sort === "boolean") {
|
|
1378
|
+
entries.sort((a, z) => a[0].localeCompare(z[0], "und"));
|
|
1379
|
+
}
|
|
1380
|
+
else if (sort) {
|
|
1381
|
+
entries.sort((a, z) => {
|
|
1382
|
+
const ka = a[0];
|
|
1383
|
+
const kz = z[0];
|
|
1384
|
+
// First, compare keys against the specific defined order
|
|
1385
|
+
const sa = sort.indexOf(ka);
|
|
1386
|
+
const sz = sort.indexOf(kz);
|
|
1387
|
+
if (sa >= 0) {
|
|
1388
|
+
if (sz < 0)
|
|
1389
|
+
return -1;
|
|
1390
|
+
return sa - sz;
|
|
1391
|
+
}
|
|
1392
|
+
else if (sz >= 0) {
|
|
1393
|
+
return 1;
|
|
1394
|
+
}
|
|
1395
|
+
// Failing that, compare them alphabetically
|
|
1396
|
+
return ka.localeCompare(kz, "und");
|
|
1397
|
+
});
|
|
1398
|
+
}
|
|
1399
|
+
const finalProps = entries.map(([k, v]) => t.objectProperty(identifierOrLiteral(k), v));
|
|
1400
|
+
target[key] = t.objectExpression(finalProps);
|
|
1055
1401
|
}
|
|
1056
1402
|
}
|
|
1057
|
-
exports.exportSchema = exportSchema;
|
|
1058
1403
|
//# sourceMappingURL=exportSchema.js.map
|