@envelop/extended-validation 4.0.0 → 4.1.0-alpha-20240806125641-9b9885ba

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 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,49 @@ 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
- let result = {
60
- data: null,
61
- errors,
62
- };
63
- if (onValidationFailed) {
64
- onValidationFailed({ args, result, setResult: newResult => (result = newResult) });
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
+ errors.forEach(e => {
86
+ if (e.path?.length) {
87
+ let currentData = (newResult.data ||= {});
88
+ for (const pathItem of e.path.slice(0, -1)) {
89
+ currentData = currentData[pathItem] ||= {};
90
+ }
91
+ currentData[e.path[e.path.length - 1]] = null;
92
+ }
93
+ });
94
+ setResult(newResult);
95
+ }
96
+ return {
97
+ onSubscribeResult: onResult,
98
+ onExecuteDone: onResult,
99
+ };
65
100
  }
66
- setResultAndStopExecution(result);
67
101
  }
68
102
  }
69
103
  }
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,49 @@ 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
- let result = {
56
- data: null,
57
- errors,
58
- };
59
- if (onValidationFailed) {
60
- onValidationFailed({ args, result, setResult: newResult => (result = newResult) });
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
+ errors.forEach(e => {
82
+ if (e.path?.length) {
83
+ let currentData = (newResult.data ||= {});
84
+ for (const pathItem of e.path.slice(0, -1)) {
85
+ currentData = currentData[pathItem] ||= {};
86
+ }
87
+ currentData[e.path[e.path.length - 1]] = null;
88
+ }
89
+ });
90
+ setResult(newResult);
91
+ }
92
+ return {
93
+ onSubscribeResult: onResult,
94
+ onExecuteDone: onResult,
95
+ };
61
96
  }
62
- setResultAndStopExecution(result);
63
97
  }
64
98
  }
65
99
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@envelop/extended-validation",
3
- "version": "4.0.0",
3
+ "version": "4.1.0-alpha-20240806125641-9b9885ba",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
6
  "@envelop/core": "^5.0.0",
@@ -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
  }>;
@@ -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
  }>;