mergeiterator
Advanced tools
Comparing version 1.3.1 to 1.4.0
@@ -13,7 +13,7 @@ "use strict"; | ||
require("./polyfills/symbolAsyncIterator.js"); | ||
require("./polyfills/symbolAsyncIterator"); | ||
var _mergeiterator = require("./mergeiterator.js"); | ||
var _mergeiterator = require("./mergeiterator"); | ||
module.exports = exports.default; | ||
module.exports.default = exports.default; |
@@ -8,2 +8,4 @@ "use strict"; | ||
function _asyncIterator(iterable) { var method; if (typeof Symbol !== "undefined") { if (Symbol.asyncIterator) { method = iterable[Symbol.asyncIterator]; if (method != null) return method.call(iterable); } if (Symbol.iterator) { method = iterable[Symbol.iterator]; if (method != null) return method.call(iterable); } } throw new TypeError("Object is not async iterable"); } | ||
function _awaitAsyncGenerator(value) { return new _AwaitValue(value); } | ||
@@ -25,2 +27,5 @@ | ||
/** | ||
* Merges async or sync iterables into async one. | ||
*/ | ||
function merge(_x) { | ||
@@ -32,35 +37,41 @@ return _merge.apply(this, arguments); | ||
_merge = _wrapAsyncGenerator(function* (sequences) { | ||
const rootIterator = getIterator((yield _awaitAsyncGenerator(sequences))); | ||
const ticks = [readRootIterator]; | ||
const getters = []; | ||
let iteratorsCount = 1; // There is only rootIterator opened so far. | ||
// | ||
let onDataNeeded = () => {}; | ||
let dataNeeded = new Promise(setOnDataNeeded); | ||
let onStateChanged = () => {}; // should be called whenever values used in the main `while` loop have been changed. These are: iteratorsCount > 0 and values | ||
const values = []; | ||
let iteratorsCount = 0; | ||
let mergeDone = false; | ||
let onStateChanged; // should be called whenever values used in the main `while` loop have been changed. These are: iteratorsCount, ticks and getters | ||
let normalReturn = true; | ||
let rootReturnResult; | ||
readRoot(); | ||
try { | ||
while (iteratorsCount > 0) { | ||
const stateChanged = new Promise(setOnStateChanged); | ||
while (ticks.length) ticks.shift()(); | ||
yield _awaitAsyncGenerator(stateChanged); | ||
while (getters.length > 0) yield getters.shift()(); | ||
while (iteratorsCount > 0 || values.length > 0) { | ||
if (values.length > 0) { | ||
if (typeof values[0] === "object" && values[0] && typeof values[0].then === "function") { | ||
yield values.shift(); | ||
} else { | ||
yield values.shift(); | ||
} | ||
} else { | ||
const oldOnDataNeeded = onDataNeeded; | ||
dataNeeded = new Promise(setOnDataNeeded); | ||
const stateChanged = new Promise(setOnStateChanged); | ||
oldOnDataNeeded(); | ||
yield _awaitAsyncGenerator(stateChanged); | ||
} | ||
} | ||
} catch (e) { | ||
} catch (error) { | ||
normalReturn = false; | ||
throw e; | ||
throw error; | ||
} finally { | ||
mergeDone = true; | ||
onDataNeeded(); | ||
while (iteratorsCount > 0) { | ||
const stateChanged = new Promise(setOnStateChanged); | ||
while (ticks.length) ticks.shift()(); | ||
yield _awaitAsyncGenerator(stateChanged); | ||
yield _awaitAsyncGenerator(new Promise(setOnStateChanged)); | ||
} // Do not hide an exception if it's been already raised. | ||
@@ -71,133 +82,109 @@ | ||
// Raise possible exceptions on iterators interruption. | ||
while (getters.length > 0) getters.shift()(); // There is no chance to return a value out of finally block if .return() is called. | ||
// eslint-disable-next-line no-unsafe-finally | ||
while (values.length > 0) yield _awaitAsyncGenerator(values.shift()); | ||
} | ||
} | ||
async function readRoot() { | ||
try { | ||
iteratorsCount++; | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
return rootReturnResult; | ||
} | ||
} // istanbul ignore next | ||
var _iteratorError; | ||
try { | ||
for (var _iterator = _asyncIterator((await sequences)), _step, _value; _step = await _iterator.next(), _iteratorNormalCompletion = _step.done, _value = await _step.value, !_iteratorNormalCompletion; _iteratorNormalCompletion = true) { | ||
const sequence = _value; | ||
throw new Error("impossible"); | ||
if (mergeDone) { | ||
break; | ||
} | ||
function setOnStateChanged(resolve) { | ||
onStateChanged = resolve; | ||
} | ||
readChild(sequence); | ||
function stopRootIterator() { | ||
stopIterator(rootIterator).then(({ | ||
done, | ||
value | ||
}) => { | ||
if (done) rootReturnResult = value; | ||
iteratorsCount--; | ||
onStateChanged(); | ||
}, error => { | ||
getters.push(() => { | ||
throw error; | ||
}); | ||
mergeDone = true; | ||
iteratorsCount--; | ||
onStateChanged(); | ||
}); | ||
} | ||
if (values.length > 0) { | ||
await dataNeeded; | ||
} | ||
function stopChildIterator(iterator) { | ||
stopIterator(iterator).then(() => { | ||
iteratorsCount--; | ||
if (mergeDone) { | ||
break; | ||
} | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return != null) { | ||
await _iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
} catch (error) { | ||
values.push(getError(error)); | ||
onStateChanged(); | ||
}, error => { | ||
getters.push(() => { | ||
throw error; | ||
}); | ||
mergeDone = true; | ||
} finally { | ||
iteratorsCount--; | ||
onStateChanged(); | ||
}); | ||
} | ||
function readRootIterator() { | ||
if (mergeDone) { | ||
stopRootIterator(); | ||
return; | ||
} | ||
readIterator(rootIterator).then(({ | ||
done, | ||
value | ||
}) => { | ||
if (done) { | ||
rootReturnResult = value; | ||
iteratorsCount--; | ||
if (iteratorsCount === 0) { | ||
onStateChanged(); | ||
return; | ||
} | ||
} | ||
} | ||
if (mergeDone) { | ||
stopRootIterator(); | ||
return; | ||
} | ||
async function readChild(sequence) { | ||
try { | ||
iteratorsCount++; | ||
var _iteratorNormalCompletion2 = true; | ||
var _didIteratorError2 = false; | ||
let childIterator; | ||
var _iteratorError2; | ||
try { | ||
childIterator = getIterator(value); | ||
} catch (error) { | ||
stopRootIterator(); | ||
getters.push(() => { | ||
throw error; | ||
}); | ||
mergeDone = true; | ||
onStateChanged(); | ||
return; | ||
for (var _iterator2 = _asyncIterator(sequence), _step2, _value2; _step2 = await _iterator2.next(), _iteratorNormalCompletion2 = _step2.done, _value2 = await _step2.value, !_iteratorNormalCompletion2; _iteratorNormalCompletion2 = true) { | ||
const value = _value2; | ||
values.push(value); | ||
onStateChanged(); | ||
await dataNeeded; | ||
if (mergeDone) { | ||
break; | ||
} | ||
} | ||
} catch (err) { | ||
_didIteratorError2 = true; | ||
_iteratorError2 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion2 && _iterator2.return != null) { | ||
await _iterator2.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError2) { | ||
throw _iteratorError2; | ||
} | ||
} | ||
} | ||
iteratorsCount++; | ||
ticks.push(readRootIterator); | ||
ticks.push(getChildReader(childIterator)); | ||
} catch (error) { | ||
values.push(getError(error)); | ||
onStateChanged(); | ||
}, error => { | ||
getters.push(() => { | ||
throw error; | ||
}); | ||
mergeDone = true; | ||
} finally { | ||
iteratorsCount--; | ||
onStateChanged(); | ||
}); | ||
} | ||
function getChildReader(iterator) { | ||
return function readChildIterator() { | ||
if (mergeDone) { | ||
stopChildIterator(iterator); | ||
return; | ||
if (iteratorsCount === 0) { | ||
onStateChanged(); | ||
} | ||
} | ||
} | ||
readIterator(iterator).then(({ | ||
done, | ||
value | ||
}) => { | ||
if (done) { | ||
iteratorsCount--; | ||
onStateChanged(); | ||
return; | ||
} | ||
function setOnStateChanged(resolve) { | ||
onStateChanged = resolve; | ||
} | ||
if (mergeDone) { | ||
stopChildIterator(iterator); | ||
return; | ||
} | ||
ticks.push(readChildIterator); | ||
getters.push(() => value); | ||
onStateChanged(); | ||
}, error => { | ||
getters.push(() => { | ||
throw error; | ||
}); | ||
mergeDone = true; | ||
iteratorsCount--; | ||
onStateChanged(); | ||
}); | ||
}; | ||
function setOnDataNeeded(resolve) { | ||
onDataNeeded = resolve; | ||
} | ||
@@ -208,45 +195,6 @@ }); | ||
const getIterator = iterable => { | ||
const method = iterable[Symbol.asyncIterator] || iterable[Symbol.iterator]; | ||
if (method) return method.call(iterable); // eslint-disable-next-line no-unused-vars | ||
for ( | ||
/* should throw here */ | ||
const x of iterable) { | ||
// istanbul ignore next | ||
throw new Error("impossible"); | ||
} // istanbul ignore next | ||
throw new Error("impossible"); | ||
}; | ||
const readIterator = iterator => PromiseTry(() => iterator.next()).then(({ | ||
done, | ||
value | ||
}) => Promise.resolve(value).then(v => ({ | ||
done, | ||
value: v | ||
}))); | ||
const stopIterator = iterator => PromiseTry(() => { | ||
const ret = iterator.return; | ||
return !ret ? { | ||
done: true, | ||
value: undefined | ||
} : Promise.resolve(ret.call(iterator)).then(({ | ||
done, | ||
value | ||
}) => Promise.resolve(value).then(v => ({ | ||
done, | ||
value: v | ||
}))); | ||
}); | ||
const PromiseTry = func => { | ||
try { | ||
return Promise.resolve(func()); | ||
} catch (error) { | ||
return Promise.reject(error); | ||
} | ||
}; | ||
function getError(error) { | ||
return { | ||
then: (resolve, reject) => reject(error) | ||
}; | ||
} |
{ | ||
"name": "mergeiterator", | ||
"version": "1.3.1", | ||
"version": "1.4.0", | ||
"description": "merges async iterators", | ||
@@ -24,3 +24,4 @@ "license": "MIT", | ||
"coverage": "npm test -- --coverage --collectCoverageFrom=src/**/*.js", | ||
"lint": "eslint .", | ||
"lint": "eslint . --ext .js,.ts", | ||
"types": "tsc --noEmit", | ||
"flow": "flow check", | ||
@@ -34,3 +35,3 @@ "flowinstall": "flow-typed install --ignoreDeps=dev; flow-typed install jest", | ||
"build": "babel src -d dist", | ||
"preversion": "npm run flowinstall && npm run lint && npm test && npm run build", | ||
"preversion": "npm run flowinstall && npm run lint && npm run types && npm test && npm run build", | ||
"postpublish": "git push origin master --follow-tags", | ||
@@ -56,11 +57,11 @@ "codecov": "codecov --token=$CODECOV_TOKEN" | ||
"devDependencies": { | ||
"@babel/cli": "^7.7.7", | ||
"@babel/core": "^7.7.7", | ||
"@babel/plugin-proposal-class-properties": "^7.7.4", | ||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.7.4", | ||
"@babel/plugin-proposal-numeric-separator": "^7.7.4", | ||
"@babel/plugin-proposal-optional-chaining": "^7.7.5", | ||
"@babel/plugin-proposal-pipeline-operator": "^7.7.7", | ||
"@babel/preset-env": "^7.7.7", | ||
"@babel/preset-flow": "^7.7.4", | ||
"@babel/cli": "^7.8.3", | ||
"@babel/core": "^7.8.3", | ||
"@babel/plugin-proposal-class-properties": "^7.8.3", | ||
"@babel/preset-env": "^7.8.3", | ||
"@babel/preset-flow": "^7.8.3", | ||
"@babel/preset-typescript": "^7.8.3", | ||
"@types/jest": "^24.9.0", | ||
"@typescript-eslint/eslint-plugin": "^2.16.0", | ||
"@typescript-eslint/parser": "^2.16.0", | ||
"babel-eslint": "^10.0.3", | ||
@@ -74,7 +75,7 @@ "babel-jest": "^24.9.0", | ||
"eslint-config-prettier": "^6.9.0", | ||
"eslint-plugin-flowtype": "^4.5.3", | ||
"eslint-plugin-flowtype": "^4.6.0", | ||
"eslint-plugin-flowtype-errors": "^4.1.0", | ||
"eslint-plugin-import": "^2.19.1", | ||
"eslint-plugin-import": "^2.20.0", | ||
"eslint-plugin-prettier": "^3.1.2", | ||
"flow-bin": "^0.115.0", | ||
"flow-bin": "^0.116.1", | ||
"flow-copy-source": "^2.0.9", | ||
@@ -85,4 +86,5 @@ "flow-typed": "^2.6.2", | ||
"prettier": "^1.19.1", | ||
"rimraf": "^3.0.0" | ||
"rimraf": "^3.0.0", | ||
"typescript": "^3.7.5" | ||
} | ||
} |
@@ -48,3 +48,3 @@ # mergeiterator | ||
The return value of `merge` is the return value of the list of iterables. Return values of merged iterables are discarded. | ||
Return values of iterables are discarded. | ||
@@ -66,4 +66,4 @@ ## API | ||
- `sequences` **AnyIterable<AnyIterable<T>, ReturnT>** | ||
- `sequences` **AnyIterable<AnyIterable<T>>** | ||
Returns **AsyncGenerator<T, ReturnT, void>** | ||
Returns **AsyncGenerator<T, any, any>** |
import { AnyIterable } from "type-any-iterable" | ||
// eslint-disable-next-line import/no-default-export | ||
export default function merge<T>(sequences: AnyIterable<AnyIterable<T>>): AsyncGenerator<T> |
// @flow | ||
import "./polyfills/symbolAsyncIterator.js" | ||
import "./polyfills/symbolAsyncIterator" | ||
// eslint-disable-next-line import/no-default-export | ||
export { merge as default } from "./mergeiterator.js" | ||
export { merge as default } from "./mergeiterator" |
@@ -8,28 +8,41 @@ // @flow | ||
*/ | ||
export async function* merge<T, ReturnT>(sequences: AnyIterable<AnyIterable<T>, ReturnT>): AsyncGenerator<T, ReturnT, void> { | ||
const rootIterator = getIterator(await sequences) | ||
const ticks = [readRootIterator] | ||
const getters = [] | ||
let iteratorsCount = 1 // There is only rootIterator opened so far. | ||
export async function* merge<T>(sequences: AnyIterable<AnyIterable<T>>): AsyncGenerator<T, *, *> { | ||
// | ||
let onDataNeeded = () => {} | ||
let dataNeeded = new Promise(setOnDataNeeded) | ||
let onStateChanged = () => {} // should be called whenever values used in the main `while` loop have been changed. These are: iteratorsCount > 0 and values | ||
const values = [] | ||
let iteratorsCount = 0 | ||
let mergeDone = false | ||
let onStateChanged // should be called whenever values used in the main `while` loop have been changed. These are: iteratorsCount, ticks and getters | ||
let normalReturn = true | ||
let rootReturnResult | ||
readRoot() | ||
try { | ||
while (iteratorsCount > 0) { | ||
const stateChanged = new Promise(setOnStateChanged) | ||
while (ticks.length) ticks.shift()() | ||
await stateChanged | ||
while (getters.length > 0) yield getters.shift()() | ||
while (iteratorsCount > 0 || values.length > 0) { | ||
if (values.length > 0) { | ||
if (typeof values[0] === "object" && values[0] && typeof values[0].then === "function") { | ||
yield await (values.shift(): any) | ||
} else { | ||
yield values.shift() | ||
} | ||
} else { | ||
const oldOnDataNeeded = onDataNeeded | ||
dataNeeded = new Promise(setOnDataNeeded) | ||
const stateChanged = new Promise(setOnStateChanged) | ||
oldOnDataNeeded() | ||
await stateChanged | ||
} | ||
} | ||
} catch (e) { | ||
} catch (error) { | ||
normalReturn = false | ||
throw e | ||
throw error | ||
} finally { | ||
mergeDone = true | ||
onDataNeeded() | ||
while (iteratorsCount > 0) { | ||
const stateChanged = new Promise(setOnStateChanged) | ||
while (ticks.length) ticks.shift()() | ||
await stateChanged | ||
await new Promise(setOnStateChanged) | ||
} | ||
@@ -39,158 +52,65 @@ // Do not hide an exception if it's been already raised. | ||
// Raise possible exceptions on iterators interruption. | ||
while (getters.length > 0) getters.shift()() | ||
// There is no chance to return a value out of finally block if .return() is called. | ||
// eslint-disable-next-line no-unsafe-finally | ||
return (rootReturnResult: any) | ||
while (values.length > 0) await values.shift() | ||
} | ||
} | ||
// istanbul ignore next | ||
throw new Error("impossible") | ||
function setOnStateChanged(resolve) { | ||
onStateChanged = resolve | ||
} | ||
function stopRootIterator() { | ||
stopIterator(rootIterator).then( | ||
({ done, value }) => { | ||
if (done) rootReturnResult = value | ||
iteratorsCount-- | ||
async function readRoot() { | ||
try { | ||
iteratorsCount++ | ||
for await (const sequence of await (sequences: any)) { | ||
if (mergeDone) { | ||
break | ||
} | ||
readChild(sequence) | ||
if (values.length > 0) { | ||
await dataNeeded | ||
} | ||
if (mergeDone) { | ||
break | ||
} | ||
} | ||
} catch (error) { | ||
values.push(getError(error)) | ||
onStateChanged() | ||
} finally { | ||
iteratorsCount-- | ||
if (iteratorsCount === 0) { | ||
onStateChanged() | ||
}, | ||
error => { | ||
getters.push(() => { | ||
throw error | ||
}) | ||
mergeDone = true | ||
iteratorsCount-- | ||
onStateChanged() | ||
}, | ||
) | ||
} | ||
} | ||
} | ||
function stopChildIterator(iterator) { | ||
stopIterator(iterator).then( | ||
() => { | ||
iteratorsCount-- | ||
async function readChild(sequence) { | ||
try { | ||
iteratorsCount++ | ||
for await (const value of sequence) { | ||
values.push(value) | ||
onStateChanged() | ||
}, | ||
error => { | ||
getters.push(() => { | ||
throw error | ||
}) | ||
mergeDone = true | ||
iteratorsCount-- | ||
onStateChanged() | ||
}, | ||
) | ||
} | ||
function readRootIterator() { | ||
if (mergeDone) { | ||
stopRootIterator() | ||
return | ||
} | ||
readIterator(rootIterator).then( | ||
({ done, value }) => { | ||
if (done) { | ||
rootReturnResult = value | ||
iteratorsCount-- | ||
onStateChanged() | ||
return | ||
} | ||
await dataNeeded | ||
if (mergeDone) { | ||
stopRootIterator() | ||
return | ||
break | ||
} | ||
let childIterator | ||
try { | ||
childIterator = getIterator(value) | ||
} catch (error) { | ||
stopRootIterator() | ||
getters.push(() => { | ||
throw error | ||
}) | ||
mergeDone = true | ||
onStateChanged() | ||
return | ||
} | ||
iteratorsCount++ | ||
ticks.push(readRootIterator) | ||
ticks.push(getChildReader(childIterator)) | ||
} | ||
} catch (error) { | ||
values.push(getError(error)) | ||
onStateChanged() | ||
} finally { | ||
iteratorsCount-- | ||
if (iteratorsCount === 0) { | ||
onStateChanged() | ||
}, | ||
error => { | ||
getters.push(() => { | ||
throw error | ||
}) | ||
mergeDone = true | ||
iteratorsCount-- | ||
onStateChanged() | ||
}, | ||
) | ||
} | ||
function getChildReader(iterator) { | ||
return function readChildIterator() { | ||
if (mergeDone) { | ||
stopChildIterator(iterator) | ||
return | ||
} | ||
readIterator(iterator).then( | ||
({ done, value }) => { | ||
if (done) { | ||
iteratorsCount-- | ||
onStateChanged() | ||
return | ||
} | ||
if (mergeDone) { | ||
stopChildIterator(iterator) | ||
return | ||
} | ||
ticks.push(readChildIterator) | ||
getters.push(() => (value: any)) | ||
onStateChanged() | ||
}, | ||
error => { | ||
getters.push(() => { | ||
throw error | ||
}) | ||
mergeDone = true | ||
iteratorsCount-- | ||
onStateChanged() | ||
}, | ||
) | ||
} | ||
} | ||
} | ||
const getIterator = (iterable: any): any => { | ||
const method = iterable[(Symbol: any).asyncIterator] || iterable[Symbol.iterator] | ||
if (method) return (method.call(iterable): any) | ||
// eslint-disable-next-line no-unused-vars | ||
for (/* should throw here */ const x of iterable) { | ||
// istanbul ignore next | ||
throw new Error("impossible") | ||
function setOnStateChanged(resolve) { | ||
onStateChanged = resolve | ||
} | ||
// istanbul ignore next | ||
throw new Error("impossible") | ||
} | ||
const readIterator = iterator => PromiseTry(() => iterator.next()).then(({ done, value }) => Promise.resolve(value).then(v => ({ done, value: v }))) | ||
const stopIterator = iterator => | ||
PromiseTry(() => { | ||
const ret = iterator.return | ||
return !ret | ||
? { done: true, value: undefined } | ||
: Promise.resolve(ret.call(iterator)).then(({ done, value }) => Promise.resolve(value).then(v => ({ done, value: v }))) | ||
}) | ||
const PromiseTry = func => { | ||
try { | ||
return Promise.resolve(func()) | ||
} catch (error) { | ||
return Promise.reject(error) | ||
function setOnDataNeeded(resolve) { | ||
onDataNeeded = resolve | ||
} | ||
} | ||
function getError(error): any { | ||
return { then: (resolve, reject) => reject(error) } | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
19091
29
292
1