diff --git a/.github/ISSUE_TEMPLATE/---bug-report.md b/.github/ISSUE_TEMPLATE/---bug-report.md new file mode 100644 index 0000000..2377639 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/---bug-report.md @@ -0,0 +1,43 @@ +--- + +name: "\U0001F41E Bug report" +about: Something is not working as it should +title: "\[fix] DESCRIPTIVE TITLE" +labels: bug +assignees: '' + +--- + +#### Describe the bug + +* Node.js version: +* OS & version: + + + +#### Actual behavior + +... + +#### Expected behavior + +... + +#### Code to reproduce + +```js +... +``` + + + +#### Checklist + +* [ ] I have read the documentation. +* [ ] I have tried my code with the latest version of Node.js and @breejs/later. diff --git a/.github/ISSUE_TEMPLATE/--feature-request.md b/.github/ISSUE_TEMPLATE/--feature-request.md new file mode 100644 index 0000000..f021a89 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/--feature-request.md @@ -0,0 +1,23 @@ +--- + +name: "⭐ Feature request" +about: Suggest an idea for Bree +title: "\[feat] DESCRIPTIVE TITLE" +labels: enhancement +assignees: '' + +--- + +#### What problem are you trying to solve? + +... + +#### Describe the feature + +... + + + +#### Checklist + +* [ ] I have read the documentation and made sure this feature doesn't already exist. diff --git a/.github/ISSUE_TEMPLATE/--question.md b/.github/ISSUE_TEMPLATE/--question.md new file mode 100644 index 0000000..9557e1d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/--question.md @@ -0,0 +1,17 @@ +--- + +name: "❓ Question" +about: Something is unclear or needs to be discussed +title: "\[discussion] DESCRIPTIVE TITLE" +labels: question +assignees: '' + +--- + +#### What would you like to discuss? + +... + +#### Checklist + +* [ ] I have read the documentation. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d2ec708 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,41 @@ +name: CI + +on: [push, pull_request] + +jobs: + test-coverage: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: + - ubuntu-latest + node_version: + - 10 + - 12 + - 14 + - 16 + + name: Node ${{ matrix.node_version }} on ${{ matrix.os }} + + steps: + - name: Checkout repo + uses: actions/checkout@v2 + + - name: Setup node + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node_version }} + + - name: Install yarn + run: npm install -g yarn + + - name: Install dependencies + run: yarn --frozen-lockfile + + - name: Run tests + run: yarn test-coverage + + - name: Uninstall yarn + if: always() + run: npm uninstall -g yarn diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index da52ee1..0000000 --- a/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: node_js -node_js: - - 10 - - 12 - - 14 -script: - - npm run test-coverage -after_success: - - npm run coverage diff --git a/README.md b/README.md index 067457a..3f4c4a0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # @breejs/later -[![build status](https://img.shields.io/travis/com/breejs/later.svg)](https://travis-ci.com/breejs/later) +[![build status](https://github.com/breejs/later/actions/workflows/ci.yml/badge.svg)](https://github.com/breejs/later/actions/workflows/ci.yml) [![code coverage](https://img.shields.io/codecov/c/github/breejs/later.svg)](https://codecov.io/gh/breejs/later) [![code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo) [![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier) @@ -25,7 +25,7 @@ ## Features -Types of schedules supported by _Later_: +Types of schedules supported by *Later*: * Run a report on the last day of every month at 12 AM except in December * Install patches on the 2nd Tuesday of every month at 4 AM @@ -97,7 +97,7 @@ Assuming you are using [browserify][], [webpack][], [rollup][], or another bundl [MIT](LICENSE) © BunKat -## +## [npm]: https://www.npmjs.com/ diff --git a/package.json b/package.json index cd396b5..278fc88 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@breejs/later", "description": "Maintained fork of later. Determine later (or previous) occurrences of recurring schedules", - "version": "4.0.3", + "version": "4.1.0", "author": "BunKat ", "bugs": { "url": "https://github.com/breejs/later/issues", @@ -12,32 +12,32 @@ "Nick Baugh (http://niftylettuce.com/)", "yrambler2001 (https://yrambler2001.me/)" ], - "dependencies": {}, "devDependencies": { "@babel/cli": "^7.10.5", "@babel/core": "^7.11.1", "@babel/plugin-transform-runtime": "^7.11.0", "@babel/preset-env": "^7.11.0", - "@commitlint/cli": "latest", - "@commitlint/config-conventional": "latest", + "@commitlint/cli": "^18.4.3", + "@commitlint/config-conventional": "^18.4.3", "babelify": "^10.0.0", - "benchmark": "*", + "benchmark": "^2.1.4", "browserify": "^16.5.2", - "codecov": "latest", - "cross-env": "latest", + "cross-env": "^7.0.3", "eslint": "^7.7.0", - "eslint-config-xo-lass": "latest", + "eslint-config-xo-lass": "^2.0.1", "eslint-plugin-compat": "^3.8.0", "eslint-plugin-node": "^11.1.0", - "fixpack": "latest", - "husky": "latest", - "lint-staged": "latest", - "mocha": "*", - "nyc": "latest", - "remark-cli": "latest", - "remark-preset-github": "latest", + "fixpack": "^4.0.0", + "husky": "^8.0.3", + "lint-staged": "^15.1.0", + "mocha": "^10.2.0", + "nyc": "^15.1.0", + "remark-cli": "11", + "remark-preset-github": "^4.0.4", + "rimraf": "^5.0.5", "semver": "^7.3.2", - "should": ">=13.2.3", + "should": "^13.2.3", + "sinon": "^11.1.2", "tinyify": "^3.0.0", "xo": "^0.33.0" }, @@ -155,7 +155,7 @@ "build:clean": "rimraf lib dist", "build:dist": "npm run browserify && npm run minify", "build:lib": "babel --config-file ./.lib.babelrc src --out-dir lib", - "coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov", + "coverage": "nyc report --reporter=text-lcov > coverage.lcov", "lint": "yarn run lint:js && yarn run lint:md && yarn run lint:lib && yarn run lint:dist", "lint:dist": "eslint --no-inline-config -c .dist.eslintrc dist", "lint:js": "xo", @@ -164,7 +164,7 @@ "minify": "cross-env NODE_ENV=production browserify src/index.js -o dist/later.min.js -s later -g [ babelify --configFile ./.dist.babelrc ] -p tinyify", "nyc": "cross-env NODE_ENV=test nyc mocha test/**/*-test.js --reporter dot", "pretest": "yarn run build && yarn run lint", - "test": "cross-env NODE_ENV=test mocha test/**/*-test.js --reporter dot", + "test": "cross-env NODE_ENV=test mocha test/**/*-test.js --reporter dot --exit", "test-coverage": "cross-env NODE_ENV=test nyc yarn run test" }, "unpkg": "dist/later.min.js", diff --git a/src/index.js b/src/index.js index 5ddfd6b..cd2650b 100644 --- a/src/index.js +++ b/src/index.js @@ -1189,7 +1189,7 @@ later.schedule = function (sched) { }; }; -later.setTimeout = function (fn, sched) { +later.setTimeout = function (fn, sched, timezone) { const s = later.schedule(sched); let t; if (fn) { @@ -1197,8 +1197,37 @@ later.setTimeout = function (fn, sched) { } function scheduleTimeout() { - const now = Date.now(); - const next = s.next(2, now); + const date = new Date(); + const now = date.getTime(); + + const next = (() => { + if (!timezone || ['local', 'system'].includes(timezone)) { + return s.next(2, now); + } + + const localOffsetMillis = date.getTimezoneOffset() * 6e4; + const offsetMillis = getOffset(date, timezone); + + // Specified timezone has the same offset as local timezone. + // ie. America/New_York = America/Nassau = GMT-4 + if (offsetMillis === localOffsetMillis) { + return s.next(2, now); + } + + // Offsets differ, adjust current time to match what + // it should've been for the specified timezone. + const adjustedNow = new Date(now + localOffsetMillis - offsetMillis); + + return (s.next(2, adjustedNow) || /* istanbul ignore next */ []).map( + (sched) => { + // adjust scheduled times to match their intended timezone + // ie. scheduled = 2021-08-22T11:30:00.000-04:00 => America/New_York + // intended = 2021-08-22T11:30:00.000-05:00 => America/Mexico_City + return new Date(sched.getTime() + offsetMillis - localOffsetMillis); + } + ); + })(); + if (!next[0]) { t = undefined; return; @@ -1209,12 +1238,11 @@ later.setTimeout = function (fn, sched) { diff = next[1] ? next[1].getTime() - now : 1e3; } - if (diff < 2147483647) { - t = setTimeout(fn, diff); - } else { - t = setTimeout(scheduleTimeout, 2147483647); - } - } + t = + diff < 2147483647 + ? setTimeout(fn, diff) + : setTimeout(scheduleTimeout, 2147483647); + } // scheduleTimeout() return { isDone() { @@ -1224,19 +1252,20 @@ later.setTimeout = function (fn, sched) { clearTimeout(t); } }; -}; +}; // setTimeout() -later.setInterval = function (fn, sched) { +later.setInterval = function (fn, sched, timezone) { if (!fn) { return; } - let t = later.setTimeout(scheduleTimeout, sched); + let t = later.setTimeout(scheduleTimeout, sched, timezone); let done = t.isDone(); function scheduleTimeout() { + /* istanbul ignore else */ if (!done) { fn(); - t = later.setTimeout(scheduleTimeout, sched); + t = later.setTimeout(scheduleTimeout, sched, timezone); } } @@ -1249,7 +1278,7 @@ later.setInterval = function (fn, sched) { t.clear(); } }; -}; +}; // setInterval() later.date = {}; later.date.timezone = function (useLocalTime) { @@ -2121,4 +2150,21 @@ later.parse.text = function (string) { return parseScheduleExpr(string.toLowerCase()); }; +function getOffset(date, zone) { + const d = date + .toLocaleString('en-US', { + hour12: false, + timeZone: zone, + timeZoneName: 'short' + }) //=> ie. "8/22/2021, 24:30:00 EDT" + .match(/(\d+)\/(\d+)\/(\d+),? (\d+):(\d+):(\d+)/) + .map((n) => (n.length === 1 ? '0' + n : n)); + + const zdate = new Date( + `${d[3]}-${d[1]}-${d[2]}T${d[4].replace('24', '00')}:${d[5]}:${d[6]}Z` + ); + + return date.getTime() - zdate.getTime(); +} // getOffset() + module.exports = later; diff --git a/test/core/setinterval-test.js b/test/core/setinterval-test.js index 7aa359e..2149262 100644 --- a/test/core/setinterval-test.js +++ b/test/core/setinterval-test.js @@ -1,10 +1,13 @@ const later = require('../..'); const should = require('should'); +const sinon = require('sinon'); describe('Set interval', function () { it('should execute a callback after the specified amount of time', function (done) { this.timeout(0); + const clock = sinon.useFakeTimers(Date.now()); + const s = later.parse.recur().every(1).second(); const t = later.setInterval(test, s); let count = 0; @@ -14,14 +17,19 @@ describe('Set interval', function () { count++; if (count > 2) { t.clear(); + clock.uninstall(); done(); } } + + clock.runAll(); }); it('should allow clearing of the timeout', function (done) { this.timeout(0); + const clock = sinon.useFakeTimers(Date.now()); + const s = later.parse.recur().every(2).second(); function test() { @@ -31,6 +39,34 @@ describe('Set interval', function () { const t = later.setInterval(test, s); t.clear(); - setTimeout(done, 3000); + clock.runAll(); + clock.uninstall(); + done(); + }); + + it('should call .setTimeout() with a timezone param', (done) => { + const clock = sinon.useFakeTimers(Date.now()); + + const spy = sinon.spy(later, 'setTimeout'); + const s = later.parse + .recur() + .on(new Date(Date.now() + 1e3)) + .fullDate(); + const t = later.setInterval( + () => { + /* noop */ + }, + s, + 'America/New_York' + ); + should.equal(later.setTimeout.calledOnce, true); + should.equal(later.setTimeout.getCall(0).args[2], 'America/New_York'); + + clock.runAll(); + + spy.restore(); + t.clear(); + clock.uninstall(); + done(); }); }); diff --git a/test/core/settimeout-test.js b/test/core/settimeout-test.js index 9a7c872..1665ba8 100644 --- a/test/core/settimeout-test.js +++ b/test/core/settimeout-test.js @@ -1,23 +1,36 @@ const later = require('../..'); const should = require('should'); +const sinon = require('sinon'); + +const noop = () => { + /* noop */ +}; describe('Set timeout', function () { it('should execute a callback after the specified amount of time', function (done) { this.timeout(3000); + const clock = sinon.useFakeTimers(Date.now()); + const s = later.parse.recur().every(2).second(); function test() { later.schedule(s).isValid(new Date()).should.eql(true); - done(); } later.setTimeout(test, s); + + clock.runAll(); + + clock.uninstall(); + done(); }); it('should allow clearing of the timeout', function (done) { this.timeout(3000); + const clock = sinon.useFakeTimers(Date.now()); + const s = later.parse.recur().every(1).second(); function test() { @@ -27,38 +40,183 @@ describe('Set timeout', function () { const t = later.setTimeout(test, s); t.clear(); - setTimeout(done, 2000); + clock.runAll(); + + clock.uninstall(); + done(); }); it('should not execute a far out schedule immediately', function (done) { this.timeout(3000); + const clock = sinon.useFakeTimers(Date.now()); + const s = later.parse.recur().on(2017).year(); function test() { should.not.exist(true); } - const t = later.setTimeout(test, s); + later.setTimeout(test, s); - setTimeout(function () { - t.clear(); - done(); - }, 2000); + clock.runAll(); + + clock.uninstall(); + done(); }); it('should execute a callback for a one-time occurrence after the specified amount of time', function (done) { this.timeout(3000); + const clock = sinon.useFakeTimers(Date.now()); + const offsetInMilliseconds = 2000; const now = new Date(); const nowOffset = now.getTime() + offsetInMilliseconds; const s = later.parse.recur().on(new Date(nowOffset)).fullDate(); function test() { + clock.uninstall(); done(); } later.setTimeout(test, s); + + clock.runAll(); + }); + + describe('timezone support', () => { + it('should accept IANA timezone strings', (done) => { + should.doesNotThrow(() => { + const s = later.parse + .recur() + .on(new Date(Date.now() + 1e3)) + .fullDate(); + later.setTimeout(noop, s, 'America/New_York'); + }); + done(); + }); + + it('should accept "local" as a valid timezone string', (done) => { + should.doesNotThrow(() => { + const s = later.parse + .recur() + .on(new Date(Date.now() + 1e3)) + .fullDate(); + later.setTimeout(noop, s, 'local'); + }); + done(); + }); + + it('should accept "system" as a valid timezone string', (done) => { + should.doesNotThrow(() => { + const s = later.parse + .recur() + .on(new Date(Date.now() + 1e3)) + .fullDate(); + later.setTimeout(noop, s, 'system'); + }); + done(); + }); + + it('should throw a RangeError when given an invalid or unsupported timezone string', (done) => { + should.throws(() => { + const s = later.parse + .recur() + .on(new Date(Date.now() + 1e3)) + .fullDate(); + later.setTimeout(noop, s, 'bogus_zone'); + }, 'RangeError'); + done(); + }); + + it('should adjust scheduled time if the local timezone is ahead of the one specified', (done) => { + const datetimeNow = new Date('2021-08-22T10:30:00.000-04:00'); // zone = America/New_York + const timezone = 'America/Mexico_City'; // time now = 2021-08-22T09:30:00.000-05:00 + const msHalfHour = 18e5; + + // Run half hour later. + // Intended datetime: 2021-08-22T10:00:00.000-05:00 + // But instead, we don't specify timezone here + const intendedDatetime = '2021-08-22T10:00:00.000'; + // And so, `new Date()` will use it's local timezone: + // Assumed datetime: 2021-08-22T10:00:00.000-04:00 + const assumedTimezone = '-04:00'; + const s = later.parse + .recur() + .on(new Date(intendedDatetime + assumedTimezone)) + .fullDate(); + + const clock = sinon.useFakeTimers({ + now: datetimeNow.getTime() + }); + clock.Date.prototype.getTimezoneOffset = () => 240; + + clock.setTimeout = (fn, ms) => { + should.equal(ms, msHalfHour); + }; + + later.setTimeout(noop, s, timezone); + + clock.uninstall(); + done(); + }); + + it('should adjust scheduled time if the local timezone is behind of the one specified', (done) => { + const datetimeNow = new Date('2021-08-22T10:30:00.000-04:00'); // zone = America/New_York + const timezone = 'Europe/Athens'; // time now = 2021-08-22T17:30:00.000+03:00 + const msHalfHour = 18e5; + + // Run half hour later. + // Intended datetime: 2021-08-22T18:00:00.000+03:00 + // But instead, we don't specify timezone here + const intendedDatetime = '2021-08-22T18:00:00.000'; + // And so, `new Date()` will use it's local timezone: + // Assumed datetime: 2021-08-22T18:00:00.000-04:00 + const assumedTimezone = '-04:00'; + const s = later.parse + .recur() + .on(new Date(intendedDatetime + assumedTimezone)) + .fullDate(); + + const clock = sinon.useFakeTimers({ + now: datetimeNow.getTime() + }); + clock.Date.prototype.getTimezoneOffset = () => 240; + + clock.setTimeout = (fn, ms) => { + should.equal(ms, msHalfHour); + }; + + later.setTimeout(noop, s, timezone); + + clock.uninstall(); + done(); + }); + + it('should not adjust time if specified and local timezones are the same', (done) => { + const datetimeNow = new Date('2021-08-22T10:30:00.000-04:00'); // zone = America/New_York + const timezone = 'America/New_York'; + const msOneHour = 36e5; + + // Intended run time is one hour later: 2021-08-22 at 11:30, New York time + const intendedRunTime = '2021-08-22T11:30:00.000-04:00'; + + const s = later.parse.recur().on(new Date(intendedRunTime)).fullDate(); + + const clock = sinon.useFakeTimers({ + now: datetimeNow.getTime() + }); + clock.Date.prototype.getTimezoneOffset = () => 240; + + clock.setTimeout = (fn, ms) => { + should.equal(ms, msOneHour); + }; + + later.setTimeout(noop, s, timezone); + + clock.uninstall(); + done(); + }); }); }); diff --git a/test/example/recur-example-test.js b/test/example/recur-example-test.js index 1613578..622ab71 100644 --- a/test/example/recur-example-test.js +++ b/test/example/recur-example-test.js @@ -345,32 +345,32 @@ describe('Recur Examples', function () { }); }); - it.skip('Every hour passing over DST', function () { - // this test will only pass when DST starts on March 10, 2013 at 2ams - later.date.localTime(); - - const sched = later.parse.recur().every(1).hour(); - - const start = new Date(2013, 2, 10); - const end = new Date(2013, 2, 10, 5); - const expected = [ - new Date(2013, 2, 10, 0), - new Date(2013, 2, 10, 1), - new Date(2013, 2, 10, 3), - new Date(2013, 2, 10, 4), - new Date(2013, 2, 10, 5) - ]; - - const next = later.schedule(sched).next(5, start, end); - next.should.eql(expected); - - const previous = later.schedule(sched).prev(5, end, start); - previous.should.eql(expected.reverse()); - - expected.forEach(function (e) { - later.schedule(sched).isValid(e).should.eql(true); - }); - }); + // it('Every hour passing over DST', function () { + // // this test will only pass when DST starts on March 10, 2013 at 2ams + // later.date.localTime(); + + // const sched = later.parse.recur().every(1).hour(); + + // const start = new Date(2013, 2, 10); + // const end = new Date(2013, 2, 10, 5); + // const expected = [ + // new Date(2013, 2, 10, 0), + // new Date(2013, 2, 10, 1), + // new Date(2013, 2, 10, 3), + // new Date(2013, 2, 10, 4), + // new Date(2013, 2, 10, 5) + // ]; + + // const next = later.schedule(sched).next(5, start, end); + // next.should.eql(expected); + + // const previous = later.schedule(sched).prev(5, end, start); + // previous.should.eql(expected.reverse()); + + // expected.forEach(function (e) { + // later.schedule(sched).isValid(e).should.eql(true); + // }); + // }); it('should recur everyday except on weekends', function () { later.date.UTC(); diff --git a/yarn.lock b/yarn.lock index df2162b..c40673e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1045,6 +1045,34 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== +"@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.8.3": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^7.0.4", "@sinonjs/fake-timers@^7.1.2": + version "7.1.2" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz#2524eae70c4910edccf99b2f4e6efc5894aff7b5" + integrity sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@sinonjs/samsam@^6.0.2": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-6.0.2.tgz#a0117d823260f282c04bff5f8704bdc2ac6910bb" + integrity sha512-jxPRPp9n93ci7b8hMfJOFDPRLFYadN6FSpeROFTR4UNF4i5b+EK6m4QXPO46BDhFgRy1JuS87zAnFOzCUwMJcQ== + dependencies: + "@sinonjs/commons" "^1.6.0" + lodash.get "^4.4.2" + type-detect "^4.0.8" + +"@sinonjs/text-encoding@^0.7.1": + version "0.7.1" + resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" + integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ== + "@szmarczak/http-timer@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" @@ -1052,11 +1080,6 @@ dependencies: defer-to-connect "^1.0.1" -"@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - "@types/color-name@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" @@ -1228,18 +1251,6 @@ acorn@^7.0.0, acorn@^7.1.1, acorn@^7.3.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c" integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w== -agent-base@5: - version "5.1.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c" - integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g== - -agent-base@6: - version "6.0.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.1.tgz#808007e4e5867decb0ab6ab2f928fbdb5a596db4" - integrity sha512-01q25QQDwLSsyfhrKbn8yuur+JNw0H+0Y4JiGIKd3z9aYk/w/2kxD/Upc+t2ZBBSUNff50VjPsSW2YxM8QYKVg== - dependencies: - debug "4" - aggregate-error@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0" @@ -1365,11 +1376,6 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" -argv@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/argv/-/argv-0.0.2.tgz#ecbd16f8949b157183711b1bda334f37840185ab" - integrity sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas= - arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -2168,17 +2174,6 @@ co@3.1.0: resolved "https://registry.yarnpkg.com/co/-/co-3.1.0.tgz#4ea54ea5a08938153185e15210c68d9092bc1b78" integrity sha1-TqVOpaCJOBUxheFSEMaNkJK8G3g= -codecov@latest: - version "3.7.2" - resolved "https://registry.yarnpkg.com/codecov/-/codecov-3.7.2.tgz#998e68c8c1ef4b55cfcf11cd456866d35e13d693" - integrity sha512-fmCjAkTese29DUX3GMIi4EaKGflHa4K51EoMc29g8fBHawdk/+KEq5CWOeXLdd9+AT7o1wO4DIpp/Z1KCqCz1g== - dependencies: - argv "0.0.2" - ignore-walk "3.0.3" - js-yaml "3.13.1" - teeny-request "6.0.1" - urlgrey "0.4.4" - collapse-white-space@^1.0.2, collapse-white-space@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" @@ -2539,13 +2534,6 @@ debug@3.2.6, debug@^3.2.6: dependencies: ms "^2.1.1" -debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -2553,6 +2541,13 @@ debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: dependencies: ms "2.0.0" +debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + decamelize-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" @@ -2690,6 +2685,11 @@ diff@4.0.2: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +diff@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + diffie-hellman@^5.0.0: version "5.0.3" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" @@ -4026,28 +4026,11 @@ http-cache-semantics@^4.0.0: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== -http-proxy-agent@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -https-proxy-agent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b" - integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg== - dependencies: - agent-base "5" - debug "4" - human-signals@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" @@ -4074,13 +4057,6 @@ ieee754@^1.1.4: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== -ignore-walk@3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" - integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== - dependencies: - minimatch "^3.0.4" - ignore@^4.0.3, ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" @@ -4559,6 +4535,11 @@ is-yarn-global@^0.3.0: resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -4763,6 +4744,11 @@ jsonparse@^1.2.0: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= +just-extend@^4.0.2: + version "4.2.1" + resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.2.1.tgz#ef5e589afb61e5d66b24eca749409a8939a8c744" + integrity sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg== + keyv@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" @@ -5447,6 +5433,17 @@ next-tick@~1.0.0: resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= +nise@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/nise/-/nise-5.1.0.tgz#713ef3ed138252daef20ec035ab62b7a28be645c" + integrity sha512-W5WlHu+wvo3PaKLsJJkgPup2LrsXCcm7AWwyNZkUnn5rwPkuPBi3Iwk5SQtN0mv+K65k7nKKjwNQ30wg3wLAQQ== + dependencies: + "@sinonjs/commons" "^1.7.0" + "@sinonjs/fake-timers" "^7.0.4" + "@sinonjs/text-encoding" "^0.7.1" + just-extend "^4.0.2" + path-to-regexp "^1.7.0" + nlcst-is-literal@^1.0.0, nlcst-is-literal@^1.1.0: version "1.2.1" resolved "https://registry.yarnpkg.com/nlcst-is-literal/-/nlcst-is-literal-1.2.1.tgz#878b68a43b5fd77b85e45b1b1737ae11a25f1be3" @@ -5475,11 +5472,6 @@ nlcst-to-string@^2.0.0: resolved "https://registry.yarnpkg.com/nlcst-to-string/-/nlcst-to-string-2.0.4.tgz#9315dfab80882bbfd86ddf1b706f53622dc400cc" integrity sha512-3x3jwTd6UPG7vi5k4GEzvxJ5rDA7hVUIRNHPblKuMVP9Z3xmlsd9cgLcpAMkc5uPOBna82EeshROFhsPkbnTZg== -node-fetch@^2.2.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" - integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== - "node-libs-browser@^1.0.0 || ^2.0.0": version "2.2.1" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" @@ -5947,6 +5939,13 @@ path-platform@~0.11.15: resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" integrity sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I= +path-to-regexp@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" + integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== + dependencies: + isarray "0.0.1" + path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" @@ -7476,6 +7475,18 @@ simple-concat@^1.0.0: resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== +sinon@^11.1.2: + version "11.1.2" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-11.1.2.tgz#9e78850c747241d5c59d1614d8f9cbe8840e8674" + integrity sha512-59237HChms4kg7/sXhiRcUzdSkKuydDeTiamT/jesUVHshBgL8XAmhgFo0GfK6RruMDM/iRSij1EybmMog9cJw== + dependencies: + "@sinonjs/commons" "^1.8.3" + "@sinonjs/fake-timers" "^7.1.2" + "@sinonjs/samsam" "^6.0.2" + diff "^5.0.0" + nise "^5.1.0" + supports-color "^7.2.0" + slash@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" @@ -7693,13 +7704,6 @@ stream-combiner@^0.2.2: duplexer "~0.1.1" through "~2.3.4" -stream-events@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/stream-events/-/stream-events-1.0.5.tgz#bbc898ec4df33a4902d892333d47da9bf1c406d5" - integrity sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg== - dependencies: - stubs "^3.0.0" - stream-http@^2.7.2: version "2.8.3" resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" @@ -7880,11 +7884,6 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -stubs@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b" - integrity sha1-6NK6H6nJBXAwPAMLaQD31fiavls= - subarg@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" @@ -7918,6 +7917,13 @@ supports-color@^6.0.0: dependencies: has-flag "^3.0.0" +supports-color@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + supports-hyperlinks@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz#f663df252af5f37c5d49bbd7eeefa9e0b9e59e47" @@ -7948,17 +7954,6 @@ tapable@^0.1.8: resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4" integrity sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q= -teeny-request@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/teeny-request/-/teeny-request-6.0.1.tgz#9b1f512cef152945827ba7e34f62523a4ce2c5b0" - integrity sha512-TAK0c9a00ELOqLrZ49cFxvPVogMUFaWY8dUsQc/0CuQPGF+BOxOQzXfE413BAk2kLomwNplvdtMpeaeGWmoc2g== - dependencies: - http-proxy-agent "^4.0.0" - https-proxy-agent "^4.0.0" - node-fetch "^2.2.0" - stream-events "^1.0.5" - uuid "^3.3.2" - term-size@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753" @@ -8200,6 +8195,11 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" +type-detect@4.0.8, type-detect@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + type-fest@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" @@ -8588,11 +8588,6 @@ url@^0.11.0, url@~0.11.0: punycode "1.3.2" querystring "0.2.0" -urlgrey@0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/urlgrey/-/urlgrey-0.4.4.tgz#892fe95960805e85519f1cd4389f2cb4cbb7652f" - integrity sha1-iS/pWWCAXoVRnxzUOJ8stMu3ZS8= - use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" @@ -8624,7 +8619,7 @@ util@~0.10.1: dependencies: inherits "2.0.3" -uuid@^3.3.2, uuid@^3.3.3: +uuid@^3.3.3: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==