Skip to content
Permalink
Browse files

Fix bug in stream processor

  • Loading branch information...
antonmedv committed Feb 25, 2019
1 parent 47b5bb2 commit bfb8aa4534daf94ad59674062993d5bf980114e5
Showing with 107 additions and 74 deletions.
  1. +1 −1 README.md
  2. +2 −72 index.js
  3. +2 −1 package.json
  4. +74 −0 stream.js
  5. +28 −0 test.js
@@ -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

@@ -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
}
}
}
}
}
}
@@ -15,7 +15,8 @@
"fx.js",
"index.js",
"print.js",
"reduce.js"
"reduce.js",
"stream.js"
],
"scripts": {
"test": "ava",
@@ -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
@@ -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()
}
})

0 comments on commit bfb8aa4

Please sign in to comment.
You can’t perform that action at this time.