149 lines
4.6 KiB
JavaScript
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; |