Skip to content

Instantly share code, notes, and snippets.

@XeCycle
Created October 12, 2015 08:27
Show Gist options
  • Save XeCycle/59a0ac7089ff1e8a5bc7 to your computer and use it in GitHub Desktop.
Save XeCycle/59a0ac7089ff1e8a5bc7 to your computer and use it in GitHub Desktop.
something like stream.readline(), returning a promise.
import {Writable} from "stream";
// scanner returns remaining string if succeeded, null/undefined otherwise
class ScanningState {
constructor(buf, scanner) {
this.buf = buf;
this.scanner = scanner;
}
scan() {
throw new Error("Another scan in progress");
}
data(chunk, _continue) {
var buf = this.buf + chunk;
var remaining = this.scanner(buf);
if (typeof remaining === "string") {
return new PausedBlockState(remaining, _continue);
}
_continue();
return new ScanningState(buf, this.scanner);
}
}
class PausedNoBlockState {
constructor(buf) {
this.buf = buf;
}
scan(scanner) {
var remaining = scanner(this.buf);
if (typeof remaining === "string")
return new PausedNoBlockState(remaining);
return new ScanningState(this.buf, scanner);
}
data(chunk, _continue) {
return new PausedBlockState(this.buf + chunk, _continue);
}
}
class PausedBlockState {
constructor(buf, _continue) {
this.buf = buf;
this.continue = _continue;
}
scan(scanner) {
var remaining = scanner(this.buf);
if (typeof remaining === "string")
return new PausedBlockState(remaining, this.continue);
this.continue();
return new ScanningState(this.buf, scanner);
}
data() {
throw new Error("Are you really using node streams?");
}
}
export default class ScannableStream extends Writable {
constructor() {
super({
decodeStrings: false,
objectMode: false
});
this._state = new PausedNoBlockState("");
}
_write(chunk, encoding, _continue) {
this._state = this._state.data(chunk, _continue);
}
scan(sep) {
return new Promise(resolve => {
if (typeof sep === "string")
this._state = this._state.scan(scanByString(sep, resolve));
else this._state = this._state.scan(scanByRegex(sep, resolve));
});
}
}
function scanByString(sep, resolve) {
return function stringScanner(buf) {
var iSep = buf.indexOf(sep);
if (iSep >= 0) {
resolve(buf.substring(0, iSep));
return buf.substr(iSep + sep.length);
}
};
}
function scanByRegex(sep, resolve) {
return function regexScanner(buf) {
var match = sep.exec(buf);
if (match) {
resolve(buf.substring(0, match.index));
return buf.substr(match.index + match[0].length);
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment