@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
211 lines • 11.3 kB
TypeScript
import type { PipelineStages, TSNodeLike } from './types.ts';
import { ProcessSubDirection, Redirect } from './types.ts';
export declare function getText(node: TSNodeLike): string;
/** The root of the tree `node` belongs to. */
export declare function treeRoot(node: TSNodeLike): TSNodeLike;
/**
* Whether `after` stands on `before`'s line within `root`: no newline between
* them. The parse has joined continued lines and folded each heredoc body
* into its statement, so a newline between two statements is a line break.
* Mirrors Python's same_line.
*/
export declare function sameLine(root: TSNodeLike, before: TSNodeLike, after: TSNodeLike): boolean;
/**
* The row the shell began reading `node`'s command on. bash reads a whole
* line before running any of it, and a complete command spanning lines
* whole, with the rest of the line it ends on: a command after a `;`, or
* inside a group that spans rows, was read with the ones before it. Mirrors
* Python's read_row.
*/
export declare function readRow(node: TSNodeLike): number;
/**
* A node's children with the source text between them, the twin of
* python's `source_parts`.
*
* The parser consumes some text without giving it a node:
* whitespace and newlines inside a double-quoted string, and the whitespace
* or line continuation opening a `${v:-word}` operand. Only the node's own
* source still holds that text, so it is sliced out between child extents
* rather than rebuilt from row or byte counts, which lose tabs, newlines and
* escapes. The parser counts `startIndex` here in UTF-16 code units, the
* units `text.slice` takes.
*/
export declare function sourceParts(node: TSNodeLike): Generator<string | TSNodeLike>;
/**
* Walk a double-quoted string without losing scanner-owned text.
*
* The text between children is the string's own, and the closing quote
* token can carry the whitespace before it. Expansion nodes keep their own
* folded prefixes.
*/
export declare function quotedParts(node: TSNodeLike): Generator<string | TSNodeLike>;
/**
* Where an index into a node's text falls in the parser's offsets, the twin
* of python's `byte_offset`.
*
* The Python parser places a node by the bytes of the UTF-8 source, so an
* index counted in code units reads one place too early for every
* multibyte character before it. `grep -ob` reads the same answer for the
* same reason.
* `encodeText` rather than `TextEncoder` because a byte that is not valid
* UTF-8 rides as a surrogate escape and stands for one byte. That is a
* requirement on the caller, not a hope: grep's family decodes every line
* through `decodeText` for it.
*/
export declare function byteOffset(text: string, index: number): number;
export declare function getCommandName(node: TSNodeLike): string;
export declare function getParts(node: TSNodeLike): TSNodeLike[];
/**
* Whether unquoted text holds a brace expansion (`{a,b}`, `{1..3}`),
* which the shell turns into several words.
*/
export declare function braceExpands(text: string): boolean;
/**
* The text a word names before any expansion, or null.
*
* A word is literal when nothing in it waits on the shell: a plain
* word, a number, a quoted string with no expansion inside, or a
* concatenation of those. Quotes are removed, escapes resolved and a
* leading unquoted `~` expanded the way expansion would (`home` null
* leaves it literal, as bash does with no `$HOME`). A word carrying a
* parameter, command, arithmetic or process substitution, or a brace
* expression, answers null: what it names is known only when it runs.
*/
export declare function literalWord(node: TSNodeLike, home?: string | null): string | null;
/** Split FOO=1 BAR=2 cmd parts into [assignments, remaining]. */
export declare function splitEnvPrefix(parts: TSNodeLike[]): [TSNodeLike[], TSNodeLike[]];
export declare function getPipelineCommands(node: TSNodeLike): [TSNodeLike[], boolean[]];
/**
* A pipeline's stages as bash reads them, whatever shape the parse gave
* them.
*
* The parser lets a redirect close over everything to its left up
* to the next pipe, so `a && b | c < f | d` parses as a pipeline whose
* first stage is `redirected(a && b | c, < f)`, and `! a < f | b` as one
* whose first stage is `redirected(! a, < f)`. Bash reads them as
* `a && (b | c <f | d)` and `! (a <f | b)`: the redirect binds to the
* command it follows, the stages on both sides of it are one pipeline, a
* `!` negates all of it, and a list the parse pulled into the first
* stage runs ahead of the pipeline and decides whether it runs at all.
* This is the last-command chain the admission gate climbs for a
* redirect's target (`statementRedirects`), read in the direction the
* executor walks. `redirects` are hoisted over the whole pipeline and
* bind to its last stage.
*/
export declare function getPipelineStages(node: TSNodeLike, redirects?: readonly Redirect[]): PipelineStages;
export declare function getWhileParts(node: TSNodeLike): [TSNodeLike[], TSNodeLike[]];
/**
* Get (variable, values, bodyCommands) from for/select. `values` is null for
* a header with no `in` (`for f do`), which loops over `"$@"`.
*/
export declare function getForParts(node: TSNodeLike): [string, TSNodeLike[] | null, TSNodeLike[]];
/**
* ([init, cond, update], body) from a C-style for. The expression slots
* are positional between the (( )) delimiters, separated by `;` tokens,
* and any of them may be empty: `for ((;;))`. A slot holds every node and
* token the parser found in it, in order, commas and stray operators
* included, since bash evaluates the slot's text as one expression: `for
* ((a=1, i=0; ...))` assigns both, and `i<1 2` is an error, not two
* expressions.
*/
export declare function getCforParts(node: TSNodeLike): [TSNodeLike[][], TSNodeLike[]];
/**
* Whether a statement's terminator is `&`.
*
* The parser puts the `&` beside the statement it ends, inside whatever
* body holds them both, so a body read as named children (every
* extractor above) never sees it. Asking the statement about its own
* next sibling is what lets a loop body, an if/case arm, a brace group
* and a function body launch the job the program loop launches for a
* top-level `cmd &`.
*/
export declare function isBackgrounded(node: TSNodeLike): boolean;
export declare const REDIRECT_NODE_TYPES: ReadonlySet<string>;
/**
* Parse all redirects from a redirected_statement.
*
* Returns [command, redirects]; command is null for a bare redirect
* like `> file` (bash runs the empty command and applies redirects,
* creating/truncating the file).
*/
export declare function getRedirects(node: TSNodeLike): [TSNodeLike | null, Redirect[]];
/**
* The redirects written among a simple command's words, in order: bash
* applies them wherever they stand (`> f echo hi`, `cat <<< x`).
*/
export declare function commandRedirects(node: TSNodeLike): Redirect[];
/**
* Redirects hoisted onto a command, after the ones written among its words:
* bash applies them in source order (`true && > a echo > b`). Mirrors
* Python's with_own_redirects.
*/
export declare function withOwnRedirects(command: TSNodeLike, redirects: readonly Redirect[]): Redirect[];
export declare function getListParts(node: TSNodeLike): [TSNodeLike, string | null, TSNodeLike];
export declare function getIfBranches(node: TSNodeLike): [[TSNodeLike[], TSNodeLike[]][], TSNodeLike[] | null];
export declare function getCaseWord(node: TSNodeLike): TSNodeLike;
/**
* Get (patternNodes, bodyStatements, terminator) triples from case.
*
* Patterns are every named child before the arm's `)`, kept as nodes so
* quoting survives to the matcher: 'a'), "$x") and $'a\n') all mean literal
* text where a bare word keeps its globs live. An arm's body is every
* statement up to its terminator, so multi-statement arms
* (x) cmd1; cmd2;;) keep all commands.
*/
export declare function getCaseItems(node: TSNodeLike): [TSNodeLike[], TSNodeLike[], string][];
export declare function getDeclarationKeyword(node: TSNodeLike): string;
/**
* Get every operand word of an unset_command, keeping `-f`/`-v`/`-n` and
* keeping a subscript target (`unset arr[1]`, quoted or not) as one word.
* A redirect among or before the words is no operand. Mirrors Python's
* `get_unset_args`.
*/
export declare function getUnsetArgs(node: TSNodeLike): string[];
/** The command a `!` negates; null for a bare `!`, which negates the empty command. */
export declare function getNegatedCommand(node: TSNodeLike): TSNodeLike | null;
export declare function getProcessSubDirection(node: TSNodeLike): ProcessSubDirection | null;
/**
* Bash's single-file command substitution, measured against 5.2.37.
* Only a lone foreground `< file` (optionally `0<`) reads input into
* the substitution. Extra redirects, commands, heredocs and descriptor
* duplication retain ordinary redirect-only semantics.
*/
export declare function inputSubstitutionRedirect(node: TSNodeLike): Redirect | null;
/** A process substitution's command text, with the heredoc bodies the line
* reads after it moved inside it. */
export declare function getProcessSubBody(node: TSNodeLike): string;
export declare function getFunctionName(node: TSNodeLike): string;
/**
* Get function body commands: the compound_statement's children, or any
* other compound command (`f() ( ... )`) as the one statement. The redirects
* a definition carries, its own and those of a statement it is the body of
* (`f() { ...; } >o 2>&1`), apply at every call, as bash's do, so then the
* body is one statement: the group under them. Mirrors Python's
* get_function_body.
*/
/**
* The redirects a function definition carries: its own, and those of a
* statement it is the body of (`f() { ...; } >o 2>&1`, whose second
* redirect the parser hangs on a redirected_statement around it).
*/
export declare function getFunctionRedirects(node: TSNodeLike): TSNodeLike[];
/** The definition's source, including redirects and heredoc bodies. */
export declare function getFunctionSource(node: TSNodeLike): string;
/** Parse one stored definition inside the caller's owned parse scope. */
export declare function parseFunction(source: string, parse: (source: string) => TSNodeLike): TSNodeLike[];
export declare function getFunctionBody(node: TSNodeLike): TSNodeLike[] | null;
/**
* What an unquoted plain word parses as: the only words bash checks for an
* alias, a name of digits included. Mirrors Python's ALIAS_WORD_TYPES.
*/
export declare const ALIAS_WORD_TYPES: ReadonlySet<string>;
/**
* A command with its alias words replaced as bash reads it, and the aliases
* being expanded at each unit of the result. An insertion carries the
* replaced word's guards and its own name, so no alias expands inside its own
* text, while the words around it keep theirs. A value ending in a blank
* checks the command's next word, the next child of the command, which an
* unquoted word must be. Mirrors Python's alias_rewrite.
*/
export declare function aliasRewrite(node: TSNodeLike, head: TSNodeLike, value: (name: string, blocked: ReadonlySet<string>) => string | null, guards: readonly ReadonlySet<string>[]): [string, ReadonlySet<string>[]] | null;
//# sourceMappingURL=helpers.d.ts.map