diff --git a/lib/invoker.js b/lib/invoker.js index b3e2e03..b185fe7 100644 --- a/lib/invoker.js +++ b/lib/invoker.js @@ -11,7 +11,7 @@ class Invoker { this.options = options } - invoke () { + async invoke () { const processArgs = this.options.argv.slice(2) const { args } = this.options const { verbose, version, files } = args @@ -21,10 +21,13 @@ class Invoker { } Invoker.prepareProcessor(args, asciidoctor) const options = this.options.options + const failureLevel = options['failure_level'] if (this.options.stdin) { - Invoker.convertFromStdin(options, args) + await Invoker.convertFromStdin(options, args) + Invoker.exit(failureLevel) } else if (files && files.length > 0) { Invoker.processFiles(files, verbose, args['timings'], options) + Invoker.exit(failureLevel) } else { this.showHelp() process.exit(0) @@ -57,17 +60,20 @@ CLI version ${pkg.version}` console.log(new Invoker().version()) } - static convertFromStdin (options, args) { - stdin.read((data) => { - if (args['timings']) { - const timings = asciidoctor.Timings.create() - const instanceOptions = Object.assign({}, options, { timings }) - Invoker.convert(asciidoctor.convert, data, instanceOptions) - timings.printReport(process.stderr, '-') - } else { - Invoker.convert(asciidoctor.convert, data, options) - } - }) + static async readFromStdin () { + return stdin.read() + } + + static async convertFromStdin (options, args) { + const data = await Invoker.readFromStdin() + if (args['timings']) { + const timings = asciidoctor.Timings.create() + const instanceOptions = Object.assign({}, options, { timings }) + Invoker.convert(asciidoctor.convert, data, instanceOptions) + timings.printReport(process.stderr, '-') + } else { + Invoker.convert(asciidoctor.convert, data, options) + } } static convert (processorFn, input, options) { @@ -101,12 +107,6 @@ CLI version ${pkg.version}` Invoker.convertFile(file, options) } }) - let code = 0 - const logger = asciidoctor.LoggerManager.getLogger() - if (logger && typeof logger.getMaxSeverity === 'function' && logger.getMaxSeverity() && logger.getMaxSeverity() >= options['failure_level']) { - code = 1 - } - process.exit(code) } static requireLibrary (requirePath, cwd = process.cwd()) { @@ -136,6 +136,15 @@ CLI version ${pkg.version}` }) } } + + static exit (failureLevel) { + let code = 0 + const logger = asciidoctor.LoggerManager.getLogger() + if (logger && typeof logger.getMaxSeverity === 'function' && logger.getMaxSeverity() && logger.getMaxSeverity() >= failureLevel) { + code = 1 + } + process.exit(code) + } } module.exports = Invoker diff --git a/lib/stdin.js b/lib/stdin.js index cb3a52c..57f8467 100644 --- a/lib/stdin.js +++ b/lib/stdin.js @@ -1,4 +1,4 @@ -const readFromStdin = (callback) => { +const readFromStdin = async () => new Promise((resolve, reject) => { const encoding = 'utf-8' let data data = '' @@ -9,12 +9,15 @@ const readFromStdin = (callback) => { data += chunk } }) + process.stdin.on('error', (error) => { + reject(error) + }) process.stdin.on('end', function () { // There will be a trailing \n from the user hitting enter. Get rid of it. data = data.replace(/\n$/, '') - callback(data) + resolve(data) }) -} +}) module.exports = { read: readFromStdin diff --git a/test/test.js b/test/test.js index 3f33815..d6b4275 100644 --- a/test/test.js +++ b/test/test.js @@ -114,11 +114,12 @@ describe('Options converter', () => { }) describe('Read from stdin', () => { - it('should read from stdin', () => { - sinon.stub(stdin, 'read').yields('An *AsciiDoc* input') + it('should read from stdin', async () => { + sinon.stub(stdin, 'read').resolves('An *AsciiDoc* input') sinon.stub(processor, 'convert') + sinon.stub(process, 'exit') try { - new Invoker(defaultOptions.parse(['/path/to/node', '/path/to/asciidoctor', '-'])).invoke() + await new Invoker(defaultOptions.parse(['/path/to/node', '/path/to/asciidoctor', '-'])).invoke() expect(stdin.read.called).to.be.true() expect(processor.convert.called).to.be.true() const firstArgument = processor.convert.getCall(0).args[0] @@ -128,6 +129,7 @@ describe('Read from stdin', () => { } finally { stdin.read.restore() processor.convert.restore() + process.exit.restore() } }) }) @@ -199,6 +201,7 @@ describe('Version', () => { return `Asciidoctor reveal.js 3.0.1 using ${super.version()}` } } + new CustomInvoker(defaultOptions.parse(['/path/to/node', '/path/to/asciidoctor', '-v'])).invoke() expect(process.exit.called).to.be.true() expect(process.exit.calledWith(0)).to.be.true() @@ -224,7 +227,8 @@ describe('Process files', () => { it('should exit with code 1 when failure level is lower than the maximum logging level', () => { sinon.stub(process, 'exit') try { - Invoker.processFiles([bookFilePath], false, false, { failure_level: 3 }) // ERROR: 3 + Invoker.processFiles([bookFilePath], false, false) + Invoker.exit(3) // ERROR: 3 expect(process.exit.called).to.be.true() expect(process.exit.calledWith(1)).to.be.true() } finally { @@ -235,7 +239,8 @@ describe('Process files', () => { it('should exit with code 0 when failure level is lower than the maximum logging level', () => { sinon.stub(process, 'exit') try { - Invoker.processFiles([bookFilePath], false, false, { failure_level: 4 }) // FATAL: 4 + Invoker.processFiles([bookFilePath], false, false) + Invoker.exit(4) // FATAL: 4 expect(process.exit.called).to.be.true() expect(process.exit.calledWith(0)).to.be.true() } finally {