change the directory structure

This commit is contained in:
Jarred Sumner
2022-06-22 23:21:48 -07:00
parent 25f820c6bf
commit 729d445b68
919 changed files with 1958 additions and 1727 deletions

138
test/README.md Normal file
View File

@@ -0,0 +1,138 @@
# Tests in Bun
Bun currently has four different kinds of tests
To run the tests:
```bash
make test-all
bun wiptest
```
### Browser tests
Browser tests run end-to-end inside of Puppeteer and execute code transpiled by `bun dev`. These tests are in [./snippets](./snippets).
The interface is:
```js
// this function is called after import()
// if testDone() is never called, the test fails
export function test() {
return testDone(import.meta.url);
}
```
On success, it saves a snapshot to [./snapshots](./snapshots) which is checked into git.
#### Adding a new test
1. Create a new file in the `snippets` directory.
2. Append the filename to [./scripts/snippets.json](./scripts/snippets.json)
3. Run `bun dev` inside this folder in one terminal window
4. Run `make integration-test-dev`
These tests are run twice. Once with HMR enabled and once with HMR disabled. HMR changes the output enough to warrant it's own special treatment.
#### Running the tests
To run the browser tests with HMR on a production build:
```bash
make test-with-hmr
```
To run the browser tests without HMR on a production build:
```bash
make test-with-no-hmr
```
To run the browser tests with HMR on a debug build:
```bash
make test-dev-with-hmr
```
To run the browser tests without HMR on a debug build:
```bash
make test-dev-no-hmr
```
To run the browser tests on whatever version of bun is running on port 3000:
```bash
make integration-test-dev
```
These were the first tests bun started with
### Runtime tests
These tests are in [./bun.js](./bun.js) and are files which are either `.test.js` or `.test.ts` files.
These test that the runtime behaves as expected. These also test the transpiler, both because test files are transpiled and directly by running the transpiler via `Bun.Transpiler`.
#### Adding a new test
1. Create a new file in [./bun.js](./bun.js/) with `.test` in the name.
These test use `bun:test` as the import (though you can also import from `vitest` or jest and it will work).
This will eventually be a public test runner for bun, but the reporter isn't very good yet and it doesn't run in parallel.
The syntax intends for Jest compatibility.
```ts
import { describe, expect, it } from "bun:test";
describe("Example", () => {
it("should work", () => {
expect(1).toBe(1);
});
});
```
#### Running the tests
Run `bun wiptest ${part-of-file-name}`
If you run the test in the top-level bun repo directory, it will take an extra couple seconds because `bun wiptest` will scan through all of WebKit recursively. Consider running it in the `bun.js` directory instead.
### CLI tests
These run the bash files in the `apps` directory.
They check end-to-end that the CLI works as expected.
```bash
# Install dependencies for running tests
# Does not run tests
make test-install
# Check a Create React App created via `bun create react ./foo` returns HTML
make test-create-react
# Check a Next.js app created via `bun create next ./foo` SSRs successfully
make test-create-next
# Check that bun run works for the same CLI args passed to npm run
make test-bun-run
# Check that "react" installed via bun install loads successfully
# and that deleting/adding updates the lockfile as expected
make test-bun-install
# Check that serving public paths works correctly
# and that files which should be transpiled are transpiled and files which shouldn't be aren't
make test-bun-dev
```
### Zig tests
These tests live in various `.zig` files throughout Bun's codebase, leveraging Zig's builtin `test` keyword.
Currently, they're not run automatically nor is there a simple way to run all of them.
This is an area bun needs to improve in.

View File

@@ -0,0 +1,57 @@
#!/bin/bash
set -euo pipefail
# The important part of this test: make sure that bun.js successfully loads
# The most likely reason for this test to fail is that something broke in the JavaScriptCore <> bun integration
killall -9 $(basename $BUN_BIN) || echo ""
rm -rf /tmp/next-app
mkdir -p /tmp/next-app
$BUN_BIN create next /tmp/next-app
if (($?)); then
echo "bun create failed"
exit 1
fi
echo "hi!" >/tmp/next-app/public/file.txt
echo "export default 'string';" >/tmp/next-app/file.js
cd /tmp/next-app
BUN_CRASH_WITHOUT_JIT=1 $BUN_BIN dev --port 8087 &
sleep 0.1
curl --fail -Ss http://localhost:8087/
if [[ "$(curl --fail -sS http://localhost:8087/file.txt)" != "hi!" ]]; then
echo ""
echo ""
echo ""
echo "ERR: Expected 'hi!', got '$(curl --fail -sS http://localhost:8087/file.txt)'"
killall -9 $(basename $BUN_BIN) || echo ""
exit 1
fi
if [[ "$(curl --fail -sS http://localhost:8087/file.js)" != *"string"* ]]; then
echo ""
echo ""
echo ""
echo "ERR: Expected file to contain string got '$(curl --fail -sS http://localhost:8087/file.js)'"
killall -9 $(basename $BUN_BIN) || echo ""
exit 1
fi
# very simple HMR test
echo "export default 'string';" >/tmp/next-app/file2.js
sleep 0.1
if [[ "$(curl --fail -sS http://localhost:8087/file2.js)" != *"string"* ]]; then
echo ""
echo ""
echo ""
echo "ERR: Expected file to contain string got '$(curl --fail -sS http://localhost:8087/file2.js)'"
killall -9 $(basename $BUN_BIN) || echo ""
exit 1
fi
killall -9 $(basename $BUN_BIN) || echo ""

View File

@@ -0,0 +1,20 @@
#!/bin/bash
killall -9 $(basename $BUN_BIN) || echo ""
rm -rf /tmp/react-app
mkdir -p /tmp/react-app
$BUN_BIN create react /tmp/react-app
if (($?)); then
echo "bun create failed"
exit 1
fi
cd /tmp/react-app
BUN_CRASH_WITHOUT_JIT=1 $BUN_BIN --port 8087 &
sleep 0.005
curl --fail http://localhost:8087/ && curl --fail http://localhost:8087/src/index.jsx && killall -9 $(basename $BUN_BIN) && echo "✅ bun create react passed."
exit $?

View File

@@ -0,0 +1,69 @@
#!/bin/bash
set -euo pipefail
killall -9 $(basename $BUN_BIN) || echo ""
dir=$(mktemp -d --suffix=bun-dev-check)
index_content="<html><body>index.html</body></html>"
bacon_content="<html><body>bacon.html</body></html>"
js_content="if(0) { var foo = 'TEST FAILED'; }"
static_content="PASS"
css_not_transpiled_content="@import url(/index.js); @import url(/i-dont-exist.css); @import url('/i-dont-exist.css'); @import url(\"/i-dont-exist.css\");"
css_is_transpiled_import="*{background-color:red;}"
css_is_transpiled="@import url(./css_is_transpiled_import.css);"
echo $index_content >"$dir/index.html"
echo $js_content >"$dir/index.js"
echo $bacon_content >"$dir/bacon.html"
echo $static_content >"$dir/static.txt"
echo $css_not_transpiled_content >"$dir/css_not_transpiled_content.css"
cd $dir
$BUN_BIN --port 8087 &
sleep 0.005
if [[ "$(curl --fail -sS http://localhost:8087/)" != "$index_content" ]]; then
echo "ERR: Expected '$index_content', got '$(curl --fail -sS http://localhost:8087/)'"
exit 1
fi
if [[ "$(curl --fail -sS http://localhost:8087/index)" != "$index_content" ]]; then
echo "ERR: Expected '$index_content', got '$(curl --fail -sS http://localhost:8087/index)'"
exit 1
fi
if [[ "$(curl --fail -sS http://localhost:8087/static.txt)" != "PASS" ]]; then
echo "ERR: Expected static file, got '$(curl --fail -sS http://localhost:8087/static.txt)'"
exit 1
fi
# Check that the file is actually transpiled
if [[ "$(curl --fail -sS http://localhost:8087/index.js)" == *"TEST FAILED"* ]]; then
echo "ERR: Expected file to be transpiled, got '$(curl --fail -sS http://localhost:8087/index.js)'"
exit 1
fi
if [[ "$(curl --fail -sS http://localhost:8087/index.html)" != "$index_content" ]]; then
echo "ERR: Expected '$index_content', got '$(curl --fail -sS http://localhost:8087/index.html)'"
exit 1
fi
if [[ "$(curl --fail -sS http://localhost:8087/foo/foo)" != "$index_content" ]]; then
echo "ERR: Expected '$index_content', got '$(curl --fail -sS http://localhost:8087/index.html)'"
exit 1
fi
if [[ "$(curl --fail -sS http://localhost:8087/bacon)" != "$bacon_content" ]]; then
echo "ERR: Expected '$bacon_content', got '$(curl --fail -sS http://localhost:8087/bacon)'"
exit 1
fi
if [[ "$(curl --fail -sS http://localhost:8087/bacon.html)" != "$bacon_content" ]]; then
echo "ERR: Expected '$bacon_content', got '$(curl --fail -sS http://localhost:8087/bacon.html)'"
exit 1
fi
killall -9 $(basename $BUN_BIN) || echo ""
echo "✅ bun dev index html check passed."

55
test/apps/bun-dev.sh Normal file
View File

@@ -0,0 +1,55 @@
#!/bin/bash
set -euo pipefail
killall -9 $(basename $BUN_BIN) || echo ""
dir=$(mktemp -d --suffix=bun-dev-check)
index_content="<html><body>index.html</body></html>"
bacon_content="<html><body>bacon.html</body></html>"
js_content="console.log('hi')"
mkdir -p $dir/public
echo $index_content >"$dir/public/index.html"
echo $js_content >"$dir/index.js"
echo $bacon_content >"$dir/public/bacon.html"
cd $dir
$BUN_BIN --port 8087 &
sleep 0.005
if [ "$(curl --fail -sS http://localhost:8087/)" != "$index_content" ]; then
echo "ERR: Expected '$index_content', got '$(curl --fail -sS http://localhost:8087/)'"
exit 1
fi
if [ "$(curl --fail -sS http://localhost:8087/index)" != "$index_content" ]; then
echo "ERR: Expected '$index_content', got '$(curl --fail -sS http://localhost:8087/index)'"
exit 1
fi
if [ "$(curl --fail -sS http://localhost:8087/index.html)" != "$index_content" ]; then
echo "ERR: Expected '$index_content', got '$(curl --fail -sS http://localhost:8087/index.html)'"
exit 1
fi
if [ "$(curl --fail -sS http://localhost:8087/foo/foo)" != "$index_content" ]; then
echo "ERR: Expected '$index_content', got '$(curl --fail -sS http://localhost:8087/index.html)'"
exit 1
fi
if [ "$(curl --fail -sS http://localhost:8087/bacon)" != "$bacon_content" ]; then
echo "ERR: Expected '$index_content', got '$(curl --fail -sS http://localhost:8087/bacon)'"
exit 1
fi
if [ "$(curl --fail -sS http://localhost:8087/bacon.html)" != "$bacon_content" ]; then
echo "ERR: Expected '$index_content', got '$(curl --fail -sS http://localhost:8087/bacon.html)'"
exit 1
fi
killall -9 $(basename $BUN_BIN) || echo ""
echo "✅ bun dev index html check passed."

View File

@@ -0,0 +1,65 @@
#!/bin/bash
set -euo pipefail
killall -9 $(basename $BUN_BIN) || echo ""
dir=$(mktemp -d --suffix=bun-lockfile)
cd $dir
$BUN_BIN add react
echo "node_modules" >.gitignore
git init && git add . && git commit -am "Initial commit"
$BUN_BIN install
ORIG_LOCKFILE="$($BUN_BIN pm hash-string)"
[[ -z $(git status --untracked-files=no --porcelain) ]] || {
echo "ERR: Expected empty git status, got '$(git status --untracked-files=no --porcelain)'"
exit 1
}
$BUN_BIN add react
NEW_LOCKFILE="$($BUN_BIN pm hash-string)"
diff <(echo "$ORIG_LOCKFILE") <(echo "$NEW_LOCKFILE") || {
echo "ERR: Expected lockfile to be unchanged, got '$NEW_LOCKFILE'"
exit 1
}
ORIG_HASH=$($BUN_BIN bun.lockb --hash)
$BUN_BIN remove react
$BUN_BIN add react
NEW_HASH=$($BUN_BIN bun.lockb --hash)
diff <(echo "$ORIG_HASH") <(echo "$NEW_HASH") || {
echo "ERR: Expected hash to be unchanged, got '$NEW_HASH'"
exit 1
}
echo '{ "dependencies": { "react": "17.0.2", "react-dom": "17.0.2" } }' >package.json
$BUN_BIN install
echo "var {version} = JSON.parse(require(\"fs\").readFileSync('./node_modules/react-dom/package.json', 'utf8')); if (version !== '17.0.2') {throw new Error('Unexpected react-dom version');}; " >index.js
$BUN_BIN run ./index.js
echo "var {version} = JSON.parse(require(\"fs\").readFileSync('./node_modules/react/package.json', 'utf8')); if (version !== '17.0.2') {throw new Error('Unexpected react version');}; " >index.js
$BUN_BIN run ./index.js
# This is just making sure that the JS was executed
realpath -e node_modules/react-dom >/dev/null || {
echo "ERR: Expected react-dom to be installed"
exit 1
}
realpath -e node_modules/react >/dev/null || {
echo "ERR: Expected react to be installed"
exit 1
}

View File

@@ -0,0 +1,14 @@
#!/bin/bash
set -euo pipefail
killall -9 $(basename $BUN_BIN) || echo ""
dir=$(mktemp -d --suffix=bun-ADD)
cd $dir
# https://github.com/Jarred-Sumner/bun/issues/115
echo '{ "author": "Arnaud Barré (https://github.com/ArnaudBarre)" }' >package.json
$BUN_BIN add react

85
test/apps/bun-install.sh Normal file
View File

@@ -0,0 +1,85 @@
#!/bin/bash
set -euo pipefail
dir=$(mktemp -d --suffix=bun-install-test-1)
cd $dir
${NPM_CLIENT:-$(which bun)} add react react-dom @types/react @babel/parser esbuild
echo "console.log(typeof require(\"react\").createElement);" >index.js
chmod +x index.js
JS_RUNTIME=${JS_RUNTIME:-"$(which bun)"}
if [ "$JS_RUNTIME" == "node" ]; then
result="$(node ./index.js)"
fi
if [ "$JS_RUNTIME" != "node" ]; then
result="$($JS_RUNTIME run ./index.js)"
fi
echo "console.log(typeof require(\"react-dom\").render);" >index.js
chmod +x index.js
JS_RUNTIME=${JS_RUNTIME:-"$(which bun)"}
# If this fails to run, it means we didn't link @babel/parser correctly
realpath -e ./node_modules/.bin/parser
# If this fails to run, it means we didn't link esbuild correctly
./node_modules/.bin/esbuild --version >/dev/null
if [ "$JS_RUNTIME" == "node" ]; then
result="$(node ./index.js)"
fi
if [ "$JS_RUNTIME" != "node" ]; then
result="$($JS_RUNTIME run ./index.js)"
fi
if [ "$result" != "function" ]; then
echo "ERR: Expected 'function', got '$result'"
exit 1
fi
${NPM_CLIENT:-$(which bun)} remove react-dom
if [ -d "node_modules/react-dom" ]; then
echo "ERR: react-dom module still exists in $dir"
exit 1
fi
yarn_dot_lock=$(${NPM_CLIENT:-$(which bun)} bun.lockb)
if echo "$yarn_dot_lock" | grep -q "react-dom"; then
echo "ERR: react-dom module still exists in lockfile"
exit 1
fi
${NPM_CLIENT:-$(which bun)} remove @types/react
yarn_dot_lock=$(${NPM_CLIENT:-$(which bun)} bun.lockb)
if echo "$yarn_dot_lock" | grep -q "@types/react"; then
echo "ERR: @types/react module still exists in lockfile"
exit 1
fi
if echo "$yarn_dot_lock" | grep -q "@types/react"; then
echo "ERR: @types/react module still exists in $dir"
exit 1
fi
${NPM_CLIENT:-$(which bun)} remove react
if [ -d "node_modules/react" ]; then
echo "ERR: react module still exists in $dir"
exit 1
fi
if [ -d "bun.lockb" ]; then
echo "ERR: empty bun.lockb should be deleted"
exit 1
fi

View File

@@ -0,0 +1,7 @@
{
"name": "check",
"scripts": {
"this-should-work": "echo \"✅ bun run test passed!\"",
"argv": "node -e 'console.log(process.argv)'"
}
}

View File

@@ -0,0 +1,43 @@
#!/bin/bash
(killall -9 $(basename $BUN_BIN) || echo "") >/dev/null 2>&1
# https://github.com/Jarred-Sumner/bun/issues/40
# Define a function (details aren't important)
fn() { :; }
# The important bit: export the function
export -f fn
rm -rf /tmp/bun-run-check
mkdir -p /tmp/bun-run-check
cp ./bun-run-check-package.json /tmp/bun-run-check/package.json
cd /tmp/bun-run-check
$BUN_BIN run bash -- -c ""
if (($?)); then
echo "Bash exported functions are broken"
exit 1
fi
# https://github.com/Jarred-Sumner/bun/issues/53
rm -f /tmp/bun-run-out.expected.txt /tmp/bun-run-out.txt >/dev/null 2>&1
$BUN_BIN run --silent argv -- foo bar baz >/tmp/bun-run-out.txt
npm run --silent argv -- foo bar baz >/tmp/bun-run-out.expected.txt
cmp -s /tmp/bun-run-out.expected.txt /tmp/bun-run-out.txt
if (($?)); then
echo "argv failed"
exit 1
fi
$BUN_BIN run --silent this-should-work
if (($?)); then
echo "this-should work failed"
exit 1
fi
exit 0

77
test/bun.js/atob.test.js Normal file
View File

@@ -0,0 +1,77 @@
import { expect, it } from "bun:test";
function expectInvalidCharacters(val) {
try {
atob(val);
throw new Error("Expected error");
} catch (error) {
expect(error.message).toBe("The string contains invalid characters.");
}
}
it("atob", () => {
expect(atob("YQ==")).toBe("a");
expect(atob("YWI=")).toBe("ab");
expect(atob("YWJj")).toBe("abc");
expect(atob("YWJjZA==")).toBe("abcd");
expect(atob("YWJjZGU=")).toBe("abcde");
expect(atob("YWJjZGVm")).toBe("abcdef");
expect(atob("zzzz")).toBe("Ï<ó");
expect(atob("")).toBe("");
expect(atob(null)).toBe("žée");
expect(atob("6ek=")).toBe("éé");
expect(atob("6ek")).toBe("éé");
expect(atob("gIE=")).toBe("€");
expect(atob("zz")).toBe("Ï");
expect(atob("zzz")).toBe("Ï<");
expect(atob("zzz=")).toBe("Ï<");
expect(atob(" YQ==")).toBe("a");
expect(atob("YQ==\u000a")).toBe("a");
try {
atob();
} catch (error) {
expect(error.name).toBe("TypeError");
}
expectInvalidCharacters(undefined);
expectInvalidCharacters(" abcd===");
expectInvalidCharacters("abcd=== ");
expectInvalidCharacters("abcd ===");
expectInvalidCharacters("тест");
expectInvalidCharacters("z");
expectInvalidCharacters("zzz==");
expectInvalidCharacters("zzz===");
expectInvalidCharacters("zzz====");
expectInvalidCharacters("zzz=====");
expectInvalidCharacters("zzzzz");
expectInvalidCharacters("z=zz");
expectInvalidCharacters("=");
expectInvalidCharacters("==");
expectInvalidCharacters("===");
expectInvalidCharacters("====");
expectInvalidCharacters("=====");
});
it("btoa", () => {
expect(btoa("a")).toBe("YQ==");
expect(btoa("ab")).toBe("YWI=");
expect(btoa("abc")).toBe("YWJj");
expect(btoa("abcd")).toBe("YWJjZA==");
expect(btoa("abcde")).toBe("YWJjZGU=");
expect(btoa("abcdef")).toBe("YWJjZGVm");
expect(typeof btoa).toBe("function");
try {
btoa();
throw new Error("Expected error");
} catch (error) {
expect(error.name).toBe("TypeError");
}
var window = "[object Window]";
expect(btoa("")).toBe("");
expect(btoa(null)).toBe("bnVsbA==");
expect(btoa(undefined)).toBe("dW5kZWZpbmVk");
expect(btoa(window)).toBe("W29iamVjdCBXaW5kb3dd");
expect(btoa("éé")).toBe("6ek=");
expect(btoa("\u0080\u0081")).toBe("gIE=");
expect(btoa(Bun)).toBe(btoa("[object Bun]"));
});

2
test/bun.js/baz.js Normal file
View File

@@ -0,0 +1,2 @@
// this file is used in resolve.test.js
export default {};

304
test/bun.js/buffer.test.js Normal file
View File

@@ -0,0 +1,304 @@
// import { describe, it, expect, beforeEach, afterEach } from "bun:test";
// import { gc } from "./gc";
// beforeEach(() => gc());
// afterEach(() => gc());
// it("buffer", () => {
// var buf = new Buffer(20);
// gc();
// // if this fails or infinitely loops, it means there is a memory issue with the JSC::Structure object
// expect(Object.keys(buf).length > 0).toBe(true);
// gc();
// expect(buf.write("hello world ")).toBe(12);
// expect(buf.write("hello world ", "utf8")).toBe(12);
// gc();
// expect(buf.toString("utf8", 0, "hello world ".length)).toBe("hello world ");
// gc();
// expect(buf.toString("base64url", 0, "hello world ".length)).toBe(
// btoa("hello world ")
// );
// gc();
// expect(buf instanceof Uint8Array).toBe(true);
// gc();
// expect(buf instanceof Buffer).toBe(true);
// gc();
// expect(buf.slice() instanceof Uint8Array).toBe(true);
// gc();
// expect(buf.slice(0, 1) instanceof Buffer).toBe(true);
// gc();
// expect(buf.slice(0, 1) instanceof Uint8Array).toBe(true);
// gc();
// expect(buf.slice(0, 1) instanceof Buffer).toBe(true);
// gc();
// });
// it("Buffer", () => {
// var inputs = [
// "hello world",
// "hello world".repeat(100),
// `😋 Get Emoji — All Emojis to ✂️ Copy and 📋 Paste 👌`,
// ];
// var good = inputs.map((a) => new TextEncoder().encode(a));
// for (let i = 0; i < inputs.length; i++) {
// var input = inputs[i];
// expect(new Buffer(input).toString("utf8")).toBe(inputs[i]);
// gc();
// expect(Array.from(new Buffer(input)).join(",")).toBe(good[i].join(","));
// gc();
// expect(Buffer.byteLength(input)).toBe(good[i].length);
// gc();
// expect(Buffer.from(input).byteLength).toBe(Buffer.byteLength(input));
// }
// });
// it("Buffer.byteLength", () => {
// expect(Buffer.byteLength("😀😃😄😁😆😅😂🤣☺️😊😊😇")).toBe(
// new TextEncoder().encode("😀😃😄😁😆😅😂🤣☺️😊😊😇").byteLength
// );
// });
// it("Buffer.isBuffer", () => {
// expect(Buffer.isBuffer(new Buffer(1))).toBe(true);
// gc();
// expect(Buffer.isBuffer(new Buffer(0))).toBe(true);
// gc();
// expect(Buffer.isBuffer(new Uint8Array(0))).toBe(false);
// gc();
// expect(Buffer.isBuffer(new Uint8Array(1))).toBe(false);
// gc();
// var a = new Uint8Array(1);
// gc();
// expect(Buffer.isBuffer(a)).toBe(false);
// gc();
// Buffer.toBuffer(a);
// gc();
// expect(Buffer.isBuffer(a)).toBe(true);
// gc();
// });
// it("Buffer.toBuffer throws", () => {
// const checks = [
// [],
// {},
// "foo",
// new Uint16Array(),
// new DataView(new Uint8Array(14).buffer),
// ];
// for (let i = 0; i < checks.length; i++) {
// try {
// Buffer.toBuffer(checks[i]);
// expect(false).toBe(true);
// } catch (exception) {
// expect(exception.message).toBe("Expected Uint8Array");
// }
// }
// expect(true).toBe(true);
// });
// it("Buffer.toBuffer works", () => {
// var array = new Uint8Array(20);
// expect(array instanceof Buffer).toBe(false);
// var buf = Buffer.toBuffer(array);
// expect(array instanceof Buffer).toBe(true);
// // if this fails or infinitely loops, it means there is a memory issue with the JSC::Structure object
// expect(Object.keys(buf).length > 0).toBe(true);
// expect(buf.write("hello world ")).toBe(12);
// gc();
// expect(buf.toString("utf8", 0, "hello world ".length)).toBe("hello world ");
// gc();
// expect(buf.toString("base64url", 0, "hello world ".length)).toBe(
// btoa("hello world ")
// );
// gc();
// expect(buf instanceof Uint8Array).toBe(true);
// expect(buf instanceof Buffer).toBe(true);
// expect(buf.slice() instanceof Uint8Array).toBe(true);
// expect(buf.slice(0, 1) instanceof Buffer).toBe(true);
// expect(buf.slice(0, 1) instanceof Uint8Array).toBe(true);
// expect(buf.slice(0, 1) instanceof Buffer).toBe(true);
// expect(new Buffer(buf) instanceof Buffer).toBe(true);
// expect(new Buffer(buf.buffer) instanceof Buffer).toBe(true);
// });
// it("writeInt", () => {
// var buf = new Buffer(1024);
// var data = new DataView(buf.buffer);
// buf.writeInt32BE(100);
// expect(data.getInt32(0, false)).toBe(100);
// buf.writeInt32BE(100);
// expect(data.getInt32(0, false)).toBe(100);
// var childBuf = buf.subarray(0, 4);
// expect(data.getInt32(0, false)).toBe(100);
// expect(childBuf.readInt32BE(0, false)).toBe(100);
// });
// it("Buffer.from", () => {
// expect(Buffer.from("hello world").toString("utf8")).toBe("hello world");
// expect(Buffer.from("hello world", "ascii").toString("utf8")).toBe(
// "hello world"
// );
// expect(Buffer.from("hello world", "latin1").toString("utf8")).toBe(
// "hello world"
// );
// gc();
// expect(Buffer.from([254]).join(",")).toBe("254");
// expect(Buffer.from(123).join(",")).toBe(Uint8Array.from(123).join(","));
// expect(Buffer.from({ length: 124 }).join(",")).toBe(
// Uint8Array.from({ length: 124 }).join(",")
// );
// expect(Buffer.from(new ArrayBuffer(1024), 0, 512).join(",")).toBe(
// new Uint8Array(512).join(",")
// );
// expect(Buffer.from(new Buffer(new ArrayBuffer(1024), 0, 512)).join(",")).toBe(
// new Uint8Array(512).join(",")
// );
// gc();
// });
// it("Buffer.equals", () => {
// var a = new Uint8Array(10);
// a[2] = 1;
// var b = new Uint8Array(10);
// b[2] = 1;
// Buffer.toBuffer(a);
// Buffer.toBuffer(b);
// expect(a.equals(b)).toBe(true);
// b[2] = 0;
// expect(a.equals(b)).toBe(false);
// });
// it("Buffer.compare", () => {
// var a = new Uint8Array(10);
// a[2] = 1;
// var b = new Uint8Array(10);
// b[2] = 1;
// Buffer.toBuffer(a);
// Buffer.toBuffer(b);
// expect(a.compare(b)).toBe(0);
// b[2] = 0;
// expect(a.compare(b)).toBe(1);
// expect(b.compare(a)).toBe(-1);
// });
// it("Buffer.copy", () => {
// var array1 = new Uint8Array(128);
// array1.fill(100);
// Buffer.toBuffer(array1);
// var array2 = new Uint8Array(128);
// array2.fill(200);
// Buffer.toBuffer(array2);
// var array3 = new Uint8Array(128);
// Buffer.toBuffer(array3);
// gc();
// expect(array1.copy(array2)).toBe(128);
// expect(array1.join("")).toBe(array2.join(""));
// });
// it("Buffer.concat", () => {
// var array1 = new Uint8Array(128);
// array1.fill(100);
// var array2 = new Uint8Array(128);
// array2.fill(200);
// var array3 = new Uint8Array(128);
// array3.fill(300);
// gc();
// expect(Buffer.concat([array1, array2, array3]).join("")).toBe(
// array1.join("") + array2.join("") + array3.join("")
// );
// expect(Buffer.concat([array1, array2, array3], 222).length).toBe(222);
// expect(
// Buffer.concat([array1, array2, array3], 222).subarray(0, 128).join("")
// ).toBe("100".repeat(128));
// expect(
// Buffer.concat([array1, array2, array3], 222).subarray(129, 222).join("")
// ).toBe("200".repeat(222 - 129));
// });
// it("read", () => {
// var buf = new Buffer(1024);
// var data = new DataView(buf.buffer);
// function reset() {
// new Uint8Array(buf.buffer).fill(0);
// }
// data.setBigInt64(0, BigInt(1000), false);
// expect(buf.readBigInt64BE(0)).toBe(BigInt(1000));
// reset();
// data.setBigInt64(0, BigInt(1000), false);
// expect(buf.readBigInt64LE(0)).toBe(BigInt(1000));
// reset();
// data.setBigUint64(0, BigInt(1000), false);
// expect(buf.readBigUInt64BE(0)).toBe(BigInt(1000));
// reset();
// data.setBigUint64(0, BigInt(1000), false);
// expect(buf.readBigUInt64LE(0)).toBe(BigInt(1000));
// reset();
// data.setFloat64(0, 1000, false);
// expect(buf.readDoubleBE(0)).toBe(1000);
// reset();
// data.setFloat64(0, 1000, true);
// expect(buf.readDoubleLE(0)).toBe(1000);
// reset();
// data.setFloat32(0, 1000, false);
// expect(buf.readFloatBE(0)).toBe(1000);
// reset();
// data.setFloat32(0, 1000, true);
// expect(buf.readFloatLE(0)).toBe(1000);
// reset();
// data.setInt16(0, 1000, false);
// expect(buf.readInt16BE(0)).toBe(1000);
// reset();
// data.setInt16(0, 1000, true);
// expect(buf.readInt16LE(0)).toBe(1000);
// reset();
// data.setInt32(0, 1000, false);
// expect(buf.readInt32BE(0)).toBe(1000);
// reset();
// data.setInt32(0, 1000, true);
// expect(buf.readInt32LE(0)).toBe(1000);
// reset();
// data.setInt8(0, 100, false);
// expect(buf.readInt8(0)).toBe(100);
// reset();
// data.setUint16(0, 1000, false);
// expect(buf.readUInt16BE(0)).toBe(1000);
// reset();
// data.setUint16(0, 1000, true);
// expect(buf.readUInt16LE(0)).toBe(1000);
// reset();
// data.setUint32(0, 1000, false);
// expect(buf.readUInt32BE(0)).toBe(1000);
// reset();
// data.setUint32(0, 1000, true);
// expect(buf.readUInt32LE(0)).toBe(1000);
// reset();
// data.setUint8(0, 255, false);
// expect(buf.readUInt8(0)).toBe(255);
// reset();
// data.setUint8(0, 255, false);
// expect(buf.readUInt8(0)).toBe(255);
// reset();
// });

View File

@@ -0,0 +1,98 @@
import { describe, expect, it } from "bun:test";
import {
describe as jscDescribe,
describeArray,
gcAndSweep,
fullGC,
edenGC,
heapSize,
heapStats,
memoryUsage,
getRandomSeed,
setRandomSeed,
isRope,
callerSourceOrigin,
noFTL,
noOSRExitFuzzing,
optimizeNextInvocation,
numberOfDFGCompiles,
releaseWeakRefs,
totalCompileTime,
reoptimizationRetryCount,
drainMicrotasks,
startRemoteDebugger,
} from "bun:jsc";
describe("bun:jsc", () => {
function count() {
var j = 0;
for (var i = 0; i < 999999; i++) {
j += i + 2;
}
return j;
}
it("describe", () => {
jscDescribe([]);
});
it("describeArray", () => {
describeArray([1, 2, 3]);
});
it("gcAndSweep", () => {
gcAndSweep();
});
it("fullGC", () => {
fullGC();
});
it("edenGC", () => {
edenGC();
});
it("heapSize", () => {
expect(heapSize() > 0).toBe(true);
});
it("heapStats", () => {
heapStats();
});
it("memoryUsage", () => {
memoryUsage();
});
it("getRandomSeed", () => {
getRandomSeed(2);
});
it("setRandomSeed", () => {
setRandomSeed(2);
});
it("isRope", () => {
expect(isRope("a" + 123 + "b")).toBe(true);
expect(isRope("abcdefgh")).toBe(false);
});
it("callerSourceOrigin", () => {
expect(callerSourceOrigin()).toBe(import.meta.url);
});
it("noFTL", () => {});
it("noOSRExitFuzzing", () => {});
it("optimizeNextInvocation", () => {
count();
optimizeNextInvocation(count);
count();
});
it("numberOfDFGCompiles", () => {
expect(numberOfDFGCompiles(count) > 0).toBe(true);
});
it("releaseWeakRefs", () => {
releaseWeakRefs();
});
it("totalCompileTime", () => {
totalCompileTime(count);
});
it("reoptimizationRetryCount", () => {
reoptimizationRetryCount(count);
});
it("drainMicrotasks", () => {
drainMicrotasks();
});
it("startRemoteDebugger", () => {
startRemoteDebugger("");
});
});

BIN
test/bun.js/bun.lockb Executable file

Binary file not shown.

View File

@@ -0,0 +1 @@
node_modules/always-bundled-module

View File

@@ -0,0 +1,10 @@
module.exports = {
default: 0xdeadbeef,
default() {
return "ok";
},
default: true,
ok() {
return true;
},
};

View File

@@ -0,0 +1,5 @@
const __esModule = true;
export const foo = () => __esModule;
export { __esModule, foo as default };

View File

@@ -0,0 +1,4 @@
{
"name": "always-bundled-module",
"version": "1.0.0"
}

View File

@@ -0,0 +1,13 @@
import "i-am-bundled/cjs";
import "i-am-bundled/esm";
import "always-bundled-module/esm";
import "always-bundled-module/cjs";
import { foo } from "i-am-bundled/esm";
import { foo as foo2 } from "always-bundled-module/esm";
import cJS from "always-bundled-module/cjs";
foo();
foo2();
cJS();
export default cJS();

View File

@@ -0,0 +1,12 @@
{
"name": "to-bundle",
"scripts": {
"prebundle": "rm -rf node_modules; cp -r to_bundle_node_modules node_modules; ln -s always-bundled-module node_modules/always-bundled-module",
"bundle": "${BUN_BIN:-$(which bun)} bun ./entrypoint.ts"
},
"bun": {
"alwaysBundle": [
"always-bundled-module"
]
}
}

View File

@@ -0,0 +1,10 @@
module.exports = {
default: 0xdeadbeef,
default() {
return "ok";
},
default: true,
ok() {
return true;
},
};

View File

@@ -0,0 +1,5 @@
const __esModule = true;
export const foo = () => __esModule;
export { __esModule, foo as default };

View File

@@ -0,0 +1,4 @@
{
"name": "i-am-bundled",
"version": "1.0.0"
}

View File

@@ -0,0 +1,6 @@
{
"compilerOptions": {
"paths": {},
"baseUrl": "."
}
}

View File

@@ -0,0 +1,46 @@
import { describe, it, expect } from "bun:test";
import { gcTick } from "./gc";
import { concatArrayBuffers } from "bun";
describe("concat", () => {
function polyfill(chunks) {
var size = 0;
for (const chunk of chunks) {
size += chunk.byteLength;
}
var buffer = new ArrayBuffer(size);
var view = new Uint8Array(buffer);
var offset = 0;
for (const chunk of chunks) {
view.set(chunk, offset);
offset += chunk.byteLength;
}
return buffer;
}
function concatToString(chunks) {
return Array.from(new Uint8Array(concatArrayBuffers(chunks))).join("");
}
function polyfillToString(chunks) {
return Array.from(new Uint8Array(polyfill(chunks))).join("");
}
it("works with one element", () => {
expect(concatToString([new Uint8Array([123])])).toBe(
polyfillToString([new Uint8Array([123])])
);
});
it("works with two elements", () => {
expect(
concatToString([Uint8Array.from([123]), Uint8Array.from([456])])
).toBe(polyfillToString([Uint8Array.from([123]), Uint8Array.from([456])]));
});
it("works with mix of ArrayBuffer and TypedArray elements", () => {
expect(
concatToString([Uint8Array.from([123]).buffer, Uint8Array.from([456])])
).toBe(polyfillToString([Uint8Array.from([123]), Uint8Array.from([456])]));
});
});

View File

@@ -0,0 +1,58 @@
console.log("Hello World!");
console.log(123);
console.log(-123);
console.log(123.567);
console.log(-123.567);
console.log(true);
console.log(false);
console.log(null);
console.log(undefined);
console.log(Symbol("Symbol Description"));
console.log(new Date(2021, 12, 30, 666, 777, 888, 999));
console.log([123, 456, 789]);
console.log({ a: 123, b: 456, c: 789 });
console.log({
a: {
b: {
c: 123,
},
bacon: true,
},
});
console.log(new Promise(() => {}));
class Foo {}
console.log(() => {});
console.log(Foo);
console.log(new Foo());
console.log(function foooo() {});
console.log(/FooRegex/);
console.error("uh oh");
console.time("Check");
console.log(
"Is it a bug or a feature that formatting numbers like %d is colored",
123
);
console.log(globalThis);
console.log(
"String %s should be 2nd word, 456 == %s and percent s %s == %s",
"123",
"456",
"%s",
"What",
"okay"
);
const infinteLoop = {
foo: {},
bar: {},
};
infinteLoop.bar = infinteLoop;
console.log(infinteLoop, "am");

View File

@@ -0,0 +1,70 @@
import {
sha,
MD5,
MD4,
SHA1,
SHA256,
SHA384,
SHA512,
SHA512_256,
gc,
} from "bun";
import { it, expect, describe } from "bun:test";
import { readFileSync } from "fs";
describe("crypto", () => {
for (let Hash of [MD5, MD4, SHA1, SHA256, SHA384, SHA512, SHA512_256]) {
for (let [input, label] of [
["hello world", '"hello world"'],
["hello world".repeat(20).slice(), '"hello world" x 20'],
["", "empty string"],
["a", '"a"'],
]) {
describe(label, () => {
gc(true);
it(`${Hash.name} base64`, () => {
gc(true);
const result = new Hash();
result.update(input);
expect(typeof result.digest("base64")).toBe("string");
gc(true);
});
it(`${Hash.name} hash base64`, () => {
Hash.hash(input, "base64");
gc(true);
});
it(`${Hash.name} hex`, () => {
const result = new Hash();
result.update(input);
expect(typeof result.digest("hex")).toBe("string");
gc(true);
});
it(`${Hash.name} hash hex`, () => {
expect(typeof Hash.hash(input, "hex")).toBe("string");
gc(true);
});
it(`${Hash.name} buffer`, () => {
var buf = new Uint8Array(256);
const result = new Hash();
result.update(input);
expect(result.digest(buf)).toBe(buf);
expect(buf[0] != 0).toBe(true);
gc(true);
});
it(`${Hash.name} buffer`, () => {
var buf = new Uint8Array(256);
expect(Hash.hash(input, buf) instanceof Uint8Array).toBe(true);
gc(true);
});
});
}
}
});

View File

@@ -0,0 +1,9 @@
import { expect, it } from "bun:test";
it("__dirname should work", () => {
expect(import.meta.dir).toBe(__dirname);
});
it("__filename should work", () => {
expect(import.meta.path).toBe(__filename);
});

View File

@@ -0,0 +1,105 @@
import { describe, it, expect } from "bun:test";
import { gcTick } from "./gc";
import { escapeHTML } from "bun";
describe("escapeHTML", () => {
// The matrix of cases we need to test for:
// 1. Works with short strings
// 2. Works with long strings
// 3. Works with latin1 strings
// 4. Works with utf16 strings
// 5. Works when the text to escape is somewhere in the middle
// 6. Works when the text to escape is in the beginning
// 7. Works when the text to escape is in the end
// 8. Returns the same string when there's no need to escape
it("works", () => {
expect(escapeHTML("absolutely nothing to do here")).toBe(
"absolutely nothing to do here"
);
expect(escapeHTML("<script>alert(1)</script>")).toBe(
"&lt;script&gt;alert(1)&lt;/script&gt;"
);
expect(escapeHTML("<")).toBe("&lt;");
expect(escapeHTML(">")).toBe("&gt;");
expect(escapeHTML("&")).toBe("&amp;");
expect(escapeHTML("'")).toBe("&#x27;");
expect(escapeHTML('"')).toBe("&quot;");
expect(escapeHTML("\n")).toBe("\n");
expect(escapeHTML("\r")).toBe("\r");
expect(escapeHTML("\t")).toBe("\t");
expect(escapeHTML("\f")).toBe("\f");
expect(escapeHTML("\v")).toBe("\v");
expect(escapeHTML("\b")).toBe("\b");
expect(escapeHTML("\u00A0")).toBe("\u00A0");
expect(escapeHTML("<script>ab")).toBe("&lt;script&gt;ab");
expect(escapeHTML("<script>")).toBe("&lt;script&gt;");
expect(escapeHTML("<script><script>")).toBe("&lt;script&gt;&lt;script&gt;");
expect(escapeHTML("lalala" + "<script>alert(1)</script>" + "lalala")).toBe(
"lalala&lt;script&gt;alert(1)&lt;/script&gt;lalala"
);
expect(escapeHTML("<script>alert(1)</script>" + "lalala")).toBe(
"&lt;script&gt;alert(1)&lt;/script&gt;lalala"
);
expect(escapeHTML("lalala" + "<script>alert(1)</script>")).toBe(
"lalala" + "&lt;script&gt;alert(1)&lt;/script&gt;"
);
expect(escapeHTML("What does 😊 mean?")).toBe("What does 😊 mean?");
const output = escapeHTML("<What does 😊");
expect(output).toBe("&lt;What does 😊");
expect(escapeHTML("<div>What does 😊 mean in text?")).toBe(
"&lt;div&gt;What does 😊 mean in text?"
);
expect(
escapeHTML(
("lalala" + "<script>alert(1)</script>" + "lalala").repeat(900)
)
).toBe("lalala&lt;script&gt;alert(1)&lt;/script&gt;lalala".repeat(900));
expect(
escapeHTML(("<script>alert(1)</script>" + "lalala").repeat(900))
).toBe("&lt;script&gt;alert(1)&lt;/script&gt;lalala".repeat(900));
expect(
escapeHTML(("lalala" + "<script>alert(1)</script>").repeat(900))
).toBe(("lalala" + "&lt;script&gt;alert(1)&lt;/script&gt;").repeat(900));
// the positions of the unicode codepoint are important
// our simd code for U16 is at 8 bytes, so we need to especially check the boundaries
expect(
escapeHTML("😊lalala" + "<script>alert(1)</script>" + "lalala")
).toBe("😊lalala&lt;script&gt;alert(1)&lt;/script&gt;lalala");
expect(escapeHTML("<script>😊alert(1)</script>" + "lalala")).toBe(
"&lt;script&gt;😊alert(1)&lt;/script&gt;lalala"
);
expect(escapeHTML("<script>alert(1)😊</script>" + "lalala")).toBe(
"&lt;script&gt;alert(1)😊&lt;/script&gt;lalala"
);
expect(escapeHTML("<script>alert(1)</script>" + "😊lalala")).toBe(
"&lt;script&gt;alert(1)&lt;/script&gt;😊lalala"
);
expect(escapeHTML("<script>alert(1)</script>" + "lal😊ala")).toBe(
"&lt;script&gt;alert(1)&lt;/script&gt;lal😊ala"
);
expect(
escapeHTML("<script>alert(1)</script>" + "lal😊ala".repeat(10))
).toBe("&lt;script&gt;alert(1)&lt;/script&gt;" + "lal😊ala".repeat(10));
for (let i = 1; i < 10; i++)
expect(escapeHTML("<script>alert(1)</script>" + "la😊".repeat(i))).toBe(
"&lt;script&gt;alert(1)&lt;/script&gt;" + "la😊".repeat(i)
);
expect(escapeHTML("la😊" + "<script>alert(1)</script>")).toBe(
"la😊" + "&lt;script&gt;alert(1)&lt;/script&gt;"
);
expect(
escapeHTML(("lalala" + "<script>alert(1)</script>😊").repeat(1))
).toBe(("lalala" + "&lt;script&gt;alert(1)&lt;/script&gt;😊").repeat(1));
expect(escapeHTML("😊".repeat(100))).toBe("😊".repeat(100));
expect(escapeHTML("😊<".repeat(100))).toBe("😊&lt;".repeat(100));
expect(escapeHTML("<😊>".repeat(100))).toBe("&lt;😊&gt;".repeat(100));
});
});

View File

@@ -0,0 +1,8 @@
import { end, start } from "./startEnd.mjs";
start("First");
import "./second.mjs";
import "./third.mjs";
end("First");

View File

@@ -0,0 +1,5 @@
import { start, end } from "./startEnd.mjs";
start("Second (nested import)");
end("Second (nested import)");

View File

@@ -0,0 +1,7 @@
import { start, end } from "./startEnd.mjs";
start("Second");
import "./second-child.mjs";
end("Second");

View File

@@ -0,0 +1,6 @@
export function start(name) {
console.log(`[start] ${name}`);
}
export function end(name) {
console.log(`[end] ${name}`);
}

View File

@@ -0,0 +1,4 @@
import { end, start } from "./startEnd.mjs";
start("Third");
end("Third");

2
test/bun.js/exit.js Normal file
View File

@@ -0,0 +1,2 @@
process.exit(0);
throw new Error("Well that didn't work");

46
test/bun.js/fetch.js.txt Normal file
View File

@@ -0,0 +1,46 @@
<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
body {
background-color: #f0f0f2;
margin: 0;
padding: 0;
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
div {
width: 600px;
margin: 5em auto;
padding: 2em;
background-color: #fdfdff;
border-radius: 0.5em;
box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
}
a:link, a:visited {
color: #38488f;
text-decoration: none;
}
@media (max-width: 700px) {
div {
margin: 0 auto;
width: auto;
}
}
</style>
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is for use in illustrative examples in documents. You may use this
domain in literature without prior coordination or asking for permission.</p>
<p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>

440
test/bun.js/fetch.test.js Normal file
View File

@@ -0,0 +1,440 @@
import { it, describe, expect } from "bun:test";
import fs from "fs";
import { gc } from "./gc";
describe("fetch", () => {
const urls = ["https://example.com", "http://example.com"];
for (let url of urls) {
gc();
it(url, async () => {
gc();
const response = await fetch(url);
gc();
const text = await response.text();
gc();
expect(
fs.readFileSync(
import.meta.path.substring(0, import.meta.path.lastIndexOf("/")) +
"/fetch.js.txt",
"utf8"
)
).toBe(text);
});
}
});
function testBlobInterface(blobbyConstructor, hasBlobFn) {
for (let withGC of [false, true]) {
for (let jsonObject of [
{ hello: true },
{
hello:
"😀 😃 😄 😁 😆 😅 😂 🤣 🥲 ☺️ 😊 😇 🙂 🙃 😉 😌 😍 🥰 😘 😗 😙 😚 😋 😛 😝 😜 🤪 🤨 🧐 🤓 😎 🥸 🤩 🥳",
},
]) {
it(`${jsonObject.hello === true ? "latin1" : "utf16"} json${
withGC ? " (with gc) " : ""
}`, async () => {
if (withGC) gc();
var response = blobbyConstructor(JSON.stringify(jsonObject));
if (withGC) gc();
expect(JSON.stringify(await response.json())).toBe(
JSON.stringify(jsonObject)
);
if (withGC) gc();
});
it(`${
jsonObject.hello === true ? "latin1" : "utf16"
} arrayBuffer -> json${withGC ? " (with gc) " : ""}`, async () => {
if (withGC) gc();
var response = blobbyConstructor(
new TextEncoder().encode(JSON.stringify(jsonObject))
);
if (withGC) gc();
expect(JSON.stringify(await response.json())).toBe(
JSON.stringify(jsonObject)
);
if (withGC) gc();
});
it(`${jsonObject.hello === true ? "latin1" : "utf16"} text${
withGC ? " (with gc) " : ""
}`, async () => {
if (withGC) gc();
var response = blobbyConstructor(JSON.stringify(jsonObject));
if (withGC) gc();
expect(await response.text()).toBe(JSON.stringify(jsonObject));
if (withGC) gc();
});
it(`${
jsonObject.hello === true ? "latin1" : "utf16"
} arrayBuffer -> text${withGC ? " (with gc) " : ""}`, async () => {
if (withGC) gc();
var response = blobbyConstructor(
new TextEncoder().encode(JSON.stringify(jsonObject))
);
if (withGC) gc();
expect(await response.text()).toBe(JSON.stringify(jsonObject));
if (withGC) gc();
});
it(`${jsonObject.hello === true ? "latin1" : "utf16"} arrayBuffer${
withGC ? " (with gc) " : ""
}`, async () => {
if (withGC) gc();
var response = blobbyConstructor(JSON.stringify(jsonObject));
if (withGC) gc();
const bytes = new TextEncoder().encode(JSON.stringify(jsonObject));
if (withGC) gc();
const compare = new Uint8Array(await response.arrayBuffer());
if (withGC) gc();
for (let i = 0; i < compare.length; i++) {
if (withGC) gc();
expect(compare[i]).toBe(bytes[i]);
if (withGC) gc();
}
if (withGC) gc();
});
it(`${
jsonObject.hello === true ? "latin1" : "utf16"
} arrayBuffer -> arrayBuffer${withGC ? " (with gc) " : ""}`, async () => {
if (withGC) gc();
var response = blobbyConstructor(
new TextEncoder().encode(JSON.stringify(jsonObject))
);
if (withGC) gc();
const bytes = new TextEncoder().encode(JSON.stringify(jsonObject));
if (withGC) gc();
const compare = new Uint8Array(await response.arrayBuffer());
if (withGC) gc();
for (let i = 0; i < compare.length; i++) {
if (withGC) gc();
expect(compare[i]).toBe(bytes[i]);
if (withGC) gc();
}
if (withGC) gc();
});
hasBlobFn &&
it(`${jsonObject.hello === true ? "latin1" : "utf16"} blob${
withGC ? " (with gc) " : ""
}`, async () => {
if (withGC) gc();
const text = JSON.stringify(jsonObject);
var response = blobbyConstructor(text);
if (withGC) gc();
const size = new TextEncoder().encode(text).byteLength;
if (withGC) gc();
const blobed = await response.blob();
if (withGC) gc();
expect(blobed instanceof Blob).toBe(true);
if (withGC) gc();
expect(blobed.size).toBe(size);
if (withGC) gc();
expect(blobed.type).toBe("");
if (withGC) gc();
blobed.type = "application/json";
if (withGC) gc();
expect(blobed.type).toBe("application/json");
if (withGC) gc();
const out = await blobed.text();
expect(out).toBe(text);
if (withGC) gc();
await new Promise((resolve) => setTimeout(resolve, 1));
if (withGC) gc();
expect(out).toBe(text);
const first = await blobed.arrayBuffer();
const initial = first[0];
first[0] = 254;
const second = await blobed.arrayBuffer();
expect(second[0]).toBe(initial);
expect(first[0]).toBe(254);
});
}
}
}
describe("Blob", () => {
testBlobInterface((data) => new Blob([data]));
var blobConstructorValues = [
["123", "456"],
["123", 456],
["123", "456", "789"],
["123", 456, 789],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[Uint8Array.from([1, 2, 3, 4, 5, 6, 7, 9])],
[Uint8Array.from([1, 2, 3, 4]), "5678", 9],
[new Blob([Uint8Array.from([1, 2, 3, 4])]), "5678", 9],
[
new Blob([
new TextEncoder().encode(
"😀 😃 😄 😁 😆 😅 😂 🤣 🥲 ☺️ 😊 😇 🙂 🙃 😉 😌 😍 🥰 😘 😗 😙 😚 😋 😛 😝 😜 🤪 🤨 🧐 🤓 😎 🥸 🤩 🥳"
),
]),
],
[
new TextEncoder().encode(
"😀 😃 😄 😁 😆 😅 😂 🤣 🥲 ☺️ 😊 😇 🙂 🙃 😉 😌 😍 🥰 😘 😗 😙 😚 😋 😛 😝 😜 🤪 🤨 🧐 🤓 😎 🥸 🤩 🥳"
),
],
];
var expected = [
"123456",
"123456",
"123456789",
"123456789",
"123456789",
"\x01\x02\x03\x04\x05\x06\x07\t",
"\x01\x02\x03\x0456789",
"\x01\x02\x03\x0456789",
"😀 😃 😄 😁 😆 😅 😂 🤣 🥲 ☺️ 😊 😇 🙂 🙃 😉 😌 😍 🥰 😘 😗 😙 😚 😋 😛 😝 😜 🤪 🤨 🧐 🤓 😎 🥸 🤩 🥳",
"😀 😃 😄 😁 😆 😅 😂 🤣 🥲 ☺️ 😊 😇 🙂 🙃 😉 😌 😍 🥰 😘 😗 😙 😚 😋 😛 😝 😜 🤪 🤨 🧐 🤓 😎 🥸 🤩 🥳",
];
it(`blobConstructorValues`, async () => {
for (let i = 0; i < blobConstructorValues.length; i++) {
var response = new Blob(blobConstructorValues[i]);
const res = await response.text();
if (res !== expected[i]) {
throw new Error(
`Failed: ${expected[i]
.split("")
.map((a) => a.charCodeAt(0))}, received: ${res
.split("")
.map((a) => a.charCodeAt(0))}`
);
}
expect(res).toBe(expected[i]);
}
});
for (let withGC of [false, true]) {
it(`Blob.slice() ${withGC ? " with gc" : ""}`, async () => {
var parts = ["hello", " ", "world"];
if (withGC) gc();
var str = parts.join("");
if (withGC) gc();
var combined = new Blob(parts);
if (withGC) gc();
for (let part of parts) {
if (withGC) gc();
expect(
await combined
.slice(str.indexOf(part), str.indexOf(part) + part.length)
.text()
).toBe(part);
if (withGC) gc();
}
if (withGC) gc();
for (let part of parts) {
if (withGC) gc();
expect(
await combined
.slice(str.indexOf(part), str.indexOf(part) + part.length)
.text()
).toBe(part);
if (withGC) gc();
}
});
}
});
describe("Response", () => {
describe("Response.json", () => {
it("works", async () => {
const inputs = [
"hellooo",
[[123], 456, 789],
{ hello: "world" },
{ ok: "😉 😌 😍 🥰 😘 " },
];
for (let input of inputs) {
const output = JSON.stringify(input);
expect(await Response.json(input).text()).toBe(output);
}
// JSON.stringify() returns undefined
expect(await Response.json().text()).toBe("");
// JSON.stringify("") returns '""'
expect(await Response.json("").text()).toBe('""');
});
it("sets the content-type header", () => {
let response = Response.json("hello");
expect(response.type).toBe("basic");
expect(response.headers.get("content-type")).toBe(
"application/json;charset=utf-8"
);
expect(response.status).toBe(200);
});
it("supports number status code", () => {
let response = Response.json("hello", 407);
expect(response.type).toBe("basic");
expect(response.headers.get("content-type")).toBe(
"application/json;charset=utf-8"
);
expect(response.status).toBe(407);
});
it("supports headers", () => {
var response = Response.json("hello", {
headers: {
"content-type": "potato",
"x-hello": "world",
},
status: 408,
});
expect(response.headers.get("x-hello")).toBe("world");
expect(response.status).toBe(408);
});
});
describe("Response.redirect", () => {
it("works", () => {
const inputs = [
"http://example.com",
"http://example.com/",
"http://example.com/hello",
"http://example.com/hello/",
"http://example.com/hello/world",
"http://example.com/hello/world/",
];
for (let input of inputs) {
expect(Response.redirect(input).headers.get("Location")).toBe(input);
}
});
it("supports headers", () => {
var response = Response.redirect("https://example.com", {
headers: {
"content-type": "potato",
"x-hello": "world",
Location: "https://wrong.com",
},
status: 408,
});
expect(response.headers.get("x-hello")).toBe("world");
expect(response.headers.get("Location")).toBe("https://example.com");
expect(response.status).toBe(302);
expect(response.type).toBe("basic");
expect(response.ok).toBe(false);
});
});
describe("Response.error", () => {
it("works", () => {
expect(Response.error().type).toBe("error");
expect(Response.error().ok).toBe(false);
expect(Response.error().status).toBe(0);
});
});
it("clone", async () => {
gc();
var body = new Response("<div>hello</div>", {
headers: {
"content-type": "text/html; charset=utf-8",
},
});
gc();
var clone = body.clone();
gc();
body.headers.set("content-type", "text/plain");
gc();
expect(clone.headers.get("content-type")).toBe("text/html; charset=utf-8");
gc();
expect(body.headers.get("content-type")).toBe("text/plain");
gc();
expect(await clone.text()).toBe("<div>hello</div>");
gc();
});
it("invalid json", async () => {
gc();
var body = new Response("<div>hello</div>", {
headers: {
"content-type": "text/html; charset=utf-8",
},
});
try {
await body.json();
expect(false).toBe(true);
} catch (exception) {
expect(exception instanceof SyntaxError);
}
});
testBlobInterface((data) => new Response(data), true);
});
describe("Request", () => {
it("clone", async () => {
gc();
var body = new Request("https://hello.com", {
headers: {
"content-type": "text/html; charset=utf-8",
},
body: "<div>hello</div>",
});
gc();
expect(body.headers.get("content-type")).toBe("text/html; charset=utf-8");
gc();
var clone = body.clone();
gc();
body.headers.set("content-type", "text/plain");
gc();
expect(clone.headers.get("content-type")).toBe("text/html; charset=utf-8");
gc();
expect(body.headers.get("content-type")).toBe("text/plain");
gc();
expect(await clone.text()).toBe("<div>hello</div>");
gc();
});
testBlobInterface(
(data) => new Request("https://hello.com", { body: data }),
true
);
});
describe("Headers", () => {
it("writes", async () => {
var headers = new Headers({
"content-type": "text/html; charset=utf-8",
});
gc();
expect(headers.get("content-type")).toBe("text/html; charset=utf-8");
gc();
headers.delete("content-type");
gc();
expect(headers.get("content-type")).toBe(null);
gc();
headers.append("content-type", "text/plain");
gc();
expect(headers.get("content-type")).toBe("text/plain");
gc();
headers.append("content-type", "text/plain");
gc();
expect(headers.get("content-type")).toBe("text/plain, text/plain");
gc();
headers.set("content-type", "text/html; charset=utf-8");
gc();
expect(headers.get("content-type")).toBe("text/html; charset=utf-8");
headers.delete("content-type");
gc();
expect(headers.get("content-type")).toBe(null);
gc();
});
});

129
test/bun.js/ffi-test.c Normal file
View File

@@ -0,0 +1,129 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
bool returns_true();
bool returns_false();
char returns_42_char();
float returns_42_float();
double returns_42_double();
uint8_t returns_42_uint8_t();
int8_t returns_neg_42_int8_t();
uint16_t returns_42_uint16_t();
uint32_t returns_42_uint32_t();
uint64_t returns_42_uint64_t();
int16_t returns_neg_42_int16_t();
int32_t returns_neg_42_int32_t();
int64_t returns_neg_42_int64_t();
bool cb_identity_true(bool (*cb)());
bool cb_identity_false(bool (*cb)());
char cb_identity_42_char(char (*cb)());
float cb_identity_42_float(float (*cb)());
double cb_identity_42_double(double (*cb)());
uint8_t cb_identity_42_uint8_t(uint8_t (*cb)());
int8_t cb_identity_neg_42_int8_t(int8_t (*cb)());
uint16_t cb_identity_42_uint16_t(uint16_t (*cb)());
uint32_t cb_identity_42_uint32_t(uint32_t (*cb)());
uint64_t cb_identity_42_uint64_t(uint64_t (*cb)());
int16_t cb_identity_neg_42_int16_t(int16_t (*cb)());
int32_t cb_identity_neg_42_int32_t(int32_t (*cb)());
int64_t cb_identity_neg_42_int64_t(int64_t (*cb)());
bool identity_bool_true();
bool identity_bool_false();
char identity_char(char a);
float identity_float(float a);
bool identity_bool(bool ident);
double identity_double(double a);
int8_t identity_int8_t(int8_t a);
int16_t identity_int16_t(int16_t a);
int32_t identity_int32_t(int32_t a);
int64_t identity_int64_t(int64_t a);
uint8_t identity_uint8_t(uint8_t a);
uint16_t identity_uint16_t(uint16_t a);
uint32_t identity_uint32_t(uint32_t a);
uint64_t identity_uint64_t(uint64_t a);
char add_char(char a, char b);
float add_float(float a, float b);
double add_double(double a, double b);
int8_t add_int8_t(int8_t a, int8_t b);
int16_t add_int16_t(int16_t a, int16_t b);
int32_t add_int32_t(int32_t a, int32_t b);
int64_t add_int64_t(int64_t a, int64_t b);
uint8_t add_uint8_t(uint8_t a, uint8_t b);
uint16_t add_uint16_t(uint16_t a, uint16_t b);
uint32_t add_uint32_t(uint32_t a, uint32_t b);
uint64_t add_uint64_t(uint64_t a, uint64_t b);
bool returns_false() { return false; }
bool returns_true() { return true; }
char returns_42_char() { return '*'; }
double returns_42_double() { return (double)42.42; }
float returns_42_float() { return 42.42f; }
int16_t returns_neg_42_int16_t() { return -42; }
int32_t returns_neg_42_int32_t() { return -42; }
int64_t returns_neg_42_int64_t() { return -42; }
int8_t returns_neg_42_int8_t() { return -42; }
uint16_t returns_42_uint16_t() { return 42; }
uint32_t returns_42_uint32_t() { return 42; }
uint64_t returns_42_uint64_t() { return 42; }
uint8_t returns_42_uint8_t() { return (uint8_t)42; }
char identity_char(char a) { return a; }
float identity_float(float a) { return a; }
double identity_double(double a) { return a; }
int8_t identity_int8_t(int8_t a) { return a; }
int16_t identity_int16_t(int16_t a) { return a; }
int32_t identity_int32_t(int32_t a) { return a; }
int64_t identity_int64_t(int64_t a) { return a; }
uint8_t identity_uint8_t(uint8_t a) { return a; }
uint16_t identity_uint16_t(uint16_t a) { return a; }
uint32_t identity_uint32_t(uint32_t a) { return a; }
uint64_t identity_uint64_t(uint64_t a) { return a; }
bool identity_bool(bool ident) { return ident; }
void *identity_ptr(void *ident) { return ident; }
char add_char(char a, char b) { return a + b; }
float add_float(float a, float b) { return a + b; }
double add_double(double a, double b) { return a + b; }
int8_t add_int8_t(int8_t a, int8_t b) { return a + b; }
int16_t add_int16_t(int16_t a, int16_t b) { return a + b; }
int32_t add_int32_t(int32_t a, int32_t b) { return a + b; }
int64_t add_int64_t(int64_t a, int64_t b) { return a + b; }
uint8_t add_uint8_t(uint8_t a, uint8_t b) { return a + b; }
uint16_t add_uint16_t(uint16_t a, uint16_t b) { return a + b; }
uint32_t add_uint32_t(uint32_t a, uint32_t b) { return a + b; }
uint64_t add_uint64_t(uint64_t a, uint64_t b) { return a + b; }
void *ptr_should_point_to_42_as_int32_t();
void *ptr_should_point_to_42_as_int32_t() {
int32_t *ptr = malloc(sizeof(int32_t));
*ptr = 42;
return ptr;
}
bool does_pointer_equal_42_as_int32_t(int32_t *ptr);
bool does_pointer_equal_42_as_int32_t(int32_t *ptr) { return *ptr == 42; }
void *return_a_function_ptr_to_function_that_returns_true();
void *return_a_function_ptr_to_function_that_returns_true() {
return (void *)&returns_true;
}
bool cb_identity_true(bool (*cb)()) { return cb(); }
bool cb_identity_false(bool (*cb)()) { return cb(); }
char cb_identity_42_char(char (*cb)()) { return cb(); }
float cb_identity_42_float(float (*cb)()) { return cb(); }
double cb_identity_42_double(double (*cb)()) { return cb(); }
uint8_t cb_identity_42_uint8_t(uint8_t (*cb)()) { return cb(); }
int8_t cb_identity_neg_42_int8_t(int8_t (*cb)()) { return cb(); }
uint16_t cb_identity_42_uint16_t(uint16_t (*cb)()) { return cb(); }
uint32_t cb_identity_42_uint32_t(uint32_t (*cb)()) { return cb(); }
uint64_t cb_identity_42_uint64_t(uint64_t (*cb)()) { return cb(); }
int16_t cb_identity_neg_42_int16_t(int16_t (*cb)()) { return cb(); }
int32_t cb_identity_neg_42_int32_t(int32_t (*cb)()) { return cb(); }
int64_t cb_identity_neg_42_int64_t(int64_t (*cb)()) { return cb(); }

View File

@@ -0,0 +1,270 @@
#define IS_CALLBACK 1
// This file is part of Bun!
// You can find the original source:
// https://github.com/Jarred-Sumner/bun/blob/main/src/bun.js/api/FFI.h#L2
//
// clang-format off
// This file is only compatible with 64 bit CPUs
// It must be kept in sync with JSCJSValue.h
// https://github.com/Jarred-Sumner/WebKit/blob/72c2052b781cbfd4af867ae79ac9de460e392fba/Source/JavaScriptCore/runtime/JSCJSValue.h#L455-L458
#ifdef IS_CALLBACK
#define INJECT_BEFORE int c = 500; // This is a callback, so we need to inject code before the call
#endif
#define IS_BIG_ENDIAN 0
#define USE_JSVALUE64 1
#define USE_JSVALUE32_64 0
// /* 7.18.1.1 Exact-width integer types */
typedef unsigned char uint8_t;
typedef signed char int8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned int uint32_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;
typedef unsigned long long size_t;
typedef long intptr_t;
typedef uint64_t uintptr_t;
typedef _Bool bool;
#define true 1
#define false 0
#ifdef INJECT_BEFORE
// #include <stdint.h>
#endif
// #include <tcclib.h>
// This value is 2^49, used to encode doubles such that the encoded value will
// begin with a 15-bit pattern within the range 0x0002..0xFFFC.
#define DoubleEncodeOffsetBit 49
#define DoubleEncodeOffset (1ll << DoubleEncodeOffsetBit)
#define OtherTag 0x2
#define BoolTag 0x4
#define UndefinedTag 0x8
#define TagValueFalse (OtherTag | BoolTag | false)
#define TagValueTrue (OtherTag | BoolTag | true)
#define TagValueUndefined (OtherTag | UndefinedTag)
#define TagValueNull (OtherTag)
#define NotCellMask NumberTag | OtherTag
#define MAX_INT32 2147483648
#define MAX_INT52 9007199254740991
// If all bits in the mask are set, this indicates an integer number,
// if any but not all are set this value is a double precision number.
#define NumberTag 0xfffe000000000000ll
typedef void* JSCell;
typedef union EncodedJSValue {
int64_t asInt64;
#if USE_JSVALUE64
JSCell *ptr;
#endif
#if IS_BIG_ENDIAN
struct {
int32_t tag;
int32_t payload;
} asBits;
#else
struct {
int32_t payload;
int32_t tag;
} asBits;
#endif
void* asPtr;
double asDouble;
} EncodedJSValue;
EncodedJSValue ValueUndefined = { TagValueUndefined };
EncodedJSValue ValueTrue = { TagValueTrue };
typedef void* JSContext;
// Bun_FFI_PointerOffsetToArgumentsList is injected into the build
// The value is generated in `make sizegen`
// The value is 6.
// On ARM64_32, the value is something else but it really doesn't matter for our case
// However, I don't want this to subtly break amidst future upgrades to JavaScriptCore
#define LOAD_ARGUMENTS_FROM_CALL_FRAME \
int64_t *argsPtr = (int64_t*)((size_t*)callFrame + Bun_FFI_PointerOffsetToArgumentsList)
#ifdef IS_CALLBACK
extern int64_t bun_call(JSContext, void* func, void* thisValue, size_t len, const EncodedJSValue args[], void* exception);
JSContext cachedJSContext;
void* cachedCallbackFunction;
#endif
static bool JSVALUE_IS_CELL(EncodedJSValue val) __attribute__((__always_inline__));
static bool JSVALUE_IS_INT32(EncodedJSValue val) __attribute__((__always_inline__));
static bool JSVALUE_IS_NUMBER(EncodedJSValue val) __attribute__((__always_inline__));
static uint64_t JSVALUE_TO_UINT64(void* globalObject, EncodedJSValue value) __attribute__((__always_inline__));
static int64_t JSVALUE_TO_INT64(EncodedJSValue value) __attribute__((__always_inline__));
uint64_t JSVALUE_TO_UINT64_SLOW(void* globalObject, EncodedJSValue value);
int64_t JSVALUE_TO_INT64_SLOW(EncodedJSValue value);
EncodedJSValue UINT64_TO_JSVALUE_SLOW(void* globalObject, uint64_t val);
EncodedJSValue INT64_TO_JSVALUE_SLOW(void* globalObject, int64_t val);
static EncodedJSValue UINT64_TO_JSVALUE(void* globalObject, uint64_t val) __attribute__((__always_inline__));
static EncodedJSValue INT64_TO_JSVALUE(void* globalObject, int64_t val) __attribute__((__always_inline__));
static EncodedJSValue INT32_TO_JSVALUE(int32_t val) __attribute__((__always_inline__));
static EncodedJSValue DOUBLE_TO_JSVALUE(double val) __attribute__((__always_inline__));
static EncodedJSValue FLOAT_TO_JSVALUE(float val) __attribute__((__always_inline__));
static EncodedJSValue BOOLEAN_TO_JSVALUE(bool val) __attribute__((__always_inline__));
static EncodedJSValue PTR_TO_JSVALUE(void* ptr) __attribute__((__always_inline__));
static void* JSVALUE_TO_PTR(EncodedJSValue val) __attribute__((__always_inline__));
static int32_t JSVALUE_TO_INT32(EncodedJSValue val) __attribute__((__always_inline__));
static float JSVALUE_TO_FLOAT(EncodedJSValue val) __attribute__((__always_inline__));
static double JSVALUE_TO_DOUBLE(EncodedJSValue val) __attribute__((__always_inline__));
static bool JSVALUE_TO_BOOL(EncodedJSValue val) __attribute__((__always_inline__));
static bool JSVALUE_IS_CELL(EncodedJSValue val) {
return !(val.asInt64 & NotCellMask);
}
static bool JSVALUE_IS_INT32(EncodedJSValue val) {
return (val.asInt64 & NumberTag) == NumberTag;
}
static bool JSVALUE_IS_NUMBER(EncodedJSValue val) {
return val.asInt64 & NumberTag;
}
static void* JSVALUE_TO_PTR(EncodedJSValue val) {
// must be a double
return (void*)(val.asInt64 - DoubleEncodeOffset);
}
static EncodedJSValue PTR_TO_JSVALUE(void* ptr) {
EncodedJSValue val;
val.asInt64 = (int64_t)ptr + DoubleEncodeOffset;
return val;
}
static int32_t JSVALUE_TO_INT32(EncodedJSValue val) {
return val.asInt64;
}
static EncodedJSValue INT32_TO_JSVALUE(int32_t val) {
EncodedJSValue res;
res.asInt64 = NumberTag | (uint32_t)val;
return res;
}
static EncodedJSValue DOUBLE_TO_JSVALUE(double val) {
EncodedJSValue res;
res.asDouble = val;
res.asInt64 += DoubleEncodeOffset;
return res;
}
static EncodedJSValue FLOAT_TO_JSVALUE(float val) {
return DOUBLE_TO_JSVALUE((double)val);
}
static EncodedJSValue BOOLEAN_TO_JSVALUE(bool val) {
EncodedJSValue res;
res.asInt64 = val ? TagValueTrue : TagValueFalse;
return res;
}
static double JSVALUE_TO_DOUBLE(EncodedJSValue val) {
val.asInt64 -= DoubleEncodeOffset;
return val.asDouble;
}
static float JSVALUE_TO_FLOAT(EncodedJSValue val) {
return (float)JSVALUE_TO_DOUBLE(val);
}
static bool JSVALUE_TO_BOOL(EncodedJSValue val) {
return val.asInt64 == TagValueTrue;
}
static uint64_t JSVALUE_TO_UINT64(void* globalObject, EncodedJSValue value) {
if (JSVALUE_IS_INT32(value)) {
return (uint64_t)JSVALUE_TO_INT32(value);
}
if (JSVALUE_IS_NUMBER(value)) {
return (uint64_t)JSVALUE_TO_DOUBLE(value);
}
return JSVALUE_TO_UINT64_SLOW(globalObject, value);
}
static int64_t JSVALUE_TO_INT64(EncodedJSValue value) {
if (JSVALUE_IS_INT32(value)) {
return (int64_t)JSVALUE_TO_INT32(value);
}
if (JSVALUE_IS_NUMBER(value)) {
return (int64_t)JSVALUE_TO_DOUBLE(value);
}
return JSVALUE_TO_INT64_SLOW(value);
}
static EncodedJSValue UINT64_TO_JSVALUE(void* globalObject, uint64_t val) {
if (val < MAX_INT32) {
return INT32_TO_JSVALUE((int32_t)val);
}
if (val < MAX_INT52) {
return DOUBLE_TO_JSVALUE((double)val);
}
return UINT64_TO_JSVALUE_SLOW(globalObject, val);
}
static EncodedJSValue INT64_TO_JSVALUE(void* globalObject, int64_t val) {
if (val >= -MAX_INT32 && val <= MAX_INT32) {
return INT32_TO_JSVALUE((int32_t)val);
}
if (val >= -MAX_INT52 && val <= MAX_INT52) {
return DOUBLE_TO_JSVALUE((double)val);
}
return INT64_TO_JSVALUE_SLOW(globalObject, val);
}
#ifndef IS_CALLBACK
void* JSFunctionCall(void* globalObject, void* callFrame);
#endif
// --- Generated Code ---
/* --- The Callback Function */
/* --- The Callback Function */
bool my_callback_function(void* arg0);
bool my_callback_function(void* arg0) {
#ifdef INJECT_BEFORE
INJECT_BEFORE;
#endif
EncodedJSValue arguments[1] = {
PTR_TO_JSVALUE(arg0)
};
EncodedJSValue return_value = {bun_call(cachedJSContext, cachedCallbackFunction, (void*)0, 1, &arguments[0], (void*)0)};
return JSVALUE_TO_BOOL(return_value);
}

View File

@@ -0,0 +1,268 @@
#define HAS_ARGUMENTS
#define USES_FLOAT 1
// This file is part of Bun!
// You can find the original source:
// https://github.com/Jarred-Sumner/bun/blob/main/src/bun.js/api/FFI.h#L2
//
// clang-format off
// This file is only compatible with 64 bit CPUs
// It must be kept in sync with JSCJSValue.h
// https://github.com/Jarred-Sumner/WebKit/blob/72c2052b781cbfd4af867ae79ac9de460e392fba/Source/JavaScriptCore/runtime/JSCJSValue.h#L455-L458
#ifdef IS_CALLBACK
#define INJECT_BEFORE int c = 500; // This is a callback, so we need to inject code before the call
#endif
#define IS_BIG_ENDIAN 0
#define USE_JSVALUE64 1
#define USE_JSVALUE32_64 0
// /* 7.18.1.1 Exact-width integer types */
typedef unsigned char uint8_t;
typedef signed char int8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned int uint32_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;
typedef unsigned long long size_t;
typedef long intptr_t;
typedef uint64_t uintptr_t;
typedef _Bool bool;
#define true 1
#define false 0
#ifdef INJECT_BEFORE
// #include <stdint.h>
#endif
// #include <tcclib.h>
// This value is 2^49, used to encode doubles such that the encoded value will
// begin with a 15-bit pattern within the range 0x0002..0xFFFC.
#define DoubleEncodeOffsetBit 49
#define DoubleEncodeOffset (1ll << DoubleEncodeOffsetBit)
#define OtherTag 0x2
#define BoolTag 0x4
#define UndefinedTag 0x8
#define TagValueFalse (OtherTag | BoolTag | false)
#define TagValueTrue (OtherTag | BoolTag | true)
#define TagValueUndefined (OtherTag | UndefinedTag)
#define TagValueNull (OtherTag)
#define NotCellMask NumberTag | OtherTag
#define MAX_INT32 2147483648
#define MAX_INT52 9007199254740991
// If all bits in the mask are set, this indicates an integer number,
// if any but not all are set this value is a double precision number.
#define NumberTag 0xfffe000000000000ll
typedef void* JSCell;
typedef union EncodedJSValue {
int64_t asInt64;
#if USE_JSVALUE64
JSCell *ptr;
#endif
#if IS_BIG_ENDIAN
struct {
int32_t tag;
int32_t payload;
} asBits;
#else
struct {
int32_t payload;
int32_t tag;
} asBits;
#endif
void* asPtr;
double asDouble;
} EncodedJSValue;
EncodedJSValue ValueUndefined = { TagValueUndefined };
EncodedJSValue ValueTrue = { TagValueTrue };
typedef void* JSContext;
// Bun_FFI_PointerOffsetToArgumentsList is injected into the build
// The value is generated in `make sizegen`
// The value is 6.
// On ARM64_32, the value is something else but it really doesn't matter for our case
// However, I don't want this to subtly break amidst future upgrades to JavaScriptCore
#define LOAD_ARGUMENTS_FROM_CALL_FRAME \
int64_t *argsPtr = (int64_t*)((size_t*)callFrame + Bun_FFI_PointerOffsetToArgumentsList)
#ifdef IS_CALLBACK
extern int64_t bun_call(JSContext, void* func, void* thisValue, size_t len, const EncodedJSValue args[], void* exception);
JSContext cachedJSContext;
void* cachedCallbackFunction;
#endif
static bool JSVALUE_IS_CELL(EncodedJSValue val) __attribute__((__always_inline__));
static bool JSVALUE_IS_INT32(EncodedJSValue val) __attribute__((__always_inline__));
static bool JSVALUE_IS_NUMBER(EncodedJSValue val) __attribute__((__always_inline__));
static uint64_t JSVALUE_TO_UINT64(void* globalObject, EncodedJSValue value) __attribute__((__always_inline__));
static int64_t JSVALUE_TO_INT64(EncodedJSValue value) __attribute__((__always_inline__));
uint64_t JSVALUE_TO_UINT64_SLOW(void* globalObject, EncodedJSValue value);
int64_t JSVALUE_TO_INT64_SLOW(EncodedJSValue value);
EncodedJSValue UINT64_TO_JSVALUE_SLOW(void* globalObject, uint64_t val);
EncodedJSValue INT64_TO_JSVALUE_SLOW(void* globalObject, int64_t val);
static EncodedJSValue UINT64_TO_JSVALUE(void* globalObject, uint64_t val) __attribute__((__always_inline__));
static EncodedJSValue INT64_TO_JSVALUE(void* globalObject, int64_t val) __attribute__((__always_inline__));
static EncodedJSValue INT32_TO_JSVALUE(int32_t val) __attribute__((__always_inline__));
static EncodedJSValue DOUBLE_TO_JSVALUE(double val) __attribute__((__always_inline__));
static EncodedJSValue FLOAT_TO_JSVALUE(float val) __attribute__((__always_inline__));
static EncodedJSValue BOOLEAN_TO_JSVALUE(bool val) __attribute__((__always_inline__));
static EncodedJSValue PTR_TO_JSVALUE(void* ptr) __attribute__((__always_inline__));
static void* JSVALUE_TO_PTR(EncodedJSValue val) __attribute__((__always_inline__));
static int32_t JSVALUE_TO_INT32(EncodedJSValue val) __attribute__((__always_inline__));
static float JSVALUE_TO_FLOAT(EncodedJSValue val) __attribute__((__always_inline__));
static double JSVALUE_TO_DOUBLE(EncodedJSValue val) __attribute__((__always_inline__));
static bool JSVALUE_TO_BOOL(EncodedJSValue val) __attribute__((__always_inline__));
static bool JSVALUE_IS_CELL(EncodedJSValue val) {
return !(val.asInt64 & NotCellMask);
}
static bool JSVALUE_IS_INT32(EncodedJSValue val) {
return (val.asInt64 & NumberTag) == NumberTag;
}
static bool JSVALUE_IS_NUMBER(EncodedJSValue val) {
return val.asInt64 & NumberTag;
}
static void* JSVALUE_TO_PTR(EncodedJSValue val) {
// must be a double
return (void*)(val.asInt64 - DoubleEncodeOffset);
}
static EncodedJSValue PTR_TO_JSVALUE(void* ptr) {
EncodedJSValue val;
val.asInt64 = (int64_t)ptr + DoubleEncodeOffset;
return val;
}
static int32_t JSVALUE_TO_INT32(EncodedJSValue val) {
return val.asInt64;
}
static EncodedJSValue INT32_TO_JSVALUE(int32_t val) {
EncodedJSValue res;
res.asInt64 = NumberTag | (uint32_t)val;
return res;
}
static EncodedJSValue DOUBLE_TO_JSVALUE(double val) {
EncodedJSValue res;
res.asDouble = val;
res.asInt64 += DoubleEncodeOffset;
return res;
}
static EncodedJSValue FLOAT_TO_JSVALUE(float val) {
return DOUBLE_TO_JSVALUE((double)val);
}
static EncodedJSValue BOOLEAN_TO_JSVALUE(bool val) {
EncodedJSValue res;
res.asInt64 = val ? TagValueTrue : TagValueFalse;
return res;
}
static double JSVALUE_TO_DOUBLE(EncodedJSValue val) {
val.asInt64 -= DoubleEncodeOffset;
return val.asDouble;
}
static float JSVALUE_TO_FLOAT(EncodedJSValue val) {
return (float)JSVALUE_TO_DOUBLE(val);
}
static bool JSVALUE_TO_BOOL(EncodedJSValue val) {
return val.asInt64 == TagValueTrue;
}
static uint64_t JSVALUE_TO_UINT64(void* globalObject, EncodedJSValue value) {
if (JSVALUE_IS_INT32(value)) {
return (uint64_t)JSVALUE_TO_INT32(value);
}
if (JSVALUE_IS_NUMBER(value)) {
return (uint64_t)JSVALUE_TO_DOUBLE(value);
}
return JSVALUE_TO_UINT64_SLOW(globalObject, value);
}
static int64_t JSVALUE_TO_INT64(EncodedJSValue value) {
if (JSVALUE_IS_INT32(value)) {
return (int64_t)JSVALUE_TO_INT32(value);
}
if (JSVALUE_IS_NUMBER(value)) {
return (int64_t)JSVALUE_TO_DOUBLE(value);
}
return JSVALUE_TO_INT64_SLOW(value);
}
static EncodedJSValue UINT64_TO_JSVALUE(void* globalObject, uint64_t val) {
if (val < MAX_INT32) {
return INT32_TO_JSVALUE((int32_t)val);
}
if (val < MAX_INT52) {
return DOUBLE_TO_JSVALUE((double)val);
}
return UINT64_TO_JSVALUE_SLOW(globalObject, val);
}
static EncodedJSValue INT64_TO_JSVALUE(void* globalObject, int64_t val) {
if (val >= -MAX_INT32 && val <= MAX_INT32) {
return INT32_TO_JSVALUE((int32_t)val);
}
if (val >= -MAX_INT52 && val <= MAX_INT52) {
return DOUBLE_TO_JSVALUE((double)val);
}
return INT64_TO_JSVALUE_SLOW(globalObject, val);
}
#ifndef IS_CALLBACK
void* JSFunctionCall(void* globalObject, void* callFrame);
#endif
// --- Generated Code ---
/* --- The Function To Call */
float not_a_callback(float arg0);
/* ---- Your Wrapper Function ---- */
void* JSFunctionCall(void* globalObject, void* callFrame) {
LOAD_ARGUMENTS_FROM_CALL_FRAME;
EncodedJSValue arg0;
arg0.asInt64 = *argsPtr;
float return_value = not_a_callback( JSVALUE_TO_FLOAT(arg0));
return FLOAT_TO_JSVALUE(return_value).asPtr;
}

543
test/bun.js/ffi.test.js Normal file
View File

@@ -0,0 +1,543 @@
// import { describe, it, expect } from "bun:test";
// import { unsafe } from "bun";
// //
// import {
// native,
// viewSource,
// dlopen,
// CString,
// ptr,
// toBuffer,
// toArrayBuffer,
// FFIType,
// callback,
// CFunction,
// } from "bun:ffi";
// it("ffi print", async () => {
// await Bun.write(
// import.meta.dir + "/ffi.test.fixture.callback.c",
// viewSource(
// {
// returns: "bool",
// args: ["ptr"],
// },
// true
// )
// );
// await Bun.write(
// import.meta.dir + "/ffi.test.fixture.receiver.c",
// viewSource(
// {
// not_a_callback: {
// returns: "float",
// args: ["float"],
// },
// },
// false
// )[0]
// );
// expect(
// viewSource(
// {
// returns: "int8_t",
// args: [],
// },
// true
// ).length > 0
// ).toBe(true);
// expect(
// viewSource(
// {
// a: {
// returns: "int8_t",
// args: [],
// },
// },
// false
// ).length > 0
// ).toBe(true);
// });
// function getTypes(fast) {
// const int64_t = fast ? "i64_fast" : "int64_t";
// const uint64_t = fast ? "u64_fast" : "uint64_t";
// return {
// returns_true: {
// returns: "bool",
// args: [],
// },
// returns_false: {
// returns: "bool",
// args: [],
// },
// returns_42_char: {
// returns: "char",
// args: [],
// },
// returns_42_float: {
// returns: "float",
// args: [],
// },
// returns_42_double: {
// returns: "double",
// args: [],
// },
// returns_42_uint8_t: {
// returns: "uint8_t",
// args: [],
// },
// returns_neg_42_int8_t: {
// returns: "int8_t",
// args: [],
// },
// returns_42_uint16_t: {
// returns: "uint16_t",
// args: [],
// },
// returns_42_uint32_t: {
// returns: "uint32_t",
// args: [],
// },
// returns_42_uint64_t: {
// returns: uint64_t,
// args: [],
// },
// returns_neg_42_int16_t: {
// returns: "int16_t",
// args: [],
// },
// returns_neg_42_int32_t: {
// returns: "int32_t",
// args: [],
// },
// returns_neg_42_int64_t: {
// returns: int64_t,
// args: [],
// },
// identity_char: {
// returns: "char",
// args: ["char"],
// },
// identity_float: {
// returns: "float",
// args: ["float"],
// },
// identity_bool: {
// returns: "bool",
// args: ["bool"],
// },
// identity_double: {
// returns: "double",
// args: ["double"],
// },
// identity_int8_t: {
// returns: "int8_t",
// args: ["int8_t"],
// },
// identity_int16_t: {
// returns: "int16_t",
// args: ["int16_t"],
// },
// identity_int32_t: {
// returns: "int32_t",
// args: ["int32_t"],
// },
// identity_int64_t: {
// returns: int64_t,
// args: [int64_t],
// },
// identity_uint8_t: {
// returns: "uint8_t",
// args: ["uint8_t"],
// },
// identity_uint16_t: {
// returns: "uint16_t",
// args: ["uint16_t"],
// },
// identity_uint32_t: {
// returns: "uint32_t",
// args: ["uint32_t"],
// },
// identity_uint64_t: {
// returns: uint64_t,
// args: [uint64_t],
// },
// add_char: {
// returns: "char",
// args: ["char", "char"],
// },
// add_float: {
// returns: "float",
// args: ["float", "float"],
// },
// add_double: {
// returns: "double",
// args: ["double", "double"],
// },
// add_int8_t: {
// returns: "int8_t",
// args: ["int8_t", "int8_t"],
// },
// add_int16_t: {
// returns: "int16_t",
// args: ["int16_t", "int16_t"],
// },
// add_int32_t: {
// returns: "int32_t",
// args: ["int32_t", "int32_t"],
// },
// add_int64_t: {
// returns: int64_t,
// args: [int64_t, int64_t],
// },
// add_uint8_t: {
// returns: "uint8_t",
// args: ["uint8_t", "uint8_t"],
// },
// add_uint16_t: {
// returns: "uint16_t",
// args: ["uint16_t", "uint16_t"],
// },
// add_uint32_t: {
// returns: "uint32_t",
// args: ["uint32_t", "uint32_t"],
// },
// does_pointer_equal_42_as_int32_t: {
// returns: "bool",
// args: ["ptr"],
// },
// ptr_should_point_to_42_as_int32_t: {
// returns: "ptr",
// args: [],
// },
// identity_ptr: {
// returns: "ptr",
// args: ["ptr"],
// },
// add_uint64_t: {
// returns: uint64_t,
// args: [uint64_t, uint64_t],
// },
// cb_identity_true: {
// returns: "bool",
// args: ["ptr"],
// },
// cb_identity_false: {
// returns: "bool",
// args: ["ptr"],
// },
// cb_identity_42_char: {
// returns: "char",
// args: ["ptr"],
// },
// cb_identity_42_float: {
// returns: "float",
// args: ["ptr"],
// },
// cb_identity_42_double: {
// returns: "double",
// args: ["ptr"],
// },
// cb_identity_42_uint8_t: {
// returns: "uint8_t",
// args: ["ptr"],
// },
// cb_identity_neg_42_int8_t: {
// returns: "int8_t",
// args: ["ptr"],
// },
// cb_identity_42_uint16_t: {
// returns: "uint16_t",
// args: ["ptr"],
// },
// cb_identity_42_uint32_t: {
// returns: "uint32_t",
// args: ["ptr"],
// },
// cb_identity_42_uint64_t: {
// returns: uint64_t,
// args: ["ptr"],
// },
// cb_identity_neg_42_int16_t: {
// returns: "int16_t",
// args: ["ptr"],
// },
// cb_identity_neg_42_int32_t: {
// returns: "int32_t",
// args: ["ptr"],
// },
// cb_identity_neg_42_int64_t: {
// returns: int64_t,
// args: ["ptr"],
// },
// return_a_function_ptr_to_function_that_returns_true: {
// returns: "ptr",
// args: [],
// },
// };
// }
// function ffiRunner(types) {
// const {
// symbols: {
// returns_true,
// returns_false,
// return_a_function_ptr_to_function_that_returns_true,
// returns_42_char,
// returns_42_float,
// returns_42_double,
// returns_42_uint8_t,
// returns_neg_42_int8_t,
// returns_42_uint16_t,
// returns_42_uint32_t,
// returns_42_uint64_t,
// returns_neg_42_int16_t,
// returns_neg_42_int32_t,
// returns_neg_42_int64_t,
// identity_char,
// identity_float,
// identity_bool,
// identity_double,
// identity_int8_t,
// identity_int16_t,
// identity_int32_t,
// identity_int64_t,
// identity_uint8_t,
// identity_uint16_t,
// identity_uint32_t,
// identity_uint64_t,
// add_char,
// add_float,
// add_double,
// add_int8_t,
// add_int16_t,
// add_int32_t,
// add_int64_t,
// add_uint8_t,
// add_uint16_t,
// identity_ptr,
// add_uint32_t,
// add_uint64_t,
// does_pointer_equal_42_as_int32_t,
// ptr_should_point_to_42_as_int32_t,
// cb_identity_true,
// cb_identity_false,
// cb_identity_42_char,
// cb_identity_42_float,
// cb_identity_42_double,
// cb_identity_42_uint8_t,
// cb_identity_neg_42_int8_t,
// cb_identity_42_uint16_t,
// cb_identity_42_uint32_t,
// cb_identity_42_uint64_t,
// cb_identity_neg_42_int16_t,
// cb_identity_neg_42_int32_t,
// cb_identity_neg_42_int64_t,
// },
// close,
// } = dlopen("/tmp/bun-ffi-test.dylib", types);
// expect(returns_true()).toBe(true);
// expect(returns_false()).toBe(false);
// expect(returns_42_char()).toBe(42);
// console.log(
// returns_42_uint64_t().valueOf(),
// returns_42_uint64_t(),
// returns_42_uint64_t().valueOf() === returns_42_uint64_t()
// );
// expect(returns_42_uint64_t().valueOf()).toBe(42);
// expect(Math.fround(returns_42_float())).toBe(Math.fround(42.41999804973602));
// expect(returns_42_double()).toBe(42.42);
// expect(returns_42_uint8_t()).toBe(42);
// expect(returns_neg_42_int8_t()).toBe(-42);
// expect(returns_42_uint16_t()).toBe(42);
// expect(returns_42_uint32_t()).toBe(42);
// expect(returns_42_uint64_t()).toBe(42);
// expect(returns_neg_42_int16_t()).toBe(-42);
// expect(returns_neg_42_int32_t()).toBe(-42);
// expect(identity_int32_t(10)).toBe(10);
// expect(returns_neg_42_int64_t()).toBe(-42);
// expect(identity_char(10)).toBe(10);
// expect(identity_float(10.199999809265137)).toBe(10.199999809265137);
// expect(identity_bool(true)).toBe(true);
// expect(identity_bool(false)).toBe(false);
// expect(identity_double(10.100000000000364)).toBe(10.100000000000364);
// expect(identity_int8_t(10)).toBe(10);
// expect(identity_int16_t(10)).toBe(10);
// expect(identity_int64_t(10)).toBe(10);
// expect(identity_uint8_t(10)).toBe(10);
// expect(identity_uint16_t(10)).toBe(10);
// expect(identity_uint32_t(10)).toBe(10);
// expect(identity_uint64_t(10)).toBe(10);
// var bigArray = new BigUint64Array(8);
// new Uint8Array(bigArray.buffer).fill(255);
// var bigIntArray = new BigInt64Array(bigArray.buffer);
// expect(identity_uint64_t(bigArray[0])).toBe(bigArray[0]);
// expect(identity_uint64_t(bigArray[0] - BigInt(1))).toBe(
// bigArray[0] - BigInt(1)
// );
// expect(add_uint64_t(BigInt(-1) * bigArray[0], bigArray[0])).toBe(0);
// expect(add_uint64_t(BigInt(-1) * bigArray[0] + BigInt(10), bigArray[0])).toBe(
// 10
// );
// expect(identity_uint64_t(0)).toBe(0);
// expect(identity_uint64_t(100)).toBe(100);
// expect(identity_uint64_t(BigInt(100))).toBe(100);
// expect(identity_int64_t(bigIntArray[0])).toBe(bigIntArray[0]);
// expect(identity_int64_t(bigIntArray[0] - BigInt(1))).toBe(
// bigIntArray[0] - BigInt(1)
// );
// expect(add_char(1, 1)).toBe(2);
// expect(add_float(2.4, 2.8)).toBe(Math.fround(5.2));
// expect(add_double(4.2, 0.1)).toBe(4.3);
// expect(add_int8_t(1, 1)).toBe(2);
// expect(add_int16_t(1, 1)).toBe(2);
// expect(add_int32_t(1, 1)).toBe(2);
// expect(add_int64_t(1, 1)).toBe(2);
// expect(add_uint8_t(1, 1)).toBe(2);
// expect(add_uint16_t(1, 1)).toBe(2);
// expect(add_uint32_t(1, 1)).toBe(2);
// const cptr = ptr_should_point_to_42_as_int32_t();
// expect(cptr != 0).toBe(true);
// expect(typeof cptr === "number").toBe(true);
// expect(does_pointer_equal_42_as_int32_t(cptr)).toBe(true);
// const buffer = toBuffer(cptr, 0, 4);
// expect(buffer.readInt32(0)).toBe(42);
// expect(new DataView(toArrayBuffer(cptr, 0, 4), 0, 4).getInt32(0, true)).toBe(
// 42
// );
// expect(ptr(buffer)).toBe(cptr);
// expect(new CString(cptr, 0, 1).toString()).toBe("*");
// expect(identity_ptr(cptr)).toBe(cptr);
// const second_ptr = ptr(new Buffer(8));
// expect(identity_ptr(second_ptr)).toBe(second_ptr);
// var myCFunction = new CFunction({
// ptr: return_a_function_ptr_to_function_that_returns_true(),
// returns: "bool",
// });
// expect(myCFunction()).toBe(true);
// // function identityBool() {
// // return true;
// // }
// // globalThis.identityBool = identityBool;
// // const first = native.callback(
// // {
// // returns: "bool",
// // },
// // identityBool
// // );
// // expect(
// // cb_identity_true()
// // ).toBe(true);
// // expect(cb_identity_true(first)).toBe(true);
// // expect(
// // cb_identity_false(
// // callback(
// // {
// // returns: "bool",
// // },
// // () => false
// // )
// // )
// // ).toBe(false);
// // expect(
// // cb_identity_42_char(
// // callback(
// // {
// // returns: "char",
// // },
// // () => 42
// // )
// // )
// // ).toBe(42);
// // expect(
// // cb_identity_42_uint8_t(
// // callback(
// // {
// // returns: "uint8_t",
// // },
// // () => 42
// // )
// // )
// // ).toBe(42);
// // cb_identity_neg_42_int8_t(
// // callback(
// // {
// // returns: "int8_t",
// // },
// // () => -42
// // )
// // ).toBe(-42);
// // cb_identity_42_uint16_t(
// // callback(
// // {
// // returns: "uint16_t",
// // },
// // () => 42
// // )
// // ).toBe(42);
// // cb_identity_42_uint32_t(
// // callback(
// // {
// // returns: "uint32_t",
// // },
// // () => 42
// // )
// // ).toBe(42);
// // cb_identity_neg_42_int16_t(
// // callback(
// // {
// // returns: "int16_t",
// // },
// // () => -42
// // )
// // ).toBe(-42);
// // cb_identity_neg_42_int32_t(
// // callback(
// // {
// // returns: "int32_t",
// // },
// // () => -42
// // )
// // ).toBe(-42);
// close();
// }
// it("run ffi fast", () => {
// ffiRunner(getTypes(true));
// });
// it("run ffi", () => {
// ffiRunner(getTypes(false));
// });

23
test/bun.js/fs-stream.js Normal file
View File

@@ -0,0 +1,23 @@
import { createReadStream, createWriteStream, readFileSync } from "fs";
await new Promise((resolve, reject) => {
createReadStream("fs-stream.js")
.pipe(createWriteStream("/tmp/fs-stream.copy.js"))
.once("error", (err) => reject(err))
.once("finish", () => {
try {
const copied = readFileSync("/tmp/fs-stream.copy.js", "utf8");
const real = readFileSync("/tmp/fs-stream.js", "utf8");
if (copied !== real) {
reject(
new Error("fs-stream.js is not the same as fs-stream.copy.js")
);
return;
}
resolve(true);
} catch (err) {
reject(err);
}
});
});

244
test/bun.js/fs.test.js Normal file
View File

@@ -0,0 +1,244 @@
import { gc } from "bun";
import { describe, expect, it } from "bun:test";
import {
closeSync,
existsSync,
mkdirSync,
openSync,
readdirSync,
readFile,
readFileSync,
readSync,
writeFileSync,
writeSync,
} from "node:fs";
const Buffer = globalThis.Buffer || Uint8Array;
if (!import.meta.dir) {
import.meta.dir = ".";
}
describe("mkdirSync", () => {
it("should create a directory", () => {
const tempdir = `/tmp/fs.test.js/${Date.now()}/1234/hi`;
expect(existsSync(tempdir)).toBe(false);
expect(tempdir.includes(mkdirSync(tempdir, { recursive: true }))).toBe(
true
);
expect(existsSync(tempdir)).toBe(true);
});
});
it("readdirSync on import.meta.dir", () => {
const dirs = readdirSync(import.meta.dir);
expect(dirs.length > 0).toBe(true);
var match = false;
gc(true);
for (let i = 0; i < dirs.length; i++) {
if (dirs[i] === import.meta.file) {
match = true;
}
}
gc(true);
expect(match).toBe(true);
});
it("readdirSync on import.meta.dir with trailing slash", () => {
const dirs = readdirSync(import.meta.dir + "/");
expect(dirs.length > 0).toBe(true);
// this file should exist in it
var match = false;
for (let i = 0; i < dirs.length; i++) {
if (dirs[i] === import.meta.file) {
match = true;
}
}
expect(match).toBe(true);
});
it("readdirSync works on empty directories", () => {
const path = `/tmp/fs-test-empty-dir-${(
Math.random() * 100000 +
100
).toString(32)}`;
mkdirSync(path, { recursive: true });
expect(readdirSync(path).length).toBe(0);
});
it("readdirSync works on directories with under 32 files", () => {
const path = `/tmp/fs-test-one-dir-${(Math.random() * 100000 + 100).toString(
32
)}`;
mkdirSync(path, { recursive: true });
writeFileSync(`${path}/a`, "a");
const results = readdirSync(path);
expect(results.length).toBe(1);
expect(results[0]).toBe("a");
});
it("readdirSync throws when given a file path", () => {
try {
readdirSync(import.meta.path);
throw new Error("should not get here");
} catch (exception) {
expect(exception.name).toBe("ENOTDIR");
}
});
it("readdirSync throws when given a path that doesn't exist", () => {
try {
readdirSync(import.meta.path + "/does-not-exist/really");
throw new Error("should not get here");
} catch (exception) {
expect(exception.name).toBe("ENOTDIR");
}
});
it("readdirSync throws when given a file path with trailing slash", () => {
try {
readdirSync(import.meta.path + "/");
throw new Error("should not get here");
} catch (exception) {
expect(exception.name).toBe("ENOTDIR");
}
});
describe("readSync", () => {
const firstFourBytes = new Uint32Array(
new TextEncoder().encode("File").buffer
)[0];
it("works with a position set to 0", () => {
const fd = openSync(import.meta.dir + "/readFileSync.txt", "r");
const four = new Uint8Array(4);
{
const count = readSync(fd, four, 0, 4, 0);
const u32 = new Uint32Array(four.buffer)[0];
expect(u32).toBe(firstFourBytes);
expect(count).toBe(4);
}
closeSync(fd);
});
it("works without position set", () => {
const fd = openSync(import.meta.dir + "/readFileSync.txt", "r");
const four = new Uint8Array(4);
{
const count = readSync(fd, four);
const u32 = new Uint32Array(four.buffer)[0];
expect(u32).toBe(firstFourBytes);
expect(count).toBe(4);
}
closeSync(fd);
});
});
describe("writeSync", () => {
it("works with a position set to 0", () => {
const fd = openSync(import.meta.dir + "/writeFileSync.txt", "w+");
const four = new Uint8Array(4);
{
const count = writeSync(fd, new TextEncoder().encode("File"), 0, 4, 0);
expect(count).toBe(4);
}
closeSync(fd);
});
it("works without position set", () => {
const fd = openSync(import.meta.dir + "/writeFileSync.txt", "w+");
const four = new Uint8Array(4);
{
const count = writeSync(fd, new TextEncoder().encode("File"));
expect(count).toBe(4);
}
closeSync(fd);
});
});
describe("readFileSync", () => {
it("works", () => {
const text = readFileSync(import.meta.dir + "/readFileSync.txt", "utf8");
expect(text).toBe("File read successfully");
});
it("works with a file url", () => {
const text = readFileSync(
new URL("file://" + import.meta.dir + "/readFileSync.txt"),
"utf8"
);
expect(text).toBe("File read successfully");
});
it("returning Buffer works", () => {
const text = readFileSync(import.meta.dir + "/readFileSync.txt");
const encoded = [
70, 105, 108, 101, 32, 114, 101, 97, 100, 32, 115, 117, 99, 99, 101, 115,
115, 102, 117, 108, 108, 121,
];
for (let i = 0; i < encoded.length; i++) {
expect(text[i]).toBe(encoded[i]);
}
});
});
describe("readFile", () => {
it("works", async () => {
await new Promise((resolve, reject) => {
readFile(import.meta.dir + "/readFileSync.txt", "utf8", (err, text) => {
expect(text).toBe("File read successfully");
resolve(true);
});
});
});
it("returning Buffer works", async () => {
await new Promise((resolve, reject) => {
readFile(import.meta.dir + "/readFileSync.txt", (err, text) => {
const encoded = [
70, 105, 108, 101, 32, 114, 101, 97, 100, 32, 115, 117, 99, 99, 101,
115, 115, 102, 117, 108, 108, 121,
];
for (let i = 0; i < encoded.length; i++) {
expect(text[i]).toBe(encoded[i]);
}
resolve(true);
});
});
});
});
describe("writeFileSync", () => {
it("works", () => {
const path = `/tmp/${Date.now()}.writeFileSync.txt`;
writeFileSync(path, "File written successfully", "utf8");
expect(readFileSync(path, "utf8")).toBe("File written successfully");
});
it("returning Buffer works", () => {
const buffer = new Buffer([
70, 105, 108, 101, 32, 119, 114, 105, 116, 116, 101, 110, 32, 115, 117,
99, 99, 101, 115, 115, 102, 117, 108, 108, 121,
]);
const path = `/tmp/${Date.now()}.blob.writeFileSync.txt`;
writeFileSync(path, buffer);
const out = readFileSync(path);
for (let i = 0; i < buffer.length; i++) {
expect(buffer[i]).toBe(out[i]);
}
});
it("returning ArrayBuffer works", () => {
const buffer = new Buffer([
70, 105, 108, 101, 32, 119, 114, 105, 116, 116, 101, 110, 32, 115, 117,
99, 99, 101, 115, 115, 102, 117, 108, 108, 121,
]);
const path = `/tmp/${Date.now()}.blob2.writeFileSync.txt`;
writeFileSync(path, buffer);
const out = readFileSync(path);
for (let i = 0; i < buffer.length; i++) {
expect(buffer[i]).toBe(out[i]);
}
});
});

15
test/bun.js/gc.js Normal file
View File

@@ -0,0 +1,15 @@
export function gc() {
// console.trace("GC");
Bun.gc(true);
}
// we must ensure that finalizers are run
// so that the reference-counting logic is exercised
export function gcTick(trace = false) {
trace && console.trace("");
// console.trace("hello");
gc();
return new Promise((resolve) => {
setTimeout(resolve, 0);
});
}

View File

@@ -0,0 +1,39 @@
import { it, describe, expect } from "bun:test";
it("extendable", () => {
const classes = [
Blob,
TextDecoder,
TextEncoder,
Request,
Response,
Headers,
HTMLRewriter,
Bun.Transpiler,
];
// None of these should error
for (let Class of classes) {
var Foo = class extends Class {};
var bar = new Foo();
expect(bar instanceof Class).toBe(true);
expect(!!Class.prototype).toBe(true);
expect(typeof Class.prototype).toBe("object");
}
expect(true).toBe(true);
});
it("name", () => {
const classes = [
["Blob", Blob],
["TextDecoder", TextDecoder],
["TextEncoder", TextEncoder],
["Request", Request],
["Response", Response],
["Headers", Headers],
["HTMLRewriter", HTMLRewriter],
["Transpiler", Bun.Transpiler],
];
for (let [name, Class] of classes) {
expect(Class.name).toBe(name);
}
});

36
test/bun.js/hash.test.js Normal file
View File

@@ -0,0 +1,36 @@
import fs from "fs";
import { it, expect } from "bun:test";
import path from "path";
it(`Bun.hash()`, () => {
Bun.hash("hello world");
Bun.hash(new TextEncoder().encode("hello world"));
});
it(`Bun.hash.wyhash()`, () => {
Bun.hash.wyhash("hello world");
Bun.hash.wyhash(new TextEncoder().encode("hello world"));
});
it(`Bun.hash.adler32()`, () => {
Bun.hash.adler32("hello world");
Bun.hash.adler32(new TextEncoder().encode("hello world"));
});
it(`Bun.hash.crc32()`, () => {
Bun.hash.crc32("hello world");
Bun.hash.crc32(new TextEncoder().encode("hello world"));
});
it(`Bun.hash.cityHash32()`, () => {
Bun.hash.cityHash32("hello world");
Bun.hash.cityHash32(new TextEncoder().encode("hello world"));
});
it(`Bun.hash.cityHash64()`, () => {
Bun.hash.cityHash64("hello world");
Bun.hash.cityHash64(new TextEncoder().encode("hello world"));
});
it(`Bun.hash.murmur32v3()`, () => {
Bun.hash.murmur32v3("hello world");
Bun.hash.murmur32v3(new TextEncoder().encode("hello world"));
});
it(`Bun.hash.murmur64v2()`, () => {
Bun.hash.murmur64v2("hello world");
Bun.hash.murmur64v2(new TextEncoder().encode("hello world"));
});

View File

@@ -0,0 +1,293 @@
import { describe, it, expect } from "bun:test";
import { gcTick } from "./gc";
var setTimeoutAsync = (fn, delay) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
try {
resolve(fn());
} catch (e) {
reject(e);
}
}, delay);
});
};
describe("HTMLRewriter", () => {
it("HTMLRewriter: async replacement", async () => {
await gcTick();
const res = new HTMLRewriter()
.on("div", {
async element(element) {
await setTimeoutAsync(() => {
element.setInnerContent("<span>replace</span>", { html: true });
}, 5);
},
})
.transform(new Response("<div>example.com</div>"));
await gcTick();
expect(await res.text()).toBe("<div><span>replace</span></div>");
await gcTick();
});
it("supports element handlers", async () => {
var rewriter = new HTMLRewriter();
rewriter.on("div", {
element(element) {
element.setInnerContent("<blink>it worked!</blink>", { html: true });
},
});
var input = new Response("<div>hello</div>");
var output = rewriter.transform(input);
expect(await output.text()).toBe("<div><blink>it worked!</blink></div>");
});
it("(from file) supports element handlers", async () => {
var rewriter = new HTMLRewriter();
rewriter.on("div", {
element(element) {
element.setInnerContent("<blink>it worked!</blink>", { html: true });
},
});
await Bun.write("/tmp/html-rewriter.txt.js", "<div>hello</div>");
var input = new Response(Bun.file("/tmp/html-rewriter.txt.js"));
var output = rewriter.transform(input);
expect(await output.text()).toBe("<div><blink>it worked!</blink></div>");
});
it("supports attribute iterator", async () => {
var rewriter = new HTMLRewriter();
var expected = [
["first", ""],
["second", "alrihgt"],
["third", "123"],
["fourth", "5"],
["fifth", "helloooo"],
];
rewriter.on("div", {
element(element2) {
for (let attr of element2.attributes) {
const stack = expected.shift();
expect(stack[0]).toBe(attr[0]);
expect(stack[1]).toBe(attr[1]);
}
},
});
var input = new Response(
'<div first second="alrihgt" third="123" fourth=5 fifth=helloooo>hello</div>'
);
var output = rewriter.transform(input);
expect(await output.text()).toBe(
'<div first second="alrihgt" third="123" fourth=5 fifth=helloooo>hello</div>'
);
expect(expected.length).toBe(0);
});
it("handles element specific mutations", async () => {
// prepend/append
let res = new HTMLRewriter()
.on("p", {
element(element) {
element.prepend("<span>prepend</span>");
element.prepend("<span>prepend html</span>", { html: true });
element.append("<span>append</span>");
element.append("<span>append html</span>", { html: true });
},
})
.transform(new Response("<p>test</p>"));
expect(await res.text()).toBe(
[
"<p>",
"<span>prepend html</span>",
"&lt;span&gt;prepend&lt;/span&gt;",
"test",
"&lt;span&gt;append&lt;/span&gt;",
"<span>append html</span>",
"</p>",
].join("")
);
// setInnerContent
res = new HTMLRewriter()
.on("p", {
element(element) {
element.setInnerContent("<span>replace</span>");
},
})
.transform(new Response("<p>test</p>"));
expect(await res.text()).toBe("<p>&lt;span&gt;replace&lt;/span&gt;</p>");
res = new HTMLRewriter()
.on("p", {
element(element) {
element.setInnerContent("<span>replace</span>", { html: true });
},
})
.transform(new Response("<p>test</p>"));
expect(await res.text()).toBe("<p><span>replace</span></p>");
// removeAndKeepContent
res = new HTMLRewriter()
.on("p", {
element(element) {
element.removeAndKeepContent();
},
})
.transform(new Response("<p>test</p>"));
expect(await res.text()).toBe("test");
});
it("handles element class properties", async () => {
class Handler {
constructor(content) {
this.content = content;
}
// noinspection JSUnusedGlobalSymbols
element(element) {
element.setInnerContent(this.content);
}
}
const res = new HTMLRewriter()
.on("p", new Handler("new"))
.transform(new Response("<p>test</p>"));
expect(await res.text()).toBe("<p>new</p>");
});
const commentsMutationsInput = "<p><!--test--></p>";
const commentsMutationsExpected = {
beforeAfter: [
"<p>",
"&lt;span&gt;before&lt;/span&gt;",
"<span>before html</span>",
"<!--test-->",
"<span>after html</span>",
"&lt;span&gt;after&lt;/span&gt;",
"</p>",
].join(""),
replace: "<p>&lt;span&gt;replace&lt;/span&gt;</p>",
replaceHtml: "<p><span>replace</span></p>",
remove: "<p></p>",
};
const commentPropertiesMacro = async (func) => {
const res = func(new HTMLRewriter(), (comment) => {
expect(comment.removed).toBe(false);
expect(comment.text).toBe("test");
comment.text = "new";
expect(comment.text).toBe("new");
}).transform(new Response("<p><!--test--></p>"));
expect(await res.text()).toBe("<p><!--new--></p>");
};
it("HTMLRewriter: handles comment properties", () =>
commentPropertiesMacro((rw, comments) => {
rw.on("p", { comments });
return rw;
}));
it("selector tests", async () => {
const checkSelector = async (selector, input, expected) => {
const res = new HTMLRewriter()
.on(selector, {
element(element) {
element.setInnerContent("new");
},
})
.transform(new Response(input));
expect(await res.text()).toBe(expected);
};
await checkSelector("*", "<h1>1</h1><p>2</p>", "<h1>new</h1><p>new</p>");
await checkSelector("p", "<h1>1</h1><p>2</p>", "<h1>1</h1><p>new</p>");
await checkSelector(
"p:nth-child(2)",
"<div><p>1</p><p>2</p><p>3</p></div>",
"<div><p>1</p><p>new</p><p>3</p></div>"
);
await checkSelector(
"p:first-child",
"<div><p>1</p><p>2</p><p>3</p></div>",
"<div><p>new</p><p>2</p><p>3</p></div>"
);
await checkSelector(
"p:nth-of-type(2)",
"<div><p>1</p><h1>2</h1><p>3</p><h1>4</h1><p>5</p></div>",
"<div><p>1</p><h1>2</h1><p>new</p><h1>4</h1><p>5</p></div>"
);
await checkSelector(
"p:first-of-type",
"<div><h1>1</h1><p>2</p><p>3</p></div>",
"<div><h1>1</h1><p>new</p><p>3</p></div>"
);
await checkSelector(
"p:not(:first-child)",
"<div><p>1</p><p>2</p><p>3</p></div>",
"<div><p>1</p><p>new</p><p>new</p></div>"
);
await checkSelector(
"p.red",
'<p class="red">1</p><p>2</p>',
'<p class="red">new</p><p>2</p>'
);
await checkSelector(
"h1#header",
'<h1 id="header">1</h1><h1>2</h1>',
'<h1 id="header">new</h1><h1>2</h1>'
);
await checkSelector(
"p[data-test]",
"<p data-test>1</p><p>2</p>",
"<p data-test>new</p><p>2</p>"
);
await checkSelector(
'p[data-test="one"]',
'<p data-test="one">1</p><p data-test="two">2</p>',
'<p data-test="one">new</p><p data-test="two">2</p>'
);
await checkSelector(
'p[data-test="one" i]',
'<p data-test="one">1</p><p data-test="OnE">2</p><p data-test="two">3</p>',
'<p data-test="one">new</p><p data-test="OnE">new</p><p data-test="two">3</p>'
);
await checkSelector(
'p[data-test="one" s]',
'<p data-test="one">1</p><p data-test="OnE">2</p><p data-test="two">3</p>',
'<p data-test="one">new</p><p data-test="OnE">2</p><p data-test="two">3</p>'
);
await checkSelector(
'p[data-test~="two"]',
'<p data-test="one two three">1</p><p data-test="one two">2</p><p data-test="one">3</p>',
'<p data-test="one two three">new</p><p data-test="one two">new</p><p data-test="one">3</p>'
);
await checkSelector(
'p[data-test^="a"]',
'<p data-test="a1">1</p><p data-test="a2">2</p><p data-test="b1">3</p>',
'<p data-test="a1">new</p><p data-test="a2">new</p><p data-test="b1">3</p>'
);
await checkSelector(
'p[data-test$="1"]',
'<p data-test="a1">1</p><p data-test="a2">2</p><p data-test="b1">3</p>',
'<p data-test="a1">new</p><p data-test="a2">2</p><p data-test="b1">new</p>'
);
await checkSelector(
'p[data-test*="b"]',
'<p data-test="abc">1</p><p data-test="ab">2</p><p data-test="a">3</p>',
'<p data-test="abc">new</p><p data-test="ab">new</p><p data-test="a">3</p>'
);
await checkSelector(
'p[data-test|="a"]',
'<p data-test="a">1</p><p data-test="a-1">2</p><p data-test="a2">3</p>',
'<p data-test="a">new</p><p data-test="a-1">new</p><p data-test="a2">3</p>'
);
await checkSelector(
"div span",
"<div><h1><span>1</span></h1><span>2</span><b>3</b></div>",
"<div><h1><span>new</span></h1><span>new</span><b>3</b></div>"
);
await checkSelector(
"div > span",
"<div><h1><span>1</span></h1><span>2</span><b>3</b></div>",
"<div><h1><span>1</span></h1><span>new</span><b>3</b></div>"
);
});
});

View File

@@ -0,0 +1,33 @@
import { it, expect } from "bun:test";
import * as Module from "node:module";
import sync from "./require-json.json";
const { path, dir } = import.meta;
it("import.meta.resolveSync", () => {
expect(
import.meta.resolveSync("./" + import.meta.file, import.meta.path)
).toBe(path);
const require = Module.createRequire(import.meta.path);
expect(require.resolve(import.meta.path)).toBe(path);
expect(require.resolve("./" + import.meta.file)).toBe(path);
// check it works with URL objects
expect(
Module.createRequire(new URL(import.meta.url)).resolve(import.meta.path)
).toBe(import.meta.path);
});
it("import.meta.require", () => {
expect(import.meta.require("./require-json.json").hello).toBe(sync.hello);
const require = Module.createRequire(import.meta.path);
expect(require("./require-json.json").hello).toBe(sync.hello);
});
it("import.meta.dir", () => {
expect(dir.endsWith("/bun/test/bun.js")).toBe(true);
});
it("import.meta.path", () => {
expect(path.endsWith("/bun/test/bun.js/import-meta.test.js")).toBe(true);
});

View File

@@ -0,0 +1,3 @@
export function whatDidIPass(expr, ctx) {
return ctx;
}

View File

@@ -0,0 +1,96 @@
import { it, expect } from "bun:test";
it("jsx with two elements", () => {
const input = Bun.inspect(
<div hello="quoted">
<input type="text" value={"123"} />
string inside child
</div>
);
const output = `<div hello="quoted">
<input type="text" value="123" />
string inside child
</div>`;
expect(input).toBe(output);
});
const Foo = () => <div hello="quoted">foo</div>;
it("jsx with anon component", () => {
const input = Bun.inspect(<Foo />);
const output = `<NoName />`;
expect(input).toBe(output);
});
it("jsx with fragment", () => {
const input = Bun.inspect(<>foo bar</>);
const output = `<>foo bar</>`;
expect(input).toBe(output);
});
it("inspect", () => {
expect(Bun.inspect(new TypeError("what")).includes("TypeError: what")).toBe(
true
);
expect("hi").toBe("hi");
expect(Bun.inspect(1)).toBe("1");
expect(Bun.inspect(1, "hi")).toBe("1 hi");
expect(Bun.inspect([])).toBe("[]");
expect(Bun.inspect({})).toBe("{ }");
expect(Bun.inspect({ hello: 1 })).toBe("{ hello: 1 }");
expect(Bun.inspect({ hello: 1, there: 2 })).toBe("{ hello: 1, there: 2 }");
expect(Bun.inspect({ hello: "1", there: 2 })).toBe(
'{ hello: "1", there: 2 }'
);
expect(Bun.inspect({ 'hello-"there': "1", there: 2 })).toBe(
'{ "hello-\\"there": "1", there: 2 }'
);
var str = "123";
while (str.length < 4096) {
str += "123";
}
expect(Bun.inspect(str)).toBe(str);
// expect(Bun.inspect(new Headers())).toBe("Headers (0 KB) {}");
expect(Bun.inspect(new Response()).length > 0).toBe(true);
// expect(
// JSON.stringify(
// new Headers({
// hi: "ok",
// })
// )
// ).toBe('{"hi":"ok"}');
expect(Bun.inspect(new Set())).toBe("Set {}");
expect(Bun.inspect(new Map())).toBe("Map {}");
expect(Bun.inspect(new Map([["foo", "bar"]]))).toBe(
'Map(1) {\n "foo": "bar",\n}'
);
expect(Bun.inspect(new Set(["bar"]))).toBe('Set(1) {\n "bar",\n}');
expect(Bun.inspect(<div>foo</div>)).toBe("<div>foo</div>");
expect(Bun.inspect(<div hello>foo</div>)).toBe("<div hello=true>foo</div>");
expect(Bun.inspect(<div hello={1}>foo</div>)).toBe("<div hello=1>foo</div>");
expect(Bun.inspect(<div hello={123}>hi</div>)).toBe(
"<div hello=123>hi</div>"
);
expect(Bun.inspect(<div hello="quoted">quoted</div>)).toBe(
'<div hello="quoted">quoted</div>'
);
expect(
Bun.inspect(
<div hello="quoted">
<input type="text" value={"123"} />
</div>
)
).toBe(
`
<div hello="quoted">
<input type="text" value="123" />
</div>`.trim()
);
expect(Bun.inspect(BigInt(32))).toBe("32n");
});

View File

@@ -0,0 +1,7 @@
export function keepSecondArgument(bacon1234) {
return bacon1234.arguments[1];
}
export function bacon(heloooo) {
return heloooo.arguments[1];
}

View File

@@ -0,0 +1,80 @@
import { it } from "bun:test";
it("queueMicrotask", async () => {
// You can verify this test is correct by copy pasting this into a browser's console and checking it doesn't throw an error.
var run = 0;
await new Promise((resolve, reject) => {
queueMicrotask(() => {
if (run++ != 0) {
reject(new Error("Microtask execution order is wrong: " + run));
}
queueMicrotask(() => {
if (run++ != 3) {
reject(new Error("Microtask execution order is wrong: " + run));
}
});
});
queueMicrotask(() => {
if (run++ != 1) {
reject(new Error("Microtask execution order is wrong: " + run));
}
queueMicrotask(() => {
if (run++ != 4) {
reject(new Error("Microtask execution order is wrong: " + run));
}
queueMicrotask(() => {
if (run++ != 6) {
reject(new Error("Microtask execution order is wrong: " + run));
}
});
});
});
queueMicrotask(() => {
if (run++ != 2) {
reject(new Error("Microtask execution order is wrong: " + run));
}
queueMicrotask(() => {
if (run++ != 5) {
reject(new Error("Microtask execution order is wrong: " + run));
}
queueMicrotask(() => {
if (run++ != 7) {
reject(new Error("Microtask execution order is wrong: " + run));
}
resolve(true);
});
});
});
});
{
var passed = false;
try {
queueMicrotask(1234);
} catch (exception) {
passed = exception instanceof TypeError;
}
if (!passed)
throw new Error(
"queueMicrotask should throw a TypeError if the argument is not a function"
);
}
{
var passed = false;
try {
queueMicrotask();
} catch (exception) {
passed = exception instanceof TypeError;
}
if (!passed)
throw new Error(
"queueMicrotask should throw a TypeError if the argument is empty"
);
}
});

69
test/bun.js/mmap.test.js Normal file
View File

@@ -0,0 +1,69 @@
import { describe, it, expect } from "bun:test";
import { gcTick } from "./gc";
describe("Bun.mmap", async () => {
await gcTick();
const path = `/tmp/bun-mmap-test_${Math.random()}.txt`;
await gcTick();
await Bun.write(path, "hello");
await gcTick();
it("mmap finalizer", async () => {
let map = Bun.mmap(path);
await gcTick();
const map2 = Bun.mmap(path);
map = null;
await gcTick();
});
it("mmap passed to other syscalls", async () => {
const map = Bun.mmap(path);
await gcTick();
await Bun.write(path + "1", map);
await gcTick();
const text = await (await Bun.file(path + "1")).text();
await gcTick();
expect(text).toBe(new TextDecoder().decode(map));
});
it("mmap sync", async () => {
const map = Bun.mmap(path);
await gcTick();
const map2 = Bun.mmap(path);
await gcTick();
const old = map[0];
await gcTick();
map[0] = 0;
await gcTick();
expect(map2[0]).toBe(0);
map2[0] = old;
await gcTick();
expect(map[0]).toBe(old);
await gcTick();
await Bun.write(path, "olleh");
await gcTick();
expect(new TextDecoder().decode(map)).toBe("olleh");
await gcTick();
});
it("mmap private", async () => {
await gcTick();
const map = Bun.mmap(path, { shared: true });
await gcTick();
const map2 = Bun.mmap(path, { shared: false });
await gcTick();
const old = map[0];
await gcTick();
map2[0] = 0;
await gcTick();
expect(map2[0]).toBe(0);
await gcTick();
expect(map[0]).toBe(old);
await gcTick();
});
});

View File

@@ -0,0 +1,16 @@
import { describe, it, expect } from "bun:test";
import { EventEmitter } from "events";
describe("EventEmitter", () => {
it("should emit events", () => {
const emitter = new EventEmitter();
var called = false;
const listener = () => {
called = true;
};
emitter.on("test", listener);
emitter.emit("test");
expect(called).toBe(true);
});
});

457
test/bun.js/path.test.js Normal file
View File

@@ -0,0 +1,457 @@
const { file } = import.meta;
import { describe, it, expect } from "bun:test";
import * as path from "node:path";
import assert from "assert";
const strictEqual = (...args) => {
assert.strictEqual(...args);
expect(true).toBe(true);
};
it("path.basename", () => {
strictEqual(path.basename(file), "path.test.js");
strictEqual(path.basename(file, ".js"), "path.test");
strictEqual(path.basename(".js", ".js"), "");
strictEqual(path.basename(""), "");
strictEqual(path.basename("/dir/basename.ext"), "basename.ext");
strictEqual(path.basename("/basename.ext"), "basename.ext");
strictEqual(path.basename("basename.ext"), "basename.ext");
strictEqual(path.basename("basename.ext/"), "basename.ext");
strictEqual(path.basename("basename.ext//"), "basename.ext");
strictEqual(path.basename("aaa/bbb", "/bbb"), "bbb");
strictEqual(path.basename("aaa/bbb", "a/bbb"), "bbb");
strictEqual(path.basename("aaa/bbb", "bbb"), "bbb");
strictEqual(path.basename("aaa/bbb//", "bbb"), "bbb");
strictEqual(path.basename("aaa/bbb", "bb"), "b");
strictEqual(path.basename("aaa/bbb", "b"), "bb");
strictEqual(path.basename("/aaa/bbb", "/bbb"), "bbb");
strictEqual(path.basename("/aaa/bbb", "a/bbb"), "bbb");
strictEqual(path.basename("/aaa/bbb", "bbb"), "bbb");
strictEqual(path.basename("/aaa/bbb//", "bbb"), "bbb");
strictEqual(path.basename("/aaa/bbb", "bb"), "b");
strictEqual(path.basename("/aaa/bbb", "b"), "bb");
strictEqual(path.basename("/aaa/bbb"), "bbb");
strictEqual(path.basename("/aaa/"), "aaa");
strictEqual(path.basename("/aaa/b"), "b");
strictEqual(path.basename("/a/b"), "b");
strictEqual(path.basename("//a"), "a");
strictEqual(path.basename("a", "a"), "");
// // On Windows a backslash acts as a path separator.
strictEqual(path.win32.basename("\\dir\\basename.ext"), "basename.ext");
strictEqual(path.win32.basename("\\basename.ext"), "basename.ext");
strictEqual(path.win32.basename("basename.ext"), "basename.ext");
strictEqual(path.win32.basename("basename.ext\\"), "basename.ext");
strictEqual(path.win32.basename("basename.ext\\\\"), "basename.ext");
strictEqual(path.win32.basename("foo"), "foo");
strictEqual(path.win32.basename("aaa\\bbb", "\\bbb"), "bbb");
strictEqual(path.win32.basename("aaa\\bbb", "a\\bbb"), "bbb");
strictEqual(path.win32.basename("aaa\\bbb", "bbb"), "bbb");
strictEqual(path.win32.basename("aaa\\bbb\\\\\\\\", "bbb"), "bbb");
strictEqual(path.win32.basename("aaa\\bbb", "bb"), "b");
strictEqual(path.win32.basename("aaa\\bbb", "b"), "bb");
strictEqual(path.win32.basename("C:"), "");
strictEqual(path.win32.basename("C:."), ".");
strictEqual(path.win32.basename("C:\\"), "");
strictEqual(path.win32.basename("C:\\dir\\base.ext"), "base.ext");
strictEqual(path.win32.basename("C:\\basename.ext"), "basename.ext");
strictEqual(path.win32.basename("C:basename.ext"), "basename.ext");
strictEqual(path.win32.basename("C:basename.ext\\"), "basename.ext");
strictEqual(path.win32.basename("C:basename.ext\\\\"), "basename.ext");
strictEqual(path.win32.basename("C:foo"), "foo");
strictEqual(path.win32.basename("file:stream"), "file:stream");
strictEqual(path.win32.basename("a", "a"), "");
// On unix a backslash is just treated as any other character.
strictEqual(
path.posix.basename("\\dir\\basename.ext"),
"\\dir\\basename.ext"
);
strictEqual(path.posix.basename("\\basename.ext"), "\\basename.ext");
strictEqual(path.posix.basename("basename.ext"), "basename.ext");
strictEqual(path.posix.basename("basename.ext\\"), "basename.ext\\");
strictEqual(path.posix.basename("basename.ext\\\\"), "basename.ext\\\\");
strictEqual(path.posix.basename("foo"), "foo");
// POSIX filenames may include control characters
// c.f. http://www.dwheeler.com/essays/fixing-unix-linux-filenames.html
const controlCharFilename = `Icon${String.fromCharCode(13)}`;
strictEqual(
path.posix.basename(`/a/b/${controlCharFilename}`),
controlCharFilename
);
});
it("path.join", () => {
const failures = [];
const backslashRE = /\\/g;
const joinTests = [
[
[path.posix.join],
// Arguments result
[
[[".", "x/b", "..", "/b/c.js"], "x/b/c.js"],
// [[], '.'],
[["/.", "x/b", "..", "/b/c.js"], "/x/b/c.js"],
[["/foo", "../../../bar"], "/bar"],
[["foo", "../../../bar"], "../../bar"],
[["foo/", "../../../bar"], "../../bar"],
[["foo/x", "../../../bar"], "../bar"],
[["foo/x", "./bar"], "foo/x/bar"],
[["foo/x/", "./bar"], "foo/x/bar"],
[["foo/x/", ".", "bar"], "foo/x/bar"],
[["./"], "./"],
[[".", "./"], "./"],
[[".", ".", "."], "."],
[[".", "./", "."], "."],
[[".", "/./", "."], "."],
[[".", "/////./", "."], "."],
[["."], "."],
[["", "."], "."],
[["", "foo"], "foo"],
[["foo", "/bar"], "foo/bar"],
[["", "/foo"], "/foo"],
[["", "", "/foo"], "/foo"],
[["", "", "foo"], "foo"],
[["foo", ""], "foo"],
[["foo/", ""], "foo/"],
[["foo", "", "/bar"], "foo/bar"],
[["./", "..", "/foo"], "../foo"],
[["./", "..", "..", "/foo"], "../../foo"],
[[".", "..", "..", "/foo"], "../../foo"],
[["", "..", "..", "/foo"], "../../foo"],
[["/"], "/"],
[["/", "."], "/"],
[["/", ".."], "/"],
[["/", "..", ".."], "/"],
[[""], "."],
[["", ""], "."],
[[" /foo"], " /foo"],
[[" ", "foo"], " /foo"],
[[" ", "."], " "],
[[" ", "/"], " /"],
[[" ", ""], " "],
[["/", "foo"], "/foo"],
[["/", "/foo"], "/foo"],
[["/", "//foo"], "/foo"],
[["/", "", "/foo"], "/foo"],
[["", "/", "foo"], "/foo"],
[["", "/", "/foo"], "/foo"],
],
],
];
// // Windows-specific join tests
// joinTests.push([
// path.win32.join,
// joinTests[0][1].slice(0).concat([
// // Arguments result
// // UNC path expected
// [["//foo/bar"], "\\\\foo\\bar\\"],
// [["\\/foo/bar"], "\\\\foo\\bar\\"],
// [["\\\\foo/bar"], "\\\\foo\\bar\\"],
// // UNC path expected - server and share separate
// [["//foo", "bar"], "\\\\foo\\bar\\"],
// [["//foo/", "bar"], "\\\\foo\\bar\\"],
// [["//foo", "/bar"], "\\\\foo\\bar\\"],
// // UNC path expected - questionable
// [["//foo", "", "bar"], "\\\\foo\\bar\\"],
// [["//foo/", "", "bar"], "\\\\foo\\bar\\"],
// [["//foo/", "", "/bar"], "\\\\foo\\bar\\"],
// // UNC path expected - even more questionable
// [["", "//foo", "bar"], "\\\\foo\\bar\\"],
// [["", "//foo/", "bar"], "\\\\foo\\bar\\"],
// [["", "//foo/", "/bar"], "\\\\foo\\bar\\"],
// // No UNC path expected (no double slash in first component)
// [["\\", "foo/bar"], "\\foo\\bar"],
// [["\\", "/foo/bar"], "\\foo\\bar"],
// [["", "/", "/foo/bar"], "\\foo\\bar"],
// // No UNC path expected (no non-slashes in first component -
// // questionable)
// [["//", "foo/bar"], "\\foo\\bar"],
// [["//", "/foo/bar"], "\\foo\\bar"],
// [["\\\\", "/", "/foo/bar"], "\\foo\\bar"],
// [["//"], "\\"],
// // No UNC path expected (share name missing - questionable).
// [["//foo"], "\\foo"],
// [["//foo/"], "\\foo\\"],
// [["//foo", "/"], "\\foo\\"],
// [["//foo", "", "/"], "\\foo\\"],
// // No UNC path expected (too many leading slashes - questionable)
// [["///foo/bar"], "\\foo\\bar"],
// [["////foo", "bar"], "\\foo\\bar"],
// [["\\\\\\/foo/bar"], "\\foo\\bar"],
// // Drive-relative vs drive-absolute paths. This merely describes the
// // status quo, rather than being obviously right
// [["c:"], "c:."],
// [["c:."], "c:."],
// [["c:", ""], "c:."],
// [["", "c:"], "c:."],
// [["c:.", "/"], "c:.\\"],
// [["c:.", "file"], "c:file"],
// [["c:", "/"], "c:\\"],
// [["c:", "file"], "c:\\file"],
// ]),
// ]);
joinTests.forEach((test) => {
if (!Array.isArray(test[0])) test[0] = [test[0]];
test[0].forEach((join) => {
test[1].forEach((test) => {
const actual = join.apply(null, test[0]);
const expected = test[1];
// For non-Windows specific tests with the Windows join(), we need to try
// replacing the slashes since the non-Windows specific tests' `expected`
// use forward slashes
let actualAlt;
let os;
if (join === path.win32.join) {
actualAlt = actual.replace(backslashRE, "/");
os = "win32";
} else {
os = "posix";
}
if (actual !== expected && actualAlt !== expected) {
const delimiter = test[0].map(JSON.stringify).join(",");
const message = `path.${os}.join(${delimiter})\n expect=${JSON.stringify(
expected
)}\n actual=${JSON.stringify(actual)}`;
failures.push(`\n${message}`);
}
});
});
});
strictEqual(failures.length, 0, failures.join(""));
});
it("path.relative", () => {
const failures = [];
const relativeTests = [
// [
// path.win32.relative,
// // Arguments result
// [
// ["c:/blah\\blah", "d:/games", "d:\\games"],
// ["c:/aaaa/bbbb", "c:/aaaa", ".."],
// ["c:/aaaa/bbbb", "c:/cccc", "..\\..\\cccc"],
// ["c:/aaaa/bbbb", "c:/aaaa/bbbb", ""],
// ["c:/aaaa/bbbb", "c:/aaaa/cccc", "..\\cccc"],
// ["c:/aaaa/", "c:/aaaa/cccc", "cccc"],
// ["c:/", "c:\\aaaa\\bbbb", "aaaa\\bbbb"],
// ["c:/aaaa/bbbb", "d:\\", "d:\\"],
// ["c:/AaAa/bbbb", "c:/aaaa/bbbb", ""],
// ["c:/aaaaa/", "c:/aaaa/cccc", "..\\aaaa\\cccc"],
// ["C:\\foo\\bar\\baz\\quux", "C:\\", "..\\..\\..\\.."],
// [
// "C:\\foo\\test",
// "C:\\foo\\test\\bar\\package.json",
// "bar\\package.json",
// ],
// ["C:\\foo\\bar\\baz-quux", "C:\\foo\\bar\\baz", "..\\baz"],
// ["C:\\foo\\bar\\baz", "C:\\foo\\bar\\baz-quux", "..\\baz-quux"],
// ["\\\\foo\\bar", "\\\\foo\\bar\\baz", "baz"],
// ["\\\\foo\\bar\\baz", "\\\\foo\\bar", ".."],
// ["\\\\foo\\bar\\baz-quux", "\\\\foo\\bar\\baz", "..\\baz"],
// ["\\\\foo\\bar\\baz", "\\\\foo\\bar\\baz-quux", "..\\baz-quux"],
// ["C:\\baz-quux", "C:\\baz", "..\\baz"],
// ["C:\\baz", "C:\\baz-quux", "..\\baz-quux"],
// ["\\\\foo\\baz-quux", "\\\\foo\\baz", "..\\baz"],
// ["\\\\foo\\baz", "\\\\foo\\baz-quux", "..\\baz-quux"],
// ["C:\\baz", "\\\\foo\\bar\\baz", "\\\\foo\\bar\\baz"],
// ["\\\\foo\\bar\\baz", "C:\\baz", "C:\\baz"],
// ],
// ],
[
path.posix.relative,
// Arguments result
[
["/var/lib", "/var", ".."],
["/var/lib", "/bin", "../../bin"],
["/var/lib", "/var/lib", ""],
["/var/lib", "/var/apache", "../apache"],
["/var/", "/var/lib", "lib"],
["/", "/var/lib", "var/lib"],
["/foo/test", "/foo/test/bar/package.json", "bar/package.json"],
["/Users/a/web/b/test/mails", "/Users/a/web/b", "../.."],
["/foo/bar/baz-quux", "/foo/bar/baz", "../baz"],
["/foo/bar/baz", "/foo/bar/baz-quux", "../baz-quux"],
["/baz-quux", "/baz", "../baz"],
["/baz", "/baz-quux", "../baz-quux"],
["/page1/page2/foo", "/", "../../.."],
],
],
];
relativeTests.forEach((test) => {
const relative = test[0];
test[1].forEach((test) => {
const actual = relative(test[0], test[1]);
const expected = test[2];
if (actual !== expected) {
const os = relative === path.win32.relative ? "win32" : "posix";
const message = `path.${os}.relative(${test
.slice(0, 2)
.map(JSON.stringify)
.join(",")})\n expect=${JSON.stringify(
expected
)}\n actual=${JSON.stringify(actual)}`;
failures.push(`\n${message}`);
}
});
});
strictEqual(failures.length, 0, failures.join(""));
expect(true).toBe(true);
});
it("path.normalize", () => {
// strictEqual(
// path.win32.normalize("./fixtures///b/../b/c.js"),
// "fixtures\\b\\c.js"
// );
// strictEqual(path.win32.normalize("/foo/../../../bar"), "\\bar");
// strictEqual(path.win32.normalize("a//b//../b"), "a\\b");
// strictEqual(path.win32.normalize("a//b//./c"), "a\\b\\c");
// strictEqual(path.win32.normalize("a//b//."), "a\\b");
// strictEqual(
// path.win32.normalize("//server/share/dir/file.ext"),
// "\\\\server\\share\\dir\\file.ext"
// );
// strictEqual(path.win32.normalize("/a/b/c/../../../x/y/z"), "\\x\\y\\z");
// strictEqual(path.win32.normalize("C:"), "C:.");
// strictEqual(path.win32.normalize("C:..\\abc"), "C:..\\abc");
// strictEqual(path.win32.normalize("C:..\\..\\abc\\..\\def"), "C:..\\..\\def");
// strictEqual(path.win32.normalize("C:\\."), "C:\\");
// strictEqual(path.win32.normalize("file:stream"), "file:stream");
// strictEqual(path.win32.normalize("bar\\foo..\\..\\"), "bar\\");
// strictEqual(path.win32.normalize("bar\\foo..\\.."), "bar");
// strictEqual(path.win32.normalize("bar\\foo..\\..\\baz"), "bar\\baz");
// strictEqual(path.win32.normalize("bar\\foo..\\"), "bar\\foo..\\");
// strictEqual(path.win32.normalize("bar\\foo.."), "bar\\foo..");
// strictEqual(path.win32.normalize("..\\foo..\\..\\..\\bar"), "..\\..\\bar");
// strictEqual(
// path.win32.normalize("..\\...\\..\\.\\...\\..\\..\\bar"),
// "..\\..\\bar"
// );
// strictEqual(
// path.win32.normalize("../../../foo/../../../bar"),
// "..\\..\\..\\..\\..\\bar"
// );
// strictEqual(
// path.win32.normalize("../../../foo/../../../bar/../../"),
// "..\\..\\..\\..\\..\\..\\"
// );
// strictEqual(
// path.win32.normalize("../foobar/barfoo/foo/../../../bar/../../"),
// "..\\..\\"
// );
// strictEqual(
// path.win32.normalize("../.../../foobar/../../../bar/../../baz"),
// "..\\..\\..\\..\\baz"
// );
// strictEqual(path.win32.normalize("foo/bar\\baz"), "foo\\bar\\baz");
strictEqual(
path.posix.normalize("./fixtures///b/../b/c.js"),
"fixtures/b/c.js"
);
strictEqual(path.posix.normalize("/foo/../../../bar"), "/bar");
strictEqual(path.posix.normalize("a//b//../b"), "a/b");
strictEqual(path.posix.normalize("a//b//./c"), "a/b/c");
strictEqual(path.posix.normalize("a//b//."), "a/b");
strictEqual(path.posix.normalize("/a/b/c/../../../x/y/z"), "/x/y/z");
strictEqual(path.posix.normalize("///..//./foo/.//bar"), "/foo/bar");
strictEqual(path.posix.normalize("bar/foo../../"), "bar/");
strictEqual(path.posix.normalize("bar/foo../.."), "bar");
strictEqual(path.posix.normalize("bar/foo../../baz"), "bar/baz");
strictEqual(path.posix.normalize("bar/foo../"), "bar/foo../");
strictEqual(path.posix.normalize("bar/foo.."), "bar/foo..");
console.log("A");
strictEqual(path.posix.normalize("../foo../../../bar"), "../../bar");
console.log("B");
strictEqual(path.posix.normalize("../.../.././.../../../bar"), "../../bar");
strictEqual(
path.posix.normalize("../../../foo/../../../bar"),
"../../../../../bar"
);
strictEqual(
path.posix.normalize("../../../foo/../../../bar/../../"),
"../../../../../../"
);
strictEqual(
path.posix.normalize("../foobar/barfoo/foo/../../../bar/../../"),
"../../"
);
strictEqual(
path.posix.normalize("../.../../foobar/../../../bar/../../baz"),
"../../../../baz"
);
strictEqual(path.posix.normalize("foo/bar\\baz"), "foo/bar\\baz");
});
it("path.resolve", () => {
const failures = [];
const slashRE = /\//g;
const backslashRE = /\\/g;
const resolveTests = [
// [
// path.win32.resolve,
// // Arguments result
// [
// [["c:/blah\\blah", "d:/games", "c:../a"], "c:\\blah\\a"],
// [["c:/ignore", "d:\\a/b\\c/d", "\\e.exe"], "d:\\e.exe"],
// [["c:/ignore", "c:/some/file"], "c:\\some\\file"],
// [["d:/ignore", "d:some/dir//"], "d:\\ignore\\some\\dir"],
// [["."], process.cwd()],
// [["//server/share", "..", "relative\\"], "\\\\server\\share\\relative"],
// [["c:/", "//"], "c:\\"],
// [["c:/", "//dir"], "c:\\dir"],
// [["c:/", "//server/share"], "\\\\server\\share\\"],
// [["c:/", "//server//share"], "\\\\server\\share\\"],
// [["c:/", "///some//dir"], "c:\\some\\dir"],
// [
// ["C:\\foo\\tmp.3\\", "..\\tmp.3\\cycles\\root.js"],
// "C:\\foo\\tmp.3\\cycles\\root.js",
// ],
// ],
// ],
[
path.posix.resolve,
// Arguments result
[
[["/var/lib", "../", "file/"], "/var/file"],
[["/var/lib", "/../", "file/"], "/file"],
[["a/b/c/", "../../.."], process.cwd()],
[["."], process.cwd()],
[["/some/dir", ".", "/absolute/"], "/absolute"],
[
["/foo/tmp.3/", "../tmp.3/cycles/root.js"],
"/foo/tmp.3/cycles/root.js",
],
],
],
];
const isWindows = false;
resolveTests.forEach(([resolve, tests]) => {
tests.forEach(([test, expected]) => {
const actual = resolve.apply(null, test);
let actualAlt;
const os = resolve === path.win32.resolve ? "win32" : "posix";
if (resolve === path.win32.resolve && !isWindows)
actualAlt = actual.replace(backslashRE, "/");
else if (resolve !== path.win32.resolve && isWindows)
actualAlt = actual.replace(slashRE, "\\");
const message = `path.${os}.resolve(${test
.map(JSON.stringify)
.join(",")})\n expect=${JSON.stringify(
expected
)}\n actual=${JSON.stringify(actual)}`;
if (actual !== expected && actualAlt !== expected) failures.push(message);
});
});
strictEqual(failures.length, 0, failures.join("\n"));
});

View File

@@ -0,0 +1,18 @@
import { expect, it } from "bun:test";
it("performance.now() should be monotonic", () => {
const first = performance.now();
const second = performance.now();
const third = performance.now();
const fourth = performance.now();
const fifth = performance.now();
const sixth = performance.now();
expect(first < second).toBe(true);
expect(second < third).toBe(true);
expect(third < fourth).toBe(true);
expect(fourth < fifth).toBe(true);
expect(fifth < sixth).toBe(true);
expect(Bun.nanoseconds() > 0).toBe(true);
expect(Bun.nanoseconds() > sixth).toBe(true);
expect(typeof Bun.nanoseconds() === "number").toBe(true);
});

View File

@@ -0,0 +1,91 @@
// You can verify this test is correct by copy pasting this into a browser's console and checking it doesn't throw an error.
var run = 0;
var queueMicrotask = process.nextTick;
await new Promise((resolve, reject) => {
queueMicrotask(() => {
if (run++ != 0) {
reject(new Error("Microtask execution order is wrong: " + run));
}
queueMicrotask(() => {
if (run++ != 3) {
reject(new Error("Microtask execution order is wrong: " + run));
}
});
});
queueMicrotask(() => {
if (run++ != 1) {
reject(new Error("Microtask execution order is wrong: " + run));
}
queueMicrotask(() => {
if (run++ != 4) {
reject(new Error("Microtask execution order is wrong: " + run));
}
queueMicrotask(() => {
if (run++ != 6) {
reject(new Error("Microtask execution order is wrong: " + run));
}
});
});
});
queueMicrotask(() => {
if (run++ != 2) {
reject(new Error("Microtask execution order is wrong: " + run));
}
queueMicrotask(() => {
if (run++ != 5) {
reject(new Error("Microtask execution order is wrong: " + run));
}
queueMicrotask(() => {
if (run++ != 7) {
reject(new Error("Microtask execution order is wrong: " + run));
}
resolve(true);
});
});
});
});
{
var passed = false;
try {
queueMicrotask(1234);
} catch (exception) {
passed = exception instanceof TypeError;
}
if (!passed)
throw new Error(
"queueMicrotask should throw a TypeError if the argument is not a function"
);
}
{
var passed = false;
try {
queueMicrotask();
} catch (exception) {
passed = exception instanceof TypeError;
}
if (!passed)
throw new Error(
"queueMicrotask should throw a TypeError if the argument is empty"
);
}
await new Promise((resolve, reject) => {
process.nextTick(
(first, second) => {
console.log(first, second);
if (first !== 12345 || second !== "hello")
reject(new Error("process.nextTick called with wrong arguments"));
resolve(true);
},
12345,
"hello"
);
});

View File

@@ -0,0 +1,93 @@
import { it } from "bun:test";
it("process.nextTick", async () => {
// You can verify this test is correct by copy pasting this into a browser's console and checking it doesn't throw an error.
var run = 0;
var queueMicrotask = process.nextTick;
await new Promise((resolve, reject) => {
queueMicrotask(() => {
if (run++ != 0) {
reject(new Error("Microtask execution order is wrong: " + run));
}
queueMicrotask(() => {
if (run++ != 3) {
reject(new Error("Microtask execution order is wrong: " + run));
}
});
});
queueMicrotask(() => {
if (run++ != 1) {
reject(new Error("Microtask execution order is wrong: " + run));
}
queueMicrotask(() => {
if (run++ != 4) {
reject(new Error("Microtask execution order is wrong: " + run));
}
queueMicrotask(() => {
if (run++ != 6) {
reject(new Error("Microtask execution order is wrong: " + run));
}
});
});
});
queueMicrotask(() => {
if (run++ != 2) {
reject(new Error("Microtask execution order is wrong: " + run));
}
queueMicrotask(() => {
if (run++ != 5) {
reject(new Error("Microtask execution order is wrong: " + run));
}
queueMicrotask(() => {
if (run++ != 7) {
reject(new Error("Microtask execution order is wrong: " + run));
}
resolve(true);
});
});
});
});
{
var passed = false;
try {
queueMicrotask(1234);
} catch (exception) {
passed = exception instanceof TypeError;
}
if (!passed)
throw new Error(
"queueMicrotask should throw a TypeError if the argument is not a function"
);
}
{
var passed = false;
try {
queueMicrotask();
} catch (exception) {
passed = exception instanceof TypeError;
}
if (!passed)
throw new Error(
"queueMicrotask should throw a TypeError if the argument is empty"
);
}
await new Promise((resolve, reject) => {
process.nextTick(
(first, second) => {
if (first !== 12345 || second !== "hello")
reject(new Error("process.nextTick called with wrong arguments"));
resolve(true);
},
12345,
"hello"
);
});
});

View File

@@ -0,0 +1,54 @@
import { describe, it } from "bun:test";
it("process", () => {
// this property isn't implemented yet but it should at least return a string
const isNode = !process.isBun;
if (!isNode && process.title !== "bun")
throw new Error("process.title is not 'bun'");
if (typeof process.env.USER !== "string")
throw new Error("process.env is not an object");
if (process.env.USER.length === 0)
throw new Error("process.env is missing a USER property");
if (process.platform !== "darwin" && process.platform !== "linux")
throw new Error("process.platform is invalid");
if (isNode) throw new Error("process.isBun is invalid");
// partially to test it doesn't crash due to various strange types
process.env.BACON = "yummy";
if (process.env.BACON !== "yummy") {
throw new Error("process.env is not writable");
}
delete process.env.BACON;
if (typeof process.env.BACON !== "undefined") {
throw new Error("process.env is not deletable");
}
process.env.BACON = "yummy";
if (process.env.BACON !== "yummy") {
throw new Error("process.env is not re-writable");
}
if (JSON.parse(JSON.stringify(process.env)).BACON !== "yummy") {
throw new Error("process.env is not serializable");
}
if (typeof JSON.parse(JSON.stringify(process.env)).toJSON !== "undefined") {
throw new Error(
"process.env should call toJSON to hide its internal state"
);
}
var { env, ...proces } = process;
console.log(JSON.stringify(proces, null, 2));
console.log(proces);
console.log("CWD", process.cwd());
console.log("SET CWD", process.chdir("../"));
console.log("CWD", process.cwd());
});

View File

@@ -0,0 +1 @@
File read successfully

9
test/bun.js/readdir.js Normal file
View File

@@ -0,0 +1,9 @@
const { readdirSync } = require("fs");
const count = parseInt(process.env.ITERATIONS || "1", 10) || 1;
for (let i = 0; i < count; i++) {
readdirSync(".");
}
console.log(readdirSync("."));

View File

@@ -0,0 +1,25 @@
import { it } from "bun:test";
it("reportError", () => {
console.log("---BEGIN REPORT ERROR TEST--");
// make sure we don't crash when given non-sensical types
reportError(new Error("reportError Test!"));
reportError(true);
reportError(false);
reportError(null);
reportError(123);
reportError(Infinity);
reportError(NaN);
reportError(-NaN);
reportError("");
reportError(new Uint8Array(1));
reportError(new Uint8Array(0));
reportError(new ArrayBuffer(0));
reportError(new ArrayBuffer(1));
reportError("string");
reportError([]);
reportError([123, null]);
reportError({});
reportError([{}]);
console.log("---END REPORT ERROR TEST--");
});

View File

@@ -0,0 +1,3 @@
{
"hello": -123
}

View File

@@ -0,0 +1 @@
export default {};

100
test/bun.js/resolve.test.js Normal file
View File

@@ -0,0 +1,100 @@
import { it, expect } from "bun:test";
import { mkdirSync, writeFileSync } from "fs";
import { join } from "path";
it("import.meta.resolve", async () => {
expect(await import.meta.resolve("./resolve.test.js")).toBe(import.meta.path);
expect(await import.meta.resolve("./resolve.test.js", import.meta.path)).toBe(
import.meta.path
);
expect(
// optional second param can be any path, including a dir
await import.meta.resolve(
"./bun.js/resolve.test.js",
join(import.meta.path, "../")
)
).toBe(import.meta.path);
// can be a package path
expect(
(await import.meta.resolve("react", import.meta.path)).length > 0
).toBe(true);
// file extensions are optional
expect(await import.meta.resolve("./resolve.test")).toBe(import.meta.path);
// works with tsconfig.json "paths"
expect(await import.meta.resolve("foo/bar")).toBe(
join(import.meta.path, "../baz.js")
);
// works with package.json "exports"
writePackageJSONExportsFixture();
expect(await import.meta.resolve("package-json-exports/baz")).toBe(
join(import.meta.path, "../node_modules/package-json-exports/foo/bar.js")
);
// works with TypeScript compiler edgecases like:
// - If the file ends with .js and it doesn't exist, try again with .ts and .tsx
expect(await import.meta.resolve("./resolve-typescript-file.js")).toBe(
join(import.meta.path, "../resolve-typescript-file.tsx")
);
expect(await import.meta.resolve("./resolve-typescript-file.tsx")).toBe(
join(import.meta.path, "../resolve-typescript-file.tsx")
);
// throws a ResolveError on failure
try {
await import.meta.resolve("THIS FILE DOESNT EXIST");
throw new Error("Test failed");
} catch (exception) {
expect(exception instanceof ResolveError).toBe(true);
expect(exception.referrer).toBe(import.meta.path);
expect(exception.name).toBe("ResolveError");
}
});
// the slightly lower level API, which doesn't prefill the second param
// and expects a directory instead of a filepath
it("Bun.resolve", async () => {
expect(await Bun.resolve("./resolve.test.js", import.meta.dir)).toBe(
import.meta.path
);
});
// synchronous
it("Bun.resolveSync", () => {
expect(Bun.resolveSync("./resolve.test.js", import.meta.dir)).toBe(
import.meta.path
);
});
function writePackageJSONExportsFixture() {
try {
mkdirSync(
join(import.meta.dir, "./node_modules/package-json-exports/foo"),
{
recursive: true,
}
);
} catch (exception) {}
writeFileSync(
join(import.meta.dir, "./node_modules/package-json-exports/foo/bar.js"),
"export const bar = 1;"
);
writeFileSync(
join(import.meta.dir, "./node_modules/package-json-exports/package.json"),
JSON.stringify(
{
name: "package-json-exports",
exports: {
"./baz": "./foo/bar.js",
},
},
null,
2
)
);
}

View File

@@ -0,0 +1,218 @@
import fs from "fs";
import { it, expect } from "bun:test";
import path from "path";
import { gcTick } from "./gc";
it("Bun.file not found returns ENOENT", async () => {
try {
await gcTick();
await Bun.file("/does/not/exist.txt").text();
await gcTick();
} catch (exception) {
expect(exception.code).toBe("ENOENT");
}
await gcTick();
});
it("Bun.write('out.txt', 'string')", async () => {
for (let erase of [true, false]) {
if (erase) {
try {
fs.unlinkSync(path.join("/tmp", "out.txt"));
} catch (e) {}
}
await gcTick();
expect(await Bun.write("/tmp/out.txt", "string")).toBe("string".length);
await gcTick();
const out = Bun.file("/tmp/out.txt");
await gcTick();
expect(await out.text()).toBe("string");
await gcTick();
expect(await out.text()).toBe(fs.readFileSync("/tmp/out.txt", "utf8"));
await gcTick();
}
});
it("Bun.write blob", async () => {
await Bun.write(
Bun.file("/tmp/response-file.test.txt"),
Bun.file(path.join(import.meta.dir, "fetch.js.txt"))
);
await gcTick();
await Bun.write(Bun.file("/tmp/response-file.test.txt"), "blah blah blha");
await gcTick();
await Bun.write(
Bun.file("/tmp/response-file.test.txt"),
new Uint32Array(1024)
);
await gcTick();
await Bun.write("/tmp/response-file.test.txt", new Uint32Array(1024));
await gcTick();
expect(
await Bun.write(
new TextEncoder().encode("/tmp/response-file.test.txt"),
new Uint32Array(1024)
)
).toBe(new Uint32Array(1024).byteLength);
await gcTick();
});
it("Bun.file -> Bun.file", async () => {
try {
fs.unlinkSync(path.join("/tmp", "fetch.js.in"));
} catch (e) {}
await gcTick();
try {
fs.unlinkSync(path.join("/tmp", "fetch.js.out"));
} catch (e) {}
await gcTick();
const file = path.join(import.meta.dir, "fetch.js.txt");
await gcTick();
const text = fs.readFileSync(file, "utf8");
fs.writeFileSync("/tmp/fetch.js.in", text);
await gcTick();
{
const result = await Bun.write(
Bun.file("/tmp/fetch.js.out"),
Bun.file("/tmp/fetch.js.in")
);
await gcTick();
expect(await Bun.file("/tmp/fetch.js.out").text()).toBe(text);
await gcTick();
}
{
await Bun.write(
Bun.file("/tmp/fetch.js.in").slice(0, (text.length / 2) | 0),
Bun.file("/tmp/fetch.js.out")
);
expect(await Bun.file("/tmp/fetch.js.in").text()).toBe(
text.substring(0, (text.length / 2) | 0)
);
}
{
await gcTick();
await Bun.write("/tmp/fetch.js.in", Bun.file("/tmp/fetch.js.out"));
await gcTick();
expect(await Bun.file("/tmp/fetch.js.in").text()).toBe(text);
}
});
it("Bun.file", async () => {
const file = path.join(import.meta.dir, "fetch.js.txt");
await gcTick();
expect(await Bun.file(file).text()).toBe(fs.readFileSync(file, "utf8"));
await gcTick();
});
it("Bun.file as a Blob", async () => {
const filePath = path.join(import.meta.path, "../fetch.js.txt");
const fixture = fs.readFileSync(filePath, "utf8");
// this is a Blob object with the same interface as the one returned by fetch
// internally, instead of a byte array, it stores the file path!
// this enables several performance optimizations
var blob = Bun.file(filePath);
await gcTick();
// no size because we haven't read it from disk yet
expect(blob.size).toBe(0);
await gcTick();
// now it reads "./fetch.js.txt" from the filesystem
// it's lazy, only loads once we ask for it
// if it fails, the promise will reject at this point
expect(await blob.text()).toBe(fixture);
await gcTick();
// now that it's loaded, the size updates
expect(blob.size).toBe(fixture.length);
await gcTick();
// and it only loads once for _all_ blobs pointing to that file path
// until all references are released
expect((await blob.arrayBuffer()).byteLength).toBe(fixture.length);
await gcTick();
const array = new Uint8Array(await blob.arrayBuffer());
await gcTick();
const text = fixture;
for (let i = 0; i < text.length; i++) {
expect(array[i]).toBe(text.charCodeAt(i));
}
await gcTick();
expect(blob.size).toBe(fixture.length);
blob = null;
await gcTick();
await new Promise((resolve) => setTimeout(resolve, 1));
// now we're back
var blob = Bun.file(filePath);
expect(blob.size).toBe(0);
});
it("Response -> Bun.file", async () => {
const file = path.join(import.meta.dir, "fetch.js.txt");
await gcTick();
const text = fs.readFileSync(file, "utf8");
await gcTick();
const response = new Response(Bun.file(file));
await gcTick();
expect(await response.text()).toBe(text);
await gcTick();
});
it("Bun.file -> Response", async () => {
// ensure the file doesn't already exist
try {
fs.unlinkSync("/tmp/fetch.js.out");
} catch {}
await gcTick();
const file = path.join(import.meta.dir, "fetch.js.txt");
await gcTick();
const text = fs.readFileSync(file, "utf8");
await gcTick();
const resp = await fetch("https://example.com");
await gcTick();
expect(await Bun.write("/tmp/fetch.js.out", resp)).toBe(text.length);
await gcTick();
expect(await Bun.file("/tmp/fetch.js.out").text()).toBe(text);
await gcTick();
});
it("Response -> Bun.file -> Response -> text", async () => {
await gcTick();
const file = path.join(import.meta.dir, "fetch.js.txt");
await gcTick();
const text = fs.readFileSync(file, "utf8");
await gcTick();
const response = new Response(Bun.file(file));
await gcTick();
const response2 = response.clone();
await gcTick();
expect(await response2.text()).toBe(text);
await gcTick();
});
// If you write nothing to a file, it shouldn't modify it
// If you want to truncate a file, it should be more explicit
it("Bun.write('output.html', '')", async () => {
await Bun.write("/tmp/output.html", "lalalala");
expect(await Bun.write("/tmp/output.html", "")).toBe(0);
expect(await Bun.file("/tmp/output.html").text()).toBe("lalalala");
});
// Since Bun.file is resolved lazily, this needs to specifically be checked
it("Bun.write('output.html', HTMLRewriter.transform(Bun.file)))", async () => {
var rewriter = new HTMLRewriter();
rewriter.on("div", {
element(element) {
element.setInnerContent("<blink>it worked!</blink>", { html: true });
},
});
await Bun.write("/tmp/html-rewriter.txt.js", "<div>hello</div>");
var input = new Response(Bun.file("/tmp/html-rewriter.txt.js"));
var output = rewriter.transform(input);
const outpath = `/tmp/html-rewriter.${Date.now()}.html`;
await Bun.write(outpath, output);
expect(await Bun.file(outpath).text()).toBe(
"<div><blink>it worked!</blink></div>"
);
});

82
test/bun.js/serve.test.ts Normal file
View File

@@ -0,0 +1,82 @@
import { file, serve } from "bun";
import { expect, it } from "bun:test";
import { readFileSync } from "fs";
import { resolve } from "path";
var port = 40000;
it("should work for a hello world", async () => {
const server = serve({
port: port++,
fetch(req) {
return new Response(`Hello, world!`);
},
});
const response = await fetch(`http://localhost:${server.port}`);
expect(await response.text()).toBe("Hello, world!");
server.stop();
});
it("should work for a file", async () => {
const fixture = resolve(import.meta.dir, "./fetch.js.txt");
const textToExpect = readFileSync(fixture, "utf-8");
const server = serve({
port: port++,
fetch(req) {
return new Response(file(fixture));
},
});
const response = await fetch(`http://localhost:${server.port}`);
expect(await response.text()).toBe(textToExpect);
server.stop();
});
it("fetch should work with headers", async () => {
const fixture = resolve(import.meta.dir, "./fetch.js.txt");
const server = serve({
port: port++,
fetch(req) {
if (req.headers.get("X-Foo") !== "bar") {
return new Response("X-Foo header not set", { status: 500 });
}
return new Response(file(fixture), {
headers: { "X-Both-Ways": "1" },
});
},
});
const response = await fetch(`http://localhost:${server.port}`, {
headers: {
"X-Foo": "bar",
},
});
expect(response.status).toBe(200);
expect(response.headers.get("X-Both-Ways")).toBe("1");
server.stop();
});
var count = 200;
it(`should work for a file ${count} times`, async () => {
const fixture = resolve(import.meta.dir, "./fetch.js.txt");
const textToExpect = readFileSync(fixture, "utf-8");
var ran = 0;
const server = serve({
port: port++,
async fetch(req) {
return new Response(file(fixture));
},
});
// this gets stuck if run about 200 times awaiting all the promises
// when the promises are run altogether, instead of one at a time
// it's hard to say if this only happens here due to some weird stuff with the test runner
// or if it's "real" issue
for (let i = 0; i < count; i++) {
const response = await fetch(`http://localhost:${server.port}`);
expect(await response.text()).toBe(textToExpect);
}
server.stop();
});

View File

@@ -0,0 +1,35 @@
import { it, expect } from "bun:test";
it("setInterval", async () => {
var counter = 0;
var start;
const result = await new Promise((resolve, reject) => {
start = performance.now();
var id = setInterval(() => {
counter++;
if (counter === 10) {
resolve(counter);
clearInterval(id);
}
}, 1);
});
expect(result).toBe(10);
expect(performance.now() - start >= 10).toBe(true);
});
it("clearInterval", async () => {
var called = false;
const id = setInterval(() => {
called = true;
expect(false).toBe(true);
}, 1);
clearInterval(id);
await new Promise((resolve, reject) => {
setInterval(() => {
resolve();
}, 10);
});
expect(called).toBe(false);
});

View File

@@ -0,0 +1,39 @@
import { it, expect } from "bun:test";
it("setTimeout", async () => {
var lastID = -1;
const result = await new Promise((resolve, reject) => {
var numbers = [];
for (let i = 1; i < 100; i++) {
const id = setTimeout(() => {
numbers.push(i);
if (i === 99) {
resolve(numbers);
}
}, i);
expect(id > lastID).toBe(true);
lastID = id;
}
});
for (let j = 0; j < result.length; j++) {
expect(result[j]).toBe(j + 1);
}
expect(result.length).toBe(99);
});
it("clearTimeout", async () => {
var called = false;
const id = setTimeout(() => {
called = true;
expect(false).toBe(true);
}, 1);
clearTimeout(id);
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 10);
});
expect(called).toBe(false);
});

View File

@@ -0,0 +1,10 @@
import { describe, it, expect } from "bun:test";
it("shadow realm works", () => {
const red = new ShadowRealm();
globalThis.someValue = 1;
// Affects only the ShadowRealm's global
const result = red.evaluate("globalThis.someValue = 2;");
expect(globalThis.someValue).toBe(1);
expect(result).toBe(2);
});

10
test/bun.js/sleep.js Normal file
View File

@@ -0,0 +1,10 @@
const interval = 0.01;
const now = performance.now();
console.time("Slept");
Bun.sleepSync(interval);
const elapsed = performance.now() - now;
if (elapsed < interval) {
throw new Error("Didn't sleep");
}
console.timeEnd("Slept");

View File

@@ -0,0 +1,74 @@
const template = (
<svg width="400" height="180">
<rect
stroke-width="2"
x="50"
y="20"
rx="20"
ry="20"
width="150"
height="150"
style="fill:red;stroke:black;stroke-width:5;opacity:0.5"
/>
<linearGradient gradientTransform="rotate(25)">
<stop offset="0%"></stop>
</linearGradient>
</svg>
);
const template2 = (
<svg width="400" height="180">
<rect
className={state.name}
stroke-width={state.width}
x={state.x}
y={state.y}
rx="20"
ry="20"
width="150"
height="150"
style={{
fill: "red",
stroke: "black",
"stroke-width": props.stroke,
opacity: 0.5,
}}
/>
</svg>
);
const template3 = (
<svg width="400" height="180">
<rect {...props} />
</svg>
);
const template4 = <rect x="50" y="20" width="150" height="150" />;
const template5 = (
<>
<rect x="50" y="20" width="150" height="150" />
</>
);
const template6 = (
<Component>
<rect x="50" y="20" width="150" height="150" />
</Component>
);
const template7 = (
<svg viewBox={"0 0 160 40"} xmlns="http://www.w3.org/2000/svg">
<a xlink:href={url}>
<text x="10" y="25">
MDN Web Docs
</text>
</a>
</svg>
);
const template8 = (
<svg viewBox={"0 0 160 40"} xmlns="http://www.w3.org/2000/svg">
<text x="10" y="25" textContent={text} />
</svg>
);

View File

@@ -0,0 +1,33 @@
var _tmpl$1 = _template$('<svg width="400" height="180"><rect stroke-width="2" x="50" y="20" rx="20" ry="20" width="150" height="150"/><linearGradient gradientTransform="rotate(25)"><stop offset="0%"/></linearGradient></svg>', 4), _tmpl$2 = _template$('<svg width="400" height="180"><rect rx="20" ry="20" width="150" height="150"/></svg>', 2), _tmpl$3 = _template$('<svg width="400" height="180"><rect/></svg>', 2), _tmpl$4 = _template$('<rect x="50" y="20" width="150" height="150"/>', 0), _tmpl$5 = _template$('<svg viewBox="0 0 160 40" xmlns="http://www.w3.org/2000/svg"><a><text x="10" y="25">MDN Web Docs</text></a></svg>', 6), _tmpl$6 = _template$('<svg viewBox="0 0 160 40" xmlns="http://www.w3.org/2000/svg"><text x="10" y="25"/></svg>', 2);
const template = _tmpl$1.cloneNode(true);
const template2 = () => {
var _el = _tmpl$1.cloneNode(true);
effect(() => {
return setAttribute(_el, "className", state.name);
});
effect(() => {
return setAttribute(_el, "stroke-width", state.width);
});
effect(() => {
return setAttribute(_el, "x", state.x);
});
effect(() => {
return setAttribute(_el, "y", state.y);
});
;
return _el;
};
const template3 = _tmpl$3.cloneNode(true);
const template4 = _tmpl$4.cloneNode(true);
const template5 = ;
const template6 = createComponent(Component, {});
const template7 = () => {
var _el = _tmpl$4.cloneNode(true);
setAttribute(_el, "xlink:href", url);
return _el;
};
const template8 = () => {
var _el = _tmpl$5.cloneNode(true);
setAttribute(_el, "textContent", text);
return _el;
};

View File

@@ -0,0 +1,108 @@
import { template as _$template } from "r-dom";
import { setAttributeNS as _$setAttributeNS } from "r-dom";
import { createComponent as _$createComponent } from "r-dom";
import { spread as _$spread } from "r-dom";
import { setAttribute as _$setAttribute } from "r-dom";
import { effect as _$effect } from "r-dom";
const _tmpl$ = /*#__PURE__*/ _$template(
`<svg width="400" height="180"><rect stroke-width="2" x="50" y="20" rx="20" ry="20" width="150" height="150" style="fill:red;stroke:black;stroke-width:5;opacity:0.5"></rect><linearGradient gradientTransform="rotate(25)"><stop offset="0%"></stop></linearGradient></svg>`,
8
),
_tmpl$2 = /*#__PURE__*/ _$template(
`<svg width="400" height="180"><rect rx="20" ry="20" width="150" height="150"></rect></svg>`,
4
),
_tmpl$3 = /*#__PURE__*/ _$template(
`<svg width="400" height="180"><rect></rect></svg>`,
4
),
_tmpl$4 = /*#__PURE__*/ _$template(
`<svg><rect x="50" y="20" width="150" height="150"></rect></svg>`,
4,
true
),
_tmpl$5 = /*#__PURE__*/ _$template(
`<svg viewBox="0 0 160 40" xmlns="http://www.w3.org/2000/svg"><a><text x="10" y="25">MDN Web Docs</text></a></svg>`,
6
),
_tmpl$6 = /*#__PURE__*/ _$template(
`<svg viewBox="0 0 160 40" xmlns="http://www.w3.org/2000/svg"><text x="10" y="25"></text></svg>`,
4
);
const template = _tmpl$.cloneNode(true);
const template2 = (() => {
const _el$2 = _tmpl$2.cloneNode(true),
_el$3 = _el$2.firstChild;
_el$3.style.setProperty("fill", "red");
_el$3.style.setProperty("stroke", "black");
_el$3.style.setProperty("opacity", "0.5");
_$effect(
(_p$) => {
const _v$ = state.name,
_v$2 = state.width,
_v$3 = state.x,
_v$4 = state.y,
_v$5 = props.stroke;
_v$ !== _p$._v$ && _$setAttribute(_el$3, "class", (_p$._v$ = _v$));
_v$2 !== _p$._v$2 &&
_$setAttribute(_el$3, "stroke-width", (_p$._v$2 = _v$2));
_v$3 !== _p$._v$3 && _$setAttribute(_el$3, "x", (_p$._v$3 = _v$3));
_v$4 !== _p$._v$4 && _$setAttribute(_el$3, "y", (_p$._v$4 = _v$4));
_v$5 !== _p$._v$5 &&
_el$3.style.setProperty("stroke-width", (_p$._v$5 = _v$5));
return _p$;
},
{
_v$: undefined,
_v$2: undefined,
_v$3: undefined,
_v$4: undefined,
_v$5: undefined,
}
);
return _el$2;
})();
const template3 = (() => {
const _el$4 = _tmpl$3.cloneNode(true),
_el$5 = _el$4.firstChild;
_$spread(_el$5, props, true, false);
return _el$4;
})();
const template4 = _tmpl$4.cloneNode(true);
const template5 = _tmpl$4.cloneNode(true);
const template6 = _$createComponent(Component, {
get children() {
return _tmpl$4.cloneNode(true);
},
});
const template7 = (() => {
const _el$9 = _tmpl$5.cloneNode(true),
_el$10 = _el$9.firstChild;
_$setAttributeNS(_el$10, "http://www.w3.org/1999/xlink", "xlink:href", url);
return _el$9;
})();
const template8 = (() => {
const _el$11 = _tmpl$6.cloneNode(true),
_el$12 = _el$11.firstChild;
_el$12.textContent = text;
return _el$11;
})();

View File

@@ -0,0 +1,115 @@
const selected = true;
let id = "my-h1";
let link;
const template = (
<div
id="main"
{...results}
classList={{ selected: unknown }}
style={{ color }}
>
<h1
class="base"
id={id}
{...results()}
disabled
readonly=""
title={welcoming()}
style={{ "background-color": color(), "margin-right": "40px" }}
classList={{ dynamic: dynamic(), selected }}
>
<a href={"/"} ref={link} classList={{ "ccc ddd": true }} readonly={value}>
Welcome
</a>
</h1>
</div>
);
const template2 = (
<div {...getProps("test")}>
<div textContent={rowId} />
<div textContent={row.label} />
<div innerHTML={"<div/>"} />
</div>
);
const template3 = (
<div
id={/*@once*/ state.id}
style={/*@once*/ { "background-color": state.color }}
name={state.name}
textContent={/*@once*/ state.content}
/>
);
const template4 = (
<div class="hi" className={state.class} classList={{ "ccc:ddd": true }} />
);
const template5 = <div class="a" className="b"></div>;
const template6 = <div style={someStyle()} textContent="Hi" />;
const template7 = (
<div
style={{
"background-color": color(),
"margin-right": "40px",
...props.style,
}}
style:padding-top={props.top}
class:my-class={props.active}
/>
);
let refTarget;
const template8 = <div ref={refTarget} />;
const template9 = <div ref={(e) => console.log(e)} />;
const template10 = <div ref={refFactory()} />;
const template11 = <div use:something use:another={thing} use:zero={0} />;
const template12 = <div prop:htmlFor={thing} />;
const template13 = <input type="checkbox" checked={true} />;
const template14 = <input type="checkbox" checked={state.visible} />;
const template15 = <div class="`a">`$`</div>;
const template16 = (
<button
class="static"
classList={{
hi: "k",
}}
type="button"
>
Write
</button>
);
const template17 = (
<button
classList={{
a: true,
b: true,
c: true,
}}
onClick={increment}
>
Hi
</button>
);
const template18 = (
<div
{...{
get [key()]() {
return props.value;
},
}}
/>
);

View File

@@ -0,0 +1,155 @@
var _tmpl = _template$(
'<div id="main"><h1 class="base" disabled readonly><a href="/">Welcome</a></h1></div>',
6
),
_tmpl$2 = _template$(
'<div><div/><div/><div innerHTML="&lt;div/&gt;"/></div>',
2
),
_tmpl$2 = _template$("<div/>", 0),
_tmpl$3 = _template$('<div class="hi"/>', 0),
_tmpl$5 = _template$('<div class="a" class="b"/>', 0),
_tmpl$5 = _template$('<div textContent="Hi"/>', 0),
_tmpl$6 = _template$("<div use:something use:zero=0/>", 0),
_tmpl$8 = _template$('<input type="checkbox" checked/>', 0),
_tmpl$8 = _template$('<input type="checkbox"/>', 0),
_tmpl$10 = _template$('<div class="`a">`$`</div>', 2),
_tmpl$10 = _template$(
'<button class="static" type="button">Write</button>',
2
),
_tmpl$11 = _template$("<button>Hi</button>", 2);
const selected = true;
let id = "my-h1";
let link;
const template = () => {
var _el = _tmpl.cloneNode(true),
_el$1 = _el.firstChild,
_el$2 = _el$1.nextSibling;
effect(() => {
return setAttribute(_el, "classList", { selected: unknown });
});
setAttribute(_el$1, "id", id);
effect(() => {
return setAttribute(_el$1, "title", welcoming());
});
effect(() => {
return setAttribute(_el$1, "classList", { dynamic: dynamic(), selected });
});
setAttribute(_el$2, "ref", link);
effect(() => {
return setAttribute(_el$2, "classList", { "ccc ddd": true });
});
setAttribute(_el$2, "readonly", value);
return _el;
};
const template2 = () => {
var _el = _tmpl$1.cloneNode(true),
_el$1 = _el.firstChild;
setAttribute(_el, "textContent", rowId);
effect(() => {
return setAttribute(_el$1, "textContent", row.label);
});
return _el;
};
const template3 = () => {
var _el = _tmpl$2.cloneNode(true);
effect(() => {
return setAttribute(_el, "id", state.id);
});
effect(() => {
return setAttribute(_el, "name", state.name);
});
effect(() => {
return setAttribute(_el, "textContent", state.content);
});
return _el;
};
const template4 = () => {
var _el = _tmpl$3.cloneNode(true);
effect(() => {
return setAttribute(_el, "className", state.class);
});
effect(() => {
return setAttribute(_el, "classList", { "ccc:ddd": true });
});
return _el;
};
const template5 = _tmpl$5.cloneNode(true);
const template6 = () => {
var _el = _tmpl$5.cloneNode(true);
return _el;
};
const template7 = () => {
var _el = _tmpl$2.cloneNode(true);
effect(() => {
return setAttribute(_el, "style:padding-top", props.top);
});
effect(() => {
return setAttribute(_el, "class:my-class", props.active);
});
return _el;
};
let refTarget;
const template8 = () => {
var _el = _tmpl$2.cloneNode(true);
setAttribute(_el, "ref", refTarget);
return _el;
};
const template9 = () => {
var _el = _tmpl$2.cloneNode(true);
effect(() => {
return setAttribute(_el, "ref", (e) => console.log(e));
});
return _el;
};
const template10 = () => {
var _el = _tmpl$2.cloneNode(true);
effect(() => {
return setAttribute(_el, "ref", refFactory());
});
return _el;
};
const template11 = () => {
var _el = _tmpl$6.cloneNode(true);
setAttribute(_el, "use:another", thing);
return _el;
};
const template12 = () => {
var _el = _tmpl$2.cloneNode(true);
setAttribute(_el, "prop:htmlFor", thing);
return _el;
};
const template13 = _tmpl$8.cloneNode(true);
const template14 = () => {
var _el = _tmpl$8.cloneNode(true);
effect(() => {
return setAttribute(_el, "checked", state.visible);
});
return _el;
};
const template15 = _tmpl$10.cloneNode(true);
const template16 = () => {
var _el = _tmpl$10.cloneNode(true);
effect(() => {
return setAttribute(_el, "classList", {
hi: "k",
});
});
return _el;
};
const template17 = () => {
var _el = _tmpl$11.cloneNode(true);
effect(() => {
return setAttribute(_el, "classList", {
a: true,
b: true,
c: true,
});
});
effect(() => {
return (_el.$$click = increment);
});
return _el;
};
const template18 = _tmpl$2.cloneNode(true);

View File

@@ -0,0 +1,241 @@
const _tmpl$ = /*#__PURE__*/ _$template(
`<div id="main"><h1 class="base selected" id="my-h1" disabled readonly=""><a href="/">Welcome</a></h1></div>`,
6
),
_tmpl$2 = /*#__PURE__*/ _$template(
`<div><div></div><div> </div><div></div></div>`,
8
),
_tmpl$3 = /*#__PURE__*/ _$template(`<div></div>`, 2),
_tmpl$4 = /*#__PURE__*/ _$template(`<div class="a b"></div>`, 2),
_tmpl$5 = /*#__PURE__*/ _$template(`<input type="checkbox">`, 1),
_tmpl$6 = /*#__PURE__*/ _$template(`<div class="\`a">\`$\`</div>`, 2),
_tmpl$7 = /*#__PURE__*/ _$template(
`<button class="static hi" type="button">Write</button>`,
2
),
_tmpl$8 = /*#__PURE__*/ _$template(`<button class="a b c">Hi</button>`, 2);
const selected = true;
let id = "my-h1";
let link;
const template = (() => {
const _el$ = _tmpl$.cloneNode(true),
_el$2 = _el$.firstChild,
_el$3 = _el$2.firstChild;
_$spread(_el$, results, false, true);
_el$.classList.toggle("selected", unknown);
_el$.style.setProperty("color", color);
_$spread(_el$2, results, false, true);
_el$2.style.setProperty("margin-right", "40px");
const _ref$ = link;
typeof _ref$ === "function" ? _ref$(_el$3) : (link = _el$3);
_$classList(_el$3, {
"ccc ddd": true,
});
_el$3.readOnly = value;
_$effect(
(_p$) => {
const _v$ = welcoming(),
_v$2 = color(),
_v$3 = !!dynamic();
_v$ !== _p$._v$ && _$setAttribute(_el$2, "title", (_p$._v$ = _v$));
_v$2 !== _p$._v$2 &&
_el$2.style.setProperty("background-color", (_p$._v$2 = _v$2));
_v$3 !== _p$._v$3 && _el$2.classList.toggle("dynamic", (_p$._v$3 = _v$3));
return _p$;
},
{
_v$: undefined,
_v$2: undefined,
_v$3: undefined,
}
);
return _el$;
})();
const template2 = (() => {
const _el$4 = _tmpl$2.cloneNode(true),
_el$5 = _el$4.firstChild,
_el$6 = _el$5.nextSibling,
_el$7 = _el$6.firstChild,
_el$8 = _el$6.nextSibling;
_$spread(_el$4, () => getProps("test"), false, true);
_el$5.textContent = rowId;
_el$8.innerHTML = "<div/>";
_$effect(() => (_el$7.data = row.label));
return _el$4;
})();
const template3 = (() => {
const _el$9 = _tmpl$3.cloneNode(true);
_$setAttribute(_el$9, "id", state.id);
_el$9.style.setProperty("background-color", state.color);
_el$9.textContent = state.content;
_$effect(() => _$setAttribute(_el$9, "name", state.name));
return _el$9;
})();
const template4 = (() => {
const _el$10 = _tmpl$3.cloneNode(true);
_$classList(_el$10, {
"ccc:ddd": true,
});
_$effect(() => _$className(_el$10, `hi ${state.class || ""}`));
return _el$10;
})();
const template5 = _tmpl$4.cloneNode(true);
const template6 = (() => {
const _el$12 = _tmpl$3.cloneNode(true);
_el$12.textContent = "Hi";
_$effect((_$p) => _$style(_el$12, someStyle(), _$p));
return _el$12;
})();
const template7 = (() => {
const _el$13 = _tmpl$3.cloneNode(true);
_$effect(
(_p$) => {
const _v$4 = {
"background-color": color(),
"margin-right": "40px",
...props.style,
},
_v$5 = props.top,
_v$6 = !!props.active;
_p$._v$4 = _$style(_el$13, _v$4, _p$._v$4);
_v$5 !== _p$._v$5 &&
_el$13.style.setProperty("padding-top", (_p$._v$5 = _v$5));
_v$6 !== _p$._v$6 &&
_el$13.classList.toggle("my-class", (_p$._v$6 = _v$6));
return _p$;
},
{
_v$4: undefined,
_v$5: undefined,
_v$6: undefined,
}
);
return _el$13;
})();
let refTarget;
const template8 = (() => {
const _el$14 = _tmpl$3.cloneNode(true);
const _ref$2 = refTarget;
typeof _ref$2 === "function" ? _ref$2(_el$14) : (refTarget = _el$14);
return _el$14;
})();
const template9 = (() => {
const _el$15 = _tmpl$3.cloneNode(true);
((e) => console.log(e))(_el$15);
return _el$15;
})();
const template10 = (() => {
const _el$16 = _tmpl$3.cloneNode(true);
const _ref$3 = refFactory();
typeof _ref$3 === "function" && _ref$3(_el$16);
return _el$16;
})();
const template11 = (() => {
const _el$17 = _tmpl$3.cloneNode(true);
zero(_el$17, () => 0);
another(_el$17, () => thing);
something(_el$17, () => true);
return _el$17;
})();
const template12 = (() => {
const _el$18 = _tmpl$3.cloneNode(true);
_el$18.htmlFor = thing;
return _el$18;
})();
const template13 = (() => {
const _el$19 = _tmpl$5.cloneNode(true);
_el$19.checked = true;
return _el$19;
})();
const template14 = (() => {
const _el$20 = _tmpl$5.cloneNode(true);
_$effect(() => (_el$20.checked = state.visible));
return _el$20;
})();
const template15 = _tmpl$6.cloneNode(true);
const template16 = _tmpl$7.cloneNode(true);
const template17 = (() => {
const _el$23 = _tmpl$8.cloneNode(true);
_$addEventListener(_el$23, "click", increment, true);
return _el$23;
})();
const template18 = (() => {
const _el$24 = _tmpl$3.cloneNode(true);
_$spread(
_el$24,
() => ({
get [key()]() {
return props.value;
},
}),
false,
false
);
return _el$24;
})();
_$delegateEvents(["click"]);

View File

@@ -0,0 +1,161 @@
import { Show } from "somewhere";
const Child = (props) => {
const [s, set] = createSignal();
return (
<>
<div ref={props.ref}>Hello {props.name}</div>
<div ref={set}>{props.children}</div>
</>
);
};
const template = (props) => {
let childRef;
const { content } = props;
return (
<div>
<Child name="John" {...props} ref={childRef} booleanProperty>
<div>From Parent</div>
</Child>
<Child name="Jason" {...dynamicSpread()} ref={props.ref}>
{/* Comment Node */}
<div>{content}</div>
</Child>
<Context.Consumer ref={props.consumerRef()}>
{(context) => context}
</Context.Consumer>
</div>
);
};
const template2 = (
<Child
name="Jake"
dynamic={state.data}
stale={/*@once*/ state.data}
handleClick={clickHandler}
hyphen-ated={state.data}
ref={(el) => (e = el)}
/>
);
const template3 = (
<Child>
<div />
<div />
<div />
After
</Child>
);
const [s, set] = createSignal();
const template4 = <Child ref={set}>{<div />}</Child>;
const template5 = <Child dynamic={state.dynamic}>{state.dynamic}</Child>;
// builtIns
const template6 = (
<For each={state.list} fallback={<Loading />}>
{(item) => <Show when={state.condition}>{item}</Show>}
</For>
);
const template7 = (
<Child>
<div />
{state.dynamic}
</Child>
);
const template8 = (
<Child>
{(item) => item}
{(item) => item}
</Child>
);
const template9 = <_garbage>Hi</_garbage>;
const template10 = (
<div>
<Link>new</Link>
{" | "}
<Link>comments</Link>
{" | "}
<Link>show</Link>
{" | "}
<Link>ask</Link>
{" | "}
<Link>jobs</Link>
{" | "}
<Link>submit</Link>
</div>
);
const template11 = (
<div>
<Link>new</Link>
{" | "}
<Link>comments</Link>
<Link>show</Link>
{" | "}
<Link>ask</Link>
<Link>jobs</Link>
{" | "}
<Link>submit</Link>
</div>
);
const template12 = (
<div>
{" | "}
<Link>comments</Link>
{" | "}
{" | "}
{" | "}
<Link>show</Link>
{" | "}
</div>
);
class Template13 {
render() {
<Component prop={this.something} onClick={() => this.shouldStay}>
<Nested prop={this.data}>{this.content}</Nested>
</Component>;
}
}
const Template14 = <Component>{data()}</Component>;
const Template15 = <Component {...props} />;
const Template16 = <Component something={something} {...props} />;
const Template17 = (
<Pre>
<span>1</span> <span>2</span> <span>3</span>
</Pre>
);
const Template18 = (
<Pre>
<span>1</span>
<span>2</span>
<span>3</span>
</Pre>
);
const Template19 = <Component {...s.dynamic()} />;
const Template20 = <Component class={prop.red ? "red" : "green"} />;
const template21 = (
<Component
{...{
get [key()]() {
return props.value;
},
}}
/>
);

View File

@@ -0,0 +1,205 @@
var _tmpl = _template$("<div><div>From Parent</div><div</div></div>", 9), _tmpl$1 = _template$("<div> | | | | | </div>", 8), _tmpl$2 = _template$("<div> | | | </div>", 8);
import {Show} from "somewhere";
const Child = (props) => {
const [s, set] = createSignal();
return ;
};
const template = (props) => {
let childRef;
const { content } = props;
return () => {
var _tmpl = _tmpl.cloneNode(true);
insert(_tmpl, createComponent(Child, {
name: "John",
ref: childRef,
booleanProperty: true
}), null);
insert(_tmpl, content, null);
insert(_tmpl, createComponent(Child, {
name: "Jason",
ref: props.ref
}), null);
insert(_tmpl, createComponent(Context.Consumer, {
ref: props.consumerRef(),
get children: [
(context) => context
]
}), null);
return _tmpl;
};
};
const template2 = createComponent(Child, {
name: "Jake",
dynamic: state.data,
stale: state.data,
handleClick: clickHandler,
"hyphen-ated": state.data,
get ref: () => {
return (el) => e = el;
}
});
const template3 = createComponent(Child, {
get children: [
"After"
]
});
const [s, set] = createSignal();
const template4 = createComponent(Child, {
ref: set
});
const template5 = createComponent(Child, {
dynamic: state.dynamic,
get children: [
state.dynamic
]
});
const template6 = createComponent(For, {
each: state.list,
fallback: ,
get children: [
(item) => createComponent(Show, {
when: state.condition,
get children: [
item
]
})
]
});
const template7 = createComponent(Child, {
get children: [
state.dynamic
]
});
const template8 = createComponent(Child, {
get children: [
(item) => item,
(item) => item
]
});
const template9 = createComponent(_garbage, {
get children: [
"Hi"
]
});
const template10 = () => {
var _tmpl$1 = _tmpl$1.cloneNode(true);
insert(_tmpl$1, createComponent(Link, {
get children: [
"new"
]
}), null);
insert(_tmpl$1, createComponent(Link, {
get children: [
"comments"
]
}), null);
insert(_tmpl$1, createComponent(Link, {
get children: [
"show"
]
}), null);
insert(_tmpl$1, createComponent(Link, {
get children: [
"ask"
]
}), null);
insert(_tmpl$1, createComponent(Link, {
get children: [
"jobs"
]
}), null);
insert(_tmpl$1, createComponent(Link, {
get children: [
"submit"
]
}), null);
return _tmpl$1;
};
const template11 = () => {
var _tmpl$2 = _tmpl$2.cloneNode(true);
insert(_tmpl$2, createComponent(Link, {
get children: [
"new"
]
}), null);
insert(_tmpl$2, createComponent(Link, {
get children: [
"comments"
]
}), null);
insert(_tmpl$2, createComponent(Link, {
get children: [
"show"
]
}), null);
insert(_tmpl$2, createComponent(Link, {
get children: [
"ask"
]
}), null);
insert(_tmpl$2, createComponent(Link, {
get children: [
"jobs"
]
}), null);
insert(_tmpl$2, createComponent(Link, {
get children: [
"submit"
]
}), null);
return _tmpl$2;
};
const template12 = () => {
var _tmpl$1 = _tmpl$1.cloneNode(true);
insert(_tmpl$1, createComponent(Link, {
get children: [
"comments"
]
}), null);
insert(_tmpl$1, createComponent(Link, {
get children: [
"show"
]
}), null);
return _tmpl$1;
};
class Template13 {
render() {
createComponent(Component, {
prop: this.something,
get onClick: () => {
return () => this.shouldStay;
},
get children: [
createComponent(Nested, {
prop: this.data,
get children: [
this.content
]
})
]
});
}
}
const Template14 = createComponent(Component, {
get children: [
data()
]
});
const Template15 = createComponent(Component, {});
const Template16 = createComponent(Component, {
something
});
const Template17 = createComponent(Pre, {
get children: [
" ",
" "
]
});
const Template18 = createComponent(Pre, {});
const Template19 = createComponent(Component, {});
const Template20 = createComponent(Component, {
class: prop.red ? "red" : "green"
});
const template21 = createComponent(Component, {});

View File

@@ -0,0 +1,443 @@
import { template as _$template } from "r-dom";
import { memo as _$memo } from "r-dom";
import { For as _$For } from "r-dom";
import { createComponent as _$createComponent } from "r-dom";
import { mergeProps as _$mergeProps } from "r-dom";
import { insert as _$insert } from "r-dom";
const _tmpl$ = /*#__PURE__*/ _$template(`<div>Hello </div>`, 2),
_tmpl$2 = /*#__PURE__*/ _$template(`<div></div>`, 2),
_tmpl$3 = /*#__PURE__*/ _$template(`<div>From Parent</div>`, 2),
_tmpl$4 = /*#__PURE__*/ _$template(
`<div> | <!> | <!> | <!> | <!> | </div>`,
6
),
_tmpl$5 = /*#__PURE__*/ _$template(`<div> | <!> | <!> | </div>`, 4),
_tmpl$6 = /*#__PURE__*/ _$template(`<div> | <!> | | | <!> | </div>`, 4),
_tmpl$7 = /*#__PURE__*/ _$template(`<span>1</span>`, 2),
_tmpl$8 = /*#__PURE__*/ _$template(`<span>2</span>`, 2),
_tmpl$9 = /*#__PURE__*/ _$template(`<span>3</span>`, 2);
import { Show } from "somewhere";
const Child = (props) => {
const [s, set] = createSignal();
return [
(() => {
const _el$ = _tmpl$.cloneNode(true),
_el$2 = _el$.firstChild;
const _ref$ = props.ref;
typeof _ref$ === "function" ? _ref$(_el$) : (props.ref = _el$);
_$insert(_el$, () => props.name, null);
return _el$;
})(),
(() => {
const _el$3 = _tmpl$2.cloneNode(true);
set(_el$3);
_$insert(_el$3, () => props.children);
return _el$3;
})(),
];
};
const template = (props) => {
let childRef;
const { content } = props;
return (() => {
const _el$4 = _tmpl$2.cloneNode(true);
_$insert(
_el$4,
_$createComponent(
Child,
_$mergeProps(
{
name: "John",
},
props,
{
ref(r$) {
const _ref$2 = childRef;
typeof _ref$2 === "function" ? _ref$2(r$) : (childRef = r$);
},
booleanProperty: true,
get children() {
return _tmpl$3.cloneNode(true);
},
}
)
),
null
);
_$insert(
_el$4,
_$createComponent(
Child,
_$mergeProps(
{
name: "Jason",
},
dynamicSpread,
{
ref(r$) {
const _ref$3 = props.ref;
typeof _ref$3 === "function" ? _ref$3(r$) : (props.ref = r$);
},
get children() {
const _el$6 = _tmpl$2.cloneNode(true);
_$insert(_el$6, content);
return _el$6;
},
}
)
),
null
);
_$insert(
_el$4,
_$createComponent(Context.Consumer, {
ref(r$) {
const _ref$4 = props.consumerRef();
typeof _ref$4 === "function" && _ref$4(r$);
},
children: (context) => context,
}),
null
);
return _el$4;
})();
};
const template2 = _$createComponent(Child, {
name: "Jake",
get dynamic() {
return state.data;
},
stale: state.data,
handleClick: clickHandler,
get ["hyphen-ated"]() {
return state.data;
},
ref: (el) => (e = el),
});
const template3 = _$createComponent(Child, {
get children() {
return [
_tmpl$2.cloneNode(true),
_tmpl$2.cloneNode(true),
_tmpl$2.cloneNode(true),
"After",
];
},
});
const [s, set] = createSignal();
const template4 = _$createComponent(Child, {
ref: set,
get children() {
return _tmpl$2.cloneNode(true);
},
});
const template5 = _$createComponent(Child, {
get dynamic() {
return state.dynamic;
},
get children() {
return state.dynamic;
},
}); // builtIns
const template6 = _$createComponent(_$For, {
get each() {
return state.list;
},
get fallback() {
return _$createComponent(Loading, {});
},
children: (item) =>
_$createComponent(Show, {
get when() {
return state.condition;
},
children: item,
}),
});
const template7 = _$createComponent(Child, {
get children() {
return [_tmpl$2.cloneNode(true), _$memo(() => state.dynamic)];
},
});
const template8 = _$createComponent(Child, {
get children() {
return [(item) => item, (item) => item];
},
});
const template9 = _$createComponent(_garbage, {
children: "Hi",
});
const template10 = (() => {
const _el$12 = _tmpl$4.cloneNode(true),
_el$13 = _el$12.firstChild,
_el$18 = _el$13.nextSibling,
_el$14 = _el$18.nextSibling,
_el$19 = _el$14.nextSibling,
_el$15 = _el$19.nextSibling,
_el$20 = _el$15.nextSibling,
_el$16 = _el$20.nextSibling,
_el$21 = _el$16.nextSibling,
_el$17 = _el$21.nextSibling;
_$insert(
_el$12,
_$createComponent(Link, {
children: "new",
}),
_el$13
);
_$insert(
_el$12,
_$createComponent(Link, {
children: "comments",
}),
_el$18
);
_$insert(
_el$12,
_$createComponent(Link, {
children: "show",
}),
_el$19
);
_$insert(
_el$12,
_$createComponent(Link, {
children: "ask",
}),
_el$20
);
_$insert(
_el$12,
_$createComponent(Link, {
children: "jobs",
}),
_el$21
);
_$insert(
_el$12,
_$createComponent(Link, {
children: "submit",
}),
null
);
return _el$12;
})();
const template11 = (() => {
const _el$22 = _tmpl$5.cloneNode(true),
_el$23 = _el$22.firstChild,
_el$26 = _el$23.nextSibling,
_el$24 = _el$26.nextSibling,
_el$27 = _el$24.nextSibling,
_el$25 = _el$27.nextSibling;
_$insert(
_el$22,
_$createComponent(Link, {
children: "new",
}),
_el$23
);
_$insert(
_el$22,
_$createComponent(Link, {
children: "comments",
}),
_el$26
);
_$insert(
_el$22,
_$createComponent(Link, {
children: "show",
}),
_el$26
);
_$insert(
_el$22,
_$createComponent(Link, {
children: "ask",
}),
_el$27
);
_$insert(
_el$22,
_$createComponent(Link, {
children: "jobs",
}),
_el$27
);
_$insert(
_el$22,
_$createComponent(Link, {
children: "submit",
}),
null
);
return _el$22;
})();
const template12 = (() => {
const _el$28 = _tmpl$6.cloneNode(true),
_el$29 = _el$28.firstChild,
_el$34 = _el$29.nextSibling,
_el$30 = _el$34.nextSibling,
_el$35 = _el$30.nextSibling,
_el$33 = _el$35.nextSibling;
_$insert(
_el$28,
_$createComponent(Link, {
children: "comments",
}),
_el$34
);
_$insert(
_el$28,
_$createComponent(Link, {
children: "show",
}),
_el$35
);
return _el$28;
})();
class Template13 {
render() {
const _self$ = this;
_$createComponent(Component, {
get prop() {
return _self$.something;
},
onClick: () => _self$.shouldStay,
get children() {
return _$createComponent(Nested, {
get prop() {
return _self$.data;
},
get children() {
return _self$.content;
},
});
},
});
}
}
const Template14 = _$createComponent(Component, {
get children() {
return data();
},
});
const Template15 = _$createComponent(Component, props);
const Template16 = _$createComponent(
Component,
_$mergeProps(
{
something: something,
},
props
)
);
const Template17 = _$createComponent(Pre, {
get children() {
return [
_tmpl$7.cloneNode(true),
" ",
_tmpl$8.cloneNode(true),
" ",
_tmpl$9.cloneNode(true),
];
},
});
const Template18 = _$createComponent(Pre, {
get children() {
return [
_tmpl$7.cloneNode(true),
_tmpl$8.cloneNode(true),
_tmpl$9.cloneNode(true),
];
},
});
const Template19 = _$createComponent(
Component,
_$mergeProps(() => s.dynamic())
);
const Template20 = _$createComponent(Component, {
get ["class"]() {
return prop.red ? "red" : "green";
},
});
const template21 = _$createComponent(
Component,
_$mergeProps(() => ({
get [key()]() {
return props.value;
},
}))
);

View File

@@ -0,0 +1,71 @@
const template1 = <div>{simple}</div>;
const template2 = <div>{state.dynamic}</div>;
const template3 = <div>{simple ? good : bad}</div>;
const template4 = <div>{simple ? good() : bad}</div>;
const template5 = <div>{state.dynamic ? good() : bad}</div>;
const template6 = <div>{state.dynamic && good()}</div>;
const template7 = (
<div>{state.count > 5 ? (state.dynamic ? best : good()) : bad}</div>
);
const template8 = <div>{state.dynamic && state.something && good()}</div>;
const template9 = <div>{(state.dynamic && good()) || bad}</div>;
const template10 = (
<div>{state.a ? "a" : state.b ? "b" : state.c ? "c" : "fallback"}</div>
);
const template11 = (
<div>{state.a ? a() : state.b ? b() : state.c ? "c" : "fallback"}</div>
);
const template12 = <Comp render={state.dynamic ? good() : bad} />;
// no dynamic predicate
const template13 = <Comp render={state.dynamic ? good : bad} />;
const template14 = <Comp render={state.dynamic && good()} />;
// no dynamic predicate
const template15 = <Comp render={state.dynamic && good} />;
const template16 = <Comp render={state.dynamic || good()} />;
const template17 = <Comp render={state.dynamic ? <Comp /> : <Comp />} />;
const template18 = <Comp>{state.dynamic ? <Comp /> : <Comp />}</Comp>;
const template19 = <div innerHTML={state.dynamic ? <Comp /> : <Comp />} />;
const template20 = <div>{state.dynamic ? <Comp /> : <Comp />}</div>;
const template21 = <Comp render={state?.dynamic ? "a" : "b"} />;
const template22 = <Comp>{state?.dynamic ? "a" : "b"}</Comp>;
const template23 = <div innerHTML={state?.dynamic ? "a" : "b"} />;
const template24 = <div>{state?.dynamic ? "a" : "b"}</div>;
const template25 = <Comp render={state.dynamic ?? <Comp />} />;
const template26 = <Comp>{state.dynamic ?? <Comp />}</Comp>;
const template27 = <div innerHTML={state.dynamic ?? <Comp />} />;
const template28 = <div>{state.dynamic ?? <Comp />}</div>;
const template29 = <div>{(thing() && thing1()) ?? thing2() ?? thing3()}</div>;
const template30 = <div>{thing() || thing1() || thing2()}</div>;
const template31 = (
<Comp value={count() ? (count() ? count() : count()) : count()} />
);

View File

@@ -0,0 +1,144 @@
var _tmpl = template("<div</div>", 2), _tmpl$1 = template("<div/>", 0);
const template1 = () => {
var _tmpl = _tmpl.cloneNode(true);
insert(_tmpl, simple, null);
return _tmpl;
};
const template2 = () => {
var _tmpl = _tmpl.cloneNode(true);
insert(_tmpl, state.dynamic, null);
return _tmpl;
};
const template3 = () => {
var _tmpl = _tmpl.cloneNode(true);
insert(_tmpl, simple ? good : bad, null);
return _tmpl;
};
const template4 = () => {
var _tmpl = _tmpl.cloneNode(true);
insert(_tmpl, simple ? good() : bad, null);
return _tmpl;
};
const template5 = () => {
var _tmpl = _tmpl.cloneNode(true);
insert(_tmpl, state.dynamic ? good() : bad, null);
return _tmpl;
};
const template6 = () => {
var _tmpl = _tmpl.cloneNode(true);
insert(_tmpl, state.dynamic && good(), null);
return _tmpl;
};
const template7 = () => {
var _tmpl = _tmpl.cloneNode(true);
insert(_tmpl, state.count > 5 ? state.dynamic ? best : good() : bad, null);
return _tmpl;
};
const template8 = () => {
var _tmpl = _tmpl.cloneNode(true);
insert(_tmpl, state.dynamic && state.something && good(), null);
return _tmpl;
};
const template9 = () => {
var _tmpl = _tmpl.cloneNode(true);
insert(_tmpl, state.dynamic && good() || bad, null);
return _tmpl;
};
const template10 = () => {
var _tmpl = _tmpl.cloneNode(true);
insert(_tmpl, state.a ? "a" : state.b ? "b" : state.c ? "c" : "fallback", null);
return _tmpl;
};
const template11 = () => {
var _tmpl = _tmpl.cloneNode(true);
insert(_tmpl, state.a ? a() : state.b ? b() : state.c ? "c" : "fallback", null);
return _tmpl;
};
const template12 = createComponent(Comp, {
render: state.dynamic ? good() : bad
});
const template13 = createComponent(Comp, {
render: state.dynamic ? good : bad
});
const template14 = createComponent(Comp, {
render: state.dynamic && good()
});
const template15 = createComponent(Comp, {
render: state.dynamic && good
});
const template16 = createComponent(Comp, {
render: state.dynamic || good()
});
const template17 = createComponent(Comp, {
render: state.dynamic ? createComponent(Comp, {}) : createComponent(Comp, {})
});
const template18 = createComponent(Comp, {
get children: [
state.dynamic ? createComponent(Comp, {}) : createComponent(Comp, {})
]
});
const template19 = () => {
var _el = _tmpl$1.cloneNode(true);
effect(() => {
return setAttribute(_el, "innerHTML", state.dynamic ? createComponent(Comp, {}) : createComponent(Comp, {}));
});
return _el;
};
const template20 = () => {
var _tmpl = _tmpl.cloneNode(true);
insert(_tmpl, state.dynamic ? createComponent(Comp, {}) : createComponent(Comp, {}), null);
return _tmpl;
};
const template21 = createComponent(Comp, {
render: state?.dynamic ? "a" : "b"
});
const template22 = createComponent(Comp, {
get children: [
state?.dynamic ? "a" : "b"
]
});
const template23 = () => {
var _el = _tmpl$1.cloneNode(true);
effect(() => {
return setAttribute(_el, "innerHTML", state?.dynamic ? "a" : "b");
});
return _el;
};
const template24 = () => {
var _tmpl = _tmpl.cloneNode(true);
insert(_tmpl, state?.dynamic ? "a" : "b", null);
return _tmpl;
};
const template25 = createComponent(Comp, {
render: state.dynamic ?? createComponent(Comp, {})
});
const template26 = createComponent(Comp, {
get children: [
state.dynamic ?? createComponent(Comp, {})
]
});
const template27 = () => {
var _el = _tmpl$1.cloneNode(true);
effect(() => {
return setAttribute(_el, "innerHTML", state.dynamic ?? createComponent(Comp, {}));
});
return _el;
};
const template28 = () => {
var _tmpl = _tmpl.cloneNode(true);
insert(_tmpl, state.dynamic ?? createComponent(Comp, {}), null);
return _tmpl;
};
const template29 = () => {
var _tmpl = _tmpl.cloneNode(true);
insert(_tmpl, (thing() && thing1()) ?? thing2() ?? thing3(), null);
return _tmpl;
};
const template30 = () => {
var _tmpl = _tmpl.cloneNode(true);
insert(_tmpl, thing() || thing1() || thing2(), null);
return _tmpl;
};
const template31 = createComponent(Comp, {
value: count() ? count() ? count() : count() : count()
});

View File

@@ -0,0 +1,319 @@
import { template as _$template } from "r-dom";
import { effect as _$effect } from "r-dom";
import { createComponent as _$createComponent } from "r-dom";
import { memo as _$memo } from "r-dom";
import { insert as _$insert } from "r-dom";
const _tmpl$ = /*#__PURE__*/ _$template(`<div></div>`, 2);
const template1 = (() => {
const _el$ = _tmpl$.cloneNode(true);
_$insert(_el$, simple);
return _el$;
})();
const template2 = (() => {
const _el$2 = _tmpl$.cloneNode(true);
_$insert(_el$2, () => state.dynamic);
return _el$2;
})();
const template3 = (() => {
const _el$3 = _tmpl$.cloneNode(true);
_$insert(_el$3, simple ? good : bad);
return _el$3;
})();
const template4 = (() => {
const _el$4 = _tmpl$.cloneNode(true);
_$insert(_el$4, () => (simple ? good() : bad));
return _el$4;
})();
const template5 = (() => {
const _el$5 = _tmpl$.cloneNode(true);
_$insert(
_el$5,
(() => {
const _c$ = _$memo(() => !!state.dynamic, true);
return () => (_c$() ? good() : bad);
})()
);
return _el$5;
})();
const template6 = (() => {
const _el$6 = _tmpl$.cloneNode(true);
_$insert(
_el$6,
(() => {
const _c$2 = _$memo(() => !!state.dynamic, true);
return () => _c$2() && good();
})()
);
return _el$6;
})();
const template7 = (() => {
const _el$7 = _tmpl$.cloneNode(true);
_$insert(
_el$7,
(() => {
const _c$3 = _$memo(() => state.count > 5, true);
return () =>
_c$3()
? (() => {
const _c$4 = _$memo(() => !!state.dynamic, true);
return () => (_c$4() ? best : good());
})()
: bad;
})()
);
return _el$7;
})();
const template8 = (() => {
const _el$8 = _tmpl$.cloneNode(true);
_$insert(
_el$8,
(() => {
const _c$5 = _$memo(() => !!(state.dynamic && state.something), true);
return () => _c$5() && good();
})()
);
return _el$8;
})();
const template9 = (() => {
const _el$9 = _tmpl$.cloneNode(true);
_$insert(
_el$9,
(() => {
const _c$6 = _$memo(() => !!state.dynamic, true);
return () => (_c$6() && good()) || bad;
})()
);
return _el$9;
})();
const template10 = (() => {
const _el$10 = _tmpl$.cloneNode(true);
_$insert(_el$10, () =>
state.a ? "a" : state.b ? "b" : state.c ? "c" : "fallback"
);
return _el$10;
})();
const template11 = (() => {
const _el$11 = _tmpl$.cloneNode(true);
_$insert(
_el$11,
(() => {
const _c$7 = _$memo(() => !!state.a, true);
return () =>
_c$7()
? a()
: (() => {
const _c$8 = _$memo(() => !!state.b, true);
return () => (_c$8() ? b() : state.c ? "c" : "fallback");
})();
})()
);
return _el$11;
})();
const template12 = _$createComponent(Comp, {
get render() {
return _$memo(() => !!state.dynamic, true)() ? good() : bad;
},
}); // no dynamic predicate
const template13 = _$createComponent(Comp, {
get render() {
return state.dynamic ? good : bad;
},
});
const template14 = _$createComponent(Comp, {
get render() {
return _$memo(() => !!state.dynamic, true)() && good();
},
}); // no dynamic predicate
const template15 = _$createComponent(Comp, {
get render() {
return state.dynamic && good;
},
});
const template16 = _$createComponent(Comp, {
get render() {
return state.dynamic || good();
},
});
const template17 = _$createComponent(Comp, {
get render() {
return _$memo(() => !!state.dynamic, true)()
? _$createComponent(Comp, {})
: _$createComponent(Comp, {});
},
});
const template18 = _$createComponent(Comp, {
get children() {
return _$memo(() => !!state.dynamic, true)()
? _$createComponent(Comp, {})
: _$createComponent(Comp, {});
},
});
const template19 = (() => {
const _el$12 = _tmpl$.cloneNode(true);
_$effect(
() =>
(_el$12.innerHTML = state.dynamic
? _$createComponent(Comp, {})
: _$createComponent(Comp, {}))
);
return _el$12;
})();
const template20 = (() => {
const _el$13 = _tmpl$.cloneNode(true);
_$insert(
_el$13,
(() => {
const _c$9 = _$memo(() => !!state.dynamic, true);
return () =>
_c$9() ? _$createComponent(Comp, {}) : _$createComponent(Comp, {});
})()
);
return _el$13;
})();
const template21 = _$createComponent(Comp, {
get render() {
return state?.dynamic ? "a" : "b";
},
});
const template22 = _$createComponent(Comp, {
get children() {
return state?.dynamic ? "a" : "b";
},
});
const template23 = (() => {
const _el$14 = _tmpl$.cloneNode(true);
_$effect(() => (_el$14.innerHTML = state?.dynamic ? "a" : "b"));
return _el$14;
})();
const template24 = (() => {
const _el$15 = _tmpl$.cloneNode(true);
_$insert(_el$15, () => (state?.dynamic ? "a" : "b"));
return _el$15;
})();
const template25 = _$createComponent(Comp, {
get render() {
return state.dynamic ?? _$createComponent(Comp, {});
},
});
const template26 = _$createComponent(Comp, {
get children() {
return state.dynamic ?? _$createComponent(Comp, {});
},
});
const template27 = (() => {
const _el$16 = _tmpl$.cloneNode(true);
_$effect(
() => (_el$16.innerHTML = state.dynamic ?? _$createComponent(Comp, {}))
);
return _el$16;
})();
const template28 = (() => {
const _el$17 = _tmpl$.cloneNode(true);
_$insert(_el$17, () => state.dynamic ?? _$createComponent(Comp, {}));
return _el$17;
})();
const template29 = (() => {
const _el$18 = _tmpl$.cloneNode(true);
_$insert(
_el$18,
(() => {
const _c$10 = _$memo(() => !!thing(), true);
return () => (_c$10() && thing1()) ?? thing2() ?? thing3();
})()
);
return _el$18;
})();
const template30 = (() => {
const _el$19 = _tmpl$.cloneNode(true);
_$insert(_el$19, () => thing() || thing1() || thing2());
return _el$19;
})();
const template31 = _$createComponent(Comp, {
get value() {
return _$memo(() => !!count(), true)()
? _$memo(() => !!count(), true)()
? count()
: count()
: count();
},
});

View File

@@ -0,0 +1,29 @@
const template = (
<my-element
some-attr={name}
notProp={data}
attr:my-attr={data}
prop:someProp={data}
/>
);
const template2 = (
<my-element
some-attr={state.name}
notProp={state.data}
attr:my-attr={state.data}
prop:someProp={state.data}
/>
);
const template3 = (
<my-element>
<header slot="head">Title</header>
</my-element>
);
const template4 = (
<>
<slot name="head"></slot>
</>
);

View File

@@ -0,0 +1,27 @@
var _tmpl = _template$("<my-element/>", 0), _tmpl$2 = _template$('<my-element><header slot="head">Title</header></my-element>', 4);
const template = () => {
var _el = _tmpl.cloneNode(true);
setAttribute(_el, "some-attr", name);
setAttribute(_el, "notProp", data);
setAttribute(_el, "attr:my-attr", data);
setAttribute(_el, "prop:someProp", data);
return _el;
};
const template2 = () => {
var _el = _tmpl.cloneNode(true);
effect(() => {
return setAttribute(_el, "some-attr", state.name);
});
effect(() => {
return setAttribute(_el, "notProp", state.data);
});
effect(() => {
return setAttribute(_el, "attr:my-attr", state.data);
});
effect(() => {
return setAttribute(_el, "prop:someProp", state.data);
});
return _el;
};
const template3 = _tmpl$2.cloneNode(true);
const template4 = ;

View File

@@ -0,0 +1,66 @@
import { template as _$template } from "r-dom";
import { effect as _$effect } from "r-dom";
import { getOwner as _$getOwner } from "r-dom";
import { setAttribute as _$setAttribute } from "r-dom";
const _tmpl$ = /*#__PURE__*/ _$template(`<my-element></my-element>`, 2),
_tmpl$2 = /*#__PURE__*/ _$template(
`<my-element><header slot="head">Title</header></my-element>`,
4
),
_tmpl$3 = /*#__PURE__*/ _$template(`<slot name="head"></slot>`, 2);
const template = (() => {
const _el$ = document.importNode(_tmpl$, true);
_el$.someAttr = name;
_el$.notprop = data;
_$setAttribute(_el$, "my-attr", data);
_el$.someProp = data;
_el$._$owner = _$getOwner();
return _el$;
})();
const template2 = (() => {
const _el$2 = document.importNode(_tmpl$, true);
_el$2._$owner = _$getOwner();
_$effect(
(_p$) => {
const _v$ = state.name,
_v$2 = state.data,
_v$3 = state.data,
_v$4 = state.data;
_v$ !== _p$._v$ && (_el$2.someAttr = _p$._v$ = _v$);
_v$2 !== _p$._v$2 && (_el$2.notprop = _p$._v$2 = _v$2);
_v$3 !== _p$._v$3 && _$setAttribute(_el$2, "my-attr", (_p$._v$3 = _v$3));
_v$4 !== _p$._v$4 && (_el$2.someProp = _p$._v$4 = _v$4);
return _p$;
},
{
_v$: undefined,
_v$2: undefined,
_v$3: undefined,
_v$4: undefined,
}
);
return _el$2;
})();
const template3 = (() => {
const _el$3 = document.importNode(_tmpl$2, true);
_el$3._$owner = _$getOwner();
return _el$3;
})();
const template4 = (() => {
const _el$4 = _tmpl$3.cloneNode(true);
_el$4._$owner = _$getOwner();
return _el$4;
})();

View File

@@ -0,0 +1,32 @@
function hoisted1() {
console.log("hoisted");
}
const hoisted2 = () => console.log("hoisted delegated");
const template = (
<div id="main">
<button onchange={() => console.log("bound")}>Change Bound</button>
<button onChange={[(id) => console.log("bound", id), id]}>
Change Bound
</button>
<button onchange={handler}>Change Bound</button>
<button onchange={[handler]}>Change Bound</button>
<button onchange={hoisted1}>Change Bound</button>
<button onclick={() => console.log("delegated")}>Click Delegated</button>
<button onClick={[(id) => console.log("delegated", id), rowId]}>
Click Delegated
</button>
<button onClick={handler}>Click Delegated</button>
<button onClick={[handler]}>Click Delegated</button>
<button onClick={hoisted2}>Click Delegated</button>
<button
on:click={() => console.log("listener")}
on:CAPS-ev={() => console.log("custom")}
>
Click Listener
</button>
<button oncapture:camelClick={() => console.log("listener")}>
Click Capture
</button>
</div>
);

View File

@@ -0,0 +1,57 @@
var _tmpl$1 = _template$(
'<div id="main"><button>Change Bound</button><button>Change Bound</button><button>Change Bound</button><button>Change Bound</button><button>Change Bound</button><button>Click Delegated</button><button>Click Delegated</button><button>Click Delegated</button><button>Click Delegated</button><button>Click Delegated</button><button>Click Listener</button><button>Click Capture</button></div>',
26
);
function hoisted1() {
console.log("hoisted");
}
const hoisted2 = () => console.log("hoisted delegated");
const template = () => {
var _el = _tmpl.cloneNode(true),
_el$1 = _el.firstChild,
_el$2 = _el$1.nextSibling,
_el$3 = _el$2.nextSibling,
_el$4 = _el$3.nextSibling,
_el$5 = _el$4.nextSibling,
_el$6 = _el$5.nextSibling,
_el$7 = _el$6.nextSibling,
_el$8 = _el$7.nextSibling,
_el$9 = _el$8.nextSibling,
_el$10 = _el$9.nextSibling,
_el$11 = _el$10.nextSibling;
effect(() => {
return setAttribute(_el, "onchange", () => console.log("bound"));
});
effect(() => {
return setAttribute(_el$1, "onChange", [
(id) => console.log("bound", id),
id,
]);
});
setAttribute(_el$2, "onchange", handler);
effect(() => {
return setAttribute(_el$3, "onchange", [handler]);
});
setAttribute(_el$4, "onchange", hoisted1);
_el$5.$$click = () => console.log("delegated");
effect(() => {
return (_el$6.$$click = [(id) => console.log("delegated", id), rowId]);
});
effect(() => {
return (_el$7.$$click = handler);
});
effect(() => {
return (_el$8.$$click = [handler]);
});
effect(() => {
return (_el$9.$$click = hoisted2);
});
_el$10.addEventListener("click", () => console.log("listener"));
_el$10.addEventListener("CAPS-ev", () => console.log("custom"));
_el$11.addEventListener(
"apture:camelClick",
() => console.log("listener"),
true
);
return _el;
};

View File

@@ -0,0 +1,63 @@
import { template as _$template } from "r-dom";
import { delegateEvents as _$delegateEvents } from "r-dom";
import { addEventListener as _$addEventListener } from "r-dom";
const _tmpl$ = /*#__PURE__*/ _$template(
`<div id="main"><button>Change Bound</button><button>Change Bound</button><button>Change Bound</button><button>Change Bound</button><button>Change Bound</button><button>Click Delegated</button><button>Click Delegated</button><button>Click Delegated</button><button>Click Delegated</button><button>Click Delegated</button><button>Click Listener</button><button>Click Capture</button></div>`,
26
);
function hoisted1() {
console.log("hoisted");
}
const hoisted2 = () => console.log("hoisted delegated");
const template = (() => {
const _el$ = _tmpl$.cloneNode(true),
_el$2 = _el$.firstChild,
_el$3 = _el$2.nextSibling,
_el$4 = _el$3.nextSibling,
_el$5 = _el$4.nextSibling,
_el$6 = _el$5.nextSibling,
_el$7 = _el$6.nextSibling,
_el$8 = _el$7.nextSibling,
_el$9 = _el$8.nextSibling,
_el$10 = _el$9.nextSibling,
_el$11 = _el$10.nextSibling,
_el$12 = _el$11.nextSibling,
_el$13 = _el$12.nextSibling;
_el$2.addEventListener("change", () => console.log("bound"));
_el$3.addEventListener("change", (e) =>
((id) => console.log("bound", id))(id, e)
);
_$addEventListener(_el$4, "change", handler);
_el$5.addEventListener("change", handler);
_el$6.addEventListener("change", hoisted1);
_el$7.$$click = () => console.log("delegated");
_el$8.$$click = (id) => console.log("delegated", id);
_el$8.$$clickData = rowId;
_$addEventListener(_el$9, "click", handler, true);
_el$10.$$click = handler;
_el$11.$$click = hoisted2;
_el$12.addEventListener("click", () => console.log("listener"));
_el$12.addEventListener("CAPS-ev", () => console.log("custom"));
_el$13.addEventListener("camelClick", () => console.log("listener"), true);
return _el$;
})();
_$delegateEvents(["click"]);

View File

@@ -0,0 +1,83 @@
const multiStatic = (
<>
<div>First</div>
<div>Last</div>
</>
);
const multiExpression = (
<>
<div>First</div>
{inserted}
<div>Last</div>
After
</>
);
const multiDynamic = (
<>
<div id={state.first}>First</div>
{state.inserted}
<div id={state.last}>Last</div>
After
</>
);
const singleExpression = <>{inserted}</>;
const singleDynamic = <>{inserted()}</>;
const firstStatic = (
<>
{inserted}
<div />
</>
);
const firstDynamic = (
<>
{inserted()}
<div />
</>
);
const firstComponent = (
<>
<Component />
<div />
</>
);
const lastStatic = (
<>
<div />
{inserted}
</>
);
const lastDynamic = (
<>
<div />
{inserted()}
</>
);
const lastComponent = (
<>
<div />
<Component />
</>
);
const spaces = (
<>
<span>1</span> <span>2</span> <span>3</span>
</>
);
const multiLineTrailing = (
<>
<span>1</span>
<span>2</span>
<span>3</span>
</>
);

View File

@@ -0,0 +1,13 @@
const multiStatic = ;
const multiExpression = ;
const multiDynamic = ;
const singleExpression = ;
const singleDynamic = ;
const firstStatic = ;
const firstDynamic = ;
const firstComponent = ;
const lastStatic = ;
const lastDynamic = ;
const lastComponent = ;
const spaces = ;
const multiLineTrailing = ;

View File

@@ -0,0 +1,66 @@
import { template as _$template } from "r-dom";
import { createComponent as _$createComponent } from "r-dom";
import { memo as _$memo } from "r-dom";
import { setAttribute as _$setAttribute } from "r-dom";
import { effect as _$effect } from "r-dom";
const _tmpl$ = /*#__PURE__*/ _$template(`<div>First</div>`, 2),
_tmpl$2 = /*#__PURE__*/ _$template(`<div>Last</div>`, 2),
_tmpl$3 = /*#__PURE__*/ _$template(`<div></div>`, 2),
_tmpl$4 = /*#__PURE__*/ _$template(`<span>1</span>`, 2),
_tmpl$5 = /*#__PURE__*/ _$template(`<span>2</span>`, 2),
_tmpl$6 = /*#__PURE__*/ _$template(`<span>3</span>`, 2);
const multiStatic = [_tmpl$.cloneNode(true), _tmpl$2.cloneNode(true)];
const multiExpression = [
_tmpl$.cloneNode(true),
inserted,
_tmpl$2.cloneNode(true),
"After",
];
const multiDynamic = [
(() => {
const _el$5 = _tmpl$.cloneNode(true);
_$effect(() => _$setAttribute(_el$5, "id", state.first));
return _el$5;
})(),
_$memo(() => state.inserted),
(() => {
const _el$6 = _tmpl$2.cloneNode(true);
_$effect(() => _$setAttribute(_el$6, "id", state.last));
return _el$6;
})(),
"After",
];
const singleExpression = inserted;
const singleDynamic = _$memo(inserted);
const firstStatic = [inserted, _tmpl$3.cloneNode(true)];
const firstDynamic = [_$memo(inserted), _tmpl$3.cloneNode(true)];
const firstComponent = [
_$createComponent(Component, {}),
_tmpl$3.cloneNode(true),
];
const lastStatic = [_tmpl$3.cloneNode(true), inserted];
const lastDynamic = [_tmpl$3.cloneNode(true), _$memo(inserted)];
const lastComponent = [
_tmpl$3.cloneNode(true),
_$createComponent(Component, {}),
];
const spaces = [
_tmpl$4.cloneNode(true),
" ",
_tmpl$5.cloneNode(true),
" ",
_tmpl$6.cloneNode(true),
];
const multiLineTrailing = [
_tmpl$4.cloneNode(true),
_tmpl$5.cloneNode(true),
_tmpl$6.cloneNode(true),
];

View File

@@ -0,0 +1,36 @@
const children = <div />;
const dynamic = {
children,
};
const template = <Module children={children} />;
const template2 = <module children={children} />;
const template3 = <module children={children}>Hello</module>;
const template4 = (
<module children={children}>
<Hello />
</module>
);
const template5 = <module children={dynamic.children} />;
const template6 = <Module children={dynamic.children} />;
const template7 = <module {...dynamic} />;
const template8 = <module {...dynamic}>Hello</module>;
const template9 = <module {...dynamic}>{dynamic.children}</module>;
const template10 = <Module {...dynamic}>Hello</Module>;
const template11 = <module children={/*@once*/ state.children} />;
const template12 = <Module children={/*@once*/ state.children} />;
const template13 = <module>{...children}</module>;
const template14 = <Module>{...children}</Module>;
const template15 = <module>{...dynamic.children}</module>;
const template16 = <Module>{...dynamic.children}</Module>;
const template18 = <module>Hi {...children}</module>;
const template19 = <Module>Hi {...children}</Module>;
const template20 = <module>{children()}</module>;
const template21 = <Module>{children()}</Module>;
const template22 = <module>{state.children()}</module>;
const template23 = <Module>{state.children()}</Module>;
const tiles = [];
tiles.push(<div>Test 1</div>);
const template24 = <div>{tiles}</div>;
const comma = <div>{(expression(), "static")}</div>;

View File

@@ -0,0 +1,185 @@
import { template as _$template } from "r-dom";
import { mergeProps as _$mergeProps } from "r-dom";
import { spread as _$spread } from "r-dom";
import { insert as _$insert } from "r-dom";
import { createComponent as _$createComponent } from "r-dom";
const _tmpl$ = /*#__PURE__*/ _$template(`<div></div>`, 2),
_tmpl$2 = /*#__PURE__*/ _$template(`<module></module>`, 2),
_tmpl$3 = /*#__PURE__*/ _$template(`<module>Hello</module>`, 2),
_tmpl$4 = /*#__PURE__*/ _$template(`<module>Hi </module>`, 2),
_tmpl$5 = /*#__PURE__*/ _$template(`<div>Test 1</div>`, 2);
const children = _tmpl$.cloneNode(true);
const dynamic = {
children,
};
const template = _$createComponent(Module, {
children: children,
});
const template2 = (() => {
const _el$2 = _tmpl$2.cloneNode(true);
_$insert(_el$2, children);
return _el$2;
})();
const template3 = _tmpl$3.cloneNode(true);
const template4 = (() => {
const _el$4 = _tmpl$2.cloneNode(true);
_$insert(_el$4, _$createComponent(Hello, {}));
return _el$4;
})();
const template5 = (() => {
const _el$5 = _tmpl$2.cloneNode(true);
_$insert(_el$5, () => dynamic.children);
return _el$5;
})();
const template6 = _$createComponent(Module, {
get children() {
return dynamic.children;
},
});
const template7 = (() => {
const _el$6 = _tmpl$2.cloneNode(true);
_$spread(_el$6, dynamic, false, false);
return _el$6;
})();
const template8 = (() => {
const _el$7 = _tmpl$3.cloneNode(true);
_$spread(_el$7, dynamic, false, true);
return _el$7;
})();
const template9 = (() => {
const _el$8 = _tmpl$2.cloneNode(true);
_$spread(_el$8, dynamic, false, true);
_$insert(_el$8, () => dynamic.children);
return _el$8;
})();
const template10 = _$createComponent(
Module,
_$mergeProps(dynamic, {
children: "Hello",
})
);
const template11 = (() => {
const _el$9 = _tmpl$2.cloneNode(true);
_$insert(_el$9, state.children);
return _el$9;
})();
const template12 = _$createComponent(Module, {
children: state.children,
});
const template13 = (() => {
const _el$10 = _tmpl$2.cloneNode(true);
_$insert(_el$10, children);
return _el$10;
})();
const template14 = _$createComponent(Module, {
children: children,
});
const template15 = (() => {
const _el$11 = _tmpl$2.cloneNode(true);
_$insert(_el$11, () => dynamic.children);
return _el$11;
})();
const template16 = _$createComponent(Module, {
get children() {
return dynamic.children;
},
});
const template18 = (() => {
const _el$12 = _tmpl$4.cloneNode(true);
_$insert(_el$12, children, null);
return _el$12;
})();
const template19 = _$createComponent(Module, {
get children() {
return ["Hi ", children];
},
});
const template20 = (() => {
const _el$13 = _tmpl$2.cloneNode(true);
_$insert(_el$13, children);
return _el$13;
})();
const template21 = _$createComponent(Module, {
get children() {
return children();
},
});
const template22 = (() => {
const _el$14 = _tmpl$2.cloneNode(true);
_$insert(_el$14, () => state.children());
return _el$14;
})();
const template23 = _$createComponent(Module, {
get children() {
return state.children();
},
});
const tiles = [];
tiles.push(_tmpl$5.cloneNode(true));
const template24 = (() => {
const _el$16 = _tmpl$.cloneNode(true);
_$insert(_el$16, tiles);
return _el$16;
})();
const comma = (() => {
const _el$17 = _tmpl$.cloneNode(true);
_$insert(_el$17, () => (expression(), "static"));
return _el$17;
})();

View File

@@ -0,0 +1,6 @@
const template = <module.A />;
const template2 = <module.a.B />;
const template3 = <module.A.B />;
const template4 = <module.a-b />;
const template5 = <module.a-b.c-d />;
const template6 = <namespace:tag />;

View File

@@ -0,0 +1,16 @@
import { template as _$template } from "r-dom";
import { createComponent as _$createComponent } from "r-dom";
const _tmpl$ = /*#__PURE__*/ _$template(`<namespace:tag></namespace:tag>`, 2);
const template = _$createComponent(module.A, {});
const template2 = _$createComponent(module.a.B, {});
const template3 = _$createComponent(module.A.B, {});
const template4 = _$createComponent(module["a-b"], {});
const template5 = _$createComponent(module["a-b"]["c-d"], {});
const template6 = _tmpl$.cloneNode(true);

View File

@@ -0,0 +1,9 @@
const template = (
<div id="main">
<style>{"div { color: red; }"}</style>
<h1>Welcome</h1>
<label for={"entry"}>Edit:</label>
<input id="entry" type="text" />
{/* Comment Node */}
</div>
);

View File

@@ -0,0 +1,5 @@
var _tmpl$1 = _template$(
'<div id="main"><style>div { color: red; }</style><h1>Welcome</h1><label for="entry">Edit:</label><input id="entry" type="text"/></div>',
8
);
const template = _tmpl$1.cloneNode(true);

View File

@@ -0,0 +1,8 @@
import { template as _$template } from "r-dom";
const _tmpl$ = /*#__PURE__*/ _$template(
`<div id="main"><style>div { color: red; }</style><h1>Welcome</h1><label for="entry">Edit:</label><input id="entry" type="text"></div>`,
9
);
const template = _tmpl$.cloneNode(true);

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