131 lines
3.4 KiB
Plaintext
131 lines
3.4 KiB
Plaintext
'use strict';
|
|
|
|
const FilterBase = require('./FilterBase');
|
|
const withParser = require('../utils/withParser');
|
|
|
|
class Filter extends FilterBase {
|
|
static make(options) {
|
|
return new Filter(options);
|
|
}
|
|
|
|
static withParser(options) {
|
|
return withParser(Filter.make, options);
|
|
}
|
|
|
|
constructor(options) {
|
|
super(options);
|
|
this._once = false;
|
|
this._lastStack = [];
|
|
}
|
|
|
|
_flush(callback) {
|
|
this._syncStack();
|
|
callback(null);
|
|
}
|
|
|
|
_checkChunk(chunk) {
|
|
switch (chunk.name) {
|
|
case 'startObject':
|
|
if (this._filter(this._stack, chunk)) {
|
|
this._syncStack();
|
|
this.push(chunk);
|
|
this._lastStack.push(null);
|
|
}
|
|
break;
|
|
case 'startArray':
|
|
if (this._filter(this._stack, chunk)) {
|
|
this._syncStack();
|
|
this.push(chunk);
|
|
this._lastStack.push(-1);
|
|
}
|
|
break;
|
|
case 'nullValue':
|
|
case 'trueValue':
|
|
case 'falseValue':
|
|
case 'stringValue':
|
|
case 'numberValue':
|
|
if (this._filter(this._stack, chunk)) {
|
|
this._syncStack();
|
|
this.push(chunk);
|
|
}
|
|
break;
|
|
case 'startString':
|
|
if (this._filter(this._stack, chunk)) {
|
|
this._syncStack();
|
|
this.push(chunk);
|
|
this._transform = this._passString;
|
|
} else {
|
|
this._transform = this._skipString;
|
|
}
|
|
break;
|
|
case 'startNumber':
|
|
if (this._filter(this._stack, chunk)) {
|
|
this._syncStack();
|
|
this.push(chunk);
|
|
this._transform = this._passNumber;
|
|
} else {
|
|
this._transform = this._skipNumber;
|
|
}
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
_syncStack() {
|
|
const stack = this._stack,
|
|
last = this._lastStack,
|
|
stackLength = stack.length,
|
|
lastLength = last.length;
|
|
|
|
// find the common part
|
|
let commonLength = 0;
|
|
for (const n = Math.min(stackLength, lastLength); commonLength < n && stack[commonLength] === last[commonLength]; ++commonLength);
|
|
|
|
// close old objects
|
|
for (let i = lastLength - 1; i > commonLength; --i) {
|
|
this.push({name: typeof last[i] == 'number' ? 'endArray' : 'endObject'});
|
|
}
|
|
if (commonLength < lastLength) {
|
|
if (commonLength < stackLength) {
|
|
if (typeof stack[commonLength] == 'string') {
|
|
const key = stack[commonLength];
|
|
if (this._streamKeys) {
|
|
this.push({name: 'startKey'});
|
|
this.push({name: 'stringChunk', value: key});
|
|
this.push({name: 'endKey'});
|
|
}
|
|
this.push({name: 'keyValue', value: key});
|
|
}
|
|
++commonLength;
|
|
} else {
|
|
this.push({name: typeof last[commonLength] == 'number' ? 'endArray' : 'endObject'});
|
|
}
|
|
}
|
|
|
|
// open new objects
|
|
for (let i = commonLength; i < stackLength; ++i) {
|
|
const key = stack[i];
|
|
if (typeof key == 'number') {
|
|
if (key >= 0) {
|
|
this.push({name: 'startArray'});
|
|
}
|
|
} else if (typeof key == 'string') {
|
|
this.push({name: 'startObject'});
|
|
if (this._streamKeys) {
|
|
this.push({name: 'startKey'});
|
|
this.push({name: 'stringChunk', value: key});
|
|
this.push({name: 'endKey'});
|
|
}
|
|
this.push({name: 'keyValue', value: key});
|
|
}
|
|
}
|
|
|
|
// update the last stack
|
|
this._lastStack = Array.prototype.concat.call(stack);
|
|
}
|
|
}
|
|
Filter.filter = Filter.make;
|
|
Filter.make.Constructor = Filter;
|
|
|
|
module.exports = Filter;
|