@cleverbrush/schema 4.5.0 → 5.0.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.
Files changed (110) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +176 -19
  3. package/dist/builders/AnySchemaBuilder.d.ts +11 -2
  4. package/dist/builders/AnySchemaBuilder.js +1 -1
  5. package/dist/builders/ArraySchemaBuilder.d.ts +15 -4
  6. package/dist/builders/ArraySchemaBuilder.js +1 -1
  7. package/dist/builders/BooleanSchemaBuilder.d.ts +21 -6
  8. package/dist/builders/BooleanSchemaBuilder.js +1 -1
  9. package/dist/builders/DateSchemaBuilder.d.ts +24 -10
  10. package/dist/builders/DateSchemaBuilder.js +1 -1
  11. package/dist/builders/ExternSchemaBuilder.d.ts +3 -2
  12. package/dist/builders/ExternSchemaBuilder.js +1 -1
  13. package/dist/builders/FunctionSchemaBuilder.d.ts +14 -2
  14. package/dist/builders/FunctionSchemaBuilder.js +1 -1
  15. package/dist/builders/GenericSchemaBuilder.d.ts +14 -3
  16. package/dist/builders/IntersectionSchemaBuilder.d.ts +1 -0
  17. package/dist/builders/LazySchemaBuilder.d.ts +1 -0
  18. package/dist/builders/NullSchemaBuilder.d.ts +2 -4
  19. package/dist/builders/NumberSchemaBuilder.d.ts +21 -7
  20. package/dist/builders/NumberSchemaBuilder.js +1 -1
  21. package/dist/builders/ObjectSchemaBuilder.d.ts +15 -4
  22. package/dist/builders/ObjectSchemaBuilder.js +1 -1
  23. package/dist/builders/ParseStringSchemaBuilder.d.ts +1 -0
  24. package/dist/builders/ParseStringSchemaBuilder.js +1 -1
  25. package/dist/builders/PromiseSchemaBuilder.d.ts +13 -2
  26. package/dist/builders/PromiseSchemaBuilder.js +1 -1
  27. package/dist/builders/RecordSchemaBuilder.d.ts +12 -0
  28. package/dist/builders/RecordSchemaBuilder.js +1 -1
  29. package/dist/builders/SchemaBuilder.d.ts +59 -10
  30. package/dist/builders/StringSchemaBuilder.d.ts +23 -8
  31. package/dist/builders/StringSchemaBuilder.js +1 -1
  32. package/dist/builders/TupleSchemaBuilder.d.ts +16 -4
  33. package/dist/builders/TupleSchemaBuilder.js +1 -1
  34. package/dist/builders/UnionSchemaBuilder.d.ts +12 -2
  35. package/dist/builders/UnionSchemaBuilder.js +1 -1
  36. package/dist/chunk-25KL2NBJ.js +2 -0
  37. package/dist/chunk-25KL2NBJ.js.map +1 -0
  38. package/dist/chunk-2BKBVVZ3.js +2 -0
  39. package/dist/chunk-2BKBVVZ3.js.map +1 -0
  40. package/dist/chunk-3E5M6GRR.js +2 -0
  41. package/dist/chunk-3E5M6GRR.js.map +1 -0
  42. package/dist/chunk-66U6MMJ2.js +2 -0
  43. package/dist/chunk-66U6MMJ2.js.map +1 -0
  44. package/dist/chunk-BMA2X7LI.js +2 -0
  45. package/dist/chunk-BMA2X7LI.js.map +1 -0
  46. package/dist/chunk-BTR3ZGES.js +2 -0
  47. package/dist/chunk-BTR3ZGES.js.map +1 -0
  48. package/dist/chunk-CR2QIV5I.js +2 -0
  49. package/dist/chunk-CR2QIV5I.js.map +1 -0
  50. package/dist/chunk-D7RXO2FA.js +2 -0
  51. package/dist/chunk-D7RXO2FA.js.map +1 -0
  52. package/dist/chunk-JEBLDVKG.js +2 -0
  53. package/dist/chunk-JEBLDVKG.js.map +1 -0
  54. package/dist/chunk-JH7VLA6C.js +2 -0
  55. package/dist/chunk-JH7VLA6C.js.map +1 -0
  56. package/dist/chunk-K7TDPKGQ.js +2 -0
  57. package/dist/chunk-K7TDPKGQ.js.map +1 -0
  58. package/dist/chunk-NDESVCWI.js +2 -0
  59. package/dist/chunk-NDESVCWI.js.map +1 -0
  60. package/dist/chunk-VBPZRO7L.js +2 -0
  61. package/dist/chunk-VBPZRO7L.js.map +1 -0
  62. package/dist/chunk-W5D22D4P.js +2 -0
  63. package/dist/chunk-W5D22D4P.js.map +1 -0
  64. package/dist/{chunk-XHSBY2QK.js → chunk-X6CT6I2V.js} +2 -2
  65. package/dist/{chunk-XHSBY2QK.js.map → chunk-X6CT6I2V.js.map} +1 -1
  66. package/dist/chunk-XASMTNON.js +2 -0
  67. package/dist/chunk-XASMTNON.js.map +1 -0
  68. package/dist/chunk-ZYWDTLNL.js +2 -0
  69. package/dist/chunk-ZYWDTLNL.js.map +1 -0
  70. package/dist/core.d.ts +3 -3
  71. package/dist/core.js +1 -1
  72. package/dist/extension.d.ts +4 -1
  73. package/dist/extension.js +1 -1
  74. package/dist/extensions/string.d.ts +2 -4
  75. package/dist/index.js +1 -1
  76. package/dist/index.js.map +1 -1
  77. package/dist/metadata-extension.d.ts +196 -0
  78. package/package.json +6 -3
  79. package/dist/chunk-54RHS4F4.js +0 -2
  80. package/dist/chunk-54RHS4F4.js.map +0 -1
  81. package/dist/chunk-6LSN7NXQ.js +0 -2
  82. package/dist/chunk-6LSN7NXQ.js.map +0 -1
  83. package/dist/chunk-C6YQOKWB.js +0 -2
  84. package/dist/chunk-C6YQOKWB.js.map +0 -1
  85. package/dist/chunk-ELPPAHNO.js +0 -2
  86. package/dist/chunk-ELPPAHNO.js.map +0 -1
  87. package/dist/chunk-G424M7GI.js +0 -2
  88. package/dist/chunk-G424M7GI.js.map +0 -1
  89. package/dist/chunk-JUFZ7PLO.js +0 -2
  90. package/dist/chunk-JUFZ7PLO.js.map +0 -1
  91. package/dist/chunk-K4ZLXLE2.js +0 -2
  92. package/dist/chunk-K4ZLXLE2.js.map +0 -1
  93. package/dist/chunk-KC45JEFL.js +0 -2
  94. package/dist/chunk-KC45JEFL.js.map +0 -1
  95. package/dist/chunk-NF4CRFMN.js +0 -2
  96. package/dist/chunk-NF4CRFMN.js.map +0 -1
  97. package/dist/chunk-ORV2G6ZL.js +0 -2
  98. package/dist/chunk-ORV2G6ZL.js.map +0 -1
  99. package/dist/chunk-PQINUGZW.js +0 -2
  100. package/dist/chunk-PQINUGZW.js.map +0 -1
  101. package/dist/chunk-REYZ7G7J.js +0 -2
  102. package/dist/chunk-REYZ7G7J.js.map +0 -1
  103. package/dist/chunk-VSU5GILY.js +0 -2
  104. package/dist/chunk-VSU5GILY.js.map +0 -1
  105. package/dist/chunk-XL723XFL.js +0 -2
  106. package/dist/chunk-XL723XFL.js.map +0 -1
  107. package/dist/chunk-XPLTW5DI.js +0 -2
  108. package/dist/chunk-XPLTW5DI.js.map +0 -1
  109. package/dist/chunk-YAOZEA2R.js +0 -2
  110. 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: BSD-3-Clause](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)](../../LICENSE)
9
9
  <!-- coverage-badge-start -->
10
- ![Coverage](https://img.shields.io/badge/coverage-97.7%25-brightgreen)
10
+ ![Unit coverage](https://img.shields.io/badge/unit_coverage-97.7%25-brightgreen)
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
- The `@cleverbrush/scheduler` library uses this exact pattern to validate job schedules. The `every` field acts as the discriminator, and each variant adds its own set of allowed properties:
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
- // For object schemas, prefer getErrorsFor() for per-property error inspection (see below)
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
- // { message: 'Name must be at least 2 characters' },
865
- // { message: 'Please enter a valid email' },
866
- // { message: 'Age cannot be negative' }
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 as before.
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 an extended result with a `getErrorsFor()` method for inspecting errors on individual properties — perfect for showing inline form errors. **This is the recommended way to inspect validation errors on object schemas** and replaces the deprecated `errors` array on `ObjectSchemaValidationResult`:
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
- Chains naturally with all other modifiers:
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
- > **Name uniqueness:** Registering two *different* schema instances under the same name throws an error. Always export named schemas as constants and reuse the same reference everywhere.
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 name passed to `.schemaName()`, or `undefined` |
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 only to give opportunity to extend it
9
- * by inheriting. It is not recommended to create an instance of this class
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-XPLTW5DI.js";import"../chunk-REYZ7G7J.js";export{a as AnySchemaBuilder,b as any};
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 only to give opportunity to extend it
41
- * by inheriting. It is not recommended to create an instance of this class
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
- * Performs synchronous validation of the schema over `object`. {@inheritDoc SchemaBuilder.validate}
71
+ * {@inheritDoc SchemaBuilder.validate}
62
72
  */
63
73
  validate(object: TResult, context?: ValidationContext): ArraySchemaValidationResult<TResult, TElementSchema>;
64
74
  /**
65
- * Performs asynchronous validation of the schema over `object`. {@inheritDoc SchemaBuilder.validateAsync}
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-KC45JEFL.js";import"../chunk-REYZ7G7J.js";export{a as ArraySchemaBuilder,b as array};
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 only to give opportunity to extend it
9
- * by inheriting. It is not recommended to create an instance of this class
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 ```ts
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 ```ts
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 ```ts
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 ```ts
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-PQINUGZW.js";import"../chunk-REYZ7G7J.js";export{a as BooleanSchemaBuilder,b as boolean};
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 only to give opportunity to extend it
9
- * by inheriting. It is not recommended to create an instance of this class
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 ```ts
13
- * const date = new Date(2020, 0, 2);
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(date);
16
+ * const result = schema.validate(value);
16
17
  * // result.valid === true
17
- * // result.object === date
18
+ * // result.object === value
18
19
  * ```
19
20
  *
20
- * @example ```ts
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 ```ts
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 ```ts
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 ```ts
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-NF4CRFMN.js";import"../chunk-REYZ7G7J.js";export{a as DateSchemaBuilder,b as date};
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 only to give opportunity to extend it
26
- * by inheriting. It is not recommended to create an instance of this class
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-YAOZEA2R.js";import"../chunk-REYZ7G7J.js";export{a as ExternSchemaBuilder,b as extern};
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 only to give opportunity to extend it
12
- * by inheriting. It is not recommended to create an instance of this class
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-K4ZLXLE2.js";import"../chunk-REYZ7G7J.js";export{a as FunctionSchemaBuilder,b as func};
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