stream-json
Advanced tools
Comparing version 0.5.1 to 0.5.2
117
Filter.js
@@ -23,2 +23,3 @@ "use strict"; | ||
this._separator = options.separator || "."; | ||
this._defaultValue = options.defaultValue || [{name: "nullValue", value: null}]; | ||
@@ -54,2 +55,28 @@ this._previous = []; | ||
return; | ||
case "startObject": | ||
case "startArray": | ||
case "startString": | ||
case "startNumber": | ||
case "nullValue": | ||
case "trueValue": | ||
case "falseValue": | ||
// update array's index | ||
if(this._stack.length){ | ||
var top = this._stack[this._stack.length - 1]; | ||
if(top === false){ | ||
this._stack[this._stack.length - 1] = 0; | ||
}else if(typeof top == "number"){ | ||
this._stack[this._stack.length - 1] = top + 1; | ||
} | ||
} | ||
break; | ||
} | ||
switch(chunk.name){ | ||
case "startObject": | ||
this._stack.push(true); | ||
break; | ||
case "startArray": | ||
this._stack.push(false); | ||
break; | ||
case "endObject": | ||
@@ -65,9 +92,3 @@ case "endArray": | ||
case "startObject": | ||
this._stack.push(true); | ||
this._sync(); | ||
break; | ||
case "startArray": | ||
this._stack.push(0); | ||
this._sync(); | ||
break; | ||
case "endObject": | ||
@@ -84,16 +105,2 @@ case "endArray": | ||
// update stack | ||
switch(chunk.name){ | ||
case "endObject": | ||
case "endArray": | ||
case "endString": | ||
case "endNumber": | ||
case "nullValue": | ||
case "trueValue": | ||
case "falseValue": | ||
// update array's index | ||
var index = this._stack.pop(); | ||
this._stack.push(typeof index == "number" ? index + 1 : index); | ||
break; | ||
} | ||
callback(); | ||
@@ -111,3 +118,3 @@ }; | ||
s = this._stack, sl = s.length, | ||
n = Math.min(pl, sl), i, j, value; | ||
n = Math.min(pl, sl), i, j, k, value; | ||
for(i = 0; i < n && p[i] === s[i]; ++i); | ||
@@ -117,17 +124,20 @@ if(pl === sl && i >= n){ | ||
} | ||
for(j = pl - 1; j > i; --j){ | ||
for(j = pl - 1, k = n && i < n ? i : i - 1; j > k; --j){ | ||
value = p[j]; | ||
this.push({name: typeof value == "number" ? "endArray" : "endObject"}); | ||
if(value === true){ | ||
this.push({name: "startObject"}); | ||
this.push({name: "endObject"}); | ||
}else if(value === false){ | ||
this.push({name: "startArray"}); | ||
this.push({name: "endArray"}); | ||
}else{ | ||
this.push({name: typeof value == "number" ? "endArray" : "endObject"}); | ||
} | ||
} | ||
if(pl <= i){ | ||
value = s[i]; | ||
this.push({name: typeof value == "number" ? "startArray" : "startObject"}); | ||
} | ||
if(sl <= i){ | ||
value = p[i]; | ||
this.push({name: typeof value == "number" ? "endArray" : "endObject"}); | ||
} | ||
if(i < sl){ | ||
value = s[i]; | ||
if(typeof value == "string"){ | ||
if(n && i < n){ | ||
if(p[i] === true || typeof p[i] == "string"){ | ||
if(p[i] === true){ | ||
this.push({name: "startObject"}); | ||
} | ||
value = s[i]; | ||
this.push({name: "startKey"}); | ||
@@ -137,6 +147,20 @@ this.push({name: "stringChunk", value: value}); | ||
this.push({name: "keyValue", value: value}); | ||
}else if(p[i] === false || typeof p[i] == "number"){ | ||
if(p[i] === false){ | ||
this.push({name: "startArray"}); | ||
} | ||
if(this._defaultValue.length){ | ||
value = s[i] || 0; | ||
for(j = (p[i] || 0) + 1; j < value; ++j) { | ||
this._defaultValue.forEach(function(chunk){ | ||
this.push(chunk); | ||
}, this); | ||
} | ||
} | ||
} | ||
for(j = i + 1; j < sl; ++j){ | ||
value = s[j]; | ||
if(typeof value == "string"){ | ||
} | ||
for(j = n && i < n ? i + 1 : i; j < sl; ++j){ | ||
value = s[j]; | ||
switch(typeof value){ | ||
case "string": | ||
this.push({name: "startObject"}); | ||
@@ -147,7 +171,13 @@ this.push({name: "startKey"}); | ||
this.push({name: "keyValue", value: value}); | ||
}else if(typeof value == "boolean"){ | ||
this.push({name: "startObject"}); | ||
}else{ | ||
break; | ||
case "number": | ||
this.push({name: "startArray"}); | ||
} | ||
if(this._defaultValue.length){ | ||
for(k = 0; k < value; ++k){ | ||
this._defaultValue.forEach(function(chunk){ | ||
this.push(chunk); | ||
}, this); | ||
} | ||
} | ||
break; | ||
} | ||
@@ -158,4 +188,5 @@ } | ||
Filter.prototype._pattern = function pattern(path){ | ||
return this._regexp.test(path.join(this._separator)); | ||
Filter.prototype._pattern = function pattern(stack){ | ||
var path = stack.filter(function(value){ return typeof value != "boolean"; }).join(this._separator); | ||
return this._regexp.test(path); | ||
}; | ||
@@ -162,0 +193,0 @@ |
{ | ||
"name": "stream-json", | ||
"version": "0.5.1", | ||
"version": "0.5.2", | ||
"description": "stream-json is a SAX-inspired stream components with a minimal memory footprint to parse huge JSON files. Includes utilities to stream Django-like JSON database dumps.", | ||
@@ -5,0 +5,0 @@ "homepage": "http://github.com/uhop/stream-json", |
@@ -241,2 +241,8 @@ # stream-json | ||
* If it is a regular expression, then a current `path` is joined be a `separator` and tested against the regular expression. If a match was found, it indicates that the event should be passed through. Otherwise it will be rejected. | ||
* `defaultValue` is an array of event objects described above, which substitute skipped array items. By default it is `[{name: "nullValue", value: null}]` — a `null` value. | ||
* `filter` can skip some array items. If it happens, `defaultValue` events are going to be inserted for every previously skipped item. | ||
* If all array items were skipped, an empty array will be issued. | ||
* Skipped items at the end of array are not substituted with `defaultValue`. A truncated array will be issued. | ||
* **Important:** make sure that the sequence of events make sense, and do not violate JSON invariants. For example, all `startXXX` and `endXXX` should be properly balanced. | ||
* It is possible to specify an empty array of events. | ||
@@ -267,2 +273,4 @@ `Filter` produces a well-formed event stream. | ||
The top element of a stack can be `true` or `false`. The former means that an object was open, but no keys were processed. The latter means that an array was open, but no items were processed. Both values can be present in an array path, but not in a string path. | ||
### Source | ||
@@ -688,2 +696,4 @@ | ||
- 0.5.2 *bug fixes in `Filter`* | ||
- 0.5.1 *corrected README* | ||
- 0.5.0 *added support for [JSON Streaming](https://en.wikipedia.org/wiki/JSON_Streaming)* | ||
@@ -690,0 +700,0 @@ - 0.4.2 *refreshed dependencies.* |
@@ -8,4 +8,7 @@ "use strict"; | ||
var Streamer = require("../Streamer"); | ||
var Combo = require("../Combo"); | ||
var Filter = require("../Filter"); | ||
var Asm = require("../utils/Assembler"); | ||
var ReadString = require("./ReadString"); | ||
@@ -45,3 +48,70 @@ | ||
}); | ||
}, | ||
function test_filter_deep(t){ | ||
var async = t.startAsync("test_filter_deep"); | ||
var data = {a: {b: {c: 1}}, b: {b: {c: 2}}, c: {b: {c: 3}}}; | ||
const pipeline = new ReadString(JSON.stringify(data)). | ||
pipe(new Combo({packKeys: true, packStrings: true, packNumbers: true})). | ||
pipe(new Filter({filter: /^(?:a|c)\.b\b/})); | ||
const asm = new Asm(); | ||
pipeline.on('data', function (chunk) { | ||
asm[chunk.name] && asm[chunk.name](chunk.value); | ||
}); | ||
pipeline.on('end', function () { | ||
eval(t.TEST("t.unify(asm.current, {a: {b: {c: 1}}, c: {b: {c: 3}}})")); | ||
async.done(); | ||
}); | ||
}, | ||
function test_filter_array(t){ | ||
var async = t.startAsync("test_filter_array"); | ||
var data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; | ||
const pipeline = new ReadString(JSON.stringify(data)). | ||
pipe(new Combo({packKeys: true, packStrings: true, packNumbers: true})). | ||
pipe(new Filter({filter: function (stack) { | ||
return stack.length == 1 && typeof stack[0] == "number" && stack[0] % 2; | ||
}})); | ||
const asm = new Asm(); | ||
pipeline.on('data', function (chunk) { | ||
asm[chunk.name] && asm[chunk.name](chunk.value); | ||
}); | ||
pipeline.on('end', function () { | ||
eval(t.TEST("t.unify(asm.current, [null, 2, null, 4, null, 6, null, 8, null, 10])")); | ||
async.done(); | ||
}); | ||
}, | ||
function test_filter_default_value(t){ | ||
var async = t.startAsync("test_filter_default_value"); | ||
var data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; | ||
const pipeline = new ReadString(JSON.stringify(data)). | ||
pipe(new Combo({packKeys: true, packStrings: true, packNumbers: true})). | ||
pipe(new Filter({defaultValue: [], filter: function (stack) { | ||
return stack.length == 1 && typeof stack[0] == "number" && stack[0] % 2; | ||
}})); | ||
const asm = new Asm(); | ||
pipeline.on('data', function (chunk) { | ||
asm[chunk.name] && asm[chunk.name](chunk.value); | ||
}); | ||
pipeline.on('end', function () { | ||
eval(t.TEST("t.unify(asm.current, [2, 4, 6, 8, 10])")); | ||
async.done(); | ||
}); | ||
} | ||
]); |
218428
59
3848
719
243