diff options
21 files changed, 534 insertions, 1 deletions
@@ -7,8 +7,10 @@ TRIPLET := $(OS_NAME)-$(ARCH_NAME) PACKAGE_DIR := packages/bun-cli-$(TRIPLET) DEBUG_PACKAGE_DIR := packages/debug-bun-cli-$(TRIPLET) BIN_DIR := $(PACKAGE_DIR)/bin -RELEASE_BIN := $(BIN_DIR)/bun +RELEASE_BUN := $(BIN_DIR)/bun DEBUG_BIN := $(DEBUG_PACKAGE_DIR)/bin +DEBUG_BIN_REALPATH := $(shell realpath $(DEBUG_PACKAGE_DIR)/bin) +DEBUG_BUN := $(shell realpath $(DEBUG_BIN)/bun-debug) BUILD_ID := $(shell cat ./build-id) PACKAGE_JSON_VERSION := 0.0.$(BUILD_ID) BUN_BUILD_TAG := bun-v$(PACKAGE_JSON_VERSION) @@ -90,6 +92,38 @@ release-mac-push: write-package-json-version gh release upload $(BUN_BUILD_TAG) --clobber /tmp/bun-cli-$(TRIPLET)-$(PACKAGE_JSON_VERSION).tgz npm publish /tmp/bun-cli-$(TRIPLET)-$(PACKAGE_JSON_VERSION).tgz +dev-obj: + zig build obj + +dev: mkdir-dev dev-obj bun-link-lld-debug + +mkdir-dev: + mkdir -p $(DEBUG_PACKAGE_DIR)/bin + +test-install: + cd integration/scripts && npm install + +test-all: test-install test-with-hmr test-no-hmr + +test-with-hmr: + -killall bun -9; + BUN_BIN=$(RELEASE_BUN) node integration/scripts/browser.js + +test-no-hmr: + -killall bun -9; + DISABLE_HMR="DISABLE_HMR" BUN_BIN=$(RELEASE_BUN) node integration/scripts/browser.js + +test-dev-with-hmr: + -killall bun-debug -9; + BUN_BIN=$(DEBUG_BUN) node integration/scripts/browser.js + +test-dev-no-hmr: + -killall bun-debug -9; + DISABLE_HMR="DISABLE_HMR" BUN_BIN=$(DEBUG_BUN) node integration/scripts/browser.js + +test-dev-all: test-dev-with-hmr test-dev-no-hmr + +test-dev: test-dev-with-hmr jsc-copy-headers: find src/JavaScript/jsc/WebKit/WebKitBuild/Release/JavaScriptCore/Headers/JavaScriptCore/ -name "*.h" -exec cp {} src/JavaScript/jsc/WebKit/WebKitBuild/Release/JavaScriptCore/PrivateHeaders/JavaScriptCore \; diff --git a/integration/scripts/browser.js b/integration/scripts/browser.js new file mode 100644 index 000000000..7aa027d77 --- /dev/null +++ b/integration/scripts/browser.js @@ -0,0 +1,116 @@ +const puppeteer = require("puppeteer"); +const http = require("http"); +const path = require("path"); +const url = require("url"); +const fs = require("fs"); +const child_process = require("child_process"); +const snippetsDir = path.resolve(__dirname, "../snippets"); +const serverURL = process.env.TEST_SERVER_URL || "http://localhost:8080"; + +const DISABLE_HMR = !!process.env.DISABLE_HMR; +const bunFlags = [ + `--origin=${serverURL}`, + DISABLE_HMR && "--disable-hmr", +].filter(Boolean); +const bunExec = process.env.BUN_BIN || "bun"; +const bunProcess = child_process.spawn(bunExec, bunFlags, { + cwd: snippetsDir, + stdio: "pipe", + + shell: false, +}); +console.log("$", bunExec, bunFlags.join(" ")); + +bunProcess.stderr.pipe(process.stderr); +bunProcess.stdout.pipe(process.stdout); +bunProcess.once("error", (err) => { + console.error("❌ bun error", err); + process.exit(1); +}); +process.on("beforeExit", () => { + bunProcess?.kill(0); +}); + +function writeSnapshot(name, code) { + const file = path.join( + __dirname, + "../snapshots" + (DISABLE_HMR ? "-no-hmr" : ""), + name + ); + fs.writeFileSync(file, code); +} + +async function main() { + const browser = await puppeteer.launch(); + const promises = []; + let allTestsPassed = true; + + async function runPage(key) { + var page; + try { + page = await browser.newPage(); + page.on("console", (obj) => + console.log(`[console.${obj.type()}] ${obj.text()}`) + ); + page.exposeFunction("testFail", (error) => { + console.log(`❌ ${error}`); + allTestsPassed = false; + }); + let testDone = new Promise((resolve) => { + page.exposeFunction("testDone", resolve); + }); + await page.goto(`${serverURL}/`, { + waitUntil: "domcontentloaded", + }); + await page.evaluate(` + globalThis.runTest("${key}"); + `); + await testDone; + + console.log(`✅ ${key}`); + } catch (e) { + allTestsPassed = false; + console.log(`❌ ${key}: ${(e && e.message) || e}`); + } finally { + try { + const code = await page.evaluate(` + globalThis.getModuleScriptSrc("${key}"); + `); + writeSnapshot(key, code); + } catch (exception) { + console.warn(`Failed to update snapshot: ${key}`, exception); + } + } + + await page.close(); + } + + const tests = [ + "/cjs-transform-shouldnt-have-static-imports-in-cjs-function.js", + "/bundled-entry-point.js", + "/export.js", + "/type-only-imports.ts", + ]; + + for (let test of tests) { + await runPage(test); + } + + await browser.close(); + bunProcess.kill(0); + + if (!allTestsPassed) { + console.error(`❌ browser test failed`); + process.exit(1); + } else { + console.log(`✅ browser test passed`); + bunProcess.kill(0); + process.exit(0); + } +} + +main().catch((error) => + setTimeout(() => { + throw error; + }) +); diff --git a/integration/snapshots-no-hmr/.prettierignore b/integration/snapshots-no-hmr/.prettierignore new file mode 100644 index 000000000..4c43fe68f --- /dev/null +++ b/integration/snapshots-no-hmr/.prettierignore @@ -0,0 +1 @@ +*.js
\ No newline at end of file diff --git a/integration/snapshots-no-hmr/bundled-entry-point.js b/integration/snapshots-no-hmr/bundled-entry-point.js new file mode 100644 index 000000000..04f92d63a --- /dev/null +++ b/integration/snapshots-no-hmr/bundled-entry-point.js @@ -0,0 +1,9 @@ +import { +__require as require +} from "http://localhost:8080/__runtime.js"; +import * as $bbcd215f from "http://localhost:8080/node_modules/react/index.js"; +var hello = null ?? "world"; + +export function test() { + return testDone(import.meta.url); +} diff --git a/integration/snapshots-no-hmr/cjs-transform-shouldnt-have-static-imports-in-cjs-function.js b/integration/snapshots-no-hmr/cjs-transform-shouldnt-have-static-imports-in-cjs-function.js new file mode 100644 index 000000000..3bf17ba79 --- /dev/null +++ b/integration/snapshots-no-hmr/cjs-transform-shouldnt-have-static-imports-in-cjs-function.js @@ -0,0 +1,33 @@ +import { +__require as require +} from "http://localhost:8080/__runtime.js"; +import { +__cJS2eSM +} from "http://localhost:8080/__runtime.js"; +import * as _login_b977_0 from "http://localhost:8080/_login.js"; +import _login from "http://localhost:8080/_login.js"; +import _auth from "http://localhost:8080/_auth.js"; +import * as _loginReally from "http://localhost:8080/_login.js"; +import * as _authReally from "http://localhost:8080/_auth.js"; + +export default __cJS2eSM(function(module, exports) { + ; + + ; + ; + ; + module.exports.iAmCommonJs = true; + exports.YouAreCommonJS = true; + require(_login_b977_0); + Object.defineProperty(module.exports,"login",{get: () => _login, enumerable: true, configurable: true}); + var test = function test() { + return testDone(import.meta.url); + }; + Object.defineProperty(module.exports,"test",{get: () => test, enumerable: true, configurable: true}); + let foo, bar; + Object.defineProperties(module.exports,{'foo': {get: () => foo, set: ($_newValue) => {foo = $_newValue;}, enumerable: true, configurable: true}, +'bar': {get: () => bar, set: ($_newValue) => {bar = $_newValue;}, enumerable: true, configurable: true}}); +}, "cjs-transform-shouldnt-have-static-imports-in-cjs-function.js"); + + + diff --git a/integration/snapshots-no-hmr/export.js b/integration/snapshots-no-hmr/export.js new file mode 100644 index 000000000..534cb2a0c --- /dev/null +++ b/integration/snapshots-no-hmr/export.js @@ -0,0 +1,31 @@ +import what from "http://localhost:8080/_auth.js"; +export {default as auth} from "http://localhost:8080/_auth.js"; + +export {default as login} from "http://localhost:8080/_login.js"; +export * from "http://localhost:8080/_bacon.js"; +export let yoyoyo = "yoyoyo"; + +export default function hey() { + return true; +} +export const foo = () => { +}; +export var bar = 100; +export let powerLevel = Symbol("9001"); + +export {what}; +export {what as when, what as whence}; +export {} from "http://localhost:8080/_bacon.js"; +import * as where from "http://localhost:8080/_auth.js"; + +export {where}; + +export {bar as booop}; +export function test() { + hey(); + foo(); + if (where.default !== "hi") + throw new Error(`_auth import is incorrect.`); + console.assert(powerLevel.description === "9001", "Symbol is not exported correctly"); + return testDone(import.meta.url); +} diff --git a/integration/snapshots-no-hmr/type-only-imports.ts b/integration/snapshots-no-hmr/type-only-imports.ts new file mode 100644 index 000000000..b4503474d --- /dev/null +++ b/integration/snapshots-no-hmr/type-only-imports.ts @@ -0,0 +1,7 @@ +export const baconator = true; +export const SilentSymbolCollisionsAreOkayInTypeScript = true; +export function test() { + console.assert(SilentSymbolCollisionsAreOkayInTypeScript); + console.assert(baconator); + return testDone(import.meta.url); +} diff --git a/integration/snapshots/.prettierignore b/integration/snapshots/.prettierignore new file mode 100644 index 000000000..4c43fe68f --- /dev/null +++ b/integration/snapshots/.prettierignore @@ -0,0 +1 @@ +*.js
\ No newline at end of file diff --git a/integration/snapshots/bundled-entry-point.js b/integration/snapshots/bundled-entry-point.js new file mode 100644 index 000000000..fd211daa2 --- /dev/null +++ b/integration/snapshots/bundled-entry-point.js @@ -0,0 +1,30 @@ +import { +__require as require +} from "http://localhost:8080/__runtime.js"; +import { +__HMRModule as HMR +} from "http://localhost:8080/__runtime.js"; +import { +__HMRClient as Bun +} from "http://localhost:8080/__runtime.js"; +import * as $bbcd215f from "http://localhost:8080/node_modules/react/index.js"; +Bun.activate(true); + +var hmr = new HMR(3012834585, "bundled-entry-point.js"), exports = hmr.exports; +(hmr._load = function() { + var hello = null ?? "world"; + function test() { + return testDone(import.meta.url); + } + hmr.exportAll({ + test: () => test + }); +})(); +var $$hmr_test = hmr.exports.test; +hmr._update = function(exports) { + $$hmr_test = exports.test; +}; + +export { + $$hmr_test as test +}; diff --git a/integration/snapshots/cjs-transform-shouldnt-have-static-imports-in-cjs-function.js b/integration/snapshots/cjs-transform-shouldnt-have-static-imports-in-cjs-function.js new file mode 100644 index 000000000..be7a60e6e --- /dev/null +++ b/integration/snapshots/cjs-transform-shouldnt-have-static-imports-in-cjs-function.js @@ -0,0 +1,33 @@ +import { +__require as require +} from "http://localhost:8080/__runtime.js"; +import { +__cJS2eSM +} from "http://localhost:8080/__runtime.js"; +import * as _login_b977_0 from "http://localhost:8080/_login.js"; +import _login from "http://localhost:8080/_login.js"; +import _auth from "http://localhost:8080/_auth.js"; +import * as _loginReally from "http://localhost:8080/_login.js"; +import * as _authReally from "http://localhost:8080/_auth.js"; + +export default __cJS2eSM(function(module, exports) { + ; + + ; + ; + ; + module.exports.iAmCommonJs = true; + exports.YouAreCommonJS = true; + require(_login_b977_0); + Object.defineProperty(module.exports,"login",{get: () => _login, enumerable: true, configurable: true}); + var test = function test() { + return testDone(import.meta.url); + }; + Object.defineProperty(module.exports,"test",{get: () => test, enumerable: true, configurable: true}); + var foo, bar; + Object.defineProperties(module.exports,{'foo': {get: () => foo, set: ($_newValue) => {foo = $_newValue;}, enumerable: true, configurable: true}, +'bar': {get: () => bar, set: ($_newValue) => {bar = $_newValue;}, enumerable: true, configurable: true}}); +}, "cjs-transform-shouldnt-have-static-imports-in-cjs-function.js"); + + + diff --git a/integration/snapshots/export.js b/integration/snapshots/export.js new file mode 100644 index 000000000..b5d3e0ad1 --- /dev/null +++ b/integration/snapshots/export.js @@ -0,0 +1,74 @@ +import { +__HMRModule as HMR +} from "http://localhost:8080/__runtime.js"; +import { +__HMRClient as Bun +} from "http://localhost:8080/__runtime.js"; +import what from "http://localhost:8080/_auth.js"; +import * as where from "http://localhost:8080/_auth.js"; +Bun.activate(true); + +var hmr = new HMR(1879780259, "export.js"), exports = hmr.exports; +(hmr._load = function() { + var yoyoyo = "yoyoyo"; + function hey() { + return true; + } + var foo = () => { + }; + var bar = 100; + var powerLevel = Symbol("9001"); + function test() { + hey(); + foo(); + if (where.default !== "hi") + throw new Error(`_auth import is incorrect.`); + console.assert(powerLevel.description === "9001", "Symbol is not exported correctly"); + return testDone(import.meta.url); + } + hmr.exportAll({ + yoyoyo: () => yoyoyo, + default: () => hey, + foo: () => foo, + bar: () => bar, + powerLevel: () => powerLevel, + what: () => what, + when: () => what, + whence: () => what, + where: () => where, + booop: () => bar, + test: () => test + }); +})(); +var $$hmr_yoyoyo = hmr.exports.yoyoyo, $$hmr_default = hmr.exports.default, $$hmr_foo = hmr.exports.foo, $$hmr_bar = hmr.exports.bar, $$hmr_powerLevel = hmr.exports.powerLevel, $$hmr_what = hmr.exports.what, $$hmr_when = hmr.exports.when, $$hmr_whence = hmr.exports.whence, $$hmr_where = hmr.exports.where, $$hmr_booop = hmr.exports.booop, $$hmr_test = hmr.exports.test; +hmr._update = function(exports) { + $$hmr_yoyoyo = exports.yoyoyo; + $$hmr_default = exports.default; + $$hmr_foo = exports.foo; + $$hmr_bar = exports.bar; + $$hmr_powerLevel = exports.powerLevel; + $$hmr_what = exports.what; + $$hmr_when = exports.when; + $$hmr_whence = exports.whence; + $$hmr_where = exports.where; + $$hmr_booop = exports.booop; + $$hmr_test = exports.test; +}; + +export { + $$hmr_yoyoyo as yoyoyo, + $$hmr_default as default, + $$hmr_foo as foo, + $$hmr_bar as bar, + $$hmr_powerLevel as powerLevel, + $$hmr_what as what, + $$hmr_when as when, + $$hmr_whence as whence, + $$hmr_where as where, + $$hmr_booop as booop, + $$hmr_test as test +}; +export {default as auth} from "http://localhost:8080/_auth.js"; +export {default as login} from "http://localhost:8080/_login.js"; +export * from "http://localhost:8080/_bacon.js"; +export {} from "http://localhost:8080/_bacon.js"; diff --git a/integration/snapshots/type-only-imports.ts b/integration/snapshots/type-only-imports.ts new file mode 100644 index 000000000..c647843ea --- /dev/null +++ b/integration/snapshots/type-only-imports.ts @@ -0,0 +1,35 @@ +import { +__HMRModule as HMR +} from "http://localhost:8080/__runtime.js"; +import { +__HMRClient as Bun +} from "http://localhost:8080/__runtime.js"; +Bun.activate(true); + +var hmr = new HMR(650094581, "type-only-imports.ts"), exports = hmr.exports; +(hmr._load = function() { + var baconator = true; + var SilentSymbolCollisionsAreOkayInTypeScript = true; + function test() { + console.assert(SilentSymbolCollisionsAreOkayInTypeScript); + console.assert(baconator); + return testDone(import.meta.url); + } + hmr.exportAll({ + baconator: () => baconator, + SilentSymbolCollisionsAreOkayInTypeScript: () => SilentSymbolCollisionsAreOkayInTypeScript, + test: () => test + }); +})(); +var $$hmr_baconator = hmr.exports.baconator, $$hmr_SilentSymbolCollisionsAreOkayInTypeScript = hmr.exports.SilentSymbolCollisionsAreOkayInTypeScript, $$hmr_test = hmr.exports.test; +hmr._update = function(exports) { + $$hmr_baconator = exports.baconator; + $$hmr_SilentSymbolCollisionsAreOkayInTypeScript = exports.SilentSymbolCollisionsAreOkayInTypeScript; + $$hmr_test = exports.test; +}; + +export { + $$hmr_baconator as baconator, + $$hmr_SilentSymbolCollisionsAreOkayInTypeScript as SilentSymbolCollisionsAreOkayInTypeScript, + $$hmr_test as test +}; diff --git a/integration/snippets/_auth.js b/integration/snippets/_auth.js new file mode 100644 index 000000000..407090812 --- /dev/null +++ b/integration/snippets/_auth.js @@ -0,0 +1 @@ +export default "hi"; diff --git a/integration/snippets/_bacon.js b/integration/snippets/_bacon.js new file mode 100644 index 000000000..c07ffb9be --- /dev/null +++ b/integration/snippets/_bacon.js @@ -0,0 +1 @@ +export let hello = true; diff --git a/integration/snippets/_login.js b/integration/snippets/_login.js new file mode 100644 index 000000000..b2fc2ef65 --- /dev/null +++ b/integration/snippets/_login.js @@ -0,0 +1,3 @@ +export default function () { + return true; +} diff --git a/integration/snippets/bundled-entry-point.js b/integration/snippets/bundled-entry-point.js new file mode 100644 index 000000000..a996f8632 --- /dev/null +++ b/integration/snippets/bundled-entry-point.js @@ -0,0 +1,7 @@ +import "react"; + +var hello = 123 ? null ?? "world" : "ok"; + +export function test() { + return testDone(import.meta.url); +} diff --git a/integration/snippets/cjs-transform-shouldnt-have-static-imports-in-cjs-function.js b/integration/snippets/cjs-transform-shouldnt-have-static-imports-in-cjs-function.js new file mode 100644 index 000000000..4191b7116 --- /dev/null +++ b/integration/snippets/cjs-transform-shouldnt-have-static-imports-in-cjs-function.js @@ -0,0 +1,15 @@ +import _login from "./_login"; +import _auth from "./_auth"; +import * as _loginReally from "./_login"; +import * as _authReally from "./_auth"; + +module.exports.iAmCommonJs = true; +exports.YouAreCommonJS = true; +require("./_login"); +export { _login as login }; + +export function test() { + return testDone(import.meta.url); +} + +export let foo, bar; diff --git a/integration/snippets/export.js b/integration/snippets/export.js new file mode 100644 index 000000000..fe0abfa53 --- /dev/null +++ b/integration/snippets/export.js @@ -0,0 +1,29 @@ +import what from "./_auth"; +export { default as auth } from "./_auth"; +export { default as login } from "./_login"; +export * from "./_bacon"; +export let yoyoyo = "yoyoyo"; +export default function hey() { + return true; +} +export const foo = () => {}; +export var bar = 100; +export let powerLevel = Symbol("9001"); +export { what }; +export { what as when, what as whence }; +export {} from "./_bacon"; +export * as where from "./_auth"; +export { bar as booop }; + +export function test() { + hey(); + foo(); + if (where.default !== "hi") { + throw new Error(`_auth import is incorrect.`); + } + console.assert( + powerLevel.description === "9001", + "Symbol is not exported correctly" + ); + return testDone(import.meta.url); +} diff --git a/integration/snippets/package.json b/integration/snippets/package.json new file mode 100644 index 000000000..8edbd79a1 --- /dev/null +++ b/integration/snippets/package.json @@ -0,0 +1,10 @@ +{ + "name": "snippets", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "dependencies": { + "react": "^17.0.2", + "redux": "^4.1.1" + } +} diff --git a/integration/snippets/public/index.html b/integration/snippets/public/index.html new file mode 100644 index 000000000..74a744a7d --- /dev/null +++ b/integration/snippets/public/index.html @@ -0,0 +1,51 @@ +<html> + <head> + <meta charset="utf-8" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <title>Bun Test</title> + </head> + <body> + <script type="module"> + globalThis.getModuleScriptSrc = async (name) => { + const response = await fetch(name, { + cache: "force-cache", + }); + + if (response.ok) { + return await response.text(); + } else { + throw new Error(`Failed to get module script ${name}`); + } + }; + + globalThis.runTest = async (name) => { + var Namespace = await import(name); + var testFunction = Namespace.test; + + if ( + !("test" in Namespace) && + "default" in Namespace && + typeof Namespace.default === "function" + ) { + Namespace = Namespace.default(); + testFunction = Namespace.test; + } + + if (!testFunction) { + throw new Error("No test function found in " + name); + } + + if (typeof testFunction !== "function") { + throw new Error( + `Expected (await import(\"${name}\"")) to have a test function.\nReceived: ${Object.keys( + Namespace + ).join(", ")} ` + ); + } + + return await testFunction(); + }; + </script> + </body> +</html> diff --git a/integration/snippets/type-only-imports.ts b/integration/snippets/type-only-imports.ts new file mode 100644 index 000000000..447f86793 --- /dev/null +++ b/integration/snippets/type-only-imports.ts @@ -0,0 +1,12 @@ +import type Bacon from "tree"; +import type { SilentSymbolCollisionsAreOkayInTypeScript } from "./app"; + +export const baconator: Bacon = true; +export const SilentSymbolCollisionsAreOkayInTypeScript: SilentSymbolCollisionsAreOkayInTypeScript = + true; + +export function test() { + console.assert(SilentSymbolCollisionsAreOkayInTypeScript); + console.assert(baconator); + return testDone(import.meta.url); +} |