import { Env } from "./Env"; export class ConfigTemplate { public static Empty: ConfigTemplate = new ConfigTemplate(); constructor(text: string = "") { this._contentText = text; this.extractParams(); } private _contentText: string = ""; private _params: string[] = []; public get content(): string { return this._contentText; } public get Params(): string[] { return [...this._params]; } private extractParams() { let regex = /@(\w+)@/g; let matches; let paramsSet = new Set(); while ((matches = regex.exec(this._contentText)) !== null) { if (matches.length > 1) { paramsSet.add(matches[1]); } } this._params = Array.from(paramsSet); } } export class Config { public static get ENV_NAME_PARAM(): string { return "env_name" }; public envs: Env[] = []; public template: ConfigTemplate = ConfigTemplate.Empty; addEnvs(envs: Env[]) { this.envs = envs; } addTemplate(text: string) { this.template = new ConfigTemplate(text); } getTemplateAsJson(): string { try { return this.template.content ; } catch (error) { console.error("Error converting template content to JSON:", error); return "{}"; } } /** * Updates the template JSON by adding/updating params from the given environment. * Params are added as "!!! paramName": "@paramName@" placeholder pairs. * If a param's @placeholder@ already exists in template, it won't be added. * Existing template content is preserved. */ updateTemplateFromEnv(env: Env) { let templateObj: Record = {}; // Try to parse existing template as JSON try { if (this.template.content.trim()) { templateObj = JSON.parse(this.template.content); } } catch (e) { // If parsing fails, start with empty object console.warn("Template is not valid JSON, starting fresh"); } // Add/update params from the environment as placeholders for (const param of env.params) { if (param.name && param.name.trim() !== "") { const placeholderValue = `@${param.name}@`; // Check if this placeholder already exists anywhere in the template const placeholderAlreadyExists = this.template.content.includes(placeholderValue); if (!placeholderAlreadyExists) { const placeholderKey = `!!! ${param.name}`; templateObj[placeholderKey] = placeholderValue; } } } // Convert back to formatted JSON string const newTemplateContent = JSON.stringify(templateObj, null, 4); this.template = new ConfigTemplate(newTemplateContent); } validateParams(): string[] { const envKeys = this.envs.map(env => env.params.map(param => param.name)).flat(); const missingParams = this.template.Params.filter(param => param != Config.ENV_NAME_PARAM && !envKeys.includes(param)); if (missingParams.length > 0) { console.error("Template: missing parameters in environments:", missingParams); } return missingParams; } /** * Validates that all @placeholders@ in template have corresponding params. * Checks DEFAULT env first, then all custom envs. * Returns array of placeholder names that are not defined. */ validatePlaceholders(): string[] { const defaultEnv = this.envs.find(e => e.name === "DEFAULT"); const customEnvs = this.envs.filter(e => e.name !== "DEFAULT"); // Collect all param names from DEFAULT const defaultParamNames = new Set( defaultEnv?.params.map(p => p.name).filter(n => n && n.trim() !== "") || [] ); // Collect all param names from all custom envs const customParamNames = new Set( customEnvs.flatMap(e => e.params.map(p => p.name).filter(n => n && n.trim() !== "")) ); // Extract all @placeholders@ from template const placeholderRegex = /@(\w+)@/g; const placeholdersInTemplate = new Set(); let match; while ((match = placeholderRegex.exec(this.template.content)) !== null) { placeholdersInTemplate.add(match[1]); } // Find placeholders that don't have matching params const missingParams: string[] = []; for (const placeholder of placeholdersInTemplate) { if (placeholder === Config.ENV_NAME_PARAM) continue; // Skip built-in // Check if exists in DEFAULT or in ANY custom env const inDefault = defaultParamNames.has(placeholder); const inCustom = customParamNames.has(placeholder); // Valid if: in DEFAULT, or in at least one custom env if (!inDefault && !inCustom) { missingParams.push(placeholder); } } return missingParams; } }