mirror of
https://github.com/oven-sh/bun
synced 2026-02-05 08:28:55 +00:00
Compare commits
13 Commits
dylan/pyth
...
add-bun-gi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a40e2b857e | ||
|
|
48a6082167 | ||
|
|
0b6d896adf | ||
|
|
c9dc5dd381 | ||
|
|
d33550ddba | ||
|
|
f02511d2f8 | ||
|
|
7f498a2e07 | ||
|
|
5d4b1821f3 | ||
|
|
41de7a3bfb | ||
|
|
d23312d3f6 | ||
|
|
de8c754c6a | ||
|
|
27e1363a66 | ||
|
|
eba4da23e6 |
@@ -1,5 +1,5 @@
|
||||
ARG LLVM_VERSION="19"
|
||||
ARG REPORTED_LLVM_VERSION="19.1.7"
|
||||
ARG LLVM_VERSION="21"
|
||||
ARG REPORTED_LLVM_VERSION="21.1.8"
|
||||
ARG OLD_BUN_VERSION="1.1.38"
|
||||
ARG BUILDKITE_AGENT_TAGS="queue=linux,os=linux,arch=${TARGETARCH}"
|
||||
|
||||
|
||||
@@ -109,13 +109,12 @@ const buildPlatforms = [
|
||||
{ os: "linux", arch: "x64", distro: "amazonlinux", release: "2023", features: ["docker"] },
|
||||
{ os: "linux", arch: "x64", baseline: true, distro: "amazonlinux", release: "2023", features: ["docker"] },
|
||||
{ os: "linux", arch: "x64", profile: "asan", distro: "amazonlinux", release: "2023", features: ["docker"] },
|
||||
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.22" },
|
||||
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.22" },
|
||||
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.22" },
|
||||
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.23" },
|
||||
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.23" },
|
||||
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.23" },
|
||||
{ os: "windows", arch: "x64", release: "2019" },
|
||||
{ os: "windows", arch: "x64", baseline: true, release: "2019" },
|
||||
// TODO: Enable when Windows ARM64 CI runners are ready
|
||||
// { os: "windows", arch: "aarch64", release: "2019" },
|
||||
{ os: "windows", arch: "aarch64", release: "2019" },
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -133,9 +132,9 @@ const testPlatforms = [
|
||||
{ os: "linux", arch: "aarch64", distro: "ubuntu", release: "25.04", tier: "latest" },
|
||||
{ os: "linux", arch: "x64", distro: "ubuntu", release: "25.04", tier: "latest" },
|
||||
{ os: "linux", arch: "x64", baseline: true, distro: "ubuntu", release: "25.04", tier: "latest" },
|
||||
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.22", tier: "latest" },
|
||||
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.22", tier: "latest" },
|
||||
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.22", tier: "latest" },
|
||||
{ os: "linux", arch: "aarch64", abi: "musl", distro: "alpine", release: "3.23", tier: "latest" },
|
||||
{ os: "linux", arch: "x64", abi: "musl", distro: "alpine", release: "3.23", tier: "latest" },
|
||||
{ os: "linux", arch: "x64", abi: "musl", baseline: true, distro: "alpine", release: "3.23", tier: "latest" },
|
||||
{ os: "windows", arch: "x64", release: "2019", tier: "oldest" },
|
||||
{ os: "windows", arch: "x64", release: "2019", baseline: true, tier: "oldest" },
|
||||
// TODO: Enable when Windows ARM64 CI runners are ready
|
||||
@@ -304,6 +303,13 @@ function getCppAgent(platform, options) {
|
||||
};
|
||||
}
|
||||
|
||||
// Cross-compile Windows ARM64 from x64 runners
|
||||
if (os === "windows" && arch === "aarch64") {
|
||||
return getEc2Agent({ ...platform, arch: "x64" }, options, {
|
||||
instanceType: "c7i.4xlarge",
|
||||
});
|
||||
}
|
||||
|
||||
return getEc2Agent(platform, options, {
|
||||
instanceType: arch === "aarch64" ? "c8g.4xlarge" : "c7i.4xlarge",
|
||||
});
|
||||
@@ -326,8 +332,10 @@ function getLinkBunAgent(platform, options) {
|
||||
}
|
||||
|
||||
if (os === "windows") {
|
||||
return getEc2Agent(platform, options, {
|
||||
instanceType: arch === "aarch64" ? "r8g.large" : "r7i.large",
|
||||
// Cross-compile Windows ARM64 from x64 runners
|
||||
const agentPlatform = arch === "aarch64" ? { ...platform, arch: "x64" } : platform;
|
||||
return getEc2Agent(agentPlatform, options, {
|
||||
instanceType: "r7i.large",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -345,7 +353,7 @@ function getZigPlatform() {
|
||||
arch: "aarch64",
|
||||
abi: "musl",
|
||||
distro: "alpine",
|
||||
release: "3.22",
|
||||
release: "3.23",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -456,6 +464,17 @@ function getBuildCommand(target, options, label) {
|
||||
return `bun run build:${buildProfile}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get extra flags needed when cross-compiling Windows ARM64 from x64.
|
||||
* Applied to C++ and link steps (not Zig, which has its own toolchain handling).
|
||||
*/
|
||||
function getWindowsArm64CrossFlags(target) {
|
||||
if (target.os === "windows" && target.arch === "aarch64") {
|
||||
return " --toolchain windows-aarch64 -DSKIP_CODEGEN=ON -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Platform} platform
|
||||
* @param {PipelineOptions} options
|
||||
@@ -463,6 +482,7 @@ function getBuildCommand(target, options, label) {
|
||||
*/
|
||||
function getBuildCppStep(platform, options) {
|
||||
const command = getBuildCommand(platform, options);
|
||||
const crossFlags = getWindowsArm64CrossFlags(platform);
|
||||
return {
|
||||
key: `${getTargetKey(platform)}-build-cpp`,
|
||||
label: `${getTargetLabel(platform)} - build-cpp`,
|
||||
@@ -476,7 +496,7 @@ function getBuildCppStep(platform, options) {
|
||||
// We used to build the C++ dependencies and bun in separate 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: [`${command} --target bun`, `${command} --target dependencies`],
|
||||
command: [`${command}${crossFlags} --target bun`, `${command}${crossFlags} --target dependencies`],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -533,7 +553,7 @@ function getLinkBunStep(platform, options) {
|
||||
ASAN_OPTIONS: "allow_user_segv_handler=1:disable_coredump=0:detect_leaks=0",
|
||||
...getBuildEnv(platform, options),
|
||||
},
|
||||
command: `${getBuildCommand(platform, options, "build-bun")} --target bun`,
|
||||
command: `${getBuildCommand(platform, options, "build-bun")}${getWindowsArm64CrossFlags(platform)} --target bun`,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1179,6 +1199,8 @@ async function getPipeline(options = {}) {
|
||||
buildImages || publishImages
|
||||
? [...buildPlatforms, ...testPlatforms]
|
||||
.filter(({ os }) => os !== "darwin")
|
||||
// Windows ARM64 cross-compiles from x64 runners, no separate image needed
|
||||
.filter(({ os, arch }) => !(os === "windows" && arch === "aarch64"))
|
||||
.map(platform => [getImageKey(platform), platform])
|
||||
: [],
|
||||
);
|
||||
|
||||
@@ -219,9 +219,8 @@ function create_release() {
|
||||
bun-windows-x64-profile.zip
|
||||
bun-windows-x64-baseline.zip
|
||||
bun-windows-x64-baseline-profile.zip
|
||||
# TODO: Enable when Windows ARM64 CI runners are ready
|
||||
# bun-windows-aarch64.zip
|
||||
# bun-windows-aarch64-profile.zip
|
||||
bun-windows-aarch64.zip
|
||||
bun-windows-aarch64-profile.zip
|
||||
)
|
||||
|
||||
function upload_artifact() {
|
||||
|
||||
4
.github/workflows/CLAUDE.md
vendored
4
.github/workflows/CLAUDE.md
vendored
@@ -33,8 +33,8 @@ The workflow runs all three formatters simultaneously:
|
||||
|
||||
#### 3. Tool Installation
|
||||
|
||||
##### Clang-format-19
|
||||
- Installs ONLY `clang-format-19` package (not the entire LLVM toolchain)
|
||||
##### Clang-format-21
|
||||
- Installs ONLY `clang-format-21` package (not the entire LLVM toolchain)
|
||||
- Uses `--no-install-recommends --no-install-suggests` to skip unnecessary packages
|
||||
- Quiet installation with `-qq` and `-o=Dpkg::Use-Pty=0`
|
||||
|
||||
|
||||
4
.github/workflows/format.yml
vendored
4
.github/workflows/format.yml
vendored
@@ -10,8 +10,8 @@ on:
|
||||
merge_group:
|
||||
env:
|
||||
BUN_VERSION: "1.3.2"
|
||||
LLVM_VERSION: "19.1.7"
|
||||
LLVM_VERSION_MAJOR: "19"
|
||||
LLVM_VERSION: "21.1.8"
|
||||
LLVM_VERSION_MAJOR: "21"
|
||||
|
||||
jobs:
|
||||
autofix:
|
||||
|
||||
@@ -35,7 +35,7 @@ $ sudo pacman -S base-devel cmake git go libiconv libtool make ninja pkg-config
|
||||
```
|
||||
|
||||
```bash#Fedora
|
||||
$ sudo dnf install cargo clang19 llvm19 lld19 cmake git golang libtool ninja-build pkg-config rustc ruby libatomic-static libstdc++-static sed unzip which libicu-devel 'perl(Math::BigInt)'
|
||||
$ sudo dnf install cargo clang21 llvm21 lld21 cmake git golang libtool ninja-build pkg-config rustc ruby libatomic-static libstdc++-static sed unzip which libicu-devel 'perl(Math::BigInt)'
|
||||
```
|
||||
|
||||
```bash#openSUSE Tumbleweed
|
||||
@@ -90,17 +90,17 @@ Our build scripts will automatically detect and use `ccache` if available. You c
|
||||
|
||||
## Install LLVM
|
||||
|
||||
Bun requires LLVM 19 (`clang` is part of LLVM). This version requirement is to match WebKit (precompiled), as mismatching versions will cause memory allocation failures at runtime. In most cases, you can install LLVM through your system package manager:
|
||||
Bun requires LLVM 21.1.8 (`clang` is part of LLVM). This version is enforced by the build system — mismatching versions will cause memory allocation failures at runtime. In most cases, you can install LLVM through your system package manager:
|
||||
|
||||
{% codetabs group="os" %}
|
||||
|
||||
```bash#macOS (Homebrew)
|
||||
$ brew install llvm@19
|
||||
$ brew install llvm@21
|
||||
```
|
||||
|
||||
```bash#Ubuntu/Debian
|
||||
$ # LLVM has an automatic installation script that is compatible with all versions of Ubuntu
|
||||
$ wget https://apt.llvm.org/llvm.sh -O - | sudo bash -s -- 19 all
|
||||
$ wget https://apt.llvm.org/llvm.sh -O - | sudo bash -s -- 21 all
|
||||
```
|
||||
|
||||
```bash#Arch
|
||||
@@ -112,17 +112,17 @@ $ sudo dnf install llvm clang lld-devel
|
||||
```
|
||||
|
||||
```bash#openSUSE Tumbleweed
|
||||
$ sudo zypper install clang19 lld19 llvm19
|
||||
$ sudo zypper install clang21 lld21 llvm21
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
If none of the above solutions apply, you will have to install it [manually](https://github.com/llvm/llvm-project/releases/tag/llvmorg-19.1.7).
|
||||
If none of the above solutions apply, you will have to install it [manually](https://github.com/llvm/llvm-project/releases/tag/llvmorg-21.1.8).
|
||||
|
||||
Make sure Clang/LLVM 19 is in your path:
|
||||
Make sure Clang/LLVM 21 is in your path:
|
||||
|
||||
```bash
|
||||
$ which clang-19
|
||||
$ which clang-21
|
||||
```
|
||||
|
||||
If not, run this to manually add it:
|
||||
@@ -131,13 +131,13 @@ If not, run this to manually add it:
|
||||
|
||||
```bash#macOS (Homebrew)
|
||||
# use fish_add_path if you're using fish
|
||||
# use path+="$(brew --prefix llvm@19)/bin" if you are using zsh
|
||||
$ export PATH="$(brew --prefix llvm@19)/bin:$PATH"
|
||||
# use path+="$(brew --prefix llvm@21)/bin" if you are using zsh
|
||||
$ export PATH="$(brew --prefix llvm@21)/bin:$PATH"
|
||||
```
|
||||
|
||||
```bash#Arch
|
||||
# use fish_add_path if you're using fish
|
||||
$ export PATH="$PATH:/usr/lib/llvm19/bin"
|
||||
$ export PATH="$PATH:/usr/lib/llvm21/bin"
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
@@ -299,7 +299,7 @@ The issue may manifest when initially running `bun setup` as Clang being unable
|
||||
```
|
||||
The C++ compiler
|
||||
|
||||
"/usr/bin/clang++-19"
|
||||
"/usr/bin/clang++-21"
|
||||
|
||||
is not able to compile a simple test program.
|
||||
```
|
||||
|
||||
110
bench/snippets/abort-signal.mjs
Normal file
110
bench/snippets/abort-signal.mjs
Normal file
@@ -0,0 +1,110 @@
|
||||
// Benchmark for AbortController/AbortSignal abort() performance
|
||||
// Tests the optimization of skipping Event creation when no listeners are registered
|
||||
|
||||
import { bench, group, run } from "../runner.mjs";
|
||||
|
||||
// Warmup: ensure JIT compilation
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
const controller = new AbortController();
|
||||
controller.abort();
|
||||
}
|
||||
|
||||
group("AbortController.abort()", () => {
|
||||
bench("no listener", () => {
|
||||
const controller = new AbortController();
|
||||
controller.abort();
|
||||
});
|
||||
|
||||
bench("with addEventListener", () => {
|
||||
const controller = new AbortController();
|
||||
controller.signal.addEventListener("abort", () => {});
|
||||
controller.abort();
|
||||
});
|
||||
|
||||
bench("with onabort property", () => {
|
||||
const controller = new AbortController();
|
||||
controller.signal.onabort = () => {};
|
||||
controller.abort();
|
||||
});
|
||||
|
||||
bench("with 3 listeners", () => {
|
||||
const controller = new AbortController();
|
||||
controller.signal.addEventListener("abort", () => {});
|
||||
controller.signal.addEventListener("abort", () => {});
|
||||
controller.signal.addEventListener("abort", () => {});
|
||||
controller.abort();
|
||||
});
|
||||
});
|
||||
|
||||
group("AbortSignal static methods", () => {
|
||||
bench("AbortSignal.abort() - pre-aborted", () => {
|
||||
const signal = AbortSignal.abort();
|
||||
// Signal is already aborted, no event dispatch needed
|
||||
});
|
||||
|
||||
bench("AbortSignal.any([]) - empty array", () => {
|
||||
const signal = AbortSignal.any([]);
|
||||
});
|
||||
|
||||
bench("AbortSignal.any([signal, signal]) - 2 signals", () => {
|
||||
const a = new AbortController();
|
||||
const b = new AbortController();
|
||||
const signal = AbortSignal.any([a.signal, b.signal]);
|
||||
});
|
||||
|
||||
bench("AbortSignal.any() then abort - no listener", () => {
|
||||
const a = new AbortController();
|
||||
const b = new AbortController();
|
||||
const signal = AbortSignal.any([a.signal, b.signal]);
|
||||
a.abort();
|
||||
});
|
||||
|
||||
bench("AbortSignal.any() then abort - with listener", () => {
|
||||
const a = new AbortController();
|
||||
const b = new AbortController();
|
||||
const signal = AbortSignal.any([a.signal, b.signal]);
|
||||
signal.addEventListener("abort", () => {});
|
||||
a.abort();
|
||||
});
|
||||
});
|
||||
|
||||
group("AbortController creation only", () => {
|
||||
bench("new AbortController()", () => {
|
||||
const controller = new AbortController();
|
||||
});
|
||||
|
||||
bench("new AbortController() + access signal", () => {
|
||||
const controller = new AbortController();
|
||||
const signal = controller.signal;
|
||||
});
|
||||
});
|
||||
|
||||
group("AbortSignal.timeout()", () => {
|
||||
// Note: These don't actually wait for timeout, just measure creation overhead
|
||||
bench("AbortSignal.timeout(1000) creation", () => {
|
||||
const signal = AbortSignal.timeout(1000);
|
||||
});
|
||||
|
||||
bench("AbortSignal.timeout(0) creation", () => {
|
||||
const signal = AbortSignal.timeout(0);
|
||||
});
|
||||
});
|
||||
|
||||
group("abort with reason", () => {
|
||||
bench("abort() with no reason", () => {
|
||||
const controller = new AbortController();
|
||||
controller.abort();
|
||||
});
|
||||
|
||||
bench("abort() with string reason", () => {
|
||||
const controller = new AbortController();
|
||||
controller.abort("cancelled");
|
||||
});
|
||||
|
||||
bench("abort() with Error reason", () => {
|
||||
const controller = new AbortController();
|
||||
controller.abort(new Error("cancelled"));
|
||||
});
|
||||
});
|
||||
|
||||
await run();
|
||||
@@ -105,6 +105,10 @@ summary(() => {
|
||||
bench(`small (${small.length} chars) - Bun.markdown.render`, () => {
|
||||
return Bun.markdown.render(small, renderCallbacks);
|
||||
});
|
||||
|
||||
bench(`small (${small.length} chars) - Bun.markdown.react`, () => {
|
||||
return Bun.markdown.react(small);
|
||||
});
|
||||
}
|
||||
|
||||
bench(`small (${small.length} chars) - marked`, () => {
|
||||
@@ -125,6 +129,10 @@ summary(() => {
|
||||
bench(`medium (${medium.length} chars) - Bun.markdown.render`, () => {
|
||||
return Bun.markdown.render(medium, renderCallbacks);
|
||||
});
|
||||
|
||||
bench(`medium (${medium.length} chars) - Bun.markdown.react`, () => {
|
||||
return Bun.markdown.react(medium);
|
||||
});
|
||||
}
|
||||
|
||||
bench(`medium (${medium.length} chars) - marked`, () => {
|
||||
@@ -145,6 +153,10 @@ summary(() => {
|
||||
bench(`large (${large.length} chars) - Bun.markdown.render`, () => {
|
||||
return Bun.markdown.render(large, renderCallbacks);
|
||||
});
|
||||
|
||||
bench(`large (${large.length} chars) - Bun.markdown.react`, () => {
|
||||
return Bun.markdown.react(large);
|
||||
});
|
||||
}
|
||||
|
||||
bench(`large (${large.length} chars) - marked`, () => {
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
"src/io/*.cpp",
|
||||
"src/bun.js/modules/*.cpp",
|
||||
"src/bun.js/bindings/*.cpp",
|
||||
"src/bun.js/bindings/git/*.cpp",
|
||||
"src/bun.js/bindings/webcore/*.cpp",
|
||||
"src/bun.js/bindings/sqlite/*.cpp",
|
||||
"src/bun.js/bindings/webcrypto/*.cpp",
|
||||
|
||||
@@ -54,6 +54,7 @@ set(BUN_DEPENDENCIES
|
||||
Cares
|
||||
Highway
|
||||
LibDeflate
|
||||
Libgit2
|
||||
LolHtml
|
||||
Lshpack
|
||||
Mimalloc
|
||||
@@ -1016,6 +1017,7 @@ if(NOT WIN32)
|
||||
-Wno-unused-function
|
||||
-Wno-c++23-lambda-attributes
|
||||
-Wno-nullability-completeness
|
||||
-Wno-character-conversion
|
||||
-Werror
|
||||
)
|
||||
else()
|
||||
@@ -1033,6 +1035,7 @@ if(NOT WIN32)
|
||||
-Werror=sometimes-uninitialized
|
||||
-Wno-c++23-lambda-attributes
|
||||
-Wno-nullability-completeness
|
||||
-Wno-character-conversion
|
||||
-Werror
|
||||
)
|
||||
|
||||
@@ -1061,6 +1064,7 @@ else()
|
||||
-Wno-inconsistent-dllimport
|
||||
-Wno-incompatible-pointer-types
|
||||
-Wno-deprecated-declarations
|
||||
-Wno-character-conversion
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -1136,6 +1140,15 @@ if(LINUX)
|
||||
-Wl,--wrap=pow
|
||||
-Wl,--wrap=powf
|
||||
)
|
||||
|
||||
# Disable LTO for workaround-missing-symbols.cpp to prevent LLD 21 from emitting
|
||||
# glibc versioned symbol names (e.g. exp@GLIBC_2.17) from .symver directives into
|
||||
# the .lto_discard assembler directive, which fails to parse the '@' character.
|
||||
if(ENABLE_LTO)
|
||||
set_source_files_properties(${CWD}/src/bun.js/bindings/workaround-missing-symbols.cpp
|
||||
PROPERTIES COMPILE_OPTIONS "-fno-lto"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT ABI STREQUAL "musl")
|
||||
@@ -1310,7 +1323,7 @@ list(TRANSFORM BUN_DEPENDENCIES TOLOWER OUTPUT_VARIABLE BUN_TARGETS)
|
||||
add_custom_target(dependencies DEPENDS ${BUN_TARGETS})
|
||||
|
||||
if(APPLE)
|
||||
target_link_libraries(${bun} PRIVATE icucore resolv)
|
||||
target_link_libraries(${bun} PRIVATE icucore resolv iconv)
|
||||
target_compile_definitions(${bun} PRIVATE U_DISABLE_RENAMING=1)
|
||||
endif()
|
||||
|
||||
|
||||
40
cmake/targets/BuildLibgit2.cmake
Normal file
40
cmake/targets/BuildLibgit2.cmake
Normal file
@@ -0,0 +1,40 @@
|
||||
register_repository(
|
||||
NAME
|
||||
libgit2
|
||||
REPOSITORY
|
||||
libgit2/libgit2
|
||||
TAG
|
||||
v1.9.0
|
||||
)
|
||||
|
||||
register_cmake_command(
|
||||
TARGET
|
||||
libgit2
|
||||
TARGETS
|
||||
libgit2package
|
||||
ARGS
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
-DBUILD_SHARED_LIBS=OFF
|
||||
-DBUILD_TESTS=OFF
|
||||
-DBUILD_CLI=OFF
|
||||
-DBUILD_EXAMPLES=OFF
|
||||
-DBUILD_FUZZERS=OFF
|
||||
# Network disabled - local operations only
|
||||
-DUSE_HTTPS=OFF
|
||||
-DUSE_SSH=OFF
|
||||
# Use bundled dependencies to avoid symbol conflicts with Bun's libraries
|
||||
-DUSE_BUNDLED_ZLIB=ON
|
||||
-DUSE_HTTP_PARSER=builtin
|
||||
-DREGEX_BACKEND=builtin
|
||||
-DUSE_SHA1=CollisionDetection
|
||||
# Enable threading
|
||||
-DUSE_THREADS=ON
|
||||
# Disable authentication features (not needed for local operations)
|
||||
-DUSE_GSSAPI=OFF
|
||||
LIB_PATH
|
||||
.
|
||||
LIBRARIES
|
||||
git2
|
||||
INCLUDES
|
||||
include
|
||||
)
|
||||
@@ -12,13 +12,7 @@ if(NOT ENABLE_LLVM)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# LLVM 21 is required for Windows ARM64 (first version with ARM64 Windows builds)
|
||||
# Other platforms use LLVM 19.1.7
|
||||
if(WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64|AARCH64")
|
||||
set(DEFAULT_LLVM_VERSION "21.1.8")
|
||||
else()
|
||||
set(DEFAULT_LLVM_VERSION "19.1.7")
|
||||
endif()
|
||||
set(DEFAULT_LLVM_VERSION "21.1.8")
|
||||
|
||||
optionx(LLVM_VERSION STRING "The version of LLVM to use" DEFAULT ${DEFAULT_LLVM_VERSION})
|
||||
|
||||
@@ -27,6 +21,8 @@ if(USE_LLVM_VERSION)
|
||||
set(LLVM_VERSION_MAJOR ${CMAKE_MATCH_1})
|
||||
set(LLVM_VERSION_MINOR ${CMAKE_MATCH_2})
|
||||
set(LLVM_VERSION_PATCH ${CMAKE_MATCH_3})
|
||||
# Accept any LLVM version within the same major.minor range (e.g. Alpine 3.23 ships 21.1.2)
|
||||
set(LLVM_VERSION_RANGE ">=${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.0 <${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.99")
|
||||
endif()
|
||||
|
||||
set(LLVM_PATHS)
|
||||
@@ -78,14 +74,12 @@ macro(find_llvm_command variable command)
|
||||
)
|
||||
endif()
|
||||
|
||||
math(EXPR LLVM_VERSION_NEXT_MAJOR "${LLVM_VERSION_MAJOR} + 1")
|
||||
|
||||
find_command(
|
||||
VARIABLE ${variable}
|
||||
VERSION_VARIABLE LLVM_VERSION
|
||||
COMMAND ${commands}
|
||||
PATHS ${LLVM_PATHS}
|
||||
VERSION ">=${LLVM_VERSION_MAJOR}.1.0 <${LLVM_VERSION_NEXT_MAJOR}.0.0"
|
||||
VERSION "${LLVM_VERSION_RANGE}"
|
||||
)
|
||||
list(APPEND CMAKE_ARGS -D${variable}=${${variable}})
|
||||
endmacro()
|
||||
|
||||
@@ -6,7 +6,7 @@ option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of down
|
||||
option(WEBKIT_BUILD_TYPE "The build type for local WebKit (defaults to CMAKE_BUILD_TYPE)")
|
||||
|
||||
if(NOT WEBKIT_VERSION)
|
||||
set(WEBKIT_VERSION 515344bc5d65aa2d4f9ff277b5fb944f0e051dcd)
|
||||
set(WEBKIT_VERSION 7bc2f97e28353062bb54776ce01e4c2ff24c35cc)
|
||||
endif()
|
||||
|
||||
# Use preview build URL for Windows ARM64 until the fix is merged to main
|
||||
|
||||
@@ -35,7 +35,7 @@ winget install "Visual Studio Community 2022" --override "--add Microsoft.Visual
|
||||
|
||||
After Visual Studio, you need the following:
|
||||
|
||||
- LLVM (19.1.7 for x64, 21.1.8 for ARM64)
|
||||
- LLVM 21.1.8
|
||||
- Go
|
||||
- Rust
|
||||
- NASM
|
||||
@@ -51,7 +51,7 @@ After Visual Studio, you need the following:
|
||||
irm https://get.scoop.sh | iex
|
||||
scoop install nodejs-lts go rust nasm ruby perl ccache
|
||||
# scoop seems to be buggy if you install llvm and the rest at the same time
|
||||
scoop install llvm@19.1.7
|
||||
scoop install llvm@21.1.8
|
||||
```
|
||||
|
||||
For Windows ARM64, download LLVM 21.1.8 directly from GitHub releases (first version with ARM64 Windows builds):
|
||||
|
||||
@@ -40,7 +40,7 @@ sudo pacman -S base-devel cmake git go libiconv libtool make ninja pkg-config py
|
||||
```
|
||||
|
||||
```bash Fedora
|
||||
sudo dnf install cargo clang19 llvm19 lld19 cmake git golang libtool ninja-build pkg-config rustc ruby libatomic-static libstdc++-static sed unzip which libicu-devel 'perl(Math::BigInt)'
|
||||
sudo dnf install cargo clang21 llvm21 lld21 cmake git golang libtool ninja-build pkg-config rustc ruby libatomic-static libstdc++-static sed unzip which libicu-devel 'perl(Math::BigInt)'
|
||||
```
|
||||
|
||||
```bash openSUSE Tumbleweed
|
||||
@@ -95,17 +95,17 @@ Our build scripts will automatically detect and use `ccache` if available. You c
|
||||
|
||||
## Install LLVM
|
||||
|
||||
Bun requires LLVM 19 (`clang` is part of LLVM). This version requirement is to match WebKit (precompiled), as mismatching versions will cause memory allocation failures at runtime. In most cases, you can install LLVM through your system package manager:
|
||||
Bun requires LLVM 21.1.8 (`clang` is part of LLVM). This version is enforced by the build system — mismatching versions will cause memory allocation failures at runtime. In most cases, you can install LLVM through your system package manager:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash macOS (Homebrew)
|
||||
brew install llvm@19
|
||||
brew install llvm@21
|
||||
```
|
||||
|
||||
```bash Ubuntu/Debian
|
||||
# LLVM has an automatic installation script that is compatible with all versions of Ubuntu
|
||||
wget https://apt.llvm.org/llvm.sh -O - | sudo bash -s -- 19 all
|
||||
wget https://apt.llvm.org/llvm.sh -O - | sudo bash -s -- 21 all
|
||||
```
|
||||
|
||||
```bash Arch
|
||||
@@ -117,17 +117,17 @@ sudo dnf install llvm clang lld-devel
|
||||
```
|
||||
|
||||
```bash openSUSE Tumbleweed
|
||||
sudo zypper install clang19 lld19 llvm19
|
||||
sudo zypper install clang21 lld21 llvm21
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
If none of the above solutions apply, you will have to install it [manually](https://github.com/llvm/llvm-project/releases/tag/llvmorg-19.1.7).
|
||||
If none of the above solutions apply, you will have to install it [manually](https://github.com/llvm/llvm-project/releases/tag/llvmorg-21.1.8).
|
||||
|
||||
Make sure Clang/LLVM 19 is in your path:
|
||||
Make sure Clang/LLVM 21 is in your path:
|
||||
|
||||
```bash
|
||||
which clang-19
|
||||
which clang-21
|
||||
```
|
||||
|
||||
If not, run this to manually add it:
|
||||
@@ -136,13 +136,13 @@ If not, run this to manually add it:
|
||||
|
||||
```bash macOS (Homebrew)
|
||||
# use fish_add_path if you're using fish
|
||||
# use path+="$(brew --prefix llvm@19)/bin" if you are using zsh
|
||||
export PATH="$(brew --prefix llvm@19)/bin:$PATH"
|
||||
# use path+="$(brew --prefix llvm@21)/bin" if you are using zsh
|
||||
export PATH="$(brew --prefix llvm@21)/bin:$PATH"
|
||||
```
|
||||
|
||||
```bash Arch
|
||||
# use fish_add_path if you're using fish
|
||||
export PATH="$PATH:/usr/lib/llvm19/bin"
|
||||
export PATH="$PATH:/usr/lib/llvm21/bin"
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -309,7 +309,7 @@ The issue may manifest when initially running `bun setup` as Clang being unable
|
||||
```txt
|
||||
The C++ compiler
|
||||
|
||||
"/usr/bin/clang++-19"
|
||||
"/usr/bin/clang++-21"
|
||||
|
||||
is not able to compile a simple test program.
|
||||
```
|
||||
|
||||
10
flake.nix
10
flake.nix
@@ -26,10 +26,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
# LLVM 19 - matching the bootstrap script (targets 19.1.7, actual version from nixpkgs-unstable)
|
||||
llvm = pkgs.llvm_19;
|
||||
clang = pkgs.clang_19;
|
||||
lld = pkgs.lld_19;
|
||||
# LLVM 21 - matching the bootstrap script (targets 21.1.8, actual version from nixpkgs-unstable)
|
||||
llvm = pkgs.llvm_21;
|
||||
clang = pkgs.clang_21;
|
||||
lld = pkgs.lld_21;
|
||||
|
||||
# Node.js 24 - matching the bootstrap script (targets 24.3.0, actual version from nixpkgs-unstable)
|
||||
nodejs = pkgs.nodejs_24;
|
||||
@@ -42,7 +42,7 @@
|
||||
pkgs.pkg-config
|
||||
pkgs.ccache
|
||||
|
||||
# Compilers and toolchain - version pinned to LLVM 19
|
||||
# Compilers and toolchain - version pinned to LLVM 21
|
||||
clang
|
||||
llvm
|
||||
lld
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Bun
|
||||
|
||||
This is the Windows ARM64 binary for Bun, a fast all-in-one JavaScript runtime. https://bun.com
|
||||
@@ -95,6 +95,12 @@ export const platforms: Platform[] = [
|
||||
bin: "bun-windows-x64-baseline",
|
||||
exe: "bin/bun.exe",
|
||||
},
|
||||
{
|
||||
os: "win32",
|
||||
arch: "arm64",
|
||||
bin: "bun-windows-aarch64",
|
||||
exe: "bin/bun.exe",
|
||||
},
|
||||
];
|
||||
|
||||
export const supportedPlatforms: Platform[] = platforms
|
||||
|
||||
2
packages/bun-types/bun.d.ts
vendored
2
packages/bun-types/bun.d.ts
vendored
@@ -2438,7 +2438,7 @@ declare module "bun" {
|
||||
| `bun-linux-${Architecture}-${Libc}`
|
||||
| `bun-linux-${Architecture}-${SIMD}`
|
||||
| `bun-linux-${Architecture}-${SIMD}-${Libc}`
|
||||
| "bun-windows-x64"
|
||||
| `bun-windows-${Architecture}`
|
||||
| `bun-windows-x64-${SIMD}`;
|
||||
}
|
||||
|
||||
|
||||
642
packages/bun-types/git.d.ts
vendored
Normal file
642
packages/bun-types/git.d.ts
vendored
Normal file
@@ -0,0 +1,642 @@
|
||||
/**
|
||||
* Fast Git operations for Bun.js powered by libgit2.
|
||||
*
|
||||
* This module provides read-only Git repository operations.
|
||||
* Network operations (HTTPS/SSH) are not supported - local operations only.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { Repository } from 'bun:git';
|
||||
*
|
||||
* const repo = Repository.open('.');
|
||||
* const head = repo.head();
|
||||
* console.log(`HEAD: ${head.id} - ${head.summary}`);
|
||||
* console.log(`Author: ${head.author.name} <${head.author.email}>`);
|
||||
* ```
|
||||
*
|
||||
* @module bun:git
|
||||
*/
|
||||
declare module "bun:git" {
|
||||
/**
|
||||
* Represents a Git signature (author or committer information).
|
||||
*/
|
||||
export interface Signature {
|
||||
/**
|
||||
* The name of the person.
|
||||
* @example "John Doe"
|
||||
*/
|
||||
readonly name: string;
|
||||
|
||||
/**
|
||||
* The email address of the person.
|
||||
* @example "john@example.com"
|
||||
*/
|
||||
readonly email: string;
|
||||
|
||||
/**
|
||||
* Unix timestamp of when the signature was created.
|
||||
* @example 1704067200
|
||||
*/
|
||||
readonly time: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Status flags for working directory entries.
|
||||
* These are bit flags that can be combined with bitwise OR.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { Status } from 'bun:git';
|
||||
*
|
||||
* const entries = repo.getStatus();
|
||||
* for (const entry of entries) {
|
||||
* if (entry.status & Status.WT_MODIFIED) {
|
||||
* console.log('Modified in workdir:', entry.path);
|
||||
* }
|
||||
* if (entry.status & Status.INDEX_NEW) {
|
||||
* console.log('New in index:', entry.path);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export const Status: {
|
||||
/** Entry is current and unchanged */
|
||||
readonly CURRENT: 0;
|
||||
/** Entry is new in the index */
|
||||
readonly INDEX_NEW: 1;
|
||||
/** Entry is modified in the index */
|
||||
readonly INDEX_MODIFIED: 2;
|
||||
/** Entry is deleted in the index */
|
||||
readonly INDEX_DELETED: 4;
|
||||
/** Entry is renamed in the index */
|
||||
readonly INDEX_RENAMED: 8;
|
||||
/** Entry type changed in the index */
|
||||
readonly INDEX_TYPECHANGE: 16;
|
||||
/** Entry is new in the working tree */
|
||||
readonly WT_NEW: 128;
|
||||
/** Entry is modified in the working tree */
|
||||
readonly WT_MODIFIED: 256;
|
||||
/** Entry is deleted in the working tree */
|
||||
readonly WT_DELETED: 512;
|
||||
/** Entry type changed in the working tree */
|
||||
readonly WT_TYPECHANGE: 1024;
|
||||
/** Entry is renamed in the working tree */
|
||||
readonly WT_RENAMED: 2048;
|
||||
/** Entry is ignored */
|
||||
readonly IGNORED: 16384;
|
||||
/** Entry is conflicted */
|
||||
readonly CONFLICTED: 32768;
|
||||
};
|
||||
|
||||
/**
|
||||
* Delta types for diff entries.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { DeltaType } from 'bun:git';
|
||||
*
|
||||
* const diff = repo.diff();
|
||||
* for (const file of diff.files) {
|
||||
* if (file.status === DeltaType.ADDED) {
|
||||
* console.log('Added:', file.newPath);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export const DeltaType: {
|
||||
/** No changes */
|
||||
readonly UNMODIFIED: 0;
|
||||
/** Entry does not exist in old version */
|
||||
readonly ADDED: 1;
|
||||
/** Entry does not exist in new version */
|
||||
readonly DELETED: 2;
|
||||
/** Entry content changed between old and new */
|
||||
readonly MODIFIED: 3;
|
||||
/** Entry was renamed between old and new */
|
||||
readonly RENAMED: 4;
|
||||
/** Entry was copied from another old entry */
|
||||
readonly COPIED: 5;
|
||||
/** Entry is ignored item in workdir */
|
||||
readonly IGNORED: 6;
|
||||
/** Entry is untracked item in workdir */
|
||||
readonly UNTRACKED: 7;
|
||||
/** Entry type changed between old and new */
|
||||
readonly TYPECHANGE: 8;
|
||||
/** Entry is unreadable */
|
||||
readonly CONFLICTED: 10;
|
||||
};
|
||||
|
||||
/**
|
||||
* Options for getting repository status.
|
||||
*/
|
||||
export interface StatusOptions {
|
||||
/**
|
||||
* Include untracked files in the status.
|
||||
* @default true
|
||||
*/
|
||||
includeUntracked?: boolean;
|
||||
|
||||
/**
|
||||
* Include ignored files in the status.
|
||||
* @default false
|
||||
*/
|
||||
includeIgnored?: boolean;
|
||||
|
||||
/**
|
||||
* Recurse into untracked directories.
|
||||
* @default true
|
||||
*/
|
||||
recurseUntrackedDirs?: boolean;
|
||||
|
||||
/**
|
||||
* Detect renamed files.
|
||||
* @default false
|
||||
*/
|
||||
detectRenames?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a status entry for a file in the working directory.
|
||||
*/
|
||||
export class StatusEntry {
|
||||
/**
|
||||
* The path of the file relative to the repository root.
|
||||
*/
|
||||
readonly path: string;
|
||||
|
||||
/**
|
||||
* Status flags (combination of Status values).
|
||||
*/
|
||||
readonly status: number;
|
||||
|
||||
/**
|
||||
* Check if the entry is new (untracked or staged as new).
|
||||
*/
|
||||
isNew(): boolean;
|
||||
|
||||
/**
|
||||
* Check if the entry is modified.
|
||||
*/
|
||||
isModified(): boolean;
|
||||
|
||||
/**
|
||||
* Check if the entry is deleted.
|
||||
*/
|
||||
isDeleted(): boolean;
|
||||
|
||||
/**
|
||||
* Check if the entry is renamed.
|
||||
*/
|
||||
isRenamed(): boolean;
|
||||
|
||||
/**
|
||||
* Check if the entry is ignored.
|
||||
*/
|
||||
isIgnored(): boolean;
|
||||
|
||||
/**
|
||||
* Check if the entry has changes staged in the index.
|
||||
*/
|
||||
inIndex(): boolean;
|
||||
|
||||
/**
|
||||
* Check if the entry has changes in the working tree.
|
||||
*/
|
||||
inWorkingTree(): boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an entry in the Git index.
|
||||
*/
|
||||
export interface IndexEntry {
|
||||
/**
|
||||
* The path of the file relative to the repository root.
|
||||
*/
|
||||
readonly path: string;
|
||||
|
||||
/**
|
||||
* The file mode (e.g., 0o100644 for regular files).
|
||||
*/
|
||||
readonly mode: number;
|
||||
|
||||
/**
|
||||
* The blob OID (SHA-1 hash) of the file content.
|
||||
*/
|
||||
readonly oid: string;
|
||||
|
||||
/**
|
||||
* The stage number (0 for normal, 1-3 for conflict stages).
|
||||
*/
|
||||
readonly stage: number;
|
||||
|
||||
/**
|
||||
* The file size in bytes.
|
||||
*/
|
||||
readonly size: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for getting diff information.
|
||||
*/
|
||||
export interface DiffOptions {
|
||||
/**
|
||||
* If true, compare HEAD to index (staged changes).
|
||||
* If false, compare HEAD to working directory.
|
||||
* @default false
|
||||
*/
|
||||
cached?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a changed file in a diff.
|
||||
*/
|
||||
export interface DiffFile {
|
||||
/**
|
||||
* The type of change (see DeltaType).
|
||||
*/
|
||||
readonly status: number;
|
||||
|
||||
/**
|
||||
* The old path (null for added files).
|
||||
*/
|
||||
readonly oldPath: string | null;
|
||||
|
||||
/**
|
||||
* The new path.
|
||||
*/
|
||||
readonly newPath: string;
|
||||
|
||||
/**
|
||||
* Similarity percentage for renamed/copied files (0-100).
|
||||
*/
|
||||
readonly similarity?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of a diff operation.
|
||||
*/
|
||||
export interface DiffResult {
|
||||
/**
|
||||
* List of changed files.
|
||||
*/
|
||||
readonly files: DiffFile[];
|
||||
|
||||
/**
|
||||
* Statistics about the diff.
|
||||
*/
|
||||
readonly stats: {
|
||||
/** Number of files changed */
|
||||
readonly filesChanged: number;
|
||||
/** Total lines inserted */
|
||||
readonly insertions: number;
|
||||
/** Total lines deleted */
|
||||
readonly deletions: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for getting commit history.
|
||||
*/
|
||||
export interface LogOptions {
|
||||
/**
|
||||
* Starting point for history traversal.
|
||||
* @default "HEAD"
|
||||
*/
|
||||
from?: string;
|
||||
|
||||
/**
|
||||
* Range specification (e.g., "origin/main..HEAD").
|
||||
* If provided, `from` is ignored.
|
||||
*/
|
||||
range?: string;
|
||||
|
||||
/**
|
||||
* Maximum number of commits to return.
|
||||
* @default unlimited
|
||||
*/
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a Git commit object.
|
||||
*
|
||||
* A commit contains information about a snapshot of the repository,
|
||||
* including the author, committer, message, and parent commits.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const head = repo.head();
|
||||
* console.log(head.id); // "abc123..."
|
||||
* console.log(head.message); // "feat: add new feature\n\nDetailed description..."
|
||||
* console.log(head.summary); // "feat: add new feature"
|
||||
* ```
|
||||
*/
|
||||
export class Commit {
|
||||
/**
|
||||
* The full 40-character hexadecimal SHA-1 hash of the commit.
|
||||
* @example "a1b2c3d4e5f6..."
|
||||
*/
|
||||
readonly id: string;
|
||||
|
||||
/**
|
||||
* The full commit message, including the body.
|
||||
* @example "feat: add new feature\n\nThis commit adds..."
|
||||
*/
|
||||
readonly message: string;
|
||||
|
||||
/**
|
||||
* The first line of the commit message (the summary/title).
|
||||
* Does not include any trailing newline.
|
||||
* @example "feat: add new feature"
|
||||
*/
|
||||
readonly summary: string;
|
||||
|
||||
/**
|
||||
* The author of the commit (who wrote the changes).
|
||||
*/
|
||||
readonly author: Signature;
|
||||
|
||||
/**
|
||||
* The committer of the commit (who committed the changes).
|
||||
* This may differ from the author in cases like cherry-picks or rebases.
|
||||
*/
|
||||
readonly committer: Signature;
|
||||
|
||||
/**
|
||||
* Unix timestamp of when the commit was created.
|
||||
* This is the committer's timestamp.
|
||||
* @example 1704067200
|
||||
*/
|
||||
readonly time: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a Git repository.
|
||||
*
|
||||
* Use {@link Repository.open} to open an existing repository.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { Repository } from 'bun:git';
|
||||
*
|
||||
* // Open the repository at the current directory
|
||||
* const repo = Repository.open('.');
|
||||
*
|
||||
* // Get repository info
|
||||
* console.log('Path:', repo.path); // "/path/to/repo/.git/"
|
||||
* console.log('Workdir:', repo.workdir); // "/path/to/repo/"
|
||||
* console.log('Is bare:', repo.isBare); // false
|
||||
*
|
||||
* // Get the HEAD commit
|
||||
* const head = repo.head();
|
||||
* console.log('HEAD:', head.id.slice(0, 7), head.summary);
|
||||
* ```
|
||||
*/
|
||||
export class Repository {
|
||||
/**
|
||||
* Opens an existing Git repository.
|
||||
*
|
||||
* The path can point to either a working directory or a bare repository.
|
||||
* If the path points to a working directory, the `.git` directory will be located automatically.
|
||||
*
|
||||
* @param path Path to the repository (working directory or .git directory)
|
||||
* @returns A Repository instance
|
||||
* @throws Error if the path is not a valid Git repository
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // Open by working directory
|
||||
* const repo = Repository.open('/path/to/project');
|
||||
*
|
||||
* // Open by .git directory
|
||||
* const repo2 = Repository.open('/path/to/project/.git');
|
||||
*
|
||||
* // Open current directory
|
||||
* const repo3 = Repository.open('.');
|
||||
* ```
|
||||
*/
|
||||
static open(path: string): Repository;
|
||||
|
||||
/**
|
||||
* Gets the commit that HEAD currently points to.
|
||||
*
|
||||
* @returns The commit that HEAD references
|
||||
* @throws Error if HEAD is unborn (new repository with no commits)
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const head = repo.head();
|
||||
* console.log(`Current commit: ${head.summary}`);
|
||||
* console.log(`Author: ${head.author.name}`);
|
||||
* ```
|
||||
*/
|
||||
head(): Commit;
|
||||
|
||||
/**
|
||||
* The path to the `.git` directory.
|
||||
* Always ends with a trailing slash.
|
||||
*
|
||||
* @example "/Users/me/project/.git/"
|
||||
*/
|
||||
readonly path: string;
|
||||
|
||||
/**
|
||||
* The path to the working directory.
|
||||
* Returns `null` for bare repositories.
|
||||
* When present, always ends with a trailing slash.
|
||||
*
|
||||
* @example "/Users/me/project/"
|
||||
*/
|
||||
readonly workdir: string | null;
|
||||
|
||||
/**
|
||||
* Whether this is a bare repository.
|
||||
* Bare repositories have no working directory.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* if (repo.isBare) {
|
||||
* console.log('This is a bare repository');
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
readonly isBare: boolean;
|
||||
|
||||
/**
|
||||
* Gets the working directory status.
|
||||
*
|
||||
* Returns an array of status entries for all changed files in the
|
||||
* working directory and index.
|
||||
*
|
||||
* @param options Options to control which files are included
|
||||
* @returns Array of status entries
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { Repository, Status } from 'bun:git';
|
||||
*
|
||||
* const repo = Repository.open('.');
|
||||
* const status = repo.getStatus();
|
||||
*
|
||||
* for (const entry of status) {
|
||||
* if (entry.isModified()) {
|
||||
* console.log('Modified:', entry.path);
|
||||
* }
|
||||
* if (entry.isNew()) {
|
||||
* console.log('New:', entry.path);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
getStatus(options?: StatusOptions): StatusEntry[];
|
||||
|
||||
/**
|
||||
* Resolves a revision specification to a commit OID.
|
||||
*
|
||||
* Supports standard Git revision syntax including:
|
||||
* - Branch names: "main", "feature/foo"
|
||||
* - Tag names: "v1.0.0"
|
||||
* - SHA prefixes: "abc123"
|
||||
* - Special refs: "HEAD", "HEAD~1", "HEAD^2"
|
||||
* - Upstream: "@{u}", "main@{u}"
|
||||
*
|
||||
* @param spec The revision specification to resolve
|
||||
* @returns The 40-character hex OID
|
||||
* @throws Error if the spec cannot be resolved
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const headOid = repo.revParse('HEAD');
|
||||
* const parentOid = repo.revParse('HEAD~1');
|
||||
* const branchOid = repo.revParse('main');
|
||||
* ```
|
||||
*/
|
||||
revParse(spec: string): string;
|
||||
|
||||
/**
|
||||
* Gets the name of the current branch.
|
||||
*
|
||||
* @returns The branch name, or null if HEAD is detached or unborn
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const branch = repo.getCurrentBranch();
|
||||
* if (branch) {
|
||||
* console.log('On branch:', branch);
|
||||
* } else {
|
||||
* console.log('HEAD is detached');
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
getCurrentBranch(): string | null;
|
||||
|
||||
/**
|
||||
* Gets the ahead/behind counts between two commits.
|
||||
*
|
||||
* This is useful for comparing a local branch to its upstream.
|
||||
*
|
||||
* @param local The local ref (default: "HEAD")
|
||||
* @param upstream The upstream ref (default: "@{u}")
|
||||
* @returns Object with ahead and behind counts
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const { ahead, behind } = repo.aheadBehind();
|
||||
* console.log(`${ahead} ahead, ${behind} behind`);
|
||||
*
|
||||
* // Compare specific refs
|
||||
* const { ahead, behind } = repo.aheadBehind('feature', 'origin/main');
|
||||
* ```
|
||||
*/
|
||||
aheadBehind(local?: string, upstream?: string): { ahead: number; behind: number };
|
||||
|
||||
/**
|
||||
* Gets the list of files tracked in the index.
|
||||
*
|
||||
* @returns Array of index entries
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const files = repo.listFiles();
|
||||
* console.log(`Tracking ${files.length} files`);
|
||||
*
|
||||
* for (const file of files) {
|
||||
* console.log(`${file.path} (mode: ${file.mode.toString(8)})`);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
listFiles(): IndexEntry[];
|
||||
|
||||
/**
|
||||
* Gets diff information between HEAD and working directory or index.
|
||||
*
|
||||
* @param options Options to control the diff behavior
|
||||
* @returns Diff result with file list and statistics
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { Repository, DeltaType } from 'bun:git';
|
||||
*
|
||||
* const repo = Repository.open('.');
|
||||
*
|
||||
* // Unstaged changes (HEAD vs workdir)
|
||||
* const diff = repo.diff();
|
||||
* console.log(`${diff.stats.filesChanged} files changed`);
|
||||
* console.log(`+${diff.stats.insertions} -${diff.stats.deletions}`);
|
||||
*
|
||||
* // Staged changes (HEAD vs index)
|
||||
* const staged = repo.diff({ cached: true });
|
||||
*
|
||||
* for (const file of diff.files) {
|
||||
* if (file.status === DeltaType.MODIFIED) {
|
||||
* console.log('Modified:', file.newPath);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
diff(options?: DiffOptions): DiffResult;
|
||||
|
||||
/**
|
||||
* Counts the number of commits in a range.
|
||||
*
|
||||
* @param range Optional range specification (e.g., "origin/main..HEAD")
|
||||
* @returns Number of commits
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // Total commits
|
||||
* const total = repo.countCommits();
|
||||
*
|
||||
* // Commits since origin/main
|
||||
* const since = repo.countCommits('origin/main..HEAD');
|
||||
* ```
|
||||
*/
|
||||
countCommits(range?: string): number;
|
||||
|
||||
/**
|
||||
* Gets the commit history.
|
||||
*
|
||||
* @param options Options to control the log behavior
|
||||
* @returns Array of commits
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // Last 10 commits
|
||||
* const commits = repo.log({ limit: 10 });
|
||||
*
|
||||
* for (const commit of commits) {
|
||||
* console.log(`${commit.id.slice(0, 7)} ${commit.summary}`);
|
||||
* }
|
||||
*
|
||||
* // Commits in a range
|
||||
* const range = repo.log({ range: 'origin/main..HEAD' });
|
||||
*
|
||||
* // Commits from a specific ref
|
||||
* const fromTag = repo.log({ from: 'v1.0.0', limit: 5 });
|
||||
* ```
|
||||
*/
|
||||
log(options?: LogOptions): Commit[];
|
||||
}
|
||||
|
||||
export default Repository;
|
||||
}
|
||||
1
packages/bun-types/index.d.ts
vendored
1
packages/bun-types/index.d.ts
vendored
@@ -14,6 +14,7 @@
|
||||
/// <reference path="./html-rewriter.d.ts" />
|
||||
/// <reference path="./jsc.d.ts" />
|
||||
/// <reference path="./sqlite.d.ts" />
|
||||
/// <reference path="./git.d.ts" />
|
||||
/// <reference path="./test.d.ts" />
|
||||
/// <reference path="./wasm.d.ts" />
|
||||
/// <reference path="./overrides.d.ts" />
|
||||
|
||||
1
packages/bun-types/test.d.ts
vendored
1
packages/bun-types/test.d.ts
vendored
@@ -2179,6 +2179,7 @@ declare module "bun:test" {
|
||||
mockResolvedValueOnce(value: ResolveType<T>): this;
|
||||
mockRejectedValue(value: RejectType<T>): this;
|
||||
mockRejectedValueOnce(value: RejectType<T>): this;
|
||||
[Symbol.dispose](): void;
|
||||
}
|
||||
|
||||
// export type MockMetadata<T, MetadataType = MockMetadataType> = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Version: 11
|
||||
# Version: 12
|
||||
# A script that installs the dependencies needed to build and test Bun.
|
||||
# This should work on Windows 10 or newer with PowerShell.
|
||||
|
||||
@@ -387,7 +387,7 @@ function Install-PdbAddr2line {
|
||||
function Install-Llvm {
|
||||
Install-Package llvm `
|
||||
-Command clang-cl `
|
||||
-Version "19.1.7"
|
||||
-Version "21.1.8"
|
||||
Add-To-Path "$env:ProgramFiles\LLVM\bin"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
# Version: 27
|
||||
# Version: 28
|
||||
|
||||
# A script that installs the dependencies needed to build and test Bun.
|
||||
# This should work on macOS and Linux with a POSIX shell.
|
||||
@@ -1096,7 +1096,7 @@ install_build_essentials() {
|
||||
}
|
||||
|
||||
llvm_version_exact() {
|
||||
print "19.1.7"
|
||||
print "21.1.8"
|
||||
}
|
||||
|
||||
llvm_version() {
|
||||
@@ -1106,23 +1106,20 @@ llvm_version() {
|
||||
install_llvm() {
|
||||
case "$pm" in
|
||||
apt)
|
||||
# Debian 13 (Trixie) has LLVM 19 natively, and apt.llvm.org doesn't have a trixie repo
|
||||
if [ "$distro" = "debian" ]; then
|
||||
install_packages \
|
||||
"llvm-$(llvm_version)" \
|
||||
"clang-$(llvm_version)" \
|
||||
"lld-$(llvm_version)" \
|
||||
"llvm-$(llvm_version)-dev" \
|
||||
"llvm-$(llvm_version)-tools" \
|
||||
"libclang-rt-$(llvm_version)-dev"
|
||||
else
|
||||
bash="$(require bash)"
|
||||
llvm_script="$(download_file "https://apt.llvm.org/llvm.sh")"
|
||||
execute_sudo "$bash" "$llvm_script" "$(llvm_version)" all
|
||||
|
||||
# Install llvm-symbolizer explicitly to ensure it's available for ASAN
|
||||
install_packages "llvm-$(llvm_version)-tools"
|
||||
# apt.llvm.org's GPG key uses SHA1, which Debian 13+ (sqv) rejects since 2026-02-01.
|
||||
# Override the sequoia crypto policy to extend the SHA1 deadline.
|
||||
# See: https://github.com/llvm/llvm-project/issues/153385
|
||||
if [ -x /usr/bin/sqv ] && [ -f /usr/share/apt/default-sequoia.config ]; then
|
||||
execute_sudo mkdir -p /etc/crypto-policies/back-ends
|
||||
execute_sudo /usr/bin/sh -c "sed 's/sha1.second_preimage_resistance = 2026-02-01/sha1.second_preimage_resistance = 2028-02-01/' /usr/share/apt/default-sequoia.config > /etc/crypto-policies/back-ends/apt-sequoia.config"
|
||||
fi
|
||||
|
||||
bash="$(require bash)"
|
||||
llvm_script="$(download_file "https://apt.llvm.org/llvm.sh")"
|
||||
execute_sudo "$bash" "$llvm_script" "$(llvm_version)" all
|
||||
|
||||
# Install llvm-symbolizer explicitly to ensure it's available for ASAN
|
||||
install_packages "llvm-$(llvm_version)-tools"
|
||||
;;
|
||||
brew)
|
||||
install_packages "llvm@$(llvm_version)"
|
||||
@@ -1177,7 +1174,7 @@ install_gcc() {
|
||||
;;
|
||||
esac
|
||||
|
||||
llvm_v="19"
|
||||
llvm_v="21"
|
||||
|
||||
append_to_profile "export CC=clang-${llvm_v}"
|
||||
append_to_profile "export CXX=clang++-${llvm_v}"
|
||||
|
||||
@@ -77,10 +77,10 @@ const HAS_CCACHE = CCACHE !== null;
|
||||
// On Windows, use clang-cl for MSVC compatibility
|
||||
const CC_BASE = IS_WINDOWS
|
||||
? findExecutable(["clang-cl.exe", "clang-cl"]) || "clang-cl"
|
||||
: findExecutable(["clang-19", "clang"]) || "clang";
|
||||
: findExecutable(["clang-21", "clang"]) || "clang";
|
||||
const CXX_BASE = IS_WINDOWS
|
||||
? findExecutable(["clang-cl.exe", "clang-cl"]) || "clang-cl"
|
||||
: findExecutable(["clang++-19", "clang++"]) || "clang++";
|
||||
: findExecutable(["clang++-21", "clang++"]) || "clang++";
|
||||
|
||||
const CC = HAS_CCACHE ? CCACHE : CC_BASE;
|
||||
const CXX = HAS_CCACHE ? CCACHE : CXX_BASE;
|
||||
|
||||
@@ -12,7 +12,7 @@ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
MODE="${1:-format}"
|
||||
|
||||
# Use LLVM_VERSION_MAJOR from environment or default to 19
|
||||
LLVM_VERSION="${LLVM_VERSION_MAJOR:-19}"
|
||||
LLVM_VERSION="${LLVM_VERSION_MAJOR:-21}"
|
||||
|
||||
# Ensure we have the specific clang-format version
|
||||
CLANG_FORMAT="clang-format-${LLVM_VERSION}"
|
||||
|
||||
16
shell.nix
16
shell.nix
@@ -8,9 +8,9 @@ pkgs.mkShell rec {
|
||||
# Core build tools (matching bootstrap.sh)
|
||||
cmake
|
||||
ninja
|
||||
clang_19
|
||||
llvm_19
|
||||
lld_19
|
||||
clang_21
|
||||
llvm_21
|
||||
lld_21
|
||||
nodejs_24
|
||||
bun
|
||||
rustc
|
||||
@@ -77,10 +77,10 @@ pkgs.mkShell rec {
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
export CC="${pkgs.lib.getExe pkgs.clang_19}"
|
||||
export CXX="${pkgs.lib.getExe' pkgs.clang_19 "clang++"}"
|
||||
export AR="${pkgs.llvm_19}/bin/llvm-ar"
|
||||
export RANLIB="${pkgs.llvm_19}/bin/llvm-ranlib"
|
||||
export CC="${pkgs.lib.getExe pkgs.clang_21}"
|
||||
export CXX="${pkgs.lib.getExe' pkgs.clang_21 "clang++"}"
|
||||
export AR="${pkgs.llvm_21}/bin/llvm-ar"
|
||||
export RANLIB="${pkgs.llvm_21}/bin/llvm-ranlib"
|
||||
export CMAKE_C_COMPILER="$CC"
|
||||
export CMAKE_CXX_COMPILER="$CXX"
|
||||
export CMAKE_AR="$AR"
|
||||
@@ -88,7 +88,7 @@ pkgs.mkShell rec {
|
||||
export CMAKE_SYSTEM_PROCESSOR=$(uname -m)
|
||||
export TMPDIR=''${TMPDIR:-/tmp}
|
||||
'' + pkgs.lib.optionalString pkgs.stdenv.isLinux ''
|
||||
export LD="${pkgs.lib.getExe' pkgs.lld_19 "ld.lld"}"
|
||||
export LD="${pkgs.lib.getExe' pkgs.lld_21 "ld.lld"}"
|
||||
export NIX_CFLAGS_LINK="''${NIX_CFLAGS_LINK:+$NIX_CFLAGS_LINK }-fuse-ld=lld"
|
||||
export LD_LIBRARY_PATH="${pkgs.lib.makeLibraryPath packages}''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||
'' + ''
|
||||
|
||||
@@ -10,6 +10,7 @@ pub const HardcodedModule = enum {
|
||||
@"bun:test",
|
||||
@"bun:wrap",
|
||||
@"bun:sqlite",
|
||||
@"bun:git",
|
||||
@"node:assert",
|
||||
@"node:assert/strict",
|
||||
@"node:async_hooks",
|
||||
@@ -98,6 +99,7 @@ pub const HardcodedModule = enum {
|
||||
.{ "bun:main", .@"bun:main" },
|
||||
.{ "bun:test", .@"bun:test" },
|
||||
.{ "bun:sqlite", .@"bun:sqlite" },
|
||||
.{ "bun:git", .@"bun:git" },
|
||||
.{ "bun:wrap", .@"bun:wrap" },
|
||||
.{ "bun:internal-for-testing", .@"bun:internal-for-testing" },
|
||||
// Node.js
|
||||
@@ -366,6 +368,7 @@ pub const HardcodedModule = enum {
|
||||
.{ "bun:ffi", .{ .path = "bun:ffi" } },
|
||||
.{ "bun:jsc", .{ .path = "bun:jsc" } },
|
||||
.{ "bun:sqlite", .{ .path = "bun:sqlite" } },
|
||||
.{ "bun:git", .{ .path = "bun:git" } },
|
||||
.{ "bun:wrap", .{ .path = "bun:wrap" } },
|
||||
.{ "bun:internal-for-testing", .{ .path = "bun:internal-for-testing" } },
|
||||
.{ "ffi", .{ .path = "bun:ffi" } },
|
||||
|
||||
@@ -7,6 +7,7 @@ const VirtualMachine = @This();
|
||||
|
||||
export var has_bun_garbage_collector_flag_enabled = false;
|
||||
pub export var isBunTest: bool = false;
|
||||
pub export var Bun__defaultRemainingRunsUntilSkipReleaseAccess: c_int = 10;
|
||||
|
||||
// TODO: evaluate if this has any measurable performance impact.
|
||||
pub var synthetic_allocation_limit: usize = std.math.maxInt(u32);
|
||||
|
||||
@@ -464,8 +464,8 @@ const ParseRenderer = struct {
|
||||
const entry = self.#stack.pop().?;
|
||||
const g = self.#globalObject;
|
||||
|
||||
// Determine HTML tag name
|
||||
const type_str: []const u8 = blockTypeName(block_type, entry.data);
|
||||
// Determine HTML tag index for cached string
|
||||
const tag_index = getBlockTypeTag(block_type, entry.data);
|
||||
|
||||
// For headings, compute slug before counting props
|
||||
const slug: ?[]const u8 = if (block_type == .h) self.#heading_tracker.leaveHeading(bun.default_allocator) else null;
|
||||
@@ -496,7 +496,7 @@ const ParseRenderer = struct {
|
||||
|
||||
// Build React element — use component override as type if set
|
||||
const component = self.getBlockComponent(block_type, entry.data);
|
||||
const type_val: JSValue = if (component != .zero) component else try bun.String.createUTF8ForJS(g, type_str);
|
||||
const type_val: JSValue = if (component != .zero) component else getCachedTagString(g, tag_index);
|
||||
|
||||
const props = JSValue.createEmptyObject(g, props_count);
|
||||
self.#marked_args.append(props);
|
||||
@@ -572,7 +572,7 @@ const ParseRenderer = struct {
|
||||
const entry = self.#stack.pop().?;
|
||||
const g = self.#globalObject;
|
||||
|
||||
const type_str: []const u8 = spanTypeName(span_type);
|
||||
const tag_index = getSpanTypeTag(span_type);
|
||||
|
||||
// Count props fields: always children (or alt for img) + metadata
|
||||
var props_count: usize = 1; // children (or alt for img)
|
||||
@@ -592,7 +592,7 @@ const ParseRenderer = struct {
|
||||
|
||||
// Build React element: { $$typeof, type, key, ref, props }
|
||||
const component = self.getSpanComponent(span_type);
|
||||
const type_val: JSValue = if (component != .zero) component else try bun.String.createUTF8ForJS(g, type_str);
|
||||
const type_val: JSValue = if (component != .zero) component else getCachedTagString(g, tag_index);
|
||||
|
||||
const props = JSValue.createEmptyObject(g, props_count);
|
||||
self.#marked_args.append(props);
|
||||
@@ -675,7 +675,7 @@ const ParseRenderer = struct {
|
||||
switch (text_type) {
|
||||
.br => {
|
||||
const br_component = self.#components.br;
|
||||
const br_type: JSValue = if (br_component != .zero) br_component else try bun.String.createUTF8ForJS(g, "br");
|
||||
const br_type: JSValue = if (br_component != .zero) br_component else getCachedTagString(g, .br);
|
||||
const empty_props = JSValue.createEmptyObject(g, 0);
|
||||
self.#marked_args.append(empty_props);
|
||||
const obj = self.createElement(br_type, empty_props);
|
||||
@@ -705,53 +705,6 @@ const ParseRenderer = struct {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Type name mappings
|
||||
// ========================================
|
||||
|
||||
fn blockTypeName(block_type: md.BlockType, data: u32) []const u8 {
|
||||
return switch (block_type) {
|
||||
.h => switch (data) {
|
||||
1 => "h1",
|
||||
2 => "h2",
|
||||
3 => "h3",
|
||||
4 => "h4",
|
||||
5 => "h5",
|
||||
else => "h6",
|
||||
},
|
||||
.p => "p",
|
||||
.quote => "blockquote",
|
||||
.ul => "ul",
|
||||
.ol => "ol",
|
||||
.li => "li",
|
||||
.code => "pre",
|
||||
.hr => "hr",
|
||||
.html => "html",
|
||||
.table => "table",
|
||||
.thead => "thead",
|
||||
.tbody => "tbody",
|
||||
.tr => "tr",
|
||||
.th => "th",
|
||||
.td => "td",
|
||||
.doc => "div",
|
||||
};
|
||||
}
|
||||
|
||||
fn spanTypeName(span_type: md.SpanType) []const u8 {
|
||||
return switch (span_type) {
|
||||
.em => "em",
|
||||
.strong => "strong",
|
||||
.a => "a",
|
||||
.img => "img",
|
||||
.code => "code",
|
||||
.del => "del",
|
||||
.latexmath => "math",
|
||||
.latexmath_display => "math",
|
||||
.wikilink => "a",
|
||||
.u => "u",
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Renderer that calls JavaScript callbacks for each markdown element.
|
||||
@@ -1125,6 +1078,89 @@ fn extractLanguage(src_text: []const u8, info_beg: u32) []const u8 {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Cached tag string indices - must match BunMarkdownTagStrings.h
|
||||
const TagIndex = enum(u8) {
|
||||
h1 = 0,
|
||||
h2 = 1,
|
||||
h3 = 2,
|
||||
h4 = 3,
|
||||
h5 = 4,
|
||||
h6 = 5,
|
||||
p = 6,
|
||||
blockquote = 7,
|
||||
ul = 8,
|
||||
ol = 9,
|
||||
li = 10,
|
||||
pre = 11,
|
||||
hr = 12,
|
||||
html = 13,
|
||||
table = 14,
|
||||
thead = 15,
|
||||
tbody = 16,
|
||||
tr = 17,
|
||||
th = 18,
|
||||
td = 19,
|
||||
div = 20,
|
||||
em = 21,
|
||||
strong = 22,
|
||||
a = 23,
|
||||
img = 24,
|
||||
code = 25,
|
||||
del = 26,
|
||||
math = 27,
|
||||
u = 28,
|
||||
br = 29,
|
||||
};
|
||||
|
||||
extern fn BunMarkdownTagStrings__getTagString(*jsc.JSGlobalObject, u8) JSValue;
|
||||
|
||||
fn getCachedTagString(globalObject: *jsc.JSGlobalObject, tag: TagIndex) JSValue {
|
||||
return BunMarkdownTagStrings__getTagString(globalObject, @intFromEnum(tag));
|
||||
}
|
||||
|
||||
fn getBlockTypeTag(block_type: md.BlockType, data: u32) TagIndex {
|
||||
return switch (block_type) {
|
||||
.h => switch (data) {
|
||||
1 => .h1,
|
||||
2 => .h2,
|
||||
3 => .h3,
|
||||
4 => .h4,
|
||||
5 => .h5,
|
||||
else => .h6,
|
||||
},
|
||||
.p => .p,
|
||||
.quote => .blockquote,
|
||||
.ul => .ul,
|
||||
.ol => .ol,
|
||||
.li => .li,
|
||||
.code => .pre,
|
||||
.hr => .hr,
|
||||
.html => .html,
|
||||
.table => .table,
|
||||
.thead => .thead,
|
||||
.tbody => .tbody,
|
||||
.tr => .tr,
|
||||
.th => .th,
|
||||
.td => .td,
|
||||
.doc => .div,
|
||||
};
|
||||
}
|
||||
|
||||
fn getSpanTypeTag(span_type: md.SpanType) TagIndex {
|
||||
return switch (span_type) {
|
||||
.em => .em,
|
||||
.strong => .strong,
|
||||
.a => .a,
|
||||
.img => .img,
|
||||
.code => .code,
|
||||
.del => .del,
|
||||
.latexmath => .math,
|
||||
.latexmath_display => .math,
|
||||
.wikilink => .a,
|
||||
.u => .u,
|
||||
};
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const bun = @import("bun");
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <JavaScriptCore/VM.h>
|
||||
#include <JavaScriptCore/Heap.h>
|
||||
|
||||
extern "C" int Bun__defaultRemainingRunsUntilSkipReleaseAccess;
|
||||
|
||||
extern "C" void Bun__JSC_onBeforeWait(JSC::VM* _Nonnull vm)
|
||||
{
|
||||
ASSERT(vm);
|
||||
@@ -46,7 +48,7 @@ extern "C" void Bun__JSC_onBeforeWait(JSC::VM* _Nonnull vm)
|
||||
// finalizers that might've been waiting to be run is a good idea.
|
||||
// But if you haven't, like if the process is just waiting on I/O
|
||||
// then don't bother.
|
||||
static constexpr int defaultRemainingRunsUntilSkipReleaseAccess = 10;
|
||||
const int defaultRemainingRunsUntilSkipReleaseAccess = Bun__defaultRemainingRunsUntilSkipReleaseAccess;
|
||||
|
||||
static thread_local int remainingRunsUntilSkipReleaseAccess = 0;
|
||||
|
||||
|
||||
59
src/bun.js/bindings/BunMarkdownTagStrings.cpp
Normal file
59
src/bun.js/bindings/BunMarkdownTagStrings.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "root.h"
|
||||
#include "BunMarkdownTagStrings.h"
|
||||
#include <JavaScriptCore/JSString.h>
|
||||
#include <JavaScriptCore/JSGlobalObject.h>
|
||||
#include <JavaScriptCore/LazyProperty.h>
|
||||
#include <JavaScriptCore/LazyPropertyInlines.h>
|
||||
#include "ZigGlobalObject.h"
|
||||
#include <JavaScriptCore/SlotVisitorInlines.h>
|
||||
#include <JavaScriptCore/VMTrapsInlines.h>
|
||||
|
||||
namespace Bun {
|
||||
using namespace JSC;
|
||||
|
||||
#define MARKDOWN_TAG_STRINGS_LAZY_PROPERTY_DEFINITION(name, str, idx) \
|
||||
this->m_strings[idx].initLater( \
|
||||
[](const JSC::LazyProperty<JSGlobalObject, JSString>::Initializer& init) { \
|
||||
init.set(jsOwnedString(init.vm, str)); \
|
||||
});
|
||||
|
||||
#define MARKDOWN_TAG_STRINGS_LAZY_PROPERTY_VISITOR(name, str, idx) \
|
||||
this->m_strings[idx].visit(visitor);
|
||||
|
||||
void MarkdownTagStrings::initialize()
|
||||
{
|
||||
MARKDOWN_TAG_STRINGS_EACH_NAME(MARKDOWN_TAG_STRINGS_LAZY_PROPERTY_DEFINITION)
|
||||
}
|
||||
|
||||
template<typename Visitor>
|
||||
void MarkdownTagStrings::visit(Visitor& visitor)
|
||||
{
|
||||
MARKDOWN_TAG_STRINGS_EACH_NAME(MARKDOWN_TAG_STRINGS_LAZY_PROPERTY_VISITOR)
|
||||
}
|
||||
|
||||
template void MarkdownTagStrings::visit(JSC::AbstractSlotVisitor&);
|
||||
template void MarkdownTagStrings::visit(JSC::SlotVisitor&);
|
||||
|
||||
} // namespace Bun
|
||||
|
||||
// C API for Zig bindings
|
||||
extern "C" JSC::EncodedJSValue BunMarkdownTagStrings__getTagString(Zig::GlobalObject* globalObject, uint8_t tagIndex)
|
||||
{
|
||||
if (tagIndex >= MARKDOWN_TAG_STRINGS_COUNT)
|
||||
return JSC::JSValue::encode(JSC::jsUndefined());
|
||||
|
||||
auto& tagStrings = globalObject->markdownTagStrings();
|
||||
|
||||
// Use a switch to call the appropriate accessor
|
||||
switch (tagIndex) {
|
||||
#define MARKDOWN_TAG_STRINGS_CASE(name, str, idx) \
|
||||
case idx: \
|
||||
return JSC::JSValue::encode(tagStrings.name##String(globalObject));
|
||||
|
||||
MARKDOWN_TAG_STRINGS_EACH_NAME(MARKDOWN_TAG_STRINGS_CASE)
|
||||
|
||||
#undef MARKDOWN_TAG_STRINGS_CASE
|
||||
default:
|
||||
return JSC::JSValue::encode(JSC::jsUndefined());
|
||||
}
|
||||
}
|
||||
70
src/bun.js/bindings/BunMarkdownTagStrings.h
Normal file
70
src/bun.js/bindings/BunMarkdownTagStrings.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include <JavaScriptCore/JSString.h>
|
||||
#include <JavaScriptCore/LazyProperty.h>
|
||||
|
||||
// Markdown HTML tag names cached as JSStrings
|
||||
// These are commonly reused when rendering markdown to React elements
|
||||
|
||||
// clang-format off
|
||||
#define MARKDOWN_TAG_STRINGS_EACH_NAME(macro) \
|
||||
macro(h1, "h1"_s, 0) \
|
||||
macro(h2, "h2"_s, 1) \
|
||||
macro(h3, "h3"_s, 2) \
|
||||
macro(h4, "h4"_s, 3) \
|
||||
macro(h5, "h5"_s, 4) \
|
||||
macro(h6, "h6"_s, 5) \
|
||||
macro(p, "p"_s, 6) \
|
||||
macro(blockquote, "blockquote"_s, 7) \
|
||||
macro(ul, "ul"_s, 8) \
|
||||
macro(ol, "ol"_s, 9) \
|
||||
macro(li, "li"_s, 10) \
|
||||
macro(pre, "pre"_s, 11) \
|
||||
macro(hr, "hr"_s, 12) \
|
||||
macro(html, "html"_s, 13) \
|
||||
macro(table, "table"_s, 14) \
|
||||
macro(thead, "thead"_s, 15) \
|
||||
macro(tbody, "tbody"_s, 16) \
|
||||
macro(tr, "tr"_s, 17) \
|
||||
macro(th, "th"_s, 18) \
|
||||
macro(td, "td"_s, 19) \
|
||||
macro(div, "div"_s, 20) \
|
||||
macro(em, "em"_s, 21) \
|
||||
macro(strong, "strong"_s, 22) \
|
||||
macro(a, "a"_s, 23) \
|
||||
macro(img, "img"_s, 24) \
|
||||
macro(code, "code"_s, 25) \
|
||||
macro(del, "del"_s, 26) \
|
||||
macro(math, "math"_s, 27) \
|
||||
macro(u, "u"_s, 28) \
|
||||
macro(br, "br"_s, 29)
|
||||
// clang-format on
|
||||
|
||||
#define MARKDOWN_TAG_STRINGS_COUNT 30
|
||||
|
||||
namespace Bun {
|
||||
|
||||
using namespace JSC;
|
||||
|
||||
class MarkdownTagStrings {
|
||||
public:
|
||||
#define MARKDOWN_TAG_STRINGS_ACCESSOR_DEFINITION(name, str, idx) \
|
||||
JSC::JSString* name##String(JSC::JSGlobalObject* globalObject) \
|
||||
{ \
|
||||
return m_strings[idx].getInitializedOnMainThread(globalObject); \
|
||||
}
|
||||
|
||||
MARKDOWN_TAG_STRINGS_EACH_NAME(MARKDOWN_TAG_STRINGS_ACCESSOR_DEFINITION)
|
||||
|
||||
#undef MARKDOWN_TAG_STRINGS_ACCESSOR_DEFINITION
|
||||
|
||||
void initialize();
|
||||
|
||||
template<typename Visitor>
|
||||
void visit(Visitor& visitor);
|
||||
|
||||
private:
|
||||
JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSString> m_strings[MARKDOWN_TAG_STRINGS_COUNT];
|
||||
};
|
||||
|
||||
} // namespace Bun
|
||||
@@ -69,6 +69,7 @@ static uint8_t x86_cpu_features()
|
||||
#if CPU(ARM64)
|
||||
|
||||
#if OS(WINDOWS)
|
||||
#include <windows.h>
|
||||
#elif OS(MACOS)
|
||||
#include <sys/sysctl.h>
|
||||
#elif OS(LINUX)
|
||||
@@ -81,7 +82,18 @@ static uint8_t aarch64_cpu_features()
|
||||
uint8_t features = 0;
|
||||
|
||||
#if OS(WINDOWS)
|
||||
#pragma error "TODO: Implement AArch64 CPU features for Windows"
|
||||
// FP is mandatory on AArch64 — no separate PF_ constant exists for it
|
||||
features |= 1 << static_cast<uint8_t>(AArch64CPUFeature::fp);
|
||||
if (IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE))
|
||||
features |= 1 << static_cast<uint8_t>(AArch64CPUFeature::neon);
|
||||
if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE))
|
||||
features |= 1 << static_cast<uint8_t>(AArch64CPUFeature::aes);
|
||||
if (IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE))
|
||||
features |= 1 << static_cast<uint8_t>(AArch64CPUFeature::crc32);
|
||||
if (IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE))
|
||||
features |= 1 << static_cast<uint8_t>(AArch64CPUFeature::atomics);
|
||||
if (IsProcessorFeaturePresent(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE))
|
||||
features |= 1 << static_cast<uint8_t>(AArch64CPUFeature::sve);
|
||||
#elif OS(MACOS)
|
||||
int value = 0;
|
||||
size_t size = sizeof(value);
|
||||
|
||||
@@ -39,7 +39,7 @@ static WebCore::ExceptionOr<void> encode(VM& vm, const WTF::BitSet<256>& doNotEs
|
||||
// 4-d-ii-1. Let V be the code unit value of C.
|
||||
char32_t codePoint;
|
||||
if (!U16_IS_LEAD(character))
|
||||
codePoint = character;
|
||||
codePoint = static_cast<char32_t>(character);
|
||||
else {
|
||||
// 4-d-iii. Else,
|
||||
// 4-d-iii-1. Increase k by 1.
|
||||
|
||||
@@ -55,6 +55,10 @@ template<typename CollectionType, typename KeyType> static auto findInSortedPair
|
||||
inline void checkEncodingTableInvariants() {}
|
||||
#endif
|
||||
|
||||
// LLVM 21+ -Wcharacter-conversion flags intentional char32_t/char16_t comparisons
|
||||
// used for Unicode code point range checks in findFirstInSortedPairs.
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wcharacter-conversion"
|
||||
struct CompareFirst {
|
||||
template<typename TypeA, typename TypeB> bool operator()(const TypeA& a, const TypeB& b)
|
||||
{
|
||||
@@ -132,5 +136,6 @@ template<typename CollectionType, typename KeyType> static auto findInSortedPair
|
||||
}
|
||||
return std::ranges::equal_range(collection, makeFirstAdapter(key), CompareFirst {});
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
}
|
||||
|
||||
@@ -988,6 +988,10 @@ void JSMockFunctionPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* g
|
||||
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
|
||||
|
||||
this->putDirect(vm, Identifier::fromString(vm, "_isMockFunction"_s), jsBoolean(true), 0);
|
||||
|
||||
// Support `using spy = spyOn(...)` — auto-restores when leaving scope.
|
||||
JSValue restoreFn = this->getDirect(vm, Identifier::fromString(vm, "mockRestore"_s));
|
||||
this->putDirect(vm, vm.propertyNames->disposeSymbol, restoreFn, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontEnum));
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(jsMockFunctionGetMockImplementation, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
|
||||
|
||||
@@ -136,23 +136,23 @@ private:
|
||||
bool load_functions()
|
||||
{
|
||||
CFRelease = (void (*)(CFTypeRef))dlsym(cf_handle, "CFRelease");
|
||||
CFStringCreateWithCString = (CFStringRef(*)(CFAllocatorRef, const char*, CFStringEncoding))dlsym(cf_handle, "CFStringCreateWithCString");
|
||||
CFDataCreate = (CFDataRef(*)(CFAllocatorRef, const UInt8*, CFIndex))dlsym(cf_handle, "CFDataCreate");
|
||||
CFStringCreateWithCString = (CFStringRef (*)(CFAllocatorRef, const char*, CFStringEncoding))dlsym(cf_handle, "CFStringCreateWithCString");
|
||||
CFDataCreate = (CFDataRef (*)(CFAllocatorRef, const UInt8*, CFIndex))dlsym(cf_handle, "CFDataCreate");
|
||||
CFDataGetBytePtr = (const UInt8* (*)(CFDataRef))dlsym(cf_handle, "CFDataGetBytePtr");
|
||||
CFDataGetLength = (CFIndex(*)(CFDataRef))dlsym(cf_handle, "CFDataGetLength");
|
||||
CFDictionaryCreateMutable = (CFMutableDictionaryRef(*)(CFAllocatorRef, CFIndex, const CFDictionaryKeyCallBacks*, const CFDictionaryValueCallBacks*))dlsym(cf_handle, "CFDictionaryCreateMutable");
|
||||
CFDataGetLength = (CFIndex (*)(CFDataRef))dlsym(cf_handle, "CFDataGetLength");
|
||||
CFDictionaryCreateMutable = (CFMutableDictionaryRef (*)(CFAllocatorRef, CFIndex, const CFDictionaryKeyCallBacks*, const CFDictionaryValueCallBacks*))dlsym(cf_handle, "CFDictionaryCreateMutable");
|
||||
CFDictionaryAddValue = (void (*)(CFMutableDictionaryRef, const void*, const void*))dlsym(cf_handle, "CFDictionaryAddValue");
|
||||
CFStringGetCString = (Boolean(*)(CFStringRef, char*, CFIndex, CFStringEncoding))dlsym(cf_handle, "CFStringGetCString");
|
||||
CFStringGetCString = (Boolean (*)(CFStringRef, char*, CFIndex, CFStringEncoding))dlsym(cf_handle, "CFStringGetCString");
|
||||
CFStringGetCStringPtr = (const char* (*)(CFStringRef, CFStringEncoding))dlsym(cf_handle, "CFStringGetCStringPtr");
|
||||
CFStringGetLength = (CFIndex(*)(CFStringRef))dlsym(cf_handle, "CFStringGetLength");
|
||||
CFStringGetMaximumSizeForEncoding = (CFIndex(*)(CFIndex, CFStringEncoding))dlsym(cf_handle, "CFStringGetMaximumSizeForEncoding");
|
||||
CFStringGetLength = (CFIndex (*)(CFStringRef))dlsym(cf_handle, "CFStringGetLength");
|
||||
CFStringGetMaximumSizeForEncoding = (CFIndex (*)(CFIndex, CFStringEncoding))dlsym(cf_handle, "CFStringGetMaximumSizeForEncoding");
|
||||
|
||||
SecItemAdd = (OSStatus(*)(CFDictionaryRef, CFTypeRef*))dlsym(handle, "SecItemAdd");
|
||||
SecItemCopyMatching = (OSStatus(*)(CFDictionaryRef, CFTypeRef*))dlsym(handle, "SecItemCopyMatching");
|
||||
SecItemUpdate = (OSStatus(*)(CFDictionaryRef, CFDictionaryRef))dlsym(handle, "SecItemUpdate");
|
||||
SecItemDelete = (OSStatus(*)(CFDictionaryRef))dlsym(handle, "SecItemDelete");
|
||||
SecCopyErrorMessageString = (CFStringRef(*)(OSStatus, void*))dlsym(handle, "SecCopyErrorMessageString");
|
||||
SecAccessCreate = (OSStatus(*)(CFStringRef, CFArrayRef, SecAccessRef*))dlsym(handle, "SecAccessCreate");
|
||||
SecItemAdd = (OSStatus (*)(CFDictionaryRef, CFTypeRef*))dlsym(handle, "SecItemAdd");
|
||||
SecItemCopyMatching = (OSStatus (*)(CFDictionaryRef, CFTypeRef*))dlsym(handle, "SecItemCopyMatching");
|
||||
SecItemUpdate = (OSStatus (*)(CFDictionaryRef, CFDictionaryRef))dlsym(handle, "SecItemUpdate");
|
||||
SecItemDelete = (OSStatus (*)(CFDictionaryRef))dlsym(handle, "SecItemDelete");
|
||||
SecCopyErrorMessageString = (CFStringRef (*)(OSStatus, void*))dlsym(handle, "SecCopyErrorMessageString");
|
||||
SecAccessCreate = (OSStatus (*)(CFStringRef, CFArrayRef, SecAccessRef*))dlsym(handle, "SecAccessCreate");
|
||||
|
||||
return CFRelease && CFStringCreateWithCString && CFDataCreate && CFDataGetBytePtr && CFDataGetLength && CFDictionaryCreateMutable && CFDictionaryAddValue && SecItemAdd && SecItemCopyMatching && SecItemUpdate && SecItemDelete && SecCopyErrorMessageString && SecAccessCreate && CFStringGetCString && CFStringGetCStringPtr && CFStringGetLength && CFStringGetMaximumSizeForEncoding;
|
||||
}
|
||||
|
||||
@@ -199,19 +199,19 @@ private:
|
||||
g_free = (void (*)(gpointer))dlsym(glib_handle, "g_free");
|
||||
g_hash_table_new = (GHashTable * (*)(void*, void*)) dlsym(glib_handle, "g_hash_table_new");
|
||||
g_hash_table_destroy = (void (*)(GHashTable*))dlsym(glib_handle, "g_hash_table_destroy");
|
||||
g_hash_table_lookup = (gpointer(*)(GHashTable*, gpointer))dlsym(glib_handle, "g_hash_table_lookup");
|
||||
g_hash_table_lookup = (gpointer (*)(GHashTable*, gpointer))dlsym(glib_handle, "g_hash_table_lookup");
|
||||
g_hash_table_insert = (void (*)(GHashTable*, gpointer, gpointer))dlsym(glib_handle, "g_hash_table_insert");
|
||||
g_list_free = (void (*)(GList*))dlsym(glib_handle, "g_list_free");
|
||||
g_list_free_full = (void (*)(GList*, void (*)(gpointer)))dlsym(glib_handle, "g_list_free_full");
|
||||
g_str_hash = (guint(*)(gpointer))dlsym(glib_handle, "g_str_hash");
|
||||
g_str_equal = (gboolean(*)(gpointer, gpointer))dlsym(glib_handle, "g_str_equal");
|
||||
g_str_hash = (guint (*)(gpointer))dlsym(glib_handle, "g_str_hash");
|
||||
g_str_equal = (gboolean (*)(gpointer, gpointer))dlsym(glib_handle, "g_str_equal");
|
||||
|
||||
// Load libsecret functions
|
||||
secret_password_store_sync = (gboolean(*)(const SecretSchema*, const gchar*, const gchar*, const gchar*, void*, GError**, ...))
|
||||
secret_password_store_sync = (gboolean (*)(const SecretSchema*, const gchar*, const gchar*, const gchar*, void*, GError**, ...))
|
||||
dlsym(secret_handle, "secret_password_store_sync");
|
||||
secret_password_lookup_sync = (gchar * (*)(const SecretSchema*, void*, GError**, ...))
|
||||
dlsym(secret_handle, "secret_password_lookup_sync");
|
||||
secret_password_clear_sync = (gboolean(*)(const SecretSchema*, void*, GError**, ...))
|
||||
secret_password_clear_sync = (gboolean (*)(const SecretSchema*, void*, GError**, ...))
|
||||
dlsym(secret_handle, "secret_password_clear_sync");
|
||||
secret_password_free = (void (*)(gchar*))dlsym(secret_handle, "secret_password_free");
|
||||
secret_service_search_sync = (GList * (*)(SecretService*, const SecretSchema*, GHashTable*, SecretSearchFlags, void*, GError**))
|
||||
@@ -220,7 +220,7 @@ private:
|
||||
secret_value_get_text = (const gchar* (*)(SecretValue*))dlsym(secret_handle, "secret_value_get_text");
|
||||
secret_value_unref = (void (*)(gpointer))dlsym(secret_handle, "secret_value_unref");
|
||||
secret_item_get_attributes = (GHashTable * (*)(SecretItem*)) dlsym(secret_handle, "secret_item_get_attributes");
|
||||
secret_item_load_secret_sync = (gboolean(*)(SecretItem*, void*, GError**))dlsym(secret_handle, "secret_item_load_secret_sync");
|
||||
secret_item_load_secret_sync = (gboolean (*)(SecretItem*, void*, GError**))dlsym(secret_handle, "secret_item_load_secret_sync");
|
||||
|
||||
return g_error_free && g_free && g_hash_table_new && g_hash_table_destroy && g_hash_table_lookup && g_hash_table_insert && g_list_free && secret_password_store_sync && secret_password_lookup_sync && secret_password_clear_sync && secret_password_free;
|
||||
}
|
||||
|
||||
@@ -890,7 +890,7 @@ static const GB18030EncodeIndex& gb18030EncodeIndex()
|
||||
// https://unicode-org.atlassian.net/browse/ICU-22357
|
||||
// The 2-byte values are handled correctly by values from gb18030()
|
||||
// but these need to be exceptions from gb18030Ranges().
|
||||
static std::optional<uint16_t> gb18030AsymmetricEncode(char16_t codePoint)
|
||||
static std::optional<uint16_t> gb18030AsymmetricEncode(char32_t codePoint)
|
||||
{
|
||||
switch (codePoint) {
|
||||
case 0xE81E:
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
#include "JSSocketAddressDTO.h"
|
||||
#include "JSReactElement.h"
|
||||
#include "JSSQLStatement.h"
|
||||
#include "git/JSGit.h"
|
||||
#include "JSStringDecoder.h"
|
||||
#include "JSTextEncoder.h"
|
||||
#include "JSTextEncoderStream.h"
|
||||
@@ -302,7 +303,6 @@ extern "C" void JSCInitialize(const char* envp[], size_t envc, void (*onCrash)(c
|
||||
JSC::Options::useJITCage() = false;
|
||||
JSC::Options::useShadowRealm() = true;
|
||||
JSC::Options::useV8DateParser() = true;
|
||||
JSC::Options::useMathSumPreciseMethod() = true;
|
||||
JSC::Options::evalMode() = evalMode;
|
||||
JSC::Options::heapGrowthSteepnessFactor() = 1.0;
|
||||
JSC::Options::heapGrowthMaxIncrease() = 2.0;
|
||||
@@ -1699,6 +1699,7 @@ void GlobalObject::finishCreation(VM& vm)
|
||||
m_commonStrings.initialize();
|
||||
m_http2CommonStrings.initialize();
|
||||
m_bakeAdditions.initialize();
|
||||
m_markdownTagStrings.initialize();
|
||||
|
||||
Bun::addNodeModuleConstructorProperties(vm, this);
|
||||
m_JSNodeHTTPServerSocketStructure.initLater(
|
||||
@@ -1868,6 +1869,16 @@ void GlobalObject::finishCreation(VM& vm)
|
||||
init.set(WebCore::createJSSQLStatementStructure(init.owner));
|
||||
});
|
||||
|
||||
m_JSGitRepositoryStructure.initLater(
|
||||
[](const Initializer<Structure>& init) {
|
||||
init.set(WebCore::createJSGitRepositoryStructure(init.owner));
|
||||
});
|
||||
|
||||
m_JSGitCommitStructure.initLater(
|
||||
[](const Initializer<Structure>& init) {
|
||||
init.set(WebCore::createJSGitCommitStructure(init.owner));
|
||||
});
|
||||
|
||||
m_V8GlobalInternals.initLater(
|
||||
[](const JSC::LazyProperty<JSC::JSGlobalObject, v8::shim::GlobalInternals>::Initializer& init) {
|
||||
init.set(
|
||||
|
||||
@@ -58,6 +58,7 @@ struct node_module;
|
||||
#include "headers-handwritten.h"
|
||||
#include "BunCommonStrings.h"
|
||||
#include "BunHttp2CommonStrings.h"
|
||||
#include "BunMarkdownTagStrings.h"
|
||||
#include "BunGlobalScope.h"
|
||||
#include <js_native_api.h>
|
||||
#include <node_api.h>
|
||||
@@ -315,6 +316,9 @@ public:
|
||||
|
||||
Structure* JSSQLStatementStructure() const { return m_JSSQLStatementStructure.getInitializedOnMainThread(this); }
|
||||
|
||||
Structure* JSGitRepositoryStructure() const { return m_JSGitRepositoryStructure.getInitializedOnMainThread(this); }
|
||||
Structure* JSGitCommitStructure() const { return m_JSGitCommitStructure.getInitializedOnMainThread(this); }
|
||||
|
||||
v8::shim::GlobalInternals* V8GlobalInternals() const { return m_V8GlobalInternals.getInitializedOnMainThread(this); }
|
||||
|
||||
Bun::BakeAdditionsToGlobalObject& bakeAdditions() { return m_bakeAdditions; }
|
||||
@@ -526,6 +530,7 @@ public:
|
||||
V(private, std::unique_ptr<WebCore::DOMConstructors>, m_constructors) \
|
||||
V(private, Bun::CommonStrings, m_commonStrings) \
|
||||
V(private, Bun::Http2CommonStrings, m_http2CommonStrings) \
|
||||
V(private, Bun::MarkdownTagStrings, m_markdownTagStrings) \
|
||||
\
|
||||
/* JSC's hashtable code-generator tries to access these properties, so we make them public. */ \
|
||||
/* However, we'd like it better if they could be protected. */ \
|
||||
@@ -618,6 +623,8 @@ public:
|
||||
V(private, LazyPropertyOfGlobalObject<Structure>, m_NapiTypeTagStructure) \
|
||||
\
|
||||
V(private, LazyPropertyOfGlobalObject<Structure>, m_JSSQLStatementStructure) \
|
||||
V(private, LazyPropertyOfGlobalObject<Structure>, m_JSGitRepositoryStructure) \
|
||||
V(private, LazyPropertyOfGlobalObject<Structure>, m_JSGitCommitStructure) \
|
||||
V(private, LazyPropertyOfGlobalObject<v8::shim::GlobalInternals>, m_V8GlobalInternals) \
|
||||
\
|
||||
V(public, LazyPropertyOfGlobalObject<JSObject>, m_bunObject) \
|
||||
@@ -716,6 +723,7 @@ public:
|
||||
|
||||
Bun::CommonStrings& commonStrings() { return m_commonStrings; }
|
||||
Bun::Http2CommonStrings& http2CommonStrings() { return m_http2CommonStrings; }
|
||||
Bun::MarkdownTagStrings& markdownTagStrings() { return m_markdownTagStrings; }
|
||||
#include "ZigGeneratedClasses+lazyStructureHeader.h"
|
||||
|
||||
void finishCreation(JSC::VM&);
|
||||
|
||||
1305
src/bun.js/bindings/git/JSGit.cpp
Normal file
1305
src/bun.js/bindings/git/JSGit.cpp
Normal file
File diff suppressed because it is too large
Load Diff
140
src/bun.js/bindings/git/JSGit.h
Normal file
140
src/bun.js/bindings/git/JSGit.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Oven-sh
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "root.h"
|
||||
#include "ZigGlobalObject.h"
|
||||
|
||||
#include <JavaScriptCore/JSFunction.h>
|
||||
#include <JavaScriptCore/JSDestructibleObject.h>
|
||||
#include <JavaScriptCore/VM.h>
|
||||
|
||||
#include "headers-handwritten.h"
|
||||
#include "BunClientData.h"
|
||||
#include <JavaScriptCore/CallFrame.h>
|
||||
|
||||
// Forward declarations for libgit2 types
|
||||
typedef struct git_repository git_repository;
|
||||
typedef struct git_commit git_commit;
|
||||
typedef struct git_oid git_oid;
|
||||
|
||||
namespace WebCore {
|
||||
|
||||
// Forward declarations
|
||||
class JSGitRepository;
|
||||
class JSGitCommit;
|
||||
class JSGitOid;
|
||||
|
||||
// JSGitRepository - Wraps git_repository*
|
||||
class JSGitRepository final : public JSC::JSDestructibleObject {
|
||||
public:
|
||||
using Base = JSC::JSDestructibleObject;
|
||||
static constexpr unsigned StructureFlags = Base::StructureFlags;
|
||||
|
||||
static JSGitRepository* create(JSC::VM& vm, JSC::Structure* structure, git_repository* repo);
|
||||
static void destroy(JSC::JSCell* cell);
|
||||
|
||||
DECLARE_INFO;
|
||||
|
||||
template<typename CellType, JSC::SubspaceAccess mode>
|
||||
static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
|
||||
{
|
||||
return WebCore::subspaceForImpl<JSGitRepository, WebCore::UseCustomHeapCellType::No>(
|
||||
vm,
|
||||
[](auto& spaces) { return spaces.m_clientSubspaceForJSGitRepository.get(); },
|
||||
[](auto& spaces, auto&& space) { spaces.m_clientSubspaceForJSGitRepository = std::forward<decltype(space)>(space); },
|
||||
[](auto& spaces) { return spaces.m_subspaceForJSGitRepository.get(); },
|
||||
[](auto& spaces, auto&& space) { spaces.m_subspaceForJSGitRepository = std::forward<decltype(space)>(space); });
|
||||
}
|
||||
|
||||
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
|
||||
{
|
||||
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
|
||||
}
|
||||
|
||||
git_repository* repository() const { return m_repo; }
|
||||
|
||||
private:
|
||||
JSGitRepository(JSC::VM& vm, JSC::Structure* structure, git_repository* repo)
|
||||
: Base(vm, structure)
|
||||
, m_repo(repo)
|
||||
{
|
||||
}
|
||||
|
||||
void finishCreation(JSC::VM& vm);
|
||||
|
||||
git_repository* m_repo { nullptr };
|
||||
};
|
||||
|
||||
// JSGitCommit - Wraps git_commit*
|
||||
class JSGitCommit final : public JSC::JSDestructibleObject {
|
||||
public:
|
||||
using Base = JSC::JSDestructibleObject;
|
||||
static constexpr unsigned StructureFlags = Base::StructureFlags;
|
||||
|
||||
static JSGitCommit* create(JSC::VM& vm, JSC::Structure* structure, git_commit* commit);
|
||||
static void destroy(JSC::JSCell* cell);
|
||||
|
||||
DECLARE_INFO;
|
||||
|
||||
template<typename CellType, JSC::SubspaceAccess mode>
|
||||
static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
|
||||
{
|
||||
return WebCore::subspaceForImpl<JSGitCommit, WebCore::UseCustomHeapCellType::No>(
|
||||
vm,
|
||||
[](auto& spaces) { return spaces.m_clientSubspaceForJSGitCommit.get(); },
|
||||
[](auto& spaces, auto&& space) { spaces.m_clientSubspaceForJSGitCommit = std::forward<decltype(space)>(space); },
|
||||
[](auto& spaces) { return spaces.m_subspaceForJSGitCommit.get(); },
|
||||
[](auto& spaces, auto&& space) { spaces.m_subspaceForJSGitCommit = std::forward<decltype(space)>(space); });
|
||||
}
|
||||
|
||||
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
|
||||
{
|
||||
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
|
||||
}
|
||||
|
||||
git_commit* commit() const { return m_commit; }
|
||||
|
||||
private:
|
||||
JSGitCommit(JSC::VM& vm, JSC::Structure* structure, git_commit* commit)
|
||||
: Base(vm, structure)
|
||||
, m_commit(commit)
|
||||
{
|
||||
}
|
||||
|
||||
void finishCreation(JSC::VM& vm);
|
||||
|
||||
git_commit* m_commit { nullptr };
|
||||
};
|
||||
|
||||
// Structure creation functions
|
||||
JSC::Structure* createJSGitRepositoryStructure(JSC::JSGlobalObject* globalObject);
|
||||
JSC::Structure* createJSGitCommitStructure(JSC::JSGlobalObject* globalObject);
|
||||
|
||||
// Module creation function (called from $cpp)
|
||||
JSC::JSValue createJSGitModule(Zig::GlobalObject* globalObject);
|
||||
|
||||
} // namespace WebCore
|
||||
@@ -80,11 +80,18 @@ size_t IndexOfAnyCharImpl(const uint8_t* HWY_RESTRICT text, size_t text_len, con
|
||||
return text_len;
|
||||
} else {
|
||||
ASSERT(chars_len <= 16);
|
||||
constexpr size_t kMaxPreloadedChars = 16;
|
||||
hn::Vec<D8> char_vecs[kMaxPreloadedChars];
|
||||
|
||||
// Use FixedTag to preload search characters into fixed-size vectors.
|
||||
// ScalableTag vectors (SVE) are sizeless and cannot be stored in arrays.
|
||||
// FixedTag gives us a known compile-time size that can be stored in arrays,
|
||||
// then ResizeBitCast converts back to scalable vectors in the inner loop.
|
||||
static constexpr size_t kMaxPreloadedChars = 16;
|
||||
const hn::FixedTag<uint8_t, 16> d_fixed;
|
||||
using VecFixed = hn::Vec<decltype(d_fixed)>;
|
||||
VecFixed char_vecs[kMaxPreloadedChars];
|
||||
const size_t num_chars_to_preload = std::min(chars_len, kMaxPreloadedChars);
|
||||
for (size_t c = 0; c < num_chars_to_preload; ++c) {
|
||||
char_vecs[c] = hn::Set(d, chars[c]);
|
||||
char_vecs[c] = hn::Set(d_fixed, chars[c]);
|
||||
}
|
||||
|
||||
const size_t simd_text_len = text_len - (text_len % N);
|
||||
@@ -95,12 +102,7 @@ size_t IndexOfAnyCharImpl(const uint8_t* HWY_RESTRICT text, size_t text_len, con
|
||||
auto found_mask = hn::MaskFalse(d);
|
||||
|
||||
for (size_t c = 0; c < num_chars_to_preload; ++c) {
|
||||
found_mask = hn::Or(found_mask, hn::Eq(text_vec, char_vecs[c]));
|
||||
}
|
||||
if (chars_len > num_chars_to_preload) {
|
||||
for (size_t c = num_chars_to_preload; c < chars_len; ++c) {
|
||||
found_mask = hn::Or(found_mask, hn::Eq(text_vec, hn::Set(d, chars[c])));
|
||||
}
|
||||
found_mask = hn::Or(found_mask, hn::Eq(text_vec, hn::ResizeBitCast(d, char_vecs[c])));
|
||||
}
|
||||
|
||||
const intptr_t pos = hn::FindFirstTrue(d, found_mask);
|
||||
|
||||
@@ -171,8 +171,8 @@ void AbortSignal::runAbortSteps()
|
||||
algorithm.second(reason);
|
||||
|
||||
// 3. Fire an event named abort at signal.
|
||||
dispatchEvent(Event::create(eventNames().abortEvent, Event::CanBubble::No, Event::IsCancelable::No));
|
||||
|
||||
if (hasEventListeners(eventNames().abortEvent))
|
||||
dispatchEvent(Event::create(eventNames().abortEvent, Event::CanBubble::No, Event::IsCancelable::No));
|
||||
setIsFiringEventListeners(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ public:
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForNapiPrototype;
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSSQLStatement;
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSSQLStatementConstructor;
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSGitRepository;
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSGitCommit;
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSSinkConstructor;
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSSinkController;
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSSink;
|
||||
|
||||
@@ -24,6 +24,8 @@ public:
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForNapiPrototype;
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForJSSQLStatement;
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForJSSQLStatementConstructor;
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForJSGitRepository;
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForJSGitCommit;
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForJSSinkConstructor;
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForJSSinkController;
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForJSSink;
|
||||
|
||||
@@ -105,7 +105,7 @@ bool EventTarget::addEventListener(const AtomString& eventType, Ref<EventListene
|
||||
if (options.signal) {
|
||||
options.signal->addAlgorithm([weakThis = WeakPtr { *this }, eventType, listener = WeakPtr { listener }, capture = options.capture](JSC::JSValue) {
|
||||
if (weakThis && listener)
|
||||
Ref { *weakThis } -> removeEventListener(eventType, *listener, capture);
|
||||
Ref { *weakThis }->removeEventListener(eventType, *listener, capture);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -470,7 +470,7 @@ String generatePatternString(const Vector<Part>& partList, const URLPatternStrin
|
||||
|
||||
if (!needsGrouping && part.prefix.isEmpty() && previousPart && previousPart->type == PartType::FixedText && !previousPart->value.isEmpty()) {
|
||||
if (options.prefixCodepoint.length() == 1
|
||||
&& options.prefixCodepoint.startsWith(*StringView(previousPart->value).codePoints().codePointAt(previousPart->value.length() - 1)))
|
||||
&& options.prefixCodepoint.startsWith(static_cast<char16_t>(*StringView(previousPart->value).codePoints().codePointAt(previousPart->value.length() - 1))))
|
||||
needsGrouping = true;
|
||||
}
|
||||
|
||||
@@ -541,7 +541,7 @@ String escapePatternString(StringView input)
|
||||
}
|
||||
|
||||
// https://urlpattern.spec.whatwg.org/#is-a-valid-name-code-point
|
||||
bool isValidNameCodepoint(char16_t codepoint, URLPatternUtilities::IsFirst first)
|
||||
bool isValidNameCodepoint(char32_t codepoint, URLPatternUtilities::IsFirst first)
|
||||
{
|
||||
if (first == URLPatternUtilities::IsFirst::Yes)
|
||||
return u_hasBinaryProperty(codepoint, UCHAR_ID_START) || codepoint == '_' || codepoint == '$';
|
||||
|
||||
@@ -104,7 +104,7 @@ ASCIILiteral convertModifierToString(Modifier);
|
||||
std::pair<String, Vector<String>> generateRegexAndNameList(const Vector<Part>& partList, const URLPatternStringOptions&);
|
||||
String generatePatternString(const Vector<Part>& partList, const URLPatternStringOptions&);
|
||||
String escapePatternString(StringView input);
|
||||
bool isValidNameCodepoint(char16_t codepoint, URLPatternUtilities::IsFirst);
|
||||
bool isValidNameCodepoint(char32_t codepoint, URLPatternUtilities::IsFirst);
|
||||
|
||||
} // namespace URLPatternUtilities
|
||||
} // namespace WebCore
|
||||
|
||||
@@ -49,14 +49,14 @@ WebCoreTypedArrayController::WebCoreTypedArrayController(bool allowAtomicsWait)
|
||||
|
||||
WebCoreTypedArrayController::~WebCoreTypedArrayController() = default;
|
||||
|
||||
JSC::JSArrayBuffer* WebCoreTypedArrayController::toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSGlobalObject* globalObject, JSC::ArrayBuffer* buffer)
|
||||
JSC::JSArrayBuffer* WebCoreTypedArrayController::toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSGlobalObject* globalObject, JSC::ArrayBuffer& buffer)
|
||||
{
|
||||
return JSC::jsCast<JSC::JSArrayBuffer*>(WebCore::toJS(lexicalGlobalObject, getDefaultGlobal(globalObject), buffer));
|
||||
}
|
||||
|
||||
void WebCoreTypedArrayController::registerWrapper(JSC::JSGlobalObject* globalObject, JSC::ArrayBuffer* native, JSC::JSArrayBuffer* wrapper)
|
||||
void WebCoreTypedArrayController::registerWrapper(JSC::JSGlobalObject* globalObject, JSC::ArrayBuffer& native, JSC::JSArrayBuffer& wrapper)
|
||||
{
|
||||
cacheWrapper(static_cast<JSVMClientData*>(JSC::getVM(globalObject).clientData)->normalWorld(), native, wrapper);
|
||||
cacheWrapper(static_cast<JSVMClientData*>(JSC::getVM(globalObject).clientData)->normalWorld(), &native, &wrapper);
|
||||
}
|
||||
|
||||
bool WebCoreTypedArrayController::isAtomicsWaitAllowedOnCurrentThread()
|
||||
|
||||
@@ -35,8 +35,8 @@ public:
|
||||
WebCoreTypedArrayController(bool allowAtomicsWait);
|
||||
virtual ~WebCoreTypedArrayController();
|
||||
|
||||
JSC::JSArrayBuffer* toJS(JSC::JSGlobalObject*, JSC::JSGlobalObject*, JSC::ArrayBuffer*) override;
|
||||
void registerWrapper(JSC::JSGlobalObject*, ArrayBuffer*, JSC::JSArrayBuffer*) override;
|
||||
JSC::JSArrayBuffer* toJS(JSC::JSGlobalObject*, JSC::JSGlobalObject*, JSC::ArrayBuffer&) override;
|
||||
void registerWrapper(JSC::JSGlobalObject*, ArrayBuffer&, JSC::JSArrayBuffer&) override;
|
||||
bool isAtomicsWaitAllowedOnCurrentThread() override;
|
||||
|
||||
JSC::WeakHandleOwner* wrapperOwner() { return &m_owner; }
|
||||
|
||||
@@ -249,32 +249,9 @@ extern "C" __attribute__((used)) char __libc_single_threaded = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _LIBCPP_VERBOSE_ABORT_NOEXCEPT
|
||||
// Workaround for this error:
|
||||
// workaround-missing-symbols.cpp:245:11: error: '__libcpp_verbose_abort' is missing exception specification 'noexcept'
|
||||
// 2025-07-10 15:59:47 PDT
|
||||
// 245 | void std::__libcpp_verbose_abort(char const* format, ...)
|
||||
// 2025-07-10 15:59:47 PDT
|
||||
// | ^
|
||||
// 2025-07-10 15:59:47 PDT
|
||||
// | noexcept
|
||||
// 2025-07-10 15:59:47 PDT
|
||||
// /opt/homebrew/Cellar/llvm/20.1.7/bin/../include/c++/v1/__verbose_abort:30:28: note: previous declaration is here
|
||||
// 2025-07-10 15:59:47 PDT
|
||||
// 30 | __printf__, 1, 2) void __libcpp_verbose_abort(const char* __format, ...) _LIBCPP_VERBOSE_ABORT_NOEXCEPT;
|
||||
// 2025-07-10 15:59:47 PDT
|
||||
// | ^
|
||||
// 2025-07-10 15:59:47 PDT
|
||||
// 1 error generated.
|
||||
// 2025-07-10 15:59:47 PDT
|
||||
// [515/540] Building CXX
|
||||
#define BUN_VERBOSE_ABORT_NOEXCEPT _LIBCPP_VERBOSE_ABORT_NOEXCEPT
|
||||
#else
|
||||
#define BUN_VERBOSE_ABORT_NOEXCEPT
|
||||
#endif
|
||||
|
||||
// Provide our implementation
|
||||
void std::__libcpp_verbose_abort(char const* format, ...) BUN_VERBOSE_ABORT_NOEXCEPT
|
||||
// LLVM 20 used _LIBCPP_VERBOSE_ABORT_NOEXCEPT, LLVM 21+ uses _NOEXCEPT (always noexcept).
|
||||
void std::__libcpp_verbose_abort(char const* format, ...) noexcept
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
|
||||
@@ -33,7 +33,7 @@ static char32_t decodeUTF16(const UChar* ptr, size_t available, size_t& outLen)
|
||||
}
|
||||
|
||||
outLen = 1;
|
||||
return c;
|
||||
return static_cast<char32_t>(c);
|
||||
}
|
||||
|
||||
static inline uint8_t getVisibleWidth(char32_t cp, bool ambiguousIsWide)
|
||||
|
||||
@@ -52,6 +52,14 @@ pub fn init(this: *GarbageCollectionController, vm: *VirtualMachine) void {
|
||||
}
|
||||
this.gc_timer_interval = gc_timer_interval;
|
||||
|
||||
if (vm.transpiler.env.get("BUN_GC_RUNS_UNTIL_SKIP_RELEASE_ACCESS")) |val| {
|
||||
if (std.fmt.parseInt(c_int, val, 10)) |parsed| {
|
||||
if (parsed >= 0) {
|
||||
VirtualMachine.Bun__defaultRemainingRunsUntilSkipReleaseAccess = parsed;
|
||||
}
|
||||
} else |_| {}
|
||||
}
|
||||
|
||||
this.disabled = vm.transpiler.env.has("BUN_GC_TIMER_DISABLE");
|
||||
|
||||
if (!this.disabled)
|
||||
|
||||
@@ -79,11 +79,13 @@ JSC_DEFINE_HOST_FUNCTION(functionStartRemoteDebugger,
|
||||
JSC::JSValue hostValue = callFrame->argument(0);
|
||||
JSC::JSValue portValue = callFrame->argument(1);
|
||||
const char* host = defaultHost;
|
||||
WTF::CString hostCString;
|
||||
if (hostValue.isString()) {
|
||||
|
||||
auto str = hostValue.toWTFString(globalObject);
|
||||
hostCString = toCString(str);
|
||||
if (!str.isEmpty())
|
||||
host = toCString(str).span().data();
|
||||
host = hostCString.span().data();
|
||||
} else if (!hostValue.isUndefined()) {
|
||||
throwVMError(globalObject, scope,
|
||||
createTypeError(globalObject, "host must be a string"_s));
|
||||
|
||||
@@ -14,10 +14,15 @@ param(
|
||||
[Switch]$DownloadWithoutCurl = $false
|
||||
);
|
||||
|
||||
# filter out 32 bit + ARM
|
||||
if (-not ((Get-CimInstance Win32_ComputerSystem)).SystemType -match "x64-based") {
|
||||
# Detect system architecture
|
||||
$SystemType = (Get-CimInstance Win32_ComputerSystem).SystemType
|
||||
if ($SystemType -match "ARM64-based") {
|
||||
$IsArm64 = $true
|
||||
} elseif ($SystemType -match "x64-based") {
|
||||
$IsArm64 = $false
|
||||
} else {
|
||||
Write-Output "Install Failed:"
|
||||
Write-Output "Bun for Windows is currently only available for x86 64-bit Windows.`n"
|
||||
Write-Output "Bun for Windows is currently only available for x86 64-bit and ARM64 Windows.`n"
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -103,13 +108,18 @@ function Install-Bun {
|
||||
$Version = "bun-$Version"
|
||||
}
|
||||
|
||||
$Arch = "x64"
|
||||
$IsBaseline = $ForceBaseline
|
||||
if (!$IsBaseline) {
|
||||
$IsBaseline = !( `
|
||||
Add-Type -MemberDefinition '[DllImport("kernel32.dll")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);' `
|
||||
-Name 'Kernel32' -Namespace 'Win32' -PassThru `
|
||||
)::IsProcessorFeaturePresent(40);
|
||||
if ($IsArm64) {
|
||||
$Arch = "aarch64"
|
||||
$IsBaseline = $false
|
||||
} else {
|
||||
$Arch = "x64"
|
||||
$IsBaseline = $ForceBaseline
|
||||
if (!$IsBaseline) {
|
||||
$IsBaseline = !( `
|
||||
Add-Type -MemberDefinition '[DllImport("kernel32.dll")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);' `
|
||||
-Name 'Kernel32' -Namespace 'Win32' -PassThru `
|
||||
)::IsProcessorFeaturePresent(40);
|
||||
}
|
||||
}
|
||||
|
||||
$BunRoot = if ($env:BUN_INSTALL) { $env:BUN_INSTALL } else { "${Home}\.bun" }
|
||||
@@ -219,7 +229,8 @@ function Install-Bun {
|
||||
# I want to keep this error message in for a few months to ensure that
|
||||
# if someone somehow runs into this, it can be reported.
|
||||
Write-Output "Install Failed - You are missing a DLL required to run bun.exe"
|
||||
Write-Output "This can be solved by installing the Visual C++ Redistributable from Microsoft:`nSee https://learn.microsoft.com/cpp/windows/latest-supported-vc-redist`nDirect Download -> https://aka.ms/vs/17/release/vc_redist.x64.exe`n`n"
|
||||
$VCRedistArch = if ($Arch -eq "aarch64") { "arm64" } else { "x64" }
|
||||
Write-Output "This can be solved by installing the Visual C++ Redistributable from Microsoft:`nSee https://learn.microsoft.com/cpp/windows/latest-supported-vc-redist`nDirect Download -> https://aka.ms/vs/17/release/vc_redist.${VCRedistArch}.exe`n`n"
|
||||
Write-Output "The error above should be unreachable as Bun does not depend on this library. Please comment in https://github.com/oven-sh/bun/issues/8598 or open a new issue.`n`n"
|
||||
Write-Output "The command '${BunBin}\bun.exe --revision' exited with code ${LASTEXITCODE}`n"
|
||||
return 1
|
||||
|
||||
@@ -1700,8 +1700,8 @@ pub fn dumpStackTrace(trace: std.builtin.StackTrace, limits: WriteStackTraceLimi
|
||||
|
||||
const programs: []const [:0]const u8 = switch (bun.Environment.os) {
|
||||
.windows => &.{"pdb-addr2line"},
|
||||
// if `llvm-symbolizer` doesn't work, also try `llvm-symbolizer-19`
|
||||
else => &.{ "llvm-symbolizer", "llvm-symbolizer-19" },
|
||||
// if `llvm-symbolizer` doesn't work, also try `llvm-symbolizer-21`
|
||||
else => &.{ "llvm-symbolizer", "llvm-symbolizer-21" },
|
||||
};
|
||||
for (programs) |program| {
|
||||
var arena = bun.ArenaAllocator.init(bun.default_allocator);
|
||||
|
||||
306
src/js/bun/git.ts
Normal file
306
src/js/bun/git.ts
Normal file
@@ -0,0 +1,306 @@
|
||||
// Hardcoded module "bun:git"
|
||||
|
||||
let Git: any;
|
||||
|
||||
function initializeGit() {
|
||||
Git = $cpp("git/JSGit.cpp", "createJSGitModule");
|
||||
}
|
||||
|
||||
interface Signature {
|
||||
name: string;
|
||||
email: string;
|
||||
time: number; // Unix timestamp in milliseconds
|
||||
}
|
||||
|
||||
interface StatusOptions {
|
||||
includeUntracked?: boolean;
|
||||
includeIgnored?: boolean;
|
||||
recurseUntrackedDirs?: boolean;
|
||||
detectRenames?: boolean;
|
||||
}
|
||||
|
||||
interface InternalStatusEntry {
|
||||
path: string;
|
||||
status: number;
|
||||
}
|
||||
|
||||
interface IndexEntry {
|
||||
path: string;
|
||||
mode: number;
|
||||
oid: string;
|
||||
stage: number;
|
||||
size: number;
|
||||
}
|
||||
|
||||
interface DiffOptions {
|
||||
cached?: boolean;
|
||||
}
|
||||
|
||||
interface DiffFile {
|
||||
status: number;
|
||||
oldPath: string | null;
|
||||
newPath: string;
|
||||
similarity?: number;
|
||||
}
|
||||
|
||||
interface DiffResult {
|
||||
files: DiffFile[];
|
||||
stats: {
|
||||
filesChanged: number;
|
||||
insertions: number;
|
||||
deletions: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface LogOptions {
|
||||
from?: string;
|
||||
range?: string;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
// Status constants (nodegit compatible)
|
||||
const Status = {
|
||||
CURRENT: 0,
|
||||
INDEX_NEW: 1,
|
||||
INDEX_MODIFIED: 2,
|
||||
INDEX_DELETED: 4,
|
||||
INDEX_RENAMED: 8,
|
||||
INDEX_TYPECHANGE: 16,
|
||||
WT_NEW: 128,
|
||||
WT_MODIFIED: 256,
|
||||
WT_DELETED: 512,
|
||||
WT_TYPECHANGE: 1024,
|
||||
WT_RENAMED: 2048,
|
||||
IGNORED: 16384,
|
||||
CONFLICTED: 32768,
|
||||
};
|
||||
|
||||
// DeltaType constants (nodegit compatible)
|
||||
const DeltaType = {
|
||||
UNMODIFIED: 0,
|
||||
ADDED: 1,
|
||||
DELETED: 2,
|
||||
MODIFIED: 3,
|
||||
RENAMED: 4,
|
||||
COPIED: 5,
|
||||
IGNORED: 6,
|
||||
UNTRACKED: 7,
|
||||
TYPECHANGE: 8,
|
||||
CONFLICTED: 10,
|
||||
};
|
||||
|
||||
class StatusEntry {
|
||||
path: string;
|
||||
status: number;
|
||||
|
||||
constructor(entry: InternalStatusEntry) {
|
||||
this.path = entry.path;
|
||||
this.status = entry.status;
|
||||
}
|
||||
|
||||
isNew(): boolean {
|
||||
return (this.status & (Status.INDEX_NEW | Status.WT_NEW)) !== 0;
|
||||
}
|
||||
|
||||
isModified(): boolean {
|
||||
return (this.status & (Status.INDEX_MODIFIED | Status.WT_MODIFIED)) !== 0;
|
||||
}
|
||||
|
||||
isDeleted(): boolean {
|
||||
return (this.status & (Status.INDEX_DELETED | Status.WT_DELETED)) !== 0;
|
||||
}
|
||||
|
||||
isRenamed(): boolean {
|
||||
return (this.status & (Status.INDEX_RENAMED | Status.WT_RENAMED)) !== 0;
|
||||
}
|
||||
|
||||
isIgnored(): boolean {
|
||||
return (this.status & Status.IGNORED) !== 0;
|
||||
}
|
||||
|
||||
inIndex(): boolean {
|
||||
return (
|
||||
(this.status &
|
||||
(Status.INDEX_NEW |
|
||||
Status.INDEX_MODIFIED |
|
||||
Status.INDEX_DELETED |
|
||||
Status.INDEX_RENAMED |
|
||||
Status.INDEX_TYPECHANGE)) !==
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
inWorkingTree(): boolean {
|
||||
return (
|
||||
(this.status &
|
||||
(Status.WT_NEW | Status.WT_MODIFIED | Status.WT_DELETED | Status.WT_TYPECHANGE | Status.WT_RENAMED)) !==
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Repository {
|
||||
#repo: any;
|
||||
|
||||
constructor(repo: any) {
|
||||
this.#repo = repo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open an existing Git repository
|
||||
*/
|
||||
static open(path: string): Repository {
|
||||
if (!Git) {
|
||||
initializeGit();
|
||||
}
|
||||
const repo = Git.Repository.open(path);
|
||||
return new Repository(repo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HEAD commit
|
||||
*/
|
||||
head(): Commit {
|
||||
const commit = this.#repo.head();
|
||||
return new Commit(commit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the .git directory path
|
||||
*/
|
||||
get path(): string {
|
||||
return this.#repo.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the working directory path (null for bare repositories)
|
||||
*/
|
||||
get workdir(): string | null {
|
||||
return this.#repo.workdir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a bare repository
|
||||
*/
|
||||
get isBare(): boolean {
|
||||
return this.#repo.isBare;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the working directory status (nodegit compatible)
|
||||
*/
|
||||
getStatus(options?: StatusOptions): StatusEntry[] {
|
||||
const entries = this.#repo.getStatus(options);
|
||||
return entries.map((e: InternalStatusEntry) => new StatusEntry(e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a revision spec to an OID
|
||||
*/
|
||||
revParse(spec: string): string {
|
||||
return this.#repo.revParse(spec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the current branch (null if detached HEAD or no commits)
|
||||
*/
|
||||
getCurrentBranch(): string | null {
|
||||
return this.#repo.getCurrentBranch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ahead/behind counts between two commits
|
||||
*/
|
||||
aheadBehind(local?: string, upstream?: string): { ahead: number; behind: number } {
|
||||
return this.#repo.aheadBehind(local, upstream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of files in the index
|
||||
*/
|
||||
listFiles(): IndexEntry[] {
|
||||
return this.#repo.listFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get diff information
|
||||
*/
|
||||
diff(options?: DiffOptions): DiffResult {
|
||||
return this.#repo.diff(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count commits in a range
|
||||
*/
|
||||
countCommits(range?: string): number {
|
||||
return this.#repo.countCommits(range);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get commit history
|
||||
*/
|
||||
log(options?: LogOptions): Commit[] {
|
||||
const commits = this.#repo.log(options);
|
||||
return commits.map((c: any) => new Commit(c));
|
||||
}
|
||||
}
|
||||
|
||||
class Commit {
|
||||
#commit: any;
|
||||
|
||||
constructor(commit: any) {
|
||||
this.#commit = commit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the commit OID (SHA-1 hash)
|
||||
*/
|
||||
get id(): string {
|
||||
return this.#commit.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full commit message
|
||||
*/
|
||||
get message(): string {
|
||||
return this.#commit.message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first line of the commit message
|
||||
*/
|
||||
get summary(): string {
|
||||
return this.#commit.summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the author signature
|
||||
*/
|
||||
get author(): Signature {
|
||||
return this.#commit.author;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the committer signature
|
||||
*/
|
||||
get committer(): Signature {
|
||||
return this.#commit.committer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the commit time as Unix timestamp (seconds since epoch)
|
||||
*/
|
||||
get time(): number {
|
||||
return this.#commit.time;
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
__esModule: true,
|
||||
Repository,
|
||||
Commit,
|
||||
StatusEntry,
|
||||
Status,
|
||||
DeltaType,
|
||||
default: Repository,
|
||||
};
|
||||
@@ -486,22 +486,27 @@ pub const HtmlRenderer = struct {
|
||||
}
|
||||
|
||||
pub fn writeHtmlEscaped(self: *HtmlRenderer, txt: []const u8) void {
|
||||
var start: usize = 0;
|
||||
for (txt, 0..) |c, i| {
|
||||
const replacement: ?[]const u8 = switch (c) {
|
||||
'&' => "&",
|
||||
'<' => "<",
|
||||
'>' => ">",
|
||||
'"' => """,
|
||||
else => null,
|
||||
var i: usize = 0;
|
||||
const needle = "&<>\"";
|
||||
|
||||
while (true) {
|
||||
const next = std.mem.indexOfAny(u8, txt[i..], needle) orelse {
|
||||
self.write(txt[i..]);
|
||||
return;
|
||||
};
|
||||
if (replacement) |r| {
|
||||
if (i > start) self.write(txt[start..i]);
|
||||
self.write(r);
|
||||
start = i + 1;
|
||||
const pos = i + next;
|
||||
if (pos > i)
|
||||
self.write(txt[i..pos]);
|
||||
const c = txt[pos];
|
||||
switch (c) {
|
||||
'&' => self.write("&"),
|
||||
'<' => self.write("<"),
|
||||
'>' => self.write(">"),
|
||||
'"' => self.write("""),
|
||||
else => unreachable,
|
||||
}
|
||||
i = pos + 1;
|
||||
}
|
||||
if (start < txt.len) self.write(txt[start..]);
|
||||
}
|
||||
|
||||
fn writeUrlEscaped(self: *HtmlRenderer, txt: []const u8) void {
|
||||
|
||||
1107
test/js/bun/git/repository.test.ts
Normal file
1107
test/js/bun/git/repository.test.ts
Normal file
File diff suppressed because it is too large
Load Diff
38
test/js/bun/test/mock-disposable.test.ts
Normal file
38
test/js/bun/test/mock-disposable.test.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { expect, mock, spyOn, test } from "bun:test";
|
||||
|
||||
test("spyOn returns a disposable that calls mockRestore", () => {
|
||||
const obj = { method: () => "original" };
|
||||
|
||||
{
|
||||
using spy = spyOn(obj, "method").mockReturnValue("mocked");
|
||||
expect(obj.method()).toBe("mocked");
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
}
|
||||
|
||||
expect(obj.method()).toBe("original");
|
||||
});
|
||||
|
||||
test("mock() returns a disposable that calls mockRestore", () => {
|
||||
const fn = mock(() => "original");
|
||||
|
||||
fn();
|
||||
expect(fn).toHaveBeenCalledTimes(1);
|
||||
expect(fn[Symbol.dispose]).toBeFunction();
|
||||
fn[Symbol.dispose]();
|
||||
expect(fn).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test("using with spyOn auto-restores prototype methods", () => {
|
||||
class Greeter {
|
||||
greet() {
|
||||
return "hello";
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
using spy = spyOn(Greeter.prototype, "greet").mockReturnValue("hola");
|
||||
expect(new Greeter().greet()).toBe("hola");
|
||||
}
|
||||
|
||||
expect(new Greeter().greet()).toBe("hello");
|
||||
});
|
||||
@@ -20,8 +20,8 @@ export async function build(dir: string) {
|
||||
// so we make it use clang instead
|
||||
...(process.platform == "linux" && isCI
|
||||
? {
|
||||
CC: !isMusl ? "/usr/lib/llvm-19/bin/clang" : "/usr/lib/llvm19/bin/clang",
|
||||
CXX: !isMusl ? "/usr/lib/llvm-19/bin/clang++" : "/usr/lib/llvm19/bin/clang++",
|
||||
CC: !isMusl ? "/usr/lib/llvm-21/bin/clang" : "/usr/lib/llvm21/bin/clang",
|
||||
CXX: !isMusl ? "/usr/lib/llvm-21/bin/clang++" : "/usr/lib/llvm21/bin/clang++",
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user