@cerios/cerios-builder
Advanced tools
+69
-5
| /** | ||
| * Unique symbol to track which properties have been set in the builder's type | ||
| * Unique symbol used internally to brand types and track which properties have been set in the builder's type. | ||
| * | ||
| * @internal | ||
| */ | ||
| declare const __brand: unique symbol; | ||
| /** | ||
| * Brand type to track set properties at the type level | ||
| * Type utility for branding builder types with information about which properties have been set. | ||
| * This is used to enforce compile-time safety for required fields in the builder pattern. | ||
| * | ||
| * @template T - The type representing the set of properties that have been set | ||
| * @internal | ||
| */ | ||
@@ -12,5 +18,21 @@ type CeriosBrand<T> = { | ||
| /** | ||
| * Base Builder class that provides type-safe building with automatic property setters | ||
| * and compile-time validation of required fields. | ||
| * Abstract base class for creating type-safe builders with automatic property setters and compile-time validation of required fields. | ||
| * | ||
| * This class is intended to be extended by concrete builder implementations for your own types. | ||
| * It provides utility methods for setting properties and building the final object, ensuring that all required fields are set at compile time. | ||
| * | ||
| * Example usage: | ||
| * ```typescript | ||
| * interface MyType { foo: string; bar: number[]; } | ||
| * class MyTypeBuilder extends CeriosBuilder<MyType> { | ||
| * setFoo(value: string) { return this.setProperty('foo', value); } | ||
| * addBar(value: number) { return this.addToArrayProperty('bar', value); } | ||
| * } | ||
| * // Usage: | ||
| * const obj = new MyTypeBuilder({}) | ||
| * .setFoo('hello') | ||
| * .addBar(42) | ||
| * .build(); | ||
| * ``` | ||
| * | ||
| * @template T - The complete type being built | ||
@@ -20,9 +42,42 @@ */ | ||
| protected readonly _actual: Partial<T>; | ||
| /** | ||
| * Creates a new builder instance. Intended to be called by subclasses. | ||
| * | ||
| * @param _actual - The current partial state of the object being built | ||
| * @protected | ||
| */ | ||
| protected constructor(_actual: Partial<T>); | ||
| /** | ||
| * Sets a property value and returns a new builder instance with updated type state. | ||
| * This method tracks which properties have been set via the type system. | ||
| * This method is intended to be wrapped by concrete builder methods in subclasses. | ||
| * | ||
| * @template K - The property key being set | ||
| * @param key - The property key to set | ||
| * @param value - The value to assign to the property | ||
| * @returns A new builder instance with the property set and type state updated | ||
| * @protected | ||
| */ | ||
| protected setProperty<K extends keyof T>(key: K, value: T[K]): this & CeriosBrand<Pick<T, K>>; | ||
| /** | ||
| * Sets multiple property values at once and returns a new builder instance with updated type state. | ||
| * @param props - An object with one or more properties to set. | ||
| * @returns A new builder instance with the properties set and type state updated. | ||
| * @protected | ||
| */ | ||
| protected setProperties<K extends keyof T>(props: Pick<T, K>): this & CeriosBrand<Pick<T, K>>; | ||
| /** | ||
| * Adds a value to an array property and returns a new builder instance with updated type state. | ||
| * This method is intended to be wrapped by concrete builder methods in subclasses for array properties. | ||
| * | ||
| * @template K - The property key (must be an array property) | ||
| * @template V - The type of the array element | ||
| * @param key - The array property key to add to | ||
| * @param value - The value to add to the array | ||
| * @returns A new builder instance with the array property updated and type state updated | ||
| * @protected | ||
| */ | ||
| protected addToArrayProperty<K extends { | ||
| [P in keyof T]: NonNullable<T[P]> extends Array<any> ? P : never; | ||
| }[keyof T], V extends T[K] extends Array<infer U> ? U : T[K] extends Array<infer U> | undefined ? U : never>(key: K, value: V): this & CeriosBrand<Pick<T, K>>; | ||
| /** | ||
| * Builds the final object. This method uses TypeScript's contextual typing to ensure | ||
@@ -32,4 +87,13 @@ * all required fields are set before allowing build() to be called. | ||
| * The type constraint checks that all required properties are present. | ||
| * | ||
| * @returns The fully built object of type T | ||
| * @throws {TypeError} If called without all required fields set (compile-time error) | ||
| */ | ||
| build(this: this & CeriosBrand<T>): T; | ||
| /** | ||
| * Builds a partial object, which may not have all required fields set. | ||
| * This is useful for scenarios where you want to inspect or validate the current state before finalizing. | ||
| * | ||
| * @returns The partially built object | ||
| */ | ||
| buildPartial(): Partial<T>; | ||
@@ -36,0 +100,0 @@ } |
+69
-5
| /** | ||
| * Unique symbol to track which properties have been set in the builder's type | ||
| * Unique symbol used internally to brand types and track which properties have been set in the builder's type. | ||
| * | ||
| * @internal | ||
| */ | ||
| declare const __brand: unique symbol; | ||
| /** | ||
| * Brand type to track set properties at the type level | ||
| * Type utility for branding builder types with information about which properties have been set. | ||
| * This is used to enforce compile-time safety for required fields in the builder pattern. | ||
| * | ||
| * @template T - The type representing the set of properties that have been set | ||
| * @internal | ||
| */ | ||
@@ -12,5 +18,21 @@ type CeriosBrand<T> = { | ||
| /** | ||
| * Base Builder class that provides type-safe building with automatic property setters | ||
| * and compile-time validation of required fields. | ||
| * Abstract base class for creating type-safe builders with automatic property setters and compile-time validation of required fields. | ||
| * | ||
| * This class is intended to be extended by concrete builder implementations for your own types. | ||
| * It provides utility methods for setting properties and building the final object, ensuring that all required fields are set at compile time. | ||
| * | ||
| * Example usage: | ||
| * ```typescript | ||
| * interface MyType { foo: string; bar: number[]; } | ||
| * class MyTypeBuilder extends CeriosBuilder<MyType> { | ||
| * setFoo(value: string) { return this.setProperty('foo', value); } | ||
| * addBar(value: number) { return this.addToArrayProperty('bar', value); } | ||
| * } | ||
| * // Usage: | ||
| * const obj = new MyTypeBuilder({}) | ||
| * .setFoo('hello') | ||
| * .addBar(42) | ||
| * .build(); | ||
| * ``` | ||
| * | ||
| * @template T - The complete type being built | ||
@@ -20,9 +42,42 @@ */ | ||
| protected readonly _actual: Partial<T>; | ||
| /** | ||
| * Creates a new builder instance. Intended to be called by subclasses. | ||
| * | ||
| * @param _actual - The current partial state of the object being built | ||
| * @protected | ||
| */ | ||
| protected constructor(_actual: Partial<T>); | ||
| /** | ||
| * Sets a property value and returns a new builder instance with updated type state. | ||
| * This method tracks which properties have been set via the type system. | ||
| * This method is intended to be wrapped by concrete builder methods in subclasses. | ||
| * | ||
| * @template K - The property key being set | ||
| * @param key - The property key to set | ||
| * @param value - The value to assign to the property | ||
| * @returns A new builder instance with the property set and type state updated | ||
| * @protected | ||
| */ | ||
| protected setProperty<K extends keyof T>(key: K, value: T[K]): this & CeriosBrand<Pick<T, K>>; | ||
| /** | ||
| * Sets multiple property values at once and returns a new builder instance with updated type state. | ||
| * @param props - An object with one or more properties to set. | ||
| * @returns A new builder instance with the properties set and type state updated. | ||
| * @protected | ||
| */ | ||
| protected setProperties<K extends keyof T>(props: Pick<T, K>): this & CeriosBrand<Pick<T, K>>; | ||
| /** | ||
| * Adds a value to an array property and returns a new builder instance with updated type state. | ||
| * This method is intended to be wrapped by concrete builder methods in subclasses for array properties. | ||
| * | ||
| * @template K - The property key (must be an array property) | ||
| * @template V - The type of the array element | ||
| * @param key - The array property key to add to | ||
| * @param value - The value to add to the array | ||
| * @returns A new builder instance with the array property updated and type state updated | ||
| * @protected | ||
| */ | ||
| protected addToArrayProperty<K extends { | ||
| [P in keyof T]: NonNullable<T[P]> extends Array<any> ? P : never; | ||
| }[keyof T], V extends T[K] extends Array<infer U> ? U : T[K] extends Array<infer U> | undefined ? U : never>(key: K, value: V): this & CeriosBrand<Pick<T, K>>; | ||
| /** | ||
| * Builds the final object. This method uses TypeScript's contextual typing to ensure | ||
@@ -32,4 +87,13 @@ * all required fields are set before allowing build() to be called. | ||
| * The type constraint checks that all required properties are present. | ||
| * | ||
| * @returns The fully built object of type T | ||
| * @throws {TypeError} If called without all required fields set (compile-time error) | ||
| */ | ||
| build(this: this & CeriosBrand<T>): T; | ||
| /** | ||
| * Builds a partial object, which may not have all required fields set. | ||
| * This is useful for scenarios where you want to inspect or validate the current state before finalizing. | ||
| * | ||
| * @returns The partially built object | ||
| */ | ||
| buildPartial(): Partial<T>; | ||
@@ -36,0 +100,0 @@ } |
+55
-1
@@ -29,2 +29,8 @@ "use strict"; | ||
| var CeriosBuilder = class { | ||
| /** | ||
| * Creates a new builder instance. Intended to be called by subclasses. | ||
| * | ||
| * @param _actual - The current partial state of the object being built | ||
| * @protected | ||
| */ | ||
| constructor(_actual) { | ||
@@ -35,3 +41,9 @@ this._actual = _actual; | ||
| * Sets a property value and returns a new builder instance with updated type state. | ||
| * This method tracks which properties have been set via the type system. | ||
| * This method is intended to be wrapped by concrete builder methods in subclasses. | ||
| * | ||
| * @template K - The property key being set | ||
| * @param key - The property key to set | ||
| * @param value - The value to assign to the property | ||
| * @returns A new builder instance with the property set and type state updated | ||
| * @protected | ||
| */ | ||
@@ -46,2 +58,35 @@ setProperty(key, value) { | ||
| /** | ||
| * Sets multiple property values at once and returns a new builder instance with updated type state. | ||
| * @param props - An object with one or more properties to set. | ||
| * @returns A new builder instance with the properties set and type state updated. | ||
| * @protected | ||
| */ | ||
| setProperties(props) { | ||
| const BuilderClass = this.constructor; | ||
| return new BuilderClass({ | ||
| ...this._actual, | ||
| ...props | ||
| }); | ||
| } | ||
| /** | ||
| * Adds a value to an array property and returns a new builder instance with updated type state. | ||
| * This method is intended to be wrapped by concrete builder methods in subclasses for array properties. | ||
| * | ||
| * @template K - The property key (must be an array property) | ||
| * @template V - The type of the array element | ||
| * @param key - The array property key to add to | ||
| * @param value - The value to add to the array | ||
| * @returns A new builder instance with the array property updated and type state updated | ||
| * @protected | ||
| */ | ||
| addToArrayProperty(key, value) { | ||
| var _a; | ||
| const BuilderClass = this.constructor; | ||
| const currentArray = (_a = this._actual[key]) != null ? _a : []; | ||
| return new BuilderClass({ | ||
| ...this._actual, | ||
| [key]: [...currentArray, value] | ||
| }); | ||
| } | ||
| /** | ||
| * Builds the final object. This method uses TypeScript's contextual typing to ensure | ||
@@ -51,2 +96,5 @@ * all required fields are set before allowing build() to be called. | ||
| * The type constraint checks that all required properties are present. | ||
| * | ||
| * @returns The fully built object of type T | ||
| * @throws {TypeError} If called without all required fields set (compile-time error) | ||
| */ | ||
@@ -56,2 +104,8 @@ build() { | ||
| } | ||
| /** | ||
| * Builds a partial object, which may not have all required fields set. | ||
| * This is useful for scenarios where you want to inspect or validate the current state before finalizing. | ||
| * | ||
| * @returns The partially built object | ||
| */ | ||
| buildPartial() { | ||
@@ -58,0 +112,0 @@ return this._actual; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/index.ts","../src/cerios-builder.ts"],"sourcesContent":["export { CeriosBrand, CeriosBuilder } from \"./cerios-builder.js\";\n","/**\n * Unique symbol to track which properties have been set in the builder's type\n */\ndeclare const __brand: unique symbol;\n\n/**\n * Brand type to track set properties at the type level\n */\nexport type CeriosBrand<T> = { [__brand]: T };\n\n/**\n * Base Builder class that provides type-safe building with automatic property setters\n * and compile-time validation of required fields.\n *\n * @template T - The complete type being built\n */\nexport abstract class CeriosBuilder<T extends object> {\n\tprotected constructor(protected readonly _actual: Partial<T>) {}\n\n\t/**\n\t * Sets a property value and returns a new builder instance with updated type state.\n\t * This method tracks which properties have been set via the type system.\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) => any;\n\t\treturn new BuilderClass({\n\t\t\t...this._actual,\n\t\t\t[key]: value,\n\t\t}) as this & CeriosBrand<Pick<T, K>>;\n\t}\n\n\t/**\n\t * Builds the final object. This method uses TypeScript's contextual typing to ensure\n\t * all required fields are set before allowing build() to be called.\n\t *\n\t * The type constraint checks that all required properties are present.\n\t */\n\tbuild(this: this & CeriosBrand<T>): T {\n\t\treturn this._actual as T;\n\t}\n\n\tbuildPartial(): Partial<T> {\n\t\treturn this._actual as Partial<T>;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACgBO,IAAe,gBAAf,MAA+C;AAAA,EAC3C,YAA+B,SAAqB;AAArB;AAAA,EAAsB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMrD,YAA+B,KAAQ,OAA6C;AAC7F,UAAM,eAAe,KAAK;AAC1B,WAAO,IAAI,aAAa;AAAA,MACvB,GAAG,KAAK;AAAA,MACR,CAAC,GAAG,GAAG;AAAA,IACR,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAsC;AACrC,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,eAA2B;AAC1B,WAAO,KAAK;AAAA,EACb;AACD;","names":[]} | ||
| {"version":3,"sources":["../src/index.ts","../src/cerios-builder.ts"],"sourcesContent":["export { CeriosBrand, CeriosBuilder } 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 * 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 * 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 * .build();\n * ```\n *\n * @template T - The complete type being built\n */\nexport abstract class CeriosBuilder<T extends object> {\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 * @protected\n\t */\n\tprotected constructor(protected readonly _actual: Partial<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) => any;\n\t\treturn new BuilderClass({\n\t\t\t...this._actual,\n\t\t\t[key]: value,\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) => any;\n\t\treturn new BuilderClass({\n\t\t\t...this._actual,\n\t\t\t...props,\n\t\t}) as this & CeriosBrand<Pick<T, K>>;\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) => any;\n\t\tconst currentArray = (this._actual[key] as Array<V> | undefined) ?? [];\n\t\treturn new BuilderClass({\n\t\t\t...this._actual,\n\t\t\t[key]: [...currentArray, value],\n\t\t}) as this & CeriosBrand<Pick<T, K>>;\n\t}\n\n\t/**\n\t * Builds the final object. This method uses TypeScript's contextual typing to ensure\n\t * all required fields are set before allowing build() to be called.\n\t *\n\t * The type constraint checks that all required properties are present.\n\t *\n\t * @returns The fully built object of type T\n\t * @throws {TypeError} If called without all required fields set (compile-time error)\n\t */\n\tbuild(this: this & CeriosBrand<T>): 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"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACsCO,IAAe,gBAAf,MAA+C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO3C,YAA+B,SAAqB;AAArB;AAAA,EAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYrD,YAA+B,KAAQ,OAA6C;AAC7F,UAAM,eAAe,KAAK;AAC1B,WAAO,IAAI,aAAa;AAAA,MACvB,GAAG,KAAK;AAAA,MACR,CAAC,GAAG,GAAG;AAAA,IACR,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQU,cAAiC,OAAmD;AAC7F,UAAM,eAAe,KAAK;AAC1B,WAAO,IAAI,aAAa;AAAA,MACvB,GAAG,KAAK;AAAA,MACR,GAAG;AAAA,IACJ,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaU,mBAGR,KAAQ,OAA0C;AA7FrD;AA8FE,UAAM,eAAe,KAAK;AAC1B,UAAM,gBAAgB,UAAK,QAAQ,GAAG,MAAhB,YAA8C,CAAC;AACrE,WAAO,IAAI,aAAa;AAAA,MACvB,GAAG,KAAK;AAAA,MACR,CAAC,GAAG,GAAG,CAAC,GAAG,cAAc,KAAK;AAAA,IAC/B,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,QAAsC;AACrC,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAA2B;AAC1B,WAAO,KAAK;AAAA,EACb;AACD;","names":[]} |
+55
-1
| // src/cerios-builder.ts | ||
| var CeriosBuilder = class { | ||
| /** | ||
| * Creates a new builder instance. Intended to be called by subclasses. | ||
| * | ||
| * @param _actual - The current partial state of the object being built | ||
| * @protected | ||
| */ | ||
| constructor(_actual) { | ||
@@ -8,3 +14,9 @@ this._actual = _actual; | ||
| * Sets a property value and returns a new builder instance with updated type state. | ||
| * This method tracks which properties have been set via the type system. | ||
| * This method is intended to be wrapped by concrete builder methods in subclasses. | ||
| * | ||
| * @template K - The property key being set | ||
| * @param key - The property key to set | ||
| * @param value - The value to assign to the property | ||
| * @returns A new builder instance with the property set and type state updated | ||
| * @protected | ||
| */ | ||
@@ -19,2 +31,35 @@ setProperty(key, value) { | ||
| /** | ||
| * Sets multiple property values at once and returns a new builder instance with updated type state. | ||
| * @param props - An object with one or more properties to set. | ||
| * @returns A new builder instance with the properties set and type state updated. | ||
| * @protected | ||
| */ | ||
| setProperties(props) { | ||
| const BuilderClass = this.constructor; | ||
| return new BuilderClass({ | ||
| ...this._actual, | ||
| ...props | ||
| }); | ||
| } | ||
| /** | ||
| * Adds a value to an array property and returns a new builder instance with updated type state. | ||
| * This method is intended to be wrapped by concrete builder methods in subclasses for array properties. | ||
| * | ||
| * @template K - The property key (must be an array property) | ||
| * @template V - The type of the array element | ||
| * @param key - The array property key to add to | ||
| * @param value - The value to add to the array | ||
| * @returns A new builder instance with the array property updated and type state updated | ||
| * @protected | ||
| */ | ||
| addToArrayProperty(key, value) { | ||
| var _a; | ||
| const BuilderClass = this.constructor; | ||
| const currentArray = (_a = this._actual[key]) != null ? _a : []; | ||
| return new BuilderClass({ | ||
| ...this._actual, | ||
| [key]: [...currentArray, value] | ||
| }); | ||
| } | ||
| /** | ||
| * Builds the final object. This method uses TypeScript's contextual typing to ensure | ||
@@ -24,2 +69,5 @@ * all required fields are set before allowing build() to be called. | ||
| * The type constraint checks that all required properties are present. | ||
| * | ||
| * @returns The fully built object of type T | ||
| * @throws {TypeError} If called without all required fields set (compile-time error) | ||
| */ | ||
@@ -29,2 +77,8 @@ build() { | ||
| } | ||
| /** | ||
| * Builds a partial object, which may not have all required fields set. | ||
| * This is useful for scenarios where you want to inspect or validate the current state before finalizing. | ||
| * | ||
| * @returns The partially built object | ||
| */ | ||
| buildPartial() { | ||
@@ -31,0 +85,0 @@ return this._actual; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/cerios-builder.ts"],"sourcesContent":["/**\n * Unique symbol to track which properties have been set in the builder's type\n */\ndeclare const __brand: unique symbol;\n\n/**\n * Brand type to track set properties at the type level\n */\nexport type CeriosBrand<T> = { [__brand]: T };\n\n/**\n * Base Builder class that provides type-safe building with automatic property setters\n * and compile-time validation of required fields.\n *\n * @template T - The complete type being built\n */\nexport abstract class CeriosBuilder<T extends object> {\n\tprotected constructor(protected readonly _actual: Partial<T>) {}\n\n\t/**\n\t * Sets a property value and returns a new builder instance with updated type state.\n\t * This method tracks which properties have been set via the type system.\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) => any;\n\t\treturn new BuilderClass({\n\t\t\t...this._actual,\n\t\t\t[key]: value,\n\t\t}) as this & CeriosBrand<Pick<T, K>>;\n\t}\n\n\t/**\n\t * Builds the final object. This method uses TypeScript's contextual typing to ensure\n\t * all required fields are set before allowing build() to be called.\n\t *\n\t * The type constraint checks that all required properties are present.\n\t */\n\tbuild(this: this & CeriosBrand<T>): T {\n\t\treturn this._actual as T;\n\t}\n\n\tbuildPartial(): Partial<T> {\n\t\treturn this._actual as Partial<T>;\n\t}\n}\n"],"mappings":";AAgBO,IAAe,gBAAf,MAA+C;AAAA,EAC3C,YAA+B,SAAqB;AAArB;AAAA,EAAsB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMrD,YAA+B,KAAQ,OAA6C;AAC7F,UAAM,eAAe,KAAK;AAC1B,WAAO,IAAI,aAAa;AAAA,MACvB,GAAG,KAAK;AAAA,MACR,CAAC,GAAG,GAAG;AAAA,IACR,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAsC;AACrC,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,eAA2B;AAC1B,WAAO,KAAK;AAAA,EACb;AACD;","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 * 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 * 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 * .build();\n * ```\n *\n * @template T - The complete type being built\n */\nexport abstract class CeriosBuilder<T extends object> {\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 * @protected\n\t */\n\tprotected constructor(protected readonly _actual: Partial<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) => any;\n\t\treturn new BuilderClass({\n\t\t\t...this._actual,\n\t\t\t[key]: value,\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) => any;\n\t\treturn new BuilderClass({\n\t\t\t...this._actual,\n\t\t\t...props,\n\t\t}) as this & CeriosBrand<Pick<T, K>>;\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) => any;\n\t\tconst currentArray = (this._actual[key] as Array<V> | undefined) ?? [];\n\t\treturn new BuilderClass({\n\t\t\t...this._actual,\n\t\t\t[key]: [...currentArray, value],\n\t\t}) as this & CeriosBrand<Pick<T, K>>;\n\t}\n\n\t/**\n\t * Builds the final object. This method uses TypeScript's contextual typing to ensure\n\t * all required fields are set before allowing build() to be called.\n\t *\n\t * The type constraint checks that all required properties are present.\n\t *\n\t * @returns The fully built object of type T\n\t * @throws {TypeError} If called without all required fields set (compile-time error)\n\t */\n\tbuild(this: this & CeriosBrand<T>): 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"],"mappings":";AAsCO,IAAe,gBAAf,MAA+C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO3C,YAA+B,SAAqB;AAArB;AAAA,EAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYrD,YAA+B,KAAQ,OAA6C;AAC7F,UAAM,eAAe,KAAK;AAC1B,WAAO,IAAI,aAAa;AAAA,MACvB,GAAG,KAAK;AAAA,MACR,CAAC,GAAG,GAAG;AAAA,IACR,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQU,cAAiC,OAAmD;AAC7F,UAAM,eAAe,KAAK;AAC1B,WAAO,IAAI,aAAa;AAAA,MACvB,GAAG,KAAK;AAAA,MACR,GAAG;AAAA,IACJ,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaU,mBAGR,KAAQ,OAA0C;AA7FrD;AA8FE,UAAM,eAAe,KAAK;AAC1B,UAAM,gBAAgB,UAAK,QAAQ,GAAG,MAAhB,YAA8C,CAAC;AACrE,WAAO,IAAI,aAAa;AAAA,MACvB,GAAG,KAAK;AAAA,MACR,CAAC,GAAG,GAAG,CAAC,GAAG,cAAc,KAAK;AAAA,IAC/B,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,QAAsC;AACrC,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAA2B;AAC1B,WAAO,KAAK;AAAA,EACb;AACD;","names":[]} |
+2
-2
| { | ||
| "name": "@cerios/cerios-builder", | ||
| "version": "1.0.0", | ||
| "version": "1.1.0", | ||
| "author": "Ronald Veth - Cerios", | ||
| "description": "A TypeScript project with Jest testing framework", | ||
| "description": "A TypeScript builder pattern library providing compile-time type safety for object construction with method chaining and required field validation", | ||
| "license": "MIT", | ||
@@ -7,0 +7,0 @@ "keywords": ["typescript", "builder-pattern", "object-construction", "cerios"], |
+65
-20
@@ -13,2 +13,3 @@ # @cerios/cerios-builder | ||
| - **TypeScript First**: Built with TypeScript, for TypeScript | ||
| - **Array Property Helpers**: Easily add values to array properties with type safety | ||
@@ -39,2 +40,3 @@ ## ๐ฆ Installation | ||
| age?: number; // Optional property | ||
| roles?: string[]; // Optional array property | ||
| }; | ||
@@ -44,6 +46,2 @@ | ||
| class UserBuilder extends CeriosBuilder<User> { | ||
| private constructor(data: Partial<User>) { | ||
| super(data); | ||
| } | ||
| static create() { | ||
@@ -69,2 +67,7 @@ return new UserBuilder({}); | ||
| // New: Add to array property | ||
| addRole(role: string) { | ||
| return this.addToArrayProperty('roles', role); | ||
| } | ||
| // Custom methods for common patterns | ||
@@ -90,5 +93,7 @@ withRandomId() { | ||
| .age(30) | ||
| .addRole("admin") // Add to array property | ||
| .addRole("editor") | ||
| .build(); | ||
| // โ Optional fields can be omitted | ||
| // โ Optional fields and arrays can be omitted | ||
| const basicUser = UserBuilder.create() | ||
@@ -98,3 +103,3 @@ .id("456") | ||
| .email("jane@example.com") | ||
| .build(); // age is optional, so this works | ||
| .build(); // age and roles are optional | ||
@@ -115,2 +120,3 @@ // โ This won't compile - missing required 'email' field | ||
| .withAdminEmail("admin") | ||
| .addRole("admin") | ||
| .age(25) | ||
@@ -120,3 +126,3 @@ .build(); | ||
| console.log(adminUser); | ||
| // Output: { id: "550e8400-...", name: "Admin User", email: "admin@admin.company.com", age: 25 } | ||
| // Output: { id: "550e8400-...", name: "Admin User", email: "admin@admin.company.com", roles: ["admin"], age: 25 } | ||
| ``` | ||
@@ -132,6 +138,2 @@ | ||
| class ProductBuilder extends CeriosBuilder<Product> { | ||
| private constructor(data: Partial<Product>) { | ||
| super(data); | ||
| } | ||
| static create() { | ||
@@ -153,2 +155,7 @@ return new ProductBuilder({}); | ||
| // Add to array property | ||
| addTag(tag: string) { | ||
| return this.addToArrayProperty('tags', tag); | ||
| } | ||
| // Custom methods for testing | ||
@@ -173,2 +180,4 @@ asElectronics() { | ||
| .asElectronics() | ||
| .addTag("featured") | ||
| .addTag("sale") | ||
| .build(); | ||
@@ -192,9 +201,6 @@ ``` | ||
| phoneNumber?: string; | ||
| notes?: string[]; | ||
| }; | ||
| class AddressBuilder extends CeriosBuilder<Address> { | ||
| private constructor(data: Partial<Address>) { | ||
| super(data); | ||
| } | ||
| static create() { | ||
@@ -204,2 +210,9 @@ return new AddressBuilder({}); | ||
| static createWithDefaults() { | ||
| return this.create().setProperties({ | ||
| city: "Othertown", | ||
| country: "United States", | ||
| }); | ||
| } | ||
| street(value: string) { | ||
@@ -228,6 +241,2 @@ return this.setProperty('street', value); | ||
| class CustomerBuilder extends CeriosBuilder<Customer> { | ||
| private constructor(data: Partial<Customer>) { | ||
| super(data); | ||
| } | ||
| static create() { | ||
@@ -253,2 +262,7 @@ return new CustomerBuilder({}); | ||
| // Add to array property | ||
| addNote(note: string) { | ||
| return this.addToArrayProperty('notes', note); | ||
| } | ||
| // Build address inline | ||
@@ -259,5 +273,15 @@ withAddress(builderFn: (builder: AddressBuilder) => AddressBuilder & CeriosBrand<Address>) { | ||
| } | ||
| // Build address with defaults (pre-sets city and country) | ||
| withAddressDefaults( | ||
| builderFn: ( | ||
| builder: AddressBuilder & CeriosBrand<Pick<Address, "city" | "country">> | ||
| ) => AddressBuilder & CeriosBrand<Address> | ||
| ) { | ||
| const address = builderFn(AddressBuilder.createWithDefaults()).build(); | ||
| return this.setProperty('address', address); | ||
| } | ||
| } | ||
| // Usage | ||
| // Usage with full address | ||
| const customer = CustomerBuilder.create() | ||
@@ -272,4 +296,17 @@ .id('CUST-001') | ||
| ) | ||
| .addNote("VIP customer") | ||
| .addNote("Prefers email contact") | ||
| .phoneNumber('+1-555-0123') | ||
| .build(); | ||
| // Usage with defaults (only set street, city/country are pre-filled) | ||
| const customerWithDefaults = CustomerBuilder.create() | ||
| .id('CUST-002') | ||
| .name('Bob Smith') | ||
| .withAddressDefaults(addr => addr.street('456 Elm St')) // city and country are already set to defaults | ||
| .addNote("New customer") | ||
| .build(); | ||
| console.log(customerWithDefaults); | ||
| // Output: { id: 'CUST-002', name: 'Bob Smith', address: { street: '456 Elm St', city: 'Othertown', country: 'United States' }, notes: ['New customer'] } | ||
| ``` | ||
@@ -285,2 +322,3 @@ | ||
| .name("Unknown User") | ||
| .addRole("guest") | ||
| .buildPartial(); // Returns Partial<User> | ||
@@ -305,2 +343,3 @@ | ||
| .email('test@example.com') | ||
| .addRole('tester') | ||
| .age(25) | ||
@@ -313,2 +352,3 @@ .build(); | ||
| expect(result.user.name).toBe('Test User'); | ||
| expect(result.user.roles).toContain('tester'); | ||
| }); | ||
@@ -321,2 +361,3 @@ | ||
| .email('ageless@example.com') | ||
| .addRole('guest') | ||
| .build(); | ||
@@ -328,2 +369,3 @@ | ||
| expect(result.user.age).toBeUndefined(); | ||
| expect(result.user.roles).toContain('guest'); | ||
| }); | ||
@@ -342,2 +384,3 @@ }); | ||
| // Oops! Forgot required email field | ||
| roles: ["admin"] | ||
| }; | ||
@@ -356,2 +399,3 @@ | ||
| .email("john@example.com") // Required - won't compile without it | ||
| .addRole("admin") | ||
| .build(); | ||
@@ -372,2 +416,3 @@ | ||
| - `setProperty<K>(key: K, value: T[K])` - Sets a property and returns a new builder instance | ||
| - `addToArrayProperty<K, V>(key: K, value: V)` - Adds a value to an array property and returns a new builder instance | ||
| - `build()` - Builds the final object (only available when all required properties are set) | ||
@@ -374,0 +419,0 @@ - `buildPartial()` - Builds a partial object with currently set properties |
40568
99.32%295
139.84%408
12.4%