@zipbul/baker 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -6
- package/dist/index-70ggmxsa.js +6 -0
- package/dist/index-gcptd79v.js +6 -0
- package/dist/index.js +194 -137
- package/dist/src/collect.d.ts +3 -3
- package/dist/src/configure.d.ts +13 -13
- package/dist/src/create-rule.d.ts +7 -7
- package/dist/src/decorators/field.d.ts +32 -20
- package/dist/src/decorators/index.js +1 -1
- package/dist/src/errors.d.ts +17 -17
- package/dist/src/functions/deserialize.d.ts +6 -5
- package/dist/src/functions/serialize.d.ts +5 -4
- package/dist/src/functions/to-json-schema.d.ts +7 -7
- package/dist/src/interfaces.d.ts +7 -7
- package/dist/src/registry.d.ts +4 -4
- package/dist/src/rules/index.js +4 -4
- package/dist/src/rules/object.d.ts +1 -1
- package/dist/src/seal/circular-analyzer.d.ts +4 -4
- package/dist/src/seal/expose-validator.d.ts +6 -6
- package/dist/src/seal/seal.d.ts +16 -16
- package/dist/src/seal/serialize-builder.d.ts +2 -2
- package/dist/src/symbols.d.ts +5 -5
- package/dist/src/symbols.js +1 -1
- package/dist/src/types.d.ts +34 -28
- package/package.json +1 -1
- package/dist/index-57gr0v18.js +0 -6
- package/dist/index-aegrb1kn.js +0 -6
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { RawClassMeta } from '../types';
|
|
2
2
|
/**
|
|
3
|
-
* @Expose
|
|
3
|
+
* Static validation of @Expose stacks (§4.1, §3.3)
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
5
|
+
* Check 1: same @Expose entry has deserializeOnly: true + serializeOnly: true → excluded from both directions
|
|
6
|
+
* Check 2: if 2+ @Expose entries in the same direction have overlapping groups → SealError
|
|
7
|
+
* - both groups=[] (ungrouped) → overlap
|
|
8
|
+
* - both non-empty groups with intersection → overlap
|
|
9
|
+
* - one ungrouped + one grouped → no overlap (different scope)
|
|
10
10
|
*/
|
|
11
11
|
export declare function validateExposeStacks(merged: RawClassMeta, className?: string): void;
|
package/dist/src/seal/seal.d.ts
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
import type { RawClassMeta, SealedExecutors } from '../types';
|
|
2
2
|
/** @internal Placeholder executor for circular dependency detection during seal */
|
|
3
3
|
declare function _circularPlaceholder(className: string): SealedExecutors<unknown>;
|
|
4
|
-
/** @internal — configure()
|
|
4
|
+
/** @internal — used by configure() to warn about post-seal calls */
|
|
5
5
|
export declare function _isSealed(): boolean;
|
|
6
|
-
/**
|
|
6
|
+
/** List of sealed classes — used by unseal to remove SEALED */
|
|
7
7
|
export declare const _sealedClasses: Set<Function>;
|
|
8
8
|
/**
|
|
9
|
-
* @internal — deserialize/serialize
|
|
10
|
-
*
|
|
9
|
+
* @internal — called from deserialize/serialize.
|
|
10
|
+
* No-op if already sealed.
|
|
11
11
|
*/
|
|
12
12
|
export declare function _autoSeal(): void;
|
|
13
13
|
/**
|
|
14
|
-
* @internal —
|
|
15
|
-
* Class[RAW]
|
|
14
|
+
* @internal — on-demand seal for classes registered after auto-seal via dynamic import.
|
|
15
|
+
* Only operates when Class[RAW] exists and Class[SEALED] does not.
|
|
16
16
|
*/
|
|
17
17
|
export declare function _sealOnDemand(Class: Function): void;
|
|
18
18
|
/**
|
|
19
|
-
* @internal
|
|
19
|
+
* @internal testing only — called by unseal() in testing.ts
|
|
20
20
|
*/
|
|
21
21
|
export declare function _resetForTesting(): void;
|
|
22
22
|
/**
|
|
23
|
-
* @internal — serialize/deserialize
|
|
23
|
+
* @internal — used by serialize/deserialize. Ensures and returns a sealed executor.
|
|
24
24
|
*/
|
|
25
25
|
export declare function _ensureSealed(Class: Function): SealedExecutors<unknown>;
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* Merges RAW metadata child-first along the prototype chain of Class.
|
|
28
28
|
*
|
|
29
|
-
*
|
|
30
|
-
* - validation: union merge (
|
|
31
|
-
* - transform:
|
|
32
|
-
* - expose:
|
|
33
|
-
* - exclude:
|
|
34
|
-
* - type:
|
|
35
|
-
* - flags:
|
|
29
|
+
* Merge rules:
|
|
30
|
+
* - validation: union merge (both parent and child apply, duplicate rules removed)
|
|
31
|
+
* - transform: child takes priority, inherits from parent if absent in child
|
|
32
|
+
* - expose: child takes priority, inherits from parent if absent in child
|
|
33
|
+
* - exclude: child takes priority, inherits from parent if absent in child
|
|
34
|
+
* - type: child takes priority, inherits from parent if absent in child
|
|
35
|
+
* - flags: child takes priority, only missing flags are supplemented from parent
|
|
36
36
|
*/
|
|
37
37
|
export declare function mergeInheritance(Class: Function): RawClassMeta;
|
|
38
38
|
export declare const __testing__: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RawClassMeta } from '../types';
|
|
2
2
|
import type { SealOptions, RuntimeOptions } from '../interfaces';
|
|
3
3
|
/**
|
|
4
|
-
* serialize executor
|
|
5
|
-
*
|
|
4
|
+
* Generate serialize executor code.
|
|
5
|
+
* Assumes no validation — always returns Record<string, unknown> (§4.3).
|
|
6
6
|
*/
|
|
7
7
|
export declare function buildSerializeCode<T>(Class: Function, merged: RawClassMeta, options: SealOptions | undefined, isAsync: boolean): (instance: T, opts?: RuntimeOptions) => Record<string, unknown> | Promise<Record<string, unknown>>;
|
package/dist/src/symbols.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 2
|
|
3
|
-
* Symbol.for
|
|
2
|
+
* 2 Symbols — zero external storage, zero global pollution
|
|
3
|
+
* Uses Symbol.for: allows AOT code and runtime code to share the same Symbol via the global registry
|
|
4
4
|
*/
|
|
5
|
-
/** Tier 1
|
|
5
|
+
/** Tier 1 collection metadata (stored on Class by decorators) */
|
|
6
6
|
export declare const RAW: unique symbol;
|
|
7
|
-
/** Tier 2
|
|
7
|
+
/** Tier 2 seal result (dual executor stored on Class by seal()) */
|
|
8
8
|
export declare const SEALED: unique symbol;
|
|
9
|
-
/**
|
|
9
|
+
/** Class-level @Schema() metadata */
|
|
10
10
|
export declare const RAW_CLASS_SCHEMA: unique symbol;
|
package/dist/src/symbols.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{e as a,f as b,g as c}from"../index-
|
|
2
|
+
import{e as a,f as b,g as c}from"../index-70ggmxsa.js";export{b as SEALED,c as RAW_CLASS_SCHEMA,a as RAW};
|
|
3
3
|
|
|
4
4
|
//# debugId=51B5F46B85FFE3B364756E2164756E21
|
|
5
5
|
//# sourceMappingURL=symbols.js.map
|
package/dist/src/types.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export interface EmitContext {
|
|
2
|
-
/** RegExp
|
|
2
|
+
/** Register a RegExp in the reference array, return its index */
|
|
3
3
|
addRegex(re: RegExp): number;
|
|
4
|
-
/**
|
|
4
|
+
/** Register in the reference array, return its index — functions, arrays, Sets, primitives, etc. */
|
|
5
5
|
addRef(value: unknown): number;
|
|
6
|
-
/** SealedExecutors
|
|
6
|
+
/** Register a SealedExecutors object in the reference array — for nested @Type DTOs */
|
|
7
7
|
addExecutor(executor: SealedExecutors<unknown>): number;
|
|
8
|
-
/**
|
|
8
|
+
/** Generate a failure code string from an error code — path is bound by the builder */
|
|
9
9
|
fail(code: string): string;
|
|
10
|
-
/**
|
|
10
|
+
/** Whether error collection mode is enabled (= !stopAtFirstError) */
|
|
11
11
|
collectErrors: boolean;
|
|
12
12
|
}
|
|
13
13
|
export interface EmittableRule {
|
|
@@ -15,17 +15,17 @@ export interface EmittableRule {
|
|
|
15
15
|
emit(varName: string, ctx: EmitContext): string;
|
|
16
16
|
readonly ruleName: string;
|
|
17
17
|
/**
|
|
18
|
-
* builder
|
|
19
|
-
*
|
|
20
|
-
* @IsString
|
|
18
|
+
* Meta for the builder to determine whether to insert a typeof guard.
|
|
19
|
+
* Only set for rules that assume a specific type (e.g., isEmail → 'string').
|
|
20
|
+
* @IsString itself is undefined (it includes its own typeof check).
|
|
21
21
|
*/
|
|
22
22
|
readonly requiresType?: 'string' | 'number' | 'boolean' | 'date';
|
|
23
|
-
/**
|
|
23
|
+
/** Expose rule parameters for external reading — used for toJsonSchema mapping */
|
|
24
24
|
readonly constraints?: Record<string, unknown>;
|
|
25
|
-
/**
|
|
25
|
+
/** true when using an async validate function — deserialize-builder generates await code */
|
|
26
26
|
readonly isAsync?: boolean;
|
|
27
27
|
}
|
|
28
|
-
/**
|
|
28
|
+
/** Arguments for user-defined message callback */
|
|
29
29
|
export interface MessageArgs {
|
|
30
30
|
property: string;
|
|
31
31
|
value: unknown;
|
|
@@ -35,17 +35,17 @@ export interface RuleDef {
|
|
|
35
35
|
rule: EmittableRule;
|
|
36
36
|
each?: boolean;
|
|
37
37
|
groups?: string[];
|
|
38
|
-
/**
|
|
38
|
+
/** Value to include in BakerError.message on validation failure */
|
|
39
39
|
message?: string | ((args: MessageArgs) => string);
|
|
40
|
-
/**
|
|
40
|
+
/** Arbitrary value to include in BakerError.context on validation failure */
|
|
41
41
|
context?: unknown;
|
|
42
42
|
}
|
|
43
|
-
/** @Transform
|
|
43
|
+
/** @Transform callback signature */
|
|
44
44
|
export type TransformFunction = (params: TransformParams) => unknown;
|
|
45
45
|
export interface TransformParams {
|
|
46
46
|
value: unknown;
|
|
47
47
|
key: string;
|
|
48
|
-
/** deserialize: input
|
|
48
|
+
/** deserialize: original input object, serialize: class instance */
|
|
49
49
|
obj: Record<string, unknown>;
|
|
50
50
|
type: 'deserialize' | 'serialize';
|
|
51
51
|
}
|
|
@@ -77,23 +77,29 @@ export interface TypeDef {
|
|
|
77
77
|
}[];
|
|
78
78
|
};
|
|
79
79
|
keepDiscriminatorProperty?: boolean;
|
|
80
|
-
/** seal()
|
|
80
|
+
/** seal() normalization result — true if fn() returns an array */
|
|
81
81
|
isArray?: boolean;
|
|
82
|
-
/** seal()
|
|
82
|
+
/** seal() normalization result — cached class after resolving fn() (DTOs only, excluding primitives) */
|
|
83
83
|
resolvedClass?: new (...args: any[]) => any;
|
|
84
|
+
/** seal() normalization result — Map or Set collection type */
|
|
85
|
+
collection?: 'Map' | 'Set';
|
|
86
|
+
/** Nested DTO class thunk for Map value / Set element */
|
|
87
|
+
collectionValue?: () => new (...args: any[]) => any;
|
|
88
|
+
/** seal() normalization result — cached class after resolving collectionValue */
|
|
89
|
+
resolvedCollectionValue?: new (...args: any[]) => any;
|
|
84
90
|
}
|
|
85
91
|
export interface PropertyFlags {
|
|
86
|
-
/** @IsOptional() —
|
|
92
|
+
/** @IsOptional() — skip all validation when undefined/null */
|
|
87
93
|
isOptional?: boolean;
|
|
88
|
-
/** @IsDefined() — undefined
|
|
94
|
+
/** @IsDefined() — disallow undefined (overrides @IsOptional). Current code rejects only undefined; null is delegated to subsequent validation */
|
|
89
95
|
isDefined?: boolean;
|
|
90
|
-
/** @IsNullable() — null
|
|
96
|
+
/** @IsNullable() — allow and assign null, reject undefined */
|
|
91
97
|
isNullable?: boolean;
|
|
92
|
-
/** @ValidateIf(cond) —
|
|
98
|
+
/** @ValidateIf(cond) — skip all field validation when false */
|
|
93
99
|
validateIf?: (obj: any) => boolean;
|
|
94
|
-
/** @ValidateNested() —
|
|
100
|
+
/** @ValidateNested() — trigger recursive validation for nested DTOs. Used with @Type */
|
|
95
101
|
validateNested?: boolean;
|
|
96
|
-
/** @ValidateNested({ each: true }) —
|
|
102
|
+
/** @ValidateNested({ each: true }) — validate nested DTOs per array element */
|
|
97
103
|
validateNestedEach?: boolean;
|
|
98
104
|
}
|
|
99
105
|
export interface RawPropertyMeta {
|
|
@@ -112,15 +118,15 @@ import type { RuntimeOptions } from './interfaces';
|
|
|
112
118
|
import type { BakerError } from './errors';
|
|
113
119
|
import type { Result, ResultAsync } from '@zipbul/result';
|
|
114
120
|
export interface SealedExecutors<T> {
|
|
115
|
-
/**
|
|
121
|
+
/** Internal executor — Result pattern. deserialize() wraps and converts to throw */
|
|
116
122
|
_deserialize(input: unknown, options?: RuntimeOptions): Result<T, BakerError[]> | ResultAsync<T, BakerError[]>;
|
|
117
|
-
/**
|
|
123
|
+
/** Internal executor — always succeeds. serialize assumes no validation */
|
|
118
124
|
_serialize(instance: T, options?: RuntimeOptions): Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
119
|
-
/** deserialize
|
|
125
|
+
/** true if the deserialize direction has async rules/transforms/nested */
|
|
120
126
|
_isAsync: boolean;
|
|
121
|
-
/** serialize
|
|
127
|
+
/** true if the serialize direction has async transforms/nested */
|
|
122
128
|
_isSerializeAsync: boolean;
|
|
123
|
-
/**
|
|
129
|
+
/** Merged metadata cache at seal time — used by toJsonSchema (valid even after RAW is deleted) */
|
|
124
130
|
_merged?: RawClassMeta;
|
|
125
131
|
}
|
|
126
132
|
export interface JsonSchema202012 {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zipbul/baker",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Decorator-based validate + transform with inline code generation. class-validator DX, AOT-level performance, zero reflect-metadata.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Junhyung Park (https://github.com/parkrevil)",
|
package/dist/index-57gr0v18.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{e as J}from"./index-aegrb1kn.js";var Q=new Set;function T(b,w){if(!Object.prototype.hasOwnProperty.call(b,J))b[J]=Object.create(null),Q.add(b);let j=b[J];return j[w]??={validation:[],transform:[],expose:[],exclude:null,type:null,flags:{},schema:null}}function U(b){return b[Symbol.toStringTag]==="AsyncFunction"}var Z=Symbol.for("baker:arrayOf");function d(...b){let w={rules:b};return w[Z]=!0,w}function $(b){return typeof b==="object"&&b!==null&&b[Z]===!0}var K=new Set(["type","discriminator","keepDiscriminatorProperty","rules","optional","nullable","name","deserializeName","serializeName","exclude","groups","when","schema","transform","transformDirection"]);function X(b){if(typeof b==="function")return!1;if(typeof b!=="object"||b===null)return!1;if($(b))return!1;let w=Object.keys(b);if(w.length===0)return!0;return w.some((j)=>K.has(j))}function N(b){if(b.length===0)return{rules:[],options:{}};if(b.length===1&&X(b[0])){let j=b[0];return{rules:j.rules??[],options:j}}let w=b[b.length-1];if(X(w)){let j=w,B=b.slice(0,-1);if(j.rules)B=[...B,...j.rules];return{rules:B,options:j}}return{rules:b,options:{}}}function P(b,w,j){for(let B of w)if($(B))for(let G of B.rules)b.validation.push({rule:G,each:!0,groups:j.groups});else b.validation.push({rule:B,groups:j.groups})}function S(b,w){if(w.name)b.expose.push({name:w.name,groups:w.groups});else if(w.deserializeName||w.serializeName){if(w.deserializeName)b.expose.push({name:w.deserializeName,deserializeOnly:!0,groups:w.groups});if(w.serializeName)b.expose.push({name:w.serializeName,serializeOnly:!0,groups:w.groups})}else if(w.groups)b.expose.push({groups:w.groups});else b.expose.push({})}function V(b,w){if(!w.transform)return;let j=w.transform,G=U(j)?async(z)=>j({value:z.value,key:z.key,obj:z.obj,direction:z.type}):(z)=>j({value:z.value,key:z.key,obj:z.obj,direction:z.type});if(w.transformDirection&&w.transformDirection!=="deserializeOnly"&&w.transformDirection!=="serializeOnly")throw Error(`Invalid transformDirection: "${w.transformDirection}". Expected 'deserializeOnly' or 'serializeOnly'.`);let q={};if(w.transformDirection==="deserializeOnly")q.deserializeOnly=!0;if(w.transformDirection==="serializeOnly")q.serializeOnly=!0;b.transform.push({fn:G,options:Object.keys(q).length>0?q:void 0})}function F(...b){return(w,j)=>{let B=w.constructor,q=T(B,j),{rules:z,options:v}=N(b);if(P(q,z,v),v.optional)q.flags.isOptional=!0;if(v.nullable)q.flags.isNullable=!0;if(v.when)q.flags.validateIf=v.when;if(v.type)q.type={fn:v.type,discriminator:v.discriminator,keepDiscriminatorProperty:v.keepDiscriminatorProperty};if(S(q,v),v.exclude){if(v.exclude===!0)q.exclude={};else if(v.exclude==="deserializeOnly")q.exclude={deserializeOnly:!0};else if(v.exclude==="serializeOnly")q.exclude={serializeOnly:!0}}if(V(q,v),v.schema)if(typeof q.schema==="function");else q.schema={...q.schema??{},...v.schema}}}
|
|
3
|
-
export{Q as a,U as b,d as c,F as d};
|
|
4
|
-
|
|
5
|
-
//# debugId=3AECA7367D7355B264756E2164756E21
|
|
6
|
-
//# sourceMappingURL=index-57gr0v18.js.map
|
package/dist/index-aegrb1kn.js
DELETED