UNPKG

mlld

Version:

mlld: a modular prompt scripting language

1,567 lines (1,558 loc) 2.84 MB
#!/usr/bin/env node 'use strict'; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. __defProp(target, "default", { value: mod, enumerable: true }) , mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); // services/fs/NodeFileSystem.ts var fs, path, _NodeFileSystem, NodeFileSystem; var init_NodeFileSystem = __esm({ "services/fs/NodeFileSystem.ts"() { fs = __toESM(require("fs/promises")); path = __toESM(require("path")); _NodeFileSystem = class _NodeFileSystem { async readFile(filePath) { return await fs.readFile(filePath, "utf-8"); } async writeFile(filePath, content) { const dir = path.dirname(filePath); await fs.mkdir(dir, { recursive: true }); await fs.writeFile(filePath, content, "utf-8"); } async exists(filePath) { try { await fs.access(filePath); return true; } catch { return false; } } async mkdir(dirPath, options) { await fs.mkdir(dirPath, options); } async readdir(dirPath) { return await fs.readdir(dirPath); } async isDirectory(filePath) { try { const stats = await fs.stat(filePath); return stats.isDirectory(); } catch { return false; } } async stat(filePath) { const stats = await fs.stat(filePath); return { isDirectory: /* @__PURE__ */ __name(() => stats.isDirectory(), "isDirectory"), isFile: /* @__PURE__ */ __name(() => stats.isFile(), "isFile") }; } }; __name(_NodeFileSystem, "NodeFileSystem"); NodeFileSystem = _NodeFileSystem; } }); // services/fs/PathService.ts var path2, _PathService, PathService; var init_PathService = __esm({ "services/fs/PathService.ts"() { path2 = __toESM(require("path")); _PathService = class _PathService { // Basic path operations resolve(...segments) { return path2.resolve(...segments); } relative(from, to) { return path2.relative(from, to); } join(...segments) { return path2.join(...segments); } dirname(filePath) { return path2.dirname(filePath); } basename(filePath, ext) { return path2.basename(filePath, ext); } extname(filePath) { return path2.extname(filePath); } isAbsolute(filePath) { return path2.isAbsolute(filePath); } normalize(filePath) { return path2.normalize(filePath); } // URL support isURL(path61) { try { const url = new URL(path61); return url.protocol === "http:" || url.protocol === "https:"; } catch { return false; } } async validateURL(url) { if (!this.isURL(url)) { throw new Error(`Invalid URL: ${url}`); } return url; } async fetchURL(url) { await this.validateURL(url); const response = await fetch(url); if (!response.ok) { throw new Error(`Failed to fetch URL: ${response.status} ${response.statusText}`); } const content = await response.text(); const headers = {}; response.headers.forEach((value, key) => { headers[key] = value; }); return { content, headers }; } }; __name(_PathService, "PathService"); PathService = _PathService; } }); // grammar/generated/parser/grammar-core.js var import_crypto, acorn, NodeType, DirectiveKind, helpers; var init_grammar_core = __esm({ "grammar/generated/parser/grammar-core.js"() { import_crypto = require("crypto"); acorn = __toESM(require("acorn")); NodeType = { Text: "Text", Comment: "Comment", CodeFence: "CodeFence", MlldRunBlock: "MlldRunBlock", VariableReference: "VariableReference", Directive: "Directive", PathSeparator: "PathSeparator", DotSeparator: "DotSeparator", Literal: "Literal", SectionMarker: "SectionMarker", Error: "Error", Newline: "Newline", StringLiteral: "StringLiteral", Frontmatter: "Frontmatter", CommandBase: "CommandBase", Parameter: "Parameter", ExecInvocation: "ExecInvocation", CommandReference: "CommandReference", FileReference: "FileReference", BinaryExpression: "BinaryExpression", TernaryExpression: "TernaryExpression", UnaryExpression: "UnaryExpression", WhenExpression: "WhenExpression" }; DirectiveKind = { run: "run", var: "var", show: "show", exe: "exe", for: "for", path: "path", import: "import", output: "output", when: "when" }; helpers = { debug(msg, ...args) { if (process.env.DEBUG_MLLD_GRAMMAR) console.log("[DEBUG GRAMMAR]", msg, ...args); }, isLogicalLineStart(input, pos) { if (pos === 0) return true; let i = pos - 1; while (i >= 0 && " \r".includes(input[i])) i--; return i < 0 || input[i] === "\n"; }, // Context Detection System - Core Helper Methods // --------------------------------------------- /** * Determines if the current position represents a slash directive context * A slash directive context requires: * 1. / symbol at logical line start * 2. Followed by a valid directive keyword */ isSlashDirectiveContext(input, pos) { if (input[pos] !== "/") return false; const isAtLineStart = this.isLogicalLineStart(input, pos); if (!isAtLineStart) return false; const directiveKeywords = Object.keys(DirectiveKind); const afterSlashPos = pos + 1; for (const keyword of directiveKeywords) { if (afterSlashPos + keyword.length > input.length) continue; const potentialKeyword = input.substring(afterSlashPos, afterSlashPos + keyword.length); if (potentialKeyword === keyword) { if (afterSlashPos + keyword.length === input.length) return true; const nextChar = input[afterSlashPos + keyword.length]; if (" \r\n".includes(nextChar)) return true; } } return false; }, /** * Determines if the current position represents a variable reference context * A variable context requires: * 1. @ symbol NOT at logical line start, or * 2. @ at line start but NOT followed by directive keyword */ isAtVariableContext(input, pos) { if (input[pos] !== "@") return false; if (this.isSlashDirectiveContext(input, pos)) return false; return true; }, /** * Determines if the current position is within a right-hand side (RHS) expression * RHS contexts are after assignment operators (=, :) in directive bodies */ isRHSContext(input, pos) { if (pos === 0) return false; let i = pos - 1; let inString = false; let stringChar = null; let foundEquals = false; while (i >= 0) { const char = input[i]; if ((char === '"' || char === "'") && (i === 0 || input[i - 1] !== "\\")) { if (!inString) { inString = true; stringChar = char; } else if (char === stringChar) { inString = false; stringChar = null; } } if (!inString) { if (char === "=" || char === ":") { foundEquals = true; break; } if (char === ";" || char === "\n") { return false; } } i--; } if (foundEquals) { let j = i - 1; while (j >= 0 && " \r".includes(input[j])) { j--; } let name = ""; while (j >= 0 && /[a-zA-Z0-9_]/.test(input[j])) { name = input[j] + name; j--; } if (j >= 0 && input[j] === "/") { const validAssignmentDirectives = [ "exec", "text", "data", "run" ]; if (validAssignmentDirectives.includes(name)) { if (this.isLogicalLineStart(input, j)) { return true; } } } return false; } return false; }, /** * Determines if the current position represents plain text context * Plain text is any context that isn't a directive, variable, or RHS */ isPlainTextContext(input, pos) { return !this.isSlashDirectiveContext(input, pos) && !this.isAtVariableContext(input, pos) && !this.isRHSContext(input, pos); }, /** * Determines if the current position is within a run code block context * This is used to identify language + code block patterns */ isInRunCodeBlockContext(input, pos) { return false; }, createNode(type, props) { if (!props.location && process.env.DEBUG_MLLD_GRAMMAR) { console.warn(`WARNING: Creating ${type} node without location data`); if (process.env.DEBUG_MLLD_GRAMMAR_TRACE) { console.trace(); } } return Object.freeze({ type, nodeId: (0, import_crypto.randomUUID)(), location: props.location, ...props }); }, createDirective(kind, data) { return this.createNode(NodeType.Directive, { directive: { kind, ...data } }); }, // New method for creating directives with the updated structure createStructuredDirective(kind, subtype, values, raw, meta, locationData, source = null) { return this.createNode(NodeType.Directive, { kind, subtype, source, values, raw, meta, location: locationData }); }, createVariableReferenceNode(valueType, data, location) { if (!location) { throw new Error(`Location is required for createVariableReferenceNode (valueType: ${valueType}, identifier: ${data.identifier || "unknown"})`); } return this.createNode(NodeType.VariableReference, { valueType, ...data, location }); }, normalizePathVar(id) { return id; }, validateRunContent: /* @__PURE__ */ __name(() => true, "validateRunContent"), validateDefineContent: /* @__PURE__ */ __name(() => true, "validateDefineContent"), validatePath(pathParts, directiveKind) { const raw = this.reconstructRawString(pathParts).trim(); let hasVariables = false; if (pathParts && pathParts.length > 0) { for (const node of pathParts) { if (node.type === NodeType.VariableReference) { hasVariables = true; } } } const finalFlags = { hasVariables }; const result = { raw, values: pathParts, ...finalFlags }; this.debug("PATH", "validatePath final result:", JSON.stringify(result, null, 2)); return result; }, getImportSubtype(list) { if (!list) return "importAll"; if (list.length === 0) return "importAll"; if (list.length === 1 && list[0].name === "*") return "importAll"; return "importSelected"; }, trace(pos, reason) { }, reconstructRawString(nodes) { if (!Array.isArray(nodes)) { if (nodes && typeof nodes === "object") { if (nodes.type === NodeType.Text) return nodes.content || ""; if (nodes.type === NodeType.VariableReference) { const varId = nodes.identifier; const valueType = nodes.valueType; const fields = nodes.fields || []; let fieldPath = ""; for (const field of fields) { if (field.type === "field" || field.type === "dot") { fieldPath += `.${field.name || field.value}`; } else if (field.type === "array") { fieldPath += `[${field.index}]`; } } if (valueType === "varInterpolation") { return `{{${varId}${fieldPath}}}`; } else if (valueType === "varIdentifier") { return `@${varId}${fieldPath}`; } else { return `{{${varId}${fieldPath}}}`; } } } return String(nodes || ""); } let raw = ""; for (const node of nodes) { if (!node) continue; if (node.type === NodeType.Text) { raw += node.content || ""; } else if (node.type === NodeType.VariableReference) { const varId = node.identifier; const valueType = node.valueType; const fields = node.fields || []; let fieldPath = ""; for (const field of fields) { if (field.type === "field" || field.type === "dot") { fieldPath += `.${field.name || field.value}`; } else if (field.type === "array") { fieldPath += `[${field.index}]`; } } if (valueType === "varInterpolation") { raw += `{{${varId}${fieldPath}}}`; } else if (valueType === "varIdentifier") { raw += `@${varId}${fieldPath}`; } else { raw += `{{${varId}${fieldPath}}}`; } } else if (node.type === NodeType.PathSeparator) { raw += node.value || ""; } else if (node.type === NodeType.SectionMarker) { raw += node.value || ""; } else if (node.type === NodeType.StringLiteral) { raw += node.value || ""; } else if (typeof node === "string") { raw += node; } else { raw += node.content || node.value || node.raw || ""; } } return raw; }, createPathMetadata(rawPath, parts) { return { hasVariables: parts.some((p) => p && p.type === NodeType.VariableReference), isAbsolute: rawPath.startsWith("/"), hasExtension: /\.[a-zA-Z0-9]+$/.test(rawPath), extension: rawPath.match(/\.([a-zA-Z0-9]+)$/)?.[1] || null }; }, createCommandMetadata(parts) { return { hasVariables: parts.some((p) => p && p.type === NodeType.VariableReference) }; }, createTemplateMetadata(parts, wrapperType) { return { hasVariables: parts.some((p) => p && (p.type === NodeType.VariableReference || p.type === NodeType.ExecInvocation)), isTemplateContent: wrapperType === "doubleBracket" }; }, createUrlMetadata(protocol, parts, hasSection = false) { return { isUrl: true, protocol, hasVariables: parts.some((p) => p && p.type === NodeType.VariableReference), hasSection }; }, ttlToSeconds(value, unit) { const multipliers = { "seconds": 1, "minutes": 60, "hours": 3600, "days": 86400, "weeks": 604800 }; return value * (multipliers[unit] || 1); }, createSecurityMeta(options) { if (!options) return {}; const meta = {}; if (options.ttl) { meta.ttl = options.ttl; } if (options.trust) { meta.trust = options.trust; } return meta; }, detectFormatFromPath(path61) { const ext = path61.match(/\.([a-zA-Z0-9]+)$/)?.[1]?.toLowerCase(); if (!ext) return null; const formatMap = { "json": "json", "xml": "xml", "yaml": "yaml", "yml": "yaml", "csv": "csv", "md": "markdown", "markdown": "markdown", "txt": "text", "text": "text" }; return formatMap[ext] || null; }, createSectionMeta(pathParts, sectionParts, hasRename) { return { sourceType: "section", hasVariables: [ ...pathParts, ...sectionParts ].some((part) => part && part.type === "VariableReference"), hasRename }; }, reconstructSectionPath(pathParts, sectionParts) { const pathStr = this.reconstructRawString(pathParts); const sectionStr = this.reconstructRawString(sectionParts); return `${pathStr} # ${sectionStr}`; }, /** * Checks if we're at a bracket that should end command parsing * This uses a specific heuristic: ] at end of input OR ] on its own line */ isCommandEndingBracket(input, pos) { if (input[pos] !== "]") return false; const nextPos = pos + 1; if (nextPos >= input.length) return true; let i = nextPos; while (i < input.length && (input[i] === " " || input[i] === " ")) { i++; } return i >= input.length || input[i] === "\n"; }, /** * Parse command content that may contain variables and text segments * This is used by the CommandBracketContent rule to handle @var interpolation * * @param content - The content to parse * @param baseLocation - The location of the content in the source */ parseCommandContent(content, baseLocation) { const parts = []; let i = 0; let currentText = ""; let textStartOffset = 0; if (!baseLocation) { console.warn("parseCommandContent called without baseLocation"); return this.parseCommandContentLegacy(content); } let currentOffset = baseLocation.start.offset; let currentLine = baseLocation.start.line; let currentColumn = baseLocation.start.column; while (i < content.length) { if (content[i] === "@" && i + 1 < content.length) { if (currentText) { const textEndOffset = currentOffset; const textEndLine = currentLine; const textEndColumn = currentColumn; parts.push(this.createNode(NodeType.Text, { content: currentText, location: { start: { offset: baseLocation.start.offset + textStartOffset, line: baseLocation.start.line, column: baseLocation.start.column + textStartOffset }, end: { offset: textEndOffset, line: textEndLine, column: textEndColumn } } })); currentText = ""; } const varStartOffset = currentOffset; const varStartLine = currentLine; const varStartColumn = currentColumn; i++; currentOffset++; currentColumn++; let varName = ""; while (i < content.length && /[a-zA-Z0-9_]/.test(content[i])) { varName += content[i]; i++; currentOffset++; currentColumn++; } if (varName) { const varEndOffset = currentOffset; const varEndLine = currentLine; const varEndColumn = currentColumn; parts.push(this.createVariableReferenceNode("varIdentifier", { identifier: varName }, { start: { offset: varStartOffset, line: varStartLine, column: varStartColumn }, end: { offset: varEndOffset, line: varEndLine, column: varEndColumn } })); textStartOffset = i; } else { currentText += "@"; } } else { if (currentText === "") { textStartOffset = i; } currentText += content[i]; if (content[i] === "\n") { currentLine++; currentColumn = 1; } else { currentColumn++; } currentOffset++; i++; } } if (currentText) { parts.push(this.createNode(NodeType.Text, { content: currentText, location: { start: { offset: baseLocation.start.offset + textStartOffset, line: baseLocation.start.line, column: baseLocation.start.column + textStartOffset }, end: { offset: currentOffset, line: currentLine, column: currentColumn } } })); } return parts; }, /** * Legacy version of parseCommandContent for backward compatibility * Creates nodes without proper location data */ parseCommandContentLegacy(content) { const parts = []; let i = 0; let currentText = ""; while (i < content.length) { if (content[i] === "@" && i + 1 < content.length) { if (currentText) { parts.push(this.createNode(NodeType.Text, { content: currentText })); currentText = ""; } i++; let varName = ""; while (i < content.length && /[a-zA-Z0-9_]/.test(content[i])) { varName += content[i]; i++; } if (varName) { parts.push(this.createNode(NodeType.Text, { content: "@" + varName })); } else { currentText += "@"; } } else { currentText += content[i]; i++; } } if (currentText) { parts.push(this.createNode(NodeType.Text, { content: currentText })); } return parts; }, /** * Create an ExecInvocation node */ createExecInvocation(commandRef, withClause, location) { return this.createNode("ExecInvocation", { commandRef, withClause: withClause || null, location }); }, /** * Get the command name from an ExecInvocation node */ getExecInvocationName(node) { if (!node || node.type !== "ExecInvocation") return null; return node.commandRef?.identifier || node.commandRef?.name; }, /** * Check if a node is an ExecInvocation */ isExecInvocationNode(node) { return node?.type === "ExecInvocation"; }, /** * Parse a JavaScript code block using acorn to find the complete block * This handles nested braces, strings, template literals, etc. properly * * @param input - The full input string * @param startPos - Position after the opening brace * @returns The parsed code content and end position, or null if invalid */ parseJavaScriptBlock(input, startPos) { const potentialCode = input.substring(startPos); let lastValidEnd = -1; let lastValidCode = ""; for (let i = 0; i < potentialCode.length; i++) { if (potentialCode[i] !== "}") continue; const testCode = potentialCode.substring(0, i); try { acorn.parse(`(${testCode})`, { ecmaVersion: "latest", allowReturnOutsideFunction: true }); lastValidEnd = i; lastValidCode = testCode; } catch (e) { try { acorn.parse(testCode, { ecmaVersion: "latest", allowReturnOutsideFunction: true, sourceType: "module" }); lastValidEnd = i; lastValidCode = testCode; } catch (e2) { } } } if (lastValidEnd >= 0) { return { content: lastValidCode.trim(), endPos: startPos + lastValidEnd }; } return null; }, // Array vs Path disambiguation helpers for /var directive createEmptyArray(location) { return { type: "array", items: [], location }; }, createArrayFromContent(content, location) { return { type: "array", items: content, location }; }, createSectionExtraction(content, location) { return { type: "section", path: content.path, section: content.section, location }; }, createPathDereference(content, location) { return { type: "path", segments: content, location }; }, createObjectFromProperties(properties, location) { return { type: "object", properties: properties || {}, location }; }, // Error Recovery Helper Functions // -------------------------------- /** * Checks if an array is unclosed by scanning ahead * Returns true if we hit a newline before finding the closing bracket */ isUnclosedArray(input, pos) { let depth = 1; let i = pos; let hasHash = false; this.debug("isUnclosedArray starting at pos", pos, "first 50 chars:", input.substring(pos, pos + 50)); while (i < input.length && depth > 0) { const char = input[i]; if (char === "[") { depth++; this.debug("Found [ at", i, "depth now", depth); } else if (char === "]") { depth--; this.debug("Found ] at", i, "depth now", depth); } else if (char === "#" && depth === 1) { hasHash = true; this.debug("Found # at", i, "in brackets - this is section syntax"); } else if (char === "\n" && depth > 0) { if (!hasHash) { this.debug("Found newline at", i, "without # - unclosed array"); return true; } this.debug("Found newline at", i, "but has # - continuing scan"); } i++; } const result = depth > 0; this.debug("isUnclosedArray finished: result=", result, "hasHash=", hasHash, "depth=", depth, "scanned to pos", i); return result; }, /** * Checks if an object is unclosed by scanning ahead * Returns true if we hit a newline before finding the closing brace */ isUnclosedObject(input, pos) { let depth = 1; let i = pos; let inString = false; let stringChar = null; while (i < input.length && depth > 0) { const char = input[i]; if ((char === '"' || char === "'") && (i === 0 || input[i - 1] !== "\\")) { if (!inString) { inString = true; stringChar = char; } else if (char === stringChar) { inString = false; stringChar = null; } } if (!inString) { if (char === "{") depth++; else if (char === "}") depth--; else if (char === "\n" && depth > 0) return true; } i++; } return depth > 0; }, /** * Checks if a string quote is unclosed * Returns true if we hit a newline or end of input before finding the closing quote */ detectMissingQuoteClose(input, pos, quoteChar) { let i = pos; while (i < input.length) { if (input[i] === quoteChar && input[i - 1] !== "\\") return false; if (input[i] === "\n") return true; i++; } return true; }, /** * Checks if a template delimiter (::) is unclosed */ isUnclosedTemplate(input, pos) { let i = pos; while (i < input.length - 1) { if (input[i] === ":" && input[i + 1] === ":") return false; i++; } return true; }, /** * Checks if we're at the start of what looks like a multiline array * (array with newline after opening bracket) */ isMultilineArrayStart(input, pos) { let i = pos; while (i < input.length && (input[i] === " " || input[i] === " ")) { i++; } return i < input.length && input[i] === "\n"; }, /** * Scans ahead to check if this looks like a valid language identifier for /run */ isValidLanguageKeyword(input, pos, lang) { const validLanguages = [ "js", "javascript", "node", "python", "py", "bash", "sh" ]; return validLanguages.includes(lang.toLowerCase()); }, /** * Checks if we're missing a 'from' keyword in an import statement */ isMissingFromKeyword(input, pos) { let i = pos; while (i < input.length && (input[i] === " " || input[i] === " ")) { i++; } if (i < input.length) { const char = input[i]; return char === '"' || char === "'" || char === "[" || char === "@"; } return false; }, /** * Create an error with enhanced location tracking * Since we can't access parser internals from here, we'll just throw * a regular error and let the parser enhance it */ mlldError(message, expectedToken, loc) { const error = new Error(message); error.isMlldError = true; error.expectedToken = expectedToken; error.mlldErrorLocation = loc; throw error; }, // Parser State Management for Code Blocks // ---------------------------------------- // These functions help prevent state corruption when parsing multiple // complex functions in mlld-run blocks /** * Parser state tracking object * Used to detect and prevent state corruption issues */ parserState: { codeBlockDepth: 0, braceDepth: 0, inString: false, stringChar: null, lastDirectiveEndPos: -1, functionCount: 0, maxNestingDepth: 20 }, /** * Reset parser state between functions * This prevents state corruption when parsing multiple complex functions */ resetCodeParsingState() { this.parserState.braceDepth = 0; this.parserState.inString = false; this.parserState.stringChar = null; this.parserState.functionCount++; this.debug("Parser state reset", { functionCount: this.parserState.functionCount, lastEndPos: this.parserState.lastDirectiveEndPos }); }, /** * Get current brace depth for debugging and limits */ getBraceDepth() { return this.parserState.braceDepth; }, /** * Increment brace depth with overflow checking */ incrementBraceDepth() { this.parserState.braceDepth++; if (this.parserState.braceDepth > this.parserState.maxNestingDepth) { this.mlldError(`Code block nesting too deep (${this.parserState.braceDepth} levels). Consider simplifying your function or splitting it into smaller functions.`); } }, /** * Decrement brace depth with underflow checking */ decrementBraceDepth() { this.parserState.braceDepth--; if (this.parserState.braceDepth < 0) { this.debug("WARNING: Brace depth underflow detected", { depth: this.parserState.braceDepth, functionCount: this.parserState.functionCount }); this.parserState.braceDepth = 0; } }, /** * Validate parser state consistency * Returns true if state is valid, false if corrupted */ validateParserState() { const isValid = this.parserState.braceDepth >= 0 && this.parserState.braceDepth <= this.parserState.maxNestingDepth; if (!isValid) { this.debug("Parser state validation failed", { braceDepth: this.parserState.braceDepth, inString: this.parserState.inString, functionCount: this.parserState.functionCount }); } return isValid; }, /** * Mark the end of a directive for state tracking */ markDirectiveEnd(pos) { this.parserState.lastDirectiveEndPos = pos; }, // File Reference Helper Functions // -------------------------------- /** * Checks if content inside <...> represents a file reference * File references are detected by presence of: . * @ * Note: We don't include / since we don't support directories * Files without extensions can be used outside interpolation contexts */ isFileReferenceContent(content) { return /[.*@]/.test(content); }, /** * Creates a FileReference AST node */ createFileReferenceNode(source, fields, pipes, location) { return { type: "FileReference", nodeId: (0, import_crypto.randomUUID)(), source, fields: fields || [], pipes: pipes || [], location, meta: { isFileReference: true, hasGlob: typeof source === "object" && source.raw && source.raw.includes("*"), isPlaceholder: source && source.type === "placeholder" } }; }, // Binary expression builder with left-to-right associativity createBinaryExpression(first, rest, location) { if (!rest || rest.length === 0) return first; return rest.reduce((left, { op, right }) => this.createNode("BinaryExpression", { operator: op, left, right, location }), first); }, // Check if nodes contain newlines containsNewline(nodes) { if (!Array.isArray(nodes)) nodes = [ nodes ]; return nodes.some((n) => n.type === "Newline" || n.content && n.content.includes("\n") || n.raw && n.raw.includes("\n")); }, /** * Creates a WhenExpression node for RHS when expressions */ createWhenExpression(conditions, withClause, location) { return this.createNode(NodeType.WhenExpression, { conditions, withClause: withClause || null, meta: { conditionCount: conditions.length, isValueReturning: true, evaluationType: "expression", hasTailModifiers: !!withClause }, location }); }, /** * Creates a ForExpression node for for...in expressions in /var assignments */ createForExpression(variable, source, expression, location) { return { type: "ForExpression", nodeId: (0, import_crypto.randomUUID)(), variable, source, expression: Array.isArray(expression) ? expression : [ expression ], location, meta: { isForExpression: true } }; }, /** * Creates an action node for /for directive actions */ createForActionNode(directive, content, location) { const kind = directive; return [ this.createNode(NodeType.Directive, { kind, subtype: kind, values: { content: Array.isArray(content) ? content : [ content ] }, raw: { content: this.reconstructRawString(content) }, meta: { implicit: false }, location }) ]; } }; } }); // grammar/generated/parser/deps/node-type.js var node_type_default; var init_node_type = __esm({ "grammar/generated/parser/deps/node-type.js"() { init_grammar_core(); node_type_default = NodeType; } }); // grammar/generated/parser/deps/directive-kind.js var directive_kind_default; var init_directive_kind = __esm({ "grammar/generated/parser/deps/directive-kind.js"() { init_grammar_core(); directive_kind_default = DirectiveKind; } }); // grammar/generated/parser/deps/helpers.js var helpers_default; var init_helpers = __esm({ "grammar/generated/parser/deps/helpers.js"() { init_grammar_core(); helpers_default = helpers; } }); // grammar/generated/parser/parser.js function peg$subclass(child, parent) { function C() { this.constructor = child; } __name(C, "C"); C.prototype = parent.prototype; child.prototype = new C(); } function peg$SyntaxError(message, expected, found, location) { var self = Error.call(this, message); if (Object.setPrototypeOf) { Object.setPrototypeOf(self, peg$SyntaxError.prototype); } self.expected = expected; self.found = found; self.location = location; self.name = "SyntaxError"; return self; } function peg$padEnd(str, targetLength, padString) { padString = padString || " "; if (str.length > targetLength) { return str; } targetLength -= str.length; padString += padString.repeat(targetLength); return str + padString.slice(0, targetLength); } function peg$parse(input, options) { options = options !== void 0 ? options : {}; var peg$FAILED = {}; var peg$source = options.grammarSource; var peg$startRuleFunctions = { Start: peg$parseStart }; var peg$startRuleFunction = peg$parseStart; var peg$c0 = ">>"; var peg$c1 = "<<"; var peg$c2 = "\n"; var peg$c3 = "{{"; var peg$c4 = "}}"; var peg$c5 = "::"; var peg$c6 = "```"; var peg$c7 = "mlld-run"; var peg$c8 = "---"; var peg$c9 = "'"; var peg$c11 = "."; var peg$c12 = "true"; var peg$c13 = "false"; var peg$c14 = "null"; var peg$c15 = "*"; var peg$c16 = "[["; var peg$c17 = "]]"; var peg$c18 = "\\"; var peg$c19 = "<"; var peg$c20 = '"'; var peg$c21 = "`"; var peg$c22 = "/"; var peg$c23 = "#"; var peg$c24 = "/var"; var peg$c25 = "/show"; var peg$c26 = "/run"; var peg$c27 = "/exe"; var peg$c28 = "/path"; var peg$c29 = "/import"; var peg$c30 = "/when"; var peg$c31 = "/output"; var peg$c32 = "\r\n"; var peg$c33 = ">"; var peg$c34 = "https"; var peg$c35 = "http"; var peg$c36 = "://"; var peg$c37 = "@"; var peg$c38 = " as "; var peg$c39 = "as"; var peg$c40 = "<>"; var peg$c41 = "["; var peg$c42 = "]"; var peg$c43 = ","; var peg$c44 = "|"; var peg$c45 = "&&"; var peg$c46 = "||"; var peg$c47 = ";"; var peg$c48 = "run"; var peg$c49 = "npx"; var peg$c50 = "npm"; var peg$c51 = "yarn"; var peg$c52 = "pnpm"; var peg$c53 = "bun"; var peg$c54 = ":"; var peg$c55 = "-m"; var peg$c56 = "python"; var peg$c57 = "python3"; var peg$c58 = "python2"; var peg$c59 = "node"; var peg$c60 = "sh"; var peg$c61 = "bash"; var peg$c62 = "zsh"; var peg$c63 = "perl"; var peg$c64 = "ruby"; var peg$c65 = "-e"; var peg$c66 = "-c"; var peg$c67 = "make"; var peg$c68 = "cargo"; var peg$c69 = "go"; var peg$c70 = "gradle"; var peg$c71 = "maven"; var peg$c72 = "mvn"; var peg$c73 = "rake"; var peg$c74 = "("; var peg$c75 = ")"; var peg$c76 = ":::"; var peg$c77 = "{"; var peg$c78 = "}"; var peg$c79 = "?"; var peg$c80 = "=="; var peg$c81 = "!="; var peg$c82 = "<="; var peg$c83 = ">="; var peg$c84 = "="; var peg$c85 = "!"; var peg$c86 = "foreach"; var peg$c87 = "with"; var peg$c88 = "separator"; var peg$c89 = "template"; var peg$c90 = "in"; var peg$c91 = "output"; var peg$c92 = "to"; var peg$c93 = "show"; var peg$c94 = "var"; var peg$c95 = "trust"; var peg$c96 = "needs"; var peg$c97 = "@run"; var peg$c98 = "stdout"; var peg$c99 = "stderr"; var peg$c100 = "env"; var peg$c101 = "s"; var peg$c102 = "file"; var peg$c103 = "//"; var peg$c104 = "\\\\"; var peg$c105 = "\\@"; var peg$c106 = "live"; var peg$c107 = "static"; var peg$c108 = "always"; var peg$c109 = "verify"; var peg$c110 = "never"; var peg$c111 = "&>"; var peg$c112 = "&"; var peg$c113 = "pipeline"; var peg$c114 = "[("; var peg$c115 = ")]"; var peg$c116 = "/*"; var peg$c117 = "*/"; var peg$c118 = "js"; var peg$c119 = "javascript"; var peg$c120 = "when"; var peg$c121 = "=>"; var peg$c122 = "for"; var peg$c123 = "each"; var peg$c124 = "now"; var peg$c125 = "base"; var peg$c126 = "input"; var peg$c127 = "debug"; var peg$c128 = "frontmatter"; var peg$c129 = "fm"; var peg$c130 = "format"; var peg$c131 = "asSection"; var peg$c132 = "from"; var peg$c133 = "nodejs"; var peg$c134 = "py"; var peg$c135 = "risk.high"; var peg$c136 = "risk.med"; var peg$c137 = "risk.low"; var peg$c138 = "risk"; var peg$c139 = "about"; var peg$c140 = "meta"; var peg$c141 = "/for"; var peg$c142 = "@item"; var peg$c143 = "@input"; var peg$c144 = "@now"; var peg$c145 = "@time"; var peg$c146 = "@stdin"; var peg$c147 = "env:"; var peg$c148 = "PROJECTPATH"; var peg$c149 = "under"; var peg$c150 = "any"; var peg$c151 = "all"; var peg$c152 = "first"; var peg$r0 = /^[ \t\r]/; var peg$r1 = /^[^\n]/; var peg$r2 = /^[ \t]/; var peg$r3 = /^[^`\r\n]/; var peg$r4 = /^[0-9]/; var peg$r5 = /^["$'@[-\]`{}]/; var peg$r6 = /^["'.0\\nrt]/; var peg$r7 = /^[ \t\r\n\/\]@${{}"'`]/; var peg$r8 = /^[\/[\]@${}]/; var peg$r9 = /^[\]\/[\]@${}]/; var peg$r10 = /^[\]]/; var peg$r11 = /^[a-zA-Z_]/; var peg$r12 = /^[a-zA-Z0-9_]/; var peg$r13 = /^[.~]/; var peg$r14 = /^[ \t\r\n\u200B\u200C\u200D]/; var peg$r15 = /^[ \t\r\n]/; var peg$r16 = /^[ \t\r\u200B\u200C\u200D]/; var peg$r17 = /^[\r\u2028-\u2029]/; var peg$r18 = /^[^\r\n]/; var peg$r19 = /^[<"]/; var peg$r20 = /^[`<@]/; var peg$r21 = /^[a-zA-Z0-9.\-]/; var peg$r22 = /^[^> ]/; var peg$r23 = /^[^@|&;[\]\n \t]/; var peg$r24 = /^[a-zA-Z0-9_\-]/; var peg$r25 = /^[a-zA-Z0-9_:\-]/; var peg$r26 = /^[a-zA-Z0-9_.\/\-]/; var peg$r27 = /^["'),`]/; var peg$r28 = /^["'),\\`]/; var peg$r29 = /^["@<\n\r]/; var peg$r30 = /^[`@<]/; var peg$r31 = /^[<@]/; var peg$r32 = /^[ \t\r\n\/\]{}]/; var peg$r33 = /^[^[\n]/; var peg$r34 = /^[^\]]/; var peg$r35 = /^[(.-\/]/; var peg$r36 = /^[a-zA-Z0-9_@\-]/; var peg$r37 = /^[a-zA-Z0-9_\/@\-]/; var peg$r38 = /^[^ \t\n\r]/; var peg$r39 = /^[^ \t\n\r"'[\]]/; var peg$r40 = /^[^\/s]/; var peg$r41 = /^[^"]/; var peg$r42 = /^[^']/; var peg$r43 = /^[^@\\s\n]/; var peg$r44 = /^[\]"'\r\n]/; var peg$r45 = /^[dhmsw]/; var peg$r46 = /^[<>]/; var peg$r47 = /^[&>]/; var peg$r48 = /^[^"@]/; var peg$r49 = /^[^@|&;<> \t\n\r"']/; var peg$r50 = /^[^}]/; var peg$r51 = /^[ \t\n\r]/; var peg$r52 = /^[^#\]]/; var peg$r53 = /^[^\\s\\n]/; var peg$r54 = /^[^)]/; var peg$r55 = /^[a-f0-9]/; var peg$r56 = /^[^,)]/; var peg$e0 = peg$classExpectation([ " ", " ", "\r" ], false, false); var peg$e1 = peg$literalExpectation(">>", false); var peg$e2 = peg$literalExpectation("<<", false); var peg$e3 = peg$classExpectation([ "\n" ], true, false); var peg$e4 = peg$literalExpectation("\n", false); var peg$e5 = peg$literalExpectation("{{", false); var peg$e6 = peg$literalExpectation("}}", false); var peg$e7 = peg$literalExpectation("::", false); var peg$e8 = peg$anyExpectation(); var peg$e9 = peg$classExpectation([ " ", " " ], false, false); var peg$e10 = peg$literalExpectation("```", false); var peg$e11 = peg$literalExpectation("mlld-run", false); var peg$e12 = peg$classExpectation([ "`", "\r", "\n" ], true, false); var peg$e13 = peg$otherExpectation("Top-level directive context"); var peg$e14 = peg$otherExpectation("Variable reference context"); var peg$e15 = peg$otherExpectation("Right-hand side context"); var peg$e16 = peg$otherExpectation("Plain text context"); var peg$e17 = peg$otherExpectation("Run-style code block context"); var peg$e18 = peg$otherExpectation("Exec /run right-hand side context"); var peg$e19 = peg$otherExpectation("Path starting with @variable context"); var peg$e20 = peg$otherExpectation("Directive boundary"); var peg$e21 = peg$otherExpectation("YAML frontmatter"); var peg$e22 = peg$literalExpectation("---", false); var peg$e23 = peg$otherExpectation("String Literal"); var peg$e24 = peg$literalExpectation("'", false); var peg$e25 = peg$otherExpectation("Number Literal"); var peg$e26 = peg$literalExpectation("-", false); var peg$e27 = peg$classExpectation([ [ "0", "9" ] ], false, false); var peg$e28 = peg$literalExpectation(".", false); var peg$e29 = peg$otherExpectation("Boolean Literal"); var peg$e30 = peg$literalExpectation("true", false); var peg$e31 = peg$literalExpectation("false", false); var peg$e32 = peg$otherExpectation("Null Literal"); var peg$e33 = peg$literalExpectation("null", false); var peg$e34 = peg$otherExpectation("Wildcard Literal"); var peg$e35 = peg$literalExpectation("*", false); var peg$e36 = peg$otherExpectation("Multi-line Template Literal"); var peg$e37 = peg$literalExpectation("[[", false); var peg$e38 = peg$literalExpectation("]]", false); var peg$e39 = peg$otherExpectation("Escape sequence"); var peg$e40 = peg$literalExpectation("\\", false); var peg$e41 = peg$classExpectation([ '"', "$", "'", "@", [ "[", "]" ], "`", "{", "}" ], false, false); var peg$e42 = peg$otherExpectation("String escape sequence"); var peg$e43 = peg$classExpectation([ '"', "'", ".", "0", "\\", "n", "r", "t" ], false, false); var peg$e44 = peg$otherExpectation("Plain text segment"); var peg$e45 = peg$classExpectation([ " ", " ", "\r", "\n", "/", "]", "@", "$", "{", "{", "}", '"', "'", "`" ], false, false); var peg$e46 = peg$otherExpectation("Template text segment"); var peg$e47 = peg$literalExpectation("<", false); var peg$e48 = peg$otherExpectation("Command text segment"); var peg$e49 = peg$classExpectation([ "/", "[", "]", "@", "$", "{", "}" ], false, false); var peg$e50 = peg$otherExpectation("Path text segment"); var peg$e51 = peg$classExpectation([ "]", "/", "[", "]", "@", "$", "{", "}" ], false, false); var peg$e52 = peg$otherExpectation("Section text segment"); var peg$e53 = peg$classExpectation([ "]" ], false, false); var peg$e54 = peg$otherExpectation("String content with escapes"); var peg$e55 = peg$literalExpectation('"', false); var peg$e56 = peg$otherExpectation("Single-quoted string content with escapes"); var peg$e57 = peg$otherExpectation("Backtick string content with escapes"); var peg$e58 = peg$literalExpectation("`", false); var peg$e59 = peg$otherExpectation("Path separator"); var peg$e60 = peg$literalExpectation("/", false); var peg$e61 = peg$otherExpectation("Dot separator"); var peg$e62 = peg$otherExpectation("Section marker"); var peg$e63 = peg$literalExpectation("#", false); var peg$e64 = peg$otherExpectation("Identifier"); var peg$e65 = peg$classExpectation([ [ "a", "z" ], [ "A", "Z" ], "_" ], false, false); var peg$e66 = peg$classExpectation([ [ "a", "z"