@neodx/vfs
Version:
Simple virtual file system - working dir context, lazy changes, different modes, integrations and moreover
283 lines (282 loc) • 8.93 kB
JavaScript
var e = require('./_internal/operations-DJhEnMA2.cjs'),
t = require('node:fs/promises'),
r = require('@neodx/fs'),
a = require('@neodx/log/node'),
n = require('@neodx/std'),
s = require('pathe'),
i = require('@neodx/colors'),
l = require('./plugins/eslint.cjs'),
o = require('./plugins/glob.cjs'),
c = require('./plugins/json.cjs'),
u = require('./plugins/package-json.cjs'),
p = require('./plugins/prettier.cjs'),
d = require('./plugins/scan.cjs'),
g = require('./_internal/create-vfs-plugin-Bg0LL_-h.cjs');
function f() {
return {
async read(e) {
try {
return await r.readFile(e);
} catch {
return null;
}
},
write: async (e, t) => (await r.ensureFile(e), await r.writeFile(e, t)),
delete: async e => await r.rm(e, { force: !0, recursive: !0 }),
exists: async e => await r.exists(e),
async readDir(e) {
try {
return await t.readdir(e, { withFileTypes: !0 });
} catch {
return [];
}
},
isDir: async e => await r.isDirectory(e),
isFile: async e => await r.isFile(e),
__: { kind: 'node-fs' }
};
}
const _ = ({ parent: e, logLevel: t, log: r = t ? x.fork({ level: t }) : x, ...a }) => {
let i = new Map(),
l = {
log: r,
...a,
catch(e, t) {
let r = Error(`${e} (${t})`);
return (r.path = l.path), (r.name = 'VfsError'), (r.cause = t), l.log.error(r), r;
},
get(e) {
let t = l.resolve(e);
return l.getAllChanges().find(e => e.path === t) ?? null;
},
getAllChanges: () => w(l.__.getAll()),
getAllDirectChanges: () => w(l.__.getScoped()),
getRelativeChanges(e) {
let t = m(l.resolve(e));
return n.uniqBy(
l.__.getAll()
.flatMap(e => Array.from(e.__.getStore().values()))
.filter(e => e.path.startsWith(t)),
e => e.path
);
},
writePathContent(e, t) {
let r = l.resolve(e),
a = l.get(r);
l.__.register(r, { deleted: !1, content: t, updatedAfterDelete: a?.deleted });
},
deletePath(e) {
l.__.register(l.resolve(e), { content: null, deleted: !0 });
},
unregister(e) {
l.__.unregister(l.resolve(e));
},
resolve: (...e) => s.resolve(l.path, ...e),
relative(e) {
let t = s.normalize(e);
return '/' === l.path && t.startsWith('/')
? t.slice(1)
: s.relative(l.path, s.resolve(l.path, t));
},
backend: n.mapValues(a.backend, (e, t) =>
'__' === t ? e : async (t, ...r) => await e(l.resolve(t), ...r)
),
__: {
kind: y,
parent: e,
plugins: [],
children: [],
getStore: () => i,
getAll: () => [...l.__.getAncestors(), l, ...l.__.getDescendants()],
getScoped: () => [l, ...l.__.getDescendants()],
getAncestors: () => h(l),
getDescendants: () => v(l),
register: (e, t) => {
let r = {
...l.get(e),
...t,
path: e,
content: n.isNull(t.content) ? t.content : Buffer.from(t.content),
relativePath: l.relative(e)
};
l.__.getAll().forEach(t => t.__.getStore().set(e, r));
},
unregister: e => {
l.__.getAll().forEach(t => t.__.getStore().delete(e));
}
}
};
return e && e.__.children.push(l), l;
},
y = Symbol('VfsContext'),
h = e => (e.__.parent ? [e.__.parent, ...h(e.__.parent)] : []),
v = e => e.__.children.flatMap(e => [e, ...v(e)]),
w = e =>
n.uniqBy(
e.flatMap(e => Array.from(e.__.getStore().values())),
e => e.path
),
m = e => (e.endsWith('/') ? e : `${e}/`),
x = a.createLogger({ name: 'vfs', level: 'info' }),
A = e => e.__?.kind ?? 'unknown',
D = () => {
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 n.asyncReduce(this.get(e), async (e, r) => await r(...t), void 0);
}
};
},
F = (e, t, r) => {
let a = {
context: t,
...n.fromKeys(['beforeApply', 'beforeApplyFile', 'afterDelete'], r.scope)
};
return {
...e,
__: a,
child(e) {
let { log: r, backend: a } = t,
n = _({ backend: a, parent: t, path: t.resolve(e), log: r });
return V(k(n), n, D(), ...t.__.plugins);
},
pipe: (...a) => V(e, t, r, ...a)
};
},
V = (e, t, r, ...a) => {
let s = a.reduce(
(e, a) =>
a(e, {
context: t,
...n.fromKeys(['beforeApply', 'beforeApplyFile', 'afterDelete'], r.scope)
}),
e
);
return t.__.plugins.push(...a), (t.__.vfs = s), F(s, t, r);
};
function k(t) {
let r = D(),
a = A(t.backend),
i = async e => {
t.log.info('%s %s', q[e.type], e.relativePath),
await r.run('beforeApplyFile', e, o()),
('delete' === e.type || e.updatedAfterDelete) && (await t.backend.delete(e.path)),
'delete' !== e.type && (await t.backend.write(e.path, e.content)),
'delete' === e.type && (await r.run('afterDelete', e.path, o())),
t.unregister(e.path);
},
l = {
[b]: t,
get log() {
return t.log;
},
get path() {
return t.path;
},
get dirname() {
return s.dirname(t.path);
},
get virtual() {
return 'in-memory' === a;
},
get readonly() {
return 'readonly' === a;
},
async apply() {
try {
let a = await e.getVfsActions(t);
t.log.info(
'Applying %d %s...',
a.length,
n.quickPluralize(a.length, 'change', 'changes')
),
await r.run('beforeApply', a, o()),
await n.concurrently(await e.getVfsActions(t), i);
} catch (e) {
throw t.catch('Failed to apply changes', e);
}
},
resolve: t.resolve,
relative: t.relative,
isDir: r => e.isVfsDir(t, r),
isFile: r => e.isVfsFile(t, r),
exists: r => e.existsVfsPath(t, r),
readDir: async (r, a) => {
let [n, { withFileTypes: s } = {}] = 'string' == typeof r ? [r, a] : [void 0, r],
i = await e.readVfsDir(t, n);
return s ? i : i.map(e => e.name);
},
read: (r, a) => e.readVfsFile(t, r, a),
write: (r, a) => e.writeVfsFile(t, r, a),
rename: (r, ...a) => e.renameVfs(t, r, ...a),
delete: r => e.deleteVfsPath(t, r),
tryRead: (r, a) => e.tryReadVfsFile(t, r, a)
},
o = () => t.__.vfs ?? l;
return F(l, t, r);
}
const q = {
delete: i.colors.red('delete'),
create: i.colors.green('create'),
update: i.colors.yellow('update')
},
b = Symbol('context');
function B(
e,
{ log: t = 'error', virtual: r, readonly: n, backend: s = j(e, { virtual: r, readonly: n }) } = {}
) {
return k(_({ path: e, log: a.createAutoLogger(t, { name: 'vfs' }), backend: s }));
}
function j(t, { virtual: r, readonly: a }) {
let i = r ? e.createInMemoryBackend(t, !0 === r ? {} : r) : f();
return a
? (function (t) {
let r = e.createInMemoryBackend(),
a = t => {
let a = Array.from(r.__.getDeleted());
return a.includes(t) || a.some(r => e.pathStartsWith(t, r));
};
return {
read: e => (a(e) ? null : r.read(e) ?? t.read(e)),
exists: e => !a(e) && (r.exists(e) || t.exists(e)),
isFile: e => !a(e) && (r.isFile(e) || t.isFile(e)),
isDir: e => !a(e) && (r.isDir(e) || t.isDir(e)),
write: r.write,
delete: r.delete,
async readDir(e) {
if (a(e)) return [];
let i = await t.readDir(e);
return n.uniqBy(
i.filter(t => !a(s.resolve(e, t.name))).concat(r.readDir(e)),
e => e.name
);
},
__: { kind: 'readonly' }
};
})(i)
: i;
}
(exports.createInMemoryBackend = e.createInMemoryBackend),
(exports.createInMemoryFilesRecord = e.createInMemoryFilesRecord),
(exports.createVfsPlugin = g.createVfsPlugin),
(exports.createBaseVfs = k),
(exports.createDefaultVfsBackend = j),
(exports.createHeadlessVfs = B),
(exports.createNodeFsBackend = f),
(exports.createVfs = function (e, { eslint: t = !0, prettier: r = !0, ...a } = {}) {
return B(e, a).pipe(
c.json(),
d.scan(),
o.glob(),
l.eslint(n.isTypeOfBoolean(t) ? { auto: t } : t),
p.prettier(n.isTypeOfBoolean(r) ? { auto: r } : r),
u.packageJson()
);
}),
(exports.createVfsContext = _);
//# sourceMappingURL=index.cjs.map