Skip to content

Commit dde9dfb

Browse files
authored
Merge pull request #418 from koordinates/olsen-cli-improvements
feat: improve CLI conventions
2 parents 574397a + afa64a0 commit dde9dfb

File tree

1 file changed

+37
-17
lines changed

1 file changed

+37
-17
lines changed

src/index.ts

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
import minimist from 'minimist';
1717
import { StyleParser, ReadStyleResult, WriteStyleResult } from 'geostyler-style';
1818
import ora, { Ora } from 'ora';
19+
import { Readable } from 'stream';
1920
import {
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

134138
function 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+
167179
async 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

308328
main();

0 commit comments

Comments
 (0)