From 55eb4ffe8fc8708d5a44c53fe75026a03f0a4de8 Mon Sep 17 00:00:00 2001 From: jhmaster <32803471+jhmaster2000@users.noreply.github.com> Date: Thu, 24 Aug 2023 18:39:28 -0300 Subject: [PATCH] Update bun-polyfills & bun-wasm (#4246) * automate Bun.version & revision polyfills * polyfill Bun.gc * bun:jsc module initial polyfills * update peechy schema * bun-polyfills: fix some project configs * bun-wasm: lots of fixes * bun-polyfills: Bun.Transpiler impl. * revision hash update --- packages/bun-polyfills/bun.lockb | Bin 27871 -> 28510 bytes packages/bun-polyfills/package.json | 4 +- packages/bun-polyfills/src/modules/bun.ts | 5 +- .../src/modules/bun/transpiler.ts | 155 +++++++++--------- packages/bun-polyfills/src/repl.ts | 1 - packages/bun-polyfills/tsconfig.json | 2 +- packages/bun-wasm/index.ts | 82 ++++----- src/api/schema.d.ts | 1 + src/api/schema.js | 16 ++ src/api/schema.peechy | 3 +- src/api/schema.zig | 5 + src/main_wasm.zig | 50 ++++-- 12 files changed, 172 insertions(+), 152 deletions(-) diff --git a/packages/bun-polyfills/bun.lockb b/packages/bun-polyfills/bun.lockb index fdc201d28173427807d7b03ca672d471ba29f33f..f93a0d084879182d04a26d04ccf265dc1ca72cb5 100755 GIT binary patch delta 5178 zcmeHLeNa@_6@T}^!aiUF2ns6_zz;q|7T5(A|K#A=f_40i12w*dKApQpGpco3ldKwWCn>sNm zv)1L(A;EsCvFgV*eLUD40 zaR`W`)Y;X+bDrxpN|ka%m9N+KEEa-oHDFpiW(_#oY;Esq;9dy}JZsg}+1Si@&n{7uRI-pTmbHGb+!#pr3DezA@_auJW7X!4b$ zSQR|Li@kW$@Ro+_wOXSjE%xdoJ=C&~`gJyOipKD~MKd~^vK$LnfZ6)eq|PeP?q?Hk z(iomIG~;K}S+kPjL;JKC0$BH0E!U{e9>&{{r1nq(?a`i96Jm{akWE>HRkc7fgeLv0VvxpyY~ppA!Sf#F7;H*C(rIo&%FAA);#V~Gh)wZDs?7yM&I_c~!3D}52ssk|YM9T^Sg=j;M;5Y!YIH<3 z<%HOjgOIVFx^TJ+K-qNmkz6GNNz1PKk_fblV#*1%DHkCtfeaxDv?^i9PA|e5IDiW1 zEMomUY8Bcj%7;K%YM;TtY&{a3XDU-suvMuBLJVPUGQg@MpfoDVvrxBAFQ%wJ%q9nf z(0EvZQh}ca+mO`o90J0t0o~Zh8$djN9})(uYzU?C@B*bBza5UQr^7JNgK2*Rl!i8c zDl%9VD}Gg+jY2i;2I4k2=x0@a0puBo-MtOu8E8^(m7~LGd{Kc?8|GOYxPY`L%89Tk zzkw_VM$`nC{laNHV)Z7h2EP#`{7m>=pqBaE7ZP|P;TOPfTvaa|oXdR9{THfI4_D~h zkr8f|#(1U78OM6@!*CvT8HoEW_wp6sTpohECHyX=RUqa_d$r8xJOEZu9f05AT)qtF z{s_Jro_uhgD1H~6b?f&PsdkY=hf^K&Vw!>{5&0lE)Vn{F32I+hOq%<#`_7e!QQhJP0L2lN;T3;fG~e-^t~LnA<^ffi=i z#pC46fPb0r4`@AwX2QQL_?KxHcACs|h*C0URk$w&HuEtp^8L*&<}V#8YUcMw3y6=9 z-Qd_{2Ee`+S?K&hc;GV>XAKiy!*lM7rLn!uw0*bd^{Ba7iFYdY&VO_BE0!%9_^$@( zaCVrer0M_LXJ~Gic!r!`{c|)w?+qOd=@Lf|m-kH}exS~7^wWH{yWmluDHsoN`W-_@WR5YFY21H^kj&f)m% zxNDElrK4shr8LI91hr@opV|04hr_0XgQK(s#K(e45YLk1!ILZjtpTyuI2rT7Q9VFq zfX9O3K#zj>@Wcn8_AXx?EU6uavF~<#BjCo-5mlrW>Vh zH}~K;vK6+P21*6RfH)Ey_e4+v2v*fu#Dd3zc%7DkcqZJ&b&lMsc{l}i6UYqW*sxdZ z9dEes#4Tl_!Y=X|k?Y);3t~lfFAv1BLQpZN2*eA{iNJCW7l)0*$F3KG7<0Xwk6TawI9$f9kfqqS!OemM0d)UMDd~p zLg~p@rMu~uUE{K-&oHH#5WzZ%*-$1LsAGdgw9~N-mMHCdW$#4zt?wL?W{10a(WJ0+GWet z^0hzv^TFwi2UePB0$Sa4y~2V|azmw29H4~CR(#DJtSl4P=|-hR_SMsZsutOxr@d7z z*lMP$jG~VIiDw(VU2P;&_2Mk;mL$We3hl3sjM6S*qL)rDJEtrigF+S*kQ7I0q}n@(sG+hNqv)hBs*Rc29ZY%Z>&K06 zO@*U}H^AEE&gbpo)$XMw@2f589D22Xly+;=uyc8SVPJ4J+Bw`9YdsCt7-eCgAJ&+~ z5M8V(6Gtez))=K-)Wm&|TAxrK_eWXm&orfT7hKNN8pR~-z;l?MuC+vImpyOa)zuZn zPh>$CgPSbr5?fqMccD2-{u?b~mTV4Vly-sRsJvXZ?cRlHOo#O`-3IE~Xq0hL^X$e_ zUVv*G&2qv53UZj$u4Ms{`~`qgx0zmW6eIoUs-rky$SeJICoQdOF|@aJ?pUp5@#s)p ctA7aJmZheostKHuX~L0aTiobhp8O=}U)%bvfdBvi delta 4832 zcmeHLeQXrR72jF=?AyZ^+t|k5TpVn^ZR4}=4*MJqytaYxvG#$D&ug0|#F)cA;txKI zu#+@L+LBalh;X0Mls^h_TB=k{ltxaXR7r~<1)_iul&0a*K;^2bkQ$=2Q55kH&jeX_t zFQZrbe}6Ug!=KGx5k0@QPcn->YRr@mtr;CIQgk%jCP{nhM#u8wF9=Ce01km?fp4_< zD{`_uIvnlp!hi=-Bq;~|gW%Jc4@8Gz{ZXku)*tIG-!jmR_6)Rd>l*4Uzdt%+SU3#M z`s=~n;6ZQ~_(E{#iSOCn8|&`H1XXF0l!=bh;4Bz{AuPCcXLj z^bTFjrnls4;}=p!MB$RGmmYGkaI)N2J#_N3I1ET+$wq{_(q_?Fhf@sF0f(lHLB
-!rzTWNpk7O=qA8E1N>UyAQ)$c*R89ib0Hsi|GpKxS^_d1K8vIynYJ#L=1gL=u zm5}lpo|d3JjWx)hI_O(JYsyR{%H)Jf)Itu^fia-A$vHj+ss(a#T$Cy- z>KY)KofC2D$kdeMXq$9c{>(-1X4Wb-$Q<@G-5mB+AXb71WdxNsf!GO|rxUr9$kH6^ zkXwuCp0tqTTX?FWdon}HIXv-Vrc&{=ph%%awx;Yy8ZJj0T%HzGetjJ|gN_1ZS}k34 zhLkout+QuPegsr)j$s$x17dS!n#c?)xyV*tJ3$k!ptBXI5{R}JR+?G$4N`M8`BWx# z=GHp1k-4mgMwgkrN;4YpPV-=>+6%-kr_h)?D4)rq&b(S@ITD@&Jvkq|g7eC%H)1 zv+2K`Jw-6+3$tguqwsZwj?dRcA!RQx=+*gd+OB4ZF$0sn>^5Fx>#9vp)wsnAG+L8$YwO9Ye0N{WyLD$Wv24GVV>81k zdxNjHqK)@hF5t4XoSGNsi2uPl&khAIQ~&*&V>`Ct%%O8ja*$BBuy(G*8gT0IHEBGf zcAsPXr^^mHU6hd48&o;ozna+aqV39RBXX4;)4J)te)IJTgoZn8l#Kqwc1>^#PClAL17+u{Y#v z=l4T4kks`6b+7NiF?4EulQ>OkYd}7pPT|%q@|kpcrFDyNQDH>&*uMe(aIyJh>`LLi z)?A2jDK$p|ci6udmiC<8{Lo`t=Wu_e*N;$q?4+k71s?mq!gGVZm-;^JK4=*LWAmuE zZAL0IZJ;X=Rj@u)aHEQ2G}NYg?Eehmiet~HZ@rO=p^K6cV%gj@(`9pj$Nm+uY5Sa| zb<;9yOfxIJQ0}6ix2f{647$+f$3d6beml)I0-gxoQM_JzPKE9cJ@w$>wX%5Fihhia z8m3u8w9imI_D_pv0>23#I{eol1TimbX2F2R{<(4Lile=L-jQmnKj4#ivVa((WvGwP zgB|SLXuFDg$4}Z-89yLSv^R3hb36R< (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.'); @@ -71,6 +72,8 @@ export const unsafe = { } } satisfies typeof Bun['unsafe']; +export const Transpiler = TranspilerImpl satisfies typeof Bun.Transpiler; + export const SHA1 = SHA1Polyfill satisfies typeof Bun.SHA1; export const MD5 = MD5Polyfill satisfies typeof Bun.MD5; export const MD4 = MD4Polyfill satisfies typeof Bun.MD4; diff --git a/packages/bun-polyfills/src/modules/bun/transpiler.ts b/packages/bun-polyfills/src/modules/bun/transpiler.ts index b4b95dae14..ba33e0653f 100644 --- a/packages/bun-polyfills/src/modules/bun/transpiler.ts +++ b/packages/bun-polyfills/src/modules/bun/transpiler.ts @@ -1,103 +1,96 @@ import type { JavaScriptLoader, TranspilerOptions, Transpiler as BunTranspiler, Import } from 'bun'; -import { NotImplementedError } from '../../utils/errors.js'; +import { transformSync, scan, init } from 'bun-wasm'; +import { Message } from 'bun-wasm/schema'; +import $ from 'chalk'; -// TODO: Possible implementation with WASM builds of bun with just the transpiler? -// NOTE: This is possible to implement with something like SWC, and was previously done, -// but it has lots of quirks due to the differences between SWC and Bun, so the plan is -// to not do that unless there is actual demand for using Bun.Transpiler in Node.js before -// the WASM build is worked on. The signatures are here for now as a placeholder. +await init(); + +enum InternalImportKind { + 'entry-point' = 1, // entry_point + 'import-statement' = 2, // stmt + 'require-call' = 3, // require + 'dynamic-import' = 4, // dynamic + 'require-resolve' = 5, // require_resolve + 'import-rule' = 6, // at + 'url-token' = 7, // url + 'internal' = 8, // internal +} + +export type ScanImportsEntry = { + kind: 'import-statement' | 'dynamic-import'; + path: string; +}; export default class Transpiler implements BunTranspiler { constructor(options?: TranspilerOptions) { this.#options = options ?? {}; + this.#rootFile = 'input.tsx'; // + (this.#options.loader ?? 'tsx'); + //? ^ NOTE: with current bun-wasm builds, the loader option is ignored and hardcoded to tsx } + #options: TranspilerOptions; + #rootFile: string; + #decoder?: TextDecoder; + #internallyCalled: boolean = false; async transform(code: StringOrBuffer, loader: JavaScriptLoader): Promise { - if (typeof code !== 'string') code = new TextDecoder().decode(code); - throw new NotImplementedError('Bun.Transpiler', this.transform); + this.#internallyCalled = true; + return this.transformSync(code, loader); } transformSync(code: StringOrBuffer, ctx: object): string; transformSync(code: StringOrBuffer, loader: JavaScriptLoader, ctx: object): string; transformSync(code: StringOrBuffer, loader?: JavaScriptLoader | undefined): string; transformSync(code: StringOrBuffer, loader?: JavaScriptLoader | object, ctx: object = {}): string { - if (typeof code !== 'string') code = new TextDecoder().decode(code); - if (typeof loader !== 'string') loader = 'js'; - throw new NotImplementedError('Bun.Transpiler', this.transformSync); + if (!code) return ''; // wasm dies with empty string input + if (typeof code !== 'string' && !(code instanceof Uint8Array)) throw new TypeError('code must be a string or Uint8Array'); + if (typeof loader !== 'string') loader = this.#options.loader; + const result = transformSync(code, this.#rootFile, loader); + // status 1 = success, status 2 = error + if (result.status === 2) throw formatBuildErrors(result.errors, this.#internallyCalled ? this.transform : this.transformSync); + this.#internallyCalled = false; + this.#decoder ??= new TextDecoder(); + return this.#decoder.decode(result.files[0].data); } scan(code: StringOrBuffer): { exports: string[]; imports: Import[]; } { - if (typeof code !== 'string') code = new TextDecoder().decode(code); - throw new NotImplementedError('Bun.Transpiler', this.scan); - //return { - // imports: this.scanImports(code), - // exports: this.#scanExports(code) - //}; + if (!code) return { exports: [], imports: [] }; // wasm dies with empty string input + if (typeof code !== 'string' && !(code instanceof Uint8Array)) throw new TypeError('code must be a string or Uint8Array'); + + const result = scan(code, this.#rootFile, this.#options.loader); + if (result.errors.length) throw formatBuildErrors(result.errors, this.#internallyCalled ? this.scanImports : this.scan); + this.#internallyCalled = false; + + result.imports.forEach(imp => (imp.kind as unknown) = InternalImportKind[imp.kind]); + return { + exports: result.exports, + imports: result.imports as unknown as Import[], + }; } - scanImports(code: StringOrBuffer): { - kind: 'import-statement' | 'dynamic-import'; - path: string; - }[] { - if (typeof code !== 'string') code = new TextDecoder().decode(code); - throw new NotImplementedError('Bun.Transpiler', this.scanImports); - //const imports: { kind: 'import-statement' | 'dynamic-import', path: string }[] = []; - //this.#scanTopLevelImports(code).forEach(x => imports.push({ kind: 'import-statement', path: x })); - //this.#scanDynamicImports(code).forEach(x => imports.push({ kind: 'dynamic-import', path: x })); - //return imports; + scanImports(code: StringOrBuffer): ScanImportsEntry[] { + this.#internallyCalled = true; + return this.scan(code).imports.filter(imp => imp.kind === 'import-statement' || imp.kind === 'dynamic-import') as ScanImportsEntry[]; } - - /*#scanDynamicImports(code: string): string[] { - return this.parseSync(code, { - syntax: this.#syntax, target: 'es2022', tsx: this.#options.loader === 'tsx' - }).body.filter(x => x.type === 'ExpressionStatement' && x.expression.type === 'CallExpression' && x.expression.callee.type === 'Import') - .map(i => (((i as swc.ExpressionStatement).expression as swc.CallExpression).arguments[0].expression as swc.StringLiteral).value); - }*/ - - /*#scanTopLevelImports(code: string): string[] { - return this.parseSync(code, { - syntax: this.#syntax, target: 'es2022', tsx: this.#options.loader === 'tsx' - }).body.filter(x => x.type === 'ImportDeclaration' || x.type === 'ExportAllDeclaration' || x.type === 'ExportNamedDeclaration') - .filter(i => !(i as swc.ImportDeclaration).typeOnly) - .map(i => (i as swc.ImportDeclaration).source.value); - }*/ - - /*#scanExports(code: string, includeDefault: boolean = false): string[] { - const parsed = this.parseSync(code, { - syntax: this.#syntax, target: 'es2022', tsx: this.#options.loader === 'tsx' - }).body; - const exports = []; - exports.push(parsed.filter(x => x.type === 'ExportDeclaration' && !x.declaration.declare) - .flatMap(i => ((i as swc.ExportDeclaration).declaration as swc.ClassDeclaration).identifier?.value ?? - ((i as swc.ExportDeclaration).declaration as swc.VariableDeclaration).declarations.map(d => (d.id as swc.Identifier).value) - ) - ); - exports.push(parsed.filter(x => x.type === 'ExportNamedDeclaration') - .flatMap(i => (i as swc.ExportNamedDeclaration).specifiers - .filter(s => s.type === 'ExportSpecifier' && !s.isTypeOnly) - .map(s => (s as swc.NamedExportSpecifier).exported?.value ?? (s as swc.NamedExportSpecifier).orig.value) - ) - ); - if (includeDefault) exports.push(this.#scanDefaultExport(code) ?? []); - return exports.flat(); - }*/ - - /*#scanDefaultExport(code: string): 'default' | undefined { - const parsed = this.parseSync(code, { - syntax: this.#syntax, target: 'es2022', tsx: this.#options.loader === 'tsx' - }).body; - - const defaultExportDecl = parsed.find(x => x.type === 'ExportDefaultDeclaration') as swc.ExportDefaultDeclaration | undefined; - if (!defaultExportDecl) { - const defaultExportExpr = parsed.find(x => x.type === 'ExportDefaultExpression') as swc.ExportDefaultExpression | undefined; - if (!defaultExportExpr) return undefined; - if (!defaultExportExpr.expression.type.startsWith('Ts')) return 'default'; - else return undefined; - } - - if (!defaultExportDecl.decl.type.startsWith('Ts') && !Reflect.get(defaultExportDecl.decl, 'declare')) return 'default'; - else return undefined; - }*/ - - #options: TranspilerOptions; +} + +function formatBuildErrors(buildErrors: Message[], caller: Transpiler[keyof Transpiler]): AggregateError { + const formatted = buildErrors.map(err => { + const loc = err.data.location; + const str = `${$.redBright('error')}${$.gray(':')} ${$.bold(err.data.text)}\n` + + (loc + ? `${highlightErrorChar(loc.line_text, loc.offset)}\n` + + $.redBright.bold('^'.padStart(loc.column)) + '\n' + + `${$.bold(loc.file)}${$.gray(':')}${$.yellowBright(loc.line)}${$.gray(':')}${$.yellowBright(loc.column)} ${$.gray(loc.offset)}` + : '' + ); + return { __proto__: Error.prototype, stack: str }; + }); + const aggregate = new AggregateError(formatted, `Input code has ${formatted.length} error${formatted.length === 1 ? '' : 's'}`); + Error.captureStackTrace(aggregate, caller); + aggregate.name = 'BuildError'; + return aggregate; +} + +function highlightErrorChar(str: string, at: number): string { + return str.slice(0, at) + $.red(str[at]) + str.slice(at + 1); } diff --git a/packages/bun-polyfills/src/repl.ts b/packages/bun-polyfills/src/repl.ts index 030e479b08..60090c7d62 100644 --- a/packages/bun-polyfills/src/repl.ts +++ b/packages/bun-polyfills/src/repl.ts @@ -15,7 +15,6 @@ globalThis.Bun = bun as typeof bun & { mmap: typeof import('bun').mmap; connect: typeof import('bun').connect; listen: typeof import('bun').listen; - Transpiler: typeof import('bun').Transpiler; password: typeof import('bun').password; CryptoHashInterface: typeof import('bun').CryptoHashInterface; CryptoHasher: typeof import('bun').CryptoHasher; diff --git a/packages/bun-polyfills/tsconfig.json b/packages/bun-polyfills/tsconfig.json index b00abe3441..e901406785 100644 --- a/packages/bun-polyfills/tsconfig.json +++ b/packages/bun-polyfills/tsconfig.json @@ -15,5 +15,5 @@ "outDir": "dist", "types": ["node"] }, - "include": [".", "../bun-types/index.d.ts"], + "include": ["src", "lib", "../bun-types/index.d.ts"], } diff --git a/packages/bun-wasm/index.ts b/packages/bun-wasm/index.ts index 72eed52201..9802d537e4 100644 --- a/packages/bun-wasm/index.ts +++ b/packages/bun-wasm/index.ts @@ -10,7 +10,7 @@ import { encodeTransform, type ScanResult, type TransformResponse, -} from "./schema"; +} from "./schema.js"; export enum Loader { jsx = BunLoader.jsx, @@ -54,17 +54,13 @@ function normalizeLoader(file_name: string, loader?: keyof typeof Loader): BunLo interface WebAssemblyModule { 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; + transform(a: bigint): bigint; + bun_malloc(a: number | bigint): bigint; + bun_free(a: bigint): void; + scan(a: bigint): bigint; + getTests(a: bigint): bigint; } -const ptr_converter = new ArrayBuffer(16); -const ptr_float = new BigUint64Array(ptr_converter); -const slice = new Uint32Array(ptr_converter); - const Wasi = { clock_time_get(clk_id: unknown, tp: unknown) { return Date.now(); @@ -92,11 +88,8 @@ const Wasi = { }, }; -var scratch: Uint8Array; -var scratch2: Uint8Array; - const env = { - console_log(slice: number) { + console_log(slice: bigint) { // @ts-expect-error const text = Bun._wasmPtrLenToString(slice); if (captureErrors) { @@ -105,7 +98,7 @@ const env = { } console.log(text); }, - console_error(slice: number) { + console_error(slice: bigint) { // @ts-expect-error const text = Bun._wasmPtrLenToString(slice); if (captureErrors) { @@ -114,11 +107,11 @@ const env = { } console.error(text); }, - console_warn(slice: number) { + console_warn(slice: bigint) { // @ts-expect-error console.warn(Bun._wasmPtrLenToString(slice)); }, - console_info(slice: number) { + console_info(slice: bigint) { // @ts-expect-error console.info(Bun._wasmPtrLenToString(slice)); }, @@ -171,6 +164,7 @@ const env = { }, emscripten_notify_memory_growth() {}, }; + export class Bun { private static has_initialized = false; private static wasm_source: WebAssembly.WebAssemblyInstantiatedSource; @@ -182,16 +176,22 @@ export class Bun { return Bun.wasm_source.instance.exports.memory as WebAssembly.Memory; } + private static scratch: Uint8Array = new Uint8Array(8096); private static memory_array: Uint8Array; private static _decoder: TextDecoder; + private static _encoder: TextEncoder = new TextEncoder(); - private static _wasmPtrToSlice(offset: number | bigint) { - ptr_float[0] = typeof offset === "number" ? BigInt(offset) : offset; - return new Uint8Array(Bun.memory.buffer, slice[0], slice[1]); + private static ptr_converter = new ArrayBuffer(16); + private static ptr_float = new BigUint64Array(Bun.ptr_converter); + private static ptr_slice = new Uint32Array(Bun.ptr_converter); + + private static _wasmPtrToSlice(offset: bigint) { + Bun.ptr_float[0] = typeof offset === "number" ? BigInt(offset) : offset; + return new Uint8Array(Bun.memory.buffer, Bun.ptr_slice[0], Bun.ptr_slice[1]); } - private static _wasmPtrLenToString(slice: number) { + private static _wasmPtrLenToString(slice: bigint) { if (!Bun._decoder) { Bun._decoder = new TextDecoder("utf8"); } @@ -201,14 +201,11 @@ export class Bun { } static async init(url?: URL | string | null, heapSize = 64_000_000, fetch = globalThis.fetch) { + if (Bun.has_initialized) return; url ??= new URL("./bun.wasm", import.meta.url); - scratch = new Uint8Array(8096); - if (Bun.has_initialized) { - return; - } if (typeof process === "undefined") { - if (globalThis?.WebAssembly?.instantiateStreaming) { + if (globalThis.WebAssembly.instantiateStreaming) { Bun.wasm_source = await globalThis.WebAssembly.instantiateStreaming(fetch(url), { env: env, wasi_snapshot_preview1: Wasi, @@ -244,7 +241,7 @@ export class Bun { } static getTests(content: Uint8Array, filename = "my.test.tsx") { - const bb = new ByteBuffer(scratch); + const bb = new ByteBuffer(Bun.scratch); bb.length = 0; bb.index = 0; const contents_buffer = content; @@ -313,25 +310,12 @@ export class Bun { } static transformSync(content: Uint8Array | string, file_name: string, loader?: keyof typeof Loader): TransformResponse { - const bb = new ByteBuffer(scratch); + const bb = new ByteBuffer(Bun.scratch); bb.length = 0; bb.index = 0; var contents_buffer; if (typeof content === "string") { - if (!scratch2) { - scratch2 = new Uint8Array(content.length * 2); - } - - let i = 0; - for (; i < content.length; i++) { - if (i > scratch2.length) { - var scratch3 = new Uint8Array(scratch2.length * 2); - scratch3.set(scratch2); - scratch2 = scratch3; - } - scratch2[i] = content.charCodeAt(i); - } - contents_buffer = scratch2.subarray(0, i); + contents_buffer = Bun._encoder.encode(content); } else { contents_buffer = content; } @@ -353,21 +337,17 @@ export class Bun { var _bb = new ByteBuffer(Bun._wasmPtrToSlice(resp_ptr)); const response = decodeTransformResponse(_bb); Bun.wasm_exports.bun_free(input_ptr); - scratch = bb.data; + Bun.scratch = bb.data; return response; } static scan(content: Uint8Array | string, file_name: string, loader?: keyof typeof Loader): ScanResult { - const bb = new ByteBuffer(scratch); + const bb = new ByteBuffer(Bun.scratch); bb.length = 0; bb.index = 0; var contents_buffer; if (typeof content === "string") { - if (!scratch2) { - scratch2 = new Uint8Array(content.length * 2); - } - const encode_into = new TextEncoder().encodeInto(content, scratch2); - contents_buffer = scratch2.subarray(0, encode_into.written); + contents_buffer = Bun._encoder.encode(content); } else { contents_buffer = content; } @@ -388,9 +368,11 @@ export class Bun { const resp_ptr = Bun.wasm_exports.scan(input_ptr); var _bb = new ByteBuffer(Bun._wasmPtrToSlice(resp_ptr)); + //console.log(resp_ptr, Bun.ptr_slice[0], Bun.ptr_slice[1], new Uint8Array(Bun.memory.buffer, Bun.ptr_slice[0], Bun.ptr_slice[1] + 82)); + //console.log(_bb); const response = decodeScanResult(_bb); Bun.wasm_exports.bun_free(input_ptr); - scratch = bb.data; + Bun.scratch = bb.data; return response; } } diff --git a/src/api/schema.d.ts b/src/api/schema.d.ts index f1d5b5f62a..3ec03e2136 100644 --- a/src/api/schema.d.ts +++ b/src/api/schema.d.ts @@ -579,6 +579,7 @@ export interface Scan { export interface ScanResult { exports: string[]; imports: ScannedImport[]; + errors: Message[]; } export interface ScannedImport { diff --git a/src/api/schema.js b/src/api/schema.js index 4931cd716a..6fb4b1d8d7 100644 --- a/src/api/schema.js +++ b/src/api/schema.js @@ -2058,6 +2058,9 @@ function decodeScanResult(bb) { var length = bb.readVarUint(); var values = (result["imports"] = Array(length)); for (var i = 0; i < length; i++) values[i] = decodeScannedImport(bb); + var length = bb.readVarUint(); + var values = (result["errors"] = Array(length)); + for (var i = 0; i < length; i++) values[i] = decodeMessage(bb); return result; } @@ -2087,6 +2090,19 @@ function encodeScanResult(message, bb) { } else { throw new Error('Missing required field "imports"'); } + + var value = message["errors"]; + if (value != null) { + var values = value, + n = values.length; + bb.writeVarUint(n); + for (var i = 0; i < n; i++) { + value = values[i]; + encodeMessage(value, bb); + } + } else { + throw new Error('Missing required field "errors"'); + } } function decodeScannedImport(bb) { diff --git a/src/api/schema.peechy b/src/api/schema.peechy index dc8e312a52..8185733c91 100644 --- a/src/api/schema.peechy +++ b/src/api/schema.peechy @@ -377,6 +377,7 @@ message Scan { struct ScanResult { string[] exports; ScannedImport[] imports; + Message[] errors; } struct ScannedImport { @@ -414,7 +415,7 @@ struct TransformResponse { enum MessageLevel { err = 1; - warn =2; + warn = 2; note = 3; info = 4; debug = 5; diff --git a/src/api/schema.zig b/src/api/schema.zig index 93b526d474..ae63af87a3 100644 --- a/src/api/schema.zig +++ b/src/api/schema.zig @@ -2117,17 +2117,22 @@ pub const Api = struct { /// imports imports: []const ScannedImport, + /// errors + errors: []const Message, + pub fn decode(reader: anytype) anyerror!ScanResult { var this = std.mem.zeroes(ScanResult); this.exports = try reader.readArray([]const u8); this.imports = try reader.readArray(ScannedImport); + this.errors = try reader.readArray(Message); return this; } pub fn encode(this: *const @This(), writer: anytype) anyerror!void { try writer.writeArray([]const u8, this.exports); try writer.writeArray(ScannedImport, this.imports); + try writer.writeArray(Message, this.errors); } }; diff --git a/src/main_wasm.zig b/src/main_wasm.zig index e7fd55d801..6d3ba24665 100644 --- a/src/main_wasm.zig +++ b/src/main_wasm.zig @@ -604,26 +604,44 @@ export fn scan(opts_array: u64) u64 { parser.options.ts = loader.isTypeScript(); parser.options.features.top_level_await = true; const result = parser.parse() catch unreachable; - var scan_result = std.mem.zeroes(Api.ScanResult); - var output = std.ArrayList(u8).init(default_allocator); - var output_writer = output.writer(); - const Encoder = ApiWriter(@TypeOf(output_writer)); + if (log.errors == 0) { + var scan_result = std.mem.zeroes(Api.ScanResult); + var output = std.ArrayList(u8).init(default_allocator); + var output_writer = output.writer(); + const Encoder = ApiWriter(@TypeOf(output_writer)); - if (result == .ast) { - var scanned_imports = allocator.alloc(Api.ScannedImport, result.ast.import_records.len) catch unreachable; - var scanned_i: usize = 0; - for (result.ast.import_records.slice()) |import_record| { - if (import_record.kind == .internal) continue; - scanned_imports[scanned_i] = Api.ScannedImport{ .path = import_record.path.text, .kind = import_record.kind.toAPI() }; - scanned_i += 1; + if (result == .ast) { + var scanned_imports = allocator.alloc(Api.ScannedImport, result.ast.import_records.len) catch unreachable; + var scanned_i: usize = 0; + for (result.ast.import_records.slice()) |import_record| { + if (import_record.kind == .internal) continue; + scanned_imports[scanned_i] = Api.ScannedImport{ .path = import_record.path.text, .kind = import_record.kind.toAPI() }; + scanned_i += 1; + } + + scan_result = Api.ScanResult{ + .exports = result.ast.named_exports.keys(), + .imports = scanned_imports[0..scanned_i], + .errors = (log.toAPI(allocator) catch unreachable).msgs, + }; } - scan_result = Api.ScanResult{ .exports = result.ast.named_exports.keys(), .imports = scanned_imports[0..scanned_i] }; + var encoder = Encoder.init(output_writer); + scan_result.encode(&encoder) catch unreachable; + return @as(u64, @bitCast([2]u32{ @intFromPtr(output.items.ptr), output.items.len })); + } else { + var output = std.ArrayList(u8).init(default_allocator); + var output_writer = output.writer(); + const Encoder = ApiWriter(@TypeOf(output_writer)); + var scan_result = Api.ScanResult{ + .exports = &.{}, + .imports = &.{}, + .errors = (log.toAPI(allocator) catch unreachable).msgs, + }; + var encoder = Encoder.init(output_writer); + scan_result.encode(&encoder) catch unreachable; + return @as(u64, @bitCast([2]u32{ @intFromPtr(output.items.ptr), output.items.len })); } - - var encoder = Encoder.init(output_writer); - scan_result.encode(&encoder) catch unreachable; - return @as(u64, @bitCast([2]u32{ @intFromPtr(output.items.ptr), output.items.len })); } // pub fn main() anyerror!void {}