sussy-util
Version:
Util package made by me
133 lines (132 loc) • 5.1 kB
JavaScript
"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;