@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
159 lines • 4.6 kB
JavaScript
// ========= 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. =========
/** One parse of a line: its tree, where each of its chars sits in the line as
* typed, and the references that keep it readable. Mirrors Python's
* ParsedProgram. */
export class ParsedProgram {
original;
root;
references = 1;
released = false;
offsets;
constructor(original, root) {
this.original = original;
this.offsets = root.offsets;
this.root = new ProgramNode(root, this);
}
check() {
if (this.references === 0)
throw new Error('parsed program is released');
}
retain() {
this.check();
this.references += 1;
let released = false;
return () => {
if (released)
return;
released = true;
this.references -= 1;
};
}
release() {
if (this.released)
return;
this.released = true;
this.references -= 1;
}
}
/** A node of a parsed program; every read checks the program is still held.
* The wrappers of a node's children are built once and kept, as in Python. */
export class ProgramNode {
borrowed;
program;
kids;
named;
constructor(borrowed, program) {
this.borrowed = borrowed;
this.program = program;
}
get node() {
this.program.check();
return this.borrowed;
}
get heredoc() {
return this.node.heredoc;
}
get warnings() {
return this.node.warnings ?? '';
}
get offsets() {
return this.program.offsets;
}
get error() {
return this.node.error ?? null;
}
get sourceText() {
return this.node.sourceText ?? this.node.text;
}
get inlined() {
return this.node.inlined;
}
get type() {
return this.node.type;
}
get text() {
return this.node.text;
}
get id() {
return this.node.id;
}
get startIndex() {
return this.node.startIndex;
}
get endIndex() {
return this.node.endIndex;
}
get startPosition() {
return this.node.startPosition;
}
get endPosition() {
return this.node.endPosition;
}
get isNamed() {
return this.node.isNamed;
}
get childCount() {
return this.node.childCount;
}
child(index) {
return this.wrap(this.node.child(index));
}
get children() {
const node = this.node;
this.kids ??= node.children.map((child) => new ProgramNode(child, this.program));
return [...this.kids];
}
get namedChildren() {
const node = this.node;
this.named ??= node.namedChildren.map((child) => new ProgramNode(child, this.program));
return [...this.named];
}
wrap(node) {
return node === null ? null : new ProgramNode(node, this.program);
}
get parent() {
return this.wrap(this.node.parent);
}
get previousSibling() {
return this.wrap(this.node.previousSibling);
}
get nextSibling() {
return this.wrap(this.node.nextSibling);
}
childForFieldName(name) {
return this.wrap(this.node.childForFieldName(name));
}
}
/** Retain each defining program once, including synthetic redirect wrappers. */
export function retainPrograms(nodes) {
const programs = new Set();
const pending = [...nodes];
while (pending.length > 0) {
const node = pending.pop();
if (node === undefined)
break;
if (node instanceof ProgramNode)
programs.add(node.program);
else if (Array.isArray(node.children))
for (const child of node.children)
pending.push(child);
}
const leases = [...programs].map((program) => program.retain());
return () => {
for (const release of leases)
release();
};
}
//# sourceMappingURL=program.js.map