mirror of
https://github.com/oven-sh/bun
synced 2026-02-11 11:29:02 +00:00
Polyfills for undici, streams/web, streams/consumer timers timers/promises, fs/promises, ws
This commit is contained in:
committed by
Jarred Sumner
parent
d9f6a3f2d2
commit
2cdbd2de83
108
src/javascript/jsc/fs_promises.exports.js
Normal file
108
src/javascript/jsc/fs_promises.exports.js
Normal file
@@ -0,0 +1,108 @@
|
||||
var fs = Bun.fs();
|
||||
|
||||
// note: this is not quite the same as how node does it
|
||||
// in some cases, node swaps around arguments or makes small tweaks to the return type
|
||||
// this is just better than nothing.
|
||||
function promisify(fsFunction) {
|
||||
// TODO: remove variadic arguments
|
||||
// we can use new Function() here instead
|
||||
// based on fsFucntion.length
|
||||
var obj = {
|
||||
[fsFunction.name]: function (resolve, reject, args) {
|
||||
var result;
|
||||
try {
|
||||
result = fsFunction.apply(fs, args);
|
||||
args = undefined;
|
||||
} catch (err) {
|
||||
args = undefined;
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(result);
|
||||
},
|
||||
};
|
||||
|
||||
var func = obj[fsFunction.name];
|
||||
|
||||
// TODO: consider @createPromiseCapabiilty intrinsic
|
||||
return (...args) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
func(resolve, reject, args);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export var access = promisify(fs.accessSync);
|
||||
export var appendFile = promisify(fs.appendFileSync);
|
||||
export var close = promisify(fs.closeSync);
|
||||
export var copyFile = promisify(fs.copyFileSync);
|
||||
export var exists = promisify(fs.existsSync);
|
||||
export var chown = promisify(fs.chownSync);
|
||||
export var chmod = promisify(fs.chmodSync);
|
||||
export var fchmod = promisify(fs.fchmodSync);
|
||||
export var fchown = promisify(fs.fchownSync);
|
||||
export var fstat = promisify(fs.fstatSync);
|
||||
export var fsync = promisify(fs.fsyncSync);
|
||||
export var ftruncate = promisify(fs.ftruncateSync);
|
||||
export var futimes = promisify(fs.futimesSync);
|
||||
export var lchmod = promisify(fs.lchmodSync);
|
||||
export var lchown = promisify(fs.lchownSync);
|
||||
export var link = promisify(fs.linkSync);
|
||||
export var lstat = promisify(fs.lstatSync);
|
||||
export var mkdir = promisify(fs.mkdirSync);
|
||||
export var mkdtemp = promisify(fs.mkdtempSync);
|
||||
export var open = promisify(fs.openSync);
|
||||
export var read = promisify(fs.readSync);
|
||||
export var write = promisify(fs.writeSync);
|
||||
export var readdir = promisify(fs.readdirSync);
|
||||
export var readFile = promisify(fs.readFileSync);
|
||||
export var readfile = readFile;
|
||||
export var writeFile = promisify(fs.writeFileSync);
|
||||
export var readlink = promisify(fs.readlinkSync);
|
||||
export var realpath = promisify(fs.realpathSync);
|
||||
export var rename = promisify(fs.renameSync);
|
||||
export var stat = promisify(fs.statSync);
|
||||
export var symlink = promisify(fs.symlinkSync);
|
||||
export var truncate = promisify(fs.truncateSync);
|
||||
export var unlink = promisify(fs.unlinkSync);
|
||||
export var utimes = promisify(fs.utimesSync);
|
||||
export var lutimes = promisify(fs.lutimesSync);
|
||||
|
||||
export default {
|
||||
access,
|
||||
appendFile,
|
||||
close,
|
||||
copyFile,
|
||||
exists,
|
||||
chown,
|
||||
chmod,
|
||||
fchmod,
|
||||
fchown,
|
||||
fstat,
|
||||
readfile,
|
||||
fsync,
|
||||
ftruncate,
|
||||
futimes,
|
||||
lchmod,
|
||||
lchown,
|
||||
link,
|
||||
lstat,
|
||||
mkdir,
|
||||
mkdtemp,
|
||||
open,
|
||||
read,
|
||||
write,
|
||||
readdir,
|
||||
readFile,
|
||||
writeFile,
|
||||
readlink,
|
||||
realpath,
|
||||
rename,
|
||||
stat,
|
||||
symlink,
|
||||
truncate,
|
||||
unlink,
|
||||
utimes,
|
||||
lutimes,
|
||||
};
|
||||
10
src/javascript/jsc/node_streams_consumer.exports.js
Normal file
10
src/javascript/jsc/node_streams_consumer.exports.js
Normal file
@@ -0,0 +1,10 @@
|
||||
export const arrayBuffer = Bun.readableStreamToArrayBuffer;
|
||||
export const text = Bun.readableStreamToText;
|
||||
export const json = (stream) =>
|
||||
Bun.readableStreamToText(stream).then(JSON.parse);
|
||||
|
||||
export const buffer = async (readableStream) => {
|
||||
return new Buffer(await arrayBuffer(readableStream));
|
||||
};
|
||||
|
||||
export const blob = Bun.readableStreamToBlob;
|
||||
18
src/javascript/jsc/node_streams_web.exports.js
Normal file
18
src/javascript/jsc/node_streams_web.exports.js
Normal file
@@ -0,0 +1,18 @@
|
||||
export const ReadableStream = globalThis.ReadableStream;
|
||||
export const ReadableStreamDefaultController =
|
||||
globalThis.ReadableStreamDefaultController;
|
||||
export const WritableStream = globalThis.WritableStream;
|
||||
export const WritableStreamDefaultController =
|
||||
globalThis.WritableStreamDefaultController;
|
||||
export const WritableStreamDefaultWriter =
|
||||
globalThis.WritableStreamDefaultWriter;
|
||||
export const TransformStream = globalThis.TransformStream;
|
||||
export const TransformStreamDefaultController =
|
||||
globalThis.TransformStreamDefaultController;
|
||||
|
||||
export const ByteLengthQueuingStrategy = globalThis.ByteLengthQueuingStrategy;
|
||||
export const CountQueuingStrategy = globalThis.CountQueuingStrategy;
|
||||
export const ReadableStreamBYOBReader = globalThis.ReadableStreamBYOBReader;
|
||||
export const ReadableStreamBYOBRequest = globalThis.ReadableStreamBYOBRequest;
|
||||
export const ReadableStreamDefaultReader =
|
||||
globalThis.ReadableStreamDefaultReader;
|
||||
20
src/javascript/jsc/node_timers.exports.js
Normal file
20
src/javascript/jsc/node_timers.exports.js
Normal file
@@ -0,0 +1,20 @@
|
||||
export const setInterval = globalThis.setInterval;
|
||||
export const setImmediate = globalThis.queueMicrotask;
|
||||
export const setTimeout = globalThis.setTimeout;
|
||||
export const clearInterval = globalThis.clearInterval;
|
||||
|
||||
// not implemented
|
||||
export const clearImmediate = () => {};
|
||||
|
||||
export const clearTimeout = globalThis.clearTimeout;
|
||||
export const queueMicrotask = globalThis.queueMicrotask;
|
||||
|
||||
export default {
|
||||
setInterval,
|
||||
queueMicrotask,
|
||||
setImmediate,
|
||||
setTimeout,
|
||||
clearInterval,
|
||||
clearImmediate,
|
||||
clearTimeout,
|
||||
};
|
||||
242
src/javascript/jsc/node_timers_promises.exports.js
Normal file
242
src/javascript/jsc/node_timers_promises.exports.js
Normal file
@@ -0,0 +1,242 @@
|
||||
// https://github.com/niksy/isomorphic-timers-promises/blob/master/index.js
|
||||
|
||||
const symbolAsyncIterator = Symbol.asyncIterator;
|
||||
|
||||
class ERR_INVALID_ARG_TYPE extends Error {
|
||||
constructor(name, expected, actual) {
|
||||
super(`${name} must be ${expected}, ${typeof actual} given`);
|
||||
this.code = "ERR_INVALID_ARG_TYPE";
|
||||
}
|
||||
}
|
||||
|
||||
class AbortError extends Error {
|
||||
constructor() {
|
||||
super("The operation was aborted");
|
||||
this.code = "ABORT_ERR";
|
||||
}
|
||||
}
|
||||
|
||||
function validateObject(object, name) {
|
||||
if (object === null || typeof object !== "object") {
|
||||
throw new ERR_INVALID_ARG_TYPE(name, "Object", object);
|
||||
}
|
||||
}
|
||||
|
||||
function validateBoolean(value, name) {
|
||||
if (typeof value !== "boolean") {
|
||||
throw new ERR_INVALID_ARG_TYPE(name, "boolean", value);
|
||||
}
|
||||
}
|
||||
|
||||
function validateAbortSignal(signal, name) {
|
||||
if (
|
||||
typeof signal !== "undefined" &&
|
||||
(signal === null || typeof signal !== "object" || !("aborted" in signal))
|
||||
) {
|
||||
throw new ERR_INVALID_ARG_TYPE(name, "AbortSignal", signal);
|
||||
}
|
||||
}
|
||||
|
||||
function asyncIterator({ next: nextFunction, return: returnFunction }) {
|
||||
const result = {};
|
||||
if (typeof nextFunction === "function") {
|
||||
result.next = nextFunction;
|
||||
}
|
||||
if (typeof returnFunction === "function") {
|
||||
result.return = returnFunction;
|
||||
}
|
||||
result[symbolAsyncIterator] = function () {
|
||||
return this;
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function setTimeoutPromise(after = 1, value, options = {}) {
|
||||
const arguments_ = [].concat(value ?? []);
|
||||
try {
|
||||
validateObject(options, "options");
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
const { signal, ref: reference = true } = options;
|
||||
try {
|
||||
validateAbortSignal(signal, "options.signal");
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
try {
|
||||
validateBoolean(reference, "options.ref");
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
if (signal?.aborted) {
|
||||
return Promise.reject(new AbortError());
|
||||
}
|
||||
let onCancel;
|
||||
const returnValue = new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => resolve(value), after, ...arguments_);
|
||||
if (!reference) {
|
||||
timeout?.unref?.();
|
||||
}
|
||||
if (signal) {
|
||||
onCancel = () => {
|
||||
clearTimeout(timeout);
|
||||
reject(new AbortError());
|
||||
};
|
||||
signal.addEventListener("abort", onCancel);
|
||||
}
|
||||
});
|
||||
if (typeof onCancel !== "undefined") {
|
||||
returnValue.finally(() => signal.removeEventListener("abort", onCancel));
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
function setImmediatePromise(value, options = {}) {
|
||||
try {
|
||||
validateObject(options, "options");
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
const { signal, ref: reference = true } = options;
|
||||
try {
|
||||
validateAbortSignal(signal, "options.signal");
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
try {
|
||||
validateBoolean(reference, "options.ref");
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
if (signal?.aborted) {
|
||||
return Promise.reject(new AbortError());
|
||||
}
|
||||
let onCancel;
|
||||
const returnValue = new Promise((resolve, reject) => {
|
||||
const immediate = setImmediate(() => resolve(value));
|
||||
if (!reference) {
|
||||
immediate?.unref?.();
|
||||
}
|
||||
if (signal) {
|
||||
onCancel = () => {
|
||||
clearImmediate(immediate);
|
||||
reject(new AbortError());
|
||||
};
|
||||
signal.addEventListener("abort", onCancel);
|
||||
}
|
||||
});
|
||||
if (typeof onCancel !== "undefined") {
|
||||
returnValue.finally(() => signal.removeEventListener("abort", onCancel));
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
function setIntervalPromise(after = 1, value, options = {}) {
|
||||
/* eslint-disable no-undefined, no-unreachable-loop, no-loop-func */
|
||||
try {
|
||||
validateObject(options, "options");
|
||||
} catch (error) {
|
||||
return asyncIterator({
|
||||
next: function () {
|
||||
return Promise.reject(error);
|
||||
},
|
||||
});
|
||||
}
|
||||
const { signal, ref: reference = true } = options;
|
||||
try {
|
||||
validateAbortSignal(signal, "options.signal");
|
||||
} catch (error) {
|
||||
return asyncIterator({
|
||||
next: function () {
|
||||
return Promise.reject(error);
|
||||
},
|
||||
});
|
||||
}
|
||||
try {
|
||||
validateBoolean(reference, "options.ref");
|
||||
} catch (error) {
|
||||
return asyncIterator({
|
||||
next: function () {
|
||||
return Promise.reject(error);
|
||||
},
|
||||
});
|
||||
}
|
||||
if (signal?.aborted) {
|
||||
return asyncIterator({
|
||||
next: function () {
|
||||
return Promise.reject(new AbortError());
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let onCancel, interval;
|
||||
|
||||
try {
|
||||
let notYielded = 0;
|
||||
let callback;
|
||||
interval = setInterval(() => {
|
||||
notYielded++;
|
||||
if (callback) {
|
||||
callback();
|
||||
callback = undefined;
|
||||
}
|
||||
}, after);
|
||||
if (!reference) {
|
||||
interval?.unref?.();
|
||||
}
|
||||
if (signal) {
|
||||
onCancel = () => {
|
||||
clearInterval(interval);
|
||||
if (callback) {
|
||||
callback();
|
||||
callback = undefined;
|
||||
}
|
||||
};
|
||||
signal.addEventListener("abort", onCancel);
|
||||
}
|
||||
|
||||
return asyncIterator({
|
||||
next: function () {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!signal?.aborted) {
|
||||
if (notYielded === 0) {
|
||||
callback = resolve;
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
} else if (notYielded === 0) {
|
||||
reject(new AbortError());
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
}).then(() => {
|
||||
if (notYielded > 0) {
|
||||
notYielded = notYielded - 1;
|
||||
return { done: false, value: value };
|
||||
}
|
||||
return { done: true };
|
||||
});
|
||||
},
|
||||
return: function () {
|
||||
clearInterval(interval);
|
||||
signal?.removeEventListener("abort", onCancel);
|
||||
return Promise.resolve({});
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
return asyncIterator({
|
||||
next: function () {
|
||||
clearInterval(interval);
|
||||
signal?.removeEventListener("abort", onCancel);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
setTimeoutPromise as setTimeout,
|
||||
setImmediatePromise as setImmediate,
|
||||
setIntervalPromise as setInterval,
|
||||
};
|
||||
104
src/javascript/jsc/undici.exports.js
Normal file
104
src/javascript/jsc/undici.exports.js
Normal file
@@ -0,0 +1,104 @@
|
||||
export var fetch = Bun.fetch;
|
||||
export var Response = globalThis.Response;
|
||||
export var Headers = globalThis.Headers;
|
||||
export var Request = globalThis.Request;
|
||||
export var URLSearchParams = globalThis.URLSearchParams;
|
||||
export var URL = globalThis.URL;
|
||||
export class File extends Blob {}
|
||||
export class FileReader extends EventTarget {
|
||||
constructor() {
|
||||
throw new Error("Not implemented yet!");
|
||||
}
|
||||
}
|
||||
|
||||
export class FormData {
|
||||
constructor() {
|
||||
throw new Error("Not implemented yet!");
|
||||
}
|
||||
}
|
||||
function notImplemented() {
|
||||
throw new Error("Not implemented in bun");
|
||||
}
|
||||
export function request() {
|
||||
throw new Error("Not implemented in bun");
|
||||
}
|
||||
export function stream() {
|
||||
throw new Error("Not implemented in bun");
|
||||
}
|
||||
export function pipeline() {
|
||||
throw new Error("Not implemented in bun");
|
||||
}
|
||||
export function connect() {
|
||||
throw new Error("Not implemented in bun");
|
||||
}
|
||||
export function upgrade() {
|
||||
throw new Error("Not implemented in bun");
|
||||
}
|
||||
|
||||
export class MockClient {
|
||||
constructor() {
|
||||
throw new Error("Not implemented in bun");
|
||||
}
|
||||
}
|
||||
export class MockPool {
|
||||
constructor() {
|
||||
throw new Error("Not implemented in bun");
|
||||
}
|
||||
}
|
||||
export class MockAgent {
|
||||
constructor() {
|
||||
throw new Error("Not implemented in bun");
|
||||
}
|
||||
}
|
||||
|
||||
export function mockErrors() {
|
||||
throw new Error("Not implemented in bun");
|
||||
}
|
||||
|
||||
export function Undici() {
|
||||
throw new Error("Not implemented in bun");
|
||||
}
|
||||
|
||||
Undici.Dispatcher =
|
||||
Undici.Pool =
|
||||
Undici.BalancedPool =
|
||||
Undici.Client =
|
||||
Undici.buildConnector =
|
||||
Undici.errors =
|
||||
Undici.Agent =
|
||||
Undici.setGlobalDispatcher =
|
||||
Undici.getGlobalDispatcher =
|
||||
Undici.request =
|
||||
Undici.stream =
|
||||
Undici.pipeline =
|
||||
Undici.connect =
|
||||
Undici.upgrade =
|
||||
Undici.MockClient =
|
||||
Undici.MockPool =
|
||||
Undici.MockAgent =
|
||||
Undici.mockErrors =
|
||||
notImplemented;
|
||||
|
||||
Undici.fetch = fetch;
|
||||
|
||||
export default {
|
||||
fetch,
|
||||
Response,
|
||||
Headers,
|
||||
Request,
|
||||
URLSearchParams,
|
||||
URL,
|
||||
File,
|
||||
FileReader,
|
||||
FormData,
|
||||
request,
|
||||
stream,
|
||||
pipeline,
|
||||
connect,
|
||||
upgrade,
|
||||
MockClient,
|
||||
MockPool,
|
||||
MockAgent,
|
||||
mockErrors,
|
||||
Undici,
|
||||
};
|
||||
Reference in New Issue
Block a user