@graphql-inspector/core 4.0.2 → 4.0.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.
Files changed (193) hide show
  1. package/cjs/ast/document.js +40 -0
  2. package/cjs/coverage/index.js +128 -0
  3. package/cjs/coverage/output/json.js +7 -0
  4. package/cjs/diff/argument.js +25 -0
  5. package/cjs/diff/changes/argument.js +48 -0
  6. package/cjs/diff/changes/change.js +75 -0
  7. package/cjs/diff/changes/directive.js +124 -0
  8. package/cjs/diff/changes/enum.js +75 -0
  9. package/cjs/diff/changes/field.js +166 -0
  10. package/cjs/diff/changes/input.js +98 -0
  11. package/cjs/diff/changes/object.js +28 -0
  12. package/cjs/diff/changes/schema.js +40 -0
  13. package/cjs/diff/changes/type.js +72 -0
  14. package/cjs/diff/changes/union.js +28 -0
  15. package/cjs/diff/directive.js +41 -0
  16. package/cjs/diff/enum.js +34 -0
  17. package/cjs/diff/field.js +54 -0
  18. package/cjs/diff/index.js +22 -0
  19. package/cjs/diff/input.js +47 -0
  20. package/cjs/diff/interface.js +20 -0
  21. package/cjs/diff/object.js +33 -0
  22. package/cjs/diff/onComplete/types.js +0 -0
  23. package/cjs/diff/rules/config.js +0 -0
  24. package/cjs/diff/rules/consider-usage.js +39 -0
  25. package/cjs/diff/rules/dangerous-breaking.js +13 -0
  26. package/cjs/diff/rules/ignore-description-changes.js +21 -0
  27. package/cjs/diff/rules/index.js +8 -0
  28. package/cjs/diff/rules/safe-unreachable.js +19 -0
  29. package/cjs/diff/rules/suppress-removal-of-deprecated-field.js +58 -0
  30. package/cjs/diff/rules/types.js +0 -0
  31. package/cjs/diff/schema.js +107 -0
  32. package/cjs/diff/union.js +18 -0
  33. package/cjs/index.js +27 -0
  34. package/cjs/package.json +1 -0
  35. package/cjs/similar/index.js +57 -0
  36. package/cjs/utils/apollo.js +21 -0
  37. package/cjs/utils/compare.js +91 -0
  38. package/cjs/utils/graphql.js +194 -0
  39. package/cjs/utils/is-deprecated.js +17 -0
  40. package/cjs/utils/path.js +7 -0
  41. package/cjs/utils/string.js +70 -0
  42. package/cjs/validate/alias-count.js +37 -0
  43. package/cjs/validate/complexity.js +39 -0
  44. package/cjs/validate/directive-count.js +37 -0
  45. package/cjs/validate/index.js +143 -0
  46. package/cjs/validate/query-depth.js +103 -0
  47. package/cjs/validate/token-count.js +55 -0
  48. package/esm/ast/document.js +36 -0
  49. package/esm/coverage/index.js +124 -0
  50. package/esm/coverage/output/json.js +3 -0
  51. package/esm/diff/argument.js +21 -0
  52. package/esm/diff/changes/argument.js +42 -0
  53. package/esm/diff/changes/change.js +72 -0
  54. package/esm/diff/changes/directive.js +111 -0
  55. package/esm/diff/changes/enum.js +66 -0
  56. package/esm/diff/changes/field.js +150 -0
  57. package/esm/diff/changes/input.js +88 -0
  58. package/esm/diff/changes/object.js +23 -0
  59. package/esm/diff/changes/schema.js +34 -0
  60. package/esm/diff/changes/type.js +63 -0
  61. package/esm/diff/changes/union.js +23 -0
  62. package/esm/diff/directive.js +37 -0
  63. package/esm/diff/enum.js +30 -0
  64. package/esm/diff/field.js +50 -0
  65. package/esm/diff/index.js +18 -0
  66. package/esm/diff/input.js +43 -0
  67. package/esm/diff/interface.js +16 -0
  68. package/esm/diff/object.js +29 -0
  69. package/esm/diff/onComplete/types.js +0 -0
  70. package/esm/diff/rules/config.js +0 -0
  71. package/esm/diff/rules/consider-usage.js +35 -0
  72. package/esm/diff/rules/dangerous-breaking.js +9 -0
  73. package/esm/diff/rules/ignore-description-changes.js +17 -0
  74. package/esm/diff/rules/index.js +5 -0
  75. package/esm/diff/rules/safe-unreachable.js +15 -0
  76. package/esm/diff/rules/suppress-removal-of-deprecated-field.js +54 -0
  77. package/esm/diff/rules/types.js +0 -0
  78. package/esm/diff/schema.js +103 -0
  79. package/esm/diff/union.js +14 -0
  80. package/esm/index.js +11 -0
  81. package/esm/similar/index.js +53 -0
  82. package/esm/utils/apollo.js +16 -0
  83. package/esm/utils/compare.js +82 -0
  84. package/esm/utils/graphql.js +181 -0
  85. package/esm/utils/is-deprecated.js +13 -0
  86. package/esm/utils/path.js +3 -0
  87. package/esm/utils/string.js +64 -0
  88. package/esm/validate/alias-count.js +32 -0
  89. package/esm/validate/complexity.js +34 -0
  90. package/esm/validate/directive-count.js +32 -0
  91. package/esm/validate/index.js +139 -0
  92. package/esm/validate/query-depth.js +97 -0
  93. package/esm/validate/token-count.js +50 -0
  94. package/package.json +30 -9
  95. package/typings/ast/document.d.ts +15 -0
  96. package/typings/coverage/index.d.ts +51 -0
  97. package/typings/coverage/output/json.d.cts +2 -0
  98. package/{coverage → typings/coverage}/output/json.d.ts +1 -1
  99. package/typings/diff/argument.d.cts +3 -0
  100. package/{diff → typings/diff}/argument.d.ts +1 -1
  101. package/typings/diff/changes/argument.d.cts +5 -0
  102. package/{diff → typings/diff}/changes/argument.d.ts +1 -1
  103. package/typings/diff/changes/change.d.ts +69 -0
  104. package/typings/diff/changes/directive.d.cts +12 -0
  105. package/{diff → typings/diff}/changes/directive.d.ts +1 -1
  106. package/typings/diff/changes/enum.d.cts +8 -0
  107. package/{diff → typings/diff}/changes/enum.d.ts +1 -1
  108. package/typings/diff/changes/field.d.cts +15 -0
  109. package/{diff → typings/diff}/changes/field.d.ts +1 -1
  110. package/typings/diff/changes/input.d.cts +9 -0
  111. package/{diff → typings/diff}/changes/input.d.ts +1 -1
  112. package/typings/diff/changes/object.d.cts +4 -0
  113. package/{diff → typings/diff}/changes/object.d.ts +1 -1
  114. package/typings/diff/changes/schema.d.cts +5 -0
  115. package/{diff → typings/diff}/changes/schema.d.ts +1 -1
  116. package/typings/diff/changes/type.d.cts +8 -0
  117. package/{diff → typings/diff}/changes/type.d.ts +1 -1
  118. package/typings/diff/changes/union.d.cts +4 -0
  119. package/{diff → typings/diff}/changes/union.d.ts +1 -1
  120. package/typings/diff/directive.d.cts +3 -0
  121. package/{diff → typings/diff}/directive.d.ts +1 -1
  122. package/typings/diff/enum.d.cts +3 -0
  123. package/{diff → typings/diff}/enum.d.ts +1 -1
  124. package/typings/diff/field.d.cts +3 -0
  125. package/{diff → typings/diff}/field.d.ts +1 -1
  126. package/typings/diff/index.d.cts +9 -0
  127. package/typings/diff/index.d.ts +9 -0
  128. package/typings/diff/input.d.cts +3 -0
  129. package/{diff → typings/diff}/input.d.ts +1 -1
  130. package/typings/diff/interface.d.cts +3 -0
  131. package/{diff → typings/diff}/interface.d.ts +1 -1
  132. package/typings/diff/object.d.cts +3 -0
  133. package/{diff → typings/diff}/object.d.ts +1 -1
  134. package/typings/diff/onComplete/types.d.cts +7 -0
  135. package/typings/diff/onComplete/types.d.ts +7 -0
  136. package/typings/diff/rules/config.d.cts +2 -0
  137. package/typings/diff/rules/config.d.ts +2 -0
  138. package/typings/diff/rules/consider-usage.d.cts +29 -0
  139. package/{diff → typings/diff}/rules/consider-usage.d.ts +2 -2
  140. package/typings/diff/rules/dangerous-breaking.d.cts +2 -0
  141. package/{diff → typings/diff}/rules/dangerous-breaking.d.ts +1 -1
  142. package/typings/diff/rules/ignore-description-changes.d.cts +2 -0
  143. package/{diff → typings/diff}/rules/ignore-description-changes.d.ts +1 -1
  144. package/typings/diff/rules/index.d.cts +5 -0
  145. package/typings/diff/rules/index.d.ts +5 -0
  146. package/typings/diff/rules/safe-unreachable.d.cts +2 -0
  147. package/{diff → typings/diff}/rules/safe-unreachable.d.ts +1 -1
  148. package/typings/diff/rules/suppress-removal-of-deprecated-field.d.cts +2 -0
  149. package/{diff → typings/diff}/rules/suppress-removal-of-deprecated-field.d.ts +1 -1
  150. package/typings/diff/rules/types.d.cts +8 -0
  151. package/{diff → typings/diff}/rules/types.d.ts +2 -2
  152. package/typings/diff/schema.d.cts +4 -0
  153. package/{diff → typings/diff}/schema.d.ts +2 -2
  154. package/typings/diff/union.d.cts +3 -0
  155. package/{diff → typings/diff}/union.d.ts +1 -1
  156. package/typings/index.d.cts +12 -0
  157. package/typings/index.d.ts +12 -0
  158. package/typings/similar/index.d.cts +6 -0
  159. package/{similar → typings/similar}/index.d.ts +1 -1
  160. package/typings/utils/apollo.d.ts +5 -0
  161. package/typings/utils/compare.d.ts +22 -0
  162. package/typings/utils/graphql.d.ts +11 -0
  163. package/typings/utils/is-deprecated.d.cts +2 -0
  164. package/{utils → typings/utils}/is-deprecated.d.ts +1 -1
  165. package/typings/utils/path.d.ts +1 -0
  166. package/typings/utils/string.d.ts +14 -0
  167. package/typings/validate/alias-count.d.ts +10 -0
  168. package/typings/validate/complexity.d.cts +16 -0
  169. package/{validate → typings/validate}/complexity.d.ts +1 -1
  170. package/typings/validate/directive-count.d.ts +10 -0
  171. package/typings/validate/index.d.ts +49 -0
  172. package/typings/validate/query-depth.d.ts +15 -0
  173. package/typings/validate/token-count.d.ts +12 -0
  174. package/diff/index.d.ts +0 -9
  175. package/diff/onComplete/types.d.ts +0 -7
  176. package/diff/rules/config.d.ts +0 -2
  177. package/diff/rules/index.d.ts +0 -5
  178. package/index.d.ts +0 -12
  179. package/index.js +0 -2075
  180. package/index.mjs +0 -2061
  181. /package/{ast/document.d.ts → typings/ast/document.d.cts} +0 -0
  182. /package/{coverage/index.d.ts → typings/coverage/index.d.cts} +0 -0
  183. /package/{diff/changes/change.d.ts → typings/diff/changes/change.d.cts} +0 -0
  184. /package/{utils/apollo.d.ts → typings/utils/apollo.d.cts} +0 -0
  185. /package/{utils/compare.d.ts → typings/utils/compare.d.cts} +0 -0
  186. /package/{utils/graphql.d.ts → typings/utils/graphql.d.cts} +0 -0
  187. /package/{utils/path.d.ts → typings/utils/path.d.cts} +0 -0
  188. /package/{utils/string.d.ts → typings/utils/string.d.cts} +0 -0
  189. /package/{validate/alias-count.d.ts → typings/validate/alias-count.d.cts} +0 -0
  190. /package/{validate/directive-count.d.ts → typings/validate/directive-count.d.cts} +0 -0
  191. /package/{validate/index.d.ts → typings/validate/index.d.cts} +0 -0
  192. /package/{validate/query-depth.d.ts → typings/validate/query-depth.d.cts} +0 -0
  193. /package/{validate/token-count.d.ts → typings/validate/token-count.d.cts} +0 -0
@@ -0,0 +1,32 @@
1
+ import { GraphQLError, Kind } from 'graphql';
2
+ export function validateAliasCount({ source, doc, maxAliasCount, fragmentGraph, }) {
3
+ var _a;
4
+ const getFragmentByFragmentName = (fragmentName) => fragmentGraph.getNodeData(fragmentName);
5
+ for (const definition of doc.definitions) {
6
+ if (definition.kind !== Kind.OPERATION_DEFINITION) {
7
+ continue;
8
+ }
9
+ const aliasCount = countAliases(definition, getFragmentByFragmentName);
10
+ if (aliasCount > maxAliasCount) {
11
+ return new GraphQLError(`Too many aliases (${aliasCount}). Maximum allowed is ${maxAliasCount}`, [definition], source, ((_a = definition.loc) === null || _a === void 0 ? void 0 : _a.start) ? [definition.loc.start] : undefined);
12
+ }
13
+ }
14
+ }
15
+ export function countAliases(node, getFragmentByName) {
16
+ let aliases = 0;
17
+ if ('alias' in node && node.alias) {
18
+ ++aliases;
19
+ }
20
+ if ('selectionSet' in node && node.selectionSet) {
21
+ for (const child of node.selectionSet.selections) {
22
+ aliases += countAliases(child, getFragmentByName);
23
+ }
24
+ }
25
+ else if (node.kind === Kind.FRAGMENT_SPREAD) {
26
+ const fragmentNode = getFragmentByName(node.name.value);
27
+ if (fragmentNode) {
28
+ aliases += countAliases(fragmentNode, getFragmentByName);
29
+ }
30
+ }
31
+ return aliases;
32
+ }
@@ -0,0 +1,34 @@
1
+ import { GraphQLError, Kind } from 'graphql';
2
+ export function validateComplexity({ source, doc, maxComplexityScore, config, fragmentGraph, }) {
3
+ var _a;
4
+ const getFragmentByFragmentName = (fragmentName) => fragmentGraph.getNodeData(fragmentName);
5
+ for (const definition of doc.definitions) {
6
+ if (definition.kind !== Kind.OPERATION_DEFINITION) {
7
+ continue;
8
+ }
9
+ const complexityScore = calculateOperationComplexity(definition, config, getFragmentByFragmentName);
10
+ if (complexityScore > maxComplexityScore) {
11
+ return new GraphQLError(`Too high complexity score (${complexityScore}). Maximum allowed is ${maxComplexityScore}`, [definition], source, ((_a = definition.loc) === null || _a === void 0 ? void 0 : _a.start) ? [definition.loc.start] : undefined);
12
+ }
13
+ }
14
+ }
15
+ export function calculateOperationComplexity(node, config, getFragmentByName, depth = 0) {
16
+ let cost = config.scalarCost;
17
+ if ('selectionSet' in node && node.selectionSet) {
18
+ cost = config.objectCost;
19
+ for (const child of node.selectionSet.selections) {
20
+ cost +=
21
+ config.depthCostFactor *
22
+ calculateOperationComplexity(child, config, getFragmentByName, depth + 1);
23
+ }
24
+ }
25
+ if (node.kind == Kind.FRAGMENT_SPREAD) {
26
+ const fragment = getFragmentByName(node.name.value);
27
+ if (fragment) {
28
+ cost +=
29
+ config.depthCostFactor *
30
+ calculateOperationComplexity(fragment, config, getFragmentByName, depth + 1);
31
+ }
32
+ }
33
+ return cost;
34
+ }
@@ -0,0 +1,32 @@
1
+ import { GraphQLError, Kind } from 'graphql';
2
+ export function validateDirectiveCount({ source, doc, maxDirectiveCount, fragmentGraph, }) {
3
+ var _a;
4
+ const getFragmentByFragmentName = (fragmentName) => fragmentGraph.getNodeData(fragmentName);
5
+ for (const definition of doc.definitions) {
6
+ if (definition.kind !== Kind.OPERATION_DEFINITION) {
7
+ continue;
8
+ }
9
+ const directiveCount = countDirectives(definition, getFragmentByFragmentName);
10
+ if (directiveCount > maxDirectiveCount) {
11
+ return new GraphQLError(`Too many directives (${directiveCount}). Maximum allowed is ${maxDirectiveCount}`, [definition], source, ((_a = definition.loc) === null || _a === void 0 ? void 0 : _a.start) ? [definition.loc.start] : undefined);
12
+ }
13
+ }
14
+ }
15
+ export function countDirectives(node, getFragmentByName) {
16
+ let directives = 0;
17
+ if (node.directives) {
18
+ directives += node.directives.length;
19
+ }
20
+ if ('selectionSet' in node && node.selectionSet) {
21
+ for (const child of node.selectionSet.selections) {
22
+ directives += countDirectives(child, getFragmentByName);
23
+ }
24
+ }
25
+ if (node.kind == Kind.FRAGMENT_SPREAD) {
26
+ const fragment = getFragmentByName(node.name.value);
27
+ if (fragment) {
28
+ directives += countDirectives(fragment, getFragmentByName);
29
+ }
30
+ }
31
+ return directives;
32
+ }
@@ -0,0 +1,139 @@
1
+ import { DepGraph } from 'dependency-graph';
2
+ import { GraphQLError, Kind, print, validate as validateDocument, } from 'graphql';
3
+ import { readDocument } from '../ast/document.js';
4
+ import { transformDocumentWithApollo, transformSchemaWithApollo } from '../utils/apollo.js';
5
+ import { findDeprecatedUsages } from '../utils/graphql.js';
6
+ import { validateAliasCount } from './alias-count.js';
7
+ import { validateDirectiveCount } from './directive-count.js';
8
+ import { validateQueryDepth } from './query-depth.js';
9
+ import { validateTokenCount } from './token-count.js';
10
+ export function validate(schema, sources, options) {
11
+ const config = Object.assign({ strictDeprecated: true, strictFragments: true, keepClientFields: false, apollo: false }, options);
12
+ const invalidDocuments = [];
13
+ // read documents
14
+ const documents = sources.map(readDocument);
15
+ // keep all named fragments
16
+ const fragments = [];
17
+ const fragmentNames = [];
18
+ const graph = new DepGraph({ circular: true });
19
+ documents.forEach(doc => {
20
+ doc.fragments.forEach(fragment => {
21
+ fragmentNames.push(fragment.node.name.value);
22
+ fragments.push(fragment);
23
+ graph.addNode(fragment.node.name.value, fragment.node);
24
+ });
25
+ });
26
+ fragments.forEach(fragment => {
27
+ const depends = extractFragments(print(fragment.node));
28
+ if (depends) {
29
+ depends.forEach(name => {
30
+ graph.addDependency(fragment.node.name.value, name);
31
+ });
32
+ }
33
+ });
34
+ documents
35
+ // since we include fragments, validate only operations
36
+ .filter(doc => doc.hasOperations)
37
+ .forEach(doc => {
38
+ const docWithOperations = {
39
+ kind: Kind.DOCUMENT,
40
+ definitions: doc.operations.map(d => d.node),
41
+ };
42
+ const extractedFragments = (extractFragments(print(docWithOperations)) || [])
43
+ // resolve all nested fragments
44
+ .map(fragmentName => resolveFragment(graph.getNodeData(fragmentName), graph))
45
+ // flatten arrays
46
+ .reduce((list, current) => list.concat(current), [])
47
+ // remove duplicates
48
+ .filter((def, i, all) => all.findIndex(item => item.name.value === def.name.value) === i);
49
+ const merged = {
50
+ kind: Kind.DOCUMENT,
51
+ definitions: [...docWithOperations.definitions, ...extractedFragments],
52
+ };
53
+ const transformedSchema = config.apollo ? transformSchemaWithApollo(schema) : schema;
54
+ const transformedDoc = config.apollo
55
+ ? transformDocumentWithApollo(merged, {
56
+ keepClientFields: config.keepClientFields,
57
+ })
58
+ : merged;
59
+ const errors = validateDocument(transformedSchema, transformedDoc) || [];
60
+ if (config.maxDepth) {
61
+ const depthError = validateQueryDepth({
62
+ source: doc.source,
63
+ doc: transformedDoc,
64
+ maxDepth: config.maxDepth,
65
+ fragmentGraph: graph,
66
+ });
67
+ if (depthError) {
68
+ errors.push(depthError);
69
+ }
70
+ }
71
+ if (config.maxAliasCount) {
72
+ const aliasError = validateAliasCount({
73
+ source: doc.source,
74
+ doc: transformedDoc,
75
+ maxAliasCount: config.maxAliasCount,
76
+ fragmentGraph: graph,
77
+ });
78
+ if (aliasError) {
79
+ errors.push(aliasError);
80
+ }
81
+ }
82
+ if (config.maxDirectiveCount) {
83
+ const directiveError = validateDirectiveCount({
84
+ source: doc.source,
85
+ doc: transformedDoc,
86
+ maxDirectiveCount: config.maxDirectiveCount,
87
+ fragmentGraph: graph,
88
+ });
89
+ if (directiveError) {
90
+ errors.push(directiveError);
91
+ }
92
+ }
93
+ if (config.maxTokenCount) {
94
+ const tokenCountError = validateTokenCount({
95
+ source: doc.source,
96
+ document: transformedDoc,
97
+ maxTokenCount: config.maxTokenCount,
98
+ getReferencedFragmentSource: fragmentName => print(graph.getNodeData(fragmentName)),
99
+ });
100
+ if (tokenCountError) {
101
+ errors.push(tokenCountError);
102
+ }
103
+ }
104
+ const deprecated = config.strictDeprecated
105
+ ? findDeprecatedUsages(transformedSchema, transformedDoc)
106
+ : [];
107
+ const duplicatedFragments = config.strictFragments
108
+ ? findDuplicatedFragments(fragmentNames)
109
+ : [];
110
+ if (sumLengths(errors, duplicatedFragments, deprecated) > 0) {
111
+ invalidDocuments.push({
112
+ source: doc.source,
113
+ errors: [...errors, ...duplicatedFragments],
114
+ deprecated,
115
+ });
116
+ }
117
+ });
118
+ return invalidDocuments;
119
+ }
120
+ function findDuplicatedFragments(fragmentNames) {
121
+ return fragmentNames
122
+ .filter((name, i, all) => all.indexOf(name) !== i)
123
+ .map(name => new GraphQLError(`Name of '${name}' fragment is not unique`));
124
+ }
125
+ //
126
+ // PostInfo -> AuthorInfo
127
+ // AuthorInfo -> None
128
+ //
129
+ function resolveFragment(fragment, graph) {
130
+ return graph
131
+ .dependenciesOf(fragment.name.value)
132
+ .reduce((list, current) => [...list, ...resolveFragment(graph.getNodeData(current), graph)], [fragment]);
133
+ }
134
+ function extractFragments(document) {
135
+ return (document.match(/[.]{3}[a-z0-9_]+\b/gi) || []).map(name => name.replace('...', ''));
136
+ }
137
+ function sumLengths(...arrays) {
138
+ return arrays.reduce((sum, { length }) => sum + length, 0);
139
+ }
@@ -0,0 +1,97 @@
1
+ import { GraphQLError, Kind, } from 'graphql';
2
+ export function validateQueryDepth({ source, doc, maxDepth, fragmentGraph, }) {
3
+ var _a;
4
+ try {
5
+ calculateDepth({
6
+ node: doc,
7
+ currentDepth: 0,
8
+ maxDepth,
9
+ getFragment(name) {
10
+ return fragmentGraph.getNodeData(name);
11
+ },
12
+ });
13
+ }
14
+ catch (errorOrNode) {
15
+ if (errorOrNode instanceof Error) {
16
+ throw errorOrNode;
17
+ }
18
+ const node = errorOrNode;
19
+ return new GraphQLError(`Query exceeds maximum depth of ${maxDepth}`, node, source, ((_a = node.loc) === null || _a === void 0 ? void 0 : _a.start) ? [node.loc.start] : undefined);
20
+ }
21
+ }
22
+ export function calculateDepth({ node, currentDepth, maxDepth, getFragment, }) {
23
+ if (maxDepth && currentDepth > maxDepth) {
24
+ throw node;
25
+ }
26
+ switch (node.kind) {
27
+ case Kind.FIELD: {
28
+ if (node.name.value.startsWith('__') || !node.selectionSet) {
29
+ return 0;
30
+ }
31
+ const maxInnerDepth = calculateDepth({
32
+ node: node.selectionSet,
33
+ currentDepth: currentDepth + 1,
34
+ maxDepth,
35
+ getFragment,
36
+ });
37
+ return 1 + maxInnerDepth;
38
+ }
39
+ case Kind.SELECTION_SET: {
40
+ return Math.max(...node.selections.map(selection => {
41
+ return calculateDepth({
42
+ node: selection,
43
+ currentDepth,
44
+ maxDepth,
45
+ getFragment,
46
+ });
47
+ }));
48
+ }
49
+ case Kind.DOCUMENT: {
50
+ return Math.max(...node.definitions.map(def => {
51
+ return calculateDepth({
52
+ node: def,
53
+ currentDepth,
54
+ maxDepth,
55
+ getFragment,
56
+ });
57
+ }));
58
+ }
59
+ case Kind.OPERATION_DEFINITION:
60
+ case Kind.INLINE_FRAGMENT:
61
+ case Kind.FRAGMENT_DEFINITION: {
62
+ return Math.max(...node.selectionSet.selections.map(selection => {
63
+ return calculateDepth({
64
+ node: selection,
65
+ currentDepth,
66
+ maxDepth,
67
+ getFragment,
68
+ });
69
+ }));
70
+ }
71
+ case Kind.FRAGMENT_SPREAD:
72
+ return calculateDepth({
73
+ node: getFragment(node.name.value),
74
+ currentDepth,
75
+ maxDepth,
76
+ getFragment,
77
+ });
78
+ default: {
79
+ throw new Error(`Couldn't handle ${node.kind}`);
80
+ }
81
+ }
82
+ }
83
+ export function countDepth(node, parentDepth, getFragmentReference) {
84
+ let depth = parentDepth;
85
+ if ('selectionSet' in node && node.selectionSet) {
86
+ for (const child of node.selectionSet.selections) {
87
+ depth = Math.max(depth, countDepth(child, parentDepth + 1, getFragmentReference));
88
+ }
89
+ }
90
+ if (node.kind == Kind.FRAGMENT_SPREAD) {
91
+ const fragment = getFragmentReference(node.name.value);
92
+ if (fragment) {
93
+ depth = Math.max(depth, countDepth(fragment, parentDepth + 1, getFragmentReference));
94
+ }
95
+ }
96
+ return depth;
97
+ }
@@ -0,0 +1,50 @@
1
+ import { GraphQLError, TokenKind, visit } from 'graphql';
2
+ import { Parser } from 'graphql/language/parser.js';
3
+ class ParserWithLexer extends Parser {
4
+ get tokenCount() {
5
+ return this.__tokenCount;
6
+ }
7
+ constructor(source, options) {
8
+ super(source, options);
9
+ this.__tokenCount = 0;
10
+ const lexer = this._lexer;
11
+ this._lexer = new Proxy(lexer, {
12
+ get: (target, prop, receiver) => {
13
+ if (prop === 'advance') {
14
+ return () => {
15
+ const token = target.advance();
16
+ if (token.kind !== TokenKind.EOF) {
17
+ this.__tokenCount++;
18
+ }
19
+ return token;
20
+ };
21
+ }
22
+ return Reflect.get(target, prop, receiver);
23
+ },
24
+ });
25
+ }
26
+ }
27
+ export function calculateTokenCount(args) {
28
+ const parser = new ParserWithLexer(args.source);
29
+ const document = parser.parseDocument();
30
+ let { tokenCount } = parser;
31
+ visit(document, {
32
+ FragmentSpread(node) {
33
+ const fragmentSource = args.getReferencedFragmentSource(node.name.value);
34
+ if (fragmentSource) {
35
+ tokenCount += calculateTokenCount({
36
+ source: fragmentSource,
37
+ getReferencedFragmentSource: args.getReferencedFragmentSource,
38
+ });
39
+ }
40
+ },
41
+ });
42
+ return tokenCount;
43
+ }
44
+ export function validateTokenCount(args) {
45
+ var _a;
46
+ const tokenCount = calculateTokenCount(args);
47
+ if (tokenCount > args.maxTokenCount) {
48
+ return new GraphQLError(`Query exceeds maximum token count of ${args.maxTokenCount} (actual: ${tokenCount})`, args.document, args.source, ((_a = args.document.loc) === null || _a === void 0 ? void 0 : _a.start) ? [args.document.loc.start] : undefined);
49
+ }
50
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-inspector/core",
3
- "version": "4.0.2",
3
+ "version": "4.0.3",
4
4
  "description": "Tooling for GraphQL. Compare GraphQL Schemas, check documents, find breaking changes, find similar types.",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
@@ -27,20 +27,41 @@
27
27
  "url": "https://github.com/kamilkisiela"
28
28
  },
29
29
  "license": "MIT",
30
- "main": "index.js",
31
- "module": "index.mjs",
32
- "typings": "index.d.ts",
30
+ "main": "cjs/index.js",
31
+ "module": "esm/index.js",
32
+ "typings": "typings/index.d.ts",
33
33
  "typescript": {
34
- "definition": "index.d.ts"
34
+ "definition": "typings/index.d.ts"
35
35
  },
36
+ "type": "module",
36
37
  "exports": {
37
38
  ".": {
38
- "require": "./index.js",
39
- "import": "./index.mjs"
39
+ "require": {
40
+ "types": "./typings/index.d.cts",
41
+ "default": "./cjs/index.js"
42
+ },
43
+ "import": {
44
+ "types": "./typings/index.d.ts",
45
+ "default": "./esm/index.js"
46
+ },
47
+ "default": {
48
+ "types": "./typings/index.d.ts",
49
+ "default": "./esm/index.js"
50
+ }
40
51
  },
41
52
  "./*": {
42
- "require": "./*.js",
43
- "import": "./*.mjs"
53
+ "require": {
54
+ "types": "./typings/*.d.cts",
55
+ "default": "./cjs/*.js"
56
+ },
57
+ "import": {
58
+ "types": "./typings/*.d.ts",
59
+ "default": "./esm/*.js"
60
+ },
61
+ "default": {
62
+ "types": "./typings/*.d.ts",
63
+ "default": "./esm/*.js"
64
+ }
44
65
  },
45
66
  "./package.json": "./package.json"
46
67
  }
@@ -0,0 +1,15 @@
1
+ import { FragmentDefinitionNode, OperationDefinitionNode, Source } from 'graphql';
2
+ export interface Document {
3
+ source: Source;
4
+ fragments: {
5
+ node: FragmentDefinitionNode;
6
+ source: string;
7
+ }[];
8
+ operations: {
9
+ node: OperationDefinitionNode;
10
+ source: string;
11
+ }[];
12
+ hasFragments: boolean;
13
+ hasOperations: boolean;
14
+ }
15
+ export declare function readDocument(source: Source): Document;
@@ -0,0 +1,51 @@
1
+ import { GraphQLError, GraphQLNamedType, GraphQLSchema, Source } from 'graphql';
2
+ export interface Location {
3
+ start: number;
4
+ end: number;
5
+ }
6
+ export interface ArgumentCoverage {
7
+ hits: number;
8
+ fieldsCount: number;
9
+ fieldsCountCovered: number;
10
+ locations: {
11
+ [name: string]: Array<Location>;
12
+ };
13
+ }
14
+ export interface TypeChildCoverage {
15
+ hits: number;
16
+ fieldsCount: number;
17
+ fieldsCountCovered: number;
18
+ locations: {
19
+ [name: string]: Array<Location>;
20
+ };
21
+ children: {
22
+ [name: string]: ArgumentCoverage;
23
+ };
24
+ }
25
+ export interface TypeCoverage {
26
+ hits: number;
27
+ fieldsCount: number;
28
+ fieldsCountCovered: number;
29
+ type: GraphQLNamedType;
30
+ children: {
31
+ [name: string]: TypeChildCoverage;
32
+ };
33
+ }
34
+ export interface SchemaCoverage {
35
+ sources: Source[];
36
+ types: {
37
+ [typename: string]: TypeCoverage;
38
+ };
39
+ stats: {
40
+ numTypes: number;
41
+ numTypesCoveredFully: number;
42
+ numTypesCovered: number;
43
+ numFields: number;
44
+ numFiledsCovered: number;
45
+ };
46
+ }
47
+ export interface InvalidDocument {
48
+ source: Source;
49
+ errors: ReadonlyArray<GraphQLError>;
50
+ }
51
+ export declare function coverage(schema: GraphQLSchema, sources: Source[]): SchemaCoverage;
@@ -0,0 +1,2 @@
1
+ import { SchemaCoverage } from '../index.cjs';
2
+ export declare function outputJSON(coverage: SchemaCoverage): string;
@@ -1,2 +1,2 @@
1
- import { SchemaCoverage } from '../index';
1
+ import { SchemaCoverage } from '../index.js';
2
2
  export declare function outputJSON(coverage: SchemaCoverage): string;
@@ -0,0 +1,3 @@
1
+ import { GraphQLArgument, GraphQLField, GraphQLInterfaceType, GraphQLObjectType } from 'graphql';
2
+ import { AddChange } from './schema.cjs';
3
+ export declare function changesInArgument(type: GraphQLObjectType | GraphQLInterfaceType, field: GraphQLField<any, any, any>, oldArg: GraphQLArgument, newArg: GraphQLArgument, addChange: AddChange): void;
@@ -1,3 +1,3 @@
1
1
  import { GraphQLArgument, GraphQLField, GraphQLInterfaceType, GraphQLObjectType } from 'graphql';
2
- import { AddChange } from './schema';
2
+ import { AddChange } from './schema.js';
3
3
  export declare function changesInArgument(type: GraphQLObjectType | GraphQLInterfaceType, field: GraphQLField<any, any, any>, oldArg: GraphQLArgument, newArg: GraphQLArgument, addChange: AddChange): void;
@@ -0,0 +1,5 @@
1
+ import { GraphQLArgument, GraphQLField, GraphQLInterfaceType, GraphQLObjectType } from 'graphql';
2
+ import { Change } from './change.cjs';
3
+ export declare function fieldArgumentDescriptionChanged(type: GraphQLObjectType | GraphQLInterfaceType, field: GraphQLField<any, any, any>, oldArg: GraphQLArgument, newArg: GraphQLArgument): Change;
4
+ export declare function fieldArgumentDefaultChanged(type: GraphQLObjectType | GraphQLInterfaceType, field: GraphQLField<any, any, any>, oldArg: GraphQLArgument, newArg: GraphQLArgument): Change;
5
+ export declare function fieldArgumentTypeChanged(type: GraphQLObjectType | GraphQLInterfaceType, field: GraphQLField<any, any, any>, oldArg: GraphQLArgument, newArg: GraphQLArgument): Change;
@@ -1,5 +1,5 @@
1
1
  import { GraphQLArgument, GraphQLField, GraphQLInterfaceType, GraphQLObjectType } from 'graphql';
2
- import { Change } from './change';
2
+ import { Change } from './change.js';
3
3
  export declare function fieldArgumentDescriptionChanged(type: GraphQLObjectType | GraphQLInterfaceType, field: GraphQLField<any, any, any>, oldArg: GraphQLArgument, newArg: GraphQLArgument): Change;
4
4
  export declare function fieldArgumentDefaultChanged(type: GraphQLObjectType | GraphQLInterfaceType, field: GraphQLField<any, any, any>, oldArg: GraphQLArgument, newArg: GraphQLArgument): Change;
5
5
  export declare function fieldArgumentTypeChanged(type: GraphQLObjectType | GraphQLInterfaceType, field: GraphQLField<any, any, any>, oldArg: GraphQLArgument, newArg: GraphQLArgument): Change;
@@ -0,0 +1,69 @@
1
+ export declare enum ChangeType {
2
+ FieldArgumentDescriptionChanged = "FIELD_ARGUMENT_DESCRIPTION_CHANGED",
3
+ FieldArgumentDefaultChanged = "FIELD_ARGUMENT_DEFAULT_CHANGED",
4
+ FieldArgumentTypeChanged = "FIELD_ARGUMENT_TYPE_CHANGED",
5
+ DirectiveRemoved = "DIRECTIVE_REMOVED",
6
+ DirectiveAdded = "DIRECTIVE_ADDED",
7
+ DirectiveDescriptionChanged = "DIRECTIVE_DESCRIPTION_CHANGED",
8
+ DirectiveLocationAdded = "DIRECTIVE_LOCATION_ADDED",
9
+ DirectiveLocationRemoved = "DIRECTIVE_LOCATION_REMOVED",
10
+ DirectiveArgumentAdded = "DIRECTIVE_ARGUMENT_ADDED",
11
+ DirectiveArgumentRemoved = "DIRECTIVE_ARGUMENT_REMOVED",
12
+ DirectiveArgumentDescriptionChanged = "DIRECTIVE_ARGUMENT_DESCRIPTION_CHANGED",
13
+ DirectiveArgumentDefaultValueChanged = "DIRECTIVE_ARGUMENT_DEFAULT_VALUE_CHANGED",
14
+ DirectiveArgumentTypeChanged = "DIRECTIVE_ARGUMENT_TYPE_CHANGED",
15
+ EnumValueRemoved = "ENUM_VALUE_REMOVED",
16
+ EnumValueAdded = "ENUM_VALUE_ADDED",
17
+ EnumValueDescriptionChanged = "ENUM_VALUE_DESCRIPTION_CHANGED",
18
+ EnumValueDeprecationReasonChanged = "ENUM_VALUE_DEPRECATION_REASON_CHANGED",
19
+ EnumValueDeprecationReasonAdded = "ENUM_VALUE_DEPRECATION_REASON_ADDED",
20
+ EnumValueDeprecationReasonRemoved = "ENUM_VALUE_DEPRECATION_REASON_REMOVED",
21
+ FieldRemoved = "FIELD_REMOVED",
22
+ FieldAdded = "FIELD_ADDED",
23
+ FieldDescriptionChanged = "FIELD_DESCRIPTION_CHANGED",
24
+ FieldDescriptionAdded = "FIELD_DESCRIPTION_ADDED",
25
+ FieldDescriptionRemoved = "FIELD_DESCRIPTION_REMOVED",
26
+ FieldDeprecationAdded = "FIELD_DEPRECATION_ADDED",
27
+ FieldDeprecationRemoved = "FIELD_DEPRECATION_REMOVED",
28
+ FieldDeprecationReasonChanged = "FIELD_DEPRECATION_REASON_CHANGED",
29
+ FieldDeprecationReasonAdded = "FIELD_DEPRECATION_REASON_ADDED",
30
+ FieldDeprecationReasonRemoved = "FIELD_DEPRECATION_REASON_REMOVED",
31
+ FieldTypeChanged = "FIELD_TYPE_CHANGED",
32
+ FieldArgumentAdded = "FIELD_ARGUMENT_ADDED",
33
+ FieldArgumentRemoved = "FIELD_ARGUMENT_REMOVED",
34
+ InputFieldRemoved = "INPUT_FIELD_REMOVED",
35
+ InputFieldAdded = "INPUT_FIELD_ADDED",
36
+ InputFieldDescriptionAdded = "INPUT_FIELD_DESCRIPTION_ADDED",
37
+ InputFieldDescriptionRemoved = "INPUT_FIELD_DESCRIPTION_REMOVED",
38
+ InputFieldDescriptionChanged = "INPUT_FIELD_DESCRIPTION_CHANGED",
39
+ InputFieldDefaultValueChanged = "INPUT_FIELD_DEFAULT_VALUE_CHANGED",
40
+ InputFieldTypeChanged = "INPUT_FIELD_TYPE_CHANGED",
41
+ ObjectTypeInterfaceAdded = "OBJECT_TYPE_INTERFACE_ADDED",
42
+ ObjectTypeInterfaceRemoved = "OBJECT_TYPE_INTERFACE_REMOVED",
43
+ SchemaQueryTypeChanged = "SCHEMA_QUERY_TYPE_CHANGED",
44
+ SchemaMutationTypeChanged = "SCHEMA_MUTATION_TYPE_CHANGED",
45
+ SchemaSubscriptionTypeChanged = "SCHEMA_SUBSCRIPTION_TYPE_CHANGED",
46
+ TypeRemoved = "TYPE_REMOVED",
47
+ TypeAdded = "TYPE_ADDED",
48
+ TypeKindChanged = "TYPE_KIND_CHANGED",
49
+ TypeDescriptionChanged = "TYPE_DESCRIPTION_CHANGED",
50
+ TypeDescriptionRemoved = "TYPE_DESCRIPTION_REMOVED",
51
+ TypeDescriptionAdded = "TYPE_DESCRIPTION_ADDED",
52
+ UnionMemberRemoved = "UNION_MEMBER_REMOVED",
53
+ UnionMemberAdded = "UNION_MEMBER_ADDED"
54
+ }
55
+ export declare enum CriticalityLevel {
56
+ Breaking = "BREAKING",
57
+ NonBreaking = "NON_BREAKING",
58
+ Dangerous = "DANGEROUS"
59
+ }
60
+ export interface Criticality {
61
+ level: CriticalityLevel;
62
+ reason?: string;
63
+ }
64
+ export interface Change {
65
+ message: string;
66
+ path?: string;
67
+ type: ChangeType;
68
+ criticality: Criticality;
69
+ }
@@ -0,0 +1,12 @@
1
+ import { DirectiveLocationEnum, GraphQLArgument, GraphQLDirective } from 'graphql';
2
+ import { Change } from './change.cjs';
3
+ export declare function directiveRemoved(directive: GraphQLDirective): Change;
4
+ export declare function directiveAdded(directive: GraphQLDirective): Change;
5
+ export declare function directiveDescriptionChanged(oldDirective: GraphQLDirective, newDirective: GraphQLDirective): Change;
6
+ export declare function directiveLocationAdded(directive: GraphQLDirective, location: DirectiveLocationEnum): Change;
7
+ export declare function directiveLocationRemoved(directive: GraphQLDirective, location: DirectiveLocationEnum): Change;
8
+ export declare function directiveArgumentAdded(directive: GraphQLDirective, arg: GraphQLArgument): Change;
9
+ export declare function directiveArgumentRemoved(directive: GraphQLDirective, arg: GraphQLArgument): Change;
10
+ export declare function directiveArgumentDescriptionChanged(directive: GraphQLDirective, oldArg: GraphQLArgument, newArg: GraphQLArgument): Change;
11
+ export declare function directiveArgumentDefaultValueChanged(directive: GraphQLDirective, oldArg: GraphQLArgument, newArg: GraphQLArgument): Change;
12
+ export declare function directiveArgumentTypeChanged(directive: GraphQLDirective, oldArg: GraphQLArgument, newArg: GraphQLArgument): Change;
@@ -1,5 +1,5 @@
1
1
  import { DirectiveLocationEnum, GraphQLArgument, GraphQLDirective } from 'graphql';
2
- import { Change } from './change';
2
+ import { Change } from './change.js';
3
3
  export declare function directiveRemoved(directive: GraphQLDirective): Change;
4
4
  export declare function directiveAdded(directive: GraphQLDirective): Change;
5
5
  export declare function directiveDescriptionChanged(oldDirective: GraphQLDirective, newDirective: GraphQLDirective): Change;
@@ -0,0 +1,8 @@
1
+ import { GraphQLEnumType, GraphQLEnumValue } from 'graphql';
2
+ import { Change } from './change.cjs';
3
+ export declare function enumValueRemoved(oldEnum: GraphQLEnumType, value: GraphQLEnumValue): Change;
4
+ export declare function enumValueAdded(newEnum: GraphQLEnumType, value: GraphQLEnumValue): Change;
5
+ export declare function enumValueDescriptionChanged(newEnum: GraphQLEnumType, oldValue: GraphQLEnumValue, newValue: GraphQLEnumValue): Change;
6
+ export declare function enumValueDeprecationReasonChanged(newEnum: GraphQLEnumType, oldValue: GraphQLEnumValue, newValue: GraphQLEnumValue): Change;
7
+ export declare function enumValueDeprecationReasonAdded(newEnum: GraphQLEnumType, oldValue: GraphQLEnumValue, newValue: GraphQLEnumValue): Change;
8
+ export declare function enumValueDeprecationReasonRemoved(newEnum: GraphQLEnumType, oldValue: GraphQLEnumValue, newValue: GraphQLEnumValue): Change;
@@ -1,5 +1,5 @@
1
1
  import { GraphQLEnumType, GraphQLEnumValue } from 'graphql';
2
- import { Change } from './change';
2
+ import { Change } from './change.js';
3
3
  export declare function enumValueRemoved(oldEnum: GraphQLEnumType, value: GraphQLEnumValue): Change;
4
4
  export declare function enumValueAdded(newEnum: GraphQLEnumType, value: GraphQLEnumValue): Change;
5
5
  export declare function enumValueDescriptionChanged(newEnum: GraphQLEnumType, oldValue: GraphQLEnumValue, newValue: GraphQLEnumValue): Change;