@@ -2,6 +2,7 @@ import { inspect } from 'node:util'
22import { Command } from '@commander-js/extra-typings'
33import { validateArg } from '@jahands/cli-tools/args'
44import * as esbuild from 'esbuild'
5+ import pMap from 'p-map'
56import { match } from 'ts-pattern'
67import { z } from 'zod'
78
@@ -11,6 +12,9 @@ import type { CompilerOptions as TSCompilerOptions } from 'typescript'
1112
1213export const buildCmd = new Command ( 'build' ) . description ( 'Scripts to build things' )
1314
15+ type Format = z . infer < typeof Format >
16+ const Format = z . enum ( [ 'esm' , 'cjs' ] )
17+
1418buildCmd
1519 . command ( 'tsc' )
1620 . description ( 'Build a library with tsc' )
@@ -75,12 +79,9 @@ buildCmd
7579 . string ( )
7680 . array ( )
7781 . min ( 1 )
78- . parse ( entryPoints )
82+ . decode ( entryPoints )
7983 . map ( ( d ) => path . join ( rootDir ?? '.' , d ) )
8084
81- type Format = z . infer < typeof Format >
82- const Format = z . enum ( [ 'esm' , 'cjs' ] )
83-
8485 const formats = Format . array ( ) . parse ( moduleFormats )
8586
8687 await fs . rm ( './dist/' , { force : true , recursive : true } )
@@ -148,7 +149,7 @@ buildCmd
148149 . action ( async ( entryPoints ) => {
149150 const tsHelpers = await new TSHelpers ( ) . init ( )
150151 const { ts } = tsHelpers
151- z . string ( ) . array ( ) . min ( 1 ) . parse ( entryPoints )
152+ z . string ( ) . array ( ) . min ( 1 ) . decode ( entryPoints )
152153
153154 const tsconfig = ts . readConfigFile ( './tsconfig.json' , ts . sys . readFile )
154155 if ( tsconfig . error ) {
@@ -167,3 +168,72 @@ buildCmd
167168 const program = ts . createProgram ( entryPoints , tsCompOpts )
168169 program . emit ( )
169170 } )
171+
172+ buildCmd
173+ . command ( 'bun' )
174+ . description ( 'Bundle with Bun' )
175+
176+ . argument ( '<entrypoints...>' , 'Entrypoint(s) of the app. e.g. src/index.ts' )
177+ . option ( '-f, --format <format...>' , 'Formats to use (options: esm, cjs)' , [ 'esm' ] )
178+ . option ( '--no-minify' , `Don't minify output` )
179+ . option ( '--no-sourcemap' , `Don't include sourcemaps` )
180+
181+ . action ( async ( entryPoints , { format, minify, sourcemap } ) => {
182+ await fs . rm ( './dist/' , { force : true , recursive : true } )
183+
184+ const formats = await z
185+ . array ( Format )
186+ . parseAsync ( format )
187+ . catch ( ( e ) => {
188+ throw new Error ( `Invalid format: ${ z . prettifyError ( e ) } ` )
189+ } )
190+
191+ await Promise . all ( [
192+ $ ( {
193+ stdio : 'inherit' ,
194+ } ) `runx build bundle-lib-build-types ${ entryPoints } ` ,
195+
196+ ...formats . map ( async ( fmt ) => {
197+ const distDir = `./dist/${ fmt } `
198+
199+ await Bun . build ( {
200+ entrypoints : entryPoints ,
201+ outdir : distDir ,
202+ target : 'node' ,
203+ minify,
204+ format : fmt ,
205+ } )
206+
207+ const outExt = match ( fmt )
208+ . with ( 'esm' , ( ) => '.mjs' )
209+ . with ( 'cjs' , ( ) => '.cjs' )
210+ . exhaustive ( )
211+
212+ // change output files to mjs/cjs
213+ await pMap ( await glob ( `${ distDir } /**/*.js` ) , async ( file ) => {
214+ await fs . rename ( file , file . replace ( / \. j s $ / , outExt ) )
215+ } )
216+ } ) ,
217+ ] )
218+
219+ const cleanupSourcemaps = async ( ) => {
220+ if ( sourcemap === false ) {
221+ const files = await glob ( 'dist/**/*.map' )
222+ await Promise . all ( files . map ( ( file ) => fs . rm ( file ) ) )
223+ }
224+ }
225+
226+ // executables don't need declaration files
227+ const cleanupBin = async ( ) => {
228+ const files = await glob ( 'dist/bin/*.d.ts' )
229+ await Promise . all ( files . map ( ( file ) => fs . rm ( file ) ) )
230+ }
231+
232+ await Promise . all ( [ cleanupSourcemaps ( ) , cleanupBin ( ) ] )
233+
234+ // check if bin is empty
235+ const files = await glob ( 'dist/bin/*' )
236+ if ( files . length === 0 ) {
237+ await fs . rm ( 'dist/bin' , { recursive : true } )
238+ }
239+ } )
0 commit comments