import { ComponentType, IStructure } from '../types'; export abstract class AbstractComponentBuilder { #state: Partial> = {}; protected constructor(private id: string, private type: TType) {} setLabel(label: string) { this.#state.label = label; return this; } setPlaceholder(placeholder: string) { this.#state.placeholder = placeholder; return this; } protected patch(state: Partial>) { this.#state = { ...this.#state, ...state, }; return this; } protected state() { return { ...this.#state, }; } isValid(): { valid: boolean; messages: string[] } | null { const { label } = this.#state; return this.createValidationResponse() .withCheck('label should be defined', () => !!label) .withCheck('id should be defined', () => !!this.id) .withCheck('type should be defined', () => !!this.type) .validate(); } protected createValidationResponse() { const checks: { message: string; validate: () => boolean; }[] = []; let initialValidationState: { valid: boolean; messages: string[]; } = { valid: true, messages: [], }; const response = { withParentValidation: ( _response: { valid: boolean; messages: string[]; } | null, ) => { if (_response) { // mb merge, but needed atm initialValidationState = { ..._response }; } return response; }, withCheck: (message: string, validate: () => boolean) => { checks.push({ message, validate }); return response; }, validate: () => { return checks.reduce( (acc, check) => { if (!check.validate()) { acc.valid = false; acc.messages.push(check.message); } return acc; }, { ...initialValidationState, id: this.id ?? 'UNKNOWN_FORM_COMPONENT_ID', type: this.type ?? 'UNKNOWN_FORM_COMPONENT_TYPE', }, ); }, }; return response; } build() { return { questionId: this.id, type: this.type, ...this.#state, } as IStructure; } }