graphile-export 0.0.2-beta.3 → 0.0.2-beta.30
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 +567 -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 +507 -167
- 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)) {
|
|
@@ -534,6 +553,9 @@ function canBeRegularObjectKey(key) {
|
|
|
534
553
|
return key !== "__proto__";
|
|
535
554
|
}
|
|
536
555
|
function _convertToAST(file, thing, locationHint, nameHint, depth, reference) {
|
|
556
|
+
if ((0, helpers_js_1.isForbidden)(thing)) {
|
|
557
|
+
throw new Error(`The value at ${locationHint} is forbidden from being exported; please be more specific in your EXPORTABLE factories!`);
|
|
558
|
+
}
|
|
537
559
|
const handleSubvalue = (value, tKey, key) => {
|
|
538
560
|
const existingIdentifier = getExistingIdentifier(file, value);
|
|
539
561
|
if (existingIdentifier) {
|
|
@@ -566,22 +588,25 @@ function _convertToAST(file, thing, locationHint, nameHint, depth, reference) {
|
|
|
566
588
|
return func(file, thing, locationHint, nameHint);
|
|
567
589
|
}
|
|
568
590
|
else if ((0, graphql_1.isSchema)(thing)) {
|
|
569
|
-
throw new Error(
|
|
591
|
+
throw new Error(`Attempted to export GraphQLSchema directly from \`_convertToAST\` (at ${locationHint}); this is currently unsupported.`);
|
|
570
592
|
}
|
|
571
593
|
else if (typeof thing === "object" && thing != null) {
|
|
572
594
|
const prototype = Object.getPrototypeOf(thing);
|
|
573
595
|
if (prototype !== null && prototype !== Object.prototype) {
|
|
574
|
-
|
|
596
|
+
if (thing.constructor) {
|
|
597
|
+
throw new Error(`Attempting to export an instance of a class (at ${locationHint}); you should wrap this definition in EXPORTABLE! (Class: ${thing.constructor})`);
|
|
598
|
+
}
|
|
599
|
+
else {
|
|
600
|
+
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)})`);
|
|
601
|
+
}
|
|
575
602
|
}
|
|
576
603
|
const propertyPairs = [];
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
604
|
+
const entries = Object.entries(thing);
|
|
605
|
+
const hasUnsafeKeys = entries.some(([key]) => !canBeRegularObjectKey(key));
|
|
606
|
+
entries.forEach(([key, value]) => {
|
|
607
|
+
const tKey = hasUnsafeKeys ? literal(key) : identifierOrLiteral(key);
|
|
580
608
|
const subvalue = handleSubvalue(value, tKey, key);
|
|
581
609
|
propertyPairs.push([tKey, subvalue]);
|
|
582
|
-
if (!canBeRegularObjectKey(key)) {
|
|
583
|
-
hasUnsafeKeys = true;
|
|
584
|
-
}
|
|
585
610
|
});
|
|
586
611
|
if (prototype === null) {
|
|
587
612
|
if (hasUnsafeKeys) {
|
|
@@ -590,20 +615,14 @@ function _convertToAST(file, thing, locationHint, nameHint, depth, reference) {
|
|
|
590
615
|
t.arrayExpression(propertyPairs.map(([key, val]) => t.arrayExpression([key, val]))),
|
|
591
616
|
]);
|
|
592
617
|
}
|
|
593
|
-
else if (propertyPairs.length === 0) {
|
|
594
|
-
return t.callExpression(t.memberExpression(t.identifier("Object"), t.identifier("create")), [t.nullLiteral()]);
|
|
595
|
-
}
|
|
596
618
|
else {
|
|
597
|
-
const obj =
|
|
598
|
-
return
|
|
599
|
-
t.callExpression(t.memberExpression(t.identifier("Object"), t.identifier("create")), [t.nullLiteral()]),
|
|
600
|
-
obj,
|
|
601
|
-
]);
|
|
619
|
+
const obj = objectNullPrototype(propertyPairs.map(([key, val]) => t.objectProperty(key, val)));
|
|
620
|
+
return obj;
|
|
602
621
|
}
|
|
603
622
|
}
|
|
604
623
|
else {
|
|
605
624
|
if (hasUnsafeKeys) {
|
|
606
|
-
throw new Error(`Unexportable key found on non-null-prototype object`);
|
|
625
|
+
throw new Error(`Unexportable key found on non-null-prototype object (at ${locationHint})`);
|
|
607
626
|
}
|
|
608
627
|
else {
|
|
609
628
|
const obj = t.objectExpression(propertyPairs.map(([key, val]) => t.objectProperty(key, val)));
|
|
@@ -639,7 +658,7 @@ const getExistingIdentifier = (file, thing) => {
|
|
|
639
658
|
const { moduleName, exportName } = (0, wellKnown_js_1.wellKnown)(file.options, thing);
|
|
640
659
|
return file.import(moduleName, exportName);
|
|
641
660
|
}
|
|
642
|
-
else if (isImportable(thing)) {
|
|
661
|
+
else if ((0, utils_js_1.isImportable)(thing)) {
|
|
643
662
|
const { moduleName, exportName } = thing.$$export;
|
|
644
663
|
return file.import(moduleName, exportName);
|
|
645
664
|
}
|
|
@@ -650,6 +669,21 @@ const getExistingIdentifier = (file, thing) => {
|
|
|
650
669
|
return file.declareType(thing);
|
|
651
670
|
}
|
|
652
671
|
};
|
|
672
|
+
function importWellKnownOrFactory(file, value, locationHint, nameHint) {
|
|
673
|
+
if ((0, utils_js_1.isImportable)(value)) {
|
|
674
|
+
return file.import(value.$$export.moduleName, value.$$export.exportName);
|
|
675
|
+
}
|
|
676
|
+
else if ((0, wellKnown_js_1.wellKnown)(file.options, value)) {
|
|
677
|
+
const { moduleName, exportName } = (0, wellKnown_js_1.wellKnown)(file.options, value);
|
|
678
|
+
return file.import(moduleName, exportName);
|
|
679
|
+
}
|
|
680
|
+
else if (isExportedFromFactory(value)) {
|
|
681
|
+
return factoryAst(file, value, locationHint, nameHint);
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
return undefined;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
653
687
|
function convertToIdentifierViaAST(file, thing, baseNameHint, locationHint, depth = 0) {
|
|
654
688
|
const existingIdentifier = getExistingIdentifier(file, thing);
|
|
655
689
|
if (existingIdentifier) {
|
|
@@ -659,9 +693,8 @@ function convertToIdentifierViaAST(file, thing, baseNameHint, locationHint, dept
|
|
|
659
693
|
const nameHint = getNameForThing(thing, locationHint, baseNameHint);
|
|
660
694
|
const variableIdentifier = file.makeVariable(nameHint || "value");
|
|
661
695
|
file._values.set(thing, variableIdentifier);
|
|
662
|
-
const ast =
|
|
663
|
-
|
|
664
|
-
: _convertToAST(file, thing, locationHint, nameHint, depth, variableIdentifier);
|
|
696
|
+
const ast = importWellKnownOrFactory(file, thing, locationHint, nameHint) ??
|
|
697
|
+
_convertToAST(file, thing, locationHint, nameHint, depth, variableIdentifier);
|
|
665
698
|
if (ast.type === "Identifier") {
|
|
666
699
|
console.warn(`graphile-export error: AST returned an identifier '${ast.name}'; this could cause an infinite loop.`);
|
|
667
700
|
}
|
|
@@ -679,20 +712,20 @@ function objectToObjectProperties(o) {
|
|
|
679
712
|
.map(([key, value]) => t.objectProperty(identifierOrLiteral(key), value));
|
|
680
713
|
}
|
|
681
714
|
function extensions(file, extensions, locationHint, nameHint) {
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
return convertToIdentifierViaAST(file, extensions, nameHint, locationHint);
|
|
715
|
+
return isNotEmpty(extensions)
|
|
716
|
+
? convertToIdentifierViaAST(file, extensions, nameHint, locationHint)
|
|
717
|
+
: null;
|
|
686
718
|
}
|
|
687
|
-
/**
|
|
719
|
+
/**
|
|
720
|
+
* Maps to `{__proto__: null, ...}` which is similar to
|
|
721
|
+
* `Object.assign(Object.create(null), {...})`
|
|
722
|
+
*/
|
|
688
723
|
function objectNullPrototype(properties) {
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
return t.callExpression(t.memberExpression(t.identifier("Object"), t.identifier("assign")), [objectCreateNull, t.objectExpression(properties)]);
|
|
724
|
+
return t.objectExpression([
|
|
725
|
+
t.objectProperty(t.identifier("__proto__"), t.nullLiteral()),
|
|
726
|
+
...properties,
|
|
727
|
+
]);
|
|
694
728
|
}
|
|
695
|
-
exports.objectNullPrototype = objectNullPrototype;
|
|
696
729
|
/*
|
|
697
730
|
function iife(statements: t.Statement[]): t.Expression {
|
|
698
731
|
return t.callExpression(
|
|
@@ -709,24 +742,13 @@ function func(file, fn, locationHint, nameHint) {
|
|
|
709
742
|
// scope; e.g.:
|
|
710
743
|
//
|
|
711
744
|
// `(() => { 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
|
-
}
|
|
745
|
+
return (importWellKnownOrFactory(file, fn, locationHint, nameHint) ??
|
|
746
|
+
funcToAst(file, fn, locationHint, nameHint).ast);
|
|
725
747
|
}
|
|
726
748
|
const shouldOptimizeFactoryCalls = true;
|
|
727
749
|
function factoryAst(file, fn, locationHint, nameHint) {
|
|
728
750
|
const factory = fn.$exporter$factory;
|
|
729
|
-
const funcAST = funcToAst(factory, locationHint, nameHint);
|
|
751
|
+
const { functionWithoutOwnAttributesAST: funcAST } = funcToAst(file, factory, locationHint, nameHint);
|
|
730
752
|
const depArgs = fn.$exporter$args.map((arg, i) => {
|
|
731
753
|
if (typeof arg === "string") {
|
|
732
754
|
return t.stringLiteral(arg);
|
|
@@ -778,13 +800,79 @@ function factoryAst(file, fn, locationHint, nameHint) {
|
|
|
778
800
|
return t.callExpression(funcAST, depArgs);
|
|
779
801
|
}
|
|
780
802
|
}
|
|
781
|
-
function funcToAst(fn, locationHint, _nameHint) {
|
|
803
|
+
function funcToAst(file, fn, locationHint, _nameHint) {
|
|
804
|
+
if (file._funcToAstCache.has(fn)) {
|
|
805
|
+
return file._funcToAstCache.get(fn);
|
|
806
|
+
}
|
|
807
|
+
const path = _funcToAst(fn, locationHint, _nameHint);
|
|
808
|
+
const externalReferences = new Set();
|
|
809
|
+
const localBindings = path.scope.bindings;
|
|
810
|
+
path.traverse({
|
|
811
|
+
Identifier(path) {
|
|
812
|
+
if (t.isReferenced(path.node, path.parent) && // Is a variable reference
|
|
813
|
+
!path.scope.hasBinding(path.node.name) && // Not defined in local scope
|
|
814
|
+
!localBindings[path.node.name] // Not a parameter of the function
|
|
815
|
+
) {
|
|
816
|
+
externalReferences.add(path.node.name);
|
|
817
|
+
}
|
|
818
|
+
},
|
|
819
|
+
});
|
|
820
|
+
// Remove global things they're allowed to reference
|
|
821
|
+
externalReferences.delete("Buffer");
|
|
822
|
+
externalReferences.delete("console");
|
|
823
|
+
externalReferences.delete("process");
|
|
824
|
+
externalReferences.delete("setTimeout");
|
|
825
|
+
externalReferences.delete("setInterval");
|
|
826
|
+
if (externalReferences.size > 0) {
|
|
827
|
+
throw new Error(`The function being exported as ${locationHint} references external variables: \`${[
|
|
828
|
+
...externalReferences,
|
|
829
|
+
].join("`, `")}\`. Please ensure this function is wrapped in \`EXPORTABLE(() => ...)\`. Fn:\n${fn}`);
|
|
830
|
+
}
|
|
831
|
+
const fnExpression = path.node;
|
|
832
|
+
const ownProps = Object.entries(fn);
|
|
833
|
+
const result = (() => {
|
|
834
|
+
if (ownProps.length > 0) {
|
|
835
|
+
// Need to assign things to it
|
|
836
|
+
const properties = ownProps.map(([key, value]) => {
|
|
837
|
+
return t.objectProperty(identifierOrLiteral(key), convertToIdentifierViaAST(file, value, `${locationHint}.${key}`, `${locationHint}['${key}']`));
|
|
838
|
+
});
|
|
839
|
+
return {
|
|
840
|
+
functionWithoutOwnAttributesAST: fnExpression,
|
|
841
|
+
ast: t.callExpression(t.memberExpression(t.identifier("Object"), t.identifier("assign")), [fnExpression, t.objectExpression(properties)]),
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
else {
|
|
845
|
+
return {
|
|
846
|
+
functionWithoutOwnAttributesAST: fnExpression,
|
|
847
|
+
ast: fnExpression,
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
})();
|
|
851
|
+
file._funcToAstCache.set(fn, result);
|
|
852
|
+
return result;
|
|
853
|
+
}
|
|
854
|
+
function parseExpressionViaDoc(funcString) {
|
|
855
|
+
const doc = (0, parser_1.parse)(`const f = ${funcString}`, {
|
|
856
|
+
sourceType: "module",
|
|
857
|
+
plugins: ["typescript"],
|
|
858
|
+
});
|
|
859
|
+
let result = null;
|
|
860
|
+
(0, traverse_1.default)(doc, {
|
|
861
|
+
VariableDeclaration(path) {
|
|
862
|
+
result = path.get("declarations.0.init");
|
|
863
|
+
path.stop();
|
|
864
|
+
},
|
|
865
|
+
});
|
|
866
|
+
if (!result) {
|
|
867
|
+
throw new Error(`graphile-export internal error - failed to find the variable declaration (?!!)`);
|
|
868
|
+
}
|
|
869
|
+
return result;
|
|
870
|
+
}
|
|
871
|
+
function _funcToAst(fn, locationHint, _nameHint) {
|
|
782
872
|
const funcString = fn.toString().trim();
|
|
783
873
|
try {
|
|
784
|
-
const
|
|
785
|
-
|
|
786
|
-
plugins: ["typescript"],
|
|
787
|
-
});
|
|
874
|
+
const path = parseExpressionViaDoc(funcString);
|
|
875
|
+
const result = path.node;
|
|
788
876
|
if (result.type !== "FunctionExpression" &&
|
|
789
877
|
result.type !== "ArrowFunctionExpression") {
|
|
790
878
|
if (result.type === "ClassExpression") {
|
|
@@ -793,7 +881,7 @@ Object.defineProperty(${result.id?.name ?? "MyClass"}, '$$export', { value: { mo
|
|
|
793
881
|
}
|
|
794
882
|
throw new Error(`Expected FunctionExpression or ArrowFunctionExpression but saw ${result.type}`);
|
|
795
883
|
}
|
|
796
|
-
return
|
|
884
|
+
return path;
|
|
797
885
|
}
|
|
798
886
|
catch (e) {
|
|
799
887
|
if (e.retry === false) {
|
|
@@ -811,15 +899,13 @@ Object.defineProperty(${result.id?.name ?? "MyClass"}, '$$export', { value: { mo
|
|
|
811
899
|
const modifiedDefinition = funcString.startsWith("async ")
|
|
812
900
|
? "async function " + funcString.slice(6)
|
|
813
901
|
: "function " + funcString;
|
|
814
|
-
const
|
|
815
|
-
|
|
816
|
-
plugins: ["typescript"],
|
|
817
|
-
});
|
|
902
|
+
const path = parseExpressionViaDoc(modifiedDefinition);
|
|
903
|
+
const result = path.node;
|
|
818
904
|
if (result.type !== "FunctionExpression" &&
|
|
819
905
|
result.type !== "ArrowFunctionExpression") {
|
|
820
906
|
throw new Error(`Expected FunctionExpression or ArrowFunctionExpression but saw ${result.type}`);
|
|
821
907
|
}
|
|
822
|
-
return
|
|
908
|
+
return path;
|
|
823
909
|
}
|
|
824
910
|
catch {
|
|
825
911
|
throw new Error(`Function export error at ${locationHint} - failed to process function definition '${trimDef(fn.toString())}'\n ${String(e.stack ?? e)
|
|
@@ -848,14 +934,9 @@ function exportSchemaGraphQLJS({ config, customTypes, customDirectives, file, })
|
|
|
848
934
|
? t.arrayExpression(customDirectives.map((directive) => file.declareDirective(directive)))
|
|
849
935
|
: null,
|
|
850
936
|
extensions: extensions(file, config.extensions, "schema.extensions", "schema.extensions"),
|
|
851
|
-
enableDeferStream:
|
|
852
|
-
/*
|
|
853
|
-
// TODO: use the below once https://github.com/graphql/graphql-js/pull/3450 is fixed:
|
|
854
|
-
enableDeferStream:
|
|
855
|
-
config.enableDeferStream != null
|
|
937
|
+
enableDeferStream: config.enableDeferStream != null
|
|
856
938
|
? t.booleanLiteral(config.enableDeferStream)
|
|
857
939
|
: null,
|
|
858
|
-
*/
|
|
859
940
|
assumeValid: null, // TODO: t.booleanLiteral(true),
|
|
860
941
|
}));
|
|
861
942
|
}
|
|
@@ -866,19 +947,30 @@ function exportSchemaGraphQLJS({ config, customTypes, customDirectives, file, })
|
|
|
866
947
|
*/
|
|
867
948
|
function exportSchemaTypeDefs({ schema, customTypes, file, }) {
|
|
868
949
|
const typeDefsExportName = file.makeVariable("typeDefs");
|
|
869
|
-
const
|
|
950
|
+
const objectPlansProperties = Object.create(null);
|
|
951
|
+
const interfacePlansProperties = Object.create(null);
|
|
952
|
+
const unionPlansProperties = Object.create(null);
|
|
953
|
+
const inputObjectPlansProperties = Object.create(null);
|
|
954
|
+
const scalarPlansProperties = Object.create(null);
|
|
955
|
+
const enumPlansProperties = Object.create(null);
|
|
870
956
|
const schemaExportName = file.makeVariable("schema");
|
|
871
957
|
const typeDefsString = (0, graphql_1.printSchema)(schema);
|
|
872
958
|
const graphqlAST = t.templateLiteral([t.templateElement({ raw: typeDefsString.replace(/[\\`]/g, "\\$&") })], []);
|
|
873
959
|
graphqlAST.leadingComments = [
|
|
874
960
|
{ type: "CommentBlock", value: " GraphQL " },
|
|
875
961
|
];
|
|
876
|
-
const plansProperties = [];
|
|
877
962
|
customTypes.forEach((type) => {
|
|
878
963
|
if (type instanceof graphql_1.GraphQLObjectType) {
|
|
879
|
-
const typeProperties =
|
|
964
|
+
const typeProperties = Object.create(null);
|
|
965
|
+
const plansProperties = Object.create(null);
|
|
880
966
|
if (type.extensions.grafast?.assertStep) {
|
|
881
|
-
typeProperties.
|
|
967
|
+
typeProperties.assertStep = convertToIdentifierViaAST(file, type.extensions.grafast.assertStep, `${type.name}AssertStep`, `${type.name}.extensions.assertStep`);
|
|
968
|
+
}
|
|
969
|
+
if (type.isTypeOf) {
|
|
970
|
+
typeProperties.isTypeOf = convertToIdentifierViaAST(file, type.isTypeOf, `${type.name}IsTypeOf`, `${type.name}.extensions.isTypeOf`);
|
|
971
|
+
}
|
|
972
|
+
if (type.extensions.grafast?.planType) {
|
|
973
|
+
typeProperties.planType = convertToIdentifierViaAST(file, type.extensions.grafast.planType, `${type.name}PlanType`, `${type.name}.extensions.planType`);
|
|
882
974
|
}
|
|
883
975
|
for (const [fieldName, field] of Object.entries(type.toConfig().fields)) {
|
|
884
976
|
// Use shorthand if there's only a `plan` and nothing else
|
|
@@ -899,9 +991,38 @@ function exportSchemaTypeDefs({ schema, customTypes, file, }) {
|
|
|
899
991
|
const args = field.args
|
|
900
992
|
? Object.entries(field.args)
|
|
901
993
|
.map(([argName, arg]) => {
|
|
902
|
-
|
|
994
|
+
if (arg.extensions) {
|
|
995
|
+
const { grafast, ...rest } = arg.extensions;
|
|
996
|
+
const extensionsAST = extensions(file, rest, `${type.name}.${fieldName}.${argName}`, `${type.name}.fields[${fieldName}].args[${argName}].extensions`);
|
|
997
|
+
if (!extensionsAST) {
|
|
998
|
+
if (!grafast)
|
|
999
|
+
return null;
|
|
1000
|
+
const keys = Object.keys(grafast);
|
|
1001
|
+
if (keys.length === 1 && keys[0] === "applyPlan") {
|
|
1002
|
+
// Shorthand
|
|
1003
|
+
return t.objectProperty(identifierOrLiteral(argName), convertToIdentifierViaAST(file, grafast.applyPlan, `${type.name}.${fieldName}${argName}ApplyPlan`, `${type.name}.fields[${fieldName}].args[${argName}].applyPlan`));
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
return t.objectProperty(identifierOrLiteral(argName), t.objectExpression([
|
|
1007
|
+
...objectToObjectProperties({
|
|
1008
|
+
extensions: extensionsAST,
|
|
1009
|
+
}),
|
|
1010
|
+
...(grafast
|
|
1011
|
+
? Object.entries(grafast)
|
|
1012
|
+
.map(([k, v]) => {
|
|
1013
|
+
if (v == null)
|
|
1014
|
+
return null;
|
|
1015
|
+
return t.objectProperty(t.identifier(k), convertToIdentifierViaAST(file, grafast.applyPlan, `${type.name}.${fieldName}${argName}${k}`, `${type.name}.fields[${fieldName}].args[${argName}].extensions.grafast[${k}]`));
|
|
1016
|
+
})
|
|
1017
|
+
.filter(utils_js_1.isNotNullish)
|
|
1018
|
+
: []),
|
|
1019
|
+
]));
|
|
1020
|
+
}
|
|
1021
|
+
else {
|
|
1022
|
+
return null;
|
|
1023
|
+
}
|
|
903
1024
|
})
|
|
904
|
-
.filter(isNotNullish)
|
|
1025
|
+
.filter(utils_js_1.isNotNullish)
|
|
905
1026
|
: null;
|
|
906
1027
|
const argsAST = args && args.length ? t.objectExpression(args) : null;
|
|
907
1028
|
if (!planAST && !subscribePlanAST && !resolveAST && !subscribeAST) {
|
|
@@ -925,24 +1046,69 @@ function exportSchemaTypeDefs({ schema, customTypes, file, }) {
|
|
|
925
1046
|
subscribe: subscribeAST,
|
|
926
1047
|
args: argsAST,
|
|
927
1048
|
}));
|
|
928
|
-
|
|
1049
|
+
plansProperties[fieldName] = fieldSpec;
|
|
929
1050
|
}
|
|
930
|
-
|
|
1051
|
+
setIfNotEmpty(typeProperties, "plans", plansProperties, true);
|
|
1052
|
+
setIfNotEmpty(objectPlansProperties, type.name, typeProperties, false);
|
|
931
1053
|
}
|
|
932
1054
|
else if (type instanceof graphql_1.GraphQLInputObjectType) {
|
|
933
|
-
const typeProperties =
|
|
1055
|
+
const typeProperties = Object.create(null);
|
|
1056
|
+
const plansProperties = Object.create(null);
|
|
1057
|
+
if (type.extensions?.grafast?.baked) {
|
|
1058
|
+
typeProperties.baked = convertToIdentifierViaAST(file, type.extensions?.grafast.baked, `${type.name}.inputPlan`, `${type.name}.extensions.grafast.baked`);
|
|
1059
|
+
}
|
|
934
1060
|
for (const [fieldName, field] of Object.entries(type.toConfig().fields)) {
|
|
935
|
-
|
|
1061
|
+
if (!field.extensions)
|
|
1062
|
+
continue;
|
|
1063
|
+
const { grafast, ...rest } = field.extensions;
|
|
1064
|
+
const extensionsAST = extensions(file, rest, `${type.name}_${fieldName}Extensions`, `${type.name}.fields[${fieldName}].extensions`);
|
|
1065
|
+
if (!extensionsAST) {
|
|
1066
|
+
if (!grafast)
|
|
1067
|
+
continue;
|
|
1068
|
+
const keys = Object.keys(grafast);
|
|
1069
|
+
if (keys.length === 1 && keys[0] === "apply") {
|
|
1070
|
+
plansProperties[fieldName] = convertToIdentifierViaAST(file, grafast.apply, `${type.name}.${fieldName}Apply`, `${type.name}.fields[${fieldName}].extensions.grafast.apply`);
|
|
1071
|
+
continue;
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
plansProperties[fieldName] = t.objectExpression([
|
|
1075
|
+
...objectToObjectProperties({
|
|
1076
|
+
extensions: extensionsAST,
|
|
1077
|
+
}),
|
|
1078
|
+
...(grafast
|
|
1079
|
+
? Object.entries(grafast)
|
|
1080
|
+
.map(([k, v]) => {
|
|
1081
|
+
if (v == null)
|
|
1082
|
+
return null;
|
|
1083
|
+
return t.objectProperty(t.identifier(k), convertToIdentifierViaAST(file, v, `${type.name}.${fieldName}${k}`, `${type.name}.fields[${fieldName}].extensions.grafast[${k}]`));
|
|
1084
|
+
})
|
|
1085
|
+
.filter(utils_js_1.isNotNullish)
|
|
1086
|
+
: []),
|
|
1087
|
+
]);
|
|
936
1088
|
}
|
|
937
|
-
|
|
1089
|
+
setIfNotEmpty(typeProperties, "plans", plansProperties, true);
|
|
1090
|
+
setIfNotEmpty(inputObjectPlansProperties, type.name, typeProperties, false);
|
|
938
1091
|
}
|
|
939
1092
|
else if (type instanceof graphql_1.GraphQLInterfaceType ||
|
|
940
1093
|
type instanceof graphql_1.GraphQLUnionType) {
|
|
941
1094
|
const config = type.toConfig();
|
|
942
|
-
if (config.resolveType
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
1095
|
+
if (config.resolveType ||
|
|
1096
|
+
config.extensions.grafast?.toSpecifier ||
|
|
1097
|
+
config.extensions.grafast?.planType) {
|
|
1098
|
+
const target = type instanceof graphql_1.GraphQLInterfaceType
|
|
1099
|
+
? interfacePlansProperties
|
|
1100
|
+
: unionPlansProperties;
|
|
1101
|
+
target[type.name] = t.objectExpression(objectToObjectProperties({
|
|
1102
|
+
resolveType: type.resolveType
|
|
1103
|
+
? convertToIdentifierViaAST(file, type.resolveType, `${type.name}ResolveType`, `${type.name}.resolveType`)
|
|
1104
|
+
: null,
|
|
1105
|
+
toSpecifier: type.extensions?.grafast?.toSpecifier
|
|
1106
|
+
? convertToIdentifierViaAST(file, type.extensions?.grafast?.toSpecifier, `${type.name}ToSpecifier`, `${type.name}.toSpecifier`)
|
|
1107
|
+
: null,
|
|
1108
|
+
planType: type.extensions?.grafast?.planType
|
|
1109
|
+
? convertToIdentifierViaAST(file, type.extensions?.grafast?.planType, `${type.name}PlanType`, `${type.name}.planType`)
|
|
1110
|
+
: null,
|
|
1111
|
+
}));
|
|
946
1112
|
}
|
|
947
1113
|
}
|
|
948
1114
|
else if (type instanceof graphql_1.GraphQLScalarType) {
|
|
@@ -950,36 +1116,65 @@ function exportSchemaTypeDefs({ schema, customTypes, file, }) {
|
|
|
950
1116
|
const planAST = config.extensions.grafast?.plan
|
|
951
1117
|
? convertToIdentifierViaAST(file, config.extensions?.grafast?.plan, `${type.name}Plan`, `${type.name}.extensions.grafast.plan`)
|
|
952
1118
|
: null;
|
|
953
|
-
if (planAST
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1119
|
+
if (planAST ||
|
|
1120
|
+
type.serialize !== graphql_1.GraphQLScalarType.prototype.serialize ||
|
|
1121
|
+
type.parseValue !== graphql_1.GraphQLScalarType.prototype.parseValue ||
|
|
1122
|
+
type.parseLiteral !== graphql_1.GraphQLScalarType.prototype.parseLiteral) {
|
|
1123
|
+
scalarPlansProperties[type.name] = t.objectExpression(objectToObjectProperties({
|
|
1124
|
+
serialize: type.serialize !== graphql_1.GraphQLScalarType.prototype.serialize
|
|
1125
|
+
? convertToIdentifierViaAST(file, type.serialize, `${type.name}Serialize`, `${type.name}.serialize`)
|
|
1126
|
+
: null,
|
|
1127
|
+
parseValue: type.parseValue !== graphql_1.GraphQLScalarType.prototype.parseValue
|
|
1128
|
+
? convertToIdentifierViaAST(file, type.parseValue, `${type.name}ParseValue`, `${type.name}.parseValue`)
|
|
1129
|
+
: null,
|
|
1130
|
+
parseLiteral: type.parseLiteral !== graphql_1.GraphQLScalarType.prototype.parseLiteral
|
|
1131
|
+
? convertToIdentifierViaAST(file, type.parseLiteral, `${type.name}ParseLiteral`, `${type.name}.parseLiteral`)
|
|
1132
|
+
: null,
|
|
958
1133
|
plan: planAST,
|
|
959
|
-
}))
|
|
1134
|
+
}));
|
|
960
1135
|
}
|
|
961
1136
|
}
|
|
962
1137
|
else if (type instanceof graphql_1.GraphQLEnumType) {
|
|
963
1138
|
const config = type.toConfig();
|
|
964
|
-
const
|
|
1139
|
+
const typeProperties = Object.create(null);
|
|
1140
|
+
const enumValueProperties = Object.create(null);
|
|
965
1141
|
for (const [enumValueName, enumValueConfig] of Object.entries(config.values)) {
|
|
966
1142
|
const valueAST = enumValueConfig.value !== undefined &&
|
|
967
1143
|
enumValueConfig.value !== enumValueName
|
|
968
1144
|
? convertToIdentifierViaAST(file, enumValueConfig.value, `${type.name}_${enumValueName}`, `${type.name}.values[${enumValueName}].value`)
|
|
969
1145
|
: null;
|
|
970
|
-
const
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1146
|
+
const { grafast, ...rest } = enumValueConfig.extensions ?? {};
|
|
1147
|
+
const extensionsAST = extensions(file, rest, `${type.name}_${enumValueName}Extensions`, `${type.name}.values[${enumValueName}].extensions`);
|
|
1148
|
+
if (!valueAST && !extensionsAST) {
|
|
1149
|
+
if (!grafast)
|
|
1150
|
+
continue;
|
|
1151
|
+
const keys = Object.keys(grafast);
|
|
1152
|
+
if (keys.length === 1 && keys[0] === "apply") {
|
|
1153
|
+
enumValueProperties[enumValueName] = convertToIdentifierViaAST(file, grafast.apply, `${type.name}.${enumValueName}Apply`, `${type.name}.values[${enumValueName}].extensions.grafast.apply`);
|
|
1154
|
+
continue;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
const grafastProperties = grafast
|
|
1158
|
+
? Object.entries(grafast)
|
|
1159
|
+
.map(([k, v]) => {
|
|
1160
|
+
if (v == null)
|
|
1161
|
+
return null;
|
|
1162
|
+
return t.objectProperty(t.identifier(k), convertToIdentifierViaAST(file, v, `${type.name}.${enumValueName}${k}`, `${type.name}.values[${enumValueName}].extensions.grafast[${k}]`));
|
|
1163
|
+
})
|
|
1164
|
+
.filter(utils_js_1.isNotNullish)
|
|
1165
|
+
: [];
|
|
1166
|
+
if (valueAST || extensionsAST || grafastProperties.length) {
|
|
1167
|
+
enumValueProperties[enumValueName] = t.objectExpression([
|
|
1168
|
+
...objectToObjectProperties({
|
|
1169
|
+
value: valueAST,
|
|
1170
|
+
extensions: extensionsAST,
|
|
1171
|
+
}),
|
|
1172
|
+
...grafastProperties,
|
|
1173
|
+
]);
|
|
978
1174
|
}
|
|
979
1175
|
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
}
|
|
1176
|
+
setIfNotEmpty(typeProperties, "values", enumValueProperties, true);
|
|
1177
|
+
setIfNotEmpty(enumPlansProperties, type.name, typeProperties, false);
|
|
983
1178
|
}
|
|
984
1179
|
else {
|
|
985
1180
|
const never = type;
|
|
@@ -989,17 +1184,40 @@ function exportSchemaTypeDefs({ schema, customTypes, file, }) {
|
|
|
989
1184
|
const typeDefs = t.exportNamedDeclaration(t.variableDeclaration("const", [
|
|
990
1185
|
t.variableDeclarator(typeDefsExportName, graphqlAST),
|
|
991
1186
|
]));
|
|
992
|
-
const plans = t.exportNamedDeclaration(t.variableDeclaration("const", [
|
|
993
|
-
t.variableDeclarator(plansExportName, t.objectExpression(plansProperties)),
|
|
994
|
-
]));
|
|
995
1187
|
file.addStatements(typeDefs);
|
|
996
|
-
|
|
1188
|
+
const typeDefsEtc = {
|
|
1189
|
+
typeDefs: typeDefsExportName,
|
|
1190
|
+
};
|
|
1191
|
+
const stuff = Object.create(null);
|
|
1192
|
+
setIfNotEmpty(stuff, "objects", objectPlansProperties, [
|
|
1193
|
+
schema.getQueryType()?.name,
|
|
1194
|
+
schema.getMutationType()?.name,
|
|
1195
|
+
schema.getSubscriptionType()?.name,
|
|
1196
|
+
].filter((n) => n != null));
|
|
1197
|
+
setIfNotEmpty(stuff, "interfaces", interfacePlansProperties, true);
|
|
1198
|
+
setIfNotEmpty(stuff, "unions", unionPlansProperties, true);
|
|
1199
|
+
setIfNotEmpty(stuff, "inputObjects", inputObjectPlansProperties, true);
|
|
1200
|
+
setIfNotEmpty(stuff, "scalars", scalarPlansProperties, true);
|
|
1201
|
+
setIfNotEmpty(stuff, "enums", enumPlansProperties, true);
|
|
1202
|
+
const todos = [];
|
|
1203
|
+
for (const [key, props] of Object.entries(stuff)) {
|
|
1204
|
+
const exportName = file.makeVariable(key);
|
|
1205
|
+
// Do this afterwards so all the variables are reserved first.
|
|
1206
|
+
todos.push(() => {
|
|
1207
|
+
const plans = t.exportNamedDeclaration(t.variableDeclaration("const", [
|
|
1208
|
+
t.variableDeclarator(exportName, props),
|
|
1209
|
+
]));
|
|
1210
|
+
file.addStatements(plans);
|
|
1211
|
+
typeDefsEtc[key] = exportName;
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
// Now all variables are declared, we can populate them
|
|
1215
|
+
for (const todo of todos) {
|
|
1216
|
+
todo();
|
|
1217
|
+
}
|
|
997
1218
|
const makeGrafastSchemaAST = file.import("grafast", "makeGrafastSchema");
|
|
998
1219
|
const schemaAST = t.callExpression(makeGrafastSchemaAST, [
|
|
999
|
-
t.objectExpression(objectToObjectProperties(
|
|
1000
|
-
typeDefs: typeDefsExportName,
|
|
1001
|
-
plans: plansExportName,
|
|
1002
|
-
})),
|
|
1220
|
+
t.objectExpression(objectToObjectProperties(typeDefsEtc)),
|
|
1003
1221
|
]);
|
|
1004
1222
|
file.addStatements(t.exportNamedDeclaration(t.variableDeclaration("const", [
|
|
1005
1223
|
t.variableDeclarator(schemaExportName, schemaAST),
|
|
@@ -1016,6 +1234,11 @@ async function exportSchemaAsString(schema, options) {
|
|
|
1016
1234
|
"defer",
|
|
1017
1235
|
"stream",
|
|
1018
1236
|
].includes(d.name));
|
|
1237
|
+
if (process.env.ENABLE_DEFER_STREAM === "1" ||
|
|
1238
|
+
config.directives.some((d) => d.name === "defer" || d.name === "skip")) {
|
|
1239
|
+
// Ref: https://github.com/graphql/graphql-js/pull/3450
|
|
1240
|
+
config.enableDeferStream = true;
|
|
1241
|
+
}
|
|
1019
1242
|
const file = new CodegenFile(options);
|
|
1020
1243
|
const schemaExportDetails = {
|
|
1021
1244
|
schema,
|
|
@@ -1031,16 +1254,79 @@ async function exportSchemaAsString(schema, options) {
|
|
|
1031
1254
|
else {
|
|
1032
1255
|
exportSchemaGraphQLJS(schemaExportDetails);
|
|
1033
1256
|
}
|
|
1257
|
+
return exportFile(file, options);
|
|
1258
|
+
}
|
|
1259
|
+
function exportFile(file, { disableOptimize }) {
|
|
1034
1260
|
const ast = file.toAST();
|
|
1035
|
-
const optimizedAst = (0, index_js_1.optimize)(ast);
|
|
1261
|
+
const optimizedAst = disableOptimize ? ast : (0, index_js_1.optimize)(ast);
|
|
1036
1262
|
const { code } = reallyGenerate(optimizedAst, {});
|
|
1037
1263
|
return { code };
|
|
1038
1264
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
const
|
|
1042
|
-
const
|
|
1043
|
-
const
|
|
1265
|
+
async function exportValueAsString(name, value, options) {
|
|
1266
|
+
const file = new CodegenFile(options);
|
|
1267
|
+
const exportName = file.makeVariable(name);
|
|
1268
|
+
const valueAST = convertToIdentifierViaAST(file, value, name, name);
|
|
1269
|
+
file.addStatements(t.exportNamedDeclaration(t.variableDeclaration("const", [
|
|
1270
|
+
t.variableDeclarator(exportName, valueAST),
|
|
1271
|
+
])));
|
|
1272
|
+
return exportFile(file, options);
|
|
1273
|
+
}
|
|
1274
|
+
async function loadESLint() {
|
|
1275
|
+
try {
|
|
1276
|
+
return await import("eslint");
|
|
1277
|
+
}
|
|
1278
|
+
catch (e) {
|
|
1279
|
+
return null;
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
async function lint(code, rawFilePath) {
|
|
1283
|
+
const eslintModule = await loadESLint();
|
|
1284
|
+
if (eslintModule == null) {
|
|
1285
|
+
console.warn(`graphile-export could not find 'eslint' so disabling additional checks`);
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1288
|
+
const filePath = typeof rawFilePath === "string" ? rawFilePath : rawFilePath.pathname;
|
|
1289
|
+
const { ESLint } = eslintModule;
|
|
1290
|
+
const eslint = new ESLint({
|
|
1291
|
+
overrideConfigFile: true, // Don't use external config
|
|
1292
|
+
allowInlineConfig: false, // Ignore `/* eslint-disable ... */` comments
|
|
1293
|
+
overrideConfig: {
|
|
1294
|
+
linterOptions: { reportUnusedDisableDirectives: false },
|
|
1295
|
+
languageOptions: {
|
|
1296
|
+
ecmaVersion: 2022,
|
|
1297
|
+
sourceType: "module",
|
|
1298
|
+
},
|
|
1299
|
+
rules: {
|
|
1300
|
+
"no-use-before-define": [
|
|
1301
|
+
"error",
|
|
1302
|
+
{
|
|
1303
|
+
functions: false,
|
|
1304
|
+
classes: false,
|
|
1305
|
+
// We often have cyclic dependencies between types, this is handled via callbacks, so we don't care about that.
|
|
1306
|
+
variables: false,
|
|
1307
|
+
allowNamedExports: false,
|
|
1308
|
+
},
|
|
1309
|
+
],
|
|
1310
|
+
},
|
|
1311
|
+
},
|
|
1312
|
+
});
|
|
1313
|
+
const results = await eslint.lintText(code, {
|
|
1314
|
+
warnIgnored: true,
|
|
1315
|
+
// DO NOT PASS THE `filePath`; it can result in the file being ignored!
|
|
1316
|
+
});
|
|
1317
|
+
if (results.length !== 1) {
|
|
1318
|
+
console.dir({ filePath, results });
|
|
1319
|
+
throw new Error(`Expected ESLint results to have exactly one entry`);
|
|
1320
|
+
}
|
|
1321
|
+
const [result] = results;
|
|
1322
|
+
if (result.warningCount > 0 || result.errorCount > 0) {
|
|
1323
|
+
console.log(`ESLint found problems in the export; this likely indicates some issue with \`EXPORTABLE\` calls`);
|
|
1324
|
+
const formatter = await eslint.loadFormatter("stylish");
|
|
1325
|
+
const output = formatter.format(results);
|
|
1326
|
+
console.log(output);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
async function format(toFormat, toPath, options) {
|
|
1044
1330
|
if (options.prettier) {
|
|
1045
1331
|
const prettier = await import("prettier");
|
|
1046
1332
|
const config = await prettier.resolveConfig(toPath.toString());
|
|
@@ -1048,11 +1334,65 @@ async function exportSchema(schema, toPath, options = {}) {
|
|
|
1048
1334
|
parser: "babel",
|
|
1049
1335
|
...(config ?? {}),
|
|
1050
1336
|
});
|
|
1051
|
-
|
|
1337
|
+
return formatted;
|
|
1052
1338
|
}
|
|
1053
1339
|
else {
|
|
1054
|
-
|
|
1340
|
+
return toFormat;
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
const HEADER = `/* eslint-disable graphile-export/export-instances, graphile-export/export-methods, graphile-export/exhaustive-deps */\n`;
|
|
1344
|
+
async function exportSchema(schema, toPath, options = {}) {
|
|
1345
|
+
const { code } = await exportSchemaAsString(schema, options);
|
|
1346
|
+
const toFormat = HEADER + code;
|
|
1347
|
+
const formatted = await format(toFormat, toPath, options);
|
|
1348
|
+
await (0, promises_1.writeFile)(toPath, formatted);
|
|
1349
|
+
await lint(formatted, toPath);
|
|
1350
|
+
}
|
|
1351
|
+
/**
|
|
1352
|
+
* Returns `false` for nullish values and empty objects, true otherwise.
|
|
1353
|
+
*/
|
|
1354
|
+
function isNotEmpty(value) {
|
|
1355
|
+
if (value == null)
|
|
1356
|
+
return false;
|
|
1357
|
+
if (typeof value !== "object")
|
|
1358
|
+
return true;
|
|
1359
|
+
const proto = Object.getPrototypeOf(value);
|
|
1360
|
+
if (proto !== null && proto !== Object.prototype)
|
|
1361
|
+
return true;
|
|
1362
|
+
if (Object.getOwnPropertyNames(value).length === 0 &&
|
|
1363
|
+
Object.getOwnPropertySymbols(value).length === 0) {
|
|
1364
|
+
// Empty object!
|
|
1365
|
+
return false;
|
|
1366
|
+
}
|
|
1367
|
+
return true;
|
|
1368
|
+
}
|
|
1369
|
+
function setIfNotEmpty(target, key, value, sort) {
|
|
1370
|
+
if (Object.keys(value).length > 0) {
|
|
1371
|
+
const entries = Object.entries(value);
|
|
1372
|
+
if (typeof sort === "boolean") {
|
|
1373
|
+
entries.sort((a, z) => a[0].localeCompare(z[0], "und"));
|
|
1374
|
+
}
|
|
1375
|
+
else if (sort) {
|
|
1376
|
+
entries.sort((a, z) => {
|
|
1377
|
+
const ka = a[0];
|
|
1378
|
+
const kz = z[0];
|
|
1379
|
+
// First, compare keys against the specific defined order
|
|
1380
|
+
const sa = sort.indexOf(ka);
|
|
1381
|
+
const sz = sort.indexOf(kz);
|
|
1382
|
+
if (sa >= 0) {
|
|
1383
|
+
if (sz < 0)
|
|
1384
|
+
return -1;
|
|
1385
|
+
return sa - sz;
|
|
1386
|
+
}
|
|
1387
|
+
else if (sz >= 0) {
|
|
1388
|
+
return 1;
|
|
1389
|
+
}
|
|
1390
|
+
// Failing that, compare them alphabetically
|
|
1391
|
+
return ka.localeCompare(kz, "und");
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
const finalProps = entries.map(([k, v]) => t.objectProperty(identifierOrLiteral(k), v));
|
|
1395
|
+
target[key] = t.objectExpression(finalProps);
|
|
1055
1396
|
}
|
|
1056
1397
|
}
|
|
1057
|
-
exports.exportSchema = exportSchema;
|
|
1058
1398
|
//# sourceMappingURL=exportSchema.js.map
|