@neodx/vfs
Version:
Simple virtual file system - working dir context, lazy changes, different modes, integrations and moreover
296 lines (295 loc) • 8.74 kB
JavaScript
import {
g as e,
i as t,
a as r,
e as a,
r as n,
b as s,
w as l,
c as i,
d as o,
t as p,
f as c,
p as d
} from './_internal/operations-D4d9Xk5B.mjs';
export { h as createInMemoryFilesRecord } from './_internal/operations-D4d9Xk5B.mjs';
import { readdir as u } from 'node:fs/promises';
import {
readFile as g,
ensureFile as f,
writeFile as _,
rm as m,
exists as h,
isDirectory as y,
isFile as w
} from '@neodx/fs';
import { createLogger as v, createAutoLogger as A } from '@neodx/log/node';
import {
uniqBy as D,
mapValues as x,
isNull as b,
fromKeys as k,
asyncReduce as F,
quickPluralize as j,
concurrently as S,
isTypeOfBoolean as V
} from '@neodx/std';
import { resolve as C, normalize as M, relative as B, dirname as P } from 'pathe';
import { colors as E } from '@neodx/colors';
import { eslint as R } from './plugins/eslint.mjs';
import { glob as W } from './plugins/glob.mjs';
import { json as $ } from './plugins/json.mjs';
import { packageJson as I } from './plugins/package-json.mjs';
import { prettier as H } from './plugins/prettier.mjs';
import { scan as N } from './plugins/scan.mjs';
export { c as createVfsPlugin } from './_internal/create-vfs-plugin-CTZbwgZU.mjs';
function T() {
return {
async read(e) {
try {
return await g(e);
} catch {
return null;
}
},
write: async (e, t) => (await f(e), await _(e, t)),
delete: async e => await m(e, { force: !0, recursive: !0 }),
exists: async e => await h(e),
async readDir(e) {
try {
return await u(e, { withFileTypes: !0 });
} catch {
return [];
}
},
isDir: async e => await y(e),
isFile: async e => await w(e),
__: { kind: 'node-fs' }
};
}
let q = ({ parent: e, logLevel: t, log: r = t ? O.fork({ level: t }) : O, ...a }) => {
let n = new Map(),
s = {
log: r,
...a,
catch(e, t) {
let r = Error(`${e} (${t})`);
return (r.path = s.path), (r.name = 'VfsError'), (r.cause = t), s.log.error(r), r;
},
get(e) {
let t = s.resolve(e);
return s.getAllChanges().find(e => e.path === t) ?? null;
},
getAllChanges: () => K(s.__.getAll()),
getAllDirectChanges: () => K(s.__.getScoped()),
getRelativeChanges(e) {
let t = L(s.resolve(e));
return D(
s.__.getAll()
.flatMap(e => Array.from(e.__.getStore().values()))
.filter(e => e.path.startsWith(t)),
e => e.path
);
},
writePathContent(e, t) {
let r = s.resolve(e),
a = s.get(r);
s.__.register(r, { deleted: !1, content: t, updatedAfterDelete: a?.deleted });
},
deletePath(e) {
s.__.register(s.resolve(e), { content: null, deleted: !0 });
},
unregister(e) {
s.__.unregister(s.resolve(e));
},
resolve: (...e) => C(s.path, ...e),
relative(e) {
let t = M(e);
return '/' === s.path && t.startsWith('/') ? t.slice(1) : B(s.path, C(s.path, t));
},
backend: x(a.backend, (e, t) =>
'__' === t ? e : async (t, ...r) => await e(s.resolve(t), ...r)
),
__: {
kind: z,
parent: e,
plugins: [],
children: [],
getStore: () => n,
getAll: () => [...s.__.getAncestors(), s, ...s.__.getDescendants()],
getScoped: () => [s, ...s.__.getDescendants()],
getAncestors: () => G(s),
getDescendants: () => J(s),
register: (e, t) => {
let r = {
...s.get(e),
...t,
path: e,
content: b(t.content) ? t.content : Buffer.from(t.content),
relativePath: s.relative(e)
};
s.__.getAll().forEach(t => t.__.getStore().set(e, r));
},
unregister: e => {
s.__.getAll().forEach(t => t.__.getStore().delete(e));
}
}
};
return e && e.__.children.push(s), s;
},
z = Symbol('VfsContext'),
G = e => (e.__.parent ? [e.__.parent, ...G(e.__.parent)] : []),
J = e => e.__.children.flatMap(e => [e, ...J(e)]),
K = e =>
D(
e.flatMap(e => Array.from(e.__.getStore().values())),
e => e.path
),
L = e => (e.endsWith('/') ? e : `${e}/`),
O = v({ name: 'vfs', level: 'info' }),
Q = e => e.__?.kind ?? 'unknown',
U = () => {
let e = new Map();
return {
scope(t) {
let r = e.get(t) ?? [];
return e.set(t, r), e => r.push(e);
},
get: t => e.get(t) ?? [],
async run(e, ...t) {
return F(this.get(e), async (e, r) => await r(...t), void 0);
}
};
},
X = (e, t, r) => {
let a = { context: t, ...k(['beforeApply', 'beforeApplyFile', 'afterDelete'], r.scope) };
return {
...e,
__: a,
child(e) {
let { log: r, backend: a } = t,
n = q({ backend: a, parent: t, path: t.resolve(e), log: r });
return Y(Z(n), n, U(), ...t.__.plugins);
},
pipe: (...a) => Y(e, t, r, ...a)
};
},
Y = (e, t, r, ...a) => {
let n = a.reduce(
(e, a) =>
a(e, { context: t, ...k(['beforeApply', 'beforeApplyFile', 'afterDelete'], r.scope) }),
e
);
return t.__.plugins.push(...a), (t.__.vfs = n), X(n, t, r);
};
function Z(c) {
let d = U(),
u = Q(c.backend),
g = async e => {
c.log.info('%s %s', ee[e.type], e.relativePath),
await d.run('beforeApplyFile', e, _()),
('delete' === e.type || e.updatedAfterDelete) && (await c.backend.delete(e.path)),
'delete' !== e.type && (await c.backend.write(e.path, e.content)),
'delete' === e.type && (await d.run('afterDelete', e.path, _())),
c.unregister(e.path);
},
f = {
[et]: c,
get log() {
return c.log;
},
get path() {
return c.path;
},
get dirname() {
return P(c.path);
},
get virtual() {
return 'in-memory' === u;
},
get readonly() {
return 'readonly' === u;
},
async apply() {
try {
let t = await e(c);
c.log.info('Applying %d %s...', t.length, j(t.length, 'change', 'changes')),
await d.run('beforeApply', t, _()),
await S(await e(c), g);
} catch (e) {
throw c.catch('Failed to apply changes', e);
}
},
resolve: c.resolve,
relative: c.relative,
isDir: e => t(c, e),
isFile: e => r(c, e),
exists: e => a(c, e),
readDir: async (e, t) => {
let [r, { withFileTypes: a } = {}] = 'string' == typeof e ? [e, t] : [void 0, e],
s = await n(c, r);
return a ? s : s.map(e => e.name);
},
read: (e, t) => s(c, e, t),
write: (e, t) => l(c, e, t),
rename: (e, ...t) => i(c, e, ...t),
delete: e => o(c, e),
tryRead: (e, t) => p(c, e, t)
},
_ = () => c.__.vfs ?? f;
return X(f, c, d);
}
let ee = { delete: E.red('delete'), create: E.green('create'), update: E.yellow('update') },
et = Symbol('context');
function er(e, { eslint: t = !0, prettier: r = !0, ...a } = {}) {
return ea(e, a).pipe($(), N(), W(), R(V(t) ? { auto: t } : t), H(V(r) ? { auto: r } : r), I());
}
function ea(
e,
{
log: t = 'error',
virtual: r,
readonly: a,
backend: n = en(e, { virtual: r, readonly: a })
} = {}
) {
return Z(q({ path: e, log: A(t, { name: 'vfs' }), backend: n }));
}
function en(e, { virtual: t, readonly: r }) {
let a = t ? c(e, !0 === t ? {} : t) : T();
return r
? (function (e) {
let t = c(),
r = e => {
let r = Array.from(t.__.getDeleted());
return r.includes(e) || r.some(t => d(e, t));
};
return {
read: a => (r(a) ? null : t.read(a) ?? e.read(a)),
exists: a => !r(a) && (t.exists(a) || e.exists(a)),
isFile: a => !r(a) && (t.isFile(a) || e.isFile(a)),
isDir: a => !r(a) && (t.isDir(a) || e.isDir(a)),
write: t.write,
delete: t.delete,
readDir: async a =>
r(a)
? []
: D(
(await e.readDir(a)).filter(e => !r(C(a, e.name))).concat(t.readDir(a)),
e => e.name
),
__: { kind: 'readonly' }
};
})(a)
: a;
}
export {
Z as createBaseVfs,
en as createDefaultVfsBackend,
ea as createHeadlessVfs,
c as createInMemoryBackend,
T as createNodeFsBackend,
er as createVfs,
q as createVfsContext
};
//# sourceMappingURL=index.mjs.map