This commit is contained in:
2025-10-26 10:52:27 +04:00
parent d48e25ce90
commit 8750e0af39
10 changed files with 482 additions and 193 deletions

View File

@@ -5,8 +5,7 @@
class MacroParser {
/**
* Parse and extract all macros from content
* Returns array of { fullMatch, actor, method, params }
* Extract macros with improved parsing
*/
static extractMacros(content) {
const macroRegex = /!!([\w.]+)\s*([\s\S]*?)(?=\n!!|\n#|$)/g;
@@ -15,17 +14,17 @@ class MacroParser {
while ((match = macroRegex.exec(content)) !== null) {
const fullMatch = match[0];
const actionPart = match[1]; // e.g., "include" or "core.include"
const actionPart = match[1];
const paramsPart = match[2];
// Parse action: "method" or "actor.method"
const [actor, method] = actionPart.includes('.')
? actionPart.split('.')
: ['core', actionPart];
// Parse parameters from HeroScript-like syntax
const params = this.parseParams(paramsPart);
console.log(`[MacroParser] Extracted: !!${actor}.${method}`, params);
macros.push({
fullMatch: fullMatch.trim(),
actor,
@@ -40,12 +39,13 @@ class MacroParser {
}
/**
* Parse HeroScript-style parameters
* key: value
* key: 'value with spaces'
* key: |
* multiline
* value
* Parse HeroScript parameters with multiline support
* Supports:
* key: 'value'
* key: '''multiline value'''
* key: |
* multiline
* value
*/
static parseParams(paramsPart) {
const params = {};
@@ -54,49 +54,95 @@ class MacroParser {
return params;
}
// Split by newlines but preserve multiline values
const lines = paramsPart.split('\n');
let currentKey = null;
let currentValue = [];
let lines = paramsPart.split('\n');
let i = 0;
for (const line of lines) {
const trimmed = line.trim();
while (i < lines.length) {
const line = lines[i].trim();
if (!trimmed) continue;
// Check if this is a key: value line
if (trimmed.includes(':')) {
// Save previous key-value
if (currentKey) {
params[currentKey] = currentValue.join('\n').trim();
}
const [key, ...valueParts] = trimmed.split(':');
currentKey = key.trim();
currentValue = [valueParts.join(':').trim()];
} else if (currentKey) {
// Continuation of multiline value
currentValue.push(trimmed);
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++;
}
// Save last key-value
if (currentKey) {
params[currentKey] = currentValue.join('\n').trim();
}
console.log(`[MacroParser] Parsed parameters:`, params);
return params;
}
/**
* Check if macro is valid
* Remove common leading whitespace from multiline strings
*/
static validateMacro(macro) {
if (!macro.actor || !macro.method) {
return { valid: false, error: 'Invalid macro format' };
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);
}
return { valid: true };
if (minIndent === Infinity) minIndent = 0;
// Remove common indentation
return lines
.map(line => line.slice(minIndent))
.join('\n')
.trim();
}
}