@zipbul/baker 5.1.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/dist/index.d.ts +11 -9
  3. package/dist/index.js +1 -1
  4. package/dist/src/baker.d.ts +8 -9
  5. package/dist/src/baker.js +1 -1
  6. package/dist/src/common/enums.d.ts +10 -0
  7. package/dist/src/common/enums.js +1 -0
  8. package/dist/src/common/index.d.ts +6 -0
  9. package/dist/src/common/index.js +1 -0
  10. package/dist/src/common/interfaces.d.ts +4 -0
  11. package/dist/src/common/types.d.ts +2 -0
  12. package/dist/src/config/config-normalizer.d.ts +7 -0
  13. package/dist/src/config/config-normalizer.js +1 -0
  14. package/dist/src/config/constants.d.ts +6 -0
  15. package/dist/src/config/constants.js +1 -0
  16. package/dist/src/config/index.d.ts +3 -0
  17. package/dist/src/config/index.js +1 -0
  18. package/dist/src/{configure.d.ts → config/interfaces.d.ts} +1 -8
  19. package/dist/src/config/interfaces.js +0 -0
  20. package/dist/src/decorators/constants.d.ts +2 -0
  21. package/dist/src/decorators/constants.js +1 -0
  22. package/dist/src/decorators/enums.d.ts +5 -0
  23. package/dist/src/decorators/enums.js +1 -0
  24. package/dist/src/decorators/field.d.ts +3 -54
  25. package/dist/src/decorators/field.js +1 -1
  26. package/dist/src/decorators/index.d.ts +2 -2
  27. package/dist/src/decorators/index.js +1 -1
  28. package/dist/src/decorators/interfaces.d.ts +50 -0
  29. package/dist/src/decorators/interfaces.js +0 -0
  30. package/dist/src/decorators/public.d.ts +2 -0
  31. package/dist/src/decorators/public.js +1 -0
  32. package/dist/src/decorators/types.d.ts +6 -0
  33. package/dist/src/decorators/types.js +0 -0
  34. package/dist/src/metadata/enums.d.ts +5 -0
  35. package/dist/src/metadata/enums.js +1 -0
  36. package/dist/src/metadata/index.d.ts +3 -0
  37. package/dist/src/metadata/index.js +1 -0
  38. package/dist/src/metadata/interfaces.d.ts +90 -0
  39. package/dist/src/metadata/interfaces.js +0 -0
  40. package/dist/src/metadata/meta-store.d.ts +49 -0
  41. package/dist/src/metadata/meta-store.js +1 -0
  42. package/dist/src/metadata/types.d.ts +10 -0
  43. package/dist/src/metadata/types.js +0 -0
  44. package/dist/src/rules/array.d.ts +2 -2
  45. package/dist/src/rules/array.js +1 -1
  46. package/dist/src/rules/binary.d.ts +2 -2
  47. package/dist/src/rules/binary.js +1 -1
  48. package/dist/src/rules/combinators.d.ts +1 -1
  49. package/dist/src/rules/combinators.js +1 -1
  50. package/dist/src/rules/common.d.ts +3 -3
  51. package/dist/src/rules/common.js +1 -1
  52. package/dist/src/rules/constants.d.ts +10 -0
  53. package/dist/src/rules/constants.js +1 -0
  54. package/dist/src/{create-rule.d.ts → rules/create-rule.d.ts} +1 -1
  55. package/dist/src/rules/create-rule.js +1 -0
  56. package/dist/src/rules/date.d.ts +1 -1
  57. package/dist/src/rules/date.js +1 -1
  58. package/dist/src/{enums.d.ts → rules/enums.d.ts} +0 -20
  59. package/dist/src/rules/enums.js +1 -0
  60. package/dist/src/rules/index.d.ts +5 -13
  61. package/dist/src/rules/index.js +1 -1
  62. package/dist/src/rules/interfaces.d.ts +43 -0
  63. package/dist/src/rules/interfaces.js +0 -0
  64. package/dist/src/rules/locales.d.ts +1 -1
  65. package/dist/src/rules/locales.js +1 -1
  66. package/dist/src/rules/number.d.ts +3 -3
  67. package/dist/src/rules/number.js +1 -1
  68. package/dist/src/rules/object.d.ts +1 -1
  69. package/dist/src/rules/object.js +1 -1
  70. package/dist/src/rules/public.d.ts +14 -0
  71. package/dist/src/rules/public.js +1 -0
  72. package/dist/src/{rule-metadata.d.ts → rules/rule-metadata.d.ts} +1 -1
  73. package/dist/src/{rule-metadata.js → rules/rule-metadata.js} +1 -1
  74. package/dist/src/{rule-plan.d.ts → rules/rule-plan.d.ts} +4 -7
  75. package/dist/src/rules/rule-plan.js +1 -0
  76. package/dist/src/rules/string-basic.d.ts +23 -0
  77. package/dist/src/rules/string-basic.js +1 -0
  78. package/dist/src/rules/string-crypto.d.ts +5 -0
  79. package/dist/src/rules/string-crypto.js +1 -0
  80. package/dist/src/rules/string-datetime.d.ts +3 -0
  81. package/dist/src/rules/string-datetime.js +1 -0
  82. package/dist/src/rules/string-encoding.d.ts +14 -0
  83. package/dist/src/rules/string-encoding.js +1 -0
  84. package/dist/src/rules/string-finance.d.ts +18 -0
  85. package/dist/src/rules/string-finance.js +10 -0
  86. package/dist/src/rules/string-format.d.ts +38 -0
  87. package/dist/src/rules/string-format.js +1 -0
  88. package/dist/src/rules/string-geo.d.ts +5 -0
  89. package/dist/src/rules/string-geo.js +1 -0
  90. package/dist/src/rules/string-identifier.d.ts +16 -0
  91. package/dist/src/rules/string-identifier.js +3 -0
  92. package/dist/src/rules/string-shared.d.ts +3 -0
  93. package/dist/src/rules/string-shared.js +1 -0
  94. package/dist/src/rules/string-width.d.ts +6 -0
  95. package/dist/src/rules/string-width.js +1 -0
  96. package/dist/src/rules/string.d.ts +14 -110
  97. package/dist/src/rules/string.js +1 -12
  98. package/dist/src/rules/typechecker.d.ts +10 -10
  99. package/dist/src/rules/typechecker.js +5 -5
  100. package/dist/src/rules/types.d.ts +26 -0
  101. package/dist/src/rules/types.js +0 -0
  102. package/dist/src/{functions → runtime}/check-call-options.d.ts +1 -1
  103. package/dist/src/runtime/check-call-options.js +1 -0
  104. package/dist/src/runtime/constants.d.ts +3 -0
  105. package/dist/src/runtime/constants.js +1 -0
  106. package/dist/src/{functions → runtime}/deserialize.d.ts +2 -3
  107. package/dist/src/runtime/deserialize.js +1 -0
  108. package/dist/src/runtime/index.d.ts +3 -0
  109. package/dist/src/runtime/index.js +1 -0
  110. package/dist/src/{functions → runtime}/serialize.d.ts +2 -2
  111. package/dist/src/runtime/serialize.js +1 -0
  112. package/dist/src/{functions → runtime}/validate.d.ts +2 -3
  113. package/dist/src/runtime/validate.js +1 -0
  114. package/dist/src/seal/async-analyzer.d.ts +20 -0
  115. package/dist/src/seal/async-analyzer.js +1 -0
  116. package/dist/src/seal/circular-analyzer.d.ts +9 -6
  117. package/dist/src/seal/circular-analyzer.js +1 -1
  118. package/dist/src/seal/circular-placeholder.d.ts +20 -0
  119. package/dist/src/seal/circular-placeholder.js +1 -0
  120. package/dist/src/seal/codegen-utils.d.ts +15 -0
  121. package/dist/src/seal/codegen-utils.js +1 -1
  122. package/dist/src/seal/compile-cache.d.ts +38 -0
  123. package/dist/src/seal/compile-cache.js +1 -0
  124. package/dist/src/seal/constants.d.ts +62 -0
  125. package/dist/src/seal/constants.js +1 -0
  126. package/dist/src/seal/deserialize-builder.d.ts +3 -6
  127. package/dist/src/seal/deserialize-builder.js +200 -263
  128. package/dist/src/seal/deserialize-codegen.d.ts +58 -0
  129. package/dist/src/seal/deserialize-codegen.js +64 -0
  130. package/dist/src/seal/enums.d.ts +1 -2
  131. package/dist/src/seal/enums.js +1 -1
  132. package/dist/src/seal/expose-validator.d.ts +2 -2
  133. package/dist/src/seal/expose-validator.js +1 -1
  134. package/dist/src/seal/index.d.ts +3 -0
  135. package/dist/src/seal/index.js +1 -0
  136. package/dist/src/seal/inheritance-merger.d.ts +18 -0
  137. package/dist/src/seal/inheritance-merger.js +1 -0
  138. package/dist/src/seal/interfaces.d.ts +89 -0
  139. package/dist/src/seal/interfaces.js +0 -0
  140. package/dist/src/seal/meta-validator.d.ts +16 -0
  141. package/dist/src/seal/meta-validator.js +1 -0
  142. package/dist/src/seal/seal.d.ts +4 -28
  143. package/dist/src/seal/seal.js +1 -1
  144. package/dist/src/seal/serialize-builder.d.ts +5 -3
  145. package/dist/src/seal/serialize-builder.js +64 -64
  146. package/dist/src/seal/type-normalizer.d.ts +9 -0
  147. package/dist/src/seal/type-normalizer.js +1 -0
  148. package/dist/src/seal/type-resolver.d.ts +2 -0
  149. package/dist/src/seal/type-resolver.js +1 -0
  150. package/dist/src/seal/types.d.ts +6 -0
  151. package/dist/src/seal/types.js +0 -0
  152. package/dist/src/transformers/{collection.transformer.d.ts → collection.d.ts} +1 -1
  153. package/dist/src/transformers/constants.d.ts +2 -0
  154. package/dist/src/transformers/constants.js +1 -0
  155. package/dist/src/transformers/{date.transformer.d.ts → date.d.ts} +1 -1
  156. package/dist/src/transformers/date.js +1 -0
  157. package/dist/src/transformers/index.d.ts +3 -8
  158. package/dist/src/transformers/index.js +1 -1
  159. package/dist/src/transformers/interfaces.d.ts +26 -0
  160. package/dist/src/transformers/interfaces.js +0 -0
  161. package/dist/src/transformers/luxon.d.ts +3 -0
  162. package/dist/src/transformers/luxon.js +1 -0
  163. package/dist/src/transformers/moment.d.ts +3 -0
  164. package/dist/src/transformers/moment.js +1 -0
  165. package/dist/src/transformers/{number.transformer.d.ts → number.d.ts} +1 -1
  166. package/dist/src/transformers/public.d.ts +7 -0
  167. package/dist/src/transformers/public.js +1 -0
  168. package/dist/src/transformers/{string.transformer.d.ts → string.d.ts} +1 -1
  169. package/dist/src/transformers/types.d.ts +3 -0
  170. package/dist/src/transformers/types.js +0 -0
  171. package/package.json +7 -7
  172. package/dist/src/collect.d.ts +0 -15
  173. package/dist/src/collect.js +0 -1
  174. package/dist/src/configure.js +0 -1
  175. package/dist/src/create-rule.js +0 -1
  176. package/dist/src/enums.js +0 -1
  177. package/dist/src/functions/check-call-options.js +0 -1
  178. package/dist/src/functions/deserialize.js +0 -1
  179. package/dist/src/functions/serialize.js +0 -1
  180. package/dist/src/functions/validate.js +0 -1
  181. package/dist/src/interfaces.d.ts +0 -32
  182. package/dist/src/meta-access.d.ts +0 -12
  183. package/dist/src/meta-access.js +0 -1
  184. package/dist/src/rule-plan.js +0 -1
  185. package/dist/src/seal/validate-meta.d.ts +0 -13
  186. package/dist/src/seal/validate-meta.js +0 -1
  187. package/dist/src/transformers/date.transformer.js +0 -1
  188. package/dist/src/transformers/luxon.transformer.d.ts +0 -8
  189. package/dist/src/transformers/luxon.transformer.js +0 -1
  190. package/dist/src/transformers/moment.transformer.d.ts +0 -7
  191. package/dist/src/transformers/moment.transformer.js +0 -1
  192. package/dist/src/types.d.ts +0 -177
  193. /package/dist/src/{errors.d.ts → common/errors.d.ts} +0 -0
  194. /package/dist/src/{errors.js → common/errors.js} +0 -0
  195. /package/dist/src/{interfaces.js → common/interfaces.js} +0 -0
  196. /package/dist/src/{types.js → common/types.js} +0 -0
  197. /package/dist/src/{utils.d.ts → common/utils.d.ts} +0 -0
  198. /package/dist/src/{utils.js → common/utils.js} +0 -0
  199. /package/dist/src/transformers/{collection.transformer.js → collection.js} +0 -0
  200. /package/dist/src/transformers/{number.transformer.js → number.js} +0 -0
  201. /package/dist/src/transformers/{string.transformer.js → string.js} +0 -0
@@ -0,0 +1,58 @@
1
+ import type { RawPropertyMeta, RuleDef } from '../metadata';
2
+ import type { EmitContext } from '../rules';
3
+ import type { CategorizedRules } from './interfaces';
4
+ import { GuardKey } from './enums';
5
+ /** Generate nested error push code that propagates message/context fields */
6
+ export declare function nestedErrPush(errList: string, pathExpr: string, errItemExpr: string, tmpVar: string): string;
7
+ /** Generate nested error return code that propagates message/context fields */
8
+ export declare function nestedErrReturn(pathExpr: string, errItemExpr: string, tmpVar: string, validateOnly?: boolean): string;
9
+ /** Convert field name to a safe JS variable name (includes prefix to prevent internal variable collisions) */
10
+ export declare function toVarName(key: string, prefix?: string): string;
11
+ export declare function resolveGuardKey(isNullable: boolean, useOptionalGuard: boolean): GuardKey;
12
+ export interface GuardParams {
13
+ varName: string;
14
+ emitCtx: EmitContext;
15
+ assignNull: string;
16
+ validationCode: string;
17
+ }
18
+ export declare const GUARD_STRATEGIES: Record<GuardKey, (p: GuardParams) => string>;
19
+ /**
20
+ * When rd.groups is set, only execute code if there is an intersection with runtime __bk$groups.
21
+ * Rules without groups always execute (preserves existing behavior).
22
+ */
23
+ export declare function wrapGroupsGuard(rd: RuleDef, code: string): string;
24
+ export declare function sameGroups(a?: string[], b?: string[]): boolean;
25
+ export declare function generateConversionCode(targetType: string, varName: string, fieldKey: string, skipVar: string | null, // null = stopAtFirstError
26
+ collectErrors: boolean, emitCtx: EmitContext): string;
27
+ /** Result of categorizeRules — each/nonEach split and typed dependency classification */
28
+ /** categorizeRules — separate each/nonEach rules, detect mixed gate conflicts (pure) */
29
+ export declare function categorizeRules(fieldKey: string, validation: RawPropertyMeta['validation']): CategorizedRules;
30
+ /** Config object for emitTypedRules — bundles closure-captured vars into explicit parameter */
31
+ export interface TypeGateConfig {
32
+ effectiveGateType: string;
33
+ gateCondition: string;
34
+ gateErrorCode: string;
35
+ gateEmitCtx: EmitContext;
36
+ otherGeneral: RuleDef[];
37
+ gateDeps: RuleDef[];
38
+ typeAsserter: RuleDef | undefined;
39
+ enableConversion: boolean;
40
+ }
41
+ /** Generate nested-result handling for deserialize mode (pure) */
42
+ export declare function generateNestedResultCode(fieldKey: string, resultVar: string, collectErrors: boolean, pathPrefix?: string): string;
43
+ /**
44
+ * Nested-executor result handling inside a per-element loop (Set / Map / array / discriminator-each).
45
+ * Single source for the `if (isErr(result)) { …re-path nested errors… } else { <success> }` block that
46
+ * every collection loop repeats — only the element path expression (`ppExpr`), the success statement
47
+ * (`arr.push` / `map.set` / `set.add`), and the base indent differ. The single-object case keeps using
48
+ * {@link generateNestedResultCode} (it writes straight to `out[field]`).
49
+ */
50
+ export declare function generateNestedEachResultCode(resultVar: string, ppExpr: string, sk: string, collectErrors: boolean, successStmt: string, indent: string): string;
51
+ /** Generate validate-mode nested result handling (null check instead of isErr) (pure) */
52
+ export declare function generateValidateNestedResult(fieldKey: string, resultVar: string, collectErrors: boolean, pathPrefix?: string): string;
53
+ /**
54
+ * Validate-mode counterpart of {@link generateNestedEachResultCode}: the per-element `if (result !==
55
+ * null) { …re-path the returned issue array… }` block shared by the Set / Map / array / discriminator
56
+ * validate-each loops. The element path expression and base indent are the only per-site differences.
57
+ */
58
+ export declare function generateValidateNestedEachResultCode(resultVar: string, ppExpr: string, sk: string, collectErrors: boolean, indent: string): string;
@@ -0,0 +1,64 @@
1
+ import{BakerError as M}from"../common/index.js";import{sanitizeKey as H,buildGroupsHasExpr as q}from"./codegen-utils.js";import{DES_GEN as W}from"./constants.js";import{GuardKey as Z}from"./enums.js";export function nestedErrPush(w,j,D,Q){const A=`${Q}_e`;return`var ${A}=${D};
2
+ if(${A}.message===undefined&&${A}.context===undefined){${w}.push({path:${j},code:${A}.code});}
3
+ else{var ${Q}={path:${j},code:${A}.code};
4
+ if(${A}.message!==undefined)${Q}.message=${A}.message;
5
+ if(${A}.context!==undefined)${Q}.context=${A}.context;
6
+ ${w}.push(${Q});}
7
+ `}export function nestedErrReturn(w,j,D,Q){const A=(U)=>Q?`return ${U};
8
+ `:`return err(${U});
9
+ `,J=`${D}_e`;return`var ${J}=${j};
10
+ if(${J}.message===undefined&&${J}.context===undefined)${A(`[{path:${w},code:${J}.code}]`)} var ${D}={path:${w},code:${J}.code};
11
+ if(${J}.message!==undefined)${D}.message=${J}.message;
12
+ if(${J}.context!==undefined)${D}.context=${J}.context;
13
+ ${A(`[${D}]`)}`}export function toVarName(w,j){return W.field+(j||"")+H(w)}export function resolveGuardKey(w,j){if(w&&j)return Z.NullableOptional;if(w)return Z.Nullable;if(j)return Z.Optional;return Z.Default}export const GUARD_STRATEGIES={[Z.NullableOptional]({varName:w,assignNull:j,validationCode:D}){let Q=`if (${w} === null) { ${j}}
14
+ `;Q+=`else if (${w} !== undefined) {
15
+ `;Q+=D;Q+=`}
16
+ `;return Q},[Z.Nullable]({varName:w,emitCtx:j,assignNull:D,validationCode:Q}){let A=`if (${w} === undefined) ${j.fail("isDefined")};
17
+ `;A+=`else if (${w} !== null) {
18
+ `;A+=Q;A+=`} else { ${D}}
19
+ `;return A},[Z.Optional]({varName:w,validationCode:j}){let D=`if (${w} !== undefined && ${w} !== null) {
20
+ `;D+=j;D+=`}
21
+ `;return D},[Z.Default]({varName:w,emitCtx:j,validationCode:D}){let Q=`if (${w} === undefined || ${w} === null) ${j.fail("isDefined")};
22
+ `;Q+=`else {
23
+ `;Q+=D;Q+=`}
24
+ `;return Q}};export function wrapGroupsGuard(w,j){if(!w.groups||w.groups.length===0)return j;return`if ((${W.group0} === null && !${W.groupsSet}) || ${q(W.group0,W.groupsSet,w.groups)}) {
25
+ ${j}
26
+ }
27
+ `}export function sameGroups(w,j){if(!w||w.length===0)return!j||j.length===0;if(!j||w.length!==j.length)return!1;for(let D=0;D<w.length;D++)if(w[D]!==j[D])return!1;return!0}export function generateConversionCode(w,j,D,Q,A,J){const U=A?`${J.fail("conversionFailed")}; ${Q} = true;`:J.fail("conversionFailed")+";";switch(w){case"string":return` ${j} = String(${j});
28
+ `;case"number":return` ${j} = Number(${j});
29
+ if (isNaN(${j})) { ${U} }
30
+ `;case"boolean":return` if (${j} === 'true' || ${j} === '1' || ${j} === 1) ${j} = true;
31
+ else if (${j} === 'false' || ${j} === '0' || ${j} === 0) ${j} = false;
32
+ else { ${U} }
33
+ `;case"date":return` ${j} = new Date(${j});
34
+ if (isNaN(${j}.getTime())) { ${U} }
35
+ `;default:throw new M(`Unknown implicit conversion type: "${w}" for field "${D}"`)}}export function categorizeRules(w,j){const D=[],Q=[],A={string:[],number:[],boolean:[],date:[],array:[],object:[]};for(const X of j){if(X.each){D.push(X);continue}const Y=X.rule.requiresType;if(Y!==void 0)A[Y].push(X);else Q.push(X)}let J=void 0,U=null;for(const X of["string","number","boolean","date","array","object"]){const Y=A[X];if(Y.length===0)continue;if(J){if(U===null)U=[J.type];U.push(X)}else J={type:X,deps:Y}}if(U)throw new M(`Field "${w}" has conflicting requiresType: ${U.join(", ")}`);return{each:D,generalRules:Q,typedDeps:J}}export function generateNestedResultCode(w,j,D,Q){const A=H(w),J=Q?`${Q}+${JSON.stringify(w+".")}`:JSON.stringify(w+".");if(D){const X=`${W.errors}${A}[${W.nestedIdx}${A}]`;return` if (isErr(${j})) {
36
+ var ${W.errors}${A} = ${j}.data;
37
+ var __bk$pp${A} = ${J};
38
+ for (var ${W.nestedIdx}${A}=0; ${W.nestedIdx}${A}<${W.errors}${A}.length; ${W.nestedIdx}${A}++) {
39
+ `+nestedErrPush(W.errList,`__bk$pp${A}+${X}.path`,X,`__ne${A}`)+` }
40
+ } else { ${W.out}[${JSON.stringify(w)}] = ${j}; }
41
+ `}const U=`${W.errors}${A}[0]`;return` if (isErr(${j})) {
42
+ var ${W.errors}${A} = ${j}.data;
43
+ var __bk$pp${A} = ${J};
44
+ `+nestedErrReturn(`__bk$pp${A}+${U}.path`,U,`__ne${A}`)+` } else { ${W.out}[${JSON.stringify(w)}] = ${j}; }
45
+ `}export function generateNestedEachResultCode(w,j,D,Q,A,J){const U=`${W.errors}${D}`,X=`__bk$pp${D}`,Y=`${J} var ${U} = ${w}.data;
46
+ ${J} var ${X} = ${j};
47
+ `;let $;if(Q){const _=`${W.nestedIdx}${D}`;$=`${J} for (var ${_}=0; ${_}<${U}.length; ${_}++) {
48
+ ${J} `+nestedErrPush(W.errList,`${X}+${U}[${_}].path`,`${U}[${_}]`,`__ne${D}`)+`${J} }
49
+ `}else $=`${J} `+nestedErrReturn(`${X}+${U}[0].path`,`${U}[0]`,`__ne${D}`);return`${J}if (isErr(${w})) {
50
+ ${Y}${$}${J}} else { ${A} }
51
+ `}export function generateValidateNestedResult(w,j,D,Q){const A=H(w),J=`__bk$pp${A}`,U=Q?`${Q}+${JSON.stringify(w+".")}`:JSON.stringify(w+".");if(D){const Y=`${j}[${W.nestedIdx}${A}]`;return` if (${j} !== null) {
52
+ var ${J} = ${U};
53
+ for (var ${W.nestedIdx}${A}=0; ${W.nestedIdx}${A}<${j}.length; ${W.nestedIdx}${A}++) {
54
+ `+nestedErrPush(W.errList,`${J}+${Y}.path`,Y,`__ne${A}`)+` }
55
+ }
56
+ `}const X=`${j}[0]`;return` if (${j} !== null) {
57
+ var ${J} = ${U};
58
+ `+nestedErrReturn(`${J}+${X}.path`,X,`__ne${A}`,!0)+` }
59
+ `}export function generateValidateNestedEachResultCode(w,j,D,Q,A){const J=`__bk$pp${D}`;let U=`${A}if (${w} !== null) {
60
+ ${A} var ${J} = ${j};
61
+ `;if(Q){const X=`${W.nestedIdx}${D}`;U+=`${A} for (var ${X}=0; ${X}<${w}.length; ${X}++) {
62
+ ${A} `+nestedErrPush(W.errList,`${J}+${w}[${X}].path`,`${w}[${X}]`,`__ne${D}`)+`${A} }
63
+ `}else U+=`${A} `+nestedErrReturn(`${J}+${w}[0].path`,`${w}[0]`,`__ne${D}`,!0);U+=`${A}}
64
+ `;return U}
@@ -1,8 +1,7 @@
1
- /** Null/undefined guard strategy selected per field from its optional/nullable/defined flags. */
1
+ /** Null/undefined guard strategy selected per field from its optional/nullable flags. */
2
2
  export declare enum GuardKey {
3
3
  NullableOptional = "nullable+optional",
4
4
  Nullable = "nullable",
5
- Defined = "defined",
6
5
  Optional = "optional",
7
6
  Default = "default"
8
7
  }
@@ -1 +1 @@
1
- export var GuardKey;((l)=>{l.NullableOptional="nullable+optional";l.Nullable="nullable";l.Defined="defined";l.Optional="optional";l.Default="default"})(GuardKey||={});
1
+ export var GuardKey;((l)=>{l.NullableOptional="nullable+optional";l.Nullable="nullable";l.Optional="optional";l.Default="default"})(GuardKey||={});
@@ -1,6 +1,6 @@
1
- import type { RawClassMeta } from '../types';
1
+ import type { RawClassMeta } from '../metadata';
2
2
  /**
3
- * Static validation of @Expose stacks (§4.1, §3.3)
3
+ * Static validation of @Expose stacks
4
4
  *
5
5
  * Check 1: same @Expose entry has deserializeOnly: true + serializeOnly: true → excluded from both directions
6
6
  * Check 2: if 2+ @Expose entries in the same direction have overlapping groups → BakerError
@@ -1 +1 @@
1
- import{Direction as L}from"../enums.js";import{BakerError as K}from"../errors.js";function validateExposeStacks(F,z){const C=z?`${z}.`:"";for(const[A,H]of Object.entries(F)){for(const q of H.expose){if(q.deserializeOnly&&q.serializeOnly)throw new K(`Invalid @Expose on field '${C}${A}': cannot have both deserializeOnly:true and serializeOnly:true on the same @Expose entry. Use separate @Expose decorators for each direction.`);if(q.name==="__proto__"||q.name==="constructor"||q.name==="prototype")throw new K(`Invalid @Field name on '${C}${A}': '${q.name}' is a reserved property name and cannot be used as a serialized key.`)}const I=H.expose.filter((q)=>!q.serializeOnly),J=H.expose.filter((q)=>!q.deserializeOnly);M(C+A,I,L.Deserialize);M(C+A,J,L.Serialize)}}function M(F,z,C){for(let A=0;A<z.length;A++)for(let H=A+1;H<z.length;H++){const I=z[A].groups??[],J=z[H].groups??[];if(R(I,J)){const q=new Set(J),P=I.length===0?[]:I.filter((Q)=>q.has(Q));throw new K(`@Expose conflict on '${F}': 2 @Expose stacks with '${C}' direction and overlapping groups [${P.join(", ")}]. Each direction must have at most one @Expose per group set.`)}}}function R(F,z){if(F.length===0&&z.length===0)return!0;if(F.length===0||z.length===0)return!1;return F.some((C)=>z.includes(C))}export{validateExposeStacks};
1
+ import{Direction as Q,BakerError as L}from"../common/index.js";import{RESERVED_PROPERTY_NAMES as Z}from"./constants.js";function validateExposeStacks(H,q){const F=q?`${q}.`:"";for(const[C,I]of Object.entries(H)){for(const z of I.expose){if(z.deserializeOnly&&z.serializeOnly)throw new L(`Invalid @Expose on field '${F}${C}': cannot have both deserializeOnly:true and serializeOnly:true on the same @Expose entry. Use separate @Expose decorators for each direction.`);if(z.name!==void 0&&Z.has(z.name))throw new L(`Invalid @Expose name on '${F}${C}': '${z.name}' is a reserved property name and cannot be used as a serialized key.`)}const J=I.expose.filter((z)=>!z.serializeOnly),K=I.expose.filter((z)=>!z.deserializeOnly);U(F+C,J,Q.Deserialize);U(F+C,K,Q.Serialize)}}function U(H,q,F){for(let C=0;C<q.length;C++)for(let I=C+1;I<q.length;I++){const J=q[C].groups??[],K=q[I].groups??[];if($(J,K)){const z=new Set(K),W=J.filter((X)=>z.has(X));throw new L(`@Expose conflict on '${H}': 2 @Expose stacks with '${F}' direction and overlapping groups [${W.join(", ")}]. Each direction must have at most one @Expose per group set.`)}}}function $(H,q){if(H.length===0&&q.length===0)return!0;if(H.length===0||q.length===0)return!1;return H.some((F)=>q.includes(F))}export{validateExposeStacks};
@@ -0,0 +1,3 @@
1
+ export type { SealedExecutors, SealOptions } from './interfaces';
2
+ export { sealRegistry } from './seal';
3
+ export { SEAL_OPTION_KEYS } from './constants';
@@ -0,0 +1 @@
1
+ export{sealRegistry}from"./seal.js";export{SEAL_OPTION_KEYS}from"./constants.js";
@@ -0,0 +1,18 @@
1
+ import type { RawClassMeta, MetaStore } from '../metadata';
2
+ /**
3
+ * Merges RAW metadata child-first along the prototype chain of a class. Holds the {@link MetaStore} it
4
+ * reads RAW through as an injected collaborator.
5
+ *
6
+ * Merge rules:
7
+ * - validation: union by ruleName — child wins on a same-ruleName collision; otherwise parent rules are appended
8
+ * - transform: child takes priority, inherits from parent if absent in child
9
+ * - expose: child takes priority, inherits from parent if absent in child
10
+ * - exclude: child takes priority, inherits from parent if absent in child
11
+ * - type: child takes priority, inherits from parent if absent in child
12
+ * - flags: child takes priority, only missing flags are supplemented from parent
13
+ */
14
+ export declare class InheritanceMerger {
15
+ #private;
16
+ constructor(meta: MetaStore);
17
+ merge(Class: Function): RawClassMeta;
18
+ }
@@ -0,0 +1 @@
1
+ export class InheritanceMerger{#b;constructor(D){this.#b=D}merge(D){const F=[];let z=D;while(z&&z!==Object){if(this.#b.hasOwn(z))F.push(z);const B=Object.getPrototypeOf(z);z=B===z?null:B}const A=Object.create(null);for(const B of F){const H=this.#b.get(B);for(const[E,x]of Object.entries(H))if(!A[E])A[E]={...x,validation:[...x.validation],transform:[...x.transform],expose:[...x.expose],exclude:x.exclude,type:x.type,flags:{...x.flags}};else{const b=A[E],j=x;for(const G of j.validation)if(!b.validation.some((I)=>I.rule.ruleName===G.rule.ruleName))b.validation.push(G);if(b.transform.length===0&&j.transform.length>0)b.transform=[...j.transform];if(b.expose.length===0&&j.expose.length>0)b.expose=[...j.expose];if(b.exclude===null&&j.exclude!==null)b.exclude=j.exclude;if(b.type===null&&j.type!==null)b.type=j.type;if(b.message===void 0&&j.message!==void 0)b.message=j.message;if(b.context===void 0&&j.context!==void 0)b.context=j.context;const q=b.flags,v=j.flags;if(v.isOptional!==void 0&&q.isOptional===void 0)q.isOptional=v.isOptional;if(v.validateIf!==void 0&&q.validateIf===void 0)q.validateIf=v.validateIf;if(v.isNullable!==void 0&&q.isNullable===void 0)q.isNullable=v.isNullable;if(v.validateNested!==void 0&&q.validateNested===void 0)q.validateNested=v.validateNested;if(v.validateNestedEach!==void 0&&q.validateNestedEach===void 0)q.validateNestedEach=v.validateNestedEach}}return A}}
@@ -0,0 +1,89 @@
1
+ import type { Result, ResultAsync } from '@zipbul/result';
2
+ import type { BakerIssue, RuntimeOptions } from '../common';
3
+ import type { CollectionType, RawClassMeta, RuleDef } from '../metadata';
4
+ export interface SealOptions {
5
+ /** Automatic conversion using validation decorators as type hints. @default false */
6
+ enableImplicitConversion?: boolean;
7
+ /** Use class default values when the key is missing from input. @default false */
8
+ exposeDefaultValues?: boolean;
9
+ /** true: return immediately on first error. false (default): collect all errors. @default false */
10
+ stopAtFirstError?: boolean;
11
+ /**
12
+ * true: reject undeclared fields. Uses the key set from mergeInheritance(Class) as the allowlist.
13
+ * `@Exclude` fields are also included in the whitelist — present but excluded from the result.
14
+ * @default false
15
+ */
16
+ whitelist?: boolean;
17
+ /** true: include field exclusion reasons as comments in generated code. @default false */
18
+ debug?: boolean;
19
+ }
20
+ export interface SealedExecutors<T> {
21
+ /** Internal executor — Result pattern. deserialize() wraps and converts to throw */
22
+ deserialize(input: unknown, options?: RuntimeOptions): Result<T, BakerIssue[]> | ResultAsync<T, BakerIssue[]>;
23
+ /** Internal executor — always succeeds. serialize assumes no validation */
24
+ serialize(instance: T, options?: RuntimeOptions): Record<string, unknown> | Promise<Record<string, unknown>>;
25
+ /** Internal executor — validate-only (no object creation). Returns null on success, BakerIssue[] on failure */
26
+ validate(input: unknown, options?: RuntimeOptions): BakerIssue[] | null | Promise<BakerIssue[] | null>;
27
+ /** true if the deserialize direction has async rules/transforms/nested */
28
+ isAsync: boolean;
29
+ /** true if the serialize direction has async transforms/nested */
30
+ isSerializeAsync: boolean;
31
+ /** Inheritance-resolved metadata — read during codegen to wire nested DTO fields and async analysis */
32
+ merged?: RawClassMeta;
33
+ }
34
+ /**
35
+ * Classification of a `@Type`/`@Field` `type` thunk's return value. The single reading of the
36
+ * Map/Set marker + array-unwrap that seal normalization, circular analysis, and async analysis all
37
+ * share — each caller then applies its OWN primitive-exclusion and error policy to `resolved` (seal
38
+ * throws on a non-constructor; the analyzers skip it), so only the classification lives here.
39
+ */
40
+ export interface ClassifiedType {
41
+ /** Set when the thunk returned the `Map` or `Set` constructor (a collection field). */
42
+ collection?: CollectionType;
43
+ /** True when the thunk returned the array form `[Element]`. */
44
+ isArray: boolean;
45
+ /** The element value (array-unwrapped), or `undefined` for a Map/Set collection. */
46
+ resolved: unknown;
47
+ }
48
+ /**
49
+ * Inline-nested scope a parent builder hands to a child: the shared mutable accumulator (reference
50
+ * arrays + circular-tracking set) plus the child's own path/var/input expression overrides.
51
+ */
52
+ export interface ChildScope {
53
+ regexes: RegExp[];
54
+ refs: unknown[];
55
+ execs: SealedExecutors<unknown>[];
56
+ inlineCounter: {
57
+ n: number;
58
+ };
59
+ inlineNestedClasses: Set<Function> | undefined;
60
+ pathPrefix: string;
61
+ varPrefix: string;
62
+ inputExpr: string;
63
+ }
64
+ /** Partitioned validation rules for a field — produced by categorizeRules. */
65
+ export interface CategorizedRules {
66
+ each: RuleDef[];
67
+ generalRules: RuleDef[];
68
+ /** The single typed dependency group (if any) after conflict check */
69
+ typedDeps: {
70
+ type: 'string' | 'number' | 'boolean' | 'date' | 'array' | 'object';
71
+ deps: RuleDef[];
72
+ } | undefined;
73
+ }
74
+ /** Result of resolveTypeGate — effective gate type and related metadata. */
75
+ export interface ResolvedTypeGate {
76
+ effectiveGateType: string | null;
77
+ /** The typed dependency rules (from requiresType) */
78
+ gateDeps: RuleDef[];
79
+ /** Index of the type asserter within generalRules (-1 if none) */
80
+ typeAsserterIdx: number;
81
+ /** The type asserter rule def (if found) */
82
+ typeAsserter: RuleDef | undefined;
83
+ /** Whether conversion is enabled for this field */
84
+ enableConversion: boolean;
85
+ /** Whether this gate was inferred from asserter only (no typed deps) */
86
+ asserterInferredGate: string | null;
87
+ /** Whether this gate was inferred from @Type hint */
88
+ typeHintGate: string | null;
89
+ }
File without changes
@@ -0,0 +1,16 @@
1
+ import type { RawClassMeta, MetaStore } from '../metadata';
2
+ /**
3
+ * Seal-time invariant checks on the merged metadata, run from sealOne after merge + type normalization
4
+ * and before codegen. Holds the {@link MetaStore} (for @Field-presence checks) as an injected collaborator.
5
+ * Throws BakerError on the first violation.
6
+ *
7
+ * Covers W2 (D7 + D9):
8
+ * - Discriminator shape: empty subTypes / invalid subType entry / name collision / missing/reserved property
9
+ * - Set/Map pairing: when a setValue/mapValue thunk is present, its target class must have @Field metadata
10
+ * (a primitive Set/Map with no value thunk is valid and intentionally not flagged)
11
+ */
12
+ export declare class MetaValidator {
13
+ #private;
14
+ constructor(meta: MetaStore);
15
+ validateShape(Class: Function, merged: RawClassMeta): void;
16
+ }
@@ -0,0 +1 @@
1
+ export class MetaValidator{#j;constructor(H){this.#j=H}validateShape(H,J){const v=H.name;for(const[w,F]of Object.entries(J)){if(F.type?.discriminator){const j=F.type.discriminator;if(typeof j.property!=="string"||j.property.length===0)throw new x(`${v}.${w}: discriminator.property must be a non-empty string.`);if(L.has(j.property))throw new x(`${v}.${w}: discriminator.property '${j.property}' is a reserved property name and cannot be used.`);if(!Array.isArray(j.subTypes)||j.subTypes.length===0)throw new x(`${v}.${w}: discriminator.subTypes must be a non-empty array of { value, name } entries.`);const G=new Set;for(let z=0;z<j.subTypes.length;z++){const q=j.subTypes[z];if(typeof q.name!=="string"||q.name.length===0)throw new x(`${v}.${w}: discriminator.subTypes[${z}].name must be a non-empty string.`);if(typeof q.value!=="function")throw new x(`${v}.${w}: discriminator.subTypes[${z}].value must be a class constructor (got ${typeof q.value}).`);if(G.has(q.name))throw new x(`${v}.${w}: discriminator.subTypes has duplicate name '${q.name}'. Each subType must have a unique name.`);G.add(q.name);if(!this.#j.hasOwn(q.value))throw new x(`${v}.${w}: discriminator.subTypes[${z}].value (${q.value.name}) has no @Field decorators.`)}}const I=F.type?.collection;if(I!==void 0&&F.type?.resolvedCollectionValue){const j=F.type.resolvedCollectionValue;if(!this.#j.hasOwn(j)){const G=I===K.Set?"setValue":"mapValue";throw new x(`${v}.${w}: ${G} target (${j.name}) has no @Field decorators.`)}}}}}import{BakerError as x}from"../common/index.js";import{CollectionType as K}from"../metadata/index.js";import{RESERVED_PROPERTY_NAMES as L}from"./constants.js";
@@ -1,31 +1,7 @@
1
- import type { SealOptions } from '../interfaces';
2
- import type { RawClassMeta, SealedExecutors } from '../types';
3
- /** @internal Placeholder executor for circular dependency detection during seal */
4
- declare function circularPlaceholder(className: string): SealedExecutors<unknown>;
5
- /** Canonical fingerprint of a SealOptions — the 5 booleans in fixed order. `{}` and a fully-defaulted
6
- * object both map to "00000", so `new Baker()` and `new Baker({})` share a cache key. */
7
- declare function configFingerprint(o: SealOptions): string;
8
- declare function getCached(cls: Function, fp: string): SealedExecutors<unknown> | undefined;
9
- /** Test-only: drop a single class's cached executors so a re-seal recompiles it. */
10
- declare function clearCached(cls: Function): void;
1
+ import type { SealOptions, SealedExecutors } from './interfaces';
11
2
  /**
12
- * Test-only: drop the ENTIRE cache. Used by `unseal()` so a test that re-seals classes starts from a
13
- * clean slate — a whole-cache reset (vs per-class) is the only way to avoid the partial-clear state
14
- * where a cached root still references a nested whose entry was dropped (a root + its nested are always
15
- * compiled together, so they must be invalidated together).
3
+ * Seal every class in `registry` with `options`, writing executors into `executors`. The core used by
4
+ * `new Baker().seal()` — a thin entry point over one {@link SealRun}.
16
5
  */
17
- declare function clearAllCached(): void;
18
6
  declare function sealRegistry(registry: Set<Function>, options: SealOptions, executors: Map<Function, SealedExecutors<unknown>>): void;
19
- /**
20
- * Merges RAW metadata child-first along the prototype chain of Class.
21
- *
22
- * Merge rules:
23
- * - validation: union merge (both parent and child apply, duplicate rules removed)
24
- * - transform: child takes priority, inherits from parent if absent in child
25
- * - expose: child takes priority, inherits from parent if absent in child
26
- * - exclude: child takes priority, inherits from parent if absent in child
27
- * - type: child takes priority, inherits from parent if absent in child
28
- * - flags: child takes priority, only missing flags are supplemented from parent
29
- */
30
- declare function mergeInheritance(Class: Function): RawClassMeta;
31
- export { sealRegistry, mergeInheritance, circularPlaceholder, getCached, configFingerprint, clearCached, clearAllCached };
7
+ export { sealRegistry };
@@ -1 +1 @@
1
- import{CollectionType as R,Direction as P}from"../enums.js";import{BakerError as F}from"../errors.js";import{getRaw as h,hasRawOwn as x}from"../meta-access.js";import{isAsyncFunction as v}from"../utils.js";import{analyzeCircular as g}from"./circular-analyzer.js";import{buildDeserializeCode as f,buildValidateCode as y}from"./deserialize-builder.js";import{validateExposeStacks as u}from"./expose-validator.js";import{buildSerializeCode as C}from"./serialize-builder.js";import{validateMeta as p}from"./validate-meta.js";const n=new Set(["__proto__","constructor","prototype"]);const D=new Set([Number,String,Boolean,Date]);function circularPlaceholder(j){const G=`Circular dependency during seal: ${j} is still being sealed`;return{deserialize(){throw new F(G)},serialize(){throw new F(G)},validate(){throw new F(G)},isAsync:!1,isSerializeAsync:!1}}function O(j,G,H,J){const K=G===P.Deserialize?"isAsync":"isSerializeAsync",W=J??new Set,L=(Q)=>{if(W.has(Q))return!1;W.add(Q);const q=H(Q);if(q?.merged)return q[K]===!0;return O(mergeInheritance(Q),G,H,W)};for(const Q of Object.values(j)){if(G===P.Deserialize&&Q.validation.some((q)=>q.rule.isAsync))return!0;for(const q of Q.transform){if(G===P.Deserialize?q.options?.serializeOnly:q.options?.deserializeOnly)continue;if(q.isAsync??v(q.fn))return!0}if(k(Q).some(L))return!0}return!1}function k(j){const G=j.type;if(!G)return[];const H=[];if(G.resolvedClass)H.push(G.resolvedClass);if(G.resolvedCollectionValue)H.push(G.resolvedCollectionValue);if(G.discriminator)for(const J of G.discriminator.subTypes)H.push(J.value);if(H.length===0&&G.fn){const J=G.fn();if(J===Map||J===Set){const K=G.collectionValue?.();if(typeof K==="function"&&!D.has(K))H.push(K)}else{const K=Array.isArray(J)?J[0]:J;if(typeof K==="function"&&!D.has(K))H.push(K)}}return H}let _=new WeakMap;function configFingerprint(j){return(j.enableImplicitConversion?"1":"0")+(j.exposeDefaultValues?"1":"0")+(j.stopAtFirstError?"1":"0")+(j.whitelist?"1":"0")+(j.debug?"1":"0")}function getCached(j,G){return _.get(j)?.get(G)}function clearCached(j){_.delete(j)}function clearAllCached(){_=new WeakMap}function d(j,G,H){let J=_.get(j);if(J===void 0){J=new Map;_.set(j,J)}J.set(G,H)}function sealRegistry(j,G,H){const J=configFingerprint(G),K=new Set;try{for(const W of j)M(W,H,J,G,K)}catch(W){H.clear();throw W}for(const W of K)d(W,J,H.get(W));j.clear()}function M(j,G,H,J,K){if(G.has(j))return;const W=getCached(j,H);if(W!==void 0){G.set(j,W);if(W.merged)for(const q of Object.values(W.merged))for(const Y of k(q))M(Y,G,H,J,K);return}const L=circularPlaceholder(j.name);G.set(j,L);const Q=(q)=>G.get(q);try{const q=mergeInheritance(j);for(const $ of Object.keys(q))if(n.has($))throw new F(`${j.name}: field name '${$}' is not allowed (reserved property name)`);for(const[$,U]of Object.entries(q)){if(!U.type?.fn)continue;let w;try{w=U.type.fn()}catch(B){throw new F(`${j.name}.${$}: type function threw: ${B.message}`,{cause:B})}if(w===Map||w===Set){const B=w===Map?R.Map:R.Set,I={...U.type,collection:B,isArray:!1};if(U.type.collectionValue){let V;try{V=U.type.collectionValue()}catch(E){throw new F(`${j.name}.${$}: collectionValue function threw: ${E.message}`,{cause:E})}if(V!=null&&typeof V==="function"&&!D.has(V))I.resolvedCollectionValue=V}q[$]={...U,type:I};continue}const T=Array.isArray(w),N=T?w[0]:w;if(N==null||typeof N!=="function")throw new F(`${j.name}: @Type/@Field type must return a constructor or [constructor], got ${String(N)}`);const z={...U.type,isArray:T};if(!D.has(N)){z.resolvedClass=N;if(!U.flags.validateNested||!U.flags.validateNestedEach){U.flags={...U.flags};if(!U.flags.validateNested)U.flags.validateNested=!0;if(T&&!U.flags.validateNestedEach)U.flags.validateNestedEach=!0}}q[$]={...U,type:z}}u(q,j.name);p(j,q);const Y=g(j);for(const $ of Object.values(q)){if($.type?.resolvedClass)M($.type.resolvedClass,G,H,J,K);if($.type?.resolvedCollectionValue)M($.type.resolvedCollectionValue,G,H,J,K);if($.type?.discriminator)for(const U of $.type.discriminator.subTypes)M(U.value,G,H,J,K)}const X=O(q,P.Deserialize,Q),Z=O(q,P.Serialize,Q),b=f(j,q,J,Y,X,Q),S=y(j,q,J,Y,X,Q),A=C(j,q,J,Z,Q);Object.assign(L,{deserialize:b,serialize:A,validate:S,isAsync:X,isSerializeAsync:Z,merged:q})}catch(q){G.delete(j);throw q}K?.add(j)}function mergeInheritance(j){const G=[];let H=j;while(H&&H!==Object){if(x(H))G.push(H);const K=Object.getPrototypeOf(H);H=K===H?null:K}const J=Object.create(null);for(const K of G){const W=h(K);for(const[L,Q]of Object.entries(W))if(!J[L])J[L]={...Q,validation:[...Q.validation],transform:[...Q.transform],expose:[...Q.expose],exclude:Q.exclude,type:Q.type,flags:{...Q.flags}};else{const q=J[L],Y=Q;for(const b of Y.validation)if(!q.validation.some((S)=>S.rule.ruleName===b.rule.ruleName))q.validation.push(b);if(q.transform.length===0&&Y.transform.length>0)q.transform=[...Y.transform];if(q.expose.length===0&&Y.expose.length>0)q.expose=[...Y.expose];if(q.exclude===null&&Y.exclude!==null)q.exclude=Y.exclude;if(q.type===null&&Y.type!==null)q.type=Y.type;const X=q.flags,Z=Y.flags;if(Z.isOptional!==void 0&&X.isOptional===void 0)X.isOptional=Z.isOptional;if(Z.isDefined!==void 0&&X.isDefined===void 0)X.isDefined=Z.isDefined;if(Z.validateIf!==void 0&&X.validateIf===void 0)X.validateIf=Z.validateIf;if(Z.isNullable!==void 0&&X.isNullable===void 0)X.isNullable=Z.isNullable;if(Z.validateNested!==void 0&&X.validateNested===void 0)X.validateNested=Z.validateNested;if(Z.validateNestedEach!==void 0&&X.validateNestedEach===void 0)X.validateNestedEach=Z.validateNestedEach}}return J}export{sealRegistry,mergeInheritance,circularPlaceholder,getCached,configFingerprint,clearCached,clearAllCached};
1
+ class W{executors;options;fp;sealed=new Map;inserted=new Set;resolve=(j)=>this.executors.get(j);#q;#F;#j;#G;constructor(j,F,G=N){this.executors=j;this.options=F;this.fp=L.fingerprint(F);this.#q=new T(G);this.#F=new Y(this.#q);this.#j=new O(this.resolve,this.#q);this.#G=new V(G)}run(j){try{for(const F of j)this.sealOne(F)}catch(F){for(const G of this.inserted)this.executors.delete(G);throw F}for(const[F,G]of this.sealed)L.set(F,this.fp,G);j.clear()}sealOne(j){if(this.executors.has(j))return;const F=L.get(j,this.fp);if(F!==void 0){this.executors.set(j,F);this.inserted.add(j);if(F.merged)for(const q of Object.values(F.merged))for(const H of this.#j.nestedClassesOf(q))this.sealOne(H);return}const G=new B(j.name);this.executors.set(j,G);this.inserted.add(j);try{const q=this.#q.merge(j);for(const J of Object.keys(q))if(_.has(J))throw new I(`${j.name}: field name '${J}' is not allowed (reserved property name)`);b(q,j.name);P(q,j.name);this.#G.validateShape(j,q);const H=this.#F.analyze(j);for(const J of Object.values(q))for(const f of this.#j.nestedClassesOf(J))this.sealOne(f);const K=this.#j.analyze(q,U.Deserialize),Q=this.#j.analyze(q,U.Serialize),X=w(j,q,this.options,H,K,this.resolve),Z=M(j,q,this.options,H,K,this.resolve),$=D(j,q,this.options,Q,this.resolve);Object.assign(G,{deserialize:X,serialize:$,validate:Z,isAsync:K,isSerializeAsync:Q,merged:q})}catch(q){this.executors.delete(j);throw q}this.sealed.set(j,G)}}import{Direction as U,BakerError as I}from"../common/index.js";import{metaStore as N}from"../metadata/index.js";import{AsyncAnalyzer as O}from"./async-analyzer.js";import{CircularAnalyzer as Y}from"./circular-analyzer.js";import{CircularPlaceholder as B}from"./circular-placeholder.js";import{compileCache as L}from"./compile-cache.js";import{RESERVED_PROPERTY_NAMES as _}from"./constants.js";import{buildDeserializeCode as w,buildValidateCode as M}from"./deserialize-builder.js";import{validateExposeStacks as P}from"./expose-validator.js";import{InheritanceMerger as T}from"./inheritance-merger.js";import{MetaValidator as V}from"./meta-validator.js";import{buildSerializeCode as D}from"./serialize-builder.js";import{normalizeTypeDefs as b}from"./type-normalizer.js";function sealRegistry(j,F,G){new W(G,F).run(j)}export{sealRegistry};
@@ -1,8 +1,10 @@
1
- import type { SealOptions, RuntimeOptions } from '../interfaces';
2
- import type { RawClassMeta, SealedExecutors } from '../types';
1
+ import type { RuntimeOptions } from '../common';
2
+ import type { RawClassMeta } from '../metadata';
3
+ import type { SealOptions, SealedExecutors } from './interfaces';
3
4
  /**
4
5
  * Generate serialize executor code.
5
- * Assumes no validation always returns Record<string, unknown> (§4.3).
6
+ * Thin wrapper preserving the historical free-function entry point: instantiates
7
+ * SerializeBuilder and returns its built executor.
6
8
  */
7
9
  declare function buildSerializeCode<T>(Class: Function, merged: RawClassMeta, options: SealOptions | undefined, isAsync: boolean, resolve: (cls: Function) => SealedExecutors<unknown> | undefined): (instance: T, opts?: RuntimeOptions) => Record<string, unknown> | Promise<Record<string, unknown>>;
8
10
  export { buildSerializeCode };
@@ -1,70 +1,70 @@
1
- import{CollectionType as c}from"../enums.js";import{BakerError as p}from"../errors.js";import{sanitizeKey as E,buildGroupsHasExpr as m}from"./codegen-utils.js";const j={out:"__bk$out",fieldVal:"__bk$fv_",groups:"__bk$groups",group0:"__bk$group0",groupsSet:"__bk$groupsSet",setArr:"__bk$sa",setItem:"__bk$si",mapObj:"__bk$m",mapEntry:"__bk$me",serResult:"__bk$sr",outItem:"__bk$out_item",discArr:"__bk$da",discIdx:"__bk$di",nestedArr:"__bk$na",nestedIdx:"__bk$ni",nestedItem:"__bk$nitem"};function u(U,q){const M=q.find((R)=>R.serializeOnly&&R.name);if(M)return M.name;const Q=q.find((R)=>!R.deserializeOnly&&!R.serializeOnly&&R.name);if(Q)return Q.name;return U}function y(U){let q=null;for(const M of U){if(M.deserializeOnly)continue;if(!M.groups||M.groups.length===0)return;if(q===null)q=new Set;for(const Q of M.groups)q.add(Q)}return q===null?void 0:[...q]}function x(U,q,M,Q){if(M.length===0)return null;if(M.length===1){const X=M[0],Z=Q.length;Q.push(X.fn);const W=`refs[${Z}]({value:${U},key:${JSON.stringify(q)},obj:instance})`;return X.isAsync?`(await ${W})`:W}if(M.length===2){const X=M[1],Z=M[0],W=Q.length;Q.push(X.fn);const B=Q.length;Q.push(Z.fn);const D=`refs[${W}]({value:${U},key:${JSON.stringify(q)},obj:instance})`,I=X.isAsync?`(await ${D})`:D,L=`refs[${B}]({value:${I},key:${JSON.stringify(q)},obj:instance})`;return Z.isAsync?`(await ${L})`:L}let R=U;for(let X=M.length-1;X>=0;X-=1){const Z=M[X],W=Q.length;Q.push(Z.fn);const B=`refs[${W}]({value:${R},key:${JSON.stringify(q)},obj:instance})`;R=Z.isAsync?`(await ${B})`:B}return R}function T(U,q,M,Q){const R=x(U,q,M,Q);return R?`
2
- ${U} = ${R};`:""}function buildSerializeCode(U,q,M,Q,R){const X=[],Z=[];let W=`'use strict';
3
- `;W+=`var ${j.out} = {};
4
- `;if(Object.values(q).some((P)=>{const O=y(P.expose);return O&&O.length>0})){W+=`var ${j.groups} = opts && opts.groups;
5
- `;W+=`var ${j.group0} = ${j.groups} && ${j.groups}.length === 1 ? ${j.groups}[0] : null;
6
- `;W+=`var ${j.groupsSet} = ${j.groups} && ${j.groups}.length > 1 ? new Set(${j.groups}) : null;
7
- `}for(const[P,O]of Object.entries(q))W+=f(P,O,X,Z,Q,R,M,U.name);W+=`return ${j.out};
8
- `;const D=U.name.replace(/[^\w$.-]/g,"_");W+=`//# sourceURL=baker://${D}/serialize
9
- `;return Function("refs","execs","BakerError",`return ${Q?"async function":"function"}(instance, opts) { `+W+" }")(X,Z,p)}function f(U,q,M,Q,R,X,Z,W=""){if(q.exclude){if(!q.exclude.deserializeOnly){if(Z?.debug){const Y=q.exclude.serializeOnly?"serializeOnly":"bidirectional";return`// [baker] field ${JSON.stringify(U)} excluded (${Y} @Exclude)
10
- `}return""}}if(q.expose.length>0&&q.expose.every((Y)=>Y.deserializeOnly)){if(Z?.debug)return`// [baker] field ${JSON.stringify(U)} excluded (all @Expose entries are deserializeOnly)
11
- `;return""}const B=u(U,q.expose),D=y(q.expose),I=E(U),L=`${j.fieldVal}${I}`;let P="";P+=`var ${L} = instance[${JSON.stringify(U)}];
12
- `;let O="",S="";if(D&&D.length>0){O=`if ((${j.group0} !== null || ${j.groupsSet}) && (${m(j.group0,j.groupsSet,D)})) {
13
- `;S=`}
14
- `}let $="";const b=q.flags.isOptional,V=q.transform.filter((Y)=>!Y.options?.deserializeOnly);if(q.type?.collection){const Y=`${j.out}[${JSON.stringify(B)}]`,_=q.type.collection;let J;if(_===c.Set)if(q.type.resolvedCollectionValue){const F=X(q.type.resolvedCollectionValue),h=Q.length;Q.push(F);if(R)J=`{ var __ser_ps = []; for (var __ser_item of ${L}) { __ser_ps.push(__ser_item == null ? __ser_item : execs[${h}].serialize(__ser_item, opts)); } ${Y} = await Promise.all(__ser_ps); }`;else{J=`var ${j.setArr} = [];
15
- `;J+=` for (var ${j.setItem} of ${L}) {
16
- `;J+=` ${j.setArr}.push(${j.setItem} == null ? ${j.setItem} : execs[${h}].serialize(${j.setItem}, opts));
17
- `;J+=` }
18
- `;J+=` ${Y} = ${j.setArr};`}}else J=`${Y} = [...${L}];`;else{const F=`if (typeof ${j.mapEntry}[0] !== 'string') { throw new BakerError(${JSON.stringify(W)} + ': Map field ' + ${JSON.stringify(U)} + ' has non-string key (' + typeof ${j.mapEntry}[0] + '). Map serialization requires string keys.'); }
19
- `;if(q.type.resolvedCollectionValue){const h=X(q.type.resolvedCollectionValue),z=Q.length;Q.push(h);const v=R?"await ":"";J=`var ${j.mapObj} = Object.create(null);
20
- `;J+=` for (var ${j.mapEntry} of ${L}) {
21
- `;J+=` ${F}`;J+=`${j.mapObj}[${j.mapEntry}[0]] = ${j.mapEntry}[1] == null ? ${j.mapEntry}[1] : ${v}execs[${z}].serialize(${j.mapEntry}[1], opts);
22
- `;J+=` }
23
- `;J+=` ${Y} = ${j.mapObj};`}else{J=`var ${j.mapObj} = Object.create(null);
24
- `;J+=` for (var ${j.mapEntry} of ${L}) {
25
- `;J+=` ${F}`;J+=`${j.mapObj}[${j.mapEntry}[0]] = ${j.mapEntry}[1];
26
- `;J+=` }
27
- `;J+=` ${Y} = ${j.mapObj};`}}J+=T(Y,U,V,M);if(b)$=`if (${L} !== undefined && ${L} !== null) {
28
- ${J}
29
- } else if (${L} === null) {
30
- ${Y} = null;
1
+ class x{refs=[];execs=[];Class;merged;options;isAsync;resolve;constructor(Q,M,U,Y,Z){this.Class=Q;this.merged=M;this.options=U;this.isAsync=Y;this.resolve=Z}build(){let Q=`'use strict';
2
+ `;Q+=`var ${q.out} = {};
3
+ `;let M=!1;for(const _ in this.merged){const j=this.merged[_];if(j===void 0)continue;const R=V(j.expose,b.Serialize);if(R&&R.length>0){M=!0;break}}if(M){Q+=`var ${q.groups} = opts && opts.groups;
4
+ `;Q+=`var ${q.group0} = ${q.groups} && ${q.groups}.length === 1 ? ${q.groups}[0] : null;
5
+ `;Q+=`var ${q.groupsSet} = ${q.groups} && ${q.groups}.length > 1 ? new Set(${q.groups}) : null;
6
+ `}for(const[_,j]of Object.entries(this.merged))Q+=this.generateFieldCode(_,j);Q+=`return ${q.out};
7
+ `;const U=this.Class.name.replace(/[^\w$.-]/g,"_");Q+=`//# sourceURL=baker://${U}/serialize
8
+ `;const Y=this.isAsync?"async function":"function";return Function("refs","execs","BakerError",`return ${Y}(instance, opts) { `+Q+" }")(this.refs,this.execs,K)}resolveExecutor(Q){const M=this.resolve(Q);if(M===void 0)throw new K(`${this.Class.name}: nested class '${Q.name}' was not sealed before serialize codegen.`);return M}generateFieldCode(Q,M){const U=this.Class.name,Y=this.options;if(M.exclude){if(!M.exclude.deserializeOnly){if(Y?.debug){const W=M.exclude.serializeOnly?"serializeOnly":"bidirectional";return`// [baker] field ${JSON.stringify(Q)} excluded (${W} @Exclude)
9
+ `}return""}}if(M.expose.length>0&&M.expose.every((W)=>W.deserializeOnly)){if(Y?.debug)return`// [baker] field ${JSON.stringify(Q)} excluded (all @Expose entries are deserializeOnly)
10
+ `;return""}const Z=p(Q,M.expose,b.Serialize),_=V(M.expose,b.Serialize),j=E(Q),R=`${q.fieldVal}${j}`;let A="";A+=`var ${R} = instance[${JSON.stringify(Q)}];
11
+ `;let v="",w="";if(_&&_.length>0){v=`if ((${q.group0} !== null || ${q.groupsSet}) && (${f(q.group0,q.groupsSet,_)})) {
12
+ `;w=`}
13
+ `}let J="";const I=M.flags.isOptional,g=M.transform.filter((W)=>!W.options?.deserializeOnly);if(M.type?.collection){const W=`${q.out}[${JSON.stringify(Z)}]`,$=M.type.collection;let L;if($===m.Set)if(M.type.resolvedCollectionValue){const H=this.resolveExecutor(M.type.resolvedCollectionValue),O=this.execs.length;this.execs.push(H);if(this.isAsync)L=`{ var __ser_ps${j} = []; for (var __ser_item${j} of ${R}) { __ser_ps${j}.push(__ser_item${j} == null ? __ser_item${j} : execs[${O}].serialize(__ser_item${j}, opts)); } ${W} = await Promise.all(__ser_ps${j}); }`;else{L=`var ${q.setArr}${j} = [];
14
+ `;L+=` for (var ${q.setItem}${j} of ${R}) {
15
+ `;L+=` ${q.setArr}${j}.push(${q.setItem}${j} == null ? ${q.setItem}${j} : execs[${O}].serialize(${q.setItem}${j}, opts));
16
+ `;L+=` }
17
+ `;L+=` ${W} = ${q.setArr}${j};`}}else L=`${W} = [...${R}];`;else{const H=`if (typeof ${q.mapEntry}${j}[0] !== 'string') { throw new BakerError(${JSON.stringify(U)} + ': Map field ' + ${JSON.stringify(Q)} + ' has non-string key (' + typeof ${q.mapEntry}${j}[0] + '). Map serialization requires string keys.'); }
18
+ `;if(M.type.resolvedCollectionValue){const O=this.resolveExecutor(M.type.resolvedCollectionValue),B=this.execs.length;this.execs.push(O);const D=this.isAsync?"await ":"";L=`var ${q.mapObj}${j} = Object.create(null);
19
+ `;L+=` for (var ${q.mapEntry}${j} of ${R}) {
20
+ `;L+=` ${H}`;L+=`${q.mapObj}${j}[${q.mapEntry}${j}[0]] = ${q.mapEntry}${j}[1] == null ? ${q.mapEntry}${j}[1] : ${D}execs[${B}].serialize(${q.mapEntry}${j}[1], opts);
21
+ `;L+=` }
22
+ `;L+=` ${W} = ${q.mapObj}${j};`}else{L=`var ${q.mapObj}${j} = Object.create(null);
23
+ `;L+=` for (var ${q.mapEntry}${j} of ${R}) {
24
+ `;L+=` ${H}`;L+=`${q.mapObj}${j}[${q.mapEntry}${j}[0]] = ${q.mapEntry}${j}[1];
25
+ `;L+=` }
26
+ `;L+=` ${W} = ${q.mapObj}${j};`}}L+=this.buildPostNestedTransformCode(W,Q,g);if(I)J=`if (${R} !== undefined && ${R} !== null) {
27
+ ${L}
28
+ } else if (${R} === null) {
29
+ ${W} = null;
31
30
  }
32
- `;else $=`if (${L} != null) {
33
- ${J}
31
+ `;else J=`if (${R} != null) {
32
+ ${L}
34
33
  } else {
35
- ${Y} = ${L};
34
+ ${W} = ${R};
36
35
  }
37
- `;P+=O+$+S;return P}if(q.type?.resolvedClass||q.type?.discriminator||q.type?.fn&&q.flags.validateNested){const Y=q.type?.isArray||q.flags.validateNestedEach||q.validation.some((F)=>F.each),_=`${j.out}[${JSON.stringify(B)}]`;let J;if(q.type.discriminator){const{property:F,subTypes:h}=q.type.discriminator,z=q.type.keepDiscriminatorProperty!==!1,v=[...h].sort((H,k)=>{if(H.value.prototype instanceof k.value)return-1;if(k.value.prototype instanceof H.value)return 1;return 0}),K=(H,k)=>{let w="";for(let A=0;A<v.length;A++){const g=v[A],N=X(g.value),C=Q.length;Q.push(N);const G=M.length;M.push(g.value);w+=`${A===0?"if":"} else if"} (${H} instanceof refs[${G}]) {
38
- `;w+=` var ${j.serResult} = ${k}execs[${C}].serialize(${H}, opts);
39
- `;if(z)w+=` ${j.serResult}[${JSON.stringify(F)}] = ${JSON.stringify(g.name)};
40
- `;w+=` ${j.outItem} = ${j.serResult};
41
- `}w+=`} else { ${j.outItem} = `+H+`; }
42
- `;return w};if(Y){const H=R?"await ":"";if(R)J=`${_} = await Promise.all(${L}.map(async function(__ser_item) {
43
- `;else{J=`var ${j.discArr} = [];
44
- `;J+=` for (var ${j.discIdx}=0; ${j.discIdx}<${L}.length; ${j.discIdx}++) {
45
- `;J+=` var __ser_item = ${L}[${j.discIdx}];
46
- `}J+=` var ${j.outItem};
47
- `;J+=K("__ser_item",H);if(R){J+=` return ${j.outItem};
48
- `;J+="}));"}else{J+=` ${j.discArr}.push(${j.outItem});
49
- `;J+=` }
50
- `;J+=` ${_} = ${j.discArr};`}}else{const H=R?"await ":"";J=`var ${j.outItem};
51
- `;J+=K(L,H);J+=`${_} = ${j.outItem};`}}else{const F=q.type.resolvedClass??q.type.fn(),h=X(F),z=Q.length;Q.push(h);if(Y)if(R)J=`${_} = await Promise.all(${L}.map(async function(__ser_item) { return __ser_item == null ? __ser_item : await execs[${z}].serialize(__ser_item, opts); }));`;else{J=`var ${j.nestedArr} = [];
52
- `;J+=` for (var ${j.nestedIdx}=0; ${j.nestedIdx}<${L}.length; ${j.nestedIdx}++) {
53
- `;J+=` var ${j.nestedItem} = ${L}[${j.nestedIdx}];
54
- `;J+=` ${j.nestedArr}.push(${j.nestedItem} == null ? ${j.nestedItem} : execs[${z}].serialize(${j.nestedItem}, opts));
55
- `;J+=` }
56
- `;J+=` ${_} = ${j.nestedArr};`}else J=`${_} = ${R?"await ":""}execs[${z}].serialize(${L}, opts);`}J+=T(_,U,V,M);if(b)$=`if (${L} !== undefined && ${L} !== null) {
57
- ${J}
58
- } else if (${L} === null) {
59
- ${_} = null;
36
+ `;A+=v+J+w;return A}const F=M.type;if(F&&(F.resolvedClass||F.discriminator||F.fn!==void 0&&M.flags.validateNested)){const W=F.isArray||M.flags.validateNestedEach||M.validation.some((H)=>H.each),$=`${q.out}[${JSON.stringify(Z)}]`;let L;if(F.discriminator){const{property:H,subTypes:O}=F.discriminator,B=F.keepDiscriminatorProperty===!0,D=O.map((X,P)=>({sub:X,index:P,depth:u(X.value)})).sort((X,P)=>P.depth-X.depth||X.index-P.index).map((X)=>X.sub),T=(X,P)=>{let z="";for(let S=0;S<D.length;S++){const h=D[S],C=this.resolveExecutor(h.value),N=this.execs.length;this.execs.push(C);const G=this.refs.length;this.refs.push(h.value);z+=`${S===0?"if":"} else if"} (${X} instanceof refs[${G}]) {
37
+ `;z+=` var ${q.serResult}${j} = ${P}execs[${N}].serialize(${X}, opts);
38
+ `;if(B)z+=` ${q.serResult}${j}[${JSON.stringify(H)}] = ${JSON.stringify(h.name)};
39
+ `;z+=` ${q.outItem}${j} = ${q.serResult}${j};
40
+ `}const c=JSON.stringify(JSON.stringify(O.map((S)=>S.name))),y=`(${X} == null ? ${X} : ${X}[${JSON.stringify(H)}])`,k=JSON.stringify(`${U}.${Q}: value matches no discriminator subtype (received discriminator=`);z+=`} else { throw new BakerError(${k} + JSON.stringify(${y}) + ${JSON.stringify(", expected one of ")} + ${c} + ${JSON.stringify(")")}); }
41
+ `;return z};if(W){const X=this.isAsync?"await ":"",P=`__ser_item${j}`;if(this.isAsync)L=`${$} = await Promise.all(${R}.map(async function(${P}) {
42
+ `;else{L=`var ${q.discArr}${j} = [];
43
+ `;L+=` for (var ${q.discIdx}${j}=0; ${q.discIdx}${j}<${R}.length; ${q.discIdx}${j}++) {
44
+ `;L+=` var ${P} = ${R}[${q.discIdx}${j}];
45
+ `}L+=` var ${q.outItem}${j};
46
+ `;L+=T(P,X);if(this.isAsync){L+=` return ${q.outItem}${j};
47
+ `;L+="}));"}else{L+=` ${q.discArr}${j}.push(${q.outItem}${j});
48
+ `;L+=` }
49
+ `;L+=` ${$} = ${q.discArr}${j};`}}else{const X=this.isAsync?"await ":"";L=`var ${q.outItem}${j};
50
+ `;L+=T(R,X);L+=`${$} = ${q.outItem}${j};`}}else{const H=F.resolvedClass,O=this.resolveExecutor(H),B=this.execs.length;this.execs.push(O);if(W)if(this.isAsync)L=`${$} = await Promise.all(${R}.map(async function(__ser_item) { return __ser_item == null ? __ser_item : await execs[${B}].serialize(__ser_item, opts); }));`;else{L=`var ${q.nestedArr}${j} = [];
51
+ `;L+=` for (var ${q.nestedIdx}${j}=0; ${q.nestedIdx}${j}<${R}.length; ${q.nestedIdx}${j}++) {
52
+ `;L+=` var ${q.nestedItem}${j} = ${R}[${q.nestedIdx}${j}];
53
+ `;L+=` ${q.nestedArr}${j}.push(${q.nestedItem}${j} == null ? ${q.nestedItem}${j} : execs[${B}].serialize(${q.nestedItem}${j}, opts));
54
+ `;L+=` }
55
+ `;L+=` ${$} = ${q.nestedArr}${j};`}else{const D=this.isAsync?"await ":"";L=`${$} = ${D}execs[${B}].serialize(${R}, opts);`}}L+=this.buildPostNestedTransformCode($,Q,g);if(I)J=`if (${R} !== undefined && ${R} !== null) {
56
+ ${L}
57
+ } else if (${R} === null) {
58
+ ${$} = null;
60
59
  }
61
- `;else $=`if (${L} != null) {
62
- ${J}
60
+ `;else J=`if (${R} != null) {
61
+ ${L}
63
62
  } else {
64
- ${_} = ${L};
63
+ ${$} = ${R};
65
64
  }
66
- `}else{const Y=n(U,B,L,q,M);if(b){$+=`if (${L} !== undefined) {
67
- `;$+=" "+Y+`
68
- `;$+=`}
69
- `}else $+=Y+`
70
- `}P+=O+$+S;return P}function n(U,q,M,Q,R){const X=`${j.out}[${JSON.stringify(q)}]`,Z=Q.transform.filter((W)=>!W.options?.deserializeOnly);if(Z.length>0){const W=x(M,U,Z,R);return`${X} = ${W};`}return`${X} = ${M};`}export{buildSerializeCode};
65
+ `}else{const W=this.buildOutputExpr(Q,Z,R,M);if(I){J+=`if (${R} !== undefined) {
66
+ `;J+=" "+W+`
67
+ `;J+=`}
68
+ `}else J+=W+`
69
+ `}A+=v+J+w;return A}buildTransformExpr(Q,M,U){if(U.length===0)return null;const Y=this.refs;let Z=Q;for(let _=U.length-1;_>=0;_-=1){const j=U[_],R=Y.length;Y.push(j.fn);const A=`refs[${R}]({value:${Z},key:${JSON.stringify(M)},obj:instance})`;Z=j.isAsync?`(await ${A})`:A}return Z}buildPostNestedTransformCode(Q,M,U){const Y=this.buildTransformExpr(Q,M,U);return Y?`
70
+ ${Q} = ${Y};`:""}buildOutputExpr(Q,M,U,Y){const Z=`${q.out}[${JSON.stringify(M)}]`,_=Y.transform.filter((j)=>!j.options?.deserializeOnly);if(_.length>0){const j=this.buildTransformExpr(U,Q,_);return`${Z} = ${j};`}return`${Z} = ${U};`}}import{BakerError as K,Direction as b}from"../common/index.js";import{CollectionType as m}from"../metadata/index.js";import{sanitizeKey as E,buildGroupsHasExpr as f,resolveExposeName as p,resolveExposeGroups as V}from"./codegen-utils.js";import{SER_GEN as q}from"./constants.js";function u(Q){let M=0,U=Object.getPrototypeOf(Q);while(typeof U==="function"){M+=1;U=Object.getPrototypeOf(U)}return M}function buildSerializeCode(Q,M,U,Y,Z){return new x(Q,M,U,Y,Z).build()}export{buildSerializeCode};
@@ -0,0 +1,9 @@
1
+ import type { RawClassMeta } from '../metadata';
2
+ /**
3
+ * Seal-time normalization of each field's `@Type`/`@Field` type thunk: resolve `type.fn()`, detect
4
+ * Map/Set collections and the `[Element]` array form, exclude primitive constructors, and auto-infer the
5
+ * `validateNested`/`validateNestedEach` flags for DTO classes. Mutates `merged` in place — it reassigns
6
+ * `merged[key]` with a copy-on-write `type` (never mutating the shared RAW `type`) and mutates the
7
+ * already-per-seal-cloned `meta.flags` directly. Stateless — a plain function (no instance needed).
8
+ */
9
+ export declare function normalizeTypeDefs(merged: RawClassMeta, className: string): void;
@@ -0,0 +1 @@
1
+ import{BakerError as H}from"../common/index.js";import{PRIMITIVE_CTORS as U}from"./constants.js";import{classifyTypeResult as W}from"./type-resolver.js";export function normalizeTypeDefs(F,G){for(const[z,b]of Object.entries(F)){if(!b.type?.fn)continue;let J;try{J=b.type.fn()}catch(j){throw new H(`${G}.${z}: type function threw: ${j instanceof Error?j.message:String(j)}`,{cause:j})}const{collection:K,isArray:L,resolved:q}=W(J);if(K!==void 0){const j={...b.type,collection:K,isArray:!1};if(b.type.collectionValue){let x;try{x=b.type.collectionValue()}catch(D){throw new H(`${G}.${z}: collectionValue function threw: ${D instanceof Error?D.message:String(D)}`,{cause:D})}if(x!=null&&typeof x==="function"&&!U.has(x))j.resolvedCollectionValue=x}F[z]={...b,type:j};continue}if(q==null||typeof q!=="function")throw new H(`${G}: @Type/@Field type must return a constructor or [constructor], got ${String(q)}`);const Q={...b.type,isArray:L};if(!U.has(q)){Q.resolvedClass=q;if(!b.flags.validateNested)b.flags.validateNested=!0;if(L&&!b.flags.validateNestedEach)b.flags.validateNestedEach=!0}F[z]={...b,type:Q}}}
@@ -0,0 +1,2 @@
1
+ import type { ClassifiedType } from './interfaces';
2
+ export declare function classifyTypeResult(result: unknown): ClassifiedType;
@@ -0,0 +1 @@
1
+ import{CollectionType as i}from"../metadata/index.js";export function classifyTypeResult(e){if(e===Map)return{collection:i.Map,isArray:!1,resolved:void 0};if(e===Set)return{collection:i.Set,isArray:!1,resolved:void 0};const r=Array.isArray(e);return{isArray:r,resolved:r?e[0]:e}}
@@ -0,0 +1,6 @@
1
+ import type { Result, ResultAsync } from '@zipbul/result';
2
+ import type { RuntimeOptions, BakerIssue } from '../common';
3
+ /** Compiled deserialize executor — Result pattern (or its async variant), produced by the builder. */
4
+ export type DeserializeExecutor<T> = (input: unknown, opts?: RuntimeOptions) => Result<T, BakerIssue[]> | ResultAsync<T, BakerIssue[]>;
5
+ /** Compiled validate-only executor — null on success, BakerIssue[] on failure (or its async variant). */
6
+ export type ValidateExecutor = (input: unknown, opts?: RuntimeOptions) => BakerIssue[] | null | Promise<BakerIssue[] | null>;
File without changes