nuxt-graphql-middleware 4.3.1 → 5.0.0-alpha.0
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/dist/module.d.mts +3 -29
- package/dist/module.d.ts +3 -29
- package/dist/module.json +1 -1
- package/dist/module.mjs +463 -727
- package/dist/runtime/composables/useAsyncGraphqlQuery.d.ts +25 -9
- package/dist/runtime/serverHandler/debug.js +2 -2
- package/dist/runtime/serverHandler/helpers/index.d.ts +2 -2
- package/dist/runtime/serverHandler/index.js +3 -3
- package/dist/runtime/serverHandler/upload.js +3 -3
- package/dist/runtime/settings/index.d.ts +1 -1
- package/dist/runtime/settings/index.js +1 -1
- package/dist/runtime/types.d.ts +5 -0
- package/package.json +11 -8
- package/dist/client/200.html +0 -11
- package/dist/client/404.html +0 -11
- package/dist/client/_nuxt/B4FhP7a6.js +0 -1
- package/dist/client/_nuxt/CH4m2wxh.js +0 -25
- package/dist/client/_nuxt/CPd6XBwJ.js +0 -1
- package/dist/client/_nuxt/GKcsigNx.js +0 -1
- package/dist/client/_nuxt/VR7nYXIq.js +0 -2
- package/dist/client/_nuxt/builds/latest.json +0 -1
- package/dist/client/_nuxt/builds/meta/08eb555c-2460-4359-b00b-ff7301e8150d.json +0 -1
- package/dist/client/_nuxt/entry.D9ltLgme.css +0 -1
- package/dist/client/_nuxt/error-404.SWzu_puR.css +0 -1
- package/dist/client/_nuxt/error-500.Bkv_zTjr.css +0 -1
- package/dist/client/_nuxt/index.D19Q16VT.css +0 -1
- package/dist/client/index.html +0 -11
package/dist/module.mjs
CHANGED
|
@@ -1,27 +1,23 @@
|
|
|
1
|
+
import { loadSchema } from '@graphql-tools/load';
|
|
1
2
|
import { fileURLToPath } from 'url';
|
|
2
|
-
import {
|
|
3
|
+
import { relative } from 'pathe';
|
|
3
4
|
import { defu } from 'defu';
|
|
4
|
-
import { useLogger,
|
|
5
|
-
import inquirer from 'inquirer';
|
|
5
|
+
import { useLogger, resolveFiles, defineNuxtModule, resolveAlias, createResolver, addImports, addServerImports, addTemplate, addServerHandler, addPlugin } from '@nuxt/kit';
|
|
6
6
|
import { onDevToolsInitialized, extendServerRpc } from '@nuxt/devtools-kit';
|
|
7
7
|
import { existsSync } from 'fs';
|
|
8
8
|
import { GraphqlMiddlewareTemplate } from '../dist/runtime/settings/index.js';
|
|
9
|
-
import * as fs from 'node:fs';
|
|
10
9
|
import { promises, existsSync as existsSync$1 } from 'node:fs';
|
|
11
|
-
import {
|
|
12
|
-
import { validateGraphQlDocuments } from '@graphql-tools/utils';
|
|
13
|
-
import { loadSchema } from '@graphql-tools/load';
|
|
14
|
-
import { concatAST, parse, print, visit, Kind, Source } from 'graphql';
|
|
15
|
-
import { falsy } from '../dist/runtime/helpers/index.js';
|
|
16
|
-
import { generate as generate$1, executeCodegen } from '@graphql-codegen/cli';
|
|
17
|
-
import * as PluginTypescript from '@graphql-codegen/typescript';
|
|
18
|
-
import * as PluginTypescriptOperations from '@graphql-codegen/typescript-operations';
|
|
10
|
+
import { generate } from '@graphql-codegen/cli';
|
|
19
11
|
import * as PluginSchemaAst from '@graphql-codegen/schema-ast';
|
|
12
|
+
import { basename } from 'node:path';
|
|
13
|
+
import { Source, parse, printSourceLocation } from 'graphql';
|
|
14
|
+
import { Generator } from 'graphql-typescript-deluxe';
|
|
20
15
|
import { pascalCase } from 'change-case-all';
|
|
21
16
|
import colors from 'picocolors';
|
|
17
|
+
import { validateGraphQlDocuments } from '@graphql-tools/utils';
|
|
22
18
|
|
|
23
19
|
const name = "nuxt-graphql-middleware";
|
|
24
|
-
const version = "
|
|
20
|
+
const version = "5.0.0-alpha.0";
|
|
25
21
|
|
|
26
22
|
const DEVTOOLS_UI_ROUTE = "/__nuxt-graphql-middleware";
|
|
27
23
|
const DEVTOOLS_UI_LOCAL_PORT = 3300;
|
|
@@ -64,236 +60,8 @@ function setupDevToolsUI(nuxt, clientPath) {
|
|
|
64
60
|
});
|
|
65
61
|
}
|
|
66
62
|
|
|
67
|
-
const importSyntaxRE = /^#import (?:'([^']*)'|"([^"]*)")/;
|
|
68
|
-
const matchImport = (value = "") => {
|
|
69
|
-
if (!value) {
|
|
70
|
-
return void 0;
|
|
71
|
-
}
|
|
72
|
-
if (value.indexOf("#import") !== 0) {
|
|
73
|
-
return void 0;
|
|
74
|
-
}
|
|
75
|
-
const matched = value.match(importSyntaxRE);
|
|
76
|
-
if (matched === null) {
|
|
77
|
-
return void 0;
|
|
78
|
-
}
|
|
79
|
-
const importIdentifierMatch = value.match(importSyntaxRE) || [];
|
|
80
|
-
const importIdentifier = importIdentifierMatch[1] ?? importIdentifierMatch[2];
|
|
81
|
-
if (importIdentifier === void 0) {
|
|
82
|
-
return void 0;
|
|
83
|
-
}
|
|
84
|
-
return { importIdentifier };
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const lineEndingRE = /\r\n|\n/;
|
|
88
|
-
function* linesWithInlinedImportsOf(fileContents, inlineImportsOptions, visited) {
|
|
89
|
-
const {
|
|
90
|
-
resolveOptions = {},
|
|
91
|
-
resolveImport,
|
|
92
|
-
fs: nodeFs = fs,
|
|
93
|
-
throwIfImportNotFound
|
|
94
|
-
} = inlineImportsOptions;
|
|
95
|
-
const { basedir } = resolveOptions;
|
|
96
|
-
if (typeof basedir !== "string") {
|
|
97
|
-
throw new TypeError(
|
|
98
|
-
"inlineImports requires options.resolverOptions.basedir be set"
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
if (!resolveImport) {
|
|
102
|
-
throw new TypeError("inlineImports requires options.resolveImport be set");
|
|
103
|
-
}
|
|
104
|
-
let lineNumber = 0;
|
|
105
|
-
for (const line of fileContents.split(lineEndingRE)) {
|
|
106
|
-
++lineNumber;
|
|
107
|
-
const matched = matchImport(line);
|
|
108
|
-
if (matched) {
|
|
109
|
-
const importIdentifier = matched.importIdentifier;
|
|
110
|
-
let filename;
|
|
111
|
-
try {
|
|
112
|
-
filename = resolveImport(importIdentifier, resolveOptions);
|
|
113
|
-
} catch (err) {
|
|
114
|
-
if (throwIfImportNotFound === false) {
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
throw err;
|
|
118
|
-
}
|
|
119
|
-
if (visited.has(filename)) {
|
|
120
|
-
continue;
|
|
121
|
-
} else {
|
|
122
|
-
visited.add(filename);
|
|
123
|
-
}
|
|
124
|
-
const fragmentSource = nodeFs.readFileSync(filename, "utf8");
|
|
125
|
-
const line2 = inlineImportsWithLineToImports(
|
|
126
|
-
fragmentSource,
|
|
127
|
-
{
|
|
128
|
-
resolveImport,
|
|
129
|
-
resolveOptions: {
|
|
130
|
-
basedir: dirname(filename)
|
|
131
|
-
}
|
|
132
|
-
},
|
|
133
|
-
visited
|
|
134
|
-
);
|
|
135
|
-
yield { line: line2.inlineImports, match: true, lineNumber, filename };
|
|
136
|
-
} else {
|
|
137
|
-
yield { line, match: false, lineNumber };
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
function inlineImportsWithLineToImports(fileContents, options, visited = /* @__PURE__ */ new Set()) {
|
|
142
|
-
const inlineImportsResult = [];
|
|
143
|
-
const lineToImports = /* @__PURE__ */ new Map();
|
|
144
|
-
for (const { line, match, lineNumber, filename } of linesWithInlinedImportsOf(
|
|
145
|
-
fileContents,
|
|
146
|
-
options,
|
|
147
|
-
visited
|
|
148
|
-
)) {
|
|
149
|
-
inlineImportsResult.push(line);
|
|
150
|
-
if (match) {
|
|
151
|
-
lineToImports.set(lineNumber, { filename, line });
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return {
|
|
155
|
-
inlineImports: inlineImportsResult.join("\n"),
|
|
156
|
-
lineToImports
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function getCodeResult(operations, typeName, serverApiPrefix) {
|
|
161
|
-
const imports = [];
|
|
162
|
-
const resultTypes = [];
|
|
163
|
-
let code = "";
|
|
164
|
-
let nitroCode = "";
|
|
165
|
-
const names = Object.keys(operations);
|
|
166
|
-
if (names.length) {
|
|
167
|
-
const lines = [];
|
|
168
|
-
const nitroLines = [];
|
|
169
|
-
names.forEach((name) => {
|
|
170
|
-
const nameResult = pascalCase(name + typeName);
|
|
171
|
-
resultTypes.push(nameResult);
|
|
172
|
-
imports.push(nameResult);
|
|
173
|
-
const nameVariables = pascalCase(name + typeName + "Variables");
|
|
174
|
-
const { hasVariables, variablesOptional } = operations[name];
|
|
175
|
-
if (hasVariables) {
|
|
176
|
-
imports.push(nameVariables);
|
|
177
|
-
}
|
|
178
|
-
const variablesType = hasVariables ? nameVariables : "null";
|
|
179
|
-
lines.push(
|
|
180
|
-
` ${name}: [${variablesType}, ${variablesOptional ? "true" : "false"}, ${nameResult}]`
|
|
181
|
-
);
|
|
182
|
-
nitroLines.push(
|
|
183
|
-
` '${serverApiPrefix}/${typeName.toLowerCase()}/${name}': {
|
|
184
|
-
'default': GraphqlResponse<${nameResult}>
|
|
185
|
-
}`
|
|
186
|
-
);
|
|
187
|
-
});
|
|
188
|
-
code += ` export type GraphqlMiddleware${typeName} = {
|
|
189
|
-
${lines.join(",\n")}
|
|
190
|
-
}
|
|
191
|
-
`;
|
|
192
|
-
nitroCode += `${nitroLines.join("\n")}`;
|
|
193
|
-
}
|
|
194
|
-
return { code, imports, nitroCode, resultTypes };
|
|
195
|
-
}
|
|
196
|
-
const plugin$1 = (_schema, documents, config) => {
|
|
197
|
-
const allAst = concatAST(documents.map((v) => v.document).filter(falsy));
|
|
198
|
-
const operations = {
|
|
199
|
-
query: {},
|
|
200
|
-
mutation: {}
|
|
201
|
-
};
|
|
202
|
-
oldVisit(allAst, {
|
|
203
|
-
enter: {
|
|
204
|
-
OperationDefinition: (node) => {
|
|
205
|
-
if ("name" in node && node.name?.value && "operation" in node && (node.operation === "query" || node.operation === "mutation")) {
|
|
206
|
-
operations[node.operation][node.name.value] = {
|
|
207
|
-
hasVariables: !!node.variableDefinitions?.length,
|
|
208
|
-
variablesOptional: !!node.variableDefinitions?.every((v) => {
|
|
209
|
-
return v.defaultValue;
|
|
210
|
-
})
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
let code = "";
|
|
217
|
-
let nitroCode = "";
|
|
218
|
-
const imports = [];
|
|
219
|
-
const resultTypes = [];
|
|
220
|
-
const resultQuery = getCodeResult(
|
|
221
|
-
operations.query,
|
|
222
|
-
"Query",
|
|
223
|
-
config.serverApiPrefix
|
|
224
|
-
);
|
|
225
|
-
code += resultQuery.code;
|
|
226
|
-
nitroCode += resultQuery.nitroCode;
|
|
227
|
-
imports.push(...resultQuery.imports);
|
|
228
|
-
resultTypes.push(...resultQuery.resultTypes);
|
|
229
|
-
const resultMutation = getCodeResult(
|
|
230
|
-
operations.mutation,
|
|
231
|
-
"Mutation",
|
|
232
|
-
config.serverApiPrefix
|
|
233
|
-
);
|
|
234
|
-
code += "\n" + resultMutation.code;
|
|
235
|
-
nitroCode += "\n" + resultMutation.nitroCode;
|
|
236
|
-
imports.push(...resultMutation.imports);
|
|
237
|
-
resultTypes.push(...resultMutation.resultTypes);
|
|
238
|
-
return `
|
|
239
|
-
import type { GraphqlResponse } from '#graphql-middleware-server-options-build'
|
|
240
|
-
import type {
|
|
241
|
-
${imports.join(",\n ")}
|
|
242
|
-
} from './../graphql-operations'
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
declare module '#nuxt-graphql-middleware/generated-types' {
|
|
246
|
-
export type GraphqlMiddlewareResponseUnion = ${resultTypes.join(" | ")}
|
|
247
|
-
${code}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
declare module 'nitropack' {
|
|
251
|
-
interface InternalApi {
|
|
252
|
-
${nitroCode}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
`;
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
const PluginNuxtGraphqlMiddleware = {
|
|
259
|
-
__proto__: null,
|
|
260
|
-
plugin: plugin$1
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
const plugin = (_schema, documents, _config) => {
|
|
264
|
-
const allAst = concatAST(documents.map((v) => v.document).filter(falsy));
|
|
265
|
-
const operations = {
|
|
266
|
-
query: {},
|
|
267
|
-
mutation: {}
|
|
268
|
-
};
|
|
269
|
-
oldVisit(allAst, {
|
|
270
|
-
enter: {
|
|
271
|
-
OperationDefinition: (node) => {
|
|
272
|
-
if (node.name?.value && node.loc?.source && (node.operation === "query" || node.operation === "mutation")) {
|
|
273
|
-
operations[node.operation][node.name.value] = node.loc.source.body;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
});
|
|
278
|
-
return `const documents = ${JSON.stringify(operations, null, 2)};
|
|
279
|
-
export { documents };`;
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
const PluginNuxtGraphqlMiddlewareDocuments = {
|
|
283
|
-
__proto__: null,
|
|
284
|
-
plugin: plugin
|
|
285
|
-
};
|
|
286
|
-
|
|
287
63
|
function pluginLoader(name) {
|
|
288
64
|
switch (name) {
|
|
289
|
-
case "@graphql-codegen/typescript":
|
|
290
|
-
return Promise.resolve(PluginTypescript);
|
|
291
|
-
case "@graphql-codegen/typescript-operations":
|
|
292
|
-
return Promise.resolve(PluginTypescriptOperations);
|
|
293
|
-
case "@graphql-codegen/typescript-nuxt-graphql-middleware":
|
|
294
|
-
return Promise.resolve(PluginNuxtGraphqlMiddleware);
|
|
295
|
-
case "@graphql-codegen/typescript-nuxt-graphql-middleware-documents":
|
|
296
|
-
return Promise.resolve(PluginNuxtGraphqlMiddlewareDocuments);
|
|
297
65
|
case "@graphql-codegen/schema-ast":
|
|
298
66
|
return Promise.resolve(PluginSchemaAst);
|
|
299
67
|
}
|
|
@@ -317,88 +85,11 @@ function generateSchema(moduleOptions, dest, writeToDisk) {
|
|
|
317
85
|
}
|
|
318
86
|
}
|
|
319
87
|
};
|
|
320
|
-
return generate
|
|
321
|
-
}
|
|
322
|
-
function generateTemplates(documents, schemaPath, options) {
|
|
323
|
-
return executeCodegen({
|
|
324
|
-
schema: schemaPath,
|
|
325
|
-
pluginLoader,
|
|
326
|
-
silent: true,
|
|
327
|
-
errorsOnly: true,
|
|
328
|
-
documents,
|
|
329
|
-
generates: {
|
|
330
|
-
[GraphqlMiddlewareTemplate.OperationTypes]: {
|
|
331
|
-
plugins: ["typescript", "typescript-operations"],
|
|
332
|
-
config: options.codegenConfig
|
|
333
|
-
},
|
|
334
|
-
[GraphqlMiddlewareTemplate.ComposableContext]: {
|
|
335
|
-
plugins: ["typescript-nuxt-graphql-middleware"],
|
|
336
|
-
config: {
|
|
337
|
-
serverApiPrefix: options.serverApiPrefix
|
|
338
|
-
}
|
|
339
|
-
},
|
|
340
|
-
[GraphqlMiddlewareTemplate.Documents]: {
|
|
341
|
-
plugins: ["typescript-nuxt-graphql-middleware-documents"]
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
function getMaxLengths(documents) {
|
|
348
|
-
let longestOperation = 0;
|
|
349
|
-
let longestName = 0;
|
|
350
|
-
let longestPath = 0;
|
|
351
|
-
for (const { operation, name, relativePath } of documents) {
|
|
352
|
-
if (operation && operation.length > longestOperation) {
|
|
353
|
-
longestOperation = operation.length;
|
|
354
|
-
}
|
|
355
|
-
if (name && name.length > longestName) {
|
|
356
|
-
longestName = name.length;
|
|
357
|
-
}
|
|
358
|
-
if (relativePath && relativePath.length > longestPath) {
|
|
359
|
-
longestPath = relativePath.length;
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
return { longestOperation, longestName, longestPath };
|
|
363
|
-
}
|
|
364
|
-
function logDocuments(logger, documents, logEverything) {
|
|
365
|
-
const { longestOperation, longestName, longestPath } = getMaxLengths(documents);
|
|
366
|
-
logger.log(colors.green("GraphQL Document Validation"));
|
|
367
|
-
for (const { operation, name, relativePath, isValid, errors } of documents) {
|
|
368
|
-
if (logEverything || !isValid) {
|
|
369
|
-
let log = "";
|
|
370
|
-
log += (operation || "").padEnd(longestOperation + 2);
|
|
371
|
-
log += colors.cyan((name || "").padEnd(longestName + 2));
|
|
372
|
-
log += colors.dim((relativePath || "").padEnd(longestPath + 2));
|
|
373
|
-
log += isValid ? colors.green("\u2713") : colors.red("x");
|
|
374
|
-
if (!isValid && errors) {
|
|
375
|
-
log += "\n" + errors.map((error) => colors.red(error)).join("\n");
|
|
376
|
-
}
|
|
377
|
-
logger.log(log);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
process.stdout.write("\n");
|
|
381
|
-
logger.restoreStd();
|
|
382
|
-
if (documents.some((v) => !v.isValid)) {
|
|
383
|
-
logger.error("GraphQL document validation failed with errors.");
|
|
384
|
-
} else {
|
|
385
|
-
logger.success("GraphQL document validation completed successfully.");
|
|
386
|
-
}
|
|
88
|
+
return generate(config, writeToDisk).then((v) => v[0]);
|
|
387
89
|
}
|
|
388
90
|
|
|
389
91
|
const logger = useLogger(name);
|
|
390
92
|
const defaultOptions = {
|
|
391
|
-
codegenConfig: {
|
|
392
|
-
exportFragmentSpreadSubTypes: true,
|
|
393
|
-
preResolveTypes: true,
|
|
394
|
-
skipTypeNameForRoot: true,
|
|
395
|
-
skipTypename: true,
|
|
396
|
-
useTypeImports: true,
|
|
397
|
-
onlyOperationTypes: true,
|
|
398
|
-
namingConvention: {
|
|
399
|
-
enumValues: "change-case-all#upperCaseFirst"
|
|
400
|
-
}
|
|
401
|
-
},
|
|
402
93
|
downloadSchema: true,
|
|
403
94
|
schemaPath: "~~/schema.graphql",
|
|
404
95
|
serverApiPrefix: "/api/graphql_middleware",
|
|
@@ -408,16 +99,6 @@ const defaultOptions = {
|
|
|
408
99
|
documents: [],
|
|
409
100
|
devtools: true
|
|
410
101
|
};
|
|
411
|
-
function inlineFragments(source, resolver) {
|
|
412
|
-
return inlineImportsWithLineToImports(source, {
|
|
413
|
-
resolveImport(identifier) {
|
|
414
|
-
return resolver(identifier);
|
|
415
|
-
},
|
|
416
|
-
resolveOptions: {
|
|
417
|
-
basedir: "./"
|
|
418
|
-
}
|
|
419
|
-
}).inlineImports;
|
|
420
|
-
}
|
|
421
102
|
function validateOptions(options) {
|
|
422
103
|
if (!options.graphqlEndpoint) {
|
|
423
104
|
throw new Error("Missing graphqlEndpoint.");
|
|
@@ -433,321 +114,443 @@ async function getSchemaPath(schemaPath, options, resolver, writeToDisk = false)
|
|
|
433
114
|
);
|
|
434
115
|
throw new Error("Missing GraphQL schema.");
|
|
435
116
|
}
|
|
436
|
-
|
|
117
|
+
const schemaContent = await promises.readFile(dest).then((v) => v.toString());
|
|
118
|
+
return { schemaPath, schemaContent };
|
|
437
119
|
}
|
|
438
120
|
if (!options.graphqlEndpoint) {
|
|
439
121
|
throw new Error("Missing graphqlEndpoint config.");
|
|
440
122
|
}
|
|
441
|
-
await generateSchema(options, dest, writeToDisk);
|
|
442
|
-
return
|
|
123
|
+
const result = await generateSchema(options, dest, writeToDisk);
|
|
124
|
+
return { schemaPath, schemaContent: result.content };
|
|
443
125
|
}
|
|
444
|
-
|
|
445
|
-
if (!
|
|
446
|
-
return
|
|
126
|
+
const fileExists = (path, extensions = ["js", "ts", "mjs"]) => {
|
|
127
|
+
if (!path) {
|
|
128
|
+
return null;
|
|
129
|
+
} else if (existsSync$1(path)) {
|
|
130
|
+
return path;
|
|
447
131
|
}
|
|
448
|
-
const
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
132
|
+
const extension = extensions.find(
|
|
133
|
+
(extension2) => existsSync$1(`${path}.${extension2}`)
|
|
134
|
+
);
|
|
135
|
+
return extension ? `${path}.${extension}` : null;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
function groupOperationsByType(ops) {
|
|
139
|
+
const result = {
|
|
140
|
+
query: {},
|
|
141
|
+
mutation: {},
|
|
142
|
+
subscription: {}
|
|
143
|
+
};
|
|
144
|
+
for (const op of ops) {
|
|
145
|
+
result[op.operationType][op.graphqlName] = {
|
|
146
|
+
hasVariables: op.hasVariables,
|
|
147
|
+
variablesOptional: !op.needsVariables
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
function buildOperationTypeCode(operationMetadata, typeName, serverApiPrefix) {
|
|
153
|
+
const imports = [];
|
|
154
|
+
const resultTypes = [];
|
|
155
|
+
let code = "";
|
|
156
|
+
let nitroCode = "";
|
|
157
|
+
const operationNames = Object.keys(operationMetadata);
|
|
158
|
+
if (operationNames.length === 0) {
|
|
159
|
+
return { code, nitroCode, imports, resultTypes };
|
|
160
|
+
}
|
|
161
|
+
const lines = [];
|
|
162
|
+
const nitroLines = [];
|
|
163
|
+
for (const name of operationNames) {
|
|
164
|
+
const nameResult = pascalCase(`${name}${typeName}`);
|
|
165
|
+
const nameVariables = pascalCase(`${name}${typeName}Variables`);
|
|
166
|
+
resultTypes.push(nameResult);
|
|
167
|
+
imports.push(nameResult);
|
|
168
|
+
const { hasVariables, variablesOptional } = operationMetadata[name];
|
|
169
|
+
if (hasVariables) {
|
|
170
|
+
imports.push(nameVariables);
|
|
171
|
+
}
|
|
172
|
+
const variablesType = hasVariables ? nameVariables : "null";
|
|
173
|
+
lines.push(
|
|
174
|
+
` ${name}: [${variablesType}, ${variablesOptional ? "true" : "false"}, ${nameResult}]`
|
|
175
|
+
);
|
|
176
|
+
nitroLines.push(`
|
|
177
|
+
'${serverApiPrefix}/${typeName.toLowerCase()}/${name}': {
|
|
178
|
+
'default': GraphqlResponse<${nameResult}>
|
|
179
|
+
}`);
|
|
180
|
+
}
|
|
181
|
+
code += ` export type GraphqlMiddleware${typeName} = {
|
|
182
|
+
${lines.join(",\n")}
|
|
183
|
+
}
|
|
184
|
+
`;
|
|
185
|
+
nitroCode += nitroLines.join("\n");
|
|
186
|
+
return { code, nitroCode, imports, resultTypes };
|
|
187
|
+
}
|
|
188
|
+
function generateContextTemplate(collectedOperations, serverApiPrefix) {
|
|
189
|
+
const grouped = groupOperationsByType(collectedOperations);
|
|
190
|
+
const queryResult = buildOperationTypeCode(
|
|
191
|
+
grouped.query,
|
|
192
|
+
"Query",
|
|
193
|
+
serverApiPrefix
|
|
463
194
|
);
|
|
195
|
+
const mutationResult = buildOperationTypeCode(
|
|
196
|
+
grouped.mutation,
|
|
197
|
+
"Mutation",
|
|
198
|
+
serverApiPrefix
|
|
199
|
+
);
|
|
200
|
+
const subscriptionResult = buildOperationTypeCode(
|
|
201
|
+
grouped.subscription,
|
|
202
|
+
"Subscription",
|
|
203
|
+
serverApiPrefix
|
|
204
|
+
);
|
|
205
|
+
const allImports = [
|
|
206
|
+
...queryResult.imports,
|
|
207
|
+
...mutationResult.imports,
|
|
208
|
+
...subscriptionResult.imports
|
|
209
|
+
];
|
|
210
|
+
const allResultTypes = [
|
|
211
|
+
...queryResult.resultTypes,
|
|
212
|
+
...mutationResult.resultTypes,
|
|
213
|
+
...subscriptionResult.resultTypes
|
|
214
|
+
];
|
|
215
|
+
const combinedCode = [
|
|
216
|
+
queryResult.code,
|
|
217
|
+
mutationResult.code,
|
|
218
|
+
subscriptionResult.code
|
|
219
|
+
].join("\n");
|
|
220
|
+
const combinedNitroCode = [
|
|
221
|
+
queryResult.nitroCode,
|
|
222
|
+
mutationResult.nitroCode,
|
|
223
|
+
subscriptionResult.nitroCode
|
|
224
|
+
].join("\n");
|
|
225
|
+
return `
|
|
226
|
+
import type { GraphqlResponse } from '#graphql-middleware-server-options-build'
|
|
227
|
+
import type {
|
|
228
|
+
${allImports.join(",\n ")}
|
|
229
|
+
} from './../graphql-operations'
|
|
230
|
+
|
|
231
|
+
declare module '#nuxt-graphql-middleware/generated-types' {
|
|
232
|
+
export type GraphqlMiddlewareResponseUnion = ${allResultTypes.join(" | ")}
|
|
233
|
+
${combinedCode}
|
|
464
234
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
235
|
+
|
|
236
|
+
declare module 'nitropack' {
|
|
237
|
+
interface InternalApi {
|
|
238
|
+
${combinedNitroCode}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
`;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function getMaxLengths(entries) {
|
|
245
|
+
let name = 0;
|
|
246
|
+
let path = 0;
|
|
247
|
+
let type = 0;
|
|
248
|
+
for (const entry of entries) {
|
|
249
|
+
if (entry.type.length > type) {
|
|
250
|
+
type = entry.type.length;
|
|
471
251
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
if (
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
252
|
+
if (entry.name.length > name) {
|
|
253
|
+
name = entry.name.length;
|
|
254
|
+
}
|
|
255
|
+
if (entry.path.length > path) {
|
|
256
|
+
path = entry.path.length;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return { name, path, type };
|
|
260
|
+
}
|
|
261
|
+
function logAllEntries(entries) {
|
|
262
|
+
const lengths = getMaxLengths(entries);
|
|
263
|
+
let prevHadError = false;
|
|
264
|
+
for (const entry of entries) {
|
|
265
|
+
const hasErrors = entry.errors.length > 0;
|
|
266
|
+
const icon = hasErrors ? colors.red(" x ") : colors.green(" \u2713 ");
|
|
267
|
+
const type = entry.type.padEnd(lengths.type);
|
|
268
|
+
const namePadded = colors.bold(entry.name.padEnd(lengths.name));
|
|
269
|
+
const name = hasErrors ? colors.red(namePadded) : colors.green(namePadded);
|
|
270
|
+
const path = colors.dim(entry.path.padEnd(lengths.path));
|
|
271
|
+
const parts = [icon, type, name, path];
|
|
272
|
+
if (hasErrors && !prevHadError) {
|
|
273
|
+
process.stdout.write("-".repeat(process.stdout.columns) + "\n");
|
|
274
|
+
}
|
|
275
|
+
logger.log(parts.join(" | "));
|
|
276
|
+
if (hasErrors) {
|
|
277
|
+
const errorLines = [];
|
|
278
|
+
entry.errors.forEach((error) => {
|
|
279
|
+
let output = colors.red(error.message);
|
|
280
|
+
if (error.source && error.locations) {
|
|
281
|
+
for (const location of error.locations) {
|
|
282
|
+
output += "\n\n" + colors.red(printSourceLocation(error.source, location));
|
|
489
283
|
}
|
|
490
284
|
}
|
|
285
|
+
errorLines.push(output);
|
|
491
286
|
});
|
|
287
|
+
logger.log(
|
|
288
|
+
errorLines.join("\n").split("\n").map((v) => " " + v).join("\n")
|
|
289
|
+
);
|
|
290
|
+
process.stdout.write("-".repeat(process.stdout.columns) + "\n");
|
|
492
291
|
}
|
|
493
|
-
|
|
494
|
-
|
|
292
|
+
prevHadError = hasErrors;
|
|
293
|
+
}
|
|
294
|
+
logger.restoreStd();
|
|
495
295
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
296
|
+
class CollectedFile {
|
|
297
|
+
filePath;
|
|
298
|
+
fileContents;
|
|
299
|
+
isOnDisk;
|
|
300
|
+
parsed;
|
|
301
|
+
constructor(filePath, fileContents, isOnDisk = false) {
|
|
302
|
+
this.filePath = filePath;
|
|
303
|
+
this.fileContents = fileContents;
|
|
304
|
+
this.isOnDisk = isOnDisk;
|
|
305
|
+
this.parsed = parse(fileContents);
|
|
306
|
+
}
|
|
307
|
+
static async fromFilePath(filePath) {
|
|
308
|
+
const content = (await promises.readFile(filePath)).toString();
|
|
309
|
+
return new CollectedFile(filePath, content, true);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* If isOnDisk, re-read file contents from disk, then parse it (syntax only).
|
|
313
|
+
*/
|
|
314
|
+
async update() {
|
|
315
|
+
if (this.isOnDisk) {
|
|
316
|
+
const newContents = (await promises.readFile(this.filePath)).toString();
|
|
317
|
+
if (newContents === this.fileContents) {
|
|
318
|
+
return false;
|
|
510
319
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
} catch (e) {
|
|
517
|
-
logger.error(e);
|
|
518
|
-
logger.error(
|
|
519
|
-
"Failed to inline fragments for document: " + v.filename
|
|
520
|
-
);
|
|
521
|
-
}
|
|
522
|
-
return null;
|
|
523
|
-
}).filter(falsy);
|
|
524
|
-
}).then((docs) => {
|
|
525
|
-
return docs.filter((v) => v.content.trim());
|
|
526
|
-
});
|
|
527
|
-
if (!autoInlineFragments) {
|
|
528
|
-
return documents;
|
|
320
|
+
this.fileContents = newContents;
|
|
321
|
+
this.parsed = parse(newContents);
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
return false;
|
|
529
325
|
}
|
|
530
|
-
const fragmentMap = {};
|
|
531
|
-
documents.forEach((doc) => {
|
|
532
|
-
const parsed = parse(doc.content);
|
|
533
|
-
visit(parsed, {
|
|
534
|
-
FragmentDefinition(node) {
|
|
535
|
-
fragmentMap[node.name.value] = print(node);
|
|
536
|
-
}
|
|
537
|
-
});
|
|
538
|
-
});
|
|
539
|
-
documents.forEach((doc) => {
|
|
540
|
-
doc.content = inlineNestedFragments(doc.content, fragmentMap);
|
|
541
|
-
});
|
|
542
|
-
return documents;
|
|
543
326
|
}
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
327
|
+
class Collector {
|
|
328
|
+
constructor(schema, context, nuxtConfigDocuments = [], generatorOptions) {
|
|
329
|
+
this.schema = schema;
|
|
330
|
+
this.context = context;
|
|
331
|
+
this.nuxtConfigDocuments = nuxtConfigDocuments;
|
|
332
|
+
this.generator = new Generator(schema, generatorOptions);
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* All collected files.
|
|
336
|
+
*/
|
|
337
|
+
files = /* @__PURE__ */ new Map();
|
|
338
|
+
/**
|
|
339
|
+
* The code generator.
|
|
340
|
+
*/
|
|
341
|
+
generator;
|
|
342
|
+
/**
|
|
343
|
+
* A map of operation name and timestamp when the operation was last validated.
|
|
344
|
+
*/
|
|
345
|
+
operationTimestamps = /* @__PURE__ */ new Map();
|
|
346
|
+
/**
|
|
347
|
+
* The generated TypeScript type template output.
|
|
348
|
+
*/
|
|
349
|
+
outputTypes = "";
|
|
350
|
+
/**
|
|
351
|
+
* The generated oeprations file.
|
|
352
|
+
*/
|
|
353
|
+
outputOperations = "";
|
|
354
|
+
/**
|
|
355
|
+
* The generated context template file.
|
|
356
|
+
*/
|
|
357
|
+
outputContext = "";
|
|
358
|
+
/**
|
|
359
|
+
* Whether we need to rebuild the Generator state.
|
|
360
|
+
*/
|
|
361
|
+
needsRebuild = false;
|
|
362
|
+
filePathToRelative(filePath) {
|
|
363
|
+
return filePath.replace(this.context.srcDir, "~");
|
|
364
|
+
}
|
|
365
|
+
operationToLogEntry(operation, errors) {
|
|
366
|
+
return {
|
|
367
|
+
name: operation.graphqlName,
|
|
368
|
+
type: operation.operationType,
|
|
369
|
+
path: this.filePathToRelative(operation.filePath),
|
|
370
|
+
errors
|
|
371
|
+
};
|
|
548
372
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
const
|
|
556
|
-
|
|
557
|
-
|
|
373
|
+
/**
|
|
374
|
+
* Executes code gen and performs validation for operations.
|
|
375
|
+
*/
|
|
376
|
+
buildState() {
|
|
377
|
+
const output = this.generator.build();
|
|
378
|
+
const operations = output.getCollectedOperations();
|
|
379
|
+
const generatedCode = output.getGeneratedCode();
|
|
380
|
+
this.outputOperations = output.getOperationsFile();
|
|
381
|
+
this.outputTypes = output.getEverything();
|
|
382
|
+
this.outputContext = generateContextTemplate(
|
|
383
|
+
operations,
|
|
384
|
+
this.context.serverApiPrefix
|
|
385
|
+
);
|
|
386
|
+
const fragmentMap = /* @__PURE__ */ new Map();
|
|
387
|
+
const operationSourceMap = /* @__PURE__ */ new Map();
|
|
388
|
+
for (const code of generatedCode) {
|
|
389
|
+
if (code.type === "fragment" && code.graphqlName && code.source) {
|
|
390
|
+
fragmentMap.set(code.graphqlName, code.source);
|
|
391
|
+
} else if (code.type === "operation" && code.graphqlName && code.source) {
|
|
392
|
+
operationSourceMap.set(code.graphqlName, code.source);
|
|
393
|
+
}
|
|
558
394
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
]);
|
|
565
|
-
const operation = node.definitions.find(
|
|
566
|
-
(v) => v.kind === "OperationDefinition"
|
|
395
|
+
let hasErrors = false;
|
|
396
|
+
const logEntries = [];
|
|
397
|
+
for (const operation of operations) {
|
|
398
|
+
const previousTimestamp = this.operationTimestamps.get(
|
|
399
|
+
operation.graphqlName
|
|
567
400
|
);
|
|
568
|
-
if (operation) {
|
|
569
|
-
|
|
570
|
-
|
|
401
|
+
if (previousTimestamp === operation.timestamp) {
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
const fragments = operation.dependencies.map(
|
|
405
|
+
(v) => v.type === "fragment-name" ? fragmentMap.get(v.value) || "" : ""
|
|
406
|
+
).join("\n");
|
|
407
|
+
const fullOperation = operationSourceMap.get(operation.graphqlName) + fragments;
|
|
408
|
+
const source = new Source(fullOperation, basename(operation.filePath));
|
|
409
|
+
const document = parse(source);
|
|
410
|
+
const errors = validateGraphQlDocuments(this.schema, [document]);
|
|
411
|
+
if (errors.length) {
|
|
412
|
+
hasErrors = true;
|
|
571
413
|
} else {
|
|
572
|
-
|
|
414
|
+
this.operationTimestamps.set(operation.graphqlName, operation.timestamp);
|
|
573
415
|
}
|
|
574
|
-
|
|
575
|
-
} catch (e) {
|
|
576
|
-
document.errors = [e];
|
|
577
|
-
document.isValid = false;
|
|
416
|
+
logEntries.push(this.operationToLogEntry(operation, errors));
|
|
578
417
|
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
break;
|
|
418
|
+
logAllEntries(logEntries);
|
|
419
|
+
if (hasErrors) {
|
|
420
|
+
throw new Error("GraphQL errors");
|
|
583
421
|
}
|
|
584
422
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
OperationDefinition(node) {
|
|
594
|
-
if (node.name?.value === operationName) {
|
|
595
|
-
selectedOperation = node;
|
|
596
|
-
}
|
|
597
|
-
},
|
|
598
|
-
FragmentDefinition(node) {
|
|
599
|
-
fragments[node.name.value] = node;
|
|
423
|
+
/**
|
|
424
|
+
* Get all file paths that match the import patterns.
|
|
425
|
+
*/
|
|
426
|
+
async getImportPatternFiles() {
|
|
427
|
+
if (this.context.patterns.length) {
|
|
428
|
+
return resolveFiles(this.context.srcDir, this.context.patterns, {
|
|
429
|
+
followSymbolicLinks: false
|
|
430
|
+
});
|
|
600
431
|
}
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
432
|
+
return [];
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Initialise the collector.
|
|
436
|
+
*/
|
|
437
|
+
async init() {
|
|
438
|
+
const files = await this.getImportPatternFiles();
|
|
439
|
+
for (const filePath of files) {
|
|
440
|
+
await this.addFile(filePath);
|
|
441
|
+
}
|
|
442
|
+
this.nuxtConfigDocuments.forEach((docString, i) => {
|
|
443
|
+
const pseudoPath = `nuxt.config.ts[${i}]`;
|
|
444
|
+
const file = new CollectedFile(pseudoPath, docString, false);
|
|
445
|
+
this.files.set(pseudoPath, file);
|
|
446
|
+
this.generator.add({
|
|
447
|
+
filePath: "~/nuxt.config.ts",
|
|
448
|
+
documentNode: file.parsed
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
this.buildState();
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Add a file.
|
|
455
|
+
*/
|
|
456
|
+
async addFile(filePath) {
|
|
457
|
+
const file = await CollectedFile.fromFilePath(filePath);
|
|
458
|
+
this.files.set(filePath, file);
|
|
459
|
+
this.generator.add({
|
|
460
|
+
filePath: this.filePathToRelative(filePath),
|
|
461
|
+
documentNode: file.parsed
|
|
462
|
+
});
|
|
463
|
+
return file;
|
|
604
464
|
}
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
465
|
+
async handleAdd(filePath) {
|
|
466
|
+
await this.addFile(filePath);
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
469
|
+
async handleChange(filePath) {
|
|
470
|
+
const file = this.files.get(filePath);
|
|
471
|
+
if (!file) {
|
|
472
|
+
return false;
|
|
608
473
|
}
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
474
|
+
const needsUpdate = await file.update();
|
|
475
|
+
if (!needsUpdate) {
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
this.generator.update({
|
|
479
|
+
filePath: this.filePathToRelative(filePath),
|
|
480
|
+
documentNode: file.parsed
|
|
481
|
+
});
|
|
482
|
+
return true;
|
|
483
|
+
}
|
|
484
|
+
handleUnlink(filePath) {
|
|
485
|
+
const file = this.files.get(filePath);
|
|
486
|
+
if (!file) {
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
489
|
+
this.files.delete(filePath);
|
|
490
|
+
this.generator.remove(this.filePathToRelative(filePath));
|
|
491
|
+
return true;
|
|
492
|
+
}
|
|
493
|
+
handleUnlinkDir(folderPath) {
|
|
494
|
+
let anyHasChanged = false;
|
|
495
|
+
for (const filePath of [...this.files.keys()]) {
|
|
496
|
+
if (filePath.startsWith(folderPath)) {
|
|
497
|
+
const hasChanged = this.handleUnlink(filePath);
|
|
498
|
+
if (hasChanged) {
|
|
499
|
+
anyHasChanged = true;
|
|
620
500
|
}
|
|
621
|
-
}
|
|
501
|
+
}
|
|
622
502
|
}
|
|
503
|
+
return anyHasChanged;
|
|
623
504
|
}
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
)
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
);
|
|
643
|
-
const validated = validateDocuments(schema, documents, rootDir);
|
|
644
|
-
const extracted = validated.filter(
|
|
645
|
-
(v) => !v.operation
|
|
646
|
-
);
|
|
647
|
-
for (let i = 0; i < validated.length; i++) {
|
|
648
|
-
const v = validated[i];
|
|
649
|
-
if (!v) {
|
|
650
|
-
continue;
|
|
651
|
-
}
|
|
652
|
-
if (v.isValid) {
|
|
653
|
-
try {
|
|
654
|
-
const node = parse(v.content);
|
|
655
|
-
oldVisit(node, {
|
|
656
|
-
enter: {
|
|
657
|
-
OperationDefinition: (node2) => {
|
|
658
|
-
if (node2.name?.value && node2.loc?.source && (node2.operation === "query" || node2.operation === "mutation")) {
|
|
659
|
-
const document = { ...v };
|
|
660
|
-
const cleaned = cleanGraphqlDocument(
|
|
661
|
-
node2.loc.source.body,
|
|
662
|
-
node2.name.value
|
|
663
|
-
);
|
|
664
|
-
const errors = validateGraphQlDocuments(schema, [cleaned]);
|
|
665
|
-
document.errors = document.errors || [];
|
|
666
|
-
document.errors.push(...errors);
|
|
667
|
-
document.isValid = !document.errors.length;
|
|
668
|
-
document.name = node2.name.value;
|
|
669
|
-
document.operation = node2.operation;
|
|
670
|
-
document.content = print(cleaned);
|
|
671
|
-
document.id = [
|
|
672
|
-
document.operation,
|
|
673
|
-
document.name,
|
|
674
|
-
document.filename
|
|
675
|
-
].filter(Boolean).join("_");
|
|
676
|
-
extracted.push(document);
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
});
|
|
681
|
-
} catch (e) {
|
|
682
|
-
logger.error(e);
|
|
683
|
-
extracted.push(v);
|
|
684
|
-
break;
|
|
505
|
+
/**
|
|
506
|
+
* Handle the watcher event for the given file path.
|
|
507
|
+
*/
|
|
508
|
+
async handleWatchEvent(event, filePath) {
|
|
509
|
+
try {
|
|
510
|
+
let hasChanged = false;
|
|
511
|
+
if (event === "add") {
|
|
512
|
+
hasChanged = await this.handleAdd(filePath);
|
|
513
|
+
} else if (event === "change") {
|
|
514
|
+
hasChanged = await this.handleChange(filePath);
|
|
515
|
+
} else if (event === "unlink") {
|
|
516
|
+
hasChanged = this.handleUnlink(filePath);
|
|
517
|
+
} else if (event === "unlinkDir") {
|
|
518
|
+
hasChanged = this.handleUnlinkDir(filePath);
|
|
519
|
+
} else if (event === "addDir") {
|
|
520
|
+
}
|
|
521
|
+
if (hasChanged) {
|
|
522
|
+
this.buildState();
|
|
685
523
|
}
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
|
|
524
|
+
} catch (e) {
|
|
525
|
+
this.generator.resetCaches();
|
|
526
|
+
console.log(e);
|
|
689
527
|
}
|
|
690
528
|
}
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
const hasErrors = extracted.some((v) => !v.isValid) || validated.some((v) => !v.isValid);
|
|
697
|
-
if (hasErrors || logEverything) {
|
|
698
|
-
logDocuments(logger, extracted, logEverything);
|
|
529
|
+
/**
|
|
530
|
+
* Get the TypeScript types template contents.
|
|
531
|
+
*/
|
|
532
|
+
getTemplateTypes() {
|
|
533
|
+
return this.outputTypes;
|
|
699
534
|
}
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
return a.filename.localeCompare(b.filename);
|
|
706
|
-
}),
|
|
707
|
-
hasErrors,
|
|
708
|
-
documents: extracted.sort((a, b) => {
|
|
709
|
-
const nameA = a.name || "";
|
|
710
|
-
const nameB = b.name || "";
|
|
711
|
-
return nameA.localeCompare(nameB);
|
|
712
|
-
})
|
|
713
|
-
};
|
|
714
|
-
}
|
|
715
|
-
const fileExists = (path, extensions = ["js", "ts", "mjs"]) => {
|
|
716
|
-
if (!path) {
|
|
717
|
-
return null;
|
|
718
|
-
} else if (existsSync$1(path)) {
|
|
719
|
-
return path;
|
|
535
|
+
/**
|
|
536
|
+
* Get the context template contents.
|
|
537
|
+
*/
|
|
538
|
+
getTemplateContext() {
|
|
539
|
+
return this.outputContext;
|
|
720
540
|
}
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
async function outputDocuments(outputPath, documents) {
|
|
727
|
-
await promises.mkdir(outputPath, { recursive: true });
|
|
728
|
-
documents.forEach((v) => {
|
|
729
|
-
if (v.operation && v.name) {
|
|
730
|
-
const fileName = [v.operation, v.name, "graphql"].join(".");
|
|
731
|
-
const filePath = resolve(outputPath, fileName);
|
|
732
|
-
promises.writeFile(filePath, v.content);
|
|
733
|
-
}
|
|
734
|
-
});
|
|
735
|
-
}
|
|
736
|
-
async function getOutputDocumentsPath(optionsOutputDocuments, nuxtBuildDir, resolvePath) {
|
|
737
|
-
if (!optionsOutputDocuments) {
|
|
738
|
-
return null;
|
|
541
|
+
/**
|
|
542
|
+
* Get the operations template contents.
|
|
543
|
+
*/
|
|
544
|
+
getTemplateOperations() {
|
|
545
|
+
return this.outputOperations;
|
|
739
546
|
}
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
547
|
+
/**
|
|
548
|
+
* Log results (including parse/validation errors).
|
|
549
|
+
*/
|
|
550
|
+
logDocuments(logEverything) {
|
|
744
551
|
}
|
|
745
552
|
}
|
|
746
553
|
|
|
747
|
-
function pathWithoutExtension(fullPath) {
|
|
748
|
-
const parsed = parse$1(fullPath);
|
|
749
|
-
return join(parsed.dir, parsed.name);
|
|
750
|
-
}
|
|
751
554
|
const RPC_NAMESPACE = "nuxt-graphql-middleware";
|
|
752
555
|
const module = defineNuxtModule({
|
|
753
556
|
meta: {
|
|
@@ -761,12 +564,14 @@ const module = defineNuxtModule({
|
|
|
761
564
|
defaults: defaultOptions,
|
|
762
565
|
async setup(passedOptions, nuxt) {
|
|
763
566
|
const options = defu({}, passedOptions, defaultOptions);
|
|
567
|
+
function addAlias(name2, aliasPath) {
|
|
568
|
+
nuxt.options.alias[name2] = aliasPath;
|
|
569
|
+
}
|
|
764
570
|
const isModuleBuild = process.env.MODULE_BUILD === "true" && nuxt.options._prepare;
|
|
765
571
|
if (isModuleBuild) {
|
|
766
572
|
options.graphqlEndpoint = "http://localhost";
|
|
767
573
|
options.downloadSchema = false;
|
|
768
574
|
options.schemaPath = "~~/schema.graphql";
|
|
769
|
-
options.autoInlineFragments = true;
|
|
770
575
|
options.autoImportPatterns = [
|
|
771
576
|
"~~/playground/**/*.{gql,graphql}",
|
|
772
577
|
"!node_modules"
|
|
@@ -783,37 +588,47 @@ const module = defineNuxtModule({
|
|
|
783
588
|
if (!nuxt.options._prepare) {
|
|
784
589
|
validateOptions(options);
|
|
785
590
|
}
|
|
786
|
-
const schemaPathReplaced = resolveAlias(options.schemaPath);
|
|
787
591
|
const moduleResolver = createResolver(import.meta.url);
|
|
788
592
|
const serverResolver = createResolver(nuxt.options.serverDir);
|
|
789
593
|
const srcResolver = createResolver(nuxt.options.srcDir);
|
|
790
594
|
const appResolver = createResolver(nuxt.options.dir.app);
|
|
791
595
|
const rootDir = nuxt.options.rootDir;
|
|
792
596
|
const rootResolver = createResolver(rootDir);
|
|
793
|
-
const schemaPath = await getSchemaPath(
|
|
794
|
-
|
|
597
|
+
const { schemaPath, schemaContent } = await getSchemaPath(
|
|
598
|
+
resolveAlias(options.schemaPath),
|
|
795
599
|
options,
|
|
796
600
|
rootResolver.resolve,
|
|
797
601
|
options.downloadSchema
|
|
798
602
|
);
|
|
603
|
+
const schema = await loadSchema(schemaContent, {
|
|
604
|
+
loaders: []
|
|
605
|
+
});
|
|
799
606
|
const runtimeDir = fileURLToPath(new URL("./runtime", import.meta.url));
|
|
800
607
|
nuxt.options.build.transpile.push(runtimeDir);
|
|
801
|
-
const
|
|
802
|
-
|
|
803
|
-
|
|
608
|
+
const context = {
|
|
609
|
+
patterns: options.autoImportPatterns || [],
|
|
610
|
+
srcDir: nuxt.options.srcDir,
|
|
611
|
+
schemaPath,
|
|
612
|
+
serverApiPrefix: options.serverApiPrefix
|
|
804
613
|
};
|
|
805
|
-
|
|
614
|
+
const collector = new Collector(
|
|
615
|
+
schema,
|
|
616
|
+
context,
|
|
617
|
+
options.documents,
|
|
618
|
+
options.codegenConfig
|
|
619
|
+
);
|
|
620
|
+
await collector.init();
|
|
806
621
|
if (options.devtools) {
|
|
807
622
|
const clientPath = moduleResolver.resolve("./client");
|
|
808
623
|
setupDevToolsUI(nuxt, clientPath);
|
|
809
624
|
const setupRpc = () => {
|
|
810
|
-
|
|
625
|
+
extendServerRpc(RPC_NAMESPACE, {
|
|
811
626
|
// register server RPC functions
|
|
812
627
|
getModuleOptions() {
|
|
813
628
|
return options;
|
|
814
629
|
},
|
|
815
630
|
getDocuments() {
|
|
816
|
-
return
|
|
631
|
+
return [];
|
|
817
632
|
}
|
|
818
633
|
});
|
|
819
634
|
};
|
|
@@ -825,70 +640,6 @@ const module = defineNuxtModule({
|
|
|
825
640
|
});
|
|
826
641
|
}
|
|
827
642
|
}
|
|
828
|
-
let prompt = null;
|
|
829
|
-
const generateHandler = async (isFirst = false) => {
|
|
830
|
-
if (prompt && prompt.ui) {
|
|
831
|
-
prompt.ui.close();
|
|
832
|
-
prompt = null;
|
|
833
|
-
}
|
|
834
|
-
try {
|
|
835
|
-
const { templates, hasErrors, documents } = await generate(
|
|
836
|
-
options,
|
|
837
|
-
schemaPath,
|
|
838
|
-
rootResolver.resolve,
|
|
839
|
-
rootDir,
|
|
840
|
-
isFirst
|
|
841
|
-
);
|
|
842
|
-
ctx.templates = templates;
|
|
843
|
-
ctx.documents = documents;
|
|
844
|
-
rpc?.broadcast.documentsUpdated(documents);
|
|
845
|
-
const outputDocumentsPath = await getOutputDocumentsPath(
|
|
846
|
-
options.outputDocuments,
|
|
847
|
-
nuxt.options.buildDir,
|
|
848
|
-
rootResolver.resolvePath
|
|
849
|
-
);
|
|
850
|
-
if (outputDocumentsPath) {
|
|
851
|
-
outputDocuments(outputDocumentsPath, documents);
|
|
852
|
-
if (isFirst) {
|
|
853
|
-
logger.info("Documents generated at " + outputDocumentsPath);
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
if (hasErrors) {
|
|
857
|
-
throw new Error("Documents has errors.");
|
|
858
|
-
}
|
|
859
|
-
} catch (e) {
|
|
860
|
-
console.log(e);
|
|
861
|
-
logger.error("Failed to generate GraphQL files.");
|
|
862
|
-
if (isFirst) {
|
|
863
|
-
process.exit(1);
|
|
864
|
-
}
|
|
865
|
-
if (!options.downloadSchema) {
|
|
866
|
-
return;
|
|
867
|
-
}
|
|
868
|
-
if (!nuxt.options.dev) {
|
|
869
|
-
return;
|
|
870
|
-
}
|
|
871
|
-
process.stdout.write("\n");
|
|
872
|
-
logger.restoreStd();
|
|
873
|
-
prompt = inquirer.prompt({
|
|
874
|
-
type: "confirm",
|
|
875
|
-
name: "accept",
|
|
876
|
-
message: "Do you want to reload the GraphQL schema?"
|
|
877
|
-
});
|
|
878
|
-
prompt.then(async ({ accept }) => {
|
|
879
|
-
if (accept) {
|
|
880
|
-
await getSchemaPath(
|
|
881
|
-
schemaPathReplaced,
|
|
882
|
-
options,
|
|
883
|
-
rootResolver.resolve,
|
|
884
|
-
true
|
|
885
|
-
);
|
|
886
|
-
await generateHandler();
|
|
887
|
-
}
|
|
888
|
-
});
|
|
889
|
-
}
|
|
890
|
-
};
|
|
891
|
-
await generateHandler(true);
|
|
892
643
|
nuxt.options.runtimeConfig.public["nuxt-graphql-middleware"] = {
|
|
893
644
|
serverApiPrefix: options.serverApiPrefix
|
|
894
645
|
};
|
|
@@ -925,32 +676,27 @@ const module = defineNuxtModule({
|
|
|
925
676
|
);
|
|
926
677
|
addServerImports(serverUtils);
|
|
927
678
|
}
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
nuxt.options.alias["#graphql-operations"] = pathWithoutExtension(
|
|
945
|
-
result.dst
|
|
946
|
-
);
|
|
947
|
-
} else if (result.dst.includes(GraphqlMiddlewareTemplate.ComposableContext)) {
|
|
948
|
-
nuxt.options.alias["#nuxt-graphql-middleware/generated-types"] = pathWithoutExtension(result.dst);
|
|
949
|
-
}
|
|
679
|
+
const templateTypescript = addTemplate({
|
|
680
|
+
filename: GraphqlMiddlewareTemplate.OperationTypes,
|
|
681
|
+
write: true,
|
|
682
|
+
getContents: () => collector.getTemplateTypes()
|
|
683
|
+
});
|
|
684
|
+
addAlias("#graphql-operations", templateTypescript.dst);
|
|
685
|
+
const templateDocuments = addTemplate({
|
|
686
|
+
filename: GraphqlMiddlewareTemplate.Documents,
|
|
687
|
+
write: true,
|
|
688
|
+
getContents: () => collector.getTemplateOperations()
|
|
689
|
+
});
|
|
690
|
+
addAlias("#graphql-documents", templateDocuments.dst);
|
|
691
|
+
const templateContext = addTemplate({
|
|
692
|
+
filename: GraphqlMiddlewareTemplate.ComposableContext,
|
|
693
|
+
write: true,
|
|
694
|
+
getContents: () => collector.getTemplateContext()
|
|
950
695
|
});
|
|
696
|
+
addAlias("#nuxt-graphql-middleware/generated-types", templateContext.dst);
|
|
951
697
|
addTemplate({
|
|
952
698
|
write: true,
|
|
953
|
-
filename: "graphql-documents.d.ts",
|
|
699
|
+
filename: "nuxt-graphql-middleware/graphql-documents.d.ts",
|
|
954
700
|
getContents: () => {
|
|
955
701
|
return `
|
|
956
702
|
import type {
|
|
@@ -959,12 +705,12 @@ import type {
|
|
|
959
705
|
} from '#nuxt-graphql-middleware/generated-types'
|
|
960
706
|
|
|
961
707
|
declare module '#graphql-documents' {
|
|
962
|
-
type
|
|
708
|
+
type Operations = {
|
|
963
709
|
query: GraphqlMiddlewareQuery
|
|
964
710
|
mutation: GraphqlMiddlewareMutation
|
|
965
711
|
}
|
|
966
|
-
const
|
|
967
|
-
export {
|
|
712
|
+
const operations: Operations
|
|
713
|
+
export { operations, Operations }
|
|
968
714
|
}
|
|
969
715
|
`;
|
|
970
716
|
}
|
|
@@ -1075,12 +821,14 @@ export type GraphqlClientContext = {}
|
|
|
1075
821
|
`;
|
|
1076
822
|
}
|
|
1077
823
|
});
|
|
1078
|
-
|
|
824
|
+
addAlias("#graphql-middleware-client-options", clientOptionsTemplate.dst);
|
|
1079
825
|
nuxt.options.nitro.externals = nuxt.options.nitro.externals || {};
|
|
1080
826
|
nuxt.options.nitro.externals.inline = nuxt.options.nitro.externals.inline || [];
|
|
1081
827
|
nuxt.options.nitro.externals.inline.push(template.dst);
|
|
1082
|
-
nuxt.options.
|
|
1083
|
-
|
|
828
|
+
nuxt.options.nitro.externals.inline.push(templateDocuments.dst);
|
|
829
|
+
addAlias("#graphql-middleware-server-options-build", template.dst);
|
|
830
|
+
addAlias(
|
|
831
|
+
"#graphql-middleware/types",
|
|
1084
832
|
moduleResolver.resolve("./runtime/types.ts")
|
|
1085
833
|
);
|
|
1086
834
|
addServerHandler({
|
|
@@ -1109,26 +857,14 @@ export type GraphqlClientContext = {}
|
|
|
1109
857
|
handler: moduleResolver.resolve("./runtime/serverHandler/debug"),
|
|
1110
858
|
route: options.serverApiPrefix + "/debug"
|
|
1111
859
|
});
|
|
1112
|
-
nuxt.hook("
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
}
|
|
1121
|
-
if (schemaPath.includes(path)) {
|
|
1122
|
-
return;
|
|
1123
|
-
}
|
|
1124
|
-
await generateHandler();
|
|
1125
|
-
await updateTemplates({
|
|
1126
|
-
filter: (template2) => {
|
|
1127
|
-
return template2.options && template2.options.nuxtGraphqlMiddleware;
|
|
1128
|
-
}
|
|
1129
|
-
});
|
|
1130
|
-
await nitro.hooks.callHook("dev:reload");
|
|
1131
|
-
});
|
|
860
|
+
nuxt.hook("builder:watch", async (event, pathAbsolute) => {
|
|
861
|
+
if (pathAbsolute === schemaPath) {
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
if (!pathAbsolute.match(/\.(gql|graphql)$/)) {
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
await collector.handleWatchEvent(event, pathAbsolute);
|
|
1132
868
|
});
|
|
1133
869
|
}
|
|
1134
870
|
}
|