mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 02:18:47 +00:00
Compare commits
107 Commits
debugger-d
...
fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cbf373c31 | ||
|
|
3a8cb27abd | ||
|
|
a2dcd680de | ||
|
|
06f03d34da | ||
|
|
b33cdf586a | ||
|
|
c4c714f10b | ||
|
|
f8abd167d8 | ||
|
|
777f98bd10 | ||
|
|
30798c7078 | ||
|
|
bc7719fc28 | ||
|
|
ff63555143 | ||
|
|
069b42a7cc | ||
|
|
ceec1afec2 | ||
|
|
5ae8e5d773 | ||
|
|
4ff920c915 | ||
|
|
217501e180 | ||
|
|
ae4b65c52e | ||
|
|
ca1fe3c602 | ||
|
|
4a13a53058 | ||
|
|
5fa13625a1 | ||
|
|
bfb322d618 | ||
|
|
43865a3e29 | ||
|
|
b691212c6e | ||
|
|
69f558db8e | ||
|
|
9befbf02f1 | ||
|
|
f81c7f10f6 | ||
|
|
b9c950bfb7 | ||
|
|
6a1fbef8fd | ||
|
|
5006435234 | ||
|
|
adb451eec6 | ||
|
|
62639081c1 | ||
|
|
570ef07170 | ||
|
|
83d7ec728f | ||
|
|
9f301e13c5 | ||
|
|
f1b1dbf5cd | ||
|
|
bdbb637b3d | ||
|
|
e9e0e05156 | ||
|
|
7d94a49ef4 | ||
|
|
cbd6d24d34 | ||
|
|
b951c1f89e | ||
|
|
b78b2a3031 | ||
|
|
7dcf8b2186 | ||
|
|
8a5b8f1fca | ||
|
|
8ad9e5755d | ||
|
|
fdb7940c4e | ||
|
|
873f615358 | ||
|
|
b2af1984ed | ||
|
|
065713aeca | ||
|
|
68c092aef2 | ||
|
|
9b8054ae11 | ||
|
|
0591c6b4bb | ||
|
|
4a22fcd93c | ||
|
|
dc06caccaa | ||
|
|
e6d4b3a89a | ||
|
|
0f131a976e | ||
|
|
7f535a20a2 | ||
|
|
bac7526c03 | ||
|
|
c2a83f87d8 | ||
|
|
333b3f6beb | ||
|
|
b7ff3b0745 | ||
|
|
a1bb79f440 | ||
|
|
171ba6327d | ||
|
|
2ab797ff75 | ||
|
|
bdb1b7124a | ||
|
|
b93bdbb124 | ||
|
|
c8d06f04d3 | ||
|
|
067a0235e4 | ||
|
|
dbb2416542 | ||
|
|
51c093e24e | ||
|
|
50a18b6bac | ||
|
|
9a8d9b5e91 | ||
|
|
ef65f3c305 | ||
|
|
02eafd5019 | ||
|
|
04cd6a82b8 | ||
|
|
a2ec2ea397 | ||
|
|
f51878a8ec | ||
|
|
f18423cf45 | ||
|
|
68b9731db2 | ||
|
|
76cf465cc2 | ||
|
|
0f018ea215 | ||
|
|
a8dc41cd9f | ||
|
|
dbcaa02d89 | ||
|
|
e6b1574046 | ||
|
|
5df26a6a9b | ||
|
|
fc3331628e | ||
|
|
0ec70119f2 | ||
|
|
bf518222d4 | ||
|
|
6565bd89d5 | ||
|
|
99485bec4c | ||
|
|
0eb5103642 | ||
|
|
edd03341b1 | ||
|
|
1d2f06b37e | ||
|
|
870e5ac1dc | ||
|
|
7e296a1adc | ||
|
|
b9a705f84b | ||
|
|
d265ed80d2 | ||
|
|
fa3cfd34cb | ||
|
|
bcd67c3455 | ||
|
|
ec71e7afe4 | ||
|
|
17bca62df1 | ||
|
|
0c11762c31 | ||
|
|
fe7d5357d8 | ||
|
|
568f170e12 | ||
|
|
c87d65856c | ||
|
|
9b996e702e | ||
|
|
2cb1376a93 | ||
|
|
1f3da24fe0 |
2
.github/workflows/bun-linux-aarch64.yml
vendored
2
.github/workflows/bun-linux-aarch64.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
arch: aarch64
|
||||
build_arch: arm64
|
||||
runner: linux-arm64
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-linux-arm64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-linux-arm64-lto.tar.gz"
|
||||
webkit_basename: "bun-webkit-linux-arm64-lto"
|
||||
build_machine_arch: aarch64
|
||||
|
||||
|
||||
8
.github/workflows/bun-linux-build.yml
vendored
8
.github/workflows/bun-linux-build.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
arch: x86_64
|
||||
build_arch: amd64
|
||||
runner: big-ubuntu
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-linux-amd64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-linux-amd64-lto.tar.gz"
|
||||
webkit_basename: "bun-webkit-linux-amd64-lto"
|
||||
build_machine_arch: x86_64
|
||||
- cpu: nehalem
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
arch: x86_64
|
||||
build_arch: amd64
|
||||
runner: big-ubuntu
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-linux-amd64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-linux-amd64-lto.tar.gz"
|
||||
webkit_basename: "bun-webkit-linux-amd64-lto"
|
||||
build_machine_arch: x86_64
|
||||
|
||||
@@ -187,8 +187,8 @@ jobs:
|
||||
unzip bun-${{matrix.tag}}.zip
|
||||
cd bun-${{matrix.tag}}
|
||||
chmod +x bun
|
||||
sudo mv bun /usr/local/bin/bun
|
||||
bun --version
|
||||
pwd >> $GITHUB_PATH
|
||||
./bun --version
|
||||
- id: test
|
||||
name: Test (node runner)
|
||||
# if: ${{github.event.inputs.use_bun == 'false'}}
|
||||
|
||||
32
.github/workflows/bun-mac-aarch64.yml
vendored
32
.github/workflows/bun-mac-aarch64.yml
vendored
@@ -117,7 +117,7 @@ jobs:
|
||||
# obj: bun-obj-darwin-x64-baseline
|
||||
# runner: macos-11
|
||||
# artifact: bun-obj-darwin-x64-baseline
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# dependencies: true
|
||||
# compile_obj: false
|
||||
# - cpu: haswell
|
||||
@@ -126,7 +126,7 @@ jobs:
|
||||
# obj: bun-obj-darwin-x64
|
||||
# runner: macos-11
|
||||
# artifact: bun-obj-darwin-x64
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# dependencies: true
|
||||
# compile_obj: false
|
||||
# - cpu: nehalem
|
||||
@@ -135,7 +135,7 @@ jobs:
|
||||
# obj: bun-obj-darwin-x64-baseline
|
||||
# runner: macos-11
|
||||
# artifact: bun-obj-darwin-x64-baseline
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# dependencies: false
|
||||
# compile_obj: true
|
||||
# - cpu: haswell
|
||||
@@ -144,7 +144,7 @@ jobs:
|
||||
# obj: bun-obj-darwin-x64
|
||||
# runner: macos-11
|
||||
# artifact: bun-obj-darwin-x64
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# dependencies: false
|
||||
# compile_obj: true
|
||||
- cpu: native
|
||||
@@ -152,7 +152,7 @@ jobs:
|
||||
tag: bun-darwin-aarch64
|
||||
obj: bun-obj-darwin-aarch64
|
||||
artifact: bun-obj-darwin-aarch64
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-arm64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-arm64-lto.tar.gz"
|
||||
runner: macos-arm64
|
||||
dependencies: true
|
||||
compile_obj: true
|
||||
@@ -173,9 +173,9 @@ jobs:
|
||||
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
|
||||
run: |
|
||||
brew install ccache rust llvm@15 pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config esbuild --force
|
||||
echo "export PATH=$(brew --prefix ccache)/bin:\$PATH" >> $GITHUB_ENV
|
||||
echo "export PATH=$(brew --prefix coreutils)/libexec/gnubin:\$PATH" >> $GITHUB_ENV
|
||||
echo "export PATH=$(brew --prefix llvm@15)/bin:\$PATH" >> $GITHUB_ENV
|
||||
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix llvm@15)/bin" >> $GITHUB_PATH
|
||||
brew link --overwrite llvm@15
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
@@ -257,7 +257,7 @@ jobs:
|
||||
# package: bun-darwin-x64
|
||||
# runner: macos-11
|
||||
# artifact: bun-obj-darwin-x64-baseline
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# - cpu: haswell
|
||||
# arch: x86_64
|
||||
# tag: bun-darwin-x64
|
||||
@@ -265,14 +265,14 @@ jobs:
|
||||
# package: bun-darwin-x64
|
||||
# runner: macos-11
|
||||
# artifact: bun-obj-darwin-x64
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
- cpu: native
|
||||
arch: aarch64
|
||||
tag: bun-darwin-aarch64
|
||||
obj: bun-obj-darwin-aarch64
|
||||
package: bun-darwin-aarch64
|
||||
artifact: bun-obj-darwin-aarch64
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-arm64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-arm64-lto.tar.gz"
|
||||
runner: macos-arm64
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -291,8 +291,8 @@ jobs:
|
||||
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
|
||||
run: |
|
||||
brew install rust ccache llvm@15 pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config esbuild --force
|
||||
echo "export PATH=$(brew --prefix coreutils)/libexec/gnubin:\$PATH" >> $GITHUB_ENV
|
||||
echo "export PATH=$(brew --prefix llvm@15)/bin:\$PATH" >> $GITHUB_ENV
|
||||
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix llvm@15)/bin" >> $GITHUB_PATH
|
||||
brew link --overwrite llvm@15
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
@@ -397,7 +397,7 @@ jobs:
|
||||
runs-on: ${{ matrix.runner }}
|
||||
needs: [macOS]
|
||||
if: github.event_name == 'pull_request' && github.repository_owner == 'oven-sh'
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 30
|
||||
outputs:
|
||||
failing_tests: ${{ steps.test.outputs.failing_tests }}
|
||||
failing_tests_count: ${{ steps.test.outputs.failing_tests_count }}
|
||||
@@ -426,8 +426,8 @@ jobs:
|
||||
unzip ${{matrix.tag}}.zip
|
||||
cd ${{matrix.tag}}
|
||||
chmod +x bun
|
||||
sudo mv bun /usr/local/bin/bun
|
||||
bun --version
|
||||
pwd >> $GITHUB_PATH
|
||||
./bun --version
|
||||
- id: test
|
||||
name: Test (node runner)
|
||||
# if: ${{github.event.inputs.use_bun == 'false'}}
|
||||
|
||||
30
.github/workflows/bun-mac-x64-baseline.yml
vendored
30
.github/workflows/bun-mac-x64-baseline.yml
vendored
@@ -117,7 +117,7 @@ jobs:
|
||||
obj: bun-obj-darwin-x64-baseline
|
||||
runner: macos-11
|
||||
artifact: bun-obj-darwin-x64-baseline
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
dependencies: true
|
||||
compile_obj: false
|
||||
# - cpu: haswell
|
||||
@@ -126,7 +126,7 @@ jobs:
|
||||
# obj: bun-obj-darwin-x64
|
||||
# runner: macos-11
|
||||
# artifact: bun-obj-darwin-x64
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# dependencies: true
|
||||
# compile_obj: false
|
||||
- cpu: nehalem
|
||||
@@ -135,7 +135,7 @@ jobs:
|
||||
obj: bun-obj-darwin-x64-baseline
|
||||
runner: macos-11
|
||||
artifact: bun-obj-darwin-x64-baseline
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
dependencies: false
|
||||
compile_obj: true
|
||||
# - cpu: haswell
|
||||
@@ -144,7 +144,7 @@ jobs:
|
||||
# obj: bun-obj-darwin-x64
|
||||
# runner: macos-11
|
||||
# artifact: bun-obj-darwin-x64
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# dependencies: false
|
||||
# compile_obj: true
|
||||
# - cpu: native
|
||||
@@ -152,7 +152,7 @@ jobs:
|
||||
# tag: bun-darwin-aarch64
|
||||
# obj: bun-obj-darwin-aarch64
|
||||
# artifact: bun-obj-darwin-aarch64
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# runner: macos-arm64
|
||||
# dependencies: true
|
||||
# compile_obj: true
|
||||
@@ -173,9 +173,9 @@ jobs:
|
||||
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
|
||||
run: |
|
||||
brew install ccache rust llvm@15 pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config esbuild --force
|
||||
echo "export PATH=$(brew --prefix ccache)/bin:\$PATH" >> $GITHUB_ENV
|
||||
echo "export PATH=$(brew --prefix coreutils)/libexec/gnubin:\$PATH" >> $GITHUB_ENV
|
||||
echo "export PATH=$(brew --prefix llvm@15)/bin:\$PATH" >> $GITHUB_ENV
|
||||
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix llvm@15)/bin" >> $GITHUB_PATH
|
||||
brew link --overwrite llvm@15
|
||||
- name: ccache (dependencies)
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
@@ -258,7 +258,7 @@ jobs:
|
||||
package: bun-darwin-x64
|
||||
runner: macos-11
|
||||
artifact: bun-obj-darwin-x64-baseline
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# - cpu: haswell
|
||||
# arch: x86_64
|
||||
# tag: bun-darwin-x64
|
||||
@@ -266,14 +266,14 @@ jobs:
|
||||
# package: bun-darwin-x64
|
||||
# runner: macos-11
|
||||
# artifact: bun-obj-darwin-x64
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# - cpu: native
|
||||
# arch: aarch64
|
||||
# tag: bun-darwin-aarch64
|
||||
# obj: bun-obj-darwin-aarch64
|
||||
# package: bun-darwin-aarch64
|
||||
# artifact: bun-obj-darwin-aarch64
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# runner: macos-arm64
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -292,8 +292,8 @@ jobs:
|
||||
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
|
||||
run: |
|
||||
brew install ccache rust llvm@15 pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config esbuild --force
|
||||
echo "export PATH=$(brew --prefix coreutils)/libexec/gnubin:\$PATH" >> $GITHUB_ENV
|
||||
echo "export PATH=$(brew --prefix llvm@15)/bin:\$PATH" >> $GITHUB_ENV
|
||||
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix llvm@15)/bin" >> $GITHUB_PATH
|
||||
brew link --overwrite llvm@15
|
||||
- name: ccache (link)
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
@@ -430,8 +430,8 @@ jobs:
|
||||
unzip ${{matrix.tag}}.zip
|
||||
cd ${{matrix.tag}}
|
||||
chmod +x bun
|
||||
sudo mv bun /usr/local/bin/bun
|
||||
bun --version
|
||||
pwd >> $GITHUB_PATH
|
||||
./bun --version
|
||||
- id: test
|
||||
name: Test (node runner)
|
||||
# if: ${{github.event.inputs.use_bun == 'false'}}
|
||||
|
||||
28
.github/workflows/bun-mac-x64.yml
vendored
28
.github/workflows/bun-mac-x64.yml
vendored
@@ -117,7 +117,7 @@ jobs:
|
||||
# obj: bun-obj-darwin-x64-baseline
|
||||
# runner: macos-11
|
||||
# artifact: bun-obj-darwin-x64-baseline
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# dependencies: true
|
||||
# compile_obj: false
|
||||
- cpu: haswell
|
||||
@@ -126,7 +126,7 @@ jobs:
|
||||
obj: bun-obj-darwin-x64
|
||||
runner: macos-11
|
||||
artifact: bun-obj-darwin-x64
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
dependencies: true
|
||||
compile_obj: false
|
||||
# - cpu: nehalem
|
||||
@@ -135,7 +135,7 @@ jobs:
|
||||
# obj: bun-obj-darwin-x64-baseline
|
||||
# runner: macos-11
|
||||
# artifact: bun-obj-darwin-x64-baseline
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# dependencies: false
|
||||
# compile_obj: true
|
||||
- cpu: haswell
|
||||
@@ -144,7 +144,7 @@ jobs:
|
||||
obj: bun-obj-darwin-x64
|
||||
runner: macos-11
|
||||
artifact: bun-obj-darwin-x64
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
dependencies: false
|
||||
compile_obj: true
|
||||
# - cpu: native
|
||||
@@ -152,7 +152,7 @@ jobs:
|
||||
# tag: bun-darwin-aarch64
|
||||
# obj: bun-obj-darwin-aarch64
|
||||
# artifact: bun-obj-darwin-aarch64
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-arm64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-arm64-lto.tar.gz"
|
||||
# runner: macos-arm64
|
||||
# dependencies: true
|
||||
# compile_obj: true
|
||||
@@ -173,8 +173,8 @@ jobs:
|
||||
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
|
||||
run: |
|
||||
brew install rust ccache llvm@15 pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config esbuild --force
|
||||
echo "export PATH=$(brew --prefix coreutils)/libexec/gnubin:\$PATH" >> $GITHUB_ENV
|
||||
echo "export PATH=$(brew --prefix llvm@15)/bin:\$PATH" >> $GITHUB_ENV
|
||||
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix llvm@15)/bin" >> $GITHUB_PATH
|
||||
brew link --overwrite llvm@15
|
||||
- name: Download WebKit
|
||||
if: matrix.compile_obj
|
||||
@@ -260,7 +260,7 @@ jobs:
|
||||
# package: bun-darwin-x64
|
||||
# runner: macos-11
|
||||
# artifact: bun-obj-darwin-x64-baseline
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
- cpu: haswell
|
||||
arch: x86_64
|
||||
tag: bun-darwin-x64
|
||||
@@ -268,14 +268,14 @@ jobs:
|
||||
package: bun-darwin-x64
|
||||
runner: macos-11
|
||||
artifact: bun-obj-darwin-x64
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# - cpu: native
|
||||
# arch: aarch64
|
||||
# tag: bun-darwin-aarch64
|
||||
# obj: bun-obj-darwin-aarch64
|
||||
# package: bun-darwin-aarch64
|
||||
# artifact: bun-obj-darwin-aarch64
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-arm64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-arm64-lto.tar.gz"
|
||||
# runner: macos-arm64
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -294,8 +294,8 @@ jobs:
|
||||
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
|
||||
run: |
|
||||
brew install rust ccache llvm@15 pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config esbuild --force
|
||||
echo "export PATH=$(brew --prefix coreutils)/libexec/gnubin:\$PATH" >> $GITHUB_ENV
|
||||
echo "export PATH=$(brew --prefix llvm@15)/bin:\$PATH" >> $GITHUB_ENV
|
||||
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix llvm@15)/bin" >> $GITHUB_PATH
|
||||
brew link --overwrite llvm@15
|
||||
- name: Download WebKit
|
||||
env:
|
||||
@@ -432,8 +432,8 @@ jobs:
|
||||
unzip ${{matrix.tag}}.zip
|
||||
cd ${{matrix.tag}}
|
||||
chmod +x bun
|
||||
sudo mv bun /usr/local/bin/bun
|
||||
bun --version
|
||||
pwd >> $GITHUB_PATH
|
||||
./bun --version
|
||||
- id: test
|
||||
name: Test (node runner)
|
||||
# if: ${{github.event.inputs.use_bun == 'false'}}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: bun-release-canary
|
||||
name: bun-release-types-canary
|
||||
concurrency: release-canary
|
||||
on:
|
||||
push:
|
||||
|
||||
4
.github/workflows/zig-fmt.yml
vendored
4
.github/workflows/zig-fmt.yml
vendored
@@ -1,7 +1,7 @@
|
||||
name: zig-fmt
|
||||
|
||||
env:
|
||||
ZIG_VERSION: 0.11.0-dev.2571+31738de28
|
||||
ZIG_VERSION: 0.11.0-dev.3737+9eb008717
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
run: |
|
||||
curl https://ziglang.org/builds/zig-linux-x86_64-${{env.ZIG_VERSION}}.tar.xz -L -o zig.tar.xz
|
||||
tar -xf zig.tar.xz
|
||||
sudo mv zig-linux-x86_64-${{env.ZIG_VERSION}}/zig /usr/local/bin
|
||||
echo "$(pwd)/zig-linux-x86_64-${{env.ZIG_VERSION}}" >> $GITHUB_PATH
|
||||
- name: Run zig fmt
|
||||
id: fmt
|
||||
run: |
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -121,3 +121,5 @@ cold-jsc-start
|
||||
cold-jsc-start.d
|
||||
|
||||
/test.ts
|
||||
|
||||
src/js/out/modules_dev
|
||||
|
||||
@@ -6,7 +6,7 @@ module.exports = {
|
||||
quoteProps: "preserve",
|
||||
overrides: [
|
||||
{
|
||||
files: "README.md",
|
||||
files: ["*.md"],
|
||||
options: {
|
||||
printWidth: 80,
|
||||
},
|
||||
|
||||
7
.vscode/c_cpp_properties.json
vendored
7
.vscode/c_cpp_properties.json
vendored
@@ -19,11 +19,11 @@
|
||||
"${workspaceFolder}/src/js/out",
|
||||
"${workspaceFolder}/src/deps/boringssl/include/",
|
||||
"${workspaceFolder}/src/deps",
|
||||
"${workspaceFolder}/src/deps/uws/uSockets/src",
|
||||
"${workspaceFolder}/src/deps/uws/src"
|
||||
"${workspaceFolder}/src/deps/uws/uSockets/src"
|
||||
],
|
||||
"browse": {
|
||||
"path": [
|
||||
"${workspaceFolder}/../webkit-build/include/",
|
||||
"${workspaceFolder}/bun-webkit/include/",
|
||||
"${workspaceFolder}/src/bun.js/WebKit/WebKitBuild/Release/",
|
||||
"${workspaceFolder}/src/bun.js/WebKit/WebKitBuild/Release/ICU/Headers/",
|
||||
@@ -39,8 +39,7 @@
|
||||
"${workspaceFolder}/src/bun.js/modules/*",
|
||||
"${workspaceFolder}/src/deps",
|
||||
"${workspaceFolder}/src/deps/boringssl/include/",
|
||||
"${workspaceFolder}/src/deps/uws/uSockets/src",
|
||||
"${workspaceFolder}/src/deps/uws/src"
|
||||
"${workspaceFolder}/src/deps/uws/uSockets/src"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ".vscode/cppdb"
|
||||
|
||||
14
.vscode/launch.json
generated
vendored
14
.vscode/launch.json
generated
vendored
@@ -136,20 +136,6 @@
|
||||
"initCommands": ["process handle -p false -s false -n false SIGHUP"],
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "bun run [Inspect]",
|
||||
"program": "bun-debug",
|
||||
"args": ["--inspect-brk", "${file}"],
|
||||
"cwd": "${fileDirname}",
|
||||
"env": {
|
||||
"FORCE_COLOR": "1",
|
||||
"BUN_DEBUG_QUIET_LOGS": "1"
|
||||
},
|
||||
"initCommands": ["process handle -p false -s false -n false SIGHUP"],
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
|
||||
@@ -10,9 +10,9 @@ ARG ARCH=x86_64
|
||||
ARG BUILD_MACHINE_ARCH=x86_64
|
||||
ARG TRIPLET=${ARCH}-linux-gnu
|
||||
ARG BUILDARCH=amd64
|
||||
ARG WEBKIT_TAG=may20
|
||||
ARG WEBKIT_TAG=may20-1
|
||||
ARG ZIG_TAG=jul1
|
||||
ARG ZIG_VERSION="0.11.0-dev.2571+31738de28"
|
||||
ARG ZIG_VERSION="0.11.0-dev.3737+9eb008717"
|
||||
ARG WEBKIT_BASENAME="bun-webkit-linux-$BUILDARCH"
|
||||
|
||||
ARG ZIG_FOLDERNAME=zig-linux-${BUILD_MACHINE_ARCH}-${ZIG_VERSION}
|
||||
|
||||
17
Makefile
17
Makefile
@@ -561,6 +561,9 @@ builtins:
|
||||
esm:
|
||||
NODE_ENV=production bun src/js/build-esm.ts
|
||||
|
||||
esm-debug:
|
||||
BUN_DEBUG_QUIET_LOGS=1 NODE_ENV=production bun-debug src/js/build-esm.ts
|
||||
|
||||
.PHONY: generate-builtins
|
||||
generate-builtins: builtins
|
||||
|
||||
@@ -1085,7 +1088,7 @@ dev-obj-linux:
|
||||
$(ZIG) build obj -Dtarget=x86_64-linux-gnu -Dcpu="$(CPU_TARGET)"
|
||||
|
||||
.PHONY: dev
|
||||
dev: mkdir-dev esm dev-obj bun-link-lld-debug
|
||||
dev: mkdir-dev esm dev-obj link
|
||||
|
||||
mkdir-dev:
|
||||
mkdir -p $(DEBUG_PACKAGE_DIR)
|
||||
@@ -1356,15 +1359,21 @@ mimalloc-wasm:
|
||||
cd $(BUN_DEPS_DIR)/mimalloc; emcmake cmake -DMI_BUILD_SHARED=OFF -DMI_BUILD_STATIC=ON -DMI_BUILD_TESTS=OFF -DMI_BUILD_OBJECT=ON ${MIMALLOC_OVERRIDE_FLAG} -DMI_USE_CXX=ON .; emmake make;
|
||||
cp $(BUN_DEPS_DIR)/mimalloc/$(MIMALLOC_INPUT_PATH) $(BUN_DEPS_OUT_DIR)/$(MIMALLOC_FILE).wasm
|
||||
|
||||
bun-link-lld-debug:
|
||||
# alias for link, incase anyone still types that
|
||||
.PHONY: bun-link-lld-debug
|
||||
bun-link-lld-debug: link
|
||||
|
||||
# link a debug build of bun
|
||||
.PHONY: link
|
||||
link:
|
||||
$(CXX) $(BUN_LLD_FLAGS_DEBUG) $(DEBUG_FLAGS) $(SYMBOLS) \
|
||||
-g \
|
||||
$(DEBUG_BIN)/bun-debug.o \
|
||||
-W \
|
||||
-o $(DEBUG_BIN)/bun-debug
|
||||
@rm -f $(DEBUG_BIN)/bun-debug.o.o 2> /dev/null # workaround for https://github.com/ziglang/zig/issues/14080
|
||||
@rm -f $(DEBUG_BIN)/bun-debug.o.o 2> /dev/null # workaround for https://github.com/ziglang/zig/issues/14080
|
||||
|
||||
bun-link-lld-debug-no-jsc:
|
||||
link-no-jsc:
|
||||
$(CXX) $(BUN_LLD_FLAGS_WITHOUT_JSC) $(SYMBOLS) \
|
||||
-g \
|
||||
$(DEBUG_BIN)/bun-debug.o \
|
||||
|
||||
@@ -128,27 +128,27 @@ pub fn main() anyerror!void {
|
||||
counters[counter].timestamp = @truncate(u64, @intCast(u128, std.time.nanoTimestamp()) / (std.time.ns_per_ms / 10));
|
||||
counters[counter].rotate = rotate % 360;
|
||||
counters[counter].percent = std.math.mod(f64, std.math.round(((progress_bar + 1.0) / destination_count) * 1000) / 1000, 100) catch 0;
|
||||
counters[counter].color_values[0] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[0][0] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[1] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[0][1] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[2] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[0][2] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[0] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[0][0] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[1] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[0][1] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[2] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[0][2] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[3] = (colors[0][0] + 1) % 256;
|
||||
counters[counter].color_values[4] = (colors[0][1] + 1) % 256;
|
||||
counters[counter].color_values[5] = (colors[0][2] + 1) % 256;
|
||||
counters[counter].color_values[6] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[1][0] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[7] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[1][1] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[8] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[1][2] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[6] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[1][0] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[7] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[1][1] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[8] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[1][2] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[9] = (colors[1][0] + 1) % 256;
|
||||
counters[counter].color_values[10] = (colors[1][1] + 1) % 256;
|
||||
counters[counter].color_values[11] = (colors[1][2] + 1) % 256;
|
||||
counters[counter].color_values[12] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[2][0] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[13] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[2][1] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[14] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[2][2] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[12] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[2][0] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[13] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[2][1] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[14] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[2][2] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[15] = (colors[2][0] + 1) % 256;
|
||||
counters[counter].color_values[16] = (colors[2][1] + 1) % 256;
|
||||
counters[counter].color_values[17] = (colors[2][2] + 1) % 256;
|
||||
counters[counter].color_values[18] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[3][0] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[19] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[3][1] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[20] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[3][2] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[18] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[3][0] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[19] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[3][1] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[20] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[3][2] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[21] = (colors[3][0] + 1) % 256;
|
||||
counters[counter].color_values[22] = (colors[3][1] + 1) % 256;
|
||||
counters[counter].color_values[23] = (colors[3][2] + 1) % 256;
|
||||
@@ -203,7 +203,7 @@ pub fn main() anyerror!void {
|
||||
_ = try recorder.wait();
|
||||
|
||||
all_timestamps[0] = wrote.len;
|
||||
for (counters) |count, i| {
|
||||
for (counters, 0..) |count, i| {
|
||||
all_timestamps[i + 1] = count.timestamp;
|
||||
}
|
||||
|
||||
|
||||
@@ -115,27 +115,27 @@ pub fn main() anyerror!void {
|
||||
counters[counter].timestamp = @truncate(u64, @intCast(u128, std.time.nanoTimestamp()) / (std.time.ns_per_ms / 10));
|
||||
counters[counter].rotate = rotate % 360;
|
||||
counters[counter].percent = std.math.mod(f64, std.math.round(((progress_bar + 1.0) / destination_count) * 1000) / 1000, 100) catch 0;
|
||||
counters[counter].color_values[0] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[0][0] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[1] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[0][1] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[2] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[0][2] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[0] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[0][0] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[1] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[0][1] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[2] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[0][2] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[3] = (colors[0][0] + 1) % 256;
|
||||
counters[counter].color_values[4] = (colors[0][1] + 1) % 256;
|
||||
counters[counter].color_values[5] = (colors[0][2] + 1) % 256;
|
||||
counters[counter].color_values[6] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[1][0] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[7] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[1][1] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[8] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[1][2] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[6] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[1][0] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[7] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[1][1] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[8] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[1][2] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[9] = (colors[1][0] + 1) % 256;
|
||||
counters[counter].color_values[10] = (colors[1][1] + 1) % 256;
|
||||
counters[counter].color_values[11] = (colors[1][2] + 1) % 256;
|
||||
counters[counter].color_values[12] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[2][0] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[13] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[2][1] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[14] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[2][2] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[12] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[2][0] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[13] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[2][1] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[14] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[2][2] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[15] = (colors[2][0] + 1) % 256;
|
||||
counters[counter].color_values[16] = (colors[2][1] + 1) % 256;
|
||||
counters[counter].color_values[17] = (colors[2][2] + 1) % 256;
|
||||
counters[counter].color_values[18] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[3][0] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[19] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[3][1] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[20] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[3][2] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[18] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[3][0] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[19] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[3][1] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[20] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[3][2] + 1) % 256)) * 0.8));
|
||||
counters[counter].color_values[21] = (colors[3][0] + 1) % 256;
|
||||
counters[counter].color_values[22] = (colors[3][1] + 1) % 256;
|
||||
counters[counter].color_values[23] = (colors[3][2] + 1) % 256;
|
||||
@@ -190,7 +190,7 @@ pub fn main() anyerror!void {
|
||||
_ = try recorder.wait();
|
||||
|
||||
all_timestamps[0] = wrote.len;
|
||||
for (counters) |count, i| {
|
||||
for (counters, 0..) |count, i| {
|
||||
all_timestamps[i + 1] = count.timestamp;
|
||||
}
|
||||
|
||||
|
||||
65
bench/snippets/module-exports-putter.cjs
Normal file
65
bench/snippets/module-exports-putter.cjs
Normal file
@@ -0,0 +1,65 @@
|
||||
// This is a stress test of some internals in How Bun does the module.exports assignment.
|
||||
// If it crashes or throws then this fails
|
||||
import("./runner.mjs").then(({ bench, run }) => {
|
||||
bench("Object.defineProperty(module, 'exports', { get() { return 42; } })", () => {
|
||||
Object.defineProperty(module, "exports", {
|
||||
get() {
|
||||
return 42;
|
||||
},
|
||||
set() {
|
||||
throw new Error("bad");
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
if (module.exports !== 42) throw new Error("bad");
|
||||
if (!Object.getOwnPropertyDescriptor(module, "exports").get) throw new Error("bad");
|
||||
});
|
||||
|
||||
bench("Object.defineProperty(module.exports = {})", () => {
|
||||
Object.defineProperty(module, "exports", {
|
||||
value: { abc: 123 },
|
||||
});
|
||||
|
||||
if (!module.exports.abc) throw new Error("bad");
|
||||
if (Object.getOwnPropertyDescriptor(module, "exports").value !== module.exports) throw new Error("bad");
|
||||
});
|
||||
|
||||
bench("module.exports = {}", () => {
|
||||
module.exports = { abc: 123 };
|
||||
|
||||
if (!module.exports.abc) throw new Error("bad");
|
||||
if (Object.getOwnPropertyDescriptor(module, "exports").value !== module.exports) throw new Error("bad");
|
||||
});
|
||||
|
||||
run().then(() => {
|
||||
module.exports = {
|
||||
a: 1,
|
||||
};
|
||||
|
||||
console.log(
|
||||
module?.exports,
|
||||
require.cache[module.id].exports,
|
||||
module?.exports === require.cache[module.id],
|
||||
__dirname,
|
||||
Object.keys(require(module.id)),
|
||||
require(module.id),
|
||||
);
|
||||
|
||||
module.exports = function lol() {
|
||||
return 42;
|
||||
};
|
||||
|
||||
console.log(module.exports, module.exports());
|
||||
|
||||
queueMicrotask(() => {
|
||||
console.log(
|
||||
module?.exports,
|
||||
require.cache[module.id].exports,
|
||||
module?.exports === require.cache[module.id]?.exports,
|
||||
__dirname,
|
||||
Object.keys(require(module.id)),
|
||||
require(module.id),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,10 @@
|
||||
import { realpathSync } from "node:fs";
|
||||
const count = parseInt(process.env.ITERATIONS || "1", 10) || 1;
|
||||
const arg = process.argv[process.argv.length - 1];
|
||||
for (let i = 0; i < count; i++) realpathSync(arg);
|
||||
import { bench, run } from "./runner.mjs";
|
||||
|
||||
bench("realpathSync x " + count, () => {
|
||||
for (let i = 0; i < count; i++) realpathSync(arg, "utf-8");
|
||||
});
|
||||
|
||||
await run();
|
||||
|
||||
60
bench/snippets/util-deprecate.mjs
Normal file
60
bench/snippets/util-deprecate.mjs
Normal file
@@ -0,0 +1,60 @@
|
||||
import { bench, run } from "./runner.mjs";
|
||||
function deprecateUsingClosure(fn, msg, code) {
|
||||
if (process.noDeprecation === true) {
|
||||
return fn;
|
||||
}
|
||||
|
||||
var realFn = fn;
|
||||
var wrapper = () => {
|
||||
return fnToWrap.apply(this, arguments);
|
||||
};
|
||||
|
||||
var deprecater = () => {
|
||||
if (process.throwDeprecation) {
|
||||
var err = new Error(msg);
|
||||
if (code) err.code = code;
|
||||
throw err;
|
||||
} else if (process.traceDeprecation) {
|
||||
console.trace(msg);
|
||||
} else {
|
||||
console.error(msg);
|
||||
}
|
||||
|
||||
fnToWrap = realFn;
|
||||
return realFn.apply(this, arguments);
|
||||
};
|
||||
var fnToWrap = deprecater;
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
function deprecateOriginal(fn, msg) {
|
||||
var warned = false;
|
||||
function deprecated() {
|
||||
if (!warned) {
|
||||
if (process.throwDeprecation) {
|
||||
throw new Error(msg);
|
||||
} else if (process.traceDeprecation) {
|
||||
console.trace(msg);
|
||||
} else {
|
||||
console.error(msg);
|
||||
}
|
||||
warned = true;
|
||||
}
|
||||
return fn.apply(this, arguments);
|
||||
}
|
||||
return deprecated;
|
||||
}
|
||||
|
||||
const deprecatedy = deprecateUsingClosure(() => {}, "This is deprecated", "DEP0001");
|
||||
const deprecatedy2 = deprecateOriginal(() => {}, "This is deprecated");
|
||||
|
||||
bench("deprecateUsingClosure", () => {
|
||||
deprecatedy(Math.random() + 1);
|
||||
});
|
||||
|
||||
bench("deprecateOriginal", () => {
|
||||
deprecatedy2(Math.random() + 1);
|
||||
});
|
||||
|
||||
await run();
|
||||
@@ -32,6 +32,7 @@ const server = Bun.serve({
|
||||
},
|
||||
|
||||
perMessageDeflate: false,
|
||||
publishToSelf: true,
|
||||
},
|
||||
|
||||
fetch(req, server) {
|
||||
|
||||
@@ -42,4 +42,4 @@ function sendReadyMessage() {
|
||||
|
||||
console.log(`Waiting for ${CLIENTS_TO_WAIT_FOR} clients to connect..`);
|
||||
|
||||
Deno.serve(reqHandler, { port });
|
||||
Deno.serve({ port }, reqHandler);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const std = @import("std");
|
||||
const Wyhash = @import("./src/wyhash.zig").Wyhash;
|
||||
|
||||
fn moduleSource(comptime out: []const u8) FileSource {
|
||||
if (comptime std.fs.path.dirname(@src().file)) |base| {
|
||||
@@ -76,13 +77,13 @@ const BunBuildOptions = struct {
|
||||
|
||||
pub fn updateRuntime(this: *BunBuildOptions) anyerror!void {
|
||||
var runtime_out_file = try std.fs.cwd().openFile("src/runtime.out.js", .{ .mode = .read_only });
|
||||
const runtime_hash = std.hash.Wyhash.hash(
|
||||
const runtime_hash = Wyhash.hash(
|
||||
0,
|
||||
try runtime_out_file.readToEndAlloc(std.heap.page_allocator, try runtime_out_file.getEndPos()),
|
||||
);
|
||||
this.runtime_js_version = runtime_hash;
|
||||
var fallback_out_file = try std.fs.cwd().openFile("src/fallback.out.js", .{ .mode = .read_only });
|
||||
const fallback_hash = std.hash.Wyhash.hash(
|
||||
const fallback_hash = Wyhash.hash(
|
||||
0,
|
||||
try fallback_out_file.readToEndAlloc(std.heap.page_allocator, try fallback_out_file.getEndPos()),
|
||||
);
|
||||
@@ -192,12 +193,12 @@ pub fn build(b: *Build) !void {
|
||||
else
|
||||
"root.zig";
|
||||
|
||||
const min_version: std.builtin.Version = if (target.getOsTag() != .freestanding)
|
||||
const min_version: std.SemanticVersion = if (target.getOsTag() != .freestanding)
|
||||
target.getOsVersionMin().semver
|
||||
else
|
||||
.{ .major = 0, .minor = 0, .patch = 0 };
|
||||
|
||||
const max_version: std.builtin.Version = if (target.getOsTag() != .freestanding)
|
||||
const max_version: std.SemanticVersion = if (target.getOsTag() != .freestanding)
|
||||
target.getOsVersionMax().semver
|
||||
else
|
||||
.{ .major = 0, .minor = 0, .patch = 0 };
|
||||
|
||||
@@ -202,6 +202,53 @@ const response = await fetch("https://bun.sh");
|
||||
await Bun.write("index.html", response);
|
||||
```
|
||||
|
||||
## Incremental writing with `FileSink`
|
||||
|
||||
Bun provides a native incremental file writing API called `FileSink`. To retrieve a `FileSink` instance from a `BunFile`:
|
||||
|
||||
```ts
|
||||
const file = Bun.file("output.txt");
|
||||
const writer = file.writer();
|
||||
```
|
||||
|
||||
To incrementally write to the file, call `.write()`.
|
||||
|
||||
```ts
|
||||
const file = Bun.file("output.txt");
|
||||
const writer = file.writer();
|
||||
|
||||
writer.write("it was the best of times\n");
|
||||
writer.write("it was the worst of times\n");
|
||||
```
|
||||
|
||||
These chunks will be buffered internally. To flush the buffer to disk, use `.flush()`. This returns the number of flushed bytes.
|
||||
|
||||
```ts
|
||||
writer.flush(); // write buffer to disk
|
||||
```
|
||||
|
||||
The buffer will also auto-flush when the `FileSink`'s _high water mark_ is reached; that is, when its internal buffer is full. This value can be configured.
|
||||
|
||||
```ts
|
||||
const file = Bun.file("output.txt");
|
||||
const writer = file.writer({ highWaterMark: 1024 * 1024 }); // 1MB
|
||||
```
|
||||
|
||||
To flush the buffer and close the file:
|
||||
|
||||
```ts
|
||||
writer.end();
|
||||
```
|
||||
|
||||
Note that, by default, the `bun` process will stay alive until this `FileSink` is explicitly closed with `.end()`. To opt out of this behavior, you can "unref" the instance.
|
||||
|
||||
```ts
|
||||
writer.unref();
|
||||
|
||||
// to "re-ref" it later
|
||||
writer.ref();
|
||||
```
|
||||
|
||||
## Benchmarks
|
||||
|
||||
The following is a 3-line implementation of the Linux `cat` command.
|
||||
@@ -250,5 +297,15 @@ interface BunFile {
|
||||
stream(): Promise<ReadableStream>;
|
||||
arrayBuffer(): Promise<ArrayBuffer>;
|
||||
json(): Promise<any>;
|
||||
writer(params: { highWaterMark?: number }): FileSink;
|
||||
}
|
||||
|
||||
export interface FileSink {
|
||||
write(chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer): number;
|
||||
flush(): number | Promise<number>;
|
||||
end(error?: Error): number | Promise<number>;
|
||||
start(options?: { highWaterMark?: number }): void;
|
||||
ref(): void;
|
||||
unref(): void;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -4,6 +4,71 @@ Bun implements the `createHash` and `createHmac` functions from [`node:crypto`](
|
||||
|
||||
{% /callout %}
|
||||
|
||||
## `Bun.password`
|
||||
|
||||
{% callout %}
|
||||
**Note** — Added in Bun 0.6.8.
|
||||
{% /callout %}
|
||||
|
||||
`Bun.password` is a collection of utility functions for hashing and verifying passwords with various cryptographically secure algorithms.
|
||||
|
||||
```ts
|
||||
const password = "super-secure-pa$$word";
|
||||
|
||||
const hash = await Bun.password.hash(password);
|
||||
// => $argon2id$v=19$m=65536,t=2,p=1$tFq+9AVr1bfPxQdh6E8DQRhEXg/M/SqYCNu6gVdRRNs$GzJ8PuBi+K+BVojzPfS5mjnC8OpLGtv8KJqF99eP6a4
|
||||
|
||||
const isMatch = await Bun.password.verify(password, hash);
|
||||
// => true
|
||||
```
|
||||
|
||||
The second argument to `Bun.password.hash` accepts a params object that lets you pick and configure the hashing algorithm.
|
||||
|
||||
```ts
|
||||
const password = "super-secure-pa$$word";
|
||||
|
||||
// use argon2 (default)
|
||||
const argonHash = await Bun.password.hash(password, {
|
||||
algorithm: "argon2id", // "argon2id" | "argon2i" | "argon2d"
|
||||
memoryCost: 4, // memory usage in kibibytes
|
||||
timeCost: 3, // the number of iterations
|
||||
});
|
||||
|
||||
// use bcrypt
|
||||
const bcryptHash = await Bun.password.hash(password, {
|
||||
algorithm: "bcrypt",
|
||||
cost: 4, // number between 4-31
|
||||
});
|
||||
```
|
||||
|
||||
The algorithm used to create the hash is stored in the hash itself. When using `bcrypt`, the returned hash is encoded in [Modular Crypt Format](https://passlib.readthedocs.io/en/stable/modular_crypt_format.html) for compatibility with most existing `bcrypt` implementations; with `argon2` the result is encoded in the newer [PHC format](https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md).
|
||||
|
||||
The `verify` function automatically detects the algorithm based on the input hash and use the correct verification method. It can correctly infer the algorithm from both PHC- or MCF-encoded hashes.
|
||||
|
||||
```ts
|
||||
const password = "super-secure-pa$$word";
|
||||
|
||||
const hash = await Bun.password.hash(password, {
|
||||
/* config */
|
||||
});
|
||||
|
||||
const isMatch = await Bun.password.verify(password, hash);
|
||||
// => true
|
||||
```
|
||||
|
||||
Synchronous versions of all functions are also available. Keep in mind that these functions are computationally expensive, so using a blocking API may degrade application performance.
|
||||
|
||||
```ts
|
||||
const password = "super-secure-pa$$word";
|
||||
|
||||
const hash = Bun.password.hashSync(password, {
|
||||
/* config */
|
||||
});
|
||||
|
||||
const isMatch = Bun.password.verifySync(password, hash);
|
||||
// => true
|
||||
```
|
||||
|
||||
## `Bun.hash`
|
||||
|
||||
`Bun.hash` is a collection of utilities for _non-cryptographic_ hashing. Non-cryptographic hashing algorithms are optimized for speed of computation over collision-resistance or security.
|
||||
|
||||
@@ -125,8 +125,7 @@ Bun.serve({
|
||||
// string
|
||||
key: fs.readFileSync("./key.pem", "utf8"),
|
||||
// array of above
|
||||
key: [Bun.file('./key1.pem'), Bun.file('./key2.pem']
|
||||
|
||||
key: [Bun.file('./key1.pem'), Bun.file('./key2.pem')],
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
@@ -75,16 +75,6 @@ Bun.sleepSync(1000); // blocks thread for one second
|
||||
console.log("hello one second later!");
|
||||
```
|
||||
|
||||
Alternatively, pass a `Date` object to receive a `Promise` that resolves at that point in time.
|
||||
|
||||
```ts
|
||||
const oneSecondInFuture = new Date(Date.now() + 1000);
|
||||
|
||||
console.log("hello");
|
||||
await Bun.sleep(oneSecondInFuture);
|
||||
console.log("hello one second later!");
|
||||
```
|
||||
|
||||
## `Bun.which()`
|
||||
|
||||
`Bun.which(bin: string)`
|
||||
|
||||
@@ -12,41 +12,7 @@
|
||||
Internally Bun's WebSocket implementation is built on [uWebSockets](https://github.com/uNetworking/uWebSockets).
|
||||
{% /callout %}
|
||||
|
||||
## Connect to a WebSocket server
|
||||
|
||||
To connect to an external socket server, create an instance of `WebSocket` with the constructor.
|
||||
|
||||
```ts
|
||||
const socket = new WebSocket("ws://localhost:3000");
|
||||
```
|
||||
|
||||
Bun supports setting custom headers. This is a Bun-specific extension of the `WebSocket` standard.
|
||||
|
||||
```ts
|
||||
const socket = new WebSocket("ws://localhost:3000", {
|
||||
headers: {
|
||||
// custom headers
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
To add event listeners to the socket:
|
||||
|
||||
```ts
|
||||
// message is received
|
||||
socket.addEventListener("message", event => {});
|
||||
|
||||
// socket opened
|
||||
socket.addEventListener("open", event => {});
|
||||
|
||||
// socket closed
|
||||
socket.addEventListener("close", event => {});
|
||||
|
||||
// error handler
|
||||
socket.addEventListener("error", event => {});
|
||||
```
|
||||
|
||||
## Create a WebSocket server
|
||||
## Start a WebSocket server
|
||||
|
||||
Below is a simple WebSocket server built with `Bun.serve`, in which all incoming requests are [upgraded](https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism) to WebSocket connections in the `fetch` handler. The socket handlers are declared in the `websocket` parameter.
|
||||
|
||||
@@ -109,7 +75,7 @@ Bun.serve({
|
||||
});
|
||||
```
|
||||
|
||||
## Sending messages
|
||||
### Sending messages
|
||||
|
||||
Each `ServerWebSocket` instance has a `.send()` method for sending messages to the client. It supports a range of input types.
|
||||
|
||||
@@ -119,7 +85,7 @@ ws.send(response.arrayBuffer()); // ArrayBuffer
|
||||
ws.send(new Uint8Array([1, 2, 3])); // TypedArray | DataView
|
||||
```
|
||||
|
||||
## Headers
|
||||
### Headers
|
||||
|
||||
Once the upgrade succeeds, Bun will send a `101 Switching Protocols` response per the [spec](https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism). Additional `headers` can be attched to this `Response` in the call to `server.upgrade()`.
|
||||
|
||||
@@ -137,7 +103,7 @@ Bun.serve({
|
||||
});
|
||||
```
|
||||
|
||||
## Contextual data
|
||||
### Contextual data
|
||||
|
||||
Contextual `data` can be attached to a new WebSocket in the `.upgrade()` call. This data is made available on the `ws.data` property inside the WebSocket handlers.
|
||||
|
||||
@@ -145,16 +111,20 @@ Contextual `data` can be attached to a new WebSocket in the `.upgrade()` call. T
|
||||
type WebSocketData = {
|
||||
createdAt: number;
|
||||
channelId: string;
|
||||
authToken: string;
|
||||
};
|
||||
|
||||
// TypeScript: specify the type of `data`
|
||||
Bun.serve<WebSocketData>({
|
||||
fetch(req, server) {
|
||||
// use a library to parse cookies
|
||||
const cookies = parseCookies(req.headers.get("Cookie"));
|
||||
server.upgrade(req, {
|
||||
// TS: this object must conform to WebSocketData
|
||||
// this object must conform to WebSocketData
|
||||
data: {
|
||||
createdAt: Date.now(),
|
||||
channelId: new URL(req.url).searchParams.get("channelId"),
|
||||
authToken: cookies["X-Token"],
|
||||
},
|
||||
});
|
||||
|
||||
@@ -163,53 +133,76 @@ Bun.serve<WebSocketData>({
|
||||
websocket: {
|
||||
// handler called when a message is received
|
||||
async message(ws, message) {
|
||||
ws.data; // WebSocketData
|
||||
const user = getUserFromToken(ws.data.authToken);
|
||||
|
||||
await saveMessageToDatabase({
|
||||
channel: ws.data.channelId,
|
||||
message: String(message),
|
||||
userId: user.id,
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Pub/Sub
|
||||
To connect to this server from the browser, create a new `WebSocket`.
|
||||
|
||||
```ts#browser.js
|
||||
const socket = new WebSocket("ws://localhost:3000/chat");
|
||||
|
||||
socket.addEventListener("message", event => {
|
||||
console.log(event.data);
|
||||
})
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
**Identifying users** — The cookies that are currently set on the page will be sent with the WebSocket upgrade request and available on `req.headers` in the `fetch` handler. Parse these cookies to determine the identity of the connecting user and set the value of `data` accordingly.
|
||||
{% /callout %}
|
||||
|
||||
### Pub/Sub
|
||||
|
||||
Bun's `ServerWebSocket` implementation implements a native publish-subscribe API for topic-based broadcasting. Individual sockets can `.subscribe()` to a topic (specified with a string identifier) and `.publish()` messages to all other subscribers to that topic. This topic-based broadcast API is similar to [MQTT](https://en.wikipedia.org/wiki/MQTT) and [Redis Pub/Sub](https://redis.io/topics/pubsub).
|
||||
|
||||
```ts
|
||||
const pubsubserver = Bun.serve<{username: string}>({
|
||||
const server = Bun.serve<{ username: string }>({
|
||||
fetch(req, server) {
|
||||
if (req.url === '/chat') {
|
||||
const cookies = getCookieFromRequest(req);
|
||||
const success = server.upgrade(req, {
|
||||
data: {username: cookies.username},
|
||||
});
|
||||
const url = new URL(req.url);
|
||||
if (url.pathname === "/chat") {
|
||||
console.log(`upgrade!`);
|
||||
const username = getUsernameFromReq(req);
|
||||
const success = server.upgrade(req, { data: { username } });
|
||||
return success
|
||||
? undefined
|
||||
: new Response('WebSocket upgrade error', {status: 400});
|
||||
: new Response("WebSocket upgrade error", { status: 400 });
|
||||
}
|
||||
|
||||
return new Response('Hello world');
|
||||
return new Response("Hello world");
|
||||
},
|
||||
websocket: {
|
||||
open(ws) {
|
||||
ws.subscribe('the-group-chat');
|
||||
ws.publish('the-group-chat', `${ws.data.username} has entered the chat`);
|
||||
const msg = `${ws.data.username} has entered the chat`;
|
||||
ws.subscribe("the-group-chat");
|
||||
ws.publish("the-group-chat", msg);
|
||||
},
|
||||
message(ws, message) {
|
||||
// this is a group chat
|
||||
// so the server re-broadcasts incoming message to everyone
|
||||
ws.publish('the-group-chat', `${ws.data.username}: ${message}`);
|
||||
ws.publish("the-group-chat", `${ws.data.username}: ${message}`);
|
||||
},
|
||||
close(ws) {
|
||||
ws.unsubscribe('the-group-chat');
|
||||
ws.publish('the-group-chat', `${ws.data.username} has left the chat`);
|
||||
const msg = `${ws.data.username} has left the chat`;
|
||||
ws.unsubscribe("the-group-chat");
|
||||
ws.publish("the-group-chat", msg);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`Listening on ${server.hostname}:${server.port}`);
|
||||
```
|
||||
|
||||
## Compression
|
||||
Calling `.publish(data)` will send the message to all subscribers of a topic _except_ the socket that called `.publish()`.
|
||||
|
||||
### Compression
|
||||
|
||||
Per-message [compression](https://websockets.readthedocs.io/en/stable/topics/compression.html) can be enabled with the `perMessageDeflate` parameter.
|
||||
|
||||
@@ -231,7 +224,7 @@ ws.send("Hello world", true);
|
||||
|
||||
For fine-grained control over compression characteristics, refer to the [Reference](#reference).
|
||||
|
||||
## Backpressure
|
||||
### Backpressure
|
||||
|
||||
The `.send(message)` method of `ServerWebSocket` returns a `number` indicating the result of the operation.
|
||||
|
||||
@@ -241,6 +234,42 @@ The `.send(message)` method of `ServerWebSocket` returns a `number` indicating t
|
||||
|
||||
This gives you better control over backpressure in your server.
|
||||
|
||||
## Connect to a `Websocket` server
|
||||
|
||||
To connect to an external socket server, either from a browser or from Bun, create an instance of `WebSocket` with the constructor.
|
||||
|
||||
```ts
|
||||
const socket = new WebSocket("ws://localhost:3000");
|
||||
```
|
||||
|
||||
In browsers, the cookies that are currently set on the page will be sent with the WebSocket upgrade request. This is a standard feature of the `WebSocket` API.
|
||||
|
||||
For convenience, Bun lets you setting custom headers directly in the constructor. This is a Bun-specific extension of the `WebSocket` standard. _This will not work in browsers._
|
||||
|
||||
```ts
|
||||
const socket = new WebSocket("ws://localhost:3000", {
|
||||
headers: {
|
||||
// custom headers
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
To add event listeners to the socket:
|
||||
|
||||
```ts
|
||||
// message is received
|
||||
socket.addEventListener("message", event => {});
|
||||
|
||||
// socket opened
|
||||
socket.addEventListener("open", event => {});
|
||||
|
||||
// socket closed
|
||||
socket.addEventListener("close", event => {});
|
||||
|
||||
// error handler
|
||||
socket.addEventListener("error", event => {});
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
```ts
|
||||
@@ -248,7 +277,10 @@ namespace Bun {
|
||||
export function serve(params: {
|
||||
fetch: (req: Request, server: Server) => Response | Promise<Response>;
|
||||
websocket?: {
|
||||
message: (ws: ServerWebSocket, message: string | ArrayBuffer | Uint8Array) => void;
|
||||
message: (
|
||||
ws: ServerWebSocket,
|
||||
message: string | ArrayBuffer | Uint8Array,
|
||||
) => void;
|
||||
open?: (ws: ServerWebSocket) => void;
|
||||
close?: (ws: ServerWebSocket) => void;
|
||||
error?: (ws: ServerWebSocket, error: Error) => void;
|
||||
@@ -278,7 +310,11 @@ type Compressor =
|
||||
|
||||
interface Server {
|
||||
pendingWebsockets: number;
|
||||
publish(topic: string, data: string | ArrayBufferView | ArrayBuffer, compress?: boolean): number;
|
||||
publish(
|
||||
topic: string,
|
||||
data: string | ArrayBufferView | ArrayBuffer,
|
||||
compress?: boolean,
|
||||
): number;
|
||||
upgrade(
|
||||
req: Request,
|
||||
options?: {
|
||||
|
||||
@@ -185,7 +185,7 @@ $ cd /path/to/my-app
|
||||
$ bun link cool-pkg
|
||||
```
|
||||
|
||||
This will add `cool-pkg` to the `dependencies` field of your app's package.json with a special version specifier that tells Bun to load from the registered local directory instead of installing from `npm`.
|
||||
In addition, the `--save` flag can be used to add `cool-pkg` to the `dependencies` field of your app's package.json with a special version specifier that tells Bun to load from the registered local directory instead of installing from `npm`:
|
||||
|
||||
```json-diff
|
||||
{
|
||||
|
||||
@@ -102,7 +102,7 @@ To debug environment variables, run `bun run env` to view a list of resolved env
|
||||
|
||||
Bun is designed to start fast and run fast.
|
||||
|
||||
Under the hood Bun uses the [JavaScriptCore engine](https://developer.apple.com/documentation/javascriptcore), which is developed by Apple for Safari. In most cases, the startup and running performance is faster than V8, the engine used by Node.js and Chromium-based browsers. It's transpiler and runtime are written in Zig, a modern, high-performance language. On Linux, this translates into startup times [4x faster](https://twitter.com/jarredsumner/status/1499225725492076544) than Node.js.
|
||||
Under the hood Bun uses the [JavaScriptCore engine](https://developer.apple.com/documentation/javascriptcore), which is developed by Apple for Safari. In most cases, the startup and running performance is faster than V8, the engine used by Node.js and Chromium-based browsers. Its transpiler and runtime are written in Zig, a modern, high-performance language. On Linux, this translates into startup times [4x faster](https://twitter.com/jarredsumner/status/1499225725492076544) than Node.js.
|
||||
|
||||
{% image src="/images/bun-run-speed.jpeg" caption="Bun vs Node.js vs Deno running Hello World" /%}
|
||||
|
||||
|
||||
@@ -77,6 +77,8 @@ Bun is compatible with popular UI testing libraries:
|
||||
- [DOM Testing Library](https://testing-library.com/docs/dom-testing-library/intro/)
|
||||
- [React Testing Library](https://testing-library.com/docs/react-testing-library/intro)
|
||||
|
||||
See [Test > DOM Testing](/docs/test/dom) for complete documentation.
|
||||
|
||||
## Performance
|
||||
|
||||
Bun's test runner is fast.
|
||||
|
||||
@@ -190,6 +190,9 @@ export default {
|
||||
page("test/snapshots", "Snapshots", {
|
||||
description: "Add lifecycle hooks to your tests that run before/after each test or test run",
|
||||
}),
|
||||
page("test/dom", "DOM testing", {
|
||||
description: "Write headless tests for UI and React/Vue/Svelte/Lit components with happy-dom",
|
||||
}),
|
||||
page("test/hot", "Watch mode", {
|
||||
description: "Reload your tests automatically on change.",
|
||||
}),
|
||||
|
||||
@@ -42,7 +42,7 @@ $ brew install llvm@15
|
||||
|
||||
```bash#Ubuntu/Debian
|
||||
# On Ubuntu 22.04 and newer, LLVM 15 is available in the default repositories
|
||||
$ sudo apt install llvm-15 lld-15
|
||||
$ sudo apt install llvm-15 lld-15 clang-15
|
||||
# On older versions,
|
||||
$ wget https://apt.llvm.org/llvm.sh -O - | sudo bash -s -- 15 all
|
||||
```
|
||||
@@ -102,7 +102,7 @@ Zig can be installed either with our npm package [`@oven/zig`](https://www.npmjs
|
||||
|
||||
```bash
|
||||
$ bun install -g @oven/zig
|
||||
$ zigup master
|
||||
$ zigup 0.11.0-dev.3737+9eb008717
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
@@ -108,8 +108,8 @@ Once it finds the `foo` package, Bun reads the `package.json` to determine how t
|
||||
"worker": "./index.js",
|
||||
"module": "./index.js",
|
||||
"node": "./index.js",
|
||||
"browser": "./index.js",
|
||||
"default": "./index.js" // lowest priority
|
||||
"default": "./index.js",
|
||||
"browser": "./index.js" // lowest priority
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
75
docs/test/dom.md
Normal file
75
docs/test/dom.md
Normal file
@@ -0,0 +1,75 @@
|
||||
Bun's test runner plays well with existing component and DOM testing libraries, including React Testing Library and [`happy-dom`](https://github.com/capricorn86/happy-dom).
|
||||
|
||||
## `happy-dom`
|
||||
|
||||
For writing headless tests for your frontend code and components, we recommend [`happy-dom`](https://github.com/capricorn86/happy-dom). Happy DOM implements a complete set of HTML and DOM APIs in plain JavaScript, making it possible to simulate a browser environment with high fidelity.
|
||||
|
||||
To get started install the `@happy-dom/global-registrator` package as a dev dependency.
|
||||
|
||||
```bash
|
||||
$ bun add -d @happy-dom/global-registrator
|
||||
```
|
||||
|
||||
We'll be using Bun's _preload_ functionality to register the `happy-dom` globals before running our tests. This step will make browser APIs like `document` available in the global scope. Create a file called `happydom.ts` in the root of your project and add the following code:
|
||||
|
||||
```ts
|
||||
import { GlobalRegistrator } from "@happy-dom/global-registrator";
|
||||
|
||||
GlobalRegistrator.register();
|
||||
```
|
||||
|
||||
To preload this file before `bun test`, open or create a `bunfig.toml` file and add the following lines.
|
||||
|
||||
```toml
|
||||
[test]
|
||||
preload = "./happydom.ts"
|
||||
```
|
||||
|
||||
This will execute `happydom.ts` when you run `bun test`. Now you can write tests that use browser APIs like `document` and `window`.
|
||||
|
||||
```ts#dom.test.ts
|
||||
import {test, expect} from 'bun:test';
|
||||
|
||||
test('dom test', () => {
|
||||
document.body.innerHTML = `<button>My button</button>`;
|
||||
const button = document.querySelector('button');
|
||||
expect(button?.innerText).toEqual('My button');
|
||||
});
|
||||
```
|
||||
|
||||
Depending on your `tsconfig.json` setup, you may see a `"Cannot find name 'document'"` type error in the code above. To "inject" the types for `document` and other browser APIs, add the following [triple-slash directive](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html) to the top of any test file.
|
||||
|
||||
```ts-diff#dom.test.ts
|
||||
+ /// <reference lib="dom" />
|
||||
|
||||
import {test, expect} from 'bun:test';
|
||||
|
||||
test('dom test', () => {
|
||||
document.body.innerHTML = `<button>My button</button>`;
|
||||
const button = document.querySelector('button');
|
||||
expect(button?.innerText).toEqual('My button');
|
||||
});
|
||||
```
|
||||
|
||||
Let's run this test with `bun test`:
|
||||
|
||||
```bash
|
||||
$ bun test
|
||||
bun test v0.x.y
|
||||
|
||||
dom.test.ts:
|
||||
✓ dom test [0.82ms]
|
||||
|
||||
1 pass
|
||||
0 fail
|
||||
1 expect() calls
|
||||
Ran 1 tests across 1 files. 1 total [125.00ms]
|
||||
```
|
||||
|
||||
<!-- ## React Testing Library
|
||||
|
||||
Once you've set up `happy-dom` as described above, you can use it with React Testing Library. To get started, install the `@testing-library/react` package as a dev dependency.
|
||||
|
||||
```bash
|
||||
$ bun add -d @testing-library/react
|
||||
``` -->
|
||||
@@ -167,12 +167,12 @@ Bun implements the following matchers. Full Jest compatibility is on the roadmap
|
||||
|
||||
---
|
||||
|
||||
- 🔴
|
||||
- 🟢
|
||||
- [`.anything()`](https://jestjs.io/docs/expect#expectanything)
|
||||
|
||||
---
|
||||
|
||||
- 🔴
|
||||
- 🟢
|
||||
- [`.any()`](https://jestjs.io/docs/expect#expectanyconstructor)
|
||||
|
||||
---
|
||||
@@ -202,12 +202,12 @@ Bun implements the following matchers. Full Jest compatibility is on the roadmap
|
||||
|
||||
---
|
||||
|
||||
- 🔴
|
||||
- 🟢
|
||||
- [`.stringContaining()`](https://jestjs.io/docs/expect#expectstringcontainingstring)
|
||||
|
||||
---
|
||||
|
||||
- 🔴
|
||||
- 🟢
|
||||
- [`.stringMatching()`](https://jestjs.io/docs/expect#expectstringmatchingstring--regexp)
|
||||
|
||||
---
|
||||
@@ -227,12 +227,12 @@ Bun implements the following matchers. Full Jest compatibility is on the roadmap
|
||||
|
||||
---
|
||||
|
||||
- 🔴
|
||||
- 🟢
|
||||
- [`.toHaveBeenCalled()`](https://jestjs.io/docs/expect#tohavebeencalled)
|
||||
|
||||
---
|
||||
|
||||
- 🔴
|
||||
- 🟢
|
||||
- [`.toHaveBeenCalledTimes()`](https://jestjs.io/docs/expect#tohavebeencalledtimesnumber)
|
||||
|
||||
---
|
||||
@@ -312,12 +312,12 @@ Bun implements the following matchers. Full Jest compatibility is on the roadmap
|
||||
|
||||
---
|
||||
|
||||
- 🔴
|
||||
- 🟢
|
||||
- [`.toMatch()`](https://jestjs.io/docs/expect#tomatchregexp--string)
|
||||
|
||||
---
|
||||
|
||||
- 🔴
|
||||
- 🟢
|
||||
- [`.toMatchObject()`](https://jestjs.io/docs/expect#tomatchobjectobject)
|
||||
|
||||
---
|
||||
|
||||
@@ -3,7 +3,8 @@ import { parse } from "querystring";
|
||||
|
||||
export default {
|
||||
fetch(req) {
|
||||
if (req.url === "/favicon.ico") return new Response("nooo dont open favicon in editor", { status: 404 });
|
||||
const url = new URL(req.url);
|
||||
if (url.pathname === "/favicon.ico") return new Response("nooo dont open favicon in editor", { status: 404 });
|
||||
|
||||
var pathname = req.url.substring(1);
|
||||
const q = pathname.indexOf("?");
|
||||
|
||||
@@ -91,7 +91,7 @@ pub const Arguments = struct {
|
||||
var raw_args: std.ArrayListUnmanaged(string) = undefined;
|
||||
|
||||
if (positionals.len > 0) {
|
||||
raw_args = .{ .capacity = positionals.len, .items = @intToPtr([*][]const u8, @ptrToInt(positionals.ptr))[0..positionals.len] };
|
||||
raw_args = .{ .capacity = positionals.len, .items = @ptrFromInt([*][]const u8, @intFromPtr(positionals.ptr))[0..positionals.len] };
|
||||
} else {
|
||||
raw_args = .{};
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ pub const Arguments = struct {
|
||||
var raw_args: std.ArrayListUnmanaged(string) = undefined;
|
||||
|
||||
if (positionals.len > 0) {
|
||||
raw_args = .{ .capacity = positionals.len, .items = @intToPtr([*][]const u8, @ptrToInt(positionals.ptr))[0..positionals.len] };
|
||||
raw_args = .{ .capacity = positionals.len, .items = @ptrFromInt([*][]const u8, @intFromPtr(positionals.ptr))[0..positionals.len] };
|
||||
} else {
|
||||
raw_args = .{};
|
||||
}
|
||||
@@ -244,7 +244,7 @@ pub fn main() anyerror!void {
|
||||
const http = channel.readItem() catch continue;
|
||||
read_count += 1;
|
||||
|
||||
Output.printElapsed(@floatCast(f64, @intToFloat(f128, http.elapsed) / std.time.ns_per_ms));
|
||||
Output.printElapsed(@floatCast(f64, @floatFromInt(f128, http.elapsed) / std.time.ns_per_ms));
|
||||
if (http.response) |resp| {
|
||||
if (resp.status_code == 200) {
|
||||
success_count += 1;
|
||||
@@ -270,7 +270,7 @@ pub fn main() anyerror!void {
|
||||
http.client.url.href,
|
||||
http.response_buffer.list.items.len,
|
||||
});
|
||||
Output.printElapsed(@floatCast(f64, @intToFloat(f128, http.gzip_elapsed) / std.time.ns_per_ms));
|
||||
Output.printElapsed(@floatCast(f64, @floatFromInt(f128, http.gzip_elapsed) / std.time.ns_per_ms));
|
||||
Output.prettyError("<d> gzip)<r>\n", .{});
|
||||
} else {
|
||||
Output.prettyError(" <d>{s}<r><d> - {s}<r> <d>({d} bytes)<r>\n", .{
|
||||
@@ -295,7 +295,7 @@ pub fn main() anyerror!void {
|
||||
fail_count,
|
||||
});
|
||||
|
||||
Output.printElapsed(@floatCast(f64, @intToFloat(f128, timer.read()) / std.time.ns_per_ms));
|
||||
Output.printElapsed(@floatCast(f64, @floatFromInt(f128, timer.read()) / std.time.ns_per_ms));
|
||||
Output.prettyErrorln(" {d} requests", .{
|
||||
read_count,
|
||||
});
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"@types/react": "^18.0.25",
|
||||
"@typescript-eslint/eslint-plugin": "^5.31.0",
|
||||
"@typescript-eslint/parser": "^5.31.0",
|
||||
"bun-webkit": "0.0.1-b2f1006a06f81bc860c89dd4c7cec3e7117c4c4c"
|
||||
"bun-webkit": "0.0.1-4b3750ddfe644a5bb131d652407653fac528ad51"
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"prettier": "./.prettierrc.cjs"
|
||||
|
||||
169
packages/bun-devtools/.gitignore
vendored
169
packages/bun-devtools/.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,3 +0,0 @@
|
||||
# bun-devtools
|
||||
|
||||
A set of auto-generated TypeScript types for the WebKit debugger protocol.
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
14
packages/bun-devtools/heap/jsc.d.ts
vendored
14
packages/bun-devtools/heap/jsc.d.ts
vendored
@@ -1,14 +0,0 @@
|
||||
export namespace JSC {
|
||||
/**
|
||||
* @link https://github.com/WebKit/webkit/blob/main/Source/JavaScriptCore/heap/HeapSnapshotBuilder.h
|
||||
*/
|
||||
export type HeapSnapshot = {
|
||||
version: 2;
|
||||
type: "Inspector";
|
||||
nodes: number[];
|
||||
nodeClassNames: string[];
|
||||
edges: number[];
|
||||
edgeTypes: string[];
|
||||
edgeNames: string[];
|
||||
};
|
||||
}
|
||||
30
packages/bun-devtools/heap/v8.d.ts
vendored
30
packages/bun-devtools/heap/v8.d.ts
vendored
@@ -1,30 +0,0 @@
|
||||
export namespace V8 {
|
||||
/**
|
||||
* @link https://github.com/julianburr/chrome-heap-snapshot-parser/blob/master/index.js#L72
|
||||
* @link https://stackoverflow.com/questions/69802133/chrome-heap-snapshot-structure-explanation
|
||||
*/
|
||||
export type HeapSnapshot = {
|
||||
snapshot: {
|
||||
meta: {
|
||||
node_fields: string[];
|
||||
node_types: [string[], ...string[]]; // ?
|
||||
edge_fields: string[];
|
||||
edge_types: [string[], ...string[]]; // ?
|
||||
trace_function_info_fields: string[];
|
||||
trace_node_fields: string[];
|
||||
sample_fields: string[];
|
||||
location_fields: string[];
|
||||
node_count: number;
|
||||
edge_count: number;
|
||||
trace_function_count: number;
|
||||
};
|
||||
};
|
||||
nodes: number[];
|
||||
edges: number[];
|
||||
trace_tree: unknown[];
|
||||
trace_function_infos: unknown[];
|
||||
samples: unknown[];
|
||||
locations: number[];
|
||||
strings: string[];
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
export * from "./protocol/jsc";
|
||||
export * from "./protocol/v8";
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"name": "bun-devtools",
|
||||
"module": "./index.ts",
|
||||
"version": "0.0.2",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./index.ts",
|
||||
"require": "./index.ts"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"generate-protocol": "bun run scripts/generate-protocol.ts"
|
||||
},
|
||||
"files": [
|
||||
"index.ts",
|
||||
"package.json",
|
||||
"tsconfig.json",
|
||||
"protocol"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.0.0"
|
||||
}
|
||||
}
|
||||
1953
packages/bun-devtools/protocol/jsc.d.ts
vendored
1953
packages/bun-devtools/protocol/jsc.d.ts
vendored
File diff suppressed because it is too large
Load Diff
3422
packages/bun-devtools/protocol/v8.d.ts
vendored
3422
packages/bun-devtools/protocol/v8.d.ts
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,129 +0,0 @@
|
||||
// A DevTools client for JavaScriptCore.
|
||||
|
||||
import type { JSC } from "..";
|
||||
|
||||
type ClientOptions = {
|
||||
url: string | URL;
|
||||
event?: (event: JSC.Event<keyof JSC.EventMap>) => void;
|
||||
request?: (request: JSC.Request<keyof JSC.RequestMap>) => void;
|
||||
response?: (response: JSC.Response<keyof JSC.ResponseMap>) => void;
|
||||
};
|
||||
|
||||
class Client {
|
||||
#webSocket: WebSocket;
|
||||
#requestId: number;
|
||||
#pendingMessages: string[];
|
||||
#pendingRequests: Map<number, AbortController>;
|
||||
#ready: Promise<void>;
|
||||
|
||||
constructor(options: ClientOptions) {
|
||||
this.#webSocket = new WebSocket(options.url);
|
||||
this.#requestId = 1;
|
||||
this.#pendingMessages = [];
|
||||
this.#pendingRequests = new Map();
|
||||
this.#ready = new Promise((resolve, reject) => {
|
||||
this.#webSocket.addEventListener("open", () => {
|
||||
for (const message of this.#pendingMessages) {
|
||||
this.#send(message);
|
||||
}
|
||||
this.#pendingMessages.length = 0;
|
||||
resolve();
|
||||
});
|
||||
this.#webSocket.addEventListener("message", ({ data }) => {
|
||||
let response;
|
||||
try {
|
||||
response = { ...JSON.parse(data) };
|
||||
} catch {
|
||||
console.error("Received an invalid message:", data);
|
||||
return;
|
||||
}
|
||||
const { id, error, result, method, params } = response;
|
||||
if (method && params) {
|
||||
options.event?.(response);
|
||||
} else if (id && (result || error)) {
|
||||
try {
|
||||
options.response?.(response);
|
||||
} finally {
|
||||
const abort = this.#pendingRequests.get(id ?? -1);
|
||||
if (!abort) {
|
||||
console.error("Received an unexpected message:", response);
|
||||
return;
|
||||
}
|
||||
if (error) {
|
||||
abort.abort(new Error(JSON.stringify(error)));
|
||||
} else {
|
||||
abort.abort(result);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.error("Received an unexpected message:", response);
|
||||
}
|
||||
});
|
||||
this.#webSocket.addEventListener("error", (error) => {
|
||||
reject(error);
|
||||
});
|
||||
this.#webSocket.addEventListener("close", ({ code, reason = ""}) => {
|
||||
reject(new Error(`WebSocket closed: ${code} ${reason}`.trimEnd()));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
get ready(): Promise<void> {
|
||||
return this.#ready;
|
||||
}
|
||||
|
||||
#send(message: string): void {
|
||||
const { readyState } = this.#webSocket;
|
||||
if (readyState === WebSocket.OPEN) {
|
||||
this.#webSocket.send(message);
|
||||
} else if (readyState === WebSocket.CONNECTING) {
|
||||
this.#pendingMessages.push(message);
|
||||
} else {
|
||||
const closed = readyState === WebSocket.CLOSING ? "closing" : "closed";
|
||||
throw new Error(`WebSocket is ${closed}`);
|
||||
}
|
||||
}
|
||||
|
||||
async fetch<T extends keyof JSC.RequestMap>(method: T, params: JSC.Request<T>["params"]): Promise<JSC.Response<T>> {
|
||||
const request: JSC.Request<T> = {
|
||||
id: this.#requestId++,
|
||||
method,
|
||||
params,
|
||||
};
|
||||
return new Promise((resolve, reject) => {
|
||||
const abort = new AbortController();
|
||||
abort.signal.addEventListener("abort", () => {
|
||||
this.#pendingRequests.delete(request.id);
|
||||
const { reason } = abort.signal;
|
||||
if (reason instanceof Error) {
|
||||
reject(reason);
|
||||
} else {
|
||||
resolve(reason);
|
||||
}
|
||||
});
|
||||
this.#pendingRequests.set(request.id, abort);
|
||||
this.#send(JSON.stringify(request));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const client = new Client({
|
||||
url: "ws://localhost:9229",
|
||||
event: (event) => console.log("EVENT:", event),
|
||||
request: (request) => console.log("REQUEST:", request),
|
||||
response: (response) => console.log("RESPONSE:", response),
|
||||
});
|
||||
await client.ready;
|
||||
|
||||
while (true) {
|
||||
const [method, ...param] = prompt(">")?.split(" ") ?? [];
|
||||
if (!method.trim()) {
|
||||
continue;
|
||||
}
|
||||
const params = !param?.length ? {} : JSON.parse(eval(`JSON.stringify(${param.join(" ")})`));
|
||||
try {
|
||||
await client.fetch(method.trim() as any, params);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
@@ -1,255 +0,0 @@
|
||||
import { join } from "node:path";
|
||||
import { writeFileSync, mkdirSync } from "node:fs";
|
||||
import { spawnSync } from "node:child_process";
|
||||
|
||||
async function download<V>(url: string): Promise<V> {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`${response.status}: ${url}`);
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
type Protocol = {
|
||||
name: string;
|
||||
version: {
|
||||
major: number;
|
||||
minor: number;
|
||||
};
|
||||
domains: Domain[];
|
||||
};
|
||||
|
||||
type Domain = {
|
||||
domain: string;
|
||||
types: Property[];
|
||||
commands?: {
|
||||
name: string;
|
||||
description?: string;
|
||||
parameters?: Property[];
|
||||
returns?: Property[];
|
||||
}[];
|
||||
events?: {
|
||||
name: string;
|
||||
description?: string;
|
||||
parameters: Property[];
|
||||
}[];
|
||||
};
|
||||
|
||||
type Property = {
|
||||
id?: string;
|
||||
type?: string;
|
||||
name?: string;
|
||||
description?: string;
|
||||
optional?: boolean;
|
||||
} & (
|
||||
| {
|
||||
type: "array";
|
||||
items?: Property;
|
||||
}
|
||||
| {
|
||||
type: "object";
|
||||
properties?: Property[];
|
||||
}
|
||||
| {
|
||||
type: "string";
|
||||
enum?: string[];
|
||||
}
|
||||
| {
|
||||
$ref: string;
|
||||
}
|
||||
);
|
||||
|
||||
function format(property: Property): string {
|
||||
if (property.id) {
|
||||
const comment = property.description
|
||||
? `/** ${property.description} */\n`
|
||||
: "";
|
||||
const body = format({ ...property, id: undefined });
|
||||
return `${comment}export type ${property.id} = ${body};\n`;
|
||||
}
|
||||
if (property.type === "array") {
|
||||
const type = "items" in property ? format(property.items!) : "unknown";
|
||||
return `Array<${type}>`;
|
||||
}
|
||||
if (property.type === "object") {
|
||||
if (!("properties" in property)) {
|
||||
return "Record<string, unknown>";
|
||||
}
|
||||
if (property.properties!.length === 0) {
|
||||
return "{}";
|
||||
}
|
||||
const properties = property
|
||||
.properties!.map((property) => {
|
||||
const comment = property.description
|
||||
? `/** ${property.description} */\n`
|
||||
: "";
|
||||
const name = `${property.name}${property.optional ? "?" : ""}`;
|
||||
return `${comment} ${name}: ${format(property)};`;
|
||||
})
|
||||
.join("\n");
|
||||
return `{\n${properties}}`;
|
||||
}
|
||||
if (property.type === "string") {
|
||||
if (!("enum" in property)) {
|
||||
return "string";
|
||||
}
|
||||
return property.enum!.map((v) => `"${v}"`).join(" | ");
|
||||
}
|
||||
if ("$ref" in property) {
|
||||
if (/^Page|DOM|Security|CSS|IO|Emulation\./.test(property.$ref)) {
|
||||
return "unknown";
|
||||
}
|
||||
return property.$ref;
|
||||
}
|
||||
if (property.type === "integer") {
|
||||
return "number";
|
||||
}
|
||||
return property.type;
|
||||
}
|
||||
|
||||
function formatAll(protocol: Protocol): string {
|
||||
let body = "";
|
||||
const append = (property: Property) => {
|
||||
body += format(property);
|
||||
};
|
||||
const titlize = (name: string) =>
|
||||
name.charAt(0).toUpperCase() + name.slice(1);
|
||||
const events = new Map();
|
||||
const commands = new Map();
|
||||
for (const domain of protocol.domains) {
|
||||
body += `export namespace ${domain.domain} {`;
|
||||
for (const type of domain.types ?? []) {
|
||||
append(type);
|
||||
}
|
||||
for (const event of domain.events ?? []) {
|
||||
const symbol = `${domain.domain}.${event.name}`;
|
||||
const title = titlize(event.name);
|
||||
events.set(symbol, `${domain.domain}.${title}`);
|
||||
append({
|
||||
id: `${title}Event`,
|
||||
type: "object",
|
||||
description: `\`${symbol}\``,
|
||||
properties: event.parameters ?? [],
|
||||
});
|
||||
}
|
||||
for (const command of domain.commands ?? []) {
|
||||
const symbol = `${domain.domain}.${command.name}`;
|
||||
const title = titlize(command.name);
|
||||
commands.set(symbol, `${domain.domain}.${title}`);
|
||||
append({
|
||||
id: `${title}Request`,
|
||||
type: "object",
|
||||
description: `\`${symbol}\``,
|
||||
properties: command.parameters ?? [],
|
||||
});
|
||||
append({
|
||||
id: `${title}Response`,
|
||||
type: "object",
|
||||
description: `\`${symbol}\``,
|
||||
properties: command.returns ?? [],
|
||||
});
|
||||
}
|
||||
body += "};";
|
||||
}
|
||||
for (const type of ["Event", "Request", "Response"]) {
|
||||
const source = type === "Event" ? events : commands;
|
||||
append({
|
||||
id: `${type}Map`,
|
||||
type: "object",
|
||||
properties: [...source.entries()].map(([name, title]) => ({
|
||||
name: `"${name}"`,
|
||||
$ref: `${title}${type}`,
|
||||
})),
|
||||
});
|
||||
}
|
||||
body += `export type Event<T extends keyof EventMap> = {
|
||||
method: T;
|
||||
params: EventMap[T];
|
||||
};
|
||||
export type Request<T extends keyof RequestMap> = {
|
||||
id: number;
|
||||
method: T;
|
||||
params: RequestMap[T];
|
||||
};
|
||||
export type Response<T extends keyof ResponseMap> = {
|
||||
id: number;
|
||||
} & ({
|
||||
method?: T;
|
||||
result: ResponseMap[T];
|
||||
} | {
|
||||
error: {
|
||||
code?: string;
|
||||
message: string;
|
||||
};
|
||||
});`;
|
||||
return `export namespace ${protocol.name.toUpperCase()} {${body}};`;
|
||||
}
|
||||
|
||||
async function downloadV8(): Promise<Protocol> {
|
||||
const baseUrl =
|
||||
"https://raw.githubusercontent.com/ChromeDevTools/devtools-protocol/master/json";
|
||||
const filter = [
|
||||
"Runtime",
|
||||
"Network",
|
||||
"Console",
|
||||
"Debugger",
|
||||
"Profiler",
|
||||
"HeapProfiler",
|
||||
];
|
||||
return Promise.all([
|
||||
download<Protocol>(`${baseUrl}/js_protocol.json`),
|
||||
download<Protocol>(`${baseUrl}/browser_protocol.json`),
|
||||
]).then(([js, browser]) => ({
|
||||
name: "v8",
|
||||
version: js.version,
|
||||
domains: [...js.domains, ...browser.domains]
|
||||
.filter((domain) => filter.includes(domain.domain))
|
||||
.sort((a, b) => a.domain.localeCompare(b.domain)),
|
||||
}));
|
||||
}
|
||||
|
||||
async function downloadJsc(): Promise<Protocol> {
|
||||
const baseUrl =
|
||||
"https://raw.githubusercontent.com/WebKit/WebKit/main/Source/JavaScriptCore/inspector/protocol";
|
||||
return {
|
||||
name: "jsc",
|
||||
version: {
|
||||
major: 1,
|
||||
minor: 3,
|
||||
},
|
||||
domains: await Promise.all([
|
||||
download<Domain>(`${baseUrl}/Debugger.json`),
|
||||
download<Domain>(`${baseUrl}/Heap.json`),
|
||||
download<Domain>(`${baseUrl}/ScriptProfiler.json`),
|
||||
download<Domain>(`${baseUrl}/Runtime.json`),
|
||||
download<Domain>(`${baseUrl}/Network.json`),
|
||||
download<Domain>(`${baseUrl}/Console.json`),
|
||||
download<Domain>(`${baseUrl}/GenericTypes.json`),
|
||||
]).then((domains) =>
|
||||
domains.sort((a, b) => a.domain.localeCompare(b.domain))
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
async function run(cwd: string) {
|
||||
const [jsc, v8] = await Promise.all([downloadJsc(), downloadV8()]);
|
||||
try {
|
||||
mkdirSync(cwd);
|
||||
} catch (error) {
|
||||
if (error.code !== "EEXIST") {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
const write = (name: string, data: string) => {
|
||||
writeFileSync(join(cwd, name), data);
|
||||
spawnSync("bunx", ["prettier", "--write", name], { cwd, stdio: "ignore" });
|
||||
};
|
||||
// Note: Can be uncommented to inspect the JSON protocol files.
|
||||
// write("devtools/jsc.json", JSON.stringify(jsc));
|
||||
// write("devtools/v8.json", JSON.stringify(v8));
|
||||
write("jsc.d.ts", "// GENERATED - DO NOT EDIT\n" + formatAll(jsc));
|
||||
write("v8.d.ts", "// GENERATED - DO NOT EDIT\n" + formatAll(v8));
|
||||
}
|
||||
|
||||
run(join(__dirname, "..", "protocol"))
|
||||
.catch(console.error);
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext"],
|
||||
"module": "esnext",
|
||||
"target": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"moduleDetection": "force",
|
||||
"allowImportingTsExtensions": true,
|
||||
"strict": true,
|
||||
"downlevelIteration": true,
|
||||
"skipLibCheck": true,
|
||||
"jsx": "preserve",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"allowJs": true,
|
||||
"noEmit": true
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,17 @@ import { fsyncSync, rmSync, writeFileSync, writeSync } from "fs";
|
||||
import { readdirSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
import { StringDecoder } from "node:string_decoder";
|
||||
import { totalmem } from "os";
|
||||
import { relative } from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const nativeMemory = totalmem();
|
||||
const BUN_JSC_forceRAMSizeNumber = parseInt(process.env["BUN_JSC_forceRAMSize"] || "0", 10);
|
||||
let BUN_JSC_forceRAMSize = Number(BigInt(nativeMemory) >> BigInt(2)) + "";
|
||||
if (!(Number.isSafeInteger(BUN_JSC_forceRAMSizeNumber) && BUN_JSC_forceRAMSizeNumber > 0)) {
|
||||
BUN_JSC_forceRAMSize = BUN_JSC_forceRAMSizeNumber + "";
|
||||
}
|
||||
|
||||
const cwd = resolve(fileURLToPath(import.meta.url), "../../../../");
|
||||
process.chdir(cwd);
|
||||
|
||||
@@ -39,6 +47,8 @@ async function runTest(path) {
|
||||
env: {
|
||||
...process.env,
|
||||
FORCE_COLOR: "1",
|
||||
BUN_GARBAGE_COLLECTOR_LEVEL: "1",
|
||||
BUN_JSC_forceRAMSize,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
|
||||
589
packages/bun-types/bun-test.d.ts
vendored
589
packages/bun-types/bun-test.d.ts
vendored
@@ -15,6 +15,77 @@
|
||||
*/
|
||||
|
||||
declare module "bun:test" {
|
||||
type AnyFunction = (...args: any) => any;
|
||||
/**
|
||||
* -- Mocks --
|
||||
*/
|
||||
export interface Mock<T extends AnyFunction>
|
||||
extends JestMock.MockInstance<T> {
|
||||
(...args: Parameters<T>): ReturnType<T>;
|
||||
}
|
||||
type _Mock<T extends AnyFunction> = Mock<T>;
|
||||
|
||||
export const mock: {
|
||||
<T extends AnyFunction>(Function: T): Mock<T>;
|
||||
};
|
||||
|
||||
interface Jest {
|
||||
restoreAllMocks(): void;
|
||||
fn<T extends AnyFunction>(func?: T): Mock<T>;
|
||||
}
|
||||
export const jest: Jest;
|
||||
export namespace jest {
|
||||
/**
|
||||
* Constructs the type of a mock function, e.g. the return type of `jest.fn()`.
|
||||
*/
|
||||
type Mock<T extends AnyFunction = AnyFunction> = _Mock<T>;
|
||||
/**
|
||||
* Wraps a class, function or object type with Jest mock type definitions.
|
||||
*/
|
||||
// type Mocked<T extends object> = JestMock.Mocked<T>;
|
||||
/**
|
||||
* Wraps a class type with Jest mock type definitions.
|
||||
*/
|
||||
// type MockedClass<T extends JestMock.ClassLike> = JestMock.MockedClass<T>;
|
||||
/**
|
||||
* Wraps a function type with Jest mock type definitions.
|
||||
*/
|
||||
// type MockedFunction<T extends AnyFunction> = JestMock.MockedFunction<T>;
|
||||
/**
|
||||
* Wraps an object type with Jest mock type definitions.
|
||||
*/
|
||||
// type MockedObject<T extends object> = JestMock.MockedObject<T>;
|
||||
/**
|
||||
* Constructs the type of a replaced property.
|
||||
*/
|
||||
type Replaced<T> = JestMock.Replaced<T>;
|
||||
/**
|
||||
* Constructs the type of a spied class or function.
|
||||
*/
|
||||
type Spied<T extends JestMock.ClassLike | AnyFunction> = JestMock.Spied<T>;
|
||||
/**
|
||||
* Constructs the type of a spied class.
|
||||
*/
|
||||
type SpiedClass<T extends JestMock.ClassLike> = JestMock.SpiedClass<T>;
|
||||
/**
|
||||
* Constructs the type of a spied function.
|
||||
*/
|
||||
type SpiedFunction<T extends AnyFunction> = JestMock.SpiedFunction<T>;
|
||||
/**
|
||||
* Constructs the type of a spied getter.
|
||||
*/
|
||||
type SpiedGetter<T> = JestMock.SpiedGetter<T>;
|
||||
/**
|
||||
* Constructs the type of a spied setter.
|
||||
*/
|
||||
type SpiedSetter<T> = JestMock.SpiedSetter<T>;
|
||||
}
|
||||
|
||||
export function spyOn<T extends object, K extends keyof T>(
|
||||
obj: T,
|
||||
methodOrPropertyValue: K,
|
||||
): Mock<() => T[K]>;
|
||||
|
||||
/**
|
||||
* Describes a group of related tests.
|
||||
*
|
||||
@@ -329,6 +400,9 @@ declare module "bun:test" {
|
||||
any: (
|
||||
constructor: ((..._: any[]) => any) | { new (..._: any[]): any },
|
||||
) => Expect;
|
||||
anything: () => Expect;
|
||||
stringContaining: (str: string) => Expect;
|
||||
stringMatching: (regex: RegExp | string) => Expect;
|
||||
};
|
||||
/**
|
||||
* Asserts that a value matches some criteria.
|
||||
@@ -350,6 +424,20 @@ declare module "bun:test" {
|
||||
* expect(null).not.toBeNull();
|
||||
*/
|
||||
not: Expect<unknown>;
|
||||
/**
|
||||
* Expects the value to be a promise that resolves.
|
||||
*
|
||||
* @example
|
||||
* expect(Promise.resolve(1)).resolves.toBe(1);
|
||||
*/
|
||||
resolves: Expect<unknown>;
|
||||
/**
|
||||
* Expects the value to be a promise that rejects.
|
||||
*
|
||||
* @example
|
||||
* expect(Promise.reject("error")).rejects.toBe("error");
|
||||
*/
|
||||
rejects: Expect<unknown>;
|
||||
/**
|
||||
* Asserts that a value equals what is expected.
|
||||
*
|
||||
@@ -366,6 +454,24 @@ declare module "bun:test" {
|
||||
* @param expected the expected value
|
||||
*/
|
||||
toBe(expected: T): void;
|
||||
/**
|
||||
* Asserts that a number is odd.
|
||||
*
|
||||
* @link https://jest-extended.jestcommunity.dev/docs/matchers/number/#tobeodd
|
||||
* @example
|
||||
* expect(1).toBeOdd();
|
||||
* expect(2).not.toBeOdd();
|
||||
*/
|
||||
toBeOdd(): void;
|
||||
/**
|
||||
* Asserts that a number is even.
|
||||
*
|
||||
* @link https://jest-extended.jestcommunity.dev/docs/matchers/number/#tobeeven
|
||||
* @example
|
||||
* expect(2).toBeEven();
|
||||
* expect(1).not.toBeEven();
|
||||
*/
|
||||
toBeEven(): void;
|
||||
/**
|
||||
* Asserts that value is close to the expected by floating point precision.
|
||||
*
|
||||
@@ -618,6 +724,16 @@ declare module "bun:test" {
|
||||
* @param hint Hint used to identify the snapshot in the snapshot file.
|
||||
*/
|
||||
toMatchSnapshot(propertyMatchers?: Object, hint?: string): void;
|
||||
/**
|
||||
* Asserts that an object matches a subset of properties.
|
||||
*
|
||||
* @example
|
||||
* expect({ a: 1, b: 2 }).toMatchObject({ b: 2 });
|
||||
* expect({ c: new Date(), d: 2 }).toMatchObject({ d: 2 });
|
||||
*
|
||||
* @param subset Subset of properties to match with.
|
||||
*/
|
||||
toMatchObject(subset: Object): void;
|
||||
/**
|
||||
* Asserts that a value is empty.
|
||||
*
|
||||
@@ -636,6 +752,27 @@ declare module "bun:test" {
|
||||
* expect(undefined).toBeNil();
|
||||
*/
|
||||
toBeNil(): void;
|
||||
/**
|
||||
* Asserts that a value is a `array`.
|
||||
*
|
||||
* @link https://jest-extended.jestcommunity.dev/docs/matchers/array/#tobearray
|
||||
* @example
|
||||
* expect([1]).toBeArray();
|
||||
* expect(new Array(1)).toBeArray();
|
||||
* expect({}).not.toBeArray();
|
||||
*/
|
||||
toBeArray(): void;
|
||||
/**
|
||||
* Asserts that a value is a `array` of a certain length.
|
||||
*
|
||||
* @link https://jest-extended.jestcommunity.dev/docs/matchers/array/#tobearrayofsize
|
||||
* @example
|
||||
* expect([]).toBeArrayOfSize(0);
|
||||
* expect([1]).toBeArrayOfSize(1);
|
||||
* expect(new Array(1)).toBeArrayOfSize(1);
|
||||
* expect({}).not.toBeArrayOfSize(0);
|
||||
*/
|
||||
toBeArrayOfSize(size: number): void;
|
||||
/**
|
||||
* Asserts that a value is a `boolean`.
|
||||
*
|
||||
@@ -655,6 +792,26 @@ declare module "bun:test" {
|
||||
* expect(1).not.toBeTrue();
|
||||
*/
|
||||
toBeTrue(): void;
|
||||
/**
|
||||
* Asserts that a value matches a specific type.
|
||||
*
|
||||
* @link https://vitest.dev/api/expect.html#tobetypeof
|
||||
* @example
|
||||
* expect(1).toBeTypeOf("number");
|
||||
* expect("hello").toBeTypeOf("string");
|
||||
* expect([]).not.toBeTypeOf("boolean");
|
||||
*/
|
||||
toBeTypeOf(
|
||||
type:
|
||||
| "bigint"
|
||||
| "boolean"
|
||||
| "function"
|
||||
| "number"
|
||||
| "object"
|
||||
| "string"
|
||||
| "symbol"
|
||||
| "undefined",
|
||||
): void;
|
||||
/**
|
||||
* Asserts that a value is `false`.
|
||||
*
|
||||
@@ -782,6 +939,18 @@ declare module "bun:test" {
|
||||
* @param expected the string to end with
|
||||
*/
|
||||
toEndWith(expected: string): void;
|
||||
/**
|
||||
* Ensures that a mock function is called.
|
||||
*/
|
||||
toHaveBeenCalled(): void;
|
||||
/**
|
||||
* Ensures that a mock function is called an exact number of times.
|
||||
*/
|
||||
toHaveBeenCalledTimes(expected: number): void;
|
||||
/**
|
||||
* Ensure that a mock function is called with specific arguments.
|
||||
*/
|
||||
// toHaveBeenCalledWith(...expected: Array<unknown>): void;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -789,3 +958,423 @@ declare module "test" {
|
||||
import BunTestModule = require("bun:test");
|
||||
export = BunTestModule;
|
||||
}
|
||||
|
||||
declare namespace JestMock {
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
export type ClassLike = {
|
||||
new (...args: any): any;
|
||||
};
|
||||
|
||||
export type ConstructorLikeKeys<T> = keyof {
|
||||
[K in keyof T as Required<T>[K] extends ClassLike ? K : never]: T[K];
|
||||
};
|
||||
|
||||
// export const fn: <T extends FunctionLike = UnknownFunction>(
|
||||
// implementation?: T | undefined,
|
||||
// ) => Mock<T>;
|
||||
|
||||
export type FunctionLike = (...args: any) => any;
|
||||
|
||||
export type MethodLikeKeys<T> = keyof {
|
||||
[K in keyof T as Required<T>[K] extends FunctionLike ? K : never]: T[K];
|
||||
};
|
||||
|
||||
/**
|
||||
* All what the internal typings need is to be sure that we have any-function.
|
||||
* `FunctionLike` type ensures that and helps to constrain the type as well.
|
||||
* The default of `UnknownFunction` makes sure that `any`s do not leak to the
|
||||
* user side. For instance, calling `fn()` without implementation will return
|
||||
* a mock of `(...args: Array<unknown>) => unknown` type. If implementation
|
||||
* is provided, its typings are inferred correctly.
|
||||
*/
|
||||
// export interface Mock<T extends FunctionLike = UnknownFunction>
|
||||
// extends Function,
|
||||
// MockInstance<T> {
|
||||
// new (...args: Parameters<T>): ReturnType<T>;
|
||||
// (...args: Parameters<T>): ReturnType<T>;
|
||||
// }
|
||||
|
||||
// export type Mocked<T> = T extends ClassLike
|
||||
// ? MockedClass<T>
|
||||
// : T extends FunctionLike
|
||||
// ? MockedFunction<T>
|
||||
// : T extends object
|
||||
// ? MockedObject<T>
|
||||
// : T;
|
||||
|
||||
// export const mocked: {
|
||||
// <T extends object>(
|
||||
// source: T,
|
||||
// options?: {
|
||||
// shallow: false;
|
||||
// },
|
||||
// ): Mocked<T>;
|
||||
// <T_1 extends object>(
|
||||
// source: T_1,
|
||||
// options: {
|
||||
// shallow: true;
|
||||
// },
|
||||
// ): MockedShallow<T_1>;
|
||||
// };
|
||||
|
||||
// export type MockedClass<T extends ClassLike> = MockInstance<
|
||||
// (...args: ConstructorParameters<T>) => Mocked<InstanceType<T>>
|
||||
// > &
|
||||
// MockedObject<T>;
|
||||
|
||||
// export type MockedFunction<T extends FunctionLike> = MockInstance<T> &
|
||||
// MockedObject<T>;
|
||||
|
||||
// type MockedFunctionShallow<T extends FunctionLike> = MockInstance<T> & T;
|
||||
|
||||
// export type MockedObject<T extends object> = {
|
||||
// [K in keyof T]: T[K] extends ClassLike
|
||||
// ? MockedClass<T[K]>
|
||||
// : T[K] extends FunctionLike
|
||||
// ? MockedFunction<T[K]>
|
||||
// : T[K] extends object
|
||||
// ? MockedObject<T[K]>
|
||||
// : T[K];
|
||||
// } & T;
|
||||
|
||||
// type MockedObjectShallow<T extends object> = {
|
||||
// [K in keyof T]: T[K] extends ClassLike
|
||||
// ? MockedClass<T[K]>
|
||||
// : T[K] extends FunctionLike
|
||||
// ? MockedFunctionShallow<T[K]>
|
||||
// : T[K];
|
||||
// } & T;
|
||||
|
||||
// export type MockedShallow<T> = T extends ClassLike
|
||||
// ? MockedClass<T>
|
||||
// : T extends FunctionLike
|
||||
// ? MockedFunctionShallow<T>
|
||||
// : T extends object
|
||||
// ? MockedObjectShallow<T>
|
||||
// : T;
|
||||
|
||||
// export type MockFunctionMetadata<
|
||||
// T = unknown,
|
||||
// MetadataType = MockMetadataType,
|
||||
// > = MockMetadata<T, MetadataType>;
|
||||
|
||||
// export type MockFunctionMetadataType = MockMetadataType;
|
||||
|
||||
type MockFunctionResult<T extends FunctionLike = UnknownFunction> =
|
||||
| MockFunctionResultIncomplete
|
||||
| MockFunctionResultReturn<T>
|
||||
| MockFunctionResultThrow;
|
||||
|
||||
type MockFunctionResultIncomplete = {
|
||||
type: "incomplete";
|
||||
/**
|
||||
* Result of a single call to a mock function that has not yet completed.
|
||||
* This occurs if you test the result from within the mock function itself,
|
||||
* or from within a function that was called by the mock.
|
||||
*/
|
||||
value: undefined;
|
||||
};
|
||||
|
||||
type MockFunctionResultReturn<T extends FunctionLike = UnknownFunction> = {
|
||||
type: "return";
|
||||
/**
|
||||
* Result of a single call to a mock function that returned.
|
||||
*/
|
||||
value: ReturnType<T>;
|
||||
};
|
||||
|
||||
type MockFunctionResultThrow = {
|
||||
type: "throw";
|
||||
/**
|
||||
* Result of a single call to a mock function that threw.
|
||||
*/
|
||||
value: unknown;
|
||||
};
|
||||
|
||||
type MockFunctionState<T extends FunctionLike = FunctionLike> = {
|
||||
/**
|
||||
* List of the call arguments of all calls that have been made to the mock.
|
||||
*/
|
||||
calls: Array<Parameters<T>>;
|
||||
/**
|
||||
* List of all the object instances that have been instantiated from the mock.
|
||||
*/
|
||||
instances: Array<ReturnType<T>>;
|
||||
/**
|
||||
* List of all the function contexts that have been applied to calls to the mock.
|
||||
*/
|
||||
contexts: Array<ThisParameterType<T>>;
|
||||
/**
|
||||
* List of the call order indexes of the mock. Jest is indexing the order of
|
||||
* invocations of all mocks in a test file. The index is starting with `1`.
|
||||
*/
|
||||
invocationCallOrder: Array<number>;
|
||||
/**
|
||||
* List of the call arguments of the last call that was made to the mock.
|
||||
* If the function was not called, it will return `undefined`.
|
||||
*/
|
||||
lastCall?: Parameters<T>;
|
||||
/**
|
||||
* List of the results of all calls that have been made to the mock.
|
||||
*/
|
||||
results: Array<MockFunctionResult<T>>;
|
||||
};
|
||||
|
||||
export interface MockInstance<T extends FunctionLike = UnknownFunction> {
|
||||
_isMockFunction: true;
|
||||
_protoImpl: Function;
|
||||
getMockImplementation(): T | undefined;
|
||||
getMockName(): string;
|
||||
mock: MockFunctionState<T>;
|
||||
mockClear(): this;
|
||||
mockReset(): this;
|
||||
mockRestore(): void;
|
||||
mockImplementation(fn: T): this;
|
||||
mockImplementationOnce(fn: T): this;
|
||||
withImplementation(fn: T, callback: () => Promise<unknown>): Promise<void>;
|
||||
withImplementation(fn: T, callback: () => void): void;
|
||||
mockName(name: string): this;
|
||||
mockReturnThis(): this;
|
||||
mockReturnValue(value: ReturnType<T>): this;
|
||||
mockReturnValueOnce(value: ReturnType<T>): this;
|
||||
mockResolvedValue(value: ResolveType<T>): this;
|
||||
mockResolvedValueOnce(value: ResolveType<T>): this;
|
||||
mockRejectedValue(value: RejectType<T>): this;
|
||||
mockRejectedValueOnce(value: RejectType<T>): this;
|
||||
}
|
||||
|
||||
// export type MockMetadata<T, MetadataType = MockMetadataType> = {
|
||||
// ref?: number;
|
||||
// members?: Record<string, MockMetadata<T>>;
|
||||
// mockImpl?: T;
|
||||
// name?: string;
|
||||
// refID?: number;
|
||||
// type?: MetadataType;
|
||||
// value?: T;
|
||||
// length?: number;
|
||||
// };
|
||||
|
||||
// export type MockMetadataType =
|
||||
// | "object"
|
||||
// | "array"
|
||||
// | "regexp"
|
||||
// | "function"
|
||||
// | "constant"
|
||||
// | "collection"
|
||||
// | "null"
|
||||
// | "undefined";
|
||||
|
||||
// export class ModuleMocker {
|
||||
// private readonly _environmentGlobal;
|
||||
// private _mockState;
|
||||
// private _mockConfigRegistry;
|
||||
// private _spyState;
|
||||
// private _invocationCallCounter;
|
||||
// /**
|
||||
// * @see README.md
|
||||
// * @param global Global object of the test environment, used to create
|
||||
// * mocks
|
||||
// */
|
||||
// constructor(global: typeof globalThis);
|
||||
// private _getSlots;
|
||||
// private _ensureMockConfig;
|
||||
// private _ensureMockState;
|
||||
// private _defaultMockConfig;
|
||||
// private _defaultMockState;
|
||||
// private _makeComponent;
|
||||
// private _createMockFunction;
|
||||
// private _generateMock;
|
||||
// /**
|
||||
// * Check whether the given property of an object has been already replaced.
|
||||
// */
|
||||
// private _findReplacedProperty;
|
||||
// /**
|
||||
// * @see README.md
|
||||
// * @param metadata Metadata for the mock in the schema returned by the
|
||||
// * getMetadata method of this module.
|
||||
// */
|
||||
// generateFromMetadata<T>(metadata: MockMetadata<T>): Mocked<T>;
|
||||
// /**
|
||||
// * @see README.md
|
||||
// * @param component The component for which to retrieve metadata.
|
||||
// */
|
||||
// getMetadata<T = unknown>(
|
||||
// component: T,
|
||||
// _refs?: Map<T, number>,
|
||||
// ): MockMetadata<T> | null;
|
||||
// isMockFunction<T extends FunctionLike = UnknownFunction>(
|
||||
// fn: MockInstance<T>,
|
||||
// ): fn is MockInstance<T>;
|
||||
// isMockFunction<P extends Array<unknown>, R>(
|
||||
// fn: (...args: P) => R,
|
||||
// ): fn is Mock<(...args: P) => R>;
|
||||
// isMockFunction(fn: unknown): fn is Mock<UnknownFunction>;
|
||||
// fn<T extends FunctionLike = UnknownFunction>(implementation?: T): Mock<T>;
|
||||
// private _attachMockImplementation;
|
||||
// spyOn<
|
||||
// T extends object,
|
||||
// K extends PropertyLikeKeys<T>,
|
||||
// A extends "get" | "set",
|
||||
// >(
|
||||
// object: T,
|
||||
// methodKey: K,
|
||||
// accessType: A,
|
||||
// ): A extends "get"
|
||||
// ? SpiedGetter<T[K]>
|
||||
// : A extends "set"
|
||||
// ? SpiedSetter<T[K]>
|
||||
// : never;
|
||||
// spyOn<
|
||||
// T extends object,
|
||||
// K extends ConstructorLikeKeys<T> | MethodLikeKeys<T>,
|
||||
// V extends Required<T>[K],
|
||||
// >(
|
||||
// object: T,
|
||||
// methodKey: K,
|
||||
// ): V extends ClassLike | FunctionLike ? Spied<V> : never;
|
||||
// private _spyOnProperty;
|
||||
// replaceProperty<
|
||||
// T extends object,
|
||||
// K extends PropertyLikeKeys<T>,
|
||||
// V extends T[K],
|
||||
// >(object: T, propertyKey: K, value: V): Replaced<T[K]>;
|
||||
// clearAllMocks(): void;
|
||||
// resetAllMocks(): void;
|
||||
// restoreAllMocks(): void;
|
||||
// private _typeOf;
|
||||
// mocked<T extends object>(
|
||||
// source: T,
|
||||
// options?: {
|
||||
// shallow: false;
|
||||
// },
|
||||
// ): Mocked<T>;
|
||||
// mocked<T extends object>(
|
||||
// source: T,
|
||||
// options: {
|
||||
// shallow: true;
|
||||
// },
|
||||
// ): MockedShallow<T>;
|
||||
// }
|
||||
|
||||
export type PropertyLikeKeys<T> = Exclude<
|
||||
keyof T,
|
||||
ConstructorLikeKeys<T> | MethodLikeKeys<T>
|
||||
>;
|
||||
|
||||
export type RejectType<T extends FunctionLike> =
|
||||
ReturnType<T> extends PromiseLike<any> ? unknown : never;
|
||||
|
||||
export interface Replaced<T = unknown> {
|
||||
/**
|
||||
* Restore property to its original value known at the time of mocking.
|
||||
*/
|
||||
restore(): void;
|
||||
/**
|
||||
* Change the value of the property.
|
||||
*/
|
||||
replaceValue(value: T): this;
|
||||
}
|
||||
|
||||
export const replaceProperty: <
|
||||
T extends object,
|
||||
K_2 extends Exclude<
|
||||
keyof T,
|
||||
| keyof {
|
||||
[K in keyof T as Required<T>[K] extends ClassLike ? K : never]: T[K];
|
||||
}
|
||||
| keyof {
|
||||
[K_1 in keyof T as Required<T>[K_1] extends FunctionLike
|
||||
? K_1
|
||||
: never]: T[K_1];
|
||||
}
|
||||
>,
|
||||
V extends T[K_2],
|
||||
>(
|
||||
object: T,
|
||||
propertyKey: K_2,
|
||||
value: V,
|
||||
) => Replaced<T[K_2]>;
|
||||
|
||||
export type ResolveType<T extends FunctionLike> =
|
||||
ReturnType<T> extends PromiseLike<infer U> ? U : never;
|
||||
|
||||
export type Spied<T extends ClassLike | FunctionLike> = T extends ClassLike
|
||||
? SpiedClass<T>
|
||||
: T extends FunctionLike
|
||||
? SpiedFunction<T>
|
||||
: never;
|
||||
|
||||
export type SpiedClass<T extends ClassLike = UnknownClass> = MockInstance<
|
||||
(...args: ConstructorParameters<T>) => InstanceType<T>
|
||||
>;
|
||||
|
||||
export type SpiedFunction<T extends FunctionLike = UnknownFunction> =
|
||||
MockInstance<(...args: Parameters<T>) => ReturnType<T>>;
|
||||
|
||||
export type SpiedGetter<T> = MockInstance<() => T>;
|
||||
|
||||
export type SpiedSetter<T> = MockInstance<(arg: T) => void>;
|
||||
|
||||
export interface SpyInstance<T extends FunctionLike = UnknownFunction>
|
||||
extends MockInstance<T> {}
|
||||
|
||||
export const spyOn: {
|
||||
<
|
||||
T extends object,
|
||||
K_2 extends Exclude<
|
||||
keyof T,
|
||||
| keyof {
|
||||
[K in keyof T as Required<T>[K] extends ClassLike
|
||||
? K
|
||||
: never]: T[K];
|
||||
}
|
||||
| keyof {
|
||||
[K_1 in keyof T as Required<T>[K_1] extends FunctionLike
|
||||
? K_1
|
||||
: never]: T[K_1];
|
||||
}
|
||||
>,
|
||||
V extends Required<T>[K_2],
|
||||
A extends "set" | "get",
|
||||
>(
|
||||
object: T,
|
||||
methodKey: K_2,
|
||||
accessType: A,
|
||||
): A extends "get"
|
||||
? SpiedGetter<V>
|
||||
: A extends "set"
|
||||
? SpiedSetter<V>
|
||||
: never;
|
||||
<
|
||||
T_1 extends object,
|
||||
K_5 extends
|
||||
| keyof {
|
||||
[K_3 in keyof T_1 as Required<T_1>[K_3] extends ClassLike
|
||||
? K_3
|
||||
: never]: T_1[K_3];
|
||||
}
|
||||
| keyof {
|
||||
[K_4 in keyof T_1 as Required<T_1>[K_4] extends FunctionLike
|
||||
? K_4
|
||||
: never]: T_1[K_4];
|
||||
},
|
||||
V_1 extends Required<T_1>[K_5],
|
||||
>(
|
||||
object: T_1,
|
||||
methodKey: K_5,
|
||||
): V_1 extends ClassLike | FunctionLike ? Spied<V_1> : never;
|
||||
};
|
||||
|
||||
export type UnknownClass = {
|
||||
new (...args: Array<unknown>): unknown;
|
||||
};
|
||||
|
||||
export type UnknownFunction = (...args: Array<unknown>) => unknown;
|
||||
|
||||
export {};
|
||||
}
|
||||
|
||||
259
packages/bun-types/bun.d.ts
vendored
259
packages/bun-types/bun.d.ts
vendored
@@ -51,6 +51,10 @@ declare module "bun" {
|
||||
*
|
||||
*/
|
||||
export const env: Env;
|
||||
/**
|
||||
* The raw arguments passed to the process, including flags passed to Bun. If you want to easily read flags passed to your script, consider using `process.argv` instead.
|
||||
*/
|
||||
export const argv: string[];
|
||||
export const origin: string;
|
||||
|
||||
/**
|
||||
@@ -744,6 +748,14 @@ declare module "bun" {
|
||||
strict?: boolean,
|
||||
): boolean;
|
||||
|
||||
/**
|
||||
* Returns true if all properties in the subset exist in the
|
||||
* other and have equal values.
|
||||
*
|
||||
* This also powers expect().toMatchObject in `bun:test`
|
||||
*/
|
||||
export function deepMatch(subset: unknown, a: unknown): boolean;
|
||||
|
||||
/**
|
||||
* tsconfig.json options supported by Bun
|
||||
*/
|
||||
@@ -1012,6 +1024,226 @@ declare module "bun" {
|
||||
// importSource?: string; // default: "react"
|
||||
// };
|
||||
}
|
||||
namespace Password {
|
||||
export type AlgorithmLabel = "bcrypt" | "argon2id" | "argon2d" | "argon2i";
|
||||
|
||||
export interface Argon2Algorithm {
|
||||
algorithm: "argon2id" | "argon2d" | "argon2i";
|
||||
/**
|
||||
* Memory cost, which defines the memory usage, given in kibibytes.
|
||||
*/
|
||||
memoryCost?: number;
|
||||
/**
|
||||
* Defines the amount of computation realized and therefore the execution
|
||||
* time, given in number of iterations.
|
||||
*/
|
||||
timeCost?: number;
|
||||
}
|
||||
|
||||
export interface BCryptAlgorithm {
|
||||
algorithm: "bcrypt";
|
||||
/**
|
||||
* A number between 4 and 31. The default is 10.
|
||||
*/
|
||||
cost?: number;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash and verify passwords using argon2 or bcrypt. The default is argon2.
|
||||
* Password hashing functions are necessarily slow, and this object will
|
||||
* automatically run in a worker thread.
|
||||
*
|
||||
* The underlying implementation of these functions are provided by the Zig
|
||||
* Standard Library. Thanks to @jedisct1 and other Zig constributors for their
|
||||
* work on this.
|
||||
*
|
||||
* ### Example with argon2
|
||||
*
|
||||
* ```ts
|
||||
* import {password} from "bun";
|
||||
*
|
||||
* const hash = await password.hash("hello world");
|
||||
* const verify = await password.verify("hello world", hash);
|
||||
* console.log(verify); // true
|
||||
* ```
|
||||
*
|
||||
* ### Example with bcrypt
|
||||
* ```ts
|
||||
* import {password} from "bun";
|
||||
*
|
||||
* const hash = await password.hash("hello world", "bcrypt");
|
||||
* // algorithm is optional, will be inferred from the hash if not specified
|
||||
* const verify = await password.verify("hello world", hash, "bcrypt");
|
||||
*
|
||||
* console.log(verify); // true
|
||||
* ```
|
||||
*/
|
||||
export const password: {
|
||||
/**
|
||||
* Verify a password against a previously hashed password.
|
||||
*
|
||||
* @returns true if the password matches, false otherwise
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import {password} from "bun";
|
||||
* await password.verify("hey", "$argon2id$v=19$m=65536,t=2,p=1$ddbcyBcbAcagei7wSkZFiouX6TqnUQHmTyS5mxGCzeM$+3OIaFatZ3n6LtMhUlfWbgJyNp7h8/oIsLK+LzZO+WI");
|
||||
* // true
|
||||
* ```
|
||||
*
|
||||
* @throws If the algorithm is specified and does not match the hash
|
||||
* @throws If the algorithm is invalid
|
||||
* @throws if the hash is invalid
|
||||
*
|
||||
*/
|
||||
verify(
|
||||
/**
|
||||
* The password to verify.
|
||||
*
|
||||
* If empty, always returns false
|
||||
*/
|
||||
password: StringOrBuffer,
|
||||
/**
|
||||
* Previously hashed password.
|
||||
* If empty, always returns false
|
||||
*/
|
||||
hash: StringOrBuffer,
|
||||
/**
|
||||
* If not specified, the algorithm will be inferred from the hash.
|
||||
*
|
||||
* If specified and the algorithm does not match the hash, this function
|
||||
* throws an error.
|
||||
*/
|
||||
algorithm?: Password.AlgorithmLabel,
|
||||
): Promise<boolean>;
|
||||
/**
|
||||
* Asynchronously hash a password using argon2 or bcrypt. The default is argon2.
|
||||
*
|
||||
* @returns A promise that resolves to the hashed password
|
||||
*
|
||||
* ## Example with argon2
|
||||
* ```ts
|
||||
* import {password} from "bun";
|
||||
* const hash = await password.hash("hello world");
|
||||
* console.log(hash); // $argon2id$v=1...
|
||||
* const verify = await password.verify("hello world", hash);
|
||||
* ```
|
||||
* ## Example with bcrypt
|
||||
* ```ts
|
||||
* import {password} from "bun";
|
||||
* const hash = await password.hash("hello world", "bcrypt");
|
||||
* console.log(hash); // $2b$10$...
|
||||
* const verify = await password.verify("hello world", hash);
|
||||
* ```
|
||||
*/
|
||||
hash(
|
||||
/**
|
||||
* The password to hash
|
||||
*
|
||||
* If empty, this function throws an error. It is usually a programming
|
||||
* mistake to hash an empty password.
|
||||
*/
|
||||
password: StringOrBuffer,
|
||||
/**
|
||||
* @default "argon2id"
|
||||
*
|
||||
* When using bcrypt, passwords exceeding 72 characters will be SHA512'd before
|
||||
*/
|
||||
algorithm?:
|
||||
| Password.AlgorithmLabel
|
||||
| Password.Argon2Algorithm
|
||||
| Password.BCryptAlgorithm,
|
||||
): Promise<string>;
|
||||
|
||||
/**
|
||||
* Synchronously hash and verify passwords using argon2 or bcrypt. The default is argon2.
|
||||
* Warning: password hashing is slow, consider using {@link Bun.password.verify}
|
||||
* instead which runs in a worker thread.
|
||||
*
|
||||
* The underlying implementation of these functions are provided by the Zig
|
||||
* Standard Library. Thanks to @jedisct1 and other Zig constributors for their
|
||||
* work on this.
|
||||
*
|
||||
* ### Example with argon2
|
||||
*
|
||||
* ```ts
|
||||
* import {password} from "bun";
|
||||
*
|
||||
* const hash = await password.hashSync("hello world");
|
||||
* const verify = await password.verifySync("hello world", hash);
|
||||
* console.log(verify); // true
|
||||
* ```
|
||||
*
|
||||
* ### Example with bcrypt
|
||||
* ```ts
|
||||
* import {password} from "bun";
|
||||
*
|
||||
* const hash = await password.hashSync("hello world", "bcrypt");
|
||||
* // algorithm is optional, will be inferred from the hash if not specified
|
||||
* const verify = await password.verifySync("hello world", hash, "bcrypt");
|
||||
*
|
||||
* console.log(verify); // true
|
||||
* ```
|
||||
*/
|
||||
verifySync(
|
||||
password: StringOrBuffer,
|
||||
hash: StringOrBuffer,
|
||||
/**
|
||||
* If not specified, the algorithm will be inferred from the hash.
|
||||
*/
|
||||
algorithm?: Password.AlgorithmLabel,
|
||||
): boolean;
|
||||
|
||||
/**
|
||||
* Synchronously hash and verify passwords using argon2 or bcrypt. The default is argon2.
|
||||
* Warning: password hashing is slow, consider using {@link Bun.password.hash}
|
||||
* instead which runs in a worker thread.
|
||||
*
|
||||
* The underlying implementation of these functions are provided by the Zig
|
||||
* Standard Library. Thanks to @jedisct1 and other Zig constributors for their
|
||||
* work on this.
|
||||
*
|
||||
* ### Example with argon2
|
||||
*
|
||||
* ```ts
|
||||
* import {password} from "bun";
|
||||
*
|
||||
* const hash = await password.hashSync("hello world");
|
||||
* const verify = await password.verifySync("hello world", hash);
|
||||
* console.log(verify); // true
|
||||
* ```
|
||||
*
|
||||
* ### Example with bcrypt
|
||||
* ```ts
|
||||
* import {password} from "bun";
|
||||
*
|
||||
* const hash = await password.hashSync("hello world", "bcrypt");
|
||||
* // algorithm is optional, will be inferred from the hash if not specified
|
||||
* const verify = await password.verifySync("hello world", hash, "bcrypt");
|
||||
*
|
||||
* console.log(verify); // true
|
||||
* ```
|
||||
*/
|
||||
hashSync(
|
||||
/**
|
||||
* The password to hash
|
||||
*
|
||||
* If empty, this function throws an error. It is usually a programming
|
||||
* mistake to hash an empty password.
|
||||
*/
|
||||
password: StringOrBuffer,
|
||||
/**
|
||||
* @default "argon2id"
|
||||
*
|
||||
* When using bcrypt, passwords exceeding 72 characters will be SHA256'd before
|
||||
*/
|
||||
algorithm?:
|
||||
| Password.AlgorithmLabel
|
||||
| Password.Argon2Algorithm
|
||||
| Password.BCryptAlgorithm,
|
||||
): string;
|
||||
};
|
||||
|
||||
interface BuildArtifact extends Blob {
|
||||
path: string;
|
||||
@@ -1379,9 +1611,9 @@ declare module "bun" {
|
||||
* ```ts
|
||||
* import { websocket, serve } from "bun";
|
||||
*
|
||||
* serve({
|
||||
* serve<{name: string}>({
|
||||
* port: 3000,
|
||||
* websocket: websocket<{name: string}>({
|
||||
* websocket: {
|
||||
* open: (ws) => {
|
||||
* console.log("Client connected");
|
||||
* },
|
||||
@@ -1391,10 +1623,11 @@ declare module "bun" {
|
||||
* close: (ws) => {
|
||||
* console.log("Client disconnected");
|
||||
* },
|
||||
* }),
|
||||
* },
|
||||
*
|
||||
* fetch(req, server) {
|
||||
* if (req.url === "/chat") {
|
||||
* const url = new URL(req.url);
|
||||
* if (url.pathname === "/chat") {
|
||||
* const upgraded = server.upgrade(req, {
|
||||
* data: {
|
||||
* name: new URL(req.url).searchParams.get("name"),
|
||||
@@ -1609,9 +1842,9 @@ declare module "bun" {
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
*import { serve, websocket } from "bun";
|
||||
*import { serve } from "bun";
|
||||
*serve({
|
||||
* websocket: websocket({
|
||||
* websocket: {
|
||||
* open: (ws) => {
|
||||
* console.log("Client connected");
|
||||
* },
|
||||
@@ -1621,9 +1854,10 @@ declare module "bun" {
|
||||
* close: (ws) => {
|
||||
* console.log("Client disconnected");
|
||||
* },
|
||||
* }),
|
||||
* },
|
||||
* fetch(req, server) {
|
||||
* if (req.url === "/chat") {
|
||||
* const url = new URL(req.url);
|
||||
* if (url.pathname === "/chat") {
|
||||
* const upgraded = server.upgrade(req);
|
||||
* if (!upgraded) {
|
||||
* return new Response("Upgrade failed", { status: 400 });
|
||||
@@ -1839,9 +2073,9 @@ declare module "bun" {
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* import { serve, websocket } from "bun";
|
||||
* import { serve } from "bun";
|
||||
* serve({
|
||||
* websocket: websocket({
|
||||
* websocket: {
|
||||
* open: (ws) => {
|
||||
* console.log("Client connected");
|
||||
* },
|
||||
@@ -1851,9 +2085,10 @@ declare module "bun" {
|
||||
* close: (ws) => {
|
||||
* console.log("Client disconnected");
|
||||
* },
|
||||
* }),
|
||||
* },
|
||||
* fetch(req, server) {
|
||||
* if (req.url === "/chat") {
|
||||
* const url = new URL(req.url);
|
||||
* if (url.pathname === "/chat") {
|
||||
* const upgraded = server.upgrade(req);
|
||||
* if (!upgraded) {
|
||||
* return new Response("Upgrade failed", { status: 400 });
|
||||
|
||||
97
packages/bun-types/fs.d.ts
vendored
97
packages/bun-types/fs.d.ts
vendored
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
declare module "fs" {
|
||||
import * as stream from "stream";
|
||||
import type EventEmitter from "events";
|
||||
import type { SystemError, ArrayBufferView } from "bun";
|
||||
interface ObjectEncodingOptions {
|
||||
encoding?: BufferEncoding | null | undefined;
|
||||
@@ -3929,6 +3930,102 @@ declare module "fs" {
|
||||
*/
|
||||
recursive?: boolean;
|
||||
}
|
||||
|
||||
export interface FSWatcher extends EventEmitter {
|
||||
/**
|
||||
* Stop watching for changes on the given `fs.FSWatcher`. Once stopped, the `fs.FSWatcher` object is no longer usable.
|
||||
* @since v0.6.8
|
||||
*/
|
||||
close(): void;
|
||||
|
||||
/**
|
||||
* When called, requests that the Node.js event loop not exit so long as the <fs.FSWatcher> is active. Calling watcher.ref() multiple times will have no effect.
|
||||
*/
|
||||
ref(): void;
|
||||
|
||||
/**
|
||||
* When called, the active <fs.FSWatcher> object will not require the Node.js event loop to remain active. If there is no other activity keeping the event loop running, the process may exit before the <fs.FSWatcher> object's callback is invoked. Calling watcher.unref() multiple times will have no effect.
|
||||
*/
|
||||
unref(): void;
|
||||
|
||||
/**
|
||||
* events.EventEmitter
|
||||
* 1. change
|
||||
* 2. error
|
||||
*/
|
||||
addListener(event: string, listener: (...args: any[]) => void): this;
|
||||
addListener(event: 'change', listener: (eventType: string, filename: string | Buffer) => void): this;
|
||||
addListener(event: 'error', listener: (error: Error) => void): this;
|
||||
addListener(event: 'close', listener: () => void): this;
|
||||
on(event: string, listener: (...args: any[]) => void): this;
|
||||
on(event: 'change', listener: (eventType: string, filename: string | Buffer) => void): this;
|
||||
on(event: 'error', listener: (error: Error) => void): this;
|
||||
on(event: 'close', listener: () => void): this;
|
||||
once(event: string, listener: (...args: any[]) => void): this;
|
||||
once(event: 'change', listener: (eventType: string, filename: string | Buffer) => void): this;
|
||||
once(event: 'error', listener: (error: Error) => void): this;
|
||||
once(event: 'close', listener: () => void): this;
|
||||
prependListener(event: string, listener: (...args: any[]) => void): this;
|
||||
prependListener(event: 'change', listener: (eventType: string, filename: string | Buffer) => void): this;
|
||||
prependListener(event: 'error', listener: (error: Error) => void): this;
|
||||
prependListener(event: 'close', listener: () => void): this;
|
||||
prependOnceListener(event: string, listener: (...args: any[]) => void): this;
|
||||
prependOnceListener(event: 'change', listener: (eventType: string, filename: string | Buffer) => void): this;
|
||||
prependOnceListener(event: 'error', listener: (error: Error) => void): this;
|
||||
prependOnceListener(event: 'close', listener: () => void): this;
|
||||
}
|
||||
/**
|
||||
* Watch for changes on `filename`, where `filename` is either a file or a
|
||||
* directory.
|
||||
*
|
||||
* The second argument is optional. If `options` is provided as a string, it
|
||||
* specifies the `encoding`. Otherwise `options` should be passed as an object.
|
||||
*
|
||||
* The listener callback gets two arguments `(eventType, filename)`. `eventType`is either `'rename'` or `'change'`, and `filename` is the name of the file
|
||||
* which triggered the event.
|
||||
*
|
||||
* On most platforms, `'rename'` is emitted whenever a filename appears or
|
||||
* disappears in the directory.
|
||||
*
|
||||
* The listener callback is attached to the `'change'` event fired by `fs.FSWatcher`, but it is not the same thing as the `'change'` value of`eventType`.
|
||||
*
|
||||
* If a `signal` is passed, aborting the corresponding AbortController will close
|
||||
* the returned `fs.FSWatcher`.
|
||||
* @since v0.6.8
|
||||
* @param listener
|
||||
*/
|
||||
export function watch(
|
||||
filename: PathLike,
|
||||
options:
|
||||
| (WatchOptions & {
|
||||
encoding: 'buffer';
|
||||
})
|
||||
| 'buffer',
|
||||
listener?: WatchListener<Buffer>
|
||||
): FSWatcher;
|
||||
/**
|
||||
* Watch for changes on `filename`, where `filename` is either a file or a directory, returning an `FSWatcher`.
|
||||
* @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param options Either the encoding for the filename provided to the listener, or an object optionally specifying encoding, persistent, and recursive options.
|
||||
* If `encoding` is not supplied, the default of `'utf8'` is used.
|
||||
* If `persistent` is not supplied, the default of `true` is used.
|
||||
* If `recursive` is not supplied, the default of `false` is used.
|
||||
*/
|
||||
export function watch(filename: PathLike, options?: WatchOptions | BufferEncoding | null, listener?: WatchListener<string>): FSWatcher;
|
||||
/**
|
||||
* Watch for changes on `filename`, where `filename` is either a file or a directory, returning an `FSWatcher`.
|
||||
* @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param options Either the encoding for the filename provided to the listener, or an object optionally specifying encoding, persistent, and recursive options.
|
||||
* If `encoding` is not supplied, the default of `'utf8'` is used.
|
||||
* If `persistent` is not supplied, the default of `true` is used.
|
||||
* If `recursive` is not supplied, the default of `false` is used.
|
||||
*/
|
||||
export function watch(filename: PathLike, options: WatchOptions | string, listener?: WatchListener<string | Buffer>): FSWatcher;
|
||||
/**
|
||||
* Watch for changes on `filename`, where `filename` is either a file or a directory, returning an `FSWatcher`.
|
||||
* @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
|
||||
*/
|
||||
export function watch(filename: PathLike, listener?: WatchListener<string>): FSWatcher;
|
||||
}
|
||||
|
||||
declare module "node:fs" {
|
||||
|
||||
58
packages/bun-types/fs/promises.d.ts
vendored
58
packages/bun-types/fs/promises.d.ts
vendored
@@ -26,6 +26,7 @@ declare module "fs/promises" {
|
||||
Abortable,
|
||||
RmOptions,
|
||||
RmDirOptions,
|
||||
WatchOptions,
|
||||
} from "node:fs";
|
||||
|
||||
const constants: typeof import("node:fs")["constants"];
|
||||
@@ -709,6 +710,63 @@ declare module "fs/promises" {
|
||||
* To remove a directory recursively, use `fs.promises.rm()` instead, with the `recursive` option set to `true`.
|
||||
*/
|
||||
function rmdir(path: PathLike, options?: RmDirOptions): Promise<void>;
|
||||
|
||||
/**
|
||||
* Returns an async iterator that watches for changes on `filename`, where `filename`is either a file or a directory.
|
||||
*
|
||||
* ```js
|
||||
* const { watch } = require('node:fs/promises');
|
||||
*
|
||||
* const ac = new AbortController();
|
||||
* const { signal } = ac;
|
||||
* setTimeout(() => ac.abort(), 10000);
|
||||
*
|
||||
* (async () => {
|
||||
* try {
|
||||
* const watcher = watch(__filename, { signal });
|
||||
* for await (const event of watcher)
|
||||
* console.log(event);
|
||||
* } catch (err) {
|
||||
* if (err.name === 'AbortError')
|
||||
* return;
|
||||
* throw err;
|
||||
* }
|
||||
* })();
|
||||
* ```
|
||||
*
|
||||
* On most platforms, `'rename'` is emitted whenever a filename appears or
|
||||
* disappears in the directory.
|
||||
*
|
||||
* All the `caveats` for `fs.watch()` also apply to `fsPromises.watch()`.
|
||||
* @since v0.6.8
|
||||
* @return of objects with the properties:
|
||||
*/
|
||||
function watch(
|
||||
filename: PathLike,
|
||||
options:
|
||||
| (WatchOptions & {
|
||||
encoding: 'buffer';
|
||||
})
|
||||
| 'buffer'
|
||||
): AsyncIterable<FileChangeInfo<Buffer>>;
|
||||
/**
|
||||
* Watch for changes on `filename`, where `filename` is either a file or a directory, returning an `FSWatcher`.
|
||||
* @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param options Either the encoding for the filename provided to the listener, or an object optionally specifying encoding, persistent, and recursive options.
|
||||
* If `encoding` is not supplied, the default of `'utf8'` is used.
|
||||
* If `persistent` is not supplied, the default of `true` is used.
|
||||
* If `recursive` is not supplied, the default of `false` is used.
|
||||
*/
|
||||
function watch(filename: PathLike, options?: WatchOptions | BufferEncoding): AsyncIterable<FileChangeInfo<string>>;
|
||||
/**
|
||||
* Watch for changes on `filename`, where `filename` is either a file or a directory, returning an `FSWatcher`.
|
||||
* @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param options Either the encoding for the filename provided to the listener, or an object optionally specifying encoding, persistent, and recursive options.
|
||||
* If `encoding` is not supplied, the default of `'utf8'` is used.
|
||||
* If `persistent` is not supplied, the default of `true` is used.
|
||||
* If `recursive` is not supplied, the default of `false` is used.
|
||||
*/
|
||||
function watch(filename: PathLike, options: WatchOptions | string): AsyncIterable<FileChangeInfo<string>> | AsyncIterable<FileChangeInfo<Buffer>>;
|
||||
}
|
||||
|
||||
declare module "node:fs/promises" {
|
||||
|
||||
79
packages/bun-types/globals.d.ts
vendored
79
packages/bun-types/globals.d.ts
vendored
@@ -3197,3 +3197,82 @@ declare module "*.txt" {
|
||||
var text: string;
|
||||
export = text;
|
||||
}
|
||||
|
||||
interface EventSourceEventMap {
|
||||
error: Event;
|
||||
message: MessageEvent;
|
||||
open: Event;
|
||||
}
|
||||
|
||||
interface EventSource extends EventTarget {
|
||||
onerror: ((this: EventSource, ev: ErrorEvent) => any) | null;
|
||||
onmessage: ((this: EventSource, ev: MessageEvent) => any) | null;
|
||||
onopen: ((this: EventSource, ev: Event) => any) | null;
|
||||
/** Returns the state of this EventSource object's connection. It can have the values described below. */
|
||||
readonly readyState: number;
|
||||
/** Returns the URL providing the event stream. */
|
||||
readonly url: string;
|
||||
/** Returns true if the credentials mode for connection requests to the URL providing the event stream is set to "include", and false otherwise.
|
||||
*
|
||||
* Not supported in Bun
|
||||
*
|
||||
*/
|
||||
readonly withCredentials: boolean;
|
||||
/** Aborts any instances of the fetch algorithm started for this EventSource object, and sets the readyState attribute to CLOSED. */
|
||||
close(): void;
|
||||
readonly CLOSED: number;
|
||||
readonly CONNECTING: number;
|
||||
readonly OPEN: number;
|
||||
addEventListener<K extends keyof EventSourceEventMap>(
|
||||
type: K,
|
||||
listener: (this: EventSource, ev: EventSourceEventMap[K]) => any,
|
||||
options?: boolean | AddEventListenerOptions,
|
||||
): void;
|
||||
addEventListener(
|
||||
type: string,
|
||||
listener: (this: EventSource, event: MessageEvent) => any,
|
||||
options?: boolean | AddEventListenerOptions,
|
||||
): void;
|
||||
addEventListener(
|
||||
type: string,
|
||||
listener: EventListenerOrEventListenerObject,
|
||||
options?: boolean | AddEventListenerOptions,
|
||||
): void;
|
||||
removeEventListener<K extends keyof EventSourceEventMap>(
|
||||
type: K,
|
||||
listener: (this: EventSource, ev: EventSourceEventMap[K]) => any,
|
||||
options?: boolean | EventListenerOptions,
|
||||
): void;
|
||||
removeEventListener(
|
||||
type: string,
|
||||
listener: (this: EventSource, event: MessageEvent) => any,
|
||||
options?: boolean | EventListenerOptions,
|
||||
): void;
|
||||
removeEventListener(
|
||||
type: string,
|
||||
listener: EventListenerOrEventListenerObject,
|
||||
options?: boolean | EventListenerOptions,
|
||||
): void;
|
||||
|
||||
/**
|
||||
* Keep the event loop alive while connection is open or reconnecting
|
||||
*
|
||||
* Not available in browsers
|
||||
*/
|
||||
ref(): void;
|
||||
|
||||
/**
|
||||
* Do not keep the event loop alive while connection is open or reconnecting
|
||||
*
|
||||
* Not available in browsers
|
||||
*/
|
||||
unref(): void;
|
||||
}
|
||||
|
||||
declare var EventSource: {
|
||||
prototype: EventSource;
|
||||
new (url: string | URL, eventSourceInitDict?: EventSourceInit): EventSource;
|
||||
readonly CLOSED: number;
|
||||
readonly CONNECTING: number;
|
||||
readonly OPEN: number;
|
||||
};
|
||||
|
||||
2
packages/bun-types/http.d.ts
vendored
2
packages/bun-types/http.d.ts
vendored
@@ -987,7 +987,7 @@ declare module "http" {
|
||||
* in the response to be dropped and the socket to be destroyed.
|
||||
* @deprecated Since v14.1.0,v13.14.0 - Use `destroy` instead.
|
||||
*/
|
||||
// abort(): void;
|
||||
abort(): void;
|
||||
/**
|
||||
* Once a socket is assigned to this request and is connected `socket.setTimeout()` will be called.
|
||||
* @param timeout Milliseconds before a request times out.
|
||||
|
||||
@@ -75,6 +75,8 @@ const tsConfig = {
|
||||
skipLibCheck: true,
|
||||
jsx: "react-jsx",
|
||||
allowImportingTsExtensions: true,
|
||||
emitDeclarationOnly: true,
|
||||
composite: true,
|
||||
allowSyntheticDefaultImports: true,
|
||||
forceConsistentCasingInFileNames: true,
|
||||
allowJs: true,
|
||||
|
||||
9
packages/bun-types/sqlite.d.ts
vendored
9
packages/bun-types/sqlite.d.ts
vendored
@@ -579,7 +579,9 @@ declare module "bun:sqlite" {
|
||||
/**
|
||||
* Execute the prepared statement and return the results as an array of arrays.
|
||||
*
|
||||
* This is a little faster than {@link all}.
|
||||
* In Bun v0.6.7 and earlier, this method returned `null` if there were no
|
||||
* results instead of `[]`. This was changed in v0.6.8 to align
|
||||
* more with what people expect.
|
||||
*
|
||||
* @param params optional values to bind to the statement. If omitted, the statement is run with the last bound values or no parameters if there are none.
|
||||
*
|
||||
@@ -595,12 +597,15 @@ declare module "bun:sqlite" {
|
||||
*
|
||||
* stmt.values("foo");
|
||||
* // => [['foo']]
|
||||
*
|
||||
* stmt.values("not-found");
|
||||
* // => []
|
||||
* ```
|
||||
*
|
||||
* The following types can be used when binding parameters:
|
||||
*
|
||||
* | JavaScript type | SQLite type |
|
||||
* | -------------- | ----------- |
|
||||
* | ---------------|-------------|
|
||||
* | `string` | `TEXT` |
|
||||
* | `number` | `INTEGER` or `DECIMAL` |
|
||||
* | `boolean` | `INTEGER` (1 or 0) |
|
||||
|
||||
151
packages/bun-types/stream.d.ts
vendored
151
packages/bun-types/stream.d.ts
vendored
@@ -46,22 +46,7 @@ declare module "stream" {
|
||||
encoding?: BufferEncoding | undefined;
|
||||
read?(this: Readable, size: number): void;
|
||||
}
|
||||
class Readable<R = any> extends Stream implements ReadableStream {
|
||||
// TODO: improve type later
|
||||
values: any;
|
||||
|
||||
readonly locked: boolean;
|
||||
cancel(reason?: any): Promise<void>;
|
||||
getReader(): ReadableStreamDefaultReader<R>;
|
||||
pipeThrough<T>(
|
||||
transform: ReadableWritablePair<T, R>,
|
||||
options?: StreamPipeOptions,
|
||||
): ReadableStream<T>;
|
||||
pipeTo(
|
||||
destination: WritableStream<R>,
|
||||
options?: StreamPipeOptions,
|
||||
): Promise<void>;
|
||||
tee(): [ReadableStream<R>, ReadableStream<R>];
|
||||
class Readable<R = any> extends Stream {
|
||||
forEach(
|
||||
callbackfn: (
|
||||
value: any,
|
||||
@@ -71,12 +56,23 @@ declare module "stream" {
|
||||
thisArg?: any,
|
||||
): void;
|
||||
/**
|
||||
* A utility method for creating Readable Streams out of iterators.
|
||||
* A utility method for creating a `Readable` from a web `ReadableStream`.
|
||||
* @since v17.0.0
|
||||
* @experimental
|
||||
*/
|
||||
static from(
|
||||
iterable: Iterable<any> | AsyncIterable<any>,
|
||||
options?: ReadableOptions,
|
||||
static fromWeb(
|
||||
readableStream: ReadableStream,
|
||||
options?: Pick<
|
||||
ReadableOptions,
|
||||
"encoding" | "highWaterMark" | "objectMode" | "signal"
|
||||
>,
|
||||
): Readable;
|
||||
/**
|
||||
* A utility method for creating a web `ReadableStream` from a `Readable`.
|
||||
* @since v17.0.0
|
||||
* @experimental
|
||||
*/
|
||||
static toWeb(streamReadable: Readable): ReadableStream;
|
||||
/**
|
||||
* Returns whether the stream has been read from or cancelled.
|
||||
*/
|
||||
@@ -512,11 +508,25 @@ declare module "stream" {
|
||||
): void;
|
||||
final?(this: Writable, callback: (error?: Error | null) => void): void;
|
||||
}
|
||||
class Writable<W = any> extends Stream implements WritableStream {
|
||||
readonly locked: boolean;
|
||||
abort(reason?: any): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
getWriter(): WritableStreamDefaultWriter<W>;
|
||||
class Writable<W = any> extends Stream {
|
||||
/**
|
||||
* A utility method for creating a `Writable` from a web `WritableStream`.
|
||||
* @since v17.0.0
|
||||
* @experimental
|
||||
*/
|
||||
static fromWeb(
|
||||
writableStream: WritableStream,
|
||||
options?: Pick<
|
||||
WritableOptions,
|
||||
"decodeStrings" | "highWaterMark" | "objectMode" | "signal"
|
||||
>,
|
||||
): Writable;
|
||||
/**
|
||||
* A utility method for creating a web `WritableStream` from a `Writable`.
|
||||
* @since v17.0.0
|
||||
* @experimental
|
||||
*/
|
||||
static toWeb(streamWritable: Writable): WritableStream;
|
||||
/**
|
||||
* Is `true` if it is safe to call `writable.write()`, which means
|
||||
* the stream has not been destroyed, errored or ended.
|
||||
@@ -634,11 +644,11 @@ declare module "stream" {
|
||||
* @return `false` if the stream wishes for the calling code to wait for the `'drain'` event to be emitted before continuing to write additional data; otherwise `true`.
|
||||
*/
|
||||
write(
|
||||
chunk: any,
|
||||
chunk: W,
|
||||
callback?: (error: Error | null | undefined) => void,
|
||||
): boolean;
|
||||
write(
|
||||
chunk: any,
|
||||
chunk: W,
|
||||
encoding: BufferEncoding,
|
||||
callback?: (error: Error | null | undefined) => void,
|
||||
): boolean;
|
||||
@@ -851,28 +861,21 @@ declare module "stream" {
|
||||
* * `zlib streams`
|
||||
* * `crypto streams`
|
||||
*/
|
||||
class Duplex extends Readable implements Writable {
|
||||
readonly writable: boolean;
|
||||
readonly writableEnded: boolean;
|
||||
readonly writableFinished: boolean;
|
||||
readonly writableHighWaterMark: number;
|
||||
readonly writableLength: number;
|
||||
readonly writableObjectMode: boolean;
|
||||
readonly writableCorked: number;
|
||||
/**
|
||||
* If `false` then the stream will automatically end the writable side when the
|
||||
* readable side ends. Set initially by the `allowHalfOpen` constructor option,
|
||||
* which defaults to `false`.
|
||||
*
|
||||
* This can be changed manually to change the half-open behavior of an existing`Duplex` stream instance, but must be changed before the `'end'` event is
|
||||
* emitted.
|
||||
* @since v0.9.4
|
||||
*/
|
||||
allowHalfOpen: boolean;
|
||||
constructor(opts?: DuplexOptions);
|
||||
abort(reason?: any): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
getWriter(): WritableStreamDefaultWriter<any>;
|
||||
type Duplex<R = any> = Readable<R> &
|
||||
Writable<R> & {
|
||||
/**
|
||||
* If `false` then the stream will automatically end the writable side when the
|
||||
* readable side ends. Set initially by the `allowHalfOpen` constructor option,
|
||||
* which defaults to `false`.
|
||||
*
|
||||
* This can be changed manually to change the half-open behavior of an existing`Duplex` stream instance, but must be changed before the `'end'` event is
|
||||
* emitted.
|
||||
* @since v0.9.4
|
||||
*/
|
||||
allowHalfOpen: boolean;
|
||||
};
|
||||
interface DuplexConstructor {
|
||||
new <T = any>(opts?: DuplexOptions): Duplex<T>;
|
||||
/**
|
||||
* A utility method for creating duplex streams.
|
||||
*
|
||||
@@ -894,7 +897,7 @@ declare module "stream" {
|
||||
*
|
||||
* @since v16.8.0
|
||||
*/
|
||||
static from(
|
||||
from(
|
||||
src:
|
||||
| Stream
|
||||
| Blob
|
||||
@@ -906,39 +909,19 @@ declare module "stream" {
|
||||
| Promise<any>
|
||||
| Object,
|
||||
): Duplex;
|
||||
_write(
|
||||
chunk: any,
|
||||
encoding: BufferEncoding,
|
||||
callback: (error?: Error | null) => void,
|
||||
): void;
|
||||
_writev?(
|
||||
chunks: Array<{
|
||||
chunk: any;
|
||||
encoding: BufferEncoding;
|
||||
}>,
|
||||
callback: (error?: Error | null) => void,
|
||||
): void;
|
||||
_destroy(
|
||||
error: Error | null,
|
||||
callback: (error: Error | null) => void,
|
||||
): void;
|
||||
_final(callback: (error?: Error | null) => void): void;
|
||||
write(
|
||||
chunk: any,
|
||||
encoding?: BufferEncoding,
|
||||
cb?: (error: Error | null | undefined) => void,
|
||||
): boolean;
|
||||
write(
|
||||
chunk: any,
|
||||
cb?: (error: Error | null | undefined) => void,
|
||||
): boolean;
|
||||
setDefaultEncoding(encoding: BufferEncoding): this;
|
||||
end(cb?: () => void): this;
|
||||
end(chunk: any, cb?: () => void): this;
|
||||
end(chunk: any, encoding?: BufferEncoding, cb?: () => void): this;
|
||||
cork(): void;
|
||||
uncork(): void;
|
||||
fromWeb<T = any>(
|
||||
pair: {
|
||||
readable: ReadableStream<T>;
|
||||
writable: WritableStream<T>;
|
||||
},
|
||||
options: DuplexOptions,
|
||||
): Duplex<T>;
|
||||
toWeb<T>(stream: Duplex<T>): {
|
||||
readable: ReadableStream<T>;
|
||||
writable: WritableStream<T>;
|
||||
};
|
||||
}
|
||||
var Duplex: DuplexConstructor;
|
||||
type TransformCallback = (error?: Error | null, data?: any) => void;
|
||||
interface TransformOptions extends DuplexOptions {
|
||||
construct?(
|
||||
@@ -985,7 +968,7 @@ declare module "stream" {
|
||||
* * `crypto streams`
|
||||
* @since v0.9.4
|
||||
*/
|
||||
class Transform extends Duplex {
|
||||
class Transform<T = any> extends Duplex<T> {
|
||||
constructor(opts?: TransformOptions);
|
||||
_transform(
|
||||
chunk: any,
|
||||
@@ -998,7 +981,7 @@ declare module "stream" {
|
||||
* The `stream.PassThrough` class is a trivial implementation of a `Transform` stream that simply passes the input bytes across to the output. Its purpose is
|
||||
* primarily for examples and testing, but there are some use cases where`stream.PassThrough` is useful as a building block for novel sorts of streams.
|
||||
*/
|
||||
class PassThrough extends Transform {}
|
||||
class PassThrough<T = any> extends Transform<T> {}
|
||||
/**
|
||||
* Attaches an AbortSignal to a readable or writeable stream. This lets code
|
||||
* control stream destruction using an `AbortController`.
|
||||
|
||||
31
packages/bun-types/tests/mocks.test-d.ts
Normal file
31
packages/bun-types/tests/mocks.test-d.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { expectType } from "tsd";
|
||||
import { mock, jest } from "bun:test";
|
||||
|
||||
const mock1 = mock((arg: string) => {
|
||||
return arg.length;
|
||||
});
|
||||
|
||||
const arg1 = mock1("1");
|
||||
expectType<number>(arg1);
|
||||
mock;
|
||||
|
||||
type arg2 = jest.Spied<() => string>;
|
||||
declare var arg2: arg2;
|
||||
arg2.mock.calls[0];
|
||||
mock;
|
||||
|
||||
// @ts-expect-error
|
||||
jest.fn<() => Promise<string>>().mockReturnValue("asdf");
|
||||
// @ts-expect-error
|
||||
jest.fn<() => string>().mockReturnValue(24);
|
||||
jest.fn<() => string>().mockReturnValue("24");
|
||||
|
||||
jest.fn<() => Promise<string>>().mockResolvedValue("asdf");
|
||||
// @ts-expect-error
|
||||
jest.fn<() => string>().mockResolvedValue(24);
|
||||
// @ts-expect-error
|
||||
jest.fn<() => string>().mockResolvedValue("24");
|
||||
|
||||
jest.fn().mockClear();
|
||||
jest.fn().mockReset();
|
||||
jest.fn().mockRejectedValueOnce(new Error());
|
||||
@@ -39,7 +39,8 @@ type User = {
|
||||
|
||||
Bun.serve<User>({
|
||||
fetch(req, server) {
|
||||
if (req.url === "/chat") {
|
||||
const url = new URL(req.url);
|
||||
if (url.pathname === "/chat") {
|
||||
if (
|
||||
server.upgrade(req, {
|
||||
data: {
|
||||
|
||||
287
src/ArenaAllocator.zig
Normal file
287
src/ArenaAllocator.zig
Normal file
@@ -0,0 +1,287 @@
|
||||
/// TODO: delete this once we've upgraded Zig and https://github.com/ziglang/zig/pull/15985 is merged.
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const mem = std.mem;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
/// This allocator takes an existing allocator, wraps it, and provides an interface
|
||||
/// where you can allocate without freeing, and then free it all together.
|
||||
pub const ArenaAllocator = struct {
|
||||
child_allocator: Allocator,
|
||||
state: State,
|
||||
|
||||
/// Inner state of ArenaAllocator. Can be stored rather than the entire ArenaAllocator
|
||||
/// as a memory-saving optimization.
|
||||
pub const State = struct {
|
||||
buffer_list: std.SinglyLinkedList(usize) = .{},
|
||||
end_index: usize = 0,
|
||||
|
||||
pub fn promote(self: State, child_allocator: Allocator) ArenaAllocator {
|
||||
return .{
|
||||
.child_allocator = child_allocator,
|
||||
.state = self,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub fn allocator(self: *ArenaAllocator) Allocator {
|
||||
return .{
|
||||
.ptr = self,
|
||||
.vtable = &.{
|
||||
.alloc = alloc,
|
||||
.resize = resize,
|
||||
.free = free,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const BufNode = std.SinglyLinkedList(usize).Node;
|
||||
|
||||
pub fn init(child_allocator: Allocator) ArenaAllocator {
|
||||
return (State{}).promote(child_allocator);
|
||||
}
|
||||
|
||||
pub fn deinit(self: ArenaAllocator) void {
|
||||
// NOTE: When changing this, make sure `reset()` is adjusted accordingly!
|
||||
|
||||
var it = self.state.buffer_list.first;
|
||||
while (it) |node| {
|
||||
// this has to occur before the free because the free frees node
|
||||
const next_it = node.next;
|
||||
const align_bits = std.math.log2_int(usize, @alignOf(BufNode));
|
||||
const alloc_buf = @ptrCast([*]u8, node)[0..node.data];
|
||||
self.child_allocator.rawFree(alloc_buf, align_bits, @returnAddress());
|
||||
it = next_it;
|
||||
}
|
||||
}
|
||||
|
||||
pub const ResetMode = union(enum) {
|
||||
/// Releases all allocated memory in the arena.
|
||||
free_all,
|
||||
/// This will pre-heat the arena for future allocations by allocating a
|
||||
/// large enough buffer for all previously done allocations.
|
||||
/// Preheating will speed up the allocation process by invoking the backing allocator
|
||||
/// less often than before. If `reset()` is used in a loop, this means that after the
|
||||
/// biggest operation, no memory allocations are performed anymore.
|
||||
retain_capacity,
|
||||
/// This is the same as `retain_capacity`, but the memory will be shrunk to
|
||||
/// this value if it exceeds the limit.
|
||||
retain_with_limit: usize,
|
||||
};
|
||||
/// Queries the current memory use of this arena.
|
||||
/// This will **not** include the storage required for internal keeping.
|
||||
pub fn queryCapacity(self: ArenaAllocator) usize {
|
||||
var size: usize = 0;
|
||||
var it = self.state.buffer_list.first;
|
||||
while (it) |node| : (it = node.next) {
|
||||
// Compute the actually allocated size excluding the
|
||||
// linked list node.
|
||||
size += node.data - @sizeOf(BufNode);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
/// Resets the arena allocator and frees all allocated memory.
|
||||
///
|
||||
/// `mode` defines how the currently allocated memory is handled.
|
||||
/// See the variant documentation for `ResetMode` for the effects of each mode.
|
||||
///
|
||||
/// The function will return whether the reset operation was successful or not.
|
||||
/// If the reallocation failed `false` is returned. The arena will still be fully
|
||||
/// functional in that case, all memory is released. Future allocations just might
|
||||
/// be slower.
|
||||
///
|
||||
/// NOTE: If `mode` is `free_mode`, the function will always return `true`.
|
||||
pub fn reset(self: *ArenaAllocator, mode: ResetMode) bool {
|
||||
// Some words on the implementation:
|
||||
// The reset function can be implemented with two basic approaches:
|
||||
// - Counting how much bytes were allocated since the last reset, and storing that
|
||||
// information in State. This will make reset fast and alloc only a teeny tiny bit
|
||||
// slower.
|
||||
// - Counting how much bytes were allocated by iterating the chunk linked list. This
|
||||
// will make reset slower, but alloc() keeps the same speed when reset() as if reset()
|
||||
// would not exist.
|
||||
//
|
||||
// The second variant was chosen for implementation, as with more and more calls to reset(),
|
||||
// the function will get faster and faster. At one point, the complexity of the function
|
||||
// will drop to amortized O(1), as we're only ever having a single chunk that will not be
|
||||
// reallocated, and we're not even touching the backing allocator anymore.
|
||||
//
|
||||
// Thus, only the first hand full of calls to reset() will actually need to iterate the linked
|
||||
// list, all future calls are just taking the first node, and only resetting the `end_index`
|
||||
// value.
|
||||
const requested_capacity = switch (mode) {
|
||||
.retain_capacity => self.queryCapacity(),
|
||||
.retain_with_limit => |limit| @min(limit, self.queryCapacity()),
|
||||
.free_all => 0,
|
||||
};
|
||||
if (requested_capacity == 0) {
|
||||
// just reset when we don't have anything to reallocate
|
||||
self.deinit();
|
||||
self.state = State{};
|
||||
return true;
|
||||
}
|
||||
const total_size = requested_capacity + @sizeOf(BufNode);
|
||||
const align_bits = std.math.log2_int(usize, @alignOf(BufNode));
|
||||
// Free all nodes except for the last one
|
||||
var it = self.state.buffer_list.first;
|
||||
const maybe_first_node = while (it) |node| {
|
||||
// this has to occur before the free because the free frees node
|
||||
const next_it = node.next;
|
||||
if (next_it == null)
|
||||
break node;
|
||||
const alloc_buf = @ptrCast([*]u8, node)[0..node.data];
|
||||
self.child_allocator.rawFree(alloc_buf, align_bits, @returnAddress());
|
||||
it = next_it;
|
||||
} else null;
|
||||
std.debug.assert(maybe_first_node == null or maybe_first_node.?.next == null);
|
||||
// reset the state before we try resizing the buffers, so we definitely have reset the arena to 0.
|
||||
self.state.end_index = 0;
|
||||
if (maybe_first_node) |first_node| {
|
||||
self.state.buffer_list.first = first_node;
|
||||
// perfect, no need to invoke the child_allocator
|
||||
if (first_node.data == total_size)
|
||||
return true;
|
||||
const first_alloc_buf = @ptrCast([*]u8, first_node)[0..first_node.data];
|
||||
if (self.child_allocator.rawResize(first_alloc_buf, align_bits, total_size, @returnAddress())) {
|
||||
// successful resize
|
||||
first_node.data = total_size;
|
||||
} else {
|
||||
// manual realloc
|
||||
const new_ptr = self.child_allocator.rawAlloc(total_size, align_bits, @returnAddress()) orelse {
|
||||
// we failed to preheat the arena properly, signal this to the user.
|
||||
return false;
|
||||
};
|
||||
self.child_allocator.rawFree(first_alloc_buf, align_bits, @returnAddress());
|
||||
const node = @ptrCast(*BufNode, @alignCast(@alignOf(BufNode), new_ptr));
|
||||
node.* = .{ .data = total_size };
|
||||
self.state.buffer_list.first = node;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn createNode(self: *ArenaAllocator, prev_len: usize, minimum_size: usize) ?*BufNode {
|
||||
const actual_min_size = minimum_size + (@sizeOf(BufNode) + 16);
|
||||
const big_enough_len = prev_len + actual_min_size;
|
||||
const len = big_enough_len + big_enough_len / 2;
|
||||
const log2_align = comptime std.math.log2_int(usize, @alignOf(BufNode));
|
||||
const ptr = self.child_allocator.rawAlloc(len, log2_align, @returnAddress()) orelse
|
||||
return null;
|
||||
const buf_node = @ptrCast(*BufNode, @alignCast(@alignOf(BufNode), ptr));
|
||||
buf_node.* = .{ .data = len };
|
||||
self.state.buffer_list.prepend(buf_node);
|
||||
self.state.end_index = 0;
|
||||
return buf_node;
|
||||
}
|
||||
|
||||
fn alloc(ctx: *anyopaque, n: usize, log2_ptr_align: u8, ra: usize) ?[*]u8 {
|
||||
const self = @ptrCast(*ArenaAllocator, @alignCast(@alignOf(ArenaAllocator), ctx));
|
||||
_ = ra;
|
||||
|
||||
const ptr_align = @as(usize, 1) << @intCast(Allocator.Log2Align, log2_ptr_align);
|
||||
var cur_node = if (self.state.buffer_list.first) |first_node|
|
||||
first_node
|
||||
else
|
||||
(self.createNode(0, n + ptr_align) orelse return null);
|
||||
while (true) {
|
||||
const cur_alloc_buf = @ptrCast([*]u8, cur_node)[0..cur_node.data];
|
||||
const cur_buf = cur_alloc_buf[@sizeOf(BufNode)..];
|
||||
const addr = @intFromPtr(cur_buf.ptr) + self.state.end_index;
|
||||
const adjusted_addr = mem.alignForward(usize, addr, ptr_align);
|
||||
const adjusted_index = self.state.end_index + (adjusted_addr - addr);
|
||||
const new_end_index = adjusted_index + n;
|
||||
|
||||
if (new_end_index <= cur_buf.len) {
|
||||
const result = cur_buf[adjusted_index..new_end_index];
|
||||
self.state.end_index = new_end_index;
|
||||
return result.ptr;
|
||||
}
|
||||
|
||||
const bigger_buf_size = @sizeOf(BufNode) + new_end_index;
|
||||
const log2_align = comptime std.math.log2_int(usize, @alignOf(BufNode));
|
||||
if (self.child_allocator.rawResize(cur_alloc_buf, log2_align, bigger_buf_size, @returnAddress())) {
|
||||
cur_node.data = bigger_buf_size;
|
||||
} else {
|
||||
// Allocate a new node if that's not possible
|
||||
cur_node = self.createNode(cur_buf.len, n + ptr_align) orelse return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resize(ctx: *anyopaque, buf: []u8, log2_buf_align: u8, new_len: usize, ret_addr: usize) bool {
|
||||
const self = @ptrCast(*ArenaAllocator, @alignCast(@alignOf(ArenaAllocator), ctx));
|
||||
_ = log2_buf_align;
|
||||
_ = ret_addr;
|
||||
|
||||
const cur_node = self.state.buffer_list.first orelse return false;
|
||||
const cur_buf = @ptrCast([*]u8, cur_node)[@sizeOf(BufNode)..cur_node.data];
|
||||
if (@intFromPtr(cur_buf.ptr) + self.state.end_index != @intFromPtr(buf.ptr) + buf.len) {
|
||||
// It's not the most recent allocation, so it cannot be expanded,
|
||||
// but it's fine if they want to make it smaller.
|
||||
return new_len <= buf.len;
|
||||
}
|
||||
|
||||
if (buf.len >= new_len) {
|
||||
self.state.end_index -= buf.len - new_len;
|
||||
return true;
|
||||
} else if (cur_buf.len - self.state.end_index >= new_len - buf.len) {
|
||||
self.state.end_index += new_len - buf.len;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fn free(ctx: *anyopaque, buf: []u8, log2_buf_align: u8, ret_addr: usize) void {
|
||||
_ = log2_buf_align;
|
||||
_ = ret_addr;
|
||||
|
||||
const self = @ptrCast(*ArenaAllocator, @alignCast(@alignOf(ArenaAllocator), ctx));
|
||||
|
||||
const cur_node = self.state.buffer_list.first orelse return;
|
||||
const cur_buf = @ptrCast([*]u8, cur_node)[@sizeOf(BufNode)..cur_node.data];
|
||||
|
||||
if (@intFromPtr(cur_buf.ptr) + self.state.end_index == @intFromPtr(buf.ptr) + buf.len) {
|
||||
self.state.end_index -= buf.len;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
test "ArenaAllocator (reset with preheating)" {
|
||||
var arena_allocator = ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena_allocator.deinit();
|
||||
// provides some variance in the allocated data
|
||||
var rng_src = std.rand.DefaultPrng.init(19930913);
|
||||
const random = rng_src.random();
|
||||
var rounds: usize = 25;
|
||||
while (rounds > 0) {
|
||||
rounds -= 1;
|
||||
_ = arena_allocator.reset(.retain_capacity);
|
||||
var alloced_bytes: usize = 0;
|
||||
var total_size: usize = random.intRangeAtMost(usize, 256, 16384);
|
||||
while (alloced_bytes < total_size) {
|
||||
const size = random.intRangeAtMost(usize, 16, 256);
|
||||
const alignment = 32;
|
||||
const slice = try arena_allocator.allocator().alignedAlloc(u8, alignment, size);
|
||||
try std.testing.expect(std.mem.isAligned(@intFromPtr(slice.ptr), alignment));
|
||||
try std.testing.expectEqual(size, slice.len);
|
||||
alloced_bytes += slice.len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test "ArenaAllocator (reset while retaining a buffer)" {
|
||||
var arena_allocator = ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena_allocator.deinit();
|
||||
const a = arena_allocator.allocator();
|
||||
|
||||
// Create two internal buffers
|
||||
_ = try a.alloc(u8, 1);
|
||||
_ = try a.alloc(u8, 1000);
|
||||
|
||||
// Check that we have at least two buffers
|
||||
try std.testing.expect(arena_allocator.state.buffer_list.first.?.next != null);
|
||||
|
||||
// This retains the first allocated buffer
|
||||
try std.testing.expect(arena_allocator.reset(.{ .retain_with_limit = 1 }));
|
||||
}
|
||||
@@ -55,7 +55,7 @@ pub const version: @import("./install/semver.zig").Version = .{
|
||||
|
||||
pub fn setThreadName(name: StringTypes.stringZ) void {
|
||||
if (Environment.isLinux) {
|
||||
_ = std.os.prctl(.SET_NAME, .{@ptrToInt(name.ptr)}) catch 0;
|
||||
_ = std.os.prctl(.SET_NAME, .{@intFromPtr(name.ptr)}) catch 0;
|
||||
} else if (Environment.isMac) {
|
||||
_ = std.c.pthread_setname_np(name);
|
||||
}
|
||||
|
||||
@@ -2,19 +2,18 @@ const std = @import("std");
|
||||
|
||||
const FeatureFlags = @import("./feature_flags.zig");
|
||||
const Environment = @import("./env.zig");
|
||||
const Wyhash = std.hash.Wyhash;
|
||||
const FixedBufferAllocator = std.heap.FixedBufferAllocator;
|
||||
const constStrToU8 = @import("root").bun.constStrToU8;
|
||||
const bun = @import("root").bun;
|
||||
pub fn isSliceInBuffer(slice: anytype, buffer: anytype) bool {
|
||||
return (@ptrToInt(&buffer) <= @ptrToInt(slice.ptr) and (@ptrToInt(slice.ptr) + slice.len) <= (@ptrToInt(buffer) + buffer.len));
|
||||
return (@intFromPtr(&buffer) <= @intFromPtr(slice.ptr) and (@intFromPtr(slice.ptr) + slice.len) <= (@intFromPtr(buffer) + buffer.len));
|
||||
}
|
||||
|
||||
pub fn sliceRange(slice: []const u8, buffer: []const u8) ?[2]u32 {
|
||||
return if (@ptrToInt(buffer.ptr) <= @ptrToInt(slice.ptr) and
|
||||
(@ptrToInt(slice.ptr) + slice.len) <= (@ptrToInt(buffer.ptr) + buffer.len))
|
||||
return if (@intFromPtr(buffer.ptr) <= @intFromPtr(slice.ptr) and
|
||||
(@intFromPtr(slice.ptr) + slice.len) <= (@intFromPtr(buffer.ptr) + buffer.len))
|
||||
[2]u32{
|
||||
@truncate(u32, @ptrToInt(slice.ptr) - @ptrToInt(buffer.ptr)),
|
||||
@truncate(u32, @intFromPtr(slice.ptr) - @intFromPtr(buffer.ptr)),
|
||||
@truncate(u32, slice.len),
|
||||
}
|
||||
else
|
||||
@@ -53,7 +52,6 @@ pub const Result = struct {
|
||||
return r.index >= count;
|
||||
}
|
||||
};
|
||||
const Seed = 999;
|
||||
|
||||
pub const NotFound = IndexType{
|
||||
.index = std.math.maxInt(u31),
|
||||
@@ -488,7 +486,7 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, comptime store_
|
||||
|
||||
pub fn getOrPut(self: *Self, denormalized_key: []const u8) !Result {
|
||||
const key = if (comptime remove_trailing_slashes) std.mem.trimRight(u8, denormalized_key, "/") else denormalized_key;
|
||||
const _key = Wyhash.hash(Seed, key);
|
||||
const _key = bun.hash(key);
|
||||
|
||||
self.mutex.lock();
|
||||
defer self.mutex.unlock();
|
||||
@@ -516,7 +514,7 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, comptime store_
|
||||
|
||||
pub fn get(self: *Self, denormalized_key: []const u8) ?*ValueType {
|
||||
const key = if (comptime remove_trailing_slashes) std.mem.trimRight(u8, denormalized_key, "/") else denormalized_key;
|
||||
const _key = Wyhash.hash(Seed, key);
|
||||
const _key = bun.hash(key);
|
||||
self.mutex.lock();
|
||||
defer self.mutex.unlock();
|
||||
const index = self.index.get(_key) orelse return null;
|
||||
@@ -577,7 +575,7 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, comptime store_
|
||||
|
||||
const key = if (comptime remove_trailing_slashes) std.mem.trimRight(u8, denormalized_key, "/") else denormalized_key;
|
||||
|
||||
const _key = Wyhash.hash(Seed, key);
|
||||
const _key = bun.hash(key);
|
||||
_ = self.index.remove(_key);
|
||||
// const index = self.index.get(_key) orelse return;
|
||||
// switch (index) {
|
||||
|
||||
@@ -201,7 +201,7 @@ pub fn Writer(comptime WritableStream: type) type {
|
||||
}
|
||||
|
||||
pub inline fn writeEnum(this: *Self, val: anytype) !void {
|
||||
try this.writeInt(@enumToInt(val));
|
||||
try this.writeInt(@intFromEnum(val));
|
||||
}
|
||||
|
||||
pub fn writeValue(this: *Self, comptime SliceType: type, slice: SliceType) !void {
|
||||
|
||||
@@ -261,7 +261,7 @@ pub const GenerateHeader = struct {
|
||||
pub const GeneratePlatform = struct {
|
||||
var osversion_name: [32]u8 = undefined;
|
||||
pub fn forMac() Analytics.Platform {
|
||||
@memset(&osversion_name, 0, osversion_name.len);
|
||||
@memset(&osversion_name, 0);
|
||||
|
||||
var platform = Analytics.Platform{ .os = Analytics.OperatingSystem.macos, .version = &[_]u8{}, .arch = platform_arch };
|
||||
var len = osversion_name.len - 1;
|
||||
@@ -340,7 +340,7 @@ pub const GenerateHeader = struct {
|
||||
offset = std.mem.indexOfScalar(u8, out, '"') orelse return Analytics.Uint64{};
|
||||
out = out[0..offset];
|
||||
|
||||
const hash = std.hash.Wyhash.hash(0, std.mem.trim(u8, out, "\n\r "));
|
||||
const hash = bun.hash(std.mem.trim(u8, out, "\n\r "));
|
||||
var hash_bytes = std.mem.asBytes(&hash);
|
||||
return Analytics.Uint64{
|
||||
.first = std.mem.readIntNative(u32, hash_bytes[0..4]),
|
||||
@@ -357,7 +357,7 @@ pub const GenerateHeader = struct {
|
||||
defer file.close();
|
||||
var read_count = try file.read(&linux_machine_id);
|
||||
|
||||
const hash = std.hash.Wyhash.hash(0, std.mem.trim(u8, linux_machine_id[0..read_count], "\n\r "));
|
||||
const hash = bun.hash(std.mem.trim(u8, linux_machine_id[0..read_count], "\n\r "));
|
||||
var hash_bytes = std.mem.asBytes(&hash);
|
||||
return Analytics.Uint64{
|
||||
.first = std.mem.readIntNative(u32, hash_bytes[0..4]),
|
||||
@@ -540,8 +540,8 @@ pub const EventList = struct {
|
||||
}
|
||||
|
||||
@atomicStore(bool, &is_stuck, retry_remaining == 0, .Release);
|
||||
stuck_count += @intCast(u8, @boolToInt(retry_remaining == 0));
|
||||
stuck_count *= @intCast(u8, @boolToInt(retry_remaining == 0));
|
||||
stuck_count += @intCast(u8, @intFromBool(retry_remaining == 0));
|
||||
stuck_count *= @intCast(u8, @intFromBool(retry_remaining == 0));
|
||||
disabled = disabled or stuck_count > 4;
|
||||
|
||||
this.in_buffer.reset();
|
||||
|
||||
@@ -201,7 +201,7 @@ pub fn Writer(comptime WritableStream: type) type {
|
||||
}
|
||||
|
||||
pub inline fn writeEnum(this: *Self, val: anytype) !void {
|
||||
try this.writeInt(@enumToInt(val));
|
||||
try this.writeInt(@intFromEnum(val));
|
||||
}
|
||||
|
||||
pub fn writeValue(this: *Self, comptime SliceType: type, slice: SliceType) !void {
|
||||
@@ -881,9 +881,9 @@ pub const Api = struct {
|
||||
try writer.writeValue(@TypeOf(this.factory), this.factory);
|
||||
try writer.writeEnum(this.runtime);
|
||||
try writer.writeValue(@TypeOf(this.fragment), this.fragment);
|
||||
try writer.writeInt(@as(u8, @boolToInt(this.development)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(this.development)));
|
||||
try writer.writeValue(@TypeOf(this.import_source), this.import_source);
|
||||
try writer.writeInt(@as(u8, @boolToInt(this.react_fast_refresh)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(this.react_fast_refresh)));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1151,7 +1151,7 @@ pub const Api = struct {
|
||||
pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
|
||||
try writer.writeEnum(this.kind);
|
||||
try writer.writeValue(@TypeOf(this.path), this.path);
|
||||
try writer.writeInt(@as(u8, @boolToInt(this.dynamic)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(this.dynamic)));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1390,7 +1390,7 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.development) |development| {
|
||||
try writer.writeFieldID(5);
|
||||
try writer.writeInt(@as(u8, @boolToInt(development)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(development)));
|
||||
}
|
||||
if (this.client_css_in_js) |client_css_in_js| {
|
||||
try writer.writeFieldID(6);
|
||||
@@ -1564,7 +1564,7 @@ pub const Api = struct {
|
||||
pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
|
||||
try writer.writeValue(@TypeOf(this.package), this.package);
|
||||
try writer.writeValue(@TypeOf(this.display_name), this.display_name);
|
||||
try writer.writeInt(@as(u8, @boolToInt(this.development)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(this.development)));
|
||||
try writer.writeValue(@TypeOf(this.entry_points), this.entry_points);
|
||||
try writer.writeEnum(this.client_css_in_js);
|
||||
try writer.writeValue(@TypeOf(this.override_modules), this.override_modules);
|
||||
@@ -1866,7 +1866,7 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.preserve_symlinks) |preserve_symlinks| {
|
||||
try writer.writeFieldID(7);
|
||||
try writer.writeInt(@as(u8, @boolToInt(preserve_symlinks)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(preserve_symlinks)));
|
||||
}
|
||||
if (this.entry_points) |entry_points| {
|
||||
try writer.writeFieldID(8);
|
||||
@@ -1874,7 +1874,7 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.write) |write| {
|
||||
try writer.writeFieldID(9);
|
||||
try writer.writeInt(@as(u8, @boolToInt(write)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(write)));
|
||||
}
|
||||
if (this.inject) |inject| {
|
||||
try writer.writeFieldID(10);
|
||||
@@ -1902,7 +1902,7 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.serve) |serve| {
|
||||
try writer.writeFieldID(16);
|
||||
try writer.writeInt(@as(u8, @boolToInt(serve)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(serve)));
|
||||
}
|
||||
if (this.extension_order) |extension_order| {
|
||||
try writer.writeFieldID(17);
|
||||
@@ -1910,7 +1910,7 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.generate_node_module_bundle) |generate_node_module_bundle| {
|
||||
try writer.writeFieldID(18);
|
||||
try writer.writeInt(@as(u8, @boolToInt(generate_node_module_bundle)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(generate_node_module_bundle)));
|
||||
}
|
||||
if (this.node_modules_bundle_path) |node_modules_bundle_path| {
|
||||
try writer.writeFieldID(19);
|
||||
@@ -1930,11 +1930,11 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.no_summary) |no_summary| {
|
||||
try writer.writeFieldID(23);
|
||||
try writer.writeInt(@as(u8, @boolToInt(no_summary)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(no_summary)));
|
||||
}
|
||||
if (this.disable_hmr) |disable_hmr| {
|
||||
try writer.writeFieldID(24);
|
||||
try writer.writeInt(@as(u8, @boolToInt(disable_hmr)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(disable_hmr)));
|
||||
}
|
||||
if (this.port) |port| {
|
||||
try writer.writeFieldID(25);
|
||||
@@ -2259,7 +2259,7 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.build) |build| {
|
||||
try writer.writeFieldID(2);
|
||||
try writer.writeInt(@as(u8, @boolToInt(build)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(build)));
|
||||
}
|
||||
try writer.endMessage();
|
||||
}
|
||||
@@ -2822,35 +2822,35 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.dry_run) |dry_run| {
|
||||
try writer.writeFieldID(6);
|
||||
try writer.writeInt(@as(u8, @boolToInt(dry_run)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(dry_run)));
|
||||
}
|
||||
if (this.force) |force| {
|
||||
try writer.writeFieldID(7);
|
||||
try writer.writeInt(@as(u8, @boolToInt(force)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(force)));
|
||||
}
|
||||
if (this.save_dev) |save_dev| {
|
||||
try writer.writeFieldID(8);
|
||||
try writer.writeInt(@as(u8, @boolToInt(save_dev)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(save_dev)));
|
||||
}
|
||||
if (this.save_optional) |save_optional| {
|
||||
try writer.writeFieldID(9);
|
||||
try writer.writeInt(@as(u8, @boolToInt(save_optional)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(save_optional)));
|
||||
}
|
||||
if (this.save_peer) |save_peer| {
|
||||
try writer.writeFieldID(10);
|
||||
try writer.writeInt(@as(u8, @boolToInt(save_peer)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(save_peer)));
|
||||
}
|
||||
if (this.save_lockfile) |save_lockfile| {
|
||||
try writer.writeFieldID(11);
|
||||
try writer.writeInt(@as(u8, @boolToInt(save_lockfile)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(save_lockfile)));
|
||||
}
|
||||
if (this.production) |production| {
|
||||
try writer.writeFieldID(12);
|
||||
try writer.writeInt(@as(u8, @boolToInt(production)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(production)));
|
||||
}
|
||||
if (this.save_yarn_lockfile) |save_yarn_lockfile| {
|
||||
try writer.writeFieldID(13);
|
||||
try writer.writeInt(@as(u8, @boolToInt(save_yarn_lockfile)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(save_yarn_lockfile)));
|
||||
}
|
||||
if (this.native_bin_links) |native_bin_links| {
|
||||
try writer.writeFieldID(14);
|
||||
@@ -2858,11 +2858,11 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.disable_cache) |disable_cache| {
|
||||
try writer.writeFieldID(15);
|
||||
try writer.writeInt(@as(u8, @boolToInt(disable_cache)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(disable_cache)));
|
||||
}
|
||||
if (this.disable_manifest_cache) |disable_manifest_cache| {
|
||||
try writer.writeFieldID(16);
|
||||
try writer.writeInt(@as(u8, @boolToInt(disable_manifest_cache)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(disable_manifest_cache)));
|
||||
}
|
||||
if (this.global_dir) |global_dir| {
|
||||
try writer.writeFieldID(17);
|
||||
|
||||
@@ -201,7 +201,7 @@ pub fn Writer(comptime WritableStream: type) type {
|
||||
}
|
||||
|
||||
pub inline fn writeEnum(this: *Self, val: anytype) !void {
|
||||
try this.writeInt(@enumToInt(val));
|
||||
try this.writeInt(@intFromEnum(val));
|
||||
}
|
||||
|
||||
pub fn writeValue(this: *Self, comptime SliceType: type, slice: SliceType) !void {
|
||||
@@ -896,9 +896,9 @@ pub const Api = struct {
|
||||
try writer.writeValue(@TypeOf(this.factory), this.factory);
|
||||
try writer.writeEnum(this.runtime);
|
||||
try writer.writeValue(@TypeOf(this.fragment), this.fragment);
|
||||
try writer.writeInt(@as(u8, @boolToInt(this.development)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(this.development)));
|
||||
try writer.writeValue(@TypeOf(this.import_source), this.import_source);
|
||||
try writer.writeInt(@as(u8, @boolToInt(this.react_fast_refresh)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(this.react_fast_refresh)));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1166,7 +1166,7 @@ pub const Api = struct {
|
||||
pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
|
||||
try writer.writeEnum(this.kind);
|
||||
try writer.writeValue(@TypeOf(this.path), this.path);
|
||||
try writer.writeInt(@as(u8, @boolToInt(this.dynamic)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(this.dynamic)));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1405,7 +1405,7 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.development) |development| {
|
||||
try writer.writeFieldID(5);
|
||||
try writer.writeInt(@as(u8, @boolToInt(development)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(development)));
|
||||
}
|
||||
if (this.client_css_in_js) |client_css_in_js| {
|
||||
try writer.writeFieldID(6);
|
||||
@@ -1579,7 +1579,7 @@ pub const Api = struct {
|
||||
pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
|
||||
try writer.writeValue(@TypeOf(this.package), this.package);
|
||||
try writer.writeValue(@TypeOf(this.display_name), this.display_name);
|
||||
try writer.writeInt(@as(u8, @boolToInt(this.development)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(this.development)));
|
||||
try writer.writeValue(@TypeOf(this.entry_points), this.entry_points);
|
||||
try writer.writeEnum(this.client_css_in_js);
|
||||
try writer.writeValue(@TypeOf(this.override_modules), this.override_modules);
|
||||
@@ -1887,7 +1887,7 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.preserve_symlinks) |preserve_symlinks| {
|
||||
try writer.writeFieldID(7);
|
||||
try writer.writeInt(@as(u8, @boolToInt(preserve_symlinks)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(preserve_symlinks)));
|
||||
}
|
||||
if (this.entry_points) |entry_points| {
|
||||
try writer.writeFieldID(8);
|
||||
@@ -1895,7 +1895,7 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.write) |write| {
|
||||
try writer.writeFieldID(9);
|
||||
try writer.writeInt(@as(u8, @boolToInt(write)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(write)));
|
||||
}
|
||||
if (this.inject) |inject| {
|
||||
try writer.writeFieldID(10);
|
||||
@@ -1923,7 +1923,7 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.serve) |serve| {
|
||||
try writer.writeFieldID(16);
|
||||
try writer.writeInt(@as(u8, @boolToInt(serve)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(serve)));
|
||||
}
|
||||
if (this.extension_order) |extension_order| {
|
||||
try writer.writeFieldID(17);
|
||||
@@ -1931,7 +1931,7 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.generate_node_module_bundle) |generate_node_module_bundle| {
|
||||
try writer.writeFieldID(18);
|
||||
try writer.writeInt(@as(u8, @boolToInt(generate_node_module_bundle)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(generate_node_module_bundle)));
|
||||
}
|
||||
if (this.node_modules_bundle_path) |node_modules_bundle_path| {
|
||||
try writer.writeFieldID(19);
|
||||
@@ -1951,11 +1951,11 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.no_summary) |no_summary| {
|
||||
try writer.writeFieldID(23);
|
||||
try writer.writeInt(@as(u8, @boolToInt(no_summary)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(no_summary)));
|
||||
}
|
||||
if (this.disable_hmr) |disable_hmr| {
|
||||
try writer.writeFieldID(24);
|
||||
try writer.writeInt(@as(u8, @boolToInt(disable_hmr)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(disable_hmr)));
|
||||
}
|
||||
if (this.port) |port| {
|
||||
try writer.writeFieldID(25);
|
||||
@@ -2427,7 +2427,7 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.build) |build| {
|
||||
try writer.writeFieldID(2);
|
||||
try writer.writeInt(@as(u8, @boolToInt(build)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(build)));
|
||||
}
|
||||
try writer.endMessage();
|
||||
}
|
||||
@@ -2995,35 +2995,35 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.dry_run) |dry_run| {
|
||||
try writer.writeFieldID(6);
|
||||
try writer.writeInt(@as(u8, @boolToInt(dry_run)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(dry_run)));
|
||||
}
|
||||
if (this.force) |force| {
|
||||
try writer.writeFieldID(7);
|
||||
try writer.writeInt(@as(u8, @boolToInt(force)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(force)));
|
||||
}
|
||||
if (this.save_dev) |save_dev| {
|
||||
try writer.writeFieldID(8);
|
||||
try writer.writeInt(@as(u8, @boolToInt(save_dev)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(save_dev)));
|
||||
}
|
||||
if (this.save_optional) |save_optional| {
|
||||
try writer.writeFieldID(9);
|
||||
try writer.writeInt(@as(u8, @boolToInt(save_optional)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(save_optional)));
|
||||
}
|
||||
if (this.save_peer) |save_peer| {
|
||||
try writer.writeFieldID(10);
|
||||
try writer.writeInt(@as(u8, @boolToInt(save_peer)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(save_peer)));
|
||||
}
|
||||
if (this.save_lockfile) |save_lockfile| {
|
||||
try writer.writeFieldID(11);
|
||||
try writer.writeInt(@as(u8, @boolToInt(save_lockfile)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(save_lockfile)));
|
||||
}
|
||||
if (this.production) |production| {
|
||||
try writer.writeFieldID(12);
|
||||
try writer.writeInt(@as(u8, @boolToInt(production)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(production)));
|
||||
}
|
||||
if (this.save_yarn_lockfile) |save_yarn_lockfile| {
|
||||
try writer.writeFieldID(13);
|
||||
try writer.writeInt(@as(u8, @boolToInt(save_yarn_lockfile)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(save_yarn_lockfile)));
|
||||
}
|
||||
if (this.native_bin_links) |native_bin_links| {
|
||||
try writer.writeFieldID(14);
|
||||
@@ -3031,11 +3031,11 @@ pub const Api = struct {
|
||||
}
|
||||
if (this.disable_cache) |disable_cache| {
|
||||
try writer.writeFieldID(15);
|
||||
try writer.writeInt(@as(u8, @boolToInt(disable_cache)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(disable_cache)));
|
||||
}
|
||||
if (this.disable_manifest_cache) |disable_manifest_cache| {
|
||||
try writer.writeFieldID(16);
|
||||
try writer.writeInt(@as(u8, @boolToInt(disable_manifest_cache)));
|
||||
try writer.writeInt(@as(u8, @intFromBool(disable_manifest_cache)));
|
||||
}
|
||||
if (this.global_dir) |global_dir| {
|
||||
try writer.writeFieldID(17);
|
||||
|
||||
@@ -275,7 +275,7 @@ pub const Ref = packed struct(u64) {
|
||||
}
|
||||
|
||||
pub inline fn hash64(key: Ref) u64 {
|
||||
return std.hash.Wyhash.hash(0, &@bitCast([8]u8, key.asU64()));
|
||||
return bun.hash(&@bitCast([8]u8, key.asU64()));
|
||||
}
|
||||
|
||||
pub fn eql(ref: Ref, b: Ref) bool {
|
||||
|
||||
@@ -30,7 +30,7 @@ pub fn BabyList(comptime Type: type) type {
|
||||
}
|
||||
|
||||
pub fn contains(this: @This(), item: []const Type) bool {
|
||||
return this.len > 0 and @ptrToInt(item.ptr) >= @ptrToInt(this.ptr) and @ptrToInt(item.ptr) < @ptrToInt(this.ptr) + this.len;
|
||||
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 {
|
||||
|
||||
@@ -34,7 +34,7 @@ pub fn main() anyerror!void {
|
||||
var i: usize = 0;
|
||||
while (j < amount) : (j += 1) {
|
||||
i = 0;
|
||||
@memcpy(duped.ptr, contents.ptr, contents.len);
|
||||
@memcpy(duped[0..contents.len], contents);
|
||||
}
|
||||
|
||||
if (index == std.math.maxInt(usize)) {
|
||||
|
||||
@@ -308,7 +308,7 @@ pub fn IntegerBitSet(comptime size: u16) type {
|
||||
}
|
||||
fn boolMaskBit(index: usize, value: bool) MaskInt {
|
||||
if (MaskInt == u0) return 0;
|
||||
return @as(MaskInt, @boolToInt(value)) << @intCast(ShiftInt, index);
|
||||
return @as(MaskInt, @intFromBool(value)) << @intCast(ShiftInt, index);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -653,7 +653,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
|
||||
return index >> @bitSizeOf(ShiftInt);
|
||||
}
|
||||
inline fn boolMaskBit(index: usize, value: bool) MaskInt {
|
||||
return @as(MaskInt, @boolToInt(value)) << @intCast(ShiftInt, index);
|
||||
return @as(MaskInt, @intFromBool(value)) << @intCast(ShiftInt, index);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -751,7 +751,7 @@ pub const DynamicBitSetUnmanaged = struct {
|
||||
// fill in any new masks
|
||||
if (new_masks > old_masks) {
|
||||
const fill_value = std.math.boolMask(MaskInt, fill);
|
||||
std.mem.set(MaskInt, self.masks[old_masks..new_masks], fill_value);
|
||||
@memset(self.masks[old_masks..new_masks], fill_value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1088,7 +1088,7 @@ pub const DynamicBitSetUnmanaged = struct {
|
||||
return index >> @bitSizeOf(ShiftInt);
|
||||
}
|
||||
fn boolMaskBit(index: usize, value: bool) MaskInt {
|
||||
return @as(MaskInt, @boolToInt(value)) << @intCast(ShiftInt, index);
|
||||
return @as(MaskInt, @intFromBool(value)) << @intCast(ShiftInt, index);
|
||||
}
|
||||
fn numMasks(bit_length: usize) usize {
|
||||
return (bit_length + (@bitSizeOf(MaskInt) - 1)) / @bitSizeOf(MaskInt);
|
||||
|
||||
@@ -42,14 +42,14 @@ pub const Map = struct {
|
||||
pub fn get(this: *Map, key: string) ?Blob {
|
||||
this.lock.lock();
|
||||
defer this.lock.unlock();
|
||||
return this.map.get(std.hash.Wyhash.hash(0, key));
|
||||
return this.map.get(bun.hash(key));
|
||||
}
|
||||
|
||||
pub fn put(this: *Map, key: string, blob: Blob) !void {
|
||||
this.lock.lock();
|
||||
defer this.lock.unlock();
|
||||
|
||||
return try this.map.put(std.hash.Wyhash.hash(0, key), blob);
|
||||
return try this.map.put(bun.hash(key), blob);
|
||||
}
|
||||
|
||||
pub fn reset(this: *Map) !void {
|
||||
|
||||
@@ -65,7 +65,8 @@ export fn OPENSSL_memory_alloc(size: usize) ?*anyopaque {
|
||||
|
||||
// BoringSSL always expects memory to be zero'd
|
||||
export fn OPENSSL_memory_free(ptr: *anyopaque) void {
|
||||
@memset(@ptrCast([*]u8, ptr), 0, bun.Mimalloc.mi_usable_size(ptr));
|
||||
const len = bun.Mimalloc.mi_usable_size(ptr);
|
||||
@memset(@ptrCast([*]u8, ptr)[0..len], 0);
|
||||
bun.Mimalloc.mi_free(ptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
8
|
||||
10
|
||||
|
||||
Submodule src/bun.js/WebKit updated: b2f1006a06...4c8ab8fdfb
@@ -844,7 +844,7 @@ pub const JSBundler = struct {
|
||||
|
||||
this.value = .{
|
||||
.success = .{
|
||||
.loader = @intToEnum(options.Loader, @intCast(u8, loader_as_int.to(i32))),
|
||||
.loader = @enumFromInt(options.Loader, @intCast(u8, loader_as_int.to(i32))),
|
||||
.source_code = source_code,
|
||||
},
|
||||
};
|
||||
@@ -928,7 +928,7 @@ pub const JSBundler = struct {
|
||||
else
|
||||
ZigString.fromUTF8(namespace);
|
||||
const path_string = ZigString.fromUTF8(path);
|
||||
JSBundlerPlugin__matchOnLoad(globalThis, this, &namespace_string, &path_string, context, @enumToInt(default_loader));
|
||||
JSBundlerPlugin__matchOnLoad(globalThis, this, &namespace_string, &path_string, context, @intFromEnum(default_loader));
|
||||
}
|
||||
|
||||
pub fn matchOnResolve(
|
||||
@@ -949,7 +949,7 @@ pub const JSBundler = struct {
|
||||
ZigString.fromUTF8(namespace);
|
||||
const path_string = ZigString.fromUTF8(path);
|
||||
const importer_string = ZigString.fromUTF8(importer);
|
||||
JSBundlerPlugin__matchOnResolve(globalThis, this, &namespace_string, &path_string, &importer_string, context, @enumToInt(import_record_kind));
|
||||
JSBundlerPlugin__matchOnResolve(globalThis, this, &namespace_string, &path_string, &importer_string, context, @intFromEnum(import_record_kind));
|
||||
}
|
||||
|
||||
pub fn addPlugin(
|
||||
|
||||
@@ -46,7 +46,7 @@ const Expr = JSAst.Expr;
|
||||
pub usingnamespace JSC.Codegen.JSTranspiler;
|
||||
|
||||
bundler: Bundler.Bundler,
|
||||
arena: std.heap.ArenaAllocator,
|
||||
arena: @import("root").bun.ArenaAllocator,
|
||||
transpiler_options: TranspilerOptions,
|
||||
scan_pass_result: ScanPassResult,
|
||||
buffer_writer: ?JSPrinter.BufferWriter = null,
|
||||
@@ -85,7 +85,7 @@ const TranspilerOptions = struct {
|
||||
// This is going to be hard to not leak
|
||||
pub const TransformTask = struct {
|
||||
input_code: ZigString = ZigString.init(""),
|
||||
protected_input_value: JSC.JSValue = @intToEnum(JSC.JSValue, 0),
|
||||
protected_input_value: JSC.JSValue = @enumFromInt(JSC.JSValue, 0),
|
||||
output_code: ZigString = ZigString.init(""),
|
||||
bundler: Bundler.Bundler = undefined,
|
||||
log: logger.Log,
|
||||
@@ -220,8 +220,8 @@ pub const TransformTask = struct {
|
||||
|
||||
finish(this.output_code, this.global, promise);
|
||||
|
||||
if (@enumToInt(this.protected_input_value) != 0) {
|
||||
this.protected_input_value = @intToEnum(JSC.JSValue, 0);
|
||||
if (@intFromEnum(this.protected_input_value) != 0) {
|
||||
this.protected_input_value = @enumFromInt(JSC.JSValue, 0);
|
||||
}
|
||||
this.deinit();
|
||||
}
|
||||
@@ -611,7 +611,7 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std
|
||||
while (length_iter.next()) |value| {
|
||||
if (value.isString()) {
|
||||
const length = @truncate(u32, value.getLength(globalThis));
|
||||
string_count += @as(u32, @boolToInt(length > 0));
|
||||
string_count += @as(u32, @intFromBool(length > 0));
|
||||
total_name_buf_len += length;
|
||||
}
|
||||
}
|
||||
@@ -726,7 +726,7 @@ pub fn constructor(
|
||||
globalThis: *JSC.JSGlobalObject,
|
||||
callframe: *JSC.CallFrame,
|
||||
) callconv(.C) ?*Transpiler {
|
||||
var temp = std.heap.ArenaAllocator.init(getAllocator(globalThis));
|
||||
var temp = @import("root").bun.ArenaAllocator.init(getAllocator(globalThis));
|
||||
const arguments = callframe.arguments(3);
|
||||
var args = JSC.Node.ArgumentsSlice.init(
|
||||
globalThis.bunVM(),
|
||||
@@ -877,7 +877,7 @@ fn getParseResult(this: *Transpiler, allocator: std.mem.Allocator, code: []const
|
||||
for (res.ast.import_records.slice()) |*import| {
|
||||
if (import.kind.isCommonJS()) {
|
||||
import.do_commonjs_transform_in_printer = true;
|
||||
import.module_id = @truncate(u32, std.hash.Wyhash.hash(0, import.path.pretty));
|
||||
import.module_id = @truncate(u32, bun.hash(import.path.pretty));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -893,7 +893,7 @@ pub fn scan(
|
||||
JSC.markBinding(@src());
|
||||
const arguments = callframe.arguments(3);
|
||||
var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments.ptr[0..arguments.len]);
|
||||
defer args.arena.deinit();
|
||||
defer args.deinit();
|
||||
const code_arg = args.next() orelse {
|
||||
globalThis.throwInvalidArgumentType("scan", "code", "string or Uint8Array");
|
||||
return .zero;
|
||||
@@ -905,7 +905,7 @@ pub fn scan(
|
||||
};
|
||||
|
||||
const code = code_holder.slice();
|
||||
args.eat();
|
||||
args.protectEat();
|
||||
var exception_ref = [_]JSC.C.JSValueRef{null};
|
||||
var exception: JSC.C.ExceptionRef = &exception_ref;
|
||||
|
||||
@@ -940,7 +940,7 @@ pub fn scan(
|
||||
JSAst.Expr.Data.Store.reset();
|
||||
}
|
||||
|
||||
const parse_result = getParseResult(this, arena.allocator(), code, loader, Bundler.MacroJSValueType.zero) orelse {
|
||||
var parse_result = getParseResult(this, arena.allocator(), code, loader, Bundler.MacroJSValueType.zero) orelse {
|
||||
if ((this.bundler.log.warnings + this.bundler.log.errors) > 0) {
|
||||
globalThis.throwValue(this.bundler.log.toJS(globalThis, globalThis.allocator(), "Parse error"));
|
||||
return .zero;
|
||||
@@ -969,7 +969,7 @@ pub fn scan(
|
||||
|
||||
const named_exports_value = namedExportsToJS(
|
||||
globalThis,
|
||||
parse_result.ast.named_exports,
|
||||
&parse_result.ast.named_exports,
|
||||
);
|
||||
return JSC.JSValue.createObject2(globalThis, imports_label, exports_label, named_imports_value, named_exports_value);
|
||||
}
|
||||
@@ -1174,25 +1174,27 @@ pub fn transformSync(
|
||||
return out.toValueGC(globalThis);
|
||||
}
|
||||
|
||||
fn namedExportsToJS(global: *JSGlobalObject, named_exports: JSAst.Ast.NamedExports) JSC.JSValue {
|
||||
fn namedExportsToJS(global: *JSGlobalObject, named_exports: *JSAst.Ast.NamedExports) JSC.JSValue {
|
||||
if (named_exports.count() == 0)
|
||||
return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArray(global, 0, null, null));
|
||||
|
||||
var named_exports_iter = named_exports.iterator();
|
||||
var stack_fallback = std.heap.stackFallback(@sizeOf(JSC.ZigString) * 32, getAllocator(global));
|
||||
var stack_fallback = std.heap.stackFallback(@sizeOf(bun.String) * 32, getAllocator(global));
|
||||
var allocator = stack_fallback.get();
|
||||
var names = allocator.alloc(
|
||||
JSC.ZigString,
|
||||
bun.String,
|
||||
named_exports.count(),
|
||||
) catch unreachable;
|
||||
defer allocator.free(names);
|
||||
named_exports.sort(strings.StringArrayByIndexSorter{
|
||||
.keys = named_exports.keys(),
|
||||
});
|
||||
var i: usize = 0;
|
||||
while (named_exports_iter.next()) |entry| {
|
||||
names[i] = JSC.ZigString.init(entry.key_ptr.*);
|
||||
names[i] = bun.String.create(entry.key_ptr.*);
|
||||
i += 1;
|
||||
}
|
||||
JSC.ZigString.sortAsc(names[0..i]);
|
||||
return JSC.JSValue.createStringArray(global, names.ptr, names.len, true);
|
||||
return bun.String.toJSArray(global, names);
|
||||
}
|
||||
|
||||
const ImportRecord = @import("../../import_record.zig").ImportRecord;
|
||||
@@ -1200,30 +1202,24 @@ const ImportRecord = @import("../../import_record.zig").ImportRecord;
|
||||
fn namedImportsToJS(
|
||||
global: *JSGlobalObject,
|
||||
import_records: []const ImportRecord,
|
||||
exception: JSC.C.ExceptionRef,
|
||||
_: JSC.C.ExceptionRef,
|
||||
) JSC.JSValue {
|
||||
var stack_fallback = std.heap.stackFallback(@sizeOf(JSC.C.JSObjectRef) * 32, getAllocator(global));
|
||||
var allocator = stack_fallback.get();
|
||||
|
||||
var i: usize = 0;
|
||||
const path_label = JSC.ZigString.static("path");
|
||||
const kind_label = JSC.ZigString.static("kind");
|
||||
var array_items = allocator.alloc(
|
||||
JSC.C.JSValueRef,
|
||||
import_records.len,
|
||||
) catch unreachable;
|
||||
defer allocator.free(array_items);
|
||||
|
||||
for (import_records) |record| {
|
||||
const array = JSC.JSValue.createEmptyArray(global, import_records.len);
|
||||
array.ensureStillAlive();
|
||||
|
||||
for (import_records, 0..) |record, i| {
|
||||
if (record.is_internal) continue;
|
||||
|
||||
array.ensureStillAlive();
|
||||
const path = JSC.ZigString.init(record.path.text).toValueGC(global);
|
||||
const kind = JSC.ZigString.init(record.kind.label()).toValue(global);
|
||||
array_items[i] = JSC.JSValue.createObject2(global, path_label, kind_label, path, kind).asObjectRef();
|
||||
i += 1;
|
||||
const kind = JSC.ZigString.init(record.kind.label()).toValueGC(global);
|
||||
array.putIndex(global, @truncate(u32, i), JSC.JSValue.createObject2(global, path_label, kind_label, path, kind));
|
||||
}
|
||||
|
||||
return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArray(global, i, array_items.ptr, exception));
|
||||
return array;
|
||||
}
|
||||
|
||||
pub fn scanImports(
|
||||
@@ -1235,6 +1231,8 @@ pub fn scanImports(
|
||||
var exception_val = [_]JSC.C.JSValueRef{null};
|
||||
var exception: JSC.C.ExceptionRef = &exception_val;
|
||||
var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments.ptr[0..arguments.len]);
|
||||
defer args.deinit();
|
||||
|
||||
const code_arg = args.next() orelse {
|
||||
globalThis.throwInvalidArgumentType("scanImports", "code", "string or Uint8Array");
|
||||
return .zero;
|
||||
@@ -1249,7 +1247,7 @@ pub fn scanImports(
|
||||
|
||||
return .zero;
|
||||
};
|
||||
args.eat();
|
||||
args.protectEat();
|
||||
const code = code_holder.slice();
|
||||
|
||||
var loader: Loader = this.transpiler_options.default_loader;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -123,7 +123,7 @@ const LibInfo = struct {
|
||||
this.vm.uws_event_loop.?,
|
||||
.machport,
|
||||
true,
|
||||
@ptrToInt(request.backend.libinfo.machport),
|
||||
@intFromPtr(request.backend.libinfo.machport),
|
||||
) == .result,
|
||||
);
|
||||
|
||||
@@ -230,7 +230,7 @@ fn addrInfoCount(addrinfo: *std.c.addrinfo) u32 {
|
||||
var count: u32 = 1;
|
||||
var current: ?*std.c.addrinfo = addrinfo.next;
|
||||
while (current != null) : (current = current.?.next) {
|
||||
count += @boolToInt(current.?.addr != null);
|
||||
count += @intFromBool(current.?.addr != null);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@@ -241,7 +241,7 @@ pub fn addrInfoToJSArray(
|
||||
globalThis: *JSC.JSGlobalObject,
|
||||
) JSC.JSValue {
|
||||
var stack = std.heap.stackFallback(2048, parent_allocator);
|
||||
var arena = std.heap.ArenaAllocator.init(stack.get());
|
||||
var arena = @import("root").bun.ArenaAllocator.init(stack.get());
|
||||
const array = JSC.JSValue.createEmptyArray(
|
||||
globalThis,
|
||||
addrInfoCount(addr_info),
|
||||
@@ -285,7 +285,7 @@ pub const GetAddrInfo = struct {
|
||||
|
||||
pub fn toCAres(this: GetAddrInfo) bun.c_ares.AddrInfo_hints {
|
||||
var hints: bun.c_ares.AddrInfo_hints = undefined;
|
||||
@memset(std.mem.asBytes(&hints), 0, @sizeOf(bun.c_ares.AddrInfo_hints));
|
||||
@memset(std.mem.asBytes(&hints)[0..@sizeOf(bun.c_ares.AddrInfo_hints)], 0);
|
||||
|
||||
hints.ai_family = this.options.family.toLibC();
|
||||
hints.ai_socktype = this.options.socktype.toLibC();
|
||||
@@ -320,7 +320,7 @@ pub const GetAddrInfo = struct {
|
||||
}
|
||||
|
||||
var hints: std.c.addrinfo = undefined;
|
||||
@memset(std.mem.asBytes(&hints), 0, @sizeOf(std.c.addrinfo));
|
||||
@memset(std.mem.asBytes(&hints)[0..@sizeOf(std.c.addrinfo)], 0);
|
||||
|
||||
hints.family = this.family.toLibC();
|
||||
hints.socktype = this.socktype.toLibC();
|
||||
@@ -385,7 +385,7 @@ pub const GetAddrInfo = struct {
|
||||
return .unspecified;
|
||||
|
||||
if (value.isNumber()) {
|
||||
return switch (value.to(i32)) {
|
||||
return switch (value.coerce(i32, globalObject)) {
|
||||
0 => .unspecified,
|
||||
4 => .inet,
|
||||
6 => .inet6,
|
||||
@@ -394,11 +394,11 @@ pub const GetAddrInfo = struct {
|
||||
}
|
||||
|
||||
if (value.isString()) {
|
||||
const str = value.getZigString(globalObject);
|
||||
if (str.len == 0)
|
||||
const str = value.toBunString(globalObject);
|
||||
if (str.isEmpty())
|
||||
return .unspecified;
|
||||
|
||||
return map.getWithEql(str, JSC.ZigString.eqlComptime) orelse return error.InvalidFamily;
|
||||
return str.inMap(map) orelse return error.InvalidFamily;
|
||||
}
|
||||
|
||||
return error.InvalidFamily;
|
||||
@@ -553,7 +553,7 @@ pub const GetAddrInfo = struct {
|
||||
.addrinfo => |addrinfo| addrInfoToJSArray(globalThis.allocator(), addrinfo orelse return null, globalThis),
|
||||
.list => |list| brk: {
|
||||
var stack = std.heap.stackFallback(2048, globalThis.allocator());
|
||||
var arena = std.heap.ArenaAllocator.init(stack.get());
|
||||
var arena = @import("root").bun.ArenaAllocator.init(stack.get());
|
||||
const array = JSC.JSValue.createEmptyArray(globalThis, @truncate(u32, list.items.len));
|
||||
var i: u32 = 0;
|
||||
const items: []const Result = list.items;
|
||||
@@ -793,7 +793,7 @@ pub const GetAddrInfoRequest = struct {
|
||||
addr_info: ?*std.c.addrinfo,
|
||||
arg: ?*anyopaque,
|
||||
) callconv(.C) void {
|
||||
const this = @intToPtr(*GetAddrInfoRequest, @ptrToInt(arg));
|
||||
const this = @ptrFromInt(*GetAddrInfoRequest, @intFromPtr(arg));
|
||||
log("getAddrInfoAsyncCallback: status={d}", .{status});
|
||||
|
||||
if (this.backend == .libinfo) {
|
||||
@@ -846,8 +846,8 @@ pub const GetAddrInfoRequest = struct {
|
||||
err,
|
||||
debug_timer,
|
||||
});
|
||||
if (@enumToInt(err) != 0 or addrinfo == null) {
|
||||
this.* = .{ .err = @enumToInt(err) };
|
||||
if (@intFromEnum(err) != 0 or addrinfo == null) {
|
||||
this.* = .{ .err = @intFromEnum(err) };
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -254,19 +254,17 @@ pub const SocketConfig = struct {
|
||||
var ssl: ?JSC.API.ServerConfig.SSLConfig = null;
|
||||
var default_data = JSValue.zero;
|
||||
|
||||
if (opts.getTruthy(globalObject, "tls")) |tls| outer: {
|
||||
if (opts.getTruthy(globalObject, "tls")) |tls| {
|
||||
if (tls.isBoolean()) {
|
||||
if (tls.toBoolean()) {
|
||||
ssl = JSC.API.ServerConfig.SSLConfig.zero;
|
||||
}
|
||||
|
||||
break :outer;
|
||||
}
|
||||
|
||||
if (JSC.API.ServerConfig.SSLConfig.inJS(globalObject, tls, exception)) |ssl_config| {
|
||||
ssl = ssl_config;
|
||||
} else if (exception.* != null) {
|
||||
return null;
|
||||
} else {
|
||||
if (JSC.API.ServerConfig.SSLConfig.inJS(globalObject, tls, exception)) |ssl_config| {
|
||||
ssl = ssl_config;
|
||||
} else if (exception.* != null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,10 +398,10 @@ pub const Listener = struct {
|
||||
pub fn deinit(this: UnixOrHost) void {
|
||||
switch (this) {
|
||||
.unix => |u| {
|
||||
bun.default_allocator.destroy(@intToPtr([*]u8, @ptrToInt(u.ptr)));
|
||||
bun.default_allocator.destroy(@ptrFromInt([*]u8, @intFromPtr(u.ptr)));
|
||||
},
|
||||
.host => |h| {
|
||||
bun.default_allocator.destroy(@intToPtr([*]u8, @ptrToInt(h.host.ptr)));
|
||||
bun.default_allocator.destroy(@ptrFromInt([*]u8, @intFromPtr(h.host.ptr)));
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -474,7 +472,7 @@ pub const Listener = struct {
|
||||
globalObject.bunVM().eventLoop().ensureWaker();
|
||||
|
||||
var socket_context = uws.us_create_bun_socket_context(
|
||||
@boolToInt(ssl_enabled),
|
||||
@intFromBool(ssl_enabled),
|
||||
uws.Loop.get().?,
|
||||
@sizeOf(usize),
|
||||
ctx_opts,
|
||||
@@ -485,7 +483,7 @@ pub const Listener = struct {
|
||||
hostname_or_unix.deinit();
|
||||
}
|
||||
|
||||
const errno = @enumToInt(std.c.getErrno(-1));
|
||||
const errno = @intFromEnum(std.c.getErrno(-1));
|
||||
if (errno != 0) {
|
||||
err.put(globalObject, ZigString.static("errno"), JSValue.jsNumber(errno));
|
||||
if (bun.C.SystemErrno.init(errno)) |str| {
|
||||
@@ -546,7 +544,7 @@ pub const Listener = struct {
|
||||
defer bun.default_allocator.free(host);
|
||||
|
||||
const socket = uws.us_socket_context_listen(
|
||||
@boolToInt(ssl_enabled),
|
||||
@intFromBool(ssl_enabled),
|
||||
socket_context,
|
||||
normalizeHost(@as([:0]const u8, host)),
|
||||
c.port,
|
||||
@@ -562,13 +560,13 @@ pub const Listener = struct {
|
||||
.unix => |u| {
|
||||
var host = bun.default_allocator.dupeZ(u8, u) catch unreachable;
|
||||
defer bun.default_allocator.free(host);
|
||||
break :brk uws.us_socket_context_listen_unix(@boolToInt(ssl_enabled), socket_context, host, socket_flags, 8);
|
||||
break :brk uws.us_socket_context_listen_unix(@intFromBool(ssl_enabled), socket_context, host, socket_flags, 8);
|
||||
},
|
||||
}
|
||||
} orelse {
|
||||
defer {
|
||||
hostname_or_unix.deinit();
|
||||
uws.us_socket_context_free(@boolToInt(ssl_enabled), socket_context);
|
||||
uws.us_socket_context_free(@intFromBool(ssl_enabled), socket_context);
|
||||
}
|
||||
|
||||
const err = globalObject.createErrorInstance(
|
||||
@@ -577,7 +575,7 @@ pub const Listener = struct {
|
||||
bun.span(hostname_or_unix.slice()),
|
||||
},
|
||||
);
|
||||
const errno = @enumToInt(std.c.getErrno(-1));
|
||||
const errno = @intFromEnum(std.c.getErrno(-1));
|
||||
if (errno != 0) {
|
||||
err.put(globalObject, ZigString.static("errno"), JSValue.jsNumber(errno));
|
||||
if (bun.C.SystemErrno.init(errno)) |str| {
|
||||
@@ -791,7 +789,7 @@ pub const Listener = struct {
|
||||
|
||||
globalObject.bunVM().eventLoop().ensureWaker();
|
||||
|
||||
var socket_context = uws.us_create_bun_socket_context(@boolToInt(ssl_enabled), uws.Loop.get().?, @sizeOf(usize), ctx_opts).?;
|
||||
var socket_context = uws.us_create_bun_socket_context(@intFromBool(ssl_enabled), uws.Loop.get().?, @sizeOf(usize), ctx_opts).?;
|
||||
var connection: Listener.UnixOrHost = if (port) |port_| .{
|
||||
.host = .{ .host = (hostname_or_unix.cloneIfNeeded(bun.default_allocator) catch unreachable).slice(), .port = port_ },
|
||||
} else .{
|
||||
@@ -1589,8 +1587,8 @@ fn NewSocket(comptime ssl: bool) type {
|
||||
|
||||
globalObject.throw("sendfile() not implemented yet", .{});
|
||||
return .{ .fail = {} };
|
||||
} else if (args.ptr[0].toStringOrNull(globalObject)) |jsstring| {
|
||||
var zig_str = jsstring.toSlice(globalObject, globalObject.bunVM().allocator);
|
||||
} else if (bun.String.tryFromJS(args.ptr[0], globalObject)) |bun_str| {
|
||||
var zig_str = bun_str.toUTF8(bun.default_allocator);
|
||||
defer zig_str.deinit();
|
||||
|
||||
var slice = zig_str.slice();
|
||||
|
||||
@@ -1011,7 +1011,7 @@ pub const Subprocess = struct {
|
||||
if (signal.name()) |name|
|
||||
return JSC.ZigString.init(name).toValueGC(global)
|
||||
else
|
||||
return JSC.JSValue.jsNumber(@enumToInt(signal));
|
||||
return JSC.JSValue.jsNumber(@intFromEnum(signal));
|
||||
}
|
||||
|
||||
return JSC.JSValue.jsNull();
|
||||
@@ -1031,7 +1031,7 @@ pub const Subprocess = struct {
|
||||
secondaryArgsValue: ?JSValue,
|
||||
comptime is_sync: bool,
|
||||
) JSValue {
|
||||
var arena = std.heap.ArenaAllocator.init(bun.default_allocator);
|
||||
var arena = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
|
||||
defer arena.deinit();
|
||||
var allocator = arena.allocator();
|
||||
|
||||
@@ -1535,9 +1535,9 @@ pub const Subprocess = struct {
|
||||
}
|
||||
|
||||
if (std.os.W.IFSIGNALED(result.status)) {
|
||||
this.signal_code = @intToEnum(SignalCode, @truncate(u8, std.os.W.TERMSIG(result.status)));
|
||||
this.signal_code = @enumFromInt(SignalCode, @truncate(u8, std.os.W.TERMSIG(result.status)));
|
||||
} else if (std.os.W.IFSTOPPED(result.status)) {
|
||||
this.signal_code = @intToEnum(SignalCode, @truncate(u8, std.os.W.STOPSIG(result.status)));
|
||||
this.signal_code = @enumFromInt(SignalCode, @truncate(u8, std.os.W.STOPSIG(result.status)));
|
||||
}
|
||||
|
||||
if (!this.hasExited()) {
|
||||
|
||||
@@ -137,8 +137,8 @@ pub const FFI = struct {
|
||||
globalThis,
|
||||
ZigString.static("ptr"),
|
||||
ZigString.static("ctx"),
|
||||
JSC.JSValue.fromPtrAddress(@ptrToInt(function_.step.compiled.ptr)),
|
||||
JSC.JSValue.fromPtrAddress(@ptrToInt(function_)),
|
||||
JSC.JSValue.fromPtrAddress(@intFromPtr(function_.step.compiled.ptr)),
|
||||
JSC.JSValue.fromPtrAddress(@intFromPtr(function_)),
|
||||
);
|
||||
},
|
||||
}
|
||||
@@ -523,7 +523,7 @@ pub const FFI = struct {
|
||||
const int = val.to(i32);
|
||||
switch (int) {
|
||||
0...ABIType.max => {
|
||||
abi_types.appendAssumeCapacity(@intToEnum(ABIType, int));
|
||||
abi_types.appendAssumeCapacity(@enumFromInt(ABIType, int));
|
||||
continue;
|
||||
},
|
||||
else => {
|
||||
@@ -560,7 +560,7 @@ pub const FFI = struct {
|
||||
const int = ret_value.toInt32();
|
||||
switch (int) {
|
||||
0...ABIType.max => {
|
||||
return_type = @intToEnum(ABIType, int);
|
||||
return_type = @enumFromInt(ABIType, int);
|
||||
break :brk;
|
||||
},
|
||||
else => {
|
||||
@@ -594,11 +594,11 @@ pub const FFI = struct {
|
||||
if (ptr.isNumber()) {
|
||||
const num = ptr.asPtrAddress();
|
||||
if (num > 0)
|
||||
function.symbol_from_dynamic_library = @intToPtr(*anyopaque, num);
|
||||
function.symbol_from_dynamic_library = @ptrFromInt(*anyopaque, num);
|
||||
} else {
|
||||
const num = ptr.toUInt64NoTruncate();
|
||||
if (num > 0) {
|
||||
function.symbol_from_dynamic_library = @intToPtr(*anyopaque, num);
|
||||
function.symbol_from_dynamic_library = @ptrFromInt(*anyopaque, num);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -866,7 +866,7 @@ pub const FFI = struct {
|
||||
c: u8,
|
||||
byte_count: usize,
|
||||
) callconv(.C) void {
|
||||
@memset(dest, c, byte_count);
|
||||
@memset(dest[0..byte_count], c);
|
||||
}
|
||||
|
||||
noinline fn memcpy(
|
||||
@@ -874,7 +874,7 @@ pub const FFI = struct {
|
||||
noalias source: [*]const u8,
|
||||
byte_count: usize,
|
||||
) callconv(.C) void {
|
||||
@memcpy(dest, source, byte_count);
|
||||
@memcpy(dest[0..byte_count], source[0..byte_count]);
|
||||
}
|
||||
|
||||
pub fn define(state: *TCC.TCCState) void {
|
||||
@@ -1205,7 +1205,7 @@ pub const FFI = struct {
|
||||
writer: anytype,
|
||||
) !void {
|
||||
{
|
||||
const ptr = @ptrToInt(globalObject);
|
||||
const ptr = @intFromPtr(globalObject);
|
||||
const fmt = bun.fmt.hexIntUpper(ptr);
|
||||
try writer.print("#define JS_GLOBAL_OBJECT (void*)0x{any}ULL\n", .{fmt});
|
||||
}
|
||||
@@ -1290,7 +1290,7 @@ pub const FFI = struct {
|
||||
var inner_buf: []u8 = &.{};
|
||||
|
||||
{
|
||||
const ptr = @ptrToInt(context_ptr);
|
||||
const ptr = @intFromPtr(context_ptr);
|
||||
const fmt = bun.fmt.hexIntUpper(ptr);
|
||||
|
||||
if (this.arg_types.items.len > 0) {
|
||||
@@ -1355,7 +1355,7 @@ pub const FFI = struct {
|
||||
|
||||
function = 17,
|
||||
|
||||
pub const max = @enumToInt(ABIType.function);
|
||||
pub const max = @intFromEnum(ABIType.function);
|
||||
|
||||
/// Types that we can directly pass through as an `int64_t`
|
||||
pub fn needsACastInC(this: ABIType) bool {
|
||||
@@ -1414,11 +1414,11 @@ pub const FFI = struct {
|
||||
// these are not all valid identifiers
|
||||
try writer.writeAll(self.name);
|
||||
try writer.writeAll("']:");
|
||||
try std.fmt.formatInt(@enumToInt(self.entry), 10, .lower, .{}, writer);
|
||||
try std.fmt.formatInt(@intFromEnum(self.entry), 10, .lower, .{}, writer);
|
||||
try writer.writeAll(",'");
|
||||
try std.fmt.formatInt(@enumToInt(self.entry), 10, .lower, .{}, writer);
|
||||
try std.fmt.formatInt(@intFromEnum(self.entry), 10, .lower, .{}, writer);
|
||||
try writer.writeAll("':");
|
||||
try std.fmt.formatInt(@enumToInt(self.entry), 10, .lower, .{}, writer);
|
||||
try std.fmt.formatInt(@intFromEnum(self.entry), 10, .lower, .{}, writer);
|
||||
}
|
||||
};
|
||||
pub const map_to_js_object = brk: {
|
||||
@@ -1426,7 +1426,7 @@ pub const FFI = struct {
|
||||
for (map, 0..) |item, i| {
|
||||
var fmt = EnumMapFormatter{ .name = item.@"0", .entry = item.@"1" };
|
||||
count += std.fmt.count("{}", .{fmt});
|
||||
count += @boolToInt(i > 0);
|
||||
count += @intFromBool(i > 0);
|
||||
}
|
||||
|
||||
var buf: [count]u8 = undefined;
|
||||
|
||||
@@ -153,7 +153,7 @@ pub const FileSystemRouter = struct {
|
||||
origin: ?*JSC.RefString = null,
|
||||
base_dir: ?*JSC.RefString = null,
|
||||
router: Router,
|
||||
arena: *std.heap.ArenaAllocator = undefined,
|
||||
arena: *@import("root").bun.ArenaAllocator = undefined,
|
||||
allocator: std.mem.Allocator = undefined,
|
||||
asset_prefix: ?*JSC.RefString = null,
|
||||
|
||||
@@ -210,8 +210,8 @@ pub const FileSystemRouter = struct {
|
||||
globalThis.throwInvalidArguments("Expected dir to be a string", .{});
|
||||
return null;
|
||||
}
|
||||
var arena = globalThis.allocator().create(std.heap.ArenaAllocator) catch unreachable;
|
||||
arena.* = std.heap.ArenaAllocator.init(globalThis.allocator());
|
||||
var arena = globalThis.allocator().create(@import("root").bun.ArenaAllocator) catch unreachable;
|
||||
arena.* = @import("root").bun.ArenaAllocator.init(globalThis.allocator());
|
||||
var allocator = arena.allocator();
|
||||
var extensions = std.ArrayList(string).init(allocator);
|
||||
if (argument.get(globalThis, "fileExtensions")) |file_extensions| {
|
||||
@@ -324,8 +324,8 @@ pub const FileSystemRouter = struct {
|
||||
pub fn reload(this: *FileSystemRouter, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
|
||||
var this_value = callframe.this();
|
||||
|
||||
var arena = globalThis.allocator().create(std.heap.ArenaAllocator) catch unreachable;
|
||||
arena.* = std.heap.ArenaAllocator.init(globalThis.allocator());
|
||||
var arena = globalThis.allocator().create(@import("root").bun.ArenaAllocator) catch unreachable;
|
||||
arena.* = @import("root").bun.ArenaAllocator.init(globalThis.allocator());
|
||||
|
||||
var allocator = arena.allocator();
|
||||
var vm = globalThis.bunVM();
|
||||
|
||||
@@ -472,13 +472,13 @@ pub const HTMLRewriter = struct {
|
||||
pub fn onFinishedLoading(sink: *BufferOutputSink, bytes: JSC.WebCore.Blob.Store.ReadFile.ResultType) void {
|
||||
switch (bytes) {
|
||||
.err => |err| {
|
||||
if (sink.response.body.value == .Locked and @ptrToInt(sink.response.body.value.Locked.task) == @ptrToInt(sink) and
|
||||
if (sink.response.body.value == .Locked and @intFromPtr(sink.response.body.value.Locked.task) == @intFromPtr(sink) and
|
||||
sink.response.body.value.Locked.promise == null)
|
||||
{
|
||||
sink.response.body.value = .{ .Empty = {} };
|
||||
// is there a pending promise?
|
||||
// we will need to reject it
|
||||
} else if (sink.response.body.value == .Locked and @ptrToInt(sink.response.body.value.Locked.task) == @ptrToInt(sink) and
|
||||
} else if (sink.response.body.value == .Locked and @intFromPtr(sink.response.body.value.Locked.task) == @intFromPtr(sink) and
|
||||
sink.response.body.value.Locked.promise != null)
|
||||
{
|
||||
sink.response.body.value.Locked.onReceiveValue = null;
|
||||
|
||||
@@ -136,6 +136,8 @@ pub const ServerConfig = struct {
|
||||
|
||||
websocket: ?WebSocketServer = null,
|
||||
|
||||
inspector: bool = false,
|
||||
|
||||
pub const SSLConfig = struct {
|
||||
server_name: [*c]const u8 = null,
|
||||
|
||||
@@ -166,7 +168,7 @@ pub const ServerConfig = struct {
|
||||
|
||||
pub fn asUSockets(this_: ?SSLConfig) uws.us_bun_socket_context_options_t {
|
||||
var ctx_opts: uws.us_bun_socket_context_options_t = undefined;
|
||||
@memset(@ptrCast([*]u8, &ctx_opts), 0, @sizeOf(uws.us_bun_socket_context_options_t));
|
||||
@memset(@ptrCast([*]u8, &ctx_opts)[0..@sizeOf(uws.us_bun_socket_context_options_t)], 0);
|
||||
|
||||
if (this_) |ssl_config| {
|
||||
if (ssl_config.key_file_name != null)
|
||||
@@ -179,7 +181,7 @@ pub const ServerConfig = struct {
|
||||
ctx_opts.dh_params_file_name = ssl_config.dh_params_file_name;
|
||||
if (ssl_config.passphrase != null)
|
||||
ctx_opts.passphrase = ssl_config.passphrase;
|
||||
ctx_opts.ssl_prefer_low_memory_usage = @boolToInt(ssl_config.low_memory_mode);
|
||||
ctx_opts.ssl_prefer_low_memory_usage = @intFromBool(ssl_config.low_memory_mode);
|
||||
|
||||
if (ssl_config.key) |key| {
|
||||
ctx_opts.key = key.ptr;
|
||||
@@ -268,6 +270,11 @@ pub const ServerConfig = struct {
|
||||
|
||||
pub fn inJS(global: *JSC.JSGlobalObject, obj: JSC.JSValue, exception: JSC.C.ExceptionRef) ?SSLConfig {
|
||||
var result = zero;
|
||||
if (!obj.isObject()) {
|
||||
JSC.throwInvalidArguments("tls option expects an object", .{}, global, exception);
|
||||
return null;
|
||||
}
|
||||
|
||||
var any = false;
|
||||
|
||||
// Required
|
||||
@@ -294,7 +301,7 @@ pub const ServerConfig = struct {
|
||||
|
||||
var i: u32 = 0;
|
||||
var valid_count: u32 = 0;
|
||||
var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
|
||||
var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
|
||||
while (i < count) : (i += 1) {
|
||||
const item = js_obj.getIndex(global, i);
|
||||
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), item, exception)) |sb| {
|
||||
@@ -349,7 +356,7 @@ pub const ServerConfig = struct {
|
||||
}
|
||||
} else {
|
||||
const native_array = bun.default_allocator.alloc([*c]const u8, 1) catch unreachable;
|
||||
var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
|
||||
var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
|
||||
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), js_obj, exception)) |sb| {
|
||||
const sliced = sb.slice();
|
||||
if (sliced.len > 0) {
|
||||
@@ -396,7 +403,7 @@ pub const ServerConfig = struct {
|
||||
var i: u32 = 0;
|
||||
var valid_count: u32 = 0;
|
||||
|
||||
var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
|
||||
var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
|
||||
while (i < count) : (i += 1) {
|
||||
const item = js_obj.getIndex(global, i);
|
||||
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), item, exception)) |sb| {
|
||||
@@ -451,7 +458,7 @@ pub const ServerConfig = struct {
|
||||
}
|
||||
} else {
|
||||
const native_array = bun.default_allocator.alloc([*c]const u8, 1) catch unreachable;
|
||||
var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
|
||||
var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
|
||||
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), js_obj, exception)) |sb| {
|
||||
const sliced = sb.slice();
|
||||
if (sliced.len > 0) {
|
||||
@@ -511,7 +518,7 @@ pub const ServerConfig = struct {
|
||||
var i: u32 = 0;
|
||||
var valid_count: u32 = 0;
|
||||
|
||||
var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
|
||||
var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
|
||||
while (i < count) : (i += 1) {
|
||||
const item = js_obj.getIndex(global, i);
|
||||
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), item, exception)) |sb| {
|
||||
@@ -566,7 +573,7 @@ pub const ServerConfig = struct {
|
||||
}
|
||||
} else {
|
||||
const native_array = bun.default_allocator.alloc([*c]const u8, 1) catch unreachable;
|
||||
var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
|
||||
var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
|
||||
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), js_obj, exception)) |sb| {
|
||||
const sliced = sb.slice();
|
||||
if (sliced.len > 0) {
|
||||
@@ -686,7 +693,7 @@ pub const ServerConfig = struct {
|
||||
}
|
||||
|
||||
if (arguments.next()) |arg| {
|
||||
if (arg.isUndefinedOrNull() or !arg.isObject()) {
|
||||
if (!arg.isObject()) {
|
||||
JSC.throwInvalidArguments("Bun.serve expects an object", .{}, global, exception);
|
||||
return args;
|
||||
}
|
||||
@@ -741,7 +748,19 @@ pub const ServerConfig = struct {
|
||||
}
|
||||
|
||||
if (arg.get(global, "development")) |dev| {
|
||||
args.development = dev.toBoolean();
|
||||
args.development = dev.coerce(bool, global);
|
||||
}
|
||||
|
||||
if (arg.get(global, "inspector")) |inspector| {
|
||||
args.inspector = inspector.coerce(bool, global);
|
||||
|
||||
if (args.inspector and !args.development) {
|
||||
JSC.throwInvalidArguments("Cannot enable inspector in production. Please set development: true in Bun.serve()", .{}, global, exception);
|
||||
if (args.ssl_config) |*conf| {
|
||||
conf.deinit();
|
||||
}
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg.getTruthy(global, "tls")) |tls| {
|
||||
@@ -798,6 +817,9 @@ pub const ServerConfig = struct {
|
||||
}
|
||||
return args;
|
||||
}
|
||||
} else {
|
||||
JSC.throwInvalidArguments("Bun.serve expects an object", .{}, global, exception);
|
||||
return args;
|
||||
}
|
||||
|
||||
if (args.base_uri.len > 0) {
|
||||
@@ -1218,7 +1240,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
|
||||
.reason = .fetch_event_handler,
|
||||
.cwd = VirtualMachine.get().bundler.fs.top_level_dir,
|
||||
.problems = Api.Problems{
|
||||
.code = @truncate(u16, @errorToInt(err)),
|
||||
.code = @truncate(u16, @intFromError(err)),
|
||||
.name = @errorName(err),
|
||||
.exceptions = exceptions,
|
||||
.build = log.toAPI(allocator) catch unreachable,
|
||||
@@ -1768,7 +1790,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
|
||||
}
|
||||
|
||||
var err = JSC.Node.Syscall.Error{
|
||||
.errno = @intCast(JSC.Node.Syscall.Error.Int, @enumToInt(std.os.E.INVAL)),
|
||||
.errno = @intCast(JSC.Node.Syscall.Error.Int, @intFromEnum(std.os.E.INVAL)),
|
||||
.syscall = .sendfile,
|
||||
};
|
||||
var sys = err.withPathLike(file.pathlike).toSystemError();
|
||||
@@ -1787,7 +1809,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
|
||||
}
|
||||
|
||||
var err = JSC.Node.Syscall.Error{
|
||||
.errno = @intCast(JSC.Node.Syscall.Error.Int, @enumToInt(std.os.E.INVAL)),
|
||||
.errno = @intCast(JSC.Node.Syscall.Error.Int, @intFromEnum(std.os.E.INVAL)),
|
||||
.syscall = .sendfile,
|
||||
};
|
||||
var sys = err.withPathLike(file.pathlike).toSystemError();
|
||||
@@ -2091,7 +2113,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
|
||||
const streamLog = Output.scoped(.ReadableStream, false);
|
||||
|
||||
pub fn didUpgradeWebSocket(this: *RequestContext) bool {
|
||||
return @ptrToInt(this.upgrade_context) == std.math.maxInt(usize);
|
||||
return @intFromPtr(this.upgrade_context) == std.math.maxInt(usize);
|
||||
}
|
||||
|
||||
pub fn onResponse(
|
||||
@@ -2358,6 +2380,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
|
||||
}
|
||||
|
||||
pub fn doRenderWithBody(this: *RequestContext, value: *JSC.WebCore.Body.Value) void {
|
||||
// If a ReadableStream can trivially be converted to a Blob, do so.
|
||||
// If it's a WTFStringImpl and it cannot be used as a UTF-8 string, convert it to a Blob.
|
||||
value.toBlobIfPossible();
|
||||
|
||||
switch (value.*) {
|
||||
@@ -2372,10 +2396,12 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
|
||||
return;
|
||||
},
|
||||
// .InlineBlob,
|
||||
.WTFStringImpl,
|
||||
.InternalBlob,
|
||||
.Blob,
|
||||
=> {
|
||||
this.blob = value.useAsAnyBlob();
|
||||
// toBlobIfPossible checks for WTFString needing a conversion.
|
||||
this.blob = value.useAsAnyBlobAllowNonUTF8String();
|
||||
this.renderWithBlobFromBodyValue();
|
||||
return;
|
||||
},
|
||||
@@ -2514,7 +2540,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
|
||||
// Faster to do the memcpy than to do the two network calls
|
||||
// We are not streaming
|
||||
// This is an important performance optimization
|
||||
if (this.has_abort_handler and this.blob.size() < 16384 - 1024) {
|
||||
if (this.has_abort_handler and this.blob.fastSize() < 16384 - 1024) {
|
||||
if (this.resp) |resp| {
|
||||
resp.runCorkedWithType(*RequestContext, doRenderBlobCorked, this);
|
||||
}
|
||||
@@ -2848,7 +2874,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
|
||||
const prev_len = bytes.items.len;
|
||||
bytes.items.len = total;
|
||||
var slice = bytes.items[prev_len..];
|
||||
@memcpy(slice.ptr, chunk.ptr, chunk.len);
|
||||
@memcpy(slice[0..chunk.len], chunk);
|
||||
body.value = .{
|
||||
.InternalBlob = .{
|
||||
.bytes = bytes.toManaged(this.allocator),
|
||||
@@ -3174,7 +3200,7 @@ pub const WebSocketServer = struct {
|
||||
globalObject.throwInvalidArguments("websocket expects maxPayloadLength to be an integer", .{});
|
||||
return null;
|
||||
}
|
||||
server.maxPayloadLength = @intCast(u32, @truncate(i33, @max(value.toInt64(), 0)));
|
||||
server.maxPayloadLength = @intCast(u32, @max(value.toInt64(), 0));
|
||||
}
|
||||
}
|
||||
if (object.get(globalObject, "idleTimeout")) |value| {
|
||||
@@ -3194,7 +3220,7 @@ pub const WebSocketServer = struct {
|
||||
return null;
|
||||
}
|
||||
|
||||
server.backpressureLimit = @intCast(u32, @truncate(i33, @max(value.toInt64(), 0)));
|
||||
server.backpressureLimit = @intCast(u32, @max(value.toInt64(), 0));
|
||||
}
|
||||
}
|
||||
// if (object.get(globalObject, "sendPings")) |value| {
|
||||
@@ -3340,7 +3366,7 @@ pub const ServerWebSocket = struct {
|
||||
opcode: uws.Opcode,
|
||||
) void {
|
||||
log("onMessage({d}): {s}", .{
|
||||
@enumToInt(opcode),
|
||||
@intFromEnum(opcode),
|
||||
message,
|
||||
});
|
||||
const onMessageHandler = this.handler.onMessage;
|
||||
@@ -4410,7 +4436,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
|
||||
return JSValue.jsNumber(
|
||||
// if 0, return 0
|
||||
// else return number of bytes sent
|
||||
@as(i32, @boolToInt(uws.AnyWebSocket.publishWithOptions(ssl_enabled, app, topic_slice.slice(), buffer.slice(), .binary, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
|
||||
@as(i32, @intFromBool(uws.AnyWebSocket.publishWithOptions(ssl_enabled, app, topic_slice.slice(), buffer.slice(), .binary, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4425,7 +4451,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
|
||||
return JSValue.jsNumber(
|
||||
// if 0, return 0
|
||||
// else return number of bytes sent
|
||||
@as(i32, @boolToInt(uws.AnyWebSocket.publishWithOptions(ssl_enabled, app, topic_slice.slice(), buffer, .text, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
|
||||
@as(i32, @intFromBool(uws.AnyWebSocket.publishWithOptions(ssl_enabled, app, topic_slice.slice(), buffer, .text, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4462,7 +4488,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
|
||||
return JSC.jsBoolean(false);
|
||||
}
|
||||
|
||||
if (upgrader.upgrade_context == null or @ptrToInt(upgrader.upgrade_context) == std.math.maxInt(usize)) {
|
||||
if (upgrader.upgrade_context == null or @intFromPtr(upgrader.upgrade_context) == std.math.maxInt(usize)) {
|
||||
return JSC.jsBoolean(false);
|
||||
}
|
||||
const resp = upgrader.resp.?;
|
||||
@@ -4556,7 +4582,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
|
||||
// See https://github.com/oven-sh/bun/issues/1339
|
||||
|
||||
// obviously invalid pointer marks it as used
|
||||
upgrader.upgrade_context = @intToPtr(*uws.uws_socket_context_s, std.math.maxInt(usize));
|
||||
upgrader.upgrade_context = @ptrFromInt(*uws.uws_socket_context_s, std.math.maxInt(usize));
|
||||
request.upgrader = null;
|
||||
|
||||
resp.clearAborted();
|
||||
@@ -4921,7 +4947,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
|
||||
if (reason.len == 0) {
|
||||
break;
|
||||
}
|
||||
@memcpy(output_buf[written..].ptr, reason.ptr, reason.len);
|
||||
@memcpy(output_buf[written..][0..reason.len], reason);
|
||||
written += reason.len;
|
||||
}
|
||||
|
||||
@@ -4932,7 +4958,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
|
||||
if (reason.len > 0) {
|
||||
output_buf[written..][0.." via ".len].* = " via ".*;
|
||||
written += " via ".len;
|
||||
@memcpy(output_buf[written..].ptr, reason.ptr, reason.len);
|
||||
@memcpy(output_buf[written..][0..reason.len], reason);
|
||||
written += reason.len;
|
||||
}
|
||||
}
|
||||
@@ -4944,7 +4970,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
|
||||
if (reason.len > 0) {
|
||||
output_buf[written..][0] = ' ';
|
||||
written += 1;
|
||||
@memcpy(output_buf[written..].ptr, reason.ptr, reason.len);
|
||||
@memcpy(output_buf[written..][0..reason.len], reason);
|
||||
written += reason.len;
|
||||
}
|
||||
}
|
||||
@@ -5239,6 +5265,11 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
|
||||
|
||||
if (comptime debug_mode) {
|
||||
this.app.get("/bun:info", *ThisServer, this, onBunInfoRequest);
|
||||
if (this.config.inspector) {
|
||||
JSC.markBinding(@src());
|
||||
Bun__addInspector(ssl_enabled, this.app, this.globalThis);
|
||||
}
|
||||
|
||||
this.app.get("/src:/*", *ThisServer, this, onSrcRequest);
|
||||
}
|
||||
|
||||
@@ -5290,3 +5321,5 @@ pub const AnyServer = union(enum) {
|
||||
};
|
||||
|
||||
const welcome_page_html_gz = @embedFile("welcome-page.html.gz");
|
||||
|
||||
extern fn Bun__addInspector(bool, *anyopaque, *JSC.JSGlobalObject) void;
|
||||
|
||||
@@ -207,6 +207,15 @@ pub const To = struct {
|
||||
|
||||
return array;
|
||||
},
|
||||
[]const bun.String => {
|
||||
defer {
|
||||
for (value) |out| {
|
||||
out.deref();
|
||||
}
|
||||
bun.default_allocator.free(value);
|
||||
}
|
||||
return bun.String.toJSArray(context, value).asObjectRef();
|
||||
},
|
||||
[]const PathString, []const []const u8, []const []u8, [][]const u8, [][:0]const u8, [][:0]u8 => {
|
||||
if (value.len == 0)
|
||||
return JSC.C.JSObjectMakeArray(context, 0, null, exception);
|
||||
@@ -1282,23 +1291,27 @@ pub fn NewClassWithInstanceType(
|
||||
|
||||
const static_properties: [property_names.len + 1]js.JSStaticValue = brk: {
|
||||
var props: [property_names.len + 1]js.JSStaticValue = undefined;
|
||||
std.mem.set(
|
||||
js.JSStaticValue,
|
||||
@memset(
|
||||
&props,
|
||||
js.JSStaticValue{
|
||||
.name = @intToPtr([*c]const u8, 0),
|
||||
.name = @ptrFromInt([*c]const u8, 0),
|
||||
.getProperty = null,
|
||||
.setProperty = null,
|
||||
.attributes = js.JSPropertyAttributes.kJSPropertyAttributeNone,
|
||||
},
|
||||
);
|
||||
if (property_name_literals.len > 0 and @TypeOf(property_name_literals[0]) == [:0]const u8) {
|
||||
@compileError("@typeInfo() struct field names are null-terminated");
|
||||
}
|
||||
for (property_name_literals, 0..) |lit, i| {
|
||||
props[i] = brk2: {
|
||||
var static_prop = JSC.C.JSStaticValue{
|
||||
.name = lit.ptr[0..lit.len :0],
|
||||
// TODO: update when @typeInfo struct field names are sentinel terminated
|
||||
// https://github.com/ziglang/zig/issues/16072
|
||||
.name = lit ++ .{0},
|
||||
.getProperty = null,
|
||||
.setProperty = null,
|
||||
.attributes = @intToEnum(js.JSPropertyAttributes, 0),
|
||||
.attributes = @enumFromInt(js.JSPropertyAttributes, 0),
|
||||
};
|
||||
static_prop.getProperty = StaticProperty(i).getter;
|
||||
|
||||
@@ -1387,14 +1400,14 @@ pub fn NewClassWithInstanceType(
|
||||
const ctxfn = CtxField.rfn;
|
||||
const Func: std.builtin.Type.Fn = @typeInfo(@TypeOf(if (@typeInfo(@TypeOf(ctxfn)) == .Pointer) ctxfn.* else ctxfn)).Fn;
|
||||
|
||||
var attributes: c_uint = @enumToInt(js.JSPropertyAttributes.kJSPropertyAttributeNone);
|
||||
var attributes: c_uint = @intFromEnum(js.JSPropertyAttributes.kJSPropertyAttributeNone);
|
||||
|
||||
if (comptime is_read_only or hasReadOnly(@TypeOf(CtxField))) {
|
||||
attributes |= @enumToInt(js.JSPropertyAttributes.kJSPropertyAttributeReadOnly);
|
||||
attributes |= @intFromEnum(js.JSPropertyAttributes.kJSPropertyAttributeReadOnly);
|
||||
}
|
||||
|
||||
if (comptime hasEnumerable(@TypeOf(CtxField)) and !CtxField.enumerable) {
|
||||
attributes |= @enumToInt(js.JSPropertyAttributes.kJSPropertyAttributeDontEnum);
|
||||
attributes |= @intFromEnum(js.JSPropertyAttributes.kJSPropertyAttributeDontEnum);
|
||||
}
|
||||
|
||||
const PointerType = comptime brk: {
|
||||
@@ -1410,7 +1423,7 @@ pub fn NewClassWithInstanceType(
|
||||
PointerType,
|
||||
if (@typeInfo(@TypeOf(ctxfn)) == .Pointer) ctxfn.* else ctxfn,
|
||||
).rfn,
|
||||
.attributes = @intToEnum(js.JSPropertyAttributes, attributes),
|
||||
.attributes = @enumFromInt(js.JSPropertyAttributes, attributes),
|
||||
};
|
||||
|
||||
count += 1;
|
||||
@@ -1429,12 +1442,12 @@ pub fn NewClassWithInstanceType(
|
||||
def.hasInstance = &staticFunctions.hasInstance;
|
||||
} else {
|
||||
const attributes: js.JSPropertyAttributes = brk: {
|
||||
var base = @enumToInt(js.JSPropertyAttributes.kJSPropertyAttributeNone);
|
||||
var base = @intFromEnum(js.JSPropertyAttributes.kJSPropertyAttributeNone);
|
||||
|
||||
if (is_read_only)
|
||||
base |= @enumToInt(js.JSPropertyAttributes.kJSPropertyAttributeReadOnly);
|
||||
base |= @intFromEnum(js.JSPropertyAttributes.kJSPropertyAttributeReadOnly);
|
||||
|
||||
break :brk @intToEnum(js.JSPropertyAttributes, base);
|
||||
break :brk @enumFromInt(js.JSPropertyAttributes, base);
|
||||
};
|
||||
|
||||
__static_functions[count] = js.JSStaticFunction{
|
||||
@@ -1825,7 +1838,7 @@ pub const ArrayBuffer = extern struct {
|
||||
this.ptr,
|
||||
this.byte_len,
|
||||
MarkedArrayBuffer_deallocator,
|
||||
@intToPtr(*anyopaque, @ptrToInt(&bun.default_allocator)),
|
||||
@ptrFromInt(*anyopaque, @intFromPtr(&bun.default_allocator)),
|
||||
exception,
|
||||
));
|
||||
}
|
||||
@@ -1836,7 +1849,7 @@ pub const ArrayBuffer = extern struct {
|
||||
this.ptr,
|
||||
this.byte_len,
|
||||
MarkedArrayBuffer_deallocator,
|
||||
@intToPtr(*anyopaque, @ptrToInt(&bun.default_allocator)),
|
||||
@ptrFromInt(*anyopaque, @intFromPtr(&bun.default_allocator)),
|
||||
exception,
|
||||
));
|
||||
}
|
||||
@@ -2042,8 +2055,8 @@ pub const RefString = struct {
|
||||
ptr: [*]const u8 = undefined,
|
||||
len: usize = 0,
|
||||
hash: Hash = 0,
|
||||
impl: bun.WTF.StringImpl,
|
||||
|
||||
count: u32 = 0,
|
||||
allocator: std.mem.Allocator,
|
||||
|
||||
ctx: ?*anyopaque = null,
|
||||
@@ -2053,17 +2066,13 @@ pub const RefString = struct {
|
||||
pub const Map = std.HashMap(Hash, *JSC.RefString, IdentityContext(Hash), 80);
|
||||
|
||||
pub fn toJS(this: *RefString, global: *JSC.JSGlobalObject) JSValue {
|
||||
return JSC.ZigString.init(this.slice()).external(global, this, RefString__external);
|
||||
return bun.String.init(this.impl).toJS(global);
|
||||
}
|
||||
|
||||
pub const Callback = fn (ctx: *anyopaque, str: *RefString) void;
|
||||
|
||||
pub fn computeHash(input: []const u8) u32 {
|
||||
return @truncate(u32, std.hash.Wyhash.hash(0, input));
|
||||
}
|
||||
|
||||
pub fn ref(this: *RefString) void {
|
||||
this.count += 1;
|
||||
return std.hash.XxHash32.hash(0, input);
|
||||
}
|
||||
|
||||
pub fn slice(this: *RefString) []const u8 {
|
||||
@@ -2072,25 +2081,21 @@ pub const RefString = struct {
|
||||
return this.leak();
|
||||
}
|
||||
|
||||
pub fn ref(this: *RefString) void {
|
||||
this.impl.ref();
|
||||
}
|
||||
|
||||
pub fn leak(this: RefString) []const u8 {
|
||||
@setRuntimeSafety(false);
|
||||
return this.ptr[0..this.len];
|
||||
}
|
||||
|
||||
pub fn deref(this: *RefString) void {
|
||||
this.count -|= 1;
|
||||
|
||||
if (this.count == 0) {
|
||||
this.deinit();
|
||||
}
|
||||
this.impl.deref();
|
||||
}
|
||||
|
||||
pub export fn RefString__free(this: *RefString, _: [*]const u8, _: usize) void {
|
||||
this.deref();
|
||||
}
|
||||
|
||||
pub export fn RefString__external(this: ?*anyopaque, _: ?*anyopaque, _: usize) void {
|
||||
bun.cast(*RefString, this.?).deref();
|
||||
pub export fn RefString__free(this: *anyopaque, _: *anyopaque, _: u32) void {
|
||||
bun.cast(*RefString, this).deinit();
|
||||
}
|
||||
|
||||
pub fn deinit(this: *RefString) void {
|
||||
@@ -3125,6 +3130,29 @@ pub fn wrapStaticMethod(
|
||||
args[i] = null;
|
||||
}
|
||||
},
|
||||
JSC.Node.SliceOrBuffer => {
|
||||
const arg = iter.nextEat() orelse {
|
||||
globalThis.throwInvalidArguments("expected string or buffer", .{});
|
||||
iter.deinit();
|
||||
return JSC.JSValue.zero;
|
||||
};
|
||||
args[i] = JSC.Node.SliceOrBuffer.fromJS(globalThis.ptr(), iter.arena.allocator(), arg) orelse {
|
||||
globalThis.throwInvalidArguments("expected string or buffer", .{});
|
||||
iter.deinit();
|
||||
return JSC.JSValue.zero;
|
||||
};
|
||||
},
|
||||
?JSC.Node.SliceOrBuffer => {
|
||||
if (iter.nextEat()) |arg| {
|
||||
args[i] = JSC.Node.SliceOrBuffer.fromJS(globalThis.ptr(), iter.arena.allocator(), arg) orelse {
|
||||
globalThis.throwInvalidArguments("expected string or buffer", .{});
|
||||
iter.deinit();
|
||||
return JSC.JSValue.zero;
|
||||
};
|
||||
} else {
|
||||
args[i] = null;
|
||||
}
|
||||
},
|
||||
JSC.ArrayBuffer => {
|
||||
if (iter.nextEat()) |arg| {
|
||||
args[i] = arg.asArrayBuffer(globalThis.ptr()) orelse {
|
||||
@@ -3331,7 +3359,7 @@ pub const FilePoll = struct {
|
||||
const DNSResolver = JSC.DNS.DNSResolver;
|
||||
const GetAddrInfoRequest = JSC.DNS.GetAddrInfoRequest;
|
||||
const Deactivated = opaque {
|
||||
pub var owner: Owner = Owner.init(@intToPtr(*Deactivated, @as(usize, 0xDEADBEEF)));
|
||||
pub var owner: Owner = Owner.init(@ptrFromInt(*Deactivated, @as(usize, 0xDEADBEEF)));
|
||||
};
|
||||
|
||||
pub const Owner = bun.TaggedPointerUnion(.{
|
||||
@@ -3586,7 +3614,7 @@ pub const FilePoll = struct {
|
||||
return;
|
||||
this.flags.insert(.disable);
|
||||
|
||||
vm.uws_event_loop.?.active -= @as(u32, @boolToInt(this.flags.contains(.has_incremented_poll_count)));
|
||||
vm.uws_event_loop.?.active -= @as(u32, @intFromBool(this.flags.contains(.has_incremented_poll_count)));
|
||||
}
|
||||
|
||||
pub fn enableKeepingProcessAlive(this: *FilePoll, vm: *JSC.VirtualMachine) void {
|
||||
@@ -3594,7 +3622,7 @@ pub const FilePoll = struct {
|
||||
return;
|
||||
this.flags.remove(.disable);
|
||||
|
||||
vm.uws_event_loop.?.active += @as(u32, @boolToInt(this.flags.contains(.has_incremented_poll_count)));
|
||||
vm.uws_event_loop.?.active += @as(u32, @intFromBool(this.flags.contains(.has_incremented_poll_count)));
|
||||
}
|
||||
|
||||
pub fn canActivate(this: *const FilePoll) bool {
|
||||
@@ -3604,16 +3632,16 @@ pub const FilePoll = struct {
|
||||
/// Only intended to be used from EventLoop.Pollable
|
||||
pub fn deactivate(this: *FilePoll, loop: *uws.Loop) void {
|
||||
std.debug.assert(this.flags.contains(.has_incremented_poll_count));
|
||||
loop.num_polls -= @as(i32, @boolToInt(this.flags.contains(.has_incremented_poll_count)));
|
||||
loop.active -|= @as(u32, @boolToInt(!this.flags.contains(.disable) and this.flags.contains(.has_incremented_poll_count)));
|
||||
loop.num_polls -= @as(i32, @intFromBool(this.flags.contains(.has_incremented_poll_count)));
|
||||
loop.active -|= @as(u32, @intFromBool(!this.flags.contains(.disable) and this.flags.contains(.has_incremented_poll_count)));
|
||||
|
||||
this.flags.remove(.has_incremented_poll_count);
|
||||
}
|
||||
|
||||
/// Only intended to be used from EventLoop.Pollable
|
||||
pub fn activate(this: *FilePoll, loop: *uws.Loop) void {
|
||||
loop.num_polls += @as(i32, @boolToInt(!this.flags.contains(.has_incremented_poll_count)));
|
||||
loop.active += @as(u32, @boolToInt(!this.flags.contains(.disable) and !this.flags.contains(.has_incremented_poll_count)));
|
||||
loop.num_polls += @as(i32, @intFromBool(!this.flags.contains(.has_incremented_poll_count)));
|
||||
loop.active += @as(u32, @intFromBool(!this.flags.contains(.disable) and !this.flags.contains(.has_incremented_poll_count)));
|
||||
|
||||
this.flags.insert(.has_incremented_poll_count);
|
||||
}
|
||||
@@ -3714,7 +3742,7 @@ pub const FilePoll = struct {
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
var event = linux.epoll_event{ .events = flags, .data = .{ .u64 = @ptrToInt(Pollable.init(this).ptr()) } };
|
||||
var event = linux.epoll_event{ .events = flags, .data = .{ .u64 = @intFromPtr(Pollable.init(this).ptr()) } };
|
||||
|
||||
const ctl = linux.epoll_ctl(
|
||||
watcher_fd,
|
||||
@@ -3735,7 +3763,7 @@ pub const FilePoll = struct {
|
||||
.filter = std.os.system.EVFILT_READ,
|
||||
.data = 0,
|
||||
.fflags = 0,
|
||||
.udata = @ptrToInt(Pollable.init(this).ptr()),
|
||||
.udata = @intFromPtr(Pollable.init(this).ptr()),
|
||||
.flags = std.c.EV_ADD | one_shot_flag,
|
||||
.ext = .{ this.generation_number, 0 },
|
||||
},
|
||||
@@ -3744,7 +3772,7 @@ pub const FilePoll = struct {
|
||||
.filter = std.os.system.EVFILT_WRITE,
|
||||
.data = 0,
|
||||
.fflags = 0,
|
||||
.udata = @ptrToInt(Pollable.init(this).ptr()),
|
||||
.udata = @intFromPtr(Pollable.init(this).ptr()),
|
||||
.flags = std.c.EV_ADD | one_shot_flag,
|
||||
.ext = .{ this.generation_number, 0 },
|
||||
},
|
||||
@@ -3753,7 +3781,7 @@ pub const FilePoll = struct {
|
||||
.filter = std.os.system.EVFILT_PROC,
|
||||
.data = 0,
|
||||
.fflags = std.c.NOTE_EXIT,
|
||||
.udata = @ptrToInt(Pollable.init(this).ptr()),
|
||||
.udata = @intFromPtr(Pollable.init(this).ptr()),
|
||||
.flags = std.c.EV_ADD | one_shot_flag,
|
||||
.ext = .{ this.generation_number, 0 },
|
||||
},
|
||||
@@ -3762,7 +3790,7 @@ pub const FilePoll = struct {
|
||||
.filter = std.os.system.EVFILT_MACHPORT,
|
||||
.data = 0,
|
||||
.fflags = 0,
|
||||
.udata = @ptrToInt(Pollable.init(this).ptr()),
|
||||
.udata = @intFromPtr(Pollable.init(this).ptr()),
|
||||
.flags = std.c.EV_ADD | one_shot_flag,
|
||||
.ext = .{ this.generation_number, 0 },
|
||||
},
|
||||
@@ -3887,7 +3915,7 @@ pub const FilePoll = struct {
|
||||
.filter = std.os.system.EVFILT_READ,
|
||||
.data = 0,
|
||||
.fflags = 0,
|
||||
.udata = @ptrToInt(Pollable.init(this).ptr()),
|
||||
.udata = @intFromPtr(Pollable.init(this).ptr()),
|
||||
.flags = std.c.EV_DELETE,
|
||||
.ext = .{ 0, 0 },
|
||||
},
|
||||
@@ -3896,7 +3924,7 @@ pub const FilePoll = struct {
|
||||
.filter = std.os.system.EVFILT_MACHPORT,
|
||||
.data = 0,
|
||||
.fflags = 0,
|
||||
.udata = @ptrToInt(Pollable.init(this).ptr()),
|
||||
.udata = @intFromPtr(Pollable.init(this).ptr()),
|
||||
.flags = std.c.EV_DELETE,
|
||||
.ext = .{ 0, 0 },
|
||||
},
|
||||
@@ -3905,7 +3933,7 @@ pub const FilePoll = struct {
|
||||
.filter = std.os.system.EVFILT_WRITE,
|
||||
.data = 0,
|
||||
.fflags = 0,
|
||||
.udata = @ptrToInt(Pollable.init(this).ptr()),
|
||||
.udata = @intFromPtr(Pollable.init(this).ptr()),
|
||||
.flags = std.c.EV_DELETE,
|
||||
.ext = .{ 0, 0 },
|
||||
},
|
||||
@@ -3914,7 +3942,7 @@ pub const FilePoll = struct {
|
||||
.filter = std.os.system.EVFILT_PROC,
|
||||
.data = 0,
|
||||
.fflags = std.c.NOTE_EXIT,
|
||||
.udata = @ptrToInt(Pollable.init(this).ptr()),
|
||||
.udata = @intFromPtr(Pollable.init(this).ptr()),
|
||||
.flags = std.c.EV_DELETE,
|
||||
.ext = .{ 0, 0 },
|
||||
},
|
||||
@@ -3949,7 +3977,7 @@ pub const FilePoll = struct {
|
||||
|
||||
const errno = std.c.getErrno(rc);
|
||||
switch (rc) {
|
||||
std.math.minInt(@TypeOf(rc))...-1 => return JSC.Maybe(void).errnoSys(@enumToInt(errno), .kevent).?,
|
||||
std.math.minInt(@TypeOf(rc))...-1 => return JSC.Maybe(void).errnoSys(@intFromEnum(errno), .kevent).?,
|
||||
else => {},
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
|
||||
|
||||
#include <JavaScriptCore/AugmentableInspectorControllerClient.h>
|
||||
#include <JavaScriptCore/InspectorBackendDispatcher.h>
|
||||
#include <JavaScriptCore/InspectorFrontendRouter.h>
|
||||
|
||||
namespace Inspector {
|
||||
|
||||
class InspectorAgentBase;
|
||||
|
||||
class AugmentableInspectorController {
|
||||
public:
|
||||
virtual ~AugmentableInspectorController() {}
|
||||
|
||||
virtual AugmentableInspectorControllerClient* augmentableInspectorControllerClient() const = 0;
|
||||
virtual void setAugmentableInspectorControllerClient(AugmentableInspectorControllerClient*) = 0;
|
||||
|
||||
virtual const FrontendRouter& frontendRouter() const = 0;
|
||||
virtual BackendDispatcher& backendDispatcher() = 0;
|
||||
virtual void registerAlternateAgent(std::unique_ptr<InspectorAgentBase>) = 0;
|
||||
|
||||
bool connected() const { return frontendRouter().hasFrontends(); }
|
||||
};
|
||||
|
||||
} // namespace Inspector
|
||||
|
||||
#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
|
||||
@@ -1,391 +1,184 @@
|
||||
#include "BunInspector.h"
|
||||
#include <JavaScriptCore/Heap.h>
|
||||
#include <JavaScriptCore/JSGlobalObject.h>
|
||||
#include <JavaScriptCore/JSGlobalObjectDebugger.h>
|
||||
#include "root.h"
|
||||
#include <uws/src/App.h>
|
||||
|
||||
namespace Zig {
|
||||
|
||||
WTF_MAKE_ISO_ALLOCATED_IMPL(BunInspector);
|
||||
|
||||
extern "C" void Bun__waitForDebuggerToStart();
|
||||
extern "C" void Bun__debuggerIsReady();
|
||||
|
||||
static BunInspector* inspectorFromGlobal(Zig::GlobalObject* globalObject)
|
||||
{
|
||||
RELEASE_ASSERT(globalObject->bunInspectorPtr);
|
||||
return reinterpret_cast<BunInspector*>(globalObject->bunInspectorPtr);
|
||||
}
|
||||
|
||||
class BunInspectorConnection {
|
||||
#include <JavaScriptCore/InspectorFrontendChannel.h>
|
||||
#include <JavaScriptCore/JSGlobalObjectDebuggable.h>
|
||||
|
||||
namespace Bun {
|
||||
using namespace JSC;
|
||||
template<bool isSSL>
|
||||
class BunInspectorConnection : public Inspector::FrontendChannel {
|
||||
public:
|
||||
WTF::Deque<WTF::CString> m_messages;
|
||||
RefPtr<BunInspector> inspector;
|
||||
bool hasSentWelcomeMessage = false;
|
||||
BunInspectorConnection(RefPtr<BunInspector> inspector)
|
||||
: inspector(inspector)
|
||||
, m_messages()
|
||||
using BunInspectorSocket = uWS::WebSocket<isSSL, true, BunInspectorConnection*>;
|
||||
|
||||
BunInspectorConnection(BunInspectorSocket* ws, JSC::JSGlobalObject* globalObject)
|
||||
: ws(ws)
|
||||
, globalObject(globalObject)
|
||||
, pendingMessages()
|
||||
{
|
||||
}
|
||||
|
||||
~BunInspectorConnection()
|
||||
{
|
||||
}
|
||||
|
||||
Inspector::FrontendChannel::ConnectionType connectionType() const override
|
||||
{
|
||||
return Inspector::FrontendChannel::ConnectionType::Remote;
|
||||
}
|
||||
|
||||
void onOpen(JSC::JSGlobalObject* globalObject)
|
||||
{
|
||||
this->globalObject = globalObject;
|
||||
this->globalObject->inspectorDebuggable().connect(*this);
|
||||
}
|
||||
|
||||
void onClose()
|
||||
{
|
||||
this->globalObject->inspectorDebuggable().disconnect(*this);
|
||||
this->pendingMessages.clear();
|
||||
}
|
||||
|
||||
void sendMessageToFrontend(const String& message) override
|
||||
{
|
||||
send(message);
|
||||
}
|
||||
|
||||
void send(const WTF::String& message)
|
||||
{
|
||||
if (ws->getBufferedAmount() == 0) {
|
||||
WTF::CString messageCString = message.utf8();
|
||||
ws->send(std::string_view { messageCString.data(), messageCString.length() }, uWS::OpCode::TEXT);
|
||||
} else {
|
||||
pendingMessages.append(message);
|
||||
}
|
||||
}
|
||||
|
||||
void onMessage(std::string_view message)
|
||||
{
|
||||
WTF::String messageString = WTF::String::fromUTF8(message.data(), message.length());
|
||||
this->globalObject->inspectorDebuggable().dispatchMessageFromRemote(WTFMove(messageString));
|
||||
}
|
||||
|
||||
void drain()
|
||||
{
|
||||
if (pendingMessages.size() == 0)
|
||||
return;
|
||||
|
||||
if (ws->getBufferedAmount() == 0) {
|
||||
ws->cork([&]() {
|
||||
for (auto& message : pendingMessages) {
|
||||
WTF::CString messageCString = message.utf8();
|
||||
ws->send(std::string_view { messageCString.data(), messageCString.length() }, uWS::OpCode::TEXT);
|
||||
}
|
||||
pendingMessages.clear();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
WTF::Vector<WTF::String> pendingMessages;
|
||||
JSC::JSGlobalObject* globalObject;
|
||||
BunInspectorSocket* ws;
|
||||
};
|
||||
|
||||
void BunInspector::sendMessageToFrontend(const String& message)
|
||||
using BunInspectorConnectionNoSSL = BunInspectorConnection<false>;
|
||||
using SSLBunInspectorConnection = BunInspectorConnection<true>;
|
||||
|
||||
template<bool isSSL>
|
||||
static void addInspector(void* app, JSC::JSGlobalObject* globalObject)
|
||||
{
|
||||
if constexpr (isSSL) {
|
||||
auto handler = uWS::SSLApp::WebSocketBehavior<SSLBunInspectorConnection*> {
|
||||
/* Settings */
|
||||
.compression = uWS::DISABLED,
|
||||
.maxPayloadLength = 16 * 1024 * 1024,
|
||||
.idleTimeout = 960,
|
||||
.maxBackpressure = 16 * 1024 * 1024,
|
||||
.closeOnBackpressureLimit = false,
|
||||
.resetIdleTimeoutOnSend = true,
|
||||
.sendPingsAutomatically = true,
|
||||
/* Handlers */
|
||||
.upgrade = nullptr,
|
||||
.open = [globalObject](auto* ws) {
|
||||
globalObject->setInspectable(true);
|
||||
*ws->getUserData() = new SSLBunInspectorConnection(ws, globalObject);
|
||||
SSLBunInspectorConnection* inspector = *ws->getUserData();
|
||||
inspector->onOpen(globalObject);
|
||||
//
|
||||
},
|
||||
.message = [](auto* ws, std::string_view message, uWS::OpCode opCode) {
|
||||
SSLBunInspectorConnection* inspector = *(SSLBunInspectorConnection**)ws->getUserData();
|
||||
inspector->onMessage(message);
|
||||
//
|
||||
},
|
||||
.drain = [](auto* ws) {
|
||||
SSLBunInspectorConnection* inspector = *(SSLBunInspectorConnection**)ws->getUserData();
|
||||
inspector->drain();
|
||||
//
|
||||
},
|
||||
.ping = [](auto* /*ws*/, std::string_view) {
|
||||
/* Not implemented yet */ },
|
||||
.pong = [](auto* /*ws*/, std::string_view) {
|
||||
/* Not implemented yet */ },
|
||||
|
||||
String out = message;
|
||||
auto jsonObject = WTF::JSONImpl::Value::parseJSON(message);
|
||||
if (jsonObject) {
|
||||
if (auto object = jsonObject->asObject()) {
|
||||
auto method = object->getString("method"_s);
|
||||
.close = [](auto* ws, int /*code*/, std::string_view /*message*/) {
|
||||
SSLBunInspectorConnection* inspector = *(SSLBunInspectorConnection**)ws->getUserData();
|
||||
inspector->onClose();
|
||||
delete inspector; }
|
||||
};
|
||||
|
||||
// {
|
||||
// "scriptId": "384",
|
||||
// "url": "file:///private/tmp/empty.js",
|
||||
// "startLine": 0,
|
||||
// "startColumn": 0,
|
||||
// "endLine": 1,
|
||||
// "endColumn": 0,
|
||||
// "executionContextId": 1,
|
||||
// "hash": "a3b314362f7e47deabee6100e0d8081619194faf1b5741e0fe2f88b150557ddd",
|
||||
// "executionContextAuxData": { "isDefault": true },
|
||||
// "isLiveEdit": false,
|
||||
// "sourceMapURL": "",
|
||||
// "hasSourceURL": false,
|
||||
// "isModule": false,
|
||||
// "length": 21,
|
||||
// "stackTrace": {
|
||||
// "callFrames": [
|
||||
// {
|
||||
// "functionName": "internalCompileFunction",
|
||||
// "scriptId": "62",
|
||||
// "url": "node:internal/vm",
|
||||
// "lineNumber": 72,
|
||||
// "columnNumber": 17
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// "scriptLanguage": "JavaScript",
|
||||
// "embedderName": "file:///private/tmp/empty.js"
|
||||
// }
|
||||
if (method == "Debugger.scriptParsed"_s) {
|
||||
if (auto params = object->getObject("params"_s)) {
|
||||
params->setInteger("executionContextId"_s, 1);
|
||||
auto url = makeString("file://"_s, params->getString("url"_s));
|
||||
params->setString("url"_s, url);
|
||||
// TODO: content hash
|
||||
params->setInteger("hash"_s, url.hash());
|
||||
params->setBoolean("isModule"_s, true);
|
||||
params->setString("scriptLanguage"_s, "JavaScript"_s);
|
||||
params->setString("embedderName"_s, "Bun!"_s);
|
||||
}
|
||||
((uWS::SSLApp*)app)->ws<SSLBunInspectorConnection*>("/bun:inspect", std::move(handler));
|
||||
} else {
|
||||
|
||||
out = object->toJSONString();
|
||||
}
|
||||
auto handler = uWS::App::WebSocketBehavior<BunInspectorConnectionNoSSL*> {
|
||||
/* Settings */
|
||||
.compression = uWS::DISABLED,
|
||||
.maxPayloadLength = 16 * 1024 * 1024,
|
||||
.idleTimeout = 960,
|
||||
.maxBackpressure = 16 * 1024 * 1024,
|
||||
.closeOnBackpressureLimit = false,
|
||||
.resetIdleTimeoutOnSend = true,
|
||||
.sendPingsAutomatically = true,
|
||||
/* Handlers */
|
||||
.upgrade = nullptr,
|
||||
.open = [globalObject](auto* ws) {
|
||||
globalObject->setInspectable(true);
|
||||
*ws->getUserData() = new BunInspectorConnectionNoSSL(ws, globalObject);
|
||||
BunInspectorConnectionNoSSL* inspector = *ws->getUserData();
|
||||
inspector->onOpen(globalObject);
|
||||
//
|
||||
},
|
||||
.message = [](auto* ws, std::string_view message, uWS::OpCode opCode) {
|
||||
BunInspectorConnectionNoSSL* inspector = *(BunInspectorConnectionNoSSL**)ws->getUserData();
|
||||
inspector->onMessage(message);
|
||||
//
|
||||
},
|
||||
.drain = [](auto* ws) {
|
||||
BunInspectorConnectionNoSSL* inspector = *(BunInspectorConnectionNoSSL**)ws->getUserData();
|
||||
inspector->drain();
|
||||
//
|
||||
},
|
||||
.ping = [](auto* /*ws*/, std::string_view) {
|
||||
/* Not implemented yet */ },
|
||||
.pong = [](auto* /*ws*/, std::string_view) {
|
||||
/* Not implemented yet */ },
|
||||
|
||||
if (method == "Debugger.enable"_s) {
|
||||
// debuggerId is missing from the response
|
||||
auto params = WTF::JSONImpl::Object::create();
|
||||
params->setString("debuggerId"_s, "3701622443570787625.-8711178633418819848"_s);
|
||||
object->setObject("params"_s, WTFMove(params));
|
||||
}
|
||||
.close = [](auto* ws, int /*code*/, std::string_view /*message*/) {
|
||||
BunInspectorConnectionNoSSL* inspector = *(BunInspectorConnectionNoSSL**)ws->getUserData();
|
||||
inspector->onClose();
|
||||
delete inspector; }
|
||||
};
|
||||
|
||||
out = object->toJSONString();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
LockHolder locker(this->m_pendingMessagesLock);
|
||||
if (!this->hasSentWelcomeMessage) {
|
||||
this->hasSentWelcomeMessage = true;
|
||||
auto welcomeMessage = makeString(
|
||||
"{ \"method\": \"Runtime.executionContextCreated\", \"params\":{\"context\":{\"id\":"_s,
|
||||
this->scriptExecutionContext()->identifier(),
|
||||
",\"origin\":\"\",\"name\":\""_s,
|
||||
this->identifier(),
|
||||
"\",\"uniqueId\":\"1234\",\"auxData\":{\"isDefault\":true}}}}"_s);
|
||||
this->m_pendingMessages.append(WTFMove(welcomeMessage.isolatedCopy()));
|
||||
}
|
||||
|
||||
this->m_pendingMessages.append(WTFMove(out.isolatedCopy()));
|
||||
}
|
||||
us_wakeup_loop((us_loop_t*)this->loop);
|
||||
}
|
||||
|
||||
void BunInspector::drainIncomingMessages()
|
||||
{
|
||||
LockHolder locker(this->m_incomingMessagesLock);
|
||||
size_t size = this->m_incomingMessages.size();
|
||||
while (size > 0) {
|
||||
auto& message = this->m_incomingMessages.first();
|
||||
this->sendMessageToTargetBackend(message);
|
||||
this->m_incomingMessages.removeFirst();
|
||||
size = this->m_incomingMessages.size();
|
||||
((uWS::App*)app)->ws<BunInspectorConnectionNoSSL*>("/bun:inspect", std::move(handler));
|
||||
}
|
||||
}
|
||||
|
||||
void BunInspector::didParseSource(SourceID id, const Debugger::Script& script)
|
||||
extern "C" void Bun__addInspector(bool isSSL, void* app, JSC::JSGlobalObject* globalObject)
|
||||
{
|
||||
}
|
||||
|
||||
void BunInspector::drainOutgoingMessages()
|
||||
{
|
||||
|
||||
if (this->server->numSubscribers("BunInspectorConnection") == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
LockHolder locker(this->m_pendingMessagesLock);
|
||||
size_t size = this->m_pendingMessages.size();
|
||||
while (size > 0) {
|
||||
auto& message = this->m_pendingMessages.first();
|
||||
auto utf8 = message.utf8();
|
||||
std::string_view view { utf8.data(), utf8.length() };
|
||||
if (!this->server->publish("BunInspectorConnection", view, uWS::OpCode::TEXT, false)) {
|
||||
return;
|
||||
}
|
||||
this->m_pendingMessages.removeFirst();
|
||||
size = this->m_pendingMessages.size();
|
||||
if (isSSL) {
|
||||
addInspector<true>((uWS::TemplatedApp<true>*)app, globalObject);
|
||||
} else {
|
||||
addInspector<false>((uWS::TemplatedApp<false>*)app, globalObject);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" void Bun__tickWhileWaitingForDebugger(JSC::JSGlobalObject* globalObject);
|
||||
|
||||
void BunInspector::startServer(WTF::String hostname, uint16_t port, WTF::URL url, WTF::String title)
|
||||
{
|
||||
uWS::App* app = new uWS::App();
|
||||
this->server = app;
|
||||
this->loop = uWS::Loop::get();
|
||||
|
||||
auto host = hostname.utf8();
|
||||
|
||||
// https://chromedevtools.github.io/devtools-protocol/ GET /json or /json/list
|
||||
app->get("/json", [hostname, port, url, title = title, inspector = this](auto* res, auto* /*req*/) {
|
||||
auto identifier = inspector->identifier();
|
||||
auto jsonString = makeString(
|
||||
"[ {\"faviconUrl\": \"https://bun.sh/favicon.svg\", \"description\": \"\", \"devtoolsFrontendUrl\": \"devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws="_s,
|
||||
hostname,
|
||||
":"_s,
|
||||
port,
|
||||
"/devtools/page/"_s,
|
||||
identifier,
|
||||
"\","_s
|
||||
" \"id\": \"6e99c4f9-6bb6-4f45-9749-5772545b2371\","_s,
|
||||
" \"title\": \""_s,
|
||||
title,
|
||||
"\","
|
||||
" \"type\": \"node\","_s,
|
||||
" \"url\": \"file://"_s,
|
||||
identifier,
|
||||
"\","_s
|
||||
" \"webSocketDebuggerUrl\": \"ws://"_s,
|
||||
hostname,
|
||||
":"_s,
|
||||
port,
|
||||
"/devtools/page/"_s,
|
||||
identifier,
|
||||
"\"} ]"_s);
|
||||
auto utf8 = jsonString.utf8();
|
||||
res->writeStatus("200 OK");
|
||||
res->writeHeader("Content-Type", "application/json");
|
||||
res->end(utf8.data(), utf8.length());
|
||||
})
|
||||
.get("/json/version", [](auto* res, auto* req) {
|
||||
auto out = makeString("{\"Browser\": \"Bun/"_s, Bun__version, "\",\"Protocol-Version\": \"1.1\"}"_s);
|
||||
auto utf8 = out.utf8();
|
||||
res->writeStatus("200 OK");
|
||||
res->writeHeader("Content-Type", "application/json");
|
||||
res->end({ utf8.data(), utf8.length() });
|
||||
})
|
||||
.ws<BunInspectorConnection*>("/*", { /* Settings */
|
||||
.compression = uWS::DISABLED,
|
||||
.maxPayloadLength = 1024 * 1024 * 1024,
|
||||
.idleTimeout = 512,
|
||||
.maxBackpressure = 64 * 1024 * 1024,
|
||||
.closeOnBackpressureLimit = false,
|
||||
.resetIdleTimeoutOnSend = false,
|
||||
.sendPingsAutomatically = true,
|
||||
/* Handlers */
|
||||
.upgrade = nullptr,
|
||||
.open = [inspector = this](auto* ws) {
|
||||
BunInspectorConnection** connectionPtr = ws->getUserData();
|
||||
*connectionPtr = new BunInspectorConnection(inspector);
|
||||
|
||||
|
||||
ws->subscribe("BunInspectorConnection");
|
||||
BunInspectorConnection* connection = *connectionPtr;
|
||||
Bun__debuggerIsReady(); },
|
||||
|
||||
.message = [inspector = this](auto* ws, std::string_view message, uWS::OpCode opCode) {
|
||||
if (opCode == uWS::OpCode::TEXT) {
|
||||
if (!inspector) {
|
||||
ws->close();
|
||||
return;
|
||||
}
|
||||
|
||||
BunInspectorConnection** connectionPtr = ws->getUserData();
|
||||
BunInspectorConnection* connection = *connectionPtr;
|
||||
|
||||
|
||||
|
||||
|
||||
connection->inspector->dispatchToBackend(message);
|
||||
connection->inspector->drainOutgoingMessages();
|
||||
|
||||
|
||||
} },
|
||||
.drain = [](auto* ws) {
|
||||
|
||||
/* Check ws->getBufferedAmount() here */
|
||||
BunInspectorConnection** connectionPtr = ws->getUserData();
|
||||
BunInspectorConnection* connection = *connectionPtr;
|
||||
|
||||
if (!connection) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
while (connection->m_messages.size() > 0) {
|
||||
auto& message = connection->m_messages.first();
|
||||
std::string_view view { message.data(), message.length() };
|
||||
if (!ws->send(view, uWS::OpCode::TEXT, false, false)) {
|
||||
return;
|
||||
}
|
||||
connection->m_messages.removeFirst();
|
||||
}
|
||||
connection->inspector->drainOutgoingMessages(); },
|
||||
.ping = [](auto* /*ws*/, std::string_view) {
|
||||
/* Not implemented yet */ },
|
||||
.pong = [](auto* /*ws*/, std::string_view) {
|
||||
/* Not implemented yet */ },
|
||||
.close = [](auto* ws, int /*code*/, std::string_view /*message*/) {
|
||||
BunInspectorConnection** connectionPtr = ws->getUserData();
|
||||
BunInspectorConnection* connection = *connectionPtr;
|
||||
if (!connection) {
|
||||
return;
|
||||
}
|
||||
if (connection->inspector.get()) {
|
||||
connection->inspector->disconnect();
|
||||
connection->inspector = nullptr;
|
||||
}
|
||||
|
||||
connection->m_messages.clear();
|
||||
delete connection; } })
|
||||
.any("/*", [](auto* res, auto* req) {
|
||||
res->writeStatus("404 Not Found");
|
||||
res->writeHeader("Content-Type", "text/plain");
|
||||
res->write(req->getUrl());
|
||||
res->end(" was not found");
|
||||
})
|
||||
.listen(std::string(host.data(), host.length()), port, [inspector = this](auto* listen_socket) {
|
||||
inspector->loop->addPostHandler(inspector, [inspector = inspector](uWS::Loop* loop) {
|
||||
inspector->drainOutgoingMessages();
|
||||
});
|
||||
WebCore::ScriptExecutionContext::postTaskTo(
|
||||
inspector->scriptExecutionContext()->identifier(),
|
||||
[inspector = inspector](WebCore::ScriptExecutionContext& ctx) mutable {
|
||||
inspector->readyToStartDebugger();
|
||||
});
|
||||
|
||||
inspector->loop->run();
|
||||
});
|
||||
}
|
||||
|
||||
void BunInspector::readyToStartDebugger()
|
||||
{
|
||||
this->ensureDebugger();
|
||||
|
||||
auto& inspectorController = globalObject()->inspectorController();
|
||||
auto* debugger = inspectorController.debugger();
|
||||
debugger->addObserver(*this);
|
||||
debugger->schedulePauseAtNextOpportunity();
|
||||
}
|
||||
|
||||
BunInspector* BunInspector::startWebSocketServer(
|
||||
Zig::GlobalObject* globalObject,
|
||||
WebCore::ScriptExecutionContext& context,
|
||||
WTF::String hostname,
|
||||
uint16_t port,
|
||||
WTF::Function<void(BunInspector*, bool success)>&& callback)
|
||||
{
|
||||
context.ensureURL();
|
||||
auto url = context.url();
|
||||
auto identifier = url.fileSystemPath();
|
||||
|
||||
auto title = makeString(
|
||||
url.fileSystemPath(),
|
||||
" (Bun "_s, Bun__version, ")"_s);
|
||||
|
||||
auto* inspector = new BunInspector(&context, nullptr, WTFMove(identifier));
|
||||
reinterpret_cast<Zig::GlobalObject*>(globalObject)->bunInspectorPtr = inspector;
|
||||
auto backgroundThreadFunction = [inspector = inspector, hostname = hostname.isolatedCopy(), port = port, url = WTFMove(url), title = WTFMove(title)]() -> void {
|
||||
inspector->startServer(hostname, port, url, WTFMove(title));
|
||||
};
|
||||
WTF::Thread::create("BunInspector", WTFMove(backgroundThreadFunction))->detach();
|
||||
|
||||
callback(inspector, true);
|
||||
Bun__waitForDebuggerToStart();
|
||||
|
||||
return inspector;
|
||||
}
|
||||
|
||||
void BunInspector::dispatchToBackend(std::string_view message)
|
||||
{
|
||||
WTF::CString data { message.data(), message.length() };
|
||||
WTF::String msg = WTF::String::fromUTF8(data.data(), data.length());
|
||||
bool needsTask = true;
|
||||
{
|
||||
LockHolder incomingMessagesLock(this->m_incomingMessagesLock);
|
||||
needsTask = this->m_incomingMessages.isEmpty();
|
||||
this->m_incomingMessages.append(WTFMove(msg.isolatedCopy()));
|
||||
}
|
||||
WebCore::ScriptExecutionContext::postTaskTo(
|
||||
scriptExecutionContext()->identifier(),
|
||||
[inspector = this](WebCore::ScriptExecutionContext& ctx) mutable {
|
||||
inspector->drainIncomingMessages();
|
||||
});
|
||||
}
|
||||
|
||||
void BunInspector::sendMessageToTargetBackend(const WTF::String& message)
|
||||
{
|
||||
globalObject()->inspectorController().dispatchMessageFromFrontend(message);
|
||||
}
|
||||
|
||||
void BunInspector::connect(Inspector::FrontendChannel::ConnectionType connectionType)
|
||||
{
|
||||
globalObject()->inspectorController().connectFrontend(*this, false, false);
|
||||
}
|
||||
|
||||
void BunInspector::disconnect()
|
||||
{
|
||||
globalObject()->inspectorController().disconnectFrontend(*this);
|
||||
}
|
||||
|
||||
void BunInspector::didPause(JSGlobalObject* jsGlobalObject, DebuggerCallFrame& callframe, JSValue exceptionOrCaughtValue)
|
||||
{
|
||||
printf("didPause\n");
|
||||
}
|
||||
void BunInspector::didContinue()
|
||||
{
|
||||
printf("didContinue\n");
|
||||
}
|
||||
|
||||
void BunInspector::waitForMessages()
|
||||
{
|
||||
this->m_incomingMessagesLock.lock();
|
||||
}
|
||||
|
||||
void BunInspector::ensureDebugger()
|
||||
{
|
||||
this->connect(Inspector::FrontendChannel::ConnectionType::Local);
|
||||
|
||||
auto* debugger = reinterpret_cast<Inspector::JSGlobalObjectDebugger*>(this->globalObject()->inspectorController().debugger());
|
||||
debugger->runWhilePausedCallback = [](JSC::JSGlobalObject& globalObject, bool& isResumed) {
|
||||
auto* inspector = inspectorFromGlobal(reinterpret_cast<Zig::GlobalObject*>(&globalObject));
|
||||
while (!isResumed) {
|
||||
inspector->drainIncomingMessages();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace Zig
|
||||
@@ -1,104 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "root.h"
|
||||
#include <uws/src/App.h>
|
||||
#include <JavaScriptCore/InspectorTarget.h>
|
||||
#include <JavaScriptCore/InspectorFrontendChannel.h>
|
||||
#include "ContextDestructionObserver.h"
|
||||
#include <wtf/RefPtr.h>
|
||||
#include <JavaScriptCore/Debugger.h>
|
||||
#include <wtf/Deque.h>
|
||||
#include "JSGlobalObjectInspectorController.h"
|
||||
|
||||
namespace Zig {
|
||||
|
||||
using namespace JSC;
|
||||
using namespace WebCore;
|
||||
|
||||
class BunInspector final : public RefCounted<BunInspector>, ::Inspector::InspectorTarget, ::Inspector::FrontendChannel, public WebCore::ContextDestructionObserver, JSC::Debugger::Observer {
|
||||
public:
|
||||
WTF_MAKE_ISO_ALLOCATED(BunInspector);
|
||||
BunInspector(ScriptExecutionContext* context, uWS::App* server, WTF::String&& identifier)
|
||||
: server(server)
|
||||
, WebCore::ContextDestructionObserver(context)
|
||||
, m_identifier(WTFMove(identifier))
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
~BunInspector()
|
||||
{
|
||||
server->close();
|
||||
}
|
||||
|
||||
bool isProvisional() const override { return false; }
|
||||
String identifier() const override { return m_identifier; }
|
||||
Inspector::InspectorTargetType type() const override { return Inspector::InspectorTargetType::DedicatedWorker; }
|
||||
GlobalObject* globalObject() { return static_cast<GlobalObject*>(scriptExecutionContext()->jsGlobalObject()); }
|
||||
|
||||
void startServer(WTF::String hostname, uint16_t port, WTF::URL url, WTF::String title);
|
||||
|
||||
Lock m_mutex;
|
||||
|
||||
void ensureDebugger();
|
||||
JSC::Debugger* debugger() { return globalObject()->inspectorController().debugger(); }
|
||||
|
||||
void didPause(JSGlobalObject*, DebuggerCallFrame&, JSValue /* exceptionOrCaughtValue */) override;
|
||||
void didContinue() override;
|
||||
void didParseSource(SourceID, const Debugger::Script&) override;
|
||||
void failedToParseSource(const String& /* url */, const String& /* data */, int /* firstLine */, int /* errorLine */, const String& /* errorMessage */) override {}
|
||||
|
||||
void didCreateNativeExecutable(NativeExecutable&) override {}
|
||||
void willCallNativeExecutable(CallFrame*) override {}
|
||||
|
||||
void willEnter(CallFrame*) override {}
|
||||
|
||||
void didQueueMicrotask(JSGlobalObject*, MicrotaskIdentifier) override {}
|
||||
void willRunMicrotask(JSGlobalObject*, MicrotaskIdentifier) override {}
|
||||
void didRunMicrotask(JSGlobalObject*, MicrotaskIdentifier) override {}
|
||||
|
||||
void applyBreakpoints(CodeBlock*) override {}
|
||||
void breakpointActionLog(JSGlobalObject*, const String& /* data */) override {}
|
||||
void breakpointActionSound(BreakpointActionID) override {}
|
||||
void breakpointActionProbe(JSGlobalObject*, BreakpointActionID, unsigned /* batchId */, unsigned /* sampleId */, JSValue /* result */) override {}
|
||||
void didDeferBreakpointPause(BreakpointID) override {}
|
||||
|
||||
static BunInspector* startWebSocketServer(
|
||||
Zig::GlobalObject* globalObject,
|
||||
WebCore::ScriptExecutionContext& ctx,
|
||||
WTF::String hostname,
|
||||
uint16_t port,
|
||||
WTF::Function<void(BunInspector*, bool success)>&& callback);
|
||||
|
||||
// Connection management.
|
||||
void connect(Inspector::FrontendChannel::ConnectionType) override;
|
||||
void disconnect() override;
|
||||
void sendMessageToTargetBackend(const String&) override;
|
||||
bool hasConnectedFrontends() { return connectionCounter > 0; }
|
||||
|
||||
void sendMessageToFrontend(const String& message) override;
|
||||
Inspector::FrontendChannel::ConnectionType connectionType() const override { return Inspector::FrontendChannel::ConnectionType::Remote; }
|
||||
|
||||
int connectionCounter = 0;
|
||||
bool hasSentWelcomeMessage = false;
|
||||
|
||||
void drainOutgoingMessages();
|
||||
void drainIncomingMessages();
|
||||
void waitForMessages();
|
||||
|
||||
void readyToStartDebugger();
|
||||
|
||||
private:
|
||||
void dispatchToBackend(std::string_view message);
|
||||
|
||||
WTF::String m_identifier;
|
||||
WTF::Lock m_pendingMessagesLock;
|
||||
uWS::App* server;
|
||||
uWS::Loop* loop;
|
||||
Deque<WTF::String> m_pendingMessages;
|
||||
|
||||
Deque<WTF::String> m_incomingMessages;
|
||||
WTF::Lock m_incomingMessagesLock;
|
||||
};
|
||||
}
|
||||
@@ -34,8 +34,6 @@
|
||||
using namespace JSC;
|
||||
using namespace WTF;
|
||||
|
||||
extern "C" bool JSGlobalObject__startRemoteInspector(JSC::JSGlobalObject* globalObject, const char* host, uint16_t port);
|
||||
|
||||
JSC_DECLARE_HOST_FUNCTION(functionStartRemoteDebugger);
|
||||
JSC_DEFINE_HOST_FUNCTION(functionStartRemoteDebugger, (JSGlobalObject * globalObject, CallFrame* callFrame))
|
||||
{
|
||||
@@ -47,13 +45,38 @@ JSC_DEFINE_HOST_FUNCTION(functionStartRemoteDebugger, (JSGlobalObject * globalOb
|
||||
|
||||
JSC::JSValue hostValue = callFrame->argument(0);
|
||||
JSC::JSValue portValue = callFrame->argument(1);
|
||||
const char* host = defaultHost;
|
||||
if (hostValue.isString()) {
|
||||
|
||||
bool res = JSGlobalObject__startRemoteInspector(
|
||||
globalObject,
|
||||
hostValue.isUndefinedOrNull() ? defaultHost : hostValue.toWTFString(globalObject).utf8().data(),
|
||||
portValue.isUndefinedOrNull() ? defaultPort : portValue.toUInt32(globalObject));
|
||||
auto str = hostValue.toWTFString(globalObject);
|
||||
if (!str.isEmpty())
|
||||
host = toCString(str).data();
|
||||
} else if (!hostValue.isUndefined()) {
|
||||
throwVMError(globalObject, scope, createTypeError(globalObject, "host must be a string"_s));
|
||||
return JSC::JSValue::encode(JSC::jsUndefined());
|
||||
}
|
||||
|
||||
RELEASE_AND_RETURN(scope, JSC::JSValue::encode(jsBoolean(res)));
|
||||
uint16_t port = defaultPort;
|
||||
if (portValue.isNumber()) {
|
||||
auto port_int = portValue.toUInt32(globalObject);
|
||||
if (!(port_int > 0 && port_int < 65536)) {
|
||||
throwVMError(globalObject, scope, createRangeError(globalObject, "port must be between 0 and 65535"_s));
|
||||
return JSC::JSValue::encode(JSC::jsUndefined());
|
||||
}
|
||||
port = port_int;
|
||||
} else if (!portValue.isUndefined()) {
|
||||
throwVMError(globalObject, scope, createTypeError(globalObject, "port must be a number between 0 and 65535"_s));
|
||||
return JSC::JSValue::encode(JSC::jsUndefined());
|
||||
}
|
||||
|
||||
globalObject->setInspectable(true);
|
||||
auto& server = Inspector::RemoteInspectorServer::singleton();
|
||||
if (!server.start(reinterpret_cast<const char*>(host), port)) {
|
||||
throwVMError(globalObject, scope, createError(globalObject, "Failed to start server \""_s + host + ":"_s + port + "\". Is port already in use?"_s));
|
||||
return JSC::JSValue::encode(JSC::jsUndefined());
|
||||
}
|
||||
|
||||
RELEASE_AND_RETURN(scope, JSC::JSValue::encode(JSC::jsUndefined()));
|
||||
#else
|
||||
auto& vm = globalObject->vm();
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
@@ -49,7 +49,7 @@ static EncodedJSValue jsFunctionAppendOnLoadPluginBody(JSC::JSGlobalObject* glob
|
||||
auto clientData = WebCore::clientData(vm);
|
||||
auto& builtinNames = clientData->builtinNames();
|
||||
JSC::RegExpObject* filter = nullptr;
|
||||
if (JSValue filterValue = filterObject->getIfPropertyExists(globalObject, builtinNames.filterPublicName())) {
|
||||
if (JSValue filterValue = filterObject->getIfPropertyExists(globalObject, Identifier::fromString(vm, "filter"_s))) {
|
||||
if (filterValue.isCell() && filterValue.asCell()->inherits<JSC::RegExpObject>())
|
||||
filter = jsCast<JSC::RegExpObject*>(filterValue);
|
||||
}
|
||||
@@ -101,7 +101,7 @@ static EncodedJSValue jsFunctionAppendOnResolvePluginBody(JSC::JSGlobalObject* g
|
||||
auto clientData = WebCore::clientData(vm);
|
||||
auto& builtinNames = clientData->builtinNames();
|
||||
JSC::RegExpObject* filter = nullptr;
|
||||
if (JSValue filterValue = filterObject->getIfPropertyExists(globalObject, builtinNames.filterPublicName())) {
|
||||
if (JSValue filterValue = filterObject->getIfPropertyExists(globalObject, Identifier::fromString(vm, "filter"_s))) {
|
||||
if (filterValue.isCell() && filterValue.asCell()->inherits<JSC::RegExpObject>())
|
||||
filter = jsCast<JSC::RegExpObject*>(filterValue);
|
||||
}
|
||||
@@ -366,15 +366,15 @@ JSFunction* BunPlugin::Group::find(JSC::JSGlobalObject* globalObject, String& pa
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EncodedJSValue BunPlugin::OnLoad::run(JSC::JSGlobalObject* globalObject, ZigString* namespaceString, ZigString* path)
|
||||
EncodedJSValue BunPlugin::OnLoad::run(JSC::JSGlobalObject* globalObject, BunString* namespaceString, BunString* path)
|
||||
{
|
||||
Group* groupPtr = this->group(namespaceString ? Zig::toString(*namespaceString) : String());
|
||||
Group* groupPtr = this->group(namespaceString ? Bun::toWTFString(*namespaceString) : String());
|
||||
if (groupPtr == nullptr) {
|
||||
return JSValue::encode(jsUndefined());
|
||||
}
|
||||
Group& group = *groupPtr;
|
||||
|
||||
auto pathString = Zig::toString(*path);
|
||||
auto pathString = Bun::toWTFString(*path);
|
||||
|
||||
JSC::JSFunction* function = group.find(globalObject, pathString);
|
||||
if (!function) {
|
||||
@@ -428,9 +428,9 @@ EncodedJSValue BunPlugin::OnLoad::run(JSC::JSGlobalObject* globalObject, ZigStri
|
||||
RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
|
||||
}
|
||||
|
||||
EncodedJSValue BunPlugin::OnResolve::run(JSC::JSGlobalObject* globalObject, ZigString* namespaceString, ZigString* path, ZigString* importer)
|
||||
EncodedJSValue BunPlugin::OnResolve::run(JSC::JSGlobalObject* globalObject, BunString* namespaceString, BunString* path, BunString* importer)
|
||||
{
|
||||
Group* groupPtr = this->group(namespaceString ? Zig::toString(*namespaceString) : String());
|
||||
Group* groupPtr = this->group(namespaceString ? Bun::toWTFString(*namespaceString) : String());
|
||||
if (groupPtr == nullptr) {
|
||||
return JSValue::encode(jsUndefined());
|
||||
}
|
||||
@@ -443,7 +443,7 @@ EncodedJSValue BunPlugin::OnResolve::run(JSC::JSGlobalObject* globalObject, ZigS
|
||||
|
||||
auto& callbacks = group.callbacks;
|
||||
|
||||
WTF::String pathString = Zig::toString(*path);
|
||||
WTF::String pathString = Bun::toWTFString(*path);
|
||||
for (size_t i = 0; i < filters.size(); i++) {
|
||||
if (!filters[i].get()->match(globalObject, pathString, 0)) {
|
||||
continue;
|
||||
@@ -461,10 +461,10 @@ EncodedJSValue BunPlugin::OnResolve::run(JSC::JSGlobalObject* globalObject, ZigS
|
||||
auto& builtinNames = clientData->builtinNames();
|
||||
paramsObject->putDirect(
|
||||
vm, clientData->builtinNames().pathPublicName(),
|
||||
Zig::toJSStringValue(*path, globalObject));
|
||||
Bun::toJS(globalObject, *path));
|
||||
paramsObject->putDirect(
|
||||
vm, clientData->builtinNames().importerPublicName(),
|
||||
Zig::toJSStringValue(*importer, globalObject));
|
||||
Bun::toJS(globalObject, *importer));
|
||||
arguments.append(paramsObject);
|
||||
|
||||
auto throwScope = DECLARE_THROW_SCOPE(vm);
|
||||
@@ -515,12 +515,12 @@ EncodedJSValue BunPlugin::OnResolve::run(JSC::JSGlobalObject* globalObject, ZigS
|
||||
|
||||
} // namespace Zig
|
||||
|
||||
extern "C" JSC::EncodedJSValue Bun__runOnResolvePlugins(Zig::GlobalObject* globalObject, ZigString* namespaceString, ZigString* path, ZigString* from, BunPluginTarget target)
|
||||
extern "C" JSC::EncodedJSValue Bun__runOnResolvePlugins(Zig::GlobalObject* globalObject, BunString* namespaceString, BunString* path, BunString* from, BunPluginTarget target)
|
||||
{
|
||||
return globalObject->onResolvePlugins[target].run(globalObject, namespaceString, path, from);
|
||||
}
|
||||
|
||||
extern "C" JSC::EncodedJSValue Bun__runOnLoadPlugins(Zig::GlobalObject* globalObject, ZigString* namespaceString, ZigString* path, BunPluginTarget target)
|
||||
extern "C" JSC::EncodedJSValue Bun__runOnLoadPlugins(Zig::GlobalObject* globalObject, BunString* namespaceString, BunString* path, BunPluginTarget target)
|
||||
{
|
||||
return globalObject->onLoadPlugins[target].run(globalObject, namespaceString, path);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
EncodedJSValue run(JSC::JSGlobalObject* globalObject, ZigString* namespaceString, ZigString* path);
|
||||
EncodedJSValue run(JSC::JSGlobalObject* globalObject, BunString* namespaceString, BunString* path);
|
||||
};
|
||||
|
||||
class OnResolve final : public Base {
|
||||
@@ -78,7 +78,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
EncodedJSValue run(JSC::JSGlobalObject* globalObject, ZigString* namespaceString, ZigString* path, ZigString* importer);
|
||||
EncodedJSValue run(JSC::JSGlobalObject* globalObject, BunString* namespaceString, BunString* path, BunString* importer);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
224
src/bun.js/bindings/BunString.cpp
Normal file
224
src/bun.js/bindings/BunString.cpp
Normal file
@@ -0,0 +1,224 @@
|
||||
#include "root.h"
|
||||
#include "headers-handwritten.h"
|
||||
#include "JavaScriptCore/JSCJSValueInlines.h"
|
||||
#include "helpers.h"
|
||||
#include "simdutf.h"
|
||||
#include "wtf/text/ExternalStringImpl.h"
|
||||
#include "GCDefferalContext.h"
|
||||
using namespace JSC;
|
||||
|
||||
extern "C" bool Bun__WTFStringImpl__hasPrefix(const WTF::StringImpl* impl, const char* bytes, size_t length)
|
||||
{
|
||||
return impl->startsWith(bytes, length);
|
||||
}
|
||||
|
||||
extern "C" void Bun__WTFStringImpl__deref(WTF::StringImpl* impl)
|
||||
{
|
||||
impl->deref();
|
||||
}
|
||||
extern "C" void Bun__WTFStringImpl__ref(WTF::StringImpl* impl)
|
||||
{
|
||||
impl->ref();
|
||||
}
|
||||
|
||||
extern "C" bool BunString__fromJS(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue encodedValue, BunString* bunString)
|
||||
{
|
||||
JSC::JSValue value = JSC::JSValue::decode(encodedValue);
|
||||
*bunString = Bun::toString(globalObject, value);
|
||||
return bunString->tag != BunStringTag::Dead;
|
||||
}
|
||||
|
||||
namespace Bun {
|
||||
JSC::JSValue toJS(JSC::JSGlobalObject* globalObject, BunString bunString)
|
||||
{
|
||||
if (bunString.tag == BunStringTag::Empty || bunString.tag == BunStringTag::Dead) {
|
||||
return JSValue(JSC::jsEmptyString(globalObject->vm()));
|
||||
}
|
||||
if (bunString.tag == BunStringTag::WTFStringImpl) {
|
||||
return JSValue(jsString(globalObject->vm(), String(bunString.impl.wtf)));
|
||||
}
|
||||
|
||||
if (bunString.tag == BunStringTag::StaticZigString) {
|
||||
return JSValue(jsString(globalObject->vm(), Zig::toStringStatic(bunString.impl.zig)));
|
||||
}
|
||||
|
||||
return JSValue(Zig::toJSStringGC(bunString.impl.zig, globalObject));
|
||||
}
|
||||
|
||||
WTF::String toWTFString(const BunString& bunString)
|
||||
{
|
||||
if (bunString.tag == BunStringTag::ZigString) {
|
||||
if (Zig::isTaggedUTF8Ptr(bunString.impl.zig.ptr)) {
|
||||
return Zig::toStringCopy(bunString.impl.zig);
|
||||
} else {
|
||||
return Zig::toString(bunString.impl.zig);
|
||||
}
|
||||
|
||||
} else if (bunString.tag == BunStringTag::StaticZigString) {
|
||||
return Zig::toStringStatic(bunString.impl.zig);
|
||||
}
|
||||
|
||||
if (bunString.tag == BunStringTag::WTFStringImpl) {
|
||||
return WTF::String(bunString.impl.wtf);
|
||||
}
|
||||
|
||||
return WTF::String();
|
||||
}
|
||||
|
||||
BunString fromJS(JSC::JSGlobalObject* globalObject, JSValue value)
|
||||
{
|
||||
JSC::JSString* str = value.toStringOrNull(globalObject);
|
||||
if (UNLIKELY(!str)) {
|
||||
return { BunStringTag::Dead };
|
||||
}
|
||||
|
||||
if (str->length() == 0) {
|
||||
return { BunStringTag::Empty };
|
||||
}
|
||||
|
||||
auto wtfString = str->value(globalObject);
|
||||
|
||||
return { BunStringTag::WTFStringImpl, { .wtf = wtfString.impl() } };
|
||||
}
|
||||
|
||||
BunString toString(JSC::JSGlobalObject* globalObject, JSValue value)
|
||||
{
|
||||
return fromJS(globalObject, value);
|
||||
}
|
||||
|
||||
BunString toString(WTF::String& wtfString)
|
||||
{
|
||||
if (wtfString.length() == 0)
|
||||
return { BunStringTag::Empty };
|
||||
|
||||
return { BunStringTag::WTFStringImpl, { .wtf = wtfString.impl() } };
|
||||
}
|
||||
BunString toString(const WTF::String& wtfString)
|
||||
{
|
||||
if (wtfString.length() == 0)
|
||||
return { BunStringTag::Empty };
|
||||
|
||||
return { BunStringTag::WTFStringImpl, { .wtf = wtfString.impl() } };
|
||||
}
|
||||
BunString toString(WTF::StringImpl* wtfString)
|
||||
{
|
||||
if (wtfString->length() == 0)
|
||||
return { BunStringTag::Empty };
|
||||
|
||||
return { BunStringTag::WTFStringImpl, { .wtf = wtfString } };
|
||||
}
|
||||
|
||||
BunString fromString(WTF::String& wtfString)
|
||||
{
|
||||
if (wtfString.length() == 0)
|
||||
return { BunStringTag::Empty };
|
||||
|
||||
return { BunStringTag::WTFStringImpl, { .wtf = wtfString.impl() } };
|
||||
}
|
||||
|
||||
BunString fromString(WTF::StringImpl* wtfString)
|
||||
{
|
||||
if (wtfString->length() == 0)
|
||||
return { BunStringTag::Empty };
|
||||
|
||||
return { BunStringTag::WTFStringImpl, { .wtf = wtfString } };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" JSC::EncodedJSValue BunString__toJS(JSC::JSGlobalObject* globalObject, BunString* bunString)
|
||||
{
|
||||
return JSValue::encode(Bun::toJS(globalObject, *bunString));
|
||||
}
|
||||
|
||||
extern "C" BunString BunString__fromUTF8(const char* bytes, size_t length)
|
||||
{
|
||||
if (simdutf::validate_utf8(bytes, length)) {
|
||||
size_t u16Length = simdutf::utf16_length_from_utf8(bytes, length);
|
||||
UChar* ptr;
|
||||
auto impl = WTF::StringImpl::createUninitialized(static_cast<unsigned int>(u16Length), ptr);
|
||||
RELEASE_ASSERT(simdutf::convert_utf8_to_utf16(bytes, length, ptr) == u16Length);
|
||||
impl->ref();
|
||||
return { BunStringTag::WTFStringImpl, { .wtf = &impl.leakRef() } };
|
||||
}
|
||||
|
||||
auto str = WTF::String::fromUTF8ReplacingInvalidSequences(reinterpret_cast<const LChar*>(bytes), length);
|
||||
str.impl()->ref();
|
||||
return Bun::fromString(str);
|
||||
}
|
||||
|
||||
extern "C" BunString BunString__fromLatin1(const char* bytes, size_t length)
|
||||
{
|
||||
return { BunStringTag::WTFStringImpl, { .wtf = &WTF::StringImpl::create(bytes, length).leakRef() } };
|
||||
}
|
||||
|
||||
extern "C" BunString BunString__fromBytes(const char* bytes, size_t length)
|
||||
{
|
||||
if (simdutf::validate_ascii(bytes, length)) {
|
||||
return BunString__fromLatin1(bytes, length);
|
||||
}
|
||||
|
||||
return BunString__fromUTF8(bytes, length);
|
||||
}
|
||||
|
||||
extern "C" BunString BunString__createExternal(const char* bytes, size_t length, bool isLatin1, void* ctx, void (*callback)(void* arg0, void* arg1, size_t arg2))
|
||||
{
|
||||
Ref<WTF::ExternalStringImpl> impl = isLatin1 ? WTF::ExternalStringImpl::create(reinterpret_cast<const LChar*>(bytes), length, ctx, callback) :
|
||||
|
||||
WTF::ExternalStringImpl::create(reinterpret_cast<const UChar*>(bytes), length, ctx, callback);
|
||||
|
||||
return { BunStringTag::WTFStringImpl, { .wtf = &impl.leakRef() } };
|
||||
}
|
||||
|
||||
extern "C" EncodedJSValue BunString__createArray(
|
||||
JSC::JSGlobalObject* globalObject,
|
||||
const BunString* ptr, size_t length)
|
||||
{
|
||||
if (length == 0)
|
||||
return JSValue::encode(JSC::constructEmptyArray(globalObject, nullptr));
|
||||
|
||||
auto& vm = globalObject->vm();
|
||||
auto throwScope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
// We must do this or Bun.gc(true) in a loop creating large arrays of strings will crash due to GC'ing.
|
||||
MarkedArgumentBuffer arguments;
|
||||
JSC::ObjectInitializationScope scope(vm);
|
||||
GCDeferralContext context(vm);
|
||||
|
||||
arguments.fill(length, [&](JSC::JSValue* value) {
|
||||
const BunString* end = ptr + length;
|
||||
while (ptr != end) {
|
||||
*value++ = Bun::toJS(globalObject, *ptr++);
|
||||
}
|
||||
});
|
||||
|
||||
if (JSC::JSArray* array = JSC::JSArray::tryCreateUninitializedRestricted(
|
||||
scope,
|
||||
globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
|
||||
length)) {
|
||||
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
array->initializeIndex(scope, i, arguments.at(i));
|
||||
}
|
||||
return JSValue::encode(array);
|
||||
}
|
||||
|
||||
JSC::throwOutOfMemoryError(globalObject, throwScope);
|
||||
RELEASE_AND_RETURN(throwScope, JSValue::encode(JSC::JSValue()));
|
||||
}
|
||||
|
||||
extern "C" void BunString__toWTFString(BunString* bunString)
|
||||
{
|
||||
if (bunString->tag == BunStringTag::ZigString) {
|
||||
if (Zig::isTaggedUTF8Ptr(bunString->impl.zig.ptr)) {
|
||||
bunString->impl.wtf = Zig::toStringCopy(bunString->impl.zig).impl();
|
||||
} else {
|
||||
bunString->impl.wtf = Zig::toString(bunString->impl.zig).impl();
|
||||
}
|
||||
|
||||
bunString->tag = BunStringTag::WTFStringImpl;
|
||||
} else if (bunString->tag == BunStringTag::StaticZigString) {
|
||||
bunString->impl.wtf = Zig::toStringStatic(bunString->impl.zig).impl();
|
||||
bunString->tag = BunStringTag::WTFStringImpl;
|
||||
}
|
||||
}
|
||||
@@ -86,6 +86,42 @@ void CallSite::visitChildrenImpl(JSCell* cell, Visitor& visitor)
|
||||
visitor.append(thisCallSite->m_sourceURL);
|
||||
}
|
||||
|
||||
void CallSite::formatAsString(JSC::VM& vm, JSC::JSGlobalObject* globalObject, WTF::StringBuilder &sb) {
|
||||
JSString* myTypeName = jsTypeStringForValue(globalObject, thisValue());
|
||||
JSString* myFunction = functionName().toString(globalObject);
|
||||
JSString* myFunctionName = functionName().toString(globalObject);
|
||||
JSString* mySourceURL = sourceURL().toString(globalObject);
|
||||
|
||||
JSString* myColumnNumber = columnNumber().toInt32(globalObject) != -1 ? columnNumber().toString(globalObject) : jsEmptyString(vm);
|
||||
JSString* myLineNumber = lineNumber().toInt32(globalObject) != -1 ? lineNumber().toString(globalObject) : jsEmptyString(vm);
|
||||
|
||||
bool myIsConstructor = isConstructor();
|
||||
|
||||
if (myFunctionName->length() > 0) {
|
||||
if (myIsConstructor) {
|
||||
sb.append("new "_s);
|
||||
} else {
|
||||
// TODO: print type or class name if available
|
||||
// sb.append(myTypeName->getString(globalObject));
|
||||
// sb.append(" "_s);
|
||||
}
|
||||
sb.append(myFunctionName->getString(globalObject));
|
||||
} else {
|
||||
sb.append("<anonymous>"_s);
|
||||
}
|
||||
sb.append(" ("_s);
|
||||
if (isNative()) {
|
||||
sb.append("native"_s);
|
||||
} else {
|
||||
sb.append(mySourceURL->getString(globalObject));
|
||||
sb.append(":"_s);
|
||||
sb.append(myLineNumber->getString(globalObject));
|
||||
sb.append(":"_s);
|
||||
sb.append(myColumnNumber->getString(globalObject));
|
||||
}
|
||||
sb.append(")"_s);
|
||||
}
|
||||
|
||||
DEFINE_VISIT_CHILDREN(CallSite);
|
||||
|
||||
}
|
||||
|
||||
@@ -77,6 +77,11 @@ public:
|
||||
bool isStrict() const { return m_flags & static_cast<unsigned int>(Flags::IsStrict); }
|
||||
bool isNative() const { return m_flags & static_cast<unsigned int>(Flags::IsNative); }
|
||||
|
||||
void setLineNumber(JSC::JSValue lineNumber) { m_lineNumber = lineNumber; }
|
||||
void setColumnNumber(JSC::JSValue columnNumber) { m_columnNumber = columnNumber; }
|
||||
|
||||
void formatAsString(JSC::VM& vm, JSC::JSGlobalObject* globalObject, WTF::StringBuilder &sb);
|
||||
|
||||
private:
|
||||
CallSite(JSC::VM& vm, JSC::Structure* structure)
|
||||
: Base(vm, structure)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user