UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

96 lines • 4.3 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 { ContentType, FileStat, FileType } from "../../types.js"; import { enoent } from "../../errors/fs.js"; import { contentTypeForPath } from "../../utils/filetype.js"; import { stripSlash } from "../../utils/slash.js"; import { ROOT } from "./scope.js"; // The node kinds, so `entryStat` can tell a FileType from a ContentType: // both are string unions and the two vocabularies do not overlap. const KINDS = new Set(Object.values(FileType)); /** * The row most id-addressed nodes share, keyed by an id field: the listed * name, size and modified time, and the node's id under `idField` in * `extra`, with whatever else the lister keeps for a child listing to read * back. A kind whose shape differs builds its own row instead. * * `kind` is the node's kind: a FileType for a non-regular node (a * directory), a ContentType for a regular file, whose node kind is then * FILE, or undefined for a regular file typed by its name (a mail * attachment). Mirrors `entry_stat` in `mirage/core/hierarchy/stat.py`. */ export function entryStat(idField, kind) { const node = kind !== undefined && KINDS.has(kind) ? kind : null; return function build(name, ident, options = {}) { const extra = { ...(options.extra ?? {}), [idField]: ident }; const modified = options.modified ?? null; return new FileStat({ name, ...(node !== null ? { type: node } : { type: FileType.FILE, content: kind ?? contentTypeForPath(name), }), size: options.size ?? null, modified: modified !== '' ? modified : null, extra, }); }; } /** * Build a hierarchy stat: the listed row, or a shape the kind holds. * * A path its parent's listing names answers with that row, which the mount * hands in (`entry`). A kind whose existence the API answers directly has a * guard instead, and one that exists by construction (the top-level * directories) needs no proof; both answer the shape their scope gives them. * An override replaces the whole answer for a kind with a bespoke stat, * handed what is at the path and at its parent. Mirrors `make_stat` in * `mirage/core/hierarchy/stat.py`. */ export function makeStat(detect, options = {}) { const { guards, extras, overrides } = options; return async function stat(accessor, path, entry = null, parent = null) { const virtual = path.virtual; const match = detect(path); if (match.kind === ROOT) return new FileStat({ name: '/', type: FileType.DIRECTORY }); const scope = match.scope; if (scope === null) throw enoent(virtual); const override = overrides?.[match.kind]; if (override !== undefined) return override(accessor, match, path, entry, parent); if (entry !== null) return entry; const guard = guards?.[match.kind]; if (guard !== undefined) await guard(accessor, match, virtual); else if (scope.probed) throw enoent(virtual); const parts = stripSlash(path.vfsPath).split('/'); const name = parts[parts.length - 1] ?? ''; const extra = extras?.[match.kind]?.(match) ?? {}; if (!scope.leaf) return new FileStat({ name, type: FileType.DIRECTORY, extra }); return new FileStat({ name, type: FileType.FILE, content: scope.filetype ?? ContentType.JSON, extra, }); }; } //# sourceMappingURL=stat.js.map