UNPKG

mlld

Version:

mlld: llm scripting language

1,484 lines (1,476 loc) 14 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 __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); // 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, options2) { await fs.mkdir(dirPath, options2); } 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(path67) { try { const url = new URL(path67); 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", // NEW: Replaces text/data show: "show", // NEW: Replaces add exe: "exe", // NEW: Replaces exec for: "for", // For loops path: "path", import: "import", output: "output", when: "when" // NO deprecated entries - clean break! }; helpers = { debug(msg, ...args) { if (process.env.DEBUG_MLLD_GRAMMAR) console.log("[DEBUG GRAMMAR]", msg, ...args); }, isExecutableReference(ref) { if (!ref) return false; if (ref.type === "ExecInvocation") return true; if (ref.type === "FieldAccessExec") return true; if (ref.arguments !== void 0 && ref.arguments !== null) return true; if (ref.hasParentheses === true) return true; return false; }, 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), "log"]; 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; }, /** * DEPRECATED: RHS slashes are no longer supported * Keeping for reference but this should not be used * @deprecated */ isRHSContext(input, pos) { 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); }, /** * 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, // No fallback - let it be undefined if not provided ...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 = { "milliseconds": 1 / 1e3, "seconds": 1, "minutes": 60, "hours": 3600, "days": 86400, "weeks": 604800 }; return value * (multipliers[unit] || 1); }, detectFormatFromPath(path67) { const ext = path67.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) { if (content.trim().startsWith("!")) { return false; } 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 when expressions (used in /var assignments) */ createWhenExpression(conditions, withClause, location, modifier = null) { return this.createNode(NodeType.WhenExpression, { conditions, withClause: withClause || null, meta: { conditionCount: conditions.length, isValueReturning: true, evaluationType: "expression", hasTailModifiers: !!withClause, modifier }, location }); }, /** * Creates a ForExpression node for for...in expressions in /var assignments */ createForExpression(variable, source, expression, location, opts, batchPipeline) { const meta = { isForExpression: true }; if (opts) { meta.forOptions = opts; } if (batchPipeline) { meta.batchPipeline = batchPipeline; } return { type: "ForExpression", nodeId: (0, import_crypto.randomUUID)(), variable, source, expression: Array.isArray(expression) ? expression : [expression], location, meta }; }, /** * Creates an action node for /for directive actions */ createForActionNode(directive, content, location, endingTail) { const kind = directive; if (kind === "show" && content) { if (content && typeof content === "object" && "content" in content && "wrapperType" in content) { const values2 = { content: content.content }; if (endingTail && endingTail.pipeline) { values2.pipeline = endingTail.pipeline; } return [this.createNode(NodeType.Directive, { kind, subtype: "showTemplate", values: values2, raw: { content: this.reconstructRawString(content.content) }, meta: { implicit: false, isTemplateContent: true }, location })]; } const isExec = content && typeof content === "object" && content.type === "ExecInvocation"; const values = { invocation: content }; if (endingTail && endingTail.pipeline) { values.withClause = { pipeline: endingTail.pipeline }; } return [this.createNode(NodeType.Directive, { kind, subtype: isExec ? "showInvocation" : "showVariable", values, raw: { content: this.reconstructRawString(content) }, meta: { implicit: false }, location })]; } return [this.createNode(NodeType.Directive, { kind, subtype: kind, values: { content: Array.isArray(content) ? content : [content] }, raw: { content: this.reconstructRawString(content) }, meta: { implicit: false }, location })]; }, /** * Helper functions for expression context detection */ isSimpleCondition(expr) { return expr.type === "VariableReference" || expr.type === "Literal" || expr.type === "UnaryExpression" && expr.operator === "!"; }, extractConditionVariables(expr) { const variables = []; function traverse(node) { if (node.type === "VariableReference") { variables.push(node.name || node.identifier); } else if (node.left) traverse(node.left); if (node.right) traverse(node.right); if (node.operand) traverse(node.operand); } __name(traverse, "traverse"); traverse(expr); return [...new Set(variables)]; }, /** * Unified pipeline processing helper * Consolidates pipeline handling across directive contexts */ processPipelineEnding(values, raw, meta, ending) { if (ending.tail) { const pipeline = ending.tail.pipeline; raw.pipeline = pipeline.map((cmd) => `@${cmd.rawIdentifier || cmd.name || cmd}`).join(" | "); meta.hasPipeline = true; if (ending.parallel) { values.withClause = { pipeline, ...ending.parallel }; meta.withClause = { ...meta.withClause || {}, ...ending.parallel }; } else { values.pipeline = pipeline; } } if (ending.comment) { meta.comment = ending.comment; } } }; } }); // 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, options2) { options2 = options2 !== void 0 ? options2 : {}; var peg$FAILED = {}; var peg$source = options2.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 = "mlld-run"; var peg$c6 = "---"; var peg$c7 = "'"; var peg$c8 = '"'; var peg$c9 = "-"; var peg$c10 = "."; var peg$c11 = "true"; var peg$c12 = "false"; var peg$c13 = "null"; var peg$c14 = "*"; var peg$c15 = "none"; var peg$c16 = "retry"; var peg$c17 = "ms"; var peg$c18 = "s"; var peg$c19 = "m"; var peg$c20 = "h"; var peg$c21 = "d"; var peg$c22 = "w"; var peg$c23 = "y"; var peg$c24 = "[["; var peg$c25 = "]]"; var peg$c26 = "\\"; var peg$c27 = "{{"; var peg$c28 = "}}"; var peg$c29 = "<"; var peg$c30 = "`"; var peg$c31 = "/"; var peg$c32 = "#"; var peg$c33 = "/var"; var peg$c34 = "/show"; var peg$c35 = "/run"; var peg$c36 = "/exe"; var peg$c37 = "/path"; var peg$c38 = "/import"; var peg$c39 = "/when"; var peg$c40 = "/output"; var peg$c41 = "?"; var peg$c42 = ":"; var peg$c43 = "||"; var peg$c44 = "&&"; var peg$c45 = "=="; var peg$c46 = "!="; var peg$c47 = "~="; var peg$c48 = "<="; var peg$c49 = ">="; var peg$c50 = "="; var peg$c51 = ">"; var peg$c52 = "("; var peg$c53 = ")"; var peg$c54 = "!"; var peg$c55 = "@"; var peg$c56 = "[?"; var peg$c57 = "]"; var peg$c58 = "["; var peg$c59 = "/for"; var peg$c60 = "/end"; var peg$c61 = ":::"; var peg$c62 = "now"; var peg$c63 = "base"; var peg$c64 = "input"; var peg$c65 = "debug"; var peg$c66 = "pipeline"; var peg$c67 = "frontmatter"; var peg$c68 = "fm"; var peg$c69 = "\\\\"; var peg$c70 = "\r\n"; var peg$c71 = "{"; var peg$c72 = ","; var peg$c73 = "}"; var peg$c74 = "https"; var peg$c75 = "http"; var peg$c76 = "://"; var peg$c77 = " as "; var peg$c78 = "as"; var peg$c79 = " as"; var peg$c80 = "<>"; var peg$c81 = "run"; var peg$c82 = "|"; var peg$c83 = "template"; var peg$c84 = "when"; var peg$c85 = "first"; var peg$c86 = "=>"; var peg$c87 = "for"; var peg$c88 = "in"; var peg$c89 = "each"; var peg$c90 = "~"; var peg$c91 = "foreach"; var peg$c92 = "with"; var peg$c93 = "separator"; var peg$c94 = "parallel"; var peg$c95 = "output"; var peg$c96 = "to"; var peg$c97 = "log"; var peg$c98 = "show"; var peg$c99 = "var"; var peg$c100 = ";"; var peg$c101 = "trust"; var peg$c102 = "needs"; var peg$c103 = "@run"; var peg$c104 = "stdout"; var peg$c105 = "stderr"; var peg$c106 = "env"; var peg$c107 = "file"; var peg$c108 = "//"; var peg$c109 = "\\@"; var peg$c110 = "[("; var peg$c111 = ")]"; var peg$c112 = "/*"; var peg$c113 = "*/"; var peg$c114 = "js"; var peg$c115 = "javascript"; var peg$c116 = "node"; var peg$c117 = "python"; var peg$c118 = "bash"; var peg$c119 = "sh"; var peg$c120 = "skip"; var peg$c121 = "stdin"; var peg$c122 = "format"; var peg$c123 = "asSection"; var peg$c124 = "delay"; var peg$c125 = "from"; var peg$c126 = "nodejs"; var peg$c127 = "py"; var peg$c128 = "risk.high"; var peg$c129 = "risk.med"; var peg$c130 = "risk.low"; var peg$c131 = "risk"; var peg$c132 = "about"; var peg$c133 = "meta"; var peg$c134 = "/export"; var peg$c135 = "@item"; var peg$c136 = "module"; var peg$c137 = "static"; var peg$c138 = "live"; var peg$c139 = "local"; var peg$c140 = "cached"; var peg$c141 = "@input"; var peg$c142 = "@now"; var peg$c143 = "@time"; var peg$c144 = "@stdin"; var peg$c145 = "mld"; var peg$c146 = "mlld"; var peg$c147 = "md"; var peg$c148 = ".md"; var peg$c149 = "env:"; var peg$c150 = "/log"; var peg$c151 = "PROJECTPATH"; var peg$c152 = "under"; var peg$c153 = "any"; var peg$c154 = "all"; 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 = /^[a-zA-Z0-9_]/; var peg$r6 = /^["$'@[-\]`{}]/; var peg$r7 = /^["'.0\\nrt]/; var peg$r8 = /^[ \t\r\n\/\]@${{}"'`]/; var peg$r9 = /^[\/[\]@${}]/; var peg$r10 = /^[\]\/[\]@${}]/; var peg$r11 = /^[\]]/; var peg$r12 = /^["@\n\r]/; var peg$r13 = /^[a-zA-Z_]/; var peg$r14 = /^[.~]/; var peg$r15 = /^[<@`]/; var peg$r16 = /^[<@]/; var peg$r17 = /^[ \t\r\n\u200B\u200C\u200D]/; var peg$r18 = /^[ \t\r\n]/; var peg$r19 = /^[ \t\r\u200B\u200C\u200D]/; var peg$r20 = /^[\r\u2028-\u2029]/; var peg$r21 = /^[^\r\n]/; var peg$r22 = /^[<"]/; var peg$r23 = /^[`<@]/; var peg$r24 = /^[a-zA-Z0-9.\-]/; var peg$r25 = /^[^> ]/; var peg$r26 = /^["'),`]/; var peg$r27 = /^["'),\\`]/; var peg$r28 = /^[`@<]/; var peg$r29 = /^[ \t\r\n\/\]{}]/; var peg$r30 = /^[^[\n]/; var peg$r31 = /^[^\]]/; var peg$r32 = /^[a-zA-Z0-9_@\-]/; var peg$r33 = /^[a-zA-Z0-9_\/@\-]/; var peg$r34 = /^[^ \t\n\r]/; var peg$r35 = /^[^ \t\n\r"'[\]]/; var peg$r36 = /^[^\/s]/; var peg$r37 = /^[^"]/; var peg$r38 = /^[^']/; var peg$r39 = /^[^@\\s\n]/; var peg$r40 = /^[\]"'\r\n]/; var peg$r41 = /^[^}]/; var peg$r42 = /^[ \t\n\r]/; var peg$r43 = /^[\n\r]/; var peg$r44 = /^[a-zA-Z@]/; var peg$r45 = /^[^=]/; var peg$r46 = /^[A-Za-z0-9_]/; var peg$r47 = /^[^#\]]/; var peg$r48 = /^[^\\s\\n]/; var peg$r49 = /^[^)]/; var peg$r50 = /^[a-zA-Z0-9_\-]/; var peg$r51 = /^[a-f0-9]/; 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$anyExpectation(); var peg$e7 = peg$classExpectation([" ", " "], false, false); var peg$e8 = peg$literalExpectation("```", false); var peg$e9 = peg$literalExpectation("mlld-run", false); var peg$e10 = peg$classExpectation(["`", "\r", "\n"], true, false); var peg$e11 = peg$otherExpectation("Top-level directive context"); var peg$e12 = peg$otherExpectation("Variable reference context"); var peg$e13 = peg$otherExpectation("Right-hand side context"); var peg$e14 = peg$otherExpectation("Plain text context"); var peg$e15 = peg$otherExpectation("Run-style code block context"); var peg$e16 = peg$otherExpectation("Exec /run right-hand side context"); var peg$e17 = peg$otherExpectation("Path starting with @variable context"); var peg$e18 = peg$otherExpectation("Directive boundary"); var peg$e19 = peg$otherExpectation("YAML frontmatter"); var peg$e20 = peg$literalExpectation("---", false); var peg$e21 = peg$otherExpectation("String Literal"); var peg$e22 = peg$literalExpectation("'", false); var peg$e23 = peg$literalExpectation('"', false); var peg$e24 = peg$otherExpectation("Number Literal"); var peg$e25 = peg$literalExpectation("-", false); var peg$e26 = peg$classExpectation([["0", "9"]], false, false); var peg$e27 = peg$literalExpectation(".", false); var peg$e28 = peg$otherExpectation("Boolean Literal"); var peg$e29 = peg$literalExpectation("true", false); var peg$e30 = peg$literalExpectation("false", false); var peg$e31 = peg$otherExpectation("Null Literal"); var peg$e32 = peg$literalExpectation("null", false); var peg$e33 = peg$otherExpectation("Wildcard Literal"); var peg$e34 = peg$literalExpectation("*", false); var peg$e35 = peg$otherExpectation("none literal"); var peg$e36 = peg$literalExpectation("none", false); var peg$e37 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"], "_"], false, false); var peg$e38 = peg$otherExpectation("Retry Literal"); var peg$e39 = peg$literalExpectation("retry", false); var peg$e40 = peg$otherExpectation("Time Duration Literal"); var peg$e41 = peg$otherExpectation("Time Unit"); var peg$e42 = peg$literalExpectation("ms", false); var peg$e43 = peg$literalExpectation("s", false); var peg$e44 = peg$literalExpectation("m", false); var peg$e45 = peg$literalExpectation("h", false); var peg$e46 = peg$literalExpectation("d", false); var peg$e47 = peg$literalExpectation("w", false); var peg$e48 = peg$literalExpectation("y", false); var peg$e49 = peg$otherExpectation("Multi-line Template Literal"); var peg$e50 = peg$literalExpectation("[[", false); var peg$e51 = peg$literalExpectation("]]", false); var peg$e52 = peg$otherExpectation("Escape sequence"); var peg$e53 = peg$literalExpectation("\\", false); var peg$e54 = peg$classExpectation(['"', "$", "'", "@", ["[", "]"], "`", "{", "}"], false, false); va