mirror of
https://github.com/Nystik-gh/ignis.git
synced 2026-06-17 04:35:53 +00:00
shim more buffer methods, and fs methods
getting importer plugin to work,
This commit is contained in:
153
src/shims/fs/fd.js
Normal file
153
src/shims/fs/fd.js
Normal file
@@ -0,0 +1,153 @@
|
||||
// File descriptor shim - maps fake integer fds to in-memory file buffers.
|
||||
// Enables libraries like yauzl that use fs.open/fs.read/fs.close to seek
|
||||
// around files without loading them via readFileSync upfront.
|
||||
|
||||
let nextFd = 100;
|
||||
const openFiles = new Map();
|
||||
|
||||
export function createFdOps(metadataCache, contentCache, transport) {
|
||||
function ensureData(path) {
|
||||
const cached = contentCache.get(path);
|
||||
|
||||
if (cached !== null) {
|
||||
if (typeof cached === "string") {
|
||||
return new TextEncoder().encode(cached);
|
||||
}
|
||||
|
||||
return cached;
|
||||
}
|
||||
|
||||
// Synchronous fetch fallback
|
||||
console.warn("[shim:fs] fd open cache miss, using sync XHR:", path);
|
||||
const data = transport.readFileSync(path);
|
||||
contentCache.set(path, data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function getEntry(fd) {
|
||||
const entry = openFiles.get(fd);
|
||||
|
||||
if (!entry) {
|
||||
const err = new Error(`EBADF: bad file descriptor, fd ${fd}`);
|
||||
err.code = "EBADF";
|
||||
throw err;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
// --- Sync ---
|
||||
|
||||
function openSync(path, flags, mode) {
|
||||
if (!metadataCache.has(path)) {
|
||||
const err = new Error(
|
||||
`ENOENT: no such file or directory, open '${path}'`,
|
||||
);
|
||||
err.code = "ENOENT";
|
||||
throw err;
|
||||
}
|
||||
|
||||
const data = ensureData(path);
|
||||
const fd = nextFd++;
|
||||
openFiles.set(fd, { path, data });
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
function readSync(fd, buffer, offset, length, position) {
|
||||
const entry = getEntry(fd);
|
||||
const available = Math.min(length, entry.data.length - position);
|
||||
|
||||
if (available <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const slice = entry.data.subarray(position, position + available);
|
||||
buffer.set(slice, offset);
|
||||
|
||||
return available;
|
||||
}
|
||||
|
||||
function closeSync(fd) {
|
||||
openFiles.delete(fd);
|
||||
}
|
||||
|
||||
function fstatSync(fd) {
|
||||
const entry = getEntry(fd);
|
||||
const stat = metadataCache.toStat(entry.path);
|
||||
|
||||
if (stat) {
|
||||
return stat;
|
||||
}
|
||||
|
||||
// Fallback: construct minimal stat from the buffer
|
||||
return {
|
||||
size: entry.data.length,
|
||||
isFile: () => true,
|
||||
isDirectory: () => false,
|
||||
};
|
||||
}
|
||||
|
||||
// --- Async (callback style) ---
|
||||
|
||||
function open(path, flags, modeOrCb, cb) {
|
||||
if (typeof modeOrCb === "function") {
|
||||
cb = modeOrCb;
|
||||
}
|
||||
|
||||
try {
|
||||
const fd = openSync(path, flags);
|
||||
queueMicrotask(() => cb(null, fd));
|
||||
} catch (e) {
|
||||
queueMicrotask(() => cb(e));
|
||||
}
|
||||
}
|
||||
|
||||
function read(fd, buffer, offset, length, position, cb) {
|
||||
try {
|
||||
const bytesRead = readSync(fd, buffer, offset, length, position);
|
||||
queueMicrotask(() => cb(null, bytesRead, buffer));
|
||||
} catch (e) {
|
||||
queueMicrotask(() => cb(e));
|
||||
}
|
||||
}
|
||||
|
||||
function close(fd, cb) {
|
||||
try {
|
||||
closeSync(fd);
|
||||
|
||||
if (cb) {
|
||||
queueMicrotask(() => cb(null));
|
||||
}
|
||||
} catch (e) {
|
||||
if (cb) {
|
||||
queueMicrotask(() => cb(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fstat(fd, optionsOrCb, cb) {
|
||||
if (typeof optionsOrCb === "function") {
|
||||
cb = optionsOrCb;
|
||||
}
|
||||
|
||||
try {
|
||||
const stat = fstatSync(fd);
|
||||
queueMicrotask(() => cb(null, stat));
|
||||
} catch (e) {
|
||||
queueMicrotask(() => cb(e));
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
openSync,
|
||||
readSync,
|
||||
closeSync,
|
||||
fstatSync,
|
||||
open,
|
||||
read,
|
||||
close,
|
||||
fstat,
|
||||
};
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { transport } from "./transport.js";
|
||||
import { createFsPromises } from "./promises.js";
|
||||
import { createFsSync } from "./sync.js";
|
||||
import { createFsWatch } from "./watch.js";
|
||||
import { createFdOps } from "./fd.js";
|
||||
import { constants } from "./constants.js";
|
||||
|
||||
const metadataCache = new MetadataCache();
|
||||
@@ -12,6 +13,7 @@ const contentCache = new ContentCache();
|
||||
const fsPromises = createFsPromises(metadataCache, contentCache, transport);
|
||||
const fsSync = createFsSync(metadataCache, contentCache, transport);
|
||||
const fsWatch = createFsWatch(transport);
|
||||
const fdOps = createFdOps(metadataCache, contentCache, transport);
|
||||
|
||||
export const fsShim = {
|
||||
promises: fsPromises,
|
||||
@@ -24,6 +26,15 @@ export const fsShim = {
|
||||
statSync: fsSync.statSync,
|
||||
readdirSync: fsSync.readdirSync,
|
||||
|
||||
open: fdOps.open,
|
||||
openSync: fdOps.openSync,
|
||||
read: fdOps.read,
|
||||
readSync: fdOps.readSync,
|
||||
close: fdOps.close,
|
||||
closeSync: fdOps.closeSync,
|
||||
fstat: fdOps.fstat,
|
||||
fstatSync: fdOps.fstatSync,
|
||||
|
||||
watch: fsWatch.watch,
|
||||
constants,
|
||||
|
||||
|
||||
@@ -197,5 +197,48 @@ export function createFsPromises(metadataCache, contentCache, transport) {
|
||||
metadataCache.set(path, meta);
|
||||
}
|
||||
},
|
||||
|
||||
async open(path, flags) {
|
||||
if (!metadataCache.has(path)) {
|
||||
const err = new Error(
|
||||
`ENOENT: no such file or directory, open '${path}'`,
|
||||
);
|
||||
err.code = "ENOENT";
|
||||
throw err;
|
||||
}
|
||||
|
||||
const data = await this.readFile(path);
|
||||
const fileData =
|
||||
typeof data === "string" ? new TextEncoder().encode(data) : data;
|
||||
|
||||
const fileStat = metadataCache.toStat(path) || {
|
||||
size: fileData.length,
|
||||
isFile: () => true,
|
||||
isDirectory: () => false,
|
||||
};
|
||||
|
||||
return {
|
||||
async stat() {
|
||||
return fileStat;
|
||||
},
|
||||
|
||||
async read(buffer, offset, length, position) {
|
||||
const available = Math.min(length, fileData.length - position);
|
||||
|
||||
if (available <= 0) {
|
||||
return { bytesRead: 0, buffer };
|
||||
}
|
||||
|
||||
const slice = fileData.subarray(position, position + available);
|
||||
buffer.set(slice, offset);
|
||||
|
||||
return { bytesRead: available, buffer };
|
||||
},
|
||||
|
||||
async close() {
|
||||
// Nothing to clean up - data is in memory
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user