@zipbul/baker 0.0.1 → 0.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.
Files changed (48) hide show
  1. package/README.ko.md +64 -12
  2. package/README.md +64 -12
  3. package/dist/index-jzjz61tg.js +14 -0
  4. package/dist/index-jzjz61tg.js.map +31 -0
  5. package/dist/index-txxjqhgc.js +6 -0
  6. package/dist/{index-w36xamck.js.map → index-txxjqhgc.js.map} +3 -3
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.js +2 -142
  9. package/dist/index.js.map +3 -12
  10. package/dist/src/collect.d.ts +2 -0
  11. package/dist/src/create-rule.d.ts +4 -0
  12. package/dist/src/decorators/common.d.ts +6 -0
  13. package/dist/src/decorators/index.d.ts +4 -1
  14. package/dist/src/decorators/index.js +2 -2
  15. package/dist/src/decorators/index.js.map +1 -1
  16. package/dist/src/decorators/nested.d.ts +17 -0
  17. package/dist/src/decorators/number.d.ts +8 -4
  18. package/dist/src/decorators/schema.d.ts +13 -0
  19. package/dist/src/errors.d.ts +2 -0
  20. package/dist/src/functions/index.d.ts +2 -0
  21. package/dist/src/functions/to-json-schema.d.ts +14 -0
  22. package/dist/src/interfaces.d.ts +7 -1
  23. package/dist/src/rules/index.js +2 -2
  24. package/dist/src/rules/index.js.map +1 -1
  25. package/dist/src/rules/number.d.ts +6 -2
  26. package/dist/src/seal/deserialize-builder.d.ts +3 -3
  27. package/dist/src/symbols.d.ts +2 -0
  28. package/dist/src/symbols.js +2 -2
  29. package/dist/src/symbols.js.map +1 -1
  30. package/dist/src/types.d.ts +65 -4
  31. package/package.json +4 -8
  32. package/dist/index-6pbm9cq6.js +0 -15
  33. package/dist/index-6pbm9cq6.js.map +0 -17
  34. package/dist/index-fww37qs9.js +0 -5
  35. package/dist/index-fww37qs9.js.map +0 -20
  36. package/dist/index-w36xamck.js +0 -6
  37. package/dist/src/aot/array.d.ts +0 -7
  38. package/dist/src/aot/common.d.ts +0 -15
  39. package/dist/src/aot/date.d.ts +0 -3
  40. package/dist/src/aot/index.d.ts +0 -9
  41. package/dist/src/aot/index.js +0 -5
  42. package/dist/src/aot/index.js.map +0 -18
  43. package/dist/src/aot/locales.d.ts +0 -5
  44. package/dist/src/aot/number.d.ts +0 -6
  45. package/dist/src/aot/object.d.ts +0 -6
  46. package/dist/src/aot/string.d.ts +0 -72
  47. package/dist/src/aot/transform.d.ts +0 -25
  48. package/dist/src/aot/typechecker.d.ts +0 -10
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/symbols.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * 2개의 Symbol — 외부 저장소 0, 글로벌 오염 0\n * Symbol.for 사용: AOT 코드와 런타임 코드가 동일 Symbol을 공유할 수 있도록 global registry 사용\n */\n\n/** Tier 1 수집 메타데이터 (데코레이터가 Class에 저장) */\nexport const RAW = Symbol.for('baker:raw');\n\n/** Tier 2 봉인 결과 (seal()이 Class에 저장하는 dual executor) */\nexport const SEALED = Symbol.for('baker:sealed');\n"
5
+ "/**\n * 2개의 Symbol — 외부 저장소 0, 글로벌 오염 0\n * Symbol.for 사용: AOT 코드와 런타임 코드가 동일 Symbol을 공유할 수 있도록 global registry 사용\n */\n\n/** Tier 1 수집 메타데이터 (데코레이터가 Class에 저장) */\nexport const RAW = Symbol.for('baker:raw');\n\n/** Tier 2 봉인 결과 (seal()이 Class에 저장하는 dual executor) */\nexport const SEALED = Symbol.for('baker:sealed');\n\n/** 클래스 레벨 @Schema() 메타데이터 */\nexport const RAW_CLASS_SCHEMA = Symbol.for('baker:rawClassSchema');\n"
6
6
  ],
7
- "mappings": ";AAMO,IAAM,EAAM,OAAO,IAAI,WAAW,EAG5B,EAAS,OAAO,IAAI,cAAc",
8
- "debugId": "321B40856435C9B864756E2164756E21",
7
+ "mappings": ";AAMO,IAAM,EAAM,OAAO,IAAI,WAAW,EAG5B,EAAS,OAAO,IAAI,cAAc,EAGlC,EAAmB,OAAO,IAAI,sBAAsB",
8
+ "debugId": "046CBE9237E503F764756E2164756E21",
9
9
  "names": []
10
10
  }
package/dist/index.d.ts CHANGED
@@ -1,9 +1,12 @@
1
1
  export { seal } from './src/seal/seal';
2
2
  export { deserialize } from './src/functions/deserialize';
3
3
  export { serialize } from './src/functions/serialize';
4
+ export { toJsonSchema } from './src/functions/to-json-schema';
4
5
  export { createRule } from './src/create-rule';
5
6
  export { unregister } from './src/registry';
6
7
  export * from './src/decorators/index';
7
8
  export type { BakerError } from './src/errors';
8
9
  export { BakerValidationError, SealError } from './src/errors';
10
+ export type { JsonSchema202012 } from './src/types';
9
11
  export type { ValidationOptions, SealOptions, RuntimeOptions } from './src/interfaces';
12
+ export type { ToJsonSchemaOptions } from './src/functions/to-json-schema';
package/dist/index.js CHANGED
@@ -1,145 +1,5 @@
1
1
  // @bun
2
- import{$ as dH,$a as dJ,A as wH,Aa as wJ,B as zH,Ba as zJ,C as DH,Ca as DJ,D as hH,Da as hJ,E as GH,Ea as GJ,F as SH,Fa as SJ,G as VH,Ga as VJ,H as AH,Ha as AJ,I as bH,Ia as bJ,J as kH,Ja as kJ,K as gH,Ka as gJ,L as EH,La as EJ,M as NH,Ma as NJ,N as KH,Na as KJ,O as CH,Oa as CJ,P as uH,Pa as uJ,Q as vH,Qa as vJ,R as pH,Ra as pJ,S as fH,Sa as fJ,T as xH,Ta as xJ,U as yH,Ua as yJ,V as nH,Va as nJ,W as cH,Wa as cJ,X as lH,Xa as lJ,Y as mH,Ya as mJ,Z as oH,Za as oJ,_ as iH,_a as iJ,a as s,aa as sH,ab as sJ,b as Oq,ba as tH,bb as tJ,c as rq,ca as rH,cb as rJ,d as aq,da as aH,db as aJ,e as eq,ea as eH,f as qH,fa as qJ,g as HH,ga as HJ,h as JH,ha as JJ,i as QH,ia as QJ,j as UH,ja as UJ,k as XH,ka as XJ,l as YH,la as YJ,m as ZH,ma as ZJ,n as $H,na as $J,o as BH,oa as BJ,p as jH,pa as jJ,q as MH,qa as MJ,r as PH,ra as PJ,s as WH,sa as WJ,t as FH,ta as FJ,u as LH,ua as LJ,v as OH,va as OJ,w as _H,wa as _J,x as TH,xa as TJ,y as RH,ya as RJ,z as IH,za as IJ}from"./index-fww37qs9.js";import"./index-6pbm9cq6.js";import{$c as z,_c as E}from"./index-w36xamck.js";class N extends Error{errors;className;constructor(H,q){let U=q?`Validation failed for ${q}`:"Validation failed";super(`${U}: ${H.length} error(s)`);this.name="BakerValidationError",this.errors=H,this.className=q}}class w extends Error{constructor(H){super(H);this.name="SealError"}}import{err as a,isErr as e}from"@zipbul/result";function S(H){return H.replace(/[^a-zA-Z0-9_]/g,(q)=>`$${q.charCodeAt(0)}$`)}function qq(H){return"__bk$f_"+S(H)}function Hq(H,q){let U=q.find((Q)=>Q.deserializeOnly&&Q.name);if(U)return U.name;let X=q.find((Q)=>!Q.deserializeOnly&&!Q.serializeOnly&&Q.name);if(X)return X.name;return H}function x(H){return H.find((U)=>!U.serializeOnly)?.groups}function y(H,q,U,X,Q){let Z=U?.stopAtFirstError??!1,$=!Z,Y=U?.exposeDefaultValues??!1,J=[],W=[],M=[],B=`'use strict';
3
- `;if(B+=`var __bk$out = new _Cls();
4
- `,$)B+=`var __bk$errors = [];
5
- `;if($)B+=`if (input == null || typeof input !== 'object' || Array.isArray(input)) return _err([{path:'',code:'invalidInput'}]);
6
- `;else B+=`if (input == null || typeof input !== 'object' || Array.isArray(input)) return _err([{path:'',code:'invalidInput'}]);
7
- `;if(X){W.push(new WeakSet);let F=W.length-1;B+=`if (_refs[${F}].has(input)) return _err([{path:'',code:'circular'}]);
8
- `,B+=`_refs[${F}].add(input);
9
- `}if(Object.values(q).some((F)=>{let L=x(F.expose);if(L&&L.length>0)return!0;if(F.validation.some((T)=>T.groups&&T.groups.length>0))return!0;return!1}))B+=`var __bk$groups = _opts && _opts.groups;
10
- `,B+=`var __bk$groupsSet = __bk$groups ? new Set(__bk$groups) : null;
11
- `;for(let[F,L]of Object.entries(q)){let T=Jq(F,L,{stopAtFirstError:Z,collectErrors:$,exposeDefaultValues:Y,isAsync:Q,regexes:J,refs:W,execs:M,options:U});B+=T}if($)B+=`if (__bk$errors.length) return _err(__bk$errors);
12
- `;B+=`return __bk$out;
13
- `,B+=`//# sourceURL=baker://${H.name}/deserialize
14
- `;let j=Function("_Cls","_re","_refs","_execs","_err","_isErr",`return ${Q?"async function":"function"}(input, _opts) { `+B+" }")(H,J,W,M,a,e);if(U?.debug)j.__bakerSource=B;return j}function Jq(H,q,U){let{collectErrors:X,exposeDefaultValues:Q}=U;if(q.exclude){if(!q.exclude.serializeOnly)return""}if(q.expose.length>0&&q.expose.every((T)=>T.serializeOnly))return"";let Z=qq(H),$=Hq(H,q.expose),Y=x(q.expose),J=Yq(H,U),W="",M=null;if(q.flags.validateIf)M=U.refs.length,U.refs.push(q.flags.validateIf);let B;if(Q&&!q.flags.isOptional)B=`var ${Z} = (${JSON.stringify($)} in input) ? input[${JSON.stringify($)}] : __bk$out[${JSON.stringify(H)}];
15
- `;else B=`var ${Z} = input[${JSON.stringify($)}];
16
- `;let P="",_="";if(Y&&Y.length>0)P=`if (__bk$groupsSet && ${JSON.stringify(Y)}.some(function(g){return __bk$groupsSet.has(g);})) {
17
- `,_=`}
18
- `;let j=B,F=q.flags.isOptional&&!q.flags.isDefined,L=Qq(H,Z,q,U,J);if(q.flags.isDefined)j+=`if (${Z} === undefined) ${J.fail("isDefined")};
19
- `,j+=L;else if(F)j+=`if (${Z} !== undefined && ${Z} !== null) {
20
- `,j+=L,j+=`}
21
- `;else if(X&&Q)j+=L;else j+=L;if(M!==null)W+=P+`if (_refs[${M}](input)) {
22
- `+j+`}
23
- `+_;else W+=P+j+_;return W}function Qq(H,q,U,X,Q){let{collectErrors:Z,execs:$}=X,Y="",J=U.transform.filter((W)=>!W.options?.serializeOnly);if(J.length>0)for(let W of J){let M=X.refs.length;X.refs.push(W.fn);let B=X.isAsync&&W.fn.constructor?.name==="AsyncFunction",P=`_refs[${M}]({value:${q},key:${JSON.stringify(H)},obj:input,type:'deserialize'})`;Y+=`${q} = ${B?"await ":""}${P};
24
- `}if(U.flags.validateNested&&U.type?.fn)return Y+=Xq(H,q,U,X,Q),Y;if(U.validation.length===0)return Y+=`__bk$out[${JSON.stringify(H)}] = ${q};
25
- `,Y;return Y+=Uq(H,q,U.validation,Z,Q,X),Y}function n(H,q,U,X){let Q="";if(typeof H.message==="string")Q+=`,message:${JSON.stringify(H.message)}`;else if(typeof H.message==="function"){let Z=X.refs.length;X.refs.push(H.message),Q+=`,message:_refs[${Z}]({property:${JSON.stringify(q)},value:${U},constraints:[]})`}if(H.context!==void 0){let Z=X.refs.length;X.refs.push(H.context),Q+=`,context:_refs[${Z}]`}return Q}function V(H,q,U,X,Q){let Z=n(X,q,U,Q);if(!Z)return H;return{...H,fail($){if(H.collectErrors)return`__bk$errors.push({path:${JSON.stringify(q)},code:${JSON.stringify($)}${Z}})`;else return`return _err([{path:${JSON.stringify(q)},code:${JSON.stringify($)}${Z}}])`}}}function A(H,q){if(!H.groups||H.groups.length===0)return q;return`if (!__bk$groupsSet || ${JSON.stringify(H.groups)}.some(function(g){return __bk$groupsSet.has(g);})) {
26
- ${q}
27
- }
28
- `}function Uq(H,q,U,X,Q,Z){let $=U.filter((j)=>j.each),Y=U.filter((j)=>!j.each),J="",W=Y.filter((j)=>j.rule.requiresType==="string"),M=Y.filter((j)=>j.rule.requiresType==="number"),B=Y.filter((j)=>!j.rule.requiresType),P=W.length>0,_=M.length>0;if(P||_){let j=P?"string":"number",F=P?W:M,L=j==="string"?"isString":"isNumber",T=B.findIndex((R)=>R.rule.ruleName===L),O=T>=0?B[T]:void 0,k=O?B.filter((R,I)=>I!==T):B,G,D;if(O){if(j==="string")G=`typeof ${q} !== 'string'`;else G=`typeof ${q} !== 'number'`;D=O.rule.ruleName}else G=`typeof ${q} !== '${j}'`,D=F[0].rule.ruleName;let g=O?V(Q,H,q,O,Z):Q;if(X){J+=`if (${G}) ${g.fail(D)};
29
- `,J+=`else {
30
- `;let R=`__bk$mark_${S(H)}`;if(J+=` var ${R} = __bk$errors.length;
31
- `,O&&O.rule.ruleName!=="isString"){let I=A(O,O.rule.emit(q,V(Q,H,q,O,Z)));J+=" "+I.replace(/\n/g,`
32
- `)+`
33
- `}for(let I of k){let b=A(I,I.rule.emit(q,V(Q,H,q,I,Z)));J+=" "+b.replace(/\n/g,`
34
- `)+`
35
- `}for(let I of F){let b=A(I,I.rule.emit(q,V(Q,H,q,I,Z)));J+=" "+b.replace(/\n/g,`
36
- `)+`
37
- `}J+=` if (__bk$errors.length === ${R}) __bk$out[${JSON.stringify(H)}] = ${q};
38
- `,J+=`}
39
- `}else{if(J+=`if (${G}) ${g.fail(D)};
40
- `,O&&O.rule.ruleName!=="isString")J+=A(O,O.rule.emit(q,V(Q,H,q,O,Z)))+`
41
- `;for(let R of k)J+=A(R,R.rule.emit(q,V(Q,H,q,R,Z)))+`
42
- `;for(let R of F)J+=A(R,R.rule.emit(q,V(Q,H,q,R,Z)))+`
43
- `;J+=`__bk$out[${JSON.stringify(H)}] = ${q};
44
- `}}else if(X)if(B.length===0)J+=`__bk$out[${JSON.stringify(H)}] = ${q};
45
- `;else{let j=`__bk$mark_${S(H)}`;J+=`var ${j} = __bk$errors.length;
46
- `;for(let F of B)J+=A(F,F.rule.emit(q,V(Q,H,q,F,Z)))+`
47
- `;J+=`if (__bk$errors.length === ${j}) __bk$out[${JSON.stringify(H)}] = ${q};
48
- `}else{for(let j of B)J+=A(j,j.rule.emit(q,V(Q,H,q,j,Z)))+`
49
- `;J+=`__bk$out[${JSON.stringify(H)}] = ${q};
50
- `}for(let j of $){let F=JSON.stringify(H),L=`__bk$i_${S(H)}`,T=`__bk$si_${S(H)}`,O=`__bk$sv_${S(H)}`,k=`__bk$mi_${S(H)}`,G=`__bk$mv_${S(H)}`,D=n(j,H,q,Z),g=j.groups&&j.groups.length>0?`if (!__bk$groupsSet || ${JSON.stringify(j.groups)}.some(function(g){return __bk$groupsSet.has(g);})) {
51
- `:"",R=j.groups&&j.groups.length>0?`}
52
- `:"";if(X){let b={...Q,fail:(h)=>`__bk$errors.push({path:${F}+'['+${L}+']',code:${JSON.stringify(h)}${D}})`},C={...Q,fail:(h)=>`__bk$errors.push({path:${F}+'['+${T}+']',code:${JSON.stringify(h)}${D}})`},u={...Q,fail:(h)=>`__bk$errors.push({path:${F}+'['+${k}+']',code:${JSON.stringify(h)}${D}})`};J+=g,J+=`if (Array.isArray(${q})) {
53
- `,J+=` for (var ${L}=0; ${L}<${q}.length; ${L}++) {
54
- `,J+=" "+j.rule.emit(`${q}[${L}]`,b)+`
55
- `,J+=` }
56
- `,J+=`} else if (${q} instanceof Set) {
57
- `,J+=` var ${T} = 0;
58
- `,J+=` for (var ${O} of ${q}) {
59
- `,J+=" "+j.rule.emit(O,C)+`
60
- `,J+=` ${T}++;
61
- `,J+=` }
62
- `,J+=`} else if (${q} instanceof Map) {
63
- `,J+=` var ${k} = 0;
64
- `,J+=` for (var ${G} of ${q}.values()) {
65
- `,J+=" "+j.rule.emit(G,u)+`
66
- `,J+=` ${k}++;
67
- `,J+=` }
68
- `,J+=`} else { __bk$errors.push({path:${F},code:'isArray'}); }
69
- `,J+=R}else{J+=g,J+=`if (!Array.isArray(${q}) && !(${q} instanceof Set) && !(${q} instanceof Map)) ${Q.fail("isArray")};
70
- `;let b={...Q,fail:(h)=>`return _err([{path:${F}+'['+${L}+']',code:${JSON.stringify(h)}${D}}])`};J+=`if (Array.isArray(${q})) {
71
- `,J+=` for (var ${L}=0; ${L}<${q}.length; ${L}++) {
72
- `,J+=" "+j.rule.emit(`${q}[${L}]`,b)+`
73
- `,J+=` }
74
- `,J+=`} else if (${q} instanceof Set) {
75
- `,J+=` for (var ${O} of ${q}) {
76
- `;let C={...Q,fail:(h)=>`return _err([{path:${F},code:${JSON.stringify(h)}${D}}])`};J+=" "+j.rule.emit(O,C)+`
77
- `,J+=` }
78
- `,J+=`} else if (${q} instanceof Map) {
79
- `,J+=` for (var ${G} of ${q}.values()) {
80
- `;let u={...Q,fail:(h)=>`return _err([{path:${F},code:${JSON.stringify(h)}${D}}])`};J+=" "+j.rule.emit(G,u)+`
81
- `,J+=` }
82
- `,J+=`}
83
- `,J+=R}}return J}function Xq(H,q,U,X,Q){let{collectErrors:Z,execs:$}=X;if(!U.type)return`__bk$out[${JSON.stringify(H)}] = ${q};
84
- `;let Y="",J=S(H);if(U.type.discriminator){let W=JSON.stringify(U.type.discriminator.property);Y+=`var __bk$dt_${J} = ${q} && ${q}[${W}];
85
- `,Y+=`switch (__bk$dt_${J}) {
86
- `;for(let M of U.type.discriminator.subTypes){let B=M.value[z],P=$.length;$.push(B);let _=X.isAsync?"await ":"";Y+=` case ${JSON.stringify(M.name)}:
87
- `,Y+=` var __bk$r_${J} = ${_}_execs[${P}]._deserialize(${q}, _opts);
88
- `,Y+=f(H,q,`__bk$r_${J}`,Z),Y+=` break;
89
- `}if(Y+=` default: ${Q.fail("invalidDiscriminator")};
90
- `,Y+=`}
91
- `,U.type.keepDiscriminatorProperty)Y+=`if (__bk$out[${JSON.stringify(H)}] != null) __bk$out[${JSON.stringify(H)}][${W}] = __bk$dt_${J};
92
- `}else{let W=U.type.fn()[z],M=$.length;if($.push(W),U.flags.validateNestedEach||U.validation.some((P)=>P.each)){let P=`__bk$i_${J}`,_=X.isAsync?"await ":"";if(Y+=`if (Array.isArray(${q})) {
93
- `,Y+=` var __bk$arr_${J} = [];
94
- `,Y+=` for (var ${P}=0; ${P}<${q}.length; ${P}++) {
95
- `,Y+=` var __bk$r_${J} = ${_}_execs[${M}]._deserialize(${q}[${P}], _opts);
96
- `,Y+=` if (_isErr(__bk$r_${J})) {
97
- `,Z)Y+=` var __bk$re_${J} = __bk$r_${J}.data;
98
- `,Y+=` for (var __bk$j_${J}=0; __bk$j_${J}<__bk$re_${J}.length; __bk$j_${J}++) {
99
- `,Y+=` __bk$errors.push({path:${JSON.stringify(H)}+'['+${P}+'].'+__bk$re_${J}[__bk$j_${J}].path,code:__bk$re_${J}[__bk$j_${J}].code});
100
- `,Y+=` }
101
- `;else Y+=` var __bk$re_${J} = __bk$r_${J}.data;
102
- `,Y+=` return _err([{path:${JSON.stringify(H)}+'['+${P}+'].'+__bk$re_${J}[0].path,code:__bk$re_${J}[0].code}]);
103
- `;Y+=` } else { __bk$arr_${J}.push(__bk$r_${J}); }
104
- `,Y+=` }
105
- `,Y+=` __bk$out[${JSON.stringify(H)}] = __bk$arr_${J};
106
- `,Y+=`} else { ${Q.fail("isArray")}; }
107
- `}else{let P=X.isAsync?"await ":"";Y+=`if (${q} != null && typeof ${q} === 'object') {
108
- `,Y+=` var __bk$r_${J} = ${P}_execs[${M}]._deserialize(${q}, _opts);
109
- `,Y+=f(H,q,`__bk$r_${J}`,Z),Y+=`} else { ${Q.fail("isObject")}; }
110
- `}}return Y}function f(H,q,U,X){let Q=S(H);if(X)return` if (_isErr(${U})) {
111
- var __bk$re_${Q} = ${U}.data;
112
- for (var __bk$j_${Q}=0; __bk$j_${Q}<__bk$re_${Q}.length; __bk$j_${Q}++) {
113
- __bk$errors.push({path:${JSON.stringify(H+".")}+__bk$re_${Q}[__bk$j_${Q}].path,code:__bk$re_${Q}[__bk$j_${Q}].code});
114
- }
115
- } else { __bk$out[${JSON.stringify(H)}] = ${U}; }
116
- `;else return` if (_isErr(${U})) {
117
- var __bk$re_${Q} = ${U}.data;
118
- return _err([{path:${JSON.stringify(H+".")}+__bk$re_${Q}[0].path,code:__bk$re_${Q}[0].code}]);
119
- } else { __bk$out[${JSON.stringify(H)}] = ${U}; }
120
- `}function Yq(H,q){let{collectErrors:U,regexes:X,refs:Q,execs:Z}=q;return{addRegex($){return X.push($),X.length-1},addRef($){return Q.push($),Q.length-1},addExecutor($){return Z.push($),Z.length-1},fail($){if(U)return`__bk$errors.push({path:${JSON.stringify(H)},code:${JSON.stringify($)}})`;else return`return _err([{path:${JSON.stringify(H)},code:${JSON.stringify($)}}])`},collectErrors:U}}function Zq(H,q){let U=q.find((Q)=>Q.serializeOnly&&Q.name);if(U)return U.name;let X=q.find((Q)=>!Q.deserializeOnly&&!Q.serializeOnly&&Q.name);if(X)return X.name;return H}function c(H){return H.find((U)=>!U.deserializeOnly)?.groups}function l(H,q,U,X){let Q=[],Z=[],$=`'use strict';
121
- `;if($+=`var __bk$out = {};
122
- `,Object.values(q).some((M)=>{let B=c(M.expose);return B&&B.length>0}))$+=`var __bk$groups = _opts && _opts.groups;
123
- `,$+=`var __bk$groupsSet = __bk$groups ? new Set(__bk$groups) : null;
124
- `;for(let[M,B]of Object.entries(q))$+=$q(M,B,Q,Z,X);$+=`return __bk$out;
125
- `,$+=`//# sourceURL=baker://${H.name}/serialize
126
- `;let W=Function("_refs","_execs",`return ${X?"async function":"function"}(instance, _opts) { `+$+" }")(Q,Z);if(U?.debug)W.__bakerSource=$;return W}function $q(H,q,U,X,Q){if(q.exclude){if(!q.exclude.deserializeOnly)return""}if(q.expose.length>0&&q.expose.every((P)=>P.deserializeOnly))return"";let Z=Zq(H,q.expose),$=c(q.expose),Y="",J="",W="";if($&&$.length>0)J=`if (__bk$groupsSet && ${JSON.stringify($)}.some(function(g){return __bk$groupsSet.has(g);})) {
127
- `,W=`}
128
- `;let M="",B=q.flags.isOptional;if(q.type?.fn&&!q.transform.filter((P)=>!P.options?.deserializeOnly).length){let P=q.type.fn()[z],_=X.length;X.push(P);let j=q.flags.validateNestedEach||q.validation.some((T)=>T.each),F=`__bk$out[${JSON.stringify(Z)}]`,L;if(j)if(Q)L=`${F} = await Promise.all(instance[${JSON.stringify(H)}].map(async function(__ser_item) { return await _execs[${_}]._serialize(__ser_item, _opts); }));`;else L=`${F} = instance[${JSON.stringify(H)}].map(function(__ser_item) { return _execs[${_}]._serialize(__ser_item, _opts); });`;else L=`${F} = ${Q?"await ":""}_execs[${_}]._serialize(instance[${JSON.stringify(H)}], _opts);`;if(B)M=`if (instance[${JSON.stringify(H)}] !== undefined && instance[${JSON.stringify(H)}] !== null) {
129
- ${L}
130
- } else if (instance[${JSON.stringify(H)}] === null) {
131
- ${F} = null;
132
- }
133
- `;else M=`if (instance[${JSON.stringify(H)}] != null) {
134
- ${L}
135
- } else {
136
- ${F} = instance[${JSON.stringify(H)}];
137
- }
138
- `}else{let P=Bq(H,Z,q,U,Q);if(B)M+=`if (instance[${JSON.stringify(H)}] !== undefined) {
139
- `,M+=" "+P+`
140
- `,M+=`}
141
- `;else M+=P+`
142
- `}return Y+=J+M+W,Y}function Bq(H,q,U,X,Q){let Z=`__bk$out[${JSON.stringify(q)}]`,$=U.transform.filter((Y)=>!Y.options?.deserializeOnly);if($.length>0){let Y=`instance[${JSON.stringify(H)}]`;for(let J of $){let W=X.length;X.push(J.fn);let M=`_refs[${W}]({value:${Y},key:${JSON.stringify(H)},obj:instance,type:'serialize'})`;Y=Q&&J.fn.constructor?.name==="AsyncFunction"?`(await ${M})`:M}return`${Z} = ${Y};`}return`${Z} = instance[${JSON.stringify(H)}];`}function m(H,q,U){if(U?.enableCircularCheck===!0)return!0;if(U?.enableCircularCheck===!1)return!1;let X=new Set;function Q(Z){if(X.has(Z))return!0;X.add(Z);let $=Z[E];if($)for(let Y of Object.values($)){if(Y.type?.fn){let J=Y.type.fn();if(Q(J))return!0}if(Y.type?.discriminator){for(let J of Y.type.discriminator.subTypes)if(Q(J.value))return!0}}return X.delete(Z),!1}return Q(H)}function i(H,q){let U=q?`${q}.`:"";for(let[X,Q]of Object.entries(H)){for(let Y of Q.expose)if(Y.deserializeOnly&&Y.serializeOnly)throw new w(`Invalid @Expose on field '${U}${X}': cannot have both deserializeOnly:true and serializeOnly:true on the same @Expose entry. Use separate @Expose decorators for each direction.`);let Z=Q.expose.filter((Y)=>!Y.serializeOnly),$=Q.expose.filter((Y)=>!Y.deserializeOnly);o(U+X,Z,"deserialize"),o(U+X,$,"serialize")}}function o(H,q,U){for(let X=0;X<q.length;X++)for(let Q=X+1;Q<q.length;Q++){let Z=q[X].groups??[],$=q[Q].groups??[];if(jq(Z,$)){let Y=Z.length===0?[]:Z.filter((J)=>$.includes(J));throw new w(`@Expose conflict on '${H}': 2 @Expose stacks with '${U}' direction and overlapping groups [${Y.join(", ")}]. Each direction must have at most one @Expose per group set.`)}}}function jq(H,q){if(H.length===0&&q.length===0)return!0;if(H.length===0||q.length===0)return!1;return H.some((U)=>q.includes(U))}function K(H,q,U){for(let X of Object.values(H)){if(q==="deserialize"&&X.validation.some((Z)=>Z.rule.isAsync))return!0;if((q==="deserialize"?X.transform.filter((Z)=>!Z.options?.serializeOnly):X.transform.filter((Z)=>!Z.options?.deserializeOnly)).some((Z)=>Z.fn.constructor?.name==="AsyncFunction"))return!0;if(X.type?.fn){let Z=X.type.fn(),$=U??new Set;if(!$.has(Z)){$.add(Z);let Y=p(Z);if(K(Y,q,$))return!0}}if(X.type?.discriminator)for(let Z of X.type.discriminator.subTypes){let $=U??new Set;if(!$.has(Z.value)){$.add(Z.value);let Y=p(Z.value);if(K(Y,q,$))return!0}}}return!1}var d=!1;function Mq(H){if(d)throw new w("already sealed: seal() must be called exactly once");for(let q of s)v(q,H);d=!0}function v(H,q){if(Object.prototype.hasOwnProperty.call(H,z))return;let U={_deserialize:()=>{throw Error("seal in progress")},_serialize:()=>{throw Error("seal in progress")},_isAsync:!1,_isSerializeAsync:!1};H[z]=U;let X=p(H),Q=["__proto__","constructor","prototype"];for(let B of Object.keys(X))if(Q.includes(B))throw new w(`${H.name}: field name '${B}' is not allowed (reserved property name)`);for(let[B,P]of Object.entries(X))if(P.type&&!P.flags.validateNested&&P.transform.filter((_)=>!_.options?.serializeOnly).length===0)console.warn(`[baker] ${H.name}.${B}: @Type without @ValidateNested \u2014 nested DTO will not be validated during deserialization. Add @ValidateNested() to enable recursive validation.`);i(X,H.name);let Z=m(H,X,q);for(let B of Object.values(X)){if(B.type?.fn){let P=B.type.fn();v(P,q)}if(B.type?.discriminator)for(let P of B.type.discriminator.subTypes)v(P.value,q)}let $=K(X,"deserialize"),Y=K(X,"serialize"),J=y(H,X,q,Z,$),W=l(H,X,q,Y),M={_deserialize:J,_serialize:W,_isAsync:$,_isSerializeAsync:Y};if(q?.debug)M._source={deserialize:J.__bakerSource??"",serialize:W.__bakerSource??""};Object.assign(U,M)}function p(H){let q=[],U=H;while(U&&U!==Object){if(Object.hasOwn(U,E))q.push(U);let Q=Object.getPrototypeOf(U);U=Q===U?null:Q}let X=Object.create(null);for(let Q of q){let Z=Q[E];for(let[$,Y]of Object.entries(Z))if(!X[$])X[$]={validation:[...Y.validation],transform:[...Y.transform],expose:[...Y.expose],exclude:Y.exclude,type:Y.type,flags:{...Y.flags}};else{let J=X[$],W=Y;for(let P of W.validation)if(!J.validation.some((_)=>_.rule===P.rule))J.validation.push(P);if(J.transform.length===0&&W.transform.length>0)J.transform=[...W.transform];if(J.expose.length===0&&W.expose.length>0)J.expose=[...W.expose];if(J.exclude===null&&W.exclude!==null)J.exclude=W.exclude;if(J.type===null&&W.type!==null)J.type=W.type;let M=J.flags,B=W.flags;if(B.isOptional!==void 0&&M.isOptional===void 0)M.isOptional=B.isOptional;if(B.isDefined!==void 0&&M.isDefined===void 0)M.isDefined=B.isDefined;if(B.validateIf!==void 0&&M.validateIf===void 0)M.validateIf=B.validateIf;if(B.validateNested!==void 0&&M.validateNested===void 0)M.validateNested=B.validateNested;if(B.validateNestedEach!==void 0&&M.validateNestedEach===void 0)M.validateNestedEach=B.validateNestedEach}}return X}import{isErr as Pq}from"@zipbul/result";async function Wq(H,q,U){let X=H[z];if(!X)throw new w(`not sealed: ${H.name}. Call seal() before deserialize()`);let Q=await X._deserialize(q,U);if(Pq(Q))throw new N(Q.data,H.name);return Q}async function Fq(H,q){let U=H.constructor,X=U[z];if(!X)throw new w(`not sealed: ${U.name}. Call seal() before serialize()`);return await X._serialize(H,q)}function Lq(H){let{name:q,validate:U}=H,X=U.constructor.name==="AsyncFunction",Q=function(Z){return U(Z)};return Q.emit=function(Z,$){let Y=$.addRef(U);if(X)return`if(!(await _refs[${Y}](${Z}))) ${$.fail(q)};`;return`if(!_refs[${Y}](${Z})) ${$.fail(q)};`},Q.ruleName=q,Q.isAsync=X,Q}export{Oq as unregister,Fq as serialize,Mq as seal,Wq as deserialize,Lq as createRule,qH as ValidateNested,eq as ValidateIf,dJ as Type,iJ as Transform,w as SealError,JH as NotEquals,SH as NotContains,zH as MinLength,IH as MinDate,LH as Min,DH as MaxLength,wH as MaxDate,OH as Max,VH as Matches,hH as Length,pH as IsVariableWidth,bH as IsUppercase,mH as IsUUID,lH as IsURL,uJ as IsTaxId,xH as IsSurrogatePair,CJ as IsStrongPassword,ZH as IsString,WJ as IsSemVer,dH as IsRgbColor,VJ as IsRFC3339,tJ as IsPostalCode,_H as IsPositive,ZJ as IsPort,KJ as IsPhoneNumber,aJ as IsPassportNumber,aq as IsOptional,nH as IsOctal,FH as IsObject,KH as IsNumberString,$H as IsNumber,YH as IsNotIn,cJ as IsNotEmptyObject,UH as IsNotEmpty,TH as IsNegative,fH as IsMultibyte,FJ as IsMongoId,sJ as IsMobilePhone,IJ as IsMimeType,AJ as IsMilitaryTime,zJ as IsMagnetURI,tH as IsMACAddress,AH as IsLowercase,kJ as IsLongitude,UJ as IsLocale,bJ as IsLatitude,QJ as IsLatLong,JJ as IsJWT,LJ as IsJSON,PH as IsInt,lJ as IsInstance,XH as IsIn,rJ as IsIdentityCard,HJ as IsISSN,qJ as IsISRC,eH as IsISO8601,NJ as IsISO4217CurrencyCode,jJ as IsISO31661Alpha3,BJ as IsISO31661Alpha2,aH as IsISIN,rH as IsISBN,oH as IsIP,hJ as IsIBAN,yH as IsHexadecimal,iH as IsHexColor,SJ as IsHash,vH as IsHalfWidth,sH as IsHSL,uH as IsFullWidth,PJ as IsFirebasePushId,YJ as IsFQDN,gJ as IsEthereumAddress,MH as IsEnum,QH as IsEmpty,cH as IsEmail,$J as IsEAN,RH as IsDivisibleBy,rq as IsDefined,CH as IsDecimal,RJ as IsDateString,jH as IsDate,XJ as IsDataURI,wJ as IsCurrency,DJ as IsCreditCard,GJ as IsByteLength,EJ as IsBtcAddress,NH as IsBooleanString,BH as IsBoolean,TJ as IsBase64,_J as IsBase58,OJ as IsBase32,MJ as IsBIC,kH as IsAscii,WH as IsArray,EH as IsAlphanumeric,gH as IsAlpha,mJ as Expose,oJ as Exclude,HH as Equals,GH as Contains,N as BakerValidationError,yJ as ArrayUnique,nJ as ArrayNotEmpty,pJ as ArrayNotContains,fJ as ArrayMinSize,xJ as ArrayMaxSize,vJ as ArrayContains};
2
+ import{$ as Sr,$a as So,A as L,Aa as Lr,B as M,Ba as Mr,C as N,Ca as Nr,D as Q,Da as Qr,E as U,Ea as Ur,F as W,Fa as Wr,G as X,Ga as Xr,H as Y,Ha as Yr,I as Z,Ia as Zr,J as _,Ja as _r,K as $,Ka as $r,L as rr,La as ro,M as or,Ma as oo,N as er,Na as eo,O as tr,Oa as to,P as pr,Pa as po,Q as sr,Qa as so,R as ar,Ra as ao,S as ir,Sa as io,T as mr,Ta as mo,U as nr,Ua as no,V as fr,Va as fo,W as cr,Wa as co,X as xr,Xa as xo,Y as lr,Ya as lo,Z as ur,Za as uo,_ as yr,_a as yo,a as h,aa as hr,ab as ho,b as O,ba as Or,bb as Oo,c as d,ca as dr,cb as Eo,d as E,da as Er,db as Jo,e as J,ea as Jr,eb as ko,f as k,fa as kr,g as z,ga as zr,h as B,ha as Br,i as P,ia as Pr,j as R,ja as Rr,k as V,ka as Vr,l as b,la as br,m as g,ma as gr,n as j,na as jr,o as A,oa as Ar,p as I,pa as Ir,q as T,qa as Tr,r as q,ra as qr,s as v,sa as vr,t as w,ta as wr,u as C,ua as Cr,v as D,va as Dr,w as F,wa as Fr,x as G,xa as Gr,y as H,ya as Hr,z as K,za as Kr}from"./index-jzjz61tg.js";import"./index-txxjqhgc.js";export{x as unregister,m as toJsonSchema,a as serialize,e as seal,p as deserialize,f as createRule,E as ValidateNested,d as ValidateIf,So as Type,yo as Transform,S as SealError,ho as Schema,z as NotEquals,W as NotContains,b as Nested,M as MinLength,K as MinDate,C as Min,N as MaxLength,L as MaxDate,D as Max,X as Matches,Q as Length,ar as IsVariableWidth,Z as IsUppercase,lr as IsUUID,xr as IsURL,po as IsTaxId,mr as IsSurrogatePair,to as IsStrongPassword,g as IsString,vr as IsSemVer,Sr as IsRgbColor,Xr as IsRFC3339,Eo as IsPostalCode,F as IsPositive,gr as IsPort,eo as IsPhoneNumber,ko as IsPassportNumber,O as IsOptional,fr as IsOctal,w as IsObject,er as IsNumberString,j as IsNumber,J as IsNullable,V as IsNotIn,co as IsNotEmptyObject,P as IsNotEmpty,G as IsNegative,ir as IsMultibyte,wr as IsMongoId,Oo as IsMobilePhone,Kr as IsMimeType,Yr as IsMilitaryTime,Mr as IsMagnetURI,Or as IsMACAddress,Y as IsLowercase,_r as IsLongitude,Rr as IsLocale,Zr as IsLatitude,Pr as IsLatLong,Br as IsJWT,Cr as IsJSON,q as IsInt,xo as IsInstance,R as IsIn,Jo as IsIdentityCard,zr as IsISSN,kr as IsISRC,Jr as IsISO8601,oo as IsISO4217CurrencyCode,Ir as IsISO31661Alpha3,Ar as IsISO31661Alpha2,Er as IsISIN,dr as IsISBN,ur as IsIP,Qr as IsIBAN,nr as IsHexadecimal,yr as IsHexColor,Wr as IsHash,sr as IsHalfWidth,hr as IsHSL,pr as IsFullWidth,qr as IsFirebasePushId,br as IsFQDN,$r as IsEthereumAddress,T as IsEnum,B as IsEmpty,cr as IsEmail,jr as IsEAN,H as IsDivisibleBy,h as IsDefined,tr as IsDecimal,Hr as IsDateString,I as IsDate,Vr as IsDataURI,Lr as IsCurrency,Nr as IsCreditCard,Ur as IsByteLength,ro as IsBtcAddress,or as IsBooleanString,A as IsBoolean,Gr as IsBase64,Fr as IsBase58,Dr as IsBase32,Tr as IsBIC,_ as IsAscii,v as IsArray,rr as IsAlphanumeric,$ as IsAlpha,lo as Expose,uo as Exclude,k as Equals,U as Contains,y as BakerValidationError,no as ArrayUnique,fo as ArrayNotEmpty,ao as ArrayNotContains,io as ArrayMinSize,mo as ArrayMaxSize,so as ArrayContains};
143
3
 
144
- //# debugId=226AE7F0D7A8B9A564756E2164756E21
4
+ //# debugId=31FD76A57C77B63964756E2164756E21
145
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1,18 +1,9 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/errors.ts", "../src/seal/deserialize-builder.ts", "../src/seal/serialize-builder.ts", "../src/seal/circular-analyzer.ts", "../src/seal/expose-validator.ts", "../src/seal/seal.ts", "../src/functions/deserialize.ts", "../src/functions/serialize.ts", "../src/create-rule.ts"],
3
+ "sources": [],
4
4
  "sourcesContent": [
5
- "// ─────────────────────────────────────────────────────────────────────────────\n// BakerError — 개별 필드 에러 (§12.2)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * 개별 필드 에러 — 최소 계약(minimum contract).\n *\n * 예약 에러 코드:\n * - 'invalidInput': input이 null, 비객체, 배열일 때 (path='')\n * - 'isObject': 중첩 @Type 필드의 값이 객체가 아닐 때\n * - 'isArray': 배열 중첩 (each:true) 필드의 값이 배열이 아닐 때\n * - 'invalidDiscriminator': discriminator 값이 subTypes에 없을 때\n *\n * 향후 확장 필드(message, expected, actual 등)는 반드시 Optional로 추가.\n */\nexport interface BakerError {\n readonly path: string;\n readonly code: string;\n /** 사용자 정의 에러 메시지 — 데코레이터 message 옵션이 설정된 경우에만 포함 */\n readonly message?: string;\n /** 사용자 정의 컨텍스트 — 데코레이터 context 옵션이 설정된 경우에만 포함 */\n readonly context?: unknown;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// BakerValidationError — Public API throw 에러 (§12.2)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * deserialize() 검증 실패 시 throw되는 에러.\n * errors 배열에 모든 필드 에러가 담겨 있다.\n */\nexport class BakerValidationError extends Error {\n readonly errors: BakerError[];\n /** 검증 대상 DTO 클래스명 (DX-2) */\n readonly className?: string;\n\n constructor(errors: BakerError[], className?: string) {\n const prefix = className ? `Validation failed for ${className}` : 'Validation failed';\n super(`${prefix}: ${errors.length} error(s)`);\n this.name = 'BakerValidationError';\n this.errors = errors;\n this.className = className;\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// SealError — 봉인 관련 에러 (§12.2)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * 봉인 관련 에러:\n * - seal() 2회 이상 호출 시\n * - 미봉인 클래스에 deserialize()/serialize() 호출 시\n */\nexport class SealError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'SealError';\n }\n}\n",
6
- "import { err as _resultErr, isErr as _resultIsErr } from '@zipbul/result';\nimport { SEALED } from '../symbols';\nimport type { RawClassMeta, RawPropertyMeta, EmitContext, EmittableRule, SealedExecutors, RuleDef } from '../types';\nimport type { SealOptions, RuntimeOptions } from '../interfaces';\nimport type { BakerError } from '../errors';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers — 코드 생성 유틸\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** key를 유효한 JS 식별자 접미사로 변환 (비알파벳 문자를 charCode로 인코딩하여 충돌 방지) */\nfunction sanitizeKey(key: string): string {\n return key.replace(/[^a-zA-Z0-9_]/g, (ch) => `$${ch.charCodeAt(0)}$`);\n}\n\n/** 필드명을 안전한 JS 변수명으로 변환 (내부 변수 충돌 방지 prefix 포함) */\nfunction toVarName(key: string): string {\n return '__bk$f_' + sanitizeKey(key);\n}\n\n/** 직렬화에 사용할 추출 키 결정 (§4.3 ③) */\nfunction getDeserializeExtractKey(fieldKey: string, exposeStack: RawPropertyMeta['expose']): string {\n // deserializeOnly @Expose with name → 해당 name 사용\n const desDef = exposeStack.find(e => e.deserializeOnly && e.name);\n if (desDef) return desDef.name!;\n // 방향 미지정 @Expose with name → 양방향 사용\n const biDef = exposeStack.find(e => !e.deserializeOnly && !e.serializeOnly && e.name);\n if (biDef) return biDef.name!;\n return fieldKey;\n}\n\n/** 필드 expose groups 결정 (직렬화에 적용되는 @Expose) */\nfunction getDeserializeExposeGroups(exposeStack: RawPropertyMeta['expose']): string[] | undefined {\n const desDef = exposeStack.find(e => !e.serializeOnly);\n return desDef?.groups;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// buildDeserializeCode — new Function 기반 executor 생성 (§4.9)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function buildDeserializeCode<T>(\n Class: Function,\n merged: RawClassMeta,\n options: SealOptions | undefined,\n needsCircularCheck: boolean,\n isAsync: boolean,\n): (input: unknown, opts?: RuntimeOptions) => (T | ReturnType<typeof _resultErr<BakerError[]>>) | Promise<T | ReturnType<typeof _resultErr<BakerError[]>>> {\n const stopAtFirstError = options?.stopAtFirstError ?? false;\n const collectErrors = !stopAtFirstError;\n const exposeDefaultValues = options?.exposeDefaultValues ?? false;\n\n // 참조 배열 — new Function 클로저에 주입\n const regexes: RegExp[] = [];\n const refs: unknown[] = [];\n const execs: SealedExecutors<unknown>[] = [];\n\n // ── 코드 생성 ────────────────────────────────────────────────────────────\n\n let body = '\\'use strict\\';\\n';\n\n // 인스턴스 생성\n body += 'var __bk$out = new _Cls();\\n';\n\n // 에러 배열 (collectErrors mode)\n if (collectErrors) {\n body += 'var __bk$errors = [];\\n';\n }\n\n // preamble: input type guard (§4.9)\n if (collectErrors) {\n body += 'if (input == null || typeof input !== \\'object\\' || Array.isArray(input)) return _err([{path:\\'\\',code:\\'invalidInput\\'}]);\\n';\n } else {\n body += 'if (input == null || typeof input !== \\'object\\' || Array.isArray(input)) return _err([{path:\\'\\',code:\\'invalidInput\\'}]);\\n';\n }\n\n // WeakSet guard (순환 참조)\n if (needsCircularCheck) {\n refs.push(new WeakSet());\n const wsIdx = refs.length - 1;\n body += `if (_refs[${wsIdx}].has(input)) return _err([{path:'',code:'circular'}]);\\n`;\n body += `_refs[${wsIdx}].add(input);\\n`;\n }\n\n // groups 변수 — expose groups 또는 validation rule groups가 있을 때만 (§4.9, §M4)\n const hasGroupsField = Object.values(merged).some(meta => {\n const exposeGroups = getDeserializeExposeGroups(meta.expose);\n if (exposeGroups && exposeGroups.length > 0) return true;\n if (meta.validation.some(rd => rd.groups && rd.groups.length > 0)) return true;\n return false;\n });\n if (hasGroupsField) {\n body += 'var __bk$groups = _opts && _opts.groups;\\n';\n body += 'var __bk$groupsSet = __bk$groups ? new Set(__bk$groups) : null;\\n';\n }\n\n // ── 필드별 코드 생성 ──────────────────────────────────────────────────────\n\n for (const [fieldKey, meta] of Object.entries(merged)) {\n const fieldCode = generateFieldCode(fieldKey, meta, {\n stopAtFirstError,\n collectErrors,\n exposeDefaultValues,\n isAsync,\n regexes,\n refs,\n execs,\n options,\n });\n body += fieldCode;\n }\n\n // ── epilogue ──────────────────────────────────────────────────────────────\n\n if (collectErrors) {\n body += 'if (__bk$errors.length) return _err(__bk$errors);\\n';\n }\n body += 'return __bk$out;\\n';\n\n // sourceURL (§4.9)\n body += `//# sourceURL=baker://${Class.name}/deserialize\\n`;\n\n // ── new Function 실행 ─────────────────────────────────────────────────────\n\n const fnKeyword = isAsync ? 'async function' : 'function';\n const executor = new Function(\n '_Cls', '_re', '_refs', '_execs', '_err', '_isErr',\n `return ${fnKeyword}(input, _opts) { ` + body + ' }',\n )(Class, regexes, refs, execs, _resultErr, _resultIsErr) as (\n input: unknown,\n opts?: RuntimeOptions,\n ) => Promise<T | ReturnType<typeof _resultErr<BakerError[]>>>;\n\n if (options?.debug) (executor as any).__bakerSource = body;\n\n return executor;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 필드 코드 생성\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface FieldCodeContext {\n stopAtFirstError: boolean;\n collectErrors: boolean;\n exposeDefaultValues: boolean;\n isAsync: boolean;\n regexes: RegExp[];\n refs: unknown[];\n execs: SealedExecutors<unknown>[];\n options: SealOptions | undefined;\n}\n\nfunction generateFieldCode(\n fieldKey: string,\n meta: RawPropertyMeta,\n ctx: FieldCodeContext,\n): string {\n const { collectErrors, exposeDefaultValues } = ctx;\n\n // ⓪ Exclude deserializeOnly / bidirectional → skip\n if (meta.exclude) {\n if (!meta.exclude.serializeOnly) return ''; // deserializeOnly or both → skip deserialize\n }\n\n // Expose: check if this field is exposed to deserialize\n // If all @Expose entries are serializeOnly, skip field\n if (meta.expose.length > 0 && meta.expose.every(e => e.serializeOnly)) {\n return ''; // only serializeOnly exposures → not visible to deserialize\n }\n\n const varName = toVarName(fieldKey);\n const extractKey = getDeserializeExtractKey(fieldKey, meta.expose);\n const exposeGroups = getDeserializeExposeGroups(meta.expose);\n\n // EmitContext 생성\n const emitCtx = makeEmitCtx(fieldKey, ctx);\n\n let fieldCode = '';\n\n // ① @ValidateIf guard\n let validateIfIdx: number | null = null;\n if (meta.flags.validateIf) {\n validateIfIdx = ctx.refs.length;\n ctx.refs.push(meta.flags.validateIf);\n }\n\n // ③ 추출 (Extract) + exposeDefaultValues\n let extractCode: string;\n if (exposeDefaultValues && !meta.flags.isOptional) {\n // key가 input에 없으면 기본값 사용\n extractCode = `var ${varName} = (${JSON.stringify(extractKey)} in input) ? input[${JSON.stringify(extractKey)}] : __bk$out[${JSON.stringify(fieldKey)}];\\n`;\n } else {\n extractCode = `var ${varName} = input[${JSON.stringify(extractKey)}];\\n`;\n }\n\n // groups check wrap (§4.5)\n let fieldStart = '';\n let fieldEnd = '';\n if (exposeGroups && exposeGroups.length > 0) {\n const groupsArr = JSON.stringify(exposeGroups);\n fieldStart = `if (__bk$groupsSet && ${groupsArr}.some(function(g){return __bk$groupsSet.has(g);})) {\\n`;\n fieldEnd = '}\\n';\n }\n\n // inner content (extract + optional guard + validation + assign)\n let innerCode = extractCode;\n\n // ② @IsOptional guard (§4.3)\n // @IsDefined overrides @IsOptional\n const useOptionalGuard = meta.flags.isOptional && !meta.flags.isDefined;\n\n const validationCode = generateValidationCode(fieldKey, varName, meta, ctx, emitCtx);\n\n if (meta.flags.isDefined) {\n // C2: @IsDefined — undefined만 거부, null/\"\"/0 등은 후속 검증으로 통과\n innerCode += `if (${varName} === undefined) ${emitCtx.fail('isDefined')};\\n`;\n innerCode += validationCode;\n } else if (useOptionalGuard) {\n innerCode += `if (${varName} !== undefined && ${varName} !== null) {\\n`;\n innerCode += validationCode;\n innerCode += '}\\n';\n } else if (collectErrors && exposeDefaultValues) {\n // exposeDefaultValues: true without isOptional — wrap in undefined check so we don't\n // fail on keys that weren't in input (they got default values already set above)\n // Actually, exposeDefaultValues already handles this by extracting default; no wrap needed\n innerCode += validationCode;\n } else {\n innerCode += validationCode;\n }\n\n // ① @ValidateIf outer wrap\n if (validateIfIdx !== null) {\n fieldCode += fieldStart + `if (_refs[${validateIfIdx}](input)) {\\n` + innerCode + '}\\n' + fieldEnd;\n } else {\n fieldCode += fieldStart + innerCode + fieldEnd;\n }\n\n return fieldCode;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 검증 코드 생성 — 타입 가드 + transform + validate + assign\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction generateValidationCode(\n fieldKey: string,\n varName: string,\n meta: RawPropertyMeta,\n ctx: FieldCodeContext,\n emitCtx: EmitContext,\n): string {\n const { collectErrors, execs } = ctx;\n\n let code = '';\n\n // @Transform (deserialize direction) — before validation (§4.3 ⑤)\n const dsTransforms = meta.transform.filter(\n td => !td.options?.serializeOnly,\n );\n if (dsTransforms.length > 0) {\n for (const td of dsTransforms) {\n const refIdx = ctx.refs.length;\n ctx.refs.push(td.fn);\n const isAsyncTransform = ctx.isAsync && (td.fn as any).constructor?.name === 'AsyncFunction';\n const callExpr = `_refs[${refIdx}]({value:${varName},key:${JSON.stringify(fieldKey)},obj:input,type:'deserialize'})`;\n code += `${varName} = ${isAsyncTransform ? 'await ' : ''}${callExpr};\\n`;\n }\n }\n\n // @ValidateNested + @Type (§8.1)\n if (meta.flags.validateNested && meta.type?.fn) {\n code += generateNestedCode(fieldKey, varName, meta, ctx, emitCtx);\n return code;\n }\n\n // No validation rules → direct assign\n if (meta.validation.length === 0) {\n code += `__bk$out[${JSON.stringify(fieldKey)}] = ${varName};\\n`;\n return code;\n }\n\n // Build validation with type gate\n code += buildRulesCode(fieldKey, varName, meta.validation, collectErrors, emitCtx, ctx);\n\n return code;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 규칙별 추가 필드(message/context) 코드 문자열 계산 헬퍼\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** 규칙의 message/context 옵션을 generated code 내 extra 필드 문자열로 변환 */\nfunction computeRuleExtras(\n rd: RuleDef,\n fieldKey: string,\n varName: string,\n ctx: FieldCodeContext,\n): string {\n let extra = '';\n if (typeof rd.message === 'string') {\n extra += `,message:${JSON.stringify(rd.message)}`;\n } else if (typeof rd.message === 'function') {\n const msgIdx = ctx.refs.length;\n ctx.refs.push(rd.message as unknown);\n // TODO(DX-4): constraints currently always empty — populate with rule-specific constraint values when EmittableRule exposes them\n extra += `,message:_refs[${msgIdx}]({property:${JSON.stringify(fieldKey)},value:${varName},constraints:[]})`;\n }\n if (rd.context !== undefined) {\n const ctxIdx = ctx.refs.length;\n ctx.refs.push(rd.context);\n extra += `,context:_refs[${ctxIdx}]`;\n }\n return extra;\n}\n\n/** 규칙별 EmitContext 생성 (message/context 오버라이드) */\nfunction makeRuleEmitCtx(\n baseEmitCtx: EmitContext,\n fieldKey: string,\n varName: string,\n rd: RuleDef,\n ctx: FieldCodeContext,\n): EmitContext {\n const extra = computeRuleExtras(rd, fieldKey, varName, ctx);\n if (!extra) return baseEmitCtx;\n return {\n ...baseEmitCtx,\n fail(code: string): string {\n if (baseEmitCtx.collectErrors) {\n return `__bk$errors.push({path:${JSON.stringify(fieldKey)},code:${JSON.stringify(code)}${extra}})`;\n } else {\n return `return _err([{path:${JSON.stringify(fieldKey)},code:${JSON.stringify(code)}${extra}}])`;\n }\n },\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// wrapGroupsGuard — per-rule validation groups 체크 래퍼 (§M4)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * rd.groups가 설정된 경우, 런타임 __bk$groups와 교집합이 있을 때만 코드를 실행.\n * groups 없는 규칙은 항상 실행 (기존 동작 유지).\n */\nfunction wrapGroupsGuard(rd: RuleDef, code: string): string {\n if (!rd.groups || rd.groups.length === 0) return code;\n const groupsArr = JSON.stringify(rd.groups);\n return `if (!__bk$groupsSet || ${groupsArr}.some(function(g){return __bk$groupsSet.has(g);})) {\\n${code}\\n}\\n`;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// buildRulesCode — 타입 가드 + 마커 패턴 (§4.3, §4.10)\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction buildRulesCode(\n fieldKey: string,\n varName: string,\n validation: RawPropertyMeta['validation'],\n collectErrors: boolean,\n emitCtx: EmitContext,\n ctx: FieldCodeContext,\n): string {\n const each = validation.filter(rd => rd.each);\n const nonEach = validation.filter(rd => !rd.each);\n\n let code = '';\n\n // Separate by requiresType\n const stringDeps = nonEach.filter(rd => rd.rule.requiresType === 'string');\n const numberDeps = nonEach.filter(rd => rd.rule.requiresType === 'number');\n const generalRules = nonEach.filter(rd => !rd.rule.requiresType);\n\n const hasStringDeps = stringDeps.length > 0;\n const hasNumberDeps = numberDeps.length > 0;\n\n if (hasStringDeps || hasNumberDeps) {\n const gateType = hasStringDeps ? 'string' : 'number';\n const gateDeps = hasStringDeps ? stringDeps : numberDeps;\n\n // Find type asserter in generalRules\n const asserterName = gateType === 'string' ? 'isString' : 'isNumber';\n const typeAsseterIdx = generalRules.findIndex(rd => rd.rule.ruleName === asserterName);\n const typeAsseter = typeAsseterIdx >= 0 ? generalRules[typeAsseterIdx] : undefined;\n\n // Other general rules (excluding the type asserter)\n const otherGeneral = typeAsseter\n ? generalRules.filter((_, i) => i !== typeAsseterIdx)\n : generalRules;\n\n // Generate type gate condition\n let gateCondition: string;\n let gateErrorCode: string;\n\n if (typeAsseter) {\n if (gateType === 'string') {\n gateCondition = `typeof ${varName} !== 'string'`;\n } else {\n gateCondition = `typeof ${varName} !== 'number'`;\n }\n gateErrorCode = typeAsseter.rule.ruleName;\n } else {\n gateCondition = `typeof ${varName} !== '${gateType}'`;\n gateErrorCode = gateDeps[0]!.rule.ruleName;\n }\n\n // 타입 게이트 fail — typeAsseter rd가 있으면 message/context 반영\n const gateEmitCtx = typeAsseter\n ? makeRuleEmitCtx(emitCtx, fieldKey, varName, typeAsseter, ctx)\n : emitCtx;\n\n if (collectErrors) {\n code += `if (${gateCondition}) ${gateEmitCtx.fail(gateErrorCode)};\\n`;\n code += `else {\\n`;\n const markVar = `__bk$mark_${sanitizeKey(fieldKey)}`;\n code += ` var ${markVar} = __bk$errors.length;\\n`;\n // typeAsseter emit — isString은 gate에서 전체 typeof 체크 완료되므로 스킵 (PERF-1)\n // isNumber 등은 NaN/Infinity 추가 검사가 필요하므로 emit 유지\n if (typeAsseter && typeAsseter.rule.ruleName !== 'isString') {\n const taCode = wrapGroupsGuard(typeAsseter, typeAsseter.rule.emit(varName, makeRuleEmitCtx(emitCtx, fieldKey, varName, typeAsseter, ctx)));\n code += ' ' + taCode.replace(/\\n/g, '\\n ') + '\\n';\n }\n for (const rd of otherGeneral) {\n const ruleCode = wrapGroupsGuard(rd, rd.rule.emit(varName, makeRuleEmitCtx(emitCtx, fieldKey, varName, rd, ctx)));\n code += ' ' + ruleCode.replace(/\\n/g, '\\n ') + '\\n';\n }\n for (const rd of gateDeps) {\n const ruleCode = wrapGroupsGuard(rd, rd.rule.emit(varName, makeRuleEmitCtx(emitCtx, fieldKey, varName, rd, ctx)));\n code += ' ' + ruleCode.replace(/\\n/g, '\\n ') + '\\n';\n }\n code += ` if (__bk$errors.length === ${markVar}) __bk$out[${JSON.stringify(fieldKey)}] = ${varName};\\n`;\n code += `}\\n`;\n } else {\n code += `if (${gateCondition}) ${gateEmitCtx.fail(gateErrorCode)};\\n`;\n // typeAsseter emit — isString은 gate에서 전체 typeof 체크 완료되므로 스킵 (PERF-1)\n if (typeAsseter && typeAsseter.rule.ruleName !== 'isString') {\n code += wrapGroupsGuard(typeAsseter, typeAsseter.rule.emit(varName, makeRuleEmitCtx(emitCtx, fieldKey, varName, typeAsseter, ctx))) + '\\n';\n }\n for (const rd of otherGeneral) {\n code += wrapGroupsGuard(rd, rd.rule.emit(varName, makeRuleEmitCtx(emitCtx, fieldKey, varName, rd, ctx))) + '\\n';\n }\n for (const rd of gateDeps) {\n code += wrapGroupsGuard(rd, rd.rule.emit(varName, makeRuleEmitCtx(emitCtx, fieldKey, varName, rd, ctx))) + '\\n';\n }\n code += `__bk$out[${JSON.stringify(fieldKey)}] = ${varName};\\n`;\n }\n } else {\n // No type-specific rules — all general\n if (collectErrors) {\n if (generalRules.length === 0) {\n code += `__bk$out[${JSON.stringify(fieldKey)}] = ${varName};\\n`;\n } else {\n const markVar = `__bk$mark_${sanitizeKey(fieldKey)}`;\n code += `var ${markVar} = __bk$errors.length;\\n`;\n for (const rd of generalRules) {\n code += wrapGroupsGuard(rd, rd.rule.emit(varName, makeRuleEmitCtx(emitCtx, fieldKey, varName, rd, ctx))) + '\\n';\n }\n code += `if (__bk$errors.length === ${markVar}) __bk$out[${JSON.stringify(fieldKey)}] = ${varName};\\n`;\n }\n } else {\n for (const rd of generalRules) {\n code += wrapGroupsGuard(rd, rd.rule.emit(varName, makeRuleEmitCtx(emitCtx, fieldKey, varName, rd, ctx))) + '\\n';\n }\n code += `__bk$out[${JSON.stringify(fieldKey)}] = ${varName};\\n`;\n }\n }\n\n // each: true rules — Array + Set + Map 지원\n for (const rd of each) {\n const pathKey = JSON.stringify(fieldKey);\n const iVar = `__bk$i_${sanitizeKey(fieldKey)}`;\n const siVar = `__bk$si_${sanitizeKey(fieldKey)}`;\n const svVar = `__bk$sv_${sanitizeKey(fieldKey)}`;\n const miVar = `__bk$mi_${sanitizeKey(fieldKey)}`;\n const mvVar = `__bk$mv_${sanitizeKey(fieldKey)}`;\n const extra = computeRuleExtras(rd, fieldKey, varName, ctx);\n const eachGuardOpen = (rd.groups && rd.groups.length > 0)\n ? `if (!__bk$groupsSet || ${JSON.stringify(rd.groups)}.some(function(g){return __bk$groupsSet.has(g);})) {\\n`\n : '';\n const eachGuardClose = (rd.groups && rd.groups.length > 0) ? '}\\n' : '';\n\n if (collectErrors) {\n const arrFail = (c: string) => `__bk$errors.push({path:${pathKey}+'['+${iVar}+']',code:${JSON.stringify(c)}${extra}})`;\n const arrEmitCtx: EmitContext = { ...emitCtx, fail: arrFail };\n const setFail = (c: string) => `__bk$errors.push({path:${pathKey}+'['+${siVar}+']',code:${JSON.stringify(c)}${extra}})`;\n const setEmitCtx: EmitContext = { ...emitCtx, fail: setFail };\n const mapFail = (c: string) => `__bk$errors.push({path:${pathKey}+'['+${miVar}+']',code:${JSON.stringify(c)}${extra}})`;\n const mapEmitCtx: EmitContext = { ...emitCtx, fail: mapFail };\n\n code += eachGuardOpen;\n code += `if (Array.isArray(${varName})) {\\n`;\n code += ` for (var ${iVar}=0; ${iVar}<${varName}.length; ${iVar}++) {\\n`;\n code += ' ' + rd.rule.emit(`${varName}[${iVar}]`, arrEmitCtx) + '\\n';\n code += ` }\\n`;\n code += `} else if (${varName} instanceof Set) {\\n`;\n code += ` var ${siVar} = 0;\\n`;\n code += ` for (var ${svVar} of ${varName}) {\\n`;\n code += ' ' + rd.rule.emit(svVar, setEmitCtx) + '\\n';\n code += ` ${siVar}++;\\n`;\n code += ` }\\n`;\n code += `} else if (${varName} instanceof Map) {\\n`;\n code += ` var ${miVar} = 0;\\n`;\n code += ` for (var ${mvVar} of ${varName}.values()) {\\n`;\n code += ' ' + rd.rule.emit(mvVar, mapEmitCtx) + '\\n';\n code += ` ${miVar}++;\\n`;\n code += ` }\\n`;\n code += `} else { __bk$errors.push({path:${pathKey},code:'isArray'}); }\\n`;\n code += eachGuardClose;\n } else {\n code += eachGuardOpen;\n code += `if (!Array.isArray(${varName}) && !(${varName} instanceof Set) && !(${varName} instanceof Map)) ${emitCtx.fail('isArray')};\\n`;\n const arrFail2 = (c: string) => `return _err([{path:${pathKey}+'['+${iVar}+']',code:${JSON.stringify(c)}${extra}}])`;\n const arrEmitCtx2: EmitContext = { ...emitCtx, fail: arrFail2 };\n code += `if (Array.isArray(${varName})) {\\n`;\n code += ` for (var ${iVar}=0; ${iVar}<${varName}.length; ${iVar}++) {\\n`;\n code += ' ' + rd.rule.emit(`${varName}[${iVar}]`, arrEmitCtx2) + '\\n';\n code += ` }\\n`;\n code += `} else if (${varName} instanceof Set) {\\n`;\n code += ` for (var ${svVar} of ${varName}) {\\n`;\n const setFail2 = (c: string) => `return _err([{path:${pathKey},code:${JSON.stringify(c)}${extra}}])`;\n const setEmitCtx2: EmitContext = { ...emitCtx, fail: setFail2 };\n code += ' ' + rd.rule.emit(svVar, setEmitCtx2) + '\\n';\n code += ` }\\n`;\n code += `} else if (${varName} instanceof Map) {\\n`;\n code += ` for (var ${mvVar} of ${varName}.values()) {\\n`;\n const mapFail2 = (c: string) => `return _err([{path:${pathKey},code:${JSON.stringify(c)}${extra}}])`;\n const mapEmitCtx2: EmitContext = { ...emitCtx, fail: mapFail2 };\n code += ' ' + rd.rule.emit(mvVar, mapEmitCtx2) + '\\n';\n code += ` }\\n`;\n code += `}\\n`;\n code += eachGuardClose;\n }\n }\n\n return code;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// generateNestedCode — @ValidateNested + @Type (§8.1, §8.2)\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction generateNestedCode(\n fieldKey: string,\n varName: string,\n meta: RawPropertyMeta,\n ctx: FieldCodeContext,\n emitCtx: EmitContext,\n): string {\n const { collectErrors, execs } = ctx;\n\n if (!meta.type) return `__bk$out[${JSON.stringify(fieldKey)}] = ${varName};\\n`;\n\n let code = '';\n const sk = sanitizeKey(fieldKey);\n\n if (meta.type.discriminator) {\n // §8.3 discriminator\n const discProp = JSON.stringify(meta.type.discriminator.property);\n code += `var __bk$dt_${sk} = ${varName} && ${varName}[${discProp}];\\n`;\n code += `switch (__bk$dt_${sk}) {\\n`;\n for (const sub of meta.type.discriminator.subTypes) {\n const nestedSealed = (sub.value as any)[SEALED] as SealedExecutors<unknown> | undefined;\n const execIdx = execs.length;\n execs.push(nestedSealed as SealedExecutors<unknown>);\n const awaitKwD = ctx.isAsync ? 'await ' : '';\n code += ` case ${JSON.stringify(sub.name)}:\\n`;\n code += ` var __bk$r_${sk} = ${awaitKwD}_execs[${execIdx}]._deserialize(${varName}, _opts);\\n`;\n code += generateNestedResultCode(fieldKey, varName, `__bk$r_${sk}`, collectErrors);\n code += ` break;\\n`;\n }\n code += ` default: ${emitCtx.fail('invalidDiscriminator')};\\n`;\n code += `}\\n`;\n // keepDiscriminatorProperty: discriminator 프로퍼티를 결과 객체에 유지 (PB-3)\n if (meta.type.keepDiscriminatorProperty) {\n code += `if (__bk$out[${JSON.stringify(fieldKey)}] != null) __bk$out[${JSON.stringify(fieldKey)}][${discProp}] = __bk$dt_${sk};\\n`;\n }\n } else {\n // §8.1 simple nested or §8.2 each array\n const nestedSealed = (meta.type.fn() as any)[SEALED] as SealedExecutors<unknown> | undefined;\n const execIdx = execs.length;\n execs.push(nestedSealed as SealedExecutors<unknown>);\n\n // Check if validateNested each (array) — determined by flags.validateNestedEach or RuleDef.each\n const hasEach = meta.flags.validateNestedEach || meta.validation.some(rd => rd.each);\n\n if (hasEach) {\n const iVar = `__bk$i_${sk}`;\n const awaitKwE = ctx.isAsync ? 'await ' : '';\n code += `if (Array.isArray(${varName})) {\\n`;\n code += ` var __bk$arr_${sk} = [];\\n`;\n code += ` for (var ${iVar}=0; ${iVar}<${varName}.length; ${iVar}++) {\\n`;\n code += ` var __bk$r_${sk} = ${awaitKwE}_execs[${execIdx}]._deserialize(${varName}[${iVar}], _opts);\\n`;\n code += ` if (_isErr(__bk$r_${sk})) {\\n`;\n if (collectErrors) {\n code += ` var __bk$re_${sk} = __bk$r_${sk}.data;\\n`;\n code += ` for (var __bk$j_${sk}=0; __bk$j_${sk}<__bk$re_${sk}.length; __bk$j_${sk}++) {\\n`;\n code += ` __bk$errors.push({path:${JSON.stringify(fieldKey)}+'['+${iVar}+'].'+__bk$re_${sk}[__bk$j_${sk}].path,code:__bk$re_${sk}[__bk$j_${sk}].code});\\n`;\n code += ` }\\n`;\n } else {\n code += ` var __bk$re_${sk} = __bk$r_${sk}.data;\\n`;\n code += ` return _err([{path:${JSON.stringify(fieldKey)}+'['+${iVar}+'].'+__bk$re_${sk}[0].path,code:__bk$re_${sk}[0].code}]);\\n`;\n }\n code += ` } else { __bk$arr_${sk}.push(__bk$r_${sk}); }\\n`;\n code += ` }\\n`;\n code += ` __bk$out[${JSON.stringify(fieldKey)}] = __bk$arr_${sk};\\n`;\n code += `} else { ${emitCtx.fail('isArray')}; }\\n`;\n } else {\n const awaitKwS = ctx.isAsync ? 'await ' : '';\n code += `if (${varName} != null && typeof ${varName} === 'object') {\\n`;\n code += ` var __bk$r_${sk} = ${awaitKwS}_execs[${execIdx}]._deserialize(${varName}, _opts);\\n`;\n code += generateNestedResultCode(fieldKey, varName, `__bk$r_${sk}`, collectErrors);\n code += `} else { ${emitCtx.fail('isObject')}; }\\n`;\n }\n }\n\n return code;\n}\n\nfunction generateNestedResultCode(\n fieldKey: string,\n _varName: string,\n resultVar: string,\n collectErrors: boolean,\n): string {\n const sk = sanitizeKey(fieldKey);\n if (collectErrors) {\n return ` if (_isErr(${resultVar})) {\\n` +\n ` var __bk$re_${sk} = ${resultVar}.data;\\n` +\n ` for (var __bk$j_${sk}=0; __bk$j_${sk}<__bk$re_${sk}.length; __bk$j_${sk}++) {\\n` +\n ` __bk$errors.push({path:${JSON.stringify(fieldKey + '.')}+__bk$re_${sk}[__bk$j_${sk}].path,code:__bk$re_${sk}[__bk$j_${sk}].code});\\n` +\n ` }\\n` +\n ` } else { __bk$out[${JSON.stringify(fieldKey)}] = ${resultVar}; }\\n`;\n } else {\n return ` if (_isErr(${resultVar})) {\\n` +\n ` var __bk$re_${sk} = ${resultVar}.data;\\n` +\n ` return _err([{path:${JSON.stringify(fieldKey+'.')}+__bk$re_${sk}[0].path,code:__bk$re_${sk}[0].code}]);\\n` +\n ` } else { __bk$out[${JSON.stringify(fieldKey)}] = ${resultVar}; }\\n`;\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// makeEmitCtx — 필드별 EmitContext 생성\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction makeEmitCtx(fieldKey: string, ctx: FieldCodeContext): EmitContext {\n const { collectErrors, regexes, refs, execs } = ctx;\n return {\n addRegex(re: RegExp): number {\n regexes.push(re);\n return regexes.length - 1;\n },\n addRef(fn: unknown): number {\n refs.push(fn);\n return refs.length - 1;\n },\n addExecutor(executor: SealedExecutors<unknown>): number {\n execs.push(executor);\n return execs.length - 1;\n },\n fail(code: string): string {\n if (collectErrors) {\n return `__bk$errors.push({path:${JSON.stringify(fieldKey)},code:${JSON.stringify(code)}})`;\n } else {\n return `return _err([{path:${JSON.stringify(fieldKey)},code:${JSON.stringify(code)}}])`;\n }\n },\n collectErrors,\n };\n}\n",
7
- "import { SEALED } from '../symbols';\nimport type { RawClassMeta, RawPropertyMeta, SealedExecutors } from '../types';\nimport type { SealOptions, RuntimeOptions } from '../interfaces';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** serialize 방향의 출력 키 결정 */\nfunction getSerializeOutputKey(fieldKey: string, exposeStack: RawPropertyMeta['expose']): string {\n // serializeOnly @Expose with name → 해당 name 사용\n const serDef = exposeStack.find(e => e.serializeOnly && e.name);\n if (serDef) return serDef.name!;\n // 방향 미지정 @Expose with name → 양방향 사용\n const biDef = exposeStack.find(e => !e.deserializeOnly && !e.serializeOnly && e.name);\n if (biDef) return biDef.name!;\n return fieldKey;\n}\n\n/** serialize 방향의 expose groups 결정 */\nfunction getSerializeExposeGroups(exposeStack: RawPropertyMeta['expose']): string[] | undefined {\n // serializeOnly 또는 방향 미지정 @Expose\n const def = exposeStack.find(e => !e.deserializeOnly);\n return def?.groups;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// buildSerializeCode — new Function 기반 serialize executor 생성 (§4.3 serialize 파이프라인)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * serialize executor 코드 생성.\n * 무검증 전제 — 항상 Record<string, unknown> 반환 (§4.3).\n */\nexport function buildSerializeCode<T>(\n Class: Function,\n merged: RawClassMeta,\n options: SealOptions | undefined,\n isAsync: boolean,\n): (instance: T, opts?: RuntimeOptions) => Record<string, unknown> | Promise<Record<string, unknown>> {\n const refs: unknown[] = [];\n const execs: SealedExecutors<unknown>[] = [];\n\n // ── 코드 생성 ─────────────────────────────────────────────────────────────\n\n let body = '\\'use strict\\';\\n';\n body += 'var __bk$out = {};\\n';\n\n // groups 변수 — groups를 참조하는 필드가 있을 때만\n const hasGroupsField = Object.values(merged).some(meta => {\n const groups = getSerializeExposeGroups(meta.expose);\n return groups && groups.length > 0;\n });\n if (hasGroupsField) {\n body += 'var __bk$groups = _opts && _opts.groups;\\n';\n body += 'var __bk$groupsSet = __bk$groups ? new Set(__bk$groups) : null;\\n';\n }\n\n for (const [fieldKey, meta] of Object.entries(merged)) {\n body += generateSerializeFieldCode(fieldKey, meta, refs, execs, isAsync);\n }\n\n body += 'return __bk$out;\\n';\n\n // sourceURL (§4.9)\n body += `//# sourceURL=baker://${Class.name}/serialize\\n`;\n\n // ── new Function 실행 ─────────────────────────────────────────────────────\n\n const fnKeyword = isAsync ? 'async function' : 'function';\n const executor = new Function(\n '_refs', '_execs',\n `return ${fnKeyword}(instance, _opts) { ` + body + ' }',\n )(refs, execs) as (instance: T, opts?: RuntimeOptions) => Record<string, unknown> | Promise<Record<string, unknown>>;\n\n if (options?.debug) (executor as any).__bakerSource = body;\n\n return executor;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 필드별 serialize 코드 생성\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction generateSerializeFieldCode(\n fieldKey: string,\n meta: RawPropertyMeta,\n refs: unknown[],\n execs: SealedExecutors<unknown>[],\n isAsync: boolean,\n): string {\n // ⓪ Exclude serializeOnly / bidirectional → skip\n if (meta.exclude) {\n if (!meta.exclude.deserializeOnly) return ''; // serializeOnly or both → skip serialize\n }\n\n // Expose: if all @Expose entries are deserializeOnly, skip for serialize\n if (meta.expose.length > 0 && meta.expose.every(e => e.deserializeOnly)) {\n return ''; // only deserializeOnly → not visible to serialize\n }\n\n const outputKey = getSerializeOutputKey(fieldKey, meta.expose);\n const exposeGroups = getSerializeExposeGroups(meta.expose);\n\n let fieldCode = '';\n\n // groups check wrap (§4.5)\n let fieldStart = '';\n let fieldEnd = '';\n if (exposeGroups && exposeGroups.length > 0) {\n const groupsArr = JSON.stringify(exposeGroups);\n fieldStart = `if (__bk$groupsSet && ${groupsArr}.some(function(g){return __bk$groupsSet.has(g);})) {\\n`;\n fieldEnd = '}\\n';\n }\n\n let innerCode = '';\n\n // ② @IsOptional → undefined 면 출력 생략 (§4.3 serialize ②)\n const useOptionalGuard = meta.flags.isOptional;\n\n // ③ nested @Type 처리 (H4) — @Transform 없는 경우에만 (§4.3 serialize 파이프라인)\n if (meta.type?.fn && !meta.transform.filter(td => !td.options?.deserializeOnly).length) {\n const nestedSealed = (meta.type.fn() as any)[SEALED] as SealedExecutors<unknown>;\n const execIdx = execs.length;\n execs.push(nestedSealed);\n\n // 배열/each 여부 판단\n const hasEach = meta.flags.validateNestedEach || meta.validation.some(rd => rd.each);\n const outputTarget = `__bk$out[${JSON.stringify(outputKey)}]`;\n\n let nestedCode: string;\n if (hasEach) {\n if (isAsync) {\n nestedCode = `${outputTarget} = await Promise.all(instance[${JSON.stringify(fieldKey)}].map(async function(__ser_item) { return await _execs[${execIdx}]._serialize(__ser_item, _opts); }));`;\n } else {\n nestedCode = `${outputTarget} = instance[${JSON.stringify(fieldKey)}].map(function(__ser_item) { return _execs[${execIdx}]._serialize(__ser_item, _opts); });`;\n }\n } else {\n const awaitKw = isAsync ? 'await ' : '';\n nestedCode = `${outputTarget} = ${awaitKw}_execs[${execIdx}]._serialize(instance[${JSON.stringify(fieldKey)}], _opts);`;\n }\n\n if (useOptionalGuard) {\n innerCode = `if (instance[${JSON.stringify(fieldKey)}] !== undefined && instance[${JSON.stringify(fieldKey)}] !== null) {\\n ${nestedCode}\\n} else if (instance[${JSON.stringify(fieldKey)}] === null) {\\n ${outputTarget} = null;\\n}\\n`;\n } else {\n innerCode = `if (instance[${JSON.stringify(fieldKey)}] != null) {\\n ${nestedCode}\\n} else {\\n ${outputTarget} = instance[${JSON.stringify(fieldKey)}];\\n}\\n`;\n }\n } else {\n // 기존 @Transform or direct assign 처리\n const outputExpr = buildSerializeOutputExpr(fieldKey, outputKey, meta, refs, isAsync);\n\n if (useOptionalGuard) {\n innerCode += `if (instance[${JSON.stringify(fieldKey)}] !== undefined) {\\n`;\n innerCode += ' ' + outputExpr + '\\n';\n innerCode += '}\\n';\n } else {\n innerCode += outputExpr + '\\n';\n }\n }\n\n fieldCode += fieldStart + innerCode + fieldEnd;\n return fieldCode;\n}\n\n/**\n * 필드 출력 표현식 빌드.\n * @Transform 있으면 _refs[i](params) 호출, 없으면 직접 할당.\n */\nfunction buildSerializeOutputExpr(\n fieldKey: string,\n outputKey: string,\n meta: RawPropertyMeta,\n refs: unknown[],\n isAsync: boolean,\n): string {\n const outputTarget = `__bk$out[${JSON.stringify(outputKey)}]`;\n\n const serTransforms = meta.transform.filter(\n td => !td.options?.deserializeOnly,\n );\n\n if (serTransforms.length > 0) {\n let valueExpr = `instance[${JSON.stringify(fieldKey)}]`;\n for (const td of serTransforms) {\n const refIdx = refs.length;\n refs.push(td.fn);\n const callExpr = `_refs[${refIdx}]({value:${valueExpr},key:${JSON.stringify(fieldKey)},obj:instance,type:'serialize'})`;\n const isAsyncTransform = isAsync && (td.fn as any).constructor?.name === 'AsyncFunction';\n valueExpr = isAsyncTransform ? `(await ${callExpr})` : callExpr;\n }\n return `${outputTarget} = ${valueExpr};`;\n }\n\n return `${outputTarget} = instance[${JSON.stringify(fieldKey)}];`;\n}\n",
8
- "import { RAW } from '../symbols';\nimport type { RawClassMeta } from '../types';\nimport type { SealOptions } from '../interfaces';\n\n/**\n * 순환 참조 정적 분석 (§4.6)\n *\n * - enableCircularCheck: true → 항상 true\n * - enableCircularCheck: false → 항상 false\n * - 'auto' (기본) → @Type 참조 그래프를 DFS로 탐색해 순환 감지\n *\n * 순환 없는 flat DTO → false (WeakSet 오버헤드 0)\n * 순환 있는 DTO → true (WeakSet 자동 삽입)\n */\nexport function analyzeCircular(\n Class: Function,\n _merged: RawClassMeta,\n options?: SealOptions,\n): boolean {\n if (options?.enableCircularCheck === true) return true;\n if (options?.enableCircularCheck === false) return false;\n\n // auto mode: @Type 참조 그래프 DFS — visited set으로 back-edge 감지\n const visited = new Set<Function>();\n\n function walk(cls: Function): boolean {\n if (visited.has(cls)) return true; // back-edge → 순환\n\n visited.add(cls);\n\n const raw = (cls as any)[RAW] as RawClassMeta | undefined;\n if (raw) {\n for (const meta of Object.values(raw)) {\n // 단순 @Type\n if (meta.type?.fn) {\n const nested = meta.type.fn();\n if (walk(nested)) return true;\n }\n // discriminator subTypes\n if (meta.type?.discriminator) {\n for (const sub of meta.type.discriminator.subTypes) {\n if (walk(sub.value)) return true;\n }\n }\n }\n }\n\n visited.delete(cls); // 트리 엣지 해제 — 다이아몬드 패턴 false positive 방지\n return false;\n }\n\n return walk(Class);\n}\n",
9
- "import { SealError } from '../errors';\nimport type { RawClassMeta, ExposeDef } from '../types';\n\n/**\n * @Expose 스택 정적 검증 (§4.1, §3.3)\n *\n * 검사 ①: 동일 @Expose 항목에 deserializeOnly: true + serializeOnly: true → 양쪽 방향 모두 제외\n * 검사 ②: 같은 방향에 2개 이상 @Expose가 있고 groups가 겹치면 SealError\n * - 둘 다 groups=[] (ungrouped) → 겹침\n * - 둘 다 non-empty groups이며 교집합 존재 → 겹침\n * - 하나는 ungrouped, 다른 하나는 grouped → 겹치지 않음 (다른 적용 범위)\n */\nexport function validateExposeStacks(merged: RawClassMeta, className?: string): void {\n const prefix = className ? `${className}.` : '';\n for (const [key, meta] of Object.entries(merged)) {\n // ① single-entry check: deserializeOnly + serializeOnly 동시 금지\n for (const exp of meta.expose) {\n if (exp.deserializeOnly && exp.serializeOnly) {\n throw new SealError(\n `Invalid @Expose on field '${prefix}${key}': cannot have both deserializeOnly:true and serializeOnly:true on the same @Expose entry. Use separate @Expose decorators for each direction.`,\n );\n }\n }\n\n // ② multi-entry check per direction\n // deserialize direction: !serializeOnly (includes bidirectional + deserializeOnly)\n const desEntries = meta.expose.filter(e => !e.serializeOnly);\n // serialize direction: !deserializeOnly (includes bidirectional + serializeOnly)\n const serEntries = meta.expose.filter(e => !e.deserializeOnly);\n\n _checkDirectionOverlap(prefix + key, desEntries, 'deserialize');\n _checkDirectionOverlap(prefix + key, serEntries, 'serialize');\n }\n}\n\n/**\n * 같은 방향 내 @Expose entries 쌍마다 groups 겹침 검사\n */\nfunction _checkDirectionOverlap(key: string, entries: ExposeDef[], direction: string): void {\n for (let i = 0; i < entries.length; i++) {\n for (let j = i + 1; j < entries.length; j++) {\n const aGroups = entries[i]!.groups ?? [];\n const bGroups = entries[j]!.groups ?? [];\n if (_groupsOverlap(aGroups, bGroups)) {\n const overlapping = aGroups.length === 0 ? [] : aGroups.filter(g => bGroups.includes(g));\n throw new SealError(\n `@Expose conflict on '${key}': 2 @Expose stacks with '${direction}' direction and overlapping groups [${overlapping.join(', ')}]. Each direction must have at most one @Expose per group set.`,\n );\n }\n }\n }\n}\n\n/**\n * 두 groups 배열이 겹치는지 여부 판단.\n * - 둘 다 empty → 겹침 (동일 ungrouped 범위)\n * - 둘 다 non-empty이며 교집합 존재 → 겹침\n * - 하나 empty + 하나 non-empty → 겹치지 않음 (서로 다른 필터 범위)\n */\nfunction _groupsOverlap(a: string[], b: string[]): boolean {\n if (a.length === 0 && b.length === 0) return true;\n if (a.length === 0 || b.length === 0) return false;\n return a.some(g => b.includes(g));\n}\n",
10
- "import { RAW, SEALED } from '../symbols';\nimport { globalRegistry } from '../registry';\nimport { SealError } from '../errors';\nimport { buildDeserializeCode } from './deserialize-builder';\nimport { buildSerializeCode } from './serialize-builder';\nimport { analyzeCircular } from './circular-analyzer';\nimport { validateExposeStacks } from './expose-validator';\nimport type { RawClassMeta, RawPropertyMeta, SealedExecutors } from '../types';\nimport type { SealOptions } from '../interfaces';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// analyzeAsync — sealed DTO가 async executor를 필요로 하는지 정적 분석 (C1)\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction analyzeAsync(merged: RawClassMeta, direction: 'deserialize' | 'serialize', visited?: Set<Function>): boolean {\n for (const meta of Object.values(merged)) {\n // 1. createRule async (deserialize 방향만)\n if (direction === 'deserialize' && meta.validation.some(rd => rd.rule.isAsync)) return true;\n // 2. @Transform async\n const transforms = direction === 'deserialize'\n ? meta.transform.filter(td => !td.options?.serializeOnly)\n : meta.transform.filter(td => !td.options?.deserializeOnly);\n if (transforms.some(td => (td.fn as any).constructor?.name === 'AsyncFunction')) return true;\n // 3. nested DTO async — RAW 메타데이터를 직접 재귀 분석 (SEALED placeholder 의존 제거, BUG-2 수정)\n if (meta.type?.fn) {\n const nestedClass = meta.type.fn();\n const v = visited ?? new Set<Function>();\n if (!v.has(nestedClass)) {\n v.add(nestedClass);\n const nestedMerged = mergeInheritance(nestedClass);\n if (analyzeAsync(nestedMerged, direction, v)) return true;\n }\n }\n // discriminator subTypes\n if (meta.type?.discriminator) {\n for (const sub of meta.type.discriminator.subTypes) {\n const v = visited ?? new Set<Function>();\n if (!v.has(sub.value)) {\n v.add(sub.value);\n const subMerged = mergeInheritance(sub.value);\n if (analyzeAsync(subMerged, direction, v)) return true;\n }\n }\n }\n }\n return false;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// 봉인 상태 플래그\n// ─────────────────────────────────────────────────────────────────────────────\n\nlet _sealed = false;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// seal() — 전역 레지스트리 모든 DTO 봉인 (§4.1)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * 전역 레지스트리에 등록된 **모든** DTO를 봉인한다.\n * - 2회 호출 시: SealError throw\n * - 순환 참조 DTO는 placeholder 패턴으로 안전하게 처리\n */\nexport function seal(options?: SealOptions): void {\n if (_sealed) throw new SealError('already sealed: seal() must be called exactly once');\n\n for (const Class of globalRegistry) {\n sealOne(Class, options);\n }\n\n _sealed = true;\n}\n\n/**\n * @internal 테스트 전용 — testing.ts의 unseal()에서 호출\n */\nexport function _resetForTesting(): void {\n _sealed = false;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// sealOne() — 개별 클래스 봉인 (§4.1)\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction sealOne<T>(Class: Function, options?: SealOptions): void {\n if (Object.prototype.hasOwnProperty.call(Class, SEALED)) return; // 이미 봉인됨 (순환 참조 중 재귀 방지)\n\n // 0. placeholder 등록 — 순환 참조 시 무한 재귀 방지\n const placeholder: SealedExecutors<T> = {\n _deserialize: () => { throw new Error('seal in progress'); },\n _serialize: () => { throw new Error('seal in progress'); },\n _isAsync: false,\n _isSerializeAsync: false,\n };\n (Class as any)[SEALED] = placeholder;\n\n // 1. 상속 메타데이터 병합\n const merged = mergeInheritance(Class);\n\n // 1a. 금지된 필드명 검사 — prototype pollution 방지 (C5)\n const BANNED_FIELD_NAMES = ['__proto__', 'constructor', 'prototype'];\n for (const key of Object.keys(merged)) {\n if (BANNED_FIELD_NAMES.includes(key)) {\n throw new SealError(`${Class.name}: field name '${key}' is not allowed (reserved property name)`);\n }\n }\n\n // 1b. @Type without @ValidateNested 경고 (DX-5)\n for (const [key, meta] of Object.entries(merged)) {\n if (meta.type && !meta.flags.validateNested && meta.transform.filter(td => !td.options?.serializeOnly).length === 0) {\n console.warn(`[baker] ${Class.name}.${key}: @Type without @ValidateNested — nested DTO will not be validated during deserialization. Add @ValidateNested() to enable recursive validation.`);\n }\n }\n\n // 2. @Expose 스택 정적 검증 (실패 시 SealError throw)\n validateExposeStacks(merged, Class.name);\n\n // 3. 순환 참조 정적 분석\n const needsCircularCheck = analyzeCircular(Class, merged, options);\n\n // 4. 중첩 @Type 참조 DTO 먼저 봉인 (재귀)\n for (const meta of Object.values(merged)) {\n if (meta.type?.fn) {\n const nested = meta.type.fn();\n sealOne(nested, options);\n }\n if (meta.type?.discriminator) {\n for (const sub of meta.type.discriminator.subTypes) {\n sealOne(sub.value, options);\n }\n }\n }\n\n // 5. async 분석\n const isAsync = analyzeAsync(merged, 'deserialize');\n const isSerializeAsync = analyzeAsync(merged, 'serialize');\n\n // 6. deserialize executor 코드 생성\n const deserializeExecutor = buildDeserializeCode<T>(Class, merged, options, needsCircularCheck, isAsync);\n\n // 7. serialize executor 코드 생성\n const serializeExecutor = buildSerializeCode<T>(Class, merged, options, isSerializeAsync);\n\n // 8. placeholder를 실제 executor로 in-place 교체 (Object.assign으로 참조 무결성 보장)\n const assigned: Record<string, unknown> = {\n _deserialize: deserializeExecutor,\n _serialize: serializeExecutor,\n _isAsync: isAsync,\n _isSerializeAsync: isSerializeAsync,\n };\n if (options?.debug) {\n assigned._source = {\n deserialize: (deserializeExecutor as any).__bakerSource ?? '',\n serialize: (serializeExecutor as any).__bakerSource ?? '',\n };\n }\n Object.assign(placeholder, assigned);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// mergeInheritance() — 상속 메타데이터 병합 (§4.2)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Class의 prototype chain을 따라 RAW 메타데이터를 child-first로 병합한다.\n *\n * 병합 규칙:\n * - validation: union merge (부모+자식 모두 적용, 중복 rule 제거)\n * - transform: 자식 우선, 자식에 없으면 부모 계승\n * - expose: 자식 우선, 자식에 없으면 부모 계승\n * - exclude: 자식 우선, 자식에 없으면 부모 계승\n * - type: 자식 우선, 자식에 없으면 부모 계승\n * - flags: 자식 우선, 자식에 없는 각 플래그만 부모에서 보충\n */\nexport function mergeInheritance(Class: Function): RawClassMeta {\n // prototype chain을 따라 RAW가 있는 클래스 수집 (array 순서: child first)\n const chain: Function[] = [];\n let current: Function | null = Class;\n while (current && current !== Object) {\n if (Object.hasOwn(current as object, RAW)) chain.push(current);\n const proto = Object.getPrototypeOf(current);\n current = proto === current ? null : proto;\n }\n\n // child-first merge\n const merged: RawClassMeta = Object.create(null) as RawClassMeta;\n\n for (const ctor of chain) {\n const raw = (ctor as any)[RAW] as RawClassMeta;\n for (const [key, meta] of Object.entries(raw)) {\n if (!merged[key]) {\n // 필드 최초 등장 → shallow copy\n merged[key] = {\n validation: [...meta.validation],\n transform: [...meta.transform],\n expose: [...meta.expose],\n exclude: meta.exclude,\n type: meta.type,\n flags: { ...meta.flags },\n };\n } else {\n // 이미 자식에 존재 → 카테고리별 독립 병합 (§4.2)\n const m = merged[key];\n const p = meta;\n\n // validation: union merge (중복 rule 제거)\n for (const rd of p.validation) {\n if (!m.validation.some(d => d.rule === rd.rule)) {\n m.validation.push(rd);\n }\n }\n\n // transform: 자식에 없으면 부모 계승\n if (m.transform.length === 0 && p.transform.length > 0) {\n m.transform = [...p.transform];\n }\n\n // expose: 자식에 없으면 부모 계승\n if (m.expose.length === 0 && p.expose.length > 0) {\n m.expose = [...p.expose];\n }\n\n // exclude: 자식에 없으면 부모 계승\n if (m.exclude === null && p.exclude !== null) {\n m.exclude = p.exclude;\n }\n\n // type: 자식에 없으면 부모 계승\n if (m.type === null && p.type !== null) {\n m.type = p.type;\n }\n\n // flags: 자식 우선, 자식에 없는 플래그만 부모 보충\n const mf = m.flags;\n const pf = p.flags;\n if (pf.isOptional !== undefined && mf.isOptional === undefined) mf.isOptional = pf.isOptional;\n if (pf.isDefined !== undefined && mf.isDefined === undefined) mf.isDefined = pf.isDefined;\n if (pf.validateIf !== undefined && mf.validateIf === undefined) mf.validateIf = pf.validateIf;\n if (pf.validateNested !== undefined && mf.validateNested === undefined) mf.validateNested = pf.validateNested;\n if (pf.validateNestedEach !== undefined && mf.validateNestedEach === undefined) mf.validateNestedEach = pf.validateNestedEach;\n }\n }\n }\n\n return merged;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// __testing__ — 테스트 전용 export (TST-ACCESS 준수)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const __testing__ = {\n mergeInheritance,\n};\n",
11
- "import { isErr } from '@zipbul/result';\nimport { SEALED } from '../symbols';\nimport { SealError, BakerValidationError } from '../errors';\nimport type { BakerError } from '../errors';\nimport type { RuntimeOptions } from '../interfaces';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// deserialize — Public API (throw 패턴) (§5.1)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * input → Class 인스턴스 변환 + 검증.\n * - 성공: Promise<T> 반환\n * - 검증 실패: BakerValidationError throw\n * - 미봉인: SealError throw\n */\nexport async function deserialize<T>(\n Class: new (...args: any[]) => T,\n input: unknown,\n options?: RuntimeOptions,\n): Promise<T> {\n const sealed = (Class as any)[SEALED];\n if (!sealed) {\n throw new SealError(`not sealed: ${Class.name}. Call seal() before deserialize()`);\n }\n\n const result = await sealed._deserialize(input, options);\n if (isErr(result)) {\n throw new BakerValidationError(result.data as BakerError[], Class.name);\n }\n return result as T;\n}\n",
12
- "import { SEALED } from '../symbols';\nimport { SealError } from '../errors';\nimport type { RuntimeOptions } from '../interfaces';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// serialize — Public API (§5.2)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Class 인스턴스 → plain 객체 변환.\n * - 무검증 전제 — 항상 Record<string, unknown> 반환 (또는 Promise)\n * - async @Transform 사용 시 Promise<Record<string, unknown>> 반환\n * - 미봉인: SealError throw\n */\nexport async function serialize<T>(\n instance: T,\n options?: RuntimeOptions,\n): Promise<Record<string, unknown>> {\n const Class = (instance as any).constructor as Function;\n const sealed = (Class as any)[SEALED];\n if (!sealed) {\n throw new SealError(`not sealed: ${Class.name}. Call seal() before serialize()`);\n }\n\n return await sealed._serialize(instance, options) as Record<string, unknown>;\n}\n",
13
- "import type { EmittableRule, EmitContext } from './types';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// createRule — 커스텀 검증 규칙 생성 Public API (§1.1)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface CreateRuleOptions {\n /** 규칙 이름. 에러 코드로 사용됨. */\n name: string;\n /** 검증 함수 — true: 통과, false: 실패. async 함수 허용 (Promise<boolean> 반환 시 자동으로 async 루르로 등록). */\n validate: (value: unknown) => boolean | Promise<boolean>;\n /**\n * 기본 에러 메시지.\n * @phase2 — 현재는 수집만 하고 코드 생성에서 미사용.\n */\n defaultMessage?: string;\n}\n\n/**\n * 사용자 정의 검증 규칙을 생성한다.\n *\n * 반환된 EmittableRule은:\n * - 함수로 직접 호출 가능 (validate 위임)\n * - .emit()으로 인라인 코드 생성 지원\n * - 데코레이터/헬퍼 양쪽에서 사용 가능\n *\n * @example\n * const isEven = createRule({\n * name: 'isEven',\n * validate: (v) => typeof v === 'number' && v % 2 === 0,\n * });\n *\n * class Dto {\n * @IsEven() count: number;\n * }\n */\nexport function createRule(options: CreateRuleOptions): EmittableRule {\n const { name, validate } = options;\n\n // async 함수 여부 자동 감지\n const isAsyncFn = validate.constructor.name === 'AsyncFunction';\n\n // 검증 함수 래퍼 — validate에 직접 위임\n const fn = function (value: unknown): boolean | Promise<boolean> {\n return validate(value);\n } as EmittableRule;\n\n // .emit() — refs 배열을 통한 함수 호출 코드 생성 (§4.8 Type C 방식이 아닌 refs 방식)\n // @Transform 사용자 함수와 동일하게 _refs[i] 슬롯에 등록\n fn.emit = function (varName: string, ctx: EmitContext): string {\n const i = ctx.addRef(validate);\n // async rule: await 삽입 (caller(desert-builder)는 async function 생성을 보장)\n if (isAsyncFn) {\n return `if(!(await _refs[${i}](${varName}))) ${ctx.fail(name)};`;\n }\n return `if(!_refs[${i}](${varName})) ${ctx.fail(name)};`;\n };\n\n // ruleName — 에러 코드로 사용\n (fn as any).ruleName = name;\n // isAsync 플래그 — deserialize-builder가 async function 생성 여부 판단에 사용\n (fn as any).isAsync = isAsyncFn;\n\n return fn;\n}\n"
14
5
  ],
15
- "mappings": "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",
16
- "debugId": "226AE7F0D7A8B9A564756E2164756E21",
6
+ "mappings": "",
7
+ "debugId": "31FD76A57C77B63964756E2164756E21",
17
8
  "names": []
18
9
  }
@@ -10,3 +10,5 @@ export declare function collectTransform(target: object, key: string, transformD
10
10
  export declare function collectExpose(target: object, key: string, exposeDef: ExposeDef): void;
11
11
  export declare function collectExclude(target: object, key: string, excludeDef: ExcludeDef): void;
12
12
  export declare function collectType(target: object, key: string, typeDef: TypeDef): void;
13
+ export declare function collectSchema(target: object, key: string, schemaDef: Record<string, unknown> | ((auto: Record<string, unknown>) => Record<string, unknown>)): void;
14
+ export declare function collectClassSchema(target: Function, schema: Record<string, unknown>): void;
@@ -9,6 +9,10 @@ export interface CreateRuleOptions {
9
9
  * @phase2 — 현재는 수집만 하고 코드 생성에서 미사용.
10
10
  */
11
11
  defaultMessage?: string;
12
+ /** 룰 파라미터 — toJsonSchema 매핑에 사용 */
13
+ constraints?: Record<string, unknown>;
14
+ /** 이 룰이 전제하는 타입 — 타입 게이트 최적화에 사용 */
15
+ requiresType?: 'string' | 'number' | 'boolean' | 'date';
12
16
  }
13
17
  /**
14
18
  * 사용자 정의 검증 규칙을 생성한다.
@@ -19,6 +19,12 @@ export declare function ValidateIf(condition: (obj: any) => boolean): PropertyDe
19
19
  * builder 트리거 조건: meta.type !== null && meta.flags.validateNested === true
20
20
  */
21
21
  export declare function ValidateNested(options?: ValidationOptions): PropertyDecorator;
22
+ /**
23
+ * null 허용+할당. undefined는 거부.
24
+ * @IsOptional과 조합 시: null은 할당, undefined는 skip.
25
+ * @IsDefined와 조합 시: Case 3과 동일 (추가 효과 없음).
26
+ */
27
+ export declare function IsNullable(_options?: ValidationOptions): PropertyDecorator;
22
28
  /** value === comparison (strict equality) */
23
29
  export declare function Equals(comparison: unknown, options?: ValidationOptions): PropertyDecorator;
24
30
  /** value !== comparison (strict inequality) */
@@ -1,4 +1,6 @@
1
- export { IsDefined, IsOptional, ValidateIf, ValidateNested, Equals, NotEquals, IsEmpty, IsNotEmpty, IsIn, IsNotIn, } from './common';
1
+ export { IsDefined, IsOptional, ValidateIf, ValidateNested, IsNullable, Equals, NotEquals, IsEmpty, IsNotEmpty, IsIn, IsNotIn, } from './common';
2
+ export { Nested } from './nested';
3
+ export type { NestedOptions } from './nested';
2
4
  export { IsString, IsNumber, IsBoolean, IsDate, IsEnum, IsInt, IsArray, IsObject, } from './typechecker';
3
5
  export { Min, Max, IsPositive, IsNegative, IsDivisibleBy, } from './number';
4
6
  export { MinDate, MaxDate, } from './date';
@@ -8,4 +10,5 @@ export { ArrayContains, ArrayNotContains, ArrayMinSize, ArrayMaxSize, ArrayUniqu
8
10
  export { IsNotEmptyObject, IsInstance, } from './object';
9
11
  export { Expose, Exclude, Transform, Type, } from './transform';
10
12
  export type { ExposeOptions, ExcludeOptions, TransformOptions, TypeOptions, } from './transform';
13
+ export { Schema } from './schema';
11
14
  export { IsMobilePhone, IsPostalCode, IsIdentityCard, IsPassportNumber, } from './locales';
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{$ as Z,$a as Za,A as y,Aa as ya,B as z,Ba as za,C as A,Ca as Aa,D as B,Da as Ba,E as C,Ea as Ca,F as D,Fa as Da,G as E,Ga as Ea,H as F,Ha as Fa,I as G,Ia as Ga,J as H,Ja as Ha,K as I,Ka as Ia,L as J,La as Ja,M as K,Ma as Ka,N as L,Na as La,O as M,Oa as Ma,P as N,Pa as Na,Q as O,Qa as Oa,R as P,Ra as Pa,S as Q,Sa as Qa,T as R,Ta as Ra,U as S,Ua as Sa,V as T,Va as Ta,W as U,Wa as Ua,X as V,Xa as Va,Y as W,Ya as Wa,Z as X,Za as Xa,_ as Y,_a as Ya,aa as _,ab as _a,ba as $,bb as $a,c as a,ca as aa,cb as ab,d as b,da as ba,db as bb,e as c,ea as ca,f as d,fa as da,g as e,ga as ea,h as f,ha as fa,i as g,ia as ga,j as h,ja as ha,k as i,ka as ia,l as j,la as ja,m as k,ma as ka,n as l,na as la,o as m,oa as ma,p as n,pa as na,q as o,qa as oa,r as p,ra as pa,s as q,sa as qa,t as r,ta as ra,u as s,ua as sa,v as t,va as ta,w as u,wa as ua,x as v,xa as va,y as w,ya as wa,z as x,za as xa}from"../../index-fww37qs9.js";import"../../index-6pbm9cq6.js";import"../../index-w36xamck.js";export{d as ValidateNested,c as ValidateIf,Za as Type,Ya as Transform,f as NotEquals,D as NotContains,z as MinLength,x as MinDate,s as Min,A as MaxLength,y as MaxDate,t as Max,E as Matches,B as Length,P as IsVariableWidth,G as IsUppercase,W as IsUUID,V as IsURL,Na as IsTaxId,R as IsSurrogatePair,Ma as IsStrongPassword,k as IsString,qa as IsSemVer,Z as IsRgbColor,Ea as IsRFC3339,$a as IsPostalCode,u as IsPositive,ka as IsPort,La as IsPhoneNumber,bb as IsPassportNumber,b as IsOptional,T as IsOctal,r as IsObject,L as IsNumberString,l as IsNumber,j as IsNotIn,Ua as IsNotEmptyObject,h as IsNotEmpty,v as IsNegative,Q as IsMultibyte,ra as IsMongoId,_a as IsMobilePhone,xa as IsMimeType,Fa as IsMilitaryTime,za as IsMagnetURI,$ as IsMACAddress,F as IsLowercase,Ha as IsLongitude,ha as IsLocale,Ga as IsLatitude,ga as IsLatLong,fa as IsJWT,sa as IsJSON,p as IsInt,Va as IsInstance,i as IsIn,ab as IsIdentityCard,ea as IsISSN,da as IsISRC,ca as IsISO8601,Ka as IsISO4217CurrencyCode,na as IsISO31661Alpha3,ma as IsISO31661Alpha2,ba as IsISIN,aa as IsISBN,X as IsIP,Ba as IsIBAN,S as IsHexadecimal,Y as IsHexColor,Da as IsHash,O as IsHalfWidth,_ as IsHSL,N as IsFullWidth,pa as IsFirebasePushId,ja as IsFQDN,Ia as IsEthereumAddress,o as IsEnum,g as IsEmpty,U as IsEmail,la as IsEAN,w as IsDivisibleBy,a as IsDefined,M as IsDecimal,wa as IsDateString,n as IsDate,ia as IsDataURI,ya as IsCurrency,Aa as IsCreditCard,Ca as IsByteLength,Ja as IsBtcAddress,K as IsBooleanString,m as IsBoolean,va as IsBase64,ua as IsBase58,ta as IsBase32,oa as IsBIC,H as IsAscii,q as IsArray,J as IsAlphanumeric,I as IsAlpha,Wa as Expose,Xa as Exclude,e as Equals,C as Contains,Sa as ArrayUnique,Ta as ArrayNotEmpty,Pa as ArrayNotContains,Qa as ArrayMinSize,Ra as ArrayMaxSize,Oa as ArrayContains};
2
+ import{$,$a,A,Aa,B,Ba,C,Ca,D,Da,E,Ea,F,Fa,G,Ga,H,Ha,I,Ia,J,Ja,K,Ka,L,La,M,Ma,N,Na,O,Oa,P,Pa,Q,Qa,R,Ra,S,Sa,T,Ta,U,Ua,V,Va,W,Wa,X,Xa,Y,Ya,Z,Za,_,_a,a,aa,ab,b,ba,bb,c,ca,cb,d,da,db,e,ea,eb,f,fa,g,ga,h,ha,i,ia,j,ja,k,ka,l,la,m,ma,n,na,o,oa,p,pa,q,qa,r,ra,s,sa,t,ta,u,ua,v,va,w,wa,x,xa,y,ya,z,za}from"../../index-jzjz61tg.js";import"../../index-txxjqhgc.js";export{d as ValidateNested,c as ValidateIf,$a as Type,_a as Transform,ab as Schema,g as NotEquals,F as NotContains,l as Nested,B as MinLength,z as MinDate,u as Min,C as MaxLength,A as MaxDate,v as Max,G as Matches,D as Length,R as IsVariableWidth,I as IsUppercase,Y as IsUUID,X as IsURL,Pa as IsTaxId,T as IsSurrogatePair,Oa as IsStrongPassword,m as IsString,sa as IsSemVer,$ as IsRgbColor,Ga as IsRFC3339,cb as IsPostalCode,w as IsPositive,ma as IsPort,Na as IsPhoneNumber,eb as IsPassportNumber,b as IsOptional,V as IsOctal,t as IsObject,N as IsNumberString,n as IsNumber,e as IsNullable,k as IsNotIn,Wa as IsNotEmptyObject,i as IsNotEmpty,x as IsNegative,S as IsMultibyte,ta as IsMongoId,bb as IsMobilePhone,za as IsMimeType,Ha as IsMilitaryTime,Ba as IsMagnetURI,ba as IsMACAddress,H as IsLowercase,Ja as IsLongitude,ja as IsLocale,Ia as IsLatitude,ia as IsLatLong,ha as IsJWT,ua as IsJSON,r as IsInt,Xa as IsInstance,j as IsIn,db as IsIdentityCard,ga as IsISSN,fa as IsISRC,ea as IsISO8601,Ma as IsISO4217CurrencyCode,pa as IsISO31661Alpha3,oa as IsISO31661Alpha2,da as IsISIN,ca as IsISBN,Z as IsIP,Da as IsIBAN,U as IsHexadecimal,_ as IsHexColor,Fa as IsHash,Q as IsHalfWidth,aa as IsHSL,P as IsFullWidth,ra as IsFirebasePushId,la as IsFQDN,Ka as IsEthereumAddress,q as IsEnum,h as IsEmpty,W as IsEmail,na as IsEAN,y as IsDivisibleBy,a as IsDefined,O as IsDecimal,ya as IsDateString,p as IsDate,ka as IsDataURI,Aa as IsCurrency,Ca as IsCreditCard,Ea as IsByteLength,La as IsBtcAddress,M as IsBooleanString,o as IsBoolean,xa as IsBase64,wa as IsBase58,va as IsBase32,qa as IsBIC,J as IsAscii,s as IsArray,L as IsAlphanumeric,K as IsAlpha,Ya as Expose,Za as Exclude,f as Equals,E as Contains,Ua as ArrayUnique,Va as ArrayNotEmpty,Ra as ArrayNotContains,Sa as ArrayMinSize,Ta as ArrayMaxSize,Qa as ArrayContains};
3
3
 
4
- //# debugId=991F98642146307F64756E2164756E21
4
+ //# debugId=7BE9DD90DFC747EF64756E2164756E21
5
5
  //# sourceMappingURL=index.js.map
@@ -4,6 +4,6 @@
4
4
  "sourcesContent": [
5
5
  ],
6
6
  "mappings": "",
7
- "debugId": "991F98642146307F64756E2164756E21",
7
+ "debugId": "7BE9DD90DFC747EF64756E2164756E21",
8
8
  "names": []
9
9
  }
@@ -0,0 +1,17 @@
1
+ export interface NestedOptions {
2
+ discriminator?: {
3
+ property: string;
4
+ subTypes: {
5
+ value: Function;
6
+ name: string;
7
+ }[];
8
+ };
9
+ keepDiscriminatorProperty?: boolean;
10
+ each?: boolean;
11
+ }
12
+ /**
13
+ * @Type(() => X) + @ValidateNested() 통합.
14
+ *
15
+ * discriminator + each 동시 사용 시 SealError throw.
16
+ */
17
+ export declare function Nested(typeFn: () => new (...args: any[]) => any, options?: NestedOptions): PropertyDecorator;
@@ -1,8 +1,12 @@
1
1
  import type { ValidationOptions } from '../interfaces';
2
- /** value >= n */
3
- export declare function Min(n: number, options?: ValidationOptions): PropertyDecorator;
4
- /** value <= n */
5
- export declare function Max(n: number, options?: ValidationOptions): PropertyDecorator;
2
+ /** value >= n (exclusive: true → value > n) */
3
+ export declare function Min(n: number, options?: ValidationOptions & {
4
+ exclusive?: boolean;
5
+ }): PropertyDecorator;
6
+ /** value <= n (exclusive: true → value < n) */
7
+ export declare function Max(n: number, options?: ValidationOptions & {
8
+ exclusive?: boolean;
9
+ }): PropertyDecorator;
6
10
  /** value > 0 */
7
11
  export declare function IsPositive(options?: ValidationOptions): PropertyDecorator;
8
12
  /** value < 0 */
@@ -0,0 +1,13 @@
1
+ import type { JsonSchema202012 } from '../types';
2
+ /**
3
+ * 객체 리터럴: ClassDecorator & PropertyDecorator.
4
+ * 프로퍼티 레벨에서는 자동 매핑 결과를 오버라이드/보충.
5
+ * 클래스 레벨에서는 루트 스키마에 title, description, $id 등 병합.
6
+ */
7
+ export declare function Schema(schema: JsonSchema202012): ClassDecorator & PropertyDecorator;
8
+ /**
9
+ * 함수형: PropertyDecorator 전용.
10
+ * `auto` 파라미터로 자동 매핑 결과를 받아 완전한 제어 가능.
11
+ * toJsonSchema() 호출 시점에 실행된다 (데코레이터 시점이 아님).
12
+ */
13
+ export declare function Schema(fn: (auto: JsonSchema202012) => JsonSchema202012): PropertyDecorator;
@@ -6,6 +6,8 @@
6
6
  * - 'isObject': 중첩 @Type 필드의 값이 객체가 아닐 때
7
7
  * - 'isArray': 배열 중첩 (each:true) 필드의 값이 배열이 아닐 때
8
8
  * - 'invalidDiscriminator': discriminator 값이 subTypes에 없을 때
9
+ * - 'conversionFailed': enableImplicitConversion에서 타입 변환 실패 시
10
+ * - 'whitelistViolation': whitelist: true에서 미선언 필드가 input에 존재할 때
9
11
  *
10
12
  * 향후 확장 필드(message, expected, actual 등)는 반드시 Optional로 추가.
11
13
  */
@@ -1,2 +1,4 @@
1
1
  export { deserialize } from './deserialize';
2
2
  export { serialize } from './serialize';
3
+ export { toJsonSchema } from './to-json-schema';
4
+ export type { ToJsonSchemaOptions } from './to-json-schema';