diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml deleted file mode 100644 index 96580fb79d..0000000000 --- a/.github/workflows/clang-format.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: clang-format - -permissions: - contents: write - -on: - workflow_call: - workflow_dispatch: - pull_request: - merge_group: - -env: - BUN_VERSION: "1.2.0" - LLVM_VERSION: "19.1.7" - LLVM_VERSION_MAJOR: "19" - -jobs: - clang-format: - name: clang-format - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Setup Bun - uses: ./.github/actions/setup-bun - with: - bun-version: ${{ env.BUN_VERSION }} - - name: Install LLVM - run: | - curl -fsSL https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.LLVM_VERSION_MAJOR }} all - - name: Clang Format - env: - LLVM_VERSION: ${{ env.LLVM_VERSION }} - run: | - bun run clang-format - - name: Commit - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: "`bun run clang-format`" diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml deleted file mode 100644 index b21448ace5..0000000000 --- a/.github/workflows/clang-tidy.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: clang-tidy - -permissions: - contents: write - -on: - workflow_call: - workflow_dispatch: - pull_request: - merge_group: - -env: - BUN_VERSION: "1.2.0" - LLVM_VERSION: "19.1.7" - LLVM_VERSION_MAJOR: "19" - -jobs: - clang-tidy: - name: clang-tidy - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Setup Bun - uses: ./.github/actions/setup-bun - with: - bun-version: ${{ env.BUN_VERSION }} - - name: Install LLVM - run: | - curl -fsSL https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.LLVM_VERSION_MAJOR }} all - - name: Clang Tidy - env: - LLVM_VERSION: ${{ env.LLVM_VERSION }} - run: | - bun run clang-tidy:diff - - name: Commit - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: "`bun run clang-tidy`" diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml new file mode 100644 index 0000000000..528f420eba --- /dev/null +++ b/.github/workflows/format.yml @@ -0,0 +1,65 @@ +name: format + +permissions: + contents: write + +on: + workflow_call: + workflow_dispatch: + pull_request: + merge_group: + +env: + BUN_VERSION: "1.2.11" + LLVM_VERSION: "19.1.7" + LLVM_VERSION_MAJOR: "19" + +jobs: + format: + name: Format + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Configure Git + run: | + git config --global core.autocrlf true + git config --global core.ignorecase true + git config --global core.precomposeUnicode true + - name: Setup Bun + uses: ./.github/actions/setup-bun + with: + bun-version: ${{ env.BUN_VERSION }} + - name: Setup Dependencies + run: | + bun install + - name: Install LLVM + run: | + curl -fsSL https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.LLVM_VERSION_MAJOR }} all + - name: Setup Zig + uses: mlugg/setup-zig@v1 + with: + version: 0.14.0 + - name: Zig Format + run: | + zig fmt src/**.zig + - name: Commit + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "`bun run zig-format`" + - name: Prettier Format + run: | + bun run prettier + - name: Commit + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "`bun run prettier`" + - name: Clang Format + run: | + bun run clang-format + - name: Commit + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "`bun run clang-format`" diff --git a/.github/workflows/prettier-format.yml b/.github/workflows/prettier-format.yml deleted file mode 100644 index 8f0c127202..0000000000 --- a/.github/workflows/prettier-format.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: prettier-format - -permissions: - contents: write - -on: - workflow_call: - workflow_dispatch: - pull_request: - merge_group: - -env: - BUN_VERSION: "1.2.0" - -jobs: - prettier-format: - name: prettier-format - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Setup Bun - uses: ./.github/actions/setup-bun - with: - bun-version: ${{ env.BUN_VERSION }} - - name: Setup Dependencies - run: | - bun install - - name: Prettier Format - run: | - bun run prettier:diff - - name: Commit - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: "`bun run prettier:extra`" diff --git a/.github/workflows/zig-format.yml b/.github/workflows/zig-format.yml deleted file mode 100644 index 199ab83395..0000000000 --- a/.github/workflows/zig-format.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: zig-format - -permissions: - contents: write - -on: - workflow_call: - workflow_dispatch: - pull_request: - merge_group: - -env: - BUN_VERSION: "1.2.0" - -jobs: - zig-format: - name: zig-format - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Setup Bun - uses: ./.github/actions/setup-bun - with: - bun-version: ${{ env.BUN_VERSION }} - - name: Zig Format - run: | - bun run zig-format:diff - - name: Commit - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: "`bun run zig-format`" diff --git a/bun.lock b/bun.lock index 5e7baad5b7..19cb86862c 100644 --- a/bun.lock +++ b/bun.lock @@ -17,7 +17,7 @@ "eslint-config-prettier": "^9.1.0", "mitata": "^0.1.11", "peechy": "0.4.34", - "prettier": "^3.2.5", + "prettier": "^3.5.3", "prettier-plugin-organize-imports": "^4.0.0", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -684,7 +684,7 @@ "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], - "prettier": ["prettier@3.3.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew=="], + "prettier": ["prettier@3.5.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="], "prettier-plugin-organize-imports": ["prettier-plugin-organize-imports@4.1.0", "", { "peerDependencies": { "prettier": ">=2.0", "typescript": ">=2.9", "vue-tsc": "^2.1.0" }, "optionalPeers": ["vue-tsc"] }, "sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A=="], diff --git a/docs/api/binary-data.md b/docs/api/binary-data.md index 3bd0a79cf6..8803765040 100644 --- a/docs/api/binary-data.md +++ b/docs/api/binary-data.md @@ -557,6 +557,7 @@ Buffer.from(buf, 0, 10); #### To `string` As UTF-8: + ```ts new TextDecoder().decode(buf); ``` @@ -638,6 +639,7 @@ Buffer.from(arr); #### To `string` As UTF-8: + ```ts new TextDecoder().decode(arr); ``` @@ -716,6 +718,7 @@ Buffer.from(view.buffer, view.byteOffset, view.byteLength); #### To `string` As UTF-8: + ```ts new TextDecoder().decode(view); ``` @@ -788,16 +791,21 @@ new DataView(buf.buffer, buf.byteOffset, buf.byteLength); #### To `string` As UTF-8: + ```ts buf.toString(); ``` + As base64: + ```ts -buf.toString('base64'); +buf.toString("base64"); ``` + As hex: + ```ts -buf.toString('hex'); +buf.toString("hex"); ``` #### To `number[]` @@ -876,6 +884,7 @@ Buffer.from(await blob.arrayBuffer()); #### To `string` As UTF-8: + ```ts await blob.text(); ``` @@ -962,6 +971,7 @@ Buffer.from(Bun.readableStreamToArrayBuffer(stream)); #### To `string` As UTF-8: + ```ts // with Response await new Response(stream).text(); diff --git a/docs/api/dns.md b/docs/api/dns.md index 4553263fab..5cb50ee549 100644 --- a/docs/api/dns.md +++ b/docs/api/dns.md @@ -10,7 +10,7 @@ console.log(addrs); ## DNS caching in Bun -In Bun v1.1.9, we added support for DNS caching. This cache makes repeated connections to the same hosts faster. +In Bun v1.1.9, we added support for DNS caching. This cache makes repeated connections to the same hosts faster. 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. @@ -27,10 +27,10 @@ This cache is automatically used by: Web browsers expose [``](https://developer.mozilla.org/en-US/docs/Web/Performance/dns-prefetch) to allow developers to prefetch DNS entries. This is useful when you know you'll need to connect to a host in the near future and want to avoid the initial DNS lookup. -In Bun, you can use the `dns.prefetch` API to achieve the same effect. +In Bun, you can use the `dns.prefetch` API to achieve the same effect. ```ts -import {dns} from "bun"; +import { dns } from "bun"; dns.prefetch("my.database-host.com", 5432); ``` @@ -52,7 +52,7 @@ dns.prefetch(hostname: string, port: number): void; Here's an example: ```ts -import {dns} from "bun"; +import { dns } from "bun"; dns.prefetch("bun.sh", 443); // @@ -66,13 +66,13 @@ await fetch("https://bun.sh"); **🚧** — This API is experimental and may change in the future. {% /callout %} -To get the current cache stats, you can use the `dns.getCacheStats` API. +To get the current cache stats, you can use the `dns.getCacheStats` API. This API returns an object with the following properties: ```ts { - // Cache hits + // Cache hits cacheHitsCompleted: number; cacheHitsInflight: number; cacheMisses: number; @@ -90,7 +90,7 @@ This API returns an object with the following properties: Example: ```ts -import {dns} from "bun"; +import { dns } from "bun"; const stats = dns.getCacheStats(); console.log(stats); @@ -107,7 +107,4 @@ BUN_CONFIG_DNS_TIME_TO_LIVE_SECONDS=5 bun run my-script.ts #### Why is 30 seconds the default? -Unfortunately, the system API underneath (`getaddrinfo`) does not provide a way to get the TTL of a DNS entry. This means we have to pick a number arbitrarily. We chose 30 seconds because it's long enough to see the benefits of caching, and short enough to be unlikely to cause issues if a DNS entry changes. [Amazon Web Services recommends 5 seconds](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/jvm-ttl-dns.html) for the Java Virtual Machine, however the JVM defaults to cache indefinitely. - - - +Unfortunately, the system API underneath (`getaddrinfo`) does not provide a way to get the TTL of a DNS entry. This means we have to pick a number arbitrarily. We chose 30 seconds because it's long enough to see the benefits of caching, and short enough to be unlikely to cause issues if a DNS entry changes. [Amazon Web Services recommends 5 seconds](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/jvm-ttl-dns.html) for the Java Virtual Machine, however the JVM defaults to cache indefinitely. diff --git a/docs/api/file-io.md b/docs/api/file-io.md index 1f8e9468bf..f8e3102783 100644 --- a/docs/api/file-io.md +++ b/docs/api/file-io.md @@ -67,7 +67,7 @@ Bun.stderr; You can delete a file by calling the `.delete()` function. ```ts -await Bun.file("logs.json").delete() +await Bun.file("logs.json").delete(); ``` ## Writing files (`Bun.write()`) diff --git a/docs/api/s3.md b/docs/api/s3.md index 04c054317c..857e77ab49 100644 --- a/docs/api/s3.md +++ b/docs/api/s3.md @@ -638,14 +638,10 @@ const credentials = { await S3Client.write("my-file.txt", "Hello World"); // Write JSON with type -await S3Client.write( - "data.json", - JSON.stringify({hello: "world"}), - { - ...credentials, - type: "application/json", - } -); +await S3Client.write("data.json", JSON.stringify({ hello: "world" }), { + ...credentials, + type: "application/json", +}); // Write from fetch const res = await fetch("https://example.com/data"); @@ -655,7 +651,7 @@ await S3Client.write("data.bin", res, credentials); await S3Client.write("public.html", html, { ...credentials, acl: "public-read", - type: "text/html" + type: "text/html", }); ``` diff --git a/docs/api/streams.md b/docs/api/streams.md index 816b94dc8d..06b6ae72e2 100644 --- a/docs/api/streams.md +++ b/docs/api/streams.md @@ -61,10 +61,12 @@ When using a direct `ReadableStream`, all chunk queueing is handled by the desti Bun also supports async generator functions as a source for `Response` and `Request`. This is an easy way to create a `ReadableStream` that fetches data from an asynchronous source. ```ts -const response = new Response(async function* () { - yield "hello"; - yield "world"; -}()); +const response = new Response( + (async function* () { + yield "hello"; + yield "world"; + })(), +); await response.text(); // "helloworld" ``` diff --git a/docs/api/udp.md b/docs/api/udp.md index 7defcd9e57..e5d58323d1 100644 --- a/docs/api/udp.md +++ b/docs/api/udp.md @@ -5,15 +5,16 @@ Use Bun's UDP API to implement services with advanced real-time requirements, su To create a new (bound) UDP socket: ```ts -const socket = await Bun.udpSocket({}) +const socket = await Bun.udpSocket({}); console.log(socket.port); // assigned by the operating system ``` Specify a port: + ```ts const socket = await Bun.udpSocket({ - port: 41234 -}) + port: 41234, +}); console.log(socket.port); // 41234 ``` @@ -28,7 +29,6 @@ socket.send("Hello, world!", 41234, "127.0.0.1"); Note that the address must be a valid IP address - `send` does not perform DNS resolution, as it is intended for low-latency operations. - ### Receive datagrams When creating your socket, add a callback to specify what should be done when packets are received: @@ -37,11 +37,11 @@ When creating your socket, add a callback to specify what should be done when pa const server = await Bun.udpSocket({ socket: { data(socket, buf, port, addr) { - console.log(`message from ${addr}:${port}:`) + console.log(`message from ${addr}:${port}:`); console.log(buf.toString()); - } - } -}) + }, + }, +}); const client = await Bun.udpSocket({}); client.send("Hello!", server.port, "127.0.0.1"); @@ -54,29 +54,26 @@ In such cases it can be beneficial to connect the socket to that peer, which spe and restricts incoming packets to that peer only. ```ts - const server = await Bun.udpSocket({ socket: { data(socket, buf, port, addr) { - console.log(`message from ${addr}:${port}:`) + console.log(`message from ${addr}:${port}:`); console.log(buf.toString()); - } - } -}) + }, + }, +}); const client = await Bun.udpSocket({ connect: { port: server.port, - hostname: '127.0.0.1', - } + hostname: "127.0.0.1", + }, }); client.send("Hello"); - ``` Because connections are implemented on the operating system level, you can potentially observe performance benefits, too. - ### Send many packets at once using `sendMany()` If you want to send a large volume of packets at once, it can make sense to batch them all together to avoid the overhead @@ -86,9 +83,9 @@ For an unconnected socket, `sendMany` takes an array as its only argument. Each The first item is the data to be sent, the second is the target port, and the last is the target address. ```ts -const socket = await Bun.udpSocket({}) +const socket = await Bun.udpSocket({}); // sends 'Hello' to 127.0.0.1:41234, and 'foo' to 1.1.1.1:53 in a single operation -socket.sendMany(['Hello', 41234, '127.0.0.1', 'foo', 53, '1.1.1.1']) +socket.sendMany(["Hello", 41234, "127.0.0.1", "foo", 53, "1.1.1.1"]); ``` With a connected socket, `sendMany` simply takes an array, where each element represents the data to be sent to the peer. @@ -97,10 +94,10 @@ With a connected socket, `sendMany` simply takes an array, where each element re const socket = await Bun.udpSocket({ connect: { port: 41234, - hostname: 'localhost', - } + hostname: "localhost", + }, }); -socket.sendMany(['foo', 'bar', 'baz']); +socket.sendMany(["foo", "bar", "baz"]); ``` `sendMany` returns the number of packets that were successfully sent. As with `send`, `sendMany` only takes valid IP addresses @@ -110,16 +107,17 @@ as destinations, as it does not perform DNS resolution. It may happen that a packet that you're sending does not fit into the operating system's packet buffer. You can detect that this has happened when: -- `send` returns `false` + +- `send` returns `false` - `sendMany` returns a number smaller than the number of packets you specified -In this case, the `drain` socket handler will be called once the socket becomes writable again: + In this case, the `drain` socket handler will be called once the socket becomes writable again: ```ts const socket = await Bun.udpSocket({ socket: { drain(socket) { // continue sending data - } - } + }, + }, }); ``` diff --git a/docs/bundler/index.md b/docs/bundler/index.md index 5ca8059472..73987cc472 100644 --- a/docs/bundler/index.md +++ b/docs/bundler/index.md @@ -1630,4 +1630,4 @@ declare class ResolveMessage { } ``` -{% bunCLIUsage command="build" /%} \ No newline at end of file +{% bunCLIUsage command="build" /%} diff --git a/docs/bundler/macros.md b/docs/bundler/macros.md index 78fb27d0d7..14001a1c86 100644 --- a/docs/bundler/macros.md +++ b/docs/bundler/macros.md @@ -71,7 +71,7 @@ node_modules/evil/index.js:3:1 50 Your application code can still import macros from `node_modules` and invoke them. ```ts -import {macro} from "some-package" with { type: "macro" }; +import { macro } from "some-package" with { type: "macro" }; macro(); ``` @@ -95,8 +95,8 @@ When shipping a library containing a macro to `npm` or another package registry, With this configuration, users can consume your package at runtime or at bundle-time using the same import specifier: ```ts -import pkg from "my-package"; // runtime import -import {macro} from "my-package" with { type: "macro" }; // macro import +import pkg from "my-package"; // runtime import +import { macro } from "my-package" with { type: "macro" }; // macro import ``` The first import will resolve to `./node_modules/my-package/index.js`, while the second will be resolved by Bun's bundler to `./node_modules/my-package/index.macro.js`. @@ -122,7 +122,7 @@ export function returnFalse() { ...then bundling the following file will produce an empty bundle, provided that the minify syntax option is enabled. ```ts -import {returnFalse} from './returnFalse.ts' with { type: 'macro' }; +import { returnFalse } from "./returnFalse.ts" with { type: "macro" }; if (returnFalse()) { console.log("This code is eliminated"); @@ -179,7 +179,7 @@ export function getText(url: string) { Macros can accept inputs, but only in limited cases. The value must be statically known. For example, the following is not allowed: ```ts -import {getText} from './getText.ts' with { type: 'macro' }; +import { getText } from "./getText.ts" with { type: "macro" }; export function howLong() { // the value of `foo` cannot be statically known @@ -193,8 +193,8 @@ export function howLong() { However, if the value of `foo` is known at bundle-time (say, if it's a constant or the result of another macro) then it's allowed: ```ts -import {getText} from './getText.ts' with { type: 'macro' }; -import {getFoo} from './getFoo.ts' with { type: 'macro' }; +import { getText } from "./getText.ts" with { type: "macro" }; +import { getFoo } from "./getFoo.ts" with { type: "macro" }; export function howLong() { // this works because getFoo() is statically known @@ -271,7 +271,9 @@ export async function extractMetaTags(url: string) { .on("meta", { element(element) { const name = - element.getAttribute("name") || element.getAttribute("property") || element.getAttribute("itemprop"); + element.getAttribute("name") || + element.getAttribute("property") || + element.getAttribute("itemprop"); if (name) meta[name] = element.getAttribute("content"); }, diff --git a/docs/cli/add.md b/docs/cli/add.md index 72c5cb25d6..edc2732c3f 100644 --- a/docs/cli/add.md +++ b/docs/cli/add.md @@ -63,8 +63,8 @@ This will add the following to your `package.json`: "react": "^18.2.0", // this matches >= 18.2.0 < 19.0.0 // with --exact - "react": "18.2.0" // this matches only 18.2.0 exactly - } + "react": "18.2.0", // this matches only 18.2.0 exactly + }, } ``` @@ -170,4 +170,4 @@ This will add the following line to your `package.json`: } ``` -{% bunCLIUsage command="add" /%} \ No newline at end of file +{% bunCLIUsage command="add" /%} diff --git a/docs/cli/link.md b/docs/cli/link.md index 5db0a1e0d9..cc11038c6f 100644 --- a/docs/cli/link.md +++ b/docs/cli/link.md @@ -37,4 +37,4 @@ In addition, the `--save` flag can be used to add `cool-pkg` to the `dependencie } ``` -{% bunCLIUsage command="link" /%} \ No newline at end of file +{% bunCLIUsage command="link" /%} diff --git a/docs/cli/patch-commit.md b/docs/cli/patch-commit.md index ba01baefa3..c9780ec9d1 100644 --- a/docs/cli/patch-commit.md +++ b/docs/cli/patch-commit.md @@ -8,4 +8,4 @@ By default, `bun patch-commit` will use the `patches` directory in the temporary You can specify a different directory with the `--patches-dir` flag. -{% bunCLIUsage command="patch-commit" /%} \ No newline at end of file +{% bunCLIUsage command="patch-commit" /%} diff --git a/docs/cli/run.md b/docs/cli/run.md index bf3e16add0..996dc4d5a0 100644 --- a/docs/cli/run.md +++ b/docs/cli/run.md @@ -206,4 +206,4 @@ When there is a package.json script and a file with the same name, `bun run` pri 3. Binaries from project packages, eg `bun add eslint && bun run eslint` 4. (`bun run` only) System commands, eg `bun run ls` -{% bunCLIUsage command="run" /%} \ No newline at end of file +{% bunCLIUsage command="run" /%} diff --git a/docs/cli/update.md b/docs/cli/update.md index 93ec2191fc..3dddfbaf51 100644 --- a/docs/cli/update.md +++ b/docs/cli/update.md @@ -33,4 +33,4 @@ For example, with the following `package.json`: - `bun update` would update to a version that matches `17.x`. - `bun update --latest` would update to a version that matches `18.x` or later. -{% bunCLIUsage command="update" /%} \ No newline at end of file +{% bunCLIUsage command="update" /%} diff --git a/docs/ecosystem/stric.md b/docs/ecosystem/stric.md index 5f2787d75d..bba1b0ae23 100644 --- a/docs/ecosystem/stric.md +++ b/docs/ecosystem/stric.md @@ -9,7 +9,7 @@ export default new Router() .get('/', () => new Response('Hi')); ``` -Stric provides support for [ArrowJS](https://www.arrow-js.com), a library for building reactive interfaces. +Stric provides support for [ArrowJS](https://www.arrow-js.com), a library for building reactive interfaces. {% codetabs %} @@ -25,6 +25,7 @@ export function render() { // Set the path to handle export const path = '/'; ``` + ```ts#index.ts import { PageRouter } from '@stricjs/arrow'; diff --git a/docs/guides/ecosystem/neon-drizzle.md b/docs/guides/ecosystem/neon-drizzle.md index d17ac150e6..1d24aaebd9 100644 --- a/docs/guides/ecosystem/neon-drizzle.md +++ b/docs/guides/ecosystem/neon-drizzle.md @@ -2,9 +2,9 @@ name: Use Neon Postgres through Drizzle ORM --- -[Neon](https://neon.tech/) is a fully managed serverless Postgres, separating compute and storage to offer features like autoscaling, branching and bottomless storage. Neon can be used from Bun directly using the `@neondatabase/serverless` driver or through an ORM like `Drizzle`. +[Neon](https://neon.tech/) is a fully managed serverless Postgres, separating compute and storage to offer features like autoscaling, branching and bottomless storage. Neon can be used from Bun directly using the `@neondatabase/serverless` driver or through an ORM like `Drizzle`. -Drizzle ORM supports both a SQL-like "query builder" API and an ORM-like [Queries API](https://orm.drizzle.team/docs/rqb). Get started by creating a project directory, initializing the directory using `bun init`, and installing Drizzle and the [Neon serverless driver](https://github.com/neondatabase/serverless/). +Drizzle ORM supports both a SQL-like "query builder" API and an ORM-like [Queries API](https://orm.drizzle.team/docs/rqb). Get started by creating a project directory, initializing the directory using `bun init`, and installing Drizzle and the [Neon serverless driver](https://github.com/neondatabase/serverless/). ```sh $ mkdir bun-drizzle-neon @@ -52,7 +52,7 @@ console.log(result.rows); --- -Then run `index.ts` with Bun. +Then run `index.ts` with Bun. ```sh $ bun run index.ts @@ -65,7 +65,7 @@ $ bun run index.ts --- -We can define a schema for our database using Drizzle ORM primitives. Create a `schema.ts` file and add this code. +We can define a schema for our database using Drizzle ORM primitives. Create a `schema.ts` file and add this code. ```ts#schema.ts import { pgTable, integer, serial, text, timestamp } from "drizzle-orm/pg-core"; @@ -215,6 +215,6 @@ $ bun run index.ts --- -This example used the Neon serverless driver's SQL-over-HTTP functionality. Neon's serverless driver also exposes `Client` and `Pool` constructors to enable sessions, interactive transactions, and node-postgres compatibility. Refer to [Neon's documentation](https://neon.tech/docs/serverless/serverless-driver) for a complete overview. +This example used the Neon serverless driver's SQL-over-HTTP functionality. Neon's serverless driver also exposes `Client` and `Pool` constructors to enable sessions, interactive transactions, and node-postgres compatibility. Refer to [Neon's documentation](https://neon.tech/docs/serverless/serverless-driver) for a complete overview. Refer to the [Drizzle website](https://orm.drizzle.team/docs/overview) for more documentation on using the Drizzle ORM. diff --git a/docs/guides/ecosystem/pm2.md b/docs/guides/ecosystem/pm2.md index 87ed5c57f7..41a06b7bd1 100644 --- a/docs/guides/ecosystem/pm2.md +++ b/docs/guides/ecosystem/pm2.md @@ -40,7 +40,7 @@ module.exports = { interpreter: "bun", // Bun interpreter env: { PATH: `${process.env.HOME}/.bun/bin:${process.env.PATH}`, // Add "~/.bun/bin/bun" to PATH - } + }, }; ``` diff --git a/docs/guides/ecosystem/sveltekit.md b/docs/guides/ecosystem/sveltekit.md index 38824a5775..61e0c3b31c 100644 --- a/docs/guides/ecosystem/sveltekit.md +++ b/docs/guides/ecosystem/sveltekit.md @@ -52,9 +52,9 @@ $ cd my-app $ bun --bun run dev $ vite dev Forced re-optimization of dependencies - + VITE v5.4.10 ready in 424 ms - + ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose ➜ press h + enter to show help @@ -88,7 +88,7 @@ Now, make the following changes to your `svelte.config.js`. // Consult https://svelte.dev/docs/kit/integrations#preprocessors // for more information about preprocessors preprocess: vitePreprocess(), - + kit: { // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list. // If your environment is not supported, or you settled on a specific environment, switch out the adapter. @@ -96,7 +96,7 @@ Now, make the following changes to your `svelte.config.js`. adapter: adapter() } }; - + export default config; ``` @@ -116,9 +116,9 @@ $ bun --bun run build ✓ built in 231ms ... ✓ built in 899ms - + Run npm run preview to preview your production build locally. - + > Using svelte-adapter-bun ✔ Start server with: bun ./build/index.js ✔ done diff --git a/docs/guides/install/add-peer.md b/docs/guides/install/add-peer.md index 0018cd1771..3b06b01f33 100644 --- a/docs/guides/install/add-peer.md +++ b/docs/guides/install/add-peer.md @@ -2,7 +2,6 @@ name: Add a peer dependency --- - To add an npm package as a peer dependency, use the `--peer` flag. ```sh diff --git a/docs/guides/process/argv.md b/docs/guides/process/argv.md index 88398a6471..7e3a60e564 100644 --- a/docs/guides/process/argv.md +++ b/docs/guides/process/argv.md @@ -56,4 +56,3 @@ $ bun run cli.ts --flag1 --flag2 value } [ "/path/to/bun", "/path/to/cli.ts" ] ``` - diff --git a/docs/guides/runtime/set-env.md b/docs/guides/runtime/set-env.md index 2b36218af2..ef10c12bcc 100644 --- a/docs/guides/runtime/set-env.md +++ b/docs/guides/runtime/set-env.md @@ -42,7 +42,6 @@ $ set FOO=helloworld && bun run dev $ $env:FOO="helloworld"; bun run dev ``` -{% /codetabs %} ---- +## {% /codetabs %} See [Docs > Runtime > Environment variables](https://bun.sh/docs/runtime/env) for more information on using environment variables with Bun. diff --git a/docs/guides/test/testing-library.md b/docs/guides/test/testing-library.md index b78ccc8457..3c3e4e9157 100644 --- a/docs/guides/test/testing-library.md +++ b/docs/guides/test/testing-library.md @@ -1,9 +1,11 @@ --- name: Using Testing Library with Bun --- + You can use [Testing Library](https://testing-library.com/) with Bun's test runner. --- + As a prerequisite to using Testing Library you will need to install [Happy Dom](https://github.com/capricorn86/happy-dom). ([see Bun's Happy DOM guide for more information](https://bun.sh/guides/test/happy-dom)). ```sh @@ -17,6 +19,7 @@ Next you should install the Testing Library packages you are planning on using. ```sh bun add -D @testing-library/react @testing-library/dom @testing-library/jest-dom ``` + --- Next you will need to create a preload script for Happy DOM and for Testing Library. For more details about the Happy DOM setup script see [Bun's Happy DOM guide](https://bun.sh/guides/test/happy-dom). @@ -26,6 +29,7 @@ import { GlobalRegistrator } from '@happy-dom/global-registrator'; GlobalRegistrator.register(); ``` + --- For Testing Library, you will want to extend Bun's `expect` function with Testing Library's matchers. Optionally, to better match the behavior of test-runners like Jest, you may want to run cleanup after each test. @@ -51,6 +55,7 @@ Next, add these preload scripts to your `bunfig.toml` (you can also have everyth [test] preload = ["./happydom.ts", "./testing-library.ts"] ``` + --- If you are using TypeScript you will also need to make use of declaration merging in order to get the new matcher types to show up in your editor. To do this, create a type declaration file that extends `Matchers` like this. @@ -71,15 +76,15 @@ declare module 'bun:test' { You should now be able to use Testing Library in your tests ```ts -import { test, expect } from 'bun:test'; -import { screen, render } from '@testing-library/react'; -import { MyComponent } from './myComponent'; +import { test, expect } from "bun:test"; +import { screen, render } from "@testing-library/react"; +import { MyComponent } from "./myComponent"; -test('Can use Testing Library', () => { +test("Can use Testing Library", () => { render(MyComponent); - const myComponent = screen.getByTestId('my-component'); + const myComponent = screen.getByTestId("my-component"); expect(myComponent).toBeInTheDocument(); -}) +}); ``` --- diff --git a/docs/install/patch.md b/docs/install/patch.md index e9dcc13efc..ea076376cd 100644 --- a/docs/install/patch.md +++ b/docs/install/patch.md @@ -56,4 +56,4 @@ $ bun patch --commit react --patches-dir=mypatches $ bun patch-commit react ``` -{% bunCLIUsage command="patch" /%} \ No newline at end of file +{% bunCLIUsage command="patch" /%} diff --git a/docs/runtime/bunfig.md b/docs/runtime/bunfig.md index 01c2843f36..6d541ca325 100644 --- a/docs/runtime/bunfig.md +++ b/docs/runtime/bunfig.md @@ -198,7 +198,6 @@ Set path where coverage reports will be saved. Please notice, that it works only coverageDir = "path/to/somewhere" # default "coverage" ``` - ## Package manager Package management is a complex issue; to support a range of use cases, the behavior of `bun install` can be configured under the `[install]` section. diff --git a/docs/runtime/hot.md b/docs/runtime/hot.md index f5c1549364..dc929bf34b 100644 --- a/docs/runtime/hot.md +++ b/docs/runtime/hot.md @@ -69,7 +69,6 @@ The **`--no-clear-screen`** flag is useful in scenarios where you don’t want t {% /callout %} - ## `--hot` mode Use `bun --hot` to enable hot reloading when executing code with Bun. This is distinct from `--watch` mode in that Bun does not hard-restart the entire process. Instead, it detects code changes and updates its internal module cache with the new code. diff --git a/docs/test/mocks.md b/docs/test/mocks.md index f450b59a5a..cad3331656 100644 --- a/docs/test/mocks.md +++ b/docs/test/mocks.md @@ -206,11 +206,13 @@ Understanding how `mock.module()` works helps you use it more effectively: 2. **Lazy Evaluation**: The mock factory callback is only evaluated when the module is actually imported or required. 3. **Path Resolution**: Bun automatically resolves the module specifier as though you were doing an import, supporting: + - Relative paths (`'./module'`) - Absolute paths (`'/path/to/module'`) - Package names (`'lodash'`) -4. **Import Timing Effects**: +4. **Import Timing Effects**: + - When mocking before first import: No side effects from the original module occur - When mocking after import: The original module's side effects have already happened - For this reason, using `--preload` is recommended for mocks that need to prevent side effects @@ -232,15 +234,15 @@ const random2 = mock(() => Math.random()); test("clearing all mocks", () => { random1(); random2(); - + expect(random1).toHaveBeenCalledTimes(1); expect(random2).toHaveBeenCalledTimes(1); - + mock.clearAllMocks(); - + expect(random1).toHaveBeenCalledTimes(0); expect(random2).toHaveBeenCalledTimes(0); - + // Note: implementations are preserved expect(typeof random1()).toBe("number"); expect(typeof random2()).toBe("number"); @@ -258,18 +260,18 @@ Using `mock.restore()` can reduce the amount of code in your tests by adding it ```ts import { expect, mock, spyOn, test } from "bun:test"; -import * as fooModule from './foo.ts'; -import * as barModule from './bar.ts'; -import * as bazModule from './baz.ts'; +import * as fooModule from "./foo.ts"; +import * as barModule from "./bar.ts"; +import * as bazModule from "./baz.ts"; -test('foo, bar, baz', () => { - const fooSpy = spyOn(fooModule, 'foo'); - const barSpy = spyOn(barModule, 'bar'); - const bazSpy = spyOn(bazModule, 'baz'); +test("foo, bar, baz", () => { + const fooSpy = spyOn(fooModule, "foo"); + const barSpy = spyOn(barModule, "bar"); + const bazSpy = spyOn(bazModule, "baz"); - expect(fooSpy).toBe('foo'); - expect(barSpy).toBe('bar'); - expect(bazSpy).toBe('baz'); + expect(fooSpy).toBe("foo"); + expect(barSpy).toBe("bar"); + expect(bazSpy).toBe("baz"); fooSpy.mockImplementation(() => 42); barSpy.mockImplementation(() => 43); @@ -281,9 +283,9 @@ test('foo, bar, baz', () => { mock.restore(); - expect(fooSpy).toBe('foo'); - expect(barSpy).toBe('bar'); - expect(bazSpy).toBe('baz'); + expect(fooSpy).toBe("foo"); + expect(barSpy).toBe("bar"); + expect(bazSpy).toBe("baz"); }); ``` @@ -297,10 +299,10 @@ import { test, expect } from "bun:test"; // Using the 'vi' alias similar to Vitest test("vitest compatibility", () => { const mockFn = vi.fn(() => 42); - + mockFn(); expect(mockFn).toHaveBeenCalled(); - + // The following functions are available on the vi object: // vi.fn // vi.spyOn diff --git a/docs/test/time.md b/docs/test/time.md index e883a91b31..be865a151c 100644 --- a/docs/test/time.md +++ b/docs/test/time.md @@ -84,10 +84,10 @@ import { test, expect, jest } from "bun:test"; test("get the current mocked time", () => { jest.useFakeTimers(); jest.setSystemTime(new Date("2020-01-01T00:00:00.000Z")); - + expect(Date.now()).toBe(1577836800000); // Jan 1, 2020 timestamp expect(jest.now()).toBe(1577836800000); // Same value - + jest.useRealTimers(); }); ``` diff --git a/package.json b/package.json index d586492866..470530805c 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "eslint-config-prettier": "^9.1.0", "mitata": "^0.1.11", "peechy": "0.4.34", - "prettier": "^3.2.5", + "prettier": "^3.5.3", "prettier-plugin-organize-imports": "^4.0.0", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -78,11 +78,7 @@ "clang-tidy:diff": "bun run analysis --target clang-tidy-diff", "zig-format": "bun run analysis:no-llvm --target zig-format", "zig-format:check": "bun run analysis:no-llvm --target zig-format-check", - "zig-format:diff": "bun run analysis:no-llvm --target zig-format-diff", - "prettier": "bun run analysis:no-llvm --target prettier", - "prettier:check": "bun run analysis:no-llvm --target prettier-check", - "prettier:extra": "bun run analysis:no-llvm --target prettier-extra", - "prettier:diff": "bun run analysis:no-llvm --target prettier-diff", + "prettier": "bunx prettier@latest --plugin=prettier-plugin-organize-imports --config .prettierrc --write src docs 'test/**/*.{test,spec}.{ts,tsx,js,jsx,mts,mjs,cjs,cts}' '!test/**/*fixture*.*'", "node:test": "node ./scripts/runner.node.mjs --quiet --exec-path=$npm_execpath --node-tests ", "clean:zig": "rm -rf build/debug/cache/zig build/debug/CMakeCache.txt 'build/debug/*.o' .zig-cache zig-out || true" } diff --git a/src/bake/bake.private.d.ts b/src/bake/bake.private.d.ts index 31aff5997c..b754128ce3 100644 --- a/src/bake/bake.private.d.ts +++ b/src/bake/bake.private.d.ts @@ -108,8 +108,7 @@ declare module "react-server-dom-bun/client.node.unbundled.js" { declare module "react-server-dom-bun/server.node.unbundled.js" { import type { ReactServerManifest } from "bun:bake/server"; - import type { ReactElement, ReactElement } from "react"; - import type { Writable } from "node:stream"; + import type { ReactElement } from "react"; export interface PipeableStream { /** Returns the input, which should match the Node.js writable interface */ @@ -134,8 +133,8 @@ declare module "react-server-dom-bun/server.node.unbundled.js" { } declare module "react-dom/server.node" { - import type { PipeableStream } from "react-server-dom-bun/server.node.unbundled.js"; import type { ReactElement } from "react"; + import type { PipeableStream } from "react-server-dom-bun/server.node.unbundled.js"; export type RenderToPipeableStreamOptions = any; export function renderToPipeableStream( diff --git a/src/bake/bun-framework-react/client.tsx b/src/bake/bun-framework-react/client.tsx index 7f10304d47..939e5cb81c 100644 --- a/src/bake/bun-framework-react/client.tsx +++ b/src/bake/bun-framework-react/client.tsx @@ -2,11 +2,11 @@ // Components integration. It is designed as a minimal base to build RSC // applications on, and to showcase what features that Bake offers. /// +import { onServerSideReload } from "bun:bake/client"; import * as React from "react"; +import { flushSync } from "react-dom"; import { hydrateRoot } from "react-dom/client"; import { createFromReadableStream } from "react-server-dom-bun/client.browser"; -import { onServerSideReload } from "bun:bake/client"; -import { flushSync } from "react-dom"; const te = new TextEncoder(); const td = new TextDecoder(); diff --git a/src/bake/bun-framework-react/server.tsx b/src/bake/bun-framework-react/server.tsx index ca7c039725..ed4a6c1809 100644 --- a/src/bake/bun-framework-react/server.tsx +++ b/src/bake/bun-framework-react/server.tsx @@ -1,8 +1,8 @@ import type { Bake } from "bun"; -import { renderToPipeableStream } from "react-server-dom-bun/server.node.unbundled.js"; import { renderToHtml, renderToStaticHtml } from "bun-framework-react/ssr.tsx" with { bunBakeGraph: "ssr" }; import { serverManifest } from "bun:bake/server"; import { PassThrough } from "node:stream"; +import { renderToPipeableStream } from "react-server-dom-bun/server.node.unbundled.js"; function assertReactComponent(Component: any) { if (typeof Component !== "function") { diff --git a/src/bake/bun-framework-react/ssr.tsx b/src/bake/bun-framework-react/ssr.tsx index c9c0a0610e..11fa091703 100644 --- a/src/bake/bun-framework-react/ssr.tsx +++ b/src/bake/bun-framework-react/ssr.tsx @@ -1,12 +1,12 @@ // This file is loaded in the SSR graph, meaning the `react-server` condition is // no longer set. This means we can import client components, using `react-dom` // to perform Server-side rendering (creating HTML) out of the RSC payload. -import * as React from "react"; import { ssrManifest } from "bun:bake/server"; -import type { Readable } from "node:stream"; import { EventEmitter } from "node:events"; -import { createFromNodeStream, type Manifest } from "react-server-dom-bun/client.node.unbundled.js"; +import type { Readable } from "node:stream"; +import * as React from "react"; import { renderToPipeableStream } from "react-dom/server.node"; +import { createFromNodeStream, type Manifest } from "react-server-dom-bun/client.node.unbundled.js"; import type { MiniAbortSignal } from "./server"; // Verify that React 19 is being used. diff --git a/src/bake/client/overlay.css b/src/bake/client/overlay.css index cbcb18bd86..d511c9d966 100644 --- a/src/bake/client/overlay.css +++ b/src/bake/client/overlay.css @@ -13,7 +13,7 @@ .root { all: initial; - + /* TODO: revive light theme error modal */ /* color-scheme: light dark; --modal-bg: light-dark(#efefef, #202020); @@ -35,11 +35,11 @@ --log-warn: #fbbf24; --log-note: #22d3ee; --log-colon: #888; - + --red: #ff5858; - --red-faded: #ff58582F; - --error-bg: #ff58582F; - --warn-bg: #eab3082F; + --red-faded: #ff58582f; + --error-bg: #ff58582f; + --warn-bg: #eab3082f; --syntax-comment: #6272a4; --syntax-cyan: #8be9fd; @@ -80,7 +80,8 @@ code, font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; } -pre, code { +pre, +code { font: unset; } @@ -93,8 +94,12 @@ button { } /* Helper classes */ -.flex { flex: 1 } -.muted { color: var(--modal-text-faded) } +.flex { + flex: 1; +} +.muted { + color: var(--modal-text-faded); +} /* Modal */ .modal { @@ -172,7 +177,7 @@ header { padding: 1rem 1.5rem; background-color: var(--error-bg); } -.message-desc.warn{ +.message-desc.warn { padding: 1rem 1.5rem; background-color: var(--warn-bg); } @@ -190,7 +195,6 @@ header { --color: var(--log-error); } - /* Bundler messages */ .b-group { display: flex; @@ -207,10 +211,18 @@ header { --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); } -.log-label { color: var(--color); } +.log-warn { + --color: var(--log-warn); +} +.log-note { + --color: var(--log-note); +} +.log-colon { + --color: var(--log-colon); +} +.log-label { + color: var(--color); +} .message-desc.note + .code { padding-top: 0.75rem; @@ -286,22 +298,44 @@ header { } /* Syntax Highlighting */ -.syntax-pink { color: var(--syntax-pink); } -.syntax-cyan { color: var(--syntax-cyan); } -.syntax-orange { color: var(--syntax-orange); } -.syntax-red { color: var(--syntax-red); } -.syntax-green { color: var(--syntax-green); } -.syntax-yellow { color: var(--syntax-yellow); } -.syntax-gray { color: var(--syntax-comment); } -.syntax-purple { color: var(--syntax-purple); } +.syntax-pink { + color: var(--syntax-pink); +} +.syntax-cyan { + color: var(--syntax-cyan); +} +.syntax-orange { + color: var(--syntax-orange); +} +.syntax-red { + color: var(--syntax-red); +} +.syntax-green { + color: var(--syntax-green); +} +.syntax-yellow { + color: var(--syntax-yellow); +} +.syntax-gray { + color: var(--syntax-comment); +} +.syntax-purple { + color: var(--syntax-purple); +} /* Icons */ -.tab-button.left { background-image: url(./icons/prev.svg); } -.tab-button.right { background-image: url(./icons/next.svg); } +.tab-button.left { + background-image: url(./icons/prev.svg); +} +.tab-button.right { + background-image: url(./icons/next.svg); +} .dismiss-all { background-image: url(./icons/dismiss.svg); opacity: 0.5; } @media (prefers-color-scheme: light) { - .dismiss-all { filter: invert(1); } + .dismiss-all { + filter: invert(1); + } } diff --git a/src/bake/client/overlay.ts b/src/bake/client/overlay.ts index 4e16f2f284..a87708ec2f 100644 --- a/src/bake/client/overlay.ts +++ b/src/bake/client/overlay.ts @@ -514,7 +514,11 @@ function updateRuntimeErrorOverlay(err: RuntimeError) { } dom.appendChild( - elem("div", { class: "r-error-trace" }, trace.map(frame => renderTraceFrame(frame, "trace-frame"))), + elem( + "div", + { class: "r-error-trace" }, + trace.map(frame => renderTraceFrame(frame, "trace-frame")), + ), ); domErrorContent.appendChild(dom); } @@ -667,7 +671,7 @@ declare global { } import { BundlerMessageLevel } from "../enums"; -import { css } from "../macros" with { type: "macro" }; +import { DataViewReader, DataViewWriter } from "./data-view"; import { BundlerMessage, BundlerMessageLocation, @@ -675,6 +679,5 @@ import { decodeSerializedError, type DeserializedFailure, } from "./error-serialization"; -import { DataViewReader, DataViewWriter } from "./data-view"; -import { parseStackTrace, type Frame } from "./stack-trace"; import { syntaxHighlight } from "./JavaScriptSyntaxHighlighter"; +import { parseStackTrace, type Frame } from "./stack-trace"; diff --git a/src/bake/client/stack-trace.ts b/src/bake/client/stack-trace.ts index 9697e41198..41d0744832 100644 --- a/src/bake/client/stack-trace.ts +++ b/src/bake/client/stack-trace.ts @@ -72,7 +72,7 @@ function parseV8OrIE(stack: string): Frame[] { let fileName = ["eval", ""].indexOf(locationParts[0]) > -1 ? undefined : locationParts[0]; return { - fn: functionName || 'unknown', + fn: functionName || "unknown", file: fileName, line: 0 | locationParts[1], col: 0 | locationParts[2], @@ -127,7 +127,7 @@ function remapFileName(fileName: string) { if (fileName.startsWith("blob:")) { const sourceMapURL = blobToSourceMap.get(fileName); if (sourceMapURL) { - return location.origin + '/_bun/client/hmr-' + sourceMapURL.id + '.js'; + return location.origin + "/_bun/client/hmr-" + sourceMapURL.id + ".js"; } } return fileName; diff --git a/src/bake/debug.ts b/src/bake/debug.ts index 2ce0fce941..57d81b7d80 100644 --- a/src/bake/debug.ts +++ b/src/bake/debug.ts @@ -10,13 +10,15 @@ // }; // } if (IS_BUN_DEVELOPMENT) { - globalThis.DEBUG = { ASSERT: function ASSERT(condition: any, message?: string): asserts condition { - if (!condition) { - if (typeof Bun === "undefined") { - console.assert(false, "ASSERTION FAILED" + (message ? `: ${message}` : "")); - } else { - console.error("ASSERTION FAILED" + (message ? `: ${message}` : "")); + globalThis.DEBUG = { + ASSERT: function ASSERT(condition: any, message?: string): asserts condition { + if (!condition) { + if (typeof Bun === "undefined") { + console.assert(false, "ASSERTION FAILED" + (message ? `: ${message}` : "")); + } else { + console.error("ASSERTION FAILED" + (message ? `: ${message}` : "")); + } } - } - } }; + }, + }; } diff --git a/src/bake/hmr-runtime-error.ts b/src/bake/hmr-runtime-error.ts index 20957a10c9..12697dfbb9 100644 --- a/src/bake/hmr-runtime-error.ts +++ b/src/bake/hmr-runtime-error.ts @@ -6,10 +6,10 @@ // 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 './debug'; -import { decodeAndAppendServerError, onServerErrorPayload, updateErrorOverlay } from "./client/overlay"; import { DataViewReader } from "./client/data-view"; +import { decodeAndAppendServerError, onServerErrorPayload, updateErrorOverlay } from "./client/overlay"; import { initWebSocket } from "./client/websocket"; +import "./debug"; import { MessageId } from "./generated"; /** Injected by DevServer */ diff --git a/src/bake/hmr-runtime-server.ts b/src/bake/hmr-runtime-server.ts index cd76fea987..68ed6cb455 100644 --- a/src/bake/hmr-runtime-server.ts +++ b/src/bake/hmr-runtime-server.ts @@ -1,8 +1,8 @@ // This file is the entrypoint to the hot-module-reloading runtime. // On the server, communication is established with `server_exports`. -import './debug'; import type { Bake } from "bun"; -import { loadExports, replaceModules, ssrManifest, serverManifest, HMRModule } from "./hmr-module"; +import "./debug"; +import { loadExports, replaceModules, serverManifest, ssrManifest } from "./hmr-module"; if (typeof IS_BUN_DEVELOPMENT !== "boolean") { throw new Error("DCE is configured incorrectly"); diff --git a/src/bake/incremental_visualizer.html b/src/bake/incremental_visualizer.html index b8701a73de..b61bc05f47 100644 --- a/src/bake/incremental_visualizer.html +++ b/src/bake/incremental_visualizer.html @@ -1,410 +1,408 @@ + + + + IncrementalGraph Visualization + + + - #stat { - font-weight: normal; - } - - - - -

IncrementalGraph Visualization

-
-
-
-
- Stale + +

IncrementalGraph Visualization

+
+
+
+
+ Stale +
+
+
+ Client +
+
+
+ HTML +
+
+
+ Route +
+
+
+ SSR +
+
+
+ Server +
+
+
+ SSR + Server +
-
-
- Client -
-
-
- HTML -
-
-
- Route -
-
-
- SSR -
-
-
- Server -
-
-
- SSR + Server -
-
- - + // Helper function to remove a node by ID + function removeNode(id) { + nodes.remove({ id }); + } - \ No newline at end of file + // 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)`; + } + + + diff --git a/src/bake/memory_visualizer.html b/src/bake/memory_visualizer.html index 7ac0d5631a..8802d58536 100644 --- a/src/bake/memory_visualizer.html +++ b/src/bake/memory_visualizer.html @@ -1,404 +1,400 @@ - - - - - DevServer Memory Visualization - - - - -

DevServer Memory Visualization

-
Last updated: Never
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CategoryMemory Usage
DevServer Memory Breakdown
Incremental Graph (Client)
Incremental Graph (Server)
JS Code
Source Maps
Assets
Other
Overall Memory Statistics
DevServer AllocationScope
Process usage
- -
-

Source Maps

-
Total Source Maps: 0
-
- - - - - - - - - - - - - - -
KeyRef CountWeak RefsExpiry TimeFile PathsSize (bytes)
-
-
- - - + offset += 40; // Move past the main memory metrics - \ No newline at end of file + // Parse source maps data + const sourceMapsCount = readUint32(buffer, offset); + offset += 4; + + const sourceMaps = []; + for (let i = 0; i < sourceMapsCount; i++) { + const key = readKey(buffer, offset); + offset += 8; + + const refCount = readUint32(buffer, offset); + offset += 4; + + const weakRefs = readUint32(buffer, offset); + offset += 4; + + let weakRefExpire = 0; + if (weakRefs > 0) { + weakRefExpire = readFloat64(buffer, offset); + offset += 8; + } + + const filePathsCount = readUint32(buffer, offset); + offset += 4; + + const mapCost = readUint32(buffer, offset); + offset += 4; + + sourceMaps.push({ + key, + refCount, + weakRefs, + weakRefExpire: weakRefs > 0 ? weakRefExpire * 1000 : 0, + filePathsCount, + mapCost, + }); + } + + // Update the tables with new data + updateMemoryTable(memoryData); + updateSourceMapsTable(sourceMaps); + + // Update the last updated time + document.getElementById("update-time").textContent = "Last updated: " + new Date().toLocaleTimeString(); + } + + function updateMemoryTable(data) { + // Calculate the max memory among the dev server breakdown fields + const devServerFields = [ + "incremental_graph_client", + "incremental_graph_server", + "js_code", + "source_maps", + "assets", + "other", + ]; + + const maxDevServerMemory = Math.max(...devServerFields.map(field => data[field])); + + // Update the dev server memory breakdown fields with color coding + devServerFields.forEach(field => { + const element = document.getElementById(field); + element.textContent = formatBytes(data[field]); + element.style.backgroundColor = getColorIntensity(data[field], maxDevServerMemory); + }); + + // Update the overall memory statistics (no color coding) + document.getElementById("devserver_tracked").textContent = formatBytes(data.devserver_tracked); + document.getElementById("process_used").textContent = formatBytes(data.process_used); + // document.getElementById('system_used').textContent = formatBytes(data.system_used); + // document.getElementById('system_total').textContent = formatBytes(data.system_total); + } + + function updateSourceMapsTable(sourceMaps) { + // Update count display + document.getElementById("source-maps-count").textContent = `Total Source Maps: ${sourceMaps.length}`; + + // Clear existing table rows + const tbody = document.getElementById("source-maps-tbody"); + tbody.innerHTML = ""; + + // Add new rows + sourceMaps.forEach(sourceMap => { + const row = document.createElement("tr"); + + // Key cell + const keyCell = document.createElement("td"); + keyCell.className = "key-cell"; + keyCell.textContent = sourceMap.key; + row.appendChild(keyCell); + + // Ref count cell + const refCountCell = document.createElement("td"); + refCountCell.className = "count-cell"; + refCountCell.textContent = sourceMap.refCount; + row.appendChild(refCountCell); + + // Weak refs cell + const weakRefsCell = document.createElement("td"); + weakRefsCell.className = "count-cell"; + weakRefsCell.textContent = sourceMap.weakRefs; + row.appendChild(weakRefsCell); + + // Expiry time cell + const expiryCell = document.createElement("td"); + expiryCell.className = "expiry-cell"; + expiryCell.textContent = formatDate(sourceMap.weakRefExpire); + row.appendChild(expiryCell); + + // File paths count cell + const filePathsCell = document.createElement("td"); + filePathsCell.className = "count-cell"; + filePathsCell.textContent = sourceMap.filePathsCount; + row.appendChild(filePathsCell); + + // Map cost cell + const mapCostCell = document.createElement("td"); + mapCostCell.className = "size-cell"; + mapCostCell.textContent = formatBytes(sourceMap.mapCost); + row.appendChild(mapCostCell); + + tbody.appendChild(row); + }); + } + + + diff --git a/src/bake/server/stack-trace-stub.ts b/src/bake/server/stack-trace-stub.ts index 3c4eca1474..7a59c55960 100644 --- a/src/bake/server/stack-trace-stub.ts +++ b/src/bake/server/stack-trace-stub.ts @@ -1 +1 @@ -export let derefMapping = null; \ No newline at end of file +export let derefMapping = null; diff --git a/src/bun.js/api/BunObject.bind.ts b/src/bun.js/api/BunObject.bind.ts index 9cfbd7ccda..a4e8b852f6 100644 --- a/src/bun.js/api/BunObject.bind.ts +++ b/src/bun.js/api/BunObject.bind.ts @@ -1,4 +1,4 @@ -import { t, fn } from "bindgen"; +import { fn, t } from "bindgen"; export const BracesOptions = t.dictionary({ tokenize: t.boolean.default(false), diff --git a/src/bun.js/bindgen_test.bind.ts b/src/bun.js/bindgen_test.bind.ts index 9093ffd0b9..ee61e0733c 100644 --- a/src/bun.js/bindgen_test.bind.ts +++ b/src/bun.js/bindgen_test.bind.ts @@ -1,4 +1,4 @@ -import { t, fn } from "bindgen"; +import { fn, t } from "bindgen"; export const add = fn({ args: { diff --git a/src/bun.js/bindings/libuv/generate_uv_posix_stubs.ts b/src/bun.js/bindings/libuv/generate_uv_posix_stubs.ts index f2e875edbc..149492fda9 100644 --- a/src/bun.js/bindings/libuv/generate_uv_posix_stubs.ts +++ b/src/bun.js/bindings/libuv/generate_uv_posix_stubs.ts @@ -1,4 +1,4 @@ -import path, { join } from "path"; +import { join } from "path"; import { symbols, test_skipped } from "./generate_uv_posix_stubs_constants"; import Parser from "tree-sitter"; diff --git a/src/codegen/bake-codegen.ts b/src/codegen/bake-codegen.ts index 9bc47dc45b..f9ddef9a06 100644 --- a/src/codegen/bake-codegen.ts +++ b/src/codegen/bake-codegen.ts @@ -134,7 +134,9 @@ async function run() { : `${code};return ${outName("server_exports")};`; const params = `${outName("$separateSSRGraph")},${outName("$importMeta")}`; - code = code.replaceAll("import.meta", outName("$importMeta")).replaceAll(outName("$importMeta") + ".hot", "import.meta.hot"); + code = code + .replaceAll("import.meta", outName("$importMeta")) + .replaceAll(outName("$importMeta") + ".hot", "import.meta.hot"); code = `let ${outName("unloadedModuleRegistry")}={},${outName("config")}={separateSSRGraph:${outName("$separateSSRGraph")}},${outName("server_exports")};${code}`; code = debug ? `((${params}) => {${code}})\n` : `((${params})=>{${code}})\n`; @@ -146,9 +148,9 @@ async function run() { if (side === "client" && code.match(/\beval\(|,\s*eval\s*\)/)) { throw new AggregateError([ new Error( - "eval is not allowed in the HMR runtime. there are problems in all " - + "browsers regarding stack traces from eval'd frames and source maps. " - + "you must find an alternative solution to your problem." + "eval is not allowed in the HMR runtime. there are problems in all " + + "browsers regarding stack traces from eval'd frames and source maps. " + + "you must find an alternative solution to your problem.", ), ]); } diff --git a/src/codegen/bindgen-lib-internal.ts b/src/codegen/bindgen-lib-internal.ts index f969c30fd1..db0e6fb6ab 100644 --- a/src/codegen/bindgen-lib-internal.ts +++ b/src/codegen/bindgen-lib-internal.ts @@ -3,9 +3,9 @@ // various footguns in JavaScript, C++, and the bindings generator to // always produce correct code, or bail with an error. import { expect } from "bun:test"; -import type { FuncOptions, Type, t } from "./bindgen-lib"; -import * as path from "node:path"; import assert from "node:assert"; +import * as path from "node:path"; +import type { FuncOptions, t } from "./bindgen-lib"; export const src = path.join(import.meta.dirname, "../"); diff --git a/src/codegen/bindgen-lib.ts b/src/codegen/bindgen-lib.ts index 5594df29fc..ec9a6915d7 100644 --- a/src/codegen/bindgen-lib.ts +++ b/src/codegen/bindgen-lib.ts @@ -5,13 +5,13 @@ */ import { - isType, dictionaryImpl, + isFunc, + isType, oneOfImpl, registerFunction, TypeImpl, type TypeKind, - isFunc, } from "./bindgen-lib-internal"; /** A type definition for argument parsing. See `bindgen.md` for usage details. */ diff --git a/src/codegen/bindgen.ts b/src/codegen/bindgen.ts index dbd0a9af69..10d09e9d6c 100644 --- a/src/codegen/bindgen.ts +++ b/src/codegen/bindgen.ts @@ -3,39 +3,39 @@ // // Generated bindings are available in `bun.generated..*` in Zig, // or `Generated::::*` in C++ from including `Generated.h`. -import * as path from "node:path"; +import assert from "node:assert"; import fs from "node:fs"; +import * as path from "node:path"; import { + ArgStrategyChildItem, CodeWriter, + Func, + NodeValidator, + Struct, TypeImpl, + alignForward, + cAbiIntegerLimits, cAbiTypeName, cap, extDispatchVariant, + extInternalDispatchVariant, extJsFunction, files, + inspect, + isFunc, + pascal, snake, src, str, - Struct, + typeHashToNamespace, + typeHashToReachableType, + zid, type CAbiType, type DictionaryField, type ReturnStrategy, type TypeKind, type Variant, - typeHashToNamespace, - typeHashToReachableType, - zid, - ArgStrategyChildItem, - inspect, - pascal, - alignForward, - isFunc, - Func, - NodeValidator, - cAbiIntegerLimits, - extInternalDispatchVariant, } from "./bindgen-lib-internal"; -import assert from "node:assert"; import { argParse, readdirRecursiveWithExclusionsAndExtensionsSync, writeIfNotChanged } from "./helpers"; // arg parsing @@ -1485,7 +1485,7 @@ zigInternal.line("};"); zigInternal.line(); zigInternal.line("comptime {"); zigInternal.line(` if (bun.Environment.export_cpp_apis) {`); -zigInternal.line(" for (@typeInfo(binding_internals).@\"struct\".decls) |decl| {"); +zigInternal.line(' for (@typeInfo(binding_internals).@"struct".decls) |decl| {'); zigInternal.line(" _ = &@field(binding_internals, decl.name);"); zigInternal.line(" }"); zigInternal.line(" }"); diff --git a/src/codegen/bundle-functions.ts b/src/codegen/bundle-functions.ts index 0ebc48a3a9..b379844324 100644 --- a/src/codegen/bundle-functions.ts +++ b/src/codegen/bundle-functions.ts @@ -16,6 +16,7 @@ // - We concatenate all the sources into one big string, which then createsa // single JSC::SourceProvider and pass start/end positions to each function's // JSC::SourceCode. JSC does this, but WebCore does not seem to. +import assert from "assert"; import { readdirSync, rmSync } from "fs"; import path from "path"; import { sliceSourceCode } from "./builtin-parser"; @@ -23,7 +24,6 @@ import { createAssertClientJS, createLogClientJS } from "./client-js"; import { getJS2NativeDTS } from "./generate-js2native"; import { addCPPCharArray, cap, low, writeIfNotChanged } from "./helpers"; import { applyGlobalReplacements, define } from "./replacements"; -import assert from "assert"; const PARALLEL = false; const KEEP_TMP = true; diff --git a/src/codegen/bundle-modules.ts b/src/codegen/bundle-modules.ts index 7719a8c36d..8ff595d652 100644 --- a/src/codegen/bundle-modules.ts +++ b/src/codegen/bundle-modules.ts @@ -12,14 +12,13 @@ import fs from "fs"; import { mkdir, writeFile } from "fs/promises"; import { builtinModules } from "node:module"; import path from "path"; -import ErrorCode from "../bun.js/bindings/ErrorCode"; +import jsclasses from "./../bun.js/bindings/js_classes"; import { sliceSourceCode } from "./builtin-parser"; import { createAssertClientJS, createLogClientJS } from "./client-js"; import { getJS2NativeCPP, getJS2NativeZig } from "./generate-js2native"; import { cap, declareASCIILiteral, writeIfNotChanged } from "./helpers"; import { createInternalModuleRegistry } from "./internal-module-registry-scanner"; import { define } from "./replacements"; -import jsclasses from "./../bun.js/bindings/js_classes"; const BASE = path.join(import.meta.dir, "../js"); const debug = process.argv[2] === "--debug=ON"; diff --git a/src/codegen/create-hash-table.ts b/src/codegen/create-hash-table.ts index 7c5bd88580..793d2d7acf 100644 --- a/src/codegen/create-hash-table.ts +++ b/src/codegen/create-hash-table.ts @@ -44,7 +44,7 @@ str = str.replaceAll(/^#include.*$/gm, ""); str = str.replaceAll(`namespace JSC {`, ""); str = str.replaceAll(`} // namespace JSC`, ""); str = str.replaceAll(/NativeFunctionType,\s([a-zA-Z0-99_]+)/gm, "NativeFunctionType, &$1"); -str = str.replaceAll('&Generated::', 'Generated::'); +str = str.replaceAll("&Generated::", "Generated::"); str = "#pragma once" + "\n" + "// File generated via `create-hash-table.ts`\n" + str.trim() + "\n"; writeIfNotChanged(output, str); diff --git a/src/codegen/generate-classes.ts b/src/codegen/generate-classes.ts index 5c74f9a981..81d1d09c08 100644 --- a/src/codegen/generate-classes.ts +++ b/src/codegen/generate-classes.ts @@ -1,8 +1,8 @@ // @ts-nocheck import path from "path"; +import jsclasses from "./../bun.js/bindings/js_classes"; import { InvalidThisBehavior, type ClassDefinition, type Field } from "./class-definitions"; import { camelCase, pascalCase, writeIfNotChanged } from "./helpers"; -import jsclasses from "./../bun.js/bindings/js_classes"; if (process.env.BUN_SILENT === "1") { console.log = () => {}; diff --git a/src/codegen/helpers.ts b/src/codegen/helpers.ts index 0b8ef64415..e6868ccd61 100644 --- a/src/codegen/helpers.ts +++ b/src/codegen/helpers.ts @@ -152,4 +152,4 @@ export function argParse(keys: string[]): any { } if (unknown.size > 0) process.exit(1); return options; -} \ No newline at end of file +} diff --git a/src/codegen/replacements.ts b/src/codegen/replacements.ts index 30cfdfffea..fd1f3438ad 100644 --- a/src/codegen/replacements.ts +++ b/src/codegen/replacements.ts @@ -1,8 +1,8 @@ import { LoaderKeys } from "../api/schema"; import NodeErrors from "../bun.js/bindings/ErrorCode.ts"; +import jsclasses from "./../bun.js/bindings/js_classes"; import { sliceSourceCode } from "./builtin-parser"; import { registerNativeCall } from "./generate-js2native"; -import jsclasses from "./../bun.js/bindings/js_classes"; // This is a list of extra syntax replacements to do. Kind of like macros // These are only run on code itself, not string contents or comments. diff --git a/src/create/projects/react-shadcn-spa/REPLACE_ME_WITH_YOUR_APP_FILE_NAME.client.tsx b/src/create/projects/react-shadcn-spa/REPLACE_ME_WITH_YOUR_APP_FILE_NAME.client.tsx index bd50af3c93..bbab5be9cd 100644 --- a/src/create/projects/react-shadcn-spa/REPLACE_ME_WITH_YOUR_APP_FILE_NAME.client.tsx +++ b/src/create/projects/react-shadcn-spa/REPLACE_ME_WITH_YOUR_APP_FILE_NAME.client.tsx @@ -1,6 +1,6 @@ +import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import { REPLACE_ME_WITH_YOUR_REACT_COMPONENT_EXPORT as Component } from "./REPLACE_ME_WITH_YOUR_APP_BASE_NAME"; -import { StrictMode } from "react"; // Optionally: import your app's CSS // import "./styles.css"; diff --git a/src/fallback-backend.html b/src/fallback-backend.html index c7e4d6db75..e19b9611b2 100644 --- a/src/fallback-backend.html +++ b/src/fallback-backend.html @@ -1,4 +1,4 @@ - + diff --git a/src/fallback.html b/src/fallback.html index 1474312ac8..35010764f1 100644 --- a/src/fallback.html +++ b/src/fallback.html @@ -1,4 +1,4 @@ - + @@ -6,17 +6,23 @@ - + {[preload]s} - + - + diff --git a/src/fixtures_example.com.html b/src/fixtures_example.com.html index 5a9b52fcf1..5ff38ab5c6 100644 --- a/src/fixtures_example.com.html +++ b/src/fixtures_example.com.html @@ -1,46 +1,50 @@ - + Example Domain - + } + + - -
-

Example Domain

-

This domain is for use in illustrative examples in documents. You may use this - domain in literature without prior coordination or asking for permission.

-

More information...

-
- + +
+

Example Domain

+

+ This domain is for use in illustrative examples in documents. You may use this domain in literature without + prior coordination or asking for permission. +

+

More information...

+
+ diff --git a/src/init/react-app/src/APITester.tsx b/src/init/react-app/src/APITester.tsx index 43ba33e5eb..fd2af48601 100644 --- a/src/init/react-app/src/APITester.tsx +++ b/src/init/react-app/src/APITester.tsx @@ -1,4 +1,4 @@ -import React, { useRef, type FormEvent } from "react"; +import { useRef, type FormEvent } from "react"; export function APITester() { const responseInputRef = useRef(null); @@ -28,23 +28,12 @@ export function APITester() { - + -