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.
@@ -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