@vytches/ddd-validation 0.26.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/LICENSE +21 -0
- package/LLMGUIDE.md +207 -0
- package/README.md +1562 -0
- package/dist/adapters/base-adapter.d.ts +54 -0
- package/dist/adapters/index.d.ts +2 -0
- package/dist/business-rules/business-rule-validator-extension.d.ts +29 -0
- package/dist/business-rules/business-rule-validator.d.ts +51 -0
- package/dist/business-rules/index.d.ts +2 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +803 -0
- package/dist/rules-registry.d.ts +69 -0
- package/dist/specifications/async-composite-specification.d.ts +72 -0
- package/dist/specifications/composite-specification.d.ts +25 -0
- package/dist/specifications/index.d.ts +5 -0
- package/dist/specifications/memoized-specification.d.ts +84 -0
- package/dist/specifications/specification-operators.d.ts +70 -0
- package/dist/specifications/specification-validator.d.ts +26 -0
- package/dist/validation-error.d.ts +13 -0
- package/dist/validation-facade.d.ts +51 -0
- package/package.json +69 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,803 @@
|
|
|
1
|
+
import { Result as o } from "@vytches/ddd-utils";
|
|
2
|
+
class u {
|
|
3
|
+
and(t) {
|
|
4
|
+
return new x(this, t);
|
|
5
|
+
}
|
|
6
|
+
or(t) {
|
|
7
|
+
return new A(this, t);
|
|
8
|
+
}
|
|
9
|
+
not() {
|
|
10
|
+
return new B(this);
|
|
11
|
+
}
|
|
12
|
+
static create(t) {
|
|
13
|
+
return new F(t);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
let F = class extends u {
|
|
17
|
+
constructor(t) {
|
|
18
|
+
super(), this.predicate = t;
|
|
19
|
+
}
|
|
20
|
+
isSatisfiedBy(t) {
|
|
21
|
+
return this.predicate(t);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
class x extends u {
|
|
25
|
+
constructor(t, e) {
|
|
26
|
+
super(), this.left = t, this.right = e;
|
|
27
|
+
}
|
|
28
|
+
isSatisfiedBy(t) {
|
|
29
|
+
return this.left.isSatisfiedBy(t) && this.right.isSatisfiedBy(t);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
class A extends u {
|
|
33
|
+
constructor(t, e) {
|
|
34
|
+
super(), this.left = t, this.right = e;
|
|
35
|
+
}
|
|
36
|
+
isSatisfiedBy(t) {
|
|
37
|
+
return this.left.isSatisfiedBy(t) || this.right.isSatisfiedBy(t);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
class B extends u {
|
|
41
|
+
constructor(t) {
|
|
42
|
+
super(), this.spec = t;
|
|
43
|
+
}
|
|
44
|
+
isSatisfiedBy(t) {
|
|
45
|
+
return !this.spec.isSatisfiedBy(t);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
class w {
|
|
49
|
+
/**
|
|
50
|
+
* Combine with another async specification using AND logic
|
|
51
|
+
*/
|
|
52
|
+
and(t) {
|
|
53
|
+
return new R(this, t);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Combine with another async specification using OR logic
|
|
57
|
+
*/
|
|
58
|
+
or(t) {
|
|
59
|
+
return new $(this, t);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Negate this async specification
|
|
63
|
+
*/
|
|
64
|
+
not() {
|
|
65
|
+
return new C(this);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Create a specification from an async predicate function
|
|
69
|
+
*/
|
|
70
|
+
static create(t, e, i) {
|
|
71
|
+
return new E(t, e, i);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Optional method to explain why specification failed
|
|
75
|
+
*/
|
|
76
|
+
async explainFailureAsync(t, e) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
class E extends w {
|
|
81
|
+
constructor(t, e, i) {
|
|
82
|
+
super(), this.predicate = t, this.name = e, this.description = i;
|
|
83
|
+
}
|
|
84
|
+
async isSatisfiedByAsync(t, e) {
|
|
85
|
+
return this.predicate(t, e);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
class R extends w {
|
|
89
|
+
constructor(t, e) {
|
|
90
|
+
super(), this.left = t, this.right = e, this.name = `(${this.left.name || "spec"} AND ${this.right.name || "spec"})`, this.description = "Both specifications must be satisfied";
|
|
91
|
+
}
|
|
92
|
+
async isSatisfiedByAsync(t, e) {
|
|
93
|
+
const [i, s] = await Promise.all([
|
|
94
|
+
this.left.isSatisfiedByAsync(t, e),
|
|
95
|
+
this.right.isSatisfiedByAsync(t, e)
|
|
96
|
+
]);
|
|
97
|
+
return i && s;
|
|
98
|
+
}
|
|
99
|
+
async explainFailureAsync(t, e) {
|
|
100
|
+
const [i, s] = await Promise.all([
|
|
101
|
+
this.left.isSatisfiedByAsync(t, e),
|
|
102
|
+
this.right.isSatisfiedByAsync(t, e)
|
|
103
|
+
]), n = [];
|
|
104
|
+
if (!i && this.left.explainFailureAsync) {
|
|
105
|
+
const a = await this.left.explainFailureAsync(t, e);
|
|
106
|
+
a && n.push(a);
|
|
107
|
+
}
|
|
108
|
+
if (!s && this.right.explainFailureAsync) {
|
|
109
|
+
const a = await this.right.explainFailureAsync(t, e);
|
|
110
|
+
a && n.push(a);
|
|
111
|
+
}
|
|
112
|
+
return n.length > 0 ? n.join(" AND ") : null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
class $ extends w {
|
|
116
|
+
constructor(t, e) {
|
|
117
|
+
super(), this.left = t, this.right = e, this.name = `(${this.left.name || "spec"} OR ${this.right.name || "spec"})`, this.description = "At least one specification must be satisfied";
|
|
118
|
+
}
|
|
119
|
+
async isSatisfiedByAsync(t, e) {
|
|
120
|
+
const [i, s] = await Promise.all([
|
|
121
|
+
this.left.isSatisfiedByAsync(t, e),
|
|
122
|
+
this.right.isSatisfiedByAsync(t, e)
|
|
123
|
+
]);
|
|
124
|
+
return i || s;
|
|
125
|
+
}
|
|
126
|
+
async explainFailureAsync(t, e) {
|
|
127
|
+
const [i, s] = await Promise.all([
|
|
128
|
+
this.left.isSatisfiedByAsync(t, e),
|
|
129
|
+
this.right.isSatisfiedByAsync(t, e)
|
|
130
|
+
]);
|
|
131
|
+
if (!i && !s) {
|
|
132
|
+
const n = [];
|
|
133
|
+
if (this.left.explainFailureAsync) {
|
|
134
|
+
const a = await this.left.explainFailureAsync(t, e);
|
|
135
|
+
a && n.push(a);
|
|
136
|
+
}
|
|
137
|
+
if (this.right.explainFailureAsync) {
|
|
138
|
+
const a = await this.right.explainFailureAsync(t, e);
|
|
139
|
+
a && n.push(a);
|
|
140
|
+
}
|
|
141
|
+
return n.length > 0 ? `(${n.join(" OR ")})` : null;
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
class C extends w {
|
|
147
|
+
constructor(t) {
|
|
148
|
+
super(), this.spec = t, this.name = `NOT(${this.spec.name || "spec"})`, this.description = "The specification must NOT be satisfied";
|
|
149
|
+
}
|
|
150
|
+
async isSatisfiedByAsync(t, e) {
|
|
151
|
+
return !await this.spec.isSatisfiedByAsync(t, e);
|
|
152
|
+
}
|
|
153
|
+
async explainFailureAsync(t, e) {
|
|
154
|
+
return await this.spec.isSatisfiedByAsync(t, e) ? `Expected specification to fail: ${this.spec.name || "specification"}` : null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
class T extends u {
|
|
158
|
+
constructor(t) {
|
|
159
|
+
super(), this.inner = t, this.cache = /* @__PURE__ */ new WeakMap();
|
|
160
|
+
}
|
|
161
|
+
isSatisfiedBy(t) {
|
|
162
|
+
if (t === null || typeof t != "object" && typeof t != "function")
|
|
163
|
+
return this.inner.isSatisfiedBy(t);
|
|
164
|
+
const e = this.cache.get(t);
|
|
165
|
+
if (e !== void 0) return e;
|
|
166
|
+
const i = this.inner.isSatisfiedBy(t);
|
|
167
|
+
return this.cache.set(t, i), i;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Manually evict a candidate from the cache. Use when you know the
|
|
171
|
+
* candidate's relevant fields have changed and you want fresh evaluation
|
|
172
|
+
* without discarding cache entries for other candidates.
|
|
173
|
+
*/
|
|
174
|
+
invalidate(t) {
|
|
175
|
+
this.cache.delete(t);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Forwarded to the inner spec, if it implements optional `explainFailure`.
|
|
179
|
+
* Skips the cache because failure explanations are typically only computed
|
|
180
|
+
* on-demand.
|
|
181
|
+
*/
|
|
182
|
+
explainFailure(t) {
|
|
183
|
+
const e = this.inner;
|
|
184
|
+
return e.explainFailure ? e.explainFailure(t) ?? null : null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
class m extends u {
|
|
188
|
+
isSatisfiedBy(t) {
|
|
189
|
+
return !0;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
class g extends u {
|
|
193
|
+
isSatisfiedBy(t) {
|
|
194
|
+
return !1;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
class P extends u {
|
|
198
|
+
constructor(t) {
|
|
199
|
+
super(), this.predicate = t;
|
|
200
|
+
}
|
|
201
|
+
isSatisfiedBy(t) {
|
|
202
|
+
return this.predicate(t);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
class N extends u {
|
|
206
|
+
constructor(t, e) {
|
|
207
|
+
super(), this.propertyName = t, this.expectedValue = e;
|
|
208
|
+
}
|
|
209
|
+
isSatisfiedBy(t) {
|
|
210
|
+
return t[this.propertyName] === this.expectedValue;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
class V extends u {
|
|
214
|
+
constructor(t, e) {
|
|
215
|
+
super(), this.propertyName = t, this.possibleValues = e;
|
|
216
|
+
}
|
|
217
|
+
isSatisfiedBy(t) {
|
|
218
|
+
return this.possibleValues.includes(t[this.propertyName]);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
class b extends u {
|
|
222
|
+
constructor(t, e, i) {
|
|
223
|
+
super(), this.propertyName = t, this.min = e, this.max = i;
|
|
224
|
+
}
|
|
225
|
+
isSatisfiedBy(t) {
|
|
226
|
+
const e = t[this.propertyName];
|
|
227
|
+
return e >= this.min && e <= this.max;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const j = {
|
|
231
|
+
/**
|
|
232
|
+
* Tworzy specyfikację zawsze prawdziwą
|
|
233
|
+
*/
|
|
234
|
+
alwaysTrue() {
|
|
235
|
+
return new m();
|
|
236
|
+
},
|
|
237
|
+
/**
|
|
238
|
+
* Tworzy specyfikację zawsze fałszywą
|
|
239
|
+
*/
|
|
240
|
+
alwaysFalse() {
|
|
241
|
+
return new g();
|
|
242
|
+
},
|
|
243
|
+
/**
|
|
244
|
+
* Tworzy specyfikację opartą o predykat
|
|
245
|
+
*/
|
|
246
|
+
create(r) {
|
|
247
|
+
return new P(r);
|
|
248
|
+
},
|
|
249
|
+
/**
|
|
250
|
+
* Tworzy specyfikację sprawdzającą równość właściwości
|
|
251
|
+
*/
|
|
252
|
+
propertyEquals(r, t) {
|
|
253
|
+
return new N(r, t);
|
|
254
|
+
},
|
|
255
|
+
/**
|
|
256
|
+
* Tworzy specyfikację sprawdzającą zawieranie się właściwości w zbiorze
|
|
257
|
+
*/
|
|
258
|
+
propertyIn(r, t) {
|
|
259
|
+
return new V(r, t);
|
|
260
|
+
},
|
|
261
|
+
/**
|
|
262
|
+
* Tworzy specyfikację sprawdzającą zakres wartości
|
|
263
|
+
*/
|
|
264
|
+
propertyBetween(r, t, e) {
|
|
265
|
+
return new b(r, t, e);
|
|
266
|
+
},
|
|
267
|
+
/**
|
|
268
|
+
* Łączy specyfikacje operatorem AND
|
|
269
|
+
*/
|
|
270
|
+
and(...r) {
|
|
271
|
+
if (r.length === 0) return new m();
|
|
272
|
+
let t = r[0];
|
|
273
|
+
for (let e = 1; e < r.length; e++)
|
|
274
|
+
t = new x(t, r[e]);
|
|
275
|
+
return t;
|
|
276
|
+
},
|
|
277
|
+
/**
|
|
278
|
+
* Łączy specyfikacje operatorem OR
|
|
279
|
+
*/
|
|
280
|
+
or(...r) {
|
|
281
|
+
if (r.length === 0) return new g();
|
|
282
|
+
let t = r[0];
|
|
283
|
+
for (let e = 1; e < r.length; e++)
|
|
284
|
+
t = new A(t, r[e]);
|
|
285
|
+
return t;
|
|
286
|
+
},
|
|
287
|
+
/**
|
|
288
|
+
* Neguje specyfikację
|
|
289
|
+
*/
|
|
290
|
+
not(r) {
|
|
291
|
+
return new B(r);
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
class h {
|
|
295
|
+
constructor(t, e, i) {
|
|
296
|
+
this.property = t, this.message = e, this.context = i;
|
|
297
|
+
}
|
|
298
|
+
toString() {
|
|
299
|
+
return `${this.property}: ${this.message}`;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
class d extends Error {
|
|
303
|
+
constructor(t) {
|
|
304
|
+
super(
|
|
305
|
+
`Validation failed with ${t.length} error(s): ${t.map((e) => e.toString()).join("; ")}`
|
|
306
|
+
), this.name = "ValidationErrors", this.errors = t;
|
|
307
|
+
}
|
|
308
|
+
get length() {
|
|
309
|
+
return this.errors.length;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
class p {
|
|
313
|
+
constructor() {
|
|
314
|
+
this.validationRules = [];
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Adds a validation rule based on a specification
|
|
318
|
+
*/
|
|
319
|
+
addRule(t, e, i, s) {
|
|
320
|
+
const n = {
|
|
321
|
+
specification: t,
|
|
322
|
+
message: e,
|
|
323
|
+
property: i || ""
|
|
324
|
+
};
|
|
325
|
+
return s !== void 0 && (n.context = s), this.validationRules.push(n), this;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Adds a rule for a specific object property
|
|
329
|
+
*/
|
|
330
|
+
addPropertyRule(t, e, i, s, n) {
|
|
331
|
+
const a = {
|
|
332
|
+
isSatisfiedBy: (c) => e.isSatisfiedBy(s(c)),
|
|
333
|
+
// The following methods are not used in this context but must be implemented
|
|
334
|
+
and: () => {
|
|
335
|
+
throw new Error("Operation not supported");
|
|
336
|
+
},
|
|
337
|
+
or: () => {
|
|
338
|
+
throw new Error("Operation not supported");
|
|
339
|
+
},
|
|
340
|
+
not: () => {
|
|
341
|
+
throw new Error("Operation not supported");
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
return this.addRule(a, i, t, n);
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Performs validation based on all specifications
|
|
348
|
+
*/
|
|
349
|
+
validate(t) {
|
|
350
|
+
const e = [];
|
|
351
|
+
for (const i of this.validationRules)
|
|
352
|
+
i.specification.isSatisfiedBy(t) || e.push(new h(i.property || "", i.message, i.context));
|
|
353
|
+
return e.length > 0 ? o.fail(new d(e)) : o.ok(t);
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Creates a validator with a single rule
|
|
357
|
+
*/
|
|
358
|
+
static fromSpecification(t, e, i, s) {
|
|
359
|
+
return new p().addRule(t, e, i, s);
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Creates an empty validator
|
|
363
|
+
*/
|
|
364
|
+
static create() {
|
|
365
|
+
return new p();
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
class f {
|
|
369
|
+
constructor() {
|
|
370
|
+
this.rules = [], this.stopOnFirstFailure = !1, this.lastCondition = null;
|
|
371
|
+
}
|
|
372
|
+
addRule(t, e, i, s) {
|
|
373
|
+
return this.rules.push({
|
|
374
|
+
property: t,
|
|
375
|
+
validate: (n) => e(n) ? o.ok(!0) : o.fail(new h(t, i, s))
|
|
376
|
+
}), this;
|
|
377
|
+
}
|
|
378
|
+
addSpecification(t, e, i, s) {
|
|
379
|
+
return this.addRule(t, (n) => e.isSatisfiedBy(n), i, s);
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Dodaje globalną specyfikację, która dotyczy całego obiektu
|
|
383
|
+
*/
|
|
384
|
+
mustSatisfy(t, e, i) {
|
|
385
|
+
return this.addSpecification("", t, e, i);
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Dodaje walidację dla konkretnej właściwości z użyciem specyfikacji
|
|
389
|
+
*/
|
|
390
|
+
propertyMustSatisfy(t, e, i, s, n) {
|
|
391
|
+
return this.addRule(
|
|
392
|
+
t,
|
|
393
|
+
(a) => e.isSatisfiedBy(s(a)),
|
|
394
|
+
i,
|
|
395
|
+
n
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Dodaje walidację dla zagnieżdżonego obiektu
|
|
400
|
+
*/
|
|
401
|
+
addNested(t, e, i) {
|
|
402
|
+
return this.rules.push({
|
|
403
|
+
property: t,
|
|
404
|
+
validate: (s) => {
|
|
405
|
+
const n = i(s);
|
|
406
|
+
if (n == null)
|
|
407
|
+
return o.fail(
|
|
408
|
+
new h(t, "Cannot validate undefined or null nested object", {
|
|
409
|
+
path: t
|
|
410
|
+
})
|
|
411
|
+
);
|
|
412
|
+
const a = e.validate(n);
|
|
413
|
+
if (a.isFailure) {
|
|
414
|
+
const c = a.error.errors.map((l) => {
|
|
415
|
+
const S = {
|
|
416
|
+
...l.context || {},
|
|
417
|
+
path: t + (l.property ? `.${l.property}` : ""),
|
|
418
|
+
originalPath: l.property || "",
|
|
419
|
+
parentPath: t
|
|
420
|
+
};
|
|
421
|
+
return new h(
|
|
422
|
+
`${t}${l.property ? `.${l.property}` : ""}`,
|
|
423
|
+
l.message,
|
|
424
|
+
S
|
|
425
|
+
);
|
|
426
|
+
});
|
|
427
|
+
return o.fail(
|
|
428
|
+
new h(t, "Nested validation failed", {
|
|
429
|
+
errors: c,
|
|
430
|
+
path: t,
|
|
431
|
+
errorCount: c.length
|
|
432
|
+
})
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
return o.ok(!0);
|
|
436
|
+
}
|
|
437
|
+
}), this;
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Dodaje walidację warunkową
|
|
441
|
+
*/
|
|
442
|
+
when(t, e) {
|
|
443
|
+
if (typeof t != "function")
|
|
444
|
+
throw new Error("Condition must be a function");
|
|
445
|
+
this.lastCondition = t;
|
|
446
|
+
const i = new f();
|
|
447
|
+
e(i);
|
|
448
|
+
for (const s of i.rules)
|
|
449
|
+
this.rules.push({
|
|
450
|
+
...s,
|
|
451
|
+
condition: t
|
|
452
|
+
});
|
|
453
|
+
return this;
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Dodaje walidację warunkową
|
|
457
|
+
*/
|
|
458
|
+
otherwise(t) {
|
|
459
|
+
if (this.lastCondition === null || this.lastCondition === void 0)
|
|
460
|
+
throw new Error(
|
|
461
|
+
"Cannot call otherwise() without a preceding when() - lastCondition is null/undefined"
|
|
462
|
+
);
|
|
463
|
+
if (typeof this.lastCondition != "function")
|
|
464
|
+
throw new Error(
|
|
465
|
+
`Cannot call otherwise() - lastCondition is not a function but a ${typeof this.lastCondition}`
|
|
466
|
+
);
|
|
467
|
+
const e = this.lastCondition, i = (n) => !e(n), s = new f();
|
|
468
|
+
t(s);
|
|
469
|
+
for (const n of s.rules)
|
|
470
|
+
this.rules.push({
|
|
471
|
+
...n,
|
|
472
|
+
condition: i
|
|
473
|
+
});
|
|
474
|
+
return this.lastCondition = null, this;
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Dodaje walidację warunkową opartą na specyfikacji
|
|
478
|
+
*/
|
|
479
|
+
whenSatisfies(t, e) {
|
|
480
|
+
return this.when((i) => t.isSatisfiedBy(i), e);
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Konfiguruje walidator do zatrzymania po pierwszym błędzie
|
|
484
|
+
*/
|
|
485
|
+
setStopOnFirstFailure() {
|
|
486
|
+
return this.stopOnFirstFailure = !0, this;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Przeprowadza walidację
|
|
490
|
+
*/
|
|
491
|
+
validate(t) {
|
|
492
|
+
const e = [];
|
|
493
|
+
for (const i of this.rules) {
|
|
494
|
+
if (i.condition && !i.condition(t))
|
|
495
|
+
continue;
|
|
496
|
+
const s = i.validate(t);
|
|
497
|
+
if (s.isFailure && (e.push(s.error), this.stopOnFirstFailure))
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
500
|
+
return e.length > 0 ? o.fail(new d(e)) : o.ok(t);
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Łączy ten walidator z innym
|
|
504
|
+
*/
|
|
505
|
+
and(t) {
|
|
506
|
+
const e = new f();
|
|
507
|
+
return e.rules = [...this.rules], e.addRule("", (i) => t.validate(i).isSuccess, "Failed combined validation"), e;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Tworzy nowy walidator ze specyfikacji
|
|
511
|
+
*/
|
|
512
|
+
static fromSpecification(t, e, i) {
|
|
513
|
+
return new f().mustSatisfy(t, e, i);
|
|
514
|
+
}
|
|
515
|
+
static create() {
|
|
516
|
+
return new f();
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
const q = {
|
|
520
|
+
/**
|
|
521
|
+
* Tworzy nowy walidator reguł biznesowych
|
|
522
|
+
*/
|
|
523
|
+
create() {
|
|
524
|
+
return f.create();
|
|
525
|
+
},
|
|
526
|
+
/**
|
|
527
|
+
* Tworzy walidator oparty na specyfikacji
|
|
528
|
+
*/
|
|
529
|
+
fromSpecification(r, t, e) {
|
|
530
|
+
return p.fromSpecification(r, t, e);
|
|
531
|
+
},
|
|
532
|
+
/**
|
|
533
|
+
* Tworzy walidator łączący wiele walidatorów
|
|
534
|
+
*/
|
|
535
|
+
combine(...r) {
|
|
536
|
+
return {
|
|
537
|
+
validate: (t) => {
|
|
538
|
+
const e = [];
|
|
539
|
+
for (const i of r) {
|
|
540
|
+
const s = i.validate(t);
|
|
541
|
+
s.isFailure && e.push(s.error);
|
|
542
|
+
}
|
|
543
|
+
if (e.length > 0) {
|
|
544
|
+
const i = e.flatMap((s) => s.errors);
|
|
545
|
+
return o.fail(new d(i));
|
|
546
|
+
}
|
|
547
|
+
return o.ok(t);
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
},
|
|
551
|
+
/**
|
|
552
|
+
* Waliduje obiekt bezpośrednio za pomocą specyfikacji
|
|
553
|
+
*/
|
|
554
|
+
validateWithSpecification(r, t, e) {
|
|
555
|
+
return this.fromSpecification(t, e).validate(r);
|
|
556
|
+
},
|
|
557
|
+
/**
|
|
558
|
+
* Waliduje za pomocą wielu specyfikacji z własnymi komunikatami błędów
|
|
559
|
+
*/
|
|
560
|
+
validateWithRules(r, t) {
|
|
561
|
+
const e = p.create();
|
|
562
|
+
for (const i of t)
|
|
563
|
+
e.addRule(i.specification, i.message, i.property);
|
|
564
|
+
return e.validate(r);
|
|
565
|
+
},
|
|
566
|
+
// Narzędzia konwersji
|
|
567
|
+
/**
|
|
568
|
+
* Konwertuje specyfikację na walidator
|
|
569
|
+
*/
|
|
570
|
+
specificationToValidator(r, t, e) {
|
|
571
|
+
return this.fromSpecification(r, t, e);
|
|
572
|
+
},
|
|
573
|
+
/**
|
|
574
|
+
* Konwertuje walidator na specyfikację
|
|
575
|
+
*/
|
|
576
|
+
validatorToSpecification(r) {
|
|
577
|
+
return u.create((t) => r.validate(t).isSuccess);
|
|
578
|
+
},
|
|
579
|
+
/**
|
|
580
|
+
* Tworzy walidator dla głęboko zagnieżdżonej struktury obiektów
|
|
581
|
+
*/
|
|
582
|
+
forNestedPath(r, t) {
|
|
583
|
+
if (r.length === 0)
|
|
584
|
+
return t;
|
|
585
|
+
let e = t;
|
|
586
|
+
for (let i = r.length - 1; i >= 0; i--) {
|
|
587
|
+
const s = r[i], n = f.create();
|
|
588
|
+
n.addNested(s, e, (a) => a ? a[s] : void 0), e = n;
|
|
589
|
+
}
|
|
590
|
+
return e;
|
|
591
|
+
},
|
|
592
|
+
/**
|
|
593
|
+
* Waliduje głęboko zagnieżdżoną właściwość
|
|
594
|
+
*/
|
|
595
|
+
validatePath(r, t, e) {
|
|
596
|
+
const s = ((a, c) => {
|
|
597
|
+
let l = a;
|
|
598
|
+
for (const S of c) {
|
|
599
|
+
if (l == null)
|
|
600
|
+
return;
|
|
601
|
+
if (typeof l == "object" && l !== null)
|
|
602
|
+
l = l[S];
|
|
603
|
+
else
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
return l;
|
|
607
|
+
})(r, t);
|
|
608
|
+
if (s === void 0)
|
|
609
|
+
return o.fail(
|
|
610
|
+
new d([new h(t.join("."), "Path does not exist", { path: t })])
|
|
611
|
+
);
|
|
612
|
+
const n = e.validate(s);
|
|
613
|
+
if (n.isFailure) {
|
|
614
|
+
const a = n.error.errors.map((c) => {
|
|
615
|
+
const l = [...t];
|
|
616
|
+
return c.property && l.push(c.property), new h(l.join("."), c.message, {
|
|
617
|
+
...c.context,
|
|
618
|
+
fullPath: l
|
|
619
|
+
});
|
|
620
|
+
});
|
|
621
|
+
return o.fail(new d(a));
|
|
622
|
+
}
|
|
623
|
+
return o.ok(r);
|
|
624
|
+
},
|
|
625
|
+
/**
|
|
626
|
+
* Używa zewnętrznego walidatora implementującego IValidator<T>
|
|
627
|
+
* Pozwala na integrację z bibliotekami takimi jak zod, class-validator, itp.
|
|
628
|
+
*/
|
|
629
|
+
useExternal(r) {
|
|
630
|
+
return r;
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
class O {
|
|
634
|
+
constructor() {
|
|
635
|
+
this.name = "core", this.required = (t, e = "Field is required") => (i) => i.addRule(
|
|
636
|
+
t,
|
|
637
|
+
(s) => s[t] !== void 0 && s[t] !== null,
|
|
638
|
+
e
|
|
639
|
+
), this.minLength = (t, e, i) => (s) => s.addRule(
|
|
640
|
+
t,
|
|
641
|
+
(n) => String(n[t]).length >= e,
|
|
642
|
+
i || `Minimum length is ${e}`
|
|
643
|
+
), this.maxLength = (t, e, i) => (s) => s.addRule(
|
|
644
|
+
t,
|
|
645
|
+
(n) => String(n[t]).length <= e,
|
|
646
|
+
i || `Maximum length is ${e}`
|
|
647
|
+
), this.pattern = (t, e, i = "Invalid format") => (s) => s.addRule(t, (n) => e.test(String(n[t])), i), this.range = (t, e, i, s) => (n) => n.addRule(
|
|
648
|
+
t,
|
|
649
|
+
(a) => {
|
|
650
|
+
const c = Number(a[t]);
|
|
651
|
+
return !isNaN(c) && c >= e && c <= i;
|
|
652
|
+
},
|
|
653
|
+
s || `Value must be between ${e} and ${i}`
|
|
654
|
+
), this.email = (t, e = "Invalid email address") => (i) => i.addRule(
|
|
655
|
+
t,
|
|
656
|
+
(s) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(s[t])),
|
|
657
|
+
e
|
|
658
|
+
), this.satisfies = (t, e) => (i) => i.mustSatisfy(t, e), this.propertySatisfies = (t, e, i, s) => (n) => n.propertyMustSatisfy(t, e, i, s), this.whenSatisfies = (t, e) => (i) => i.whenSatisfies(t, e), this.otherwise = (t) => (e) => e.otherwise(t), this.when = (t, e) => (i) => i.when(t, e);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
const y = class y {
|
|
662
|
+
/**
|
|
663
|
+
* Register a domain-specific rule provider
|
|
664
|
+
*/
|
|
665
|
+
static register(t) {
|
|
666
|
+
if (this.providers.has(t.name))
|
|
667
|
+
throw new Error(`Rule provider with name "${t.name}" is already registered`);
|
|
668
|
+
this.providers.set(t.name, t);
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Get a specific rule provider by name
|
|
672
|
+
*/
|
|
673
|
+
static getProvider(t) {
|
|
674
|
+
const e = this.providers.get(t);
|
|
675
|
+
if (!e)
|
|
676
|
+
throw new Error(`Rule provider "${t}" not found`);
|
|
677
|
+
return e;
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Get core rules
|
|
681
|
+
*/
|
|
682
|
+
static get Rules() {
|
|
683
|
+
return this.core;
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Access domain-specific rules
|
|
687
|
+
*/
|
|
688
|
+
static forDomain(t) {
|
|
689
|
+
return this.getProvider(t);
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
y.providers = /* @__PURE__ */ new Map(), y.core = new O();
|
|
693
|
+
let v = y;
|
|
694
|
+
class I {
|
|
695
|
+
constructor(t) {
|
|
696
|
+
this.schema = t;
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Helper method do tworzenia ValidationError z kontekstem
|
|
700
|
+
*/
|
|
701
|
+
createValidationError(t, e, i) {
|
|
702
|
+
return new h(t, e, i);
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Helper method do tworzenia ValidationErrors z tablicy błędów
|
|
706
|
+
*/
|
|
707
|
+
createValidationErrors(t) {
|
|
708
|
+
return new d(t);
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Helper method do konwersji ścieżki na string
|
|
712
|
+
*/
|
|
713
|
+
pathToString(t) {
|
|
714
|
+
return t.join(".");
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* Helper method do tworzenia Result.fail z błędami
|
|
718
|
+
*/
|
|
719
|
+
failWithErrors(t) {
|
|
720
|
+
return o.fail(this.createValidationErrors(t));
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Helper method do tworzenia Result.ok
|
|
724
|
+
*/
|
|
725
|
+
success(t) {
|
|
726
|
+
return o.ok(t);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
class W {
|
|
730
|
+
/**
|
|
731
|
+
* Tworzy prosty adapter z funkcji walidacyjnej
|
|
732
|
+
*/
|
|
733
|
+
static create(t, e = "") {
|
|
734
|
+
return {
|
|
735
|
+
validate: (i) => {
|
|
736
|
+
const s = t(i);
|
|
737
|
+
if (!s.success && s.errors) {
|
|
738
|
+
const n = s.errors.map(
|
|
739
|
+
(a) => new h(e, a)
|
|
740
|
+
);
|
|
741
|
+
return o.fail(new d(n));
|
|
742
|
+
}
|
|
743
|
+
return o.ok(i);
|
|
744
|
+
}
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Łączy wiele adapterów w jeden
|
|
749
|
+
*/
|
|
750
|
+
static combine(...t) {
|
|
751
|
+
return {
|
|
752
|
+
validate: (e) => {
|
|
753
|
+
const i = [];
|
|
754
|
+
for (const s of t) {
|
|
755
|
+
const n = s.validate(e);
|
|
756
|
+
n.isFailure && i.push(...n.error.errors);
|
|
757
|
+
}
|
|
758
|
+
return i.length > 0 ? o.fail(new d(i)) : o.ok(e);
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Tworzy adapter z custom error mapping
|
|
764
|
+
*/
|
|
765
|
+
static withErrorMapping(t, e) {
|
|
766
|
+
return {
|
|
767
|
+
validate: (i) => {
|
|
768
|
+
const s = t(i);
|
|
769
|
+
if (!s.success && s.errors) {
|
|
770
|
+
const n = s.errors.map(e);
|
|
771
|
+
return o.fail(new d(n));
|
|
772
|
+
}
|
|
773
|
+
return o.ok(i);
|
|
774
|
+
}
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
export {
|
|
779
|
+
W as AdapterUtils,
|
|
780
|
+
g as AlwaysFalseSpecification,
|
|
781
|
+
m as AlwaysTrueSpecification,
|
|
782
|
+
R as AndAsyncSpecification,
|
|
783
|
+
x as AndSpecification,
|
|
784
|
+
w as AsyncCompositeSpecification,
|
|
785
|
+
I as BaseValidationAdapter,
|
|
786
|
+
f as BusinessRuleValidator,
|
|
787
|
+
u as CompositeSpecification,
|
|
788
|
+
T as MemoizedSpecification,
|
|
789
|
+
C as NotAsyncSpecification,
|
|
790
|
+
B as NotSpecification,
|
|
791
|
+
$ as OrAsyncSpecification,
|
|
792
|
+
A as OrSpecification,
|
|
793
|
+
P as PredicateSpecification,
|
|
794
|
+
b as PropertyBetweenSpecification,
|
|
795
|
+
N as PropertyEqualsSpecification,
|
|
796
|
+
V as PropertyInSpecification,
|
|
797
|
+
v as RulesRegistry,
|
|
798
|
+
j as Specification,
|
|
799
|
+
p as SpecificationValidator,
|
|
800
|
+
h as ValidationError,
|
|
801
|
+
d as ValidationErrors,
|
|
802
|
+
q as ValidationFacade
|
|
803
|
+
};
|