0.3.0 Release
This commit is contained in:
parent
5074a991fc
commit
e1796d5896
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
.vscode
|
||||
node_modules
|
||||
**/*.js
|
||||
**/*.js.map
|
||||
dist
|
||||
sample_output
|
@ -1,5 +0,0 @@
|
||||
.vscode
|
||||
node_modules
|
||||
**/*.ts
|
||||
tsconfig.json
|
||||
tslint.json
|
4
.prettierrc
Normal file
4
.prettierrc
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"tabWidth": 4,
|
||||
"trailingComma": "all"
|
||||
}
|
79
README.md
79
README.md
@ -1,6 +1,79 @@
|
||||
# mysah
|
||||
ES6 Promise library
|
||||
|
||||
## State of the project
|
||||
Promise, Stream and EventEmitter utils for Node.js
|
||||
|
||||
**mysah** is in its infancy. More development to come!
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
yarn add mysah
|
||||
```
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```js
|
||||
const stream = require("mysah/stream");
|
||||
const { once, sleep } = require("mysah");
|
||||
|
||||
async function main() {
|
||||
const collector = stream
|
||||
.concat(
|
||||
stream.fromArray(["a", "b", "c"]),
|
||||
stream.fromArray(["d", "e"])
|
||||
)
|
||||
.pipe(stream.collect({ objectMode: true }));
|
||||
|
||||
const collected = await once(collector, "data");
|
||||
console.log(collected); // [ 'a', 'b', 'c', 'd', 'e' ]
|
||||
await sleep(1000); // Resolve after one second
|
||||
}
|
||||
main();
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### mysah/stream
|
||||
|
||||
```ts
|
||||
/**
|
||||
* Convert an array into a readable stream of its elements
|
||||
* @param array The array of elements to stream
|
||||
*/
|
||||
export declare function fromArray(array: any[]): NodeJS.ReadableStream;
|
||||
|
||||
/**
|
||||
* Return a ReadWrite stream that collects streamed objects or bytes into an array or buffer
|
||||
* @param options
|
||||
* @param options.objectMode Whether this stream should behave as a stream of objects
|
||||
*/
|
||||
export declare function collect({
|
||||
objectMode,
|
||||
}?: {
|
||||
objectMode?: boolean | undefined;
|
||||
}): NodeJS.ReadWriteStream;
|
||||
|
||||
/**
|
||||
* Return a stream of readable streams concatenated together
|
||||
* @param streams The readable streams to concatenate
|
||||
*/
|
||||
export declare function concat(
|
||||
...streams: NodeJS.ReadableStream[]
|
||||
): NodeJS.ReadableStream;
|
||||
```
|
||||
|
||||
### mysah
|
||||
|
||||
```ts
|
||||
/**
|
||||
* Resolve after the given delay in milliseconds
|
||||
*
|
||||
* @param ms - The number of milliseconds to wait
|
||||
*/
|
||||
export declare function sleep(ms: number): Promise<{}>;
|
||||
/**
|
||||
* Resolve once the given event emitter emits the specified event
|
||||
*
|
||||
* @param emitter - The event emitter to watch
|
||||
* @param event - The event to watch
|
||||
*/
|
||||
export declare function once<T>(emitter: NodeJS.EventEmitter, event: string): Promise<T>;
|
||||
```
|
||||
|
31
index.ts
31
index.ts
@ -1,31 +0,0 @@
|
||||
const es6Promisify = require('es6-promisify');
|
||||
|
||||
/**
|
||||
* Return a promise that resolves once the given event emitter emits the specified event
|
||||
*
|
||||
* @param {NodeJS.EventEmitter} emitter - The event emitter to watch
|
||||
* @param {string} event - The event to watch
|
||||
* @returns {Promise<{}>} - The promise that resolves once the given emitter emits the specified evnet
|
||||
*/
|
||||
export function once(emitter: NodeJS.EventEmitter, event: string) {
|
||||
return new Promise((resolve) => {
|
||||
emitter.once(event, result => {
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform callback-based function -- func(arg1, arg2 .. argN, callback) -- into
|
||||
* an ES6-compatible Promise. Promisify provides a default callback of the form (error, result)
|
||||
* and rejects when `error` is truthy. You can also supply settings object as the second argument.
|
||||
*
|
||||
* @param {function} original - The function to promisify
|
||||
* @param {object} [settings] - Settings object
|
||||
* @param {object} settings.thisArg - A `this` context to use. If not set, assume `settings` _is_ `thisArg`
|
||||
* @param {bool} settings.multiArgs - Should multiple arguments be returned as an array?
|
||||
* @returns {function} A promisified version of `original`
|
||||
*/
|
||||
export function promisify(original: Function, settings?: Object): Function {
|
||||
return es6Promisify(original, settings);
|
||||
};
|
78
package.json
78
package.json
@ -1,22 +1,60 @@
|
||||
{
|
||||
"name": "mysah",
|
||||
"version": "0.1.0",
|
||||
"description": "ES6 Promise library",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
"ES6",
|
||||
"Promise",
|
||||
"library"
|
||||
],
|
||||
"author": "Sami Turcotte",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^7.0.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"es6-promisify": "^5.0.0"
|
||||
}
|
||||
"name": "mysah",
|
||||
"version": "0.3.0",
|
||||
"description": "Promise, Stream and EventEmitter utils for Node.js",
|
||||
"keywords": [
|
||||
"promise",
|
||||
"stream",
|
||||
"event emitter",
|
||||
"utils"
|
||||
],
|
||||
"author": {
|
||||
"name": "Sami Turcotte",
|
||||
"email": "samiturcotte@gmail.com"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "index.js",
|
||||
"types": "dist/**/*.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"repository": {
|
||||
"url": "git@github.com:Wenzil/mysah.git",
|
||||
"type": "git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "ava",
|
||||
"lint": "tslint -p tsconfig.json",
|
||||
"validate:tslint": "tslint-config-prettier-check ./tslint.json",
|
||||
"prepublishOnly": "yarn lint && yarn test && yarn tsc"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.1.7",
|
||||
"@types/node": "^10.12.10",
|
||||
"ava": "^1.0.0-rc.2",
|
||||
"chai": "^4.2.0",
|
||||
"prettier": "^1.14.3",
|
||||
"ts-node": "^7.0.1",
|
||||
"tslint": "^5.11.0",
|
||||
"tslint-config-prettier": "^1.16.0",
|
||||
"tslint-plugin-prettier": "^2.0.1",
|
||||
"typescript": "^3.1.6"
|
||||
},
|
||||
"ava": {
|
||||
"files": [
|
||||
"src/**/*.spec.ts"
|
||||
],
|
||||
"sources": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"compileEnhancements": false,
|
||||
"failWithoutAssertions": false,
|
||||
"extensions": [
|
||||
"ts"
|
||||
],
|
||||
"require": [
|
||||
"ts-node/register/transpile-only"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
21
samples/concat_files.js
Normal file
21
samples/concat_files.js
Normal file
@ -0,0 +1,21 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const stream = require("mysah/stream");
|
||||
|
||||
const sourceFile1 = path.join(process.cwd(), "package.json");
|
||||
const sourceFile2 = path.join(process.cwd(), "README.md");
|
||||
const outputDir = path.join(process.cwd(), "sample_output");
|
||||
const outputFile = path.join(outputDir, "concat_files.txt");
|
||||
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
fs.mkdirSync(outputDir, { recursive: true });
|
||||
}
|
||||
|
||||
// Concat two source files together into one
|
||||
stream
|
||||
.concat(
|
||||
fs.createReadStream(sourceFile1),
|
||||
stream.fromArray(["\n"]),
|
||||
fs.createReadStream(sourceFile2),
|
||||
)
|
||||
.pipe(fs.createWriteStream(outputFile));
|
29
src/index.spec.ts
Normal file
29
src/index.spec.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import test from "ava";
|
||||
import { expect } from "chai";
|
||||
import { once, sleep } from "./";
|
||||
import { EventEmitter } from "events";
|
||||
|
||||
const TimingErrorMarginMs = 50;
|
||||
|
||||
test("sleep() resolves after the specified delay in milliseconds", async t => {
|
||||
const before = Date.now();
|
||||
await sleep(200);
|
||||
const after = Date.now();
|
||||
|
||||
expect(after - before).gte(200);
|
||||
expect(after - before).closeTo(200, TimingErrorMarginMs);
|
||||
});
|
||||
|
||||
test("once() resolves only after the specified event is emitted", async t => {
|
||||
const emitter = new EventEmitter();
|
||||
const before = Date.now();
|
||||
emitter.emit("noise", "is ignored");
|
||||
setTimeout(() => emitter.emit("done", "some-result"), 200);
|
||||
|
||||
const result = await once(emitter, "done");
|
||||
const after = Date.now();
|
||||
|
||||
expect(result).to.equal("some-result");
|
||||
expect(after - before).gte(200);
|
||||
expect(after - before).closeTo(200, TimingErrorMarginMs);
|
||||
});
|
27
src/index.ts
Normal file
27
src/index.ts
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Resolve after the given delay in milliseconds
|
||||
*
|
||||
* @param ms - The number of milliseconds to wait
|
||||
*/
|
||||
export function sleep(ms: number) {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, ms);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve once the given event emitter emits the specified event
|
||||
*
|
||||
* @param emitter - The event emitter to watch
|
||||
* @param event - The event to watch
|
||||
*/
|
||||
export function once<T>(
|
||||
emitter: NodeJS.EventEmitter,
|
||||
event: string,
|
||||
): Promise<T> {
|
||||
return new Promise(resolve => {
|
||||
emitter.once(event, result => {
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
}
|
350
src/stream.spec.ts
Normal file
350
src/stream.spec.ts
Normal file
@ -0,0 +1,350 @@
|
||||
import test from "ava";
|
||||
import { expect } from "chai";
|
||||
import { fromArray, collect, concat } from "./stream";
|
||||
import { Readable } from "stream";
|
||||
|
||||
test.cb("fromArray() streams array elements in flowing mode", t => {
|
||||
t.plan(3);
|
||||
const elements = ["a", "b", "c"];
|
||||
const stream = fromArray(elements);
|
||||
let i = 0;
|
||||
stream
|
||||
.on("data", element => {
|
||||
expect(element).to.equal(elements[i]);
|
||||
t.pass();
|
||||
i++;
|
||||
})
|
||||
.on("error", t.end)
|
||||
.on("end", t.end);
|
||||
});
|
||||
|
||||
test.cb("fromArray() streams array elements in paused mode", t => {
|
||||
t.plan(3);
|
||||
const elements = ["a", "b", "c"];
|
||||
const stream = fromArray(elements);
|
||||
let i = 0;
|
||||
stream
|
||||
.on("readable", () => {
|
||||
let element = stream.read();
|
||||
while (element !== null) {
|
||||
expect(element).to.equal(elements[i]);
|
||||
t.pass();
|
||||
i++;
|
||||
element = stream.read();
|
||||
}
|
||||
})
|
||||
.on("error", t.end)
|
||||
.on("end", t.end);
|
||||
});
|
||||
|
||||
test.cb("fromArray() ends immediately if there are no array elements", t => {
|
||||
t.plan(0);
|
||||
fromArray([])
|
||||
.on("data", () => t.fail())
|
||||
.on("error", t.end)
|
||||
.on("end", t.end);
|
||||
});
|
||||
|
||||
test.cb(
|
||||
"collect() collects streamed elements into an array (object, flowing mode)",
|
||||
t => {
|
||||
t.plan(1);
|
||||
const source = new Readable({ objectMode: true });
|
||||
|
||||
source
|
||||
.pipe(collect({ objectMode: true }))
|
||||
.on("data", collected => {
|
||||
expect(collected).to.deep.equal(["a", "b", "c"]);
|
||||
t.pass();
|
||||
})
|
||||
.on("error", t.end)
|
||||
.on("end", t.end);
|
||||
|
||||
source.push("a");
|
||||
source.push("b");
|
||||
source.push("c");
|
||||
source.push(null);
|
||||
},
|
||||
);
|
||||
|
||||
test.cb(
|
||||
"collect() collects streamed elements into an array (object, paused mode)",
|
||||
t => {
|
||||
t.plan(1);
|
||||
const source = new Readable({ objectMode: true });
|
||||
const collector = source.pipe(collect({ objectMode: true }));
|
||||
|
||||
collector
|
||||
.on("readable", () => {
|
||||
let collected = collector.read();
|
||||
while (collected !== null) {
|
||||
expect(collected).to.deep.equal(["a", "b", "c"]);
|
||||
t.pass();
|
||||
collected = collector.read();
|
||||
}
|
||||
})
|
||||
.on("error", t.end)
|
||||
.on("end", t.end);
|
||||
|
||||
source.push("a");
|
||||
source.push("b");
|
||||
source.push("c");
|
||||
source.push(null);
|
||||
},
|
||||
);
|
||||
|
||||
test.cb(
|
||||
"collect() collects streamed bytes into a buffer (non-object, flowing mode)",
|
||||
t => {
|
||||
t.plan(1);
|
||||
const source = new Readable({ objectMode: false });
|
||||
|
||||
source
|
||||
.pipe(collect())
|
||||
.on("data", collected => {
|
||||
expect(collected).to.deep.equal(Buffer.from("abc"));
|
||||
t.pass();
|
||||
})
|
||||
.on("error", t.end)
|
||||
.on("end", t.end);
|
||||
|
||||
source.push("a");
|
||||
source.push("b");
|
||||
source.push("c");
|
||||
source.push(null);
|
||||
},
|
||||
);
|
||||
|
||||
test.cb(
|
||||
"collect() collects streamed bytes into a buffer (non-object, paused mode)",
|
||||
t => {
|
||||
t.plan(1);
|
||||
const source = new Readable({ objectMode: false });
|
||||
const collector = source.pipe(collect({ objectMode: false }));
|
||||
collector
|
||||
.on("readable", () => {
|
||||
let collected = collector.read();
|
||||
while (collected !== null) {
|
||||
expect(collected).to.deep.equal(Buffer.from("abc"));
|
||||
t.pass();
|
||||
collected = collector.read();
|
||||
}
|
||||
})
|
||||
.on("error", t.end)
|
||||
.on("end", t.end);
|
||||
|
||||
source.push("a");
|
||||
source.push("b");
|
||||
source.push("c");
|
||||
source.push(null);
|
||||
},
|
||||
);
|
||||
|
||||
test.cb(
|
||||
"collect() emits an empty array if the source was empty (object mode)",
|
||||
t => {
|
||||
t.plan(1);
|
||||
const source = new Readable({ objectMode: true });
|
||||
const collector = source.pipe(collect({ objectMode: true }));
|
||||
collector
|
||||
.on("data", collected => {
|
||||
expect(collected).to.deep.equal([]);
|
||||
t.pass();
|
||||
})
|
||||
.on("error", t.end)
|
||||
.on("end", t.end);
|
||||
|
||||
source.push(null);
|
||||
},
|
||||
);
|
||||
|
||||
test.cb(
|
||||
"collect() emits nothing if the source was empty (non-object mode)",
|
||||
t => {
|
||||
t.plan(0);
|
||||
const source = new Readable({ objectMode: false });
|
||||
const collector = source.pipe(collect({ objectMode: false }));
|
||||
collector
|
||||
.on("data", () => t.fail())
|
||||
.on("error", t.end)
|
||||
.on("end", t.end);
|
||||
|
||||
source.push(null);
|
||||
},
|
||||
);
|
||||
|
||||
test.cb(
|
||||
"concat() concatenates multiple readable streams (object, flowing mode)",
|
||||
t => {
|
||||
t.plan(6);
|
||||
const source1 = new Readable({ objectMode: true });
|
||||
const source2 = new Readable({ objectMode: true });
|
||||
const expectedElements = ["a", "b", "c", "d", "e", "f"];
|
||||
let i = 0;
|
||||
concat(source1, source2)
|
||||
.on("data", element => {
|
||||
expect(element).to.equal(expectedElements[i]);
|
||||
t.pass();
|
||||
i++;
|
||||
})
|
||||
.on("error", t.end)
|
||||
.on("end", t.end);
|
||||
|
||||
source1.push("a");
|
||||
source2.push("d");
|
||||
source1.push("b");
|
||||
source2.push("e");
|
||||
source1.push("c");
|
||||
source2.push("f");
|
||||
source2.push(null);
|
||||
source1.push(null);
|
||||
},
|
||||
);
|
||||
|
||||
test.cb(
|
||||
"concat() concatenates multiple readable streams (object, paused mode)",
|
||||
t => {
|
||||
t.plan(6);
|
||||
const source1 = new Readable({ objectMode: true });
|
||||
const source2 = new Readable({ objectMode: true });
|
||||
const expectedElements = ["a", "b", "c", "d", "e", "f"];
|
||||
let i = 0;
|
||||
const concatenation = concat(source1, source2)
|
||||
.on("readable", () => {
|
||||
let element = concatenation.read();
|
||||
while (element !== null) {
|
||||
expect(element).to.equal(expectedElements[i]);
|
||||
t.pass();
|
||||
i++;
|
||||
element = concatenation.read();
|
||||
}
|
||||
})
|
||||
.on("error", t.end)
|
||||
.on("end", t.end);
|
||||
|
||||
source1.push("a");
|
||||
source2.push("d");
|
||||
source1.push("b");
|
||||
source2.push("e");
|
||||
source1.push("c");
|
||||
source2.push("f");
|
||||
source2.push(null);
|
||||
source1.push(null);
|
||||
},
|
||||
);
|
||||
|
||||
test.cb(
|
||||
"concat() concatenates multiple readable streams (non-object, flowing mode)",
|
||||
t => {
|
||||
t.plan(6);
|
||||
const source1 = new Readable({ objectMode: false });
|
||||
const source2 = new Readable({ objectMode: false });
|
||||
const expectedElements = ["a", "b", "c", "d", "e", "f"];
|
||||
let i = 0;
|
||||
concat(source1, source2)
|
||||
.on("data", element => {
|
||||
expect(element).to.deep.equal(Buffer.from(expectedElements[i]));
|
||||
t.pass();
|
||||
i++;
|
||||
})
|
||||
.on("error", t.end)
|
||||
.on("end", t.end);
|
||||
|
||||
source1.push("a");
|
||||
source2.push("d");
|
||||
source1.push("b");
|
||||
source2.push("e");
|
||||
source1.push("c");
|
||||
source2.push("f");
|
||||
source2.push(null);
|
||||
source1.push(null);
|
||||
},
|
||||
);
|
||||
|
||||
test.cb(
|
||||
"concat() concatenates multiple readable streams (non-object, paused mode)",
|
||||
t => {
|
||||
t.plan(6);
|
||||
const source1 = new Readable({ objectMode: false });
|
||||
const source2 = new Readable({ objectMode: false });
|
||||
const expectedElements = ["a", "b", "c", "d", "e", "f"];
|
||||
let i = 0;
|
||||
const concatenation = concat(source1, source2)
|
||||
.on("readable", () => {
|
||||
let element = concatenation.read();
|
||||
while (element !== null) {
|
||||
expect(element).to.deep.equal(
|
||||
Buffer.from(expectedElements[i]),
|
||||
);
|
||||
t.pass();
|
||||
i++;
|
||||
element = concatenation.read();
|
||||
}
|
||||
})
|
||||
.on("error", t.end)
|
||||
.on("end", t.end);
|
||||
|
||||
source1.push("a");
|
||||
source2.push("d");
|
||||
source1.push("b");
|
||||
source2.push("e");
|
||||
source1.push("c");
|
||||
source2.push("f");
|
||||
source2.push(null);
|
||||
source1.push(null);
|
||||
},
|
||||
);
|
||||
|
||||
test.cb("concat() concatenates a single readable stream (object mode)", t => {
|
||||
t.plan(3);
|
||||
const source = new Readable({ objectMode: true });
|
||||
const expectedElements = ["a", "b", "c", "d", "e", "f"];
|
||||
let i = 0;
|
||||
concat(source)
|
||||
.on("data", element => {
|
||||
expect(element).to.equal(expectedElements[i]);
|
||||
t.pass();
|
||||
i++;
|
||||
})
|
||||
.on("error", t.end)
|
||||
.on("end", t.end);
|
||||
|
||||
source.push("a");
|
||||
source.push("b");
|
||||
source.push("c");
|
||||
source.push(null);
|
||||
});
|
||||
|
||||
test.cb(
|
||||
"concat() concatenates a single readable stream (non-object mode)",
|
||||
t => {
|
||||
t.plan(3);
|
||||
const source = new Readable({ objectMode: false });
|
||||
const expectedElements = ["a", "b", "c", "d", "e", "f"];
|
||||
let i = 0;
|
||||
concat(source)
|
||||
.on("data", element => {
|
||||
expect(element).to.deep.equal(Buffer.from(expectedElements[i]));
|
||||
t.pass();
|
||||
i++;
|
||||
})
|
||||
.on("error", t.end)
|
||||
.on("end", t.end);
|
||||
|
||||
source.push("a");
|
||||
source.push("b");
|
||||
source.push("c");
|
||||
source.push(null);
|
||||
},
|
||||
);
|
||||
|
||||
test.cb("concat() concatenates empty list of readable streams", t => {
|
||||
t.plan(0);
|
||||
concat()
|
||||
.pipe(collect())
|
||||
.on("data", _ => {
|
||||
t.fail();
|
||||
})
|
||||
.on("error", t.end)
|
||||
.on("end", t.end);
|
||||
});
|
83
src/stream.ts
Normal file
83
src/stream.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import { Transform, Readable } from "stream";
|
||||
|
||||
/**
|
||||
* Convert an array into a readable stream of its elements
|
||||
* @param array The array of elements to stream
|
||||
*/
|
||||
export function fromArray(array: any[]): NodeJS.ReadableStream {
|
||||
let cursor = 0;
|
||||
return new Readable({
|
||||
objectMode: true,
|
||||
read() {
|
||||
if (cursor < array.length) {
|
||||
this.push(array[cursor]);
|
||||
cursor++;
|
||||
} else {
|
||||
this.push(null);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a ReadWrite stream that collects streamed objects or bytes into an array or buffer
|
||||
* @param options
|
||||
* @param options.objectMode Whether this stream should behave as a stream of objects
|
||||
*/
|
||||
export function collect({ objectMode = false } = {}): NodeJS.ReadWriteStream {
|
||||
const collected: any[] = [];
|
||||
return new Transform({
|
||||
readableObjectMode: objectMode,
|
||||
writableObjectMode: objectMode,
|
||||
transform(data, encoding, callback) {
|
||||
collected.push(data);
|
||||
callback();
|
||||
},
|
||||
flush(callback) {
|
||||
this.push(objectMode ? collected : Buffer.concat(collected));
|
||||
callback();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a stream of readable streams concatenated together
|
||||
* @param streams The readable streams to concatenate
|
||||
*/
|
||||
export function concat(
|
||||
...streams: NodeJS.ReadableStream[]
|
||||
): NodeJS.ReadableStream {
|
||||
let isStarted = false;
|
||||
let currentStreamIndex = 0;
|
||||
const startCurrentStream = () => {
|
||||
if (currentStreamIndex >= streams.length) {
|
||||
wrapper.push(null);
|
||||
} else {
|
||||
streams[currentStreamIndex]
|
||||
.on("data", chunk => {
|
||||
if (!wrapper.push(chunk)) {
|
||||
streams[currentStreamIndex].pause();
|
||||
}
|
||||
})
|
||||
.on("error", err => wrapper.emit("error", err))
|
||||
.on("end", () => {
|
||||
currentStreamIndex++;
|
||||
startCurrentStream();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const wrapper = new Readable({
|
||||
objectMode: true,
|
||||
read() {
|
||||
if (!isStarted) {
|
||||
isStarted = true;
|
||||
startCurrentStream();
|
||||
}
|
||||
if (currentStreamIndex < streams.length) {
|
||||
streams[currentStreamIndex].resume();
|
||||
}
|
||||
},
|
||||
});
|
||||
return wrapper;
|
||||
}
|
@ -1,13 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"sourceMap": true,
|
||||
"watch": false,
|
||||
"noUnusedParameters": true,
|
||||
"noUnusedLocals": true
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
]
|
||||
}
|
||||
"compilerOptions": {
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"noImplicitReturns": true,
|
||||
"noUnusedLocals": true,
|
||||
"noImplicitThis": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"outDir": "./dist",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"lib": ["es2017"],
|
||||
"sourceMap": true,
|
||||
"declaration": true
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
|
30
tslint.json
30
tslint.json
@ -1,19 +1,13 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-unused-expression": true,
|
||||
"no-duplicate-variable": true,
|
||||
"curly": true,
|
||||
"class-name": true,
|
||||
"semicolon": [true, "always"],
|
||||
"triple-equals": true,
|
||||
"trailing-comma": [true, {"multiline": "never", "singleline": "never"}],
|
||||
"only-arrow-functions": [true, "allow-declarations"],
|
||||
"no-eval": true,
|
||||
"no-invalid-this": true,
|
||||
"switch-default": true,
|
||||
"prefer-const": true,
|
||||
"arrow-return-shorthand": [true],
|
||||
"jsdoc-format": true,
|
||||
"no-consecutive-blank-lines": [true]
|
||||
}
|
||||
}
|
||||
"extends": [
|
||||
"tslint:latest",
|
||||
"tslint-plugin-prettier",
|
||||
"tslint-config-prettier"
|
||||
],
|
||||
"rules": {
|
||||
"no-console": false,
|
||||
"no-implicit-dependencies": [true, ["ava"]],
|
||||
"prettier": true,
|
||||
"ordered-imports": false
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user