From 1424cca9a3029008a2421d9a76ea6a227aca59e6 Mon Sep 17 00:00:00 2001 From: Sepehr Laal <5657848+3p3r@users.noreply.github.com> Date: Sun, 7 Apr 2024 21:43:40 -0700 Subject: [PATCH] feat: standard buffer api compat + callback and streaming apis --- .gitignore | 1 + package-lock.json | 105 ++++++++++++++++ package.json | 5 + src/fs.rs | 13 +- src/index.ts | 300 ++++++++++++++++++++-------------------------- tsconfig.json | 5 +- webpack.config.ts | 7 ++ 7 files changed, 266 insertions(+), 170 deletions(-) diff --git a/.gitignore b/.gitignore index 7d2cca5..4ea44c3 100644 --- a/.gitignore +++ b/.gitignore @@ -130,6 +130,7 @@ dist .pnp.* # generated files +src/index.js target deps pkg diff --git a/package-lock.json b/package-lock.json index 9a1f3d7..743ced2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@types/karma": "^6.3.8", "@types/mocha": "^10.0.6", "@types/node": "^20.11.30", + "@types/typedarray-to-buffer": "^4.0.4", "@types/webpack": "^5.28.5", "assert": "^2.1.0", "atob-lite": "^2.0.0", @@ -30,18 +31,22 @@ "karma-jasmine": "^5.1.0", "karma-mocha": "^2.0.1", "karma-webpack": "^5.0.1", + "memfs": "^4.8.1", "mocha": "^10.3.0", "path-browserify": "^1.0.1", "prettier": "^3.2.5", "process": "^0.11.10", "puppeteer": "^22.6.1", + "stream-browserify": "^3.0.0", "string-replace-loader": "^3.1.0", "terser-webpack-plugin": "^5.3.10", "ts-loader": "^9.5.1", "ts-mocha": "^10.0.0", "ts-node": "^10.9.2", "tsx": "^4.7.1", + "typedarray-to-buffer": "^4.0.0", "typescript": "^5.4.3", + "url": "^0.11.3", "url-loader": "^4.1.1", "web-worker": "^1.3.0", "webpack": "^5.91.0", @@ -1167,6 +1172,15 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/typedarray-to-buffer": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/typedarray-to-buffer/-/typedarray-to-buffer-4.0.4.tgz", + "integrity": "sha512-TAH+1wUD82Dgotp/+CcRi3UGuJHnHkqv4Tbt4x3zNI9Lqvvfj+drzshWML0fbQYmEKEbS5cMTDV8FUDzAirp7g==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/webpack": { "version": "5.28.5", "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-5.28.5.tgz", @@ -4283,6 +4297,22 @@ "node": ">= 0.6" } }, + "node_modules/memfs": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.8.1.tgz", + "integrity": "sha512-7q/AdPzf2WpwPlPL4v1kE2KsJsHl7EF4+hAeVzlyanr2+YnR21NVn9mDqo+7DEaKDRsQy8nvxPlKH4WqMtiO0w==", + "dev": true, + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -5725,6 +5755,30 @@ "node": ">= 0.6" } }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dev": true, + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/stream-browserify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/streamroller": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", @@ -6729,6 +6783,26 @@ "node": ">= 0.6" } }, + "node_modules/typedarray-to-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-4.0.0.tgz", + "integrity": "sha512-6dOYeZfS3O9RtRD1caom0sMxgK59b27+IwoNy8RDPsmslSGOyU+mpTamlaIW7aNKi90ZQZ9DFaZL3YRoiSCULQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/typescript": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", @@ -6874,6 +6948,16 @@ "punycode": "^2.1.0" } }, + "node_modules/url": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.3.tgz", + "integrity": "sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==", + "dev": true, + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.11.2" + } + }, "node_modules/url-loader": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", @@ -6950,6 +7034,27 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/url/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true + }, + "node_modules/url/node_modules/qs": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.0.tgz", + "integrity": "sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/urlpattern-polyfill": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", diff --git a/package.json b/package.json index ed586b1..3b51edd 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "@types/karma": "^6.3.8", "@types/mocha": "^10.0.6", "@types/node": "^20.11.30", + "@types/typedarray-to-buffer": "^4.0.4", "@types/webpack": "^5.28.5", "assert": "^2.1.0", "atob-lite": "^2.0.0", @@ -53,18 +54,22 @@ "karma-jasmine": "^5.1.0", "karma-mocha": "^2.0.1", "karma-webpack": "^5.0.1", + "memfs": "^4.8.1", "mocha": "^10.3.0", "path-browserify": "^1.0.1", "prettier": "^3.2.5", "process": "^0.11.10", "puppeteer": "^22.6.1", + "stream-browserify": "^3.0.0", "string-replace-loader": "^3.1.0", "terser-webpack-plugin": "^5.3.10", "ts-loader": "^9.5.1", "ts-mocha": "^10.0.0", "ts-node": "^10.9.2", "tsx": "^4.7.1", + "typedarray-to-buffer": "^4.0.0", "typescript": "^5.4.3", + "url": "^0.11.3", "url-loader": "^4.1.1", "web-worker": "^1.3.0", "webpack": "^5.91.0", diff --git a/src/fs.rs b/src/fs.rs index 1d44a29..daf7397 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -173,6 +173,7 @@ pub unsafe fn openSync( return Ok(fd); } else { let err: JsValue = JsError::new("ENOENT: no such file or directory").into(); + Reflect::set(&err, &"path".into(), &path.into()).unwrap(); Reflect::set(&err, &"code".into(), &"ENOENT".into()).unwrap(); Reflect::set(&err, &"syscall".into(), &"open".into()).unwrap(); return Err(err); @@ -378,6 +379,7 @@ pub unsafe fn readdirSync( ) -> Result { if !existsSync(path.clone()) { let err: JsValue = JsError::new("ENOENT: no such file or directory").into(); + Reflect::set(&err, &"path".into(), &path.into()).unwrap(); Reflect::set(&err, &"code".into(), &"ENOENT".into()).unwrap(); Reflect::set(&err, &"syscall".into(), &"readdir".into()).unwrap(); return Err(err); @@ -501,6 +503,7 @@ pub unsafe fn readFileSync( .to_lowercase(); if !existsSync(path.clone()) { let err: JsValue = JsError::new("ENOENT: no such file or directory").into(); + Reflect::set(&err, &"path".into(), &path.into()).unwrap(); Reflect::set(&err, &"code".into(), &"ENOENT".into()).unwrap(); Reflect::set(&err, &"syscall".into(), &"open".into()).unwrap(); return Err(err); @@ -514,7 +517,13 @@ pub unsafe fn readFileSync( broadcast!(name_of!(readFileSync), path); let data = lfs::read_file_sync(path.as_str()).unwrap(); let out = match encoding.as_str() { - "utf8" | "utf-8" => JsValue::from(String::from_utf8(data).unwrap()), + "utf8" | "utf-8" => { + if String::from_utf8(data.clone()).is_ok() { + JsValue::from(String::from_utf8(data).unwrap()) + } else { + JsValue::from(js_sys::Uint8Array::from(data.as_slice())) + } + } "buffer" => JsValue::from(js_sys::Uint8Array::from(data.as_slice())), _ => return Err(JsError::new("unsupported encoding").into()), }; @@ -733,6 +742,7 @@ pub unsafe fn statSync( if !existsSync(path.clone()) { if throw_if_no_entry { let err: JsValue = JsError::new("ENOENT: no such file or directory").into(); + Reflect::set(&err, &"path".into(), &path.into()).unwrap(); Reflect::set(&err, &"code".into(), &"ENOENT".into()).unwrap(); Reflect::set(&err, &"syscall".into(), &"stat".into()).unwrap(); return Err(err); @@ -801,6 +811,7 @@ pub unsafe fn lstatSync( if !existsSync(path.clone()) { if throw_if_no_entry { let err: JsValue = JsError::new("ENOENT: no such file or directory").into(); + Reflect::set(&err, &"path".into(), &path.into()).unwrap(); Reflect::set(&err, &"code".into(), &"ENOENT".into()).unwrap(); Reflect::set(&err, &"syscall".into(), &"lstat".into()).unwrap(); return Err(err); diff --git a/src/index.ts b/src/index.ts index 343bed7..1b5c5d5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,12 +20,25 @@ import init, { // @ts-ignore - handled by webpack, turns into base64 import WASM_BASE64 from "../pkg/wasabio_bg.wasm"; import type { EventEmitter as IEventEmitter } from "events"; // type only! +import type { Readable, Writable } from "stream"; import { ok } from "assert"; import atob from "atob-lite"; -import type * as fs from "fs"; +import * as fs from "fs"; +import { Volume } from "memfs/lib/volume"; import { backOff } from "exponential-backoff"; +import { callbackify } from "util"; import JSZip from "jszip"; +import toBuffer from "typedarray-to-buffer"; +const toUInt8 = (buf: any): Uint8Array => + buf instanceof ArrayBuffer + ? new Uint8Array(buf) + : ArrayBuffer.isView(buf) + ? buf instanceof Uint8Array && buf.constructor.name === Uint8Array.name + ? buf + : new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength) + : new TextEncoder().encode(buf); + import { checksum, commit, built } from "../pkg/package.json"; const METADATA = { checksum, commit, built }; @@ -96,6 +109,10 @@ export interface InitializeOptions { let MEMORY: WebAssembly.Memory | undefined; let THREAD_COUNTER_ADDRESS: number | undefined; +export function memory(): WebAssembly.Memory | undefined { + return MEMORY; +} + export function initialize( mem?: WebAssembly.Memory | Uint8Array, opts?: InitializeOptions, @@ -594,7 +611,7 @@ export { mkdtempSync }; import { writeFileSync as _writeFileSync } from "../pkg"; export function writeFileSync( pathOrFd: fs.PathLike | number, - data: Uint8Array | string, + data: Buffer | Uint8Array | string, options?: object | encoding, ): void { if (typeof options === "string") { @@ -603,11 +620,11 @@ export function writeFileSync( if (typeof pathOrFd === "number") { throw new Error("not implemented, use writeSync"); } else { - _writeFileSync(normalizePathLikeToString(pathOrFd), data, options); + _writeFileSync(normalizePathLikeToString(pathOrFd), toUInt8(data), options); } } import { readFileSync as _readFileSync } from "../pkg"; -export function readFileSync(pathOrFd: fs.PathLike | number, options?: object | encoding): Uint8Array | string { +export function readFileSync(pathOrFd: fs.PathLike | number, options?: object | encoding): Buffer | string { if (typeof options === "string") { options = { encoding: options }; } @@ -615,13 +632,14 @@ export function readFileSync(pathOrFd: fs.PathLike | number, options?: object | throw new Error("not implemented, use readSync"); } else { pathOrFd = normalizePathLikeToString(pathOrFd); - return _readFileSync(pathOrFd, options); + const content = _readFileSync(pathOrFd, options); + return typeof content === "string" ? content : toBuffer(content); } } import { appendFileSync as _appendFileSync } from "../pkg"; export function appendFileSync( pathOrFd: fs.PathLike | number, - data: Uint8Array | string, + data: Buffer | Uint8Array | string, options?: object | encoding, ): void { if (typeof options === "string") { @@ -631,7 +649,7 @@ export function appendFileSync( throw new Error("not implemented, use appendSync"); } else { pathOrFd = normalizePathLikeToString(pathOrFd); - _appendFileSync(pathOrFd, data, options); + _appendFileSync(pathOrFd, toUInt8(data), options); } } import { statfsSync } from "../pkg"; @@ -733,171 +751,119 @@ const delayedBackOff = async (fn: () => Promise): Promise => { return await backOff(fn, backOffOpts); }; +function promisify any>(fn: T): (...args: Parameters) => Promise> { + return (...args: Parameters) => { + return delayedBackOff(() => fn(...args)); + }; +} + /** - * note: if you are accessing the filesystem in webworker, you can use either + * note: if you are accessing the filesystem in a webworker, you can use either * sync or async versions of the functions. if you are accessing the filesystem - * in the main thread or another UI context (webview extensions), you must use + * on the main thread or another UI context (webview extensions), you must use * the async versions of the functions. this is because the sync versions of * the functions will block the main thread and cause the UI to freeze. + * * async version simply backs off exponentially until the operation succeeds. + * + * callback versions are just wrappers around the async versions. */ + export namespace promises { - export async function link(existing: string, path: string): Promise { - return await delayedBackOff(async () => linkSync(existing, path)); - } - export async function symlink(target: string, path: string): Promise { - return await delayedBackOff(async () => symlinkSync(target, path)); - } - export async function open(path: fs.PathLike, flags?: fs.OpenMode, mode?: fs.Mode): Promise { - return await delayedBackOff(async () => openSync(path, flags, mode)); - } - export async function opendir(path: string): Promise { - return await delayedBackOff(async () => opendirSync(path)); - } - export async function openfile(path: string, flags?: string, mode?: string | number): Promise { - return await delayedBackOff(async () => openfileSync(path, flags, mode)); - } - export async function close(fd: number): Promise { - return await delayedBackOff(async () => closeSync(fd)); - } - export async function lseek(fd: number, offset: number, whence: number): Promise { - return await delayedBackOff(async () => lseekSync(fd, offset, whence)); - } - export async function read( - fd: number, - buffer: Uint8Array, - offset?: number, - length?: number, - position?: number, - ): Promise { - return await delayedBackOff(async () => readSync(fd, buffer, offset, length, position)); - } - export async function write( - fd: number, - buffer: Uint8Array, - offset?: number, - length?: number, - position?: number, - ): Promise { - return await delayedBackOff(async () => writeSync(fd, buffer, offset, length, position)); - } - export async function fstat(fd: number): Promise | undefined> { - return await delayedBackOff(async () => fstatSync(fd)); - } - export async function fchmod(fd: number, mode: string | number): Promise { - return await delayedBackOff(async () => fchmodSync(fd, mode)); - } - export async function fchown(fd: number, uid: number, gid: number): Promise { - return await delayedBackOff(async () => fchownSync(fd, uid, gid)); - } - export async function ftruncate(fd: number, len?: number): Promise { - return await delayedBackOff(async () => ftruncateSync(fd, len)); - } - export async function futimes(fd: number, atime: number, mtime: number): Promise { - return await delayedBackOff(async () => futimesSync(fd, atime, mtime)); - } - export async function fsync(fd: number): Promise { - return await delayedBackOff(async () => fsyncSync(fd)); - } - export async function fdatasync(fd: number): Promise { - return await delayedBackOff(async () => fdatasyncSync(fd)); - } - export async function exists(path: fs.PathLike): Promise { - return await delayedBackOff(async () => existsSync(path)); - } - export async function freaddir(fd: number): Promise { - return await delayedBackOff(async () => freaddirSync(fd)); - } - export async function readdir( - path: fs.PathLike, - options?: { withFileTypes?: boolean; recursive?: boolean | undefined }, - ): Promise { - return await delayedBackOff(async () => readdirSync(path, options)); - } - export async function mkdir(path: fs.PathLike, options?: fs.MakeDirectoryOptions | string | number): Promise { - return await delayedBackOff(async () => mkdirSync(path, options)); - } - export async function mkdtemp(prefix: string): Promise { - return await delayedBackOff(async () => mkdtempSync(prefix)); - } - export async function writeFile( - pathOrFd: fs.PathLike | number, - data: Uint8Array | string, - options?: object | encoding, - ): Promise { - return await delayedBackOff(async () => writeFileSync(pathOrFd, data, options)); - } - export async function readFile( - pathOrFd: fs.PathLike | number, - options?: object | encoding, - ): Promise { - return await delayedBackOff(async () => readFileSync(pathOrFd, options)); - } - export async function appendFile( - pathOrFd: fs.PathLike | number, - data: Uint8Array | string, - options?: object | encoding, - ): Promise { - return await delayedBackOff(async () => appendFileSync(pathOrFd, data, options)); - } - export async function statfs(path: string, dump?: boolean): Promise { - return await delayedBackOff(async () => moveStatFsToJsMemory(statfsSync(path, dump))); - } - export async function chmod(path: fs.PathLike, mode: fs.Mode): Promise { - return await delayedBackOff(async () => chmodSync(path, mode)); - } - export async function chown(path: fs.PathLike, uid: number, gid: number): Promise { - return await delayedBackOff(async () => chownSync(path, uid, gid)); - } - export async function truncate(pathOrFd: fs.PathLike | number, len?: number): Promise { - return await delayedBackOff(async () => truncateSync(pathOrFd, len)); - } - export async function utimes(path: fs.PathLike, atime: fs.TimeLike, mtime: fs.TimeLike): Promise { - return await delayedBackOff(async () => utimesSync(path, atime, mtime)); - } - export async function unlink(path: fs.PathLike): Promise { - return await delayedBackOff(async () => unlinkSync(path)); - } - export async function rename(old_path: fs.PathLike, new_path: fs.PathLike): Promise { - return await delayedBackOff(async () => renameSync(old_path, new_path)); - } - export async function copyFile(src: string, dest: string, options?: object | undefined): Promise { - return await delayedBackOff(async () => copyFileSync(src, dest, options)); - } - export async function rmdir(path: string): Promise { - return await delayedBackOff(async () => rmdirSync(path)); - } - export async function rm(path: string, options?: object | undefined): Promise { - return await delayedBackOff(async () => rmSync(path, options)); - } - export async function access(path: fs.PathLike, mode?: number): Promise { - return await delayedBackOff(async () => accessSync(path, mode)); - } - export async function realpath(path: string): Promise { - return await delayedBackOff(async () => realpathSync(path)); - } - export async function readlink(path: string): Promise { - return await delayedBackOff(async () => readlinkSync(path)); - } - export async function stat( - path: fs.PathLike, - options?: { throwIfNoEntry: boolean }, - ): Promise | undefined> { - return await delayedBackOff(async () => statSync(path, options)); - } - export async function lchmod(path: fs.PathLike, mode: fs.Mode): Promise { - return await delayedBackOff(async () => lchmodSync(path, mode)); - } - export async function lchown(path: fs.PathLike, uid: number, gid: number): Promise { - return await delayedBackOff(async () => lchownSync(path, uid, gid)); - } - export async function lutimes(path: fs.PathLike, atime: fs.TimeLike, mtime: fs.TimeLike): Promise { - return await delayedBackOff(async () => lutimesSync(path, atime, mtime)); - } - export async function lstat( - path: fs.PathLike, - options?: { bigint: boolean }, - ): Promise | undefined> { - return await delayedBackOff(async () => lstatSync(path, options)); - } + export const link = promisify(linkSync); + export const symlink = promisify(symlinkSync); + export const open = promisify(openSync); + export const opendir = promisify(opendirSync); + export const openfile = promisify(openfileSync); + export const close = promisify(closeSync); + export const lseek = promisify(lseekSync); + export const read = promisify(readSync); + export const write = promisify(writeSync); + export const fstat = promisify(fstatSync); + export const fchmod = promisify(fchmodSync); + export const fchown = promisify(fchownSync); + export const ftruncate = promisify(ftruncateSync); + export const futimes = promisify(futimesSync); + export const fsync = promisify(fsyncSync); + export const fdatasync = promisify(fdatasyncSync); + export const exists = promisify(existsSync); + export const freaddir = promisify(freaddirSync); + export const readdir = promisify(readdirSync); + export const mkdir = promisify(mkdirSync); + export const mkdtemp = promisify(mkdtempSync); + export const writeFile = promisify(writeFileSync); + export const readFile = promisify(readFileSync); + export const appendFile = promisify(appendFileSync); + export const statfs = promisify(statfsSync); + export const chmod = promisify(chmodSync); + export const chown = promisify(chownSync); + export const truncate = promisify(truncateSync); + export const utimes = promisify(utimesSync); + export const unlink = promisify(unlinkSync); + export const rename = promisify(renameSync); + export const copyFile = promisify(copyFileSync); + export const rmdir = promisify(rmdirSync); + export const rm = promisify(rmSync); + export const access = promisify(accessSync); + export const realpath = promisify(realpathSync); + export const readlink = promisify(readlinkSync); + export const stat = promisify(statSync); + export const lchmod = promisify(lchmodSync); + export const lchown = promisify(lchownSync); + export const lutimes = promisify(lutimesSync); + export const lstat = promisify(lstatSync); +} + +export const link = callbackify(promises.link); +export const symlink = callbackify(promises.symlink); +export const open = callbackify(promises.open); +export const opendir = callbackify(promises.opendir); +export const openfile = callbackify(promises.openfile); +export const close = callbackify(promises.close); +export const lseek = callbackify(promises.lseek); +export const read = callbackify(promises.read); +export const write = callbackify(promises.write); +export const fstat = callbackify(promises.fstat); +export const fchmod = callbackify(promises.fchmod); +export const fchown = callbackify(promises.fchown); +export const ftruncate = callbackify(promises.ftruncate); +export const futimes = callbackify(promises.futimes); +export const fsync = callbackify(promises.fsync); +export const fdatasync = callbackify(promises.fdatasync); +export const exists = callbackify(promises.exists); +export const freaddir = callbackify(promises.freaddir); +export const readdir = callbackify(promises.readdir); +export const mkdir = callbackify(promises.mkdir); +export const mkdtemp = callbackify(promises.mkdtemp); +export const writeFile = callbackify(promises.writeFile); +export const readFile = callbackify(promises.readFile); +export const appendFile = callbackify(promises.appendFile); +export const statfs = callbackify(promises.statfs); +export const chmod = callbackify(promises.chmod); +export const chown = callbackify(promises.chown); +export const truncate = callbackify(promises.truncate); +export const utimes = callbackify(promises.utimes); +export const unlink = callbackify(promises.unlink); +export const rename = callbackify(promises.rename); +export const copyFile = callbackify(promises.copyFile); +export const rmdir = callbackify(promises.rmdir); +export const rm = callbackify(promises.rm); +export const access = callbackify(promises.access); +export const realpath = callbackify(promises.realpath); +export const readlink = callbackify(promises.readlink); +export const stat = callbackify(promises.stat); +export const lchmod = callbackify(promises.lchmod); +export const lchown = callbackify(promises.lchown); +export const lutimes = callbackify(promises.lutimes); +export const lstat = callbackify(promises.lstat); + +const emptyVolume = new Volume(); + +export function createReadStream(path: fs.PathLike, options?: string | object): Readable { + const _opts = typeof options === "string" ? { encoding: options } : options || {}; + return new emptyVolume.ReadStream.prototype.__proto__.constructor({ open, read, close }, path, _opts) as Readable; +} +export function createWriteStream(path: fs.PathLike, options?: string | object): Writable { + const _opts = typeof options === "string" ? { encoding: options } : options || {}; + return new emptyVolume.WriteStream.prototype.__proto__.constructor({ open, write, close }, path, _opts) as Writable; } diff --git a/tsconfig.json b/tsconfig.json index 8af4df3..a7a4c7d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,8 @@ "declaration": true, "module": "CommonJS", "target": "ES2017", - "allowJs": true + "allowJs": true, + "skipLibCheck": true }, - "files": ["src/index.ts"] + "files": ["./src/index.ts"], } diff --git a/webpack.config.ts b/webpack.config.ts index 9275017..7adf2fd 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -198,6 +198,7 @@ export default [ new webpack.ProvidePlugin({ Buffer: ["buffer", "Buffer"], process: "process", + URL: ["url", "URL"], }), new CopyPlugin({ patterns: [ @@ -252,6 +253,12 @@ export default [ }, resolve: { extensions: [".tsx", ".ts", ".jsx", ".js", ".json"], + fallback: { + fs: false, + url: require.resolve("url/"), + path: require.resolve("path-browserify"), + stream: require.resolve("stream-browserify"), + }, alias: { assert: "assert", buffer: "buffer",