162 lines
5.4 KiB
JavaScript
162 lines
5.4 KiB
JavaScript
/**
|
|
* Macro Processor
|
|
* Handles macro execution and result rendering
|
|
*/
|
|
|
|
class MacroProcessor {
|
|
constructor(webdavClient) {
|
|
this.webdavClient = webdavClient;
|
|
this.plugins = new Map();
|
|
this.includeStack = []; // Track includes to detect cycles
|
|
this.registerDefaultPlugins();
|
|
}
|
|
|
|
/**
|
|
* Register a macro plugin
|
|
* Plugin must implement: { canHandle(actor, method), process(macro, webdavClient) }
|
|
*/
|
|
registerPlugin(actor, method, plugin) {
|
|
const key = `${actor}.${method}`;
|
|
this.plugins.set(key, plugin);
|
|
}
|
|
|
|
/**
|
|
* Process all macros in content
|
|
* Returns { success: boolean, content: string, errors: [] }
|
|
*/
|
|
async processMacros(content) {
|
|
console.log('MacroProcessor: Starting macro processing for content:', content);
|
|
const macros = MacroParser.extractMacros(content);
|
|
console.log('MacroProcessor: Extracted macros:', macros);
|
|
const errors = [];
|
|
let processedContent = content;
|
|
|
|
// Process macros in reverse order to preserve positions
|
|
for (let i = macros.length - 1; i >= 0; i--) {
|
|
const macro = macros[i];
|
|
console.log('MacroProcessor: Processing macro:', macro);
|
|
|
|
try {
|
|
const result = await this.processMacro(macro);
|
|
console.log('MacroProcessor: Macro processing result:', result);
|
|
|
|
if (result.success) {
|
|
// Replace macro with result
|
|
processedContent =
|
|
processedContent.substring(0, macro.start) +
|
|
result.content +
|
|
processedContent.substring(macro.end);
|
|
} else {
|
|
errors.push({
|
|
macro: macro.fullMatch,
|
|
error: result.error
|
|
});
|
|
|
|
// Replace with error message
|
|
const errorMsg = `\n\n⚠️ **Macro Error**: ${result.error}\n\n`;
|
|
processedContent =
|
|
processedContent.substring(0, macro.start) +
|
|
errorMsg +
|
|
processedContent.substring(macro.end);
|
|
}
|
|
} catch (error) {
|
|
errors.push({
|
|
macro: macro.fullMatch,
|
|
error: error.message
|
|
});
|
|
|
|
const errorMsg = `\n\n⚠️ **Macro Error**: ${error.message}\n\n`;
|
|
processedContent =
|
|
processedContent.substring(0, macro.start) +
|
|
errorMsg +
|
|
processedContent.substring(macro.end);
|
|
}
|
|
}
|
|
|
|
console.log('MacroProcessor: Final processed content:', processedContent);
|
|
return {
|
|
success: errors.length === 0,
|
|
content: processedContent,
|
|
errors
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Process single macro
|
|
*/
|
|
async processMacro(macro) {
|
|
const key = `${macro.actor}.${macro.method}`;
|
|
const plugin = this.plugins.get(key);
|
|
|
|
// Check for circular includes
|
|
if (macro.method === 'include') {
|
|
const path = macro.params.path || macro.params[''];
|
|
if (this.includeStack.includes(path)) {
|
|
return {
|
|
success: false,
|
|
error: `Circular include detected: ${this.includeStack.join(' → ')} → ${path}`
|
|
};
|
|
}
|
|
}
|
|
|
|
if (!plugin) {
|
|
return {
|
|
success: false,
|
|
error: `Unknown macro: !!${key}`
|
|
};
|
|
}
|
|
|
|
// Validate macro
|
|
const validation = MacroParser.validateMacro(macro);
|
|
if (!validation.valid) {
|
|
return { success: false, error: validation.error };
|
|
}
|
|
|
|
// Execute plugin
|
|
try {
|
|
return await plugin.process(macro, this.webdavClient);
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
error: `Plugin error: ${error.message}`
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Register default plugins
|
|
*/
|
|
registerDefaultPlugins() {
|
|
// Include plugin
|
|
this.registerPlugin('core', 'include', {
|
|
process: async (macro, webdavClient) => {
|
|
const path = macro.params.path || macro.params[''];
|
|
|
|
if (!path) {
|
|
return {
|
|
success: false,
|
|
error: 'include macro requires "path" parameter'
|
|
};
|
|
}
|
|
|
|
try {
|
|
// Add to include stack
|
|
this.includeStack.push(path);
|
|
const content = await webdavClient.includeFile(path);
|
|
// Remove from include stack
|
|
this.includeStack.pop();
|
|
return { success: true, content };
|
|
} catch (error) {
|
|
// Remove from include stack on error
|
|
this.includeStack.pop();
|
|
return {
|
|
success: false,
|
|
error: `Failed to include "${path}": ${error.message}`
|
|
};
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
window.MacroProcessor = MacroProcessor; |