mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
bun-wasm fixes & improvements (#4126)
* automate Bun.version & revision polyfills * polyfill Bun.gc * bun:jsc module initial polyfills * fixes & improvements to bun-wasm
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -96,6 +96,8 @@ packages/bun-wasm/*.cjs
|
||||
packages/bun-wasm/*.map
|
||||
packages/bun-wasm/*.js
|
||||
packages/bun-wasm/*.d.ts
|
||||
packages/bun-wasm/*.d.cts
|
||||
packages/bun-wasm/*.d.mts
|
||||
*.bc
|
||||
|
||||
src/fallback.version
|
||||
|
||||
10
Makefile
10
Makefile
@@ -705,7 +705,7 @@ dev-build-obj-wasm:
|
||||
dev-wasm: dev-build-obj-wasm
|
||||
emcc -sEXPORTED_FUNCTIONS="['_bun_free', '_cycleStart', '_cycleEnd', '_bun_malloc', '_scan', '_transform', '_init', '_getTests']" \
|
||||
-g2 -s ERROR_ON_UNDEFINED_SYMBOLS=0 -DNDEBUG \
|
||||
$(BUN_DEPS_DIR)/libmimalloc.a.wasm \
|
||||
$(BUN_DEPS_DIR)/$(MIMALLOC_FILE).wasm \
|
||||
packages/debug-bun-freestanding-wasm32/bun-wasm.o --no-entry --allow-undefined -s ASSERTIONS=0 -s ALLOW_MEMORY_GROWTH=1 -s WASM_BIGINT=1 \
|
||||
-o packages/debug-bun-freestanding-wasm32/bun-wasm.wasm
|
||||
cp packages/debug-bun-freestanding-wasm32/bun-wasm.wasm packages/bun-wasm/bun.wasm
|
||||
@@ -715,7 +715,7 @@ build-obj-wasm:
|
||||
$(ZIG) build bun-wasm -Doptimize=ReleaseFast -Dtarget=wasm32-freestanding
|
||||
emcc -sEXPORTED_FUNCTIONS="['_bun_free', '_cycleStart', '_cycleEnd', '_bun_malloc', '_scan', '_transform', '_init', '_getTests']" \
|
||||
-s ERROR_ON_UNDEFINED_SYMBOLS=0 -DNDEBUG \
|
||||
$(BUN_DEPS_DIR)/libmimalloc.a.wasm \
|
||||
$(BUN_DEPS_DIR)/$(MIMALLOC_FILE).wasm \
|
||||
packages/bun-freestanding-wasm32/bun-wasm.o $(OPTIMIZATION_LEVEL) --no-entry --allow-undefined -s ASSERTIONS=0 -s ALLOW_MEMORY_GROWTH=1 -s WASM_BIGINT=1 \
|
||||
-o packages/bun-freestanding-wasm32/bun-wasm.wasm
|
||||
cp packages/bun-freestanding-wasm32/bun-wasm.wasm packages/bun-wasm/bun.wasm
|
||||
@@ -725,18 +725,20 @@ build-obj-wasm-small:
|
||||
$(ZIG) build bun-wasm -Doptimize=ReleaseFast -Dtarget=wasm32-freestanding
|
||||
emcc -sEXPORTED_FUNCTIONS="['_bun_free', '_cycleStart', '_cycleEnd', '_bun_malloc', '_scan', '_transform', '_init', '_getTests']" \
|
||||
-Oz -s ERROR_ON_UNDEFINED_SYMBOLS=0 -DNDEBUG \
|
||||
$(BUN_DEPS_DIR)/libmimalloc.a.wasm \
|
||||
$(BUN_DEPS_DIR)/$(MIMALLOC_FILE).wasm \
|
||||
packages/bun-freestanding-wasm32/bun-wasm.o -Oz --no-entry --allow-undefined -s ASSERTIONS=0 -s ALLOW_MEMORY_GROWTH=1 -s WASM_BIGINT=1 \
|
||||
-o packages/bun-freestanding-wasm32/bun-wasm.wasm
|
||||
cp packages/bun-freestanding-wasm32/bun-wasm.wasm packages/bun-wasm/bun.wasm
|
||||
|
||||
.PHONY: wasm
|
||||
wasm: api mimalloc-wasm build-obj-wasm-small
|
||||
@rm -rf packages/bun-wasm/*.{d.ts,js,wasm,cjs,mjs,tsbuildinfo}
|
||||
@rm -rf packages/bun-wasm/*.{d.ts,d.cts,d.mts,js,wasm,cjs,mjs,tsbuildinfo}
|
||||
@cp packages/bun-freestanding-wasm32/bun-wasm.wasm packages/bun-wasm/bun.wasm
|
||||
@cp src/api/schema.d.ts packages/bun-wasm/schema.d.ts
|
||||
@cp src/api/schema.js packages/bun-wasm/schema.js
|
||||
@cd packages/bun-wasm && $(NPM_CLIENT) run tsc -- -p .
|
||||
@cp packages/bun-wasm/index.d.ts packages/bun-wasm/index.d.cts
|
||||
@mv packages/bun-wasm/index.d.ts packages/bun-wasm/index.d.mts
|
||||
@bun build --sourcemap=external --external=fs --outdir=packages/bun-wasm --target=browser --minify ./packages/bun-wasm/index.ts
|
||||
@mv packages/bun-wasm/index.js packages/bun-wasm/index.mjs
|
||||
@mv packages/bun-wasm/index.js.map packages/bun-wasm/index.mjs.map
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
"scripts": {
|
||||
"node": "node --enable-source-maps --import ./dist/src/repl.js",
|
||||
"clean": "rm -rf dist",
|
||||
"build": "bun run clean && bunx tsc && bunx copyfiles \"./**/*.wasm\" dist",
|
||||
"preprocess": "bun tools/updateversions.ts",
|
||||
"build": "bun run clean && bun run preprocess && bunx tsc && bunx copyfiles \"./**/*.wasm\" dist",
|
||||
"build/wasm": "bun run build/zighash",
|
||||
"build/zighash": "cd lib/zighash && bun run build && cd ../.."
|
||||
},
|
||||
|
||||
@@ -30,8 +30,16 @@ import openEditor from 'open-editor';
|
||||
|
||||
export const main = path.resolve(process.cwd(), process.argv[1] ?? 'repl') satisfies typeof Bun.main;
|
||||
|
||||
export const version = '0.7.1' satisfies typeof Bun.version; // TODO: This can probably be fetched from somewhere in the repo
|
||||
export const revision = '0'.repeat(39) + '1' satisfies typeof Bun.revision;
|
||||
//? These are automatically updated on build by tools/updateversions.ts, do not edit manually.
|
||||
export const version = '0.7.4' satisfies typeof Bun.version;
|
||||
export const revision = '7088d7e182635a58a50860302da0b1abc42c7ce7' satisfies typeof Bun.revision;
|
||||
|
||||
export const gc = (globalThis.gc ? (() => (globalThis.gc!(), process.memoryUsage().heapUsed)) : (() => {
|
||||
const err = new Error('[bun-polyfills] Garbage collection polyfills are only available when Node.js is ran with the --expose-gc flag.');
|
||||
Error.captureStackTrace(err, gc);
|
||||
throw err;
|
||||
})) satisfies typeof Bun.gc;
|
||||
|
||||
//getter(bun, 'cwd', proc.cwd); //! Can't named export a getter
|
||||
export const origin = '' satisfies typeof Bun.origin;
|
||||
// @ts-expect-error ---
|
||||
|
||||
111
packages/bun-polyfills/src/modules/jsc.ts
Normal file
111
packages/bun-polyfills/src/modules/jsc.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import type jsc from 'bun:jsc';
|
||||
import v8 from 'node:v8';
|
||||
//import { setRandomSeed, getRandomSeed } from './mathrandom.js';
|
||||
import { NotImplementedError, getCallSites } from '../utils/errors.js';
|
||||
import { gc } from './bun.js';
|
||||
|
||||
const STUB = () => void 0;
|
||||
|
||||
function jscSerialize(value: any, options?: { binaryType: 'nodebuffer'; }): Buffer;
|
||||
function jscSerialize(value: any, options?: { binaryType?: 'arraybuffer'; }): SharedArrayBuffer;
|
||||
function jscSerialize(value: any, options?: { binaryType?: string }): Buffer | SharedArrayBuffer {
|
||||
const serialized = v8.serialize(value);
|
||||
if (options?.binaryType === 'nodebuffer') return serialized;
|
||||
else return new SharedArrayBuffer(serialized.byteLength);
|
||||
}
|
||||
// TODO: Investigate ways of making these the actual JSC serialization format (probably Bun WASM)
|
||||
// TODO: whilst this works for common use-cases like Node <-> Node it still does not make it
|
||||
// TODO: possible for Node <-> Bun transfers of this kind of data, which might be interesting to have.
|
||||
export const serialize = jscSerialize satisfies typeof jsc.serialize;
|
||||
export const deserialize = (value => {
|
||||
if (value instanceof ArrayBuffer || value instanceof SharedArrayBuffer) return v8.deserialize(Buffer.from(value));
|
||||
else return v8.deserialize(value);
|
||||
}) satisfies typeof jsc.deserialize;
|
||||
|
||||
export const setTimeZone = ((timeZone: string) => {
|
||||
const resolvedTZ = Intl.DateTimeFormat(undefined, { timeZone }).resolvedOptions().timeZone;
|
||||
return process.env.TZ = resolvedTZ;
|
||||
}) satisfies typeof jsc.setTimeZone;
|
||||
|
||||
export const callerSourceOrigin = (() => {
|
||||
const callsites: NodeJS.CallSite[] = getCallSites(2);
|
||||
// This may be inaccurate with async code. Needs more testing.
|
||||
let lastSeenURL = '';
|
||||
for (const callsite of callsites) {
|
||||
const sourceURL = callsite.getScriptNameOrSourceURL();
|
||||
if (sourceURL.startsWith('file://')) lastSeenURL = sourceURL;
|
||||
}
|
||||
return lastSeenURL;
|
||||
}) satisfies typeof jsc.callerSourceOrigin;
|
||||
|
||||
// TODO: Like with jsc.serialize/deserialize, these may be possible with Bun WASM.
|
||||
export const jscDescribe = (() => { throw new NotImplementedError('jsc.jscDescribe', STUB); }) satisfies typeof jsc.jscDescribe;
|
||||
export const jscDescribeArray = (() => { throw new NotImplementedError('jsc.jscDescribeArray', STUB); }) satisfies typeof jsc.jscDescribeArray;
|
||||
// These are no longer documented but still exist.
|
||||
export const describe = jscDescribe;
|
||||
export const describeArray = jscDescribeArray;
|
||||
|
||||
// Node.js only provides a singular non-configurable global GC function, so we have to make do with that.
|
||||
export const edenGC = gc satisfies typeof jsc.edenGC;
|
||||
export const fullGC = gc satisfies typeof jsc.fullGC;
|
||||
export const gcAndSweep = gc satisfies typeof jsc.gcAndSweep;
|
||||
|
||||
export const drainMicrotasks = STUB satisfies typeof jsc.drainMicrotasks; // no-op
|
||||
export const releaseWeakRefs = STUB satisfies typeof jsc.releaseWeakRefs; // no-op
|
||||
export const startSamplingProfiler = STUB satisfies typeof jsc.startSamplingProfiler; // no-op
|
||||
//! likely broken but needs more testing
|
||||
export const startRemoteDebugger = STUB satisfies typeof jsc.startRemoteDebugger; // no-op
|
||||
|
||||
//! this is a really poor polyfill but it's better than nothing
|
||||
export const getProtectedObjects = (() => { return [globalThis]; }) satisfies typeof jsc.getProtectedObjects;
|
||||
|
||||
export const getRandomSeed = 0; // TODO
|
||||
export const setRandomSeed = 0; // TODO
|
||||
|
||||
export const heapSize = (() => { return v8.getHeapStatistics().used_heap_size; }) satisfies typeof jsc.heapSize;
|
||||
export const heapStats = (() => {
|
||||
const stats = v8.getHeapStatistics();
|
||||
return {
|
||||
heapSize: stats.used_heap_size,
|
||||
heapCapacity: stats.total_available_size,
|
||||
extraMemorySize: stats.external_memory ?? 0,
|
||||
objectCount: 1, // TODO: how to get this in node?
|
||||
protectedObjectCount: getProtectedObjects().length,
|
||||
globalObjectCount: 2, // TODO: this one is probably fine hardcoded but is there a way to get this in node?
|
||||
protectedGlobalObjectCount: 1, // TODO: ^
|
||||
objectTypeCounts: {}, //! can't really throw an error here, so just return an empty object (TODO: how to get this in node?)
|
||||
protectedObjectTypeCounts: {} //! can't really throw an error here, so just return an empty object (TODO: how to get this in node?)
|
||||
};
|
||||
}) satisfies typeof jsc.heapStats;
|
||||
|
||||
//! doubtful anyone relies on the return of this for anything besides debugging
|
||||
export const isRope = (() => false) satisfies typeof jsc.isRope;
|
||||
|
||||
export const memoryUsage = (() => {
|
||||
const stats = v8.getHeapStatistics();
|
||||
const resUse = process.resourceUsage();
|
||||
return {
|
||||
current: stats.malloced_memory,
|
||||
peak: stats.peak_malloced_memory,
|
||||
currentCommit: stats.malloced_memory,
|
||||
peakCommit: stats.malloced_memory,
|
||||
pageFaults: resUse.minorPageFault + resUse.majorPageFault
|
||||
};
|
||||
}) satisfies typeof jsc.memoryUsage;
|
||||
|
||||
//! these are likely broken, seemingly always returning undefined which does not match the documented return types
|
||||
export const noFTL = (() => { return void 0 as unknown as Function; }) satisfies typeof jsc.noFTL;
|
||||
export const noOSRExitFuzzing = (() => { return void 0 as unknown as Function; }) satisfies typeof jsc.noOSRExitFuzzing;
|
||||
//! likely broken, seems to always returns zero
|
||||
export const totalCompileTime = (() => 0) satisfies typeof jsc.totalCompileTime;
|
||||
//! likely broken, seem to always returns 0 if any arguments are passed, undefined otherwise
|
||||
export const numberOfDFGCompiles = ((...args) => args.length ? 0 : void 0 as unknown as number) satisfies typeof jsc.numberOfDFGCompiles;
|
||||
export const reoptimizationRetryCount = ((...args) => args.length ? 0 : void 0 as unknown as number) satisfies typeof jsc.reoptimizationRetryCount;
|
||||
|
||||
//! The following are very likely impossible to ever polyfill.
|
||||
export const profile = (() => {
|
||||
throw new NotImplementedError('jsc.profile is not polyfillable', STUB, true);
|
||||
}) satisfies typeof jsc.profile;
|
||||
export const optimizeNextInvocation = (() => {
|
||||
throw new NotImplementedError('jsc.optimizeNextInvocation is not polyfillable', STUB, true);
|
||||
}) satisfies typeof jsc.optimizeNextInvocation;
|
||||
@@ -1,4 +1,5 @@
|
||||
import bun from './index.js';
|
||||
import * as jsc from './modules/jsc.js';
|
||||
|
||||
// This file serves two purposes:
|
||||
// 1. It is the entry point for using the Bun global in the REPL. (--import this file)
|
||||
@@ -12,7 +13,6 @@ globalThis.Bun = bun as typeof bun & {
|
||||
deepMatch: typeof import('bun').deepMatch;
|
||||
build: typeof import('bun').build;
|
||||
mmap: typeof import('bun').mmap;
|
||||
gc: typeof import('bun').gc;
|
||||
connect: typeof import('bun').connect;
|
||||
listen: typeof import('bun').listen;
|
||||
Transpiler: typeof import('bun').Transpiler;
|
||||
@@ -27,3 +27,5 @@ globalThis.Bun = bun as typeof bun & {
|
||||
stderr: typeof import('bun').stderr;
|
||||
stdin: typeof import('bun').stdin;
|
||||
};
|
||||
|
||||
Reflect.set(globalThis, 'jsc', jsc);
|
||||
|
||||
15
packages/bun-polyfills/src/types/sync.d.ts
vendored
15
packages/bun-polyfills/src/types/sync.d.ts
vendored
@@ -12,4 +12,19 @@ declare module 'stream/web' {
|
||||
|
||||
declare global {
|
||||
var performance: typeof import('perf_hooks').performance;
|
||||
|
||||
// TODO: These should be contributed to @types/node upstream
|
||||
namespace NodeJS {
|
||||
interface CallSite {
|
||||
getScriptNameOrSourceURL(): string;
|
||||
getEnclosingColumnNumber(): number;
|
||||
getEnclosingLineNumber(): number;
|
||||
getPosition(): number;
|
||||
getPromiseIndex(): number;
|
||||
getScriptHash(): string;
|
||||
isAsync(): boolean;
|
||||
isPromiseAll(): boolean;
|
||||
toString(): string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
type PosixErrNo = MapKeysType<ReturnType<typeof getPosixSystemErrorMap>>;
|
||||
type Win32ErrNo = MapKeysType<ReturnType<typeof getWin32SystemErrorMap>>;
|
||||
|
||||
export function getCallSites(sliceOff = 1) {
|
||||
const originalPST = Error.prepareStackTrace;
|
||||
Error.prepareStackTrace = (error, stack) => stack;
|
||||
const { stack } = new Error();
|
||||
if (stack?.constructor.name !== 'Array') throw new Error('Failed to acquire structured JS stack trace');
|
||||
Error.prepareStackTrace = originalPST;
|
||||
return (stack as unknown as NodeJS.CallSite[]).slice(sliceOff);
|
||||
}
|
||||
|
||||
export function getPosixSystemErrorMap() {
|
||||
return new Map([
|
||||
[ -7, [ 'E2BIG', 'argument list too long' ] ],
|
||||
|
||||
41
packages/bun-polyfills/tools/updateversions.ts
Normal file
41
packages/bun-polyfills/tools/updateversions.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import path from 'path';
|
||||
|
||||
const abort = (...msg: string[]): never => (console.error(...msg), process.exit(1));
|
||||
|
||||
const makefilePath = path.resolve(import.meta.dir, '../../../Makefile');
|
||||
const makefile = Bun.file(makefilePath);
|
||||
if (!await makefile.exists()) abort('Makefile not found at', makefilePath);
|
||||
|
||||
const makefileContent = await makefile.text();
|
||||
const matched = makefileContent.match(/^BUN_BASE_VERSION\s*=\s*(\d+.\d+)/m);
|
||||
if (!matched) abort('Could not find BUN_BASE_VERSION in Makefile');
|
||||
|
||||
const buildidPath = path.resolve(import.meta.dir, '../../../src/build-id');
|
||||
const buildid = Bun.file(buildidPath);
|
||||
if (!await buildid.exists()) abort('Build ID file not found at', buildidPath);
|
||||
|
||||
const [, BUN_BASE_VERSION] = matched!;
|
||||
const BUN_VERSION = `${BUN_BASE_VERSION}.${await buildid.text()}`.trim();
|
||||
|
||||
const bunTsPath = path.resolve(import.meta.dir, '../src/modules/bun.ts');
|
||||
const bunTs = Bun.file(bunTsPath);
|
||||
if (!await bunTs.exists()) abort('bun.ts source file not found at', bunTsPath);
|
||||
|
||||
const bunTsContent = await bunTs.text();
|
||||
const bunTsContentNew = bunTsContent.replace(
|
||||
/^export const version = '.+' satisfies typeof Bun.version;$/m,
|
||||
`export const version = '${BUN_VERSION}' satisfies typeof Bun.version;`
|
||||
);
|
||||
if (bunTsContentNew !== bunTsContent) console.info('Updated Bun.version polyfill to', BUN_VERSION);
|
||||
|
||||
const git = Bun.spawnSync({ cmd: ['git', 'rev-parse', 'HEAD'] });
|
||||
if (!git.success) abort('Could not get git HEAD commit hash');
|
||||
const BUN_REVISION = git.stdout.toString('utf8').trim();
|
||||
|
||||
const bunTsContentNewer = bunTsContentNew.replace(
|
||||
/^export const revision = '.+' satisfies typeof Bun.revision;$/m,
|
||||
`export const revision = '${BUN_REVISION}' satisfies typeof Bun.revision;`
|
||||
);
|
||||
if (bunTsContentNewer !== bunTsContentNew) console.info('Updated Bun.revision polyfill to', BUN_REVISION);
|
||||
|
||||
Bun.write(bunTs, bunTsContentNewer);
|
||||
Binary file not shown.
@@ -1,4 +1,3 @@
|
||||
// @ts-nocheck
|
||||
import { ByteBuffer } from "peechy/bb";
|
||||
import {
|
||||
Loader as BunLoader,
|
||||
@@ -12,20 +11,28 @@ import {
|
||||
type ScanResult,
|
||||
type TransformResponse,
|
||||
} from "./schema";
|
||||
|
||||
export enum Loader {
|
||||
jsx = BunLoader.jsx,
|
||||
js = BunLoader.js,
|
||||
tsx = BunLoader.tsx,
|
||||
ts = BunLoader.ts,
|
||||
}
|
||||
export interface TestReference {
|
||||
name: string,
|
||||
byteOffset: number,
|
||||
kind: 'test' | 'describe',
|
||||
}
|
||||
export type { ScanResult, TransformResponse };
|
||||
|
||||
const testKindMap = {
|
||||
[TestKind.describe_fn]: "describe",
|
||||
[TestKind.test_fn]: "test",
|
||||
};
|
||||
const capturedErrors = [];
|
||||
const capturedErrors: string[] = [];
|
||||
let captureErrors = false;
|
||||
export type { ScanResult, TransformResponse };
|
||||
function normalizeLoader(file_name: string, loader?: Loader): BunLoader {
|
||||
|
||||
function normalizeLoader(file_name: string, loader?: keyof typeof Loader): BunLoader {
|
||||
return (
|
||||
(loader
|
||||
? {
|
||||
@@ -46,11 +53,12 @@ function normalizeLoader(file_name: string, loader?: Loader): BunLoader {
|
||||
}
|
||||
|
||||
interface WebAssemblyModule {
|
||||
init(): number;
|
||||
init(heapSize: number): number;
|
||||
transform(a: number): number;
|
||||
bun_malloc(a: number): number;
|
||||
bun_free(a: number): number;
|
||||
scan(a: number): number;
|
||||
getTests(a: number): number;
|
||||
}
|
||||
|
||||
const ptr_converter = new ArrayBuffer(16);
|
||||
@@ -58,28 +66,28 @@ const ptr_float = new BigUint64Array(ptr_converter);
|
||||
const slice = new Uint32Array(ptr_converter);
|
||||
|
||||
const Wasi = {
|
||||
clock_time_get(clk_id, tp) {
|
||||
clock_time_get(clk_id: unknown, tp: unknown) {
|
||||
return Date.now();
|
||||
},
|
||||
environ_sizes_get() {
|
||||
debugger;
|
||||
return 0;
|
||||
},
|
||||
environ_get(__environ, environ_buf) {
|
||||
environ_get(__environ: unknown, environ_buf: unknown) {
|
||||
debugger;
|
||||
return 0;
|
||||
},
|
||||
|
||||
fd_close(fd) {
|
||||
fd_close(fd: number) {
|
||||
debugger;
|
||||
return 0;
|
||||
},
|
||||
proc_exit() {},
|
||||
|
||||
fd_seek(fd, offset_bigint, whence, newOffset) {
|
||||
fd_seek(fd: number, offset_bigint: bigint, whence: unknown, newOffset: unknown) {
|
||||
debugger;
|
||||
},
|
||||
fd_write(fd, iov, iovcnt, pnum) {
|
||||
fd_write(fd: unknown, iov: unknown, iovcnt: unknown, pnum: unknown) {
|
||||
debugger;
|
||||
},
|
||||
};
|
||||
@@ -89,16 +97,16 @@ var scratch2: Uint8Array;
|
||||
|
||||
const env = {
|
||||
console_log(slice: number) {
|
||||
// @ts-expect-error
|
||||
const text = Bun._wasmPtrLenToString(slice);
|
||||
if (captureErrors) {
|
||||
capturedErrors.push(text);
|
||||
return;
|
||||
}
|
||||
//@ts-ignore
|
||||
console.log(text);
|
||||
},
|
||||
console_error(slice: number) {
|
||||
//@ts-ignore
|
||||
// @ts-expect-error
|
||||
const text = Bun._wasmPtrLenToString(slice);
|
||||
if (captureErrors) {
|
||||
capturedErrors.push(text);
|
||||
@@ -107,19 +115,17 @@ const env = {
|
||||
console.error(text);
|
||||
},
|
||||
console_warn(slice: number) {
|
||||
//@ts-ignore
|
||||
// @ts-expect-error
|
||||
console.warn(Bun._wasmPtrLenToString(slice));
|
||||
},
|
||||
console_info(slice: number) {
|
||||
//@ts-ignore
|
||||
// @ts-expect-error
|
||||
console.info(Bun._wasmPtrLenToString(slice));
|
||||
},
|
||||
// @ts-ignore-line
|
||||
__indirect_function_table: new WebAssembly.Table({
|
||||
initial: 0,
|
||||
element: "anyfunc",
|
||||
}),
|
||||
// @ts-ignore-line
|
||||
__stack_pointer: new WebAssembly.Global({
|
||||
mutable: true,
|
||||
value: "i32",
|
||||
@@ -131,11 +137,11 @@ const env = {
|
||||
return one % two;
|
||||
},
|
||||
memset(ptr: number, value: number, len: number) {
|
||||
//@ts-ignore
|
||||
// @ts-expect-error
|
||||
Bun.memory_array.fill(value, ptr, ptr + len);
|
||||
},
|
||||
memcpy(ptr: number, value: number, len: number) {
|
||||
//@ts-ignore
|
||||
// @ts-expect-error
|
||||
Bun.memory_array.copyWithin(ptr, value, value + len);
|
||||
},
|
||||
// These functions convert a to an unsigned long long, rounding toward zero. Negative values all become zero.
|
||||
@@ -167,14 +173,13 @@ const env = {
|
||||
};
|
||||
export class Bun {
|
||||
private static has_initialized = false;
|
||||
// @ts-ignore-line
|
||||
private static wasm_source: WebAssembly.WebAssemblyInstantiatedSource = null;
|
||||
private static wasm_source: WebAssembly.WebAssemblyInstantiatedSource;
|
||||
private static get wasm_exports(): WebAssemblyModule {
|
||||
return Bun.wasm_source.instance.exports as any;
|
||||
return Bun.wasm_source.instance.exports as unknown as WebAssemblyModule;
|
||||
}
|
||||
// @ts-ignore-line
|
||||
|
||||
private static get memory(): WebAssembly.Memory {
|
||||
return Bun.wasm_source.instance.exports.memory as any;
|
||||
return Bun.wasm_source.instance.exports.memory as WebAssembly.Memory;
|
||||
}
|
||||
|
||||
private static memory_array: Uint8Array;
|
||||
@@ -195,7 +200,8 @@ export class Bun {
|
||||
return Bun._decoder.decode(region);
|
||||
}
|
||||
|
||||
static async init(url, heapSize = 64_000_000, fetch = globalThis.fetch) {
|
||||
static async init(url?: URL | string | null, heapSize = 64_000_000, fetch = globalThis.fetch) {
|
||||
url ??= new URL("./bun.wasm", import.meta.url);
|
||||
scratch = new Uint8Array(8096);
|
||||
|
||||
if (Bun.has_initialized) {
|
||||
@@ -216,9 +222,12 @@ export class Bun {
|
||||
// is it node?
|
||||
}
|
||||
} else {
|
||||
//@ts-ignore
|
||||
const fs = await import("fs");
|
||||
|
||||
if (typeof url === 'string' && url.startsWith('file://')) {
|
||||
url = new URL(url); // fs.readFileSync cannot consume URL strings, only URL objects
|
||||
}
|
||||
|
||||
Bun.wasm_source = await globalThis.WebAssembly.instantiate(fs.readFileSync(url), {
|
||||
env: env,
|
||||
wasi_snapshot_preview1: Wasi,
|
||||
@@ -234,7 +243,7 @@ export class Bun {
|
||||
Bun.has_initialized = true;
|
||||
}
|
||||
|
||||
static getTests(content: Uint8Array | string, filename = "my.test.tsx") {
|
||||
static getTests(content: Uint8Array, filename = "my.test.tsx") {
|
||||
const bb = new ByteBuffer(scratch);
|
||||
bb.length = 0;
|
||||
bb.index = 0;
|
||||
@@ -283,7 +292,7 @@ export class Bun {
|
||||
var _bb = new ByteBuffer(Bun._wasmPtrToSlice(resp_ptr));
|
||||
|
||||
const response = decodeGetTestsResponse(_bb);
|
||||
var tests = new Array(response.tests.length);
|
||||
var tests: TestReference[] = new Array(response.tests.length);
|
||||
|
||||
for (var i = 0; i < response.tests.length; i++) {
|
||||
tests[i] = {
|
||||
@@ -294,7 +303,7 @@ export class Bun {
|
||||
),
|
||||
),
|
||||
byteOffset: response.tests[i].byteOffset,
|
||||
kind: testKindMap[response.tests[i].kind],
|
||||
kind: testKindMap[response.tests[i].kind] as 'test' | 'describe',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -303,7 +312,7 @@ export class Bun {
|
||||
return tests;
|
||||
}
|
||||
|
||||
static transformSync(content: Uint8Array | string, file_name: string, loader?: Loader): TransformResponse {
|
||||
static transformSync(content: Uint8Array | string, file_name: string, loader?: keyof typeof Loader): TransformResponse {
|
||||
const bb = new ByteBuffer(scratch);
|
||||
bb.length = 0;
|
||||
bb.index = 0;
|
||||
@@ -330,7 +339,6 @@ export class Bun {
|
||||
{
|
||||
contents: contents_buffer,
|
||||
path: file_name,
|
||||
// @ts-ignore
|
||||
loader: normalizeLoader(file_name, loader),
|
||||
},
|
||||
bb,
|
||||
@@ -349,7 +357,7 @@ export class Bun {
|
||||
return response;
|
||||
}
|
||||
|
||||
static scan(content: Uint8Array | string, file_name: string, loader?: Loader): ScanResult {
|
||||
static scan(content: Uint8Array | string, file_name: string, loader?: keyof typeof Loader): ScanResult {
|
||||
const bb = new ByteBuffer(scratch);
|
||||
bb.length = 0;
|
||||
bb.index = 0;
|
||||
@@ -368,7 +376,6 @@ export class Bun {
|
||||
{
|
||||
contents: contents_buffer,
|
||||
path: file_name,
|
||||
// @ts-ignore
|
||||
loader: normalizeLoader(file_name, loader),
|
||||
},
|
||||
bb,
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
{
|
||||
"name": "bun-wasm",
|
||||
"version": "0.0.79",
|
||||
"scripts": {
|
||||
"build": "cd ../.. && make wasm",
|
||||
"dev": "cd ../.. && make dev-wasm"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.4.10",
|
||||
"peechy": "0.4.32",
|
||||
"typescript": "latest"
|
||||
},
|
||||
@@ -16,7 +21,7 @@
|
||||
"schema.js"
|
||||
],
|
||||
"type": "module",
|
||||
"types": "index.d.ts",
|
||||
"types": "index.d.mts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./index.mjs",
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { readFileSync } from "fs";
|
||||
import { init, getTests } from "../index.mjs";
|
||||
|
||||
const buf = (process.argv.length > 2 ? readFileSync(process.argv.at(-1)) : "") || readFileSync(import.meta.url);
|
||||
await init(new URL("../bun.wasm", import.meta.url));
|
||||
const filePath = process.argv[2];
|
||||
if (!filePath) throw new Error("Usage: node node.mjs <file>");
|
||||
|
||||
const buf = readFileSync(filePath);
|
||||
await init();
|
||||
|
||||
console.log(getTests(buf));
|
||||
|
||||
@@ -8,8 +8,10 @@
|
||||
"isolatedModules": false,
|
||||
"skipLibCheck": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"strict": true,
|
||||
"outDir": ".",
|
||||
"baseUrl": "."
|
||||
"baseUrl": ".",
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": [
|
||||
"./node_modules/peechy",
|
||||
|
||||
Reference in New Issue
Block a user