@@ -16,6 +16,7 @@ import {
1616import minimist from 'minimist' ;
1717import { StyleParser , ReadStyleResult , WriteStyleResult } from 'geostyler-style' ;
1818import ora , { Ora } from 'ora' ;
19+ import { Readable } from 'stream' ;
1920import {
2021 logHelp ,
2122 logVersion
@@ -102,6 +103,9 @@ const computeTargetPath = (
102103 targetIsFile : boolean ,
103104 targetFormat : string
104105) : string => {
106+ if ( sourcePathFile === '-' ) {
107+ return outputPath ;
108+ }
105109 if ( targetIsFile ) {
106110 // Case file -> file
107111 return outputPath ;
@@ -132,7 +136,7 @@ const computeTargetPath = (
132136} ;
133137
134138function collectPaths ( basePath : string , isFile : boolean ) : string [ ] {
135- if ( isFile ) {
139+ if ( isFile || basePath === '-' ) {
136140 return [ basePath ] ;
137141 } else {
138142 const files = readdirSync ( basePath ) ;
@@ -164,29 +168,40 @@ function handleResult(result: ReadStyleResult | WriteStyleResult, parser: StyleP
164168 return output ;
165169}
166170
171+ async function readStream ( stream : Readable , encoding : BufferEncoding ) {
172+ const chunks = [ ] ;
173+ for await ( const chunk of stream ) {
174+ chunks . push ( chunk ) ;
175+ }
176+ return Buffer . concat ( chunks ) . toString ( encoding ) ;
177+ }
178+
167179async function writeFile (
168180 sourceFile : string , sourceParser : StyleParser | undefined ,
169181 targetFile : string , targetParser : StyleParser | undefined ,
170182 oraIndicator : Ora
171- ) {
183+ ) : Promise < number > {
172184 if ( targetParser instanceof LyrxParser ) {
173185 throw new Error ( 'LyrxParser is not supported as target parser.' ) ;
174186 }
175187 if ( targetParser instanceof MapfileParser ) {
176188 throw new Error ( 'MapfileParser is not supported as target parser.' ) ;
177189 }
178-
179- let inputFileData = await promises . readFile ( sourceFile , 'utf-8' ) ;
180190 const indicator = oraIndicator ; // for linter.
181191
182- // If no sourceParser is set, just parse it as JSON - it should already be in geostyler format.
183- // LyrxParser expects a JSON object as input, so we need to parse it as an extra step.
184- if ( ! sourceParser || sourceParser instanceof LyrxParser ) {
185- inputFileData = JSON . parse ( inputFileData ) ;
186- }
187-
188192 try {
189193 indicator . text = `Reading from ${ sourceFile } ` ;
194+
195+ let inputFileData = ( sourceFile === '-' )
196+ ? await readStream ( process . stdin , 'utf-8' )
197+ : await promises . readFile ( sourceFile , 'utf-8' ) ;
198+
199+ // If no sourceParser is set, just parse it as JSON - it should already be in geostyler format.
200+ // LyrxParser expects a JSON object as input, so we need to parse it as an extra step.
201+ if ( ! sourceParser || sourceParser instanceof LyrxParser ) {
202+ inputFileData = JSON . parse ( inputFileData ) ;
203+ }
204+
190205 const readOutput = sourceParser
191206 ? handleResult ( await sourceParser . readStyle ( inputFileData as any ) , sourceParser , 'Source' )
192207 : inputFileData ;
@@ -205,8 +220,10 @@ async function writeFile(
205220 indicator . succeed ( `File "${ sourceFile } " translated successfully. Output written to stdout:\n` ) ;
206221 console . log ( finalOutput ) ;
207222 }
223+ return 0 ;
208224 } catch ( error ) {
209225 indicator . fail ( `Error during translation of file "${ sourceFile } ": ${ error } ` ) ;
226+ return 1 ;
210227 }
211228}
212229
@@ -244,19 +261,20 @@ async function main() {
244261 const outputPath : string = o || output ;
245262
246263 // Instantiate progress indicator
247- const indicator = ora ( { text : 'Starting Geostyler CLI' , stream : process . stdout } ) . start ( ) ;
264+ const indicator = ora ( { text : 'Starting Geostyler CLI' } ) . start ( ) ;
248265
249266 // Check source path arg.
250267 if ( ! sourcePath ) {
251268 indicator . fail ( 'No input file or folder specified.' ) ;
252- return ;
269+ process . exit ( 1 ) ;
253270 }
254271
255272 // Check source exists, is a dir or a file ?
256- if ( ! existsSync ( sourcePath ) ) {
273+ if ( sourcePath !== '-' && ! existsSync ( sourcePath ) ) {
257274 indicator . fail ( 'Input file or folder does not exist.' ) ;
275+ process . exit ( 1 ) ;
258276 }
259- const sourceIsFile = lstatSync ( sourcePath ) . isFile ( ) ;
277+ const sourceIsFile = ( sourcePath !== '-' ) && lstatSync ( sourcePath ) . isFile ( ) ;
260278
261279 // Try to define type of target (file or dir).
262280 // Assume the target is the same as the source
@@ -266,7 +284,7 @@ async function main() {
266284 // Dir to file is not possible
267285 if ( ! sourceIsFile && targetIsFile ) {
268286 indicator . fail ( 'The source is a directory, so the target must be directory, too.' ) ;
269- return ;
287+ process . exit ( 1 ) ;
270288 }
271289
272290 // Get source parser.
@@ -292,7 +310,7 @@ async function main() {
292310 // Get source(s) path(s).
293311 const sourcePaths = collectPaths ( sourcePath , sourceIsFile ) ;
294312
295- const writePromises : Promise < void > [] = [];
313+ const writePromises : Promise < number > [] = [];
296314 sourcePaths.forEach((srcPath) => {
297315 indicator . text = `Transforming ${ srcPath } from ${ sourceFormat } to ${ targetFormat } ` ;
298316 // Get correct output path
@@ -302,7 +320,9 @@ async function main() {
302320 writePromises . push ( writeFile ( srcPath , sourceParser , outputPathFile , targetParser , indicator ) ) ;
303321 } ) ;
304322
305- await Promise . all ( writePromises ) ;
323+ const returnCodes = await Promise . all ( writePromises ) ;
324+ const returnCode = returnCodes . reduce ( ( acc , value ) => acc || value , 0 ) ;
325+ process . exit ( returnCode ) ;
306326}
307327
308328main ( ) ;
0 commit comments