graphql 16.8.2 → 16.9.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/index.d.ts +3 -0
- package/index.js +18 -0
- package/index.mjs +6 -3
- package/package.json +1 -1
- package/type/definition.d.ts +4 -1
- package/type/definition.js +29 -6
- package/type/definition.mjs +26 -6
- package/type/directives.d.ts +4 -0
- package/type/directives.js +15 -1
- package/type/directives.mjs +12 -0
- package/type/index.d.ts +1 -0
- package/type/index.js +6 -0
- package/type/index.mjs +2 -1
- package/type/introspection.js +8 -0
- package/type/introspection.mjs +8 -0
- package/type/validate.js +24 -0
- package/type/validate.mjs +24 -0
- package/utilities/buildClientSchema.js +1 -0
- package/utilities/buildClientSchema.mjs +1 -0
- package/utilities/coerceInputValue.js +25 -0
- package/utilities/coerceInputValue.mjs +25 -0
- package/utilities/extendSchema.js +10 -0
- package/utilities/extendSchema.mjs +9 -0
- package/utilities/getIntrospectionQuery.d.ts +6 -0
- package/utilities/getIntrospectionQuery.js +3 -0
- package/utilities/getIntrospectionQuery.mjs +3 -0
- package/utilities/introspectionFromSchema.js +1 -0
- package/utilities/introspectionFromSchema.mjs +1 -0
- package/utilities/printSchema.js +6 -1
- package/utilities/printSchema.mjs +6 -1
- package/utilities/valueFromAST.js +12 -0
- package/utilities/valueFromAST.mjs +12 -0
- package/validation/index.d.ts +2 -1
- package/validation/index.js +14 -0
- package/validation/index.mjs +3 -2
- package/validation/rules/MaxIntrospectionDepthRule.d.ts +5 -0
- package/validation/rules/MaxIntrospectionDepthRule.js +90 -0
- package/validation/rules/MaxIntrospectionDepthRule.mjs +77 -0
- package/validation/rules/ValuesOfCorrectTypeRule.js +88 -0
- package/validation/rules/ValuesOfCorrectTypeRule.mjs +83 -0
- package/validation/specifiedRules.d.ts +6 -0
- package/validation/specifiedRules.js +17 -1
- package/validation/specifiedRules.mjs +10 -1
- package/version.js +3 -3
- package/version.mjs +3 -3
|
@@ -9,6 +9,7 @@ export function getIntrospectionQuery(options) {
|
|
|
9
9
|
directiveIsRepeatable: false,
|
|
10
10
|
schemaDescription: false,
|
|
11
11
|
inputValueDeprecation: false,
|
|
12
|
+
oneOf: false,
|
|
12
13
|
...options,
|
|
13
14
|
};
|
|
14
15
|
const descriptions = optionsWithDefault.descriptions ? 'description' : '';
|
|
@@ -26,6 +27,7 @@ export function getIntrospectionQuery(options) {
|
|
|
26
27
|
return optionsWithDefault.inputValueDeprecation ? str : '';
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
const oneOf = optionsWithDefault.oneOf ? 'isOneOf' : '';
|
|
29
31
|
return `
|
|
30
32
|
query IntrospectionQuery {
|
|
31
33
|
__schema {
|
|
@@ -53,6 +55,7 @@ export function getIntrospectionQuery(options) {
|
|
|
53
55
|
name
|
|
54
56
|
${descriptions}
|
|
55
57
|
${specifiedByUrl}
|
|
58
|
+
${oneOf}
|
|
56
59
|
fields(includeDeprecated: true) {
|
|
57
60
|
name
|
|
58
61
|
${descriptions}
|
package/utilities/printSchema.js
CHANGED
|
@@ -214,7 +214,12 @@ function printInputObject(type) {
|
|
|
214
214
|
const fields = Object.values(type.getFields()).map(
|
|
215
215
|
(f, i) => printDescription(f, ' ', !i) + ' ' + printInputValue(f),
|
|
216
216
|
);
|
|
217
|
-
return
|
|
217
|
+
return (
|
|
218
|
+
printDescription(type) +
|
|
219
|
+
`input ${type.name}` +
|
|
220
|
+
(type.isOneOf ? ' @oneOf' : '') +
|
|
221
|
+
printBlock(fields)
|
|
222
|
+
);
|
|
218
223
|
}
|
|
219
224
|
|
|
220
225
|
function printFields(type) {
|
|
@@ -193,7 +193,12 @@ function printInputObject(type) {
|
|
|
193
193
|
const fields = Object.values(type.getFields()).map(
|
|
194
194
|
(f, i) => printDescription(f, ' ', !i) + ' ' + printInputValue(f),
|
|
195
195
|
);
|
|
196
|
-
return
|
|
196
|
+
return (
|
|
197
|
+
printDescription(type) +
|
|
198
|
+
`input ${type.name}` +
|
|
199
|
+
(type.isOneOf ? ' @oneOf' : '') +
|
|
200
|
+
printBlock(fields)
|
|
201
|
+
);
|
|
197
202
|
}
|
|
198
203
|
|
|
199
204
|
function printFields(type) {
|
|
@@ -145,6 +145,18 @@ function valueFromAST(valueNode, type, variables) {
|
|
|
145
145
|
coercedObj[field.name] = fieldValue;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
if (type.isOneOf) {
|
|
149
|
+
const keys = Object.keys(coercedObj);
|
|
150
|
+
|
|
151
|
+
if (keys.length !== 1) {
|
|
152
|
+
return; // Invalid: not exactly one key, intentionally return no value.
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (coercedObj[keys[0]] === null) {
|
|
156
|
+
return; // Invalid: value not non-null, intentionally return no value.
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
148
160
|
return coercedObj;
|
|
149
161
|
}
|
|
150
162
|
|
|
@@ -136,6 +136,18 @@ export function valueFromAST(valueNode, type, variables) {
|
|
|
136
136
|
coercedObj[field.name] = fieldValue;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
if (type.isOneOf) {
|
|
140
|
+
const keys = Object.keys(coercedObj);
|
|
141
|
+
|
|
142
|
+
if (keys.length !== 1) {
|
|
143
|
+
return; // Invalid: not exactly one key, intentionally return no value.
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (coercedObj[keys[0]] === null) {
|
|
147
|
+
return; // Invalid: value not non-null, intentionally return no value.
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
139
151
|
return coercedObj;
|
|
140
152
|
}
|
|
141
153
|
|
package/validation/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { validate } from './validate';
|
|
2
2
|
export { ValidationContext } from './ValidationContext';
|
|
3
3
|
export type { ValidationRule } from './ValidationContext';
|
|
4
|
-
export { specifiedRules } from './specifiedRules';
|
|
4
|
+
export { specifiedRules, recommendedRules } from './specifiedRules';
|
|
5
5
|
export { ExecutableDefinitionsRule } from './rules/ExecutableDefinitionsRule';
|
|
6
6
|
export { FieldsOnCorrectTypeRule } from './rules/FieldsOnCorrectTypeRule';
|
|
7
7
|
export { FragmentsOnCompositeTypesRule } from './rules/FragmentsOnCompositeTypesRule';
|
|
@@ -28,6 +28,7 @@ export { UniqueVariableNamesRule } from './rules/UniqueVariableNamesRule';
|
|
|
28
28
|
export { ValuesOfCorrectTypeRule } from './rules/ValuesOfCorrectTypeRule';
|
|
29
29
|
export { VariablesAreInputTypesRule } from './rules/VariablesAreInputTypesRule';
|
|
30
30
|
export { VariablesInAllowedPositionRule } from './rules/VariablesInAllowedPositionRule';
|
|
31
|
+
export { MaxIntrospectionDepthRule } from './rules/MaxIntrospectionDepthRule';
|
|
31
32
|
export { LoneSchemaDefinitionRule } from './rules/LoneSchemaDefinitionRule';
|
|
32
33
|
export { UniqueOperationTypesRule } from './rules/UniqueOperationTypesRule';
|
|
33
34
|
export { UniqueTypeNamesRule } from './rules/UniqueTypeNamesRule';
|
package/validation/index.js
CHANGED
|
@@ -57,6 +57,12 @@ Object.defineProperty(exports, 'LoneSchemaDefinitionRule', {
|
|
|
57
57
|
return _LoneSchemaDefinitionRule.LoneSchemaDefinitionRule;
|
|
58
58
|
},
|
|
59
59
|
});
|
|
60
|
+
Object.defineProperty(exports, 'MaxIntrospectionDepthRule', {
|
|
61
|
+
enumerable: true,
|
|
62
|
+
get: function () {
|
|
63
|
+
return _MaxIntrospectionDepthRule.MaxIntrospectionDepthRule;
|
|
64
|
+
},
|
|
65
|
+
});
|
|
60
66
|
Object.defineProperty(exports, 'NoDeprecatedCustomRule', {
|
|
61
67
|
enumerable: true,
|
|
62
68
|
get: function () {
|
|
@@ -225,6 +231,12 @@ Object.defineProperty(exports, 'VariablesInAllowedPositionRule', {
|
|
|
225
231
|
return _VariablesInAllowedPositionRule.VariablesInAllowedPositionRule;
|
|
226
232
|
},
|
|
227
233
|
});
|
|
234
|
+
Object.defineProperty(exports, 'recommendedRules', {
|
|
235
|
+
enumerable: true,
|
|
236
|
+
get: function () {
|
|
237
|
+
return _specifiedRules.recommendedRules;
|
|
238
|
+
},
|
|
239
|
+
});
|
|
228
240
|
Object.defineProperty(exports, 'specifiedRules', {
|
|
229
241
|
enumerable: true,
|
|
230
242
|
get: function () {
|
|
@@ -296,6 +308,8 @@ var _VariablesAreInputTypesRule = require('./rules/VariablesAreInputTypesRule.js
|
|
|
296
308
|
|
|
297
309
|
var _VariablesInAllowedPositionRule = require('./rules/VariablesInAllowedPositionRule.js');
|
|
298
310
|
|
|
311
|
+
var _MaxIntrospectionDepthRule = require('./rules/MaxIntrospectionDepthRule.js');
|
|
312
|
+
|
|
299
313
|
var _LoneSchemaDefinitionRule = require('./rules/LoneSchemaDefinitionRule.js');
|
|
300
314
|
|
|
301
315
|
var _UniqueOperationTypesRule = require('./rules/UniqueOperationTypesRule.js');
|
package/validation/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { validate } from './validate.mjs';
|
|
2
2
|
export { ValidationContext } from './ValidationContext.mjs';
|
|
3
3
|
// All validation rules in the GraphQL Specification.
|
|
4
|
-
export { specifiedRules } from './specifiedRules.mjs'; // Spec Section: "Executable Definitions"
|
|
4
|
+
export { specifiedRules, recommendedRules } from './specifiedRules.mjs'; // Spec Section: "Executable Definitions"
|
|
5
5
|
|
|
6
6
|
export { ExecutableDefinitionsRule } from './rules/ExecutableDefinitionsRule.mjs'; // Spec Section: "Field Selections on Objects, Interfaces, and Unions Types"
|
|
7
7
|
|
|
@@ -53,7 +53,8 @@ export { ValuesOfCorrectTypeRule } from './rules/ValuesOfCorrectTypeRule.mjs'; /
|
|
|
53
53
|
|
|
54
54
|
export { VariablesAreInputTypesRule } from './rules/VariablesAreInputTypesRule.mjs'; // Spec Section: "All Variable Usages Are Allowed"
|
|
55
55
|
|
|
56
|
-
export { VariablesInAllowedPositionRule } from './rules/VariablesInAllowedPositionRule.mjs';
|
|
56
|
+
export { VariablesInAllowedPositionRule } from './rules/VariablesInAllowedPositionRule.mjs';
|
|
57
|
+
export { MaxIntrospectionDepthRule } from './rules/MaxIntrospectionDepthRule.mjs'; // SDL-specific validation rules
|
|
57
58
|
|
|
58
59
|
export { LoneSchemaDefinitionRule } from './rules/LoneSchemaDefinitionRule.mjs';
|
|
59
60
|
export { UniqueOperationTypesRule } from './rules/UniqueOperationTypesRule.mjs';
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', {
|
|
4
|
+
value: true,
|
|
5
|
+
});
|
|
6
|
+
exports.MaxIntrospectionDepthRule = MaxIntrospectionDepthRule;
|
|
7
|
+
|
|
8
|
+
var _GraphQLError = require('../../error/GraphQLError.js');
|
|
9
|
+
|
|
10
|
+
var _kinds = require('../../language/kinds.js');
|
|
11
|
+
|
|
12
|
+
const MAX_LISTS_DEPTH = 3;
|
|
13
|
+
|
|
14
|
+
function MaxIntrospectionDepthRule(context) {
|
|
15
|
+
/**
|
|
16
|
+
* Counts the depth of list fields in "__Type" recursively and
|
|
17
|
+
* returns `true` if the limit has been reached.
|
|
18
|
+
*/
|
|
19
|
+
function checkDepth(node, visitedFragments = Object.create(null), depth = 0) {
|
|
20
|
+
if (node.kind === _kinds.Kind.FRAGMENT_SPREAD) {
|
|
21
|
+
const fragmentName = node.name.value;
|
|
22
|
+
|
|
23
|
+
if (visitedFragments[fragmentName] === true) {
|
|
24
|
+
// Fragment cycles are handled by `NoFragmentCyclesRule`.
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const fragment = context.getFragment(fragmentName);
|
|
29
|
+
|
|
30
|
+
if (!fragment) {
|
|
31
|
+
// Missing fragments checks are handled by `KnownFragmentNamesRule`.
|
|
32
|
+
return false;
|
|
33
|
+
} // Rather than following an immutable programming pattern which has
|
|
34
|
+
// significant memory and garbage collection overhead, we've opted to
|
|
35
|
+
// take a mutable approach for efficiency's sake. Importantly visiting a
|
|
36
|
+
// fragment twice is fine, so long as you don't do one visit inside the
|
|
37
|
+
// other.
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
visitedFragments[fragmentName] = true;
|
|
41
|
+
return checkDepth(fragment, visitedFragments, depth);
|
|
42
|
+
} finally {
|
|
43
|
+
visitedFragments[fragmentName] = undefined;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (
|
|
48
|
+
node.kind === _kinds.Kind.FIELD && // check all introspection lists
|
|
49
|
+
(node.name.value === 'fields' ||
|
|
50
|
+
node.name.value === 'interfaces' ||
|
|
51
|
+
node.name.value === 'possibleTypes' ||
|
|
52
|
+
node.name.value === 'inputFields')
|
|
53
|
+
) {
|
|
54
|
+
// eslint-disable-next-line no-param-reassign
|
|
55
|
+
depth++;
|
|
56
|
+
|
|
57
|
+
if (depth >= MAX_LISTS_DEPTH) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
} // handles fields and inline fragments
|
|
61
|
+
|
|
62
|
+
if ('selectionSet' in node && node.selectionSet) {
|
|
63
|
+
for (const child of node.selectionSet.selections) {
|
|
64
|
+
if (checkDepth(child, visitedFragments, depth)) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
Field(node) {
|
|
75
|
+
if (node.name.value === '__schema' || node.name.value === '__type') {
|
|
76
|
+
if (checkDepth(node)) {
|
|
77
|
+
context.reportError(
|
|
78
|
+
new _GraphQLError.GraphQLError(
|
|
79
|
+
'Maximum introspection depth exceeded',
|
|
80
|
+
{
|
|
81
|
+
nodes: [node],
|
|
82
|
+
},
|
|
83
|
+
),
|
|
84
|
+
);
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { GraphQLError } from '../../error/GraphQLError.mjs';
|
|
2
|
+
import { Kind } from '../../language/kinds.mjs';
|
|
3
|
+
const MAX_LISTS_DEPTH = 3;
|
|
4
|
+
export function MaxIntrospectionDepthRule(context) {
|
|
5
|
+
/**
|
|
6
|
+
* Counts the depth of list fields in "__Type" recursively and
|
|
7
|
+
* returns `true` if the limit has been reached.
|
|
8
|
+
*/
|
|
9
|
+
function checkDepth(node, visitedFragments = Object.create(null), depth = 0) {
|
|
10
|
+
if (node.kind === Kind.FRAGMENT_SPREAD) {
|
|
11
|
+
const fragmentName = node.name.value;
|
|
12
|
+
|
|
13
|
+
if (visitedFragments[fragmentName] === true) {
|
|
14
|
+
// Fragment cycles are handled by `NoFragmentCyclesRule`.
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const fragment = context.getFragment(fragmentName);
|
|
19
|
+
|
|
20
|
+
if (!fragment) {
|
|
21
|
+
// Missing fragments checks are handled by `KnownFragmentNamesRule`.
|
|
22
|
+
return false;
|
|
23
|
+
} // Rather than following an immutable programming pattern which has
|
|
24
|
+
// significant memory and garbage collection overhead, we've opted to
|
|
25
|
+
// take a mutable approach for efficiency's sake. Importantly visiting a
|
|
26
|
+
// fragment twice is fine, so long as you don't do one visit inside the
|
|
27
|
+
// other.
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
visitedFragments[fragmentName] = true;
|
|
31
|
+
return checkDepth(fragment, visitedFragments, depth);
|
|
32
|
+
} finally {
|
|
33
|
+
visitedFragments[fragmentName] = undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (
|
|
38
|
+
node.kind === Kind.FIELD && // check all introspection lists
|
|
39
|
+
(node.name.value === 'fields' ||
|
|
40
|
+
node.name.value === 'interfaces' ||
|
|
41
|
+
node.name.value === 'possibleTypes' ||
|
|
42
|
+
node.name.value === 'inputFields')
|
|
43
|
+
) {
|
|
44
|
+
// eslint-disable-next-line no-param-reassign
|
|
45
|
+
depth++;
|
|
46
|
+
|
|
47
|
+
if (depth >= MAX_LISTS_DEPTH) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
} // handles fields and inline fragments
|
|
51
|
+
|
|
52
|
+
if ('selectionSet' in node && node.selectionSet) {
|
|
53
|
+
for (const child of node.selectionSet.selections) {
|
|
54
|
+
if (checkDepth(child, visitedFragments, depth)) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
Field(node) {
|
|
65
|
+
if (node.name.value === '__schema' || node.name.value === '__type') {
|
|
66
|
+
if (checkDepth(node)) {
|
|
67
|
+
context.reportError(
|
|
68
|
+
new GraphQLError('Maximum introspection depth exceeded', {
|
|
69
|
+
nodes: [node],
|
|
70
|
+
}),
|
|
71
|
+
);
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -15,6 +15,8 @@ var _suggestionList = require('../../jsutils/suggestionList.js');
|
|
|
15
15
|
|
|
16
16
|
var _GraphQLError = require('../../error/GraphQLError.js');
|
|
17
17
|
|
|
18
|
+
var _kinds = require('../../language/kinds.js');
|
|
19
|
+
|
|
18
20
|
var _printer = require('../../language/printer.js');
|
|
19
21
|
|
|
20
22
|
var _definition = require('../../type/definition.js');
|
|
@@ -28,7 +30,18 @@ var _definition = require('../../type/definition.js');
|
|
|
28
30
|
* See https://spec.graphql.org/draft/#sec-Values-of-Correct-Type
|
|
29
31
|
*/
|
|
30
32
|
function ValuesOfCorrectTypeRule(context) {
|
|
33
|
+
let variableDefinitions = {};
|
|
31
34
|
return {
|
|
35
|
+
OperationDefinition: {
|
|
36
|
+
enter() {
|
|
37
|
+
variableDefinitions = {};
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
VariableDefinition(definition) {
|
|
42
|
+
variableDefinitions[definition.variable.name.value] = definition;
|
|
43
|
+
},
|
|
44
|
+
|
|
32
45
|
ListValue(node) {
|
|
33
46
|
// Note: TypeInfo will traverse into a list's item type, so look to the
|
|
34
47
|
// parent input type to check if it is a list.
|
|
@@ -70,6 +83,16 @@ function ValuesOfCorrectTypeRule(context) {
|
|
|
70
83
|
);
|
|
71
84
|
}
|
|
72
85
|
}
|
|
86
|
+
|
|
87
|
+
if (type.isOneOf) {
|
|
88
|
+
validateOneOfInputObject(
|
|
89
|
+
context,
|
|
90
|
+
node,
|
|
91
|
+
type,
|
|
92
|
+
fieldNodeMap,
|
|
93
|
+
variableDefinitions,
|
|
94
|
+
);
|
|
95
|
+
}
|
|
73
96
|
},
|
|
74
97
|
|
|
75
98
|
ObjectField(node) {
|
|
@@ -190,3 +213,68 @@ function isValidValueNode(context, node) {
|
|
|
190
213
|
}
|
|
191
214
|
}
|
|
192
215
|
}
|
|
216
|
+
|
|
217
|
+
function validateOneOfInputObject(
|
|
218
|
+
context,
|
|
219
|
+
node,
|
|
220
|
+
type,
|
|
221
|
+
fieldNodeMap,
|
|
222
|
+
variableDefinitions,
|
|
223
|
+
) {
|
|
224
|
+
var _fieldNodeMap$keys$;
|
|
225
|
+
|
|
226
|
+
const keys = Object.keys(fieldNodeMap);
|
|
227
|
+
const isNotExactlyOneField = keys.length !== 1;
|
|
228
|
+
|
|
229
|
+
if (isNotExactlyOneField) {
|
|
230
|
+
context.reportError(
|
|
231
|
+
new _GraphQLError.GraphQLError(
|
|
232
|
+
`OneOf Input Object "${type.name}" must specify exactly one key.`,
|
|
233
|
+
{
|
|
234
|
+
nodes: [node],
|
|
235
|
+
},
|
|
236
|
+
),
|
|
237
|
+
);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const value =
|
|
242
|
+
(_fieldNodeMap$keys$ = fieldNodeMap[keys[0]]) === null ||
|
|
243
|
+
_fieldNodeMap$keys$ === void 0
|
|
244
|
+
? void 0
|
|
245
|
+
: _fieldNodeMap$keys$.value;
|
|
246
|
+
const isNullLiteral = !value || value.kind === _kinds.Kind.NULL;
|
|
247
|
+
const isVariable =
|
|
248
|
+
(value === null || value === void 0 ? void 0 : value.kind) ===
|
|
249
|
+
_kinds.Kind.VARIABLE;
|
|
250
|
+
|
|
251
|
+
if (isNullLiteral) {
|
|
252
|
+
context.reportError(
|
|
253
|
+
new _GraphQLError.GraphQLError(
|
|
254
|
+
`Field "${type.name}.${keys[0]}" must be non-null.`,
|
|
255
|
+
{
|
|
256
|
+
nodes: [node],
|
|
257
|
+
},
|
|
258
|
+
),
|
|
259
|
+
);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (isVariable) {
|
|
264
|
+
const variableName = value.name.value;
|
|
265
|
+
const definition = variableDefinitions[variableName];
|
|
266
|
+
const isNullableVariable =
|
|
267
|
+
definition.type.kind !== _kinds.Kind.NON_NULL_TYPE;
|
|
268
|
+
|
|
269
|
+
if (isNullableVariable) {
|
|
270
|
+
context.reportError(
|
|
271
|
+
new _GraphQLError.GraphQLError(
|
|
272
|
+
`Variable "${variableName}" must be non-nullable to be used for OneOf Input Object "${type.name}".`,
|
|
273
|
+
{
|
|
274
|
+
nodes: [node],
|
|
275
|
+
},
|
|
276
|
+
),
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
@@ -3,6 +3,7 @@ import { inspect } from '../../jsutils/inspect.mjs';
|
|
|
3
3
|
import { keyMap } from '../../jsutils/keyMap.mjs';
|
|
4
4
|
import { suggestionList } from '../../jsutils/suggestionList.mjs';
|
|
5
5
|
import { GraphQLError } from '../../error/GraphQLError.mjs';
|
|
6
|
+
import { Kind } from '../../language/kinds.mjs';
|
|
6
7
|
import { print } from '../../language/printer.mjs';
|
|
7
8
|
import {
|
|
8
9
|
getNamedType,
|
|
@@ -23,7 +24,18 @@ import {
|
|
|
23
24
|
* See https://spec.graphql.org/draft/#sec-Values-of-Correct-Type
|
|
24
25
|
*/
|
|
25
26
|
export function ValuesOfCorrectTypeRule(context) {
|
|
27
|
+
let variableDefinitions = {};
|
|
26
28
|
return {
|
|
29
|
+
OperationDefinition: {
|
|
30
|
+
enter() {
|
|
31
|
+
variableDefinitions = {};
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
VariableDefinition(definition) {
|
|
36
|
+
variableDefinitions[definition.variable.name.value] = definition;
|
|
37
|
+
},
|
|
38
|
+
|
|
27
39
|
ListValue(node) {
|
|
28
40
|
// Note: TypeInfo will traverse into a list's item type, so look to the
|
|
29
41
|
// parent input type to check if it is a list.
|
|
@@ -60,6 +72,16 @@ export function ValuesOfCorrectTypeRule(context) {
|
|
|
60
72
|
);
|
|
61
73
|
}
|
|
62
74
|
}
|
|
75
|
+
|
|
76
|
+
if (type.isOneOf) {
|
|
77
|
+
validateOneOfInputObject(
|
|
78
|
+
context,
|
|
79
|
+
node,
|
|
80
|
+
type,
|
|
81
|
+
fieldNodeMap,
|
|
82
|
+
variableDefinitions,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
63
85
|
},
|
|
64
86
|
|
|
65
87
|
ObjectField(node) {
|
|
@@ -171,3 +193,64 @@ function isValidValueNode(context, node) {
|
|
|
171
193
|
}
|
|
172
194
|
}
|
|
173
195
|
}
|
|
196
|
+
|
|
197
|
+
function validateOneOfInputObject(
|
|
198
|
+
context,
|
|
199
|
+
node,
|
|
200
|
+
type,
|
|
201
|
+
fieldNodeMap,
|
|
202
|
+
variableDefinitions,
|
|
203
|
+
) {
|
|
204
|
+
var _fieldNodeMap$keys$;
|
|
205
|
+
|
|
206
|
+
const keys = Object.keys(fieldNodeMap);
|
|
207
|
+
const isNotExactlyOneField = keys.length !== 1;
|
|
208
|
+
|
|
209
|
+
if (isNotExactlyOneField) {
|
|
210
|
+
context.reportError(
|
|
211
|
+
new GraphQLError(
|
|
212
|
+
`OneOf Input Object "${type.name}" must specify exactly one key.`,
|
|
213
|
+
{
|
|
214
|
+
nodes: [node],
|
|
215
|
+
},
|
|
216
|
+
),
|
|
217
|
+
);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const value =
|
|
222
|
+
(_fieldNodeMap$keys$ = fieldNodeMap[keys[0]]) === null ||
|
|
223
|
+
_fieldNodeMap$keys$ === void 0
|
|
224
|
+
? void 0
|
|
225
|
+
: _fieldNodeMap$keys$.value;
|
|
226
|
+
const isNullLiteral = !value || value.kind === Kind.NULL;
|
|
227
|
+
const isVariable =
|
|
228
|
+
(value === null || value === void 0 ? void 0 : value.kind) ===
|
|
229
|
+
Kind.VARIABLE;
|
|
230
|
+
|
|
231
|
+
if (isNullLiteral) {
|
|
232
|
+
context.reportError(
|
|
233
|
+
new GraphQLError(`Field "${type.name}.${keys[0]}" must be non-null.`, {
|
|
234
|
+
nodes: [node],
|
|
235
|
+
}),
|
|
236
|
+
);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (isVariable) {
|
|
241
|
+
const variableName = value.name.value;
|
|
242
|
+
const definition = variableDefinitions[variableName];
|
|
243
|
+
const isNullableVariable = definition.type.kind !== Kind.NON_NULL_TYPE;
|
|
244
|
+
|
|
245
|
+
if (isNullableVariable) {
|
|
246
|
+
context.reportError(
|
|
247
|
+
new GraphQLError(
|
|
248
|
+
`Variable "${variableName}" must be non-nullable to be used for OneOf Input Object "${type.name}".`,
|
|
249
|
+
{
|
|
250
|
+
nodes: [node],
|
|
251
|
+
},
|
|
252
|
+
),
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
import { MaxIntrospectionDepthRule } from './rules/MaxIntrospectionDepthRule';
|
|
1
2
|
import type { SDLValidationRule, ValidationRule } from './ValidationContext';
|
|
3
|
+
/**
|
|
4
|
+
* Technically these aren't part of the spec but they are strongly encouraged
|
|
5
|
+
* validation rules.
|
|
6
|
+
*/
|
|
7
|
+
export declare const recommendedRules: readonly typeof MaxIntrospectionDepthRule[];
|
|
2
8
|
/**
|
|
3
9
|
* This set includes all validation rules defined by the GraphQL spec.
|
|
4
10
|
*
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', {
|
|
4
4
|
value: true,
|
|
5
5
|
});
|
|
6
|
-
exports.specifiedSDLRules =
|
|
6
|
+
exports.specifiedSDLRules =
|
|
7
|
+
exports.specifiedRules =
|
|
8
|
+
exports.recommendedRules =
|
|
9
|
+
void 0;
|
|
7
10
|
|
|
8
11
|
var _ExecutableDefinitionsRule = require('./rules/ExecutableDefinitionsRule.js');
|
|
9
12
|
|
|
@@ -23,6 +26,8 @@ var _LoneAnonymousOperationRule = require('./rules/LoneAnonymousOperationRule.js
|
|
|
23
26
|
|
|
24
27
|
var _LoneSchemaDefinitionRule = require('./rules/LoneSchemaDefinitionRule.js');
|
|
25
28
|
|
|
29
|
+
var _MaxIntrospectionDepthRule = require('./rules/MaxIntrospectionDepthRule.js');
|
|
30
|
+
|
|
26
31
|
var _NoFragmentCyclesRule = require('./rules/NoFragmentCyclesRule.js');
|
|
27
32
|
|
|
28
33
|
var _NoUndefinedVariablesRule = require('./rules/NoUndefinedVariablesRule.js');
|
|
@@ -82,6 +87,7 @@ var _VariablesInAllowedPositionRule = require('./rules/VariablesInAllowedPositio
|
|
|
82
87
|
// Spec Section: "Fragment Spread Type Existence"
|
|
83
88
|
// Spec Section: "Lone Anonymous Operation"
|
|
84
89
|
// SDL-specific validation rules
|
|
90
|
+
// TODO: Spec Section
|
|
85
91
|
// Spec Section: "Fragments must not form cycles"
|
|
86
92
|
// Spec Section: "All Variable Used Defined"
|
|
87
93
|
// Spec Section: "Fragments must be used"
|
|
@@ -101,12 +107,21 @@ var _VariablesInAllowedPositionRule = require('./rules/VariablesInAllowedPositio
|
|
|
101
107
|
// Spec Section: "Variables are Input Types"
|
|
102
108
|
// Spec Section: "All Variable Usages Are Allowed"
|
|
103
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Technically these aren't part of the spec but they are strongly encouraged
|
|
112
|
+
* validation rules.
|
|
113
|
+
*/
|
|
114
|
+
const recommendedRules = Object.freeze([
|
|
115
|
+
_MaxIntrospectionDepthRule.MaxIntrospectionDepthRule,
|
|
116
|
+
]);
|
|
104
117
|
/**
|
|
105
118
|
* This set includes all validation rules defined by the GraphQL spec.
|
|
106
119
|
*
|
|
107
120
|
* The order of the rules in this list has been adjusted to lead to the
|
|
108
121
|
* most clear output when encountering multiple validation errors.
|
|
109
122
|
*/
|
|
123
|
+
|
|
124
|
+
exports.recommendedRules = recommendedRules;
|
|
110
125
|
const specifiedRules = Object.freeze([
|
|
111
126
|
_ExecutableDefinitionsRule.ExecutableDefinitionsRule,
|
|
112
127
|
_UniqueOperationNamesRule.UniqueOperationNamesRule,
|
|
@@ -134,6 +149,7 @@ const specifiedRules = Object.freeze([
|
|
|
134
149
|
_VariablesInAllowedPositionRule.VariablesInAllowedPositionRule,
|
|
135
150
|
_OverlappingFieldsCanBeMergedRule.OverlappingFieldsCanBeMergedRule,
|
|
136
151
|
_UniqueInputFieldNamesRule.UniqueInputFieldNamesRule,
|
|
152
|
+
...recommendedRules,
|
|
137
153
|
]);
|
|
138
154
|
/**
|
|
139
155
|
* @internal
|
|
@@ -18,7 +18,9 @@ import { KnownTypeNamesRule } from './rules/KnownTypeNamesRule.mjs'; // Spec Sec
|
|
|
18
18
|
|
|
19
19
|
import { LoneAnonymousOperationRule } from './rules/LoneAnonymousOperationRule.mjs'; // SDL-specific validation rules
|
|
20
20
|
|
|
21
|
-
import { LoneSchemaDefinitionRule } from './rules/LoneSchemaDefinitionRule.mjs'; // Spec Section
|
|
21
|
+
import { LoneSchemaDefinitionRule } from './rules/LoneSchemaDefinitionRule.mjs'; // TODO: Spec Section
|
|
22
|
+
|
|
23
|
+
import { MaxIntrospectionDepthRule } from './rules/MaxIntrospectionDepthRule.mjs'; // Spec Section: "Fragments must not form cycles"
|
|
22
24
|
|
|
23
25
|
import { NoFragmentCyclesRule } from './rules/NoFragmentCyclesRule.mjs'; // Spec Section: "All Variable Used Defined"
|
|
24
26
|
|
|
@@ -66,12 +68,18 @@ import { VariablesAreInputTypesRule } from './rules/VariablesAreInputTypesRule.m
|
|
|
66
68
|
|
|
67
69
|
import { VariablesInAllowedPositionRule } from './rules/VariablesInAllowedPositionRule.mjs';
|
|
68
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Technically these aren't part of the spec but they are strongly encouraged
|
|
73
|
+
* validation rules.
|
|
74
|
+
*/
|
|
75
|
+
export const recommendedRules = Object.freeze([MaxIntrospectionDepthRule]);
|
|
69
76
|
/**
|
|
70
77
|
* This set includes all validation rules defined by the GraphQL spec.
|
|
71
78
|
*
|
|
72
79
|
* The order of the rules in this list has been adjusted to lead to the
|
|
73
80
|
* most clear output when encountering multiple validation errors.
|
|
74
81
|
*/
|
|
82
|
+
|
|
75
83
|
export const specifiedRules = Object.freeze([
|
|
76
84
|
ExecutableDefinitionsRule,
|
|
77
85
|
UniqueOperationNamesRule,
|
|
@@ -99,6 +107,7 @@ export const specifiedRules = Object.freeze([
|
|
|
99
107
|
VariablesInAllowedPositionRule,
|
|
100
108
|
OverlappingFieldsCanBeMergedRule,
|
|
101
109
|
UniqueInputFieldNamesRule,
|
|
110
|
+
...recommendedRules,
|
|
102
111
|
]);
|
|
103
112
|
/**
|
|
104
113
|
* @internal
|