| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- 'use strict';
- const EventEmitter = require('events');
- const startObject = Ctr =>
- function () {
- if (this.done) {
- this.done = false;
- } else {
- this.stack.push(this.current, this.key);
- }
- this.current = new Ctr();
- this.key = null;
- };
- class Assembler extends EventEmitter {
- static connectTo(stream, options) {
- return new Assembler(options).connectTo(stream);
- }
- constructor(options) {
- super();
- this.stack = [];
- this.current = this.key = null;
- this.done = true;
- if (options) {
- this.reviver = typeof options.reviver == 'function' && options.reviver;
- if (this.reviver) {
- this.stringValue = this._saveValue = this._saveValueWithReviver;
- }
- if (options.numberAsString) {
- this.numberValue = this.stringValue;
- }
- }
- }
- connectTo(stream) {
- stream.on('data', chunk => {
- if (this[chunk.name]) {
- this[chunk.name](chunk.value);
- if (this.done) this.emit('done', this);
- }
- });
- return this;
- }
- get depth() {
- return (this.stack.length >> 1) + (this.done ? 0 : 1);
- }
- get path() {
- const path = [];
- for (let i = 0; i < this.stack.length; i += 2) {
- const key = this.stack[i + 1];
- path.push(key === null ? this.stack[i].length : key);
- }
- return path;
- }
- dropToLevel(level) {
- if (level < this.depth) {
- if (level) {
- const index = (level - 1) << 1;
- this.current = this.stack[index];
- this.key = this.stack[index + 1];
- this.stack.splice(index);
- } else {
- this.stack = [];
- this.current = this.key = null;
- this.done = true;
- }
- }
- return this;
- }
- consume(chunk) {
- this[chunk.name] && this[chunk.name](chunk.value);
- return this;
- }
- keyValue(value) {
- this.key = value;
- }
- //stringValue() - aliased below to _saveValue()
- numberValue(value) {
- this._saveValue(parseFloat(value));
- }
- nullValue() {
- this._saveValue(null);
- }
- trueValue() {
- this._saveValue(true);
- }
- falseValue() {
- this._saveValue(false);
- }
- //startObject() - assigned below
- endObject() {
- if (this.stack.length) {
- const value = this.current;
- this.key = this.stack.pop();
- this.current = this.stack.pop();
- this._saveValue(value);
- } else {
- this.done = true;
- }
- }
- //startArray() - assigned below
- //endArray() - aliased below to endObject()
- _saveValue(value) {
- if (this.done) {
- this.current = value;
- } else {
- if (this.current instanceof Array) {
- this.current.push(value);
- } else {
- this.current[this.key] = value;
- this.key = null;
- }
- }
- }
- _saveValueWithReviver(value) {
- if (this.done) {
- this.current = this.reviver('', value);
- } else {
- if (this.current instanceof Array) {
- value = this.reviver('' + this.current.length, value);
- this.current.push(value);
- if (value === undefined) {
- delete this.current[this.current.length - 1];
- }
- } else {
- value = this.reviver(this.key, value);
- if (value !== undefined) {
- this.current[this.key] = value;
- }
- this.key = null;
- }
- }
- }
- }
- Assembler.prototype.stringValue = Assembler.prototype._saveValue;
- Assembler.prototype.startObject = startObject(Object);
- Assembler.prototype.startArray = startObject(Array);
- Assembler.prototype.endArray = Assembler.prototype.endObject;
- module.exports = Assembler;
|