UNPKG

sussy-util

Version:
133 lines (132 loc) 5.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.GenericBuilder = void 0; const StringUtil_1 = __importDefault(require("./StringUtil")); /** * A builder for creating instances of the `GenericBuilder` class, * allowing construction of instances of a specified class using fluent API-style method calls. * * @template T - The type of the class for which a builder is to be generated. * @template Mode - The mode for the builder: 'constructorReading' or 'objectPropertyReading'. */ class BuilderBuilder { /** * Creates an instance of the BuilderBuilder. * @param {Function} ClassType - The constructor of the target class for which a builder is to be generated. * @param {Mode} [CreationType='objectPropertyReading'] - Specifies the method used for creating the builder: * - "constructorReading": Parses instance variables based on the constructor's signature. * - "objectPropertyReading": Generates setters based on the class's properties. * * IMPORTANT: The target class's constructor should work with no properties given. */ constructor(ClassType, CreationType = 'objectPropertyReading') { this.ClassType = ClassType; this.CreationType = CreationType; } /** * Builds and returns a constructor for a generic builder class associated with the target class. * * @returns {Constructor<GenericBuilder<T, Mode>>} A constructor function for the generic builder class. */ build() { return GenericBuilder.bind(GenericBuilder, this.ClassType, this.CreationType); } } exports.default = BuilderBuilder; /** * A generic builder class for creating instances of a given class using a fluent API. * * @template T - The target class type for which an instance is being built. * @template Mode - Determines the builder's mode: * - 'constructorReading': Uses constructor arguments for building. * - 'objectPropertyReading': Uses object properties for building. */ class GenericBuilder { /** * Initializes the builder for the specified class and mode. * * @param {Constructor<T>} ClassType - The constructor of the class to build. * @param {Mode} Type - The mode for the builder: * - "objectPropertyReading": Builds using object properties. * - "constructorReading": Builds using constructor parameters. */ constructor(ClassType, Type) { this.ClassType = ClassType; this.Type = Type; this.attributes = {}; this.args = []; if (Type === 'objectPropertyReading') { this.createSettersFromProperties(); } else { this.createSettersFromConstructorParameters(); } Object.preventExtensions(this); } /** * Generates setter methods based on the properties of the class instance. * This is used when the builder mode is 'objectPropertyReading'. * * @private */ createSettersFromProperties() { const instance = new this.ClassType(); for (const key in instance) { if (!Object.prototype.hasOwnProperty.call(instance, key)) continue; const typedKey = key; const methodName = `set${StringUtil_1.default.capitalize(key)}`; const method = (value) => { this.attributes[typedKey] = value; return this; }; this.defineMethod(methodName, method); } } /** * Generates setter methods based on the constructor parameters of the class. * This is used when the builder mode is 'constructorReading'. * * @private */ createSettersFromConstructorParameters() { const paramCount = this.ClassType.length; for (let i = 0; i < paramCount; i++) { const methodName = `setArg${i}`; const method = (value) => { this.args[i] = value; return this; }; this.defineMethod(methodName, method); } } /** * Dynamically defines a method on the builder. * * @param {string} name - The name of the method to define. * @param {AnyFunction} method - The function to assign to the method. * @private */ defineMethod(name, method) { Object.defineProperty(this, name, { get: () => method, set: (_value) => { throw new Error(`You cannot overwrite this property with another. ${_value}`); }, }); } /** * Builds and returns an instance of the target class. * * @returns {T} An instance of the class specified by `ClassType`. */ build() { if (this.Type === 'objectPropertyReading') { return Object.assign(new this.ClassType(), this.attributes); } return new this.ClassType(...this.args); } } exports.GenericBuilder = GenericBuilder;