...
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user