nuxt-graphql-middleware 4.3.2 → 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.mjs CHANGED
@@ -1,27 +1,23 @@
1
+ import { loadSchema } from '@graphql-tools/load';
1
2
  import { fileURLToPath } from 'url';
2
- import { dirname, resolve, relative } from 'pathe';
3
+ import { relative } from 'pathe';
3
4
  import { defu } from 'defu';
4
- import { useLogger, resolveAlias, resolveFiles, defineNuxtModule, createResolver, addImports, addServerImports, addTemplate, addServerHandler, addPlugin, updateTemplates } from '@nuxt/kit';
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 { oldVisit } from '@graphql-codegen/plugin-helpers';
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 = "4.3.2";
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$1(config, writeToDisk).then((v) => v[0]);
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,314 +114,440 @@ async function getSchemaPath(schemaPath, options, resolver, writeToDisk = false)
433
114
  );
434
115
  throw new Error("Missing GraphQL schema.");
435
116
  }
436
- return dest;
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 dest;
123
+ const result = await generateSchema(options, dest, writeToDisk);
124
+ return { schemaPath, schemaContent: result.content };
443
125
  }
444
- async function autoImportDocuments(patterns = [], srcResolver) {
445
- if (!patterns.length) {
446
- return Promise.resolve([]);
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 files = (await resolveFiles(srcResolver(), patterns, {
449
- followSymbolicLinks: false
450
- })).filter((path) => {
451
- return !path.includes("schema.gql") && !path.includes("schema.graphql");
452
- });
453
- return Promise.all(
454
- files.map((filename) => {
455
- return promises.readFile(filename).then((v) => {
456
- const content = v.toString().trim();
457
- return {
458
- content,
459
- filename
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
194
+ );
195
+ const mutationResult = buildOperationTypeCode(
196
+ grouped.mutation,
197
+ "Mutation",
198
+ serverApiPrefix
199
+ );
200
+ const subscriptionResult = buildOperationTypeCode(
201
+ grouped.subscription,
202
+ "Subscription",
203
+ serverApiPrefix
463
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}
234
+ }
235
+
236
+ declare module 'nitropack' {
237
+ interface InternalApi {
238
+ ${combinedNitroCode}
239
+ }
240
+ }
241
+ `;
464
242
  }
465
- function inlineNestedFragments(document, fragmentMap) {
466
- const parsed = parse(document);
467
- const fragmentsToInline = /* @__PURE__ */ new Set();
468
- visit(parsed, {
469
- FragmentSpread(node) {
470
- fragmentsToInline.add(node.name.value);
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
- fragmentsToInline.forEach((fragmentName) => {
474
- const fragment = fragmentMap[fragmentName];
475
- if (fragment) {
476
- document += "\n" + fragment;
477
- const nestedFragmentNames = /* @__PURE__ */ new Set();
478
- visit(parse(fragment), {
479
- FragmentSpread(node) {
480
- nestedFragmentNames.add(node.name.value);
481
- }
482
- });
483
- nestedFragmentNames.forEach((nestedFragmentName) => {
484
- if (!fragmentsToInline.has(nestedFragmentName)) {
485
- fragmentsToInline.add(nestedFragmentName);
486
- const nestedFragment = fragmentMap[nestedFragmentName];
487
- if (nestedFragment) {
488
- document += "\n" + nestedFragment;
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
- return document;
292
+ prevHadError = hasErrors;
293
+ }
294
+ logger.restoreStd();
495
295
  }
496
- async function buildDocuments(providedDocuments = [], autoImportPatterns, resolver, autoInlineFragments) {
497
- const documents = await autoImportDocuments(autoImportPatterns, resolver).then((importedDocuments) => [
498
- ...importedDocuments,
499
- ...providedDocuments.map((content) => ({
500
- content,
501
- filename: "nuxt.config.ts"
502
- }))
503
- ]).then((documents2) => {
504
- if (autoInlineFragments) {
505
- return documents2;
506
- }
507
- return documents2.map((v) => {
508
- if (!v.content.trim()) {
509
- return null;
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
- try {
512
- return {
513
- content: inlineFragments(v.content, resolveAlias),
514
- filename: v.filename
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
- function parseDocument(document, rootDir) {
545
- let name2 = document.filename ? document.filename.replace(rootDir, "") : "";
546
- if (name2.charAt(0) === "/") {
547
- name2 = name2.slice(1);
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
- const source = new Source(document.content, name2);
550
- return parse(source);
551
- }
552
- function validateDocuments(schema, documents, rootDir) {
553
- const validated = [];
554
- for (let i = 0; i < documents.length; i++) {
555
- const document = { ...documents[i] };
556
- if (document.filename) {
557
- document.relativePath = document.filename.replace(rootDir + "/", "");
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
- try {
560
- const node = parseDocument(document, rootDir);
561
- document.content = print(node);
562
- document.errors = validateGraphQlDocuments(schema, [
563
- node
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
- document.name = operation.name?.value;
570
- document.operation = operation.operation;
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
- document.name = document.relativePath;
414
+ this.operationTimestamps.set(operation.graphqlName, operation.timestamp);
573
415
  }
574
- document.isValid = document.errors.length === 0;
575
- } catch (e) {
576
- document.errors = [e];
577
- document.isValid = false;
416
+ logEntries.push(this.operationToLogEntry(operation, errors));
578
417
  }
579
- document.id = [document.operation, document.name, document.filename].filter(Boolean).join("_");
580
- validated.push(document);
581
- if (!document.isValid) {
582
- break;
418
+ logAllEntries(logEntries);
419
+ if (hasErrors) {
420
+ throw new Error("GraphQL errors");
583
421
  }
584
422
  }
585
- return validated;
586
- }
587
- function cleanGraphqlDocument(graphqlContent, operationName) {
588
- const document = parse(graphqlContent);
589
- let selectedOperation = null;
590
- const fragments = {};
591
- const usedFragments = /* @__PURE__ */ new Set();
592
- visit(document, {
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
- if (!selectedOperation) {
603
- throw new Error(`Operation named "${operationName}" not found`);
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;
464
+ }
465
+ async handleAdd(filePath) {
466
+ await this.addFile(filePath);
467
+ return true;
604
468
  }
605
- visit(selectedOperation, {
606
- FragmentSpread(node) {
607
- usedFragments.add(node.name.value);
469
+ async handleChange(filePath) {
470
+ const file = this.files.get(filePath);
471
+ if (!file) {
472
+ return false;
608
473
  }
609
- });
610
- let hasNewFragments = true;
611
- while (hasNewFragments) {
612
- hasNewFragments = false;
613
- for (const fragmentName of usedFragments) {
614
- visit(fragments[fragmentName], {
615
- FragmentSpread(node) {
616
- if (!usedFragments.has(node.name.value)) {
617
- usedFragments.add(node.name.value);
618
- hasNewFragments = true;
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
- return {
625
- kind: Kind.DOCUMENT,
626
- definitions: [
627
- selectedOperation,
628
- ...Array.from(usedFragments).map(
629
- (fragmentName) => fragments[fragmentName]
630
- )
631
- ]
632
- };
633
- }
634
- async function generate(options, schemaPath, resolver, rootDir, logEverything = false) {
635
- const schemaContent = await promises.readFile(schemaPath).then((v) => v.toString());
636
- const schema = await loadSchema(schemaContent, { loaders: [] });
637
- const documents = await buildDocuments(
638
- options.documents,
639
- options.autoImportPatterns,
640
- resolver,
641
- !!options.autoInlineFragments
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") {
685
520
  }
686
- } else {
687
- extracted.push(v);
688
- break;
521
+ if (hasChanged) {
522
+ this.buildState();
523
+ }
524
+ } catch (e) {
525
+ this.generator.resetCaches();
526
+ console.log(e);
689
527
  }
690
528
  }
691
- const templates = await generateTemplates(
692
- extracted.filter((v) => v.isValid).map((v) => v.content),
693
- schemaPath,
694
- options
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
- process.stdout.write("\n");
701
- logger.restoreStd();
702
- hasErrors ? logger.error("GraphQL code generation failed with errors.") : logger.success("Finished GraphQL code generation.");
703
- return {
704
- templates: templates.sort((a, b) => {
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
- const extension = extensions.find(
722
- (extension2) => existsSync$1(`${path}.${extension2}`)
723
- );
724
- return extension ? `${path}.${extension}` : null;
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
- if (typeof optionsOutputDocuments === "boolean") {
741
- return resolve(nuxtBuildDir, `${name}/documents`);
742
- } else {
743
- return await resolvePath(optionsOutputDocuments);
547
+ /**
548
+ * Log results (including parse/validation errors).
549
+ */
550
+ logDocuments(logEverything) {
744
551
  }
745
552
  }
746
553
 
@@ -765,7 +572,6 @@ const module = defineNuxtModule({
765
572
  options.graphqlEndpoint = "http://localhost";
766
573
  options.downloadSchema = false;
767
574
  options.schemaPath = "~~/schema.graphql";
768
- options.autoInlineFragments = true;
769
575
  options.autoImportPatterns = [
770
576
  "~~/playground/**/*.{gql,graphql}",
771
577
  "!node_modules"
@@ -782,37 +588,47 @@ const module = defineNuxtModule({
782
588
  if (!nuxt.options._prepare) {
783
589
  validateOptions(options);
784
590
  }
785
- const schemaPathReplaced = resolveAlias(options.schemaPath);
786
591
  const moduleResolver = createResolver(import.meta.url);
787
592
  const serverResolver = createResolver(nuxt.options.serverDir);
788
593
  const srcResolver = createResolver(nuxt.options.srcDir);
789
594
  const appResolver = createResolver(nuxt.options.dir.app);
790
595
  const rootDir = nuxt.options.rootDir;
791
596
  const rootResolver = createResolver(rootDir);
792
- const schemaPath = await getSchemaPath(
793
- schemaPathReplaced,
597
+ const { schemaPath, schemaContent } = await getSchemaPath(
598
+ resolveAlias(options.schemaPath),
794
599
  options,
795
600
  rootResolver.resolve,
796
601
  options.downloadSchema
797
602
  );
603
+ const schema = await loadSchema(schemaContent, {
604
+ loaders: []
605
+ });
798
606
  const runtimeDir = fileURLToPath(new URL("./runtime", import.meta.url));
799
607
  nuxt.options.build.transpile.push(runtimeDir);
800
- const ctx = {
801
- templates: [],
802
- documents: []
608
+ const context = {
609
+ patterns: options.autoImportPatterns || [],
610
+ srcDir: nuxt.options.srcDir,
611
+ schemaPath,
612
+ serverApiPrefix: options.serverApiPrefix
803
613
  };
804
- let rpc = null;
614
+ const collector = new Collector(
615
+ schema,
616
+ context,
617
+ options.documents,
618
+ options.codegenConfig
619
+ );
620
+ await collector.init();
805
621
  if (options.devtools) {
806
622
  const clientPath = moduleResolver.resolve("./client");
807
623
  setupDevToolsUI(nuxt, clientPath);
808
624
  const setupRpc = () => {
809
- rpc = extendServerRpc(RPC_NAMESPACE, {
625
+ extendServerRpc(RPC_NAMESPACE, {
810
626
  // register server RPC functions
811
627
  getModuleOptions() {
812
628
  return options;
813
629
  },
814
630
  getDocuments() {
815
- return ctx.documents;
631
+ return [];
816
632
  }
817
633
  });
818
634
  };
@@ -824,70 +640,6 @@ const module = defineNuxtModule({
824
640
  });
825
641
  }
826
642
  }
827
- let prompt = null;
828
- const generateHandler = async (isFirst = false) => {
829
- if (prompt && prompt.ui) {
830
- prompt.ui.close();
831
- prompt = null;
832
- }
833
- try {
834
- const { templates, hasErrors, documents } = await generate(
835
- options,
836
- schemaPath,
837
- rootResolver.resolve,
838
- rootDir,
839
- isFirst
840
- );
841
- ctx.templates = templates;
842
- ctx.documents = documents;
843
- rpc?.broadcast.documentsUpdated(documents);
844
- const outputDocumentsPath = await getOutputDocumentsPath(
845
- options.outputDocuments,
846
- nuxt.options.buildDir,
847
- rootResolver.resolvePath
848
- );
849
- if (outputDocumentsPath) {
850
- outputDocuments(outputDocumentsPath, documents);
851
- if (isFirst) {
852
- logger.info("Documents generated at " + outputDocumentsPath);
853
- }
854
- }
855
- if (hasErrors) {
856
- throw new Error("Documents has errors.");
857
- }
858
- } catch (e) {
859
- console.log(e);
860
- logger.error("Failed to generate GraphQL files.");
861
- if (isFirst) {
862
- process.exit(1);
863
- }
864
- if (!options.downloadSchema) {
865
- return;
866
- }
867
- if (!nuxt.options.dev) {
868
- return;
869
- }
870
- process.stdout.write("\n");
871
- logger.restoreStd();
872
- prompt = inquirer.prompt({
873
- type: "confirm",
874
- name: "accept",
875
- message: "Do you want to reload the GraphQL schema?"
876
- });
877
- prompt.then(async ({ accept }) => {
878
- if (accept) {
879
- await getSchemaPath(
880
- schemaPathReplaced,
881
- options,
882
- rootResolver.resolve,
883
- true
884
- );
885
- await generateHandler();
886
- }
887
- });
888
- }
889
- };
890
- await generateHandler(true);
891
643
  nuxt.options.runtimeConfig.public["nuxt-graphql-middleware"] = {
892
644
  serverApiPrefix: options.serverApiPrefix
893
645
  };
@@ -924,28 +676,27 @@ const module = defineNuxtModule({
924
676
  );
925
677
  addServerImports(serverUtils);
926
678
  }
927
- Object.values(GraphqlMiddlewareTemplate).forEach((filename) => {
928
- const result = addTemplate({
929
- write: true,
930
- filename,
931
- options: {
932
- nuxtGraphqlMiddleware: true
933
- },
934
- getContents: () => {
935
- return ctx.templates.find((v) => v.filename === filename)?.content || "";
936
- }
937
- });
938
- if (result.dst.includes(GraphqlMiddlewareTemplate.Documents)) {
939
- addAlias("#graphql-documents", result.dst);
940
- } else if (result.dst.includes(GraphqlMiddlewareTemplate.OperationTypes)) {
941
- addAlias("#graphql-operations", result.dst);
942
- } else if (result.dst.includes(GraphqlMiddlewareTemplate.ComposableContext)) {
943
- addAlias("#nuxt-graphql-middleware/generated-types", result.dst);
944
- }
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()
945
695
  });
696
+ addAlias("#nuxt-graphql-middleware/generated-types", templateContext.dst);
946
697
  addTemplate({
947
698
  write: true,
948
- filename: "graphql-documents.d.ts",
699
+ filename: "nuxt-graphql-middleware/graphql-documents.d.ts",
949
700
  getContents: () => {
950
701
  return `
951
702
  import type {
@@ -954,12 +705,12 @@ import type {
954
705
  } from '#nuxt-graphql-middleware/generated-types'
955
706
 
956
707
  declare module '#graphql-documents' {
957
- type Documents = {
708
+ type Operations = {
958
709
  query: GraphqlMiddlewareQuery
959
710
  mutation: GraphqlMiddlewareMutation
960
711
  }
961
- const documents: Documents
962
- export { documents, Documents }
712
+ const operations: Operations
713
+ export { operations, Operations }
963
714
  }
964
715
  `;
965
716
  }
@@ -1074,6 +825,7 @@ export type GraphqlClientContext = {}
1074
825
  nuxt.options.nitro.externals = nuxt.options.nitro.externals || {};
1075
826
  nuxt.options.nitro.externals.inline = nuxt.options.nitro.externals.inline || [];
1076
827
  nuxt.options.nitro.externals.inline.push(template.dst);
828
+ nuxt.options.nitro.externals.inline.push(templateDocuments.dst);
1077
829
  addAlias("#graphql-middleware-server-options-build", template.dst);
1078
830
  addAlias(
1079
831
  "#graphql-middleware/types",
@@ -1105,26 +857,14 @@ export type GraphqlClientContext = {}
1105
857
  handler: moduleResolver.resolve("./runtime/serverHandler/debug"),
1106
858
  route: options.serverApiPrefix + "/debug"
1107
859
  });
1108
- nuxt.hook("nitro:build:before", (nitro) => {
1109
- nuxt.hook("builder:watch", async (_event, path) => {
1110
- path = relative(
1111
- nuxt.options.srcDir,
1112
- resolve(nuxt.options.srcDir, path)
1113
- );
1114
- if (!path.match(/\.(gql|graphql)$/)) {
1115
- return;
1116
- }
1117
- if (schemaPath.includes(path)) {
1118
- return;
1119
- }
1120
- await generateHandler();
1121
- await updateTemplates({
1122
- filter: (template2) => {
1123
- return template2.options && template2.options.nuxtGraphqlMiddleware;
1124
- }
1125
- });
1126
- await nitro.hooks.callHook("dev:reload");
1127
- });
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);
1128
868
  });
1129
869
  }
1130
870
  }