@envelop/extended-validation 4.0.0 → 4.1.0-alpha-20240810114324-912296f8
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/cjs/plugin.js +54 -11
- package/esm/plugin.js +54 -11
- package/package.json +1 -1
- package/typings/plugin.d.cts +6 -0
- package/typings/plugin.d.ts +6 -0
package/cjs/plugin.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.useExtendedValidation = void 0;
|
|
4
4
|
const graphql_1 = require("graphql");
|
|
5
|
+
const core_1 = require("@envelop/core");
|
|
5
6
|
const symbolExtendedValidationRules = Symbol('extendedValidationContext');
|
|
6
7
|
const useExtendedValidation = (options) => {
|
|
7
8
|
let schemaTypeInfo;
|
|
@@ -27,12 +28,12 @@ const useExtendedValidation = (options) => {
|
|
|
27
28
|
}
|
|
28
29
|
validationRulesContext.rules.push(...options.rules);
|
|
29
30
|
},
|
|
30
|
-
onSubscribe: buildHandler('subscribe', getTypeInfo, options.onValidationFailed),
|
|
31
|
-
onExecute: buildHandler('execute', getTypeInfo, options.onValidationFailed),
|
|
31
|
+
onSubscribe: buildHandler('subscribe', getTypeInfo, options.onValidationFailed, options.rejectOnErrors !== false),
|
|
32
|
+
onExecute: buildHandler('execute', getTypeInfo, options.onValidationFailed, options.rejectOnErrors !== false),
|
|
32
33
|
};
|
|
33
34
|
};
|
|
34
35
|
exports.useExtendedValidation = useExtendedValidation;
|
|
35
|
-
function buildHandler(name, getTypeInfo, onValidationFailed) {
|
|
36
|
+
function buildHandler(name, getTypeInfo, onValidationFailed, rejectOnErrors = true) {
|
|
36
37
|
return function handler({ args, setResultAndStopExecution, }) {
|
|
37
38
|
// We hook into onExecute/onSubscribe even though this is a validation pattern. The reasoning behind
|
|
38
39
|
// it is that hooking right after validation and before execution has started is the
|
|
@@ -54,16 +55,58 @@ function buildHandler(name, getTypeInfo, onValidationFailed) {
|
|
|
54
55
|
errors.push(e);
|
|
55
56
|
});
|
|
56
57
|
const visitor = (0, graphql_1.visitInParallel)(validationRulesContext.rules.map(rule => rule(validationContext, args)));
|
|
57
|
-
(0, graphql_1.visit)(args.document, (0, graphql_1.visitWithTypeInfo)(typeInfo, visitor));
|
|
58
|
+
args.document = (0, graphql_1.visit)(args.document, (0, graphql_1.visitWithTypeInfo)(typeInfo, visitor));
|
|
58
59
|
if (errors.length > 0) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
if (rejectOnErrors) {
|
|
61
|
+
let result = {
|
|
62
|
+
data: null,
|
|
63
|
+
errors,
|
|
64
|
+
};
|
|
65
|
+
if (onValidationFailed) {
|
|
66
|
+
onValidationFailed({ args, result, setResult: newResult => (result = newResult) });
|
|
67
|
+
}
|
|
68
|
+
setResultAndStopExecution(result);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
// eslint-disable-next-line no-inner-declarations
|
|
72
|
+
function onResult({ result, setResult, }) {
|
|
73
|
+
if ((0, core_1.isAsyncIterable)(result)) {
|
|
74
|
+
// rejectOnErrors is false doesn't work with async iterables
|
|
75
|
+
setResult({
|
|
76
|
+
data: null,
|
|
77
|
+
errors,
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const newResult = {
|
|
82
|
+
...result,
|
|
83
|
+
errors: [...(result.errors || []), ...errors],
|
|
84
|
+
};
|
|
85
|
+
function visitPath(path, data = {}) {
|
|
86
|
+
let currentData = (data ||= typeof path[0] === 'number' ? [] : {});
|
|
87
|
+
for (const pathItemIndex in path.slice(0, -1)) {
|
|
88
|
+
const pathItem = path[pathItemIndex];
|
|
89
|
+
currentData = currentData[pathItem] ||=
|
|
90
|
+
typeof path[Number(pathItemIndex) + 1] === 'number' ? [] : {};
|
|
91
|
+
if (Array.isArray(currentData)) {
|
|
92
|
+
currentData = currentData.map((c, i) => visitPath(path.slice(Number(pathItemIndex) + 1), c));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
currentData[path[path.length - 1]] = null;
|
|
96
|
+
return data;
|
|
97
|
+
}
|
|
98
|
+
errors.forEach(e => {
|
|
99
|
+
if (e.path?.length) {
|
|
100
|
+
newResult.data = visitPath(e.path, newResult.data);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
setResult(newResult);
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
onSubscribeResult: onResult,
|
|
107
|
+
onExecuteDone: onResult,
|
|
108
|
+
};
|
|
65
109
|
}
|
|
66
|
-
setResultAndStopExecution(result);
|
|
67
110
|
}
|
|
68
111
|
}
|
|
69
112
|
}
|
package/esm/plugin.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { TypeInfo, ValidationContext, visit, visitInParallel, visitWithTypeInfo, } from 'graphql';
|
|
2
|
+
import { isAsyncIterable, } from '@envelop/core';
|
|
2
3
|
const symbolExtendedValidationRules = Symbol('extendedValidationContext');
|
|
3
4
|
export const useExtendedValidation = (options) => {
|
|
4
5
|
let schemaTypeInfo;
|
|
@@ -24,11 +25,11 @@ export const useExtendedValidation = (options) => {
|
|
|
24
25
|
}
|
|
25
26
|
validationRulesContext.rules.push(...options.rules);
|
|
26
27
|
},
|
|
27
|
-
onSubscribe: buildHandler('subscribe', getTypeInfo, options.onValidationFailed),
|
|
28
|
-
onExecute: buildHandler('execute', getTypeInfo, options.onValidationFailed),
|
|
28
|
+
onSubscribe: buildHandler('subscribe', getTypeInfo, options.onValidationFailed, options.rejectOnErrors !== false),
|
|
29
|
+
onExecute: buildHandler('execute', getTypeInfo, options.onValidationFailed, options.rejectOnErrors !== false),
|
|
29
30
|
};
|
|
30
31
|
};
|
|
31
|
-
function buildHandler(name, getTypeInfo, onValidationFailed) {
|
|
32
|
+
function buildHandler(name, getTypeInfo, onValidationFailed, rejectOnErrors = true) {
|
|
32
33
|
return function handler({ args, setResultAndStopExecution, }) {
|
|
33
34
|
// We hook into onExecute/onSubscribe even though this is a validation pattern. The reasoning behind
|
|
34
35
|
// it is that hooking right after validation and before execution has started is the
|
|
@@ -50,16 +51,58 @@ function buildHandler(name, getTypeInfo, onValidationFailed) {
|
|
|
50
51
|
errors.push(e);
|
|
51
52
|
});
|
|
52
53
|
const visitor = visitInParallel(validationRulesContext.rules.map(rule => rule(validationContext, args)));
|
|
53
|
-
visit(args.document, visitWithTypeInfo(typeInfo, visitor));
|
|
54
|
+
args.document = visit(args.document, visitWithTypeInfo(typeInfo, visitor));
|
|
54
55
|
if (errors.length > 0) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
if (rejectOnErrors) {
|
|
57
|
+
let result = {
|
|
58
|
+
data: null,
|
|
59
|
+
errors,
|
|
60
|
+
};
|
|
61
|
+
if (onValidationFailed) {
|
|
62
|
+
onValidationFailed({ args, result, setResult: newResult => (result = newResult) });
|
|
63
|
+
}
|
|
64
|
+
setResultAndStopExecution(result);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// eslint-disable-next-line no-inner-declarations
|
|
68
|
+
function onResult({ result, setResult, }) {
|
|
69
|
+
if (isAsyncIterable(result)) {
|
|
70
|
+
// rejectOnErrors is false doesn't work with async iterables
|
|
71
|
+
setResult({
|
|
72
|
+
data: null,
|
|
73
|
+
errors,
|
|
74
|
+
});
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const newResult = {
|
|
78
|
+
...result,
|
|
79
|
+
errors: [...(result.errors || []), ...errors],
|
|
80
|
+
};
|
|
81
|
+
function visitPath(path, data = {}) {
|
|
82
|
+
let currentData = (data ||= typeof path[0] === 'number' ? [] : {});
|
|
83
|
+
for (const pathItemIndex in path.slice(0, -1)) {
|
|
84
|
+
const pathItem = path[pathItemIndex];
|
|
85
|
+
currentData = currentData[pathItem] ||=
|
|
86
|
+
typeof path[Number(pathItemIndex) + 1] === 'number' ? [] : {};
|
|
87
|
+
if (Array.isArray(currentData)) {
|
|
88
|
+
currentData = currentData.map((c, i) => visitPath(path.slice(Number(pathItemIndex) + 1), c));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
currentData[path[path.length - 1]] = null;
|
|
92
|
+
return data;
|
|
93
|
+
}
|
|
94
|
+
errors.forEach(e => {
|
|
95
|
+
if (e.path?.length) {
|
|
96
|
+
newResult.data = visitPath(e.path, newResult.data);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
setResult(newResult);
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
onSubscribeResult: onResult,
|
|
103
|
+
onExecuteDone: onResult,
|
|
104
|
+
};
|
|
61
105
|
}
|
|
62
|
-
setResultAndStopExecution(result);
|
|
63
106
|
}
|
|
64
107
|
}
|
|
65
108
|
}
|
package/package.json
CHANGED
package/typings/plugin.d.cts
CHANGED
|
@@ -17,6 +17,12 @@ export declare const useExtendedValidation: <PluginContext extends Record<string
|
|
|
17
17
|
* Callback that is invoked if the extended validation yields any errors.
|
|
18
18
|
*/
|
|
19
19
|
onValidationFailed?: OnValidationFailedCallback;
|
|
20
|
+
/**
|
|
21
|
+
* Reject the execution if the validation fails.
|
|
22
|
+
*
|
|
23
|
+
* @default true
|
|
24
|
+
*/
|
|
25
|
+
rejectOnErrors?: boolean;
|
|
20
26
|
}) => Plugin<PluginContext & {
|
|
21
27
|
[symbolExtendedValidationRules]?: ExtendedValidationContext | undefined;
|
|
22
28
|
}>;
|
package/typings/plugin.d.ts
CHANGED
|
@@ -17,6 +17,12 @@ export declare const useExtendedValidation: <PluginContext extends Record<string
|
|
|
17
17
|
* Callback that is invoked if the extended validation yields any errors.
|
|
18
18
|
*/
|
|
19
19
|
onValidationFailed?: OnValidationFailedCallback;
|
|
20
|
+
/**
|
|
21
|
+
* Reject the execution if the validation fails.
|
|
22
|
+
*
|
|
23
|
+
* @default true
|
|
24
|
+
*/
|
|
25
|
+
rejectOnErrors?: boolean;
|
|
20
26
|
}) => Plugin<PluginContext & {
|
|
21
27
|
[symbolExtendedValidationRules]?: ExtendedValidationContext | undefined;
|
|
22
28
|
}>;
|