UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

77 lines • 3.7 kB
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= import { expandNode } from "../expand/node.js"; import { expandPattern, expandRegex } from "../expand/pattern.js"; import { CondParser, PATTERN_OPS, condTokens } from "./test_tokens.js"; /** * Build a structured condition tree from a `[[ ... ]]` node. * * The parser nests the expression by its own precedence (`=~` looser than * `||`, `!` tighter than `=~`), so its tokens are read again as bash parses * them. */ export async function expandDoubleBracket(node, context, executeFn, cs, view) { return condNode(new CondParser(condTokens(node)).parse(), context, executeFn, cs, view); } /** Expand one parsed `[[ ]]` tree into a CondNode. */ async function condNode(tree, context, executeFn, cs, view) { switch (tree.kind) { case 'and': case 'or': { // Expansion is part of evaluating an operand, so skipped branches cannot // run substitutions or observe state before the left side. const { left, right } = tree; const first = { kind: 'lazy', expand: () => condNode(left, context, executeFn, cs, view), }; const second = { kind: 'lazy', expand: () => condNode(right, context, executeFn, cs, view), }; return { kind: tree.kind, left: first, right: second }; } case 'not': return { kind: 'not', inner: await condNode(tree.inner, context, executeFn, cs, view) }; case 'group': return condNode(tree.inner, context, executeFn, cs, view); case 'unary': return { kind: 'unary', op: tree.op, operand: await expandNode(tree.operand, context, executeFn, cs, view), }; case 'binary': { const leftText = await expandNode(tree.left, context, executeFn, cs, view); return comparison(tree.op, leftText, tree.right, context, executeFn, cs, view); } case 'word': return { kind: 'word', value: await expandNode(tree.operand, context, executeFn, cs, view) }; } } /** A binary test, its right operand expanded as `op` reads it. */ async function comparison(op, leftText, right, context, executeFn, cs, view) { if (PATTERN_OPS.has(op)) { // The right side of a match is a pattern word; the shared expander // renders its quoting into the matcher's dialect per segment (quoted // literal, unquoted live), so the evaluator matches unconditionally. A // wholly-literal pattern matches exactly itself. const expand = op === '=~' ? expandRegex : expandPattern; const pattern = await expand(right, context, executeFn, cs, view); return { kind: 'binary', left: leftText, op, right: pattern }; } const rightText = await expandNode(right, context, executeFn, cs, view); return { kind: 'binary', left: leftText, op, right: rightText }; } //# sourceMappingURL=test_expr.js.map