Skip to main content
Glama
syntaxRuleLoader.js•4.88 kB
/** * Syntax Rule Loader Service * Loads configurable syntax rules from external files or ConfigMaps * Author: Gregorio Elias Roecker Momm */ const fs = require('fs'); const path = require('path'); const logger = require('../utils/logger'); const config = require('../config/config'); class SyntaxRuleLoader { constructor() { this.rulesCache = new Map(); this.rulesDirectory = process.env.SYNTAX_RULES_DIR || path.join(__dirname, '../config/syntax-rules'); this.loadAllRules(); } /** * Load all syntax rule files into memory */ loadAllRules() { try { logger.info('Loading syntax rules from:', { directory: this.rulesDirectory }); // Load general rules this.loadRuleFile('general'); // Load diagram-type-specific rules const diagramTypes = [ 'erDiagram', 'flowchart', 'sequenceDiagram', 'classDiagram', 'stateDiagram', 'gantt', 'journey', 'mindmap', 'timeline', 'requirement', 'sankey-beta', 'xychart-beta', 'kanban', 'block', 'c4', 'quadrant', 'packet', 'architecture', 'treemap' ]; diagramTypes.forEach(type => { this.loadRuleFile(type); }); logger.info('Syntax rules loaded successfully', { totalRules: this.rulesCache.size, availableTypes: Array.from(this.rulesCache.keys()) }); } catch (error) { logger.error('Failed to load syntax rules:', error); throw error; } } /** * Load a specific rule file * @param {string} ruleType - Type of rule file to load */ loadRuleFile(ruleType) { try { const filePath = path.join(this.rulesDirectory, `${ruleType}.txt`); if (fs.existsSync(filePath)) { const content = fs.readFileSync(filePath, 'utf8'); this.rulesCache.set(ruleType, content.trim()); logger.debug(`Loaded syntax rules for ${ruleType}`, { file: filePath, contentLength: content.length }); } else { // Fallback to default rules if file doesn't exist this.rulesCache.set(ruleType, this.getDefaultRules(ruleType)); logger.warn(`Syntax rule file not found, using defaults for ${ruleType}`, { file: filePath }); } } catch (error) { logger.error(`Failed to load syntax rules for ${ruleType}:`, error); this.rulesCache.set(ruleType, this.getDefaultRules(ruleType)); } } /** * Get syntax rules for a specific diagram type * @param {string} diagramType - Type of diagram * @returns {string} Syntax rules text */ getRules(diagramType) { // Get type-specific rules const typeRules = this.rulesCache.get(diagramType) || this.rulesCache.get('general') || ''; // Always include general rules const generalRules = this.rulesCache.get('general') || ''; if (typeRules && typeRules !== generalRules) { return `${generalRules}\n\n${typeRules}`; } return generalRules; } /** * Reload rules from files (for hot reloading) */ reloadRules() { this.rulesCache.clear(); this.loadAllRules(); logger.info('Syntax rules reloaded from files'); } /** * Update a specific rule (for runtime updates) * @param {string} ruleType - Type of rule to update * @param {string} content - New rule content */ updateRule(ruleType, content) { this.rulesCache.set(ruleType, content.trim()); logger.info(`Updated syntax rules for ${ruleType}`, { contentLength: content.length }); } /** * Get default rules if file doesn't exist * @param {string} ruleType - Type of rule * @returns {string} Default rule content */ getDefaultRules(ruleType) { const defaults = { general: `GENERAL MERMAID SYNTAX RULES: - Node IDs: Must start with letter, contain only letters/numbers/underscores - Text with spaces: Must be quoted ["text with spaces"] - Line breaks: Use <br/> tags, never literal breaks`, erDiagram: `ER DIAGRAM SYNTAX RULES: - Declaration: erDiagram - Entity syntax: ENTITY_NAME { datatype column_name constraints } - Relationships: ||--|| = One to one, ||--o{ = One to many - Constraints: PK, FK, UK`, flowchart: `FLOWCHART SYNTAX RULES: - Declaration: flowchart TD - Node shapes: [text] = Rectangle, {text} = Diamond - Arrows: --> = Standard arrow, -->|text| = Labeled arrow`, default: `DIAGRAM SYNTAX RULES: - Follow Mermaid syntax guidelines - Use valid node identifiers - Quote text with spaces or special characters` }; return defaults[ruleType] || defaults.default; } /** * Get available rule types * @returns {Array} List of available rule types */ getAvailableRuleTypes() { return Array.from(this.rulesCache.keys()); } /** * Check if rules are loaded * @returns {boolean} True if rules are loaded */ isLoaded() { return this.rulesCache.size > 0; } } module.exports = SyntaxRuleLoader;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ai-of-mine/fast-mermaid-validator-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server