mirror of
https://github.com/oven-sh/bun
synced 2026-02-23 18:21:41 +01:00
Compare commits
92 Commits
bun-v1.2.1
...
nektro-pat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0b6fec97d | ||
|
|
44c97fa591 | ||
|
|
7230b88c5d | ||
|
|
11978cd48d | ||
|
|
2fd2d6eeea | ||
|
|
2a2247bbb6 | ||
|
|
3ea7953474 | ||
|
|
b97cc6cb6c | ||
|
|
4dc7076cad | ||
|
|
8b10b0ae6b | ||
|
|
d4b02dcdc2 | ||
|
|
26e296a7e8 | ||
|
|
cb6abd2116 | ||
|
|
8bd05b534d | ||
|
|
7b134693d6 | ||
|
|
ec6cb8283e | ||
|
|
93ff4d97da | ||
|
|
465379d96a | ||
|
|
745b37038c | ||
|
|
1ee7bab0e7 | ||
|
|
915b8be722 | ||
|
|
448340cf3f | ||
|
|
9ca2e1445c | ||
|
|
4b297ef61a | ||
|
|
b82b330954 | ||
|
|
147fb975e1 | ||
|
|
b7c5bd0922 | ||
|
|
b97561f3f8 | ||
|
|
ea681fa9ec | ||
|
|
d531e86634 | ||
|
|
4c059b290c | ||
|
|
46881358e5 | ||
|
|
b58afbc7d5 | ||
|
|
092ad39f6c | ||
|
|
181da96604 | ||
|
|
397aa4a8a4 | ||
|
|
8d3f1d07f9 | ||
|
|
eb0ea8e96b | ||
|
|
5152254b2b | ||
|
|
83a2a64965 | ||
|
|
a1eb595d86 | ||
|
|
e6c516465e | ||
|
|
316cc20456 | ||
|
|
59b2a60790 | ||
|
|
d070f110d0 | ||
|
|
2d8009c19b | ||
|
|
33d656eebe | ||
|
|
1924c27f1d | ||
|
|
7a3dea8ac4 | ||
|
|
512dee748b | ||
|
|
41388204b9 | ||
|
|
98c66605e5 | ||
|
|
be65720f71 | ||
|
|
9f0ba15995 | ||
|
|
c97bbe6428 | ||
|
|
f5fdd02237 | ||
|
|
5cc34b667c | ||
|
|
80aff24951 | ||
|
|
1294128b47 | ||
|
|
506afcbc7e | ||
|
|
9646bf1a38 | ||
|
|
ce8cae060d | ||
|
|
6aaef99f88 | ||
|
|
acc2925bbb | ||
|
|
3c2e5c22e6 | ||
|
|
3349c995b5 | ||
|
|
842fe8664e | ||
|
|
00689e13a0 | ||
|
|
27a5712ed3 | ||
|
|
508b4d2783 | ||
|
|
0471254e4e | ||
|
|
b117d14650 | ||
|
|
a512ad5155 | ||
|
|
78fd584c0d | ||
|
|
d7a3e9e3a1 | ||
|
|
b07aea6161 | ||
|
|
ce5d4c8ddc | ||
|
|
032713c58c | ||
|
|
7e8e559fce | ||
|
|
218ee99155 | ||
|
|
6e3519fd49 | ||
|
|
a001c584dd | ||
|
|
b7c7b2dd7f | ||
|
|
7d7512076b | ||
|
|
a3809676e9 | ||
|
|
6bf2e57933 | ||
|
|
4ec410e0d7 | ||
|
|
ef17164c69 | ||
|
|
169f9eb1df | ||
|
|
a137a0e986 | ||
|
|
681a1ec3bb | ||
|
|
509bbb342b |
@@ -436,7 +436,10 @@ function getBuildCppStep(platform, options) {
|
||||
BUN_CPP_ONLY: "ON",
|
||||
...getBuildEnv(platform, options),
|
||||
},
|
||||
command: "bun run build:ci --target bun",
|
||||
// We used to build the C++ dependencies and bun in seperate steps.
|
||||
// However, as long as the zig build takes longer than both sequentially,
|
||||
// it's cheaper to run them in the same step. Can be revisited in the future.
|
||||
command: ["bun run build:ci --target bun", "bun run build:ci --target dependencies"],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -484,11 +487,7 @@ function getLinkBunStep(platform, options) {
|
||||
return {
|
||||
key: `${getTargetKey(platform)}-build-bun`,
|
||||
label: `${getTargetLabel(platform)} - build-bun`,
|
||||
depends_on: [
|
||||
`${getTargetKey(platform)}-build-vendor`,
|
||||
`${getTargetKey(platform)}-build-cpp`,
|
||||
`${getTargetKey(platform)}-build-zig`,
|
||||
],
|
||||
depends_on: [`${getTargetKey(platform)}-build-cpp`, `${getTargetKey(platform)}-build-zig`],
|
||||
agents: getCppAgent(platform, options),
|
||||
retry: getRetry(),
|
||||
cancel_on_build_failing: isMergeQueue(),
|
||||
@@ -1089,12 +1088,7 @@ async function getPipeline(options = {}) {
|
||||
group: getTargetLabel(target),
|
||||
steps: unifiedBuilds
|
||||
? [getBuildBunStep(target, options)]
|
||||
: [
|
||||
getBuildVendorStep(target, options),
|
||||
getBuildCppStep(target, options),
|
||||
getBuildZigStep(target, options),
|
||||
getLinkBunStep(target, options),
|
||||
],
|
||||
: [getBuildCppStep(target, options), getBuildZigStep(target, options), getLinkBunStep(target, options)],
|
||||
},
|
||||
imagePlatforms.has(imageKey) ? `${imageKey}-build-image` : undefined,
|
||||
);
|
||||
|
||||
8
.git-blame-ignore-revs
Normal file
8
.git-blame-ignore-revs
Normal file
@@ -0,0 +1,8 @@
|
||||
# Add commits to ignore in `git blame`. This allows large stylistic refactors to
|
||||
# avoid mucking up blames.
|
||||
#
|
||||
# To configure git to use this, run:
|
||||
#
|
||||
# git config blame.ignoreRevsFile .git-blame-ignore-revs
|
||||
#
|
||||
4ec410e0d7c5f6a712c323444edbf56b48d432d8 # make @import("bun") work in zig (#19096)
|
||||
1
.github/workflows/docs.yml
vendored
1
.github/workflows/docs.yml
vendored
@@ -4,6 +4,7 @@ on:
|
||||
push:
|
||||
paths:
|
||||
- "docs/**"
|
||||
- "packages/bun-types/**.d.ts"
|
||||
- "CONTRIBUTING.md"
|
||||
branches:
|
||||
- main
|
||||
|
||||
5
.github/workflows/lint.yml
vendored
5
.github/workflows/lint.yml
vendored
@@ -5,8 +5,7 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
BUN_VERSION: "1.2.0"
|
||||
OXLINT_VERSION: "0.15.0"
|
||||
BUN_VERSION: "1.2.10"
|
||||
|
||||
jobs:
|
||||
lint-js:
|
||||
@@ -19,4 +18,4 @@ jobs:
|
||||
with:
|
||||
bun-version: ${{ env.BUN_VERSION }}
|
||||
- name: Lint
|
||||
run: bunx oxlint --config oxlint.json --quiet --format github
|
||||
run: bun lint
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -153,6 +153,7 @@ test/cli/install/registry/packages/publish-pkg-*
|
||||
test/cli/install/registry/packages/@secret/publish-pkg-8
|
||||
test/js/third_party/prisma/prisma/sqlite/dev.db-journal
|
||||
tmp
|
||||
codegen-for-zig-team.tar.gz
|
||||
|
||||
# Dependencies
|
||||
/vendor
|
||||
|
||||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -30,11 +30,13 @@
|
||||
"zig.initialSetupDone": true,
|
||||
"zig.buildOption": "build",
|
||||
"zig.zls.zigLibPath": "${workspaceFolder}/vendor/zig/lib",
|
||||
"zig.buildArgs": ["-Dgenerated-code=./build/debug/codegen"],
|
||||
"zig.buildArgs": ["-Dgenerated-code=./build/debug/codegen", "--watch", "-fincremental"],
|
||||
"zig.zls.buildOnSaveStep": "check",
|
||||
// "zig.zls.enableBuildOnSave": true,
|
||||
// "zig.buildOnSave": true,
|
||||
"zig.buildFilePath": "${workspaceFolder}/build.zig",
|
||||
"zig.path": "${workspaceFolder}/vendor/zig/zig.exe",
|
||||
"zig.zls.path": "${workspaceFolder}/vendor/zig/zls.exe",
|
||||
"zig.formattingProvider": "zls",
|
||||
"zig.zls.enableInlayHints": false,
|
||||
"[zig]": {
|
||||
@@ -144,6 +146,8 @@
|
||||
"*.mdc": "markdown",
|
||||
"array": "cpp",
|
||||
"ios": "cpp",
|
||||
"oxlint.json": "jsonc",
|
||||
"bun.lock": "jsonc",
|
||||
},
|
||||
"C_Cpp.files.exclude": {
|
||||
"**/.vscode": true,
|
||||
|
||||
@@ -222,6 +222,9 @@ $ git -C vendor/WebKit checkout <commit_hash>
|
||||
# Optionally, you can use `make jsc` for a release build
|
||||
$ make jsc-debug && rm vendor/WebKit/WebKitBuild/Debug/JavaScriptCore/DerivedSources/inspector/InspectorProtocolObjects.h
|
||||
|
||||
# After an initial run of `make jsc-debug`, you can rebuild JSC with:
|
||||
$ cmake --build vendor/WebKit/WebKitBuild/Debug --target jsc && rm vendor/WebKit/WebKitBuild/Debug/JavaScriptCore/DerivedSources/inspector/InspectorProtocolObjects.h
|
||||
|
||||
# Build bun with the local JSC build
|
||||
$ bun run build:local
|
||||
```
|
||||
|
||||
2
Makefile
2
Makefile
@@ -1392,7 +1392,7 @@ jsc-build-linux-compile-build-debug:
|
||||
cmake --build $(WEBKIT_DEBUG_DIR) --config Debug --target jsc
|
||||
|
||||
|
||||
jsc-build-mac: jsc-force-fastjit jsc-build-mac-compile jsc-build-copy
|
||||
jsc-build-mac: jsc-force-fastjit jsc-build-mac-compile
|
||||
jsc-build-mac-debug: jsc-force-fastjit jsc-build-mac-compile-debug
|
||||
|
||||
jsc-build-linux: jsc-build-linux-compile-config jsc-build-linux-compile-build jsc-build-copy
|
||||
|
||||
263
build.zig
263
build.zig
@@ -4,7 +4,7 @@ const builtin = @import("builtin");
|
||||
const Build = std.Build;
|
||||
const Step = Build.Step;
|
||||
const Compile = Step.Compile;
|
||||
const LazyPath = Step.LazyPath;
|
||||
const LazyPath = Build.LazyPath;
|
||||
const Target = std.Target;
|
||||
const ResolvedTarget = std.Build.ResolvedTarget;
|
||||
const CrossTarget = std.zig.CrossTarget;
|
||||
@@ -18,21 +18,21 @@ const OperatingSystem = @import("src/env.zig").OperatingSystem;
|
||||
|
||||
const pathRel = fs.path.relative;
|
||||
|
||||
/// Do not rename this constant. It is scanned by some scripts to determine which zig version to install.
|
||||
/// When updating this, make sure to adjust SetupZig.cmake
|
||||
const recommended_zig_version = "0.14.0";
|
||||
|
||||
comptime {
|
||||
if (!std.mem.eql(u8, builtin.zig_version_string, recommended_zig_version)) {
|
||||
@compileError(
|
||||
"" ++
|
||||
"Bun requires Zig version " ++ recommended_zig_version ++ ", but you have " ++
|
||||
builtin.zig_version_string ++ ". This is automatically configured via Bun's " ++
|
||||
"CMake setup. You likely meant to run `bun run build`. If you are trying to " ++
|
||||
"upgrade the Zig compiler, edit ZIG_COMMIT in cmake/tools/SetupZig.cmake or " ++
|
||||
"comment this error out.",
|
||||
);
|
||||
}
|
||||
}
|
||||
// comptime {
|
||||
// if (!std.mem.eql(u8, builtin.zig_version_string, recommended_zig_version)) {
|
||||
// @compileError(
|
||||
// "" ++
|
||||
// "Bun requires Zig version " ++ recommended_zig_version ++ ", but you have " ++
|
||||
// builtin.zig_version_string ++ ". This is automatically configured via Bun's " ++
|
||||
// "CMake setup. You likely meant to run `bun run build`. If you are trying to " ++
|
||||
// "upgrade the Zig compiler, edit ZIG_COMMIT in cmake/tools/SetupZig.cmake or " ++
|
||||
// "comment this error out.",
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
const zero_sha = "0000000000000000000000000000000000000000";
|
||||
|
||||
@@ -93,6 +93,7 @@ const BunBuildOptions = struct {
|
||||
opts.addOption(bool, "baseline", this.isBaseline());
|
||||
opts.addOption(bool, "enable_logs", this.enable_logs);
|
||||
opts.addOption([]const u8, "reported_nodejs_version", b.fmt("{}", .{this.reported_nodejs_version}));
|
||||
opts.addOption(bool, "zig_self_hosted_backend", this.no_llvm);
|
||||
|
||||
const mod = opts.createModule();
|
||||
this.cached_options_module = mod;
|
||||
@@ -198,10 +199,8 @@ pub fn build(b: *Build) !void {
|
||||
|
||||
const bun_version = b.option([]const u8, "version", "Value of `Bun.version`") orelse "0.0.0";
|
||||
|
||||
b.reference_trace = ref_trace: {
|
||||
const trace = b.option(u32, "reference-trace", "Set the reference trace") orelse 24;
|
||||
break :ref_trace if (trace == 0) null else trace;
|
||||
};
|
||||
// Lower the default reference trace for incremental
|
||||
b.reference_trace = b.reference_trace orelse if (b.graph.incremental == true) 8 else 16;
|
||||
|
||||
const obj_format = b.option(ObjectFormat, "obj_format", "Output file for object files") orelse .obj;
|
||||
|
||||
@@ -335,6 +334,22 @@ pub fn build(b: *Build) !void {
|
||||
b.default_step.dependOn(step);
|
||||
}
|
||||
|
||||
// zig build watch
|
||||
// const enable_watch_step = b.option(bool, "watch_step", "Enable the watch step. This reads more files so it is off by default") orelse false;
|
||||
// if (no_llvm or enable_watch_step) {
|
||||
// self_hosted_watch.selfHostedExeBuild(b, &build_options) catch @panic("OOM");
|
||||
// }
|
||||
|
||||
// zig build check-debug
|
||||
{
|
||||
const step = b.step("check-debug", "Check for semantic analysis errors on some platforms");
|
||||
addMultiCheck(b, step, build_options, &.{
|
||||
.{ .os = .windows, .arch = .x86_64 },
|
||||
.{ .os = .mac, .arch = .aarch64 },
|
||||
.{ .os = .linux, .arch = .x86_64 },
|
||||
}, &.{.Debug});
|
||||
}
|
||||
|
||||
// zig build check-all
|
||||
{
|
||||
const step = b.step("check-all", "Check for semantic analysis errors on all supported platforms");
|
||||
@@ -388,7 +403,22 @@ pub fn build(b: *Build) !void {
|
||||
// zig build translate-c-headers
|
||||
{
|
||||
const step = b.step("translate-c", "Copy generated translated-c-headers.zig to zig-out");
|
||||
step.dependOn(&b.addInstallFile(getTranslateC(b, b.graph.host, .Debug).getOutput(), "translated-c-headers.zig").step);
|
||||
for ([_]TargetDescription{
|
||||
.{ .os = .windows, .arch = .x86_64 },
|
||||
.{ .os = .mac, .arch = .x86_64 },
|
||||
.{ .os = .mac, .arch = .aarch64 },
|
||||
.{ .os = .linux, .arch = .x86_64 },
|
||||
.{ .os = .linux, .arch = .aarch64 },
|
||||
.{ .os = .linux, .arch = .x86_64, .musl = true },
|
||||
.{ .os = .linux, .arch = .aarch64, .musl = true },
|
||||
}) |t| {
|
||||
const resolved = t.resolveTarget(b);
|
||||
step.dependOn(
|
||||
&b.addInstallFile(getTranslateC(b, resolved, .Debug), b.fmt("translated-c-headers/{s}.zig", .{
|
||||
resolved.result.zigTriple(b.allocator) catch @panic("OOM"),
|
||||
})).step,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// zig build enum-extractor
|
||||
@@ -405,23 +435,32 @@ pub fn build(b: *Build) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addMultiCheck(
|
||||
const TargetDescription = struct {
|
||||
os: OperatingSystem,
|
||||
arch: Arch,
|
||||
musl: bool = false,
|
||||
|
||||
fn resolveTarget(desc: TargetDescription, b: *Build) std.Build.ResolvedTarget {
|
||||
return b.resolveTargetQuery(.{
|
||||
.os_tag = OperatingSystem.stdOSTag(desc.os),
|
||||
.cpu_arch = desc.arch,
|
||||
.cpu_model = getCpuModel(desc.os, desc.arch) orelse .determined_by_arch_os,
|
||||
.os_version_min = getOSVersionMin(desc.os),
|
||||
.glibc_version = if (desc.musl) null else getOSGlibCVersion(desc.os),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
fn addMultiCheck(
|
||||
b: *Build,
|
||||
parent_step: *Step,
|
||||
root_build_options: BunBuildOptions,
|
||||
to_check: []const struct { os: OperatingSystem, arch: Arch, musl: bool = false },
|
||||
to_check: []const TargetDescription,
|
||||
optimize: []const std.builtin.OptimizeMode,
|
||||
) void {
|
||||
for (to_check) |check| {
|
||||
for (optimize) |mode| {
|
||||
const check_target = b.resolveTargetQuery(.{
|
||||
.os_tag = OperatingSystem.stdOSTag(check.os),
|
||||
.cpu_arch = check.arch,
|
||||
.cpu_model = getCpuModel(check.os, check.arch) orelse .determined_by_arch_os,
|
||||
.os_version_min = getOSVersionMin(check.os),
|
||||
.glibc_version = if (check.musl) null else getOSGlibCVersion(check.os),
|
||||
});
|
||||
|
||||
const check_target = check.resolveTarget(b);
|
||||
var options: BunBuildOptions = .{
|
||||
.target = check_target,
|
||||
.os = check.os,
|
||||
@@ -445,7 +484,13 @@ pub fn addMultiCheck(
|
||||
}
|
||||
}
|
||||
|
||||
fn getTranslateC(b: *Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *Step.TranslateC {
|
||||
fn getTranslateC(b: *Build, initial_target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) LazyPath {
|
||||
const target = b.resolveTargetQuery(q: {
|
||||
var query = initial_target.query;
|
||||
if (query.os_tag == .windows)
|
||||
query.abi = .gnu;
|
||||
break :q query;
|
||||
});
|
||||
const translate_c = b.addTranslateC(.{
|
||||
.root_source_file = b.path("src/c-headers-for-zig.h"),
|
||||
.target = target,
|
||||
@@ -461,33 +506,72 @@ fn getTranslateC(b: *Build, target: std.Build.ResolvedTarget, optimize: std.buil
|
||||
const str, const value = entry;
|
||||
translate_c.defineCMacroRaw(b.fmt("{s}={d}", .{ str, @intFromBool(value) }));
|
||||
}
|
||||
return translate_c;
|
||||
|
||||
if (target.result.os.tag == .windows) {
|
||||
// translate-c is unable to translate the unsuffixed windows functions
|
||||
// like `SetCurrentDirectory` since they are defined with an odd macro
|
||||
// that translate-c doesn't handle.
|
||||
//
|
||||
// #define SetCurrentDirectory __MINGW_NAME_AW(SetCurrentDirectory)
|
||||
//
|
||||
// In these cases, it's better to just reference the underlying function
|
||||
// directly: SetCurrentDirectoryW. To make the error better, a post
|
||||
// processing step is applied to the translate-c file.
|
||||
//
|
||||
// Additionally, this step makes it so that decls like NTSTATUS and
|
||||
// HANDLE point to the standard library structures.
|
||||
const helper_exe = b.addExecutable(.{
|
||||
.name = "process_windows_translate_c",
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("src/codegen/process_windows_translate_c.zig"),
|
||||
.target = b.graph.host,
|
||||
.optimize = .Debug,
|
||||
}),
|
||||
});
|
||||
const in = translate_c.getOutput();
|
||||
const run = b.addRunArtifact(helper_exe);
|
||||
run.addFileArg(in);
|
||||
const out = run.addOutputFileArg("c-headers-for-zig.zig");
|
||||
return out;
|
||||
}
|
||||
return translate_c.getOutput();
|
||||
}
|
||||
|
||||
pub fn addBunObject(b: *Build, opts: *BunBuildOptions) *Compile {
|
||||
const obj = b.addObject(.{
|
||||
.name = if (opts.optimize == .Debug) "bun-debug" else "bun",
|
||||
.root_source_file = switch (opts.os) {
|
||||
.wasm => b.path("root_wasm.zig"),
|
||||
else => b.path("src/main.zig"),
|
||||
// else => b.path("root_css.zig"),
|
||||
},
|
||||
// Create `@import("bun")`, containing most of Bun's code.
|
||||
const bun = b.createModule(.{
|
||||
.root_source_file = b.path("src/bun.zig"),
|
||||
});
|
||||
bun.addImport("bun", bun); // allow circular "bun" import
|
||||
addInternalImports(b, bun, opts);
|
||||
|
||||
const root = b.createModule(.{
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
|
||||
// Root module gets compilation flags. Forwarded as default to dependencies.
|
||||
.target = opts.target,
|
||||
.optimize = opts.optimize,
|
||||
.use_llvm = !opts.no_llvm,
|
||||
.use_lld = if (opts.os == .mac) false else !opts.no_llvm,
|
||||
});
|
||||
root.addImport("bun", bun);
|
||||
|
||||
// https://github.com/ziglang/zig/issues/17430
|
||||
.pic = true,
|
||||
|
||||
.omit_frame_pointer = false,
|
||||
.strip = false, // stripped at the end
|
||||
const obj = b.addObject(.{
|
||||
.name = if (opts.optimize == .Debug) "bun-debug" else "bun",
|
||||
.root_module = root,
|
||||
});
|
||||
configureObj(b, opts, obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
fn configureObj(b: *Build, opts: *BunBuildOptions, obj: *Compile) void {
|
||||
// Flags on root module get used for the compilation
|
||||
obj.root_module.omit_frame_pointer = false;
|
||||
obj.root_module.strip = false; // stripped at the end
|
||||
// https://github.com/ziglang/zig/issues/17430
|
||||
obj.root_module.pic = true;
|
||||
|
||||
// Object options
|
||||
obj.use_llvm = !opts.no_llvm;
|
||||
obj.use_lld = if (opts.os == .mac) false else !opts.no_llvm;
|
||||
if (opts.enable_asan) {
|
||||
if (@hasField(Build.Module, "sanitize_address")) {
|
||||
obj.root_module.sanitize_address = true;
|
||||
@@ -498,7 +582,6 @@ fn configureObj(b: *Build, opts: *BunBuildOptions, obj: *Compile) void {
|
||||
}
|
||||
obj.bundle_compiler_rt = false;
|
||||
obj.bundle_ubsan_rt = false;
|
||||
obj.root_module.omit_frame_pointer = false;
|
||||
|
||||
// Link libc
|
||||
if (opts.os != .wasm) {
|
||||
@@ -508,6 +591,7 @@ fn configureObj(b: *Build, opts: *BunBuildOptions, obj: *Compile) void {
|
||||
|
||||
// Disable stack probing on x86 so we don't need to include compiler_rt
|
||||
if (opts.arch.isX86()) {
|
||||
// TODO: enable on debug please.
|
||||
obj.root_module.stack_check = false;
|
||||
obj.root_module.stack_protector = false;
|
||||
}
|
||||
@@ -522,15 +606,18 @@ fn configureObj(b: *Build, opts: *BunBuildOptions, obj: *Compile) void {
|
||||
obj.root_module.valgrind = true;
|
||||
}
|
||||
}
|
||||
addInternalPackages(b, obj, opts);
|
||||
obj.root_module.addImport("build_options", opts.buildOptionsModule(b));
|
||||
|
||||
const translate_c = getTranslateC(b, opts.target, opts.optimize);
|
||||
obj.root_module.addImport("translated-c-headers", translate_c.createModule());
|
||||
}
|
||||
|
||||
const ObjectFormat = enum {
|
||||
/// Emitting LLVM bc files could allow a stronger LTO pass, however it
|
||||
/// doesn't yet work. It is left accessible with `-Dobj_format=bc` or in
|
||||
/// CMake with `-DZIG_OBJECT_FORMAT=bc`.
|
||||
///
|
||||
/// To use LLVM bitcode from Zig, more work needs to be done. Currently, an install of
|
||||
/// LLVM 18.1.7 does not compatible with what bitcode Zig 0.13 outputs (has LLVM 18.1.7)
|
||||
/// Change to "bc" to experiment, "Invalid record" means it is not valid output.
|
||||
bc,
|
||||
/// Emit a .o / .obj file for the bun-zig object.
|
||||
obj,
|
||||
};
|
||||
|
||||
@@ -560,16 +647,21 @@ fn exists(path: []const u8) bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
fn addInternalPackages(b: *Build, obj: *Compile, opts: *BunBuildOptions) void {
|
||||
fn addInternalImports(b: *Build, mod: *Module, opts: *BunBuildOptions) void {
|
||||
const os = opts.os;
|
||||
|
||||
mod.addImport("build_options", opts.buildOptionsModule(b));
|
||||
|
||||
const translate_c = getTranslateC(b, opts.target, opts.optimize);
|
||||
mod.addImport("translated-c-headers", b.createModule(.{ .root_source_file = translate_c }));
|
||||
|
||||
const zlib_internal_path = switch (os) {
|
||||
.windows => "src/deps/zlib.win32.zig",
|
||||
.linux, .mac => "src/deps/zlib.posix.zig",
|
||||
else => null,
|
||||
};
|
||||
if (zlib_internal_path) |path| {
|
||||
obj.root_module.addAnonymousImport("zlib-internal", .{
|
||||
mod.addAnonymousImport("zlib-internal", .{
|
||||
.root_source_file = b.path(path),
|
||||
});
|
||||
}
|
||||
@@ -579,7 +671,7 @@ fn addInternalPackages(b: *Build, obj: *Compile, opts: *BunBuildOptions) void {
|
||||
.windows => "src/async/windows_event_loop.zig",
|
||||
else => "src/async/stub_event_loop.zig",
|
||||
};
|
||||
obj.root_module.addAnonymousImport("async", .{
|
||||
mod.addAnonymousImport("async", .{
|
||||
.root_source_file = b.path(async_path),
|
||||
});
|
||||
|
||||
@@ -627,7 +719,7 @@ fn addInternalPackages(b: *Build, obj: *Compile, opts: *BunBuildOptions) void {
|
||||
entry.import
|
||||
else
|
||||
entry.file;
|
||||
obj.root_module.addAnonymousImport(import_path, .{
|
||||
mod.addAnonymousImport(import_path, .{
|
||||
.root_source_file = .{ .cwd_relative = path },
|
||||
});
|
||||
}
|
||||
@@ -637,16 +729,37 @@ fn addInternalPackages(b: *Build, obj: *Compile, opts: *BunBuildOptions) void {
|
||||
.{ .import = "completions-zsh", .file = b.path("completions/bun.zsh") },
|
||||
.{ .import = "completions-fish", .file = b.path("completions/bun.fish") },
|
||||
}) |entry| {
|
||||
obj.root_module.addAnonymousImport(entry.import, .{
|
||||
mod.addAnonymousImport(entry.import, .{
|
||||
.root_source_file = entry.file,
|
||||
});
|
||||
}
|
||||
|
||||
if (os == .windows) {
|
||||
obj.root_module.addAnonymousImport("bun_shim_impl.exe", .{
|
||||
mod.addAnonymousImport("bun_shim_impl.exe", .{
|
||||
.root_source_file = opts.windowsShim(b).exe.getEmittedBin(),
|
||||
});
|
||||
}
|
||||
|
||||
// Finally, make it so all modules share the same import table.
|
||||
propagateImports(mod) catch @panic("OOM");
|
||||
}
|
||||
|
||||
/// Makes all imports of `source_mod` visible to all of its dependencies.
|
||||
/// Does not replace existing imports.
|
||||
fn propagateImports(source_mod: *Module) !void {
|
||||
var seen = std.AutoHashMap(*Module, void).init(source_mod.owner.graph.arena);
|
||||
defer seen.deinit();
|
||||
var queue = std.ArrayList(*Module).init(source_mod.owner.graph.arena);
|
||||
defer queue.deinit();
|
||||
try queue.appendSlice(source_mod.import_table.values());
|
||||
while (queue.pop()) |mod| {
|
||||
if ((try seen.getOrPut(mod)).found_existing) continue;
|
||||
try queue.appendSlice(mod.import_table.values());
|
||||
|
||||
for (source_mod.import_table.keys(), source_mod.import_table.values()) |k, v|
|
||||
if (mod.import_table.get(k) == null)
|
||||
mod.addImport(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
fn validateGeneratedPath(path: []const u8) void {
|
||||
@@ -675,30 +788,34 @@ const WindowsShim = struct {
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "bun_shim_impl",
|
||||
.root_source_file = path,
|
||||
.target = target,
|
||||
.optimize = .ReleaseFast,
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = path,
|
||||
.target = target,
|
||||
.optimize = .ReleaseFast,
|
||||
.unwind_tables = .none,
|
||||
.omit_frame_pointer = true,
|
||||
.strip = true,
|
||||
.sanitize_thread = false,
|
||||
.single_threaded = true,
|
||||
.link_libc = false,
|
||||
}),
|
||||
.linkage = .static,
|
||||
.use_llvm = true,
|
||||
.use_lld = true,
|
||||
.unwind_tables = .none,
|
||||
.omit_frame_pointer = true,
|
||||
.strip = true,
|
||||
.linkage = .static,
|
||||
.sanitize_thread = false,
|
||||
.single_threaded = true,
|
||||
.link_libc = false,
|
||||
});
|
||||
|
||||
const dbg = b.addExecutable(.{
|
||||
.name = "bun_shim_debug",
|
||||
.root_source_file = path,
|
||||
.target = target,
|
||||
.optimize = .Debug,
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = path,
|
||||
.target = target,
|
||||
.optimize = .Debug,
|
||||
.single_threaded = true,
|
||||
.link_libc = false,
|
||||
}),
|
||||
.linkage = .static,
|
||||
.use_llvm = true,
|
||||
.use_lld = true,
|
||||
.linkage = .static,
|
||||
.single_threaded = true,
|
||||
.link_libc = false,
|
||||
});
|
||||
|
||||
return .{ .exe = exe, .dbg = dbg };
|
||||
|
||||
@@ -423,7 +423,7 @@ function(register_command)
|
||||
# libbun-profile.a is now over 5gb in size, compress it first
|
||||
list(APPEND CMD_COMMANDS COMMAND ${CMAKE_COMMAND} -E chdir ${BUILD_PATH} rm -r ${BUILD_PATH}/codegen)
|
||||
list(APPEND CMD_COMMANDS COMMAND ${CMAKE_COMMAND} -E chdir ${BUILD_PATH} rm -r ${CACHE_PATH})
|
||||
list(APPEND CMD_COMMANDS COMMAND ${CMAKE_COMMAND} -E chdir ${BUILD_PATH} gzip -6 libbun-profile.a)
|
||||
list(APPEND CMD_COMMANDS COMMAND ${CMAKE_COMMAND} -E chdir ${BUILD_PATH} gzip -1 libbun-profile.a)
|
||||
list(APPEND CMD_COMMANDS COMMAND ${CMAKE_COMMAND} -E chdir ${BUILD_PATH} buildkite-agent artifact upload libbun-profile.a.gz)
|
||||
else()
|
||||
list(APPEND CMD_COMMANDS COMMAND ${CMAKE_COMMAND} -E chdir ${BUILD_PATH} buildkite-agent artifact upload ${filename})
|
||||
|
||||
@@ -632,6 +632,7 @@ file(GLOB BUN_CXX_SOURCES ${CONFIGURE_DEPENDS}
|
||||
${CWD}/src/bun.js/bindings/sqlite/*.cpp
|
||||
${CWD}/src/bun.js/bindings/webcrypto/*.cpp
|
||||
${CWD}/src/bun.js/bindings/webcrypto/*/*.cpp
|
||||
${CWD}/src/bun.js/bindings/node/*.cpp
|
||||
${CWD}/src/bun.js/bindings/node/crypto/*.cpp
|
||||
${CWD}/src/bun.js/bindings/v8/*.cpp
|
||||
${CWD}/src/bun.js/bindings/v8/shim/*.cpp
|
||||
@@ -1089,6 +1090,7 @@ set(BUN_DEPENDENCIES
|
||||
BoringSSL
|
||||
Brotli
|
||||
Cares
|
||||
Highway
|
||||
LibDeflate
|
||||
LolHtml
|
||||
Lshpack
|
||||
|
||||
33
cmake/targets/BuildHighway.cmake
Normal file
33
cmake/targets/BuildHighway.cmake
Normal file
@@ -0,0 +1,33 @@
|
||||
register_repository(
|
||||
NAME
|
||||
highway
|
||||
REPOSITORY
|
||||
google/highway
|
||||
COMMIT
|
||||
12b325bc1793dee68ab2157995a690db859fe9e0
|
||||
)
|
||||
|
||||
set(HIGHWAY_CMAKE_ARGS
|
||||
# Build a static library
|
||||
-DBUILD_SHARED_LIBS=OFF
|
||||
# Enable position-independent code for linking into the main executable
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
# Disable unnecessary components
|
||||
-DHWY_ENABLE_TESTS=OFF
|
||||
-DHWY_ENABLE_EXAMPLES=OFF
|
||||
-DHWY_ENABLE_CONTRIB=OFF
|
||||
# Disable building of the install target
|
||||
-DHWY_ENABLE_INSTALL=OFF
|
||||
)
|
||||
|
||||
register_cmake_command(
|
||||
TARGET
|
||||
highway
|
||||
LIBRARIES
|
||||
hwy
|
||||
ARGS
|
||||
${HIGHWAY_CMAKE_ARGS}
|
||||
INCLUDES
|
||||
.
|
||||
hwy
|
||||
)
|
||||
@@ -2,7 +2,7 @@ option(WEBKIT_VERSION "The version of WebKit to use")
|
||||
option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading")
|
||||
|
||||
if(NOT WEBKIT_VERSION)
|
||||
set(WEBKIT_VERSION 06820714a7990ea77c78157f9eeaabaf56c2098a)
|
||||
set(WEBKIT_VERSION e26b186170c48a40d872c05a5ba61821a3f31196)
|
||||
endif()
|
||||
|
||||
string(SUBSTRING ${WEBKIT_VERSION} 0 16 WEBKIT_VERSION_PREFIX)
|
||||
|
||||
@@ -50,7 +50,7 @@ optionx(ZIG_OBJECT_FORMAT "obj|bc" "Output file format for Zig object files" DEF
|
||||
|
||||
optionx(ZIG_LOCAL_CACHE_DIR FILEPATH "The path to local the zig cache directory" DEFAULT ${CACHE_PATH}/zig/local)
|
||||
optionx(ZIG_GLOBAL_CACHE_DIR FILEPATH "The path to the global zig cache directory" DEFAULT ${CACHE_PATH}/zig/global)
|
||||
optionx(ZIG_COMPILER_SAFE BOOL "Download a ReleaseSafe build of the Zig compiler. Only availble on macos aarch64." DEFAULT OFF)
|
||||
optionx(ZIG_COMPILER_SAFE BOOL "Download a ReleaseSafe build of the Zig compiler. Only availble on macos aarch64." DEFAULT ${BUILDKITE})
|
||||
|
||||
setenv(ZIG_LOCAL_CACHE_DIR ${ZIG_LOCAL_CACHE_DIR})
|
||||
setenv(ZIG_GLOBAL_CACHE_DIR ${ZIG_GLOBAL_CACHE_DIR})
|
||||
|
||||
@@ -21,28 +21,6 @@ const exists = await redis.exists("greeting");
|
||||
await redis.del("greeting");
|
||||
```
|
||||
|
||||
{% features title="Features" %}
|
||||
|
||||
{% icon size=20 name="Bolt" /%} Fast native implementation using Zig and JavaScriptCore
|
||||
|
||||
{% icon size=20 name="Link" /%} Automatic pipelining for better performance
|
||||
|
||||
{% icon size=20 name="EthernetPort" /%} Auto-reconnect with exponential backoff
|
||||
|
||||
{% icon size=20 name="Omega" /%} Support for RESP3 protocol
|
||||
|
||||
{% icon size=20 name="Lock" /%} TLS support
|
||||
|
||||
{% icon size=20 name="Clock" /%} Connection management with configurable timeouts
|
||||
|
||||
{% icon size=20 name="IndentDecrease" /%} Offline command queue
|
||||
|
||||
{% icon size=20 name="Settings" /%} Automatic configuration with environment variables
|
||||
|
||||
{% icon size=20 name="Hash" /%} Support for hash, set, and other Redis data structures
|
||||
|
||||
{% /features %}
|
||||
|
||||
## Getting Started
|
||||
|
||||
To use the Redis client, you first need to create a connection:
|
||||
|
||||
@@ -117,14 +117,14 @@ type WebSocketData = {
|
||||
// TypeScript: specify the type of `data`
|
||||
Bun.serve<WebSocketData>({
|
||||
fetch(req, server) {
|
||||
// use a library to parse cookies
|
||||
const cookies = parseCookies(req.headers.get("Cookie"));
|
||||
const cookies = new Bun.CookieMap(req.headers.get("cookie")!);
|
||||
|
||||
server.upgrade(req, {
|
||||
// this object must conform to WebSocketData
|
||||
data: {
|
||||
createdAt: Date.now(),
|
||||
channelId: new URL(req.url).searchParams.get("channelId"),
|
||||
authToken: cookies["X-Token"],
|
||||
authToken: cookies.get("X-Token"),
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ pub fn add(global: *JSC.JSGlobalObject, a: i32, b: i32) !i32 {
|
||||
const gen = bun.gen.math; // "math" being this file's basename
|
||||
|
||||
const std = @import("std");
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const JSC = bun.JSC;
|
||||
```
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
|
||||
|
||||
### [`node:events`](https://nodejs.org/api/events.html)
|
||||
|
||||
🟢 Fully implemented. `EventEmitterAsyncResource` uses `AsyncResource` underneath. 100% of Node.js's test suite for EventEmitter passes.
|
||||
🟢 Fully implemented. 100% of Node.js's test suite passes. `EventEmitterAsyncResource` uses `AsyncResource` underneath.
|
||||
|
||||
### [`node:fs`](https://nodejs.org/api/fs.html)
|
||||
|
||||
@@ -106,8 +106,6 @@ This page is updated regularly to reflect compatibility status of the latest ver
|
||||
|
||||
🟡 Missing `secureHeapUsed` `setEngine` `setFips`
|
||||
|
||||
Some methods are not optimized yet.
|
||||
|
||||
### [`node:domain`](https://nodejs.org/api/domain.html)
|
||||
|
||||
🟡 Missing `Domain` `active`
|
||||
@@ -142,7 +140,7 @@ Some methods are not optimized yet.
|
||||
|
||||
### [`node:util`](https://nodejs.org/api/util.html)
|
||||
|
||||
🟡 Missing `getCallSite` `getCallSites` `getSystemErrorMap` `getSystemErrorMessage` `transferableAbortSignal` `transferableAbortController` `MIMEType` `MIMEParams`
|
||||
🟡 Missing `getCallSite` `getCallSites` `getSystemErrorMap` `getSystemErrorMessage` `transferableAbortSignal` `transferableAbortController`
|
||||
|
||||
### [`node:v8`](https://nodejs.org/api/v8.html)
|
||||
|
||||
@@ -379,6 +377,7 @@ The table below lists all globals implemented by Node.js and Bun's current compa
|
||||
### [`require()`](https://nodejs.org/api/globals.html#require)
|
||||
|
||||
🟢 Fully implemented, including [`require.main`](https://nodejs.org/api/modules.html#requiremain), [`require.cache`](https://nodejs.org/api/modules.html#requirecache), [`require.resolve`](https://nodejs.org/api/modules.html#requireresolverequest-options).
|
||||
|
||||
### [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
|
||||
|
||||
🟢 Fully implemented.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const std = @import("std");
|
||||
|
||||
const path_handler = @import("../src/resolver/resolve_path.zig");
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const string = bun.string;
|
||||
const Output = bun.Output;
|
||||
const Global = bun.Global;
|
||||
|
||||
@@ -98,7 +98,7 @@ chunks.push(`// Auto-generated file. Do not edit.
|
||||
// This used to be a comptime block, but it made the build too slow.
|
||||
// Compressing the completions list saves about 100 KB of binary size.
|
||||
const std = @import("std");
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const zstd = bun.zstd;
|
||||
const Environment = bun.Environment;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const string = bun.string;
|
||||
const Output = bun.Output;
|
||||
const Global = bun.Global;
|
||||
@@ -12,7 +12,6 @@ const C = bun.C;
|
||||
const clap = @import("../src/deps/zig-clap/clap.zig");
|
||||
|
||||
const URL = @import("../src/url.zig").URL;
|
||||
const Headers = @import("../src/bun.js/webcore/response.zig").Headers;
|
||||
const Method = @import("../src/http/method.zig").Method;
|
||||
const ColonListType = @import("../src/cli/colon_list_type.zig").ColonListType;
|
||||
const HeadersTuple = ColonListType(string, noop_resolver);
|
||||
|
||||
@@ -61,7 +61,6 @@ zig_keywords = {
|
||||
'try',
|
||||
'union',
|
||||
'unreachable',
|
||||
'usingnamespace',
|
||||
'var',
|
||||
'volatile',
|
||||
'while',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// most of this file is copy pasted from other files in misctools
|
||||
const std = @import("std");
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const string = bun.string;
|
||||
const Output = bun.Output;
|
||||
const Global = bun.Global;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const std = @import("std");
|
||||
|
||||
const path_handler = @import("../src/resolver/resolve_path.zig");
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const string = bun.string;
|
||||
const Output = bun.Output;
|
||||
const Global = bun.Global;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const std = @import("std");
|
||||
|
||||
const path_handler = @import("../src/resolver/resolve_path.zig");
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const string = bun.string;
|
||||
const Output = bun.Output;
|
||||
const Global = bun.Global;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const std = @import("std");
|
||||
|
||||
const path_handler = @import("../src/resolver/resolve_path.zig");
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const string = bun.string;
|
||||
const Output = bun.Output;
|
||||
const Global = bun.Global;
|
||||
|
||||
38
oxlint.json
38
oxlint.json
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/oxc-project/oxc/refs/heads/main/npm/oxlint/configuration_schema.json",
|
||||
"categories": {
|
||||
"correctness": "warn" // TODO: gradually fix bugs and turn this to error
|
||||
"correctness": "error"
|
||||
},
|
||||
"rules": {
|
||||
"const-comparisons": "off", // TODO: there's a bug when comparing private identifiers. Re-enable once it's fixed.
|
||||
"const-comparisons": "error",
|
||||
"no-cond-assign": "error",
|
||||
"no-const-assign": "error",
|
||||
"no-debugger": "error",
|
||||
@@ -13,12 +13,35 @@
|
||||
"no-empty-pattern": "error",
|
||||
"import/no-duplicates": "error",
|
||||
|
||||
"no-useless-escape": "off" // there's a lot of these. Should be fixed eventually.
|
||||
"no-control-regex": "off",
|
||||
|
||||
"no-useless-escape": "off",
|
||||
"no-this-alias": "off", // many intentional this aliases
|
||||
"triple-slash-reference": "off", // many intentional triple slash references
|
||||
|
||||
// This rule is dumb.
|
||||
// Array.from is MUCH slower than new Array(size).
|
||||
"no-new-array": "off",
|
||||
|
||||
// We have custom thenables. This is not a bug.
|
||||
"no-thenable": "off",
|
||||
|
||||
"no-undef-init": "error",
|
||||
|
||||
// We use this in some cases. The ordering is deliberate.
|
||||
"no-unsafe-finally": "off",
|
||||
|
||||
// We use !!$debug to check if the debugger is enabled.
|
||||
// Boolean() is also generally slower than !!.
|
||||
"no-extra-boolean-cast": "off",
|
||||
|
||||
// Eslint is not a type checker.
|
||||
"no-throw-literal": "off"
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"vendor",
|
||||
"build",
|
||||
"test/snapshots/**",
|
||||
"bench",
|
||||
"bench/react-hello-world/*.js",
|
||||
"bun.lock",
|
||||
|
||||
@@ -32,8 +55,13 @@
|
||||
"test/bundler/transpiler/with-statement-works.js", // parser doesn't allow `with` statement
|
||||
"test/js/node/module/extensions-fixture", // these files are not meant to be linted
|
||||
"test/cli/run/module-type-fixture",
|
||||
"test/bundler/transpiler/with-statement-works.js" // parser doesn't allow `with` statement
|
||||
"test/bundler/transpiler/with-statement-works.js", // parser doesn't allow `with` statement
|
||||
|
||||
// TODO: fix these
|
||||
"src/js/node/http2.ts",
|
||||
"src/js/node/http.ts"
|
||||
],
|
||||
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["test/**", "examples/**", "packages/bun-internal/test/runners/**"],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "bun",
|
||||
"version": "1.2.10",
|
||||
"version": "1.2.12",
|
||||
"workspaces": [
|
||||
"./packages/bun-types"
|
||||
],
|
||||
@@ -31,6 +31,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "bun run build:debug",
|
||||
"watch": "zig build check --watch -fincremental --prominent-compile-errors --global-cache-dir build/debug/zig-check-cache --zig-lib-dir vendor/zig/lib",
|
||||
"bd": "(bun run --silent build:debug &> /tmp/bun.debug.build.log || (cat /tmp/bun.debug.build.log && rm -rf /tmp/bun.debug.build.log && exit 1)) && rm -f /tmp/bun.debug.build.log && ./build/debug/bun-debug",
|
||||
"build:debug": "bun ./scripts/build.mjs -GNinja -DCMAKE_BUILD_TYPE=Debug -B build/debug",
|
||||
"build:valgrind": "bun ./scripts/build.mjs -GNinja -DCMAKE_BUILD_TYPE=Debug -DENABLE_BASELINE=ON -ENABLE_VALGRIND=ON -B build/debug-valgrind",
|
||||
@@ -51,7 +52,7 @@
|
||||
"fmt": "bun run prettier",
|
||||
"fmt:cpp": "bun run clang-format",
|
||||
"fmt:zig": "bun run zig-format",
|
||||
"lint": "oxlint --config oxlint.json",
|
||||
"lint": "bunx oxlint --config=oxlint.json --format=github src/js",
|
||||
"lint:fix": "oxlint --config oxlint.json --fix",
|
||||
"test": "node scripts/runner.node.mjs --exec-path ./build/debug/bun-debug",
|
||||
"test:release": "node scripts/runner.node.mjs --exec-path ./build/release/bun",
|
||||
|
||||
172
packages/bun-polyfills/.gitignore
vendored
172
packages/bun-polyfills/.gitignore
vendored
@@ -1,172 +0,0 @@
|
||||
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
|
||||
|
||||
# Logs
|
||||
|
||||
logs
|
||||
_.log
|
||||
npm-debug.log_
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# Runtime data
|
||||
|
||||
pids
|
||||
_.pid
|
||||
_.seed
|
||||
\*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
|
||||
coverage
|
||||
\*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
|
||||
.lock-wscript
|
||||
|
||||
# Dependency directories
|
||||
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
|
||||
\*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
|
||||
\*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
|
||||
.cache/
|
||||
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.\*
|
||||
|
||||
# Misc
|
||||
|
||||
_*
|
||||
.old
|
||||
.vscode
|
||||
!build
|
||||
@@ -1,9 +0,0 @@
|
||||
# Bun APIs Polyfills
|
||||
|
||||
Polyfills for Bun's JavaScript runtime APIs for use in environments outside of Bun, such as Node.js or the browser¹.
|
||||
|
||||
¹ **Note:** The current priority is Node.js, browser support will vary per polyfill.
|
||||
|
||||
## Usage
|
||||
|
||||
This is currently a work in progress and is not ready for general use.
|
||||
@@ -1,181 +0,0 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "bun-polyfills",
|
||||
"dependencies": {
|
||||
"bun-wasm": "link:bun-wasm",
|
||||
"chalk": "^5.3.0",
|
||||
"js-md4": "^0.3.2",
|
||||
"open-editor": "^4.0.0",
|
||||
"supports-color": "^9.4.0",
|
||||
"which": "^3.0.1",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.4.5",
|
||||
"@types/which": "^3.0.0",
|
||||
"bun-types": "^0.7.0",
|
||||
"copyfiles": "^2.4.1",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.0.0",
|
||||
},
|
||||
"optionalPeers": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@types/node": ["@types/node@20.4.5", "", {}, "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg=="],
|
||||
|
||||
"@types/which": ["@types/which@3.0.0", "", {}, "sha512-ASCxdbsrwNfSMXALlC3Decif9rwDMu+80KGp5zI2RLRotfMsTv7fHL8W8VDp24wymzDyIFudhUeSCugrgRFfHQ=="],
|
||||
|
||||
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
||||
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||
|
||||
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||
|
||||
"brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
|
||||
|
||||
"bun-types": ["bun-types@0.7.0", "", {}, "sha512-jXFiYtwSUQtD/Y3LHRWeWNwhFaUYvcO96zI7y3gSPgTq+ozxXpuTGDxABLdIKmFc672Q7Qp/OgrfJFEjg4Mnkg=="],
|
||||
|
||||
"bun-wasm": ["bun-wasm@link:bun-wasm", {}],
|
||||
|
||||
"chalk": ["chalk@5.3.0", "", {}, "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w=="],
|
||||
|
||||
"cliui": ["cliui@7.0.4", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="],
|
||||
|
||||
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
|
||||
|
||||
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
|
||||
|
||||
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
|
||||
|
||||
"copyfiles": ["copyfiles@2.4.1", "", { "dependencies": { "glob": "^7.0.5", "minimatch": "^3.0.3", "mkdirp": "^1.0.4", "noms": "0.0.0", "through2": "^2.0.1", "untildify": "^4.0.0", "yargs": "^16.1.0" }, "bin": { "copyfiles": "copyfiles", "copyup": "copyfiles" } }, "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg=="],
|
||||
|
||||
"core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="],
|
||||
|
||||
"cross-spawn": ["cross-spawn@7.0.3", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w=="],
|
||||
|
||||
"define-lazy-prop": ["define-lazy-prop@2.0.0", "", {}, "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="],
|
||||
|
||||
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
|
||||
"env-editor": ["env-editor@1.1.0", "", {}, "sha512-7AXskzN6T7Q9TFcKAGJprUbpQa4i1VsAetO9rdBqbGMGlragTziBgWt4pVYJMBWHQlLoX0buy6WFikzPH4Qjpw=="],
|
||||
|
||||
"escalade": ["escalade@3.1.1", "", {}, "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="],
|
||||
|
||||
"execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="],
|
||||
|
||||
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
|
||||
|
||||
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
|
||||
|
||||
"get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="],
|
||||
|
||||
"glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
|
||||
|
||||
"human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="],
|
||||
|
||||
"inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="],
|
||||
|
||||
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||
|
||||
"is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="],
|
||||
|
||||
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
|
||||
|
||||
"is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
|
||||
|
||||
"is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="],
|
||||
|
||||
"isarray": ["isarray@0.0.1", "", {}, "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="],
|
||||
|
||||
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||
|
||||
"js-md4": ["js-md4@0.3.2", "", {}, "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA=="],
|
||||
|
||||
"line-column-path": ["line-column-path@3.0.0", "", { "dependencies": { "type-fest": "^2.0.0" } }, "sha512-Atocnm7Wr9nuvAn97yEPQa3pcQI5eLQGBz+m6iTb+CVw+IOzYB9MrYK7jI7BfC9ISnT4Fu0eiwhAScV//rp4Hw=="],
|
||||
|
||||
"merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="],
|
||||
|
||||
"mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
|
||||
|
||||
"minimatch": ["minimatch@3.0.8", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q=="],
|
||||
|
||||
"mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
|
||||
|
||||
"noms": ["noms@0.0.0", "", { "dependencies": { "inherits": "^2.0.1", "readable-stream": "~1.0.31" } }, "sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow=="],
|
||||
|
||||
"npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="],
|
||||
|
||||
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
||||
|
||||
"onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
|
||||
|
||||
"open": ["open@8.4.2", "", { "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", "is-wsl": "^2.2.0" } }, "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ=="],
|
||||
|
||||
"open-editor": ["open-editor@4.0.0", "", { "dependencies": { "env-editor": "^1.0.0", "execa": "^5.1.1", "line-column-path": "^3.0.0", "open": "^8.4.0" } }, "sha512-5mKZ98iFdkivozt5XTCOspoKbL3wtYu6oOoVxfWQ0qUX9NYsK8pdkHE7VUHXr+CwyC3nf6mV0S5FPsMS65innw=="],
|
||||
|
||||
"path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="],
|
||||
|
||||
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||
|
||||
"process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="],
|
||||
|
||||
"readable-stream": ["readable-stream@1.0.34", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", "isarray": "0.0.1", "string_decoder": "~0.10.x" } }, "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg=="],
|
||||
|
||||
"require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
|
||||
|
||||
"safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||
|
||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||
|
||||
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||
|
||||
"signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
|
||||
|
||||
"string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
|
||||
"string_decoder": ["string_decoder@0.10.31", "", {}, "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="],
|
||||
|
||||
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
|
||||
"strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
|
||||
|
||||
"supports-color": ["supports-color@9.4.0", "", {}, "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw=="],
|
||||
|
||||
"through2": ["through2@2.0.5", "", { "dependencies": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" } }, "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ=="],
|
||||
|
||||
"type-fest": ["type-fest@2.19.0", "", {}, "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA=="],
|
||||
|
||||
"untildify": ["untildify@4.0.0", "", {}, "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw=="],
|
||||
|
||||
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
||||
|
||||
"which": ["which@3.0.1", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg=="],
|
||||
|
||||
"wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
|
||||
|
||||
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
||||
|
||||
"xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="],
|
||||
|
||||
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
|
||||
|
||||
"yargs": ["yargs@16.2.0", "", { "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } }, "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw=="],
|
||||
|
||||
"yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="],
|
||||
|
||||
"cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
"glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
||||
|
||||
"through2/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
|
||||
|
||||
"through2/readable-stream/isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
|
||||
|
||||
"through2/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
// @ts-check
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const { instance } = /** @type {ZighashInstance} */(
|
||||
await WebAssembly.instantiate(
|
||||
fs.readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), 'zighash.wasm')),
|
||||
{
|
||||
env: {
|
||||
/** @param {any} x */
|
||||
print(x) { console.log(x); },
|
||||
},
|
||||
}
|
||||
)
|
||||
);
|
||||
const exports = instance.exports;
|
||||
const mem = exports.memory;
|
||||
const memview = {
|
||||
get u8() { return new Uint8Array(mem.buffer); },
|
||||
get u16() { return new Uint16Array(mem.buffer); },
|
||||
get u32() { return new Uint32Array(mem.buffer); },
|
||||
get u64() { return new BigUint64Array(mem.buffer); },
|
||||
get i8() { return new Int8Array(mem.buffer); },
|
||||
get i16() { return new Int16Array(mem.buffer); },
|
||||
get i32() { return new Int32Array(mem.buffer); },
|
||||
get i64() { return new BigInt64Array(mem.buffer); },
|
||||
get f32() { return new Float32Array(mem.buffer); },
|
||||
get f64() { return new Float64Array(mem.buffer); },
|
||||
};
|
||||
|
||||
const nullptr = { ptr: -1, size: 0 };
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
const allocBuffer = (
|
||||
/** @type {ArrayBufferView | ArrayBuffer | SharedArrayBuffer} */ buf,
|
||||
/** @type {boolean=} */ nullTerminate = false,
|
||||
) => {
|
||||
const size = buf.byteLength + +nullTerminate;
|
||||
if (size === 0) return nullptr;
|
||||
const ptr = exports.alloc(size);
|
||||
if (ptr === -1) throw new Error('WASM memory allocation failed');
|
||||
const u8heap = memview.u8;
|
||||
u8heap.set(new Uint8Array(ArrayBuffer.isView(buf) ? buf.buffer : buf), ptr);
|
||||
if (nullTerminate) u8heap[ptr + buf.byteLength] = 0;
|
||||
return { ptr, size };
|
||||
};
|
||||
const allocString = (
|
||||
/** @type {string} */ str,
|
||||
/** @type {boolean=} */ nullTerminate = true,
|
||||
) => {
|
||||
const strbuf = encoder.encode(str);
|
||||
return allocBuffer(strbuf, nullTerminate);
|
||||
};
|
||||
|
||||
/** @type {JSSeededHash64Function} */
|
||||
export function wyhash(input = '', seed = 0n) {
|
||||
const { ptr, size } = typeof input === 'string' ? allocString(input, false) : allocBuffer(input);
|
||||
return BigInt.asUintN(64, exports.wyhash(ptr, size, seed));
|
||||
}
|
||||
/** @type {JSHash32Function} */
|
||||
export function adler32(input = '') {
|
||||
const { ptr, size } = typeof input === 'string' ? allocString(input, false) : allocBuffer(input);
|
||||
return exports.adler32(ptr, size) >>> 0;
|
||||
}
|
||||
/** @type {JSHash32Function} */
|
||||
export function crc32(input = '') {
|
||||
const { ptr, size } = typeof input === 'string' ? allocString(input, false) : allocBuffer(input);
|
||||
return exports.crc32(ptr, size) >>> 0;
|
||||
}
|
||||
/** @type {JSHash32Function} */
|
||||
export function cityhash32(input = '') {
|
||||
const { ptr, size } = typeof input === 'string' ? allocString(input, false) : allocBuffer(input);
|
||||
return exports.cityhash32(ptr, size) >>> 0;
|
||||
}
|
||||
/** @type {JSSeededHash64Function} */
|
||||
export function cityhash64(input = '', seed = 0n) {
|
||||
const { ptr, size } = typeof input === 'string' ? allocString(input, false) : allocBuffer(input);
|
||||
return BigInt.asUintN(64, exports.cityhash64(ptr, size, seed));
|
||||
}
|
||||
/** @type {JSSeededHash32Function} */
|
||||
export function xxhash32(input = '', seed = 0) {
|
||||
const { ptr, size } = typeof input === 'string' ? allocString(input, false) : allocBuffer(input);
|
||||
return exports.xxhash32(ptr, size, seed)
|
||||
}
|
||||
/** @type {JSSeededHash64Function} */
|
||||
export function xxhash64(input = '', seed = 0n) {
|
||||
const { ptr, size } = typeof input === 'string' ? allocString(input, false) : allocBuffer(input);
|
||||
return BigInt.asUintN(64, exports.xxhash64(ptr, size, seed));
|
||||
}
|
||||
/** @type {JSSeededHash64Function} */
|
||||
export function xxhash3(input = '', seed = 0n) {
|
||||
const { ptr, size } = typeof input === 'string' ? allocString(input, false) : allocBuffer(input);
|
||||
return BigInt.asUintN(64, exports.xxhash3(ptr, size, seed));
|
||||
}
|
||||
/** @type {JSSeededHash32Function} */
|
||||
export function murmur32v3(input = '', seed = 0) {
|
||||
const { ptr, size } = typeof input === 'string' ? allocString(input, false) : allocBuffer(input);
|
||||
return exports.murmur32v3(ptr, size, seed); //! Bun doesn't unsigned-cast this one, likely unintended but for now we'll do the same
|
||||
}
|
||||
/** @type {JSSeededHash32Function} */
|
||||
export function murmur32v2(input = '', seed = 0) {
|
||||
const { ptr, size } = typeof input === 'string' ? allocString(input, false) : allocBuffer(input);
|
||||
return exports.murmur32v2(ptr, size, seed); //! Bun doesn't unsigned-cast this one, likely unintended but for now we'll do the same
|
||||
}
|
||||
/** @type {JSSeededHash64Function} */
|
||||
export function murmur64v2(input = '', seed = 0n) {
|
||||
const { ptr, size } = typeof input === 'string' ? allocString(input, false) : allocBuffer(input);
|
||||
return BigInt.asUintN(64, exports.murmur64v2(ptr, size, seed));
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"name": "zighash-wasm",
|
||||
"module": "index.mjs",
|
||||
"scripts": {
|
||||
"build": "bun run clean && zig build-lib src/main.zig --name zighash -target wasm32-freestanding -dynamic -rdynamic -OReleaseSmall",
|
||||
"clean": "rm -f *.wasm *.o"
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
const std = @import("std");
|
||||
|
||||
extern fn print(*const u8) void;
|
||||
|
||||
comptime {
|
||||
std.debug.assert(@alignOf(u16) >= 2);
|
||||
std.debug.assert(@alignOf(u32) >= 4);
|
||||
std.debug.assert(@alignOf(u64) >= 8);
|
||||
std.debug.assert(@alignOf(i16) >= 2);
|
||||
std.debug.assert(@alignOf(i32) >= 4);
|
||||
std.debug.assert(@alignOf(i64) >= 8);
|
||||
}
|
||||
|
||||
export fn alloc(size: u32) [*]const u8 {
|
||||
const slice = std.heap.wasm_allocator.alloc(u8, size) catch @panic("wasm failed to allocate memory");
|
||||
return slice.ptr;
|
||||
}
|
||||
|
||||
export fn wyhash(input_ptr: [*]const u8, input_size: u32, seed: u64) u64 {
|
||||
const input: []const u8 = input_ptr[0..input_size];
|
||||
defer std.heap.wasm_allocator.free(input);
|
||||
return std.hash.Wyhash.hash(seed, input);
|
||||
}
|
||||
export fn adler32(input_ptr: [*]const u8, input_size: u32) u32 {
|
||||
const input: []const u8 = input_ptr[0..input_size];
|
||||
defer std.heap.wasm_allocator.free(input);
|
||||
return std.hash.Adler32.hash(input);
|
||||
}
|
||||
export fn crc32(input_ptr: [*]const u8, input_size: u32) u32 {
|
||||
const input: []const u8 = input_ptr[0..input_size];
|
||||
defer std.heap.wasm_allocator.free(input);
|
||||
return std.hash.Crc32.hash(input);
|
||||
}
|
||||
export fn cityhash32(input_ptr: [*]const u8, input_size: u32) u32 {
|
||||
const input: []const u8 = input_ptr[0..input_size];
|
||||
defer std.heap.wasm_allocator.free(input);
|
||||
return std.hash.CityHash32.hash(input);
|
||||
}
|
||||
export fn cityhash64(input_ptr: [*]const u8, input_size: u32, seed: u64) u64 {
|
||||
const input: []const u8 = input_ptr[0..input_size];
|
||||
defer std.heap.wasm_allocator.free(input);
|
||||
return std.hash.CityHash64.hashWithSeed(input, seed);
|
||||
}
|
||||
export fn xxhash32(input_ptr: [*]const u8, input_size: u32, seed: u32) u32 {
|
||||
const input: []const u8 = input_ptr[0..input_size];
|
||||
defer std.heap.wasm_allocator.free(input);
|
||||
return std.hash.XxHash32.hash(seed, input);
|
||||
}
|
||||
export fn xxhash64(input_ptr: [*]const u8, input_size: u32, seed: u64) u64 {
|
||||
const input: []const u8 = input_ptr[0..input_size];
|
||||
defer std.heap.wasm_allocator.free(input);
|
||||
return std.hash.XxHash64.hash(seed, input);
|
||||
}
|
||||
export fn xxhash3(input_ptr: [*]const u8, input_size: u32, seed: u64) u64 {
|
||||
const input: []const u8 = input_ptr[0..input_size];
|
||||
defer std.heap.wasm_allocator.free(input);
|
||||
return std.hash.XxHash3.hash(seed, input);
|
||||
}
|
||||
export fn murmur32v3(input_ptr: [*]const u8, input_size: u32, seed: u32) u32 {
|
||||
const input: []const u8 = input_ptr[0..input_size];
|
||||
defer std.heap.wasm_allocator.free(input);
|
||||
return std.hash.Murmur3_32.hashWithSeed(input, seed);
|
||||
}
|
||||
export fn murmur32v2(input_ptr: [*]const u8, input_size: u32, seed: u32) u32 {
|
||||
const input: []const u8 = input_ptr[0..input_size];
|
||||
defer std.heap.wasm_allocator.free(input);
|
||||
return std.hash.Murmur2_32.hashWithSeed(input, seed);
|
||||
}
|
||||
export fn murmur64v2(input_ptr: [*]const u8, input_size: u32, seed: u64) u64 {
|
||||
const input: []const u8 = input_ptr[0..input_size];
|
||||
defer std.heap.wasm_allocator.free(input);
|
||||
return std.hash.Murmur2_64.hashWithSeed(input, seed);
|
||||
}
|
||||
28
packages/bun-polyfills/lib/zighash/types.d.ts
vendored
28
packages/bun-polyfills/lib/zighash/types.d.ts
vendored
@@ -1,28 +0,0 @@
|
||||
type WasmHash32Function = (input_ptr: number, input_size: number) => number;
|
||||
type WasmHash64Function = (input_ptr: number, input_size: number) => bigint;
|
||||
type WasmSeededHash32Function = (input_ptr: number, input_size: number, seed: number) => number;
|
||||
type WasmSeededHash64Function = (input_ptr: number, input_size: number, seed: bigint) => bigint;
|
||||
type JSHash32Function = (input: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer) => number;
|
||||
type JSHash64Function = (input: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer) => bigint;
|
||||
type JSSeededHash32Function = (input: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: number) => number;
|
||||
type JSSeededHash64Function = (input: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, seed?: bigint) => bigint;
|
||||
|
||||
type ZighashInstance = WebAssembly.WebAssemblyInstantiatedSource & {
|
||||
instance: {
|
||||
exports: {
|
||||
memory: WebAssembly.Memory,
|
||||
alloc(size: number): number,
|
||||
wyhash: WasmSeededHash64Function,
|
||||
adler32: WasmHash32Function,
|
||||
crc32: WasmHash32Function,
|
||||
cityhash32: WasmHash32Function,
|
||||
cityhash64: WasmSeededHash64Function,
|
||||
xxhash32: WasmSeededHash32Function,
|
||||
xxhash64: WasmSeededHash64Function,
|
||||
xxhash3: WasmSeededHash64Function,
|
||||
murmur32v3: WasmSeededHash32Function,
|
||||
murmur32v2: WasmSeededHash32Function,
|
||||
murmur64v2: WasmSeededHash64Function,
|
||||
};
|
||||
};
|
||||
}
|
||||
Binary file not shown.
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"type": "module",
|
||||
"name": "bun-polyfills",
|
||||
"module": "src/index.ts",
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.4.5",
|
||||
"@types/which": "^3.0.0",
|
||||
"bun-types": "^0.7.0",
|
||||
"copyfiles": "^2.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"node": "node --enable-source-maps --import ./dist/src/repl.js",
|
||||
"clean": "rm -rf dist",
|
||||
"preprocess": "bun tools/updateversions.ts",
|
||||
"build": "bun run clean && bun run preprocess && bunx tsc && bunx copyfiles \"./lib/**/*.wasm\" dist",
|
||||
"build/wasm": "bun run build/zighash",
|
||||
"build/zighash": "cd lib/zighash && bun run build && cd ../.."
|
||||
},
|
||||
"dependencies": {
|
||||
"bun-wasm": "link:bun-wasm",
|
||||
"chalk": "^5.3.0",
|
||||
"js-md4": "^0.3.2",
|
||||
"open-editor": "^4.0.0",
|
||||
"supports-color": "^9.4.0",
|
||||
"which": "^3.0.1"
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
//? Implements: Red colored console.error from Bun
|
||||
//if (Bun.enableANSIColors) {
|
||||
// const RED = '\x1B[31m' as const;
|
||||
// const RESET = '\x1B[0m' as const;
|
||||
// const consoleError = console.error;
|
||||
// console.error = (...args) => {
|
||||
// if (typeof args[0] === 'string') args[0] = RED + args[0];
|
||||
// consoleError(...args, RESET);
|
||||
// };
|
||||
//}
|
||||
|
||||
//? Implements: for await (const line of console) { ... }
|
||||
console[Symbol.asyncIterator] = async function* () {
|
||||
while (true) yield await new Promise(resolve => {
|
||||
process.stdin.on('data', (data: Buffer | string) => {
|
||||
const str = data.toString('utf-8').replaceAll(/[\r\n]+/g, '');
|
||||
resolve(str);
|
||||
});
|
||||
});
|
||||
} satisfies Console[typeof Symbol.asyncIterator];
|
||||
|
||||
//? Implements: Bun-exclusive console function
|
||||
console.write = ((...data) => {
|
||||
const str = data.map(val => {
|
||||
if (val instanceof ArrayBuffer) val = new TextDecoder('utf-8').decode(val);
|
||||
else if (typeof val === 'object') val = new TextDecoder('utf-8').decode(val.buffer);
|
||||
return val;
|
||||
}).join('');
|
||||
process.stdout.write(str);
|
||||
return new TextEncoder('utf-8').encode(str).byteLength;
|
||||
}) satisfies Console['write'];
|
||||
@@ -1,32 +0,0 @@
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createRequire } from 'node:module';
|
||||
|
||||
// Without an ESM loader, this polyfill is impossible to apply automatically,
|
||||
// due to the per-module nature of import.meta. In order to use this polyfill,
|
||||
// you must import it in every module that uses import.meta, and call it with
|
||||
// the import.meta object as the argument. When the polyfills are integrated
|
||||
// with bun build, this could be done automatically by the build process at
|
||||
// the top of every module file bundled.
|
||||
|
||||
export default function polyfillImportMeta(metaIn: ImportMeta) {
|
||||
const require2 = createRequire(metaIn.url);
|
||||
const metapath = fileURLToPath(metaIn.url);
|
||||
const meta: ImportMeta = {
|
||||
url: metaIn.url,
|
||||
main: metapath === process.argv[1],
|
||||
path: metapath,
|
||||
dir: path.dirname(metapath),
|
||||
file: path.basename(metapath),
|
||||
require: require2,
|
||||
resolve: metaIn.resolve,
|
||||
resolveSync(id: string, parent?: string) {
|
||||
return require2.resolve(id, {
|
||||
paths: typeof parent === 'string' ? [
|
||||
path.resolve(parent.startsWith('file://') ? fileURLToPath(parent) : parent, '..')
|
||||
] : undefined,
|
||||
});
|
||||
},
|
||||
};
|
||||
Object.assign(metaIn, meta);
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import { version } from '../modules/bun.js';
|
||||
import './console.js';
|
||||
import './process.js';
|
||||
import os from 'node:os';
|
||||
|
||||
//? NodeJS Blob doesn't implement Blob.json(), so we need to polyfill it.
|
||||
Blob.prototype.json = async function json<T>(this: Blob): Promise<T> {
|
||||
try {
|
||||
return JSON.parse(await this.text()) as T;
|
||||
} catch (err) {
|
||||
Error.captureStackTrace(err as Error, json);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
//? navigator global object polyfill
|
||||
Reflect.set(globalThis, 'navigator', {
|
||||
userAgent: `Bun/${version}`,
|
||||
hardwareConcurrency: os.cpus().length,
|
||||
});
|
||||
|
||||
//? method only available in Bun
|
||||
// this isn't quite accurate, but it shouldn't break anything and is currently here just for matching bun and node types
|
||||
const ReadableStreamDefaultReaderPrototype = Object.getPrototypeOf(new ReadableStream().getReader());
|
||||
Reflect.set(
|
||||
ReadableStreamDefaultReaderPrototype, 'readMany',
|
||||
function readMany(this: ReadableStreamDefaultReader): Promise<ReadableStreamDefaultReadManyResult<any>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const result: ReadableStreamDefaultReadManyResult<any> = {
|
||||
value: [],
|
||||
size: 0,
|
||||
done: true
|
||||
};
|
||||
this.read().then(({ done, value }) => {
|
||||
if (done) resolve(result);
|
||||
else {
|
||||
result.value.push(value);
|
||||
result.size = value.length;
|
||||
result.done = false;
|
||||
resolve(result);
|
||||
}
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -1,19 +0,0 @@
|
||||
|
||||
if (typeof process === 'object' && process !== null) {
|
||||
// process polyfills (node-only)
|
||||
Reflect.set(process, 'isBun', 1 satisfies Process['isBun']);
|
||||
Reflect.set(process, 'browser', false satisfies Process['browser']);
|
||||
|
||||
const NULL_VERSION = '0'.repeat(39) + '1';
|
||||
process.versions.bun = '0.7.1' satisfies Process['versions'][string]; // TODO: This can probably be fetched from somewhere in the repo
|
||||
process.versions.webkit = NULL_VERSION satisfies Process['versions'][string];
|
||||
process.versions.mimalloc = NULL_VERSION satisfies Process['versions'][string];
|
||||
process.versions.libarchive = NULL_VERSION satisfies Process['versions'][string];
|
||||
process.versions.picohttpparser = NULL_VERSION satisfies Process['versions'][string];
|
||||
process.versions.boringssl = NULL_VERSION satisfies Process['versions'][string];
|
||||
process.versions.zig = '0.10.0' satisfies Process['versions'][string];
|
||||
Reflect.set(process, 'revision', NULL_VERSION satisfies Process['revision']);
|
||||
|
||||
// Doesn't work on Windows sadly
|
||||
//Object.defineProperty(process, 'execPath', { value: path.resolve(root, 'cli.js') });
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export * from './modules/bun.js';
|
||||
export * as default from './modules/bun.js';
|
||||
import './global/index.js';
|
||||
@@ -1,518 +0,0 @@
|
||||
import type {
|
||||
BunPlugin, PluginConstraints, PluginBuilder, OnLoadCallback, OnResolveCallback, HeapSnapshot,
|
||||
EditorOptions, SpawnOptions, Subprocess, SyncSubprocess, FileBlob as BunFileBlob, ArrayBufferView, Hash
|
||||
} from 'bun';
|
||||
import { TextDecoderStream } from 'node:stream/web';
|
||||
import { NotImplementedError, type SystemError } from '../utils/errors.js';
|
||||
import { streamToBuffer, isArrayBufferView, isFileBlob, isOptions } from '../utils/misc.js';
|
||||
import dnsPolyfill from './bun/dns.js';
|
||||
import { FileSink } from './bun/filesink.js';
|
||||
import {
|
||||
bunHash, bunHashProto,
|
||||
MD4 as MD4Polyfill, MD5 as MD5Polyfill,
|
||||
SHA1 as SHA1Polyfill, SHA224 as SHA224Polyfill,
|
||||
SHA256 as SHA256Polyfill, SHA384 as SHA384Polyfill,
|
||||
SHA512 as SHA512Polyfill, SHA512_256 as SHA512_256Polyfill
|
||||
} from './bun/hashes.js';
|
||||
import { ArrayBufferSink as ArrayBufferSinkPolyfill } from './bun/arraybuffersink.js';
|
||||
import { FileBlob, NodeJSStreamFileBlob } from './bun/fileblob.js';
|
||||
import TranspilerImpl from './bun/transpiler.js';
|
||||
import fs from 'node:fs';
|
||||
import v8 from 'node:v8';
|
||||
import path from 'node:path';
|
||||
import util from 'node:util';
|
||||
import zlib from 'node:zlib';
|
||||
import streams from 'node:stream';
|
||||
import workers from 'node:worker_threads';
|
||||
import chp, { type ChildProcess, type StdioOptions, type SpawnSyncReturns } from 'node:child_process';
|
||||
import { fileURLToPath as fileURLToPathNode, pathToFileURL as pathToFileURLNode } from 'node:url';
|
||||
import npm_which from 'which';
|
||||
import openEditor from 'open-editor';
|
||||
|
||||
export const main = path.resolve(process.cwd(), process.argv[1] ?? 'repl') satisfies typeof Bun.main;
|
||||
|
||||
//? These are automatically updated on build by tools/updateversions.ts, do not edit manually.
|
||||
export const version = '0.7.4' satisfies typeof Bun.version;
|
||||
export const revision = '56816a3ec845a4b9fc40ade34dbe5c0033433d51' satisfies typeof Bun.revision;
|
||||
|
||||
export const gc = (globalThis.gc ? (() => (globalThis.gc!(), process.memoryUsage().heapUsed)) : (() => {
|
||||
const err = new Error('[bun-polyfills] Garbage collection polyfills are only available when Node.js is ran with the --expose-gc flag.');
|
||||
Error.captureStackTrace(err, gc);
|
||||
throw err;
|
||||
})) satisfies typeof Bun.gc;
|
||||
|
||||
//getter(bun, 'cwd', proc.cwd); //! Can't named export a getter
|
||||
export const origin = '' satisfies typeof Bun.origin;
|
||||
// @ts-expect-error ---
|
||||
export const stdin = new NodeJSStreamFileBlob(process.stdin) satisfies typeof Bun.stdin;
|
||||
// @ts-expect-error ---
|
||||
export const stdout = new NodeJSStreamFileBlob(process.stdout) satisfies typeof Bun.stdout;
|
||||
// @ts-expect-error ---
|
||||
export const stderr = new NodeJSStreamFileBlob(process.stderr) satisfies typeof Bun.stderr;
|
||||
export const argv = [process.argv0, ...process.execArgv, ...process.argv.slice(1)] satisfies typeof Bun.argv;
|
||||
export const env = process.env satisfies typeof Bun.env;
|
||||
Object.setPrototypeOf(env, {
|
||||
toJSON(this: typeof env) { return { ...this }; }
|
||||
});
|
||||
// @ts-expect-error supports-color types are unbelievably bad
|
||||
export const enableANSIColors = (await import('supports-color')).createSupportsColor().hasBasic satisfies typeof Bun.enableANSIColors;
|
||||
|
||||
export const hash = bunHash satisfies typeof Bun.hash;
|
||||
Object.setPrototypeOf(hash, bunHashProto satisfies Hash);
|
||||
|
||||
export const unsafe = {
|
||||
gcAggressionLevel: () => 0, //! no-op
|
||||
arrayBufferToString: (buf) => new TextDecoder().decode(buf),
|
||||
segfault: () => {
|
||||
const segfault = new Error();
|
||||
segfault.name = 'SegfaultTest';
|
||||
segfault.message = '';
|
||||
console.error(segfault);
|
||||
process.exit(1);
|
||||
}
|
||||
} satisfies typeof Bun['unsafe'];
|
||||
|
||||
export const Transpiler = TranspilerImpl satisfies typeof Bun.Transpiler;
|
||||
|
||||
export const SHA1 = SHA1Polyfill satisfies typeof Bun.SHA1;
|
||||
export const MD5 = MD5Polyfill satisfies typeof Bun.MD5;
|
||||
export const MD4 = MD4Polyfill satisfies typeof Bun.MD4;
|
||||
export const SHA224 = SHA224Polyfill satisfies typeof Bun.SHA224;
|
||||
export const SHA512 = SHA512Polyfill satisfies typeof Bun.SHA512;
|
||||
export const SHA384 = SHA384Polyfill satisfies typeof Bun.SHA384;
|
||||
export const SHA256 = SHA256Polyfill satisfies typeof Bun.SHA256;
|
||||
export const SHA512_256 = SHA512_256Polyfill satisfies typeof Bun.SHA512_256;
|
||||
|
||||
export const indexOfLine = ((data, offset) => {
|
||||
if (data instanceof ArrayBuffer || data instanceof SharedArrayBuffer) data = new Uint8Array(data);
|
||||
if (data instanceof DataView || !(data instanceof Uint8Array)) data = new Uint8Array(data.buffer);
|
||||
return data.indexOf(10, offset);
|
||||
}) satisfies typeof Bun.indexOfLine;
|
||||
|
||||
const peek_ = function peek(promise: Parameters<typeof Bun.peek>[0]) {
|
||||
throw new NotImplementedError('Bun.peek', peek);
|
||||
};
|
||||
peek_.status = (promise => {
|
||||
return util.inspect(promise).includes('<pending>') ? 'pending'
|
||||
: util.inspect(promise).includes('<rejected>') ? 'rejected' : 'fulfilled';
|
||||
}) satisfies typeof Bun.peek.status;
|
||||
export const peek = peek_ satisfies typeof Bun.peek;
|
||||
|
||||
export const sleep = (ms => {
|
||||
return new Promise(r => setTimeout(r, ms instanceof Date ? ms.valueOf() - Date.now() : ms));
|
||||
}) satisfies typeof Bun.sleep;
|
||||
export const sleepSync = (ms => {
|
||||
if (ms < 0) throw new TypeError('argument to sleepSync must not be negative');
|
||||
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
||||
}) satisfies typeof Bun.sleepSync;
|
||||
|
||||
//? This is not 1:1 matching, but no one should be relying on the exact output of this function anyway.
|
||||
//? To quote Node's inspect itself: "The output of util.inspect() may change at any time and should not be depended upon programmatically."
|
||||
//? Of course in Node's case some didn't listen and relied on the output of util.inspect() anyway, but hopefully this won't happen with this one.
|
||||
export const inspect = ((arg: any): string => util.inspect(arg, {
|
||||
breakLength: Infinity,
|
||||
colors: false,
|
||||
compact: true,
|
||||
customInspect: false,
|
||||
depth: Infinity,
|
||||
getters: true,
|
||||
maxArrayLength: Infinity,
|
||||
maxStringLength: Infinity,
|
||||
showHidden: false,
|
||||
showProxy: false,
|
||||
sorted: false
|
||||
})) satisfies typeof Bun.inspect;
|
||||
|
||||
export const resolveSync = ((id: string, parent: string) => import.meta.resolveSync(id, parent)) satisfies typeof Bun.resolveSync;
|
||||
export const resolve = (async (id: string, parent: string) => import.meta.resolve!(id, parent)) satisfies typeof Bun.resolve;
|
||||
|
||||
//? Yes, this is faster than new Uint8Array(Buffer.allocUnsafe(size).buffer) by about 2.5x in Node.js
|
||||
export const allocUnsafe = ((size: number) => new Uint8Array(size)) satisfies typeof Bun.allocUnsafe;
|
||||
|
||||
export const generateHeapSnapshot = (async (): Promise<HeapSnapshot> => {
|
||||
process.emitWarning('The polyfill for Bun.generateHeapShot is asynchronous, unlike the original which is synchronous.', {
|
||||
type: 'BunPolyfillWarning',
|
||||
code: 'BUN_POLYFILLS_ASYNC_GENERATE_HEAP_SNAPSHOT',
|
||||
detail: 'This is due to v8.getHeapSnapshot() returning a stream in Node.js. This is not a bug, but a limitation of the polyfill.'
|
||||
});
|
||||
const raw = (await streamToBuffer(v8.getHeapSnapshot())).toString('utf8');
|
||||
const json = JSON.parse(raw) as V8HeapSnapshot;
|
||||
return {
|
||||
version: 2,
|
||||
type: 'Inspector',
|
||||
nodes: json.nodes,
|
||||
edges: json.edges,
|
||||
edgeTypes: json.snapshot.meta.edge_types.flat(),
|
||||
edgeNames: json.snapshot.meta.edge_fields.flat(),
|
||||
nodeClassNames: json.snapshot.meta.node_types.flat(),
|
||||
};
|
||||
// @ts-expect-error Refer to the above emitWarning call
|
||||
}) satisfies typeof Bun.generateHeapSnapshot;
|
||||
|
||||
//! This is a no-op in Node.js, as there is no way to shrink the V8 heap from JS as far as I know.
|
||||
export const shrink = (() => void 0) satisfies typeof Bun.shrink;
|
||||
|
||||
export const openInEditor = ((file: string, opts?: EditorOptions) => {
|
||||
const target = [{ file: path.resolve(process.cwd(), file), line: opts?.line, column: opts?.column }] as const;
|
||||
if (opts?.editor) openEditor(target, opts);
|
||||
else openEditor(target, { editor: process.env.TERM_PROGRAM ?? process.env.VISUAL ?? process.env.EDITOR ?? 'vscode' });
|
||||
}) satisfies typeof Bun.openInEditor;
|
||||
|
||||
export const serve = (() => { throw new NotImplementedError('Bun.serve', serve); }) satisfies typeof Bun.serve;
|
||||
|
||||
export const file = ((path: string | URL | Uint8Array | ArrayBufferLike | number, options?: BlobPropertyBag): BunFileBlob => {
|
||||
if (typeof path === 'object') throw new NotImplementedError('Bun.file with typed array', file);
|
||||
return new FileBlob(path, options);
|
||||
}) satisfies typeof Bun.file;
|
||||
|
||||
export const write = (async (dest: BunFileBlob | PathLike, input: string | Blob | TypedArray | ArrayBufferLike | BlobPart[] | Response | BunFileBlob): ReturnType<typeof Bun.write> => {
|
||||
if (!isFileBlob(dest)) {
|
||||
let fd: number;
|
||||
if (dest instanceof ArrayBuffer || dest instanceof SharedArrayBuffer) fd = fs.openSync(Buffer.from(dest), 'w');
|
||||
// bun-types thought it'd be funny to make their own URL definition which doesnt match with the correct URL definition...
|
||||
else if (typeof dest === 'string' || dest instanceof URL) fd = fs.openSync(dest as import('url').URL, 'w');
|
||||
else fd = fs.openSync(Buffer.from(dest.buffer), 'w');
|
||||
|
||||
if (input instanceof Response || input instanceof Blob) {
|
||||
const data = await input.text();
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.write(fd, data, (err, written) => err ? reject(err) : resolve(written));
|
||||
});
|
||||
}
|
||||
if (Array.isArray(input)) {
|
||||
const data = await new Blob(input).text();
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.write(fd, data, (err, written) => err ? reject(err) : resolve(written));
|
||||
});
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof input === 'string') return fs.write(fd, input, (err, written) => err ? reject(err) : resolve(written));
|
||||
if (input instanceof Uint8Array) return fs.write(fd, input, (err, written) => err ? reject(err) : resolve(written));
|
||||
if (input instanceof ArrayBuffer) return fs.write(fd, new Uint8Array(input), (err, written) => err ? reject(err) : resolve(written));
|
||||
if (input instanceof SharedArrayBuffer) return fs.write(fd, new Uint8Array(input), (err, written) => err ? reject(err) : resolve(written));
|
||||
return write(dest, String(input)); // if all else fails, it seems Bun tries to convert to string and write that.
|
||||
});
|
||||
} else {
|
||||
const writer = dest.writer();
|
||||
if (Array.isArray(input)) input = new Blob(input);
|
||||
if (input instanceof Blob || input instanceof Response) return writer.write(await input.arrayBuffer());
|
||||
if (input instanceof ArrayBuffer || input instanceof SharedArrayBuffer || ArrayBuffer.isView(input)) return writer.write(input);
|
||||
if (typeof input === 'string') return writer.write(input);
|
||||
else return write(dest, String(input)); // if all else fails, it seems Bun tries to convert to string and write that.
|
||||
}
|
||||
}) satisfies typeof Bun.write;
|
||||
|
||||
export const sha = SHA512_256.hash satisfies typeof Bun.sha;
|
||||
|
||||
export const nanoseconds = (() => Math.trunc(performance.now() * 1000000)) satisfies typeof Bun.nanoseconds;
|
||||
|
||||
//? This just prints out some debug stuff in console, and as the name implies no one should be using it.
|
||||
//? But, just in case someone does, we'll make it a no-op function so at least the program doesn't crash trying to run the function.
|
||||
export const DO_NOT_USE_OR_YOU_WILL_BE_FIRED_mimalloc_dump = (() => {
|
||||
console.warn('DO_NOT_USE_OR_YOU_WILL_BE_FIRED_mimalloc_dump called.');
|
||||
}) satisfies unknown; /* undocumented */
|
||||
|
||||
export const gzipSync = zlib.gzipSync satisfies typeof Bun.gzipSync;
|
||||
export const deflateSync = zlib.deflateSync satisfies typeof Bun.deflateSync;
|
||||
export const gunzipSync = zlib.gunzipSync satisfies typeof Bun.gunzipSync;
|
||||
export const inflateSync = zlib.inflateSync satisfies typeof Bun.inflateSync;
|
||||
|
||||
export const which = ((cmd: string, options) => {
|
||||
const opts: npm_which.Options = { all: false, nothrow: true };
|
||||
if (options?.PATH) opts.path = options.PATH;
|
||||
const result = npm_which.sync(cmd, opts) as string | null;
|
||||
if (!result || !options?.cwd) return result;
|
||||
if (path.normalize(result).includes(path.normalize(options.cwd))) return result;
|
||||
else return null;
|
||||
}) satisfies typeof Bun.which;
|
||||
|
||||
export const spawn = ((...args) => {
|
||||
let cmd: string;
|
||||
let argv: string[];
|
||||
let opts: SpawnOptions.OptionsObject;
|
||||
|
||||
if (args[0] instanceof Array) {
|
||||
cmd = args[0][0];
|
||||
argv = args[0].slice(1);
|
||||
opts = isOptions(args[1]) ? args[1] : {};
|
||||
} else {
|
||||
cmd = args[0].cmd[0];
|
||||
argv = args[0].cmd.slice(1);
|
||||
opts = args[0];
|
||||
Reflect.deleteProperty(opts, 'cmd');
|
||||
}
|
||||
|
||||
let stdio: StdioOptions = [];
|
||||
opts.stdio ??= [undefined, undefined, undefined];
|
||||
if (opts.stdin) opts.stdio[0] = opts.stdin;
|
||||
if (opts.stdout) opts.stdio[1] = opts.stdout;
|
||||
if (opts.stderr) opts.stdio[2] = opts.stderr;
|
||||
for (let i = 1; i < 3; i++) { // this intentionally skips stdin
|
||||
let std = opts.stdio[i];
|
||||
if (isArrayBufferView(std)) stdio[i] = streams.Readable.fromWeb(new Blob([std]).stream());
|
||||
else if (std instanceof Blob || isFileBlob(std)) stdio[i] = streams.Readable.fromWeb(std.stream());
|
||||
else if (std instanceof ReadableStream) stdio[i] = streams.Readable.fromWeb(std);
|
||||
else if (std instanceof Response || std instanceof Request) stdio[i] = streams.Readable.fromWeb(std.body!);
|
||||
else stdio[i] = std;
|
||||
}
|
||||
let stdinSrc: typeof opts.stdio[0] = null;
|
||||
if (opts.stdio[0] && typeof opts.stdio[0] !== 'string') {
|
||||
stdinSrc = opts.stdio[0];
|
||||
stdio[0] = 'pipe';
|
||||
}
|
||||
|
||||
const subp = chp.spawn(cmd, argv, {
|
||||
cwd: opts.cwd ?? process.cwd(),
|
||||
// why is this set to (string | number) on env values...
|
||||
env: { ...(opts.env as Record<string, string> ?? process.env) },
|
||||
stdio
|
||||
}) as unknown as Subprocess;
|
||||
const subpAsNode = subp as unknown as ChildProcess;
|
||||
const stdstreams = [subpAsNode.stdin, subpAsNode.stdout, subpAsNode.stderr] as const;
|
||||
if (subpAsNode.stdout) {
|
||||
const rstream = streams.Readable.toWeb(subpAsNode.stdout) as ReadableStream;
|
||||
Reflect.set(rstream, 'destroy', function (this: ReadableStream, err?: Error) {
|
||||
void (err ? this.cancel(String(err)) : this.cancel()).catch(() => { /* if it fails its already closed */ });
|
||||
return this;
|
||||
});
|
||||
(<Mutable<Subprocess>>subp).stdout = rstream;
|
||||
}
|
||||
if (subpAsNode.stderr) {
|
||||
const rstream = streams.Readable.toWeb(subpAsNode.stderr) as ReadableStream;
|
||||
Reflect.set(rstream, 'destroy', function (this: ReadableStream, err?: Error) {
|
||||
void (err ? this.cancel(String(err)) : this.cancel()).catch(() => { /* if it fails its already closed */ });
|
||||
return this;
|
||||
});
|
||||
(<Mutable<Subprocess>>subp).stderr = rstream;
|
||||
}
|
||||
let internalStdinStream: streams.Writable;
|
||||
if (subpAsNode.stdin) {
|
||||
const wstream = subpAsNode.stdin;
|
||||
Reflect.set(wstream, 'destroy', function (this: NodeJS.WritableStream, err?: Error) {
|
||||
void this.end(); /* if it fails its already closed */
|
||||
return this;
|
||||
});
|
||||
internalStdinStream = wstream;
|
||||
(<Mutable<Subprocess>>subp).stdin = new FileSink(wstream);
|
||||
|
||||
}
|
||||
Object.defineProperty(subp, 'readable', { get(this: Subprocess) { return this.stdout; } });
|
||||
Object.defineProperty(subp, 'exited', {
|
||||
value: new Promise((resolve, reject) => {
|
||||
subpAsNode.once('exit', (code) => {
|
||||
stdstreams[0]?.destroy();
|
||||
stdstreams[1]?.destroy();
|
||||
stdstreams[2]?.destroy();
|
||||
subp.kill();
|
||||
subp.unref();
|
||||
subpAsNode.disconnect?.();
|
||||
subpAsNode.removeAllListeners();
|
||||
resolve(code);
|
||||
});
|
||||
})
|
||||
});
|
||||
if (stdinSrc) subpAsNode.once('spawn', () => {
|
||||
const stdinWeb = streams.Writable.toWeb(internalStdinStream);
|
||||
if (isArrayBufferView(stdinSrc)) stdinSrc = new Blob([stdinSrc]);
|
||||
if (stdinSrc instanceof Blob) void stdinSrc.stream().pipeTo(stdinWeb);
|
||||
else if (stdinSrc instanceof Response || stdinSrc instanceof Request) void stdinSrc.body!.pipeTo(stdinWeb);
|
||||
else if (typeof stdinSrc === 'number') void fs.createReadStream('', { fd: stdinSrc }).pipe(internalStdinStream);
|
||||
else void stdinSrc;
|
||||
});
|
||||
// change the error stack to point to the spawn() call instead of internal Node.js callback stuff
|
||||
const here = new Error('§__PLACEHOLDER__§');
|
||||
Error.captureStackTrace(here, spawn);
|
||||
if (!subpAsNode.pid) return subpAsNode.once('error', (err: SystemError) => {
|
||||
err.message = (err.syscall ?? `spawn ${err.path ?? ''}`) + ' ' + (err.code ?? String(err.errno ?? ''));
|
||||
err.stack = here.stack!.replace('§__PLACEHOLDER__§', err.message);
|
||||
throw err;
|
||||
}) as unknown as Subprocess;
|
||||
return subp;
|
||||
}) satisfies typeof Bun.spawn;
|
||||
export const spawnSync = ((...args): SyncSubprocess => {
|
||||
let cmd: string;
|
||||
let argv: string[];
|
||||
let opts: SpawnOptions.OptionsObject;
|
||||
if (args[0] instanceof Array) {
|
||||
cmd = args[0][0];
|
||||
argv = args[0].slice(1);
|
||||
opts = isOptions(args[1]) ? args[1] : {};
|
||||
} else {
|
||||
cmd = args[0].cmd[0];
|
||||
argv = args[0].cmd.slice(1);
|
||||
opts = args[0];
|
||||
Reflect.deleteProperty(opts, 'cmd');
|
||||
}
|
||||
|
||||
let stdio: StdioOptions = [];
|
||||
opts.stdio ??= [undefined, undefined, undefined];
|
||||
if (opts.stdin) opts.stdio[0] = opts.stdin;
|
||||
if (opts.stdout) opts.stdio[1] = opts.stdout;
|
||||
if (opts.stderr) opts.stdio[2] = opts.stderr;
|
||||
for (let i = 1; i < 3; i++) { // this intentionally skips stdin
|
||||
let std = opts.stdio[i];
|
||||
if (isArrayBufferView(std)) stdio[i] = streams.Readable.fromWeb(new Blob([std]).stream());
|
||||
else if (std instanceof Blob || isFileBlob(std)) stdio[i] = streams.Readable.fromWeb(std.stream());
|
||||
else if (std instanceof ReadableStream) stdio[i] = streams.Readable.fromWeb(std);
|
||||
else if (std instanceof Response || std instanceof Request) stdio[i] = streams.Readable.fromWeb(std.body!);
|
||||
else stdio[i] = std;
|
||||
}
|
||||
let input: ArrayBufferView | string | undefined;
|
||||
if (opts.stdio[0] && typeof opts.stdio[0] !== 'string') {
|
||||
stdio[0] = null; // will be overridden by chp.spawnSync "input" option
|
||||
//! Due to the fully async nature of Blobs, Responses and Requests,
|
||||
//! we can't synchronously get the data out of them here in userland.
|
||||
if (opts.stdio[0] instanceof Blob) throw new NotImplementedError('Bun.spawnSync({ stdin: <Blob> })', spawnSync);
|
||||
else if (opts.stdio[0] instanceof Response || opts.stdio[0] instanceof Request) throw new NotImplementedError('Bun.spawnSync({ stdin: <Response|Request> })', spawnSync);
|
||||
else if (typeof opts.stdio[0] === 'number') input = fs.readFileSync(opts.stdio[0]);
|
||||
else input = opts.stdio[0] as ArrayBufferView;
|
||||
}
|
||||
|
||||
const subp = chp.spawnSync(cmd, argv, {
|
||||
cwd: opts.cwd ?? process.cwd(),
|
||||
env: { ...(opts.env as Record<string, string> ?? process.env) },
|
||||
stdio, input
|
||||
}) as unknown as SyncSubprocess;
|
||||
const subpAsNode = subp as unknown as SpawnSyncReturns<Buffer>;
|
||||
if (subpAsNode.error) throw subpAsNode.error;
|
||||
|
||||
subp.exitCode = subpAsNode.status ?? NaN; //! not sure what Bun would return here (child killed by signal)
|
||||
subp.success = subp.exitCode === 0;
|
||||
return subp;
|
||||
}) satisfies typeof Bun.spawnSync;
|
||||
|
||||
export const escapeHTML = ((input) => {
|
||||
const str = String(input);
|
||||
let out = '';
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const char = str[i];
|
||||
switch (char) {
|
||||
case '"': out += '"'; break;
|
||||
case "'": out += '''; break;
|
||||
case '&': out += '&'; break;
|
||||
case '<': out += '<'; break;
|
||||
case '>': out += '>'; break;
|
||||
default: out += char;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}) satisfies typeof Bun.escapeHTML;
|
||||
|
||||
export const readableStreamToArrayBuffer = ((stream: ReadableStream<ArrayBufferView | ArrayBufferLike>): ArrayBuffer | Promise<ArrayBuffer> => {
|
||||
return (async () => {
|
||||
const sink = new ArrayBufferSink();
|
||||
const reader = stream.getReader();
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
sink.write(value);
|
||||
}
|
||||
return sink.end() as ArrayBuffer;
|
||||
})();
|
||||
}) satisfies typeof Bun.readableStreamToArrayBuffer;
|
||||
|
||||
export const readableStreamToBytes = ((stream: ReadableStream<ArrayBufferView | ArrayBufferLike>): Uint8Array | Promise<Uint8Array> => {
|
||||
return (async () => {
|
||||
const sink = new ArrayBufferSink();
|
||||
sink.start({ asUint8Array: true });
|
||||
const reader = stream.getReader();
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
sink.write(value);
|
||||
}
|
||||
return sink.end() as Uint8Array;
|
||||
})();
|
||||
}) satisfies typeof Bun.readableStreamToBytes;
|
||||
|
||||
export const readableStreamToText = (async (stream: ReadableStream<ArrayBufferView | ArrayBuffer>) => {
|
||||
let result = '';
|
||||
const reader = stream.pipeThrough(new TextDecoderStream()).getReader(); ReadableStreamDefaultReader
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
//! for some reason "done" isnt being set to true so this is just infinitely looping at the moment... sigh
|
||||
if (done || !value || !value?.length) break;
|
||||
result += value;
|
||||
}
|
||||
return result;
|
||||
}) satisfies typeof Bun.readableStreamToText;
|
||||
export const readableStreamToBlob = (async (stream: ReadableStream<any>) => {
|
||||
const parts = await readableStreamToArray(stream);
|
||||
return new Blob(parts as BlobPart[]);
|
||||
}) satisfies typeof Bun.readableStreamToBlob;
|
||||
export const readableStreamToArray = (async <T = unknown>(stream: ReadableStream<T>) => {
|
||||
const array = new Array<T>();
|
||||
const reader = stream.getReader();
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done || !value || !(<any>value)?.length) break;
|
||||
array.push(value as unknown as T);
|
||||
}
|
||||
return array;
|
||||
}) satisfies typeof Bun.readableStreamToArray;
|
||||
export const readableStreamToJSON = (async <T = unknown>(stream: ReadableStream<Uint8Array>) => {
|
||||
const text = await readableStreamToText(stream);
|
||||
try {
|
||||
return JSON.parse(text) as T;
|
||||
} catch (err) {
|
||||
Error.captureStackTrace(err as Error, readableStreamToJSON);
|
||||
throw err;
|
||||
}
|
||||
}) satisfies typeof Bun.readableStreamToJSON;
|
||||
|
||||
export const concatArrayBuffers = ((buffers, maxLength = Infinity, asUint8Array = false) => {
|
||||
let size = 0;
|
||||
for (const chunk of buffers) size += chunk.byteLength;
|
||||
size = Math.min(size, maxLength);
|
||||
const buffer = new ArrayBuffer(size);
|
||||
const view = new Uint8Array(buffer);
|
||||
let offset = 0;
|
||||
for (const chunk of buffers) {
|
||||
if (offset > size) break;
|
||||
view.set(new Uint8Array(chunk instanceof ArrayBuffer || chunk instanceof SharedArrayBuffer ? chunk : chunk.buffer), offset);
|
||||
offset += chunk.byteLength;
|
||||
}
|
||||
if (asUint8Array) return view;
|
||||
return buffer;
|
||||
}) satisfies typeof Bun.concatArrayBuffers;
|
||||
|
||||
export const ArrayBufferSink = ArrayBufferSinkPolyfill satisfies typeof Bun.ArrayBufferSink;
|
||||
|
||||
export const pathToFileURL = pathToFileURLNode satisfies typeof Bun.pathToFileURL;
|
||||
export const fileURLToPath = fileURLToPathNode satisfies typeof Bun.fileURLToPath;
|
||||
|
||||
export const dns = dnsPolyfill satisfies typeof Bun.dns;
|
||||
|
||||
export const isMainThread = workers.isMainThread satisfies typeof Bun.isMainThread;
|
||||
|
||||
//! It may be possible to implement plugins with Node ESM loaders, but it would take some effort and have some caveats.
|
||||
//! For now, we'll simply make all calls to Bun.plugin no-op, such that manual implementation of an external ESM loader is possible,
|
||||
//! but without needing to strip out all Bun.plugin calls from the source code for running on Node.
|
||||
const dummyPluginBuilder: PluginBuilder = ({
|
||||
onLoad(constraints: PluginConstraints, callback: OnLoadCallback): void {
|
||||
return; // stubbed
|
||||
},
|
||||
onResolve(constraints: PluginConstraints, callback: OnResolveCallback): void {
|
||||
return; // stubbed
|
||||
},
|
||||
config: { plugins: [], entrypoints: [] },
|
||||
}) satisfies PluginBuilder;
|
||||
const bunPlugin = <T extends BunPlugin>(options: T) => options?.setup?.(dummyPluginBuilder) as ReturnType<T['setup']>;
|
||||
bunPlugin.clearAll = () => void 0;
|
||||
export const plugin = bunPlugin satisfies typeof Bun.plugin;
|
||||
/*void plugin({
|
||||
name: 'test',
|
||||
target: 'bun',
|
||||
setup(builder) {
|
||||
if (builder.target !== 'bun') return;
|
||||
builder.onResolve({ namespace: 'sample', filter: /.+/ }, args => {
|
||||
args.importer;
|
||||
if (args.path === 'foo') return { namespace: 'redirect', path: 'bar' };
|
||||
else return;
|
||||
});
|
||||
builder.onLoad({ namespace: 'sample', filter: /.+/ }, args => {
|
||||
args.path;
|
||||
return { loader: 'object', exports: { foo: 'bar' }, contents: 'void 0;' };
|
||||
});
|
||||
}
|
||||
});*/
|
||||
@@ -1,67 +0,0 @@
|
||||
type BunArrayBufferSink = InstanceType<typeof Bun.ArrayBufferSink>;
|
||||
|
||||
export class ArrayBufferSink implements BunArrayBufferSink {
|
||||
#started: boolean = true;
|
||||
#closed: boolean = false;
|
||||
#offset: number = 0;
|
||||
#stream: boolean = false;
|
||||
#asUint8: boolean = false;
|
||||
#buffer: Buffer = Buffer.allocUnsafe(8192);
|
||||
|
||||
get sinkId(): number { return 0; } //? undocumented, seems to always return 0
|
||||
|
||||
#ASSERT_NOT_CLOSED(caller: AnyFunction): void {
|
||||
if (!this.#closed) return;
|
||||
const err = new TypeError('Expected Sink');
|
||||
Error.captureStackTrace(err, caller);
|
||||
throw err;
|
||||
}
|
||||
|
||||
start({ asUint8Array = false, highWaterMark = 8192, stream = false }: Parameters<BunArrayBufferSink['start']>[0] = {}): void {
|
||||
this.#ASSERT_NOT_CLOSED(this.start);
|
||||
this.#started = true;
|
||||
this.#offset = 0;
|
||||
this.#stream = stream;
|
||||
this.#asUint8 = asUint8Array;
|
||||
if (highWaterMark !== this.#buffer.byteLength) this.#buffer = Buffer.allocUnsafe(highWaterMark);
|
||||
}
|
||||
|
||||
write(data: string | ArrayBufferView | SharedArrayBuffer | ArrayBuffer): number {
|
||||
this.#ASSERT_NOT_CLOSED(this.write);
|
||||
if (typeof data === 'string') data = new TextEncoder().encode(data);
|
||||
const writedata = (data instanceof ArrayBuffer || data instanceof SharedArrayBuffer) ? new Uint8Array(data) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
||||
// this is very bad API design to not throw an error here, but it's what Bun does
|
||||
if (!this.#started) return writedata.byteLength;
|
||||
|
||||
if (this.#offset + writedata.byteLength > this.#buffer.byteLength) {
|
||||
const newLength = Math.ceil((this.#offset + writedata.byteLength) / 1024) * 1024;
|
||||
const newBuffer = Buffer.allocUnsafe(newLength);
|
||||
newBuffer.set(this.#buffer);
|
||||
this.#buffer = newBuffer;
|
||||
}
|
||||
this.#buffer.set(writedata, this.#offset);
|
||||
this.#offset += writedata.byteLength;
|
||||
return writedata.byteLength;
|
||||
}
|
||||
|
||||
flush(): number | Uint8Array | ArrayBuffer {
|
||||
this.#ASSERT_NOT_CLOSED(this.flush);
|
||||
if (!this.#stream) return 0; //! brokenly seems to always return 0 and do nothing
|
||||
const flushed = new Uint8Array(this.#offset);
|
||||
flushed.set(this.#buffer.subarray(0, this.#offset)); // faster than Buffer.copy or Uint8Array.slice
|
||||
this.#offset = 0;
|
||||
return this.#asUint8 ? flushed : flushed.buffer as ArrayBuffer;
|
||||
}
|
||||
|
||||
end(): Uint8Array | ArrayBuffer {
|
||||
this.#ASSERT_NOT_CLOSED(this.end);
|
||||
const stream = this.#stream;
|
||||
this.#stream = true; // force flush() to return the data
|
||||
const buffer = this.flush() as Uint8Array | ArrayBuffer;
|
||||
this.#stream = stream;
|
||||
this.#started = false;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
close(): void { this.#closed = true; } //? undocumented
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import dns from 'node:dns';
|
||||
|
||||
const dnsObj: typeof Bun.dns = {
|
||||
async lookup(hostname, options) {
|
||||
const opts = { verbatim: true, all: true } as dns.LookupOptions;
|
||||
if (options?.family) {
|
||||
if (options.family === 'IPv4') opts.family = 4;
|
||||
else if (options.family === 'IPv6') opts.family = 6;
|
||||
else if (options.family === 'any') opts.family = 0;
|
||||
else opts.family = options.family;
|
||||
}
|
||||
if (options?.flags) opts.hints = options.flags;
|
||||
const records = ((await dns.promises.resolveAny(hostname))
|
||||
.filter(r => r.type === 'A' || r.type === 'AAAA') as (dns.AnyARecord | dns.AnyAaaaRecord)[])
|
||||
.map(r => ({ address: r.address, family: r.type === 'A' ? 4 as const : 6 as const, ttl: r.ttl }));
|
||||
return records;
|
||||
},
|
||||
// This has more properties but they're not documented on bun-types yet, oh well.
|
||||
};
|
||||
|
||||
export default dnsObj;
|
||||
@@ -1,195 +0,0 @@
|
||||
import fs from 'node:fs';
|
||||
import tty from 'node:tty';
|
||||
import streams from 'node:stream';
|
||||
import { ReadableStream as NodeWebReadableStream } from 'node:stream/web';
|
||||
import { FileSink } from './filesink.js';
|
||||
import { SystemError } from '../../utils/errors.js';
|
||||
import type { FileBlob as BunFileBlob, FileSink as BunFileSink } from 'bun';
|
||||
|
||||
type NodeJSStream = streams.Readable | streams.Writable;
|
||||
|
||||
function NodeJSReadableStreamToBlob(stream: NodeJS.ReadableStream | NodeJS.ReadWriteStream, iostream: boolean = false, type?: string): Promise<Blob> {
|
||||
if (stream.isPaused()) stream.resume();
|
||||
return new Promise((resolve, reject) => {
|
||||
const chunks: any[] = [];
|
||||
const dataHandler = (chunk: any) => { chunks.push(chunk); if (iostream) end(); };
|
||||
const end = () => {
|
||||
resolve(new Blob(chunks, type != null ? { type } : undefined));
|
||||
stream.off('data', dataHandler);
|
||||
stream.off('end', end);
|
||||
stream.pause();
|
||||
};
|
||||
stream.once('data', dataHandler).once('end', end);
|
||||
//.once('error', reject); Bun waits to error on actual operations on the stream, therefore so will we.
|
||||
});
|
||||
}
|
||||
|
||||
export const NodeJSStreamFileBlob = class FileBlob extends Blob {
|
||||
constructor(source: NodeJSStream, slice: [number?, number?] = [undefined, undefined], type = 'application/octet-stream') {
|
||||
super(undefined, { type });
|
||||
Reflect.deleteProperty(this, 'size');
|
||||
if (source === process.stdout || source === process.stdin || source === process.stderr) {
|
||||
this.#iostream = true;
|
||||
}
|
||||
this.#readable = source instanceof streams.Readable && !(source instanceof tty.WriteStream);
|
||||
this.#source = source;
|
||||
this.#slice = slice;
|
||||
this.#size = Infinity;
|
||||
}
|
||||
readonly #iostream: boolean = false;
|
||||
readonly #readable: boolean;
|
||||
readonly #source: NodeJSStream;
|
||||
readonly #slice: [number?, number?];
|
||||
#size: number;
|
||||
|
||||
slice(begin?: number, end?: number, contentType?: string): Blob;
|
||||
slice(begin?: number, contentType?: string): Blob;
|
||||
slice(contentType?: string): Blob;
|
||||
slice(beginOrType?: number | string, endOrType?: number | string, contentType: string = this.type): Blob {
|
||||
if (typeof beginOrType === 'string') return new FileBlob(this.#source, this.#slice, beginOrType);
|
||||
if (typeof endOrType === 'string') return new FileBlob(this.#source, [beginOrType, undefined], endOrType);
|
||||
return new FileBlob(this.#source, [beginOrType, endOrType], contentType);
|
||||
}
|
||||
|
||||
override stream(): ReadableStream<Uint8Array> {
|
||||
// This makes no sense but Bun does it so we will too
|
||||
if (!this.#readable) return new ReadableStream();
|
||||
return streams.Readable.toWeb(this.#source as streams.Readable);
|
||||
}
|
||||
|
||||
#blobStackFn: AnyFunction = this.#getBlob;
|
||||
|
||||
async #getBlob(): Promise<Blob> {
|
||||
if (!this.#readable) {
|
||||
const err = new SystemError(-1, 'read');
|
||||
Error.captureStackTrace(err, this.#blobStackFn);
|
||||
throw err;
|
||||
}
|
||||
const blob = (await NodeJSReadableStreamToBlob(this.#source as streams.Readable, this.#iostream)).slice(...this.#slice);
|
||||
this.#size = blob.size;
|
||||
return blob;
|
||||
}
|
||||
|
||||
override async text(): Promise<string> {
|
||||
if (this.#blobStackFn !== this.json) this.#blobStackFn = this.text;
|
||||
return (await this.#getBlob()).text();
|
||||
}
|
||||
override async arrayBuffer(): Promise<ArrayBuffer> {
|
||||
this.#blobStackFn = this.arrayBuffer;
|
||||
return (await this.#getBlob()).arrayBuffer();
|
||||
}
|
||||
override async json<TJSONReturnType = unknown>(): Promise<TJSONReturnType> {
|
||||
this.#blobStackFn = this.json;
|
||||
return JSON.parse(await this.text()) as Promise<TJSONReturnType>;
|
||||
}
|
||||
|
||||
override get size(): number { return this.#size; }
|
||||
override set size(_) { return; }
|
||||
};
|
||||
|
||||
export class FileBlob extends Blob implements BunFileBlob {
|
||||
constructor(fdOrPath: number | string, opts: BlobPropertyBag = {}) {
|
||||
opts.type ??= 'application/octet-stream'; // TODO: Get MIME type from file extension
|
||||
super(undefined, opts);
|
||||
Reflect.deleteProperty(this, 'size');
|
||||
if (Reflect.get(opts, '__data')) this.#data = Reflect.get(opts, '__data') as Blob;
|
||||
const slice = Reflect.get(opts, '__slice') as [number?, number?] | undefined;
|
||||
if (slice) {
|
||||
slice[0] &&= slice[0] | 0; // int cast
|
||||
slice[1] &&= slice[1] | 0; // int cast
|
||||
this.#slice = slice;
|
||||
slice[0] ??= 0;
|
||||
if (typeof slice[1] === 'undefined') {
|
||||
if (slice[0] < 0) this.#sliceSize = -slice[0];
|
||||
}
|
||||
else if (slice[0] < 0 && slice[1] < 0) this.#sliceSize = -(slice[0] - slice[1]);
|
||||
else if (slice[0] >= 0 && slice[1] >= 0) this.#sliceSize = slice[1] - slice[0];
|
||||
}
|
||||
if (typeof fdOrPath === 'string') try {
|
||||
this.#fd = fs.openSync(fdOrPath, 'r+');
|
||||
} catch (err) {
|
||||
this.#error = err as SystemError;
|
||||
}
|
||||
else {
|
||||
this.#fd = fdOrPath;
|
||||
this.#error = Reflect.get(opts, '__error') as SystemError | undefined;
|
||||
}
|
||||
if (!this.#error) {
|
||||
const rstream = fs.createReadStream('', { fd: this.#fd, start: this.#slice[0], end: this.#slice[1] });
|
||||
this.#readable = streams.Readable.toWeb(rstream);
|
||||
}
|
||||
}
|
||||
readonly #readable?: NodeWebReadableStream;
|
||||
readonly #error?: SystemError;
|
||||
readonly #slice: [number?, number?] = [];
|
||||
readonly #sliceSize: number = 0;
|
||||
readonly #fd: number = NaN;
|
||||
#data?: Blob;
|
||||
|
||||
#read() {
|
||||
if (this.#error) throw this.#error;
|
||||
const read = fs.readFileSync(this.#fd);
|
||||
this.#data = new Blob([read.subarray(...this.#slice)], { type: this.type });
|
||||
}
|
||||
|
||||
//! Bun 0.2 seems to return undefined for this, this might not be accurate or it's broken on Bun's side
|
||||
get readable(): ReadableStream<any> {
|
||||
if (this.#error) throw this.#error;
|
||||
return this.#readable! as ReadableStream;
|
||||
}
|
||||
|
||||
get lastModified(): number {
|
||||
if (this.#error) throw this.#error;
|
||||
return fs.fstatSync(this.#fd).mtimeMs;
|
||||
}
|
||||
|
||||
async exists(): Promise<boolean> {
|
||||
return !this.#error;
|
||||
}
|
||||
|
||||
writer(): BunFileSink {
|
||||
if (this.#error) throw this.#error;
|
||||
return new FileSink(this.#fd);
|
||||
}
|
||||
|
||||
// TODO: what's contentType?
|
||||
override slice(begin?: number | string, end?: number | string, contentType?: string): FileBlob {
|
||||
if (typeof begin === 'string') {
|
||||
contentType = begin;
|
||||
begin = undefined;
|
||||
}
|
||||
if (typeof end === 'string') {
|
||||
contentType = end;
|
||||
end = undefined;
|
||||
}
|
||||
return new FileBlob(this.#fd, {
|
||||
__error: this.#error,
|
||||
__slice: [begin, end],
|
||||
__data: this.#data?.slice(begin, end),
|
||||
} as BlobPropertyBag);
|
||||
}
|
||||
override arrayBuffer(): Promise<ArrayBuffer> {
|
||||
if (!this.#data) this.#read();
|
||||
return new Blob([this.#data ?? '']).arrayBuffer();
|
||||
}
|
||||
override text(): Promise<string> {
|
||||
if (!this.#data) this.#read();
|
||||
return new Blob([this.#data ?? '']).text();
|
||||
}
|
||||
override json(): Promise<any>;
|
||||
override json<TJSONReturnType = unknown>(): Promise<TJSONReturnType>;
|
||||
override json<TJSONReturnType = unknown>(): Promise<TJSONReturnType> | Promise<any> {
|
||||
if (!this.#data) this.#read();
|
||||
return new Blob([this.#data ?? '']).json();
|
||||
}
|
||||
override stream(): NodeJS.ReadableStream;
|
||||
override stream(): ReadableStream<Uint8Array>;
|
||||
override stream(): ReadableStream<Uint8Array> | NodeJS.ReadableStream {
|
||||
if (!this.#data) this.#read();
|
||||
return new Blob([this.#data ?? '']).stream();
|
||||
}
|
||||
|
||||
override get size(): number {
|
||||
return this.#data?.size ?? (this.#sliceSize || 0);
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
import fs from 'node:fs';
|
||||
import { SystemError } from '../../utils/errors.js';
|
||||
import type { FileSink as BunFileSink } from 'bun';
|
||||
|
||||
export class FileSink implements BunFileSink {
|
||||
constructor(fdOrPathOrStream: number | string | NodeJS.WritableStream) {
|
||||
if (typeof fdOrPathOrStream === 'string') try {
|
||||
this.#fd = fs.openSync(fdOrPathOrStream, 'a+');
|
||||
fs.ftruncateSync(this.#fd, 0);
|
||||
} catch (err) {
|
||||
throw err as SystemError;
|
||||
}
|
||||
else if (typeof fdOrPathOrStream === 'number') {
|
||||
this.#fd = fdOrPathOrStream; // hope this fd is writable
|
||||
fs.ftruncateSync(this.#fd, 0);
|
||||
}
|
||||
else {
|
||||
this.#stream = fdOrPathOrStream;
|
||||
}
|
||||
}
|
||||
#fd: number = NaN;
|
||||
#stream: NodeJS.WritableStream | undefined;
|
||||
#closed: boolean = false;
|
||||
#writtenSinceFlush: number = 0;
|
||||
#totalWritten: number = 0;
|
||||
|
||||
start(options?: { highWaterMark?: number | undefined; } | undefined): void {
|
||||
return; // TODO
|
||||
}
|
||||
|
||||
ref(): void {
|
||||
return; // TODO
|
||||
}
|
||||
|
||||
unref(): void {
|
||||
return; // TODO
|
||||
}
|
||||
|
||||
write(chunk: string | ArrayBufferView | SharedArrayBuffer | ArrayBuffer): number {
|
||||
if (this.#closed) {
|
||||
return typeof chunk === 'string' ? chunk.length : chunk.byteLength;
|
||||
}
|
||||
if (this.#stream) {
|
||||
let data;
|
||||
if (chunk instanceof ArrayBuffer || chunk instanceof SharedArrayBuffer) data = new Uint8Array(chunk);
|
||||
else if (!(chunk instanceof Uint8Array) && typeof chunk !== 'string') data = new Uint8Array(chunk.buffer);
|
||||
else data = chunk;
|
||||
this.#stream.write(data);
|
||||
const written = typeof data === 'string' ? data.length : data.byteLength;
|
||||
this.#totalWritten += written;
|
||||
return written;
|
||||
}
|
||||
if (typeof chunk === 'string') {
|
||||
fs.appendFileSync(this.#fd, chunk, 'utf8');
|
||||
this.#writtenSinceFlush += chunk.length;
|
||||
return chunk.length;
|
||||
}
|
||||
if (chunk instanceof ArrayBuffer || chunk instanceof SharedArrayBuffer) fs.appendFileSync(this.#fd, new Uint8Array(chunk));
|
||||
else fs.appendFileSync(this.#fd, new Uint8Array(chunk.buffer));
|
||||
this.#writtenSinceFlush += chunk.byteLength;
|
||||
return chunk.byteLength;
|
||||
}
|
||||
|
||||
//! flushing after writing to a closed FileSink segfaults in Bun but I don't see the need to implement that behavior
|
||||
flush(): number | Promise<number> {
|
||||
if (this.#closed) return 0;
|
||||
// no-op because this is a synchronous implementation
|
||||
const written = this.#writtenSinceFlush;
|
||||
this.#writtenSinceFlush = 0;
|
||||
return written;
|
||||
}
|
||||
|
||||
//! not sure what to do with this error
|
||||
end(error?: Error): number | Promise<number> {
|
||||
if (this.#closed) return this.#totalWritten;
|
||||
const flushed = this.flush();
|
||||
if (this.#stream) {
|
||||
this.#stream.end();
|
||||
this.#closed = true;
|
||||
return flushed;
|
||||
}
|
||||
this.#totalWritten = fs.fstatSync(this.#fd).size;
|
||||
fs.closeSync(this.#fd);
|
||||
this.#closed = true;
|
||||
return flushed;
|
||||
}
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
import type { CryptoHashInterface, DigestEncoding, Hash } from 'bun';
|
||||
import nodecrypto from 'node:crypto';
|
||||
import os from 'node:os';
|
||||
import md4, { Md4 } from 'js-md4';
|
||||
import { wyhash, adler32, crc32, cityhash32, cityhash64, xxhash32, xxhash64, xxhash3, murmur32v3, murmur64v2, murmur32v2 } from '../../../lib/zighash/index.mjs';
|
||||
|
||||
export const bunHash = ((data, seed = 0): bigint => wyhash(data, BigInt(seed))) as typeof Bun.hash;
|
||||
export const bunHashProto: Hash = {
|
||||
wyhash(data, seed = 0n) { return wyhash(data, seed); },
|
||||
adler32(data) { return adler32(data); },
|
||||
crc32(data) { return crc32(data); },
|
||||
cityHash32(data) { return cityhash32(data); },
|
||||
cityHash64(data, seed = 0n) { return cityhash64(data, seed); },
|
||||
xxHash32(data, seed = 0) { return xxhash32(data, seed); },
|
||||
xxHash64(data, seed = 0n) { return xxhash64(data, seed); },
|
||||
xxHash3(data, seed = 0n) { return xxhash3(data, seed); },
|
||||
murmur32v3(data, seed = 0) { return murmur32v3(data, seed); },
|
||||
murmur32v2(data, seed = 0) { return murmur32v2(data, seed); },
|
||||
murmur64v2(data, seed = 0n) { return murmur64v2(data, seed); },
|
||||
};
|
||||
|
||||
type HashImpl = {
|
||||
digest(): Buffer;
|
||||
digest(encoding: nodecrypto.BinaryToTextEncoding): string;
|
||||
update(data: nodecrypto.BinaryLike): HashImpl;
|
||||
update(data: string, inputEncoding: nodecrypto.Encoding): HashImpl;
|
||||
};
|
||||
abstract class BaseHash<T> implements CryptoHashInterface<T> {
|
||||
readonly #hash: HashImpl | null;
|
||||
constructor(algorithm: string | HashImpl) {
|
||||
if (typeof algorithm === 'string') this.#hash = nodecrypto.createHash(algorithm);
|
||||
// If no preset algorithm is given, expect the subclass to fully implement its own.
|
||||
else this.#hash = algorithm;
|
||||
}
|
||||
update(data: StringOrBuffer) {
|
||||
if (data instanceof ArrayBuffer || data instanceof SharedArrayBuffer) this.#hash!.update(new Uint8Array(data));
|
||||
else this.#hash!.update(data);
|
||||
return this as unknown as T; // is there any good way to do this without asserting?
|
||||
}
|
||||
digest(encoding: DigestEncoding): string;
|
||||
digest(hashInto?: TypedArray): TypedArray;
|
||||
digest(encodingOrHashInto?: DigestEncoding | TypedArray): string | TypedArray {
|
||||
if (typeof encodingOrHashInto === 'string') {
|
||||
const encoded = this.#hash!.digest(encodingOrHashInto);
|
||||
// you'd think node would throw an error if the encoding is invalid, but nope!
|
||||
// instead it silently returns as if you passed no encoding and gives a Buffer...
|
||||
if (Buffer.isBuffer(encoded)) throw new TypeError(`Unknown encoding: "${encodingOrHashInto}"`);
|
||||
else return encoded;
|
||||
}
|
||||
const digested = this.#hash!.digest();
|
||||
if (encodingOrHashInto === undefined) return new Uint8Array(digested.buffer, digested.byteOffset, digested.byteLength);
|
||||
if (encodingOrHashInto.byteLength < this.byteLength) throw new TypeError(`TypedArray must be at least ${this.byteLength} bytes`);
|
||||
if (encodingOrHashInto instanceof BigInt64Array || encodingOrHashInto instanceof BigUint64Array) {
|
||||
// avoid checking endianness for every loop iteration
|
||||
const endianAwareInsert = os.endianness() === 'LE'
|
||||
? (arr: string[], j: number, num: string) => arr[7 - j] = num
|
||||
: (arr: string[], j: number, num: string) => arr[j] = num;
|
||||
|
||||
for (let i = 0; i < digested.byteLength; i += 8) {
|
||||
const bigintStrArr = ['', '', '', '', '', '', '', ''];
|
||||
for (let j = 0; j < 8; j++) {
|
||||
const byte = digested[i + j];
|
||||
if (byte === undefined) break;
|
||||
endianAwareInsert(bigintStrArr, j, byte.toString(16).padStart(2, '0'));
|
||||
}
|
||||
encodingOrHashInto[i / 8] = BigInt(`0x${bigintStrArr.join('')}`);
|
||||
}
|
||||
} else {
|
||||
const HashIntoTypedArray = encodingOrHashInto.constructor as TypedArrayConstructor;
|
||||
// this will work as long as all hash classes have a byteLength that is a multiple of 4 bytes
|
||||
encodingOrHashInto.set(new HashIntoTypedArray(digested.buffer, digested.byteOffset, digested.byteLength / HashIntoTypedArray.BYTES_PER_ELEMENT));
|
||||
}
|
||||
return encodingOrHashInto;
|
||||
}
|
||||
static hash(data: StringOrBuffer, encoding?: DigestEncoding): string;
|
||||
static hash(data: StringOrBuffer, hashInto?: TypedArray): TypedArray;
|
||||
static hash(data: StringOrBuffer, encodingOrHashInto?: DigestEncoding | TypedArray): string | TypedArray { return '' };
|
||||
static readonly byteLength: number;
|
||||
abstract readonly byteLength: number;
|
||||
}
|
||||
|
||||
export class SHA1 extends BaseHash<SHA1> {
|
||||
constructor() { super('sha1'); }
|
||||
static override readonly byteLength = 20;
|
||||
override readonly byteLength = 20;
|
||||
static override hash(data: StringOrBuffer, encoding?: DigestEncoding): string;
|
||||
static override hash(data: StringOrBuffer, hashInto?: TypedArray): TypedArray;
|
||||
static override hash(data: StringOrBuffer, encodingOrHashInto?: DigestEncoding | TypedArray): string | TypedArray {
|
||||
const instance = new this(); instance.update(data);
|
||||
return instance.digest(encodingOrHashInto as DigestEncoding & TypedArray);
|
||||
}
|
||||
}
|
||||
export class MD4 extends BaseHash<MD4> {
|
||||
constructor() { //! Not supported by nodecrypto
|
||||
const hash = md4.create() as unknown as Omit<Md4, 'toString'> & { _update: Md4['update'] };
|
||||
function digest(): Buffer;
|
||||
function digest(encoding: nodecrypto.BinaryToTextEncoding): string;
|
||||
function digest(encoding?: nodecrypto.BinaryToTextEncoding) {
|
||||
const buf = Buffer.from(hash.arrayBuffer());
|
||||
if (encoding) return buf.toString(encoding);
|
||||
else return buf;
|
||||
}
|
||||
function update(data: nodecrypto.BinaryLike) {
|
||||
if (typeof data === 'string') hash._update(data);
|
||||
else if (data instanceof ArrayBuffer || data instanceof SharedArrayBuffer) hash._update(new Uint8Array(data));
|
||||
else hash._update(new Uint8Array(data.buffer));
|
||||
return hash as unknown as MD4HashImpl;
|
||||
}
|
||||
type MD4HashImpl = Omit<Md4, 'toString'> & { digest: typeof digest, update: typeof update };
|
||||
// @ts-expect-error patches to reuse the BaseHash methods
|
||||
hash.digest = digest; hash._update = hash.update; hash.update = update;
|
||||
super(hash as unknown as MD4HashImpl);
|
||||
}
|
||||
static override readonly byteLength = 16;
|
||||
override readonly byteLength = 16;
|
||||
static override hash(data: StringOrBuffer, encoding?: DigestEncoding): string;
|
||||
static override hash(data: StringOrBuffer, hashInto?: TypedArray): TypedArray;
|
||||
static override hash(data: StringOrBuffer, encodingOrHashInto?: DigestEncoding | TypedArray): string | TypedArray {
|
||||
const instance = new this(); instance.update(data);
|
||||
return instance.digest(encodingOrHashInto as DigestEncoding & TypedArray);
|
||||
}
|
||||
}
|
||||
export class MD5 extends BaseHash<MD5> {
|
||||
constructor() { super('md5'); }
|
||||
static override readonly byteLength = 16;
|
||||
override readonly byteLength = 16;
|
||||
static override hash(data: StringOrBuffer, encoding?: DigestEncoding): string;
|
||||
static override hash(data: StringOrBuffer, hashInto?: TypedArray): TypedArray;
|
||||
static override hash(data: StringOrBuffer, encodingOrHashInto?: DigestEncoding | TypedArray): string | TypedArray {
|
||||
const instance = new this(); instance.update(data);
|
||||
return instance.digest(encodingOrHashInto as DigestEncoding & TypedArray);
|
||||
}
|
||||
}
|
||||
export class SHA224 extends BaseHash<SHA224> {
|
||||
constructor() { super('sha224'); }
|
||||
static override readonly byteLength = 28;
|
||||
override readonly byteLength = 28;
|
||||
static override hash(data: StringOrBuffer, encoding?: DigestEncoding): string;
|
||||
static override hash(data: StringOrBuffer, hashInto?: TypedArray): TypedArray;
|
||||
static override hash(data: StringOrBuffer, encodingOrHashInto?: DigestEncoding | TypedArray): string | TypedArray {
|
||||
const instance = new this(); instance.update(data);
|
||||
return instance.digest(encodingOrHashInto as DigestEncoding & TypedArray);
|
||||
}
|
||||
}
|
||||
export class SHA512 extends BaseHash<SHA512> {
|
||||
constructor() { super('sha512'); }
|
||||
static override readonly byteLength = 64;
|
||||
override readonly byteLength = 64;
|
||||
static override hash(data: StringOrBuffer, encoding?: DigestEncoding): string;
|
||||
static override hash(data: StringOrBuffer, hashInto?: TypedArray): TypedArray;
|
||||
static override hash(data: StringOrBuffer, encodingOrHashInto?: DigestEncoding | TypedArray): string | TypedArray {
|
||||
const instance = new this(); instance.update(data);
|
||||
return instance.digest(encodingOrHashInto as DigestEncoding & TypedArray);
|
||||
}
|
||||
}
|
||||
export class SHA384 extends BaseHash<SHA384> {
|
||||
constructor() { super('sha384'); }
|
||||
static override readonly byteLength = 48;
|
||||
override readonly byteLength = 48;
|
||||
static override hash(data: StringOrBuffer, encoding?: DigestEncoding): string;
|
||||
static override hash(data: StringOrBuffer, hashInto?: TypedArray): TypedArray;
|
||||
static override hash(data: StringOrBuffer, encodingOrHashInto?: DigestEncoding | TypedArray): string | TypedArray {
|
||||
const instance = new this(); instance.update(data);
|
||||
return instance.digest(encodingOrHashInto as DigestEncoding & TypedArray);
|
||||
}
|
||||
}
|
||||
export class SHA256 extends BaseHash<SHA256> {
|
||||
constructor() { super('sha256'); }
|
||||
static override readonly byteLength = 32;
|
||||
override readonly byteLength = 32;
|
||||
static override hash(data: StringOrBuffer, encoding?: DigestEncoding): string;
|
||||
static override hash(data: StringOrBuffer, hashInto?: TypedArray): TypedArray;
|
||||
static override hash(data: StringOrBuffer, encodingOrHashInto?: DigestEncoding | TypedArray): string | TypedArray {
|
||||
const instance = new this(); instance.update(data);
|
||||
return instance.digest(encodingOrHashInto as DigestEncoding & TypedArray);
|
||||
}
|
||||
}
|
||||
export class SHA512_256 extends BaseHash<SHA512_256> {
|
||||
constructor() { super('sha512-256'); }
|
||||
static override readonly byteLength = 32;
|
||||
override readonly byteLength = 32;
|
||||
static override hash(data: StringOrBuffer, encoding?: DigestEncoding): string;
|
||||
static override hash(data: StringOrBuffer, hashInto?: TypedArray): TypedArray;
|
||||
static override hash(data: StringOrBuffer, encodingOrHashInto?: DigestEncoding | TypedArray): string | TypedArray {
|
||||
const instance = new this(); instance.update(data);
|
||||
return instance.digest(encodingOrHashInto as DigestEncoding & TypedArray);
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
import type { JavaScriptLoader, TranspilerOptions, Transpiler as BunTranspiler, Import } from 'bun';
|
||||
import { transformSync, scan, init } from 'bun-wasm';
|
||||
import { Message } from 'bun-wasm/schema';
|
||||
import $ from 'chalk';
|
||||
|
||||
await init();
|
||||
|
||||
enum InternalImportKind {
|
||||
'entry-point-run' = 1, // entry_point_run
|
||||
'entry-point-build' = 2, // entry_point_build
|
||||
'import-statement' = 3, // stmt
|
||||
'require-call' = 4, // require
|
||||
'dynamic-import' = 5, // dynamic
|
||||
'require-resolve' = 6, // require_resolve
|
||||
'import-rule' = 7, // at
|
||||
'url-token' = 8, // url
|
||||
'internal' = 9, // internal
|
||||
}
|
||||
|
||||
export type ScanImportsEntry = {
|
||||
kind: 'import-statement' | 'dynamic-import';
|
||||
path: string;
|
||||
};
|
||||
|
||||
export default class Transpiler implements BunTranspiler {
|
||||
constructor(options?: TranspilerOptions) {
|
||||
this.#options = options ?? {};
|
||||
this.#rootFile = 'input.tsx'; // + (this.#options.loader ?? 'tsx');
|
||||
//? ^ NOTE: with current bun-wasm builds, the loader option is ignored and hardcoded to tsx
|
||||
}
|
||||
#options: TranspilerOptions;
|
||||
#rootFile: string;
|
||||
#decoder?: TextDecoder;
|
||||
#internallyCalled: boolean = false;
|
||||
|
||||
async transform(code: StringOrBuffer, loader: JavaScriptLoader): Promise<string> {
|
||||
this.#internallyCalled = true;
|
||||
return this.transformSync(code, loader);
|
||||
}
|
||||
|
||||
transformSync(code: StringOrBuffer, ctx: object): string;
|
||||
transformSync(code: StringOrBuffer, loader: JavaScriptLoader, ctx: object): string;
|
||||
transformSync(code: StringOrBuffer, loader?: JavaScriptLoader | undefined): string;
|
||||
transformSync(code: StringOrBuffer, loader?: JavaScriptLoader | object, ctx: object = {}): string {
|
||||
if (!code) return ''; // wasm dies with empty string input
|
||||
if (typeof code !== 'string' && !(code instanceof Uint8Array)) throw new TypeError('code must be a string or Uint8Array');
|
||||
if (typeof loader !== 'string') loader = this.#options.loader;
|
||||
const result = transformSync(code, this.#rootFile, loader);
|
||||
// status 1 = success, status 2 = error
|
||||
if (result.status === 2) throw formatBuildErrors(result.errors, this.#internallyCalled ? this.transform : this.transformSync);
|
||||
this.#internallyCalled = false;
|
||||
this.#decoder ??= new TextDecoder();
|
||||
return this.#decoder.decode(result.files[0].data);
|
||||
}
|
||||
|
||||
scan(code: StringOrBuffer): { exports: string[]; imports: Import[]; } {
|
||||
if (!code) return { exports: [], imports: [] }; // wasm dies with empty string input
|
||||
if (typeof code !== 'string' && !(code instanceof Uint8Array)) throw new TypeError('code must be a string or Uint8Array');
|
||||
|
||||
const result = scan(code, this.#rootFile, this.#options.loader);
|
||||
if (result.errors.length) throw formatBuildErrors(result.errors, this.#internallyCalled ? this.scanImports : this.scan);
|
||||
this.#internallyCalled = false;
|
||||
|
||||
result.imports.forEach(imp => (imp.kind as unknown) = InternalImportKind[imp.kind]);
|
||||
return {
|
||||
exports: result.exports,
|
||||
imports: result.imports as unknown as Import[],
|
||||
};
|
||||
}
|
||||
|
||||
scanImports(code: StringOrBuffer): ScanImportsEntry[] {
|
||||
this.#internallyCalled = true;
|
||||
return this.scan(code).imports.filter(imp => imp.kind === 'import-statement' || imp.kind === 'dynamic-import') as ScanImportsEntry[];
|
||||
}
|
||||
}
|
||||
|
||||
function formatBuildErrors(buildErrors: Message[], caller: Transpiler[keyof Transpiler]): AggregateError {
|
||||
const formatted = buildErrors.map(err => {
|
||||
const loc = err.data.location;
|
||||
const str = `${$.redBright('error')}${$.gray(':')} ${$.bold(err.data.text)}\n` +
|
||||
(loc
|
||||
? `${highlightErrorChar(loc.line_text, loc.offset)}\n` +
|
||||
$.redBright.bold('^'.padStart(loc.column)) + '\n' +
|
||||
`${$.bold(loc.file)}${$.gray(':')}${$.yellowBright(loc.line)}${$.gray(':')}${$.yellowBright(loc.column)} ${$.gray(loc.offset)}`
|
||||
: ''
|
||||
);
|
||||
return { __proto__: Error.prototype, stack: str };
|
||||
});
|
||||
const aggregate = new AggregateError(formatted, `Input code has ${formatted.length} error${formatted.length === 1 ? '' : 's'}`);
|
||||
Error.captureStackTrace(aggregate, caller);
|
||||
aggregate.name = 'BuildError';
|
||||
return aggregate;
|
||||
}
|
||||
|
||||
function highlightErrorChar(str: string, at: number): string {
|
||||
return str.slice(0, at) + $.red(str[at]) + str.slice(at + 1);
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
import type jsc from 'bun:jsc';
|
||||
import v8 from 'node:v8';
|
||||
//import { setRandomSeed, getRandomSeed } from './mathrandom.js';
|
||||
import { NotImplementedError, getCallSites } from '../utils/errors.js';
|
||||
import { gc } from './bun.js';
|
||||
|
||||
const STUB = () => void 0;
|
||||
|
||||
function jscSerialize(value: any, options?: { binaryType: 'nodebuffer'; }): Buffer;
|
||||
function jscSerialize(value: any, options?: { binaryType?: 'arraybuffer'; }): SharedArrayBuffer;
|
||||
function jscSerialize(value: any, options?: { binaryType?: string }): Buffer | SharedArrayBuffer {
|
||||
const serialized = v8.serialize(value);
|
||||
if (options?.binaryType === 'nodebuffer') return serialized;
|
||||
else return new SharedArrayBuffer(serialized.byteLength);
|
||||
}
|
||||
// TODO: Investigate ways of making these the actual JSC serialization format (probably Bun WASM)
|
||||
// TODO: whilst this works for common use-cases like Node <-> Node it still does not make it
|
||||
// TODO: possible for Node <-> Bun transfers of this kind of data, which might be interesting to have.
|
||||
export const serialize = jscSerialize satisfies typeof jsc.serialize;
|
||||
export const deserialize = (value => {
|
||||
if (value instanceof ArrayBuffer || value instanceof SharedArrayBuffer) return v8.deserialize(Buffer.from(value));
|
||||
else return v8.deserialize(value);
|
||||
}) satisfies typeof jsc.deserialize;
|
||||
|
||||
export const setTimeZone = ((timeZone: string) => {
|
||||
const resolvedTZ = Intl.DateTimeFormat(undefined, { timeZone }).resolvedOptions().timeZone;
|
||||
return process.env.TZ = resolvedTZ;
|
||||
}) satisfies typeof jsc.setTimeZone;
|
||||
|
||||
export const callerSourceOrigin = (() => {
|
||||
const callsites: NodeJS.CallSite[] = getCallSites(2);
|
||||
// This may be inaccurate with async code. Needs more testing.
|
||||
let lastSeenURL = '';
|
||||
for (const callsite of callsites) {
|
||||
const sourceURL = callsite.getScriptNameOrSourceURL();
|
||||
if (sourceURL.startsWith('file://')) lastSeenURL = sourceURL;
|
||||
}
|
||||
return lastSeenURL;
|
||||
}) satisfies typeof jsc.callerSourceOrigin;
|
||||
|
||||
// TODO: Like with jsc.serialize/deserialize, these may be possible with Bun WASM.
|
||||
export const jscDescribe = (() => { throw new NotImplementedError('jsc.jscDescribe', STUB); }) satisfies typeof jsc.jscDescribe;
|
||||
export const jscDescribeArray = (() => { throw new NotImplementedError('jsc.jscDescribeArray', STUB); }) satisfies typeof jsc.jscDescribeArray;
|
||||
// These are no longer documented but still exist.
|
||||
export const describe = jscDescribe;
|
||||
export const describeArray = jscDescribeArray;
|
||||
|
||||
// Node.js only provides a singular non-configurable global GC function, so we have to make do with that.
|
||||
export const edenGC = gc satisfies typeof jsc.edenGC;
|
||||
export const fullGC = gc satisfies typeof jsc.fullGC;
|
||||
export const gcAndSweep = gc satisfies typeof jsc.gcAndSweep;
|
||||
|
||||
export const drainMicrotasks = STUB satisfies typeof jsc.drainMicrotasks; // no-op
|
||||
export const releaseWeakRefs = STUB satisfies typeof jsc.releaseWeakRefs; // no-op
|
||||
export const startSamplingProfiler = STUB satisfies typeof jsc.startSamplingProfiler; // no-op
|
||||
//! likely broken but needs more testing
|
||||
export const startRemoteDebugger = STUB satisfies typeof jsc.startRemoteDebugger; // no-op
|
||||
|
||||
//! this is a really poor polyfill but it's better than nothing
|
||||
export const getProtectedObjects = (() => { return [globalThis]; }) satisfies typeof jsc.getProtectedObjects;
|
||||
|
||||
export const getRandomSeed = 0; // TODO
|
||||
export const setRandomSeed = 0; // TODO
|
||||
|
||||
export const heapSize = (() => { return v8.getHeapStatistics().used_heap_size; }) satisfies typeof jsc.heapSize;
|
||||
export const heapStats = (() => {
|
||||
const stats = v8.getHeapStatistics();
|
||||
return {
|
||||
heapSize: stats.used_heap_size,
|
||||
heapCapacity: stats.total_available_size,
|
||||
extraMemorySize: stats.external_memory ?? 0,
|
||||
objectCount: 1, // TODO: how to get this in node?
|
||||
protectedObjectCount: getProtectedObjects().length,
|
||||
globalObjectCount: 2, // TODO: this one is probably fine hardcoded but is there a way to get this in node?
|
||||
protectedGlobalObjectCount: 1, // TODO: ^
|
||||
objectTypeCounts: {}, //! can't really throw an error here, so just return an empty object (TODO: how to get this in node?)
|
||||
protectedObjectTypeCounts: {} //! can't really throw an error here, so just return an empty object (TODO: how to get this in node?)
|
||||
};
|
||||
}) satisfies typeof jsc.heapStats;
|
||||
|
||||
//! doubtful anyone relies on the return of this for anything besides debugging
|
||||
export const isRope = (() => false) satisfies typeof jsc.isRope;
|
||||
|
||||
export const memoryUsage = (() => {
|
||||
const stats = v8.getHeapStatistics();
|
||||
const resUse = process.resourceUsage();
|
||||
return {
|
||||
current: stats.malloced_memory,
|
||||
peak: stats.peak_malloced_memory,
|
||||
currentCommit: stats.malloced_memory,
|
||||
peakCommit: stats.malloced_memory,
|
||||
pageFaults: resUse.minorPageFault + resUse.majorPageFault
|
||||
};
|
||||
}) satisfies typeof jsc.memoryUsage;
|
||||
|
||||
//! these are likely broken, seemingly always returning undefined which does not match the documented return types
|
||||
export const noFTL = (() => { return void 0 as unknown as Function; }) satisfies typeof jsc.noFTL;
|
||||
export const noOSRExitFuzzing = (() => { return void 0 as unknown as Function; }) satisfies typeof jsc.noOSRExitFuzzing;
|
||||
//! likely broken, seems to always returns zero
|
||||
export const totalCompileTime = (() => 0) satisfies typeof jsc.totalCompileTime;
|
||||
//! likely broken, seem to always returns 0 if any arguments are passed, undefined otherwise
|
||||
export const numberOfDFGCompiles = ((...args) => args.length ? 0 : void 0 as unknown as number) satisfies typeof jsc.numberOfDFGCompiles;
|
||||
export const reoptimizationRetryCount = ((...args) => args.length ? 0 : void 0 as unknown as number) satisfies typeof jsc.reoptimizationRetryCount;
|
||||
|
||||
//! The following are very likely impossible to ever polyfill.
|
||||
export const profile = (() => {
|
||||
throw new NotImplementedError('jsc.profile is not polyfillable', STUB, true);
|
||||
}) satisfies typeof jsc.profile;
|
||||
export const optimizeNextInvocation = (() => {
|
||||
throw new NotImplementedError('jsc.optimizeNextInvocation is not polyfillable', STUB, true);
|
||||
}) satisfies typeof jsc.optimizeNextInvocation;
|
||||
@@ -1,30 +0,0 @@
|
||||
import bun from './index.js';
|
||||
import * as jsc from './modules/jsc.js';
|
||||
|
||||
// This file serves two purposes:
|
||||
// 1. It is the entry point for using the Bun global in the REPL. (--import this file)
|
||||
// 2. It makes TypeScript check the full structural compatibility of the Bun global vs the polyfills object,
|
||||
// which allows for the type assertion below to be used as a TODO list index.
|
||||
|
||||
globalThis.Bun = bun as typeof bun & {
|
||||
// TODO: Missing polyfills
|
||||
readableStreamToFormData: typeof import('bun').readableStreamToFormData;
|
||||
deepEquals: typeof import('bun').deepEquals;
|
||||
deepMatch: typeof import('bun').deepMatch;
|
||||
build: typeof import('bun').build;
|
||||
mmap: typeof import('bun').mmap;
|
||||
connect: typeof import('bun').connect;
|
||||
listen: typeof import('bun').listen;
|
||||
password: typeof import('bun').password;
|
||||
CryptoHashInterface: typeof import('bun').CryptoHashInterface;
|
||||
CryptoHasher: typeof import('bun').CryptoHasher;
|
||||
FileSystemRouter: typeof import('bun').FileSystemRouter;
|
||||
|
||||
//? Polyfilled but with broken types (See each one in ./src/modules/bun.ts for details)
|
||||
generateHeapSnapshot: typeof import('bun').generateHeapSnapshot;
|
||||
stdout: typeof import('bun').stdout;
|
||||
stderr: typeof import('bun').stderr;
|
||||
stdin: typeof import('bun').stdin;
|
||||
};
|
||||
|
||||
Reflect.set(globalThis, 'jsc', jsc);
|
||||
13
packages/bun-polyfills/src/types/helpers.d.ts
vendored
13
packages/bun-polyfills/src/types/helpers.d.ts
vendored
@@ -1,13 +0,0 @@
|
||||
type AnyFunction = (...args: any[]) => any;
|
||||
type AnyClass = new (...args: any[]) => any;
|
||||
type AnyCallable = AnyFunction | AnyClass;
|
||||
|
||||
type MapKeysType<T extends Map<unknown, unknown>> = T extends Map<infer K, infer V> ? K : never;
|
||||
type MapValuesType<T extends Map<unknown, unknown>> = T extends Map<infer K, infer V> ? V : never;
|
||||
|
||||
type Mutable<T> = { -readonly [K in keyof T]: T[K] };
|
||||
|
||||
/** Excluding the BigInt typed arrays */
|
||||
type TypedArrayConstructor =
|
||||
| typeof Uint8Array | typeof Uint16Array | typeof Uint32Array | typeof Uint8ClampedArray
|
||||
| typeof Int8Array | typeof Int16Array | typeof Int32Array | typeof Float32Array | typeof Float64Array;
|
||||
72
packages/bun-polyfills/src/types/md4.d.ts
vendored
72
packages/bun-polyfills/src/types/md4.d.ts
vendored
@@ -1,72 +0,0 @@
|
||||
declare module 'js-md4' {
|
||||
export type MD4Input = string | ArrayBuffer | Uint8Array | number[];
|
||||
|
||||
interface md4 {
|
||||
/**
|
||||
* # Broken, will throw an error.
|
||||
* @deprecated Use {@link md4.hex} instead.
|
||||
*/
|
||||
(input: MD4Input): never;
|
||||
/** Creates an `Md4` hasher instance. */
|
||||
create(): Md4;
|
||||
/** Shortcut for `md4.create().update(...)` */
|
||||
update(message: MD4Input): Md4;
|
||||
/** Hash `message` into a hex string. */
|
||||
hex(message: MD4Input): string;
|
||||
/** Hash `message` into an Array. */
|
||||
array(message: MD4Input): number[];
|
||||
/** Identical to {@link md4.array}. */
|
||||
digest(message: MD4Input): number[];
|
||||
/**
|
||||
* Identical to {@link md4.arrayBuffer}.
|
||||
* @deprecated Use {@link md4.arrayBuffer} instead.
|
||||
*/
|
||||
buffer(message: MD4Input): ArrayBuffer;
|
||||
/** Hash `message` into an ArrayBuffer. */
|
||||
arrayBuffer(message: MD4Input): ArrayBuffer;
|
||||
}
|
||||
|
||||
export type Md4 = Md4;
|
||||
declare class Md4 {
|
||||
private constructor();
|
||||
|
||||
private toString(): string;
|
||||
private finalize(): void;
|
||||
private hash(): void;
|
||||
/**
|
||||
* Append `message` to the internal hash source data.
|
||||
* @returns A reference to `this` for chaining, or nothing if the instance has been finalized.
|
||||
*/
|
||||
update(message: MD4Input): this | void;
|
||||
/** Hash into a hex string. Finalizes the hash. */
|
||||
hex(): string;
|
||||
/** Hash into an Array. Finalizes the hash. */
|
||||
array(): number[];
|
||||
/** Identical to {@link Md4.array}. */
|
||||
digest(): number[];
|
||||
/**
|
||||
* Identical to {@link Md4.arrayBuffer}.
|
||||
* @deprecated Use {@link Md4.arrayBuffer} instead.
|
||||
*/
|
||||
buffer(): ArrayBuffer;
|
||||
/** Hash into an ArrayBuffer. Finalizes the hash. */
|
||||
arrayBuffer(): ArrayBuffer;
|
||||
|
||||
private buffer8: Uint8Array;
|
||||
private blocks: Uint32Array;
|
||||
private bytes: number;
|
||||
private start: number;
|
||||
private h3: number;
|
||||
private h2: number;
|
||||
private h1: number;
|
||||
private h0: number;
|
||||
readonly hashed: boolean;
|
||||
/** If true, `update()` operations will silently fail. */
|
||||
readonly finalized: boolean;
|
||||
readonly first: boolean;
|
||||
private lastByteIndex?: number;
|
||||
}
|
||||
|
||||
const md4: md4;
|
||||
export default md4;
|
||||
}
|
||||
30
packages/bun-polyfills/src/types/sync.d.ts
vendored
30
packages/bun-polyfills/src/types/sync.d.ts
vendored
@@ -1,30 +0,0 @@
|
||||
// This file explicitly redefines global types used in order to enforce the correct types,
|
||||
// regardless of the arbitrary order in which TSC/TSServer decide to load the type libraries in.
|
||||
// Annoyingly, even this file can sometimes break, so if your types are inverted, try restarting TSServer.
|
||||
|
||||
import '@types/node';
|
||||
|
||||
declare module 'stream/web' {
|
||||
interface ReadableStreamDefaultReader {
|
||||
readMany(): Promise<ReadableStreamDefaultReadManyResult<any>>;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
var performance: typeof import('perf_hooks').performance;
|
||||
|
||||
// TODO: These should be contributed to @types/node upstream
|
||||
namespace NodeJS {
|
||||
interface CallSite {
|
||||
getScriptNameOrSourceURL(): string;
|
||||
getEnclosingColumnNumber(): number;
|
||||
getEnclosingLineNumber(): number;
|
||||
getPosition(): number;
|
||||
getPromiseIndex(): number;
|
||||
getScriptHash(): string;
|
||||
isAsync(): boolean;
|
||||
isPromiseAll(): boolean;
|
||||
toString(): string;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
interface V8HeapSnapshot {
|
||||
snapshot: {
|
||||
meta: {
|
||||
node_fields: string[],
|
||||
node_types: [string[], ...string[]],
|
||||
edge_fields: string[],
|
||||
edge_types: [string[], ...string[]],
|
||||
trace_function_info_fields: string[],
|
||||
trace_node_fields: string[],
|
||||
sample_fields: string[],
|
||||
location_fields: string[]
|
||||
},
|
||||
node_count: number,
|
||||
edge_count: number,
|
||||
trace_function_count: number
|
||||
},
|
||||
nodes: number[],
|
||||
edges: number[],
|
||||
trace_function_infos: unknown[],
|
||||
trace_tree: unknown[],
|
||||
samples: unknown[],
|
||||
locations: number[],
|
||||
strings: string[]
|
||||
}
|
||||
@@ -1,230 +0,0 @@
|
||||
type PosixErrNo = MapKeysType<ReturnType<typeof getPosixSystemErrorMap>>;
|
||||
type Win32ErrNo = MapKeysType<ReturnType<typeof getWin32SystemErrorMap>>;
|
||||
|
||||
export function getCallSites(sliceOff = 1) {
|
||||
const originalPST = Error.prepareStackTrace;
|
||||
Error.prepareStackTrace = (error, stack) => stack;
|
||||
const { stack } = new Error();
|
||||
if (stack?.constructor.name !== 'Array') throw new Error('Failed to acquire structured JS stack trace');
|
||||
Error.prepareStackTrace = originalPST;
|
||||
return (stack as unknown as NodeJS.CallSite[]).slice(sliceOff);
|
||||
}
|
||||
|
||||
export function getPosixSystemErrorMap() {
|
||||
return new Map([
|
||||
[ -7, [ 'E2BIG', 'argument list too long' ] ],
|
||||
[ -13, [ 'EACCES', 'permission denied' ] ],
|
||||
[ -98, [ 'EADDRINUSE', 'address already in use' ] ],
|
||||
[ -99, [ 'EADDRNOTAVAIL', 'address not available' ] ],
|
||||
[ -97, [ 'EAFNOSUPPORT', 'address family not supported' ] ],
|
||||
[ -11, [ 'EAGAIN', 'resource temporarily unavailable' ] ],
|
||||
[ -3000, [ 'EAI_ADDRFAMILY', 'address family not supported' ] ],
|
||||
[ -3001, [ 'EAI_AGAIN', 'temporary failure' ] ],
|
||||
[ -3002, [ 'EAI_BADFLAGS', 'bad ai_flags value' ] ],
|
||||
[ -3013, [ 'EAI_BADHINTS', 'invalid value for hints' ] ],
|
||||
[ -3003, [ 'EAI_CANCELED', 'request canceled' ] ],
|
||||
[ -3004, [ 'EAI_FAIL', 'permanent failure' ] ],
|
||||
[ -3005, [ 'EAI_FAMILY', 'ai_family not supported' ] ],
|
||||
[ -3006, [ 'EAI_MEMORY', 'out of memory' ] ],
|
||||
[ -3007, [ 'EAI_NODATA', 'no address' ] ],
|
||||
[ -3008, [ 'EAI_NONAME', 'unknown node or service' ] ],
|
||||
[ -3009, [ 'EAI_OVERFLOW', 'argument buffer overflow' ] ],
|
||||
[ -3014, [ 'EAI_PROTOCOL', 'resolved protocol is unknown' ] ],
|
||||
[ -3010, [ 'EAI_SERVICE', 'service not available for socket type' ] ],
|
||||
[ -3011, [ 'EAI_SOCKTYPE', 'socket type not supported' ] ],
|
||||
[ -114, [ 'EALREADY', 'connection already in progress' ] ],
|
||||
[ -9, [ 'EBADF', 'bad file descriptor' ] ],
|
||||
[ -16, [ 'EBUSY', 'resource busy or locked' ] ],
|
||||
[ -125, [ 'ECANCELED', 'operation canceled' ] ],
|
||||
[ -4080, [ 'ECHARSET', 'invalid Unicode character' ] ],
|
||||
[ -103, [ 'ECONNABORTED', 'software caused connection abort' ] ],
|
||||
[ -111, [ 'ECONNREFUSED', 'connection refused' ] ],
|
||||
[ -104, [ 'ECONNRESET', 'connection reset by peer' ] ],
|
||||
[ -89, [ 'EDESTADDRREQ', 'destination address required' ] ],
|
||||
[ -17, [ 'EEXIST', 'file already exists' ] ],
|
||||
[ -14, [ 'EFAULT', 'bad address in system call argument' ] ],
|
||||
[ -27, [ 'EFBIG', 'file too large' ] ],
|
||||
[ -113, [ 'EHOSTUNREACH', 'host is unreachable' ] ],
|
||||
[ -4, [ 'EINTR', 'interrupted system call' ] ],
|
||||
[ -22, [ 'EINVAL', 'invalid argument' ] ],
|
||||
[ -5, [ 'EIO', 'i/o error' ] ],
|
||||
[ -106, [ 'EISCONN', 'socket is already connected' ] ],
|
||||
[ -21, [ 'EISDIR', 'illegal operation on a directory' ] ],
|
||||
[ -40, [ 'ELOOP', 'too many symbolic links encountered' ] ],
|
||||
[ -24, [ 'EMFILE', 'too many open files' ] ],
|
||||
[ -90, [ 'EMSGSIZE', 'message too long' ] ],
|
||||
[ -36, [ 'ENAMETOOLONG', 'name too long' ] ],
|
||||
[ -100, [ 'ENETDOWN', 'network is down' ] ],
|
||||
[ -101, [ 'ENETUNREACH', 'network is unreachable' ] ],
|
||||
[ -23, [ 'ENFILE', 'file table overflow' ] ],
|
||||
[ -105, [ 'ENOBUFS', 'no buffer space available' ] ],
|
||||
[ -19, [ 'ENODEV', 'no such device' ] ],
|
||||
[ -2, [ 'ENOENT', 'no such file or directory' ] ],
|
||||
[ -12, [ 'ENOMEM', 'not enough memory' ] ],
|
||||
[ -64, [ 'ENONET', 'machine is not on the network' ] ],
|
||||
[ -92, [ 'ENOPROTOOPT', 'protocol not available' ] ],
|
||||
[ -28, [ 'ENOSPC', 'no space left on device' ] ],
|
||||
[ -38, [ 'ENOSYS', 'function not implemented' ] ],
|
||||
[ -107, [ 'ENOTCONN', 'socket is not connected' ] ],
|
||||
[ -20, [ 'ENOTDIR', 'not a directory' ] ],
|
||||
[ -39, [ 'ENOTEMPTY', 'directory not empty' ] ],
|
||||
[ -88, [ 'ENOTSOCK', 'socket operation on non-socket' ] ],
|
||||
[ -95, [ 'ENOTSUP', 'operation not supported on socket' ] ],
|
||||
[ -75, [ 'EOVERFLOW', 'value too large for defined data type' ] ],
|
||||
[ -1, [ 'EPERM', 'operation not permitted' ] ],
|
||||
[ -32, [ 'EPIPE', 'broken pipe' ] ],
|
||||
[ -71, [ 'EPROTO', 'protocol error' ] ],
|
||||
[ -93, [ 'EPROTONOSUPPORT', 'protocol not supported' ] ],
|
||||
[ -91, [ 'EPROTOTYPE', 'protocol wrong type for socket' ] ],
|
||||
[ -34, [ 'ERANGE', 'result too large' ] ],
|
||||
[ -30, [ 'EROFS', 'read-only file system' ] ],
|
||||
[ -108, [ 'ESHUTDOWN', 'cannot send after transport endpoint shutdown' ] ],
|
||||
[ -29, [ 'ESPIPE', 'invalid seek' ] ],
|
||||
[ -3, [ 'ESRCH', 'no such process' ] ],
|
||||
[ -110, [ 'ETIMEDOUT', 'connection timed out' ] ],
|
||||
[ -26, [ 'ETXTBSY', 'text file is busy' ] ],
|
||||
[ -18, [ 'EXDEV', 'cross-device link not permitted' ] ],
|
||||
[ -4094, [ 'UNKNOWN', 'unknown error' ] ],
|
||||
[ -4095, [ 'EOF', 'end of file' ] ],
|
||||
[ -6, [ 'ENXIO', 'no such device or address' ] ],
|
||||
[ -31, [ 'EMLINK', 'too many links' ] ],
|
||||
[ -112, [ 'EHOSTDOWN', 'host is down' ] ],
|
||||
[ -121, [ 'EREMOTEIO', 'remote I/O error' ] ],
|
||||
[ -25, [ 'ENOTTY', 'inappropriate ioctl for device' ] ],
|
||||
[ -4028, [ 'EFTYPE', 'inappropriate file type or format' ] ],
|
||||
[ -84, [ 'EILSEQ', 'illegal byte sequence' ] ],
|
||||
[ -94, [ 'ESOCKTNOSUPPORT', 'socket type not supported' ] ]
|
||||
] as const);
|
||||
}
|
||||
|
||||
export function getWin32SystemErrorMap() {
|
||||
return new Map([
|
||||
[ -4093, [ 'E2BIG', 'argument list too long' ] ],
|
||||
[ -4092, [ 'EACCES', 'permission denied' ] ],
|
||||
[ -4091, [ 'EADDRINUSE', 'address already in use' ] ],
|
||||
[ -4090, [ 'EADDRNOTAVAIL', 'address not available' ] ],
|
||||
[ -4089, [ 'EAFNOSUPPORT', 'address family not supported' ] ],
|
||||
[ -4088, [ 'EAGAIN', 'resource temporarily unavailable' ] ],
|
||||
[ -3000, [ 'EAI_ADDRFAMILY', 'address family not supported' ] ],
|
||||
[ -3001, [ 'EAI_AGAIN', 'temporary failure' ] ],
|
||||
[ -3002, [ 'EAI_BADFLAGS', 'bad ai_flags value' ] ],
|
||||
[ -3013, [ 'EAI_BADHINTS', 'invalid value for hints' ] ],
|
||||
[ -3003, [ 'EAI_CANCELED', 'request canceled' ] ],
|
||||
[ -3004, [ 'EAI_FAIL', 'permanent failure' ] ],
|
||||
[ -3005, [ 'EAI_FAMILY', 'ai_family not supported' ] ],
|
||||
[ -3006, [ 'EAI_MEMORY', 'out of memory' ] ],
|
||||
[ -3007, [ 'EAI_NODATA', 'no address' ] ],
|
||||
[ -3008, [ 'EAI_NONAME', 'unknown node or service' ] ],
|
||||
[ -3009, [ 'EAI_OVERFLOW', 'argument buffer overflow' ] ],
|
||||
[ -3014, [ 'EAI_PROTOCOL', 'resolved protocol is unknown' ] ],
|
||||
[ -3010, [ 'EAI_SERVICE', 'service not available for socket type' ] ],
|
||||
[ -3011, [ 'EAI_SOCKTYPE', 'socket type not supported' ] ],
|
||||
[ -4084, [ 'EALREADY', 'connection already in progress' ] ],
|
||||
[ -4083, [ 'EBADF', 'bad file descriptor' ] ],
|
||||
[ -4082, [ 'EBUSY', 'resource busy or locked' ] ],
|
||||
[ -4081, [ 'ECANCELED', 'operation canceled' ] ],
|
||||
[ -4080, [ 'ECHARSET', 'invalid Unicode character' ] ],
|
||||
[ -4079, [ 'ECONNABORTED', 'software caused connection abort' ] ],
|
||||
[ -4078, [ 'ECONNREFUSED', 'connection refused' ] ],
|
||||
[ -4077, [ 'ECONNRESET', 'connection reset by peer' ] ],
|
||||
[ -4076, [ 'EDESTADDRREQ', 'destination address required' ] ],
|
||||
[ -4075, [ 'EEXIST', 'file already exists' ] ],
|
||||
[ -4074, [ 'EFAULT', 'bad address in system call argument' ] ],
|
||||
[ -4036, [ 'EFBIG', 'file too large' ] ],
|
||||
[ -4073, [ 'EHOSTUNREACH', 'host is unreachable' ] ],
|
||||
[ -4072, [ 'EINTR', 'interrupted system call' ] ],
|
||||
[ -4071, [ 'EINVAL', 'invalid argument' ] ],
|
||||
[ -4070, [ 'EIO', 'i/o error' ] ],
|
||||
[ -4069, [ 'EISCONN', 'socket is already connected' ] ],
|
||||
[ -4068, [ 'EISDIR', 'illegal operation on a directory' ] ],
|
||||
[ -4067, [ 'ELOOP', 'too many symbolic links encountered' ] ],
|
||||
[ -4066, [ 'EMFILE', 'too many open files' ] ],
|
||||
[ -4065, [ 'EMSGSIZE', 'message too long' ] ],
|
||||
[ -4064, [ 'ENAMETOOLONG', 'name too long' ] ],
|
||||
[ -4063, [ 'ENETDOWN', 'network is down' ] ],
|
||||
[ -4062, [ 'ENETUNREACH', 'network is unreachable' ] ],
|
||||
[ -4061, [ 'ENFILE', 'file table overflow' ] ],
|
||||
[ -4060, [ 'ENOBUFS', 'no buffer space available' ] ],
|
||||
[ -4059, [ 'ENODEV', 'no such device' ] ],
|
||||
[ -4058, [ 'ENOENT', 'no such file or directory' ] ],
|
||||
[ -4057, [ 'ENOMEM', 'not enough memory' ] ],
|
||||
[ -4056, [ 'ENONET', 'machine is not on the network' ] ],
|
||||
[ -4035, [ 'ENOPROTOOPT', 'protocol not available' ] ],
|
||||
[ -4055, [ 'ENOSPC', 'no space left on device' ] ],
|
||||
[ -4054, [ 'ENOSYS', 'function not implemented' ] ],
|
||||
[ -4053, [ 'ENOTCONN', 'socket is not connected' ] ],
|
||||
[ -4052, [ 'ENOTDIR', 'not a directory' ] ],
|
||||
[ -4051, [ 'ENOTEMPTY', 'directory not empty' ] ],
|
||||
[ -4050, [ 'ENOTSOCK', 'socket operation on non-socket' ] ],
|
||||
[ -4049, [ 'ENOTSUP', 'operation not supported on socket' ] ],
|
||||
[ -4026, [ 'EOVERFLOW', 'value too large for defined data type' ] ],
|
||||
[ -4048, [ 'EPERM', 'operation not permitted' ] ],
|
||||
[ -4047, [ 'EPIPE', 'broken pipe' ] ],
|
||||
[ -4046, [ 'EPROTO', 'protocol error' ] ],
|
||||
[ -4045, [ 'EPROTONOSUPPORT', 'protocol not supported' ] ],
|
||||
[ -4044, [ 'EPROTOTYPE', 'protocol wrong type for socket' ] ],
|
||||
[ -4034, [ 'ERANGE', 'result too large' ] ],
|
||||
[ -4043, [ 'EROFS', 'read-only file system' ] ],
|
||||
[ -4042, [ 'ESHUTDOWN', 'cannot send after transport endpoint shutdown' ] ],
|
||||
[ -4041, [ 'ESPIPE', 'invalid seek' ] ],
|
||||
[ -4040, [ 'ESRCH', 'no such process' ] ],
|
||||
[ -4039, [ 'ETIMEDOUT', 'connection timed out' ] ],
|
||||
[ -4038, [ 'ETXTBSY', 'text file is busy' ] ],
|
||||
[ -4037, [ 'EXDEV', 'cross-device link not permitted' ] ],
|
||||
[ -4094, [ 'UNKNOWN', 'unknown error' ] ],
|
||||
[ -4095, [ 'EOF', 'end of file' ] ],
|
||||
[ -4033, [ 'ENXIO', 'no such device or address' ] ],
|
||||
[ -4032, [ 'EMLINK', 'too many links' ] ],
|
||||
[ -4031, [ 'EHOSTDOWN', 'host is down' ] ],
|
||||
[ -4030, [ 'EREMOTEIO', 'remote I/O error' ] ],
|
||||
[ -4029, [ 'ENOTTY', 'inappropriate ioctl for device' ] ],
|
||||
[ -4028, [ 'EFTYPE', 'inappropriate file type or format' ] ],
|
||||
[ -4027, [ 'EILSEQ', 'illegal byte sequence' ] ],
|
||||
[ -4025, [ 'ESOCKTNOSUPPORT', 'socket type not supported' ] ]
|
||||
] as const);
|
||||
}
|
||||
|
||||
export function getPosixToWin32SystemErrorMap() {
|
||||
const posixEntries = [...getPosixSystemErrorMap().entries()];
|
||||
const win32Entries = [...getWin32SystemErrorMap().entries()];
|
||||
const map: Map<PosixErrNo, Win32ErrNo> = new Map();
|
||||
posixEntries.forEach(([code, val]) => {
|
||||
const found = win32Entries.find(([_, v]) => v[0] === val[0]);
|
||||
if (!found) console.error(val[0]);
|
||||
else map.set(code, found[0]);
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
export function getPlatformSystemErrorFromPosix(posixErrNo: PosixErrNo) {
|
||||
if (process.platform === 'win32') {
|
||||
const win32errno = getPosixToWin32SystemErrorMap().get(posixErrNo)!;
|
||||
return getWin32SystemErrorMap().get(win32errno);
|
||||
} else {
|
||||
return getPosixSystemErrorMap().get(posixErrNo);
|
||||
}
|
||||
}
|
||||
|
||||
export class SystemError extends Error {
|
||||
constructor(errno: PosixErrNo, syscall?: string, errpath?: string) {
|
||||
const [errname, errmsg] = getPlatformSystemErrorFromPosix(errno) ?? ['SystemError', 'Unknown system error'];
|
||||
super(errmsg);
|
||||
this.name = errname;
|
||||
this.code = errname;
|
||||
this.errno = errno;
|
||||
if (syscall) this.syscall = syscall;
|
||||
if (errpath) this.path = errpath;
|
||||
}
|
||||
errno?: number | undefined;
|
||||
code?: string | undefined;
|
||||
path?: string | undefined;
|
||||
syscall?: string | undefined;
|
||||
}
|
||||
|
||||
export class NotImplementedError extends Error {
|
||||
constructor(thing: string, func: AnyCallable = NotImplementedError, overrideMsg: boolean = false) {
|
||||
super(overrideMsg ? thing : `A polyfill for ${thing} is not yet implemented by bun-polyfills.`);
|
||||
this.name = 'NotImplementedError';
|
||||
Error.captureStackTrace(this, func);
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import streams from 'node:stream';
|
||||
import type { SpawnOptions, FileBlob } from 'bun';
|
||||
|
||||
export const getter = <T>(obj: T, key: string | symbol, get: () => any, enumerable = false, configurable = true): void => {
|
||||
Object.defineProperty(obj, key, { get, configurable, enumerable });
|
||||
};
|
||||
|
||||
export const setter = <T>(obj: T, key: string | symbol, set: () => any, enumerable = false, configurable = true): void => {
|
||||
Object.defineProperty(obj, key, { set, configurable, enumerable });
|
||||
};
|
||||
|
||||
export const readonly = <T>(obj: T, key: string | symbol, value: unknown, enumerable = false, configurable = true): void => {
|
||||
Object.defineProperty(obj, key, { value, configurable, enumerable });
|
||||
};
|
||||
|
||||
export function streamToBuffer(stream: streams.Readable | streams.Duplex): Promise<Buffer> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const buffers: Uint8Array[] = [];
|
||||
stream.on("data", (chunk: Uint8Array) => buffers.push(chunk));
|
||||
stream.on("end", () => resolve(Buffer.concat(buffers)));
|
||||
stream.on("error", (err: Error) => reject(err));
|
||||
});
|
||||
}
|
||||
|
||||
export function isArrayBufferView(value: any): value is ArrayBufferView {
|
||||
return value !== null && typeof value === 'object' &&
|
||||
value.buffer instanceof ArrayBuffer && typeof value.byteLength === 'number' && typeof value.byteOffset === 'number';
|
||||
}
|
||||
|
||||
export function isOptions(options: any): options is SpawnOptions.OptionsObject {
|
||||
return options !== null && typeof options === 'object';
|
||||
}
|
||||
|
||||
export function isFileBlob(blob: any): blob is FileBlob {
|
||||
return blob instanceof Blob && Reflect.get(blob, 'readable') instanceof ReadableStream && typeof Reflect.get(blob, 'writer') === 'function';
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import path from 'path';
|
||||
|
||||
const abort = (...msg: string[]): never => (console.error(...msg), process.exit(1));
|
||||
|
||||
const makefilePath = path.resolve(import.meta.dir, '../../../Makefile');
|
||||
const makefile = Bun.file(makefilePath);
|
||||
if (!await makefile.exists()) abort('Makefile not found at', makefilePath);
|
||||
|
||||
const makefileContent = await makefile.text();
|
||||
const matched = makefileContent.match(/^BUN_BASE_VERSION\s*=\s*(\d+.\d+)/m);
|
||||
if (!matched) abort('Could not find BUN_BASE_VERSION in Makefile');
|
||||
|
||||
const buildidPath = path.resolve(import.meta.dir, '../../../src/build-id');
|
||||
const buildid = Bun.file(buildidPath);
|
||||
if (!await buildid.exists()) abort('Build ID file not found at', buildidPath);
|
||||
|
||||
const [, BUN_BASE_VERSION] = matched!;
|
||||
const BUN_VERSION = `${BUN_BASE_VERSION}.${await buildid.text()}`.trim();
|
||||
|
||||
const bunTsPath = path.resolve(import.meta.dir, '../src/modules/bun.ts');
|
||||
const bunTs = Bun.file(bunTsPath);
|
||||
if (!await bunTs.exists()) abort('bun.ts source file not found at', bunTsPath);
|
||||
|
||||
const bunTsContent = await bunTs.text();
|
||||
const bunTsContentNew = bunTsContent.replace(
|
||||
/^export const version = '.+' satisfies typeof Bun.version;$/m,
|
||||
`export const version = '${BUN_VERSION}' satisfies typeof Bun.version;`
|
||||
);
|
||||
if (bunTsContentNew !== bunTsContent) console.info('Updated Bun.version polyfill to', BUN_VERSION);
|
||||
|
||||
const git = Bun.spawnSync({ cmd: ['git', 'rev-parse', 'HEAD'] });
|
||||
if (!git.success) abort('Could not get git HEAD commit hash');
|
||||
const BUN_REVISION = git.stdout.toString('utf8').trim();
|
||||
|
||||
const bunTsContentNewer = bunTsContentNew.replace(
|
||||
/^export const revision = '.+' satisfies typeof Bun.revision;$/m,
|
||||
`export const revision = '${BUN_REVISION}' satisfies typeof Bun.revision;`
|
||||
);
|
||||
if (bunTsContentNewer !== bunTsContentNew) console.info('Updated Bun.revision polyfill to', BUN_REVISION);
|
||||
|
||||
Bun.write(bunTs, bunTsContentNewer);
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext"],
|
||||
"module": "esnext",
|
||||
"target": "esnext",
|
||||
"moduleResolution": "nodenext",
|
||||
"moduleDetection": "force",
|
||||
"strict": true,
|
||||
"downlevelIteration": true,
|
||||
"skipLibCheck": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"inlineSourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "dist",
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["src", "lib", "../bun-types/index.d.ts"]
|
||||
}
|
||||
851
packages/bun-types/bun.d.ts
vendored
851
packages/bun-types/bun.d.ts
vendored
File diff suppressed because it is too large
Load Diff
2
packages/bun-types/fetch.d.ts
vendored
2
packages/bun-types/fetch.d.ts
vendored
@@ -39,7 +39,7 @@ declare module "bun" {
|
||||
*
|
||||
* Does not preserve insertion order. Well-known header names are lowercased. Other header names are left as-is.
|
||||
*/
|
||||
toJSON(): Record<string, string>;
|
||||
toJSON(): Record<string, string> & { "set-cookie"?: string[] };
|
||||
|
||||
/**
|
||||
* Get the total number of headers
|
||||
|
||||
30
packages/bun-types/globals.d.ts
vendored
30
packages/bun-types/globals.d.ts
vendored
@@ -1312,7 +1312,7 @@ interface PromiseConstructor {
|
||||
* This is useful when you want to return a Promise and have code outside the Promise
|
||||
* resolve or reject it.
|
||||
*
|
||||
* ## Example
|
||||
* @example
|
||||
* ```ts
|
||||
* const { promise, resolve, reject } = Promise.withResolvers();
|
||||
*
|
||||
@@ -1322,8 +1322,6 @@ interface PromiseConstructor {
|
||||
*
|
||||
* await promise; // "Hello world!"
|
||||
* ```
|
||||
*
|
||||
* `Promise.withResolvers()` is a [stage3 proposal](https://github.com/tc39/proposal-promise-with-resolvers).
|
||||
*/
|
||||
withResolvers<T>(): {
|
||||
promise: Promise<T>;
|
||||
@@ -1832,14 +1830,40 @@ interface BunFetchRequestInit extends RequestInit {
|
||||
/**
|
||||
* Override http_proxy or HTTPS_PROXY
|
||||
* This is a custom property that is not part of the Fetch API specification.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* const response = await fetch("http://example.com", {
|
||||
* proxy: "https://username:password@127.0.0.1:8080"
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
proxy?: string;
|
||||
|
||||
/**
|
||||
* Override the default S3 options
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* const response = await fetch("s3://bucket/key", {
|
||||
* s3: {
|
||||
* accessKeyId: "AKIAIOSFODNN7EXAMPLE",
|
||||
* secretAccessKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
|
||||
* region: "us-east-1",
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
s3?: Bun.S3Options;
|
||||
|
||||
/**
|
||||
* Make the request over a Unix socket
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* const response = await fetch("http://example.com", { unix: "/path/to/socket" });
|
||||
* ```
|
||||
*/
|
||||
unix?: string;
|
||||
}
|
||||
|
||||
|
||||
40
packages/bun-types/jsc.d.ts
vendored
40
packages/bun-types/jsc.d.ts
vendored
@@ -8,24 +8,8 @@ declare module "bun:jsc" {
|
||||
function fullGC(): number;
|
||||
function edenGC(): number;
|
||||
function heapSize(): number;
|
||||
function heapStats(): {
|
||||
heapSize: number;
|
||||
heapCapacity: number;
|
||||
extraMemorySize: number;
|
||||
objectCount: number;
|
||||
protectedObjectCount: number;
|
||||
globalObjectCount: number;
|
||||
protectedGlobalObjectCount: number;
|
||||
objectTypeCounts: Record<string, number>;
|
||||
protectedObjectTypeCounts: Record<string, number>;
|
||||
};
|
||||
function memoryUsage(): {
|
||||
current: number;
|
||||
peak: number;
|
||||
currentCommit: number;
|
||||
peakCommit: number;
|
||||
pageFaults: number;
|
||||
};
|
||||
function heapStats(): HeapStats;
|
||||
function memoryUsage(): MemoryUsage;
|
||||
function getRandomSeed(): number;
|
||||
function setRandomSeed(value: number): void;
|
||||
function isRope(input: string): boolean;
|
||||
@@ -78,6 +62,26 @@ declare module "bun:jsc" {
|
||||
*/
|
||||
function setTimeZone(timeZone: string): string;
|
||||
|
||||
interface HeapStats {
|
||||
heapSize: number;
|
||||
heapCapacity: number;
|
||||
extraMemorySize: number;
|
||||
objectCount: number;
|
||||
protectedObjectCount: number;
|
||||
globalObjectCount: number;
|
||||
protectedGlobalObjectCount: number;
|
||||
objectTypeCounts: Record<string, number>;
|
||||
protectedObjectTypeCounts: Record<string, number>;
|
||||
}
|
||||
|
||||
interface MemoryUsage {
|
||||
current: number;
|
||||
peak: number;
|
||||
currentCommit: number;
|
||||
peakCommit: number;
|
||||
pageFaults: number;
|
||||
}
|
||||
|
||||
interface SamplingProfile {
|
||||
/**
|
||||
* A formatted summary of the top functions
|
||||
|
||||
6
packages/bun-types/redis.d.ts
vendored
6
packages/bun-types/redis.d.ts
vendored
@@ -1,11 +1,5 @@
|
||||
declare module "bun" {
|
||||
export interface RedisOptions {
|
||||
/**
|
||||
* URL to connect to, defaults to "redis://localhost:6379"
|
||||
* Supported protocols: redis://, rediss://, redis+unix://, redis+tls://
|
||||
*/
|
||||
url?: string;
|
||||
|
||||
/**
|
||||
* Connection timeout in milliseconds
|
||||
* @default 10000
|
||||
|
||||
1
packages/bun-types/s3.d.ts
vendored
1
packages/bun-types/s3.d.ts
vendored
@@ -764,7 +764,6 @@ declare module "bun" {
|
||||
* @category Cloud Storage
|
||||
*/
|
||||
class S3Client {
|
||||
prototype: S3Client;
|
||||
/**
|
||||
* Create a new instance of an S3 bucket so that credentials can be managed
|
||||
* from a single instance instead of being passed to every method.
|
||||
|
||||
84
packages/bun-types/shell.d.ts
vendored
84
packages/bun-types/shell.d.ts
vendored
@@ -6,21 +6,27 @@ declare module "bun" {
|
||||
| Array<ShellExpression>
|
||||
| string
|
||||
| { raw: string }
|
||||
| Subprocess
|
||||
| Subprocess<SpawnOptions.Writable, SpawnOptions.Readable, SpawnOptions.Readable>
|
||||
| SpawnOptions.Readable
|
||||
| SpawnOptions.Writable
|
||||
| ReadableStream;
|
||||
|
||||
/**
|
||||
* The Bun shell
|
||||
* The [Bun shell](https://bun.sh/docs/runtime/shell) is a powerful tool for running shell commands.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const result = await $`echo "Hello, world!"`.text();
|
||||
* console.log(result); // "Hello, world!"
|
||||
* ```
|
||||
*
|
||||
* @category Process Management
|
||||
*/
|
||||
function $(strings: TemplateStringsArray, ...expressions: ShellExpression[]): $.ShellPromise;
|
||||
|
||||
namespace $ {
|
||||
const Shell: new () => typeof $;
|
||||
type $ = typeof $;
|
||||
|
||||
namespace $ {
|
||||
/**
|
||||
* Perform bash-like brace expansion on the given pattern.
|
||||
* @param pattern - Brace pattern to expand
|
||||
@@ -46,8 +52,7 @@ declare module "bun" {
|
||||
* @param newEnv Default environment variables to use for shells created by this instance.
|
||||
* @default process.env
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* import {$} from 'bun';
|
||||
* $.env({ BUN: "bun" });
|
||||
@@ -55,24 +60,35 @@ declare module "bun" {
|
||||
* // "bun"
|
||||
* ```
|
||||
*/
|
||||
function env(newEnv?: Record<string, string | undefined>): typeof $;
|
||||
function env(newEnv?: Record<string, string | undefined>): $;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param newCwd Default working directory to use for shells created by this instance.
|
||||
*/
|
||||
function cwd(newCwd?: string): typeof $;
|
||||
function cwd(newCwd?: string): $;
|
||||
|
||||
/**
|
||||
* Configure the shell to not throw an exception on non-zero exit codes.
|
||||
*/
|
||||
function nothrow(): typeof $;
|
||||
function nothrow(): $;
|
||||
|
||||
/**
|
||||
* Configure whether or not the shell should throw an exception on non-zero exit codes.
|
||||
*/
|
||||
function throws(shouldThrow: boolean): typeof $;
|
||||
function throws(shouldThrow: boolean): $;
|
||||
|
||||
/**
|
||||
* The `Bun.$.ShellPromise` class represents a shell command that gets executed
|
||||
* once awaited, or called with `.text()`, `.json()`, etc.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const myShellPromise = $`echo "Hello, world!"`;
|
||||
* const result = await myShellPromise.text();
|
||||
* console.log(result); // "Hello, world!"
|
||||
* ```
|
||||
*/
|
||||
class ShellPromise extends Promise<ShellOutput> {
|
||||
get stdin(): WritableStream;
|
||||
|
||||
@@ -81,6 +97,7 @@ declare module "bun" {
|
||||
* @param newCwd - The new working directory
|
||||
*/
|
||||
cwd(newCwd: string): this;
|
||||
|
||||
/**
|
||||
* Set environment variables for the shell.
|
||||
* @param newEnv - The new environment variables
|
||||
@@ -92,6 +109,7 @@ declare module "bun" {
|
||||
* ```
|
||||
*/
|
||||
env(newEnv: Record<string, string> | undefined): this;
|
||||
|
||||
/**
|
||||
* By default, the shell will write to the current process's stdout and stderr, as well as buffering that output.
|
||||
*
|
||||
@@ -107,27 +125,25 @@ declare module "bun" {
|
||||
lines(): AsyncIterable<string>;
|
||||
|
||||
/**
|
||||
* Read from stdout as a string
|
||||
* Read from stdout as a string.
|
||||
*
|
||||
* Automatically calls {@link quiet} to disable echoing to stdout.
|
||||
*
|
||||
* @param encoding - The encoding to use when decoding the output
|
||||
* @returns A promise that resolves with stdout as a string
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ## Read as UTF-8 string
|
||||
*
|
||||
* **Read as UTF-8 string**
|
||||
* ```ts
|
||||
* const output = await $`echo hello`.text();
|
||||
* console.log(output); // "hello\n"
|
||||
* ```
|
||||
*
|
||||
* ## Read as base64 string
|
||||
*
|
||||
* **Read as base64 string**
|
||||
* ```ts
|
||||
* const output = await $`echo ${atob("hello")}`.text("base64");
|
||||
* console.log(output); // "hello\n"
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
text(encoding?: BufferEncoding): Promise<string>;
|
||||
|
||||
@@ -189,6 +205,20 @@ declare module "bun" {
|
||||
throws(shouldThrow: boolean): this;
|
||||
}
|
||||
|
||||
/**
|
||||
* ShellError represents an error that occurred while executing a shell command with [the Bun Shell](https://bun.sh/docs/runtime/shell).
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* try {
|
||||
* const result = await $`exit 1`;
|
||||
* } catch (error) {
|
||||
* if (error instanceof ShellError) {
|
||||
* console.log(error.exitCode); // 1
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class ShellError extends Error implements ShellOutput {
|
||||
readonly stdout: Buffer;
|
||||
readonly stderr: Buffer;
|
||||
@@ -199,22 +229,19 @@ declare module "bun" {
|
||||
*
|
||||
* @param encoding - The encoding to use when decoding the output
|
||||
* @returns Stdout as a string with the given encoding
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ## Read as UTF-8 string
|
||||
*
|
||||
* **Read as UTF-8 string**
|
||||
* ```ts
|
||||
* const output = await $`echo hello`;
|
||||
* console.log(output.text()); // "hello\n"
|
||||
* ```
|
||||
*
|
||||
* ## Read as base64 string
|
||||
*
|
||||
* **Read as base64 string**
|
||||
* ```ts
|
||||
* const output = await $`echo ${atob("hello")}`;
|
||||
* console.log(output.text("base64")); // "hello\n"
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
text(encoding?: BufferEncoding): string;
|
||||
|
||||
@@ -280,22 +307,19 @@ declare module "bun" {
|
||||
*
|
||||
* @param encoding - The encoding to use when decoding the output
|
||||
* @returns Stdout as a string with the given encoding
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ## Read as UTF-8 string
|
||||
*
|
||||
* **Read as UTF-8 string**
|
||||
* ```ts
|
||||
* const output = await $`echo hello`;
|
||||
* console.log(output.text()); // "hello\n"
|
||||
* ```
|
||||
*
|
||||
* ## Read as base64 string
|
||||
*
|
||||
* **Read as base64 string**
|
||||
* ```ts
|
||||
* const output = await $`echo ${atob("hello")}`;
|
||||
* console.log(output.text("base64")); // "hello\n"
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
text(encoding?: BufferEncoding): string;
|
||||
|
||||
@@ -351,5 +375,7 @@ declare module "bun" {
|
||||
*/
|
||||
blob(): Blob;
|
||||
}
|
||||
|
||||
const Shell: new () => $;
|
||||
}
|
||||
}
|
||||
|
||||
139
packages/bun-types/sqlite.d.ts
vendored
139
packages/bun-types/sqlite.d.ts
vendored
@@ -849,147 +849,146 @@ declare module "bun:sqlite" {
|
||||
*
|
||||
* This list isn't exhaustive, but some of the ones which are relevant
|
||||
*/
|
||||
export const constants: {
|
||||
export namespace constants {
|
||||
/**
|
||||
* Open the database as read-only (no write operations, no create).
|
||||
* @constant 0x00000001
|
||||
*/
|
||||
SQLITE_OPEN_READONLY: number;
|
||||
const SQLITE_OPEN_READONLY: number;
|
||||
/**
|
||||
* Open the database for reading and writing
|
||||
* @constant 0x00000002
|
||||
*/
|
||||
SQLITE_OPEN_READWRITE: number;
|
||||
const SQLITE_OPEN_READWRITE: number;
|
||||
/**
|
||||
* Allow creating a new database
|
||||
* @constant 0x00000004
|
||||
*/
|
||||
SQLITE_OPEN_CREATE: number;
|
||||
const SQLITE_OPEN_CREATE: number;
|
||||
/**
|
||||
* @constant 0x00000008
|
||||
*/
|
||||
SQLITE_OPEN_DELETEONCLOSE: number;
|
||||
const SQLITE_OPEN_DELETEONCLOSE: number;
|
||||
/**
|
||||
* @constant 0x00000010
|
||||
*/
|
||||
SQLITE_OPEN_EXCLUSIVE: number;
|
||||
const SQLITE_OPEN_EXCLUSIVE: number;
|
||||
/**
|
||||
* @constant 0x00000020
|
||||
*/
|
||||
SQLITE_OPEN_AUTOPROXY: number;
|
||||
const SQLITE_OPEN_AUTOPROXY: number;
|
||||
/**
|
||||
* @constant 0x00000040
|
||||
*/
|
||||
SQLITE_OPEN_URI: number;
|
||||
const SQLITE_OPEN_URI: number;
|
||||
/**
|
||||
* @constant 0x00000080
|
||||
*/
|
||||
SQLITE_OPEN_MEMORY: number;
|
||||
const SQLITE_OPEN_MEMORY: number;
|
||||
/**
|
||||
* @constant 0x00000100
|
||||
*/
|
||||
SQLITE_OPEN_MAIN_DB: number;
|
||||
const SQLITE_OPEN_MAIN_DB: number;
|
||||
/**
|
||||
* @constant 0x00000200
|
||||
*/
|
||||
SQLITE_OPEN_TEMP_DB: number;
|
||||
const SQLITE_OPEN_TEMP_DB: number;
|
||||
/**
|
||||
* @constant 0x00000400
|
||||
*/
|
||||
SQLITE_OPEN_TRANSIENT_DB: number;
|
||||
const SQLITE_OPEN_TRANSIENT_DB: number;
|
||||
/**
|
||||
* @constant 0x00000800
|
||||
*/
|
||||
SQLITE_OPEN_MAIN_JOURNAL: number;
|
||||
const SQLITE_OPEN_MAIN_JOURNAL: number;
|
||||
/**
|
||||
* @constant 0x00001000
|
||||
*/
|
||||
SQLITE_OPEN_TEMP_JOURNAL: number;
|
||||
const SQLITE_OPEN_TEMP_JOURNAL: number;
|
||||
/**
|
||||
* @constant 0x00002000
|
||||
*/
|
||||
SQLITE_OPEN_SUBJOURNAL: number;
|
||||
const SQLITE_OPEN_SUBJOURNAL: number;
|
||||
/**
|
||||
* @constant 0x00004000
|
||||
*/
|
||||
SQLITE_OPEN_SUPER_JOURNAL: number;
|
||||
const SQLITE_OPEN_SUPER_JOURNAL: number;
|
||||
/**
|
||||
* @constant 0x00008000
|
||||
*/
|
||||
SQLITE_OPEN_NOMUTEX: number;
|
||||
const SQLITE_OPEN_NOMUTEX: number;
|
||||
/**
|
||||
* @constant 0x00010000
|
||||
*/
|
||||
SQLITE_OPEN_FULLMUTEX: number;
|
||||
const SQLITE_OPEN_FULLMUTEX: number;
|
||||
/**
|
||||
* @constant 0x00020000
|
||||
*/
|
||||
SQLITE_OPEN_SHAREDCACHE: number;
|
||||
const SQLITE_OPEN_SHAREDCACHE: number;
|
||||
/**
|
||||
* @constant 0x00040000
|
||||
*/
|
||||
SQLITE_OPEN_PRIVATECACHE: number;
|
||||
const SQLITE_OPEN_PRIVATECACHE: number;
|
||||
/**
|
||||
* @constant 0x00080000
|
||||
*/
|
||||
SQLITE_OPEN_WAL: number;
|
||||
const SQLITE_OPEN_WAL: number;
|
||||
/**
|
||||
* @constant 0x01000000
|
||||
*/
|
||||
SQLITE_OPEN_NOFOLLOW: number;
|
||||
const SQLITE_OPEN_NOFOLLOW: number;
|
||||
/**
|
||||
* @constant 0x02000000
|
||||
*/
|
||||
SQLITE_OPEN_EXRESCODE: number;
|
||||
const SQLITE_OPEN_EXRESCODE: number;
|
||||
/**
|
||||
* @constant 0x01
|
||||
*/
|
||||
SQLITE_PREPARE_PERSISTENT: number;
|
||||
const SQLITE_PREPARE_PERSISTENT: number;
|
||||
/**
|
||||
* @constant 0x02
|
||||
*/
|
||||
SQLITE_PREPARE_NORMALIZE: number;
|
||||
const SQLITE_PREPARE_NORMALIZE: number;
|
||||
/**
|
||||
* @constant 0x04
|
||||
*/
|
||||
SQLITE_PREPARE_NO_VTAB: number;
|
||||
|
||||
const SQLITE_PREPARE_NO_VTAB: number;
|
||||
/**
|
||||
* @constant 1
|
||||
*/
|
||||
SQLITE_FCNTL_LOCKSTATE: number;
|
||||
const SQLITE_FCNTL_LOCKSTATE: number;
|
||||
/**
|
||||
* @constant 2
|
||||
*/
|
||||
SQLITE_FCNTL_GET_LOCKPROXYFILE: number;
|
||||
const SQLITE_FCNTL_GET_LOCKPROXYFILE: number;
|
||||
/**
|
||||
* @constant 3
|
||||
*/
|
||||
SQLITE_FCNTL_SET_LOCKPROXYFILE: number;
|
||||
const SQLITE_FCNTL_SET_LOCKPROXYFILE: number;
|
||||
/**
|
||||
* @constant 4
|
||||
*/
|
||||
SQLITE_FCNTL_LAST_ERRNO: number;
|
||||
const SQLITE_FCNTL_LAST_ERRNO: number;
|
||||
/**
|
||||
* @constant 5
|
||||
*/
|
||||
SQLITE_FCNTL_SIZE_HINT: number;
|
||||
const SQLITE_FCNTL_SIZE_HINT: number;
|
||||
/**
|
||||
* @constant 6
|
||||
*/
|
||||
SQLITE_FCNTL_CHUNK_SIZE: number;
|
||||
const SQLITE_FCNTL_CHUNK_SIZE: number;
|
||||
/**
|
||||
* @constant 7
|
||||
*/
|
||||
SQLITE_FCNTL_FILE_POINTER: number;
|
||||
const SQLITE_FCNTL_FILE_POINTER: number;
|
||||
/**
|
||||
* @constant 8
|
||||
*/
|
||||
SQLITE_FCNTL_SYNC_OMITTED: number;
|
||||
const SQLITE_FCNTL_SYNC_OMITTED: number;
|
||||
/**
|
||||
* @constant 9
|
||||
*/
|
||||
SQLITE_FCNTL_WIN32_AV_RETRY: number;
|
||||
const SQLITE_FCNTL_WIN32_AV_RETRY: number;
|
||||
/**
|
||||
* @constant 10
|
||||
*
|
||||
@@ -998,7 +997,7 @@ declare module "bun:sqlite" {
|
||||
*
|
||||
* You can change this with code like the below:
|
||||
* ```ts
|
||||
* import { Database } from "bun:sqlite";
|
||||
* import { Database, constants } from "bun:sqlite";
|
||||
*
|
||||
* const db = Database.open("mydb.sqlite");
|
||||
* db.fileControl(constants.SQLITE_FCNTL_PERSIST_WAL, 0);
|
||||
@@ -1009,132 +1008,132 @@ declare module "bun:sqlite" {
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
SQLITE_FCNTL_PERSIST_WAL: number;
|
||||
const SQLITE_FCNTL_PERSIST_WAL: number;
|
||||
/**
|
||||
* @constant 11
|
||||
*/
|
||||
SQLITE_FCNTL_OVERWRITE: number;
|
||||
const SQLITE_FCNTL_OVERWRITE: number;
|
||||
/**
|
||||
* @constant 12
|
||||
*/
|
||||
SQLITE_FCNTL_VFSNAME: number;
|
||||
const SQLITE_FCNTL_VFSNAME: number;
|
||||
/**
|
||||
* @constant 13
|
||||
*/
|
||||
SQLITE_FCNTL_POWERSAFE_OVERWRITE: number;
|
||||
const SQLITE_FCNTL_POWERSAFE_OVERWRITE: number;
|
||||
/**
|
||||
* @constant 14
|
||||
*/
|
||||
SQLITE_FCNTL_PRAGMA: number;
|
||||
const SQLITE_FCNTL_PRAGMA: number;
|
||||
/**
|
||||
* @constant 15
|
||||
*/
|
||||
SQLITE_FCNTL_BUSYHANDLER: number;
|
||||
const SQLITE_FCNTL_BUSYHANDLER: number;
|
||||
/**
|
||||
* @constant 16
|
||||
*/
|
||||
SQLITE_FCNTL_TEMPFILENAME: number;
|
||||
const SQLITE_FCNTL_TEMPFILENAME: number;
|
||||
/**
|
||||
* @constant 18
|
||||
*/
|
||||
SQLITE_FCNTL_MMAP_SIZE: number;
|
||||
const SQLITE_FCNTL_MMAP_SIZE: number;
|
||||
/**
|
||||
* @constant 19
|
||||
*/
|
||||
SQLITE_FCNTL_TRACE: number;
|
||||
const SQLITE_FCNTL_TRACE: number;
|
||||
/**
|
||||
* @constant 20
|
||||
*/
|
||||
SQLITE_FCNTL_HAS_MOVED: number;
|
||||
const SQLITE_FCNTL_HAS_MOVED: number;
|
||||
/**
|
||||
* @constant 21
|
||||
*/
|
||||
SQLITE_FCNTL_SYNC: number;
|
||||
const SQLITE_FCNTL_SYNC: number;
|
||||
/**
|
||||
* @constant 22
|
||||
*/
|
||||
SQLITE_FCNTL_COMMIT_PHASETWO: number;
|
||||
const SQLITE_FCNTL_COMMIT_PHASETWO: number;
|
||||
/**
|
||||
* @constant 23
|
||||
*/
|
||||
SQLITE_FCNTL_WIN32_SET_HANDLE: number;
|
||||
const SQLITE_FCNTL_WIN32_SET_HANDLE: number;
|
||||
/**
|
||||
* @constant 24
|
||||
*/
|
||||
SQLITE_FCNTL_WAL_BLOCK: number;
|
||||
const SQLITE_FCNTL_WAL_BLOCK: number;
|
||||
/**
|
||||
* @constant 25
|
||||
*/
|
||||
SQLITE_FCNTL_ZIPVFS: number;
|
||||
const SQLITE_FCNTL_ZIPVFS: number;
|
||||
/**
|
||||
* @constant 26
|
||||
*/
|
||||
SQLITE_FCNTL_RBU: number;
|
||||
const SQLITE_FCNTL_RBU: number;
|
||||
/**
|
||||
* @constant 27
|
||||
*/
|
||||
SQLITE_FCNTL_VFS_POINTER: number;
|
||||
const SQLITE_FCNTL_VFS_POINTER: number;
|
||||
/**
|
||||
* @constant 28
|
||||
*/
|
||||
SQLITE_FCNTL_JOURNAL_POINTER: number;
|
||||
const SQLITE_FCNTL_JOURNAL_POINTER: number;
|
||||
/**
|
||||
* @constant 29
|
||||
*/
|
||||
SQLITE_FCNTL_WIN32_GET_HANDLE: number;
|
||||
const SQLITE_FCNTL_WIN32_GET_HANDLE: number;
|
||||
/**
|
||||
* @constant 30
|
||||
*/
|
||||
SQLITE_FCNTL_PDB: number;
|
||||
const SQLITE_FCNTL_PDB: number;
|
||||
/**
|
||||
* @constant 31
|
||||
*/
|
||||
SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: number;
|
||||
const SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: number;
|
||||
/**
|
||||
* @constant 32
|
||||
*/
|
||||
SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: number;
|
||||
const SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: number;
|
||||
/**
|
||||
* @constant 33
|
||||
*/
|
||||
SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: number;
|
||||
const SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: number;
|
||||
/**
|
||||
* @constant 34
|
||||
*/
|
||||
SQLITE_FCNTL_LOCK_TIMEOUT: number;
|
||||
const SQLITE_FCNTL_LOCK_TIMEOUT: number;
|
||||
/**
|
||||
* @constant 35
|
||||
*/
|
||||
SQLITE_FCNTL_DATA_VERSION: number;
|
||||
const SQLITE_FCNTL_DATA_VERSION: number;
|
||||
/**
|
||||
* @constant 36
|
||||
*/
|
||||
SQLITE_FCNTL_SIZE_LIMIT: number;
|
||||
const SQLITE_FCNTL_SIZE_LIMIT: number;
|
||||
/**
|
||||
* @constant 37
|
||||
*/
|
||||
SQLITE_FCNTL_CKPT_DONE: number;
|
||||
const SQLITE_FCNTL_CKPT_DONE: number;
|
||||
/**
|
||||
* @constant 38
|
||||
*/
|
||||
SQLITE_FCNTL_RESERVE_BYTES: number;
|
||||
const SQLITE_FCNTL_RESERVE_BYTES: number;
|
||||
/**
|
||||
* @constant 39
|
||||
*/
|
||||
SQLITE_FCNTL_CKPT_START: number;
|
||||
const SQLITE_FCNTL_CKPT_START: number;
|
||||
/**
|
||||
* @constant 40
|
||||
*/
|
||||
SQLITE_FCNTL_EXTERNAL_READER: number;
|
||||
const SQLITE_FCNTL_EXTERNAL_READER: number;
|
||||
/**
|
||||
* @constant 41
|
||||
*/
|
||||
SQLITE_FCNTL_CKSM_FILE: number;
|
||||
const SQLITE_FCNTL_CKSM_FILE: number;
|
||||
/**
|
||||
* @constant 42
|
||||
*/
|
||||
SQLITE_FCNTL_RESET_CACHE: number;
|
||||
};
|
||||
const SQLITE_FCNTL_RESET_CACHE: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* The native module implementing the sqlite3 C bindings
|
||||
|
||||
765
packages/bun-types/test.d.ts
vendored
765
packages/bun-types/test.d.ts
vendored
@@ -29,11 +29,14 @@ declare module "bun:test" {
|
||||
*
|
||||
* This is useful for mocking modules.
|
||||
*
|
||||
* If the module is already loaded, exports are overwritten with the return
|
||||
* value of `factory`. If the export didn't exist before, it will not be
|
||||
* added to existing import statements. This is due to how ESM works.
|
||||
*
|
||||
* @param id module ID to mock
|
||||
* @param factory a function returning an object that will be used as the exports of the mocked module
|
||||
*
|
||||
* @example
|
||||
* ## Example
|
||||
* ```ts
|
||||
* import { mock } from "bun:test";
|
||||
*
|
||||
@@ -47,12 +50,6 @@ declare module "bun:test" {
|
||||
*
|
||||
* console.log(await readFile("hello.txt", "utf8")); // hello world
|
||||
* ```
|
||||
*
|
||||
* ## More notes
|
||||
*
|
||||
* If the module is already loaded, exports are overwritten with the return
|
||||
* value of `factory`. If the export didn't exist before, it will not be
|
||||
* added to existing import statements. This is due to how ESM works.
|
||||
*/
|
||||
module(id: string, factory: () => any): void | Promise<void>;
|
||||
/**
|
||||
@@ -155,6 +152,8 @@ declare module "bun:test" {
|
||||
readonly name: string;
|
||||
}
|
||||
|
||||
type DescribeLabel = number | string | Function | FunctionLike;
|
||||
|
||||
/**
|
||||
* Describes a group of related tests.
|
||||
*
|
||||
@@ -176,28 +175,28 @@ declare module "bun:test" {
|
||||
export interface Describe {
|
||||
(fn: () => void): void;
|
||||
|
||||
(label: number | string | Function | FunctionLike, fn: () => void): void;
|
||||
(label: DescribeLabel, fn: () => void): void;
|
||||
/**
|
||||
* Skips all other tests, except this group of tests.
|
||||
*
|
||||
* @param label the label for the tests
|
||||
* @param fn the function that defines the tests
|
||||
*/
|
||||
only(label: string, fn: () => void): void;
|
||||
only(label: DescribeLabel, fn: () => void): void;
|
||||
/**
|
||||
* Skips this group of tests.
|
||||
*
|
||||
* @param label the label for the tests
|
||||
* @param fn the function that defines the tests
|
||||
*/
|
||||
skip(label: string, fn: () => void): void;
|
||||
skip(label: DescribeLabel, fn: () => void): void;
|
||||
/**
|
||||
* Marks this group of tests as to be written or to be fixed.
|
||||
*
|
||||
* @param label the label for the tests
|
||||
* @param fn the function that defines the tests
|
||||
*/
|
||||
todo(label: string, fn?: () => void): void;
|
||||
todo(label: DescribeLabel, fn?: () => void): void;
|
||||
/**
|
||||
* Runs this group of tests, only if `condition` is true.
|
||||
*
|
||||
@@ -205,19 +204,19 @@ declare module "bun:test" {
|
||||
*
|
||||
* @param condition if these tests should run
|
||||
*/
|
||||
if(condition: boolean): (label: string, fn: () => void) => void;
|
||||
if(condition: boolean): (label: DescribeLabel, fn: () => void) => void;
|
||||
/**
|
||||
* Skips this group of tests, if `condition` is true.
|
||||
*
|
||||
* @param condition if these tests should be skipped
|
||||
*/
|
||||
skipIf(condition: boolean): (label: string, fn: () => void) => void;
|
||||
skipIf(condition: boolean): (label: DescribeLabel, fn: () => void) => void;
|
||||
/**
|
||||
* Marks this group of tests as to be written or to be fixed, if `condition` is true.
|
||||
*
|
||||
* @param condition if these tests should be skipped
|
||||
*/
|
||||
todoIf(condition: boolean): (label: string, fn: () => void) => void;
|
||||
todoIf(condition: boolean): (label: DescribeLabel, fn: () => void) => void;
|
||||
/**
|
||||
* Returns a function that runs for each item in `table`.
|
||||
*
|
||||
@@ -225,13 +224,17 @@ declare module "bun:test" {
|
||||
*/
|
||||
each<T extends Readonly<[any, ...any[]]>>(
|
||||
table: readonly T[],
|
||||
): (label: string, fn: (...args: [...T]) => void | Promise<unknown>, options?: number | TestOptions) => void;
|
||||
): (label: DescribeLabel, fn: (...args: [...T]) => void | Promise<unknown>, options?: number | TestOptions) => void;
|
||||
each<T extends any[]>(
|
||||
table: readonly T[],
|
||||
): (label: string, fn: (...args: Readonly<T>) => void | Promise<unknown>, options?: number | TestOptions) => void;
|
||||
): (
|
||||
label: DescribeLabel,
|
||||
fn: (...args: Readonly<T>) => void | Promise<unknown>,
|
||||
options?: number | TestOptions,
|
||||
) => void;
|
||||
each<T>(
|
||||
table: T[],
|
||||
): (label: string, fn: (...args: T[]) => void | Promise<unknown>, options?: number | TestOptions) => void;
|
||||
): (label: DescribeLabel, fn: (...args: T[]) => void | Promise<unknown>, options?: number | TestOptions) => void;
|
||||
}
|
||||
/**
|
||||
* Describes a group of related tests.
|
||||
@@ -593,8 +596,6 @@ declare module "bun:test" {
|
||||
* @returns never
|
||||
*
|
||||
* @example
|
||||
* ## Example
|
||||
*
|
||||
* ```ts
|
||||
* import { expect, test } from "bun:test";
|
||||
*
|
||||
@@ -1786,367 +1787,329 @@ declare module "bun:test" {
|
||||
}
|
||||
|
||||
type MatcherContext = MatcherUtils & MatcherState;
|
||||
}
|
||||
|
||||
declare namespace JestMock {
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
export interface ClassLike {
|
||||
new (...args: any): any;
|
||||
}
|
||||
|
||||
export type ConstructorLikeKeys<T> = keyof {
|
||||
[K in keyof T as Required<T>[K] extends ClassLike ? K : never]: T[K];
|
||||
};
|
||||
|
||||
// export const fn: <T extends FunctionLike = UnknownFunction>(
|
||||
// implementation?: T | undefined,
|
||||
// ) => Mock<T>;
|
||||
|
||||
export type FunctionLike = (...args: any) => any;
|
||||
|
||||
export type MethodLikeKeys<T> = keyof {
|
||||
[K in keyof T as Required<T>[K] extends FunctionLike ? K : never]: T[K];
|
||||
};
|
||||
|
||||
export interface Mock<T extends (...args: any[]) => any> extends MockInstance<T> {
|
||||
(...args: Parameters<T>): ReturnType<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* All what the internal typings need is to be sure that we have any-function.
|
||||
* `FunctionLike` type ensures that and helps to constrain the type as well.
|
||||
* The default of `UnknownFunction` makes sure that `any`s do not leak to the
|
||||
* user side. For instance, calling `fn()` without implementation will return
|
||||
* a mock of `(...args: Array<unknown>) => unknown` type. If implementation
|
||||
* is provided, its typings are inferred correctly.
|
||||
*/
|
||||
// export interface Mock<T extends FunctionLike = UnknownFunction>
|
||||
// extends Function,
|
||||
// MockInstance<T> {
|
||||
// new (...args: Parameters<T>): ReturnType<T>;
|
||||
// (...args: Parameters<T>): ReturnType<T>;
|
||||
// }
|
||||
|
||||
// export type Mocked<T> = T extends ClassLike
|
||||
// ? MockedClass<T>
|
||||
// : T extends FunctionLike
|
||||
// ? MockedFunction<T>
|
||||
// : T extends object
|
||||
// ? MockedObject<T>
|
||||
// : T;
|
||||
|
||||
// export const mocked: {
|
||||
// <T extends object>(
|
||||
// source: T,
|
||||
// options?: {
|
||||
// shallow: false;
|
||||
// },
|
||||
// ): Mocked<T>;
|
||||
// <T_1 extends object>(
|
||||
// source: T_1,
|
||||
// options: {
|
||||
// shallow: true;
|
||||
// },
|
||||
// ): MockedShallow<T_1>;
|
||||
// };
|
||||
|
||||
// export type MockedClass<T extends ClassLike> = MockInstance<
|
||||
// (...args: ConstructorParameters<T>) => Mocked<InstanceType<T>>
|
||||
// > &
|
||||
// MockedObject<T>;
|
||||
|
||||
// export type MockedFunction<T extends FunctionLike> = MockInstance<T> &
|
||||
// MockedObject<T>;
|
||||
|
||||
// type MockedFunctionShallow<T extends FunctionLike> = MockInstance<T> & T;
|
||||
|
||||
// export type MockedObject<T extends object> = {
|
||||
// [K in keyof T]: T[K] extends ClassLike
|
||||
// ? MockedClass<T[K]>
|
||||
// : T[K] extends FunctionLike
|
||||
// ? MockedFunction<T[K]>
|
||||
// : T[K] extends object
|
||||
// ? MockedObject<T[K]>
|
||||
// : T[K];
|
||||
// } & T;
|
||||
|
||||
// type MockedObjectShallow<T extends object> = {
|
||||
// [K in keyof T]: T[K] extends ClassLike
|
||||
// ? MockedClass<T[K]>
|
||||
// : T[K] extends FunctionLike
|
||||
// ? MockedFunctionShallow<T[K]>
|
||||
// : T[K];
|
||||
// } & T;
|
||||
|
||||
// export type MockedShallow<T> = T extends ClassLike
|
||||
// ? MockedClass<T>
|
||||
// : T extends FunctionLike
|
||||
// ? MockedFunctionShallow<T>
|
||||
// : T extends object
|
||||
// ? MockedObjectShallow<T>
|
||||
// : T;
|
||||
|
||||
// export type MockFunctionMetadata<
|
||||
// T = unknown,
|
||||
// MetadataType = MockMetadataType,
|
||||
// > = MockMetadata<T, MetadataType>;
|
||||
|
||||
// export type MockFunctionMetadataType = MockMetadataType;
|
||||
|
||||
type MockFunctionResult<T extends FunctionLike = UnknownFunction> =
|
||||
| MockFunctionResultIncomplete
|
||||
| MockFunctionResultReturn<T>
|
||||
| MockFunctionResultThrow;
|
||||
|
||||
interface MockFunctionResultIncomplete {
|
||||
type: "incomplete";
|
||||
namespace JestMock {
|
||||
/**
|
||||
* Result of a single call to a mock function that has not yet completed.
|
||||
* This occurs if you test the result from within the mock function itself,
|
||||
* or from within a function that was called by the mock.
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
value: undefined;
|
||||
}
|
||||
export interface ClassLike {
|
||||
new (...args: any): any;
|
||||
}
|
||||
|
||||
export type ConstructorLikeKeys<T> = keyof {
|
||||
[K in keyof T as Required<T>[K] extends ClassLike ? K : never]: T[K];
|
||||
};
|
||||
|
||||
// export const fn: <T extends FunctionLike = UnknownFunction>(
|
||||
// implementation?: T | undefined,
|
||||
// ) => Mock<T>;
|
||||
|
||||
export type FunctionLike = (...args: any) => any;
|
||||
|
||||
export type MethodLikeKeys<T> = keyof {
|
||||
[K in keyof T as Required<T>[K] extends FunctionLike ? K : never]: T[K];
|
||||
};
|
||||
|
||||
export interface Mock<T extends (...args: any[]) => any> extends MockInstance<T> {
|
||||
(...args: Parameters<T>): ReturnType<T>;
|
||||
}
|
||||
|
||||
interface MockFunctionResultReturn<T extends FunctionLike = UnknownFunction> {
|
||||
type: "return";
|
||||
/**
|
||||
* Result of a single call to a mock function that returned.
|
||||
* All what the internal typings need is to be sure that we have any-function.
|
||||
* `FunctionLike` type ensures that and helps to constrain the type as well.
|
||||
* The default of `UnknownFunction` makes sure that `any`s do not leak to the
|
||||
* user side. For instance, calling `fn()` without implementation will return
|
||||
* a mock of `(...args: Array<unknown>) => unknown` type. If implementation
|
||||
* is provided, its typings are inferred correctly.
|
||||
*/
|
||||
value: ReturnType<T>;
|
||||
}
|
||||
// export interface Mock<T extends FunctionLike = UnknownFunction>
|
||||
// extends Function,
|
||||
// MockInstance<T> {
|
||||
// new (...args: Parameters<T>): ReturnType<T>;
|
||||
// (...args: Parameters<T>): ReturnType<T>;
|
||||
// }
|
||||
|
||||
interface MockFunctionResultThrow {
|
||||
type: "throw";
|
||||
/**
|
||||
* Result of a single call to a mock function that threw.
|
||||
*/
|
||||
value: unknown;
|
||||
}
|
||||
// export type Mocked<T> = T extends ClassLike
|
||||
// ? MockedClass<T>
|
||||
// : T extends FunctionLike
|
||||
// ? MockedFunction<T>
|
||||
// : T extends object
|
||||
// ? MockedObject<T>
|
||||
// : T;
|
||||
|
||||
interface MockFunctionState<T extends FunctionLike = FunctionLike> {
|
||||
/**
|
||||
* List of the call arguments of all calls that have been made to the mock.
|
||||
*/
|
||||
calls: Array<Parameters<T>>;
|
||||
/**
|
||||
* List of all the object instances that have been instantiated from the mock.
|
||||
*/
|
||||
instances: Array<ReturnType<T>>;
|
||||
/**
|
||||
* List of all the function contexts that have been applied to calls to the mock.
|
||||
*/
|
||||
contexts: Array<ThisParameterType<T>>;
|
||||
/**
|
||||
* List of the call order indexes of the mock. Jest is indexing the order of
|
||||
* invocations of all mocks in a test file. The index is starting with `1`.
|
||||
*/
|
||||
invocationCallOrder: number[];
|
||||
/**
|
||||
* List of the call arguments of the last call that was made to the mock.
|
||||
* If the function was not called, it will return `undefined`.
|
||||
*/
|
||||
lastCall?: Parameters<T>;
|
||||
/**
|
||||
* List of the results of all calls that have been made to the mock.
|
||||
*/
|
||||
results: Array<MockFunctionResult<T>>;
|
||||
}
|
||||
// export const mocked: {
|
||||
// <T extends object>(
|
||||
// source: T,
|
||||
// options?: {
|
||||
// shallow: false;
|
||||
// },
|
||||
// ): Mocked<T>;
|
||||
// <T_1 extends object>(
|
||||
// source: T_1,
|
||||
// options: {
|
||||
// shallow: true;
|
||||
// },
|
||||
// ): MockedShallow<T_1>;
|
||||
// };
|
||||
|
||||
export interface MockInstance<T extends FunctionLike = UnknownFunction> {
|
||||
_isMockFunction: true;
|
||||
_protoImpl: Function;
|
||||
getMockImplementation(): T | undefined;
|
||||
getMockName(): string;
|
||||
mock: MockFunctionState<T>;
|
||||
mockClear(): this;
|
||||
mockReset(): this;
|
||||
mockRestore(): void;
|
||||
mockImplementation(fn: T): this;
|
||||
mockImplementationOnce(fn: T): this;
|
||||
withImplementation(fn: T, callback: () => Promise<unknown>): Promise<void>;
|
||||
withImplementation(fn: T, callback: () => void): void;
|
||||
mockName(name: string): this;
|
||||
mockReturnThis(): this;
|
||||
mockReturnValue(value: ReturnType<T>): this;
|
||||
mockReturnValueOnce(value: ReturnType<T>): this;
|
||||
mockResolvedValue(value: ResolveType<T>): this;
|
||||
mockResolvedValueOnce(value: ResolveType<T>): this;
|
||||
mockRejectedValue(value: RejectType<T>): this;
|
||||
mockRejectedValueOnce(value: RejectType<T>): this;
|
||||
}
|
||||
// export type MockedClass<T extends ClassLike> = MockInstance<
|
||||
// (...args: ConstructorParameters<T>) => Mocked<InstanceType<T>>
|
||||
// > &
|
||||
// MockedObject<T>;
|
||||
|
||||
// export type MockMetadata<T, MetadataType = MockMetadataType> = {
|
||||
// ref?: number;
|
||||
// members?: Record<string, MockMetadata<T>>;
|
||||
// mockImpl?: T;
|
||||
// name?: string;
|
||||
// refID?: number;
|
||||
// type?: MetadataType;
|
||||
// value?: T;
|
||||
// length?: number;
|
||||
// };
|
||||
// export type MockedFunction<T extends FunctionLike> = MockInstance<T> &
|
||||
// MockedObject<T>;
|
||||
|
||||
// export type MockMetadataType =
|
||||
// | "object"
|
||||
// | "array"
|
||||
// | "regexp"
|
||||
// | "function"
|
||||
// | "constant"
|
||||
// | "collection"
|
||||
// | "null"
|
||||
// | "undefined";
|
||||
// type MockedFunctionShallow<T extends FunctionLike> = MockInstance<T> & T;
|
||||
|
||||
// export class ModuleMocker {
|
||||
// private readonly _environmentGlobal;
|
||||
// private _mockState;
|
||||
// private _mockConfigRegistry;
|
||||
// private _spyState;
|
||||
// private _invocationCallCounter;
|
||||
// /**
|
||||
// * @see README.md
|
||||
// * @param global Global object of the test environment, used to create
|
||||
// * mocks
|
||||
// */
|
||||
// constructor(global: typeof globalThis);
|
||||
// private _getSlots;
|
||||
// private _ensureMockConfig;
|
||||
// private _ensureMockState;
|
||||
// private _defaultMockConfig;
|
||||
// private _defaultMockState;
|
||||
// private _makeComponent;
|
||||
// private _createMockFunction;
|
||||
// private _generateMock;
|
||||
// /**
|
||||
// * Check whether the given property of an object has been already replaced.
|
||||
// */
|
||||
// private _findReplacedProperty;
|
||||
// /**
|
||||
// * @see README.md
|
||||
// * @param metadata Metadata for the mock in the schema returned by the
|
||||
// * getMetadata method of this module.
|
||||
// */
|
||||
// generateFromMetadata<T>(metadata: MockMetadata<T>): Mocked<T>;
|
||||
// /**
|
||||
// * @see README.md
|
||||
// * @param component The component for which to retrieve metadata.
|
||||
// */
|
||||
// getMetadata<T = unknown>(
|
||||
// component: T,
|
||||
// _refs?: Map<T, number>,
|
||||
// ): MockMetadata<T> | null;
|
||||
// isMockFunction<T extends FunctionLike = UnknownFunction>(
|
||||
// fn: MockInstance<T>,
|
||||
// ): fn is MockInstance<T>;
|
||||
// isMockFunction<P extends Array<unknown>, R>(
|
||||
// fn: (...args: P) => R,
|
||||
// ): fn is Mock<(...args: P) => R>;
|
||||
// isMockFunction(fn: unknown): fn is Mock<UnknownFunction>;
|
||||
// fn<T extends FunctionLike = UnknownFunction>(implementation?: T): Mock<T>;
|
||||
// private _attachMockImplementation;
|
||||
// spyOn<
|
||||
// T extends object,
|
||||
// K extends PropertyLikeKeys<T>,
|
||||
// A extends "get" | "set",
|
||||
// >(
|
||||
// object: T,
|
||||
// methodKey: K,
|
||||
// accessType: A,
|
||||
// ): A extends "get"
|
||||
// ? SpiedGetter<T[K]>
|
||||
// : A extends "set"
|
||||
// ? SpiedSetter<T[K]>
|
||||
// : never;
|
||||
// spyOn<
|
||||
// T extends object,
|
||||
// K extends ConstructorLikeKeys<T> | MethodLikeKeys<T>,
|
||||
// V extends Required<T>[K],
|
||||
// >(
|
||||
// object: T,
|
||||
// methodKey: K,
|
||||
// ): V extends ClassLike | FunctionLike ? Spied<V> : never;
|
||||
// private _spyOnProperty;
|
||||
// replaceProperty<
|
||||
// T extends object,
|
||||
// K extends PropertyLikeKeys<T>,
|
||||
// V extends T[K],
|
||||
// >(object: T, propertyKey: K, value: V): Replaced<T[K]>;
|
||||
// clearAllMocks(): void;
|
||||
// resetAllMocks(): void;
|
||||
// restoreAllMocks(): void;
|
||||
// private _typeOf;
|
||||
// mocked<T extends object>(
|
||||
// source: T,
|
||||
// options?: {
|
||||
// shallow: false;
|
||||
// },
|
||||
// ): Mocked<T>;
|
||||
// mocked<T extends object>(
|
||||
// source: T,
|
||||
// options: {
|
||||
// shallow: true;
|
||||
// },
|
||||
// ): MockedShallow<T>;
|
||||
// }
|
||||
// export type MockedObject<T extends object> = {
|
||||
// [K in keyof T]: T[K] extends ClassLike
|
||||
// ? MockedClass<T[K]>
|
||||
// : T[K] extends FunctionLike
|
||||
// ? MockedFunction<T[K]>
|
||||
// : T[K] extends object
|
||||
// ? MockedObject<T[K]>
|
||||
// : T[K];
|
||||
// } & T;
|
||||
|
||||
export type PropertyLikeKeys<T> = Exclude<keyof T, ConstructorLikeKeys<T> | MethodLikeKeys<T>>;
|
||||
// type MockedObjectShallow<T extends object> = {
|
||||
// [K in keyof T]: T[K] extends ClassLike
|
||||
// ? MockedClass<T[K]>
|
||||
// : T[K] extends FunctionLike
|
||||
// ? MockedFunctionShallow<T[K]>
|
||||
// : T[K];
|
||||
// } & T;
|
||||
|
||||
export type RejectType<T extends FunctionLike> = ReturnType<T> extends PromiseLike<any> ? unknown : never;
|
||||
// export type MockedShallow<T> = T extends ClassLike
|
||||
// ? MockedClass<T>
|
||||
// : T extends FunctionLike
|
||||
// ? MockedFunctionShallow<T>
|
||||
// : T extends object
|
||||
// ? MockedObjectShallow<T>
|
||||
// : T;
|
||||
|
||||
export interface Replaced<T = unknown> {
|
||||
/**
|
||||
* Restore property to its original value known at the time of mocking.
|
||||
*/
|
||||
restore(): void;
|
||||
/**
|
||||
* Change the value of the property.
|
||||
*/
|
||||
replaceValue(value: T): this;
|
||||
}
|
||||
// export type MockFunctionMetadata<
|
||||
// T = unknown,
|
||||
// MetadataType = MockMetadataType,
|
||||
// > = MockMetadata<T, MetadataType>;
|
||||
|
||||
export function replaceProperty<
|
||||
T extends object,
|
||||
K_2 extends Exclude<
|
||||
keyof T,
|
||||
| keyof {
|
||||
[K in keyof T as Required<T>[K] extends ClassLike ? K : never]: T[K];
|
||||
}
|
||||
| keyof {
|
||||
[K_1 in keyof T as Required<T>[K_1] extends FunctionLike ? K_1 : never]: T[K_1];
|
||||
}
|
||||
>,
|
||||
V extends T[K_2],
|
||||
>(object: T, propertyKey: K_2, value: V): Replaced<T[K_2]>;
|
||||
// export type MockFunctionMetadataType = MockMetadataType;
|
||||
|
||||
export type ResolveType<T extends FunctionLike> = ReturnType<T> extends PromiseLike<infer U> ? U : never;
|
||||
type MockFunctionResult<T extends FunctionLike = UnknownFunction> =
|
||||
| MockFunctionResultIncomplete
|
||||
| MockFunctionResultReturn<T>
|
||||
| MockFunctionResultThrow;
|
||||
|
||||
export type Spied<T extends ClassLike | FunctionLike> = T extends ClassLike
|
||||
? SpiedClass<T>
|
||||
: T extends FunctionLike
|
||||
? SpiedFunction<T>
|
||||
: never;
|
||||
interface MockFunctionResultIncomplete {
|
||||
type: "incomplete";
|
||||
/**
|
||||
* Result of a single call to a mock function that has not yet completed.
|
||||
* This occurs if you test the result from within the mock function itself,
|
||||
* or from within a function that was called by the mock.
|
||||
*/
|
||||
value: undefined;
|
||||
}
|
||||
|
||||
export type SpiedClass<T extends ClassLike = UnknownClass> = MockInstance<
|
||||
(...args: ConstructorParameters<T>) => InstanceType<T>
|
||||
>;
|
||||
interface MockFunctionResultReturn<T extends FunctionLike = UnknownFunction> {
|
||||
type: "return";
|
||||
/**
|
||||
* Result of a single call to a mock function that returned.
|
||||
*/
|
||||
value: ReturnType<T>;
|
||||
}
|
||||
|
||||
export type SpiedFunction<T extends FunctionLike = UnknownFunction> = MockInstance<
|
||||
(...args: Parameters<T>) => ReturnType<T>
|
||||
>;
|
||||
interface MockFunctionResultThrow {
|
||||
type: "throw";
|
||||
/**
|
||||
* Result of a single call to a mock function that threw.
|
||||
*/
|
||||
value: unknown;
|
||||
}
|
||||
|
||||
export type SpiedGetter<T> = MockInstance<() => T>;
|
||||
interface MockFunctionState<T extends FunctionLike = FunctionLike> {
|
||||
/**
|
||||
* List of the call arguments of all calls that have been made to the mock.
|
||||
*/
|
||||
calls: Array<Parameters<T>>;
|
||||
/**
|
||||
* List of all the object instances that have been instantiated from the mock.
|
||||
*/
|
||||
instances: Array<ReturnType<T>>;
|
||||
/**
|
||||
* List of all the function contexts that have been applied to calls to the mock.
|
||||
*/
|
||||
contexts: Array<ThisParameterType<T>>;
|
||||
/**
|
||||
* List of the call order indexes of the mock. Jest is indexing the order of
|
||||
* invocations of all mocks in a test file. The index is starting with `1`.
|
||||
*/
|
||||
invocationCallOrder: number[];
|
||||
/**
|
||||
* List of the call arguments of the last call that was made to the mock.
|
||||
* If the function was not called, it will return `undefined`.
|
||||
*/
|
||||
lastCall?: Parameters<T>;
|
||||
/**
|
||||
* List of the results of all calls that have been made to the mock.
|
||||
*/
|
||||
results: Array<MockFunctionResult<T>>;
|
||||
}
|
||||
|
||||
export type SpiedSetter<T> = MockInstance<(arg: T) => void>;
|
||||
export interface MockInstance<T extends FunctionLike = UnknownFunction> {
|
||||
_isMockFunction: true;
|
||||
_protoImpl: Function;
|
||||
getMockImplementation(): T | undefined;
|
||||
getMockName(): string;
|
||||
mock: MockFunctionState<T>;
|
||||
mockClear(): this;
|
||||
mockReset(): this;
|
||||
mockRestore(): void;
|
||||
mockImplementation(fn: T): this;
|
||||
mockImplementationOnce(fn: T): this;
|
||||
withImplementation(fn: T, callback: () => Promise<unknown>): Promise<void>;
|
||||
withImplementation(fn: T, callback: () => void): void;
|
||||
mockName(name: string): this;
|
||||
mockReturnThis(): this;
|
||||
mockReturnValue(value: ReturnType<T>): this;
|
||||
mockReturnValueOnce(value: ReturnType<T>): this;
|
||||
mockResolvedValue(value: ResolveType<T>): this;
|
||||
mockResolvedValueOnce(value: ResolveType<T>): this;
|
||||
mockRejectedValue(value: RejectType<T>): this;
|
||||
mockRejectedValueOnce(value: RejectType<T>): this;
|
||||
}
|
||||
|
||||
export interface SpyInstance<T extends FunctionLike = UnknownFunction> extends MockInstance<T> {}
|
||||
// export type MockMetadata<T, MetadataType = MockMetadataType> = {
|
||||
// ref?: number;
|
||||
// members?: Record<string, MockMetadata<T>>;
|
||||
// mockImpl?: T;
|
||||
// name?: string;
|
||||
// refID?: number;
|
||||
// type?: MetadataType;
|
||||
// value?: T;
|
||||
// length?: number;
|
||||
// };
|
||||
|
||||
export const spyOn: {
|
||||
<
|
||||
// export type MockMetadataType =
|
||||
// | "object"
|
||||
// | "array"
|
||||
// | "regexp"
|
||||
// | "function"
|
||||
// | "constant"
|
||||
// | "collection"
|
||||
// | "null"
|
||||
// | "undefined";
|
||||
|
||||
// export class ModuleMocker {
|
||||
// private readonly _environmentGlobal;
|
||||
// private _mockState;
|
||||
// private _mockConfigRegistry;
|
||||
// private _spyState;
|
||||
// private _invocationCallCounter;
|
||||
// /**
|
||||
// * @see README.md
|
||||
// * @param global Global object of the test environment, used to create
|
||||
// * mocks
|
||||
// */
|
||||
// constructor(global: typeof globalThis);
|
||||
// private _getSlots;
|
||||
// private _ensureMockConfig;
|
||||
// private _ensureMockState;
|
||||
// private _defaultMockConfig;
|
||||
// private _defaultMockState;
|
||||
// private _makeComponent;
|
||||
// private _createMockFunction;
|
||||
// private _generateMock;
|
||||
// /**
|
||||
// * Check whether the given property of an object has been already replaced.
|
||||
// */
|
||||
// private _findReplacedProperty;
|
||||
// /**
|
||||
// * @see README.md
|
||||
// * @param metadata Metadata for the mock in the schema returned by the
|
||||
// * getMetadata method of this module.
|
||||
// */
|
||||
// generateFromMetadata<T>(metadata: MockMetadata<T>): Mocked<T>;
|
||||
// /**
|
||||
// * @see README.md
|
||||
// * @param component The component for which to retrieve metadata.
|
||||
// */
|
||||
// getMetadata<T = unknown>(
|
||||
// component: T,
|
||||
// _refs?: Map<T, number>,
|
||||
// ): MockMetadata<T> | null;
|
||||
// isMockFunction<T extends FunctionLike = UnknownFunction>(
|
||||
// fn: MockInstance<T>,
|
||||
// ): fn is MockInstance<T>;
|
||||
// isMockFunction<P extends Array<unknown>, R>(
|
||||
// fn: (...args: P) => R,
|
||||
// ): fn is Mock<(...args: P) => R>;
|
||||
// isMockFunction(fn: unknown): fn is Mock<UnknownFunction>;
|
||||
// fn<T extends FunctionLike = UnknownFunction>(implementation?: T): Mock<T>;
|
||||
// private _attachMockImplementation;
|
||||
// spyOn<
|
||||
// T extends object,
|
||||
// K extends PropertyLikeKeys<T>,
|
||||
// A extends "get" | "set",
|
||||
// >(
|
||||
// object: T,
|
||||
// methodKey: K,
|
||||
// accessType: A,
|
||||
// ): A extends "get"
|
||||
// ? SpiedGetter<T[K]>
|
||||
// : A extends "set"
|
||||
// ? SpiedSetter<T[K]>
|
||||
// : never;
|
||||
// spyOn<
|
||||
// T extends object,
|
||||
// K extends ConstructorLikeKeys<T> | MethodLikeKeys<T>,
|
||||
// V extends Required<T>[K],
|
||||
// >(
|
||||
// object: T,
|
||||
// methodKey: K,
|
||||
// ): V extends ClassLike | FunctionLike ? Spied<V> : never;
|
||||
// private _spyOnProperty;
|
||||
// replaceProperty<
|
||||
// T extends object,
|
||||
// K extends PropertyLikeKeys<T>,
|
||||
// V extends T[K],
|
||||
// >(object: T, propertyKey: K, value: V): Replaced<T[K]>;
|
||||
// clearAllMocks(): void;
|
||||
// resetAllMocks(): void;
|
||||
// restoreAllMocks(): void;
|
||||
// private _typeOf;
|
||||
// mocked<T extends object>(
|
||||
// source: T,
|
||||
// options?: {
|
||||
// shallow: false;
|
||||
// },
|
||||
// ): Mocked<T>;
|
||||
// mocked<T extends object>(
|
||||
// source: T,
|
||||
// options: {
|
||||
// shallow: true;
|
||||
// },
|
||||
// ): MockedShallow<T>;
|
||||
// }
|
||||
|
||||
export type PropertyLikeKeys<T> = Exclude<keyof T, ConstructorLikeKeys<T> | MethodLikeKeys<T>>;
|
||||
|
||||
export type RejectType<T extends FunctionLike> = ReturnType<T> extends PromiseLike<any> ? unknown : never;
|
||||
|
||||
export interface Replaced<T = unknown> {
|
||||
/**
|
||||
* Restore property to its original value known at the time of mocking.
|
||||
*/
|
||||
restore(): void;
|
||||
/**
|
||||
* Change the value of the property.
|
||||
*/
|
||||
replaceValue(value: T): this;
|
||||
}
|
||||
|
||||
export function replaceProperty<
|
||||
T extends object,
|
||||
K_2 extends Exclude<
|
||||
keyof T,
|
||||
@@ -2157,32 +2120,70 @@ declare namespace JestMock {
|
||||
[K_1 in keyof T as Required<T>[K_1] extends FunctionLike ? K_1 : never]: T[K_1];
|
||||
}
|
||||
>,
|
||||
V extends Required<T>[K_2],
|
||||
A extends "set" | "get",
|
||||
>(
|
||||
object: T,
|
||||
methodKey: K_2,
|
||||
accessType: A,
|
||||
): A extends "get" ? SpiedGetter<V> : A extends "set" ? SpiedSetter<V> : never;
|
||||
<
|
||||
T_1 extends object,
|
||||
K_5 extends
|
||||
| keyof {
|
||||
[K_3 in keyof T_1 as Required<T_1>[K_3] extends ClassLike ? K_3 : never]: T_1[K_3];
|
||||
}
|
||||
| keyof {
|
||||
[K_4 in keyof T_1 as Required<T_1>[K_4] extends FunctionLike ? K_4 : never]: T_1[K_4];
|
||||
},
|
||||
V_1 extends Required<T_1>[K_5],
|
||||
>(
|
||||
object: T_1,
|
||||
methodKey: K_5,
|
||||
): V_1 extends ClassLike | FunctionLike ? Spied<V_1> : never;
|
||||
};
|
||||
V extends T[K_2],
|
||||
>(object: T, propertyKey: K_2, value: V): Replaced<T[K_2]>;
|
||||
|
||||
export interface UnknownClass {
|
||||
new (...args: unknown[]): unknown;
|
||||
export type ResolveType<T extends FunctionLike> = ReturnType<T> extends PromiseLike<infer U> ? U : never;
|
||||
|
||||
export type Spied<T extends ClassLike | FunctionLike> = T extends ClassLike
|
||||
? SpiedClass<T>
|
||||
: T extends FunctionLike
|
||||
? SpiedFunction<T>
|
||||
: never;
|
||||
|
||||
export type SpiedClass<T extends ClassLike = UnknownClass> = MockInstance<
|
||||
(...args: ConstructorParameters<T>) => InstanceType<T>
|
||||
>;
|
||||
|
||||
export type SpiedFunction<T extends FunctionLike = UnknownFunction> = MockInstance<
|
||||
(...args: Parameters<T>) => ReturnType<T>
|
||||
>;
|
||||
|
||||
export type SpiedGetter<T> = MockInstance<() => T>;
|
||||
|
||||
export type SpiedSetter<T> = MockInstance<(arg: T) => void>;
|
||||
|
||||
export interface SpyInstance<T extends FunctionLike = UnknownFunction> extends MockInstance<T> {}
|
||||
|
||||
export const spyOn: {
|
||||
<
|
||||
T extends object,
|
||||
K_2 extends Exclude<
|
||||
keyof T,
|
||||
| keyof {
|
||||
[K in keyof T as Required<T>[K] extends ClassLike ? K : never]: T[K];
|
||||
}
|
||||
| keyof {
|
||||
[K_1 in keyof T as Required<T>[K_1] extends FunctionLike ? K_1 : never]: T[K_1];
|
||||
}
|
||||
>,
|
||||
V extends Required<T>[K_2],
|
||||
A extends "set" | "get",
|
||||
>(
|
||||
object: T,
|
||||
methodKey: K_2,
|
||||
accessType: A,
|
||||
): A extends "get" ? SpiedGetter<V> : A extends "set" ? SpiedSetter<V> : never;
|
||||
<
|
||||
T_1 extends object,
|
||||
K_5 extends
|
||||
| keyof {
|
||||
[K_3 in keyof T_1 as Required<T_1>[K_3] extends ClassLike ? K_3 : never]: T_1[K_3];
|
||||
}
|
||||
| keyof {
|
||||
[K_4 in keyof T_1 as Required<T_1>[K_4] extends FunctionLike ? K_4 : never]: T_1[K_4];
|
||||
},
|
||||
V_1 extends Required<T_1>[K_5],
|
||||
>(
|
||||
object: T_1,
|
||||
methodKey: K_5,
|
||||
): V_1 extends ClassLike | FunctionLike ? Spied<V_1> : never;
|
||||
};
|
||||
|
||||
export interface UnknownClass {
|
||||
new (...args: unknown[]): unknown;
|
||||
}
|
||||
|
||||
export type UnknownFunction = (...args: unknown[]) => unknown;
|
||||
}
|
||||
|
||||
export type UnknownFunction = (...args: unknown[]) => unknown;
|
||||
}
|
||||
|
||||
@@ -1617,7 +1617,7 @@ struct us_socket_t *us_internal_ssl_socket_context_connect(
|
||||
2, &context->sc, host, port, options,
|
||||
sizeof(struct us_internal_ssl_socket_t) - sizeof(struct us_socket_t) +
|
||||
socket_ext_size, is_connecting);
|
||||
if (*is_connecting) {
|
||||
if (*is_connecting && s) {
|
||||
us_internal_zero_ssl_data_for_connected_socket_before_onopen(s);
|
||||
}
|
||||
|
||||
|
||||
@@ -614,13 +614,22 @@ public:
|
||||
httpContext->getSocketContextData()->onSocketClosed = onClose;
|
||||
}
|
||||
|
||||
void setOnClientError(HttpContextData<SSL>::OnClientErrorCallback onClientError) {
|
||||
httpContext->getSocketContextData()->onClientError = std::move(onClientError);
|
||||
}
|
||||
|
||||
TemplatedApp &&run() {
|
||||
uWS::run();
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
TemplatedApp &&setUsingCustomExpectHandler(bool value) {
|
||||
httpContext->getSocketContextData()->usingCustomExpectHandler = value;
|
||||
httpContext->getSocketContextData()->flags.usingCustomExpectHandler = value;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
TemplatedApp &&setRequireHostHeader(bool value) {
|
||||
httpContext->getSocketContextData()->flags.requireHostHeader = value;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include <string_view>
|
||||
#include <iostream>
|
||||
#include "MoveOnlyFunction.h"
|
||||
|
||||
#include "HttpParser.h"
|
||||
namespace uWS {
|
||||
template<bool> struct HttpResponse;
|
||||
|
||||
@@ -73,13 +73,14 @@ private:
|
||||
// if we are closing or already closed, we don't need to do anything
|
||||
if (!us_socket_is_closed(SSL, s) && !us_socket_is_shut_down(SSL, s)) {
|
||||
HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);
|
||||
|
||||
if(httpContextData->rejectUnauthorized) {
|
||||
httpContextData->flags.isAuthorized = success;
|
||||
if(httpContextData->flags.rejectUnauthorized) {
|
||||
if(!success || verify_error.error != 0) {
|
||||
// we failed to handshake, close the socket
|
||||
us_socket_close(SSL, s, 0, nullptr);
|
||||
return;
|
||||
}
|
||||
httpContextData->flags.isAuthorized = true;
|
||||
}
|
||||
|
||||
/* Any connected socket should timeout until it has a request */
|
||||
@@ -118,8 +119,15 @@ private:
|
||||
/* Get socket ext */
|
||||
auto *httpResponseData = reinterpret_cast<HttpResponseData<SSL> *>(us_socket_ext(SSL, s));
|
||||
|
||||
|
||||
|
||||
/* Call filter */
|
||||
HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);
|
||||
if(httpContextData->flags.isParsingHttp) {
|
||||
if(httpContextData->onClientError) {
|
||||
httpContextData->onClientError(SSL, s,uWS::HTTP_PARSER_ERROR_INVALID_EOF, nullptr, 0);
|
||||
}
|
||||
}
|
||||
for (auto &f : httpContextData->filterHandlers) {
|
||||
f((HttpResponse<SSL> *) s, -1);
|
||||
}
|
||||
@@ -163,7 +171,7 @@ private:
|
||||
((AsyncSocket<SSL> *) s)->cork();
|
||||
|
||||
/* Mark that we are inside the parser now */
|
||||
httpContextData->isParsingHttp = true;
|
||||
httpContextData->flags.isParsingHttp = true;
|
||||
|
||||
// clients need to know the cursor after http parse, not servers!
|
||||
// how far did we read then? we need to know to continue with websocket parsing data? or?
|
||||
@@ -174,7 +182,7 @@ private:
|
||||
#endif
|
||||
|
||||
/* The return value is entirely up to us to interpret. The HttpParser cares only for whether the returned value is DIFFERENT from passed user */
|
||||
auto [err, returnedSocket] = httpResponseData->consumePostPadded(data, (unsigned int) length, s, proxyParser, [httpContextData](void *s, HttpRequest *httpRequest) -> void * {
|
||||
auto [err, parserError, returnedSocket] = httpResponseData->consumePostPadded(httpContextData->flags.requireHostHeader,data, (unsigned int) length, s, proxyParser, [httpContextData](void *s, HttpRequest *httpRequest) -> void * {
|
||||
/* For every request we reset the timeout and hang until user makes action */
|
||||
/* Warning: if we are in shutdown state, resetting the timer is a security issue! */
|
||||
us_socket_timeout(SSL, (us_socket_t *) s, 0);
|
||||
@@ -201,6 +209,7 @@ private:
|
||||
|
||||
httpResponseData->fromAncientRequest = httpRequest->isAncient();
|
||||
|
||||
|
||||
/* Select the router based on SNI (only possible for SSL) */
|
||||
auto *selectedRouter = &httpContextData->router;
|
||||
if constexpr (SSL) {
|
||||
@@ -290,10 +299,12 @@ private:
|
||||
});
|
||||
|
||||
/* Mark that we are no longer parsing Http */
|
||||
httpContextData->isParsingHttp = false;
|
||||
|
||||
httpContextData->flags.isParsingHttp = false;
|
||||
/* If we got fullptr that means the parser wants us to close the socket from error (same as calling the errorHandler) */
|
||||
if (returnedSocket == FULLPTR) {
|
||||
if(httpContextData->onClientError) {
|
||||
httpContextData->onClientError(SSL, s, parserError, data, length);
|
||||
}
|
||||
/* For errors, we only deliver them "at most once". We don't care if they get halfways delivered or not. */
|
||||
us_socket_write(SSL, s, httpErrorResponses[err].data(), (int) httpErrorResponses[err].length(), false);
|
||||
us_socket_shutdown(SSL, s);
|
||||
@@ -467,7 +478,7 @@ public:
|
||||
/* Init socket context data */
|
||||
auto* httpContextData = new ((HttpContextData<SSL> *) us_socket_context_ext(SSL, (us_socket_context_t *) httpContext)) HttpContextData<SSL>();
|
||||
if(options.request_cert && options.reject_unauthorized) {
|
||||
httpContextData->rejectUnauthorized = true;
|
||||
httpContextData->flags.rejectUnauthorized = true;
|
||||
}
|
||||
return httpContext->init();
|
||||
}
|
||||
@@ -515,15 +526,15 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
const bool &customContinue = httpContextData->usingCustomExpectHandler;
|
||||
|
||||
|
||||
httpContextData->currentRouter->add(methods, pattern, [handler = std::move(handler), parameterOffsets = std::move(parameterOffsets), &customContinue](auto *r) mutable {
|
||||
httpContextData->currentRouter->add(methods, pattern, [handler = std::move(handler), parameterOffsets = std::move(parameterOffsets), httpContextData](auto *r) mutable {
|
||||
auto user = r->getUserData();
|
||||
user.httpRequest->setYield(false);
|
||||
user.httpRequest->setParameters(r->getParameters());
|
||||
user.httpRequest->setParameterOffsets(¶meterOffsets);
|
||||
|
||||
if (!customContinue) {
|
||||
if (!httpContextData->flags.usingCustomExpectHandler) {
|
||||
/* Middleware? Automatically respond to expectations */
|
||||
std::string_view expect = user.httpRequest->getHeader("expect");
|
||||
if (expect.length() && expect == "100-continue") {
|
||||
|
||||
@@ -22,11 +22,19 @@
|
||||
|
||||
#include <vector>
|
||||
#include "MoveOnlyFunction.h"
|
||||
|
||||
#include "HttpParser.h"
|
||||
namespace uWS {
|
||||
template<bool> struct HttpResponse;
|
||||
struct HttpRequest;
|
||||
|
||||
struct HttpFlags {
|
||||
bool isParsingHttp: 1 = false;
|
||||
bool rejectUnauthorized: 1 = false;
|
||||
bool usingCustomExpectHandler: 1 = false;
|
||||
bool requireHostHeader: 1 = true;
|
||||
bool isAuthorized: 1 = false;
|
||||
};
|
||||
|
||||
template <bool SSL>
|
||||
struct alignas(16) HttpContextData {
|
||||
template <bool> friend struct HttpContext;
|
||||
@@ -35,6 +43,7 @@ struct alignas(16) HttpContextData {
|
||||
private:
|
||||
std::vector<MoveOnlyFunction<void(HttpResponse<SSL> *, int)>> filterHandlers;
|
||||
using OnSocketClosedCallback = void (*)(void* userData, int is_ssl, struct us_socket_t *rawSocket);
|
||||
using OnClientErrorCallback = MoveOnlyFunction<void(int is_ssl, struct us_socket_t *rawSocket, uWS::HttpParserError errorCode, char *rawPacket, int rawPacketLength)>;
|
||||
|
||||
MoveOnlyFunction<void(const char *hostname)> missingServerNameHandler;
|
||||
|
||||
@@ -49,12 +58,11 @@ private:
|
||||
/* This is the default router for default SNI or non-SSL */
|
||||
HttpRouter<RouterData> router;
|
||||
void *upgradedWebSocket = nullptr;
|
||||
bool isParsingHttp = false;
|
||||
bool rejectUnauthorized = false;
|
||||
bool usingCustomExpectHandler = false;
|
||||
|
||||
/* Used to simulate Node.js socket events. */
|
||||
OnSocketClosedCallback onSocketClosed = nullptr;
|
||||
OnClientErrorCallback onClientError = nullptr;
|
||||
|
||||
HttpFlags flags;
|
||||
|
||||
// TODO: SNI
|
||||
void clearRoutes() {
|
||||
@@ -62,6 +70,11 @@ private:
|
||||
this->currentRouter = &router;
|
||||
filterHandlers.clear();
|
||||
}
|
||||
|
||||
public:
|
||||
bool isAuthorized() const {
|
||||
return flags.isAuthorized;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -48,6 +48,28 @@ namespace uWS
|
||||
static const unsigned int MINIMUM_HTTP_POST_PADDING = 32;
|
||||
static void *FULLPTR = (void *)~(uintptr_t)0;
|
||||
|
||||
enum HttpParserError: uint8_t {
|
||||
HTTP_PARSER_ERROR_NONE = 0,
|
||||
HTTP_PARSER_ERROR_INVALID_CHUNKED_ENCODING = 1,
|
||||
HTTP_PARSER_ERROR_INVALID_CONTENT_LENGTH = 2,
|
||||
HTTP_PARSER_ERROR_INVALID_TRANSFER_ENCODING = 3,
|
||||
HTTP_PARSER_ERROR_MISSING_HOST_HEADER = 4,
|
||||
HTTP_PARSER_ERROR_INVALID_REQUEST = 5,
|
||||
HTTP_PARSER_ERROR_REQUEST_HEADER_FIELDS_TOO_LARGE = 6,
|
||||
HTTP_PARSER_ERROR_INVALID_HTTP_VERSION = 7,
|
||||
HTTP_PARSER_ERROR_INVALID_EOF = 8,
|
||||
HTTP_PARSER_ERROR_INVALID_METHOD = 9,
|
||||
};
|
||||
|
||||
|
||||
enum HTTPHeaderParserError: uint8_t {
|
||||
HTTP_HEADER_PARSER_ERROR_NONE = 0,
|
||||
HTTP_HEADER_PARSER_ERROR_INVALID_HTTP_VERSION = 1,
|
||||
HTTP_HEADER_PARSER_ERROR_INVALID_REQUEST = 2,
|
||||
HTTP_HEADER_PARSER_ERROR_INVALID_METHOD = 3,
|
||||
};
|
||||
|
||||
|
||||
struct HttpRequest
|
||||
{
|
||||
|
||||
@@ -59,8 +81,8 @@ namespace uWS
|
||||
std::string_view key, value;
|
||||
} headers[UWS_HTTP_MAX_HEADERS_COUNT];
|
||||
bool ancientHttp;
|
||||
unsigned int querySeparator;
|
||||
bool didYield;
|
||||
unsigned int querySeparator;
|
||||
BloomFilter bf;
|
||||
std::pair<int, std::string_view *> currentParameters;
|
||||
std::map<std::string, unsigned short, std::less<>> *currentParameterOffsets = nullptr;
|
||||
@@ -134,6 +156,7 @@ namespace uWS
|
||||
return std::string_view(nullptr, 0);
|
||||
}
|
||||
|
||||
|
||||
std::string_view getUrl()
|
||||
{
|
||||
return std::string_view(headers->value.data(), querySeparator);
|
||||
@@ -312,6 +335,20 @@ namespace uWS
|
||||
return (void *)p;
|
||||
}
|
||||
|
||||
static bool isValidMethod(std::string_view str) {
|
||||
if (str.empty()) return false;
|
||||
|
||||
for (char c : str) {
|
||||
if (!isValidMethodChar(c))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool isValidMethodChar(char c) {
|
||||
return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) || c == '-';
|
||||
}
|
||||
|
||||
static inline int isHTTPorHTTPSPrefixForProxies(char *data, char *end) {
|
||||
// We can check 8 because:
|
||||
// 1. If it's "http://" that's 7 bytes, and it's supposed to at least have a trailing slash.
|
||||
@@ -353,11 +390,18 @@ namespace uWS
|
||||
}
|
||||
|
||||
/* Puts method as key, target as value and returns non-null (or nullptr on error). */
|
||||
/* PS: this function on error can return char* to HTTPHeaderParserError enum, with is not the best design, this need to be refactor */
|
||||
static inline char *consumeRequestLine(char *data, char *end, HttpRequest::Header &header, bool &isAncientHTTP) {
|
||||
/* Scan until single SP, assume next is / (origin request) */
|
||||
char *start = data;
|
||||
/* This catches the post padded CR and fails */
|
||||
while (data[0] > 32) data++;
|
||||
while (data[0] > 32) {
|
||||
if (!isValidMethodChar(data[0]) ) {
|
||||
return (char *) HTTP_HEADER_PARSER_ERROR_INVALID_METHOD;
|
||||
}
|
||||
data++;
|
||||
|
||||
}
|
||||
if (&data[1] == end) [[unlikely]] {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -365,6 +409,9 @@ namespace uWS
|
||||
if (data[0] == 32 && (__builtin_expect(data[1] == '/', 1) || isHTTPorHTTPSPrefixForProxies(data + 1, end) == 1)) [[likely]] {
|
||||
header.key = {start, (size_t) (data - start)};
|
||||
data++;
|
||||
if(!isValidMethod(header.key)) {
|
||||
return (char *) HTTP_HEADER_PARSER_ERROR_INVALID_METHOD;
|
||||
}
|
||||
/* Scan for less than 33 (catches post padded CR and fails) */
|
||||
start = data;
|
||||
for (; true; data += 8) {
|
||||
@@ -383,7 +430,7 @@ namespace uWS
|
||||
isAncientHTTP = true;
|
||||
return data + 11;
|
||||
}
|
||||
return (char *) 0x1;
|
||||
return (char *) HTTP_HEADER_PARSER_ERROR_INVALID_HTTP_VERSION;
|
||||
}
|
||||
if (memcmp(" HTTP/1.1\r\n", data, 11) == 0) {
|
||||
return data + 11;
|
||||
@@ -396,7 +443,7 @@ namespace uWS
|
||||
return nullptr;
|
||||
}
|
||||
/* This is an error */
|
||||
return (char *) 0x1;
|
||||
return (char *) HTTP_HEADER_PARSER_ERROR_INVALID_HTTP_VERSION;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -413,11 +460,11 @@ namespace uWS
|
||||
return nullptr;
|
||||
// Otherwise, if it's not http:// or https://, return 400
|
||||
default:
|
||||
return (char *) 0x2;
|
||||
return (char *) HTTP_HEADER_PARSER_ERROR_INVALID_REQUEST;
|
||||
}
|
||||
}
|
||||
|
||||
return (char *) 0x1;
|
||||
return (char *) HTTP_HEADER_PARSER_ERROR_INVALID_HTTP_VERSION;
|
||||
}
|
||||
|
||||
/* RFC 9110: 5.5 Field Values (TLDR; anything above 31 is allowed; htab (9) is also allowed)
|
||||
@@ -436,7 +483,7 @@ namespace uWS
|
||||
}
|
||||
|
||||
/* End is only used for the proxy parser. The HTTP parser recognizes "\ra" as invalid "\r\n" scan and breaks. */
|
||||
static unsigned int getHeaders(char *postPaddedBuffer, char *end, struct HttpRequest::Header *headers, void *reserved, unsigned int &err, bool &isAncientHTTP) {
|
||||
static unsigned int getHeaders(char *postPaddedBuffer, char *end, struct HttpRequest::Header *headers, void *reserved, unsigned int &err, HttpParserError &parserError, bool &isAncientHTTP) {
|
||||
char *preliminaryKey, *preliminaryValue, *start = postPaddedBuffer;
|
||||
|
||||
#ifdef UWS_WITH_PROXY
|
||||
@@ -466,15 +513,21 @@ namespace uWS
|
||||
* which is then removed, and our counters to flip due to overflow and we end up with a crash */
|
||||
|
||||
/* The request line is different from the field names / field values */
|
||||
if ((char *) 3 > (postPaddedBuffer = consumeRequestLine(postPaddedBuffer, end, headers[0], isAncientHTTP))) {
|
||||
if ((char *) 4 > (postPaddedBuffer = consumeRequestLine(postPaddedBuffer, end, headers[0], isAncientHTTP))) {
|
||||
/* Error - invalid request line */
|
||||
/* Assuming it is 505 HTTP Version Not Supported */
|
||||
switch (reinterpret_cast<uintptr_t>(postPaddedBuffer)) {
|
||||
case 0x1:
|
||||
err = HTTP_ERROR_505_HTTP_VERSION_NOT_SUPPORTED;;
|
||||
case HTTP_HEADER_PARSER_ERROR_INVALID_HTTP_VERSION:
|
||||
err = HTTP_ERROR_505_HTTP_VERSION_NOT_SUPPORTED;
|
||||
parserError = HTTP_PARSER_ERROR_INVALID_HTTP_VERSION;
|
||||
break;
|
||||
case 0x2:
|
||||
case HTTP_HEADER_PARSER_ERROR_INVALID_REQUEST:
|
||||
err = HTTP_ERROR_400_BAD_REQUEST;
|
||||
parserError = HTTP_PARSER_ERROR_INVALID_REQUEST;
|
||||
break;
|
||||
case HTTP_HEADER_PARSER_ERROR_INVALID_METHOD:
|
||||
err = HTTP_ERROR_400_BAD_REQUEST;
|
||||
parserError = HTTP_PARSER_ERROR_INVALID_METHOD;
|
||||
break;
|
||||
default: {
|
||||
err = 0;
|
||||
@@ -483,6 +536,18 @@ namespace uWS
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* No request headers found */
|
||||
size_t buffer_size = end - postPaddedBuffer;
|
||||
if(buffer_size < 2) {
|
||||
/* Fragmented request */
|
||||
err = HTTP_ERROR_400_BAD_REQUEST;
|
||||
parserError = HTTP_PARSER_ERROR_INVALID_REQUEST;
|
||||
return 0;
|
||||
}
|
||||
if(buffer_size >= 2 && postPaddedBuffer[0] == '\r' && postPaddedBuffer[1] == '\n') {
|
||||
/* No headers found */
|
||||
return (unsigned int) ((postPaddedBuffer + 2) - start);
|
||||
}
|
||||
headers++;
|
||||
|
||||
for (unsigned int i = 1; i < UWS_HTTP_MAX_HEADERS_COUNT - 1; i++) {
|
||||
@@ -499,6 +564,7 @@ namespace uWS
|
||||
}
|
||||
/* Error: invalid chars in field name */
|
||||
err = HTTP_ERROR_400_BAD_REQUEST;
|
||||
parserError = HTTP_PARSER_ERROR_INVALID_REQUEST;
|
||||
return 0;
|
||||
}
|
||||
postPaddedBuffer++;
|
||||
@@ -516,6 +582,7 @@ namespace uWS
|
||||
}
|
||||
/* Error - invalid chars in field value */
|
||||
err = HTTP_ERROR_400_BAD_REQUEST;
|
||||
parserError = HTTP_PARSER_ERROR_INVALID_REQUEST;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
@@ -549,6 +616,7 @@ namespace uWS
|
||||
/* \r\n\r plus non-\n letter is malformed request, or simply out of search space */
|
||||
if (postPaddedBuffer + 1 < end) {
|
||||
err = HTTP_ERROR_400_BAD_REQUEST;
|
||||
parserError = HTTP_PARSER_ERROR_INVALID_REQUEST;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -568,26 +636,26 @@ namespace uWS
|
||||
* or [consumed, nullptr] for "break; I am closed or upgraded to websocket"
|
||||
* or [whatever, fullptr] for "break and close me, I am a parser error!" */
|
||||
template <bool ConsumeMinimally>
|
||||
std::pair<unsigned int, void *> fenceAndConsumePostPadded(char *data, unsigned int length, void *user, void *reserved, HttpRequest *req, MoveOnlyFunction<void *(void *, HttpRequest *)> &requestHandler, MoveOnlyFunction<void *(void *, std::string_view, bool)> &dataHandler) {
|
||||
std::tuple<unsigned int, HttpParserError, void *> fenceAndConsumePostPadded(bool requireHostHeader, char *data, unsigned int length, void *user, void *reserved, HttpRequest *req, MoveOnlyFunction<void *(void *, HttpRequest *)> &requestHandler, MoveOnlyFunction<void *(void *, std::string_view, bool)> &dataHandler) {
|
||||
|
||||
/* How much data we CONSUMED (to throw away) */
|
||||
unsigned int consumedTotal = 0;
|
||||
unsigned int err = 0;
|
||||
HttpParserError parserError = HTTP_PARSER_ERROR_NONE;
|
||||
|
||||
/* Fence two bytes past end of our buffer (buffer has post padded margins).
|
||||
* This is to always catch scan for \r but not for \r\n. */
|
||||
data[length] = '\r';
|
||||
data[length + 1] = 'a'; /* Anything that is not \n, to trigger "invalid request" */
|
||||
bool isAncientHTTP = false;
|
||||
|
||||
for (unsigned int consumed; length && (consumed = getHeaders(data, data + length, req->headers, reserved, err, isAncientHTTP)); ) {
|
||||
for (unsigned int consumed; length && (consumed = getHeaders(data, data + length, req->headers, reserved, err, parserError, isAncientHTTP)); ) {
|
||||
data += consumed;
|
||||
length -= consumed;
|
||||
consumedTotal += consumed;
|
||||
|
||||
/* Even if we could parse it, check for length here as well */
|
||||
if (consumed > MAX_FALLBACK_SIZE) {
|
||||
return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};
|
||||
return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, HTTP_PARSER_ERROR_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};
|
||||
}
|
||||
|
||||
/* Store HTTP version (ancient 1.0 or 1.1) */
|
||||
@@ -595,13 +663,13 @@ namespace uWS
|
||||
|
||||
/* Add all headers to bloom filter */
|
||||
req->bf.reset();
|
||||
|
||||
for (HttpRequest::Header *h = req->headers; (++h)->key.length(); ) {
|
||||
req->bf.add(h->key);
|
||||
}
|
||||
|
||||
/* Break if no host header (but we can have empty string which is different from nullptr) */
|
||||
if (!req->getHeader("host").data()) {
|
||||
return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
|
||||
if (!isAncientHTTP && requireHostHeader && !req->getHeader("host").data()) {
|
||||
return {HTTP_ERROR_400_BAD_REQUEST, HTTP_PARSER_ERROR_MISSING_HOST_HEADER, FULLPTR};
|
||||
}
|
||||
|
||||
/* RFC 9112 6.3
|
||||
@@ -618,7 +686,7 @@ namespace uWS
|
||||
/* Returning fullptr is the same as calling the errorHandler */
|
||||
/* We could be smart and set an error in the context along with this, to indicate what
|
||||
* http error response we might want to return */
|
||||
return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
|
||||
return {HTTP_ERROR_400_BAD_REQUEST, HTTP_PARSER_ERROR_INVALID_TRANSFER_ENCODING, FULLPTR};
|
||||
}
|
||||
|
||||
/* Parse query */
|
||||
@@ -630,25 +698,17 @@ namespace uWS
|
||||
remainingStreamingBytes = toUnsignedInteger(contentLengthString);
|
||||
if (remainingStreamingBytes == UINT64_MAX) {
|
||||
/* Parser error */
|
||||
return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
|
||||
return {HTTP_ERROR_400_BAD_REQUEST, HTTP_PARSER_ERROR_INVALID_CONTENT_LENGTH, FULLPTR};
|
||||
}
|
||||
}
|
||||
|
||||
// lets check if content len is valid before calling requestHandler
|
||||
if(contentLengthStringLen) {
|
||||
remainingStreamingBytes = toUnsignedInteger(contentLengthString);
|
||||
if (remainingStreamingBytes == UINT64_MAX) {
|
||||
/* Parser error */
|
||||
return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
|
||||
}
|
||||
}
|
||||
/* If returned socket is not what we put in we need
|
||||
* to break here as we either have upgraded to
|
||||
* WebSockets or otherwise closed the socket. */
|
||||
void *returnedUser = requestHandler(user, req);
|
||||
if (returnedUser != user) {
|
||||
/* We are upgraded to WebSocket or otherwise broken */
|
||||
return {consumedTotal, returnedUser};
|
||||
return {consumedTotal, HTTP_PARSER_ERROR_NONE, returnedUser};
|
||||
}
|
||||
|
||||
/* The rules at play here according to RFC 9112 for requests are essentially:
|
||||
@@ -684,7 +744,7 @@ namespace uWS
|
||||
}
|
||||
if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {
|
||||
// TODO: what happen if we already responded?
|
||||
return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
|
||||
return {HTTP_ERROR_400_BAD_REQUEST, HTTP_PARSER_ERROR_INVALID_CHUNKED_ENCODING, FULLPTR};
|
||||
}
|
||||
unsigned int consumed = (length - (unsigned int) dataToConsume.length());
|
||||
data = (char *) dataToConsume.data();
|
||||
@@ -713,13 +773,13 @@ namespace uWS
|
||||
}
|
||||
/* Whenever we return FULLPTR, the interpretation of "consumed" should be the HttpError enum. */
|
||||
if (err) {
|
||||
return {err, FULLPTR};
|
||||
return {err, parserError, FULLPTR};
|
||||
}
|
||||
return {consumedTotal, user};
|
||||
return {consumedTotal, HTTP_PARSER_ERROR_NONE, user};
|
||||
}
|
||||
|
||||
public:
|
||||
std::pair<unsigned int, void *> consumePostPadded(char *data, unsigned int length, void *user, void *reserved, MoveOnlyFunction<void *(void *, HttpRequest *)> &&requestHandler, MoveOnlyFunction<void *(void *, std::string_view, bool)> &&dataHandler) {
|
||||
std::tuple<unsigned int, HttpParserError, void *> consumePostPadded(bool requireHostHeader, char *data, unsigned int length, void *user, void *reserved, MoveOnlyFunction<void *(void *, HttpRequest *)> &&requestHandler, MoveOnlyFunction<void *(void *, std::string_view, bool)> &&dataHandler) {
|
||||
|
||||
/* This resets BloomFilter by construction, but later we also reset it again.
|
||||
* Optimize this to skip resetting twice (req could be made global) */
|
||||
@@ -733,7 +793,7 @@ public:
|
||||
dataHandler(user, chunk, chunk.length() == 0);
|
||||
}
|
||||
if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {
|
||||
return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
|
||||
return {HTTP_ERROR_400_BAD_REQUEST, HTTP_PARSER_ERROR_INVALID_CHUNKED_ENCODING, FULLPTR};
|
||||
}
|
||||
data = (char *) dataToConsume.data();
|
||||
length = (unsigned int) dataToConsume.length();
|
||||
@@ -743,7 +803,7 @@ public:
|
||||
if (remainingStreamingBytes >= length) {
|
||||
void *returnedUser = dataHandler(user, std::string_view(data, length), remainingStreamingBytes == length);
|
||||
remainingStreamingBytes -= length;
|
||||
return {0, returnedUser};
|
||||
return {0, HTTP_PARSER_ERROR_NONE, returnedUser};
|
||||
} else {
|
||||
void *returnedUser = dataHandler(user, std::string_view(data, remainingStreamingBytes), true);
|
||||
|
||||
@@ -753,7 +813,7 @@ public:
|
||||
remainingStreamingBytes = 0;
|
||||
|
||||
if (returnedUser != user) {
|
||||
return {0, returnedUser};
|
||||
return {0, HTTP_PARSER_ERROR_NONE, returnedUser};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -768,19 +828,19 @@ public:
|
||||
fallback.append(data, maxCopyDistance);
|
||||
|
||||
// break here on break
|
||||
std::pair<unsigned int, void *> consumed = fenceAndConsumePostPadded<true>(fallback.data(), (unsigned int) fallback.length(), user, reserved, &req, requestHandler, dataHandler);
|
||||
if (consumed.second != user) {
|
||||
std::tuple<unsigned int, HttpParserError, void *> consumed = fenceAndConsumePostPadded<true>(requireHostHeader,fallback.data(), (unsigned int) fallback.length(), user, reserved, &req, requestHandler, dataHandler);
|
||||
if (std::get<2>(consumed) != user) {
|
||||
return consumed;
|
||||
}
|
||||
|
||||
if (consumed.first) {
|
||||
if (std::get<0>(consumed)) {
|
||||
|
||||
/* This logic assumes that we consumed everything in fallback buffer.
|
||||
* This is critically important, as we will get an integer overflow in case
|
||||
* of "had" being larger than what we consumed, and that we would drop data */
|
||||
fallback.clear();
|
||||
data += consumed.first - had;
|
||||
length -= consumed.first - had;
|
||||
data += std::get<0>(consumed) - had;
|
||||
length -= std::get<0>(consumed) - had;
|
||||
|
||||
if (remainingStreamingBytes) {
|
||||
/* It's either chunked or with a content-length */
|
||||
@@ -790,7 +850,7 @@ public:
|
||||
dataHandler(user, chunk, chunk.length() == 0);
|
||||
}
|
||||
if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {
|
||||
return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
|
||||
return {HTTP_ERROR_400_BAD_REQUEST, HTTP_PARSER_ERROR_INVALID_CHUNKED_ENCODING, FULLPTR};
|
||||
}
|
||||
data = (char *) dataToConsume.data();
|
||||
length = (unsigned int) dataToConsume.length();
|
||||
@@ -799,7 +859,7 @@ public:
|
||||
if (remainingStreamingBytes >= (unsigned int) length) {
|
||||
void *returnedUser = dataHandler(user, std::string_view(data, length), remainingStreamingBytes == (unsigned int) length);
|
||||
remainingStreamingBytes -= length;
|
||||
return {0, returnedUser};
|
||||
return {0, HTTP_PARSER_ERROR_NONE, returnedUser};
|
||||
} else {
|
||||
void *returnedUser = dataHandler(user, std::string_view(data, remainingStreamingBytes), true);
|
||||
|
||||
@@ -809,7 +869,7 @@ public:
|
||||
remainingStreamingBytes = 0;
|
||||
|
||||
if (returnedUser != user) {
|
||||
return {0, returnedUser};
|
||||
return {0, HTTP_PARSER_ERROR_NONE, returnedUser};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -817,30 +877,30 @@ public:
|
||||
|
||||
} else {
|
||||
if (fallback.length() == MAX_FALLBACK_SIZE) {
|
||||
return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};
|
||||
return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, HTTP_PARSER_ERROR_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};
|
||||
}
|
||||
return {0, user};
|
||||
return {0, HTTP_PARSER_ERROR_NONE, user};
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<unsigned int, void *> consumed = fenceAndConsumePostPadded<false>(data, length, user, reserved, &req, requestHandler, dataHandler);
|
||||
if (consumed.second != user) {
|
||||
std::tuple<unsigned int, HttpParserError, void *> consumed = fenceAndConsumePostPadded<false>(requireHostHeader,data, length, user, reserved, &req, requestHandler, dataHandler);
|
||||
if (std::get<2>(consumed) != user) {
|
||||
return consumed;
|
||||
}
|
||||
|
||||
data += consumed.first;
|
||||
length -= consumed.first;
|
||||
data += std::get<0>(consumed);
|
||||
length -= std::get<0>(consumed);
|
||||
|
||||
if (length) {
|
||||
if (length < MAX_FALLBACK_SIZE) {
|
||||
fallback.append(data, length);
|
||||
} else {
|
||||
return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};
|
||||
return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, HTTP_PARSER_ERROR_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};
|
||||
}
|
||||
}
|
||||
|
||||
// added for now
|
||||
return {0, user};
|
||||
return {0, HTTP_PARSER_ERROR_NONE, user};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -104,17 +104,20 @@ public:
|
||||
|
||||
/* In some cases, such as when refusing huge data we want to close the connection when drained */
|
||||
if (closeConnection) {
|
||||
/* We can only write the header once */
|
||||
if (!(httpResponseData->state & (HttpResponseData<SSL>::HTTP_END_CALLED))) {
|
||||
|
||||
/* HTTP 1.1 must send this back unless the client already sent it to us.
|
||||
* It is a connection close when either of the two parties say so but the
|
||||
* one party must tell the other one so.
|
||||
*
|
||||
* This check also serves to limit writing the header only once. */
|
||||
if ((httpResponseData->state & HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE) == 0) {
|
||||
writeHeader("Connection", "close");
|
||||
}
|
||||
|
||||
/* HTTP 1.1 must send this back unless the client already sent it to us.
|
||||
* It is a connection close when either of the two parties say so but the
|
||||
* one party must tell the other one so.
|
||||
*
|
||||
* This check also serves to limit writing the header only once. */
|
||||
if ((httpResponseData->state & HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE) == 0) {
|
||||
writeHeader("Connection", "close");
|
||||
httpResponseData->state |= HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE;
|
||||
}
|
||||
|
||||
httpResponseData->state |= HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE;
|
||||
}
|
||||
|
||||
/* if write was called and there was previously no Content-Length header set */
|
||||
@@ -128,7 +131,7 @@ public:
|
||||
|
||||
|
||||
/* Terminating 0 chunk */
|
||||
Super::write("\r\n0\r\n\r\n", 7);
|
||||
Super::write("0\r\n\r\n", 5);
|
||||
|
||||
httpResponseData->markDone();
|
||||
|
||||
@@ -331,7 +334,7 @@ public:
|
||||
|
||||
/* We should only mark this if inside the parser; if upgrading "async" we cannot set this */
|
||||
HttpContextData<SSL> *httpContextData = httpContext->getSocketContextData();
|
||||
if (httpContextData->isParsingHttp) {
|
||||
if (httpContextData->flags.isParsingHttp) {
|
||||
/* We need to tell the Http parser that we changed socket */
|
||||
httpContextData->upgradedWebSocket = webSocket;
|
||||
}
|
||||
@@ -453,6 +456,7 @@ public:
|
||||
writeMark();
|
||||
|
||||
writeHeader("Transfer-Encoding", "chunked");
|
||||
Super::write("\r\n", 2);
|
||||
httpResponseData->state |= HttpResponseData<SSL>::HTTP_WRITE_CALLED;
|
||||
}
|
||||
|
||||
@@ -462,6 +466,28 @@ public:
|
||||
return internalEnd({nullptr, 0}, 0, false, false, closeConnection);
|
||||
}
|
||||
|
||||
void flushHeaders() {
|
||||
|
||||
writeStatus(HTTP_200_OK);
|
||||
|
||||
HttpResponseData<SSL> *httpResponseData = getHttpResponseData();
|
||||
|
||||
if (!(httpResponseData->state & HttpResponseData<SSL>::HTTP_WROTE_CONTENT_LENGTH_HEADER) && !httpResponseData->fromAncientRequest) {
|
||||
if (!(httpResponseData->state & HttpResponseData<SSL>::HTTP_WRITE_CALLED)) {
|
||||
/* Write mark on first call to write */
|
||||
writeMark();
|
||||
|
||||
writeHeader("Transfer-Encoding", "chunked");
|
||||
Super::write("\r\n", 2);
|
||||
httpResponseData->state |= HttpResponseData<SSL>::HTTP_WRITE_CALLED;
|
||||
}
|
||||
|
||||
} else if (!(httpResponseData->state & HttpResponseData<SSL>::HTTP_WRITE_CALLED)) {
|
||||
writeMark();
|
||||
Super::write("\r\n", 2);
|
||||
httpResponseData->state |= HttpResponseData<SSL>::HTTP_WRITE_CALLED;
|
||||
}
|
||||
}
|
||||
/* Write parts of the response in chunking fashion. Starts timeout if failed. */
|
||||
bool write(std::string_view data, size_t *writtenPtr = nullptr) {
|
||||
writeStatus(HTTP_200_OK);
|
||||
@@ -517,10 +543,10 @@ public:
|
||||
writeMark();
|
||||
|
||||
writeHeader("Transfer-Encoding", "chunked");
|
||||
Super::write("\r\n", 2);
|
||||
httpResponseData->state |= HttpResponseData<SSL>::HTTP_WRITE_CALLED;
|
||||
}
|
||||
|
||||
Super::write("\r\n", 2);
|
||||
|
||||
writeUnsignedHex((unsigned int) data.length());
|
||||
Super::write("\r\n", 2);
|
||||
} else if (!(httpResponseData->state & HttpResponseData<SSL>::HTTP_WRITE_CALLED)) {
|
||||
@@ -548,6 +574,11 @@ public:
|
||||
has_failed = has_failed || failed;
|
||||
total_written += written;
|
||||
}
|
||||
|
||||
if (!(httpResponseData->state & HttpResponseData<SSL>::HTTP_WROTE_CONTENT_LENGTH_HEADER) && !httpResponseData->fromAncientRequest) {
|
||||
// Write End of Chunked Encoding after data has been written
|
||||
Super::write("\r\n", 2);
|
||||
}
|
||||
|
||||
/* Reset timeout on each sended chunk */
|
||||
this->resetTimeout();
|
||||
|
||||
23
patches/highway/silence-warnings.patch
Normal file
23
patches/highway/silence-warnings.patch
Normal file
@@ -0,0 +1,23 @@
|
||||
--- a/hwy/base.h
|
||||
+++ b/hwy/base.h
|
||||
@@ -332,8 +332,7 @@ HWY_DLLEXPORT HWY_NORETURN void HWY_FORMAT(3, 4)
|
||||
|
||||
#endif // HWY_HEADER_ONLY
|
||||
|
||||
-#define HWY_WARN(format, ...) \
|
||||
- ::hwy::Warn(__FILE__, __LINE__, format, ##__VA_ARGS__)
|
||||
+#define HWY_WARN(format, ...)
|
||||
|
||||
#define HWY_ABORT(format, ...) \
|
||||
::hwy::Abort(__FILE__, __LINE__, format, ##__VA_ARGS__)
|
||||
--- a/hwy/contrib/thread_pool/topology.cc
|
||||
+++ b/hwy/contrib/thread_pool/topology.cc
|
||||
@@ -162,7 +162,7 @@ void ForeachBit(size_t num_groups, const GROUP_AFFINITY* affinity,
|
||||
size_t lp = Num0BitsBelowLS1Bit_Nonzero64(bits);
|
||||
bits &= bits - 1; // clear LSB
|
||||
if (HWY_UNLIKELY(lp >= lps.size())) {
|
||||
- Warn(__FILE__, line, "Clamping lp %zu to lps.size() %zu, groups %zu\n",
|
||||
+ HWY_WARN("Clamping lp %zu to lps.size() %zu, groups %zu\n",
|
||||
lp, lps.size(), num_groups);
|
||||
lp = lps.size() - 1;
|
||||
}
|
||||
14
scripts/pack-codegen-for-zig-team.sh
Executable file
14
scripts/pack-codegen-for-zig-team.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
if ! test -d build/debug/codegen; then
|
||||
echo "Missing codegen"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
out="codegen-for-zig-team.tar.gz"
|
||||
tar --no-xattrs \
|
||||
--exclude=".DS_Store" \
|
||||
-zcf "$out" \
|
||||
build/debug/codegen \
|
||||
src/bun.js/bindings/GeneratedBindings.zig \
|
||||
src/bun.js/bindings/GeneratedJS2Native.zig
|
||||
echo "-> $out"
|
||||
@@ -127,7 +127,7 @@ const { values: options, positionals: filters } = parseArgs({
|
||||
},
|
||||
["junit"]: {
|
||||
type: "boolean",
|
||||
default: isCI, // Always enable JUnit in CI
|
||||
default: false, // Disabled for now, because it's too much $
|
||||
},
|
||||
["junit-temp-dir"]: {
|
||||
type: "string",
|
||||
|
||||
@@ -5,7 +5,7 @@ const Output = @import("output.zig");
|
||||
const use_mimalloc = bun.use_mimalloc;
|
||||
const StringTypes = @import("./string_types.zig");
|
||||
const Mimalloc = bun.Mimalloc;
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
|
||||
const version_string = Environment.version_string;
|
||||
|
||||
@@ -123,7 +123,10 @@ pub fn exit(code: u32) noreturn {
|
||||
Bun__onExit();
|
||||
std.os.windows.kernel32.ExitProcess(code);
|
||||
},
|
||||
else => bun.C.quick_exit(@bitCast(code)),
|
||||
else => {
|
||||
bun.c.quick_exit(@bitCast(code));
|
||||
std.c.abort(); // quick_exit should be noreturn
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const string = bun.string;
|
||||
const ImportRecord = @import("./import_record.zig").ImportRecord;
|
||||
const ImportKind = @import("./import_record.zig").ImportKind;
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const assert = bun.assert;
|
||||
const testing = std.testing;
|
||||
const Thread = std.Thread;
|
||||
|
||||
@@ -128,7 +128,7 @@ pub const SavedFile = struct {
|
||||
const store = JSC.WebCore.Blob.Store.initFile(
|
||||
JSC.Node.PathOrFileDescriptor{
|
||||
.path = JSC.Node.PathLike{
|
||||
.string = JSC.PathString.init(path),
|
||||
.string = bun.PathString.init(path),
|
||||
},
|
||||
},
|
||||
mime_type,
|
||||
@@ -251,7 +251,7 @@ pub fn writeToDisk(f: OutputFile, root_dir: std.fs.Dir, root_dir_path: []const u
|
||||
}
|
||||
|
||||
var path_buf: bun.PathBuffer = undefined;
|
||||
_ = try JSC.Node.NodeFS.writeFileWithPathBuffer(&path_buf, .{
|
||||
_ = try JSC.Node.fs.NodeFS.writeFileWithPathBuffer(&path_buf, .{
|
||||
.data = .{ .buffer = .{
|
||||
.buffer = .{
|
||||
.ptr = @constCast(value.bytes.ptr),
|
||||
@@ -263,7 +263,7 @@ pub fn writeToDisk(f: OutputFile, root_dir: std.fs.Dir, root_dir_path: []const u
|
||||
.mode = if (f.is_executable) 0o755 else 0o644,
|
||||
.dirfd = .fromStdDir(root_dir),
|
||||
.file = .{ .path = .{
|
||||
.string = JSC.PathString.init(rel_path),
|
||||
.string = bun.PathString.init(rel_path),
|
||||
} },
|
||||
}).unwrap();
|
||||
},
|
||||
@@ -278,7 +278,7 @@ pub fn writeToDisk(f: OutputFile, root_dir: std.fs.Dir, root_dir_path: []const u
|
||||
}
|
||||
|
||||
pub fn moveTo(file: *const OutputFile, _: string, rel_path: []const u8, dir: FileDescriptorType) !void {
|
||||
try bun.C.moveFileZ(file.value.move.dir, bun.sliceTo(&(try std.posix.toPosixPath(file.value.move.getPathname())), 0), dir, bun.sliceTo(&(try std.posix.toPosixPath(rel_path)), 0));
|
||||
try bun.sys.moveFileZ(file.value.move.dir, bun.sliceTo(&(try std.posix.toPosixPath(file.value.move.getPathname())), 0), dir, bun.sliceTo(&(try std.posix.toPosixPath(rel_path)), 0));
|
||||
}
|
||||
|
||||
pub fn copyTo(file: *const OutputFile, _: string, rel_path: []const u8, dir: FileDescriptorType) !void {
|
||||
@@ -483,7 +483,7 @@ const string = []const u8;
|
||||
const FileDescriptorType = bun.FileDescriptor;
|
||||
|
||||
const std = @import("std");
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const JSC = bun.JSC;
|
||||
const Fs = bun.fs;
|
||||
const Loader = @import("./options.zig").Loader;
|
||||
|
||||
@@ -20,7 +20,7 @@ const windows = std.os.windows;
|
||||
const testing = std.testing;
|
||||
const assert = bun.assert;
|
||||
const Progress = @This();
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
|
||||
/// `null` if the current node (and its children) should
|
||||
/// not print on update()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Originally, we tried using LIEF to inject the module graph into a MachO segment
|
||||
//! But this incurred a fixed 350ms overhead on every build, which is unacceptable
|
||||
//! so we give up on codesigning support on macOS for now until we can find a better solution
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const std = @import("std");
|
||||
const Schema = bun.Schema.Api;
|
||||
const strings = bun.strings;
|
||||
@@ -136,7 +136,7 @@ pub const StandaloneModuleGraph = struct {
|
||||
loader: bun.options.Loader,
|
||||
contents: [:0]const u8 = "",
|
||||
sourcemap: LazySourceMap,
|
||||
cached_blob: ?*bun.JSC.WebCore.Blob = null,
|
||||
cached_blob: ?*bun.webcore.Blob = null,
|
||||
encoding: Encoding = .binary,
|
||||
wtf_string: bun.String = bun.String.empty,
|
||||
bytecode: []u8 = "",
|
||||
@@ -171,13 +171,13 @@ pub const StandaloneModuleGraph = struct {
|
||||
return this.wtf_string.dupeRef();
|
||||
}
|
||||
|
||||
pub fn blob(this: *File, globalObject: *bun.JSC.JSGlobalObject) *bun.JSC.WebCore.Blob {
|
||||
pub fn blob(this: *File, globalObject: *bun.JSC.JSGlobalObject) *bun.webcore.Blob {
|
||||
if (this.cached_blob == null) {
|
||||
const store = bun.JSC.WebCore.Blob.Store.init(@constCast(this.contents), bun.default_allocator);
|
||||
const store = bun.webcore.Blob.Store.init(@constCast(this.contents), bun.default_allocator);
|
||||
// make it never free
|
||||
store.ref();
|
||||
|
||||
const b = bun.JSC.WebCore.Blob.initWithStore(store, globalObject).new();
|
||||
const b = bun.webcore.Blob.initWithStore(store, globalObject).new();
|
||||
b.allocator = bun.default_allocator;
|
||||
|
||||
if (bun.http.MimeType.byExtensionNoDefault(bun.strings.trimLeadingChar(std.fs.path.extension(this.name), '.'))) |mime| {
|
||||
@@ -659,7 +659,7 @@ pub const StandaloneModuleGraph = struct {
|
||||
Global.exit(1);
|
||||
};
|
||||
if (comptime !Environment.isWindows) {
|
||||
_ = bun.C.fchmod(cloned_executable_fd.native(), 0o777);
|
||||
_ = bun.c.fchmod(cloned_executable_fd.native(), 0o777);
|
||||
}
|
||||
return cloned_executable_fd;
|
||||
},
|
||||
@@ -727,7 +727,7 @@ pub const StandaloneModuleGraph = struct {
|
||||
// the final 8 bytes in the file are the length of the module graph with padding, excluding the trailer and offsets
|
||||
_ = Syscall.write(cloned_executable_fd, std.mem.asBytes(&total_byte_count));
|
||||
if (comptime !Environment.isWindows) {
|
||||
_ = bun.C.fchmod(cloned_executable_fd.native(), 0o777);
|
||||
_ = bun.c.fchmod(cloned_executable_fd.native(), 0o777);
|
||||
}
|
||||
|
||||
return cloned_executable_fd;
|
||||
@@ -803,14 +803,14 @@ pub const StandaloneModuleGraph = struct {
|
||||
break :brk outfile_buf_u16[0..outfile_w.len :0];
|
||||
};
|
||||
|
||||
bun.C.moveOpenedFileAtLoose(fd, .fromStdDir(root_dir), outfile_slice, true).unwrap() catch |err| {
|
||||
bun.windows.moveOpenedFileAtLoose(fd, .fromStdDir(root_dir), outfile_slice, true).unwrap() catch |err| {
|
||||
if (err == error.EISDIR) {
|
||||
Output.errGeneric("{} is a directory. Please choose a different --outfile or delete the directory", .{bun.fmt.utf16(outfile_slice)});
|
||||
} else {
|
||||
Output.err(err, "failed to move executable to result path", .{});
|
||||
}
|
||||
|
||||
_ = bun.C.deleteOpenedFile(fd);
|
||||
_ = bun.windows.deleteOpenedFile(fd);
|
||||
|
||||
Global.exit(1);
|
||||
};
|
||||
@@ -832,7 +832,7 @@ pub const StandaloneModuleGraph = struct {
|
||||
Global.exit(1);
|
||||
};
|
||||
|
||||
bun.C.moveFileZWithHandle(
|
||||
bun.sys.moveFileZWithHandle(
|
||||
fd,
|
||||
bun.FD.cwd(),
|
||||
bun.sliceTo(&(try std.posix.toPosixPath(temp_location)), 0),
|
||||
|
||||
@@ -6,7 +6,7 @@ const mem = std.mem;
|
||||
const math = std.math;
|
||||
const testing = std.testing;
|
||||
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const assert = bun.assert;
|
||||
|
||||
pub fn AutoHashMap(comptime K: type, comptime V: type, comptime max_load_percentage: comptime_int) type {
|
||||
@@ -57,7 +57,20 @@ pub fn StaticHashMap(comptime K: type, comptime V: type, comptime Context: type,
|
||||
// get_probe_count: usize = 0,
|
||||
// del_probe_count: usize = 0,
|
||||
|
||||
pub usingnamespace HashMapMixin(Self, K, V, Context);
|
||||
const impl = HashMapMixin(Self, K, V, Context);
|
||||
pub const putAssumeCapacity = impl.putAssumeCapacity;
|
||||
pub const slice = impl.slice;
|
||||
pub const clearRetainingCapacity = impl.clearRetainingCapacity;
|
||||
pub const putAssumeCapacityContext = impl.putAssumeCapacityContext;
|
||||
pub const getOrPutAssumeCapacity = impl.getOrPutAssumeCapacity;
|
||||
pub const getOrPutAssumeCapacityContext = impl.getOrPutAssumeCapacityContext;
|
||||
pub const get = impl.get;
|
||||
pub const getContext = impl.getContext;
|
||||
pub const has = impl.has;
|
||||
pub const hasWithHash = impl.hasWithHash;
|
||||
pub const hasContext = impl.hasContext;
|
||||
pub const delete = impl.delete;
|
||||
pub const deleteContext = impl.deleteContext;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -96,7 +109,20 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime Context: type, compt
|
||||
// get_probe_count: usize = 0,
|
||||
// del_probe_count: usize = 0,
|
||||
|
||||
pub usingnamespace HashMapMixin(Self, K, V, Context);
|
||||
const impl = HashMapMixin(Self, K, V, Context);
|
||||
pub const putAssumeCapacity = impl.putAssumeCapacity;
|
||||
pub const slice = impl.slice;
|
||||
pub const clearRetainingCapacity = impl.clearRetainingCapacity;
|
||||
pub const putAssumeCapacityContext = impl.putAssumeCapacityContext;
|
||||
pub const getOrPutAssumeCapacity = impl.getOrPutAssumeCapacity;
|
||||
pub const getOrPutAssumeCapacityContext = impl.getOrPutAssumeCapacityContext;
|
||||
pub const get = impl.get;
|
||||
pub const getContext = impl.getContext;
|
||||
pub const has = impl.has;
|
||||
pub const hasWithHash = impl.hasWithHash;
|
||||
pub const hasContext = impl.hasContext;
|
||||
pub const delete = impl.delete;
|
||||
pub const deleteContext = impl.deleteContext;
|
||||
|
||||
pub fn initCapacity(gpa: mem.Allocator, capacity: u64) !Self {
|
||||
assert(math.isPowerOfTwo(capacity));
|
||||
|
||||
@@ -665,7 +665,7 @@ pub fn onMaybeWatchDirectory(watch: *Watcher, file_path: string, dir_fd: bun.Sto
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const string = bun.string;
|
||||
const Output = bun.Output;
|
||||
const Global = bun.Global;
|
||||
|
||||
@@ -3,7 +3,7 @@ const std = @import("std");
|
||||
const FeatureFlags = @import("./feature_flags.zig");
|
||||
const Environment = @import("./env.zig");
|
||||
const FixedBufferAllocator = std.heap.FixedBufferAllocator;
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const OOM = bun.OOM;
|
||||
|
||||
pub fn isSliceInBufferT(comptime T: type, slice: []const T, buffer: []const T) bool {
|
||||
|
||||
@@ -237,6 +237,6 @@ pub inline fn downcast(a: Allocator) ?*AllocationScope {
|
||||
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const Output = bun.Output;
|
||||
const StoredTrace = bun.crash_handler.StoredTrace;
|
||||
|
||||
90
src/allocators/MemoryReportingAllocator.zig
Normal file
90
src/allocators/MemoryReportingAllocator.zig
Normal file
@@ -0,0 +1,90 @@
|
||||
const MemoryReportingAllocator = @This();
|
||||
const log = bun.Output.scoped(.MEM, false);
|
||||
|
||||
child_allocator: std.mem.Allocator,
|
||||
memory_cost: std.atomic.Value(usize) = std.atomic.Value(usize).init(0),
|
||||
|
||||
fn alloc(context: *anyopaque, n: usize, alignment: std.mem.Alignment, return_address: usize) ?[*]u8 {
|
||||
const this: *MemoryReportingAllocator = @alignCast(@ptrCast(context));
|
||||
const result = this.child_allocator.rawAlloc(n, alignment, return_address) orelse return null;
|
||||
_ = this.memory_cost.fetchAdd(n, .monotonic);
|
||||
if (comptime Environment.allow_assert)
|
||||
log("malloc({d}) = {d}", .{ n, this.memory_cost.raw });
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn discard(this: *MemoryReportingAllocator, buf: []const u8) void {
|
||||
_ = this.memory_cost.fetchSub(buf.len, .monotonic);
|
||||
if (comptime Environment.allow_assert)
|
||||
log("discard({d}) = {d}", .{ buf.len, this.memory_cost.raw });
|
||||
}
|
||||
|
||||
fn resize(context: *anyopaque, buf: []u8, alignment: std.mem.Alignment, new_len: usize, ret_addr: usize) bool {
|
||||
const this: *MemoryReportingAllocator = @alignCast(@ptrCast(context));
|
||||
if (this.child_allocator.rawResize(buf, alignment, new_len, ret_addr)) {
|
||||
_ = this.memory_cost.fetchAdd(new_len -| buf.len, .monotonic);
|
||||
if (comptime Environment.allow_assert)
|
||||
log("resize() = {d}", .{this.memory_cost.raw});
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fn free(context: *anyopaque, buf: []u8, alignment: std.mem.Alignment, ret_addr: usize) void {
|
||||
const this: *MemoryReportingAllocator = @alignCast(@ptrCast(context));
|
||||
this.child_allocator.rawFree(buf, alignment, ret_addr);
|
||||
|
||||
if (comptime Environment.allow_assert) {
|
||||
_ = this.memory_cost.fetchSub(buf.len, .monotonic);
|
||||
log("free({d}) = {d}", .{ buf.len, this.memory_cost.raw });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wrap(this: *MemoryReportingAllocator, allocator_: std.mem.Allocator) std.mem.Allocator {
|
||||
this.* = .{
|
||||
.child_allocator = allocator_,
|
||||
};
|
||||
|
||||
return this.allocator();
|
||||
}
|
||||
|
||||
pub fn allocator(this: *MemoryReportingAllocator) std.mem.Allocator {
|
||||
return std.mem.Allocator{
|
||||
.ptr = this,
|
||||
.vtable = &MemoryReportingAllocator.VTable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn report(this: *MemoryReportingAllocator, vm: *jsc.VM) void {
|
||||
const mem = this.memory_cost.load(.monotonic);
|
||||
if (mem > 0) {
|
||||
vm.reportExtraMemory(mem);
|
||||
if (comptime Environment.allow_assert)
|
||||
log("report({d})", .{mem});
|
||||
}
|
||||
}
|
||||
|
||||
pub inline fn assert(this: *const MemoryReportingAllocator) void {
|
||||
if (comptime !Environment.allow_assert) {
|
||||
return;
|
||||
}
|
||||
|
||||
const memory_cost = this.memory_cost.load(.monotonic);
|
||||
if (memory_cost > 0) {
|
||||
Output.panic("MemoryReportingAllocator still has {d} bytes allocated", .{memory_cost});
|
||||
}
|
||||
}
|
||||
|
||||
pub const VTable = std.mem.Allocator.VTable{
|
||||
.alloc = &alloc,
|
||||
.resize = &resize,
|
||||
.remap = &std.mem.Allocator.noRemap,
|
||||
.free = &free,
|
||||
};
|
||||
|
||||
const std = @import("std");
|
||||
const bun = @import("bun");
|
||||
const jsc = bun.jsc;
|
||||
const Environment = bun.Environment;
|
||||
const Output = bun.Output;
|
||||
@@ -1,6 +1,6 @@
|
||||
//! A nullable allocator the same size as `std.mem.Allocator`.
|
||||
const std = @import("std");
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
|
||||
const NullableAllocator = @This();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const std = @import("std");
|
||||
|
||||
/// When cloning large amounts of data potentially multiple times, we can
|
||||
@@ -76,7 +76,7 @@ pub const LinuxMemFdAllocator = struct {
|
||||
};
|
||||
};
|
||||
|
||||
pub fn alloc(this: *LinuxMemFdAllocator, len: usize, offset: usize, flags: std.posix.MAP) bun.JSC.Maybe(bun.JSC.WebCore.Blob.ByteStore) {
|
||||
pub fn alloc(this: *LinuxMemFdAllocator, len: usize, offset: usize, flags: std.posix.MAP) bun.JSC.Maybe(bun.webcore.Blob.Store.Bytes) {
|
||||
var size = len;
|
||||
|
||||
// size rounded up to nearest page
|
||||
@@ -95,7 +95,7 @@ pub const LinuxMemFdAllocator = struct {
|
||||
)) {
|
||||
.result => |slice| {
|
||||
return .{
|
||||
.result = bun.JSC.WebCore.Blob.ByteStore{
|
||||
.result = bun.webcore.Blob.Store.Bytes{
|
||||
.cap = @truncate(slice.len),
|
||||
.ptr = slice.ptr,
|
||||
.len = @truncate(len),
|
||||
@@ -123,7 +123,7 @@ pub const LinuxMemFdAllocator = struct {
|
||||
return bytes.len >= 1024 * 1024 * 8;
|
||||
}
|
||||
|
||||
pub fn create(bytes: []const u8) bun.JSC.Maybe(bun.JSC.WebCore.Blob.ByteStore) {
|
||||
pub fn create(bytes: []const u8) bun.JSC.Maybe(bun.webcore.Blob.Store.Bytes) {
|
||||
if (comptime !bun.Environment.isLinux) {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const std = @import("std");
|
||||
|
||||
/// Single allocation only.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const mem = @import("std").mem;
|
||||
const builtin = @import("std").builtin;
|
||||
const std = @import("std");
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const log = bun.Output.scoped(.mimalloc, true);
|
||||
const assert = bun.assert;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
@@ -7,7 +7,7 @@ const Environment = @import("../env.zig");
|
||||
const FeatureFlags = @import("../feature_flags.zig");
|
||||
const Allocator = mem.Allocator;
|
||||
const assert = bun.assert;
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const log = bun.Output.scoped(.mimalloc, true);
|
||||
|
||||
pub const Arena = struct {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const string = bun.string;
|
||||
const Output = bun.Output;
|
||||
const Global = bun.Global;
|
||||
@@ -8,7 +8,6 @@ const MutableString = bun.MutableString;
|
||||
const stringZ = bun.stringZ;
|
||||
const default_allocator = bun.default_allocator;
|
||||
const FeatureFlags = bun.FeatureFlags;
|
||||
const C = bun.C;
|
||||
|
||||
const sync = @import("../sync.zig");
|
||||
const std = @import("std");
|
||||
@@ -79,7 +78,7 @@ pub fn isCI() bool {
|
||||
|
||||
/// This answers, "What parts of bun are people actually using?"
|
||||
pub const Features = struct {
|
||||
pub var builtin_modules = std.enums.EnumSet(bun.JSC.HardcodedModule).initEmpty();
|
||||
pub var builtin_modules = std.enums.EnumSet(bun.jsc.ModuleLoader.HardcodedModule).initEmpty();
|
||||
|
||||
pub var @"Bun.stderr": usize = 0;
|
||||
pub var @"Bun.stdin": usize = 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const js_ast = bun.JSAst;
|
||||
const OOM = bun.OOM;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const unicode = std.unicode;
|
||||
|
||||
const js_ast = bun.JSAst;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const Output = bun.Output;
|
||||
const JSC = bun.JSC;
|
||||
const uws = bun.uws;
|
||||
@@ -157,9 +157,9 @@ pub const FilePoll = struct {
|
||||
const StaticPipeWriter = Subprocess.StaticPipeWriter.Poll;
|
||||
const ShellStaticPipeWriter = bun.shell.ShellSubprocess.StaticPipeWriter.Poll;
|
||||
const FileSink = JSC.WebCore.FileSink.Poll;
|
||||
const DNSResolver = JSC.DNS.DNSResolver;
|
||||
const GetAddrInfoRequest = JSC.DNS.GetAddrInfoRequest;
|
||||
const Request = JSC.DNS.InternalDNS.Request;
|
||||
const DNSResolver = bun.api.DNS.DNSResolver;
|
||||
const GetAddrInfoRequest = bun.api.DNS.GetAddrInfoRequest;
|
||||
const Request = bun.api.DNS.InternalDNS.Request;
|
||||
const LifecycleScriptSubprocessOutputReader = bun.install.LifecycleScriptSubprocess.OutputReader;
|
||||
const BufferedReader = bun.io.BufferedReader;
|
||||
|
||||
@@ -904,7 +904,7 @@ pub const FilePoll = struct {
|
||||
&timeout,
|
||||
);
|
||||
|
||||
if (bun.C.getErrno(rc) == .INTR) continue;
|
||||
if (bun.sys.getErrno(rc) == .INTR) continue;
|
||||
break :rc rc;
|
||||
}
|
||||
};
|
||||
@@ -921,7 +921,7 @@ pub const FilePoll = struct {
|
||||
// indicate the error condition.
|
||||
}
|
||||
|
||||
const errno = bun.C.getErrno(rc);
|
||||
const errno = bun.sys.getErrno(rc);
|
||||
|
||||
if (errno != .SUCCESS) {
|
||||
this.deactivate(loop);
|
||||
@@ -1073,7 +1073,7 @@ pub const FilePoll = struct {
|
||||
// indicate the error condition.
|
||||
}
|
||||
|
||||
const errno = bun.C.getErrno(rc);
|
||||
const errno = bun.sys.getErrno(rc);
|
||||
switch (rc) {
|
||||
std.math.minInt(@TypeOf(rc))...-1 => return JSC.Maybe(void).errnoSys(@intFromEnum(errno), .kevent).?,
|
||||
else => {},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
const Output = bun.Output;
|
||||
const JSC = bun.JSC;
|
||||
const uws = bun.uws;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const std = @import("std");
|
||||
const Environment = @import("./env.zig");
|
||||
const strings = @import("./string_immutable.zig");
|
||||
const bun = @import("root").bun;
|
||||
const bun = @import("bun");
|
||||
|
||||
/// This is like ArrayList except it stores the length and capacity as u32
|
||||
/// In practice, it is very unusual to have lengths above 4 GB
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user