diff --git a/.github/workflows/check-on-push.yml b/.github/workflows/check-on-push.yml index 2ffc82be..3f37a97a 100644 --- a/.github/workflows/check-on-push.yml +++ b/.github/workflows/check-on-push.yml @@ -26,6 +26,8 @@ jobs: uses: actions/checkout@v2 - name: Setup node and npm uses: actions/setup-node@v1 + with: + node-version: 13.12.0 - name: install packages run: npm install . # Runs the Linter action diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 6a74a1ee..5b1132b8 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: - node-version: 12 + node-version: 13.12.0 - run: npm ci - run: npm run test-on-github @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: - node-version: 12 + node-version: 13.12.0 registry-url: https://registry.npmjs.org/ - run: npm ci - run: npm publish diff --git a/cli.js b/cli.js index 30542233..ba52dd97 100755 --- a/cli.js +++ b/cli.js @@ -13,8 +13,6 @@ const { argv } = require('yargs') .choices('filter', ['scripture']) .describe('format', 'specifies the output file format') .choices('format', ['csv', 'tsv', 'usfm', 'json']) - .alias('o', 'output') - .describe('o', 'specify the fully qualified file path for output.') .alias('h', 'help') .alias('v', 'version') .help('help'); @@ -73,18 +71,4 @@ if (argv.format === 'usfm' || isJson) { } } -if (Object.prototype.hasOwnProperty.call(argv, 'o') || Object.prototype.hasOwnProperty.call(argv, 'output')) { - let filePath = argv.o; - if (!filePath) { - filePath = argv.output; - } - try { - fs.writeFileSync(filePath, output); - } catch (e) { - console.error('Error writting output file'); - console.error(e.message); - process.exit(1); - } -} else { - console.log(output); -} +console.log(output); diff --git a/js/USFMparser.js b/js/USFMparser.js index 2bdd9c2b..ac0421bb 100644 --- a/js/USFMparser.js +++ b/js/USFMparser.js @@ -137,6 +137,10 @@ class USFMParser extends Parser { toCSV() { const jsonOutput = this.toJSON(); + if (Object.keys(jsonOutput).includes('_messages') + && Object.keys(jsonOutput._messages).includes('_error')) { + return jsonOutput; + } const myJsonParser = new JSONParser(jsonOutput); const csvOutput = myJsonParser.toCSV(); return csvOutput; @@ -144,6 +148,10 @@ class USFMParser extends Parser { toTSV() { const jsonOutput = this.toJSON(); + if (Object.keys(jsonOutput).includes('_messages') + && Object.keys(jsonOutput._messages).includes('_error')) { + return jsonOutput; + } const myJsonParser = new JSONParser(jsonOutput); const csvOutput = myJsonParser.toTSV(); return csvOutput; diff --git a/js/grammarOperations-relaxed.js b/js/grammarOperations-relaxed.js index 98021372..bc5b6d08 100644 --- a/js/grammarOperations-relaxed.js +++ b/js/grammarOperations-relaxed.js @@ -1,5 +1,6 @@ const ohm = require('ohm-js'); const { contents: grammar } = require('../grammar/usfm-relaxed.ohm.js'); +const { buildVerseText } = require('./grammarOperations.js'); const { usfmRelaxed: bib } = ohm.grammars(grammar); const sem = bib.createSemantics(); @@ -11,15 +12,15 @@ const sem = bib.createSemantics(); // We need to know which all marker's contents should be considered as verseText // while composing the .verseText property of each verse element. // This list is consulted for that -const verseCarryingMarkers = ['li', 'li1', 'li2', 'li3', 'lh', 'lf', 'lim', 'litl', - 'lik', 'liv', 'liv1', 'liv2', 'liv3', 'th', 'th1', 'th2', 'th3', - 'thr', 'thr1', 'thr2', 'thr3', 'tc', 'tc1', 'tc2', 'tc3', 'tcr', - 'tcr1', 'tcr2', 'tcr3', 'add', 'bk', 'dc', 'k', 'lit', 'nd', 'ord', - 'pn', 'png', 'addpn', 'qt', 'sig', 'sls', 'tl', 'wj', 'em', 'bd', - 'it', 'bdit', 'no', 'sc', 'sup', 'w', 'rb', 'wa', 'wg', 'wh', 'pro', - '+add', '+bk', '+dc', '+k', '+lit', '+nd', '+ord', '+pn', '+png', - '+addpn', '+qt', '+sig', '+sls', '+tl', '+wj', '+em', '+bd', '+it', - '+bdit', '+no', '+sc', '+sup', '+w', '+rb', '+wa', '+wg', '+wh', '+pro']; +// const verseCarryingMarkers = ['li', 'li1', 'li2', 'li3', 'lh', 'lf', 'lim', 'litl', +// 'lik', 'liv', 'liv1', 'liv2', 'liv3', 'th', 'th1', 'th2', 'th3', +// 'thr', 'thr1', 'thr2', 'thr3', 'tc', 'tc1', 'tc2', 'tc3', 'tcr', +// 'tcr1', 'tcr2', 'tcr3', 'add', 'bk', 'dc', 'k', 'lit', 'nd', 'ord', +// 'pn', 'png', 'addpn', 'qt', 'sig', 'sls', 'tl', 'wj', 'em', 'bd', +// 'it', 'bdit', 'no', 'sc', 'sup', 'w', 'rb', 'wa', 'wg', 'wh', 'pro', +// '+add', '+bk', '+dc', '+k', '+lit', '+nd', '+ord', '+pn', '+png', +// '+addpn', '+qt', '+sig', '+sls', '+tl', '+wj', '+em', '+bd', '+it', +// '+bdit', '+no', '+sc', '+sup', '+w', '+rb', '+wa', '+wg', '+wh', '+pro']; // In normal grammar these markers are implemented as not containing text or other contents. // The relaxed grammar doesnot implement makers separately but have general rules for all. @@ -30,7 +31,7 @@ const paraMarkers = ['p', 'm', 'po', 'pr', 'cls', 'pmo', 'pm', 'pmc', 'ph3', 'b', 'q', 'q1', 'q2', 'q3', 'qr', 'qc', 'qs', 'qa', 'qac', 'qm', 'qm1', 'qm2', 'qm3']; -const punctPattern = new RegExp('^[,./;:\'"`~!@#$%^&*(){}[}|]'); +// const punctPattern = new RegExp('^[,./;:\'"`~!@#$%^&*(){}[}|]'); sem.addOperation('buildJson', { File(bookhead, chapters) { @@ -105,42 +106,7 @@ sem.addOperation('buildJson', { verseNumber: num.sourceString.trim(), contents: contents.buildJson(), }; - res.verseText = ''; - for (let i = 0; i < res.contents.length; i += 1) { - if (typeof res.contents[i] === 'string') { - if (punctPattern.test(res.contents[i])) { - res.verseText = res.verseText.trim(); - res.verseText += res.contents[i]; - } else { - res.verseText += ` ${res.contents[i]}`; - } - } else { - // console.log(res.contents[i].keys()); - const key = Object.keys(res.contents[i])[0]; - if (verseCarryingMarkers.includes(key)) { - if (punctPattern.test(res.contents[i][key])) { - res.verseText = res.verseText.trim(); - res.verseText += res.contents[i][key]; - } else { - res.verseText += ` ${res.contents[i][key]}`; - } - } else if (paraMarkers.includes(key)) { - const text = res.contents[i][key]; - if (punctPattern.test(text)) { - res.verseText = res.verseText.trim(); - res.verseText += text; - } else { - res.verseText += ` ${text}`; - } - res.contents[i][key] = null; - if (text !== '') { - res.contents.splice(i + 1, 0, text); - i += 1; - } - } - } - } - res.verseText = res.verseText.replace(/ +/g, ' ').trim(); + res.verseText = buildVerseText(res.contents).replace(/ +/g, ' ').trim(); return res; }, diff --git a/js/grammarOperations.js b/js/grammarOperations.js index 3d17af44..3b889bb7 100644 --- a/js/grammarOperations.js +++ b/js/grammarOperations.js @@ -25,10 +25,10 @@ const verseCarryingMarkers = ['li', 'li1', 'li2', 'li3', 'lh', 'lf', 'lim', 'lit '+addpn', '+qt', '+sig', '+sls', '+tl', '+wj', '+em', '+bd', '+it', '+bdit', '+no', '+sc', '+sup', '+w', '+rb', '+wa', '+wg', '+wh', '+pro']; -// const paraMarkers = ['p', 'm', 'po', 'pr', 'cls', 'pmo', 'pm', 'pmc', -// 'pmr', 'pi', 'pi1', 'pi2', 'pi3', 'mi', 'nb', 'pc', 'ph', 'ph1', 'ph2', -// 'ph3', 'b', 'q', 'q1', 'q2', 'q3', 'qr', 'qc', 'qs', 'qa', 'qac', 'qm', -// 'qm1', 'qm2', 'qm3']; +const paraMarkers = ['p', 'm', 'po', 'pr', 'cls', 'pmo', 'pm', 'pmc', + 'pmr', 'pi', 'pi1', 'pi2', 'pi3', 'mi', 'nb', 'pc', 'ph', 'ph1', 'ph2', + 'ph3', 'b', 'q', 'q1', 'q2', 'q3', 'qr', 'qc', 'qs', 'qa', 'qac', 'qm', + 'qm1', 'qm2', 'qm3']; const punctPattern = new RegExp('^[,./;:\'"`~!@#$%^&*(){}[}|]'); @@ -36,6 +36,16 @@ function buildVerseText(elmts) { let verseTextPartial = ''; if (typeof elmts === 'string') { verseTextPartial = elmts; + } else if (Array.isArray(elmts)) { + for (let i = 0; i < elmts.length; i += 1) { + const text = buildVerseText(elmts[i]); + if (punctPattern.test(text)) { + verseTextPartial = verseTextPartial.trim(); + verseTextPartial += text; + } else { + verseTextPartial += ` ${text}`; + } + } } else { const key = Object.keys(elmts)[0]; if (verseCarryingMarkers.includes(key) && typeof elmts[key] === 'string') { @@ -70,6 +80,8 @@ function buildVerseText(elmts) { if (elmts.text !== null) { verseTextPartial = elmts.text; } + } else if (paraMarkers.includes(key) && elmts[key] !== null) { + verseTextPartial = buildVerseText(elmts[key]); } } return verseTextPartial; @@ -210,26 +222,15 @@ sem.addOperation('composeJson', { verse.contents = []; if (verseMeta.sourceString !== '') { const metadata = verseMeta.composeJson(); - verse.contents.concat(metadata); + verse.contents = verse.contents.concat(metadata); } const elmts = verseContent.composeJson(); if (verseContent.sourceString === '') { emitter.emit('warning', new Error(`Verse text is empty, at \\v ${verseNumber.sourceString}. `)); + } else { + verse.contents = verse.contents.concat(elmts); } - for (let i = 0; i < elmts.length; i += 1) { - const text = buildVerseText(elmts[i]); - if (punctPattern.test(text)) { - verse.verseText = verse.verseText.trim(); - verse.verseText += text; - } else { - verse.verseText += ` ${text}`; - } - if (Object.prototype.hasOwnProperty.call(elmts[i], 'table')) { - delete elmts[i].text; - } - verse.contents.push(elmts[i]); - } - verse.verseText = verse.verseText.trim().replace(/ +/g, ' '); + verse.verseText = buildVerseText(elmts).trim().replace(/ +/g, ' '); return verse; }, @@ -1219,3 +1220,4 @@ function match(str) { } exports.match = match; +exports.buildVerseText = buildVerseText; diff --git a/package-lock.json b/package-lock.json index 0e0af778..d31b5d43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "usfm-grammar", - "version": "2.0.0-beta.6", + "version": "2.0.0-beta.7", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -193,6 +193,12 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -326,6 +332,18 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, "confusing-browser-globals": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", @@ -1693,6 +1711,17 @@ "read-pkg": "^2.0.0" } }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, "readdirp": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", @@ -1882,6 +1911,15 @@ "es-abstract": "^1.17.5" } }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, "strip-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", @@ -1965,6 +2003,12 @@ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", @@ -1974,6 +2018,12 @@ "punycode": "^2.1.0" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, "util-extend": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", diff --git a/package.json b/package.json index 79d2b59c..54f3f296 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "test": "mocha --expose-gc --timeout 40000", "start": "node ../server.js", "lint": "eslint .", - "test-on-github": "mocha --expose-gc --timeout 40000 --ignore test/test_filesFromWild.js" + "test-on-github": "mocha --expose-gc --timeout 40000 --ignore test/test_filesFromWild.js --ignore test/test_cli.js" }, "dependencies": { "jsonschema": "^1.4.0", @@ -34,6 +34,7 @@ }, "homepage": "https://github.com/Bridgeconn/usfm-grammar", "devDependencies": { + "concat-stream": "^2.0.0", "eslint": "^7.7.0", "eslint-config-airbnb-base": "^14.2.0", "eslint-plugin-import": "^2.22.0", diff --git a/test/resources/small.json b/test/resources/small.json new file mode 100644 index 00000000..eb27ca74 --- /dev/null +++ b/test/resources/small.json @@ -0,0 +1,40 @@ +{ + "book": { + "bookCode": "GEN", + "description": "A small sample usfm file" + }, + "chapters": [ + { + "chapterNumber": "1", + "contents": [ + { + "p": null + }, + { + "verseNumber": "1", + "verseText": "one verse", + "contents": [ + "one verse" + ] + }, + { + "verseNumber": "2", + "verseText": "second verse", + "contents": [ + "second verse" + ] + }, + { + "verseNumber": "3", + "verseText": "final verse", + "contents": [ + "final verse" + ] + } + ] + } + ], + "_messages": { + "_warnings": [] + } +} \ No newline at end of file diff --git a/test/resources/small.usfm b/test/resources/small.usfm new file mode 100644 index 00000000..d635d633 --- /dev/null +++ b/test/resources/small.usfm @@ -0,0 +1,6 @@ +\id GEN A small sample usfm file +\c 1 +\p +\v 1 one verse +\v 2 second verse +\v 3 final verse \ No newline at end of file diff --git a/test/resources/small1.json b/test/resources/small1.json new file mode 100644 index 00000000..eb27ca74 --- /dev/null +++ b/test/resources/small1.json @@ -0,0 +1,40 @@ +{ + "book": { + "bookCode": "GEN", + "description": "A small sample usfm file" + }, + "chapters": [ + { + "chapterNumber": "1", + "contents": [ + { + "p": null + }, + { + "verseNumber": "1", + "verseText": "one verse", + "contents": [ + "one verse" + ] + }, + { + "verseNumber": "2", + "verseText": "second verse", + "contents": [ + "second verse" + ] + }, + { + "verseNumber": "3", + "verseText": "final verse", + "contents": [ + "final verse" + ] + } + ] + } + ], + "_messages": { + "_warnings": [] + } +} \ No newline at end of file diff --git a/test/resources/small2.json b/test/resources/small2.json new file mode 100644 index 00000000..eb27ca74 --- /dev/null +++ b/test/resources/small2.json @@ -0,0 +1,40 @@ +{ + "book": { + "bookCode": "GEN", + "description": "A small sample usfm file" + }, + "chapters": [ + { + "chapterNumber": "1", + "contents": [ + { + "p": null + }, + { + "verseNumber": "1", + "verseText": "one verse", + "contents": [ + "one verse" + ] + }, + { + "verseNumber": "2", + "verseText": "second verse", + "contents": [ + "second verse" + ] + }, + { + "verseNumber": "3", + "verseText": "final verse", + "contents": [ + "final verse" + ] + } + ] + } + ], + "_messages": { + "_warnings": [] + } +} \ No newline at end of file diff --git a/test/test_cli.js b/test/test_cli.js new file mode 100644 index 00000000..05b53c55 --- /dev/null +++ b/test/test_cli.js @@ -0,0 +1,231 @@ +const { spawn } = require('child_process'); +const concat = require('concat-stream'); +const assert = require('assert'); + +function createProcess(args = [], env = null) { + // args = [processPath].concat(args); + + return spawn('usfm-grammar', args, { + env: { + NODE_ENV: 'test', + ...env, + }, + }); +} + +function execute(processPath, args = [], opts = {}) { + const { env = null } = opts; + const childProcess = createProcess(args, env); + childProcess.stdin.setEncoding('utf-8'); + const promise = new Promise((resolve, reject) => { + childProcess.stderr.once('data', (err) => { + reject(err.toString()); + }); + childProcess.on('error', reject); + childProcess.stdout.pipe( + concat((result) => { + resolve(result.toString()); + }), + ); + }); + return promise; +} + +describe('Test CLI: version and help', () => { + it('version with --version', async () => { + const response = await execute( + 'usfm-grammar', + ['--version'], + ); + const versionPattern = new RegExp('^\\d\\.\\d\\.\\d.*', 'g'); + assert.match(response, versionPattern); + }); + + it('version with -v', async () => { + const response = await execute( + 'usfm-grammar', + ['-v'], + ); + const versionPattern = new RegExp('^\\d\\.\\d\\.\\d.*', 'g'); + assert.match(response, versionPattern); + }); + + it('No arg', async () => { + let thrownError = false; + try { + await execute( + 'usfm-grammar', + [], + ); + } catch (err) { + thrownError = true; + const helpPattern = new RegExp('^usfm-grammar \\n.*', 'g'); + assert.match(err, helpPattern); + } + assert.strictEqual(thrownError, true); + }); + + it('Wrong argument', async () => { + let thrownError = false; + try { + await execute( + 'usfm-grammar', + ['-f'], + ); + } catch (err) { + thrownError = true; + const helpPattern = new RegExp('^usfm-grammar \\n.*', 'g'); + assert.match(err, helpPattern); + } + assert.strictEqual(thrownError, true); + }); + + it('help with -h', async () => { + const response = await execute( + 'usfm-grammar', + ['-h'], + ); + const helpPattern = new RegExp('^usfm-grammar \\n.*', 'g'); + assert.match(response, helpPattern); + }); + + it('help with --help', async () => { + const response = await execute( + 'usfm-grammar', + ['--help'], + ); + const helpPattern = new RegExp('^usfm-grammar \\n.*', 'g'); + assert.match(response, helpPattern); + }); +}); + +describe('Test CLI: USFM parsing', () => { + it('one file argument', async () => { + const response = await execute( + 'usfm-grammar', + ['./test/resources/small.usfm'], + ); + const jsonObj = JSON.parse(response); + assert.strictEqual(Object.keys(jsonObj).includes('book'), true); + assert.strictEqual(Object.keys(jsonObj).includes('chapters'), true); + }); + + it('with invalid file', async () => { + const response = await execute( + 'usfm-grammar', + ['./test/test.js'], + ); + const jsonObj = JSON.parse(response); + assert.strictEqual(Object.keys(jsonObj).includes('_messages'), true); + assert.strictEqual(Object.keys(jsonObj._messages).includes('_error'), true); + }); + + it('level relaxed, with --level=relaxed', async () => { + const response = await execute( + 'usfm-grammar', + ['./test/resources/small.usfm', '--level=relaxed'], + ); + const jsonObj = JSON.parse(response); + assert.strictEqual(Object.keys(jsonObj).includes('book'), true); + assert.strictEqual(Object.keys(jsonObj).includes('chapters'), true); + }); + + it('level relaxed, with -l relaxed', async () => { + const response = await execute( + 'usfm-grammar', + ['./test/resources/small.usfm', '-l', 'relaxed'], + ); + const jsonObj = JSON.parse(response); + assert.strictEqual(Object.keys(jsonObj).includes('book'), true); + assert.strictEqual(Object.keys(jsonObj).includes('chapters'), true); + }); + + it('level relaxed, with --level relaxed', async () => { + const response = await execute( + 'usfm-grammar', + ['./test/resources/small.usfm', '--level', 'relaxed'], + ); + const jsonObj = JSON.parse(response); + assert.strictEqual(Object.keys(jsonObj).includes('book'), true); + assert.strictEqual(Object.keys(jsonObj).includes('chapters'), true); + }); + + it('level, without value', async () => { + let thrownError = false; + try { + await execute( + 'usfm-grammar', + ['--level'], + ); + } catch (err) { + thrownError = true; + const helpPattern = new RegExp('^usfm-grammar \\n.*', 'g'); + assert.match(err, helpPattern); + } + assert.strictEqual(thrownError, true); + }); + + it('scripture filtered, with --filter scripture', async () => { + const response = await execute( + 'usfm-grammar', + ['./test/resources/small.usfm', '--filter', 'scripture'], + ); + const jsonObj = JSON.parse(response); + assert.strictEqual(Object.keys(jsonObj).includes('book'), true); + assert.strictEqual(Object.keys(jsonObj).includes('chapters'), true); + }); + + it('filter with wrong value', async () => { + let thrownError = false; + try { + await execute( + 'usfm-grammar', + ['./test/resources/small.usfm', '--level', 'bible'], + ); + } catch (err) { + thrownError = true; + const helpPattern = new RegExp('^usfm-grammar \\n.*', 'g'); + assert.match(err, helpPattern); + } + assert.strictEqual(thrownError, true); + }); + + it('both filter and level arguments', async () => { + const response = await execute( + 'usfm-grammar', + ['./test/resources/small.usfm', '--filter', 'scripture', '--level', 'relaxed'], + ); + const jsonObj = JSON.parse(response); + assert.strictEqual(Object.keys(jsonObj).includes('book'), true); + assert.strictEqual(Object.keys(jsonObj).includes('chapters'), true); + }); + + it('output format specified, with --format==csv', async () => { + const response = await execute( + 'usfm-grammar', + ['./test/resources/small.usfm', '--format=csv'], + ); + const csvPattern = new RegExp('Book, Chapter, Verse, Text\\n.*', 'g'); + assert.match(response, csvPattern); + }); +}); + +describe('Test CLI: JSON parsing', () => { + it('with one json file-path', async () => { + const response = await execute( + 'usfm-grammar', + ['./test/resources/small.json'], + ); + const usfmPattern = new RegExp('^\\\\id GEN A small sample usfm file\\n.*', 'g'); + assert.match(response, usfmPattern); + }); + + it('with additional arguments', async () => { + const response = await execute( + 'usfm-grammar', + ['./test/resources/small.json', '--filter', 'scripture'], + ); + const usfmPattern = new RegExp('^\\\\id GEN A small sample usfm file\\n.*', 'g'); + assert.match(response, usfmPattern); + }); +});