mirror of
https://github.com/oven-sh/bun
synced 2026-02-03 07:28:53 +00:00
Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c68e26d8d | ||
|
|
0731dfa0a4 | ||
|
|
9e2ddb936e | ||
|
|
dacd00d708 | ||
|
|
a068e9c8db | ||
|
|
936f112b6a | ||
|
|
627de5b29d | ||
|
|
526f7d8541 | ||
|
|
df6cca0fc2 | ||
|
|
e1c00ebaaf | ||
|
|
6313655c8e | ||
|
|
f0ebdfff74 | ||
|
|
c4a2209841 | ||
|
|
cc6065583e | ||
|
|
87636ca02a | ||
|
|
40aa26ad7e | ||
|
|
1881c51509 | ||
|
|
1cddf16076 | ||
|
|
eb27f18c2e | ||
|
|
26f5869cdb | ||
|
|
5dc79f1924 | ||
|
|
2bcbafe7d3 | ||
|
|
f7f734788c | ||
|
|
2cd1d59387 | ||
|
|
b70210a005 | ||
|
|
b9c2309c8a | ||
|
|
43c4da8c9a | ||
|
|
8a48e8bb0b | ||
|
|
097ae4e982 | ||
|
|
213f5bef9d | ||
|
|
e115638cba | ||
|
|
6e57556fad | ||
|
|
339d2c7f19 | ||
|
|
d2bef4fbea | ||
|
|
19aa9d93de | ||
|
|
55eb4ffe8f | ||
|
|
a051a6f620 | ||
|
|
9c68abdb8d | ||
|
|
ad326b7734 | ||
|
|
aa08c35c06 | ||
|
|
20d42dfaa3 | ||
|
|
3556fa3b1e | ||
|
|
5e07fd4fbc | ||
|
|
c60385716b | ||
|
|
f3266ff436 | ||
|
|
b01764b31e | ||
|
|
851763174e | ||
|
|
8518fbb573 | ||
|
|
d86084dd8e | ||
|
|
52802a4c55 | ||
|
|
44e4d5852a | ||
|
|
3a45f2c71b | ||
|
|
9eeb7bdbff | ||
|
|
ed14b64e65 | ||
|
|
bca1bcf29c | ||
|
|
9027484ae1 | ||
|
|
91eacade97 | ||
|
|
6a02edef5d |
2
.github/ISSUE_TEMPLATE/2-bug-report.yml
vendored
2
.github/ISSUE_TEMPLATE/2-bug-report.yml
vendored
@@ -14,7 +14,7 @@ body:
|
||||
- type: input
|
||||
attributes:
|
||||
label: What version of Bun is running?
|
||||
description: Copy the output of `bun -v`
|
||||
description: Copy the output of `bun --revision`
|
||||
- type: input
|
||||
attributes:
|
||||
label: What platform is your computer?
|
||||
|
||||
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/2023-aug3-4/bun-webkit-linux-arm64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/bun-webkit-linux-arm64-lto.tar.gz"
|
||||
webkit_basename: "bun-webkit-linux-arm64-lto"
|
||||
build_machine_arch: aarch64
|
||||
|
||||
|
||||
4
.github/workflows/bun-linux-build.yml
vendored
4
.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/2023-aug3-4/bun-webkit-linux-amd64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-linux-amd64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/bun-webkit-linux-amd64-lto.tar.gz"
|
||||
webkit_basename: "bun-webkit-linux-amd64-lto"
|
||||
build_machine_arch: x86_64
|
||||
|
||||
|
||||
16
.github/workflows/bun-mac-aarch64.yml
vendored
16
.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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-arm64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/bun-webkit-macos-arm64-lto.tar.gz"
|
||||
runner: macos-arm64
|
||||
dependencies: true
|
||||
compile_obj: true
|
||||
@@ -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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-arm64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/bun-webkit-macos-arm64-lto.tar.gz"
|
||||
runner: macos-arm64
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
16
.github/workflows/bun-mac-x64-baseline.yml
vendored
16
.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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# runner: macos-arm64
|
||||
# dependencies: true
|
||||
# compile_obj: true
|
||||
@@ -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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# runner: macos-arm64
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
16
.github/workflows/bun-mac-x64.yml
vendored
16
.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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-arm64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/bun-webkit-macos-arm64-lto.tar.gz"
|
||||
# runner: macos-arm64
|
||||
# dependencies: true
|
||||
# compile_obj: true
|
||||
@@ -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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-amd64-lto.tar.gz"
|
||||
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/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/2023-aug3-4/bun-webkit-macos-arm64-lto.tar.gz"
|
||||
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/2023-aug3-5/bun-webkit-macos-arm64-lto.tar.gz"
|
||||
# runner: macos-arm64
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
2
.github/workflows/zig-fmt.yml
vendored
2
.github/workflows/zig-fmt.yml
vendored
@@ -1,7 +1,7 @@
|
||||
name: zig-fmt
|
||||
|
||||
env:
|
||||
ZIG_VERSION: 0.11.0-dev.4006+bf827d0b5
|
||||
ZIG_VERSION: 0.12.0-dev.163+6780a6bbf
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -130,3 +130,6 @@ src/js/out/tmp
|
||||
src/js/out/DebugPath.h
|
||||
|
||||
make-dev-stats.csv
|
||||
|
||||
.uuid
|
||||
tsconfig.tsbuildinfo
|
||||
@@ -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=2023-aug3-4
|
||||
ARG WEBKIT_TAG=2023-aug3-5
|
||||
ARG ZIG_TAG=jul1
|
||||
ARG ZIG_VERSION="0.11.0-dev.4006+bf827d0b5"
|
||||
ARG ZIG_VERSION="0.12.0-dev.163+6780a6bbf"
|
||||
ARG WEBKIT_BASENAME="bun-webkit-linux-$BUILDARCH"
|
||||
|
||||
ARG ZIG_FOLDERNAME=zig-linux-${BUILD_MACHINE_ARCH}-${ZIG_VERSION}
|
||||
@@ -20,7 +20,7 @@ ARG ZIG_FILENAME=${ZIG_FOLDERNAME}.tar.xz
|
||||
ARG WEBKIT_URL="https://github.com/oven-sh/WebKit/releases/download/$WEBKIT_TAG/${WEBKIT_BASENAME}.tar.gz"
|
||||
ARG ZIG_URL="https://ziglang.org/builds/${ZIG_FILENAME}"
|
||||
ARG GIT_SHA=""
|
||||
ARG BUN_BASE_VERSION=0.7
|
||||
ARG BUN_BASE_VERSION=0.8
|
||||
|
||||
FROM bitnami/minideb:bullseye as bun-base
|
||||
|
||||
|
||||
2
Makefile
2
Makefile
@@ -38,7 +38,7 @@ NATIVE_OR_OLD_MARCH = -march=nehalem
|
||||
endif
|
||||
|
||||
MIN_MACOS_VERSION ?= $(DEFAULT_MIN_MACOS_VERSION)
|
||||
BUN_BASE_VERSION = 0.7
|
||||
BUN_BASE_VERSION = 0.8
|
||||
|
||||
CI ?= false
|
||||
|
||||
|
||||
@@ -123,7 +123,6 @@ bun upgrade --canary
|
||||
- [HTMLRewriter](https://bun.sh/docs/api/html-rewriter)
|
||||
- [Testing](https://bun.sh/docs/api/test)
|
||||
- [Utils](https://bun.sh/docs/api/utils)
|
||||
- [DNS](https://bun.sh/docs/api/dns)
|
||||
- [Node-API](https://bun.sh/docs/api/node-api)
|
||||
|
||||
## Contributing
|
||||
|
||||
98
build.zig
98
build.zig
@@ -1,4 +1,5 @@
|
||||
const std = @import("std");
|
||||
const pathRel = std.fs.path.relative;
|
||||
const Wyhash = @import("./src/wyhash.zig").Wyhash;
|
||||
var is_debug_build = false;
|
||||
fn moduleSource(comptime out: []const u8) FileSource {
|
||||
@@ -96,6 +97,7 @@ const BunBuildOptions = struct {
|
||||
}
|
||||
};
|
||||
|
||||
// relative to the prefix
|
||||
var output_dir: []const u8 = "";
|
||||
fn panicIfNotFound(comptime filepath: []const u8) []const u8 {
|
||||
var file = std.fs.cwd().openFile(filepath, .{ .optimize = .read_only }) catch |err| {
|
||||
@@ -172,13 +174,12 @@ pub fn build(b: *Build) !void {
|
||||
var triplet = triplet_buf[0 .. osname.len + cpuArchName.len + 1];
|
||||
|
||||
if (b.option([]const u8, "output-dir", "target to install to") orelse std.os.getenv("OUTPUT_DIR")) |output_dir_| {
|
||||
output_dir = b.pathFromRoot(output_dir_);
|
||||
output_dir = try pathRel(b.allocator, b.install_prefix, output_dir_);
|
||||
} else {
|
||||
const output_dir_base = try std.fmt.bufPrint(&output_dir_buf, "{s}{s}", .{ bin_label, triplet });
|
||||
output_dir = b.pathFromRoot(output_dir_base);
|
||||
output_dir = try pathRel(b.allocator, b.install_prefix, output_dir_base);
|
||||
}
|
||||
|
||||
std.fs.cwd().makePath(output_dir) catch {};
|
||||
is_debug_build = optimize == OptimizeMode.Debug;
|
||||
const bun_executable_name = if (optimize == std.builtin.OptimizeMode.Debug) "bun-debug" else "bun";
|
||||
const root_src = if (target.getOsTag() == std.Target.Os.Tag.freestanding)
|
||||
@@ -186,12 +187,12 @@ pub fn build(b: *Build) !void {
|
||||
else
|
||||
"root.zig";
|
||||
|
||||
const min_version: std.SemanticVersion = if (target.getOsTag() != .freestanding and !target.isWindows())
|
||||
const min_version: std.SemanticVersion = if (target.getOsTag() != .freestanding)
|
||||
target.getOsVersionMin().semver
|
||||
else
|
||||
.{ .major = 0, .minor = 0, .patch = 0 };
|
||||
|
||||
const max_version: std.SemanticVersion = if (target.getOsTag() != .freestanding and !target.isWindows())
|
||||
const max_version: std.SemanticVersion = if (target.getOsTag() != .freestanding)
|
||||
target.getOsVersionMax().semver
|
||||
else
|
||||
.{ .major = 0, .minor = 0, .patch = 0 };
|
||||
@@ -202,6 +203,7 @@ pub fn build(b: *Build) !void {
|
||||
.root_source_file = FileSource.relative(root_src),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.main_pkg_path = .{ .cwd_relative = b.pathFromRoot(".") },
|
||||
});
|
||||
|
||||
var default_build_options: BunBuildOptions = brk: {
|
||||
@@ -239,8 +241,6 @@ pub fn build(b: *Build) !void {
|
||||
};
|
||||
|
||||
{
|
||||
obj.setMainPkgPath(b.pathFromRoot("."));
|
||||
|
||||
try addInternalPackages(
|
||||
b,
|
||||
obj,
|
||||
@@ -271,9 +271,15 @@ pub fn build(b: *Build) !void {
|
||||
std.io.getStdErr().writer().print("Output: {s}/{s}\n\n", .{ output_dir, bun_executable_name }) catch unreachable;
|
||||
|
||||
defer obj_step.dependOn(&obj.step);
|
||||
obj.emit_bin = .{
|
||||
.emit_to = b.fmt("{s}/{s}.o", .{ output_dir, bun_executable_name }),
|
||||
};
|
||||
|
||||
var install = b.addInstallFileWithDir(
|
||||
obj.getEmittedBin(),
|
||||
.{ .custom = output_dir },
|
||||
b.fmt("{s}.o", .{bun_executable_name}),
|
||||
);
|
||||
install.step.dependOn(&obj.step);
|
||||
obj_step.dependOn(&install.step);
|
||||
|
||||
var actual_build_options = default_build_options;
|
||||
if (b.option(bool, "generate-sizes", "Generate sizes of things") orelse false) {
|
||||
actual_build_options.sizegen = true;
|
||||
@@ -290,7 +296,8 @@ pub fn build(b: *Build) !void {
|
||||
if (target.getCpuArch().isX86()) obj.disable_stack_probing = true;
|
||||
|
||||
if (b.option(bool, "for-editor", "Do not emit bin, just check for errors") orelse false) {
|
||||
obj.emit_bin = .no_emit;
|
||||
// obj.emit_bin = .no_emit;
|
||||
obj.generated_bin = null;
|
||||
}
|
||||
|
||||
if (target.getOsTag() == .linux) {
|
||||
@@ -308,9 +315,10 @@ pub fn build(b: *Build) !void {
|
||||
.root_source_file = FileSource.relative("src/bindgen.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.main_pkg_path = obj.main_pkg_path,
|
||||
});
|
||||
defer headers_step.dependOn(&headers_obj.step);
|
||||
try configureObjectStep(b, headers_obj, @TypeOf(target), target, obj.main_pkg_path.?);
|
||||
try configureObjectStep(b, headers_obj, headers_step, @TypeOf(target), target);
|
||||
var headers_build_options = default_build_options;
|
||||
headers_build_options.bindgen = true;
|
||||
headers_obj.addOptions("build_options", default_build_options.step(b));
|
||||
@@ -318,21 +326,22 @@ pub fn build(b: *Build) !void {
|
||||
}
|
||||
|
||||
{
|
||||
const wasm = b.step("bun-wasm", "Build WASM");
|
||||
var wasm_step = b.addStaticLibrary(.{
|
||||
const wasm_step = b.step("bun-wasm", "Build WASM");
|
||||
var wasm = b.addStaticLibrary(.{
|
||||
.name = "bun-wasm",
|
||||
.root_source_file = FileSource.relative("root_wasm.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.main_pkg_path = obj.main_pkg_path,
|
||||
});
|
||||
defer wasm.dependOn(&wasm_step.step);
|
||||
wasm_step.strip = false;
|
||||
defer wasm_step.dependOn(&wasm.step);
|
||||
wasm.strip = false;
|
||||
// wasm_step.link_function_sections = true;
|
||||
// wasm_step.link_emit_relocs = true;
|
||||
// wasm_step.single_threaded = true;
|
||||
try configureObjectStep(b, wasm_step, @TypeOf(target), target, obj.main_pkg_path.?);
|
||||
try configureObjectStep(b, wasm, wasm_step, @TypeOf(target), target);
|
||||
var build_opts = default_build_options;
|
||||
wasm_step.addOptions("build_options", build_opts.step(b));
|
||||
wasm.addOptions("build_options", build_opts.step(b));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -342,9 +351,10 @@ pub fn build(b: *Build) !void {
|
||||
.root_source_file = FileSource.relative("misctools/http_bench.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.main_pkg_path = obj.main_pkg_path,
|
||||
});
|
||||
defer headers_step.dependOn(&headers_obj.step);
|
||||
try configureObjectStep(b, headers_obj, @TypeOf(target), target, obj.main_pkg_path.?);
|
||||
try configureObjectStep(b, headers_obj, headers_step, @TypeOf(target), target);
|
||||
headers_obj.addOptions("build_options", default_build_options.step(b));
|
||||
}
|
||||
|
||||
@@ -355,9 +365,10 @@ pub fn build(b: *Build) !void {
|
||||
.root_source_file = FileSource.relative("misctools/machbench.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.main_pkg_path = obj.main_pkg_path,
|
||||
});
|
||||
defer headers_step.dependOn(&headers_obj.step);
|
||||
try configureObjectStep(b, headers_obj, @TypeOf(target), target, obj.main_pkg_path.?);
|
||||
try configureObjectStep(b, headers_obj, headers_step, @TypeOf(target), target);
|
||||
headers_obj.addOptions("build_options", default_build_options.step(b));
|
||||
}
|
||||
|
||||
@@ -368,9 +379,10 @@ pub fn build(b: *Build) !void {
|
||||
.root_source_file = FileSource.relative("misctools/fetch.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.main_pkg_path = obj.main_pkg_path,
|
||||
});
|
||||
defer headers_step.dependOn(&headers_obj.step);
|
||||
try configureObjectStep(b, headers_obj, @TypeOf(target), target, obj.main_pkg_path.?);
|
||||
try configureObjectStep(b, headers_obj, headers_step, @TypeOf(target), target);
|
||||
headers_obj.addOptions("build_options", default_build_options.step(b));
|
||||
}
|
||||
|
||||
@@ -381,9 +393,10 @@ pub fn build(b: *Build) !void {
|
||||
.root_source_file = FileSource.relative("src/bench/string-handling.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.main_pkg_path = obj.main_pkg_path,
|
||||
});
|
||||
defer headers_step.dependOn(&headers_obj.step);
|
||||
try configureObjectStep(b, headers_obj, @TypeOf(target), target, obj.main_pkg_path.?);
|
||||
try configureObjectStep(b, headers_obj, headers_step, @TypeOf(target), target);
|
||||
headers_obj.addOptions("build_options", default_build_options.step(b));
|
||||
}
|
||||
|
||||
@@ -394,9 +407,10 @@ pub fn build(b: *Build) !void {
|
||||
.root_source_file = FileSource.relative("src/sha.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.main_pkg_path = obj.main_pkg_path,
|
||||
});
|
||||
defer headers_step.dependOn(&headers_obj.step);
|
||||
try configureObjectStep(b, headers_obj, @TypeOf(target), target, obj.main_pkg_path.?);
|
||||
try configureObjectStep(b, headers_obj, headers_step, @TypeOf(target), target);
|
||||
headers_obj.addOptions("build_options", default_build_options.step(b));
|
||||
}
|
||||
|
||||
@@ -407,9 +421,10 @@ pub fn build(b: *Build) !void {
|
||||
.root_source_file = FileSource.relative("src/sourcemap/vlq_bench.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.main_pkg_path = obj.main_pkg_path,
|
||||
});
|
||||
defer headers_step.dependOn(&headers_obj.step);
|
||||
try configureObjectStep(b, headers_obj, @TypeOf(target), target, obj.main_pkg_path.?);
|
||||
try configureObjectStep(b, headers_obj, headers_step, @TypeOf(target), target);
|
||||
headers_obj.addOptions("build_options", default_build_options.step(b));
|
||||
}
|
||||
|
||||
@@ -420,9 +435,10 @@ pub fn build(b: *Build) !void {
|
||||
.root_source_file = FileSource.relative("misctools/tgz.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.main_pkg_path = obj.main_pkg_path,
|
||||
});
|
||||
defer headers_step.dependOn(&headers_obj.step);
|
||||
try configureObjectStep(b, headers_obj, @TypeOf(target), target, obj.main_pkg_path.?);
|
||||
try configureObjectStep(b, headers_obj, headers_step, @TypeOf(target), target);
|
||||
headers_obj.addOptions("build_options", default_build_options.step(b));
|
||||
}
|
||||
|
||||
@@ -436,16 +452,23 @@ pub fn build(b: *Build) !void {
|
||||
var headers_obj: *CompileStep = b.addTest(.{
|
||||
.root_source_file = FileSource.relative(test_file orelse "src/main.zig"),
|
||||
.target = target,
|
||||
.main_pkg_path = obj.main_pkg_path,
|
||||
});
|
||||
headers_obj.filter = test_filter;
|
||||
if (test_bin_) |test_bin| {
|
||||
headers_obj.name = std.fs.path.basename(test_bin);
|
||||
if (std.fs.path.dirname(test_bin)) |dir| headers_obj.emit_bin = .{
|
||||
.emit_to = b.fmt("{s}/{s}", .{ dir, headers_obj.name }),
|
||||
};
|
||||
if (std.fs.path.dirname(test_bin)) |dir| {
|
||||
var install = b.addInstallFileWithDir(
|
||||
headers_obj.getEmittedBin(),
|
||||
.{ .custom = try std.fs.path.relative(b.allocator, output_dir, dir) },
|
||||
headers_obj.name,
|
||||
);
|
||||
install.step.dependOn(&headers_obj.step);
|
||||
headers_step.dependOn(&install.step);
|
||||
}
|
||||
}
|
||||
|
||||
try configureObjectStep(b, headers_obj, @TypeOf(target), target, obj.main_pkg_path.?);
|
||||
try configureObjectStep(b, headers_obj, headers_step, @TypeOf(target), target);
|
||||
|
||||
headers_step.dependOn(&headers_obj.step);
|
||||
headers_obj.addOptions("build_options", default_build_options.step(b));
|
||||
@@ -456,9 +479,7 @@ pub fn build(b: *Build) !void {
|
||||
|
||||
pub var original_make_fn: ?*const fn (step: *std.build.Step) anyerror!void = null;
|
||||
|
||||
pub fn configureObjectStep(b: *std.build.Builder, obj: *CompileStep, comptime Target: type, target: Target, main_pkg_path: []const u8) !void {
|
||||
obj.setMainPkgPath(main_pkg_path);
|
||||
|
||||
pub fn configureObjectStep(b: *std.build.Builder, obj: *CompileStep, obj_step: *std.build.Step, comptime Target: type, target: Target) !void {
|
||||
// obj.setTarget(target);
|
||||
try addInternalPackages(b, obj, std.heap.page_allocator, b.zig_exe, target);
|
||||
|
||||
@@ -466,11 +487,16 @@ pub fn configureObjectStep(b: *std.build.Builder, obj: *CompileStep, comptime Ta
|
||||
|
||||
// obj.setBuildMode(optimize);
|
||||
obj.bundle_compiler_rt = false;
|
||||
if (obj.emit_bin == .default)
|
||||
obj.emit_bin = .{
|
||||
.emit_to = b.fmt("{s}/{s}.o", .{ output_dir, obj.name }),
|
||||
};
|
||||
if (obj.emit_directory == null) {
|
||||
var install = b.addInstallFileWithDir(
|
||||
obj.getEmittedBin(),
|
||||
.{ .custom = output_dir },
|
||||
b.fmt("{s}.o", .{obj.name}),
|
||||
);
|
||||
|
||||
install.step.dependOn(&obj.step);
|
||||
obj_step.dependOn(&install.step);
|
||||
}
|
||||
if (target.getOsTag() != .freestanding) obj.linkLibC();
|
||||
if (target.getOsTag() != .freestanding) obj.bundle_compiler_rt = false;
|
||||
|
||||
|
||||
@@ -428,6 +428,21 @@ const str = Bun.inspect(arr);
|
||||
// => "Uint8Array(3) [ 1, 2, 3 ]"
|
||||
```
|
||||
|
||||
## `Bun.inspect.custom`
|
||||
|
||||
This is the symbol that Bun uses to implement `Bun.inspect`. You can override this to customize how your objects are printed. It is identical to `util.inspect.custom` in Node.js.
|
||||
|
||||
```ts
|
||||
class Foo {
|
||||
[Bun.inspect.custom]() {
|
||||
return "foo";
|
||||
}
|
||||
}
|
||||
|
||||
const foo = new Foo();
|
||||
console.log(foo); // => "foo"
|
||||
```
|
||||
|
||||
## `Bun.nanoseconds()`
|
||||
|
||||
Returns the number of nanoseconds since the current `bun` process started, as a `number`. Useful for high-precision timing and benchmarking.
|
||||
|
||||
@@ -30,14 +30,50 @@ The runner recursively searches the working directory for files that match the f
|
||||
- `*.spec.{js|jsx|ts|tsx}`
|
||||
- `*_spec.{js|jsx|ts|tsx}`
|
||||
|
||||
You can filter the set of tests to run by passing additional positional arguments to `bun test`. Any file in the directory with an _absolute path_ that contains one of the filters will run. Commonly, these filters will be file or directory names; glob patterns are not yet supported.
|
||||
You can filter the set of _test files_ to run by passing additional positional arguments to `bun test`. Any test file with a path that matches one of the filters will run. Commonly, these filters will be file or directory names; glob patterns are not yet supported.
|
||||
|
||||
```bash
|
||||
$ bun test <filter> <filter> ...
|
||||
```
|
||||
|
||||
To filter by _test name_, use the `-t`/`--test-name-pattern` flag.
|
||||
|
||||
```sh
|
||||
# run all tests or test suites with "addition" in the name
|
||||
$ bun test --test-name-pattern addition
|
||||
```
|
||||
|
||||
The test runner runs all tests in a single process. It loads all `--preload` scripts (see [Lifecycle](/docs/test/lifecycle) for details), then runs all tests. If a test fails, the test runner will exit with a non-zero exit code.
|
||||
|
||||
## Timeouts
|
||||
|
||||
Use the `--timeout` flag to specify a _per-test_ timeout in milliseconds. If a test times out, it will be marked as failed. The default value is `5000`.
|
||||
|
||||
```bash
|
||||
# default value is 5000
|
||||
$ bun test --timeout 20
|
||||
```
|
||||
|
||||
## Rerun tests
|
||||
|
||||
Use the `--rerun-each` flag to run each test multiple times. This is useful for detecting flaky or non-deterministic test failures.
|
||||
|
||||
```sh
|
||||
$ bun test --rerun-each 100
|
||||
```
|
||||
|
||||
## Bail out with `--bail`
|
||||
|
||||
Use the `--bail` flag to abort the test run early after a pre-determined number of test failures. By default Bun will run all tests and report all failures, but sometimes in CI environments it's preferable to terminate earlier to reduce CPU usage.
|
||||
|
||||
```sh
|
||||
# bail after 1 failure
|
||||
$ bun test --bail
|
||||
|
||||
# bail after 10 failure
|
||||
$ bun test --bail 10
|
||||
```
|
||||
|
||||
## Watch mode
|
||||
|
||||
Similar to `bun run`, you can pass the `--watch` flag to `bun test` to watch for changes and re-run tests.
|
||||
|
||||
65
docs/guides/ecosystem/nuxt.md
Normal file
65
docs/guides/ecosystem/nuxt.md
Normal file
@@ -0,0 +1,65 @@
|
||||
---
|
||||
name: Build an app with Nuxt and Bun
|
||||
---
|
||||
|
||||
Bun supports [Nuxt](https://nuxt.com) out of the box. Initialize a Nuxt app with official `nuxi` CLI.
|
||||
|
||||
```sh
|
||||
$ bunx nuxi init my-nuxt-app
|
||||
Nuxi 3.6.5
|
||||
✨ Nuxt project is created with v3 template. Next steps:
|
||||
› cd my-nuxt-app
|
||||
› Install dependencies with npm install or yarn install or pnpm install
|
||||
› Start development server with npm run dev or yarn dev or pnpm run dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Then move into the project directory and install dependencies.
|
||||
|
||||
```sh
|
||||
$ cd my-app
|
||||
$ bun install
|
||||
bun install v0.8.0
|
||||
+ @nuxt/devtools@0.8.0
|
||||
+ @types/node@18.17.6
|
||||
+ nuxt@3.6.5
|
||||
Nuxi 3.6.5
|
||||
✔ Types generated in .nuxt
|
||||
|
||||
776 packages installed [1.72s]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
To start the dev server, run `bun run dev` from the project root. This will execute the `nuxt dev` command (as defined in the `"dev"` script in `package.json`).
|
||||
|
||||
{% callout %}
|
||||
The `nuxt` CLI uses Node.js by default; passing the `--bun` flag forces the dev server to use the Bun runtime instead.
|
||||
{% /callout %}
|
||||
|
||||
```
|
||||
$ bun --bun run dev
|
||||
$ nuxt dev
|
||||
Nuxi 3.6.5
|
||||
Nuxt 3.6.5 with Nitro 2.5.2
|
||||
> Local: http://localhost:3000/
|
||||
> Network: http://192.168.0.21:3000/
|
||||
> Network: http://[fd8a:d31d:481c:4883:1c64:3d90:9f83:d8a2]:3000/
|
||||
|
||||
✔ Nuxt DevTools is enabled v0.8.0 (experimental)
|
||||
ℹ Vite client warmed up in 547ms
|
||||
✔ Nitro built in 244 ms
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Once the dev server spins up, open [http://localhost:3000](http://localhost:3000) to see the app. The app will render Nuxt's built-in `WelcomePage` template component.
|
||||
|
||||
To start developing your app, replace `<WelcomePage />` in `app.vue` with your own UI.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/2c683ecc-3298-4bb0-b8c0-cf4cfaea1daa" caption="Demo Nuxt app running on localhost" /%}
|
||||
|
||||
---
|
||||
|
||||
Refer to the [Nuxt website](https://nuxt.com/docs) for complete documentation.
|
||||
82
docs/guides/runtime/web-debugger.md
Normal file
82
docs/guides/runtime/web-debugger.md
Normal file
@@ -0,0 +1,82 @@
|
||||
---
|
||||
name: Debugging Bun with the web debugger
|
||||
---
|
||||
|
||||
Bun speaks the [WebKit Inspector Protocol](https://github.com/oven-sh/bun/blob/main/packages/bun-vscode/types/jsc.d.ts). To enable debugging when running code with Bun, use the `--inspect` flag. For demonstration purposes, consider the following simple web server.
|
||||
|
||||
```ts#server.ts
|
||||
Bun.serve({
|
||||
fetch(req){
|
||||
console.log(req.url);
|
||||
return new Response("Hello, world!");
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Let's run this file with the `--inspect` flag.
|
||||
|
||||
This automatically starts a WebSocket server on an available port that can be used to introspect the running Bun process. Various debugging tools can connect to this server to provide an interactive debugging experience.
|
||||
|
||||
Bun hosts a web-based debugger at [debug.bun.sh](https://debug.bun.sh). It is a modified version of WebKit's [Web Inspector Interface](https://webkit.org/web-inspector/web-inspector-interface/), which will look familiar to Safari users.
|
||||
|
||||
```sh
|
||||
$ bun --inspect server.ts
|
||||
------------------ Bun Inspector ------------------
|
||||
Listening at:
|
||||
ws://localhost:6499/0tqxs9exrgrm
|
||||
|
||||
Inspect in browser:
|
||||
https://debug.bun.sh/#localhost:6499/0tqxs9exrgrm
|
||||
------------------ Bun Inspector ------------------
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Open the provided `debug.bun.sh` URL in your browser to start a debugging session. From this interface, you'll be able to view the source code of the running file, view and set breakpoints, and execute code with the built-in console.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/e6a976a8-80cc-4394-8925-539025cc025d" alt="Screenshot of Bun debugger, Console tab" /%}
|
||||
|
||||
---
|
||||
|
||||
Let's set a breakpoint. Navigate to the Sources tab; you should see the code from earlier. Click on the line number `3` to set a breakpoint on our `console.log(req.url)` statement.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/3b69c7e9-25ff-4f9d-acc4-caa736862935" alt="screenshot of Bun debugger" /%}
|
||||
|
||||
---
|
||||
|
||||
Then visit [`http://localhost:3000`](http://localhost:3000) in your web browser. This will send an HTTP request to our `localhost` web server. It will seem like the page isn't loading. Why? Because the program has paused execution at the breakpoint we set earlier.
|
||||
|
||||
Note how the UI has changed.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/8b565e58-5445-4061-9bc4-f41090dfe769" alt="screenshot of Bun debugger" /%}
|
||||
|
||||
---
|
||||
|
||||
At this point there's a lot we can do to introspect the current execution environment. We can use the console at the bottom to run arbitrary code in the context of the program, with full access to the variables in scope at our breakpoint.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/f4312b76-48ba-4a7d-b3b6-6205968ac681" /%}
|
||||
|
||||
---
|
||||
|
||||
On the right side of the Sources pane, we can see all local variables currently in scope, and drill down to see their properties and methods. Here, we're inspecting the `req` variable.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/63d7f843-5180-489c-aa94-87c486e68646" /%}
|
||||
|
||||
---
|
||||
|
||||
In the upper left of the Sources pane, we can control the execution of the program.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/41b76deb-7371-4461-9d5d-81b5a6d2f7a4" /%}
|
||||
|
||||
---
|
||||
|
||||
Here's a cheat sheet explaining the functions of the control flow buttons.
|
||||
|
||||
- _Continue script execution_ — continue running the program until the next breakpoint or exception.
|
||||
- _Step over_ — The program will continue to the next line.
|
||||
- _Step into_ — If the current statement contains a function call, the debugger will "step into" the called function.
|
||||
- _Step out_ — If the current statement is a function call, the debugger will finish executing the call, then "step out" of the function to the location where it was called.
|
||||
|
||||
{% image src="https://github-production-user-asset-6210df.s3.amazonaws.com/3084745/261510346-6a94441c-75d3-413a-99a7-efa62365f83d.png" /%}
|
||||
23
docs/guides/util/detect-bun.md
Normal file
23
docs/guides/util/detect-bun.md
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: Detect when code is executed with Bun
|
||||
---
|
||||
|
||||
The recommended way to conditionally detect when code is being executed with `bun` is to check for the existence of the `Bun` global.
|
||||
|
||||
This is similar to how you'd check for the existence of the `window` variable to detect when code is being executed in a browser.
|
||||
|
||||
```ts
|
||||
if (typeof Bun !== "undefined") {
|
||||
// this code will only run when the file is run with Bun
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
In TypeScript environments, the previous approach will result in a type error unless `bun-types` is globally installed. To avoid this, you can check `process.versions` instead.
|
||||
|
||||
```ts
|
||||
if (process.versions.bun) {
|
||||
// this code will only run when the file is run with Bun
|
||||
}
|
||||
```
|
||||
@@ -8,7 +8,7 @@ The `Bun.password.hash()` function provides a fast, built-in mechanism for secur
|
||||
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
|
||||
// => $argon2id$v=19$m=65536,t=2,p=1$tFq+9AVr1bfPxQdh6E8DQRhEXg/M/...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -132,6 +132,9 @@ export default {
|
||||
page("runtime/configuration", "Configuration", {
|
||||
description: `Bun's runtime is configurable with environment variables and the bunfig.toml config file.`,
|
||||
}),
|
||||
page("runtime/debugger", "Debugger", {
|
||||
description: `Debug your code with Bun's web-based debugger or VS Code extension`,
|
||||
}),
|
||||
page("runtime/framework", "Framework API", {
|
||||
disabled: true,
|
||||
description:
|
||||
@@ -188,13 +191,13 @@ export default {
|
||||
page("cli/test", "`bun test`", {
|
||||
description: "Bun's test runner uses Jest-compatible syntax but runs 100x faster.",
|
||||
}),
|
||||
page("test/hot", "Watch mode", {
|
||||
description: "Reload your tests automatically on change.",
|
||||
}),
|
||||
page("test/writing", "Writing tests", {
|
||||
description:
|
||||
"Write your tests using Jest-like expect matchers, plus setup/teardown hooks, snapshot testing, and more",
|
||||
}),
|
||||
page("test/hot", "Watch mode", {
|
||||
description: "Reload your tests automatically on change.",
|
||||
}),
|
||||
page("test/lifecycle", "Lifecycle hooks", {
|
||||
description: "Add lifecycle hooks to your tests that run before/after each test or test run",
|
||||
}),
|
||||
|
||||
@@ -112,7 +112,7 @@ Zig can be installed either with our npm package [`@oven/zig`](https://www.npmjs
|
||||
|
||||
```bash
|
||||
$ bun install -g @oven/zig
|
||||
$ zigup 0.11.0-dev.4006+bf827d0b5
|
||||
$ zigup 0.12.0-dev.163+6780a6bbf
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
|
||||
90
docs/runtime/debugger.md
Normal file
90
docs/runtime/debugger.md
Normal file
@@ -0,0 +1,90 @@
|
||||
---
|
||||
name: Debugger
|
||||
---
|
||||
|
||||
Bun speaks the [WebKit Inspector Protocol](https://github.com/oven-sh/bun/blob/main/packages/bun-vscode/types/jsc.d.ts). For demonstration purposes, consider the following simple web server.
|
||||
|
||||
```ts#server.ts
|
||||
Bun.serve({
|
||||
fetch(req){
|
||||
console.log(req.url);
|
||||
return new Response("Hello, world!");
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### `--inspect`
|
||||
|
||||
To enable debugging when running code with Bun, use the `--inspect` flag. This automatically starts a WebSocket server on an available port that can be used to introspect the running Bun process.
|
||||
|
||||
```sh
|
||||
$ bun --inspect server.ts
|
||||
------------------ Bun Inspector ------------------
|
||||
Listening at:
|
||||
ws://localhost:6499/0tqxs9exrgrm
|
||||
|
||||
Inspect in browser:
|
||||
https://debug.bun.sh/#localhost:6499/0tqxs9exrgrm
|
||||
------------------ Bun Inspector ------------------
|
||||
```
|
||||
|
||||
### `--inspect-brk`
|
||||
|
||||
The `--inspect-brk` flag behaves identically to `--inspect`, except it automatically injects a breakpoint at the first line of the executed script. This is useful for debugging scripts that run quickly and exit immediately.
|
||||
|
||||
### `--inspect-wait`
|
||||
|
||||
The `--inspect-wait` flag behaves identically to `--inspect`, except the code will not execute until a debugger has attached to the running process.
|
||||
|
||||
### Setting a port or URL for the debugger
|
||||
|
||||
Regardless of which flag you use, you can optionally specify a port number, URL prefix, or both.
|
||||
|
||||
```sh
|
||||
$ bun --inspect=4000 server.ts
|
||||
$ bun --inspect=localhost:4000 server.ts
|
||||
$ bun --inspect=localhost:4000/prefix server.ts
|
||||
```
|
||||
|
||||
## Debuggers
|
||||
|
||||
Various debugging tools can connect to this server to provide an interactive debugging experience. Bun hosts a web-based debugger at [debug.bun.sh](https://debug.bun.sh). It is a modified version of WebKit's [Web Inspector Interface](https://webkit.org/web-inspector/web-inspector-interface/), which will look familiar to Safari users.
|
||||
|
||||
### `debug.bun.sh`
|
||||
|
||||
Bun hosts a web-based debugger at [debug.bun.sh](https://debug.bun.sh). It is a modified version of WebKit's [Web Inspector Interface](https://webkit.org/web-inspector/web-inspector-interface/), which will look familiar to Safari users.
|
||||
|
||||
Open the provided `debug.bun.sh` URL in your browser to start a debugging session. From this interface, you'll be able to view the source code of the running file, view and set breakpoints, and execute code with the built-in console.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/e6a976a8-80cc-4394-8925-539025cc025d" alt="Screenshot of Bun debugger, Console tab" /%}
|
||||
|
||||
Let's set a breakpoint. Navigate to the Sources tab; you should see the code from earlier. Click on the line number `3` to set a breakpoint on our `console.log(req.url)` statement.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/3b69c7e9-25ff-4f9d-acc4-caa736862935" alt="screenshot of Bun debugger" /%}
|
||||
|
||||
Then visit [`http://localhost:3000`](http://localhost:3000) in your web browser. This will send an HTTP request to our `localhost` web server. It will seem like the page isn't loading. Why? Because the program has paused execution at the breakpoint we set earlier.
|
||||
|
||||
Note how the UI has changed.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/8b565e58-5445-4061-9bc4-f41090dfe769" alt="screenshot of Bun debugger" /%}
|
||||
|
||||
At this point there's a lot we can do to introspect the current execution environment. We can use the console at the bottom to run arbitrary code in the context of the program, with full access to the variables in scope at our breakpoint.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/f4312b76-48ba-4a7d-b3b6-6205968ac681" /%}
|
||||
|
||||
On the right side of the Sources pane, we can see all local variables currently in scope, and drill down to see their properties and methods. Here, we're inspecting the `req` variable.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/63d7f843-5180-489c-aa94-87c486e68646" /%}
|
||||
|
||||
In the upper left of the Sources pane, we can control the execution of the program.
|
||||
|
||||
{% image src="https://github.com/oven-sh/bun/assets/3084745/41b76deb-7371-4461-9d5d-81b5a6d2f7a4" /%}
|
||||
|
||||
Here's a cheat sheet explaining the functions of the control flow buttons.
|
||||
|
||||
- _Continue script execution_ — continue running the program until the next breakpoint or exception.
|
||||
- _Step over_ — The program will continue to the next line.
|
||||
- _Step into_ — If the current statement contains a function call, the debugger will "step into" the called function.
|
||||
- _Step out_ — If the current statement is a function call, the debugger will finish executing the call, then "step out" of the function to the location where it was called.
|
||||
|
||||
{% image src="https://github-production-user-asset-6210df.s3.amazonaws.com/3084745/261510346-6a94441c-75d3-413a-99a7-efa62365f83d.png" /%}
|
||||
@@ -138,7 +138,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
|
||||
|
||||
### [`node:tty`](https://nodejs.org/api/tty.html)
|
||||
|
||||
🟡 Missing `tty.ReadStream` and `tty.WriteStream`.
|
||||
🟢 Fully implemented.
|
||||
|
||||
### [`node:url`](https://nodejs.org/api/url.html)
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
`bun:test` supports seeing which lines of code are covered by tests. To use this feature, pass `--coverage` to the CLI:
|
||||
Bun's test runner now supports built-in _code coverage reporting_. This makes it easy to see how much of the codebase is covered by tests, and find areas that are not currently well-tested.
|
||||
|
||||
```sh
|
||||
bun test --coverage
|
||||
```
|
||||
## Enabling coverage
|
||||
|
||||
It will print out a coverage report to the console:
|
||||
`bun:test` supports seeing which lines of code are covered by tests. To use this feature, pass `--coverage` to the CLI. It will print out a coverage report to the console:
|
||||
|
||||
```js
|
||||
$ bun test --coverage
|
||||
-------------|---------|---------|-------------------
|
||||
File | % Funcs | % Lines | Uncovered Line #s
|
||||
-------------|---------|---------|-------------------
|
||||
@@ -26,32 +25,45 @@ All files | 38.89 | 42.11 |
|
||||
-------------|---------|---------|-------------------
|
||||
```
|
||||
|
||||
If coverage is below a threshold, `bun:test` will exit with a non-zero exit code to indicate the failure.
|
||||
|
||||
### Configuring coverage
|
||||
|
||||
`bunfig.toml` supports configuring coverage:
|
||||
To always enable coverage reporting by default, add the following line to your `bunfig.toml`:
|
||||
|
||||
```toml
|
||||
[test]
|
||||
|
||||
# Always enable coverage
|
||||
# always enable coverage
|
||||
coverage = true
|
||||
|
||||
# Anything less than 90% coverage will fail the test
|
||||
# coverageThreshold = 0.9
|
||||
coverageThreshold = { line = 0.9, function = 0.9 }
|
||||
|
||||
|
||||
# Don't include .test.* files in coverage reports
|
||||
coverageSkipTestFiles = true
|
||||
|
||||
# Disable sourcemap support in coverage reports
|
||||
# By default, coverage reports will automatically use Bun's internal sourcemap.
|
||||
# You probably don't want to configure this
|
||||
# coverageIgnoreSourcemaps = false
|
||||
```
|
||||
|
||||
`coverageThreshold` can be either a number or an object with `line` and `function` keys. When a number, it is treated as both the line and function threshold.
|
||||
By default coverage reports will _include_ test files and _exclude_ sourcemaps. This is usually what you want, but it can be configured otherwise in `bunfig.toml`.
|
||||
|
||||
Coverage support was added in Bun v0.7.3.
|
||||
```toml
|
||||
[test]
|
||||
coverageSkipTestFiles = true # default false
|
||||
```
|
||||
|
||||
### Coverage thresholds
|
||||
|
||||
{% callout %}
|
||||
**Note** — Support for coverage reporting was added in Bun v0.7.3.
|
||||
{% /callout %}
|
||||
|
||||
It is possible to specify a coverage threshold in `bunfig.toml`. If your test suite does not meet or exceed this threshold, `bun test` will exit with a non-zero exit code to indicate the failure.
|
||||
|
||||
```toml
|
||||
[test]
|
||||
|
||||
# to require 90% line-level and function-level coverage
|
||||
coverageThreshold = 0.9
|
||||
|
||||
# to set different thresholds for lines and functions
|
||||
coverageThreshold = { line = 0.9, function = 0.9 }
|
||||
```
|
||||
|
||||
### Sourcemaps
|
||||
|
||||
Internally, Bun transpiles all files by default, so Bun automatically generates an internal [source map](https://web.dev/source-maps/) that maps lines of your original source code onto Bun's internal representation. If for any reason you want to disable this, set `test.coverageIgnoreSourcemaps` to `false`; this will rarely be desirable outside of advanced use cases.
|
||||
|
||||
```toml
|
||||
[test]
|
||||
coverageIgnoreSourcemaps = true # default false
|
||||
```
|
||||
|
||||
@@ -187,7 +187,17 @@ pub fn main() anyerror!void {
|
||||
var ctx = try default_allocator.create(HTTP.HTTPChannelContext);
|
||||
ctx.* = .{
|
||||
.channel = channel,
|
||||
.http = try HTTP.AsyncHTTP.init(default_allocator, args.method, args.url, args.headers, args.headers_buf, response_body_string, args.body, 0, HTTP.FetchRedirect.follow),
|
||||
.http = try HTTP.AsyncHTTP.init(
|
||||
default_allocator,
|
||||
args.method,
|
||||
args.url,
|
||||
args.headers,
|
||||
args.headers_buf,
|
||||
response_body_string,
|
||||
args.body,
|
||||
0,
|
||||
HTTP.FetchRedirect.follow,
|
||||
),
|
||||
};
|
||||
ctx.http.callback = HTTP.HTTPChannelContext.callback;
|
||||
var batch = HTTPThread.Batch{};
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"prettier": "^2.4.1",
|
||||
"react": "next",
|
||||
"react-dom": "next",
|
||||
"source-map-js": "^1.0.2",
|
||||
"typescript": "^5.0.2"
|
||||
},
|
||||
"private": true,
|
||||
@@ -17,7 +18,7 @@
|
||||
"build-fallback": "esbuild --target=esnext --bundle src/fallback.ts --format=iife --platform=browser --minify > src/fallback.out.js",
|
||||
"postinstall": "bash .scripts/postinstall.sh",
|
||||
"typecheck": "tsc --noEmit && cd test && bun run typecheck",
|
||||
"fmt": "prettier --write --cache './{src,test,bench}/**/*.{mjs,ts,tsx,js,jsx}'",
|
||||
"fmt": "prettier --write --cache './{src,test,bench,packages/{bun-inspector-*,bun-vscode,bun-debug-adapter-protocol}}/**/*.{mjs,ts,tsx,js,jsx}'",
|
||||
"lint": "eslint './**/*.d.ts' --cache",
|
||||
"lint:fix": "eslint './**/*.d.ts' --cache --fix"
|
||||
},
|
||||
@@ -25,7 +26,7 @@
|
||||
"@types/react": "^18.0.25",
|
||||
"@typescript-eslint/eslint-plugin": "^5.31.0",
|
||||
"@typescript-eslint/parser": "^5.31.0",
|
||||
"bun-webkit": "0.0.1-fd79ce3120a692f4aed314c3da3dd452b4aa865f"
|
||||
"bun-webkit": "0.0.1-48c1316e907ca597e27e5a7624160dc18a4df8ec"
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"prettier": "./.prettierrc.cjs"
|
||||
|
||||
2
packages/bun-debug-adapter-protocol/.gitattributes
vendored
Normal file
2
packages/bun-debug-adapter-protocol/.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
protocol/*/protocol.json linguist-generated=true
|
||||
protocol/*/index.d.ts linguist-generated=true
|
||||
1
packages/bun-debug-adapter-protocol/.gitignore
vendored
Normal file
1
packages/bun-debug-adapter-protocol/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
protocol/*.json
|
||||
3
packages/bun-debug-adapter-protocol/README.md
Normal file
3
packages/bun-debug-adapter-protocol/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# bun-debug-adapter-protocol
|
||||
|
||||
https://microsoft.github.io/debug-adapter-protocol/overview
|
||||
BIN
packages/bun-debug-adapter-protocol/bun.lockb
Executable file
BIN
packages/bun-debug-adapter-protocol/bun.lockb
Executable file
Binary file not shown.
2
packages/bun-debug-adapter-protocol/index.ts
Normal file
2
packages/bun-debug-adapter-protocol/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export type * from "./src/protocol";
|
||||
export * from "./src/debugger/adapter";
|
||||
8
packages/bun-debug-adapter-protocol/package.json
Normal file
8
packages/bun-debug-adapter-protocol/package.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "bun-debug-adapter-protocol",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"semver": "^7.5.4",
|
||||
"source-map-js": "^1.0.2"
|
||||
}
|
||||
}
|
||||
176
packages/bun-debug-adapter-protocol/scripts/generate-protocol.ts
Normal file
176
packages/bun-debug-adapter-protocol/scripts/generate-protocol.ts
Normal file
@@ -0,0 +1,176 @@
|
||||
import type { Protocol, Type } from "../src/protocol/schema";
|
||||
import { writeFileSync } from "node:fs";
|
||||
import { spawnSync } from "node:child_process";
|
||||
|
||||
run().catch(console.error);
|
||||
|
||||
async function run() {
|
||||
const cwd = new URL("../protocol/", import.meta.url);
|
||||
const runner = "Bun" in globalThis ? "bunx" : "npx";
|
||||
const write = (name: string, data: string) => {
|
||||
const path = new URL(name, cwd);
|
||||
writeFileSync(path, data);
|
||||
spawnSync(runner, ["prettier", "--write", path.pathname], { cwd, stdio: "ignore" });
|
||||
};
|
||||
const schema: Protocol = await download(
|
||||
"https://microsoft.github.io/debug-adapter-protocol/debugAdapterProtocol.json",
|
||||
);
|
||||
write("protocol.json", JSON.stringify(schema));
|
||||
const types = formatProtocol(schema);
|
||||
write("index.d.ts", `// GENERATED - DO NOT EDIT\n${types}`);
|
||||
}
|
||||
|
||||
function formatProtocol(protocol: Protocol, extraTs?: string): string {
|
||||
const { definitions } = protocol;
|
||||
const requestMap = new Map();
|
||||
const responseMap = new Map();
|
||||
const eventMap = new Map();
|
||||
let body = `export namespace DAP {`;
|
||||
loop: for (const [key, definition] of Object.entries(definitions)) {
|
||||
if (/[a-z]+Request$/i.test(key)) {
|
||||
continue;
|
||||
}
|
||||
if (/[a-z]+Arguments$/i.test(key)) {
|
||||
const name = key.replace(/(Request)?Arguments$/, "");
|
||||
const requestName = `${name}Request`;
|
||||
requestMap.set(toMethod(name), requestName);
|
||||
body += formatType(definition, requestName);
|
||||
continue;
|
||||
}
|
||||
if ("allOf" in definition) {
|
||||
const { allOf } = definition;
|
||||
for (const type of allOf) {
|
||||
if (type.type !== "object") {
|
||||
continue;
|
||||
}
|
||||
const { description, properties = {} } = type;
|
||||
if (/[a-z]+Event$/i.test(key)) {
|
||||
const { event, body: type = {} } = properties;
|
||||
if (!event || !("enum" in event)) {
|
||||
continue;
|
||||
}
|
||||
const [eventKey] = event.enum ?? [];
|
||||
eventMap.set(eventKey, key);
|
||||
const eventType: Type = {
|
||||
type: "object",
|
||||
description,
|
||||
...type,
|
||||
};
|
||||
body += formatType(eventType, key);
|
||||
continue loop;
|
||||
}
|
||||
if (/[a-z]+Response$/i.test(key)) {
|
||||
const { body: type = {} } = properties;
|
||||
const bodyType: Type = {
|
||||
type: "object",
|
||||
description,
|
||||
...type,
|
||||
};
|
||||
const name = key.replace(/Response$/, "");
|
||||
responseMap.set(toMethod(name), key);
|
||||
body += formatType(bodyType, key);
|
||||
continue loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
body += formatType(definition, key);
|
||||
}
|
||||
for (const [key, name] of responseMap) {
|
||||
if (requestMap.has(key)) {
|
||||
continue;
|
||||
}
|
||||
const requestName = `${name.replace(/Response$/, "")}Request`;
|
||||
requestMap.set(key, requestName);
|
||||
body += formatType({ type: "object", properties: {} }, requestName);
|
||||
}
|
||||
body += formatMapType("RequestMap", requestMap);
|
||||
body += formatMapType("ResponseMap", responseMap);
|
||||
body += formatMapType("EventMap", eventMap);
|
||||
if (extraTs) {
|
||||
body += extraTs;
|
||||
}
|
||||
return body + "};";
|
||||
}
|
||||
|
||||
function formatMapType(key: string, typeMap: Map<string, string>): string {
|
||||
const type: Type = {
|
||||
type: "object",
|
||||
required: [...typeMap.keys()],
|
||||
properties: Object.fromEntries([...typeMap.entries()].map(([key, value]) => [key, { $ref: value }])),
|
||||
};
|
||||
return formatType(type, key);
|
||||
}
|
||||
|
||||
function formatType(type: Type, key?: string): string {
|
||||
const { description, type: kind } = type;
|
||||
let body = "";
|
||||
if (key) {
|
||||
if (description) {
|
||||
body += `\n${toComment(description)}\n`;
|
||||
}
|
||||
body += `export type ${key}=`;
|
||||
}
|
||||
if (kind === "boolean") {
|
||||
body += "boolean";
|
||||
} else if (kind === "number" || kind === "integer") {
|
||||
body += "number";
|
||||
} else if (kind === "string") {
|
||||
const { enum: choices } = type;
|
||||
if (choices) {
|
||||
body += choices.map(value => `"${value}"`).join("|");
|
||||
} else {
|
||||
body += "string";
|
||||
}
|
||||
} else if (kind === "array") {
|
||||
const { items } = type;
|
||||
const itemType = items ? formatType(items) : "unknown";
|
||||
body += `${itemType}[]`;
|
||||
} else if (kind === "object") {
|
||||
const { properties, required } = type;
|
||||
if (!properties || Object.keys(properties).length === 0) {
|
||||
body += "{}";
|
||||
} else {
|
||||
body += "{";
|
||||
for (const [key, { description, ...type }] of Object.entries(properties)) {
|
||||
if (description) {
|
||||
body += `\n${toComment(description)}`;
|
||||
}
|
||||
const delimit = required?.includes(key) ? ":" : "?:";
|
||||
body += `\n${key}${delimit}${formatType(type)};`;
|
||||
}
|
||||
body += "}";
|
||||
}
|
||||
} else if ("$ref" in type) {
|
||||
const { $ref: ref } = type;
|
||||
body += ref.split("/").pop() || "unknown";
|
||||
} else if ("allOf" in type) {
|
||||
const { allOf } = type;
|
||||
body += allOf.map(type => formatType(type)).join("&");
|
||||
} else {
|
||||
body += "unknown";
|
||||
}
|
||||
if (key) {
|
||||
body += ";";
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
function toMethod(name: string): string {
|
||||
return `${name.substring(0, 1).toLowerCase()}${name.substring(1)}`;
|
||||
}
|
||||
|
||||
function toComment(description?: string): string {
|
||||
if (!description) {
|
||||
return "";
|
||||
}
|
||||
const lines = ["/**", ...description.split("\n").map(line => ` * ${line.trim()}`), "*/"];
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
async function download<T>(url: string | URL): Promise<T> {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to download ${url}: ${response.statusText}`);
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
1712
packages/bun-debug-adapter-protocol/src/debugger/adapter.ts
Normal file
1712
packages/bun-debug-adapter-protocol/src/debugger/adapter.ts
Normal file
File diff suppressed because it is too large
Load Diff
271
packages/bun-debug-adapter-protocol/src/debugger/capabilities.ts
Normal file
271
packages/bun-debug-adapter-protocol/src/debugger/capabilities.ts
Normal file
@@ -0,0 +1,271 @@
|
||||
import type { DAP } from "../protocol";
|
||||
|
||||
const capabilities: DAP.Capabilities = {
|
||||
/**
|
||||
* The debug adapter supports the `configurationDone` request.
|
||||
* @see configurationDone
|
||||
*/
|
||||
supportsConfigurationDoneRequest: true,
|
||||
|
||||
/**
|
||||
* The debug adapter supports function breakpoints using the `setFunctionBreakpoints` request.
|
||||
* @see setFunctionBreakpoints
|
||||
*/
|
||||
supportsFunctionBreakpoints: true,
|
||||
|
||||
/**
|
||||
* The debug adapter supports conditional breakpoints.
|
||||
* @see setBreakpoints
|
||||
* @see setInstructionBreakpoints
|
||||
* @see setFunctionBreakpoints
|
||||
* @see setExceptionBreakpoints
|
||||
* @see setDataBreakpoints
|
||||
*/
|
||||
supportsConditionalBreakpoints: true,
|
||||
|
||||
/**
|
||||
* The debug adapter supports breakpoints that break execution after a specified number of hits.
|
||||
* @see setBreakpoints
|
||||
* @see setInstructionBreakpoints
|
||||
* @see setFunctionBreakpoints
|
||||
* @see setExceptionBreakpoints
|
||||
* @see setDataBreakpoints
|
||||
*/
|
||||
supportsHitConditionalBreakpoints: true,
|
||||
|
||||
/**
|
||||
* The debug adapter supports a (side effect free) `evaluate` request for data hovers.
|
||||
* @see evaluate
|
||||
*/
|
||||
supportsEvaluateForHovers: true,
|
||||
|
||||
/**
|
||||
* Available exception filter options for the `setExceptionBreakpoints` request.
|
||||
* @see setExceptionBreakpoints
|
||||
*/
|
||||
exceptionBreakpointFilters: [
|
||||
{
|
||||
filter: "all",
|
||||
label: "Caught Exceptions",
|
||||
default: false,
|
||||
supportsCondition: true,
|
||||
description: "Breaks on all throw errors, even if they're caught later.",
|
||||
conditionDescription: `error.name == "CustomError"`,
|
||||
},
|
||||
{
|
||||
filter: "uncaught",
|
||||
label: "Uncaught Exceptions",
|
||||
default: false,
|
||||
supportsCondition: true,
|
||||
description: "Breaks only on errors or promise rejections that are not handled.",
|
||||
conditionDescription: `error.name == "CustomError"`,
|
||||
},
|
||||
],
|
||||
|
||||
/**
|
||||
* The debug adapter supports stepping back via the `stepBack` and `reverseContinue` requests.
|
||||
* @see stepBack
|
||||
* @see reverseContinue
|
||||
*/
|
||||
supportsStepBack: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports setting a variable to a value.
|
||||
* @see setVariable
|
||||
*/
|
||||
supportsSetVariable: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports restarting a frame.
|
||||
* @see restartFrame
|
||||
*/
|
||||
supportsRestartFrame: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `gotoTargets` request.
|
||||
* @see gotoTargets
|
||||
*/
|
||||
supportsGotoTargetsRequest: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `stepInTargets` request.
|
||||
* @see stepInTargets
|
||||
*/
|
||||
supportsStepInTargetsRequest: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `completions` request.
|
||||
* @see completions
|
||||
*/
|
||||
supportsCompletionsRequest: false,
|
||||
|
||||
/**
|
||||
* The set of characters that should trigger completion in a REPL.
|
||||
* If not specified, the UI should assume the `.` character.
|
||||
* @see completions
|
||||
*/
|
||||
completionTriggerCharacters: [".", "[", '"', "'"],
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `modules` request.
|
||||
* @see modules
|
||||
*/
|
||||
supportsModulesRequest: false,
|
||||
|
||||
/**
|
||||
* The set of additional module information exposed by the debug adapter.
|
||||
* @see modules
|
||||
*/
|
||||
additionalModuleColumns: [],
|
||||
|
||||
/**
|
||||
* Checksum algorithms supported by the debug adapter.
|
||||
*/
|
||||
supportedChecksumAlgorithms: [],
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `restart` request.
|
||||
* In this case a client should not implement `restart` by terminating
|
||||
* and relaunching the adapter but by calling the `restart` request.
|
||||
* @see restart
|
||||
*/
|
||||
supportsRestartRequest: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports `exceptionOptions` on the `setExceptionBreakpoints` request.
|
||||
* @see setExceptionBreakpoints
|
||||
*/
|
||||
supportsExceptionOptions: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports a `format` attribute on the `stackTrace`, `variables`, and `evaluate` requests.
|
||||
* @see stackTrace
|
||||
* @see variables
|
||||
* @see evaluate
|
||||
*/
|
||||
supportsValueFormattingOptions: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `exceptionInfo` request.
|
||||
* @see exceptionInfo
|
||||
*/
|
||||
supportsExceptionInfoRequest: true,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `terminateDebuggee` attribute on the `disconnect` request.
|
||||
* @see disconnect
|
||||
*/
|
||||
supportTerminateDebuggee: true,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `suspendDebuggee` attribute on the `disconnect` request.
|
||||
* @see disconnect
|
||||
*/
|
||||
supportSuspendDebuggee: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the delayed loading of parts of the stack,
|
||||
* which requires that both the `startFrame` and `levels` arguments and
|
||||
* the `totalFrames` result of the `stackTrace` request are supported.
|
||||
* @see stackTrace
|
||||
*/
|
||||
supportsDelayedStackTraceLoading: true,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `loadedSources` request.
|
||||
* @see loadedSources
|
||||
*/
|
||||
supportsLoadedSourcesRequest: true,
|
||||
|
||||
/**
|
||||
* The debug adapter supports log points by interpreting the `logMessage` attribute of the `SourceBreakpoint`.
|
||||
* @see setBreakpoints
|
||||
*/
|
||||
supportsLogPoints: true,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `terminateThreads` request.
|
||||
* @see terminateThreads
|
||||
*/
|
||||
supportsTerminateThreadsRequest: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `setExpression` request.
|
||||
* @see setExpression
|
||||
*/
|
||||
supportsSetExpression: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `terminate` request.
|
||||
* @see terminate
|
||||
*/
|
||||
supportsTerminateRequest: true,
|
||||
|
||||
/**
|
||||
* The debug adapter supports data breakpoints.
|
||||
* @see setDataBreakpoints
|
||||
*/
|
||||
supportsDataBreakpoints: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `readMemory` request.
|
||||
* @see readMemory
|
||||
*/
|
||||
supportsReadMemoryRequest: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `writeMemory` request.
|
||||
* @see writeMemory
|
||||
*/
|
||||
supportsWriteMemoryRequest: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `disassemble` request.
|
||||
* @see disassemble
|
||||
*/
|
||||
supportsDisassembleRequest: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `cancel` request.
|
||||
* @see cancel
|
||||
*/
|
||||
supportsCancelRequest: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `breakpointLocations` request.
|
||||
* @see breakpointLocations
|
||||
*/
|
||||
supportsBreakpointLocationsRequest: true,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `clipboard` context value in the `evaluate` request.
|
||||
* @see evaluate
|
||||
*/
|
||||
supportsClipboardContext: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports stepping granularities (argument `granularity`) for the stepping requests.
|
||||
* @see stepIn
|
||||
*/
|
||||
supportsSteppingGranularity: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports adding breakpoints based on instruction references.
|
||||
* @see setInstructionBreakpoints
|
||||
*/
|
||||
supportsInstructionBreakpoints: false,
|
||||
|
||||
/**
|
||||
* The debug adapter supports `filterOptions` as an argument on the `setExceptionBreakpoints` request.
|
||||
* @see setExceptionBreakpoints
|
||||
*/
|
||||
supportsExceptionFilterOptions: true,
|
||||
|
||||
/**
|
||||
* The debug adapter supports the `singleThread` property on the execution requests
|
||||
* (`continue`, `next`, `stepIn`, `stepOut`, `reverseContinue`, `stepBack`).
|
||||
*/
|
||||
supportsSingleThreadExecutionRequests: false,
|
||||
};
|
||||
|
||||
export default capabilities;
|
||||
@@ -0,0 +1,36 @@
|
||||
"use strict";
|
||||
export default {
|
||||
fetch(request) {
|
||||
const animal = getAnimal(request.url);
|
||||
const voice = animal.talk();
|
||||
return new Response(voice);
|
||||
},
|
||||
};
|
||||
function getAnimal(query) {
|
||||
switch (query.split("/").pop()) {
|
||||
case "dog":
|
||||
return new Dog();
|
||||
case "cat":
|
||||
return new Cat();
|
||||
}
|
||||
return new Bird();
|
||||
}
|
||||
class Dog {
|
||||
name = "dog";
|
||||
talk() {
|
||||
return "woof";
|
||||
}
|
||||
}
|
||||
class Cat {
|
||||
name = "cat";
|
||||
talk() {
|
||||
return "meow";
|
||||
}
|
||||
}
|
||||
class Bird {
|
||||
name = "bird";
|
||||
talk() {
|
||||
return "chirp";
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsicGFja2FnZXMvYnVuLWRlYnVnLWFkYXB0ZXItcHJvdG9jb2wvZGVidWdnZXIvZml4dHVyZXMvd2l0aC1zb3VyY2VtYXAudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImV4cG9ydCBkZWZhdWx0IHtcbiAgZmV0Y2gocmVxdWVzdDogUmVxdWVzdCk6IFJlc3BvbnNlIHtcbiAgICBjb25zdCBhbmltYWwgPSBnZXRBbmltYWwocmVxdWVzdC51cmwpO1xuICAgIGNvbnN0IHZvaWNlID0gYW5pbWFsLnRhbGsoKTtcbiAgICByZXR1cm4gbmV3IFJlc3BvbnNlKHZvaWNlKTtcbiAgfSxcbn07XG5cbmZ1bmN0aW9uIGdldEFuaW1hbChxdWVyeTogc3RyaW5nKTogQW5pbWFsIHtcbiAgc3dpdGNoIChxdWVyeS5zcGxpdChcIi9cIikucG9wKCkpIHtcbiAgICBjYXNlIFwiZG9nXCI6XG4gICAgICByZXR1cm4gbmV3IERvZygpO1xuICAgIGNhc2UgXCJjYXRcIjpcbiAgICAgIHJldHVybiBuZXcgQ2F0KCk7XG4gIH1cbiAgcmV0dXJuIG5ldyBCaXJkKCk7XG59XG5cbmludGVyZmFjZSBBbmltYWwge1xuICByZWFkb25seSBuYW1lOiBzdHJpbmc7XG4gIHRhbGsoKTogc3RyaW5nO1xufVxuXG5jbGFzcyBEb2cgaW1wbGVtZW50cyBBbmltYWwge1xuICBuYW1lID0gXCJkb2dcIjtcblxuICB0YWxrKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIFwid29vZlwiO1xuICB9XG59XG5cbmNsYXNzIENhdCBpbXBsZW1lbnRzIEFuaW1hbCB7XG4gIG5hbWUgPSBcImNhdFwiO1xuXG4gIHRhbGsoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gXCJtZW93XCI7XG4gIH1cbn1cblxuY2xhc3MgQmlyZCBpbXBsZW1lbnRzIEFuaW1hbCB7XG4gIG5hbWUgPSBcImJpcmRcIjtcblxuICB0YWxrKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIFwiY2hpcnBcIjtcbiAgfVxufVxuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUFBLGVBQWU7QUFBQSxFQUNiLE1BQU0sU0FBNEI7QUFDaEMsVUFBTSxTQUFTLFVBQVUsUUFBUSxHQUFHO0FBQ3BDLFVBQU0sUUFBUSxPQUFPLEtBQUs7QUFDMUIsV0FBTyxJQUFJLFNBQVMsS0FBSztBQUFBLEVBQzNCO0FBQ0Y7QUFFQSxTQUFTLFVBQVUsT0FBdUI7QUFDeEMsVUFBUSxNQUFNLE1BQU0sR0FBRyxFQUFFLElBQUksR0FBRztBQUFBLElBQzlCLEtBQUs7QUFDSCxhQUFPLElBQUksSUFBSTtBQUFBLElBQ2pCLEtBQUs7QUFDSCxhQUFPLElBQUksSUFBSTtBQUFBLEVBQ25CO0FBQ0EsU0FBTyxJQUFJLEtBQUs7QUFDbEI7QUFPQSxNQUFNLElBQXNCO0FBQUEsRUFDMUIsT0FBTztBQUFBLEVBRVAsT0FBZTtBQUNiLFdBQU87QUFBQSxFQUNUO0FBQ0Y7QUFFQSxNQUFNLElBQXNCO0FBQUEsRUFDMUIsT0FBTztBQUFBLEVBRVAsT0FBZTtBQUNiLFdBQU87QUFBQSxFQUNUO0FBQ0Y7QUFFQSxNQUFNLEtBQXVCO0FBQUEsRUFDM0IsT0FBTztBQUFBLEVBRVAsT0FBZTtBQUNiLFdBQU87QUFBQSxFQUNUO0FBQ0Y7IiwKICAibmFtZXMiOiBbXQp9Cg==
|
||||
@@ -0,0 +1,46 @@
|
||||
export default {
|
||||
fetch(request: Request): Response {
|
||||
const animal = getAnimal(request.url);
|
||||
const voice = animal.talk();
|
||||
return new Response(voice);
|
||||
},
|
||||
};
|
||||
|
||||
function getAnimal(query: string): Animal {
|
||||
switch (query.split("/").pop()) {
|
||||
case "dog":
|
||||
return new Dog();
|
||||
case "cat":
|
||||
return new Cat();
|
||||
}
|
||||
return new Bird();
|
||||
}
|
||||
|
||||
interface Animal {
|
||||
readonly name: string;
|
||||
talk(): string;
|
||||
}
|
||||
|
||||
class Dog implements Animal {
|
||||
name = "dog";
|
||||
|
||||
talk(): string {
|
||||
return "woof";
|
||||
}
|
||||
}
|
||||
|
||||
class Cat implements Animal {
|
||||
name = "cat";
|
||||
|
||||
talk(): string {
|
||||
return "meow";
|
||||
}
|
||||
}
|
||||
|
||||
class Bird implements Animal {
|
||||
name = "bird";
|
||||
|
||||
talk(): string {
|
||||
return "chirp";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
export default {
|
||||
fetch(request) {
|
||||
return new Response(a());
|
||||
},
|
||||
};
|
||||
|
||||
function a() {
|
||||
return b();
|
||||
}
|
||||
|
||||
function b() {
|
||||
return c();
|
||||
}
|
||||
|
||||
function c() {
|
||||
function d() {
|
||||
return "hello";
|
||||
}
|
||||
return d();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { test, expect } from "bun:test";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { SourceMap } from "./sourcemap";
|
||||
|
||||
test("works without source map", () => {
|
||||
const sourceMap = getSourceMap("without-sourcemap.js");
|
||||
expect(sourceMap.generatedLocation({ line: 7 })).toEqual({ line: 7, column: 0, verified: true });
|
||||
expect(sourceMap.generatedLocation({ line: 7, column: 2 })).toEqual({ line: 7, column: 2, verified: true });
|
||||
expect(sourceMap.originalLocation({ line: 11 })).toEqual({ line: 11, column: 0, verified: true });
|
||||
expect(sourceMap.originalLocation({ line: 11, column: 2 })).toEqual({ line: 11, column: 2, verified: true });
|
||||
});
|
||||
|
||||
test("works with source map", () => {
|
||||
const sourceMap = getSourceMap("with-sourcemap.js");
|
||||
// FIXME: Columns don't appear to be accurate for `generatedLocation`
|
||||
expect(sourceMap.generatedLocation({ line: 3 })).toMatchObject({ line: 4, verified: true });
|
||||
expect(sourceMap.generatedLocation({ line: 27 })).toMatchObject({ line: 20, verified: true });
|
||||
expect(sourceMap.originalLocation({ line: 32 })).toEqual({ line: 43, column: 4, verified: true });
|
||||
expect(sourceMap.originalLocation({ line: 13 })).toEqual({ line: 13, column: 6, verified: true });
|
||||
});
|
||||
|
||||
function getSourceMap(filename: string): SourceMap {
|
||||
const { pathname } = new URL(`./fixtures/${filename}`, import.meta.url);
|
||||
const source = readFileSync(pathname, "utf-8");
|
||||
const match = source.match(/\/\/# sourceMappingURL=(.*)$/m);
|
||||
if (match) {
|
||||
const [, url] = match;
|
||||
return SourceMap(url);
|
||||
}
|
||||
return SourceMap();
|
||||
}
|
||||
193
packages/bun-debug-adapter-protocol/src/debugger/sourcemap.ts
Normal file
193
packages/bun-debug-adapter-protocol/src/debugger/sourcemap.ts
Normal file
@@ -0,0 +1,193 @@
|
||||
import type { LineRange, MappedPosition } from "source-map-js";
|
||||
import { SourceMapConsumer } from "source-map-js";
|
||||
|
||||
export type LocationRequest = {
|
||||
line?: number;
|
||||
column?: number;
|
||||
url?: string;
|
||||
};
|
||||
|
||||
export type Location = {
|
||||
line: number; // 0-based
|
||||
column: number; // 0-based
|
||||
} & (
|
||||
| {
|
||||
verified: true;
|
||||
}
|
||||
| {
|
||||
verified?: false;
|
||||
message?: string;
|
||||
}
|
||||
);
|
||||
|
||||
export interface SourceMap {
|
||||
generatedLocation(request: LocationRequest): Location;
|
||||
originalLocation(request: LocationRequest): Location;
|
||||
}
|
||||
|
||||
class ActualSourceMap implements SourceMap {
|
||||
#sourceMap: SourceMapConsumer;
|
||||
#sources: string[];
|
||||
|
||||
constructor(sourceMap: SourceMapConsumer) {
|
||||
this.#sourceMap = sourceMap;
|
||||
this.#sources = (sourceMap as any)._absoluteSources;
|
||||
}
|
||||
|
||||
#getSource(url?: string): string {
|
||||
const sources = this.#sources;
|
||||
if (!sources.length) {
|
||||
return "";
|
||||
}
|
||||
if (sources.length === 1 || !url) {
|
||||
return sources[0];
|
||||
}
|
||||
for (const source of sources) {
|
||||
if (url.endsWith(source)) {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
generatedLocation(request: LocationRequest): Location {
|
||||
const { line, column, url } = request;
|
||||
|
||||
let lineRange: LineRange;
|
||||
try {
|
||||
const source = this.#getSource(url);
|
||||
lineRange = this.#sourceMap.generatedPositionFor({
|
||||
line: lineTo1BasedLine(line),
|
||||
column: columnToColumn(column),
|
||||
source,
|
||||
});
|
||||
} catch (error) {
|
||||
return {
|
||||
line: lineToLine(line),
|
||||
column: columnToColumn(column),
|
||||
verified: false,
|
||||
message: unknownToError(error),
|
||||
};
|
||||
}
|
||||
|
||||
if (!locationIsValid(lineRange)) {
|
||||
return {
|
||||
line: lineToLine(line),
|
||||
column: columnToColumn(column),
|
||||
verified: false,
|
||||
};
|
||||
}
|
||||
|
||||
const { line: gline, column: gcolumn } = lineRange;
|
||||
return {
|
||||
line: lineToLine(gline),
|
||||
column: columnToColumn(gcolumn),
|
||||
verified: true,
|
||||
};
|
||||
}
|
||||
|
||||
originalLocation(request: LocationRequest): Location {
|
||||
const { line, column } = request;
|
||||
|
||||
let mappedPosition: MappedPosition;
|
||||
try {
|
||||
mappedPosition = this.#sourceMap.originalPositionFor({
|
||||
line: lineTo1BasedLine(line),
|
||||
column: columnToColumn(column),
|
||||
});
|
||||
} catch (error) {
|
||||
return {
|
||||
line: lineToLine(line),
|
||||
column: columnToColumn(column),
|
||||
verified: false,
|
||||
message: unknownToError(error),
|
||||
};
|
||||
}
|
||||
|
||||
if (!locationIsValid(mappedPosition)) {
|
||||
return {
|
||||
line: lineToLine(line),
|
||||
column: columnToColumn(column),
|
||||
verified: false,
|
||||
};
|
||||
}
|
||||
|
||||
const { line: oline, column: ocolumn } = mappedPosition;
|
||||
return {
|
||||
line: lineTo0BasedLine(oline),
|
||||
column: columnToColumn(ocolumn),
|
||||
verified: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class NoopSourceMap implements SourceMap {
|
||||
generatedLocation(request: LocationRequest): Location {
|
||||
const { line, column } = request;
|
||||
return {
|
||||
line: lineToLine(line),
|
||||
column: columnToColumn(column),
|
||||
verified: true,
|
||||
};
|
||||
}
|
||||
|
||||
originalLocation(request: LocationRequest): Location {
|
||||
const { line, column } = request;
|
||||
return {
|
||||
line: lineToLine(line),
|
||||
column: columnToColumn(column),
|
||||
verified: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const defaultSourceMap = new NoopSourceMap();
|
||||
|
||||
export function SourceMap(url?: string): SourceMap {
|
||||
if (!url || !url.startsWith("data:")) {
|
||||
return defaultSourceMap;
|
||||
}
|
||||
try {
|
||||
const [_, base64] = url.split(",", 2);
|
||||
const decoded = Buffer.from(base64, "base64url").toString("utf8");
|
||||
const schema = JSON.parse(decoded);
|
||||
const sourceMap = new SourceMapConsumer(schema);
|
||||
return new ActualSourceMap(sourceMap);
|
||||
} catch (error) {
|
||||
console.warn("Failed to parse source map URL", url);
|
||||
}
|
||||
return defaultSourceMap;
|
||||
}
|
||||
|
||||
function lineTo1BasedLine(line?: number): number {
|
||||
return numberIsValid(line) ? line + 1 : 1;
|
||||
}
|
||||
|
||||
function lineTo0BasedLine(line?: number): number {
|
||||
return numberIsValid(line) ? line - 1 : 0;
|
||||
}
|
||||
|
||||
function lineToLine(line?: number): number {
|
||||
return numberIsValid(line) ? line : 0;
|
||||
}
|
||||
|
||||
function columnToColumn(column?: number): number {
|
||||
return numberIsValid(column) ? column : 0;
|
||||
}
|
||||
|
||||
function locationIsValid(location: Location): location is Location {
|
||||
const { line, column } = location;
|
||||
return numberIsValid(line) && numberIsValid(column);
|
||||
}
|
||||
|
||||
function numberIsValid(number?: number): number is number {
|
||||
return typeof number === "number" && isFinite(number) && number >= 0;
|
||||
}
|
||||
|
||||
function unknownToError(error: unknown): string {
|
||||
if (error instanceof Error) {
|
||||
const { message } = error;
|
||||
return message;
|
||||
}
|
||||
return String(error);
|
||||
}
|
||||
2696
packages/bun-debug-adapter-protocol/src/protocol/index.d.ts
vendored
Normal file
2696
packages/bun-debug-adapter-protocol/src/protocol/index.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3761
packages/bun-debug-adapter-protocol/src/protocol/protocol.json
Normal file
3761
packages/bun-debug-adapter-protocol/src/protocol/protocol.json
Normal file
File diff suppressed because it is too large
Load Diff
37
packages/bun-debug-adapter-protocol/src/protocol/schema.d.ts
vendored
Normal file
37
packages/bun-debug-adapter-protocol/src/protocol/schema.d.ts
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
export type Protocol = {
|
||||
$schema: string;
|
||||
title: string;
|
||||
description: string;
|
||||
type: "object";
|
||||
definitions: Record<string, Type>;
|
||||
};
|
||||
|
||||
export type Type = {
|
||||
description?: string;
|
||||
} & (
|
||||
| {
|
||||
type: "number" | "integer" | "boolean";
|
||||
}
|
||||
| {
|
||||
type: "string";
|
||||
enum?: string[];
|
||||
enumDescriptions?: string[];
|
||||
}
|
||||
| {
|
||||
type: "object";
|
||||
properties?: Record<string, Type>;
|
||||
required?: string[];
|
||||
}
|
||||
| {
|
||||
type: "array";
|
||||
items?: Type;
|
||||
}
|
||||
| {
|
||||
type?: undefined;
|
||||
$ref: string;
|
||||
}
|
||||
| {
|
||||
type?: undefined;
|
||||
allOf: Type[];
|
||||
}
|
||||
);
|
||||
@@ -3,18 +3,19 @@
|
||||
"lib": ["ESNext"],
|
||||
"module": "esnext",
|
||||
"target": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"moduleResolution": "nodenext",
|
||||
"moduleDetection": "force",
|
||||
"allowImportingTsExtensions": true,
|
||||
"noEmit": true,
|
||||
"composite": true,
|
||||
"strict": true,
|
||||
"downlevelIteration": true,
|
||||
"skipLibCheck": true,
|
||||
"jsx": "preserve",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"inlineSourceMap": true,
|
||||
"allowJs": true,
|
||||
"noEmit": true,
|
||||
"types": [
|
||||
"bun-types" // add Bun global
|
||||
]
|
||||
}
|
||||
"outDir": "dist",
|
||||
},
|
||||
"include": ["src", "scripts", "../bun-types/index.d.ts", "../bun-inspector-protocol/src"]
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"name": "bun-ecosystem-ci",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"globby": "^13.1.3"
|
||||
@@ -11,4 +12,4 @@
|
||||
"format": "prettier --write src",
|
||||
"test": "bun run src/runner.ts"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# web-inspector-bun
|
||||
# bun-devtools-frontend
|
||||
|
||||
This is the WebKit Web Inspector bundled as standalone assets.
|
||||
|
||||
20
packages/bun-inspector-frontend/tsconfig.json
Normal file
20
packages/bun-inspector-frontend/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext"],
|
||||
"module": "esnext",
|
||||
"target": "esnext",
|
||||
"moduleResolution": "nodenext",
|
||||
"moduleDetection": "force",
|
||||
"strict": true,
|
||||
"downlevelIteration": true,
|
||||
"skipLibCheck": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"inlineSourceMap": true,
|
||||
"allowJs": true,
|
||||
"noImplicitAny": false,
|
||||
"outDir": "dist",
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": [".", "../bun-types/index.d.ts"]
|
||||
}
|
||||
2
packages/bun-inspector-protocol/.gitattributes
vendored
Normal file
2
packages/bun-inspector-protocol/.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
protocol/*/protocol.json linguist-generated=true
|
||||
protocol/*/index.d.ts linguist-generated=true
|
||||
2
packages/bun-inspector-protocol/.gitignore
vendored
Normal file
2
packages/bun-inspector-protocol/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
protocol/*.json
|
||||
protocol/v8
|
||||
1
packages/bun-inspector-protocol/README.md
Normal file
1
packages/bun-inspector-protocol/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# bun-inspector-protocol
|
||||
BIN
packages/bun-inspector-protocol/bun.lockb
Executable file
BIN
packages/bun-inspector-protocol/bun.lockb
Executable file
Binary file not shown.
4
packages/bun-inspector-protocol/index.ts
Normal file
4
packages/bun-inspector-protocol/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export type * from "./src/protocol";
|
||||
export type * from "./src/inspector";
|
||||
export * from "./src/util/preview";
|
||||
export * from "./src/inspector/websocket";
|
||||
7
packages/bun-inspector-protocol/package.json
Normal file
7
packages/bun-inspector-protocol/package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "bun-inspector-protocol",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"ws": "^8.13.0"
|
||||
}
|
||||
}
|
||||
202
packages/bun-inspector-protocol/scripts/generate-protocol.ts
Normal file
202
packages/bun-inspector-protocol/scripts/generate-protocol.ts
Normal file
@@ -0,0 +1,202 @@
|
||||
import type { Protocol, Domain, Property } from "../src/protocol/schema";
|
||||
import { readFileSync, writeFileSync } from "node:fs";
|
||||
import { spawnSync } from "node:child_process";
|
||||
|
||||
run().catch(console.error);
|
||||
|
||||
async function run() {
|
||||
const cwd = new URL("../protocol/", import.meta.url);
|
||||
const runner = "Bun" in globalThis ? "bunx" : "npx";
|
||||
const write = (name: string, data: string) => {
|
||||
const path = new URL(name, cwd);
|
||||
writeFileSync(path, data);
|
||||
spawnSync(runner, ["prettier", "--write", path.pathname], { cwd, stdio: "ignore" });
|
||||
};
|
||||
const base = readFileSync(new URL("protocol.d.ts", cwd), "utf-8");
|
||||
const baseNoComments = base.replace(/\/\/.*/g, "");
|
||||
const jsc = await downloadJsc();
|
||||
write("jsc/protocol.json", JSON.stringify(jsc));
|
||||
write("jsc/index.d.ts", "// GENERATED - DO NOT EDIT\n" + formatProtocol(jsc, baseNoComments));
|
||||
const v8 = await downloadV8();
|
||||
write("v8/protocol.json", JSON.stringify(v8));
|
||||
write("v8/index.d.ts", "// GENERATED - DO NOT EDIT\n" + formatProtocol(v8, baseNoComments));
|
||||
}
|
||||
|
||||
function formatProtocol(protocol: Protocol, extraTs?: string): string {
|
||||
const { name, domains } = protocol;
|
||||
const eventMap = new Map();
|
||||
const commandMap = new Map();
|
||||
let body = `export namespace ${name} {`;
|
||||
for (const { domain, types = [], events = [], commands = [] } of domains) {
|
||||
body += `export namespace ${domain} {`;
|
||||
for (const type of types) {
|
||||
body += formatProperty(type);
|
||||
}
|
||||
for (const { name, description, parameters = [] } of events) {
|
||||
const symbol = `${domain}.${name}`;
|
||||
const title = toTitle(name);
|
||||
eventMap.set(symbol, `${domain}.${title}`);
|
||||
body += formatProperty({
|
||||
id: `${title}Event`,
|
||||
type: "object",
|
||||
description: `${description}\n@event \`${symbol}\``,
|
||||
properties: parameters,
|
||||
});
|
||||
}
|
||||
for (const { name, description, parameters = [], returns = [] } of commands) {
|
||||
const symbol = `${domain}.${name}`;
|
||||
const title = toTitle(name);
|
||||
commandMap.set(symbol, `${domain}.${title}`);
|
||||
body += formatProperty({
|
||||
id: `${title}Request`,
|
||||
type: "object",
|
||||
description: `${description}\n@request \`${symbol}\``,
|
||||
properties: parameters,
|
||||
});
|
||||
body += formatProperty({
|
||||
id: `${title}Response`,
|
||||
type: "object",
|
||||
description: `${description}\n@response \`${symbol}\``,
|
||||
properties: returns,
|
||||
});
|
||||
}
|
||||
body += "};";
|
||||
}
|
||||
for (const type of ["Event", "Request", "Response"]) {
|
||||
const sourceMap = type === "Event" ? eventMap : commandMap;
|
||||
body += formatProperty({
|
||||
id: `${type}Map`,
|
||||
type: "object",
|
||||
properties: [...sourceMap.entries()].map(([name, title]) => ({
|
||||
name: `"${name}"`,
|
||||
type: undefined,
|
||||
$ref: `${title}${type}`,
|
||||
})),
|
||||
});
|
||||
}
|
||||
if (extraTs) {
|
||||
body += extraTs;
|
||||
}
|
||||
return body + "};";
|
||||
}
|
||||
|
||||
function formatProperty(property: Property): string {
|
||||
const { id, description, type, optional } = property;
|
||||
let body = "";
|
||||
if (id) {
|
||||
if (description) {
|
||||
body += `\n${toComment(description)}\n`;
|
||||
}
|
||||
body += `export type ${id}=`;
|
||||
}
|
||||
if (type === "boolean") {
|
||||
body += "boolean";
|
||||
} else if (type === "number" || type === "integer") {
|
||||
body += "number";
|
||||
} else if (type === "string") {
|
||||
const { enum: choices } = property;
|
||||
if (choices) {
|
||||
body += choices.map(value => `"${value}"`).join("|");
|
||||
} else {
|
||||
body += "string";
|
||||
}
|
||||
} else if (type === "array") {
|
||||
const { items } = property;
|
||||
const itemType = items ? formatProperty(items) : "unknown";
|
||||
body += `${itemType}[]`;
|
||||
} else if (type === "object") {
|
||||
const { properties } = property;
|
||||
if (!properties) {
|
||||
body += "Record<string, unknown>";
|
||||
} else if (properties.length === 0) {
|
||||
body += "{}";
|
||||
} else {
|
||||
body += "{";
|
||||
for (const { name, description, ...property } of properties) {
|
||||
if (description) {
|
||||
body += `\n${toComment(description)}`;
|
||||
}
|
||||
const delimit = property.optional ? "?:" : ":";
|
||||
body += `\n${name}${delimit}${formatProperty({ ...property, id: undefined })};`;
|
||||
}
|
||||
body += "}";
|
||||
}
|
||||
} else if ("$ref" in property) {
|
||||
body += property.$ref;
|
||||
} else {
|
||||
body += "unknown";
|
||||
}
|
||||
if (optional) {
|
||||
body += "|undefined";
|
||||
}
|
||||
if (id) {
|
||||
body += ";";
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @link https://github.com/ChromeDevTools/devtools-protocol/tree/master/json
|
||||
*/
|
||||
async function downloadV8(): Promise<Protocol> {
|
||||
const baseUrl = "https://raw.githubusercontent.com/ChromeDevTools/devtools-protocol/master/json";
|
||||
const domains = ["Runtime", "Console", "Debugger", "Memory", "HeapProfiler", "Profiler", "Network", "Inspector"];
|
||||
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 => !domains.includes(domain.domain))
|
||||
.sort((a, b) => a.domain.localeCompare(b.domain)),
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @link https://github.com/WebKit/WebKit/tree/main/Source/JavaScriptCore/inspector/protocol
|
||||
*/
|
||||
async function downloadJsc(): Promise<Protocol> {
|
||||
const baseUrl = "https://raw.githubusercontent.com/WebKit/WebKit/main/Source/JavaScriptCore/inspector/protocol";
|
||||
const domains = [
|
||||
"Runtime",
|
||||
"Console",
|
||||
"Debugger",
|
||||
"Heap",
|
||||
"ScriptProfiler",
|
||||
"CPUProfiler",
|
||||
"GenericTypes",
|
||||
"Network",
|
||||
"Inspector",
|
||||
];
|
||||
return {
|
||||
name: "JSC",
|
||||
version: {
|
||||
major: 1,
|
||||
minor: 3,
|
||||
},
|
||||
domains: await Promise.all(domains.map(domain => download<Domain>(`${baseUrl}/${domain}.json`))).then(domains =>
|
||||
domains.sort((a, b) => a.domain.localeCompare(b.domain)),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
function toTitle(name: string): string {
|
||||
return name.charAt(0).toUpperCase() + name.slice(1);
|
||||
}
|
||||
|
||||
function toComment(description?: string): string {
|
||||
if (!description) {
|
||||
return "";
|
||||
}
|
||||
const lines = ["/**", ...description.split("\n").map(line => ` * ${line.trim()}`), "*/"];
|
||||
return lines.join("\n");
|
||||
}
|
||||
49
packages/bun-inspector-protocol/src/inspector/index.d.ts
vendored
Normal file
49
packages/bun-inspector-protocol/src/inspector/index.d.ts
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
import type { JSC } from "..";
|
||||
|
||||
/**
|
||||
* A client that can send and receive messages to/from a debugger.
|
||||
*/
|
||||
export abstract class Inspector {
|
||||
constructor(listener?: InspectorListener);
|
||||
/**
|
||||
* Starts the inspector.
|
||||
*/
|
||||
start(...args: unknown[]): void;
|
||||
/**
|
||||
* Sends a request to the debugger.
|
||||
*/
|
||||
send<M extends keyof JSC.RequestMap & keyof JSC.ResponseMap>(
|
||||
method: M,
|
||||
params?: JSC.RequestMap[M],
|
||||
): Promise<JSC.ResponseMap[M]>;
|
||||
/**
|
||||
* Accepts a message from the debugger.
|
||||
* @param message the unparsed message from the debugger
|
||||
*/
|
||||
accept(message: string): void;
|
||||
/**
|
||||
* If the inspector is closed.
|
||||
*/
|
||||
get closed(): boolean;
|
||||
/**
|
||||
* Closes the inspector.
|
||||
*/
|
||||
close(...args: unknown[]): void;
|
||||
}
|
||||
|
||||
export type InspectorListener = {
|
||||
/**
|
||||
* Defines a handler when a debugger event is received.
|
||||
*/
|
||||
[M in keyof JSC.EventMap]?: (event: JSC.EventMap[M]) => void;
|
||||
} & {
|
||||
/**
|
||||
* Defines a handler when the debugger is connected or reconnected.
|
||||
*/
|
||||
["Inspector.connected"]?: () => void;
|
||||
/**
|
||||
* Defines a handler when the debugger is disconnected.
|
||||
* @param error the error that caused the disconnect, if any
|
||||
*/
|
||||
["Inspector.disconnected"]?: (error?: Error) => void;
|
||||
};
|
||||
217
packages/bun-inspector-protocol/src/inspector/websocket.ts
Normal file
217
packages/bun-inspector-protocol/src/inspector/websocket.ts
Normal file
@@ -0,0 +1,217 @@
|
||||
import type { Inspector, InspectorListener } from ".";
|
||||
import type { JSC } from "../protocol";
|
||||
import { WebSocket } from "ws";
|
||||
|
||||
export type WebSocketInspectorOptions = {
|
||||
url?: string | URL;
|
||||
listener?: InspectorListener;
|
||||
logger?: (...messages: unknown[]) => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* An inspector that communicates with a debugger over a WebSocket.
|
||||
*/
|
||||
export class WebSocketInspector implements Inspector {
|
||||
#url?: URL;
|
||||
#webSocket?: WebSocket;
|
||||
#requestId: number;
|
||||
#pendingRequests: Map<number, (result: unknown) => void>;
|
||||
#pendingMessages: string[];
|
||||
#listener: InspectorListener;
|
||||
#log: (...messages: unknown[]) => void;
|
||||
|
||||
constructor({ url, listener, logger }: WebSocketInspectorOptions) {
|
||||
this.#url = url ? new URL(url) : undefined;
|
||||
this.#requestId = 1;
|
||||
this.#pendingRequests = new Map();
|
||||
this.#pendingMessages = [];
|
||||
this.#listener = listener ?? {};
|
||||
this.#log = logger ?? (() => {});
|
||||
}
|
||||
|
||||
start(url?: string | URL): void {
|
||||
if (url) {
|
||||
this.#url = new URL(url);
|
||||
}
|
||||
if (this.#url) {
|
||||
this.#connect();
|
||||
}
|
||||
}
|
||||
|
||||
#connect(): void {
|
||||
if (!this.#url) {
|
||||
return;
|
||||
}
|
||||
this.#webSocket?.close();
|
||||
|
||||
let webSocket: WebSocket;
|
||||
try {
|
||||
this.#log("connecting:", this.#url.href);
|
||||
webSocket = new WebSocket(this.#url, {
|
||||
headers: {
|
||||
"Ref-Event-Loop": "0",
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
this.#close(unknownToError(error));
|
||||
return;
|
||||
}
|
||||
|
||||
webSocket.addEventListener("open", () => {
|
||||
this.#log("connected");
|
||||
|
||||
for (const message of this.#pendingMessages) {
|
||||
this.#send(message);
|
||||
}
|
||||
|
||||
this.#pendingMessages.length = 0;
|
||||
this.#listener["Inspector.connected"]?.();
|
||||
});
|
||||
|
||||
webSocket.addEventListener("message", ({ data }) => {
|
||||
if (typeof data === "string") {
|
||||
this.accept(data);
|
||||
}
|
||||
});
|
||||
|
||||
webSocket.addEventListener("error", event => {
|
||||
this.#log("error:", event);
|
||||
this.#close(unknownToError(event));
|
||||
});
|
||||
|
||||
webSocket.addEventListener("unexpected-response", () => {
|
||||
this.#log("unexpected-response");
|
||||
this.#close(new Error("WebSocket upgrade failed"));
|
||||
});
|
||||
|
||||
webSocket.addEventListener("close", ({ code, reason }) => {
|
||||
this.#log("closed:", code, reason);
|
||||
|
||||
if (code === 1001) {
|
||||
this.#close();
|
||||
} else {
|
||||
this.#close(new Error(`WebSocket closed: ${code} ${reason}`.trimEnd()));
|
||||
}
|
||||
});
|
||||
|
||||
this.#webSocket = webSocket;
|
||||
}
|
||||
|
||||
send<M extends keyof JSC.RequestMap & keyof JSC.ResponseMap>(
|
||||
method: M,
|
||||
params?: JSC.RequestMap[M] | undefined,
|
||||
): Promise<JSC.ResponseMap[M]> {
|
||||
const id = this.#requestId++;
|
||||
const request = { id, method, params };
|
||||
|
||||
this.#log("-->", request);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const done = (result: any) => {
|
||||
this.#pendingRequests.delete(id);
|
||||
if (result instanceof Error) {
|
||||
reject(result);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
};
|
||||
|
||||
this.#pendingRequests.set(id, done);
|
||||
this.#send(JSON.stringify(request));
|
||||
});
|
||||
}
|
||||
|
||||
#send(message: string): void {
|
||||
if (this.#webSocket) {
|
||||
const { readyState } = this.#webSocket!;
|
||||
if (readyState === WebSocket.OPEN) {
|
||||
this.#webSocket.send(message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.#pendingMessages.includes(message)) {
|
||||
this.#pendingMessages.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
accept(message: string): void {
|
||||
let event: JSC.Event | JSC.Response;
|
||||
try {
|
||||
event = JSON.parse(message);
|
||||
} catch (error) {
|
||||
this.#log("Failed to parse message:", message);
|
||||
return;
|
||||
}
|
||||
|
||||
this.#log("<--", event);
|
||||
|
||||
if (!("id" in event)) {
|
||||
const { method, params } = event;
|
||||
try {
|
||||
this.#listener[method]?.(params as any);
|
||||
} catch (error) {
|
||||
this.#log(`Failed to accept ${method} event:`, error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = event;
|
||||
const resolve = this.#pendingRequests.get(id);
|
||||
if (!resolve) {
|
||||
this.#log("Failed to accept response with unknown ID:", id);
|
||||
return;
|
||||
}
|
||||
|
||||
this.#pendingRequests.delete(id);
|
||||
if ("error" in event) {
|
||||
const { error } = event;
|
||||
const { message } = error;
|
||||
resolve(new Error(message));
|
||||
} else {
|
||||
const { result } = event;
|
||||
resolve(result);
|
||||
}
|
||||
}
|
||||
|
||||
get closed(): boolean {
|
||||
if (!this.#webSocket) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const { readyState } = this.#webSocket;
|
||||
switch (readyState) {
|
||||
case WebSocket.CLOSED:
|
||||
case WebSocket.CLOSING:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
close(code?: number, reason?: string): void {
|
||||
this.#webSocket?.close(code ?? 1001, reason);
|
||||
}
|
||||
|
||||
#close(error?: Error): void {
|
||||
try {
|
||||
this.#listener["Inspector.disconnected"]?.(error);
|
||||
} finally {
|
||||
for (const resolve of this.#pendingRequests.values()) {
|
||||
resolve(error ?? new Error("WebSocket closed"));
|
||||
}
|
||||
this.#pendingRequests.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function unknownToError(input: unknown): Error {
|
||||
if (input instanceof Error) {
|
||||
return input;
|
||||
}
|
||||
if (typeof input === "object" && input !== null && "message" in input) {
|
||||
const { message } = input;
|
||||
return new Error(`${message}`);
|
||||
}
|
||||
return new Error(`${input}`);
|
||||
}
|
||||
1
packages/bun-inspector-protocol/src/protocol/index.d.ts
vendored
Normal file
1
packages/bun-inspector-protocol/src/protocol/index.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export type { JSC } from "./jsc";
|
||||
3695
packages/bun-inspector-protocol/src/protocol/jsc/index.d.ts
vendored
Normal file
3695
packages/bun-inspector-protocol/src/protocol/jsc/index.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3114
packages/bun-inspector-protocol/src/protocol/jsc/protocol.json
Normal file
3114
packages/bun-inspector-protocol/src/protocol/jsc/protocol.json
Normal file
File diff suppressed because it is too large
Load Diff
28
packages/bun-inspector-protocol/src/protocol/protocol.d.ts
vendored
Normal file
28
packages/bun-inspector-protocol/src/protocol/protocol.d.ts
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// @ts-nocheck
|
||||
// The content of this file is included in each generated protocol file.
|
||||
|
||||
export type Event<T extends keyof EventMap = keyof EventMap> = {
|
||||
readonly method: T;
|
||||
readonly params: EventMap[T];
|
||||
};
|
||||
|
||||
export type Request<T extends keyof RequestMap = keyof RequestMap> = {
|
||||
readonly id: number;
|
||||
readonly method: T;
|
||||
readonly params: RequestMap[T];
|
||||
};
|
||||
|
||||
export type Response<T extends keyof ResponseMap = keyof ResponseMap> = {
|
||||
readonly id: number;
|
||||
} & (
|
||||
| {
|
||||
readonly method?: T;
|
||||
readonly result: ResponseMap[T];
|
||||
}
|
||||
| {
|
||||
readonly error: {
|
||||
readonly code?: string;
|
||||
readonly message: string;
|
||||
};
|
||||
}
|
||||
);
|
||||
58
packages/bun-inspector-protocol/src/protocol/schema.d.ts
vendored
Normal file
58
packages/bun-inspector-protocol/src/protocol/schema.d.ts
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
// Represents the schema of the protocol.json file.
|
||||
|
||||
export type Protocol = {
|
||||
readonly name: string;
|
||||
readonly version: {
|
||||
readonly major: number;
|
||||
readonly minor: number;
|
||||
};
|
||||
readonly domains: readonly Domain[];
|
||||
};
|
||||
|
||||
export type Domain = {
|
||||
readonly domain: string;
|
||||
readonly dependencies?: readonly string[];
|
||||
readonly types: readonly Property[];
|
||||
readonly commands?: readonly Command[];
|
||||
readonly events?: readonly Event[];
|
||||
};
|
||||
|
||||
export type Command = {
|
||||
readonly name: string;
|
||||
readonly description?: string;
|
||||
readonly parameters?: readonly Property[];
|
||||
readonly returns?: readonly Property[];
|
||||
};
|
||||
|
||||
export type Event = {
|
||||
readonly name: string;
|
||||
readonly description?: string;
|
||||
readonly parameters: readonly Property[];
|
||||
};
|
||||
|
||||
export type Property = {
|
||||
readonly id?: string;
|
||||
readonly name?: string;
|
||||
readonly description?: string;
|
||||
readonly optional?: boolean;
|
||||
} & (
|
||||
| {
|
||||
readonly type: "array";
|
||||
readonly items?: Property;
|
||||
}
|
||||
| {
|
||||
readonly type: "object";
|
||||
readonly properties?: readonly Property[];
|
||||
}
|
||||
| {
|
||||
readonly type: "string";
|
||||
readonly enum?: readonly string[];
|
||||
}
|
||||
| {
|
||||
readonly type: "boolean" | "number" | "integer";
|
||||
}
|
||||
| {
|
||||
readonly type: undefined;
|
||||
readonly $ref: string;
|
||||
}
|
||||
);
|
||||
17428
packages/bun-inspector-protocol/src/protocol/v8/index.d.ts
vendored
Normal file
17428
packages/bun-inspector-protocol/src/protocol/v8/index.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
14136
packages/bun-inspector-protocol/src/protocol/v8/protocol.json
Normal file
14136
packages/bun-inspector-protocol/src/protocol/v8/protocol.json
Normal file
File diff suppressed because it is too large
Load Diff
113
packages/bun-inspector-protocol/src/util/preview.ts
Normal file
113
packages/bun-inspector-protocol/src/util/preview.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import type { JSC } from "../protocol";
|
||||
|
||||
export function remoteObjectToString(remoteObject: JSC.Runtime.RemoteObject, topLevel?: boolean): string {
|
||||
const { type, subtype, value, description, className, preview } = remoteObject;
|
||||
switch (type) {
|
||||
case "undefined":
|
||||
return "undefined";
|
||||
case "boolean":
|
||||
case "number":
|
||||
return description ?? JSON.stringify(value);
|
||||
case "string":
|
||||
if (topLevel) {
|
||||
return String(value ?? description);
|
||||
}
|
||||
return JSON.stringify(value ?? description);
|
||||
case "symbol":
|
||||
case "bigint":
|
||||
return description!;
|
||||
case "function":
|
||||
return description!.replace("function", "ƒ") || "ƒ";
|
||||
}
|
||||
switch (subtype) {
|
||||
case "null":
|
||||
return "null";
|
||||
case "regexp":
|
||||
case "date":
|
||||
case "error":
|
||||
return description!;
|
||||
}
|
||||
if (preview) {
|
||||
return objectPreviewToString(preview);
|
||||
}
|
||||
if (className) {
|
||||
return className;
|
||||
}
|
||||
return description || "Object";
|
||||
}
|
||||
|
||||
export function objectPreviewToString(objectPreview: JSC.Runtime.ObjectPreview): string {
|
||||
const { type, subtype, entries, properties, overflow, description, size } = objectPreview;
|
||||
if (type !== "object") {
|
||||
return remoteObjectToString(objectPreview);
|
||||
}
|
||||
let items: string[];
|
||||
if (entries) {
|
||||
items = entries.map(entryPreviewToString).sort();
|
||||
} else if (properties) {
|
||||
if (isIndexed(subtype)) {
|
||||
items = properties.map(indexedPropertyPreviewToString).sort();
|
||||
} else {
|
||||
items = properties.map(namedPropertyPreviewToString).sort();
|
||||
}
|
||||
} else {
|
||||
items = ["…"];
|
||||
}
|
||||
if (overflow) {
|
||||
items.push("…");
|
||||
}
|
||||
let label: string;
|
||||
if (description === "Object") {
|
||||
label = "";
|
||||
} else if (size === undefined) {
|
||||
label = description!;
|
||||
} else {
|
||||
label = `${description}(${size})`;
|
||||
}
|
||||
if (!items.length) {
|
||||
return label || "{}";
|
||||
}
|
||||
if (label) {
|
||||
label += " ";
|
||||
}
|
||||
if (isIndexed(subtype)) {
|
||||
return `${label}[${items.join(", ")}]`;
|
||||
}
|
||||
return `${label}{${items.join(", ")}}`;
|
||||
}
|
||||
|
||||
function propertyPreviewToString(propertyPreview: JSC.Runtime.PropertyPreview): string {
|
||||
const { type, value, ...preview } = propertyPreview;
|
||||
if (type === "accessor") {
|
||||
return "ƒ";
|
||||
}
|
||||
return remoteObjectToString({ ...preview, type, description: value });
|
||||
}
|
||||
|
||||
function entryPreviewToString(entryPreview: JSC.Runtime.EntryPreview): string {
|
||||
const { key, value } = entryPreview;
|
||||
if (key) {
|
||||
return `${objectPreviewToString(key)} => ${objectPreviewToString(value)}`;
|
||||
}
|
||||
return objectPreviewToString(value);
|
||||
}
|
||||
|
||||
function namedPropertyPreviewToString(propertyPreview: JSC.Runtime.PropertyPreview): string {
|
||||
const { name, valuePreview } = propertyPreview;
|
||||
if (valuePreview) {
|
||||
return `${name}: ${objectPreviewToString(valuePreview)}`;
|
||||
}
|
||||
return `${name}: ${propertyPreviewToString(propertyPreview)}`;
|
||||
}
|
||||
|
||||
function indexedPropertyPreviewToString(propertyPreview: JSC.Runtime.PropertyPreview): string {
|
||||
const { valuePreview } = propertyPreview;
|
||||
if (valuePreview) {
|
||||
return objectPreviewToString(valuePreview);
|
||||
}
|
||||
return propertyPreviewToString(propertyPreview);
|
||||
}
|
||||
|
||||
function isIndexed(type?: JSC.Runtime.RemoteObject["subtype"]): boolean {
|
||||
return type === "array" || type === "set" || type === "weakset";
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
// Bun Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`remoteObjectToString 1`] = `"undefined"`;
|
||||
|
||||
exports[`remoteObjectToString 2`] = `"null"`;
|
||||
|
||||
exports[`remoteObjectToString 3`] = `"true"`;
|
||||
|
||||
exports[`remoteObjectToString 4`] = `"false"`;
|
||||
|
||||
exports[`remoteObjectToString 5`] = `"0"`;
|
||||
|
||||
exports[`remoteObjectToString 6`] = `"1"`;
|
||||
|
||||
exports[`remoteObjectToString 7`] = `"3.141592653589793"`;
|
||||
|
||||
exports[`remoteObjectToString 8`] = `"-2.718281828459045"`;
|
||||
|
||||
exports[`remoteObjectToString 9`] = `"NaN"`;
|
||||
|
||||
exports[`remoteObjectToString 10`] = `"Infinity"`;
|
||||
|
||||
exports[`remoteObjectToString 11`] = `"-Infinity"`;
|
||||
|
||||
exports[`remoteObjectToString 12`] = `"0n"`;
|
||||
|
||||
exports[`remoteObjectToString 13`] = `"1n"`;
|
||||
|
||||
exports[`remoteObjectToString 14`] = `"10000000000000n"`;
|
||||
|
||||
exports[`remoteObjectToString 15`] = `"-10000000000000n"`;
|
||||
|
||||
exports[`remoteObjectToString 16`] = `""""`;
|
||||
|
||||
exports[`remoteObjectToString 17`] = `"" ""`;
|
||||
|
||||
exports[`remoteObjectToString 18`] = `""Hello""`;
|
||||
|
||||
exports[`remoteObjectToString 19`] = `""Hello World""`;
|
||||
|
||||
exports[`remoteObjectToString 20`] = `"Array(0)"`;
|
||||
|
||||
exports[`remoteObjectToString 21`] = `"Array(3) [1, 2, 3]"`;
|
||||
|
||||
exports[`remoteObjectToString 22`] = `"Array(4) ["a", 1, null, undefined]"`;
|
||||
|
||||
exports[`remoteObjectToString 23`] = `"Array(2) [1, Array]"`;
|
||||
|
||||
exports[`remoteObjectToString 24`] = `"Array(1) [Array]"`;
|
||||
|
||||
exports[`remoteObjectToString 25`] = `"{}"`;
|
||||
|
||||
exports[`remoteObjectToString 26`] = `"{a: 1}"`;
|
||||
|
||||
exports[`remoteObjectToString 27`] = `"{a: 1, b: 2, c: 3}"`;
|
||||
|
||||
exports[`remoteObjectToString 28`] = `"{a: Object}"`;
|
||||
|
||||
exports[`remoteObjectToString 29`] = `
|
||||
"ƒ() {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`remoteObjectToString 30`] = `
|
||||
"ƒ namedFunction() {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`remoteObjectToString 31`] = `
|
||||
"class {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`remoteObjectToString 32`] = `
|
||||
"class namedClass {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`remoteObjectToString 33`] = `
|
||||
"class namedClass {
|
||||
a() {
|
||||
}
|
||||
b = 1;
|
||||
c = [
|
||||
null,
|
||||
undefined,
|
||||
"a",
|
||||
{
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3
|
||||
}
|
||||
];
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`remoteObjectToString 34`] = `"Wed Dec 31 1969 16:00:00 GMT-0800 (Pacific Standard Time)"`;
|
||||
|
||||
exports[`remoteObjectToString 35`] = `"Invalid Date"`;
|
||||
|
||||
exports[`remoteObjectToString 36`] = `"/(?:)/"`;
|
||||
|
||||
exports[`remoteObjectToString 37`] = `"/abc/"`;
|
||||
|
||||
exports[`remoteObjectToString 38`] = `"/abc/g"`;
|
||||
|
||||
exports[`remoteObjectToString 39`] = `"/abc/"`;
|
||||
|
||||
exports[`remoteObjectToString 40`] = `"Set(0)"`;
|
||||
|
||||
exports[`remoteObjectToString 41`] = `"Set(3) [1, 2, 3]"`;
|
||||
|
||||
exports[`remoteObjectToString 42`] = `"WeakSet(0)"`;
|
||||
|
||||
exports[`remoteObjectToString 43`] = `"WeakSet(3) [{a: 1}, {b: 2}, {c: 3}]"`;
|
||||
|
||||
exports[`remoteObjectToString 44`] = `"Map(0)"`;
|
||||
|
||||
exports[`remoteObjectToString 45`] = `"Map(3) {"a" => 1, "b" => 2, "c" => 3}"`;
|
||||
|
||||
exports[`remoteObjectToString 46`] = `"WeakMap(0)"`;
|
||||
|
||||
exports[`remoteObjectToString 47`] = `"WeakMap(3) {{a: 1} => 1, {b: 2} => 2, {c: 3} => 3}"`;
|
||||
|
||||
exports[`remoteObjectToString 48`] = `"Symbol()"`;
|
||||
|
||||
exports[`remoteObjectToString 49`] = `"Symbol(namedSymbol)"`;
|
||||
|
||||
exports[`remoteObjectToString 50`] = `"Error"`;
|
||||
|
||||
exports[`remoteObjectToString 51`] = `"TypeError: This is a TypeError"`;
|
||||
|
||||
exports[`remoteObjectToString 52`] = `"Headers {append: ƒ, delete: ƒ, get: ƒ, getAll: ƒ, has: ƒ, …}"`;
|
||||
|
||||
exports[`remoteObjectToString 53`] = `"Headers {a: "1", append: ƒ, b: "2", delete: ƒ, get: ƒ, …}"`;
|
||||
|
||||
exports[`remoteObjectToString 54`] = `"Request {arrayBuffer: ƒ, blob: ƒ, body: null, bodyUsed: false, cache: "default", …}"`;
|
||||
|
||||
exports[`remoteObjectToString 55`] = `"Request {arrayBuffer: ƒ, blob: ƒ, body: ReadableStream, bodyUsed: false, cache: "default", …}"`;
|
||||
|
||||
exports[`remoteObjectToString 56`] = `"Response {arrayBuffer: ƒ, blob: ƒ, body: null, bodyUsed: false, clone: ƒ, …}"`;
|
||||
|
||||
exports[`remoteObjectToString 57`] = `"Response {arrayBuffer: ƒ, blob: ƒ, body: ReadableStream, bodyUsed: false, clone: ƒ, …}"`;
|
||||
99
packages/bun-inspector-protocol/test/util/preview.js
Normal file
99
packages/bun-inspector-protocol/test/util/preview.js
Normal file
@@ -0,0 +1,99 @@
|
||||
console.log(
|
||||
undefined,
|
||||
null,
|
||||
true,
|
||||
false,
|
||||
0,
|
||||
1,
|
||||
Math.PI,
|
||||
-Math.E,
|
||||
NaN,
|
||||
Infinity,
|
||||
-Infinity,
|
||||
BigInt(0),
|
||||
BigInt(1),
|
||||
BigInt("10000000000000"),
|
||||
BigInt("-10000000000000"),
|
||||
"",
|
||||
" ",
|
||||
"Hello",
|
||||
"Hello World",
|
||||
[],
|
||||
[1, 2, 3],
|
||||
["a", 1, null, undefined],
|
||||
[1, [2, [3, [4, [5, [6, [7, [8, [9, [10]]]]]]]]]],
|
||||
[[[[[]]]]],
|
||||
{},
|
||||
{ a: 1 },
|
||||
{ a: 1, b: 2, c: 3 },
|
||||
{ a: { b: { c: { d: { e: { f: { g: { h: { i: { j: 10 } } } } } } } } } },
|
||||
function () {},
|
||||
function namedFunction() {},
|
||||
class {},
|
||||
class namedClass {},
|
||||
class namedClass {
|
||||
a() {}
|
||||
b = 1;
|
||||
c = [
|
||||
null,
|
||||
undefined,
|
||||
"a",
|
||||
{
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
},
|
||||
];
|
||||
},
|
||||
new Date(0),
|
||||
new Date(NaN),
|
||||
new RegExp(),
|
||||
new RegExp("abc"),
|
||||
new RegExp("abc", "g"),
|
||||
/abc/,
|
||||
new Set(),
|
||||
new Set([1, 2, 3]),
|
||||
new WeakSet(),
|
||||
new WeakSet([{ a: 1 }, { b: 2 }, { c: 3 }]),
|
||||
new Map(),
|
||||
new Map([
|
||||
["a", 1],
|
||||
["b", 2],
|
||||
["c", 3],
|
||||
]),
|
||||
new WeakMap(),
|
||||
new WeakMap([
|
||||
[{ a: 1 }, 1],
|
||||
[{ b: 2 }, 2],
|
||||
[{ c: 3 }, 3],
|
||||
]),
|
||||
Symbol(),
|
||||
Symbol("namedSymbol"),
|
||||
new Error(),
|
||||
new TypeError("This is a TypeError"),
|
||||
//"a".repeat(10000),
|
||||
//["a"].fill("a", 0, 10000),
|
||||
new Headers(),
|
||||
new Headers({
|
||||
a: "1",
|
||||
b: "2",
|
||||
}),
|
||||
new Request("https://example.com/"),
|
||||
new Request("https://example.com/", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
a: "1",
|
||||
b: "2",
|
||||
},
|
||||
body: '{"example":true}',
|
||||
}),
|
||||
new Response(),
|
||||
new Response('{"example":true}', {
|
||||
status: 200,
|
||||
statusText: "OK",
|
||||
headers: {
|
||||
a: "1",
|
||||
b: "2",
|
||||
},
|
||||
}),
|
||||
);
|
||||
61
packages/bun-inspector-protocol/test/util/preview.test.ts
Normal file
61
packages/bun-inspector-protocol/test/util/preview.test.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { beforeAll, afterAll, test, expect } from "bun:test";
|
||||
import type { PipedSubprocess } from "bun";
|
||||
import { spawn } from "bun";
|
||||
import type { JSC } from "../..";
|
||||
import { WebSocketInspector, remoteObjectToString } from "../..";
|
||||
|
||||
let subprocess: PipedSubprocess | undefined;
|
||||
let objects: JSC.Runtime.RemoteObject[] = [];
|
||||
|
||||
beforeAll(async () => {
|
||||
subprocess = spawn({
|
||||
cwd: import.meta.dir,
|
||||
cmd: [process.argv0, "--inspect-wait=0", "preview.js"],
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
stdin: "pipe",
|
||||
});
|
||||
const decoder = new TextDecoder();
|
||||
let url: URL;
|
||||
for await (const chunk of subprocess!.stdout) {
|
||||
const text = decoder.decode(chunk);
|
||||
if (text.includes("ws://")) {
|
||||
url = new URL(/(ws:\/\/.*)/.exec(text)![0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
objects = await new Promise((resolve, reject) => {
|
||||
const inspector = new WebSocketInspector({
|
||||
url,
|
||||
listener: {
|
||||
["Inspector.connected"]: () => {
|
||||
inspector.send("Inspector.enable");
|
||||
inspector.send("Runtime.enable");
|
||||
inspector.send("Console.enable");
|
||||
inspector.send("Debugger.enable");
|
||||
inspector.send("Debugger.resume");
|
||||
inspector.send("Inspector.initialized");
|
||||
},
|
||||
["Inspector.disconnected"]: error => {
|
||||
reject(error);
|
||||
},
|
||||
["Console.messageAdded"]: ({ message }) => {
|
||||
const { parameters } = message;
|
||||
resolve(parameters!);
|
||||
inspector.close();
|
||||
},
|
||||
},
|
||||
});
|
||||
inspector.start();
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
subprocess?.kill();
|
||||
});
|
||||
|
||||
test("remoteObjectToString", () => {
|
||||
for (const object of objects) {
|
||||
expect(remoteObjectToString(object)).toMatchSnapshot();
|
||||
}
|
||||
});
|
||||
18
packages/bun-inspector-protocol/tsconfig.json
Normal file
18
packages/bun-inspector-protocol/tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext"],
|
||||
"module": "ESNext",
|
||||
"target": "ESNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"moduleDetection": "force",
|
||||
"strict": true,
|
||||
"downlevelIteration": true,
|
||||
"skipLibCheck": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"inlineSourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "dist",
|
||||
},
|
||||
"include": [".", "../bun-types/index.d.ts"]
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"name": "bun-lambda",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"bun-types": "^0.7.0",
|
||||
"jszip": "^3.10.1",
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"ESNext"
|
||||
],
|
||||
"lib": ["ESNext"],
|
||||
"module": "esnext",
|
||||
"target": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"moduleDetection": "force",
|
||||
"allowImportingTsExtensions": true,
|
||||
"noEmit": true,
|
||||
"composite": true,
|
||||
"strict": true,
|
||||
"downlevelIteration": true,
|
||||
"skipLibCheck": true,
|
||||
@@ -19,8 +19,5 @@
|
||||
"bun-types" // add Bun global
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"modules.d.ts"
|
||||
]
|
||||
}
|
||||
"include": ["**/*.ts", "modules.d.ts"]
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"ESNext"
|
||||
],
|
||||
"lib": ["ESNext"],
|
||||
"module": "esnext",
|
||||
"target": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"moduleDetection": "force",
|
||||
"allowImportingTsExtensions": true,
|
||||
"noEmit": true,
|
||||
"composite": true,
|
||||
"strict": true,
|
||||
"downlevelIteration": true,
|
||||
"skipLibCheck": true,
|
||||
@@ -19,8 +19,5 @@
|
||||
"bun-types" // add Bun global
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"modules.d.ts"
|
||||
]
|
||||
}
|
||||
"include": ["**/*.ts", "modules.d.ts"]
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -15,11 +15,13 @@
|
||||
"node": "node --enable-source-maps --import ./dist/src/repl.js",
|
||||
"clean": "rm -rf dist",
|
||||
"preprocess": "bun tools/updateversions.ts",
|
||||
"build": "bun run clean && bun run preprocess && bunx tsc && bunx copyfiles \"./**/*.wasm\" dist",
|
||||
"build": "bun run clean && bun run preprocess && bunx tsc && bunx copyfiles \"./lib/**/*.wasm\" dist",
|
||||
"build/wasm": "bun run build/zighash",
|
||||
"build/zighash": "cd lib/zighash && bun run build && cd ../.."
|
||||
},
|
||||
"dependencies": {
|
||||
"bun-wasm": "link:bun-wasm",
|
||||
"chalk": "^5.3.0",
|
||||
"js-md4": "^0.3.2",
|
||||
"open-editor": "^4.0.0",
|
||||
"supports-color": "^9.4.0",
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
} from './bun/hashes.js';
|
||||
import { ArrayBufferSink as ArrayBufferSinkPolyfill } from './bun/arraybuffersink.js';
|
||||
import { FileBlob, NodeJSStreamFileBlob } from './bun/fileblob.js';
|
||||
import TranspilerImpl from './bun/transpiler.js';
|
||||
import fs from 'node:fs';
|
||||
import v8 from 'node:v8';
|
||||
import path from 'node:path';
|
||||
@@ -32,7 +33,7 @@ export const main = path.resolve(process.cwd(), process.argv[1] ?? 'repl') satis
|
||||
|
||||
//? These are automatically updated on build by tools/updateversions.ts, do not edit manually.
|
||||
export const version = '0.7.4' satisfies typeof Bun.version;
|
||||
export const revision = '7088d7e182635a58a50860302da0b1abc42c7ce7' satisfies typeof Bun.revision;
|
||||
export const revision = '56816a3ec845a4b9fc40ade34dbe5c0033433d51' satisfies typeof Bun.revision;
|
||||
|
||||
export const gc = (globalThis.gc ? (() => (globalThis.gc!(), process.memoryUsage().heapUsed)) : (() => {
|
||||
const err = new Error('[bun-polyfills] Garbage collection polyfills are only available when Node.js is ran with the --expose-gc flag.');
|
||||
@@ -71,6 +72,8 @@ export const unsafe = {
|
||||
}
|
||||
} satisfies typeof Bun['unsafe'];
|
||||
|
||||
export const Transpiler = TranspilerImpl satisfies typeof Bun.Transpiler;
|
||||
|
||||
export const SHA1 = SHA1Polyfill satisfies typeof Bun.SHA1;
|
||||
export const MD5 = MD5Polyfill satisfies typeof Bun.MD5;
|
||||
export const MD4 = MD4Polyfill satisfies typeof Bun.MD4;
|
||||
|
||||
@@ -1,103 +1,96 @@
|
||||
import type { JavaScriptLoader, TranspilerOptions, Transpiler as BunTranspiler, Import } from 'bun';
|
||||
import { NotImplementedError } from '../../utils/errors.js';
|
||||
import { transformSync, scan, init } from 'bun-wasm';
|
||||
import { Message } from 'bun-wasm/schema';
|
||||
import $ from 'chalk';
|
||||
|
||||
// TODO: Possible implementation with WASM builds of bun with just the transpiler?
|
||||
// NOTE: This is possible to implement with something like SWC, and was previously done,
|
||||
// but it has lots of quirks due to the differences between SWC and Bun, so the plan is
|
||||
// to not do that unless there is actual demand for using Bun.Transpiler in Node.js before
|
||||
// the WASM build is worked on. The signatures are here for now as a placeholder.
|
||||
await init();
|
||||
|
||||
enum InternalImportKind {
|
||||
'entry-point' = 1, // entry_point
|
||||
'import-statement' = 2, // stmt
|
||||
'require-call' = 3, // require
|
||||
'dynamic-import' = 4, // dynamic
|
||||
'require-resolve' = 5, // require_resolve
|
||||
'import-rule' = 6, // at
|
||||
'url-token' = 7, // url
|
||||
'internal' = 8, // internal
|
||||
}
|
||||
|
||||
export type ScanImportsEntry = {
|
||||
kind: 'import-statement' | 'dynamic-import';
|
||||
path: string;
|
||||
};
|
||||
|
||||
export default class Transpiler implements BunTranspiler {
|
||||
constructor(options?: TranspilerOptions) {
|
||||
this.#options = options ?? {};
|
||||
this.#rootFile = 'input.tsx'; // + (this.#options.loader ?? 'tsx');
|
||||
//? ^ NOTE: with current bun-wasm builds, the loader option is ignored and hardcoded to tsx
|
||||
}
|
||||
#options: TranspilerOptions;
|
||||
#rootFile: string;
|
||||
#decoder?: TextDecoder;
|
||||
#internallyCalled: boolean = false;
|
||||
|
||||
async transform(code: StringOrBuffer, loader: JavaScriptLoader): Promise<string> {
|
||||
if (typeof code !== 'string') code = new TextDecoder().decode(code);
|
||||
throw new NotImplementedError('Bun.Transpiler', this.transform);
|
||||
this.#internallyCalled = true;
|
||||
return this.transformSync(code, loader);
|
||||
}
|
||||
|
||||
transformSync(code: StringOrBuffer, ctx: object): string;
|
||||
transformSync(code: StringOrBuffer, loader: JavaScriptLoader, ctx: object): string;
|
||||
transformSync(code: StringOrBuffer, loader?: JavaScriptLoader | undefined): string;
|
||||
transformSync(code: StringOrBuffer, loader?: JavaScriptLoader | object, ctx: object = {}): string {
|
||||
if (typeof code !== 'string') code = new TextDecoder().decode(code);
|
||||
if (typeof loader !== 'string') loader = 'js';
|
||||
throw new NotImplementedError('Bun.Transpiler', this.transformSync);
|
||||
if (!code) return ''; // wasm dies with empty string input
|
||||
if (typeof code !== 'string' && !(code instanceof Uint8Array)) throw new TypeError('code must be a string or Uint8Array');
|
||||
if (typeof loader !== 'string') loader = this.#options.loader;
|
||||
const result = transformSync(code, this.#rootFile, loader);
|
||||
// status 1 = success, status 2 = error
|
||||
if (result.status === 2) throw formatBuildErrors(result.errors, this.#internallyCalled ? this.transform : this.transformSync);
|
||||
this.#internallyCalled = false;
|
||||
this.#decoder ??= new TextDecoder();
|
||||
return this.#decoder.decode(result.files[0].data);
|
||||
}
|
||||
|
||||
scan(code: StringOrBuffer): { exports: string[]; imports: Import[]; } {
|
||||
if (typeof code !== 'string') code = new TextDecoder().decode(code);
|
||||
throw new NotImplementedError('Bun.Transpiler', this.scan);
|
||||
//return {
|
||||
// imports: this.scanImports(code),
|
||||
// exports: this.#scanExports(code)
|
||||
//};
|
||||
if (!code) return { exports: [], imports: [] }; // wasm dies with empty string input
|
||||
if (typeof code !== 'string' && !(code instanceof Uint8Array)) throw new TypeError('code must be a string or Uint8Array');
|
||||
|
||||
const result = scan(code, this.#rootFile, this.#options.loader);
|
||||
if (result.errors.length) throw formatBuildErrors(result.errors, this.#internallyCalled ? this.scanImports : this.scan);
|
||||
this.#internallyCalled = false;
|
||||
|
||||
result.imports.forEach(imp => (imp.kind as unknown) = InternalImportKind[imp.kind]);
|
||||
return {
|
||||
exports: result.exports,
|
||||
imports: result.imports as unknown as Import[],
|
||||
};
|
||||
}
|
||||
|
||||
scanImports(code: StringOrBuffer): {
|
||||
kind: 'import-statement' | 'dynamic-import';
|
||||
path: string;
|
||||
}[] {
|
||||
if (typeof code !== 'string') code = new TextDecoder().decode(code);
|
||||
throw new NotImplementedError('Bun.Transpiler', this.scanImports);
|
||||
//const imports: { kind: 'import-statement' | 'dynamic-import', path: string }[] = [];
|
||||
//this.#scanTopLevelImports(code).forEach(x => imports.push({ kind: 'import-statement', path: x }));
|
||||
//this.#scanDynamicImports(code).forEach(x => imports.push({ kind: 'dynamic-import', path: x }));
|
||||
//return imports;
|
||||
scanImports(code: StringOrBuffer): ScanImportsEntry[] {
|
||||
this.#internallyCalled = true;
|
||||
return this.scan(code).imports.filter(imp => imp.kind === 'import-statement' || imp.kind === 'dynamic-import') as ScanImportsEntry[];
|
||||
}
|
||||
|
||||
/*#scanDynamicImports(code: string): string[] {
|
||||
return this.parseSync(code, {
|
||||
syntax: this.#syntax, target: 'es2022', tsx: this.#options.loader === 'tsx'
|
||||
}).body.filter(x => x.type === 'ExpressionStatement' && x.expression.type === 'CallExpression' && x.expression.callee.type === 'Import')
|
||||
.map(i => (((i as swc.ExpressionStatement).expression as swc.CallExpression).arguments[0].expression as swc.StringLiteral).value);
|
||||
}*/
|
||||
|
||||
/*#scanTopLevelImports(code: string): string[] {
|
||||
return this.parseSync(code, {
|
||||
syntax: this.#syntax, target: 'es2022', tsx: this.#options.loader === 'tsx'
|
||||
}).body.filter(x => x.type === 'ImportDeclaration' || x.type === 'ExportAllDeclaration' || x.type === 'ExportNamedDeclaration')
|
||||
.filter(i => !(i as swc.ImportDeclaration).typeOnly)
|
||||
.map(i => (i as swc.ImportDeclaration).source.value);
|
||||
}*/
|
||||
|
||||
/*#scanExports(code: string, includeDefault: boolean = false): string[] {
|
||||
const parsed = this.parseSync(code, {
|
||||
syntax: this.#syntax, target: 'es2022', tsx: this.#options.loader === 'tsx'
|
||||
}).body;
|
||||
const exports = [];
|
||||
exports.push(parsed.filter(x => x.type === 'ExportDeclaration' && !x.declaration.declare)
|
||||
.flatMap(i => ((i as swc.ExportDeclaration).declaration as swc.ClassDeclaration).identifier?.value ??
|
||||
((i as swc.ExportDeclaration).declaration as swc.VariableDeclaration).declarations.map(d => (d.id as swc.Identifier).value)
|
||||
)
|
||||
);
|
||||
exports.push(parsed.filter(x => x.type === 'ExportNamedDeclaration')
|
||||
.flatMap(i => (i as swc.ExportNamedDeclaration).specifiers
|
||||
.filter(s => s.type === 'ExportSpecifier' && !s.isTypeOnly)
|
||||
.map(s => (s as swc.NamedExportSpecifier).exported?.value ?? (s as swc.NamedExportSpecifier).orig.value)
|
||||
)
|
||||
);
|
||||
if (includeDefault) exports.push(this.#scanDefaultExport(code) ?? []);
|
||||
return exports.flat();
|
||||
}*/
|
||||
|
||||
/*#scanDefaultExport(code: string): 'default' | undefined {
|
||||
const parsed = this.parseSync(code, {
|
||||
syntax: this.#syntax, target: 'es2022', tsx: this.#options.loader === 'tsx'
|
||||
}).body;
|
||||
|
||||
const defaultExportDecl = parsed.find(x => x.type === 'ExportDefaultDeclaration') as swc.ExportDefaultDeclaration | undefined;
|
||||
if (!defaultExportDecl) {
|
||||
const defaultExportExpr = parsed.find(x => x.type === 'ExportDefaultExpression') as swc.ExportDefaultExpression | undefined;
|
||||
if (!defaultExportExpr) return undefined;
|
||||
if (!defaultExportExpr.expression.type.startsWith('Ts')) return 'default';
|
||||
else return undefined;
|
||||
}
|
||||
|
||||
if (!defaultExportDecl.decl.type.startsWith('Ts') && !Reflect.get(defaultExportDecl.decl, 'declare')) return 'default';
|
||||
else return undefined;
|
||||
}*/
|
||||
|
||||
#options: TranspilerOptions;
|
||||
}
|
||||
|
||||
function formatBuildErrors(buildErrors: Message[], caller: Transpiler[keyof Transpiler]): AggregateError {
|
||||
const formatted = buildErrors.map(err => {
|
||||
const loc = err.data.location;
|
||||
const str = `${$.redBright('error')}${$.gray(':')} ${$.bold(err.data.text)}\n` +
|
||||
(loc
|
||||
? `${highlightErrorChar(loc.line_text, loc.offset)}\n` +
|
||||
$.redBright.bold('^'.padStart(loc.column)) + '\n' +
|
||||
`${$.bold(loc.file)}${$.gray(':')}${$.yellowBright(loc.line)}${$.gray(':')}${$.yellowBright(loc.column)} ${$.gray(loc.offset)}`
|
||||
: ''
|
||||
);
|
||||
return { __proto__: Error.prototype, stack: str };
|
||||
});
|
||||
const aggregate = new AggregateError(formatted, `Input code has ${formatted.length} error${formatted.length === 1 ? '' : 's'}`);
|
||||
Error.captureStackTrace(aggregate, caller);
|
||||
aggregate.name = 'BuildError';
|
||||
return aggregate;
|
||||
}
|
||||
|
||||
function highlightErrorChar(str: string, at: number): string {
|
||||
return str.slice(0, at) + $.red(str[at]) + str.slice(at + 1);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ globalThis.Bun = bun as typeof bun & {
|
||||
mmap: typeof import('bun').mmap;
|
||||
connect: typeof import('bun').connect;
|
||||
listen: typeof import('bun').listen;
|
||||
Transpiler: typeof import('bun').Transpiler;
|
||||
password: typeof import('bun').password;
|
||||
CryptoHashInterface: typeof import('bun').CryptoHashInterface;
|
||||
CryptoHasher: typeof import('bun').CryptoHasher;
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
"outDir": "dist",
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": [".", "../bun-types/index.d.ts"],
|
||||
"include": ["src", "lib", "../bun-types/index.d.ts"],
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"name": "bun-release-action",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"aws4fetch": "^1.0.17",
|
||||
|
||||
2
packages/bun-types/bun.d.ts
vendored
2
packages/bun-types/bun.d.ts
vendored
@@ -2308,7 +2308,7 @@ declare module "bun" {
|
||||
*
|
||||
* @param args
|
||||
*/
|
||||
export function inspect(arg: any, options: BunInspectOptions): string;
|
||||
export function inspect(arg: any, options?: BunInspectOptions): string;
|
||||
export namespace inspect {
|
||||
/**
|
||||
* That can be used to declare custom inspect functions.
|
||||
|
||||
262
packages/bun-types/ffi.d.ts
vendored
262
packages/bun-types/ffi.d.ts
vendored
@@ -350,7 +350,7 @@ declare module "bun:ffi" {
|
||||
type UNTYPED = never;
|
||||
export type Pointer = number & {};
|
||||
|
||||
interface FFITypeToType {
|
||||
interface FFITypeToArgsType {
|
||||
[FFIType.char]: number;
|
||||
[FFIType.int8_t]: number;
|
||||
[FFIType.i8]: number;
|
||||
@@ -365,22 +365,54 @@ declare module "bun:ffi" {
|
||||
[FFIType.int]: number;
|
||||
[FFIType.uint32_t]: number;
|
||||
[FFIType.u32]: number;
|
||||
[FFIType.int64_t]: number;
|
||||
[FFIType.i64]: number;
|
||||
[FFIType.uint64_t]: number;
|
||||
[FFIType.u64]: number;
|
||||
[FFIType.int64_t]: number | bigint;
|
||||
[FFIType.i64]: number | bigint;
|
||||
[FFIType.uint64_t]: number | bigint;
|
||||
[FFIType.u64]: number | bigint;
|
||||
[FFIType.double]: number;
|
||||
[FFIType.f64]: number;
|
||||
[FFIType.float]: number;
|
||||
[FFIType.f32]: number;
|
||||
[FFIType.bool]: boolean;
|
||||
[FFIType.ptr]: Pointer;
|
||||
[FFIType.pointer]: Pointer;
|
||||
[FFIType.ptr]: TypedArray | Pointer | CString | null;
|
||||
[FFIType.pointer]: TypedArray | Pointer | CString | null;
|
||||
[FFIType.void]: void;
|
||||
[FFIType.cstring]: TypedArray | Pointer | CString | null;
|
||||
[FFIType.i64_fast]: number | bigint;
|
||||
[FFIType.u64_fast]: number | bigint;
|
||||
[FFIType.function]: Pointer | JSCallback; // cannot be null
|
||||
}
|
||||
interface FFITypeToReturnsType {
|
||||
[FFIType.char]: number;
|
||||
[FFIType.int8_t]: number;
|
||||
[FFIType.i8]: number;
|
||||
[FFIType.uint8_t]: number;
|
||||
[FFIType.u8]: number;
|
||||
[FFIType.int16_t]: number;
|
||||
[FFIType.i16]: number;
|
||||
[FFIType.uint16_t]: number;
|
||||
[FFIType.u16]: number;
|
||||
[FFIType.int32_t]: number;
|
||||
[FFIType.i32]: number;
|
||||
[FFIType.int]: number;
|
||||
[FFIType.uint32_t]: number;
|
||||
[FFIType.u32]: number;
|
||||
[FFIType.int64_t]: bigint;
|
||||
[FFIType.i64]: bigint;
|
||||
[FFIType.uint64_t]: bigint;
|
||||
[FFIType.u64]: bigint;
|
||||
[FFIType.double]: number;
|
||||
[FFIType.f64]: number;
|
||||
[FFIType.float]: number;
|
||||
[FFIType.f32]: number;
|
||||
[FFIType.bool]: boolean;
|
||||
[FFIType.ptr]: Pointer | null;
|
||||
[FFIType.pointer]: Pointer | null;
|
||||
[FFIType.void]: void;
|
||||
[FFIType.cstring]: CString;
|
||||
[FFIType.i64_fast]: number | bigint;
|
||||
[FFIType.u64_fast]: number | bigint;
|
||||
[FFIType.function]: (...args: any[]) => any;
|
||||
[FFIType.function]: Pointer | null;
|
||||
}
|
||||
interface FFITypeStringToType {
|
||||
["char"]: FFIType.char;
|
||||
@@ -417,36 +449,7 @@ declare module "bun:ffi" {
|
||||
|
||||
export type FFITypeOrString =
|
||||
| FFIType
|
||||
| "char"
|
||||
| "int8_t"
|
||||
| "i8"
|
||||
| "uint8_t"
|
||||
| "u8"
|
||||
| "int16_t"
|
||||
| "i16"
|
||||
| "uint16_t"
|
||||
| "u16"
|
||||
| "int32_t"
|
||||
| "i32"
|
||||
| "int"
|
||||
| "uint32_t"
|
||||
| "u32"
|
||||
| "int64_t"
|
||||
| "i64"
|
||||
| "uint64_t"
|
||||
| "u64"
|
||||
| "double"
|
||||
| "f64"
|
||||
| "float"
|
||||
| "f32"
|
||||
| "bool"
|
||||
| "ptr"
|
||||
| "pointer"
|
||||
| "void"
|
||||
| "cstring"
|
||||
| "function"
|
||||
| "usize"
|
||||
| "callback";
|
||||
| keyof FFITypeStringToType;
|
||||
|
||||
interface FFIFunction {
|
||||
/**
|
||||
@@ -477,7 +480,7 @@ declare module "bun:ffi" {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
args?: FFITypeOrString[];
|
||||
readonly args?: readonly FFITypeOrString[];
|
||||
/**
|
||||
* Return type to a FFI function (C ABI)
|
||||
*
|
||||
@@ -505,7 +508,7 @@ declare module "bun:ffi" {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
returns?: FFITypeOrString;
|
||||
readonly returns?: FFITypeOrString;
|
||||
|
||||
/**
|
||||
* Function pointer to the native function
|
||||
@@ -516,7 +519,7 @@ declare module "bun:ffi" {
|
||||
* This is useful if the library has already been loaded
|
||||
* or if the module is also using Node-API.
|
||||
*/
|
||||
ptr?: number | bigint;
|
||||
readonly ptr?: number | bigint;
|
||||
|
||||
/**
|
||||
* Can C/FFI code call this function from a separate thread?
|
||||
@@ -533,10 +536,10 @@ declare module "bun:ffi" {
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
threadsafe?: boolean;
|
||||
readonly threadsafe?: boolean;
|
||||
}
|
||||
|
||||
type Symbols = Record<string, FFIFunction>;
|
||||
type Symbols = Readonly<Record<string, FFIFunction>>;
|
||||
|
||||
// /**
|
||||
// * Compile a callback function
|
||||
@@ -546,7 +549,7 @@ declare module "bun:ffi" {
|
||||
// */
|
||||
// export function callback(ffi: FFIFunction, cb: Function): number;
|
||||
|
||||
export interface Library<Fns extends Record<string, Narrow<FFIFunction>>> {
|
||||
export interface Library<Fns extends Readonly<Record<string, Narrow<FFIFunction>>>> {
|
||||
symbols: ConvertFns<Fns>;
|
||||
|
||||
/**
|
||||
@@ -577,12 +580,14 @@ declare module "bun:ffi" {
|
||||
| (T extends object ? { [K in keyof T]: Narrow<T[K]> } : never)
|
||||
| Extract<{} | null | undefined, T>;
|
||||
|
||||
type ConvertFns<Fns extends Record<string, FFIFunction>> = {
|
||||
type ConvertFns<Fns extends Readonly<Record<string, FFIFunction>>> = {
|
||||
[K in keyof Fns]: (
|
||||
...args: Fns[K]["args"] extends infer A extends FFITypeOrString[]
|
||||
? { [L in keyof A]: FFITypeToType[ToFFIType<A[L]>] }
|
||||
: never
|
||||
) => FFITypeToType[ToFFIType<NonNullable<Fns[K]["returns"]>>];
|
||||
...args: Fns[K]["args"] extends infer A extends readonly FFITypeOrString[]
|
||||
? { [L in keyof A]: FFITypeToArgsType[ToFFIType<A[L]>] }
|
||||
: [unknown] extends [Fns[K]["args"]] ? [] : never
|
||||
) => [unknown] extends [Fns[K]["returns"]]
|
||||
? void
|
||||
: FFITypeToReturnsType[ToFFIType<NonNullable<Fns[K]["returns"]>>];
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -750,6 +755,165 @@ declare module "bun:ffi" {
|
||||
byteLength?: number,
|
||||
): ArrayBuffer;
|
||||
|
||||
export namespace read {
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
* While there are some checks to catch invalid pointers, this is a difficult
|
||||
* thing to do safely. Passing an invalid pointer can crash the program and
|
||||
* reading beyond the bounds of the pointer will crash the program or cause
|
||||
* undefined behavior. Use with care!
|
||||
*/
|
||||
export function u8(ptr: Pointer, byteOffset?: number): number;
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
* While there are some checks to catch invalid pointers, this is a difficult
|
||||
* thing to do safely. Passing an invalid pointer can crash the program and
|
||||
* reading beyond the bounds of the pointer will crash the program or cause
|
||||
* undefined behavior. Use with care!
|
||||
*/
|
||||
export function i8(ptr: Pointer, byteOffset?: number): number;
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
* While there are some checks to catch invalid pointers, this is a difficult
|
||||
* thing to do safely. Passing an invalid pointer can crash the program and
|
||||
* reading beyond the bounds of the pointer will crash the program or cause
|
||||
* undefined behavior. Use with care!
|
||||
*/
|
||||
export function u16(ptr: Pointer, byteOffset?: number): number;
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
* While there are some checks to catch invalid pointers, this is a difficult
|
||||
* thing to do safely. Passing an invalid pointer can crash the program and
|
||||
* reading beyond the bounds of the pointer will crash the program or cause
|
||||
* undefined behavior. Use with care!
|
||||
*/
|
||||
export function i16(ptr: Pointer, byteOffset?: number): number;
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
* While there are some checks to catch invalid pointers, this is a difficult
|
||||
* thing to do safely. Passing an invalid pointer can crash the program and
|
||||
* reading beyond the bounds of the pointer will crash the program or cause
|
||||
* undefined behavior. Use with care!
|
||||
*/
|
||||
export function u32(ptr: Pointer, byteOffset?: number): number;
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
* While there are some checks to catch invalid pointers, this is a difficult
|
||||
* thing to do safely. Passing an invalid pointer can crash the program and
|
||||
* reading beyond the bounds of the pointer will crash the program or cause
|
||||
* undefined behavior. Use with care!
|
||||
*/
|
||||
export function i32(ptr: Pointer, byteOffset?: number): number;
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
* While there are some checks to catch invalid pointers, this is a difficult
|
||||
* thing to do safely. Passing an invalid pointer can crash the program and
|
||||
* reading beyond the bounds of the pointer will crash the program or cause
|
||||
* undefined behavior. Use with care!
|
||||
*/
|
||||
export function f32(ptr: Pointer, byteOffset?: number): number;
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
* While there are some checks to catch invalid pointers, this is a difficult
|
||||
* thing to do safely. Passing an invalid pointer can crash the program and
|
||||
* reading beyond the bounds of the pointer will crash the program or cause
|
||||
* undefined behavior. Use with care!
|
||||
*/
|
||||
export function u64(ptr: Pointer, byteOffset?: number): bigint;
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
* While there are some checks to catch invalid pointers, this is a difficult
|
||||
* thing to do safely. Passing an invalid pointer can crash the program and
|
||||
* reading beyond the bounds of the pointer will crash the program or cause
|
||||
* undefined behavior. Use with care!
|
||||
*/
|
||||
export function i64(ptr: Pointer, byteOffset?: number): bigint;
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
* While there are some checks to catch invalid pointers, this is a difficult
|
||||
* thing to do safely. Passing an invalid pointer can crash the program and
|
||||
* reading beyond the bounds of the pointer will crash the program or cause
|
||||
* undefined behavior. Use with care!
|
||||
*/
|
||||
export function f64(ptr: Pointer, byteOffset?: number): number;
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
* While there are some checks to catch invalid pointers, this is a difficult
|
||||
* thing to do safely. Passing an invalid pointer can crash the program and
|
||||
* reading beyond the bounds of the pointer will crash the program or cause
|
||||
* undefined behavior. Use with care!
|
||||
*/
|
||||
export function ptr(ptr: Pointer, byteOffset?: number): number;
|
||||
/**
|
||||
* The read function behaves similarly to DataView,
|
||||
* but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.
|
||||
*
|
||||
* @param ptr The memory address to read
|
||||
* @param byteOffset bytes to skip before reading
|
||||
*
|
||||
* While there are some checks to catch invalid pointers, this is a difficult
|
||||
* thing to do safely. Passing an invalid pointer can crash the program and
|
||||
* reading beyond the bounds of the pointer will crash the program or cause
|
||||
* undefined behavior. Use with care!
|
||||
*/
|
||||
export function intptr(ptr: Pointer, byteOffset?: number): number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pointer backing a {@link TypedArray} or {@link ArrayBuffer}
|
||||
*
|
||||
|
||||
13
packages/bun-types/globals.d.ts
vendored
13
packages/bun-types/globals.d.ts
vendored
@@ -602,9 +602,9 @@ interface Process {
|
||||
getgroups: () => number[];
|
||||
// setgroups?: (groups: ReadonlyArray<string | number>) => void;
|
||||
dlopen(module: { exports: any }, filename: string, flags?: number): void;
|
||||
stdin: import("stream").Duplex & { isTTY: boolean };
|
||||
stdout: import("stream").Writable & { isTTY: boolean };
|
||||
stderr: import("stream").Writable & { isTTY: boolean };
|
||||
stdin: import("tty").ReadStream;
|
||||
stdout: import("tty").WriteStream;
|
||||
stderr: import("tty").WriteStream;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -739,11 +739,10 @@ interface BlobInterface {
|
||||
|
||||
type BlobPart = string | Blob | BufferSource;
|
||||
interface BlobPropertyBag {
|
||||
/** Set a default "type" */
|
||||
/** Set a default "type". Not yet implemented. */
|
||||
type?: string;
|
||||
|
||||
/** Not implemented in Bun yet. */
|
||||
endings?: "transparent" | "native";
|
||||
// endings?: "transparent" | "native";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3673,7 +3672,7 @@ declare module "*.txt" {
|
||||
}
|
||||
|
||||
declare module "*.toml" {
|
||||
var contents: unknown;
|
||||
var contents: any;
|
||||
export = contents;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ const tsConfig = {
|
||||
skipLibCheck: true,
|
||||
jsx: "react-jsx",
|
||||
allowImportingTsExtensions: true,
|
||||
emitDeclarationOnly: true,
|
||||
noEmit: true,
|
||||
composite: true,
|
||||
allowSyntheticDefaultImports: true,
|
||||
forceConsistentCasingInFileNames: true,
|
||||
|
||||
@@ -4,6 +4,8 @@ import {
|
||||
suffix,
|
||||
CString,
|
||||
Pointer,
|
||||
JSCallback,
|
||||
read,
|
||||
// FFIFunction,
|
||||
// ConvertFns,
|
||||
// Narrow,
|
||||
@@ -27,6 +29,14 @@ const lib = dlopen(
|
||||
args: [FFIType.i32, FFIType.i32],
|
||||
returns: FFIType.i32,
|
||||
},
|
||||
ptr_type: {
|
||||
args: [FFIType.pointer],
|
||||
returns: FFIType.pointer,
|
||||
},
|
||||
fn_type: {
|
||||
args: [FFIType.function],
|
||||
returns: FFIType.function,
|
||||
},
|
||||
allArgs: {
|
||||
args: [
|
||||
FFIType.char, // string
|
||||
@@ -67,6 +77,17 @@ const lib = dlopen(
|
||||
tsd.expectType<CString>(lib.symbols.sqlite3_libversion());
|
||||
tsd.expectType<number>(lib.symbols.add(1, 2));
|
||||
|
||||
tsd.expectType<Pointer | null>(lib.symbols.ptr_type(0));
|
||||
tc.assert<
|
||||
tc.IsExact<
|
||||
(typeof lib)["symbols"]["ptr_type"],
|
||||
TypedArray | Pointer | CString
|
||||
>
|
||||
>;
|
||||
|
||||
tsd.expectType<Pointer | null>(lib.symbols.fn_type(0));
|
||||
tc.assert<tc.IsExact<(typeof lib)["symbols"]["fn_type"], Pointer | JSCallback>>;
|
||||
|
||||
tc.assert<
|
||||
tc.IsExact<
|
||||
(typeof lib)["symbols"]["allArgs"],
|
||||
@@ -103,3 +124,41 @@ tc.assert<
|
||||
]
|
||||
>
|
||||
>;
|
||||
|
||||
const as_const_test = {
|
||||
sqlite3_libversion: {
|
||||
args: [],
|
||||
returns: FFIType.cstring,
|
||||
},
|
||||
multi_args: {
|
||||
args: [FFIType.i32, FFIType.f32],
|
||||
returns: FFIType.void,
|
||||
},
|
||||
no_returns: {
|
||||
args: [FFIType.i32],
|
||||
},
|
||||
no_args: {
|
||||
returns: FFIType.i32,
|
||||
},
|
||||
} as const;
|
||||
|
||||
const lib2 = dlopen(path, as_const_test);
|
||||
|
||||
tsd.expectType<CString>(lib2.symbols.sqlite3_libversion());
|
||||
tsd.expectType<void>(lib2.symbols.multi_args(1, 2));
|
||||
tc.assert<tc.IsExact<ReturnType<(typeof lib2)["symbols"]["no_returns"]>, void>>;
|
||||
tc.assert<tc.IsExact<Parameters<(typeof lib2)["symbols"]["no_args"]>, []>>;
|
||||
|
||||
tsd.expectType<number>(read.u8(0));
|
||||
tsd.expectType<number>(read.u8(0, 0));
|
||||
tsd.expectType<number>(read.i8(0, 0));
|
||||
tsd.expectType<number>(read.u16(0, 0));
|
||||
tsd.expectType<number>(read.i16(0, 0));
|
||||
tsd.expectType<number>(read.u32(0, 0));
|
||||
tsd.expectType<number>(read.i32(0, 0));
|
||||
tsd.expectType<bigint>(read.u64(0, 0));
|
||||
tsd.expectType<bigint>(read.i64(0, 0));
|
||||
tsd.expectType<number>(read.f32(0, 0));
|
||||
tsd.expectType<number>(read.f64(0, 0));
|
||||
tsd.expectType<number>(read.ptr(0, 0));
|
||||
tsd.expectType<number>(read.intptr(0, 0));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expectType } from "tsd";
|
||||
import data from "../../../bunfig.toml";
|
||||
|
||||
expectType<unknown>(data);
|
||||
expectType<any>(data);
|
||||
|
||||
49
packages/bun-types/tests/tty.test-d.ts
Normal file
49
packages/bun-types/tests/tty.test-d.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import * as tty from "tty";
|
||||
|
||||
const rs = new tty.ReadStream(234, {
|
||||
allowHalfOpen: true,
|
||||
readable: true,
|
||||
signal: new AbortSignal(),
|
||||
writable: true,
|
||||
});
|
||||
|
||||
const ws = new tty.WriteStream(234);
|
||||
|
||||
process.stdin.setRawMode(true);
|
||||
process.stdin.setRawMode(false);
|
||||
process.stdin.isRaw;
|
||||
process.stdin.setRawMode(true).isRaw;
|
||||
|
||||
rs.isRaw;
|
||||
rs.setRawMode(true);
|
||||
rs.setRawMode(false);
|
||||
rs.setRawMode(true).isRaw;
|
||||
rs.isTTY;
|
||||
|
||||
ws.isPaused;
|
||||
ws.isTTY;
|
||||
ws.bytesWritten;
|
||||
ws.bytesRead;
|
||||
ws.columns;
|
||||
ws.rows;
|
||||
ws.isTTY;
|
||||
ws.clearLine(1);
|
||||
ws.clearLine(0);
|
||||
ws.clearScreenDown();
|
||||
ws.cursorTo(1);
|
||||
ws.cursorTo(1, 2);
|
||||
ws.cursorTo(1, () => {});
|
||||
ws.cursorTo(1, 2, () => {});
|
||||
ws.moveCursor(1, 2);
|
||||
ws.moveCursor(1, 2, () => {});
|
||||
ws.clearLine(1, () => {});
|
||||
ws.clearLine(0, () => {});
|
||||
ws.clearScreenDown(() => {});
|
||||
ws.cursorTo(1, () => {});
|
||||
|
||||
process.stdout.clearLine;
|
||||
process.stdout.clearScreenDown;
|
||||
process.stdout.cursorTo;
|
||||
process.stdout.moveCursor;
|
||||
process.stdout.getColorDepth;
|
||||
process.stdout.getWindowSize;
|
||||
@@ -1,10 +1,8 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"lib": [
|
||||
"ESNext"
|
||||
],
|
||||
"noEmit": true,
|
||||
"lib": ["ESNext"],
|
||||
"baseUrl": ".",
|
||||
"rootDir": ".",
|
||||
"outFile": "./types.d.ts",
|
||||
@@ -12,14 +10,11 @@
|
||||
"target": "esnext",
|
||||
"disableSolutionSearching": true
|
||||
},
|
||||
"include": [
|
||||
"./*.d.ts",
|
||||
"dist"
|
||||
],
|
||||
"include": ["./*.d.ts", "dist"],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"./node_modules",
|
||||
"./node_modules/*",
|
||||
"./node_modules/@types/node/index.d.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
200
packages/bun-types/tty.d.ts
vendored
200
packages/bun-types/tty.d.ts
vendored
@@ -1,4 +1,31 @@
|
||||
/**
|
||||
* The `tty` module provides the `tty.ReadStream` and `tty.WriteStream` classes.
|
||||
* In most cases, it will not be necessary or possible to use this module directly.
|
||||
* However, it can be accessed using:
|
||||
*
|
||||
* ```js
|
||||
* const tty = require('tty');
|
||||
* ```
|
||||
*
|
||||
* When Node.js detects that it is being run with a text terminal ("TTY")
|
||||
* attached, `process.stdin` will, by default, be initialized as an instance of`tty.ReadStream` and both `process.stdout` and `process.stderr` will, by
|
||||
* default, be instances of `tty.WriteStream`. The preferred method of determining
|
||||
* whether Node.js is being run within a TTY context is to check that the value of
|
||||
* the `process.stdout.isTTY` property is `true`:
|
||||
*
|
||||
* ```console
|
||||
* $ node -p -e "Boolean(process.stdout.isTTY)"
|
||||
* true
|
||||
* $ node -p -e "Boolean(process.stdout.isTTY)" | cat
|
||||
* false
|
||||
* ```
|
||||
*
|
||||
* In most cases, there should be little to no reason for an application to
|
||||
* manually create instances of the `tty.ReadStream` and `tty.WriteStream`classes.
|
||||
* @see [source](https://github.com/nodejs/node/blob/v18.0.0/lib/tty.js)
|
||||
*/
|
||||
declare module "tty" {
|
||||
import * as net from "node:net";
|
||||
/**
|
||||
* The `tty.isatty()` method returns `true` if the given `fd` is associated with
|
||||
* a TTY and `false` if it is not, including whenever `fd` is not a non-negative
|
||||
@@ -7,10 +34,175 @@ declare module "tty" {
|
||||
* @param fd A numeric file descriptor
|
||||
*/
|
||||
function isatty(fd: number): boolean;
|
||||
|
||||
// TODO: tty-browserify only polyfills functions that throws errors, wouldn't make sense to have types at the moment
|
||||
var ReadStream: Function;
|
||||
var WriteStream: Function;
|
||||
/**
|
||||
* Represents the readable side of a TTY. In normal circumstances `process.stdin` will be the only `tty.ReadStream` instance in a Node.js
|
||||
* process and there should be no reason to create additional instances.
|
||||
* @since v0.5.8
|
||||
*/
|
||||
class ReadStream extends net.Socket {
|
||||
constructor(fd: number, options?: net.SocketConstructorOpts);
|
||||
/**
|
||||
* A `boolean` that is `true` if the TTY is currently configured to operate as a
|
||||
* raw device. Defaults to `false`.
|
||||
* @since v0.7.7
|
||||
*/
|
||||
isRaw: boolean;
|
||||
/**
|
||||
* Allows configuration of `tty.ReadStream` so that it operates as a raw device.
|
||||
*
|
||||
* When in raw mode, input is always available character-by-character, not
|
||||
* including modifiers. Additionally, all special processing of characters by the
|
||||
* terminal is disabled, including echoing input
|
||||
* characters. Ctrl+C will no longer cause a `SIGINT` when
|
||||
* in this mode.
|
||||
* @since v0.7.7
|
||||
* @param mode If `true`, configures the `tty.ReadStream` to operate as a raw device. If `false`, configures the `tty.ReadStream` to operate in its default mode. The `readStream.isRaw`
|
||||
* property will be set to the resulting mode.
|
||||
* @return The read stream instance.
|
||||
*/
|
||||
setRawMode(mode: boolean): this;
|
||||
/**
|
||||
* A `boolean` that is always `true` for `tty.ReadStream` instances.
|
||||
* @since v0.5.8
|
||||
*/
|
||||
isTTY: boolean;
|
||||
}
|
||||
/**
|
||||
* -1 - to the left from cursor
|
||||
* 0 - the entire line
|
||||
* 1 - to the right from cursor
|
||||
*/
|
||||
type Direction = -1 | 0 | 1;
|
||||
/**
|
||||
* Represents the writable side of a TTY. In normal circumstances,`process.stdout` and `process.stderr` will be the only`tty.WriteStream` instances created for a Node.js process and there
|
||||
* should be no reason to create additional instances.
|
||||
* @since v0.5.8
|
||||
*/
|
||||
class WriteStream extends net.Socket {
|
||||
constructor(fd: number);
|
||||
addListener(event: string, listener: (...args: any[]) => void): this;
|
||||
addListener(event: "resize", listener: () => void): this;
|
||||
emit(event: string | symbol, ...args: any[]): boolean;
|
||||
emit(event: "resize"): boolean;
|
||||
on(event: string, listener: (...args: any[]) => void): this;
|
||||
on(event: "resize", listener: () => void): this;
|
||||
once(event: string, listener: (...args: any[]) => void): this;
|
||||
once(event: "resize", listener: () => void): this;
|
||||
prependListener(event: string, listener: (...args: any[]) => void): this;
|
||||
prependListener(event: "resize", listener: () => void): this;
|
||||
prependOnceListener(
|
||||
event: string,
|
||||
listener: (...args: any[]) => void,
|
||||
): this;
|
||||
prependOnceListener(event: "resize", listener: () => void): this;
|
||||
/**
|
||||
* `writeStream.clearLine()` clears the current line of this `WriteStream` in a
|
||||
* direction identified by `dir`.
|
||||
* @since v0.7.7
|
||||
* @param callback Invoked once the operation completes.
|
||||
* @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`.
|
||||
*/
|
||||
clearLine(dir: Direction, callback?: () => void): boolean;
|
||||
/**
|
||||
* `writeStream.clearScreenDown()` clears this `WriteStream` from the current
|
||||
* cursor down.
|
||||
* @since v0.7.7
|
||||
* @param callback Invoked once the operation completes.
|
||||
* @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`.
|
||||
*/
|
||||
clearScreenDown(callback?: () => void): boolean;
|
||||
/**
|
||||
* `writeStream.cursorTo()` moves this `WriteStream`'s cursor to the specified
|
||||
* position.
|
||||
* @since v0.7.7
|
||||
* @param callback Invoked once the operation completes.
|
||||
* @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`.
|
||||
*/
|
||||
cursorTo(x: number, y?: number, callback?: () => void): boolean;
|
||||
cursorTo(x: number, callback: () => void): boolean;
|
||||
/**
|
||||
* `writeStream.moveCursor()` moves this `WriteStream`'s cursor _relative_ to its
|
||||
* current position.
|
||||
* @since v0.7.7
|
||||
* @param callback Invoked once the operation completes.
|
||||
* @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`.
|
||||
*/
|
||||
moveCursor(dx: number, dy: number, callback?: () => void): boolean;
|
||||
/**
|
||||
* Returns:
|
||||
*
|
||||
* * `1` for 2,
|
||||
* * `4` for 16,
|
||||
* * `8` for 256,
|
||||
* * `24` for 16,777,216 colors supported.
|
||||
*
|
||||
* Use this to determine what colors the terminal supports. Due to the nature of
|
||||
* colors in terminals it is possible to either have false positives or false
|
||||
* negatives. It depends on process information and the environment variables that
|
||||
* may lie about what terminal is used.
|
||||
* It is possible to pass in an `env` object to simulate the usage of a specific
|
||||
* terminal. This can be useful to check how specific environment settings behave.
|
||||
*
|
||||
* To enforce a specific color support, use one of the below environment settings.
|
||||
*
|
||||
* * 2 colors: `FORCE_COLOR = 0` (Disables colors)
|
||||
* * 16 colors: `FORCE_COLOR = 1`
|
||||
* * 256 colors: `FORCE_COLOR = 2`
|
||||
* * 16,777,216 colors: `FORCE_COLOR = 3`
|
||||
*
|
||||
* Disabling color support is also possible by using the `NO_COLOR` and`NODE_DISABLE_COLORS` environment variables.
|
||||
* @since v9.9.0
|
||||
* @param [env=process.env] An object containing the environment variables to check. This enables simulating the usage of a specific terminal.
|
||||
*/
|
||||
getColorDepth(env?: object): number;
|
||||
/**
|
||||
* Returns `true` if the `writeStream` supports at least as many colors as provided
|
||||
* in `count`. Minimum support is 2 (black and white).
|
||||
*
|
||||
* This has the same false positives and negatives as described in `writeStream.getColorDepth()`.
|
||||
*
|
||||
* ```js
|
||||
* process.stdout.hasColors();
|
||||
* // Returns true or false depending on if `stdout` supports at least 16 colors.
|
||||
* process.stdout.hasColors(256);
|
||||
* // Returns true or false depending on if `stdout` supports at least 256 colors.
|
||||
* process.stdout.hasColors({ TMUX: '1' });
|
||||
* // Returns true.
|
||||
* process.stdout.hasColors(2 ** 24, { TMUX: '1' });
|
||||
* // Returns false (the environment setting pretends to support 2 ** 8 colors).
|
||||
* ```
|
||||
* @since v11.13.0, v10.16.0
|
||||
* @param [count=16] The number of colors that are requested (minimum 2).
|
||||
* @param [env=process.env] An object containing the environment variables to check. This enables simulating the usage of a specific terminal.
|
||||
*/
|
||||
hasColors(count?: number): boolean;
|
||||
hasColors(env?: object): boolean;
|
||||
hasColors(count: number, env?: object): boolean;
|
||||
/**
|
||||
* `writeStream.getWindowSize()` returns the size of the TTY
|
||||
* corresponding to this `WriteStream`. The array is of the type`[numColumns, numRows]` where `numColumns` and `numRows` represent the number
|
||||
* of columns and rows in the corresponding TTY.
|
||||
* @since v0.7.7
|
||||
*/
|
||||
getWindowSize(): [number, number];
|
||||
/**
|
||||
* A `number` specifying the number of columns the TTY currently has. This property
|
||||
* is updated whenever the `'resize'` event is emitted.
|
||||
* @since v0.7.7
|
||||
*/
|
||||
columns: number;
|
||||
/**
|
||||
* A `number` specifying the number of rows the TTY currently has. This property
|
||||
* is updated whenever the `'resize'` event is emitted.
|
||||
* @since v0.7.7
|
||||
*/
|
||||
rows: number;
|
||||
/**
|
||||
* A `boolean` that is always `true`.
|
||||
* @since v0.5.8
|
||||
*/
|
||||
isTTY: boolean;
|
||||
}
|
||||
}
|
||||
declare module "node:tty" {
|
||||
export * from "tty";
|
||||
|
||||
2
packages/bun-vscode/.gitignore
vendored
Normal file
2
packages/bun-vscode/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
extension
|
||||
5
packages/bun-vscode/.vscode/launch.json
vendored
5
packages/bun-vscode/.vscode/launch.json
vendored
@@ -5,10 +5,7 @@
|
||||
"name": "Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}",
|
||||
"${workspaceFolder}/example"
|
||||
],
|
||||
"args": ["--extensionDevelopmentPath=${workspaceFolder}", "${workspaceFolder}/example"],
|
||||
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
|
||||
"preLaunchTask": "Build (watch)"
|
||||
},
|
||||
|
||||
4
packages/bun-vscode/.vscode/settings.json
vendored
4
packages/bun-vscode/.vscode/settings.json
vendored
@@ -5,5 +5,5 @@
|
||||
"search.exclude": {
|
||||
"out": true // set this to false to include "out" folder in search results
|
||||
},
|
||||
"typescript.tsc.autoDetect": "off",
|
||||
}
|
||||
"typescript.tsc.autoDetect": "off"
|
||||
}
|
||||
|
||||
8
packages/bun-vscode/.vscode/tasks.json
vendored
8
packages/bun-vscode/.vscode/tasks.json
vendored
@@ -4,13 +4,15 @@
|
||||
{
|
||||
"label": "Build",
|
||||
"type": "shell",
|
||||
"command": "bun run build"
|
||||
"command": "bun run build",
|
||||
"problemMatcher": "$esbuild"
|
||||
},
|
||||
{
|
||||
"label": "Build (watch)",
|
||||
"type": "shell",
|
||||
"command": "bun run build:watch",
|
||||
"isBackground": true
|
||||
"isBackground": true,
|
||||
"problemMatcher": "$esbuild-watch"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,22 @@
|
||||
# Debug Adapter Protocol for Bun
|
||||
# Bun for Visual Studio Code
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
<img align="right" src="https://user-images.githubusercontent.com/709451/182802334-d9c42afe-f35d-4a7b-86ea-9985f73f20c3.png" height="150px" style="float: right; padding: 30px;">
|
||||
|
||||
This extension adds support for using [Bun](https://bun.sh/) with Visual Studio Code. Bun is an all-in-one toolkit for JavaScript and TypeScript apps.
|
||||
|
||||
At its core is the _Bun runtime_, a fast JavaScript runtime designed as a drop-in replacement for Node.js. It's written in Zig and powered by JavaScriptCore under the hood, dramatically reducing startup times and memory usage.
|
||||
|
||||
<div align="center">
|
||||
<a href="https://bun.sh/docs">Documentation</a>
|
||||
<span> • </span>
|
||||
<a href="https://discord.com/invite/CXdq2DP29u">Discord</a>
|
||||
<span> • </span>
|
||||
<a href="https://github.com/oven-sh/bun/issues/new">Issues</a>
|
||||
<span> • </span>
|
||||
<a href="https://github.com/oven-sh/bun/issues/159">Roadmap</a>
|
||||
<br/>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
* Off-by-one for debug lines
|
||||
* Formatting values in console (some code is wired up)
|
||||
* Play button on debugger actually starting Bun
|
||||
* bun debug or --inspect command added to Bun, not need Bun.serve
|
||||
* Breakpoint actually setting
|
||||
Binary file not shown.
11
packages/bun-vscode/example/.vscode/launch.json
vendored
11
packages/bun-vscode/example/.vscode/launch.json
vendored
@@ -4,16 +4,15 @@
|
||||
{
|
||||
"type": "bun",
|
||||
"request": "launch",
|
||||
"name": "Debug",
|
||||
"program": "${workspaceFolder}/example.js",
|
||||
"stopOnEntry": true
|
||||
"name": "Debug Bun",
|
||||
"program": "${file}",
|
||||
"watch": true
|
||||
},
|
||||
{
|
||||
"type": "bun",
|
||||
"request": "attach",
|
||||
"name": "Attach",
|
||||
"program": "${workspaceFolder}/example.js",
|
||||
"stopOnEntry": true
|
||||
"name": "Attach to Bun",
|
||||
"url": "ws://localhost:6499/",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
30
packages/bun-vscode/example/example-sourcemap.js
Normal file
30
packages/bun-vscode/example/example-sourcemap.js
Normal file
@@ -0,0 +1,30 @@
|
||||
// @bun
|
||||
// example.ts
|
||||
var a = function (request) {
|
||||
b(request);
|
||||
};
|
||||
var b = function (request) {
|
||||
c(request);
|
||||
};
|
||||
var c = function (request) {
|
||||
console.log(request);
|
||||
};
|
||||
var example_default = {
|
||||
async fetch(request, server) {
|
||||
a(request);
|
||||
const coolThing = new SuperCoolThing();
|
||||
coolThing.doCoolThing();
|
||||
debugger;
|
||||
return new Response(request.url);
|
||||
},
|
||||
};
|
||||
|
||||
class SuperCoolThing {
|
||||
doCoolThing() {
|
||||
console.log("super cool thing!");
|
||||
}
|
||||
}
|
||||
export { example_default as default };
|
||||
|
||||
//# debugId=9BB0B773A8E4771564756e2164756e21
|
||||
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiZXhhbXBsZS50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsKICAgICJpbXBvcnQgdHlwZSB7IFNlcnZlciB9IGZyb20gXCJidW5cIjtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBhc3luYyBmZXRjaChyZXF1ZXN0OiBSZXF1ZXN0LCBzZXJ2ZXI6IFNlcnZlcik6IFByb21pc2U8UmVzcG9uc2U+IHtcbiAgICBhKHJlcXVlc3QpO1xuICAgIGNvbnN0IGNvb2xUaGluZzogQ29vbFRoaW5nID0gbmV3IFN1cGVyQ29vbFRoaW5nKCk7XG4gICAgY29vbFRoaW5nLmRvQ29vbFRoaW5nKCk7XG4gICAgZGVidWdnZXI7XG4gICAgcmV0dXJuIG5ldyBSZXNwb25zZShyZXF1ZXN0LnVybCk7XG4gIH1cbn07XG5cbi8vIGFcbmZ1bmN0aW9uIGEocmVxdWVzdDogUmVxdWVzdCk6IHZvaWQge1xuICBiKHJlcXVlc3QpO1xufVxuXG4vLyBiXG5mdW5jdGlvbiBiKHJlcXVlc3Q6IFJlcXVlc3QpOiB2b2lkIHtcbiAgYyhyZXF1ZXN0KTtcbn1cblxuLy8gY1xuZnVuY3Rpb24gYyhyZXF1ZXN0OiBSZXF1ZXN0KSB7XG4gIGNvbnNvbGUubG9nKHJlcXVlc3QpO1xufVxuXG5pbnRlcmZhY2UgQ29vbFRoaW5nIHtcbiAgZG9Db29sVGhpbmcoKTogdm9pZDtcbn1cblxuY2xhc3MgU3VwZXJDb29sVGhpbmcgaW1wbGVtZW50cyBDb29sVGhpbmcge1xuICBkb0Nvb2xUaGluZygpOiB2b2lkIHtcbiAgICBjb25zb2xlLmxvZyhcInN1cGVyIGNvb2wgdGhpbmchXCIpO1xuICB9XG59XG4iCiAgXSwKICAibWFwcGluZ3MiOiAiOztBQS8vLy8vZkFhQSxJQUFTLFlBQUMsQ0FBQyxTQUF3QjtBQUNqQyxJQUFFLE9BQU87QUFBQTtBQUlYLElBQVMsWUFBQyxDQUFDLFNBQXdCO0FBQ2pDLElBQUUsT0FBTztBQUFBO0FBSVgsSUFBUyxZQUFDLENBQUMsU0FBa0I7QUFDM0IsVUFBUSxJQUFJLE9BQU87QUFBQTtBQXRCckIsSUFBZTtBQUFBLE9BQ1AsTUFBSyxDQUFDLFNBQWtCLFFBQW1DO0FBQy9ELE1BQUUsT0FBTztBQUNULFVBQU0sWUFBdUIsSUFBSTtBQUNqQyxjQUFVLFlBQVk7QUFDdEI7QUFDQSxXQUFPLElBQUksU0FBUyxRQUFRLEdBQUc7QUFBQTtBQUVuQztBQXFCQTtBQUFBLE1BQU0sZUFBb0M7QUFBQSxFQUN4QyxXQUFXLEdBQVM7QUFDbEIsWUFBUSxJQUFJLG1CQUFtQjtBQUFBO0FBRW5DOyIsCiAgImRlYnVnSWQiOiAiOUJCMEI3NzNBOEU0NzcxNTY0NzU2ZTIxNjQ3NTZlMjEiLAogICJuYW1lcyI6IFtdCn0=
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user