@koala-ts/framework 2.9.1 → 2.11.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/Application/Response.test.js +1 -4
- package/dist/Application/Response.test.js.map +1 -1
- package/dist/Routing/Router.test.js +1 -5
- package/dist/Routing/Router.test.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/serializer/normalizer/normalizer.test.js +60 -0
- package/dist/serializer/normalizer/normalizer.test.js.map +1 -1
- package/dist/serializer/normalizer/record-normalizer.d.ts.map +1 -1
- package/dist/serializer/normalizer/record-normalizer.js +25 -4
- package/dist/serializer/normalizer/record-normalizer.js.map +1 -1
- package/dist/serializer/normalizer/record-normalizer.test.js +4 -4
- package/dist/serializer/normalizer/record-normalizer.test.js.map +1 -1
- package/dist/serializer/normalizer/types.d.ts +3 -1
- package/dist/serializer/normalizer/types.d.ts.map +1 -1
- package/dist/validator/constraints/basic/not-blank.d.ts +3 -0
- package/dist/validator/constraints/basic/not-blank.d.ts.map +1 -0
- package/dist/validator/constraints/basic/not-blank.js +21 -0
- package/dist/validator/constraints/basic/not-blank.js.map +1 -0
- package/dist/validator/constraints/basic/not-blank.test.d.ts +2 -0
- package/dist/validator/constraints/basic/not-blank.test.d.ts.map +1 -0
- package/dist/validator/constraints/basic/not-blank.test.js +79 -0
- package/dist/validator/constraints/basic/not-blank.test.js.map +1 -0
- package/dist/validator/constraints/index.d.ts +7 -0
- package/dist/validator/constraints/index.d.ts.map +1 -0
- package/dist/validator/constraints/index.js +9 -0
- package/dist/validator/constraints/index.js.map +1 -0
- package/dist/validator/constraints/other/compound.d.ts +3 -0
- package/dist/validator/constraints/other/compound.d.ts.map +1 -0
- package/dist/validator/constraints/other/compound.integration.test.d.ts +2 -0
- package/dist/validator/constraints/other/compound.integration.test.d.ts.map +1 -0
- package/dist/validator/constraints/other/compound.integration.test.js +76 -0
- package/dist/validator/constraints/other/compound.integration.test.js.map +1 -0
- package/dist/validator/constraints/other/compound.js +6 -0
- package/dist/validator/constraints/other/compound.js.map +1 -0
- package/dist/validator/constraints/other/compound.test.d.ts +2 -0
- package/dist/validator/constraints/other/compound.test.d.ts.map +1 -0
- package/dist/validator/constraints/other/compound.test.js +62 -0
- package/dist/validator/constraints/other/compound.test.js.map +1 -0
- package/dist/validator/constraints/string/email.d.ts +3 -0
- package/dist/validator/constraints/string/email.d.ts.map +1 -0
- package/dist/validator/constraints/string/email.js +29 -0
- package/dist/validator/constraints/string/email.js.map +1 -0
- package/dist/validator/constraints/string/email.test.d.ts +2 -0
- package/dist/validator/constraints/string/email.test.d.ts.map +1 -0
- package/dist/validator/constraints/string/email.test.js +119 -0
- package/dist/validator/constraints/string/email.test.js.map +1 -0
- package/dist/validator/errors.d.ts +4 -0
- package/dist/validator/errors.d.ts.map +1 -0
- package/dist/validator/errors.js +7 -0
- package/dist/validator/errors.js.map +1 -0
- package/dist/validator/index.d.ts +4 -0
- package/dist/validator/index.d.ts.map +1 -0
- package/dist/validator/index.js +4 -0
- package/dist/validator/index.js.map +1 -0
- package/dist/validator/types.d.ts +31 -0
- package/dist/validator/types.d.ts.map +1 -0
- package/dist/validator/types.js +1 -0
- package/dist/validator/types.js.map +1 -0
- package/dist/validator/validator.d.ts +3 -0
- package/dist/validator/validator.d.ts.map +1 -0
- package/dist/validator/validator.js +59 -0
- package/dist/validator/validator.js.map +1 -0
- package/dist/validator/validator.test.d.ts +2 -0
- package/dist/validator/validator.test.d.ts.map +1 -0
- package/dist/validator/validator.test.js +281 -0
- package/dist/validator/validator.test.js.map +1 -0
- package/package.json +6 -7
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { compound } from './compound.js';
|
|
3
|
+
describe('compound', () => {
|
|
4
|
+
it('creates a constraint that applies nested constraints from arrays', () => {
|
|
5
|
+
const applyConstraints = vi.fn(() => [
|
|
6
|
+
{
|
|
7
|
+
path: 'user',
|
|
8
|
+
constraint: 'notBlank',
|
|
9
|
+
message: 'Required',
|
|
10
|
+
value: '',
|
|
11
|
+
},
|
|
12
|
+
]);
|
|
13
|
+
const nestedConstraints = ['notBlank'];
|
|
14
|
+
const context = {
|
|
15
|
+
path: 'user',
|
|
16
|
+
root: { user: '' },
|
|
17
|
+
value: '',
|
|
18
|
+
constraint: 'requiredEmail',
|
|
19
|
+
options: {},
|
|
20
|
+
runNestedRules: applyConstraints,
|
|
21
|
+
};
|
|
22
|
+
const requiredEmail = compound(nestedConstraints);
|
|
23
|
+
const violations = requiredEmail('', context);
|
|
24
|
+
expect(applyConstraints).toHaveBeenCalledWith('', ['notBlank'], 'user');
|
|
25
|
+
expect(violations).toHaveLength(1);
|
|
26
|
+
expect(violations[0]).toEqual({
|
|
27
|
+
path: 'user',
|
|
28
|
+
constraint: 'notBlank',
|
|
29
|
+
message: 'Required',
|
|
30
|
+
value: '',
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
it('creates a constraint that applies nested constraints from objects', () => {
|
|
34
|
+
const applyConstraints = vi.fn(() => [
|
|
35
|
+
{
|
|
36
|
+
path: 'user',
|
|
37
|
+
constraint: 'notNull',
|
|
38
|
+
message: 'Required',
|
|
39
|
+
value: null,
|
|
40
|
+
},
|
|
41
|
+
]);
|
|
42
|
+
const context = {
|
|
43
|
+
path: 'user',
|
|
44
|
+
root: { user: null },
|
|
45
|
+
value: null,
|
|
46
|
+
constraint: 'requiredEmail',
|
|
47
|
+
options: {},
|
|
48
|
+
runNestedRules: applyConstraints,
|
|
49
|
+
};
|
|
50
|
+
const requiredEmail = compound({ notNull: {} });
|
|
51
|
+
const violations = requiredEmail(null, context);
|
|
52
|
+
expect(applyConstraints).toHaveBeenCalledWith(null, { notNull: {} }, 'user');
|
|
53
|
+
expect(violations).toHaveLength(1);
|
|
54
|
+
expect(violations[0]).toEqual({
|
|
55
|
+
path: 'user',
|
|
56
|
+
constraint: 'notNull',
|
|
57
|
+
message: 'Required',
|
|
58
|
+
value: null,
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=compound.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compound.test.js","sourceRoot":"","sources":["../../../../src/validator/constraints/other/compound.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAElD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,gBAAgB,GAAG,EAAE,CAAC,EAAE,CAAC,GAAgB,EAAE,CAAC;YAChD;gBACE,IAAI,EAAE,MAAM;gBACZ,UAAU,EAAE,UAAU;gBACtB,OAAO,EAAE,UAAU;gBACnB,KAAK,EAAE,EAAE;aACV;SACF,CAAC,CAAC;QAEH,MAAM,iBAAiB,GAAG,CAAC,UAAU,CAAC,CAAC;QAEvC,MAAM,OAAO,GAAsB;YACjC,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;YAClB,KAAK,EAAE,EAAE;YACT,UAAU,EAAE,eAAe;YAC3B,OAAO,EAAE,EAAE;YACX,cAAc,EAAE,gBAAgB;SACjC,CAAC;QAEF,MAAM,aAAa,GAAG,QAAQ,CAAC,iBAAiB,CAAC,CAAC;QAClD,MAAM,UAAU,GAAG,aAAa,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAE9C,MAAM,CAAC,gBAAgB,CAAC,CAAC,oBAAoB,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC;QACxE,MAAM,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC5B,IAAI,EAAE,MAAM;YACZ,UAAU,EAAE,UAAU;YACtB,OAAO,EAAE,UAAU;YACnB,KAAK,EAAE,EAAE;SACV,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,gBAAgB,GAAG,EAAE,CAAC,EAAE,CAAC,GAAgB,EAAE,CAAC;YAChD;gBACE,IAAI,EAAE,MAAM;gBACZ,UAAU,EAAE,SAAS;gBACrB,OAAO,EAAE,UAAU;gBACnB,KAAK,EAAE,IAAI;aACZ;SACF,CAAC,CAAC;QAEH,MAAM,OAAO,GAAsB;YACjC,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;YACpB,KAAK,EAAE,IAAI;YACX,UAAU,EAAE,eAAe;YAC3B,OAAO,EAAE,EAAE;YACX,cAAc,EAAE,gBAAgB;SACjC,CAAC;QAEF,MAAM,aAAa,GAAG,QAAQ,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QAChD,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAEhD,MAAM,CAAC,gBAAgB,CAAC,CAAC,oBAAoB,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;QAC7E,MAAM,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC5B,IAAI,EAAE,MAAM;YACZ,UAAU,EAAE,SAAS;YACrB,OAAO,EAAE,UAAU;YACnB,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../../../../src/validator/constraints/string/email.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAWhE,wBAAgB,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,GAAG,SAAS,EAAE,CA6B7E"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const DEFAULT_MESSAGE = 'This value is not a valid email address.';
|
|
2
|
+
const strictEmailRegex = /^[A-Za-z0-9.!#$%&'*+/=?^_`{|}~-]+@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+$/;
|
|
3
|
+
export function email(value, context) {
|
|
4
|
+
const options = context.options;
|
|
5
|
+
const message = options.message ?? DEFAULT_MESSAGE;
|
|
6
|
+
if (typeof value !== 'string') {
|
|
7
|
+
return [
|
|
8
|
+
{
|
|
9
|
+
path: context.path,
|
|
10
|
+
constraint: context.constraint,
|
|
11
|
+
message,
|
|
12
|
+
value,
|
|
13
|
+
},
|
|
14
|
+
];
|
|
15
|
+
}
|
|
16
|
+
const normalized = options.normalizer ? options.normalizer(value) : value;
|
|
17
|
+
if (!strictEmailRegex.test(normalized)) {
|
|
18
|
+
return [
|
|
19
|
+
{
|
|
20
|
+
path: context.path,
|
|
21
|
+
constraint: context.constraint,
|
|
22
|
+
message,
|
|
23
|
+
value,
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=email.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email.js","sourceRoot":"","sources":["../../../../src/validator/constraints/string/email.ts"],"names":[],"mappings":"AAEA,MAAM,eAAe,GAAG,0CAA0C,CAAC;AAOnE,MAAM,gBAAgB,GAAG,sEAAsE,CAAC;AAEhG,MAAM,UAAU,KAAK,CAAC,KAAc,EAAE,OAA0B;IAC9D,MAAM,OAAO,GAAG,OAAO,CAAC,OAAuB,CAAC;IAChD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,eAAe,CAAC;IAEnD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO;YACL;gBACE,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,OAAO;gBACP,KAAK;aACN;SACF,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAE1E,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACvC,OAAO;YACL;gBACE,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,OAAO;gBACP,KAAK;aACN;SACF,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email.test.d.ts","sourceRoot":"","sources":["../../../../src/validator/constraints/string/email.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { email } from './email.js';
|
|
3
|
+
describe('email', () => {
|
|
4
|
+
it('rejects invalid email by default', () => {
|
|
5
|
+
const context = {
|
|
6
|
+
path: 'email',
|
|
7
|
+
root: { email: 'invalid' },
|
|
8
|
+
value: 'invalid',
|
|
9
|
+
constraint: 'email',
|
|
10
|
+
options: {},
|
|
11
|
+
runNestedRules: () => [],
|
|
12
|
+
};
|
|
13
|
+
const violations = email('invalid', context);
|
|
14
|
+
expect(violations).toHaveLength(1);
|
|
15
|
+
expect(violations[0]).toEqual({
|
|
16
|
+
path: 'email',
|
|
17
|
+
constraint: 'email',
|
|
18
|
+
message: 'This value is not a valid email address.',
|
|
19
|
+
value: 'invalid',
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
it('accepts valid email by default', () => {
|
|
23
|
+
const context = {
|
|
24
|
+
path: 'email',
|
|
25
|
+
root: { email: 'user@example.com' },
|
|
26
|
+
value: 'user@example.com',
|
|
27
|
+
constraint: 'email',
|
|
28
|
+
options: {},
|
|
29
|
+
runNestedRules: () => [],
|
|
30
|
+
};
|
|
31
|
+
const violations = email('user@example.com', context);
|
|
32
|
+
expect(violations).toHaveLength(0);
|
|
33
|
+
});
|
|
34
|
+
it('rejects localhost domains by default', () => {
|
|
35
|
+
const context = {
|
|
36
|
+
path: 'email',
|
|
37
|
+
root: { email: 'user@localhost' },
|
|
38
|
+
value: 'user@localhost',
|
|
39
|
+
constraint: 'email',
|
|
40
|
+
options: {},
|
|
41
|
+
runNestedRules: () => [],
|
|
42
|
+
};
|
|
43
|
+
const violations = email('user@localhost', context);
|
|
44
|
+
expect(violations).toHaveLength(1);
|
|
45
|
+
expect(violations[0]).toEqual({
|
|
46
|
+
path: 'email',
|
|
47
|
+
constraint: 'email',
|
|
48
|
+
message: 'This value is not a valid email address.',
|
|
49
|
+
value: 'user@localhost',
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
it('normalizes values before validation', () => {
|
|
53
|
+
const context = {
|
|
54
|
+
path: 'email',
|
|
55
|
+
root: { email: ' USER@EXAMPLE.COM ' },
|
|
56
|
+
value: ' USER@EXAMPLE.COM ',
|
|
57
|
+
constraint: 'email',
|
|
58
|
+
options: { normalizer: (value) => value.trim().toLowerCase() },
|
|
59
|
+
runNestedRules: () => [],
|
|
60
|
+
};
|
|
61
|
+
const violations = email(' USER@EXAMPLE.COM ', context);
|
|
62
|
+
expect(violations).toHaveLength(0);
|
|
63
|
+
});
|
|
64
|
+
it('uses a custom message when provided', () => {
|
|
65
|
+
const context = {
|
|
66
|
+
path: 'email',
|
|
67
|
+
root: { email: 'invalid' },
|
|
68
|
+
value: 'invalid',
|
|
69
|
+
constraint: 'email',
|
|
70
|
+
options: { message: 'Invalid email' },
|
|
71
|
+
runNestedRules: () => [],
|
|
72
|
+
};
|
|
73
|
+
const violations = email('invalid', context);
|
|
74
|
+
expect(violations).toHaveLength(1);
|
|
75
|
+
expect(violations[0]).toEqual({
|
|
76
|
+
path: 'email',
|
|
77
|
+
constraint: 'email',
|
|
78
|
+
message: 'Invalid email',
|
|
79
|
+
value: 'invalid',
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
it('rejects non-string values with the default message', () => {
|
|
83
|
+
const context = {
|
|
84
|
+
path: 'email',
|
|
85
|
+
root: { email: 42 },
|
|
86
|
+
value: 42,
|
|
87
|
+
constraint: 'email',
|
|
88
|
+
options: {},
|
|
89
|
+
runNestedRules: () => [],
|
|
90
|
+
};
|
|
91
|
+
const violations = email(42, context);
|
|
92
|
+
expect(violations).toHaveLength(1);
|
|
93
|
+
expect(violations[0]).toEqual({
|
|
94
|
+
path: 'email',
|
|
95
|
+
constraint: 'email',
|
|
96
|
+
message: 'This value is not a valid email address.',
|
|
97
|
+
value: 42,
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
it('uses a custom message for non-string values', () => {
|
|
101
|
+
const context = {
|
|
102
|
+
path: 'email',
|
|
103
|
+
root: { email: 42 },
|
|
104
|
+
value: 42,
|
|
105
|
+
constraint: 'email',
|
|
106
|
+
options: { message: 'Invalid email' },
|
|
107
|
+
runNestedRules: () => [],
|
|
108
|
+
};
|
|
109
|
+
const violations = email(42, context);
|
|
110
|
+
expect(violations).toHaveLength(1);
|
|
111
|
+
expect(violations[0]).toEqual({
|
|
112
|
+
path: 'email',
|
|
113
|
+
constraint: 'email',
|
|
114
|
+
message: 'Invalid email',
|
|
115
|
+
value: 42,
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
//# sourceMappingURL=email.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email.test.js","sourceRoot":"","sources":["../../../../src/validator/constraints/string/email.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/validator/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;CAI9C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/validator/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC/C,YAAY,KAAa,EAAE,UAAkB;QAC3C,KAAK,CAAC,UAAU,KAAK,yCAAyC,UAAU,IAAI,CAAC,CAAC;QAC9E,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/validator/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/validator/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type Violation = {
|
|
2
|
+
path: string;
|
|
3
|
+
message: string;
|
|
4
|
+
constraint: string;
|
|
5
|
+
value: unknown;
|
|
6
|
+
};
|
|
7
|
+
export type ConstraintOptions = {
|
|
8
|
+
groups?: string[];
|
|
9
|
+
} & Record<string, unknown>;
|
|
10
|
+
export type ConstraintContext = {
|
|
11
|
+
path: string;
|
|
12
|
+
root: unknown;
|
|
13
|
+
value: unknown;
|
|
14
|
+
constraint: string;
|
|
15
|
+
options: ConstraintOptions;
|
|
16
|
+
runNestedRules: (value: unknown, rules: FieldRules, path: string) => Violation[];
|
|
17
|
+
};
|
|
18
|
+
export type ConstraintValidator = (value: unknown, context: ConstraintContext) => Violation[];
|
|
19
|
+
export type ConstraintsMap = Record<string, ConstraintValidator>;
|
|
20
|
+
export type FieldRuleEntry = string | Record<string, ConstraintOptions>;
|
|
21
|
+
export type FieldRules = Record<string, ConstraintOptions> | FieldRuleEntry[];
|
|
22
|
+
export type ValidationRules = Record<string, FieldRules>;
|
|
23
|
+
export type ValidatorOptions = {
|
|
24
|
+
constraints: ConstraintsMap;
|
|
25
|
+
};
|
|
26
|
+
export type ValidateOptions = {
|
|
27
|
+
groups?: string[];
|
|
28
|
+
};
|
|
29
|
+
export type Payload = Record<string, unknown>;
|
|
30
|
+
export type Validator = (payload: Payload, rules: ValidationRules, options?: ValidateOptions) => Violation[];
|
|
31
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/validator/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAChF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,cAAc,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;CAClF,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,KAAK,SAAS,EAAE,CAAC;AAE9F,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;AAEjE,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;AAExE,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,cAAc,EAAE,CAAC;AAE9E,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAEzD,MAAM,MAAM,gBAAgB,GAAG;IAAE,WAAW,EAAE,cAAc,CAAA;CAAE,CAAC;AAE/D,MAAM,MAAM,eAAe,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEpD,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE9C,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,eAAe,KAAK,SAAS,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/validator/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/validator/validator.ts"],"names":[],"mappings":"AACA,OAAO,EAUL,SAAS,EACT,gBAAgB,EACjB,MAAM,SAAS,CAAC;AAIjB,eAAO,MAAM,eAAe,GAAI,SAAS,gBAAgB,KAAG,SAc3D,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { UnknownConstraintError } from './errors.js';
|
|
2
|
+
export const createValidator = (options) => {
|
|
3
|
+
const { constraints } = options;
|
|
4
|
+
return function validate(payload, rules, options) {
|
|
5
|
+
const ruleEntries = Object.entries(rules);
|
|
6
|
+
// If no groups are provided, implicitly validate against "Default".
|
|
7
|
+
const activeGroups = options?.groups && options.groups.length > 0 ? options.groups : ['Default'];
|
|
8
|
+
// Apply all field rules and aggregate results.
|
|
9
|
+
return ruleEntries.flatMap(function (fieldEntry) {
|
|
10
|
+
return applyFieldRules(constraints, payload, fieldEntry, activeGroups);
|
|
11
|
+
});
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
function applyFieldRules(constraintsByName, payload, [field, rulesForField], activeGroups, currentValue) {
|
|
15
|
+
const isGroupActive = (groups) => groups.length === 0 || groups.some(group => activeGroups.includes(group));
|
|
16
|
+
const normalizedFieldRules = normalizeFieldRules(rulesForField);
|
|
17
|
+
return normalizedFieldRules.flatMap(([constraintName, options]) => {
|
|
18
|
+
// Check if the constraint should be applied based on groups.
|
|
19
|
+
const groups = options?.groups ?? [];
|
|
20
|
+
if (!isGroupActive(groups))
|
|
21
|
+
return [];
|
|
22
|
+
// Helper function to apply nested rules.
|
|
23
|
+
const applyNestedRules = (nextValue, rules, path) => applyFieldRules(constraintsByName, payload, [path, rules], activeGroups, nextValue);
|
|
24
|
+
// Find the constraint, build the context, and apply it.
|
|
25
|
+
const constraintValidator = resolveConstraint(constraintsByName, field, constraintName);
|
|
26
|
+
const value = currentValue ?? payload[field];
|
|
27
|
+
const context = {
|
|
28
|
+
path: field,
|
|
29
|
+
root: payload,
|
|
30
|
+
value,
|
|
31
|
+
constraint: constraintName,
|
|
32
|
+
options,
|
|
33
|
+
runNestedRules: applyNestedRules,
|
|
34
|
+
};
|
|
35
|
+
return constraintValidator(value, context);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function resolveConstraint(constraintValidatorMap, field, constraintName) {
|
|
39
|
+
const constraintValidator = constraintValidatorMap[constraintName];
|
|
40
|
+
if (!constraintValidator) {
|
|
41
|
+
throw new UnknownConstraintError(field, constraintName);
|
|
42
|
+
}
|
|
43
|
+
return constraintValidator;
|
|
44
|
+
}
|
|
45
|
+
function normalizeFieldRules(fieldRules) {
|
|
46
|
+
// Normalize rule shapes (array or map) into a consistent tuple list.
|
|
47
|
+
if (Array.isArray(fieldRules)) {
|
|
48
|
+
return fieldRules.flatMap(entry => normalizeFieldRuleEntry(entry));
|
|
49
|
+
}
|
|
50
|
+
return Object.entries(fieldRules).map(([constraintName, options]) => [constraintName, options]);
|
|
51
|
+
}
|
|
52
|
+
function normalizeFieldRuleEntry(entry) {
|
|
53
|
+
// Convert shorthand rule declarations into a full [name, options] tuple.
|
|
54
|
+
if (typeof entry === 'string') {
|
|
55
|
+
return [[entry, {}]];
|
|
56
|
+
}
|
|
57
|
+
return Object.entries(entry).map(([constraintName, options]) => [constraintName, options]);
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/validator/validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.test.d.ts","sourceRoot":"","sources":["../../src/validator/validator.test.ts"],"names":[],"mappings":""}
|