streaming
Version:
Transforms and other streaming helpers
175 lines (170 loc) • 6.85 kB
JavaScript
;
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;