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