@modulify/validator 0.2.1 → 0.3.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/CHANGELOG.md +27 -1
- package/README.md +12 -2
- package/dist/assert-BDOtHdLx.cjs +289 -0
- package/dist/assert-CzMg5aO7.mjs +206 -0
- package/dist/assert.cjs +7 -65
- package/dist/assert.d.cts +37 -0
- package/dist/assert.d.mts +37 -0
- package/dist/assert.d.ts +24 -3
- package/dist/assert.mjs +2 -66
- package/dist/assertions-DPYCHREw.mjs +297 -0
- package/dist/assertions-nfOKqcjs.cjs +476 -0
- package/dist/assertions.cjs +34 -206
- package/dist/assertions.d.cts +56 -0
- package/dist/assertions.d.mts +56 -0
- package/dist/assertions.d.ts +43 -45
- package/dist/assertions.mjs +3 -207
- package/dist/checkers.d.cts +8 -0
- package/dist/checkers.d.mts +8 -0
- package/dist/checkers.d.ts +1 -1
- package/dist/combinators.cjs +303 -304
- package/dist/combinators.d.cts +16 -0
- package/dist/combinators.d.mts +16 -0
- package/dist/combinators.d.ts +15 -16
- package/dist/combinators.mjs +304 -315
- package/dist/constraints.d.cts +4 -0
- package/dist/constraints.d.mts +4 -0
- package/dist/constraints.d.ts +2 -2
- package/dist/extractors.d.cts +2 -0
- package/dist/extractors.d.mts +2 -0
- package/dist/index.cjs +210 -213
- package/dist/index.d.cts +12 -0
- package/dist/index.d.mts +12 -0
- package/dist/index.d.ts +9 -9
- package/dist/index.mjs +165 -218
- package/dist/json-schema.cjs +364 -489
- package/dist/json-schema.d.cts +14 -0
- package/dist/json-schema.d.mts +14 -0
- package/dist/json-schema.d.ts +3 -3
- package/dist/json-schema.mjs +365 -492
- package/dist/metadata.cjs +6 -7
- package/dist/metadata.d.cts +8 -0
- package/dist/metadata.d.mts +8 -0
- package/dist/metadata.d.ts +2 -2
- package/dist/metadata.mjs +2 -8
- package/dist/predicates.cjs +98 -41
- package/dist/predicates.d.cts +77 -0
- package/dist/predicates.d.mts +77 -0
- package/dist/predicates.d.ts +25 -4
- package/dist/predicates.mjs +92 -66
- package/dist/types/index.d.cts +984 -0
- package/dist/types/index.d.mts +984 -0
- package/dist/types/index.d.ts +984 -0
- package/dist/types/json-schema.d.cts +75 -0
- package/dist/types/json-schema.d.mts +75 -0
- package/dist/types/json-schema.d.ts +75 -0
- package/dist/violations.d.cts +29 -0
- package/dist/violations.d.mts +29 -0
- package/dist/violations.d.ts +1 -1
- package/docs/RELEASING.md +66 -0
- package/docs/en/00-index.md +2 -0
- package/docs/en/01-shape-api.md +35 -10
- package/docs/en/02-metadata-and-introspection.md +2 -1
- package/docs/en/03-violations.md +1 -1
- package/docs/en/04-json-schema-export.md +5 -0
- package/docs/en/05-public-api.md +35 -3
- package/docs/en/06-common-recipes.md +2 -1
- package/docs/en/07-ai-reference.md +5 -2
- package/docs/en/08-violation-code-types.md +28 -2
- package/docs/en/09-migration.md +75 -0
- package/docs/ru/00-index.md +2 -0
- package/docs/ru/01-shape-api.md +35 -10
- package/docs/ru/02-metadata-and-introspection.md +2 -1
- package/docs/ru/03-violations.md +1 -1
- package/docs/ru/04-json-schema-export.md +5 -0
- package/docs/ru/05-public-api.md +35 -3
- package/docs/ru/06-common-recipes.md +2 -1
- package/docs/ru/07-ai-reference.md +5 -2
- package/docs/ru/08-violation-code-types.md +28 -2
- package/docs/ru/09-migration.md +76 -0
- package/docs/ru/README.md +10 -2
- package/package.json +63 -37
- package/types/index.d.ts +275 -115
- package/dist/metadata.cjs.js +0 -130
- package/dist/metadata.es.js +0 -131
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### ⚠ BREAKING CHANGE* **types:** Public type names were simplified
|
|
6
|
+
* **types:** Exported public type names were renamed without compatibility aliases.
|
|
7
|
+
* Object shape refinements were made async-first
|
|
8
|
+
* shape.refine(...) was changed to the async-first object-level API. Use shape.refine.sync(...) for explicitly sync-safe object rules.
|
|
9
|
+
* ObjectShapeRefinement now describes the async-first refinement contract. Use ObjectShapeRefinementSync for the explicit sync-only type name.
|
|
10
|
+
* validate.sync(...), matches.sync(...), and shape.check(...) now throw when they encounter async object-level shape refinements.
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* Object shape refinements were made async-first ([8877b93](https://github.com/modulify/validator/commit/8877b93fa4a8b7c29c918d5d9df08e90ae816379))
|
|
16
|
+
* Built-in value guards were expanded ([1846c17](https://github.com/modulify/validator/commit/1846c176188182b76074b46a60c12d3a2af790a0))
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* **predicates:** Shape field validation and inference were corrected ([b2c0e44](https://github.com/modulify/validator/commit/b2c0e441ecf923c0ed3e3a8cbe432a052fed42ce))
|
|
21
|
+
* **types:** Strict assertion contracts were aligned ([2bdd390](https://github.com/modulify/validator/commit/2bdd39019caff5522821ab3b07d832efdd4ca1ab))
|
|
22
|
+
* **build:** Packed ESM and CommonJS consumers were supported ([6fd0c3b](https://github.com/modulify/validator/commit/6fd0c3b2ad7adca314b321283245f831deb2e160))
|
|
23
|
+
|
|
24
|
+
### Performance Improvements
|
|
25
|
+
|
|
26
|
+
* **build:** Tree-shaking hints were added ([29bbc70](https://github.com/modulify/validator/commit/29bbc7017b58ef50927ccda745a7be76a8b73ba4))
|
|
27
|
+
|
|
28
|
+
All notable changes to this project will be documented in this file. Release notes are generated by [@modulify/conventional-release](https://github.com/modulify/conventional/tree/main/packages/conventional-release) from Conventional Commits.
|
|
4
29
|
|
|
5
30
|
### [0.2.1](https://github.com/modulify/validator/compare/v0.2.0...v0.2.1) (2026-03-09)
|
|
6
31
|
|
|
@@ -73,3 +98,4 @@ All notable changes to this project will be documented in this file. See [standa
|
|
|
73
98
|
* Added meta to OneOf violation ([8dd59fc](https://github.com/modulify/validator/commit/8dd59fc2663df1e791ad95449ba774374b6e0bf8))
|
|
74
99
|
* Added possibility to override initial valitators set ([0192f44](https://github.com/modulify/validator/commit/0192f44e4e9e487cbc1230cd588ea62d926e7143))
|
|
75
100
|
* Asynchronous validation ([1505f41](https://github.com/modulify/validator/commit/1505f417bd869ba762f6a91d1d30a360d2505ad4))
|
|
101
|
+
|
package/README.md
CHANGED
|
@@ -204,7 +204,7 @@ if (ok) {
|
|
|
204
204
|
|
|
205
205
|
## Shape API
|
|
206
206
|
|
|
207
|
-
`shape(...)` is the reusable object-shape API. It validates nested record-like objects and exposes small immutable helpers such as `strict()`, `pick()`, `omit()`, `partial()`, `extend()`, `merge()`, `refine()`, and `fieldsMatch(...)`.
|
|
207
|
+
`shape(...)` is the reusable object-shape API. It validates nested record-like objects and exposes small immutable helpers such as `strict()`, `pick()`, `omit()`, `partial()`, `extend()`, `merge()`, async-first `refine()`, explicit `refine.sync()`, and `fieldsMatch(...)`.
|
|
208
208
|
|
|
209
209
|
```typescript
|
|
210
210
|
import {
|
|
@@ -270,11 +270,17 @@ A practical way to think about the library is:
|
|
|
270
270
|
|
|
271
271
|
In the current API this usually looks like:
|
|
272
272
|
|
|
273
|
-
-
|
|
273
|
+
- guard assertions such as `isString`, `isNumber`, `isDefined`, `oneOf(...)` establish the base domain for a value;
|
|
274
|
+
- refinement assertions such as `hasLength(...)`, `hasPattern(...)`, `startsWith(...)`, `hasValue(...)`, `multipleOf(...)` validate properties inside that domain;
|
|
274
275
|
- schema composition with combinators such as `exact`, `optional`, `nullable`, `nullish`, `shape(...)`, `each(...)`;
|
|
275
276
|
- typed validation through `validate(...)` or `validate.sync(...)`;
|
|
276
277
|
- narrowing of the original sync variable through `matches.sync(...)`.
|
|
277
278
|
|
|
279
|
+
Sequential assertion arrays are stage-aware. A tuple like `[isString, hasLength({ min: 3 })]` is valid, while incompatible combinations like `[isNumber, hasLength({ min: 3 })]` are rejected by TypeScript.
|
|
280
|
+
Refinement assertions are not meant to be passed to `validate(...)` or `matches.sync(...)` on their own.
|
|
281
|
+
|
|
282
|
+
`validate(...)` is the default async-first validation entrypoint. `validate.sync(...)` and `matches.sync(...)` are specialized sync APIs and will throw if they encounter async validators or async object-level `shape(...).refine(...)` rules.
|
|
283
|
+
|
|
278
284
|
## Violations
|
|
279
285
|
|
|
280
286
|
`validate(...)` returns machine-readable `Violation[]`, and `collection(...)` can wrap that list into a small helper API for exact path lookups and tree traversal.
|
|
@@ -354,6 +360,8 @@ Two additional guides are useful when you want faster practical navigation inste
|
|
|
354
360
|
- [Common Recipes](./docs/en/06-common-recipes.md) - task-oriented examples for payload validation, wrapper choice, reusable shapes, form error mapping, and JSON Schema export.
|
|
355
361
|
- [AI Reference](./docs/en/07-ai-reference.md) - compact contract summary for agents, tooling, and quick semantic lookup.
|
|
356
362
|
|
|
363
|
+
- [Migration From 0.2.1](./docs/en/09-migration.md)
|
|
364
|
+
|
|
357
365
|
## Notes
|
|
358
366
|
|
|
359
367
|
- Assertions return structured metadata instead of messages.
|
|
@@ -366,3 +374,5 @@ Two additional guides are useful when you want faster practical navigation inste
|
|
|
366
374
|
## Translations
|
|
367
375
|
|
|
368
376
|
- [Russian](./docs/ru/README.md)
|
|
377
|
+
|
|
378
|
+
Release workflow and npm OIDC setup: [Releasing](docs/RELEASING.md).
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
//#region src/constraints.ts
|
|
2
|
+
var isValidator = (constraint) => "run" in constraint;
|
|
3
|
+
function arrayify(value) {
|
|
4
|
+
return Array.isArray(value) ? [...value] : [value];
|
|
5
|
+
}
|
|
6
|
+
function matchesConstraints(value, constraints) {
|
|
7
|
+
let establishedDomain = false;
|
|
8
|
+
return arrayify(constraints).every((constraint) => {
|
|
9
|
+
if (isValidator(constraint)) {
|
|
10
|
+
establishedDomain = false;
|
|
11
|
+
return constraint.check(value);
|
|
12
|
+
}
|
|
13
|
+
if (!establishedDomain && isRefinementAssertion(constraint)) return false;
|
|
14
|
+
const matched = establishedDomain && isRefinementAssertion(constraint) ? checkRefinementAssertion(constraint, value) : constraint.check(value);
|
|
15
|
+
if (matched) establishedDomain = true;
|
|
16
|
+
return matched;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/metadata.ts
|
|
21
|
+
var constraintDescriptorSymbol = Symbol("modulify.validator.descriptor");
|
|
22
|
+
var constraintMetadataSymbol = Symbol("modulify.validator.metadata");
|
|
23
|
+
var cloneCallableConstraint = (constraint) => {
|
|
24
|
+
const source = constraint;
|
|
25
|
+
const cloned = ((value) => source(value));
|
|
26
|
+
const { length: _length, name: _name, prototype: _prototype, ...descriptors } = Object.getOwnPropertyDescriptors(source);
|
|
27
|
+
Object.defineProperties(cloned, descriptors);
|
|
28
|
+
try {
|
|
29
|
+
Object.defineProperty(cloned, "name", {
|
|
30
|
+
configurable: true,
|
|
31
|
+
value: source.name
|
|
32
|
+
});
|
|
33
|
+
} catch {}
|
|
34
|
+
Object.setPrototypeOf(cloned, Object.getPrototypeOf(source));
|
|
35
|
+
return cloned;
|
|
36
|
+
};
|
|
37
|
+
var cloneConstraint = (constraint) => {
|
|
38
|
+
if (typeof constraint === "function") return cloneCallableConstraint(constraint);
|
|
39
|
+
return Object.create(Object.getPrototypeOf(constraint), Object.getOwnPropertyDescriptors(constraint));
|
|
40
|
+
};
|
|
41
|
+
var freezeMetadata = (metadata) => Object.freeze({ ...metadata });
|
|
42
|
+
var getConstraintMetadata = (constraint) => {
|
|
43
|
+
return constraint[constraintMetadataSymbol];
|
|
44
|
+
};
|
|
45
|
+
var getDescriptorFactory = (constraint) => {
|
|
46
|
+
return constraint[constraintDescriptorSymbol];
|
|
47
|
+
};
|
|
48
|
+
var getPublicDescriptor = (constraint) => {
|
|
49
|
+
if (!isValidator(constraint)) return;
|
|
50
|
+
const { describe } = constraint;
|
|
51
|
+
return typeof describe === "function" ? describe.call(constraint) : void 0;
|
|
52
|
+
};
|
|
53
|
+
var inferAssertionDescriptor = (assertion) => ({
|
|
54
|
+
kind: "assertion",
|
|
55
|
+
name: assertion.name,
|
|
56
|
+
bail: assertion.bail,
|
|
57
|
+
code: assertion.name,
|
|
58
|
+
args: [],
|
|
59
|
+
constraints: assertion.constraints.map(([, , code, ...args]) => ({
|
|
60
|
+
code,
|
|
61
|
+
args
|
|
62
|
+
}))
|
|
63
|
+
});
|
|
64
|
+
var withMetadata = (descriptor, metadata) => {
|
|
65
|
+
if (!metadata) return descriptor;
|
|
66
|
+
return {
|
|
67
|
+
...descriptor,
|
|
68
|
+
metadata
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
var attachConstraintDescriptor = (constraint, describe) => {
|
|
72
|
+
Object.defineProperty(constraint, constraintDescriptorSymbol, {
|
|
73
|
+
configurable: false,
|
|
74
|
+
enumerable: false,
|
|
75
|
+
value: describe,
|
|
76
|
+
writable: false
|
|
77
|
+
});
|
|
78
|
+
return constraint;
|
|
79
|
+
};
|
|
80
|
+
var meta = (constraint, metadata) => {
|
|
81
|
+
const cloned = cloneConstraint(constraint);
|
|
82
|
+
const nextMetadata = freezeMetadata({
|
|
83
|
+
...getConstraintMetadata(constraint) ?? {},
|
|
84
|
+
...metadata
|
|
85
|
+
});
|
|
86
|
+
Object.defineProperty(cloned, constraintMetadataSymbol, {
|
|
87
|
+
configurable: true,
|
|
88
|
+
enumerable: false,
|
|
89
|
+
value: nextMetadata,
|
|
90
|
+
writable: false
|
|
91
|
+
});
|
|
92
|
+
return cloned;
|
|
93
|
+
};
|
|
94
|
+
var custom = (validator) => validator;
|
|
95
|
+
var describeConstraints = (constraints) => {
|
|
96
|
+
const values = arrayify(constraints);
|
|
97
|
+
return values.length === 1 ? describe(values[0]) : {
|
|
98
|
+
kind: "allOf",
|
|
99
|
+
constraints: values.map((value) => describe(value))
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
var describe = (constraint) => {
|
|
103
|
+
const factory = getDescriptorFactory(constraint);
|
|
104
|
+
const metadata = getConstraintMetadata(constraint);
|
|
105
|
+
if (factory) return withMetadata(factory(), metadata);
|
|
106
|
+
const publicDescriptor = getPublicDescriptor(constraint);
|
|
107
|
+
if (publicDescriptor) return withMetadata(publicDescriptor, metadata);
|
|
108
|
+
if (isValidator(constraint)) return withMetadata({ kind: "validator" }, metadata);
|
|
109
|
+
return withMetadata(inferAssertionDescriptor(constraint), metadata);
|
|
110
|
+
};
|
|
111
|
+
//#endregion
|
|
112
|
+
//#region src/assert.ts
|
|
113
|
+
var assertionStageSymbol = Symbol("modulify.validator.assertion.stage");
|
|
114
|
+
var runRefinementSymbol = Symbol("modulify.validator.assertion.runRefinement");
|
|
115
|
+
var checkRefinementSymbol = Symbol("modulify.validator.assertion.checkRefinement");
|
|
116
|
+
var createAssertion = (stage, predicate, meta, constraints = []) => {
|
|
117
|
+
const assertionCode = meta.code ?? meta.name;
|
|
118
|
+
const assertionArgs = meta.args ?? [];
|
|
119
|
+
const violationSubject = {
|
|
120
|
+
kind: "assertion",
|
|
121
|
+
name: meta.name,
|
|
122
|
+
code: assertionCode,
|
|
123
|
+
args: assertionArgs
|
|
124
|
+
};
|
|
125
|
+
const runConstraints = (value) => {
|
|
126
|
+
for (const [extract, check, code, ...args] of constraints) if (!check(extract(value), ...args)) return {
|
|
127
|
+
value,
|
|
128
|
+
violates: {
|
|
129
|
+
kind: "assertion",
|
|
130
|
+
name: meta.name,
|
|
131
|
+
code,
|
|
132
|
+
args
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
return null;
|
|
136
|
+
};
|
|
137
|
+
const checkConstraints = (value) => !constraints.length || constraints.every(([extract, check, , ...args]) => check(extract(value), ...args));
|
|
138
|
+
const assertion = ((value) => {
|
|
139
|
+
if (!predicate(value)) return {
|
|
140
|
+
value,
|
|
141
|
+
violates: violationSubject
|
|
142
|
+
};
|
|
143
|
+
return runConstraints(value);
|
|
144
|
+
});
|
|
145
|
+
Object.defineProperties(assertion, {
|
|
146
|
+
name: {
|
|
147
|
+
configurable: true,
|
|
148
|
+
value: meta.name
|
|
149
|
+
},
|
|
150
|
+
bail: {
|
|
151
|
+
enumerable: true,
|
|
152
|
+
value: meta.bail
|
|
153
|
+
},
|
|
154
|
+
constraints: {
|
|
155
|
+
enumerable: true,
|
|
156
|
+
value: constraints
|
|
157
|
+
},
|
|
158
|
+
check: {
|
|
159
|
+
enumerable: true,
|
|
160
|
+
value: (value) => predicate(value) && checkConstraints(value)
|
|
161
|
+
},
|
|
162
|
+
[assertionStageSymbol]: {
|
|
163
|
+
enumerable: false,
|
|
164
|
+
value: stage
|
|
165
|
+
},
|
|
166
|
+
[runRefinementSymbol]: {
|
|
167
|
+
enumerable: false,
|
|
168
|
+
value: (value) => runConstraints(value)
|
|
169
|
+
},
|
|
170
|
+
[checkRefinementSymbol]: {
|
|
171
|
+
enumerable: false,
|
|
172
|
+
value: (value) => checkConstraints(value)
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
return /* @__PURE__ */ attachConstraintDescriptor(assertion, () => ({
|
|
176
|
+
kind: "assertion",
|
|
177
|
+
name: meta.name,
|
|
178
|
+
bail: meta.bail,
|
|
179
|
+
code: assertionCode,
|
|
180
|
+
args: assertionArgs,
|
|
181
|
+
constraints: constraints.map(([, , code, ...args]) => ({
|
|
182
|
+
code,
|
|
183
|
+
args
|
|
184
|
+
}))
|
|
185
|
+
}));
|
|
186
|
+
};
|
|
187
|
+
var assert = (predicate, meta, constraints = []) => {
|
|
188
|
+
return createAssertion("guard", predicate, meta, constraints);
|
|
189
|
+
};
|
|
190
|
+
var isRefinementAssertion = (constraint) => {
|
|
191
|
+
return typeof constraint === "function" && constraint[assertionStageSymbol] === "refinement";
|
|
192
|
+
};
|
|
193
|
+
var runRefinementAssertion = (constraint, value) => {
|
|
194
|
+
const runRefinement = constraint[runRefinementSymbol];
|
|
195
|
+
return runRefinement ? runRefinement(value) : constraint(value);
|
|
196
|
+
};
|
|
197
|
+
var checkRefinementAssertion = (constraint, value) => {
|
|
198
|
+
const checkRefinement = constraint[checkRefinementSymbol];
|
|
199
|
+
return checkRefinement ? checkRefinement(value) : constraint.check(value);
|
|
200
|
+
};
|
|
201
|
+
var createRefinement = (meta, constraints = []) => {
|
|
202
|
+
return createAssertion("refinement", ((value) => true), meta, constraints);
|
|
203
|
+
};
|
|
204
|
+
var refine = createRefinement;
|
|
205
|
+
//#endregion
|
|
206
|
+
Object.defineProperty(exports, "arrayify", {
|
|
207
|
+
enumerable: true,
|
|
208
|
+
get: function() {
|
|
209
|
+
return arrayify;
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
Object.defineProperty(exports, "assert", {
|
|
213
|
+
enumerable: true,
|
|
214
|
+
get: function() {
|
|
215
|
+
return assert;
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
Object.defineProperty(exports, "attachConstraintDescriptor", {
|
|
219
|
+
enumerable: true,
|
|
220
|
+
get: function() {
|
|
221
|
+
return attachConstraintDescriptor;
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
Object.defineProperty(exports, "checkRefinementAssertion", {
|
|
225
|
+
enumerable: true,
|
|
226
|
+
get: function() {
|
|
227
|
+
return checkRefinementAssertion;
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
Object.defineProperty(exports, "createRefinement", {
|
|
231
|
+
enumerable: true,
|
|
232
|
+
get: function() {
|
|
233
|
+
return createRefinement;
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
Object.defineProperty(exports, "custom", {
|
|
237
|
+
enumerable: true,
|
|
238
|
+
get: function() {
|
|
239
|
+
return custom;
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
Object.defineProperty(exports, "describe", {
|
|
243
|
+
enumerable: true,
|
|
244
|
+
get: function() {
|
|
245
|
+
return describe;
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
Object.defineProperty(exports, "describeConstraints", {
|
|
249
|
+
enumerable: true,
|
|
250
|
+
get: function() {
|
|
251
|
+
return describeConstraints;
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
Object.defineProperty(exports, "isRefinementAssertion", {
|
|
255
|
+
enumerable: true,
|
|
256
|
+
get: function() {
|
|
257
|
+
return isRefinementAssertion;
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
Object.defineProperty(exports, "isValidator", {
|
|
261
|
+
enumerable: true,
|
|
262
|
+
get: function() {
|
|
263
|
+
return isValidator;
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
Object.defineProperty(exports, "matchesConstraints", {
|
|
267
|
+
enumerable: true,
|
|
268
|
+
get: function() {
|
|
269
|
+
return matchesConstraints;
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
Object.defineProperty(exports, "meta", {
|
|
273
|
+
enumerable: true,
|
|
274
|
+
get: function() {
|
|
275
|
+
return meta;
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
Object.defineProperty(exports, "refine", {
|
|
279
|
+
enumerable: true,
|
|
280
|
+
get: function() {
|
|
281
|
+
return refine;
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
Object.defineProperty(exports, "runRefinementAssertion", {
|
|
285
|
+
enumerable: true,
|
|
286
|
+
get: function() {
|
|
287
|
+
return runRefinementAssertion;
|
|
288
|
+
}
|
|
289
|
+
});
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
//#region src/constraints.ts
|
|
2
|
+
var isValidator = (constraint) => "run" in constraint;
|
|
3
|
+
function arrayify(value) {
|
|
4
|
+
return Array.isArray(value) ? [...value] : [value];
|
|
5
|
+
}
|
|
6
|
+
function matchesConstraints(value, constraints) {
|
|
7
|
+
let establishedDomain = false;
|
|
8
|
+
return arrayify(constraints).every((constraint) => {
|
|
9
|
+
if (isValidator(constraint)) {
|
|
10
|
+
establishedDomain = false;
|
|
11
|
+
return constraint.check(value);
|
|
12
|
+
}
|
|
13
|
+
if (!establishedDomain && isRefinementAssertion(constraint)) return false;
|
|
14
|
+
const matched = establishedDomain && isRefinementAssertion(constraint) ? checkRefinementAssertion(constraint, value) : constraint.check(value);
|
|
15
|
+
if (matched) establishedDomain = true;
|
|
16
|
+
return matched;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/metadata.ts
|
|
21
|
+
var constraintDescriptorSymbol = Symbol("modulify.validator.descriptor");
|
|
22
|
+
var constraintMetadataSymbol = Symbol("modulify.validator.metadata");
|
|
23
|
+
var cloneCallableConstraint = (constraint) => {
|
|
24
|
+
const source = constraint;
|
|
25
|
+
const cloned = ((value) => source(value));
|
|
26
|
+
const { length: _length, name: _name, prototype: _prototype, ...descriptors } = Object.getOwnPropertyDescriptors(source);
|
|
27
|
+
Object.defineProperties(cloned, descriptors);
|
|
28
|
+
try {
|
|
29
|
+
Object.defineProperty(cloned, "name", {
|
|
30
|
+
configurable: true,
|
|
31
|
+
value: source.name
|
|
32
|
+
});
|
|
33
|
+
} catch {}
|
|
34
|
+
Object.setPrototypeOf(cloned, Object.getPrototypeOf(source));
|
|
35
|
+
return cloned;
|
|
36
|
+
};
|
|
37
|
+
var cloneConstraint = (constraint) => {
|
|
38
|
+
if (typeof constraint === "function") return cloneCallableConstraint(constraint);
|
|
39
|
+
return Object.create(Object.getPrototypeOf(constraint), Object.getOwnPropertyDescriptors(constraint));
|
|
40
|
+
};
|
|
41
|
+
var freezeMetadata = (metadata) => Object.freeze({ ...metadata });
|
|
42
|
+
var getConstraintMetadata = (constraint) => {
|
|
43
|
+
return constraint[constraintMetadataSymbol];
|
|
44
|
+
};
|
|
45
|
+
var getDescriptorFactory = (constraint) => {
|
|
46
|
+
return constraint[constraintDescriptorSymbol];
|
|
47
|
+
};
|
|
48
|
+
var getPublicDescriptor = (constraint) => {
|
|
49
|
+
if (!isValidator(constraint)) return;
|
|
50
|
+
const { describe } = constraint;
|
|
51
|
+
return typeof describe === "function" ? describe.call(constraint) : void 0;
|
|
52
|
+
};
|
|
53
|
+
var inferAssertionDescriptor = (assertion) => ({
|
|
54
|
+
kind: "assertion",
|
|
55
|
+
name: assertion.name,
|
|
56
|
+
bail: assertion.bail,
|
|
57
|
+
code: assertion.name,
|
|
58
|
+
args: [],
|
|
59
|
+
constraints: assertion.constraints.map(([, , code, ...args]) => ({
|
|
60
|
+
code,
|
|
61
|
+
args
|
|
62
|
+
}))
|
|
63
|
+
});
|
|
64
|
+
var withMetadata = (descriptor, metadata) => {
|
|
65
|
+
if (!metadata) return descriptor;
|
|
66
|
+
return {
|
|
67
|
+
...descriptor,
|
|
68
|
+
metadata
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
var attachConstraintDescriptor = (constraint, describe) => {
|
|
72
|
+
Object.defineProperty(constraint, constraintDescriptorSymbol, {
|
|
73
|
+
configurable: false,
|
|
74
|
+
enumerable: false,
|
|
75
|
+
value: describe,
|
|
76
|
+
writable: false
|
|
77
|
+
});
|
|
78
|
+
return constraint;
|
|
79
|
+
};
|
|
80
|
+
var meta = (constraint, metadata) => {
|
|
81
|
+
const cloned = cloneConstraint(constraint);
|
|
82
|
+
const nextMetadata = freezeMetadata({
|
|
83
|
+
...getConstraintMetadata(constraint) ?? {},
|
|
84
|
+
...metadata
|
|
85
|
+
});
|
|
86
|
+
Object.defineProperty(cloned, constraintMetadataSymbol, {
|
|
87
|
+
configurable: true,
|
|
88
|
+
enumerable: false,
|
|
89
|
+
value: nextMetadata,
|
|
90
|
+
writable: false
|
|
91
|
+
});
|
|
92
|
+
return cloned;
|
|
93
|
+
};
|
|
94
|
+
var custom = (validator) => validator;
|
|
95
|
+
var describeConstraints = (constraints) => {
|
|
96
|
+
const values = arrayify(constraints);
|
|
97
|
+
return values.length === 1 ? describe(values[0]) : {
|
|
98
|
+
kind: "allOf",
|
|
99
|
+
constraints: values.map((value) => describe(value))
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
var describe = (constraint) => {
|
|
103
|
+
const factory = getDescriptorFactory(constraint);
|
|
104
|
+
const metadata = getConstraintMetadata(constraint);
|
|
105
|
+
if (factory) return withMetadata(factory(), metadata);
|
|
106
|
+
const publicDescriptor = getPublicDescriptor(constraint);
|
|
107
|
+
if (publicDescriptor) return withMetadata(publicDescriptor, metadata);
|
|
108
|
+
if (isValidator(constraint)) return withMetadata({ kind: "validator" }, metadata);
|
|
109
|
+
return withMetadata(inferAssertionDescriptor(constraint), metadata);
|
|
110
|
+
};
|
|
111
|
+
//#endregion
|
|
112
|
+
//#region src/assert.ts
|
|
113
|
+
var assertionStageSymbol = Symbol("modulify.validator.assertion.stage");
|
|
114
|
+
var runRefinementSymbol = Symbol("modulify.validator.assertion.runRefinement");
|
|
115
|
+
var checkRefinementSymbol = Symbol("modulify.validator.assertion.checkRefinement");
|
|
116
|
+
var createAssertion = (stage, predicate, meta, constraints = []) => {
|
|
117
|
+
const assertionCode = meta.code ?? meta.name;
|
|
118
|
+
const assertionArgs = meta.args ?? [];
|
|
119
|
+
const violationSubject = {
|
|
120
|
+
kind: "assertion",
|
|
121
|
+
name: meta.name,
|
|
122
|
+
code: assertionCode,
|
|
123
|
+
args: assertionArgs
|
|
124
|
+
};
|
|
125
|
+
const runConstraints = (value) => {
|
|
126
|
+
for (const [extract, check, code, ...args] of constraints) if (!check(extract(value), ...args)) return {
|
|
127
|
+
value,
|
|
128
|
+
violates: {
|
|
129
|
+
kind: "assertion",
|
|
130
|
+
name: meta.name,
|
|
131
|
+
code,
|
|
132
|
+
args
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
return null;
|
|
136
|
+
};
|
|
137
|
+
const checkConstraints = (value) => !constraints.length || constraints.every(([extract, check, , ...args]) => check(extract(value), ...args));
|
|
138
|
+
const assertion = ((value) => {
|
|
139
|
+
if (!predicate(value)) return {
|
|
140
|
+
value,
|
|
141
|
+
violates: violationSubject
|
|
142
|
+
};
|
|
143
|
+
return runConstraints(value);
|
|
144
|
+
});
|
|
145
|
+
Object.defineProperties(assertion, {
|
|
146
|
+
name: {
|
|
147
|
+
configurable: true,
|
|
148
|
+
value: meta.name
|
|
149
|
+
},
|
|
150
|
+
bail: {
|
|
151
|
+
enumerable: true,
|
|
152
|
+
value: meta.bail
|
|
153
|
+
},
|
|
154
|
+
constraints: {
|
|
155
|
+
enumerable: true,
|
|
156
|
+
value: constraints
|
|
157
|
+
},
|
|
158
|
+
check: {
|
|
159
|
+
enumerable: true,
|
|
160
|
+
value: (value) => predicate(value) && checkConstraints(value)
|
|
161
|
+
},
|
|
162
|
+
[assertionStageSymbol]: {
|
|
163
|
+
enumerable: false,
|
|
164
|
+
value: stage
|
|
165
|
+
},
|
|
166
|
+
[runRefinementSymbol]: {
|
|
167
|
+
enumerable: false,
|
|
168
|
+
value: (value) => runConstraints(value)
|
|
169
|
+
},
|
|
170
|
+
[checkRefinementSymbol]: {
|
|
171
|
+
enumerable: false,
|
|
172
|
+
value: (value) => checkConstraints(value)
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
return /* @__PURE__ */ attachConstraintDescriptor(assertion, () => ({
|
|
176
|
+
kind: "assertion",
|
|
177
|
+
name: meta.name,
|
|
178
|
+
bail: meta.bail,
|
|
179
|
+
code: assertionCode,
|
|
180
|
+
args: assertionArgs,
|
|
181
|
+
constraints: constraints.map(([, , code, ...args]) => ({
|
|
182
|
+
code,
|
|
183
|
+
args
|
|
184
|
+
}))
|
|
185
|
+
}));
|
|
186
|
+
};
|
|
187
|
+
var assert = (predicate, meta, constraints = []) => {
|
|
188
|
+
return createAssertion("guard", predicate, meta, constraints);
|
|
189
|
+
};
|
|
190
|
+
var isRefinementAssertion = (constraint) => {
|
|
191
|
+
return typeof constraint === "function" && constraint[assertionStageSymbol] === "refinement";
|
|
192
|
+
};
|
|
193
|
+
var runRefinementAssertion = (constraint, value) => {
|
|
194
|
+
const runRefinement = constraint[runRefinementSymbol];
|
|
195
|
+
return runRefinement ? runRefinement(value) : constraint(value);
|
|
196
|
+
};
|
|
197
|
+
var checkRefinementAssertion = (constraint, value) => {
|
|
198
|
+
const checkRefinement = constraint[checkRefinementSymbol];
|
|
199
|
+
return checkRefinement ? checkRefinement(value) : constraint.check(value);
|
|
200
|
+
};
|
|
201
|
+
var createRefinement = (meta, constraints = []) => {
|
|
202
|
+
return createAssertion("refinement", ((value) => true), meta, constraints);
|
|
203
|
+
};
|
|
204
|
+
var refine = createRefinement;
|
|
205
|
+
//#endregion
|
|
206
|
+
export { refine as a, custom as c, meta as d, arrayify as f, isRefinementAssertion as i, describe as l, matchesConstraints as m, checkRefinementAssertion as n, runRefinementAssertion as o, isValidator as p, createRefinement as r, attachConstraintDescriptor as s, assert as t, describeConstraints as u };
|
package/dist/assert.cjs
CHANGED
|
@@ -1,66 +1,8 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
code: assertionCode,
|
|
11
|
-
args: assertionArgs
|
|
12
|
-
};
|
|
13
|
-
const assertion = ((value) => {
|
|
14
|
-
if (!predicate(value)) {
|
|
15
|
-
return {
|
|
16
|
-
value,
|
|
17
|
-
violates: violationSubject
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
for (const [extract, check, code, ...args] of constraints) {
|
|
21
|
-
if (!check(extract(value), ...args)) {
|
|
22
|
-
const constraintSubject = {
|
|
23
|
-
kind: "assertion",
|
|
24
|
-
name: meta.name,
|
|
25
|
-
code,
|
|
26
|
-
args
|
|
27
|
-
};
|
|
28
|
-
return {
|
|
29
|
-
value,
|
|
30
|
-
violates: constraintSubject
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return null;
|
|
35
|
-
});
|
|
36
|
-
Object.defineProperties(assertion, {
|
|
37
|
-
name: {
|
|
38
|
-
configurable: true,
|
|
39
|
-
value: meta.name
|
|
40
|
-
},
|
|
41
|
-
bail: {
|
|
42
|
-
enumerable: true,
|
|
43
|
-
value: meta.bail
|
|
44
|
-
},
|
|
45
|
-
constraints: {
|
|
46
|
-
enumerable: true,
|
|
47
|
-
value: constraints
|
|
48
|
-
},
|
|
49
|
-
check: {
|
|
50
|
-
enumerable: true,
|
|
51
|
-
value: (value) => predicate(value) && (!constraints.length || constraints.every(([extract, check, , ...args]) => check(extract(value), ...args)))
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
return metadata.attachConstraintDescriptor(assertion, () => ({
|
|
55
|
-
kind: "assertion",
|
|
56
|
-
name: meta.name,
|
|
57
|
-
bail: meta.bail,
|
|
58
|
-
code: assertionCode,
|
|
59
|
-
args: assertionArgs,
|
|
60
|
-
constraints: constraints.map(([, , code, ...args]) => ({
|
|
61
|
-
code,
|
|
62
|
-
args
|
|
63
|
-
}))
|
|
64
|
-
}));
|
|
65
|
-
};
|
|
66
|
-
exports.assert = assert;
|
|
2
|
+
const require_assert = require("./assert-BDOtHdLx.cjs");
|
|
3
|
+
exports.assert = require_assert.assert;
|
|
4
|
+
exports.checkRefinementAssertion = require_assert.checkRefinementAssertion;
|
|
5
|
+
exports.createRefinement = require_assert.createRefinement;
|
|
6
|
+
exports.isRefinementAssertion = require_assert.isRefinementAssertion;
|
|
7
|
+
exports.refine = require_assert.refine;
|
|
8
|
+
exports.runRefinementAssertion = require_assert.runRefinementAssertion;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Assertion, Constraint, AssertionConstraint, Guard, Predicate, Refinement } from './types/index.cjs';
|
|
2
|
+
type AssertMeta = {
|
|
3
|
+
name: string;
|
|
4
|
+
bail: boolean;
|
|
5
|
+
code?: string;
|
|
6
|
+
args?: readonly unknown[];
|
|
7
|
+
};
|
|
8
|
+
type ResolveAssertionCode<Name extends string, Code extends string | undefined> = Code extends string ? Code : Name;
|
|
9
|
+
type ResolveAssertionArgs<Args extends readonly unknown[] | undefined> = Args extends readonly unknown[] ? Args : [];
|
|
10
|
+
type ConstraintInputFunction<C extends AssertionConstraint> = C extends unknown ? (value: Parameters<C[0]>[0]) => void : never;
|
|
11
|
+
type ConstraintInput<C extends readonly AssertionConstraint[]> = C extends readonly [] ? unknown : ConstraintInputFunction<C[number]> extends (value: infer Input) => void ? Input : never;
|
|
12
|
+
type ConstraintArgs<C extends AssertionConstraint> = C extends readonly [unknown, unknown, string, ...infer Args] ? Args : never;
|
|
13
|
+
type CompatibleAssertionConstraints<Input, C extends readonly AssertionConstraint[]> = {
|
|
14
|
+
[K in keyof C]: AssertionConstraint<Input, ReturnType<C[K][0]>, ConstraintArgs<C[K]>, C[K][2]>;
|
|
15
|
+
};
|
|
16
|
+
export declare const assert: <T, const Name extends string, const Bail extends boolean, const Code extends string | undefined = undefined, const Args extends readonly unknown[] | undefined = undefined, const C extends readonly AssertionConstraint<T, any, any[], string>[] = []>(predicate: Predicate<T>, meta: AssertMeta & {
|
|
17
|
+
name: Name;
|
|
18
|
+
bail: Bail;
|
|
19
|
+
code?: Code;
|
|
20
|
+
args?: Args;
|
|
21
|
+
}, constraints?: C & CompatibleAssertionConstraints<T, C>) => Guard<T, C, ResolveAssertionCode<Name, Code>, ResolveAssertionArgs<Args>, Name>;
|
|
22
|
+
export declare const isRefinementAssertion: (constraint: Constraint) => constraint is Assertion;
|
|
23
|
+
export declare const runRefinementAssertion: (constraint: Assertion, value: unknown) => ReturnType<Assertion>;
|
|
24
|
+
export declare const checkRefinementAssertion: (constraint: Assertion, value: unknown) => boolean;
|
|
25
|
+
export declare const createRefinement: <const Name extends string, const Bail extends boolean, const Code extends string | undefined = undefined, const Args extends readonly unknown[] | undefined = undefined, const C extends readonly AssertionConstraint[] = []>(meta: AssertMeta & {
|
|
26
|
+
name: Name;
|
|
27
|
+
bail: Bail;
|
|
28
|
+
code?: Code;
|
|
29
|
+
args?: Args;
|
|
30
|
+
}, constraints?: C) => Refinement<ConstraintInput<C>, C, ResolveAssertionCode<Name, Code>, ResolveAssertionArgs<Args>, Name>;
|
|
31
|
+
export declare const refine: <const Name extends string, const Bail extends boolean, const Code extends string | undefined = undefined, const Args extends readonly unknown[] | undefined = undefined, const C extends readonly AssertionConstraint[] = []>(meta: AssertMeta & {
|
|
32
|
+
name: Name;
|
|
33
|
+
bail: Bail;
|
|
34
|
+
code?: Code;
|
|
35
|
+
args?: Args;
|
|
36
|
+
}, constraints?: C & CompatibleAssertionConstraints<ConstraintInput<C>, C>) => Refinement<ConstraintInput<C>, C, ResolveAssertionCode<Name, Code>, ResolveAssertionArgs<Args>, Name>;
|
|
37
|
+
export {};
|