From d571194fc8d51b1aeb42abaa3d87049d4ca93f11 Mon Sep 17 00:00:00 2001 From: Anton Medvedev Date: Mon, 25 Feb 2019 01:41:01 +0700 Subject: [PATCH] Add streaming support --- README.md | 4 +- index.js | 119 ++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 95 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 55d7322..4da4888 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,11 @@ Command-line JSON processing tool ## Features -* Formatting and highlighting +* Easy to use * Standalone binary * Interactive mode 🎉 * Themes support 🎨 -* Easily expandable +* Streaming support 🌊 ## Install diff --git a/index.js b/index.js index 1e95a1e..4bc97df 100755 --- a/index.js +++ b/index.js @@ -14,7 +14,6 @@ try { const print = require('./print') const reduce = require('./reduce') -const {stdin, stdout, stderr} = process const usage = ` Usage @@ -23,7 +22,7 @@ const usage = ` Examples $ echo '{"key": "value"}' | fx 'x => x.key' value - + $ echo '{"key": "value"}' | fx .key value @@ -35,46 +34,36 @@ const usage = ` $ echo '{"count": 0}' | fx '{...this, count: 1}' {"count": 1} - + $ echo '{"foo": 1, "bar": 2}' | fx ? ["foo", "bar"] - + ` +const {stdin, stdout, stderr} = process +const args = process.argv.slice(2) const skip = Symbol('skip') +global.select = select void function main() { - const args = process.argv.slice(2) - stdin.setEncoding('utf8') + if (stdin.isTTY) { - handle('', args) + handle('') return } - let buff = '' - stdin.on('readable', () => { - let chunk, input - - while ((chunk = stdin.read())) { - buff += chunk - - // // Stream handle. - // if (buff.includes('\n')) { - // [input, buff] = buff.split('\n') - // apply(input, args) - // } - } - }) + const reader = stream() + stdin.on('readable', reader.read) stdin.on('end', () => { - handle(buff, args) + handle(reader.value()) }) }() -function handle(input, args) { +function handle(input) { let filename = 'fx' if (input === '') { @@ -93,7 +82,7 @@ function handle(input, args) { input = fs.readFileSync(args[0]) filename = path.basename(args[0]) - args = args.slice(1) + args.shift() } const json = JSON.parse(input) @@ -103,11 +92,11 @@ function handle(input, args) { return } - apply(json, args) + apply(json) } -function apply(json, args) { +function apply(json) { let output try { @@ -129,3 +118,81 @@ function apply(json, args) { console.log(text) } } + + +function select(cb) { + return json => { + if (!cb(json)) { + throw skip + } + return json + } +} + + +function stream() { + let buff = '' + let len = 0 + let depth = 0 + let isString = false + let isStream = false + let head = '' + + const check = (i) => { + if (depth <= 0) { + const input = buff.substring(0, len + i + 1) + + if (isStream) { + if (head !== '') { + const json = JSON.parse(head) + apply(json) + head = '' + } + + const json = JSON.parse(input) + apply(json) + } else { + isStream = true + head = input + } + + buff = buff.substring(len + i + 1) + len = buff.length + } + } + + return { + value() { + return head + buff + }, + read() { + let chunk + + while ((chunk = stdin.read())) { + len = buff.length + buff += chunk + + for (let i = 0; i < chunk.length; i++) { + if (isString) { + if (chunk[i] === '"') { + if ((i > 1 && chunk[i - 1] !== '\\') || buff[buff.length] !== '\\') { + isString = false + check(i) + } + } + continue + } + + if (chunk[i] === '{' || chunk[i] === '[') { + depth++ + } else if (chunk[i] === '}' || chunk[i] === ']') { + depth-- + check(i) + } else if (chunk[i] === '"') { + isString = true + } + } + } + } + } +}