UNPKG

sussy-util

Version:
135 lines (134 loc) 6.04 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const StringUtil_1 = __importDefault(require("./StringUtil")); /** * A generic builder class that facilitates the construction of instances for a specified class * by setting attributes using fluent API-style method calls. * @template T - The type of class for which instances are built. */ class GenericBuilder { /** * Creates an instance of GenericBuilder. * @param {Constructor<T>} ClassType - The constructor function of the class for which instances will be built. * @param {string} Type - The type of builder to create, either "constructorReading" or "objectPropertyReading". */ constructor(ClassType, Type) { this.ClassType = ClassType; this.Type = Type; this.constructorParams = { order: [], attributes: {} }; this.attributes = {}; Type === "objectPropertyReading" ? this.createSettersProperties() : this.createSettersSignature(); Object.preventExtensions(this); } interpretConstructor(input) { input = input.replace(/ /g, ""); const result = []; const regex = /{([^}]*)}|([^,]+)/g; let match; while ((match = regex.exec(input)) !== null) { if (match[1]) { const groupContent = match[1].split(',').map(item => item.trim()); result.push(groupContent); } else if (match[2]) { result.push(match[2].trim()); } } return result; } createSettersProperties() { for (const key in new this.ClassType()) { const methodName = `set${StringUtil_1.default.capitalize(key)}`; const method = (value) => { this.attributes[key] = value; return this; }; this.defineMethod(methodName, method); } } createSettersSignature() { const classSignature = this.ClassType.toString(); const parameterNames = classSignature.match(/\(([^)]*)\)/); if (parameterNames == null) throw new Error("No constructor found."); this.constructorParams.order = this.interpretConstructor(parameterNames[0].substring(1, parameterNames[0].length - 1)); for (let i = 0; i < this.constructorParams.order.length; i++) { if (Array.isArray(this.constructorParams.order[i])) { this.constructorParams.attributes[`param${i}`] = {}; this.constructorParams.attributes[`param${i}`].length = this.constructorParams.order[i].length; for (let j = 0; j < this.constructorParams.order[i].length; j++) { const propName = this.constructorParams.order[i][j]; const methodName = `setParam${i}${StringUtil_1.default.capitalize(propName)}`; const method = (value) => { this.constructorParams.attributes[`param${i}`][propName] = value; return this; }; this.defineMethod(methodName, method); } continue; } const propName = this.constructorParams.order[i]; const methodName = `set${StringUtil_1.default.capitalize(propName)}`; const method = (value) => { this.constructorParams.attributes[propName] = value; return this; }; this.defineMethod(methodName, method); } } defineMethod(name, method) { Object.defineProperty(this, name, { get: () => method, set(_value) { throw new Error("You cannot overwrite this property with another."); } }); } /** * Build and return an instance of the specified class type with the attributes set using the builder methods. * @returns {T} - An instance of the specified class type with attributes set. */ build() { Object.freeze(this.attributes); if (this.Type === "objectPropertyReading") { return Object.assign(new this.ClassType(), this.attributes); } return new this.ClassType(...this.constructorParams.order.map((e, i) => { if (Array.isArray(e)) { return this.constructorParams.attributes[`param${i}`]; } return this.constructorParams.attributes[e]; })); } } /** * 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 class for which instances are built using the GenericBuilder. */ 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 {string} CreationType - Specifies the method used for creating the builder: * - "constructorReading": Parses instance variables based on the constructor's signature. * * IMPORTANT: The constructor must be the first function in the class. * - "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>>} A constructor function for the generic builder class. */ build() { return GenericBuilder.bind(GenericBuilder, this.ClassType, this.CreationType); } } exports.default = BuilderBuilder;