@zipbul/baker 5.1.0 → 5.2.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 +84 -0
- package/dist/index.d.ts +11 -9
- package/dist/index.js +1 -1
- package/dist/src/baker.d.ts +8 -9
- package/dist/src/baker.js +1 -1
- package/dist/src/common/enums.d.ts +10 -0
- package/dist/src/common/enums.js +1 -0
- package/dist/src/common/index.d.ts +6 -0
- package/dist/src/common/index.js +1 -0
- package/dist/src/common/interfaces.d.ts +4 -0
- package/dist/src/common/types.d.ts +2 -0
- package/dist/src/config/config-normalizer.d.ts +7 -0
- package/dist/src/config/config-normalizer.js +1 -0
- package/dist/src/config/constants.d.ts +6 -0
- package/dist/src/config/constants.js +1 -0
- package/dist/src/config/index.d.ts +3 -0
- package/dist/src/config/index.js +1 -0
- package/dist/src/{configure.d.ts → config/interfaces.d.ts} +1 -8
- package/dist/src/config/interfaces.js +0 -0
- package/dist/src/decorators/constants.d.ts +2 -0
- package/dist/src/decorators/constants.js +1 -0
- package/dist/src/decorators/enums.d.ts +5 -0
- package/dist/src/decorators/enums.js +1 -0
- package/dist/src/decorators/field.d.ts +3 -54
- package/dist/src/decorators/field.js +1 -1
- package/dist/src/decorators/index.d.ts +2 -2
- package/dist/src/decorators/index.js +1 -1
- package/dist/src/decorators/interfaces.d.ts +50 -0
- package/dist/src/decorators/interfaces.js +0 -0
- package/dist/src/decorators/public.d.ts +2 -0
- package/dist/src/decorators/public.js +1 -0
- package/dist/src/decorators/types.d.ts +6 -0
- package/dist/src/decorators/types.js +0 -0
- package/dist/src/metadata/enums.d.ts +5 -0
- package/dist/src/metadata/enums.js +1 -0
- package/dist/src/metadata/index.d.ts +3 -0
- package/dist/src/metadata/index.js +1 -0
- package/dist/src/metadata/interfaces.d.ts +90 -0
- package/dist/src/metadata/interfaces.js +0 -0
- package/dist/src/metadata/meta-store.d.ts +49 -0
- package/dist/src/metadata/meta-store.js +1 -0
- package/dist/src/metadata/types.d.ts +10 -0
- package/dist/src/metadata/types.js +0 -0
- package/dist/src/rules/array.d.ts +2 -2
- package/dist/src/rules/array.js +1 -1
- package/dist/src/rules/binary.d.ts +2 -2
- package/dist/src/rules/binary.js +1 -1
- package/dist/src/rules/combinators.d.ts +1 -1
- package/dist/src/rules/combinators.js +1 -1
- package/dist/src/rules/common.d.ts +3 -3
- package/dist/src/rules/common.js +1 -1
- package/dist/src/rules/constants.d.ts +10 -0
- package/dist/src/rules/constants.js +1 -0
- package/dist/src/{create-rule.d.ts → rules/create-rule.d.ts} +1 -1
- package/dist/src/rules/create-rule.js +1 -0
- package/dist/src/rules/date.d.ts +1 -1
- package/dist/src/rules/date.js +1 -1
- package/dist/src/{enums.d.ts → rules/enums.d.ts} +0 -20
- package/dist/src/rules/enums.js +1 -0
- package/dist/src/rules/index.d.ts +5 -13
- package/dist/src/rules/index.js +1 -1
- package/dist/src/rules/interfaces.d.ts +43 -0
- package/dist/src/rules/interfaces.js +0 -0
- package/dist/src/rules/locales.d.ts +1 -1
- package/dist/src/rules/locales.js +1 -1
- package/dist/src/rules/number.d.ts +3 -3
- package/dist/src/rules/number.js +1 -1
- package/dist/src/rules/object.d.ts +1 -1
- package/dist/src/rules/object.js +1 -1
- package/dist/src/rules/public.d.ts +14 -0
- package/dist/src/rules/public.js +1 -0
- package/dist/src/{rule-metadata.d.ts → rules/rule-metadata.d.ts} +1 -1
- package/dist/src/{rule-metadata.js → rules/rule-metadata.js} +1 -1
- package/dist/src/{rule-plan.d.ts → rules/rule-plan.d.ts} +4 -7
- package/dist/src/rules/rule-plan.js +1 -0
- package/dist/src/rules/string-basic.d.ts +23 -0
- package/dist/src/rules/string-basic.js +1 -0
- package/dist/src/rules/string-crypto.d.ts +5 -0
- package/dist/src/rules/string-crypto.js +1 -0
- package/dist/src/rules/string-datetime.d.ts +3 -0
- package/dist/src/rules/string-datetime.js +1 -0
- package/dist/src/rules/string-encoding.d.ts +14 -0
- package/dist/src/rules/string-encoding.js +1 -0
- package/dist/src/rules/string-finance.d.ts +18 -0
- package/dist/src/rules/string-finance.js +10 -0
- package/dist/src/rules/string-format.d.ts +38 -0
- package/dist/src/rules/string-format.js +1 -0
- package/dist/src/rules/string-geo.d.ts +5 -0
- package/dist/src/rules/string-geo.js +1 -0
- package/dist/src/rules/string-identifier.d.ts +16 -0
- package/dist/src/rules/string-identifier.js +3 -0
- package/dist/src/rules/string-shared.d.ts +3 -0
- package/dist/src/rules/string-shared.js +1 -0
- package/dist/src/rules/string-width.d.ts +6 -0
- package/dist/src/rules/string-width.js +1 -0
- package/dist/src/rules/string.d.ts +14 -110
- package/dist/src/rules/string.js +1 -12
- package/dist/src/rules/typechecker.d.ts +10 -10
- package/dist/src/rules/typechecker.js +5 -5
- package/dist/src/rules/types.d.ts +26 -0
- package/dist/src/rules/types.js +0 -0
- package/dist/src/{functions → runtime}/check-call-options.d.ts +1 -1
- package/dist/src/runtime/check-call-options.js +1 -0
- package/dist/src/runtime/constants.d.ts +3 -0
- package/dist/src/runtime/constants.js +1 -0
- package/dist/src/{functions → runtime}/deserialize.d.ts +2 -3
- package/dist/src/runtime/deserialize.js +1 -0
- package/dist/src/runtime/index.d.ts +3 -0
- package/dist/src/runtime/index.js +1 -0
- package/dist/src/{functions → runtime}/serialize.d.ts +2 -2
- package/dist/src/runtime/serialize.js +1 -0
- package/dist/src/{functions → runtime}/validate.d.ts +2 -3
- package/dist/src/runtime/validate.js +1 -0
- package/dist/src/seal/async-analyzer.d.ts +20 -0
- package/dist/src/seal/async-analyzer.js +1 -0
- package/dist/src/seal/circular-analyzer.d.ts +9 -6
- package/dist/src/seal/circular-analyzer.js +1 -1
- package/dist/src/seal/circular-placeholder.d.ts +20 -0
- package/dist/src/seal/circular-placeholder.js +1 -0
- package/dist/src/seal/codegen-utils.d.ts +15 -0
- package/dist/src/seal/codegen-utils.js +1 -1
- package/dist/src/seal/compile-cache.d.ts +38 -0
- package/dist/src/seal/compile-cache.js +1 -0
- package/dist/src/seal/constants.d.ts +62 -0
- package/dist/src/seal/constants.js +1 -0
- package/dist/src/seal/deserialize-builder.d.ts +3 -6
- package/dist/src/seal/deserialize-builder.js +200 -263
- package/dist/src/seal/deserialize-codegen.d.ts +58 -0
- package/dist/src/seal/deserialize-codegen.js +64 -0
- package/dist/src/seal/enums.d.ts +1 -2
- package/dist/src/seal/enums.js +1 -1
- package/dist/src/seal/expose-validator.d.ts +2 -2
- package/dist/src/seal/expose-validator.js +1 -1
- package/dist/src/seal/index.d.ts +3 -0
- package/dist/src/seal/index.js +1 -0
- package/dist/src/seal/inheritance-merger.d.ts +18 -0
- package/dist/src/seal/inheritance-merger.js +1 -0
- package/dist/src/seal/interfaces.d.ts +89 -0
- package/dist/src/seal/interfaces.js +0 -0
- package/dist/src/seal/meta-validator.d.ts +16 -0
- package/dist/src/seal/meta-validator.js +1 -0
- package/dist/src/seal/seal.d.ts +4 -28
- package/dist/src/seal/seal.js +1 -1
- package/dist/src/seal/serialize-builder.d.ts +5 -3
- package/dist/src/seal/serialize-builder.js +64 -64
- package/dist/src/seal/type-normalizer.d.ts +9 -0
- package/dist/src/seal/type-normalizer.js +1 -0
- package/dist/src/seal/type-resolver.d.ts +2 -0
- package/dist/src/seal/type-resolver.js +1 -0
- package/dist/src/seal/types.d.ts +6 -0
- package/dist/src/seal/types.js +0 -0
- package/dist/src/transformers/{collection.transformer.d.ts → collection.d.ts} +1 -1
- package/dist/src/transformers/constants.d.ts +2 -0
- package/dist/src/transformers/constants.js +1 -0
- package/dist/src/transformers/{date.transformer.d.ts → date.d.ts} +1 -1
- package/dist/src/transformers/date.js +1 -0
- package/dist/src/transformers/index.d.ts +3 -8
- package/dist/src/transformers/index.js +1 -1
- package/dist/src/transformers/interfaces.d.ts +26 -0
- package/dist/src/transformers/interfaces.js +0 -0
- package/dist/src/transformers/luxon.d.ts +3 -0
- package/dist/src/transformers/luxon.js +1 -0
- package/dist/src/transformers/moment.d.ts +3 -0
- package/dist/src/transformers/moment.js +1 -0
- package/dist/src/transformers/{number.transformer.d.ts → number.d.ts} +1 -1
- package/dist/src/transformers/public.d.ts +7 -0
- package/dist/src/transformers/public.js +1 -0
- package/dist/src/transformers/{string.transformer.d.ts → string.d.ts} +1 -1
- package/dist/src/transformers/types.d.ts +3 -0
- package/dist/src/transformers/types.js +0 -0
- package/package.json +7 -7
- package/dist/src/collect.d.ts +0 -15
- package/dist/src/collect.js +0 -1
- package/dist/src/configure.js +0 -1
- package/dist/src/create-rule.js +0 -1
- package/dist/src/enums.js +0 -1
- package/dist/src/functions/check-call-options.js +0 -1
- package/dist/src/functions/deserialize.js +0 -1
- package/dist/src/functions/serialize.js +0 -1
- package/dist/src/functions/validate.js +0 -1
- package/dist/src/interfaces.d.ts +0 -32
- package/dist/src/meta-access.d.ts +0 -12
- package/dist/src/meta-access.js +0 -1
- package/dist/src/rule-plan.js +0 -1
- package/dist/src/seal/validate-meta.d.ts +0 -13
- package/dist/src/seal/validate-meta.js +0 -1
- package/dist/src/transformers/date.transformer.js +0 -1
- package/dist/src/transformers/luxon.transformer.d.ts +0 -8
- package/dist/src/transformers/luxon.transformer.js +0 -1
- package/dist/src/transformers/moment.transformer.d.ts +0 -7
- package/dist/src/transformers/moment.transformer.js +0 -1
- package/dist/src/types.d.ts +0 -177
- /package/dist/src/{errors.d.ts → common/errors.d.ts} +0 -0
- /package/dist/src/{errors.js → common/errors.js} +0 -0
- /package/dist/src/{interfaces.js → common/interfaces.js} +0 -0
- /package/dist/src/{types.js → common/types.js} +0 -0
- /package/dist/src/{utils.d.ts → common/utils.d.ts} +0 -0
- /package/dist/src/{utils.js → common/utils.js} +0 -0
- /package/dist/src/transformers/{collection.transformer.js → collection.js} +0 -0
- /package/dist/src/transformers/{number.transformer.js → number.js} +0 -0
- /package/dist/src/transformers/{string.transformer.js → string.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,89 @@
|
|
|
1
1
|
# @zipbul/baker
|
|
2
2
|
|
|
3
|
+
## 5.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- f768694: Fix four correctness bugs found in a package-wide audit. Two of them change observable behavior for
|
|
8
|
+
input that previously "worked", so review before upgrading:
|
|
9
|
+
|
|
10
|
+
- **`@IsEnum` with numeric enums (behavior change).** TypeScript numeric enums compile to a reverse-mapped
|
|
11
|
+
object (`{ 0: 'Inactive', 1: 'Active', Active: 1, Inactive: 0 }`), so the previous `Object.values()`
|
|
12
|
+
lookup wrongly accepted the member-_name_ strings (e.g. `'Active'`) as valid values. Values are now read
|
|
13
|
+
through the non-numeric keys, so only real members pass — correct for string, numeric, and heterogeneous
|
|
14
|
+
enums. Input that relied on the member-name strings being accepted will now be rejected.
|
|
15
|
+
|
|
16
|
+
- **`momentTransformer` parses in UTC (behavior change).** It now uses `moment.utc(value)` so a zoneless
|
|
17
|
+
datetime string resolves to the same instant on every host; previously local-time parsing made the
|
|
18
|
+
serialized output depend on the machine timezone. Zoneless inputs that were parsed in local time will now
|
|
19
|
+
be parsed as UTC. Matches `luxonTransformer`'s UTC default.
|
|
20
|
+
|
|
21
|
+
- **`luxonTransformer` invalid-date passthrough.** An unparseable date string / `Date` now passes through
|
|
22
|
+
untouched instead of being laundered into an Invalid `DateTime` (which serialized to `null` /
|
|
23
|
+
`"Invalid DateTime"` and corrupted data). Matches `momentTransformer`'s pass-through contract.
|
|
24
|
+
|
|
25
|
+
- **Per-call `groups` option validation.** A non-`string[]` `groups` value now throws a clear `BakerError`
|
|
26
|
+
at the call boundary instead of silently misbehaving inside the generated executor.
|
|
27
|
+
|
|
28
|
+
- 26e13af: Fix declared-collection element validation (RED tests added first), speed up collection `validate`, and
|
|
29
|
+
land an internal layering cleanup. One item changes observable behavior — review before upgrading:
|
|
30
|
+
|
|
31
|
+
- **Declared `@Type(() => Set)` / `@Type(() => Map)` now validate their elements (behavior change).** The
|
|
32
|
+
declared-collection codegen path hand-rolled its per-element loop separately from the canonical
|
|
33
|
+
(`type: null`) path and had three defects: a declared **Map** dropped every per-element `each` rule
|
|
34
|
+
entirely; declared Set/Map `each` rules ignored the runtime `groups` filter; and a function `message` on
|
|
35
|
+
an `each` rule received the whole collection as `value` instead of the failing element. All four sites
|
|
36
|
+
(Set/Map × deserialize/validate) now route through one shared emitter with the same rule-major ordering,
|
|
37
|
+
group filtering, per-element `value` binding, and `field[i]` paths as the canonical path. Input that was
|
|
38
|
+
silently accepted because a Map's element rules never ran will now be validated.
|
|
39
|
+
|
|
40
|
+
- **Collection `validate` is ~4.7× faster on large arrays.** The inline-nested validate path eagerly
|
|
41
|
+
allocated a per-element error-path string (`field[i].`) on every element even for valid input; it is now
|
|
42
|
+
built only at the (cold) error-push sites. A 1000-element nested-DTO `validate` drops from ~10µs to
|
|
43
|
+
~2.2µs (now on par with TypeBox and ahead of Ajv). `deserialize` and all error paths are byte-identical.
|
|
44
|
+
|
|
45
|
+
- **`createRule` is now also exported from the `@zipbul/baker/rules` subpath** (it was already exported from
|
|
46
|
+
the package root).
|
|
47
|
+
|
|
48
|
+
- **`luxonTransformer` / `momentTransformer` peer-dep error is now precise.** A genuinely-missing peer still
|
|
49
|
+
throws the "install it" `BakerError`; a peer that IS installed but throws during evaluation now surfaces
|
|
50
|
+
its real error instead of the misleading install hint.
|
|
51
|
+
|
|
52
|
+
Internal-only (no API change): the seal stage's TypeDef normalization was extracted out of the `sealOne`
|
|
53
|
+
god-function, large static lookup tables and the `string-format` validators were split into cohesive
|
|
54
|
+
modules, and several stateless helpers were simplified. Public surface is unchanged except the `createRule`
|
|
55
|
+
subpath export above (verified by an export-diff).
|
|
56
|
+
|
|
57
|
+
- 96ed92c: Fix five reproduced correctness bugs (each added as a RED test first) and unify the unknown-key failure
|
|
58
|
+
model. Several change observable behavior — review before upgrading:
|
|
59
|
+
|
|
60
|
+
- **Discriminated arrays now work (was broken).** A field typed `type: () => [Base]` with a `discriminator`
|
|
61
|
+
previously read the discriminator off the _array itself_ (`undefined`) and rejected every valid input with
|
|
62
|
+
`invalidDiscriminator`. `deserialize`/`validate` now dispatch the discriminator switch **per element**,
|
|
63
|
+
reporting nested errors at `field[i].path` and the invalid-discriminator error at the `field[i]` element
|
|
64
|
+
path. (serialize already handled arrays.)
|
|
65
|
+
|
|
66
|
+
- **serialize throws on an unmatched discriminator subtype (behavior change).** When an instance matched no
|
|
67
|
+
`instanceof` branch, serialize silently emitted the raw, un-serialized object (leaking undeclared fields).
|
|
68
|
+
It now throws a `BakerError`, symmetric with deserialize rejecting an unknown discriminator value.
|
|
69
|
+
|
|
70
|
+
- **`each` rule messages receive the failing element (behavior change).** A `message`/`context` function on
|
|
71
|
+
an `arrayOf(...)` rule was passed the whole collection as `value` while the path pointed at `field[i]`.
|
|
72
|
+
It now receives the failing element, consistent with the element-level path.
|
|
73
|
+
|
|
74
|
+
- **`isDateString` / `isISO8601({ strict: true })` leap-year for years 0–99.** Calendar validity used
|
|
75
|
+
`new Date(year, …)`, which remaps a 0–99 year argument to 1900–1999 — so `0000-02-29` (a valid leap date
|
|
76
|
+
by the 400 rule) was wrongly rejected. Now computed with the proleptic Gregorian rule for all years (and
|
|
77
|
+
without allocating a `Date`).
|
|
78
|
+
|
|
79
|
+
- **`isHash` / `isTaxId` reject an unknown algorithm/locale at construction (behavior change).** They
|
|
80
|
+
previously returned a rule that always failed at runtime; they now throw a `BakerError` when called with
|
|
81
|
+
an unsupported key, matching `isMobilePhone`/`isPostalCode`/`isIdentityCard`/`isPassportNumber`.
|
|
82
|
+
|
|
83
|
+
- **`isURL` no longer shares its default-protocols array across rules.** With default protocols, every
|
|
84
|
+
`isURL()` rule exposed the same module-level `['http','https','ftp']` array on `rule.constraints`;
|
|
85
|
+
mutating one rule's constraints would have corrupted every other. Each rule now owns an independent copy.
|
|
86
|
+
|
|
3
87
|
## 5.1.0
|
|
4
88
|
|
|
5
89
|
### Minor Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
export { createRule } from './src/
|
|
2
|
-
export { Field, arrayOf } from './src/decorators
|
|
3
|
-
export type { FieldOptions, ArrayOfMarker } from './src/decorators
|
|
1
|
+
export { createRule } from './src/rules';
|
|
2
|
+
export { Field, arrayOf } from './src/decorators';
|
|
3
|
+
export type { FieldOptions, ArrayOfMarker } from './src/decorators';
|
|
4
4
|
export { Baker } from './src/baker';
|
|
5
|
-
export { ExcludeMode
|
|
6
|
-
export
|
|
7
|
-
export {
|
|
8
|
-
export
|
|
9
|
-
export type {
|
|
10
|
-
export type {
|
|
5
|
+
export { ExcludeMode } from './src/decorators';
|
|
6
|
+
export { RequiredType } from './src/rules';
|
|
7
|
+
export type { BakerIssue, BakerIssueSet } from './src/common';
|
|
8
|
+
export { isBakerIssueSet, BakerError } from './src/common';
|
|
9
|
+
export type { EmittableRule } from './src/rules';
|
|
10
|
+
export type { Transformer, TransformParams } from './src/transformers';
|
|
11
|
+
export type { BakerConfig } from './src/config';
|
|
12
|
+
export type { RuntimeOptions } from './src/common';
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{createRule}from"./src/
|
|
1
|
+
export{createRule}from"./src/rules/index.js";export{Field,arrayOf}from"./src/decorators/index.js";export{Baker}from"./src/baker.js";export{ExcludeMode}from"./src/decorators/index.js";export{RequiredType}from"./src/rules/index.js";export{isBakerIssueSet,BakerError}from"./src/common/index.js";
|
package/dist/src/baker.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type { RuntimeOptions } from './interfaces';
|
|
1
|
+
import type { BakerIssueSet, ClassCtor, RuntimeOptions } from './common';
|
|
2
|
+
import type { BakerConfig } from './config';
|
|
4
3
|
/**
|
|
5
4
|
* A baker — an isolated registration + seal + runtime boundary. Each `new Baker()` owns its own
|
|
6
5
|
* registry, config, and compiled executors, so multiple bakers in one process (or a bundler-duplicated
|
|
@@ -30,12 +29,12 @@ export declare class Baker {
|
|
|
30
29
|
readonly Recipe: (value: Function, _context: ClassDecoratorContext) => void;
|
|
31
30
|
/** Seal every root registered to this baker (and its nested DTOs) with this baker's config. */
|
|
32
31
|
readonly seal: () => void;
|
|
33
|
-
deserialize: <T>(Class:
|
|
34
|
-
deserializeSync: <T>(Class:
|
|
35
|
-
deserializeAsync: <T>(Class:
|
|
36
|
-
validate: <T>(Class:
|
|
37
|
-
validateSync: <T>(Class:
|
|
38
|
-
validateAsync: <T>(Class:
|
|
32
|
+
deserialize: <T>(Class: ClassCtor<T>, input: unknown, options?: RuntimeOptions) => T | BakerIssueSet | Promise<T | BakerIssueSet>;
|
|
33
|
+
deserializeSync: <T>(Class: ClassCtor<T>, input: unknown, options?: RuntimeOptions) => T | BakerIssueSet;
|
|
34
|
+
deserializeAsync: <T>(Class: ClassCtor<T>, input: unknown, options?: RuntimeOptions) => Promise<T | BakerIssueSet>;
|
|
35
|
+
validate: <T>(Class: ClassCtor<T>, input: unknown, options?: RuntimeOptions) => true | BakerIssueSet | Promise<true | BakerIssueSet>;
|
|
36
|
+
validateSync: <T>(Class: ClassCtor<T>, input: unknown, options?: RuntimeOptions) => true | BakerIssueSet;
|
|
37
|
+
validateAsync: <T>(Class: ClassCtor<T>, input: unknown, options?: RuntimeOptions) => Promise<true | BakerIssueSet>;
|
|
39
38
|
serialize: <T>(instance: T, options?: RuntimeOptions) => Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
40
39
|
serializeSync: <T>(instance: T, options?: RuntimeOptions) => Record<string, unknown>;
|
|
41
40
|
serializeAsync: <T>(instance: T, options?: RuntimeOptions) => Promise<Record<string, unknown>>;
|
package/dist/src/baker.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export class Baker{#G=new Set;#F=new Map;#H;#I=!1;constructor(j){this.#H=j===void 0?
|
|
1
|
+
export class Baker{#G=new Set;#F=new Map;#H;#I=!1;constructor(j){this.#H=L(j===void 0?{}:j)}Recipe=(j,F)=>{this.#G.add(j)};seal=()=>{if(this.#I)return;_(this.#G,this.#H,this.#F);this.#I=!0};#j(j){let F=j;while(F){const H=this.#F.get(F);if(H){if(F!==j)this.#F.set(j,H);return H}const J=Object.getPrototypeOf(F);F=typeof J==="function"?J:null}const G=j.name||"<anonymous class>";throw new K(`${G} is not sealed by this baker`)}deserialize=(j,F,G)=>M(this.#j(j),F,G);deserializeSync=(j,F,G)=>N(this.#j(j),j.name,F,G);deserializeAsync=(j,F,G)=>P(this.#j(j),F,G);validate=(j,F,G)=>X(this.#j(j),F,G);validateSync=(j,F,G)=>Y(this.#j(j),j.name,F,G);validateAsync=(j,F,G)=>Z(this.#j(j),F,G);serialize=(j,F)=>Q(this.#j(I(j,"serialize")),j,F);serializeSync=(j,F)=>{const G=I(j,"serializeSync");return U(this.#j(G),G.name,j,F)};serializeAsync=(j,F)=>W(this.#j(I(j,"serializeAsync")),j,F)}import{BakerError as K}from"./common/index.js";import{normalizeConfig as L}from"./config/index.js";import{runDeserialize as M,runDeserializeSync as N,runDeserializeAsync as P,resolveSerializeClass as I,runSerialize as Q,runSerializeSync as U,runSerializeAsync as W,runValidate as X,runValidateSync as Y,runValidateAsync as Z}from"./runtime/index.js";import{sealRegistry as _}from"./seal/index.js";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Direction of a (de)serialization pass. */
|
|
2
|
+
export declare enum Direction {
|
|
3
|
+
Deserialize = "deserialize",
|
|
4
|
+
Serialize = "serialize"
|
|
5
|
+
}
|
|
6
|
+
/** Cached accessor a RulePlan reuses across checks. */
|
|
7
|
+
export declare enum CacheKey {
|
|
8
|
+
Length = "length",
|
|
9
|
+
Time = "time"
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export var Direction;((b)=>{b.Deserialize="deserialize";b.Serialize="serialize"})(Direction||={});export var CacheKey;((b)=>{b.Length="length";b.Time="time"})(CacheKey||={});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { BakerError, isBakerIssueSet, toBakerIssueSet } from './errors';
|
|
2
|
+
export type { BakerIssue, BakerIssueSet } from './errors';
|
|
3
|
+
export { Direction, CacheKey } from './enums';
|
|
4
|
+
export type { ClassCtor } from './types';
|
|
5
|
+
export type { RuntimeOptions } from './interfaces';
|
|
6
|
+
export { isAsyncFunction, isPromiseLike } from './utils';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{BakerError,isBakerIssueSet,toBakerIssueSet}from"./errors.js";export{Direction,CacheKey}from"./enums.js";export{isAsyncFunction,isPromiseLike}from"./utils.js";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SealOptions } from '../seal';
|
|
2
|
+
import type { BakerConfig } from './interfaces';
|
|
3
|
+
/**
|
|
4
|
+
* Validates a {@link BakerConfig} and maps it to the internal {@link SealOptions}. Used by
|
|
5
|
+
* `new Baker(config)`. Stateless — a plain function (no instance/class needed).
|
|
6
|
+
*/
|
|
7
|
+
export declare function normalizeConfig(config: BakerConfig): SealOptions;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{BakerError as v}from"../common/index.js";import{BAKER_CONFIG_KEYS as x}from"./constants.js";export function normalizeConfig(j){if(j===null||typeof j!=="object"||Array.isArray(j))throw new v(`[baker] config requires a plain object. Received: ${j===null?"null":Array.isArray(j)?"array":typeof j}.`);for(const q of Object.keys(j))if(!x.has(q))throw new v(`[baker] unknown key '${q}'. Valid keys: ${[...x].join(", ")}.`);return Object.freeze({enableImplicitConversion:j.autoConvert??!1,exposeDefaultValues:j.allowClassDefaults??!1,stopAtFirstError:j.stopAtFirstError??!1,whitelist:j.forbidUnknown??!1,debug:j.debug??!1})}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { BakerConfig } from './interfaces';
|
|
2
|
+
/**
|
|
3
|
+
* The valid {@link BakerConfig} keys. Shared single source: the ConfigNormalizer rejects unknown keys
|
|
4
|
+
* with it, and the per-call options guard (runtime) rejects a seal-time config key passed at call time.
|
|
5
|
+
*/
|
|
6
|
+
export declare const BAKER_CONFIG_KEYS: Set<keyof BakerConfig>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const BAKER_CONFIG_KEYS=new Set(["autoConvert","allowClassDefaults","stopAtFirstError","forbidUnknown","debug"]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{normalizeConfig}from"./config-normalizer.js";export{BAKER_CONFIG_KEYS}from"./constants.js";
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
interface BakerConfig {
|
|
1
|
+
export interface BakerConfig {
|
|
3
2
|
/** Automatic type conversion ("123" → 123). @default false */
|
|
4
3
|
autoConvert?: boolean;
|
|
5
4
|
/** Use class default values when key is missing from input. @default false */
|
|
@@ -11,9 +10,3 @@ interface BakerConfig {
|
|
|
11
10
|
/** Include field exclusion reasons as comments in generated code. @default false */
|
|
12
11
|
debug?: boolean;
|
|
13
12
|
}
|
|
14
|
-
/**
|
|
15
|
-
* Validate a BakerConfig and map it to the internal SealOptions. Used by `new Baker(config)`.
|
|
16
|
-
*/
|
|
17
|
-
declare function normalizeConfig(config: BakerConfig): SealOptions;
|
|
18
|
-
export { normalizeConfig };
|
|
19
|
-
export type { BakerConfig };
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const ARRAY_OF=Symbol.for("baker:arrayOf");export const FIELD_OPTION_KEYS=new Set(Object.keys({type:!0,discriminator:!0,keepDiscriminatorProperty:!0,rules:!0,optional:!0,nullable:!0,name:!0,deserializeName:!0,serializeName:!0,exclude:!0,groups:!0,when:!0,transform:!0,message:!0,context:!0,mapValue:!0,setValue:!0}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export var ExcludeMode;((i)=>{i.DeserializeOnly="deserializeOnly";i.SerializeOnly="serializeOnly"})(ExcludeMode||={});
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
readonly [key: symbol]: true;
|
|
5
|
-
readonly rules: EmittableRule[];
|
|
6
|
-
}
|
|
1
|
+
import type { EmittableRule } from '../rules';
|
|
2
|
+
import type { ArrayOfMarker, FieldOptions } from './interfaces';
|
|
3
|
+
import type { FieldDecorator, RuleArg } from './types';
|
|
7
4
|
/**
|
|
8
5
|
* Apply rules to each element of an array.
|
|
9
6
|
*
|
|
@@ -14,54 +11,6 @@ interface ArrayOfMarker {
|
|
|
14
11
|
* ```
|
|
15
12
|
*/
|
|
16
13
|
declare function arrayOf(...rules: EmittableRule[]): ArrayOfMarker;
|
|
17
|
-
interface FieldOptions {
|
|
18
|
-
/** Nested DTO type. Thunk — supports circular references. [Dto] for arrays. */
|
|
19
|
-
type?: () => ClassCtor | ClassCtor[] | MapConstructor | SetConstructor;
|
|
20
|
-
/** Polymorphic discriminator configuration — used with type */
|
|
21
|
-
discriminator?: {
|
|
22
|
-
property: string;
|
|
23
|
-
subTypes: {
|
|
24
|
-
value: Function;
|
|
25
|
-
name: string;
|
|
26
|
-
}[];
|
|
27
|
-
};
|
|
28
|
-
/** Whether to keep the discriminator property in the result object */
|
|
29
|
-
keepDiscriminatorProperty?: boolean;
|
|
30
|
-
/** Validation rules array */
|
|
31
|
-
rules?: (EmittableRule | ArrayOfMarker)[];
|
|
32
|
-
/** Allow undefined */
|
|
33
|
-
optional?: boolean;
|
|
34
|
-
/** Allow null */
|
|
35
|
-
nullable?: boolean;
|
|
36
|
-
/** JSON key mapping (bidirectional) */
|
|
37
|
-
name?: string;
|
|
38
|
-
/** Deserialize direction key mapping (cannot be used with name) */
|
|
39
|
-
deserializeName?: string;
|
|
40
|
-
/** Serialize direction key mapping (cannot be used with name) */
|
|
41
|
-
serializeName?: string;
|
|
42
|
-
/** Field exclusion — true: bidirectional, 'deserializeOnly': deserialization only, 'serializeOnly': serialization only */
|
|
43
|
-
exclude?: boolean | ExcludeMode;
|
|
44
|
-
/** Groups — field visibility control + conditional validation rule application */
|
|
45
|
-
groups?: string[];
|
|
46
|
-
/** Conditional validation — skip all field validation when false */
|
|
47
|
-
when?: (obj: Record<string, unknown>) => boolean;
|
|
48
|
-
/** Transformer or array of transformers (serialize direction applies in reverse order) */
|
|
49
|
-
transform?: Transformer | Transformer[];
|
|
50
|
-
/** Error message on validation failure — applied to all rules of the field (rule's own message takes precedence) */
|
|
51
|
-
message?: string | ((args: {
|
|
52
|
-
property: string;
|
|
53
|
-
value: unknown;
|
|
54
|
-
constraints: Record<string, unknown>;
|
|
55
|
-
}) => string);
|
|
56
|
-
/** Error context on validation failure — applied to all rules of the field (rule's own context takes precedence) */
|
|
57
|
-
context?: unknown;
|
|
58
|
-
/** Nested DTO class thunk for Map values — used with type: () => Map */
|
|
59
|
-
mapValue?: () => ClassCtor;
|
|
60
|
-
/** Nested DTO class thunk for Set elements — used with type: () => Set */
|
|
61
|
-
setValue?: () => ClassCtor;
|
|
62
|
-
}
|
|
63
|
-
type RuleArg = EmittableRule | ArrayOfMarker;
|
|
64
|
-
type FieldDecorator = (value: undefined, context: ClassFieldDecoratorContext) => void;
|
|
65
14
|
/** `@Field`() — empty field registration */
|
|
66
15
|
declare function Field(): FieldDecorator;
|
|
67
16
|
/** `@Field`(isString(), email()) — variadic rules */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{Direction as I,BakerError as X,isAsyncFunction as j,isPromiseLike as z}from"../common/index.js";import{metaStore as _}from"../metadata/index.js";import{ARRAY_OF as h,FIELD_OPTION_KEYS as w}from"./constants.js";import{ExcludeMode as L}from"./enums.js";function arrayOf(...b){return{rules:b,[h]:!0}}function V(b){return typeof b==="object"&&b!==null&&b[h]===!0}function P(b){if(typeof b==="function")return!1;if(typeof b!=="object"||b===null)return!1;if(V(b))return!1;const q=Object.keys(b);if(q.length===0)return!0;return q.some((H)=>w.has(H))}function S(b,q,H){const J=H?`${q} ${H}`:q;if(typeof b==="function"){const U=b;if(typeof U.emit!=="function"||typeof U.ruleName!=="string"){const C=U.name?` Did you forget to call '${U.name}()'? Factories must be invoked (e.g., '${U.name}()'). Rule constants are passed directly (e.g., 'isString' without parentheses).`:" Use createRule() or import a rule from @zipbul/baker/rules.";throw new X(`@Field on ${J}: argument is not a baker rule.${C} Valid @Field forms: @Field(), @Field(rule, ...), @Field(options), @Field(rule, ..., options).`)}return}throw new X(`@Field on ${J}: expected a baker rule (function with .emit and .ruleName), got ${b===null?"null":typeof b}. Use createRule() or import a rule from @zipbul/baker/rules. Valid @Field forms: @Field(), @Field(rule, ...), @Field(options), @Field(rule, ..., options).`)}function M(b){if(b.length===0)return{rules:[],options:{}};if(b.length===1&&P(b[0])){const H=b[0];return{rules:H.rules??[],options:H}}const q=b[b.length-1];if(P(q)){const H=q;let J=b.slice(0,-1);if(H.rules)J=[...J,...H.rules];return{rules:J,options:H}}return{rules:b,options:{}}}function G(b,q){if(q.groups!==void 0)b.groups=q.groups;if(q.message!==void 0)b.message=q.message;if(q.context!==void 0)b.context=q.context;return b}function N(b,q){if(q.groups!==void 0)b.groups=q.groups;return b}function T(b,q,H){for(const J of q)if(V(J))for(const Q of J.rules)b.validation.push(G({rule:Q,each:!0},H));else b.validation.push(G({rule:J},H))}function D(b,q){if(q.name)b.expose.push(N({name:q.name},q));else if(q.deserializeName||q.serializeName){if(q.deserializeName)b.expose.push(N({name:q.deserializeName,deserializeOnly:!0},q));if(q.serializeName)b.expose.push(N({name:q.serializeName,serializeOnly:!0},q))}else if(q.groups)b.expose.push({groups:q.groups});else b.expose.push({})}function Y(b,q,H){const J=j(H);return{fn:(U)=>{const C=H(U);if(!J&&z(C))throw new X(`@Field(${b}) ${q} transform returned Promise. Declare the transform with async if it is asynchronous.`);return C},isAsync:J}}function B(b,q,H){if(!H.transform)return;const J=Array.isArray(H.transform)?H.transform:[H.transform];for(const Q of J){const U=Y(q,I.Deserialize,Q.deserialize),C=Y(q,I.Serialize,Q.serialize);b.transform.push({fn:U.fn,isAsync:U.isAsync,options:{deserializeOnly:!0}},{fn:C.fn,isAsync:C.isAsync,options:{serializeOnly:!0}})}}function Field(...b){return(q,H)=>{if(H.static)throw new X("@Field cannot decorate static fields.");if(H.private)throw new X("@Field cannot decorate private fields.");if(typeof H.name==="symbol")throw new X("@Field: symbol property keys are not supported. Use a string property name.");const J=H.name,Q=_.ensure(H.metadata,J),{rules:U,options:C}=M(b);if(C.name&&(C.deserializeName||C.serializeName))throw new X(`@Field on ${J}: 'name' cannot be combined with 'deserializeName'/'serializeName'. Use one or the other.`);if(C.mapValue!==void 0&&C.setValue!==void 0)throw new X(`@Field on ${J}: 'mapValue' and 'setValue' cannot both be set \u2014 use 'mapValue' for a Map value type and 'setValue' for a Set element type.`);for(let W=0;W<U.length;W++){const Z=U[W];if(V(Z))for(let $=0;$<Z.rules.length;$++)S(Z.rules[$],J,`arrayOf[${$}]`);else S(Z,J)}T(Q,U,C);if(C.context!==void 0)Q.context=C.context;if(C.message!==void 0)Q.message=C.message;if(C.optional)Q.flags.isOptional=!0;if(C.nullable)Q.flags.isNullable=!0;if(C.when)Q.flags.validateIf=C.when;if(C.type){const W={fn:C.type};if(C.discriminator!==void 0)W.discriminator=C.discriminator;if(C.keepDiscriminatorProperty!==void 0)W.keepDiscriminatorProperty=C.keepDiscriminatorProperty;const Z=C.mapValue??C.setValue;if(Z!==void 0)W.collectionValue=Z;Q.type=W}D(Q,C);if(C.exclude){if(C.exclude===!0)Q.exclude={};else if(C.exclude===L.DeserializeOnly)Q.exclude={deserializeOnly:!0};else if(C.exclude===L.SerializeOnly)Q.exclude={serializeOnly:!0}}B(Q,J,C)}}export{arrayOf,Field};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
1
|
+
export * from './public';
|
|
2
|
+
export { ExcludeMode } from './enums';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{
|
|
1
|
+
export*from"./public.js";export{ExcludeMode}from"./enums.js";
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ClassCtor } from '../common';
|
|
2
|
+
import type { DiscriminatorDef } from '../metadata';
|
|
3
|
+
import type { EmittableRule } from '../rules';
|
|
4
|
+
import type { Transformer } from '../transformers';
|
|
5
|
+
import type { ExcludeMode } from './enums';
|
|
6
|
+
import { ARRAY_OF } from './constants';
|
|
7
|
+
export interface ArrayOfMarker {
|
|
8
|
+
readonly [ARRAY_OF]: true;
|
|
9
|
+
readonly rules: EmittableRule[];
|
|
10
|
+
}
|
|
11
|
+
export interface FieldOptions {
|
|
12
|
+
/** Nested DTO type. Thunk — supports circular references. [Dto] for arrays. */
|
|
13
|
+
type?: () => ClassCtor | ClassCtor[] | MapConstructor | SetConstructor;
|
|
14
|
+
/** Polymorphic discriminator configuration — used with type */
|
|
15
|
+
discriminator?: DiscriminatorDef;
|
|
16
|
+
/** Whether to keep the discriminator property in the result object */
|
|
17
|
+
keepDiscriminatorProperty?: boolean;
|
|
18
|
+
/** Validation rules array */
|
|
19
|
+
rules?: (EmittableRule | ArrayOfMarker)[];
|
|
20
|
+
/** Allow undefined */
|
|
21
|
+
optional?: boolean;
|
|
22
|
+
/** Allow null */
|
|
23
|
+
nullable?: boolean;
|
|
24
|
+
/** JSON key mapping (bidirectional) */
|
|
25
|
+
name?: string;
|
|
26
|
+
/** Deserialize direction key mapping (cannot be used with name) */
|
|
27
|
+
deserializeName?: string;
|
|
28
|
+
/** Serialize direction key mapping (cannot be used with name) */
|
|
29
|
+
serializeName?: string;
|
|
30
|
+
/** Field exclusion — true: bidirectional, 'deserializeOnly': deserialization only, 'serializeOnly': serialization only */
|
|
31
|
+
exclude?: boolean | ExcludeMode;
|
|
32
|
+
/** Groups — field visibility control + conditional validation rule application */
|
|
33
|
+
groups?: string[];
|
|
34
|
+
/** Conditional validation — skip all field validation when false */
|
|
35
|
+
when?: (obj: Record<string, unknown>) => boolean;
|
|
36
|
+
/** Transformer or array of transformers (serialize direction applies in reverse order) */
|
|
37
|
+
transform?: Transformer | Transformer[];
|
|
38
|
+
/** Error message on validation failure — applied to all rules of the field (rule's own message takes precedence) */
|
|
39
|
+
message?: string | ((args: {
|
|
40
|
+
property: string;
|
|
41
|
+
value: unknown;
|
|
42
|
+
constraints: Record<string, unknown>;
|
|
43
|
+
}) => string);
|
|
44
|
+
/** Error context on validation failure — applied to all rules of the field (rule's own context takes precedence) */
|
|
45
|
+
context?: unknown;
|
|
46
|
+
/** Nested DTO class thunk for Map values — used with type: () => Map */
|
|
47
|
+
mapValue?: () => ClassCtor;
|
|
48
|
+
/** Nested DTO class thunk for Set elements — used with type: () => Set */
|
|
49
|
+
setValue?: () => ClassCtor;
|
|
50
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Field,arrayOf}from"./field.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { EmittableRule } from '../rules';
|
|
2
|
+
import type { ArrayOfMarker } from './interfaces';
|
|
3
|
+
/** A positional @Field argument — either a rule or an arrayOf(...) element-rules marker. */
|
|
4
|
+
export type RuleArg = EmittableRule | ArrayOfMarker;
|
|
5
|
+
/** The class-field decorator @Field returns — TC39 field decorators receive `undefined` as the value. */
|
|
6
|
+
export type FieldDecorator = (value: undefined, context: ClassFieldDecoratorContext) => void;
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export var CollectionType;((e)=>{e.Map="Map";e.Set="Set"})(CollectionType||={});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{CollectionType}from"./enums.js";export{MetaStore,metaStore}from"./meta-store.js";
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { ClassCtor } from '../common';
|
|
2
|
+
import type { InternalRule } from '../rules';
|
|
3
|
+
import type { TransformFunction } from '../transformers';
|
|
4
|
+
import type { CollectionType } from './enums';
|
|
5
|
+
/** Arguments for user-defined message callback */
|
|
6
|
+
export interface MessageArgs {
|
|
7
|
+
property: string;
|
|
8
|
+
value: unknown;
|
|
9
|
+
constraints: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
export interface RuleDef {
|
|
12
|
+
rule: InternalRule;
|
|
13
|
+
each?: boolean;
|
|
14
|
+
groups?: string[];
|
|
15
|
+
/** Value to include in BakerIssue.message on validation failure */
|
|
16
|
+
message?: string | ((args: MessageArgs) => string);
|
|
17
|
+
/** Arbitrary value to include in BakerIssue.context on validation failure */
|
|
18
|
+
context?: unknown;
|
|
19
|
+
}
|
|
20
|
+
export interface TransformDef {
|
|
21
|
+
fn: TransformFunction;
|
|
22
|
+
isAsync?: boolean;
|
|
23
|
+
options?: {
|
|
24
|
+
groups?: string[];
|
|
25
|
+
deserializeOnly?: boolean;
|
|
26
|
+
serializeOnly?: boolean;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export interface ExposeDef {
|
|
30
|
+
name?: string;
|
|
31
|
+
groups?: string[];
|
|
32
|
+
deserializeOnly?: boolean;
|
|
33
|
+
serializeOnly?: boolean;
|
|
34
|
+
}
|
|
35
|
+
export interface ExcludeDef {
|
|
36
|
+
deserializeOnly?: boolean;
|
|
37
|
+
serializeOnly?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** A polymorphic discriminator subtype mapping — a class constructor keyed by its wire name. */
|
|
40
|
+
export interface DiscriminatorSubType {
|
|
41
|
+
value: ClassCtor;
|
|
42
|
+
name: string;
|
|
43
|
+
}
|
|
44
|
+
/** Polymorphic discriminator config — shared single source between @Field options and the IR TypeDef. */
|
|
45
|
+
export interface DiscriminatorDef {
|
|
46
|
+
property: string;
|
|
47
|
+
subTypes: DiscriminatorSubType[];
|
|
48
|
+
}
|
|
49
|
+
export interface TypeDef {
|
|
50
|
+
fn: () => ClassCtor | ClassCtor[] | MapConstructor | SetConstructor;
|
|
51
|
+
discriminator?: DiscriminatorDef;
|
|
52
|
+
keepDiscriminatorProperty?: boolean;
|
|
53
|
+
/** seal-time normalization result — true if fn() returns an array */
|
|
54
|
+
isArray?: boolean;
|
|
55
|
+
/** seal-time normalization result — cached class after resolving fn() (DTOs only, excluding primitives) */
|
|
56
|
+
resolvedClass?: ClassCtor;
|
|
57
|
+
/** seal-time normalization result — Map or Set collection type */
|
|
58
|
+
collection?: CollectionType;
|
|
59
|
+
/** Nested DTO class thunk for Map value / Set element */
|
|
60
|
+
collectionValue?: () => ClassCtor;
|
|
61
|
+
/** seal-time normalization result — cached class after resolving collectionValue */
|
|
62
|
+
resolvedCollectionValue?: ClassCtor;
|
|
63
|
+
}
|
|
64
|
+
export interface PropertyFlags {
|
|
65
|
+
/** `@Field({ optional })` — skip all validation when undefined/null */
|
|
66
|
+
isOptional?: boolean;
|
|
67
|
+
/** `@Field({ nullable })` — allow and assign null, reject undefined */
|
|
68
|
+
isNullable?: boolean;
|
|
69
|
+
/** `@Field({ when })` — skip all field validation when the predicate returns false */
|
|
70
|
+
validateIf?: (obj: Record<string, unknown>) => boolean;
|
|
71
|
+
/** Seal-derived — trigger recursive validation for nested `@Field({ type })` DTOs */
|
|
72
|
+
validateNested?: boolean;
|
|
73
|
+
/** Seal-derived — validate nested DTOs per array element */
|
|
74
|
+
validateNestedEach?: boolean;
|
|
75
|
+
}
|
|
76
|
+
export interface RawPropertyMeta {
|
|
77
|
+
validation: RuleDef[];
|
|
78
|
+
transform: TransformDef[];
|
|
79
|
+
expose: ExposeDef[];
|
|
80
|
+
exclude: ExcludeDef | null;
|
|
81
|
+
type: TypeDef | null;
|
|
82
|
+
flags: PropertyFlags;
|
|
83
|
+
/** Field-level message applied to ALL failures of this field (gate/structural/required/conversion/rule) */
|
|
84
|
+
message?: string | ((args: MessageArgs) => string);
|
|
85
|
+
/** Field-level context attached to ALL failures of this field */
|
|
86
|
+
context?: unknown;
|
|
87
|
+
}
|
|
88
|
+
export interface RawClassMeta {
|
|
89
|
+
[propertyKey: string]: RawPropertyMeta;
|
|
90
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { RawClassMeta, RawPropertyMeta } from './interfaces';
|
|
2
|
+
import type { MetaObject } from './types';
|
|
3
|
+
import { RAW } from '../symbols';
|
|
4
|
+
/**
|
|
5
|
+
* The single boundary that bridges symbol-keyed decorator metadata to typed RAW metadata. All RAW
|
|
6
|
+
* access goes through this one process-wide `metaStore` instance (and, for the seal pipeline, an
|
|
7
|
+
* injected reference) — no other module touches `Class[Symbol.metadata][this.#rawKey]` directly. The private
|
|
8
|
+
* `#metaOf`/`#ensureOwnMeta` methods are the actual encapsulation; `RAW` itself is process-global
|
|
9
|
+
* (`Symbol.for('baker:raw')`), so the value of consolidating access here is one access protocol, not
|
|
10
|
+
* a "private symbol".
|
|
11
|
+
*
|
|
12
|
+
* RAW lives on the TC39 decorator metadata object (`Class[Symbol.metadata][this.#rawKey]`) — where modern field
|
|
13
|
+
* decorators can write (they receive `context.metadata`, never the class). Sealed executors live in
|
|
14
|
+
* each Baker's own map, never on the class.
|
|
15
|
+
*/
|
|
16
|
+
declare class MetaStore {
|
|
17
|
+
#private;
|
|
18
|
+
constructor(rawKey?: typeof RAW);
|
|
19
|
+
get(cls: Function): RawClassMeta | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Test-only: like {@link get} but throws if the class has no @Field decorators. Specs use it to
|
|
22
|
+
* assert metadata presence; production reads go through {@link get}/{@link hasOwn}.
|
|
23
|
+
*/
|
|
24
|
+
require(cls: Function): RawClassMeta;
|
|
25
|
+
/**
|
|
26
|
+
* Test-only: inject RAW metadata directly, bypassing the @Field decorator path. The seal-pipeline
|
|
27
|
+
* specs use this to author DTOs programmatically; production metadata is written via {@link ensure}.
|
|
28
|
+
*/
|
|
29
|
+
set(cls: Function, raw: RawClassMeta): void;
|
|
30
|
+
/** Test-only: drop a class's own RAW slot so specs can reset state between cases. */
|
|
31
|
+
delete(cls: Function): void;
|
|
32
|
+
/**
|
|
33
|
+
* True only when cls has its OWN RAW slot. A subclass without its own @Field decorators resolves
|
|
34
|
+
* `Class[Symbol.metadata]` to the parent's metadata via the class prototype chain; the dual own-check
|
|
35
|
+
* keeps inheritance merging from double-counting inherited fields.
|
|
36
|
+
*/
|
|
37
|
+
hasOwn(cls: Function): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* The RawPropertyMeta for `key` on a decorator metadata object — creating the RAW slot and the
|
|
40
|
+
* per-key default meta if absent. Called by @Field, which receives `context.metadata`.
|
|
41
|
+
*
|
|
42
|
+
* The own-RAW check is required: a subclass's metadata inherits the parent's RAW via the metadata
|
|
43
|
+
* prototype chain, so a bare assignment would pollute the parent. A fresh own RAW (null prototype)
|
|
44
|
+
* keeps child fields isolated.
|
|
45
|
+
*/
|
|
46
|
+
ensure(metadata: MetaObject, key: string): RawPropertyMeta;
|
|
47
|
+
}
|
|
48
|
+
export { MetaStore };
|
|
49
|
+
export declare const metaStore: MetaStore;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class MetaStore{#z;constructor(z=I){this.#z=z}#D(z){return z[Symbol.metadata]??void 0}#G(z){if(!Object.hasOwn(z,Symbol.metadata))Object.defineProperty(z,Symbol.metadata,{value:{},writable:!0,configurable:!0,enumerable:!1});return z[Symbol.metadata]}get(z){return this.#D(z)?.[this.#z]}require(z){const D=this.get(z);if(D===void 0)throw new H(`${z.name||"<anonymous>"}: class has no @Field decorators`);return D}set(z,D){this.#G(z)[this.#z]=D}delete(z){if(Object.hasOwn(z,Symbol.metadata))delete z[Symbol.metadata][this.#z]}hasOwn(z){if(!Object.hasOwn(z,Symbol.metadata))return!1;const D=z[Symbol.metadata];return D!=null&&Object.hasOwn(D,this.#z)}ensure(z,D){if(!Object.hasOwn(z,this.#z))z[this.#z]=Object.create(null);const G=z[this.#z];return G[D]??={validation:[],transform:[],expose:[],exclude:null,type:null,flags:{}}}}import{BakerError as H}from"../common/index.js";import{RAW as I}from"../symbols.js";export{MetaStore};export const metaStore=new MetaStore;
|