graphql-buddy 0.1.2 → 0.1.3

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/api.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  normalizeGraphqlFiles,
6
6
  validate,
7
7
  validateDocuments
8
- } from "./chunk-O3MJ27FP.js";
8
+ } from "./chunk-6QT6BK6R.js";
9
9
  export {
10
10
  bundle,
11
11
  loadDocuments,
@@ -37,7 +37,6 @@ var __async = (__this, __arguments, generator) => {
37
37
 
38
38
  // src/api/commands/bundle.ts
39
39
  import * as graphqlToolsUtils from "@graphql-tools/utils";
40
- import * as graphql2 from "graphql";
41
40
 
42
41
  // src/api/shared/GraphqlFiles.ts
43
42
  import * as nodePath from "path";
@@ -171,7 +170,7 @@ var bundle = (options) => __async(null, null, function* () {
171
170
  if (shake) {
172
171
  schema = graphqlToolsUtils.pruneSchema(schema);
173
172
  }
174
- return graphql2.printSchema(schema);
173
+ return graphqlToolsUtils.printSchemaWithDirectives(schema);
175
174
  });
176
175
 
177
176
  // src/api/commands/validate.ts
@@ -220,4 +219,4 @@ export {
220
219
  bundle,
221
220
  validate
222
221
  };
223
- //# sourceMappingURL=chunk-O3MJ27FP.js.map
222
+ //# sourceMappingURL=chunk-6QT6BK6R.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api/commands/bundle.ts","../src/api/shared/GraphqlFiles.ts","../src/api/shared/loadDocuments.ts","../src/api/shared/loadSchema.ts","../src/api/shared/validateDocuments.ts","../src/api/commands/validate.ts"],"sourcesContent":["import * as graphqlToolsUtils from '@graphql-tools/utils';\n\nimport * as shared from '../shared';\n\nexport type BundleOptions = {\n schema: shared.GraphqlFiles;\n\n // Defaults to true.\n shake?: boolean | null;\n};\n\n/**\n * Bundles multiple schema together into a single file.\n *\n * @param options - Bundle options.\n *\n * @returns The merged schema as text.\n */\nexport const bundle = async (options: BundleOptions): Promise<string> => {\n const shake = options.shake ?? true;\n\n let schema = await shared.loadSchema(options.schema);\n if (shake) {\n schema = graphqlToolsUtils.pruneSchema(schema);\n }\n\n return graphqlToolsUtils.printSchemaWithDirectives(schema);\n};\n","import * as nodePath from 'node:path';\n\nimport * as glob from 'glob';\n\nexport type GraphqlFiles = UnsafeGraphqlFiles | NormalizedGraphqlFiles;\n\nexport type UnsafeGraphqlFiles = {\n normalized?: false | null;\n\n // Relative paths will be resolved using `base`.\n //\n // Also accepts glob patterns.\n files: Array<string>;\n\n // Directory from which `files` are resolved.\n //\n // Defaults to `process.cwd()`.\n base?: string | null;\n\n // See @graphql-tools/import#PathAliases\n //\n // Note that relative paths will be resolved relative to `base` to maintain\n // parity with `files`.\n pathAliases?: Map<string, string> | null;\n};\n\nexport type NormalizedGraphqlFiles = {\n normalized: true;\n\n // Absolute paths.\n files: Array<string>;\n\n // See @graphql-tools/import#PathAliases\n pathAliases: Map<string, string>;\n};\n\nexport const normalizeGraphqlFiles = async (\n graphqlFiles: GraphqlFiles,\n): Promise<NormalizedGraphqlFiles> => {\n if (graphqlFiles.normalized) {\n return graphqlFiles;\n }\n\n const base = graphqlFiles.base ?? process.cwd();\n const files = await glob.glob(\n graphqlFiles.files.map((file) => nodePath.resolve(base, file)),\n );\n\n const pathAliases = new Map<string, string>();\n if (graphqlFiles.pathAliases != null) {\n for (const [alias, source] of graphqlFiles.pathAliases.entries()) {\n pathAliases.set(alias, nodePath.resolve(base, source));\n }\n }\n\n return {\n normalized: true,\n files,\n pathAliases,\n };\n};\n","import * as nodeFs from 'node:fs/promises';\n\nimport * as graphqlFileLoader from '@graphql-tools/graphql-file-loader';\nimport * as graphqlLoad from '@graphql-tools/load';\n\nimport type * as graphqlUtils from '@graphql-tools/utils';\n\nimport * as graphqlFilesModule from './GraphqlFiles';\n\n/**\n * Loads, validates, and parses graphql documents.\n *\n * @param graphqlFiles - Operation or fragment files to process.\n *\n * @returns The parsed GraphQL documents (or throws an error if parsing fails).\n */\nexport const loadDocuments = async (\n graphqlFiles: graphqlFilesModule.GraphqlFiles,\n): Promise<Array<graphqlUtils.Source>> => {\n const { files, pathAliases } =\n await graphqlFilesModule.normalizeGraphqlFiles(graphqlFiles);\n\n // @graphql-tools/graphql-file-loader silently skips input files which are not\n // found. I suspect this is so that it can delegate missing inputs to other\n // loaders. For our purposes, this is undesirable because we want to inform\n // clients if expected inputs are missing. For that reason, we manually\n // validate that the files exist first.\n for (const file of files) {\n try {\n await nodeFs.access(file, nodeFs.constants.F_OK);\n } catch {\n throw new Error(`File does not exist: ${file}`);\n }\n }\n\n return await graphqlLoad.loadDocuments(files, {\n loaders: [new graphqlFileLoader.GraphQLFileLoader()],\n // By default @graphql-tools/load strips type definitions out of executable\n // documents, so SDL that lands in an operations file (or a schema file\n // caught by an operations glob) would silently vanish. Keeping every\n // definition lets `ExecutableDefinitionsRule` reject it during validation\n // instead.\n filterKinds: [],\n pathAliases: {\n mappings: Object.fromEntries(pathAliases.entries()),\n },\n });\n};\n","import * as nodeFs from 'node:fs/promises';\n\nimport * as graphqlFileLoader from '@graphql-tools/graphql-file-loader';\nimport * as graphqlLoad from '@graphql-tools/load';\n\nimport type * as graphql from 'graphql';\n\nimport * as graphqlFilesModule from './GraphqlFiles';\n\n/**\n * Loads, validates, and parses graphql schema.\n *\n * @param graphqlFiles - Schema files to process.\n *\n * @returns The parsed GraphQL schema (or throws an error if parsing fails).\n */\nexport const loadSchema = async (\n graphqlFiles: graphqlFilesModule.GraphqlFiles,\n): Promise<graphql.GraphQLSchema> => {\n const { files, pathAliases } =\n await graphqlFilesModule.normalizeGraphqlFiles(graphqlFiles);\n\n // @graphql-tools/graphql-file-loader silently skips input files which are not\n // found. I suspect this is so that it can delegate missing inputs to other\n // loaders. For our purposes, this is undesirable because we want to inform\n // clients if expected inputs are missing. For that reason, we manually\n // validate that the files exist first.\n for (const file of files) {\n try {\n await nodeFs.access(file, nodeFs.constants.F_OK);\n } catch {\n throw new Error(`File does not exist: ${file}`);\n }\n }\n\n return graphqlLoad.loadSchema(files, {\n loaders: [new graphqlFileLoader.GraphQLFileLoader()],\n pathAliases: {\n mappings: Object.fromEntries(pathAliases.entries()),\n },\n });\n};\n","import * as graphql from 'graphql';\n\nimport type * as graphqlUtils from '@graphql-tools/utils';\n\nexport type ValidateDocumentsOptions = {\n schema: graphql.GraphQLSchema;\n documents: Array<graphqlUtils.Source>;\n};\n\n/**\n * Validates GraphQL documents against their target schema.\n *\n * @param options - Validation options (schema and documents).\n *\n * @throws GraphQLError instances when validation fails.\n */\nexport const validateDocuments = (options: ValidateDocumentsOptions): void => {\n const { schema, documents } = options;\n\n for (const source of documents) {\n if (source.document == null) {\n continue;\n }\n\n const errors = validateDocument(schema, source.document);\n if (errors.length > 0) {\n throw errors[0];\n }\n }\n};\n\n/**\n * Validates a single document against the schema.\n *\n * This deliberately does not use `graphql.validate`. That function begins by\n * asserting the *schema* is valid, which among other things requires a query\n * root type. Fragment libraries are frequently validated against only the\n * type definitions they select from.\n *\n * @param schema - The parsed graphql schema.\n * @param document - The document to validate.\n *\n * @returns Any errors found in the document.\n */\nconst validateDocument = (\n schema: graphql.GraphQLSchema,\n document: graphql.DocumentNode,\n): Array<graphql.GraphQLError> => {\n const errors: Array<graphql.GraphQLError> = [];\n\n const operations = document.definitions.filter(\n (definition): definition is graphql.OperationDefinitionNode =>\n definition.kind === graphql.Kind.OPERATION_DEFINITION,\n );\n\n // Ensure each operation matches a root GraphQL type. This is not natively\n // checked by the `ValidationContext` because the validation context only\n // inspects operations whose type information is available.\n for (const operation of operations) {\n if (schema.getRootType(operation.operation) == null) {\n errors.push(\n new graphql.GraphQLError(\n `Schema does not define a ${operation.operation} root type.`,\n { nodes: operation },\n ),\n );\n }\n }\n\n // Fragment-only documents are fragment \"libraries\" that operations pull in\n // via `#import`. Validated in isolation they would trip\n // `NoUnusedFragmentsRule`, so we drop that single rule for them. Every\n // other rule, most importantly that each referenced field, argument, and\n // type actually exists, are still enforced.\n const rules = graphql.specifiedRules.filter(\n (rule) => operations.length > 0 || rule !== graphql.NoUnusedFragmentsRule,\n );\n\n const typeInfo = new graphql.TypeInfo(schema);\n const context = new graphql.ValidationContext(\n schema,\n document,\n typeInfo,\n (error) => {\n errors.push(error);\n },\n );\n graphql.visit(\n document,\n graphql.visitWithTypeInfo(\n typeInfo,\n graphql.visitInParallel(rules.map((rule) => rule(context))),\n ),\n );\n\n return errors;\n};\n","import * as stringifyObject from 'stringify-object';\n\nimport * as shared from '../shared';\n\nexport type ValidateOptions = {\n schema: shared.GraphqlFiles;\n\n // Optional GraphQL operation documents (queries, mutations, subscriptions,\n // and fragments) to validate against the loaded schema. When omitted, only\n // the schema itself is validated.\n operations?: shared.GraphqlFiles | null;\n};\n\n/**\n * Validates that the provided GraphQL schema contain valid syntax and have no\n * unknown symbols. When operations are provided, additionally validates that\n * every operation is valid against that schema.\n *\n * @param options - Validate options.\n *\n * @returns If validation is successful, returns a validation stamp: a text blob\n * describing the successful outcome and options used during validation. This\n * is often useful in build systems where a build step *must* emit a file. If\n * validation fails, a runtime error will be thrown.\n */\nexport const validate = async (options: ValidateOptions): Promise<string> => {\n // We manually normalize the `LoadSchemaOptions` so that we can write the most\n // accurate data in our validation stamp. For example, normalization expands\n // globs and resolves absolute paths. These are critical steps to ensure the\n // validation stamp describes without ambiguity which schema were loaded.\n const normalizedSchemaOptions = await shared.normalizeGraphqlFiles(\n options.schema,\n );\n\n const schema = await shared.loadSchema(normalizedSchemaOptions);\n\n if (options.operations == null) {\n return createValidationStamp({ schema: normalizedSchemaOptions });\n }\n\n const normalizedOperationsOptions = await shared.normalizeGraphqlFiles(\n options.operations,\n );\n shared.validateDocuments({\n schema,\n documents: await shared.loadDocuments(normalizedOperationsOptions),\n });\n\n return createValidationStamp({\n schema: normalizedSchemaOptions,\n operations: normalizedOperationsOptions,\n });\n};\n\nconst createValidationStamp = (options: {\n schema: shared.NormalizedGraphqlFiles;\n operations?: shared.NormalizedGraphqlFiles;\n}): string =>\n stringifyObject.default(\n {\n options: {\n schema: options.schema,\n operations: options.operations,\n },\n outcome: { valid: true },\n },\n {\n indent: ` `,\n filter: (container, property) =>\n !(container === options.schema && property === `normalized`) &&\n !(container === options.operations && property === `normalized`),\n },\n );\n"],"mappings":"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","names":["loadDocuments","nodeFs","graphqlFileLoader","graphqlLoad","loadSchema","loadSchema","loadSchema","loadDocuments"]}
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  __spreadValues,
5
5
  bundle,
6
6
  validate
7
- } from "./chunk-O3MJ27FP.js";
7
+ } from "./chunk-6QT6BK6R.js";
8
8
 
9
9
  // src/cli/index.ts
10
10
  import * as commander3 from "@commander-js/extra-typings";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphql-buddy",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": "Hunter John Larco",
@@ -26,6 +26,7 @@
26
26
  },
27
27
  "funding": "https://github.com/sponsors/hunterlarco",
28
28
  "scripts": {
29
+ "prepublishOnly": "pnpm run build",
29
30
  "build": "pnpm run typecheck && pnpm run bundle",
30
31
  "typecheck": "tsc --noEmit",
31
32
  "bundle": "tsup",
@@ -18,6 +18,10 @@ describe(`bundle`, () => {
18
18
  }),
19
19
  ).toStrictEqual(
20
20
  `
21
+ schema {
22
+ query: Query
23
+ }
24
+
21
25
  type Query {
22
26
  foo: Foo
23
27
  bar: Bar
@@ -49,6 +53,11 @@ type Bar {
49
53
  }),
50
54
  ).toStrictEqual(
51
55
  `
56
+ schema {
57
+ query: Query
58
+ mutation: Mutation
59
+ }
60
+
52
61
  type Bar {
53
62
  baz: Baz
54
63
  }
@@ -93,6 +102,12 @@ type Query {
93
102
  }),
94
103
  ).toStrictEqual(
95
104
  `
105
+ schema {
106
+ query: Query
107
+ mutation: Mutation
108
+ subscription: Subscription
109
+ }
110
+
96
111
  type Query {
97
112
  foo: Foo
98
113
  }
@@ -122,6 +137,48 @@ type FooEvent {
122
137
  );
123
138
  });
124
139
 
140
+ it(`preserves directive definitions and usages.`, async () => {
141
+ expect(
142
+ await bundle.bundle({
143
+ schema: {
144
+ files: [`*.graphql`],
145
+ base: nodePath.resolve(
146
+ __dirname,
147
+ `../../../test_fixtures/schema/directives`,
148
+ ),
149
+ },
150
+ }),
151
+ ).toStrictEqual(
152
+ `
153
+ schema {
154
+ query: Query
155
+ }
156
+
157
+ directive @auth(requires: Role = ADMIN) on OBJECT | FIELD_DEFINITION
158
+
159
+ directive @tag(name: String!) repeatable on OBJECT | FIELD_DEFINITION | ENUM
160
+
161
+ directive @unused on FIELD_DEFINITION
162
+
163
+ enum Role @tag(name: "enum") {
164
+ ADMIN
165
+ USER
166
+ }
167
+
168
+ type Query {
169
+ foo: Foo
170
+ legacyFoo: Foo @deprecated(reason: "Use \`foo\` instead.")
171
+ }
172
+
173
+ type Foo @auth @tag(name: "first") @tag(name: "second") {
174
+ id: ID!
175
+ displayName: String @auth(requires: USER)
176
+ secret: String @auth(requires: ADMIN) @tag(name: "sensitive")
177
+ }
178
+ `.trim(),
179
+ );
180
+ });
181
+
125
182
  it(`throws for invalid schema.`, async () => {
126
183
  await expect(
127
184
  bundle.bundle({
@@ -1,5 +1,4 @@
1
1
  import * as graphqlToolsUtils from '@graphql-tools/utils';
2
- import * as graphql from 'graphql';
3
2
 
4
3
  import * as shared from '../shared';
5
4
 
@@ -25,5 +24,5 @@ export const bundle = async (options: BundleOptions): Promise<string> => {
25
24
  schema = graphqlToolsUtils.pruneSchema(schema);
26
25
  }
27
26
 
28
- return graphql.printSchema(schema);
27
+ return graphqlToolsUtils.printSchemaWithDirectives(schema);
29
28
  };
@@ -0,0 +1,23 @@
1
+ directive @auth(requires: Role = ADMIN) on OBJECT | FIELD_DEFINITION
2
+
3
+ directive @tag(name: String!) repeatable on OBJECT | FIELD_DEFINITION | ENUM
4
+
5
+ directive @unused on FIELD_DEFINITION
6
+
7
+ enum Role @tag(name: "enum") {
8
+ ADMIN
9
+ USER
10
+ }
11
+
12
+ type Query {
13
+ foo: Foo
14
+ legacyFoo: Foo @deprecated(reason: "Use `foo` instead.")
15
+ }
16
+
17
+ type Foo @auth @tag(name: "first") @tag(name: "second") {
18
+ id: ID!
19
+
20
+ displayName: String @auth(requires: USER)
21
+
22
+ secret: String @auth(requires: ADMIN) @tag(name: "sensitive")
23
+ }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api/commands/bundle.ts","../src/api/shared/GraphqlFiles.ts","../src/api/shared/loadDocuments.ts","../src/api/shared/loadSchema.ts","../src/api/shared/validateDocuments.ts","../src/api/commands/validate.ts"],"sourcesContent":["import * as graphqlToolsUtils from '@graphql-tools/utils';\nimport * as graphql from 'graphql';\n\nimport * as shared from '../shared';\n\nexport type BundleOptions = {\n schema: shared.GraphqlFiles;\n\n // Defaults to true.\n shake?: boolean | null;\n};\n\n/**\n * Bundles multiple schema together into a single file.\n *\n * @param options - Bundle options.\n *\n * @returns The merged schema as text.\n */\nexport const bundle = async (options: BundleOptions): Promise<string> => {\n const shake = options.shake ?? true;\n\n let schema = await shared.loadSchema(options.schema);\n if (shake) {\n schema = graphqlToolsUtils.pruneSchema(schema);\n }\n\n return graphql.printSchema(schema);\n};\n","import * as nodePath from 'node:path';\n\nimport * as glob from 'glob';\n\nexport type GraphqlFiles = UnsafeGraphqlFiles | NormalizedGraphqlFiles;\n\nexport type UnsafeGraphqlFiles = {\n normalized?: false | null;\n\n // Relative paths will be resolved using `base`.\n //\n // Also accepts glob patterns.\n files: Array<string>;\n\n // Directory from which `files` are resolved.\n //\n // Defaults to `process.cwd()`.\n base?: string | null;\n\n // See @graphql-tools/import#PathAliases\n //\n // Note that relative paths will be resolved relative to `base` to maintain\n // parity with `files`.\n pathAliases?: Map<string, string> | null;\n};\n\nexport type NormalizedGraphqlFiles = {\n normalized: true;\n\n // Absolute paths.\n files: Array<string>;\n\n // See @graphql-tools/import#PathAliases\n pathAliases: Map<string, string>;\n};\n\nexport const normalizeGraphqlFiles = async (\n graphqlFiles: GraphqlFiles,\n): Promise<NormalizedGraphqlFiles> => {\n if (graphqlFiles.normalized) {\n return graphqlFiles;\n }\n\n const base = graphqlFiles.base ?? process.cwd();\n const files = await glob.glob(\n graphqlFiles.files.map((file) => nodePath.resolve(base, file)),\n );\n\n const pathAliases = new Map<string, string>();\n if (graphqlFiles.pathAliases != null) {\n for (const [alias, source] of graphqlFiles.pathAliases.entries()) {\n pathAliases.set(alias, nodePath.resolve(base, source));\n }\n }\n\n return {\n normalized: true,\n files,\n pathAliases,\n };\n};\n","import * as nodeFs from 'node:fs/promises';\n\nimport * as graphqlFileLoader from '@graphql-tools/graphql-file-loader';\nimport * as graphqlLoad from '@graphql-tools/load';\n\nimport type * as graphqlUtils from '@graphql-tools/utils';\n\nimport * as graphqlFilesModule from './GraphqlFiles';\n\n/**\n * Loads, validates, and parses graphql documents.\n *\n * @param graphqlFiles - Operation or fragment files to process.\n *\n * @returns The parsed GraphQL documents (or throws an error if parsing fails).\n */\nexport const loadDocuments = async (\n graphqlFiles: graphqlFilesModule.GraphqlFiles,\n): Promise<Array<graphqlUtils.Source>> => {\n const { files, pathAliases } =\n await graphqlFilesModule.normalizeGraphqlFiles(graphqlFiles);\n\n // @graphql-tools/graphql-file-loader silently skips input files which are not\n // found. I suspect this is so that it can delegate missing inputs to other\n // loaders. For our purposes, this is undesirable because we want to inform\n // clients if expected inputs are missing. For that reason, we manually\n // validate that the files exist first.\n for (const file of files) {\n try {\n await nodeFs.access(file, nodeFs.constants.F_OK);\n } catch {\n throw new Error(`File does not exist: ${file}`);\n }\n }\n\n return await graphqlLoad.loadDocuments(files, {\n loaders: [new graphqlFileLoader.GraphQLFileLoader()],\n // By default @graphql-tools/load strips type definitions out of executable\n // documents, so SDL that lands in an operations file (or a schema file\n // caught by an operations glob) would silently vanish. Keeping every\n // definition lets `ExecutableDefinitionsRule` reject it during validation\n // instead.\n filterKinds: [],\n pathAliases: {\n mappings: Object.fromEntries(pathAliases.entries()),\n },\n });\n};\n","import * as nodeFs from 'node:fs/promises';\n\nimport * as graphqlFileLoader from '@graphql-tools/graphql-file-loader';\nimport * as graphqlLoad from '@graphql-tools/load';\n\nimport type * as graphql from 'graphql';\n\nimport * as graphqlFilesModule from './GraphqlFiles';\n\n/**\n * Loads, validates, and parses graphql schema.\n *\n * @param graphqlFiles - Schema files to process.\n *\n * @returns The parsed GraphQL schema (or throws an error if parsing fails).\n */\nexport const loadSchema = async (\n graphqlFiles: graphqlFilesModule.GraphqlFiles,\n): Promise<graphql.GraphQLSchema> => {\n const { files, pathAliases } =\n await graphqlFilesModule.normalizeGraphqlFiles(graphqlFiles);\n\n // @graphql-tools/graphql-file-loader silently skips input files which are not\n // found. I suspect this is so that it can delegate missing inputs to other\n // loaders. For our purposes, this is undesirable because we want to inform\n // clients if expected inputs are missing. For that reason, we manually\n // validate that the files exist first.\n for (const file of files) {\n try {\n await nodeFs.access(file, nodeFs.constants.F_OK);\n } catch {\n throw new Error(`File does not exist: ${file}`);\n }\n }\n\n return graphqlLoad.loadSchema(files, {\n loaders: [new graphqlFileLoader.GraphQLFileLoader()],\n pathAliases: {\n mappings: Object.fromEntries(pathAliases.entries()),\n },\n });\n};\n","import * as graphql from 'graphql';\n\nimport type * as graphqlUtils from '@graphql-tools/utils';\n\nexport type ValidateDocumentsOptions = {\n schema: graphql.GraphQLSchema;\n documents: Array<graphqlUtils.Source>;\n};\n\n/**\n * Validates GraphQL documents against their target schema.\n *\n * @param options - Validation options (schema and documents).\n *\n * @throws GraphQLError instances when validation fails.\n */\nexport const validateDocuments = (options: ValidateDocumentsOptions): void => {\n const { schema, documents } = options;\n\n for (const source of documents) {\n if (source.document == null) {\n continue;\n }\n\n const errors = validateDocument(schema, source.document);\n if (errors.length > 0) {\n throw errors[0];\n }\n }\n};\n\n/**\n * Validates a single document against the schema.\n *\n * This deliberately does not use `graphql.validate`. That function begins by\n * asserting the *schema* is valid, which among other things requires a query\n * root type. Fragment libraries are frequently validated against only the\n * type definitions they select from.\n *\n * @param schema - The parsed graphql schema.\n * @param document - The document to validate.\n *\n * @returns Any errors found in the document.\n */\nconst validateDocument = (\n schema: graphql.GraphQLSchema,\n document: graphql.DocumentNode,\n): Array<graphql.GraphQLError> => {\n const errors: Array<graphql.GraphQLError> = [];\n\n const operations = document.definitions.filter(\n (definition): definition is graphql.OperationDefinitionNode =>\n definition.kind === graphql.Kind.OPERATION_DEFINITION,\n );\n\n // Ensure each operation matches a root GraphQL type. This is not natively\n // checked by the `ValidationContext` because the validation context only\n // inspects operations whose type information is available.\n for (const operation of operations) {\n if (schema.getRootType(operation.operation) == null) {\n errors.push(\n new graphql.GraphQLError(\n `Schema does not define a ${operation.operation} root type.`,\n { nodes: operation },\n ),\n );\n }\n }\n\n // Fragment-only documents are fragment \"libraries\" that operations pull in\n // via `#import`. Validated in isolation they would trip\n // `NoUnusedFragmentsRule`, so we drop that single rule for them. Every\n // other rule, most importantly that each referenced field, argument, and\n // type actually exists, are still enforced.\n const rules = graphql.specifiedRules.filter(\n (rule) => operations.length > 0 || rule !== graphql.NoUnusedFragmentsRule,\n );\n\n const typeInfo = new graphql.TypeInfo(schema);\n const context = new graphql.ValidationContext(\n schema,\n document,\n typeInfo,\n (error) => {\n errors.push(error);\n },\n );\n graphql.visit(\n document,\n graphql.visitWithTypeInfo(\n typeInfo,\n graphql.visitInParallel(rules.map((rule) => rule(context))),\n ),\n );\n\n return errors;\n};\n","import * as stringifyObject from 'stringify-object';\n\nimport * as shared from '../shared';\n\nexport type ValidateOptions = {\n schema: shared.GraphqlFiles;\n\n // Optional GraphQL operation documents (queries, mutations, subscriptions,\n // and fragments) to validate against the loaded schema. When omitted, only\n // the schema itself is validated.\n operations?: shared.GraphqlFiles | null;\n};\n\n/**\n * Validates that the provided GraphQL schema contain valid syntax and have no\n * unknown symbols. When operations are provided, additionally validates that\n * every operation is valid against that schema.\n *\n * @param options - Validate options.\n *\n * @returns If validation is successful, returns a validation stamp: a text blob\n * describing the successful outcome and options used during validation. This\n * is often useful in build systems where a build step *must* emit a file. If\n * validation fails, a runtime error will be thrown.\n */\nexport const validate = async (options: ValidateOptions): Promise<string> => {\n // We manually normalize the `LoadSchemaOptions` so that we can write the most\n // accurate data in our validation stamp. For example, normalization expands\n // globs and resolves absolute paths. These are critical steps to ensure the\n // validation stamp describes without ambiguity which schema were loaded.\n const normalizedSchemaOptions = await shared.normalizeGraphqlFiles(\n options.schema,\n );\n\n const schema = await shared.loadSchema(normalizedSchemaOptions);\n\n if (options.operations == null) {\n return createValidationStamp({ schema: normalizedSchemaOptions });\n }\n\n const normalizedOperationsOptions = await shared.normalizeGraphqlFiles(\n options.operations,\n );\n shared.validateDocuments({\n schema,\n documents: await shared.loadDocuments(normalizedOperationsOptions),\n });\n\n return createValidationStamp({\n schema: normalizedSchemaOptions,\n operations: normalizedOperationsOptions,\n });\n};\n\nconst createValidationStamp = (options: {\n schema: shared.NormalizedGraphqlFiles;\n operations?: shared.NormalizedGraphqlFiles;\n}): string =>\n stringifyObject.default(\n {\n options: {\n schema: options.schema,\n operations: options.operations,\n },\n outcome: { valid: true },\n },\n {\n indent: ` `,\n filter: (container, property) =>\n !(container === options.schema && property === `normalized`) &&\n !(container === options.operations && property === `normalized`),\n },\n );\n"],"mappings":"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","names":["graphql","loadDocuments","nodeFs","graphqlFileLoader","graphqlLoad","loadSchema","loadSchema","loadSchema","loadDocuments"]}