@cleverbrush/schema 4.5.0 → 5.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/LICENSE +28 -0
- package/README.md +176 -19
- package/dist/builders/AnySchemaBuilder.d.ts +11 -2
- package/dist/builders/AnySchemaBuilder.js +1 -1
- package/dist/builders/ArraySchemaBuilder.d.ts +15 -4
- package/dist/builders/ArraySchemaBuilder.js +1 -1
- package/dist/builders/BooleanSchemaBuilder.d.ts +21 -6
- package/dist/builders/BooleanSchemaBuilder.js +1 -1
- package/dist/builders/DateSchemaBuilder.d.ts +24 -10
- package/dist/builders/DateSchemaBuilder.js +1 -1
- package/dist/builders/ExternSchemaBuilder.d.ts +3 -2
- package/dist/builders/ExternSchemaBuilder.js +1 -1
- package/dist/builders/FunctionSchemaBuilder.d.ts +14 -2
- package/dist/builders/FunctionSchemaBuilder.js +1 -1
- package/dist/builders/GenericSchemaBuilder.d.ts +14 -3
- package/dist/builders/IntersectionSchemaBuilder.d.ts +1 -0
- package/dist/builders/LazySchemaBuilder.d.ts +1 -0
- package/dist/builders/NullSchemaBuilder.d.ts +2 -4
- package/dist/builders/NumberSchemaBuilder.d.ts +21 -7
- package/dist/builders/NumberSchemaBuilder.js +1 -1
- package/dist/builders/ObjectSchemaBuilder.d.ts +15 -4
- package/dist/builders/ObjectSchemaBuilder.js +1 -1
- package/dist/builders/ParseStringSchemaBuilder.d.ts +1 -0
- package/dist/builders/ParseStringSchemaBuilder.js +1 -1
- package/dist/builders/PromiseSchemaBuilder.d.ts +13 -2
- package/dist/builders/PromiseSchemaBuilder.js +1 -1
- package/dist/builders/RecordSchemaBuilder.d.ts +12 -0
- package/dist/builders/RecordSchemaBuilder.js +1 -1
- package/dist/builders/SchemaBuilder.d.ts +59 -10
- package/dist/builders/StringSchemaBuilder.d.ts +23 -8
- package/dist/builders/StringSchemaBuilder.js +1 -1
- package/dist/builders/TupleSchemaBuilder.d.ts +16 -4
- package/dist/builders/TupleSchemaBuilder.js +1 -1
- package/dist/builders/UnionSchemaBuilder.d.ts +12 -2
- package/dist/builders/UnionSchemaBuilder.js +1 -1
- package/dist/chunk-25KL2NBJ.js +2 -0
- package/dist/chunk-25KL2NBJ.js.map +1 -0
- package/dist/chunk-2BKBVVZ3.js +2 -0
- package/dist/chunk-2BKBVVZ3.js.map +1 -0
- package/dist/chunk-3E5M6GRR.js +2 -0
- package/dist/chunk-3E5M6GRR.js.map +1 -0
- package/dist/chunk-66U6MMJ2.js +2 -0
- package/dist/chunk-66U6MMJ2.js.map +1 -0
- package/dist/chunk-BMA2X7LI.js +2 -0
- package/dist/chunk-BMA2X7LI.js.map +1 -0
- package/dist/chunk-BTR3ZGES.js +2 -0
- package/dist/chunk-BTR3ZGES.js.map +1 -0
- package/dist/chunk-D7RXO2FA.js +2 -0
- package/dist/chunk-D7RXO2FA.js.map +1 -0
- package/dist/chunk-JH7VLA6C.js +2 -0
- package/dist/chunk-JH7VLA6C.js.map +1 -0
- package/dist/chunk-K7TDPKGQ.js +2 -0
- package/dist/chunk-K7TDPKGQ.js.map +1 -0
- package/dist/chunk-NDESVCWI.js +2 -0
- package/dist/chunk-NDESVCWI.js.map +1 -0
- package/dist/chunk-VBPZRO7L.js +2 -0
- package/dist/chunk-VBPZRO7L.js.map +1 -0
- package/dist/chunk-W5D22D4P.js +2 -0
- package/dist/chunk-W5D22D4P.js.map +1 -0
- package/dist/{chunk-XHSBY2QK.js → chunk-W5LLKFM7.js} +2 -2
- package/dist/{chunk-XHSBY2QK.js.map → chunk-W5LLKFM7.js.map} +1 -1
- package/dist/chunk-WNAU5MPQ.js +2 -0
- package/dist/chunk-WNAU5MPQ.js.map +1 -0
- package/dist/chunk-XASMTNON.js +2 -0
- package/dist/chunk-XASMTNON.js.map +1 -0
- package/dist/chunk-Z4SFUZSP.js +2 -0
- package/dist/chunk-Z4SFUZSP.js.map +1 -0
- package/dist/chunk-ZYWDTLNL.js +2 -0
- package/dist/chunk-ZYWDTLNL.js.map +1 -0
- package/dist/core.d.ts +3 -3
- package/dist/core.js +1 -1
- package/dist/extension.d.ts +4 -1
- package/dist/extension.js +1 -1
- package/dist/extensions/string.d.ts +2 -4
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/metadata-extension.d.ts +196 -0
- package/package.json +6 -3
- package/dist/chunk-54RHS4F4.js +0 -2
- package/dist/chunk-54RHS4F4.js.map +0 -1
- package/dist/chunk-6LSN7NXQ.js +0 -2
- package/dist/chunk-6LSN7NXQ.js.map +0 -1
- package/dist/chunk-C6YQOKWB.js +0 -2
- package/dist/chunk-C6YQOKWB.js.map +0 -1
- package/dist/chunk-ELPPAHNO.js +0 -2
- package/dist/chunk-ELPPAHNO.js.map +0 -1
- package/dist/chunk-G424M7GI.js +0 -2
- package/dist/chunk-G424M7GI.js.map +0 -1
- package/dist/chunk-JUFZ7PLO.js +0 -2
- package/dist/chunk-JUFZ7PLO.js.map +0 -1
- package/dist/chunk-K4ZLXLE2.js +0 -2
- package/dist/chunk-K4ZLXLE2.js.map +0 -1
- package/dist/chunk-KC45JEFL.js +0 -2
- package/dist/chunk-KC45JEFL.js.map +0 -1
- package/dist/chunk-NF4CRFMN.js +0 -2
- package/dist/chunk-NF4CRFMN.js.map +0 -1
- package/dist/chunk-ORV2G6ZL.js +0 -2
- package/dist/chunk-ORV2G6ZL.js.map +0 -1
- package/dist/chunk-PQINUGZW.js +0 -2
- package/dist/chunk-PQINUGZW.js.map +0 -1
- package/dist/chunk-REYZ7G7J.js +0 -2
- package/dist/chunk-REYZ7G7J.js.map +0 -1
- package/dist/chunk-VSU5GILY.js +0 -2
- package/dist/chunk-VSU5GILY.js.map +0 -1
- package/dist/chunk-XL723XFL.js +0 -2
- package/dist/chunk-XL723XFL.js.map +0 -1
- package/dist/chunk-XPLTW5DI.js +0 -2
- package/dist/chunk-XPLTW5DI.js.map +0 -1
- package/dist/chunk-YAOZEA2R.js +0 -2
- package/dist/chunk-YAOZEA2R.js.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (C) 2024 by Andrew Zolotuhkin <andrew_zol@cleverbrush.com>
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
9
|
+
this list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its contributors
|
|
16
|
+
may be used to endorse or promote products derived from this software
|
|
17
|
+
without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
CHANGED
|
@@ -7,13 +7,37 @@
|
|
|
7
7
|
<!-- bundle-badge-end -->
|
|
8
8
|
[](../../LICENSE)
|
|
9
9
|
<!-- coverage-badge-start -->
|
|
10
|
-

|
|
11
11
|
<!-- coverage-badge-end -->
|
|
12
12
|
|
|
13
13
|
A schema definition and validation library for TypeScript — faster than Zod in 14/15 benchmarks (up to 204× faster on invalid input), 3× smaller than Zod v4, and compatible with 50+ ecosystem tools via [Standard Schema v1](https://standardschema.dev/).
|
|
14
14
|
|
|
15
15
|
Define a schema **once** and get TypeScript type inference, runtime validation, object mapping ([`@cleverbrush/mapper`](../mapper)), auto-generated React forms ([`@cleverbrush/react-form`](../react-form)), and bidirectional JSON Schema conversion ([`@cleverbrush/schema-json`](../schema-json)) — all from the same immutable, fluent API.
|
|
16
16
|
|
|
17
|
+
## Indexed property descriptors
|
|
18
|
+
|
|
19
|
+
Array descriptors keep their whole-array binding and expose lazy, cached indexed
|
|
20
|
+
children for primitive, object and nested-array elements:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { object, array, string, SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR } from '@cleverbrush/schema';
|
|
24
|
+
const Profile = object({ addresses: array(object({ city: string().minLength(2) })) });
|
|
25
|
+
const profile = { addresses: [{ city: 'Rome' }] };
|
|
26
|
+
const properties = object.getPropertiesFor(Profile);
|
|
27
|
+
const city = properties.addresses[0].city[SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR];
|
|
28
|
+
city.toJsonPointer(); // '/addresses/0/city'
|
|
29
|
+
city.setValue(profile, 'Paris', { createMissingStructure: true });
|
|
30
|
+
const result = Profile.validate(profile, { doNotStopOnFirstError: true });
|
|
31
|
+
result.getErrorsFor(t => t.addresses[0].city);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Both sync and async validation expose precise indexed paths in
|
|
35
|
+
`getInvalidProperties()`, while retaining aggregate array errors. Indexed setters
|
|
36
|
+
create actual arrays when requested; with `createMissingStructure: false` they
|
|
37
|
+
do not create missing containers. Valid indices are canonical non-negative array
|
|
38
|
+
indices, not negative/fractional positions. Descriptors are positional, not keyed
|
|
39
|
+
item identities, and do not add array mutation methods to the descriptor tree.
|
|
40
|
+
|
|
17
41
|
## Why @cleverbrush/schema?
|
|
18
42
|
|
|
19
43
|
**The problem:** In a typical TypeScript project, types and runtime validation are separate concerns. You define a `User` type in one file, then write Joi / Yup / Zod schemas (or manual `if` checks) in another. Over time these drift apart — the type says a field is required, but the validation allows it to be `undefined`. Tests pass, but production data breaks because the validation didn't match the type.
|
|
@@ -98,10 +122,6 @@ if (result.valid) {
|
|
|
98
122
|
const nameErrors = result.getErrorsFor((p) => p.name);
|
|
99
123
|
console.log(nameErrors.isValid); // false
|
|
100
124
|
console.log(nameErrors.errors); // ['Name must be at least 2 characters']
|
|
101
|
-
|
|
102
|
-
// result.errors on object schemas is deprecated — use getErrorsFor() instead
|
|
103
|
-
console.log('Errors:', result.errors);
|
|
104
|
-
// Array of { message: string }
|
|
105
125
|
}
|
|
106
126
|
```
|
|
107
127
|
|
|
@@ -694,7 +714,7 @@ const result = ShapeSchema.validate({ type: 'circle', radius: 5 });
|
|
|
694
714
|
|
|
695
715
|
### Real-World Example: Job Scheduler
|
|
696
716
|
|
|
697
|
-
|
|
717
|
+
An application's schedule-input form can use this pattern. The `every` field acts as the discriminator, and each variant adds its own set of allowed properties:
|
|
698
718
|
|
|
699
719
|
```typescript
|
|
700
720
|
import { object, string, number, array, date, union, type InferType } from '@cleverbrush/schema';
|
|
@@ -841,8 +861,7 @@ const result = UserSchema.validate(someObject);
|
|
|
841
861
|
if (result.valid) {
|
|
842
862
|
console.log(result.object); // typed as InferType<typeof UserSchema>
|
|
843
863
|
} else {
|
|
844
|
-
|
|
845
|
-
console.log(result.errors); // deprecated for object schemas — Array of { message: string }
|
|
864
|
+
console.log(result.getErrorsFor(t => t.name).errors); // field error strings
|
|
846
865
|
}
|
|
847
866
|
|
|
848
867
|
// Async validation (use when validators/preprocessors are async)
|
|
@@ -859,12 +878,12 @@ const result = UserSchema.validate(
|
|
|
859
878
|
{ doNotStopOnFirstError: true }
|
|
860
879
|
);
|
|
861
880
|
|
|
862
|
-
console.log(result.errors);
|
|
863
|
-
// [
|
|
864
|
-
|
|
865
|
-
//
|
|
866
|
-
|
|
867
|
-
// ]
|
|
881
|
+
console.log(result.getErrorsFor(t => t.name).errors);
|
|
882
|
+
// ['Name must be at least 2 characters']
|
|
883
|
+
console.log(result.getErrorsFor(t => t.email).errors);
|
|
884
|
+
// ['Please enter a valid email']
|
|
885
|
+
console.log(result.getErrorsFor(t => t.age).errors);
|
|
886
|
+
// ['Age cannot be negative']
|
|
868
887
|
```
|
|
869
888
|
|
|
870
889
|
### Custom Error Messages
|
|
@@ -955,11 +974,11 @@ result.getErrorsFor((t) => t.password).errors;
|
|
|
955
974
|
// → []
|
|
956
975
|
```
|
|
957
976
|
|
|
958
|
-
You can target multiple properties from a single validator by returning multiple errors with different `property` selectors. Errors without a `property` selector are attached to the root object
|
|
977
|
+
You can target multiple properties from a single validator by returning multiple errors with different `property` selectors. Errors without a `property` selector are attached to the root object.
|
|
959
978
|
|
|
960
979
|
### Per-Property Errors with `getErrorsFor()` (Recommended)
|
|
961
980
|
|
|
962
|
-
`ObjectSchemaBuilder.validate()` returns
|
|
981
|
+
`ObjectSchemaBuilder.validate()` returns a result with a `getErrorsFor()` method for inspecting errors on individual properties — useful for showing inline form errors:
|
|
963
982
|
|
|
964
983
|
```typescript
|
|
965
984
|
const PersonSchema = object({
|
|
@@ -1125,6 +1144,43 @@ console.log(info.hasCatch); // true
|
|
|
1125
1144
|
console.log(info.catchValue); // 'unknown'
|
|
1126
1145
|
```
|
|
1127
1146
|
|
|
1147
|
+
### Optional and nullable fallbacks
|
|
1148
|
+
|
|
1149
|
+
Fallback values and factories respect the schema's resolved output type:
|
|
1150
|
+
optional schemas allow `undefined`, and nullable schemas allow `null`.
|
|
1151
|
+
|
|
1152
|
+
```typescript
|
|
1153
|
+
const optionalText = string().optional().catch(undefined);
|
|
1154
|
+
const nullableText = string().nullable().catch(() => null);
|
|
1155
|
+
|
|
1156
|
+
optionalText.parse(42); // undefined
|
|
1157
|
+
nullableText.parse(42); // null
|
|
1158
|
+
object({ text: optionalText }).parse({ text: false }); // { text: undefined }
|
|
1159
|
+
array(optionalText).parse(['ok', 42]); // ['ok', undefined] — no entries dropped
|
|
1160
|
+
```
|
|
1161
|
+
|
|
1162
|
+
Fallbacks are opt-in: a fallback on a property does not make a malformed required
|
|
1163
|
+
root object valid. A fallback factory runs only when validation fails.
|
|
1164
|
+
|
|
1165
|
+
**Null handling:** optional schemas accept `null` at runtime even
|
|
1166
|
+
though their inferred type does not include it. `.optional().catch(undefined)`
|
|
1167
|
+
therefore leaves `null` unchanged. Normalize it explicitly when needed:
|
|
1168
|
+
|
|
1169
|
+
```typescript
|
|
1170
|
+
const normalizedText = string().optional()
|
|
1171
|
+
.addPreprocessor(value => value == null ? undefined : value)
|
|
1172
|
+
.catch(undefined);
|
|
1173
|
+
|
|
1174
|
+
normalizedText.parse(null); // undefined
|
|
1175
|
+
```
|
|
1176
|
+
|
|
1177
|
+
Preprocessors can return optional/nullable values, including asynchronously.
|
|
1178
|
+
Their existing callback parameter typing does not guarantee that unknown input
|
|
1179
|
+
already has that type: guard untrusted values before using type-specific methods.
|
|
1180
|
+
Use `parseAsync` / `validateAsync` for async preprocessors or validators.
|
|
1181
|
+
`InferType` and `hasType` keep their existing meaning; static overrides and casts
|
|
1182
|
+
do not perform runtime conversion or validation.
|
|
1183
|
+
|
|
1128
1184
|
## Readonly Modifier
|
|
1129
1185
|
|
|
1130
1186
|
Every schema builder supports `.readonly()`. This is a **type-level-only** modifier — it marks the inferred TypeScript type as immutable, but does not alter validation behaviour or freeze the validated value at runtime.
|
|
@@ -1189,7 +1245,7 @@ export const UserSchema = object({
|
|
|
1189
1245
|
UserSchema.introspect().schemaName; // 'User'
|
|
1190
1246
|
```
|
|
1191
1247
|
|
|
1192
|
-
|
|
1248
|
+
Annotations can be applied after naming a definition:
|
|
1193
1249
|
|
|
1194
1250
|
```typescript
|
|
1195
1251
|
const ProductSchema = object({
|
|
@@ -1210,12 +1266,64 @@ import { generateOpenApiSpec } from '@cleverbrush/server-openapi';
|
|
|
1210
1266
|
generateOpenApiSpec({ registrations, info: { title: 'My API', version: '1.0.0' } });
|
|
1211
1267
|
```
|
|
1212
1268
|
|
|
1213
|
-
|
|
1269
|
+
### Reusing a named definition
|
|
1270
|
+
|
|
1271
|
+
Use the plain constant directly, or apply ordinary use-site modifiers. No wrapper
|
|
1272
|
+
is needed; the concrete builder, fluent and extension methods, inferred types,
|
|
1273
|
+
and nested property selectors are preserved. The original remains unchanged.
|
|
1274
|
+
|
|
1275
|
+
```typescript
|
|
1276
|
+
const History = object({
|
|
1277
|
+
current: UserSchema,
|
|
1278
|
+
previous: UserSchema.optional().nullable().describe('Previous user')
|
|
1279
|
+
});
|
|
1280
|
+
// One canonical User component; previous has local annotations/nullability.
|
|
1281
|
+
```
|
|
1282
|
+
|
|
1283
|
+
These modifiers retain the canonical named definition for document exporters:
|
|
1284
|
+
|
|
1285
|
+
- Presence/nullability: `optional`, `required`, `nullable`, `notNullable`.
|
|
1286
|
+
- Annotations: `describe`, `example`, `readonly`.
|
|
1287
|
+
- Type-only changes: `brand`, `hasType`, `clearHasType`, `optimize`.
|
|
1288
|
+
|
|
1289
|
+
Modifier chains reference the original definition, not another alias. JSON Schema,
|
|
1290
|
+
OpenAPI and AsyncAPI compose local annotations and nullability around that
|
|
1291
|
+
definition, including Draft 07 references. Runtime validation still follows the
|
|
1292
|
+
ordinary builder's behavior; canonical-reference metadata is for exporters.
|
|
1293
|
+
|
|
1294
|
+
### Shape and rule changes discard inherited names
|
|
1295
|
+
|
|
1296
|
+
Property additions/removals, `partial`, `pick`, `omit`, constraints, validators,
|
|
1297
|
+
preprocessors, defaults, fallbacks and their available clear methods produce
|
|
1298
|
+
unnamed derivatives. Extension changes detach conservatively too. Later
|
|
1299
|
+
annotations or optionality do not reconnect the derivative to the original.
|
|
1300
|
+
|
|
1301
|
+
```typescript
|
|
1302
|
+
const PatchUser = UserSchema.partial(); // unnamed, changed shape
|
|
1303
|
+
const UserWithEmail = UserSchema.addProp('email', string()); // unnamed
|
|
1304
|
+
const PublicUser = UserSchema.omit('id').schemaName('PublicUser'); // new definition
|
|
1305
|
+
const ShortName = string().schemaName('Name').maxLength(20); // unnamed rule change
|
|
1306
|
+
```
|
|
1307
|
+
|
|
1308
|
+
Existing nested named schemas still reuse their own definitions. Apply
|
|
1309
|
+
`schemaName` **after** shape/rule edits when the result needs a stable component
|
|
1310
|
+
name. This changes inherited-name behavior: code that relied on property or
|
|
1311
|
+
constraint edits retaining a name should name the final result explicitly.
|
|
1312
|
+
|
|
1313
|
+
Defaults and fallbacks keep ordinary builder semantics. Adding or clearing them
|
|
1314
|
+
detaches the inherited name; `clearDefault()` removes the default completely,
|
|
1315
|
+
without revealing a hidden default from the canonical definition.
|
|
1316
|
+
|
|
1317
|
+
> **Name uniqueness:** Independent definitions with the same name still conflict,
|
|
1318
|
+
> even with identical shapes; there is no name-only or structural deduplication.
|
|
1319
|
+
> Use-site modifiers reuse the original definition and do not conflict. Calling
|
|
1320
|
+
> `schemaName` explicitly always establishes a fresh independent definition,
|
|
1321
|
+
> even on an alias or when the previous name is reused.
|
|
1214
1322
|
|
|
1215
1323
|
| Method / Property | Signature | Notes |
|
|
1216
1324
|
|---|---|---|
|
|
1217
1325
|
| `.schemaName(name)` | `schemaName(name: string): this` | Returns a new builder; original is unchanged |
|
|
1218
|
-
| `.introspect().schemaName` | `string \| undefined` | The
|
|
1326
|
+
| `.introspect().schemaName` | `string \| undefined` | The explicit or preserved name; `undefined` after a shape/rule change |
|
|
1219
1327
|
|
|
1220
1328
|
## Describe
|
|
1221
1329
|
|
|
@@ -1452,6 +1560,55 @@ console.log(priceSchema.introspect().extensions.currency);
|
|
|
1452
1560
|
// { maxDecimals: 4 } — structured metadata, not the raw args
|
|
1453
1561
|
```
|
|
1454
1562
|
|
|
1563
|
+
### Typed metadata methods
|
|
1564
|
+
|
|
1565
|
+
Use `defineMetadataMethod()` when a method only records metadata and its value
|
|
1566
|
+
must also be available to TypeScript consumers. It works inside the same
|
|
1567
|
+
`defineExtension()` / `withExtensions()` system:
|
|
1568
|
+
|
|
1569
|
+
```ts
|
|
1570
|
+
import {
|
|
1571
|
+
defineExtension, defineMetadataMethod, withExtensions,
|
|
1572
|
+
type InferExtensionMetadata, type InferType
|
|
1573
|
+
} from '@cleverbrush/schema';
|
|
1574
|
+
|
|
1575
|
+
const labels = defineExtension({
|
|
1576
|
+
string: {
|
|
1577
|
+
label: defineMetadataMethod('label').argument<string>(),
|
|
1578
|
+
internal: defineMetadataMethod('visibility').value('internal'),
|
|
1579
|
+
lengthHint: defineMetadataMethod('lengthHint').compute(
|
|
1580
|
+
(min: number, max: number) => ({ min, max })
|
|
1581
|
+
)
|
|
1582
|
+
}
|
|
1583
|
+
});
|
|
1584
|
+
const s = withExtensions(labels);
|
|
1585
|
+
const title = s.string().label('Title').internal().optional();
|
|
1586
|
+
type Value = InferType<typeof title>; // string | undefined
|
|
1587
|
+
type Label = InferExtensionMetadata<typeof title>['label']; // 'Title'
|
|
1588
|
+
|
|
1589
|
+
const renamed = title.label('Display name').lengthHint(1, 80);
|
|
1590
|
+
type UpdatedLabel = InferExtensionMetadata<typeof renamed>['label']; // 'Display name'
|
|
1591
|
+
renamed.introspect().extensions.lengthHint; // { min: 1, max: 80 }
|
|
1592
|
+
title.introspect().extensions.label; // 'Title' — original is unchanged
|
|
1593
|
+
```
|
|
1594
|
+
|
|
1595
|
+
- `.argument<T>()` creates a one-argument method constrained to `T` and retains
|
|
1596
|
+
the caller's literal type. Omit `T` to accept any metadata value.
|
|
1597
|
+
- `.value(value)` creates a zero-argument method storing a fixed value.
|
|
1598
|
+
- `.compute(fn)` retains the callback's parameter and return types. Use a literal
|
|
1599
|
+
or template-literal return type when that precision matters; arbitrary callback
|
|
1600
|
+
results cannot be evaluated by TypeScript.
|
|
1601
|
+
|
|
1602
|
+
The key passed to `defineMetadataMethod` controls runtime storage independently
|
|
1603
|
+
of the method name. A subsequent write replaces that key's value and inferred
|
|
1604
|
+
type. Metadata and ordinary extension methods compose through native modifiers
|
|
1605
|
+
without resetting optionality, nullability or defaults. Only factories produced
|
|
1606
|
+
by `withExtensions()` receive the methods; global builder prototypes are not
|
|
1607
|
+
modified. Metadata is descriptive: these helpers do not add validators, transform
|
|
1608
|
+
schema values or assign domain meaning to keys. Consumers decide how to use it.
|
|
1609
|
+
Ordinary `defineExtension()` methods remain appropriate for validation and other
|
|
1610
|
+
behavior; use `this.withExtension()` inside them for runtime-only metadata.
|
|
1611
|
+
|
|
1455
1612
|
### Stacking Extensions
|
|
1456
1613
|
|
|
1457
1614
|
Multiple extensions can be stacked — their methods are merged per builder type. A runtime error is thrown if two extensions define the same method name on the same builder type:
|
|
@@ -5,8 +5,8 @@ type AnySchemaBuilderCreateProps<R extends boolean = true> = Partial<ReturnType<
|
|
|
5
5
|
* in TypeScript. Allows to define a schema for `any` value.
|
|
6
6
|
* Use it when you don't know the type of the value.
|
|
7
7
|
*
|
|
8
|
-
* **NOTE** this class is exported
|
|
9
|
-
*
|
|
8
|
+
* **NOTE** this class is exported for type annotations and advanced use.
|
|
9
|
+
* Customize via extensions rather than subclassing. Avoid instantiating it
|
|
10
10
|
* directly. Use `any()` function instead.
|
|
11
11
|
*
|
|
12
12
|
* @example
|
|
@@ -19,6 +19,15 @@ type AnySchemaBuilderCreateProps<R extends boolean = true> = Partial<ReturnType<
|
|
|
19
19
|
*/
|
|
20
20
|
export declare class AnySchemaBuilder<TRequired extends boolean = true, TNullable extends boolean = false, TExplicitType = undefined, THasDefault extends boolean = false, TExtensions = {}, TResult = TExplicitType extends undefined ? any : TExplicitType> extends SchemaBuilder<TResult, TRequired, TNullable, THasDefault, TExtensions> {
|
|
21
21
|
#private;
|
|
22
|
+
/** Native type parameters for extension rebinding; never emitted at runtime. @internal */
|
|
23
|
+
readonly __cleverbrush_builder_type__: readonly [
|
|
24
|
+
'any',
|
|
25
|
+
TRequired,
|
|
26
|
+
TNullable,
|
|
27
|
+
TExplicitType,
|
|
28
|
+
THasDefault,
|
|
29
|
+
TResult
|
|
30
|
+
];
|
|
22
31
|
/**
|
|
23
32
|
* @hidden
|
|
24
33
|
*/
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a,b}from"../chunk-
|
|
1
|
+
import{a,b}from"../chunk-NDESVCWI.js";import"../chunk-2BKBVVZ3.js";export{a as AnySchemaBuilder,b as any};
|
|
2
2
|
//# sourceMappingURL=AnySchemaBuilder.js.map
|
|
@@ -37,13 +37,23 @@ type ArraySchemaBuilderCreateProps<TElementSchema extends SchemaBuilder<any, any
|
|
|
37
37
|
* Also you can limit the length of the array by using `minLength`
|
|
38
38
|
* and `maxLength` methods.
|
|
39
39
|
*
|
|
40
|
-
* **NOTE** this class is exported
|
|
41
|
-
*
|
|
40
|
+
* **NOTE** this class is exported for type annotations and advanced use.
|
|
41
|
+
* Customize via extensions rather than subclassing. Avoid instantiating it
|
|
42
42
|
* directly. Use {@link array | array()} function instead.
|
|
43
43
|
* @see {@link array}
|
|
44
44
|
*/
|
|
45
45
|
export declare class ArraySchemaBuilder<TElementSchema extends SchemaBuilder<any, any, any, any, any>, TRequired extends boolean = true, TNullable extends boolean = false, TExplicitType = undefined, THasDefault extends boolean = false, TExtensions = {}, TResult = TExplicitType extends undefined ? TElementSchema extends undefined ? Array<any> : TElementSchema extends SchemaBuilder<infer T1, infer T2> ? Array<InferType<SchemaBuilder<T1, T2>>> : never : TExplicitType> extends SchemaBuilder<TResult, TRequired, TNullable, THasDefault, TExtensions> {
|
|
46
46
|
#private;
|
|
47
|
+
/** Native type parameters for extension rebinding; never emitted at runtime. @internal */
|
|
48
|
+
readonly __cleverbrush_builder_type__: readonly [
|
|
49
|
+
'array',
|
|
50
|
+
TElementSchema,
|
|
51
|
+
TRequired,
|
|
52
|
+
TNullable,
|
|
53
|
+
TExplicitType,
|
|
54
|
+
THasDefault,
|
|
55
|
+
TResult
|
|
56
|
+
];
|
|
47
57
|
/**
|
|
48
58
|
* @hidden
|
|
49
59
|
*/
|
|
@@ -58,11 +68,11 @@ export declare class ArraySchemaBuilder<TElementSchema extends SchemaBuilder<any
|
|
|
58
68
|
*/
|
|
59
69
|
clearHasType(): ArraySchemaBuilder<TElementSchema, TRequired, TNullable, undefined, THasDefault, TExtensions> & TExtensions;
|
|
60
70
|
/**
|
|
61
|
-
*
|
|
71
|
+
* {@inheritDoc SchemaBuilder.validate}
|
|
62
72
|
*/
|
|
63
73
|
validate(object: TResult, context?: ValidationContext): ArraySchemaValidationResult<TResult, TElementSchema>;
|
|
64
74
|
/**
|
|
65
|
-
*
|
|
75
|
+
* {@inheritDoc SchemaBuilder.validateAsync}
|
|
66
76
|
*/
|
|
67
77
|
validateAsync(object: TResult, context?: ValidationContext): Promise<ArraySchemaValidationResult<TResult, TElementSchema>>;
|
|
68
78
|
/**
|
|
@@ -148,6 +158,7 @@ export declare class ArraySchemaBuilder<TElementSchema extends SchemaBuilder<any
|
|
|
148
158
|
defaultValue: TResult | (() => TResult) | undefined;
|
|
149
159
|
description: string | undefined;
|
|
150
160
|
schemaName: string | undefined;
|
|
161
|
+
referenceTarget: SchemaBuilder<any, any, any, any, any> | undefined;
|
|
151
162
|
hasCatch: boolean;
|
|
152
163
|
catchValue: TResult | (() => TResult) | undefined;
|
|
153
164
|
example: unknown;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a,b}from"../chunk-
|
|
1
|
+
import{a,b}from"../chunk-XASMTNON.js";import"../chunk-2BKBVVZ3.js";export{a as ArraySchemaBuilder,b as array};
|
|
2
2
|
//# sourceMappingURL=ArraySchemaBuilder.js.map
|
|
@@ -5,23 +5,26 @@ type BooleanSchemaBuilderCreateProps<R extends boolean = true> = Partial<ReturnT
|
|
|
5
5
|
* Allows to define a schema for a boolean value. It can be required or optional.
|
|
6
6
|
* It can be restricted to be equal to a certain value.
|
|
7
7
|
*
|
|
8
|
-
* **NOTE** this class is exported
|
|
9
|
-
*
|
|
8
|
+
* **NOTE** this class is exported for type annotations and advanced use.
|
|
9
|
+
* Customize via extensions rather than subclassing. Avoid instantiating it
|
|
10
10
|
* directly. Use {@link boolean | boolean()} function instead.
|
|
11
11
|
*
|
|
12
|
-
* @example
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
13
14
|
* const schema = boolean().equals(true);
|
|
14
15
|
* const result = schema.validate(true);
|
|
15
16
|
* // result.valid === true
|
|
16
17
|
* // result.object === true
|
|
17
18
|
* ```
|
|
18
|
-
* @example
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
19
21
|
* const schema = boolean().equals(false);
|
|
20
22
|
* const result = schema.validate(true);
|
|
21
23
|
* // result.valid === false
|
|
22
24
|
* // result.errors[0].message === 'is expected to be equal to 'false''
|
|
23
25
|
* ```
|
|
24
|
-
* @example
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
25
28
|
* const schema = boolean().equals(true).optional();
|
|
26
29
|
* const result = schema.validate(undefined);
|
|
27
30
|
* // result.valid === true
|
|
@@ -32,6 +35,16 @@ type BooleanSchemaBuilderCreateProps<R extends boolean = true> = Partial<ReturnT
|
|
|
32
35
|
*/
|
|
33
36
|
export declare class BooleanSchemaBuilder<TResult = boolean, TRequired extends boolean = true, TNullable extends boolean = false, TExplicitType = undefined, THasDefault extends boolean = false, TExtensions = {}, TFinalResult = TExplicitType extends undefined ? TResult : TExplicitType> extends SchemaBuilder<TFinalResult, TRequired, TNullable, THasDefault, TExtensions> {
|
|
34
37
|
#private;
|
|
38
|
+
/** Native type parameters for extension rebinding; never emitted at runtime. @internal */
|
|
39
|
+
readonly __cleverbrush_builder_type__: readonly [
|
|
40
|
+
'boolean',
|
|
41
|
+
TResult,
|
|
42
|
+
TRequired,
|
|
43
|
+
TNullable,
|
|
44
|
+
TExplicitType,
|
|
45
|
+
THasDefault,
|
|
46
|
+
TFinalResult
|
|
47
|
+
];
|
|
35
48
|
/**
|
|
36
49
|
* @hidden
|
|
37
50
|
*/
|
|
@@ -61,6 +74,7 @@ export declare class BooleanSchemaBuilder<TResult = boolean, TRequired extends b
|
|
|
61
74
|
defaultValue: TFinalResult | (() => TFinalResult) | undefined;
|
|
62
75
|
description: string | undefined;
|
|
63
76
|
schemaName: string | undefined;
|
|
77
|
+
referenceTarget: SchemaBuilder<any, any, any, any, any> | undefined;
|
|
64
78
|
hasCatch: boolean;
|
|
65
79
|
catchValue: TFinalResult | (() => TFinalResult) | undefined;
|
|
66
80
|
example: unknown;
|
|
@@ -137,7 +151,8 @@ export declare class BooleanSchemaBuilder<TResult = boolean, TRequired extends b
|
|
|
137
151
|
* Accepts `"true"` → `true` and `"false"` → `false`; other values are
|
|
138
152
|
* left unchanged so the boolean schema rejects them.
|
|
139
153
|
*
|
|
140
|
-
* @example
|
|
154
|
+
* @example
|
|
155
|
+
* ```ts
|
|
141
156
|
* const schema = boolean().coerce();
|
|
142
157
|
* const result = schema.validate('true');
|
|
143
158
|
* // result.valid === true
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a,b}from"../chunk-
|
|
1
|
+
import{a,b}from"../chunk-D7RXO2FA.js";import"../chunk-2BKBVVZ3.js";export{a as BooleanSchemaBuilder,b as boolean};
|
|
2
2
|
//# sourceMappingURL=BooleanSchemaBuilder.js.map
|
|
@@ -5,33 +5,37 @@ type DateSchemaBuilderCreateProps<T = Date, R extends boolean = true> = Partial<
|
|
|
5
5
|
* It can be restricted to be: equal to a certain value, in future, in past, in a certain range.
|
|
6
6
|
* Supports parsing from JSON string and UNIX epoch (using preprocessors).
|
|
7
7
|
*
|
|
8
|
-
* **NOTE** this class is exported
|
|
9
|
-
*
|
|
8
|
+
* **NOTE** this class is exported for type annotations and advanced use.
|
|
9
|
+
* Customize via extensions rather than subclassing. Avoid instantiating it
|
|
10
10
|
* directly. Use {@link date | date()} function instead.
|
|
11
11
|
*
|
|
12
|
-
* @example
|
|
13
|
-
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* const value = new Date(2020, 0, 2);
|
|
14
15
|
* const schema = date().min(new Date(2020, 0, 1));
|
|
15
|
-
* const result = schema.validate(
|
|
16
|
+
* const result = schema.validate(value);
|
|
16
17
|
* // result.valid === true
|
|
17
|
-
* // result.object ===
|
|
18
|
+
* // result.object === value
|
|
18
19
|
* ```
|
|
19
20
|
*
|
|
20
|
-
* @example
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
21
23
|
* const schema = date();
|
|
22
24
|
* const result = schema.validate('2020-01-01');
|
|
23
25
|
* // result.valid === false
|
|
24
26
|
* // result.errors[0].message === 'is expected to be a date'
|
|
25
27
|
* ```
|
|
26
28
|
*
|
|
27
|
-
* @example
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
28
31
|
* const schema = date().parseFromJson();
|
|
29
32
|
* const result = schema.validate('2020-01-01T00:00:00.000Z');
|
|
30
33
|
* // result.valid === true
|
|
31
34
|
* // result.object is equal to corresponding Date object
|
|
32
35
|
* ```
|
|
33
36
|
*
|
|
34
|
-
* @example
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
35
39
|
* const schema = date().parseFromEpoch();
|
|
36
40
|
* const result = schema.validate(1577836800000);
|
|
37
41
|
* // result.valid === true
|
|
@@ -42,6 +46,14 @@ type DateSchemaBuilderCreateProps<T = Date, R extends boolean = true> = Partial<
|
|
|
42
46
|
*/
|
|
43
47
|
export declare class DateSchemaBuilder<TResult = Date, TRequired extends boolean = true, TNullable extends boolean = false, THasDefault extends boolean = false, TExtensions = {}> extends SchemaBuilder<TResult, TRequired, TNullable, THasDefault, TExtensions> {
|
|
44
48
|
#private;
|
|
49
|
+
/** Native type parameters for extension rebinding; never emitted at runtime. @internal */
|
|
50
|
+
readonly __cleverbrush_builder_type__: readonly [
|
|
51
|
+
'date',
|
|
52
|
+
TResult,
|
|
53
|
+
TRequired,
|
|
54
|
+
TNullable,
|
|
55
|
+
THasDefault
|
|
56
|
+
];
|
|
45
57
|
/**
|
|
46
58
|
* @hidden
|
|
47
59
|
*/
|
|
@@ -123,6 +135,7 @@ export declare class DateSchemaBuilder<TResult = Date, TRequired extends boolean
|
|
|
123
135
|
defaultValue: TResult | (() => TResult) | undefined;
|
|
124
136
|
description: string | undefined;
|
|
125
137
|
schemaName: string | undefined;
|
|
138
|
+
referenceTarget: SchemaBuilder<any, any, any, any, any> | undefined;
|
|
126
139
|
hasCatch: boolean;
|
|
127
140
|
catchValue: TResult | (() => TResult) | undefined;
|
|
128
141
|
example: unknown;
|
|
@@ -255,7 +268,8 @@ export declare class DateSchemaBuilder<TResult = Date, TRequired extends boolean
|
|
|
255
268
|
* For more specific parsing, see {@link acceptJsonString} and
|
|
256
269
|
* {@link acceptEpoch}.
|
|
257
270
|
*
|
|
258
|
-
* @example
|
|
271
|
+
* @example
|
|
272
|
+
* ```ts
|
|
259
273
|
* const schema = date().coerce();
|
|
260
274
|
* const result = schema.validate('2024-01-15');
|
|
261
275
|
* // result.valid === true
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a,b}from"../chunk-
|
|
1
|
+
import{a,b}from"../chunk-66U6MMJ2.js";import"../chunk-2BKBVVZ3.js";export{a as DateSchemaBuilder,b as date};
|
|
2
2
|
//# sourceMappingURL=DateSchemaBuilder.js.map
|
|
@@ -22,8 +22,8 @@ type ExternSchemaBuilderCreateProps<R extends boolean = true> = Partial<ReturnTy
|
|
|
22
22
|
* so `getErrorsFor(t => t.order.id)` works without any additional
|
|
23
23
|
* configuration.
|
|
24
24
|
*
|
|
25
|
-
* **NOTE** this class is exported
|
|
26
|
-
*
|
|
25
|
+
* **NOTE** this class is exported for type annotations and advanced use.
|
|
26
|
+
* Customize via extensions rather than subclassing. Avoid instantiating it
|
|
27
27
|
* directly. Use the {@link extern | extern()} factory function instead.
|
|
28
28
|
*
|
|
29
29
|
* @example
|
|
@@ -108,6 +108,7 @@ export declare class ExternSchemaBuilder<TStandardSchema extends StandardSchemaV
|
|
|
108
108
|
defaultValue: TResult | (() => TResult) | undefined;
|
|
109
109
|
description: string | undefined;
|
|
110
110
|
schemaName: string | undefined;
|
|
111
|
+
referenceTarget: SchemaBuilder<any, any, any, any, any> | undefined;
|
|
111
112
|
hasCatch: boolean;
|
|
112
113
|
catchValue: TResult | (() => TResult) | undefined;
|
|
113
114
|
example: unknown;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a,b}from"../chunk-
|
|
1
|
+
import{a,b}from"../chunk-K7TDPKGQ.js";import"../chunk-2BKBVVZ3.js";export{a as ExternSchemaBuilder,b as extern};
|
|
2
2
|
//# sourceMappingURL=ExternSchemaBuilder.js.map
|
|
@@ -8,8 +8,8 @@ type InferParameters<TParams extends SchemaBuilder<any, any, any, any, any>[]> =
|
|
|
8
8
|
* It can be required or optional, and may carry typed parameter and return-type
|
|
9
9
|
* schemas so that the inferred TypeScript function signature is fully typed.
|
|
10
10
|
*
|
|
11
|
-
* **NOTE** this class is exported
|
|
12
|
-
*
|
|
11
|
+
* **NOTE** this class is exported for type annotations and advanced use.
|
|
12
|
+
* Customize via extensions rather than subclassing. Avoid instantiating it
|
|
13
13
|
* directly. Use {@link func | func()} function instead.
|
|
14
14
|
*
|
|
15
15
|
* @example Basic validation
|
|
@@ -50,6 +50,17 @@ type InferParameters<TParams extends SchemaBuilder<any, any, any, any, any>[]> =
|
|
|
50
50
|
*/
|
|
51
51
|
export declare class FunctionSchemaBuilder<TRequired extends boolean = true, TNullable extends boolean = false, TExplicitType = undefined, THasDefault extends boolean = false, TExtensions = {}, TParameters extends SchemaBuilder<any, any, any, any, any>[] = [], TReturnTypeSchema extends SchemaBuilder<any, any, any, any, any> | undefined = undefined, TResult = TExplicitType extends undefined ? (...args: TParameters extends [] ? any[] : InferParameters<TParameters>) => TReturnTypeSchema extends SchemaBuilder<any, any, any, any, any> ? InferType<TReturnTypeSchema> : any : TExplicitType> extends SchemaBuilder<TResult, TRequired, TNullable, THasDefault, TExtensions> {
|
|
52
52
|
#private;
|
|
53
|
+
/** Native type parameters for extension rebinding; never emitted at runtime. @internal */
|
|
54
|
+
readonly __cleverbrush_builder_type__: readonly [
|
|
55
|
+
'func',
|
|
56
|
+
TRequired,
|
|
57
|
+
TNullable,
|
|
58
|
+
TExplicitType,
|
|
59
|
+
THasDefault,
|
|
60
|
+
TParameters,
|
|
61
|
+
TReturnTypeSchema,
|
|
62
|
+
TResult
|
|
63
|
+
];
|
|
53
64
|
/**
|
|
54
65
|
* @hidden
|
|
55
66
|
*/
|
|
@@ -106,6 +117,7 @@ export declare class FunctionSchemaBuilder<TRequired extends boolean = true, TNu
|
|
|
106
117
|
defaultValue: TResult | (() => TResult) | undefined;
|
|
107
118
|
description: string | undefined;
|
|
108
119
|
schemaName: string | undefined;
|
|
120
|
+
referenceTarget: SchemaBuilder<any, any, any, any, any> | undefined;
|
|
109
121
|
hasCatch: boolean;
|
|
110
122
|
catchValue: TResult | (() => TResult) | undefined;
|
|
111
123
|
example: unknown;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a,b}from"../chunk-
|
|
1
|
+
import{a,b}from"../chunk-BMA2X7LI.js";import"../chunk-2BKBVVZ3.js";export{a as FunctionSchemaBuilder,b as func};
|
|
2
2
|
//# sourceMappingURL=FunctionSchemaBuilder.js.map
|