Files
markdown_editor/static/js/macro-parser.js
2025-10-26 10:52:27 +04:00

149 lines
4.6 KiB
JavaScript

/**
* Macro Parser and Processor
* Parses HeroScript-style macros from markdown content
*/
class MacroParser {
/**
* Extract macros with improved parsing
*/
static extractMacros(content) {
const macroRegex = /!!([\w.]+)\s*([\s\S]*?)(?=\n!!|\n#|$)/g;
const macros = [];
let match;
while ((match = macroRegex.exec(content)) !== null) {
const fullMatch = match[0];
const actionPart = match[1];
const paramsPart = match[2];
const [actor, method] = actionPart.includes('.')
? actionPart.split('.')
: ['core', actionPart];
const params = this.parseParams(paramsPart);
console.log(`[MacroParser] Extracted: !!${actor}.${method}`, params);
macros.push({
fullMatch: fullMatch.trim(),
actor,
method,
params,
start: match.index,
end: match.index + fullMatch.length
});
}
return macros;
}
/**
* Parse HeroScript parameters with multiline support
* Supports:
* key: 'value'
* key: '''multiline value'''
* key: |
* multiline
* value
*/
static parseParams(paramsPart) {
const params = {};
if (!paramsPart || !paramsPart.trim()) {
return params;
}
let lines = paramsPart.split('\n');
let i = 0;
while (i < lines.length) {
const line = lines[i].trim();
if (!line) {
i++;
continue;
}
// Check for key: value pattern
if (line.includes(':')) {
const colonIndex = line.indexOf(':');
const key = line.substring(0, colonIndex).trim();
let value = line.substring(colonIndex + 1).trim();
// Handle triple-quoted multiline
if (value.startsWith("'''")) {
value = value.substring(3);
const valueLines = [value];
i++;
while (i < lines.length) {
const contentLine = lines[i];
if (contentLine.trim().endsWith("'''")) {
valueLines.push(contentLine.trim().slice(0, -3));
break;
}
valueLines.push(contentLine);
i++;
}
// Remove leading whitespace from multiline
const processedValue = this.dedent(valueLines.join('\n'));
params[key] = processedValue;
}
// Handle pipe multiline
else if (value === '|') {
const valueLines = [];
i++;
while (i < lines.length && lines[i].startsWith('\t')) {
valueLines.push(lines[i].substring(1)); // Remove tab
i++;
}
i--; // Back up one since loop will increment
const processedValue = this.dedent(valueLines.join('\n'));
params[key] = processedValue;
}
// Handle quoted value
else if (value.startsWith("'") && value.endsWith("'")) {
params[key] = value.slice(1, -1);
}
// Handle unquoted value
else {
params[key] = value;
}
}
i++;
}
console.log(`[MacroParser] Parsed parameters:`, params);
return params;
}
/**
* Remove common leading whitespace from multiline strings
*/
static dedent(text) {
const lines = text.split('\n');
// Find minimum indentation
let minIndent = Infinity;
for (const line of lines) {
if (line.trim().length === 0) continue;
const indent = line.search(/\S/);
minIndent = Math.min(minIndent, indent);
}
if (minIndent === Infinity) minIndent = 0;
// Remove common indentation
return lines
.map(line => line.slice(minIndent))
.join('\n')
.trim();
}
}
window.MacroParser = MacroParser;