@zipbul/baker 3.4.1 → 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.
- package/CHANGELOG.md +45 -0
- package/README.md +256 -159
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/src/baker.d.ts +31 -0
- package/dist/src/baker.js +1 -0
- package/dist/src/configure.d.ts +3 -8
- package/dist/src/configure.js +1 -1
- package/dist/src/create-rule.d.ts +2 -1
- package/dist/src/decorators/field.d.ts +2 -1
- package/dist/src/decorators/field.js +1 -1
- package/dist/src/decorators/index.d.ts +0 -1
- package/dist/src/decorators/index.js +1 -1
- package/dist/src/enums.d.ts +51 -0
- package/dist/src/enums.js +1 -0
- package/dist/src/errors.d.ts +1 -1
- package/dist/src/errors.js +1 -1
- package/dist/src/functions/check-call-options.d.ts +1 -1
- package/dist/src/functions/check-call-options.js +1 -1
- package/dist/src/functions/deserialize.d.ts +1 -1
- package/dist/src/functions/serialize.d.ts +1 -1
- package/dist/src/rule-plan.d.ts +5 -3
- package/dist/src/rule-plan.js +1 -1
- package/dist/src/rules/array.js +1 -1
- package/dist/src/rules/date.js +1 -1
- package/dist/src/rules/locales.js +1 -1
- package/dist/src/rules/number.js +1 -1
- package/dist/src/rules/object.js +1 -1
- package/dist/src/rules/string.js +5 -5
- package/dist/src/rules/typechecker.js +5 -5
- package/dist/src/seal/deserialize-builder.js +230 -230
- package/dist/src/seal/enums.d.ts +8 -0
- package/dist/src/seal/enums.js +1 -0
- package/dist/src/seal/expose-validator.js +1 -1
- package/dist/src/seal/seal.d.ts +10 -21
- package/dist/src/seal/seal.js +1 -1
- package/dist/src/seal/serialize-builder.js +8 -8
- package/dist/src/seal/validate-meta.js +1 -1
- package/dist/src/symbols.d.ts +1 -1
- package/dist/src/types.d.ts +15 -14
- package/package.json +1 -1
- package/dist/src/decorators/recipe.d.ts +0 -17
- package/dist/src/decorators/recipe.js +0 -1
- package/dist/src/registry.d.ts +0 -8
- package/dist/src/registry.js +0 -1
- package/dist/src/seal/seal-state.d.ts +0 -10
- package/dist/src/seal/seal-state.js +0 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { BakerConfig } from './configure';
|
|
2
|
+
/**
|
|
3
|
+
* A baker — an isolated registration + seal boundary. Each `new Baker()` owns its own registry and
|
|
4
|
+
* config, so multiple bakers in one process (or a bundler-duplicated copy of the library) never
|
|
5
|
+
* fragment each other. `@Field`, the rule factories, and `deserialize`/`serialize`/`validate` stay
|
|
6
|
+
* global — they read the metadata/executor stored on the class itself — so only the class-collecting
|
|
7
|
+
* `Recipe` and `seal` belong to the instance.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* const app = new Baker({ autoConvert: true });
|
|
11
|
+
* @app.Recipe class UserDto { @Field(isString) name!: string }
|
|
12
|
+
* app.seal();
|
|
13
|
+
* deserialize(UserDto, input);
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* Isolation boundary is class identity: distinct classes are fully isolated (each sealed with its
|
|
17
|
+
* baker's config); a class shared across bakers is reused as one sealed form.
|
|
18
|
+
*
|
|
19
|
+
* `Recipe` and `seal` are arrow-field properties, not prototype methods, by design: `@app.Recipe`
|
|
20
|
+
* is applied as a detached value (the runtime calls the decorator with no `this` receiver), so it
|
|
21
|
+
* must be bound to the instance; arrow fields also keep `const { Recipe, seal } = new Baker()`
|
|
22
|
+
* working.
|
|
23
|
+
*/
|
|
24
|
+
export declare class Baker {
|
|
25
|
+
#private;
|
|
26
|
+
constructor(config?: BakerConfig);
|
|
27
|
+
/** Class decorator — registers the class as a root of this baker. Use as `@app.Recipe`. */
|
|
28
|
+
readonly Recipe: (value: Function, _context: ClassDecoratorContext) => void;
|
|
29
|
+
/** Seal every root registered to this baker (and its nested DTOs) with this baker's config. */
|
|
30
|
+
readonly seal: () => void;
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export class Baker{#j=new Set;#q;#x=!1;constructor(j){this.#q=j===void 0?Object.freeze({}):q(j)}Recipe=(j,A)=>{this.#j.add(j)};seal=()=>{if(this.#x)return;x(this.#j,this.#q);this.#x=!0}}import{normalizeConfig as q}from"./configure.js";import{sealRegistry as x}from"./seal/seal.js";
|
package/dist/src/configure.d.ts
CHANGED
|
@@ -12,13 +12,8 @@ interface BakerConfig {
|
|
|
12
12
|
debug?: boolean;
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
16
|
-
* If not called, defaults are applied.
|
|
15
|
+
* Validate a BakerConfig and map it to the internal SealOptions. Used by `new Baker(config)`.
|
|
17
16
|
*/
|
|
18
|
-
declare function
|
|
19
|
-
|
|
20
|
-
declare function getGlobalOptions(): SealOptions;
|
|
21
|
-
/** @internal — reset to defaults on unseal */
|
|
22
|
-
declare function resetConfigForTesting(): void;
|
|
23
|
-
export { configure, getGlobalOptions, resetConfigForTesting };
|
|
17
|
+
declare function normalizeConfig(config: BakerConfig): SealOptions;
|
|
18
|
+
export { normalizeConfig };
|
|
24
19
|
export type { BakerConfig };
|
package/dist/src/configure.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BakerError as
|
|
1
|
+
import{BakerError as u}from"./errors.js";const v=new Set(["autoConvert","allowClassDefaults","stopAtFirstError","forbidUnknown","debug"]);function normalizeConfig(j){if(j===null||typeof j!=="object"||Array.isArray(j))throw new u(`[baker] config requires a plain object. Received: ${j===null?"null":Array.isArray(j)?"array":typeof j}.`);for(const q of Object.keys(j))if(!v.has(q))throw new u(`[baker] unknown key '${q}'. Valid keys: ${[...v].join(", ")}.`);return Object.freeze({enableImplicitConversion:j.autoConvert??!1,exposeDefaultValues:j.allowClassDefaults??!1,stopAtFirstError:j.stopAtFirstError??!1,whitelist:j.forbidUnknown??!1,debug:j.debug??!1})}export{normalizeConfig};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RequiredType } from './enums';
|
|
1
2
|
import type { EmittableRule } from './types';
|
|
2
3
|
export interface CreateRuleOptions {
|
|
3
4
|
/** Rule name. Used as the error code. */
|
|
@@ -7,7 +8,7 @@ export interface CreateRuleOptions {
|
|
|
7
8
|
/** Rule parameters */
|
|
8
9
|
constraints?: Record<string, unknown>;
|
|
9
10
|
/** Type assumed by this rule — used for type gate optimization */
|
|
10
|
-
requiresType?:
|
|
11
|
+
requiresType?: RequiredType;
|
|
11
12
|
}
|
|
12
13
|
/**
|
|
13
14
|
* Creates a user-defined validation rule.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ClassCtor, EmittableRule, Transformer } from '../types';
|
|
2
|
+
import { ExcludeMode } from '../enums';
|
|
2
3
|
interface ArrayOfMarker {
|
|
3
4
|
readonly [key: symbol]: true;
|
|
4
5
|
readonly rules: EmittableRule[];
|
|
@@ -39,7 +40,7 @@ interface FieldOptions {
|
|
|
39
40
|
/** Serialize direction key mapping (cannot be used with name) */
|
|
40
41
|
serializeName?: string;
|
|
41
42
|
/** Field exclusion — true: bidirectional, 'deserializeOnly': deserialization only, 'serializeOnly': serialization only */
|
|
42
|
-
exclude?: boolean |
|
|
43
|
+
exclude?: boolean | ExcludeMode;
|
|
43
44
|
/** Groups — field visibility control + conditional validation rule application */
|
|
44
45
|
groups?: string[];
|
|
45
46
|
/** Conditional validation — skip all field validation when false */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ensureMeta as
|
|
1
|
+
import{ensureMeta as L}from"../collect.js";import{Direction as h,ExcludeMode as N}from"../enums.js";import{BakerError as X}from"../errors.js";import{isAsyncFunction as P,isPromiseLike as Y}from"../utils.js";const I=Symbol.for("baker:arrayOf");function arrayOf(...q){return{rules:q,[I]:!0}}function $(q){return typeof q==="object"&&q!==null&&q[I]===!0}const j=new Set(["type","discriminator","keepDiscriminatorProperty","rules","optional","nullable","name","deserializeName","serializeName","exclude","groups","when","transform","message","context","mapValue","setValue"]);function S(q){if(typeof q==="function")return!1;if(typeof q!=="object"||q===null)return!1;if($(q))return!1;const C=Object.keys(q);if(C.length===0)return!0;return C.some((b)=>j.has(b))}function V(q,C,b){const J=b?`${C} ${b}`:C;if(typeof q==="function"){const Q=q;if(typeof Q.emit!=="function"||typeof Q.ruleName!=="string"){const G=Q.name?` Did you forget to call '${Q.name}()'? Factories must be invoked (e.g., '${Q.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.${G} 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 ${q===null?"null":typeof q}. Use createRule() or import a rule from @zipbul/baker/rules. Valid @Field forms: @Field(), @Field(rule, ...), @Field(options), @Field(rule, ..., options).`)}function z(q){if(q.length===0)return{rules:[],options:{}};if(q.length===1&&S(q[0])){const b=q[0];return{rules:b.rules??[],options:b}}const C=q[q.length-1];if(S(C)){const b=C;let J=q.slice(0,-1);if(b.rules)J=[...J,...b.rules];return{rules:J,options:b}}return{rules:q,options:{}}}function D(q,C,b){for(const J of C)if($(J))for(const H of J.rules){const Q={rule:H,each:!0};if(b.groups!==void 0)Q.groups=b.groups;if(b.message!==void 0)Q.message=b.message;if(b.context!==void 0)Q.context=b.context;q.validation.push(Q)}else{const H={rule:J};if(b.groups!==void 0)H.groups=b.groups;if(b.message!==void 0)H.message=b.message;if(b.context!==void 0)H.context=b.context;q.validation.push(H)}}function _(q,C){if(C.name){const b={name:C.name};if(C.groups!==void 0)b.groups=C.groups;q.expose.push(b)}else if(C.deserializeName||C.serializeName){if(C.deserializeName){const b={name:C.deserializeName,deserializeOnly:!0};if(C.groups!==void 0)b.groups=C.groups;q.expose.push(b)}if(C.serializeName){const b={name:C.serializeName,serializeOnly:!0};if(C.groups!==void 0)b.groups=C.groups;q.expose.push(b)}}else if(C.groups)q.expose.push({groups:C.groups});else q.expose.push({})}function w(q,C,b){const J=P(b);return{fn:(Q)=>{const G=b(Q);if(!J&&Y(G))throw new X(`@Field(${q}) ${C} transform returned Promise. Declare the transform with async if it is asynchronous.`);return G},isAsync:J}}function T(q,C,b){if(!b.transform)return;const J=Array.isArray(b.transform)?b.transform:[b.transform];for(const H of J){const Q=w(C,h.Deserialize,H.deserialize),G=w(C,h.Serialize,H.serialize);q.transform.push({fn:Q.fn,isAsync:Q.isAsync,options:{deserializeOnly:!0}},{fn:G.fn,isAsync:G.isAsync,options:{serializeOnly:!0}})}}function Field(...q){return(C,b)=>{if(b.static)throw new X("@Field cannot decorate static fields.");if(b.private)throw new X("@Field cannot decorate private fields.");if(typeof b.name==="symbol")throw new X("@Field: symbol property keys are not supported. Use a string property name.");const J=b.name,H=L(b.metadata,J),{rules:Q,options:G}=z(q);if(G.name&&(G.deserializeName||G.serializeName))throw new X(`@Field on ${J}: 'name' cannot be combined with 'deserializeName'/'serializeName'. Use one or the other.`);for(let U=0;U<Q.length;U++){const W=Q[U];if($(W))for(let Z=0;Z<W.rules.length;Z++)V(W.rules[Z],J,`arrayOf[${Z}]`);else V(W,J)}D(H,Q,G);if(G.context!==void 0)H.context=G.context;if(G.message!==void 0)H.message=G.message;if(G.optional)H.flags.isOptional=!0;if(G.nullable)H.flags.isNullable=!0;if(G.when)H.flags.validateIf=G.when;if(G.type){const U={fn:G.type};if(G.discriminator!==void 0)U.discriminator=G.discriminator;if(G.keepDiscriminatorProperty!==void 0)U.keepDiscriminatorProperty=G.keepDiscriminatorProperty;const W=G.mapValue??G.setValue;if(W!==void 0)U.collectionValue=W;H.type=U}_(H,G);if(G.exclude){if(G.exclude===!0)H.exclude={};else if(G.exclude===N.DeserializeOnly)H.exclude={deserializeOnly:!0};else if(G.exclude===N.SerializeOnly)H.exclude={serializeOnly:!0}}T(H,J,G)}}export{arrayOf,Field};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{Field,arrayOf}from"./field.js";
|
|
1
|
+
export{Field,arrayOf}from"./field.js";
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** Type a rule assumes for its value — drives the builder's type gate, gate dedup, and autoConvert target. */
|
|
2
|
+
export declare enum RequiredType {
|
|
3
|
+
String = "string",
|
|
4
|
+
Number = "number",
|
|
5
|
+
Boolean = "boolean",
|
|
6
|
+
Date = "date",
|
|
7
|
+
Array = "array",
|
|
8
|
+
Object = "object"
|
|
9
|
+
}
|
|
10
|
+
/** Direction of a (de)serialization pass. */
|
|
11
|
+
export declare enum Direction {
|
|
12
|
+
Deserialize = "deserialize",
|
|
13
|
+
Serialize = "serialize"
|
|
14
|
+
}
|
|
15
|
+
/** Collection container type for a nested field. */
|
|
16
|
+
export declare enum CollectionType {
|
|
17
|
+
Map = "Map",
|
|
18
|
+
Set = "Set"
|
|
19
|
+
}
|
|
20
|
+
/** Cached accessor a RulePlan reuses across checks. */
|
|
21
|
+
export declare enum CacheKey {
|
|
22
|
+
Length = "length",
|
|
23
|
+
Time = "time"
|
|
24
|
+
}
|
|
25
|
+
/** Discriminant for a RulePlanExpr node. */
|
|
26
|
+
export declare enum RulePlanExprKind {
|
|
27
|
+
Value = "value",
|
|
28
|
+
Member = "member",
|
|
29
|
+
Call0 = "call0",
|
|
30
|
+
Literal = "literal"
|
|
31
|
+
}
|
|
32
|
+
/** Discriminant for a RulePlanCheck node. */
|
|
33
|
+
export declare enum RulePlanCheckKind {
|
|
34
|
+
Compare = "compare",
|
|
35
|
+
And = "and",
|
|
36
|
+
Or = "or"
|
|
37
|
+
}
|
|
38
|
+
/** Comparison operator emitted into generated check code. */
|
|
39
|
+
export declare enum RuleOp {
|
|
40
|
+
Lt = "<",
|
|
41
|
+
Lte = "<=",
|
|
42
|
+
Gt = ">",
|
|
43
|
+
Gte = ">=",
|
|
44
|
+
Eq = "===",
|
|
45
|
+
Neq = "!=="
|
|
46
|
+
}
|
|
47
|
+
/** Direction in which a field is excluded. */
|
|
48
|
+
export declare enum ExcludeMode {
|
|
49
|
+
DeserializeOnly = "deserializeOnly",
|
|
50
|
+
SerializeOnly = "serializeOnly"
|
|
51
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export var RequiredType;((b)=>{b.String="string";b.Number="number";b.Boolean="boolean";b.Date="date";b.Array="array";b.Object="object"})(RequiredType||={});export var Direction;((g)=>{g.Deserialize="deserialize";g.Serialize="serialize"})(Direction||={});export var CollectionType;((g)=>{g.Map="Map";g.Set="Set"})(CollectionType||={});export var CacheKey;((g)=>{g.Length="length";g.Time="time"})(CacheKey||={});export var RulePlanExprKind;((j)=>{j.Value="value";j.Member="member";j.Call0="call0";j.Literal="literal"})(RulePlanExprKind||={});export var RulePlanCheckKind;((m)=>{m.Compare="compare";m.And="and";m.Or="or"})(RulePlanCheckKind||={});export var RuleOp;((b)=>{b.Lt="<";b.Lte="<=";b.Gt=">";b.Gte=">=";b.Eq="===";b.Neq="!=="})(RuleOp||={});export var ExcludeMode;((g)=>{g.DeserializeOnly="deserializeOnly";g.SerializeOnly="serializeOnly"})(ExcludeMode||={});
|
package/dist/src/errors.d.ts
CHANGED
|
@@ -47,7 +47,7 @@ export declare function toBakerIssueSet(errors: BakerIssue[]): BakerIssueSet;
|
|
|
47
47
|
*
|
|
48
48
|
* Thrown when, e.g.:
|
|
49
49
|
* - deserialize()/serialize()/validate() is called on an unsealed class
|
|
50
|
-
* -
|
|
50
|
+
* - new Baker() receives a config object with an unknown key or a non-plain-object
|
|
51
51
|
* - seal-time metadata invariants fail (discriminator, Map keys, banned names, …)
|
|
52
52
|
* - per-call options contain unsupported keys
|
|
53
53
|
* - @Field receives a non-rule value, or a rule/transformer factory is misused
|
package/dist/src/errors.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const BAKER_ERROR=Symbol.for("baker:error");export function isBakerIssueSet(
|
|
1
|
+
export const BAKER_ERROR=Symbol.for("baker:error");export function isBakerIssueSet(q){return q!=null&&typeof q==="object"&&!Array.isArray(q)&&q[BAKER_ERROR]===!0}export function toBakerIssueSet(q){return{[BAKER_ERROR]:!0,errors:q}}export class BakerError extends Error{constructor(q,C){super(q,C);this.name="BakerError"}}
|
|
@@ -2,7 +2,7 @@ import type { RuntimeOptions } from '../interfaces';
|
|
|
2
2
|
/**
|
|
3
3
|
* @internal — validate per-call options object at public-API entry.
|
|
4
4
|
* `groups` is the only valid per-call key; everything else is rejected:
|
|
5
|
-
* - seal-time keys (BakerConfig / SealOptions) → "move to
|
|
5
|
+
* - seal-time keys (BakerConfig / SealOptions) → "move to new Baker({...})"
|
|
6
6
|
* - any other key → "unknown call option"
|
|
7
7
|
*/
|
|
8
8
|
export declare function checkCallOptions(opts: unknown): RuntimeOptions | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BakerError as v}from"../errors.js";const x=new Set(["groups"]);const F=new Set(["autoConvert","allowClassDefaults","stopAtFirstError","forbidUnknown","debug","enableImplicitConversion","exposeDefaultValues","whitelist"]);export function checkCallOptions(d){if(d===void 0||d===null)return;if(typeof d!=="object"||Array.isArray(d))throw new v(`Call options must be a plain object. Received: ${Array.isArray(d)?"array":typeof d}.`);const D=Object.getPrototypeOf(d);if(D!==null&&D!==Object.prototype){const q=d.constructor?.name??"unknown";throw new v(`Call options must be a plain object literal. Received instance of ${q}.`)}for(const q of Object.keys(d)){if(x.has(q))continue;if(F.has(q))throw new v(`Option '${q}' is a seal-time setting and cannot be passed per-call. Move it to
|
|
1
|
+
import{BakerError as v}from"../errors.js";const x=new Set(["groups"]);const F=new Set(["autoConvert","allowClassDefaults","stopAtFirstError","forbidUnknown","debug","enableImplicitConversion","exposeDefaultValues","whitelist"]);export function checkCallOptions(d){if(d===void 0||d===null)return;if(typeof d!=="object"||Array.isArray(d))throw new v(`Call options must be a plain object. Received: ${Array.isArray(d)?"array":typeof d}.`);const D=Object.getPrototypeOf(d);if(D!==null&&D!==Object.prototype){const q=d.constructor?.name??"unknown";throw new v(`Call options must be a plain object literal. Received instance of ${q}.`)}for(const q of Object.keys(d)){if(x.has(q))continue;if(F.has(q))throw new v(`Option '${q}' is a seal-time setting and cannot be passed per-call. Move it to new Baker({ ${q}: ... }) at app startup. Per-call options: ${[...x].join(", ")}.`);throw new v(`Unknown per-call option '${q}'. Valid per-call options: ${[...x].join(", ")}. Seal-time options go to new Baker({...}).`)}return d}
|
|
@@ -2,7 +2,7 @@ import type { RuntimeOptions } from '../interfaces';
|
|
|
2
2
|
import { type BakerIssueSet } from '../errors';
|
|
3
3
|
/**
|
|
4
4
|
* Converts input to a Class instance + validates.
|
|
5
|
-
* - Requires `seal()`
|
|
5
|
+
* - Requires the class's baker to be sealed (`new Baker().seal()`) beforehand; throws `BakerError` if not sealed
|
|
6
6
|
* - Sync DTOs return directly; async DTOs return Promise
|
|
7
7
|
* - Success: T
|
|
8
8
|
* - Validation failure: BakerIssueSet (use isBakerIssueSet() to narrow)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RuntimeOptions } from '../interfaces';
|
|
2
2
|
/**
|
|
3
3
|
* Converts a Class instance to a plain object.
|
|
4
|
-
* - Requires `seal()`
|
|
4
|
+
* - Requires the class's baker to be sealed (`new Baker().seal()`) beforehand; throws `BakerError` if not sealed
|
|
5
5
|
* - Sync DTOs return directly; async DTOs return Promise
|
|
6
6
|
* - No validation — always returns Record<string, unknown>
|
|
7
7
|
*/
|
package/dist/src/rule-plan.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type { RequiredType } from './enums';
|
|
1
2
|
import type { EmitContext, InternalRule, RulePlan, RulePlanCheck, RulePlanExpr } from './types';
|
|
3
|
+
import { RuleOp } from './enums';
|
|
2
4
|
type RulePlanCache = {
|
|
3
5
|
length?: string;
|
|
4
6
|
time?: string;
|
|
@@ -7,11 +9,11 @@ declare const planValue: () => RulePlanExpr;
|
|
|
7
9
|
declare const planLength: (object?: RulePlanExpr) => RulePlanExpr;
|
|
8
10
|
declare const planTime: (object?: RulePlanExpr) => RulePlanExpr;
|
|
9
11
|
declare const planLiteral: (value: number) => RulePlanExpr;
|
|
10
|
-
declare const planCompare: (left: RulePlanExpr, op:
|
|
12
|
+
declare const planCompare: (left: RulePlanExpr, op: RuleOp, right: number | RulePlanExpr) => RulePlanCheck;
|
|
11
13
|
declare const planOr: (...checks: RulePlanCheck[]) => RulePlanCheck;
|
|
12
14
|
declare function makePlannedRule(options: {
|
|
13
15
|
name: string;
|
|
14
|
-
requiresType:
|
|
16
|
+
requiresType: RequiredType;
|
|
15
17
|
constraints?: Record<string, unknown>;
|
|
16
18
|
plan: RulePlan;
|
|
17
19
|
validate: (value: unknown) => boolean;
|
|
@@ -20,7 +22,7 @@ declare function makeRule(options: {
|
|
|
20
22
|
name: string;
|
|
21
23
|
validate: (value: unknown) => boolean | Promise<boolean>;
|
|
22
24
|
emit: (varName: string, ctx: EmitContext) => string;
|
|
23
|
-
requiresType?:
|
|
25
|
+
requiresType?: RequiredType;
|
|
24
26
|
constraints?: Record<string, unknown>;
|
|
25
27
|
isAsync?: boolean;
|
|
26
28
|
plan?: RulePlan;
|
package/dist/src/rule-plan.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{defineRuleMetadata as
|
|
1
|
+
import{RuleOp as Y,RulePlanCheckKind as H,RulePlanExprKind as D}from"./enums.js";import{defineRuleMetadata as Z}from"./rule-metadata.js";const planValue=()=>({kind:D.Value});const planLength=(z=planValue())=>({kind:D.Member,object:z,property:"length"});const planTime=(z=planValue())=>({kind:D.Call0,object:z,method:"getTime"});const planLiteral=(z)=>({kind:D.Literal,value:z});const planCompare=(z,A,B)=>({kind:H.Compare,left:z,op:A,right:typeof B==="number"?planLiteral(B):B});const planOr=(...z)=>({kind:H.Or,checks:z});function makePlannedRule(z){const A={name:z.name,requiresType:z.requiresType,plan:z.plan,validate:z.validate,emit:(B,F)=>emitRulePlan(B,F,z.name,z.plan,void 0,F.insideTypeGate)};if(z.constraints!==void 0)A.constraints=z.constraints;return makeRule(A)}function makeRule(z){const A=(F)=>z.validate(F),B={emit:z.emit,ruleName:z.name,constraints:z.constraints??{}};if(z.requiresType!==void 0)B.requiresType=z.requiresType;if(z.isAsync!==void 0)B.isAsync=z.isAsync;if(z.plan!==void 0)B.plan=z.plan;Z(A,B);return A}function emitRulePlan(z,A,B,F,J,W){const X=W?_(F.failure):F.failure;return`if (${U(X,z,J)}) ${A.fail(B)};`}function _(z){if(z.kind===H.Compare)return z;const A=z.checks.filter((B)=>!$(B));if(A.length===0)return z;if(A.length===1)return A[0];return{kind:z.kind,checks:A}}function $(z){if(z.kind!==H.Compare||z.op!==Y.Neq)return!1;return Q(z.left,z.right)}function Q(z,A){if(z.kind!==A.kind)return!1;switch(z.kind){case D.Value:return!0;case D.Literal:return z.value===A.value;case D.Member:return Q(z.object,A.object);case D.Call0:return z.method===A.method&&Q(z.object,A.object);default:return z}}function U(z,A,B){if(z.kind===H.Compare)return`${I(z.left,A,B)} ${z.op} ${I(z.right,A,B)}`;const F=z.kind===H.And?" && ":" || ";return`(${z.checks.map((J)=>U(J,A,B)).join(F)})`}function I(z,A,B){switch(z.kind){case D.Value:return A;case D.Literal:return String(z.value);case D.Member:return B?.length??`${I(z.object,A,B)}.length`;case D.Call0:return B?.time??`${I(z.object,A,B)}.getTime()`;default:return z}}export{planValue,planLength,planTime,planLiteral,planCompare,planOr,makePlannedRule,makeRule,emitRulePlan};
|
package/dist/src/rules/array.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{makePlannedRule as
|
|
1
|
+
import{CacheKey as D,RequiredType as A,RuleOp as F}from"../enums.js";import{makePlannedRule as G,makeRule as H,planCompare as I,planLength as J}from"../rule-plan.js";function arrayContains(b){return H({name:"arrayContains",requiresType:A.Array,constraints:{values:b},validate:(j)=>Array.isArray(j)&&b.every((w)=>j.includes(w)),emit:(j,w)=>{return`if (!refs[${w.addRef(b)}].every(function(v){return ${j}.includes(v);})) ${w.fail("arrayContains")};`}})}function arrayNotContains(b){return H({name:"arrayNotContains",requiresType:A.Array,constraints:{values:b},validate:(j)=>Array.isArray(j)&&b.every((w)=>!j.includes(w)),emit:(j,w)=>{return`if (refs[${w.addRef(b)}].some(function(v){return ${j}.includes(v);})) ${w.fail("arrayNotContains")};`}})}function arrayMinSize(b){const j={cacheKey:D.Length,failure:I(J(),F.Lt,b)};return G({name:"arrayMinSize",requiresType:A.Array,constraints:{min:b},plan:j,validate:(w)=>Array.isArray(w)&&w.length>=b})}function arrayMaxSize(b){const j={cacheKey:D.Length,failure:I(J(),F.Gt,b)};return G({name:"arrayMaxSize",requiresType:A.Array,constraints:{max:b},plan:j,validate:(w)=>Array.isArray(w)&&w.length<=b})}function arrayUnique(b){return H({name:"arrayUnique",requiresType:A.Array,constraints:{},validate:(j)=>{if(!Array.isArray(j))return!1;if(b){const w=j.map(b);return new Set(w).size===w.length}return new Set(j).size===j.length},emit:(j,w)=>{if(b){const B=w.addRef(b);return`{var keys=${j}.map(refs[${B}]);if(new Set(keys).size!==keys.length)${w.fail("arrayUnique")};}`}return`if(new Set(${j}).size!==${j}.length)${w.fail("arrayUnique")};`}})}const Q={cacheKey:D.Length,failure:I(J(),F.Eq,0)};const arrayNotEmpty=G({name:"arrayNotEmpty",requiresType:A.Array,constraints:{},plan:Q,validate:(b)=>Array.isArray(b)&&b.length>0});export{arrayContains,arrayNotContains,arrayMinSize,arrayMaxSize,arrayUnique,arrayNotEmpty};
|
package/dist/src/rules/date.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{makePlannedRule as
|
|
1
|
+
import{CacheKey as A,RequiredType as B,RuleOp as w}from"../enums.js";import{makePlannedRule as D,planCompare as x,planLiteral as E,planOr as F,planTime as b}from"../rule-plan.js";export function minDate(f){const g=f.getTime(),z={cacheKey:A.Time,failure:F(x(b(),w.Neq,b()),x(b(),w.Lt,E(g)))};return D({name:"minDate",requiresType:B.Date,constraints:{min:f.toISOString()},plan:z,validate:(j)=>j instanceof Date&&j.getTime()>=g})}export function maxDate(f){const g=f.getTime(),z={cacheKey:A.Time,failure:F(x(b(),w.Neq,b()),x(b(),w.Gt,E(g)))};return D({name:"maxDate",requiresType:B.Date,constraints:{max:f.toISOString()},plan:z,validate:(j)=>j instanceof Date&&j.getTime()<=g})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BakerError as
|
|
1
|
+
import{RequiredType as Q}from"../enums.js";import{BakerError as U}from"../errors.js";import{makeRule as V}from"../rule-plan.js";const W={"ko-KR":/^(\+?82|0)1[016789]\d{7,8}$/,"en-US":/^\+?1?[2-9]\d{2}[2-9]\d{6}$/,"zh-CN":/^(\+?86)?1[3-9]\d{9}$/,"zh-TW":/^(\+?886)?9\d{8}$/,"ja-JP":/^(\+?81)?0?[789]0[0-9]{8}$/,"de-DE":/^(\+?49)?1(5\d|6[0-9]|7[0-9])\d{8}$/,"fr-FR":/^(\+?33)?[67]\d{8}$/,"en-GB":/^(\+?44)?7[1-9]\d{8}$/,"ru-RU":/^(\+?7)?9\d{9}$/,"pt-BR":/^(\+?55)?[1-9]{2}9?\d{8}$/,"in-IN":/^(\+?91)?[6-9]\d{9}$/,"ar-SA":/^(\+?966)?5\d{8}$/,"ar-EG":/^(\+?20)?1[0125]\d{8}$/,"vi-VN":/^(\+?84)?[35789]\d{8}$/,"th-TH":/^(\+?66)?[689]\d{8}$/,"id-ID":/^(\+?62)?8\d{9,11}$/,"ms-MY":/^(\+?60)?1\d{8,9}$/,"nl-NL":/^(\+?31)?6\d{8}$/,"it-IT":/^(\+?39)?3\d{9}$/,"es-ES":/^(\+?34)?[67]\d{8}$/,"pl-PL":/^(\+?48)?[45789]\d{8}$/};function isMobilePhone(f){return w("isMobilePhone",f,W)}const Z={AD:/^AD\d{3}$/,AT:/^\d{4}$/,AU:/^\d{4}$/,AZ:/^\d{4}$/,BE:/^\d{4}$/,BG:/^\d{4}$/,BR:/^\d{5}-?\d{3}$/,BY:/^\d{6}$/,CA:/^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJ-NPRSTV-Z] ?\d[ABCEGHJ-NPRSTV-Z]\d$/i,CH:/^\d{4}$/,CN:/^\d{6}$/,CZ:/^\d{3} ?\d{2}$/,DE:/^\d{5}$/,DK:/^\d{4}$/,EE:/^\d{5}$/,ES:/^\d{5}$/,FI:/^\d{5}$/,FR:/^\d{2} ?\d{3}$/,GB:/^(GIR ?0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]([0-9ABEHMNPRV-Y])?)|[0-9][A-HJKPSTUW]) ?[0-9][ABD-HJLNP-UW-Z]{2})$/i,GR:/^\d{3} ?\d{2}$/,HR:/^\d{5}$/,HU:/^\d{4}$/,ID:/^\d{5}$/,IL:/^\d{5}(\d{2})?$/,IN:/^\d{6}$/,IS:/^\d{3}$/,IT:/^\d{5}$/,JP:/^\d{3}-?\d{4}$/,KR:/^\d{5}$/,LI:/^(948[5-9]|949[0-7])$/,LT:/^LT-\d{5}$/,LU:/^\d{4}$/,LV:/^LV-\d{4}$/,MX:/^\d{5}$/,MT:/^[A-Z]{3} ?\d{4}$/i,MZ:/^\d{4}$/,NL:/^\d{4} ?[A-Z]{2}$/i,NO:/^\d{4}$/,NP:/^\d{5}$/,NZ:/^\d{4}$/,PH:/^\d{4}$/,PK:/^\d{5}$/,PL:/^\d{2}-\d{3}$/,PR:/^009\d{2}([ -]\d{4})?$/,PT:/^\d{4}-\d{3}$/,RO:/^\d{6}$/,RU:/^\d{6}$/,SE:/^\d{3} ?\d{2}$/,SG:/^\d{6}$/,SI:/^\d{4}$/,SK:/^\d{3} ?\d{2}$/,TH:/^\d{5}$/,TN:/^\d{4}$/,TW:/^\d{3}(\d{2})?$/,UA:/^\d{5}$/,US:/^\d{5}(-\d{4})?$/,ZA:/^\d{4}$/,ZM:/^\d{5}$/};function isPostalCode(f){return w("isPostalCode",f,Z)}const $={AF:/^\d{8}$/,AL:/^[A-Z]\d{8}[A-Z]$/i,AR:/^\d{7,8}$/,AZ:/^AZE\d{8}$/,BE:/^\d{11}$/,BG:/^\d{10}$/,BR:/^\d{9}$/,BY:/^[A-Z]{2}\d{7}$/i,CA:/^\d{9}$/,CH:/^756\d{10}$/,CN:/^\d{15}(\d{2}[0-9xX])?$/,CY:/^\d{7}[A-Z]$/i,CZ:/^\d{9,10}$/,DE:/^[LITOUAEVBMNPRSZDFGHCK]{9}$/i,DK:/^\d{10}$/,EE:/^\d{11}$/,ES:/^[0-9X-Z]\d{7}[TRWAGMYFPDXBNJZSQVHLCKE]$/i,FI:/^\d{6}[+-A]\d{3}[0-9A-FHJ-NPR-Y]$/,FR:/^\d{8,9}[0-9\u00C1-\u00FF]{1}$/i,GB:/^[A-Z]{2}\d{6}[A-Z]$/i,GR:/^[A-Z]{2}\d{6}$/i,HR:/^\d{11}$/,HU:/^\d{8}[A-Z]{2}$/i,ID:/^\d{16}$/,IE:/^\d{7}[A-W][A-W]?$/,IL:/^\d{9}$/,IN:/^\d{12}$/,IR:/^\d{10}$/,IS:/^\d{10}$/,IT:/^[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]$/i,JP:/^\d{12}$/,KR:/^\d{6}-\d{7}$/,LT:/^\d{11}$/,LU:/^\d{13}$/,LV:/^\d{6}-\d{5}$/,MK:/^\d{13}$/,MX:/^[A-Z]{4}\d{6}[HM][A-Z]{2}[B-DF-HJ-NP-TV-Z]{3}[A-Z0-9]\d$/i,MT:/^\d{7}[A-Z]$/i,NL:/^\d{9}$/,NO:/^\d{11}$/,PL:/^\d{11}$/,PT:/^[1-9]\d{7}[0-9TV]$/i,RO:/^\d{13}$/,RS:/^\d{13}$/,RU:/^\d{10}$/,SE:/^\d{10,12}$/,SI:/^\d{13}$/,SK:/^\d{9,10}$/,TH:/^\d{13}$/,TR:/^\d{11}$/,TW:/^[A-Z]\d{9}$/i,UA:/^\d{9}$/,US:/^\d{3}-\d{2}-\d{4}$/,ZA:/^\d{13}$/};function isIdentityCard(f){return w("isIdentityCard",f,$)}const h={AM:/^[A-Z]{2}\d{7}$/i,AR:/^[A-Z]{3}\d{6}$/i,AT:/^[A-Z]\d{7}$/i,AU:/^[A-Z]\d{7}$/i,AZ:/^[Aa]\d{8}$/,BE:/^[A-Z]{2}\d{6}$/i,BG:/^\d{9}$/,BH:/^[A-Z]{2}\d{6}$/i,BR:/^[A-Z]{2}\d{6}$/i,BY:/^[A-Z]{2}\d{7}$/i,CA:/^[A-Z]{2}\d{6}$/i,CH:/^[A-Z]\d{7}$/i,CN:/^G\d{8}$/,CY:/^[A-Z](\d{6}|\d{8})$/i,CZ:/^\d{8}$/,DE:/^[CFGHJKLMNPRTVWXYZ0-9]{9}$/i,DK:/^\d{9}$/,EE:/^([A-Z]\d{7}|[A-Z]{2}\d{7})$/i,ES:/^[A-Z0-9]{2}([A-Z0-9]?)\d{6}$/i,FI:/^[A-Z]{2}\d{7}$/i,FR:/^[A-Z0-9]{9}$/i,GB:/^\d{9}$/,GR:/^[A-Z]{2}\d{7}$/i,HR:/^\d{9}$/,HU:/^[A-Z]{2}(\d{6}|\d{7})$/i,ID:/^[A-C]\d{7}$/i,IE:/^[A-Z0-9]{2}\d{7}$/i,IL:/^\d{9}$/,IN:/^[A-Z]\d{7}$/i,IR:/^[A-Z]\d{8}$/i,IS:/^(A)\d{7}$/i,IT:/^[A-Z0-9]{9}$/i,JO:/^[A-Z]{2}\d{7}$/i,JP:/^[A-Z]{2}\d{7}$/i,KR:/^[A-Z][A-Z0-9]\d{7}$/i,KW:/^\d{8}$/,KZ:/^[A-Z]\d{8}$/i,LI:/^[A-Z]\d{6}X$/i,LT:/^[A-Z0-9]{8}$/i,LU:/^[A-Z0-9]{8}$/i,LV:/^[A-Z0-9]{2}\d{7}$/i,LY:/^[A-Z]{2}\d{7}$/i,MA:/^[A-Z0-9]{2}\d{7}$/i,MD:/^[A-Z]{2}\d{7}$/i,ME:/^[A-Z]{2}\d{7}$/i,MK:/^[A-Z]\d{7}$/i,MT:/^\d{7}$/,MX:/^[A-Z]\d{8}$/i,MY:/^[AHK]\d{8}[A-Z]$/i,NL:/^[A-NP-Z]{2}[A-NP-Z0-9]{6}\d$/i,NO:/^\d{9}$/,NZ:/^[A-Z]{2}\d{6}$/i,PH:/^[A-Z]\d{7}[A-Z]$/i,PK:/^[A-Z]{2}\d{7}$/i,PL:/^[A-Z]{2}\d{7}$/i,PT:/^[A-Z]\d{6}$/i,RO:/^\d{8}$/,RS:/^\d{9}$/,RU:/^\d{9}$/,SA:/^[A-Z]\d{8}$/i,SE:/^\d{8}$/,SL:/^(P)[A-Z]\d{7}$/i,SK:/^[0-9A-Z]\d{7}$/i,TH:/^[A-Z]{1,2}\d{6,7}$/i,TN:/^\d{8}$/,TR:/^[A-Z]\d{8}$/i,TW:/^[A-Z]\d{9}$/i,UA:/^[A-Z]{2}\d{6}$/i,US:/^\d{9}$/,ZA:/^[A-Z]\d{8}$/i};function isPassportNumber(f){return w("isPassportNumber",f,h)}function w(f,z,K){const F=K[z];if(!F)throw new U(`Unsupported locale: "${z}" for ${f}`);return V({name:f,requiresType:Q.String,constraints:{locale:z},validate:(j)=>typeof j==="string"&&F.test(j),emit:(j,J)=>{return`if (!re[${J.addRegex(F)}].test(${j})) ${J.fail(f)};`}})}export{isMobilePhone,isPostalCode,isIdentityCard,isPassportNumber};
|
package/dist/src/rules/number.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BakerError as
|
|
1
|
+
import{RequiredType as A,RuleOp as h}from"../enums.js";import{BakerError as I}from"../errors.js";import{makePlannedRule as D,makeRule as J,planCompare as z,planLiteral as F,planOr as G,planValue as f}from"../rule-plan.js";export function min(b,w){if(!Number.isFinite(b))throw new I(`min: bound must be a finite number, got ${b}`);const j=w?.exclusive??!1,H={failure:G(z(f(),h.Neq,f()),z(f(),j?h.Lte:h.Lt,F(b)))};return D({name:"min",requiresType:A.Number,constraints:j?{min:b,exclusive:!0}:{min:b},plan:H,validate:j?(g)=>typeof g==="number"&&g>b:(g)=>typeof g==="number"&&g>=b})}export function max(b,w){if(!Number.isFinite(b))throw new I(`max: bound must be a finite number, got ${b}`);const j=w?.exclusive??!1,H={failure:G(z(f(),h.Neq,f()),z(f(),j?h.Gte:h.Gt,F(b)))};return D({name:"max",requiresType:A.Number,constraints:j?{max:b,exclusive:!0}:{max:b},plan:H,validate:j?(g)=>typeof g==="number"&&g<b:(g)=>typeof g==="number"&&g<=b})}export const isPositive=D({name:"isPositive",requiresType:A.Number,constraints:{min:0,exclusive:!0},plan:{failure:G(z(f(),h.Neq,f()),z(f(),h.Lte,F(0)))},validate:(b)=>typeof b==="number"&&b>0});export const isNegative=D({name:"isNegative",requiresType:A.Number,constraints:{max:0,exclusive:!0},plan:{failure:G(z(f(),h.Neq,f()),z(f(),h.Gte,F(0)))},validate:(b)=>typeof b==="number"&&b<0});export function isDivisibleBy(b){if(b===0)throw new I("isDivisibleBy: divisor must not be zero");return J({name:"isDivisibleBy",requiresType:A.Number,constraints:{divisor:b},validate:(w)=>typeof w==="number"&&w%b===0,emit:(w,j)=>`if (${w} % ${b} !== 0) ${j.fail("isDivisibleBy")};`})}
|
package/dist/src/rules/object.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{makeRule as
|
|
1
|
+
import{RequiredType as C}from"../enums.js";import{makeRule as B}from"../rule-plan.js";export function isNotEmptyObject(w){const z=(f)=>{if(f===null||typeof f!=="object"||Array.isArray(f))return!1;const h=f;if(w?.nullable){for(const A in h)if(h[A]!=null)return!0;return!1}for(const A in h)return!0;return!1};return B({name:"isNotEmptyObject",requiresType:C.Object,constraints:{nullable:w?.nullable},validate:z,emit:(f,h)=>{if(w?.nullable)return`{var __ne=false;for(var __k in ${f}){if(${f}[__k]!=null){__ne=true;break;}}if(!__ne) ${h.fail("isNotEmptyObject")};}`;return`{var __ne=false;for(var __k in ${f}){__ne=true;break;}if(!__ne) ${h.fail("isNotEmptyObject")};}`}})}export function isInstance(w){return B({name:"isInstance",constraints:{type:w.name},validate:(z)=>z instanceof w,emit:(z,f)=>{const h=f.addRef(w);return`if (!(${z} instanceof refs[${h}])) ${f.fail("isInstance")};`}})}
|