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; |