diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 39033b6d..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - "extends": "standard", - "rules": { - "no-var": ["error"], - "prefer-const": ["error"], - "prefer-arrow-callback": ["error"], - "prefer-template": ["error"] - } -}; diff --git a/.gitignore b/.gitignore index e4c4b4f6..3c3629e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,30 +1 @@ -*~ - -# Logs -logs -*.log - -# Runtime data -pids -*.pid -*.seed - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release - -# Dependency directory -# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- node_modules -.nyc_output diff --git a/.travis.yml b/.travis.yml index 54a9db62..aa1dc398 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,6 @@ language: node_js + node_js: -- '14' -- '12' -- '10' -- '9' -- '8' -script: npm run test -# deploy: -# provider: npm -# email: evan@fuzzy.ai -# api_key: -# secure: GBaiqCYxs6sYyGoyqWx/B066cJMe7wdeaVW6WCIJRJSkUO34ZKLI19sUCM8P6fV4qnhoIQH6LlnmWcu/8LpswCmx+5DWhNdcVzIWWJ4ewheccSlckdI2crqCaAkE52fQxLZbI/g+xiwE4QcYHNgmJIcONbf8PQwSPtYDK44Edh8ILxO+VdYg/AHpQyoCn8afovuh7nzNCdsR0iDBAY20RoSNungB/360riCCCaUxc95d/gzMccase2/z78zgQoz84ffarP1N5GjZlMsCm0u8aIMjI3YPiOWjwClXP7ZUH/VDrKpYhKxbFo2jb2h0ynhhneg+jK2b7rR5zXSK/koagT6y/IGl75/M5i9CTAEc6BlKBEa/KLDVl89IdXAr7b3KYY1KQdNuwpuxnX6QwIDRVqKdFzknkiUYttWvyL9SG/c6WfucYS07f+FKC4qrAcAjgt7VLV7N72amrFleTazQ67NSPpLaxjjX8qffRbjaACJwO2ydhVcKOXe3CqDxGgh3uvK90qfcBvO8U8fDz6759FT2HxYjpnYV7DXRuC47TDwQHHDNOQFDgFwOb2F1FqQAws9BWwbKtZWwPBdYaT0L3GYwlTMaL816D9sCxyo9whXPz0k7s59uks+VrP6t1x/WBFd68XTsGB7/B2h9LglLkQOFFl7PbOdQfqQZJqYA2uo= -# on: -# tags: true -# repo: vowsjs/vows + - 0.4 + - 0.6 + diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 13aaebad..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,577 +0,0 @@ -v1.0.0 / (?) -============ - * [perjury](https://github.com/fuzzy-ai/perjury), a vows work-alike with a new - codebase, becomes the new vows. - * the minimum required Node version is now Node 9 (4, 5, 6, and 8 were previously supported by perjury and are now dropped; 7 was never supported) - -v0.8.1 / Fri, 21 Nov 2014 -========================= - * [81333f3](https://github.com/flatiron/vows/commit/81333f3) [dist] Version bump. 0.8.1 (`indexzero`) - * [73872a8](https://github.com/flatiron/vows/commit/73872a8) [fix doc] Remove all mentions of the word "promise", vows is based on the EventEmitter. (`indexzero`) - * [a8314b8](https://github.com/flatiron/vows/commit/a8314b8) Delay process.exit for proper drain of streams on node 0.10 (`Illya Klymov`) - * [01590ff](https://github.com/flatiron/vows/commit/01590ff) make importSuites work with jscover (`Reno Reckling`) - * [a39d1b8](https://github.com/flatiron/vows/commit/a39d1b8) Ensure that assertions fail when arguments are missing (`Christian Tegnér`) - * [049b026](https://github.com/flatiron/vows/commit/049b026) [fix] One significant digit for code coverage. Fixes #240. (`indexzero`) - * [9ee52a7](https://github.com/flatiron/vows/commit/9ee52a7) Round coverage percentage down. (`David I. Lehn`) - * [acbb20a](https://github.com/flatiron/vows/commit/acbb20a) [fix] Partially revert bc4c23929f3ce4ba66650130675405a1e85bb26c. Fixes #325. (`indexzero`) - * [2405195](https://github.com/flatiron/vows/commit/2405195) [fix] Use `.toStringEx()` in test from #324. (`indexzero`) - * [e9b4d76](https://github.com/flatiron/vows/commit/e9b4d76) Show full path in error traces (`execjosh`) - * [d6118ec](https://github.com/flatiron/vows/commit/d6118ec) Refactor error stack trace file path extraction (`execjosh`) - * [5dced8e](https://github.com/flatiron/vows/commit/5dced8e) Fixed recursive call of assertion errors which led to a huge delay when a test failed - Fixes cloudhead/vows#278 (`Pascal Mathis`) - * [f5cec76](https://github.com/flatiron/vows/commit/f5cec76) Tests for assert.epsilon failing on NaN (`James Gibson`) - * [ec0442c](https://github.com/flatiron/vows/commit/ec0442c) Make assert.epsilon fail for NaN actual value (`James Gibson`) - * [64857e3](https://github.com/flatiron/vows/commit/64857e3) [dist] Towards a meaningful CHANGELOG.md. Generated from: https://github.com/indexzero/dotfiles/blob/master/scripts/git-changelog-all (`indexzero`) - * [f18b325](https://github.com/flatiron/vows/commit/f18b325) [fix dist] Fix travis and the "^" operator on `node@0.8.x`. (`indexzero`) - * [875f0d3](https://github.com/flatiron/vows/commit/875f0d3) Correct assignment for assert.notInclude() synonym assert.notIncludes() (`Evan Prodromou`) - * [1c598f0](https://github.com/flatiron/vows/commit/1c598f0) [fix] Properly handle `NaN` in `assert.inDelta` extension. Fixes #120. Thanks @mbostock! (`indexzero`) - * [1b44458](https://github.com/flatiron/vows/commit/1b44458) [fix] Fix typos in some reporters. Fixes #287. (`indexzero`) - * [b14f762](https://github.com/flatiron/vows/commit/b14f762) [test] Add failing tests for #287. (`indexzero`) - * [e9fb10d](https://github.com/flatiron/vows/commit/e9fb10d) Add instructive error message to `importSuites` that could help new users. (`Michael Floering`) - -v0.8.0 / Tue, 4 Nov 2014 -======================== - * [775db8f](https://github.com/flatiron/vows/commit/775db8f) [dist] Version bump. 0.8.0 (`indexzero`) - * [623b375](https://github.com/flatiron/vows/commit/623b375) [dist] Update dependencies to latest. (`indexzero`) - * [bf8e6aa](https://github.com/flatiron/vows/commit/bf8e6aa) [dist] Update contributors on README and package.json. (`indexzero`) - * [f113849](https://github.com/flatiron/vows/commit/f113849) [doc] Added TravisCI build status. (`indexzero`) - * [f9f37df](https://github.com/flatiron/vows/commit/f9f37df) sh instead of js (`Ionică Bizău`) - * [8db36b9](https://github.com/flatiron/vows/commit/8db36b9) Code highlight (`Ionică Bizău`) - * [43e917c](https://github.com/flatiron/vows/commit/43e917c) Regenerated package.json (`Ionică Bizău`) - * [a7764ad](https://github.com/flatiron/vows/commit/a7764ad) Add tests on context and sub context, synchronous and asynchronous (`Romain`) - * [03a04db](https://github.com/flatiron/vows/commit/03a04db) [fix] Support backwards compatibility for Object reporters in #190. (`indexzero`) - * [f120d45](https://github.com/flatiron/vows/commit/f120d45) Ability to programmatically specify reporter (`Ilya Shaisultanov`) - * [7939c94](https://github.com/flatiron/vows/commit/7939c94) [test] fix .travis.yml file needs quote, remove 0.9, add 0.11 (`Swaagie`) - * [a5acef5](https://github.com/flatiron/vows/commit/a5acef5) Typo fix. (`Brian Donovan`) - * [1e8fa11](https://github.com/flatiron/vows/commit/1e8fa11) Make coffeescript register itself if it has a register function. (`Steven H. Noble`) - * [42f23c3](https://github.com/flatiron/vows/commit/42f23c3) refactor: remove line that was made redundant after the last merge from upstream (`adamstallard`) - * [ef5e76b](https://github.com/flatiron/vows/commit/ef5e76b) ignore hg files (`adamstallard`) - * [e6bcc64](https://github.com/flatiron/vows/commit/e6bcc64) update vows package (`adamstallard`) - * [45e9fdf](https://github.com/flatiron/vows/commit/45e9fdf) Moved tag master to changeset 45104b15b3a8 (from changeset 45e0b0d31984) (`adamstallard`) - * [ecac185](https://github.com/flatiron/vows/commit/ecac185) Moved tag default/master to changeset 45104b15b3a8 (from changeset 5797560897ea) (`adamstallard`) - * [ce6c2c6](https://github.com/flatiron/vows/commit/ce6c2c6) update vows package (`adamstallard`) - * [c8c2ff0](https://github.com/flatiron/vows/commit/c8c2ff0) Backed out changeset: be18031783bf (`adamstallard`) - * [e86bddd](https://github.com/flatiron/vows/commit/e86bddd) Backed out changeset: 19f9533f9bae (`adamstallard`) - * [f031545](https://github.com/flatiron/vows/commit/f031545) Added tag default for changeset 162f542dd244 (`adamstallard`) - * [eaaf51a](https://github.com/flatiron/vows/commit/eaaf51a) Moved tag master to changeset 45e0b0d31984 (from changeset be18031783bf) (`adamstallard`) - * [7595734](https://github.com/flatiron/vows/commit/7595734) Moved tag default/master to changeset 45e0b0d31984 (from changeset 5797560897ea) (`adamstallard`) - * [d6e2872](https://github.com/flatiron/vows/commit/d6e2872) Added tag master for changeset be18031783bf (`adamstallard`) - * [e1d3d16](https://github.com/flatiron/vows/commit/e1d3d16) remove accidental commit (`adamstallard`) - * [2d77a7a](https://github.com/flatiron/vows/commit/2d77a7a) update vows package (`adamstallard`) - * [1ed1b8c](https://github.com/flatiron/vows/commit/1ed1b8c) Added repository field to package.json (`Gabe De`) - * [d1d02e0](https://github.com/flatiron/vows/commit/d1d02e0) [test] Test on recent versions of node (`Maciej Małecki`) - * [bc4c239](https://github.com/flatiron/vows/commit/bc4c239) [fix] Do not use `util.{print,puts}` (`Maciej Małecki`) - * [a23a1c9](https://github.com/flatiron/vows/commit/a23a1c9) continue to run subtopics even if a parent topic has an error in it (fixes #231) (`adamstallard`) - * [eb66421](https://github.com/flatiron/vows/commit/eb66421) Set the return value to 'undefined' on an unexpected error (since we always use a callback); improve comments (`adamstallard`) - * [8e4c8b8](https://github.com/flatiron/vows/commit/8e4c8b8) use node-glob instead of wildcard for better pattern support (`J. Lee Coltrane`) - * [d6604c3](https://github.com/flatiron/vows/commit/d6604c3) Don't print out extra blank lines in the spec reporter when end of suite fires. (`adamstallard`) - * [e10dc94](https://github.com/flatiron/vows/commit/e10dc94) Make the xunit reporter follow the established pattern of using the vows console module and allowing for overriding the stream. (`adamstallard`) - * [98470cb](https://github.com/flatiron/vows/commit/98470cb) revert accidental inclusion of print statement (`adamstallard`) - * [4acd17e](https://github.com/flatiron/vows/commit/4acd17e) Check that tests report errors like they should (`adamstallard`) - * [50a13b5](https://github.com/flatiron/vows/commit/50a13b5) Handle errors correctly based on suite.options.error and the number of parameters expected by the vow: When suite.options.error is set to false or a vow expects two or more parameters, get the error as the first argument and don't report it; When suite.options.error is set to true and a vow expects zero or one parameters, report the error and do not run the vow. (`adamstallard`) - * [26e5941](https://github.com/flatiron/vows/commit/26e5941) fix typo in comment (`adamstallard`) - * [a7843f4](https://github.com/flatiron/vows/commit/a7843f4) [dist doc] Remove unnecessary Makefile and document that tests should be run with `npm test`. Fixes #241 (`indexzero`) - * [458eb3e](https://github.com/flatiron/vows/commit/458eb3e) diff colors were reversed (`Andrew Petersen`) - * [154b6cd](https://github.com/flatiron/vows/commit/154b6cd) Add a not include assertion (`Fred Cox`) - * [4a9dc5d](https://github.com/flatiron/vows/commit/4a9dc5d) added nopstream to mimic writing to /dev/null on windows (`Dale Stammen`) - * [5d087fc](https://github.com/flatiron/vows/commit/5d087fc) added nullstream.js to mock /dev/null on windows (`Dale Stammen`) - * [92868a9](https://github.com/flatiron/vows/commit/92868a9) support for windows drives other than c: (`Dale Stammen`) - * [f7d09c5](https://github.com/flatiron/vows/commit/f7d09c5) node can't write to nul. reserved filename in windows. changed to .nul. updated .gitignore (`Dale Stammen`) - * [4c53be1](https://github.com/flatiron/vows/commit/4c53be1) fix for issue 248. file starts with a c (`Dale Stammen`) - -v0.7.0 / Fri, 16 Nov 2012 -========================= - * [c683d88](https://github.com/flatiron/vows/commit/c683d88) [dist] Bump version to 0.7.0 (`Maciej Małecki`) - * [8776492](https://github.com/flatiron/vows/commit/8776492) use nul for windows equivalent of /dev/null. Added nul to .gitignore (`Dale Stammen`) - * [48683fb](https://github.com/flatiron/vows/commit/48683fb) fixed path handling for wildcards and test module loading with require (`Dale Stammen`) - * [5085b39](https://github.com/flatiron/vows/commit/5085b39) remove console.log statementsif present from start of results (`Dale Stammen`) - * [7f8d511](https://github.com/flatiron/vows/commit/7f8d511) remove os.EOL for strerr test. Only removed first result if not json (`Dale Stammen`) - * [aace8dd](https://github.com/flatiron/vows/commit/aace8dd) skip over non json results (`Dale Stammen`) - * [b5438a1](https://github.com/flatiron/vows/commit/b5438a1) remove --supress-stdout only on win32 (`Dale Stammen`) - * [d419819](https://github.com/flatiron/vows/commit/d419819) remove windows specific reposne in stdout (`Dale Stammen`) - * [8ceef77](https://github.com/flatiron/vows/commit/8ceef77) removed --supress-stdout from spawn. check for C: in file paths (`Dale Stammen`) - * [cfe7888](https://github.com/flatiron/vows/commit/cfe7888) removed console.log (`Dale Stammen`) - * [70865cc](https://github.com/flatiron/vows/commit/70865cc) added wildcard * support to files (`Dale Stammen`) - * [e85197b](https://github.com/flatiron/vows/commit/e85197b) use process.execPath and not ./bin/vows in for cmd in call to exec(). Fix for windows (`Dale Stammen`) - * [cde6d9b](https://github.com/flatiron/vows/commit/cde6d9b) added ignore .idea (`Dale Stammen`) - * [304643f](https://github.com/flatiron/vows/commit/304643f) use process.execPath not ./bin/vows. This is consistent with how exec works in vows and works on windows. Use os.EOL to check oh no string so it works on platforms that use \r\n (`Dale Stammen`) - * [d728652](https://github.com/flatiron/vows/commit/d728652) added cross-platform fixes to support windows (`Dale Stammen`) - * [f412e4a](https://github.com/flatiron/vows/commit/f412e4a) [fix] Fix crashes on node v0.9.3 (`Maciej Małecki`) - * [d073b06](https://github.com/flatiron/vows/commit/d073b06) Do not catch ReferenceError (`Romain`) - -v0.6.4 / Thu, 23 Aug 2012 -========================= - * [e797515](https://github.com/flatiron/vows/commit/e797515) [dist] Bump version to 0.6.4 (`Maciej Małecki`) - * [8dea08d](https://github.com/flatiron/vows/commit/8dea08d) [dist] Fix `package.json` (`Maciej Małecki`) - * [fb123cc](https://github.com/flatiron/vows/commit/fb123cc) fix console require (`Jerry Sievert`) - * [bfb4bf5](https://github.com/flatiron/vows/commit/bfb4bf5) Use plus/minus unicode in error msg (`Trevor Norris`) - * [1e6eb0f](https://github.com/flatiron/vows/commit/1e6eb0f) Epsilon check fix (`Trevor Norris`) - * [3c0dc3b](https://github.com/flatiron/vows/commit/3c0dc3b) Add IEEE float epsilon check (`Trevor Norris`) - * [bfb8998](https://github.com/flatiron/vows/commit/bfb8998) Add Mocha credit. (`Reid Burke`) - * [cbd6123](https://github.com/flatiron/vows/commit/cbd6123) Add Mocha-style multi-line string diffs. (`Reid Burke`) - * [aa51288](https://github.com/flatiron/vows/commit/aa51288) Add \ to the HTML coverage report. (`Reid Burke`) - * [f7afb1b](https://github.com/flatiron/vows/commit/f7afb1b) Better style for directory names in coverage menu. (`Reid Burke`) - * [526f036](https://github.com/flatiron/vows/commit/526f036) Use Mocha's style for HTML coverage report. (`Reid Burke`) - * [93dbc61](https://github.com/flatiron/vows/commit/93dbc61) Summarize coverage data for HTML report. (`Reid Burke`) - * [abb0d5a](https://github.com/flatiron/vows/commit/abb0d5a) Implement TAP reporter (`execjosh`) - -v0.6.3 / Wed, 27 Jun 2012 -========================= - * [f0d2ecc](https://github.com/flatiron/vows/commit/f0d2ecc) [dist] Bump version to 0.6.3 (`Maciej Małecki`) - * [674830d](https://github.com/flatiron/vows/commit/674830d) [bin] Make isolate mode work in node >= 0.7 (`Maciej Małecki`) - * [075b0eb](https://github.com/flatiron/vows/commit/075b0eb) [minor] `Math.floor` instead of `Math.ceil` (`Maciej Małecki`) - * [796ac5d](https://github.com/flatiron/vows/commit/796ac5d) [bin] Add `--shuffle` option (`Maciej Małecki`) - * [4347cdd](https://github.com/flatiron/vows/commit/4347cdd) [fix] Fix unsafe object iterations (`Maciej Małecki`) - * [a785630](https://github.com/flatiron/vows/commit/a785630) Allow camelCase test filename (`Romain`) - * [03f60dd](https://github.com/flatiron/vows/commit/03f60dd) Add `assert.lengthOf` on objects (`Romain`) - * [38817c1](https://github.com/flatiron/vows/commit/38817c1) Exit code should be 1 if asynchronous errors occurs (`Olivier Bazoud`) - * [3e60864](https://github.com/flatiron/vows/commit/3e60864) [refactor] Don't touch `require.extensions` (`Maciej Małecki`) - -v0.6.2 / Fri, 24 Feb 2012 -========================= - * [6aa9673](https://github.com/flatiron/vows/commit/6aa9673) [dist] Version 0.6.2 (`Maciej Małecki`) - * [6b803ab](https://github.com/flatiron/vows/commit/6b803ab) [bin] Use `process.execPath` instead of `process.argv[0]` (`Maciej Małecki`) - * [1d06e90](https://github.com/flatiron/vows/commit/1d06e90) [api] Write XML coverage report to `coverage.xml` (`Maciej Małecki`) - * [9dd9b9e](https://github.com/flatiron/vows/commit/9dd9b9e) [bin] Skip dotfiles before `fs.stat()`ing them (`Nathan Hunzaker`) - * [4342fe9](https://github.com/flatiron/vows/commit/4342fe9) [ui] Add support for `\n` in context names (`jmreidy`) - * [bbc8e55](https://github.com/flatiron/vows/commit/bbc8e55) [api] Make `assert.include` fail when given unknown type (`Maciej Małecki`) - * [fe37eec](https://github.com/flatiron/vows/commit/fe37eec) [test] Add `.travis.yml` for testing on Travis CI (`Maciej Małecki`) - * [b2ca904](https://github.com/flatiron/vows/commit/b2ca904) Add coverage report in xml format. (`Cliffano Subagio`) - -v0.6.1 / Mon, 26 Dec 2011 -========================= - * [c84e55c](https://github.com/flatiron/vows/commit/c84e55c) [dist] Version 0.6.1 (`Maciej Małecki`) - * [239df60](https://github.com/flatiron/vows/commit/239df60) [test] Test if exception thrown in the topic gets passed down (`Bernardo Heynemann`) - * [6f84e3b](https://github.com/flatiron/vows/commit/6f84e3b) [api fix] When topic `throw`s, treat exception as a return value (`Maciej Małecki`) - * [722d4d8](https://github.com/flatiron/vows/commit/722d4d8) Documentation bug fix: Rename *length* to *lengthOf* in a test. (`Johnny Weng Luu`) - * [08b0650](https://github.com/flatiron/vows/commit/08b0650) [reporters/json] fix async error reporting (`Fedor Indutny`) - * [fbf7f69](https://github.com/flatiron/vows/commit/fbf7f69) [fix] Fix leaking `self` (`Maciej Małecki`) - * [9853e64](https://github.com/flatiron/vows/commit/9853e64) Async topic is passed to vows with topic-less subcontext (`seebees`) - -v0.6.0 / Fri, 25 Nov 2011 -========================= - * [82d5541](https://github.com/flatiron/vows/commit/82d5541) [dist] Version bump. 0.6.0 (`indexzero`) - * [3943fec](https://github.com/flatiron/vows/commit/3943fec) event order for 'on' (`seebees`) - * [d9fe353](https://github.com/flatiron/vows/commit/d9fe353) [minor] Update style from previous commit (`indexzero`) - * [e92c1e4](https://github.com/flatiron/vows/commit/e92c1e4) Added --no-color option to suppress terminal colors (`Alexander Shtuchkin`) - * [8788a52](https://github.com/flatiron/vows/commit/8788a52) [v0.6 fix] Properly inspect errors (`Maciej Małecki`) - * [6760a2e](https://github.com/flatiron/vows/commit/6760a2e) [merge] Manual merge of #135 since the fork no longer exists. Fixes #135 (`indexzero`) - * [ddd9588](https://github.com/flatiron/vows/commit/ddd9588) When an uncaught exception is caught in watch mode, print it in the console and continue watch. (`Julien Guimont`) - * [ddf3cf4](https://github.com/flatiron/vows/commit/ddf3cf4) [merge] add support for coffee files when printing out errors. Fixes #140 (`indexzero`) - * [1448de2](https://github.com/flatiron/vows/commit/1448de2) When called outside the vows context where `this.stack` && `source` are undefined it will now no longer crash and burn (`Raynos`) - * [c92aabc](https://github.com/flatiron/vows/commit/c92aabc) Expose console so we can re-use it in custom reporters. (`Raynos`) - * [c67786f](https://github.com/flatiron/vows/commit/c67786f) [merge] Manual merge of #95 since the fork no longer exists. Fixes #95 (`indexzero`) - * [81482b1](https://github.com/flatiron/vows/commit/81482b1) Fixed indentation and some missing semicolons requested in #82 (`Ryan Olds`) - * [f39a4e2](https://github.com/flatiron/vows/commit/f39a4e2) Add support for asynchronous teardowns. (`Daniel Brockman`) - * [a44ee69](https://github.com/flatiron/vows/commit/a44ee69) Edited README.md via GitHub (`Jerry Sievert`) - * [a781c45](https://github.com/flatiron/vows/commit/a781c45) events other then success (`seebees`) - * [d081d49](https://github.com/flatiron/vows/commit/d081d49) Buffer not needed and leaking a global. (`Nicolas Morel`) - * [482d09c](https://github.com/flatiron/vows/commit/482d09c) adding a filter to the watch logic, so that only test files are run (`jmreidy`) - * [f77e4bd](https://github.com/flatiron/vows/commit/f77e4bd) fixing regular expression for specFileExt to use an OR (`jmreidy`) - * [e7fbdb4](https://github.com/flatiron/vows/commit/e7fbdb4) test require should refer to lib/vows, not system vows (`jmreidy`) - * [907d308](https://github.com/flatiron/vows/commit/907d308) Adding vows support for underscores, in addition to dashes, in spec or test names (`jmreidy`) - -v0.5.13 / Wed, 2 Nov 2011 -========================= - * [a5912ba](https://github.com/flatiron/vows/commit/a5912ba) [dist] Version bump. 0.5.13 (`indexzero`) - * [7290532](https://github.com/flatiron/vows/commit/7290532) [fix] Fix failed assertions output (`Maciej Małecki`) - -v0.5.12 / Sat, 22 Oct 2011 -========================== - * [ef4a803](https://github.com/flatiron/vows/commit/ef4a803) [dist] Version bump. 0.5.12 (`indexzero`) - * [58f44f0](https://github.com/flatiron/vows/commit/58f44f0) [dist] Add test script for `npm test` (`indexzero`) - * [bd14209](https://github.com/flatiron/vows/commit/bd14209) [fix minor] Remove unnecessary argument in `exec` callback (`Maciej Małecki`) - * [00509bd](https://github.com/flatiron/vows/commit/00509bd) [test] Test `--supress-stdout` flag (`Maciej Małecki`) - * [8ce12a5](https://github.com/flatiron/vows/commit/8ce12a5) [test] Add fixtures for supress-stdout test (`Maciej Małecki`) - * [50052f5](https://github.com/flatiron/vows/commit/50052f5) [test v0.6] Make `assert-test.js` v0.6-compatible (`Maciej Małecki`) - * [fde1216](https://github.com/flatiron/vows/commit/fde1216) [refactor minor] Use `JSON.parse` when getting version (`Maciej Małecki`) - * [cc76162](https://github.com/flatiron/vows/commit/cc76162) [refactor minor] Remove unused variables in `vows.addVow.runTest` (`Maciej Małecki`) - * [006476f](https://github.com/flatiron/vows/commit/006476f) [v0.6] Handle stdout suppressing correctly (`Maciej Małecki`) - * [87462e6](https://github.com/flatiron/vows/commit/87462e6) [api] Rename `assert.length` to `assert.lengthOf` (`Maciej Małecki`) - * [fd44e08](https://github.com/flatiron/vows/commit/fd44e08) [fix v0.6] No `error.stack` for nextTick errors (`Maciej Małecki`) - * [eac4362](https://github.com/flatiron/vows/commit/eac4362) [refactor v0.6] Remove/replace `sys` usages (`Maciej Małecki`) - * [485698d](https://github.com/flatiron/vows/commit/485698d) (doc) add 'authors' section to README (`Alexis Sellier`) - -v0.5.11 / Sat, 20 Aug 2011 -========================== - * [3843409](https://github.com/flatiron/vows/commit/3843409) (dist) Version bump. 0.5.11 (`indexzero`) - * [954386c](https://github.com/flatiron/vows/commit/954386c) (test) Added tests for error pass thru (`indexzero`) - * [0108f1f](https://github.com/flatiron/vows/commit/0108f1f) Allow arguments to flow through to callbacks in error conditions. (`Ben Taber`) - * [3b9acac](https://github.com/flatiron/vows/commit/3b9acac) add unified coverage maps, and fix issue when using coverage without instrumentation (`Jerry Sievert`) - * [3a2f697](https://github.com/flatiron/vows/commit/3a2f697) add unified coverage maps, and fix issue when using coverage without instrumentation (`Jerry Sievert`) - * [5b2ae84](https://github.com/flatiron/vows/commit/5b2ae84) (fix) Check topic.constructor to reverse regression introduced by instanceof check (`indexzero`) - * [c7f9e3c](https://github.com/flatiron/vows/commit/c7f9e3c) added assert.isNotEmpty and assert.isDefined (`nekaab`) - -v0.5.10 / Fri, 12 Aug 2011 -========================== - * [484b5f4](https://github.com/flatiron/vows/commit/484b5f4) [fix] Update references to `stylize` after refactor (`indexzero`) - * [f18b45c](https://github.com/flatiron/vows/commit/f18b45c) (minor) Move .vowsText and .contextText out of reporters/spec into vows/console (`indexzero`) - * [a813268](https://github.com/flatiron/vows/commit/a813268) (fix) Remove unecessary reference to spec in reporters/dot-matrix.js. Fixes #117 (`indexzero`) - * [0d8c406](https://github.com/flatiron/vows/commit/0d8c406) [fix] Dont always append a tailing `\n` to all test output (`indexzero`) - * [67b7ce7](https://github.com/flatiron/vows/commit/67b7ce7) (minor) Update package.json (`indexzero`) - * [33aeb64](https://github.com/flatiron/vows/commit/33aeb64) (dist) Version bump. 0.5.10 (`indexzero`) - * [889b748](https://github.com/flatiron/vows/commit/889b748) [bin test] Added additional teardown test. Update bin/vows to support absolute path. #83 (`indexzero`) - * [c8ee815](https://github.com/flatiron/vows/commit/c8ee815) [style] respect cloudhead's style (`Fedor Indutny`) - * [dcf5021](https://github.com/flatiron/vows/commit/dcf5021) [isolate] fixed test fixtures naming (`Fedor Indutny`) - * [9be20ef](https://github.com/flatiron/vows/commit/9be20ef) [isolate] allow reporters to output raw data (`Fedor Indutny`) - * [5c40a46](https://github.com/flatiron/vows/commit/5c40a46) [isolate] tests (`Fedor Indutny`) - * [26fc3f7](https://github.com/flatiron/vows/commit/26fc3f7) [isolate] supress-stdout option and true stream usage in reporters (`Fedor Indutny`) - * [d53c429](https://github.com/flatiron/vows/commit/d53c429) [isolate] exec => spawn, stream suite output, fix command line arguments to child process (`Fedor Indutny`) - * [c2a1d60](https://github.com/flatiron/vows/commit/c2a1d60) [isolate] collect results (`Fedor Indutny`) - * [b275024](https://github.com/flatiron/vows/commit/b275024) [isolate] implement runner (`Fedor Indutny`) - * [3543c0e](https://github.com/flatiron/vows/commit/3543c0e) [isolate] added command line option (`Fedor Indutny`) - * [63a15e7](https://github.com/flatiron/vows/commit/63a15e7) Provide some very rudimentary CSS & JS to collapse the 'covered' source by default and use colours to draw your eye to the areas that need tackling (`ciaranj`) - * [96a17a2](https://github.com/flatiron/vows/commit/96a17a2) use instanceof to check if the return value from a topic is an EventEmitter (`seebees`) - * [3e98285](https://github.com/flatiron/vows/commit/3e98285) Test for change (`seebees`) - -v0.5.9 / Fri, 22 Jul 2011 -========================= - * [e80e96d](https://github.com/flatiron/vows/commit/e80e96d) (dist) version bump (`cloudhead`) - * [76e9175](https://github.com/flatiron/vows/commit/76e9175) add /bin folder to package.json (`cloudhead`) - * [d597378](https://github.com/flatiron/vows/commit/d597378) fix assert.inDelta global vars (`cloudhead`) - * [9418795](https://github.com/flatiron/vows/commit/9418795) remove `require.paths` dependency (`cloudhead`) - * [3d400b8](https://github.com/flatiron/vows/commit/3d400b8) adds coverage map functionality (`Jerry Sievert`) - * [bc868fa](https://github.com/flatiron/vows/commit/bc868fa) (new) added assert.inDelta (`mynyml`) - * [db608e2](https://github.com/flatiron/vows/commit/db608e2) NaN !== Boolean (`Joshua Kehn`) - * [4144271](https://github.com/flatiron/vows/commit/4144271) Implemented isBoolean and tests to match (`Joshua Kehn`) - * [342dbae](https://github.com/flatiron/vows/commit/342dbae) added assert.deepInclude (`mynyml`) - * [27f683a](https://github.com/flatiron/vows/commit/27f683a) added assert.deepInclude (`mynyml`) - -v0.5.8 / Sat, 12 Mar 2011 -========================= - * [7c9b21d](https://github.com/flatiron/vows/commit/7c9b21d) (dist) version bump (`Alexis Sellier`) - * [72b9299](https://github.com/flatiron/vows/commit/72b9299) (style) ws (`Alexis Sellier`) - * [381c0a3](https://github.com/flatiron/vows/commit/381c0a3) Fixed CoffeeScript support on Node 0.3+ (`Janne Hietamäki`) - * [697ada4](https://github.com/flatiron/vows/commit/697ada4) (minor test) cleanup (`Alexis Sellier`) - * [3291d77](https://github.com/flatiron/vows/commit/3291d77) fix vow context when global (`Alexis Sellier`) - -v0.5.7 / Sun, 20 Feb 2011 -========================= - * [f700eed](https://github.com/flatiron/vows/commit/f700eed) (dist) version bump (`Alexis Sellier`) - * [7b20446](https://github.com/flatiron/vows/commit/7b20446) support for this.callback.call({}, ...) (`Alexis Sellier`) - * [7874f54](https://github.com/flatiron/vows/commit/7874f54) improve async error report (`Alexis Sellier`) - * [332b522](https://github.com/flatiron/vows/commit/332b522) include test filename in some error reports (`Alexis Sellier`) - * [1ddf5b1](https://github.com/flatiron/vows/commit/1ddf5b1) (api) support for /.test.js$/ filenames (`Alexis Sellier`) - * [93da10b](https://github.com/flatiron/vows/commit/93da10b) (minor) cleanup (`cloudhead`) - * [402e309](https://github.com/flatiron/vows/commit/402e309) Fixed watch mode. (`Matteo Collina`) - -v0.5.6 / Mon, 31 Jan 2011 -========================= - * [0b54a98](https://github.com/flatiron/vows/commit/0b54a98) (dist) revert to node 0.2.6, version bump to 0.5.6 (`cloudhead`) - * [f1ff2c1](https://github.com/flatiron/vows/commit/f1ff2c1) preserve 0.2.6 compatibility (`cloudhead`) - * [d6ba141](https://github.com/flatiron/vows/commit/d6ba141) added simple xunit support, so vows can be used together with Hudson (`Anders Thøgersen`) - * [d88924d](https://github.com/flatiron/vows/commit/d88924d) (dist) update package.json to include node version (`cloudhead`) - * [a00c89d](https://github.com/flatiron/vows/commit/a00c89d) Updated teardown to execute after subcontexts complete (`Jeremiah Wuenschel`) - -v0.5.4 / Sat, 29 Jan 2011 -========================= - * [c2633dc](https://github.com/flatiron/vows/commit/c2633dc) (dist) version bump (`cloudhead`) - * [4361e42](https://github.com/flatiron/vows/commit/4361e42) use 'on' instead of 'addListener' (`cloudhead`) - * [eb4d50d](https://github.com/flatiron/vows/commit/eb4d50d) support '.' in filenames (`cloudhead`) - * [3030206](https://github.com/flatiron/vows/commit/3030206) (test) test for multiple arguments in callbacks (`cloudhead`) - * [1c18b66](https://github.com/flatiron/vows/commit/1c18b66) remove listeners warning on topics (`cloudhead`) - * [8fb1a56](https://github.com/flatiron/vows/commit/8fb1a56) support for multiple arguments passed to sub-topics (`cloudhead`) - * [398443d](https://github.com/flatiron/vows/commit/398443d) (minor) aliased export to exportTo (`cloudhead`) - * [3b1545a](https://github.com/flatiron/vows/commit/3b1545a) (bin) update for node 0.2.5 (`cloudhead`) - * [f0f823d](https://github.com/flatiron/vows/commit/f0f823d) (bin) fix auto-discover mode (`cloudhead`) - -v0.5.3 / Wed, 29 Dec 2010 -========================= - * [3d12553](https://github.com/flatiron/vows/commit/3d12553) (dist) version bump (`cloudhead`) - * [936e18a](https://github.com/flatiron/vows/commit/936e18a) fix some error messages (`cloudhead`) - * [64760fe](https://github.com/flatiron/vows/commit/64760fe) (bin) fix exit status (`cloudhead`) - -v0.5.2 / Wed, 13 Oct 2010 -========================= - * [349437b](https://github.com/flatiron/vows/commit/349437b) (dist) version bump (`cloudhead`) - * [61c01d9](https://github.com/flatiron/vows/commit/61c01d9) tell user if no tests were run. (`cloudhead`) - * [50077aa](https://github.com/flatiron/vows/commit/50077aa) Pass suite reference to batches (`Yurii Rashkovskii`) - * [213d6cd](https://github.com/flatiron/vows/commit/213d6cd) Made a change that eliminates the following bug (see http://github.com/cloudhead/vows/issues#issue/16): Sometimes you want to test an object that inherits from EventEmitter. In this case, if you return said testable object as the topic, then the code hangs if the EventEmitter subclass instance that I'm testing doesn't emit "success" or "error." (`bnoguchi`) - -v0.5.1 / Tue, 24 Aug 2010 -========================= - * [679e8a6](https://github.com/flatiron/vows/commit/679e8a6) (dist) version bump (`cloudhead`) - * [c3ad80d](https://github.com/flatiron/vows/commit/c3ad80d) (new) basic teardown support (`cloudhead`) - -v0.5.0 / Tue, 10 Aug 2010 -========================= - * [7cdf94f](https://github.com/flatiron/vows/commit/7cdf94f) (dist) version bump, update package.json (`cloudhead`) - * [e8cf93e](https://github.com/flatiron/vows/commit/e8cf93e) (minor) naming/style changes (`cloudhead`) - * [db57e70](https://github.com/flatiron/vows/commit/db57e70) Add ability to circumvent `addBatch` (`Travis Swicegood`) - * [36c5c47](https://github.com/flatiron/vows/commit/36c5c47) Add ability to run .coffee files (`Travis Swicegood`) - * [ccf6ec0](https://github.com/flatiron/vows/commit/ccf6ec0) (doc) fix link (`Alexis Sellier`) - -v0.4.6 / Thu, 1 Jul 2010 -======================== - * [d78e098](https://github.com/flatiron/vows/commit/d78e098) (dist) version bump (`cloudhead`) - * [a6c51c4](https://github.com/flatiron/vows/commit/a6c51c4) better assert.isNaN check (`cloudhead`) - * [2b7398e](https://github.com/flatiron/vows/commit/2b7398e) ability to pass suite options to export method (`cloudhead`) - * [4fc9097](https://github.com/flatiron/vows/commit/4fc9097) (new) --no-error (`cloudhead`) - * [f2eb7b2](https://github.com/flatiron/vows/commit/f2eb7b2) more refactoring in addVow (`cloudhead`) - * [cca54cf](https://github.com/flatiron/vows/commit/cca54cf) refactor counter updates (`cloudhead`) - * [c98bcc4](https://github.com/flatiron/vows/commit/c98bcc4) (doc) fix README (`Alexis Sellier`) - * [726b82f](https://github.com/flatiron/vows/commit/726b82f) updated README for site (`cloudhead`) - -v0.4.5 / Mon, 28 Jun 2010 -========================= - * [ed576d7](https://github.com/flatiron/vows/commit/ed576d7) (dist) version bump (`cloudhead`) - * [5cdc2ba](https://github.com/flatiron/vows/commit/5cdc2ba) (api) watch mode can take arguments, fixed a couple edge cases (`cloudhead`) - -v0.4.4 / Sun, 27 Jun 2010 -========================= - * [9ea324f](https://github.com/flatiron/vows/commit/9ea324f) (dist) version bump (`cloudhead`) - * [e0ffeea](https://github.com/flatiron/vows/commit/e0ffeea) fix --version (`cloudhead`) - * [afd3aab](https://github.com/flatiron/vows/commit/afd3aab) handle edge case in this.callback, where a single boolean is returned (`cloudhead`) - * [30e6688](https://github.com/flatiron/vows/commit/30e6688) don't exit until stdout is drained (`cloudhead`) - * [d1b71d8](https://github.com/flatiron/vows/commit/d1b71d8) (test) add an empty batch to make sure it works (`cloudhead`) - * [92aafed](https://github.com/flatiron/vows/commit/92aafed) improved error message when callback returns uncaught error (`cloudhead`) - * [93aeaa3](https://github.com/flatiron/vows/commit/93aeaa3) result of this.callback is passed down to nested topics (`cloudhead`) - * [ae16916](https://github.com/flatiron/vows/commit/ae16916) fixed a bug with falsy topics (`cloudhead`) - -v0.4.3 / Thu, 24 Jun 2010 -========================= - * [335a8ee](https://github.com/flatiron/vows/commit/335a8ee) (dist) version bump (`cloudhead`) - * [7875366](https://github.com/flatiron/vows/commit/7875366) return an appropriate exit code from bin/vows, depending on success of the tests. (`cloudhead`) - * [4e1da2f](https://github.com/flatiron/vows/commit/4e1da2f) allow this.callback to be used more flexibly (`cloudhead`) - -v0.4.2 / Wed, 23 Jun 2010 -========================= - * [3d83502](https://github.com/flatiron/vows/commit/3d83502) (dist) version bump (`cloudhead`) - * [b94c047](https://github.com/flatiron/vows/commit/b94c047) fixed watch mode in OS X Terminal (`cloudhead`) - * [a532f17](https://github.com/flatiron/vows/commit/a532f17) rename context.name => context.description, and make context.name be the last level only (`cloudhead`) - * [cd4a763](https://github.com/flatiron/vows/commit/cd4a763) remove throw/doesNotThrow message customization, cause it's fucked (`cloudhead`) - * [6298227](https://github.com/flatiron/vows/commit/6298227) (minor) fixed grammar in assertion message (`cloudhead`) - -v0.4.1 / Thu, 17 Jun 2010 -========================= - * [a2f11f0](https://github.com/flatiron/vows/commit/a2f11f0) (dist) version bump (`cloudhead`) - * [df248d4](https://github.com/flatiron/vows/commit/df248d4) include subject in error message (`cloudhead`) - * [cf3f4e2](https://github.com/flatiron/vows/commit/cf3f4e2) use suite's reporter for errors (`cloudhead`) - * [833a2a0](https://github.com/flatiron/vows/commit/833a2a0) console.result prints 'dropped' vows (`cloudhead`) - * [3d1217a](https://github.com/flatiron/vows/commit/3d1217a) detect un-fired vows on exit, and report error (`cloudhead`) - * [e1d1ea5](https://github.com/flatiron/vows/commit/e1d1ea5) track vows and vow statuses in batches (`cloudhead`) - * [8917efe](https://github.com/flatiron/vows/commit/8917efe) fix indentation in assert.equal error message (`cloudhead`) - * [31c46cf](https://github.com/flatiron/vows/commit/31c46cf) (dist) fix Makefile (`cloudhead`) - * [8ac48b9](https://github.com/flatiron/vows/commit/8ac48b9) rename some internal functions for consistency (`cloudhead`) - * [0acf40e](https://github.com/flatiron/vows/commit/0acf40e) update --help command (`cloudhead`) - * [3f3cc66](https://github.com/flatiron/vows/commit/3f3cc66) silent reporter (`cloudhead`) - * [692cb71](https://github.com/flatiron/vows/commit/692cb71) try to handle async errors more intelligently (`cloudhead`) - * [7ed9f65](https://github.com/flatiron/vows/commit/7ed9f65) (api) '-m' and '-r' now require a space between pattern (`cloudhead`) - * [82f6e5e](https://github.com/flatiron/vows/commit/82f6e5e) (new) added more options to bin (`cloudhead`) - * [75ff4ab](https://github.com/flatiron/vows/commit/75ff4ab) (api) addVows => addBatch (`cloudhead`) - * [a7f9f30](https://github.com/flatiron/vows/commit/a7f9f30) (test) improve test descriptions (`cloudhead`) - * [e53338c](https://github.com/flatiron/vows/commit/e53338c) (api) don't add space between context descriptions in some cases (`cloudhead`) - * [1593768](https://github.com/flatiron/vows/commit/1593768) (test) remove other-test.js (`cloudhead`) - * [f2ff9b5](https://github.com/flatiron/vows/commit/f2ff9b5) (test) move assert module tests to its own file (`cloudhead`) - * [5f415df](https://github.com/flatiron/vows/commit/5f415df) output function name in AssertionError, if {expected} is a function (`cloudhead`) - -v0.4.0 / Tue, 15 Jun 2010 -========================= - * [0b32f54](https://github.com/flatiron/vows/commit/0b32f54) (dist) version bump to 0.4.0 (`cloudhead`) - * [3e0fb87](https://github.com/flatiron/vows/commit/3e0fb87) improve subject appearance in spec.js (`cloudhead`) - * [29161c7](https://github.com/flatiron/vows/commit/29161c7) make sure we only output on exit, if there's a failure (`cloudhead`) - * [98418c7](https://github.com/flatiron/vows/commit/98418c7) set batch.status to 'end' when ended (`cloudhead`) - * [5a3362f](https://github.com/flatiron/vows/commit/5a3362f) catch silent async failures on exit (`cloudhead`) - * [6546552](https://github.com/flatiron/vows/commit/6546552) don't try to exist when tests complete (`cloudhead`) - * [7edb97a](https://github.com/flatiron/vows/commit/7edb97a) reset pending vows in Suite#reset (`cloudhead`) - * [6baca02](https://github.com/flatiron/vows/commit/6baca02) nicer output. refactor of formatters (`cloudhead`) - -v0.3.5 / Sun, 13 Jun 2010 -========================= - * [4a1a65a](https://github.com/flatiron/vows/commit/4a1a65a) (dist) version bump (`cloudhead`) - * [f10884d](https://github.com/flatiron/vows/commit/f10884d) improved assertion error messages. added tests (`cloudhead`) - * [72eecd7](https://github.com/flatiron/vows/commit/72eecd7) (new) added new assertions (`cloudhead`) - * [1e90188](https://github.com/flatiron/vows/commit/1e90188) set styles to false for inspector (`cloudhead`) - * [47c2d1f](https://github.com/flatiron/vows/commit/47c2d1f) (new) support multiple test suites per file (`cloudhead`) - * [bb9a5af](https://github.com/flatiron/vows/commit/bb9a5af) abort() function to exit with an error (`cloudhead`) - * [90e0bae](https://github.com/flatiron/vows/commit/90e0bae) (api) watch mode is activated with -w (`cloudhead`) - * [1cdfd1c](https://github.com/flatiron/vows/commit/1cdfd1c) don't output contexts for pending vows in watch mode (`cloudhead`) - * [3416f44](https://github.com/flatiron/vows/commit/3416f44) fix spec reporter + pending vow (`cloudhead`) - * [4b92fa4](https://github.com/flatiron/vows/commit/4b92fa4) (new api) '-m' matches a string, changes -R to -r (`cloudhead`) - -v0.3.4 / Wed, 9 Jun 2010 -======================== - * [25abf72](https://github.com/flatiron/vows/commit/25abf72) (dist) version bump (`cloudhead`) - * [8052146](https://github.com/flatiron/vows/commit/8052146) fix/improve the cleanup on exit (`cloudhead`) - * [df83078](https://github.com/flatiron/vows/commit/df83078) print a different cue when running tests in watch mode (`cloudhead`) - * [c533efa](https://github.com/flatiron/vows/commit/c533efa) fix context reporting for dot-matrix (`cloudhead`) - * [3e67750](https://github.com/flatiron/vows/commit/3e67750) remove deprecated 'brief' option (`cloudhead`) - * [11a1edd](https://github.com/flatiron/vows/commit/11a1edd) (new) tests can be 'pending' (`cloudhead`) - * [062450c](https://github.com/flatiron/vows/commit/062450c) handle this.callback called synchronously (`cloudhead`) - -v0.3.3 / Tue, 8 Jun 2010 -======================== - * [311df5f](https://github.com/flatiron/vows/commit/311df5f) (dist) version bump (`cloudhead`) - * [55a7a92](https://github.com/flatiron/vows/commit/55a7a92) print contexts in dot-matrix & watch output (`cloudhead`) - * [06b5563](https://github.com/flatiron/vows/commit/06b5563) (doc) updated README (`cloudhead`) - -v0.3.2 / Mon, 7 Jun 2010 -======================== - * [4079f57](https://github.com/flatiron/vows/commit/4079f57) (dist) version bump (`cloudhead`) - * [cca5d46](https://github.com/flatiron/vows/commit/cca5d46) move inspect() to vows/console (`cloudhead`) - -v0.3.1 / Mon, 7 Jun 2010 -======================== - * [fe7ae18](https://github.com/flatiron/vows/commit/fe7ae18) (dist) version bump (`cloudhead`) - * [a0dacb7](https://github.com/flatiron/vows/commit/a0dacb7) Set default for `options` in run(). (`cloudhead`) - * [e27bdfc](https://github.com/flatiron/vows/commit/e27bdfc) round time output (`cloudhead`) - -v0.3.0 / Sat, 5 Jun 2010 -======================== - * [868cd9f](https://github.com/flatiron/vows/commit/868cd9f) ability to print messages without a nl (`cloudhead`) - * [b851ffe](https://github.com/flatiron/vows/commit/b851ffe) only the spec reporter prints subjects (`cloudhead`) - * [d5b0d34](https://github.com/flatiron/vows/commit/d5b0d34) pattern matching is operational (`cloudhead`) - * [09e31cf](https://github.com/flatiron/vows/commit/09e31cf) better remaining vow detection and handling (`cloudhead`) - * [b3985d8](https://github.com/flatiron/vows/commit/b3985d8) we don't support vows as functions anymore (`cloudhead`) - * [a2e15a2](https://github.com/flatiron/vows/commit/a2e15a2) better vow counting (`cloudhead`) - * [7beb71d](https://github.com/flatiron/vows/commit/7beb71d) parse vows at run-time, so we can apply a matcher (`cloudhead`) - * [247015b](https://github.com/flatiron/vows/commit/247015b) use options in run() or default to Suite (`cloudhead`) - * [ee77415](https://github.com/flatiron/vows/commit/ee77415) Suite-level matcher/reporter (`cloudhead`) - * [aae87c2](https://github.com/flatiron/vows/commit/aae87c2) no more global module state (`cloudhead`) - * [f825f7f](https://github.com/flatiron/vows/commit/f825f7f) tidy up the requires in bin/vows (`cloudhead`) - * [b9d856e](https://github.com/flatiron/vows/commit/b9d856e) (dist) lib is lib/vows (`cloudhead`) - * [2f9bb00](https://github.com/flatiron/vows/commit/2f9bb00) (dist) added bin to package.json (`cloudhead`) - * [575d1a5](https://github.com/flatiron/vows/commit/575d1a5) updated Makefile to use test runner (`cloudhead`) - * [7d93078](https://github.com/flatiron/vows/commit/7d93078) (dist) version bump (`cloudhead`) - * [c3afbbc](https://github.com/flatiron/vows/commit/c3afbbc) revised vows.js header (`cloudhead`) - * [ec867b6](https://github.com/flatiron/vows/commit/ec867b6) output fixes (`cloudhead`) - * [1f2abe5](https://github.com/flatiron/vows/commit/1f2abe5) (new) watch reporter (`cloudhead`) - * [b9882a5](https://github.com/flatiron/vows/commit/b9882a5) add print() function to reporters (`cloudhead`) - * [151b76c](https://github.com/flatiron/vows/commit/151b76c) fuck the buffer (`cloudhead`) - * [1ab43bd](https://github.com/flatiron/vows/commit/1ab43bd) report subject on run() (`cloudhead`) - * [88b5ade](https://github.com/flatiron/vows/commit/88b5ade) complete rewrite of bin/vows (`cloudhead`) - * [af04a10](https://github.com/flatiron/vows/commit/af04a10) exported Suites also run automatically when file is run directly (`cloudhead`) - * [244cd01](https://github.com/flatiron/vows/commit/244cd01) reset Suite before running it, instead of after, so we don't upset the exit check (`cloudhead`) - * [7ce4579](https://github.com/flatiron/vows/commit/7ce4579) another test, just to test runner (`cloudhead`) - * [0e3b661](https://github.com/flatiron/vows/commit/0e3b661) ability to export batch/suite (`cloudhead`) - * [073e875](https://github.com/flatiron/vows/commit/073e875) ability to reset batch/suite (`cloudhead`) - * [bd8a4f8](https://github.com/flatiron/vows/commit/bd8a4f8) refactor reporters, share more. (`cloudhead`) - * [8cd49ba](https://github.com/flatiron/vows/commit/8cd49ba) 'reporter' option instead of boolean flags. Also pass subject to Suite. (`cloudhead`) - * [e2d1951](https://github.com/flatiron/vows/commit/e2d1951) bye bye addVow (`cloudhead`) - * [e5855a2](https://github.com/flatiron/vows/commit/e5855a2) fix dot-matrix reporter not reporting errors (`cloudhead`) - * [6fe14ec](https://github.com/flatiron/vows/commit/6fe14ec) suite.js init (`cloudhead`) - * [b9c0329](https://github.com/flatiron/vows/commit/b9c0329) Complete re-architecturing of vows. (`cloudhead`) - * [4adab80](https://github.com/flatiron/vows/commit/4adab80) dot-matrix is the default reporter (`cloudhead`) - * [e16cadf](https://github.com/flatiron/vows/commit/e16cadf) (dist) cleanup Makefile (`cloudhead`) - * [7200208](https://github.com/flatiron/vows/commit/7200208) moved vows.prepare to extras.js (`cloudhead`) - * [14278d0](https://github.com/flatiron/vows/commit/14278d0) cleaned up project structure a little (`cloudhead`) - * [fb7d8a9](https://github.com/flatiron/vows/commit/fb7d8a9) extracted console utils out of spec/dot-matrix reporters (`cloudhead`) - * [ba8c46e](https://github.com/flatiron/vows/commit/ba8c46e) (new) dot-matrix reporter (`cloudhead`) - -v0.2.5 / Mon, 24 May 2010 -========================= - * [0a53b70](https://github.com/flatiron/vows/commit/0a53b70) (dist) version bump (`cloudhead`) - * [ce73ecd](https://github.com/flatiron/vows/commit/ce73ecd) Cleaned up the inner loop a little (`cloudhead`) - * [9fa313c](https://github.com/flatiron/vows/commit/9fa313c) Fix incorrect binding in test functions. (`cloudhead`) - -v0.2.4 / Sun, 23 May 2010 -========================= - * [b10a30a](https://github.com/flatiron/vows/commit/b10a30a) (dist) version bump (`cloudhead`) - * [2f231b1](https://github.com/flatiron/vows/commit/2f231b1) (doc) updated README with assertion macros (`cloudhead`) - * [179f854](https://github.com/flatiron/vows/commit/179f854) (new) assert.instanceOf assert.isUndefined (`cloudhead`) - * [87afe4c](https://github.com/flatiron/vows/commit/87afe4c) don't complain about return value in topic if old (`cloudhead`) - -v0.2.3 / Sat, 22 May 2010 -========================= - * [f867791](https://github.com/flatiron/vows/commit/f867791) (dist) version bump (`cloudhead`) - * [cb9e66e](https://github.com/flatiron/vows/commit/cb9e66e) (new) added assert.isNull, and made isObject more robust (`cloudhead`) - * [cf459bc](https://github.com/flatiron/vows/commit/cf459bc) fixed inspector doing weird shit. (`cloudhead`) - -v0.2.2 / Sat, 22 May 2010 -========================= - * [5df28a5](https://github.com/flatiron/vows/commit/5df28a5) (dist) version bump (`cloudhead`) - * [c741f7b](https://github.com/flatiron/vows/commit/c741f7b) (minor doc) typo in README (`cloudhead`) - * [8092bb3](https://github.com/flatiron/vows/commit/8092bb3) throw error when this.callback with a return value (`cloudhead`) - * [70cf79e](https://github.com/flatiron/vows/commit/70cf79e) (minor) standardized error messages (`cloudhead`) - * [a214eb8](https://github.com/flatiron/vows/commit/a214eb8) (new) Support for callback-style async testing (`cloudhead`) - * [c600238](https://github.com/flatiron/vows/commit/c600238) (doc) new install instructions (`cloudhead`) - * [473e215](https://github.com/flatiron/vows/commit/473e215) (dist) fixed dependencies (`cloudhead`) - * [0083f0a](https://github.com/flatiron/vows/commit/0083f0a) (dist) version bump (`cloudhead`) - * [94a58be](https://github.com/flatiron/vows/commit/94a58be) (dist) updated paths and package.json (`cloudhead`) - * [03a4171](https://github.com/flatiron/vows/commit/03a4171) (new) test for NaN, and added assert.isNaN (`cloudhead`) - * [3f4bbec](https://github.com/flatiron/vows/commit/3f4bbec) throw Error if missing top-level context (`cloudhead`) - * [748e1ee](https://github.com/flatiron/vows/commit/748e1ee) added 'install' task (`cloudhead`) - * [babc2e6](https://github.com/flatiron/vows/commit/babc2e6) version bump to 0.2.0 (`cloudhead`) - -v0.2.0 / Mon, 17 May 2010 -========================= - * [fba631c](https://github.com/flatiron/vows/commit/fba631c) (minor) renamed statusText to status (`cloudhead`) - * [bf80bec](https://github.com/flatiron/vows/commit/bf80bec) time can equal 0, check more reliably (`cloudhead`) - * [98c70ad](https://github.com/flatiron/vows/commit/98c70ad) make console reporter a little more powerful (`cloudhead`) - * [1606341](https://github.com/flatiron/vows/commit/1606341) use json reporter if --json is passed (`cloudhead`) - * [8a1d447](https://github.com/flatiron/vows/commit/8a1d447) overhaul of continuous testing functionality, to use json backend (`cloudhead`) - * [cc041ee](https://github.com/flatiron/vows/commit/cc041ee) fix JSON reporter (`cloudhead`) - * [a604161](https://github.com/flatiron/vows/commit/a604161) renamed 'printer' -> 'reporter' (`cloudhead`) - * [dc9a746](https://github.com/flatiron/vows/commit/dc9a746) Decouple the reporting system. (`cloudhead`) - * [aba0f57](https://github.com/flatiron/vows/commit/aba0f57) updated SS (`Alexis Sellier`) - * [1882f19](https://github.com/flatiron/vows/commit/1882f19) (fix) topics getting added multiple times (`cloudhead`) - * [f59fb55](https://github.com/flatiron/vows/commit/f59fb55) version bump (`cloudhead`) - -v0.1.4 / Sun, 16 May 2010 -========================= - * [f887206](https://github.com/flatiron/vows/commit/f887206) (fix) output the subjects without need for nextTick (`cloudhead`) - * [1cb886c](https://github.com/flatiron/vows/commit/1cb886c) (fix) count vows properly, by skipping 'topic' keys (`cloudhead`) - * [6454351](https://github.com/flatiron/vows/commit/6454351) fixed bug with function returning topics (`cloudhead`) - * [053d7de](https://github.com/flatiron/vows/commit/053d7de) (test) topics returning functions (`cloudhead`) - * [28f23ca](https://github.com/flatiron/vows/commit/28f23ca) make sure result doesn't precede title (`cloudhead`) - * [219ea81](https://github.com/flatiron/vows/commit/219ea81) fix lastTopic not being set properly (`cloudhead`) - * [0cefa91](https://github.com/flatiron/vows/commit/0cefa91) version bump (`cloudhead`) - -v0.1.3 / Wed, 12 May 2010 -========================= - * [e97b946](https://github.com/flatiron/vows/commit/e97b946) pass emitted errors if test is expecting it (`cloudhead`) - * [d79b6d5](https://github.com/flatiron/vows/commit/d79b6d5) fixed assert.include on objects (`cloudhead`) - * [e43aa0e](https://github.com/flatiron/vows/commit/e43aa0e) added assert.length & assert.isFunction (`cloudhead`) - * [99eb7de](https://github.com/flatiron/vows/commit/99eb7de) improved emitter code in describe() (`cloudhead`) - * [8a4f76d](https://github.com/flatiron/vows/commit/8a4f76d) vows.describe is the default now (`cloudhead`) - -v0.1.2 / Tue, 11 May 2010 -========================= - * [06290ee](https://github.com/flatiron/vows/commit/06290ee) updated readme/comments to new API (`cloudhead`) - * [fee2e78](https://github.com/flatiron/vows/commit/fee2e78) version bump (`cloudhead`) - * [15648b1](https://github.com/flatiron/vows/commit/15648b1) 'end' takes some parameters (`cloudhead`) - * [a54c076](https://github.com/flatiron/vows/commit/a54c076) when passing a function, there is no promise, also print an nl (`cloudhead`) - * [4fc5b9c](https://github.com/flatiron/vows/commit/4fc5b9c) only count vows if passing an object to addVows() (`cloudhead`) - * [0dd8387](https://github.com/flatiron/vows/commit/0dd8387) tests. (`cloudhead`) - * [cb3ab7e](https://github.com/flatiron/vows/commit/cb3ab7e) don't require a topic at all (`cloudhead`) - * [57fa14b](https://github.com/flatiron/vows/commit/57fa14b) use 'end' as a completion event for test-suites (`cloudhead`) - * [68e147d](https://github.com/flatiron/vows/commit/68e147d) pass the test-suite promises to tryFinish() (`cloudhead`) - * [bfa2a26](https://github.com/flatiron/vows/commit/bfa2a26) keep track of the number of test suites (`cloudhead`) - * [f394e79](https://github.com/flatiron/vows/commit/f394e79) test for chained vows (`cloudhead`) - * [b7a65c0](https://github.com/flatiron/vows/commit/b7a65c0) vow counting is sync. emit success when local remaining == 0 (`cloudhead`) - * [b95d282](https://github.com/flatiron/vows/commit/b95d282) API change, ability to run serial test suites (`cloudhead`) - * [fa51949](https://github.com/flatiron/vows/commit/fa51949) allow nested contexts with no topics (`cloudhead`) - * [0b891d6](https://github.com/flatiron/vows/commit/0b891d6) topic/subject ref fix (`cloudhead`) - * [6e49a11](https://github.com/flatiron/vows/commit/6e49a11) write an error if an EventEmitter hasn't fired (`cloudhead`) - * [06485b8](https://github.com/flatiron/vows/commit/06485b8) added spinning wheel (`cloudhead`) - * [8260e38](https://github.com/flatiron/vows/commit/8260e38) updated READMe (`cloudhead`) - * [8a03c2a](https://github.com/flatiron/vows/commit/8a03c2a) 'setup' is now called 'topic' (`cloudhead`) - * [a7b5857](https://github.com/flatiron/vows/commit/a7b5857) allow non-function subjects (`cloudhead`) - * [11d2e8f](https://github.com/flatiron/vows/commit/11d2e8f) added isEmpty and typeOf assertion macros (`cloudhead`) - -v0.1.1 / Sun, 2 May 2010 -======================== - * [abadd5d](https://github.com/flatiron/vows/commit/abadd5d) updated eyes (`cloudhead`) - * [1198d46](https://github.com/flatiron/vows/commit/1198d46) evaluate everything within an 'environment', which is passed down (`cloudhead`) - * [531d4bf](https://github.com/flatiron/vows/commit/531d4bf) refactored escape code printing (`cloudhead`) - * [c1167bd](https://github.com/flatiron/vows/commit/c1167bd) package.json (`cloudhead`) - * [d15c538](https://github.com/flatiron/vows/commit/d15c538) rename makefile to Makefile (`cloudhead`) - * [333a7f2](https://github.com/flatiron/vows/commit/333a7f2) attempt to detect the name of the test folder (`cloudhead`) - * [3cfd5a5](https://github.com/flatiron/vows/commit/3cfd5a5) explicitly return vows.promise from test runner (`cloudhead`) - * [b78539e](https://github.com/flatiron/vows/commit/b78539e) allow access to Context object, from tests (`cloudhead`) - * [1348def](https://github.com/flatiron/vows/commit/1348def) describe is an alias of tell (`cloudhead`) - * [ba08ca3](https://github.com/flatiron/vows/commit/ba08ca3) use typeof instead of instanceof (`cloudhead`) - -v0.1.0 / Sat, 1 May 2010 -======================== - * [547d478](https://github.com/flatiron/vows/commit/547d478) forgot to remove some test code (`cloudhead`) - * [5bba9c3](https://github.com/flatiron/vows/commit/5bba9c3) default value for matcher (`cloudhead`) - * [1a64009](https://github.com/flatiron/vows/commit/1a64009) bin/vows, autotesting utility (`cloudhead`) - * [051bb40](https://github.com/flatiron/vows/commit/051bb40) formatting (`cloudhead`) - * [3db9c6a](https://github.com/flatiron/vows/commit/3db9c6a) the matcher is an option now. -R'match string' (`cloudhead`) - * [d4d7e3e](https://github.com/flatiron/vows/commit/d4d7e3e) the --brief option. Also fixed various buffering problems (`cloudhead`) - * [6d6c950](https://github.com/flatiron/vows/commit/6d6c950) changed spacing in test output (`cloudhead`) - * [8b2afda](https://github.com/flatiron/vows/commit/8b2afda) don't use a Vow object, just use Object.create() (`cloudhead`) - * [70ef3a6](https://github.com/flatiron/vows/commit/70ef3a6) whitespace (`cloudhead`) - * [1d14683](https://github.com/flatiron/vows/commit/1d14683) Buffer test output, return EventEmitter. (`cloudhead`) - * [50f76f8](https://github.com/flatiron/vows/commit/50f76f8) other repos should be submodules (`Matt Lyon`) - * [1b02c0a](https://github.com/flatiron/vows/commit/1b02c0a) bugfix: only add setup vals to context once (`Matt Lyon`) diff --git a/LICENSE b/LICENSE index d6456956..a1edd93b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,202 +1,20 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +Copyright (c) 2009 cloudhead + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..6bf89912 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +# +# Run all tests +# +test: + @@bin/vows test/* + +.PHONY: test install diff --git a/README.md b/README.md index a1cd56ad..bfa410e9 100644 --- a/README.md +++ b/README.md @@ -1,592 +1,65 @@ -# vows +Vows +==== -vows is a testing framework for NodeJS. +> Asynchronous BDD & continuous integration for node.js -## License +#### # - - Copyright 2016-2018 fuzzy.ai - - Copyright 2017 AJ Jordan +introduction +------------ +There are two reasons why we might want asynchronous testing. The first, and obvious reason is that node.js is asynchronous, and therefore our tests need to be. The second reason is to make test suites which target I/O libraries run much faster. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at +_Vows_ is an experiment in making this possible, while adding a minimum of overhead. - +synopsis +-------- -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. + var vows = require('vows'), + assert = require('assert'); -## Example + vows.describe('Deep Thought').addBatch({ + 'An instance of DeepThought': { + topic: new DeepThought, -```javascript - -var vows = require('vows'); - -// vows does not pollute the assert module namespace by default - -var assert = vows.assert; - -vows - .describe("My first vows test") - .addBatch({ - 'When we open a file': { - topic: function() { - fs.open("/tmp/fakefile", "w", this.callback); - }, - 'it works': function(err, fd) { - assert.ifError(err); - assert.isNumber(fd); - }, - teardown: function(fd) { - fs.close(fd, this.callback); - } - 'and we write to the file': { - topic: function(fd) { - fs.write(fd, "My dog has fleas\n", this.callback); - }, - 'it works': function(err, written, buffer) { - assert.ifError(err); - assert.greater(written, 0); - assert.isString(buffer); - } - } - } - }) - .run(); - -``` - -## Introduction - -### Requiring - -You require the module like any other module. - -### Assert macros - -vows provides its own suite of assert macros. To use them, you should use the -`assert` property from the `vows` module, like so: - -```javascript -var vows = require('vows'); -var assert = vows.assert; -``` - -### Data structures - -The basic way to use tests is to build really large hierarchical -objects with a particular well-defined form. - -### Batch - -For `vows`, the core concept is the test `batch`. A batch is an object that -consists of the following: - - - A `topic` function that generates values to be tested - - - One or more test functions, which accept the results of the `topic` and - use assert macros to validate the results - - - Zero or more sub-batches - - - An optional `teardown` function that cleans up any values generated by the - topic - -A batch can be either *synchronous* or *asynchronous*. For a synchronous batch, -the `topic` function just returns a value, and the test functions measure that -value: - -```javascript -let batch = { - "We get the answer": { - topic() { - return 6 * 7; - }, - "it equals 42": (err, answer) => { - assert.ifError(err); - assert.equal(answer, 42); - } - } -}; -``` - -For an asynchronous batch, the topic returns its results through the `callback` -property of `this`. `vows` knows that the callback will be used because the -result returned by the `topic` function is `undefined`. - -```javascript -let batch = { - "When we get the answer asynchronously": { - topic() { - setImmediate(() => { - this.callback(null, 6 * 7); - }); - return undefined; - }, - "it equals 42": (err, answer) => { - assert.ifError(err); - assert.equal(answer, 42); - } - } -}; -``` - -Alternately, a topic can return a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). -vows will resolve the returned Promise and call tests with the same -`(err, results)` format as with other types of call. - -```javascript -let batch = { - "When we get the answer": { - topic() { - return new Promise((resolve, reject) => { - fs.open("/tmp/testfile", "w", (err, fd) => { - if (err) { - reject(err); - } else { - resolve(fd); - } - }) - }); - }, - "it equals 42": (err, fd) => { - assert.ifError(err); - assert.isNumber(fd); - } - } -}; -``` - -Note that all test functions receive at least an `err` argument, and then one or -more arguments. Synchronous batches can only have one test argument; -asynchronous batches can have a lot. - -For backwards compatibility, it's possible to call `this.callback` synchronously -in your `topic`. vows will simply call `setImmediate` to call the callback -later. But that is a tricky and confusing way to write your tests, and you -should probably avoid it. - -A batch can also have sub-batches. These are just properties of the batch that -are also batch objects, with their own `topic`, tests, sub-batches, `teardown`, -etc. The argument to the topic will be the results of the parent batch, in -reverse order up the hierarchy. - -```javascript -let batch = { - "When we get the answer": { - topic() { - return 6 * 7; - }, - "it equals 42": (err, answer) => { - assert.ifError(err); - assert.isNumber(answer); - assert.equal(answer, 42); - }, - "and we ask a couple of questions": { - topic(answer) { - return [ - "What is six times seven?", - "How many roads must a person walk down?" - ]; - }, - "they look plausible": (err, questions) => { - assert.ifError(err); - assert.isString(question[0]); - assert.equal(question[0][question[0].length - 1], '?'); - assert.isString(question[1]); - assert.equal(question[1][question[1].length - 1], '?'); - }, - "and we compare the answer and the question": { - topic(questions, answer) { - setImmediate(() => { - this.callback(null, questions[0], questions[1], answer); - }); - return undefined; - }, - "they match up well": (err, question0, question1, answer) => { - assert.ifError(err); - // NB: you need to implement isAnswerTo yourself - assert(isAnswerTo(answer, question0)); - assert(isAnswerTo(answer, question1)); - } - } - } - } -}; -``` - -Note that if a batch's `topic` returns more than one value to its callback, they -will be provided *in order* for any sub-batches' `topic`, but hierarchically -*in reverse order*. This may be a little confusing. - -Note also that if an error occurs, in either the topic or the tests, the -sub-batches will not be run. - -The `teardown` method is called after all the tests and sub-batches have been -run. So, the order is something like this: - - - topic - - tests - - sub-batches (if there are no errors) - - teardown - -The `teardown` gets the non-error results of the `topic` as arguments. It's -useful for cleaning up things that the `topic` made a mess of. - -```javascript - -batch = { - 'When we open a file': { - topic: function() { - fs.open("/tmp/fakefile", "w", this.callback); - }, - 'it works': function(err, fd) { - assert.ifError(err); - assert.isNumber(fd); - }, - teardown: function(fd) { - fs.close(fd, this.callback); - } - } -}; - -``` - -`teardown` functions can also be synchronous or asynchronous, or they can return -a Promise. However, the results are ignored. - -```javascript -let batch = { - "When we get the answer": { - topic() { - return new Promise((resolve, reject) => { - fs.open("/tmp/testfile", "w", (err, fd) => { - if (err) { - reject(err); - } else { - resolve(fd); - } - }) - }); - }, - "it equals 42": (err, fd) => { - assert.ifError(err); - assert.isNumber(fd); - }, - teardown(fd) { - return new Promise((resolve, reject) => { - if (typeof(fd) != 'number') { - reject(new Error("File descriptor is not a number")); - } else { - fs.close(fd, (err) => { - if (err) { - reject(err); - } else { - resolve(); + 'should know the answer to the ultimate question of life': function (deepThought) { + assert.equal (deepThought.question('what is the answer to the universe?'), 42); } - }) } - }); - } - } -}; -``` - -Note that the teardown will be called regardless of whether errors happened or -not, so it's a good idea to check the arguments to make sure they're valid. - -Teardowns are called as soon as the batch finishes; this is different from how -vows.js works, but it is better. - -If you're using a version of node that can handle [async/await syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function), -(>= 7.10.1), you can use async functions in your topics and teardowns, which can -make your aysnchronous test code about as lovely and compact as can be. - -```javascript - -const fs = require('fs'); -const util = require('util'); - -// util.promisify is available in node > 8.0.0 - -const open = util.promisify(fs.open); -const close = util.promisify(fs.close); - -let batch = { - "When we get the answer": { - topic: async function () { - return await open("/tmp/testfile", "w"); - }, - "it equals 42": (err, fd) => { - assert.ifError(err); - assert.isNumber(fd); - }, - teardown: async function (fd) { - return await close(fd); - } - } -}; -``` - -### Suite - -Batches are organized into suites. You create a suite with the `describe` method -of `vows`. - -```javascript -const vows = require('vows'); - -let suite = vows.describe('A new suite'); -``` - -You can then add one or more batches to the suite using the `addBatch` method. - -```javascript -suite.addBatch(batch1); -suite.addBatch(batch2); -suite.addBatch(batch3); -``` - -Finally, you have two options to actually run the test suite. The first is the -aptly-named `run()` method, which runs all the tests and reports the results to -`stdout`. You can then run the script through node and you'll run all your -tests. - -Alternately, you can use the `export()` method, passing the current `module` as -an argument. This will change the `exports` property of the `module` to be the -`run()` method of the suite. In other words, the module will now export a single -function that runs the suite. - -The `vows` command-line tool can be used to run all your test modules that -use `export()`. - -```shell -./node_modules/.bin/vows test/*.js -``` - -All the suite methods are [chainable](https://en.wikipedia.org/wiki/Method_chaining). -The typical way to actually use this library, then, is to require vows, use the -`describe` method to create a suite, use `addBatch` to add one or more batches, -and then use `export(module)` or more rarely `run()` to run the suite. - -```javascript -const fs = require('fs'); -const vows = require('vows'); -let assert = vows.assert; - -vows.describe('Input/output tests') - .addBatch({ - 'When we open a file': { - topic: function() { - fs.open("/tmp/fakefile", "w", this.callback); - }, - 'it works': function(err, fd) { - assert.ifError(err); - assert.isNumber(fd); - }, - teardown: function(fd) { - fs.close(fd, this.callback); - } - } - }) - .export(module); -``` - -### CoffeeScript - -[CoffeeScript](http://coffeescript.org/) is a nice pre-processor for JavaScript. -If you write your test scripts in CoffeeScript, it's totally OK to run them with -the `vows` command-line tool, as-is. - -```shell -./node_modules/.bin/vows test/*.js test/*.coffee -``` - -`vows` uses the CoffeeScript package to load the test modules automatically. - -## Debugging - -[Test-driven development](https://en.wikipedia.org/wiki/Test-driven_development) -means roughly that write your tests *first*, then write the implementations, -then keep running the tests till they work. - -`vows` doesn't necessarily do a fantastic job at this, but it's a little -better, and it's definitely a goal. `vows` uses the -[debug](https://www.npmjs.com/package/debug) library to spoot out debug info to -stderr at run time. This can be very useful for looking at how the `vows` -module is running, and figuring out where errors are happening. - -To use it, define the `DEBUG` environment variable when running your tests: - -```shell -DEBUG=vows:* ./node_modules/.bin/vows mytest.js -``` - -Watch this space for more help in doing TDD with vows. - -## Compatibility - -This 1.x version is incompatible with previous 0.x versions of vows in a few -small ways. - - - vows 0.x will check the - [arity](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length) - of test methods and call the method different ways based on that arity. With - vows 1.x, tests will always take an error argument and then zero or - more result arguments. This should help preserve your sanity and make you - write more robust tests. - - - vows 0.x will automatically pollute the namespace of the `assert` module. - vows 1.x makes you use a property instead. - - - vows 0.x handle all teardowns at the same time, without waiting for - sub-batch teardowns to finish. vows 1.x handles teardowns when the batch is - finished, so you can do things like deleting created files in your sub-batch - teardowns, and deleting their directory in your main batch teardown, - and things will just work right. - -- vows 0.x treat a Promise returned from the topic just like any - other results. So test functions will receive the Promise as a results - argument. vows 1.x will resolve the Promise and pass the results to the - test instead. So, if your tests expect to receive a Promise passed - synchronously, you should change that. - -- vows 1.x does not pass `this.context` to the topic. - -- vows 1.x does not support many of the undocumented features of vows 0.x, - including `vows.prepare()`, `beforeSuite()`, `afterSuite()`, and - `vows.options`. - -- vows 1.x only provides a single, default reporter. - -- vows 1.x does not support command-line control of verbosity (`-v` or `-s`). - -- vows 1.x does not support the `-m` or `-r` command-line flags. - -- vows 0.x automatically runs any tests in the `test` or `spec` directory. - vows 1.x requires that you specify the tests you want to run. - -- vows 1.x does not support the `-i` (isolate) command-line flag. - -## assert - -The exposed `assert` module-ish object has a number of useful methods for doing -tests. - -The module exposes all the methods of the built-in -[assert](https://nodejs.org/api/assert.html) module. It also has the following -utility methods. Each will do a check and if the check fails, will throw a new -`AssertionError` with either the `message` argument as its message, or a -standard message for that macro. - -### assert.epsilon(eps, actual, expected, message) - -Checks that the number `actual` is within `eps` from `expected`. - -### assert.match(actual, expected, message) - -Checks that `actual` matches the regular expression `expected`. Note that -`actual` will be coerced to a string if it is not one already. - -`assert.matches` is a synonym. - -### assert.isTrue(actual, message) - -Checks that `actual` is `true` (not just truthy; `true`). - -### assert.isFalse(actual, message) - -Checks that `actual` is `false` (not just falsy; `false`). - -### assert.isZero(actual, message) - -Checks that `actual` is 0. - -### assert.isNotZero(actual, message) - -Checks that `actual` is not 0. - -### assert.greater(actual, expected, message) - -Checks that `actual` is strictly greater than `expected`. - -### assert.lesser(actual, expected, message) - -Checks that `actual` is strictly lesser than `expected`. - -### assert.inDelta(actual, expected, delta, message) - -Checks that `actual` is less than `delta` away from `expected`. It's a lot -like `assert.epsilon()`. - -### assert.include(actual, expected, message) - -Checks that `actual` contains `expected`. `assert.includes` is a synonym. - -### assert.notInclude(actual, expected, message) - -Checks that `actual` does not contain `expected`. `assert.notIncludes` is a -synonym. - -### assert.isEmpty(actual, message) - -Checks that `actual` is empty (an empty array or an object with no properties). - -### assert.isNotEmpty(actual, message) - -Checks that `actual` is not empty. - -### assert.isArray(actual, message) - -Checks that `actual` is an array. - -### assert.isObject(actual, message) - -Checks that `actual` is an object. - -### assert.isNumber(actual, message) - -Checks that `actual` is a number. - -### assert.isBoolean(actual, message) - -Checks that `actual` is a boolean (`true` or `false`). - -### assert.isNaN(actual, message) - -Checks that `actual` is `NaN`. - -### assert.isNull(actual, message) - -Checks that `actual` is `null`. - -### assert.isNotNull(actual, message) - -Checks that `actual` is not `null`. + }); -### assert.isUndefined(actual, message) +coverage reporting +------------------ +Code coverage reporting is available if _instrumented_ code is detected. Currently only _instrumentation_ via [node-jscoverage](https://github.com/visionmedia/node-jscoverage) is supported. When _instrumented_ code is detected and coverage reporting is enabled using any of the `--cover-plain`, `--cover-html`, or `--cover-json` options a code coverage map is generated. -Checks that `actual` is `undefined`. +### downloading and installing [node-jscoverage](https://github.com/visionmedia/node-jscoverage) +[node-jscoverage](https://github.com/visionmedia/node-jscoverage) is a binary package that needs to be compiled from source: -### assert.isDefined(actual, message) + $ git clone https://github.com/visionmedia/node-jscoverage.git + $ cd node-jscoverage/ + $ ./configure + checking for a BSD-compatible install... /usr/bin/install -c + checking whether build environment is sane... yes + [...] + $ make && sudo make install -Checks that `actual` is not `undefined`. +### instrumenting with jscoverage -### assert.isString(actual, message) + $ jscoverage myfile.js myfile-instrumented.js + +installation +------------ -Checks that `actual` is a string. + $ npm install vows -### assert.isFunction(actual, message) +documentation +------------- -Checks that `actual` is a function. +Head over to -### assert.typeOf(actual, expected, message) +authors +------- -Checks that `actual` is of type `expected`. +Alexis Sellier <>, Charlie Robbins, -### assert.instanceOf(actual, expected, message) +*...and many others* -Checks that `actual` is an object and an instance of `expected`. diff --git a/bin/vows b/bin/vows new file mode 100755 index 00000000..1e701e2e --- /dev/null +++ b/bin/vows @@ -0,0 +1,560 @@ +#!/usr/bin/env node + +var path = require('path'), + fs = require('fs'), + util = require('util'), + events = require('events'); + +// +// Attempt to load Coffee-Script. If it's not available, continue on our +// merry way, if it is available, set it up so we can include `*.coffee` +// scripts and start searching for them. +// +var fileExt, specFileExt; + +try { + var coffee = require('coffee-script'); + if (require.extensions) { + require.extensions['.coffee'] = function (module, filename) { + var content = coffee.compile(fs.readFileSync(filename, 'utf8')); + return module._compile(content, filename); + }; + } else { + require.registerExtension('.coffee', function (content) { return coffee.compile(content) }); + } + fileExt = /\.(js|coffee)$/; + specFileExt = /[.(-|_)](test|spec)\.(js|coffee)$/; +} catch (_) { + fileExt = /\.js$/; + specFileExt = /[.(-|_)](test|spec)\.js$/; +} + +var inspect = require('eyes').inspector({ + stream: null, + styles: { string: 'grey', regexp: 'grey' } +}); + +var vows = require('../lib/vows'); +var cutils = require('../lib/vows/console'); +var stylize = require('../lib/vows/console').stylize; +var _reporter = require('../lib/vows/reporters/dot-matrix'), reporter = { + name: _reporter.name +}; +var _coverage; + +var help = [ + "usage: vows [FILE, ...] [options]", + "", + "options:", + " -v, --verbose Enable verbose output", + " -w, --watch Watch mode", + " -s, --silent Don't report", + " -i, --isolate Run each test in it's own vows process", + " -m PATTERN Only run tests matching the PATTERN string", + " -r PATTERN Only run tests matching the PATTERN regexp", + " --json Use JSON reporter", + " --spec Use Spec reporter", + " --dot-matrix Use Dot-Matrix reporter", + " --xunit Use xUnit reporter", + " --cover-plain Print plain coverage map if detected", + " --cover-html Write coverage map to \"coverage.html\"", + " --cover-json Write unified coverage map to \"coverage.json\"", + " --cover-xml Write coverage map to \"coverage.xml\" in Emma xml", + " --no-color Don't use terminal colors", + " --version Show version", + " -h, --help You're staring at it" +].join('\n'); + +var options = { + reporter: reporter, + matcher: /.*/, + watch: false, + coverage: false, + isolate: false, + nocolor: !process.stdout.isTTY +}; + +var files = []; + +// Get rid of process runner +// ('node' in most cases) +var arg, args = [], argv = process.argv.slice(2); + +// Current directory index, +// and path of test folder. +var root, testFolder; + +// +// Parse command-line parameters +// +while (arg = argv.shift()) { + if (arg === __filename) { continue } + + if (arg[0] !== '-') { + args.push(arg); + } else { + arg = arg.match(/^--?(.+)/)[1]; + + if (arg[0] === 'r') { + options.matcher = new(RegExp)(argv.shift()); + } else if (arg[0] === 'm') { + options.matcher = (function (str) { // Create an escaped RegExp + var specials = '. * + ? | ( ) [ ] { } \\ ^ ? ! = : $'.split(' ').join('|\\'), + regex = new(RegExp)('(\\' + specials + ')', 'g'); + return new(RegExp)(str.replace(regex, '\\$1')); + })(argv.shift()); + } else if (arg in options) { + options[arg] = true; + } else { + switch (arg) { + case 'json': + _reporter = require('../lib/vows/reporters/json'); + break; + case 'spec': + _reporter = require('../lib/vows/reporters/spec'); + break; + case 'dot-matrix': + _reporter = require('../lib/vows/reporters/dot-matrix'); + break; + case 'silent': + case 's': + _reporter = require('../lib/vows/reporters/silent'); + break; + case 'xunit': + _reporter = require('../lib/vows/reporters/xunit'); + break; + case 'cover-plain': + options.coverage = true; + _coverage = require('../lib/vows/coverage/report-plain'); + break; + case 'cover-html': + options.coverage = true; + _coverage = require('../lib/vows/coverage/report-html'); + break; + case 'cover-json': + options.coverage = true; + _coverage = require('../lib/vows/coverage/report-json'); + break; + case 'cover-xml': + options.coverage = true; + _coverage = require('../lib/vows/coverage/report-xml'); + break; + case 'verbose': + case 'v': + options.verbose = true; + break; + case 'watch': + case 'w': + options.watch = true; + break; + case 'supress-stdout': + options.supressStdout = true; + break; + case 'isolate': + case 'i': + options.isolate = true; + break; + case 'no-color': + options.nocolor = true; + break; + case 'color': + options.nocolor = false; + break; + case 'no-error': + options.error = false; + break; + case 'version': + console.log('vows ' + vows.version); + process.exit(0); + case 'help': + case 'h': + console.log(help); + process.exit(0); + break; + } + } + } +} + +if (options.nocolor) { + cutils.nocolor = true; + inspect = require('eyes').inspector({ stream: null, styles: false }); +} + +if (options.supressStdout) { + _reporter.setStream && _reporter.setStream(process.stdout); + var devNullStream = fs.createWriteStream('/dev/null'); + process.__defineGetter__('stdout', function () { + return devNullStream; + }); +} + +if (options.watch) { + options.reporter = reporter = require('../lib/vows/reporters/watch'); +} + +msg('bin', 'argv', args); +msg('bin', 'options', { reporter: options.reporter.name, matcher: options.matcher }); + +if (args.length === 0 || options.watch) { + msg('bin', 'discovering', 'folder structure'); + root = fs.readdirSync('.'); + + if (root.indexOf('test') !== -1) { + testFolder = 'test'; + } else if (root.indexOf('spec') !== -1) { + testFolder = 'spec'; + } else { + abort("runner", "couldn't find test folder"); + } + msg('bin', 'discovered', "./" + testFolder); + if (args.length === 0) { + args = paths(testFolder).filter(function (f) { + return specFileExt.test(f); + }); + + if (options.watch) { + args = args.concat(paths('lib'), paths('src')); + } + } +} + +if (! options.watch) { + reporter.report = function (data, filename) { + switch (data[0]) { + case 'subject': + case 'vow': + case 'context': + case 'error': + _reporter.report(data, filename); + break; + case 'end': + (options.verbose || _reporter.name === 'json') && + _reporter.report(data); + break; + case 'finish': + options.verbose ? + _reporter.print('\n') + : + _reporter.print(' '); + break; + } + }; + reporter.reset = function () { _reporter.reset && _reporter.reset() }; + reporter.print = _reporter.print; + + files = args.map(function (a) { + return (!a.match(/^\//)) + ? path.join(process.cwd(), a.replace(fileExt, '')) + : a.replace(fileExt, ''); + }); + + runSuites(importSuites(files), function (results) { + var status = results.errored ? 2 : (results.broken ? 1 : 0); + + !options.verbose && _reporter.print('\n'); + msg('runner', 'finish'); + _reporter.report(['finish', results], { + write: function (str) { + util.print(str.replace(/^\n\n/, '\n')); + } + }); + try { + if (options.coverage === true && _$jscoverage !== undefined) { + _coverage.report(_$jscoverage); + } + } catch (err) { + // ignore the undefined jscoverage + } + if (process.stdout.write('')) { // Check if stdout is drained + process.exit(status); + } else { + process.stdout.on('drain', function () { + process.exit(status); + }); + } + }); +} else { + // + // Watch mode + // + (function () { + var pendulum = [ + '. ', '.. ', '... ', ' ...', + ' ..', ' .', ' .', ' ..', + '... ', '.. ', '. ' + ]; + var strobe = ['.', ' ']; + var status, + cue, + current = 0, + running = 0, + lastRun, + colors = ['32m', '33m', '31m'], + timer = setInterval(tick, 100); + process.on('uncaughtException', exception); + process.on('exit', cleanup); + process.on('SIGINT', function () { + process.exit(0); + }); + process.on('SIGQUIT', function () { + changed(); + }); + + cursorHide(); + + // Run every 100ms + function tick() { + if (running && (cue !== strobe)) { + cue = strobe, current = 0; + } else if (!running && (cue !== pendulum)) { + cue = pendulum, current = 0; + } + + eraseLine(); + lastRun && !running && esc(colors[status.errored ? 2 : (status.broken ? 1 : 0)]); + print(cue[current]); + + if (current == cue.length - 1) { current = -1 } + + current ++; + esc('39m'); + cursorRestore(); + } + + // + // Utility functions + // + function print(str) { util.print(str) } + function esc(str) { print("\x1b[" + str) } + function eraseLine() { esc("0K") } + function cursorRestore() { esc("0G") } + function cursorHide() { esc("?25l") } + function cursorShow() { esc("?25h") } + function cleanup() { eraseLine(), cursorShow(), clearInterval(timer), print('\n') } + function exception(err) { print(err.stack || err.message || JSON.stringify(err)), running = 0} + + // + // Get a matching test for a given file + // + function getMatchingTest(file, join) { + join || (join = '-'); + var testFile; + if (specFileExt.test(file)) { + testFile = path.join(testFolder, file); + } + else { + var root, extension; + _s = file.split('.'), root = _s[0], extension = _s[1]; + testFile = path.join(testFolder, root + join + testFolder + "." + extension); + } + + try { + fs.statSync(testFile); + } catch (e) { + if (join == '-') { + return getMatchingTest(file, '_'); + } + else { + msg('watcher', 'no equivalence found, running all tests.'); + testFile = null; + } + } + return testFile; + } + + // + // Called when a file has been modified. + // Run the matching tests and change the status. + // + function changed(file) { + status = { honored: 0, broken: 0, errored: 0, pending: 0 }; + + msg('watcher', 'detected change in', file); + + file = getMatchingTest(file); + + var files = (specFileExt.test(file) ? [file] : paths(testFolder)).map(function (p) { + return path.join(process.cwd(), p); + }).filter(function (p) { + return specFileExt.test(p); + }).map(function (p) { + var cache = require.main.moduleCache || require.cache; + if (cache[p]) { delete(cache[p]) } + return p; + }).map(function (p) { + return p.replace(fileExt, ''); + }); + + running ++; + + runSuites(importSuites(files), function (results) { + delete(results.time); + print(cutils.result(results).join('') + '\n\n'); + lastRun = new(Date); + status = results; + running --; + }); + } + + msg('watcher', 'watching', args); + + // + // Watch all relevant files, + // and call `changed()` on change. + // + args.forEach(function (p) { + fs.watchFile(p, function (current, previous) { + if (new(Date)(current.mtime).valueOf() === + new(Date)(previous.mtime).valueOf()) { return } + else { + changed(p); + } + }); + }); + })(); +} + +function runSuites(suites, callback) { + var results = { + honored: 0, + broken: 0, + errored: 0, + pending: 0, + total: 0, + time: 0 + }; + reporter.reset(); + + (function run(suites, callback) { + var suite = suites.shift(); + if (suite) { + msg('runner', "running", suite.subject + ' ', options.watch ? false : true); + suite.run(options, function (result) { + Object.keys(result).forEach(function (k) { + results[k] += result[k]; + }); + run(suites, callback); + }); + } else { + callback(results); + } + })(suites, callback); +} + +function importSuites(files) { + msg(options.watcher ? 'watcher' : 'runner', 'loading', files); + + var spawn = require('child_process').spawn; + + function cwdname(f) { + return f.replace(process.cwd() + '/', '') + '.js'; + } + + function wrapSpawn(f) { + f = cwdname(f); + return function (options, callback) { + var args = [process.argv[1], '--json', '--supress-stdout', f], + p = spawn(process.argv[0], args), + result; + + p.on('exit', function (code) { + callback( + !result ? + {errored: 1, total: 1} + : + result + ); + }); + + var buffer = []; + p.stdout.on('data', function (data) { + data = data.toString().split(/\n/g); + if (data.length == 1) { + buffer.push(data[0]); + } else { + data[0] = buffer.concat(data[0]).join(''); + buffer = [data.pop()]; + + data.forEach(function (data) { + if (data) { + data = JSON.parse(data); + if (data && data[0] === 'finish') { + result = data[1]; + } else { + reporter.report(data); + } + } + }); + } + }); + + p.stderr.pipe(process.stderr); + } + } + + return files.reduce(options.isolate ? function (suites, f) { + return suites.concat({ + run: wrapSpawn(f) + }); + } : function (suites, f) { + var obj = require(f); + return suites.concat(Object.keys(obj).map(function (s) { + obj[s]._filename = cwdname(f); + return obj[s]; + })); + }, []) +} + +// +// Recursively traverse a hierarchy, returning +// a list of all relevant .js files. +// +function paths(dir) { + var paths = []; + + try { fs.statSync(dir) } + catch (e) { return [] } + + (function traverse(dir, stack) { + stack.push(dir); + fs.readdirSync(stack.join('/')).forEach(function (file) { + // + // Skip dotfiles and `vendor` directory before `fs.stat()`ing them. + // Not doing so causes race conditions with Emacs buffer files + // (`.#filename.js`). + // + if (file[0] == '.' || file === 'vendor') { + return; + } + + var path = stack.concat([file]).join('/'), + stat = fs.statSync(path); + + if (stat.isFile() && fileExt.test(file)) { + paths.push(path); + } else if (stat.isDirectory()) { + traverse(file, stack); + } + }); + stack.pop(); + })(dir || '.', []); + + return paths; +} + +function msg(cmd, subject, str, p) { + if (options.verbose) { + util[p ? 'print' : 'puts']( stylize('vows ', 'green') + + stylize(cmd, 'bold') + + ' ' + subject + ' ' + + (str ? (typeof(str) === 'string' ? str : inspect(str)) : '') + ); + } +} + +function abort(cmd, str) { + console.log(stylize('vows ', 'red') + stylize(cmd, 'bold') + ' ' + str); + console.log(stylize('vows ', 'red') + stylize(cmd, 'bold') + ' exiting'); + process.exit(-1); +} diff --git a/bin/vows.js b/bin/vows.js deleted file mode 100644 index 69d949f2..00000000 --- a/bin/vows.js +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env node - -// vows.js -- command-line driver for vows test scripts -// -// Copyright 2016 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License") -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const path = require('path') - -const _ = require('lodash') -const async = require('async') -const debug = require('debug')('vows:command-line') - -// This registers a hook so that coffeescript modules can be loaded - -require('coffeescript/register') - -const argv = require('yargs') - .help('h') - .argv - -const cwd = process.cwd() - -let broken = 0 -let successes = 0 -let failures = 0 - -const runTestSuite = (testFileName, callback) => { - const testPath = path.join(cwd, testFileName) - const runner = require(testPath) - if (!_.isFunction(runner)) { - callback(new Error(`Path ${testFileName} does not return a function`)) - } else { - runner((err, suiteBroken, suiteSuccesses, suiteFailures) => { - if (err) { - callback(err) - } else if (!_.isNumber(suiteBroken)) { - callback(new Error(`suiteBroken for ${testFileName} should be a number, is ${suiteBroken}`)) - } else if (!_.isNumber(suiteSuccesses)) { - callback(new Error(`suiteSuccesses for ${testFileName} should be a number, is ${suiteSuccesses}`)) - } else if (!_.isNumber(suiteFailures)) { - callback(new Error(`suiteFailures for ${testFileName} should be a number, is ${suiteFailures}`)) - } else { - debug(`Finished suite ${testFileName}: ${suiteBroken}, ${suiteSuccesses}, ${suiteFailures}`) - broken += suiteBroken - successes += suiteSuccesses - failures += suiteFailures - callback(null) - } - }) - } -} - -async.eachSeries(argv._, runTestSuite, (err) => { - if (err) { - console.error(err) - } else { - console.log('SUMMARY') - console.log(`\tBroken:\t\t${broken}`) - console.log(`\tSuccesses:\t${successes}`) - console.log(`\tFailures:\t${failures}`) - if (broken > 0 || failures > 0) { - process.exit(1) - } else { - process.exit(0) - } - } -}) diff --git a/lib/assert.js b/lib/assert.js deleted file mode 100644 index bce18ddc..00000000 --- a/lib/assert.js +++ /dev/null @@ -1,150 +0,0 @@ -// assert.js -- extended asserts -// -// Copyright 2016 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License") -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const assert = require('assert') -const debug = require('debug')('vows:assert') -const _ = require('lodash') - -// This can't be an arrow function because of some weird stuff with `this`. -// If it is, then plain `assert()` doesn't work and you have to `assert.ok()` -const me = function () { - debug(arguments) - assert.apply(this, arguments) -} - -module.exports = me - -// Copy everything from assert module to this module - -_.assign(me, assert) - -// Extend this module with some extra utilities - -me.epsilon = function (eps, actual, expected, message) { - me.isNumber(eps) - me.isNumber(actual) - me.isNumber(expected) - return me.lesser(Math.abs(actual - expected), eps) -} - -me.match = function (actual, expected, message) { - assert(_.isRegExp(expected), `${expected} must be a regular expression`) - return assert(expected.test(actual), - message || `${actual} does not match ${expected}`) -} - -me.matches = me.match - -me.isTrue = (actual, message) => - assert(actual === true, message || 'Argument must be true') - -me.isFalse = (actual, message) => - assert(actual === false, message || 'Argument must be false') - -me.isZero = (actual, message) => - assert.equal(actual, 0, message || 'Argument must be zero') - -me.isNotZero = (actual, message) => - assert.notEqual(actual, 0, message || 'Argument must not be zero') - -me.greater = (actual, expected, message) => - assert(actual > expected, - message || `${actual} is not greater than ${expected}`) - -me.lesser = (actual, expected, message) => - assert(actual < expected, - message || `${actual} is not less than ${expected}`) - -me.inDelta = (actual, expected, delta, message) => - assert(Math.abs(actual - expected) <= delta, - message || `${actual} is not greater than ${expected}`) - -me.include = (actual, expected, message) => - assert(_.hasIn(actual, expected), - message || `${actual} does not contain ${expected}`) - -me.includes = me.include - -me.notInclude = (actual, expected, message) => - assert(!_.hasIn(actual, expected), - message || `${actual} contains ${expected}`) - -me.notIncludes = me.notInclude - -// FIXME: figure out include/deepInclude - -me.deepInclude = me.include - -me.deepIncludes = me.deepInclude - -me.isEmpty = (actual, message) => - assert(_.isEmpty(actual), message || `${actual} is not empty`) - -me.isNotEmpty = (actual, message) => - assert(!_.isEmpty(actual), message || `${actual} is empty`) - -me.lengthOf = function (actual, expected, message) { - assert(actual !== null) - me.include(actual, 'length') - return assert.equal(actual.length, expected, - `Length is ${actual.length} not ${expected}`) -} - -me.isArray = (actual, message) => - assert(_.isArray(actual), message || 'Argument is not an array') - -me.isObject = (actual, message) => - assert(_.isObject(actual), message || 'Argument must be an object') - -me.isNumber = (actual, message) => - assert(_.isNumber(actual), message || 'Argument must be a number') - -me.isBoolean = (actual, message) => - assert(_.isBoolean(actual), message || 'Argument must be a boolean') - -me.isNaN = (actual, message) => - assert(_.isNaN(actual), message || 'Argument must be NaN') - -me.isNull = (actual, message) => - assert(_.isNull(actual), message || 'Argument must be null') - -me.isNotNull = (actual, message) => - assert(!_.isNull(actual), message || 'Argument must not be null') - -me.isUndefined = (actual, message) => - assert(_.isUndefined(actual), message || 'Argument must be undefined') - -me.isDefined = (actual, message) => - assert(!_.isUndefined(actual), message || 'Argument must be defined') - -me.isString = (actual, message) => - assert(_.isString(actual), message || 'Argument must be a string') - -me.isFunction = (actual, message) => - assert(_.isFunction(actual), message || 'Argument must be a function') - -me.typeOf = (actual, expected, message) => - // eslint-disable-next-line valid-typeof - assert(typeof (actual) === expected, - message || `Argument is not of type ${expected}`) - -me.instanceOf = (actual, expected, message) => - assert(actual instanceof expected, - message || `Argument is not an instance of ${expected}`) diff --git a/lib/assert/error.js b/lib/assert/error.js new file mode 100644 index 00000000..3f52271d --- /dev/null +++ b/lib/assert/error.js @@ -0,0 +1,42 @@ +var stylize = require('../vows/console').stylize; +var inspect = require('../vows/console').inspect; + +require('assert').AssertionError.prototype.toString = function () { + var that = this, + source; + + if (this.stack) { + source = this.stack.match(/([a-zA-Z0-9._-]+\.(?:js|coffee))(:\d+):\d+/); + } + + function parse(str) { + var actual = inspect(that.actual, {showHidden: that.actual instanceof Error}), + expected; + + if (that.expected instanceof Function) { + expected = that.expected.name; + } + else { + expected = inspect(that.expected, {showHidden: that.actual instanceof Error}); + } + + return str.replace(/{actual}/g, actual). + replace(/{operator}/g, stylize(that.operator, 'bold')). + replace(/{expected}/g, expected); + } + + if (this.message) { + var msg = stylize(parse(this.message), 'yellow'); + if (source) { + msg += stylize(' // ' + source[1] + source[2], 'grey'); + } + return msg; + } else { + return stylize([ + this.expected, + this.operator, + this.actual + ].join(' '), 'yellow'); + } +}; + diff --git a/lib/assert/macros.js b/lib/assert/macros.js new file mode 100644 index 00000000..154aa143 --- /dev/null +++ b/lib/assert/macros.js @@ -0,0 +1,215 @@ +var assert = require('assert'), + utils = require('./utils'); + +var messages = { + 'equal' : "expected {expected},\n\tgot\t {actual} ({operator})", + 'notEqual' : "didn't expect {actual} ({operator})" +}; +messages['strictEqual'] = messages['deepEqual'] = messages['equal']; +messages['notStrictEqual'] = messages['notDeepEqual'] = messages['notEqual']; + +for (var key in messages) { + assert[key] = (function (key, callback) { + return function (actual, expected, message) { + callback(actual, expected, message || messages[key]); + }; + })(key, assert[key]); +} + +assert.ok = (function (callback) { + return function (actual, message) { + callback(actual, message || "expected expression to evaluate to {expected}, but was {actual}"); + }; +})(assert.ok); + +assert.match = function (actual, expected, message) { + if (! expected.test(actual)) { + assert.fail(actual, expected, message || "expected {actual} to match {expected}", "match", assert.match); + } +}; +assert.matches = assert.match; + +assert.isTrue = function (actual, message) { + if (actual !== true) { + assert.fail(actual, true, message || "expected {expected}, got {actual}", "===", assert.isTrue); + } +}; +assert.isFalse = function (actual, message) { + if (actual !== false) { + assert.fail(actual, false, message || "expected {expected}, got {actual}", "===", assert.isFalse); + } +}; +assert.isZero = function (actual, message) { + if (actual !== 0) { + assert.fail(actual, 0, message || "expected {expected}, got {actual}", "===", assert.isZero); + } +}; +assert.isNotZero = function (actual, message) { + if (actual === 0) { + assert.fail(actual, 0, message || "expected non-zero value, got {actual}", "===", assert.isNotZero); + } +}; + +assert.greater = function (actual, expected, message) { + if (actual <= expected) { + assert.fail(actual, expected, message || "expected {actual} to be greater than {expected}", ">", assert.greater); + } +}; +assert.lesser = function (actual, expected, message) { + if (actual >= expected) { + assert.fail(actual, expected, message || "expected {actual} to be lesser than {expected}", "<", assert.lesser); + } +}; + +assert.inDelta = function (actual, expected, delta, message) { + var lower = expected - delta; + var upper = expected + delta; + if (actual < lower || actual > upper) { + assert.fail(actual, expected, message || "expected {actual} to be in within *" + delta.toString() + "* of {expected}", null, assert.inDelta); + } +}; + +// +// Inclusion +// +assert.include = function (actual, expected, message) { + if ((function (obj) { + if (isArray(obj) || isString(obj)) { + return obj.indexOf(expected) === -1; + } else if (isObject(actual)) { + return ! obj.hasOwnProperty(expected); + } + return true; + })(actual)) { + assert.fail(actual, expected, message || "expected {actual} to include {expected}", "include", assert.include); + } +}; +assert.includes = assert.include; + +assert.deepInclude = function (actual, expected, message) { + if (!isArray(actual)) { + return assert.include(actual, expected, message); + } + if (!actual.some(function (item) { return utils.deepEqual(item, expected) })) { + assert.fail(actual, expected, message || "expected {actual} to include {expected}", "include", assert.deepInclude); + } +}; +assert.deepIncludes = assert.deepInclude; + +// +// Length +// +assert.isEmpty = function (actual, message) { + if ((isObject(actual) && Object.keys(actual).length > 0) || actual.length > 0) { + assert.fail(actual, 0, message || "expected {actual} to be empty", "length", assert.isEmpty); + } +}; +assert.isNotEmpty = function (actual, message) { + if ((isObject(actual) && Object.keys(actual).length === 0) || actual.length === 0) { + assert.fail(actual, 0, message || "expected {actual} to be not empty", "length", assert.isNotEmpty); + } +}; + +assert.lengthOf = function (actual, expected, message) { + if (actual.length !== expected) { + assert.fail(actual, expected, message || "expected {actual} to have {expected} element(s)", "length", assert.length); + } +}; + +// +// Type +// +assert.isArray = function (actual, message) { + assertTypeOf(actual, 'array', message || "expected {actual} to be an Array", assert.isArray); +}; +assert.isObject = function (actual, message) { + assertTypeOf(actual, 'object', message || "expected {actual} to be an Object", assert.isObject); +}; +assert.isNumber = function (actual, message) { + if (isNaN(actual)) { + assert.fail(actual, 'number', message || "expected {actual} to be of type {expected}", "isNaN", assert.isNumber); + } else { + assertTypeOf(actual, 'number', message || "expected {actual} to be a Number", assert.isNumber); + } +}; +assert.isBoolean = function (actual, message) { + if (actual !== true && actual !== false) { + assert.fail(actual, 'boolean', message || "expected {actual} to be a Boolean", "===", assert.isBoolean); + } +}; +assert.isNaN = function (actual, message) { + if (actual === actual) { + assert.fail(actual, 'NaN', message || "expected {actual} to be NaN", "===", assert.isNaN); + } +}; +assert.isNull = function (actual, message) { + if (actual !== null) { + assert.fail(actual, null, message || "expected {expected}, got {actual}", "===", assert.isNull); + } +}; +assert.isNotNull = function (actual, message) { + if (actual === null) { + assert.fail(actual, null, message || "expected non-null value, got {actual}", "===", assert.isNotNull); + } +}; +assert.isUndefined = function (actual, message) { + if (actual !== undefined) { + assert.fail(actual, undefined, message || "expected {actual} to be {expected}", "===", assert.isUndefined); + } +}; +assert.isDefined = function (actual, message) { + if(actual === undefined) { + assert.fail(actual, 0, message || "expected {actual} to be defined", "===", assert.isDefined); + } +}; +assert.isString = function (actual, message) { + assertTypeOf(actual, 'string', message || "expected {actual} to be a String", assert.isString); +}; +assert.isFunction = function (actual, message) { + assertTypeOf(actual, 'function', message || "expected {actual} to be a Function", assert.isFunction); +}; +assert.typeOf = function (actual, expected, message) { + assertTypeOf(actual, expected, message, assert.typeOf); +}; +assert.instanceOf = function (actual, expected, message) { + if (! (actual instanceof expected)) { + assert.fail(actual, expected, message || "expected {actual} to be an instance of {expected}", "instanceof", assert.instanceOf); + } +}; + +// +// Utility functions +// + +function assertTypeOf(actual, expected, message, caller) { + if (typeOf(actual) !== expected) { + assert.fail(actual, expected, message || "expected {actual} to be of type {expected}", "typeOf", caller); + } +}; + +function isArray (obj) { + return Array.isArray(obj); +} + +function isString (obj) { + return typeof(obj) === 'string' || obj instanceof String; +} + +function isObject (obj) { + return typeof(obj) === 'object' && obj && !isArray(obj); +} + +// A better `typeof` +function typeOf(value) { + var s = typeof(value), + types = [Object, Array, String, RegExp, Number, Function, Boolean, Date]; + + if (s === 'object' || s === 'function') { + if (value) { + types.forEach(function (t) { + if (value instanceof t) { s = t.name.toLowerCase() } + }); + } else { s = 'null' } + } + return s; +} diff --git a/lib/assert/utils.js b/lib/assert/utils.js new file mode 100644 index 00000000..dccd0f65 --- /dev/null +++ b/lib/assert/utils.js @@ -0,0 +1,77 @@ + +// Taken from node/lib/assert.js +exports.deepEqual = function (actual, expected) { + if (actual === expected) { + return true; + + } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { + if (actual.length != expected.length) return false; + + for (var i = 0; i < actual.length; i++) { + if (actual[i] !== expected[i]) return false; + } + return true; + + } else if (actual instanceof Date && expected instanceof Date) { + return actual.getTime() === expected.getTime(); + + } else if (typeof actual != 'object' && typeof expected != 'object') { + return actual == expected; + + } else { + return objEquiv(actual, expected); + } +} + +// Taken from node/lib/assert.js +exports.notDeepEqual = function (actual, expected, message) { + if (exports.deepEqual(actual, expected)) { + fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); + } +} + +// Taken from node/lib/assert.js +function isUndefinedOrNull(value) { + return value === null || value === undefined; +} + +// Taken from node/lib/assert.js +function isArguments(object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; +} + +// Taken from node/lib/assert.js +function objEquiv(a, b) { + if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) + return false; + if (a.prototype !== b.prototype) return false; + if (isArguments(a)) { + if (!isArguments(b)) { + return false; + } + a = pSlice.call(a); + b = pSlice.call(b); + return exports.deepEqual(a, b); + } + try { + var ka = Object.keys(a), + kb = Object.keys(b), + key, i; + } catch (e) { + return false; + } + if (ka.length != kb.length) + return false; + ka.sort(); + kb.sort(); + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!exports.deepEqual(a[key], b[key])) return false; + } + return true; +} + diff --git a/lib/at-most-once.js b/lib/at-most-once.js deleted file mode 100644 index e6f98be5..00000000 --- a/lib/at-most-once.js +++ /dev/null @@ -1,55 +0,0 @@ -// at-most-once.js -- run a function at most once -// -// Copyright 2016 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const debug = require('debug')('vows:at-most-once') - -const assert = require('./assert') - -class AtMostOnceError extends Error { - constructor (name, called) { - const message = `${name} wrapper called ${called} times!` - super(message) - this.message = message - this.functionName = name - this.called = called - this.name = 'AtMostOnceError' - } -} - -const atMostOnce = function (fn) { - let called = 0 - assert.isFunction(fn) - const name = (fn.name) ? `${fn.name}()` : '' - debug(`Creating atMostOnce() wrapper for ${name}`) - const wrapper = function () { - const args = Array.prototype.slice.call(arguments) - called += 1 - if (called === 1) { - debug(`First call of atMostOnce() wrapper of ${name}`) - return fn.apply(null, args) - } else { - debug(`call number ${called} of atMostOnce() wrapper of ${name}`) - throw new AtMostOnceError(name, called) - } - } - return wrapper -} - -module.exports = atMostOnce diff --git a/lib/batch.js b/lib/batch.js deleted file mode 100644 index 9816ac28..00000000 --- a/lib/batch.js +++ /dev/null @@ -1,339 +0,0 @@ -// batch.js -- A batch of tests for vows -// -// Copyright 2016 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const _ = require('lodash') -const async = require('async') -const debug = require('debug')('vows:batch') - -const assert = require('./assert') -const atMostOnce = require('./at-most-once') -const Report = require('./report') - -class Batch { - constructor (title, definition) { - this.title = title - assert.isString(this.title, 'Batch title must be a string') - assert.isObject(definition, 'Batch definition must be an object') - - debug(`Batch constructor with title '${this.title}'`) - debug(`Definition for '${this.title}' has ${_.keys(definition).length} keys`) - - this.topic = null - this.teardown = null - this.tests = {} - this.batches = {} - - for (const name in definition) { - const value = definition[name] - assert.isString(name, - `keys of definition must be strings, not '${name}'`) - - if (name === 'topic') { - assert.ok(!_.isNil(value), 'topic must be defined and not null') - debug(`Adding topic to '${this.title}'`) - if (_.isFunction(value)) { - this.topic = value - } else { - this.topic = () => { - return value - } - } - } else if (name === 'teardown') { - debug(`Adding teardown to '${this.title}'`) - assert.isFunction(value, - `'teardown' of '${this.title}' must be a function`) - this.teardown = value - } else if (_.isFunction(value)) { - debug(`Adding test '${name}' to '${this.title}'`) - this.tests[name] = value - } else if (_.isObject(value)) { - debug(`Adding batch '${name}' to '${this.title}'`) - this.batches[name] = new Batch(`${this.title} ${name}`, value) - } else { - throw new Error(`Unexpected value '${value}' for key '${name}'`) - } - } - - assert.isFunction(this.topic, `Batch '${this.title}' has no topic`) - - assert(_.size(this.tests) > 0 || _.size(this.batches) > 0, - `Batch '${this.title}' has no sub-batches or tests`) - - debug(`Batch '${this.title}' has ${_.size(this.tests)} tests`) - debug(`Batch '${this.title}' has ${_.size(this.batches)} batches`) - - if (this.teardown !== null) { - debug(`Batch '${this.title}' has a teardown`) - } else { - debug(`Batch '${this.title}' has no teardown`) - } - } - - run (args, callback) { - assert.isArray(args, 'Args to Batch::run() must be an array') - assert.isFunction(callback, 'Callback for Batch::run() must be function') - - debug(`Beginning run of batch '${this.title}'`) - - this.report = new Report(this.title) - - debug('Creating callback') - - const next = this.onTopicComplete(args, callback) - - let results = null - - // It's weird to call this.callback() synchronously, but we - // allow it. If it's called while the topic is running, - // we just call setImmediate() to do it "later". - - let sync = null - const title = this.title - - const thisCallback = function () { - const args = Array.prototype.slice.call(arguments) - if (sync) { - debug(`this.callback called synchronously from topic '${title}'`) - setImmediate(() => { - debug(`this.callback of topic '${title}' activated after setImmediate()`) - next.apply(null, args) - }) - } else { - debug(`this.callback called asynchronously from topic '${title}'`) - next.apply(null, args) - } - } - - debug(`Beginning topic of batch '${this.title}'`) - - try { - sync = true - results = this.topic.apply({ callback: thisCallback }, args) - sync = false - } catch (err) { - sync = false - debug(`Error running topic of batch '${this.title}'`) - return next(err) - } - - debug(`Completed topic of batch '${this.title}'`) - - if (_.isUndefined(results)) { - debug(`Results of topic of batch '${this.title}' undefined; running async`) - } else if (!_.isUndefined(Promise) && (results instanceof Promise)) { - debug(`Results of topic of batch '${this.title}' defined and is a Promise; resolving`) - results - .then(function () { - debug(arguments.length) - const args = Array.prototype.slice.call(arguments) - debug(`Resolved Promise returned by topic with ${args.length} arguments`) - debug(args) - // We pass along a null in zero position for the error value - next.apply(null, _.concat([null], args)) - }) - .catch((err) => { - next(err) - }) - } else { - debug(`Results of topic of batch '${this.title}' defined and not a Promise; running sync`) - next(null, results) - } - - return undefined - } - - onTopicComplete (args, callback) { - return atMostOnce(function () { - const calledWith = Array.prototype.slice.call(arguments) - const err = calledWith[0] - const results = calledWith.slice(1) - - debug(`Results for topic of '${this.title}': ${err}, ${results.join(', ')}`) - - this.runTests(err, results) - this.report.successes = _.keys(this.tests).length - this.report.failures - - assert.ok(_.isFinite(this.report.failures), `failures must be a finite number, not ${this.report.failures}`) - assert.ok(_.isFinite(this.report.successes), `successes must be a finite number, not ${this.report.successes}`) - assert.equal(this.report.successes + this.report.failures, _.keys(this.tests).length, 'failures + successes != number of tests') - - if (err) { - this.report.broken = 1 - debug(`Error ${err} from topic; skipping batches for '${this.title}'`) - this.runTeardown(results, callback) - } else if (this.report.failures > 0) { - debug(`${this.report.failures} failures; skipping batches for '${this.title}'`) - this.runTeardown(results, callback) - } else { - debug(`${this.report.failures} failures; running batches for '${this.title}'`) - this.runSubBatches(args, results, (err) => { - if (err) { - debug(`runSubBatches for '${this.title}' returned error '${err}'`) - - this.runTeardown(results, callback) - } else { - debug(`runSubBatches for '${this.title}' complete`) - - this.runTeardown(results, callback) - } - }) - } - - return undefined - }.bind(this)) - } - - runTeardown (topicResults, callback) { - const next = this.onTeardownComplete(callback) - - if (this.teardown !== null) { - debug(`Running teardown for '${this.title}'`) - - try { - const tdres = this.teardown.apply({ callback: next }, topicResults) - if (_.isUndefined(tdres)) { - return debug(`Results of teardown for '${this.title}' are undef; running async`) - } else if (!_.isUndefined(Promise) && tdres instanceof Promise) { - debug(`Results of teardown for '${this.title}' are defined and a Promise; resolving`) - tdres - .then((realTdres) => { - next(null, realTdres) - }) - .catch((err) => { - next(err) - }) - } else { - debug(`Results of teardown for '${this.title}' are defined and not a Promise; running sync`) - return next(null, tdres) - } - } catch (err) { - debug(`Error thrown on teardown for '${this.title}': '${err}'`) - return next(err) - } - } else { - debug(`No teardown for '${this.title}'`) - - return next(null) - } - } - - onTeardownComplete (callback) { - return atMostOnce(function () { - const calledWith = Array.prototype.slice.call(arguments) - const err = calledWith[0] - const results = calledWith.slice(1) - - debug(`Teardown for '${this.title}' is complete`) - - if (err !== null) { - debug(`Teardown for '${this.title}' called with err '${err}'`) - } - - if ((results !== null) && results.length > 0) { - debug(`Teardown for '${this.title}' called with results '${results}'`) - } - - // Clear the report - - const report = this.report - this.report = null - - return callback(null, report) - }.bind(this)) - } - - runTests (err, results) { - debug(`Running ${_.size(this.tests)} tests for batch '${this.title}'`) - - if (_.size(this.tests) > 0) { - const args = _.concat([err], results) - - debug(`Passing args '${args.join(', ')}' to tests for batch '${this.title}'`) - - for (const name in this.tests) { - const test = this.tests[name] - assert.isString(name, `Name of test must be a string; '${name}'`) - assert.isFunction(test, 'Test is not a function') - - debug(`Running test '${name}' for '${this.title}'`) - - try { - test.apply(null, args) - assert.ok(_.isObject(this.report)) - assert.ok(_.isObject(this.report.tests)) - this.report.tests[name] = true - - debug(`Finished running test '${name}' for '${this.title}'`) - } catch (caught) { - debug(`Error running test '${name}' for '${this.title}'`) - - assert.ok(_.isObject(this.report)) - assert.ok(_.isObject(this.report.tests)) - this.report.tests[name] = `${caught.name}: ${caught.message}` - this.report.failures += 1 - } - } - } - } - - runSubBatches (args, results, callback) { - const batch = this - - assert.isArray(args, 'args for runSubBatches() must be an array') - assert.isArray(results, 'results for runSubBatches() must be an array') - assert.isFunction(callback, 'callback for runSubBatches() must be an array') - - debug(`Running ${_.size(this.batches)} batches for batch '${this.title}'`) - - if (_.size(this.batches) === 0) { - return callback(null) - } else { - const batchArgs = _.concat(_.clone(results), args) - - debug(`Passing args '${batchArgs.join(', ')}' to batches for '${this.title}'`) - - const runBatch = (sub, callback) => { - sub.run(batchArgs, (err, report) => { - if (err) { - debug(`Running sub-batch ${sub.title} resulted in an error`) - batch.report.addSub(sub.title, report) - callback(err) - } else { - debug(`Running sub-batch ${sub.title} succeeded`) - batch.report.addSub(sub.title, report) - callback(null) - } - }) - } - - return async.each(this.batches, runBatch, err => { - if (err) { - debug(`Running batches for '${this.title}' resulted in ${err}`) - callback(err) - } else { - debug(`Running batches for '${this.title}' succeeded`) - callback(null) - } - }) - } - } -} - -module.exports = Batch diff --git a/lib/index.js b/lib/index.js deleted file mode 100644 index 24c26b7e..00000000 --- a/lib/index.js +++ /dev/null @@ -1,33 +0,0 @@ -// index.js -- main module for vows -// -// Copyright 2016 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const debug = require('debug')('vows') - -const Suite = require('./suite') - -const describe = function (description) { - debug(`Creating new suite with description '${description}'`) - return new Suite(description) -} - -module.exports = { - describe, - assert: require('./assert') -} diff --git a/lib/report.js b/lib/report.js deleted file mode 100644 index 40defb3b..00000000 --- a/lib/report.js +++ /dev/null @@ -1,39 +0,0 @@ -// report.js -- Report of the results of a batch and its sub-batches -// -// Copyright 2017 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -class Report { - constructor (title) { - this.title = title - this.broken = 0 - this.successes = 0 - this.failures = 0 - this.tests = {} - this.subs = {} - } - - addSub (title, report) { - this.subs[title] = report - this.broken += report.broken - this.successes += report.successes - this.failures += report.failures - } -} - -module.exports = Report diff --git a/lib/suite.js b/lib/suite.js deleted file mode 100644 index 7bafd469..00000000 --- a/lib/suite.js +++ /dev/null @@ -1,129 +0,0 @@ -// suite.js -- a suite of batches of tests for vows -// -// Copyright 2016 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const _ = require('lodash') -const async = require('async') -const debug = require('debug')('vows:suite') - -const assert = require('./assert') -const Batch = require('./batch') - -class Suite { - constructor (description) { - this.run = this.run.bind(this) - this.description = description - assert.isString(this.description, 'Suite description must be a string') - - debug(`Suite constructor with description '${this.description}'`) - - this.batches = [] - } - - addBatch (obj) { - assert.isObject(obj, 'Argument to addBatch must be an Object') - assert.equal(_.keys(obj).length, 1, 'Argument to addBatch must have one key') - - const title = _.keys(obj)[0] - - debug(`Adding batch '${title}' to suite '${this.description}'`) - - const batch = new Batch(title, obj[title]) - - this.batches.push(batch) - - return this - } - - export (module) { - assert.isObject(module, 'Module is not an object') - - module.exports = this.run - - return this - } - - run (callback) { - let broken = 0 - let successes = 0 - let failures = 0 - const suite = this - - assert(_.isUndefined(callback) || _.isFunction(callback), - 'If defined callback must be a function') - - const runBatch = (batch, callback) => { - assert.isObject(batch, 'batch is not an object') - assert.instanceOf(batch, Batch, 'batch is not a Batch') - debug(`Running batch '${batch.title}' from suite '${this.description}'`) - batch.run([], (err, report) => { - if (err) { - callback(err) - } else { - debug(`Batch ${batch.title} complete`) - - broken += report.broken - successes += report.successes - failures += report.failures - - suite.showReport(report) - - callback(null) - } - }) - } - - debug(`Running ${_.size(this.batches)} batches for suite '${this.description}'`) - - console.log() - console.log(this.description) - console.log() - - async.eachSeries(this.batches, runBatch, (err) => { - if (err) { - console.error(err) - } - - console.log() - - if (_.isFunction(callback)) { - return callback(null, broken, successes, failures) - } - }) - - return this - } - - showReport (report) { - const suite = this - console.log(report.title) - _.each(report.tests, (value, name) => { - if (_.isString(value)) { - console.log(` ${name}: ${value}`) - } else { - console.log(` ${name}: OK`) - } - }) - _.each(report.subs, (subReport) => { - suite.showReport(subReport) - }) - } -} - -module.exports = Suite diff --git a/lib/vows.js b/lib/vows.js new file mode 100644 index 00000000..363f96f2 --- /dev/null +++ b/lib/vows.js @@ -0,0 +1,255 @@ +// +// Vows.js - asynchronous event-based BDD for node.js +// +// usage: +// +// var vows = require('vows'); +// +// vows.describe('Deep Thought').addBatch({ +// "An instance of DeepThought": { +// topic: new DeepThought, +// +// "should know the answer to the ultimate question of life": function (deepThought) { +// assert.equal (deepThought.question('what is the answer to the universe?'), 42); +// } +// } +// }).run(); +// +var util = require('util'), + path = require('path'), + events = require('events'), + vows = exports; + +// Options +vows.options = { + Emitter: events.EventEmitter, + reporter: require('./vows/reporters/dot-matrix'), + matcher: /.*/, + error: true // Handle "error" event +}; + +vows.__defineGetter__('reporter', function () { + return vows.options.reporter; +}); + +var stylize = require('./vows/console').stylize; +var console = vows.console = require('./vows/console'); + +vows.inspect = require('./vows/console').inspect; +vows.prepare = require('./vows/extras').prepare; +vows.tryEnd = require('./vows/suite').tryEnd; + +// +// Assertion Macros & Extensions +// +require('./assert/error'); +require('./assert/macros'); + +// +// Suite constructor +// +var Suite = require('./vows/suite').Suite; + +// +// This function gets added to events.EventEmitter.prototype, by default. +// It's essentially a wrapper around `on`, which adds all the specification +// goodness. +// +function addVow(vow) { + var batch = vow.batch, + event = vow.binding.context.event || 'success', + self = this; + + batch.total ++; + batch.vows.push(vow); + + // always set a listener on the event + this.on(event, function () { + var args = Array.prototype.slice.call(arguments); + // If the vow is a sub-event then we know it is an + // emitted event. So I don't muck with the arguments + // However the legacy behavior: + // If the callback is expecting two or more arguments, + // pass the error as the first (null) and the result after. + if (!(this.ctx && this.ctx.isEvent) && + vow.callback.length >= 2 && batch.suite.options.error) { + args.unshift(null); + } + runTest(args, this.ctx); + vows.tryEnd(batch); + }); + + if (event !== 'error') { + this.on("error", function (err) { + if (vow.callback.length >= 2 || !batch.suite.options.error) { + runTest(arguments, this.ctx); + } else { + output('errored', { type: 'promise', error: err.stack || + err.message || JSON.stringify(err) }); + } + vows.tryEnd(batch); + }); + } + + // in case an event fired before we could listen + if (this._vowsEmitedEvents && + this._vowsEmitedEvents.hasOwnProperty(event)) { + // make sure no one is messing with me + if (Array.isArray(this._vowsEmitedEvents[event])) { + // I don't think I need to optimize for one event, + // I think it is more important to make sure I check the vow n times + self._vowsEmitedEvents[event].forEach(function(args) { + runTest(args, self.ctx); + }); + } else { + // initial conditions problem + throw new Error('_vowsEmitedEvents[' + event + '] is not an Array') + } + vows.tryEnd(batch); + } + + return this; + + function runTest(args, ctx) { + if (vow.callback instanceof String) { + return output('pending'); + } + + if (vow.binding.context.isEvent && vow.binding.context.after) { + var after = vow.binding.context.after; + // only need to check order. I won't get here if the after event + // has never been emitted + if (self._vowsEmitedEventsOrder.indexOf(after) > + self._vowsEmitedEventsOrder.indexOf(event)) { + output('broken', event + ' emitted before ' + after); + return; + } + } + + // Run the test, and try to catch `AssertionError`s and other exceptions; + // increment counters accordingly. + try { + vow.callback.apply(ctx === global || !ctx ? vow.binding : ctx, args); + output('honored'); + } catch (e) { + if (e.name && e.name.match(/AssertionError/)) { + output('broken', e.toString().replace(/\`/g, '`')); + } else { + output('errored', e.stack || e.message || e); + } + } + } + + function output(status, exception) { + batch[status] ++; + vow.status = status; + + if (vow.context && batch.lastContext !== vow.context) { + batch.lastContext = vow.context; + batch.suite.report(['context', vow.context]); + } + batch.suite.report(['vow', { + title: vow.description, + context: vow.context, + status: status, + exception: exception || null + }]); + } +}; + +// +// On exit, check that all promises have been fired. +// If not, report an error message. +// +process.on('exit', function () { + var results = { honored: 0, broken: 0, errored: 0, pending: 0, total: 0 }, + failure; + + vows.suites.forEach(function (s) { + if ((s.results.total > 0) && (s.results.time === null)) { + s.reporter.print('\n\n'); + s.reporter.report(['error', { error: "Asynchronous Error", suite: s }]); + } + s.batches.forEach(function (b) { + var unFired = []; + + b.vows.forEach(function (vow) { + if (! vow.status) { + if (unFired.indexOf(vow.context) === -1) { + unFired.push(vow.context); + } + } + }); + + if (unFired.length > 0) { util.print('\n') } + + unFired.forEach(function (title) { + s.reporter.report(['error', { + error: "callback not fired", + context: title, + batch: b, + suite: s + }]); + }); + + if (b.status === 'begin') { + failure = true; + results.errored ++; + results.total ++; + } + Object.keys(results).forEach(function (k) { results[k] += b[k] }); + }); + }); + if (failure) { + util.puts(console.result(results)); + } +}); + +vows.suites = []; + +// We need the old emit function so we can hook it +// and do magic to deal with events that have fired +var oldEmit = vows.options.Emitter.prototype.emit; + +// +// Create a new test suite +// +vows.describe = function (subject) { + var suite = new(Suite)(subject); + + this.options.Emitter.prototype.addVow = addVow; + // just in case someone emit's before I get to it + this.options.Emitter.prototype.emit = function (event) { + this._vowsEmitedEvents = this._vowsEmitedEvents || {}; + this._vowsEmitedEventsOrder = this._vowsEmitedEventsOrder || []; + // slice off the event + var args = Array.prototype.slice.call(arguments, 1); + // if multiple events are fired, add or push + if (this._vowsEmitedEvents.hasOwnProperty(event)) { + this._vowsEmitedEvents[event].push(args); + } else { + this._vowsEmitedEvents[event] = [args]; + } + + // push the event onto a stack so I have an order + this._vowsEmitedEventsOrder.push(event); + return oldEmit.apply(this, arguments); + } + this.suites.push(suite); + + // + // Add any additional arguments as batches if they're present + // + if (arguments.length > 1) { + for (var i = 1, l = arguments.length; i < l; ++i) { + suite.addBatch(arguments[i]); + } + } + + return suite; +}; + + +vows.version = JSON.parse(require('fs') + .readFileSync(path.join(__dirname, '..', 'package.json'))) + .version diff --git a/lib/vows/console.js b/lib/vows/console.js new file mode 100644 index 00000000..900cef96 --- /dev/null +++ b/lib/vows/console.js @@ -0,0 +1,140 @@ +var eyes = require('eyes').inspector({ stream: null, styles: false }); + +// Stylize a string +this.stylize = function stylize(str, style) { + if (module.exports.nocolor) { + return str; + } + + var styles = { + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'cyan' : [96, 39], + 'yellow' : [33, 39], + 'green' : [32, 39], + 'red' : [31, 39], + 'grey' : [90, 39], + 'green-hi' : [92, 32], + }; + return '\033[' + styles[style][0] + 'm' + str + + '\033[' + styles[style][1] + 'm'; +}; + +var $ = this.$ = function (str) { + str = new(String)(str); + + ['bold', 'grey', 'yellow', 'red', 'green', 'white', 'cyan', 'italic'].forEach(function (style) { + Object.defineProperty(str, style, { + get: function () { + return exports.$(exports.stylize(this, style)); + } + }); + }); + return str; +}; + +this.puts = function (options) { + var stylize = exports.stylize; + options.stream || (options.stream = process.stdout); + options.tail = options.tail || ''; + + return function (args) { + args = Array.prototype.slice.call(arguments); + if (!options.raw) { + args = args.map(function (a) { + return a.replace(/`([^`]+)`/g, function (_, capture) { return stylize(capture, 'italic') }) + .replace(/\*([^*]+)\*/g, function (_, capture) { return stylize(capture, 'bold') }) + .replace(/\n/g, function (_, capture) { return ' \n ' } ); + }); + } + return options.stream.write(args.join('\n') + options.tail); + }; +}; + +this.result = function (event) { + var result = [], buffer = [], time = '', header; + var complete = event.honored + event.pending + event.errored + event.broken; + var status = (event.errored && 'errored') || (event.broken && 'broken') || + (event.honored && 'honored') || (event.pending && 'pending'); + + if (event.total === 0) { + return [$("Could not find any tests to run.").bold.red]; + } + + event.honored && result.push($(event.honored).bold + " honored"); + event.broken && result.push($(event.broken).bold + " broken"); + event.errored && result.push($(event.errored).bold + " errored"); + event.pending && result.push($(event.pending).bold + " pending"); + + if (complete < event.total) { + result.push($(event.total - complete).bold + " dropped"); + } + + result = result.join(' ∙ '); + + header = { + honored: '✓ ' + $('OK').bold.green, + broken: '✗ ' + $('Broken').bold.yellow, + errored: '✗ ' + $('Errored').bold.red, + pending: '- ' + $('Pending').bold.cyan + }[status] + ' » '; + + if (typeof(event.time) === 'number') { + time = ' (' + event.time.toFixed(3) + 's)'; + time = this.stylize(time, 'grey'); + } + buffer.push(header + result + time + '\n'); + + return buffer; +}; + +this.inspect = function inspect(val) { + if (module.exports.nocolor) { + return eyes(val); + } + + return '\033[1m' + eyes(val) + '\033[22m'; +}; + +this.error = function (obj) { + var string = '✗ ' + $('Errored ').red + '» '; + string += $(obj.error).red.bold + '\n'; + string += (obj.context ? ' in ' + $(obj.context).red + '\n': ''); + string += ' in ' + $(obj.suite.subject).red + '\n'; + string += ' in ' + $(obj.suite._filename).red; + + return string; +}; + +this.contextText = function (event) { + return ' ' + event; +}; + +this.vowText = function (event) { + var buffer = []; + + buffer.push(' ' + { + honored: ' ✓ ', + broken: ' ✗ ', + errored: ' ✗ ', + pending: ' - ' + }[event.status] + this.stylize(event.title, ({ + honored: 'green', + broken: 'yellow', + errored: 'red', + pending: 'cyan' + })[event.status])); + + if (event.status === 'broken') { + buffer.push(' » ' + event.exception); + } else if (event.status === 'errored') { + if (event.exception.type === 'promise') { + buffer.push(' » ' + this.stylize("An unexpected error was caught: " + + this.stylize(event.exception.error, 'bold'), 'red')); + } else { + buffer.push(' ' + this.stylize(event.exception, 'red')); + } + } + return buffer.join('\n'); +}; diff --git a/lib/vows/context.js b/lib/vows/context.js new file mode 100644 index 00000000..b11d6762 --- /dev/null +++ b/lib/vows/context.js @@ -0,0 +1,76 @@ + +this.Context = function (vow, ctx, env) { + var that = this; + + this.tests = vow.callback; + this.topics = (ctx.topics || []).slice(0); + this.emitter = null; + this.env = env || {}; + this.env.context = this; + + this.env.callback = function (/* arguments */) { + var ctx = this; + var args = Array.prototype.slice.call(arguments); + + var emit = (function (args) { + // + // Convert callback-style results into events. + // + if (vow.batch.suite.options.error) { + return function () { + var e = args.shift(); + that.emitter.ctx = ctx; + // We handle a special case, where the first argument is a + // boolean, in which case we treat it as a result, and not + // an error. This is useful for `path.exists` and other + // functions like it, which only pass a single boolean + // parameter instead of the more common (error, result) pair. + if (typeof(e) === 'boolean' && args.length === 0) { + that.emitter.emit.call(that.emitter, 'success', e); + } else { + if (e) { that.emitter.emit.apply(that.emitter, ['error', e].concat(args)) } + else { that.emitter.emit.apply(that.emitter, ['success'].concat(args)) } + } + }; + } else { + return function () { + that.emitter.ctx = ctx; + that.emitter.emit.apply(that.emitter, ['success'].concat(args)); + }; + } + })(args.slice(0)); + // If `this.callback` is called synchronously, + // the emitter will not have been set yet, + // so we defer the emition, that way it'll behave + // asynchronously. + if (that.emitter) { emit() } + else { process.nextTick(emit) } + }; + this.name = vow.description; + // events is an alias for on + if (this.name === 'events') { + this.name = vow.description = 'on'; + } + + // if this is a sub-event context AND it's context was an event, + // then I must enforce event order. + // this will not do a good job of handling pin-pong events + if (this.name === 'on' && ctx.isEvent) { + this.after = ctx.name; + } + + if (ctx.name === 'on') { + this.isEvent = true; + this.event = this.name; + this.after = ctx.after; + } else { + this.isEvent = false; + this.event = 'success'; + } + + this.title = [ + ctx.title || '', + vow.description || '' + ].join(/^[#.:]/.test(vow.description) ? '' : ' ').trim(); +}; + diff --git a/lib/vows/coverage/file.js b/lib/vows/coverage/file.js new file mode 100644 index 00000000..5bdef903 --- /dev/null +++ b/lib/vows/coverage/file.js @@ -0,0 +1,29 @@ + +exports.coverage = function (filename, data) { + var ret = { + filename: filename, + coverage: 0, + hits: 0, + misses: 0, + sloc : 0 + }; + + var source = data.source; + ret.source = source.map(function (line, num) { + num++; + + if (data[num] === 0) { + ret.misses++; + ret.sloc++; + } else if (data[num] !== undefined) { + ret.hits++; + ret.sloc++; + } + + return { line: line, coverage: (data[num] === undefined ? '' : data[num]) }; + }); + + ret.coverage = (ret.hits / ret.sloc) * 100; + + return ret; +}; \ No newline at end of file diff --git a/lib/vows/coverage/fragments/coverage-foot.html b/lib/vows/coverage/fragments/coverage-foot.html new file mode 100644 index 00000000..691287b6 --- /dev/null +++ b/lib/vows/coverage/fragments/coverage-foot.html @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/lib/vows/coverage/fragments/coverage-head.html b/lib/vows/coverage/fragments/coverage-head.html new file mode 100644 index 00000000..aa2f107e --- /dev/null +++ b/lib/vows/coverage/fragments/coverage-head.html @@ -0,0 +1,61 @@ + + + + + + + diff --git a/lib/vows/coverage/report-html.js b/lib/vows/coverage/report-html.js new file mode 100644 index 00000000..f7e5b724 --- /dev/null +++ b/lib/vows/coverage/report-html.js @@ -0,0 +1,54 @@ +var util = require('util'), + fs = require('fs'), + file = require('./file'); + +this.name = 'coverage-report-html'; + +function getCoverageClass( data ) { + var fullCoverage= (data.coverage == 100); + var okCoverage= (!fullCoverage && data.coverage >=60); + var coverageClass= ''; + if( fullCoverage ) coverageClass= 'fullCoverage'; + else if( okCoverage) coverageClass= 'okCoverage'; + else coverageClass= 'poorCoverage'; + return coverageClass; +} +this.report = function (coverageMap) { + var out, head, foot; + + try { + out = fs.openSync("coverage.html", "w"); + head = fs.readFileSync(__dirname + "/fragments/coverage-head.html", "utf8"); + foot = fs.readFileSync(__dirname + "/fragments/coverage-foot.html", "utf8"); + } catch (error) { + util.print("Error: Unable to write to file coverage.html\n"); + return; + } + + fs.writeSync(out, head); + + for (var filename in coverageMap) { + if (coverageMap.hasOwnProperty(filename)) { + var data = file.coverage(filename, coverageMap[filename]); + var coverageClass= getCoverageClass( data ); + fs.writeSync(out, "

" + filename + "

\n"); + fs.writeSync(out, '' + "[ hits: " + data.hits); + fs.writeSync(out, ", misses: " + data.misses + ", sloc: " + data.sloc); + fs.writeSync(out, ", coverage: " + data.coverage.toFixed(2) + "% ]" + " [+]\n"); + fs.writeSync(out, "\n"); + fs.writeSync(out, "
\n"); + } + } + + fs.writeSync(out, foot); + fs.close(out); +}; diff --git a/lib/vows/coverage/report-json.js b/lib/vows/coverage/report-json.js new file mode 100644 index 00000000..bcbab258 --- /dev/null +++ b/lib/vows/coverage/report-json.js @@ -0,0 +1,54 @@ +var util = require('util'), + fs = require('fs'), + file = require('./file'); + +this.name = 'coverage-report-json'; + +this.report = function (coverageMap) { + var output = { + meta: { + "generator": "vowsjs", + "generated": new Date().toString(), + "instrumentation": "node-jscoverage", + "file-version": "1.0" + }, + files: [ ], + coverage: [ ] + }; + + + for (var filename in coverageMap) { + if (coverageMap.hasOwnProperty(filename)) { + var data = file.coverage(filename, coverageMap[filename]); + + var coverage = { + file: filename, + coverage: data.coverage.toFixed(2), + hits: data.hits, + misses: data.misses, + sloc: data.sloc, + source: { } + }; + + for (var i = 0; i < data.source.length; i++) { + coverage.source[i + 1] = { + line: data.source[i].line, + coverage: data.source[i].coverage + }; + } + + output.coverage.push(coverage); + + output.files.push(filename); + } + } + + try { + out = fs.openSync("coverage.json", "w"); + fs.writeSync(out, JSON.stringify(output)); + fs.close(out); + } catch (error) { + util.print("Error: Unable to write to file coverage.json\n"); + return; + } +}; diff --git a/lib/vows/coverage/report-plain.js b/lib/vows/coverage/report-plain.js new file mode 100644 index 00000000..9de70051 --- /dev/null +++ b/lib/vows/coverage/report-plain.js @@ -0,0 +1,38 @@ +var util = require('util'), + file = require('./file'); + +this.name = 'coverage-report-plain'; + +function lpad(str, width) { + str = String(str); + var n = width - str.length; + + if (n < 1) { + return str; + } + + while (n--) { + str = ' ' + str; + } + + return str; +} + + +this.report = function (coverageMap) { + for (var filename in coverageMap) { + if (coverageMap.hasOwnProperty(filename)) { + var data = file.coverage(filename, coverageMap[filename]); + + util.print(filename + ":\n"); + util.print("[ hits: " + data.hits + ", misses: " + data.misses); + util.print(", sloc: " + data.sloc + ", coverage: " + data.coverage.toFixed(2) + "% ]\n"); + + for (var i = 0; i < data.source.length; i++) { + util.print(lpad(data.source[i].coverage, 5) + " | " + data.source[i].line + "\n"); + } + + util.print("\n"); + } + } +}; diff --git a/lib/vows/coverage/report-xml.js b/lib/vows/coverage/report-xml.js new file mode 100644 index 00000000..b9ff95b1 --- /dev/null +++ b/lib/vows/coverage/report-xml.js @@ -0,0 +1,81 @@ +var fs = require('fs'), + file = require('./file'); + +this.name = 'coverage-report-xml'; + +this.report = function (coverageMap) { + var all = { + xml: '', + packages: 0, + files: 0, + lines: 0, + hits: 0 + }, + data = {}; + + // group data by path + for (var filename in coverageMap) { + if (coverageMap.hasOwnProperty(filename)) { + var pkg = (filename.indexOf('/') > 0) + ? filename.substr(0, filename.lastIndexOf('/')) + : filename; + if (!data[pkg]) { + data[pkg] = {}; + } + data[pkg][ (filename.indexOf('/')) + ? filename.substr(filename.lastIndexOf('/') + 1, filename.length) + : filename ] + = file.coverage(filename, coverageMap[filename]); + } + } + + // generate groups xml-fragment + for (var pkg in data) { + if (data.hasOwnProperty(pkg)) { + var pkgStat = { + xml: '', + files: 0, + lines: 0, + hits: 0 + }; + + all.xml += '\t\n'; + + for (var filename in data[pkg]) { + if (data[pkg].hasOwnProperty(filename)) { + pkgStat.files += 1; + pkgStat.lines += data[pkg][filename].sloc; + pkgStat.hits += data[pkg][filename].hits; + + pkgStat.xml += '\t\t\n' + + '\t\t\t\n' + + '\t\t\n'; + } + } + + all.packages += 1; + all.files += pkgStat.files; + all.lines += pkgStat.lines; + all.hits += pkgStat.hits; + + all.xml += '\t\t\n' + + pkgStat.xml + + '\t\n'; + } + } + + all.xml = '\n' + + '\n\n' + + '\t\n' + + '\t\n' + + '\t\n' + + '\t\n' + + '\t\n' + + '\n\n' + + '\n' + + '\t\n' + + all.xml + + '\n\n\n'; + + fs.writeFileSync('coverage.xml', all.xml); +}; diff --git a/lib/vows/extras.js b/lib/vows/extras.js new file mode 100644 index 00000000..a90d7a5f --- /dev/null +++ b/lib/vows/extras.js @@ -0,0 +1,28 @@ +var events = require('events'); +// +// Wrap a Node.js style async function into an EventEmmitter +// +this.prepare = function (obj, targets) { + targets.forEach(function (target) { + if (target in obj) { + obj[target] = (function (fun) { + return function () { + var args = Array.prototype.slice.call(arguments); + var ee = new(events.EventEmitter); + + args.push(function (err /* [, data] */) { + var args = Array.prototype.slice.call(arguments, 1); + + if (err) { ee.emit.apply(ee, ['error', err].concat(args)) } + else { ee.emit.apply(ee, ['success'].concat(args)) } + }); + fun.apply(obj, args); + + return ee; + }; + })(obj[target]); + } + }); + return obj; +}; + diff --git a/lib/vows/reporters/dot-matrix.js b/lib/vows/reporters/dot-matrix.js new file mode 100644 index 00000000..0ecf590c --- /dev/null +++ b/lib/vows/reporters/dot-matrix.js @@ -0,0 +1,67 @@ +var options = { tail: '' }, + console = require('../../vows/console'), + stylize = console.stylize, + puts = console.puts(options); +// +// Console reporter +// +var messages = [], lastContext; + +this.name = 'dot-matrix'; +this.setStream = function (s) { + options.stream = s; +}; + +this.reset = function () { + messages = []; + lastContext = null; +}; +this.report = function (data) { + var event = data[1]; + + switch (data[0]) { + case 'subject': + // messages.push(stylize(event, 'underline') + '\n'); + break; + case 'context': + break; + case 'vow': + if (event.status === 'honored') { + puts(stylize('·', 'green')); + } else if (event.status === 'pending') { + puts(stylize('-', 'cyan')); + } else { + if (lastContext !== event.context) { + lastContext = event.context; + messages.push(' ' + event.context); + } + if (event.status === 'broken') { + puts(stylize('✗', 'yellow')); + messages.push(console.vowText(event)); + } else if (event.status === 'errored') { + puts(stylize('✗', 'red')); + messages.push(console.vowText(event)); + } + messages.push(''); + } + break; + case 'end': + puts(' '); + break; + case 'finish': + if (messages.length) { + puts('\n\n' + messages.join('\n')); + } else { + puts(''); + } + puts(console.result(event).join('\n')); + break; + case 'error': + puts(console.error(event)); + break; + } +}; + +this.print = function (str) { + puts(str); +}; diff --git a/lib/vows/reporters/json.js b/lib/vows/reporters/json.js new file mode 100644 index 00000000..20c1366d --- /dev/null +++ b/lib/vows/reporters/json.js @@ -0,0 +1,33 @@ +var options = { tail: '\n', raw: true }; +var console = require('../../vows/console'); +var puts = console.puts(options); + +// +// Console JSON reporter +// +this.name = 'json'; +this.setStream = function (s) { + options.stream = s; +}; + +function removeCircularSuite(obj, suite) { + var result = {}; + + if (typeof obj !== 'object' || obj === null) return obj; + + Object.keys(obj).forEach(function(key) { + if (obj[key] === suite) { + result[key] = {}; + } else { + result[key] = removeCircularSuite(obj[key], suite || obj.suite); + } + }); + + return result; +}; + +this.report = function (obj) { + puts(JSON.stringify(removeCircularSuite(obj))); +}; + +this.print = function (str) {}; diff --git a/lib/vows/reporters/silent.js b/lib/vows/reporters/silent.js new file mode 100644 index 00000000..fe90a333 --- /dev/null +++ b/lib/vows/reporters/silent.js @@ -0,0 +1,8 @@ +// +// Silent reporter - "Shhh" +// +this.name = 'silent'; +this.reset = function () {}; +this.report = function () {}; +this.print = function () {}; + diff --git a/lib/vows/reporters/spec.js b/lib/vows/reporters/spec.js new file mode 100644 index 00000000..d1c6dd84 --- /dev/null +++ b/lib/vows/reporters/spec.js @@ -0,0 +1,42 @@ +var util = require('util'); + +var options = { tail: '\n' }; +var console = require('../../vows/console'); +var stylize = console.stylize, + puts = console.puts(options); +// +// Console reporter +// + +this.name = 'spec'; +this.setStream = function (s) { + options.stream = s; +}; +this.report = function (data) { + var event = data[1]; + + switch (data[0]) { + case 'subject': + puts('\n♢ ' + stylize(event, 'bold') + '\n'); + break; + case 'context': + puts(console.contextText(event)); + break; + case 'vow': + puts(console.vowText(event)); + break; + case 'end': + util.print('\n'); + break; + case 'finish': + puts(console.result(event).join('\n')); + break; + case 'error': + puts(console.error(event)); + break; + } +}; + +this.print = function (str) { + util.print(str); +}; diff --git a/lib/vows/reporters/watch.js b/lib/vows/reporters/watch.js new file mode 100644 index 00000000..58f6e3c8 --- /dev/null +++ b/lib/vows/reporters/watch.js @@ -0,0 +1,37 @@ +var options = {}; +var console = require('../../vows/console'); +var spec = require('../../vows/reporters/spec'); +var stylize = console.stylize, + puts = console.puts(options); +// +// Console reporter +// +var lastContext; + +this.name = 'watch'; +this.setStream = function (s) { + options.stream = s; +}; +this.reset = function () { + lastContext = null; +}; +this.report = function (data) { + var event = data[1]; + + switch (data[0]) { + case 'vow': + if (['honored', 'pending'].indexOf(event.status) === -1) { + if (lastContext !== event.context) { + lastContext = event.context; + puts(console.contextText(event.context)); + } + puts(console.vowText(event)); + puts(''); + } + break; + case 'error': + puts(console.error(event)); + break; + } +}; +this.print = function (str) {}; diff --git a/lib/vows/reporters/xunit.js b/lib/vows/reporters/xunit.js new file mode 100644 index 00000000..411a9481 --- /dev/null +++ b/lib/vows/reporters/xunit.js @@ -0,0 +1,90 @@ +// xunit outoput for vows, so we can run things under hudson +// +// The translation to xunit is simple. Most likely more tags/attributes can be +// added, see: http://ant.1045680.n5.nabble.com/schema-for-junit-xml-output-td1375274.html +// + +var puts = require('util').puts; + +var buffer = [], + curSubject = null; + +function xmlEnc(value) { + return !value ? value : String(value).replace(/&/g, "&") + .replace(/>/g, ">") + .replace(/'; +} + +function cdata(data) { + return ''; +} + +this.name = 'xunit'; +this.report = function (data) { + var event = data[1]; + + switch (data[0]) { + case 'subject': + curSubject = event; + break; + case 'context': + break; + case 'vow': + switch (event.status) { + case 'honored': + buffer.push(tag('testcase', {classname: curSubject, name: event.context + ': ' + event.title}, true)); + break; + case 'broken': + var err = tag('error', {type: 'vows.event.broken', message: 'Broken test'}, false, cdata(event.exception)); + buffer.push(tag('testcase', {classname: curSubject, name: event.context + ': ' + event.title}, false, err)); + break; + case 'errored': + var skip = tag('skipped', {type: 'vows.event.errored', message: 'Errored test'}, false, cdata(event.exception)); + buffer.push(tag('testcase', {classname: curSubject, name: event.context + ': ' + event.title}, false, skip)); + break; + case 'pending': + // nop + break; + } + break; + case 'end': + buffer.push(end('testcase')); + break; + case 'finish': + buffer.unshift(tag('testsuite', {name: 'Vows test', tests: event.total, timestamp: (new Date()).toUTCString(), errors: event.errored, failures: event.broken, skip: event.pending, time: event.time})); + buffer.push(end('testsuite')); + puts(buffer.join('\n')); + break; + case 'error': + break; + } +}; + +this.print = function (str) { }; diff --git a/lib/vows/suite.js b/lib/vows/suite.js new file mode 100644 index 00000000..737b295d --- /dev/null +++ b/lib/vows/suite.js @@ -0,0 +1,380 @@ +var events = require('events'), + path = require('path'); + +var vows = require('../vows'); +var Context = require('../vows/context').Context; + +this.Suite = function (subject) { + this.subject = subject; + this.matcher = /.*/; + this.reporter = require('./reporters/dot-matrix'); + this.batches = []; + this.options = { error: true }; + this.reset(); +}; + +this.Suite.prototype = new(function () { + this.reset = function () { + this.results = { + honored: 0, + broken: 0, + errored: 0, + pending: 0, + total: 0, + time: null + }; + this.batches.forEach(function (b) { + b.lastContext = null; + b.remaining = b._remaining; + b.honored = b.broken = b.errored = b.total = b.pending = 0; + b.vows.forEach(function (vow) { vow.status = null }); + b.teardowns = []; + }); + }; + + this.addBatch = function (tests) { + this.batches.push({ + tests: tests, + suite: this, + vows: [], + remaining: 0, + _remaining: 0, + honored: 0, + broken: 0, + errored: 0, + pending: 0, + total: 0, + teardowns: [] + }); + return this; + }; + this.addVows = this.addBatch; + + this.parseBatch = function (batch, matcher) { + var tests = batch.tests; + + if ('topic' in tests) { + throw new(Error)("missing top-level context."); + } + // Count the number of vows/promises expected to fire, + // so we know when the tests are over. + // We match the keys against `matcher`, to decide + // whether or not they should be included in the test. + // Any key, including assertion function keys can be matched. + // If a child matches, then the n parent topics must not be skipped. + (function count(tests, _match) { + var match = false; + + var keys = Object.keys(tests).filter(function (k) { + return k !== 'topic' && k !== 'teardown'; + }); + + for (var i = 0, key; i < keys.length; i++) { + key = keys[i]; + + // If the parent node, or this one matches. + match = _match || matcher.test(key); + + if (typeof(tests[key]) === 'object') { + match = count(tests[key], match); + } else { + if (typeof(tests[key]) === 'string') { + tests[key] = new(String)(tests[key]); + } + if (! match) { + tests[key]._skip = true; + } + } + } + + // If any of the children matched, + // don't skip this node. + for (var i = 0; i < keys.length; i++) { + if (! tests[keys[i]]._skip) { match = true } + } + + if (match) { batch.remaining ++ } + else { tests._skip = true } + + return match; + })(tests, false); + + batch._remaining = batch.remaining; + }; + + this.runBatch = function (batch) { + var topic, + tests = batch.tests, + promise = batch.promise = new(events.EventEmitter); + + var that = this; + + batch.status = 'begin'; + + // The test runner, it calls itself recursively, passing the + // previous context to the inner contexts. This is so the `topic` + // functions have access to all the previous context topics in their + // arguments list. + // It is defined and invoked at the same time. + // If it encounters a `topic` function, it waits for the returned + // promise to emit (the topic), at which point it runs the functions under it, + // passing the topic as an argument. + (function run(ctx, lastTopic) { + var old = false; + topic = ctx.tests.topic; + + if (typeof(topic) === 'function') { + if (ctx.isEvent || ctx.name === 'on') { + throw new Error('Event context cannot contain a topic'); + } + + // Run the topic, passing the previous context topics + // If topic `throw`s an exception, pass it down as a value + try { + topic = topic.apply(ctx.env, ctx.topics); + } + catch (ex) { + topic = ex; + } + + if (typeof(topic) === 'undefined') { ctx._callback = true } + } + + // If this context has a topic, store it in `lastTopic`, + // if not, use the last topic, passed down by a parent + // context. + if (typeof(topic) !== 'undefined' || ctx._callback) { + lastTopic = topic; + } else { + old = true; + topic = lastTopic; + } + + // If the topic doesn't return an event emitter (such as a promise), + // we create it ourselves, and emit the value on the next tick. + if (! (topic && + topic.constructor === events.EventEmitter)) { + // If the context is a traditional vow, then a topic can ONLY + // be an EventEmitter. However if the context is a sub-event + // then the topic may be an instanceof EventEmitter + if (!ctx.isEvent || + (ctx.isEvent && !(topic instanceof events.EventEmitter))) { + + ctx.emitter = new(events.EventEmitter); + + if (! ctx._callback) { + process.nextTick(function (val) { + return function () { + ctx.emitter.emit("success", val) + }; + }(topic)); + } + // if I have a callback, push the new topic back up to + // lastTopic + if (ctx._callback) { + lastTopic = topic = ctx.emitter; + } else { + topic = ctx.emitter; + } + } + } + + topic.on(ctx.event, function (val) { + // Once the topic fires, add the return value + // to the beginning of the topics list, so it + // becomes the first argument for the next topic. + // If we're using the parent topic, no need to + // prepend it to the topics list, or we'll get + // duplicates. + if (!old || ctx.isEvent) { + Array.prototype.unshift.apply(ctx.topics, arguments) + }; + }); + if (topic.setMaxListeners) { topic.setMaxListeners(Infinity) } + // Now run the tests, or sub-contexts + Object.keys(ctx.tests).filter(function (k) { + return ctx.tests[k] && k !== 'topic' && + k !== 'teardown' && !ctx.tests[k]._skip; + }).forEach(function (item) { + // Create a new evaluation context, + // inheriting from the parent one. + var env = Object.create(ctx.env); + env.suite = that; + + // Holds the current test or context + var vow = Object.create({ + callback: ctx.tests[item], + context: ctx.title, + description: item, + binding: ctx.env, + status: null, + batch: batch + }); + + // If we encounter a function, add it to the callbacks + // of the `topic` function, so it'll get called once the + // topic fires. + // If we encounter an object literal, we recurse, sending it + // our current context. + if ((typeof(vow.callback) === 'function') || + (vow.callback instanceof String)) { + topic.addVow(vow); + } else if (typeof(vow.callback) === 'object') { + // If there's a setup stage, we have to wait for it to fire, + // before calling the inner context. + // If the event has already fired, the context is 'on' or + // there is no setup stage, just run the inner context + // synchronously. + if (topic && + ctx.name !== 'on' && + !topic._vowsEmitedEvents.hasOwnProperty(ctx.event)) { + topic.on(ctx.event, function (ctx) { + return function (val) { + return run(new(Context)(vow, ctx, env), lastTopic); + }; + }(ctx)); + } else { + run(new(Context)(vow, ctx, env), lastTopic); + } + } + }); + // Teardown + if (ctx.tests.teardown) { + batch.teardowns.push(ctx); + } + if (! ctx.tests._skip) { + batch.remaining --; + } + // Check if we're done running the tests + exports.tryEnd(batch); + // This is our initial, empty context + })(new(Context)({ callback: tests, context: null, description: null }, {})); + return promise; + }; + + this.report = function () { + return this.reporter.report.apply(this.reporter, arguments); + }; + + this.run = function (options, callback) { + var that = this, start; + + options = options || {}; + + for (var k in options) { this.options[k] = options[k] } + + this.matcher = this.options.matcher || this.matcher; + this.reporter = this.options.reporter || this.reporter; + + this.batches.forEach(function (batch) { + that.parseBatch(batch, that.matcher); + }); + + this.reset(); + + start = new(Date); + + if (this.batches.filter(function (b) { return b.remaining > 0 }).length) { + this.report(['subject', this.subject]); + } + + return (function run(batches) { + var batch = batches.shift(); + + if (batch) { + // If the batch has no vows to run, + // go to the next one. + if (batch.remaining === 0) { + run(batches); + } else { + that.runBatch(batch).on('end', function () { + run(batches); + }); + } + } else { + that.results.time = (new(Date) - start) / 1000; + that.report(['finish', that.results]); + + if (callback) { callback(that.results) } + + if (that.results.honored + that.results.pending === that.results.total) { + return 0; + } else { + return 1; + } + } + })(this.batches.slice(0)); + }; + + this.runParallel = function () {}; + + this.export = function (module, options) { + for (var k in (options || {})) { this.options[k] = options[k] } + + if (require.main === module) { + return this.run(); + } else { + return module.exports[this.subject] = this; + } + }; + this.exportTo = function (module, options) { // Alias, for JSLint + return this.export(module, options); + }; +}); + +// +// Checks if all the tests in the batch have been run, +// and triggers the next batch (if any), by emitting the 'end' event. +// +this.tryEnd = function (batch) { + var result, style, time; + + if (batch.honored + batch.broken + batch.errored + batch.pending === batch.total && + batch.remaining === 0) { + + Object.keys(batch).forEach(function (k) { + (k in batch.suite.results) && (batch.suite.results[k] += batch[k]); + }); + + if (batch.teardowns) { + for (var i = batch.teardowns.length - 1, ctx; i >= 0; i--) { + runTeardown(batch.teardowns[i]); + } + + maybeFinish(); + } + + function runTeardown(teardown) { + var env = Object.create(teardown.env); + + Object.defineProperty(env, "callback", { + get: function () { + teardown.awaitingCallback = true; + + return function () { + teardown.awaitingCallback = false; + maybeFinish(); + }; + } + }); + + teardown.tests.teardown.apply(env, teardown.topics); + } + + function maybeFinish() { + var pending = batch.teardowns.filter(function (teardown) { + return teardown.awaitingCallback; + }); + + if (pending.length === 0) { + finish(); + } + } + + function finish() { + batch.status = 'end'; + batch.suite.report(['end']); + batch.promise.emit('end', batch.honored, batch.broken, batch.errored, batch.pending); + } + } +}; diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 570da2d5..00000000 --- a/package-lock.json +++ /dev/null @@ -1,3017 +0,0 @@ -{ - "name": "vows", - "version": "1.0.0-alpha.1", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", - "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.1" - } - }, - "@babel/core": { - "version": "7.10.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.10.2.tgz", - "integrity": "sha512-KQmV9yguEjQsXqyOUGKjS4+3K8/DlOCE2pZcq4augdQmtTy5iv5EHtmMSJ7V4c1BIPjuwtZYqYLCq9Ga+hGBRQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.1", - "@babel/generator": "^7.10.2", - "@babel/helper-module-transforms": "^7.10.1", - "@babel/helpers": "^7.10.1", - "@babel/parser": "^7.10.2", - "@babel/template": "^7.10.1", - "@babel/traverse": "^7.10.1", - "@babel/types": "^7.10.2", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.10.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.2.tgz", - "integrity": "sha512-AxfBNHNu99DTMvlUPlt1h2+Hn7knPpH5ayJ8OqDWSeLld+Fi2AYBTC/IejWDM9Edcii4UzZRCsbUt0WlSDsDsA==", - "dev": true, - "requires": { - "@babel/types": "^7.10.2", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - } - } - }, - "@babel/helper-function-name": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.1.tgz", - "integrity": "sha512-fcpumwhs3YyZ/ttd5Rz0xn0TpIwVkN7X0V38B9TWNfVF42KEkhkAAuPCQ3oXmtTRtiPJrmZ0TrfS0GKF0eMaRQ==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.1", - "@babel/template": "^7.10.1", - "@babel/types": "^7.10.1" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz", - "integrity": "sha512-F5qdXkYGOQUb0hpRaPoetF9AnsXknKjWMZ+wmsIRsp5ge5sFh4c3h1eH2pRTTuy9KKAA2+TTYomGXAtEL2fQEw==", - "dev": true, - "requires": { - "@babel/types": "^7.10.1" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.1.tgz", - "integrity": "sha512-u7XLXeM2n50gb6PWJ9hoO5oO7JFPaZtrh35t8RqKLT1jFKj9IWeD1zrcrYp1q1qiZTdEarfDWfTIP8nGsu0h5g==", - "dev": true, - "requires": { - "@babel/types": "^7.10.1" - } - }, - "@babel/helper-module-imports": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.1.tgz", - "integrity": "sha512-SFxgwYmZ3HZPyZwJRiVNLRHWuW2OgE5k2nrVs6D9Iv4PPnXVffuEHy83Sfx/l4SqF+5kyJXjAyUmrG7tNm+qVg==", - "dev": true, - "requires": { - "@babel/types": "^7.10.1" - } - }, - "@babel/helper-module-transforms": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.10.1.tgz", - "integrity": "sha512-RLHRCAzyJe7Q7sF4oy2cB+kRnU4wDZY/H2xJFGof+M+SJEGhZsb+GFj5j1AD8NiSaVBJ+Pf0/WObiXu/zxWpFg==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.1", - "@babel/helper-replace-supers": "^7.10.1", - "@babel/helper-simple-access": "^7.10.1", - "@babel/helper-split-export-declaration": "^7.10.1", - "@babel/template": "^7.10.1", - "@babel/types": "^7.10.1", - "lodash": "^4.17.13" - }, - "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - } - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.1.tgz", - "integrity": "sha512-a0DjNS1prnBsoKx83dP2falChcs7p3i8VMzdrSbfLhuQra/2ENC4sbri34dz/rWmDADsmF1q5GbfaXydh0Jbjg==", - "dev": true, - "requires": { - "@babel/types": "^7.10.1" - } - }, - "@babel/helper-replace-supers": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.1.tgz", - "integrity": "sha512-SOwJzEfpuQwInzzQJGjGaiG578UYmyi2Xw668klPWV5n07B73S0a9btjLk/52Mlcxa+5AdIYqws1KyXRfMoB7A==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.10.1", - "@babel/helper-optimise-call-expression": "^7.10.1", - "@babel/traverse": "^7.10.1", - "@babel/types": "^7.10.1" - } - }, - "@babel/helper-simple-access": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.1.tgz", - "integrity": "sha512-VSWpWzRzn9VtgMJBIWTZ+GP107kZdQ4YplJlCmIrjoLVSi/0upixezHCDG8kpPVTBJpKfxTH01wDhh+jS2zKbw==", - "dev": true, - "requires": { - "@babel/template": "^7.10.1", - "@babel/types": "^7.10.1" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz", - "integrity": "sha512-UQ1LVBPrYdbchNhLwj6fetj46BcFwfS4NllJo/1aJsT+1dLTEnXJL0qHqtY7gPzF8S2fXBJamf1biAXV3X077g==", - "dev": true, - "requires": { - "@babel/types": "^7.10.1" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", - "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==", - "dev": true - }, - "@babel/helpers": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.1.tgz", - "integrity": "sha512-muQNHF+IdU6wGgkaJyhhEmI54MOZBKsFfsXFhboz1ybwJ1Kl7IHlbm2a++4jwrmY5UYsgitt5lfqo1wMFcHmyw==", - "dev": true, - "requires": { - "@babel/template": "^7.10.1", - "@babel/traverse": "^7.10.1", - "@babel/types": "^7.10.1" - } - }, - "@babel/highlight": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", - "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.1", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - } - } - }, - "@babel/parser": { - "version": "7.10.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.2.tgz", - "integrity": "sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ==", - "dev": true - }, - "@babel/template": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.1.tgz", - "integrity": "sha512-OQDg6SqvFSsc9A0ej6SKINWrpJiNonRIniYondK2ViKhB06i3c0s+76XUft71iqBEe9S1OKsHwPAjfHnuvnCig==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.1", - "@babel/parser": "^7.10.1", - "@babel/types": "^7.10.1" - } - }, - "@babel/traverse": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.1.tgz", - "integrity": "sha512-C/cTuXeKt85K+p08jN6vMDz8vSV0vZcI0wmQ36o6mjbuo++kPMdpOYw23W2XH04dbRt9/nMEfA4W3eR21CD+TQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.1", - "@babel/generator": "^7.10.1", - "@babel/helper-function-name": "^7.10.1", - "@babel/helper-split-export-declaration": "^7.10.1", - "@babel/parser": "^7.10.1", - "@babel/types": "^7.10.1", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" - }, - "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.10.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.2.tgz", - "integrity": "sha512-AD3AwWBSz0AWF0AkCN9VPiWrvldXq+/e3cHa4J89vo4ymjz1XwrBFFVZmkJTsQIPNk+ZVomPSXUJqq8yyjZsng==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.1", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - } - } - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", - "dev": true - }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true - }, - "acorn": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", - "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", - "dev": true - }, - "acorn-jsx": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", - "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", - "dev": true - }, - "aggregate-error": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", - "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", - "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-colors": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", - "dev": true - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - }, - "dependencies": { - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } - } - }, - "append-transform": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", - "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", - "dev": true, - "requires": { - "default-require-extensions": "^3.0.0" - } - }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, - "async": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", - "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "caching-transform": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", - "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", - "dev": true, - "requires": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" - }, - "chalk": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", - "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.1.0", - "escape-string-regexp": "^1.0.5", - "supports-color": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", - "dev": true, - "requires": { - "has-flag": "^2.0.0" - } - } - } - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" - }, - "coffeescript": { - "version": "1.12.7", - "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.12.7.tgz", - "integrity": "sha512-pLXHFxQMPklVoEekowk8b3erNynC+DVJzChxS/LCBBgR6/8AJkHivkm//zbowcfc7BTCAjryuhx6gPqPRfsFoA==" - }, - "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "dev": true, - "requires": { - "color-name": "^1.1.1" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "default-require-extensions": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", - "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", - "dev": true, - "requires": { - "strip-bom": "^4.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - } - } - }, - "define-properties": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", - "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", - "dev": true, - "requires": { - "foreach": "^2.0.5", - "object-keys": "^1.0.8" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "enquirer": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.5.tgz", - "integrity": "sha512-BNT1C08P9XD0vNg3J475yIUG+mVdp9T6towYFHUv897X0KoHBjB1shyrNmhmtHWKP17iSWgo7Gqh7BBuzLZMSA==", - "dev": true, - "requires": { - "ansi-colors": "^3.2.1" - } - }, - "error-ex": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.9.0.tgz", - "integrity": "sha512-kk3IJoKo7A3pWJc0OV8yZ/VEX2oSUytfekrJiqoxBlKJMFAJVJVpGdHClCCTdv+Fn2zHfpDHHIelMFhZVfef3Q==", - "dev": true, - "requires": { - "es-to-primitive": "^1.1.1", - "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" - } - }, - "es-to-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", - "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", - "dev": true, - "requires": { - "is-callable": "^1.1.1", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.1" - } - }, - "es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "eslint": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.3.0.tgz", - "integrity": "sha512-dJMVXwfU5PT1cj2Nv2VPPrKahKTGdX+5Dh0Q3YuKt+Y2UhdL2YbzsVaBMyG9HC0tBismlv/r1+eZqs6SMIV38Q==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "eslint-scope": "^5.1.0", - "eslint-utils": "^2.0.0", - "eslint-visitor-keys": "^1.2.0", - "espree": "^7.1.0", - "esquery": "^1.2.0", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash": "^4.17.14", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "requires": { - "type-fest": "^0.8.1" - } - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "eslint-config-standard": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz", - "integrity": "sha512-Z9B+VR+JIXRxz21udPTL9HpFMyoMUEeX1G251EQ6e05WD9aPVtVBn09XUmZ259wCMlCDmYDSZG62Hhm+ZTJcUg==", - "dev": true - }, - "eslint-import-resolver-node": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "resolve": "^1.5.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "eslint-module-utils": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", - "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", - "dev": true, - "requires": { - "debug": "^2.6.8", - "pkg-dir": "^1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "eslint-plugin-es": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", - "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", - "dev": true, - "requires": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, - "dependencies": { - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true - } - } - }, - "eslint-plugin-import": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.11.0.tgz", - "integrity": "sha1-Fa7qN6Z0mdhI6OmBgG1GJ7VQOBY=", - "dev": true, - "requires": { - "contains-path": "^0.1.0", - "debug": "^2.6.8", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.1", - "eslint-module-utils": "^2.2.0", - "has": "^1.0.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.3", - "read-pkg-up": "^2.0.0", - "resolve": "^1.6.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "resolve": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", - "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", - "dev": true, - "requires": { - "path-parse": "^1.0.5" - } - } - } - }, - "eslint-plugin-node": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", - "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", - "dev": true, - "requires": { - "eslint-plugin-es": "^3.0.0", - "eslint-utils": "^2.0.0", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" - }, - "dependencies": { - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "eslint-plugin-promise": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz", - "integrity": "sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==", - "dev": true - }, - "eslint-plugin-standard": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz", - "integrity": "sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ==", - "dev": true - }, - "eslint-scope": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", - "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.2.0.tgz", - "integrity": "sha512-WFb4ihckKil6hu3Dp798xdzSfddwKKU3+nGniKF6HfeW6OLd2OUDEPP7TcHtB5+QXOKg2s6B2DaMPE1Nn/kxKQ==", - "dev": true - }, - "espree": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.1.0.tgz", - "integrity": "sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw==", - "dev": true, - "requires": { - "acorn": "^7.2.0", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.2.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", - "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", - "dev": true, - "requires": { - "estraverse": "^4.1.0" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } - }, - "find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", - "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - } - } - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, - "foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - }, - "dependencies": { - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "fromentries": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.0.tgz", - "integrity": "sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.1", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", - "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", - "dev": true - }, - "get-caller-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=" - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "11.5.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.5.0.tgz", - "integrity": "sha512-hYyf+kI8dm3nORsiiXUQigOU62hDLfJ9G01uyGMxhc6BKsircrUhC4uJPQPUSuq2GrTmiiEt7ewxlMdBewfmKQ==", - "dev": true - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true - }, - "has": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", - "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", - "dev": true, - "requires": { - "function-bind": "^1.0.2" - } - }, - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", - "dev": true - }, - "hasha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.0.tgz", - "integrity": "sha512-2W+jKdQbAdSIrggA8Q35Br8qKadTrqCTC8+XZvBWepKDK6m9XkX6Iz1a2yh2KP01kzAR/dpuMeUnocoLYDcskw==", - "dev": true, - "requires": { - "is-stream": "^2.0.0", - "type-fest": "^0.8.0" - }, - "dependencies": { - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - } - } - }, - "hosted-git-info": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", - "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==", - "dev": true - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } - }, - "is-callable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", - "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", - "dev": true - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, - "requires": { - "has": "^1.0.1" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "is-symbol": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", - "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", - "dev": true - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true - }, - "istanbul-lib-hook": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", - "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", - "dev": true, - "requires": { - "append-transform": "^2.0.0" - } - }, - "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-processinfo": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", - "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", - "dev": true, - "requires": { - "archy": "^1.0.0", - "cross-spawn": "^7.0.0", - "istanbul-lib-coverage": "^3.0.0-alpha.1", - "make-dir": "^3.0.0", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "uuid": "^3.3.3" - }, - "dependencies": { - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - }, - "dependencies": { - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - } - } - }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "requires": { - "invert-kv": "^1.0.0" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - } - } - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - }, - "lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", - "dev": true - }, - "lru-cache": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", - "integrity": "sha1-Yi4y6CSItJJ5EUpPns9F581rulU=", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "mem": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", - "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "mimic-fn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", - "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node-preload": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", - "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", - "dev": true, - "requires": { - "process-on-spawn": "^1.0.0" - } - }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "requires": { - "path-key": "^2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "nyc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", - "dev": true, - "requires": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yargs": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", - "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.1" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "object-keys": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", - "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", - "dev": true - }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "os-locale": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", - "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, - "p-limit": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", - "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=" - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "package-hash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", - "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.15", - "hasha": "^5.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true - } - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" - }, - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", - "dev": true - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, - "pkg-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", - "dev": true, - "requires": { - "find-up": "^1.0.0" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "process-on-spawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", - "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", - "dev": true, - "requires": { - "fromentries": "^1.2.0" - } - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - } - } - }, - "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true - }, - "release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", - "dev": true, - "requires": { - "es6-error": "^4.0.1" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" - }, - "resolve": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", - "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", - "dev": true, - "requires": { - "path-parse": "^1.0.5" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "semver": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" - }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - } - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", - "dev": true, - "requires": { - "foreground-child": "^2.0.0", - "is-windows": "^1.0.2", - "make-dir": "^3.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "which": "^2.0.1" - }, - "dependencies": { - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "spdx-correct": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" - }, - "strip-json-comments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", - "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - } - } - }, - "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dev": true, - "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "dependencies": { - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "util-promisify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", - "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3" - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - }, - "v8-compile-cache": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", - "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "which": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha1-/wS9/AEO5UfXgL7DjhrBwnd9JTo=", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "yargs": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", - "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "requires": { - "locate-path": "^2.0.0" - } - } - } - }, - "yargs-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", - "requires": { - "camelcase": "^4.1.0" - } - } - } -} diff --git a/package.json b/package.json index b06a8f47..e1e521c3 100644 --- a/package.json +++ b/package.json @@ -1,53 +1,15 @@ { - "name": "vows", - "version": "1.0.0-alpha.1", - "license": "Apache-2.0", - "description": "testing framework", - "keywords": [ - "unit test", - "vows", - "test" - ], - "author": { - "name": "Evan Prodromou", - "email": "evan@fuzzy.ai" - }, - "main": "lib/index.js", - "bin": "./bin/vows.js", - "scripts": { - "lint": "eslint bin/*.js lib/*.js test/*.js", - "test": "node test/standalone.js && node bin/vows.js test/test-*", - "test-coverage": "nyc -r lcov npm test" - }, - "directories": { - "lib": "./lib" - }, - "files": [ - "bin/*", - "lib/*", - "CHANGELOG.md", - "LICENSE", - "README.md" - ], - "repository": "vowsjs/vows", - "dependencies": { - "async": "^3.2.0", - "coffeescript": "^1.12.7", - "debug": "^4.1.1", - "lodash": "^4.17.11", - "yargs": "^11.1.0" - }, - "devDependencies": { - "eslint": "^7.3.0", - "eslint-config-standard": "^14.1.1", - "eslint-plugin-import": "^2.11.0", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^4.2.1", - "eslint-plugin-standard": "^4.0.1", - "nyc": "^15.1.0", - "util-promisify": "^2.1.0" - }, - "engines": { - "node": ">=9 <=14" - } + "name" : "vows", + "description" : "Asynchronous BDD & continuous integration for node.js", + "url" : "http://vowsjs.org", + "keywords" : ["testing", "spec", "test", "BDD"], + "author" : "Alexis Sellier ", + "contributors" : [{ "name": "Charlie Robbins", "email": "charlie.robbins@gmail.com" }], + "dependencies" : {"eyes": ">=0.1.6"}, + "main" : "./lib/vows", + "bin" : { "vows": "./bin/vows" }, + "directories" : { "test": "./test", "bin": "./bin" }, + "version" : "0.6.1", + "scripts" : {"test": "./bin/vows --spec"}, + "engines" : {"node": ">=0.2.6"} } diff --git a/test/assert-test.js b/test/assert-test.js new file mode 100644 index 00000000..c191588f --- /dev/null +++ b/test/assert-test.js @@ -0,0 +1,133 @@ +var vows = require('../lib/vows'); +var assert = require('assert'); + +vows.describe('vows/assert').addBatch({ + "The Assertion module": { + "`equal`": function () { + assert.equal("hello world", "hello world"); + assert.equal(1, true); + }, + "`match`": function () { + assert.match("hello world", /^[a-z]+ [a-z]+$/); + }, + "`lengthOf`": function () { + assert.lengthOf("hello world", 11); + assert.lengthOf([1, 2, 3], 3); + }, + "`isDefined`": function () { + assert.isDefined(null); + assertError(assert.isDefined, undefined); + }, + "`include`": function () { + assert.include("hello world", "world"); + assert.include([0, 42, 0], 42); + assert.include({goo:true}, 'goo'); + }, + "`deepInclude`": function () { + assert.deepInclude([{a:'b'},{c:'d'}], {a:'b'}); + assert.deepInclude("hello world", "world"); + assert.deepInclude({goo:true}, 'goo'); + }, + "`typeOf`": function () { + assert.typeOf('goo', 'string'); + assert.typeOf(42, 'number'); + assert.typeOf([], 'array'); + assert.typeOf({}, 'object'); + assert.typeOf(false, 'boolean'); + }, + "`instanceOf`": function () { + assert.instanceOf([], Array); + assert.instanceOf(function () {}, Function); + }, + "`isArray`": function () { + assert.isArray([]); + assertError(assert.isArray, {}); + }, + "`isString`": function () { + assert.isString(""); + }, + "`isObject`": function () { + assert.isObject({}); + assertError(assert.isObject, []); + }, + "`isNumber`": function () { + assert.isNumber(0); + }, + "`isBoolean`": function (){ + assert.isBoolean(true); + assert.isBoolean(false); + assertError(assert.isBoolean, 0); + }, + "`isNan`": function () { + assert.isNaN(0/0); + }, + "`isTrue`": function () { + assert.isTrue(true); + assertError(assert.isTrue, 1); + }, + "`isFalse`": function () { + assert.isFalse(false); + assertError(assert.isFalse, 0); + }, + "`isZero`": function () { + assert.isZero(0); + assertError(assert.isZero, null); + }, + "`isNotZero`": function () { + assert.isNotZero(1); + }, + "`isUndefined`": function () { + assert.isUndefined(undefined); + assertError(assert.isUndefined, null); + }, + "`isDefined`": function () { + assert.isDefined(null); + assertError(assert.isDefined, undefined); + }, + "`isNull`": function () { + assert.isNull(null); + assertError(assert.isNull, 0); + assertError(assert.isNull, undefined); + }, + "`isNotNull`": function () { + assert.isNotNull(0); + }, + "`greater` and `lesser`": function () { + assert.greater(5, 4); + assert.lesser(4, 5); + }, + "`inDelta`": function () { + assert.inDelta(42, 40, 5); + assert.inDelta(42, 40, 2); + assert.inDelta(42, 42, 0); + assert.inDelta(3.1, 3.0, 0.2); + assertError(assert.inDelta, [42, 40, 1]); + }, + "`isEmpty`": function () { + assert.isEmpty({}); + assert.isEmpty([]); + assert.isEmpty(""); + }, + "`isNotEmpty`": function () { + assert.isNotEmpty({goo:true}); + assert.isNotEmpty([1]); + assert.isNotEmpty(" "); + assertError(assert.isNotEmpty, {}); + assertError(assert.isNotEmpty, []); + assertError(assert.isNotEmpty, ""); + } + } +}).export(module); + +function assertError(assertion, args, fail) { + if (!Array.isArray(args)) { args = [args]; } + try { + assertion.apply(null, args); + fail = true; + } catch (e) {/* Success */} + + fail && assert.fail(args.join(' '), assert.AssertionError, + "expected an AssertionError for {actual}", + "assertError", assertError); +} + diff --git a/test/fixtures/isolate/failing.js b/test/fixtures/isolate/failing.js new file mode 100644 index 00000000..7a1865ef --- /dev/null +++ b/test/fixtures/isolate/failing.js @@ -0,0 +1,18 @@ +var vows = require('../../../lib/vows'), + assert = require('assert'); + +var obvious; +vows.describe('failing').addBatch({ + 'Obvious test': obvious = { + topic: function () { + this.callback(null, false); + }, + 'should work': function (result) { + assert.ok(result); + } + // but it won't + }, + 'Obvious test #2': obvious, + 'Obvious test #3': obvious, + 'Obvious test #4': obvious +}).export(module); diff --git a/test/fixtures/isolate/log.js b/test/fixtures/isolate/log.js new file mode 100644 index 00000000..98280458 --- /dev/null +++ b/test/fixtures/isolate/log.js @@ -0,0 +1,18 @@ +var vows = require('../../../lib/vows'), + assert = require('assert'); + +var obvious; +vows.describe('stderr').addBatch({ + 'Obvious test': obvious = { + topic: function () { + this.callback(null, true); + }, + 'should work': function (result) { + console.log('oh no!'); + assert.ok(result); + } + }, + 'Obvious test #2': obvious, + 'Obvious test #3': obvious, + 'Obvious test #4': obvious +}).export(module); diff --git a/test/fixtures/isolate/passing.js b/test/fixtures/isolate/passing.js new file mode 100644 index 00000000..7f95730d --- /dev/null +++ b/test/fixtures/isolate/passing.js @@ -0,0 +1,17 @@ +var vows = require('../../../lib/vows'), + assert = require('assert'); + +var obvious; +vows.describe('passing').addBatch({ + 'Obvious test': obvious = { + topic: function () { + this.callback(null, true); + }, + 'should work': function (result) { + assert.ok(result); + } + }, + 'Obvious test #2': obvious, + 'Obvious test #3': obvious, + 'Obvious test #4': obvious +}).export(module); diff --git a/test/fixtures/isolate/stderr.js b/test/fixtures/isolate/stderr.js new file mode 100644 index 00000000..545ad20f --- /dev/null +++ b/test/fixtures/isolate/stderr.js @@ -0,0 +1,18 @@ +var vows = require('../../../lib/vows'), + assert = require('assert'); + +var obvious; +vows.describe('stderr').addBatch({ + 'Obvious test': obvious = { + topic: function () { + this.callback(null, true); + }, + 'should work': function (result) { + console.error('oh no!'); + assert.ok(result); + } + }, + 'Obvious test #2': obvious, + 'Obvious test #3': obvious, + 'Obvious test #4': obvious +}).export(module); diff --git a/test/fixtures/supress-stdout/output.js b/test/fixtures/supress-stdout/output.js new file mode 100644 index 00000000..e5c16350 --- /dev/null +++ b/test/fixtures/supress-stdout/output.js @@ -0,0 +1,16 @@ +var vows = require('../../../lib/vows'), + assert = require('assert'); + +vows.describe('output').addBatch({ + 'outputting': { + topic: function () { + console.log('goo'); + this.callback(null, true); + }, + 'should work': function (result) { + console.log('goo'); + assert.ok(result); + } + }, +}).export(module); + diff --git a/test/isolate-test.js b/test/isolate-test.js new file mode 100644 index 00000000..40f993bd --- /dev/null +++ b/test/isolate-test.js @@ -0,0 +1,140 @@ +var vows = require('../lib/vows'), + assert = require('assert'), + path = require('path'), + exec = require('child_process').exec; + +function generateTopic(args, file) { + return function () { + var cmd = './bin/vows' + ' -i ' + (args || '') + + ' ./test/fixtures/isolate/' + file, + options = {cwd: path.resolve(__dirname + '/../')}, + callback = this.callback; + + exec(cmd, options, function (err, stdout, stderr) { + callback(null, { + err: err, + stdout: stdout, + stderr: stderr + }); + }); + } +}; + +function assertExecOk(r) { + assert.isNull(r.err); +} + +function assertExecNotOk(r) { + assert.isNotNull(r.err); +} + +function parseResults(stdout) { + return stdout.split(/\n/g).map(function (s) { + if (!s) return; + return JSON.parse(s); + }).filter(function (s) {return s}); +} + +function assertResultTypePresent(results, type) { + assert.ok(results.some(function (result) { + return result[0] == type; + })); +} + +function assertResultsFinish(results, expected) { + var finish = results[results.length - 1]; + assert.equal(finish[0], 'finish'); + + finish = finish[1]; + + Object.keys(expected).forEach(function (key) { + assert.equal(finish[key], expected[key]); + }); +} + +vows.describe('vows/isolate').addBatch({ + 'Running vows with -i flag for test/fixtures/isolate/': { + 'passing.js': { + 'with default reporter': { + topic: generateTopic(null, 'passing.js'), + 'should be ok': assertExecOk + }, + 'with json reporter': { + topic: generateTopic('--json', 'passing.js'), + 'should be ok': assertExecOk, + 'should have correct output': function (r) { + var results = parseResults(r.stdout) + + assertResultTypePresent(results, 'subject'); + assertResultTypePresent(results, 'end'); + + assertResultsFinish(results, { + total: 4, + honored: 4 + }); + } + } + }, + 'failing.js': { + 'with json reporter': { + topic: generateTopic('--json', 'failing.js'), + 'should be not ok': assertExecNotOk, + 'should have correct output though': function (r) { + var results = parseResults(r.stdout); + + assertResultsFinish(results, { + total: 4, + broken: 4 + }); + } + } + }, + 'stderr.js': { + 'with json reporter': { + topic: generateTopic('--json', 'stderr.js'), + 'should be ok': assertExecOk, + 'should have stderr': function (r) { + assert.equal(r.stderr, + ['oh no!', 'oh no!', 'oh no!', 'oh no!', ''].join('\n')); + }, + 'should have correct output': function (r) { + var results= parseResults(r.stdout); + + assertResultsFinish(results, { + total: 4, + honored: 4 + }); + } + } + }, + 'log.js': { + 'with json reporter': { + topic: generateTopic('--json', 'log.js'), + 'should be ok': assertExecOk, + 'should have correct output': function (r) { + var results= parseResults(r.stdout); + + assertResultsFinish(results, { + total: 4, + honored: 4 + }); + } + } + }, + 'all tests (*)': { + 'with json reporter': { + topic: generateTopic('--json', '*'), + 'should be not ok': assertExecNotOk, + 'should have correct output': function (r) { + var results= parseResults(r.stdout); + + assertResultsFinish(results, { + total: 16, + broken: 4, + honored: 12 + }); + } + } + } + } +}).export(module); diff --git a/test/standalone.js b/test/standalone.js deleted file mode 100644 index bffcd79a..00000000 --- a/test/standalone.js +++ /dev/null @@ -1,54 +0,0 @@ -// standalone.js -- A test script that uses vows -// -// Copyright 2016, 2017 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const fs = require('fs') - -const vows = require('../lib/index') -const assert = vows.assert - -vows.describe('run() test') - .addBatch({ - 'When we open a file': { - topic () { - fs.open('/tmp/fakefile', 'w', this.callback) - return undefined - }, - 'it works' (err, fd) { - assert.ifError(err) - return assert.isNumber(fd) - }, - teardown (fd) { - fs.close(fd, this.callback) - return undefined - }, - 'and we write to the file': { - topic (fd) { - fs.write(fd, 'My dog has fleas\n', this.callback) - return undefined - }, - 'it works' (err, written, buffer) { - assert.ifError(err) - assert.greater(written, 0) - return assert.isString(buffer) - } - } - } - }) - .run() diff --git a/test/supress-stdout-test.js b/test/supress-stdout-test.js new file mode 100644 index 00000000..2321e4d2 --- /dev/null +++ b/test/supress-stdout-test.js @@ -0,0 +1,43 @@ +var assert = require('assert'), + path = require('path'), + vows = require('../lib/vows'), + exec = require('child_process').exec; + +function generateTopic(supress) { + return function () { + var cmd = './bin/vows ' + (supress ? '--supress-stdout ' : '') + + './test/fixtures/supress-stdout/output.js', + options = {cwd: path.resolve(__dirname + '/../')}, + callback = this.callback; + + exec(cmd, options, function (err, stdout) { + callback(null, {err: err, stdout: stdout}); + }); + }; +} + +vows.describe('vows/supress-stdout').addBatch({ + 'Running vows for test/fixtures/supress-stdout/output.js': { + 'with --supress-stdout flag': { + topic: generateTopic(true), + 'should be ok': function (result) { + assert.isNull(result.err); + }, + 'should not contain output from stdout': function (result) { + assert.equal(result.stdout.toString().indexOf('goo'), -1); + // console.log output? + // nope, just Chuck Testa! + } + }, + 'without --supress-stdout flag': { + topic: generateTopic(), + 'should be ok': function (result) { + assert.isNull(result.err); + }, + 'should contain output from stdout': function (result) { + assert.notEqual(result.stdout.toString().indexOf('goo'), -1); + } + } + } +}).export(module); + diff --git a/test/test-assert-greater.js b/test/test-assert-greater.js deleted file mode 100644 index c6fd2adf..00000000 --- a/test/test-assert-greater.js +++ /dev/null @@ -1,69 +0,0 @@ -// test-assert-greater.js -- Test assert.greater() -// -// Copyright 2017 Fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const vows = require('../lib/index') -const assert = vows.assert - -const shouldSucceed = (actual, expected) => { - const batch = { - topic () { - try { - assert.greater(actual, expected) - this.callback(null) - } catch (err) { - this.callback(err) - } - }, - 'it works': (err) => { - assert.ifError(err) - } - } - return batch -} - -const shouldFail = (actual, expected) => { - const batch = { - topic () { - try { - assert.greater(actual, expected) - this.callback(new Error('Unexpected success')) - } catch (err) { - this.callback(null) - } - }, - 'it works': (err) => { - assert.ifError(err) - } - } - return batch -} - -vows - .describe('assert.greater()') - .addBatch({ - 'When actual > extended': shouldSucceed(2, 1) - }) - .addBatch({ - 'When actual < extended': shouldFail(1, 2) - }) - .addBatch({ - 'When actual == extended': shouldFail(1, 1) - }) - .export(module) diff --git a/test/test-assert-root.js b/test/test-assert-root.js deleted file mode 100644 index 3e5f6984..00000000 --- a/test/test-assert-root.js +++ /dev/null @@ -1,56 +0,0 @@ -// test-assert-root.js -- Test assert() -// -// Copyright 2017 AJ Jordan -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const vows = require('../lib/index') -const assert = vows.assert - -vows - .describe('bare assert()') - .addBatch({ - 'When we assert(true)': { - topic () { - try { - assert(true) - this.callback(null) - } catch (err) { - this.callback(err) - } - }, - 'it succeeds': (err) => { - assert.ifError(err) - } - } - }) - .addBatch({ - 'When we assert(false)': { - topic () { - try { - assert(false) - this.callback(new Error('Unexpected success')) - } catch (err) { - this.callback(null) - } - }, - 'it fails': (err) => { - assert.ifError(err) - } - } - }) - .export(module) diff --git a/test/test-async-function.js b/test/test-async-function.js deleted file mode 100644 index a352fcd7..00000000 --- a/test/test-async-function.js +++ /dev/null @@ -1,49 +0,0 @@ -// atest-async-function.js -- Test async topic -// -// Copyright 2017 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const fs = require('fs') - -const promisify = require('util-promisify') - -const vows = require('../lib/index') -const assert = vows.assert - -const open = promisify(fs.open) -const close = promisify(fs.close) - -vows - .describe('using an async function as a topic and teardown') - .addBatch({ - 'When we create a topic that returns a Promise': { - topic: async function () { - const result = await open('/tmp/fakefile', 'w') - return result - }, - 'it works': (err, fd) => { - assert.ifError(err) - assert.isNumber(fd, (fd instanceof Promise) ? 'fd is a Promise' : 'fd is not a number') - }, - teardown: async function (fd) { - const result = await close(fd) - return result - } - } - }) - .export(module) diff --git a/test/test-asynchronous-callback-arguments.js b/test/test-asynchronous-callback-arguments.js deleted file mode 100644 index f75e5cbf..00000000 --- a/test/test-asynchronous-callback-arguments.js +++ /dev/null @@ -1,78 +0,0 @@ -// test-asynchronous-callback-arguments.js -// Tests for different kinds of callback arguments -// -// Copyright 2016 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const vows = require('../lib/index') -const assert = vows.assert - -vows - .describe('Asynchronous topic callback arguments') - .addBatch({ - 'When we use the async callback with a single argument': { - topic () { - this.callback(null, 42) - return undefined - }, - 'it works': (err, value) => { - assert.ifError(err) - assert.isNumber(value) - assert.equal(value, 42) - } - } - }) - .addBatch({ - 'When we use the async callback with multiple arguments': { - topic () { - this.callback(null, 4, 8) - return undefined - }, - 'it works': (err, value1, value2) => { - assert.ifError(err) - assert.isNumber(value1) - assert.equal(value1, 4) - assert.isNumber(value2) - assert.equal(value2, 8) - } - } - }) - .addBatch({ - 'When we use the async callback with no arguments': { - topic () { - this.callback() - return undefined - }, - 'it works': (err) => { - assert.ifError(err) - } - } - }) - .addBatch({ - 'When we use the async callback without explicitly returning undefined': { - topic () { - this.callback(null, 23) - }, - 'it works': (err, value) => { - assert.ifError(err) - assert.isNumber(value) - assert.equal(value, 23) - } - } - }) - .export(module) diff --git a/test/test-at-most-once.js b/test/test-at-most-once.js deleted file mode 100644 index 04baac7c..00000000 --- a/test/test-at-most-once.js +++ /dev/null @@ -1,64 +0,0 @@ -// test-at-most-once.js -- Test atMostOnce() -// -// Copyright 2017 Fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const vows = require('../lib/index') -const assert = vows.assert - -const atMostOnce = require('../lib/at-most-once') - -vows - .describe('atMostOnce()') - .addBatch({ - 'When we call a wrapped function once': { - topic () { - const sqr = x => x * x - const wsqr = atMostOnce(sqr) - return wsqr(3) - }, - 'it works': (err, result) => { - assert.ifError(err) - assert.isNumber(result) - assert.equal(result, 9) - } - } - }) - .addBatch({ - 'When we call a wrapped function twice': { - topic () { - try { - const sqr = x => x * x - const wsqr = atMostOnce(sqr) - wsqr(3) - wsqr(4) - this.callback(new Error('No error from calling wrapped function twice')) - } catch (err) { - if (err.name === 'AtMostOnceError') { - this.callback(null) - } else { - this.callback(err) - } - } - }, - 'it fails correctly': (err) => { - assert.ifError(err) - } - } - }) - .export(module) diff --git a/test/test-batch-report.js b/test/test-batch-report.js deleted file mode 100644 index bf11836a..00000000 --- a/test/test-batch-report.js +++ /dev/null @@ -1,246 +0,0 @@ -// test-batch-report.js -- Test the use of batches -// -// Copyright 2016 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const vows = require('../lib/index') -const Batch = require('../lib/batch') -const Report = require('../lib/report') -const assert = vows.assert - -const br = (title, broken, successes, failures, def) => { - const bd = {} - bd[title] = { - topic () { - const batch = new Batch(title, def) - batch.run([], this.callback) - }, - 'it works': (err, report) => { - assert.ifError(err) - }, - 'it returns a report': (err, report) => { - assert.ifError(err) - assert.instanceOf(report, Report) - }, - 'it has the right number of broken results': (err, report) => { - assert.ifError(err) - assert.isObject(report) - assert.equal(report.broken, broken) - }, - 'it has the right number of successful results': (err, report) => { - assert.ifError(err) - assert.isObject(report) - assert.equal(report.successes, successes) - }, - 'it has the right number of failure results': (err, report) => { - assert.ifError(err) - assert.isObject(report) - assert.equal(report.failures, failures) - } - } - return bd -} - -vows.describe('batch report') - .addBatch(br('When we run a batch with only successes', 0, 3, 0, { - topic () { - return 3 - }, - 'it works': (err, result) => { - assert.ifError(err) - }, - 'it is the correct value': (err, result) => { - assert.ifError(err) - assert.equal(result, 3) - }, - 'it is a number': (err, result) => { - assert.ifError(err) - assert.isNumber(result) - } - } - )) - .addBatch(br('When we run a batch with sub-batches', 0, 6, 0, { - topic () { - return 3 - }, - 'it works': (err, result) => { - assert.ifError(err) - }, - 'it is the correct value': (err, result) => { - assert.ifError(err) - assert.equal(result, 3) - }, - 'it is a number': (err, result) => { - assert.ifError(err) - assert.isNumber(result) - }, - 'and we run some sub-batches': { - topic () { - return 4 - }, - 'it works': (err, results) => { - assert.ifError(err) - }, - 'it returns a number': (err, results) => { - assert.ifError(err) - assert.isNumber(results) - }, - 'it has the right value': (err, results) => { - assert.ifError(err) - assert.equal(results, 4) - } - } - } - )) - .addBatch(br('When we run a batch with failures', 0, 2, 2, { - topic () { - return 3 - }, - 'it works': (err, result) => { - assert.ifError(err) - }, - 'it is a number': (err, result) => { - assert.ifError(err) - assert.isNumber(result) - }, - 'it equals 4': (err, result) => { - assert.ifError(err) - assert.equal(result, 4) - }, - 'it is greater than 7': (err, result) => { - assert.ifError(err) - assert.greater(result, 7) - } - } - )) - .addBatch(br('When we run a batch with failures in the sub-batches', 0, 6, 4, { - topic () { - return 3 - }, - 'it works': (err, result) => { - assert.ifError(err) - }, - 'it is a number': (err, result) => { - assert.ifError(err) - assert.isNumber(result) - }, - 'and we run a sub-batch': { - topic () { - return 2 - }, - 'it works': (err, result) => { - assert.ifError(err) - }, - 'it is a number': (err, result) => { - assert.ifError(err) - assert.isNumber(result) - }, - 'it equals 4': (err, result) => { - assert.ifError(err) - assert.equal(result, 4) - }, - 'it is greater than 7': (err, result) => { - assert.ifError(err) - assert.greater(result, 7) - } - }, - 'and we run another sub-batch': { - topic () { - return 5 - }, - 'it works': (err, result) => { - assert.ifError(err) - }, - 'it is a number': (err, result) => { - assert.ifError(err) - assert.isNumber(result) - }, - 'it equals 4': (err, result) => { - assert.ifError(err) - assert.equal(result, 4) - }, - 'it is greater than 7': (err, result) => { - assert.ifError(err) - assert.greater(result, 7) - } - } - } - )) - .addBatch(br('When we run a batch with an error', 1, 2, 3, { - topic () { - this.callback(new Error('Sample error'), 3) - return undefined - }, - 'it works': (err, result) => { - assert.ifError(err) - }, - // eslint-disable-next-line handle-callback-err - 'it is a number': (err, result) => { - assert.isNumber(result) - }, - // eslint-disable-next-line handle-callback-err - 'it is the right value': (err, result) => { - assert.equal(result, 3) - }, - // eslint-disable-next-line handle-callback-err - 'it is greater than 7': (err, result) => { - assert.greater(result, 7) - }, - // eslint-disable-next-line handle-callback-err - 'it is less than 0': (err, result) => { - assert.lesser(result, 0) - } - } - )) - .addBatch(br('When we run a batch with a sub-batch with an error', 1, 3, 3, { - topic () { - return 4 - }, - 'it works': (err, result) => { - assert.ifError(err) - assert.isNumber(result) - assert.equal(result, 4) - }, - 'and we run the sub-batch': { - topic () { - this.callback(new Error('Sample error'), 3) - return undefined - }, - 'it works': (err, result) => { - assert.ifError(err) - }, - // eslint-disable-next-line handle-callback-err - 'it is a number': (err, result) => { - assert.isNumber(result) - }, - // eslint-disable-next-line handle-callback-err - 'it is the right value': (err, result) => { - assert.equal(result, 3) - }, - // eslint-disable-next-line handle-callback-err - 'it is greater than 7': (err, result) => { - assert.greater(result, 7) - }, - // eslint-disable-next-line handle-callback-err - 'it is less than 0': (err, result) => { - assert.lesser(result, 0) - } - } - } - )) - .export(module) diff --git a/test/test-callback-synchronous.js b/test/test-callback-synchronous.js deleted file mode 100644 index 1693f772..00000000 --- a/test/test-callback-synchronous.js +++ /dev/null @@ -1,47 +0,0 @@ -// test-callback-synchronous.js -- warn on synchronous calls to this.callback -// -// Copyright 2017 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -const vows = require('../lib/index') -const assert = vows.assert - -const Batch = require('../lib/batch') -const Report = require('../lib/report') - -vows.describe('Calling this.callback() synchronously') - .addBatch({ - 'When we run a batch that calls this.callback() synchronously': { - topic () { - const b = new Batch('When we add two numbers', { - topic () { - this.callback(null, 2 + 2) - return undefined - }, - 'it works': (err, result) => { - assert.ifError(err) - assert.isNumber(result) - assert.equal(result, 4) - } - }) - - b.run([], this.callback) - }, - 'it works': (err, report) => { - assert.ifError(err) - assert.instanceOf(report, Report) - } - } - }) - .export(module) diff --git a/test/test-export.coffee b/test/test-export.coffee deleted file mode 100644 index 33cf6980..00000000 --- a/test/test-export.coffee +++ /dev/null @@ -1,48 +0,0 @@ -# test-export.coffee -- A test script that uses vows -# -# Copyright 2016 fuzzy.ai -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -### jshint esversion: 6 ### - -'use strict' - -fs = require('fs') - -_ = require('lodash') - -vows = require('../lib/index') -assert = vows.assert - -vows.describe 'Coffeescript test' - .addBatch - 'When we open a file': - topic: -> - fs.open '/tmp/fakefile', 'w', @callback - undefined - 'it works': (err, fd) -> - assert.ifError err - assert.isNumber fd - teardown: (fd) -> - fs.close fd, @callback - undefined - 'and we write to the file': - topic: (fd) -> - fs.write fd, 'My dog has fleas\n', @callback - undefined - 'it works': (err, written, buffer) -> - assert.ifError err - assert.greater written, 0 - assert.isString buffer - .export(module) diff --git a/test/test-export.js b/test/test-export.js deleted file mode 100644 index 9bceb0f7..00000000 --- a/test/test-export.js +++ /dev/null @@ -1,55 +0,0 @@ -// test-export.js -- A test script that uses vows -// -// Copyright 2016 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const fs = require('fs') - -const vows = require('../lib/index') -const assert = vows.assert - -vows - .describe('export(module) test') - .addBatch({ - 'When we open a file': { - topic () { - fs.open('/tmp/fakefile', 'w', this.callback) - return undefined - }, - 'it works' (err, fd) { - assert.ifError(err) - return assert.isNumber(fd) - }, - teardown (fd) { - fs.close(fd, this.callback) - return undefined - }, - 'and we write to the file': { - topic (fd) { - fs.write(fd, 'My dog has fleas\n', this.callback) - return undefined - }, - 'it works' (err, written, buffer) { - assert.ifError(err) - assert.greater(written, 0) - return assert.isString(buffer) - } - } - } - }) - .export(module) diff --git a/test/test-multiple-batch-async.js b/test/test-multiple-batch-async.js deleted file mode 100644 index 7e97fccf..00000000 --- a/test/test-multiple-batch-async.js +++ /dev/null @@ -1,48 +0,0 @@ -// test-multiple-batch.js -- Multiple calls to addBatch() with async results -// -// Copyright 2016 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const vows = require('../lib/index') -const assert = vows.assert - -const numberBatchAsync = (num) => { - const batch = {} - batch[`When we return ${num}`] = { - topic () { - this.callback(null, num) - return undefined - }, - 'it works': (err, value) => { - assert.ifError(err) - assert.isNumber(value) - assert.equal(value, num) - } - } - return batch -} - -vows - .describe('Multiple addBatch() calls with async results') - .addBatch(numberBatchAsync(4)) - .addBatch(numberBatchAsync(8)) - .addBatch(numberBatchAsync(15)) - .addBatch(numberBatchAsync(16)) - .addBatch(numberBatchAsync(23)) - .addBatch(numberBatchAsync(42)) - .export(module) diff --git a/test/test-multiple-batch.js b/test/test-multiple-batch.js deleted file mode 100644 index 27949eee..00000000 --- a/test/test-multiple-batch.js +++ /dev/null @@ -1,48 +0,0 @@ -// test-multiple-batch.js -- Multiple calls to addBatch() -// -// Copyright 2016 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const vows = require('../lib/index') -const assert = vows.assert - -// benedict -const numberBatch = (num) => { - const batch = {} - batch[`When we return ${num}`] = { - topic () { - return num - }, - 'it works': (err, value) => { - assert.ifError(err) - assert.isNumber(value) - assert.equal(value, num) - } - } - return batch -} - -vows - .describe('Multiple addBatch() calls') - .addBatch(numberBatch(4)) - .addBatch(numberBatch(8)) - .addBatch(numberBatch(15)) - .addBatch(numberBatch(16)) - .addBatch(numberBatch(23)) - .addBatch(numberBatch(42)) - .export(module) diff --git a/test/test-promise-resolve-empty-arguments.js b/test/test-promise-resolve-empty-arguments.js deleted file mode 100644 index b765eb62..00000000 --- a/test/test-promise-resolve-empty-arguments.js +++ /dev/null @@ -1,62 +0,0 @@ -// test-promise-resolve-empty-arguments.js -- Promise resolves with empty arguments -// -// Copyright 2017 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const vows = require('../lib/index') -const assert = vows.assert - -vows - .describe('A promise that resolves with no arguments') - .addBatch({ - 'When we return a value': { - topic () { - return 42 - }, - 'it works': (err, num) => { - assert.ifError(err) - assert.isNumber(num) - assert.equal(num, 42) - }, - 'and we have a promise that resolves with no arguments': { - topic () { - return new Promise((resolve, reject) => { - resolve() - }) - }, - 'it works': (err, empty) => { - assert.ifError(err) - assert.isUndefined(empty) - }, - 'and we examine the stack in the topic of a sub-batch': { - topic (empty, num) { - // In the error condition num is undefined, so we go - // async by default - this.callback(null, num) - return undefined - }, - 'the correct arguments are available': (err, num) => { - assert.ifError(err) - assert.isNumber(num) - assert.equal(num, 42) - } - } - } - } - }) - .export(module) diff --git a/test/test-promise.js b/test/test-promise.js deleted file mode 100644 index 8505c766..00000000 --- a/test/test-promise.js +++ /dev/null @@ -1,58 +0,0 @@ -// test-promise.js -- Test returning a promise from the topic -// -// Copyright 2017 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const fs = require('fs') - -const vows = require('../lib/index') -const assert = vows.assert - -vows - .describe('returning a Promise from a topic') - .addBatch({ - 'When we create a topic that returns a Promise': { - topic () { - return new Promise((resolve, reject) => { - fs.open('/tmp/fakefile', 'w', (err, fd) => { - if (err) { - reject(err) - } else { - resolve(fd) - } - }) - }) - }, - 'it works': (err, fd) => { - assert.ifError(err) - assert.isNumber(fd, (fd instanceof Promise) ? 'fd is a Promise' : 'fd is not a number') - }, - teardown: (fd) => { - return new Promise((resolve, reject) => { - fs.close(fd, (err) => { - if (err) { - reject(err) - } else { - resolve() - } - }) - }) - } - } - }) - .export(module) diff --git a/test/test-static-topic.js b/test/test-static-topic.js deleted file mode 100644 index 5cc15071..00000000 --- a/test/test-static-topic.js +++ /dev/null @@ -1,33 +0,0 @@ -// test-static-topic.js -- A topic that is not a function -// -// Copyright 2018 Fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -'use strict' - -const vows = require('../lib/index') -const assert = vows.assert - -vows.describe('topic that is not a function') - .addBatch({ - 'When we use a static topic': { - topic: 42, - 'it works' (err, data) { - assert.ifError(err) - assert.isNumber(data) - assert.equal(data, 42) - } - } - }) - .export(module) diff --git a/test/test-this-callback.js b/test/test-this-callback.js deleted file mode 100644 index 2018f7d4..00000000 --- a/test/test-this-callback.js +++ /dev/null @@ -1,51 +0,0 @@ -// test-this-callback.js -- Test this.callback() -// -// Copyright 2017 AJ Jordan -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const vows = require('../lib/index') -const assert = vows.assert - -vows - .describe('this.callback()') - .addBatch({ - 'this.callback': { - topic () { - // We can't return this.callback directly because if it's undefined, vows thinks it's an async batch - return { cb: this.callback } - }, - 'is a function': (err, obj) => { - assert.ifError(err) - assert.isObject(obj) - const cb = obj.cb - assert.isFunction(cb) - }, - 'in a sub-batch': { - topic () { - return { cb: this.callback } - }, - 'is a function': (err, obj) => { - assert.ifError(err) - assert.isObject(obj) - const cb = obj.cb - assert.isFunction(cb) - } - } - } - }) - .export(module) diff --git a/test/test-topic-argument.js b/test/test-topic-argument.js deleted file mode 100644 index 524ad98b..00000000 --- a/test/test-topic-argument.js +++ /dev/null @@ -1,116 +0,0 @@ -// test-topic-argument.js -- Test passing arguments to sub-batches -// -// Copyright 2016 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const debug = require('debug')('vows:test-topic-argument') - -const vows = require('../lib/index') -const assert = vows.assert - -const js = JSON.stringify - -vows - .describe('topic argument test') - .addBatch({ - 'When we return a value from a topic synchronously': { - topic () { - debug(`a batch arguments: ${js(arguments)}`) - return 'a' - }, - 'it is passed down to the tests': (err, val1) => { - assert.ifError(err) - assert.isString(val1) - assert.equal(val1, 'a') - }, - 'and we add a sub-batch': { - topic (val1) { - debug(`a-b sub-batch arguments: ${js(arguments)}`) - assert.isString(val1, 'First argument to a-b sub-batch is not a string') - assert.equal(val1, 'a', "First argument to a-b sub-batch is not 'a' string") - return 'b' - }, - 'its value is passed to tests': (err, val2) => { - assert.ifError(err) - assert.isString(val2) - assert.equal(val2, 'b') - }, - 'and we add a sub-sub-batch': { - topic (val2, val1) { - debug(`a-b-c sub-batch arguments: ${js(arguments)}`) - assert.isString(val1, 'Second argument to a-b-c sub-batch is not a string') - assert.equal(val1, 'a', "Second argument to a-b-c sub-batch is not 'a' string") - assert.isString(val2, 'Second argument to a-b-c sub-batch is not a string') - assert.equal(val2, 'b', "Second argument to a-b-c sub-batch is not 'a' string") - return 'c' - }, - 'its value is passed to tests': (err, val3) => { - assert.ifError(err) - assert.isString(val3) - assert.equal(val3, 'c') - } - } - }, - 'and we add a different sub-batch': { - topic (val1) { - debug(`a-d sub-batch arguments: ${js(arguments)}`) - assert.isString(val1, 'First argument to a-d sub-batch is not a string') - assert.equal(val1, 'a', "First argument to a-d sub-batch is not 'a' string") - return 'd' - }, - 'its value is passed to tests': (err, val4) => { - assert.ifError(err) - assert.isString(val4) - assert.equal(val4, 'd') - }, - 'and we add a different sub-sub-batch': { - topic (val4, val1) { - debug(`a-d-e sub-batch arguments: ${js(arguments)}`) - assert.isString(val1, 'Second argument to a-d-e sub-batch is not a string') - assert.equal(val1, 'a', "Second argument to a-d-e sub-batch is not 'a' string") - assert.isString(val4, 'First argument to a-d-e sub-batch is not a string') - assert.equal(val4, 'd', "First argument to a-d-e sub-batch is not 'd'") - return 'e' - }, - 'its value is passed to tests': (err, val5) => { - assert.ifError(err) - assert.isString(val5) - assert.equal(val5, 'e') - }, - 'and we add a sub-sub-sub-batch': { - topic (val5, val4, val1) { - debug(`a-d-e-f sub-batch arguments: ${js(arguments)}`) - assert.isString(val1, 'Third argument to a-d-e sub-batch is not a string') - assert.equal(val1, 'a', "Third argument to a-d-e sub-batch is not 'a' string") - assert.isString(val4, 'Second argument to a-d-e sub-batch is not a string') - assert.equal(val4, 'd', "Second argument to a-d-e sub-batch is not 'd'") - assert.isString(val5, 'First argument to a-d-e sub-batch is not a string') - assert.equal(val5, 'e', "First argument to a-d-e sub-batch is not 'e'") - return 'f' - }, - 'its value is passed to tests': (err, val6) => { - assert.ifError(err) - assert.isString(val6) - assert.equal(val6, 'f') - } - } - } - } - } - }) - .export(module) diff --git a/test/test-topic-error.js b/test/test-topic-error.js deleted file mode 100644 index 0576f93a..00000000 --- a/test/test-topic-error.js +++ /dev/null @@ -1,99 +0,0 @@ -// test-topic-error.js -- Test topics that throw errors -// -// Copyright 2016 fuzzy.ai -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* jshint esversion: 6 */ - -'use strict' - -const fs = require('fs') - -const vows = require('../lib/index') -const assert = vows.assert - -vows - .describe('throwing an error in a topic') - .addBatch({ - 'When we create a suite that throws an error': { - topic () { - const suite = vows.describe('internal sub suite') - suite.addBatch({ - 'When we throw an error in a topic': { - topic () { - throw new Error('Test error') - }, - 'it is passed on to tests': (err) => { - assert.isObject(err) - assert.instanceOf(err, Error) - assert.equal(err.message, 'Test error') - }, - 'sub batches are not run': { - topic () { - throw new Error('This batch should not be run') - }, - 'sub-batch tests are not run': (err) => { - assert.ifError(err) - } - } - } - }) - suite.addBatch({ - 'When we use the async callback with an error argument': { - topic () { - this.callback(new Error('Oh no Mr. Bill')) - return undefined - }, - 'it works': (err) => { - assert.isObject(err) - assert.instanceOf(err, Error) - assert.equal(err.message, 'Oh no Mr. Bill') - }, - 'sub-batch is not called': { - topic () { - throw new Error("sub-batch shouldn't be called if parent errored") - }, - 'it is not called': (err) => { - assert.ifError(err) - } - } - } - }) - return suite - }, - 'it works': (err, suite) => { - assert.ifError(err) - assert.isObject(suite) - }, - 'and we run the suite': { - topic (suite) { - const callback = this.callback - const oldWrite = process.stdout.write - const redir = fs.createWriteStream('/dev/null', { defaultEncoding: 'utf8' }) - process.stdout.write = redir.write.bind(redir) - suite.run((err, broken, successes, failures) => { - process.stdout.write = oldWrite - callback(err, broken, successes, failures) - }) - }, - 'it works': (err, broken, successes, failures) => { - assert.ifError(err) - assert.isNumber(broken) - assert.isNumber(successes) - assert.isNumber(failures) - } - } - } - }) - .export(module) diff --git a/test/vows-error-test.js b/test/vows-error-test.js new file mode 100644 index 00000000..79afaba1 --- /dev/null +++ b/test/vows-error-test.js @@ -0,0 +1,51 @@ +var path = require('path'), + events = require('events'), + assert = require('assert'), + fs = require('fs'), + vows = require('../lib/vows'); + +function doSomethingAsync(callback) { + var err = null; + var testValue = 'a'; + + process.nextTick(function() { + callback(err, testValue); + }); +} + +function doSomethingAsyncWithError(callback) { + var err = true; + var testValue = 'a'; + + process.nextTick(function() { + callback(err, testValue); + }); +} + + +vows.describe('vows/error').addBatch({ + 'Generate success response to async function': { + topic: function() { + doSomethingAsync(this.callback) + }, + 'Validate success': function(err, testValue) { + assert.ok(!err); + }, + 'Validate testValue': function(err, testValue) { + assert.equal(testValue, 'a'); + } + }, + + 'Generate error response to async function': { + topic: function() { + doSomethingAsyncWithError(this.callback) + }, + 'Validate error': function(err, testValue) { + assert.ok(err); + }, + 'Validate testValue': function(err, testValue) { + // This assertion fails. It shouldn't. + assert.equal(testValue, 'a'); + } + } +}).export(module) \ No newline at end of file diff --git a/test/vows-test.js b/test/vows-test.js new file mode 100644 index 00000000..d539a54f --- /dev/null +++ b/test/vows-test.js @@ -0,0 +1,522 @@ +var path = require('path'), + events = require('events'), + assert = require('assert'), + fs = require('fs'), + vows = require('../lib/vows'); + +var api = vows.prepare({ + get: function (id, callback) { + process.nextTick(function () { callback(null, id) }); + }, + version: function () { return '1.0' } +}, ['get']); + +var promiser = function (val) { + return function () { + var promise = new(events.EventEmitter); + process.nextTick(function () { promise.emit('success', val) }); + return promise; + } +}; + +vows.describe("Vows").addBatch({ + "A context": { + topic: promiser("hello world"), + + "with a nested context": { + topic: function (parent) { + this.state = 42; + return promiser(parent)(); + }, + "has access to the environment": function () { + assert.equal(this.state, 42); + }, + "and a sub nested context": { + topic: function () { + return this.state; + }, + "has access to the parent environment": function (r) { + assert.equal(r, 42); + assert.equal(this.state, 42); + }, + "has access to the parent context object": function (r) { + assert.ok(Array.isArray(this.context.topics)); + assert.include(this.context.topics, "hello world"); + } + } + } + }, + "A nested context": { + topic: promiser(1), + + ".": { + topic: function (a) { return promiser(2)() }, + + ".": { + topic: function (b, a) { return promiser(3)() }, + + ".": { + topic: function (c, b, a) { return promiser([4, c, b, a])() }, + + "should have access to the parent topics": function (topics) { + assert.equal(topics.join(), [4, 3, 2, 1].join()); + } + }, + + "from": { + topic: function (c, b, a) { return promiser([4, c, b, a])() }, + + "the parent topics": function(topics) { + assert.equal(topics.join(), [4, 3, 2, 1].join()); + } + } + } + } + }, + "Nested contexts with callback-style async": { + topic: function () { + fs.stat(__dirname + '/vows-test.js', this.callback); + }, + 'after a successful `fs.stat`': { + topic: function (stat) { + fs.open(__dirname + '/vows-test.js', "r", stat.mode, this.callback); + }, + 'after a successful `fs.open`': { + topic: function (fd, stat) { + fs.read(fd, stat.size, 0, "utf8", this.callback); + }, + 'after a successful `fs.read`': function (data) { + assert.match (data, /after a successful `fs.read`/); + } + } + } + }, + "A nested context with no topics": { + topic: 45, + ".": { + ".": { + "should pass the value down": function (topic) { + assert.equal(topic, 45); + } + } + } + }, + "A Nested context with topic gaps": { + topic: 45, + ".": { + ".": { + topic: 101, + ".": { + ".": { + topic: function (prev, prev2) { + return this.context.topics.slice(0); + }, + "should pass the topics down": function (topics) { + assert.lengthOf(topics, 2); + assert.equal(topics[0], 101); + assert.equal(topics[1], 45); + } + } + } + } + } + }, + "A non-promise return value": { + topic: function () { return 1 }, + "should be converted to a promise": function (val) { + assert.equal(val, 1); + } + }, + "A 'prepared' interface": { + "with a wrapped function": { + topic: function () { return api.get(42) }, + "should work as expected": function (val) { + assert.equal(val, 42); + } + }, + "with a non-wrapped function": { + topic: function () { return api.version() }, + "should work as expected": function (val) { + assert.equal(val, '1.0'); + } + } + }, + "A non-function topic": { + topic: 45, + + "should work as expected": function (topic) { + assert.equal(topic, 45); + } + }, + "A non-function topic with a falsy value": { + topic: 0, + + "should work as expected": function (topic) { + assert.equal(topic, 0); + } + }, + "A topic returning a function": { + topic: function () { + return function () { return 42 }; + }, + + "should work as expected": function (topic) { + assert.isFunction(topic); + assert.equal(topic(), 42); + }, + "in a sub-context": { + "should work as expected": function (topic) { + assert.isFunction(topic); + assert.equal(topic(), 42); + }, + } + }, + "A topic with a function that errors": { + topic: function() { + throw("Something wrong here"); + }, + "should error out": function(topic) { + assert.equal(topic, "Something wrong here"); + } + }, + "A topic emitting an error": { + topic: function () { + var promise = new(events.EventEmitter); + process.nextTick(function () { + promise.emit("error", 404); + }); + return promise; + }, + "shouldn't raise an exception if the test expects it": function (e, res) { + assert.equal(e, 404); + assert.ok(! res); + } + }, + "A topic not emitting an error": { + topic: function () { + var promise = new(events.EventEmitter); + process.nextTick(function () { + promise.emit("success", true); + }); + return promise; + }, + "should pass `null` as first argument, if the test is expecting an error": function (e, res) { + assert.strictEqual(e, null); + assert.equal(res, true); + }, + "should pass the result as first argument if the test isn't expecting an error": function (res) { + assert.equal(res, true); + } + }, + "A topic with callback-style async": { + "when successful": { + topic: function () { + var that = this; + process.nextTick(function () { + that.callback(null, "OK"); + }); + }, + "should work like an event-emitter": function (res) { + assert.equal(res, "OK"); + }, + "should assign `null` to the error argument": function (e, res) { + assert.strictEqual(e, null); + assert.equal(res, "OK"); + } + }, + "when unsuccessful": { + topic: function () { + function async(callback) { + process.nextTick(function () { + callback("ERROR"); + }); + } + async(this.callback); + }, + "should have a non-null error value": function (e, res) { + assert.equal(e, "ERROR"); + }, + "should work like an event-emitter": function (e, res) { + assert.equal(res, undefined); + } + }, + "using this.callback synchronously": { + topic: function () { + this.callback(null, 'hello'); + }, + "should work the same as returning a value": function (res) { + assert.equal(res, 'hello'); + } + }, + "using this.callback with a user context": { + topic: function () { + this.callback.call({ boo: true }, null, 'hello'); + }, + "should give access to the user context": function (res) { + assert.isTrue(this.boo); + } + }, + "passing this.callback to a function": { + topic: function () { + this.boo = true; + var async = function (callback) { + callback(null); + }; + async(this.callback); + }, + "should give access to the topic context": function () { + assert.isTrue(this.boo); + } + }, + "with multiple arguments": { + topic: function () { + this.callback(null, 1, 2, 3); + }, + "should pass them to the vow": function (e, a, b, c) { + assert.strictEqual(e, null); + assert.strictEqual(a, 1); + assert.strictEqual(b, 2); + assert.strictEqual(c, 3); + }, + "and a sub-topic": { + topic: function (a, b, c) { + return [a, b, c]; + }, + "should receive them too": function (val) { + assert.deepEqual(val, [1, 2, 3]); + } + } + } + } +}).addBatch({ + "A Sibling context": { + "'A', with `this.foo = true`": { + topic: function () { + this.foo = true; + return this; + }, + "should have `this.foo` set to true": function (res) { + assert.equal(res.foo, true); + } + }, + "'B', with nothing set": { + topic: function () { + return this; + }, + "shouldn't have access to `this.foo`": function (e, res) { + assert.isUndefined(res.foo); + } + } + } +}).addBatch({ + "A 2nd batch": { + topic: function () { + var p = new(events.EventEmitter); + setTimeout(function () { + p.emit("success"); + }, 100); + return p; + }, + "should run after the first": function () {} + } +}).addBatch({ + "A 3rd batch": { + topic: true, "should run last": function () {} + } +}).addBatch({}).export(module); + +vows.describe("Vows with a single batch", { + "This is a batch that's added as the optional parameter to describe()": { + topic: true, + "And a vow": function () {} + } +}).export(module); + +vows.describe("Vows with multiple batches added as optional parameters", { + "First batch": { + topic: true, + "should be run first": function () {} + } +}, { + "Second batch": { + topic: true, + "should be run second": function () {} + } +}).export(module); + +vows.describe("Vows with teardowns").addBatch({ + "A context": { + topic: function () { + return { flag: true }; + }, + "And a vow": function (topic) { + assert.isTrue(topic.flag); + }, + "And another vow": function (topic) { + assert.isTrue(topic.flag); + }, + "And a final vow": function (topic) { + assert.isTrue(topic.flag); + }, + 'subcontext': { + 'nested': function (_, topic) { + assert.isTrue(topic.flag); + } + }, + teardown: function (topic) { + topic.flag = false; + }, + "with a subcontext" : { + topic: function (topic) { + var that = this; + process.nextTick(function () { + that.callback(null, topic); + }); + }, + "Waits for the subcontext before teardown" : function(topic) { + assert.isTrue(topic.flag); + } + } + } +}).export(module); + +vows.describe("Vows with sub events").addBatch({ + "A context with sub-events": { + topic: function () { + var topic = new(events.EventEmitter); + topic.emit('before', 'before'); + + process.nextTick(function () { + topic.emit('request', 'request_data'); + }); + + process.nextTick(function () { + topic.emit('end', 'end_data'); + }); + + process.nextTick(function () { + topic.emit('nested', 'empty_nest'); + }); + + process.nextTick(function () { + topic.emit('success', 'legacey_data'); + }); + + return topic; + }, + on: { + "before": { + "will catch events emited before the topic returns" : function (ret) { + assert.strictEqual(ret, 'before'); + } + }, + "request": { + "will catch request": function (ret) { + assert.strictEqual(ret, 'request_data'); + }, + on: { + on: { + "end": { + "will require that 'end' is emitted after 'request'": function (ret) { + assert.strictEqual(ret, 'end_data'); + // TODO need a test that fails to prove this works + } + } + } + } + }, + on: { + on: { + "nested": { + "will catch nested, even if it is in empty nested 'on'": function (ret) { + assert.strictEqual(ret, 'empty_nest') + } + } + } + } + }, + "will catch the legacy success event": function (err, ret) { + assert.strictEqual(ret, 'legacey_data'); + } + }, + "Sub-events emitted by children of EventEmitter": { + topic: function() { + var MyEmitter = function () { + events.EventEmitter.call(this); + }; + require('util').inherits(MyEmitter, events.EventEmitter); + + var topic = new(MyEmitter); + process.nextTick(function () { + topic.emit('success', 'Legacy Does not Catch'); + }); + + return topic; + }, + "will return the emitter for traditional vows" : function (err, ret) { + assert.ok(ret instanceof events.EventEmitter); + }, + // events is an alias for on + events: { + "success" : { + "will catch the event" : function (ret) { + assert.strictEqual(ret, 'Legacy Does not Catch'); + }, + "will change events to on in the title" : function() { + assert.strictEqual(this.context.title, + 'Sub-events emitted by children of EventEmitter on success'); + } + } + } + } +}).export(module); + +var tornDown = false + +vows.describe("Vows with asynchonous teardowns").addBatch({ + "Context with long-running teardown": { + "is run first": function () {}, + teardown: function () { + var callback = this.callback; + + setTimeout(function () { + tornDown = true; + callback(); + }, 100); + } + } +}).addBatch({ + "The next batch": { + "is not run until the teardown is complete": function () { + assert.ok(tornDown); + } + } +}).export(module); + +vows.describe('Async topic is passed to vows with topic-less subcontext').addBatch({ + 'Async 42': { + topic: function () { + var callback = this.callback; + process.nextTick(function () { + callback(null, 42); + }); + }, + 'equals 42': function (topic) { + assert.equal(topic, 42); + }, + 'has the property that': { + 'it is equal to 42': function (topic) { + // <-- This vow fails, topic is undefined!? + assert.equal(topic, 42); + } + }, + 'plus 1': { + topic: function (parentTopic) { + return parentTopic + 1; + }, + 'equals 43': function (topic) { + assert.equal(topic, 43); + } + } + } +})['export'](module); diff --git a/test/vows_underscore_test.js b/test/vows_underscore_test.js new file mode 100644 index 00000000..1f3ce5c9 --- /dev/null +++ b/test/vows_underscore_test.js @@ -0,0 +1,14 @@ +var vows = require('../lib/vows'), + assert = require('assert'); + +vows.describe("Vows test file with underscore").addBatch({ + + "The test file": { + topic: function () { + return { flag: true }; + }, + "is run": function (topic) { + assert.isTrue(topic.flag); + } + } +}).export(module);