1 | import { Kind, validate, specifiedRules, concatAST, versionInfo, } from 'graphql';
|
2 | import { AggregateError } from './AggregateError.js';
|
3 | export async function validateGraphQlDocuments(schema, documentFiles, effectiveRules = createDefaultRules()) {
|
4 | const allFragmentMap = new Map();
|
5 | const documentFileObjectsToValidate = [];
|
6 | for (const documentFile of documentFiles) {
|
7 | if (documentFile.document) {
|
8 | const definitionsToValidate = [];
|
9 | for (const definitionNode of documentFile.document.definitions) {
|
10 | if (definitionNode.kind === Kind.FRAGMENT_DEFINITION) {
|
11 | allFragmentMap.set(definitionNode.name.value, definitionNode);
|
12 | }
|
13 | else {
|
14 | definitionsToValidate.push(definitionNode);
|
15 | }
|
16 | }
|
17 | documentFileObjectsToValidate.push({
|
18 | location: documentFile.location,
|
19 | document: {
|
20 | kind: Kind.DOCUMENT,
|
21 | definitions: definitionsToValidate,
|
22 | },
|
23 | });
|
24 | }
|
25 | }
|
26 | const allErrors = [];
|
27 | const allFragmentsDocument = {
|
28 | kind: Kind.DOCUMENT,
|
29 | definitions: [...allFragmentMap.values()],
|
30 | };
|
31 | await Promise.all(documentFileObjectsToValidate.map(async (documentFile) => {
|
32 | const documentToValidate = concatAST([allFragmentsDocument, documentFile.document]);
|
33 | const errors = validate(schema, documentToValidate, effectiveRules);
|
34 | if (errors.length > 0) {
|
35 | allErrors.push({
|
36 | filePath: documentFile.location,
|
37 | errors,
|
38 | });
|
39 | }
|
40 | }));
|
41 | return allErrors;
|
42 | }
|
43 | export function checkValidationErrors(loadDocumentErrors) {
|
44 | if (loadDocumentErrors.length > 0) {
|
45 | const errors = [];
|
46 | for (const loadDocumentError of loadDocumentErrors) {
|
47 | for (const graphQLError of loadDocumentError.errors) {
|
48 | const error = new Error();
|
49 | error.name = 'GraphQLDocumentError';
|
50 | error.message = `${error.name}: ${graphQLError.message}`;
|
51 | error.stack = error.message;
|
52 | if (graphQLError.locations) {
|
53 | for (const location of graphQLError.locations) {
|
54 | error.stack += `\n at ${loadDocumentError.filePath}:${location.line}:${location.column}`;
|
55 | }
|
56 | }
|
57 | errors.push(error);
|
58 | }
|
59 | }
|
60 | throw new AggregateError(errors, `GraphQL Document Validation failed with ${errors.length} errors;
|
61 | ${errors.map((error, index) => `Error ${index}: ${error.stack}`).join('\n\n')}`);
|
62 | }
|
63 | }
|
64 | export function createDefaultRules() {
|
65 | let ignored = ['NoUnusedFragmentsRule', 'NoUnusedVariablesRule', 'KnownDirectivesRule'];
|
66 | if (versionInfo.major < 15) {
|
67 | ignored = ignored.map(rule => rule.replace(/Rule$/, ''));
|
68 | }
|
69 | return specifiedRules.filter((f) => !ignored.includes(f.name));
|
70 | }
|