UNPKG

protoml-parser

Version:

ProtoML is a lightweight, declarative markup language designed for writing and structuring meeting protocols, notes and task lists in a human-readable and machine-parseable format.

89 lines (67 loc) 2.59 kB
const fs = require("fs") const path = require("path") const { tokenize } = require("./tokenizer") const { parseBlocks } = require("./blockParser") function loadAndMergeImports(mainAst, basePath, options = {}) { if (!mainAst || typeof mainAst !== "object") return mainAst const importLines = findTagImports(mainAst) for (const importFile of importLines) { const fullPath = path.resolve(basePath, importFile) if (!fs.existsSync(fullPath)) { if (options.strict) throw new Error(`Import file not found: ${fullPath}`) else continue } const raw = fs.readFileSync(fullPath, "utf8") const tokens = tokenize(raw) const importedAst = parseBlocks(tokens, options) // Merge relevant blocks (tags, participants, subjects…) for (const key in importedAst) { if (!mainAst[key]) mainAst[key] = {} if (typeof importedAst[key] === "object" && !Array.isArray(importedAst[key])) { mainAst[key] = { ...importedAst[key], ...mainAst[key] } // imported gets overridden by main } } } return mainAst } function findTagImports(ast) { if (!ast || !ast.tags_import) return [] const lines = Array.isArray(ast.tags_import) ? ast.tags_import : [ast.tags_import] return lines .map(line => line.match(/@tags_import\s+"(.+?)"/)) .filter(Boolean) .map(match => match[1]) } const macroCache = {} function loadAndMergeMacros(ast, basePath, options = {}) { if (!ast.macros) return ast for (const name in ast.macros) { const file = ast.macros[name] const fullPath = path.join(basePath, file.replace(/\"/g, "")) if (!fs.existsSync(fullPath)) continue const lines = fs.readFileSync(fullPath, "utf8").split(/\r?\n/) let macroName = null let templateLines = [] let inTemplate = false for (const line of lines) { if (line.startsWith("=name:")) { macroName = line.slice(6).trim() } else if (line.startsWith("=template:")) { inTemplate = true const rest = line.slice(10).trim() if (rest) templateLines.push(rest) } else if (inTemplate && (line.startsWith("@") || line.startsWith("="))) { // Stop reading template inTemplate = false } else if (inTemplate) { templateLines.push(line) } } if (macroName && templateLines.length) { macroCache[macroName] = templateLines.join("\n") } } ast._macroCache = macroCache return ast } module.exports = { loadAndMergeImports, loadAndMergeMacros }