UNPKG

streaming

Version:

Transforms and other streaming helpers

175 lines (170 loc) 6.85 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.Parser = exports.Stringifier = exports.ArrayStringifier = void 0; var stream_1 = require("stream"); var os_1 = require("os"); /** A SyntaxError thrown by JSON.parse() might look like the following: name: 'SyntaxError' message: 'Unexpected token w' arguments: 'w' stack: <a stack trace> type: 'unexpected_token' */ var ParseError = /** @class */ (function (_super) { __extends(ParseError, _super); function ParseError(syntaxError, input) { var _this = _super.call(this, "".concat(syntaxError.message, " when parsing \"").concat(input, "\"")) || this; _this.syntaxError = syntaxError; _this.name = 'ParseError'; return _this; // Error.captureStackTrace(this, this.constructor); // or (this, arguments.callee); } return ParseError; }(Error)); /** Stringify all written objects into a single proper JSON array, surrounded by [ and ] delimiters, and separated by commas. * `replacer` - If a function, transforms values and properties encountered while stringifying; if an array, specifies the set of properties included in objects in the final string. Details on [MDN](https://developer.mozilla.org/En/Using_native_JSON#The_replacer_parameter). * `space` - Causes the resulting string to be pretty-printed (by some number of spaces or literal space). */ var ArrayStringifier = /** @class */ (function (_super) { __extends(ArrayStringifier, _super); function ArrayStringifier(replacer, space) { var _this = _super.call(this) || this; _this.replacer = replacer; _this.space = space; _this._seenFirstItem = false; _this['_writableState'].objectMode = true; _this.push('['); return _this; } ArrayStringifier.prototype._transform = function (chunk, encoding, callback) { if (this._seenFirstItem) { this.push(',' + JSON.stringify(chunk, this.replacer, this.space)); } else { this.push(JSON.stringify(chunk, this.replacer, this.space)); this._seenFirstItem = true; } callback(); }; ArrayStringifier.prototype._flush = function (callback) { this.push(']'); callback(); }; return ArrayStringifier; }(stream_1.Transform)); exports.ArrayStringifier = ArrayStringifier; /** streaming.json.Stringifer expects objects and outputs strings / buffers _writableState.objectMode = true _readableState.objectMode = false * `replacer` Function If a function, transforms values and properties encountered while stringifying; if an array, specifies the set of properties included in objects in the final string. Details on [MDN](https://developer.mozilla.org/En/Using_native_JSON#The_replacer_parameter). * `space` Number | String Causes the resulting string to be pretty-printed (by some number of spaces or literal space). */ var Stringifier = /** @class */ (function (_super) { __extends(Stringifier, _super); function Stringifier(replacer, space) { var _this = _super.call(this) || this; _this.replacer = replacer; _this.space = space; _this['_writableState'].objectMode = true; return _this; } Stringifier.prototype._transform = function (chunk, encoding, callback) { this.push(JSON.stringify(chunk, this.replacer, this.space) + os_1.EOL); // , 'utf8' callback(); }; return Stringifier; }(stream_1.Transform)); exports.Stringifier = Stringifier; /** streaming.json.Parser expects Buffer input with universal newlines dividing JSON objects. You shouldn't put a Splitter() in front of it. */ var Parser = /** @class */ (function (_super) { __extends(Parser, _super); function Parser(replacer, space) { var _this = _super.call(this) || this; _this.replacer = replacer; _this.space = space; _this._buffer = Buffer.alloc(0); _this['_writableState'].objectMode = false; // buffer input _this['_readableState'].objectMode = true; // object output return _this; } Parser.prototype._line = function (lineBuffer) { var lineString = lineBuffer.toString('utf8'); var obj; try { obj = JSON.parse(lineString); } catch (syntax_error) { var error = new ParseError(syntax_error, lineString); this.emit('error', error); } if (obj !== undefined) { // only push the parsed object along if it was parsed without error this.push(obj); } }; /** Find the split points */ Parser.prototype._processBuffer = function (eof) { var offset = 0; var cursor = offset; var length = this._buffer.length; while (cursor < length) { var prev = this._buffer[cursor - 1]; var curr = this._buffer[cursor]; var next = this._buffer[cursor + 1]; var eol = (curr === 10) || // '\n' (prev === 13 && curr === 10) || // '\r\n' (curr === 13 && next !== 10 && next !== undefined) || // '\r[^\n]' (eof && (cursor + 1) === length); // flush final line if eof is true cursor++; if (eol) { // include the full EOL marker in the line chunk this._line(this._buffer.subarray(offset, cursor)); offset = cursor; } } this._buffer = this._buffer.subarray(offset); }; /** chunk will be a Buffer, and either one is fine by JSON.parse, but to appease TypeScript, type assert that it's <any> */ Parser.prototype._transform = function (chunk, encoding, callback) { this._buffer = Buffer.concat([this._buffer, chunk]); this._processBuffer(false); callback(); }; Parser.prototype._flush = function (callback) { this._processBuffer(true); callback(); }; return Parser; }(stream_1.Transform)); exports.Parser = Parser;