@tyravel/validation 0.1.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/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/rules.d.ts +16 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +114 -0
- package/dist/rules.js.map +1 -0
- package/dist/validator.d.ts +17 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +74 -0
- package/dist/validator.js.map +1 -0
- package/dist/validator.test.d.ts +2 -0
- package/dist/validator.test.d.ts.map +1 -0
- package/dist/validator.test.js +25 -0
- package/dist/validator.test.js.map +1 -0
- package/package.json +36 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { email, integer, max, maxLength, min, minLength, parseRule, required, } from './rules.js';
|
|
2
|
+
export type { Rule, ValidationRule, ValidationRules } from './rules.js';
|
|
3
|
+
export { validateRequest, ValidationException, Validator, } from './validator.js';
|
|
4
|
+
export type { ValidationErrors } from './validator.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,OAAO,EACP,GAAG,EACH,SAAS,EACT,GAAG,EACH,SAAS,EACT,SAAS,EACT,QAAQ,GACT,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,SAAS,GACV,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,OAAO,EACP,GAAG,EACH,SAAS,EACT,GAAG,EACH,SAAS,EACT,SAAS,EACT,QAAQ,GACT,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,SAAS,GACV,MAAM,gBAAgB,CAAC"}
|
package/dist/rules.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type Rule = string | ValidationRule;
|
|
2
|
+
export interface ValidationRule {
|
|
3
|
+
validate(value: unknown, field: string): string | undefined;
|
|
4
|
+
}
|
|
5
|
+
export type ValidationRules<T extends Record<string, unknown>> = {
|
|
6
|
+
[K in keyof T]?: Rule | Rule[];
|
|
7
|
+
};
|
|
8
|
+
export declare function required(): ValidationRule;
|
|
9
|
+
export declare function email(): ValidationRule;
|
|
10
|
+
export declare function minLength(min: number): ValidationRule;
|
|
11
|
+
export declare function maxLength(max: number): ValidationRule;
|
|
12
|
+
export declare function integer(): ValidationRule;
|
|
13
|
+
export declare function min(minimum: number): ValidationRule;
|
|
14
|
+
export declare function max(maximum: number): ValidationRule;
|
|
15
|
+
export declare function parseRule(rule: Rule): ValidationRule[];
|
|
16
|
+
//# sourceMappingURL=rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,cAAc,CAAC;AAE3C,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CAC7D;AAED,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;KAC9D,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,GAAG,IAAI,EAAE;CAC/B,CAAC;AAEF,wBAAgB,QAAQ,IAAI,cAAc,CASzC;AAED,wBAAgB,KAAK,IAAI,cAAc,CAYtC;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAYrD;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAYrD;AAED,wBAAgB,OAAO,IAAI,cAAc,CAaxC;AAED,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAanD;AAED,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAanD;AAYD,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,cAAc,EAAE,CAatD"}
|
package/dist/rules.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
export function required() {
|
|
2
|
+
return {
|
|
3
|
+
validate(value, field) {
|
|
4
|
+
if (value === undefined || value === null || value === '') {
|
|
5
|
+
return `The ${field} field is required.`;
|
|
6
|
+
}
|
|
7
|
+
return undefined;
|
|
8
|
+
},
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function email() {
|
|
12
|
+
return {
|
|
13
|
+
validate(value, field) {
|
|
14
|
+
if (value === undefined || value === null || value === '') {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
if (typeof value !== 'string' || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
|
|
18
|
+
return `The ${field} field must be a valid email address.`;
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function minLength(min) {
|
|
25
|
+
return {
|
|
26
|
+
validate(value, field) {
|
|
27
|
+
if (value === undefined || value === null) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
if (typeof value !== 'string' || value.length < min) {
|
|
31
|
+
return `The ${field} field must be at least ${min} characters.`;
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function maxLength(max) {
|
|
38
|
+
return {
|
|
39
|
+
validate(value, field) {
|
|
40
|
+
if (value === undefined || value === null) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
if (typeof value !== 'string' || value.length > max) {
|
|
44
|
+
return `The ${field} field must not exceed ${max} characters.`;
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export function integer() {
|
|
51
|
+
return {
|
|
52
|
+
validate(value, field) {
|
|
53
|
+
if (value === undefined || value === null || value === '') {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
const parsed = Number(value);
|
|
57
|
+
if (!Number.isInteger(parsed)) {
|
|
58
|
+
return `The ${field} field must be an integer.`;
|
|
59
|
+
}
|
|
60
|
+
return undefined;
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export function min(minimum) {
|
|
65
|
+
return {
|
|
66
|
+
validate(value, field) {
|
|
67
|
+
if (value === undefined || value === null || value === '') {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
const parsed = Number(value);
|
|
71
|
+
if (!Number.isFinite(parsed) || parsed < minimum) {
|
|
72
|
+
return `The ${field} field must be at least ${minimum}.`;
|
|
73
|
+
}
|
|
74
|
+
return undefined;
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export function max(maximum) {
|
|
79
|
+
return {
|
|
80
|
+
validate(value, field) {
|
|
81
|
+
if (value === undefined || value === null || value === '') {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
const parsed = Number(value);
|
|
85
|
+
if (!Number.isFinite(parsed) || parsed > maximum) {
|
|
86
|
+
return `The ${field} field must not be greater than ${maximum}.`;
|
|
87
|
+
}
|
|
88
|
+
return undefined;
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const BUILT_IN_RULES = {
|
|
93
|
+
required: () => required(),
|
|
94
|
+
email: () => email(),
|
|
95
|
+
integer: () => integer(),
|
|
96
|
+
min: (arg) => min(Number(arg)),
|
|
97
|
+
max: (arg) => max(Number(arg)),
|
|
98
|
+
min_length: (arg) => minLength(Number(arg)),
|
|
99
|
+
max_length: (arg) => maxLength(Number(arg)),
|
|
100
|
+
};
|
|
101
|
+
export function parseRule(rule) {
|
|
102
|
+
if (typeof rule !== 'string') {
|
|
103
|
+
return [rule];
|
|
104
|
+
}
|
|
105
|
+
return rule.split('|').map((segment) => {
|
|
106
|
+
const [name, arg] = segment.split(':');
|
|
107
|
+
const factory = BUILT_IN_RULES[name ?? ''];
|
|
108
|
+
if (!factory) {
|
|
109
|
+
throw new Error(`Unknown validation rule: ${name}`);
|
|
110
|
+
}
|
|
111
|
+
return factory(arg);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { TyravelRequest } from '@tyravel/http';
|
|
2
|
+
import { type ValidationRules } from './rules.js';
|
|
3
|
+
export interface ValidationErrors {
|
|
4
|
+
[field: string]: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare class ValidationException extends Error {
|
|
7
|
+
readonly errors: ValidationErrors;
|
|
8
|
+
constructor(errors: ValidationErrors);
|
|
9
|
+
}
|
|
10
|
+
export declare class Validator<T extends Record<string, unknown>> {
|
|
11
|
+
private readonly data;
|
|
12
|
+
private readonly rules;
|
|
13
|
+
constructor(data: Partial<T>, rules: ValidationRules<T>);
|
|
14
|
+
validate(): T;
|
|
15
|
+
}
|
|
16
|
+
export declare function validateRequest<T extends Record<string, unknown>>(request: TyravelRequest, rules: ValidationRules<T>): Promise<T>;
|
|
17
|
+
//# sourceMappingURL=validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,WAAW,gBAAgB;IAC/B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC3B;AAED,qBAAa,mBAAoB,SAAQ,KAAK;aAChB,MAAM,EAAE,gBAAgB;gBAAxB,MAAM,EAAE,gBAAgB;CAIrD;AAED,qBAAa,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAEpD,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK;gBADL,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAChB,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC;IAG5C,QAAQ,IAAI,CAAC;CAqCd;AAED,wBAAsB,eAAe,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrE,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,GACxB,OAAO,CAAC,CAAC,CAAC,CA2BZ"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { parseRule } from './rules.js';
|
|
2
|
+
export class ValidationException extends Error {
|
|
3
|
+
errors;
|
|
4
|
+
constructor(errors) {
|
|
5
|
+
super('The given data was invalid.');
|
|
6
|
+
this.errors = errors;
|
|
7
|
+
this.name = 'ValidationException';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export class Validator {
|
|
11
|
+
data;
|
|
12
|
+
rules;
|
|
13
|
+
constructor(data, rules) {
|
|
14
|
+
this.data = data;
|
|
15
|
+
this.rules = rules;
|
|
16
|
+
}
|
|
17
|
+
validate() {
|
|
18
|
+
const errors = {};
|
|
19
|
+
const validated = { ...this.data };
|
|
20
|
+
for (const field of Object.keys(this.rules)) {
|
|
21
|
+
const ruleSet = this.rules[field];
|
|
22
|
+
if (!ruleSet) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const normalizedRules = Array.isArray(ruleSet)
|
|
26
|
+
? ruleSet.flatMap((rule) => parseRule(rule))
|
|
27
|
+
: parseRule(ruleSet);
|
|
28
|
+
const value = this.data[field];
|
|
29
|
+
const fieldErrors = [];
|
|
30
|
+
for (const rule of normalizedRules) {
|
|
31
|
+
const message = rule.validate(value, String(field));
|
|
32
|
+
if (message) {
|
|
33
|
+
fieldErrors.push(message);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (fieldErrors.length > 0) {
|
|
37
|
+
errors[String(field)] = fieldErrors;
|
|
38
|
+
}
|
|
39
|
+
else if (value !== undefined) {
|
|
40
|
+
validated[field] = value;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (Object.keys(errors).length > 0) {
|
|
44
|
+
throw new ValidationException(errors);
|
|
45
|
+
}
|
|
46
|
+
return validated;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export async function validateRequest(request, rules) {
|
|
50
|
+
const contentType = request.headers.get('content-type') ?? '';
|
|
51
|
+
let data = {};
|
|
52
|
+
if (contentType.includes('application/json')) {
|
|
53
|
+
data = (await request.json());
|
|
54
|
+
}
|
|
55
|
+
else if (contentType.includes('application/x-www-form-urlencoded') ||
|
|
56
|
+
contentType.includes('multipart/form-data')) {
|
|
57
|
+
const formData = await request.formData();
|
|
58
|
+
const entries = {};
|
|
59
|
+
formData.forEach((value, key) => {
|
|
60
|
+
entries[key] = value;
|
|
61
|
+
});
|
|
62
|
+
data = entries;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
for (const field of Object.keys(rules)) {
|
|
66
|
+
const queryValue = request.query(field);
|
|
67
|
+
if (queryValue !== undefined) {
|
|
68
|
+
data[field] = queryValue;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return new Validator(data, rules).validate();
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.test.d.ts","sourceRoot":"","sources":["../src/validator.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { TyravelRequest } from '@tyravel/http';
|
|
3
|
+
import { validateRequest, ValidationException, Validator } from './validator.js';
|
|
4
|
+
describe('Validator', () => {
|
|
5
|
+
it('validates required and email rules', () => {
|
|
6
|
+
const result = new Validator({ email: 'user@example.com', name: 'Tyravel' }, { email: 'required|email', name: 'required|max_length:50' }).validate();
|
|
7
|
+
expect(result.email).toBe('user@example.com');
|
|
8
|
+
});
|
|
9
|
+
it('throws a validation exception with field errors', () => {
|
|
10
|
+
expect(() => new Validator({ email: 'invalid' }, { email: 'required|email' }).validate()).toThrow(ValidationException);
|
|
11
|
+
});
|
|
12
|
+
it('validates json request bodies', async () => {
|
|
13
|
+
const request = new TyravelRequest(new Request('http://localhost/register', {
|
|
14
|
+
method: 'POST',
|
|
15
|
+
headers: { 'content-type': 'application/json' },
|
|
16
|
+
body: JSON.stringify({ email: 'user@example.com', age: 21 }),
|
|
17
|
+
}));
|
|
18
|
+
const data = await validateRequest(request, {
|
|
19
|
+
email: 'required|email',
|
|
20
|
+
age: 'required|integer|min:18',
|
|
21
|
+
});
|
|
22
|
+
expect(data).toEqual({ email: 'user@example.com', age: 21 });
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
//# sourceMappingURL=validator.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.test.js","sourceRoot":"","sources":["../src/validator.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEjF,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,SAAS,EAAE,EAC9C,EAAE,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,wBAAwB,EAAE,CAC5D,CAAC,QAAQ,EAAE,CAAC;QAEb,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,CAAC,GAAG,EAAE,CACV,IAAI,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC,QAAQ,EAAE,CAC5E,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,OAAO,GAAG,IAAI,cAAc,CAChC,IAAI,OAAO,CAAC,2BAA2B,EAAE;YACvC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;SAC7D,CAAC,CACH,CAAC;QAEF,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,OAAO,EAAE;YAC1C,KAAK,EAAE,gBAAgB;YACvB,GAAG,EAAE,yBAAyB;SAC/B,CAAC,CAAC;QAEH,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tyravel/validation",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc -p tsconfig.json",
|
|
15
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@tyravel/http": "0.1.0"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"description": "Request validation for Tyravel",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/thesimonharms/tyravel.git",
|
|
28
|
+
"directory": "packages/validation"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=22"
|
|
35
|
+
}
|
|
36
|
+
}
|