๐Ÿš€ Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more โ†’
Sign In

@cerios/cerios-builder

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@cerios/cerios-builder - npm Package Compare versions

Comparing version
1.3.0
to
1.4.0
+67
-0
dist/index.d.mts

@@ -33,2 +33,22 @@ /**

/**
* Recursively makes all properties readonly for deep immutability.
* Handles arrays, objects, and primitive types.
*
* @template T - The type to make deeply readonly
*/
type DeepReadonly<T> = T extends (infer R)[] ? DeepReadonlyArray<R> : T extends (...args: any[]) => any ? T : T extends object ? DeepReadonlyObject<T> : T;
/**
* Helper type for deep readonly arrays
* @internal
*/
interface DeepReadonlyArray<T> extends ReadonlyArray<DeepReadonly<T>> {
}
/**
* Helper type for deep readonly objects
* @internal
*/
type DeepReadonlyObject<T> = {
readonly [P in keyof T]: DeepReadonly<T[P]>;
};
/**
* Cache the root key extraction to avoid repeated computation

@@ -222,4 +242,51 @@ * Handles optional properties by ensuring the key is valid for T

buildSafe(): T;
/**
* Builds and freezes the final object with both compile-time and runtime validation.
* The returned object is shallowly frozen - top-level properties cannot be modified,
* but nested objects remain mutable.
*
* - Compile-time: TypeScript enforces all required properties are set
* - Runtime: Validates all fields in the requiredTemplate and applies Object.freeze()
*
* @returns The frozen object of type Readonly<T>
* @throws {Error} If any required field is missing at runtime
*/
buildFrozen(this: this & CeriosBrand<T>): Readonly<T>;
/**
* Builds and deeply freezes the final object with both compile-time and runtime validation.
* The returned object is recursively frozen - all nested objects and arrays are also frozen.
*
* - Compile-time: TypeScript enforces all required properties are set
* - Runtime: Validates all fields in the requiredTemplate and recursively applies Object.freeze()
*
* @returns The deeply frozen object of type DeepReadonly<T>
* @throws {Error} If any required field is missing at runtime
*/
buildDeepFrozen(this: this & CeriosBrand<T>): DeepReadonly<T>;
/**
* Builds and seals the final object with both compile-time and runtime validation.
* The returned object is shallowly sealed - properties cannot be added or removed,
* but existing properties can still be modified. Nested objects remain unsealed.
*
* - Compile-time: TypeScript enforces all required properties are set
* - Runtime: Validates all fields in the requiredTemplate and applies Object.seal()
*
* @returns The sealed object of type T
* @throws {Error} If any required field is missing at runtime
*/
buildSealed(this: this & CeriosBrand<T>): T;
/**
* Builds and deeply seals the final object with both compile-time and runtime validation.
* The returned object is recursively sealed - properties cannot be added or removed at any level,
* but existing properties can still be modified.
*
* - Compile-time: TypeScript enforces all required properties are set
* - Runtime: Validates all fields in the requiredTemplate and recursively applies Object.seal()
*
* @returns The deeply sealed object of type T
* @throws {Error} If any required field is missing at runtime
*/
buildDeepSealed(this: this & CeriosBrand<T>): T;
}
export { type CeriosBrand, CeriosBuilder, type RequiredFieldsTemplate };

@@ -33,2 +33,22 @@ /**

/**
* Recursively makes all properties readonly for deep immutability.
* Handles arrays, objects, and primitive types.
*
* @template T - The type to make deeply readonly
*/
type DeepReadonly<T> = T extends (infer R)[] ? DeepReadonlyArray<R> : T extends (...args: any[]) => any ? T : T extends object ? DeepReadonlyObject<T> : T;
/**
* Helper type for deep readonly arrays
* @internal
*/
interface DeepReadonlyArray<T> extends ReadonlyArray<DeepReadonly<T>> {
}
/**
* Helper type for deep readonly objects
* @internal
*/
type DeepReadonlyObject<T> = {
readonly [P in keyof T]: DeepReadonly<T[P]>;
};
/**
* Cache the root key extraction to avoid repeated computation

@@ -222,4 +242,51 @@ * Handles optional properties by ensuring the key is valid for T

buildSafe(): T;
/**
* Builds and freezes the final object with both compile-time and runtime validation.
* The returned object is shallowly frozen - top-level properties cannot be modified,
* but nested objects remain mutable.
*
* - Compile-time: TypeScript enforces all required properties are set
* - Runtime: Validates all fields in the requiredTemplate and applies Object.freeze()
*
* @returns The frozen object of type Readonly<T>
* @throws {Error} If any required field is missing at runtime
*/
buildFrozen(this: this & CeriosBrand<T>): Readonly<T>;
/**
* Builds and deeply freezes the final object with both compile-time and runtime validation.
* The returned object is recursively frozen - all nested objects and arrays are also frozen.
*
* - Compile-time: TypeScript enforces all required properties are set
* - Runtime: Validates all fields in the requiredTemplate and recursively applies Object.freeze()
*
* @returns The deeply frozen object of type DeepReadonly<T>
* @throws {Error} If any required field is missing at runtime
*/
buildDeepFrozen(this: this & CeriosBrand<T>): DeepReadonly<T>;
/**
* Builds and seals the final object with both compile-time and runtime validation.
* The returned object is shallowly sealed - properties cannot be added or removed,
* but existing properties can still be modified. Nested objects remain unsealed.
*
* - Compile-time: TypeScript enforces all required properties are set
* - Runtime: Validates all fields in the requiredTemplate and applies Object.seal()
*
* @returns The sealed object of type T
* @throws {Error} If any required field is missing at runtime
*/
buildSealed(this: this & CeriosBrand<T>): T;
/**
* Builds and deeply seals the final object with both compile-time and runtime validation.
* The returned object is recursively sealed - properties cannot be added or removed at any level,
* but existing properties can still be modified.
*
* - Compile-time: TypeScript enforces all required properties are set
* - Runtime: Validates all fields in the requiredTemplate and recursively applies Object.seal()
*
* @returns The deeply sealed object of type T
* @throws {Error} If any required field is missing at runtime
*/
buildDeepSealed(this: this & CeriosBrand<T>): T;
}
export { type CeriosBrand, CeriosBuilder, type RequiredFieldsTemplate };

@@ -28,2 +28,20 @@ "use strict";

// src/cerios-builder.ts
function deepFreeze(obj) {
Object.getOwnPropertyNames(obj).forEach((prop) => {
const value = obj[prop];
if (value !== null && (typeof value === "object" || typeof value === "function")) {
deepFreeze(value);
}
});
return Object.freeze(obj);
}
function deepSeal(obj) {
Object.getOwnPropertyNames(obj).forEach((prop) => {
const value = obj[prop];
if (value !== null && (typeof value === "object" || typeof value === "function")) {
deepSeal(value);
}
});
return Object.seal(obj);
}
var CeriosBuilder = class {

@@ -297,2 +315,73 @@ /**

}
/**
* Builds and freezes the final object with both compile-time and runtime validation.
* The returned object is shallowly frozen - top-level properties cannot be modified,
* but nested objects remain mutable.
*
* - Compile-time: TypeScript enforces all required properties are set
* - Runtime: Validates all fields in the requiredTemplate and applies Object.freeze()
*
* @returns The frozen object of type Readonly<T>
* @throws {Error} If any required field is missing at runtime
*/
buildFrozen() {
const missing = this.validateRequiredFields();
if (missing.length > 0) {
throw new Error(`Missing required fields: ${missing.join(", ")}. Please set these fields before calling build.`);
}
return Object.freeze(this._actual);
}
/**
* Builds and deeply freezes the final object with both compile-time and runtime validation.
* The returned object is recursively frozen - all nested objects and arrays are also frozen.
*
* - Compile-time: TypeScript enforces all required properties are set
* - Runtime: Validates all fields in the requiredTemplate and recursively applies Object.freeze()
*
* @returns The deeply frozen object of type DeepReadonly<T>
* @throws {Error} If any required field is missing at runtime
*/
buildDeepFrozen() {
const missing = this.validateRequiredFields();
if (missing.length > 0) {
throw new Error(`Missing required fields: ${missing.join(", ")}. Please set these fields before calling build.`);
}
return deepFreeze(this._actual);
}
/**
* Builds and seals the final object with both compile-time and runtime validation.
* The returned object is shallowly sealed - properties cannot be added or removed,
* but existing properties can still be modified. Nested objects remain unsealed.
*
* - Compile-time: TypeScript enforces all required properties are set
* - Runtime: Validates all fields in the requiredTemplate and applies Object.seal()
*
* @returns The sealed object of type T
* @throws {Error} If any required field is missing at runtime
*/
buildSealed() {
const missing = this.validateRequiredFields();
if (missing.length > 0) {
throw new Error(`Missing required fields: ${missing.join(", ")}. Please set these fields before calling build.`);
}
return Object.seal(this._actual);
}
/**
* Builds and deeply seals the final object with both compile-time and runtime validation.
* The returned object is recursively sealed - properties cannot be added or removed at any level,
* but existing properties can still be modified.
*
* - Compile-time: TypeScript enforces all required properties are set
* - Runtime: Validates all fields in the requiredTemplate and recursively applies Object.seal()
*
* @returns The deeply sealed object of type T
* @throws {Error} If any required field is missing at runtime
*/
buildDeepSealed() {
const missing = this.validateRequiredFields();
if (missing.length > 0) {
throw new Error(`Missing required fields: ${missing.join(", ")}. Please set these fields before calling build.`);
}
return deepSeal(this._actual);
}
};

@@ -299,0 +388,0 @@ // Annotate the CommonJS export names for ESM import in node:

+1
-1

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/index.ts","../src/cerios-builder.ts"],"sourcesContent":["export { CeriosBrand, CeriosBuilder, RequiredFieldsTemplate } from \"./cerios-builder.js\";\n","/**\n * Unique symbol used internally to brand types and track which properties have been set in the builder's type.\n *\n * @internal\n */\ndeclare const __brand: unique symbol;\n\n/**\n * Type utility for branding builder types with information about which properties have been set.\n * This is used to enforce compile-time safety for required fields in the builder pattern.\n *\n * @template T - The type representing the set of properties that have been set\n * @internal\n */\nexport type CeriosBrand<T> = { [__brand]: T };\n\n/**\n * Helper type to represent a path through an object structure\n * Handles optional properties by unwrapping them with NonNullable\n */\ntype PathImpl<T, K extends keyof T = keyof T> = K extends string | number\n\t? NonNullable<T[K]> extends Record<string, any>\n\t\t? NonNullable<T[K]> extends Array<any>\n\t\t\t? K\n\t\t\t: K | `${K}.${PathImpl<NonNullable<T[K]>> & string}`\n\t\t: K\n\t: never;\n\nexport type Path<T> = PathImpl<T>;\n\n/**\n * Helper type to get the value at a specific path, handling optional properties\n */\ntype PathValue<T, P> = P extends keyof T\n\t? T[P]\n\t: P extends `${infer K}.${infer Rest}`\n\t\t? K extends keyof T\n\t\t\t? PathValue<NonNullable<T[K]>, Rest>\n\t\t\t: never\n\t\t: never;\n\n/**\n * Type-safe template for defining required fields using an array of paths.\n * Simply list the paths that are required.\n */\nexport type RequiredFieldsTemplate<T> = ReadonlyArray<Path<T>>;\n\n/**\n * Cache the root key extraction to avoid repeated computation\n * Handles optional properties by ensuring the key is valid for T\n * @internal\n */\ntype RootKey<P extends string, T = any> = P extends `${infer K}.${string}`\n\t? K extends keyof T\n\t\t? K\n\t\t: never\n\t: P extends keyof T\n\t\t? P\n\t\t: never;\n\n/**\n * Abstract base class for creating type-safe builders with automatic property setters and compile-time validation of required fields.\n *\n * This class is intended to be extended by concrete builder implementations for your own types.\n * It provides utility methods for setting properties and building the final object, ensuring that all required fields are set at compile time.\n *\n * Example usage:\n * ```typescript\n * interface MyType { foo: string; bar: number[]; }\n * class MyTypeBuilder extends CeriosBuilder<MyType> {\n * static requiredTemplate: RequiredFieldsTemplate<MyType> = ['foo'];\n * setFoo(value: string) { return this.setProperty('foo', value); }\n * addBar(value: number) { return this.addToArrayProperty('bar', value); }\n * }\n * // Usage:\n * const obj = new MyTypeBuilder({})\n * .setFoo('hello')\n * .addBar(42)\n * .buildSafe(); // Validates that 'foo' is set\n * ```\n *\n * @template T - The complete type being built\n */\nexport abstract class CeriosBuilder<T extends object> {\n\t/**\n\t * Template defining which fields are required for this builder.\n\t * Subclasses should override this to specify their required fields as an array of paths.\n\t * The template is type-safe - only valid paths from type T can be used.\n\t */\n\tstatic requiredTemplate?: ReadonlyArray<string>;\n\n\t/**\n\t * Instance-level required fields that can be populated dynamically.\n\t * This allows adding required fields at runtime via the setRequiredFields method.\n\t * @private\n\t */\n\tprivate _requiredFields: Set<string> = new Set();\n\n\t/**\n\t * Sets the required fields for this builder instance.\n\t * This allows you to dynamically define which fields are required.\n\t *\n\t * @param fields - Array of dot-notation paths to required fields\n\t * @returns The builder instance for chaining\n\t *\n\t * @example\n\t * ```typescript\n\t * const builder = new MyBuilder({})\n\t * .setRequiredFields(['path.to.field1', 'path.to.field2'])\n\t * .setField1('value1')\n\t * .setField2('value2')\n\t * .buildSafe();\n\t * ```\n\t */\n\tsetRequiredFields(fields: ReadonlyArray<Path<T>>): this {\n\t\tthis._requiredFields = new Set([...fields] as string[]);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the combined required fields from both the static template and instance-level fields.\n\t * @private\n\t */\n\tprivate getRequiredTemplate(): ReadonlyArray<string> {\n\t\tconst ctor = this.constructor as typeof CeriosBuilder;\n\t\tconst staticFields = ctor.requiredTemplate || [];\n\t\tconst instanceFields = Array.from(this._requiredFields);\n\n\t\t// Combine and deduplicate\n\t\treturn [...new Set([...staticFields, ...instanceFields])];\n\t}\n\n\t/**\n\t * Validates that all fields in the required template have been set.\n\t * @private\n\t */\n\tprivate validateRequiredFields(): string[] {\n\t\tconst requiredPaths = this.getRequiredTemplate();\n\t\tconst missing: string[] = [];\n\n\t\tfor (const path of requiredPaths) {\n\t\t\tconst keys = path.split(\".\");\n\t\t\tlet current: any = this._actual;\n\n\t\t\tfor (let i = 0; i < keys.length; i++) {\n\t\t\t\tconst key = keys[i];\n\t\t\t\tif (current === null || current === undefined || !(key in current)) {\n\t\t\t\t\tmissing.push(path);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcurrent = current[key];\n\t\t\t}\n\n\t\t\t// Check if the final value is null or undefined\n\t\t\tif (current === null || current === undefined) {\n\t\t\t\tif (!missing.includes(path)) {\n\t\t\t\t\tmissing.push(path);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn missing;\n\t}\n\n\t/**\n\t * Creates a new builder instance. Intended to be called by subclasses.\n\t *\n\t * @param _actual - The current partial state of the object being built\n\t * @param _requiredFields - Optional array of required field paths to preserve across instances\n\t * @protected\n\t */\n\tprotected constructor(\n\t\tprotected readonly _actual: Partial<T>,\n\t\t_requiredFields?: RequiredFieldsTemplate<T>\n\t) {\n\t\tif (_requiredFields) {\n\t\t\tthis._requiredFields = new Set([..._requiredFields] as string[]);\n\t\t}\n\t}\n\n\t/**\n\t * Sets a property value and returns a new builder instance with updated type state.\n\t * This method is intended to be wrapped by concrete builder methods in subclasses.\n\t *\n\t * @template K - The property key being set\n\t * @param key - The property key to set\n\t * @param value - The value to assign to the property\n\t * @returns A new builder instance with the property set and type state updated\n\t * @protected\n\t */\n\tprotected setProperty<K extends keyof T>(key: K, value: T[K]): this & CeriosBrand<Pick<T, K>> {\n\t\tconst BuilderClass = this.constructor as new (data: any, requiredFields?: RequiredFieldsTemplate<T>) => any;\n\t\treturn new BuilderClass(\n\t\t\t{\n\t\t\t\t...this._actual,\n\t\t\t\t[key]: value,\n\t\t\t},\n\t\t\tArray.from(this._requiredFields) as unknown as RequiredFieldsTemplate<T>\n\t\t) as this & CeriosBrand<Pick<T, K>>;\n\t}\n\n\t/**\n\t * Sets multiple property values at once and returns a new builder instance with updated type state.\n\t * @param props - An object with one or more properties to set.\n\t * @returns A new builder instance with the properties set and type state updated.\n\t * @protected\n\t */\n\tprotected setProperties<K extends keyof T>(props: Pick<T, K>): this & CeriosBrand<Pick<T, K>> {\n\t\tconst BuilderClass = this.constructor as new (data: any, requiredFields?: RequiredFieldsTemplate<T>) => any;\n\t\treturn new BuilderClass(\n\t\t\t{\n\t\t\t\t...this._actual,\n\t\t\t\t...props,\n\t\t\t},\n\t\t\tArray.from(this._requiredFields) as unknown as RequiredFieldsTemplate<T>\n\t\t) as this & CeriosBrand<Pick<T, K>>;\n\t}\n\n\t/**\n\t * Sets a deeply nested property value and returns a new builder instance with updated type state.\n\t * This method uses dot notation to set nested properties in a type-safe way.\n\t *\n\t * @template P - The property path (e.g., \"parent.child.grandchild\")\n\t * @param path - The dot-notation path to the property\n\t * @param value - The value to assign to the nested property\n\t * @returns A new builder instance with the nested property set\n\t * @protected\n\t *\n\t * @example\n\t * ```typescript\n\t * builder.setNestedProperty('Order.Details.CustomerId', 'value')\n\t * ```\n\t */\n\tprotected setNestedProperty<P extends Path<T>>(\n\t\tpath: P,\n\t\tvalue: PathValue<T, P>\n\t): this & CeriosBrand<Pick<T, RootKey<P & string, T> extends never ? keyof T : RootKey<P & string, T>>> {\n\t\tconst BuilderClass = this.constructor as new (data: any, requiredFields?: RequiredFieldsTemplate<T>) => any;\n\t\tconst keys = (path as string).split(\".\");\n\t\tconst newActual = this.deepClone(this._actual);\n\n\t\tlet current: any = newActual;\n\t\tfor (let i = 0; i < keys.length - 1; i++) {\n\t\t\tconst key = keys[i];\n\t\t\tif (!(key in current) || typeof current[key] !== \"object\" || current[key] === null) {\n\t\t\t\tcurrent[key] = {};\n\t\t\t} else {\n\t\t\t\tcurrent[key] = this.deepClone(current[key]);\n\t\t\t}\n\t\t\tcurrent = current[key];\n\t\t}\n\n\t\tcurrent[keys[keys.length - 1]] = value;\n\n\t\treturn new BuilderClass(\n\t\t\tnewActual,\n\t\t\tArray.from(this._requiredFields) as unknown as RequiredFieldsTemplate<T>\n\t\t) as this & CeriosBrand<Pick<T, RootKey<P & string, T> extends never ? keyof T : RootKey<P & string, T>>>;\n\t}\n\n\t/**\n\t * Deep clone helper for nested objects\n\t * @private\n\t */\n\tprivate deepClone<V>(obj: V): V {\n\t\tif (obj === null || typeof obj !== \"object\") {\n\t\t\treturn obj;\n\t\t}\n\t\tif (Array.isArray(obj)) {\n\t\t\treturn obj.map(item => this.deepClone(item)) as any;\n\t\t}\n\t\tconst cloned: any = {};\n\t\tconst hasOwn = Object.prototype.hasOwnProperty;\n\t\tfor (const key in obj) {\n\t\t\tif (hasOwn.call(obj, key)) {\n\t\t\t\tcloned[key] = this.deepClone(obj[key]);\n\t\t\t}\n\t\t}\n\t\treturn cloned;\n\t}\n\n\t/**\n\t * Adds a value to an array property and returns a new builder instance with updated type state.\n\t * This method is intended to be wrapped by concrete builder methods in subclasses for array properties.\n\t *\n\t * @template K - The property key (must be an array property)\n\t * @template V - The type of the array element\n\t * @param key - The array property key to add to\n\t * @param value - The value to add to the array\n\t * @returns A new builder instance with the array property updated and type state updated\n\t * @protected\n\t */\n\tprotected addToArrayProperty<\n\t\tK extends { [P in keyof T]: NonNullable<T[P]> extends Array<any> ? P : never }[keyof T],\n\t\tV extends T[K] extends Array<infer U> ? U : T[K] extends Array<infer U> | undefined ? U : never,\n\t>(key: K, value: V): this & CeriosBrand<Pick<T, K>> {\n\t\tconst BuilderClass = this.constructor as new (data: any, requiredFields?: RequiredFieldsTemplate<T>) => any;\n\t\tconst currentArray = (this._actual[key] as Array<V> | undefined) ?? [];\n\t\treturn new BuilderClass(\n\t\t\t{\n\t\t\t\t...this._actual,\n\t\t\t\t[key]: [...currentArray, value],\n\t\t\t},\n\t\t\tArray.from(this._requiredFields) as unknown as RequiredFieldsTemplate<T>\n\t\t) as this & CeriosBrand<Pick<T, K>>;\n\t}\n\n\t/**\n\t * Builds the final object with both compile-time and runtime validation.\n\t * This is the recommended and safest way to build objects.\n\t *\n\t * - Compile-time: TypeScript enforces all required properties are set\n\t * - Runtime: Validates all fields in the requiredTemplate\n\t *\n\t * @returns The fully built object of type T\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuild(this: this & CeriosBrand<T>): T {\n\t\tconst missing = this.validateRequiredFields();\n\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(`Missing required fields: ${missing.join(\", \")}. Please set these fields before calling build.`);\n\t\t}\n\n\t\treturn this._actual as T;\n\t}\n\n\t/**\n\t * Builds the final object with only compile-time validation, skipping runtime checks.\n\t * Use this when you want TypeScript safety but need to skip runtime validation for performance.\n\t *\n\t * - Compile-time: TypeScript enforces all required properties are set\n\t * - Runtime: No validation\n\t *\n\t * @returns The fully built object of type T\n\t */\n\tbuildWithoutRuntimeValidation(this: this & CeriosBrand<T>): T {\n\t\treturn this._actual as T;\n\t}\n\n\t/**\n\t * Builds the final object with only runtime validation, skipping compile-time checks.\n\t * Use this when building from external data where compile-time checks aren't possible.\n\t *\n\t * - Compile-time: No TypeScript enforcement\n\t * - Runtime: Validates all fields in the requiredTemplate\n\t *\n\t * @returns The fully built object of type T\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuildWithoutCompileTimeValidation(): T {\n\t\tconst missing = this.validateRequiredFields();\n\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(`Missing required fields: ${missing.join(\", \")}. Please set these fields before calling build.`);\n\t\t}\n\n\t\treturn this._actual as T;\n\t}\n\n\t/**\n\t * Builds the final object without any validation (neither compile-time nor runtime).\n\t * Use this only when you're certain the object is valid and need maximum performance.\n\t *\n\t * - Compile-time: No TypeScript enforcement\n\t * - Runtime: No validation\n\t *\n\t * @returns The object of type T (may be incomplete)\n\t */\n\tbuildUnsafe(): T {\n\t\treturn this._actual as T;\n\t}\n\n\t/**\n\t * Builds a partial object, which may not have all required fields set.\n\t * This is useful for scenarios where you want to inspect or validate the current state before finalizing.\n\t *\n\t * @returns The partially built object\n\t */\n\tbuildPartial(): Partial<T> {\n\t\treturn this._actual as Partial<T>;\n\t}\n\n\t/**\n\t * @deprecated Use build() instead. buildSafe() is now an alias for build().\n\t * Builds the final object with runtime validation using the requiredTemplate.\n\t * This method validates that all fields in the requiredTemplate array are present.\n\t *\n\t * @returns The fully built object of type T\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuildSafe(): T {\n\t\treturn this.buildWithoutCompileTimeValidation();\n\t}\n}\n"],"mappings":"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","names":[]}
{"version":3,"sources":["../src/index.ts","../src/cerios-builder.ts"],"sourcesContent":["export { CeriosBrand, CeriosBuilder, RequiredFieldsTemplate } from \"./cerios-builder.js\";\n","/**\n * Unique symbol used internally to brand types and track which properties have been set in the builder's type.\n *\n * @internal\n */\ndeclare const __brand: unique symbol;\n\n/**\n * Type utility for branding builder types with information about which properties have been set.\n * This is used to enforce compile-time safety for required fields in the builder pattern.\n *\n * @template T - The type representing the set of properties that have been set\n * @internal\n */\nexport type CeriosBrand<T> = { [__brand]: T };\n\n/**\n * Helper type to represent a path through an object structure\n * Handles optional properties by unwrapping them with NonNullable\n */\ntype PathImpl<T, K extends keyof T = keyof T> = K extends string | number\n\t? NonNullable<T[K]> extends Record<string, any>\n\t\t? NonNullable<T[K]> extends Array<any>\n\t\t\t? K\n\t\t\t: K | `${K}.${PathImpl<NonNullable<T[K]>> & string}`\n\t\t: K\n\t: never;\n\nexport type Path<T> = PathImpl<T>;\n\n/**\n * Helper type to get the value at a specific path, handling optional properties\n */\ntype PathValue<T, P> = P extends keyof T\n\t? T[P]\n\t: P extends `${infer K}.${infer Rest}`\n\t\t? K extends keyof T\n\t\t\t? PathValue<NonNullable<T[K]>, Rest>\n\t\t\t: never\n\t\t: never;\n\n/**\n * Type-safe template for defining required fields using an array of paths.\n * Simply list the paths that are required.\n */\nexport type RequiredFieldsTemplate<T> = ReadonlyArray<Path<T>>;\n\n/**\n * Recursively makes all properties readonly for deep immutability.\n * Handles arrays, objects, and primitive types.\n *\n * @template T - The type to make deeply readonly\n */\nexport type DeepReadonly<T> = T extends (infer R)[]\n\t? DeepReadonlyArray<R>\n\t: T extends (...args: any[]) => any\n\t\t? T\n\t\t: T extends object\n\t\t\t? DeepReadonlyObject<T>\n\t\t\t: T;\n\n/**\n * Helper type for deep readonly arrays\n * @internal\n */\ninterface DeepReadonlyArray<T> extends ReadonlyArray<DeepReadonly<T>> {}\n\n/**\n * Helper type for deep readonly objects\n * @internal\n */\ntype DeepReadonlyObject<T> = {\n\treadonly [P in keyof T]: DeepReadonly<T[P]>;\n};\n\n/**\n * Cache the root key extraction to avoid repeated computation\n * Handles optional properties by ensuring the key is valid for T\n * @internal\n */\ntype RootKey<P extends string, T = any> = P extends `${infer K}.${string}`\n\t? K extends keyof T\n\t\t? K\n\t\t: never\n\t: P extends keyof T\n\t\t? P\n\t\t: never;\n\n/**\n * Recursively freezes an object and all its nested properties.\n * @param obj - The object to freeze\n * @returns The frozen object\n * @internal\n */\nfunction deepFreeze<T>(obj: T): T {\n\t// Retrieve the property names defined on obj\n\tObject.getOwnPropertyNames(obj).forEach(prop => {\n\t\tconst value = (obj as any)[prop];\n\n\t\t// Freeze properties before freezing self\n\t\tif (value !== null && (typeof value === \"object\" || typeof value === \"function\")) {\n\t\t\tdeepFreeze(value);\n\t\t}\n\t});\n\n\treturn Object.freeze(obj);\n}\n\n/**\n * Recursively seals an object and all its nested properties.\n * @param obj - The object to seal\n * @returns The sealed object\n * @internal\n */\nfunction deepSeal<T>(obj: T): T {\n\t// Retrieve the property names defined on obj\n\tObject.getOwnPropertyNames(obj).forEach(prop => {\n\t\tconst value = (obj as any)[prop];\n\n\t\t// Seal properties before sealing self\n\t\tif (value !== null && (typeof value === \"object\" || typeof value === \"function\")) {\n\t\t\tdeepSeal(value);\n\t\t}\n\t});\n\n\treturn Object.seal(obj);\n}\n\n/**\n * Abstract base class for creating type-safe builders with automatic property setters and compile-time validation of required fields.\n *\n * This class is intended to be extended by concrete builder implementations for your own types.\n * It provides utility methods for setting properties and building the final object, ensuring that all required fields are set at compile time.\n *\n * Example usage:\n * ```typescript\n * interface MyType { foo: string; bar: number[]; }\n * class MyTypeBuilder extends CeriosBuilder<MyType> {\n * static requiredTemplate: RequiredFieldsTemplate<MyType> = ['foo'];\n * setFoo(value: string) { return this.setProperty('foo', value); }\n * addBar(value: number) { return this.addToArrayProperty('bar', value); }\n * }\n * // Usage:\n * const obj = new MyTypeBuilder({})\n * .setFoo('hello')\n * .addBar(42)\n * .buildSafe(); // Validates that 'foo' is set\n * ```\n *\n * @template T - The complete type being built\n */\nexport abstract class CeriosBuilder<T extends object> {\n\t/**\n\t * Template defining which fields are required for this builder.\n\t * Subclasses should override this to specify their required fields as an array of paths.\n\t * The template is type-safe - only valid paths from type T can be used.\n\t */\n\tstatic requiredTemplate?: ReadonlyArray<string>;\n\n\t/**\n\t * Instance-level required fields that can be populated dynamically.\n\t * This allows adding required fields at runtime via the setRequiredFields method.\n\t * @private\n\t */\n\tprivate _requiredFields: Set<string> = new Set();\n\n\t/**\n\t * Sets the required fields for this builder instance.\n\t * This allows you to dynamically define which fields are required.\n\t *\n\t * @param fields - Array of dot-notation paths to required fields\n\t * @returns The builder instance for chaining\n\t *\n\t * @example\n\t * ```typescript\n\t * const builder = new MyBuilder({})\n\t * .setRequiredFields(['path.to.field1', 'path.to.field2'])\n\t * .setField1('value1')\n\t * .setField2('value2')\n\t * .buildSafe();\n\t * ```\n\t */\n\tsetRequiredFields(fields: ReadonlyArray<Path<T>>): this {\n\t\tthis._requiredFields = new Set([...fields] as string[]);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the combined required fields from both the static template and instance-level fields.\n\t * @private\n\t */\n\tprivate getRequiredTemplate(): ReadonlyArray<string> {\n\t\tconst ctor = this.constructor as typeof CeriosBuilder;\n\t\tconst staticFields = ctor.requiredTemplate || [];\n\t\tconst instanceFields = Array.from(this._requiredFields);\n\n\t\t// Combine and deduplicate\n\t\treturn [...new Set([...staticFields, ...instanceFields])];\n\t}\n\n\t/**\n\t * Validates that all fields in the required template have been set.\n\t * @private\n\t */\n\tprivate validateRequiredFields(): string[] {\n\t\tconst requiredPaths = this.getRequiredTemplate();\n\t\tconst missing: string[] = [];\n\n\t\tfor (const path of requiredPaths) {\n\t\t\tconst keys = path.split(\".\");\n\t\t\tlet current: any = this._actual;\n\n\t\t\tfor (let i = 0; i < keys.length; i++) {\n\t\t\t\tconst key = keys[i];\n\t\t\t\tif (current === null || current === undefined || !(key in current)) {\n\t\t\t\t\tmissing.push(path);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcurrent = current[key];\n\t\t\t}\n\n\t\t\t// Check if the final value is null or undefined\n\t\t\tif (current === null || current === undefined) {\n\t\t\t\tif (!missing.includes(path)) {\n\t\t\t\t\tmissing.push(path);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn missing;\n\t}\n\n\t/**\n\t * Creates a new builder instance. Intended to be called by subclasses.\n\t *\n\t * @param _actual - The current partial state of the object being built\n\t * @param _requiredFields - Optional array of required field paths to preserve across instances\n\t * @protected\n\t */\n\tprotected constructor(\n\t\tprotected readonly _actual: Partial<T>,\n\t\t_requiredFields?: RequiredFieldsTemplate<T>\n\t) {\n\t\tif (_requiredFields) {\n\t\t\tthis._requiredFields = new Set([..._requiredFields] as string[]);\n\t\t}\n\t}\n\n\t/**\n\t * Sets a property value and returns a new builder instance with updated type state.\n\t * This method is intended to be wrapped by concrete builder methods in subclasses.\n\t *\n\t * @template K - The property key being set\n\t * @param key - The property key to set\n\t * @param value - The value to assign to the property\n\t * @returns A new builder instance with the property set and type state updated\n\t * @protected\n\t */\n\tprotected setProperty<K extends keyof T>(key: K, value: T[K]): this & CeriosBrand<Pick<T, K>> {\n\t\tconst BuilderClass = this.constructor as new (data: any, requiredFields?: RequiredFieldsTemplate<T>) => any;\n\t\treturn new BuilderClass(\n\t\t\t{\n\t\t\t\t...this._actual,\n\t\t\t\t[key]: value,\n\t\t\t},\n\t\t\tArray.from(this._requiredFields) as unknown as RequiredFieldsTemplate<T>\n\t\t) as this & CeriosBrand<Pick<T, K>>;\n\t}\n\n\t/**\n\t * Sets multiple property values at once and returns a new builder instance with updated type state.\n\t * @param props - An object with one or more properties to set.\n\t * @returns A new builder instance with the properties set and type state updated.\n\t * @protected\n\t */\n\tprotected setProperties<K extends keyof T>(props: Pick<T, K>): this & CeriosBrand<Pick<T, K>> {\n\t\tconst BuilderClass = this.constructor as new (data: any, requiredFields?: RequiredFieldsTemplate<T>) => any;\n\t\treturn new BuilderClass(\n\t\t\t{\n\t\t\t\t...this._actual,\n\t\t\t\t...props,\n\t\t\t},\n\t\t\tArray.from(this._requiredFields) as unknown as RequiredFieldsTemplate<T>\n\t\t) as this & CeriosBrand<Pick<T, K>>;\n\t}\n\n\t/**\n\t * Sets a deeply nested property value and returns a new builder instance with updated type state.\n\t * This method uses dot notation to set nested properties in a type-safe way.\n\t *\n\t * @template P - The property path (e.g., \"parent.child.grandchild\")\n\t * @param path - The dot-notation path to the property\n\t * @param value - The value to assign to the nested property\n\t * @returns A new builder instance with the nested property set\n\t * @protected\n\t *\n\t * @example\n\t * ```typescript\n\t * builder.setNestedProperty('Order.Details.CustomerId', 'value')\n\t * ```\n\t */\n\tprotected setNestedProperty<P extends Path<T>>(\n\t\tpath: P,\n\t\tvalue: PathValue<T, P>\n\t): this & CeriosBrand<Pick<T, RootKey<P & string, T> extends never ? keyof T : RootKey<P & string, T>>> {\n\t\tconst BuilderClass = this.constructor as new (data: any, requiredFields?: RequiredFieldsTemplate<T>) => any;\n\t\tconst keys = (path as string).split(\".\");\n\t\tconst newActual = this.deepClone(this._actual);\n\n\t\tlet current: any = newActual;\n\t\tfor (let i = 0; i < keys.length - 1; i++) {\n\t\t\tconst key = keys[i];\n\t\t\tif (!(key in current) || typeof current[key] !== \"object\" || current[key] === null) {\n\t\t\t\tcurrent[key] = {};\n\t\t\t} else {\n\t\t\t\tcurrent[key] = this.deepClone(current[key]);\n\t\t\t}\n\t\t\tcurrent = current[key];\n\t\t}\n\n\t\tcurrent[keys[keys.length - 1]] = value;\n\n\t\treturn new BuilderClass(\n\t\t\tnewActual,\n\t\t\tArray.from(this._requiredFields) as unknown as RequiredFieldsTemplate<T>\n\t\t) as this & CeriosBrand<Pick<T, RootKey<P & string, T> extends never ? keyof T : RootKey<P & string, T>>>;\n\t}\n\n\t/**\n\t * Deep clone helper for nested objects\n\t * @private\n\t */\n\tprivate deepClone<V>(obj: V): V {\n\t\tif (obj === null || typeof obj !== \"object\") {\n\t\t\treturn obj;\n\t\t}\n\t\tif (Array.isArray(obj)) {\n\t\t\treturn obj.map(item => this.deepClone(item)) as any;\n\t\t}\n\t\tconst cloned: any = {};\n\t\tconst hasOwn = Object.prototype.hasOwnProperty;\n\t\tfor (const key in obj) {\n\t\t\tif (hasOwn.call(obj, key)) {\n\t\t\t\tcloned[key] = this.deepClone(obj[key]);\n\t\t\t}\n\t\t}\n\t\treturn cloned;\n\t}\n\n\t/**\n\t * Adds a value to an array property and returns a new builder instance with updated type state.\n\t * This method is intended to be wrapped by concrete builder methods in subclasses for array properties.\n\t *\n\t * @template K - The property key (must be an array property)\n\t * @template V - The type of the array element\n\t * @param key - The array property key to add to\n\t * @param value - The value to add to the array\n\t * @returns A new builder instance with the array property updated and type state updated\n\t * @protected\n\t */\n\tprotected addToArrayProperty<\n\t\tK extends { [P in keyof T]: NonNullable<T[P]> extends Array<any> ? P : never }[keyof T],\n\t\tV extends T[K] extends Array<infer U> ? U : T[K] extends Array<infer U> | undefined ? U : never,\n\t>(key: K, value: V): this & CeriosBrand<Pick<T, K>> {\n\t\tconst BuilderClass = this.constructor as new (data: any, requiredFields?: RequiredFieldsTemplate<T>) => any;\n\t\tconst currentArray = (this._actual[key] as Array<V> | undefined) ?? [];\n\t\treturn new BuilderClass(\n\t\t\t{\n\t\t\t\t...this._actual,\n\t\t\t\t[key]: [...currentArray, value],\n\t\t\t},\n\t\t\tArray.from(this._requiredFields) as unknown as RequiredFieldsTemplate<T>\n\t\t) as this & CeriosBrand<Pick<T, K>>;\n\t}\n\n\t/**\n\t * Builds the final object with both compile-time and runtime validation.\n\t * This is the recommended and safest way to build objects.\n\t *\n\t * - Compile-time: TypeScript enforces all required properties are set\n\t * - Runtime: Validates all fields in the requiredTemplate\n\t *\n\t * @returns The fully built object of type T\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuild(this: this & CeriosBrand<T>): T {\n\t\tconst missing = this.validateRequiredFields();\n\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(`Missing required fields: ${missing.join(\", \")}. Please set these fields before calling build.`);\n\t\t}\n\n\t\treturn this._actual as T;\n\t}\n\n\t/**\n\t * Builds the final object with only compile-time validation, skipping runtime checks.\n\t * Use this when you want TypeScript safety but need to skip runtime validation for performance.\n\t *\n\t * - Compile-time: TypeScript enforces all required properties are set\n\t * - Runtime: No validation\n\t *\n\t * @returns The fully built object of type T\n\t */\n\tbuildWithoutRuntimeValidation(this: this & CeriosBrand<T>): T {\n\t\treturn this._actual as T;\n\t}\n\n\t/**\n\t * Builds the final object with only runtime validation, skipping compile-time checks.\n\t * Use this when building from external data where compile-time checks aren't possible.\n\t *\n\t * - Compile-time: No TypeScript enforcement\n\t * - Runtime: Validates all fields in the requiredTemplate\n\t *\n\t * @returns The fully built object of type T\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuildWithoutCompileTimeValidation(): T {\n\t\tconst missing = this.validateRequiredFields();\n\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(`Missing required fields: ${missing.join(\", \")}. Please set these fields before calling build.`);\n\t\t}\n\n\t\treturn this._actual as T;\n\t}\n\n\t/**\n\t * Builds the final object without any validation (neither compile-time nor runtime).\n\t * Use this only when you're certain the object is valid and need maximum performance.\n\t *\n\t * - Compile-time: No TypeScript enforcement\n\t * - Runtime: No validation\n\t *\n\t * @returns The object of type T (may be incomplete)\n\t */\n\tbuildUnsafe(): T {\n\t\treturn this._actual as T;\n\t}\n\n\t/**\n\t * Builds a partial object, which may not have all required fields set.\n\t * This is useful for scenarios where you want to inspect or validate the current state before finalizing.\n\t *\n\t * @returns The partially built object\n\t */\n\tbuildPartial(): Partial<T> {\n\t\treturn this._actual as Partial<T>;\n\t}\n\n\t/**\n\t * @deprecated Use build() instead. buildSafe() is now an alias for build().\n\t * Builds the final object with runtime validation using the requiredTemplate.\n\t * This method validates that all fields in the requiredTemplate array are present.\n\t *\n\t * @returns The fully built object of type T\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuildSafe(): T {\n\t\treturn this.buildWithoutCompileTimeValidation();\n\t}\n\n\t/**\n\t * Builds and freezes the final object with both compile-time and runtime validation.\n\t * The returned object is shallowly frozen - top-level properties cannot be modified,\n\t * but nested objects remain mutable.\n\t *\n\t * - Compile-time: TypeScript enforces all required properties are set\n\t * - Runtime: Validates all fields in the requiredTemplate and applies Object.freeze()\n\t *\n\t * @returns The frozen object of type Readonly<T>\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuildFrozen(this: this & CeriosBrand<T>): Readonly<T> {\n\t\tconst missing = this.validateRequiredFields();\n\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(`Missing required fields: ${missing.join(\", \")}. Please set these fields before calling build.`);\n\t\t}\n\n\t\treturn Object.freeze(this._actual as T);\n\t}\n\n\t/**\n\t * Builds and deeply freezes the final object with both compile-time and runtime validation.\n\t * The returned object is recursively frozen - all nested objects and arrays are also frozen.\n\t *\n\t * - Compile-time: TypeScript enforces all required properties are set\n\t * - Runtime: Validates all fields in the requiredTemplate and recursively applies Object.freeze()\n\t *\n\t * @returns The deeply frozen object of type DeepReadonly<T>\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuildDeepFrozen(this: this & CeriosBrand<T>): DeepReadonly<T> {\n\t\tconst missing = this.validateRequiredFields();\n\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(`Missing required fields: ${missing.join(\", \")}. Please set these fields before calling build.`);\n\t\t}\n\n\t\treturn deepFreeze(this._actual as T) as DeepReadonly<T>;\n\t}\n\n\t/**\n\t * Builds and seals the final object with both compile-time and runtime validation.\n\t * The returned object is shallowly sealed - properties cannot be added or removed,\n\t * but existing properties can still be modified. Nested objects remain unsealed.\n\t *\n\t * - Compile-time: TypeScript enforces all required properties are set\n\t * - Runtime: Validates all fields in the requiredTemplate and applies Object.seal()\n\t *\n\t * @returns The sealed object of type T\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuildSealed(this: this & CeriosBrand<T>): T {\n\t\tconst missing = this.validateRequiredFields();\n\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(`Missing required fields: ${missing.join(\", \")}. Please set these fields before calling build.`);\n\t\t}\n\n\t\treturn Object.seal(this._actual as T);\n\t}\n\n\t/**\n\t * Builds and deeply seals the final object with both compile-time and runtime validation.\n\t * The returned object is recursively sealed - properties cannot be added or removed at any level,\n\t * but existing properties can still be modified.\n\t *\n\t * - Compile-time: TypeScript enforces all required properties are set\n\t * - Runtime: Validates all fields in the requiredTemplate and recursively applies Object.seal()\n\t *\n\t * @returns The deeply sealed object of type T\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuildDeepSealed(this: this & CeriosBrand<T>): T {\n\t\tconst missing = this.validateRequiredFields();\n\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(`Missing required fields: ${missing.join(\", \")}. Please set these fields before calling build.`);\n\t\t}\n\n\t\treturn deepSeal(this._actual as T);\n\t}\n}\n"],"mappings":"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","names":[]}
// src/cerios-builder.ts
function deepFreeze(obj) {
Object.getOwnPropertyNames(obj).forEach((prop) => {
const value = obj[prop];
if (value !== null && (typeof value === "object" || typeof value === "function")) {
deepFreeze(value);
}
});
return Object.freeze(obj);
}
function deepSeal(obj) {
Object.getOwnPropertyNames(obj).forEach((prop) => {
const value = obj[prop];
if (value !== null && (typeof value === "object" || typeof value === "function")) {
deepSeal(value);
}
});
return Object.seal(obj);
}
var CeriosBuilder = class {

@@ -270,2 +288,73 @@ /**

}
/**
* Builds and freezes the final object with both compile-time and runtime validation.
* The returned object is shallowly frozen - top-level properties cannot be modified,
* but nested objects remain mutable.
*
* - Compile-time: TypeScript enforces all required properties are set
* - Runtime: Validates all fields in the requiredTemplate and applies Object.freeze()
*
* @returns The frozen object of type Readonly<T>
* @throws {Error} If any required field is missing at runtime
*/
buildFrozen() {
const missing = this.validateRequiredFields();
if (missing.length > 0) {
throw new Error(`Missing required fields: ${missing.join(", ")}. Please set these fields before calling build.`);
}
return Object.freeze(this._actual);
}
/**
* Builds and deeply freezes the final object with both compile-time and runtime validation.
* The returned object is recursively frozen - all nested objects and arrays are also frozen.
*
* - Compile-time: TypeScript enforces all required properties are set
* - Runtime: Validates all fields in the requiredTemplate and recursively applies Object.freeze()
*
* @returns The deeply frozen object of type DeepReadonly<T>
* @throws {Error} If any required field is missing at runtime
*/
buildDeepFrozen() {
const missing = this.validateRequiredFields();
if (missing.length > 0) {
throw new Error(`Missing required fields: ${missing.join(", ")}. Please set these fields before calling build.`);
}
return deepFreeze(this._actual);
}
/**
* Builds and seals the final object with both compile-time and runtime validation.
* The returned object is shallowly sealed - properties cannot be added or removed,
* but existing properties can still be modified. Nested objects remain unsealed.
*
* - Compile-time: TypeScript enforces all required properties are set
* - Runtime: Validates all fields in the requiredTemplate and applies Object.seal()
*
* @returns The sealed object of type T
* @throws {Error} If any required field is missing at runtime
*/
buildSealed() {
const missing = this.validateRequiredFields();
if (missing.length > 0) {
throw new Error(`Missing required fields: ${missing.join(", ")}. Please set these fields before calling build.`);
}
return Object.seal(this._actual);
}
/**
* Builds and deeply seals the final object with both compile-time and runtime validation.
* The returned object is recursively sealed - properties cannot be added or removed at any level,
* but existing properties can still be modified.
*
* - Compile-time: TypeScript enforces all required properties are set
* - Runtime: Validates all fields in the requiredTemplate and recursively applies Object.seal()
*
* @returns The deeply sealed object of type T
* @throws {Error} If any required field is missing at runtime
*/
buildDeepSealed() {
const missing = this.validateRequiredFields();
if (missing.length > 0) {
throw new Error(`Missing required fields: ${missing.join(", ")}. Please set these fields before calling build.`);
}
return deepSeal(this._actual);
}
};

@@ -272,0 +361,0 @@ export {

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/cerios-builder.ts"],"sourcesContent":["/**\n * Unique symbol used internally to brand types and track which properties have been set in the builder's type.\n *\n * @internal\n */\ndeclare const __brand: unique symbol;\n\n/**\n * Type utility for branding builder types with information about which properties have been set.\n * This is used to enforce compile-time safety for required fields in the builder pattern.\n *\n * @template T - The type representing the set of properties that have been set\n * @internal\n */\nexport type CeriosBrand<T> = { [__brand]: T };\n\n/**\n * Helper type to represent a path through an object structure\n * Handles optional properties by unwrapping them with NonNullable\n */\ntype PathImpl<T, K extends keyof T = keyof T> = K extends string | number\n\t? NonNullable<T[K]> extends Record<string, any>\n\t\t? NonNullable<T[K]> extends Array<any>\n\t\t\t? K\n\t\t\t: K | `${K}.${PathImpl<NonNullable<T[K]>> & string}`\n\t\t: K\n\t: never;\n\nexport type Path<T> = PathImpl<T>;\n\n/**\n * Helper type to get the value at a specific path, handling optional properties\n */\ntype PathValue<T, P> = P extends keyof T\n\t? T[P]\n\t: P extends `${infer K}.${infer Rest}`\n\t\t? K extends keyof T\n\t\t\t? PathValue<NonNullable<T[K]>, Rest>\n\t\t\t: never\n\t\t: never;\n\n/**\n * Type-safe template for defining required fields using an array of paths.\n * Simply list the paths that are required.\n */\nexport type RequiredFieldsTemplate<T> = ReadonlyArray<Path<T>>;\n\n/**\n * Cache the root key extraction to avoid repeated computation\n * Handles optional properties by ensuring the key is valid for T\n * @internal\n */\ntype RootKey<P extends string, T = any> = P extends `${infer K}.${string}`\n\t? K extends keyof T\n\t\t? K\n\t\t: never\n\t: P extends keyof T\n\t\t? P\n\t\t: never;\n\n/**\n * Abstract base class for creating type-safe builders with automatic property setters and compile-time validation of required fields.\n *\n * This class is intended to be extended by concrete builder implementations for your own types.\n * It provides utility methods for setting properties and building the final object, ensuring that all required fields are set at compile time.\n *\n * Example usage:\n * ```typescript\n * interface MyType { foo: string; bar: number[]; }\n * class MyTypeBuilder extends CeriosBuilder<MyType> {\n * static requiredTemplate: RequiredFieldsTemplate<MyType> = ['foo'];\n * setFoo(value: string) { return this.setProperty('foo', value); }\n * addBar(value: number) { return this.addToArrayProperty('bar', value); }\n * }\n * // Usage:\n * const obj = new MyTypeBuilder({})\n * .setFoo('hello')\n * .addBar(42)\n * .buildSafe(); // Validates that 'foo' is set\n * ```\n *\n * @template T - The complete type being built\n */\nexport abstract class CeriosBuilder<T extends object> {\n\t/**\n\t * Template defining which fields are required for this builder.\n\t * Subclasses should override this to specify their required fields as an array of paths.\n\t * The template is type-safe - only valid paths from type T can be used.\n\t */\n\tstatic requiredTemplate?: ReadonlyArray<string>;\n\n\t/**\n\t * Instance-level required fields that can be populated dynamically.\n\t * This allows adding required fields at runtime via the setRequiredFields method.\n\t * @private\n\t */\n\tprivate _requiredFields: Set<string> = new Set();\n\n\t/**\n\t * Sets the required fields for this builder instance.\n\t * This allows you to dynamically define which fields are required.\n\t *\n\t * @param fields - Array of dot-notation paths to required fields\n\t * @returns The builder instance for chaining\n\t *\n\t * @example\n\t * ```typescript\n\t * const builder = new MyBuilder({})\n\t * .setRequiredFields(['path.to.field1', 'path.to.field2'])\n\t * .setField1('value1')\n\t * .setField2('value2')\n\t * .buildSafe();\n\t * ```\n\t */\n\tsetRequiredFields(fields: ReadonlyArray<Path<T>>): this {\n\t\tthis._requiredFields = new Set([...fields] as string[]);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the combined required fields from both the static template and instance-level fields.\n\t * @private\n\t */\n\tprivate getRequiredTemplate(): ReadonlyArray<string> {\n\t\tconst ctor = this.constructor as typeof CeriosBuilder;\n\t\tconst staticFields = ctor.requiredTemplate || [];\n\t\tconst instanceFields = Array.from(this._requiredFields);\n\n\t\t// Combine and deduplicate\n\t\treturn [...new Set([...staticFields, ...instanceFields])];\n\t}\n\n\t/**\n\t * Validates that all fields in the required template have been set.\n\t * @private\n\t */\n\tprivate validateRequiredFields(): string[] {\n\t\tconst requiredPaths = this.getRequiredTemplate();\n\t\tconst missing: string[] = [];\n\n\t\tfor (const path of requiredPaths) {\n\t\t\tconst keys = path.split(\".\");\n\t\t\tlet current: any = this._actual;\n\n\t\t\tfor (let i = 0; i < keys.length; i++) {\n\t\t\t\tconst key = keys[i];\n\t\t\t\tif (current === null || current === undefined || !(key in current)) {\n\t\t\t\t\tmissing.push(path);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcurrent = current[key];\n\t\t\t}\n\n\t\t\t// Check if the final value is null or undefined\n\t\t\tif (current === null || current === undefined) {\n\t\t\t\tif (!missing.includes(path)) {\n\t\t\t\t\tmissing.push(path);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn missing;\n\t}\n\n\t/**\n\t * Creates a new builder instance. Intended to be called by subclasses.\n\t *\n\t * @param _actual - The current partial state of the object being built\n\t * @param _requiredFields - Optional array of required field paths to preserve across instances\n\t * @protected\n\t */\n\tprotected constructor(\n\t\tprotected readonly _actual: Partial<T>,\n\t\t_requiredFields?: RequiredFieldsTemplate<T>\n\t) {\n\t\tif (_requiredFields) {\n\t\t\tthis._requiredFields = new Set([..._requiredFields] as string[]);\n\t\t}\n\t}\n\n\t/**\n\t * Sets a property value and returns a new builder instance with updated type state.\n\t * This method is intended to be wrapped by concrete builder methods in subclasses.\n\t *\n\t * @template K - The property key being set\n\t * @param key - The property key to set\n\t * @param value - The value to assign to the property\n\t * @returns A new builder instance with the property set and type state updated\n\t * @protected\n\t */\n\tprotected setProperty<K extends keyof T>(key: K, value: T[K]): this & CeriosBrand<Pick<T, K>> {\n\t\tconst BuilderClass = this.constructor as new (data: any, requiredFields?: RequiredFieldsTemplate<T>) => any;\n\t\treturn new BuilderClass(\n\t\t\t{\n\t\t\t\t...this._actual,\n\t\t\t\t[key]: value,\n\t\t\t},\n\t\t\tArray.from(this._requiredFields) as unknown as RequiredFieldsTemplate<T>\n\t\t) as this & CeriosBrand<Pick<T, K>>;\n\t}\n\n\t/**\n\t * Sets multiple property values at once and returns a new builder instance with updated type state.\n\t * @param props - An object with one or more properties to set.\n\t * @returns A new builder instance with the properties set and type state updated.\n\t * @protected\n\t */\n\tprotected setProperties<K extends keyof T>(props: Pick<T, K>): this & CeriosBrand<Pick<T, K>> {\n\t\tconst BuilderClass = this.constructor as new (data: any, requiredFields?: RequiredFieldsTemplate<T>) => any;\n\t\treturn new BuilderClass(\n\t\t\t{\n\t\t\t\t...this._actual,\n\t\t\t\t...props,\n\t\t\t},\n\t\t\tArray.from(this._requiredFields) as unknown as RequiredFieldsTemplate<T>\n\t\t) as this & CeriosBrand<Pick<T, K>>;\n\t}\n\n\t/**\n\t * Sets a deeply nested property value and returns a new builder instance with updated type state.\n\t * This method uses dot notation to set nested properties in a type-safe way.\n\t *\n\t * @template P - The property path (e.g., \"parent.child.grandchild\")\n\t * @param path - The dot-notation path to the property\n\t * @param value - The value to assign to the nested property\n\t * @returns A new builder instance with the nested property set\n\t * @protected\n\t *\n\t * @example\n\t * ```typescript\n\t * builder.setNestedProperty('Order.Details.CustomerId', 'value')\n\t * ```\n\t */\n\tprotected setNestedProperty<P extends Path<T>>(\n\t\tpath: P,\n\t\tvalue: PathValue<T, P>\n\t): this & CeriosBrand<Pick<T, RootKey<P & string, T> extends never ? keyof T : RootKey<P & string, T>>> {\n\t\tconst BuilderClass = this.constructor as new (data: any, requiredFields?: RequiredFieldsTemplate<T>) => any;\n\t\tconst keys = (path as string).split(\".\");\n\t\tconst newActual = this.deepClone(this._actual);\n\n\t\tlet current: any = newActual;\n\t\tfor (let i = 0; i < keys.length - 1; i++) {\n\t\t\tconst key = keys[i];\n\t\t\tif (!(key in current) || typeof current[key] !== \"object\" || current[key] === null) {\n\t\t\t\tcurrent[key] = {};\n\t\t\t} else {\n\t\t\t\tcurrent[key] = this.deepClone(current[key]);\n\t\t\t}\n\t\t\tcurrent = current[key];\n\t\t}\n\n\t\tcurrent[keys[keys.length - 1]] = value;\n\n\t\treturn new BuilderClass(\n\t\t\tnewActual,\n\t\t\tArray.from(this._requiredFields) as unknown as RequiredFieldsTemplate<T>\n\t\t) as this & CeriosBrand<Pick<T, RootKey<P & string, T> extends never ? keyof T : RootKey<P & string, T>>>;\n\t}\n\n\t/**\n\t * Deep clone helper for nested objects\n\t * @private\n\t */\n\tprivate deepClone<V>(obj: V): V {\n\t\tif (obj === null || typeof obj !== \"object\") {\n\t\t\treturn obj;\n\t\t}\n\t\tif (Array.isArray(obj)) {\n\t\t\treturn obj.map(item => this.deepClone(item)) as any;\n\t\t}\n\t\tconst cloned: any = {};\n\t\tconst hasOwn = Object.prototype.hasOwnProperty;\n\t\tfor (const key in obj) {\n\t\t\tif (hasOwn.call(obj, key)) {\n\t\t\t\tcloned[key] = this.deepClone(obj[key]);\n\t\t\t}\n\t\t}\n\t\treturn cloned;\n\t}\n\n\t/**\n\t * Adds a value to an array property and returns a new builder instance with updated type state.\n\t * This method is intended to be wrapped by concrete builder methods in subclasses for array properties.\n\t *\n\t * @template K - The property key (must be an array property)\n\t * @template V - The type of the array element\n\t * @param key - The array property key to add to\n\t * @param value - The value to add to the array\n\t * @returns A new builder instance with the array property updated and type state updated\n\t * @protected\n\t */\n\tprotected addToArrayProperty<\n\t\tK extends { [P in keyof T]: NonNullable<T[P]> extends Array<any> ? P : never }[keyof T],\n\t\tV extends T[K] extends Array<infer U> ? U : T[K] extends Array<infer U> | undefined ? U : never,\n\t>(key: K, value: V): this & CeriosBrand<Pick<T, K>> {\n\t\tconst BuilderClass = this.constructor as new (data: any, requiredFields?: RequiredFieldsTemplate<T>) => any;\n\t\tconst currentArray = (this._actual[key] as Array<V> | undefined) ?? [];\n\t\treturn new BuilderClass(\n\t\t\t{\n\t\t\t\t...this._actual,\n\t\t\t\t[key]: [...currentArray, value],\n\t\t\t},\n\t\t\tArray.from(this._requiredFields) as unknown as RequiredFieldsTemplate<T>\n\t\t) as this & CeriosBrand<Pick<T, K>>;\n\t}\n\n\t/**\n\t * Builds the final object with both compile-time and runtime validation.\n\t * This is the recommended and safest way to build objects.\n\t *\n\t * - Compile-time: TypeScript enforces all required properties are set\n\t * - Runtime: Validates all fields in the requiredTemplate\n\t *\n\t * @returns The fully built object of type T\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuild(this: this & CeriosBrand<T>): T {\n\t\tconst missing = this.validateRequiredFields();\n\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(`Missing required fields: ${missing.join(\", \")}. Please set these fields before calling build.`);\n\t\t}\n\n\t\treturn this._actual as T;\n\t}\n\n\t/**\n\t * Builds the final object with only compile-time validation, skipping runtime checks.\n\t * Use this when you want TypeScript safety but need to skip runtime validation for performance.\n\t *\n\t * - Compile-time: TypeScript enforces all required properties are set\n\t * - Runtime: No validation\n\t *\n\t * @returns The fully built object of type T\n\t */\n\tbuildWithoutRuntimeValidation(this: this & CeriosBrand<T>): T {\n\t\treturn this._actual as T;\n\t}\n\n\t/**\n\t * Builds the final object with only runtime validation, skipping compile-time checks.\n\t * Use this when building from external data where compile-time checks aren't possible.\n\t *\n\t * - Compile-time: No TypeScript enforcement\n\t * - Runtime: Validates all fields in the requiredTemplate\n\t *\n\t * @returns The fully built object of type T\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuildWithoutCompileTimeValidation(): T {\n\t\tconst missing = this.validateRequiredFields();\n\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(`Missing required fields: ${missing.join(\", \")}. Please set these fields before calling build.`);\n\t\t}\n\n\t\treturn this._actual as T;\n\t}\n\n\t/**\n\t * Builds the final object without any validation (neither compile-time nor runtime).\n\t * Use this only when you're certain the object is valid and need maximum performance.\n\t *\n\t * - Compile-time: No TypeScript enforcement\n\t * - Runtime: No validation\n\t *\n\t * @returns The object of type T (may be incomplete)\n\t */\n\tbuildUnsafe(): T {\n\t\treturn this._actual as T;\n\t}\n\n\t/**\n\t * Builds a partial object, which may not have all required fields set.\n\t * This is useful for scenarios where you want to inspect or validate the current state before finalizing.\n\t *\n\t * @returns The partially built object\n\t */\n\tbuildPartial(): Partial<T> {\n\t\treturn this._actual as Partial<T>;\n\t}\n\n\t/**\n\t * @deprecated Use build() instead. buildSafe() is now an alias for build().\n\t * Builds the final object with runtime validation using the requiredTemplate.\n\t * This method validates that all fields in the requiredTemplate array are present.\n\t *\n\t * @returns The fully built object of type T\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuildSafe(): T {\n\t\treturn this.buildWithoutCompileTimeValidation();\n\t}\n}\n"],"mappings":"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","names":[]}
{"version":3,"sources":["../src/cerios-builder.ts"],"sourcesContent":["/**\n * Unique symbol used internally to brand types and track which properties have been set in the builder's type.\n *\n * @internal\n */\ndeclare const __brand: unique symbol;\n\n/**\n * Type utility for branding builder types with information about which properties have been set.\n * This is used to enforce compile-time safety for required fields in the builder pattern.\n *\n * @template T - The type representing the set of properties that have been set\n * @internal\n */\nexport type CeriosBrand<T> = { [__brand]: T };\n\n/**\n * Helper type to represent a path through an object structure\n * Handles optional properties by unwrapping them with NonNullable\n */\ntype PathImpl<T, K extends keyof T = keyof T> = K extends string | number\n\t? NonNullable<T[K]> extends Record<string, any>\n\t\t? NonNullable<T[K]> extends Array<any>\n\t\t\t? K\n\t\t\t: K | `${K}.${PathImpl<NonNullable<T[K]>> & string}`\n\t\t: K\n\t: never;\n\nexport type Path<T> = PathImpl<T>;\n\n/**\n * Helper type to get the value at a specific path, handling optional properties\n */\ntype PathValue<T, P> = P extends keyof T\n\t? T[P]\n\t: P extends `${infer K}.${infer Rest}`\n\t\t? K extends keyof T\n\t\t\t? PathValue<NonNullable<T[K]>, Rest>\n\t\t\t: never\n\t\t: never;\n\n/**\n * Type-safe template for defining required fields using an array of paths.\n * Simply list the paths that are required.\n */\nexport type RequiredFieldsTemplate<T> = ReadonlyArray<Path<T>>;\n\n/**\n * Recursively makes all properties readonly for deep immutability.\n * Handles arrays, objects, and primitive types.\n *\n * @template T - The type to make deeply readonly\n */\nexport type DeepReadonly<T> = T extends (infer R)[]\n\t? DeepReadonlyArray<R>\n\t: T extends (...args: any[]) => any\n\t\t? T\n\t\t: T extends object\n\t\t\t? DeepReadonlyObject<T>\n\t\t\t: T;\n\n/**\n * Helper type for deep readonly arrays\n * @internal\n */\ninterface DeepReadonlyArray<T> extends ReadonlyArray<DeepReadonly<T>> {}\n\n/**\n * Helper type for deep readonly objects\n * @internal\n */\ntype DeepReadonlyObject<T> = {\n\treadonly [P in keyof T]: DeepReadonly<T[P]>;\n};\n\n/**\n * Cache the root key extraction to avoid repeated computation\n * Handles optional properties by ensuring the key is valid for T\n * @internal\n */\ntype RootKey<P extends string, T = any> = P extends `${infer K}.${string}`\n\t? K extends keyof T\n\t\t? K\n\t\t: never\n\t: P extends keyof T\n\t\t? P\n\t\t: never;\n\n/**\n * Recursively freezes an object and all its nested properties.\n * @param obj - The object to freeze\n * @returns The frozen object\n * @internal\n */\nfunction deepFreeze<T>(obj: T): T {\n\t// Retrieve the property names defined on obj\n\tObject.getOwnPropertyNames(obj).forEach(prop => {\n\t\tconst value = (obj as any)[prop];\n\n\t\t// Freeze properties before freezing self\n\t\tif (value !== null && (typeof value === \"object\" || typeof value === \"function\")) {\n\t\t\tdeepFreeze(value);\n\t\t}\n\t});\n\n\treturn Object.freeze(obj);\n}\n\n/**\n * Recursively seals an object and all its nested properties.\n * @param obj - The object to seal\n * @returns The sealed object\n * @internal\n */\nfunction deepSeal<T>(obj: T): T {\n\t// Retrieve the property names defined on obj\n\tObject.getOwnPropertyNames(obj).forEach(prop => {\n\t\tconst value = (obj as any)[prop];\n\n\t\t// Seal properties before sealing self\n\t\tif (value !== null && (typeof value === \"object\" || typeof value === \"function\")) {\n\t\t\tdeepSeal(value);\n\t\t}\n\t});\n\n\treturn Object.seal(obj);\n}\n\n/**\n * Abstract base class for creating type-safe builders with automatic property setters and compile-time validation of required fields.\n *\n * This class is intended to be extended by concrete builder implementations for your own types.\n * It provides utility methods for setting properties and building the final object, ensuring that all required fields are set at compile time.\n *\n * Example usage:\n * ```typescript\n * interface MyType { foo: string; bar: number[]; }\n * class MyTypeBuilder extends CeriosBuilder<MyType> {\n * static requiredTemplate: RequiredFieldsTemplate<MyType> = ['foo'];\n * setFoo(value: string) { return this.setProperty('foo', value); }\n * addBar(value: number) { return this.addToArrayProperty('bar', value); }\n * }\n * // Usage:\n * const obj = new MyTypeBuilder({})\n * .setFoo('hello')\n * .addBar(42)\n * .buildSafe(); // Validates that 'foo' is set\n * ```\n *\n * @template T - The complete type being built\n */\nexport abstract class CeriosBuilder<T extends object> {\n\t/**\n\t * Template defining which fields are required for this builder.\n\t * Subclasses should override this to specify their required fields as an array of paths.\n\t * The template is type-safe - only valid paths from type T can be used.\n\t */\n\tstatic requiredTemplate?: ReadonlyArray<string>;\n\n\t/**\n\t * Instance-level required fields that can be populated dynamically.\n\t * This allows adding required fields at runtime via the setRequiredFields method.\n\t * @private\n\t */\n\tprivate _requiredFields: Set<string> = new Set();\n\n\t/**\n\t * Sets the required fields for this builder instance.\n\t * This allows you to dynamically define which fields are required.\n\t *\n\t * @param fields - Array of dot-notation paths to required fields\n\t * @returns The builder instance for chaining\n\t *\n\t * @example\n\t * ```typescript\n\t * const builder = new MyBuilder({})\n\t * .setRequiredFields(['path.to.field1', 'path.to.field2'])\n\t * .setField1('value1')\n\t * .setField2('value2')\n\t * .buildSafe();\n\t * ```\n\t */\n\tsetRequiredFields(fields: ReadonlyArray<Path<T>>): this {\n\t\tthis._requiredFields = new Set([...fields] as string[]);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the combined required fields from both the static template and instance-level fields.\n\t * @private\n\t */\n\tprivate getRequiredTemplate(): ReadonlyArray<string> {\n\t\tconst ctor = this.constructor as typeof CeriosBuilder;\n\t\tconst staticFields = ctor.requiredTemplate || [];\n\t\tconst instanceFields = Array.from(this._requiredFields);\n\n\t\t// Combine and deduplicate\n\t\treturn [...new Set([...staticFields, ...instanceFields])];\n\t}\n\n\t/**\n\t * Validates that all fields in the required template have been set.\n\t * @private\n\t */\n\tprivate validateRequiredFields(): string[] {\n\t\tconst requiredPaths = this.getRequiredTemplate();\n\t\tconst missing: string[] = [];\n\n\t\tfor (const path of requiredPaths) {\n\t\t\tconst keys = path.split(\".\");\n\t\t\tlet current: any = this._actual;\n\n\t\t\tfor (let i = 0; i < keys.length; i++) {\n\t\t\t\tconst key = keys[i];\n\t\t\t\tif (current === null || current === undefined || !(key in current)) {\n\t\t\t\t\tmissing.push(path);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcurrent = current[key];\n\t\t\t}\n\n\t\t\t// Check if the final value is null or undefined\n\t\t\tif (current === null || current === undefined) {\n\t\t\t\tif (!missing.includes(path)) {\n\t\t\t\t\tmissing.push(path);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn missing;\n\t}\n\n\t/**\n\t * Creates a new builder instance. Intended to be called by subclasses.\n\t *\n\t * @param _actual - The current partial state of the object being built\n\t * @param _requiredFields - Optional array of required field paths to preserve across instances\n\t * @protected\n\t */\n\tprotected constructor(\n\t\tprotected readonly _actual: Partial<T>,\n\t\t_requiredFields?: RequiredFieldsTemplate<T>\n\t) {\n\t\tif (_requiredFields) {\n\t\t\tthis._requiredFields = new Set([..._requiredFields] as string[]);\n\t\t}\n\t}\n\n\t/**\n\t * Sets a property value and returns a new builder instance with updated type state.\n\t * This method is intended to be wrapped by concrete builder methods in subclasses.\n\t *\n\t * @template K - The property key being set\n\t * @param key - The property key to set\n\t * @param value - The value to assign to the property\n\t * @returns A new builder instance with the property set and type state updated\n\t * @protected\n\t */\n\tprotected setProperty<K extends keyof T>(key: K, value: T[K]): this & CeriosBrand<Pick<T, K>> {\n\t\tconst BuilderClass = this.constructor as new (data: any, requiredFields?: RequiredFieldsTemplate<T>) => any;\n\t\treturn new BuilderClass(\n\t\t\t{\n\t\t\t\t...this._actual,\n\t\t\t\t[key]: value,\n\t\t\t},\n\t\t\tArray.from(this._requiredFields) as unknown as RequiredFieldsTemplate<T>\n\t\t) as this & CeriosBrand<Pick<T, K>>;\n\t}\n\n\t/**\n\t * Sets multiple property values at once and returns a new builder instance with updated type state.\n\t * @param props - An object with one or more properties to set.\n\t * @returns A new builder instance with the properties set and type state updated.\n\t * @protected\n\t */\n\tprotected setProperties<K extends keyof T>(props: Pick<T, K>): this & CeriosBrand<Pick<T, K>> {\n\t\tconst BuilderClass = this.constructor as new (data: any, requiredFields?: RequiredFieldsTemplate<T>) => any;\n\t\treturn new BuilderClass(\n\t\t\t{\n\t\t\t\t...this._actual,\n\t\t\t\t...props,\n\t\t\t},\n\t\t\tArray.from(this._requiredFields) as unknown as RequiredFieldsTemplate<T>\n\t\t) as this & CeriosBrand<Pick<T, K>>;\n\t}\n\n\t/**\n\t * Sets a deeply nested property value and returns a new builder instance with updated type state.\n\t * This method uses dot notation to set nested properties in a type-safe way.\n\t *\n\t * @template P - The property path (e.g., \"parent.child.grandchild\")\n\t * @param path - The dot-notation path to the property\n\t * @param value - The value to assign to the nested property\n\t * @returns A new builder instance with the nested property set\n\t * @protected\n\t *\n\t * @example\n\t * ```typescript\n\t * builder.setNestedProperty('Order.Details.CustomerId', 'value')\n\t * ```\n\t */\n\tprotected setNestedProperty<P extends Path<T>>(\n\t\tpath: P,\n\t\tvalue: PathValue<T, P>\n\t): this & CeriosBrand<Pick<T, RootKey<P & string, T> extends never ? keyof T : RootKey<P & string, T>>> {\n\t\tconst BuilderClass = this.constructor as new (data: any, requiredFields?: RequiredFieldsTemplate<T>) => any;\n\t\tconst keys = (path as string).split(\".\");\n\t\tconst newActual = this.deepClone(this._actual);\n\n\t\tlet current: any = newActual;\n\t\tfor (let i = 0; i < keys.length - 1; i++) {\n\t\t\tconst key = keys[i];\n\t\t\tif (!(key in current) || typeof current[key] !== \"object\" || current[key] === null) {\n\t\t\t\tcurrent[key] = {};\n\t\t\t} else {\n\t\t\t\tcurrent[key] = this.deepClone(current[key]);\n\t\t\t}\n\t\t\tcurrent = current[key];\n\t\t}\n\n\t\tcurrent[keys[keys.length - 1]] = value;\n\n\t\treturn new BuilderClass(\n\t\t\tnewActual,\n\t\t\tArray.from(this._requiredFields) as unknown as RequiredFieldsTemplate<T>\n\t\t) as this & CeriosBrand<Pick<T, RootKey<P & string, T> extends never ? keyof T : RootKey<P & string, T>>>;\n\t}\n\n\t/**\n\t * Deep clone helper for nested objects\n\t * @private\n\t */\n\tprivate deepClone<V>(obj: V): V {\n\t\tif (obj === null || typeof obj !== \"object\") {\n\t\t\treturn obj;\n\t\t}\n\t\tif (Array.isArray(obj)) {\n\t\t\treturn obj.map(item => this.deepClone(item)) as any;\n\t\t}\n\t\tconst cloned: any = {};\n\t\tconst hasOwn = Object.prototype.hasOwnProperty;\n\t\tfor (const key in obj) {\n\t\t\tif (hasOwn.call(obj, key)) {\n\t\t\t\tcloned[key] = this.deepClone(obj[key]);\n\t\t\t}\n\t\t}\n\t\treturn cloned;\n\t}\n\n\t/**\n\t * Adds a value to an array property and returns a new builder instance with updated type state.\n\t * This method is intended to be wrapped by concrete builder methods in subclasses for array properties.\n\t *\n\t * @template K - The property key (must be an array property)\n\t * @template V - The type of the array element\n\t * @param key - The array property key to add to\n\t * @param value - The value to add to the array\n\t * @returns A new builder instance with the array property updated and type state updated\n\t * @protected\n\t */\n\tprotected addToArrayProperty<\n\t\tK extends { [P in keyof T]: NonNullable<T[P]> extends Array<any> ? P : never }[keyof T],\n\t\tV extends T[K] extends Array<infer U> ? U : T[K] extends Array<infer U> | undefined ? U : never,\n\t>(key: K, value: V): this & CeriosBrand<Pick<T, K>> {\n\t\tconst BuilderClass = this.constructor as new (data: any, requiredFields?: RequiredFieldsTemplate<T>) => any;\n\t\tconst currentArray = (this._actual[key] as Array<V> | undefined) ?? [];\n\t\treturn new BuilderClass(\n\t\t\t{\n\t\t\t\t...this._actual,\n\t\t\t\t[key]: [...currentArray, value],\n\t\t\t},\n\t\t\tArray.from(this._requiredFields) as unknown as RequiredFieldsTemplate<T>\n\t\t) as this & CeriosBrand<Pick<T, K>>;\n\t}\n\n\t/**\n\t * Builds the final object with both compile-time and runtime validation.\n\t * This is the recommended and safest way to build objects.\n\t *\n\t * - Compile-time: TypeScript enforces all required properties are set\n\t * - Runtime: Validates all fields in the requiredTemplate\n\t *\n\t * @returns The fully built object of type T\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuild(this: this & CeriosBrand<T>): T {\n\t\tconst missing = this.validateRequiredFields();\n\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(`Missing required fields: ${missing.join(\", \")}. Please set these fields before calling build.`);\n\t\t}\n\n\t\treturn this._actual as T;\n\t}\n\n\t/**\n\t * Builds the final object with only compile-time validation, skipping runtime checks.\n\t * Use this when you want TypeScript safety but need to skip runtime validation for performance.\n\t *\n\t * - Compile-time: TypeScript enforces all required properties are set\n\t * - Runtime: No validation\n\t *\n\t * @returns The fully built object of type T\n\t */\n\tbuildWithoutRuntimeValidation(this: this & CeriosBrand<T>): T {\n\t\treturn this._actual as T;\n\t}\n\n\t/**\n\t * Builds the final object with only runtime validation, skipping compile-time checks.\n\t * Use this when building from external data where compile-time checks aren't possible.\n\t *\n\t * - Compile-time: No TypeScript enforcement\n\t * - Runtime: Validates all fields in the requiredTemplate\n\t *\n\t * @returns The fully built object of type T\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuildWithoutCompileTimeValidation(): T {\n\t\tconst missing = this.validateRequiredFields();\n\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(`Missing required fields: ${missing.join(\", \")}. Please set these fields before calling build.`);\n\t\t}\n\n\t\treturn this._actual as T;\n\t}\n\n\t/**\n\t * Builds the final object without any validation (neither compile-time nor runtime).\n\t * Use this only when you're certain the object is valid and need maximum performance.\n\t *\n\t * - Compile-time: No TypeScript enforcement\n\t * - Runtime: No validation\n\t *\n\t * @returns The object of type T (may be incomplete)\n\t */\n\tbuildUnsafe(): T {\n\t\treturn this._actual as T;\n\t}\n\n\t/**\n\t * Builds a partial object, which may not have all required fields set.\n\t * This is useful for scenarios where you want to inspect or validate the current state before finalizing.\n\t *\n\t * @returns The partially built object\n\t */\n\tbuildPartial(): Partial<T> {\n\t\treturn this._actual as Partial<T>;\n\t}\n\n\t/**\n\t * @deprecated Use build() instead. buildSafe() is now an alias for build().\n\t * Builds the final object with runtime validation using the requiredTemplate.\n\t * This method validates that all fields in the requiredTemplate array are present.\n\t *\n\t * @returns The fully built object of type T\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuildSafe(): T {\n\t\treturn this.buildWithoutCompileTimeValidation();\n\t}\n\n\t/**\n\t * Builds and freezes the final object with both compile-time and runtime validation.\n\t * The returned object is shallowly frozen - top-level properties cannot be modified,\n\t * but nested objects remain mutable.\n\t *\n\t * - Compile-time: TypeScript enforces all required properties are set\n\t * - Runtime: Validates all fields in the requiredTemplate and applies Object.freeze()\n\t *\n\t * @returns The frozen object of type Readonly<T>\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuildFrozen(this: this & CeriosBrand<T>): Readonly<T> {\n\t\tconst missing = this.validateRequiredFields();\n\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(`Missing required fields: ${missing.join(\", \")}. Please set these fields before calling build.`);\n\t\t}\n\n\t\treturn Object.freeze(this._actual as T);\n\t}\n\n\t/**\n\t * Builds and deeply freezes the final object with both compile-time and runtime validation.\n\t * The returned object is recursively frozen - all nested objects and arrays are also frozen.\n\t *\n\t * - Compile-time: TypeScript enforces all required properties are set\n\t * - Runtime: Validates all fields in the requiredTemplate and recursively applies Object.freeze()\n\t *\n\t * @returns The deeply frozen object of type DeepReadonly<T>\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuildDeepFrozen(this: this & CeriosBrand<T>): DeepReadonly<T> {\n\t\tconst missing = this.validateRequiredFields();\n\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(`Missing required fields: ${missing.join(\", \")}. Please set these fields before calling build.`);\n\t\t}\n\n\t\treturn deepFreeze(this._actual as T) as DeepReadonly<T>;\n\t}\n\n\t/**\n\t * Builds and seals the final object with both compile-time and runtime validation.\n\t * The returned object is shallowly sealed - properties cannot be added or removed,\n\t * but existing properties can still be modified. Nested objects remain unsealed.\n\t *\n\t * - Compile-time: TypeScript enforces all required properties are set\n\t * - Runtime: Validates all fields in the requiredTemplate and applies Object.seal()\n\t *\n\t * @returns The sealed object of type T\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuildSealed(this: this & CeriosBrand<T>): T {\n\t\tconst missing = this.validateRequiredFields();\n\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(`Missing required fields: ${missing.join(\", \")}. Please set these fields before calling build.`);\n\t\t}\n\n\t\treturn Object.seal(this._actual as T);\n\t}\n\n\t/**\n\t * Builds and deeply seals the final object with both compile-time and runtime validation.\n\t * The returned object is recursively sealed - properties cannot be added or removed at any level,\n\t * but existing properties can still be modified.\n\t *\n\t * - Compile-time: TypeScript enforces all required properties are set\n\t * - Runtime: Validates all fields in the requiredTemplate and recursively applies Object.seal()\n\t *\n\t * @returns The deeply sealed object of type T\n\t * @throws {Error} If any required field is missing at runtime\n\t */\n\tbuildDeepSealed(this: this & CeriosBrand<T>): T {\n\t\tconst missing = this.validateRequiredFields();\n\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(`Missing required fields: ${missing.join(\", \")}. Please set these fields before calling build.`);\n\t\t}\n\n\t\treturn deepSeal(this._actual as T);\n\t}\n}\n"],"mappings":"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","names":[]}
{
"name": "@cerios/cerios-builder",
"version": "1.3.0",
"version": "1.4.0",
"author": "Ronald Veth - Cerios",

@@ -5,0 +5,0 @@ "description": "A TypeScript builder pattern library providing compile-time type safety for object construction with method chaining and required field validation",

+340
-28

@@ -10,2 +10,3 @@ # @cerios/cerios-builder

- **Flexible Runtime Validation**: Choose between compile-time, runtime, or both validations
- **Immutability Options**: Create frozen or sealed objects with shallow or deep variants
- **Dynamic Required Fields**: Add required fields at runtime based on your business logic

@@ -90,2 +91,6 @@ - **Method Chaining**: Fluent API for readable object construction

| **Partial Build** | `buildPartial()` | Build incomplete objects |
| **Shallow Freeze** | `buildFrozen()` | Create immutable object (top-level only) |
| **Deep Freeze** | `buildDeepFrozen()` | Create fully immutable object tree |
| **Shallow Seal** | `buildSealed()` | Lock structure, allow modifications |
| **Deep Seal** | `buildDeepSealed()` | Lock all structures, allow modifications |

@@ -688,2 +693,10 @@ ## ๐Ÿ”ง Basic Usage

// NEW: Create with ALL required fields set
static createComplete() {
return this.create()
.street("123 Default Street")
.city("Othertown")
.country("United States");
}
street(value: string) {

@@ -735,2 +748,3 @@ return this.setProperty('street', value);

// Pattern 1: No defaults - must set all required fields
withAddress(builderFn: (builder: AddressBuilder) => AddressBuilder & CeriosBrand<Address>) {

@@ -741,2 +755,3 @@ const address = builderFn(AddressBuilder.create()).build();

// Pattern 2: Partial defaults - must set remaining required fields (street)
withAddressDefaults(

@@ -750,6 +765,17 @@ builderFn: (

}
// Pattern 3: Complete defaults - callback is OPTIONAL
withCompleteAddress(
builderFn?: (
builder: AddressBuilder & CeriosBrand<Address>
) => AddressBuilder & CeriosBrand<Address>
) {
const builder = AddressBuilder.createComplete();
const address = builderFn ? builderFn(builder).build() : builder.build();
return this.setProperty('address', address);
}
}
// Usage with full address
const customer = CustomerBuilder.create()
// Pattern 1: No defaults - must set all required fields
const customer1 = CustomerBuilder.create()
.id('CUST-001')

@@ -764,8 +790,7 @@ .name('Alice Johnson')

.addNote("VIP customer")
.addNote("Prefers email contact")
.phoneNumber('+1-555-0123')
.build();
// Usage with defaults
const customerWithDefaults = CustomerBuilder.create()
// Pattern 2: Partial defaults - city and country already set, must provide street
const customer2 = CustomerBuilder.create()
.id('CUST-002')

@@ -777,21 +802,72 @@ .name('Bob Smith')

console.log(customerWithDefaults);
console.log(customer2);
// Output: { id: 'CUST-002', name: 'Bob Smith', address: { street: '456 Elm St', city: 'Othertown', country: 'United States' }, notes: ['New customer'] }
// Pattern 3a: Complete defaults - no callback needed, use all defaults
const customer3 = CustomerBuilder.create()
.id('CUST-003')
.name('Charlie Davis')
.withCompleteAddress() // โœ… No callback needed - all required fields already set!
.build();
console.log(customer3);
// Output: { id: 'CUST-003', name: 'Charlie Davis', address: { street: '123 Default Street', city: 'Othertown', country: 'United States' } }
// Pattern 3b: Complete defaults - optional callback to modify/add optional fields
const customer4 = CustomerBuilder.create()
.id('CUST-004')
.name('Diana Evans')
.withCompleteAddress(addr => addr
.zipCode('90210') // Only modify/add optional fields if needed
)
.build();
console.log(customer4);
// Output: { id: 'CUST-004', name: 'Diana Evans', address: { street: '123 Default Street', city: 'Othertown', country: 'United States', zipCode: '90210' } }
// Pattern 3c: Complete defaults - optional callback to override any field
const customer5 = CustomerBuilder.create()
.id('CUST-005')
.name('Eve Foster')
.withCompleteAddress(addr => addr
.street('789 Custom Ave') // Override the default street
.zipCode('10001')
)
.addNote("Premium customer")
.build();
console.log(customer5);
// Output: { id: 'CUST-005', name: 'Eve Foster', address: { street: '789 Custom Ave', city: 'Othertown', country: 'United States', zipCode: '10001' }, notes: ['Premium customer'] }
```
### Partial Building for Flexibility
#### Using `createWithDefaults()` with Nested Builders
Sometimes you need to build incomplete objects:
The key pattern is:
1. **`createComplete()`**: Returns a builder with **all required fields already set**
2. **Optional callback parameter**: The callback parameter is typed as `optional` (`?`), so you don't have to provide it
3. **Already branded**: Since all required fields are set, the builder is already branded with `CeriosBrand<Address>`, so you can call `build()` immediately
This pattern is perfect when:
- You have sensible defaults for all required fields
- Most users will use the defaults
- Some users may want to customize optional fields or override defaults
- You want a clean API without forcing users to write empty callbacks
**Comparison of the three patterns:**
```typescript
// Build partial objects when not all data is available
const partialUser = UserBuilder.create()
.name("Unknown User")
.addRole("guest")
.buildPartial(); // Returns Partial<User>
// Pattern 1: Must set ALL required fields
.withAddress(addr => addr.street('...').city('...').country('...'))
// This is useful for:
// - Progressive form filling
// - API responses with optional fields
// - Template objects
// Pattern 2: Must set REMAINING required fields (street)
.withAddressDefaults(addr => addr.street('...'))
// Pattern 3a: NO callback needed - all defaults
.withCompleteAddress()
// Pattern 3b: OPTIONAL callback - only if you want to customize
.withCompleteAddress(addr => addr.zipCode('...'))
// Pattern 3c: OPTIONAL callback - can override any field
.withCompleteAddress(addr => addr.street('...').zipCode('...'))
```

@@ -1116,4 +1192,248 @@

## ๐Ÿ’ก Best Practices
## ๏ฟฝ Immutable Build Methods
In addition to the standard build methods, `@cerios/cerios-builder` provides **frozen** and **sealed** variants that create immutable objects. These methods help prevent accidental mutations and enforce data integrity.
### Understanding Freeze vs Seal
Before diving into the methods, it's important to understand the difference between **frozen** and **sealed** objects:
| Feature | `Object.freeze()` | `Object.seal()` |
|---------|------------------|-----------------|
| **Add properties** | โŒ Prevented | โŒ Prevented |
| **Delete properties** | โŒ Prevented | โŒ Prevented |
| **Modify properties** | โŒ Prevented | โœ… Allowed |
| **Use case** | Complete immutability | Prevent structural changes |
**Shallow vs Deep:**
- **Shallow**: Only applies to the top-level object
- **Deep**: Recursively applies to all nested objects and arrays
### `buildFrozen()` - Shallow Freeze
Creates a **shallowly frozen** object where top-level properties cannot be modified, but nested objects remain mutable.
```typescript
const user = UserBuilder.create()
.id('123')
.name('John')
.email('john@example.com')
.buildFrozen(); // Returns Readonly<User>
// โŒ Error: Cannot modify top-level properties
user.name = 'Jane'; // TypeError in strict mode
// โš ๏ธ Nested objects can still be modified (shallow freeze)
user.address.city = 'New York'; // Works if address is an object
```
**Use when:**
- You want to prevent accidental top-level modifications
- Nested objects are intentionally mutable
- Performance is a concern (shallow operations are faster)
### `buildDeepFrozen()` - Deep Freeze
Creates a **deeply frozen** object where all properties at all levels are immutable.
```typescript
const user = UserBuilder.create()
.id('123')
.name('John')
.email('john@example.com')
.setNestedProperty('address.city', 'Boston')
.buildDeepFrozen(); // Returns DeepReadonly<User>
// โŒ Error: Cannot modify top-level properties
user.name = 'Jane'; // TypeError
// โŒ Error: Cannot modify nested properties
user.address.city = 'New York'; // TypeError
// โŒ Error: Cannot modify arrays
user.tags.push('new tag'); // TypeError
```
**Use when:**
- You need complete immutability
- Building configuration objects
- Creating frozen state snapshots
- Working with Redux/immutable state patterns
- Passing objects to untrusted code
### `buildSealed()` - Shallow Seal
Creates a **shallowly sealed** object where properties cannot be added or removed, but existing properties can be modified.
```typescript
const user = UserBuilder.create()
.id('123')
.name('John')
.email('john@example.com')
.buildSealed(); // Returns T
// โœ… Can modify existing properties
user.name = 'Jane'; // Works!
// โŒ Cannot add new properties
user.newProp = 'value'; // TypeError in strict mode
// โŒ Cannot delete properties
delete user.email; // TypeError in strict mode
// โš ๏ธ Can modify nested objects (shallow seal)
user.address.city = 'New York'; // Works if address is an object
```
**Use when:**
- You want to lock the object structure
- Properties should be modifiable
- Preventing accidental property additions
- Building objects with fixed schemas
### `buildDeepSealed()` - Deep Seal
Creates a **deeply sealed** object where no properties can be added or removed at any level, but all properties can still be modified.
```typescript
const user = UserBuilder.create()
.id('123')
.name('John')
.email('john@example.com')
.setNestedProperty('address.city', 'Boston')
.buildDeepSealed(); // Returns T
// โœ… Can modify properties at all levels
user.name = 'Jane'; // Works
user.address.city = 'New York'; // Works
// โŒ Cannot add properties at any level
user.newProp = 'value'; // TypeError
user.address.newProp = 'value'; // TypeError
// โŒ Cannot add array elements
user.tags.push('new tag'); // TypeError
// โœ… Can modify array elements
user.tags[0] = 'updated tag'; // Works
```
**Use when:**
- You want to lock all object structures
- Values should be modifiable
- Preventing structural changes throughout the tree
- Building objects with deeply fixed schemas
### Immutability Comparison
| Method | Modify Top-Level | Modify Nested | Add Properties | Delete Properties | Performance |
|--------|-----------------|---------------|----------------|-------------------|-------------|
| `buildFrozen()` | โŒ | โœ… | โŒ | โŒ | Fast |
| `buildDeepFrozen()` | โŒ | โŒ | โŒ | โŒ | Slower |
| `buildSealed()` | โœ… | โœ… | โŒ | โŒ | Fast |
| `buildDeepSealed()` | โœ… | โœ… | โŒ | โŒ | Slower |
### Immutability Examples
#### Example 1: Configuration Object
```typescript
class ConfigBuilder extends CeriosBuilder<AppConfig> {
static requiredTemplate: RequiredFieldsTemplate<AppConfig> = [
'apiUrl',
'timeout',
'features.authentication'
];
static create() {
return new ConfigBuilder({});
}
// ... builder methods
}
const config = ConfigBuilder.create()
.setApiUrl('https://api.example.com')
.setTimeout(5000)
.setNestedProperty('features.authentication', true)
.buildDeepFrozen(); // Configuration should never change
// โŒ Configuration is completely frozen
config.timeout = 10000; // TypeError
config.features.authentication = false; // TypeError
```
#### Example 2: Mutable Data with Fixed Structure
```typescript
class UserStateBuilder extends CeriosBuilder<UserState> {
static create() {
return new UserStateBuilder({});
}
// ... builder methods
}
const userState = UserStateBuilder.create()
.setUserId('123')
.setStatus('active')
.setLastSeen(new Date())
.buildDeepSealed(); // Structure is fixed, but values can change
// โœ… Can update state values
userState.status = 'inactive';
userState.lastSeen = new Date();
// โŒ Cannot add new properties
userState.newField = 'value'; // TypeError
```
#### Example 3: Snapshot for Time Travel Debugging
```typescript
class AppStateBuilder extends CeriosBuilder<AppState> {
// ... methods
}
const snapshots: DeepReadonly<AppState>[] = [];
// Capture immutable snapshots
snapshots.push(
AppStateBuilder.create()
.setCurrentUser(user)
.setOpenDocuments(documents)
.buildDeepFrozen()
);
// Snapshots cannot be modified
snapshots[0].currentUser.name = 'Changed'; // TypeError
```
### When to Use Immutability
**Use `buildDeepFrozen()`:**
- โœ… Configuration objects
- โœ… State snapshots
- โœ… Event data
- โœ… Cached results
- โœ… Objects passed to untrusted code
**Use `buildDeepSealed()`:**
- โœ… State objects with fixed schemas
- โœ… Form data models
- โœ… Database records with fixed columns
- โœ… API response models
**Use shallow variants (`buildFrozen()`, `buildSealed()`):**
- โœ… When nested objects need flexibility
- โœ… Performance-critical scenarios
- โœ… Intentional selective mutability
**Avoid immutable builds when:**
- โŒ Building frequently updated objects
- โŒ Working with large data structures (performance cost)
- โŒ Objects that need frequent transformations
## ๏ฟฝ๐Ÿ’ก Best Practices
1. **Use `setNestedProperty()` for deep structures**: Instead of building nested objects separately, use dot notation for better type safety and cleaner code.

@@ -1128,2 +1448,4 @@

- Use `buildUnsafe()` only when absolutely necessary
- Use `buildDeepFrozen()` for configuration and immutable data
- Use `buildDeepSealed()` when you need fixed schemas with mutable values

@@ -1156,11 +1478,1 @@ 4. **Use `setRequiredFields()` for conditional requirements**: When requirements change based on context (e.g., new vs existing records), use dynamic required fields.

```
## ๐Ÿ“„ License
MIT ยฉ [Cerios](LICENSE)
## ๐Ÿ”— Links
- [GitHub Repository](https://github.com/CeriosTesting/cerios-builder)
- [Issues](https://github.com/CeriosTesting/cerios-builder/issues)
- [NPM Package](https://www.npmjs.com/package/@cerios/cerios-builder)