notes/node_modules/JSONStream/index.js

193 lines
3.9 KiB
JavaScript
Executable File

#! /usr/bin/env node
var Parser = require('jsonparse')
, through = require('through')
/*
the value of this.stack that creationix's jsonparse has is weird.
it makes this code ugly, but his problem is way harder that mine,
so i'll forgive him.
*/
exports.parse = function (path, map) {
var parser = new Parser()
var stream = through(function (chunk) {
if('string' === typeof chunk)
chunk = new Buffer(chunk)
parser.write(chunk)
},
function (data) {
if(data)
stream.write(data)
stream.queue(null)
})
if('string' === typeof path)
path = path.split('.').map(function (e) {
if (e === '*')
return true
else if (e === '') // '..'.split('.') returns an empty string
return {recurse: true}
else
return e
})
var count = 0, _key
if(!path || !path.length)
path = null
parser.onValue = function () {
if (!this.root && this.stack.length == 1)
stream.root = this.value
if(! path) return
var i = 0 // iterates on path
var j = 0 // iterates on stack
while (i < path.length) {
var key = path[i]
var c
j++
if (key && !key.recurse) {
c = (j === this.stack.length) ? this : this.stack[j]
if (!c) return
if (! check(key, c.key)) return
i++
} else {
i++
var nextKey = path[i]
if (! nextKey) return
while (true) {
c = (j === this.stack.length) ? this : this.stack[j]
if (!c) return
if (check(nextKey, c.key)) { i++; break}
j++
}
}
}
if (j !== this.stack.length) return
count ++
var data = this.value[this.key]
if(null != data)
if(null != (data = map ? map(data) : data))
stream.queue(data)
delete this.value[this.key]
}
parser._onToken = parser.onToken;
parser.onToken = function (token, value) {
parser._onToken(token, value);
if (this.stack.length === 0) {
if (stream.root) {
if(!path)
stream.queue(stream.root)
stream.emit('root', stream.root, count)
count = 0;
stream.root = null;
}
}
}
parser.onError = function (err) {
stream.emit('error', err)
}
return stream
}
function check (x, y) {
if ('string' === typeof x)
return y == x
else if (x && 'function' === typeof x.exec)
return x.exec(y)
else if ('boolean' === typeof x)
return x
else if ('function' === typeof x)
return x(y)
return false
}
exports.stringify = function (op, sep, cl, indent) {
indent = indent || 0
if (op === false){
op = ''
sep = '\n'
cl = ''
} else if (op == null) {
op = '[\n'
sep = '\n,\n'
cl = '\n]\n'
}
//else, what ever you like
var stream
, first = true
, anyData = false
stream = through(function (data) {
anyData = true
var json = JSON.stringify(data, null, indent)
if(first) { first = false ; stream.queue(op + json)}
else stream.queue(sep + json)
},
function (data) {
if(!anyData)
stream.queue(op)
stream.queue(cl)
stream.queue(null)
})
return stream
}
exports.stringifyObject = function (op, sep, cl, indent) {
indent = indent || 0
if (op === false){
op = ''
sep = '\n'
cl = ''
} else if (op == null) {
op = '{\n'
sep = '\n,\n'
cl = '\n}\n'
}
//else, what ever you like
var first = true
, anyData = false
stream = through(function (data) {
anyData = true
var json = JSON.stringify(data[0]) + ':' + JSON.stringify(data[1], null, indent)
if(first) { first = false ; this.queue(op + json)}
else this.queue(sep + json)
},
function (data) {
if(!anyData) this.queue(op)
this.queue(cl)
this.queue(null)
})
return stream
}
if(!module.parent && process.title !== 'browser') {
process.stdin
.pipe(exports.parse(process.argv[2]))
.pipe(exports.stringify('[', ',\n', ']\n', 2))
.pipe(process.stdout)
}