UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

159 lines • 4.6 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. ========= /** 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