11import { spawnSync , type SpawnSyncReturns } from "node:child_process"
22import { copyFileSync , existsSync , mkdirSync , readFileSync , readdirSync , rmSync , writeFileSync } from "fs"
33import { dirname , join , resolve } from "path"
4+ import { ModuleKind , ScriptTarget , transpileModule } from "typescript"
45import { fileURLToPath } from "url"
56import process from "process"
67import path from "path"
@@ -30,6 +31,13 @@ interface PackageJson {
3031 peerDependencies ?: Record < string , string >
3132}
3233
34+ interface BunBuildOptions {
35+ entryPoints : string [ ]
36+ externalPatterns ?: string [ ]
37+ splitting ?: boolean
38+ target : "bun" | "node"
39+ }
40+
3341const __filename = fileURLToPath ( import . meta. url )
3442const __dirname = dirname ( __filename )
3543const rootDir = resolve ( __dirname , ".." )
@@ -88,6 +96,55 @@ if (missingRequired.length > 0) {
8896 process . exit ( 1 )
8997}
9098
99+ const runCommand = ( command : string , commandArgs : string [ ] , cwd : string , errorMessage : string ) : void => {
100+ const result : SpawnSyncReturns < Buffer > = spawnSync ( command , commandArgs , {
101+ cwd,
102+ stdio : "inherit" ,
103+ } )
104+
105+ if ( result . error ) {
106+ console . error ( `${ errorMessage } : ${ result . error . message } ` )
107+ process . exit ( 1 )
108+ }
109+
110+ if ( result . status !== 0 ) {
111+ console . error ( errorMessage )
112+ process . exit ( 1 )
113+ }
114+ }
115+
116+ const runBunBuild = ( { entryPoints, externalPatterns = [ ] , splitting = false , target } : BunBuildOptions ) : void => {
117+ const buildArgs = [
118+ "build" ,
119+ `--target=${ target } ` ,
120+ "--outdir=dist" ,
121+ "--sourcemap" ,
122+ ...( splitting ? [ "--splitting" ] : [ ] ) ,
123+ ...externalPatterns . flatMap ( ( pattern ) => [ "--external" , pattern ] ) ,
124+ ...entryPoints ,
125+ ]
126+
127+ runCommand ( "bun" , buildArgs , rootDir , `Error: Bun ${ target } build failed for ${ entryPoints . join ( ", " ) } ` )
128+ }
129+
130+ const transpileEntryPoint = ( entryPoint : string , outputPath : string ) : void => {
131+ const sourcePath = join ( rootDir , entryPoint )
132+ const sourceText = readFileSync ( sourcePath , "utf8" )
133+ const result = transpileModule ( sourceText , {
134+ compilerOptions : {
135+ module : ModuleKind . ESNext ,
136+ sourceMap : true ,
137+ target : ScriptTarget . ES2022 ,
138+ } ,
139+ fileName : sourcePath ,
140+ } )
141+
142+ writeFileSync ( outputPath , result . outputText )
143+ if ( result . sourceMapText ) {
144+ writeFileSync ( `${ outputPath } .map` , result . sourceMapText )
145+ }
146+ }
147+
91148if ( buildNative ) {
92149 console . log ( `Building native ${ isDev ? "dev" : "prod" } binaries${ buildAll ? " for all platforms" : "" } ...` )
93150
@@ -99,20 +156,7 @@ if (buildNative) {
99156 zigArgs . push ( "-Dgpa-safe-stats=true" )
100157 }
101158
102- const zigBuild : SpawnSyncReturns < Buffer > = spawnSync ( "zig" , zigArgs , {
103- cwd : join ( rootDir , "src" , "zig" ) ,
104- stdio : "inherit" ,
105- } )
106-
107- if ( zigBuild . error ) {
108- console . error ( "Error: Zig is not installed or not in PATH" )
109- process . exit ( 1 )
110- }
111-
112- if ( zigBuild . status !== 0 ) {
113- console . error ( "Error: Zig build failed" )
114- process . exit ( 1 )
115- }
159+ runCommand ( "zig" , zigArgs , join ( rootDir , "src" , "zig" ) , "Error: Zig build failed" )
116160
117161 const variantsToPackage = buildAll ? variants : [ getHostVariant ( ) ]
118162
@@ -221,12 +265,21 @@ if (buildLib) {
221265 process . exit ( 1 )
222266 }
223267
224- const entryPoints : string [ ] = [
225- packageJson . module ,
226- "src/testing.ts" ,
227- "src/runtime-plugin.ts" ,
228- "src/runtime-plugin-support.ts" ,
229- "src/runtime-plugin-support-configure.ts" ,
268+ const portableEntryPoints : string [ ] = [ packageJson . module , "src/testing.ts" ]
269+
270+ const bunOnlyEntryPoints = [
271+ {
272+ entryPoint : "src/runtime-plugin.ts" ,
273+ outputFile : "runtime-plugin.js" ,
274+ } ,
275+ {
276+ entryPoint : "src/runtime-plugin-support-configure.ts" ,
277+ outputFile : "runtime-plugin-support-configure.js" ,
278+ } ,
279+ {
280+ entryPoint : "src/runtime-plugin-support.ts" ,
281+ outputFile : "runtime-plugin-support.js" ,
282+ } ,
230283 ]
231284
232285 // Build main entry points with code splitting
@@ -241,25 +294,19 @@ if (buildLib) {
241294 "./lib/tree-sitter/default-parsers.ts" ,
242295 ]
243296
244- spawnSync (
245- "bun" ,
246- [
247- "build" ,
248- "--target=bun" ,
249- "--splitting" ,
250- "--outdir=dist" ,
251- "--sourcemap" ,
252- ...externalPatterns . flatMap ( ( dep ) => [ "--external" , dep ] ) ,
253- ...entryPoints ,
254- ] ,
255- {
256- cwd : rootDir ,
257- stdio : "inherit" ,
258- } ,
259- )
297+ runBunBuild ( {
298+ entryPoints : portableEntryPoints ,
299+ externalPatterns,
300+ splitting : true ,
301+ target : "node" ,
302+ } )
303+
304+ for ( const { entryPoint, outputFile } of bunOnlyEntryPoints ) {
305+ transpileEntryPoint ( entryPoint , join ( distDir , outputFile ) )
306+ }
260307
261308 // Build updater as a separate entry so generator code stays out of the core runtime bundle.
262- spawnSync (
309+ runCommand (
263310 "bun" ,
264311 [
265312 "build" ,
@@ -269,31 +316,17 @@ if (buildLib) {
269316 ...externalDeps . flatMap ( ( dep ) => [ "--external" , dep ] ) ,
270317 "src/lib/tree-sitter/update-assets.ts" ,
271318 ] ,
272- {
273- cwd : rootDir ,
274- stdio : "inherit" ,
275- } ,
319+ rootDir ,
320+ "Error: Bun build failed for src/lib/tree-sitter/update-assets.ts" ,
276321 )
277322
278323 // Build parser worker as standalone bundle (no splitting) so it can be loaded as a Worker
279324 // Make web-tree-sitter external so it loads from node_modules with its WASM file
280- spawnSync (
281- "bun" ,
282- [
283- "build" ,
284- "--target=bun" ,
285- "--outdir=dist" ,
286- "--sourcemap" ,
287- ...externalDeps . flatMap ( ( dep ) => [ "--external" , dep ] ) ,
288- "--external" ,
289- "web-tree-sitter" ,
290- "src/lib/tree-sitter/parser.worker.ts" ,
291- ] ,
292- {
293- cwd : rootDir ,
294- stdio : "inherit" ,
295- } ,
296- )
325+ runBunBuild ( {
326+ entryPoints : [ "src/lib/tree-sitter/parser.worker.ts" ] ,
327+ externalPatterns : [ ...externalDeps , "web-tree-sitter" ] ,
328+ target : "node" ,
329+ } )
297330
298331 // Post-process to fix Bun's duplicate export issue
299332 // See: https://github.com/oven-sh/bun/issues/5344
@@ -306,7 +339,7 @@ if (buildLib) {
306339 "dist/runtime-plugin-support.js" ,
307340 "dist/runtime-plugin-support-configure.js" ,
308341 "dist/lib/tree-sitter/update-assets.js" ,
309- "dist/lib/tree-sitter/ parser.worker.js" ,
342+ "dist/parser.worker.js" ,
310343 ]
311344 for ( const filePath of bundledFiles ) {
312345 const fullPath = join ( rootDir , filePath )
@@ -339,17 +372,8 @@ if (buildLib) {
339372
340373 const tsconfigBuildPath = join ( rootDir , "tsconfig.build.json" )
341374
342- const tscResult : SpawnSyncReturns < Buffer > = spawnSync ( "bunx" , [ "tsc" , "-p" , tsconfigBuildPath ] , {
343- cwd : rootDir ,
344- stdio : "inherit" ,
345- } )
346-
347- if ( tscResult . status !== 0 ) {
348- console . error ( "Error: TypeScript declaration generation failed" )
349- process . exit ( 1 )
350- } else {
351- console . log ( "TypeScript declarations generated" )
352- }
375+ runCommand ( "bunx" , [ "tsc" , "-p" , tsconfigBuildPath ] , rootDir , "Error: TypeScript declaration generation failed" )
376+ console . log ( "TypeScript declarations generated" )
353377
354378 const treeSitterSrcDir = join ( rootDir , "src" , "lib" , "tree-sitter" )
355379
@@ -370,41 +394,71 @@ if (buildLib) {
370394 copyAssets ( join ( treeSitterSrcDir , "assets" ) , join ( distDir , "assets" ) )
371395 console . log ( " Copied tree-sitter assets (*.wasm, *.scm) to dist/assets/" )
372396
397+ const writeBunOnlyStub = ( fileName : string , specifier : string , exportNames : string [ ] ) : void => {
398+ const errorMessage = `${ specifier } is Bun-only and is not available in Node.js. Use Bun to import this entrypoint.`
399+ const namedExports = exportNames
400+ . map (
401+ ( exportName ) => `export function ${ exportName } () {\n throw new Error(${ JSON . stringify ( errorMessage ) } )\n}` ,
402+ )
403+ . join ( "\n\n" )
404+
405+ writeFileSync (
406+ join ( distDir , fileName ) ,
407+ `const errorMessage = ${ JSON . stringify ( errorMessage ) } \n\n${ namedExports } \n\nthrow new Error(errorMessage)\n` ,
408+ )
409+ }
410+
411+ writeBunOnlyStub ( "runtime-plugin.node.js" , `${ packageJson . name } /runtime-plugin` , [
412+ "createRuntimePlugin" ,
413+ "isCoreRuntimeModuleSpecifier" ,
414+ "runtimeModuleIdForSpecifier" ,
415+ ] )
416+ writeBunOnlyStub ( "runtime-plugin-support.node.js" , `${ packageJson . name } /runtime-plugin-support` , [
417+ "ensureRuntimePluginSupport" ,
418+ "createRuntimePlugin" ,
419+ "runtimeModuleIdForSpecifier" ,
420+ ] )
421+ writeBunOnlyStub ( "runtime-plugin-support-configure.node.js" , `${ packageJson . name } /runtime-plugin-support/configure` , [
422+ "ensureRuntimePluginSupport" ,
423+ "createRuntimePlugin" ,
424+ "runtimeModuleIdForSpecifier" ,
425+ ] )
426+
373427 // Configure exports for multiple entry points
374428 const exports = {
375429 "." : {
376430 import : "./index.js" ,
377- require : "./index.js" ,
378431 types : "./index.d.ts" ,
379432 } ,
380433 "./testing" : {
381434 import : "./testing.js" ,
382- require : "./testing.js" ,
383435 types : "./testing.d.ts" ,
384436 } ,
385437 "./runtime-plugin" : {
386- import : "./runtime-plugin.js" ,
387- require : "./runtime-plugin.js" ,
388438 types : "./runtime-plugin.d.ts" ,
439+ bun : "./runtime-plugin.js" ,
440+ node : "./runtime-plugin.node.js" ,
441+ default : "./runtime-plugin.node.js" ,
389442 } ,
390443 "./runtime-plugin-support" : {
391- import : "./runtime-plugin-support.js" ,
392- require : "./runtime-plugin-support.js" ,
393444 types : "./runtime-plugin-support.d.ts" ,
445+ bun : "./runtime-plugin-support.js" ,
446+ node : "./runtime-plugin-support.node.js" ,
447+ default : "./runtime-plugin-support.node.js" ,
394448 } ,
395449 "./runtime-plugin-support/configure" : {
396- import : "./runtime-plugin-support-configure.js" ,
397- require : "./runtime-plugin-support-configure.js" ,
398450 types : "./runtime-plugin-support-configure.d.ts" ,
451+ bun : "./runtime-plugin-support-configure.js" ,
452+ node : "./runtime-plugin-support-configure.node.js" ,
453+ default : "./runtime-plugin-support-configure.node.js" ,
399454 } ,
400455 "./tree-sitter/update-assets" : {
401456 import : "./lib/tree-sitter/update-assets.js" ,
402457 require : "./lib/tree-sitter/update-assets.js" ,
403458 types : "./lib/tree-sitter/update-assets.d.ts" ,
404459 } ,
405460 "./parser.worker" : {
406- import : "./lib/tree-sitter/parser.worker.js" ,
407- require : "./lib/tree-sitter/parser.worker.js" ,
461+ import : "./parser.worker.js" ,
408462 types : "./lib/tree-sitter/parser.worker.d.ts" ,
409463 } ,
410464 }
@@ -432,7 +486,6 @@ if (buildLib) {
432486 bugs : packageJson . bugs ,
433487 exports,
434488 dependencies : packageJson . dependencies ,
435- devDependencies : packageJson . devDependencies ,
436489 peerDependencies : packageJson . peerDependencies ,
437490 optionalDependencies : {
438491 ...packageJson . optionalDependencies ,
0 commit comments