stream-compare
Advanced tools
Comparing version 2.0.0 to 3.0.0
@@ -1,3 +0,20 @@ | ||
# Change Log | ||
# [3.0.0](https://github.com/kevinoid/stream-compare/compare/v2.0.0...v3.0.0) (2020-04-26) | ||
### BREAKING CHANGES | ||
* Additional events after `'end'` are compared by default, if they occur before | ||
the event queue becomes empty since the previous event (i.e. before | ||
`setImmediate` from the last event on a stream). | ||
* `options.delay` applies after `setImmediate` from the last event. | ||
* Drop support for Node.js before 10.13. | ||
### Bug Fixes | ||
* `makeIncremental` now considers whether additional events are expected, | ||
rather than whether `'end'` has been emitted | ||
([f7ddc29](https://github.com/kevinoid/stream-compare/commit/f7ddc29690ca6a1d8f54144097cefb1cf9394cda)) | ||
## [v2.0.0](https://github.com/kevinoid/stream-compare/tree/v2.0.0) (2018-06-29) | ||
@@ -4,0 +21,0 @@ [Full Changelog](https://github.com/kevinoid/stream-compare/compare/v1.0.0...v2.0.0) |
119
index.js
@@ -8,3 +8,3 @@ /** | ||
const {EventEmitter} = require('events'); | ||
const { EventEmitter } = require('events'); | ||
const util = require('util'); | ||
@@ -24,3 +24,3 @@ | ||
/** A full comparison followed by <code>'end'</code>. */ | ||
last: 'last' | ||
last: 'last', | ||
}; | ||
@@ -43,3 +43,3 @@ | ||
* reached. */ | ||
none: 'none' | ||
none: 'none', | ||
}; | ||
@@ -59,3 +59,3 @@ | ||
/** @type {!ReadPolicy} */ | ||
readPolicy: 'least' | ||
readPolicy: 'least', | ||
}; | ||
@@ -87,2 +87,9 @@ | ||
this.events = []; | ||
/** Are more events expected on this stream? | ||
* | ||
* Initially true, currently set false once an event in options.endEvents has | ||
* been emitted and no additional events have been emitted since the event | ||
* queue was last cleared (i.e. after setImmediate). | ||
*/ | ||
this.expectEvents = true; | ||
/** Data returned/emitted by the stream (as an <code>Array</code> if in | ||
@@ -120,4 +127,4 @@ * <code>objectMode</code>). | ||
* not specified. | ||
* @property {number=} delay Additional delay (in ms) after streams end before | ||
* comparing. (default: <code>0</code>) | ||
* @property {number=} delay Delay (in ms) after both streams have emitted | ||
* their last expected event before comparing. (default: <code>0</code>) | ||
* @property {Array<string>=} endEvents Names of events which signal the end of | ||
@@ -172,3 +179,3 @@ * a stream. Final compare is performed once both streams have emitted an end | ||
if (typeof optionsOrCompare === 'function') { | ||
options = {compare: optionsOrCompare}; | ||
options = { compare: optionsOrCompare }; | ||
} else if (typeof optionsOrCompare === 'object') { | ||
@@ -181,3 +188,3 @@ options = optionsOrCompare; | ||
options = Object.assign({}, DEFAULT_OPTIONS, options); | ||
options = { ...DEFAULT_OPTIONS, ...options }; | ||
if (!options.compare) { | ||
@@ -228,13 +235,14 @@ options.compare = options.incremental; | ||
let resolve; | ||
const promise = new Promise(((resolveArg, rejectArg) => { | ||
// eslint-disable-next-line promise/param-names | ||
const promise = new Promise((resolveArg, rejectArg) => { | ||
resolve = resolveArg; | ||
reject = rejectArg; | ||
})); | ||
}); | ||
const state1 = new StreamState(); | ||
const state2 = new StreamState(); | ||
let ended = 0; | ||
let isDone = false; | ||
const listeners1 = {}; | ||
const listeners2 = {}; | ||
let postEndImmediate; | ||
let lastEventImmediate1; | ||
let lastEventImmediate2; | ||
let postEndTimeout; | ||
@@ -256,2 +264,4 @@ | ||
/* eslint-disable no-use-before-define */ | ||
Object.keys(listeners1).forEach((eventName) => { | ||
@@ -277,3 +287,6 @@ stream1.removeListener(eventName, listeners1[eventName]); | ||
clearImmediate(postEndImmediate); | ||
/* eslint-enable no-use-before-define */ | ||
clearImmediate(lastEventImmediate1); | ||
clearImmediate(lastEventImmediate2); | ||
clearTimeout(postEndTimeout); | ||
@@ -346,2 +359,42 @@ | ||
function lastEventListener(stream, state) { | ||
debug(`Not expecting more events from ${streamName(stream)}.`); | ||
state.expectEvents = false; | ||
if (options.incremental) { | ||
if (doCompare(options.incremental, CompareType.incremental)) { | ||
return; | ||
} | ||
} | ||
if (!state1.expectEvents && !state2.expectEvents) { | ||
const postEventsCompare = | ||
() => doCompare(options.compare, CompareType.last); | ||
if (options.delay) { | ||
debug(`All streams have ended. Delaying for ${options.delay | ||
}ms before final compare.`); | ||
postEndTimeout = setTimeout(postEventsCompare, options.delay); | ||
} else { | ||
postEventsCompare(); | ||
} | ||
} | ||
} | ||
function anyEventListener1() { | ||
// If waiting for the last event on this stream, move to end of queue. | ||
if (lastEventImmediate1) { | ||
clearImmediate(lastEventImmediate1); | ||
lastEventImmediate1 = setImmediate(lastEventListener, stream1, state1); | ||
} | ||
} | ||
function anyEventListener2() { | ||
// If waiting for the last event on this stream, move to end of queue. | ||
if (lastEventImmediate2) { | ||
clearImmediate(lastEventImmediate2); | ||
lastEventImmediate2 = setImmediate(lastEventListener, stream2, state2); | ||
} | ||
} | ||
// Note: Add event listeners before endListeners so end/error is recorded | ||
@@ -361,3 +414,3 @@ options.events.forEach((eventName) => { | ||
name: eventName, | ||
args: Array.prototype.slice.call(args) | ||
args: Array.prototype.slice.call(args), | ||
}); | ||
@@ -370,13 +423,17 @@ | ||
listeners1[eventName] = function listener1(...args) { | ||
function listener1(...args) { | ||
debug(`'${eventName}' event from stream1.`); | ||
listener.apply(state1, args); | ||
}; | ||
stream1.on(eventName, listeners1[eventName]); | ||
anyEventListener1(); | ||
} | ||
listeners1[eventName] = listener1; | ||
stream1.on(eventName, listener1); | ||
listeners2[eventName] = function listener2(...args) { | ||
function listener2(...args) { | ||
debug(`'${eventName}' event from stream2.`); | ||
listener.apply(state2, args); | ||
}; | ||
stream2.on(eventName, listeners2[eventName]); | ||
anyEventListener2(); | ||
} | ||
listeners2[eventName] = listener2; | ||
stream2.on(eventName, listener2); | ||
}); | ||
@@ -397,3 +454,2 @@ | ||
state.ended = true; | ||
ended += 1; | ||
@@ -408,15 +464,6 @@ debug(`${streamName(this)} has ended.`); | ||
if (ended === 2) { | ||
const postEndCompare = function() { | ||
doCompare(options.compare, CompareType.last); | ||
}; | ||
if (options.delay) { | ||
debug(`All streams have ended. Delaying for ${options.delay | ||
}ms before final compare.`); | ||
postEndTimeout = setTimeout(postEndCompare, options.delay); | ||
} else { | ||
// Let pending I/O and callbacks complete to catch some errant events | ||
debug('All streams have ended. Delaying before final compare.'); | ||
postEndImmediate = setImmediate(postEndCompare); | ||
} | ||
if (state === state1) { | ||
lastEventImmediate1 = setImmediate(lastEventListener, this, state); | ||
} else { | ||
lastEventImmediate2 = setImmediate(lastEventListener, this, state); | ||
} | ||
@@ -426,5 +473,7 @@ } | ||
function endListener1() { | ||
anyEventListener1(); | ||
endListener.call(this, state1); | ||
} | ||
function endListener2() { | ||
anyEventListener2(); | ||
endListener.call(this, state2); | ||
@@ -485,3 +534,3 @@ } | ||
[this.data, data], | ||
this.data.length + data.length | ||
this.data.length + data.length, | ||
); | ||
@@ -488,0 +537,0 @@ } |
@@ -27,12 +27,12 @@ /** | ||
// Note: Values may be undefined if no data was read. | ||
if (((values1 && values1.length !== 0) || state1.ended) | ||
&& ((values2 && values2.length !== 0) || state2.ended)) { | ||
if (((values1 && values1.length !== 0) || !state1.expectEvents) | ||
&& ((values2 && values2.length !== 0) || !state2.expectEvents)) { | ||
const minLen = Math.min( | ||
values1 ? values1.length : 0, | ||
values2 ? values2.length : 0 | ||
values2 ? values2.length : 0, | ||
); | ||
if ((values1 && values1.length > minLen) && !state2.ended) { | ||
if ((values1 && values1.length > minLen) && state2.expectEvents) { | ||
result = compare(values1.slice(0, minLen), values2); | ||
} else if ((values2 && values2.length > minLen) && !state1.ended) { | ||
} else if ((values2 && values2.length > minLen) && state1.expectEvents) { | ||
result = compare(values1, values2.slice(0, minLen)); | ||
@@ -39,0 +39,0 @@ } else { |
{ | ||
"name": "stream-compare", | ||
"version": "2.0.0", | ||
"version": "3.0.0", | ||
"description": "Compare the behavior of readable streams.", | ||
@@ -23,2 +23,3 @@ "keywords": [ | ||
"scripts": { | ||
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -u", | ||
"clean": "rimraf coverage && rimraf doc", | ||
@@ -30,37 +31,44 @@ "doc": "npm run doc-js && npm run doc-spec", | ||
"lint-doc": "jsdoc -t templates/silent -c jsdoc-lint.conf.json . && echo JSDoc passed.", | ||
"lint-js": "eslint . && echo ESLint passed.", | ||
"postpublish": "git -C doc push && git push --follow-tags origin master gh-pages && echo Remember to update GitHub Releases from CHANGELOG.md && echo until skywinder/github-changelog-generator#56 is fixed.", | ||
"lint-js": "eslint --report-unused-disable-directives . && echo ESLint passed.", | ||
"postpublish": "git -C doc push && git push --follow-tags origin master gh-pages && echo Remember to update GitHub Releases from CHANGELOG.md", | ||
"postversion": "rimraf doc && git clone -b gh-pages -l -q . doc && npm run doc && git -C doc add . && git -C doc commit -n -m \"Docs for v$npm_package_version\"", | ||
"preversion": "depcheck --ignores eslint-plugin-import,greenkeeper-lockfile --ignore-dirs doc && david -i eslint && git-branch-is master && travis-status -b master -c -wx && appveyor-status -b master -c -p kevinoid/stream-compare -w && istanbul check-coverage --statements 95 coverage/coverage.json", | ||
"preversion": "npm run test-cov && nyc check-coverage --statements 95 && depcheck --ignore-dirs doc && david && git-branch-is master && travis-status -b master -c -w -x && appveyor-status -b master -c -w -p kevinoid/stream-compare", | ||
"test": "npm run lint && npm run test-unit", | ||
"test-cov": "npm run lint && npm run test-unit-cov", | ||
"test-unit": "mocha --recursive test", | ||
"test-unit-cov": "istanbul cover _mocha -- --recursive test", | ||
"test-unit-cov": "nyc mocha --recursive test", | ||
"upload-cov": "codecov < ./coverage/lcov.info && coveralls < ./coverage/lcov.info", | ||
"version": "github_changelog_generator -t \"$npm_config_gcg_github_token\" --future-release \"$npm_package_version\" && echo && echo === Please edit CHANGELOG.md as desired, then exit === && echo && $npm_config_shell && git commit -m \"Update CHANGELOG.md for $npm_package_version\" CHANGELOG.md", | ||
"version-deps": "npm install david depcheck git-branch-is travis-status" | ||
"version": "npm run changelog && echo && echo === Please edit CHANGELOG.md as desired, then exit === && echo && $npm_config_shell && git commit -m \"Update CHANGELOG.md for $npm_package_version\" CHANGELOG.md", | ||
"version-deps": "npm install conventional-changelog-cli david depcheck git-branch-is travis-status" | ||
}, | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"@kevinoid/eslint-config": "^7.0.0", | ||
"codecov": "^3.0.0", | ||
"coveralls": "^3.0.0", | ||
"eslint": "^4.6.1", | ||
"eslint-config-airbnb-base": "^13.0.0", | ||
"eslint-plugin-import": "^2.7.0", | ||
"greenkeeper-lockfile": "^1.15.1", | ||
"istanbul": "^0.4.1", | ||
"jsdoc": "^3.4.1", | ||
"mocha": "^5.0.0", | ||
"eslint": "^6.7.1", | ||
"eslint-config-airbnb-base": "^14.0.0", | ||
"eslint-plugin-import": "^2.18.2", | ||
"eslint-plugin-node": "^11.0.0", | ||
"eslint-plugin-promise": "^4.2.1", | ||
"eslint-plugin-unicorn": "^19.0.0", | ||
"jsdoc": "^3.6.0", | ||
"mocha": "^7.0.0", | ||
"nodecat": "^2.0.0", | ||
"rimraf": "^2.2.0" | ||
"nyc": "^15.0.0", | ||
"rimraf": "^3.0.0" | ||
}, | ||
"engines": { | ||
"node": ">=6", | ||
"node": ">=10.13", | ||
"npm": ">=1.3.7" | ||
}, | ||
"greenkeeper": { | ||
"ignore": [ | ||
"eslint" | ||
"mocha": { | ||
"checkLeaks": true, | ||
"exit": false | ||
}, | ||
"nyc": { | ||
"exclude": [ | ||
"test" | ||
] | ||
} | ||
} |
@@ -163,4 +163,9 @@ stream-compare | ||
Contributions are welcome and very much appreciated! Please add tests to | ||
cover any changes and ensure `npm test` passes. | ||
Contributions are appreciated. Contributors agree to abide by the [Contributor | ||
Covenant Code of | ||
Conduct](https://www.contributor-covenant.org/version/1/4/code-of-conduct.html). | ||
If this is your first time contributing to a Free and Open Source Software | ||
project, consider reading [How to Contribute to Open | ||
Source](https://opensource.guide/how-to-contribute/) | ||
in the Open Source Guides. | ||
@@ -175,3 +180,7 @@ If the desired change is large, complex, backwards-incompatible, can have | ||
This package is available under the terms of the | ||
[MIT License](https://opensource.org/licenses/MIT). | ||
This project is available under the terms of the [MIT License](LICENSE.txt). | ||
See the [summary at TLDRLegal](https://tldrlegal.com/license/mit-license). | ||
The [template](https://github.com/kevinoid/node-project-template) upon which | ||
this project is based is available under the terms of | ||
[CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/). |
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
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
36007
636
185
14