graphile-export 0.0.2-0.2
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 +28 -0
- package/LICENSE.md +20 -0
- package/README.md +3 -0
- package/dist/exportSchema.d.ts +14 -0
- package/dist/exportSchema.d.ts.map +1 -0
- package/dist/exportSchema.js +1004 -0
- package/dist/exportSchema.js.map +1 -0
- package/dist/helpers.d.ts +2 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +15 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces.d.ts +28 -0
- package/dist/interfaces.d.ts.map +1 -0
- package/dist/interfaces.js +3 -0
- package/dist/interfaces.js.map +1 -0
- package/dist/optimize/index.d.ts +3 -0
- package/dist/optimize/index.d.ts.map +1 -0
- package/dist/optimize/index.js +176 -0
- package/dist/optimize/index.js.map +1 -0
- package/dist/wellKnown.d.ts +14 -0
- package/dist/wellKnown.d.ts.map +1 -0
- package/dist/wellKnown.js +106 -0
- package/dist/wellKnown.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,1004 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.exportSchema = exports.exportSchemaAsString = exports.objectNullPrototype = exports.isNotNullish = exports.canRepresentAsIdentifier = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const generator_1 = tslib_1.__importDefault(require("@babel/generator"));
|
|
6
|
+
const parser_1 = require("@babel/parser");
|
|
7
|
+
const template_1 = tslib_1.__importDefault(require("@babel/template"));
|
|
8
|
+
const t = tslib_1.__importStar(require("@babel/types"));
|
|
9
|
+
const promises_1 = require("fs/promises");
|
|
10
|
+
const graphql_1 = require("graphql");
|
|
11
|
+
const pg_sql2_1 = require("pg-sql2");
|
|
12
|
+
const util_1 = require("util");
|
|
13
|
+
const index_js_1 = require("./optimize/index.js");
|
|
14
|
+
const wellKnown_js_1 = require("./wellKnown.js");
|
|
15
|
+
// Do **NOT** allow variables that start with `__`!
|
|
16
|
+
const canRepresentAsIdentifier = (key) => /^(?:[a-z$]|_[a-z0-9$])[a-z0-9_$]*$/i.test(key);
|
|
17
|
+
exports.canRepresentAsIdentifier = canRepresentAsIdentifier;
|
|
18
|
+
function identifierOrLiteral(key) {
|
|
19
|
+
if (typeof key === "number") {
|
|
20
|
+
return t.numericLiteral(key);
|
|
21
|
+
}
|
|
22
|
+
if ((0, exports.canRepresentAsIdentifier)(key)) {
|
|
23
|
+
return t.identifier(key);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
return t.stringLiteral(key);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function locationHintToIdentifierName(locationHint) {
|
|
30
|
+
let result = locationHint;
|
|
31
|
+
result = result.replace(/[[.]/g, "__").replace(/\]/g, "");
|
|
32
|
+
result = result.replace(/[^a-z0-9_]+/gi, "");
|
|
33
|
+
result = result.replace(/^([0-9])/, "_$1");
|
|
34
|
+
if (result.includes("scope")) {
|
|
35
|
+
console.log({ locationHint, result });
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
function getNameForThing(thing, locationHint, baseNameHint) {
|
|
40
|
+
if (typeof thing === "function") {
|
|
41
|
+
if (baseNameHint) {
|
|
42
|
+
return baseNameHint;
|
|
43
|
+
}
|
|
44
|
+
const thingName = thing.name ?? thing.displayName ?? null;
|
|
45
|
+
if (thingName) {
|
|
46
|
+
return (baseNameHint ? baseNameHint + "-" : "") + thingName;
|
|
47
|
+
}
|
|
48
|
+
return locationHintToIdentifierName(locationHint);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const thingConstructor = thing.constructor;
|
|
52
|
+
const thingConstructorNameRaw = thingConstructor?.name ?? thingConstructor?.displayName ?? null;
|
|
53
|
+
const thingConstructorName = ["Array", "Object", "Set", "Map"].includes(thingConstructorNameRaw)
|
|
54
|
+
? null
|
|
55
|
+
: thingConstructorNameRaw;
|
|
56
|
+
const thingName = thing.name ?? thing.displayName ?? null;
|
|
57
|
+
const name = thingConstructorName && thingName
|
|
58
|
+
? `${thingName}${thingConstructorName}`
|
|
59
|
+
: thingName ?? thingConstructorName ?? null;
|
|
60
|
+
return baseNameHint || name
|
|
61
|
+
? (baseNameHint ?? "") + (baseNameHint && name ? "-" : "") + (name ?? "")
|
|
62
|
+
: "value";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function trimDef(def) {
|
|
66
|
+
const str = def.replace(/\s+/g, " ");
|
|
67
|
+
const PREFIX_LENGTH = 60;
|
|
68
|
+
const SUFFIX_LENGTH = 10;
|
|
69
|
+
if (str.length < PREFIX_LENGTH + SUFFIX_LENGTH + 10) {
|
|
70
|
+
return str;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
return (str.slice(0, 0 + PREFIX_LENGTH) +
|
|
74
|
+
"..." +
|
|
75
|
+
str.slice(str.length - SUFFIX_LENGTH));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//const reallyGenerate = (generate as any).default as typeof generate;
|
|
79
|
+
const reallyGenerate = generator_1.default;
|
|
80
|
+
const templateOptions = {
|
|
81
|
+
plugins: ["typescript"],
|
|
82
|
+
};
|
|
83
|
+
function isNotNullish(input) {
|
|
84
|
+
return input != null;
|
|
85
|
+
}
|
|
86
|
+
exports.isNotNullish = isNotNullish;
|
|
87
|
+
function isImportable(thing) {
|
|
88
|
+
return ((typeof thing === "object" || typeof thing === "function") &&
|
|
89
|
+
thing !== null &&
|
|
90
|
+
"$$export" in thing);
|
|
91
|
+
}
|
|
92
|
+
function isExportedFromFactory(thing) {
|
|
93
|
+
return ((typeof thing === "object" || typeof thing === "function") &&
|
|
94
|
+
thing !== null &&
|
|
95
|
+
"$exporter$factory" in thing);
|
|
96
|
+
}
|
|
97
|
+
const BUILTINS = ["Int", "Float", "Boolean", "ID", "String"];
|
|
98
|
+
function isBuiltinType(type) {
|
|
99
|
+
return type.name.startsWith("__") || BUILTINS.includes(type.name);
|
|
100
|
+
}
|
|
101
|
+
class CodegenFile {
|
|
102
|
+
options;
|
|
103
|
+
_variables = Object.assign(Object.create(null), {
|
|
104
|
+
// Reserved variables
|
|
105
|
+
AbortController: true,
|
|
106
|
+
Array: true,
|
|
107
|
+
Buffer: true,
|
|
108
|
+
DOMException: true,
|
|
109
|
+
Error: true,
|
|
110
|
+
Event: true,
|
|
111
|
+
EventTarget: true,
|
|
112
|
+
JSON: true,
|
|
113
|
+
Math: true,
|
|
114
|
+
MessageChannel: true,
|
|
115
|
+
MessageEvent: true,
|
|
116
|
+
MessagePort: true,
|
|
117
|
+
Object: true,
|
|
118
|
+
TextDecoder: true,
|
|
119
|
+
TextEncoder: true,
|
|
120
|
+
URL: true,
|
|
121
|
+
URLSearchParams: true,
|
|
122
|
+
WebAssembly: true,
|
|
123
|
+
__dirname: true,
|
|
124
|
+
__filename: true,
|
|
125
|
+
atob: true,
|
|
126
|
+
btoa: true,
|
|
127
|
+
clearImmediate: true,
|
|
128
|
+
clearInterval: true,
|
|
129
|
+
clearTimeout: true,
|
|
130
|
+
console: true,
|
|
131
|
+
exports: true,
|
|
132
|
+
global: true,
|
|
133
|
+
module: true,
|
|
134
|
+
performance: true,
|
|
135
|
+
process: true,
|
|
136
|
+
queueMicrotask: true,
|
|
137
|
+
require: true,
|
|
138
|
+
setImmediate: true,
|
|
139
|
+
setInterval: true,
|
|
140
|
+
setTimeout: true,
|
|
141
|
+
structuredClone: true,
|
|
142
|
+
});
|
|
143
|
+
_imports = Object.create(null);
|
|
144
|
+
_types = Object.create(null);
|
|
145
|
+
_directives = Object.create(null);
|
|
146
|
+
_statements = [];
|
|
147
|
+
_values = new Map();
|
|
148
|
+
constructor(options) {
|
|
149
|
+
this.options = options;
|
|
150
|
+
}
|
|
151
|
+
addStatements(statements) {
|
|
152
|
+
if (Array.isArray(statements)) {
|
|
153
|
+
this._statements.push(...statements);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
this._statements.push(statements);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
makeVariable(preferredName) {
|
|
160
|
+
const allowedName = preferredName.replace(/[^_a-z0-9]+/gi, "_");
|
|
161
|
+
for (let i = 0; i < 10000; i++) {
|
|
162
|
+
const variableName = allowedName + (i > 0 ? String(i + 1) : "");
|
|
163
|
+
if (!this._variables[variableName]) {
|
|
164
|
+
this._variables[variableName] = true;
|
|
165
|
+
return t.identifier(variableName);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
throw new Error("Could not find a suitable variable name");
|
|
169
|
+
}
|
|
170
|
+
import(fromModule, exportNames = "default", asType = false) {
|
|
171
|
+
if (Array.isArray(exportNames)) {
|
|
172
|
+
const [exportName, ...path] = exportNames;
|
|
173
|
+
if (!exportName) {
|
|
174
|
+
throw new Error("Could not determine the export name");
|
|
175
|
+
}
|
|
176
|
+
const variable = this.importOnly(fromModule, exportName, asType);
|
|
177
|
+
if (path.length) {
|
|
178
|
+
let result = variable;
|
|
179
|
+
for (const pathSegment of path) {
|
|
180
|
+
result = t.memberExpression(result, identifierOrLiteral(pathSegment));
|
|
181
|
+
}
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
return variable;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
const variable = this.importOnly(fromModule, exportNames, asType);
|
|
190
|
+
return variable;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
importOnly(fromModule, exportName = "default", asType = false) {
|
|
194
|
+
const importedModule = this._imports[fromModule] ??
|
|
195
|
+
(this._imports[fromModule] = Object.create(null));
|
|
196
|
+
const existing = importedModule[exportName];
|
|
197
|
+
if (existing) {
|
|
198
|
+
if (!asType) {
|
|
199
|
+
existing.asType = false;
|
|
200
|
+
}
|
|
201
|
+
return existing.variableName;
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
const preferredName = exportName === "default" || exportName === "*"
|
|
205
|
+
? fromModule
|
|
206
|
+
: exportName;
|
|
207
|
+
const variableName = this.makeVariable(preferredName);
|
|
208
|
+
importedModule[exportName] = {
|
|
209
|
+
variableName,
|
|
210
|
+
asType,
|
|
211
|
+
};
|
|
212
|
+
return variableName;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
declareType(type) {
|
|
216
|
+
const existing = this._types[type.name];
|
|
217
|
+
if (existing) {
|
|
218
|
+
if (existing.type !== type) {
|
|
219
|
+
throw new Error("Duplicate types with same name found! Error!");
|
|
220
|
+
}
|
|
221
|
+
return existing.variableName;
|
|
222
|
+
}
|
|
223
|
+
if (BUILTINS.includes(type.name)) {
|
|
224
|
+
return this.importOnly("graphql", "GraphQL" + type.name);
|
|
225
|
+
}
|
|
226
|
+
if (isBuiltinType(type)) {
|
|
227
|
+
throw new Error(`declareType called with introspection type '${type.name}'`);
|
|
228
|
+
}
|
|
229
|
+
const VARIABLE_NAME = this.makeVariable(type.name);
|
|
230
|
+
const spec = {
|
|
231
|
+
type,
|
|
232
|
+
variableName: VARIABLE_NAME,
|
|
233
|
+
declaration: null,
|
|
234
|
+
};
|
|
235
|
+
this._types[type.name] = spec;
|
|
236
|
+
// Must perform declaration _AFTER_ registering type, otherwise we might
|
|
237
|
+
// get infinite recursion.
|
|
238
|
+
spec.declaration = this.makeTypeDeclaration(type, VARIABLE_NAME);
|
|
239
|
+
this.addStatements(spec.declaration);
|
|
240
|
+
return VARIABLE_NAME;
|
|
241
|
+
}
|
|
242
|
+
declareDirective(directive) {
|
|
243
|
+
const existing = this._directives[directive.name];
|
|
244
|
+
if (existing) {
|
|
245
|
+
if (existing.directive !== directive) {
|
|
246
|
+
throw new Error("Duplicate types with same name found! Error!");
|
|
247
|
+
}
|
|
248
|
+
return existing.variableName;
|
|
249
|
+
}
|
|
250
|
+
const config = directive.toConfig();
|
|
251
|
+
const VARIABLE_NAME = this.makeVariable(config.name);
|
|
252
|
+
const spec = {
|
|
253
|
+
directive,
|
|
254
|
+
variableName: VARIABLE_NAME,
|
|
255
|
+
declaration: null,
|
|
256
|
+
};
|
|
257
|
+
this._directives[config.name] = spec;
|
|
258
|
+
const locationHint = `@${config.name}`;
|
|
259
|
+
// Must perform declaration _AFTER_ registering type, otherwise we might
|
|
260
|
+
// get infinite recursion.
|
|
261
|
+
const iDirectiveLocation = this.import("graphql", "DirectiveLocation");
|
|
262
|
+
spec.declaration = declareGraphQLEntity(this, VARIABLE_NAME, "GraphQLDirective", {
|
|
263
|
+
name: t.stringLiteral(config.name),
|
|
264
|
+
description: desc(config.description),
|
|
265
|
+
locations: t.arrayExpression(config.locations.map((l) => t.memberExpression(iDirectiveLocation, identifierOrLiteral(String(l))))),
|
|
266
|
+
args: config.args && Object.keys(config.args).length > 0
|
|
267
|
+
? this.makeFieldArgs(config.args, `${locationHint}.args`, `@${config.name}.args`)
|
|
268
|
+
: null,
|
|
269
|
+
isRepeatable: t.booleanLiteral(config.isRepeatable),
|
|
270
|
+
extensions: extensions(this, config.extensions, `${config.name}.extensions`, `@${config.name}.extensions`),
|
|
271
|
+
});
|
|
272
|
+
this.addStatements(spec.declaration);
|
|
273
|
+
return VARIABLE_NAME;
|
|
274
|
+
}
|
|
275
|
+
typeExpression(type) {
|
|
276
|
+
if (type instanceof graphql_1.GraphQLNonNull) {
|
|
277
|
+
const iGraphQLNonNull = this.import("graphql", "GraphQLNonNull");
|
|
278
|
+
return t.newExpression(iGraphQLNonNull, [
|
|
279
|
+
this.typeExpression(type.ofType),
|
|
280
|
+
]);
|
|
281
|
+
}
|
|
282
|
+
else if (type instanceof graphql_1.GraphQLList) {
|
|
283
|
+
const iGraphQLList = this.import("graphql", "GraphQLList");
|
|
284
|
+
return t.newExpression(iGraphQLList, [this.typeExpression(type.ofType)]);
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
return this.declareType(type);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
makeEnumValue(config, typeName, enumValueName) {
|
|
291
|
+
const locationHint = `${typeName}.values[${JSON.stringify(enumValueName)}]`;
|
|
292
|
+
const mappedConfig = {
|
|
293
|
+
description: desc(config.description),
|
|
294
|
+
value: convertToIdentifierViaAST(this, config.value, `${typeName}.${enumValueName}`, `${locationHint}.value`),
|
|
295
|
+
extensions: extensions(this, config.extensions, `${locationHint}.extensions`, `${typeName}.extensions`),
|
|
296
|
+
deprecationReason: desc(config.deprecationReason),
|
|
297
|
+
};
|
|
298
|
+
return configToAST(mappedConfig);
|
|
299
|
+
}
|
|
300
|
+
// For objects and interfaces
|
|
301
|
+
makeObjectFields(fields, typeName) {
|
|
302
|
+
const obj = Object.entries(fields).reduce((memo, [fieldName, config]) => {
|
|
303
|
+
if (!fieldName.startsWith("__")) {
|
|
304
|
+
const locationHint = `${typeName}.fields[${fieldName}]`;
|
|
305
|
+
const mappedConfig = {
|
|
306
|
+
description: desc(config.description),
|
|
307
|
+
type: this.typeExpression(config.type),
|
|
308
|
+
args: config.args && Object.keys(config.args).length > 0
|
|
309
|
+
? this.makeFieldArgs(config.args, `${typeName}.fields[${fieldName}].args`, `${typeName}.${fieldName}`)
|
|
310
|
+
: null,
|
|
311
|
+
resolve: config.resolve
|
|
312
|
+
? func(this, config.resolve, `${locationHint}.resolve`, `${typeName}.${fieldName}.resolve`)
|
|
313
|
+
: null,
|
|
314
|
+
subscribe: config.subscribe
|
|
315
|
+
? func(this, config.subscribe, `${locationHint}.subscribe`, `${typeName}.${fieldName}.subscribe`)
|
|
316
|
+
: null,
|
|
317
|
+
deprecationReason: desc(config.deprecationReason),
|
|
318
|
+
extensions: extensions(this, config.extensions, `${locationHint}.extensions`, `${typeName}.${fieldName}.extensions`),
|
|
319
|
+
};
|
|
320
|
+
memo[fieldName] = configToAST(mappedConfig);
|
|
321
|
+
}
|
|
322
|
+
return memo;
|
|
323
|
+
}, {});
|
|
324
|
+
return t.objectExpression(objectToObjectProperties(obj));
|
|
325
|
+
}
|
|
326
|
+
makeInputObjectFields(fields, typeName) {
|
|
327
|
+
const obj = Object.entries(fields).reduce((memo, [fieldName, config]) => {
|
|
328
|
+
if (!fieldName.startsWith("__")) {
|
|
329
|
+
const locationHint = `${typeName}.fields[${fieldName}]`;
|
|
330
|
+
const mappedConfig = {
|
|
331
|
+
description: desc(config.description),
|
|
332
|
+
type: this.typeExpression(config.type),
|
|
333
|
+
defaultValue: config.defaultValue !== undefined
|
|
334
|
+
? convertToIdentifierViaAST(this, config.defaultValue, `${typeName}.${fieldName}.defaultValue`, `${locationHint}.defaultValue`)
|
|
335
|
+
: null,
|
|
336
|
+
deprecationReason: desc(config.deprecationReason),
|
|
337
|
+
extensions: extensions(this, config.extensions, `${locationHint}.extensions`, `${typeName}.${fieldName}.extensions`),
|
|
338
|
+
};
|
|
339
|
+
memo[fieldName] = configToAST(mappedConfig);
|
|
340
|
+
}
|
|
341
|
+
return memo;
|
|
342
|
+
}, {});
|
|
343
|
+
return t.objectExpression(objectToObjectProperties(obj));
|
|
344
|
+
}
|
|
345
|
+
makeFieldArgs(args, baseLocationHint, nameHint) {
|
|
346
|
+
const obj = Object.entries(args).reduce((memo, [argName, config]) => {
|
|
347
|
+
if (!argName.startsWith("__")) {
|
|
348
|
+
const locationHint = `${baseLocationHint}[${argName}]`;
|
|
349
|
+
const mappedConfig = {
|
|
350
|
+
description: desc(config.description),
|
|
351
|
+
type: this.typeExpression(config.type),
|
|
352
|
+
defaultValue: config.defaultValue !== undefined
|
|
353
|
+
? convertToIdentifierViaAST(this, config.defaultValue, `${nameHint}.${argName}.defaultValue`, `${locationHint}.defaultValue`)
|
|
354
|
+
: null,
|
|
355
|
+
deprecationReason: desc(config.deprecationReason),
|
|
356
|
+
extensions: extensions(this, config.extensions, `${locationHint}.extensions`, `${nameHint}.${argName}.extensions`),
|
|
357
|
+
};
|
|
358
|
+
memo[argName] = configToAST(mappedConfig);
|
|
359
|
+
}
|
|
360
|
+
return memo;
|
|
361
|
+
}, {});
|
|
362
|
+
return t.objectExpression(objectToObjectProperties(obj));
|
|
363
|
+
}
|
|
364
|
+
makeTypeDeclaration(type, VARIABLE_NAME) {
|
|
365
|
+
if (type instanceof graphql_1.GraphQLObjectType) {
|
|
366
|
+
const config = type.toConfig();
|
|
367
|
+
return declareGraphQLEntity(this, VARIABLE_NAME, "GraphQLObjectType", {
|
|
368
|
+
name: t.stringLiteral(config.name),
|
|
369
|
+
description: desc(config.description),
|
|
370
|
+
isTypeOf: config.isTypeOf
|
|
371
|
+
? func(this, config.isTypeOf, `${config.name}.isTypeOf`, `${config.name}.isTypeOf`)
|
|
372
|
+
: null,
|
|
373
|
+
extensions: extensions(this, config.extensions, `${config.name}.extensions`, `${config.name}.extensions`),
|
|
374
|
+
fields: t.arrowFunctionExpression([], this.makeObjectFields(config.fields, config.name)),
|
|
375
|
+
interfaces: config.interfaces.length > 0
|
|
376
|
+
? t.arrowFunctionExpression([], t.arrayExpression(config.interfaces.map((interfaceType) => this.declareType(interfaceType))))
|
|
377
|
+
: null,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
else if (type instanceof graphql_1.GraphQLInterfaceType) {
|
|
381
|
+
const config = type.toConfig();
|
|
382
|
+
return declareGraphQLEntity(this, VARIABLE_NAME, "GraphQLInterfaceType", {
|
|
383
|
+
name: t.stringLiteral(config.name),
|
|
384
|
+
description: desc(config.description),
|
|
385
|
+
resolveType: config.resolveType
|
|
386
|
+
? func(this, config.resolveType, `${config.name}.resolveType`, `${config.name}.resolveType`)
|
|
387
|
+
: null,
|
|
388
|
+
extensions: extensions(this, config.extensions, `${config.name}.extensions`, `${config.name}.extensions`),
|
|
389
|
+
fields: t.arrowFunctionExpression([], this.makeObjectFields(config.fields, config.name)),
|
|
390
|
+
interfaces: config.interfaces.length > 0
|
|
391
|
+
? t.arrayExpression(config.interfaces.map((interfaceType) => this.declareType(interfaceType)))
|
|
392
|
+
: null,
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
else if (type instanceof graphql_1.GraphQLUnionType) {
|
|
396
|
+
const config = type.toConfig();
|
|
397
|
+
return declareGraphQLEntity(this, VARIABLE_NAME, "GraphQLUnionType", {
|
|
398
|
+
name: t.stringLiteral(config.name),
|
|
399
|
+
description: desc(config.description),
|
|
400
|
+
resolveType: config.resolveType
|
|
401
|
+
? func(this, config.resolveType, `${config.name}.resolveType`, `${config.name}.resolveType`)
|
|
402
|
+
: null,
|
|
403
|
+
extensions: extensions(this, config.extensions, `${config.name}.extensions`, `${config.name}.extensions`),
|
|
404
|
+
types: t.arrowFunctionExpression([], t.arrayExpression(config.types.map((t) => this.declareType(t)))),
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
else if (type instanceof graphql_1.GraphQLInputObjectType) {
|
|
408
|
+
const config = type.toConfig();
|
|
409
|
+
return declareGraphQLEntity(this, VARIABLE_NAME, "GraphQLInputObjectType", {
|
|
410
|
+
name: t.stringLiteral(config.name),
|
|
411
|
+
description: desc(config.description),
|
|
412
|
+
extensions: extensions(this, config.extensions, `${config.name}.extensions`, `${config.name}.extensions`),
|
|
413
|
+
fields: t.arrowFunctionExpression([], this.makeInputObjectFields(config.fields, config.name)),
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
else if (type instanceof graphql_1.GraphQLScalarType) {
|
|
417
|
+
const config = type.toConfig();
|
|
418
|
+
return declareGraphQLEntity(this, VARIABLE_NAME, "GraphQLScalarType", {
|
|
419
|
+
name: t.stringLiteral(config.name),
|
|
420
|
+
description: desc(config.description),
|
|
421
|
+
specifiedByURL: desc(config.specifiedByURL),
|
|
422
|
+
serialize: func(this, config.serialize, `${config.name}.serialize`, `${config.name}.serialize`),
|
|
423
|
+
parseValue: func(this, config.parseValue, `${config.name}.parseValue`, `${config.name}.parseValue`),
|
|
424
|
+
parseLiteral: func(this, config.parseLiteral, `${config.name}.parseLiteral`, `${config.name}.parseLiteral`),
|
|
425
|
+
extensions: extensions(this, config.extensions, `${config.name}.extensions`, `${config.name}.extensions`),
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
else if (type instanceof graphql_1.GraphQLEnumType) {
|
|
429
|
+
const config = type.toConfig();
|
|
430
|
+
return declareGraphQLEntity(this, VARIABLE_NAME, "GraphQLEnumType", {
|
|
431
|
+
name: t.stringLiteral(config.name),
|
|
432
|
+
description: desc(config.description),
|
|
433
|
+
extensions: extensions(this, config.extensions, `${config.name}.extensions`, `${config.name}.extensions`),
|
|
434
|
+
values: objectNullPrototype(Object.entries(config.values).map(([key, value]) => t.objectProperty(identifierOrLiteral(key), this.makeEnumValue(value, config.name, key)))),
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
const never = type;
|
|
439
|
+
throw new Error(`Did not understand type: ${never.constructor.name}`);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
toAST() {
|
|
443
|
+
const importStatements = [];
|
|
444
|
+
Object.keys(this._imports)
|
|
445
|
+
.sort()
|
|
446
|
+
.forEach((moduleName) => {
|
|
447
|
+
const importedModule = this._imports[moduleName];
|
|
448
|
+
const MODULE_NAME = t.stringLiteral(moduleName);
|
|
449
|
+
if (!importedModule) {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
const { "*": starImport, default: defaultImport, ...rest } = importedModule;
|
|
453
|
+
if (starImport) {
|
|
454
|
+
const VARIABLE_NAME = starImport.variableName;
|
|
455
|
+
importStatements.push(starImport.asType
|
|
456
|
+
? importStarAsType({ MODULE_NAME, VARIABLE_NAME })
|
|
457
|
+
: importStar({ MODULE_NAME, VARIABLE_NAME }));
|
|
458
|
+
}
|
|
459
|
+
const exportNames = Object.keys(rest).sort();
|
|
460
|
+
if (defaultImport || exportNames.length > 0) {
|
|
461
|
+
const importStatement = t.importDeclaration([
|
|
462
|
+
...(defaultImport
|
|
463
|
+
? [t.importDefaultSpecifier(defaultImport.variableName)]
|
|
464
|
+
: []),
|
|
465
|
+
...(exportNames.length
|
|
466
|
+
? exportNames.map((name) => t.importSpecifier(rest[name].variableName, t.identifier(name)))
|
|
467
|
+
: []),
|
|
468
|
+
], MODULE_NAME);
|
|
469
|
+
importStatements.push(importStatement);
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
const allStatements = [...importStatements, ...this._statements];
|
|
473
|
+
return t.file(t.program(allStatements));
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
const importStarAsType = template_1.default.statement(`\
|
|
477
|
+
import type VARIABLE_NAME from MODULE_NAME;
|
|
478
|
+
`, templateOptions);
|
|
479
|
+
/**
|
|
480
|
+
* A manual way of doing this (which doesn't seem to work).
|
|
481
|
+
*
|
|
482
|
+
* ```
|
|
483
|
+
* const importStar = template.statement(
|
|
484
|
+
* `import * as VARIABLE_NAME from MODULE_NAME;`,
|
|
485
|
+
* templateOptions,
|
|
486
|
+
* );
|
|
487
|
+
* ```
|
|
488
|
+
*/
|
|
489
|
+
const importStar = (args) => t.importDeclaration([t.importNamespaceSpecifier(args.VARIABLE_NAME)], args.MODULE_NAME);
|
|
490
|
+
const declareConstructorWithConfig = template_1.default.statement(`\
|
|
491
|
+
export const VARIABLE_NAME = new CONSTRUCTOR(CONFIG);
|
|
492
|
+
`, templateOptions);
|
|
493
|
+
function declareGraphQLEntity(file, VARIABLE_NAME, constructorName, config) {
|
|
494
|
+
return declareConstructorWithConfig({
|
|
495
|
+
VARIABLE_NAME,
|
|
496
|
+
CONSTRUCTOR: file.import("graphql", constructorName),
|
|
497
|
+
CONFIG: configToAST(config),
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
function desc(description) {
|
|
501
|
+
return description ? t.stringLiteral(description) : null;
|
|
502
|
+
}
|
|
503
|
+
function _convertToAST(file, thing, locationHint, nameHint, depth, reference) {
|
|
504
|
+
const handleSubvalue = (value, tKey, key) => {
|
|
505
|
+
const existingIdentifier = getExistingIdentifier(file, value);
|
|
506
|
+
if (existingIdentifier) {
|
|
507
|
+
return existingIdentifier;
|
|
508
|
+
}
|
|
509
|
+
else if (isExportedFromFactory(value)) {
|
|
510
|
+
const val = convertToIdentifierViaAST(file, value, nameHint + `.${key}`, locationHint + `[${JSON.stringify(key)}]`, depth + 1);
|
|
511
|
+
return val;
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
const newReference = t.memberExpression(reference, tKey, !t.isIdentifier(tKey));
|
|
515
|
+
file._values.set(value, newReference);
|
|
516
|
+
const val = _convertToAST(file, value, locationHint + `[${JSON.stringify(key)}]`, nameHint + `.${key}`, depth + 1, newReference);
|
|
517
|
+
return val;
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
if (depth > 100) {
|
|
521
|
+
throw new Error(`_convertToAST: potentially infinite recursion at ${locationHint}. TODO: allow exporting recursive structures.`);
|
|
522
|
+
}
|
|
523
|
+
if (pg_sql2_1.sql.isSQL(thing)) {
|
|
524
|
+
throw new Error(`Exporting of 'sql' values is not supported (at ${locationHint}), please wrap in EXPORTABLE: ${pg_sql2_1.sql.compile(thing).text}`);
|
|
525
|
+
}
|
|
526
|
+
else if (Array.isArray(thing)) {
|
|
527
|
+
return t.arrayExpression(thing.map((entry, i) => {
|
|
528
|
+
const tKey = identifierOrLiteral(i);
|
|
529
|
+
return handleSubvalue(entry, tKey, i);
|
|
530
|
+
}));
|
|
531
|
+
}
|
|
532
|
+
else if (typeof thing === "function") {
|
|
533
|
+
return func(file, thing, locationHint, nameHint);
|
|
534
|
+
}
|
|
535
|
+
else if ((0, graphql_1.isSchema)(thing)) {
|
|
536
|
+
throw new Error("Attempted to export GraphQLSchema directly from `_convertToAST`; this is currently unsupported.");
|
|
537
|
+
}
|
|
538
|
+
else if (typeof thing === "object" && thing != null) {
|
|
539
|
+
return t.objectExpression(Object.entries(thing).map(([key, value]) => {
|
|
540
|
+
const tKey = identifierOrLiteral(key);
|
|
541
|
+
return t.objectProperty(tKey, handleSubvalue(value, tKey, key));
|
|
542
|
+
}));
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
throw new Error(`_convertToAST: did not understand item (${(0, util_1.inspect)(thing)}) at ${locationHint}`);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
const getExistingIdentifier = (file, thing) => {
|
|
549
|
+
const existingIdentifier = file._values.get(thing);
|
|
550
|
+
if (existingIdentifier) {
|
|
551
|
+
return existingIdentifier;
|
|
552
|
+
}
|
|
553
|
+
if (thing === null) {
|
|
554
|
+
return t.nullLiteral();
|
|
555
|
+
}
|
|
556
|
+
else if (thing === undefined) {
|
|
557
|
+
return t.identifier("undefined");
|
|
558
|
+
}
|
|
559
|
+
else if (typeof thing === "boolean") {
|
|
560
|
+
return t.booleanLiteral(thing);
|
|
561
|
+
}
|
|
562
|
+
else if (typeof thing === "string") {
|
|
563
|
+
return t.stringLiteral(thing);
|
|
564
|
+
}
|
|
565
|
+
else if (typeof thing === "number") {
|
|
566
|
+
return t.numericLiteral(thing);
|
|
567
|
+
}
|
|
568
|
+
else if ((0, wellKnown_js_1.wellKnown)(file.options, thing)) {
|
|
569
|
+
const { moduleName, exportName } = (0, wellKnown_js_1.wellKnown)(file.options, thing);
|
|
570
|
+
return file.import(moduleName, exportName);
|
|
571
|
+
}
|
|
572
|
+
else if (isImportable(thing)) {
|
|
573
|
+
const { moduleName, exportName } = thing.$$export;
|
|
574
|
+
return file.import(moduleName, exportName);
|
|
575
|
+
}
|
|
576
|
+
else if ((0, graphql_1.isDirective)(thing)) {
|
|
577
|
+
return file.declareDirective(thing);
|
|
578
|
+
}
|
|
579
|
+
else if ((0, graphql_1.isNamedType)(thing)) {
|
|
580
|
+
return file.declareType(thing);
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
function convertToIdentifierViaAST(file, thing, baseNameHint, locationHint, depth = 0) {
|
|
584
|
+
const existingIdentifier = getExistingIdentifier(file, thing);
|
|
585
|
+
if (existingIdentifier) {
|
|
586
|
+
return existingIdentifier;
|
|
587
|
+
}
|
|
588
|
+
// Prevent infinite loop by declaring the variableIdentifier immediately
|
|
589
|
+
const nameHint = getNameForThing(thing, locationHint, baseNameHint);
|
|
590
|
+
const variableIdentifier = file.makeVariable(nameHint || "value");
|
|
591
|
+
file._values.set(thing, variableIdentifier);
|
|
592
|
+
const ast = isExportedFromFactory(thing)
|
|
593
|
+
? factoryAst(file, thing, locationHint, nameHint)
|
|
594
|
+
: _convertToAST(file, thing, locationHint, nameHint, depth, variableIdentifier);
|
|
595
|
+
if (ast.type === "Identifier") {
|
|
596
|
+
console.warn(`graphile-export error: AST returned an identifier '${ast.name}'; this could cause an infinite loop.`);
|
|
597
|
+
}
|
|
598
|
+
file.addStatements(t.variableDeclaration("const", [
|
|
599
|
+
t.variableDeclarator(variableIdentifier, ast),
|
|
600
|
+
]));
|
|
601
|
+
return variableIdentifier;
|
|
602
|
+
}
|
|
603
|
+
function configToAST(o) {
|
|
604
|
+
return t.objectExpression(objectToObjectProperties(o));
|
|
605
|
+
}
|
|
606
|
+
function objectToObjectProperties(o) {
|
|
607
|
+
return Object.entries(o)
|
|
608
|
+
.filter(([, value]) => value != null)
|
|
609
|
+
.map(([key, value]) => t.objectProperty(identifierOrLiteral(key), value));
|
|
610
|
+
}
|
|
611
|
+
function extensions(file, extensions, locationHint, nameHint) {
|
|
612
|
+
if (extensions == null || Object.keys(extensions).length === 0) {
|
|
613
|
+
return null;
|
|
614
|
+
}
|
|
615
|
+
return convertToIdentifierViaAST(file, extensions, nameHint, locationHint);
|
|
616
|
+
}
|
|
617
|
+
/** Maps to `Object.assign(Object.create(null), {...})` */
|
|
618
|
+
function objectNullPrototype(properties) {
|
|
619
|
+
return t.callExpression(t.memberExpression(t.identifier("Object"), t.identifier("assign")), [
|
|
620
|
+
t.callExpression(t.memberExpression(t.identifier("Object"), t.identifier("create")), [t.nullLiteral()]),
|
|
621
|
+
t.objectExpression(properties),
|
|
622
|
+
]);
|
|
623
|
+
}
|
|
624
|
+
exports.objectNullPrototype = objectNullPrototype;
|
|
625
|
+
/*
|
|
626
|
+
function iife(statements: t.Statement[]): t.Expression {
|
|
627
|
+
return t.callExpression(
|
|
628
|
+
t.arrowFunctionExpression([], t.blockStatement(statements)),
|
|
629
|
+
[],
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
*/
|
|
633
|
+
function func(file, fn, locationHint, nameHint) {
|
|
634
|
+
if (fn == null) {
|
|
635
|
+
return t.identifier("undefined");
|
|
636
|
+
}
|
|
637
|
+
// Determine if we should wrap it in an IIFE to put the variables into
|
|
638
|
+
// scope; e.g.:
|
|
639
|
+
//
|
|
640
|
+
// `(() => { const foo = 1, bar = 2; return /*>*/() => {return foo+bar}/*<*/})();`
|
|
641
|
+
if (isExportedFromFactory(fn)) {
|
|
642
|
+
return factoryAst(file, fn, locationHint, nameHint);
|
|
643
|
+
}
|
|
644
|
+
else if ((0, wellKnown_js_1.wellKnown)(file.options, fn)) {
|
|
645
|
+
const { moduleName, exportName } = (0, wellKnown_js_1.wellKnown)(file.options, fn);
|
|
646
|
+
return file.import(moduleName, exportName);
|
|
647
|
+
}
|
|
648
|
+
else if (isImportable(fn)) {
|
|
649
|
+
return file.import(fn.$$export.moduleName, fn.$$export.exportName);
|
|
650
|
+
}
|
|
651
|
+
else {
|
|
652
|
+
return funcToAst(fn, locationHint, nameHint);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
const shouldOptimizeFactoryCalls = true;
|
|
656
|
+
function factoryAst(file, fn, locationHint, nameHint) {
|
|
657
|
+
const factory = fn.$exporter$factory;
|
|
658
|
+
const funcAST = funcToAst(factory, locationHint, nameHint);
|
|
659
|
+
const depArgs = fn.$exporter$args.map((arg, i) => {
|
|
660
|
+
if (typeof arg === "string") {
|
|
661
|
+
return t.stringLiteral(arg);
|
|
662
|
+
}
|
|
663
|
+
else if (typeof arg === "number") {
|
|
664
|
+
return t.numericLiteral(arg);
|
|
665
|
+
}
|
|
666
|
+
else if (typeof arg === "boolean") {
|
|
667
|
+
return t.booleanLiteral(arg);
|
|
668
|
+
}
|
|
669
|
+
else if (arg === null) {
|
|
670
|
+
return t.nullLiteral();
|
|
671
|
+
}
|
|
672
|
+
else if (arg === undefined) {
|
|
673
|
+
return t.identifier("undefined");
|
|
674
|
+
}
|
|
675
|
+
const param = funcAST.params[i];
|
|
676
|
+
const paramName = param && param.type === "Identifier" ? param.name : null;
|
|
677
|
+
return convertToIdentifierViaAST(file, arg, paramName || "parameter", `${locationHint}[$$scope][${JSON.stringify(i)}]`);
|
|
678
|
+
});
|
|
679
|
+
// TODO: we can remove this now that we have the post-processing via babel
|
|
680
|
+
if (shouldOptimizeFactoryCalls) {
|
|
681
|
+
/*
|
|
682
|
+
* Factories take the form of an IIFE: `((a, b, c) => ...)(x, y, z)`; where
|
|
683
|
+
* the corresponding argument names match up with the names of the values
|
|
684
|
+
* we're passing we can remove both the arg and the value and rely on it
|
|
685
|
+
* being available in the ambient scope.
|
|
686
|
+
*
|
|
687
|
+
* Further, if we get down to the situation where we have `(() => ...)()`
|
|
688
|
+
* and the `...` is not a block, then it must be an expression so we can
|
|
689
|
+
* just return it directly and get rid of the IIFE.
|
|
690
|
+
*/
|
|
691
|
+
const factoryArgNames = funcAST.params.map((p) => p.type === "Identifier" ? p.name : null);
|
|
692
|
+
const depArgsNames = depArgs.map((d) => d.type === "Identifier" ? d.name : null);
|
|
693
|
+
for (let i = factoryArgNames.length - 1; i >= 0; i--) {
|
|
694
|
+
if (factoryArgNames[i] === depArgsNames[i]) {
|
|
695
|
+
funcAST.params.splice(i, 1);
|
|
696
|
+
depArgs.splice(i, 1);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
if (funcAST.params.length === 0 && funcAST.body.type !== "BlockStatement") {
|
|
700
|
+
return funcAST.body;
|
|
701
|
+
}
|
|
702
|
+
return t.callExpression(funcAST, depArgs);
|
|
703
|
+
}
|
|
704
|
+
else {
|
|
705
|
+
return t.callExpression(funcAST, depArgs);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
function funcToAst(fn, locationHint, _nameHint) {
|
|
709
|
+
const funcString = fn.toString().trim();
|
|
710
|
+
try {
|
|
711
|
+
const result = (0, parser_1.parseExpression)(funcString, {
|
|
712
|
+
sourceType: "module",
|
|
713
|
+
plugins: ["typescript"],
|
|
714
|
+
});
|
|
715
|
+
if (result.type !== "FunctionExpression" &&
|
|
716
|
+
result.type !== "ArrowFunctionExpression") {
|
|
717
|
+
if (result.type === "ClassExpression") {
|
|
718
|
+
throw Object.assign(new Error(`We don't support exporting classes directly, instead you should mark your class as importable via:
|
|
719
|
+
Object.defineProperty(${result.id?.name ?? "MyClass"}, '$$export', { value: { moduleName: 'my-module', exportName: '${result.id?.name ?? "MyClass"}' } });`), { retry: false });
|
|
720
|
+
}
|
|
721
|
+
throw new Error(`Expected FunctionExpression or ArrowFunctionExpression but saw ${result.type}`);
|
|
722
|
+
}
|
|
723
|
+
return result;
|
|
724
|
+
}
|
|
725
|
+
catch (e) {
|
|
726
|
+
if (e.retry === false) {
|
|
727
|
+
throw e;
|
|
728
|
+
}
|
|
729
|
+
try {
|
|
730
|
+
// Parsing failed; so it's not any of these:
|
|
731
|
+
//
|
|
732
|
+
// - () => {}
|
|
733
|
+
// - async () => {}
|
|
734
|
+
// - function(){}
|
|
735
|
+
// - async function(){}
|
|
736
|
+
//
|
|
737
|
+
// Guessing it must be a property method declaration then; let's try adding the `function` keyword
|
|
738
|
+
const modifiedDefinition = funcString.startsWith("async ")
|
|
739
|
+
? "async function " + funcString.slice(6)
|
|
740
|
+
: "function " + funcString;
|
|
741
|
+
const result = (0, parser_1.parseExpression)(modifiedDefinition, {
|
|
742
|
+
sourceType: "module",
|
|
743
|
+
plugins: ["typescript"],
|
|
744
|
+
});
|
|
745
|
+
if (result.type !== "FunctionExpression" &&
|
|
746
|
+
result.type !== "ArrowFunctionExpression") {
|
|
747
|
+
throw new Error(`Expected FunctionExpression or ArrowFunctionExpression but saw ${result.type}`);
|
|
748
|
+
}
|
|
749
|
+
return result;
|
|
750
|
+
}
|
|
751
|
+
catch {
|
|
752
|
+
throw new Error(`Function export error at ${locationHint} - failed to process function definition '${trimDef(fn.toString())}'\n ${String(e.stack ?? e)
|
|
753
|
+
.split("\n")
|
|
754
|
+
.join("\n ")}`);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* Exposes a `GraphQLSchema` object built via GraphQL.js constructors
|
|
760
|
+
*/
|
|
761
|
+
function exportSchemaGraphQLJS({ config, customTypes, customDirectives, file, }) {
|
|
762
|
+
const schemaExportName = file.makeVariable("schema");
|
|
763
|
+
const types = customTypes.map((type) => {
|
|
764
|
+
return file.declareType(type);
|
|
765
|
+
});
|
|
766
|
+
file.addStatements(declareGraphQLEntity(file, schemaExportName, "GraphQLSchema", {
|
|
767
|
+
description: desc(config.description),
|
|
768
|
+
query: config.query ? file.declareType(config.query) : t.nullLiteral(),
|
|
769
|
+
mutation: config.mutation ? file.declareType(config.mutation) : null,
|
|
770
|
+
subscription: config.subscription
|
|
771
|
+
? file.declareType(config.subscription)
|
|
772
|
+
: null,
|
|
773
|
+
types: t.arrayExpression(types),
|
|
774
|
+
directives: customDirectives.length > 0
|
|
775
|
+
? t.arrayExpression(customDirectives.map((directive) => file.declareDirective(directive)))
|
|
776
|
+
: null,
|
|
777
|
+
extensions: extensions(file, config.extensions, "schema.extensions", "schema.extensions"),
|
|
778
|
+
enableDeferStream: t.booleanLiteral(true),
|
|
779
|
+
/*
|
|
780
|
+
// TODO: use the below once https://github.com/graphql/graphql-js/pull/3450 is fixed:
|
|
781
|
+
enableDeferStream:
|
|
782
|
+
config.enableDeferStream != null
|
|
783
|
+
? t.booleanLiteral(config.enableDeferStream)
|
|
784
|
+
: null,
|
|
785
|
+
*/
|
|
786
|
+
assumeValid: null, // TODO: t.booleanLiteral(true),
|
|
787
|
+
}));
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Exposes as `typeDefs`/`plans` for simplified read.
|
|
791
|
+
*
|
|
792
|
+
* EXPERIMENTAL!
|
|
793
|
+
*/
|
|
794
|
+
function exportSchemaTypeDefs({ schema, customTypes, file, }) {
|
|
795
|
+
const typeDefsExportName = file.makeVariable("typeDefs");
|
|
796
|
+
const plansExportName = file.makeVariable("plans");
|
|
797
|
+
const schemaExportName = file.makeVariable("schema");
|
|
798
|
+
const typeDefsString = (0, graphql_1.printSchema)(schema);
|
|
799
|
+
const graphqlAST = t.templateLiteral([t.templateElement({ raw: typeDefsString.replace(/[\\`]/g, "\\$&") })], []);
|
|
800
|
+
graphqlAST.leadingComments = [
|
|
801
|
+
{ type: "CommentBlock", value: " GraphQL " },
|
|
802
|
+
];
|
|
803
|
+
const plansProperties = [];
|
|
804
|
+
customTypes.forEach((type) => {
|
|
805
|
+
if (type instanceof graphql_1.GraphQLObjectType) {
|
|
806
|
+
const typeProperties = [];
|
|
807
|
+
if (type.extensions.graphile?.Step) {
|
|
808
|
+
typeProperties.push(t.objectProperty(t.identifier("__Step"), convertToIdentifierViaAST(file, type.extensions.graphile.Step, `${type.name}ExpectedStep`, `${type.name}.extensions.Step`)));
|
|
809
|
+
}
|
|
810
|
+
for (const [fieldName, field] of Object.entries(type.toConfig().fields)) {
|
|
811
|
+
// Use shorthand if there's only a `plan` and nothing else
|
|
812
|
+
const planAST = field.extensions?.graphile?.plan
|
|
813
|
+
? convertToIdentifierViaAST(file, field.extensions?.graphile?.plan, `${type.name}.${fieldName}Step`, `${type.name}.fields[${fieldName}].extensions.graphile.plan`)
|
|
814
|
+
: null;
|
|
815
|
+
const subscribePlanAST = field.extensions?.graphile?.subscribePlan
|
|
816
|
+
? convertToIdentifierViaAST(file, field.extensions?.graphile?.subscribePlan, `${type.name}.${fieldName}SubscribeStep`, `${type.name}.fields[${fieldName}].extensions.graphile.subscribePlan`)
|
|
817
|
+
: null;
|
|
818
|
+
const originalResolver = field.resolve;
|
|
819
|
+
const originalSubscribe = field.subscribe;
|
|
820
|
+
const resolveAST = originalResolver
|
|
821
|
+
? convertToIdentifierViaAST(file, originalResolver, `${type.name}.${fieldName}Resolve`, `${type.name}.fields[${fieldName}].resolve`)
|
|
822
|
+
: null;
|
|
823
|
+
const subscribeAST = originalResolver
|
|
824
|
+
? convertToIdentifierViaAST(file, originalSubscribe, `${type.name}.${fieldName}Subscribe`, `${type.name}.fields[${fieldName}].subscribe`)
|
|
825
|
+
: null;
|
|
826
|
+
const args = field.args
|
|
827
|
+
? Object.entries(field.args)
|
|
828
|
+
.map(([argName, arg]) => {
|
|
829
|
+
return t.objectProperty(identifierOrLiteral(argName), configToAST({
|
|
830
|
+
input: arg.extensions?.graphile?.inputPlan
|
|
831
|
+
? convertToIdentifierViaAST(file, arg.extensions.graphile.inputPlan, `${type.name}.${fieldName}.${argName}InputStep`, `${type.name}.fields[${fieldName}].args[${argName}].extensions.graphile.inputPlan`)
|
|
832
|
+
: null,
|
|
833
|
+
apply: arg.extensions?.graphile?.applyPlan
|
|
834
|
+
? convertToIdentifierViaAST(file, arg.extensions.graphile.applyPlan, `${type.name}.${fieldName}.${argName}ApplyStep`, `${type.name}.fields[${fieldName}].args[${argName}].extensions.graphile.applyPlan`)
|
|
835
|
+
: null,
|
|
836
|
+
}));
|
|
837
|
+
})
|
|
838
|
+
.filter(isNotNullish)
|
|
839
|
+
: null;
|
|
840
|
+
const argsAST = args && args.length ? t.objectExpression(args) : null;
|
|
841
|
+
if (!planAST && !subscribePlanAST && !resolveAST && !subscribeAST) {
|
|
842
|
+
if (argsAST) {
|
|
843
|
+
throw new Error(`Invalid schema! ${type.name}.${fieldName} has no plan, but it's arguments do!`);
|
|
844
|
+
}
|
|
845
|
+
// No definition
|
|
846
|
+
continue;
|
|
847
|
+
}
|
|
848
|
+
const shorthand = planAST &&
|
|
849
|
+
!subscribePlanAST &&
|
|
850
|
+
!originalResolver &&
|
|
851
|
+
!originalSubscribe &&
|
|
852
|
+
!argsAST;
|
|
853
|
+
const fieldSpec = shorthand
|
|
854
|
+
? planAST
|
|
855
|
+
: t.objectExpression(objectToObjectProperties({
|
|
856
|
+
plan: planAST,
|
|
857
|
+
subscribePlan: subscribePlanAST,
|
|
858
|
+
resolve: resolveAST,
|
|
859
|
+
subscribe: subscribeAST,
|
|
860
|
+
args: argsAST,
|
|
861
|
+
}));
|
|
862
|
+
typeProperties.push(t.objectProperty(identifierOrLiteral(fieldName), fieldSpec));
|
|
863
|
+
}
|
|
864
|
+
plansProperties.push(t.objectProperty(identifierOrLiteral(type.name), t.objectExpression(typeProperties)));
|
|
865
|
+
}
|
|
866
|
+
else if (type instanceof graphql_1.GraphQLInputObjectType) {
|
|
867
|
+
const typeProperties = [];
|
|
868
|
+
for (const [fieldName, field] of Object.entries(type.toConfig().fields)) {
|
|
869
|
+
// Use shorthand if there's only a `plan` and nothing else
|
|
870
|
+
const inputPlanAST = field.extensions?.graphile?.inputPlan
|
|
871
|
+
? convertToIdentifierViaAST(file, field.extensions?.graphile?.inputPlan, `${type.name}.${fieldName}InputStep`, `${type.name}.fields[${fieldName}].extensions.graphile.inputPlan`)
|
|
872
|
+
: null;
|
|
873
|
+
const applyPlanAST = field.extensions?.graphile?.applyPlan
|
|
874
|
+
? convertToIdentifierViaAST(file, field.extensions?.graphile?.applyPlan, `${type.name}.${fieldName}ApplyStep`, `${type.name}.fields[${fieldName}].extensions.graphile.applyPlan`)
|
|
875
|
+
: null;
|
|
876
|
+
if (inputPlanAST || applyPlanAST) {
|
|
877
|
+
typeProperties.push(t.objectProperty(identifierOrLiteral(fieldName), configToAST({
|
|
878
|
+
input: inputPlanAST,
|
|
879
|
+
apply: applyPlanAST,
|
|
880
|
+
})));
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
plansProperties.push(t.objectProperty(identifierOrLiteral(type.name), t.objectExpression(typeProperties)));
|
|
884
|
+
}
|
|
885
|
+
else if (type instanceof graphql_1.GraphQLInterfaceType ||
|
|
886
|
+
type instanceof graphql_1.GraphQLUnionType) {
|
|
887
|
+
const config = type.toConfig();
|
|
888
|
+
if (config.resolveType) {
|
|
889
|
+
plansProperties.push(t.objectProperty(identifierOrLiteral(type.name), t.objectExpression(objectToObjectProperties({
|
|
890
|
+
__resolveType: convertToIdentifierViaAST(file, type.resolveType, `${type.name}ResolveType`, `${type.name}.resolveType`),
|
|
891
|
+
}))));
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
else if (type instanceof graphql_1.GraphQLScalarType) {
|
|
895
|
+
const config = type.toConfig();
|
|
896
|
+
const planAST = config.extensions.graphile?.plan
|
|
897
|
+
? convertToIdentifierViaAST(file, config.extensions?.graphile?.plan, `${type.name}Step`, `${type.name}.extensions.graphile.plan`)
|
|
898
|
+
: null;
|
|
899
|
+
if (planAST) {
|
|
900
|
+
plansProperties.push(t.objectProperty(identifierOrLiteral(type.name), t.objectExpression(objectToObjectProperties({
|
|
901
|
+
serialize: convertToIdentifierViaAST(file, type.serialize, `${type.name}Serialize`, `${type.name}.serialize`),
|
|
902
|
+
parseValue: convertToIdentifierViaAST(file, type.parseValue, `${type.name}ParseValue`, `${type.name}.parseValue`),
|
|
903
|
+
parseLiteral: convertToIdentifierViaAST(file, type.parseLiteral, `${type.name}ParseLiteral`, `${type.name}.parseLiteral`),
|
|
904
|
+
plan: planAST,
|
|
905
|
+
}))));
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
else if (type instanceof graphql_1.GraphQLEnumType) {
|
|
909
|
+
const config = type.toConfig();
|
|
910
|
+
const enumValues = [];
|
|
911
|
+
for (const [enumValueName, enumValueConfig] of Object.entries(config.values)) {
|
|
912
|
+
const valueAST = enumValueConfig.value !== undefined &&
|
|
913
|
+
enumValueConfig.value !== enumValueName
|
|
914
|
+
? convertToIdentifierViaAST(file, enumValueConfig.value, `${type.name}_${enumValueName}`, `${type.name}.values[${enumValueName}].value`)
|
|
915
|
+
: null;
|
|
916
|
+
const applyPlanAST = enumValueConfig.extensions?.graphile?.applyPlan
|
|
917
|
+
? convertToIdentifierViaAST(file, enumValueConfig.extensions.graphile.applyPlan, `${type.name}_${enumValueName}ApplyStep`, `${type.name}.values[${enumValueName}].extensions.graphile.applyPlan`)
|
|
918
|
+
: null;
|
|
919
|
+
if (valueAST || applyPlanAST) {
|
|
920
|
+
enumValues.push(t.objectProperty(identifierOrLiteral(enumValueName), t.objectExpression(objectToObjectProperties({
|
|
921
|
+
value: valueAST,
|
|
922
|
+
apply: applyPlanAST,
|
|
923
|
+
}))));
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
if (enumValues.length > 0) {
|
|
927
|
+
plansProperties.push(t.objectProperty(identifierOrLiteral(type.name), t.objectExpression(enumValues)));
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
else {
|
|
931
|
+
const never = type;
|
|
932
|
+
console.warn(`Unhandled type ${never}`);
|
|
933
|
+
}
|
|
934
|
+
});
|
|
935
|
+
const typeDefs = t.exportNamedDeclaration(t.variableDeclaration("const", [
|
|
936
|
+
t.variableDeclarator(typeDefsExportName, graphqlAST),
|
|
937
|
+
]));
|
|
938
|
+
const plans = t.exportNamedDeclaration(t.variableDeclaration("const", [
|
|
939
|
+
t.variableDeclarator(plansExportName, t.objectExpression(plansProperties)),
|
|
940
|
+
]));
|
|
941
|
+
file.addStatements(typeDefs);
|
|
942
|
+
file.addStatements(plans);
|
|
943
|
+
const makeGrafastSchemaAST = file.import("grafast", "makeGrafastSchema");
|
|
944
|
+
const schemaAST = t.callExpression(makeGrafastSchemaAST, [
|
|
945
|
+
t.objectExpression(objectToObjectProperties({
|
|
946
|
+
typeDefs: typeDefsExportName,
|
|
947
|
+
plans: plansExportName,
|
|
948
|
+
})),
|
|
949
|
+
]);
|
|
950
|
+
file.addStatements(t.exportNamedDeclaration(t.variableDeclaration("const", [
|
|
951
|
+
t.variableDeclarator(schemaExportName, schemaAST),
|
|
952
|
+
])));
|
|
953
|
+
}
|
|
954
|
+
async function exportSchemaAsString(schema, options) {
|
|
955
|
+
const config = schema.toConfig();
|
|
956
|
+
const customTypes = config.types.filter((type) => !isBuiltinType(type));
|
|
957
|
+
const customDirectives = config.directives.filter((d) => ![
|
|
958
|
+
"skip",
|
|
959
|
+
"include",
|
|
960
|
+
"deprecated",
|
|
961
|
+
"specifiedBy",
|
|
962
|
+
"defer",
|
|
963
|
+
"stream",
|
|
964
|
+
].includes(d.name));
|
|
965
|
+
const file = new CodegenFile(options);
|
|
966
|
+
const schemaExportDetails = {
|
|
967
|
+
schema,
|
|
968
|
+
config,
|
|
969
|
+
options,
|
|
970
|
+
customTypes,
|
|
971
|
+
customDirectives,
|
|
972
|
+
file,
|
|
973
|
+
};
|
|
974
|
+
if (options.mode === "typeDefs") {
|
|
975
|
+
exportSchemaTypeDefs(schemaExportDetails);
|
|
976
|
+
}
|
|
977
|
+
else {
|
|
978
|
+
exportSchemaGraphQLJS(schemaExportDetails);
|
|
979
|
+
}
|
|
980
|
+
const ast = file.toAST();
|
|
981
|
+
const optimizedAst = (0, index_js_1.optimize)(ast);
|
|
982
|
+
const { code } = reallyGenerate(optimizedAst, {});
|
|
983
|
+
return { code };
|
|
984
|
+
}
|
|
985
|
+
exports.exportSchemaAsString = exportSchemaAsString;
|
|
986
|
+
async function exportSchema(schema, toPath, options = {}) {
|
|
987
|
+
const { code } = await exportSchemaAsString(schema, options);
|
|
988
|
+
const HEADER = `/* eslint-disable graphile-export/export-instances, graphile-export/export-methods, graphile-export/exhaustive-deps */\n`;
|
|
989
|
+
const toFormat = HEADER + code;
|
|
990
|
+
if (options.prettier) {
|
|
991
|
+
const prettier = await import("prettier");
|
|
992
|
+
const config = await prettier.resolveConfig(toPath.toString());
|
|
993
|
+
const formatted = prettier.format(toFormat, {
|
|
994
|
+
parser: "babel",
|
|
995
|
+
...(config ?? {}),
|
|
996
|
+
});
|
|
997
|
+
await (0, promises_1.writeFile)(toPath, formatted);
|
|
998
|
+
}
|
|
999
|
+
else {
|
|
1000
|
+
await (0, promises_1.writeFile)(toPath, toFormat);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
exports.exportSchema = exportSchema;
|
|
1004
|
+
//# sourceMappingURL=exportSchema.js.map
|