mirror of
https://github.com/oven-sh/bun
synced 2026-02-07 09:28:51 +00:00
Compare commits
74 Commits
fix-format
...
jarred/nam
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbcf90b0f5 | ||
|
|
016ebf7b9b | ||
|
|
2f7ff95e5c | ||
|
|
857a472033 | ||
|
|
7720d23da1 | ||
|
|
ecc3e5e187 | ||
|
|
dcaaeecfa3 | ||
|
|
9ab51983b8 | ||
|
|
af82a446df | ||
|
|
dd12715071 | ||
|
|
514d37b3d2 | ||
|
|
d09df1af47 | ||
|
|
05afe42f31 | ||
|
|
123b5219e0 | ||
|
|
7113206a7d | ||
|
|
89fc3ef34d | ||
|
|
392a58b0ed | ||
|
|
02fb802b25 | ||
|
|
69d33bb1d0 | ||
|
|
4e51f7d85b | ||
|
|
5e97fb8d97 | ||
|
|
d42c032eec | ||
|
|
afe974a175 | ||
|
|
274e5a2022 | ||
|
|
18822b9f45 | ||
|
|
7b058e24ff | ||
|
|
ec7078a006 | ||
|
|
af12ff104a | ||
|
|
80db770521 | ||
|
|
c4c3019cb0 | ||
|
|
1f0f666210 | ||
|
|
73f90c3359 | ||
|
|
291a50aff5 | ||
|
|
128c658f91 | ||
|
|
a87341b239 | ||
|
|
3ab990e615 | ||
|
|
ecf5d79e01 | ||
|
|
b9a56a6087 | ||
|
|
5722ae8d04 | ||
|
|
2856267fda | ||
|
|
da70c891df | ||
|
|
6f27b5559d | ||
|
|
117e1b3883 | ||
|
|
1e1025ca37 | ||
|
|
30dc72c17b | ||
|
|
17d719fa4e | ||
|
|
0ac2a7da0a | ||
|
|
9d23ce16ec | ||
|
|
7d94c59545 | ||
|
|
33075394a4 | ||
|
|
ff9560c82a | ||
|
|
2f8c20ef82 | ||
|
|
d05070dbfd | ||
|
|
1244907a92 | ||
|
|
81e5ee26bd | ||
|
|
27e7aa7923 | ||
|
|
f89623aa5e | ||
|
|
3cc51ceb98 | ||
|
|
e944bb3638 | ||
|
|
797750ef42 | ||
|
|
c267d76f05 | ||
|
|
c5c1e8ff3a | ||
|
|
1eab8ec107 | ||
|
|
60d8c8ad4c | ||
|
|
dba108f8c4 | ||
|
|
18251e1b60 | ||
|
|
0bc21b3ddf | ||
|
|
c298b23c45 | ||
|
|
722e3fa481 | ||
|
|
3fc092d23f | ||
|
|
6e0847ca49 | ||
|
|
7a190de2f1 | ||
|
|
57a1d7b4ee | ||
|
|
3e0e99176a |
1539
.docker/chrome.json
1539
.docker/chrome.json
File diff suppressed because it is too large
Load Diff
@@ -1,14 +0,0 @@
|
||||
# Note: 2 blank lines are required between entries
|
||||
Package: *
|
||||
Pin: release a=eoan
|
||||
Pin-Priority: 500
|
||||
|
||||
Package: *
|
||||
Pin: origin "ftp.debian.org"
|
||||
Pin-Priority: 300
|
||||
|
||||
# Pattern includes 'chromium', 'chromium-browser' and similarly
|
||||
# named dependencies:
|
||||
Package: chromium*
|
||||
Pin: origin "ftp.debian.org"
|
||||
Pin-Priority: 700
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
name=$(openssl rand -hex 12)
|
||||
id=$(docker create --name=bun-binary-$name $CONTAINER_TAG)
|
||||
docker container cp bun-binary-$name:$BUN_RELEASE_DIR bun-binary
|
||||
echo -e "bun-binary-$name"
|
||||
@@ -1,3 +0,0 @@
|
||||
deb http://deb.debian.org/debian buster main
|
||||
deb http://deb.debian.org/debian buster-updates main
|
||||
deb http://deb.debian.org/debian-security buster/updates main
|
||||
@@ -1,34 +0,0 @@
|
||||
export DOCKER_BUILDKIT=1
|
||||
|
||||
export BUILDKIT_ARCH=$(uname -m)
|
||||
export ARCH=${BUILDKIT_ARCH}
|
||||
|
||||
if [ "$BUILDKIT_ARCH" == "amd64" ]; then
|
||||
export BUILDKIT_ARCH="amd64"
|
||||
export ARCH=x64
|
||||
fi
|
||||
|
||||
if [ "$BUILDKIT_ARCH" == "x86_64" ]; then
|
||||
export BUILDKIT_ARCH="amd64"
|
||||
export ARCH=x64
|
||||
fi
|
||||
|
||||
if [ "$BUILDKIT_ARCH" == "arm64" ]; then
|
||||
export BUILDKIT_ARCH="arm64"
|
||||
export ARCH=aarch64
|
||||
fi
|
||||
|
||||
if [ "$BUILDKIT_ARCH" == "aarch64" ]; then
|
||||
export BUILDKIT_ARCH="arm64"
|
||||
export ARCH=aarch64
|
||||
fi
|
||||
|
||||
if [ "$BUILDKIT_ARCH" == "armv7l" ]; then
|
||||
echo "Unsupported platform: $BUILDKIT_ARCH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export BUILD_ID=$(cat build-id)
|
||||
export CONTAINER_NAME=bun-linux-$ARCH
|
||||
export DEBUG_CONTAINER_NAME=debug-bun-linux-$ARCH
|
||||
export TEMP=/tmp/bun-0.0.$BUILD_ID
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
docker pull bunbunbunbun/bun-test-base:latest --platform=linux/amd64
|
||||
docker pull bunbunbunbun/bun-base:latest --platform=linux/amd64
|
||||
docker pull bunbunbunbun/bun-base-with-zig-and-webkit:latest --platform=linux/amd64
|
||||
|
||||
docker tag bunbunbunbun/bun-test-base:latest bun-base:latest
|
||||
docker tag bunbunbunbun/bun-base:latest bun-base:latest
|
||||
docker tag bunbunbunbun/bun-base-with-zig-and-webkit:latest bun-base-with-zig-and-webkit:latest
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "dockerfile-common.sh"
|
||||
|
||||
export $CONTAINER_NAME=$CONTAINER_NAME-local
|
||||
|
||||
rm -rf $TEMP
|
||||
mkdir -p $TEMP
|
||||
|
||||
docker build . --target release --progress=plain -t $CONTAINER_NAME:latest --build-arg BUILDKIT_INLINE_CACHE=1 --platform=linux/$BUILDKIT_ARCH --cache-from $CONTAINER_NAME:latest
|
||||
|
||||
if (($?)); then
|
||||
echo "Failed to build container"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
id=$(docker create $CONTAINER_NAME:latest)
|
||||
docker cp $id:/home/ubuntu/bun-release $TEMP/$CONTAINER_NAME
|
||||
if (($?)); then
|
||||
echo "Failed to cp container"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd $TEMP
|
||||
mkdir -p $TEMP/$CONTAINER_NAME $TEMP/$DEBUG_CONTAINER_NAME
|
||||
mv $CONTAINER_NAME/bun-profile $DEBUG_CONTAINER_NAME/bun
|
||||
zip -r $CONTAINER_NAME.zip $CONTAINER_NAME
|
||||
zip -r $DEBUG_CONTAINER_NAME.zip $DEBUG_CONTAINER_NAME
|
||||
docker rm -v $id
|
||||
abs=$(realpath $TEMP/$CONTAINER_NAME.zip)
|
||||
debug_abs=$(realpath $TEMP/$DEBUG_CONTAINER_NAME.zip)
|
||||
|
||||
case $(uname -s) in
|
||||
"Linux") target="linux" ;;
|
||||
*) target="other" ;;
|
||||
esac
|
||||
|
||||
if [ "$target" = "linux" ]; then
|
||||
if command -v bun --version >/dev/null; then
|
||||
cp $TEMP/$CONTAINER_NAME/bun $(which bun)
|
||||
cp $TEMP/$DEBUG_CONTAINER_NAME/bun $(which bun-profile)
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Saved to:"
|
||||
echo $debug_abs
|
||||
echo $abs
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
bun install
|
||||
bun install --cwd ./test/snippets
|
||||
bun install --cwd ./test/scripts
|
||||
|
||||
make $BUN_TEST_NAME
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
docker container run --security-opt seccomp=.docker/chrome.json --env GITHUB_WORKSPACE=$GITHUB_WORKSPACE --env BUN_TEST_NAME=$BUN_TEST_NAME --ulimit memlock=-1:-1 --init --rm bun-test:latest
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
docker container run --security-opt seccomp=.docker/chrome.json --env GITHUB_WORKSPACE=$GITHUB_WORKSPACE --ulimit memlock=-1:-1 --init --rm bun-unit-tests:latest
|
||||
1
.github/actions/setup-bun/action.yml
vendored
1
.github/actions/setup-bun/action.yml
vendored
@@ -47,4 +47,5 @@ runs:
|
||||
mkdir -p ${{ runner.temp }}/.bun/bin
|
||||
mv ${target}/bun* ${{ runner.temp }}/.bun/bin/
|
||||
chmod +x ${{ runner.temp }}/.bun/bin/*
|
||||
ln -fs ${{ runner.temp }}/.bun/bin/bun ${{ runner.temp }}/.bun/bin/bunx
|
||||
echo "${{ runner.temp }}/.bun/bin" >> ${GITHUB_PATH}
|
||||
|
||||
60
.github/workflows/clang-format.yml
vendored
Normal file
60
.github/workflows/clang-format.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
name: clang-format
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/clang-format.yml"
|
||||
- ".clang-format"
|
||||
- "package.json"
|
||||
- "scripts/**"
|
||||
- "cmake/**"
|
||||
- "src/**/*.c"
|
||||
- "src/**/*.cpp"
|
||||
- "src/**/*.h"
|
||||
- "packages/**/*.c"
|
||||
- "packages/**/*.cpp"
|
||||
- "packages/**/*.h"
|
||||
|
||||
env:
|
||||
BUN_VERSION: "1.1.27"
|
||||
LLVM_VERSION: "18.1.8"
|
||||
LLVM_VERSION_MAJOR: "18"
|
||||
|
||||
jobs:
|
||||
clang-format:
|
||||
name: clang-format
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.github
|
||||
.clang-format
|
||||
package.json
|
||||
scripts
|
||||
cmake
|
||||
src
|
||||
packages
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: ${{ env.BUN_VERSION }}
|
||||
- name: Install LLVM
|
||||
run: |
|
||||
curl -fsSL https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.LLVM_VERSION_MAJOR }} all
|
||||
- name: Clang Format
|
||||
env:
|
||||
ENABLE_CCACHE: OFF
|
||||
LLVM_VERSION: ${{ env.LLVM_VERSION }}
|
||||
run: |
|
||||
bun run clang-format:diff
|
||||
- name: Commit
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: "`bun run clang-format`"
|
||||
60
.github/workflows/clang-tidy.yml
vendored
Normal file
60
.github/workflows/clang-tidy.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
name: clang-tidy
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/clang-tidy.yml"
|
||||
- ".clang-tidy"
|
||||
- "package.json"
|
||||
- "scripts/**"
|
||||
- "cmake/**"
|
||||
- "src/**/*.c"
|
||||
- "src/**/*.cpp"
|
||||
- "src/**/*.h"
|
||||
- "packages/**/*.c"
|
||||
- "packages/**/*.cpp"
|
||||
- "packages/**/*.h"
|
||||
|
||||
env:
|
||||
BUN_VERSION: "1.1.27"
|
||||
LLVM_VERSION: "18.1.8"
|
||||
LLVM_VERSION_MAJOR: "18"
|
||||
|
||||
jobs:
|
||||
clang-tidy:
|
||||
name: clang-tidy
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.github
|
||||
.clang-tidy
|
||||
package.json
|
||||
scripts
|
||||
cmake
|
||||
src
|
||||
packages
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: ${{ env.BUN_VERSION }}
|
||||
- name: Install LLVM
|
||||
run: |
|
||||
curl -fsSL https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.LLVM_VERSION_MAJOR }} all
|
||||
- name: Clang Tidy
|
||||
env:
|
||||
ENABLE_CCACHE: OFF
|
||||
LLVM_VERSION: ${{ env.LLVM_VERSION }}
|
||||
run: |
|
||||
bun run clang-tidy:diff
|
||||
- name: Commit
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: "`bun run clang-tidy`"
|
||||
61
.github/workflows/format.yml
vendored
61
.github/workflows/format.yml
vendored
@@ -1,61 +0,0 @@
|
||||
name: Format
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: format-${{ github.workflow }}-${{ github.event_name == 'workflow_dispatch' && inputs.run-id || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
run-id:
|
||||
type: string
|
||||
description: The workflow ID to download artifacts (skips the build step)
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
format:
|
||||
name: Format
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.prettierrc-ci
|
||||
.github
|
||||
.vscode
|
||||
src
|
||||
scripts
|
||||
packages
|
||||
test
|
||||
bench
|
||||
package.json
|
||||
bun.lockb
|
||||
.clang-format
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: "1.1.25"
|
||||
- name: Setup Zig
|
||||
uses: mlugg/setup-zig@v1
|
||||
with:
|
||||
version: 0.13.0
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
bun install
|
||||
- name: Format
|
||||
run: |
|
||||
bun fmt
|
||||
- name: Format Zig
|
||||
run: |
|
||||
bun fmt:zig
|
||||
- name: Format Cpp
|
||||
run: |
|
||||
bun fmt:cpp
|
||||
- name: Commit
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: Apply formatting changes
|
||||
49
.github/workflows/prettier-format.yml
vendored
Normal file
49
.github/workflows/prettier-format.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
name: prettier-format
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/prettier-format.yml"
|
||||
- "package.json"
|
||||
- "scripts/**"
|
||||
- "**.yml"
|
||||
- "**.json"
|
||||
- "**.js"
|
||||
- "**.jsx"
|
||||
- "**.ts"
|
||||
- "**.tsx"
|
||||
- "**.mjs"
|
||||
- "**.cjs"
|
||||
|
||||
env:
|
||||
BUN_VERSION: "1.1.27"
|
||||
|
||||
jobs:
|
||||
prettier-format:
|
||||
name: prettier-format
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: ${{ env.BUN_VERSION }}
|
||||
- name: Setup Dependencies
|
||||
run: |
|
||||
bun install
|
||||
- name: Prettier Format
|
||||
env:
|
||||
ENABLE_CCACHE: OFF
|
||||
SKIP_LLVM: ON
|
||||
run: |
|
||||
bun run prettier:diff
|
||||
- name: Commit
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: "`bun run prettier:extra`"
|
||||
56
.github/workflows/run-format.yml
vendored
56
.github/workflows/run-format.yml
vendored
@@ -1,56 +0,0 @@
|
||||
name: Format
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
zig-version:
|
||||
type: string
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
format:
|
||||
name: Format
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.prettierrc-ci
|
||||
.github
|
||||
.vscode
|
||||
src
|
||||
scripts
|
||||
packages
|
||||
test
|
||||
bench
|
||||
package.json
|
||||
bun.lockb
|
||||
.clang-format
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: "1.1.25"
|
||||
- name: Setup Zig
|
||||
uses: mlugg/setup-zig@v1
|
||||
with:
|
||||
version: ${{ inputs.zig-version }}
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
bun install
|
||||
- name: Format
|
||||
run: |
|
||||
bun fmt
|
||||
- name: Format Zig
|
||||
run: |
|
||||
bun fmt:zig
|
||||
- name: Format Cpp
|
||||
run: |
|
||||
bun fmt:cpp
|
||||
- name: Commit
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: Apply formatting changes
|
||||
48
.github/workflows/zig-format.yml
vendored
Normal file
48
.github/workflows/zig-format.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: zig-format
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/zig-format.yml"
|
||||
- "package.json"
|
||||
- "scripts/**"
|
||||
- "cmake/**"
|
||||
- "src/**/*.zig"
|
||||
|
||||
env:
|
||||
BUN_VERSION: "1.1.27"
|
||||
|
||||
jobs:
|
||||
zig-format:
|
||||
name: zig-format
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.github
|
||||
package.json
|
||||
scripts
|
||||
cmake
|
||||
src
|
||||
packages
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: ${{ env.BUN_VERSION }}
|
||||
- name: Zig Format
|
||||
env:
|
||||
ENABLE_CCACHE: OFF
|
||||
SKIP_LLVM: ON
|
||||
run: |
|
||||
bun run zig-format:diff
|
||||
- name: Commit
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: "`bun run zig-format`"
|
||||
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"arrowParens": "avoid",
|
||||
"printWidth": 120,
|
||||
"trailingComma": "all",
|
||||
"useTabs": false,
|
||||
"quoteProps": "preserve",
|
||||
"plugins": [
|
||||
"prettier-plugin-organize-imports"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
".vscode/*.json"
|
||||
],
|
||||
"options": {
|
||||
"parser": "jsonc",
|
||||
"quoteProps": "preserve",
|
||||
"singleQuote": false,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.md"
|
||||
],
|
||||
"options": {
|
||||
"printWidth": 80
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
2
.vscode/launch.json
generated
vendored
2
.vscode/launch.json
generated
vendored
@@ -1192,4 +1192,4 @@
|
||||
"description": "Usage: bun test [...]",
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -52,12 +52,15 @@
|
||||
"cmake.configureOnOpen": false,
|
||||
"C_Cpp.errorSquiggles": "enabled",
|
||||
"[cpp]": {
|
||||
"editor.tabSize": 4,
|
||||
"editor.defaultFormatter": "xaver.clang-format",
|
||||
},
|
||||
"[c]": {
|
||||
"editor.tabSize": 4,
|
||||
"editor.defaultFormatter": "xaver.clang-format",
|
||||
},
|
||||
"[h]": {
|
||||
"editor.tabSize": 4,
|
||||
"editor.defaultFormatter": "xaver.clang-format",
|
||||
},
|
||||
"clangd.arguments": ["-header-insertion=never"],
|
||||
|
||||
@@ -30,6 +30,7 @@ include(CompilerFlags)
|
||||
|
||||
# --- Tools ---
|
||||
|
||||
include(SetupGit)
|
||||
include(SetupBuildkite)
|
||||
include(SetupBun)
|
||||
include(SetupEsbuild)
|
||||
@@ -39,3 +40,13 @@ include(SetupRust)
|
||||
# --- Targets ---
|
||||
|
||||
include(BuildBun)
|
||||
|
||||
# --- Analysis ---
|
||||
|
||||
include(RunClangFormat)
|
||||
include(RunClangTidy)
|
||||
include(RunZigFormat)
|
||||
|
||||
if (ENABLE_PRETTIER)
|
||||
include(RunPrettier)
|
||||
endif()
|
||||
|
||||
27
Makefile
27
Makefile
@@ -77,7 +77,7 @@ BUN_RELEASE_BIN = $(PACKAGE_DIR)/bun
|
||||
PRETTIER ?= $(shell which prettier 2>/dev/null || echo "./node_modules/.bin/prettier")
|
||||
ESBUILD = "$(shell which esbuild 2>/dev/null || echo "./node_modules/.bin/esbuild")"
|
||||
DSYMUTIL ?= $(shell which dsymutil 2>/dev/null || which dsymutil-15 2>/dev/null)
|
||||
WEBKIT_DIR ?= $(realpath src/bun.js/WebKit)
|
||||
WEBKIT_DIR ?= $(realpath vendor/WebKit)
|
||||
WEBKIT_RELEASE_DIR ?= $(WEBKIT_DIR)/WebKitBuild/Release
|
||||
WEBKIT_DEBUG_DIR ?= $(WEBKIT_DIR)/WebKitBuild/Debug
|
||||
WEBKIT_RELEASE_DIR_LTO ?= $(WEBKIT_DIR)/WebKitBuild/ReleaseLTO
|
||||
@@ -138,8 +138,8 @@ endif
|
||||
SED = $(shell which gsed 2>/dev/null || which sed 2>/dev/null)
|
||||
|
||||
BUN_DIR ?= $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
|
||||
BUN_DEPS_DIR ?= $(shell pwd)/src/deps
|
||||
BUN_DEPS_OUT_DIR ?= $(shell pwd)/build/bun-deps
|
||||
BUN_DEPS_DIR ?= $(shell pwd)/vendor
|
||||
BUN_DEPS_OUT_DIR ?= $(shell pwd)/build/release
|
||||
CPU_COUNT = 2
|
||||
ifeq ($(OS_NAME),darwin)
|
||||
CPU_COUNT = $(shell sysctl -n hw.logicalcpu)
|
||||
@@ -689,19 +689,10 @@ assert-deps:
|
||||
@test $(shell cargo --version | awk '{print $$2}' | cut -d. -f2) -gt 57 || (echo -e "ERROR: cargo version must be at least 1.57."; exit 1)
|
||||
@echo "You have the dependencies installed! Woo"
|
||||
|
||||
# the following allows you to run `make submodule` to update or init submodules. but we will exclude webkit
|
||||
# unless you explicitly clone it yourself (a huge download)
|
||||
SUBMODULE_NAMES=$(shell cat .gitmodules | grep 'path = ' | awk '{print $$3}')
|
||||
ifeq ("$(wildcard src/bun.js/WebKit/.git)", "")
|
||||
SUBMODULE_NAMES := $(filter-out src/bun.js/WebKit, $(SUBMODULE_NAMES))
|
||||
endif
|
||||
|
||||
.PHONY: init-submodules
|
||||
init-submodules: submodule # (backwards-compatibility alias)
|
||||
|
||||
.PHONY: submodule
|
||||
submodule: ## to init or update all submodules
|
||||
git submodule update --init --recursive --progress --depth=1 --checkout $(SUBMODULE_NAMES)
|
||||
|
||||
.PHONY: build-obj
|
||||
build-obj:
|
||||
@@ -804,7 +795,7 @@ cls:
|
||||
@echo -e "\n\n---\n\n"
|
||||
|
||||
jsc-check:
|
||||
@ls $(JSC_BASE_DIR) >/dev/null 2>&1 || (echo -e "Failed to access WebKit build. Please compile the WebKit submodule using the Dockerfile at $(shell pwd)/src/javascript/WebKit/Dockerfile and then copy from /output in the Docker container to $(JSC_BASE_DIR). You can override the directory via JSC_BASE_DIR. \n\n DOCKER_BUILDKIT=1 docker build -t bun-webkit $(shell pwd)/src/bun.js/WebKit -f $(shell pwd)/src/bun.js/WebKit/Dockerfile --progress=plain\n\n docker container create bun-webkit\n\n # Get the container ID\n docker container ls\n\n docker cp DOCKER_CONTAINER_ID_YOU_JUST_FOUND:/output $(JSC_BASE_DIR)" && exit 1)
|
||||
@ls $(JSC_BASE_DIR) >/dev/null 2>&1 || (echo -e "Failed to access WebKit build. Please compile the WebKit submodule using the Dockerfile at $(shell pwd)/src/javascript/WebKit/Dockerfile and then copy from /output in the Docker container to $(JSC_BASE_DIR). You can override the directory via JSC_BASE_DIR. \n\n DOCKER_BUILDKIT=1 docker build -t bun-webkit $(shell pwd)/vendor/WebKit -f $(shell pwd)/vendor/WebKit/Dockerfile --progress=plain\n\n docker container create bun-webkit\n\n # Get the container ID\n docker container ls\n\n docker cp DOCKER_CONTAINER_ID_YOU_JUST_FOUND:/output $(JSC_BASE_DIR)" && exit 1)
|
||||
@ls $(JSC_INCLUDE_DIR) >/dev/null 2>&1 || (echo "Failed to access WebKit include directory at $(JSC_INCLUDE_DIR)." && exit 1)
|
||||
@ls $(JSC_LIB) >/dev/null 2>&1 || (echo "Failed to access WebKit lib directory at $(JSC_LIB)." && exit 1)
|
||||
|
||||
@@ -945,7 +936,7 @@ jsc-bindings: headers bindings
|
||||
|
||||
.PHONY: clone-submodules
|
||||
clone-submodules:
|
||||
git -c submodule."src/bun.js/WebKit".update=none submodule update --init --recursive --depth=1 --progress
|
||||
git -c submodule."vendor/WebKit".update=none submodule update --init --recursive --depth=1 --progress
|
||||
|
||||
|
||||
.PHONY: headers
|
||||
@@ -1265,7 +1256,7 @@ jsc-build-mac-compile:
|
||||
-DENABLE_STATIC_JSC=ON \
|
||||
-DENABLE_SINGLE_THREADED_VM_ENTRY_SCOPE=ON \
|
||||
-DALLOW_LINE_AND_COLUMN_NUMBER_IN_BUILTINS=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DUSE_THIN_ARCHIVES=OFF \
|
||||
-DBUN_FAST_TLS=ON \
|
||||
-DENABLE_FTL_JIT=ON \
|
||||
@@ -1277,7 +1268,7 @@ jsc-build-mac-compile:
|
||||
$(WEBKIT_DIR) \
|
||||
$(WEBKIT_RELEASE_DIR) && \
|
||||
CFLAGS="$(CFLAGS) -ffat-lto-objects" CXXFLAGS="$(CXXFLAGS) -ffat-lto-objects" \
|
||||
cmake --build $(WEBKIT_RELEASE_DIR) --config Release --target jsc
|
||||
cmake --build $(WEBKIT_RELEASE_DIR) --config RelWithDebInfo --target jsc
|
||||
|
||||
.PHONY: jsc-build-mac-compile-lto
|
||||
jsc-build-mac-compile-lto:
|
||||
@@ -1379,7 +1370,7 @@ jsc-build-linux-compile-config-debug:
|
||||
$(WEBKIT_DEBUG_DIR)
|
||||
|
||||
# If you get "Error: could not load cache"
|
||||
# run rm -rf src/bun.js/WebKit/CMakeCache.txt
|
||||
# run rm -rf vendor/WebKit/CMakeCache.txt
|
||||
.PHONY: jsc-build-linux-compile-build
|
||||
jsc-build-linux-compile-build:
|
||||
mkdir -p $(WEBKIT_RELEASE_DIR) && \
|
||||
@@ -1414,7 +1405,7 @@ jsc-build-copy-debug:
|
||||
cp $(WEBKIT_DEBUG_DIR)/lib/libbmalloc.a $(BUN_DEPS_OUT_DIR)/libbmalloc.a
|
||||
|
||||
clean-jsc:
|
||||
cd src/bun.js/WebKit && rm -rf **/CMakeCache.txt **/CMakeFiles && rm -rf src/bun.js/WebKit/WebKitBuild
|
||||
cd vendor/WebKit && rm -rf **/CMakeCache.txt **/CMakeFiles && rm -rf vendor/WebKit/WebKitBuild
|
||||
clean-bindings:
|
||||
rm -rf $(OBJ_DIR)/*.o $(DEBUG_OBJ_DIR)/*.o $(DEBUG_OBJ_DIR)/webcore/*.o $(DEBUG_BINDINGS_OBJ) $(OBJ_DIR)/webcore/*.o $(BINDINGS_OBJ) $(OBJ_DIR)/*.d $(DEBUG_OBJ_DIR)/*.d
|
||||
|
||||
|
||||
BIN
bench/bun.lockb
BIN
bench/bun.lockb
Binary file not shown.
24
bench/crypto/asymmetricSign.js
Normal file
24
bench/crypto/asymmetricSign.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { bench, run } from "mitata";
|
||||
const crypto = require("node:crypto");
|
||||
|
||||
const keyPair = crypto.generateKeyPairSync("rsa", {
|
||||
modulusLength: 2048,
|
||||
publicKeyEncoding: {
|
||||
type: "spki",
|
||||
format: "pem",
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: "pkcs8",
|
||||
format: "pem",
|
||||
},
|
||||
});
|
||||
|
||||
// Max message size for 2048-bit RSA keys
|
||||
const plaintext = crypto.getRandomValues(Buffer.alloc(245));
|
||||
|
||||
bench("RSA sign RSA_PKCS1_PADDING round-trip", () => {
|
||||
const sig = crypto.privateEncrypt(keyPair.privateKey, plaintext);
|
||||
crypto.publicDecrypt(keyPair.publicKey, sig);
|
||||
});
|
||||
|
||||
await run();
|
||||
@@ -7,6 +7,7 @@
|
||||
"@swc/core": "^1.2.133",
|
||||
"benchmark": "^2.1.4",
|
||||
"braces": "^3.0.2",
|
||||
"color": "^4.2.3",
|
||||
"esbuild": "^0.14.12",
|
||||
"eventemitter3": "^5.0.0",
|
||||
"execa": "^8.0.1",
|
||||
@@ -14,6 +15,7 @@
|
||||
"fdir": "^6.1.0",
|
||||
"mitata": "^0.1.6",
|
||||
"string-width": "7.1.0",
|
||||
"tinycolor2": "^1.6.0",
|
||||
"zx": "^7.2.3"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
25
bench/snippets/color.mjs
Normal file
25
bench/snippets/color.mjs
Normal file
@@ -0,0 +1,25 @@
|
||||
import Color from "color";
|
||||
import tinycolor from "tinycolor2";
|
||||
import { bench, run, group } from "./runner.mjs";
|
||||
|
||||
const inputs = ["#f00", "rgb(255, 0, 0)", "rgba(255, 0, 0, 1)", "hsl(0, 100%, 50%)"];
|
||||
|
||||
for (const input of inputs) {
|
||||
group(`${input}`, () => {
|
||||
if (typeof Bun !== "undefined") {
|
||||
bench("Bun.color()", () => {
|
||||
Bun.color(input, "css");
|
||||
});
|
||||
}
|
||||
|
||||
bench("color", () => {
|
||||
Color(input).hex();
|
||||
});
|
||||
|
||||
bench("'tinycolor2'", () => {
|
||||
tinycolor(input).toHexString();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
await run();
|
||||
@@ -157,7 +157,7 @@ pub fn build(b: *Build) !void {
|
||||
|
||||
// TODO: Upgrade path for 0.14.0
|
||||
// b.graph.zig_lib_directory = brk: {
|
||||
// const sub_path = "src/deps/zig/lib";
|
||||
// const sub_path = "vendor/zig/lib";
|
||||
// const dir = try b.build_root.handle.openDir(sub_path, .{});
|
||||
// break :brk .{ .handle = dir, .path = try b.build_root.join(b.graph.arena, &.{sub_path}) };
|
||||
// };
|
||||
@@ -295,7 +295,7 @@ pub fn build(b: *Build) !void {
|
||||
bun_check_obj.generated_bin = null;
|
||||
step.dependOn(&bun_check_obj.step);
|
||||
|
||||
// The default install step will run zig build check This is so ZLS
|
||||
// The default install step will run zig build check. This is so ZLS
|
||||
// identifies the codebase, as well as performs checking if build on
|
||||
// save is enabled.
|
||||
|
||||
@@ -368,6 +368,7 @@ pub fn addBunObject(b: *Build, opts: *BunBuildOptions) *Compile {
|
||||
.root_source_file = switch (opts.os) {
|
||||
.wasm => b.path("root_wasm.zig"),
|
||||
else => b.path("root.zig"),
|
||||
// else => b.path("root_css.zig"),
|
||||
},
|
||||
.target = opts.target,
|
||||
.optimize = opts.optimize,
|
||||
|
||||
@@ -124,12 +124,19 @@ optionx(CACHE_STRATEGY "read-write|read-only|write-only|none" "The strategy to u
|
||||
optionx(CI BOOL "If CI is enabled" DEFAULT OFF)
|
||||
|
||||
if(CI)
|
||||
set(DEFAULT_VENDOR_PATH ${CACHE_PATH}/vendor)
|
||||
set(WARNING FATAL_ERROR)
|
||||
else()
|
||||
set(DEFAULT_VENDOR_PATH ${CWD}/vendor)
|
||||
set(WARNING WARNING)
|
||||
endif()
|
||||
|
||||
optionx(VENDOR_PATH FILEPATH "The path to the vendor directory" DEFAULT ${DEFAULT_VENDOR_PATH})
|
||||
# TODO: This causes flaky zig builds in CI, so temporarily disable it.
|
||||
# if(CI)
|
||||
# set(DEFAULT_VENDOR_PATH ${CACHE_PATH}/vendor)
|
||||
# else()
|
||||
# set(DEFAULT_VENDOR_PATH ${CWD}/vendor)
|
||||
# endif()
|
||||
|
||||
optionx(VENDOR_PATH FILEPATH "The path to the vendor directory" DEFAULT ${CWD}/vendor)
|
||||
optionx(TMP_PATH FILEPATH "The path to the temporary directory" DEFAULT ${BUILD_PATH}/tmp)
|
||||
|
||||
optionx(FRESH BOOL "Set when --fresh is used" DEFAULT OFF)
|
||||
@@ -377,12 +384,12 @@ function(register_command)
|
||||
get_source_file_property(generated ${output} GENERATED)
|
||||
if(generated)
|
||||
list(REMOVE_ITEM CMD_EFFECTIVE_OUTPUTS ${output})
|
||||
list(APPEND CMD_EFFECTIVE_OUTPUTS ${output}.always_run)
|
||||
list(APPEND CMD_EFFECTIVE_OUTPUTS ${output}.always_run_${CMD_TARGET})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(CMD_ALWAYS_RUN)
|
||||
list(APPEND CMD_EFFECTIVE_OUTPUTS ${CMD_CWD}/.always_run)
|
||||
list(APPEND CMD_EFFECTIVE_OUTPUTS ${CMD_CWD}/.always_run_${CMD_TARGET})
|
||||
endif()
|
||||
|
||||
if(CMD_TARGET_PHASE)
|
||||
@@ -575,14 +582,6 @@ function(register_repository)
|
||||
set(GIT_PATH ${VENDOR_PATH}/${GIT_NAME})
|
||||
endif()
|
||||
|
||||
if(GIT_COMMIT)
|
||||
set(GIT_REF ${GIT_COMMIT})
|
||||
elseif(GIT_TAG)
|
||||
set(GIT_REF refs/tags/${GIT_TAG})
|
||||
else()
|
||||
set(GIT_REF refs/heads/${GIT_BRANCH})
|
||||
endif()
|
||||
|
||||
set(GIT_EFFECTIVE_OUTPUTS)
|
||||
foreach(output ${GIT_OUTPUTS})
|
||||
list(APPEND GIT_EFFECTIVE_OUTPUTS ${GIT_PATH}/${output})
|
||||
@@ -597,8 +596,10 @@ function(register_repository)
|
||||
${CMAKE_COMMAND}
|
||||
-DGIT_PATH=${GIT_PATH}
|
||||
-DGIT_REPOSITORY=${GIT_REPOSITORY}
|
||||
-DGIT_REF=${GIT_REF}
|
||||
-DGIT_NAME=${GIT_NAME}
|
||||
-DGIT_COMMIT=${GIT_COMMIT}
|
||||
-DGIT_TAG=${GIT_TAG}
|
||||
-DGIT_BRANCH=${GIT_BRANCH}
|
||||
-P ${CWD}/cmake/scripts/GitClone.cmake
|
||||
OUTPUTS
|
||||
${GIT_PATH}
|
||||
|
||||
@@ -91,6 +91,8 @@ if(LINUX)
|
||||
optionx(ENABLE_VALGRIND BOOL "If Valgrind support should be enabled" DEFAULT OFF)
|
||||
endif()
|
||||
|
||||
optionx(ENABLE_PRETTIER BOOL "If prettier should be ran" DEFAULT OFF)
|
||||
|
||||
if(USE_VALGRIND AND NOT USE_BASELINE)
|
||||
message(WARNING "If valgrind is enabled, baseline must also be enabled")
|
||||
setx(USE_BASELINE ON)
|
||||
|
||||
71
cmake/analysis/RunClangFormat.cmake
Normal file
71
cmake/analysis/RunClangFormat.cmake
Normal file
@@ -0,0 +1,71 @@
|
||||
# https://clang.llvm.org/docs/ClangFormat.html
|
||||
|
||||
find_command(
|
||||
VARIABLE
|
||||
CLANG_FORMAT_PROGRAM
|
||||
COMMAND
|
||||
clang-format
|
||||
REQUIRED
|
||||
OFF
|
||||
)
|
||||
|
||||
set(CLANG_FORMAT_SOURCES ${BUN_C_SOURCES} ${BUN_CXX_SOURCES})
|
||||
|
||||
register_command(
|
||||
TARGET
|
||||
clang-format-check
|
||||
COMMENT
|
||||
"Running clang-format"
|
||||
COMMAND
|
||||
${CLANG_FORMAT_PROGRAM}
|
||||
-Werror
|
||||
--dry-run
|
||||
--verbose
|
||||
${CLANG_FORMAT_SOURCES}
|
||||
ALWAYS_RUN
|
||||
)
|
||||
|
||||
register_command(
|
||||
TARGET
|
||||
clang-format
|
||||
COMMENT
|
||||
"Fixing clang-format"
|
||||
COMMAND
|
||||
${CLANG_FORMAT_PROGRAM}
|
||||
-i # edits files in-place
|
||||
--verbose
|
||||
${CLANG_FORMAT_SOURCES}
|
||||
ALWAYS_RUN
|
||||
)
|
||||
|
||||
if(GIT_CHANGED_SOURCES)
|
||||
set(CLANG_FORMAT_CHANGED_SOURCES)
|
||||
foreach(source ${CLANG_FORMAT_SOURCES})
|
||||
list(FIND GIT_CHANGED_SOURCES ${source} index)
|
||||
if(NOT ${index} EQUAL -1)
|
||||
list(APPEND CLANG_FORMAT_CHANGED_SOURCES ${source})
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(CLANG_FORMAT_CHANGED_SOURCES)
|
||||
set(CLANG_FORMAT_DIFF_COMMAND ${CLANG_FORMAT_PROGRAM}
|
||||
-i # edits files in-place
|
||||
--verbose
|
||||
${CLANG_FORMAT_CHANGED_SOURCES}
|
||||
)
|
||||
else()
|
||||
set(CLANG_FORMAT_DIFF_COMMAND ${CMAKE_COMMAND} -E echo "No changed files for clang-format")
|
||||
endif()
|
||||
|
||||
register_command(
|
||||
TARGET
|
||||
clang-format-diff
|
||||
COMMENT
|
||||
"Running clang-format on changed files"
|
||||
COMMAND
|
||||
${CLANG_FORMAT_DIFF_COMMAND}
|
||||
CWD
|
||||
${BUILD_PATH}
|
||||
ALWAYS_RUN
|
||||
)
|
||||
@@ -11,46 +11,75 @@ find_command(
|
||||
OFF
|
||||
)
|
||||
|
||||
set(CLANG_TIDY_COMMAND ${CLANG_TIDY_PROGRAM} ${BUN_CPP_SOURCES}
|
||||
set(CLANG_TIDY_SOURCES ${BUN_C_SOURCES} ${BUN_CXX_SOURCES})
|
||||
|
||||
set(CLANG_TIDY_COMMAND ${CLANG_TIDY_PROGRAM}
|
||||
-p ${BUILD_PATH}
|
||||
--config-file=${CWD}/.clang-tidy
|
||||
--fix
|
||||
--fix-errors
|
||||
--fix-notes
|
||||
)
|
||||
|
||||
if(CMAKE_COLOR_DIAGNOSTICS)
|
||||
list(APPEND CLANG_TIDY_COMMAND --use-color)
|
||||
endif()
|
||||
|
||||
# Extra clang-tidy checks that are normally disabled due to noise.
|
||||
# e.g. JavaScriptCore/Lookup.h
|
||||
set(CLANG_TIDY_EXTRA_COMMAND ${CLANG_TIDY_PROGRAM}
|
||||
--checks=performance-*
|
||||
)
|
||||
|
||||
register_command(
|
||||
TARGET
|
||||
clang-tidy
|
||||
COMMENT
|
||||
"Running clang-tidy"
|
||||
COMMAND
|
||||
${CLANG_TIDY_COMMAND}
|
||||
${CLANG_TIDY_COMMAND}
|
||||
${CLANG_TIDY_SOURCES}
|
||||
--fix
|
||||
--fix-errors
|
||||
--fix-notes
|
||||
CWD
|
||||
${BUILD_PATH}
|
||||
TARGETS
|
||||
${bun}
|
||||
ALWAYS_RUN
|
||||
)
|
||||
|
||||
register_command(
|
||||
TARGET
|
||||
clang-tidy-extra
|
||||
clang-tidy-check
|
||||
COMMENT
|
||||
"Running clang-tidy with extra checks"
|
||||
"Checking clang-tidy"
|
||||
COMMAND
|
||||
${CLANG_TIDY_EXTRA_COMMAND}
|
||||
${CLANG_TIDY_COMMAND}
|
||||
${CLANG_TIDY_SOURCES}
|
||||
CWD
|
||||
${BUILD_PATH}
|
||||
TARGETS
|
||||
${bun}
|
||||
ALWAYS_RUN
|
||||
)
|
||||
|
||||
if(GIT_CHANGED_SOURCES)
|
||||
set(CLANG_TIDY_CHANGED_SOURCES)
|
||||
foreach(source ${CLANG_TIDY_SOURCES})
|
||||
list(FIND GIT_CHANGED_SOURCES ${source} index)
|
||||
if(NOT ${index} EQUAL -1)
|
||||
list(APPEND CLANG_TIDY_CHANGED_SOURCES ${source})
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(CLANG_TIDY_CHANGED_SOURCES)
|
||||
set(CLANG_TIDY_DIFF_COMMAND ${CLANG_TIDY_PROGRAM}
|
||||
${CLANG_TIDY_CHANGED_SOURCES}
|
||||
--fix
|
||||
--fix-errors
|
||||
--fix-notes
|
||||
)
|
||||
else()
|
||||
set(CLANG_TIDY_DIFF_COMMAND ${CMAKE_COMMAND} -E echo "No changed files for clang-tidy")
|
||||
endif()
|
||||
|
||||
register_command(
|
||||
TARGET
|
||||
clang-tidy-diff
|
||||
COMMENT
|
||||
"Running clang-tidy on changed files"
|
||||
COMMAND
|
||||
${CLANG_TIDY_DIFF_COMMAND}
|
||||
CWD
|
||||
${BUILD_PATH}
|
||||
ALWAYS_RUN
|
||||
)
|
||||
|
||||
123
cmake/analysis/RunPrettier.cmake
Normal file
123
cmake/analysis/RunPrettier.cmake
Normal file
@@ -0,0 +1,123 @@
|
||||
if(CMAKE_HOST_WIN32)
|
||||
setx(PRETTIER_EXECUTABLE ${CWD}/node_modules/.bin/prettier.exe)
|
||||
else()
|
||||
setx(PRETTIER_EXECUTABLE ${CWD}/node_modules/.bin/prettier)
|
||||
endif()
|
||||
|
||||
set(PRETTIER_PATHS
|
||||
${CWD}/src
|
||||
${CWD}/packages/bun-error
|
||||
${CWD}/packages/bun-types
|
||||
${CWD}/packages/bun-inspector-protocol
|
||||
${CWD}/packages/bun-inspector-frontend
|
||||
${CWD}/packages/bun-debug-adapter-protocol
|
||||
${CWD}/packages/bun-vscode
|
||||
${CWD}/test
|
||||
${CWD}/bench
|
||||
${CWD}/.vscode
|
||||
${CWD}/.buildkite
|
||||
${CWD}/.github
|
||||
)
|
||||
|
||||
set(PRETTIER_EXTENSIONS
|
||||
*.jsonc?
|
||||
*.ya?ml
|
||||
*.jsx?
|
||||
*.tsx?
|
||||
*.mjs
|
||||
*.cjs
|
||||
*.mts
|
||||
*.cts
|
||||
)
|
||||
|
||||
set(PRETTIER_GLOBS)
|
||||
foreach(path ${PRETTIER_PATHS})
|
||||
foreach(extension ${PRETTIER_EXTENSIONS})
|
||||
list(APPEND PRETTIER_GLOBS ${path}/${extension})
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
file(GLOB_RECURSE PRETTIER_SOURCES ${PRETTIER_GLOBS})
|
||||
|
||||
register_command(
|
||||
COMMAND
|
||||
${BUN_EXECUTABLE}
|
||||
install
|
||||
--frozen-lockfile
|
||||
SOURCES
|
||||
${CWD}/package.json
|
||||
OUTPUTS
|
||||
${PRETTIER_EXECUTABLE}
|
||||
)
|
||||
|
||||
set(PRETTIER_COMMAND ${PRETTIER_EXECUTABLE}
|
||||
--config=${CWD}/.prettierrc
|
||||
--cache
|
||||
)
|
||||
|
||||
register_command(
|
||||
TARGET
|
||||
prettier
|
||||
COMMENT
|
||||
"Running prettier"
|
||||
COMMAND
|
||||
${PRETTIER_COMMAND}
|
||||
--write
|
||||
${PRETTIER_SOURCES}
|
||||
ALWAYS_RUN
|
||||
)
|
||||
|
||||
register_command(
|
||||
TARGET
|
||||
prettier-extra
|
||||
COMMENT
|
||||
"Running prettier with extra plugins"
|
||||
COMMAND
|
||||
${PRETTIER_COMMAND}
|
||||
--write
|
||||
--plugin=prettier-plugin-organize-imports
|
||||
${PRETTIER_SOURCES}
|
||||
ALWAYS_RUN
|
||||
)
|
||||
|
||||
register_command(
|
||||
TARGET
|
||||
prettier-check
|
||||
COMMENT
|
||||
"Checking prettier"
|
||||
COMMAND
|
||||
${PRETTIER_COMMAND}
|
||||
--check
|
||||
${PRETTIER_SOURCES}
|
||||
ALWAYS_RUN
|
||||
)
|
||||
|
||||
if(GIT_CHANGED_SOURCES)
|
||||
set(PRETTIER_CHANGED_SOURCES)
|
||||
foreach(source ${PRETTIER_SOURCES})
|
||||
list(FIND PRETTIER_CHANGED_SOURCES ${source} index)
|
||||
if(NOT ${index} EQUAL -1)
|
||||
list(APPEND PRETTIER_CHANGED_SOURCES ${source})
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(PRETTIER_CHANGED_SOURCES)
|
||||
set(PRETTIER_DIFF_COMMAND ${PRETTIER_COMMAND}
|
||||
--write
|
||||
--plugin=prettier-plugin-organize-imports
|
||||
${PRETTIER_CHANGED_SOURCES}
|
||||
)
|
||||
else()
|
||||
set(PRETTIER_DIFF_COMMAND ${CMAKE_COMMAND} -E echo "No changed files for prettier")
|
||||
endif()
|
||||
|
||||
register_command(
|
||||
TARGET
|
||||
prettier-diff
|
||||
COMMENT
|
||||
"Running prettier on changed files"
|
||||
COMMAND
|
||||
${PRETTIER_DIFF_COMMAND}
|
||||
ALWAYS_RUN
|
||||
)
|
||||
57
cmake/analysis/RunZigFormat.cmake
Normal file
57
cmake/analysis/RunZigFormat.cmake
Normal file
@@ -0,0 +1,57 @@
|
||||
set(ZIG_FORMAT_SOURCES ${BUN_ZIG_SOURCES})
|
||||
|
||||
register_command(
|
||||
TARGET
|
||||
zig-format-check
|
||||
COMMENT
|
||||
"Checking zig fmt"
|
||||
COMMAND
|
||||
${ZIG_EXECUTABLE}
|
||||
fmt
|
||||
--check
|
||||
${ZIG_FORMAT_SOURCES}
|
||||
ALWAYS_RUN
|
||||
)
|
||||
|
||||
register_command(
|
||||
TARGET
|
||||
zig-format
|
||||
COMMENT
|
||||
"Running zig fmt"
|
||||
COMMAND
|
||||
${ZIG_EXECUTABLE}
|
||||
fmt
|
||||
${ZIG_FORMAT_SOURCES}
|
||||
ALWAYS_RUN
|
||||
)
|
||||
|
||||
if(GIT_CHANGED_SOURCES)
|
||||
set(ZIG_FORMAT_CHANGED_SOURCES)
|
||||
foreach(source ${ZIG_FORMAT_SOURCES})
|
||||
list(FIND GIT_CHANGED_SOURCES ${source} index)
|
||||
if(NOT ${index} EQUAL -1)
|
||||
list(APPEND ZIG_FORMAT_CHANGED_SOURCES ${source})
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(ZIG_FORMAT_CHANGED_SOURCES)
|
||||
set(ZIG_FORMAT_DIFF_COMMAND ${ZIG_EXECUTABLE}
|
||||
fmt
|
||||
${ZIG_FORMAT_CHANGED_SOURCES}
|
||||
)
|
||||
else()
|
||||
set(ZIG_FORMAT_DIFF_COMMAND ${CMAKE_COMMAND} -E echo "No changed files for zig-format")
|
||||
endif()
|
||||
|
||||
register_command(
|
||||
TARGET
|
||||
zig-format-diff
|
||||
COMMENT
|
||||
"Running zig fmt on changed files"
|
||||
COMMAND
|
||||
${ZIG_FORMAT_DIFF_COMMAND}
|
||||
CWD
|
||||
${BUILD_PATH}
|
||||
ALWAYS_RUN
|
||||
)
|
||||
129
cmake/scripts/DownloadUrl.cmake
Normal file
129
cmake/scripts/DownloadUrl.cmake
Normal file
@@ -0,0 +1,129 @@
|
||||
get_filename_component(SCRIPT_NAME ${CMAKE_CURRENT_LIST_FILE} NAME)
|
||||
message(STATUS "Running script: ${SCRIPT_NAME}")
|
||||
|
||||
if(NOT DOWNLOAD_URL OR NOT DOWNLOAD_PATH)
|
||||
message(FATAL_ERROR "DOWNLOAD_URL and DOWNLOAD_PATH are required")
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
set(TMP_PATH $ENV{TEMP})
|
||||
else()
|
||||
set(TMP_PATH $ENV{TMPDIR})
|
||||
endif()
|
||||
|
||||
if(NOT TMP_PATH)
|
||||
set(TMP_PATH ${CMAKE_BINARY_DIR}/tmp)
|
||||
endif()
|
||||
|
||||
string(REGEX REPLACE "/+$" "" TMP_PATH ${TMP_PATH})
|
||||
string(REGEX REPLACE "[^a-zA-Z0-9]" "-" DOWNLOAD_ID ${DOWNLOAD_URL})
|
||||
string(RANDOM LENGTH 8 RANDOM_ID)
|
||||
|
||||
set(DOWNLOAD_TMP_PATH ${TMP_PATH}/${DOWNLOAD_ID}-${RANDOM_ID})
|
||||
set(DOWNLOAD_TMP_FILE ${DOWNLOAD_TMP_PATH}/tmp)
|
||||
|
||||
file(REMOVE_RECURSE ${DOWNLOAD_TMP_PATH})
|
||||
|
||||
if(DOWNLOAD_ACCEPT_HEADER)
|
||||
set(DOWNLOAD_ACCEPT_HEADER "Accept: ${DOWNLOAD_ACCEPT_HEADER}")
|
||||
else()
|
||||
set(DOWNLOAD_ACCEPT_HEADER "Accept: */*")
|
||||
endif()
|
||||
|
||||
foreach(i RANGE 10)
|
||||
set(DOWNLOAD_TMP_FILE_${i} ${DOWNLOAD_TMP_FILE}.${i})
|
||||
|
||||
if(i EQUAL 0)
|
||||
message(STATUS "Downloading ${DOWNLOAD_URL}...")
|
||||
else()
|
||||
message(STATUS "Downloading ${DOWNLOAD_URL}... (retry ${i})")
|
||||
endif()
|
||||
|
||||
file(DOWNLOAD
|
||||
${DOWNLOAD_URL}
|
||||
${DOWNLOAD_TMP_FILE_${i}}
|
||||
HTTPHEADER "User-Agent: cmake/${CMAKE_VERSION}"
|
||||
HTTPHEADER ${DOWNLOAD_ACCEPT_HEADER}
|
||||
STATUS DOWNLOAD_STATUS
|
||||
INACTIVITY_TIMEOUT 60
|
||||
TIMEOUT 180
|
||||
SHOW_PROGRESS
|
||||
)
|
||||
|
||||
list(GET DOWNLOAD_STATUS 0 DOWNLOAD_STATUS_CODE)
|
||||
if(DOWNLOAD_STATUS_CODE EQUAL 0)
|
||||
if(NOT EXISTS ${DOWNLOAD_TMP_FILE_${i}})
|
||||
message(WARNING "Download failed: result is ok, but file does not exist: ${DOWNLOAD_TMP_FILE_${i}}")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
file(RENAME ${DOWNLOAD_TMP_FILE_${i}} ${DOWNLOAD_TMP_FILE})
|
||||
break()
|
||||
endif()
|
||||
|
||||
list(GET DOWNLOAD_STATUS 1 DOWNLOAD_STATUS_TEXT)
|
||||
file(REMOVE ${DOWNLOAD_TMP_FILE_${i}})
|
||||
message(WARNING "Download failed: ${DOWNLOAD_STATUS_CODE} ${DOWNLOAD_STATUS_TEXT}")
|
||||
endforeach()
|
||||
|
||||
if(NOT EXISTS ${DOWNLOAD_TMP_FILE})
|
||||
file(REMOVE_RECURSE ${DOWNLOAD_TMP_PATH})
|
||||
message(FATAL_ERROR "Download failed after too many attempts: ${DOWNLOAD_URL}")
|
||||
endif()
|
||||
|
||||
get_filename_component(DOWNLOAD_FILENAME ${DOWNLOAD_URL} NAME)
|
||||
if(DOWNLOAD_FILENAME MATCHES "\\.(zip|tar|gz|xz)$")
|
||||
message(STATUS "Extracting ${DOWNLOAD_FILENAME}...")
|
||||
|
||||
set(DOWNLOAD_TMP_EXTRACT ${DOWNLOAD_TMP_PATH}/extract)
|
||||
file(ARCHIVE_EXTRACT
|
||||
INPUT ${DOWNLOAD_TMP_FILE}
|
||||
DESTINATION ${DOWNLOAD_TMP_EXTRACT}
|
||||
TOUCH
|
||||
)
|
||||
|
||||
file(REMOVE ${DOWNLOAD_TMP_FILE})
|
||||
|
||||
if(DOWNLOAD_FILTERS)
|
||||
list(TRANSFORM DOWNLOAD_FILTERS PREPEND ${DOWNLOAD_TMP_EXTRACT}/ OUTPUT_VARIABLE DOWNLOAD_GLOBS)
|
||||
else()
|
||||
set(DOWNLOAD_GLOBS ${DOWNLOAD_TMP_EXTRACT}/*)
|
||||
endif()
|
||||
|
||||
file(GLOB DOWNLOAD_TMP_EXTRACT_PATHS LIST_DIRECTORIES ON ${DOWNLOAD_GLOBS})
|
||||
list(LENGTH DOWNLOAD_TMP_EXTRACT_PATHS DOWNLOAD_COUNT)
|
||||
|
||||
if(DOWNLOAD_COUNT EQUAL 0)
|
||||
file(REMOVE_RECURSE ${DOWNLOAD_TMP_PATH})
|
||||
|
||||
if(DOWNLOAD_FILTERS)
|
||||
message(FATAL_ERROR "Extract failed: No files found matching ${DOWNLOAD_FILTERS}")
|
||||
else()
|
||||
message(FATAL_ERROR "Extract failed: No files found")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(DOWNLOAD_FILTERS)
|
||||
set(DOWNLOAD_TMP_FILE ${DOWNLOAD_TMP_EXTRACT_PATHS})
|
||||
elseif(DOWNLOAD_COUNT EQUAL 1)
|
||||
list(GET DOWNLOAD_TMP_EXTRACT_PATHS 0 DOWNLOAD_TMP_FILE)
|
||||
get_filename_component(DOWNLOAD_FILENAME ${DOWNLOAD_TMP_FILE} NAME)
|
||||
message(STATUS "Hoisting ${DOWNLOAD_FILENAME}...")
|
||||
else()
|
||||
set(DOWNLOAD_TMP_FILE ${DOWNLOAD_TMP_EXTRACT})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(DOWNLOAD_FILTERS)
|
||||
foreach(file ${DOWNLOAD_TMP_FILE})
|
||||
file(RENAME ${file} ${DOWNLOAD_PATH})
|
||||
endforeach()
|
||||
else()
|
||||
file(REMOVE_RECURSE ${DOWNLOAD_PATH})
|
||||
get_filename_component(DOWNLOAD_PARENT_PATH ${DOWNLOAD_PATH} DIRECTORY)
|
||||
file(MAKE_DIRECTORY ${DOWNLOAD_PARENT_PATH})
|
||||
file(RENAME ${DOWNLOAD_TMP_FILE} ${DOWNLOAD_PATH})
|
||||
endif()
|
||||
|
||||
file(REMOVE_RECURSE ${DOWNLOAD_TMP_PATH})
|
||||
message(STATUS "Saved ${DOWNLOAD_PATH}")
|
||||
96
cmake/scripts/DownloadZig.cmake
Normal file
96
cmake/scripts/DownloadZig.cmake
Normal file
@@ -0,0 +1,96 @@
|
||||
get_filename_component(SCRIPT_NAME ${CMAKE_CURRENT_LIST_FILE} NAME)
|
||||
message(STATUS "Running script: ${SCRIPT_NAME}")
|
||||
|
||||
if(NOT ZIG_PATH OR NOT ZIG_COMMIT OR NOT ZIG_VERSION)
|
||||
message(FATAL_ERROR "ZIG_PATH, ZIG_COMMIT, and ZIG_VERSION are required")
|
||||
endif()
|
||||
|
||||
if(CMAKE_HOST_APPLE)
|
||||
set(ZIG_OS "macos")
|
||||
elseif(CMAKE_HOST_WIN32)
|
||||
set(ZIG_OS "windows")
|
||||
elseif(CMAKE_HOST_UNIX)
|
||||
set(ZIG_OS "linux")
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported operating system: ${CMAKE_HOST_SYSTEM_NAME}")
|
||||
endif()
|
||||
|
||||
# In script mode, using -P, this variable is not set
|
||||
if(NOT DEFINED CMAKE_HOST_SYSTEM_PROCESSOR)
|
||||
cmake_host_system_information(RESULT CMAKE_HOST_SYSTEM_PROCESSOR QUERY OS_PLATFORM)
|
||||
endif()
|
||||
|
||||
if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "arm64|ARM64|aarch64|AARCH64")
|
||||
set(ZIG_ARCH "aarch64")
|
||||
elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|AMD64|x86_64|X86_64|x64|X64")
|
||||
set(ZIG_ARCH "x86_64")
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported architecture: ${CMAKE_HOST_SYSTEM_PROCESSOR}")
|
||||
endif()
|
||||
|
||||
set(ZIG_NAME zig-${ZIG_OS}-${ZIG_ARCH}-${ZIG_VERSION})
|
||||
|
||||
if(CMAKE_HOST_WIN32)
|
||||
set(ZIG_EXE "zig.exe")
|
||||
set(ZIG_FILENAME ${ZIG_NAME}.zip)
|
||||
else()
|
||||
set(ZIG_EXE "zig")
|
||||
set(ZIG_FILENAME ${ZIG_NAME}.tar.xz)
|
||||
endif()
|
||||
|
||||
set(ZIG_DOWNLOAD_URL https://ziglang.org/download/${ZIG_VERSION}/${ZIG_FILENAME})
|
||||
|
||||
execute_process(
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-DDOWNLOAD_URL=${ZIG_DOWNLOAD_URL}
|
||||
-DDOWNLOAD_PATH=${ZIG_PATH}
|
||||
-P ${CMAKE_CURRENT_LIST_DIR}/DownloadUrl.cmake
|
||||
ERROR_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_VARIABLE
|
||||
ZIG_DOWNLOAD_ERROR
|
||||
RESULT_VARIABLE
|
||||
ZIG_DOWNLOAD_RESULT
|
||||
)
|
||||
|
||||
if(NOT ZIG_DOWNLOAD_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "Download failed: ${ZIG_DOWNLOAD_ERROR}")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS ${ZIG_PATH}/${ZIG_EXE})
|
||||
message(FATAL_ERROR "Executable not found: \"${ZIG_PATH}/${ZIG_EXE}\"")
|
||||
endif()
|
||||
|
||||
# Tools like VSCode need a stable path to the zig executable, on both Unix and Windows
|
||||
# To workaround this, we create a `bun.exe` symlink on Unix.
|
||||
if(NOT WIN32)
|
||||
file(CREATE_LINK ${ZIG_PATH}/${ZIG_EXE} ${ZIG_PATH}/zig.exe SYMBOLIC)
|
||||
endif()
|
||||
|
||||
set(ZIG_REPOSITORY_PATH ${ZIG_PATH}/repository)
|
||||
|
||||
execute_process(
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-DGIT_PATH=${ZIG_REPOSITORY_PATH}
|
||||
-DGIT_REPOSITORY=oven-sh/zig
|
||||
-DGIT_COMMIT=${ZIG_COMMIT}
|
||||
-P ${CMAKE_CURRENT_LIST_DIR}/GitClone.cmake
|
||||
ERROR_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_VARIABLE
|
||||
ZIG_REPOSITORY_ERROR
|
||||
RESULT_VARIABLE
|
||||
ZIG_REPOSITORY_RESULT
|
||||
)
|
||||
|
||||
if(NOT ZIG_REPOSITORY_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "Download failed: ${ZIG_REPOSITORY_ERROR}")
|
||||
endif()
|
||||
|
||||
file(REMOVE_RECURSE ${ZIG_PATH}/lib)
|
||||
|
||||
# Use copy_directory instead of file(RENAME) because there were
|
||||
# race conditions in CI where some files were not copied.
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory ${ZIG_REPOSITORY_PATH}/lib ${ZIG_PATH}/lib)
|
||||
|
||||
file(REMOVE_RECURSE ${ZIG_REPOSITORY_PATH})
|
||||
@@ -1,74 +1,85 @@
|
||||
include(cmake/Globals.cmake)
|
||||
get_filename_component(SCRIPT_NAME ${CMAKE_CURRENT_LIST_FILE} NAME)
|
||||
message(STATUS "Running script: ${SCRIPT_NAME}")
|
||||
|
||||
if(NOT GIT_PATH OR NOT GIT_REPOSITORY OR NOT GIT_REF)
|
||||
message(FATAL_ERROR "git_clone: GIT_PATH, GIT_REPOSITORY, and GIT_REF are required")
|
||||
if(NOT GIT_PATH OR NOT GIT_REPOSITORY)
|
||||
message(FATAL_ERROR "GIT_PATH and GIT_REPOSITORY are required")
|
||||
endif()
|
||||
|
||||
setx(GIT_PATH ${GIT_PATH})
|
||||
setx(GIT_REPOSITORY ${GIT_REPOSITORY})
|
||||
setx(GIT_REF ${GIT_REF})
|
||||
if(GIT_COMMIT)
|
||||
set(GIT_REF ${GIT_COMMIT})
|
||||
elseif(GIT_TAG)
|
||||
set(GIT_REF refs/tags/${GIT_TAG})
|
||||
elseif(GIT_BRANCH)
|
||||
set(GIT_REF refs/heads/${GIT_BRANCH})
|
||||
else()
|
||||
message(FATAL_ERROR "GIT_COMMIT, GIT_TAG, or GIT_BRANCH are required")
|
||||
endif()
|
||||
|
||||
string(REGEX MATCH "([^/]+)$" GIT_ORIGINAL_NAME ${GIT_REPOSITORY})
|
||||
|
||||
if(NOT GIT_NAME)
|
||||
setx(GIT_NAME ${GIT_ORIGINAL_NAME})
|
||||
set(GIT_NAME ${GIT_ORIGINAL_NAME})
|
||||
endif()
|
||||
|
||||
set(GIT_REF_PATH ${GIT_PATH}/.ref)
|
||||
set(GIT_DOWNLOAD_URL https://github.com/${GIT_REPOSITORY}/archive/${GIT_REF}.tar.gz)
|
||||
|
||||
if(EXISTS ${GIT_REF_PATH})
|
||||
file(READ ${GIT_REF_PATH} GIT_CACHED_REF)
|
||||
if(GIT_CACHED_REF STREQUAL GIT_REF)
|
||||
return()
|
||||
endif()
|
||||
message(STATUS "Cloning ${GIT_REPOSITORY} at ${GIT_REF}...")
|
||||
execute_process(
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-DDOWNLOAD_URL=${GIT_DOWNLOAD_URL}
|
||||
-DDOWNLOAD_PATH=${GIT_PATH}
|
||||
-DDOWNLOAD_FILTERS=${GIT_FILTERS}
|
||||
-P ${CMAKE_CURRENT_LIST_DIR}/DownloadUrl.cmake
|
||||
ERROR_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_VARIABLE
|
||||
GIT_ERROR
|
||||
RESULT_VARIABLE
|
||||
GIT_RESULT
|
||||
)
|
||||
|
||||
if(NOT GIT_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "Clone failed: ${GIT_ERROR}")
|
||||
endif()
|
||||
|
||||
setx(GIT_DOWNLOAD_PATH ${GIT_PATH}.tar.gz)
|
||||
setx(GIT_DOWNLOAD_URL https://github.com/${GIT_REPOSITORY}/archive/${GIT_REF}.tar.gz)
|
||||
|
||||
foreach(i RANGE 10)
|
||||
set(GIT_DOWNLOAD_TMP_PATH ${GIT_PATH}.tmp.${i})
|
||||
file(DOWNLOAD
|
||||
${GIT_DOWNLOAD_URL}
|
||||
${GIT_DOWNLOAD_TMP_PATH}
|
||||
TIMEOUT 120
|
||||
STATUS GIT_DOWNLOAD_STATUS
|
||||
SHOW_PROGRESS
|
||||
)
|
||||
if(GIT_DOWNLOAD_STATUS MATCHES "^0" AND EXISTS ${GIT_DOWNLOAD_TMP_PATH})
|
||||
file(RENAME ${GIT_DOWNLOAD_TMP_PATH} ${GIT_DOWNLOAD_PATH})
|
||||
break()
|
||||
endif()
|
||||
message(WARNING "git_clone: ${GIT_DOWNLOAD_STATUS}: ${GIT_DOWNLOAD_URL}")
|
||||
file(REMOVE ${GIT_DOWNLOAD_TMP_PATH})
|
||||
endforeach()
|
||||
|
||||
if(NOT EXISTS ${GIT_DOWNLOAD_PATH})
|
||||
message(FATAL_ERROR "git_clone: failed to download ${GIT_DOWNLOAD_URL}")
|
||||
endif()
|
||||
|
||||
file(REMOVE_RECURSE ${GIT_PATH})
|
||||
get_filename_component(GIT_PARENT_PATH ${GIT_PATH} DIRECTORY)
|
||||
file(ARCHIVE_EXTRACT INPUT ${GIT_DOWNLOAD_PATH} DESTINATION ${GIT_PARENT_PATH}/tmp-${GIT_ORIGINAL_NAME} TOUCH)
|
||||
file(GLOB GIT_TMP_PATH LIST_DIRECTORIES ON ${GIT_PARENT_PATH}/tmp-${GIT_ORIGINAL_NAME}/${GIT_ORIGINAL_NAME}-*)
|
||||
file(RENAME ${GIT_TMP_PATH} ${GIT_PATH})
|
||||
file(REMOVE_RECURSE ${GIT_PARENT_PATH}/tmp-${GIT_ORIGINAL_NAME})
|
||||
file(REMOVE ${GIT_DOWNLOAD_PATH})
|
||||
|
||||
file(GLOB_RECURSE GIT_PATCH_PATHS ${CMAKE_SOURCE_DIR}/patches/${GIT_NAME}/*)
|
||||
foreach(GIT_PATCH_PATH ${GIT_PATCH_PATHS})
|
||||
if(GIT_PATCH_PATH MATCHES "\\.patch$")
|
||||
execute_process(
|
||||
COMMAND git apply --ignore-whitespace --ignore-space-change --no-index --verbose ${GIT_PATCH_PATH}
|
||||
WORKING_DIRECTORY ${GIT_PATH}
|
||||
RESULT_VARIABLE GIT_PATCH_RESULT
|
||||
)
|
||||
if(NOT GIT_PATCH_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "git_clone: failed to apply patch: ${GIT_PATCH_PATH}")
|
||||
endif()
|
||||
else()
|
||||
file(COPY ${GIT_PATCH_PATH} DESTINATION ${GIT_PATH})
|
||||
endif()
|
||||
endforeach()
|
||||
list(LENGTH GIT_PATCH_PATHS GIT_PATCH_COUNT)
|
||||
|
||||
file(WRITE ${GIT_REF_PATH} ${GIT_REF})
|
||||
if(GIT_PATCH_COUNT GREATER 0)
|
||||
find_program(GIT_PROGRAM git REQUIRED)
|
||||
|
||||
foreach(GIT_PATCH ${GIT_PATCH_PATHS})
|
||||
get_filename_component(GIT_PATCH_NAME ${GIT_PATCH} NAME)
|
||||
|
||||
if(GIT_PATCH_NAME MATCHES "\\.patch$")
|
||||
message(STATUS "Applying patch ${GIT_PATCH_NAME}...")
|
||||
execute_process(
|
||||
COMMAND
|
||||
${GIT_PROGRAM}
|
||||
apply
|
||||
--ignore-whitespace
|
||||
--ignore-space-change
|
||||
--no-index
|
||||
--verbose
|
||||
${GIT_PATCH}
|
||||
WORKING_DIRECTORY
|
||||
${GIT_PATH}
|
||||
ERROR_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_VARIABLE
|
||||
GIT_PATCH_ERROR
|
||||
RESULT_VARIABLE
|
||||
GIT_PATCH_RESULT
|
||||
)
|
||||
|
||||
if(NOT GIT_PATCH_RESULT EQUAL 0 AND NOT GIT_PATCH_ERROR MATCHES "cleanly")
|
||||
file(REMOVE_RECURSE ${GIT_PATH})
|
||||
message(FATAL_ERROR "Failed to apply patch: ${GIT_PATCH_ERROR}")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Copying file ${GIT_PATCH_NAME}...")
|
||||
file(COPY ${GIT_PATCH} DESTINATION ${GIT_PATH})
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
file(WRITE ${GIT_PATH}/.ref ${GIT_REF})
|
||||
message(STATUS "Cloned ${GIT_REPOSITORY}")
|
||||
|
||||
@@ -54,16 +54,16 @@ register_command(
|
||||
COMMENT
|
||||
"Generating src/js_lexer/*.blob"
|
||||
COMMAND
|
||||
${CMAKE_ZIG_COMPILER}
|
||||
${ZIG_EXECUTABLE}
|
||||
run
|
||||
${CMAKE_ZIG_FLAGS}
|
||||
${BUN_ZIG_IDENTIFIER_SCRIPT}
|
||||
SOURCES
|
||||
${BUN_ZIG_IDENTIFIER_SOURCES}
|
||||
OUTPUTS
|
||||
${BUN_ZIG_IDENTIFIER_OUTPUTS}
|
||||
TARGETS
|
||||
clone-zig
|
||||
OUTPUTS
|
||||
${BUN_ZIG_IDENTIFIER_OUTPUTS}
|
||||
)
|
||||
|
||||
set(BUN_ERROR_SOURCE ${CWD}/packages/bun-error)
|
||||
@@ -484,6 +484,9 @@ list(APPEND BUN_ZIG_SOURCES
|
||||
${CWD}/build.zig
|
||||
${CWD}/root.zig
|
||||
${CWD}/root_wasm.zig
|
||||
)
|
||||
|
||||
set(BUN_ZIG_GENERATED_SOURCES
|
||||
${BUN_ZIG_IDENTIFIER_OUTPUTS}
|
||||
${BUN_ERROR_OUTPUTS}
|
||||
${BUN_FALLBACK_DECODER_OUTPUT}
|
||||
@@ -496,9 +499,9 @@ list(APPEND BUN_ZIG_SOURCES
|
||||
|
||||
# In debug builds, these are not embedded, but rather referenced at runtime.
|
||||
if (DEBUG)
|
||||
list(APPEND BUN_ZIG_SOURCES ${CODEGEN_PATH}/kit_empty_file)
|
||||
list(APPEND BUN_ZIG_GENERATED_SOURCES ${CODEGEN_PATH}/kit_empty_file)
|
||||
else()
|
||||
list(APPEND BUN_ZIG_SOURCES ${BUN_KIT_RUNTIME_OUTPUTS})
|
||||
list(APPEND BUN_ZIG_GENERATED_SOURCES ${BUN_KIT_RUNTIME_OUTPUTS})
|
||||
endif()
|
||||
|
||||
set(BUN_ZIG_OUTPUT ${BUILD_PATH}/bun-zig.o)
|
||||
@@ -527,7 +530,7 @@ register_command(
|
||||
COMMENT
|
||||
"Building src/*.zig for ${ZIG_TARGET}"
|
||||
COMMAND
|
||||
${CMAKE_ZIG_COMPILER}
|
||||
${ZIG_EXECUTABLE}
|
||||
build obj
|
||||
${CMAKE_ZIG_FLAGS}
|
||||
--prefix ${BUILD_PATH}
|
||||
@@ -543,10 +546,11 @@ register_command(
|
||||
-Dgenerated-code=${CODEGEN_PATH}
|
||||
ARTIFACTS
|
||||
${BUN_ZIG_OUTPUT}
|
||||
SOURCES
|
||||
${BUN_ZIG_SOURCES}
|
||||
TARGETS
|
||||
clone-zig
|
||||
SOURCES
|
||||
${BUN_ZIG_SOURCES}
|
||||
${BUN_ZIG_GENERATED_SOURCES}
|
||||
)
|
||||
|
||||
set_property(TARGET bun-zig PROPERTY JOB_POOL compile_pool)
|
||||
@@ -565,6 +569,7 @@ file(GLOB BUN_CXX_SOURCES ${CONFIGURE_DEPENDS}
|
||||
${CWD}/src/bun.js/bindings/webcrypto/*.cpp
|
||||
${CWD}/src/bun.js/bindings/webcrypto/*/*.cpp
|
||||
${CWD}/src/bun.js/bindings/v8/*.cpp
|
||||
${CWD}/src/bun.js/bindings/v8/shim/*.cpp
|
||||
${CWD}/src/kit/*.cpp
|
||||
${CWD}/src/deps/*.cpp
|
||||
${BUN_USOCKETS_SOURCE}/src/crypto/*.cpp
|
||||
@@ -577,6 +582,10 @@ file(GLOB BUN_C_SOURCES ${CONFIGURE_DEPENDS}
|
||||
${BUN_USOCKETS_SOURCE}/src/crypto/*.c
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND BUN_C_SOURCES ${CWD}/src/bun.js/bindings/windows/musl-memmem.c)
|
||||
endif()
|
||||
|
||||
register_repository(
|
||||
NAME
|
||||
picohttpparser
|
||||
@@ -588,15 +597,27 @@ register_repository(
|
||||
picohttpparser.c
|
||||
)
|
||||
|
||||
list(APPEND BUN_C_SOURCES ${VENDOR_PATH}/picohttpparser/picohttpparser.c)
|
||||
set(NODEJS_HEADERS_PATH ${VENDOR_PATH}/nodejs)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND BUN_C_SOURCES ${CWD}/src/bun.js/bindings/windows/musl-memmem.c)
|
||||
endif()
|
||||
register_command(
|
||||
TARGET
|
||||
bun-node-headers
|
||||
COMMENT
|
||||
"Download node ${NODEJS_VERSION} headers"
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-DDOWNLOAD_PATH=${NODEJS_HEADERS_PATH}
|
||||
-DDOWNLOAD_URL=https://nodejs.org/dist/v${NODEJS_VERSION}/node-v${NODEJS_VERSION}-headers.tar.gz
|
||||
-P ${CWD}/cmake/scripts/DownloadUrl.cmake
|
||||
OUTPUTS
|
||||
${NODEJS_HEADERS_PATH}/include/node/node_version.h
|
||||
)
|
||||
|
||||
list(APPEND BUN_CPP_SOURCES
|
||||
${BUN_C_SOURCES}
|
||||
${BUN_CXX_SOURCES}
|
||||
${VENDOR_PATH}/picohttpparser/picohttpparser.c
|
||||
${NODEJS_HEADERS_PATH}/include/node/node_version.h
|
||||
${BUN_ZIG_GENERATED_CLASSES_OUTPUTS}
|
||||
${BUN_JS_SINK_OUTPUTS}
|
||||
${BUN_JAVASCRIPT_OUTPUTS}
|
||||
@@ -674,6 +695,7 @@ target_include_directories(${bun} PRIVATE
|
||||
${CWD}/src/bun.js/bindings/webcore
|
||||
${CWD}/src/bun.js/bindings/webcrypto
|
||||
${CWD}/src/bun.js/bindings/sqlite
|
||||
${CWD}/src/bun.js/bindings/v8
|
||||
${CWD}/src/bun.js/modules
|
||||
${CWD}/src/js/builtins
|
||||
${CWD}/src/napi
|
||||
@@ -681,6 +703,7 @@ target_include_directories(${bun} PRIVATE
|
||||
${CODEGEN_PATH}
|
||||
${VENDOR_PATH}
|
||||
${VENDOR_PATH}/picohttpparser
|
||||
${NODEJS_HEADERS_PATH}/include
|
||||
)
|
||||
|
||||
# --- C/C++ Definitions ---
|
||||
@@ -820,8 +843,34 @@ elseif(APPLE)
|
||||
-fno-keep-static-consts
|
||||
)
|
||||
else()
|
||||
# Try to use lld-16 if available, otherwise fallback to lld
|
||||
# Cache it so we don't have to re-run CMake to pick it up
|
||||
if((NOT DEFINED LLD_NAME) AND (NOT CI OR BUN_LINK_ONLY))
|
||||
find_program(LLD_EXECUTABLE_NAME lld-${LLVM_VERSION_MAJOR})
|
||||
|
||||
if(NOT LLD_EXECUTABLE_NAME)
|
||||
if(CI)
|
||||
# Ensure we don't use a differing version of lld in CI vs clang
|
||||
message(FATAL_ERROR "lld-${LLVM_VERSION_MAJOR} not found. Please make sure you have LLVM ${LLVM_VERSION_MAJOR}.x installed and set to lld-${LLVM_VERSION_MAJOR}")
|
||||
endif()
|
||||
|
||||
# To make it easier for contributors, allow differing versions of lld vs clang/cmake
|
||||
find_program(LLD_EXECUTABLE_NAME lld)
|
||||
endif()
|
||||
|
||||
if(NOT LLD_EXECUTABLE_NAME)
|
||||
message(FATAL_ERROR "LLD not found. Please make sure you have LLVM ${LLVM_VERSION_MAJOR}.x installed and lld is available in your PATH as lld-${LLVM_VERSION_MAJOR}")
|
||||
endif()
|
||||
|
||||
# normalize to basename so it can be used with -fuse-ld
|
||||
get_filename_component(LLD_NAME ${LLD_EXECUTABLE_NAME} NAME CACHE)
|
||||
message(STATUS "Using linker: ${LLD_NAME} (${LLD_EXECUTABLE_NAME})")
|
||||
elseif(NOT DEFINED LLD_NAME)
|
||||
set(LLD_NAME lld-${LLVM_VERSION_MAJOR})
|
||||
endif()
|
||||
|
||||
target_link_options(${bun} PUBLIC
|
||||
-fuse-ld=lld-${LLVM_VERSION_MAJOR}
|
||||
-fuse-ld=${LLD_NAME}
|
||||
-fno-pic
|
||||
-static-libstdc++
|
||||
-static-libgcc
|
||||
|
||||
38
cmake/tools/SetupGit.cmake
Normal file
38
cmake/tools/SetupGit.cmake
Normal file
@@ -0,0 +1,38 @@
|
||||
find_command(
|
||||
VARIABLE
|
||||
GIT_PROGRAM
|
||||
COMMAND
|
||||
git
|
||||
REQUIRED
|
||||
OFF
|
||||
)
|
||||
|
||||
if(NOT GIT_PROGRAM)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(GIT_DIFF_COMMAND ${GIT_PROGRAM} diff --no-color --name-only --diff-filter=AMCR)
|
||||
|
||||
execute_process(
|
||||
COMMAND
|
||||
${GIT_DIFF_COMMAND}
|
||||
WORKING_DIRECTORY
|
||||
${CWD}
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
OUTPUT_VARIABLE
|
||||
GIT_DIFF
|
||||
ERROR_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_VARIABLE
|
||||
GIT_DIFF_ERROR
|
||||
RESULT_VARIABLE
|
||||
GIT_DIFF_RESULT
|
||||
)
|
||||
|
||||
if(NOT GIT_DIFF_RESULT EQUAL 0)
|
||||
message(${WARNING} "Command failed: ${GIT_DIFF_COMMAND} ${GIT_DIFF_ERROR}")
|
||||
return()
|
||||
endif()
|
||||
|
||||
string(REPLACE "\n" ";" GIT_CHANGED_SOURCES "${GIT_DIFF}")
|
||||
list(TRANSFORM GIT_CHANGED_SOURCES PREPEND ${CWD}/)
|
||||
list(LENGTH GIT_CHANGED_SOURCES GIT_CHANGED_SOURCES_COUNT)
|
||||
@@ -1,3 +1,9 @@
|
||||
optionx(SKIP_LLVM BOOL "If LLVM setup should be skipped" DEFAULT OFF)
|
||||
|
||||
if(SKIP_LLVM)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(CMAKE_HOST_WIN32 OR CMAKE_HOST_APPLE)
|
||||
set(DEFAULT_LLVM_VERSION "18.1.8")
|
||||
else()
|
||||
|
||||
@@ -2,7 +2,7 @@ option(WEBKIT_VERSION "The version of WebKit to use")
|
||||
option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading")
|
||||
|
||||
if(NOT WEBKIT_VERSION)
|
||||
set(WEBKIT_VERSION 4a2db3254a9535949a5d5380eb58cf0f77c8e15a)
|
||||
set(WEBKIT_VERSION 76798f7b2fb287ee9f1ecce98bae895a2d026d93)
|
||||
endif()
|
||||
|
||||
if(WEBKIT_LOCAL)
|
||||
|
||||
@@ -16,6 +16,8 @@ else()
|
||||
unsupported(CMAKE_SYSTEM_NAME)
|
||||
endif()
|
||||
|
||||
optionx(ZIG_VERSION STRING "The zig version of the compiler to download" DEFAULT "0.13.0")
|
||||
optionx(ZIG_COMMIT STRING "The zig commit to use in oven-sh/zig" DEFAULT "131a009ba2eb127a3447d05b9e12f710429aa5ee")
|
||||
optionx(ZIG_TARGET STRING "The zig target to use" DEFAULT ${DEFAULT_ZIG_TARGET})
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
@@ -43,101 +45,39 @@ optionx(ZIG_OPTIMIZE "ReleaseFast|ReleaseSafe|ReleaseSmall|Debug" "The Zig optim
|
||||
# Change to "bc" to experiment, "Invalid record" means it is not valid output.
|
||||
optionx(ZIG_OBJECT_FORMAT "obj|bc" "Output file format for Zig object files" DEFAULT obj)
|
||||
|
||||
optionx(ZIG_VERSION STRING "The version of zig to use" DEFAULT "0.13.0")
|
||||
optionx(ZIG_LOCAL_CACHE_DIR FILEPATH "The path to local the zig cache directory" DEFAULT ${CACHE_PATH}/zig/local)
|
||||
optionx(ZIG_GLOBAL_CACHE_DIR FILEPATH "The path to the global zig cache directory" DEFAULT ${CACHE_PATH}/zig/global)
|
||||
|
||||
setx(ZIG_REPOSITORY_PATH ${VENDOR_PATH}/zig)
|
||||
setx(ZIG_PATH ${CACHE_PATH}/zig/bin)
|
||||
|
||||
register_repository(
|
||||
NAME
|
||||
zig
|
||||
REPOSITORY
|
||||
oven-sh/zig
|
||||
COMMIT
|
||||
131a009ba2eb127a3447d05b9e12f710429aa5ee
|
||||
PATH
|
||||
${ZIG_REPOSITORY_PATH}
|
||||
)
|
||||
|
||||
setenv(ZIG_LOCAL_CACHE_DIR ${ZIG_LOCAL_CACHE_DIR})
|
||||
setenv(ZIG_GLOBAL_CACHE_DIR ${ZIG_GLOBAL_CACHE_DIR})
|
||||
|
||||
setx(ZIG_PATH ${VENDOR_PATH}/zig)
|
||||
|
||||
if(WIN32)
|
||||
setx(ZIG_EXECUTABLE ${ZIG_PATH}/zig.exe)
|
||||
else()
|
||||
setx(ZIG_EXECUTABLE ${ZIG_PATH}/zig)
|
||||
endif()
|
||||
|
||||
set(CMAKE_ZIG_FLAGS
|
||||
--cache-dir ${ZIG_LOCAL_CACHE_DIR}
|
||||
--global-cache-dir ${ZIG_GLOBAL_CACHE_DIR}
|
||||
--zig-lib-dir ${ZIG_REPOSITORY_PATH}/lib
|
||||
--zig-lib-dir ${ZIG_PATH}/lib
|
||||
)
|
||||
|
||||
find_command(
|
||||
VARIABLE
|
||||
CMAKE_ZIG_COMPILER
|
||||
COMMAND
|
||||
zig
|
||||
zig.exe
|
||||
PATHS
|
||||
${ZIG_PATH}
|
||||
VERSION
|
||||
${ZIG_VERSION}
|
||||
REQUIRED
|
||||
OFF
|
||||
)
|
||||
|
||||
if(CMAKE_ZIG_COMPILER)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "arm64|aarch64")
|
||||
set(ZIG_HOST_ARCH "aarch64")
|
||||
elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|x64|AMD64")
|
||||
set(ZIG_HOST_ARCH "x86_64")
|
||||
else()
|
||||
unsupported(CMAKE_HOST_SYSTEM_PROCESSOR)
|
||||
endif()
|
||||
|
||||
if(CMAKE_HOST_APPLE)
|
||||
set(ZIG_HOST_OS "macos")
|
||||
elseif(CMAKE_HOST_WIN32)
|
||||
set(ZIG_HOST_OS "windows")
|
||||
elseif(CMAKE_HOST_UNIX)
|
||||
set(ZIG_HOST_OS "linux")
|
||||
else()
|
||||
unsupported(CMAKE_HOST_SYSTEM_NAME)
|
||||
endif()
|
||||
|
||||
set(ZIG_NAME zig-${ZIG_HOST_OS}-${ZIG_HOST_ARCH}-${ZIG_VERSION})
|
||||
|
||||
if(CMAKE_HOST_WIN32)
|
||||
set(ZIG_EXE "zig.exe")
|
||||
set(ZIG_FILENAME ${ZIG_NAME}.zip)
|
||||
else()
|
||||
set(ZIG_EXE "zig")
|
||||
set(ZIG_FILENAME ${ZIG_NAME}.tar.xz)
|
||||
endif()
|
||||
|
||||
setx(ZIG_DOWNLOAD_URL https://ziglang.org/download/${ZIG_VERSION}/${ZIG_FILENAME})
|
||||
file(DOWNLOAD ${ZIG_DOWNLOAD_URL} ${TMP_PATH}/${ZIG_FILENAME} SHOW_PROGRESS)
|
||||
file(ARCHIVE_EXTRACT INPUT ${TMP_PATH}/${ZIG_FILENAME} DESTINATION ${TMP_PATH} TOUCH)
|
||||
file(REMOVE ${TMP_PATH}/${ZIG_FILENAME})
|
||||
file(COPY ${TMP_PATH}/${ZIG_NAME}/${ZIG_EXE} DESTINATION ${ZIG_PATH})
|
||||
file(CHMOD ${ZIG_PATH}/${ZIG_EXE} PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE)
|
||||
setx(CMAKE_ZIG_COMPILER ${ZIG_PATH}/${ZIG_EXE})
|
||||
|
||||
if(NOT WIN32)
|
||||
file(CREATE_LINK ${ZIG_PATH}/${ZIG_EXE} ${ZIG_PATH}/zig.exe SYMBOLIC)
|
||||
endif()
|
||||
|
||||
# Some zig commands need the executable to be in the same directory as the zig repository
|
||||
register_command(
|
||||
COMMENT
|
||||
"Creating symlink for zig"
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E copy ${ZIG_PATH}/${ZIG_EXE} ${ZIG_REPOSITORY_PATH}/${ZIG_EXE}
|
||||
&& ${CMAKE_COMMAND} -E create_symlink ${ZIG_REPOSITORY_PATH}/${ZIG_EXE} ${ZIG_REPOSITORY_PATH}/zig.exe
|
||||
OUTPUTS
|
||||
${ZIG_REPOSITORY_PATH}/${ZIG_EXE}
|
||||
${ZIG_REPOSITORY_PATH}/zig.exe
|
||||
TARGETS
|
||||
TARGET
|
||||
clone-zig
|
||||
COMMENT
|
||||
"Downloading zig"
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-DZIG_PATH=${ZIG_PATH}
|
||||
-DZIG_VERSION=${ZIG_VERSION}
|
||||
-DZIG_COMMIT=${ZIG_COMMIT}
|
||||
-P ${CWD}/cmake/scripts/DownloadZig.cmake
|
||||
SOURCES
|
||||
${CWD}/cmake/scripts/DownloadZig.cmake
|
||||
OUTPUTS
|
||||
${ZIG_EXECUTABLE}
|
||||
)
|
||||
|
||||
262
docs/api/color.md
Normal file
262
docs/api/color.md
Normal file
@@ -0,0 +1,262 @@
|
||||
`Bun.color(input, outputFormat?)` leverages Bun's CSS parser to parse, normalize, and convert colors from user input to a variety of output formats, including:
|
||||
|
||||
| Format | Example |
|
||||
| ------------ | -------------------------------- |
|
||||
| `"css"` | `"red"` |
|
||||
| `"ansi"` | `"\x1b[38;2;255;0;0m"` |
|
||||
| `"ansi-16"` | `"\x1b[38;5;\tm"` |
|
||||
| `"ansi-256"` | `"\x1b[38;5;196m"` |
|
||||
| `"ansi-16m"` | `"\x1b[38;2;255;0;0m"` |
|
||||
| `"number"` | `0x1a2b3c` |
|
||||
| `"rgb"` | `"rgb(255, 99, 71)"` |
|
||||
| `"rgba"` | `"rgba(255, 99, 71, 0.5)"` |
|
||||
| `"hsl"` | `"hsl(120, 50%, 50%)"` |
|
||||
| `"hex"` | `"#1a2b3c"` |
|
||||
| `"HEX"` | `"#1A2B3C"` |
|
||||
| `"{rgb}"` | `{ r: 255, g: 99, b: 71 }` |
|
||||
| `"{rgba}"` | `{ r: 255, g: 99, b: 71, a: 1 }` |
|
||||
| `"[rgb]"` | `[ 255, 99, 71 ]` |
|
||||
| `"[rgba]"` | `[ 255, 99, 71, 255]` |
|
||||
|
||||
There are many different ways to use this API:
|
||||
|
||||
- Validate and normalize colors to persist in a database (`number` is the most database-friendly)
|
||||
- Convert colors to different formats
|
||||
- Colorful logging beyond the 16 colors many use today (use `ansi` if you don't want to figure out what the user's terminal supports, otherwise use `ansi-16`, `ansi-256`, or `ansi-16m` for how many colors the terminal supports)
|
||||
- Format colors for use in CSS injected into HTML
|
||||
- Get the `r`, `g`, `b`, and `a` color components as JavaScript objects or numbers from a CSS color string
|
||||
|
||||
You can think of this as an alternative to the popular npm packages [`color`](https://github.com/Qix-/color) and [`tinycolor2`](https://github.com/bgrins/TinyColor) except with full support for parsing CSS color strings and zero dependencies built directly into Bun.
|
||||
|
||||
### Flexible input
|
||||
|
||||
You can pass in any of the following:
|
||||
|
||||
- Standard CSS color names like `"red"`
|
||||
- Numbers like `0xff0000`
|
||||
- Hex strings like `"#f00"`
|
||||
- RGB strings like `"rgb(255, 0, 0)"`
|
||||
- RGBA strings like `"rgba(255, 0, 0, 1)"`
|
||||
- HSL strings like `"hsl(0, 100%, 50%)"`
|
||||
- HSLA strings like `"hsla(0, 100%, 50%, 1)"`
|
||||
- RGB objects like `{ r: 255, g: 0, b: 0 }`
|
||||
- RGBA objects like `{ r: 255, g: 0, b: 0, a: 1 }`
|
||||
- RGB arrays like `[255, 0, 0]`
|
||||
- RGBA arrays like `[255, 0, 0, 255]`
|
||||
- LAB strings like `"lab(50% 50% 50%)"`
|
||||
- ... anything else that CSS can parse as a single color value
|
||||
|
||||
### Format colors as CSS
|
||||
|
||||
The `"css"` format outputs valid CSS for use in stylesheets, inline styles, CSS variables, css-in-js, etc. It returns the most compact representation of the color as a string.
|
||||
|
||||
```ts
|
||||
Bun.color("red", "css"); // "red"
|
||||
Bun.color(0xff0000, "css"); // "#f000"
|
||||
Bun.color("#f00", "css"); // "red"
|
||||
Bun.color("#ff0000", "css"); // "red"
|
||||
Bun.color("rgb(255, 0, 0)", "css"); // "red"
|
||||
Bun.color("rgba(255, 0, 0, 1)", "css"); // "red"
|
||||
Bun.color("hsl(0, 100%, 50%)", "css"); // "red"
|
||||
Bun.color("hsla(0, 100%, 50%, 1)", "css"); // "red"
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "css"); // "red"
|
||||
Bun.color({ r: 255, g: 0, b: 0, a: 1 }, "css"); // "red"
|
||||
Bun.color([255, 0, 0], "css"); // "red"
|
||||
Bun.color([255, 0, 0, 255], "css"); // "red"
|
||||
```
|
||||
|
||||
If the input is unknown or fails to parse, `Bun.color` returns `null`.
|
||||
|
||||
### Format colors as ANSI (for terminals)
|
||||
|
||||
The `"ansi"` format outputs ANSI escape codes for use in terminals to make text colorful.
|
||||
|
||||
```ts
|
||||
Bun.color("red", "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color(0xff0000, "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color("#f00", "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color("#ff0000", "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color("rgb(255, 0, 0)", "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color("rgba(255, 0, 0, 1)", "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color("hsl(0, 100%, 50%)", "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color("hsla(0, 100%, 50%, 1)", "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color({ r: 255, g: 0, b: 0, a: 1 }, "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color([255, 0, 0], "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
Bun.color([255, 0, 0, 255], "ansi"); // "\u001b[38;2;255;0;0m"
|
||||
```
|
||||
|
||||
This gets the color depth of stdout and automatically chooses one of `"ansi-16m"`, `"ansi-256"`, `"ansi-16"` based on the environment variables. If stdout doesn't support any form of ANSI color, it returns an empty string. As with the rest of Bun's color API, if the input is unknown or fails to parse, it returns `null`.
|
||||
|
||||
#### 24-bit ANSI colors (`ansi-16m`)
|
||||
|
||||
The `"ansi-16m"` format outputs 24-bit ANSI colors for use in terminals to make text colorful. 24-bit color means you can display 16 million colors on supported terminals, and requires a modern terminal that supports it.
|
||||
|
||||
This converts the input color to RGBA, and then outputs that as an ANSI color.
|
||||
|
||||
```ts
|
||||
Bun.color("red", "ansi-16m"); // "\x1b[38;2;255;0;0m"
|
||||
Bun.color(0xff0000, "ansi-16m"); // "\x1b[38;2;255;0;0m"
|
||||
Bun.color("#f00", "ansi-16m"); // "\x1b[38;2;255;0;0m"
|
||||
Bun.color("#ff0000", "ansi-16m"); // "\x1b[38;2;255;0;0m"
|
||||
```
|
||||
|
||||
#### 256 ANSI colors (`ansi-256`)
|
||||
|
||||
The `"ansi-256"` format approximates the input color to the nearest of the 256 ANSI colors supported by some terminals.
|
||||
|
||||
```ts
|
||||
Bun.color("red", "ansi-256"); // "\u001b[38;5;196m"
|
||||
Bun.color(0xff0000, "ansi-256"); // "\u001b[38;5;196m"
|
||||
Bun.color("#f00", "ansi-256"); // "\u001b[38;5;196m"
|
||||
Bun.color("#ff0000", "ansi-256"); // "\u001b[38;5;196m"
|
||||
```
|
||||
|
||||
To convert from RGBA to one of the 256 ANSI colors, we ported the algorithm that [`tmux` uses](https://github.com/tmux/tmux/blob/dae2868d1227b95fd076fb4a5efa6256c7245943/colour.c#L44-L55).
|
||||
|
||||
#### 16 ANSI colors (`ansi-16`)
|
||||
|
||||
The `"ansi-16"` format approximates the input color to the nearest of the 16 ANSI colors supported by most terminals.
|
||||
|
||||
```ts
|
||||
Bun.color("red", "ansi-16"); // "\u001b[38;5;\tm"
|
||||
Bun.color(0xff0000, "ansi-16"); // "\u001b[38;5;\tm"
|
||||
Bun.color("#f00", "ansi-16"); // "\u001b[38;5;\tm"
|
||||
Bun.color("#ff0000", "ansi-16"); // "\u001b[38;5;\tm"
|
||||
```
|
||||
|
||||
This works by first converting the input to a 24-bit RGB color space, then to `ansi-256`, and then we convert that to the nearest 16 ANSI color.
|
||||
|
||||
### Format colors as numbers
|
||||
|
||||
The `"number"` format outputs a 24-bit number for use in databases, configuration, or any other use case where a compact representation of the color is desired.
|
||||
|
||||
```ts
|
||||
Bun.color("red", "number"); // 16711680
|
||||
Bun.color(0xff0000, "number"); // 16711680
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "number"); // 16711680
|
||||
Bun.color([255, 0, 0], "number"); // 16711680
|
||||
Bun.color("rgb(255, 0, 0)", "number"); // 16711680
|
||||
Bun.color("rgba(255, 0, 0, 1)", "number"); // 16711680
|
||||
Bun.color("hsl(0, 100%, 50%)", "number"); // 16711680
|
||||
Bun.color("hsla(0, 100%, 50%, 1)", "number"); // 16711680
|
||||
```
|
||||
|
||||
### Get the red, green, blue, and alpha channels
|
||||
|
||||
You can use the `"{rgba}"`, `"{rgb}"`, `"[rgba]"` and `"[rgb]"` formats to get the red, green, blue, and alpha channels as objects or arrays.
|
||||
|
||||
#### `{rgba}` object
|
||||
|
||||
The `"{rgba}"` format outputs an object with the red, green, blue, and alpha channels.
|
||||
|
||||
```ts
|
||||
type RGBAObject = {
|
||||
// 0 - 255
|
||||
r: number;
|
||||
// 0 - 255
|
||||
g: number;
|
||||
// 0 - 255
|
||||
b: number;
|
||||
// 0 - 1
|
||||
a: number;
|
||||
};
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```ts
|
||||
Bun.color("hsl(0, 0%, 50%)", "{rgba}"); // { r: 128, g: 128, b: 128, a: 1 }
|
||||
Bun.color("red", "{rgba}"); // { r: 255, g: 0, b: 0, a: 1 }
|
||||
Bun.color(0xff0000, "{rgba}"); // { r: 255, g: 0, b: 0, a: 1 }
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "{rgba}"); // { r: 255, g: 0, b: 0, a: 1 }
|
||||
Bun.color([255, 0, 0], "{rgba}"); // { r: 255, g: 0, b: 0, a: 1 }
|
||||
```
|
||||
|
||||
To behave similarly to CSS, the `a` channel is a decimal number between `0` and `1`.
|
||||
|
||||
The `"{rgb}"` format is similar, but it doesn't include the alpha channel.
|
||||
|
||||
```ts
|
||||
Bun.color("hsl(0, 0%, 50%)", "{rgb}"); // { r: 128, g: 128, b: 128 }
|
||||
Bun.color("red", "{rgb}"); // { r: 255, g: 0, b: 0 }
|
||||
Bun.color(0xff0000, "{rgb}"); // { r: 255, g: 0, b: 0 }
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "{rgb}"); // { r: 255, g: 0, b: 0 }
|
||||
Bun.color([255, 0, 0], "{rgb}"); // { r: 255, g: 0, b: 0 }
|
||||
```
|
||||
|
||||
#### `[rgba]` array
|
||||
|
||||
The `"[rgba]"` format outputs an array with the red, green, blue, and alpha channels.
|
||||
|
||||
```ts
|
||||
// All values are 0 - 255
|
||||
type RGBAArray = [number, number, number, number];
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```ts
|
||||
Bun.color("hsl(0, 0%, 50%)", "[rgba]"); // [128, 128, 128, 255]
|
||||
Bun.color("red", "[rgba]"); // [255, 0, 0, 255]
|
||||
Bun.color(0xff0000, "[rgba]"); // [255, 0, 0, 255]
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "[rgba]"); // [255, 0, 0, 255]
|
||||
Bun.color([255, 0, 0], "[rgba]"); // [255, 0, 0, 255]
|
||||
```
|
||||
|
||||
Unlike the `"{rgba}"` format, the alpha channel is an integer between `0` and `255`. This is useful for typed arrays where each channel must be the same underlying type.
|
||||
|
||||
The `"[rgb]"` format is similar, but it doesn't include the alpha channel.
|
||||
|
||||
```ts
|
||||
Bun.color("hsl(0, 0%, 50%)", "[rgb]"); // [128, 128, 128]
|
||||
Bun.color("red", "[rgb]"); // [255, 0, 0]
|
||||
Bun.color(0xff0000, "[rgb]"); // [255, 0, 0]
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "[rgb]"); // [255, 0, 0]
|
||||
Bun.color([255, 0, 0], "[rgb]"); // [255, 0, 0]
|
||||
```
|
||||
|
||||
### Format colors as hex strings
|
||||
|
||||
The `"hex"` format outputs a lowercase hex string for use in CSS or other contexts.
|
||||
|
||||
```ts
|
||||
Bun.color("hsl(0, 0%, 50%)", "hex"); // "#808080"
|
||||
Bun.color("red", "hex"); // "#ff0000"
|
||||
Bun.color(0xff0000, "hex"); // "#ff0000"
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "hex"); // "#ff0000"
|
||||
Bun.color([255, 0, 0], "hex"); // "#ff0000"
|
||||
```
|
||||
|
||||
The `"HEX"` format is similar, but it outputs a hex string with uppercase letters instead of lowercase letters.
|
||||
|
||||
```ts
|
||||
Bun.color("hsl(0, 0%, 50%)", "HEX"); // "#808080"
|
||||
Bun.color("red", "HEX"); // "#FF0000"
|
||||
Bun.color(0xff0000, "HEX"); // "#FF0000"
|
||||
Bun.color({ r: 255, g: 0, b: 0 }, "HEX"); // "#FF0000"
|
||||
Bun.color([255, 0, 0], "HEX"); // "#FF0000"
|
||||
```
|
||||
|
||||
### Bundle-time client-side color formatting
|
||||
|
||||
Like many of Bun's APIs, you can use macros to invoke `Bun.color` at bundle-time for use in client-side JavaScript builds:
|
||||
|
||||
```ts#client-side.ts
|
||||
import { color } from "bun" with { type: "macro" };
|
||||
|
||||
console.log(color("#f00", "css"));
|
||||
```
|
||||
|
||||
Then, build the client-side code:
|
||||
|
||||
```sh
|
||||
bun build ./client-side.ts
|
||||
```
|
||||
|
||||
This will output the following to `client-side.js`:
|
||||
|
||||
```js
|
||||
// client-side.ts
|
||||
console.log("red");
|
||||
```
|
||||
@@ -206,4 +206,42 @@ console.log(arr);
|
||||
// => Uint8Array(32) [ 185, 77, 39, 185, 147, ... ]
|
||||
```
|
||||
|
||||
<!-- Bun.sha; -->
|
||||
### HMAC in `Bun.CryptoHasher`
|
||||
|
||||
`Bun.CryptoHasher` can be used to compute HMAC digests. To do so, pass the key to the constructor.
|
||||
|
||||
```ts
|
||||
const hasher = new Bun.CryptoHasher("sha256", "secret-key");
|
||||
hasher.update("hello world");
|
||||
console.log(hasher.digest("hex"));
|
||||
// => "095d5a21fe6d0646db223fdf3de6436bb8dfb2fab0b51677ecf6441fcf5f2a67"
|
||||
```
|
||||
|
||||
When using HMAC, a more limited set of algorithms are supported:
|
||||
|
||||
- `"blake2b512"`
|
||||
- `"md5"`
|
||||
- `"sha1"`
|
||||
- `"sha224"`
|
||||
- `"sha256"`
|
||||
- `"sha384"`
|
||||
- `"sha512-224"`
|
||||
- `"sha512-256"`
|
||||
- `"sha512"`
|
||||
|
||||
Unlike the non-HMAC `Bun.CryptoHasher`, the HMAC `Bun.CryptoHasher` instance is not reset after `.digest()` is called, and attempting to use the same instance again will throw an error.
|
||||
|
||||
Other methods like `.copy()` and `.update()` are supported (as long as it's before `.digest()`), but methods like `.digest()` that finalize the hasher are not.
|
||||
|
||||
```ts
|
||||
const hasher = new Bun.CryptoHasher("sha256", "secret-key");
|
||||
hasher.update("hello world");
|
||||
|
||||
const copy = hasher.copy();
|
||||
copy.update("!");
|
||||
console.log(copy.digest("hex"));
|
||||
// => "3840176c3d8923f59ac402b7550404b28ab11cb0ef1fa199130a5c37864b5497"
|
||||
|
||||
console.log(hasher.digest("hex"));
|
||||
// => "095d5a21fe6d0646db223fdf3de6436bb8dfb2fab0b51677ecf6441fcf5f2a67"
|
||||
```
|
||||
|
||||
@@ -100,12 +100,30 @@ When deploying to production, we recommend the following:
|
||||
bun build --compile --minify --sourcemap ./path/to/my/app.ts --outfile myapp
|
||||
```
|
||||
|
||||
**What do these flags do?**
|
||||
### Bytecode compilation
|
||||
|
||||
To improve startup time, enable bytecode compilation:
|
||||
|
||||
```sh
|
||||
bun build --compile --minify --sourcemap --bytecode ./path/to/my/app.ts --outfile myapp
|
||||
```
|
||||
|
||||
Using bytecode compilation, `tsc` starts 2x faster:
|
||||
|
||||
{% image src="https://github.com/user-attachments/assets/dc8913db-01d2-48f8-a8ef-ac4e984f9763" width="689" /%}
|
||||
|
||||
Bytecode compilation moves parsing overhead for large input files from runtime to bundle time. Your app starts faster, in exchange for making the `bun build` command a little slower. It doesn't obscure source code.
|
||||
|
||||
**Experimental:** Bytecode compilation is an experimental feature introduced in Bun v1.1.30. Only `cjs` format is supported (which means no top-level-await). Let us know if you run into any issues!
|
||||
|
||||
### What do these flags do?
|
||||
|
||||
The `--minify` argument optimizes the size of the transpiled output code. If you have a large application, this can save megabytes of space. For smaller applications, it might still improve start time a little.
|
||||
|
||||
The `--sourcemap` argument embeds a sourcemap compressed with zstd, so that errors & stacktraces point to their original locations instead of the transpiled location. Bun will automatically decompress & resolve the sourcemap when an error occurs.
|
||||
|
||||
The `--bytecode` argument enables bytecode compilation. Every time you run JavaScript code in Bun, JavaScriptCore (the engine) will compile your source code into bytecode. We can move this parsing work from runtime to bundle time, saving you startup time.
|
||||
|
||||
## Worker
|
||||
|
||||
To use workers in a standalone executable, add the worker's entrypoint to the CLI arguments:
|
||||
|
||||
@@ -330,6 +330,8 @@ Depending on the target, Bun will apply different module resolution rules and op
|
||||
|
||||
If any entrypoints contains a Bun shebang (`#!/usr/bin/env bun`) the bundler will default to `target: "bun"` instead of `"browser"`.
|
||||
|
||||
When using `target: "bun"` and `format: "cjs"` together, the `// @bun @bun-cjs` pragma is added and the CommonJS wrapper function is not compatible with Node.js.
|
||||
|
||||
---
|
||||
|
||||
- `node`
|
||||
@@ -1157,6 +1159,11 @@ Each artifact also contains the following properties:
|
||||
|
||||
---
|
||||
|
||||
- `bytecode`
|
||||
- Generate bytecode for any JavaScript/TypeScript entrypoints. This can greatly improve startup times for large applications. Only supported for `"cjs"` format, only supports `"target": "bun"` and dependent on a matching version of Bun. This adds a corresponding `.jsc` file for each entrypoint
|
||||
|
||||
---
|
||||
|
||||
- `sourcemap`
|
||||
- The sourcemap file corresponding to this file, if generated. Only defined for entrypoints and chunks.
|
||||
|
||||
@@ -1266,33 +1273,104 @@ interface Bun {
|
||||
build(options: BuildOptions): Promise<BuildOutput>;
|
||||
}
|
||||
|
||||
interface BuildOptions {
|
||||
entrypoints: string[]; // required
|
||||
outdir?: string; // default: no write (in-memory only)
|
||||
format?: "esm"; // later: "cjs" | "iife"
|
||||
target?: "browser" | "bun" | "node"; // "browser"
|
||||
splitting?: boolean; // true
|
||||
plugins?: BunPlugin[]; // [] // See https://bun.sh/docs/bundler/plugins
|
||||
loader?: { [k in string]: Loader }; // See https://bun.sh/docs/bundler/loaders
|
||||
manifest?: boolean; // false
|
||||
external?: string[]; // []
|
||||
sourcemap?: "none" | "inline" | "linked" | "external" | "linked" | boolean; // "none"
|
||||
root?: string; // computed from entrypoints
|
||||
interface BuildConfig {
|
||||
entrypoints: string[]; // list of file path
|
||||
outdir?: string; // output directory
|
||||
target?: Target; // default: "browser"
|
||||
/**
|
||||
* Output module format. Top-level await is only supported for `"esm"`.
|
||||
*
|
||||
* Can be:
|
||||
* - `"esm"`
|
||||
* - `"cjs"` (**experimental**)
|
||||
* - `"iife"` (**experimental**)
|
||||
*
|
||||
* @default "esm"
|
||||
*/
|
||||
format?: /**
|
||||
|
||||
* ECMAScript Module format
|
||||
*/
|
||||
| "esm"
|
||||
/**
|
||||
* CommonJS format
|
||||
* **Experimental**
|
||||
*/
|
||||
| "cjs"
|
||||
/**
|
||||
* IIFE format
|
||||
* **Experimental**
|
||||
*/
|
||||
| "iife";
|
||||
naming?:
|
||||
| string
|
||||
| {
|
||||
entry?: string; // '[dir]/[name].[ext]'
|
||||
chunk?: string; // '[name]-[hash].[ext]'
|
||||
asset?: string; // '[name]-[hash].[ext]'
|
||||
};
|
||||
publicPath?: string; // e.g. http://mydomain.com/
|
||||
chunk?: string;
|
||||
entry?: string;
|
||||
asset?: string;
|
||||
}; // | string;
|
||||
root?: string; // project root
|
||||
splitting?: boolean; // default true, enable code splitting
|
||||
plugins?: BunPlugin[];
|
||||
// manifest?: boolean; // whether to return manifest
|
||||
external?: string[];
|
||||
packages?: "bundle" | "external";
|
||||
publicPath?: string;
|
||||
define?: Record<string, string>;
|
||||
// origin?: string; // e.g. http://mydomain.com
|
||||
loader?: { [k in string]: Loader };
|
||||
sourcemap?: "none" | "linked" | "inline" | "external" | "linked"; // default: "none", true -> "inline"
|
||||
/**
|
||||
* package.json `exports` conditions used when resolving imports
|
||||
*
|
||||
* Equivalent to `--conditions` in `bun build` or `bun run`.
|
||||
*
|
||||
* https://nodejs.org/api/packages.html#exports
|
||||
*/
|
||||
conditions?: Array<string> | string;
|
||||
minify?:
|
||||
| boolean // false
|
||||
| boolean
|
||||
| {
|
||||
identifiers?: boolean;
|
||||
whitespace?: boolean;
|
||||
syntax?: boolean;
|
||||
identifiers?: boolean;
|
||||
};
|
||||
/**
|
||||
* Ignore dead code elimination/tree-shaking annotations such as @__PURE__ and package.json
|
||||
* "sideEffects" fields. This should only be used as a temporary workaround for incorrect
|
||||
* annotations in libraries.
|
||||
*/
|
||||
ignoreDCEAnnotations?: boolean;
|
||||
/**
|
||||
* Force emitting @__PURE__ annotations even if minify.whitespace is true.
|
||||
*/
|
||||
emitDCEAnnotations?: boolean;
|
||||
// treeshaking?: boolean;
|
||||
|
||||
// jsx?:
|
||||
// | "automatic"
|
||||
// | "classic"
|
||||
// | /* later: "preserve" */ {
|
||||
// runtime?: "automatic" | "classic"; // later: "preserve"
|
||||
// /** Only works when runtime=classic */
|
||||
// factory?: string; // default: "React.createElement"
|
||||
// /** Only works when runtime=classic */
|
||||
// fragment?: string; // default: "React.Fragment"
|
||||
// /** Only works when runtime=automatic */
|
||||
// importSource?: string; // default: "react"
|
||||
// };
|
||||
|
||||
/**
|
||||
* Generate bytecode for the output. This can dramatically improve cold
|
||||
* start times, but will make the final output larger and slightly increase
|
||||
* memory usage.
|
||||
*
|
||||
* Bytecode is currently only supported for CommonJS (`format: "cjs"`).
|
||||
*
|
||||
* Must be `target: "bun"`
|
||||
* @default false
|
||||
*/
|
||||
bytecode?: boolean;
|
||||
}
|
||||
|
||||
interface BuildOutput {
|
||||
@@ -1304,9 +1382,9 @@ interface BuildOutput {
|
||||
interface BuildArtifact extends Blob {
|
||||
path: string;
|
||||
loader: Loader;
|
||||
hash?: string;
|
||||
kind: "entry-point" | "chunk" | "asset" | "sourcemap";
|
||||
sourcemap?: BuildArtifact;
|
||||
hash: string | null;
|
||||
kind: "entry-point" | "chunk" | "asset" | "sourcemap" | "bytecode";
|
||||
sourcemap: BuildArtifact | null;
|
||||
}
|
||||
|
||||
type Loader =
|
||||
|
||||
@@ -59,7 +59,7 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
|
||||
|
||||
- `--format`
|
||||
- `--format`
|
||||
- Bun only supports `"esm"` currently but other module formats are planned. esbuild defaults to `"iife"`.
|
||||
- Bun supports `"esm"` and `"cjs"` currently, but more module formats are planned. esbuild defaults to `"iife"`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
214
docs/guides/install/from-npm-install-to-bun-install.md
Normal file
214
docs/guides/install/from-npm-install-to-bun-install.md
Normal file
@@ -0,0 +1,214 @@
|
||||
---
|
||||
name: Migrate from npm install to bun install
|
||||
---
|
||||
|
||||
`bun install` is a Node.js compatible npm client designed to be an incredibly fast successor to npm.
|
||||
|
||||
We've put a lot of work into making sure that the migration path from `npm install` to `bun install` is as easy as running `bun install` instead of `npm install`.
|
||||
|
||||
- **Designed for Node.js & Bun**: `bun install` installs a Node.js compatible `node_modules` folder. You can use it in place of `npm install` for Node.js projects without any code changes and without using Bun's runtime.
|
||||
- **Automatically converts `package-lock.json`** to bun's `bun.lockb` lockfile format, preserving your existing resolved dependency versions without any manual work on your part. You can secretly use `bun install` in place of `npm install` at work without anyone noticing.
|
||||
- **`.npmrc` compatible**: bun install reads npm registry configuration from npm's `.npmrc`, so you can use the same configuration for both npm and Bun.
|
||||
- **Hardlinks**: On Windows and Linux, `bun install` uses hardlinks to conserve disk space and install times.
|
||||
|
||||
```bash
|
||||
# It only takes one command to migrate
|
||||
$ bun i
|
||||
|
||||
# To add dependencies:
|
||||
$ bun i @types/bun
|
||||
|
||||
# To add devDependencies:
|
||||
$ bun i -d @types/bun
|
||||
|
||||
# To remove a dependency:
|
||||
$ bun rm @types/bun
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Run package.json scripts faster
|
||||
|
||||
Run scripts from package.json, executables from `node_modules/.bin` (sort of like `npx`), and JavaScript/TypeScript files (just like `node`) - all from a single simple command.
|
||||
|
||||
| NPM | Bun |
|
||||
| ------------------ | ---------------- |
|
||||
| `npm run <script>` | `bun <script>` |
|
||||
| `npm exec <bin>` | `bun <bin>` |
|
||||
| `node <file>` | `bun <file>` |
|
||||
| `npx <package>` | `bunx <package>` |
|
||||
|
||||
When you use `bun run <executable>`, it will choose the locally-installed executable
|
||||
|
||||
```sh
|
||||
# Run a package.json script:
|
||||
$ bun my-script
|
||||
$ bun run my-script
|
||||
|
||||
# Run an executable in node_modules/.bin:
|
||||
$ bun my-executable # such as tsc, esbuild, etc.
|
||||
$ bun run my-executable
|
||||
|
||||
# Run a JavaScript/TypeScript file:
|
||||
$ bun ./index.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Workspaces? Yes.
|
||||
|
||||
`bun install` supports workspaces similarly to npm, with more features.
|
||||
|
||||
In package.json, you can set `"workspaces"` to an array of relative paths.
|
||||
|
||||
```json#package.json
|
||||
{
|
||||
"name": "my-app",
|
||||
"workspaces": ["packages/*", "apps/*"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Filter scripts by workspace name
|
||||
|
||||
In Bun, the `--filter` flag accepts a glob pattern, and will run the command concurrently for all workspace packages with a `name` that matches the pattern, respecting dependency order.
|
||||
|
||||
```sh
|
||||
$ bun --filter 'lib-*' my-script
|
||||
# instead of:
|
||||
# npm run --workspace lib-foo --workspace lib-bar my-script
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Update dependencies
|
||||
|
||||
To update a dependency, you can use `bun update <package>`. This will update the dependency to the latest version that satisfies the semver range specified in package.json.
|
||||
|
||||
```sh
|
||||
# Update a single dependency
|
||||
$ bun update @types/bun
|
||||
|
||||
# Update all dependencies
|
||||
$ bun update
|
||||
|
||||
# Ignore semver, update to the latest version
|
||||
$ bun update @types/bun --latest
|
||||
|
||||
# Update a dependency to a specific version
|
||||
$ bun update @types/bun@1.1.10
|
||||
|
||||
# Update all dependencies to the latest versions
|
||||
$ bun update --latest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### View outdated dependencies
|
||||
|
||||
To view outdated dependencies, run `bun outdated`. This is like `npm outdated` but with more compact output.
|
||||
|
||||
```sh
|
||||
$ bun outdated
|
||||
┌────────────────────────────────────────┬─────────┬────────┬────────┐
|
||||
│ Package │ Current │ Update │ Latest │
|
||||
├────────────────────────────────────────┼─────────┼────────┼────────┤
|
||||
│ @types/bun (dev) │ 1.1.6 │ 1.1.10 │ 1.1.10 │
|
||||
├────────────────────────────────────────┼─────────┼────────┼────────┤
|
||||
│ @types/react (dev) │ 18.3.3 │ 18.3.8 │ 18.3.8 │
|
||||
├────────────────────────────────────────┼─────────┼────────┼────────┤
|
||||
│ @typescript-eslint/eslint-plugin (dev) │ 7.16.1 │ 7.18.0 │ 8.6.0 │
|
||||
├────────────────────────────────────────┼─────────┼────────┼────────┤
|
||||
│ @typescript-eslint/parser (dev) │ 7.16.1 │ 7.18.0 │ 8.6.0 │
|
||||
├────────────────────────────────────────┼─────────┼────────┼────────┤
|
||||
│ @vscode/debugadapter (dev) │ 1.66.0 │ 1.67.0 │ 1.67.0 │
|
||||
├────────────────────────────────────────┼─────────┼────────┼────────┤
|
||||
│ esbuild (dev) │ 0.21.5 │ 0.21.5 │ 0.24.0 │
|
||||
├────────────────────────────────────────┼─────────┼────────┼────────┤
|
||||
│ eslint (dev) │ 9.7.0 │ 9.11.0 │ 9.11.0 │
|
||||
├────────────────────────────────────────┼─────────┼────────┼────────┤
|
||||
│ mitata (dev) │ 0.1.11 │ 0.1.14 │ 1.0.2 │
|
||||
├────────────────────────────────────────┼─────────┼────────┼────────┤
|
||||
│ prettier-plugin-organize-imports (dev) │ 4.0.0 │ 4.1.0 │ 4.1.0 │
|
||||
├────────────────────────────────────────┼─────────┼────────┼────────┤
|
||||
│ source-map-js (dev) │ 1.2.0 │ 1.2.1 │ 1.2.1 │
|
||||
├────────────────────────────────────────┼─────────┼────────┼────────┤
|
||||
│ typescript (dev) │ 5.5.3 │ 5.6.2 │ 5.6.2 │
|
||||
└────────────────────────────────────────┴─────────┴────────┴────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## List installed packages
|
||||
|
||||
To list installed packages, you can use `bun pm ls`. This will list all the packages that are installed in the `node_modules` folder using Bun's lockfile as the source of truth. You can pass the `-a` flag to list all installed packages, including transitive dependencies.
|
||||
|
||||
```sh
|
||||
# List top-level installed packages:
|
||||
$ bun pm ls
|
||||
my-pkg node_modules (781)
|
||||
├── @types/node@20.16.5
|
||||
├── @types/react@18.3.8
|
||||
├── @types/react-dom@18.3.0
|
||||
├── eslint@8.57.1
|
||||
├── eslint-config-next@14.2.8
|
||||
|
||||
# List all installed packages:
|
||||
$ bun pm ls -a
|
||||
my-pkg node_modules
|
||||
├── @alloc/quick-lru@5.2.0
|
||||
├── @isaacs/cliui@8.0.2
|
||||
│ └── strip-ansi@7.1.0
|
||||
│ └── ansi-regex@6.1.0
|
||||
├── @jridgewell/gen-mapping@0.3.5
|
||||
├── @jridgewell/resolve-uri@3.1.2
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Create a package tarball
|
||||
|
||||
To create a package tarball, you can use `bun pm pack`. This will create a tarball of the package in the current directory.
|
||||
|
||||
```sh
|
||||
# Create a tarball
|
||||
$ bun pm pack
|
||||
|
||||
Total files: 46
|
||||
Shasum: 2ee19b6f0c6b001358449ca0eadead703f326216
|
||||
Integrity: sha512-ZV0lzWTEkGAMz[...]Gl4f8lA9sl97g==
|
||||
Unpacked size: 0.41MB
|
||||
Packed size: 117.50KB
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Shebang
|
||||
|
||||
If the package references `node` in the `#!/usr/bin/env node` shebang, `bun run` will by default respect it and use the system's `node` executable. You can force it to use Bun's `node` by passing `--bun` to `bun run`.
|
||||
|
||||
When you pass `--bun` to `bun run`, we create a symlink to the locally-installed Bun executable named `"node"` in a temporary directory and add that to your `PATH` for the duration of the script's execution.
|
||||
|
||||
```sh
|
||||
# Force using Bun's runtime instead of node
|
||||
$ bun --bun my-script
|
||||
|
||||
# This also works:
|
||||
$ bun run --bun my-script
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Global installs
|
||||
|
||||
You can install packages globally using `bun i -g <package>`. This will install into a `.bun/install/global/node_modules` folder inside your home directory by default.
|
||||
|
||||
```sh
|
||||
# Install a package globally
|
||||
$ bun i -g eslint
|
||||
|
||||
# Run a globally-installed package without the `bun run` prefix
|
||||
$ eslint --init
|
||||
```
|
||||
@@ -374,6 +374,10 @@ export default {
|
||||
description: `Bun's native Semver implementation is 20x faster than the popular \`node-semver\` package.`,
|
||||
}), // "`Semver`"),
|
||||
|
||||
page("api/color", "Color", {
|
||||
description: `Bun's color function leverages Bun's CSS parser for parsing, normalizing, and converting colors from user input to a variety of output formats.`,
|
||||
}), // "`Color`"),
|
||||
|
||||
// divider("Dev Server"),
|
||||
// page("bun-dev", "Vanilla"),
|
||||
// page("dev/css", "CSS"),
|
||||
|
||||
@@ -67,6 +67,7 @@ After Visual Studio, you need the following:
|
||||
- Perl
|
||||
- Ruby
|
||||
- Node.js
|
||||
- Ccache
|
||||
|
||||
{% callout %}
|
||||
**Note** – The Zig compiler is automatically downloaded, installed, and updated by the building process.
|
||||
@@ -78,12 +79,12 @@ After Visual Studio, you need the following:
|
||||
|
||||
```ps1#WinGet
|
||||
## Select "Add LLVM to the system PATH for all users" in the LLVM installer
|
||||
> winget install -i LLVM.LLVM -v 18.1.8 && winget install GoLang.Go Rustlang.Rustup NASM.NASM StrawberryPerl.StrawberryPerl RubyInstallerTeam.Ruby.3.2 OpenJS.NodeJS.LTS
|
||||
> winget install -i LLVM.LLVM -v 18.1.8 && winget install GoLang.Go Rustlang.Rustup NASM.NASM StrawberryPerl.StrawberryPerl RubyInstallerTeam.Ruby.3.2 OpenJS.NodeJS.LTS Ccache.Ccache
|
||||
```
|
||||
|
||||
```ps1#Scoop
|
||||
> irm https://get.scoop.sh | iex
|
||||
> scoop install nodejs-lts go rust nasm ruby perl
|
||||
> 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@18.1.8
|
||||
```
|
||||
@@ -104,10 +105,10 @@ If you intend on building WebKit locally (optional), you should install these pa
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
From here on out, it is **expected you use a PowerShell Terminal with `.\scripts\env.ps1` sourced**. This script is available in the Bun repository and can be loaded by executing it:
|
||||
From here on out, it is **expected you use a PowerShell Terminal with `.\scripts\vs-shell.ps1` sourced**. This script is available in the Bun repository and can be loaded by executing it:
|
||||
|
||||
```ps1
|
||||
> .\scripts\env.ps1
|
||||
> .\scripts\vs-shell.ps1
|
||||
```
|
||||
|
||||
To verify, you can check for an MSVC-only command line such as `mt.exe`
|
||||
@@ -117,49 +118,41 @@ To verify, you can check for an MSVC-only command line such as `mt.exe`
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
It is not recommended to install `ninja` / `cmake` into your global path, because you may run into a situation where you try to build bun without .\scripts\env.ps1 sourced.
|
||||
It is not recommended to install `ninja` / `cmake` into your global path, because you may run into a situation where you try to build bun without .\scripts\vs-shell.ps1 sourced.
|
||||
{% /callout %}
|
||||
|
||||
## Building
|
||||
|
||||
```ps1
|
||||
> bun install
|
||||
> bun run build
|
||||
|
||||
> .\scripts\env.ps1
|
||||
> .\scripts\update-submodules.ps1 # this syncs git submodule state
|
||||
> .\scripts\all-dependencies.ps1 # this builds all dependencies
|
||||
> .\scripts\make-old-js.ps1 # runs some old code generators
|
||||
|
||||
# Configure build environment
|
||||
> cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Debug
|
||||
|
||||
# Build bun
|
||||
> ninja -Cbuild
|
||||
# after the initial `bun run build` you can use the following to build
|
||||
> ninja -Cbuild/debug
|
||||
```
|
||||
|
||||
If this was successful, you should have a `bun-debug.exe` in the `build` folder.
|
||||
If this was successful, you should have a `bun-debug.exe` in the `build/debug` folder.
|
||||
|
||||
```ps1
|
||||
> .\build\bun-debug.exe --revision
|
||||
> .\build\debug\bun-debug.exe --revision
|
||||
```
|
||||
|
||||
You should add this to `$Env:PATH`. The simplest way to do so is to open the start menu, type "Path", and then navigate the environment variables menu to add `C:\.....\bun\build` to the user environment variable `PATH`. You should then restart your editor (if it does not update still, log out and log back in).
|
||||
You should add this to `$Env:PATH`. The simplest way to do so is to open the start menu, type "Path", and then navigate the environment variables menu to add `C:\.....\bun\build\debug` to the user environment variable `PATH`. You should then restart your editor (if it does not update still, log out and log back in).
|
||||
|
||||
## Extra paths
|
||||
|
||||
- WebKit is extracted to `build/bun-webkit`
|
||||
- Zig is extracted to `.cache/zig/zig.exe`
|
||||
- WebKit is extracted to `build/debug/cache/webkit/`
|
||||
- Zig is extracted to `build/debug/cache/zig/bin/zig.exe`
|
||||
|
||||
## Tests
|
||||
|
||||
You can run the test suite either using `bun test`, or by using the wrapper script `packages\bun-internal-test`. The internal test package is a wrapper cli to run every test file in a separate instance of bun.exe, to prevent a crash in the test runner from stopping the entire suite.
|
||||
You can run the test suite either using `bun test <path>`, or by using the wrapper script `packages\bun-internal-test`. The internal test package is a wrapper cli to run every test file in a separate instance of bun.exe, to prevent a crash in the test runner from stopping the entire suite.
|
||||
|
||||
```ps1
|
||||
# Setup
|
||||
> bun i --cwd packages\bun-internal-test
|
||||
|
||||
# Run the entire test suite with reporter
|
||||
# the package.json script "test" uses "build/bun-debug.exe" by default
|
||||
# the package.json script "test" uses "build/debug/bun-debug.exe" by default
|
||||
> bun run test
|
||||
|
||||
# Run an individual test file:
|
||||
|
||||
@@ -40,7 +40,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionWrite, (JSC::JSGlobalObject * globalObject,
|
||||
int32_t fd = STDOUT_FILENO;
|
||||
if (callframe->argumentCount() > 1) {
|
||||
fd = arg1.toInt32(globalObject);
|
||||
RETURN_IF_EXCEPTION(scope, encodedJSValue());
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
} else {
|
||||
toWriteArg = arg1;
|
||||
}
|
||||
@@ -53,7 +53,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionWrite, (JSC::JSGlobalObject * globalObject,
|
||||
}
|
||||
|
||||
auto string = toWriteArg.toWTFString(globalObject);
|
||||
RETURN_IF_EXCEPTION(scope, encodedJSValue());
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
auto utf8 = string.utf8();
|
||||
auto length = utf8.length();
|
||||
auto written = write(fd, utf8.data(), length);
|
||||
|
||||
35
package.json
35
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "bun",
|
||||
"version": "1.1.29",
|
||||
"version": "1.1.30",
|
||||
"workspaces": [
|
||||
"./packages/bun-types"
|
||||
],
|
||||
@@ -21,7 +21,10 @@
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"source-map-js": "^1.2.0",
|
||||
"typescript": "^5.4.5"
|
||||
"typescript": "^5.4.5",
|
||||
"caniuse-lite": "^1.0.30001620",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"@mdn/browser-compat-data": "~5.5.28"
|
||||
},
|
||||
"resolutions": {
|
||||
"bun-types": "workspace:packages/bun-types"
|
||||
@@ -42,18 +45,32 @@
|
||||
"build:debug-zig-release": "cmake . -DCMAKE_BUILD_TYPE=Release -DZIG_OPTIMIZE=Debug -GNinja -Bbuild-debug-zig-release && ninja -Cbuild-debug-zig-release",
|
||||
"bump": "bun ./scripts/bump.ts",
|
||||
"typecheck": "tsc --noEmit && cd test && bun run typecheck",
|
||||
"fmt": "prettier --config=.prettierrc-ci --write --cache './{.vscode,src,test,bench,packages/{bun-types,bun-inspector-*,bun-vscode,bun-debug-adapter-protocol}}/**/*.{mjs,ts,tsx,js,jsx}'",
|
||||
"fmt:cpp": "clang-format -i src/bun.js/bindings/**/*.{cpp,h} --verbose",
|
||||
"fmt:zig": "bun run zig:fmt",
|
||||
"fmt": "bun run prettier",
|
||||
"fmt:cpp": "bun run clang-format",
|
||||
"fmt:zig": "bun run zig-format",
|
||||
"lint": "eslint './**/*.d.ts' --cache",
|
||||
"lint:fix": "eslint './**/*.d.ts' --cache --fix",
|
||||
"test": "node scripts/runner.node.mjs ./build/bun-debug",
|
||||
"test:release": "node scripts/runner.node.mjs ./build-release/bun",
|
||||
"test": "node scripts/runner.node.mjs --exec-path ./build/debug/bun-debug",
|
||||
"test:release": "node scripts/runner.node.mjs --exec-path ./build/release/bun",
|
||||
"banned": "bun packages/bun-internal-test/src/linter.ts",
|
||||
"zig": "vendor/zig/zig.exe",
|
||||
"zig:fmt": "bun run zig fmt src/*.zig src/*/*.zig src/*/*/*.zig src/*/*/*/*.zig",
|
||||
"zig:fmt": "bun run zig-format",
|
||||
"zig:check": "bun run zig build check --summary new",
|
||||
"zig:check-all": "bun run zig build check-all --summary new",
|
||||
"zig:check-windows": "bun run zig build check-windows --summary new"
|
||||
"zig:check-windows": "bun run zig build check-windows --summary new",
|
||||
"cmake": "bun ./scripts/build.mjs -DCMAKE_BUILD_TYPE=Debug -B build/debug",
|
||||
"clang-format": "bun run cmake --target clang-format",
|
||||
"clang-format:check": "bun run cmake --target clang-format-check",
|
||||
"clang-format:diff": "bun run cmake --target clang-format-diff",
|
||||
"clang-tidy": "bun run cmake --target clang-tidy",
|
||||
"clang-tidy:check": "bun run cmake --target clang-tidy-check",
|
||||
"clang-tidy:diff": "bun run cmake --target clang-tidy-diff",
|
||||
"zig-format": "bun run cmake --target zig-format",
|
||||
"zig-format:check": "bun run cmake --target zig-format-check",
|
||||
"zig-format:diff": "bun run cmake --target zig-format-diff",
|
||||
"prettier": "bun run cmake -DENABLE_PRETTIER=ON --target prettier",
|
||||
"prettier:check": "bun run cmake -DENABLE_PRETTIER=ON --target prettier-check",
|
||||
"prettier:extra": "bun run cmake -DENABLE_PRETTIER=ON --target prettier-extra",
|
||||
"prettier:diff": "bun run cmake -DENABLE_PRETTIER=ON --target prettier-diff"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
bin/bun-profile
|
||||
bin/*.o
|
||||
*.o
|
||||
*.a
|
||||
@@ -2,13 +2,27 @@ import type { InspectorEventMap } from "../../../bun-inspector-protocol/src/insp
|
||||
import type { JSC } from "../../../bun-inspector-protocol/src/protocol";
|
||||
import type { DAP } from "../protocol";
|
||||
// @ts-ignore
|
||||
import type { ChildProcess } from "node:child_process";
|
||||
import { spawn } from "node:child_process";
|
||||
import { ChildProcess, spawn } from "node:child_process";
|
||||
import { EventEmitter } from "node:events";
|
||||
import { WebSocketInspector, remoteObjectToString } from "../../../bun-inspector-protocol/index";
|
||||
import { UnixSignal, randomUnixPath } from "./signal";
|
||||
import { AddressInfo, createServer } from "node:net";
|
||||
import * as path from "node:path";
|
||||
import { remoteObjectToString, WebSocketInspector } from "../../../bun-inspector-protocol/index";
|
||||
import { randomUnixPath, TCPSocketSignal, UnixSignal } from "./signal";
|
||||
import { Location, SourceMap } from "./sourcemap";
|
||||
|
||||
export async function getAvailablePort(): Promise<number> {
|
||||
const server = createServer();
|
||||
server.listen(0);
|
||||
return new Promise((resolve, reject) => {
|
||||
server.on("listening", () => {
|
||||
const { port } = server.address() as AddressInfo;
|
||||
server.close(() => {
|
||||
resolve(port);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const capabilities: DAP.Capabilities = {
|
||||
supportsConfigurationDoneRequest: true,
|
||||
supportsFunctionBreakpoints: true,
|
||||
@@ -489,36 +503,73 @@ export class DebugAdapter extends EventEmitter<DebugAdapterEventMap> implements
|
||||
...env,
|
||||
};
|
||||
|
||||
const url = `ws+unix://${randomUnixPath()}`;
|
||||
const signal = new UnixSignal();
|
||||
if (process.platform !== "win32") {
|
||||
// we're on unix
|
||||
const url = `ws+unix://${randomUnixPath()}`;
|
||||
const signal = new UnixSignal();
|
||||
|
||||
signal.on("Signal.received", () => {
|
||||
this.#attach({ url });
|
||||
});
|
||||
signal.on("Signal.received", () => {
|
||||
this.#attach({ url });
|
||||
});
|
||||
|
||||
this.once("Adapter.terminated", () => {
|
||||
signal.close();
|
||||
});
|
||||
this.once("Adapter.terminated", () => {
|
||||
signal.close();
|
||||
});
|
||||
|
||||
const query = stopOnEntry ? "break=1" : "wait=1";
|
||||
processEnv["BUN_INSPECT"] = `${url}?${query}`;
|
||||
processEnv["BUN_INSPECT_NOTIFY"] = signal.url;
|
||||
const query = stopOnEntry ? "break=1" : "wait=1";
|
||||
processEnv["BUN_INSPECT"] = `${url}?${query}`;
|
||||
processEnv["BUN_INSPECT_NOTIFY"] = signal.url;
|
||||
|
||||
// This is probably not correct, but it's the best we can do for now.
|
||||
processEnv["FORCE_COLOR"] = "1";
|
||||
processEnv["BUN_QUIET_DEBUG_LOGS"] = "1";
|
||||
processEnv["BUN_DEBUG_QUIET_LOGS"] = "1";
|
||||
// This is probably not correct, but it's the best we can do for now.
|
||||
processEnv["FORCE_COLOR"] = "1";
|
||||
processEnv["BUN_QUIET_DEBUG_LOGS"] = "1";
|
||||
processEnv["BUN_DEBUG_QUIET_LOGS"] = "1";
|
||||
|
||||
const started = await this.#spawn({
|
||||
command: runtime,
|
||||
args: processArgs,
|
||||
env: processEnv,
|
||||
cwd,
|
||||
isDebugee: true,
|
||||
});
|
||||
const started = await this.#spawn({
|
||||
command: runtime,
|
||||
args: processArgs,
|
||||
env: processEnv,
|
||||
cwd,
|
||||
isDebugee: true,
|
||||
});
|
||||
|
||||
if (!started) {
|
||||
throw new Error("Program could not be started.");
|
||||
if (!started) {
|
||||
throw new Error("Program could not be started.");
|
||||
}
|
||||
} else {
|
||||
// we're on windows
|
||||
// Create TCPSocketSignal
|
||||
const url = `ws://127.0.0.1:${await getAvailablePort()}/${getRandomId()}`; // 127.0.0.1 so it resolves correctly on windows
|
||||
const signal = new TCPSocketSignal(await getAvailablePort());
|
||||
|
||||
signal.on("Signal.received", async () => {
|
||||
this.#attach({ url });
|
||||
});
|
||||
|
||||
this.once("Adapter.terminated", () => {
|
||||
signal.close();
|
||||
});
|
||||
|
||||
const query = stopOnEntry ? "break=1" : "wait=1";
|
||||
processEnv["BUN_INSPECT"] = `${url}?${query}`;
|
||||
processEnv["BUN_INSPECT_NOTIFY"] = signal.url; // 127.0.0.1 so it resolves correctly on windows
|
||||
|
||||
// This is probably not correct, but it's the best we can do for now.
|
||||
processEnv["FORCE_COLOR"] = "1";
|
||||
processEnv["BUN_QUIET_DEBUG_LOGS"] = "1";
|
||||
processEnv["BUN_DEBUG_QUIET_LOGS"] = "1";
|
||||
|
||||
const started = await this.#spawn({
|
||||
command: runtime,
|
||||
args: processArgs,
|
||||
env: processEnv,
|
||||
cwd,
|
||||
isDebugee: true,
|
||||
});
|
||||
|
||||
if (!started) {
|
||||
throw new Error("Program could not be started.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -684,6 +735,9 @@ export class DebugAdapter extends EventEmitter<DebugAdapterEventMap> implements
|
||||
|
||||
async breakpointLocations(request: DAP.BreakpointLocationsRequest): Promise<DAP.BreakpointLocationsResponse> {
|
||||
const { line, endLine, column, endColumn, source: source0 } = request;
|
||||
if (process.platform === "win32") {
|
||||
source0.path = source0.path ? normalizeWindowsPath(source0.path) : source0.path;
|
||||
}
|
||||
const source = await this.#getSource(sourceToId(source0));
|
||||
|
||||
const { locations } = await this.send("Debugger.getBreakpointLocations", {
|
||||
@@ -788,6 +842,9 @@ export class DebugAdapter extends EventEmitter<DebugAdapterEventMap> implements
|
||||
}
|
||||
|
||||
async #setBreakpointsByUrl(url: string, requests: DAP.SourceBreakpoint[], unsetOld?: boolean): Promise<Breakpoint[]> {
|
||||
if (process.platform === "win32") {
|
||||
url = url ? normalizeWindowsPath(url) : url;
|
||||
}
|
||||
const source = this.#getSourceIfPresent(url);
|
||||
|
||||
// If the source is not loaded, set a placeholder breakpoint at the start of the file.
|
||||
@@ -1161,6 +1218,9 @@ export class DebugAdapter extends EventEmitter<DebugAdapterEventMap> implements
|
||||
|
||||
async gotoTargets(request: DAP.GotoTargetsRequest): Promise<DAP.GotoTargetsResponse> {
|
||||
const { source: source0 } = request;
|
||||
if (process.platform === "win32") {
|
||||
source0.path = source0.path ? normalizeWindowsPath(source0.path) : source0.path;
|
||||
}
|
||||
const source = await this.#getSource(sourceToId(source0));
|
||||
|
||||
const { breakpoints } = await this.breakpointLocations(request);
|
||||
@@ -1327,7 +1387,7 @@ export class DebugAdapter extends EventEmitter<DebugAdapterEventMap> implements
|
||||
// 1. If it has a `path`, the client retrieves the source from the file system.
|
||||
// 2. If it has a `sourceReference`, the client sends a `source` request.
|
||||
// Moreover, the code is usually shown in a read-only editor.
|
||||
const isUserCode = url.startsWith("/");
|
||||
const isUserCode = path.isAbsolute(url);
|
||||
const sourceMap = SourceMap(sourceMapURL);
|
||||
const name = sourceName(url);
|
||||
const presentationHint = sourcePresentationHint(url);
|
||||
@@ -1646,12 +1706,11 @@ export class DebugAdapter extends EventEmitter<DebugAdapterEventMap> implements
|
||||
|
||||
// If the source does not have a path or is a builtin module,
|
||||
// it cannot be retrieved from the file system.
|
||||
if (typeof sourceId === "number" || !sourceId.startsWith("/")) {
|
||||
if (typeof sourceId === "number" || !path.isAbsolute(sourceId)) {
|
||||
throw new Error(`Source not found: ${sourceId}`);
|
||||
}
|
||||
|
||||
// If the source is not present, it may not have been loaded yet.
|
||||
// In that case, wait for it to be loaded.
|
||||
let resolves = this.#pendingSources.get(sourceId);
|
||||
if (!resolves) {
|
||||
this.#pendingSources.set(sourceId, (resolves = []));
|
||||
@@ -2107,7 +2166,6 @@ export class DebugAdapter extends EventEmitter<DebugAdapterEventMap> implements
|
||||
|
||||
close(): void {
|
||||
this.#process?.kill();
|
||||
// this.#signal?.close();
|
||||
this.#inspector.close();
|
||||
this.#reset();
|
||||
}
|
||||
@@ -2149,10 +2207,10 @@ function titleize(name: string): string {
|
||||
}
|
||||
|
||||
function sourcePresentationHint(url?: string): DAP.Source["presentationHint"] {
|
||||
if (!url || !url.startsWith("/")) {
|
||||
if (!url || !path.isAbsolute(url)) {
|
||||
return "deemphasize";
|
||||
}
|
||||
if (url.includes("/node_modules/")) {
|
||||
if (url.includes("/node_modules/") || url.includes("\\node_modules\\")) {
|
||||
return "normal";
|
||||
}
|
||||
return "emphasize";
|
||||
@@ -2163,6 +2221,9 @@ function sourceName(url?: string): string {
|
||||
return "unknown.js";
|
||||
}
|
||||
if (isJavaScript(url)) {
|
||||
if (process.platform === "win32") {
|
||||
url = url.replaceAll("\\", "/");
|
||||
}
|
||||
return url.split("/").pop() || url;
|
||||
}
|
||||
return `${url}.js`;
|
||||
@@ -2567,3 +2628,15 @@ let sequence = 1;
|
||||
function nextId(): number {
|
||||
return sequence++;
|
||||
}
|
||||
|
||||
export function getRandomId() {
|
||||
return Math.random().toString(36).slice(2);
|
||||
}
|
||||
|
||||
export function normalizeWindowsPath(winPath: string): string {
|
||||
winPath = path.normalize(winPath);
|
||||
if (winPath[1] === ":" && (winPath[2] === "\\" || winPath[2] === "/")) {
|
||||
return (winPath.charAt(0).toUpperCase() + winPath.slice(1)).replaceAll("\\\\", "\\");
|
||||
}
|
||||
return winPath;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { EventEmitter } from "node:events";
|
||||
import type { Server } from "node:net";
|
||||
import type { Server, Socket } from "node:net";
|
||||
import { createServer } from "node:net";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
@@ -85,3 +85,75 @@ function parseUnixPath(path: string | URL): string {
|
||||
throw new Error(`Invalid UNIX path: ${path}`);
|
||||
}
|
||||
}
|
||||
|
||||
export type TCPSocketSignalEventMap = {
|
||||
"Signal.listening": [];
|
||||
"Signal.error": [Error];
|
||||
"Signal.closed": [];
|
||||
"Signal.received": [string];
|
||||
};
|
||||
|
||||
export class TCPSocketSignal extends EventEmitter {
|
||||
#port: number;
|
||||
#server: ReturnType<typeof createServer>;
|
||||
#ready: Promise<void>;
|
||||
|
||||
constructor(port: number) {
|
||||
super();
|
||||
this.#port = port;
|
||||
|
||||
this.#server = createServer((socket: Socket) => {
|
||||
socket.on("data", data => {
|
||||
this.emit("Signal.received", data.toString());
|
||||
});
|
||||
|
||||
socket.on("error", error => {
|
||||
this.emit("Signal.error", error);
|
||||
});
|
||||
|
||||
socket.on("close", () => {
|
||||
this.emit("Signal.closed");
|
||||
});
|
||||
});
|
||||
|
||||
this.#ready = new Promise((resolve, reject) => {
|
||||
this.#server.listen(this.#port, () => {
|
||||
this.emit("Signal.listening");
|
||||
resolve();
|
||||
});
|
||||
this.#server.on("error", reject);
|
||||
});
|
||||
}
|
||||
|
||||
emit<E extends keyof TCPSocketSignalEventMap>(event: E, ...args: TCPSocketSignalEventMap[E]): boolean {
|
||||
if (isDebug) {
|
||||
console.log(event, ...args);
|
||||
}
|
||||
return super.emit(event, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* The TCP port.
|
||||
*/
|
||||
get port(): number {
|
||||
return this.#port;
|
||||
}
|
||||
|
||||
get url(): string {
|
||||
return `tcp://127.0.0.1:${this.#port}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves when the server is listening or rejects if an error occurs.
|
||||
*/
|
||||
get ready(): Promise<void> {
|
||||
return this.#ready;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the server.
|
||||
*/
|
||||
close(): void {
|
||||
this.#server.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
bin/bun-profile
|
||||
bin/*.o
|
||||
*.o
|
||||
*.a
|
||||
@@ -1,3 +0,0 @@
|
||||
# `bun-plugin-css`
|
||||
|
||||
Not implemented.
|
||||
@@ -1 +0,0 @@
|
||||
throw new Error("Not implemented.");
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"name": "bun-plugin-css",
|
||||
"version": "0.0.1-alpha.0",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"files": [
|
||||
"index.ts",
|
||||
"package.json"
|
||||
]
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# `bun-plugin-lightningcss`
|
||||
|
||||
Not implemented.
|
||||
@@ -1 +0,0 @@
|
||||
throw new Error("Not implemented.");
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"name": "bun-plugin-lightningcss",
|
||||
"version": "0.0.1-alpha.0",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"files": [
|
||||
"index.ts",
|
||||
"package.json"
|
||||
]
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# `bun-plugin-mdx`
|
||||
|
||||
Not implemented.
|
||||
@@ -1 +0,0 @@
|
||||
throw new Error("Not implemented.");
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"name": "bun-plugin-mdx",
|
||||
"version": "0.0.1-alpha.0",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"files": [
|
||||
"index.ts",
|
||||
"package.json"
|
||||
]
|
||||
}
|
||||
169
packages/bun-plugin-server-components/.gitignore
vendored
169
packages/bun-plugin-server-components/.gitignore
vendored
@@ -1,169 +0,0 @@
|
||||
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
|
||||
|
||||
# Logs
|
||||
|
||||
logs
|
||||
_.log
|
||||
npm-debug.log_
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# Runtime data
|
||||
|
||||
pids
|
||||
_.pid
|
||||
_.seed
|
||||
\*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
|
||||
coverage
|
||||
\*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
|
||||
\*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
|
||||
\*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
|
||||
.cache/
|
||||
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.\*
|
||||
@@ -1,149 +0,0 @@
|
||||
# `bun-plugin-server-components`
|
||||
|
||||
The official Bun plugin for **server components**.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
bun add bun-plugin-server-components -d
|
||||
```
|
||||
|
||||
## Context
|
||||
|
||||
Server components are a new abstraction for building web applications. They look similar to standard React/JSX components, but render exclusively on the server. They differ from classic "client components" in a few ways:
|
||||
|
||||
1. They can be `async`.
|
||||
2. Their implementation can run privileged code like database queries. Normally this would be unsafe, because the source code of client components are typically bundled and sent to the client, where they can be inspected and reverse-engineered. Server components are never sent to the client, so they can run privileged code safely.
|
||||
3. They _cannot_ contain stateful hooks like `useState` or `useEffect`.
|
||||
|
||||
Server components require a deep integration with the bundler to work. To understand why, we need a bit of background on how server components work.
|
||||
|
||||
### How server components work
|
||||
|
||||
Imagine you have a server component that looks like this:
|
||||
|
||||
```tsx
|
||||
// index.tsx
|
||||
import { Component } from "./Component";
|
||||
export default async function HomePage() {
|
||||
return (
|
||||
<div>
|
||||
<Component />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
This file imports a client component called `Component`.
|
||||
|
||||
```ts
|
||||
// ./Component.tsx
|
||||
"use client";
|
||||
|
||||
export function Component() {
|
||||
return <div>Hello world</div>;
|
||||
}
|
||||
```
|
||||
|
||||
To run this component we need to generate two builds.
|
||||
|
||||
> Here the term "build" refers to a typical bundling step—the act of converting a set of entrypoints into a set of bundles.
|
||||
|
||||
1. The first is our "server component build". It contains all the code we need to render `HomePage` to a component tree. When an incoming `Request` comes in, we can use React's built-in tools to convert this tree into a "virtual DOM stream" that we can return as a `Response`.
|
||||
2. The second is our "client build". It contains the bundled versions of all client components that were referenced by our server components.
|
||||
|
||||
The browser hits the server and gets back the "virtual DOM stream". The virtual DOM stream will contain references to client components, which will be loaded from the client bundle. React provides a built-in utility (`createFromFetch`)that accepts the VDOM stream, dynamically loads the necessary client components, and returns a renderable component.
|
||||
|
||||
```ts
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { createFromFetch } from "react-server-dom-webpack/client.browser";
|
||||
|
||||
const stream = fetch("/", { headers: { Accept: "text/x-component" } });
|
||||
const data = createFromFetch(stream);
|
||||
|
||||
const root = createRoot(document);
|
||||
root.render(<App />);
|
||||
```
|
||||
|
||||
### Server-side rendering
|
||||
|
||||
One potentially confusing aspect of server components is that they "return" virtual DOM. From the perspective of a server component, client components are black boxes.
|
||||
|
||||
If we want to do server-side rendering, we need to render our server component to VDOM, _then_ render the VDOM to plain HTML. These are two distinct steps. The second step requires a _third build_, we we'll call the "SSR build". Like the "client build", this build will bundle all the client components. Unlike the "client build", those bundles will be intended for consumption on the server; in bundler terms, the build's `"target"` will be`"bun"` (or perhaps `"node"`).
|
||||
|
||||
### Bundling server components
|
||||
|
||||
That's a high-level overview of how server components work. The important takeaway is that we need to generate totally separate bundles for server and client components.
|
||||
|
||||
But it's not just a simple matter of running two separate bundling scripts. The true "entrypoints" of our application are the server components. Over the course of bundling our server components, we will discover some files containing the `"use client"` directive; these files then become the entrypoints for our "client build", which will require a totally separate build configuration from the server build.
|
||||
|
||||
The goal of this plugin is to hide the complexty of this multi-stage build from the user.
|
||||
|
||||
## Usage
|
||||
|
||||
To use this plugin:
|
||||
|
||||
```ts
|
||||
import ServerComponentsPlugin from "bun-plugin-server-components";
|
||||
|
||||
await Bun.build({
|
||||
entrypoints: ["./index.tsx"], // server component files
|
||||
plugins: [
|
||||
ServerComponentsPlugin({
|
||||
// plugin configuration
|
||||
}),
|
||||
],
|
||||
// other configuration
|
||||
});
|
||||
```
|
||||
|
||||
The `"entrypoints"` you pass into `Bun.build()` should be your _server components_. Bun's bundler will automatically detect any files containing the `"use client"` directive, and will use those files as entrypoints for the "client build" and "SSR build". The bundler configuration for these builds can be provided `client` and `ssr` keys respectively.
|
||||
|
||||
```ts
|
||||
import ServerComponentsPlugin from "bun-plugin-server-components";
|
||||
|
||||
await Bun.build({
|
||||
entrypoints: ["./index.tsx"], // server component files
|
||||
outdir: "./build",
|
||||
manifest: true,
|
||||
plugins: [ServerComponentsPlugin({
|
||||
client: {
|
||||
entrypoints: [], // optional - additional client entrypoints
|
||||
outdir: "./build/client", // default: inherits from the main build
|
||||
target: "browser",
|
||||
plugins: [/* */],
|
||||
}
|
||||
ssr: {
|
||||
entrypoints: [], // optional - additional SSR entrypoints
|
||||
outdir: "./build/client", // default: inherits from the main build
|
||||
target: "bun", // this is default
|
||||
plugins: [/* */],
|
||||
}
|
||||
})],
|
||||
});
|
||||
```
|
||||
|
||||
The result of `Bun.build()` will contain additional manifests for the SSR and client builds.
|
||||
|
||||
```ts
|
||||
const result = await Bun.build({
|
||||
// config
|
||||
plugins: [
|
||||
ServerComponentsPlugin({
|
||||
/* config */
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// standard manifest
|
||||
// for the top-level (server components) build
|
||||
result.manifest;
|
||||
|
||||
// manifest for client build
|
||||
result.clientManifest;
|
||||
|
||||
// manifest for client build
|
||||
result.ssrManifest;
|
||||
```
|
||||
|
||||
Once the build is complete, use the manifests to implement your RSC server.
|
||||
Binary file not shown.
@@ -1,10 +0,0 @@
|
||||
import { BunPlugin, BuildConfig } from "bun";
|
||||
|
||||
function Plugin(config: { client?: BuildConfig; ssr?: BuildConfig }): BunPlugin {
|
||||
return {
|
||||
name: "bun-plugin-server-components",
|
||||
SECRET_SERVER_COMPONENTS_INTERNALS: config,
|
||||
} as any;
|
||||
}
|
||||
|
||||
export default Plugin;
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"name": "bun-plugin-server-components",
|
||||
"version": "0.0.1-alpha.0",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"types": "index.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./index.ts",
|
||||
"require": "./index.ts",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
"index.ts",
|
||||
"tsconfig.json",
|
||||
"package.json",
|
||||
"modules.d.ts"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/js-yaml": "^4.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"bun-types": "canary",
|
||||
"js-yaml": "^4.1.0"
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext"],
|
||||
"module": "esnext",
|
||||
"target": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"moduleDetection": "force",
|
||||
"allowImportingTsExtensions": true,
|
||||
"noEmit": true,
|
||||
"composite": true,
|
||||
"strict": true,
|
||||
"downlevelIteration": true,
|
||||
"skipLibCheck": true,
|
||||
"jsx": "react-jsx",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"allowJs": true,
|
||||
"types": [
|
||||
"bun-types" // add Bun global
|
||||
]
|
||||
},
|
||||
"include": ["**/*.ts", "modules.d.ts"]
|
||||
}
|
||||
@@ -2,6 +2,27 @@ import { AwsClient } from "aws4fetch";
|
||||
import { getBuild, getRelease, getSemver, getSha } from "../src/github";
|
||||
import { join, tmp } from "../src/fs";
|
||||
|
||||
// The source of truth for the git sha is what's in the local build, extracted from features.json
|
||||
// NOT the git tag revision.
|
||||
// Ideally, these are always the same, but mistakes can happen.
|
||||
const local =
|
||||
"bun-" +
|
||||
(
|
||||
{
|
||||
darwin: "darwin",
|
||||
win32: "windows",
|
||||
linux: "linux",
|
||||
} as any
|
||||
)[process.platform] +
|
||||
"-" +
|
||||
(
|
||||
{
|
||||
arm64: "aarch64",
|
||||
x64: "x64",
|
||||
} as any
|
||||
)[process.arch] +
|
||||
".zip";
|
||||
|
||||
const dryRun = process.argv.includes("--dry-run");
|
||||
|
||||
const [tag] = process.argv.slice(2);
|
||||
@@ -28,40 +49,68 @@ const full_commit_hash = await getSha(tag, "long");
|
||||
console.log("Found release:", release.tag_name, "with commit hash:", full_commit_hash);
|
||||
|
||||
console.log("Found build:", full_commit_hash);
|
||||
const isCanary = release.tag_name === "canary";
|
||||
|
||||
let paths: string[];
|
||||
if (latest.tag_name === release.tag_name) {
|
||||
paths = ["releases/latest", `releases/${release.tag_name}`, `releases/${full_commit_hash}`];
|
||||
} else if (release.tag_name === "canary") {
|
||||
try {
|
||||
const build = await getSemver("canary", await getBuild());
|
||||
paths = ["releases/canary", `releases/${build}`, `releases/${full_commit_hash}-canary`];
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
paths = ["releases/canary"];
|
||||
let paths: string[] = [];
|
||||
async function setPaths(revision: string, isCanary: boolean) {
|
||||
const releaseSha = `releases/${revision + (isCanary ? "-canary" : "")}`;
|
||||
if (latest.tag_name === release.tag_name) {
|
||||
paths = ["releases/latest", `releases/${release.tag_name}`, releaseSha];
|
||||
} else if (isCanary) {
|
||||
try {
|
||||
const build = await getSemver("canary", await getBuild());
|
||||
paths = ["releases/canary", `releases/${build}`, releaseSha];
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
paths = ["releases/canary", releaseSha];
|
||||
}
|
||||
} else {
|
||||
paths = [`releases/${release.tag_name}`, releaseSha];
|
||||
}
|
||||
} else {
|
||||
paths = [`releases/${release.tag_name}`, `releases/${full_commit_hash}`];
|
||||
}
|
||||
console.log("Found paths:", paths);
|
||||
|
||||
const local =
|
||||
"bun-" +
|
||||
(
|
||||
{
|
||||
darwin: "darwin",
|
||||
win32: "windows",
|
||||
linux: "linux",
|
||||
} as any
|
||||
)[process.platform] +
|
||||
"-" +
|
||||
(
|
||||
{
|
||||
arm64: "aarch64",
|
||||
x64: "x64",
|
||||
} as any
|
||||
)[process.arch] +
|
||||
".zip";
|
||||
console.log("Found paths:", paths);
|
||||
}
|
||||
|
||||
async function getFeaturesJSON(body: ArrayBuffer) {
|
||||
// extract feature data using the local build
|
||||
const temp = tmp();
|
||||
await Bun.write(join(temp, "bun.zip"), body);
|
||||
let unzip = Bun.spawnSync({
|
||||
cmd: ["unzip", join(temp, "bun.zip")],
|
||||
cwd: temp,
|
||||
});
|
||||
if (!unzip.success) throw new Error("Failed to unzip");
|
||||
let data = Bun.spawnSync({
|
||||
cmd: [
|
||||
join(temp, local.replace(".zip", ""), "bun"),
|
||||
"--print",
|
||||
'JSON.stringify(require("bun:internal-for-testing").crash_handler.getFeatureData())',
|
||||
],
|
||||
cwd: temp,
|
||||
env: {
|
||||
...process.env,
|
||||
BUN_DEBUG_QUIET_LOGS: "1",
|
||||
BUN_GARBAGE_COLLECTOR_LEVEL: "0",
|
||||
BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: "1",
|
||||
},
|
||||
stdio: ["ignore", "pipe", "inherit"],
|
||||
});
|
||||
return data.stdout.toString("utf8").trim();
|
||||
}
|
||||
|
||||
// Make the first asset the local build
|
||||
for (let i = 0; i < release.assets.length; i++) {
|
||||
const asset = release.assets[i];
|
||||
if (asset.name === local) {
|
||||
release.assets.splice(i, 1);
|
||||
release.assets.unshift(asset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (release?.assets?.[0]?.name !== local) {
|
||||
throw new Error("Expected local build to be the first asset");
|
||||
}
|
||||
|
||||
for (const asset of release.assets) {
|
||||
const url = asset.browser_download_url;
|
||||
@@ -83,39 +132,25 @@ for (const asset of release.assets) {
|
||||
contentType = response.headers.get("Content-Type") || "";
|
||||
}
|
||||
|
||||
console.log("Downloading asset:", name);
|
||||
const body = await response.arrayBuffer();
|
||||
|
||||
if (name == local) {
|
||||
// extract feature data using the local build
|
||||
const temp = tmp();
|
||||
await Bun.write(join(temp, "bun.zip"), body);
|
||||
let unzip = Bun.spawnSync({
|
||||
cmd: ["unzip", join(temp, "bun.zip")],
|
||||
cwd: temp,
|
||||
});
|
||||
if (!unzip.success) throw new Error("Failed to unzip");
|
||||
let data = Bun.spawnSync({
|
||||
cmd: [
|
||||
join(temp, local.replace(".zip", ""), "bun"),
|
||||
"--print",
|
||||
'JSON.stringify(require("bun:internal-for-testing").crash_handler.getFeatureData())',
|
||||
],
|
||||
cwd: temp,
|
||||
env: {
|
||||
...process.env,
|
||||
BUN_DEBUG_QUIET_LOGS: "1",
|
||||
BUN_GARBAGE_COLLECTOR_LEVEL: "0",
|
||||
BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: "1",
|
||||
},
|
||||
stdio: ["ignore", "pipe", "inherit"],
|
||||
});
|
||||
const json = data.stdout.toString("utf8");
|
||||
const text = await getFeaturesJSON(body);
|
||||
const features = JSON.parse(text);
|
||||
const sha = features.revision;
|
||||
if (features.is_canary && !isCanary) {
|
||||
console.warn("Local build is a canary but release is not tagged as canary.");
|
||||
}
|
||||
await setPaths(sha, features.is_canary);
|
||||
console.log("features.json:", JSON.stringify(features, null, 2));
|
||||
|
||||
for (const path of paths) {
|
||||
const key = `${path}/features.json`;
|
||||
console.log("Uploading:", key);
|
||||
await uploadToS3({
|
||||
key,
|
||||
body: new TextEncoder().encode(json).buffer,
|
||||
body: new TextEncoder().encode(text).buffer,
|
||||
headers: {
|
||||
"Content-Type": contentType,
|
||||
"Content-Disposition": `attachment; filename="${name}"`,
|
||||
|
||||
156
packages/bun-types/bun.d.ts
vendored
156
packages/bun-types/bun.d.ts
vendored
@@ -1497,13 +1497,35 @@ declare module "bun" {
|
||||
kind: ImportKind;
|
||||
}
|
||||
|
||||
type ModuleFormat = "esm"; // later: "cjs", "iife"
|
||||
|
||||
interface BuildConfig {
|
||||
entrypoints: string[]; // list of file path
|
||||
outdir?: string; // output directory
|
||||
target?: Target; // default: "browser"
|
||||
format?: ModuleFormat; // later: "cjs", "iife"
|
||||
/**
|
||||
* Output module format. Top-level await is only supported for `"esm"`.
|
||||
*
|
||||
* Can be:
|
||||
* - `"esm"`
|
||||
* - `"cjs"` (**experimental**)
|
||||
* - `"iife"` (**experimental**)
|
||||
*
|
||||
* @default "esm"
|
||||
*/
|
||||
format?: /**
|
||||
|
||||
* ECMAScript Module format
|
||||
*/
|
||||
| "esm"
|
||||
/**
|
||||
* CommonJS format
|
||||
* **Experimental**
|
||||
*/
|
||||
| "cjs"
|
||||
/**
|
||||
* IIFE format
|
||||
* **Experimental**
|
||||
*/
|
||||
| "iife";
|
||||
naming?:
|
||||
| string
|
||||
| {
|
||||
@@ -1561,6 +1583,18 @@ declare module "bun" {
|
||||
// /** Only works when runtime=automatic */
|
||||
// importSource?: string; // default: "react"
|
||||
// };
|
||||
|
||||
/**
|
||||
* Generate bytecode for the output. This can dramatically improve cold
|
||||
* start times, but will make the final output larger and slightly increase
|
||||
* memory usage.
|
||||
*
|
||||
* Bytecode is currently only supported for CommonJS (`format: "cjs"`).
|
||||
*
|
||||
* Must be `target: "bun"`
|
||||
* @default false
|
||||
*/
|
||||
bytecode?: boolean;
|
||||
}
|
||||
|
||||
namespace Password {
|
||||
@@ -1781,7 +1815,7 @@ declare module "bun" {
|
||||
path: string;
|
||||
loader: Loader;
|
||||
hash: string | null;
|
||||
kind: "entry-point" | "chunk" | "asset" | "sourcemap";
|
||||
kind: "entry-point" | "chunk" | "asset" | "sourcemap" | "bytecode";
|
||||
sourcemap: BuildArtifact | null;
|
||||
}
|
||||
|
||||
@@ -2282,7 +2316,7 @@ declare module "bun" {
|
||||
*/
|
||||
development?: boolean;
|
||||
|
||||
error?: (this: Server, request: ErrorLike) => Response | Promise<Response> | undefined | Promise<undefined>;
|
||||
error?: (this: Server, error: ErrorLike) => Response | Promise<Response> | undefined | Promise<undefined>;
|
||||
|
||||
/**
|
||||
* Uniquely identify a server instance with an ID
|
||||
@@ -2660,7 +2694,7 @@ declare module "bun" {
|
||||
* @param closeActiveConnections Immediately terminate in-flight requests, websockets, and stop accepting new connections.
|
||||
* @default false
|
||||
*/
|
||||
stop(closeActiveConnections?: boolean): void;
|
||||
stop(closeActiveConnections?: boolean): Promise<void>;
|
||||
|
||||
/**
|
||||
* Update the `fetch` and `error` handlers without restarting the server.
|
||||
@@ -3029,6 +3063,87 @@ declare module "bun" {
|
||||
|
||||
type StringLike = string | { toString(): string };
|
||||
|
||||
type ColorInput =
|
||||
| { r: number; g: number; b: number; a?: number }
|
||||
| [number, number, number]
|
||||
| [number, number, number, number]
|
||||
| Uint8Array
|
||||
| Uint8ClampedArray
|
||||
| Float32Array
|
||||
| Float64Array
|
||||
| string
|
||||
| number
|
||||
| { toString(): string };
|
||||
|
||||
function color(
|
||||
input: ColorInput,
|
||||
outputFormat?: /**
|
||||
* True color ANSI color string, for use in terminals
|
||||
* @example \x1b[38;2;100;200;200m
|
||||
*/
|
||||
| "ansi"
|
||||
/**
|
||||
* 256 color ANSI color string, for use in terminals which don't support true color
|
||||
*
|
||||
* Tries to match closest 24-bit color to 256 color palette
|
||||
*/
|
||||
| "ansi256"
|
||||
/**
|
||||
* Lowercase hex color string without alpha
|
||||
* @example #aabb11
|
||||
*/
|
||||
| "hex"
|
||||
/**
|
||||
* RGB color string without alpha
|
||||
* rgb(100, 200, 200)
|
||||
*/
|
||||
| "rgb"
|
||||
/**
|
||||
* RGB color string with alpha
|
||||
* rgba(100, 200, 200, 0.5)
|
||||
*/
|
||||
| "rgba"
|
||||
| "hsl"
|
||||
| "lab"
|
||||
| "css"
|
||||
| "lab"
|
||||
| "HEX",
|
||||
): string | null;
|
||||
|
||||
function color(
|
||||
input: ColorInput,
|
||||
/**
|
||||
* An array of numbers representing the RGB color
|
||||
* @example [100, 200, 200]
|
||||
*/
|
||||
outputFormat: "[rgb]",
|
||||
): [number, number, number] | null;
|
||||
function color(
|
||||
input: ColorInput,
|
||||
/**
|
||||
* An array of numbers representing the RGBA color
|
||||
* @example [100, 200, 200, 255]
|
||||
*/
|
||||
outputFormat: "[rgba]",
|
||||
): [number, number, number, number] | null;
|
||||
function color(
|
||||
input: ColorInput,
|
||||
/**
|
||||
* An object representing the RGB color
|
||||
* @example { r: 100, g: 200, b: 200 }
|
||||
*/
|
||||
outputFormat: "{rgb}",
|
||||
): { r: number; g: number; b: number } | null;
|
||||
function color(
|
||||
input: ColorInput,
|
||||
/**
|
||||
* An object representing the RGBA color
|
||||
* @example { r: 100, g: 200, b: 200, a: 0.5 }
|
||||
*/
|
||||
outputFormat: "{rgba}",
|
||||
): { r: number; g: number; b: number; a: number } | null;
|
||||
function color(input: ColorInput, outputFormat: "number"): number | null;
|
||||
|
||||
interface Semver {
|
||||
/**
|
||||
* Test if the version satisfies the range. Stringifies both arguments. Returns `true` or `false`.
|
||||
@@ -3264,8 +3379,9 @@ declare module "bun" {
|
||||
* Create a new hasher
|
||||
*
|
||||
* @param algorithm The algorithm to use. See {@link algorithms} for a list of supported algorithms
|
||||
* @param hmacKey Optional key for HMAC. Must be a string or `TypedArray`. If not provided, the hasher will be a non-HMAC hasher.
|
||||
*/
|
||||
constructor(algorithm: SupportedCryptoAlgorithms);
|
||||
constructor(algorithm: SupportedCryptoAlgorithms, hmacKey?: string | NodeJS.TypedArray);
|
||||
|
||||
/**
|
||||
* Update the hash with data
|
||||
@@ -4615,6 +4731,32 @@ declare module "bun" {
|
||||
* @default cmds[0]
|
||||
*/
|
||||
argv0?: string;
|
||||
|
||||
/**
|
||||
* An {@link AbortSignal} that can be used to abort the subprocess.
|
||||
*
|
||||
* This is useful for aborting a subprocess when some other part of the
|
||||
* program is aborted, such as a `fetch` response.
|
||||
*
|
||||
* Internally, this works by calling `subprocess.kill(1)`.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const controller = new AbortController();
|
||||
* const { signal } = controller;
|
||||
* const start = performance.now();
|
||||
* const subprocess = Bun.spawn({
|
||||
* cmd: ["sleep", "100"],
|
||||
* signal,
|
||||
* });
|
||||
* await Bun.sleep(1);
|
||||
* controller.abort();
|
||||
* await subprocess.exited;
|
||||
* const end = performance.now();
|
||||
* console.log(end - start); // 1ms instead of 101ms
|
||||
* ```
|
||||
*/
|
||||
signal?: AbortSignal;
|
||||
}
|
||||
|
||||
type OptionsToSubprocess<Opts extends OptionsObject> =
|
||||
|
||||
1
packages/bun-usockets/.clang-format
Normal file
1
packages/bun-usockets/.clang-format
Normal file
@@ -0,0 +1 @@
|
||||
DisableFormat: true
|
||||
@@ -368,7 +368,7 @@ struct us_poll_t *us_poll_resize(struct us_poll_t *p, struct us_loop_t *loop, un
|
||||
return new_p;
|
||||
}
|
||||
|
||||
void us_poll_start(struct us_poll_t *p, struct us_loop_t *loop, int events) {
|
||||
int us_poll_start_rc(struct us_poll_t *p, struct us_loop_t *loop, int events) {
|
||||
p->state.poll_type = us_internal_poll_type(p) | ((events & LIBUS_SOCKET_READABLE) ? POLL_TYPE_POLLING_IN : 0) | ((events & LIBUS_SOCKET_WRITABLE) ? POLL_TYPE_POLLING_OUT : 0);
|
||||
|
||||
#ifdef LIBUS_USE_EPOLL
|
||||
@@ -379,11 +379,16 @@ void us_poll_start(struct us_poll_t *p, struct us_loop_t *loop, int events) {
|
||||
do {
|
||||
ret = epoll_ctl(loop->fd, EPOLL_CTL_ADD, p->state.fd, &event);
|
||||
} while (IS_EINTR(ret));
|
||||
return ret;
|
||||
#else
|
||||
kqueue_change(loop->fd, p->state.fd, 0, events, p);
|
||||
return kqueue_change(loop->fd, p->state.fd, 0, events, p);
|
||||
#endif
|
||||
}
|
||||
|
||||
void us_poll_start(struct us_poll_t *p, struct us_loop_t *loop, int events) {
|
||||
us_poll_start_rc(p, loop, events);
|
||||
}
|
||||
|
||||
void us_poll_change(struct us_poll_t *p, struct us_loop_t *loop, int events) {
|
||||
int old_events = us_poll_events(p);
|
||||
if (old_events != events) {
|
||||
|
||||
@@ -371,6 +371,8 @@ void us_poll_init(us_poll_r p, LIBUS_SOCKET_DESCRIPTOR fd, int poll_type);
|
||||
|
||||
/* Start, change and stop polling for events */
|
||||
void us_poll_start(us_poll_r p, us_loop_r loop, int events) nonnull_fn_decl;
|
||||
/* Returns 0 if successful */
|
||||
int us_poll_start_rc(us_poll_r p, us_loop_r loop, int events) nonnull_fn_decl;
|
||||
void us_poll_change(us_poll_r p, us_loop_r loop, int events) nonnull_fn_decl;
|
||||
void us_poll_stop(us_poll_r p, struct us_loop_t *loop) nonnull_fn_decl;
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef WIN32
|
||||
@@ -310,7 +309,11 @@ struct us_socket_t *us_socket_from_fd(struct us_socket_context_t *ctx, int socke
|
||||
#else
|
||||
struct us_poll_t *p1 = us_create_poll(ctx->loop, 0, sizeof(struct us_socket_t) + socket_ext_size);
|
||||
us_poll_init(p1, fd, POLL_TYPE_SOCKET);
|
||||
us_poll_start(p1, ctx->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE);
|
||||
int rc = us_poll_start_rc(p1, ctx->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE);
|
||||
if (rc != 0) {
|
||||
us_poll_free(p1, ctx->loop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct us_socket_t *s = (struct us_socket_t *) p1;
|
||||
s->context = ctx;
|
||||
|
||||
1
packages/bun-uws/.clang-format
Normal file
1
packages/bun-uws/.clang-format
Normal file
@@ -0,0 +1 @@
|
||||
DisableFormat: true
|
||||
13
packages/bun-vscode/.gitignore
vendored
13
packages/bun-vscode/.gitignore
vendored
@@ -1,3 +1,10 @@
|
||||
node_modules
|
||||
extension
|
||||
example/.vscode
|
||||
# Project files
|
||||
|
||||
/node_modules
|
||||
/extension
|
||||
/example/.vscode
|
||||
/.vscode-test
|
||||
|
||||
# macOS files
|
||||
|
||||
.DS_Store
|
||||
|
||||
Binary file not shown.
@@ -1,8 +0,0 @@
|
||||
console.log("HELLO");
|
||||
console.log("HELLO 2");
|
||||
console.log("HELLO 3");
|
||||
a();
|
||||
|
||||
function a() {
|
||||
console.log("HELLO 4");
|
||||
}
|
||||
7
packages/bun-vscode/example/hello.ts
Normal file
7
packages/bun-vscode/example/hello.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
type OS = "Windows";
|
||||
|
||||
Bun.serve({
|
||||
fetch(req: Request) {
|
||||
return new Response(`Hello, ${"Windows" as OS}!`);
|
||||
},
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bun-vscode",
|
||||
"version": "0.0.8",
|
||||
"version": "0.0.15",
|
||||
"author": "oven",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -8,11 +8,13 @@
|
||||
},
|
||||
"main": "dist/extension.js",
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.1.10",
|
||||
"@types/vscode": "^1.60.0",
|
||||
"@vscode/debugadapter": "^1.56.0",
|
||||
"@vscode/debugadapter-testsupport": "^1.56.0",
|
||||
"@vscode/test-cli": "^0.0.10",
|
||||
"@vscode/test-electron": "^2.4.1",
|
||||
"@vscode/vsce": "^2.20.1",
|
||||
"bun-types": "^0.7.3",
|
||||
"esbuild": "^0.19.2",
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
@@ -43,6 +45,7 @@
|
||||
"build": "node scripts/build.mjs",
|
||||
"pretest": "bun run build",
|
||||
"test": "node scripts/test.mjs",
|
||||
"dev": "vscode-test --config scripts/dev.mjs",
|
||||
"prepublish": "npm version patch && bun run build",
|
||||
"publish": "cd extension && bunx vsce publish"
|
||||
},
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { buildSync } from "esbuild";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { execSync } from "node:child_process";
|
||||
import { cpSync, mkdirSync, rmSync } from "node:fs";
|
||||
import { dirname } from "node:path";
|
||||
|
||||
const { pathname } = new URL("..", import.meta.url);
|
||||
process.chdir(pathname);
|
||||
process.chdir(dirname(import.meta.dirname));
|
||||
|
||||
buildSync({
|
||||
entryPoints: ["src/extension.ts", "src/web-extension.ts"],
|
||||
@@ -26,7 +26,7 @@ cpSync("LICENSE", "extension/LICENSE");
|
||||
cpSync("package.json", "extension/package.json");
|
||||
|
||||
const cmd = process.isBun ? "bunx" : "npx";
|
||||
spawnSync(cmd, ["vsce", "package"], {
|
||||
execSync(`${cmd} vsce package --no-dependencies`, {
|
||||
cwd: "extension",
|
||||
stdio: "inherit",
|
||||
});
|
||||
|
||||
29
packages/bun-vscode/scripts/dev.mjs
Normal file
29
packages/bun-vscode/scripts/dev.mjs
Normal file
@@ -0,0 +1,29 @@
|
||||
import { defineConfig } from "@vscode/test-cli";
|
||||
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
|
||||
const workspacePath = dirname(import.meta.dirname);
|
||||
const vscodePath = join(workspacePath, ".vscode-test");
|
||||
const vscodeTestPath = join(vscodePath, "launch.test.js");
|
||||
|
||||
if (!existsSync(vscodeTestPath)) {
|
||||
mkdirSync(vscodePath, { recursive: true });
|
||||
writeFileSync(
|
||||
vscodeTestPath,
|
||||
`// Generated by ${import.meta.filename}
|
||||
// A test that intentionally waits forever and does nothing,
|
||||
// so you can debug and test the VSCode extension in a clean environment.
|
||||
suite("VSCode extension", function () {
|
||||
this.timeout(Number.MAX_SAFE_INTEGER);
|
||||
test("wait forever", (done) => {});
|
||||
});
|
||||
`,
|
||||
);
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
workspaceFolder: join(workspacePath, "example"),
|
||||
extensionDevelopmentPath: workspacePath,
|
||||
skipExtensionDependencies: true,
|
||||
files: vscodeTestPath,
|
||||
});
|
||||
@@ -1,21 +1,21 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import { exec } from "node:child_process";
|
||||
import { readdirSync } from "node:fs";
|
||||
import { dirname } from "node:path";
|
||||
|
||||
const { pathname } = new URL("..", import.meta.url);
|
||||
process.chdir(pathname);
|
||||
process.chdir(dirname(import.meta.dirname));
|
||||
|
||||
let path;
|
||||
let extPath;
|
||||
for (const filename of readdirSync("extension")) {
|
||||
if (filename.endsWith(".vsix")) {
|
||||
path = `extension/${filename}`;
|
||||
extPath = `extension/${filename}`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!path) {
|
||||
if (!extPath) {
|
||||
throw new Error("No .vsix file found");
|
||||
}
|
||||
|
||||
spawn("code", ["--new-window", `--install-extension=${path}`, `--extensionDevelopmentPath=${pathname}`, "example"], {
|
||||
exec(`code --new-window --install-extension=${extPath} --extensionDevelopmentPath=${process.cwd()} example`, {
|
||||
stdio: "inherit",
|
||||
});
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
import { DebugSession } from "@vscode/debugadapter";
|
||||
import { tmpdir } from "node:os";
|
||||
import * as vscode from "vscode";
|
||||
import type { DAP } from "../../../bun-debug-adapter-protocol";
|
||||
import { DebugAdapter, UnixSignal } from "../../../bun-debug-adapter-protocol";
|
||||
import {
|
||||
DAP,
|
||||
DebugAdapter,
|
||||
getAvailablePort,
|
||||
getRandomId,
|
||||
TCPSocketSignal,
|
||||
UnixSignal,
|
||||
} from "../../../bun-debug-adapter-protocol";
|
||||
|
||||
export const DEBUG_CONFIGURATION: vscode.DebugConfiguration = {
|
||||
type: "bun",
|
||||
@@ -81,7 +87,7 @@ function debugFileCommand(resource?: vscode.Uri) {
|
||||
if (path) debugCommand(path);
|
||||
}
|
||||
|
||||
function injectDebugTerminal(terminal: vscode.Terminal): void {
|
||||
async function injectDebugTerminal(terminal: vscode.Terminal): Promise<void> {
|
||||
if (!getConfig("debugTerminal.enabled")) return;
|
||||
|
||||
const { name, creationOptions } = terminal;
|
||||
@@ -97,14 +103,16 @@ function injectDebugTerminal(terminal: vscode.Terminal): void {
|
||||
const stopOnEntry = getConfig("debugTerminal.stopOnEntry") === true;
|
||||
const query = stopOnEntry ? "break=1" : "wait=1";
|
||||
|
||||
const { adapter, signal } = new TerminalDebugSession();
|
||||
const debugSession = new TerminalDebugSession();
|
||||
await debugSession.initialize();
|
||||
const { adapter, signal } = debugSession;
|
||||
const debug = vscode.window.createTerminal({
|
||||
...creationOptions,
|
||||
name: "JavaScript Debug Terminal",
|
||||
env: {
|
||||
...env,
|
||||
"BUN_INSPECT": `${adapter.url}?${query}`,
|
||||
"BUN_INSPECT_NOTIFY": `${signal.url}`,
|
||||
"BUN_INSPECT_NOTIFY": signal.url,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -153,7 +161,9 @@ class DebugConfigurationProvider implements vscode.DebugConfigurationProvider {
|
||||
}
|
||||
|
||||
class InlineDebugAdapterFactory implements vscode.DebugAdapterDescriptorFactory {
|
||||
createDebugAdapterDescriptor(session: vscode.DebugSession): vscode.ProviderResult<vscode.DebugAdapterDescriptor> {
|
||||
async createDebugAdapterDescriptor(
|
||||
session: vscode.DebugSession,
|
||||
): Promise<vscode.ProviderResult<vscode.DebugAdapterDescriptor>> {
|
||||
const { configuration } = session;
|
||||
const { request, url } = configuration;
|
||||
|
||||
@@ -166,18 +176,28 @@ class InlineDebugAdapterFactory implements vscode.DebugAdapterDescriptorFactory
|
||||
}
|
||||
|
||||
const adapter = new FileDebugSession(session.id);
|
||||
await adapter.initialize();
|
||||
return new vscode.DebugAdapterInlineImplementation(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
class FileDebugSession extends DebugSession {
|
||||
readonly adapter: DebugAdapter;
|
||||
adapter: DebugAdapter;
|
||||
sessionId?: string;
|
||||
|
||||
constructor(sessionId?: string) {
|
||||
super();
|
||||
const uniqueId = sessionId ?? Math.random().toString(36).slice(2);
|
||||
const url = `ws+unix://${tmpdir()}/${uniqueId}.sock`;
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
const uniqueId = this.sessionId ?? Math.random().toString(36).slice(2);
|
||||
let url;
|
||||
if (process.platform === "win32") {
|
||||
url = `ws://127.0.0.1:${await getAvailablePort()}/${getRandomId()}`;
|
||||
} else {
|
||||
url = `ws+unix://${tmpdir()}/${uniqueId}.sock`;
|
||||
}
|
||||
this.adapter = new DebugAdapter(url);
|
||||
this.adapter.on("Adapter.response", response => this.sendResponse(response));
|
||||
this.adapter.on("Adapter.event", event => this.sendEvent(event));
|
||||
@@ -204,11 +224,19 @@ class FileDebugSession extends DebugSession {
|
||||
}
|
||||
|
||||
class TerminalDebugSession extends FileDebugSession {
|
||||
readonly signal: UnixSignal;
|
||||
signal: TCPSocketSignal | UnixSignal;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.signal = new UnixSignal();
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
await super.initialize();
|
||||
if (process.platform === "win32") {
|
||||
this.signal = new TCPSocketSignal(await getAvailablePort());
|
||||
} else {
|
||||
this.signal = new UnixSignal();
|
||||
}
|
||||
this.signal.on("Signal.received", () => {
|
||||
vscode.debug.startDebugging(undefined, {
|
||||
...ATTACH_CONFIGURATION,
|
||||
@@ -222,7 +250,7 @@ class TerminalDebugSession extends FileDebugSession {
|
||||
name: "Bun Terminal",
|
||||
env: {
|
||||
"BUN_INSPECT": `${this.adapter.url}?wait=1`,
|
||||
"BUN_INSPECT_NOTIFY": `${this.signal.url}`,
|
||||
"BUN_INSPECT_NOTIFY": this.signal.url,
|
||||
},
|
||||
isTransient: true,
|
||||
iconPath: new vscode.ThemeIcon("debug-console"),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { spawn as nodeSpawn } from "node:child_process";
|
||||
import { existsSync, readFileSync, readdirSync, mkdirSync, cpSync, chmodSync } from "node:fs";
|
||||
import { basename, join, relative, resolve } from "node:path";
|
||||
import { existsSync, readFileSync, mkdirSync, cpSync, chmodSync } from "node:fs";
|
||||
import { basename, join, resolve } from "node:path";
|
||||
|
||||
// https://cmake.org/cmake/help/latest/manual/cmake.1.html#generate-a-project-buildsystem
|
||||
const generateFlags = [
|
||||
@@ -118,26 +118,6 @@ async function build(args) {
|
||||
.flatMap(([flag, value]) => [flag, value]);
|
||||
await spawn("cmake", buildArgs, { env }, "compilation");
|
||||
|
||||
const buildFiles = ["ccache.log", "compile_commands.json"];
|
||||
const buildPaths = [buildPath, ...readdirSync(buildPath).map(path => join(buildPath, path))];
|
||||
const buildArtifacts = [];
|
||||
for (const buildPath of buildPaths) {
|
||||
for (const buildFile of buildFiles) {
|
||||
const path = join(buildPath, buildFile);
|
||||
if (existsSync(path)) {
|
||||
buildArtifacts.push(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isBuildkite()) {
|
||||
await Promise.all(
|
||||
buildArtifacts.map(path =>
|
||||
spawn("buildkite-agent", ["artifact", "upload", relative(buildPath, path)], { cwd: buildPath, env }),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
printDuration("total", Date.now() - startTime);
|
||||
}
|
||||
|
||||
|
||||
@@ -172,23 +172,16 @@ const string = bun.string;
|
||||
pub const BunInfo = struct {
|
||||
bun_version: string,
|
||||
platform: Analytics.GenerateHeader.GeneratePlatform.Platform,
|
||||
framework: string = "",
|
||||
framework_version: string = "",
|
||||
|
||||
const Analytics = @import("./analytics/analytics_thread.zig");
|
||||
const JSON = bun.JSON;
|
||||
const JSAst = bun.JSAst;
|
||||
pub fn generate(comptime Bundler: type, bundler: Bundler, allocator: std.mem.Allocator) !JSAst.Expr {
|
||||
var info = BunInfo{
|
||||
pub fn generate(comptime Bundler: type, _: Bundler, allocator: std.mem.Allocator) !JSAst.Expr {
|
||||
const info = BunInfo{
|
||||
.bun_version = Global.package_json_version,
|
||||
.platform = Analytics.GenerateHeader.GeneratePlatform.forOS(),
|
||||
};
|
||||
|
||||
if (bundler.options.framework) |framework| {
|
||||
info.framework = framework.package;
|
||||
info.framework_version = framework.version;
|
||||
}
|
||||
|
||||
return try JSON.toAST(allocator, BunInfo, info);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -75,8 +75,10 @@ pub const StandaloneModuleGraph = struct {
|
||||
name: Schema.StringPointer = .{},
|
||||
contents: Schema.StringPointer = .{},
|
||||
sourcemap: Schema.StringPointer = .{},
|
||||
bytecode: Schema.StringPointer = .{},
|
||||
encoding: Encoding = .latin1,
|
||||
loader: bun.options.Loader = .file,
|
||||
module_format: ModuleFormat = .none,
|
||||
};
|
||||
|
||||
pub const Encoding = enum(u8) {
|
||||
@@ -88,6 +90,12 @@ pub const StandaloneModuleGraph = struct {
|
||||
utf8 = 2,
|
||||
};
|
||||
|
||||
pub const ModuleFormat = enum(u8) {
|
||||
none = 0,
|
||||
esm = 1,
|
||||
cjs = 2,
|
||||
};
|
||||
|
||||
pub const File = struct {
|
||||
name: []const u8 = "",
|
||||
loader: bun.options.Loader,
|
||||
@@ -96,6 +104,8 @@ pub const StandaloneModuleGraph = struct {
|
||||
cached_blob: ?*bun.JSC.WebCore.Blob = null,
|
||||
encoding: Encoding = .binary,
|
||||
wtf_string: bun.String = bun.String.empty,
|
||||
bytecode: []u8 = "",
|
||||
module_format: ModuleFormat = .none,
|
||||
|
||||
pub fn lessThanByIndex(ctx: []const File, lhs_i: u32, rhs_i: u32) bool {
|
||||
const lhs = ctx[lhs_i];
|
||||
@@ -225,7 +235,7 @@ pub const StandaloneModuleGraph = struct {
|
||||
};
|
||||
|
||||
const modules_list_bytes = sliceTo(raw_bytes, offsets.modules_ptr);
|
||||
const modules_list = std.mem.bytesAsSlice(CompiledModuleGraphFile, modules_list_bytes);
|
||||
const modules_list: []align(1) const CompiledModuleGraphFile = std.mem.bytesAsSlice(CompiledModuleGraphFile, modules_list_bytes);
|
||||
|
||||
if (offsets.entry_point_id > modules_list.len) {
|
||||
return error.@"Corrupted module graph: entry point ID is greater than module list count";
|
||||
@@ -246,6 +256,8 @@ pub const StandaloneModuleGraph = struct {
|
||||
} }
|
||||
else
|
||||
.none,
|
||||
.bytecode = if (module.bytecode.length > 0) @constCast(sliceTo(raw_bytes, module.bytecode)) else &.{},
|
||||
.module_format = module.module_format,
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -271,14 +283,14 @@ pub const StandaloneModuleGraph = struct {
|
||||
return bytes[ptr.offset..][0..ptr.length :0];
|
||||
}
|
||||
|
||||
pub fn toBytes(allocator: std.mem.Allocator, prefix: []const u8, output_files: []const bun.options.OutputFile) ![]u8 {
|
||||
pub fn toBytes(allocator: std.mem.Allocator, prefix: []const u8, output_files: []const bun.options.OutputFile, output_format: bun.options.Format) ![]u8 {
|
||||
var serialize_trace = bun.tracy.traceNamed(@src(), "StandaloneModuleGraph.serialize");
|
||||
defer serialize_trace.end();
|
||||
|
||||
var entry_point_id: ?usize = null;
|
||||
var string_builder = bun.StringBuilder{};
|
||||
var module_count: usize = 0;
|
||||
for (output_files, 0..) |output_file, i| {
|
||||
for (output_files) |output_file| {
|
||||
string_builder.countZ(output_file.dest_path);
|
||||
string_builder.countZ(prefix);
|
||||
if (output_file.value == .buffer) {
|
||||
@@ -288,10 +300,13 @@ pub const StandaloneModuleGraph = struct {
|
||||
// the exact amount is not possible without allocating as it
|
||||
// involves a JSON parser.
|
||||
string_builder.cap += output_file.value.buffer.bytes.len * 2;
|
||||
} else if (output_file.output_kind == .bytecode) {
|
||||
// Allocate up to 256 byte alignment for bytecode
|
||||
string_builder.cap += (output_file.value.buffer.bytes.len + 255) / 256 * 256 + 256;
|
||||
} else {
|
||||
if (entry_point_id == null) {
|
||||
if (output_file.output_kind == .@"entry-point") {
|
||||
entry_point_id = i;
|
||||
entry_point_id = module_count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,7 +335,7 @@ pub const StandaloneModuleGraph = struct {
|
||||
defer source_map_arena.deinit();
|
||||
|
||||
for (output_files) |output_file| {
|
||||
if (output_file.output_kind == .sourcemap) {
|
||||
if (!output_file.output_kind.isFileInStandaloneMode()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -330,6 +345,23 @@ pub const StandaloneModuleGraph = struct {
|
||||
|
||||
const dest_path = bun.strings.removeLeadingDotSlash(output_file.dest_path);
|
||||
|
||||
const bytecode: StringPointer = brk: {
|
||||
if (output_file.bytecode_index != std.math.maxInt(u32)) {
|
||||
// Use up to 256 byte alignment for bytecode
|
||||
// Not aligning it correctly will cause a runtime assertion error, or a segfault.
|
||||
const bytecode = output_files[output_file.bytecode_index].value.buffer.bytes;
|
||||
const aligned = std.mem.alignInSlice(string_builder.writable(), 128).?;
|
||||
@memcpy(aligned[0..bytecode.len], bytecode[0..bytecode.len]);
|
||||
const unaligned_space = aligned[bytecode.len..];
|
||||
const offset = @intFromPtr(aligned.ptr) - @intFromPtr(string_builder.ptr.?);
|
||||
const len = bytecode.len + @min(unaligned_space.len, 128);
|
||||
string_builder.len += len;
|
||||
break :brk StringPointer{ .offset = @truncate(offset), .length = @truncate(len) };
|
||||
} else {
|
||||
break :brk .{};
|
||||
}
|
||||
};
|
||||
|
||||
var module = CompiledModuleGraphFile{
|
||||
.name = string_builder.fmtAppendCountZ("{s}{s}", .{
|
||||
prefix,
|
||||
@@ -341,7 +373,14 @@ pub const StandaloneModuleGraph = struct {
|
||||
.js, .jsx, .ts, .tsx => .latin1,
|
||||
else => .binary,
|
||||
},
|
||||
.module_format = if (output_file.loader.isJavaScriptLike()) switch (output_format) {
|
||||
.cjs => .cjs,
|
||||
.esm => .esm,
|
||||
else => .none,
|
||||
} else .none,
|
||||
.bytecode = bytecode,
|
||||
};
|
||||
|
||||
if (output_file.source_map_index != std.math.maxInt(u32)) {
|
||||
defer source_map_header_list.clearRetainingCapacity();
|
||||
defer source_map_string_list.clearRetainingCapacity();
|
||||
@@ -619,8 +658,9 @@ pub const StandaloneModuleGraph = struct {
|
||||
module_prefix: []const u8,
|
||||
outfile: []const u8,
|
||||
env: *bun.DotEnv.Loader,
|
||||
output_format: bun.options.Format,
|
||||
) !void {
|
||||
const bytes = try toBytes(allocator, module_prefix, output_files);
|
||||
const bytes = try toBytes(allocator, module_prefix, output_files, output_format);
|
||||
if (bytes.len == 0) return;
|
||||
|
||||
const fd = inject(
|
||||
@@ -999,7 +1039,7 @@ pub const StandaloneModuleGraph = struct {
|
||||
bun.JSAst.Expr.Data.Store.reset();
|
||||
bun.JSAst.Stmt.Data.Store.reset();
|
||||
}
|
||||
var json = bun.JSON.ParseJSON(&json_src, &log, arena) catch
|
||||
var json = bun.JSON.ParseJSON(&json_src, &log, arena, false) catch
|
||||
return error.InvalidSourceMap;
|
||||
|
||||
const mappings_str = json.get("mappings") orelse
|
||||
|
||||
@@ -79,41 +79,44 @@ pub fn isCI() bool {
|
||||
|
||||
/// This answers, "What parts of bun are people actually using?"
|
||||
pub const Features = struct {
|
||||
/// Set right before JSC::initialize is called
|
||||
pub var jsc: usize = 0;
|
||||
pub var builtin_modules = std.enums.EnumSet(bun.JSC.HardcodedModule).initEmpty();
|
||||
|
||||
pub var @"Bun.stderr": usize = 0;
|
||||
pub var @"Bun.stdin": usize = 0;
|
||||
pub var @"Bun.stdout": usize = 0;
|
||||
pub var WebSocket: usize = 0;
|
||||
pub var abort_signal: usize = 0;
|
||||
pub var binlinks: usize = 0;
|
||||
pub var bunfig: usize = 0;
|
||||
pub var define: usize = 0;
|
||||
pub var dotenv: usize = 0;
|
||||
pub var external: usize = 0;
|
||||
pub var extracted_packages: usize = 0;
|
||||
/// Incremented for each call to `fetch`
|
||||
pub var fetch: usize = 0;
|
||||
pub var filesystem_router: usize = 0;
|
||||
pub var git_dependencies: usize = 0;
|
||||
pub var html_rewriter: usize = 0;
|
||||
pub var http_server: usize = 0;
|
||||
pub var https_server: usize = 0;
|
||||
/// Set right before JSC::initialize is called
|
||||
pub var jsc: usize = 0;
|
||||
/// Set when kit.DevServer is initialized
|
||||
pub var kit_dev: usize = 0;
|
||||
pub var lifecycle_scripts: usize = 0;
|
||||
pub var loaders: usize = 0;
|
||||
pub var lockfile_migration_from_package_lock: usize = 0;
|
||||
pub var macros: usize = 0;
|
||||
pub var no_avx2: usize = 0;
|
||||
pub var no_avx: usize = 0;
|
||||
pub var shell: usize = 0;
|
||||
pub var spawn: usize = 0;
|
||||
pub var standalone_shell: usize = 0;
|
||||
pub var transpiler_cache: usize = 0;
|
||||
pub var tsconfig_paths: usize = 0;
|
||||
pub var tsconfig: usize = 0;
|
||||
pub var virtual_modules: usize = 0;
|
||||
pub var WebSocket: usize = 0;
|
||||
pub var no_avx: usize = 0;
|
||||
pub var no_avx2: usize = 0;
|
||||
pub var binlinks: usize = 0;
|
||||
pub var builtin_modules = std.enums.EnumSet(bun.JSC.HardcodedModule).initEmpty();
|
||||
pub var standalone_executable: usize = 0;
|
||||
pub var standalone_shell: usize = 0;
|
||||
/// Set when invoking a todo panic
|
||||
pub var todo_panic: usize = 0;
|
||||
pub var transpiler_cache: usize = 0;
|
||||
pub var tsconfig: usize = 0;
|
||||
pub var tsconfig_paths: usize = 0;
|
||||
pub var virtual_modules: usize = 0;
|
||||
pub var workers_spawned: usize = 0;
|
||||
pub var workers_terminated: usize = 0;
|
||||
|
||||
|
||||
@@ -1671,12 +1671,6 @@ pub const Api = struct {
|
||||
/// extension_order
|
||||
extension_order: []const []const u8,
|
||||
|
||||
/// framework
|
||||
framework: ?FrameworkConfig = null,
|
||||
|
||||
/// router
|
||||
router: ?RouteConfig = null,
|
||||
|
||||
/// no_summary
|
||||
no_summary: ?bool = null,
|
||||
|
||||
|
||||
@@ -48,6 +48,9 @@ pub const Index = packed struct(u32) {
|
||||
pub const invalid = Index{ .value = std.math.maxInt(Int) };
|
||||
pub const runtime = Index{ .value = 0 };
|
||||
|
||||
pub const kit_server_data = Index{ .value = 1 };
|
||||
pub const kit_client_data = Index{ .value = 2 };
|
||||
|
||||
pub const Int = u32;
|
||||
|
||||
pub inline fn source(num: anytype) Index {
|
||||
@@ -229,6 +232,8 @@ pub const Ref = packed struct(u64) {
|
||||
*const std.ArrayList(js_ast.Symbol) => symbol_table.items,
|
||||
*std.ArrayList(js_ast.Symbol) => symbol_table.items,
|
||||
[]js_ast.Symbol => symbol_table,
|
||||
*js_ast.Symbol.Map => return symbol_table.get(ref) orelse
|
||||
unreachable, // ref must exist within symbol table
|
||||
else => |T| @compileError("Unsupported type to Ref.getSymbol: " ++ @typeName(T)),
|
||||
};
|
||||
return &resolved_symbol_table[ref.innerIndex()];
|
||||
|
||||
@@ -45,7 +45,7 @@ pub fn BabyList(comptime Type: type) type {
|
||||
return this.len > 0 and @intFromPtr(item.ptr) >= @intFromPtr(this.ptr) and @intFromPtr(item.ptr) < @intFromPtr(this.ptr) + this.len;
|
||||
}
|
||||
|
||||
pub inline fn initConst(items: []const Type) ListType {
|
||||
pub fn initConst(items: []const Type) callconv(bun.callconv_inline) ListType {
|
||||
@setRuntimeSafety(false);
|
||||
return ListType{
|
||||
// Remove the const qualifier from the items
|
||||
@@ -204,24 +204,24 @@ pub fn BabyList(comptime Type: type) type {
|
||||
};
|
||||
}
|
||||
|
||||
pub inline fn first(this: ListType) ?*Type {
|
||||
pub fn first(this: ListType) callconv(bun.callconv_inline) ?*Type {
|
||||
return if (this.len > 0) this.ptr[0] else @as(?*Type, null);
|
||||
}
|
||||
|
||||
pub inline fn last(this: ListType) ?*Type {
|
||||
pub fn last(this: ListType) callconv(bun.callconv_inline) ?*Type {
|
||||
return if (this.len > 0) &this.ptr[this.len - 1] else @as(?*Type, null);
|
||||
}
|
||||
|
||||
pub inline fn first_(this: ListType) Type {
|
||||
pub fn first_(this: ListType) callconv(bun.callconv_inline) Type {
|
||||
return this.ptr[0];
|
||||
}
|
||||
|
||||
pub inline fn at(this: ListType, index: usize) *const Type {
|
||||
pub fn at(this: ListType, index: usize) callconv(bun.callconv_inline) *const Type {
|
||||
bun.assert(index < this.len);
|
||||
return &this.ptr[index];
|
||||
}
|
||||
|
||||
pub inline fn mut(this: ListType, index: usize) *Type {
|
||||
pub fn mut(this: ListType, index: usize) callconv(bun.callconv_inline) *Type {
|
||||
bun.assert(index < this.len);
|
||||
return &this.ptr[index];
|
||||
}
|
||||
@@ -236,7 +236,7 @@ pub fn BabyList(comptime Type: type) type {
|
||||
};
|
||||
}
|
||||
|
||||
pub inline fn @"[0]"(this: ListType) Type {
|
||||
pub fn @"[0]"(this: ListType) callconv(bun.callconv_inline) Type {
|
||||
return this.ptr[0];
|
||||
}
|
||||
const OOM = error{OutOfMemory};
|
||||
@@ -259,7 +259,7 @@ pub fn BabyList(comptime Type: type) type {
|
||||
this.update(list__);
|
||||
}
|
||||
|
||||
pub inline fn slice(this: ListType) []Type {
|
||||
pub fn slice(this: ListType) callconv(bun.callconv_inline) []Type {
|
||||
@setRuntimeSafety(false);
|
||||
return this.ptr[0..this.len];
|
||||
}
|
||||
@@ -273,6 +273,7 @@ pub fn BabyList(comptime Type: type) type {
|
||||
this.update(list_);
|
||||
return this.len - initial;
|
||||
}
|
||||
|
||||
pub fn writeLatin1(this: *@This(), allocator: std.mem.Allocator, str: []const u8) !u32 {
|
||||
if (comptime Type != u8)
|
||||
@compileError("Unsupported for type " ++ @typeName(Type));
|
||||
@@ -282,6 +283,7 @@ pub fn BabyList(comptime Type: type) type {
|
||||
this.update(new);
|
||||
return this.len - initial;
|
||||
}
|
||||
|
||||
pub fn writeUTF16(this: *@This(), allocator: std.mem.Allocator, str: []const u16) !u32 {
|
||||
if (comptime Type != u8)
|
||||
@compileError("Unsupported for type " ++ @typeName(Type));
|
||||
|
||||
62
src/bitflags.zig
Normal file
62
src/bitflags.zig
Normal file
@@ -0,0 +1,62 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn Bitflags(comptime T: type) type {
|
||||
const tyinfo = @typeInfo(T);
|
||||
const IntType = tyinfo.Struct.backing_integer.?;
|
||||
|
||||
return struct {
|
||||
pub inline fn empty() T {
|
||||
return @bitCast(@as(IntType, 0));
|
||||
}
|
||||
|
||||
pub inline fn intersects(lhs: T, rhs: T) bool {
|
||||
return asBits(lhs) & asBits(rhs) != 0;
|
||||
}
|
||||
|
||||
pub inline fn fromName(comptime name: []const u8) T {
|
||||
var this: T = .{};
|
||||
@field(this, name) = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
pub inline fn fromNames(comptime names: []const []const u8) T {
|
||||
var this: T = .{};
|
||||
inline for (names) |name| {
|
||||
@field(this, name) = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
pub fn bitwiseOr(lhs: T, rhs: T) T {
|
||||
return @bitCast(@as(IntType, @bitCast(lhs)) | @as(IntType, @bitCast(rhs)));
|
||||
}
|
||||
|
||||
pub fn bitwiseAnd(lhs: T, rhs: T) T {
|
||||
return @bitCast(@as(IntType, asBits(lhs) & asBits(rhs)));
|
||||
}
|
||||
|
||||
pub inline fn insert(this: *T, other: T) void {
|
||||
this.* = bitwiseOr(this.*, other);
|
||||
}
|
||||
|
||||
pub fn contains(lhs: T, rhs: T) bool {
|
||||
return @as(IntType, @bitCast(lhs)) & @as(IntType, @bitCast(rhs)) != 0;
|
||||
}
|
||||
|
||||
pub inline fn asBits(this: T) IntType {
|
||||
return @as(IntType, @bitCast(this));
|
||||
}
|
||||
|
||||
pub fn isEmpty(this: T) bool {
|
||||
return asBits(this) == 0;
|
||||
}
|
||||
|
||||
pub fn eq(lhs: T, rhs: T) bool {
|
||||
return asBits(lhs) == asBits(rhs);
|
||||
}
|
||||
|
||||
pub fn neq(lhs: T, rhs: T) bool {
|
||||
return asBits(lhs) != asBits(rhs);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -9,7 +9,7 @@ const BrotliEncoder = c.BrotliEncoder;
|
||||
|
||||
const mimalloc = bun.Mimalloc;
|
||||
|
||||
const BrotliAllocator = struct {
|
||||
pub const BrotliAllocator = struct {
|
||||
pub fn alloc(_: ?*anyopaque, len: usize) callconv(.C) *anyopaque {
|
||||
if (bun.heap_breakdown.enabled) {
|
||||
const zone = bun.heap_breakdown.getZone("brotli");
|
||||
|
||||
@@ -1118,7 +1118,7 @@ pub const Formatter = struct {
|
||||
|
||||
// Is this a react element?
|
||||
if (js_type.isObject()) {
|
||||
if (value.get(globalThis, "$$typeof")) |typeof_symbol| {
|
||||
if (value.getOwnTruthy(globalThis, "$$typeof")) |typeof_symbol| {
|
||||
var reactElement = ZigString.init("react.element");
|
||||
var react_fragment = ZigString.init("react.fragment");
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
/// Version 4: TypeScript enums are properly handled + more constant folding
|
||||
/// Version 5: `require.main === module` no longer marks a module as CJS
|
||||
/// Version 6: `use strict` is preserved in CommonJS modules when at the top of the file
|
||||
const expected_version = 6;
|
||||
/// Version 7: Several bundler changes that are likely to impact the runtime as well.
|
||||
const expected_version = 7;
|
||||
|
||||
const bun = @import("root").bun;
|
||||
const std = @import("std");
|
||||
|
||||
@@ -42,6 +42,7 @@ pub const BunObject = struct {
|
||||
pub const shellEscape = toJSCallback(Bun.shellEscape);
|
||||
pub const createParsedShellScript = toJSCallback(bun.shell.ParsedShellScript.createParsedShellScript);
|
||||
pub const createShellInterpreter = toJSCallback(bun.shell.Interpreter.createShellInterpreter);
|
||||
pub const color = bun.css.CssColor.jsFunctionColor;
|
||||
// --- Callbacks ---
|
||||
|
||||
// --- Getters ---
|
||||
@@ -60,7 +61,6 @@ pub const BunObject = struct {
|
||||
pub const Glob = toJSGetter(Bun.getGlobConstructor);
|
||||
pub const Transpiler = toJSGetter(Bun.getTranspilerConstructor);
|
||||
pub const argv = toJSGetter(Bun.getArgv);
|
||||
pub const assetPrefix = toJSGetter(Bun.getAssetPrefix);
|
||||
pub const cwd = toJSGetter(Bun.getCWD);
|
||||
pub const enableANSIColors = toJSGetter(Bun.enableANSIColors);
|
||||
pub const hash = toJSGetter(Bun.getHashObject);
|
||||
@@ -120,7 +120,6 @@ pub const BunObject = struct {
|
||||
@export(BunObject.Glob, .{ .name = getterName("Glob") });
|
||||
@export(BunObject.Transpiler, .{ .name = getterName("Transpiler") });
|
||||
@export(BunObject.argv, .{ .name = getterName("argv") });
|
||||
@export(BunObject.assetPrefix, .{ .name = getterName("assetPrefix") });
|
||||
@export(BunObject.cwd, .{ .name = getterName("cwd") });
|
||||
@export(BunObject.enableANSIColors, .{ .name = getterName("enableANSIColors") });
|
||||
@export(BunObject.hash, .{ .name = getterName("hash") });
|
||||
@@ -136,12 +135,13 @@ pub const BunObject = struct {
|
||||
// --- Getters --
|
||||
|
||||
// -- Callbacks --
|
||||
@export(BunObject.createParsedShellScript, .{ .name = callbackName("createParsedShellScript") });
|
||||
@export(BunObject.createShellInterpreter, .{ .name = callbackName("createShellInterpreter") });
|
||||
@export(BunObject.allocUnsafe, .{ .name = callbackName("allocUnsafe") });
|
||||
@export(BunObject.braces, .{ .name = callbackName("braces") });
|
||||
@export(BunObject.build, .{ .name = callbackName("build") });
|
||||
@export(BunObject.color, .{ .name = callbackName("color") });
|
||||
@export(BunObject.connect, .{ .name = callbackName("connect") });
|
||||
@export(BunObject.createParsedShellScript, .{ .name = callbackName("createParsedShellScript") });
|
||||
@export(BunObject.createShellInterpreter, .{ .name = callbackName("createShellInterpreter") });
|
||||
@export(BunObject.deflateSync, .{ .name = callbackName("deflateSync") });
|
||||
@export(BunObject.file, .{ .name = callbackName("file") });
|
||||
@export(BunObject.gc, .{ .name = callbackName("gc") });
|
||||
@@ -152,7 +152,6 @@ pub const BunObject = struct {
|
||||
@export(BunObject.inflateSync, .{ .name = callbackName("inflateSync") });
|
||||
@export(BunObject.jest, .{ .name = callbackName("jest") });
|
||||
@export(BunObject.listen, .{ .name = callbackName("listen") });
|
||||
@export(BunObject.udpSocket, .{ .name = callbackName("udpSocket") });
|
||||
@export(BunObject.mmap, .{ .name = callbackName("mmap") });
|
||||
@export(BunObject.nanoseconds, .{ .name = callbackName("nanoseconds") });
|
||||
@export(BunObject.openInEditor, .{ .name = callbackName("openInEditor") });
|
||||
@@ -161,14 +160,15 @@ pub const BunObject = struct {
|
||||
@export(BunObject.resolveSync, .{ .name = callbackName("resolveSync") });
|
||||
@export(BunObject.serve, .{ .name = callbackName("serve") });
|
||||
@export(BunObject.sha, .{ .name = callbackName("sha") });
|
||||
@export(BunObject.shellEscape, .{ .name = callbackName("shellEscape") });
|
||||
@export(BunObject.shrink, .{ .name = callbackName("shrink") });
|
||||
@export(BunObject.sleepSync, .{ .name = callbackName("sleepSync") });
|
||||
@export(BunObject.spawn, .{ .name = callbackName("spawn") });
|
||||
@export(BunObject.spawnSync, .{ .name = callbackName("spawnSync") });
|
||||
@export(BunObject.stringWidth, .{ .name = callbackName("stringWidth") });
|
||||
@export(BunObject.udpSocket, .{ .name = callbackName("udpSocket") });
|
||||
@export(BunObject.which, .{ .name = callbackName("which") });
|
||||
@export(BunObject.write, .{ .name = callbackName("write") });
|
||||
@export(BunObject.stringWidth, .{ .name = callbackName("stringWidth") });
|
||||
@export(BunObject.shellEscape, .{ .name = callbackName("shellEscape") });
|
||||
// -- Callbacks --
|
||||
}
|
||||
};
|
||||
@@ -252,161 +252,13 @@ const zlib = @import("../../zlib.zig");
|
||||
const Which = @import("../../which.zig");
|
||||
const ErrorableString = JSC.ErrorableString;
|
||||
const is_bindgen = JSC.is_bindgen;
|
||||
const max_addressible_memory = std.math.maxInt(u56);
|
||||
const max_addressable_memory = std.math.maxInt(u56);
|
||||
const glob = @import("../../glob.zig");
|
||||
const Async = bun.Async;
|
||||
const SemverObject = @import("../../install/semver.zig").SemverObject;
|
||||
const Braces = @import("../../shell/braces.zig");
|
||||
const Shell = @import("../../shell/shell.zig");
|
||||
|
||||
threadlocal var css_imports_list_strings: [512]ZigString = undefined;
|
||||
threadlocal var css_imports_list: [512]Api.StringPointer = undefined;
|
||||
threadlocal var css_imports_list_tail: u16 = 0;
|
||||
threadlocal var css_imports_buf: std.ArrayList(u8) = undefined;
|
||||
threadlocal var css_imports_buf_loaded: bool = false;
|
||||
|
||||
threadlocal var routes_list_strings: [1024]ZigString = undefined;
|
||||
|
||||
pub fn onImportCSS(
|
||||
resolve_result: *const Resolver.Result,
|
||||
import_record: *ImportRecord,
|
||||
origin: URL,
|
||||
) void {
|
||||
if (!css_imports_buf_loaded) {
|
||||
css_imports_buf = std.ArrayList(u8).initCapacity(
|
||||
VirtualMachine.get().allocator,
|
||||
import_record.path.text.len,
|
||||
) catch unreachable;
|
||||
css_imports_buf_loaded = true;
|
||||
}
|
||||
|
||||
const writer = css_imports_buf.writer();
|
||||
const offset = css_imports_buf.items.len;
|
||||
css_imports_list[css_imports_list_tail] = .{
|
||||
.offset = @as(u32, @truncate(offset)),
|
||||
.length = 0,
|
||||
};
|
||||
getPublicPath(resolve_result.path_pair.primary.text, origin, @TypeOf(writer), writer);
|
||||
const length = css_imports_buf.items.len - offset;
|
||||
css_imports_list[css_imports_list_tail].length = @as(u32, @truncate(length));
|
||||
css_imports_list_tail += 1;
|
||||
}
|
||||
|
||||
pub fn flushCSSImports() void {
|
||||
if (css_imports_buf_loaded) {
|
||||
css_imports_buf.clearRetainingCapacity();
|
||||
css_imports_list_tail = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getCSSImports() []ZigString {
|
||||
const tail = css_imports_list_tail;
|
||||
for (0..tail) |i| {
|
||||
ZigString.fromStringPointer(css_imports_list[i], css_imports_buf.items, &css_imports_list_strings[i]);
|
||||
}
|
||||
return css_imports_list_strings[0..tail];
|
||||
}
|
||||
|
||||
const ShellTask = struct {
|
||||
arena: std.heap.Arena,
|
||||
script: std.ArrayList(u8),
|
||||
interpreter: Shell.InterpreterSync,
|
||||
|
||||
pub const AsyncShellTask = JSC.ConcurrentPromiseTask(ShellTask);
|
||||
};
|
||||
|
||||
pub fn shell(
|
||||
globalThis: *JSC.JSGlobalObject,
|
||||
callframe: *JSC.CallFrame,
|
||||
) JSC.JSValue {
|
||||
const Interpreter = @import("../../shell/interpreter.zig").Interpreter;
|
||||
|
||||
// var allocator = globalThis.bunVM().allocator;
|
||||
const allocator = getAllocator(globalThis);
|
||||
var arena = bun.ArenaAllocator.init(allocator);
|
||||
|
||||
const arguments_ = callframe.arguments(8);
|
||||
var arguments = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments_.slice());
|
||||
const string_args = arguments.nextEat() orelse {
|
||||
globalThis.throw("shell: expected 2 arguments, got 0", .{});
|
||||
return .undefined;
|
||||
};
|
||||
|
||||
const template_args_js = arguments.nextEat() orelse {
|
||||
globalThis.throw("shell: expected 2 arguments, got 0", .{});
|
||||
return .undefined;
|
||||
};
|
||||
var template_args = template_args_js.arrayIterator(globalThis);
|
||||
var jsobjs = std.ArrayList(JSValue).init(arena.allocator());
|
||||
var script = std.ArrayList(u8).init(arena.allocator());
|
||||
|
||||
if (!(bun.shell.shellCmdFromJS(globalThis, string_args, &template_args, &jsobjs, &script) catch {
|
||||
if (!globalThis.hasException())
|
||||
globalThis.throwOutOfMemory();
|
||||
return JSValue.undefined;
|
||||
})) {
|
||||
return .undefined;
|
||||
}
|
||||
|
||||
if (globalThis.hasException()) {
|
||||
arena.deinit();
|
||||
return .undefined;
|
||||
}
|
||||
|
||||
const lex_result = brk: {
|
||||
if (bun.strings.isAllASCII(script.items[0..])) {
|
||||
var lexer = Shell.LexerAscii.new(arena.allocator(), script.items[0..]);
|
||||
lexer.lex() catch |err| {
|
||||
globalThis.throwError(err, "failed to lex shell");
|
||||
return JSValue.undefined;
|
||||
};
|
||||
break :brk lexer.get_result();
|
||||
}
|
||||
var lexer = Shell.LexerUnicode.new(arena.allocator(), script.items[0..]);
|
||||
lexer.lex() catch |err| {
|
||||
globalThis.throwError(err, "failed to lex shell");
|
||||
return JSValue.undefined;
|
||||
};
|
||||
break :brk lexer.get_result();
|
||||
};
|
||||
|
||||
var parser = Shell.Parser.new(arena.allocator(), lex_result, jsobjs.items[0..]) catch |err| {
|
||||
globalThis.throwError(err, "failed to create shell parser");
|
||||
return JSValue.undefined;
|
||||
};
|
||||
|
||||
const script_ast = parser.parse() catch |err| {
|
||||
globalThis.throwError(err, "failed to parse shell");
|
||||
return JSValue.undefined;
|
||||
};
|
||||
|
||||
const script_heap = arena.allocator().create(Shell.AST.Script) catch {
|
||||
globalThis.throwOutOfMemory();
|
||||
return JSValue.undefined;
|
||||
};
|
||||
|
||||
script_heap.* = script_ast;
|
||||
|
||||
const interpreter = Interpreter.init(
|
||||
globalThis,
|
||||
allocator,
|
||||
&arena,
|
||||
script_heap,
|
||||
jsobjs.items[0..],
|
||||
) catch {
|
||||
arena.deinit();
|
||||
return .false;
|
||||
};
|
||||
_ = interpreter; // autofix
|
||||
|
||||
// return interpreter;
|
||||
return .undefined;
|
||||
|
||||
// return interpreter.start(globalThis) catch {
|
||||
// return .false;
|
||||
// };
|
||||
}
|
||||
|
||||
pub fn shellEscape(
|
||||
globalThis: *JSC.JSGlobalObject,
|
||||
callframe: *JSC.CallFrame,
|
||||
@@ -435,7 +287,8 @@ pub fn shellEscape(
|
||||
globalThis.throw("String has invalid utf-16: {s}", .{bunstr.byteSlice()});
|
||||
return .undefined;
|
||||
}
|
||||
return bun.String.createUTF8(outbuf.items[0..]).toJS(globalThis);
|
||||
var str = bun.String.createUTF8(outbuf.items[0..]);
|
||||
return str.transferToJS(globalThis);
|
||||
}
|
||||
return jsval;
|
||||
}
|
||||
@@ -445,7 +298,8 @@ pub fn shellEscape(
|
||||
globalThis.throwOutOfMemory();
|
||||
return .undefined;
|
||||
};
|
||||
return bun.String.createUTF8(outbuf.items[0..]).toJS(globalThis);
|
||||
var str = bun.String.createUTF8(outbuf.items[0..]);
|
||||
return str.transferToJS(globalThis);
|
||||
}
|
||||
|
||||
return jsval;
|
||||
@@ -475,11 +329,11 @@ pub fn braces(
|
||||
if (arguments.nextEat()) |opts_val| {
|
||||
if (opts_val.isObject()) {
|
||||
if (comptime bun.Environment.allow_assert) {
|
||||
if (opts_val.getTruthy(globalThis, "tokenize")) |tokenize_val| {
|
||||
if (opts_val.getOwnTruthy(globalThis, "tokenize")) |tokenize_val| {
|
||||
tokenize = if (tokenize_val.isBoolean()) tokenize_val.asBoolean() else false;
|
||||
}
|
||||
|
||||
if (opts_val.getTruthy(globalThis, "parse")) |tokenize_val| {
|
||||
if (opts_val.getOwnTruthy(globalThis, "parse")) |tokenize_val| {
|
||||
parse = if (tokenize_val.isBoolean()) tokenize_val.asBoolean() else false;
|
||||
}
|
||||
}
|
||||
@@ -607,11 +461,11 @@ pub fn which(
|
||||
|
||||
if (arguments.nextEat()) |arg| {
|
||||
if (!arg.isEmptyOrUndefinedOrNull() and arg.isObject()) {
|
||||
if (arg.get(globalThis, "PATH")) |str_| {
|
||||
if (arg.getOwn(globalThis, "PATH")) |str_| {
|
||||
path_str = str_.toSlice(globalThis, globalThis.bunVM().allocator);
|
||||
}
|
||||
|
||||
if (arg.get(globalThis, "cwd")) |str_| {
|
||||
if (arg.getOwn(globalThis, "cwd")) |str_| {
|
||||
cwd_str = str_.toSlice(globalThis, globalThis.bunVM().allocator);
|
||||
}
|
||||
}
|
||||
@@ -660,7 +514,7 @@ pub fn inspect(
|
||||
const arg1 = arguments[1];
|
||||
|
||||
if (arg1.isObject()) {
|
||||
if (arg1.getTruthy(globalThis, "depth")) |opt| {
|
||||
if (arg1.getOwnTruthy(globalThis, "depth")) |opt| {
|
||||
if (opt.isInt32()) {
|
||||
const arg = opt.toInt32();
|
||||
if (arg < 0) {
|
||||
@@ -898,13 +752,6 @@ pub fn getMain(
|
||||
return ZigString.init(vm.main).toJS(globalThis);
|
||||
}
|
||||
|
||||
pub fn getAssetPrefix(
|
||||
globalThis: *JSC.JSGlobalObject,
|
||||
_: *JSC.JSObject,
|
||||
) JSC.JSValue {
|
||||
return ZigString.init(VirtualMachine.get().bundler.options.routes.asset_prefix_path).toJS(globalThis);
|
||||
}
|
||||
|
||||
pub fn getArgv(
|
||||
globalThis: *JSC.JSGlobalObject,
|
||||
_: *JSC.JSObject,
|
||||
@@ -932,7 +779,7 @@ pub fn openInEditor(
|
||||
|
||||
if (arguments.nextEat()) |opts| {
|
||||
if (!opts.isUndefinedOrNull()) {
|
||||
if (opts.getTruthy(globalThis, "editor")) |editor_val| {
|
||||
if (opts.getOwnTruthy(globalThis, "editor")) |editor_val| {
|
||||
var sliced = editor_val.toSlice(globalThis, arguments.arena.allocator());
|
||||
const prev_name = edit.name;
|
||||
|
||||
@@ -952,11 +799,11 @@ pub fn openInEditor(
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.getTruthy(globalThis, "line")) |line_| {
|
||||
if (opts.getOwnTruthy(globalThis, "line")) |line_| {
|
||||
line = line_.toSlice(globalThis, arguments.arena.allocator()).slice();
|
||||
}
|
||||
|
||||
if (opts.getTruthy(globalThis, "column")) |column_| {
|
||||
if (opts.getOwnTruthy(globalThis, "column")) |column_| {
|
||||
column = column_.toSlice(globalThis, arguments.arena.allocator()).slice();
|
||||
}
|
||||
}
|
||||
@@ -990,7 +837,7 @@ pub fn getPublicPath(to: string, origin: URL, comptime Writer: type, writer: Wri
|
||||
to,
|
||||
VirtualMachine.get().bundler.fs.top_level_dir,
|
||||
origin,
|
||||
VirtualMachine.get().bundler.options.routes.asset_prefix_path,
|
||||
"",
|
||||
comptime Writer,
|
||||
writer,
|
||||
.loose,
|
||||
@@ -1282,22 +1129,6 @@ export fn Bun__resolveSyncWithSource(
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getPublicPathJS(globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue {
|
||||
const arguments = callframe.arguments(1).slice();
|
||||
if (arguments.len < 1) {
|
||||
return bun.String.empty.toJS(globalObject);
|
||||
}
|
||||
var public_path_temp_str: bun.PathBuffer = undefined;
|
||||
|
||||
const to = arguments[0].toSlice(globalObject, bun.default_allocator);
|
||||
defer to.deinit();
|
||||
var stream = std.io.fixedBufferStream(&public_path_temp_str);
|
||||
var writer = stream.writer();
|
||||
getPublicPath(to.slice(), VirtualMachine.get().origin, @TypeOf(&writer), &writer);
|
||||
|
||||
return ZigString.init(stream.buffer[0..stream.pos]).toJS(globalObject);
|
||||
}
|
||||
|
||||
extern fn dump_zone_malloc_stats() void;
|
||||
|
||||
fn dump_mimalloc(globalObject: *JSC.JSGlobalObject, _: *JSC.CallFrame) JSC.JSValue {
|
||||
@@ -1359,6 +1190,58 @@ pub const Crypto = struct {
|
||||
const Hashers = @import("../../sha.zig");
|
||||
|
||||
const BoringSSL = bun.BoringSSL;
|
||||
pub const HMAC = struct {
|
||||
ctx: BoringSSL.HMAC_CTX,
|
||||
algorithm: EVP.Algorithm,
|
||||
|
||||
pub usingnamespace bun.New(@This());
|
||||
|
||||
pub fn init(algorithm: EVP.Algorithm, key: []const u8) ?*HMAC {
|
||||
var ctx: BoringSSL.HMAC_CTX = undefined;
|
||||
BoringSSL.HMAC_CTX_init(&ctx);
|
||||
if (BoringSSL.HMAC_Init_ex(&ctx, key.ptr, @intCast(key.len), algorithm.md(), null) != 1) {
|
||||
BoringSSL.HMAC_CTX_cleanup(&ctx);
|
||||
return null;
|
||||
}
|
||||
return HMAC.new(.{
|
||||
.ctx = ctx,
|
||||
.algorithm = algorithm,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn update(this: *HMAC, data: []const u8) void {
|
||||
_ = BoringSSL.HMAC_Update(&this.ctx, data.ptr, data.len);
|
||||
}
|
||||
|
||||
pub fn size(this: *const HMAC) usize {
|
||||
return BoringSSL.HMAC_size(&this.ctx);
|
||||
}
|
||||
|
||||
pub fn copy(this: *HMAC) !*HMAC {
|
||||
var ctx: BoringSSL.HMAC_CTX = undefined;
|
||||
BoringSSL.HMAC_CTX_init(&ctx);
|
||||
if (BoringSSL.HMAC_CTX_copy(&ctx, &this.ctx) != 1) {
|
||||
BoringSSL.HMAC_CTX_cleanup(&ctx);
|
||||
return error.BoringSSLError;
|
||||
}
|
||||
return HMAC.new(.{
|
||||
.ctx = ctx,
|
||||
.algorithm = this.algorithm,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn final(this: *HMAC, out: []u8) []u8 {
|
||||
var outlen: c_uint = undefined;
|
||||
_ = BoringSSL.HMAC_Final(&this.ctx, out.ptr, &outlen);
|
||||
return out[0..outlen];
|
||||
}
|
||||
|
||||
pub fn deinit(this: *HMAC) void {
|
||||
BoringSSL.HMAC_CTX_cleanup(&this.ctx);
|
||||
this.destroy();
|
||||
}
|
||||
};
|
||||
|
||||
pub const EVP = struct {
|
||||
ctx: BoringSSL.EVP_MD_CTX = undefined,
|
||||
md: *const BoringSSL.EVP_MD = undefined,
|
||||
@@ -1828,7 +1711,7 @@ pub const Crypto = struct {
|
||||
|
||||
pub fn fromJS(globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) ?Value {
|
||||
if (value.isObject()) {
|
||||
if (value.getTruthy(globalObject, "algorithm")) |algorithm_value| {
|
||||
if (value.getOwnTruthy(globalObject, "algorithm")) |algorithm_value| {
|
||||
if (!algorithm_value.isString()) {
|
||||
globalObject.throwInvalidArgumentType("hash", "algorithm", "string");
|
||||
return null;
|
||||
@@ -1845,7 +1728,7 @@ pub const Crypto = struct {
|
||||
.bcrypt = PasswordObject.Algorithm.Value.bcrpyt_default,
|
||||
};
|
||||
|
||||
if (value.getTruthy(globalObject, "cost")) |rounds_value| {
|
||||
if (value.getOwnTruthy(globalObject, "cost")) |rounds_value| {
|
||||
if (!rounds_value.isNumber()) {
|
||||
globalObject.throwInvalidArgumentType("hash", "cost", "number");
|
||||
return null;
|
||||
@@ -1866,7 +1749,7 @@ pub const Crypto = struct {
|
||||
inline .argon2id, .argon2d, .argon2i => |tag| {
|
||||
var argon = Algorithm.Argon2Params{};
|
||||
|
||||
if (value.getTruthy(globalObject, "timeCost")) |time_value| {
|
||||
if (value.getOwnTruthy(globalObject, "timeCost")) |time_value| {
|
||||
if (!time_value.isNumber()) {
|
||||
globalObject.throwInvalidArgumentType("hash", "timeCost", "number");
|
||||
return null;
|
||||
@@ -1882,7 +1765,7 @@ pub const Crypto = struct {
|
||||
argon.time_cost = @as(u32, @intCast(time_cost));
|
||||
}
|
||||
|
||||
if (value.getTruthy(globalObject, "memoryCost")) |memory_value| {
|
||||
if (value.getOwnTruthy(globalObject, "memoryCost")) |memory_value| {
|
||||
if (!memory_value.isNumber()) {
|
||||
globalObject.throwInvalidArgumentType("hash", "memoryCost", "number");
|
||||
return null;
|
||||
@@ -2602,6 +2485,9 @@ pub const Crypto = struct {
|
||||
};
|
||||
|
||||
pub const CryptoHasher = union(enum) {
|
||||
// HMAC_CTX contains 3 EVP_CTX, so let's store it as a pointer.
|
||||
hmac: ?*HMAC,
|
||||
|
||||
evp: EVP,
|
||||
zig: CryptoHasherZig,
|
||||
|
||||
@@ -2613,12 +2499,20 @@ pub const Crypto = struct {
|
||||
pub const digest = JSC.wrapInstanceMethod(CryptoHasher, "digest_", false);
|
||||
pub const hash = JSC.wrapStaticMethod(CryptoHasher, "hash_", false);
|
||||
|
||||
fn throwHmacConsumed(globalThis: *JSC.JSGlobalObject) void {
|
||||
globalThis.throw("HMAC has been consumed and is no longer usable", .{});
|
||||
}
|
||||
|
||||
pub fn getByteLength(
|
||||
this: *CryptoHasher,
|
||||
_: *JSC.JSGlobalObject,
|
||||
globalThis: *JSC.JSGlobalObject,
|
||||
) JSC.JSValue {
|
||||
return JSC.JSValue.jsNumber(switch (this.*) {
|
||||
.evp => |*inner| inner.size(),
|
||||
.hmac => |inner| if (inner) |hmac| hmac.size() else {
|
||||
throwHmacConsumed(globalThis);
|
||||
return JSC.JSValue.zero;
|
||||
},
|
||||
.zig => |*inner| inner.digest_length,
|
||||
});
|
||||
}
|
||||
@@ -2628,7 +2522,11 @@ pub const Crypto = struct {
|
||||
globalObject: *JSC.JSGlobalObject,
|
||||
) JSC.JSValue {
|
||||
return switch (this.*) {
|
||||
inline else => |*inner| ZigString.fromUTF8(bun.asByteSlice(@tagName(inner.algorithm))).toJS(globalObject),
|
||||
inline .evp, .zig => |*inner| ZigString.fromUTF8(bun.asByteSlice(@tagName(inner.algorithm))).toJS(globalObject),
|
||||
.hmac => |inner| if (inner) |hmac| ZigString.fromUTF8(bun.asByteSlice(@tagName(hmac.algorithm))).toJS(globalObject) else {
|
||||
throwHmacConsumed(globalObject);
|
||||
return JSC.JSValue.zero;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2738,6 +2636,7 @@ pub const Crypto = struct {
|
||||
}
|
||||
}
|
||||
|
||||
// Bun.CryptoHasher(algorithm, hmacKey?: string | Buffer)
|
||||
pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) ?*CryptoHasher {
|
||||
const arguments = callframe.arguments(2);
|
||||
if (arguments.len == 0) {
|
||||
@@ -2758,13 +2657,54 @@ pub const Crypto = struct {
|
||||
return null;
|
||||
}
|
||||
|
||||
var this: CryptoHasher = undefined;
|
||||
const evp = EVP.byName(algorithm, globalThis) orelse return CryptoHasherZig.constructor(algorithm) orelse {
|
||||
globalThis.throwInvalidArguments("Unsupported algorithm {any}", .{algorithm});
|
||||
return null;
|
||||
};
|
||||
this = .{ .evp = evp };
|
||||
return CryptoHasher.new(this);
|
||||
const hmac_value = arguments.ptr[1];
|
||||
var hmac_key: ?JSC.Node.StringOrBuffer = null;
|
||||
defer {
|
||||
if (hmac_key) |*key| {
|
||||
key.deinit();
|
||||
}
|
||||
}
|
||||
|
||||
if (!hmac_value.isEmptyOrUndefinedOrNull()) {
|
||||
hmac_key = JSC.Node.StringOrBuffer.fromJS(globalThis, bun.default_allocator, hmac_value) orelse {
|
||||
globalThis.throwInvalidArguments("key must be a string or buffer", .{});
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
return CryptoHasher.new(brk: {
|
||||
if (hmac_key) |*key| {
|
||||
const chosen_algorithm = algorithm_name.toEnumFromMap(globalThis, "algorithm", EVP.Algorithm, EVP.Algorithm.map) catch return null;
|
||||
if (chosen_algorithm == .ripemd160) {
|
||||
// crashes at runtime.
|
||||
globalThis.throw("ripemd160 is not supported", .{});
|
||||
return null;
|
||||
}
|
||||
|
||||
break :brk .{
|
||||
.hmac = HMAC.init(chosen_algorithm, key.slice()) orelse {
|
||||
if (!globalThis.hasException()) {
|
||||
const err = BoringSSL.ERR_get_error();
|
||||
if (err != 0) {
|
||||
const instance = createCryptoError(globalThis, err);
|
||||
BoringSSL.ERR_clear_error();
|
||||
globalThis.throwValue(instance);
|
||||
} else {
|
||||
globalThis.throwTODO("HMAC is not supported for this algorithm");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
break :brk .{
|
||||
.evp = EVP.byName(algorithm, globalThis) orelse return CryptoHasherZig.constructor(algorithm) orelse {
|
||||
globalThis.throwInvalidArguments("Unsupported algorithm {any}", .{algorithm});
|
||||
return null;
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
pub fn getter(
|
||||
@@ -2804,6 +2744,21 @@ pub const Crypto = struct {
|
||||
return .zero;
|
||||
}
|
||||
},
|
||||
.hmac => |inner| {
|
||||
const hmac = inner orelse {
|
||||
throwHmacConsumed(globalThis);
|
||||
return JSC.JSValue.zero;
|
||||
};
|
||||
|
||||
hmac.update(buffer.slice());
|
||||
const err = BoringSSL.ERR_get_error();
|
||||
if (err != 0) {
|
||||
const instance = createCryptoError(globalThis, err);
|
||||
BoringSSL.ERR_clear_error();
|
||||
globalThis.throwValue(instance);
|
||||
return .zero;
|
||||
}
|
||||
},
|
||||
.zig => |*inner| {
|
||||
inner.update(buffer.slice());
|
||||
return thisValue;
|
||||
@@ -2823,6 +2778,20 @@ pub const Crypto = struct {
|
||||
.evp => |*inner| {
|
||||
new = .{ .evp = inner.copy(globalObject.bunVM().rareData().boringEngine()) catch bun.outOfMemory() };
|
||||
},
|
||||
.hmac => |inner| {
|
||||
const hmac = inner orelse {
|
||||
throwHmacConsumed(globalObject);
|
||||
return JSC.JSValue.zero;
|
||||
};
|
||||
new = .{
|
||||
.hmac = hmac.copy() catch {
|
||||
const err = createCryptoError(globalObject, BoringSSL.ERR_get_error());
|
||||
BoringSSL.ERR_clear_error();
|
||||
globalObject.throwValue(err);
|
||||
return JSC.JSValue.zero;
|
||||
},
|
||||
};
|
||||
},
|
||||
.zig => |*inner| {
|
||||
new = .{ .zig = inner.copy() };
|
||||
},
|
||||
@@ -2873,6 +2842,9 @@ pub const Crypto = struct {
|
||||
}
|
||||
|
||||
const result = this.final(globalThis, output_digest_slice);
|
||||
if (globalThis.hasException()) {
|
||||
return JSC.JSValue.zero;
|
||||
}
|
||||
|
||||
if (output) |output_buf| {
|
||||
return output_buf.value;
|
||||
@@ -2886,11 +2858,23 @@ pub const Crypto = struct {
|
||||
var output_digest_buf: EVP.Digest = std.mem.zeroes(EVP.Digest);
|
||||
const output_digest_slice: []u8 = &output_digest_buf;
|
||||
const out = this.final(globalThis, output_digest_slice);
|
||||
if (globalThis.hasException()) {
|
||||
return JSC.JSValue.zero;
|
||||
}
|
||||
return encoding.encodeWithMaxSize(globalThis, BoringSSL.EVP_MAX_MD_SIZE, out);
|
||||
}
|
||||
|
||||
fn final(this: *CryptoHasher, globalThis: *JSGlobalObject, output_digest_slice: []u8) []u8 {
|
||||
return switch (this.*) {
|
||||
.hmac => |inner| brk: {
|
||||
const hmac: *HMAC = inner orelse {
|
||||
throwHmacConsumed(globalThis);
|
||||
return &.{};
|
||||
};
|
||||
this.hmac = null;
|
||||
defer hmac.deinit();
|
||||
break :brk hmac.final(output_digest_slice);
|
||||
},
|
||||
.evp => |*inner| inner.final(globalThis.bunVM().rareData().boringEngine(), output_digest_slice),
|
||||
.zig => |*inner| inner.final(output_digest_slice),
|
||||
};
|
||||
@@ -2905,6 +2889,11 @@ pub const Crypto = struct {
|
||||
.zig => |*inner| {
|
||||
inner.deinit();
|
||||
},
|
||||
.hmac => |inner| {
|
||||
if (inner) |hmac| {
|
||||
hmac.deinit();
|
||||
}
|
||||
},
|
||||
}
|
||||
this.destroy();
|
||||
}
|
||||
@@ -4373,7 +4362,7 @@ pub const FFIObject = struct {
|
||||
}
|
||||
}
|
||||
|
||||
if (addr > max_addressible_memory) {
|
||||
if (addr > max_addressable_memory) {
|
||||
return JSC.toInvalidArguments("Pointer is outside max addressible memory, which usually means a bug in your program.", .{}, globalThis);
|
||||
}
|
||||
|
||||
@@ -4455,7 +4444,7 @@ pub const FFIObject = struct {
|
||||
return .{ .err = JSC.toInvalidArguments("length must be > 0. This usually means a bug in your code.", .{}, globalThis) };
|
||||
}
|
||||
|
||||
if (length_i > max_addressible_memory) {
|
||||
if (length_i > max_addressable_memory) {
|
||||
return .{ .err = JSC.toInvalidArguments("length exceeds max addressable memory. This usually means a bug in your code.", .{}, globalThis) };
|
||||
}
|
||||
|
||||
@@ -4610,11 +4599,11 @@ fn stringWidth(globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC
|
||||
var ambiguous_as_wide = false;
|
||||
|
||||
if (options_object.isObject()) {
|
||||
if (options_object.getTruthy(globalObject, "countAnsiEscapeCodes")) |count_ansi_escapes_value| {
|
||||
if (options_object.getOwnTruthy(globalObject, "countAnsiEscapeCodes")) |count_ansi_escapes_value| {
|
||||
if (count_ansi_escapes_value.isBoolean())
|
||||
count_ansi_escapes = count_ansi_escapes_value.toBoolean();
|
||||
}
|
||||
if (options_object.getTruthy(globalObject, "ambiguousIsNarrow")) |ambiguous_is_narrow| {
|
||||
if (options_object.getOwnTruthy(globalObject, "ambiguousIsNarrow")) |ambiguous_is_narrow| {
|
||||
if (ambiguous_is_narrow.isBoolean())
|
||||
ambiguous_as_wide = !ambiguous_is_narrow.toBoolean();
|
||||
}
|
||||
@@ -4795,7 +4784,7 @@ pub const JSZlib = struct {
|
||||
library = .zlib;
|
||||
}
|
||||
|
||||
if (options_val.getTruthy(globalThis, "library")) |library_value| {
|
||||
if (options_val.getOwnTruthy(globalThis, "library")) |library_value| {
|
||||
if (!library_value.isString()) {
|
||||
globalThis.throwInvalidArguments("Expected library to be a string", .{});
|
||||
return .zero;
|
||||
@@ -4922,7 +4911,7 @@ pub const JSZlib = struct {
|
||||
library = .zlib;
|
||||
}
|
||||
|
||||
if (options_val.getTruthy(globalThis, "library")) |library_value| {
|
||||
if (options_val.getOwnTruthy(globalThis, "library")) |library_value| {
|
||||
if (!library_value.isString()) {
|
||||
globalThis.throwInvalidArguments("Expected library to be a string", .{});
|
||||
return .zero;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user