11/**
2- * @fileoverview Build script for socket-packageurl-js.
3- * Orchestrates the complete build process:
4- * - Cleans dist directory
5- * - Compiles source with Rollup
6- * - Generates TypeScript declarations
7- *
8- * Usage:
9- * node scripts/build.mjs [--src-only|--types-only]
2+ * @fileoverview Unified build runner with flag-based configuration.
3+ * Orchestrates the complete build process with flexible options.
104 */
115
6+ import { existsSync } from 'node:fs'
7+ import path from 'node:path'
8+ import { fileURLToPath } from 'node:url'
129import { parseArgs } from 'node:util'
1310
14- import { logger } from '@socketsecurity/registry/lib/logger '
11+ import colors from 'yoctocolors-cjs '
1512
16- import { runSequence } from './utils/run-command.mjs'
13+ import { runCommand , runSequence } from './utils/run-command.mjs'
14+
15+ const __dirname = path . dirname ( fileURLToPath ( import . meta. url ) )
16+ const rootPath = path . join ( __dirname , '..' )
17+
18+ // Simple clean logging without prefixes
19+ const log = {
20+ info : msg => console . log ( msg ) ,
21+ error : msg => console . error ( `${ colors . red ( '✗' ) } ${ msg } ` ) ,
22+ success : msg => console . log ( `${ colors . green ( '✓' ) } ${ msg } ` ) ,
23+ step : msg => console . log ( `\n${ msg } ` ) ,
24+ substep : msg => console . log ( ` ${ msg } ` ) ,
25+ progress : msg => {
26+ // Write progress message without newline for in-place updates
27+ process . stdout . write ( ` ∴ ${ msg } ` )
28+ } ,
29+ done : msg => {
30+ // Clear current line and write success message
31+ // Carriage return + clear line
32+ process . stdout . write ( '\r\x1b[K' )
33+ console . log ( ` ${ colors . green ( '✓' ) } ${ msg } ` )
34+ } ,
35+ failed : msg => {
36+ // Clear current line and write failure message
37+ // Carriage return + clear line
38+ process . stdout . write ( '\r\x1b[K' )
39+ console . log ( ` ${ colors . red ( '✗' ) } ${ msg } ` )
40+ }
41+ }
42+
43+ /**
44+ * Build source code with Rollup.
45+ */
46+ async function buildSource ( options = { } ) {
47+ const { quiet = false } = options
48+
49+ if ( ! quiet ) {
50+ log . progress ( 'Building source code' )
51+ }
52+
53+ const exitCode = await runSequence ( [
54+ { args : [ 'run' , 'clean:dist' ] , command : 'pnpm' } ,
55+ {
56+ args : [ 'exec' , 'rollup' , '-c' , '.config/rollup.dist.config.mjs' ] ,
57+ command : 'pnpm' ,
58+ } ,
59+ ] )
60+
61+ if ( exitCode !== 0 ) {
62+ if ( ! quiet ) {
63+ log . failed ( 'Source build failed' )
64+ }
65+ return exitCode
66+ }
67+
68+ if ( ! quiet ) {
69+ log . done ( 'Source build complete' )
70+ }
71+
72+ return 0
73+ }
74+
75+ /**
76+ * Build TypeScript declarations.
77+ */
78+ async function buildTypes ( options = { } ) {
79+ const { quiet = false } = options
80+
81+ if ( ! quiet ) {
82+ log . progress ( 'Building TypeScript declarations' )
83+ }
84+
85+ const exitCode = await runSequence ( [
86+ { args : [ 'run' , 'clean:dist:types' ] , command : 'pnpm' } ,
87+ {
88+ args : [ 'exec' , 'tsgo' , '--project' , 'tsconfig.dts.json' ] ,
89+ command : 'pnpm' ,
90+ } ,
91+ ] )
92+
93+ if ( exitCode !== 0 ) {
94+ if ( ! quiet ) {
95+ log . failed ( 'Type declarations build failed' )
96+ }
97+ return exitCode
98+ }
99+
100+ if ( ! quiet ) {
101+ log . done ( 'Type declarations built' )
102+ }
103+
104+ return 0
105+ }
106+
107+ /**
108+ * Watch mode for development.
109+ */
110+ async function watchBuild ( options = { } ) {
111+ const { quiet = false } = options
112+
113+ if ( ! quiet ) {
114+ log . step ( 'Starting watch mode' )
115+ log . substep ( 'Watching for file changes...' )
116+ }
117+
118+ const exitCode = await runCommand (
119+ 'pnpm' ,
120+ [ 'exec' , 'rollup' , '-c' , '.config/rollup.dist.config.mjs' , '--watch' ] ,
121+ {
122+ stdio : 'inherit'
123+ }
124+ )
125+
126+ return exitCode
127+ }
128+
129+ /**
130+ * Check if build is needed.
131+ */
132+ function isBuildNeeded ( ) {
133+ const distPath = path . join ( rootPath , 'dist' , 'index.js' )
134+ const distTypesPath = path . join ( rootPath , 'dist' , 'types' , 'index.d.ts' )
135+
136+ return ! existsSync ( distPath ) || ! existsSync ( distTypesPath )
137+ }
17138
18139async function main ( ) {
19140 try {
141+ // Parse arguments
20142 const { values } = parseArgs ( {
21143 options : {
22- 'src-only' : { type : 'boolean' , default : false } ,
23- 'types-only' : { type : 'boolean' , default : false } ,
144+ help : {
145+ type : 'boolean' ,
146+ default : false ,
147+ } ,
148+ source : {
149+ type : 'boolean' ,
150+ default : false ,
151+ } ,
152+ types : {
153+ type : 'boolean' ,
154+ default : false ,
155+ } ,
156+ watch : {
157+ type : 'boolean' ,
158+ default : false ,
159+ } ,
160+ 'if-needed' : {
161+ type : 'boolean' ,
162+ default : false ,
163+ } ,
164+ quiet : {
165+ type : 'boolean' ,
166+ default : false ,
167+ } ,
24168 } ,
169+ allowPositionals : false ,
25170 strict : false ,
26171 } )
27172
28- const srcOnly = values [ 'src-only' ]
29- const typesOnly = values [ 'types-only' ]
30-
31- if ( typesOnly ) {
32- logger . log ( 'Building TypeScript declarations only...' )
33- const exitCode = await runSequence ( [
34- { args : [ 'run' , 'clean:dist:types' ] , command : 'pnpm' } ,
35- {
36- args : [ 'exec' , 'tsgo' , '--project' , 'tsconfig.dts.json' ] ,
37- command : 'pnpm' ,
38- } ,
39- ] )
40- process . exitCode = exitCode
173+ // Show help if requested
174+ if ( values . help ) {
175+ console . log ( 'Socket PackageURL Build Runner' )
176+ console . log ( '\nUsage: pnpm build [options]' )
177+ console . log ( '\nOptions:' )
178+ console . log ( ' --help Show this help message' )
179+ console . log ( ' --source Build source code only' )
180+ console . log ( ' --types Build TypeScript declarations only' )
181+ console . log ( ' --watch Watch mode for development' )
182+ console . log ( ' --if-needed Only build if dist files are missing' )
183+ console . log ( ' --quiet Suppress progress messages' )
184+ console . log ( '\nExamples:' )
185+ console . log ( ' pnpm build # Full build (source + types)' )
186+ console . log ( ' pnpm build --source # Build source only' )
187+ console . log ( ' pnpm build --types # Build types only' )
188+ console . log ( ' pnpm build --watch # Watch mode' )
189+ console . log ( ' pnpm build --if-needed # Build only if needed' )
190+ process . exitCode = 0
41191 return
42192 }
43193
44- if ( srcOnly ) {
45- logger . log ( 'Building source only...' )
46- const exitCode = await runSequence ( [
47- { args : [ 'run' , 'clean:dist' ] , command : 'pnpm' } ,
48- {
49- args : [ 'exec' , 'rollup' , '-c' , '.config/rollup.dist.config.mjs' ] ,
50- command : 'pnpm' ,
51- } ,
52- ] )
53- process . exitCode = exitCode
194+ // Check if build is needed
195+ if ( values [ 'if-needed' ] && ! isBuildNeeded ( ) ) {
196+ if ( ! values . quiet ) {
197+ log . info ( 'Build artifacts exist, skipping build' )
198+ }
199+ process . exitCode = 0
54200 return
55201 }
56202
57- // Build both src and types
58- logger . log ( 'Building package (source + types)...' )
203+ if ( ! values . quiet ) {
204+ console . log ( '═══════════════════════════════════════════════════════' )
205+ console . log ( ' Socket PackageURL Build Runner' )
206+ console . log ( '═══════════════════════════════════════════════════════' )
207+ }
59208
60- // Build src
61- const srcExitCode = await runSequence ( [
62- { args : [ 'run' , 'clean:dist' ] , command : 'pnpm' } ,
63- {
64- args : [ 'exec' , 'rollup' , '-c' , '.config/rollup.dist.config.mjs' ] ,
65- command : 'pnpm' ,
66- } ,
67- ] )
209+ let exitCode = 0
68210
69- if ( srcExitCode !== 0 ) {
70- process . exitCode = srcExitCode
71- return
211+ // Handle watch mode
212+ if ( values . watch ) {
213+ exitCode = await watchBuild ( { quiet : values . quiet } )
214+ }
215+ // Build types only
216+ else if ( values . types && ! values . source ) {
217+ if ( ! values . quiet ) {
218+ log . step ( 'Building TypeScript declarations only' )
219+ }
220+ exitCode = await buildTypes ( { quiet : values . quiet } )
72221 }
222+ // Build source only
223+ else if ( values . source && ! values . types ) {
224+ if ( ! values . quiet ) {
225+ log . step ( 'Building source only' )
226+ }
227+ exitCode = await buildSource ( { quiet : values . quiet } )
228+ }
229+ // Build everything (default)
230+ else {
231+ if ( ! values . quiet ) {
232+ log . step ( 'Building package (source + types)' )
233+ }
73234
74- // Build types
75- const typesExitCode = await runSequence ( [
76- { args : [ 'run' , 'clean:dist:types' ] , command : 'pnpm' } ,
77- {
78- args : [ 'exec' , 'tsgo' , '--project' , 'tsconfig.dts.json' ] ,
79- command : 'pnpm' ,
80- } ,
81- ] )
235+ // Build source first
236+ exitCode = await buildSource ( { quiet : values . quiet } )
237+ if ( exitCode !== 0 ) {
238+ if ( ! values . quiet ) {
239+ log . error ( 'Build failed' )
240+ }
241+ process . exitCode = exitCode
242+ return
243+ }
82244
83- process . exitCode = typesExitCode
245+ // Then build types
246+ exitCode = await buildTypes ( { quiet : values . quiet } )
247+ }
248+
249+ if ( exitCode !== 0 ) {
250+ if ( ! values . quiet ) {
251+ log . error ( 'Build failed' )
252+ }
253+ process . exitCode = exitCode
254+ } else {
255+ if ( ! values . quiet ) {
256+ console . log ( '\n═══════════════════════════════════════════════════════' )
257+ log . success ( 'Build completed successfully!' )
258+ console . log ( '═══════════════════════════════════════════════════════' )
259+ }
260+ }
84261 } catch ( error ) {
85- logger . error ( ' Build failed:' , error . message )
262+ log . error ( ` Build runner failed: ${ error . message } ` )
86263 process . exitCode = 1
87264 }
88265}
89266
90- main ( ) . catch ( console . error )
267+ main ( ) . catch ( console . error )
0 commit comments