@@ -7,7 +7,7 @@ import path from 'path';
77
88class DiagnosticEngine {
99 /**
10- * @param {string } level
10+ * @param {keyof typeof DiagnosticEngine.LEVELS } level
1111 */
1212 constructor ( level ) {
1313 const levelInfo = DiagnosticEngine . LEVELS [ level ] ;
@@ -73,20 +73,18 @@ class DiagnosticEngine {
7373}
7474
7575function printUsage ( ) {
76- console . error ( 'Usage: ts2swift <d.ts file path> -p <tsconfig.json path> [--global <d.ts>]... [-o output.swift]' ) ;
76+ console . error ( 'Usage: ts2swift <d.ts file path>... [ -p <tsconfig.json path>] [--global <d.ts>]... [-o output.swift]' ) ;
7777}
7878
7979/**
8080 * Run ts2swift for a single input file (programmatic API, no process I/O).
81- * @param {string } filePath - Path to the .d.ts file
82- * @param {{ tsconfigPath: string, logLevel?: string , globalFiles?: string[] } } options
81+ * @param {string[] } filePaths - Paths to the .d.ts files
82+ * @param {{ tsconfigPath: string, logLevel?: keyof typeof DiagnosticEngine.LEVELS , globalFiles?: string[] } } options
8383 * @returns {string } Generated Swift source
8484 * @throws {Error } on parse/type-check errors (diagnostics are included in the message)
8585 */
86- export function run ( filePath , options ) {
87- const { tsconfigPath, logLevel = 'info' , globalFiles : globalFilesOpt = [ ] } = options ;
88- const globalFiles = Array . isArray ( globalFilesOpt ) ? globalFilesOpt : ( globalFilesOpt ? [ globalFilesOpt ] : [ ] ) ;
89-
86+ export function run ( filePaths , options ) {
87+ const { tsconfigPath, logLevel = 'info' , globalFiles = [ ] } = options ;
9088 const diagnosticEngine = new DiagnosticEngine ( logLevel ) ;
9189
9290 const configFile = ts . readConfigFile ( tsconfigPath , ts . sys . readFile ) ;
@@ -105,7 +103,7 @@ export function run(filePath, options) {
105103 throw new Error ( `TypeScript config/parse errors:\n${ message } ` ) ;
106104 }
107105
108- const program = TypeProcessor . createProgram ( [ filePath , ...globalFiles ] , configParseResult . options ) ;
106+ const program = TypeProcessor . createProgram ( [ ... filePaths , ...globalFiles ] , configParseResult . options ) ;
109107 const diagnostics = program . getSemanticDiagnostics ( ) ;
110108 if ( diagnostics . length > 0 ) {
111109 const message = ts . formatDiagnosticsWithColorAndContext ( diagnostics , {
@@ -131,7 +129,7 @@ export function run(filePath, options) {
131129 /** @type {string[] } */
132130 const bodies = [ ] ;
133131 const globalFileSet = new Set ( globalFiles ) ;
134- for ( const inputPath of [ filePath , ...globalFiles ] ) {
132+ for ( const inputPath of [ ... filePaths , ...globalFiles ] ) {
135133 const processor = new TypeProcessor ( program . getTypeChecker ( ) , diagnosticEngine , {
136134 defaultImportFromGlobal : globalFileSet . has ( inputPath ) ,
137135 } ) ;
@@ -169,39 +167,52 @@ export function main(args) {
169167 type : 'string' ,
170168 default : 'info' ,
171169 } ,
170+ help : {
171+ type : 'boolean' ,
172+ short : 'h' ,
173+ } ,
172174 } ,
173175 allowPositionals : true
174176 } )
175177
176- if ( options . positionals . length !== 1 ) {
178+ if ( options . values . help ) {
177179 printUsage ( ) ;
178- process . exit ( 1 ) ;
180+ process . exit ( 0 ) ;
179181 }
180182
181- const tsconfigPath = options . values . project ;
182- if ( ! tsconfigPath ) {
183+ if ( options . positionals . length !== 1 ) {
183184 printUsage ( ) ;
184185 process . exit ( 1 ) ;
185186 }
186187
187- const filePath = options . positionals [ 0 ] ;
188- const logLevel = options . values [ "log-level" ] || "info" ;
189- /** @type {string[] } */
190- const globalFiles = Array . isArray ( options . values . global )
191- ? options . values . global
192- : ( options . values . global ? [ options . values . global ] : [ ] ) ;
188+ const filePaths = options . positionals ;
189+ const logLevel = /** @type {keyof typeof DiagnosticEngine.LEVELS } */ ( ( ( ) => {
190+ const logLevel = options . values [ "log-level" ] || "info" ;
191+ if ( ! Object . keys ( DiagnosticEngine . LEVELS ) . includes ( logLevel ) ) {
192+ console . error ( `Invalid log level: ${ logLevel } . Valid levels are: ${ Object . keys ( DiagnosticEngine . LEVELS ) . join ( ", " ) } ` ) ;
193+ process . exit ( 1 ) ;
194+ }
195+ return logLevel ;
196+ } ) ( ) ) ;
197+ const globalFiles = options . values . global || [ ] ;
198+ const tsconfigPath = options . values . project || "tsconfig.json" ;
193199
194200 const diagnosticEngine = new DiagnosticEngine ( logLevel ) ;
195- diagnosticEngine . print ( "verbose" , `Processing ${ filePath } ... ` ) ;
201+ diagnosticEngine . print ( "verbose" , `Processing ${ filePaths . join ( ", " ) } ` ) ;
196202
197203 let swiftOutput ;
198204 try {
199- swiftOutput = run ( filePath , { tsconfigPath, logLevel, globalFiles } ) ;
200- } catch ( err ) {
201- console . error ( err . message ) ;
205+ swiftOutput = run ( filePaths , { tsconfigPath, logLevel, globalFiles } ) ;
206+ } catch ( /** @type {unknown } */ err ) {
207+ if ( err instanceof Error ) {
208+ diagnosticEngine . print ( "error" , err . message ) ;
209+ } else {
210+ diagnosticEngine . print ( "error" , String ( err ) ) ;
211+ }
202212 process . exit ( 1 ) ;
203213 }
204- if ( options . values . output ) {
214+ // Write to file or stdout
215+ if ( options . values . output && options . values . output !== "-" ) {
205216 if ( swiftOutput . length > 0 ) {
206217 fs . mkdirSync ( path . dirname ( options . values . output ) , { recursive : true } ) ;
207218 fs . writeFileSync ( options . values . output , swiftOutput ) ;
0 commit comments