Fix bug in stream processor

This commit is contained in:
Anton Medvedev 2019-02-26 02:06:12 +07:00
parent 47b5bb2366
commit bfb8aa4534
5 changed files with 107 additions and 74 deletions

View File

@ -6,7 +6,7 @@ _* Function eXecution_
[![Build Status](https://travis-ci.org/antonmedv/fx.svg?branch=master)](https://travis-ci.org/antonmedv/fx)
[![Npm Version](https://img.shields.io/npm/v/fx.svg)](https://www.npmjs.com/package/fx)
[![Brew Version](https://img.shields.io/homebrew/v/fx.svg)](https://formulae.brew.sh/formula/fx)
[![Snap Version](https://img.shields.io/badge/snap-12.0.0-blue.svg)](https://snapcraft.io/fx)
[![Snap Version](https://img.shields.io/badge/snap-12.0.2-blue.svg)](https://snapcraft.io/fx)
Command-line JSON processing tool

View File

@ -14,6 +14,7 @@ try {
const print = require('./print')
const reduce = require('./reduce')
const stream = require('./stream')
const usage = `
Usage
@ -54,7 +55,7 @@ void function main() {
return
}
const reader = stream()
const reader = stream(stdin, apply)
stdin.on('readable', reader.read)
stdin.on('end', () => {
@ -130,74 +131,3 @@ function select(cb) {
return json
}
}
function stream() {
let buff = ''
let len = 0
let depth = 0
let isString = false
let count = 0
let head = ''
const check = (i) => {
if (depth <= 0) {
const input = buff.substring(0, len + i + 1)
if (count > 0) {
if (head !== '') {
const json = JSON.parse(head)
apply(json)
head = ''
}
const json = JSON.parse(input)
apply(json)
} else {
head = input
}
buff = buff.substring(len + i + 1)
len = buff.length
count++
}
}
return {
isStream() {
return count > 1
},
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 === 0 && buff[len - 1] !== '\\') || (i > 0 && chunk[i - 1] !== '\\')) {
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
}
}
}
}
}
}

View File

@ -15,7 +15,8 @@
"fx.js",
"index.js",
"print.js",
"reduce.js"
"reduce.js",
"stream.js"
],
"scripts": {
"test": "ava",

74
stream.js Normal file
View File

@ -0,0 +1,74 @@
'use strict'
function stream(from, cb) {
let buff = ''
let lastChar = ''
let len = 0
let depth = 0
let isString = false
let count = 0
let head = ''
const check = (i) => {
if (depth <= 0) {
const input = buff.substring(0, len + i + 1)
if (count > 0) {
if (head !== '') {
const json = JSON.parse(head)
cb(json)
head = ''
}
const json = JSON.parse(input)
cb(json)
} else {
head = input
}
buff = buff.substring(len + i + 1)
len = -i - 1
count++
}
}
return {
isStream() {
return count > 1
},
value() {
return head + buff
},
read() {
let chunk
while ((chunk = from.read())) {
len = buff.length
buff += chunk
for (let i = 0; i < chunk.length; i++) {
if (isString) {
if (chunk[i] === '"' && ((i === 0 && lastChar !== '\\') || (i > 0 && chunk[i - 1] !== '\\'))) {
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
}
}
lastChar = chunk[chunk.length - 1]
}
}
}
}
module.exports = stream

28
test.js
View File

@ -1,6 +1,7 @@
'use strict'
const test = require('ava')
const {execSync} = require('child_process')
const stream = require('./stream')
function fx(json, code = '') {
return execSync(`echo '${JSON.stringify(json)}' | node index.js ${code}`).toString('utf8')
@ -45,3 +46,30 @@ test('file argument', t => {
const r = execSync(`node index.js package.json .name`).toString('utf8')
t.deepEqual(r, 'fx\n')
})
test('stream', t => {
const input = `
{"index": 0} {"index": 1}
{"index": 2, "quote": "\\""}
{"index": 3} "Hello" "world"
{"index": 6, "key": "one \\"two\\" three"}
`
t.plan(7 * (input.length - 1))
for (let i = 0; i < input.length; i++) {
const parts = [input.substring(0, i), input.substring(i)]
const reader = stream(
{
read() {
return parts.shift()
}
},
json => {
t.pass()
}
)
reader.read()
}
})