Compare commits

..

107 Commits

Author SHA1 Message Date
Jarred Sumner
8cbf373c31 Update fs.js 2023-06-25 16:04:09 -07:00
Hanaasagi
3a8cb27abd wait first stream finished 2023-06-26 00:44:20 +09:00
Hanaasagi
a2dcd680de fix lint 2023-06-26 00:16:36 +09:00
Hanaasagi
06f03d34da test append mode in createWriteStream 2023-06-25 22:30:48 +09:00
Hanaasagi
b33cdf586a Fix the parameters of the WriteStream constructor.
Close: https://github.com/oven-sh/bun/issues/3395
2023-06-25 22:25:58 +09:00
Jarred Sumner
c4c714f10b Speculative fix for regression causing a hang with install --production (#3400)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-25 04:52:43 -07:00
Jarred Sumner
f8abd167d8 Revert "make these strings lazy"
This reverts commit 777f98bd10.
2023-06-25 04:17:07 -07:00
Jarred Sumner
777f98bd10 make these strings lazy 2023-06-25 03:32:10 -07:00
Jarred Sumner
30798c7078 Make timeout longer 2023-06-25 03:32:10 -07:00
Jarred Sumner
bc7719fc28 Reliability bugfix for WebSocket (#3394)
* Rewrite elementLengthLatin1IntoUTF8

* Update SIMDUTF

* Make `elementLengthLatin1IntoUTF8` faster

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-25 02:58:49 -07:00
Jarred Sumner
ff63555143 Rewrite Bun's runtime CommonJS loader (#3379)
* wip changes for CommonJS

* this rewrite is almost complete

* even more code

* wip

* Remove usages of `import.meta.require` from builtins

* Remove usages of require

* Regenerate

* ✂️ builtin rewrite commonjs in printer

* Use lazy custom getters for import.meta

* fixups

* Remove depd

* ugh

* still crashing

* fixup undici

* comment out import.meta.require.resolve temporarily

not a real solution but it stops the crashes

* Redo import.meta.primordials

* Builtins now have a `builtin://` protocol in source origin

* Seems to work?

* Finsih getting rid of primordials

* switcharoo

* No more function

* just one more bug

* Update launch.json

* Implement `require.main`

* ✂️

* Bump WebKit

* Fixup import cycles

* Fixup improt cycles

* export more things

* Implement `createCommonJSModule` builtin

* More exports

* regenerate

* i broke some stuff

* some of these tests work now

* We lost the encoding

* Sort of fix zlib

* Sort of fix util

* Update events.js

* bump

* bump

* bump

* Fix missing export in fs

* fix some bugs with builtin esm modules (stream, worker_threads, events). its not perfect yet.

* fix some other internal module bugs

* oops

* fix some extra require default stuff

* uncomment this file but it crsahes on my machine

* tidy code here

* fixup tls exports

* make simdutf happier

* Add hasPrefix binding

* Add test for `require.main`

* Fix CommonJS evaluation order race condition

* Make node:http load faster

* Add missing exports to tls.js

* Use the getter

* Regenerate builtins

* Fix assertion failure in Bun.write()

* revamp dotEnv parser (#3347)

- fixes `strings.indexOfAny()`
- fixes OOB array access

fixes #411
fixes #2823
fixes #3042

* fix tests for `expect()` (#3384)

- extend test job time-out for `darwin-aarch64`

* `expect().resolves` and `expect().rejects` (#3318)

* Move expect and snapshots to their own files

* expect().resolves and expect().rejects

* Fix promise being added to unhandled rejection list

* Handle timeouts in expect(<promise>)

* wip merge

* Fix merge issue

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>

* fixup min/memcopy (#3388)

* Fix crash in builtins

* Don't attempt to evaluate modules with no source code

* Update WebCoreJSBuiltins.cpp

* Update WebCoreJSBuiltins.cpp

* Update WebCoreJSBuiltins.cpp

* Fix crash

* cleanup

* Fix test

cc @paperdave

* Fixup Undici

* Fix issue in node:http

* Create util-deprecate.mjs

* Fix several bugs

* Use the identifier

* Support error.code in `util.deprecate`

* make the CJs loader slightly more resilient

* Update WebCoreJSBuiltins.cpp

* Fix macros

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Co-authored-by: dave caruso <me@paperdave.net>
Co-authored-by: Alex Lam S.L <alexlamsl@gmail.com>
Co-authored-by: Ashcon Partovi <ashcon@partovi.net>
Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com>
2023-06-24 06:02:16 -07:00
Ciro Spaciari
069b42a7cc [feat] fs.watch (#3249)
* initial support

* add types

* fix comment

* fix types

* bigfix up

* more fixes

* fix some encoding support for watch

* fix rename event

* fixup

* fix latin1

* add fs_events, still failing some tests

* fixuup

* remove unecesary check

* readd tests ops

* this is necessary? just testing CI/CD weird errors

* just use dupe here

* cleanup and fix deinit

* fix zig upgrade
2023-06-23 23:24:34 -07:00
dave caruso
ceec1afec2 Add vi.spyOn and clean up some mock function binding calls (#3376)
* Add vi.spyOn and clean up some binding calls

* add vi.restoreAllMocks

* remove junk file

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2023-06-23 23:24:05 -07:00
dave caruso
5ae8e5d773 Make node-fallbacks build as esm not cjs / Fix node-fetch (#3377)
* Make node-fallbacks build as esm not cjs.

* fix stuff
2023-06-23 23:23:39 -07:00
Ciro Spaciari
4ff920c915 fixup min/memcopy (#3388) 2023-06-23 18:19:00 -07:00
Ashcon Partovi
217501e180 expect().resolves and expect().rejects (#3318)
* Move expect and snapshots to their own files

* expect().resolves and expect().rejects

* Fix promise being added to unhandled rejection list

* Handle timeouts in expect(<promise>)

* wip merge

* Fix merge issue

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-22 22:27:00 -07:00
Alex Lam S.L
ae4b65c52e fix tests for expect() (#3384)
- extend test job time-out for `darwin-aarch64`
2023-06-22 20:13:26 -07:00
Alex Lam S.L
ca1fe3c602 revamp dotEnv parser (#3347)
- fixes `strings.indexOfAny()`
- fixes OOB array access

fixes #411
fixes #2823
fixes #3042
2023-06-22 17:05:54 -07:00
Jarred Sumner
4a13a53058 CommonJS bun build cannot use import.meta (#3378)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-22 01:06:50 -07:00
Dylan Conway
5fa13625a1 upgrade zig to v0.11.0-dev.3737+9eb008717 (#3374)
* progress

* finish `@memset/@memcpy` update

* Update build.zig

* change `@enumToInt` to `@intFromEnum` and friends

* update zig versions

* it was 1

* add link to issue

* add `compileError` reminder

* fix merge

* format

* upgrade to llvm 16

* Revert "upgrade to llvm 16"

This reverts commit cc930ceb1c.

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-21 23:38:18 -07:00
Jarred Sumner
bfb322d618 Revert "Update Github action runners"
This reverts commit 69f558db8e.
2023-06-21 19:52:53 -07:00
dave caruso
43865a3e29 finish implementing JSMockFunction prototype + lots of expect test organizing (#3304)
* mock tests

* fix mistake

* stuff

* partially implement mock return promises

* lot of housecleaning on jest tests

* document / rename internalFields in jsmockfunction

* finish implementing JSMockFunction prototype

* cleanup

* more progress

* everything is done

* remove demo.test.js

* finish rebase

* requested changes

* fix compile error
2023-06-21 12:59:56 -07:00
Andreas Pfurtscheller
b691212c6e Update module resolution order docs (#3372)
If I'm reading and interpreting [these lines](69f558db8e/src/options.zig (L605-L627)) correct, the module resolution order [in the current docs](https://bun.sh/docs/runtime/modules#resolution) is outdated.

This change will fix the order.
2023-06-21 12:08:05 -07:00
Ashcon Partovi
69f558db8e Update Github action runners 2023-06-21 11:14:41 -07:00
Jarred Sumner
9befbf02f1 Update WebKit 2023-06-20 21:32:19 -07:00
Jarred Sumner
f81c7f10f6 Fix crash with .env files that are exactly 159 bytes long (#3369)
* Fix crash with .env files that are exactly 158 bytes and a newline character

* Update env_loader.zig

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-20 21:17:32 -07:00
Jarred Sumner
b9c950bfb7 Improve error message for error.DependencyLoop (#3368)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-20 19:29:47 -07:00
Dylan Conway
6a1fbef8fd record jsx factory symbols in classic mode (#3360)
* record jsx factory symbols

* merge factory/fragment when more than one part

* update test

* use existing functions, use, `memberListToComponentsIfDifferent`

* missing file

* fix defaults
2023-06-20 19:29:20 -07:00
Dylan Conway
5006435234 enable asymmetric matchers in expect.toEqual, expect.toStrictEqual, and expect.toHaveProperty (#3367)
* add asymmetric matchers to `deepEquals`

* fix comparison of a few jstypes

* clean up and tests

* fix merge

* improve `expect.any` for primitives
2023-06-20 19:06:58 -07:00
Colin McDonnell
adb451eec6 Docs for DOM testing and FileSink (#3330)
* Update websocket docs & jsdoc

* Add info about user-specific data in ws

* Document FileSink

* Docs for happydom test

* Updates
2023-06-20 18:57:37 -07:00
Jarred Sumner
62639081c1 [JSTranspiler] Make scan and scanImports more careful with GC 2023-06-20 18:55:14 -07:00
Jarred Sumner
570ef07170 woops 2023-06-20 18:06:28 -07:00
Jarred Sumner
83d7ec728f Clone SourceOrigin string 2023-06-20 17:12:47 -07:00
Jarred Sumner
9f301e13c5 Cleanup fs.utimesSync (#3363)
* Fix UB in fs.utimesSync when passing a number with an integer greater than i32

* Fix make headers

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-20 00:31:07 -07:00
Jarred Sumner
f1b1dbf5cd prettier 2023-06-20 00:02:14 -07:00
Keyhan Vakil
bdbb637b3d implement more of V8's stack trace API (#3359)
- fix source map positions for getLineNumber / getColumnNumber
- fix return value getting coerced to a string
- implement CallFrame.p.toString
- add tests for getFunction, getThis, isConstructor, isNative, toString,
  getLineNumber, getColumnNumber

still not implemented:
- isPromiseAll/getPromiseIndex
- getEvalOrigin
- getScriptHash
- getPosition
- getEnclosingColumnNumber/getEnclosingLineNumber
- isAsync
- accessing Error.stack should call prepareStackTrace

still broken:
- isEval: often returns false when it should return true
- isToplevel: often returns true when it should return false

Refs: https://v8.dev/docs/stack-trace-api
Refs: v8/src/objects/call-site-info.cc
Fixes: https://github.com/oven-sh/bun/issues/2883
2023-06-19 23:28:40 -07:00
Tiramify (A.K. Daniel)
e9e0e05156 feat(bun/test): Impl. "toBeArray", "toBeArrayOfSize" & "toBeTypeOf" (#3316)
* Implement toBeArray, toBeArrayOfSize, toBeTypeOf

* fix typos/variable names

* Add testcases for regex and dates

* little fix

* i didn't paste that...
2023-06-19 22:39:44 -07:00
Jarred Sumner
7d94a49ef4 Fix bug that breaks bunx prisma init when node is not installed (#3362)
* tweak cjs

* Handle more cases, add a test

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-19 22:34:22 -07:00
Jarred Sumner
cbd6d24d34 Move this code up a bit 2023-06-19 00:33:14 -07:00
Jarred Sumner
b951c1f89e Press the secret "use less RAM" button 2023-06-18 23:30:01 -07:00
Jarred Sumner
b78b2a3031 Update esbuild-test.js 2023-06-18 21:57:52 -07:00
Jarred Sumner
7dcf8b2186 Make the esbuild integration test more thorough 2023-06-18 21:57:40 -07:00
Jarred Sumner
8a5b8f1fca Make more tests fail 2023-06-18 21:07:38 -07:00
Jarred Sumner
8ad9e5755d Add missing ucs2 alias 2023-06-18 21:05:05 -07:00
Jarred Sumner
fdb7940c4e Fix a bunch of bugs (#3352)
* Fix a bunch of bugs

* undo that one

* Fix crash in readdir()

* woops

* woops

* Add comment

* ✂️

* Make `readlink()` and `realpath` use much less memory

* Update BunString.cpp

* woopsie

* Unnecessary

* Don't commit these

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-18 10:47:42 -07:00
Alex Lam S.L
873f615358 minor build diffs (#3349) 2023-06-18 03:45:41 -07:00
Ciro Spaciari
b2af1984ed [eventsource] SSE Client (#3074)
* fix flush

* remove logs

* add HTTP/1.1 eventsource

* fix parse spec

* multiple data in one event

* get lastEventId for reconnection

* fix parsing add reconnect

* fix reconnection retry

* add retry option

* move eventsource to builtins

* remove duplicate interface on globals.d.ts

* move test to TS

* fmt

* allow no Content-Length or Transfer Encoding

* udpate builtins

* hardcoded

* merge

* revert /src/out

* updated

* Update .gitignore

* Make the tests fail

* Cleanup EventSource getter

* fixup

* fixup TS

* fmt

* update builtins

* fix tests

* Clear existing timeouts

* Add `ref` and `unref` methods

* Use `super` to make prototype pollution slightly harder

* Reduce test timeout

* Regenerate builtins

* prettier + ref/unref

* Outdated

* forgot to commit this

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-17 20:54:50 -07:00
Tiramify (A.K. Daniel)
065713aeca Add types for toBeOdd & toBeEven (#3344) 2023-06-17 14:05:28 -07:00
Luigi Pinca
68c092aef2 Set the publishToSelf option to true (#3343)
All messages sent by the clients are expected to be received by all
clients. Without the `publishToSelf` option a message is not sent back
to the sender and the benchmark hangs.
2023-06-17 14:05:11 -07:00
Dylan Conway
9b8054ae11 don't remove const if referenced before declaration (#3337) 2023-06-16 21:11:57 -07:00
Jarred Sumner
0591c6b4bb Fix make headers jun 15 edition 2023-06-15 23:00:57 -07:00
Kabir Goel
4a22fcd93c Fix typo in run.md (#3331) 2023-06-15 15:03:46 -07:00
Jarred Sumner
dc06caccaa Tweak CommonJS output (#3320)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-15 01:18:23 -07:00
Ciro Spaciari
e6d4b3a89a [Bun.serve] fix Bun.serve argument check (#3314)
* fixup checks

* throw when tls is not a object also fix socket

* fix error message

* null or undefined on tls option in Bun.serve or sockets should not throw

* add tests

* fix tests and socket validation

* remove unnecessary check

* add listen tests
2023-06-14 19:29:36 -07:00
Jarred Sumner
0f131a976e Update build-id 2023-06-14 08:37:33 -07:00
Jarred Sumner
7f535a20a2 Workaround issue with module.require = 2023-06-14 08:35:51 -07:00
Jarred Sumner
bac7526c03 Make Bun.argv the same as process.argv (#3310)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-14 04:01:28 -07:00
Jarred Sumner
c2a83f87d8 Remove redudant put 2023-06-14 03:25:43 -07:00
Jarred Sumner
333b3f6beb Prepare to support webkit debug build assertions 2023-06-14 03:24:39 -07:00
dave caruso
b7ff3b0745 document Bun.argv in typedefs (#3302) 2023-06-14 01:48:51 -07:00
Colin McDonnell
a1bb79f440 mock type changes (#3305)
* Update mock types and set bun-types@latest in bun init

* Remove mockfn methods from toplevel mock

* Remove comments
2023-06-13 22:28:31 -07:00
xxxhussein
171ba6327d fix TS5096 (#3256) 2023-06-13 17:42:29 -07:00
Jarred Sumner
2ab797ff75 lol 2023-06-13 10:54:51 -07:00
Jarred Sumner
bdb1b7124a Fix crash in CJS (#3294)
* Fix crash in CJS

* Add std.heap.ArenaAllocator

* Use our arena allocator

* Reduce JS parser memory usage and make HMR faster

* Write some comments

* fix test failure & clean up this code

* Update javascript.zig

* make arena usage safer

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-13 09:15:05 -07:00
Jarred Sumner
b93bdbb124 Add test 2023-06-13 07:29:02 -07:00
Alex Lam S.L
c8d06f04d3 workaround quote escape issues for bun run (#3290)
fixes #53
2023-06-13 05:38:10 -07:00
Dylan Conway
067a0235e4 handle unwrapping require in any expression (#3292) 2023-06-12 21:43:45 -07:00
Jarred Sumner
dbb2416542 Make mocks use FunctionPrototype (#3291)
* Make mocks use FunctionPrototype

* Fix static methods

* Fix types

* Update JSMockFunction.cpp

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-12 19:55:07 -07:00
dave caruso
51c093e24e typo in readline (#3286) 2023-06-12 07:41:54 -07:00
Keyhan Vakil
50a18b6bac doc: minor fixes (#3278)
* `bun link` only modifies `package.json` when `--save` is passed.
* clang-15 is a separate package from llvm-15.
2023-06-11 09:26:46 -07:00
Keyhan Vakil
9a8d9b5e91 add --save argument to install (#3277) 2023-06-11 07:10:55 -07:00
Jarred Sumner
ef65f3c305 Support using WTF::StringImpl from Zig (#3279)
* Fix `make headers`

* [JS parser] Fix bug with printing non-ascii import paths in ascii mode

* Introduce `bun.String`

* Add test for non-ascii imports & entry points

* Add comment

* Fix build issue

* Support HTTP server

* Make it print the same

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-11 05:26:37 -07:00
Jarred Sumner
02eafd5019 Make cold bun install use 2x less memory (#3271)
* Make cold `bun install` use 2x less memory

In this benchmark: https://github.com/orogene/orogene/blob/main/BENCHMARKS.md

This brings us from around 2.7 GB to 1.2 GB of memory

* Address comments

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-10 15:38:09 -07:00
Luigi Pinca
04cd6a82b8 Fix benchmark (#3276) 2023-06-10 11:39:26 -07:00
Jarred Sumner
a2ec2ea397 Fixes #3250 (#3269)
* Fixes #3250

We must call `EVP_MD_CTX_cleanup` because `EVP_MD_CTX` containers pointers inside to allocated memory

* Fix leak

* Update sha.zig

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-10 02:26:48 -07:00
paperluigis
f51878a8ec Fix wording and code example in docs for Bun.sleepSync (#3270) 2023-06-10 01:03:30 -07:00
Alex Lam S.L
f18423cf45 [install] fix lockfile fallback for life cycle scripts (#3265) 2023-06-09 21:02:37 -07:00
Dylan Conway
68b9731db2 Update writing.md (#3264) 2023-06-09 19:46:29 -07:00
Dylan Conway
76cf465cc2 toMatchObject and some asymmetric matchers (#3260)
* `toMatchObject` progress

* add `expect.stringContaining()`

* add `expect.stringMatching()`

* print asymmetric matchers

* cleanup

* return before printing if constructor value isn't there

* move matcher logic to cpp

* pretty format and tests

* fix formatting for snapshots

* format `stringContaining` and `stringMatching` like jest

* better test

* remove commented tests

* remove old property matcher code

* add types

* make sure all props are matched in arrays

* add `Bun.deepMatch`
2023-06-09 19:26:36 -07:00
Jarred Sumner
0f018ea215 Fixes #3206 (#3262)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-09 18:22:32 -07:00
Colin McDonnell
a8dc41cd9f Fix jest.fn type 2023-06-09 18:08:36 -07:00
Alex Lam S.L
dbcaa02d89 [install] fix life cycle scripts execution (#3235)
[install] fix life cycle scripts execution
- scripts from dependencies did not run during re-installation
- `bun.lockb` now contains data on life cycle scripts
- handle prior lockfile format by reading missing info from every `package.json`
- suppress spurious log output from tests
2023-06-10 03:30:43 +03:00
Colin McDonnell
e6b1574046 Clean up types 2023-06-09 17:23:06 -07:00
Colin McDonnell
5df26a6a9b Improve types for mocks (#3261)
* Add jest.fn to types

* Fix type-tests
2023-06-09 17:10:19 -07:00
Colin McDonnell
fc3331628e Clean up comments in types 2023-06-09 16:45:41 -07:00
Colin McDonnell
0ec70119f2 Add types for mocks 2023-06-09 16:44:29 -07:00
Jarred Sumner
bf518222d4 Implement mocks in bun:test (#3252)
* wip

* wip

* most of the code for mocks in bun:test

* finishing up

* Implement `toHaveBeenCalled` and `toHaveBeenCalledTimes(1)`

* Test

* visit

* results, not returnValues

* exact

* Update jest.zig

* A couple more tests

* Add jest.fn

* support resetting mocks

* Implement spyOn

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-09 16:38:06 -07:00
ytakhs
6565bd89d5 Fix to retain a newline after removing a package (#3231) 2023-06-09 08:42:38 -07:00
Ashcon Partovi
99485bec4c Fix tests that pass but generate annotation 2023-06-09 05:53:23 -07:00
Ashcon Partovi
0eb5103642 Fix missing JSC.markBinding 2023-06-09 05:40:44 -07:00
James Liu
edd03341b1 docs: add missing right parenthesis in example code (#3245)
add missing right parenthesis in example code in `HTTP server` section
2023-06-09 05:20:37 -07:00
Alex Lam S.L
1d2f06b37e replace sudo usage in GitHub Actions (#3254) 2023-06-09 11:33:22 +03:00
dave caruso
870e5ac1dc improve stream types (#3240) 2023-06-07 14:45:14 -07:00
Jarred Sumner
7e296a1adc [breaking][bun:sqlite] .values() returns [] instead of null for queries returning 0 results (#3219)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-06 23:52:23 -07:00
Jarred Sumner
b9a705f84b add buffer label (#3220)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-06 23:51:05 -07:00
Colin McDonnell
d265ed80d2 Docs for Bun.password and ws publish (#3227)
* Update websocket docs & jsdoc

* Document Bun.password

* Update hash encoding docs

* Fix typos

* Add info about user-specific data in ws

* Update outdated websocket jsdoc

* Replace usages of req.url

* Remove log
2023-06-06 23:50:43 -07:00
dave caruso
fa3cfd34cb yeah (#3229) 2023-06-06 23:48:13 -07:00
Colin McDonnell
bcd67c3455 Bun.passwordSync -> Bun.password.{method}Sync (#3228)
* Bun.passwordSync -> Bun.password.{method}Sync

* Update jsdoc

* Updates
2023-06-06 23:44:40 -07:00
Jarred Sumner
ec71e7afe4 Rename bun-link-lld-debug to link 2023-06-05 18:14:44 -07:00
dave caruso
17bca62df1 add a test for lodash-es (#3217)
* add bundling tests for lodash-es

* add isBuffer tests
2023-06-05 17:38:03 -07:00
Jarred Sumner
0c11762c31 [node:vm] Fix crash when new ArrayBuffer() is returned 2023-06-05 17:17:48 -07:00
Dylan Conway
fe7d5357d8 allow v flag in regexp literal (#3213)
* add v to possible regexp flags

* alphabetical
2023-06-05 13:33:02 -07:00
Dylan Conway
568f170e12 [transpiler] Fix new length for raw template contents (#3215)
* use correct length for raw template contents

* tests for raw template contents
2023-06-05 12:55:56 -07:00
Jarred Sumner
c87d65856c [Inspector] Introduce inspector: true in Bun.serve()
This exposes the WebKit inspector debugger protocol over WebSockets at the endpoint `/bun:inspect` when `Bun.serve()`.

To enable, pass:
```js
Bun.serve({inspector: true, development: true, fetch(req){ /* rest of params *... });
```

Both `development` and `inspector` must be true, as this is very security sensitive to expose publicly.
2023-06-05 04:31:13 -07:00
Jarred Sumner
9b996e702e Implement Bun.password and Bun.passwordSync (#3204)
* Implement `Bun.password.{verify, hash}` and `Bun.passwordSync.{verify, hash}`

* flip the booleans

* delete unused

* Add `cost` for `"bcrypt"`, add `"memoryCost"` and `"timeCost'` for argon2, use SHA512

* Update bun.zig

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-04 18:20:04 -07:00
Dylan Conway
2cb1376a93 removeAllListeners return this (#3208)
* return this in `removeAllListeners`

* move `UNUSED_PARAM` for used params
2023-06-04 18:19:41 -07:00
Jarred Sumner
1f3da24fe0 [Transpiler] Fix normalizing \r\n in template string literals (#3209) 2023-06-04 18:07:38 -07:00
449 changed files with 54120 additions and 88414 deletions

View File

@@ -36,7 +36,7 @@ jobs:
arch: aarch64
build_arch: arm64
runner: linux-arm64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-linux-arm64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-linux-arm64-lto.tar.gz"
webkit_basename: "bun-webkit-linux-arm64-lto"
build_machine_arch: aarch64

View File

@@ -46,7 +46,7 @@ jobs:
arch: x86_64
build_arch: amd64
runner: big-ubuntu
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-linux-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-linux-amd64-lto.tar.gz"
webkit_basename: "bun-webkit-linux-amd64-lto"
build_machine_arch: x86_64
- cpu: nehalem
@@ -54,7 +54,7 @@ jobs:
arch: x86_64
build_arch: amd64
runner: big-ubuntu
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-linux-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-linux-amd64-lto.tar.gz"
webkit_basename: "bun-webkit-linux-amd64-lto"
build_machine_arch: x86_64
@@ -187,8 +187,8 @@ jobs:
unzip bun-${{matrix.tag}}.zip
cd bun-${{matrix.tag}}
chmod +x bun
sudo mv bun /usr/local/bin/bun
bun --version
pwd >> $GITHUB_PATH
./bun --version
- id: test
name: Test (node runner)
# if: ${{github.event.inputs.use_bun == 'false'}}

View File

@@ -117,7 +117,7 @@ jobs:
# obj: bun-obj-darwin-x64-baseline
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: true
# compile_obj: false
# - cpu: haswell
@@ -126,7 +126,7 @@ jobs:
# obj: bun-obj-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: true
# compile_obj: false
# - cpu: nehalem
@@ -135,7 +135,7 @@ jobs:
# obj: bun-obj-darwin-x64-baseline
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: false
# compile_obj: true
# - cpu: haswell
@@ -144,7 +144,7 @@ jobs:
# obj: bun-obj-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: false
# compile_obj: true
- cpu: native
@@ -152,7 +152,7 @@ jobs:
tag: bun-darwin-aarch64
obj: bun-obj-darwin-aarch64
artifact: bun-obj-darwin-aarch64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-arm64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-arm64-lto.tar.gz"
runner: macos-arm64
dependencies: true
compile_obj: true
@@ -173,9 +173,9 @@ jobs:
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
run: |
brew install ccache rust llvm@15 pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config esbuild --force
echo "export PATH=$(brew --prefix ccache)/bin:\$PATH" >> $GITHUB_ENV
echo "export PATH=$(brew --prefix coreutils)/libexec/gnubin:\$PATH" >> $GITHUB_ENV
echo "export PATH=$(brew --prefix llvm@15)/bin:\$PATH" >> $GITHUB_ENV
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@15)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@15
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
@@ -257,7 +257,7 @@ jobs:
# package: bun-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# - cpu: haswell
# arch: x86_64
# tag: bun-darwin-x64
@@ -265,14 +265,14 @@ jobs:
# package: bun-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
- cpu: native
arch: aarch64
tag: bun-darwin-aarch64
obj: bun-obj-darwin-aarch64
package: bun-darwin-aarch64
artifact: bun-obj-darwin-aarch64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-arm64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-arm64-lto.tar.gz"
runner: macos-arm64
steps:
- uses: actions/checkout@v3
@@ -291,8 +291,8 @@ jobs:
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
run: |
brew install rust ccache llvm@15 pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config esbuild --force
echo "export PATH=$(brew --prefix coreutils)/libexec/gnubin:\$PATH" >> $GITHUB_ENV
echo "export PATH=$(brew --prefix llvm@15)/bin:\$PATH" >> $GITHUB_ENV
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@15)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@15
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
@@ -397,7 +397,7 @@ jobs:
runs-on: ${{ matrix.runner }}
needs: [macOS]
if: github.event_name == 'pull_request' && github.repository_owner == 'oven-sh'
timeout-minutes: 10
timeout-minutes: 30
outputs:
failing_tests: ${{ steps.test.outputs.failing_tests }}
failing_tests_count: ${{ steps.test.outputs.failing_tests_count }}
@@ -426,8 +426,8 @@ jobs:
unzip ${{matrix.tag}}.zip
cd ${{matrix.tag}}
chmod +x bun
sudo mv bun /usr/local/bin/bun
bun --version
pwd >> $GITHUB_PATH
./bun --version
- id: test
name: Test (node runner)
# if: ${{github.event.inputs.use_bun == 'false'}}

View File

@@ -117,7 +117,7 @@ jobs:
obj: bun-obj-darwin-x64-baseline
runner: macos-11
artifact: bun-obj-darwin-x64-baseline
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
dependencies: true
compile_obj: false
# - cpu: haswell
@@ -126,7 +126,7 @@ jobs:
# obj: bun-obj-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: true
# compile_obj: false
- cpu: nehalem
@@ -135,7 +135,7 @@ jobs:
obj: bun-obj-darwin-x64-baseline
runner: macos-11
artifact: bun-obj-darwin-x64-baseline
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
dependencies: false
compile_obj: true
# - cpu: haswell
@@ -144,7 +144,7 @@ jobs:
# obj: bun-obj-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: false
# compile_obj: true
# - cpu: native
@@ -152,7 +152,7 @@ jobs:
# tag: bun-darwin-aarch64
# obj: bun-obj-darwin-aarch64
# artifact: bun-obj-darwin-aarch64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# runner: macos-arm64
# dependencies: true
# compile_obj: true
@@ -173,9 +173,9 @@ jobs:
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
run: |
brew install ccache rust llvm@15 pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config esbuild --force
echo "export PATH=$(brew --prefix ccache)/bin:\$PATH" >> $GITHUB_ENV
echo "export PATH=$(brew --prefix coreutils)/libexec/gnubin:\$PATH" >> $GITHUB_ENV
echo "export PATH=$(brew --prefix llvm@15)/bin:\$PATH" >> $GITHUB_ENV
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@15)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@15
- name: ccache (dependencies)
uses: hendrikmuhs/ccache-action@v1.2
@@ -258,7 +258,7 @@ jobs:
package: bun-darwin-x64
runner: macos-11
artifact: bun-obj-darwin-x64-baseline
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# - cpu: haswell
# arch: x86_64
# tag: bun-darwin-x64
@@ -266,14 +266,14 @@ jobs:
# package: bun-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# - cpu: native
# arch: aarch64
# tag: bun-darwin-aarch64
# obj: bun-obj-darwin-aarch64
# package: bun-darwin-aarch64
# artifact: bun-obj-darwin-aarch64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# runner: macos-arm64
steps:
- uses: actions/checkout@v3
@@ -292,8 +292,8 @@ jobs:
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
run: |
brew install ccache rust llvm@15 pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config esbuild --force
echo "export PATH=$(brew --prefix coreutils)/libexec/gnubin:\$PATH" >> $GITHUB_ENV
echo "export PATH=$(brew --prefix llvm@15)/bin:\$PATH" >> $GITHUB_ENV
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@15)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@15
- name: ccache (link)
uses: hendrikmuhs/ccache-action@v1.2
@@ -430,8 +430,8 @@ jobs:
unzip ${{matrix.tag}}.zip
cd ${{matrix.tag}}
chmod +x bun
sudo mv bun /usr/local/bin/bun
bun --version
pwd >> $GITHUB_PATH
./bun --version
- id: test
name: Test (node runner)
# if: ${{github.event.inputs.use_bun == 'false'}}

View File

@@ -117,7 +117,7 @@ jobs:
# obj: bun-obj-darwin-x64-baseline
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: true
# compile_obj: false
- cpu: haswell
@@ -126,7 +126,7 @@ jobs:
obj: bun-obj-darwin-x64
runner: macos-11
artifact: bun-obj-darwin-x64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
dependencies: true
compile_obj: false
# - cpu: nehalem
@@ -135,7 +135,7 @@ jobs:
# obj: bun-obj-darwin-x64-baseline
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: false
# compile_obj: true
- cpu: haswell
@@ -144,7 +144,7 @@ jobs:
obj: bun-obj-darwin-x64
runner: macos-11
artifact: bun-obj-darwin-x64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
dependencies: false
compile_obj: true
# - cpu: native
@@ -152,7 +152,7 @@ jobs:
# tag: bun-darwin-aarch64
# obj: bun-obj-darwin-aarch64
# artifact: bun-obj-darwin-aarch64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-arm64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-arm64-lto.tar.gz"
# runner: macos-arm64
# dependencies: true
# compile_obj: true
@@ -173,8 +173,8 @@ jobs:
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
run: |
brew install rust ccache llvm@15 pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config esbuild --force
echo "export PATH=$(brew --prefix coreutils)/libexec/gnubin:\$PATH" >> $GITHUB_ENV
echo "export PATH=$(brew --prefix llvm@15)/bin:\$PATH" >> $GITHUB_ENV
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@15)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@15
- name: Download WebKit
if: matrix.compile_obj
@@ -260,7 +260,7 @@ jobs:
# package: bun-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
- cpu: haswell
arch: x86_64
tag: bun-darwin-x64
@@ -268,14 +268,14 @@ jobs:
package: bun-darwin-x64
runner: macos-11
artifact: bun-obj-darwin-x64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# - cpu: native
# arch: aarch64
# tag: bun-darwin-aarch64
# obj: bun-obj-darwin-aarch64
# package: bun-darwin-aarch64
# artifact: bun-obj-darwin-aarch64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20/bun-webkit-macos-arm64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-arm64-lto.tar.gz"
# runner: macos-arm64
steps:
- uses: actions/checkout@v3
@@ -294,8 +294,8 @@ jobs:
BUN_DEPS_OUT_DIR: ${{runner.temp}}/bun-deps
run: |
brew install rust ccache llvm@15 pkg-config coreutils libtool cmake libiconv automake openssl@1.1 ninja gnu-sed pkg-config esbuild --force
echo "export PATH=$(brew --prefix coreutils)/libexec/gnubin:\$PATH" >> $GITHUB_ENV
echo "export PATH=$(brew --prefix llvm@15)/bin:\$PATH" >> $GITHUB_ENV
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
echo "$(brew --prefix llvm@15)/bin" >> $GITHUB_PATH
brew link --overwrite llvm@15
- name: Download WebKit
env:
@@ -432,8 +432,8 @@ jobs:
unzip ${{matrix.tag}}.zip
cd ${{matrix.tag}}
chmod +x bun
sudo mv bun /usr/local/bin/bun
bun --version
pwd >> $GITHUB_PATH
./bun --version
- id: test
name: Test (node runner)
# if: ${{github.event.inputs.use_bun == 'false'}}

View File

@@ -1,4 +1,4 @@
name: bun-release-canary
name: bun-release-types-canary
concurrency: release-canary
on:
push:

View File

@@ -1,7 +1,7 @@
name: zig-fmt
env:
ZIG_VERSION: 0.11.0-dev.2571+31738de28
ZIG_VERSION: 0.11.0-dev.3737+9eb008717
on:
pull_request:
@@ -28,7 +28,7 @@ jobs:
run: |
curl https://ziglang.org/builds/zig-linux-x86_64-${{env.ZIG_VERSION}}.tar.xz -L -o zig.tar.xz
tar -xf zig.tar.xz
sudo mv zig-linux-x86_64-${{env.ZIG_VERSION}}/zig /usr/local/bin
echo "$(pwd)/zig-linux-x86_64-${{env.ZIG_VERSION}}" >> $GITHUB_PATH
- name: Run zig fmt
id: fmt
run: |

2
.gitignore vendored
View File

@@ -121,3 +121,5 @@ cold-jsc-start
cold-jsc-start.d
/test.ts
src/js/out/modules_dev

View File

@@ -6,7 +6,7 @@ module.exports = {
quoteProps: "preserve",
overrides: [
{
files: "README.md",
files: ["*.md"],
options: {
printWidth: 80,
},

View File

@@ -19,11 +19,11 @@
"${workspaceFolder}/src/js/out",
"${workspaceFolder}/src/deps/boringssl/include/",
"${workspaceFolder}/src/deps",
"${workspaceFolder}/src/deps/uws/uSockets/src",
"${workspaceFolder}/src/deps/uws/src"
"${workspaceFolder}/src/deps/uws/uSockets/src"
],
"browse": {
"path": [
"${workspaceFolder}/../webkit-build/include/",
"${workspaceFolder}/bun-webkit/include/",
"${workspaceFolder}/src/bun.js/WebKit/WebKitBuild/Release/",
"${workspaceFolder}/src/bun.js/WebKit/WebKitBuild/Release/ICU/Headers/",
@@ -39,8 +39,7 @@
"${workspaceFolder}/src/bun.js/modules/*",
"${workspaceFolder}/src/deps",
"${workspaceFolder}/src/deps/boringssl/include/",
"${workspaceFolder}/src/deps/uws/uSockets/src",
"${workspaceFolder}/src/deps/uws/src"
"${workspaceFolder}/src/deps/uws/uSockets/src"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ".vscode/cppdb"

14
.vscode/launch.json generated vendored
View File

@@ -136,20 +136,6 @@
"initCommands": ["process handle -p false -s false -n false SIGHUP"],
"console": "internalConsole"
},
{
"type": "lldb",
"request": "launch",
"name": "bun run [Inspect]",
"program": "bun-debug",
"args": ["--inspect-brk", "${file}"],
"cwd": "${fileDirname}",
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1"
},
"initCommands": ["process handle -p false -s false -n false SIGHUP"],
"console": "internalConsole"
},
{
"type": "lldb",
"request": "launch",

View File

@@ -10,9 +10,9 @@ ARG ARCH=x86_64
ARG BUILD_MACHINE_ARCH=x86_64
ARG TRIPLET=${ARCH}-linux-gnu
ARG BUILDARCH=amd64
ARG WEBKIT_TAG=may20
ARG WEBKIT_TAG=may20-1
ARG ZIG_TAG=jul1
ARG ZIG_VERSION="0.11.0-dev.2571+31738de28"
ARG ZIG_VERSION="0.11.0-dev.3737+9eb008717"
ARG WEBKIT_BASENAME="bun-webkit-linux-$BUILDARCH"
ARG ZIG_FOLDERNAME=zig-linux-${BUILD_MACHINE_ARCH}-${ZIG_VERSION}

View File

@@ -561,6 +561,9 @@ builtins:
esm:
NODE_ENV=production bun src/js/build-esm.ts
esm-debug:
BUN_DEBUG_QUIET_LOGS=1 NODE_ENV=production bun-debug src/js/build-esm.ts
.PHONY: generate-builtins
generate-builtins: builtins
@@ -1085,7 +1088,7 @@ dev-obj-linux:
$(ZIG) build obj -Dtarget=x86_64-linux-gnu -Dcpu="$(CPU_TARGET)"
.PHONY: dev
dev: mkdir-dev esm dev-obj bun-link-lld-debug
dev: mkdir-dev esm dev-obj link
mkdir-dev:
mkdir -p $(DEBUG_PACKAGE_DIR)
@@ -1356,15 +1359,21 @@ mimalloc-wasm:
cd $(BUN_DEPS_DIR)/mimalloc; emcmake cmake -DMI_BUILD_SHARED=OFF -DMI_BUILD_STATIC=ON -DMI_BUILD_TESTS=OFF -DMI_BUILD_OBJECT=ON ${MIMALLOC_OVERRIDE_FLAG} -DMI_USE_CXX=ON .; emmake make;
cp $(BUN_DEPS_DIR)/mimalloc/$(MIMALLOC_INPUT_PATH) $(BUN_DEPS_OUT_DIR)/$(MIMALLOC_FILE).wasm
bun-link-lld-debug:
# alias for link, incase anyone still types that
.PHONY: bun-link-lld-debug
bun-link-lld-debug: link
# link a debug build of bun
.PHONY: link
link:
$(CXX) $(BUN_LLD_FLAGS_DEBUG) $(DEBUG_FLAGS) $(SYMBOLS) \
-g \
$(DEBUG_BIN)/bun-debug.o \
-W \
-o $(DEBUG_BIN)/bun-debug
@rm -f $(DEBUG_BIN)/bun-debug.o.o 2> /dev/null # workaround for https://github.com/ziglang/zig/issues/14080
@rm -f $(DEBUG_BIN)/bun-debug.o.o 2> /dev/null # workaround for https://github.com/ziglang/zig/issues/14080
bun-link-lld-debug-no-jsc:
link-no-jsc:
$(CXX) $(BUN_LLD_FLAGS_WITHOUT_JSC) $(SYMBOLS) \
-g \
$(DEBUG_BIN)/bun-debug.o \

View File

@@ -128,27 +128,27 @@ pub fn main() anyerror!void {
counters[counter].timestamp = @truncate(u64, @intCast(u128, std.time.nanoTimestamp()) / (std.time.ns_per_ms / 10));
counters[counter].rotate = rotate % 360;
counters[counter].percent = std.math.mod(f64, std.math.round(((progress_bar + 1.0) / destination_count) * 1000) / 1000, 100) catch 0;
counters[counter].color_values[0] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[0][0] + 1) % 256)) * 0.8));
counters[counter].color_values[1] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[0][1] + 1) % 256)) * 0.8));
counters[counter].color_values[2] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[0][2] + 1) % 256)) * 0.8));
counters[counter].color_values[0] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[0][0] + 1) % 256)) * 0.8));
counters[counter].color_values[1] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[0][1] + 1) % 256)) * 0.8));
counters[counter].color_values[2] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[0][2] + 1) % 256)) * 0.8));
counters[counter].color_values[3] = (colors[0][0] + 1) % 256;
counters[counter].color_values[4] = (colors[0][1] + 1) % 256;
counters[counter].color_values[5] = (colors[0][2] + 1) % 256;
counters[counter].color_values[6] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[1][0] + 1) % 256)) * 0.8));
counters[counter].color_values[7] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[1][1] + 1) % 256)) * 0.8));
counters[counter].color_values[8] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[1][2] + 1) % 256)) * 0.8));
counters[counter].color_values[6] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[1][0] + 1) % 256)) * 0.8));
counters[counter].color_values[7] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[1][1] + 1) % 256)) * 0.8));
counters[counter].color_values[8] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[1][2] + 1) % 256)) * 0.8));
counters[counter].color_values[9] = (colors[1][0] + 1) % 256;
counters[counter].color_values[10] = (colors[1][1] + 1) % 256;
counters[counter].color_values[11] = (colors[1][2] + 1) % 256;
counters[counter].color_values[12] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[2][0] + 1) % 256)) * 0.8));
counters[counter].color_values[13] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[2][1] + 1) % 256)) * 0.8));
counters[counter].color_values[14] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[2][2] + 1) % 256)) * 0.8));
counters[counter].color_values[12] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[2][0] + 1) % 256)) * 0.8));
counters[counter].color_values[13] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[2][1] + 1) % 256)) * 0.8));
counters[counter].color_values[14] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[2][2] + 1) % 256)) * 0.8));
counters[counter].color_values[15] = (colors[2][0] + 1) % 256;
counters[counter].color_values[16] = (colors[2][1] + 1) % 256;
counters[counter].color_values[17] = (colors[2][2] + 1) % 256;
counters[counter].color_values[18] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[3][0] + 1) % 256)) * 0.8));
counters[counter].color_values[19] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[3][1] + 1) % 256)) * 0.8));
counters[counter].color_values[20] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[3][2] + 1) % 256)) * 0.8));
counters[counter].color_values[18] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[3][0] + 1) % 256)) * 0.8));
counters[counter].color_values[19] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[3][1] + 1) % 256)) * 0.8));
counters[counter].color_values[20] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[3][2] + 1) % 256)) * 0.8));
counters[counter].color_values[21] = (colors[3][0] + 1) % 256;
counters[counter].color_values[22] = (colors[3][1] + 1) % 256;
counters[counter].color_values[23] = (colors[3][2] + 1) % 256;
@@ -203,7 +203,7 @@ pub fn main() anyerror!void {
_ = try recorder.wait();
all_timestamps[0] = wrote.len;
for (counters) |count, i| {
for (counters, 0..) |count, i| {
all_timestamps[i + 1] = count.timestamp;
}

View File

@@ -115,27 +115,27 @@ pub fn main() anyerror!void {
counters[counter].timestamp = @truncate(u64, @intCast(u128, std.time.nanoTimestamp()) / (std.time.ns_per_ms / 10));
counters[counter].rotate = rotate % 360;
counters[counter].percent = std.math.mod(f64, std.math.round(((progress_bar + 1.0) / destination_count) * 1000) / 1000, 100) catch 0;
counters[counter].color_values[0] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[0][0] + 1) % 256)) * 0.8));
counters[counter].color_values[1] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[0][1] + 1) % 256)) * 0.8));
counters[counter].color_values[2] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[0][2] + 1) % 256)) * 0.8));
counters[counter].color_values[0] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[0][0] + 1) % 256)) * 0.8));
counters[counter].color_values[1] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[0][1] + 1) % 256)) * 0.8));
counters[counter].color_values[2] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[0][2] + 1) % 256)) * 0.8));
counters[counter].color_values[3] = (colors[0][0] + 1) % 256;
counters[counter].color_values[4] = (colors[0][1] + 1) % 256;
counters[counter].color_values[5] = (colors[0][2] + 1) % 256;
counters[counter].color_values[6] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[1][0] + 1) % 256)) * 0.8));
counters[counter].color_values[7] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[1][1] + 1) % 256)) * 0.8));
counters[counter].color_values[8] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[1][2] + 1) % 256)) * 0.8));
counters[counter].color_values[6] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[1][0] + 1) % 256)) * 0.8));
counters[counter].color_values[7] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[1][1] + 1) % 256)) * 0.8));
counters[counter].color_values[8] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[1][2] + 1) % 256)) * 0.8));
counters[counter].color_values[9] = (colors[1][0] + 1) % 256;
counters[counter].color_values[10] = (colors[1][1] + 1) % 256;
counters[counter].color_values[11] = (colors[1][2] + 1) % 256;
counters[counter].color_values[12] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[2][0] + 1) % 256)) * 0.8));
counters[counter].color_values[13] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[2][1] + 1) % 256)) * 0.8));
counters[counter].color_values[14] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[2][2] + 1) % 256)) * 0.8));
counters[counter].color_values[12] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[2][0] + 1) % 256)) * 0.8));
counters[counter].color_values[13] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[2][1] + 1) % 256)) * 0.8));
counters[counter].color_values[14] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[2][2] + 1) % 256)) * 0.8));
counters[counter].color_values[15] = (colors[2][0] + 1) % 256;
counters[counter].color_values[16] = (colors[2][1] + 1) % 256;
counters[counter].color_values[17] = (colors[2][2] + 1) % 256;
counters[counter].color_values[18] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[3][0] + 1) % 256)) * 0.8));
counters[counter].color_values[19] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[3][1] + 1) % 256)) * 0.8));
counters[counter].color_values[20] = @floatToInt(u32, std.math.round(@intToFloat(f64, ((colors[3][2] + 1) % 256)) * 0.8));
counters[counter].color_values[18] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[3][0] + 1) % 256)) * 0.8));
counters[counter].color_values[19] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[3][1] + 1) % 256)) * 0.8));
counters[counter].color_values[20] = @intFromFloat(u32, std.math.round(@floatFromInt(f64, ((colors[3][2] + 1) % 256)) * 0.8));
counters[counter].color_values[21] = (colors[3][0] + 1) % 256;
counters[counter].color_values[22] = (colors[3][1] + 1) % 256;
counters[counter].color_values[23] = (colors[3][2] + 1) % 256;
@@ -190,7 +190,7 @@ pub fn main() anyerror!void {
_ = try recorder.wait();
all_timestamps[0] = wrote.len;
for (counters) |count, i| {
for (counters, 0..) |count, i| {
all_timestamps[i + 1] = count.timestamp;
}

View File

@@ -0,0 +1,65 @@
// This is a stress test of some internals in How Bun does the module.exports assignment.
// If it crashes or throws then this fails
import("./runner.mjs").then(({ bench, run }) => {
bench("Object.defineProperty(module, 'exports', { get() { return 42; } })", () => {
Object.defineProperty(module, "exports", {
get() {
return 42;
},
set() {
throw new Error("bad");
},
configurable: true,
});
if (module.exports !== 42) throw new Error("bad");
if (!Object.getOwnPropertyDescriptor(module, "exports").get) throw new Error("bad");
});
bench("Object.defineProperty(module.exports = {})", () => {
Object.defineProperty(module, "exports", {
value: { abc: 123 },
});
if (!module.exports.abc) throw new Error("bad");
if (Object.getOwnPropertyDescriptor(module, "exports").value !== module.exports) throw new Error("bad");
});
bench("module.exports = {}", () => {
module.exports = { abc: 123 };
if (!module.exports.abc) throw new Error("bad");
if (Object.getOwnPropertyDescriptor(module, "exports").value !== module.exports) throw new Error("bad");
});
run().then(() => {
module.exports = {
a: 1,
};
console.log(
module?.exports,
require.cache[module.id].exports,
module?.exports === require.cache[module.id],
__dirname,
Object.keys(require(module.id)),
require(module.id),
);
module.exports = function lol() {
return 42;
};
console.log(module.exports, module.exports());
queueMicrotask(() => {
console.log(
module?.exports,
require.cache[module.id].exports,
module?.exports === require.cache[module.id]?.exports,
__dirname,
Object.keys(require(module.id)),
require(module.id),
);
});
});
});

View File

@@ -1,4 +1,10 @@
import { realpathSync } from "node:fs";
const count = parseInt(process.env.ITERATIONS || "1", 10) || 1;
const arg = process.argv[process.argv.length - 1];
for (let i = 0; i < count; i++) realpathSync(arg);
import { bench, run } from "./runner.mjs";
bench("realpathSync x " + count, () => {
for (let i = 0; i < count; i++) realpathSync(arg, "utf-8");
});
await run();

View File

@@ -0,0 +1,60 @@
import { bench, run } from "./runner.mjs";
function deprecateUsingClosure(fn, msg, code) {
if (process.noDeprecation === true) {
return fn;
}
var realFn = fn;
var wrapper = () => {
return fnToWrap.apply(this, arguments);
};
var deprecater = () => {
if (process.throwDeprecation) {
var err = new Error(msg);
if (code) err.code = code;
throw err;
} else if (process.traceDeprecation) {
console.trace(msg);
} else {
console.error(msg);
}
fnToWrap = realFn;
return realFn.apply(this, arguments);
};
var fnToWrap = deprecater;
return wrapper;
}
function deprecateOriginal(fn, msg) {
var warned = false;
function deprecated() {
if (!warned) {
if (process.throwDeprecation) {
throw new Error(msg);
} else if (process.traceDeprecation) {
console.trace(msg);
} else {
console.error(msg);
}
warned = true;
}
return fn.apply(this, arguments);
}
return deprecated;
}
const deprecatedy = deprecateUsingClosure(() => {}, "This is deprecated", "DEP0001");
const deprecatedy2 = deprecateOriginal(() => {}, "This is deprecated");
bench("deprecateUsingClosure", () => {
deprecatedy(Math.random() + 1);
});
bench("deprecateOriginal", () => {
deprecatedy2(Math.random() + 1);
});
await run();

View File

@@ -32,6 +32,7 @@ const server = Bun.serve({
},
perMessageDeflate: false,
publishToSelf: true,
},
fetch(req, server) {

View File

@@ -42,4 +42,4 @@ function sendReadyMessage() {
console.log(`Waiting for ${CLIENTS_TO_WAIT_FOR} clients to connect..`);
Deno.serve(reqHandler, { port });
Deno.serve({ port }, reqHandler);

View File

@@ -1,4 +1,5 @@
const std = @import("std");
const Wyhash = @import("./src/wyhash.zig").Wyhash;
fn moduleSource(comptime out: []const u8) FileSource {
if (comptime std.fs.path.dirname(@src().file)) |base| {
@@ -76,13 +77,13 @@ const BunBuildOptions = struct {
pub fn updateRuntime(this: *BunBuildOptions) anyerror!void {
var runtime_out_file = try std.fs.cwd().openFile("src/runtime.out.js", .{ .mode = .read_only });
const runtime_hash = std.hash.Wyhash.hash(
const runtime_hash = Wyhash.hash(
0,
try runtime_out_file.readToEndAlloc(std.heap.page_allocator, try runtime_out_file.getEndPos()),
);
this.runtime_js_version = runtime_hash;
var fallback_out_file = try std.fs.cwd().openFile("src/fallback.out.js", .{ .mode = .read_only });
const fallback_hash = std.hash.Wyhash.hash(
const fallback_hash = Wyhash.hash(
0,
try fallback_out_file.readToEndAlloc(std.heap.page_allocator, try fallback_out_file.getEndPos()),
);
@@ -192,12 +193,12 @@ pub fn build(b: *Build) !void {
else
"root.zig";
const min_version: std.builtin.Version = if (target.getOsTag() != .freestanding)
const min_version: std.SemanticVersion = if (target.getOsTag() != .freestanding)
target.getOsVersionMin().semver
else
.{ .major = 0, .minor = 0, .patch = 0 };
const max_version: std.builtin.Version = if (target.getOsTag() != .freestanding)
const max_version: std.SemanticVersion = if (target.getOsTag() != .freestanding)
target.getOsVersionMax().semver
else
.{ .major = 0, .minor = 0, .patch = 0 };

BIN
bun.lockb

Binary file not shown.

View File

@@ -202,6 +202,53 @@ const response = await fetch("https://bun.sh");
await Bun.write("index.html", response);
```
## Incremental writing with `FileSink`
Bun provides a native incremental file writing API called `FileSink`. To retrieve a `FileSink` instance from a `BunFile`:
```ts
const file = Bun.file("output.txt");
const writer = file.writer();
```
To incrementally write to the file, call `.write()`.
```ts
const file = Bun.file("output.txt");
const writer = file.writer();
writer.write("it was the best of times\n");
writer.write("it was the worst of times\n");
```
These chunks will be buffered internally. To flush the buffer to disk, use `.flush()`. This returns the number of flushed bytes.
```ts
writer.flush(); // write buffer to disk
```
The buffer will also auto-flush when the `FileSink`'s _high water mark_ is reached; that is, when its internal buffer is full. This value can be configured.
```ts
const file = Bun.file("output.txt");
const writer = file.writer({ highWaterMark: 1024 * 1024 }); // 1MB
```
To flush the buffer and close the file:
```ts
writer.end();
```
Note that, by default, the `bun` process will stay alive until this `FileSink` is explicitly closed with `.end()`. To opt out of this behavior, you can "unref" the instance.
```ts
writer.unref();
// to "re-ref" it later
writer.ref();
```
## Benchmarks
The following is a 3-line implementation of the Linux `cat` command.
@@ -250,5 +297,15 @@ interface BunFile {
stream(): Promise<ReadableStream>;
arrayBuffer(): Promise<ArrayBuffer>;
json(): Promise<any>;
writer(params: { highWaterMark?: number }): FileSink;
}
export interface FileSink {
write(chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer): number;
flush(): number | Promise<number>;
end(error?: Error): number | Promise<number>;
start(options?: { highWaterMark?: number }): void;
ref(): void;
unref(): void;
}
```

View File

@@ -4,6 +4,71 @@ Bun implements the `createHash` and `createHmac` functions from [`node:crypto`](
{% /callout %}
## `Bun.password`
{% callout %}
**Note** — Added in Bun 0.6.8.
{% /callout %}
`Bun.password` is a collection of utility functions for hashing and verifying passwords with various cryptographically secure algorithms.
```ts
const password = "super-secure-pa$$word";
const hash = await Bun.password.hash(password);
// => $argon2id$v=19$m=65536,t=2,p=1$tFq+9AVr1bfPxQdh6E8DQRhEXg/M/SqYCNu6gVdRRNs$GzJ8PuBi+K+BVojzPfS5mjnC8OpLGtv8KJqF99eP6a4
const isMatch = await Bun.password.verify(password, hash);
// => true
```
The second argument to `Bun.password.hash` accepts a params object that lets you pick and configure the hashing algorithm.
```ts
const password = "super-secure-pa$$word";
// use argon2 (default)
const argonHash = await Bun.password.hash(password, {
algorithm: "argon2id", // "argon2id" | "argon2i" | "argon2d"
memoryCost: 4, // memory usage in kibibytes
timeCost: 3, // the number of iterations
});
// use bcrypt
const bcryptHash = await Bun.password.hash(password, {
algorithm: "bcrypt",
cost: 4, // number between 4-31
});
```
The algorithm used to create the hash is stored in the hash itself. When using `bcrypt`, the returned hash is encoded in [Modular Crypt Format](https://passlib.readthedocs.io/en/stable/modular_crypt_format.html) for compatibility with most existing `bcrypt` implementations; with `argon2` the result is encoded in the newer [PHC format](https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md).
The `verify` function automatically detects the algorithm based on the input hash and use the correct verification method. It can correctly infer the algorithm from both PHC- or MCF-encoded hashes.
```ts
const password = "super-secure-pa$$word";
const hash = await Bun.password.hash(password, {
/* config */
});
const isMatch = await Bun.password.verify(password, hash);
// => true
```
Synchronous versions of all functions are also available. Keep in mind that these functions are computationally expensive, so using a blocking API may degrade application performance.
```ts
const password = "super-secure-pa$$word";
const hash = Bun.password.hashSync(password, {
/* config */
});
const isMatch = Bun.password.verifySync(password, hash);
// => true
```
## `Bun.hash`
`Bun.hash` is a collection of utilities for _non-cryptographic_ hashing. Non-cryptographic hashing algorithms are optimized for speed of computation over collision-resistance or security.

View File

@@ -125,8 +125,7 @@ Bun.serve({
// string
key: fs.readFileSync("./key.pem", "utf8"),
// array of above
key: [Bun.file('./key1.pem'), Bun.file('./key2.pem']
key: [Bun.file('./key1.pem'), Bun.file('./key2.pem')],
});
```

View File

@@ -75,16 +75,6 @@ Bun.sleepSync(1000); // blocks thread for one second
console.log("hello one second later!");
```
Alternatively, pass a `Date` object to receive a `Promise` that resolves at that point in time.
```ts
const oneSecondInFuture = new Date(Date.now() + 1000);
console.log("hello");
await Bun.sleep(oneSecondInFuture);
console.log("hello one second later!");
```
## `Bun.which()`
`Bun.which(bin: string)`

View File

@@ -12,41 +12,7 @@
Internally Bun's WebSocket implementation is built on [uWebSockets](https://github.com/uNetworking/uWebSockets).
{% /callout %}
## Connect to a WebSocket server
To connect to an external socket server, create an instance of `WebSocket` with the constructor.
```ts
const socket = new WebSocket("ws://localhost:3000");
```
Bun supports setting custom headers. This is a Bun-specific extension of the `WebSocket` standard.
```ts
const socket = new WebSocket("ws://localhost:3000", {
headers: {
// custom headers
},
});
```
To add event listeners to the socket:
```ts
// message is received
socket.addEventListener("message", event => {});
// socket opened
socket.addEventListener("open", event => {});
// socket closed
socket.addEventListener("close", event => {});
// error handler
socket.addEventListener("error", event => {});
```
## Create a WebSocket server
## Start a WebSocket server
Below is a simple WebSocket server built with `Bun.serve`, in which all incoming requests are [upgraded](https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism) to WebSocket connections in the `fetch` handler. The socket handlers are declared in the `websocket` parameter.
@@ -109,7 +75,7 @@ Bun.serve({
});
```
## Sending messages
### Sending messages
Each `ServerWebSocket` instance has a `.send()` method for sending messages to the client. It supports a range of input types.
@@ -119,7 +85,7 @@ ws.send(response.arrayBuffer()); // ArrayBuffer
ws.send(new Uint8Array([1, 2, 3])); // TypedArray | DataView
```
## Headers
### Headers
Once the upgrade succeeds, Bun will send a `101 Switching Protocols` response per the [spec](https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism). Additional `headers` can be attched to this `Response` in the call to `server.upgrade()`.
@@ -137,7 +103,7 @@ Bun.serve({
});
```
## Contextual data
### Contextual data
Contextual `data` can be attached to a new WebSocket in the `.upgrade()` call. This data is made available on the `ws.data` property inside the WebSocket handlers.
@@ -145,16 +111,20 @@ Contextual `data` can be attached to a new WebSocket in the `.upgrade()` call. T
type WebSocketData = {
createdAt: number;
channelId: string;
authToken: string;
};
// TypeScript: specify the type of `data`
Bun.serve<WebSocketData>({
fetch(req, server) {
// use a library to parse cookies
const cookies = parseCookies(req.headers.get("Cookie"));
server.upgrade(req, {
// TS: this object must conform to WebSocketData
// this object must conform to WebSocketData
data: {
createdAt: Date.now(),
channelId: new URL(req.url).searchParams.get("channelId"),
authToken: cookies["X-Token"],
},
});
@@ -163,53 +133,76 @@ Bun.serve<WebSocketData>({
websocket: {
// handler called when a message is received
async message(ws, message) {
ws.data; // WebSocketData
const user = getUserFromToken(ws.data.authToken);
await saveMessageToDatabase({
channel: ws.data.channelId,
message: String(message),
userId: user.id,
});
},
},
});
```
## Pub/Sub
To connect to this server from the browser, create a new `WebSocket`.
```ts#browser.js
const socket = new WebSocket("ws://localhost:3000/chat");
socket.addEventListener("message", event => {
console.log(event.data);
})
```
{% callout %}
**Identifying users** — The cookies that are currently set on the page will be sent with the WebSocket upgrade request and available on `req.headers` in the `fetch` handler. Parse these cookies to determine the identity of the connecting user and set the value of `data` accordingly.
{% /callout %}
### Pub/Sub
Bun's `ServerWebSocket` implementation implements a native publish-subscribe API for topic-based broadcasting. Individual sockets can `.subscribe()` to a topic (specified with a string identifier) and `.publish()` messages to all other subscribers to that topic. This topic-based broadcast API is similar to [MQTT](https://en.wikipedia.org/wiki/MQTT) and [Redis Pub/Sub](https://redis.io/topics/pubsub).
```ts
const pubsubserver = Bun.serve<{username: string}>({
const server = Bun.serve<{ username: string }>({
fetch(req, server) {
if (req.url === '/chat') {
const cookies = getCookieFromRequest(req);
const success = server.upgrade(req, {
data: {username: cookies.username},
});
const url = new URL(req.url);
if (url.pathname === "/chat") {
console.log(`upgrade!`);
const username = getUsernameFromReq(req);
const success = server.upgrade(req, { data: { username } });
return success
? undefined
: new Response('WebSocket upgrade error', {status: 400});
: new Response("WebSocket upgrade error", { status: 400 });
}
return new Response('Hello world');
return new Response("Hello world");
},
websocket: {
open(ws) {
ws.subscribe('the-group-chat');
ws.publish('the-group-chat', `${ws.data.username} has entered the chat`);
const msg = `${ws.data.username} has entered the chat`;
ws.subscribe("the-group-chat");
ws.publish("the-group-chat", msg);
},
message(ws, message) {
// this is a group chat
// so the server re-broadcasts incoming message to everyone
ws.publish('the-group-chat', `${ws.data.username}: ${message}`);
ws.publish("the-group-chat", `${ws.data.username}: ${message}`);
},
close(ws) {
ws.unsubscribe('the-group-chat');
ws.publish('the-group-chat', `${ws.data.username} has left the chat`);
const msg = `${ws.data.username} has left the chat`;
ws.unsubscribe("the-group-chat");
ws.publish("the-group-chat", msg);
},
},
});
console.log(`Listening on ${server.hostname}:${server.port}`);
```
## Compression
Calling `.publish(data)` will send the message to all subscribers of a topic _except_ the socket that called `.publish()`.
### Compression
Per-message [compression](https://websockets.readthedocs.io/en/stable/topics/compression.html) can be enabled with the `perMessageDeflate` parameter.
@@ -231,7 +224,7 @@ ws.send("Hello world", true);
For fine-grained control over compression characteristics, refer to the [Reference](#reference).
## Backpressure
### Backpressure
The `.send(message)` method of `ServerWebSocket` returns a `number` indicating the result of the operation.
@@ -241,6 +234,42 @@ The `.send(message)` method of `ServerWebSocket` returns a `number` indicating t
This gives you better control over backpressure in your server.
## Connect to a `Websocket` server
To connect to an external socket server, either from a browser or from Bun, create an instance of `WebSocket` with the constructor.
```ts
const socket = new WebSocket("ws://localhost:3000");
```
In browsers, the cookies that are currently set on the page will be sent with the WebSocket upgrade request. This is a standard feature of the `WebSocket` API.
For convenience, Bun lets you setting custom headers directly in the constructor. This is a Bun-specific extension of the `WebSocket` standard. _This will not work in browsers._
```ts
const socket = new WebSocket("ws://localhost:3000", {
headers: {
// custom headers
},
});
```
To add event listeners to the socket:
```ts
// message is received
socket.addEventListener("message", event => {});
// socket opened
socket.addEventListener("open", event => {});
// socket closed
socket.addEventListener("close", event => {});
// error handler
socket.addEventListener("error", event => {});
```
## Reference
```ts
@@ -248,7 +277,10 @@ namespace Bun {
export function serve(params: {
fetch: (req: Request, server: Server) => Response | Promise<Response>;
websocket?: {
message: (ws: ServerWebSocket, message: string | ArrayBuffer | Uint8Array) => void;
message: (
ws: ServerWebSocket,
message: string | ArrayBuffer | Uint8Array,
) => void;
open?: (ws: ServerWebSocket) => void;
close?: (ws: ServerWebSocket) => void;
error?: (ws: ServerWebSocket, error: Error) => void;
@@ -278,7 +310,11 @@ type Compressor =
interface Server {
pendingWebsockets: number;
publish(topic: string, data: string | ArrayBufferView | ArrayBuffer, compress?: boolean): number;
publish(
topic: string,
data: string | ArrayBufferView | ArrayBuffer,
compress?: boolean,
): number;
upgrade(
req: Request,
options?: {

View File

@@ -185,7 +185,7 @@ $ cd /path/to/my-app
$ bun link cool-pkg
```
This will add `cool-pkg` to the `dependencies` field of your app's package.json with a special version specifier that tells Bun to load from the registered local directory instead of installing from `npm`.
In addition, the `--save` flag can be used to add `cool-pkg` to the `dependencies` field of your app's package.json with a special version specifier that tells Bun to load from the registered local directory instead of installing from `npm`:
```json-diff
{

View File

@@ -102,7 +102,7 @@ To debug environment variables, run `bun run env` to view a list of resolved env
Bun is designed to start fast and run fast.
Under the hood Bun uses the [JavaScriptCore engine](https://developer.apple.com/documentation/javascriptcore), which is developed by Apple for Safari. In most cases, the startup and running performance is faster than V8, the engine used by Node.js and Chromium-based browsers. It's transpiler and runtime are written in Zig, a modern, high-performance language. On Linux, this translates into startup times [4x faster](https://twitter.com/jarredsumner/status/1499225725492076544) than Node.js.
Under the hood Bun uses the [JavaScriptCore engine](https://developer.apple.com/documentation/javascriptcore), which is developed by Apple for Safari. In most cases, the startup and running performance is faster than V8, the engine used by Node.js and Chromium-based browsers. Its transpiler and runtime are written in Zig, a modern, high-performance language. On Linux, this translates into startup times [4x faster](https://twitter.com/jarredsumner/status/1499225725492076544) than Node.js.
{% image src="/images/bun-run-speed.jpeg" caption="Bun vs Node.js vs Deno running Hello World" /%}

View File

@@ -77,6 +77,8 @@ Bun is compatible with popular UI testing libraries:
- [DOM Testing Library](https://testing-library.com/docs/dom-testing-library/intro/)
- [React Testing Library](https://testing-library.com/docs/react-testing-library/intro)
See [Test > DOM Testing](/docs/test/dom) for complete documentation.
## Performance
Bun's test runner is fast.

View File

@@ -190,6 +190,9 @@ export default {
page("test/snapshots", "Snapshots", {
description: "Add lifecycle hooks to your tests that run before/after each test or test run",
}),
page("test/dom", "DOM testing", {
description: "Write headless tests for UI and React/Vue/Svelte/Lit components with happy-dom",
}),
page("test/hot", "Watch mode", {
description: "Reload your tests automatically on change.",
}),

View File

@@ -42,7 +42,7 @@ $ brew install llvm@15
```bash#Ubuntu/Debian
# On Ubuntu 22.04 and newer, LLVM 15 is available in the default repositories
$ sudo apt install llvm-15 lld-15
$ sudo apt install llvm-15 lld-15 clang-15
# On older versions,
$ wget https://apt.llvm.org/llvm.sh -O - | sudo bash -s -- 15 all
```
@@ -102,7 +102,7 @@ Zig can be installed either with our npm package [`@oven/zig`](https://www.npmjs
```bash
$ bun install -g @oven/zig
$ zigup master
$ zigup 0.11.0-dev.3737+9eb008717
```
## Building

View File

@@ -108,8 +108,8 @@ Once it finds the `foo` package, Bun reads the `package.json` to determine how t
"worker": "./index.js",
"module": "./index.js",
"node": "./index.js",
"browser": "./index.js",
"default": "./index.js" // lowest priority
"default": "./index.js",
"browser": "./index.js" // lowest priority
}
}
```

75
docs/test/dom.md Normal file
View File

@@ -0,0 +1,75 @@
Bun's test runner plays well with existing component and DOM testing libraries, including React Testing Library and [`happy-dom`](https://github.com/capricorn86/happy-dom).
## `happy-dom`
For writing headless tests for your frontend code and components, we recommend [`happy-dom`](https://github.com/capricorn86/happy-dom). Happy DOM implements a complete set of HTML and DOM APIs in plain JavaScript, making it possible to simulate a browser environment with high fidelity.
To get started install the `@happy-dom/global-registrator` package as a dev dependency.
```bash
$ bun add -d @happy-dom/global-registrator
```
We'll be using Bun's _preload_ functionality to register the `happy-dom` globals before running our tests. This step will make browser APIs like `document` available in the global scope. Create a file called `happydom.ts` in the root of your project and add the following code:
```ts
import { GlobalRegistrator } from "@happy-dom/global-registrator";
GlobalRegistrator.register();
```
To preload this file before `bun test`, open or create a `bunfig.toml` file and add the following lines.
```toml
[test]
preload = "./happydom.ts"
```
This will execute `happydom.ts` when you run `bun test`. Now you can write tests that use browser APIs like `document` and `window`.
```ts#dom.test.ts
import {test, expect} from 'bun:test';
test('dom test', () => {
document.body.innerHTML = `<button>My button</button>`;
const button = document.querySelector('button');
expect(button?.innerText).toEqual('My button');
});
```
Depending on your `tsconfig.json` setup, you may see a `"Cannot find name 'document'"` type error in the code above. To "inject" the types for `document` and other browser APIs, add the following [triple-slash directive](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html) to the top of any test file.
```ts-diff#dom.test.ts
+ /// <reference lib="dom" />
import {test, expect} from 'bun:test';
test('dom test', () => {
document.body.innerHTML = `<button>My button</button>`;
const button = document.querySelector('button');
expect(button?.innerText).toEqual('My button');
});
```
Let's run this test with `bun test`:
```bash
$ bun test
bun test v0.x.y
dom.test.ts:
✓ dom test [0.82ms]
1 pass
0 fail
1 expect() calls
Ran 1 tests across 1 files. 1 total [125.00ms]
```
<!-- ## React Testing Library
Once you've set up `happy-dom` as described above, you can use it with React Testing Library. To get started, install the `@testing-library/react` package as a dev dependency.
```bash
$ bun add -d @testing-library/react
``` -->

View File

@@ -167,12 +167,12 @@ Bun implements the following matchers. Full Jest compatibility is on the roadmap
---
- 🔴
- 🟢
- [`.anything()`](https://jestjs.io/docs/expect#expectanything)
---
- 🔴
- 🟢
- [`.any()`](https://jestjs.io/docs/expect#expectanyconstructor)
---
@@ -202,12 +202,12 @@ Bun implements the following matchers. Full Jest compatibility is on the roadmap
---
- 🔴
- 🟢
- [`.stringContaining()`](https://jestjs.io/docs/expect#expectstringcontainingstring)
---
- 🔴
- 🟢
- [`.stringMatching()`](https://jestjs.io/docs/expect#expectstringmatchingstring--regexp)
---
@@ -227,12 +227,12 @@ Bun implements the following matchers. Full Jest compatibility is on the roadmap
---
- 🔴
- 🟢
- [`.toHaveBeenCalled()`](https://jestjs.io/docs/expect#tohavebeencalled)
---
- 🔴
- 🟢
- [`.toHaveBeenCalledTimes()`](https://jestjs.io/docs/expect#tohavebeencalledtimesnumber)
---
@@ -312,12 +312,12 @@ Bun implements the following matchers. Full Jest compatibility is on the roadmap
---
- 🔴
- 🟢
- [`.toMatch()`](https://jestjs.io/docs/expect#tomatchregexp--string)
---
- 🔴
- 🟢
- [`.toMatchObject()`](https://jestjs.io/docs/expect#tomatchobjectobject)
---

View File

@@ -3,7 +3,8 @@ import { parse } from "querystring";
export default {
fetch(req) {
if (req.url === "/favicon.ico") return new Response("nooo dont open favicon in editor", { status: 404 });
const url = new URL(req.url);
if (url.pathname === "/favicon.ico") return new Response("nooo dont open favicon in editor", { status: 404 });
var pathname = req.url.substring(1);
const q = pathname.indexOf("?");

View File

@@ -91,7 +91,7 @@ pub const Arguments = struct {
var raw_args: std.ArrayListUnmanaged(string) = undefined;
if (positionals.len > 0) {
raw_args = .{ .capacity = positionals.len, .items = @intToPtr([*][]const u8, @ptrToInt(positionals.ptr))[0..positionals.len] };
raw_args = .{ .capacity = positionals.len, .items = @ptrFromInt([*][]const u8, @intFromPtr(positionals.ptr))[0..positionals.len] };
} else {
raw_args = .{};
}

View File

@@ -95,7 +95,7 @@ pub const Arguments = struct {
var raw_args: std.ArrayListUnmanaged(string) = undefined;
if (positionals.len > 0) {
raw_args = .{ .capacity = positionals.len, .items = @intToPtr([*][]const u8, @ptrToInt(positionals.ptr))[0..positionals.len] };
raw_args = .{ .capacity = positionals.len, .items = @ptrFromInt([*][]const u8, @intFromPtr(positionals.ptr))[0..positionals.len] };
} else {
raw_args = .{};
}
@@ -244,7 +244,7 @@ pub fn main() anyerror!void {
const http = channel.readItem() catch continue;
read_count += 1;
Output.printElapsed(@floatCast(f64, @intToFloat(f128, http.elapsed) / std.time.ns_per_ms));
Output.printElapsed(@floatCast(f64, @floatFromInt(f128, http.elapsed) / std.time.ns_per_ms));
if (http.response) |resp| {
if (resp.status_code == 200) {
success_count += 1;
@@ -270,7 +270,7 @@ pub fn main() anyerror!void {
http.client.url.href,
http.response_buffer.list.items.len,
});
Output.printElapsed(@floatCast(f64, @intToFloat(f128, http.gzip_elapsed) / std.time.ns_per_ms));
Output.printElapsed(@floatCast(f64, @floatFromInt(f128, http.gzip_elapsed) / std.time.ns_per_ms));
Output.prettyError("<d> gzip)<r>\n", .{});
} else {
Output.prettyError(" <d>{s}<r><d> - {s}<r> <d>({d} bytes)<r>\n", .{
@@ -295,7 +295,7 @@ pub fn main() anyerror!void {
fail_count,
});
Output.printElapsed(@floatCast(f64, @intToFloat(f128, timer.read()) / std.time.ns_per_ms));
Output.printElapsed(@floatCast(f64, @floatFromInt(f128, timer.read()) / std.time.ns_per_ms));
Output.prettyErrorln(" {d} requests", .{
read_count,
});

View File

@@ -24,7 +24,7 @@
"@types/react": "^18.0.25",
"@typescript-eslint/eslint-plugin": "^5.31.0",
"@typescript-eslint/parser": "^5.31.0",
"bun-webkit": "0.0.1-b2f1006a06f81bc860c89dd4c7cec3e7117c4c4c"
"bun-webkit": "0.0.1-4b3750ddfe644a5bb131d652407653fac528ad51"
},
"version": "0.0.0",
"prettier": "./.prettierrc.cjs"

View File

@@ -1,169 +0,0 @@
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
# Logs
logs
_.log
npm-debug.log_
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# Runtime data
pids
_.pid
_.seed
\*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
\*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
\*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
\*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
.cache
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.\*

View File

@@ -1,3 +0,0 @@
# bun-devtools
A set of auto-generated TypeScript types for the WebKit debugger protocol.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -1,14 +0,0 @@
export namespace JSC {
/**
* @link https://github.com/WebKit/webkit/blob/main/Source/JavaScriptCore/heap/HeapSnapshotBuilder.h
*/
export type HeapSnapshot = {
version: 2;
type: "Inspector";
nodes: number[];
nodeClassNames: string[];
edges: number[];
edgeTypes: string[];
edgeNames: string[];
};
}

View File

@@ -1,30 +0,0 @@
export namespace V8 {
/**
* @link https://github.com/julianburr/chrome-heap-snapshot-parser/blob/master/index.js#L72
* @link https://stackoverflow.com/questions/69802133/chrome-heap-snapshot-structure-explanation
*/
export type HeapSnapshot = {
snapshot: {
meta: {
node_fields: string[];
node_types: [string[], ...string[]]; // ?
edge_fields: string[];
edge_types: [string[], ...string[]]; // ?
trace_function_info_fields: string[];
trace_node_fields: string[];
sample_fields: string[];
location_fields: string[];
node_count: number;
edge_count: number;
trace_function_count: number;
};
};
nodes: number[];
edges: number[];
trace_tree: unknown[];
trace_function_infos: unknown[];
samples: unknown[];
locations: number[];
strings: string[];
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +0,0 @@
export * from "./protocol/jsc";
export * from "./protocol/v8";

View File

@@ -1,24 +0,0 @@
{
"name": "bun-devtools",
"module": "./index.ts",
"version": "0.0.2",
"type": "module",
"exports": {
".": {
"import": "./index.ts",
"require": "./index.ts"
}
},
"scripts": {
"generate-protocol": "bun run scripts/generate-protocol.ts"
},
"files": [
"index.ts",
"package.json",
"tsconfig.json",
"protocol"
],
"peerDependencies": {
"typescript": "^5.0.0"
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,129 +0,0 @@
// A DevTools client for JavaScriptCore.
import type { JSC } from "..";
type ClientOptions = {
url: string | URL;
event?: (event: JSC.Event<keyof JSC.EventMap>) => void;
request?: (request: JSC.Request<keyof JSC.RequestMap>) => void;
response?: (response: JSC.Response<keyof JSC.ResponseMap>) => void;
};
class Client {
#webSocket: WebSocket;
#requestId: number;
#pendingMessages: string[];
#pendingRequests: Map<number, AbortController>;
#ready: Promise<void>;
constructor(options: ClientOptions) {
this.#webSocket = new WebSocket(options.url);
this.#requestId = 1;
this.#pendingMessages = [];
this.#pendingRequests = new Map();
this.#ready = new Promise((resolve, reject) => {
this.#webSocket.addEventListener("open", () => {
for (const message of this.#pendingMessages) {
this.#send(message);
}
this.#pendingMessages.length = 0;
resolve();
});
this.#webSocket.addEventListener("message", ({ data }) => {
let response;
try {
response = { ...JSON.parse(data) };
} catch {
console.error("Received an invalid message:", data);
return;
}
const { id, error, result, method, params } = response;
if (method && params) {
options.event?.(response);
} else if (id && (result || error)) {
try {
options.response?.(response);
} finally {
const abort = this.#pendingRequests.get(id ?? -1);
if (!abort) {
console.error("Received an unexpected message:", response);
return;
}
if (error) {
abort.abort(new Error(JSON.stringify(error)));
} else {
abort.abort(result);
}
}
} else {
console.error("Received an unexpected message:", response);
}
});
this.#webSocket.addEventListener("error", (error) => {
reject(error);
});
this.#webSocket.addEventListener("close", ({ code, reason = ""}) => {
reject(new Error(`WebSocket closed: ${code} ${reason}`.trimEnd()));
});
});
}
get ready(): Promise<void> {
return this.#ready;
}
#send(message: string): void {
const { readyState } = this.#webSocket;
if (readyState === WebSocket.OPEN) {
this.#webSocket.send(message);
} else if (readyState === WebSocket.CONNECTING) {
this.#pendingMessages.push(message);
} else {
const closed = readyState === WebSocket.CLOSING ? "closing" : "closed";
throw new Error(`WebSocket is ${closed}`);
}
}
async fetch<T extends keyof JSC.RequestMap>(method: T, params: JSC.Request<T>["params"]): Promise<JSC.Response<T>> {
const request: JSC.Request<T> = {
id: this.#requestId++,
method,
params,
};
return new Promise((resolve, reject) => {
const abort = new AbortController();
abort.signal.addEventListener("abort", () => {
this.#pendingRequests.delete(request.id);
const { reason } = abort.signal;
if (reason instanceof Error) {
reject(reason);
} else {
resolve(reason);
}
});
this.#pendingRequests.set(request.id, abort);
this.#send(JSON.stringify(request));
});
}
}
const client = new Client({
url: "ws://localhost:9229",
event: (event) => console.log("EVENT:", event),
request: (request) => console.log("REQUEST:", request),
response: (response) => console.log("RESPONSE:", response),
});
await client.ready;
while (true) {
const [method, ...param] = prompt(">")?.split(" ") ?? [];
if (!method.trim()) {
continue;
}
const params = !param?.length ? {} : JSON.parse(eval(`JSON.stringify(${param.join(" ")})`));
try {
await client.fetch(method.trim() as any, params);
} catch (error) {
console.error(error);
}
}

View File

@@ -1,255 +0,0 @@
import { join } from "node:path";
import { writeFileSync, mkdirSync } from "node:fs";
import { spawnSync } from "node:child_process";
async function download<V>(url: string): Promise<V> {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`${response.status}: ${url}`);
}
return response.json();
}
type Protocol = {
name: string;
version: {
major: number;
minor: number;
};
domains: Domain[];
};
type Domain = {
domain: string;
types: Property[];
commands?: {
name: string;
description?: string;
parameters?: Property[];
returns?: Property[];
}[];
events?: {
name: string;
description?: string;
parameters: Property[];
}[];
};
type Property = {
id?: string;
type?: string;
name?: string;
description?: string;
optional?: boolean;
} & (
| {
type: "array";
items?: Property;
}
| {
type: "object";
properties?: Property[];
}
| {
type: "string";
enum?: string[];
}
| {
$ref: string;
}
);
function format(property: Property): string {
if (property.id) {
const comment = property.description
? `/** ${property.description} */\n`
: "";
const body = format({ ...property, id: undefined });
return `${comment}export type ${property.id} = ${body};\n`;
}
if (property.type === "array") {
const type = "items" in property ? format(property.items!) : "unknown";
return `Array<${type}>`;
}
if (property.type === "object") {
if (!("properties" in property)) {
return "Record<string, unknown>";
}
if (property.properties!.length === 0) {
return "{}";
}
const properties = property
.properties!.map((property) => {
const comment = property.description
? `/** ${property.description} */\n`
: "";
const name = `${property.name}${property.optional ? "?" : ""}`;
return `${comment} ${name}: ${format(property)};`;
})
.join("\n");
return `{\n${properties}}`;
}
if (property.type === "string") {
if (!("enum" in property)) {
return "string";
}
return property.enum!.map((v) => `"${v}"`).join(" | ");
}
if ("$ref" in property) {
if (/^Page|DOM|Security|CSS|IO|Emulation\./.test(property.$ref)) {
return "unknown";
}
return property.$ref;
}
if (property.type === "integer") {
return "number";
}
return property.type;
}
function formatAll(protocol: Protocol): string {
let body = "";
const append = (property: Property) => {
body += format(property);
};
const titlize = (name: string) =>
name.charAt(0).toUpperCase() + name.slice(1);
const events = new Map();
const commands = new Map();
for (const domain of protocol.domains) {
body += `export namespace ${domain.domain} {`;
for (const type of domain.types ?? []) {
append(type);
}
for (const event of domain.events ?? []) {
const symbol = `${domain.domain}.${event.name}`;
const title = titlize(event.name);
events.set(symbol, `${domain.domain}.${title}`);
append({
id: `${title}Event`,
type: "object",
description: `\`${symbol}\``,
properties: event.parameters ?? [],
});
}
for (const command of domain.commands ?? []) {
const symbol = `${domain.domain}.${command.name}`;
const title = titlize(command.name);
commands.set(symbol, `${domain.domain}.${title}`);
append({
id: `${title}Request`,
type: "object",
description: `\`${symbol}\``,
properties: command.parameters ?? [],
});
append({
id: `${title}Response`,
type: "object",
description: `\`${symbol}\``,
properties: command.returns ?? [],
});
}
body += "};";
}
for (const type of ["Event", "Request", "Response"]) {
const source = type === "Event" ? events : commands;
append({
id: `${type}Map`,
type: "object",
properties: [...source.entries()].map(([name, title]) => ({
name: `"${name}"`,
$ref: `${title}${type}`,
})),
});
}
body += `export type Event<T extends keyof EventMap> = {
method: T;
params: EventMap[T];
};
export type Request<T extends keyof RequestMap> = {
id: number;
method: T;
params: RequestMap[T];
};
export type Response<T extends keyof ResponseMap> = {
id: number;
} & ({
method?: T;
result: ResponseMap[T];
} | {
error: {
code?: string;
message: string;
};
});`;
return `export namespace ${protocol.name.toUpperCase()} {${body}};`;
}
async function downloadV8(): Promise<Protocol> {
const baseUrl =
"https://raw.githubusercontent.com/ChromeDevTools/devtools-protocol/master/json";
const filter = [
"Runtime",
"Network",
"Console",
"Debugger",
"Profiler",
"HeapProfiler",
];
return Promise.all([
download<Protocol>(`${baseUrl}/js_protocol.json`),
download<Protocol>(`${baseUrl}/browser_protocol.json`),
]).then(([js, browser]) => ({
name: "v8",
version: js.version,
domains: [...js.domains, ...browser.domains]
.filter((domain) => filter.includes(domain.domain))
.sort((a, b) => a.domain.localeCompare(b.domain)),
}));
}
async function downloadJsc(): Promise<Protocol> {
const baseUrl =
"https://raw.githubusercontent.com/WebKit/WebKit/main/Source/JavaScriptCore/inspector/protocol";
return {
name: "jsc",
version: {
major: 1,
minor: 3,
},
domains: await Promise.all([
download<Domain>(`${baseUrl}/Debugger.json`),
download<Domain>(`${baseUrl}/Heap.json`),
download<Domain>(`${baseUrl}/ScriptProfiler.json`),
download<Domain>(`${baseUrl}/Runtime.json`),
download<Domain>(`${baseUrl}/Network.json`),
download<Domain>(`${baseUrl}/Console.json`),
download<Domain>(`${baseUrl}/GenericTypes.json`),
]).then((domains) =>
domains.sort((a, b) => a.domain.localeCompare(b.domain))
),
};
}
async function run(cwd: string) {
const [jsc, v8] = await Promise.all([downloadJsc(), downloadV8()]);
try {
mkdirSync(cwd);
} catch (error) {
if (error.code !== "EEXIST") {
throw error;
}
}
const write = (name: string, data: string) => {
writeFileSync(join(cwd, name), data);
spawnSync("bunx", ["prettier", "--write", name], { cwd, stdio: "ignore" });
};
// Note: Can be uncommented to inspect the JSON protocol files.
// write("devtools/jsc.json", JSON.stringify(jsc));
// write("devtools/v8.json", JSON.stringify(v8));
write("jsc.d.ts", "// GENERATED - DO NOT EDIT\n" + formatAll(jsc));
write("v8.d.ts", "// GENERATED - DO NOT EDIT\n" + formatAll(v8));
}
run(join(__dirname, "..", "protocol"))
.catch(console.error);

View File

@@ -1,18 +0,0 @@
{
"compilerOptions": {
"lib": ["ESNext"],
"module": "esnext",
"target": "esnext",
"moduleResolution": "bundler",
"moduleDetection": "force",
"allowImportingTsExtensions": true,
"strict": true,
"downlevelIteration": true,
"skipLibCheck": true,
"jsx": "preserve",
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"allowJs": true,
"noEmit": true
}
}

View File

@@ -4,9 +4,17 @@ import { fsyncSync, rmSync, writeFileSync, writeSync } from "fs";
import { readdirSync } from "node:fs";
import { resolve } from "node:path";
import { StringDecoder } from "node:string_decoder";
import { totalmem } from "os";
import { relative } from "path";
import { fileURLToPath } from "url";
const nativeMemory = totalmem();
const BUN_JSC_forceRAMSizeNumber = parseInt(process.env["BUN_JSC_forceRAMSize"] || "0", 10);
let BUN_JSC_forceRAMSize = Number(BigInt(nativeMemory) >> BigInt(2)) + "";
if (!(Number.isSafeInteger(BUN_JSC_forceRAMSizeNumber) && BUN_JSC_forceRAMSizeNumber > 0)) {
BUN_JSC_forceRAMSize = BUN_JSC_forceRAMSizeNumber + "";
}
const cwd = resolve(fileURLToPath(import.meta.url), "../../../../");
process.chdir(cwd);
@@ -39,6 +47,8 @@ async function runTest(path) {
env: {
...process.env,
FORCE_COLOR: "1",
BUN_GARBAGE_COLLECTOR_LEVEL: "1",
BUN_JSC_forceRAMSize,
},
});
} catch (e) {

View File

@@ -15,6 +15,77 @@
*/
declare module "bun:test" {
type AnyFunction = (...args: any) => any;
/**
* -- Mocks --
*/
export interface Mock<T extends AnyFunction>
extends JestMock.MockInstance<T> {
(...args: Parameters<T>): ReturnType<T>;
}
type _Mock<T extends AnyFunction> = Mock<T>;
export const mock: {
<T extends AnyFunction>(Function: T): Mock<T>;
};
interface Jest {
restoreAllMocks(): void;
fn<T extends AnyFunction>(func?: T): Mock<T>;
}
export const jest: Jest;
export namespace jest {
/**
* Constructs the type of a mock function, e.g. the return type of `jest.fn()`.
*/
type Mock<T extends AnyFunction = AnyFunction> = _Mock<T>;
/**
* Wraps a class, function or object type with Jest mock type definitions.
*/
// type Mocked<T extends object> = JestMock.Mocked<T>;
/**
* Wraps a class type with Jest mock type definitions.
*/
// type MockedClass<T extends JestMock.ClassLike> = JestMock.MockedClass<T>;
/**
* Wraps a function type with Jest mock type definitions.
*/
// type MockedFunction<T extends AnyFunction> = JestMock.MockedFunction<T>;
/**
* Wraps an object type with Jest mock type definitions.
*/
// type MockedObject<T extends object> = JestMock.MockedObject<T>;
/**
* Constructs the type of a replaced property.
*/
type Replaced<T> = JestMock.Replaced<T>;
/**
* Constructs the type of a spied class or function.
*/
type Spied<T extends JestMock.ClassLike | AnyFunction> = JestMock.Spied<T>;
/**
* Constructs the type of a spied class.
*/
type SpiedClass<T extends JestMock.ClassLike> = JestMock.SpiedClass<T>;
/**
* Constructs the type of a spied function.
*/
type SpiedFunction<T extends AnyFunction> = JestMock.SpiedFunction<T>;
/**
* Constructs the type of a spied getter.
*/
type SpiedGetter<T> = JestMock.SpiedGetter<T>;
/**
* Constructs the type of a spied setter.
*/
type SpiedSetter<T> = JestMock.SpiedSetter<T>;
}
export function spyOn<T extends object, K extends keyof T>(
obj: T,
methodOrPropertyValue: K,
): Mock<() => T[K]>;
/**
* Describes a group of related tests.
*
@@ -329,6 +400,9 @@ declare module "bun:test" {
any: (
constructor: ((..._: any[]) => any) | { new (..._: any[]): any },
) => Expect;
anything: () => Expect;
stringContaining: (str: string) => Expect;
stringMatching: (regex: RegExp | string) => Expect;
};
/**
* Asserts that a value matches some criteria.
@@ -350,6 +424,20 @@ declare module "bun:test" {
* expect(null).not.toBeNull();
*/
not: Expect<unknown>;
/**
* Expects the value to be a promise that resolves.
*
* @example
* expect(Promise.resolve(1)).resolves.toBe(1);
*/
resolves: Expect<unknown>;
/**
* Expects the value to be a promise that rejects.
*
* @example
* expect(Promise.reject("error")).rejects.toBe("error");
*/
rejects: Expect<unknown>;
/**
* Asserts that a value equals what is expected.
*
@@ -366,6 +454,24 @@ declare module "bun:test" {
* @param expected the expected value
*/
toBe(expected: T): void;
/**
* Asserts that a number is odd.
*
* @link https://jest-extended.jestcommunity.dev/docs/matchers/number/#tobeodd
* @example
* expect(1).toBeOdd();
* expect(2).not.toBeOdd();
*/
toBeOdd(): void;
/**
* Asserts that a number is even.
*
* @link https://jest-extended.jestcommunity.dev/docs/matchers/number/#tobeeven
* @example
* expect(2).toBeEven();
* expect(1).not.toBeEven();
*/
toBeEven(): void;
/**
* Asserts that value is close to the expected by floating point precision.
*
@@ -618,6 +724,16 @@ declare module "bun:test" {
* @param hint Hint used to identify the snapshot in the snapshot file.
*/
toMatchSnapshot(propertyMatchers?: Object, hint?: string): void;
/**
* Asserts that an object matches a subset of properties.
*
* @example
* expect({ a: 1, b: 2 }).toMatchObject({ b: 2 });
* expect({ c: new Date(), d: 2 }).toMatchObject({ d: 2 });
*
* @param subset Subset of properties to match with.
*/
toMatchObject(subset: Object): void;
/**
* Asserts that a value is empty.
*
@@ -636,6 +752,27 @@ declare module "bun:test" {
* expect(undefined).toBeNil();
*/
toBeNil(): void;
/**
* Asserts that a value is a `array`.
*
* @link https://jest-extended.jestcommunity.dev/docs/matchers/array/#tobearray
* @example
* expect([1]).toBeArray();
* expect(new Array(1)).toBeArray();
* expect({}).not.toBeArray();
*/
toBeArray(): void;
/**
* Asserts that a value is a `array` of a certain length.
*
* @link https://jest-extended.jestcommunity.dev/docs/matchers/array/#tobearrayofsize
* @example
* expect([]).toBeArrayOfSize(0);
* expect([1]).toBeArrayOfSize(1);
* expect(new Array(1)).toBeArrayOfSize(1);
* expect({}).not.toBeArrayOfSize(0);
*/
toBeArrayOfSize(size: number): void;
/**
* Asserts that a value is a `boolean`.
*
@@ -655,6 +792,26 @@ declare module "bun:test" {
* expect(1).not.toBeTrue();
*/
toBeTrue(): void;
/**
* Asserts that a value matches a specific type.
*
* @link https://vitest.dev/api/expect.html#tobetypeof
* @example
* expect(1).toBeTypeOf("number");
* expect("hello").toBeTypeOf("string");
* expect([]).not.toBeTypeOf("boolean");
*/
toBeTypeOf(
type:
| "bigint"
| "boolean"
| "function"
| "number"
| "object"
| "string"
| "symbol"
| "undefined",
): void;
/**
* Asserts that a value is `false`.
*
@@ -782,6 +939,18 @@ declare module "bun:test" {
* @param expected the string to end with
*/
toEndWith(expected: string): void;
/**
* Ensures that a mock function is called.
*/
toHaveBeenCalled(): void;
/**
* Ensures that a mock function is called an exact number of times.
*/
toHaveBeenCalledTimes(expected: number): void;
/**
* Ensure that a mock function is called with specific arguments.
*/
// toHaveBeenCalledWith(...expected: Array<unknown>): void;
};
}
@@ -789,3 +958,423 @@ declare module "test" {
import BunTestModule = require("bun:test");
export = BunTestModule;
}
declare namespace JestMock {
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
export type ClassLike = {
new (...args: any): any;
};
export type ConstructorLikeKeys<T> = keyof {
[K in keyof T as Required<T>[K] extends ClassLike ? K : never]: T[K];
};
// export const fn: <T extends FunctionLike = UnknownFunction>(
// implementation?: T | undefined,
// ) => Mock<T>;
export type FunctionLike = (...args: any) => any;
export type MethodLikeKeys<T> = keyof {
[K in keyof T as Required<T>[K] extends FunctionLike ? K : never]: T[K];
};
/**
* All what the internal typings need is to be sure that we have any-function.
* `FunctionLike` type ensures that and helps to constrain the type as well.
* The default of `UnknownFunction` makes sure that `any`s do not leak to the
* user side. For instance, calling `fn()` without implementation will return
* a mock of `(...args: Array<unknown>) => unknown` type. If implementation
* is provided, its typings are inferred correctly.
*/
// export interface Mock<T extends FunctionLike = UnknownFunction>
// extends Function,
// MockInstance<T> {
// new (...args: Parameters<T>): ReturnType<T>;
// (...args: Parameters<T>): ReturnType<T>;
// }
// export type Mocked<T> = T extends ClassLike
// ? MockedClass<T>
// : T extends FunctionLike
// ? MockedFunction<T>
// : T extends object
// ? MockedObject<T>
// : T;
// export const mocked: {
// <T extends object>(
// source: T,
// options?: {
// shallow: false;
// },
// ): Mocked<T>;
// <T_1 extends object>(
// source: T_1,
// options: {
// shallow: true;
// },
// ): MockedShallow<T_1>;
// };
// export type MockedClass<T extends ClassLike> = MockInstance<
// (...args: ConstructorParameters<T>) => Mocked<InstanceType<T>>
// > &
// MockedObject<T>;
// export type MockedFunction<T extends FunctionLike> = MockInstance<T> &
// MockedObject<T>;
// type MockedFunctionShallow<T extends FunctionLike> = MockInstance<T> & T;
// export type MockedObject<T extends object> = {
// [K in keyof T]: T[K] extends ClassLike
// ? MockedClass<T[K]>
// : T[K] extends FunctionLike
// ? MockedFunction<T[K]>
// : T[K] extends object
// ? MockedObject<T[K]>
// : T[K];
// } & T;
// type MockedObjectShallow<T extends object> = {
// [K in keyof T]: T[K] extends ClassLike
// ? MockedClass<T[K]>
// : T[K] extends FunctionLike
// ? MockedFunctionShallow<T[K]>
// : T[K];
// } & T;
// export type MockedShallow<T> = T extends ClassLike
// ? MockedClass<T>
// : T extends FunctionLike
// ? MockedFunctionShallow<T>
// : T extends object
// ? MockedObjectShallow<T>
// : T;
// export type MockFunctionMetadata<
// T = unknown,
// MetadataType = MockMetadataType,
// > = MockMetadata<T, MetadataType>;
// export type MockFunctionMetadataType = MockMetadataType;
type MockFunctionResult<T extends FunctionLike = UnknownFunction> =
| MockFunctionResultIncomplete
| MockFunctionResultReturn<T>
| MockFunctionResultThrow;
type MockFunctionResultIncomplete = {
type: "incomplete";
/**
* Result of a single call to a mock function that has not yet completed.
* This occurs if you test the result from within the mock function itself,
* or from within a function that was called by the mock.
*/
value: undefined;
};
type MockFunctionResultReturn<T extends FunctionLike = UnknownFunction> = {
type: "return";
/**
* Result of a single call to a mock function that returned.
*/
value: ReturnType<T>;
};
type MockFunctionResultThrow = {
type: "throw";
/**
* Result of a single call to a mock function that threw.
*/
value: unknown;
};
type MockFunctionState<T extends FunctionLike = FunctionLike> = {
/**
* List of the call arguments of all calls that have been made to the mock.
*/
calls: Array<Parameters<T>>;
/**
* List of all the object instances that have been instantiated from the mock.
*/
instances: Array<ReturnType<T>>;
/**
* List of all the function contexts that have been applied to calls to the mock.
*/
contexts: Array<ThisParameterType<T>>;
/**
* List of the call order indexes of the mock. Jest is indexing the order of
* invocations of all mocks in a test file. The index is starting with `1`.
*/
invocationCallOrder: Array<number>;
/**
* List of the call arguments of the last call that was made to the mock.
* If the function was not called, it will return `undefined`.
*/
lastCall?: Parameters<T>;
/**
* List of the results of all calls that have been made to the mock.
*/
results: Array<MockFunctionResult<T>>;
};
export interface MockInstance<T extends FunctionLike = UnknownFunction> {
_isMockFunction: true;
_protoImpl: Function;
getMockImplementation(): T | undefined;
getMockName(): string;
mock: MockFunctionState<T>;
mockClear(): this;
mockReset(): this;
mockRestore(): void;
mockImplementation(fn: T): this;
mockImplementationOnce(fn: T): this;
withImplementation(fn: T, callback: () => Promise<unknown>): Promise<void>;
withImplementation(fn: T, callback: () => void): void;
mockName(name: string): this;
mockReturnThis(): this;
mockReturnValue(value: ReturnType<T>): this;
mockReturnValueOnce(value: ReturnType<T>): this;
mockResolvedValue(value: ResolveType<T>): this;
mockResolvedValueOnce(value: ResolveType<T>): this;
mockRejectedValue(value: RejectType<T>): this;
mockRejectedValueOnce(value: RejectType<T>): this;
}
// export type MockMetadata<T, MetadataType = MockMetadataType> = {
// ref?: number;
// members?: Record<string, MockMetadata<T>>;
// mockImpl?: T;
// name?: string;
// refID?: number;
// type?: MetadataType;
// value?: T;
// length?: number;
// };
// export type MockMetadataType =
// | "object"
// | "array"
// | "regexp"
// | "function"
// | "constant"
// | "collection"
// | "null"
// | "undefined";
// export class ModuleMocker {
// private readonly _environmentGlobal;
// private _mockState;
// private _mockConfigRegistry;
// private _spyState;
// private _invocationCallCounter;
// /**
// * @see README.md
// * @param global Global object of the test environment, used to create
// * mocks
// */
// constructor(global: typeof globalThis);
// private _getSlots;
// private _ensureMockConfig;
// private _ensureMockState;
// private _defaultMockConfig;
// private _defaultMockState;
// private _makeComponent;
// private _createMockFunction;
// private _generateMock;
// /**
// * Check whether the given property of an object has been already replaced.
// */
// private _findReplacedProperty;
// /**
// * @see README.md
// * @param metadata Metadata for the mock in the schema returned by the
// * getMetadata method of this module.
// */
// generateFromMetadata<T>(metadata: MockMetadata<T>): Mocked<T>;
// /**
// * @see README.md
// * @param component The component for which to retrieve metadata.
// */
// getMetadata<T = unknown>(
// component: T,
// _refs?: Map<T, number>,
// ): MockMetadata<T> | null;
// isMockFunction<T extends FunctionLike = UnknownFunction>(
// fn: MockInstance<T>,
// ): fn is MockInstance<T>;
// isMockFunction<P extends Array<unknown>, R>(
// fn: (...args: P) => R,
// ): fn is Mock<(...args: P) => R>;
// isMockFunction(fn: unknown): fn is Mock<UnknownFunction>;
// fn<T extends FunctionLike = UnknownFunction>(implementation?: T): Mock<T>;
// private _attachMockImplementation;
// spyOn<
// T extends object,
// K extends PropertyLikeKeys<T>,
// A extends "get" | "set",
// >(
// object: T,
// methodKey: K,
// accessType: A,
// ): A extends "get"
// ? SpiedGetter<T[K]>
// : A extends "set"
// ? SpiedSetter<T[K]>
// : never;
// spyOn<
// T extends object,
// K extends ConstructorLikeKeys<T> | MethodLikeKeys<T>,
// V extends Required<T>[K],
// >(
// object: T,
// methodKey: K,
// ): V extends ClassLike | FunctionLike ? Spied<V> : never;
// private _spyOnProperty;
// replaceProperty<
// T extends object,
// K extends PropertyLikeKeys<T>,
// V extends T[K],
// >(object: T, propertyKey: K, value: V): Replaced<T[K]>;
// clearAllMocks(): void;
// resetAllMocks(): void;
// restoreAllMocks(): void;
// private _typeOf;
// mocked<T extends object>(
// source: T,
// options?: {
// shallow: false;
// },
// ): Mocked<T>;
// mocked<T extends object>(
// source: T,
// options: {
// shallow: true;
// },
// ): MockedShallow<T>;
// }
export type PropertyLikeKeys<T> = Exclude<
keyof T,
ConstructorLikeKeys<T> | MethodLikeKeys<T>
>;
export type RejectType<T extends FunctionLike> =
ReturnType<T> extends PromiseLike<any> ? unknown : never;
export interface Replaced<T = unknown> {
/**
* Restore property to its original value known at the time of mocking.
*/
restore(): void;
/**
* Change the value of the property.
*/
replaceValue(value: T): this;
}
export const replaceProperty: <
T extends object,
K_2 extends Exclude<
keyof T,
| keyof {
[K in keyof T as Required<T>[K] extends ClassLike ? K : never]: T[K];
}
| keyof {
[K_1 in keyof T as Required<T>[K_1] extends FunctionLike
? K_1
: never]: T[K_1];
}
>,
V extends T[K_2],
>(
object: T,
propertyKey: K_2,
value: V,
) => Replaced<T[K_2]>;
export type ResolveType<T extends FunctionLike> =
ReturnType<T> extends PromiseLike<infer U> ? U : never;
export type Spied<T extends ClassLike | FunctionLike> = T extends ClassLike
? SpiedClass<T>
: T extends FunctionLike
? SpiedFunction<T>
: never;
export type SpiedClass<T extends ClassLike = UnknownClass> = MockInstance<
(...args: ConstructorParameters<T>) => InstanceType<T>
>;
export type SpiedFunction<T extends FunctionLike = UnknownFunction> =
MockInstance<(...args: Parameters<T>) => ReturnType<T>>;
export type SpiedGetter<T> = MockInstance<() => T>;
export type SpiedSetter<T> = MockInstance<(arg: T) => void>;
export interface SpyInstance<T extends FunctionLike = UnknownFunction>
extends MockInstance<T> {}
export const spyOn: {
<
T extends object,
K_2 extends Exclude<
keyof T,
| keyof {
[K in keyof T as Required<T>[K] extends ClassLike
? K
: never]: T[K];
}
| keyof {
[K_1 in keyof T as Required<T>[K_1] extends FunctionLike
? K_1
: never]: T[K_1];
}
>,
V extends Required<T>[K_2],
A extends "set" | "get",
>(
object: T,
methodKey: K_2,
accessType: A,
): A extends "get"
? SpiedGetter<V>
: A extends "set"
? SpiedSetter<V>
: never;
<
T_1 extends object,
K_5 extends
| keyof {
[K_3 in keyof T_1 as Required<T_1>[K_3] extends ClassLike
? K_3
: never]: T_1[K_3];
}
| keyof {
[K_4 in keyof T_1 as Required<T_1>[K_4] extends FunctionLike
? K_4
: never]: T_1[K_4];
},
V_1 extends Required<T_1>[K_5],
>(
object: T_1,
methodKey: K_5,
): V_1 extends ClassLike | FunctionLike ? Spied<V_1> : never;
};
export type UnknownClass = {
new (...args: Array<unknown>): unknown;
};
export type UnknownFunction = (...args: Array<unknown>) => unknown;
export {};
}

View File

@@ -51,6 +51,10 @@ declare module "bun" {
*
*/
export const env: Env;
/**
* The raw arguments passed to the process, including flags passed to Bun. If you want to easily read flags passed to your script, consider using `process.argv` instead.
*/
export const argv: string[];
export const origin: string;
/**
@@ -744,6 +748,14 @@ declare module "bun" {
strict?: boolean,
): boolean;
/**
* Returns true if all properties in the subset exist in the
* other and have equal values.
*
* This also powers expect().toMatchObject in `bun:test`
*/
export function deepMatch(subset: unknown, a: unknown): boolean;
/**
* tsconfig.json options supported by Bun
*/
@@ -1012,6 +1024,226 @@ declare module "bun" {
// importSource?: string; // default: "react"
// };
}
namespace Password {
export type AlgorithmLabel = "bcrypt" | "argon2id" | "argon2d" | "argon2i";
export interface Argon2Algorithm {
algorithm: "argon2id" | "argon2d" | "argon2i";
/**
* Memory cost, which defines the memory usage, given in kibibytes.
*/
memoryCost?: number;
/**
* Defines the amount of computation realized and therefore the execution
* time, given in number of iterations.
*/
timeCost?: number;
}
export interface BCryptAlgorithm {
algorithm: "bcrypt";
/**
* A number between 4 and 31. The default is 10.
*/
cost?: number;
}
}
/**
* Hash and verify passwords using argon2 or bcrypt. The default is argon2.
* Password hashing functions are necessarily slow, and this object will
* automatically run in a worker thread.
*
* The underlying implementation of these functions are provided by the Zig
* Standard Library. Thanks to @jedisct1 and other Zig constributors for their
* work on this.
*
* ### Example with argon2
*
* ```ts
* import {password} from "bun";
*
* const hash = await password.hash("hello world");
* const verify = await password.verify("hello world", hash);
* console.log(verify); // true
* ```
*
* ### Example with bcrypt
* ```ts
* import {password} from "bun";
*
* const hash = await password.hash("hello world", "bcrypt");
* // algorithm is optional, will be inferred from the hash if not specified
* const verify = await password.verify("hello world", hash, "bcrypt");
*
* console.log(verify); // true
* ```
*/
export const password: {
/**
* Verify a password against a previously hashed password.
*
* @returns true if the password matches, false otherwise
*
* @example
* ```ts
* import {password} from "bun";
* await password.verify("hey", "$argon2id$v=19$m=65536,t=2,p=1$ddbcyBcbAcagei7wSkZFiouX6TqnUQHmTyS5mxGCzeM$+3OIaFatZ3n6LtMhUlfWbgJyNp7h8/oIsLK+LzZO+WI");
* // true
* ```
*
* @throws If the algorithm is specified and does not match the hash
* @throws If the algorithm is invalid
* @throws if the hash is invalid
*
*/
verify(
/**
* The password to verify.
*
* If empty, always returns false
*/
password: StringOrBuffer,
/**
* Previously hashed password.
* If empty, always returns false
*/
hash: StringOrBuffer,
/**
* If not specified, the algorithm will be inferred from the hash.
*
* If specified and the algorithm does not match the hash, this function
* throws an error.
*/
algorithm?: Password.AlgorithmLabel,
): Promise<boolean>;
/**
* Asynchronously hash a password using argon2 or bcrypt. The default is argon2.
*
* @returns A promise that resolves to the hashed password
*
* ## Example with argon2
* ```ts
* import {password} from "bun";
* const hash = await password.hash("hello world");
* console.log(hash); // $argon2id$v=1...
* const verify = await password.verify("hello world", hash);
* ```
* ## Example with bcrypt
* ```ts
* import {password} from "bun";
* const hash = await password.hash("hello world", "bcrypt");
* console.log(hash); // $2b$10$...
* const verify = await password.verify("hello world", hash);
* ```
*/
hash(
/**
* The password to hash
*
* If empty, this function throws an error. It is usually a programming
* mistake to hash an empty password.
*/
password: StringOrBuffer,
/**
* @default "argon2id"
*
* When using bcrypt, passwords exceeding 72 characters will be SHA512'd before
*/
algorithm?:
| Password.AlgorithmLabel
| Password.Argon2Algorithm
| Password.BCryptAlgorithm,
): Promise<string>;
/**
* Synchronously hash and verify passwords using argon2 or bcrypt. The default is argon2.
* Warning: password hashing is slow, consider using {@link Bun.password.verify}
* instead which runs in a worker thread.
*
* The underlying implementation of these functions are provided by the Zig
* Standard Library. Thanks to @jedisct1 and other Zig constributors for their
* work on this.
*
* ### Example with argon2
*
* ```ts
* import {password} from "bun";
*
* const hash = await password.hashSync("hello world");
* const verify = await password.verifySync("hello world", hash);
* console.log(verify); // true
* ```
*
* ### Example with bcrypt
* ```ts
* import {password} from "bun";
*
* const hash = await password.hashSync("hello world", "bcrypt");
* // algorithm is optional, will be inferred from the hash if not specified
* const verify = await password.verifySync("hello world", hash, "bcrypt");
*
* console.log(verify); // true
* ```
*/
verifySync(
password: StringOrBuffer,
hash: StringOrBuffer,
/**
* If not specified, the algorithm will be inferred from the hash.
*/
algorithm?: Password.AlgorithmLabel,
): boolean;
/**
* Synchronously hash and verify passwords using argon2 or bcrypt. The default is argon2.
* Warning: password hashing is slow, consider using {@link Bun.password.hash}
* instead which runs in a worker thread.
*
* The underlying implementation of these functions are provided by the Zig
* Standard Library. Thanks to @jedisct1 and other Zig constributors for their
* work on this.
*
* ### Example with argon2
*
* ```ts
* import {password} from "bun";
*
* const hash = await password.hashSync("hello world");
* const verify = await password.verifySync("hello world", hash);
* console.log(verify); // true
* ```
*
* ### Example with bcrypt
* ```ts
* import {password} from "bun";
*
* const hash = await password.hashSync("hello world", "bcrypt");
* // algorithm is optional, will be inferred from the hash if not specified
* const verify = await password.verifySync("hello world", hash, "bcrypt");
*
* console.log(verify); // true
* ```
*/
hashSync(
/**
* The password to hash
*
* If empty, this function throws an error. It is usually a programming
* mistake to hash an empty password.
*/
password: StringOrBuffer,
/**
* @default "argon2id"
*
* When using bcrypt, passwords exceeding 72 characters will be SHA256'd before
*/
algorithm?:
| Password.AlgorithmLabel
| Password.Argon2Algorithm
| Password.BCryptAlgorithm,
): string;
};
interface BuildArtifact extends Blob {
path: string;
@@ -1379,9 +1611,9 @@ declare module "bun" {
* ```ts
* import { websocket, serve } from "bun";
*
* serve({
* serve<{name: string}>({
* port: 3000,
* websocket: websocket<{name: string}>({
* websocket: {
* open: (ws) => {
* console.log("Client connected");
* },
@@ -1391,10 +1623,11 @@ declare module "bun" {
* close: (ws) => {
* console.log("Client disconnected");
* },
* }),
* },
*
* fetch(req, server) {
* if (req.url === "/chat") {
* const url = new URL(req.url);
* if (url.pathname === "/chat") {
* const upgraded = server.upgrade(req, {
* data: {
* name: new URL(req.url).searchParams.get("name"),
@@ -1609,9 +1842,9 @@ declare module "bun" {
*
* @example
* ```js
*import { serve, websocket } from "bun";
*import { serve } from "bun";
*serve({
* websocket: websocket({
* websocket: {
* open: (ws) => {
* console.log("Client connected");
* },
@@ -1621,9 +1854,10 @@ declare module "bun" {
* close: (ws) => {
* console.log("Client disconnected");
* },
* }),
* },
* fetch(req, server) {
* if (req.url === "/chat") {
* const url = new URL(req.url);
* if (url.pathname === "/chat") {
* const upgraded = server.upgrade(req);
* if (!upgraded) {
* return new Response("Upgrade failed", { status: 400 });
@@ -1839,9 +2073,9 @@ declare module "bun" {
*
* @example
* ```js
* import { serve, websocket } from "bun";
* import { serve } from "bun";
* serve({
* websocket: websocket({
* websocket: {
* open: (ws) => {
* console.log("Client connected");
* },
@@ -1851,9 +2085,10 @@ declare module "bun" {
* close: (ws) => {
* console.log("Client disconnected");
* },
* }),
* },
* fetch(req, server) {
* if (req.url === "/chat") {
* const url = new URL(req.url);
* if (url.pathname === "/chat") {
* const upgraded = server.upgrade(req);
* if (!upgraded) {
* return new Response("Upgrade failed", { status: 400 });

View File

@@ -19,6 +19,7 @@
*/
declare module "fs" {
import * as stream from "stream";
import type EventEmitter from "events";
import type { SystemError, ArrayBufferView } from "bun";
interface ObjectEncodingOptions {
encoding?: BufferEncoding | null | undefined;
@@ -3929,6 +3930,102 @@ declare module "fs" {
*/
recursive?: boolean;
}
export interface FSWatcher extends EventEmitter {
/**
* Stop watching for changes on the given `fs.FSWatcher`. Once stopped, the `fs.FSWatcher` object is no longer usable.
* @since v0.6.8
*/
close(): void;
/**
* When called, requests that the Node.js event loop not exit so long as the <fs.FSWatcher> is active. Calling watcher.ref() multiple times will have no effect.
*/
ref(): void;
/**
* When called, the active <fs.FSWatcher> object will not require the Node.js event loop to remain active. If there is no other activity keeping the event loop running, the process may exit before the <fs.FSWatcher> object's callback is invoked. Calling watcher.unref() multiple times will have no effect.
*/
unref(): void;
/**
* events.EventEmitter
* 1. change
* 2. error
*/
addListener(event: string, listener: (...args: any[]) => void): this;
addListener(event: 'change', listener: (eventType: string, filename: string | Buffer) => void): this;
addListener(event: 'error', listener: (error: Error) => void): this;
addListener(event: 'close', listener: () => void): this;
on(event: string, listener: (...args: any[]) => void): this;
on(event: 'change', listener: (eventType: string, filename: string | Buffer) => void): this;
on(event: 'error', listener: (error: Error) => void): this;
on(event: 'close', listener: () => void): this;
once(event: string, listener: (...args: any[]) => void): this;
once(event: 'change', listener: (eventType: string, filename: string | Buffer) => void): this;
once(event: 'error', listener: (error: Error) => void): this;
once(event: 'close', listener: () => void): this;
prependListener(event: string, listener: (...args: any[]) => void): this;
prependListener(event: 'change', listener: (eventType: string, filename: string | Buffer) => void): this;
prependListener(event: 'error', listener: (error: Error) => void): this;
prependListener(event: 'close', listener: () => void): this;
prependOnceListener(event: string, listener: (...args: any[]) => void): this;
prependOnceListener(event: 'change', listener: (eventType: string, filename: string | Buffer) => void): this;
prependOnceListener(event: 'error', listener: (error: Error) => void): this;
prependOnceListener(event: 'close', listener: () => void): this;
}
/**
* Watch for changes on `filename`, where `filename` is either a file or a
* directory.
*
* The second argument is optional. If `options` is provided as a string, it
* specifies the `encoding`. Otherwise `options` should be passed as an object.
*
* The listener callback gets two arguments `(eventType, filename)`. `eventType`is either `'rename'` or `'change'`, and `filename` is the name of the file
* which triggered the event.
*
* On most platforms, `'rename'` is emitted whenever a filename appears or
* disappears in the directory.
*
* The listener callback is attached to the `'change'` event fired by `fs.FSWatcher`, but it is not the same thing as the `'change'` value of`eventType`.
*
* If a `signal` is passed, aborting the corresponding AbortController will close
* the returned `fs.FSWatcher`.
* @since v0.6.8
* @param listener
*/
export function watch(
filename: PathLike,
options:
| (WatchOptions & {
encoding: 'buffer';
})
| 'buffer',
listener?: WatchListener<Buffer>
): FSWatcher;
/**
* Watch for changes on `filename`, where `filename` is either a file or a directory, returning an `FSWatcher`.
* @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
* @param options Either the encoding for the filename provided to the listener, or an object optionally specifying encoding, persistent, and recursive options.
* If `encoding` is not supplied, the default of `'utf8'` is used.
* If `persistent` is not supplied, the default of `true` is used.
* If `recursive` is not supplied, the default of `false` is used.
*/
export function watch(filename: PathLike, options?: WatchOptions | BufferEncoding | null, listener?: WatchListener<string>): FSWatcher;
/**
* Watch for changes on `filename`, where `filename` is either a file or a directory, returning an `FSWatcher`.
* @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
* @param options Either the encoding for the filename provided to the listener, or an object optionally specifying encoding, persistent, and recursive options.
* If `encoding` is not supplied, the default of `'utf8'` is used.
* If `persistent` is not supplied, the default of `true` is used.
* If `recursive` is not supplied, the default of `false` is used.
*/
export function watch(filename: PathLike, options: WatchOptions | string, listener?: WatchListener<string | Buffer>): FSWatcher;
/**
* Watch for changes on `filename`, where `filename` is either a file or a directory, returning an `FSWatcher`.
* @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
*/
export function watch(filename: PathLike, listener?: WatchListener<string>): FSWatcher;
}
declare module "node:fs" {

View File

@@ -26,6 +26,7 @@ declare module "fs/promises" {
Abortable,
RmOptions,
RmDirOptions,
WatchOptions,
} from "node:fs";
const constants: typeof import("node:fs")["constants"];
@@ -709,6 +710,63 @@ declare module "fs/promises" {
* To remove a directory recursively, use `fs.promises.rm()` instead, with the `recursive` option set to `true`.
*/
function rmdir(path: PathLike, options?: RmDirOptions): Promise<void>;
/**
* Returns an async iterator that watches for changes on `filename`, where `filename`is either a file or a directory.
*
* ```js
* const { watch } = require('node:fs/promises');
*
* const ac = new AbortController();
* const { signal } = ac;
* setTimeout(() => ac.abort(), 10000);
*
* (async () => {
* try {
* const watcher = watch(__filename, { signal });
* for await (const event of watcher)
* console.log(event);
* } catch (err) {
* if (err.name === 'AbortError')
* return;
* throw err;
* }
* })();
* ```
*
* On most platforms, `'rename'` is emitted whenever a filename appears or
* disappears in the directory.
*
* All the `caveats` for `fs.watch()` also apply to `fsPromises.watch()`.
* @since v0.6.8
* @return of objects with the properties:
*/
function watch(
filename: PathLike,
options:
| (WatchOptions & {
encoding: 'buffer';
})
| 'buffer'
): AsyncIterable<FileChangeInfo<Buffer>>;
/**
* Watch for changes on `filename`, where `filename` is either a file or a directory, returning an `FSWatcher`.
* @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
* @param options Either the encoding for the filename provided to the listener, or an object optionally specifying encoding, persistent, and recursive options.
* If `encoding` is not supplied, the default of `'utf8'` is used.
* If `persistent` is not supplied, the default of `true` is used.
* If `recursive` is not supplied, the default of `false` is used.
*/
function watch(filename: PathLike, options?: WatchOptions | BufferEncoding): AsyncIterable<FileChangeInfo<string>>;
/**
* Watch for changes on `filename`, where `filename` is either a file or a directory, returning an `FSWatcher`.
* @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
* @param options Either the encoding for the filename provided to the listener, or an object optionally specifying encoding, persistent, and recursive options.
* If `encoding` is not supplied, the default of `'utf8'` is used.
* If `persistent` is not supplied, the default of `true` is used.
* If `recursive` is not supplied, the default of `false` is used.
*/
function watch(filename: PathLike, options: WatchOptions | string): AsyncIterable<FileChangeInfo<string>> | AsyncIterable<FileChangeInfo<Buffer>>;
}
declare module "node:fs/promises" {

View File

@@ -3197,3 +3197,82 @@ declare module "*.txt" {
var text: string;
export = text;
}
interface EventSourceEventMap {
error: Event;
message: MessageEvent;
open: Event;
}
interface EventSource extends EventTarget {
onerror: ((this: EventSource, ev: ErrorEvent) => any) | null;
onmessage: ((this: EventSource, ev: MessageEvent) => any) | null;
onopen: ((this: EventSource, ev: Event) => any) | null;
/** Returns the state of this EventSource object's connection. It can have the values described below. */
readonly readyState: number;
/** Returns the URL providing the event stream. */
readonly url: string;
/** Returns true if the credentials mode for connection requests to the URL providing the event stream is set to "include", and false otherwise.
*
* Not supported in Bun
*
*/
readonly withCredentials: boolean;
/** Aborts any instances of the fetch algorithm started for this EventSource object, and sets the readyState attribute to CLOSED. */
close(): void;
readonly CLOSED: number;
readonly CONNECTING: number;
readonly OPEN: number;
addEventListener<K extends keyof EventSourceEventMap>(
type: K,
listener: (this: EventSource, ev: EventSourceEventMap[K]) => any,
options?: boolean | AddEventListenerOptions,
): void;
addEventListener(
type: string,
listener: (this: EventSource, event: MessageEvent) => any,
options?: boolean | AddEventListenerOptions,
): void;
addEventListener(
type: string,
listener: EventListenerOrEventListenerObject,
options?: boolean | AddEventListenerOptions,
): void;
removeEventListener<K extends keyof EventSourceEventMap>(
type: K,
listener: (this: EventSource, ev: EventSourceEventMap[K]) => any,
options?: boolean | EventListenerOptions,
): void;
removeEventListener(
type: string,
listener: (this: EventSource, event: MessageEvent) => any,
options?: boolean | EventListenerOptions,
): void;
removeEventListener(
type: string,
listener: EventListenerOrEventListenerObject,
options?: boolean | EventListenerOptions,
): void;
/**
* Keep the event loop alive while connection is open or reconnecting
*
* Not available in browsers
*/
ref(): void;
/**
* Do not keep the event loop alive while connection is open or reconnecting
*
* Not available in browsers
*/
unref(): void;
}
declare var EventSource: {
prototype: EventSource;
new (url: string | URL, eventSourceInitDict?: EventSourceInit): EventSource;
readonly CLOSED: number;
readonly CONNECTING: number;
readonly OPEN: number;
};

View File

@@ -987,7 +987,7 @@ declare module "http" {
* in the response to be dropped and the socket to be destroyed.
* @deprecated Since v14.1.0,v13.14.0 - Use `destroy` instead.
*/
// abort(): void;
abort(): void;
/**
* Once a socket is assigned to this request and is connected `socket.setTimeout()` will be called.
* @param timeout Milliseconds before a request times out.

View File

@@ -75,6 +75,8 @@ const tsConfig = {
skipLibCheck: true,
jsx: "react-jsx",
allowImportingTsExtensions: true,
emitDeclarationOnly: true,
composite: true,
allowSyntheticDefaultImports: true,
forceConsistentCasingInFileNames: true,
allowJs: true,

View File

@@ -579,7 +579,9 @@ declare module "bun:sqlite" {
/**
* Execute the prepared statement and return the results as an array of arrays.
*
* This is a little faster than {@link all}.
* In Bun v0.6.7 and earlier, this method returned `null` if there were no
* results instead of `[]`. This was changed in v0.6.8 to align
* more with what people expect.
*
* @param params optional values to bind to the statement. If omitted, the statement is run with the last bound values or no parameters if there are none.
*
@@ -595,12 +597,15 @@ declare module "bun:sqlite" {
*
* stmt.values("foo");
* // => [['foo']]
*
* stmt.values("not-found");
* // => []
* ```
*
* The following types can be used when binding parameters:
*
* | JavaScript type | SQLite type |
* | -------------- | ----------- |
* | ---------------|-------------|
* | `string` | `TEXT` |
* | `number` | `INTEGER` or `DECIMAL` |
* | `boolean` | `INTEGER` (1 or 0) |

View File

@@ -46,22 +46,7 @@ declare module "stream" {
encoding?: BufferEncoding | undefined;
read?(this: Readable, size: number): void;
}
class Readable<R = any> extends Stream implements ReadableStream {
// TODO: improve type later
values: any;
readonly locked: boolean;
cancel(reason?: any): Promise<void>;
getReader(): ReadableStreamDefaultReader<R>;
pipeThrough<T>(
transform: ReadableWritablePair<T, R>,
options?: StreamPipeOptions,
): ReadableStream<T>;
pipeTo(
destination: WritableStream<R>,
options?: StreamPipeOptions,
): Promise<void>;
tee(): [ReadableStream<R>, ReadableStream<R>];
class Readable<R = any> extends Stream {
forEach(
callbackfn: (
value: any,
@@ -71,12 +56,23 @@ declare module "stream" {
thisArg?: any,
): void;
/**
* A utility method for creating Readable Streams out of iterators.
* A utility method for creating a `Readable` from a web `ReadableStream`.
* @since v17.0.0
* @experimental
*/
static from(
iterable: Iterable<any> | AsyncIterable<any>,
options?: ReadableOptions,
static fromWeb(
readableStream: ReadableStream,
options?: Pick<
ReadableOptions,
"encoding" | "highWaterMark" | "objectMode" | "signal"
>,
): Readable;
/**
* A utility method for creating a web `ReadableStream` from a `Readable`.
* @since v17.0.0
* @experimental
*/
static toWeb(streamReadable: Readable): ReadableStream;
/**
* Returns whether the stream has been read from or cancelled.
*/
@@ -512,11 +508,25 @@ declare module "stream" {
): void;
final?(this: Writable, callback: (error?: Error | null) => void): void;
}
class Writable<W = any> extends Stream implements WritableStream {
readonly locked: boolean;
abort(reason?: any): Promise<void>;
close(): Promise<void>;
getWriter(): WritableStreamDefaultWriter<W>;
class Writable<W = any> extends Stream {
/**
* A utility method for creating a `Writable` from a web `WritableStream`.
* @since v17.0.0
* @experimental
*/
static fromWeb(
writableStream: WritableStream,
options?: Pick<
WritableOptions,
"decodeStrings" | "highWaterMark" | "objectMode" | "signal"
>,
): Writable;
/**
* A utility method for creating a web `WritableStream` from a `Writable`.
* @since v17.0.0
* @experimental
*/
static toWeb(streamWritable: Writable): WritableStream;
/**
* Is `true` if it is safe to call `writable.write()`, which means
* the stream has not been destroyed, errored or ended.
@@ -634,11 +644,11 @@ declare module "stream" {
* @return `false` if the stream wishes for the calling code to wait for the `'drain'` event to be emitted before continuing to write additional data; otherwise `true`.
*/
write(
chunk: any,
chunk: W,
callback?: (error: Error | null | undefined) => void,
): boolean;
write(
chunk: any,
chunk: W,
encoding: BufferEncoding,
callback?: (error: Error | null | undefined) => void,
): boolean;
@@ -851,28 +861,21 @@ declare module "stream" {
* * `zlib streams`
* * `crypto streams`
*/
class Duplex extends Readable implements Writable {
readonly writable: boolean;
readonly writableEnded: boolean;
readonly writableFinished: boolean;
readonly writableHighWaterMark: number;
readonly writableLength: number;
readonly writableObjectMode: boolean;
readonly writableCorked: number;
/**
* If `false` then the stream will automatically end the writable side when the
* readable side ends. Set initially by the `allowHalfOpen` constructor option,
* which defaults to `false`.
*
* This can be changed manually to change the half-open behavior of an existing`Duplex` stream instance, but must be changed before the `'end'` event is
* emitted.
* @since v0.9.4
*/
allowHalfOpen: boolean;
constructor(opts?: DuplexOptions);
abort(reason?: any): Promise<void>;
close(): Promise<void>;
getWriter(): WritableStreamDefaultWriter<any>;
type Duplex<R = any> = Readable<R> &
Writable<R> & {
/**
* If `false` then the stream will automatically end the writable side when the
* readable side ends. Set initially by the `allowHalfOpen` constructor option,
* which defaults to `false`.
*
* This can be changed manually to change the half-open behavior of an existing`Duplex` stream instance, but must be changed before the `'end'` event is
* emitted.
* @since v0.9.4
*/
allowHalfOpen: boolean;
};
interface DuplexConstructor {
new <T = any>(opts?: DuplexOptions): Duplex<T>;
/**
* A utility method for creating duplex streams.
*
@@ -894,7 +897,7 @@ declare module "stream" {
*
* @since v16.8.0
*/
static from(
from(
src:
| Stream
| Blob
@@ -906,39 +909,19 @@ declare module "stream" {
| Promise<any>
| Object,
): Duplex;
_write(
chunk: any,
encoding: BufferEncoding,
callback: (error?: Error | null) => void,
): void;
_writev?(
chunks: Array<{
chunk: any;
encoding: BufferEncoding;
}>,
callback: (error?: Error | null) => void,
): void;
_destroy(
error: Error | null,
callback: (error: Error | null) => void,
): void;
_final(callback: (error?: Error | null) => void): void;
write(
chunk: any,
encoding?: BufferEncoding,
cb?: (error: Error | null | undefined) => void,
): boolean;
write(
chunk: any,
cb?: (error: Error | null | undefined) => void,
): boolean;
setDefaultEncoding(encoding: BufferEncoding): this;
end(cb?: () => void): this;
end(chunk: any, cb?: () => void): this;
end(chunk: any, encoding?: BufferEncoding, cb?: () => void): this;
cork(): void;
uncork(): void;
fromWeb<T = any>(
pair: {
readable: ReadableStream<T>;
writable: WritableStream<T>;
},
options: DuplexOptions,
): Duplex<T>;
toWeb<T>(stream: Duplex<T>): {
readable: ReadableStream<T>;
writable: WritableStream<T>;
};
}
var Duplex: DuplexConstructor;
type TransformCallback = (error?: Error | null, data?: any) => void;
interface TransformOptions extends DuplexOptions {
construct?(
@@ -985,7 +968,7 @@ declare module "stream" {
* * `crypto streams`
* @since v0.9.4
*/
class Transform extends Duplex {
class Transform<T = any> extends Duplex<T> {
constructor(opts?: TransformOptions);
_transform(
chunk: any,
@@ -998,7 +981,7 @@ declare module "stream" {
* The `stream.PassThrough` class is a trivial implementation of a `Transform` stream that simply passes the input bytes across to the output. Its purpose is
* primarily for examples and testing, but there are some use cases where`stream.PassThrough` is useful as a building block for novel sorts of streams.
*/
class PassThrough extends Transform {}
class PassThrough<T = any> extends Transform<T> {}
/**
* Attaches an AbortSignal to a readable or writeable stream. This lets code
* control stream destruction using an `AbortController`.

View File

@@ -0,0 +1,31 @@
import { expectType } from "tsd";
import { mock, jest } from "bun:test";
const mock1 = mock((arg: string) => {
return arg.length;
});
const arg1 = mock1("1");
expectType<number>(arg1);
mock;
type arg2 = jest.Spied<() => string>;
declare var arg2: arg2;
arg2.mock.calls[0];
mock;
// @ts-expect-error
jest.fn<() => Promise<string>>().mockReturnValue("asdf");
// @ts-expect-error
jest.fn<() => string>().mockReturnValue(24);
jest.fn<() => string>().mockReturnValue("24");
jest.fn<() => Promise<string>>().mockResolvedValue("asdf");
// @ts-expect-error
jest.fn<() => string>().mockResolvedValue(24);
// @ts-expect-error
jest.fn<() => string>().mockResolvedValue("24");
jest.fn().mockClear();
jest.fn().mockReset();
jest.fn().mockRejectedValueOnce(new Error());

View File

@@ -39,7 +39,8 @@ type User = {
Bun.serve<User>({
fetch(req, server) {
if (req.url === "/chat") {
const url = new URL(req.url);
if (url.pathname === "/chat") {
if (
server.upgrade(req, {
data: {

287
src/ArenaAllocator.zig Normal file
View File

@@ -0,0 +1,287 @@
/// TODO: delete this once we've upgraded Zig and https://github.com/ziglang/zig/pull/15985 is merged.
const std = @import("std");
const assert = std.debug.assert;
const mem = std.mem;
const Allocator = std.mem.Allocator;
/// This allocator takes an existing allocator, wraps it, and provides an interface
/// where you can allocate without freeing, and then free it all together.
pub const ArenaAllocator = struct {
child_allocator: Allocator,
state: State,
/// Inner state of ArenaAllocator. Can be stored rather than the entire ArenaAllocator
/// as a memory-saving optimization.
pub const State = struct {
buffer_list: std.SinglyLinkedList(usize) = .{},
end_index: usize = 0,
pub fn promote(self: State, child_allocator: Allocator) ArenaAllocator {
return .{
.child_allocator = child_allocator,
.state = self,
};
}
};
pub fn allocator(self: *ArenaAllocator) Allocator {
return .{
.ptr = self,
.vtable = &.{
.alloc = alloc,
.resize = resize,
.free = free,
},
};
}
const BufNode = std.SinglyLinkedList(usize).Node;
pub fn init(child_allocator: Allocator) ArenaAllocator {
return (State{}).promote(child_allocator);
}
pub fn deinit(self: ArenaAllocator) void {
// NOTE: When changing this, make sure `reset()` is adjusted accordingly!
var it = self.state.buffer_list.first;
while (it) |node| {
// this has to occur before the free because the free frees node
const next_it = node.next;
const align_bits = std.math.log2_int(usize, @alignOf(BufNode));
const alloc_buf = @ptrCast([*]u8, node)[0..node.data];
self.child_allocator.rawFree(alloc_buf, align_bits, @returnAddress());
it = next_it;
}
}
pub const ResetMode = union(enum) {
/// Releases all allocated memory in the arena.
free_all,
/// This will pre-heat the arena for future allocations by allocating a
/// large enough buffer for all previously done allocations.
/// Preheating will speed up the allocation process by invoking the backing allocator
/// less often than before. If `reset()` is used in a loop, this means that after the
/// biggest operation, no memory allocations are performed anymore.
retain_capacity,
/// This is the same as `retain_capacity`, but the memory will be shrunk to
/// this value if it exceeds the limit.
retain_with_limit: usize,
};
/// Queries the current memory use of this arena.
/// This will **not** include the storage required for internal keeping.
pub fn queryCapacity(self: ArenaAllocator) usize {
var size: usize = 0;
var it = self.state.buffer_list.first;
while (it) |node| : (it = node.next) {
// Compute the actually allocated size excluding the
// linked list node.
size += node.data - @sizeOf(BufNode);
}
return size;
}
/// Resets the arena allocator and frees all allocated memory.
///
/// `mode` defines how the currently allocated memory is handled.
/// See the variant documentation for `ResetMode` for the effects of each mode.
///
/// The function will return whether the reset operation was successful or not.
/// If the reallocation failed `false` is returned. The arena will still be fully
/// functional in that case, all memory is released. Future allocations just might
/// be slower.
///
/// NOTE: If `mode` is `free_mode`, the function will always return `true`.
pub fn reset(self: *ArenaAllocator, mode: ResetMode) bool {
// Some words on the implementation:
// The reset function can be implemented with two basic approaches:
// - Counting how much bytes were allocated since the last reset, and storing that
// information in State. This will make reset fast and alloc only a teeny tiny bit
// slower.
// - Counting how much bytes were allocated by iterating the chunk linked list. This
// will make reset slower, but alloc() keeps the same speed when reset() as if reset()
// would not exist.
//
// The second variant was chosen for implementation, as with more and more calls to reset(),
// the function will get faster and faster. At one point, the complexity of the function
// will drop to amortized O(1), as we're only ever having a single chunk that will not be
// reallocated, and we're not even touching the backing allocator anymore.
//
// Thus, only the first hand full of calls to reset() will actually need to iterate the linked
// list, all future calls are just taking the first node, and only resetting the `end_index`
// value.
const requested_capacity = switch (mode) {
.retain_capacity => self.queryCapacity(),
.retain_with_limit => |limit| @min(limit, self.queryCapacity()),
.free_all => 0,
};
if (requested_capacity == 0) {
// just reset when we don't have anything to reallocate
self.deinit();
self.state = State{};
return true;
}
const total_size = requested_capacity + @sizeOf(BufNode);
const align_bits = std.math.log2_int(usize, @alignOf(BufNode));
// Free all nodes except for the last one
var it = self.state.buffer_list.first;
const maybe_first_node = while (it) |node| {
// this has to occur before the free because the free frees node
const next_it = node.next;
if (next_it == null)
break node;
const alloc_buf = @ptrCast([*]u8, node)[0..node.data];
self.child_allocator.rawFree(alloc_buf, align_bits, @returnAddress());
it = next_it;
} else null;
std.debug.assert(maybe_first_node == null or maybe_first_node.?.next == null);
// reset the state before we try resizing the buffers, so we definitely have reset the arena to 0.
self.state.end_index = 0;
if (maybe_first_node) |first_node| {
self.state.buffer_list.first = first_node;
// perfect, no need to invoke the child_allocator
if (first_node.data == total_size)
return true;
const first_alloc_buf = @ptrCast([*]u8, first_node)[0..first_node.data];
if (self.child_allocator.rawResize(first_alloc_buf, align_bits, total_size, @returnAddress())) {
// successful resize
first_node.data = total_size;
} else {
// manual realloc
const new_ptr = self.child_allocator.rawAlloc(total_size, align_bits, @returnAddress()) orelse {
// we failed to preheat the arena properly, signal this to the user.
return false;
};
self.child_allocator.rawFree(first_alloc_buf, align_bits, @returnAddress());
const node = @ptrCast(*BufNode, @alignCast(@alignOf(BufNode), new_ptr));
node.* = .{ .data = total_size };
self.state.buffer_list.first = node;
}
}
return true;
}
fn createNode(self: *ArenaAllocator, prev_len: usize, minimum_size: usize) ?*BufNode {
const actual_min_size = minimum_size + (@sizeOf(BufNode) + 16);
const big_enough_len = prev_len + actual_min_size;
const len = big_enough_len + big_enough_len / 2;
const log2_align = comptime std.math.log2_int(usize, @alignOf(BufNode));
const ptr = self.child_allocator.rawAlloc(len, log2_align, @returnAddress()) orelse
return null;
const buf_node = @ptrCast(*BufNode, @alignCast(@alignOf(BufNode), ptr));
buf_node.* = .{ .data = len };
self.state.buffer_list.prepend(buf_node);
self.state.end_index = 0;
return buf_node;
}
fn alloc(ctx: *anyopaque, n: usize, log2_ptr_align: u8, ra: usize) ?[*]u8 {
const self = @ptrCast(*ArenaAllocator, @alignCast(@alignOf(ArenaAllocator), ctx));
_ = ra;
const ptr_align = @as(usize, 1) << @intCast(Allocator.Log2Align, log2_ptr_align);
var cur_node = if (self.state.buffer_list.first) |first_node|
first_node
else
(self.createNode(0, n + ptr_align) orelse return null);
while (true) {
const cur_alloc_buf = @ptrCast([*]u8, cur_node)[0..cur_node.data];
const cur_buf = cur_alloc_buf[@sizeOf(BufNode)..];
const addr = @intFromPtr(cur_buf.ptr) + self.state.end_index;
const adjusted_addr = mem.alignForward(usize, addr, ptr_align);
const adjusted_index = self.state.end_index + (adjusted_addr - addr);
const new_end_index = adjusted_index + n;
if (new_end_index <= cur_buf.len) {
const result = cur_buf[adjusted_index..new_end_index];
self.state.end_index = new_end_index;
return result.ptr;
}
const bigger_buf_size = @sizeOf(BufNode) + new_end_index;
const log2_align = comptime std.math.log2_int(usize, @alignOf(BufNode));
if (self.child_allocator.rawResize(cur_alloc_buf, log2_align, bigger_buf_size, @returnAddress())) {
cur_node.data = bigger_buf_size;
} else {
// Allocate a new node if that's not possible
cur_node = self.createNode(cur_buf.len, n + ptr_align) orelse return null;
}
}
}
fn resize(ctx: *anyopaque, buf: []u8, log2_buf_align: u8, new_len: usize, ret_addr: usize) bool {
const self = @ptrCast(*ArenaAllocator, @alignCast(@alignOf(ArenaAllocator), ctx));
_ = log2_buf_align;
_ = ret_addr;
const cur_node = self.state.buffer_list.first orelse return false;
const cur_buf = @ptrCast([*]u8, cur_node)[@sizeOf(BufNode)..cur_node.data];
if (@intFromPtr(cur_buf.ptr) + self.state.end_index != @intFromPtr(buf.ptr) + buf.len) {
// It's not the most recent allocation, so it cannot be expanded,
// but it's fine if they want to make it smaller.
return new_len <= buf.len;
}
if (buf.len >= new_len) {
self.state.end_index -= buf.len - new_len;
return true;
} else if (cur_buf.len - self.state.end_index >= new_len - buf.len) {
self.state.end_index += new_len - buf.len;
return true;
} else {
return false;
}
}
fn free(ctx: *anyopaque, buf: []u8, log2_buf_align: u8, ret_addr: usize) void {
_ = log2_buf_align;
_ = ret_addr;
const self = @ptrCast(*ArenaAllocator, @alignCast(@alignOf(ArenaAllocator), ctx));
const cur_node = self.state.buffer_list.first orelse return;
const cur_buf = @ptrCast([*]u8, cur_node)[@sizeOf(BufNode)..cur_node.data];
if (@intFromPtr(cur_buf.ptr) + self.state.end_index == @intFromPtr(buf.ptr) + buf.len) {
self.state.end_index -= buf.len;
}
}
};
test "ArenaAllocator (reset with preheating)" {
var arena_allocator = ArenaAllocator.init(std.testing.allocator);
defer arena_allocator.deinit();
// provides some variance in the allocated data
var rng_src = std.rand.DefaultPrng.init(19930913);
const random = rng_src.random();
var rounds: usize = 25;
while (rounds > 0) {
rounds -= 1;
_ = arena_allocator.reset(.retain_capacity);
var alloced_bytes: usize = 0;
var total_size: usize = random.intRangeAtMost(usize, 256, 16384);
while (alloced_bytes < total_size) {
const size = random.intRangeAtMost(usize, 16, 256);
const alignment = 32;
const slice = try arena_allocator.allocator().alignedAlloc(u8, alignment, size);
try std.testing.expect(std.mem.isAligned(@intFromPtr(slice.ptr), alignment));
try std.testing.expectEqual(size, slice.len);
alloced_bytes += slice.len;
}
}
}
test "ArenaAllocator (reset while retaining a buffer)" {
var arena_allocator = ArenaAllocator.init(std.testing.allocator);
defer arena_allocator.deinit();
const a = arena_allocator.allocator();
// Create two internal buffers
_ = try a.alloc(u8, 1);
_ = try a.alloc(u8, 1000);
// Check that we have at least two buffers
try std.testing.expect(arena_allocator.state.buffer_list.first.?.next != null);
// This retains the first allocated buffer
try std.testing.expect(arena_allocator.reset(.{ .retain_with_limit = 1 }));
}

View File

@@ -55,7 +55,7 @@ pub const version: @import("./install/semver.zig").Version = .{
pub fn setThreadName(name: StringTypes.stringZ) void {
if (Environment.isLinux) {
_ = std.os.prctl(.SET_NAME, .{@ptrToInt(name.ptr)}) catch 0;
_ = std.os.prctl(.SET_NAME, .{@intFromPtr(name.ptr)}) catch 0;
} else if (Environment.isMac) {
_ = std.c.pthread_setname_np(name);
}

View File

@@ -2,19 +2,18 @@ const std = @import("std");
const FeatureFlags = @import("./feature_flags.zig");
const Environment = @import("./env.zig");
const Wyhash = std.hash.Wyhash;
const FixedBufferAllocator = std.heap.FixedBufferAllocator;
const constStrToU8 = @import("root").bun.constStrToU8;
const bun = @import("root").bun;
pub fn isSliceInBuffer(slice: anytype, buffer: anytype) bool {
return (@ptrToInt(&buffer) <= @ptrToInt(slice.ptr) and (@ptrToInt(slice.ptr) + slice.len) <= (@ptrToInt(buffer) + buffer.len));
return (@intFromPtr(&buffer) <= @intFromPtr(slice.ptr) and (@intFromPtr(slice.ptr) + slice.len) <= (@intFromPtr(buffer) + buffer.len));
}
pub fn sliceRange(slice: []const u8, buffer: []const u8) ?[2]u32 {
return if (@ptrToInt(buffer.ptr) <= @ptrToInt(slice.ptr) and
(@ptrToInt(slice.ptr) + slice.len) <= (@ptrToInt(buffer.ptr) + buffer.len))
return if (@intFromPtr(buffer.ptr) <= @intFromPtr(slice.ptr) and
(@intFromPtr(slice.ptr) + slice.len) <= (@intFromPtr(buffer.ptr) + buffer.len))
[2]u32{
@truncate(u32, @ptrToInt(slice.ptr) - @ptrToInt(buffer.ptr)),
@truncate(u32, @intFromPtr(slice.ptr) - @intFromPtr(buffer.ptr)),
@truncate(u32, slice.len),
}
else
@@ -53,7 +52,6 @@ pub const Result = struct {
return r.index >= count;
}
};
const Seed = 999;
pub const NotFound = IndexType{
.index = std.math.maxInt(u31),
@@ -488,7 +486,7 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, comptime store_
pub fn getOrPut(self: *Self, denormalized_key: []const u8) !Result {
const key = if (comptime remove_trailing_slashes) std.mem.trimRight(u8, denormalized_key, "/") else denormalized_key;
const _key = Wyhash.hash(Seed, key);
const _key = bun.hash(key);
self.mutex.lock();
defer self.mutex.unlock();
@@ -516,7 +514,7 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, comptime store_
pub fn get(self: *Self, denormalized_key: []const u8) ?*ValueType {
const key = if (comptime remove_trailing_slashes) std.mem.trimRight(u8, denormalized_key, "/") else denormalized_key;
const _key = Wyhash.hash(Seed, key);
const _key = bun.hash(key);
self.mutex.lock();
defer self.mutex.unlock();
const index = self.index.get(_key) orelse return null;
@@ -577,7 +575,7 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, comptime store_
const key = if (comptime remove_trailing_slashes) std.mem.trimRight(u8, denormalized_key, "/") else denormalized_key;
const _key = Wyhash.hash(Seed, key);
const _key = bun.hash(key);
_ = self.index.remove(_key);
// const index = self.index.get(_key) orelse return;
// switch (index) {

View File

@@ -201,7 +201,7 @@ pub fn Writer(comptime WritableStream: type) type {
}
pub inline fn writeEnum(this: *Self, val: anytype) !void {
try this.writeInt(@enumToInt(val));
try this.writeInt(@intFromEnum(val));
}
pub fn writeValue(this: *Self, comptime SliceType: type, slice: SliceType) !void {

View File

@@ -261,7 +261,7 @@ pub const GenerateHeader = struct {
pub const GeneratePlatform = struct {
var osversion_name: [32]u8 = undefined;
pub fn forMac() Analytics.Platform {
@memset(&osversion_name, 0, osversion_name.len);
@memset(&osversion_name, 0);
var platform = Analytics.Platform{ .os = Analytics.OperatingSystem.macos, .version = &[_]u8{}, .arch = platform_arch };
var len = osversion_name.len - 1;
@@ -340,7 +340,7 @@ pub const GenerateHeader = struct {
offset = std.mem.indexOfScalar(u8, out, '"') orelse return Analytics.Uint64{};
out = out[0..offset];
const hash = std.hash.Wyhash.hash(0, std.mem.trim(u8, out, "\n\r "));
const hash = bun.hash(std.mem.trim(u8, out, "\n\r "));
var hash_bytes = std.mem.asBytes(&hash);
return Analytics.Uint64{
.first = std.mem.readIntNative(u32, hash_bytes[0..4]),
@@ -357,7 +357,7 @@ pub const GenerateHeader = struct {
defer file.close();
var read_count = try file.read(&linux_machine_id);
const hash = std.hash.Wyhash.hash(0, std.mem.trim(u8, linux_machine_id[0..read_count], "\n\r "));
const hash = bun.hash(std.mem.trim(u8, linux_machine_id[0..read_count], "\n\r "));
var hash_bytes = std.mem.asBytes(&hash);
return Analytics.Uint64{
.first = std.mem.readIntNative(u32, hash_bytes[0..4]),
@@ -540,8 +540,8 @@ pub const EventList = struct {
}
@atomicStore(bool, &is_stuck, retry_remaining == 0, .Release);
stuck_count += @intCast(u8, @boolToInt(retry_remaining == 0));
stuck_count *= @intCast(u8, @boolToInt(retry_remaining == 0));
stuck_count += @intCast(u8, @intFromBool(retry_remaining == 0));
stuck_count *= @intCast(u8, @intFromBool(retry_remaining == 0));
disabled = disabled or stuck_count > 4;
this.in_buffer.reset();

View File

@@ -201,7 +201,7 @@ pub fn Writer(comptime WritableStream: type) type {
}
pub inline fn writeEnum(this: *Self, val: anytype) !void {
try this.writeInt(@enumToInt(val));
try this.writeInt(@intFromEnum(val));
}
pub fn writeValue(this: *Self, comptime SliceType: type, slice: SliceType) !void {
@@ -881,9 +881,9 @@ pub const Api = struct {
try writer.writeValue(@TypeOf(this.factory), this.factory);
try writer.writeEnum(this.runtime);
try writer.writeValue(@TypeOf(this.fragment), this.fragment);
try writer.writeInt(@as(u8, @boolToInt(this.development)));
try writer.writeInt(@as(u8, @intFromBool(this.development)));
try writer.writeValue(@TypeOf(this.import_source), this.import_source);
try writer.writeInt(@as(u8, @boolToInt(this.react_fast_refresh)));
try writer.writeInt(@as(u8, @intFromBool(this.react_fast_refresh)));
}
};
@@ -1151,7 +1151,7 @@ pub const Api = struct {
pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
try writer.writeEnum(this.kind);
try writer.writeValue(@TypeOf(this.path), this.path);
try writer.writeInt(@as(u8, @boolToInt(this.dynamic)));
try writer.writeInt(@as(u8, @intFromBool(this.dynamic)));
}
};
@@ -1390,7 +1390,7 @@ pub const Api = struct {
}
if (this.development) |development| {
try writer.writeFieldID(5);
try writer.writeInt(@as(u8, @boolToInt(development)));
try writer.writeInt(@as(u8, @intFromBool(development)));
}
if (this.client_css_in_js) |client_css_in_js| {
try writer.writeFieldID(6);
@@ -1564,7 +1564,7 @@ pub const Api = struct {
pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
try writer.writeValue(@TypeOf(this.package), this.package);
try writer.writeValue(@TypeOf(this.display_name), this.display_name);
try writer.writeInt(@as(u8, @boolToInt(this.development)));
try writer.writeInt(@as(u8, @intFromBool(this.development)));
try writer.writeValue(@TypeOf(this.entry_points), this.entry_points);
try writer.writeEnum(this.client_css_in_js);
try writer.writeValue(@TypeOf(this.override_modules), this.override_modules);
@@ -1866,7 +1866,7 @@ pub const Api = struct {
}
if (this.preserve_symlinks) |preserve_symlinks| {
try writer.writeFieldID(7);
try writer.writeInt(@as(u8, @boolToInt(preserve_symlinks)));
try writer.writeInt(@as(u8, @intFromBool(preserve_symlinks)));
}
if (this.entry_points) |entry_points| {
try writer.writeFieldID(8);
@@ -1874,7 +1874,7 @@ pub const Api = struct {
}
if (this.write) |write| {
try writer.writeFieldID(9);
try writer.writeInt(@as(u8, @boolToInt(write)));
try writer.writeInt(@as(u8, @intFromBool(write)));
}
if (this.inject) |inject| {
try writer.writeFieldID(10);
@@ -1902,7 +1902,7 @@ pub const Api = struct {
}
if (this.serve) |serve| {
try writer.writeFieldID(16);
try writer.writeInt(@as(u8, @boolToInt(serve)));
try writer.writeInt(@as(u8, @intFromBool(serve)));
}
if (this.extension_order) |extension_order| {
try writer.writeFieldID(17);
@@ -1910,7 +1910,7 @@ pub const Api = struct {
}
if (this.generate_node_module_bundle) |generate_node_module_bundle| {
try writer.writeFieldID(18);
try writer.writeInt(@as(u8, @boolToInt(generate_node_module_bundle)));
try writer.writeInt(@as(u8, @intFromBool(generate_node_module_bundle)));
}
if (this.node_modules_bundle_path) |node_modules_bundle_path| {
try writer.writeFieldID(19);
@@ -1930,11 +1930,11 @@ pub const Api = struct {
}
if (this.no_summary) |no_summary| {
try writer.writeFieldID(23);
try writer.writeInt(@as(u8, @boolToInt(no_summary)));
try writer.writeInt(@as(u8, @intFromBool(no_summary)));
}
if (this.disable_hmr) |disable_hmr| {
try writer.writeFieldID(24);
try writer.writeInt(@as(u8, @boolToInt(disable_hmr)));
try writer.writeInt(@as(u8, @intFromBool(disable_hmr)));
}
if (this.port) |port| {
try writer.writeFieldID(25);
@@ -2259,7 +2259,7 @@ pub const Api = struct {
}
if (this.build) |build| {
try writer.writeFieldID(2);
try writer.writeInt(@as(u8, @boolToInt(build)));
try writer.writeInt(@as(u8, @intFromBool(build)));
}
try writer.endMessage();
}
@@ -2822,35 +2822,35 @@ pub const Api = struct {
}
if (this.dry_run) |dry_run| {
try writer.writeFieldID(6);
try writer.writeInt(@as(u8, @boolToInt(dry_run)));
try writer.writeInt(@as(u8, @intFromBool(dry_run)));
}
if (this.force) |force| {
try writer.writeFieldID(7);
try writer.writeInt(@as(u8, @boolToInt(force)));
try writer.writeInt(@as(u8, @intFromBool(force)));
}
if (this.save_dev) |save_dev| {
try writer.writeFieldID(8);
try writer.writeInt(@as(u8, @boolToInt(save_dev)));
try writer.writeInt(@as(u8, @intFromBool(save_dev)));
}
if (this.save_optional) |save_optional| {
try writer.writeFieldID(9);
try writer.writeInt(@as(u8, @boolToInt(save_optional)));
try writer.writeInt(@as(u8, @intFromBool(save_optional)));
}
if (this.save_peer) |save_peer| {
try writer.writeFieldID(10);
try writer.writeInt(@as(u8, @boolToInt(save_peer)));
try writer.writeInt(@as(u8, @intFromBool(save_peer)));
}
if (this.save_lockfile) |save_lockfile| {
try writer.writeFieldID(11);
try writer.writeInt(@as(u8, @boolToInt(save_lockfile)));
try writer.writeInt(@as(u8, @intFromBool(save_lockfile)));
}
if (this.production) |production| {
try writer.writeFieldID(12);
try writer.writeInt(@as(u8, @boolToInt(production)));
try writer.writeInt(@as(u8, @intFromBool(production)));
}
if (this.save_yarn_lockfile) |save_yarn_lockfile| {
try writer.writeFieldID(13);
try writer.writeInt(@as(u8, @boolToInt(save_yarn_lockfile)));
try writer.writeInt(@as(u8, @intFromBool(save_yarn_lockfile)));
}
if (this.native_bin_links) |native_bin_links| {
try writer.writeFieldID(14);
@@ -2858,11 +2858,11 @@ pub const Api = struct {
}
if (this.disable_cache) |disable_cache| {
try writer.writeFieldID(15);
try writer.writeInt(@as(u8, @boolToInt(disable_cache)));
try writer.writeInt(@as(u8, @intFromBool(disable_cache)));
}
if (this.disable_manifest_cache) |disable_manifest_cache| {
try writer.writeFieldID(16);
try writer.writeInt(@as(u8, @boolToInt(disable_manifest_cache)));
try writer.writeInt(@as(u8, @intFromBool(disable_manifest_cache)));
}
if (this.global_dir) |global_dir| {
try writer.writeFieldID(17);

View File

@@ -201,7 +201,7 @@ pub fn Writer(comptime WritableStream: type) type {
}
pub inline fn writeEnum(this: *Self, val: anytype) !void {
try this.writeInt(@enumToInt(val));
try this.writeInt(@intFromEnum(val));
}
pub fn writeValue(this: *Self, comptime SliceType: type, slice: SliceType) !void {
@@ -896,9 +896,9 @@ pub const Api = struct {
try writer.writeValue(@TypeOf(this.factory), this.factory);
try writer.writeEnum(this.runtime);
try writer.writeValue(@TypeOf(this.fragment), this.fragment);
try writer.writeInt(@as(u8, @boolToInt(this.development)));
try writer.writeInt(@as(u8, @intFromBool(this.development)));
try writer.writeValue(@TypeOf(this.import_source), this.import_source);
try writer.writeInt(@as(u8, @boolToInt(this.react_fast_refresh)));
try writer.writeInt(@as(u8, @intFromBool(this.react_fast_refresh)));
}
};
@@ -1166,7 +1166,7 @@ pub const Api = struct {
pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
try writer.writeEnum(this.kind);
try writer.writeValue(@TypeOf(this.path), this.path);
try writer.writeInt(@as(u8, @boolToInt(this.dynamic)));
try writer.writeInt(@as(u8, @intFromBool(this.dynamic)));
}
};
@@ -1405,7 +1405,7 @@ pub const Api = struct {
}
if (this.development) |development| {
try writer.writeFieldID(5);
try writer.writeInt(@as(u8, @boolToInt(development)));
try writer.writeInt(@as(u8, @intFromBool(development)));
}
if (this.client_css_in_js) |client_css_in_js| {
try writer.writeFieldID(6);
@@ -1579,7 +1579,7 @@ pub const Api = struct {
pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
try writer.writeValue(@TypeOf(this.package), this.package);
try writer.writeValue(@TypeOf(this.display_name), this.display_name);
try writer.writeInt(@as(u8, @boolToInt(this.development)));
try writer.writeInt(@as(u8, @intFromBool(this.development)));
try writer.writeValue(@TypeOf(this.entry_points), this.entry_points);
try writer.writeEnum(this.client_css_in_js);
try writer.writeValue(@TypeOf(this.override_modules), this.override_modules);
@@ -1887,7 +1887,7 @@ pub const Api = struct {
}
if (this.preserve_symlinks) |preserve_symlinks| {
try writer.writeFieldID(7);
try writer.writeInt(@as(u8, @boolToInt(preserve_symlinks)));
try writer.writeInt(@as(u8, @intFromBool(preserve_symlinks)));
}
if (this.entry_points) |entry_points| {
try writer.writeFieldID(8);
@@ -1895,7 +1895,7 @@ pub const Api = struct {
}
if (this.write) |write| {
try writer.writeFieldID(9);
try writer.writeInt(@as(u8, @boolToInt(write)));
try writer.writeInt(@as(u8, @intFromBool(write)));
}
if (this.inject) |inject| {
try writer.writeFieldID(10);
@@ -1923,7 +1923,7 @@ pub const Api = struct {
}
if (this.serve) |serve| {
try writer.writeFieldID(16);
try writer.writeInt(@as(u8, @boolToInt(serve)));
try writer.writeInt(@as(u8, @intFromBool(serve)));
}
if (this.extension_order) |extension_order| {
try writer.writeFieldID(17);
@@ -1931,7 +1931,7 @@ pub const Api = struct {
}
if (this.generate_node_module_bundle) |generate_node_module_bundle| {
try writer.writeFieldID(18);
try writer.writeInt(@as(u8, @boolToInt(generate_node_module_bundle)));
try writer.writeInt(@as(u8, @intFromBool(generate_node_module_bundle)));
}
if (this.node_modules_bundle_path) |node_modules_bundle_path| {
try writer.writeFieldID(19);
@@ -1951,11 +1951,11 @@ pub const Api = struct {
}
if (this.no_summary) |no_summary| {
try writer.writeFieldID(23);
try writer.writeInt(@as(u8, @boolToInt(no_summary)));
try writer.writeInt(@as(u8, @intFromBool(no_summary)));
}
if (this.disable_hmr) |disable_hmr| {
try writer.writeFieldID(24);
try writer.writeInt(@as(u8, @boolToInt(disable_hmr)));
try writer.writeInt(@as(u8, @intFromBool(disable_hmr)));
}
if (this.port) |port| {
try writer.writeFieldID(25);
@@ -2427,7 +2427,7 @@ pub const Api = struct {
}
if (this.build) |build| {
try writer.writeFieldID(2);
try writer.writeInt(@as(u8, @boolToInt(build)));
try writer.writeInt(@as(u8, @intFromBool(build)));
}
try writer.endMessage();
}
@@ -2995,35 +2995,35 @@ pub const Api = struct {
}
if (this.dry_run) |dry_run| {
try writer.writeFieldID(6);
try writer.writeInt(@as(u8, @boolToInt(dry_run)));
try writer.writeInt(@as(u8, @intFromBool(dry_run)));
}
if (this.force) |force| {
try writer.writeFieldID(7);
try writer.writeInt(@as(u8, @boolToInt(force)));
try writer.writeInt(@as(u8, @intFromBool(force)));
}
if (this.save_dev) |save_dev| {
try writer.writeFieldID(8);
try writer.writeInt(@as(u8, @boolToInt(save_dev)));
try writer.writeInt(@as(u8, @intFromBool(save_dev)));
}
if (this.save_optional) |save_optional| {
try writer.writeFieldID(9);
try writer.writeInt(@as(u8, @boolToInt(save_optional)));
try writer.writeInt(@as(u8, @intFromBool(save_optional)));
}
if (this.save_peer) |save_peer| {
try writer.writeFieldID(10);
try writer.writeInt(@as(u8, @boolToInt(save_peer)));
try writer.writeInt(@as(u8, @intFromBool(save_peer)));
}
if (this.save_lockfile) |save_lockfile| {
try writer.writeFieldID(11);
try writer.writeInt(@as(u8, @boolToInt(save_lockfile)));
try writer.writeInt(@as(u8, @intFromBool(save_lockfile)));
}
if (this.production) |production| {
try writer.writeFieldID(12);
try writer.writeInt(@as(u8, @boolToInt(production)));
try writer.writeInt(@as(u8, @intFromBool(production)));
}
if (this.save_yarn_lockfile) |save_yarn_lockfile| {
try writer.writeFieldID(13);
try writer.writeInt(@as(u8, @boolToInt(save_yarn_lockfile)));
try writer.writeInt(@as(u8, @intFromBool(save_yarn_lockfile)));
}
if (this.native_bin_links) |native_bin_links| {
try writer.writeFieldID(14);
@@ -3031,11 +3031,11 @@ pub const Api = struct {
}
if (this.disable_cache) |disable_cache| {
try writer.writeFieldID(15);
try writer.writeInt(@as(u8, @boolToInt(disable_cache)));
try writer.writeInt(@as(u8, @intFromBool(disable_cache)));
}
if (this.disable_manifest_cache) |disable_manifest_cache| {
try writer.writeFieldID(16);
try writer.writeInt(@as(u8, @boolToInt(disable_manifest_cache)));
try writer.writeInt(@as(u8, @intFromBool(disable_manifest_cache)));
}
if (this.global_dir) |global_dir| {
try writer.writeFieldID(17);

View File

@@ -275,7 +275,7 @@ pub const Ref = packed struct(u64) {
}
pub inline fn hash64(key: Ref) u64 {
return std.hash.Wyhash.hash(0, &@bitCast([8]u8, key.asU64()));
return bun.hash(&@bitCast([8]u8, key.asU64()));
}
pub fn eql(ref: Ref, b: Ref) bool {

View File

@@ -30,7 +30,7 @@ pub fn BabyList(comptime Type: type) type {
}
pub fn contains(this: @This(), item: []const Type) bool {
return this.len > 0 and @ptrToInt(item.ptr) >= @ptrToInt(this.ptr) and @ptrToInt(item.ptr) < @ptrToInt(this.ptr) + this.len;
return this.len > 0 and @intFromPtr(item.ptr) >= @intFromPtr(this.ptr) and @intFromPtr(item.ptr) < @intFromPtr(this.ptr) + this.len;
}
pub inline fn initConst(items: []const Type) ListType {

View File

@@ -34,7 +34,7 @@ pub fn main() anyerror!void {
var i: usize = 0;
while (j < amount) : (j += 1) {
i = 0;
@memcpy(duped.ptr, contents.ptr, contents.len);
@memcpy(duped[0..contents.len], contents);
}
if (index == std.math.maxInt(usize)) {

View File

@@ -308,7 +308,7 @@ pub fn IntegerBitSet(comptime size: u16) type {
}
fn boolMaskBit(index: usize, value: bool) MaskInt {
if (MaskInt == u0) return 0;
return @as(MaskInt, @boolToInt(value)) << @intCast(ShiftInt, index);
return @as(MaskInt, @intFromBool(value)) << @intCast(ShiftInt, index);
}
};
}
@@ -653,7 +653,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
return index >> @bitSizeOf(ShiftInt);
}
inline fn boolMaskBit(index: usize, value: bool) MaskInt {
return @as(MaskInt, @boolToInt(value)) << @intCast(ShiftInt, index);
return @as(MaskInt, @intFromBool(value)) << @intCast(ShiftInt, index);
}
};
}
@@ -751,7 +751,7 @@ pub const DynamicBitSetUnmanaged = struct {
// fill in any new masks
if (new_masks > old_masks) {
const fill_value = std.math.boolMask(MaskInt, fill);
std.mem.set(MaskInt, self.masks[old_masks..new_masks], fill_value);
@memset(self.masks[old_masks..new_masks], fill_value);
}
}
@@ -1088,7 +1088,7 @@ pub const DynamicBitSetUnmanaged = struct {
return index >> @bitSizeOf(ShiftInt);
}
fn boolMaskBit(index: usize, value: bool) MaskInt {
return @as(MaskInt, @boolToInt(value)) << @intCast(ShiftInt, index);
return @as(MaskInt, @intFromBool(value)) << @intCast(ShiftInt, index);
}
fn numMasks(bit_length: usize) usize {
return (bit_length + (@bitSizeOf(MaskInt) - 1)) / @bitSizeOf(MaskInt);

View File

@@ -42,14 +42,14 @@ pub const Map = struct {
pub fn get(this: *Map, key: string) ?Blob {
this.lock.lock();
defer this.lock.unlock();
return this.map.get(std.hash.Wyhash.hash(0, key));
return this.map.get(bun.hash(key));
}
pub fn put(this: *Map, key: string, blob: Blob) !void {
this.lock.lock();
defer this.lock.unlock();
return try this.map.put(std.hash.Wyhash.hash(0, key), blob);
return try this.map.put(bun.hash(key), blob);
}
pub fn reset(this: *Map) !void {

View File

@@ -65,7 +65,8 @@ export fn OPENSSL_memory_alloc(size: usize) ?*anyopaque {
// BoringSSL always expects memory to be zero'd
export fn OPENSSL_memory_free(ptr: *anyopaque) void {
@memset(@ptrCast([*]u8, ptr), 0, bun.Mimalloc.mi_usable_size(ptr));
const len = bun.Mimalloc.mi_usable_size(ptr);
@memset(@ptrCast([*]u8, ptr)[0..len], 0);
bun.Mimalloc.mi_free(ptr);
}

View File

@@ -1 +1 @@
8
10

View File

@@ -844,7 +844,7 @@ pub const JSBundler = struct {
this.value = .{
.success = .{
.loader = @intToEnum(options.Loader, @intCast(u8, loader_as_int.to(i32))),
.loader = @enumFromInt(options.Loader, @intCast(u8, loader_as_int.to(i32))),
.source_code = source_code,
},
};
@@ -928,7 +928,7 @@ pub const JSBundler = struct {
else
ZigString.fromUTF8(namespace);
const path_string = ZigString.fromUTF8(path);
JSBundlerPlugin__matchOnLoad(globalThis, this, &namespace_string, &path_string, context, @enumToInt(default_loader));
JSBundlerPlugin__matchOnLoad(globalThis, this, &namespace_string, &path_string, context, @intFromEnum(default_loader));
}
pub fn matchOnResolve(
@@ -949,7 +949,7 @@ pub const JSBundler = struct {
ZigString.fromUTF8(namespace);
const path_string = ZigString.fromUTF8(path);
const importer_string = ZigString.fromUTF8(importer);
JSBundlerPlugin__matchOnResolve(globalThis, this, &namespace_string, &path_string, &importer_string, context, @enumToInt(import_record_kind));
JSBundlerPlugin__matchOnResolve(globalThis, this, &namespace_string, &path_string, &importer_string, context, @intFromEnum(import_record_kind));
}
pub fn addPlugin(

View File

@@ -46,7 +46,7 @@ const Expr = JSAst.Expr;
pub usingnamespace JSC.Codegen.JSTranspiler;
bundler: Bundler.Bundler,
arena: std.heap.ArenaAllocator,
arena: @import("root").bun.ArenaAllocator,
transpiler_options: TranspilerOptions,
scan_pass_result: ScanPassResult,
buffer_writer: ?JSPrinter.BufferWriter = null,
@@ -85,7 +85,7 @@ const TranspilerOptions = struct {
// This is going to be hard to not leak
pub const TransformTask = struct {
input_code: ZigString = ZigString.init(""),
protected_input_value: JSC.JSValue = @intToEnum(JSC.JSValue, 0),
protected_input_value: JSC.JSValue = @enumFromInt(JSC.JSValue, 0),
output_code: ZigString = ZigString.init(""),
bundler: Bundler.Bundler = undefined,
log: logger.Log,
@@ -220,8 +220,8 @@ pub const TransformTask = struct {
finish(this.output_code, this.global, promise);
if (@enumToInt(this.protected_input_value) != 0) {
this.protected_input_value = @intToEnum(JSC.JSValue, 0);
if (@intFromEnum(this.protected_input_value) != 0) {
this.protected_input_value = @enumFromInt(JSC.JSValue, 0);
}
this.deinit();
}
@@ -611,7 +611,7 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std
while (length_iter.next()) |value| {
if (value.isString()) {
const length = @truncate(u32, value.getLength(globalThis));
string_count += @as(u32, @boolToInt(length > 0));
string_count += @as(u32, @intFromBool(length > 0));
total_name_buf_len += length;
}
}
@@ -726,7 +726,7 @@ pub fn constructor(
globalThis: *JSC.JSGlobalObject,
callframe: *JSC.CallFrame,
) callconv(.C) ?*Transpiler {
var temp = std.heap.ArenaAllocator.init(getAllocator(globalThis));
var temp = @import("root").bun.ArenaAllocator.init(getAllocator(globalThis));
const arguments = callframe.arguments(3);
var args = JSC.Node.ArgumentsSlice.init(
globalThis.bunVM(),
@@ -877,7 +877,7 @@ fn getParseResult(this: *Transpiler, allocator: std.mem.Allocator, code: []const
for (res.ast.import_records.slice()) |*import| {
if (import.kind.isCommonJS()) {
import.do_commonjs_transform_in_printer = true;
import.module_id = @truncate(u32, std.hash.Wyhash.hash(0, import.path.pretty));
import.module_id = @truncate(u32, bun.hash(import.path.pretty));
}
}
}
@@ -893,7 +893,7 @@ pub fn scan(
JSC.markBinding(@src());
const arguments = callframe.arguments(3);
var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments.ptr[0..arguments.len]);
defer args.arena.deinit();
defer args.deinit();
const code_arg = args.next() orelse {
globalThis.throwInvalidArgumentType("scan", "code", "string or Uint8Array");
return .zero;
@@ -905,7 +905,7 @@ pub fn scan(
};
const code = code_holder.slice();
args.eat();
args.protectEat();
var exception_ref = [_]JSC.C.JSValueRef{null};
var exception: JSC.C.ExceptionRef = &exception_ref;
@@ -940,7 +940,7 @@ pub fn scan(
JSAst.Expr.Data.Store.reset();
}
const parse_result = getParseResult(this, arena.allocator(), code, loader, Bundler.MacroJSValueType.zero) orelse {
var parse_result = getParseResult(this, arena.allocator(), code, loader, Bundler.MacroJSValueType.zero) orelse {
if ((this.bundler.log.warnings + this.bundler.log.errors) > 0) {
globalThis.throwValue(this.bundler.log.toJS(globalThis, globalThis.allocator(), "Parse error"));
return .zero;
@@ -969,7 +969,7 @@ pub fn scan(
const named_exports_value = namedExportsToJS(
globalThis,
parse_result.ast.named_exports,
&parse_result.ast.named_exports,
);
return JSC.JSValue.createObject2(globalThis, imports_label, exports_label, named_imports_value, named_exports_value);
}
@@ -1174,25 +1174,27 @@ pub fn transformSync(
return out.toValueGC(globalThis);
}
fn namedExportsToJS(global: *JSGlobalObject, named_exports: JSAst.Ast.NamedExports) JSC.JSValue {
fn namedExportsToJS(global: *JSGlobalObject, named_exports: *JSAst.Ast.NamedExports) JSC.JSValue {
if (named_exports.count() == 0)
return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArray(global, 0, null, null));
var named_exports_iter = named_exports.iterator();
var stack_fallback = std.heap.stackFallback(@sizeOf(JSC.ZigString) * 32, getAllocator(global));
var stack_fallback = std.heap.stackFallback(@sizeOf(bun.String) * 32, getAllocator(global));
var allocator = stack_fallback.get();
var names = allocator.alloc(
JSC.ZigString,
bun.String,
named_exports.count(),
) catch unreachable;
defer allocator.free(names);
named_exports.sort(strings.StringArrayByIndexSorter{
.keys = named_exports.keys(),
});
var i: usize = 0;
while (named_exports_iter.next()) |entry| {
names[i] = JSC.ZigString.init(entry.key_ptr.*);
names[i] = bun.String.create(entry.key_ptr.*);
i += 1;
}
JSC.ZigString.sortAsc(names[0..i]);
return JSC.JSValue.createStringArray(global, names.ptr, names.len, true);
return bun.String.toJSArray(global, names);
}
const ImportRecord = @import("../../import_record.zig").ImportRecord;
@@ -1200,30 +1202,24 @@ const ImportRecord = @import("../../import_record.zig").ImportRecord;
fn namedImportsToJS(
global: *JSGlobalObject,
import_records: []const ImportRecord,
exception: JSC.C.ExceptionRef,
_: JSC.C.ExceptionRef,
) JSC.JSValue {
var stack_fallback = std.heap.stackFallback(@sizeOf(JSC.C.JSObjectRef) * 32, getAllocator(global));
var allocator = stack_fallback.get();
var i: usize = 0;
const path_label = JSC.ZigString.static("path");
const kind_label = JSC.ZigString.static("kind");
var array_items = allocator.alloc(
JSC.C.JSValueRef,
import_records.len,
) catch unreachable;
defer allocator.free(array_items);
for (import_records) |record| {
const array = JSC.JSValue.createEmptyArray(global, import_records.len);
array.ensureStillAlive();
for (import_records, 0..) |record, i| {
if (record.is_internal) continue;
array.ensureStillAlive();
const path = JSC.ZigString.init(record.path.text).toValueGC(global);
const kind = JSC.ZigString.init(record.kind.label()).toValue(global);
array_items[i] = JSC.JSValue.createObject2(global, path_label, kind_label, path, kind).asObjectRef();
i += 1;
const kind = JSC.ZigString.init(record.kind.label()).toValueGC(global);
array.putIndex(global, @truncate(u32, i), JSC.JSValue.createObject2(global, path_label, kind_label, path, kind));
}
return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArray(global, i, array_items.ptr, exception));
return array;
}
pub fn scanImports(
@@ -1235,6 +1231,8 @@ pub fn scanImports(
var exception_val = [_]JSC.C.JSValueRef{null};
var exception: JSC.C.ExceptionRef = &exception_val;
var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments.ptr[0..arguments.len]);
defer args.deinit();
const code_arg = args.next() orelse {
globalThis.throwInvalidArgumentType("scanImports", "code", "string or Uint8Array");
return .zero;
@@ -1249,7 +1247,7 @@ pub fn scanImports(
return .zero;
};
args.eat();
args.protectEat();
const code = code_holder.slice();
var loader: Loader = this.transpiler_options.default_loader;

File diff suppressed because it is too large Load Diff

View File

@@ -123,7 +123,7 @@ const LibInfo = struct {
this.vm.uws_event_loop.?,
.machport,
true,
@ptrToInt(request.backend.libinfo.machport),
@intFromPtr(request.backend.libinfo.machport),
) == .result,
);
@@ -230,7 +230,7 @@ fn addrInfoCount(addrinfo: *std.c.addrinfo) u32 {
var count: u32 = 1;
var current: ?*std.c.addrinfo = addrinfo.next;
while (current != null) : (current = current.?.next) {
count += @boolToInt(current.?.addr != null);
count += @intFromBool(current.?.addr != null);
}
return count;
}
@@ -241,7 +241,7 @@ pub fn addrInfoToJSArray(
globalThis: *JSC.JSGlobalObject,
) JSC.JSValue {
var stack = std.heap.stackFallback(2048, parent_allocator);
var arena = std.heap.ArenaAllocator.init(stack.get());
var arena = @import("root").bun.ArenaAllocator.init(stack.get());
const array = JSC.JSValue.createEmptyArray(
globalThis,
addrInfoCount(addr_info),
@@ -285,7 +285,7 @@ pub const GetAddrInfo = struct {
pub fn toCAres(this: GetAddrInfo) bun.c_ares.AddrInfo_hints {
var hints: bun.c_ares.AddrInfo_hints = undefined;
@memset(std.mem.asBytes(&hints), 0, @sizeOf(bun.c_ares.AddrInfo_hints));
@memset(std.mem.asBytes(&hints)[0..@sizeOf(bun.c_ares.AddrInfo_hints)], 0);
hints.ai_family = this.options.family.toLibC();
hints.ai_socktype = this.options.socktype.toLibC();
@@ -320,7 +320,7 @@ pub const GetAddrInfo = struct {
}
var hints: std.c.addrinfo = undefined;
@memset(std.mem.asBytes(&hints), 0, @sizeOf(std.c.addrinfo));
@memset(std.mem.asBytes(&hints)[0..@sizeOf(std.c.addrinfo)], 0);
hints.family = this.family.toLibC();
hints.socktype = this.socktype.toLibC();
@@ -385,7 +385,7 @@ pub const GetAddrInfo = struct {
return .unspecified;
if (value.isNumber()) {
return switch (value.to(i32)) {
return switch (value.coerce(i32, globalObject)) {
0 => .unspecified,
4 => .inet,
6 => .inet6,
@@ -394,11 +394,11 @@ pub const GetAddrInfo = struct {
}
if (value.isString()) {
const str = value.getZigString(globalObject);
if (str.len == 0)
const str = value.toBunString(globalObject);
if (str.isEmpty())
return .unspecified;
return map.getWithEql(str, JSC.ZigString.eqlComptime) orelse return error.InvalidFamily;
return str.inMap(map) orelse return error.InvalidFamily;
}
return error.InvalidFamily;
@@ -553,7 +553,7 @@ pub const GetAddrInfo = struct {
.addrinfo => |addrinfo| addrInfoToJSArray(globalThis.allocator(), addrinfo orelse return null, globalThis),
.list => |list| brk: {
var stack = std.heap.stackFallback(2048, globalThis.allocator());
var arena = std.heap.ArenaAllocator.init(stack.get());
var arena = @import("root").bun.ArenaAllocator.init(stack.get());
const array = JSC.JSValue.createEmptyArray(globalThis, @truncate(u32, list.items.len));
var i: u32 = 0;
const items: []const Result = list.items;
@@ -793,7 +793,7 @@ pub const GetAddrInfoRequest = struct {
addr_info: ?*std.c.addrinfo,
arg: ?*anyopaque,
) callconv(.C) void {
const this = @intToPtr(*GetAddrInfoRequest, @ptrToInt(arg));
const this = @ptrFromInt(*GetAddrInfoRequest, @intFromPtr(arg));
log("getAddrInfoAsyncCallback: status={d}", .{status});
if (this.backend == .libinfo) {
@@ -846,8 +846,8 @@ pub const GetAddrInfoRequest = struct {
err,
debug_timer,
});
if (@enumToInt(err) != 0 or addrinfo == null) {
this.* = .{ .err = @enumToInt(err) };
if (@intFromEnum(err) != 0 or addrinfo == null) {
this.* = .{ .err = @intFromEnum(err) };
return;
}

View File

@@ -254,19 +254,17 @@ pub const SocketConfig = struct {
var ssl: ?JSC.API.ServerConfig.SSLConfig = null;
var default_data = JSValue.zero;
if (opts.getTruthy(globalObject, "tls")) |tls| outer: {
if (opts.getTruthy(globalObject, "tls")) |tls| {
if (tls.isBoolean()) {
if (tls.toBoolean()) {
ssl = JSC.API.ServerConfig.SSLConfig.zero;
}
break :outer;
}
if (JSC.API.ServerConfig.SSLConfig.inJS(globalObject, tls, exception)) |ssl_config| {
ssl = ssl_config;
} else if (exception.* != null) {
return null;
} else {
if (JSC.API.ServerConfig.SSLConfig.inJS(globalObject, tls, exception)) |ssl_config| {
ssl = ssl_config;
} else if (exception.* != null) {
return null;
}
}
}
@@ -400,10 +398,10 @@ pub const Listener = struct {
pub fn deinit(this: UnixOrHost) void {
switch (this) {
.unix => |u| {
bun.default_allocator.destroy(@intToPtr([*]u8, @ptrToInt(u.ptr)));
bun.default_allocator.destroy(@ptrFromInt([*]u8, @intFromPtr(u.ptr)));
},
.host => |h| {
bun.default_allocator.destroy(@intToPtr([*]u8, @ptrToInt(h.host.ptr)));
bun.default_allocator.destroy(@ptrFromInt([*]u8, @intFromPtr(h.host.ptr)));
},
}
}
@@ -474,7 +472,7 @@ pub const Listener = struct {
globalObject.bunVM().eventLoop().ensureWaker();
var socket_context = uws.us_create_bun_socket_context(
@boolToInt(ssl_enabled),
@intFromBool(ssl_enabled),
uws.Loop.get().?,
@sizeOf(usize),
ctx_opts,
@@ -485,7 +483,7 @@ pub const Listener = struct {
hostname_or_unix.deinit();
}
const errno = @enumToInt(std.c.getErrno(-1));
const errno = @intFromEnum(std.c.getErrno(-1));
if (errno != 0) {
err.put(globalObject, ZigString.static("errno"), JSValue.jsNumber(errno));
if (bun.C.SystemErrno.init(errno)) |str| {
@@ -546,7 +544,7 @@ pub const Listener = struct {
defer bun.default_allocator.free(host);
const socket = uws.us_socket_context_listen(
@boolToInt(ssl_enabled),
@intFromBool(ssl_enabled),
socket_context,
normalizeHost(@as([:0]const u8, host)),
c.port,
@@ -562,13 +560,13 @@ pub const Listener = struct {
.unix => |u| {
var host = bun.default_allocator.dupeZ(u8, u) catch unreachable;
defer bun.default_allocator.free(host);
break :brk uws.us_socket_context_listen_unix(@boolToInt(ssl_enabled), socket_context, host, socket_flags, 8);
break :brk uws.us_socket_context_listen_unix(@intFromBool(ssl_enabled), socket_context, host, socket_flags, 8);
},
}
} orelse {
defer {
hostname_or_unix.deinit();
uws.us_socket_context_free(@boolToInt(ssl_enabled), socket_context);
uws.us_socket_context_free(@intFromBool(ssl_enabled), socket_context);
}
const err = globalObject.createErrorInstance(
@@ -577,7 +575,7 @@ pub const Listener = struct {
bun.span(hostname_or_unix.slice()),
},
);
const errno = @enumToInt(std.c.getErrno(-1));
const errno = @intFromEnum(std.c.getErrno(-1));
if (errno != 0) {
err.put(globalObject, ZigString.static("errno"), JSValue.jsNumber(errno));
if (bun.C.SystemErrno.init(errno)) |str| {
@@ -791,7 +789,7 @@ pub const Listener = struct {
globalObject.bunVM().eventLoop().ensureWaker();
var socket_context = uws.us_create_bun_socket_context(@boolToInt(ssl_enabled), uws.Loop.get().?, @sizeOf(usize), ctx_opts).?;
var socket_context = uws.us_create_bun_socket_context(@intFromBool(ssl_enabled), uws.Loop.get().?, @sizeOf(usize), ctx_opts).?;
var connection: Listener.UnixOrHost = if (port) |port_| .{
.host = .{ .host = (hostname_or_unix.cloneIfNeeded(bun.default_allocator) catch unreachable).slice(), .port = port_ },
} else .{
@@ -1589,8 +1587,8 @@ fn NewSocket(comptime ssl: bool) type {
globalObject.throw("sendfile() not implemented yet", .{});
return .{ .fail = {} };
} else if (args.ptr[0].toStringOrNull(globalObject)) |jsstring| {
var zig_str = jsstring.toSlice(globalObject, globalObject.bunVM().allocator);
} else if (bun.String.tryFromJS(args.ptr[0], globalObject)) |bun_str| {
var zig_str = bun_str.toUTF8(bun.default_allocator);
defer zig_str.deinit();
var slice = zig_str.slice();

View File

@@ -1011,7 +1011,7 @@ pub const Subprocess = struct {
if (signal.name()) |name|
return JSC.ZigString.init(name).toValueGC(global)
else
return JSC.JSValue.jsNumber(@enumToInt(signal));
return JSC.JSValue.jsNumber(@intFromEnum(signal));
}
return JSC.JSValue.jsNull();
@@ -1031,7 +1031,7 @@ pub const Subprocess = struct {
secondaryArgsValue: ?JSValue,
comptime is_sync: bool,
) JSValue {
var arena = std.heap.ArenaAllocator.init(bun.default_allocator);
var arena = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
defer arena.deinit();
var allocator = arena.allocator();
@@ -1535,9 +1535,9 @@ pub const Subprocess = struct {
}
if (std.os.W.IFSIGNALED(result.status)) {
this.signal_code = @intToEnum(SignalCode, @truncate(u8, std.os.W.TERMSIG(result.status)));
this.signal_code = @enumFromInt(SignalCode, @truncate(u8, std.os.W.TERMSIG(result.status)));
} else if (std.os.W.IFSTOPPED(result.status)) {
this.signal_code = @intToEnum(SignalCode, @truncate(u8, std.os.W.STOPSIG(result.status)));
this.signal_code = @enumFromInt(SignalCode, @truncate(u8, std.os.W.STOPSIG(result.status)));
}
if (!this.hasExited()) {

View File

@@ -137,8 +137,8 @@ pub const FFI = struct {
globalThis,
ZigString.static("ptr"),
ZigString.static("ctx"),
JSC.JSValue.fromPtrAddress(@ptrToInt(function_.step.compiled.ptr)),
JSC.JSValue.fromPtrAddress(@ptrToInt(function_)),
JSC.JSValue.fromPtrAddress(@intFromPtr(function_.step.compiled.ptr)),
JSC.JSValue.fromPtrAddress(@intFromPtr(function_)),
);
},
}
@@ -523,7 +523,7 @@ pub const FFI = struct {
const int = val.to(i32);
switch (int) {
0...ABIType.max => {
abi_types.appendAssumeCapacity(@intToEnum(ABIType, int));
abi_types.appendAssumeCapacity(@enumFromInt(ABIType, int));
continue;
},
else => {
@@ -560,7 +560,7 @@ pub const FFI = struct {
const int = ret_value.toInt32();
switch (int) {
0...ABIType.max => {
return_type = @intToEnum(ABIType, int);
return_type = @enumFromInt(ABIType, int);
break :brk;
},
else => {
@@ -594,11 +594,11 @@ pub const FFI = struct {
if (ptr.isNumber()) {
const num = ptr.asPtrAddress();
if (num > 0)
function.symbol_from_dynamic_library = @intToPtr(*anyopaque, num);
function.symbol_from_dynamic_library = @ptrFromInt(*anyopaque, num);
} else {
const num = ptr.toUInt64NoTruncate();
if (num > 0) {
function.symbol_from_dynamic_library = @intToPtr(*anyopaque, num);
function.symbol_from_dynamic_library = @ptrFromInt(*anyopaque, num);
}
}
}
@@ -866,7 +866,7 @@ pub const FFI = struct {
c: u8,
byte_count: usize,
) callconv(.C) void {
@memset(dest, c, byte_count);
@memset(dest[0..byte_count], c);
}
noinline fn memcpy(
@@ -874,7 +874,7 @@ pub const FFI = struct {
noalias source: [*]const u8,
byte_count: usize,
) callconv(.C) void {
@memcpy(dest, source, byte_count);
@memcpy(dest[0..byte_count], source[0..byte_count]);
}
pub fn define(state: *TCC.TCCState) void {
@@ -1205,7 +1205,7 @@ pub const FFI = struct {
writer: anytype,
) !void {
{
const ptr = @ptrToInt(globalObject);
const ptr = @intFromPtr(globalObject);
const fmt = bun.fmt.hexIntUpper(ptr);
try writer.print("#define JS_GLOBAL_OBJECT (void*)0x{any}ULL\n", .{fmt});
}
@@ -1290,7 +1290,7 @@ pub const FFI = struct {
var inner_buf: []u8 = &.{};
{
const ptr = @ptrToInt(context_ptr);
const ptr = @intFromPtr(context_ptr);
const fmt = bun.fmt.hexIntUpper(ptr);
if (this.arg_types.items.len > 0) {
@@ -1355,7 +1355,7 @@ pub const FFI = struct {
function = 17,
pub const max = @enumToInt(ABIType.function);
pub const max = @intFromEnum(ABIType.function);
/// Types that we can directly pass through as an `int64_t`
pub fn needsACastInC(this: ABIType) bool {
@@ -1414,11 +1414,11 @@ pub const FFI = struct {
// these are not all valid identifiers
try writer.writeAll(self.name);
try writer.writeAll("']:");
try std.fmt.formatInt(@enumToInt(self.entry), 10, .lower, .{}, writer);
try std.fmt.formatInt(@intFromEnum(self.entry), 10, .lower, .{}, writer);
try writer.writeAll(",'");
try std.fmt.formatInt(@enumToInt(self.entry), 10, .lower, .{}, writer);
try std.fmt.formatInt(@intFromEnum(self.entry), 10, .lower, .{}, writer);
try writer.writeAll("':");
try std.fmt.formatInt(@enumToInt(self.entry), 10, .lower, .{}, writer);
try std.fmt.formatInt(@intFromEnum(self.entry), 10, .lower, .{}, writer);
}
};
pub const map_to_js_object = brk: {
@@ -1426,7 +1426,7 @@ pub const FFI = struct {
for (map, 0..) |item, i| {
var fmt = EnumMapFormatter{ .name = item.@"0", .entry = item.@"1" };
count += std.fmt.count("{}", .{fmt});
count += @boolToInt(i > 0);
count += @intFromBool(i > 0);
}
var buf: [count]u8 = undefined;

View File

@@ -153,7 +153,7 @@ pub const FileSystemRouter = struct {
origin: ?*JSC.RefString = null,
base_dir: ?*JSC.RefString = null,
router: Router,
arena: *std.heap.ArenaAllocator = undefined,
arena: *@import("root").bun.ArenaAllocator = undefined,
allocator: std.mem.Allocator = undefined,
asset_prefix: ?*JSC.RefString = null,
@@ -210,8 +210,8 @@ pub const FileSystemRouter = struct {
globalThis.throwInvalidArguments("Expected dir to be a string", .{});
return null;
}
var arena = globalThis.allocator().create(std.heap.ArenaAllocator) catch unreachable;
arena.* = std.heap.ArenaAllocator.init(globalThis.allocator());
var arena = globalThis.allocator().create(@import("root").bun.ArenaAllocator) catch unreachable;
arena.* = @import("root").bun.ArenaAllocator.init(globalThis.allocator());
var allocator = arena.allocator();
var extensions = std.ArrayList(string).init(allocator);
if (argument.get(globalThis, "fileExtensions")) |file_extensions| {
@@ -324,8 +324,8 @@ pub const FileSystemRouter = struct {
pub fn reload(this: *FileSystemRouter, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
var this_value = callframe.this();
var arena = globalThis.allocator().create(std.heap.ArenaAllocator) catch unreachable;
arena.* = std.heap.ArenaAllocator.init(globalThis.allocator());
var arena = globalThis.allocator().create(@import("root").bun.ArenaAllocator) catch unreachable;
arena.* = @import("root").bun.ArenaAllocator.init(globalThis.allocator());
var allocator = arena.allocator();
var vm = globalThis.bunVM();

View File

@@ -472,13 +472,13 @@ pub const HTMLRewriter = struct {
pub fn onFinishedLoading(sink: *BufferOutputSink, bytes: JSC.WebCore.Blob.Store.ReadFile.ResultType) void {
switch (bytes) {
.err => |err| {
if (sink.response.body.value == .Locked and @ptrToInt(sink.response.body.value.Locked.task) == @ptrToInt(sink) and
if (sink.response.body.value == .Locked and @intFromPtr(sink.response.body.value.Locked.task) == @intFromPtr(sink) and
sink.response.body.value.Locked.promise == null)
{
sink.response.body.value = .{ .Empty = {} };
// is there a pending promise?
// we will need to reject it
} else if (sink.response.body.value == .Locked and @ptrToInt(sink.response.body.value.Locked.task) == @ptrToInt(sink) and
} else if (sink.response.body.value == .Locked and @intFromPtr(sink.response.body.value.Locked.task) == @intFromPtr(sink) and
sink.response.body.value.Locked.promise != null)
{
sink.response.body.value.Locked.onReceiveValue = null;

View File

@@ -136,6 +136,8 @@ pub const ServerConfig = struct {
websocket: ?WebSocketServer = null,
inspector: bool = false,
pub const SSLConfig = struct {
server_name: [*c]const u8 = null,
@@ -166,7 +168,7 @@ pub const ServerConfig = struct {
pub fn asUSockets(this_: ?SSLConfig) uws.us_bun_socket_context_options_t {
var ctx_opts: uws.us_bun_socket_context_options_t = undefined;
@memset(@ptrCast([*]u8, &ctx_opts), 0, @sizeOf(uws.us_bun_socket_context_options_t));
@memset(@ptrCast([*]u8, &ctx_opts)[0..@sizeOf(uws.us_bun_socket_context_options_t)], 0);
if (this_) |ssl_config| {
if (ssl_config.key_file_name != null)
@@ -179,7 +181,7 @@ pub const ServerConfig = struct {
ctx_opts.dh_params_file_name = ssl_config.dh_params_file_name;
if (ssl_config.passphrase != null)
ctx_opts.passphrase = ssl_config.passphrase;
ctx_opts.ssl_prefer_low_memory_usage = @boolToInt(ssl_config.low_memory_mode);
ctx_opts.ssl_prefer_low_memory_usage = @intFromBool(ssl_config.low_memory_mode);
if (ssl_config.key) |key| {
ctx_opts.key = key.ptr;
@@ -268,6 +270,11 @@ pub const ServerConfig = struct {
pub fn inJS(global: *JSC.JSGlobalObject, obj: JSC.JSValue, exception: JSC.C.ExceptionRef) ?SSLConfig {
var result = zero;
if (!obj.isObject()) {
JSC.throwInvalidArguments("tls option expects an object", .{}, global, exception);
return null;
}
var any = false;
// Required
@@ -294,7 +301,7 @@ pub const ServerConfig = struct {
var i: u32 = 0;
var valid_count: u32 = 0;
var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
while (i < count) : (i += 1) {
const item = js_obj.getIndex(global, i);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), item, exception)) |sb| {
@@ -349,7 +356,7 @@ pub const ServerConfig = struct {
}
} else {
const native_array = bun.default_allocator.alloc([*c]const u8, 1) catch unreachable;
var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), js_obj, exception)) |sb| {
const sliced = sb.slice();
if (sliced.len > 0) {
@@ -396,7 +403,7 @@ pub const ServerConfig = struct {
var i: u32 = 0;
var valid_count: u32 = 0;
var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
while (i < count) : (i += 1) {
const item = js_obj.getIndex(global, i);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), item, exception)) |sb| {
@@ -451,7 +458,7 @@ pub const ServerConfig = struct {
}
} else {
const native_array = bun.default_allocator.alloc([*c]const u8, 1) catch unreachable;
var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), js_obj, exception)) |sb| {
const sliced = sb.slice();
if (sliced.len > 0) {
@@ -511,7 +518,7 @@ pub const ServerConfig = struct {
var i: u32 = 0;
var valid_count: u32 = 0;
var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
while (i < count) : (i += 1) {
const item = js_obj.getIndex(global, i);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), item, exception)) |sb| {
@@ -566,7 +573,7 @@ pub const ServerConfig = struct {
}
} else {
const native_array = bun.default_allocator.alloc([*c]const u8, 1) catch unreachable;
var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), js_obj, exception)) |sb| {
const sliced = sb.slice();
if (sliced.len > 0) {
@@ -686,7 +693,7 @@ pub const ServerConfig = struct {
}
if (arguments.next()) |arg| {
if (arg.isUndefinedOrNull() or !arg.isObject()) {
if (!arg.isObject()) {
JSC.throwInvalidArguments("Bun.serve expects an object", .{}, global, exception);
return args;
}
@@ -741,7 +748,19 @@ pub const ServerConfig = struct {
}
if (arg.get(global, "development")) |dev| {
args.development = dev.toBoolean();
args.development = dev.coerce(bool, global);
}
if (arg.get(global, "inspector")) |inspector| {
args.inspector = inspector.coerce(bool, global);
if (args.inspector and !args.development) {
JSC.throwInvalidArguments("Cannot enable inspector in production. Please set development: true in Bun.serve()", .{}, global, exception);
if (args.ssl_config) |*conf| {
conf.deinit();
}
return args;
}
}
if (arg.getTruthy(global, "tls")) |tls| {
@@ -798,6 +817,9 @@ pub const ServerConfig = struct {
}
return args;
}
} else {
JSC.throwInvalidArguments("Bun.serve expects an object", .{}, global, exception);
return args;
}
if (args.base_uri.len > 0) {
@@ -1218,7 +1240,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
.reason = .fetch_event_handler,
.cwd = VirtualMachine.get().bundler.fs.top_level_dir,
.problems = Api.Problems{
.code = @truncate(u16, @errorToInt(err)),
.code = @truncate(u16, @intFromError(err)),
.name = @errorName(err),
.exceptions = exceptions,
.build = log.toAPI(allocator) catch unreachable,
@@ -1768,7 +1790,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
}
var err = JSC.Node.Syscall.Error{
.errno = @intCast(JSC.Node.Syscall.Error.Int, @enumToInt(std.os.E.INVAL)),
.errno = @intCast(JSC.Node.Syscall.Error.Int, @intFromEnum(std.os.E.INVAL)),
.syscall = .sendfile,
};
var sys = err.withPathLike(file.pathlike).toSystemError();
@@ -1787,7 +1809,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
}
var err = JSC.Node.Syscall.Error{
.errno = @intCast(JSC.Node.Syscall.Error.Int, @enumToInt(std.os.E.INVAL)),
.errno = @intCast(JSC.Node.Syscall.Error.Int, @intFromEnum(std.os.E.INVAL)),
.syscall = .sendfile,
};
var sys = err.withPathLike(file.pathlike).toSystemError();
@@ -2091,7 +2113,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
const streamLog = Output.scoped(.ReadableStream, false);
pub fn didUpgradeWebSocket(this: *RequestContext) bool {
return @ptrToInt(this.upgrade_context) == std.math.maxInt(usize);
return @intFromPtr(this.upgrade_context) == std.math.maxInt(usize);
}
pub fn onResponse(
@@ -2358,6 +2380,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
}
pub fn doRenderWithBody(this: *RequestContext, value: *JSC.WebCore.Body.Value) void {
// If a ReadableStream can trivially be converted to a Blob, do so.
// If it's a WTFStringImpl and it cannot be used as a UTF-8 string, convert it to a Blob.
value.toBlobIfPossible();
switch (value.*) {
@@ -2372,10 +2396,12 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
return;
},
// .InlineBlob,
.WTFStringImpl,
.InternalBlob,
.Blob,
=> {
this.blob = value.useAsAnyBlob();
// toBlobIfPossible checks for WTFString needing a conversion.
this.blob = value.useAsAnyBlobAllowNonUTF8String();
this.renderWithBlobFromBodyValue();
return;
},
@@ -2514,7 +2540,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
// Faster to do the memcpy than to do the two network calls
// We are not streaming
// This is an important performance optimization
if (this.has_abort_handler and this.blob.size() < 16384 - 1024) {
if (this.has_abort_handler and this.blob.fastSize() < 16384 - 1024) {
if (this.resp) |resp| {
resp.runCorkedWithType(*RequestContext, doRenderBlobCorked, this);
}
@@ -2848,7 +2874,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
const prev_len = bytes.items.len;
bytes.items.len = total;
var slice = bytes.items[prev_len..];
@memcpy(slice.ptr, chunk.ptr, chunk.len);
@memcpy(slice[0..chunk.len], chunk);
body.value = .{
.InternalBlob = .{
.bytes = bytes.toManaged(this.allocator),
@@ -3174,7 +3200,7 @@ pub const WebSocketServer = struct {
globalObject.throwInvalidArguments("websocket expects maxPayloadLength to be an integer", .{});
return null;
}
server.maxPayloadLength = @intCast(u32, @truncate(i33, @max(value.toInt64(), 0)));
server.maxPayloadLength = @intCast(u32, @max(value.toInt64(), 0));
}
}
if (object.get(globalObject, "idleTimeout")) |value| {
@@ -3194,7 +3220,7 @@ pub const WebSocketServer = struct {
return null;
}
server.backpressureLimit = @intCast(u32, @truncate(i33, @max(value.toInt64(), 0)));
server.backpressureLimit = @intCast(u32, @max(value.toInt64(), 0));
}
}
// if (object.get(globalObject, "sendPings")) |value| {
@@ -3340,7 +3366,7 @@ pub const ServerWebSocket = struct {
opcode: uws.Opcode,
) void {
log("onMessage({d}): {s}", .{
@enumToInt(opcode),
@intFromEnum(opcode),
message,
});
const onMessageHandler = this.handler.onMessage;
@@ -4410,7 +4436,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
return JSValue.jsNumber(
// if 0, return 0
// else return number of bytes sent
@as(i32, @boolToInt(uws.AnyWebSocket.publishWithOptions(ssl_enabled, app, topic_slice.slice(), buffer.slice(), .binary, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
@as(i32, @intFromBool(uws.AnyWebSocket.publishWithOptions(ssl_enabled, app, topic_slice.slice(), buffer.slice(), .binary, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
);
}
@@ -4425,7 +4451,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
return JSValue.jsNumber(
// if 0, return 0
// else return number of bytes sent
@as(i32, @boolToInt(uws.AnyWebSocket.publishWithOptions(ssl_enabled, app, topic_slice.slice(), buffer, .text, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
@as(i32, @intFromBool(uws.AnyWebSocket.publishWithOptions(ssl_enabled, app, topic_slice.slice(), buffer, .text, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
);
}
@@ -4462,7 +4488,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
return JSC.jsBoolean(false);
}
if (upgrader.upgrade_context == null or @ptrToInt(upgrader.upgrade_context) == std.math.maxInt(usize)) {
if (upgrader.upgrade_context == null or @intFromPtr(upgrader.upgrade_context) == std.math.maxInt(usize)) {
return JSC.jsBoolean(false);
}
const resp = upgrader.resp.?;
@@ -4556,7 +4582,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
// See https://github.com/oven-sh/bun/issues/1339
// obviously invalid pointer marks it as used
upgrader.upgrade_context = @intToPtr(*uws.uws_socket_context_s, std.math.maxInt(usize));
upgrader.upgrade_context = @ptrFromInt(*uws.uws_socket_context_s, std.math.maxInt(usize));
request.upgrader = null;
resp.clearAborted();
@@ -4921,7 +4947,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
if (reason.len == 0) {
break;
}
@memcpy(output_buf[written..].ptr, reason.ptr, reason.len);
@memcpy(output_buf[written..][0..reason.len], reason);
written += reason.len;
}
@@ -4932,7 +4958,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
if (reason.len > 0) {
output_buf[written..][0.." via ".len].* = " via ".*;
written += " via ".len;
@memcpy(output_buf[written..].ptr, reason.ptr, reason.len);
@memcpy(output_buf[written..][0..reason.len], reason);
written += reason.len;
}
}
@@ -4944,7 +4970,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
if (reason.len > 0) {
output_buf[written..][0] = ' ';
written += 1;
@memcpy(output_buf[written..].ptr, reason.ptr, reason.len);
@memcpy(output_buf[written..][0..reason.len], reason);
written += reason.len;
}
}
@@ -5239,6 +5265,11 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
if (comptime debug_mode) {
this.app.get("/bun:info", *ThisServer, this, onBunInfoRequest);
if (this.config.inspector) {
JSC.markBinding(@src());
Bun__addInspector(ssl_enabled, this.app, this.globalThis);
}
this.app.get("/src:/*", *ThisServer, this, onSrcRequest);
}
@@ -5290,3 +5321,5 @@ pub const AnyServer = union(enum) {
};
const welcome_page_html_gz = @embedFile("welcome-page.html.gz");
extern fn Bun__addInspector(bool, *anyopaque, *JSC.JSGlobalObject) void;

View File

@@ -207,6 +207,15 @@ pub const To = struct {
return array;
},
[]const bun.String => {
defer {
for (value) |out| {
out.deref();
}
bun.default_allocator.free(value);
}
return bun.String.toJSArray(context, value).asObjectRef();
},
[]const PathString, []const []const u8, []const []u8, [][]const u8, [][:0]const u8, [][:0]u8 => {
if (value.len == 0)
return JSC.C.JSObjectMakeArray(context, 0, null, exception);
@@ -1282,23 +1291,27 @@ pub fn NewClassWithInstanceType(
const static_properties: [property_names.len + 1]js.JSStaticValue = brk: {
var props: [property_names.len + 1]js.JSStaticValue = undefined;
std.mem.set(
js.JSStaticValue,
@memset(
&props,
js.JSStaticValue{
.name = @intToPtr([*c]const u8, 0),
.name = @ptrFromInt([*c]const u8, 0),
.getProperty = null,
.setProperty = null,
.attributes = js.JSPropertyAttributes.kJSPropertyAttributeNone,
},
);
if (property_name_literals.len > 0 and @TypeOf(property_name_literals[0]) == [:0]const u8) {
@compileError("@typeInfo() struct field names are null-terminated");
}
for (property_name_literals, 0..) |lit, i| {
props[i] = brk2: {
var static_prop = JSC.C.JSStaticValue{
.name = lit.ptr[0..lit.len :0],
// TODO: update when @typeInfo struct field names are sentinel terminated
// https://github.com/ziglang/zig/issues/16072
.name = lit ++ .{0},
.getProperty = null,
.setProperty = null,
.attributes = @intToEnum(js.JSPropertyAttributes, 0),
.attributes = @enumFromInt(js.JSPropertyAttributes, 0),
};
static_prop.getProperty = StaticProperty(i).getter;
@@ -1387,14 +1400,14 @@ pub fn NewClassWithInstanceType(
const ctxfn = CtxField.rfn;
const Func: std.builtin.Type.Fn = @typeInfo(@TypeOf(if (@typeInfo(@TypeOf(ctxfn)) == .Pointer) ctxfn.* else ctxfn)).Fn;
var attributes: c_uint = @enumToInt(js.JSPropertyAttributes.kJSPropertyAttributeNone);
var attributes: c_uint = @intFromEnum(js.JSPropertyAttributes.kJSPropertyAttributeNone);
if (comptime is_read_only or hasReadOnly(@TypeOf(CtxField))) {
attributes |= @enumToInt(js.JSPropertyAttributes.kJSPropertyAttributeReadOnly);
attributes |= @intFromEnum(js.JSPropertyAttributes.kJSPropertyAttributeReadOnly);
}
if (comptime hasEnumerable(@TypeOf(CtxField)) and !CtxField.enumerable) {
attributes |= @enumToInt(js.JSPropertyAttributes.kJSPropertyAttributeDontEnum);
attributes |= @intFromEnum(js.JSPropertyAttributes.kJSPropertyAttributeDontEnum);
}
const PointerType = comptime brk: {
@@ -1410,7 +1423,7 @@ pub fn NewClassWithInstanceType(
PointerType,
if (@typeInfo(@TypeOf(ctxfn)) == .Pointer) ctxfn.* else ctxfn,
).rfn,
.attributes = @intToEnum(js.JSPropertyAttributes, attributes),
.attributes = @enumFromInt(js.JSPropertyAttributes, attributes),
};
count += 1;
@@ -1429,12 +1442,12 @@ pub fn NewClassWithInstanceType(
def.hasInstance = &staticFunctions.hasInstance;
} else {
const attributes: js.JSPropertyAttributes = brk: {
var base = @enumToInt(js.JSPropertyAttributes.kJSPropertyAttributeNone);
var base = @intFromEnum(js.JSPropertyAttributes.kJSPropertyAttributeNone);
if (is_read_only)
base |= @enumToInt(js.JSPropertyAttributes.kJSPropertyAttributeReadOnly);
base |= @intFromEnum(js.JSPropertyAttributes.kJSPropertyAttributeReadOnly);
break :brk @intToEnum(js.JSPropertyAttributes, base);
break :brk @enumFromInt(js.JSPropertyAttributes, base);
};
__static_functions[count] = js.JSStaticFunction{
@@ -1825,7 +1838,7 @@ pub const ArrayBuffer = extern struct {
this.ptr,
this.byte_len,
MarkedArrayBuffer_deallocator,
@intToPtr(*anyopaque, @ptrToInt(&bun.default_allocator)),
@ptrFromInt(*anyopaque, @intFromPtr(&bun.default_allocator)),
exception,
));
}
@@ -1836,7 +1849,7 @@ pub const ArrayBuffer = extern struct {
this.ptr,
this.byte_len,
MarkedArrayBuffer_deallocator,
@intToPtr(*anyopaque, @ptrToInt(&bun.default_allocator)),
@ptrFromInt(*anyopaque, @intFromPtr(&bun.default_allocator)),
exception,
));
}
@@ -2042,8 +2055,8 @@ pub const RefString = struct {
ptr: [*]const u8 = undefined,
len: usize = 0,
hash: Hash = 0,
impl: bun.WTF.StringImpl,
count: u32 = 0,
allocator: std.mem.Allocator,
ctx: ?*anyopaque = null,
@@ -2053,17 +2066,13 @@ pub const RefString = struct {
pub const Map = std.HashMap(Hash, *JSC.RefString, IdentityContext(Hash), 80);
pub fn toJS(this: *RefString, global: *JSC.JSGlobalObject) JSValue {
return JSC.ZigString.init(this.slice()).external(global, this, RefString__external);
return bun.String.init(this.impl).toJS(global);
}
pub const Callback = fn (ctx: *anyopaque, str: *RefString) void;
pub fn computeHash(input: []const u8) u32 {
return @truncate(u32, std.hash.Wyhash.hash(0, input));
}
pub fn ref(this: *RefString) void {
this.count += 1;
return std.hash.XxHash32.hash(0, input);
}
pub fn slice(this: *RefString) []const u8 {
@@ -2072,25 +2081,21 @@ pub const RefString = struct {
return this.leak();
}
pub fn ref(this: *RefString) void {
this.impl.ref();
}
pub fn leak(this: RefString) []const u8 {
@setRuntimeSafety(false);
return this.ptr[0..this.len];
}
pub fn deref(this: *RefString) void {
this.count -|= 1;
if (this.count == 0) {
this.deinit();
}
this.impl.deref();
}
pub export fn RefString__free(this: *RefString, _: [*]const u8, _: usize) void {
this.deref();
}
pub export fn RefString__external(this: ?*anyopaque, _: ?*anyopaque, _: usize) void {
bun.cast(*RefString, this.?).deref();
pub export fn RefString__free(this: *anyopaque, _: *anyopaque, _: u32) void {
bun.cast(*RefString, this).deinit();
}
pub fn deinit(this: *RefString) void {
@@ -3125,6 +3130,29 @@ pub fn wrapStaticMethod(
args[i] = null;
}
},
JSC.Node.SliceOrBuffer => {
const arg = iter.nextEat() orelse {
globalThis.throwInvalidArguments("expected string or buffer", .{});
iter.deinit();
return JSC.JSValue.zero;
};
args[i] = JSC.Node.SliceOrBuffer.fromJS(globalThis.ptr(), iter.arena.allocator(), arg) orelse {
globalThis.throwInvalidArguments("expected string or buffer", .{});
iter.deinit();
return JSC.JSValue.zero;
};
},
?JSC.Node.SliceOrBuffer => {
if (iter.nextEat()) |arg| {
args[i] = JSC.Node.SliceOrBuffer.fromJS(globalThis.ptr(), iter.arena.allocator(), arg) orelse {
globalThis.throwInvalidArguments("expected string or buffer", .{});
iter.deinit();
return JSC.JSValue.zero;
};
} else {
args[i] = null;
}
},
JSC.ArrayBuffer => {
if (iter.nextEat()) |arg| {
args[i] = arg.asArrayBuffer(globalThis.ptr()) orelse {
@@ -3331,7 +3359,7 @@ pub const FilePoll = struct {
const DNSResolver = JSC.DNS.DNSResolver;
const GetAddrInfoRequest = JSC.DNS.GetAddrInfoRequest;
const Deactivated = opaque {
pub var owner: Owner = Owner.init(@intToPtr(*Deactivated, @as(usize, 0xDEADBEEF)));
pub var owner: Owner = Owner.init(@ptrFromInt(*Deactivated, @as(usize, 0xDEADBEEF)));
};
pub const Owner = bun.TaggedPointerUnion(.{
@@ -3586,7 +3614,7 @@ pub const FilePoll = struct {
return;
this.flags.insert(.disable);
vm.uws_event_loop.?.active -= @as(u32, @boolToInt(this.flags.contains(.has_incremented_poll_count)));
vm.uws_event_loop.?.active -= @as(u32, @intFromBool(this.flags.contains(.has_incremented_poll_count)));
}
pub fn enableKeepingProcessAlive(this: *FilePoll, vm: *JSC.VirtualMachine) void {
@@ -3594,7 +3622,7 @@ pub const FilePoll = struct {
return;
this.flags.remove(.disable);
vm.uws_event_loop.?.active += @as(u32, @boolToInt(this.flags.contains(.has_incremented_poll_count)));
vm.uws_event_loop.?.active += @as(u32, @intFromBool(this.flags.contains(.has_incremented_poll_count)));
}
pub fn canActivate(this: *const FilePoll) bool {
@@ -3604,16 +3632,16 @@ pub const FilePoll = struct {
/// Only intended to be used from EventLoop.Pollable
pub fn deactivate(this: *FilePoll, loop: *uws.Loop) void {
std.debug.assert(this.flags.contains(.has_incremented_poll_count));
loop.num_polls -= @as(i32, @boolToInt(this.flags.contains(.has_incremented_poll_count)));
loop.active -|= @as(u32, @boolToInt(!this.flags.contains(.disable) and this.flags.contains(.has_incremented_poll_count)));
loop.num_polls -= @as(i32, @intFromBool(this.flags.contains(.has_incremented_poll_count)));
loop.active -|= @as(u32, @intFromBool(!this.flags.contains(.disable) and this.flags.contains(.has_incremented_poll_count)));
this.flags.remove(.has_incremented_poll_count);
}
/// Only intended to be used from EventLoop.Pollable
pub fn activate(this: *FilePoll, loop: *uws.Loop) void {
loop.num_polls += @as(i32, @boolToInt(!this.flags.contains(.has_incremented_poll_count)));
loop.active += @as(u32, @boolToInt(!this.flags.contains(.disable) and !this.flags.contains(.has_incremented_poll_count)));
loop.num_polls += @as(i32, @intFromBool(!this.flags.contains(.has_incremented_poll_count)));
loop.active += @as(u32, @intFromBool(!this.flags.contains(.disable) and !this.flags.contains(.has_incremented_poll_count)));
this.flags.insert(.has_incremented_poll_count);
}
@@ -3714,7 +3742,7 @@ pub const FilePoll = struct {
else => unreachable,
};
var event = linux.epoll_event{ .events = flags, .data = .{ .u64 = @ptrToInt(Pollable.init(this).ptr()) } };
var event = linux.epoll_event{ .events = flags, .data = .{ .u64 = @intFromPtr(Pollable.init(this).ptr()) } };
const ctl = linux.epoll_ctl(
watcher_fd,
@@ -3735,7 +3763,7 @@ pub const FilePoll = struct {
.filter = std.os.system.EVFILT_READ,
.data = 0,
.fflags = 0,
.udata = @ptrToInt(Pollable.init(this).ptr()),
.udata = @intFromPtr(Pollable.init(this).ptr()),
.flags = std.c.EV_ADD | one_shot_flag,
.ext = .{ this.generation_number, 0 },
},
@@ -3744,7 +3772,7 @@ pub const FilePoll = struct {
.filter = std.os.system.EVFILT_WRITE,
.data = 0,
.fflags = 0,
.udata = @ptrToInt(Pollable.init(this).ptr()),
.udata = @intFromPtr(Pollable.init(this).ptr()),
.flags = std.c.EV_ADD | one_shot_flag,
.ext = .{ this.generation_number, 0 },
},
@@ -3753,7 +3781,7 @@ pub const FilePoll = struct {
.filter = std.os.system.EVFILT_PROC,
.data = 0,
.fflags = std.c.NOTE_EXIT,
.udata = @ptrToInt(Pollable.init(this).ptr()),
.udata = @intFromPtr(Pollable.init(this).ptr()),
.flags = std.c.EV_ADD | one_shot_flag,
.ext = .{ this.generation_number, 0 },
},
@@ -3762,7 +3790,7 @@ pub const FilePoll = struct {
.filter = std.os.system.EVFILT_MACHPORT,
.data = 0,
.fflags = 0,
.udata = @ptrToInt(Pollable.init(this).ptr()),
.udata = @intFromPtr(Pollable.init(this).ptr()),
.flags = std.c.EV_ADD | one_shot_flag,
.ext = .{ this.generation_number, 0 },
},
@@ -3887,7 +3915,7 @@ pub const FilePoll = struct {
.filter = std.os.system.EVFILT_READ,
.data = 0,
.fflags = 0,
.udata = @ptrToInt(Pollable.init(this).ptr()),
.udata = @intFromPtr(Pollable.init(this).ptr()),
.flags = std.c.EV_DELETE,
.ext = .{ 0, 0 },
},
@@ -3896,7 +3924,7 @@ pub const FilePoll = struct {
.filter = std.os.system.EVFILT_MACHPORT,
.data = 0,
.fflags = 0,
.udata = @ptrToInt(Pollable.init(this).ptr()),
.udata = @intFromPtr(Pollable.init(this).ptr()),
.flags = std.c.EV_DELETE,
.ext = .{ 0, 0 },
},
@@ -3905,7 +3933,7 @@ pub const FilePoll = struct {
.filter = std.os.system.EVFILT_WRITE,
.data = 0,
.fflags = 0,
.udata = @ptrToInt(Pollable.init(this).ptr()),
.udata = @intFromPtr(Pollable.init(this).ptr()),
.flags = std.c.EV_DELETE,
.ext = .{ 0, 0 },
},
@@ -3914,7 +3942,7 @@ pub const FilePoll = struct {
.filter = std.os.system.EVFILT_PROC,
.data = 0,
.fflags = std.c.NOTE_EXIT,
.udata = @ptrToInt(Pollable.init(this).ptr()),
.udata = @intFromPtr(Pollable.init(this).ptr()),
.flags = std.c.EV_DELETE,
.ext = .{ 0, 0 },
},
@@ -3949,7 +3977,7 @@ pub const FilePoll = struct {
const errno = std.c.getErrno(rc);
switch (rc) {
std.math.minInt(@TypeOf(rc))...-1 => return JSC.Maybe(void).errnoSys(@enumToInt(errno), .kevent).?,
std.math.minInt(@TypeOf(rc))...-1 => return JSC.Maybe(void).errnoSys(@intFromEnum(errno), .kevent).?,
else => {},
}
} else {

View File

@@ -1,54 +0,0 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
#include <JavaScriptCore/AugmentableInspectorControllerClient.h>
#include <JavaScriptCore/InspectorBackendDispatcher.h>
#include <JavaScriptCore/InspectorFrontendRouter.h>
namespace Inspector {
class InspectorAgentBase;
class AugmentableInspectorController {
public:
virtual ~AugmentableInspectorController() {}
virtual AugmentableInspectorControllerClient* augmentableInspectorControllerClient() const = 0;
virtual void setAugmentableInspectorControllerClient(AugmentableInspectorControllerClient*) = 0;
virtual const FrontendRouter& frontendRouter() const = 0;
virtual BackendDispatcher& backendDispatcher() = 0;
virtual void registerAlternateAgent(std::unique_ptr<InspectorAgentBase>) = 0;
bool connected() const { return frontendRouter().hasFrontends(); }
};
} // namespace Inspector
#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)

View File

@@ -1,391 +1,184 @@
#include "BunInspector.h"
#include <JavaScriptCore/Heap.h>
#include <JavaScriptCore/JSGlobalObject.h>
#include <JavaScriptCore/JSGlobalObjectDebugger.h>
#include "root.h"
#include <uws/src/App.h>
namespace Zig {
WTF_MAKE_ISO_ALLOCATED_IMPL(BunInspector);
extern "C" void Bun__waitForDebuggerToStart();
extern "C" void Bun__debuggerIsReady();
static BunInspector* inspectorFromGlobal(Zig::GlobalObject* globalObject)
{
RELEASE_ASSERT(globalObject->bunInspectorPtr);
return reinterpret_cast<BunInspector*>(globalObject->bunInspectorPtr);
}
class BunInspectorConnection {
#include <JavaScriptCore/InspectorFrontendChannel.h>
#include <JavaScriptCore/JSGlobalObjectDebuggable.h>
namespace Bun {
using namespace JSC;
template<bool isSSL>
class BunInspectorConnection : public Inspector::FrontendChannel {
public:
WTF::Deque<WTF::CString> m_messages;
RefPtr<BunInspector> inspector;
bool hasSentWelcomeMessage = false;
BunInspectorConnection(RefPtr<BunInspector> inspector)
: inspector(inspector)
, m_messages()
using BunInspectorSocket = uWS::WebSocket<isSSL, true, BunInspectorConnection*>;
BunInspectorConnection(BunInspectorSocket* ws, JSC::JSGlobalObject* globalObject)
: ws(ws)
, globalObject(globalObject)
, pendingMessages()
{
}
~BunInspectorConnection()
{
}
Inspector::FrontendChannel::ConnectionType connectionType() const override
{
return Inspector::FrontendChannel::ConnectionType::Remote;
}
void onOpen(JSC::JSGlobalObject* globalObject)
{
this->globalObject = globalObject;
this->globalObject->inspectorDebuggable().connect(*this);
}
void onClose()
{
this->globalObject->inspectorDebuggable().disconnect(*this);
this->pendingMessages.clear();
}
void sendMessageToFrontend(const String& message) override
{
send(message);
}
void send(const WTF::String& message)
{
if (ws->getBufferedAmount() == 0) {
WTF::CString messageCString = message.utf8();
ws->send(std::string_view { messageCString.data(), messageCString.length() }, uWS::OpCode::TEXT);
} else {
pendingMessages.append(message);
}
}
void onMessage(std::string_view message)
{
WTF::String messageString = WTF::String::fromUTF8(message.data(), message.length());
this->globalObject->inspectorDebuggable().dispatchMessageFromRemote(WTFMove(messageString));
}
void drain()
{
if (pendingMessages.size() == 0)
return;
if (ws->getBufferedAmount() == 0) {
ws->cork([&]() {
for (auto& message : pendingMessages) {
WTF::CString messageCString = message.utf8();
ws->send(std::string_view { messageCString.data(), messageCString.length() }, uWS::OpCode::TEXT);
}
pendingMessages.clear();
});
}
}
WTF::Vector<WTF::String> pendingMessages;
JSC::JSGlobalObject* globalObject;
BunInspectorSocket* ws;
};
void BunInspector::sendMessageToFrontend(const String& message)
using BunInspectorConnectionNoSSL = BunInspectorConnection<false>;
using SSLBunInspectorConnection = BunInspectorConnection<true>;
template<bool isSSL>
static void addInspector(void* app, JSC::JSGlobalObject* globalObject)
{
if constexpr (isSSL) {
auto handler = uWS::SSLApp::WebSocketBehavior<SSLBunInspectorConnection*> {
/* Settings */
.compression = uWS::DISABLED,
.maxPayloadLength = 16 * 1024 * 1024,
.idleTimeout = 960,
.maxBackpressure = 16 * 1024 * 1024,
.closeOnBackpressureLimit = false,
.resetIdleTimeoutOnSend = true,
.sendPingsAutomatically = true,
/* Handlers */
.upgrade = nullptr,
.open = [globalObject](auto* ws) {
globalObject->setInspectable(true);
*ws->getUserData() = new SSLBunInspectorConnection(ws, globalObject);
SSLBunInspectorConnection* inspector = *ws->getUserData();
inspector->onOpen(globalObject);
//
},
.message = [](auto* ws, std::string_view message, uWS::OpCode opCode) {
SSLBunInspectorConnection* inspector = *(SSLBunInspectorConnection**)ws->getUserData();
inspector->onMessage(message);
//
},
.drain = [](auto* ws) {
SSLBunInspectorConnection* inspector = *(SSLBunInspectorConnection**)ws->getUserData();
inspector->drain();
//
},
.ping = [](auto* /*ws*/, std::string_view) {
/* Not implemented yet */ },
.pong = [](auto* /*ws*/, std::string_view) {
/* Not implemented yet */ },
String out = message;
auto jsonObject = WTF::JSONImpl::Value::parseJSON(message);
if (jsonObject) {
if (auto object = jsonObject->asObject()) {
auto method = object->getString("method"_s);
.close = [](auto* ws, int /*code*/, std::string_view /*message*/) {
SSLBunInspectorConnection* inspector = *(SSLBunInspectorConnection**)ws->getUserData();
inspector->onClose();
delete inspector; }
};
// {
// "scriptId": "384",
// "url": "file:///private/tmp/empty.js",
// "startLine": 0,
// "startColumn": 0,
// "endLine": 1,
// "endColumn": 0,
// "executionContextId": 1,
// "hash": "a3b314362f7e47deabee6100e0d8081619194faf1b5741e0fe2f88b150557ddd",
// "executionContextAuxData": { "isDefault": true },
// "isLiveEdit": false,
// "sourceMapURL": "",
// "hasSourceURL": false,
// "isModule": false,
// "length": 21,
// "stackTrace": {
// "callFrames": [
// {
// "functionName": "internalCompileFunction",
// "scriptId": "62",
// "url": "node:internal/vm",
// "lineNumber": 72,
// "columnNumber": 17
// }
// ]
// },
// "scriptLanguage": "JavaScript",
// "embedderName": "file:///private/tmp/empty.js"
// }
if (method == "Debugger.scriptParsed"_s) {
if (auto params = object->getObject("params"_s)) {
params->setInteger("executionContextId"_s, 1);
auto url = makeString("file://"_s, params->getString("url"_s));
params->setString("url"_s, url);
// TODO: content hash
params->setInteger("hash"_s, url.hash());
params->setBoolean("isModule"_s, true);
params->setString("scriptLanguage"_s, "JavaScript"_s);
params->setString("embedderName"_s, "Bun!"_s);
}
((uWS::SSLApp*)app)->ws<SSLBunInspectorConnection*>("/bun:inspect", std::move(handler));
} else {
out = object->toJSONString();
}
auto handler = uWS::App::WebSocketBehavior<BunInspectorConnectionNoSSL*> {
/* Settings */
.compression = uWS::DISABLED,
.maxPayloadLength = 16 * 1024 * 1024,
.idleTimeout = 960,
.maxBackpressure = 16 * 1024 * 1024,
.closeOnBackpressureLimit = false,
.resetIdleTimeoutOnSend = true,
.sendPingsAutomatically = true,
/* Handlers */
.upgrade = nullptr,
.open = [globalObject](auto* ws) {
globalObject->setInspectable(true);
*ws->getUserData() = new BunInspectorConnectionNoSSL(ws, globalObject);
BunInspectorConnectionNoSSL* inspector = *ws->getUserData();
inspector->onOpen(globalObject);
//
},
.message = [](auto* ws, std::string_view message, uWS::OpCode opCode) {
BunInspectorConnectionNoSSL* inspector = *(BunInspectorConnectionNoSSL**)ws->getUserData();
inspector->onMessage(message);
//
},
.drain = [](auto* ws) {
BunInspectorConnectionNoSSL* inspector = *(BunInspectorConnectionNoSSL**)ws->getUserData();
inspector->drain();
//
},
.ping = [](auto* /*ws*/, std::string_view) {
/* Not implemented yet */ },
.pong = [](auto* /*ws*/, std::string_view) {
/* Not implemented yet */ },
if (method == "Debugger.enable"_s) {
// debuggerId is missing from the response
auto params = WTF::JSONImpl::Object::create();
params->setString("debuggerId"_s, "3701622443570787625.-8711178633418819848"_s);
object->setObject("params"_s, WTFMove(params));
}
.close = [](auto* ws, int /*code*/, std::string_view /*message*/) {
BunInspectorConnectionNoSSL* inspector = *(BunInspectorConnectionNoSSL**)ws->getUserData();
inspector->onClose();
delete inspector; }
};
out = object->toJSONString();
}
}
{
LockHolder locker(this->m_pendingMessagesLock);
if (!this->hasSentWelcomeMessage) {
this->hasSentWelcomeMessage = true;
auto welcomeMessage = makeString(
"{ \"method\": \"Runtime.executionContextCreated\", \"params\":{\"context\":{\"id\":"_s,
this->scriptExecutionContext()->identifier(),
",\"origin\":\"\",\"name\":\""_s,
this->identifier(),
"\",\"uniqueId\":\"1234\",\"auxData\":{\"isDefault\":true}}}}"_s);
this->m_pendingMessages.append(WTFMove(welcomeMessage.isolatedCopy()));
}
this->m_pendingMessages.append(WTFMove(out.isolatedCopy()));
}
us_wakeup_loop((us_loop_t*)this->loop);
}
void BunInspector::drainIncomingMessages()
{
LockHolder locker(this->m_incomingMessagesLock);
size_t size = this->m_incomingMessages.size();
while (size > 0) {
auto& message = this->m_incomingMessages.first();
this->sendMessageToTargetBackend(message);
this->m_incomingMessages.removeFirst();
size = this->m_incomingMessages.size();
((uWS::App*)app)->ws<BunInspectorConnectionNoSSL*>("/bun:inspect", std::move(handler));
}
}
void BunInspector::didParseSource(SourceID id, const Debugger::Script& script)
extern "C" void Bun__addInspector(bool isSSL, void* app, JSC::JSGlobalObject* globalObject)
{
}
void BunInspector::drainOutgoingMessages()
{
if (this->server->numSubscribers("BunInspectorConnection") == 0) {
return;
}
LockHolder locker(this->m_pendingMessagesLock);
size_t size = this->m_pendingMessages.size();
while (size > 0) {
auto& message = this->m_pendingMessages.first();
auto utf8 = message.utf8();
std::string_view view { utf8.data(), utf8.length() };
if (!this->server->publish("BunInspectorConnection", view, uWS::OpCode::TEXT, false)) {
return;
}
this->m_pendingMessages.removeFirst();
size = this->m_pendingMessages.size();
if (isSSL) {
addInspector<true>((uWS::TemplatedApp<true>*)app, globalObject);
} else {
addInspector<false>((uWS::TemplatedApp<false>*)app, globalObject);
}
};
}
extern "C" void Bun__tickWhileWaitingForDebugger(JSC::JSGlobalObject* globalObject);
void BunInspector::startServer(WTF::String hostname, uint16_t port, WTF::URL url, WTF::String title)
{
uWS::App* app = new uWS::App();
this->server = app;
this->loop = uWS::Loop::get();
auto host = hostname.utf8();
// https://chromedevtools.github.io/devtools-protocol/ GET /json or /json/list
app->get("/json", [hostname, port, url, title = title, inspector = this](auto* res, auto* /*req*/) {
auto identifier = inspector->identifier();
auto jsonString = makeString(
"[ {\"faviconUrl\": \"https://bun.sh/favicon.svg\", \"description\": \"\", \"devtoolsFrontendUrl\": \"devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws="_s,
hostname,
":"_s,
port,
"/devtools/page/"_s,
identifier,
"\","_s
" \"id\": \"6e99c4f9-6bb6-4f45-9749-5772545b2371\","_s,
" \"title\": \""_s,
title,
"\","
" \"type\": \"node\","_s,
" \"url\": \"file://"_s,
identifier,
"\","_s
" \"webSocketDebuggerUrl\": \"ws://"_s,
hostname,
":"_s,
port,
"/devtools/page/"_s,
identifier,
"\"} ]"_s);
auto utf8 = jsonString.utf8();
res->writeStatus("200 OK");
res->writeHeader("Content-Type", "application/json");
res->end(utf8.data(), utf8.length());
})
.get("/json/version", [](auto* res, auto* req) {
auto out = makeString("{\"Browser\": \"Bun/"_s, Bun__version, "\",\"Protocol-Version\": \"1.1\"}"_s);
auto utf8 = out.utf8();
res->writeStatus("200 OK");
res->writeHeader("Content-Type", "application/json");
res->end({ utf8.data(), utf8.length() });
})
.ws<BunInspectorConnection*>("/*", { /* Settings */
.compression = uWS::DISABLED,
.maxPayloadLength = 1024 * 1024 * 1024,
.idleTimeout = 512,
.maxBackpressure = 64 * 1024 * 1024,
.closeOnBackpressureLimit = false,
.resetIdleTimeoutOnSend = false,
.sendPingsAutomatically = true,
/* Handlers */
.upgrade = nullptr,
.open = [inspector = this](auto* ws) {
BunInspectorConnection** connectionPtr = ws->getUserData();
*connectionPtr = new BunInspectorConnection(inspector);
ws->subscribe("BunInspectorConnection");
BunInspectorConnection* connection = *connectionPtr;
Bun__debuggerIsReady(); },
.message = [inspector = this](auto* ws, std::string_view message, uWS::OpCode opCode) {
if (opCode == uWS::OpCode::TEXT) {
if (!inspector) {
ws->close();
return;
}
BunInspectorConnection** connectionPtr = ws->getUserData();
BunInspectorConnection* connection = *connectionPtr;
connection->inspector->dispatchToBackend(message);
connection->inspector->drainOutgoingMessages();
} },
.drain = [](auto* ws) {
/* Check ws->getBufferedAmount() here */
BunInspectorConnection** connectionPtr = ws->getUserData();
BunInspectorConnection* connection = *connectionPtr;
if (!connection) {
return;
}
while (connection->m_messages.size() > 0) {
auto& message = connection->m_messages.first();
std::string_view view { message.data(), message.length() };
if (!ws->send(view, uWS::OpCode::TEXT, false, false)) {
return;
}
connection->m_messages.removeFirst();
}
connection->inspector->drainOutgoingMessages(); },
.ping = [](auto* /*ws*/, std::string_view) {
/* Not implemented yet */ },
.pong = [](auto* /*ws*/, std::string_view) {
/* Not implemented yet */ },
.close = [](auto* ws, int /*code*/, std::string_view /*message*/) {
BunInspectorConnection** connectionPtr = ws->getUserData();
BunInspectorConnection* connection = *connectionPtr;
if (!connection) {
return;
}
if (connection->inspector.get()) {
connection->inspector->disconnect();
connection->inspector = nullptr;
}
connection->m_messages.clear();
delete connection; } })
.any("/*", [](auto* res, auto* req) {
res->writeStatus("404 Not Found");
res->writeHeader("Content-Type", "text/plain");
res->write(req->getUrl());
res->end(" was not found");
})
.listen(std::string(host.data(), host.length()), port, [inspector = this](auto* listen_socket) {
inspector->loop->addPostHandler(inspector, [inspector = inspector](uWS::Loop* loop) {
inspector->drainOutgoingMessages();
});
WebCore::ScriptExecutionContext::postTaskTo(
inspector->scriptExecutionContext()->identifier(),
[inspector = inspector](WebCore::ScriptExecutionContext& ctx) mutable {
inspector->readyToStartDebugger();
});
inspector->loop->run();
});
}
void BunInspector::readyToStartDebugger()
{
this->ensureDebugger();
auto& inspectorController = globalObject()->inspectorController();
auto* debugger = inspectorController.debugger();
debugger->addObserver(*this);
debugger->schedulePauseAtNextOpportunity();
}
BunInspector* BunInspector::startWebSocketServer(
Zig::GlobalObject* globalObject,
WebCore::ScriptExecutionContext& context,
WTF::String hostname,
uint16_t port,
WTF::Function<void(BunInspector*, bool success)>&& callback)
{
context.ensureURL();
auto url = context.url();
auto identifier = url.fileSystemPath();
auto title = makeString(
url.fileSystemPath(),
" (Bun "_s, Bun__version, ")"_s);
auto* inspector = new BunInspector(&context, nullptr, WTFMove(identifier));
reinterpret_cast<Zig::GlobalObject*>(globalObject)->bunInspectorPtr = inspector;
auto backgroundThreadFunction = [inspector = inspector, hostname = hostname.isolatedCopy(), port = port, url = WTFMove(url), title = WTFMove(title)]() -> void {
inspector->startServer(hostname, port, url, WTFMove(title));
};
WTF::Thread::create("BunInspector", WTFMove(backgroundThreadFunction))->detach();
callback(inspector, true);
Bun__waitForDebuggerToStart();
return inspector;
}
void BunInspector::dispatchToBackend(std::string_view message)
{
WTF::CString data { message.data(), message.length() };
WTF::String msg = WTF::String::fromUTF8(data.data(), data.length());
bool needsTask = true;
{
LockHolder incomingMessagesLock(this->m_incomingMessagesLock);
needsTask = this->m_incomingMessages.isEmpty();
this->m_incomingMessages.append(WTFMove(msg.isolatedCopy()));
}
WebCore::ScriptExecutionContext::postTaskTo(
scriptExecutionContext()->identifier(),
[inspector = this](WebCore::ScriptExecutionContext& ctx) mutable {
inspector->drainIncomingMessages();
});
}
void BunInspector::sendMessageToTargetBackend(const WTF::String& message)
{
globalObject()->inspectorController().dispatchMessageFromFrontend(message);
}
void BunInspector::connect(Inspector::FrontendChannel::ConnectionType connectionType)
{
globalObject()->inspectorController().connectFrontend(*this, false, false);
}
void BunInspector::disconnect()
{
globalObject()->inspectorController().disconnectFrontend(*this);
}
void BunInspector::didPause(JSGlobalObject* jsGlobalObject, DebuggerCallFrame& callframe, JSValue exceptionOrCaughtValue)
{
printf("didPause\n");
}
void BunInspector::didContinue()
{
printf("didContinue\n");
}
void BunInspector::waitForMessages()
{
this->m_incomingMessagesLock.lock();
}
void BunInspector::ensureDebugger()
{
this->connect(Inspector::FrontendChannel::ConnectionType::Local);
auto* debugger = reinterpret_cast<Inspector::JSGlobalObjectDebugger*>(this->globalObject()->inspectorController().debugger());
debugger->runWhilePausedCallback = [](JSC::JSGlobalObject& globalObject, bool& isResumed) {
auto* inspector = inspectorFromGlobal(reinterpret_cast<Zig::GlobalObject*>(&globalObject));
while (!isResumed) {
inspector->drainIncomingMessages();
}
};
}
} // namespace Zig

View File

@@ -1,104 +0,0 @@
#pragma once
#include "root.h"
#include <uws/src/App.h>
#include <JavaScriptCore/InspectorTarget.h>
#include <JavaScriptCore/InspectorFrontendChannel.h>
#include "ContextDestructionObserver.h"
#include <wtf/RefPtr.h>
#include <JavaScriptCore/Debugger.h>
#include <wtf/Deque.h>
#include "JSGlobalObjectInspectorController.h"
namespace Zig {
using namespace JSC;
using namespace WebCore;
class BunInspector final : public RefCounted<BunInspector>, ::Inspector::InspectorTarget, ::Inspector::FrontendChannel, public WebCore::ContextDestructionObserver, JSC::Debugger::Observer {
public:
WTF_MAKE_ISO_ALLOCATED(BunInspector);
BunInspector(ScriptExecutionContext* context, uWS::App* server, WTF::String&& identifier)
: server(server)
, WebCore::ContextDestructionObserver(context)
, m_identifier(WTFMove(identifier))
{
}
public:
~BunInspector()
{
server->close();
}
bool isProvisional() const override { return false; }
String identifier() const override { return m_identifier; }
Inspector::InspectorTargetType type() const override { return Inspector::InspectorTargetType::DedicatedWorker; }
GlobalObject* globalObject() { return static_cast<GlobalObject*>(scriptExecutionContext()->jsGlobalObject()); }
void startServer(WTF::String hostname, uint16_t port, WTF::URL url, WTF::String title);
Lock m_mutex;
void ensureDebugger();
JSC::Debugger* debugger() { return globalObject()->inspectorController().debugger(); }
void didPause(JSGlobalObject*, DebuggerCallFrame&, JSValue /* exceptionOrCaughtValue */) override;
void didContinue() override;
void didParseSource(SourceID, const Debugger::Script&) override;
void failedToParseSource(const String& /* url */, const String& /* data */, int /* firstLine */, int /* errorLine */, const String& /* errorMessage */) override {}
void didCreateNativeExecutable(NativeExecutable&) override {}
void willCallNativeExecutable(CallFrame*) override {}
void willEnter(CallFrame*) override {}
void didQueueMicrotask(JSGlobalObject*, MicrotaskIdentifier) override {}
void willRunMicrotask(JSGlobalObject*, MicrotaskIdentifier) override {}
void didRunMicrotask(JSGlobalObject*, MicrotaskIdentifier) override {}
void applyBreakpoints(CodeBlock*) override {}
void breakpointActionLog(JSGlobalObject*, const String& /* data */) override {}
void breakpointActionSound(BreakpointActionID) override {}
void breakpointActionProbe(JSGlobalObject*, BreakpointActionID, unsigned /* batchId */, unsigned /* sampleId */, JSValue /* result */) override {}
void didDeferBreakpointPause(BreakpointID) override {}
static BunInspector* startWebSocketServer(
Zig::GlobalObject* globalObject,
WebCore::ScriptExecutionContext& ctx,
WTF::String hostname,
uint16_t port,
WTF::Function<void(BunInspector*, bool success)>&& callback);
// Connection management.
void connect(Inspector::FrontendChannel::ConnectionType) override;
void disconnect() override;
void sendMessageToTargetBackend(const String&) override;
bool hasConnectedFrontends() { return connectionCounter > 0; }
void sendMessageToFrontend(const String& message) override;
Inspector::FrontendChannel::ConnectionType connectionType() const override { return Inspector::FrontendChannel::ConnectionType::Remote; }
int connectionCounter = 0;
bool hasSentWelcomeMessage = false;
void drainOutgoingMessages();
void drainIncomingMessages();
void waitForMessages();
void readyToStartDebugger();
private:
void dispatchToBackend(std::string_view message);
WTF::String m_identifier;
WTF::Lock m_pendingMessagesLock;
uWS::App* server;
uWS::Loop* loop;
Deque<WTF::String> m_pendingMessages;
Deque<WTF::String> m_incomingMessages;
WTF::Lock m_incomingMessagesLock;
};
}

View File

@@ -34,8 +34,6 @@
using namespace JSC;
using namespace WTF;
extern "C" bool JSGlobalObject__startRemoteInspector(JSC::JSGlobalObject* globalObject, const char* host, uint16_t port);
JSC_DECLARE_HOST_FUNCTION(functionStartRemoteDebugger);
JSC_DEFINE_HOST_FUNCTION(functionStartRemoteDebugger, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
@@ -47,13 +45,38 @@ JSC_DEFINE_HOST_FUNCTION(functionStartRemoteDebugger, (JSGlobalObject * globalOb
JSC::JSValue hostValue = callFrame->argument(0);
JSC::JSValue portValue = callFrame->argument(1);
const char* host = defaultHost;
if (hostValue.isString()) {
bool res = JSGlobalObject__startRemoteInspector(
globalObject,
hostValue.isUndefinedOrNull() ? defaultHost : hostValue.toWTFString(globalObject).utf8().data(),
portValue.isUndefinedOrNull() ? defaultPort : portValue.toUInt32(globalObject));
auto str = hostValue.toWTFString(globalObject);
if (!str.isEmpty())
host = toCString(str).data();
} else if (!hostValue.isUndefined()) {
throwVMError(globalObject, scope, createTypeError(globalObject, "host must be a string"_s));
return JSC::JSValue::encode(JSC::jsUndefined());
}
RELEASE_AND_RETURN(scope, JSC::JSValue::encode(jsBoolean(res)));
uint16_t port = defaultPort;
if (portValue.isNumber()) {
auto port_int = portValue.toUInt32(globalObject);
if (!(port_int > 0 && port_int < 65536)) {
throwVMError(globalObject, scope, createRangeError(globalObject, "port must be between 0 and 65535"_s));
return JSC::JSValue::encode(JSC::jsUndefined());
}
port = port_int;
} else if (!portValue.isUndefined()) {
throwVMError(globalObject, scope, createTypeError(globalObject, "port must be a number between 0 and 65535"_s));
return JSC::JSValue::encode(JSC::jsUndefined());
}
globalObject->setInspectable(true);
auto& server = Inspector::RemoteInspectorServer::singleton();
if (!server.start(reinterpret_cast<const char*>(host), port)) {
throwVMError(globalObject, scope, createError(globalObject, "Failed to start server \""_s + host + ":"_s + port + "\". Is port already in use?"_s));
return JSC::JSValue::encode(JSC::jsUndefined());
}
RELEASE_AND_RETURN(scope, JSC::JSValue::encode(JSC::jsUndefined()));
#else
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);

View File

@@ -49,7 +49,7 @@ static EncodedJSValue jsFunctionAppendOnLoadPluginBody(JSC::JSGlobalObject* glob
auto clientData = WebCore::clientData(vm);
auto& builtinNames = clientData->builtinNames();
JSC::RegExpObject* filter = nullptr;
if (JSValue filterValue = filterObject->getIfPropertyExists(globalObject, builtinNames.filterPublicName())) {
if (JSValue filterValue = filterObject->getIfPropertyExists(globalObject, Identifier::fromString(vm, "filter"_s))) {
if (filterValue.isCell() && filterValue.asCell()->inherits<JSC::RegExpObject>())
filter = jsCast<JSC::RegExpObject*>(filterValue);
}
@@ -101,7 +101,7 @@ static EncodedJSValue jsFunctionAppendOnResolvePluginBody(JSC::JSGlobalObject* g
auto clientData = WebCore::clientData(vm);
auto& builtinNames = clientData->builtinNames();
JSC::RegExpObject* filter = nullptr;
if (JSValue filterValue = filterObject->getIfPropertyExists(globalObject, builtinNames.filterPublicName())) {
if (JSValue filterValue = filterObject->getIfPropertyExists(globalObject, Identifier::fromString(vm, "filter"_s))) {
if (filterValue.isCell() && filterValue.asCell()->inherits<JSC::RegExpObject>())
filter = jsCast<JSC::RegExpObject*>(filterValue);
}
@@ -366,15 +366,15 @@ JSFunction* BunPlugin::Group::find(JSC::JSGlobalObject* globalObject, String& pa
return nullptr;
}
EncodedJSValue BunPlugin::OnLoad::run(JSC::JSGlobalObject* globalObject, ZigString* namespaceString, ZigString* path)
EncodedJSValue BunPlugin::OnLoad::run(JSC::JSGlobalObject* globalObject, BunString* namespaceString, BunString* path)
{
Group* groupPtr = this->group(namespaceString ? Zig::toString(*namespaceString) : String());
Group* groupPtr = this->group(namespaceString ? Bun::toWTFString(*namespaceString) : String());
if (groupPtr == nullptr) {
return JSValue::encode(jsUndefined());
}
Group& group = *groupPtr;
auto pathString = Zig::toString(*path);
auto pathString = Bun::toWTFString(*path);
JSC::JSFunction* function = group.find(globalObject, pathString);
if (!function) {
@@ -428,9 +428,9 @@ EncodedJSValue BunPlugin::OnLoad::run(JSC::JSGlobalObject* globalObject, ZigStri
RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
}
EncodedJSValue BunPlugin::OnResolve::run(JSC::JSGlobalObject* globalObject, ZigString* namespaceString, ZigString* path, ZigString* importer)
EncodedJSValue BunPlugin::OnResolve::run(JSC::JSGlobalObject* globalObject, BunString* namespaceString, BunString* path, BunString* importer)
{
Group* groupPtr = this->group(namespaceString ? Zig::toString(*namespaceString) : String());
Group* groupPtr = this->group(namespaceString ? Bun::toWTFString(*namespaceString) : String());
if (groupPtr == nullptr) {
return JSValue::encode(jsUndefined());
}
@@ -443,7 +443,7 @@ EncodedJSValue BunPlugin::OnResolve::run(JSC::JSGlobalObject* globalObject, ZigS
auto& callbacks = group.callbacks;
WTF::String pathString = Zig::toString(*path);
WTF::String pathString = Bun::toWTFString(*path);
for (size_t i = 0; i < filters.size(); i++) {
if (!filters[i].get()->match(globalObject, pathString, 0)) {
continue;
@@ -461,10 +461,10 @@ EncodedJSValue BunPlugin::OnResolve::run(JSC::JSGlobalObject* globalObject, ZigS
auto& builtinNames = clientData->builtinNames();
paramsObject->putDirect(
vm, clientData->builtinNames().pathPublicName(),
Zig::toJSStringValue(*path, globalObject));
Bun::toJS(globalObject, *path));
paramsObject->putDirect(
vm, clientData->builtinNames().importerPublicName(),
Zig::toJSStringValue(*importer, globalObject));
Bun::toJS(globalObject, *importer));
arguments.append(paramsObject);
auto throwScope = DECLARE_THROW_SCOPE(vm);
@@ -515,12 +515,12 @@ EncodedJSValue BunPlugin::OnResolve::run(JSC::JSGlobalObject* globalObject, ZigS
} // namespace Zig
extern "C" JSC::EncodedJSValue Bun__runOnResolvePlugins(Zig::GlobalObject* globalObject, ZigString* namespaceString, ZigString* path, ZigString* from, BunPluginTarget target)
extern "C" JSC::EncodedJSValue Bun__runOnResolvePlugins(Zig::GlobalObject* globalObject, BunString* namespaceString, BunString* path, BunString* from, BunPluginTarget target)
{
return globalObject->onResolvePlugins[target].run(globalObject, namespaceString, path, from);
}
extern "C" JSC::EncodedJSValue Bun__runOnLoadPlugins(Zig::GlobalObject* globalObject, ZigString* namespaceString, ZigString* path, BunPluginTarget target)
extern "C" JSC::EncodedJSValue Bun__runOnLoadPlugins(Zig::GlobalObject* globalObject, BunString* namespaceString, BunString* path, BunPluginTarget target)
{
return globalObject->onLoadPlugins[target].run(globalObject, namespaceString, path);
}

View File

@@ -67,7 +67,7 @@ public:
{
}
EncodedJSValue run(JSC::JSGlobalObject* globalObject, ZigString* namespaceString, ZigString* path);
EncodedJSValue run(JSC::JSGlobalObject* globalObject, BunString* namespaceString, BunString* path);
};
class OnResolve final : public Base {
@@ -78,7 +78,7 @@ public:
{
}
EncodedJSValue run(JSC::JSGlobalObject* globalObject, ZigString* namespaceString, ZigString* path, ZigString* importer);
EncodedJSValue run(JSC::JSGlobalObject* globalObject, BunString* namespaceString, BunString* path, BunString* importer);
};
};

View File

@@ -0,0 +1,224 @@
#include "root.h"
#include "headers-handwritten.h"
#include "JavaScriptCore/JSCJSValueInlines.h"
#include "helpers.h"
#include "simdutf.h"
#include "wtf/text/ExternalStringImpl.h"
#include "GCDefferalContext.h"
using namespace JSC;
extern "C" bool Bun__WTFStringImpl__hasPrefix(const WTF::StringImpl* impl, const char* bytes, size_t length)
{
return impl->startsWith(bytes, length);
}
extern "C" void Bun__WTFStringImpl__deref(WTF::StringImpl* impl)
{
impl->deref();
}
extern "C" void Bun__WTFStringImpl__ref(WTF::StringImpl* impl)
{
impl->ref();
}
extern "C" bool BunString__fromJS(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue encodedValue, BunString* bunString)
{
JSC::JSValue value = JSC::JSValue::decode(encodedValue);
*bunString = Bun::toString(globalObject, value);
return bunString->tag != BunStringTag::Dead;
}
namespace Bun {
JSC::JSValue toJS(JSC::JSGlobalObject* globalObject, BunString bunString)
{
if (bunString.tag == BunStringTag::Empty || bunString.tag == BunStringTag::Dead) {
return JSValue(JSC::jsEmptyString(globalObject->vm()));
}
if (bunString.tag == BunStringTag::WTFStringImpl) {
return JSValue(jsString(globalObject->vm(), String(bunString.impl.wtf)));
}
if (bunString.tag == BunStringTag::StaticZigString) {
return JSValue(jsString(globalObject->vm(), Zig::toStringStatic(bunString.impl.zig)));
}
return JSValue(Zig::toJSStringGC(bunString.impl.zig, globalObject));
}
WTF::String toWTFString(const BunString& bunString)
{
if (bunString.tag == BunStringTag::ZigString) {
if (Zig::isTaggedUTF8Ptr(bunString.impl.zig.ptr)) {
return Zig::toStringCopy(bunString.impl.zig);
} else {
return Zig::toString(bunString.impl.zig);
}
} else if (bunString.tag == BunStringTag::StaticZigString) {
return Zig::toStringStatic(bunString.impl.zig);
}
if (bunString.tag == BunStringTag::WTFStringImpl) {
return WTF::String(bunString.impl.wtf);
}
return WTF::String();
}
BunString fromJS(JSC::JSGlobalObject* globalObject, JSValue value)
{
JSC::JSString* str = value.toStringOrNull(globalObject);
if (UNLIKELY(!str)) {
return { BunStringTag::Dead };
}
if (str->length() == 0) {
return { BunStringTag::Empty };
}
auto wtfString = str->value(globalObject);
return { BunStringTag::WTFStringImpl, { .wtf = wtfString.impl() } };
}
BunString toString(JSC::JSGlobalObject* globalObject, JSValue value)
{
return fromJS(globalObject, value);
}
BunString toString(WTF::String& wtfString)
{
if (wtfString.length() == 0)
return { BunStringTag::Empty };
return { BunStringTag::WTFStringImpl, { .wtf = wtfString.impl() } };
}
BunString toString(const WTF::String& wtfString)
{
if (wtfString.length() == 0)
return { BunStringTag::Empty };
return { BunStringTag::WTFStringImpl, { .wtf = wtfString.impl() } };
}
BunString toString(WTF::StringImpl* wtfString)
{
if (wtfString->length() == 0)
return { BunStringTag::Empty };
return { BunStringTag::WTFStringImpl, { .wtf = wtfString } };
}
BunString fromString(WTF::String& wtfString)
{
if (wtfString.length() == 0)
return { BunStringTag::Empty };
return { BunStringTag::WTFStringImpl, { .wtf = wtfString.impl() } };
}
BunString fromString(WTF::StringImpl* wtfString)
{
if (wtfString->length() == 0)
return { BunStringTag::Empty };
return { BunStringTag::WTFStringImpl, { .wtf = wtfString } };
}
}
extern "C" JSC::EncodedJSValue BunString__toJS(JSC::JSGlobalObject* globalObject, BunString* bunString)
{
return JSValue::encode(Bun::toJS(globalObject, *bunString));
}
extern "C" BunString BunString__fromUTF8(const char* bytes, size_t length)
{
if (simdutf::validate_utf8(bytes, length)) {
size_t u16Length = simdutf::utf16_length_from_utf8(bytes, length);
UChar* ptr;
auto impl = WTF::StringImpl::createUninitialized(static_cast<unsigned int>(u16Length), ptr);
RELEASE_ASSERT(simdutf::convert_utf8_to_utf16(bytes, length, ptr) == u16Length);
impl->ref();
return { BunStringTag::WTFStringImpl, { .wtf = &impl.leakRef() } };
}
auto str = WTF::String::fromUTF8ReplacingInvalidSequences(reinterpret_cast<const LChar*>(bytes), length);
str.impl()->ref();
return Bun::fromString(str);
}
extern "C" BunString BunString__fromLatin1(const char* bytes, size_t length)
{
return { BunStringTag::WTFStringImpl, { .wtf = &WTF::StringImpl::create(bytes, length).leakRef() } };
}
extern "C" BunString BunString__fromBytes(const char* bytes, size_t length)
{
if (simdutf::validate_ascii(bytes, length)) {
return BunString__fromLatin1(bytes, length);
}
return BunString__fromUTF8(bytes, length);
}
extern "C" BunString BunString__createExternal(const char* bytes, size_t length, bool isLatin1, void* ctx, void (*callback)(void* arg0, void* arg1, size_t arg2))
{
Ref<WTF::ExternalStringImpl> impl = isLatin1 ? WTF::ExternalStringImpl::create(reinterpret_cast<const LChar*>(bytes), length, ctx, callback) :
WTF::ExternalStringImpl::create(reinterpret_cast<const UChar*>(bytes), length, ctx, callback);
return { BunStringTag::WTFStringImpl, { .wtf = &impl.leakRef() } };
}
extern "C" EncodedJSValue BunString__createArray(
JSC::JSGlobalObject* globalObject,
const BunString* ptr, size_t length)
{
if (length == 0)
return JSValue::encode(JSC::constructEmptyArray(globalObject, nullptr));
auto& vm = globalObject->vm();
auto throwScope = DECLARE_THROW_SCOPE(vm);
// We must do this or Bun.gc(true) in a loop creating large arrays of strings will crash due to GC'ing.
MarkedArgumentBuffer arguments;
JSC::ObjectInitializationScope scope(vm);
GCDeferralContext context(vm);
arguments.fill(length, [&](JSC::JSValue* value) {
const BunString* end = ptr + length;
while (ptr != end) {
*value++ = Bun::toJS(globalObject, *ptr++);
}
});
if (JSC::JSArray* array = JSC::JSArray::tryCreateUninitializedRestricted(
scope,
globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
length)) {
for (size_t i = 0; i < length; ++i) {
array->initializeIndex(scope, i, arguments.at(i));
}
return JSValue::encode(array);
}
JSC::throwOutOfMemoryError(globalObject, throwScope);
RELEASE_AND_RETURN(throwScope, JSValue::encode(JSC::JSValue()));
}
extern "C" void BunString__toWTFString(BunString* bunString)
{
if (bunString->tag == BunStringTag::ZigString) {
if (Zig::isTaggedUTF8Ptr(bunString->impl.zig.ptr)) {
bunString->impl.wtf = Zig::toStringCopy(bunString->impl.zig).impl();
} else {
bunString->impl.wtf = Zig::toString(bunString->impl.zig).impl();
}
bunString->tag = BunStringTag::WTFStringImpl;
} else if (bunString->tag == BunStringTag::StaticZigString) {
bunString->impl.wtf = Zig::toStringStatic(bunString->impl.zig).impl();
bunString->tag = BunStringTag::WTFStringImpl;
}
}

View File

@@ -86,6 +86,42 @@ void CallSite::visitChildrenImpl(JSCell* cell, Visitor& visitor)
visitor.append(thisCallSite->m_sourceURL);
}
void CallSite::formatAsString(JSC::VM& vm, JSC::JSGlobalObject* globalObject, WTF::StringBuilder &sb) {
JSString* myTypeName = jsTypeStringForValue(globalObject, thisValue());
JSString* myFunction = functionName().toString(globalObject);
JSString* myFunctionName = functionName().toString(globalObject);
JSString* mySourceURL = sourceURL().toString(globalObject);
JSString* myColumnNumber = columnNumber().toInt32(globalObject) != -1 ? columnNumber().toString(globalObject) : jsEmptyString(vm);
JSString* myLineNumber = lineNumber().toInt32(globalObject) != -1 ? lineNumber().toString(globalObject) : jsEmptyString(vm);
bool myIsConstructor = isConstructor();
if (myFunctionName->length() > 0) {
if (myIsConstructor) {
sb.append("new "_s);
} else {
// TODO: print type or class name if available
// sb.append(myTypeName->getString(globalObject));
// sb.append(" "_s);
}
sb.append(myFunctionName->getString(globalObject));
} else {
sb.append("<anonymous>"_s);
}
sb.append(" ("_s);
if (isNative()) {
sb.append("native"_s);
} else {
sb.append(mySourceURL->getString(globalObject));
sb.append(":"_s);
sb.append(myLineNumber->getString(globalObject));
sb.append(":"_s);
sb.append(myColumnNumber->getString(globalObject));
}
sb.append(")"_s);
}
DEFINE_VISIT_CHILDREN(CallSite);
}

View File

@@ -77,6 +77,11 @@ public:
bool isStrict() const { return m_flags & static_cast<unsigned int>(Flags::IsStrict); }
bool isNative() const { return m_flags & static_cast<unsigned int>(Flags::IsNative); }
void setLineNumber(JSC::JSValue lineNumber) { m_lineNumber = lineNumber; }
void setColumnNumber(JSC::JSValue columnNumber) { m_columnNumber = columnNumber; }
void formatAsString(JSC::VM& vm, JSC::JSGlobalObject* globalObject, WTF::StringBuilder &sb);
private:
CallSite(JSC::VM& vm, JSC::Structure* structure)
: Base(vm, structure)

Some files were not shown because too many files have changed in this diff Show More