This commit is contained in:
94
src/utils/templateUtils.ts
Normal file
94
src/utils/templateUtils.ts
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
import * as path from 'path';
|
||||||
|
import * as fs from 'fs-extra';
|
||||||
|
import { Layout, Template, TemplateVariable } from '../models/types';
|
||||||
|
|
||||||
|
export class TemplateUtils {
|
||||||
|
private readonly variablePattern = /\$\{([^}]+)\}/g;
|
||||||
|
|
||||||
|
extractVariables(template: Template): string[] {
|
||||||
|
const variables: string[] = [];
|
||||||
|
const layoutJson = JSON.stringify(template.layout);
|
||||||
|
|
||||||
|
let match: RegExpExecArray | null;
|
||||||
|
while ((match = this.variablePattern.exec(layoutJson)) !== null) {
|
||||||
|
if (!variables.includes(match[1])) {
|
||||||
|
variables.push(match[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
substituteVariables(layout: Layout, variables: Record<string, string>): Layout {
|
||||||
|
const layoutStr = JSON.stringify(layout);
|
||||||
|
let substituted = layoutStr;
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(variables)) {
|
||||||
|
const patterns = [`\\$\\{${key}\\}`, `\\$\\{${key}:([^}]*)\\}`];
|
||||||
|
for (const pattern of patterns) {
|
||||||
|
substituted = substituted.replace(new RegExp(pattern, 'g'), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.parse(substituted) as Layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
async createTemplateFromLayout(
|
||||||
|
name: string,
|
||||||
|
displayName: string,
|
||||||
|
description: string,
|
||||||
|
layout: Layout,
|
||||||
|
variableDefaults?: Record<string, string>
|
||||||
|
): Promise<Template> {
|
||||||
|
const variables: TemplateVariable[] = [];
|
||||||
|
const extractedVars = this.extractVariables({ name, displayName, description, variables: [], layout });
|
||||||
|
|
||||||
|
for (const varName of extractedVars) {
|
||||||
|
const isRequired = !variableDefaults || !variableDefaults[varName];
|
||||||
|
variables.push({
|
||||||
|
name: varName,
|
||||||
|
description: `Variable: ${varName}`,
|
||||||
|
defaultValue: variableDefaults?.[varName],
|
||||||
|
required: isRequired,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
displayName,
|
||||||
|
description,
|
||||||
|
variables,
|
||||||
|
layout,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
validateTemplateVariables(template: Template, providedVars: Record<string, string>): string[] {
|
||||||
|
const missing: string[] = [];
|
||||||
|
|
||||||
|
for (const variable of template.variables) {
|
||||||
|
if (variable.required && !(variable.name in providedVars) && !variable.defaultValue) {
|
||||||
|
missing.push(variable.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return missing;
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveTemplate(template: Template, templatesDir: string): Promise<string> {
|
||||||
|
const filePath = path.join(templatesDir, `${template.name}.json`);
|
||||||
|
await fs.writeJson(filePath, template, { spaces: 2 });
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadTemplate(filePath: string): Promise<Template> {
|
||||||
|
const content = await fs.readFile(filePath, 'utf-8');
|
||||||
|
return JSON.parse(content) as Template;
|
||||||
|
}
|
||||||
|
|
||||||
|
generateTemplatePreview(template: Template, variables: Record<string, string>): string {
|
||||||
|
const substitutedLayout = this.substituteVariables(template.layout, variables);
|
||||||
|
return JSON.stringify(substitutedLayout, null, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const templateUtils = new TemplateUtils();
|
||||||
Reference in New Issue
Block a user