mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
Compare commits
32 Commits
nektro-pat
...
ben/fix-ex
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e763dc64bb | ||
|
|
2d0b557ff7 | ||
|
|
15f5ba3e26 | ||
|
|
1385f9f686 | ||
|
|
07ccec0fd8 | ||
|
|
7283453eed | ||
|
|
1a08cfcd6b | ||
|
|
06e733cc64 | ||
|
|
409e674526 | ||
|
|
d15eadaa2c | ||
|
|
5532e1af10 | ||
|
|
68e6304c73 | ||
|
|
709cd95c30 | ||
|
|
3830b0c499 | ||
|
|
291b59eb19 | ||
|
|
035f97ba13 | ||
|
|
fef9555f82 | ||
|
|
ae0106b651 | ||
|
|
355dc56db0 | ||
|
|
5fc53353fb | ||
|
|
d2fe1ce1c8 | ||
|
|
29d287261b | ||
|
|
6dbd679c06 | ||
|
|
a5006a13a8 | ||
|
|
bebf762bcf | ||
|
|
e6ea389e4e | ||
|
|
47ff4748bd | ||
|
|
09b031d044 | ||
|
|
6b8fd718c2 | ||
|
|
9ed3858e40 | ||
|
|
6cf9c41d1f | ||
|
|
183a8f61d8 |
2
.vscode/launch.json
generated
vendored
2
.vscode/launch.json
generated
vendored
@@ -174,6 +174,8 @@
|
||||
"BUN_GARBAGE_COLLECTOR_LEVEL": "0",
|
||||
"BUN_DEBUG_IncrementalGraph": "1",
|
||||
"BUN_DEBUG_Bake": "1",
|
||||
"BUN_DEBUG_reload_file_list": "1",
|
||||
"GOMAXPROCS": "1",
|
||||
},
|
||||
"console": "internalConsole",
|
||||
},
|
||||
|
||||
33
bench/grpc-server/cert.pem
Normal file
33
bench/grpc-server/cert.pem
Normal file
@@ -0,0 +1,33 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFxjCCA66gAwIBAgIUUaQCzOcxcFBP0KwoQfNqD/FoI44wDQYJKoZIhvcNAQEL
|
||||
BQAwYjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1TYW4gRnJh
|
||||
bmNpc2NvMQwwCgYDVQQKDANCdW4xDDAKBgNVBAsMA0J1bjESMBAGA1UEAwwJbG9j
|
||||
YWxob3N0MB4XDTI0MTAxNjAwMDExNloXDTM0MTAxNDAwMDExNlowYjELMAkGA1UE
|
||||
BhMCVVMxCzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQwwCgYD
|
||||
VQQKDANCdW4xDDAKBgNVBAsMA0J1bjESMBAGA1UEAwwJbG9jYWxob3N0MIICIjAN
|
||||
BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp2s1CWRRV3bkjUxyBefcRCiZj8v6
|
||||
LIIWOb/kFJOo1PQsmQtOOWfY/kNEATPhLtEVolMzsQtaKV+u/Jnp6vU6cCU0qfQ/
|
||||
cha/s0XaSn9zkJSXjmNOPDOXoeJ5wmSUvWETRvDgeYXCg84zTwRnD1pXIsKxHtia
|
||||
SYkTC29skSn0+63GW2Ebzkbn3jcYbk3gfkRO/qw8EDh/4/TcS2SjoHl96E1QcfBX
|
||||
InXrPGoHQhuqJV60rmmkVws0lTIZIq0g2p7iFDCg5TG1asakX7+CrEM/q+oyo3e8
|
||||
RwMfc+9pqFEqyvXGIQSulS+CVKKbpAFMg07UGYe1t0s5iCwfLQ9apaKL31t/3Vkr
|
||||
uVKgy5FrPLnRXkFXDZ1v+43AZBmdLrKODzsqHEbt2JmV0V6JVUkE4kbeJr/nlkhQ
|
||||
x6yXloYY3VKbnCb1L3HmMInrK1QSpxlOb8RllTd33oBwd1FKEvH2gza0j9hqq8uQ
|
||||
hWVN7tlamkgtBteZ8Y9fd3MdxD9iZOx4dVtCX1+sgJFdaL2ZgE0asojn46yT8Uqw
|
||||
5d0M9vqmWc5AqG7c4UWWRrfB1MfOq/X8GtImmKyhEgizIPdWFeF1cNjhPffJv4yR
|
||||
Y4Rj33OBTCM+9h8ZSw/fKo55yRXyz3bjrW2Mg8Dtq+6TcRd5gSLCaTN6jX8E9y7G
|
||||
TobnA9MnKHhSIhsCAwEAAaN0MHIwHQYDVR0OBBYEFEJU6/9ELCp1CAxYJ5FJJxpV
|
||||
FSRmMB8GA1UdIwQYMBaAFEJU6/9ELCp1CAxYJ5FJJxpVFSRmMA8GA1UdEwEB/wQF
|
||||
MAMBAf8wHwYDVR0RBBgwFoIJbG9jYWxob3N0ggkxMjcuMC4wLjEwDQYJKoZIhvcN
|
||||
AQELBQADggIBACyOPdVwfJg1aUNANy78+cm6eoInM9NDdXGWHMqCJwYF6qJTQV11
|
||||
jYwYrl+OWOi3CEC+ogXl+uJX4tSS5d+rBTXEb73cLpogxP+xuxr4cBHhtgpGRpY0
|
||||
GqWCFUTexHxXMrYhHQxf3uv79PNauw/dd1Baby1OjF3zSKRzFsv4KId97cAgT/9H
|
||||
HfUo2ym5jmhNFj5rhUavO3Pw1++1eeDeDAkS6T59buzx0h9760WD20oBdgjt42cb
|
||||
P6xg9OwV7ALQSwJ8YPEXpkl7u+6jy0j5ceYmXh76tAyA+hDYOJrY0opBjSPmXH99
|
||||
p3W63gvk/AdfeAdbFHp6en0b04x4EIogOGZxBP35rzBvsQpqavBE3PBpUIyrQs5p
|
||||
OBUncRrcjEDL6WKh6RJIjZnvpHPrEqOqyxaeWRc4+85ZrVArJHGMc8I+zs9uCFjo
|
||||
Cjfde3d317kCszUTxo0l3azyBpr007PMIUoBF2VJEAyQp2Tz/yu0CbEscNJO/wCn
|
||||
Sb1A6ojaQcgQe2hsaJz/mS+OOjHHaDbCp9iltP2CS63PYleEx4q1Bn8KVRy2zYTB
|
||||
n74y4YaD8Q+hSA6zU741pzqK2SFCpBQnSz757ocr6WspQ47iOonX2giGZS/3KVeK
|
||||
qNzU14+h0b8HaBqZmOvjF+S4G0HDpRwxPzDWgc7dEIWlzHH+ZCqjBFwL
|
||||
-----END CERTIFICATE-----
|
||||
31
bench/grpc-server/index.js
Normal file
31
bench/grpc-server/index.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const grpc = require("@grpc/grpc-js");
|
||||
const protoLoader = require("@grpc/proto-loader");
|
||||
const packageDefinition = protoLoader.loadSync("benchmark.proto", {});
|
||||
const proto = grpc.loadPackageDefinition(packageDefinition).benchmark;
|
||||
const fs = require("fs");
|
||||
|
||||
function ping(call, callback) {
|
||||
callback(null, { message: "Hello, World" });
|
||||
}
|
||||
|
||||
function main() {
|
||||
const server = new grpc.Server();
|
||||
server.addService(proto.BenchmarkService.service, { ping: ping });
|
||||
const tls = !!process.env.TLS && (process.env.TLS === "1" || process.env.TLS === "true");
|
||||
const port = process.env.PORT || 50051;
|
||||
const host = process.env.HOST || "localhost";
|
||||
let credentials;
|
||||
if (tls) {
|
||||
const ca = fs.readFileSync("./cert.pem");
|
||||
const key = fs.readFileSync("./key.pem");
|
||||
const cert = fs.readFileSync("./cert.pem");
|
||||
credentials = grpc.ServerCredentials.createSsl(ca, [{ private_key: key, cert_chain: cert }]);
|
||||
} else {
|
||||
credentials = grpc.ServerCredentials.createInsecure();
|
||||
}
|
||||
server.bindAsync(`${host}:${port}`, credentials, () => {
|
||||
console.log(`Server running at ${tls ? "https" : "http"}://${host}:${port}`);
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
52
bench/grpc-server/key.pem
Normal file
52
bench/grpc-server/key.pem
Normal file
@@ -0,0 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCnazUJZFFXduSN
|
||||
THIF59xEKJmPy/osghY5v+QUk6jU9CyZC045Z9j+Q0QBM+Eu0RWiUzOxC1opX678
|
||||
menq9TpwJTSp9D9yFr+zRdpKf3OQlJeOY048M5eh4nnCZJS9YRNG8OB5hcKDzjNP
|
||||
BGcPWlciwrEe2JpJiRMLb2yRKfT7rcZbYRvORufeNxhuTeB+RE7+rDwQOH/j9NxL
|
||||
ZKOgeX3oTVBx8Fcides8agdCG6olXrSuaaRXCzSVMhkirSDanuIUMKDlMbVqxqRf
|
||||
v4KsQz+r6jKjd7xHAx9z72moUSrK9cYhBK6VL4JUopukAUyDTtQZh7W3SzmILB8t
|
||||
D1qloovfW3/dWSu5UqDLkWs8udFeQVcNnW/7jcBkGZ0uso4POyocRu3YmZXRXolV
|
||||
SQTiRt4mv+eWSFDHrJeWhhjdUpucJvUvceYwiesrVBKnGU5vxGWVN3fegHB3UUoS
|
||||
8faDNrSP2Gqry5CFZU3u2VqaSC0G15nxj193cx3EP2Jk7Hh1W0JfX6yAkV1ovZmA
|
||||
TRqyiOfjrJPxSrDl3Qz2+qZZzkCobtzhRZZGt8HUx86r9fwa0iaYrKESCLMg91YV
|
||||
4XVw2OE998m/jJFjhGPfc4FMIz72HxlLD98qjnnJFfLPduOtbYyDwO2r7pNxF3mB
|
||||
IsJpM3qNfwT3LsZOhucD0ycoeFIiGwIDAQABAoICAE+YYrDCZwHEXsjmzVcNcuVc
|
||||
wBVjjt9WQabXGmLGCQClzgY9H8WfH8VSyaQgvDB762MvV2YW1ZjSCunBazrvuAbV
|
||||
SYJ7wyZEtoNO9IdyrMjSPHPPtsRcavzmJalMFIMtAfM6Vh6wf1gW0sIAf9cGxmKa
|
||||
WYcmx8OqTcmkAePKJNT7O1D6jDO39kjpvM3EbLTbWQsva6bylasVIR8fC8QhvsCQ
|
||||
8WwaLfMOSPaCGk1Nxcjai+BYDW/sveUo2lZoJTSLUUT0EaqlxXCsXD3BWSj5F+5t
|
||||
/AFHzdWdIHkIHB2P6V5xFu9fwHjhC3+dh42jqHLNKX2xza0FMKcTAwdzQ094RjL3
|
||||
cOGIsa0Vdt7Mks5eLCRxz0xI3kyrbF0/CopxT0pVWZwUzPk1G+Z3HesWkVtQpg7u
|
||||
RYzsoNKKc5mhc/V+vG290WAcNB4E3m85DgKQr4ib+J/rCy5/SnJYgg4QXsEyNlQ5
|
||||
ESBtRmuPfnrPIxqrDKZ7ZsJv8XFWydXTOfJxeKR1T1S02iYna+z1FnNu+t0ELTr9
|
||||
uhmkuqmV8RJVTub1P2EJPdiku/61UwNLyyZMgFjATDxB0hHIj1FP1HbfhEYbkYNc
|
||||
Dl7a7egJ4KFYWpQ+7MzOmc0OKq1HuJ9H4FhoYpbVq1OQosZ6G3d9afKSZa6dFdK0
|
||||
8ujvdQBR0NlAhc/LAr6BAoIBAQDfD3h9P4i5L8NCdocovCi3Eo0kcNQ3QuvnWrrs
|
||||
B/9CLoWhJrcLV85d0dEX6lSYl9BWW02ilVB+Qvom2wS2td1CBUgDxovX4tCZCuXt
|
||||
otYL/yWWOA7IG0Fjt6YEERQD/tRfKnn8hVBlk5cDTXXxHRGVMku4CHsN3ILtITQS
|
||||
VnVsTrGoWd6mFFA9X9Qu4zR9wKtjGEuL7BT8ixxtXLa2tMjdc4UL140yAgmMemJS
|
||||
TzC6EURe2OnhIzVe9yyLKcqw0prkGHg/Lau5lA1CAh67ZMY4EjO3cuda8R+O7vyO
|
||||
z2afeaTORzzdEbSZPG+8oqIN1/RjRCbl3RXYN8ibSwOzp6X7AoIBAQDAJEVta98J
|
||||
P2/36rXrkl6WrRfYqUPy6vgo/lPuRpp+BQ7ldgmH4+ZrJW5Mxa5hktVujk/C2kAO
|
||||
auzhzNlsxR+c/KwtsL1JXwBn8CT1bR0qvi+URmvGQn9GOKrLLy+6cfphuZWuc4/r
|
||||
hAgXzEjzPcJJJfxA1i2soKPbiFiCGHxot68P4uJSM2sU6QjNIxEjPbTJjEg894pD
|
||||
GJoiRRVHgnzzxL3cqrK90Zn6MAl9f2tYihfddsENeZb5t84LBppxBSGouE3ZH8uD
|
||||
Sufs4DSj1ptocbDbX+0kRNqfjTI5ivDxlS+ZKBe05PVTUmGBAWLamfCe89IW3/z+
|
||||
Rfkh4ZBPtlphAoIBADwjSqPR7kWnN+iCVjxIRl3dNYpelQh1FW7hikW6fjpUmphw
|
||||
/KalPLEUsV/WQIqHW5b8tLihsvrnidPR9rpf29BB5kGGVQuWThEE3CquXTEM0BBo
|
||||
+qs+lemRiMPN6uyM1qr1o7/OHXfVS8CLMMIZyTTFQ57RQoPhMLdH3WcYQj46FTHD
|
||||
UQDLtzpkzKr7fJpuyIZF9ZA6zQmtY7OkbGpj4Ue7LmKb8ahK3lIuaLWyPfvcTeeY
|
||||
aa3WNTxuPWcjlE8J6NKYOksmQAcfgFeMhMaXC83wMltCMlfVbGG30wWZqxxRynoG
|
||||
wMUFUgCCR8m+uxwqXewpYqdUbOBHYeFkXxIfn+MCggEAR5p8wQ1NHd4lNOekCfkP
|
||||
BOnWlChoKRPFjUlSL97h3gq2hW6amKimitF1LGkS1kvo+/1O3heFfZn9UxyK/kzr
|
||||
vg4vgAt4Tup3dUR6EXgrQW2Ev6YKreTEF4Awre2UxM+K9nY5wLxSKvuWJIA9w2AF
|
||||
kkr0mZj3hniK99n02e6UFlY1iB8OJoIA6tb5L7FcxpxNTjrYBNhfDygQ8Kp8Bp0r
|
||||
QZDVDHIUkEaXMjRKpRkiAOndgOurgAEK8V69C0DXtzypUX31jO+bYP8+NPlMxK3K
|
||||
Vn7f4LD75+M88e6lg+oyZmUpStM1GnWksvtlWLUSiNKLaEEGzv2EA6JB+I1dwUb8
|
||||
oQKCAQEAlmisUyn1/lpNnEzKsfUnRs53WxS2e1br5vJ5+pet3cjXT2btfp6J5/mf
|
||||
Tfqv5mZfTjYxydG0Kl3afI/SnhTcRS2/s4svrktZYLOLM2PAGYdCV6j1stXl4ObO
|
||||
eIfjzB3y1Zc2dEcWTylJ/lABoNGMPWFJQ67q8WS37pUHQPseJ++LmZFvlRyBgZBl
|
||||
VLqiHHiZ2ax+yC1ZxY4RECtEiYFplspNldNe+bP/lzTJftsUDe1FqRT/SvEam+1f
|
||||
kb//sbHkJ+l4BEv0Us3SIGwJ0BblhxLYO34IFVpheY4UQBy/nRaeUUdVR9r8JtYD
|
||||
z/cCLOrUJfealezimyd8SKPWPeHhrA==
|
||||
-----END PRIVATE KEY-----
|
||||
15
bench/grpc-server/package.json
Normal file
15
bench/grpc-server/package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "bench",
|
||||
"scripts": {
|
||||
"deps": "exit 0",
|
||||
"build": "exit 0",
|
||||
"bun:server": "TLS=1 PORT=50051 $BUN bun.js",
|
||||
"node:server": "TLS=1 PORT=50051 $NODE node.js",
|
||||
"bench": "ghz --cacert ./cert.pem --proto ./benchmark.proto --call benchmark.BenchmarkService.Ping -d '{\"message\": \"Hello\"}' --total=100000 localhost:50051",
|
||||
"bench:insecure": "ghz --insecure --proto ./benchmark.proto --call benchmark.BenchmarkService.Ping -d '{\"message\": \"Hello\"}' --total=100000 localhost:50051"
|
||||
},
|
||||
"dependencies": {
|
||||
"@grpc/grpc-js": "1.12.0",
|
||||
"@grpc/proto-loader": "0.7.10"
|
||||
}
|
||||
}
|
||||
15
bench/snippets/buffer-fill.mjs
Normal file
15
bench/snippets/buffer-fill.mjs
Normal file
@@ -0,0 +1,15 @@
|
||||
import { bench, run } from "./runner.mjs";
|
||||
|
||||
for (let size of [32, 2048, 1024 * 16, 1024 * 1024 * 2, 1024 * 1024 * 16]) {
|
||||
for (let fillSize of [4, 8, 16, 11]) {
|
||||
const buffer = Buffer.allocUnsafe(size);
|
||||
|
||||
const pattern = "x".repeat(fillSize);
|
||||
|
||||
bench(`Buffer.fill ${size} bytes with ${fillSize} byte value`, () => {
|
||||
buffer.fill(pattern);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await run();
|
||||
@@ -478,6 +478,7 @@ fn addInternalPackages(b: *Build, obj: *Compile, opts: *BunBuildOptions) void {
|
||||
.{ .file = "ErrorCode.zig", .import = "ErrorCode" },
|
||||
.{ .file = "runtime.out.js" },
|
||||
.{ .file = "bake.client.js", .import = "bake-codegen/bake.client.js", .enable = opts.shouldEmbedCode() },
|
||||
.{ .file = "bake.error.js", .import = "bake-codegen/bake.error.js", .enable = opts.shouldEmbedCode() },
|
||||
.{ .file = "bake.server.js", .import = "bake-codegen/bake.server.js", .enable = opts.shouldEmbedCode() },
|
||||
.{ .file = "bun-error/index.js", .enable = opts.shouldEmbedCode() },
|
||||
.{ .file = "bun-error/bun-error.css", .enable = opts.shouldEmbedCode() },
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
# https://clang.llvm.org/docs/ClangFormat.html
|
||||
|
||||
set(CLANG_FORMAT_SOURCES ${BUN_C_SOURCES} ${BUN_CXX_SOURCES})
|
||||
file(GLOB BUN_H_SOURCES LIST_DIRECTORIES false ${CONFIGURE_DEPENDS}
|
||||
${CWD}/src/bun.js/bindings/*.h
|
||||
${CWD}/src/bun.js/modules/*.h
|
||||
)
|
||||
|
||||
set(CLANG_FORMAT_SOURCES ${BUN_C_SOURCES} ${BUN_CXX_SOURCES} ${BUN_H_SOURCES})
|
||||
|
||||
register_command(
|
||||
TARGET
|
||||
|
||||
@@ -18,6 +18,7 @@ register_cmake_command(
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
-DCARES_SHARED=OFF
|
||||
-DCARES_BUILD_TOOLS=OFF # this was set to ON?
|
||||
-DCMAKE_INSTALL_LIBDIR=lib
|
||||
LIB_PATH
|
||||
lib
|
||||
LIBRARIES
|
||||
|
||||
@@ -2,7 +2,7 @@ option(WEBKIT_VERSION "The version of WebKit to use")
|
||||
option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading")
|
||||
|
||||
if(NOT WEBKIT_VERSION)
|
||||
set(WEBKIT_VERSION 01ac6a63449713c5b7cf38fb03628283041f63be)
|
||||
set(WEBKIT_VERSION 12e2f46fb01f7c5cf5a992b9414ddfaab32b7110)
|
||||
endif()
|
||||
|
||||
if(WEBKIT_LOCAL)
|
||||
|
||||
@@ -14,7 +14,7 @@ In Bun v1.1.9, we added support for DNS caching. This cache makes repeated conne
|
||||
|
||||
At the time of writing, we cache up to 255 entries for a maximum of 30 seconds (each). If any connections to a host fail, we remove the entry from the cache. When multiple connections are made to the same host simultaneously, DNS lookups are deduplicated to avoid making multiple requests for the same host.
|
||||
|
||||
This cache is automatically used by;
|
||||
This cache is automatically used by:
|
||||
|
||||
- `bun install`
|
||||
- `fetch()`
|
||||
@@ -99,7 +99,7 @@ console.log(stats);
|
||||
|
||||
### Configuring DNS cache TTL
|
||||
|
||||
Bun defaults to 30 seconds for the TTL of DNS cache entries. To change this, you can set the envionrment variable `$BUN_CONFIG_DNS_TIME_TO_LIVE_SECONDS`. For example, to set the TTL to 5 seconds:
|
||||
Bun defaults to 30 seconds for the TTL of DNS cache entries. To change this, you can set the environment variable `$BUN_CONFIG_DNS_TIME_TO_LIVE_SECONDS`. For example, to set the TTL to 5 seconds:
|
||||
|
||||
```sh
|
||||
BUN_CONFIG_DNS_TIME_TO_LIVE_SECONDS=5 bun run my-script.ts
|
||||
|
||||
@@ -325,6 +325,28 @@ As a performance optimization, the class constructor is not called, default init
|
||||
|
||||
The database columns are set as properties on the class instance.
|
||||
|
||||
### `.iterate()` (`@@iterator`)
|
||||
|
||||
Use `.iterate()` to run a query and incrementally return results. This is useful for large result sets that you want to process one row at a time without loading all the results into memory.
|
||||
|
||||
```ts
|
||||
const query = db.query("SELECT * FROM foo");
|
||||
for (const row of query.iterate()) {
|
||||
console.log(row);
|
||||
}
|
||||
```
|
||||
|
||||
You can also use the `@@iterator` protocol:
|
||||
|
||||
```ts
|
||||
const query = db.query("SELECT * FROM foo");
|
||||
for (const row of query) {
|
||||
console.log(row);
|
||||
}
|
||||
```
|
||||
|
||||
This feature was added in Bun v1.1.31.
|
||||
|
||||
### `.values()`
|
||||
|
||||
Use `values()` to run a query and get back all results as an array of arrays.
|
||||
|
||||
@@ -2,12 +2,6 @@
|
||||
name: Build an app with Next.js and Bun
|
||||
---
|
||||
|
||||
{% callout %}
|
||||
The Next.js [App Router](https://nextjs.org/docs/app) currently relies on Node.js APIs that Bun does not yet implement. The guide below uses Bun to initialize a project and install dependencies, but it uses Node.js to run the dev server.
|
||||
{% /callout %}
|
||||
|
||||
---
|
||||
|
||||
Initialize a Next.js app with `create-next-app`. This automatically installs dependencies using `npm`.
|
||||
|
||||
```sh
|
||||
|
||||
@@ -27,16 +27,6 @@ data.version; // => "1.0.0"
|
||||
data.author.name; // => "John Dough"
|
||||
```
|
||||
|
||||
Bun also supports [Import Attributes](https://github.com/tc39/proposal-import-attributes/) and [JSON modules](https://github.com/tc39/proposal-json-modules) syntax.
|
||||
|
||||
```ts
|
||||
import data from "./package.json" with { type: "json" };
|
||||
|
||||
data.name; // => "bun"
|
||||
data.version; // => "1.0.0"
|
||||
data.author.name; // => "John Dough"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Bun also supports [Import Attributes](https://github.com/tc39/proposal-import-attributes/) and [JSON modules](https://github.com/tc39/proposal-json-modules) syntax.
|
||||
|
||||
9
packages/bun-types/bun.d.ts
vendored
9
packages/bun-types/bun.d.ts
vendored
@@ -1650,7 +1650,7 @@ declare module "bun" {
|
||||
* automatically run in a worker thread.
|
||||
*
|
||||
* The underlying implementation of these functions are provided by the Zig
|
||||
* Standard Library. Thanks to @jedisct1 and other Zig constributors for their
|
||||
* Standard Library. Thanks to @jedisct1 and other Zig contributors for their
|
||||
* work on this.
|
||||
*
|
||||
* ### Example with argon2
|
||||
@@ -1753,7 +1753,7 @@ declare module "bun" {
|
||||
* instead which runs in a worker thread.
|
||||
*
|
||||
* The underlying implementation of these functions are provided by the Zig
|
||||
* Standard Library. Thanks to @jedisct1 and other Zig constributors for their
|
||||
* Standard Library. Thanks to @jedisct1 and other Zig contributors for their
|
||||
* work on this.
|
||||
*
|
||||
* ### Example with argon2
|
||||
@@ -1792,7 +1792,7 @@ declare module "bun" {
|
||||
* instead which runs in a worker thread.
|
||||
*
|
||||
* The underlying implementation of these functions are provided by the Zig
|
||||
* Standard Library. Thanks to @jedisct1 and other Zig constributors for their
|
||||
* Standard Library. Thanks to @jedisct1 and other Zig contributors for their
|
||||
* work on this.
|
||||
*
|
||||
* ### Example with argon2
|
||||
@@ -4448,15 +4448,18 @@ declare module "bun" {
|
||||
hostname: string;
|
||||
port: number;
|
||||
tls?: TLSOptions;
|
||||
exclusive?: boolean;
|
||||
}
|
||||
|
||||
interface TCPSocketConnectOptions<Data = undefined> extends SocketOptions<Data> {
|
||||
hostname: string;
|
||||
port: number;
|
||||
tls?: boolean;
|
||||
exclusive?: boolean;
|
||||
}
|
||||
|
||||
interface UnixSocketOptions<Data = undefined> extends SocketOptions<Data> {
|
||||
tls?: TLSOptions;
|
||||
unix: string;
|
||||
}
|
||||
|
||||
|
||||
8
packages/bun-types/globals.d.ts
vendored
8
packages/bun-types/globals.d.ts
vendored
@@ -1838,14 +1838,6 @@ declare global {
|
||||
withCredentials?: boolean;
|
||||
}
|
||||
|
||||
interface EventSource extends Bun.EventSource {}
|
||||
var EventSource: typeof globalThis extends {
|
||||
onerror: any;
|
||||
EventSource: infer T;
|
||||
}
|
||||
? T
|
||||
: EventSource;
|
||||
|
||||
interface PromiseConstructor {
|
||||
/**
|
||||
* Create a deferred promise, with exposed `resolve` and `reject` methods which can be called
|
||||
|
||||
9
packages/bun-types/sqlite.d.ts
vendored
9
packages/bun-types/sqlite.d.ts
vendored
@@ -579,6 +579,15 @@ declare module "bun:sqlite" {
|
||||
*/
|
||||
get(...params: ParamsType): ReturnType | null;
|
||||
|
||||
/**
|
||||
* Execute the prepared statement and return an
|
||||
*
|
||||
* @param params optional values to bind to the statement. If omitted, the statement is run with the last bound values or no parameters if there are none.
|
||||
*
|
||||
*/
|
||||
iterate(...params: ParamsType): IterableIterator<ReturnType>;
|
||||
[Symbol.iterator](): IterableIterator<ReturnType>;
|
||||
|
||||
/**
|
||||
* Execute the prepared statement. This returns `undefined`.
|
||||
*
|
||||
|
||||
@@ -208,10 +208,6 @@ const writableStream = new WritableStream();
|
||||
const a = new ResolveError();
|
||||
a.level;
|
||||
}
|
||||
{
|
||||
const a = new EventSource("asdf");
|
||||
a.CLOSED;
|
||||
}
|
||||
{
|
||||
const a = new AbortController();
|
||||
a;
|
||||
|
||||
@@ -233,8 +233,13 @@ async function runTests() {
|
||||
reportOutputToGitHubAction("failing_tests", markdown);
|
||||
}
|
||||
|
||||
if (!isCI) console.log("-------");
|
||||
if (!isCI) console.log("passing", results.length - failedTests.length, "/", results.length);
|
||||
if (!isCI) {
|
||||
console.log("-------");
|
||||
console.log("passing", results.length - failedTests.length, "/", results.length);
|
||||
for (const { testPath } of failedTests) {
|
||||
console.log("-", testPath);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,29 @@ pub fn BabyList(comptime Type: type) type {
|
||||
|
||||
pub const Elem = Type;
|
||||
|
||||
pub fn parse(input: *bun.css.Parser) bun.css.Result(ListType) {
|
||||
return switch (input.parseCommaSeparated(Type, bun.css.generic.parseFor(Type))) {
|
||||
.result => |v| return .{ .result = ListType{
|
||||
.ptr = v.items.ptr,
|
||||
.len = @intCast(v.items.len),
|
||||
.cap = @intCast(v.capacity),
|
||||
} },
|
||||
.err => |e| return .{ .err = e },
|
||||
};
|
||||
}
|
||||
|
||||
pub fn toCss(this: *const ListType, comptime W: type, dest: *bun.css.Printer(W)) bun.css.PrintErr!void {
|
||||
return bun.css.to_css.fromBabyList(Type, this, W, dest);
|
||||
}
|
||||
|
||||
pub fn eql(lhs: *const ListType, rhs: *const ListType) bool {
|
||||
if (lhs.len != rhs.len) return false;
|
||||
for (lhs.sliceConst(), rhs.sliceConst()) |*a, *b| {
|
||||
if (!bun.css.generic.eql(Type, a, b)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn set(this: *@This(), slice_: []Type) void {
|
||||
this.ptr = slice_.ptr;
|
||||
this.len = @as(u32, @truncate(slice_.len));
|
||||
@@ -29,6 +52,12 @@ pub fn BabyList(comptime Type: type) type {
|
||||
this.* = .{};
|
||||
}
|
||||
|
||||
pub fn shrinkAndFree(this: *@This(), allocator: std.mem.Allocator, size: usize) void {
|
||||
var list_ = this.listManaged(allocator);
|
||||
list_.shrinkAndFree(size);
|
||||
this.update(list_);
|
||||
}
|
||||
|
||||
pub fn orderedRemove(this: *@This(), index: usize) Type {
|
||||
var l = this.list();
|
||||
defer this.update(l);
|
||||
@@ -290,6 +319,11 @@ pub fn BabyList(comptime Type: type) type {
|
||||
return this.ptr[0..this.len];
|
||||
}
|
||||
|
||||
pub fn sliceConst(this: *const ListType) callconv(bun.callconv_inline) []const Type {
|
||||
@setRuntimeSafety(false);
|
||||
return this.ptr[0..this.len];
|
||||
}
|
||||
|
||||
pub fn write(this: *@This(), allocator: std.mem.Allocator, str: []const u8) !u32 {
|
||||
if (comptime Type != u8)
|
||||
@compileError("Unsupported for type " ++ @typeName(Type));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
6
src/bake/bake.private.d.ts
vendored
6
src/bake/bake.private.d.ts
vendored
@@ -40,7 +40,11 @@ declare const side: "client" | "server";
|
||||
*/
|
||||
declare var server_exports: {
|
||||
handleRequest: (req: Request, meta: HandleRequestMeta, id: Id) => any;
|
||||
registerUpdate: (modules: any) => void;
|
||||
registerUpdate: (
|
||||
modules: any,
|
||||
componentManifestAdd: null | string[],
|
||||
componentManifestDelete: null | string[],
|
||||
) => void;
|
||||
};
|
||||
|
||||
interface HandleRequestMeta {
|
||||
|
||||
@@ -42,8 +42,8 @@ extern fn BakeInitProcessIdentifier() void;
|
||||
///
|
||||
/// Full documentation on these fields is located in the TypeScript definitions.
|
||||
pub const Framework = struct {
|
||||
entry_client: ?[]const u8 = null,
|
||||
entry_server: ?[]const u8 = null,
|
||||
entry_client: []const u8,
|
||||
entry_server: []const u8,
|
||||
|
||||
server_components: ?ServerComponents = null,
|
||||
react_fast_refresh: ?ReactFastRefresh = null,
|
||||
@@ -59,7 +59,7 @@ pub const Framework = struct {
|
||||
.server_components = .{
|
||||
.separate_ssr_graph = true,
|
||||
.server_runtime_import = "react-server-dom-webpack/server",
|
||||
.client_runtime_import = "react-server-dom-webpack/client",
|
||||
// .client_runtime_import = "react-server-dom-webpack/client",
|
||||
},
|
||||
.react_fast_refresh = .{},
|
||||
.entry_client = "bun-framework-rsc/client.tsx",
|
||||
@@ -88,7 +88,7 @@ pub const Framework = struct {
|
||||
const ServerComponents = struct {
|
||||
separate_ssr_graph: bool = false,
|
||||
server_runtime_import: []const u8,
|
||||
client_runtime_import: []const u8,
|
||||
// client_runtime_import: []const u8,
|
||||
server_register_client_reference: []const u8 = "registerClientReference",
|
||||
server_register_server_reference: []const u8 = "registerServerReference",
|
||||
client_register_server_reference: []const u8 = "registerServerReference",
|
||||
@@ -106,16 +106,16 @@ pub const Framework = struct {
|
||||
var clone = f;
|
||||
var had_errors: bool = false;
|
||||
|
||||
if (clone.entry_client) |*path| f.resolveHelper(client, path, &had_errors);
|
||||
if (clone.entry_server) |*path| f.resolveHelper(server, path, &had_errors);
|
||||
f.resolveHelper(client, &clone.entry_client, &had_errors, "client entrypoint");
|
||||
f.resolveHelper(server, &clone.entry_server, &had_errors, "server entrypoint");
|
||||
|
||||
if (clone.react_fast_refresh) |*react_fast_refresh| {
|
||||
f.resolveHelper(client, &react_fast_refresh.import_source, &had_errors);
|
||||
f.resolveHelper(client, &react_fast_refresh.import_source, &had_errors, "react refresh runtime");
|
||||
}
|
||||
|
||||
if (clone.server_components) |*sc| {
|
||||
f.resolveHelper(server, &sc.server_runtime_import, &had_errors);
|
||||
f.resolveHelper(client, &sc.client_runtime_import, &had_errors);
|
||||
f.resolveHelper(server, &sc.server_runtime_import, &had_errors, "server components runtime");
|
||||
// f.resolveHelper(client, &sc.client_runtime_import, &had_errors);
|
||||
}
|
||||
|
||||
if (had_errors) return error.ModuleNotFound;
|
||||
@@ -123,7 +123,7 @@ pub const Framework = struct {
|
||||
return clone;
|
||||
}
|
||||
|
||||
inline fn resolveHelper(f: *const Framework, r: *bun.resolver.Resolver, path: *[]const u8, had_errors: *bool) void {
|
||||
inline fn resolveHelper(f: *const Framework, r: *bun.resolver.Resolver, path: *[]const u8, had_errors: *bool, desc: []const u8) void {
|
||||
if (f.built_in_modules.get(path.*)) |mod| {
|
||||
switch (mod) {
|
||||
.import => |p| path.* = p,
|
||||
@@ -133,9 +133,8 @@ pub const Framework = struct {
|
||||
}
|
||||
|
||||
var result = r.resolve(r.fs.top_level_dir, path.*, .stmt) catch |err| {
|
||||
bun.Output.err(err, "Failed to resolve '{s}' for framework", .{path.*});
|
||||
bun.Output.err(err, "Failed to resolve '{s}' for framework ({s})", .{ path.*, desc });
|
||||
had_errors.* = true;
|
||||
|
||||
return;
|
||||
};
|
||||
path.* = result.path().?.text; // TODO: what is the lifetime of this string
|
||||
@@ -203,17 +202,17 @@ pub const Framework = struct {
|
||||
bun.todoPanic(@src(), "custom react-fast-refresh import source", .{});
|
||||
},
|
||||
.server_components = sc: {
|
||||
const rfr: JSValue = opts.get(global, "serverComponents") orelse {
|
||||
const sc: JSValue = opts.get(global, "serverComponents") orelse {
|
||||
if (global.hasException())
|
||||
return error.JSError;
|
||||
break :sc null;
|
||||
};
|
||||
if (rfr == .null or rfr == .undefined) break :sc null;
|
||||
if (sc == .null or sc == .undefined) break :sc null;
|
||||
|
||||
break :sc .{
|
||||
.client_runtime_import = "",
|
||||
// .client_runtime_import = "",
|
||||
.separate_ssr_graph = brk: {
|
||||
const prop: JSValue = opts.get(global, "separateSSRGraph") orelse {
|
||||
const prop: JSValue = sc.get(global, "separateSSRGraph") orelse {
|
||||
if (!global.hasException())
|
||||
global.throwInvalidArguments("Missing 'framework.serverComponents.separateSSRGraph'", .{});
|
||||
return error.JSError;
|
||||
@@ -224,7 +223,7 @@ pub const Framework = struct {
|
||||
return error.JSError;
|
||||
},
|
||||
.server_runtime_import = brk: {
|
||||
const prop: JSValue = opts.get(global, "serverRuntimeImportSource") orelse {
|
||||
const prop: JSValue = sc.get(global, "serverRuntimeImportSource") orelse {
|
||||
if (!global.hasException())
|
||||
global.throwInvalidArguments("Missing 'framework.serverComponents.serverRuntimeImportSource'", .{});
|
||||
return error.JSError;
|
||||
@@ -239,7 +238,7 @@ pub const Framework = struct {
|
||||
break :brk str.toUTF8(bun.default_allocator).slice();
|
||||
},
|
||||
.server_register_client_reference = brk: {
|
||||
const prop: JSValue = opts.get(global, "serverRegisterClientReferenceExport") orelse {
|
||||
const prop: JSValue = sc.get(global, "serverRegisterClientReferenceExport") orelse {
|
||||
if (!global.hasException())
|
||||
global.throwInvalidArguments("Missing 'framework.serverComponents.serverRegisterClientReferenceExport'", .{});
|
||||
return error.JSError;
|
||||
@@ -326,14 +325,13 @@ pub fn getHmrRuntime(mode: Side) []const u8 {
|
||||
.server => @embedFile("bake-codegen/bake.server.js"),
|
||||
}
|
||||
else switch (mode) {
|
||||
inline else => |m| bun.runtimeEmbedFile(.codegen, "bake." ++ @tagName(m) ++ ".js"),
|
||||
inline else => |m| bun.runtimeEmbedFile(.codegen_eager, "bake." ++ @tagName(m) ++ ".js"),
|
||||
};
|
||||
}
|
||||
|
||||
pub const Mode = enum { production, development };
|
||||
pub const Side = enum { client, server };
|
||||
/// TODO: Rename this to Graph
|
||||
pub const Renderer = enum(u2) {
|
||||
pub const Graph = enum(u2) {
|
||||
client,
|
||||
server,
|
||||
/// Only used when Framework has .server_components.separate_ssr_graph set
|
||||
|
||||
82
src/bake/client/error-serialization.ts
Normal file
82
src/bake/client/error-serialization.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
// This implements error deserialization from the WebSocket protocol
|
||||
import { BundlerMessageLevel } from "../enums";
|
||||
import { DataViewReader } from "./reader";
|
||||
|
||||
export interface DeserializedFailure {
|
||||
// If not specified, it is a client-side error.
|
||||
file: string | null;
|
||||
messages: BundlerMessage[];
|
||||
};
|
||||
|
||||
export interface BundlerMessage {
|
||||
kind: "bundler";
|
||||
level: BundlerMessageLevel;
|
||||
message: string;
|
||||
location: BundlerMessageLocation | null;
|
||||
notes: BundlerNote[];
|
||||
}
|
||||
|
||||
export interface BundlerMessageLocation {
|
||||
/** One-based */
|
||||
line: number;
|
||||
/** One-based */
|
||||
column: number;
|
||||
/** Byte length */
|
||||
length: number;
|
||||
lineText: string;
|
||||
}
|
||||
|
||||
export interface BundlerNote {
|
||||
message: string;
|
||||
location: BundlerMessageLocation | null;
|
||||
}
|
||||
|
||||
export function decodeSerializedError(reader: DataViewReader) {
|
||||
const kind = reader.u8();
|
||||
if (kind >= 0 && kind <= 4) {
|
||||
return readLogMsg(reader, kind);
|
||||
} else {
|
||||
throw new Error("TODO: JS Errors");
|
||||
}
|
||||
}
|
||||
|
||||
/** First byte is already read in. */
|
||||
function readLogMsg(r: DataViewReader, level: BundlerMessageLevel) {
|
||||
const message = r.string32();
|
||||
const location = readBundlerMessageLocationOrNull(r);
|
||||
const noteCount = r.u32();
|
||||
const notes = new Array(noteCount);
|
||||
for (let i = 0; i < noteCount; i++) {
|
||||
notes[i] = readLogData(r);
|
||||
}
|
||||
return {
|
||||
kind: 'bundler',
|
||||
level,
|
||||
message,
|
||||
location,
|
||||
notes,
|
||||
};
|
||||
}
|
||||
|
||||
function readLogData(r: DataViewReader): BundlerNote | null {
|
||||
return {
|
||||
message: r.string32(),
|
||||
location: readBundlerMessageLocationOrNull(r),
|
||||
};
|
||||
}
|
||||
|
||||
function readBundlerMessageLocationOrNull(r: DataViewReader): BundlerMessageLocation | null {
|
||||
const line = r.u32();
|
||||
if (line == 0) return null;
|
||||
|
||||
const column = r.u32();
|
||||
const length = r.u32();
|
||||
const lineText = r.string32();
|
||||
|
||||
return {
|
||||
line,
|
||||
column,
|
||||
length,
|
||||
lineText,
|
||||
};
|
||||
}
|
||||
0
src/bake/client/jsx-runtime.ts
Normal file
0
src/bake/client/jsx-runtime.ts
Normal file
@@ -3,12 +3,26 @@
|
||||
* the user's application causes no issue. This sheet is used to
|
||||
* style error popups and other elements provided by DevServer.
|
||||
*/
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
main {
|
||||
.root {
|
||||
color-scheme: light dark;
|
||||
|
||||
--modal-bg: light-dark(#efefef, #202020);
|
||||
--modal-text: light-dark(#0a0a0a, #fafafa);
|
||||
--modal-text-faded: light-dark(#0a0a0a88, #fafafa88);
|
||||
--item-bg: light-dark(#d4d4d4, #0f0f0f);
|
||||
--item-bg-hover: light-dark(#cccccc, #171717);
|
||||
--red: #ff5858;
|
||||
--log-error: light-dark(#dc0000, #ff5858);
|
||||
--log-warn: light-dark(#eab308, #fbbf24);
|
||||
--log-note: light-dark(#008ae6, #22d3ee);
|
||||
--log-colon: light-dark(#888, #888);
|
||||
|
||||
font-family:
|
||||
system-ui,
|
||||
-apple-system,
|
||||
@@ -21,9 +35,142 @@ main {
|
||||
"Open Sans",
|
||||
"Helvetica Neue",
|
||||
sans-serif;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.error {
|
||||
padding: 1rem;
|
||||
background-color: rgba(255, 169, 169, 0.9);
|
||||
code,
|
||||
.file-name,
|
||||
.message {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
}
|
||||
|
||||
.modal {
|
||||
color: var(--modal-text);
|
||||
background-color: var(--modal-bg);
|
||||
border-top: 8px solid var(--red);
|
||||
border-radius: 8px;
|
||||
margin: 4rem 2rem 2rem 2rem;
|
||||
max-width: 940px;
|
||||
width: 100%;
|
||||
box-shadow:
|
||||
0 2px 6px #0004,
|
||||
0 2px 32px #0003;
|
||||
}
|
||||
|
||||
header {
|
||||
margin: 1rem 1rem;
|
||||
color: var(--red);
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
footer {
|
||||
color: var(--modal-text-faded);
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
pre {
|
||||
font: unset;
|
||||
}
|
||||
|
||||
.message-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--item-bg);
|
||||
}
|
||||
|
||||
/* this is a <button> */
|
||||
.file-name {
|
||||
appearance: none;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
font-size: unset;
|
||||
font-weight: bold;
|
||||
padding: 0.5rem 1rem;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* .file-name:hover,
|
||||
.file-name:focus-visible {
|
||||
background-color: var(--item-bg-hover);
|
||||
}
|
||||
|
||||
.file-name::after {
|
||||
color: var(--modal-text-faded);
|
||||
font-size: 70%;
|
||||
}
|
||||
|
||||
.file-name:hover::after {
|
||||
content: " (click to open in editor)";
|
||||
} */
|
||||
|
||||
.message {
|
||||
margin: 1rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
button+.message {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.message-text>span {
|
||||
color: var(--color);
|
||||
}
|
||||
|
||||
.log-error {
|
||||
--color: var(--log-error);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.log-warn {
|
||||
--color: var(--log-warn);
|
||||
}
|
||||
|
||||
.log-note {
|
||||
--color: var(--log-note);
|
||||
}
|
||||
|
||||
.log-colon {
|
||||
--color: var(--log-colon);
|
||||
}
|
||||
|
||||
.code-line {
|
||||
display: flex;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.line-num {
|
||||
color: var(--modal-text-faded);
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.highlight-wrap {
|
||||
color: transparent;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
transform: translateY(-20px);
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
|
||||
.highlight-wrap .line {
|
||||
margin-left: 10px;
|
||||
text-decoration: underline;
|
||||
text-decoration-style: wavy;
|
||||
text-decoration-color: var(--color);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
|
||||
.log-warn,
|
||||
.log-note {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,252 @@
|
||||
// This file implements the UI for error modals. Since using a framework like
|
||||
// React could collide with the user's code (consider React DevTools), this
|
||||
// entire modal is written from scratch using the standard DOM APIs. All CSS is
|
||||
// scoped in `overlay.css`, and all elements exist under a shadow root. These
|
||||
// constraints make the overlay simple to understand and work on.
|
||||
//
|
||||
// This file has two consumers:
|
||||
// - The bundler error page which embeds a list of bundler errors to render.
|
||||
// - The client runtime, for when reloading errors happen.
|
||||
// Both use a WebSocket to coordinate followup updates, when new errors are
|
||||
// added or previous ones are solved.
|
||||
import { BundlerMessageLevel } from "../enums";
|
||||
import { css } from "../macros" with { type: "macro" };
|
||||
import { BundlerMessage, BundlerMessageLocation, BundlerNote, decodeSerializedError, type DeserializedFailure } from "./error-serialization";
|
||||
import { DataViewReader } from "./reader";
|
||||
|
||||
// Create a root element to contain all our our DOM nodes.
|
||||
var root!: HTMLElement;
|
||||
var mount;
|
||||
if (side !== "client") throw new Error("Not client side!");
|
||||
|
||||
if (side === "client") {
|
||||
mount = function mount() {
|
||||
const wrap = document.createElement("bun-hmr");
|
||||
wrap.setAttribute(
|
||||
"style",
|
||||
"position:absolute;display:block;top:0;left:0;width:100%;height:100%;background:transparent",
|
||||
);
|
||||
const shadow = wrap.attachShadow({ mode: "open" });
|
||||
|
||||
const sheet = new CSSStyleSheet();
|
||||
sheet.replace(css("client/overlay.css", IS_BUN_DEVELOPMENT));
|
||||
shadow.adoptedStyleSheets = [sheet];
|
||||
|
||||
root = document.createElement("main");
|
||||
shadow.appendChild(root);
|
||||
document.body.appendChild(wrap);
|
||||
};
|
||||
// I would have used JSX, but TypeScript types interfere in odd ways.
|
||||
function elem(tagName: string, props?: null | Record<string, string>, children?: (HTMLElement | Text)[]) {
|
||||
const node = document.createElement(tagName);
|
||||
if (props)
|
||||
for (let key in props) {
|
||||
node.setAttribute(key, props[key]);
|
||||
}
|
||||
if (children)
|
||||
for (const child of children) {
|
||||
node.appendChild(child);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
export function showErrorOverlay(e) {
|
||||
mount();
|
||||
console.error(e);
|
||||
root.innerHTML = `<div class='error'><h1>Client-side Runtime Error</h1><pre><code>${e?.message ? `${e?.name ?? e?.constructor?.name ?? "Error"}: ${e.message}\n` : JSON.stringify(e)}${e?.message ? e?.stack : ""}</code></pre><button class='dismiss'>x</button></div>`;
|
||||
root.querySelector(".dismiss")!.addEventListener("click", () => {
|
||||
root.innerHTML = "";
|
||||
function elemText(tagName: string, props: null | Record<string, string>, innerHTML: string) {
|
||||
const node = document.createElement(tagName);
|
||||
if (props)
|
||||
for (let key in props) {
|
||||
node.setAttribute(key, props[key]);
|
||||
}
|
||||
node.textContent = innerHTML;
|
||||
return node;
|
||||
}
|
||||
|
||||
const textNode = (str = "") => document.createTextNode(str);
|
||||
|
||||
/**
|
||||
* 32-bit integer corresponding to `SerializedFailure.Owner.Packed`
|
||||
* It is never decoded client-side; treat this as an opaque identifier.
|
||||
*/
|
||||
type ErrorId = number;
|
||||
|
||||
const errors = new Map<ErrorId, DeserializedFailure>();
|
||||
const errorDoms = new Map<ErrorId, ErrorDomNodes>();
|
||||
const updatedErrorOwners = new Set<ErrorId>();
|
||||
|
||||
let domShadowRoot: HTMLElement;
|
||||
let domModalTitle: Text;
|
||||
let domErrorList: HTMLElement;
|
||||
|
||||
interface ErrorDomNodes {
|
||||
root: HTMLElement;
|
||||
title: Text;
|
||||
messages: HTMLElement[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial mount is done lazily. The modal starts invisible, controlled
|
||||
* by `setModalVisible`.
|
||||
*/
|
||||
function mountModal() {
|
||||
if (domModalTitle) return;
|
||||
domShadowRoot = elem("bun-hmr", {
|
||||
style:
|
||||
"position:absolute!important;" +
|
||||
"display:none!important;" +
|
||||
"top:0!important;" +
|
||||
"left:0!important;" +
|
||||
"width:100%!important;" +
|
||||
"height:100%!important;" +
|
||||
"background:#8883!important",
|
||||
});
|
||||
const shadow = domShadowRoot.attachShadow({ mode: "open" });
|
||||
const sheet = new CSSStyleSheet();
|
||||
sheet.replace(css("client/overlay.css", IS_BUN_DEVELOPMENT));
|
||||
shadow.adoptedStyleSheets = [sheet];
|
||||
|
||||
const root = elem("div", { class: "root" }, [
|
||||
elem("div", { class: "modal" }, [
|
||||
elem("header", null, [(domModalTitle = textNode())]),
|
||||
(domErrorList = elem("div", { class: "error-list" })),
|
||||
elem("footer", null, [
|
||||
// TODO: for HMR turn this into a clickable thing + say it can be dismissed
|
||||
textNode("Errors during a build can only be dismissed fixing them."),
|
||||
]),
|
||||
]),
|
||||
]);
|
||||
shadow.appendChild(root);
|
||||
document.body.appendChild(domShadowRoot);
|
||||
}
|
||||
|
||||
let isModalVisible = false;
|
||||
function setModalVisible(visible: boolean) {
|
||||
if (isModalVisible === visible || !domShadowRoot) return;
|
||||
isModalVisible = visible;
|
||||
domShadowRoot.style.display = visible ? "block" : "none";
|
||||
}
|
||||
|
||||
/** Handler for `MessageId.errors` websocket packet */
|
||||
export function onErrorMessage(view: DataView) {
|
||||
const reader = new DataViewReader(view, 1);
|
||||
const removedCount = reader.u32();
|
||||
|
||||
for (let i = 0; i < removedCount; i++) {
|
||||
const removed = reader.u32();
|
||||
updatedErrorOwners.add(removed);
|
||||
errors.delete(removed);
|
||||
}
|
||||
|
||||
while (reader.hasMoreData()) {
|
||||
decodeAndAppendError(reader);
|
||||
}
|
||||
|
||||
updateErrorOverlay();
|
||||
}
|
||||
|
||||
export function onErrorClearedMessage() {
|
||||
errors.keys().forEach(key => updatedErrorOwners.add(key));
|
||||
errors.clear();
|
||||
updateErrorOverlay();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this for each error, then call `updateErrorOverlay` to commit the
|
||||
* changes to the UI in one smooth motion.
|
||||
*/
|
||||
export function decodeAndAppendError(r: DataViewReader) {
|
||||
const owner = r.u32();
|
||||
const file = r.string32() || null;
|
||||
const messageCount = r.u32();
|
||||
const messages = new Array(messageCount);
|
||||
for (let i = 0; i < messageCount; i++) {
|
||||
messages[i] = decodeSerializedError(r);
|
||||
}
|
||||
errors.set(owner, { file, messages });
|
||||
updatedErrorOwners.add(owner);
|
||||
}
|
||||
|
||||
export function updateErrorOverlay() {
|
||||
console.log(errors, updatedErrorOwners);
|
||||
|
||||
if (errors.size === 0) {
|
||||
setModalVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
mountModal();
|
||||
|
||||
let totalCount = 0;
|
||||
|
||||
for (const owner of updatedErrorOwners) {
|
||||
const data = errors.get(owner);
|
||||
let dom = errorDoms.get(owner);
|
||||
|
||||
// If this failure was removed, delete it.
|
||||
if (!data) {
|
||||
dom?.root.remove();
|
||||
errorDoms.delete(owner);
|
||||
continue;
|
||||
}
|
||||
|
||||
totalCount += data.messages.length;
|
||||
|
||||
// Create the element for the root if it does not yet exist.
|
||||
if (!dom) {
|
||||
let title;
|
||||
const root = elem("div", { class: "message-group" }, [
|
||||
elem("button", { class: "file-name" }, [
|
||||
title = textNode()
|
||||
]),
|
||||
]);
|
||||
dom = { root, title, messages: [] };
|
||||
// TODO: sorted insert?
|
||||
domErrorList.appendChild(root);
|
||||
errorDoms.set(owner, dom);
|
||||
} else {
|
||||
// For simplicity, messages are not reused, even if left unchanged.
|
||||
dom.messages.forEach(msg => msg.remove());
|
||||
}
|
||||
|
||||
// Update the DOM with the new data.
|
||||
dom.title.textContent = data.file;
|
||||
|
||||
for (const msg of data.messages) {
|
||||
const domMessage = renderBundlerMessage(msg);
|
||||
dom.root.appendChild(domMessage);
|
||||
dom.messages.push(domMessage);
|
||||
}
|
||||
}
|
||||
|
||||
domModalTitle.textContent = `${errors.size} Build Error${errors.size !== 1 ? "s" : ""}`;
|
||||
|
||||
updatedErrorOwners.clear();
|
||||
|
||||
setModalVisible(true);
|
||||
}
|
||||
|
||||
const bundleLogLevelToName = [
|
||||
"error",
|
||||
"warn",
|
||||
"note",
|
||||
"debug",
|
||||
"verbose",
|
||||
];
|
||||
|
||||
function renderBundlerMessage(msg: BundlerMessage) {
|
||||
return elem('div', { class: 'message' }, [
|
||||
renderErrorMessageLine(msg.level, msg.message),
|
||||
...msg.location ? renderCodeLine(msg.location, msg.level) : [],
|
||||
...msg.notes.map(renderNote),
|
||||
].flat(1));
|
||||
}
|
||||
|
||||
function renderErrorMessageLine(level: BundlerMessageLevel, text: string) {
|
||||
const levelName = bundleLogLevelToName[level];
|
||||
if(IS_BUN_DEVELOPMENT && !levelName) {
|
||||
throw new Error("Unknown log level: " + level);
|
||||
}
|
||||
return elem('div', { class: 'message-text' } , [
|
||||
elemText('span', { class: 'log-' + levelName }, levelName),
|
||||
elemText('span', { class: 'log-colon' }, ': '),
|
||||
elemText('span', { class: 'log-text' }, text),
|
||||
]);
|
||||
}
|
||||
|
||||
function renderCodeLine(location: BundlerMessageLocation, level: BundlerMessageLevel) {
|
||||
return [
|
||||
elem('div', { class: 'code-line' }, [
|
||||
elemText('code', { class: 'line-num' }, `${location.line}`),
|
||||
elemText('pre', { class: 'code-view' }, location.lineText),
|
||||
]),
|
||||
elem('div', { class: 'highlight-wrap log-' + bundleLogLevelToName[level] }, [
|
||||
elemText('span', { class: 'space' }, '_'.repeat(`${location.line}`.length + location.column - 1)),
|
||||
elemText('span', { class: 'line' }, '_'.repeat(location.length)),
|
||||
])
|
||||
];
|
||||
}
|
||||
|
||||
function renderNote(note: BundlerNote) {
|
||||
return [
|
||||
renderErrorMessageLine(BundlerMessageLevel.note, note.message),
|
||||
...note.location ? renderCodeLine(note.location, BundlerMessageLevel.note) : [],
|
||||
];
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { td } from "../text-decoder";
|
||||
import { td } from "../shared";
|
||||
|
||||
export class DataViewReader {
|
||||
view: DataView;
|
||||
@@ -27,9 +27,17 @@ export class DataViewReader {
|
||||
return value;
|
||||
}
|
||||
|
||||
string(byteLength: number) {
|
||||
stringWithLength(byteLength: number) {
|
||||
const str = td.decode(this.view.buffer.slice(this.cursor, this.cursor + byteLength));
|
||||
this.cursor += byteLength;
|
||||
return str;
|
||||
}
|
||||
|
||||
string32() {
|
||||
return this.stringWithLength(this.u32());
|
||||
}
|
||||
|
||||
hasMoreData() {
|
||||
return this.cursor < this.view.byteLength;
|
||||
}
|
||||
}
|
||||
|
||||
85
src/bake/client/websocket.ts
Normal file
85
src/bake/client/websocket.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
const isLocal = location.host === "localhost" || location.host === "127.0.0.1";
|
||||
|
||||
function wait() {
|
||||
return new Promise<void>(done => {
|
||||
let timer;
|
||||
|
||||
const onTimeout = () => {
|
||||
if (timer !== null) clearTimeout(timer);
|
||||
document.removeEventListener("focus", onTimeout);
|
||||
done();
|
||||
};
|
||||
|
||||
document.addEventListener("focus", onTimeout);
|
||||
timer = setTimeout(
|
||||
() => {
|
||||
timer = null;
|
||||
onTimeout();
|
||||
},
|
||||
isLocal ? 2_500 : 30_000,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function initWebSocket(handlers: Record<number, (dv: DataView) => void>) {
|
||||
let firstConnection = true;
|
||||
|
||||
function onOpen() {
|
||||
if (firstConnection) {
|
||||
firstConnection = false;
|
||||
console.info("[Bun] Hot-module-reloading socket connected, waiting for changes...");
|
||||
}
|
||||
}
|
||||
|
||||
function onMessage(ev: MessageEvent<string | ArrayBuffer>) {
|
||||
const { data } = ev;
|
||||
if (typeof data === "object") {
|
||||
const view = new DataView(data);
|
||||
if (IS_BUN_DEVELOPMENT) {
|
||||
console.info("[WS] " + String.fromCharCode(view.getUint8(0)));
|
||||
}
|
||||
handlers[view.getUint8(0)]?.(view);
|
||||
}
|
||||
}
|
||||
|
||||
function onError(ev: Event) {
|
||||
console.error(ev);
|
||||
}
|
||||
|
||||
async function onClose() {
|
||||
console.warn("[Bun] Hot-module-reloading socket disconnected, reconnecting...");
|
||||
|
||||
while (true) {
|
||||
await wait();
|
||||
|
||||
// Note: Cannot use Promise.withResolvers due to lacking support on iOS
|
||||
let done;
|
||||
const promise = new Promise<boolean>(cb => (done = cb));
|
||||
|
||||
ws = new WebSocket("/_bun/hmr");
|
||||
ws.binaryType = "arraybuffer";
|
||||
ws.onopen = () => {
|
||||
console.info("[Bun] Reconnected");
|
||||
done(true);
|
||||
onOpen();
|
||||
ws.onerror = onError;
|
||||
};
|
||||
ws.onmessage = onMessage;
|
||||
ws.onerror = ev => {
|
||||
onError(ev);
|
||||
done(false);
|
||||
};
|
||||
|
||||
if (await promise) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let ws = new WebSocket("/_bun/hmr");
|
||||
ws.binaryType = "arraybuffer";
|
||||
ws.onopen = onOpen;
|
||||
ws.onmessage = onMessage;
|
||||
ws.onclose = onClose;
|
||||
ws.onerror = onError;
|
||||
}
|
||||
26
src/bake/enums.ts
Normal file
26
src/bake/enums.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
// TODO: generate this using information in DevServer.zig
|
||||
|
||||
export const enum MessageId {
|
||||
/// Version packet
|
||||
version = 86,
|
||||
/// When visualization mode is enabled, this packet contains
|
||||
/// the entire serialized IncrementalGraph state.
|
||||
visualizer = 118,
|
||||
/// Sent on a successful bundle, containing client code.
|
||||
hot_update = 40,
|
||||
/// Sent on a successful bundle, containing a list of
|
||||
/// routes that are updated.
|
||||
route_update = 82,
|
||||
/// Sent when the list of errors changes.
|
||||
errors = 69,
|
||||
/// Sent when all errors are cleared. Semi-redundant
|
||||
errors_cleared = 99,
|
||||
}
|
||||
|
||||
export const enum BundlerMessageLevel {
|
||||
err = 0,
|
||||
warn = 1,
|
||||
note = 2,
|
||||
debug = 3,
|
||||
verbose = 4,
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{[page_title]s}</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script id="bun_error_payload" type="text/bun-error-payload">
|
||||
{[error_payload]s}
|
||||
</script>
|
||||
<script src="/_bun/error.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -19,9 +19,9 @@ export const enum LoadModuleType {
|
||||
|
||||
/**
|
||||
* This object is passed as the CommonJS "module", but has a bunch of
|
||||
* non-standard properties that are used for implementing hot-module
|
||||
* reloading. It is unacceptable to depend on these properties, and
|
||||
* it will not be considered a breaking change.
|
||||
* non-standard properties that are used for implementing hot-module reloading.
|
||||
* It is unacceptable for users to depend on these properties, and it will not
|
||||
* be considered a breaking change when these internals are altered.
|
||||
*/
|
||||
export class HotModule<E = any> {
|
||||
id: Id;
|
||||
@@ -115,6 +115,8 @@ export function loadModule<T = any>(key: Id, type: LoadModuleType): HotModule<T>
|
||||
return module;
|
||||
}
|
||||
|
||||
export const getModule = registry.get.bind(registry);
|
||||
|
||||
export function replaceModule(key: Id, load: ModuleLoadFunction) {
|
||||
const module = registry.get(key);
|
||||
if (module) {
|
||||
@@ -151,6 +153,16 @@ export function replaceModules(modules: any) {
|
||||
registry.set("bun:wrap", runtime);
|
||||
}
|
||||
|
||||
export const serverManifest = {};
|
||||
export const clientManifest = {};
|
||||
|
||||
if (side === "server") {
|
||||
const server_module = new HotModule("bun:bake/server");
|
||||
server_module.__esModule = true;
|
||||
server_module.exports = { serverManifest, clientManifest };
|
||||
registry.set(server_module.id, server_module);
|
||||
}
|
||||
|
||||
if (side === "client") {
|
||||
const { refresh } = config;
|
||||
if (refresh) {
|
||||
|
||||
@@ -33,15 +33,24 @@ V1.1.30-canary.37+117e1b388
|
||||
|
||||
Hot-module-reloading patch. The entire payload is UTF-8 Encoded JavaScript Payload.
|
||||
|
||||
### `R`
|
||||
### `R` - Route reload request
|
||||
|
||||
Server-side code has reloaded. Client should either refetch the route or perform a hard reload.
|
||||
|
||||
- `u32` Number of updated routes
|
||||
- `u32`: Number of updated routes
|
||||
- For each route:
|
||||
- `u32` Route ID
|
||||
- `u16` Length of route name.
|
||||
- `[n]u8` Route name in UTF-8 encoded text.
|
||||
- `u32`: Route ID
|
||||
- `u16`: Length of route name.
|
||||
- `[n]u8`: Route name in UTF-8 encoded text.
|
||||
|
||||
### `e` - Error status update
|
||||
|
||||
- `u32`: Number of errors removed
|
||||
- For each removed error:
|
||||
- `u32` Error owner
|
||||
- Remainder of payload is repeating each error object:
|
||||
- `u32` Error owner
|
||||
- Error Payload
|
||||
|
||||
### `v`
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
// This file is the entrypoint to the hot-module-reloading runtime
|
||||
// In the browser, this uses a WebSocket to communicate with the bundler.
|
||||
import { loadModule, LoadModuleType, replaceModules } from "./hmr-module";
|
||||
import { showErrorOverlay } from "./client/overlay";
|
||||
import { onErrorClearedMessage, onErrorMessage } from "./client/overlay";
|
||||
import { Bake } from "bun";
|
||||
import { int } from "./macros" with { type: "macro" };
|
||||
import { td } from "./text-decoder";
|
||||
import { td } from "./shared";
|
||||
import { DataViewReader } from "./client/reader";
|
||||
import { routeMatch } from "./client/route";
|
||||
import { initWebSocket } from "./client/websocket";
|
||||
import { MessageId } from "./enums";
|
||||
|
||||
if (typeof IS_BUN_DEVELOPMENT !== "boolean") {
|
||||
throw new Error("DCE is configured incorrectly");
|
||||
@@ -23,7 +24,7 @@ async function performRouteReload() {
|
||||
console.error(err);
|
||||
console.error("The page will hard-reload now.");
|
||||
if (IS_BUN_DEVELOPMENT) {
|
||||
return showErrorOverlay(err);
|
||||
// return showErrorOverlay(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,84 +34,45 @@ async function performRouteReload() {
|
||||
location.reload();
|
||||
}
|
||||
|
||||
try {
|
||||
const main = loadModule<Bake.ClientEntryPoint>(config.main, LoadModuleType.AssertPresent);
|
||||
let main;
|
||||
|
||||
try {
|
||||
main = loadModule<Bake.ClientEntryPoint>(config.main, LoadModuleType.AssertPresent);
|
||||
var { onServerSideReload, ...rest } = main.exports;
|
||||
if (Object.keys(rest).length > 0) {
|
||||
console.warn(
|
||||
`Framework client entry point (${config.main}) exported unknown properties, found: ${Object.keys(rest).join(", ")}`,
|
||||
);
|
||||
}
|
||||
|
||||
const enum SocketState {
|
||||
Connecting,
|
||||
Connected,
|
||||
}
|
||||
|
||||
let state = SocketState.Connecting;
|
||||
|
||||
function initHmrWebSocket() {
|
||||
const ws = new WebSocket("/_bun/hmr");
|
||||
ws.binaryType = "arraybuffer";
|
||||
ws.onopen = ev => {
|
||||
console.log("HMR socket open!");
|
||||
state = SocketState.Connected;
|
||||
};
|
||||
ws.onmessage = (ev: MessageEvent<string | ArrayBuffer>) => {
|
||||
const { data } = ev;
|
||||
if (typeof data === "string") return data;
|
||||
const view = new DataView(data);
|
||||
// See hmr-protocol.md
|
||||
switch (view.getUint8(0)) {
|
||||
case int("V"): {
|
||||
console.log("VERSION", data);
|
||||
break;
|
||||
}
|
||||
case int("("): {
|
||||
const code = td.decode(data);
|
||||
const modules = (0, eval)(code);
|
||||
replaceModules(modules);
|
||||
break;
|
||||
}
|
||||
case int("R"): {
|
||||
const reader = new DataViewReader(view, 1);
|
||||
let routeCount = reader.u32();
|
||||
|
||||
while (routeCount > 0) {
|
||||
routeCount -= 1;
|
||||
const routeId = reader.u32();
|
||||
const routePattern = reader.string(reader.u16());
|
||||
if (routeMatch(routeId, routePattern)) {
|
||||
performRouteReload();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (IS_BUN_DEVELOPMENT) {
|
||||
return showErrorOverlay(
|
||||
new Error("Unknown WebSocket Payload ID: " + String.fromCharCode(view.getUint8(0))),
|
||||
);
|
||||
}
|
||||
location.reload();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
ws.onclose = ev => {
|
||||
// TODO: visual feedback in overlay.ts
|
||||
// TODO: reconnection
|
||||
};
|
||||
ws.onerror = ev => {
|
||||
console.error(ev);
|
||||
};
|
||||
}
|
||||
|
||||
initHmrWebSocket();
|
||||
} catch (e) {
|
||||
if (side !== "client") throw e;
|
||||
showErrorOverlay(e);
|
||||
// showErrorOverlay(e);
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
initWebSocket({
|
||||
[MessageId.version](view) {
|
||||
// TODO: config.version and verify everything is sane
|
||||
console.log("VERSION: ", td.decode(view.buffer.slice(1)));
|
||||
},
|
||||
[MessageId.hot_update](view) {
|
||||
const code = td.decode(view.buffer);
|
||||
const modules = (0, eval)(code);
|
||||
replaceModules(modules);
|
||||
},
|
||||
[MessageId.errors]: onErrorMessage,
|
||||
[MessageId.errors_cleared]: onErrorClearedMessage,
|
||||
[MessageId.route_update](view) {
|
||||
const reader = new DataViewReader(view, 1);
|
||||
let routeCount = reader.u32();
|
||||
|
||||
while (routeCount > 0) {
|
||||
routeCount -= 1;
|
||||
const routeId = reader.u32();
|
||||
const routePattern = reader.stringWithLength(reader.u16());
|
||||
if (routeMatch(routeId, routePattern)) {
|
||||
performRouteReload();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
60
src/bake/hmr-runtime-error.ts
Normal file
60
src/bake/hmr-runtime-error.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
// When a bundling error happens, we cannot load any of the users code, since
|
||||
// that code expects the SSR step to succeed. This version of client just opens
|
||||
// a websocket and listens only for error resolution events, and reloads the
|
||||
// page.
|
||||
//
|
||||
// This is embedded in `DevServer.sendSerializedFailures`. SSR is
|
||||
// left unused for simplicity; a flash of unstyled content is
|
||||
// stopped by the fact this script runs synchronously.
|
||||
import { decodeAndAppendError, onErrorMessage, updateErrorOverlay } from "./client/overlay";
|
||||
import { DataViewReader } from "./client/reader";
|
||||
import { routeMatch } from "./client/route";
|
||||
import { initWebSocket } from "./client/websocket";
|
||||
import { MessageId } from "./enums";
|
||||
|
||||
/** Injected by DevServer */
|
||||
declare const error: Uint8Array;
|
||||
|
||||
{
|
||||
const reader = new DataViewReader(new DataView(error.buffer), 0);
|
||||
while (reader.hasMoreData()) {
|
||||
decodeAndAppendError(reader);
|
||||
}
|
||||
updateErrorOverlay();
|
||||
}
|
||||
|
||||
let firstVersionPacket = true;
|
||||
|
||||
initWebSocket({
|
||||
[MessageId.version](dv) {
|
||||
if (firstVersionPacket) {
|
||||
firstVersionPacket = false;
|
||||
} else {
|
||||
// On re-connection, the server may have restarted. The route that was
|
||||
// requested could be in unqueued state. A reload is the only way to
|
||||
// ensure this bundle is enqueued.
|
||||
location.reload();
|
||||
}
|
||||
},
|
||||
|
||||
[MessageId.errors]: onErrorMessage,
|
||||
|
||||
[MessageId.route_update](view) {
|
||||
const reader = new DataViewReader(view, 1);
|
||||
let routeCount = reader.u32();
|
||||
|
||||
while (routeCount > 0) {
|
||||
routeCount -= 1;
|
||||
const routeId = reader.u32();
|
||||
const routePattern = reader.stringWithLength(reader.u16());
|
||||
if (routeMatch(routeId, routePattern)) {
|
||||
location.reload();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
[MessageId.errors_cleared]() {
|
||||
location.reload();
|
||||
},
|
||||
});
|
||||
@@ -2,7 +2,7 @@
|
||||
// On the server, communication is facilitated using the default
|
||||
// export, which is assigned via `server_exports`.
|
||||
import type { Bake } from "bun";
|
||||
import { loadModule, LoadModuleType, replaceModules } from "./hmr-module";
|
||||
import { loadModule, LoadModuleType, replaceModules, clientManifest, serverManifest, getModule } from "./hmr-module";
|
||||
|
||||
if (typeof IS_BUN_DEVELOPMENT !== "boolean") {
|
||||
throw new Error("DCE is configured incorrectly");
|
||||
@@ -32,5 +32,37 @@ server_exports = {
|
||||
// TODO: support streaming
|
||||
return await response.text();
|
||||
},
|
||||
registerUpdate: replaceModules,
|
||||
registerUpdate(modules, componentManifestAdd, componentManifestDelete) {
|
||||
replaceModules(modules);
|
||||
|
||||
if (componentManifestAdd) {
|
||||
for (const uid of componentManifestAdd) {
|
||||
try {
|
||||
const mod = loadModule(uid, LoadModuleType.AssertPresent);
|
||||
const { exports, __esModule } = mod;
|
||||
const exp = __esModule ? exports : (mod._ext_exports ??= { ...exports, default: exports });
|
||||
|
||||
for (const exportName of Object.keys(exp)) {
|
||||
serverManifest[uid] = {
|
||||
id: uid,
|
||||
name: exportName,
|
||||
chunks: [],
|
||||
};
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (componentManifestDelete) {
|
||||
for (const fileName of componentManifestDelete) {
|
||||
const client = clientManifest[fileName];
|
||||
for (const exportName in client) {
|
||||
delete serverManifest[`${fileName}#${exportName}`];
|
||||
}
|
||||
delete clientManifest[fileName];
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,326 +1,345 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>IncrementalGraph Visualization</title>
|
||||
<script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
background-color: #1e1e2e;
|
||||
color: #cdd6f4;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>IncrementalGraph Visualization</title>
|
||||
<script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
background-color: #1e1e2e;
|
||||
color: #cdd6f4;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
#network {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
#network {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
h1 {
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
left: 1rem;
|
||||
pointer-events: none;
|
||||
font-size: 1rem;
|
||||
margin: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
h1 {
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
left: 1rem;
|
||||
pointer-events: none;
|
||||
font-size: 1rem;
|
||||
margin: 0;
|
||||
}
|
||||
#stat {
|
||||
font-weight: normal;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
#stat {
|
||||
font-weight: normal;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>IncrementalGraph Visualization <span id="stat"></span></h1>
|
||||
<div id="network"></div>
|
||||
|
||||
<body>
|
||||
<h1>IncrementalGraph Visualization <span id="stat"></span></h1>
|
||||
<div id="network"></div>
|
||||
<script>
|
||||
// Connect to HMR WebSocket and enable visualization packets. This
|
||||
// serializes the both `IncrementalGraph`s in full and sends them
|
||||
// over the wire. A visualization is provided by `vis.js`. Support
|
||||
//
|
||||
// Script written partially by ChatGPT
|
||||
|
||||
<script>
|
||||
const c = {
|
||||
// derived from mocha theme on https://catppuccin.com/palette
|
||||
red: '#f38ba8',
|
||||
green: '#a6e3a1',
|
||||
mauve: '#cba6f7',
|
||||
gray: '#7f849c',
|
||||
orange: '#fab387',
|
||||
sky: '#89dceb',
|
||||
blue: '#89b4fa',
|
||||
yellow: '#f9e2af',
|
||||
};
|
||||
const ws = new WebSocket(location.origin + "/_bun/hmr");
|
||||
const c = {
|
||||
// Derived from mocha theme on https://catppuccin.com/palette
|
||||
red: "#f38ba8",
|
||||
green: "#a6e3a1",
|
||||
mauve: "#cba6f7",
|
||||
gray: "#7f849c",
|
||||
orange: "#fab387",
|
||||
sky: "#89dceb",
|
||||
blue: "#89b4fa",
|
||||
yellow: "#f9e2af",
|
||||
};
|
||||
const ws = new WebSocket(location.origin + "/_bun/hmr");
|
||||
|
||||
ws.binaryType = "arraybuffer"; // We are expecting binary data
|
||||
ws.binaryType = "arraybuffer"; // We are expecting binary data
|
||||
|
||||
ws.onopen = function () {
|
||||
ws.send(new Uint8Array([118])); // Send 'v' byte to initiate connection
|
||||
};
|
||||
ws.onopen = function () {
|
||||
ws.send(new Uint8Array([118])); // Send 'v' byte to initiate connection
|
||||
};
|
||||
|
||||
// Store nodes and edges
|
||||
let clientFiles = [];
|
||||
let serverFiles = [];
|
||||
let clientEdges = [];
|
||||
let serverEdges = [];
|
||||
let currentEdgeIds = new Set();
|
||||
let isFirst = true;
|
||||
// Store nodes and edges
|
||||
let clientFiles = [];
|
||||
let serverFiles = [];
|
||||
let clientEdges = [];
|
||||
let serverEdges = [];
|
||||
let currentEdgeIds = new Set();
|
||||
let currentNodeIds = new Set();
|
||||
let isFirst = true;
|
||||
|
||||
// When a message is received
|
||||
ws.onmessage = function (event) {
|
||||
const buffer = new Uint8Array(event.data);
|
||||
// When a message is received
|
||||
ws.onmessage = function (event) {
|
||||
const buffer = new Uint8Array(event.data);
|
||||
|
||||
// Only process messages starting with 'v' (ASCII code 118)
|
||||
if (buffer[0] !== 118) return;
|
||||
console.log('Got Event');
|
||||
// Only process messages starting with 'v' (ASCII code 118)
|
||||
if (buffer[0] !== 118) return;
|
||||
console.log("Got Event");
|
||||
|
||||
let offset = 1; // Skip the 'v' byte
|
||||
let offset = 1; // Skip the 'v' byte
|
||||
|
||||
// Parse client files
|
||||
const clientFileCount = readUint32(buffer, offset);
|
||||
offset += 4;
|
||||
|
||||
clientFiles = parseFiles(buffer, clientFileCount, offset);
|
||||
offset = clientFiles.offset;
|
||||
clientFiles = clientFiles.files;
|
||||
|
||||
// Parse server files
|
||||
const serverFileCount = readUint32(buffer, offset);
|
||||
offset += 4;
|
||||
|
||||
serverFiles = parseFiles(buffer, serverFileCount, offset);
|
||||
offset = serverFiles.offset;
|
||||
serverFiles = serverFiles.files;
|
||||
|
||||
// Parse client edges
|
||||
const clientEdgeCount = readUint32(buffer, offset);
|
||||
offset += 4;
|
||||
clientEdges = parseEdges(buffer, clientEdgeCount, offset);
|
||||
offset = clientEdges.offset;
|
||||
clientEdges = clientEdges.edges;
|
||||
|
||||
// Parse server edges
|
||||
const serverEdgeCount = readUint32(buffer, offset);
|
||||
offset += 4;
|
||||
serverEdges = parseEdges(buffer, serverEdgeCount, offset);
|
||||
offset = serverEdges.offset;
|
||||
serverEdges = serverEdges.edges;
|
||||
|
||||
// Update the graph visualization
|
||||
updateGraph();
|
||||
};
|
||||
|
||||
// Helper to read 4-byte unsigned int
|
||||
function readUint32(buffer, offset) {
|
||||
return buffer[offset] |
|
||||
(buffer[offset + 1] << 8) |
|
||||
(buffer[offset + 2] << 16) |
|
||||
(buffer[offset + 3] << 24);
|
||||
}
|
||||
|
||||
function basename(path) {
|
||||
return path.slice(path.lastIndexOf('/') + 1)
|
||||
}
|
||||
|
||||
// Parse the files from the buffer
|
||||
function parseFiles(buffer, count, offset) {
|
||||
const files = [];
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const nameLength = readUint32(buffer, offset);
|
||||
// Parse client files
|
||||
const clientFileCount = readUint32(buffer, offset);
|
||||
offset += 4;
|
||||
|
||||
// If the name length is 0, it's a deleted file
|
||||
if (nameLength === 0) {
|
||||
files.push({ id: i, deleted: true });
|
||||
continue;
|
||||
clientFiles = parseFiles(buffer, clientFileCount, offset);
|
||||
offset = clientFiles.offset;
|
||||
clientFiles = clientFiles.files;
|
||||
|
||||
// Parse server files
|
||||
const serverFileCount = readUint32(buffer, offset);
|
||||
offset += 4;
|
||||
|
||||
serverFiles = parseFiles(buffer, serverFileCount, offset);
|
||||
offset = serverFiles.offset;
|
||||
serverFiles = serverFiles.files;
|
||||
|
||||
// Parse client edges
|
||||
const clientEdgeCount = readUint32(buffer, offset);
|
||||
offset += 4;
|
||||
clientEdges = parseEdges(buffer, clientEdgeCount, offset);
|
||||
offset = clientEdges.offset;
|
||||
clientEdges = clientEdges.edges;
|
||||
|
||||
// Parse server edges
|
||||
const serverEdgeCount = readUint32(buffer, offset);
|
||||
offset += 4;
|
||||
serverEdges = parseEdges(buffer, serverEdgeCount, offset);
|
||||
offset = serverEdges.offset;
|
||||
serverEdges = serverEdges.edges;
|
||||
|
||||
// Update the graph visualization
|
||||
updateGraph();
|
||||
};
|
||||
|
||||
// Helper to read 4-byte unsigned int
|
||||
function readUint32(buffer, offset) {
|
||||
return buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24);
|
||||
}
|
||||
|
||||
function basename(path) {
|
||||
return path.slice(path.lastIndexOf("/") + 1);
|
||||
}
|
||||
|
||||
// Parse the files from the buffer
|
||||
function parseFiles(buffer, count, offset) {
|
||||
const files = [];
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const nameLength = readUint32(buffer, offset);
|
||||
offset += 4;
|
||||
|
||||
// If the name length is 0, it's a deleted file
|
||||
if (nameLength === 0) {
|
||||
files.push({ id: i, deleted: true });
|
||||
continue;
|
||||
}
|
||||
|
||||
const nameBytes = buffer.slice(offset, offset + nameLength);
|
||||
const name = new TextDecoder().decode(nameBytes);
|
||||
offset += nameLength;
|
||||
|
||||
const isStale = buffer[offset++] === 1;
|
||||
const isServer = buffer[offset++] === 1;
|
||||
const isSSR = buffer[offset++] === 1;
|
||||
const isRoute = buffer[offset++] === 1;
|
||||
const isFramework = buffer[offset++] === 1;
|
||||
const isBoundary = buffer[offset++] === 1;
|
||||
|
||||
files.push({
|
||||
id: i,
|
||||
name,
|
||||
isStale,
|
||||
isServer,
|
||||
isSSR,
|
||||
isRoute,
|
||||
isFramework,
|
||||
isBoundary,
|
||||
});
|
||||
}
|
||||
|
||||
const nameBytes = buffer.slice(offset, offset + nameLength);
|
||||
const name = new TextDecoder().decode(nameBytes);
|
||||
offset += nameLength;
|
||||
|
||||
const isStale = buffer[offset++] === 1;
|
||||
const isServer = buffer[offset++] === 1;
|
||||
const isSSR = buffer[offset++] === 1;
|
||||
const isRoute = buffer[offset++] === 1;
|
||||
const isFramework = buffer[offset++] === 1;
|
||||
const isBoundary = buffer[offset++] === 1;
|
||||
|
||||
files.push({
|
||||
id: i,
|
||||
name,
|
||||
isStale,
|
||||
isServer,
|
||||
isSSR,
|
||||
isRoute,
|
||||
isFramework,
|
||||
isBoundary
|
||||
});
|
||||
return { files, offset };
|
||||
}
|
||||
|
||||
return { files, offset };
|
||||
}
|
||||
|
||||
// Parse the edges from the buffer
|
||||
function parseEdges(buffer, count, offset) {
|
||||
const edges = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
const from = readUint32(buffer, offset);
|
||||
offset += 4;
|
||||
const to = readUint32(buffer, offset);
|
||||
offset += 4;
|
||||
edges.push({ from, to });
|
||||
// Parse the edges from the buffer
|
||||
function parseEdges(buffer, count, offset) {
|
||||
const edges = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
const from = readUint32(buffer, offset);
|
||||
offset += 4;
|
||||
const to = readUint32(buffer, offset);
|
||||
offset += 4;
|
||||
edges.push({ from, to });
|
||||
}
|
||||
return { edges, offset };
|
||||
}
|
||||
return { edges, offset };
|
||||
}
|
||||
|
||||
// Initialize Vis.js network
|
||||
const nodes = new vis.DataSet();
|
||||
const edges = new vis.DataSet();
|
||||
// Initialize Vis.js network
|
||||
const nodes = new vis.DataSet();
|
||||
const edges = new vis.DataSet();
|
||||
|
||||
const container = document.getElementById("network");
|
||||
const data = { nodes, edges };
|
||||
const options = {};
|
||||
const network = new vis.Network(container, data, options);
|
||||
const container = document.getElementById("network");
|
||||
const data = { nodes, edges };
|
||||
const options = {};
|
||||
const network = new vis.Network(container, data, options);
|
||||
|
||||
// Helper function to add or update nodes in the graph
|
||||
function updateNode(id, file, group) {
|
||||
const label = basename(file.name);
|
||||
const color = file.name.includes('/node_modules/')
|
||||
? c.gray
|
||||
: file.isStale
|
||||
? c.red
|
||||
: file.isBoundary
|
||||
? c.orange
|
||||
: group === 'client'
|
||||
? c.mauve
|
||||
: file.isRoute
|
||||
? c.blue
|
||||
: file.isSSR ? file.isServer ? c.yellow : c.green : c.sky;
|
||||
const props = {
|
||||
id,
|
||||
label,
|
||||
shape: 'dot',
|
||||
color: color,
|
||||
borderWidth: file.isRoute ? 3 : 1,
|
||||
group,
|
||||
font: file.name.includes('/node_modules/')
|
||||
? '10px sans-serif #cdd6f488' : '20px sans-serif #cdd6f4',
|
||||
}
|
||||
if (nodes.get(id)) {
|
||||
nodes.update(props);
|
||||
} else {
|
||||
nodes.add(props);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to remove a node by ID
|
||||
function removeNode(id) {
|
||||
nodes.remove({ id });
|
||||
}
|
||||
|
||||
// Helper function to add or update edges in the graph
|
||||
const edgeProps = { arrows: 'to' };
|
||||
function updateEdge(id, from, to, variant) {
|
||||
const prop = variant === 'normal'
|
||||
? { id, from, to, arrows: 'to' }
|
||||
: variant === 'client'
|
||||
? { id, from, to, arrows: 'to,from', color: '#ffffff99', width: 2, label: '[use client]' }
|
||||
: { id, from, to };
|
||||
if (edges.get(id)) {
|
||||
edges.update(prop);
|
||||
} else {
|
||||
edges.add(prop);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to remove all edges of a node
|
||||
function removeEdges(nodeId) {
|
||||
const edgesToRemove = edges.get({
|
||||
filter: (edge) => edge.from === nodeId || edge.to === nodeId,
|
||||
});
|
||||
edges.remove(edgesToRemove.map(e => e.id));
|
||||
}
|
||||
|
||||
// Function to update the entire graph when new data is received
|
||||
function updateGraph() {
|
||||
const newEdgeIds = new Set(); // Track new edges
|
||||
|
||||
const boundaries = new Map();
|
||||
|
||||
// Update server files
|
||||
serverFiles.forEach((file, index) => {
|
||||
const id = `S_${index}`;
|
||||
if (file.deleted) {
|
||||
removeNode(id);
|
||||
removeEdges(id);
|
||||
// Helper function to add or update nodes in the graph
|
||||
function updateNode(id, file, group) {
|
||||
const label = basename(file.name);
|
||||
const color = file.name.includes("/node_modules/")
|
||||
? c.gray
|
||||
: file.isStale
|
||||
? c.red
|
||||
: file.isBoundary
|
||||
? c.orange
|
||||
: group === "client"
|
||||
? c.mauve
|
||||
: file.isRoute
|
||||
? c.blue
|
||||
: file.isSSR
|
||||
? file.isServer
|
||||
? c.yellow
|
||||
: c.green
|
||||
: c.sky;
|
||||
const props = {
|
||||
id,
|
||||
label,
|
||||
shape: "dot",
|
||||
color: color,
|
||||
borderWidth: file.isRoute ? 3 : 1,
|
||||
group,
|
||||
font: file.name.includes("/node_modules/") ? "10px sans-serif #cdd6f488" : "20px sans-serif #cdd6f4",
|
||||
};
|
||||
if (nodes.get(id)) {
|
||||
nodes.update(props);
|
||||
} else {
|
||||
updateNode(id, file, 'server');
|
||||
nodes.add(props);
|
||||
}
|
||||
|
||||
if (file.isBoundary) {
|
||||
boundaries.set(file.name, { server: index, client: -1 });
|
||||
}
|
||||
});
|
||||
|
||||
// Update client files
|
||||
clientFiles.forEach((file, index) => {
|
||||
const id = `C_${index}`;
|
||||
if (file.deleted) {
|
||||
removeNode(id);
|
||||
removeEdges(id);
|
||||
return;
|
||||
}
|
||||
updateNode(id, file, 'client');
|
||||
const b = boundaries.get(file.name);
|
||||
if (b) {
|
||||
b.client = index;
|
||||
}
|
||||
});
|
||||
|
||||
// Update client edges
|
||||
clientEdges.forEach((edge, index) => {
|
||||
const id = `C_edge_${index}`;
|
||||
updateEdge(id, `C_${edge.from}`, `C_${edge.to}`, 'normal');
|
||||
newEdgeIds.add(id); // Track this edge
|
||||
});
|
||||
|
||||
// Update server edges
|
||||
serverEdges.forEach((edge, index) => {
|
||||
const id = `S_edge_${index}`;
|
||||
updateEdge(id, `S_${edge.from}`, `S_${edge.to}`, 'normal');
|
||||
newEdgeIds.add(id); // Track this edge
|
||||
});
|
||||
|
||||
boundaries.forEach(({ server, client }) => {
|
||||
if (client === -1) return;
|
||||
const id = `S_edge_bound_${server}_${client}`;
|
||||
updateEdge(id, `S_${server}`, `C_${client}`, 'client');
|
||||
newEdgeIds.add(id); // Track this edge
|
||||
});
|
||||
|
||||
// Remove edges that are no longer present
|
||||
currentEdgeIds.forEach((id) => {
|
||||
if (!newEdgeIds.has(id)) {
|
||||
edges.remove(id);
|
||||
}
|
||||
});
|
||||
|
||||
// Update the currentEdgeIds set to the new one
|
||||
currentEdgeIds = newEdgeIds;
|
||||
|
||||
if (isFirst) {
|
||||
network.stabilize();
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
document.getElementById('stat').innerText = `(server: ${serverFiles.length} files, ${serverEdges.length} edges; client: ${clientFiles.length} files, ${clientEdges.length} edges; ${boundaries.size} boundaries)`;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
// Helper function to remove a node by ID
|
||||
function removeNode(id) {
|
||||
nodes.remove({ id });
|
||||
}
|
||||
|
||||
</html>
|
||||
// Helper function to add or update edges in the graph
|
||||
const edgeProps = { arrows: "to" };
|
||||
function updateEdge(id, from, to, variant) {
|
||||
const prop =
|
||||
variant === "normal"
|
||||
? { id, from, to, arrows: "to" }
|
||||
: variant === "client"
|
||||
? { id, from, to, arrows: "to,from", color: "#ffffff99", width: 2, label: "[use client]" }
|
||||
: { id, from, to };
|
||||
if (edges.get(id)) {
|
||||
edges.update(prop);
|
||||
} else {
|
||||
edges.add(prop);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to remove all edges of a node
|
||||
function removeEdges(nodeId) {
|
||||
const edgesToRemove = edges.get({
|
||||
filter: edge => edge.from === nodeId || edge.to === nodeId,
|
||||
});
|
||||
edges.remove(edgesToRemove.map(e => e.id));
|
||||
}
|
||||
|
||||
// Function to update the entire graph when new data is received
|
||||
function updateGraph() {
|
||||
const newEdgeIds = new Set(); // Track new edges
|
||||
const newNodeIds = new Set(); // Track new nodes
|
||||
|
||||
const boundaries = new Map();
|
||||
|
||||
// Update server files
|
||||
serverFiles.forEach((file, index) => {
|
||||
const id = `S_${file.name}`;
|
||||
if (file.deleted) {
|
||||
removeNode(id);
|
||||
removeEdges(id);
|
||||
} else {
|
||||
updateNode(id, file, "server");
|
||||
}
|
||||
|
||||
if (file.isBoundary) {
|
||||
boundaries.set(file.name, { server: index, client: -1 });
|
||||
}
|
||||
newNodeIds.add(id); // Track this node
|
||||
});
|
||||
|
||||
// Update client files
|
||||
clientFiles.forEach((file, index) => {
|
||||
const id = `C_${file.name}`;
|
||||
if (file.deleted) {
|
||||
removeNode(id);
|
||||
removeEdges(id);
|
||||
return;
|
||||
}
|
||||
updateNode(id, file, "client");
|
||||
const b = boundaries.get(file.name);
|
||||
if (b) {
|
||||
b.client = index;
|
||||
}
|
||||
newNodeIds.add(id); // Track this node
|
||||
});
|
||||
|
||||
// Update client edges
|
||||
clientEdges.forEach((edge, index) => {
|
||||
const id = `C_edge_${index}`;
|
||||
updateEdge(id, `C_${clientFiles[edge.from].name}`, `C_${clientFiles[edge.to].name}`, "normal");
|
||||
newEdgeIds.add(id); // Track this edge
|
||||
});
|
||||
|
||||
// Update server edges
|
||||
serverEdges.forEach((edge, index) => {
|
||||
const id = `S_edge_${index}`;
|
||||
updateEdge(id, `S_${serverFiles[edge.from].name}`, `S_${serverFiles[edge.to].name}`, "normal");
|
||||
newEdgeIds.add(id); // Track this edge
|
||||
});
|
||||
|
||||
boundaries.forEach(({ server, client }) => {
|
||||
if (client === -1) return;
|
||||
const id = `S_edge_bound_${server}_${client}`;
|
||||
updateEdge(id, `S_${serverFiles[server].name}`, `C_${clientFiles[client].name}`, "client");
|
||||
newEdgeIds.add(id); // Track this edge
|
||||
});
|
||||
|
||||
// Remove edges that are no longer present
|
||||
currentEdgeIds.forEach(id => {
|
||||
if (!newEdgeIds.has(id)) {
|
||||
edges.remove(id);
|
||||
}
|
||||
});
|
||||
|
||||
// Remove nodes that are no longer present
|
||||
currentNodeIds.forEach(id => {
|
||||
if (!newNodeIds.has(id)) {
|
||||
nodes.remove(id);
|
||||
}
|
||||
});
|
||||
|
||||
// Update the currentEdgeIds set to the new one
|
||||
currentEdgeIds = newEdgeIds;
|
||||
currentNodeIds = newNodeIds;
|
||||
|
||||
if (isFirst) {
|
||||
network.stabilize();
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
document.getElementById("stat").innerText =
|
||||
`(server: ${serverFiles.length} files, ${serverEdges.length} edges; client: ${clientFiles.length} files, ${clientEdges.length} edges; ${boundaries.size} boundaries)`;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
export function css(file: string, is_development: boolean): string {
|
||||
const contents = readFileSync(resolve(import.meta.dir, file), "utf-8");
|
||||
if (!is_development) {
|
||||
// TODO: minify
|
||||
return contents;
|
||||
}
|
||||
return contents;
|
||||
}
|
||||
// @ts-ignore
|
||||
export async function css(file: string, is_development: boolean): string {
|
||||
// TODO: CI does not have `experimentalCss`
|
||||
// const { success, stdout, stderr } = await Bun.spawnSync({
|
||||
// cmd: [process.execPath, "build", file, "--experimental-css", ...(is_development ? [] : ["--minify"])],
|
||||
// cwd: import.meta.dir,
|
||||
// stdio: ["ignore", "pipe", "pipe"],
|
||||
// });
|
||||
// if (!success) throw new Error(stderr.toString("utf-8"));
|
||||
// return stdout.toString("utf-8");
|
||||
|
||||
export function int(char: string): number {
|
||||
if (char.length !== 1) throw new Error("Must be one char long");
|
||||
return char.charCodeAt(0);
|
||||
return readFileSync(resolve(import.meta.dir, file)).toString('utf-8');
|
||||
}
|
||||
|
||||
1
src/bake/shared.ts
Normal file
1
src/bake/shared.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const td = /* #__PURE__ */ new TextDecoder();
|
||||
@@ -1 +0,0 @@
|
||||
export const td = new TextDecoder();
|
||||
@@ -12,7 +12,7 @@
|
||||
"downlevelIteration": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"jsx": "react-jsx",
|
||||
"jsx": "react",
|
||||
"paths": {
|
||||
"bun-framework-rsc/*": ["./bun-framework-rsc/*"]
|
||||
}
|
||||
|
||||
@@ -39,6 +39,14 @@ pub fn Bitflags(comptime T: type) type {
|
||||
this.* = bitwiseOr(this.*, other);
|
||||
}
|
||||
|
||||
pub inline fn remove(this: *T, other: T) void {
|
||||
this.* = bitwiseAnd(this.*, ~other);
|
||||
}
|
||||
|
||||
pub inline fn maskOut(this: T, other: T) T {
|
||||
return @bitCast(asBits(this) & ~asBits(other));
|
||||
}
|
||||
|
||||
pub fn contains(lhs: T, rhs: T) bool {
|
||||
return @as(IntType, @bitCast(lhs)) & @as(IntType, @bitCast(rhs)) != 0;
|
||||
}
|
||||
@@ -55,8 +63,16 @@ pub fn Bitflags(comptime T: type) type {
|
||||
return asBits(lhs) == asBits(rhs);
|
||||
}
|
||||
|
||||
pub fn eql(lhs: T, rhs: T) bool {
|
||||
return eq(lhs, rhs);
|
||||
}
|
||||
|
||||
pub fn neq(lhs: T, rhs: T) bool {
|
||||
return asBits(lhs) != asBits(rhs);
|
||||
}
|
||||
|
||||
pub fn hash(this: *const T, hasher: *std.hash.Wyhash) void {
|
||||
hasher.update(std.mem.asBytes(this));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,8 @@ const lshpack_header = extern struct {
|
||||
name_len: usize = 0,
|
||||
value: [*]const u8 = undefined,
|
||||
value_len: usize = 0,
|
||||
never_index: bool = false,
|
||||
hpack_index: u16 = 255,
|
||||
};
|
||||
|
||||
/// wrapper implemented at src/bun.js/bindings/c-bindings.cpp
|
||||
@@ -16,6 +18,8 @@ pub const HPACK = extern struct {
|
||||
pub const DecodeResult = struct {
|
||||
name: []const u8,
|
||||
value: []const u8,
|
||||
never_index: bool,
|
||||
well_know: u16,
|
||||
// offset of the next header position in src
|
||||
next: usize,
|
||||
};
|
||||
@@ -37,6 +41,8 @@ pub const HPACK = extern struct {
|
||||
.name = header.name[0..header.name_len],
|
||||
.value = header.value[0..header.value_len],
|
||||
.next = offset,
|
||||
.never_index = header.never_index,
|
||||
.well_know = header.hpack_index,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ const BoringSSL = bun.BoringSSL;
|
||||
const X509 = @import("./x509.zig");
|
||||
const Async = bun.Async;
|
||||
const uv = bun.windows.libuv;
|
||||
const H2FrameParser = @import("./h2_frame_parser.zig").H2FrameParser;
|
||||
noinline fn getSSLException(globalThis: *JSC.JSGlobalObject, defaultMessage: []const u8) JSValue {
|
||||
var zig_str: ZigString = ZigString.init("");
|
||||
var output_buf: [4096]u8 = undefined;
|
||||
@@ -1309,7 +1310,6 @@ fn selectALPNCallback(
|
||||
return BoringSSL.SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
}
|
||||
|
||||
fn NewSocket(comptime ssl: bool) type {
|
||||
return struct {
|
||||
pub const Socket = uws.NewSocketHandler(ssl);
|
||||
@@ -1328,13 +1328,42 @@ fn NewSocket(comptime ssl: bool) type {
|
||||
connection: ?Listener.UnixOrHost = null,
|
||||
protos: ?[]const u8,
|
||||
server_name: ?[]const u8 = null,
|
||||
bytesWritten: u64 = 0,
|
||||
|
||||
// TODO: switch to something that uses `visitAggregate` and have the
|
||||
// `Listener` keep a list of all the sockets JSValue in there
|
||||
// This is wasteful because it means we are keeping a JSC::Weak for every single open socket
|
||||
has_pending_activity: std.atomic.Value(bool) = std.atomic.Value(bool).init(true),
|
||||
native_callback: NativeCallbacks = .none,
|
||||
pub usingnamespace bun.NewRefCounted(@This(), @This().deinit);
|
||||
|
||||
pub const DEBUG_REFCOUNT_NAME = "Socket";
|
||||
|
||||
// We use this direct callbacks on HTTP2 when available
|
||||
pub const NativeCallbacks = union(enum) {
|
||||
h2: *H2FrameParser,
|
||||
none,
|
||||
|
||||
pub fn onData(this: NativeCallbacks, data: []const u8) bool {
|
||||
switch (this) {
|
||||
.h2 => |h2| {
|
||||
h2.onNativeRead(data);
|
||||
return true;
|
||||
},
|
||||
.none => return false,
|
||||
}
|
||||
}
|
||||
pub fn onWritable(this: NativeCallbacks) bool {
|
||||
switch (this) {
|
||||
.h2 => |h2| {
|
||||
h2.onNativeWritable();
|
||||
return true;
|
||||
},
|
||||
.none => return false,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const This = @This();
|
||||
const log = Output.scoped(.Socket, false);
|
||||
const WriteResult = union(enum) {
|
||||
@@ -1362,6 +1391,29 @@ fn NewSocket(comptime ssl: bool) type {
|
||||
return this.has_pending_activity.load(.acquire);
|
||||
}
|
||||
|
||||
pub fn attachNativeCallback(this: *This, callback: NativeCallbacks) bool {
|
||||
if (this.native_callback != .none) return false;
|
||||
this.native_callback = callback;
|
||||
|
||||
switch (callback) {
|
||||
.h2 => |h2| h2.ref(),
|
||||
.none => {},
|
||||
}
|
||||
return true;
|
||||
}
|
||||
pub fn detachNativeCallback(this: *This) void {
|
||||
const native_callback = this.native_callback;
|
||||
this.native_callback = .none;
|
||||
|
||||
switch (native_callback) {
|
||||
.h2 => |h2| {
|
||||
h2.onNativeClose();
|
||||
h2.deref();
|
||||
},
|
||||
.none => {},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn doConnect(this: *This, connection: Listener.UnixOrHost) !void {
|
||||
bun.assert(this.socket_context != null);
|
||||
this.ref();
|
||||
@@ -1418,6 +1470,7 @@ fn NewSocket(comptime ssl: bool) type {
|
||||
JSC.markBinding(@src());
|
||||
log("onWritable", .{});
|
||||
if (this.socket.isDetached()) return;
|
||||
if (this.native_callback.onWritable()) return;
|
||||
const handlers = this.handlers;
|
||||
const callback = handlers.onWritable;
|
||||
if (callback == .zero) return;
|
||||
@@ -1549,6 +1602,8 @@ fn NewSocket(comptime ssl: bool) type {
|
||||
pub fn closeAndDetach(this: *This, code: uws.CloseCode) void {
|
||||
const socket = this.socket;
|
||||
this.socket.detach();
|
||||
this.detachNativeCallback();
|
||||
|
||||
socket.close(code);
|
||||
}
|
||||
|
||||
@@ -1780,6 +1835,7 @@ fn NewSocket(comptime ssl: bool) type {
|
||||
pub fn onClose(this: *This, _: Socket, err: c_int, _: ?*anyopaque) void {
|
||||
JSC.markBinding(@src());
|
||||
log("onClose", .{});
|
||||
this.detachNativeCallback();
|
||||
this.socket.detach();
|
||||
defer this.deref();
|
||||
defer this.markInactive();
|
||||
@@ -1821,6 +1877,8 @@ fn NewSocket(comptime ssl: bool) type {
|
||||
log("onData({d})", .{data.len});
|
||||
if (this.socket.isDetached()) return;
|
||||
|
||||
if (this.native_callback.onData(data)) return;
|
||||
|
||||
const handlers = this.handlers;
|
||||
const callback = handlers.onData;
|
||||
if (callback == .zero or this.flags.finalizing) return;
|
||||
@@ -2015,7 +2073,7 @@ fn NewSocket(comptime ssl: bool) type {
|
||||
return ZigString.init(text).toJS(globalThis);
|
||||
}
|
||||
|
||||
fn writeMaybeCorked(this: *This, buffer: []const u8, is_end: bool) i32 {
|
||||
pub fn writeMaybeCorked(this: *This, buffer: []const u8, is_end: bool) i32 {
|
||||
if (this.socket.isShutdown() or this.socket.isClosed()) {
|
||||
return -1;
|
||||
}
|
||||
@@ -2025,12 +2083,18 @@ fn NewSocket(comptime ssl: bool) type {
|
||||
// TLS wrapped but in TCP mode
|
||||
if (this.wrapped == .tcp) {
|
||||
const res = this.socket.rawWrite(buffer, is_end);
|
||||
if (res > 0) {
|
||||
this.bytesWritten += @intCast(res);
|
||||
}
|
||||
log("write({d}, {any}) = {d}", .{ buffer.len, is_end, res });
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const res = this.socket.write(buffer, is_end);
|
||||
if (res > 0) {
|
||||
this.bytesWritten += @intCast(res);
|
||||
}
|
||||
log("write({d}, {any}) = {d}", .{ buffer.len, is_end, res });
|
||||
return res;
|
||||
}
|
||||
@@ -2261,6 +2325,7 @@ fn NewSocket(comptime ssl: bool) type {
|
||||
|
||||
pub fn deinit(this: *This) void {
|
||||
this.markInactive();
|
||||
this.detachNativeCallback();
|
||||
|
||||
this.poll_ref.unref(JSC.VirtualMachine.get());
|
||||
// need to deinit event without being attached
|
||||
@@ -2499,7 +2564,12 @@ fn NewSocket(comptime ssl: bool) type {
|
||||
bun.assert(result_size == size);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
pub fn getBytesWritten(
|
||||
this: *This,
|
||||
_: *JSC.JSGlobalObject,
|
||||
) JSValue {
|
||||
return JSC.JSValue.jsNumber(this.bytesWritten);
|
||||
}
|
||||
pub fn getALPNProtocol(
|
||||
this: *This,
|
||||
globalObject: *JSC.JSGlobalObject,
|
||||
@@ -3322,6 +3392,7 @@ fn NewSocket(comptime ssl: bool) type {
|
||||
defer this.deref();
|
||||
|
||||
// detach and invalidate the old instance
|
||||
this.detachNativeCallback();
|
||||
this.socket.detach();
|
||||
|
||||
// start TLS handshake after we set extension on the socket
|
||||
|
||||
@@ -9,6 +9,10 @@ export default [
|
||||
fn: "request",
|
||||
length: 2,
|
||||
},
|
||||
setNativeSocket: {
|
||||
fn: "setNativeSocketFromJS",
|
||||
length: 1,
|
||||
},
|
||||
ping: {
|
||||
fn: "ping",
|
||||
length: 0,
|
||||
@@ -29,6 +33,14 @@ export default [
|
||||
fn: "read",
|
||||
length: 1,
|
||||
},
|
||||
flush: {
|
||||
fn: "flushFromJS",
|
||||
length: 0,
|
||||
},
|
||||
detach: {
|
||||
fn: "detachFromJS",
|
||||
length: 0,
|
||||
},
|
||||
rstStream: {
|
||||
fn: "rstStream",
|
||||
length: 1,
|
||||
@@ -41,12 +53,20 @@ export default [
|
||||
fn: "sendTrailers",
|
||||
length: 2,
|
||||
},
|
||||
noTrailers: {
|
||||
fn: "noTrailers",
|
||||
length: 1,
|
||||
},
|
||||
setStreamPriority: {
|
||||
fn: "setStreamPriority",
|
||||
length: 2,
|
||||
},
|
||||
setEndAfterHeaders: {
|
||||
fn: "setEndAfterHeaders",
|
||||
getStreamContext: {
|
||||
fn: "getStreamContext",
|
||||
length: 1,
|
||||
},
|
||||
setStreamContext: {
|
||||
fn: "setStreamContext",
|
||||
length: 2,
|
||||
},
|
||||
getEndAfterHeaders: {
|
||||
@@ -61,6 +81,30 @@ export default [
|
||||
fn: "getStreamState",
|
||||
length: 1,
|
||||
},
|
||||
bufferSize: {
|
||||
fn: "getBufferSize",
|
||||
length: 0,
|
||||
},
|
||||
hasNativeRead: {
|
||||
fn: "hasNativeRead",
|
||||
length: 1,
|
||||
},
|
||||
getAllStreams: {
|
||||
fn: "getAllStreams",
|
||||
length: 0,
|
||||
},
|
||||
emitErrorToAllStreams: {
|
||||
fn: "emitErrorToAllStreams",
|
||||
length: 1,
|
||||
},
|
||||
emitAbortToAllStreams: {
|
||||
fn: "emitAbortToAllStreams",
|
||||
length: 0,
|
||||
},
|
||||
getNextStream: {
|
||||
fn: "getNextStream",
|
||||
length: 0,
|
||||
},
|
||||
},
|
||||
finalize: true,
|
||||
construct: true,
|
||||
|
||||
@@ -83,6 +83,9 @@ function generate(ssl) {
|
||||
alpnProtocol: {
|
||||
getter: "getALPNProtocol",
|
||||
},
|
||||
bytesWritten: {
|
||||
getter: "getBytesWritten",
|
||||
},
|
||||
write: {
|
||||
fn: "write",
|
||||
length: 3,
|
||||
|
||||
@@ -17,4 +17,4 @@ enum class BufferEncodingType {
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,4 +199,4 @@ namespace WebCore {
|
||||
using JSVMClientData = WebCore::JSVMClientData;
|
||||
using JSHeapData = WebCore::JSHeapData;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
37
src/bun.js/bindings/BunHttp2CommonStrings.cpp
Normal file
37
src/bun.js/bindings/BunHttp2CommonStrings.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "root.h"
|
||||
#include "BunHttp2CommonStrings.h"
|
||||
#include <JavaScriptCore/JSString.h>
|
||||
#include <JavaScriptCore/JSGlobalObject.h>
|
||||
#include <JavaScriptCore/LazyProperty.h>
|
||||
#include <JavaScriptCore/LazyPropertyInlines.h>
|
||||
#include "ZigGlobalObject.h"
|
||||
#include <JavaScriptCore/SlotVisitorInlines.h>
|
||||
#include <JavaScriptCore/VMTrapsInlines.h>
|
||||
|
||||
namespace Bun {
|
||||
using namespace JSC;
|
||||
|
||||
#define HTTP2_COMMON_STRINGS_LAZY_PROPERTY_DEFINITION(jsName, key, value, idx) \
|
||||
this->m_names[idx].initLater( \
|
||||
[](const JSC::LazyProperty<JSGlobalObject, JSString>::Initializer& init) { \
|
||||
init.set(jsOwnedString(init.vm, key)); \
|
||||
});
|
||||
|
||||
#define HTTP2_COMMON_STRINGS_LAZY_PROPERTY_VISITOR(name, key, value, idx) \
|
||||
this->m_names[idx].visit(visitor);
|
||||
|
||||
void Http2CommonStrings::initialize()
|
||||
{
|
||||
HTTP2_COMMON_STRINGS_EACH_NAME(HTTP2_COMMON_STRINGS_LAZY_PROPERTY_DEFINITION)
|
||||
}
|
||||
|
||||
template<typename Visitor>
|
||||
void Http2CommonStrings::visit(Visitor& visitor)
|
||||
{
|
||||
HTTP2_COMMON_STRINGS_EACH_NAME(HTTP2_COMMON_STRINGS_LAZY_PROPERTY_VISITOR)
|
||||
}
|
||||
|
||||
template void Http2CommonStrings::visit(JSC::AbstractSlotVisitor&);
|
||||
template void Http2CommonStrings::visit(JSC::SlotVisitor&);
|
||||
|
||||
} // namespace Bun
|
||||
107
src/bun.js/bindings/BunHttp2CommonStrings.h
Normal file
107
src/bun.js/bindings/BunHttp2CommonStrings.h
Normal file
@@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
// clang-format off
|
||||
|
||||
#define HTTP2_COMMON_STRINGS_EACH_NAME(macro) \
|
||||
macro(authority, ":authority"_s, ""_s, 0) \
|
||||
macro(methodGet, ":method"_s, "GET"_s, 1) \
|
||||
macro(methodPost, ":method"_s, "POST"_s, 2) \
|
||||
macro(pathRoot, ":path"_s, "/"_s, 3) \
|
||||
macro(pathIndex, ":path"_s, "/index.html"_s, 4) \
|
||||
macro(schemeHttp, ":scheme"_s, "http"_s, 5) \
|
||||
macro(schemeHttps, ":scheme"_s, "https"_s, 6) \
|
||||
macro(status200, ":status"_s, "200"_s, 7) \
|
||||
macro(status204, ":status"_s, "204"_s, 8) \
|
||||
macro(status206, ":status"_s, "206"_s, 9) \
|
||||
macro(status304, ":status"_s, "304"_s, 10) \
|
||||
macro(status400, ":status"_s, "400"_s, 11) \
|
||||
macro(status404, ":status"_s, "404"_s, 12) \
|
||||
macro(status500, ":status"_s, "500"_s, 13) \
|
||||
macro(acceptCharset, "accept-charset"_s, ""_s, 14) \
|
||||
macro(acceptEncoding, "accept-encoding"_s, "gzip, deflate"_s, 15) \
|
||||
macro(acceptLanguage, "accept-language"_s, ""_s, 16) \
|
||||
macro(acceptRanges, "accept-ranges"_s, ""_s, 17) \
|
||||
macro(accept, "accept"_s, ""_s, 18) \
|
||||
macro(accessControlAllowOrigin, "access-control-allow-origin"_s, ""_s, 19) \
|
||||
macro(age, "age"_s, ""_s, 20) \
|
||||
macro(allow, "allow"_s, ""_s, 21) \
|
||||
macro(authorization, "authorization"_s, ""_s, 22) \
|
||||
macro(cacheControl, "cache-control"_s, ""_s, 23) \
|
||||
macro(contentDisposition, "content-disposition"_s, ""_s, 24) \
|
||||
macro(contentEncoding, "content-encoding"_s, ""_s, 25) \
|
||||
macro(contentLanguage, "content-language"_s, ""_s, 26) \
|
||||
macro(contentLength, "content-length"_s, ""_s, 27) \
|
||||
macro(contentLocation, "content-location"_s, ""_s, 28) \
|
||||
macro(contentRange, "content-range"_s, ""_s, 29) \
|
||||
macro(contentType, "content-type"_s, ""_s, 30) \
|
||||
macro(cookie, "cookie"_s, ""_s, 31) \
|
||||
macro(date, "date"_s, ""_s, 32) \
|
||||
macro(etag, "etag"_s, ""_s, 33) \
|
||||
macro(expect, "expect"_s, ""_s, 34) \
|
||||
macro(expires, "expires"_s, ""_s, 35) \
|
||||
macro(from, "from"_s, ""_s, 36) \
|
||||
macro(host, "host"_s, ""_s, 37) \
|
||||
macro(ifMatch, "if-match"_s, ""_s, 38) \
|
||||
macro(ifModifiedSince, "if-modified-since"_s, ""_s, 39) \
|
||||
macro(ifNoneMatch, "if-none-match"_s, ""_s, 40) \
|
||||
macro(ifRange, "if-range"_s, ""_s, 41) \
|
||||
macro(ifUnmodifiedSince, "if-unmodified-since"_s, ""_s, 42) \
|
||||
macro(lastModified, "last-modified"_s, ""_s, 43) \
|
||||
macro(link, "link"_s, ""_s, 44) \
|
||||
macro(location, "location"_s, ""_s, 45) \
|
||||
macro(maxForwards, "max-forwards"_s, ""_s, 46) \
|
||||
macro(proxyAuthenticate, "proxy-authenticate"_s, ""_s, 47) \
|
||||
macro(proxyAuthorization, "proxy-authorization"_s, ""_s, 48) \
|
||||
macro(range, "range"_s, ""_s, 49) \
|
||||
macro(referer, "referer"_s, ""_s, 50) \
|
||||
macro(refresh, "refresh"_s, ""_s, 51) \
|
||||
macro(retryAfter, "retry-after"_s, ""_s, 52) \
|
||||
macro(server, "server"_s, ""_s, 53) \
|
||||
macro(setCookie, "set-cookie"_s, ""_s, 54) \
|
||||
macro(strictTransportSecurity, "strict-transport-security"_s, ""_s, 55) \
|
||||
macro(transferEncoding, "transfer-encoding"_s, ""_s, 56) \
|
||||
macro(userAgent, "user-agent"_s, ""_s, 57) \
|
||||
macro(vary, "vary"_s, ""_s, 58) \
|
||||
macro(via, "via"_s, ""_s, 59) \
|
||||
macro(wwwAuthenticate, "www-authenticate"_s, ""_s, 60)
|
||||
|
||||
// clang-format on
|
||||
|
||||
#define HTTP2_COMMON_STRINGS_ACCESSOR_DEFINITION(name, key, value, idx) \
|
||||
JSC::JSString* name##String(JSC::JSGlobalObject* globalObject) \
|
||||
{ \
|
||||
return m_names[idx].getInitializedOnMainThread(globalObject); \
|
||||
}
|
||||
|
||||
namespace Bun {
|
||||
|
||||
using namespace JSC;
|
||||
|
||||
class Http2CommonStrings {
|
||||
|
||||
public:
|
||||
typedef JSC::JSString* (*commonStringInitializer)(Http2CommonStrings*, JSC::JSGlobalObject* globalObject);
|
||||
|
||||
HTTP2_COMMON_STRINGS_EACH_NAME(HTTP2_COMMON_STRINGS_ACCESSOR_DEFINITION)
|
||||
|
||||
void initialize();
|
||||
|
||||
template<typename Visitor>
|
||||
void visit(Visitor& visitor);
|
||||
|
||||
JSC::JSString* getStringFromHPackIndex(uint16_t index, JSC::JSGlobalObject* globalObject)
|
||||
{
|
||||
if (index > 60) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_names[index].getInitializedOnMainThread(globalObject);
|
||||
}
|
||||
|
||||
private:
|
||||
JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSString> m_names[61];
|
||||
};
|
||||
|
||||
} // namespace Bun
|
||||
|
||||
#undef BUN_COMMON_STRINGS_ACCESSOR_DEFINITION
|
||||
#undef BUN_COMMON_STRINGS_LAZY_PROPERTY_DECLARATION
|
||||
@@ -12,4 +12,4 @@ public:
|
||||
bool isHTMLAllCollection(JSC::VM&, JSC::JSValue) override { return false; }
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "PathInlines.h"
|
||||
#include "wtf/text/ASCIILiteral.h"
|
||||
#include "BunObject+exports.h"
|
||||
#include "ErrorCode.h"
|
||||
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__lookup);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__resolve);
|
||||
@@ -120,8 +121,7 @@ static inline JSC::EncodedJSValue flattenArrayOfBuffersIntoArrayBufferOrUint8Arr
|
||||
|
||||
if (auto* typedArray = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(element)) {
|
||||
if (UNLIKELY(typedArray->isDetached())) {
|
||||
throwTypeError(lexicalGlobalObject, throwScope, "ArrayBufferView is detached"_s);
|
||||
return {};
|
||||
return Bun::ERR::INVALID_STATE(throwScope, lexicalGlobalObject, "Cannot validate on a detached buffer"_s);
|
||||
}
|
||||
size_t current = typedArray->byteLength();
|
||||
any_typed = true;
|
||||
@@ -133,8 +133,7 @@ static inline JSC::EncodedJSValue flattenArrayOfBuffersIntoArrayBufferOrUint8Arr
|
||||
} else if (auto* arrayBuffer = JSC::jsDynamicCast<JSC::JSArrayBuffer*>(element)) {
|
||||
auto* impl = arrayBuffer->impl();
|
||||
if (UNLIKELY(!impl)) {
|
||||
throwTypeError(lexicalGlobalObject, throwScope, "ArrayBuffer is detached"_s);
|
||||
return {};
|
||||
return Bun::ERR::INVALID_STATE(throwScope, lexicalGlobalObject, "Cannot validate on a detached buffer"_s);
|
||||
}
|
||||
|
||||
size_t current = impl->byteLength();
|
||||
|
||||
@@ -106,4 +106,4 @@ class GlobalObject;
|
||||
namespace Bun {
|
||||
JSC::JSValue runVirtualModule(Zig::GlobalObject*, BunString* specifier, bool& wasModuleMock);
|
||||
JSC::Structure* createModuleMockStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,4 +53,4 @@ public:
|
||||
private:
|
||||
MessagePortChannelProviderImpl* m_messagePortChannelProvider;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,4 +6,4 @@ namespace WebCore {
|
||||
|
||||
class CachedScript {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,42 +13,39 @@
|
||||
#include <JavaScriptCore/CodeBlock.h>
|
||||
#include <JavaScriptCore/Operations.h>
|
||||
#include <JavaScriptCore/JSCInlines.h>
|
||||
|
||||
#include <JavaScriptCore/ObjectConstructor.h>
|
||||
#include <JavaScriptCore/JSBoundFunction.h>
|
||||
using namespace JSC;
|
||||
|
||||
namespace Zig {
|
||||
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetThis);
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetTypeName);
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetFunction);
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetFunctionName);
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetMethodName);
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetFileName);
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetLineNumber);
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetColumnNumber);
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetEvalOrigin);
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetScriptNameOrSourceURL);
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsToplevel);
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsEval);
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsNative);
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsConstructor);
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsAsync);
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsPromiseAll);
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetPromiseIndex);
|
||||
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncToString);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetThis);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetTypeName);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetFunction);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetFunctionName);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetMethodName);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetFileName);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetLineNumber);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetColumnNumber);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetEvalOrigin);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetScriptNameOrSourceURL);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsToplevel);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsEval);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsNative);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsConstructor);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsAsync);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsPromiseAll);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetPromiseIndex);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncToString);
|
||||
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncToJSON);
|
||||
|
||||
ALWAYS_INLINE static CallSite* getCallSite(JSGlobalObject* globalObject, JSC::JSValue thisValue)
|
||||
{
|
||||
JSC::VM& vm = globalObject->vm();
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
if (UNLIKELY(!thisValue.isCell())) {
|
||||
JSC::throwVMError(globalObject, scope, createNotAnObjectError(globalObject, thisValue));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (LIKELY(thisValue.asCell()->inherits(CallSite::info()))) {
|
||||
return JSC::jsCast<CallSite*>(thisValue);
|
||||
if (auto* callSite = JSC::jsDynamicCast<CallSite*>(thisValue)) {
|
||||
return callSite;
|
||||
}
|
||||
|
||||
throwTypeError(globalObject, scope, "CallSite operation called on non-CallSite object"_s);
|
||||
@@ -84,6 +81,7 @@ static const HashTableValue CallSitePrototypeTableValues[]
|
||||
{ "isPromiseAll"_s, JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Function, NoIntrinsic, { HashTableValue::NativeFunctionType, callSiteProtoFuncIsPromiseAll, 0 } },
|
||||
{ "getPromiseIndex"_s, JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Function, NoIntrinsic, { HashTableValue::NativeFunctionType, callSiteProtoFuncGetPromiseIndex, 0 } },
|
||||
{ "toString"_s, JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Function, NoIntrinsic, { HashTableValue::NativeFunctionType, callSiteProtoFuncToString, 0 } },
|
||||
{ "toJSON"_s, JSC::PropertyAttribute::Function | 0, NoIntrinsic, { HashTableValue::NativeFunctionType, callSiteProtoFuncToJSON, 0 } },
|
||||
};
|
||||
|
||||
const JSC::ClassInfo CallSitePrototype::s_info = { "CallSite"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(CallSitePrototype) };
|
||||
@@ -165,10 +163,29 @@ JSC_DEFINE_HOST_FUNCTION(callSiteProtoFuncIsToplevel, (JSGlobalObject * globalOb
|
||||
{
|
||||
ENTER_PROTO_FUNC();
|
||||
|
||||
if (JSValue functionValue = callSite->function()) {
|
||||
if (JSObject* fn = functionValue.getObject()) {
|
||||
if (JSFunction* function = jsDynamicCast<JSFunction*>(fn)) {
|
||||
if (function->inherits<JSC::JSBoundFunction>()) {
|
||||
return JSC::JSValue::encode(JSC::jsBoolean(false));
|
||||
}
|
||||
|
||||
if (function->isHostFunction()) {
|
||||
return JSC::JSValue::encode(JSC::jsBoolean(true));
|
||||
}
|
||||
|
||||
if (auto* executable = function->jsExecutable()) {
|
||||
return JSValue::encode(jsBoolean(executable->isProgramExecutable() || executable->isModuleProgramExecutable()));
|
||||
}
|
||||
} else if (auto* function = jsDynamicCast<InternalFunction*>(functionValue)) {
|
||||
return JSC::JSValue::encode(JSC::jsBoolean(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSC::JSValue thisValue = callSite->thisValue();
|
||||
|
||||
// This is what v8 does (JSStackFrame::IsToplevel in messages.cc):
|
||||
|
||||
if (thisValue.isUndefinedOrNull()) {
|
||||
return JSC::JSValue::encode(JSC::jsBoolean(true));
|
||||
}
|
||||
@@ -237,4 +254,15 @@ JSC_DEFINE_HOST_FUNCTION(callSiteProtoFuncToString, (JSGlobalObject * globalObje
|
||||
return JSC::JSValue::encode(JSC::JSValue(jsString(vm, sb.toString())));
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(callSiteProtoFuncToJSON, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
|
||||
{
|
||||
ENTER_PROTO_FUNC();
|
||||
JSObject* obj = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 4);
|
||||
obj->putDirect(vm, JSC::Identifier::fromString(vm, "sourceURL"_s), callSite->sourceURL());
|
||||
obj->putDirect(vm, JSC::Identifier::fromString(vm, "lineNumber"_s), jsNumber(callSite->lineNumber().oneBasedInt()));
|
||||
obj->putDirect(vm, JSC::Identifier::fromString(vm, "columnNumber"_s), jsNumber(callSite->columnNumber().zeroBasedInt()));
|
||||
obj->putDirect(vm, JSC::Identifier::fromString(vm, "functionName"_s), callSite->functionName());
|
||||
return JSC::JSValue::encode(obj);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -44,4 +44,4 @@ private:
|
||||
void finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,4 +13,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,12 +60,6 @@ static JSC::JSObject* createErrorPrototype(JSC::VM& vm, JSC::JSGlobalObject* glo
|
||||
return prototype;
|
||||
}
|
||||
|
||||
extern "C" JSC::EncodedJSValue Bun__ERR_INVALID_ARG_TYPE(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue val_arg_name, JSC::EncodedJSValue val_expected_type, JSC::EncodedJSValue val_actual_value);
|
||||
extern "C" JSC::EncodedJSValue Bun__ERR_INVALID_ARG_TYPE_static(JSC::JSGlobalObject* globalObject, const ZigString* val_arg_name, const ZigString* val_expected_type, JSC::EncodedJSValue val_actual_value);
|
||||
extern "C" JSC::EncodedJSValue Bun__ERR_MISSING_ARGS(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue arg1, JSC::EncodedJSValue arg2, JSC::EncodedJSValue arg3);
|
||||
extern "C" JSC::EncodedJSValue Bun__ERR_MISSING_ARGS_static(JSC::JSGlobalObject* globalObject, const ZigString* arg1, const ZigString* arg2, const ZigString* arg3);
|
||||
extern "C" JSC::EncodedJSValue Bun__ERR_IPC_CHANNEL_CLOSED(JSC::JSGlobalObject* globalObject);
|
||||
|
||||
// clang-format on
|
||||
|
||||
#define EXPECT_ARG_COUNT(count__) \
|
||||
@@ -227,7 +221,6 @@ namespace Message {
|
||||
|
||||
WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, const StringView& arg_name, const StringView& expected_type, JSValue actual_value)
|
||||
{
|
||||
|
||||
auto actual_value_string = JSValueToStringSafe(globalObject, actual_value);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
@@ -279,7 +272,6 @@ WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* gl
|
||||
|
||||
WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue val_arg_name, JSValue val_expected_type, JSValue val_actual_value)
|
||||
{
|
||||
|
||||
auto arg_name = val_arg_name.toWTFString(globalObject);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
@@ -307,7 +299,7 @@ WTF::String ERR_OUT_OF_RANGE(JSC::ThrowScope& scope, JSC::JSGlobalObject* global
|
||||
|
||||
namespace ERR {
|
||||
|
||||
JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral val_arg_name, ASCIILiteral val_expected_type, JSC::JSValue val_actual_value)
|
||||
JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& val_arg_name, const WTF::String& val_expected_type, JSC::JSValue val_actual_value)
|
||||
{
|
||||
auto arg_name = val_arg_name.span8();
|
||||
ASSERT(WTF::charactersAreAllASCII(arg_name));
|
||||
@@ -327,7 +319,7 @@ JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalO
|
||||
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, message));
|
||||
return {};
|
||||
}
|
||||
JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue val_arg_name, ASCIILiteral val_expected_type, JSC::JSValue val_actual_value)
|
||||
JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue val_arg_name, const WTF::String& val_expected_type, JSC::JSValue val_actual_value)
|
||||
{
|
||||
auto arg_name = val_arg_name.toWTFString(globalObject);
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
@@ -348,7 +340,7 @@ JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalO
|
||||
return {};
|
||||
}
|
||||
|
||||
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral arg_name, size_t lower, size_t upper, JSC::JSValue actual)
|
||||
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name, size_t lower, size_t upper, JSC::JSValue actual)
|
||||
{
|
||||
auto lowerStr = jsNumber(lower).toWTFString(globalObject);
|
||||
auto upperStr = jsNumber(upper).toWTFString(globalObject);
|
||||
@@ -392,7 +384,7 @@ JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObjec
|
||||
}
|
||||
}
|
||||
}
|
||||
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, ASCIILiteral msg, JSC::JSValue actual)
|
||||
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, const WTF::String& msg, JSC::JSValue actual)
|
||||
{
|
||||
auto arg_name = arg_name_val.toWTFString(globalObject);
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
@@ -403,7 +395,7 @@ JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObjec
|
||||
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, message));
|
||||
return {};
|
||||
}
|
||||
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral arg_name, ASCIILiteral msg, JSC::JSValue actual)
|
||||
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name, const WTF::String& msg, JSC::JSValue actual)
|
||||
{
|
||||
auto actual_value = JSValueToStringSafe(globalObject, actual);
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
@@ -413,7 +405,7 @@ JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObjec
|
||||
return {};
|
||||
}
|
||||
|
||||
JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral name, JSC::JSValue value, WTF::String reason)
|
||||
JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& name, JSC::JSValue value, const WTF::String& reason)
|
||||
{
|
||||
ASCIILiteral type;
|
||||
{
|
||||
@@ -430,7 +422,7 @@ JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobal
|
||||
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_INVALID_ARG_VALUE, message));
|
||||
return {};
|
||||
}
|
||||
JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue name, JSC::JSValue value, WTF::String reason)
|
||||
JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue name, JSC::JSValue value, const WTF::String& reason)
|
||||
{
|
||||
auto name_string = JSValueToStringSafe(globalObject, name);
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
@@ -443,17 +435,14 @@ JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobal
|
||||
return {};
|
||||
}
|
||||
|
||||
JSC::EncodedJSValue UNKNOWN_ENCODING(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue encoding)
|
||||
JSC::EncodedJSValue UNKNOWN_ENCODING(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& encoding)
|
||||
{
|
||||
auto encoding_string = JSValueToStringSafe(globalObject, encoding);
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
|
||||
auto message = makeString("Unknown encoding: "_s, encoding_string);
|
||||
auto message = makeString("Unknown encoding: "_s, encoding);
|
||||
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_UNKNOWN_ENCODING, message));
|
||||
return {};
|
||||
}
|
||||
|
||||
JSC::EncodedJSValue INVALID_STATE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral statemsg)
|
||||
JSC::EncodedJSValue INVALID_STATE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& statemsg)
|
||||
{
|
||||
auto message = makeString("Invalid state: "_s, statemsg);
|
||||
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_INVALID_STATE, message));
|
||||
@@ -462,7 +451,7 @@ JSC::EncodedJSValue INVALID_STATE(JSC::ThrowScope& throwScope, JSC::JSGlobalObje
|
||||
|
||||
JSC::EncodedJSValue STRING_TOO_LONG(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject)
|
||||
{
|
||||
auto message = makeString("Cannot create a string longer than "_s, WTF::String::MaxLength, " characters"_s);
|
||||
auto message = makeString("Cannot create a string longer than "_s, WTF::String ::MaxLength, " characters"_s);
|
||||
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_STRING_TOO_LONG, message));
|
||||
return {};
|
||||
}
|
||||
@@ -520,25 +509,6 @@ static JSC::JSValue ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalOb
|
||||
return createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, msg);
|
||||
}
|
||||
|
||||
extern "C" JSC::EncodedJSValue Bun__ERR_INVALID_ARG_TYPE(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue val_arg_name, JSC::EncodedJSValue val_expected_type, JSC::EncodedJSValue val_actual_value)
|
||||
{
|
||||
JSC::VM& vm = globalObject->vm();
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
auto message = Message::ERR_INVALID_ARG_TYPE(scope, globalObject, JSValue::decode(val_arg_name), JSValue::decode(val_expected_type), JSValue::decode(val_actual_value));
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, message));
|
||||
}
|
||||
extern "C" JSC::EncodedJSValue Bun__ERR_INVALID_ARG_TYPE_static(JSC::JSGlobalObject* globalObject, const ZigString* val_arg_name, const ZigString* val_expected_type, JSC::EncodedJSValue val_actual_value)
|
||||
{
|
||||
JSC::VM& vm = globalObject->vm();
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
WTF::String message = Message::ERR_INVALID_ARG_TYPE(scope, globalObject, val_arg_name, val_expected_type, JSValue::decode(val_actual_value));
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, message));
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_OUT_OF_RANGE, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
|
||||
{
|
||||
JSC::VM& vm = globalObject->vm();
|
||||
@@ -566,82 +536,7 @@ extern "C" JSC::EncodedJSValue Bun__createErrorWithCode(JSC::JSGlobalObject* glo
|
||||
return JSValue::encode(createError(globalObject, code, message->toWTFString(BunString::ZeroCopy)));
|
||||
}
|
||||
|
||||
extern "C" JSC::EncodedJSValue Bun__ERR_MISSING_ARGS(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue arg1, JSC::EncodedJSValue arg2, JSC::EncodedJSValue arg3)
|
||||
{
|
||||
JSC::VM& vm = globalObject->vm();
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
if (arg1 == 0) {
|
||||
JSC::throwTypeError(globalObject, scope, "requires at least 1 argument"_s);
|
||||
return {};
|
||||
}
|
||||
|
||||
auto name1 = JSValue::decode(arg1).toWTFString(globalObject);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
if (arg2 == 0) {
|
||||
// 1 arg name passed
|
||||
auto message = makeString("The \""_s, name1, "\" argument must be specified"_s);
|
||||
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_MISSING_ARGS, message));
|
||||
}
|
||||
|
||||
auto name2 = JSValue::decode(arg2).toWTFString(globalObject);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
if (arg3 == 0) {
|
||||
// 2 arg names passed
|
||||
auto message = makeString("The \""_s, name1, "\" and \""_s, name2, "\" arguments must be specified"_s);
|
||||
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_MISSING_ARGS, message));
|
||||
}
|
||||
|
||||
auto name3 = JSValue::decode(arg3).toWTFString(globalObject);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
// 3 arg names passed
|
||||
auto message = makeString("The \""_s, name1, "\", \""_s, name2, "\", and \""_s, name3, "\" arguments must be specified"_s);
|
||||
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_MISSING_ARGS, message));
|
||||
}
|
||||
extern "C" JSC::EncodedJSValue Bun__ERR_MISSING_ARGS_static(JSC::JSGlobalObject* globalObject, const ZigString* arg1, const ZigString* arg2, const ZigString* arg3)
|
||||
{
|
||||
JSC::VM& vm = globalObject->vm();
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
if (arg1 == nullptr) {
|
||||
JSC::throwTypeError(globalObject, scope, "requires at least 1 argument"_s);
|
||||
return {};
|
||||
}
|
||||
|
||||
auto name1 = std::span<const unsigned char>(arg1->ptr, arg1->len);
|
||||
ASSERT(WTF::charactersAreAllASCII(name1));
|
||||
|
||||
if (arg2 == nullptr) {
|
||||
// 1 arg name passed
|
||||
auto message = makeString("The \""_s, name1, "\" argument must be specified"_s);
|
||||
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_MISSING_ARGS, message));
|
||||
}
|
||||
|
||||
auto name2 = std::span<const unsigned char>(arg2->ptr, arg2->len);
|
||||
ASSERT(WTF::charactersAreAllASCII(name2));
|
||||
|
||||
if (arg3 == nullptr) {
|
||||
// 2 arg names passed
|
||||
auto message = makeString("The \""_s, name1, "\" and \""_s, name2, "\" arguments must be specified"_s);
|
||||
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_MISSING_ARGS, message));
|
||||
}
|
||||
|
||||
auto name3 = std::span<const unsigned char>(arg3->ptr, arg3->len);
|
||||
ASSERT(WTF::charactersAreAllASCII(name3));
|
||||
|
||||
// 3 arg names passed
|
||||
auto message = makeString("The \""_s, name1, "\", \""_s, name2, "\", and \""_s, name3, "\" arguments must be specified"_s);
|
||||
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_MISSING_ARGS, message));
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_IPC_CHANNEL_CLOSED, (JSC::JSGlobalObject * globalObject, JSC::CallFrame*))
|
||||
{
|
||||
return Bun__ERR_IPC_CHANNEL_CLOSED(globalObject);
|
||||
}
|
||||
extern "C" JSC::EncodedJSValue Bun__ERR_IPC_CHANNEL_CLOSED(JSC::JSGlobalObject* globalObject)
|
||||
{
|
||||
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_IPC_CHANNEL_CLOSED, "Channel closed."_s));
|
||||
}
|
||||
|
||||
@@ -75,17 +75,17 @@ enum Bound {
|
||||
|
||||
namespace ERR {
|
||||
|
||||
JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral val_arg_name, ASCIILiteral val_expected_type, JSC::JSValue val_actual_value);
|
||||
JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue val_arg_name, ASCIILiteral val_expected_type, JSC::JSValue val_actual_value);
|
||||
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral arg_name, size_t lower, size_t upper, JSC::JSValue actual);
|
||||
JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& val_arg_name, const WTF::String& val_expected_type, JSC::JSValue val_actual_value);
|
||||
JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue val_arg_name, const WTF::String& val_expected_type, JSC::JSValue val_actual_value);
|
||||
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name, size_t lower, size_t upper, JSC::JSValue actual);
|
||||
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name, size_t lower, size_t upper, JSC::JSValue actual);
|
||||
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, size_t bound_num, Bound bound, JSC::JSValue actual);
|
||||
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, ASCIILiteral msg, JSC::JSValue actual);
|
||||
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral arg_name_val, ASCIILiteral msg, JSC::JSValue actual);
|
||||
JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral name, JSC::JSValue value, WTF::String reason = "is invalid"_s);
|
||||
JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue name, JSC::JSValue value, WTF::String reason = "is invalid"_s);
|
||||
JSC::EncodedJSValue UNKNOWN_ENCODING(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue encoding);
|
||||
JSC::EncodedJSValue INVALID_STATE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral statemsg);
|
||||
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, const WTF::String& msg, JSC::JSValue actual);
|
||||
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name_val, const WTF::String& msg, JSC::JSValue actual);
|
||||
JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& name, JSC::JSValue value, const WTF::String& reason = "is invalid"_s);
|
||||
JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue name, JSC::JSValue value, const WTF::String& reason = "is invalid"_s);
|
||||
JSC::EncodedJSValue UNKNOWN_ENCODING(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& encoding);
|
||||
JSC::EncodedJSValue INVALID_STATE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& statemsg);
|
||||
JSC::EncodedJSValue STRING_TOO_LONG(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject);
|
||||
JSC::EncodedJSValue BUFFER_OUT_OF_BOUNDS(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject);
|
||||
JSC::EncodedJSValue UNKNOWN_SIGNAL(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue signal, bool triedUppercase = false);
|
||||
|
||||
@@ -13,9 +13,6 @@ export default [
|
||||
["ABORT_ERR", Error, "AbortError"],
|
||||
["ERR_CRYPTO_INVALID_DIGEST", TypeError, "TypeError"],
|
||||
["ERR_ENCODING_INVALID_ENCODED_DATA", TypeError, "TypeError"],
|
||||
["ERR_HTTP2_INVALID_HEADER_VALUE", TypeError, "TypeError"],
|
||||
["ERR_HTTP2_INVALID_PSEUDOHEADER", TypeError, "TypeError"],
|
||||
["ERR_HTTP2_INVALID_SINGLE_VALUE_HEADER", TypeError, "TypeError"],
|
||||
["ERR_INVALID_ARG_TYPE", TypeError, "TypeError"],
|
||||
["ERR_INVALID_ARG_VALUE", TypeError, "TypeError"],
|
||||
["ERR_INVALID_PROTOCOL", TypeError, "TypeError"],
|
||||
@@ -54,4 +51,30 @@ export default [
|
||||
["ERR_BODY_ALREADY_USED", Error, "Error"],
|
||||
["ERR_STREAM_WRAP", Error, "Error"],
|
||||
["ERR_BORINGSSL", Error, "Error"],
|
||||
|
||||
//HTTP2
|
||||
["ERR_INVALID_HTTP_TOKEN", TypeError, "TypeError"],
|
||||
["ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED", TypeError, "TypeError"],
|
||||
["ERR_HTTP2_SEND_FILE", Error, "Error"],
|
||||
["ERR_HTTP2_SEND_FILE_NOSEEK", Error, "Error"],
|
||||
["ERR_HTTP2_HEADERS_SENT", Error, "ERR_HTTP2_HEADERS_SENT"],
|
||||
["ERR_HTTP2_INFO_STATUS_NOT_ALLOWED", RangeError, "RangeError"],
|
||||
["ERR_HTTP2_STATUS_INVALID", RangeError, "RangeError"],
|
||||
["ERR_HTTP2_INVALID_PSEUDOHEADER", TypeError, "TypeError"],
|
||||
["ERR_HTTP2_INVALID_HEADER_VALUE", TypeError, "TypeError"],
|
||||
["ERR_HTTP2_PING_CANCEL", Error, "Error"],
|
||||
["ERR_HTTP2_STREAM_ERROR", Error, "Error"],
|
||||
["ERR_HTTP2_INVALID_SINGLE_VALUE_HEADER", TypeError, "TypeError"],
|
||||
["ERR_HTTP2_SESSION_ERROR", Error, "Error"],
|
||||
["ERR_HTTP2_INVALID_SESSION", Error, "Error"],
|
||||
["ERR_HTTP2_INVALID_HEADERS", Error, "Error"],
|
||||
["ERR_HTTP2_PING_LENGTH", RangeError, "RangeError"],
|
||||
["ERR_HTTP2_INVALID_STREAM", Error, "Error"],
|
||||
["ERR_HTTP2_TRAILERS_ALREADY_SENT", Error, "Error"],
|
||||
["ERR_HTTP2_TRAILERS_NOT_READY", Error, "Error"],
|
||||
["ERR_HTTP2_PAYLOAD_FORBIDDEN", Error, "Error"],
|
||||
["ERR_HTTP2_NO_SOCKET_MANIPULATION", Error, "Error"],
|
||||
["ERR_HTTP2_SOCKET_UNBOUND", Error, "Error"],
|
||||
["ERR_HTTP2_ERROR", Error, "Error"],
|
||||
["ERR_HTTP2_OUT_OF_STREAMS", Error, "Error"],
|
||||
] as ErrorCodeMapping;
|
||||
|
||||
@@ -22,7 +22,15 @@ void adjustPositionBackwards(ZigStackFramePosition& pos, int amount, CodeBlock*
|
||||
|
||||
pos.column_zero_based = pos.column_zero_based - amount;
|
||||
if (pos.column_zero_based < 0) {
|
||||
auto source = code->source().provider()->source();
|
||||
auto* provider = code->source().provider();
|
||||
if (!provider) {
|
||||
pos.line_zero_based = 0;
|
||||
pos.column_zero_based = 0;
|
||||
pos.byte_position = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
auto source = provider->source();
|
||||
if (!source.is8Bit()) {
|
||||
// Debug-only assertion
|
||||
// Bun does not yet use 16-bit sources anywhere. The transpiler ensures everything
|
||||
@@ -75,6 +83,8 @@ ZigStackFramePosition getAdjustedPositionForBytecode(JSC::CodeBlock* code, JSC::
|
||||
switch (inst->opcodeID()) {
|
||||
case op_construct:
|
||||
case op_construct_varargs:
|
||||
case op_super_construct:
|
||||
case op_super_construct_varargs:
|
||||
// The divot by default is pointing at the `(` or the end of the class name.
|
||||
// We want to point at the `new` keyword, which is conveniently at the
|
||||
// expression start.
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include <JavaScriptCore/StackVisitor.h>
|
||||
#include <JavaScriptCore/NativeCallee.h>
|
||||
#include <wtf/IterationStatus.h>
|
||||
#include <JavaScriptCore/CodeBlock.h>
|
||||
#include <JavaScriptCore/FunctionCodeBlock.h>
|
||||
|
||||
#include "ErrorStackFrame.h"
|
||||
|
||||
@@ -24,6 +26,69 @@ using namespace WebCore;
|
||||
|
||||
namespace Zig {
|
||||
|
||||
static ImplementationVisibility getImplementationVisibility(JSC::CodeBlock* codeBlock)
|
||||
{
|
||||
|
||||
if (auto* executable = codeBlock->ownerExecutable()) {
|
||||
return executable->implementationVisibility();
|
||||
}
|
||||
|
||||
return ImplementationVisibility::Public;
|
||||
}
|
||||
|
||||
static bool isImplementationVisibilityPrivate(JSC::StackVisitor& visitor)
|
||||
{
|
||||
ImplementationVisibility implementationVisibility = [&]() -> ImplementationVisibility {
|
||||
if (visitor->callee().isCell()) {
|
||||
if (auto* callee = visitor->callee().asCell()) {
|
||||
if (auto* jsFunction = jsDynamicCast<JSFunction*>(callee)) {
|
||||
if (auto* executable = jsFunction->executable())
|
||||
return executable->implementationVisibility();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (auto* codeBlock = visitor->codeBlock()) {
|
||||
return getImplementationVisibility(codeBlock);
|
||||
}
|
||||
|
||||
#if ENABLE(WEBASSEMBLY)
|
||||
if (visitor->isNativeCalleeFrame())
|
||||
return visitor->callee().asNativeCallee()->implementationVisibility();
|
||||
#endif
|
||||
|
||||
return ImplementationVisibility::Public;
|
||||
}();
|
||||
|
||||
return implementationVisibility != ImplementationVisibility::Public;
|
||||
}
|
||||
|
||||
static bool isImplementationVisibilityPrivate(const JSC::StackFrame& frame)
|
||||
{
|
||||
ImplementationVisibility implementationVisibility = [&]() -> ImplementationVisibility {
|
||||
|
||||
#if ENABLE(WEBASSEMBLY)
|
||||
if (frame.isWasmFrame())
|
||||
return ImplementationVisibility::Public;
|
||||
#endif
|
||||
|
||||
if (auto* callee = frame.callee()) {
|
||||
if (auto* jsFunction = jsDynamicCast<JSFunction*>(callee)) {
|
||||
if (auto* executable = jsFunction->executable())
|
||||
return executable->implementationVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
if (auto* codeBlock = frame.codeBlock()) {
|
||||
return getImplementationVisibility(codeBlock);
|
||||
}
|
||||
|
||||
return ImplementationVisibility::Public;
|
||||
}();
|
||||
|
||||
return implementationVisibility != ImplementationVisibility::Public;
|
||||
}
|
||||
|
||||
JSCStackTrace JSCStackTrace::fromExisting(JSC::VM& vm, const WTF::Vector<JSC::StackFrame>& existingFrames)
|
||||
{
|
||||
WTF::Vector<JSCStackFrame> newFrames;
|
||||
@@ -35,41 +100,155 @@ JSCStackTrace JSCStackTrace::fromExisting(JSC::VM& vm, const WTF::Vector<JSC::St
|
||||
|
||||
newFrames.reserveInitialCapacity(frameCount);
|
||||
for (size_t i = 0; i < frameCount; i++) {
|
||||
newFrames.constructAndAppend(vm, existingFrames.at(i));
|
||||
if (!isImplementationVisibilityPrivate(existingFrames.at(i))) {
|
||||
newFrames.constructAndAppend(vm, existingFrames.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
return JSCStackTrace(newFrames);
|
||||
}
|
||||
|
||||
static bool isImplementationVisibilityPrivate(JSC::StackVisitor& visitor)
|
||||
void JSCStackTrace::getFramesForCaller(JSC::VM& vm, JSC::CallFrame* callFrame, JSC::JSCell* owner, JSC::JSValue caller, WTF::Vector<JSC::StackFrame>& stackTrace, size_t stackTraceLimit)
|
||||
{
|
||||
ImplementationVisibility implementationVisibility = [&]() -> ImplementationVisibility {
|
||||
if (auto* codeBlock = visitor->codeBlock()) {
|
||||
if (auto* executable = codeBlock->ownerExecutable()) {
|
||||
return executable->implementationVisibility();
|
||||
}
|
||||
return ImplementationVisibility::Public;
|
||||
size_t framesCount = 0;
|
||||
|
||||
bool belowCaller = false;
|
||||
int32_t skipFrames = 0;
|
||||
|
||||
WTF::String callerName {};
|
||||
if (JSC::JSFunction* callerFunction = JSC::jsDynamicCast<JSC::JSFunction*>(caller)) {
|
||||
callerName = callerFunction->name(vm);
|
||||
if (callerName.isEmpty() && callerFunction->jsExecutable()) {
|
||||
callerName = callerFunction->jsExecutable()->name().string();
|
||||
}
|
||||
}
|
||||
if (JSC::InternalFunction* callerFunctionInternal = JSC::jsDynamicCast<JSC::InternalFunction*>(caller)) {
|
||||
callerName = callerFunctionInternal->name();
|
||||
}
|
||||
|
||||
#if ENABLE(WEBASSEMBLY)
|
||||
if (visitor->isNativeCalleeFrame())
|
||||
return visitor->callee().asNativeCallee()->implementationVisibility();
|
||||
#endif
|
||||
size_t totalFrames = 0;
|
||||
|
||||
if (visitor->callee().isCell()) {
|
||||
if (auto* callee = visitor->callee().asCell()) {
|
||||
if (auto* jsFunction = jsDynamicCast<JSFunction*>(callee)) {
|
||||
if (auto* executable = jsFunction->executable())
|
||||
return executable->implementationVisibility();
|
||||
return ImplementationVisibility::Public;
|
||||
if (!callerName.isEmpty()) {
|
||||
JSC::StackVisitor::visit(callFrame, vm, [&](JSC::StackVisitor& visitor) -> WTF::IterationStatus {
|
||||
if (isImplementationVisibilityPrivate(visitor)) {
|
||||
return WTF::IterationStatus::Continue;
|
||||
}
|
||||
|
||||
framesCount += 1;
|
||||
|
||||
// skip caller frame and all frames above it
|
||||
if (!belowCaller) {
|
||||
skipFrames += 1;
|
||||
|
||||
if (visitor->functionName() == callerName) {
|
||||
belowCaller = true;
|
||||
return WTF::IterationStatus::Continue;
|
||||
}
|
||||
}
|
||||
|
||||
totalFrames += 1;
|
||||
|
||||
if (totalFrames > stackTraceLimit) {
|
||||
return WTF::IterationStatus::Done;
|
||||
}
|
||||
|
||||
return WTF::IterationStatus::Continue;
|
||||
});
|
||||
} else if (caller && caller.isCell()) {
|
||||
JSC::StackVisitor::visit(callFrame, vm, [&](JSC::StackVisitor& visitor) -> WTF::IterationStatus {
|
||||
if (isImplementationVisibilityPrivate(visitor)) {
|
||||
return WTF::IterationStatus::Continue;
|
||||
}
|
||||
|
||||
framesCount += 1;
|
||||
|
||||
// skip caller frame and all frames above it
|
||||
if (!belowCaller) {
|
||||
auto callee = visitor->callee();
|
||||
skipFrames += 1;
|
||||
if (callee.isCell() && callee.asCell() == caller) {
|
||||
belowCaller = true;
|
||||
return WTF::IterationStatus::Continue;
|
||||
}
|
||||
}
|
||||
|
||||
totalFrames += 1;
|
||||
|
||||
if (totalFrames > stackTraceLimit) {
|
||||
return WTF::IterationStatus::Done;
|
||||
}
|
||||
|
||||
return WTF::IterationStatus::Continue;
|
||||
});
|
||||
} else if (caller.isEmpty() || caller.isUndefined()) {
|
||||
// Skip the first frame.
|
||||
JSC::StackVisitor::visit(callFrame, vm, [&](JSC::StackVisitor& visitor) -> WTF::IterationStatus {
|
||||
if (isImplementationVisibilityPrivate(visitor)) {
|
||||
return WTF::IterationStatus::Continue;
|
||||
}
|
||||
|
||||
framesCount += 1;
|
||||
|
||||
if (!belowCaller) {
|
||||
skipFrames += 1;
|
||||
belowCaller = true;
|
||||
}
|
||||
|
||||
totalFrames += 1;
|
||||
|
||||
if (totalFrames > stackTraceLimit) {
|
||||
return WTF::IterationStatus::Done;
|
||||
}
|
||||
|
||||
return WTF::IterationStatus::Continue;
|
||||
});
|
||||
}
|
||||
size_t i = 0;
|
||||
totalFrames = 0;
|
||||
stackTrace.reserveInitialCapacity(framesCount);
|
||||
JSC::StackVisitor::visit(callFrame, vm, [&](JSC::StackVisitor& visitor) -> WTF::IterationStatus {
|
||||
// Skip native frames
|
||||
if (isImplementationVisibilityPrivate(visitor)) {
|
||||
return WTF::IterationStatus::Continue;
|
||||
}
|
||||
|
||||
return ImplementationVisibility::Public;
|
||||
}();
|
||||
// Skip frames if needed
|
||||
if (skipFrames > 0) {
|
||||
skipFrames--;
|
||||
return WTF::IterationStatus::Continue;
|
||||
}
|
||||
|
||||
return implementationVisibility != ImplementationVisibility::Public;
|
||||
totalFrames += 1;
|
||||
|
||||
if (totalFrames > stackTraceLimit) {
|
||||
return WTF::IterationStatus::Done;
|
||||
}
|
||||
|
||||
if (visitor->isNativeCalleeFrame()) {
|
||||
|
||||
auto* nativeCallee = visitor->callee().asNativeCallee();
|
||||
switch (nativeCallee->category()) {
|
||||
case NativeCallee::Category::Wasm: {
|
||||
stackTrace.append(StackFrame(visitor->wasmFunctionIndexOrName()));
|
||||
break;
|
||||
}
|
||||
case NativeCallee::Category::InlineCache: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if USE(ALLOW_LINE_AND_COLUMN_NUMBER_IN_BUILTINS)
|
||||
} else if (!!visitor->codeBlock())
|
||||
#else
|
||||
} else if (!!visitor->codeBlock() && !visitor->codeBlock()->unlinkedCodeBlock()->isBuiltinFunction())
|
||||
#endif
|
||||
stackTrace.append(StackFrame(vm, owner, visitor->callee().asCell(), visitor->codeBlock(), visitor->bytecodeIndex()));
|
||||
else
|
||||
stackTrace.append(StackFrame(vm, owner, visitor->callee().asCell()));
|
||||
|
||||
i++;
|
||||
|
||||
return (i == framesCount) ? WTF::IterationStatus::Done : WTF::IterationStatus::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
JSCStackTrace JSCStackTrace::captureCurrentJSStackTrace(Zig::GlobalObject* globalObject, JSC::CallFrame* callFrame, size_t frameLimit, JSC::JSValue caller)
|
||||
@@ -203,6 +382,22 @@ JSCStackTrace JSCStackTrace::getStackTraceForThrownValue(JSC::VM& vm, JSC::JSVal
|
||||
return fromExisting(vm, *jscStackTrace);
|
||||
}
|
||||
|
||||
static bool isVisibleBuiltinFunction(JSC::CodeBlock* codeBlock)
|
||||
{
|
||||
if (!codeBlock->ownerExecutable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const JSC::SourceCode& source = codeBlock->source();
|
||||
if (auto* provider = source.provider()) {
|
||||
const auto& url = provider->sourceURL();
|
||||
if (!url.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
JSCStackFrame::JSCStackFrame(JSC::VM& vm, JSC::StackVisitor& visitor)
|
||||
: m_vm(vm)
|
||||
, m_codeBlock(nullptr)
|
||||
@@ -228,9 +423,18 @@ JSCStackFrame::JSCStackFrame(JSC::VM& vm, JSC::StackVisitor& visitor)
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (!!visitor->codeBlock() && !visitor->codeBlock()->unlinkedCodeBlock()->isBuiltinFunction()) {
|
||||
m_codeBlock = visitor->codeBlock();
|
||||
m_bytecodeIndex = visitor->bytecodeIndex();
|
||||
} else if (auto* codeBlock = visitor->codeBlock()) {
|
||||
auto* unlinkedCodeBlock = codeBlock->unlinkedCodeBlock();
|
||||
if (!unlinkedCodeBlock->isBuiltinFunction() || isVisibleBuiltinFunction(codeBlock)) {
|
||||
m_codeBlock = codeBlock;
|
||||
m_bytecodeIndex = visitor->bytecodeIndex();
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_bytecodeIndex && visitor->hasLineAndColumnInfo()) {
|
||||
auto lineColumn = visitor->computeLineAndColumn();
|
||||
m_sourcePositions = { OrdinalNumber::fromOneBasedInt(lineColumn.line), OrdinalNumber::fromOneBasedInt(lineColumn.column) };
|
||||
m_sourcePositionsState = SourcePositionsState::Calculated;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,12 +454,19 @@ JSCStackFrame::JSCStackFrame(JSC::VM& vm, const JSC::StackFrame& frame)
|
||||
if (frame.isWasmFrame()) {
|
||||
m_wasmFunctionIndexOrName = frame.wasmFunctionIndexOrName();
|
||||
m_isWasmFrame = true;
|
||||
} else {
|
||||
m_codeBlock = frame.codeBlock();
|
||||
if (frame.hasBytecodeIndex()) {
|
||||
} else if (auto* codeBlock = frame.codeBlock()) {
|
||||
auto* unlinkedCodeBlock = codeBlock->unlinkedCodeBlock();
|
||||
if (!unlinkedCodeBlock->isBuiltinFunction() || isVisibleBuiltinFunction(codeBlock)) {
|
||||
m_codeBlock = codeBlock;
|
||||
m_bytecodeIndex = frame.bytecodeIndex();
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_codeBlock && frame.hasLineAndColumnInfo()) {
|
||||
auto lineColumn = frame.computeLineAndColumn();
|
||||
m_sourcePositions = { OrdinalNumber::fromOneBasedInt(lineColumn.line), OrdinalNumber::fromOneBasedInt(lineColumn.column) };
|
||||
m_sourcePositionsState = SourcePositionsState::Calculated;
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t JSCStackFrame::sourceID() const
|
||||
@@ -308,16 +519,36 @@ ALWAYS_INLINE String JSCStackFrame::retrieveSourceURL()
|
||||
return String(sourceURLWasmString);
|
||||
}
|
||||
|
||||
if (m_callee && m_callee->isObject()) {
|
||||
if (auto* jsFunction = jsDynamicCast<JSFunction*>(m_callee)) {
|
||||
if (auto* executable = jsFunction->executable()) {
|
||||
if (!executable->isHostFunction()) {
|
||||
auto* jsExectuable = jsFunction->jsExecutable();
|
||||
if (jsExectuable) {
|
||||
const auto* sourceProvider = jsExectuable->source().provider();
|
||||
if (sourceProvider) {
|
||||
return sourceProvider->sourceURL();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_codeBlock) {
|
||||
return String(sourceURLNativeString);
|
||||
}
|
||||
|
||||
return m_codeBlock->ownerExecutable()->sourceURL();
|
||||
auto* provider = m_codeBlock->source().provider();
|
||||
if (provider) {
|
||||
return provider->sourceURL();
|
||||
}
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE String JSCStackFrame::retrieveFunctionName()
|
||||
{
|
||||
static auto functionNameEvalCodeString = MAKE_STATIC_STRING_IMPL("eval code");
|
||||
static auto functionNameModuleCodeString = MAKE_STATIC_STRING_IMPL("module code");
|
||||
static auto functionNameGlobalCodeString = MAKE_STATIC_STRING_IMPL("global code");
|
||||
|
||||
@@ -328,7 +559,8 @@ ALWAYS_INLINE String JSCStackFrame::retrieveFunctionName()
|
||||
if (m_codeBlock) {
|
||||
switch (m_codeBlock->codeType()) {
|
||||
case JSC::EvalCode:
|
||||
return String(functionNameEvalCodeString);
|
||||
// Node returns null here.
|
||||
return String();
|
||||
case JSC::ModuleCode:
|
||||
return String(functionNameModuleCodeString);
|
||||
case JSC::FunctionCode:
|
||||
@@ -340,13 +572,26 @@ ALWAYS_INLINE String JSCStackFrame::retrieveFunctionName()
|
||||
}
|
||||
}
|
||||
|
||||
String name;
|
||||
if (m_callee) {
|
||||
if (m_callee->isObject())
|
||||
name = getCalculatedDisplayName(m_vm, jsCast<JSObject*>(m_callee)).impl();
|
||||
if (auto* callee = m_callee->getObject()) {
|
||||
// Does the code block have a user-defined name property?
|
||||
JSC::JSValue name = callee->getDirect(m_vm, m_vm.propertyNames->name);
|
||||
if (name && name.isString()) {
|
||||
auto scope = DECLARE_CATCH_SCOPE(m_vm);
|
||||
auto nameString = name.toWTFString(callee->globalObject());
|
||||
if (scope.exception()) {
|
||||
scope.clearException();
|
||||
}
|
||||
if (!nameString.isEmpty()) {
|
||||
return nameString;
|
||||
}
|
||||
}
|
||||
|
||||
return JSC::getCalculatedDisplayName(m_vm, callee);
|
||||
}
|
||||
}
|
||||
|
||||
return name.isNull() ? emptyString() : name;
|
||||
return emptyString();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE String JSCStackFrame::retrieveTypeName()
|
||||
|
||||
@@ -46,13 +46,13 @@ public:
|
||||
|
||||
private:
|
||||
JSC::VM& m_vm;
|
||||
JSC::JSCell* m_callee;
|
||||
JSC::JSCell* m_callee { nullptr };
|
||||
|
||||
// May be null
|
||||
JSC::CallFrame* m_callFrame;
|
||||
|
||||
// May be null
|
||||
JSC::CodeBlock* m_codeBlock;
|
||||
JSC::CodeBlock* m_codeBlock { nullptr };
|
||||
JSC::BytecodeIndex m_bytecodeIndex;
|
||||
|
||||
// Lazy-initialized
|
||||
@@ -96,8 +96,40 @@ public:
|
||||
SourcePositions* getSourcePositions();
|
||||
|
||||
bool isWasmFrame() const { return m_isWasmFrame; }
|
||||
bool isEval() const { return m_codeBlock && (JSC::EvalCode == m_codeBlock->codeType()); }
|
||||
bool isConstructor() const { return m_codeBlock && (JSC::CodeForConstruct == m_codeBlock->specializationKind()); }
|
||||
bool isEval()
|
||||
{
|
||||
if (m_codeBlock) {
|
||||
if (m_codeBlock->codeType() == JSC::EvalCode) {
|
||||
return true;
|
||||
}
|
||||
auto* executable = m_codeBlock->ownerExecutable();
|
||||
if (!executable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (executable->evalContextType()) {
|
||||
case JSC::EvalContextType::None: {
|
||||
return false;
|
||||
}
|
||||
case JSC::EvalContextType::FunctionEvalContext:
|
||||
case JSC::EvalContextType::InstanceFieldEvalContext:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_callee && m_callee->inherits<JSC::JSFunction>()) {
|
||||
auto* function = jsCast<JSC::JSFunction*>(m_callee);
|
||||
if (function->isHostFunction()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
bool isConstructor() const
|
||||
{
|
||||
return m_codeBlock && (JSC::CodeForConstruct == m_codeBlock->specializationKind());
|
||||
}
|
||||
|
||||
private:
|
||||
ALWAYS_INLINE String retrieveSourceURL();
|
||||
@@ -130,10 +162,17 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
JSCStackTrace(WTF::Vector<JSCStackFrame>&& frames)
|
||||
: m_frames(WTFMove(frames))
|
||||
{
|
||||
}
|
||||
|
||||
size_t size() const { return m_frames.size(); }
|
||||
bool isEmpty() const { return m_frames.isEmpty(); }
|
||||
JSCStackFrame& at(size_t i) { return m_frames.at(i); }
|
||||
|
||||
WTF::Vector<JSCStackFrame>&& frames() { return WTFMove(m_frames); }
|
||||
|
||||
static JSCStackTrace fromExisting(JSC::VM& vm, const WTF::Vector<JSC::StackFrame>& existingFrames);
|
||||
|
||||
/* This is based on JSC::Interpreter::getStackTrace, but skips native (non js and not wasm)
|
||||
@@ -145,6 +184,7 @@ public:
|
||||
*
|
||||
* Return value must remain stack allocated. */
|
||||
static JSCStackTrace captureCurrentJSStackTrace(Zig::GlobalObject* globalObject, JSC::CallFrame* callFrame, size_t frameLimit, JSC::JSValue caller);
|
||||
static void getFramesForCaller(JSC::VM& vm, JSC::CallFrame* callFrame, JSC::JSCell* owner, JSC::JSValue caller, WTF::Vector<JSC::StackFrame>& stackTrace, size_t stackTraceLimit);
|
||||
|
||||
/* In JSC, JSC::Exception points to the actual value that was thrown, usually
|
||||
* a JSC::ErrorInstance (but could be any JSValue). In v8, on the other hand,
|
||||
|
||||
@@ -41,4 +41,4 @@ protected:
|
||||
bool m_isCleanupTask;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,4 +18,4 @@ ALWAYS_INLINE GCDeferralContext::~GCDeferralContext()
|
||||
m_vm.heap.collectIfNecessaryOrDefer();
|
||||
}
|
||||
|
||||
} // namespace JSC
|
||||
} // namespace JSC
|
||||
|
||||
@@ -414,4 +414,4 @@ template<typename T>
|
||||
struct IsIDLArrayBufferViewAllowShared : public std::integral_constant<bool, std::is_base_of<IDLAllowSharedAdaptor<IDLArrayBufferView>, T>::value> {
|
||||
};
|
||||
|
||||
} // namespace WebCore
|
||||
} // namespace WebCore
|
||||
|
||||
@@ -10,4 +10,4 @@ JSC_DECLARE_HOST_FUNCTION(jsDollarCpp);
|
||||
JSC_DECLARE_HOST_FUNCTION(jsDollarZig);
|
||||
|
||||
} // namespace JS2Native
|
||||
} // namespace Bun
|
||||
} // namespace Bun
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
|
||||
#include "JSBufferEncodingType.h"
|
||||
#include "ErrorCode.h"
|
||||
#include "NodeValidator.h"
|
||||
#include "wtf/Assertions.h"
|
||||
#include "wtf/Forward.h"
|
||||
#include <JavaScriptCore/JSBase.h>
|
||||
@@ -90,6 +91,7 @@ static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_allocUnsafeSlow);
|
||||
static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_byteLength);
|
||||
static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_compare);
|
||||
static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_concat);
|
||||
static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_copyBytesFrom);
|
||||
static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_from);
|
||||
static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_isBuffer);
|
||||
static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_isEncoding);
|
||||
@@ -246,29 +248,15 @@ static int normalizeCompareVal(int val, size_t a_length, size_t b_length)
|
||||
return val;
|
||||
}
|
||||
|
||||
const unsigned U32_MAX = std::numeric_limits<unsigned>().max();
|
||||
|
||||
static inline uint32_t parseIndex(JSC::JSGlobalObject* lexicalGlobalObject, JSC::ThrowScope& scope, ASCIILiteral name, JSValue arg, size_t upperBound)
|
||||
{
|
||||
if (!arg.isNumber()) return Bun::ERR::INVALID_ARG_TYPE(scope, lexicalGlobalObject, name, "number"_s, arg);
|
||||
auto num = arg.asNumber();
|
||||
if (num < 0 || std::isinf(num)) return Bun::ERR::OUT_OF_RANGE(scope, lexicalGlobalObject, name, 0, upperBound, arg);
|
||||
double intpart;
|
||||
if (std::modf(num, &intpart) != 0) return Bun::ERR::INVALID_ARG_TYPE(scope, lexicalGlobalObject, name, "integer"_s, arg);
|
||||
if (intpart >= 0 && intpart <= U32_MAX) return intpart;
|
||||
return Bun::ERR::OUT_OF_RANGE(scope, lexicalGlobalObject, name, 0, upperBound, arg);
|
||||
}
|
||||
|
||||
static inline WebCore::BufferEncodingType parseEncoding(JSC::JSGlobalObject* lexicalGlobalObject, JSC::ThrowScope& scope, JSValue arg)
|
||||
{
|
||||
if (UNLIKELY(!arg.isString())) {
|
||||
Bun::ERR::INVALID_ARG_TYPE(scope, lexicalGlobalObject, "encoding"_s, "string"_s, arg);
|
||||
return WebCore::BufferEncodingType::utf8;
|
||||
}
|
||||
auto arg_ = arg.toStringOrNull(lexicalGlobalObject);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
auto arg_s = arg_->getString(lexicalGlobalObject);
|
||||
|
||||
std::optional<BufferEncodingType> encoded = parseEnumeration<BufferEncodingType>(*lexicalGlobalObject, arg);
|
||||
std::optional<BufferEncodingType> encoded = parseEnumeration2(*lexicalGlobalObject, arg_s);
|
||||
if (UNLIKELY(!encoded)) {
|
||||
Bun::ERR::UNKNOWN_ENCODING(scope, lexicalGlobalObject, arg);
|
||||
Bun::ERR::UNKNOWN_ENCODING(scope, lexicalGlobalObject, arg_s);
|
||||
return WebCore::BufferEncodingType::utf8;
|
||||
}
|
||||
|
||||
@@ -415,6 +403,10 @@ static inline JSC::JSUint8Array* JSBuffer__bufferFromLengthAsArray(JSC::JSGlobal
|
||||
throwNodeRangeError(lexicalGlobalObject, throwScope, "Invalid array length"_s);
|
||||
return nullptr;
|
||||
}
|
||||
if (length > MAX_ARRAY_BUFFER_SIZE) {
|
||||
Bun::ERR::OUT_OF_RANGE(throwScope, lexicalGlobalObject, "size"_s, 0, MAX_ARRAY_BUFFER_SIZE, jsNumber(length));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
|
||||
auto* subclassStructure = globalObject->JSBufferSubclassStructure();
|
||||
@@ -428,27 +420,18 @@ extern "C" JSC::EncodedJSValue JSBuffer__bufferFromLength(JSC::JSGlobalObject* l
|
||||
return JSC::JSValue::encode(JSBuffer__bufferFromLengthAsArray(lexicalGlobalObject, length));
|
||||
}
|
||||
|
||||
// https://github.com/nodejs/node/blob/v22.9.0/lib/buffer.js#L404
|
||||
static inline JSC::EncodedJSValue jsBufferConstructorFunction_allocUnsafeBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
|
||||
{
|
||||
|
||||
VM& vm = lexicalGlobalObject->vm();
|
||||
|
||||
auto throwScope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
JSValue lengthValue = callFrame->argument(0);
|
||||
if (UNLIKELY(!lengthValue.isNumber())) {
|
||||
return Bun::ERR::INVALID_ARG_TYPE(throwScope, lexicalGlobalObject, "size"_s, "number"_s, lengthValue);
|
||||
}
|
||||
|
||||
double lengthDouble = lengthValue.toIntegerWithTruncation(lexicalGlobalObject);
|
||||
|
||||
if (UNLIKELY(lengthDouble < 0 || lengthDouble > MAX_ARRAY_BUFFER_SIZE || lengthDouble != lengthDouble)) {
|
||||
return Bun::ERR::OUT_OF_RANGE(throwScope, lexicalGlobalObject, "size"_s, 0, MAX_ARRAY_BUFFER_SIZE, lengthValue);
|
||||
}
|
||||
|
||||
size_t length = static_cast<size_t>(lengthDouble);
|
||||
|
||||
RELEASE_AND_RETURN(throwScope, JSValue::encode(allocBufferUnsafe(lexicalGlobalObject, length)));
|
||||
Bun::V::validateNumber(throwScope, lexicalGlobalObject, lengthValue, jsString(vm, String("size"_s)), jsNumber(0), jsNumber(Bun::Buffer::kMaxLength));
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
size_t length = lengthValue.toLength(lexicalGlobalObject);
|
||||
auto result = allocBufferUnsafe(lexicalGlobalObject, length);
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
|
||||
}
|
||||
|
||||
// new Buffer()
|
||||
@@ -542,7 +525,7 @@ static inline JSC::EncodedJSValue constructBufferFromStringAndEncoding(JSC::JSGl
|
||||
if (arg1 && arg1.isString()) {
|
||||
std::optional<BufferEncodingType> encoded = parseEnumeration<BufferEncodingType>(*lexicalGlobalObject, arg1);
|
||||
if (!encoded) {
|
||||
return Bun::ERR::UNKNOWN_ENCODING(scope, lexicalGlobalObject, arg1);
|
||||
return Bun::ERR::UNKNOWN_ENCODING(scope, lexicalGlobalObject, arg1.getString(lexicalGlobalObject));
|
||||
}
|
||||
|
||||
encoding = encoded.value();
|
||||
@@ -556,23 +539,16 @@ static inline JSC::EncodedJSValue constructBufferFromStringAndEncoding(JSC::JSGl
|
||||
RELEASE_AND_RETURN(scope, result);
|
||||
}
|
||||
|
||||
// https://github.com/nodejs/node/blob/v22.9.0/lib/buffer.js#L391
|
||||
static inline JSC::EncodedJSValue jsBufferConstructorFunction_allocBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
|
||||
{
|
||||
VM& vm = lexicalGlobalObject->vm();
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
JSValue lengthValue = callFrame->uncheckedArgument(0);
|
||||
if (UNLIKELY(!lengthValue.isNumber())) {
|
||||
return Bun::ERR::INVALID_ARG_TYPE(scope, lexicalGlobalObject, "size"_s, "number"_s, lengthValue);
|
||||
return {};
|
||||
}
|
||||
|
||||
double lengthDouble = lengthValue.toIntegerWithTruncation(lexicalGlobalObject);
|
||||
|
||||
if (UNLIKELY(lengthDouble < 0 || lengthDouble > MAX_ARRAY_BUFFER_SIZE || lengthDouble != lengthDouble)) {
|
||||
return Bun::ERR::OUT_OF_RANGE(scope, lexicalGlobalObject, "size"_s, 0, MAX_ARRAY_BUFFER_SIZE, lengthValue);
|
||||
}
|
||||
|
||||
size_t length = static_cast<size_t>(lengthDouble);
|
||||
JSValue lengthValue = callFrame->argument(0);
|
||||
Bun::V::validateNumber(scope, lexicalGlobalObject, lengthValue, jsString(vm, String("size"_s)), jsNumber(0), jsNumber(Bun::Buffer::kMaxLength));
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
size_t length = lengthValue.toLength(lexicalGlobalObject);
|
||||
|
||||
// fill argument
|
||||
if (UNLIKELY(callFrame->argumentCount() > 1)) {
|
||||
@@ -769,6 +745,7 @@ static inline JSC::EncodedJSValue jsBufferConstructorFunction_compareBody(JSC::J
|
||||
|
||||
RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNumber(normalizeCompareVal(result, sourceLength, targetLength))));
|
||||
}
|
||||
|
||||
static inline JSC::EncodedJSValue jsBufferConstructorFunction_concatBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
|
||||
{
|
||||
auto& vm = JSC::getVM(lexicalGlobalObject);
|
||||
@@ -876,13 +853,76 @@ static inline JSC::EncodedJSValue jsBufferConstructorFunction_concatBody(JSC::JS
|
||||
RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::JSValue(outBuffer)));
|
||||
}
|
||||
|
||||
// https://github.com/nodejs/node/blob/v22.9.0/lib/buffer.js#L337
|
||||
static inline JSC::EncodedJSValue jsBufferConstructorFunction_copyBytesFromBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
|
||||
{
|
||||
auto& vm = JSC::getVM(lexicalGlobalObject);
|
||||
auto throwScope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
auto viewValue = callFrame->argument(0);
|
||||
auto offsetValue = callFrame->argument(1);
|
||||
auto lengthValue = callFrame->argument(2);
|
||||
|
||||
auto view = jsDynamicCast<JSArrayBufferView*>(viewValue);
|
||||
if (!view) {
|
||||
return Bun::ERR::INVALID_ARG_TYPE(throwScope, lexicalGlobalObject, "view"_s, "TypedArray"_s, viewValue);
|
||||
}
|
||||
|
||||
auto ty = JSC::typedArrayType(view->type());
|
||||
|
||||
auto viewLength = view->length();
|
||||
if (viewLength == 0) {
|
||||
return JSValue::encode(createEmptyBuffer(lexicalGlobalObject));
|
||||
}
|
||||
|
||||
double offset;
|
||||
double length;
|
||||
|
||||
if (!offsetValue.isUndefined() || !lengthValue.isUndefined()) {
|
||||
if (!offsetValue.isUndefined()) {
|
||||
Bun::V::validateInteger(throwScope, lexicalGlobalObject, offsetValue, jsString(vm, String("offset"_s)), jsNumber(0), jsUndefined());
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
offset = offsetValue.asNumber();
|
||||
if (offset >= viewLength) return JSValue::encode(createEmptyBuffer(lexicalGlobalObject));
|
||||
} else {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
double end = 0;
|
||||
if (!lengthValue.isUndefined()) {
|
||||
Bun::V::validateInteger(throwScope, lexicalGlobalObject, lengthValue, jsString(vm, String("length"_s)), jsNumber(0), jsUndefined());
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
length = lengthValue.asNumber();
|
||||
end = offset + length;
|
||||
} else {
|
||||
end = viewLength;
|
||||
}
|
||||
end = std::min(end, (double)viewLength);
|
||||
|
||||
auto elemSize = JSC::elementSize(ty);
|
||||
auto offset_r = offset * elemSize;
|
||||
auto end_r = end * elemSize;
|
||||
auto span = view->span().subspan(offset_r, end_r - offset_r);
|
||||
return JSValue::encode(createBuffer(lexicalGlobalObject, span.data(), span.size()));
|
||||
}
|
||||
|
||||
auto boffset = view->byteOffset();
|
||||
auto blength = view->byteLength();
|
||||
auto span = view->span().subspan(boffset, blength - boffset);
|
||||
return JSValue::encode(createBuffer(lexicalGlobalObject, span.data(), span.size()));
|
||||
}
|
||||
|
||||
static inline JSC::EncodedJSValue jsBufferConstructorFunction_isEncodingBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
|
||||
{
|
||||
auto* encoding_ = callFrame->argument(0).toStringOrNull(lexicalGlobalObject);
|
||||
if (!encoding_)
|
||||
auto& vm = lexicalGlobalObject->vm();
|
||||
auto throwScope = DECLARE_THROW_SCOPE(vm);
|
||||
auto encodingValue = callFrame->argument(0);
|
||||
if (!encodingValue.isString()) {
|
||||
return JSValue::encode(jsBoolean(false));
|
||||
|
||||
std::optional<BufferEncodingType> encoded = parseEnumeration<BufferEncodingType>(*lexicalGlobalObject, encoding_);
|
||||
}
|
||||
auto* encoding = encodingValue.toString(lexicalGlobalObject);
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
std::optional<BufferEncodingType> encoded = parseEnumeration<BufferEncodingType>(*lexicalGlobalObject, encoding);
|
||||
return JSValue::encode(jsBoolean(!!encoded));
|
||||
}
|
||||
|
||||
@@ -951,26 +991,38 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_compareBody(JSC::JSG
|
||||
switch (callFrame->argumentCount()) {
|
||||
default:
|
||||
sourceEndValue = callFrame->uncheckedArgument(4);
|
||||
if (sourceEndValue != jsUndefined())
|
||||
sourceEnd = parseIndex(lexicalGlobalObject, throwScope, "sourceEnd"_s, sourceEndValue, sourceEndInit);
|
||||
if (sourceEndValue != jsUndefined()) {
|
||||
Bun::V::validateInteger(throwScope, lexicalGlobalObject, sourceEndValue, jsString(vm, String("sourceEnd"_s)), jsNumber(0), jsNumber(Bun::Buffer::kMaxLength));
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
sourceEnd = sourceEndValue.asNumber();
|
||||
}
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
FALLTHROUGH;
|
||||
case 4:
|
||||
sourceStartValue = callFrame->uncheckedArgument(3);
|
||||
if (sourceStartValue != jsUndefined())
|
||||
sourceStart = parseIndex(lexicalGlobalObject, throwScope, "sourceStart"_s, sourceStartValue, sourceEndInit);
|
||||
if (sourceStartValue != jsUndefined()) {
|
||||
Bun::V::validateInteger(throwScope, lexicalGlobalObject, sourceStartValue, jsString(vm, String("sourceStart"_s)), jsNumber(0), jsNumber(Bun::Buffer::kMaxLength));
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
sourceStart = sourceStartValue.asNumber();
|
||||
}
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
FALLTHROUGH;
|
||||
case 3:
|
||||
targetEndValue = callFrame->uncheckedArgument(2);
|
||||
if (targetEndValue != jsUndefined())
|
||||
targetEnd = parseIndex(lexicalGlobalObject, throwScope, "targetEnd"_s, targetEndValue, targetEndInit);
|
||||
if (targetEndValue != jsUndefined()) {
|
||||
Bun::V::validateInteger(throwScope, lexicalGlobalObject, targetEndValue, jsString(vm, String("targetEnd"_s)), jsNumber(0), jsNumber(Bun::Buffer::kMaxLength));
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
targetEnd = targetEndValue.asNumber();
|
||||
}
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
FALLTHROUGH;
|
||||
case 2:
|
||||
targetStartValue = callFrame->uncheckedArgument(1);
|
||||
if (targetStartValue != jsUndefined())
|
||||
targetStart = parseIndex(lexicalGlobalObject, throwScope, "targetStart"_s, targetStartValue, targetEndInit);
|
||||
if (targetStartValue != jsUndefined()) {
|
||||
Bun::V::validateInteger(throwScope, lexicalGlobalObject, targetStartValue, jsString(vm, String("targetStart"_s)), jsNumber(0), jsNumber(Bun::Buffer::kMaxLength));
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
targetStart = targetStartValue.asNumber();
|
||||
}
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
break;
|
||||
case 1:
|
||||
@@ -1005,76 +1057,83 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_compareBody(JSC::JSG
|
||||
|
||||
RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNumber(normalizeCompareVal(result, sourceLength, targetLength))));
|
||||
}
|
||||
|
||||
static double toInteger(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, double defaultVal)
|
||||
{
|
||||
auto n = value.toNumber(globalObject);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
if (std::isnan(n)) return defaultVal;
|
||||
if (n < JSC::minSafeInteger()) return defaultVal;
|
||||
if (n > JSC::maxSafeInteger()) return defaultVal;
|
||||
return std::trunc(n);
|
||||
}
|
||||
|
||||
// https://github.com/nodejs/node/blob/v22.9.0/lib/buffer.js#L825
|
||||
// https://github.com/nodejs/node/blob/v22.9.0/lib/buffer.js#L205
|
||||
static inline JSC::EncodedJSValue jsBufferPrototypeFunction_copyBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSArrayBufferView>::ClassParameter castedThis)
|
||||
{
|
||||
auto& vm = JSC::getVM(lexicalGlobalObject);
|
||||
auto throwScope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
if (callFrame->argumentCount() < 1) {
|
||||
throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
|
||||
return {};
|
||||
auto targetValue = callFrame->argument(0);
|
||||
auto targetStartValue = callFrame->argument(1);
|
||||
auto sourceStartValue = callFrame->argument(2);
|
||||
auto sourceEndValue = callFrame->argument(3);
|
||||
|
||||
auto source = castedThis;
|
||||
auto target = jsDynamicCast<JSArrayBufferView*>(targetValue);
|
||||
if (!target) {
|
||||
return Bun::ERR::INVALID_ARG_TYPE(throwScope, lexicalGlobalObject, "target"_s, "Buffer or Uint8Array"_s, targetValue);
|
||||
}
|
||||
|
||||
auto buffer = callFrame->uncheckedArgument(0);
|
||||
|
||||
if (!buffer.isCell() || !JSC::isTypedView(buffer.asCell()->type())) {
|
||||
throwVMTypeError(lexicalGlobalObject, throwScope, "Expected Uint8Array"_s);
|
||||
return {};
|
||||
}
|
||||
|
||||
JSC::JSArrayBufferView* view = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(buffer);
|
||||
if (UNLIKELY(!view || view->isDetached())) {
|
||||
throwVMTypeError(lexicalGlobalObject, throwScope, "Uint8Array is detached"_s);
|
||||
return {};
|
||||
}
|
||||
auto sourceLength = source->byteLength();
|
||||
auto targetLength = target->byteLength();
|
||||
|
||||
size_t targetStart = 0;
|
||||
size_t targetEnd = view->byteLength();
|
||||
|
||||
size_t sourceStart = 0;
|
||||
size_t sourceEndInit = castedThis->byteLength();
|
||||
size_t sourceEnd = sourceEndInit;
|
||||
|
||||
JSValue targetStartValue = jsUndefined();
|
||||
JSValue sourceStartValue = jsUndefined();
|
||||
JSValue sourceEndValue = jsUndefined();
|
||||
|
||||
switch (callFrame->argumentCount()) {
|
||||
default:
|
||||
sourceEndValue = callFrame->uncheckedArgument(3);
|
||||
sourceEnd = parseIndex(lexicalGlobalObject, throwScope, "sourceEnd"_s, callFrame->uncheckedArgument(3), sourceEndInit);
|
||||
if (targetStartValue.isUndefined()) {
|
||||
} else {
|
||||
double targetStartD = targetStartValue.isAnyInt() ? targetStartValue.asNumber() : toInteger(throwScope, lexicalGlobalObject, targetStartValue, 0);
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
FALLTHROUGH;
|
||||
case 3:
|
||||
sourceStartValue = callFrame->uncheckedArgument(2);
|
||||
sourceStart = parseIndex(lexicalGlobalObject, throwScope, "sourceStart"_s, callFrame->uncheckedArgument(2), sourceEndInit);
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
FALLTHROUGH;
|
||||
case 2:
|
||||
targetStartValue = callFrame->uncheckedArgument(1);
|
||||
targetStart = parseIndex(lexicalGlobalObject, throwScope, "targetStart"_s, callFrame->uncheckedArgument(1), targetEnd);
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
break;
|
||||
case 1:
|
||||
case 0:
|
||||
break;
|
||||
if (targetStartD < 0) return Bun::ERR::OUT_OF_RANGE(throwScope, lexicalGlobalObject, "targetStart"_s, 0, targetLength, targetStartValue);
|
||||
targetStart = static_cast<size_t>(targetStartD);
|
||||
}
|
||||
|
||||
targetStart = std::min(targetStart, targetEnd);
|
||||
sourceEnd = std::min(sourceEnd, sourceEndInit);
|
||||
sourceStart = std::min(sourceStart, sourceEnd);
|
||||
size_t sourceStart = 0;
|
||||
if (sourceStartValue.isUndefined()) {
|
||||
} else {
|
||||
double sourceStartD = sourceStartValue.isAnyInt() ? sourceStartValue.asNumber() : toInteger(throwScope, lexicalGlobalObject, sourceStartValue, 0);
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
if (sourceStartD < 0 || sourceStartD > sourceLength) return Bun::ERR::OUT_OF_RANGE(throwScope, lexicalGlobalObject, "sourceStart"_s, 0, sourceLength, sourceStartValue);
|
||||
sourceStart = static_cast<size_t>(sourceStartD);
|
||||
}
|
||||
|
||||
auto sourceLength = sourceEnd - sourceStart;
|
||||
auto targetLength = targetEnd - targetStart;
|
||||
auto actualLength = std::min(sourceLength, targetLength);
|
||||
size_t sourceEnd = sourceLength;
|
||||
if (sourceEndValue.isUndefined()) {
|
||||
} else {
|
||||
double sourceEndD = sourceEndValue.isAnyInt() ? sourceEndValue.asNumber() : toInteger(throwScope, lexicalGlobalObject, sourceEndValue, 0);
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
if (sourceEndD < 0) return Bun::ERR::OUT_OF_RANGE(throwScope, lexicalGlobalObject, "sourceEnd"_s, 0, sourceLength, sourceEndValue);
|
||||
sourceEnd = static_cast<size_t>(sourceEndD);
|
||||
}
|
||||
|
||||
auto sourceStartPtr = castedThis->typedVector() + sourceStart;
|
||||
auto targetStartPtr = reinterpret_cast<unsigned char*>(view->vector()) + targetStart;
|
||||
if (targetStart >= targetLength || sourceStart >= sourceEnd) {
|
||||
return JSValue::encode(jsNumber(0));
|
||||
}
|
||||
|
||||
if (actualLength > 0)
|
||||
memmove(targetStartPtr, sourceStartPtr, actualLength);
|
||||
if (sourceEnd - sourceStart > targetLength - targetStart)
|
||||
sourceEnd = sourceStart + targetLength - targetStart;
|
||||
|
||||
return JSValue::encode(jsNumber(actualLength));
|
||||
ssize_t nb = sourceEnd - sourceStart;
|
||||
auto sourceLen = sourceLength - sourceStart;
|
||||
if (nb > sourceLen) nb = sourceLen;
|
||||
|
||||
if (nb <= 0) return JSValue::encode(jsNumber(0));
|
||||
|
||||
auto sourceStartPtr = reinterpret_cast<unsigned char*>(source->vector()) + sourceStart;
|
||||
auto targetStartPtr = reinterpret_cast<unsigned char*>(target->vector()) + targetStart;
|
||||
memmove(targetStartPtr, sourceStartPtr, nb);
|
||||
|
||||
return JSValue::encode(jsNumber(nb));
|
||||
}
|
||||
|
||||
static inline JSC::EncodedJSValue jsBufferPrototypeFunction_equalsBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSArrayBufferView>::ClassParameter castedThis)
|
||||
@@ -1089,8 +1148,7 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_equalsBody(JSC::JSGl
|
||||
auto buffer = callFrame->uncheckedArgument(0);
|
||||
JSC::JSArrayBufferView* view = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(buffer);
|
||||
if (UNLIKELY(!view)) {
|
||||
throwVMTypeError(lexicalGlobalObject, throwScope, "Expected Buffer"_s);
|
||||
return {};
|
||||
return Bun::ERR::INVALID_ARG_TYPE(throwScope, lexicalGlobalObject, "otherBuffer"_s, "Buffer or Uint8Array"_s, buffer);
|
||||
}
|
||||
|
||||
if (UNLIKELY(view->isDetached())) {
|
||||
@@ -1123,19 +1181,19 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_fillBody(JSC::JSGlob
|
||||
|
||||
auto value = callFrame->uncheckedArgument(0);
|
||||
const size_t limit = castedThis->byteLength();
|
||||
size_t start = 0;
|
||||
size_t offset = 0;
|
||||
size_t end = limit;
|
||||
WebCore::BufferEncodingType encoding = WebCore::BufferEncodingType::utf8;
|
||||
JSValue encodingValue = jsUndefined();
|
||||
JSValue offsetValue = jsUndefined();
|
||||
JSValue lengthValue = jsUndefined();
|
||||
JSValue endValue = jsUndefined();
|
||||
|
||||
switch (callFrame->argumentCount()) {
|
||||
case 4:
|
||||
encodingValue = callFrame->uncheckedArgument(3);
|
||||
FALLTHROUGH;
|
||||
case 3:
|
||||
lengthValue = callFrame->uncheckedArgument(2);
|
||||
endValue = callFrame->uncheckedArgument(2);
|
||||
FALLTHROUGH;
|
||||
case 2:
|
||||
offsetValue = callFrame->uncheckedArgument(1);
|
||||
@@ -1147,49 +1205,48 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_fillBody(JSC::JSGlob
|
||||
if (offsetValue.isUndefined() || offsetValue.isString()) {
|
||||
encodingValue = offsetValue;
|
||||
offsetValue = jsUndefined();
|
||||
} else if (lengthValue.isString()) {
|
||||
encodingValue = lengthValue;
|
||||
lengthValue = jsUndefined();
|
||||
} else if (endValue.isString()) {
|
||||
encodingValue = endValue;
|
||||
endValue = jsUndefined();
|
||||
}
|
||||
|
||||
if (!encodingValue.isUndefined()) {
|
||||
if (!encodingValue.isUndefined() && value.isString()) {
|
||||
if (!encodingValue.isString()) return Bun::ERR::INVALID_ARG_TYPE(scope, lexicalGlobalObject, "encoding"_s, "string"_s, encodingValue);
|
||||
encoding = parseEncoding(lexicalGlobalObject, scope, encodingValue);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
}
|
||||
|
||||
// https://github.com/nodejs/node/blob/v22.9.0/lib/buffer.js#L1066-L1079
|
||||
// https://github.com/nodejs/node/blob/v22.9.0/lib/buffer.js#L122
|
||||
if (!offsetValue.isUndefined()) {
|
||||
start = parseIndex(lexicalGlobalObject, scope, "start"_s, offsetValue, limit);
|
||||
Bun::V::validateNumber(scope, lexicalGlobalObject, offsetValue, jsString(vm, String("offset"_s)), jsNumber(0), jsNumber(Bun::Buffer::kMaxLength));
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
offset = offsetValue.toLength(lexicalGlobalObject);
|
||||
}
|
||||
|
||||
if (!lengthValue.isUndefined()) {
|
||||
end = parseIndex(lexicalGlobalObject, scope, "end"_s, lengthValue, limit - start);
|
||||
if (!endValue.isUndefined()) {
|
||||
Bun::V::validateNumber(scope, lexicalGlobalObject, endValue, jsString(vm, String("end"_s)), jsNumber(0), jsNumber(limit));
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
end = endValue.toLength(lexicalGlobalObject);
|
||||
}
|
||||
|
||||
if (start >= end) {
|
||||
if (offset >= end) {
|
||||
RELEASE_AND_RETURN(scope, JSValue::encode(castedThis));
|
||||
}
|
||||
|
||||
if (UNLIKELY(end > limit)) {
|
||||
throwNodeRangeError(lexicalGlobalObject, scope, "end out of range"_s);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (value.isString()) {
|
||||
auto startPtr = castedThis->typedVector() + start;
|
||||
auto startPtr = castedThis->typedVector() + offset;
|
||||
auto str_ = value.toWTFString(lexicalGlobalObject);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
ZigString str = Zig::toZigString(str_);
|
||||
|
||||
if (str.len == 0) {
|
||||
memset(startPtr, 0, end - start);
|
||||
} else if (UNLIKELY(!Bun__Buffer_fill(&str, startPtr, end - start, encoding))) {
|
||||
memset(startPtr, 0, end - offset);
|
||||
} else if (UNLIKELY(!Bun__Buffer_fill(&str, startPtr, end - offset, encoding))) {
|
||||
return Bun::ERR::INVALID_ARG_VALUE(scope, lexicalGlobalObject, "value"_s, value);
|
||||
}
|
||||
} else if (auto* view = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(value)) {
|
||||
auto* startPtr = castedThis->typedVector() + start;
|
||||
auto* startPtr = castedThis->typedVector() + offset;
|
||||
auto* head = startPtr;
|
||||
size_t remain = end - start;
|
||||
size_t remain = end - offset;
|
||||
|
||||
if (UNLIKELY(view->isDetached())) {
|
||||
throwVMTypeError(lexicalGlobalObject, scope, "Uint8Array is detached"_s);
|
||||
@@ -1218,11 +1275,12 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_fillBody(JSC::JSGlob
|
||||
}
|
||||
} else {
|
||||
auto value_ = value.toInt32(lexicalGlobalObject) & 0xFF;
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
auto value_uint8 = static_cast<uint8_t>(value_);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
auto startPtr = castedThis->typedVector() + start;
|
||||
auto startPtr = castedThis->typedVector() + offset;
|
||||
auto endPtr = castedThis->typedVector() + end;
|
||||
memset(startPtr, value_uint8, endPtr - startPtr);
|
||||
}
|
||||
@@ -1481,6 +1539,9 @@ static inline JSC::EncodedJSValue jsBufferToString(JSC::VM& vm, JSC::JSGlobalObj
|
||||
if (length > WTF::String::MaxLength) {
|
||||
return Bun::ERR::STRING_TOO_LONG(scope, lexicalGlobalObject);
|
||||
}
|
||||
if (length > castedThis->byteLength()) {
|
||||
length = castedThis->byteLength();
|
||||
}
|
||||
|
||||
JSC::EncodedJSValue ret = 0;
|
||||
|
||||
@@ -1558,6 +1619,8 @@ bool inline parseArrayIndex(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalO
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://github.com/nodejs/node/blob/v22.9.0/lib/buffer.js#L834
|
||||
// using byteLength and byte offsets here is intentional
|
||||
static inline JSC::EncodedJSValue jsBufferPrototypeFunction_toStringBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSArrayBufferView>::ClassParameter castedThis)
|
||||
{
|
||||
auto& vm = JSC::getVM(lexicalGlobalObject);
|
||||
@@ -1584,25 +1647,30 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_toStringBody(JSC::JS
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
}
|
||||
|
||||
if (!arg2.isUndefined()) {
|
||||
int32_t istart = arg2.toInt32(lexicalGlobalObject);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
if (istart < 0) {
|
||||
throwTypeError(lexicalGlobalObject, scope, "Start must be a positive integer"_s);
|
||||
return {};
|
||||
}
|
||||
|
||||
start = static_cast<uint32_t>(istart);
|
||||
auto fstart = arg2.toNumber(lexicalGlobalObject);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
if (fstart < 0) {
|
||||
fstart = 0;
|
||||
goto lstart;
|
||||
}
|
||||
if (fstart > byteLength) {
|
||||
return JSC::JSValue::encode(JSC::jsEmptyString(vm));
|
||||
}
|
||||
start = static_cast<uint32_t>(fstart);
|
||||
lstart:
|
||||
|
||||
if (!arg3.isUndefined()) {
|
||||
// length is end
|
||||
end = std::min(byteLength, static_cast<uint32_t>(arg3.toInt32(lexicalGlobalObject)));
|
||||
auto lend = arg3.toLength(lexicalGlobalObject);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
if (lend < byteLength) end = lend;
|
||||
}
|
||||
|
||||
return jsBufferToString(vm, lexicalGlobalObject, castedThis, start, end > start ? end - start : 0, encoding);
|
||||
if (end <= start)
|
||||
return JSC::JSValue::encode(JSC::jsEmptyString(vm));
|
||||
|
||||
auto offset = start;
|
||||
auto length = end > start ? end - start : 0;
|
||||
return jsBufferToString(vm, lexicalGlobalObject, castedThis, offset, length, encoding);
|
||||
}
|
||||
|
||||
// https://github.com/nodejs/node/blob/2eff28fb7a93d3f672f80b582f664a7c701569fb/src/node_buffer.cc#L544
|
||||
@@ -1912,6 +1980,11 @@ JSC_DEFINE_HOST_FUNCTION(jsBufferConstructorFunction_concat, (JSGlobalObject * l
|
||||
return jsBufferConstructorFunction_concatBody(lexicalGlobalObject, callFrame);
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(jsBufferConstructorFunction_copyBytesFrom, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
|
||||
{
|
||||
return jsBufferConstructorFunction_copyBytesFromBody(lexicalGlobalObject, callFrame);
|
||||
}
|
||||
|
||||
extern "C" JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(jsBufferConstructorAllocWithoutTypeChecks, JSUint8Array*, (JSC::JSGlobalObject * lexicalGlobalObject, void* thisValue, int size));
|
||||
extern "C" JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(jsBufferConstructorAllocUnsafeWithoutTypeChecks, JSUint8Array*, (JSC::JSGlobalObject * lexicalGlobalObject, void* thisValue, int size));
|
||||
extern "C" JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(jsBufferConstructorAllocUnsafeSlowWithoutTypeChecks, JSUint8Array*, (JSC::JSGlobalObject * lexicalGlobalObject, void* thisValue, int size));
|
||||
@@ -2228,6 +2301,7 @@ const ClassInfo JSBufferPrototype::s_info = {
|
||||
byteLength jsBufferConstructorFunction_byteLength Function 2
|
||||
compare jsBufferConstructorFunction_compare Function 2
|
||||
concat jsBufferConstructorFunction_concat Function 2
|
||||
copyBytesFrom jsBufferConstructorFunction_copyBytesFrom Function 1
|
||||
from JSBuiltin Builtin|Function 1
|
||||
isBuffer JSBuiltin Builtin|Function 1
|
||||
isEncoding jsBufferConstructorFunction_isEncoding Function 1
|
||||
@@ -2242,6 +2316,7 @@ void JSBufferConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, J
|
||||
Base::finishCreation(vm, 3, "Buffer"_s, PropertyAdditionMode::WithoutStructureTransition);
|
||||
putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
|
||||
prototype->putDirect(vm, vm.propertyNames->speciesSymbol, this, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
|
||||
putDirectWithoutTransition(vm, Identifier::fromString(vm, "poolSize"_s), jsNumber(8192));
|
||||
}
|
||||
|
||||
JSC::Structure* createBufferStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
|
||||
@@ -2278,13 +2353,16 @@ static inline JSC::EncodedJSValue createJSBufferFromJS(JSC::JSGlobalObject* lexi
|
||||
|
||||
if (distinguishingArg.isAnyInt()) {
|
||||
throwScope.release();
|
||||
if (args.at(1).isString()) {
|
||||
return Bun::ERR::INVALID_ARG_TYPE(throwScope, lexicalGlobalObject, "string"_s, "string"_s, distinguishingArg);
|
||||
}
|
||||
return JSBuffer__bufferFromLength(lexicalGlobalObject, distinguishingArg.asAnyInt());
|
||||
} else if (distinguishingArg.isNumber()) {
|
||||
double lengthDouble = distinguishingArg.toIntegerWithTruncation(lexicalGlobalObject);
|
||||
if (UNLIKELY(lengthDouble < 0 || lengthDouble > MAX_ARRAY_BUFFER_SIZE || lengthDouble != lengthDouble)) {
|
||||
return Bun::ERR::OUT_OF_RANGE(throwScope, lexicalGlobalObject, "size"_s, 0, MAX_ARRAY_BUFFER_SIZE, distinguishingArg);
|
||||
}
|
||||
return JSBuffer__bufferFromLength(lexicalGlobalObject, lengthDouble);
|
||||
JSValue lengthValue = distinguishingArg;
|
||||
Bun::V::validateNumber(throwScope, lexicalGlobalObject, lengthValue, jsString(vm, String("size"_s)), jsNumber(0), jsNumber(Bun::Buffer::kMaxLength));
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
size_t length = lengthValue.toLength(lexicalGlobalObject);
|
||||
return JSBuffer__bufferFromLength(lexicalGlobalObject, length);
|
||||
} else if (distinguishingArg.isUndefinedOrNull() || distinguishingArg.isBoolean()) {
|
||||
auto arg_string = distinguishingArg.toWTFString(globalObject);
|
||||
auto message = makeString("The first argument must be of type string or an instance of Buffer, ArrayBuffer, Array or an Array-like object. Received "_s, arg_string);
|
||||
|
||||
@@ -39,6 +39,15 @@ namespace Bun {
|
||||
|
||||
std::optional<double> byteLength(JSC::JSString* str, WebCore::BufferEncodingType encoding);
|
||||
|
||||
namespace Buffer {
|
||||
|
||||
const size_t kMaxLength = MAX_ARRAY_BUFFER_SIZE;
|
||||
const size_t kStringMaxLength = WTF::String::MaxLength;
|
||||
const size_t MAX_LENGTH = MAX_ARRAY_BUFFER_SIZE;
|
||||
const size_t MAX_STRING_LENGTH = WTF::String::MaxLength;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace WebCore {
|
||||
@@ -55,4 +64,4 @@ JSC::JSObject* createBufferPrototype(JSC::VM&, JSC::JSGlobalObject*);
|
||||
JSC::Structure* createBufferStructure(JSC::VM&, JSC::JSGlobalObject*, JSC::JSValue prototype);
|
||||
JSC::JSObject* createBufferConstructor(JSC::VM&, JSC::JSGlobalObject*, JSC::JSObject* bufferPrototype);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,14 +53,17 @@ template<> JSString* convertEnumerationToJS(JSGlobalObject& lexicalGlobalObject,
|
||||
}
|
||||
|
||||
// this function is mostly copied from node
|
||||
template<> std::optional<BufferEncodingType> parseEnumeration<BufferEncodingType>(JSGlobalObject& lexicalGlobalObject, JSValue value)
|
||||
template<> std::optional<BufferEncodingType> parseEnumeration<BufferEncodingType>(JSGlobalObject& lexicalGlobalObject, JSValue arg)
|
||||
{
|
||||
if (UNLIKELY(!arg.isString())) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return parseEnumeration2(lexicalGlobalObject, asString(arg)->getString(&lexicalGlobalObject));
|
||||
}
|
||||
|
||||
std::optional<BufferEncodingType> parseEnumeration2(JSGlobalObject& lexicalGlobalObject, WTF::String encoding)
|
||||
{
|
||||
// caller must check if value is a string
|
||||
JSC::JSString* str = asString(value);
|
||||
if (UNLIKELY(!str))
|
||||
return std::nullopt;
|
||||
|
||||
String encoding = str->value(&lexicalGlobalObject);
|
||||
switch (encoding.length()) {
|
||||
case 0: {
|
||||
return BufferEncodingType::utf8;
|
||||
|
||||
@@ -7,7 +7,8 @@ namespace WebCore {
|
||||
String convertEnumerationToString(BufferEncodingType);
|
||||
template<> JSC::JSString* convertEnumerationToJS(JSC::JSGlobalObject&, BufferEncodingType);
|
||||
|
||||
template<> std::optional<BufferEncodingType> parseEnumeration<BufferEncodingType>(JSC::JSGlobalObject&, JSC::JSValue);
|
||||
template<> std::optional<BufferEncodingType> parseEnumeration<BufferEncodingType>(JSC::JSGlobalObject&, JSValue);
|
||||
std::optional<BufferEncodingType> parseEnumeration2(JSC::JSGlobalObject&, WTF::String);
|
||||
template<> WTF::ASCIILiteral expectedEnumerationValues<BufferEncodingType>();
|
||||
|
||||
} // namespace WebCore
|
||||
} // namespace WebCore
|
||||
|
||||
@@ -69,4 +69,4 @@ public:
|
||||
bool tombstoned { false };
|
||||
};
|
||||
|
||||
} // namespace Zig
|
||||
} // namespace Zig
|
||||
|
||||
@@ -26,4 +26,4 @@ public:
|
||||
HashSet<Ref<JSC::DeferredWorkTimer::TicketData>> m_pendingTicketsOther;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@ namespace Bun {
|
||||
|
||||
JSC::JSValue createJSCTestingHelpers(Zig::GlobalObject* global);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
|
||||
namespace WebCore {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,4 +35,4 @@ JSClass* toJSDOMGlobalObject(JSC::VM& vm, JSC::JSValue value)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,4 +12,4 @@ namespace Bun {
|
||||
|
||||
JSC::JSValue createEnvironmentVariablesMap(Zig::GlobalObject* globalObject);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,4 +37,4 @@ public:
|
||||
bool isEmpty();
|
||||
void drain(JSC::VM& vm, JSC::JSGlobalObject* globalObject);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,4 +71,4 @@ private:
|
||||
JSC::WriteBarrier<JSC::JSFunction> m_wrappedFn;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "ZigGlobalObject.h"
|
||||
|
||||
namespace Bun {
|
||||
|
||||
|
||||
JSC::JSValue createAsyncHooksBinding(Zig::GlobalObject*);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,4 @@ namespace Bun {
|
||||
|
||||
JSC::JSValue createNodeFetchInternalBinding(Zig::GlobalObject*);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "config.h"
|
||||
|
||||
namespace Bun {
|
||||
|
||||
|
||||
JSC_DECLARE_HOST_FUNCTION(jsHTTPAssignHeaders);
|
||||
JSC_DECLARE_HOST_FUNCTION(jsHTTPGetHeader);
|
||||
JSC_DECLARE_HOST_FUNCTION(jsHTTPSetHeader);
|
||||
|
||||
JSC::JSValue createNodeHTTPInternalBinding(Zig::GlobalObject*);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "ZigGlobalObject.h"
|
||||
|
||||
namespace Bun {
|
||||
|
||||
|
||||
JSC::JSValue createNodeTLSBinding(Zig::GlobalObject*);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@ namespace Bun {
|
||||
|
||||
JSC::JSValue createNodeURLBinding(Zig::GlobalObject*);
|
||||
|
||||
} // namespace Bun
|
||||
} // namespace Bun
|
||||
|
||||
@@ -30,10 +30,13 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_validateInteger, (JSC::JSGlobalObject * glob
|
||||
auto name = callFrame->argument(1);
|
||||
auto min = callFrame->argument(2);
|
||||
auto max = callFrame->argument(3);
|
||||
|
||||
return Bun::V::validateInteger(scope, globalObject, value, name, min, max);
|
||||
}
|
||||
JSC::EncodedJSValue V::validateInteger(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSC::JSValue value, JSC::JSValue name, JSC::JSValue min, JSC::JSValue max)
|
||||
{
|
||||
if (!value.isNumber()) return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, name, "number"_s, value);
|
||||
if (min.isUndefined()) min = jsNumber(-9007199254740991); // Number.MIN_SAFE_INTEGER
|
||||
if (max.isUndefined()) max = jsNumber(9007199254740991); // Number.MAX_SAFE_INTEGER
|
||||
if (min.isUndefined()) min = jsDoubleNumber(JSC::minSafeInteger());
|
||||
if (max.isUndefined()) max = jsDoubleNumber(JSC::maxSafeInteger());
|
||||
|
||||
auto value_num = value.asNumber();
|
||||
auto min_num = min.toNumber(globalObject);
|
||||
|
||||
@@ -26,6 +26,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_validateBuffer, (JSC::JSGlobalObject * globa
|
||||
|
||||
namespace V {
|
||||
|
||||
JSC::EncodedJSValue validateInteger(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSC::JSValue value, JSC::JSValue name, JSC::JSValue min, JSC::JSValue max);
|
||||
JSC::EncodedJSValue validateNumber(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSC::JSValue value, JSC::JSValue name, JSC::JSValue min, JSC::JSValue max);
|
||||
JSC::EncodedJSValue validateFiniteNumber(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSC::JSValue number, JSC::JSValue name);
|
||||
JSC::EncodedJSValue validateString(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, JSValue name);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "ZigGlobalObject.h"
|
||||
|
||||
namespace Bun {
|
||||
|
||||
|
||||
JSC::JSValue createNodePathBinding(Zig::GlobalObject* globalObject);
|
||||
|
||||
} // namespace Bun
|
||||
|
||||
@@ -43,11 +43,11 @@ using namespace JSC;
|
||||
static JSValue processBindingConstantsGetOs(VM& vm, JSObject* bindingObject)
|
||||
{
|
||||
auto globalObject = bindingObject->globalObject();
|
||||
auto osObj = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 1);
|
||||
auto dlopenObj = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 1);
|
||||
auto errnoObj = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 1);
|
||||
auto signalsObj = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 1);
|
||||
auto priorityObj = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 1);
|
||||
auto osObj = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
|
||||
auto dlopenObj = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
|
||||
auto errnoObj = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
|
||||
auto signalsObj = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
|
||||
auto priorityObj = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
|
||||
osObj->putDirect(vm, Identifier::fromString(vm, "UV_UDP_REUSEADDR"_s), jsNumber(4));
|
||||
osObj->putDirect(vm, Identifier::fromString(vm, "dlopen"_s), dlopenObj);
|
||||
osObj->putDirect(vm, Identifier::fromString(vm, "errno"_s), errnoObj);
|
||||
@@ -602,7 +602,7 @@ static JSValue processBindingConstantsGetOs(VM& vm, JSObject* bindingObject)
|
||||
static JSValue processBindingConstantsGetTrace(VM& vm, JSObject* bindingObject)
|
||||
{
|
||||
auto globalObject = bindingObject->globalObject();
|
||||
auto object = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 26);
|
||||
auto object = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
|
||||
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "TRACE_EVENT_PHASE_BEGIN"_s)), jsNumber(66));
|
||||
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "TRACE_EVENT_PHASE_END"_s)), jsNumber(69));
|
||||
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "TRACE_EVENT_PHASE_COMPLETE"_s)), jsNumber(88));
|
||||
@@ -635,7 +635,7 @@ static JSValue processBindingConstantsGetTrace(VM& vm, JSObject* bindingObject)
|
||||
static JSValue processBindingConstantsGetFs(VM& vm, JSObject* bindingObject)
|
||||
{
|
||||
auto globalObject = bindingObject->globalObject();
|
||||
auto object = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 26);
|
||||
auto object = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
|
||||
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "UV_FS_SYMLINK_DIR"_s)), jsNumber(1));
|
||||
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "UV_FS_SYMLINK_JUNCTION"_s)), jsNumber(2));
|
||||
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "O_RDONLY"_s)), jsNumber(O_RDONLY));
|
||||
@@ -775,7 +775,7 @@ static JSValue processBindingConstantsGetFs(VM& vm, JSObject* bindingObject)
|
||||
static JSValue processBindingConstantsGetCrypto(VM& vm, JSObject* bindingObject)
|
||||
{
|
||||
auto globalObject = bindingObject->globalObject();
|
||||
auto object = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype());
|
||||
auto object = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
|
||||
#ifdef OPENSSL_VERSION_NUMBER
|
||||
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "OPENSSL_VERSION_NUMBER"_s)), jsNumber(OPENSSL_VERSION_NUMBER));
|
||||
#endif
|
||||
@@ -978,7 +978,7 @@ static JSValue processBindingConstantsGetCrypto(VM& vm, JSObject* bindingObject)
|
||||
static JSValue processBindingConstantsGetZlib(VM& vm, JSObject* bindingObject)
|
||||
{
|
||||
auto globalObject = bindingObject->globalObject();
|
||||
auto object = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype());
|
||||
auto object = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
|
||||
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "Z_NO_FLUSH"_s)), jsNumber(Z_NO_FLUSH));
|
||||
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "Z_PARTIAL_FLUSH"_s)), jsNumber(Z_PARTIAL_FLUSH));
|
||||
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "Z_SYNC_FLUSH"_s)), jsNumber(Z_SYNC_FLUSH));
|
||||
|
||||
@@ -15,4 +15,4 @@ JSC::JSValue createNodeTTYWrapObject(JSC::JSGlobalObject* globalObject);
|
||||
|
||||
JSC_DECLARE_HOST_FUNCTION(Process_functionInternalGetWindowSize);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,4 +10,4 @@ JSC_DECLARE_HOST_FUNCTION(jsGetErrorMap);
|
||||
JSC::JSObject* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject);
|
||||
|
||||
} // namespace ProcessBindingUV
|
||||
} // namespace Bun
|
||||
} // namespace Bun
|
||||
|
||||
@@ -206,4 +206,4 @@ public:
|
||||
|
||||
ScriptExecutionContext* executionContext(JSC::JSGlobalObject*);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,4 +14,4 @@ enum SinkID : uint8_t {
|
||||
static constexpr unsigned numberOfSinkIDs
|
||||
= 7;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,4 +31,4 @@ public:
|
||||
JSC::Strong<JSC::Unknown> m_cell;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ namespace Bun {
|
||||
|
||||
JSC::JSValue createUndiciInternalBinding(Zig::GlobalObject* globalObject);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,4 @@ namespace Bun {
|
||||
|
||||
JSC::Structure* createUtilInspectOptionsStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,6 +172,7 @@ using namespace Bun;
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__NodeUtil__jsParseArgs);
|
||||
BUN_DECLARE_HOST_FUNCTION(BUN__HTTP2__getUnpackedSettings);
|
||||
BUN_DECLARE_HOST_FUNCTION(BUN__HTTP2_getPackedSettings);
|
||||
BUN_DECLARE_HOST_FUNCTION(BUN__HTTP2_assertSettings);
|
||||
|
||||
using JSGlobalObject = JSC::JSGlobalObject;
|
||||
using Exception = JSC::Exception;
|
||||
@@ -276,27 +277,10 @@ extern "C" void* Bun__getVM();
|
||||
|
||||
extern "C" void Bun__setDefaultGlobalObject(Zig::GlobalObject* globalObject);
|
||||
|
||||
// Error.captureStackTrace may cause computeErrorInfo to be called twice
|
||||
// Rather than figure out the plumbing in JSC, we just skip the next call
|
||||
// TODO: thread_local for workers
|
||||
static bool skipNextComputeErrorInfo = false;
|
||||
|
||||
static JSValue formatStackTraceToJSValue(JSC::VM& vm, Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSObject* errorObject, JSC::JSArray* callSites, JSValue prepareStackTrace)
|
||||
static JSValue formatStackTraceToJSValue(JSC::VM& vm, Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSObject* errorObject, JSC::JSArray* callSites)
|
||||
{
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
auto* errorConstructor = lexicalGlobalObject->m_errorStructure.constructor(globalObject);
|
||||
|
||||
if (!prepareStackTrace) {
|
||||
if (lexicalGlobalObject->inherits<Zig::GlobalObject>()) {
|
||||
if (auto prepare = globalObject->m_errorConstructorPrepareStackTraceValue.get()) {
|
||||
prepareStackTrace = prepare;
|
||||
}
|
||||
} else {
|
||||
prepareStackTrace = errorConstructor->getIfPropertyExists(lexicalGlobalObject, JSC::Identifier::fromString(vm, "prepareStackTrace"_s));
|
||||
}
|
||||
}
|
||||
|
||||
// default formatting
|
||||
size_t framesCount = callSites->length();
|
||||
|
||||
@@ -322,21 +306,20 @@ static JSValue formatStackTraceToJSValue(JSC::VM& vm, Zig::GlobalObject* globalO
|
||||
CallSite* callSite = JSC::jsDynamicCast<CallSite*>(callSiteValue);
|
||||
sb.append(" at "_s);
|
||||
callSite->formatAsString(vm, lexicalGlobalObject, sb);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
if (i != framesCount - 1) {
|
||||
sb.append("\n"_s);
|
||||
}
|
||||
}
|
||||
|
||||
bool originalSkipNextComputeErrorInfo = skipNextComputeErrorInfo;
|
||||
skipNextComputeErrorInfo = true;
|
||||
if (errorObject->hasProperty(lexicalGlobalObject, vm.propertyNames->stack)) {
|
||||
skipNextComputeErrorInfo = true;
|
||||
errorObject->deleteProperty(lexicalGlobalObject, vm.propertyNames->stack);
|
||||
}
|
||||
return jsString(vm, sb.toString());
|
||||
}
|
||||
|
||||
skipNextComputeErrorInfo = originalSkipNextComputeErrorInfo;
|
||||
|
||||
JSValue stackStringValue = jsString(vm, sb.toString());
|
||||
static JSValue formatStackTraceToJSValue(JSC::VM& vm, Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSObject* errorObject, JSC::JSArray* callSites, JSValue prepareStackTrace)
|
||||
{
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
auto stackStringValue = formatStackTraceToJSValue(vm, globalObject, lexicalGlobalObject, errorObject, callSites);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
if (prepareStackTrace && prepareStackTrace.isObject()) {
|
||||
JSC::CallData prepareStackTraceCallData = JSC::getCallData(prepareStackTrace);
|
||||
@@ -355,10 +338,10 @@ static JSValue formatStackTraceToJSValue(JSC::VM& vm, Zig::GlobalObject* globalO
|
||||
JSC::ProfilingReason::Other,
|
||||
prepareStackTrace,
|
||||
prepareStackTraceCallData,
|
||||
errorConstructor,
|
||||
lexicalGlobalObject->m_errorStructure.constructor(globalObject),
|
||||
arguments);
|
||||
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
RETURN_IF_EXCEPTION(scope, stackStringValue);
|
||||
|
||||
if (result.isUndefinedOrNull()) {
|
||||
result = jsUndefined();
|
||||
@@ -371,6 +354,26 @@ static JSValue formatStackTraceToJSValue(JSC::VM& vm, Zig::GlobalObject* globalO
|
||||
return stackStringValue;
|
||||
}
|
||||
|
||||
static JSValue formatStackTraceToJSValueWithoutPrepareStackTrace(JSC::VM& vm, Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSObject* errorObject, JSC::JSArray* callSites)
|
||||
{
|
||||
JSValue prepareStackTrace = {};
|
||||
if (lexicalGlobalObject->inherits<Zig::GlobalObject>()) {
|
||||
if (auto prepare = globalObject->m_errorConstructorPrepareStackTraceValue.get()) {
|
||||
prepareStackTrace = prepare;
|
||||
}
|
||||
} else {
|
||||
auto scope = DECLARE_CATCH_SCOPE(vm);
|
||||
|
||||
auto* errorConstructor = lexicalGlobalObject->m_errorStructure.constructor(globalObject);
|
||||
prepareStackTrace = errorConstructor->getIfPropertyExists(lexicalGlobalObject, JSC::Identifier::fromString(vm, "prepareStackTrace"_s));
|
||||
if (scope.exception()) {
|
||||
scope.clearException();
|
||||
}
|
||||
}
|
||||
|
||||
return formatStackTraceToJSValue(vm, globalObject, lexicalGlobalObject, errorObject, callSites, prepareStackTrace);
|
||||
}
|
||||
|
||||
WTF::String Bun::formatStackTrace(
|
||||
JSC::VM& vm,
|
||||
Zig::GlobalObject* globalObject,
|
||||
@@ -467,12 +470,13 @@ WTF::String Bun::formatStackTrace(
|
||||
|
||||
for (size_t i = 0; i < framesCount; i++) {
|
||||
StackFrame& frame = stackTrace.at(i);
|
||||
WTF::String functionName;
|
||||
bool isBuiltinFunction = false;
|
||||
|
||||
sb.append(" at "_s);
|
||||
|
||||
WTF::String functionName;
|
||||
|
||||
if (auto codeblock = frame.codeBlock()) {
|
||||
|
||||
if (codeblock->isConstructor()) {
|
||||
sb.append("new "_s);
|
||||
}
|
||||
@@ -484,11 +488,25 @@ WTF::String Bun::formatStackTrace(
|
||||
case JSC::CodeType::FunctionCode:
|
||||
case JSC::CodeType::EvalCode: {
|
||||
if (auto* callee = frame.callee()) {
|
||||
if (callee->isObject()) {
|
||||
JSValue functionNameValue = callee->getObject()->getDirect(vm, vm.propertyNames->name);
|
||||
if (auto* object = callee->getObject()) {
|
||||
JSValue functionNameValue = object->getDirect(vm, vm.propertyNames->name);
|
||||
if (functionNameValue && functionNameValue.isString()) {
|
||||
functionName = functionNameValue.toWTFString(lexicalGlobalObject);
|
||||
}
|
||||
|
||||
if (functionName.isEmpty()) {
|
||||
auto catchScope = DECLARE_CATCH_SCOPE(vm);
|
||||
functionName = JSC::getCalculatedDisplayName(vm, object);
|
||||
if (catchScope.exception()) {
|
||||
catchScope.clearException();
|
||||
}
|
||||
}
|
||||
|
||||
if (auto* unlinkedCodeBlock = codeblock->unlinkedCodeBlock()) {
|
||||
if (unlinkedCodeBlock->isBuiltinFunction()) {
|
||||
isBuiltinFunction = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -544,8 +562,10 @@ WTF::String Bun::formatStackTrace(
|
||||
}
|
||||
}
|
||||
|
||||
// If it's not a Zig::GlobalObject, don't bother source-mapping it.
|
||||
if (globalObject == lexicalGlobalObject && globalObject) {
|
||||
bool isDefinitelyNotRunninginNodeVMGlobalObject = (globalObject == lexicalGlobalObject && globalObject);
|
||||
|
||||
bool isDefaultGlobalObjectInAFinalizer = (globalObject && !lexicalGlobalObject && !errorInstance);
|
||||
if (isDefinitelyNotRunninginNodeVMGlobalObject || isDefaultGlobalObjectInAFinalizer) {
|
||||
// https://github.com/oven-sh/bun/issues/3595
|
||||
if (!sourceURLForFrame.isEmpty()) {
|
||||
remappedFrame.source_url = Bun::toStringRef(sourceURLForFrame);
|
||||
@@ -572,7 +592,15 @@ WTF::String Bun::formatStackTrace(
|
||||
}
|
||||
|
||||
sb.append(" ("_s);
|
||||
sb.append(sourceURLForFrame);
|
||||
if (sourceURLForFrame.isEmpty()) {
|
||||
if (isBuiltinFunction) {
|
||||
sb.append("native"_s);
|
||||
} else {
|
||||
sb.append("unknown"_s);
|
||||
}
|
||||
} else {
|
||||
sb.append(sourceURLForFrame);
|
||||
}
|
||||
sb.append(":"_s);
|
||||
sb.append(remappedFrame.position.line().oneBasedInt());
|
||||
sb.append(":"_s);
|
||||
@@ -623,16 +651,14 @@ static String computeErrorInfoWithoutPrepareStackTrace(
|
||||
return Bun::formatStackTrace(vm, globalObject, lexicalGlobalObject, name, message, line, column, sourceURL, stackTrace, errorInstance);
|
||||
}
|
||||
|
||||
static String computeErrorInfoWithPrepareStackTrace(JSC::VM& vm, Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, Vector<StackFrame>& stackFrames, OrdinalNumber& line, OrdinalNumber& column, String& sourceURL, JSObject* errorObject, JSObject* prepareStackTrace)
|
||||
static JSValue computeErrorInfoWithPrepareStackTrace(JSC::VM& vm, Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, Vector<StackFrame>& stackFrames, OrdinalNumber& line, OrdinalNumber& column, String& sourceURL, JSObject* errorObject, JSObject* prepareStackTrace)
|
||||
{
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
JSCStackTrace stackTrace = JSCStackTrace::fromExisting(vm, stackFrames);
|
||||
|
||||
// Note: we cannot use tryCreateUninitializedRestricted here because we cannot allocate memory inside initializeIndex()
|
||||
JSC::JSArray* callSites = JSC::JSArray::create(vm,
|
||||
globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
|
||||
stackTrace.size());
|
||||
MarkedArgumentBuffer callSites;
|
||||
|
||||
// Create the call sites (one per frame)
|
||||
GlobalObject::createCallSitesFromFrames(globalObject, lexicalGlobalObject, stackTrace, callSites);
|
||||
@@ -657,7 +683,7 @@ static String computeErrorInfoWithPrepareStackTrace(JSC::VM& vm, Zig::GlobalObje
|
||||
Bun__remapStackFramePositions(globalObject, remappedFrames, framesCount);
|
||||
|
||||
for (size_t i = 0; i < framesCount; i++) {
|
||||
JSC::JSValue callSiteValue = callSites->getIndex(lexicalGlobalObject, i);
|
||||
JSC::JSValue callSiteValue = callSites.at(i);
|
||||
CallSite* callSite = JSC::jsDynamicCast<CallSite*>(callSiteValue);
|
||||
if (remappedFrames[i].remapped) {
|
||||
callSite->setColumnNumber(remappedFrames[i].position.column());
|
||||
@@ -666,64 +692,85 @@ static String computeErrorInfoWithPrepareStackTrace(JSC::VM& vm, Zig::GlobalObje
|
||||
}
|
||||
}
|
||||
|
||||
JSValue value = formatStackTraceToJSValue(vm, jsDynamicCast<Zig::GlobalObject*>(lexicalGlobalObject), lexicalGlobalObject, errorObject, callSites, prepareStackTrace);
|
||||
JSArray* callSitesArray = JSC::constructArray(globalObject, globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous), callSites);
|
||||
|
||||
RETURN_IF_EXCEPTION(scope, String());
|
||||
|
||||
if (errorObject && !value.isEmpty()) {
|
||||
errorObject->putDirect(vm, vm.propertyNames->stack, value, 0);
|
||||
}
|
||||
|
||||
if (value.isString()) {
|
||||
return value.toWTFString(lexicalGlobalObject);
|
||||
}
|
||||
|
||||
return String();
|
||||
return formatStackTraceToJSValue(vm, globalObject, lexicalGlobalObject, errorObject, callSitesArray, prepareStackTrace);
|
||||
}
|
||||
|
||||
static String computeErrorInfo(JSC::VM& vm, Vector<StackFrame>& stackTrace, OrdinalNumber& line, OrdinalNumber& column, String& sourceURL, JSObject* errorInstance)
|
||||
static String computeErrorInfoToString(JSC::VM& vm, Vector<StackFrame>& stackTrace, OrdinalNumber& line, OrdinalNumber& column, String& sourceURL)
|
||||
{
|
||||
if (skipNextComputeErrorInfo) {
|
||||
return String();
|
||||
}
|
||||
|
||||
Zig::GlobalObject* globalObject = nullptr;
|
||||
JSC::JSGlobalObject* lexicalGlobalObject = nullptr;
|
||||
|
||||
if (errorInstance) {
|
||||
lexicalGlobalObject = errorInstance->globalObject();
|
||||
globalObject = jsDynamicCast<Zig::GlobalObject*>(lexicalGlobalObject);
|
||||
return computeErrorInfoWithoutPrepareStackTrace(vm, globalObject, lexicalGlobalObject, stackTrace, line, column, sourceURL, nullptr);
|
||||
}
|
||||
|
||||
// Error.prepareStackTrace - https://v8.dev/docs/stack-trace-api#customizing-stack-traces
|
||||
if (!globalObject) {
|
||||
// node:vm will use a different JSGlobalObject
|
||||
globalObject = defaultGlobalObject();
|
||||
static JSValue computeErrorInfoToJSValueWithoutSkipping(JSC::VM& vm, Vector<StackFrame>& stackTrace, OrdinalNumber& line, OrdinalNumber& column, String& sourceURL, JSObject* errorInstance)
|
||||
{
|
||||
Zig::GlobalObject* globalObject = nullptr;
|
||||
JSC::JSGlobalObject* lexicalGlobalObject = nullptr;
|
||||
|
||||
lexicalGlobalObject = errorInstance->globalObject();
|
||||
globalObject = jsDynamicCast<Zig::GlobalObject*>(lexicalGlobalObject);
|
||||
|
||||
// Error.prepareStackTrace - https://v8.dev/docs/stack-trace-api#customizing-stack-traces
|
||||
if (!globalObject) {
|
||||
// node:vm will use a different JSGlobalObject
|
||||
globalObject = defaultGlobalObject();
|
||||
if (!globalObject->isInsideErrorPrepareStackTraceCallback) {
|
||||
auto* errorConstructor = lexicalGlobalObject->m_errorStructure.constructor(lexicalGlobalObject);
|
||||
if (JSValue prepareStackTrace = errorConstructor->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "prepareStackTrace"_s))) {
|
||||
if (prepareStackTrace.isCell() && prepareStackTrace.isObject() && prepareStackTrace.isCallable()) {
|
||||
return computeErrorInfoWithPrepareStackTrace(vm, globalObject, lexicalGlobalObject, stackTrace, line, column, sourceURL, errorInstance, prepareStackTrace.getObject());
|
||||
globalObject->isInsideErrorPrepareStackTraceCallback = true;
|
||||
auto result = computeErrorInfoWithPrepareStackTrace(vm, globalObject, lexicalGlobalObject, stackTrace, line, column, sourceURL, errorInstance, prepareStackTrace.getObject());
|
||||
globalObject->isInsideErrorPrepareStackTraceCallback = false;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (JSValue prepareStackTrace = globalObject->m_errorConstructorPrepareStackTraceValue.get()) {
|
||||
if (prepareStackTrace.isCell() && prepareStackTrace.isObject() && prepareStackTrace.isCallable()) {
|
||||
return computeErrorInfoWithPrepareStackTrace(vm, globalObject, lexicalGlobalObject, stackTrace, line, column, sourceURL, errorInstance, prepareStackTrace.getObject());
|
||||
}
|
||||
} else if (!globalObject->isInsideErrorPrepareStackTraceCallback) {
|
||||
if (JSValue prepareStackTrace = globalObject->m_errorConstructorPrepareStackTraceValue.get()) {
|
||||
if (prepareStackTrace) {
|
||||
if (prepareStackTrace.isCallable()) {
|
||||
globalObject->isInsideErrorPrepareStackTraceCallback = true;
|
||||
auto result = computeErrorInfoWithPrepareStackTrace(vm, globalObject, lexicalGlobalObject, stackTrace, line, column, sourceURL, errorInstance, prepareStackTrace.getObject());
|
||||
globalObject->isInsideErrorPrepareStackTraceCallback = false;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return computeErrorInfoWithoutPrepareStackTrace(vm, globalObject, lexicalGlobalObject, stackTrace, line, column, sourceURL, errorInstance);
|
||||
String result = computeErrorInfoWithoutPrepareStackTrace(vm, globalObject, lexicalGlobalObject, stackTrace, line, column, sourceURL, errorInstance);
|
||||
return jsString(vm, result);
|
||||
}
|
||||
|
||||
static JSValue computeErrorInfoToJSValue(JSC::VM& vm, Vector<StackFrame>& stackTrace, OrdinalNumber& line, OrdinalNumber& column, String& sourceURL, JSObject* errorInstance)
|
||||
{
|
||||
return computeErrorInfoToJSValueWithoutSkipping(vm, stackTrace, line, column, sourceURL, errorInstance);
|
||||
}
|
||||
|
||||
// TODO: @paperdave: remove this wrapper and make the WTF::Function from JavaScriptCore expect OrdinalNumber instead of unsigned.
|
||||
static String computeErrorInfoWrapper(JSC::VM& vm, Vector<StackFrame>& stackTrace, unsigned int& line_in, unsigned int& column_in, String& sourceURL, JSObject* errorInstance)
|
||||
static String computeErrorInfoWrapperToString(JSC::VM& vm, Vector<StackFrame>& stackTrace, unsigned int& line_in, unsigned int& column_in, String& sourceURL)
|
||||
{
|
||||
OrdinalNumber line = OrdinalNumber::fromOneBasedInt(line_in);
|
||||
OrdinalNumber column = OrdinalNumber::fromOneBasedInt(column_in);
|
||||
|
||||
WTF::String result = computeErrorInfo(vm, stackTrace, line, column, sourceURL, errorInstance);
|
||||
WTF::String result = computeErrorInfoToString(vm, stackTrace, line, column, sourceURL);
|
||||
|
||||
line_in = line.oneBasedInt();
|
||||
column_in = column.oneBasedInt();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static JSValue computeErrorInfoWrapperToJSValue(JSC::VM& vm, Vector<StackFrame>& stackTrace, unsigned int& line_in, unsigned int& column_in, String& sourceURL, JSObject* errorInstance)
|
||||
{
|
||||
OrdinalNumber line = OrdinalNumber::fromOneBasedInt(line_in);
|
||||
OrdinalNumber column = OrdinalNumber::fromOneBasedInt(column_in);
|
||||
|
||||
JSValue result = computeErrorInfoToJSValue(vm, stackTrace, line, column, sourceURL, errorInstance);
|
||||
|
||||
line_in = line.oneBasedInt();
|
||||
column_in = column.oneBasedInt();
|
||||
@@ -820,7 +867,8 @@ extern "C" JSC__JSGlobalObject* Zig__GlobalObject__create(void* console_client,
|
||||
Bun__setDefaultGlobalObject(globalObject);
|
||||
JSC::gcProtect(globalObject);
|
||||
|
||||
vm.setOnComputeErrorInfo(computeErrorInfoWrapper);
|
||||
vm.setOnComputeErrorInfo(computeErrorInfoWrapperToString);
|
||||
vm.setOnComputeErrorInfoJSValue(computeErrorInfoWrapperToJSValue);
|
||||
vm.setOnEachMicrotaskTick([](JSC::VM& vm) -> void {
|
||||
auto* globalObject = defaultGlobalObject();
|
||||
if (auto nextTickQueue = globalObject->m_nextTickQueue.get()) {
|
||||
@@ -2528,7 +2576,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionPerformMicrotaskVariadic, (JSGlobalObject * g
|
||||
return JSValue::encode(jsUndefined());
|
||||
}
|
||||
|
||||
void GlobalObject::createCallSitesFromFrames(Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSCStackTrace& stackTrace, JSC::JSArray* callSites)
|
||||
void GlobalObject::createCallSitesFromFrames(Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSCStackTrace& stackTrace, MarkedArgumentBuffer& callSites)
|
||||
{
|
||||
/* From v8's "Stack Trace API" (https://github.com/v8/v8/wiki/Stack-Trace-API):
|
||||
* "To maintain restrictions imposed on strict mode functions, frames that have a
|
||||
@@ -2543,20 +2591,12 @@ void GlobalObject::createCallSitesFromFrames(Zig::GlobalObject* globalObject, JS
|
||||
|
||||
for (size_t i = 0; i < framesCount; i++) {
|
||||
CallSite* callSite = CallSite::create(lexicalGlobalObject, callSiteStructure, stackTrace.at(i), encounteredStrictFrame);
|
||||
callSites->putDirectIndex(lexicalGlobalObject, i, callSite);
|
||||
|
||||
if (!encounteredStrictFrame) {
|
||||
encounteredStrictFrame = callSite->isStrict();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GlobalObject::formatStackTrace(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSObject* errorObject, JSC::JSArray* callSites, JSValue prepareStackTrace)
|
||||
{
|
||||
JSValue stackTraceValue = formatStackTraceToJSValue(vm, this, lexicalGlobalObject, errorObject, callSites, prepareStackTrace);
|
||||
|
||||
if (!stackTraceValue.isEmpty()) {
|
||||
errorObject->putDirect(vm, vm.propertyNames->stack, stackTraceValue, 0);
|
||||
callSites.append(callSite);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2606,6 +2646,44 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionDefaultErrorPrepareStackTrace, (JSGlobalObjec
|
||||
return JSC::JSValue::encode(result);
|
||||
}
|
||||
|
||||
JSC_DEFINE_CUSTOM_GETTER(errorInstanceLazyStackCustomGetter, (JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, PropertyName))
|
||||
{
|
||||
auto& vm = globalObject->vm();
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
auto* errorObject = jsDynamicCast<ErrorInstance*>(JSValue::decode(thisValue));
|
||||
|
||||
// This shouldn't be possible.
|
||||
if (!errorObject) {
|
||||
return JSValue::encode(jsUndefined());
|
||||
}
|
||||
|
||||
OrdinalNumber line;
|
||||
OrdinalNumber column;
|
||||
String sourceURL;
|
||||
auto stackTrace = errorObject->stackTrace();
|
||||
if (stackTrace == nullptr) {
|
||||
return JSValue::encode(jsUndefined());
|
||||
}
|
||||
|
||||
JSValue result = computeErrorInfoToJSValue(vm, *stackTrace, line, column, sourceURL, errorObject);
|
||||
stackTrace->clear();
|
||||
errorObject->setStackFrames(vm, {});
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
errorObject->putDirect(vm, vm.propertyNames->stack, result, 0);
|
||||
return JSValue::encode(result);
|
||||
}
|
||||
|
||||
JSC_DEFINE_CUSTOM_SETTER(errorInstanceLazyStackCustomSetter, (JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue value, PropertyName))
|
||||
{
|
||||
auto& vm = globalObject->vm();
|
||||
JSValue decodedValue = JSValue::decode(thisValue);
|
||||
if (auto* object = decodedValue.getObject()) {
|
||||
object->putDirect(vm, vm.propertyNames->stack, JSValue::decode(value), 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(errorConstructorFuncCaptureStackTrace, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
|
||||
{
|
||||
GlobalObject* globalObject = reinterpret_cast<GlobalObject*>(lexicalGlobalObject);
|
||||
@@ -2625,56 +2703,30 @@ JSC_DEFINE_HOST_FUNCTION(errorConstructorFuncCaptureStackTrace, (JSC::JSGlobalOb
|
||||
stackTraceLimit = DEFAULT_ERROR_STACK_TRACE_LIMIT;
|
||||
}
|
||||
|
||||
JSCStackTrace stackTrace = JSCStackTrace::captureCurrentJSStackTrace(globalObject, callFrame, stackTraceLimit, caller);
|
||||
WTF::Vector<JSC::StackFrame> stackTrace;
|
||||
JSCStackTrace::getFramesForCaller(vm, callFrame, errorObject, caller, stackTrace, stackTraceLimit);
|
||||
|
||||
// Note: we cannot use tryCreateUninitializedRestricted here because we cannot allocate memory inside initializeIndex()
|
||||
JSC::JSArray* callSites = JSC::JSArray::create(vm,
|
||||
globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
|
||||
stackTrace.size());
|
||||
|
||||
// Create the call sites (one per frame)
|
||||
GlobalObject::createCallSitesFromFrames(globalObject, lexicalGlobalObject, stackTrace, callSites);
|
||||
|
||||
/* Format the stack trace.
|
||||
* Note that v8 won't actually format the stack trace here, but will create a "stack" accessor
|
||||
* on the error object, which will format the stack trace on the first access. For now, since
|
||||
* we're not being used internally by JSC, we can assume callers of Error.captureStackTrace in
|
||||
* node are interested in the (formatted) stack. */
|
||||
|
||||
size_t framesCount = stackTrace.size();
|
||||
ZigStackFrame remappedFrames[64];
|
||||
framesCount = framesCount > 64 ? 64 : framesCount;
|
||||
|
||||
for (int i = 0; i < framesCount; i++) {
|
||||
memset(remappedFrames + i, 0, sizeof(ZigStackFrame));
|
||||
remappedFrames[i].source_url = Bun::toStringRef(lexicalGlobalObject, stackTrace.at(i).sourceURL());
|
||||
if (JSCStackFrame::SourcePositions* sourcePositions = stackTrace.at(i).getSourcePositions()) {
|
||||
remappedFrames[i].position.line_zero_based = sourcePositions->line.zeroBasedInt();
|
||||
remappedFrames[i].position.column_zero_based = sourcePositions->column.zeroBasedInt();
|
||||
} else {
|
||||
remappedFrames[i].position.line_zero_based = -1;
|
||||
remappedFrames[i].position.column_zero_based = -1;
|
||||
if (auto* instance = jsDynamicCast<JSC::ErrorInstance*>(errorObject)) {
|
||||
instance->setStackFrames(vm, WTFMove(stackTrace));
|
||||
if (instance->hasMaterializedErrorInfo()) {
|
||||
const auto& propertyName = vm.propertyNames->stack;
|
||||
VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
|
||||
DeletePropertySlot slot;
|
||||
JSObject::deleteProperty(instance, globalObject, propertyName, slot);
|
||||
if (auto* zigGlobalObject = jsDynamicCast<Zig::GlobalObject*>(globalObject)) {
|
||||
instance->putDirectCustomAccessor(vm, vm.propertyNames->stack, zigGlobalObject->m_lazyStackCustomGetterSetter.get(zigGlobalObject), JSC::PropertyAttribute::CustomAccessor | 0);
|
||||
} else {
|
||||
instance->putDirectCustomAccessor(vm, vm.propertyNames->stack, CustomGetterSetter::create(vm, errorInstanceLazyStackCustomGetter, errorInstanceLazyStackCustomSetter), JSC::PropertyAttribute::CustomAccessor | 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OrdinalNumber line;
|
||||
OrdinalNumber column;
|
||||
String sourceURL;
|
||||
JSValue result = computeErrorInfoToJSValue(vm, stackTrace, line, column, sourceURL, errorObject);
|
||||
errorObject->putDirect(vm, vm.propertyNames->stack, result, 0);
|
||||
}
|
||||
|
||||
// remap line and column start to original source
|
||||
// XXX: this function does not fully populate the fields of ZigStackFrame,
|
||||
// be careful reading the fields below.
|
||||
Bun__remapStackFramePositions(lexicalGlobalObject, remappedFrames, framesCount);
|
||||
|
||||
// write the remapped lines back to the CallSites
|
||||
for (size_t i = 0; i < framesCount; i++) {
|
||||
JSC::JSValue callSiteValue = callSites->getIndex(lexicalGlobalObject, i);
|
||||
CallSite* callSite = JSC::jsDynamicCast<CallSite*>(callSiteValue);
|
||||
if (remappedFrames[i].remapped) {
|
||||
callSite->setColumnNumber(remappedFrames[i].position.column());
|
||||
callSite->setLineNumber(remappedFrames[i].position.line());
|
||||
}
|
||||
}
|
||||
|
||||
globalObject->formatStackTrace(vm, lexicalGlobalObject, errorObject, callSites, JSC::JSValue());
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
return JSC::JSValue::encode(JSC::jsUndefined());
|
||||
}
|
||||
|
||||
@@ -2686,9 +2738,15 @@ void GlobalObject::finishCreation(VM& vm)
|
||||
ASSERT(inherits(info()));
|
||||
|
||||
m_commonStrings.initialize();
|
||||
m_http2_commongStrings.initialize();
|
||||
|
||||
Bun::addNodeModuleConstructorProperties(vm, this);
|
||||
|
||||
m_lazyStackCustomGetterSetter.initLater(
|
||||
[](const Initializer<CustomGetterSetter>& init) {
|
||||
init.set(CustomGetterSetter::create(init.vm, errorInstanceLazyStackCustomGetter, errorInstanceLazyStackCustomSetter));
|
||||
});
|
||||
|
||||
m_JSDOMFileConstructor.initLater(
|
||||
[](const Initializer<JSObject>& init) {
|
||||
JSObject* fileConstructor = Bun::createJSDOMFileConstructor(init.vm, init.owner);
|
||||
@@ -3275,30 +3333,6 @@ JSC_DEFINE_HOST_FUNCTION(functionSetImmediate,
|
||||
return Bun__Timer__setImmediate(globalObject, JSC::JSValue::encode(job), JSValue::encode(arguments));
|
||||
}
|
||||
|
||||
JSValue getEventSourceConstructor(VM& vm, JSObject* thisObject)
|
||||
{
|
||||
auto globalObject = jsCast<Zig::GlobalObject*>(thisObject);
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
JSC::JSFunction* getSourceEvent = JSC::JSFunction::create(vm, globalObject, eventSourceGetEventSourceCodeGenerator(vm), globalObject);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
JSC::MarkedArgumentBuffer args;
|
||||
|
||||
JSC::CallData callData = JSC::getCallData(getSourceEvent);
|
||||
|
||||
NakedPtr<JSC::Exception> returnedException = nullptr;
|
||||
auto result = JSC::call(globalObject, getSourceEvent, callData, globalObject->globalThis(), args, returnedException);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
if (returnedException) {
|
||||
throwException(globalObject, scope, returnedException.get());
|
||||
return jsUndefined();
|
||||
}
|
||||
|
||||
RELEASE_AND_RETURN(scope, result);
|
||||
}
|
||||
|
||||
// `console.Console` or `import { Console } from 'console';`
|
||||
JSC_DEFINE_CUSTOM_GETTER(getConsoleConstructor, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName property))
|
||||
{
|
||||
@@ -3429,6 +3463,7 @@ JSValue GlobalObject_getGlobalThis(VM& vm, JSObject* globalObject)
|
||||
|
||||
void GlobalObject::addBuiltinGlobals(JSC::VM& vm)
|
||||
{
|
||||
auto scope = DECLARE_CATCH_SCOPE(vm);
|
||||
m_builtinInternalFunctions.initialize(*this);
|
||||
|
||||
auto clientData = WebCore::clientData(vm);
|
||||
@@ -3545,6 +3580,8 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm)
|
||||
consoleObject->putDirectCustomAccessor(vm, Identifier::fromString(vm, "Console"_s), CustomGetterSetter::create(vm, getConsoleConstructor, nullptr), PropertyAttribute::CustomValue | 0);
|
||||
consoleObject->putDirectCustomAccessor(vm, Identifier::fromString(vm, "_stdout"_s), CustomGetterSetter::create(vm, getConsoleStdout, nullptr), PropertyAttribute::DontEnum | PropertyAttribute::CustomValue | 0);
|
||||
consoleObject->putDirectCustomAccessor(vm, Identifier::fromString(vm, "_stderr"_s), CustomGetterSetter::create(vm, getConsoleStderr, nullptr), PropertyAttribute::DontEnum | PropertyAttribute::CustomValue | 0);
|
||||
|
||||
scope.assertNoException();
|
||||
}
|
||||
|
||||
extern "C" bool JSC__JSGlobalObject__startRemoteInspector(JSC__JSGlobalObject* globalObject, unsigned char* host, uint16_t arg1)
|
||||
@@ -3575,6 +3612,15 @@ extern "C" void JSC__JSGlobalObject__drainMicrotasks(Zig::GlobalObject* globalOb
|
||||
globalObject->drainMicrotasks();
|
||||
}
|
||||
|
||||
extern "C" EncodedJSValue JSC__JSGlobalObject__getHTTP2CommonString(Zig::GlobalObject* globalObject, uint32_t hpack_index)
|
||||
{
|
||||
auto value = globalObject->http2CommonStrings().getStringFromHPackIndex(hpack_index, globalObject);
|
||||
if (value != nullptr) {
|
||||
return JSValue::encode(value);
|
||||
}
|
||||
return JSValue::encode(JSValue::JSUndefined);
|
||||
}
|
||||
|
||||
template<typename Visitor>
|
||||
void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
|
||||
{
|
||||
@@ -3598,6 +3644,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
|
||||
|
||||
thisObject->m_builtinInternalFunctions.visit(visitor);
|
||||
thisObject->m_commonStrings.visit<Visitor>(visitor);
|
||||
thisObject->m_http2_commongStrings.visit<Visitor>(visitor);
|
||||
visitor.append(thisObject->m_assignToStream);
|
||||
visitor.append(thisObject->m_readableStreamToArrayBuffer);
|
||||
visitor.append(thisObject->m_readableStreamToArrayBufferResolve);
|
||||
@@ -3634,6 +3681,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
|
||||
thisObject->m_JSBufferListClassStructure.visit(visitor);
|
||||
thisObject->m_JSBufferSubclassStructure.visit(visitor);
|
||||
thisObject->m_JSCryptoKey.visit(visitor);
|
||||
thisObject->m_lazyStackCustomGetterSetter.visit(visitor);
|
||||
thisObject->m_JSDOMFileConstructor.visit(visitor);
|
||||
thisObject->m_JSFFIFunctionStructure.visit(visitor);
|
||||
thisObject->m_JSFileSinkClassStructure.visit(visitor);
|
||||
@@ -4026,8 +4074,7 @@ JSC::JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalOb
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
auto moduleKey = key.toWTFString(globalObject);
|
||||
if (UNLIKELY(scope.exception()))
|
||||
return rejectedInternalPromise(globalObject, scope.exception()->value());
|
||||
RETURN_IF_EXCEPTION(scope, rejectedInternalPromise(globalObject, scope.exception()->value()));
|
||||
|
||||
if (moduleKey.endsWith(".node"_s)) {
|
||||
return rejectedInternalPromise(globalObject, createTypeError(globalObject, "To load Node-API modules, use require() or process.dlopen instead of import."_s));
|
||||
@@ -4063,6 +4110,7 @@ JSC::JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalOb
|
||||
&moduleKeyBun,
|
||||
&source,
|
||||
typeAttributeString.isEmpty() ? nullptr : &typeAttribute);
|
||||
RETURN_IF_EXCEPTION(scope, rejectedInternalPromise(globalObject, scope.exception()->value()));
|
||||
|
||||
if (auto* internalPromise = JSC::jsDynamicCast<JSC::JSInternalPromise*>(result)) {
|
||||
return internalPromise;
|
||||
|
||||
@@ -51,6 +51,7 @@ class GlobalInternals;
|
||||
#include "WebCoreJSBuiltins.h"
|
||||
#include "headers-handwritten.h"
|
||||
#include "BunCommonStrings.h"
|
||||
#include "BunHttp2CommonStrings.h"
|
||||
#include "BunGlobalScope.h"
|
||||
|
||||
namespace WebCore {
|
||||
@@ -191,8 +192,7 @@ public:
|
||||
|
||||
void clearDOMGuardedObjects();
|
||||
|
||||
static void createCallSitesFromFrames(Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSCStackTrace& stackTrace, JSC::JSArray* callSites);
|
||||
void formatStackTrace(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSObject* errorObject, JSC::JSArray* callSites, JSValue prepareStack = JSC::jsUndefined());
|
||||
static void createCallSitesFromFrames(Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSCStackTrace& stackTrace, MarkedArgumentBuffer& callSites);
|
||||
|
||||
static void reportUncaughtExceptionAtEventLoop(JSGlobalObject*, JSC::Exception*);
|
||||
static JSGlobalObject* deriveShadowRealmGlobalObject(JSGlobalObject* globalObject);
|
||||
@@ -374,6 +374,8 @@ public:
|
||||
}
|
||||
|
||||
bool asyncHooksNeedsCleanup = false;
|
||||
double INSPECT_MAX_BYTES = 50;
|
||||
bool isInsideErrorPrepareStackTraceCallback = false;
|
||||
|
||||
/**
|
||||
* WARNING: You must update visitChildrenImpl() if you add a new field.
|
||||
@@ -483,7 +485,7 @@ public:
|
||||
JSObject* cryptoObject() const { return m_cryptoObject.getInitializedOnMainThread(this); }
|
||||
JSObject* JSDOMFileConstructor() const { return m_JSDOMFileConstructor.getInitializedOnMainThread(this); }
|
||||
Bun::CommonStrings& commonStrings() { return m_commonStrings; }
|
||||
|
||||
Bun::Http2CommonStrings& http2CommonStrings() { return m_http2_commongStrings; }
|
||||
#include "ZigGeneratedClasses+lazyStructureHeader.h"
|
||||
|
||||
void finishCreation(JSC::VM&);
|
||||
@@ -499,6 +501,7 @@ private:
|
||||
Lock m_gcLock;
|
||||
Ref<WebCore::DOMWrapperWorld> m_world;
|
||||
Bun::CommonStrings m_commonStrings;
|
||||
Bun::Http2CommonStrings m_http2_commongStrings;
|
||||
RefPtr<WebCore::Performance> m_performance { nullptr };
|
||||
|
||||
// JSC's hashtable code-generator tries to access these properties, so we make them public.
|
||||
@@ -584,6 +587,7 @@ public:
|
||||
LazyProperty<JSGlobalObject, JSObject> m_navigatorObject;
|
||||
LazyProperty<JSGlobalObject, JSObject> m_performanceObject;
|
||||
LazyProperty<JSGlobalObject, JSObject> m_processObject;
|
||||
LazyProperty<JSGlobalObject, CustomGetterSetter> m_lazyStackCustomGetterSetter;
|
||||
|
||||
bool hasOverridenModuleResolveFilenameFunction = false;
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
structuredClone functionStructuredClone Function 2
|
||||
|
||||
global GlobalObject_getGlobalThis PropertyCallback
|
||||
EventSource getEventSourceConstructor PropertyCallback
|
||||
|
||||
Bun GlobalObject::m_bunObject CellProperty|DontDelete|ReadOnly
|
||||
File GlobalObject::m_JSDOMFileConstructor CellProperty
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user