summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2021-04-14 13:48:56 +0200
committerOskar Nyberg <oskar@mullvad.net>2021-04-14 13:48:56 +0200
commit130f56e4b4530d096403250f675ec42031ca64f2 (patch)
treea696588a0712414bfd8605d4c39c6367600046f2
parent937a8a3ea26dddb761e85e74228069f6f1b6a591 (diff)
parent1f3b51141b7da5cb2c38618708f606326413f5de (diff)
downloadmullvadvpn-130f56e4b4530d096403250f675ec42031ca64f2.tar.xz
mullvadvpn-130f56e4b4530d096403250f675ec42031ca64f2.zip
Merge branch 'remove-moment-js'
-rw-r--r--CHANGELOG.md1
-rw-r--r--gui/locales/messages.pot124
-rw-r--r--gui/package-lock.json769
-rw-r--r--gui/package.json7
-rw-r--r--gui/src/main/account-data-cache.ts11
-rw-r--r--gui/src/main/index.ts3
-rw-r--r--gui/src/renderer/components/Settings.tsx3
-rw-r--r--gui/src/renderer/components/WireguardKeys.tsx16
-rw-r--r--gui/src/renderer/containers/SettingsPage.tsx1
-rw-r--r--gui/src/renderer/containers/WireguardKeysPage.tsx1
-rw-r--r--gui/src/shared/account-expiry.ts53
-rw-r--r--gui/src/shared/date-helper.ts121
-rw-r--r--gui/src/shared/logging.ts17
-rw-r--r--gui/src/shared/notifications/close-to-account-expiry.ts16
-rw-r--r--gui/test/date-helper.spec.ts152
15 files changed, 668 insertions, 627 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 64bbc5ff0c..d7b5c11ae0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,6 +37,7 @@ Line wrap the file at 100 chars. Th
### Fixed
- Fix relay selection failing to pick a WireGuard relay when no tunnel protocol is specified.
+- Fix time left not always being translated in desktop app settings.
#### Windows
- Prevent tray icons from being extraced to `%TEMP%` directory.
diff --git a/gui/locales/messages.pot b/gui/locales/messages.pot
index 088dfe0550..6cfb89cabf 100644
--- a/gui/locales/messages.pot
+++ b/gui/locales/messages.pot
@@ -2,6 +2,61 @@ msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
+msgid "1 day"
+msgid_plural "%d days"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 day left"
+msgid_plural "%d days left"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 month"
+msgid_plural "%d months"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 month left"
+msgid_plural "%d months left"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 year"
+msgid_plural "%d years"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 year left"
+msgid_plural "%d years left"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "a day ago"
+msgid_plural "%d days ago"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "a minute ago"
+msgid_plural "%d minutes ago"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "a month ago"
+msgid_plural "%d months ago"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "a year ago"
+msgid_plural "%d years ago"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "an hour ago"
+msgid_plural "%d hours ago"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Back"
msgstr ""
@@ -41,6 +96,15 @@ msgstr ""
msgid "Invalid account number"
msgstr ""
+msgid "less than a day"
+msgstr ""
+
+msgid "less than a day left"
+msgstr ""
+
+msgid "less than a minute ago"
+msgstr ""
+
msgid "Open URL"
msgstr ""
@@ -92,20 +156,6 @@ msgctxt "accessibility"
msgid "Select location. Current location is %(location)s"
msgstr ""
-#. The remaining time left on the account measured in days.
-#. Available placeholders:
-#. %(duration)s - The remaining time measured in days.
-msgctxt "account-expiry"
-msgid "%(duration)s days"
-msgstr ""
-
-#. The remaining time left on the account displayed across the app.
-#. Available placeholders:
-#. %(duration)s - a localized remaining time (in minutes, hours, or days) until the account expiry
-msgctxt "account-expiry"
-msgid "%(duration)s left"
-msgstr ""
-
#. Title label in navigation bar
msgctxt "account-view"
msgid "Account"
@@ -1175,27 +1225,6 @@ msgstr ""
msgid "You may need to go back to the app's main screen and click Disconnect before trying again. Don't worry, the information you entered will remain in the form."
msgstr ""
-msgid "less than a day left"
-msgstr ""
-
-msgid "less than a minute ago"
-msgstr ""
-
-msgid "1 day left"
-msgid_plural "%d days left"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "1 month left"
-msgid_plural "%d months left"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "1 year left"
-msgid_plural "%d years left"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Account credit expires in a day"
msgid_plural "Account credit expires in %d days"
msgstr[0] ""
@@ -1205,28 +1234,3 @@ msgid "Account credit expires in an hour"
msgid_plural "Account credit expires in %d hours"
msgstr[0] ""
msgstr[1] ""
-
-msgid "a day ago"
-msgid_plural "%d days ago"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "a minute ago"
-msgid_plural "%d minutes ago"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "a month ago"
-msgid_plural "%d months ago"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "a year ago"
-msgid_plural "%d years ago"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "an hour ago"
-msgid_plural "%d hours ago"
-msgstr[0] ""
-msgstr[1] ""
diff --git a/gui/package-lock.json b/gui/package-lock.json
index e44373c850..9db878e062 100644
--- a/gui/package-lock.json
+++ b/gui/package-lock.json
@@ -15,7 +15,6 @@
"d3-geo": "^1.12.1",
"gettext-parser": "^4.0.3",
"google-protobuf": "^3.14.0",
- "moment": "^2.29.1",
"node-gettext": "^3.0.0",
"rbush": "^2.0.2",
"react": "^17.0.1",
@@ -52,8 +51,8 @@
"@types/styled-components": "^5.1.4",
"@types/topojson-specification": "^1.0.1",
"@types/uuid": "^3.4.4",
- "@typescript-eslint/eslint-plugin": "^4.8.2",
- "@typescript-eslint/parser": "^4.8.2",
+ "@typescript-eslint/eslint-plugin": "^4.21.0",
+ "@typescript-eslint/parser": "^4.21.0",
"browser-sync": "^2.26.13",
"browserify": "^17.0.0",
"chai": "^4.2.0",
@@ -80,7 +79,7 @@
"spa-server": "^1.0.0",
"ts-node": "^9.1.1",
"tsc-watch": "^4.2.9",
- "typescript": "^4.1.5",
+ "typescript": "^4.2.3",
"vinyl-buffer": "^1.0.1",
"vinyl-source-stream": "^2.0.0"
},
@@ -808,12 +807,12 @@
}
},
"node_modules/@nodelib/fs.scandir": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
- "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==",
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
+ "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==",
"dev": true,
"dependencies": {
- "@nodelib/fs.stat": "2.0.3",
+ "@nodelib/fs.stat": "2.0.4",
"run-parallel": "^1.1.9"
},
"engines": {
@@ -821,21 +820,21 @@
}
},
"node_modules/@nodelib/fs.stat": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
- "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz",
+ "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==",
"dev": true,
"engines": {
"node": ">= 8"
}
},
"node_modules/@nodelib/fs.walk": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz",
- "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==",
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz",
+ "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==",
"dev": true,
"dependencies": {
- "@nodelib/fs.scandir": "2.1.3",
+ "@nodelib/fs.scandir": "2.1.4",
"fastq": "^1.6.0"
},
"engines": {
@@ -1008,9 +1007,9 @@
}
},
"node_modules/@types/json-schema": {
- "version": "7.0.6",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
- "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==",
+ "version": "7.0.7",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz",
+ "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==",
"dev": true
},
"node_modules/@types/minimatch": {
@@ -1207,56 +1206,35 @@
"dev": true
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.8.2.tgz",
- "integrity": "sha512-gQ06QLV5l1DtvYtqOyFLXD9PdcILYqlrJj2l+CGDlPtmgLUzc1GpqciJFIRvyfvgLALpnxYINFuw+n9AZhPBKQ==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.21.0.tgz",
+ "integrity": "sha512-FPUyCPKZbVGexmbCFI3EQHzCZdy2/5f+jv6k2EDljGdXSRc0cKvbndd2nHZkSLqCNOPk0jB6lGzwIkglXcYVsQ==",
"dev": true,
"dependencies": {
- "@typescript-eslint/experimental-utils": "4.8.2",
- "@typescript-eslint/scope-manager": "4.8.2",
+ "@typescript-eslint/experimental-utils": "4.21.0",
+ "@typescript-eslint/scope-manager": "4.21.0",
"debug": "^4.1.1",
"functional-red-black-tree": "^1.0.1",
+ "lodash": "^4.17.15",
"regexpp": "^3.0.0",
"semver": "^7.3.2",
"tsutils": "^3.17.1"
},
"engines": {
"node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.8.2.tgz",
- "integrity": "sha512-qHQ8ODi7mMin4Sq2eh/6eu03uVzsf5TX+J43xRmiq8ujng7ViQSHNPLOHGw/Wr5dFEoxq/ubKhzClIIdQy5q3g==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "4.8.2",
- "@typescript-eslint/visitor-keys": "4.8.2"
},
- "engines": {
- "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
- }
- },
- "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.8.2.tgz",
- "integrity": "sha512-z1/AVcVF8ju5ObaHe2fOpZYEQrwHyZ7PTOlmjd3EoFeX9sv7UekQhfrCmgUO7PruLNfSHrJGQvrW3Q7xQ8EoAw==",
- "dev": true,
- "engines": {
- "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
- }
- },
- "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.8.2.tgz",
- "integrity": "sha512-Vg+/SJTMZJEKKGHW7YC21QxgKJrSbxoYYd3MEUGtW7zuytHuEcksewq0DUmo4eh/CTNrVJGSdIY9AtRb6riWFw==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "4.8.2",
- "eslint-visitor-keys": "^2.0.0"
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
},
- "engines": {
- "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^4.0.0",
+ "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
}
},
"node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": {
@@ -1271,15 +1249,6 @@
"node": ">=6.0"
}
},
- "node_modules/@typescript-eslint/eslint-plugin/node_modules/eslint-visitor-keys": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz",
- "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -1287,137 +1256,54 @@
"dev": true
},
"node_modules/@typescript-eslint/experimental-utils": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.8.2.tgz",
- "integrity": "sha512-hpTw6o6IhBZEsQsjuw/4RWmceRyESfAiEzAEnXHKG1X7S5DXFaZ4IO1JO7CW1aQ604leQBzjZmuMI9QBCAJX8Q==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.21.0.tgz",
+ "integrity": "sha512-cEbgosW/tUFvKmkg3cU7LBoZhvUs+ZPVM9alb25XvR0dal4qHL3SiUqHNrzoWSxaXA9gsifrYrS1xdDV6w/gIA==",
"dev": true,
"dependencies": {
"@types/json-schema": "^7.0.3",
- "@typescript-eslint/scope-manager": "4.8.2",
- "@typescript-eslint/types": "4.8.2",
- "@typescript-eslint/typescript-estree": "4.8.2",
+ "@typescript-eslint/scope-manager": "4.21.0",
+ "@typescript-eslint/types": "4.21.0",
+ "@typescript-eslint/typescript-estree": "4.21.0",
"eslint-scope": "^5.0.0",
"eslint-utils": "^2.0.0"
},
"engines": {
"node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/scope-manager": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.8.2.tgz",
- "integrity": "sha512-qHQ8ODi7mMin4Sq2eh/6eu03uVzsf5TX+J43xRmiq8ujng7ViQSHNPLOHGw/Wr5dFEoxq/ubKhzClIIdQy5q3g==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "4.8.2",
- "@typescript-eslint/visitor-keys": "4.8.2"
},
- "engines": {
- "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
- }
- },
- "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/types": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.8.2.tgz",
- "integrity": "sha512-z1/AVcVF8ju5ObaHe2fOpZYEQrwHyZ7PTOlmjd3EoFeX9sv7UekQhfrCmgUO7PruLNfSHrJGQvrW3Q7xQ8EoAw==",
- "dev": true,
- "engines": {
- "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
- }
- },
- "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/typescript-estree": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.8.2.tgz",
- "integrity": "sha512-HToGNwI6fekH0dOw3XEVESUm71Onfam0AKin6f26S2FtUmO7o3cLlWgrIaT1q3vjB3wCTdww3Dx2iGq5wtUOCg==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "4.8.2",
- "@typescript-eslint/visitor-keys": "4.8.2",
- "debug": "^4.1.1",
- "globby": "^11.0.1",
- "is-glob": "^4.0.1",
- "lodash": "^4.17.15",
- "semver": "^7.3.2",
- "tsutils": "^3.17.1"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/visitor-keys": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.8.2.tgz",
- "integrity": "sha512-Vg+/SJTMZJEKKGHW7YC21QxgKJrSbxoYYd3MEUGtW7zuytHuEcksewq0DUmo4eh/CTNrVJGSdIY9AtRb6riWFw==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "4.8.2",
- "eslint-visitor-keys": "^2.0.0"
- },
- "engines": {
- "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
- }
- },
- "node_modules/@typescript-eslint/experimental-utils/node_modules/debug": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
- "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
- "dev": true,
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- }
- },
- "node_modules/@typescript-eslint/experimental-utils/node_modules/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,
- "dependencies": {
- "eslint-visitor-keys": "^1.1.0"
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
},
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-visitor-keys": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz",
- "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==",
- "dev": true,
- "engines": {
- "node": ">=10"
+ "peerDependencies": {
+ "eslint": "*"
}
},
- "node_modules/@typescript-eslint/experimental-utils/node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
"node_modules/@typescript-eslint/parser": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.8.2.tgz",
- "integrity": "sha512-u0leyJqmclYr3KcXOqd2fmx6SDGBO0MUNHHAjr0JS4Crbb3C3d8dwAdlazy133PLCcPn+aOUFiHn72wcuc5wYw==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.21.0.tgz",
+ "integrity": "sha512-eyNf7QmE5O/l1smaQgN0Lj2M/1jOuNg2NrBm1dqqQN0sVngTLyw8tdCbih96ixlhbF1oINoN8fDCyEH9SjLeIA==",
"dev": true,
"dependencies": {
- "@typescript-eslint/scope-manager": "4.8.2",
- "@typescript-eslint/types": "4.8.2",
- "@typescript-eslint/typescript-estree": "4.8.2",
+ "@typescript-eslint/scope-manager": "4.21.0",
+ "@typescript-eslint/types": "4.21.0",
+ "@typescript-eslint/typescript-estree": "4.21.0",
"debug": "^4.1.1"
},
"engines": {
"node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
}
},
"node_modules/@typescript-eslint/parser/node_modules/debug": {
@@ -1439,44 +1325,60 @@
"dev": true
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.8.2.tgz",
- "integrity": "sha512-qHQ8ODi7mMin4Sq2eh/6eu03uVzsf5TX+J43xRmiq8ujng7ViQSHNPLOHGw/Wr5dFEoxq/ubKhzClIIdQy5q3g==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.21.0.tgz",
+ "integrity": "sha512-kfOjF0w1Ix7+a5T1knOw00f7uAP9Gx44+OEsNQi0PvvTPLYeXJlsCJ4tYnDj5PQEYfpcgOH5yBlw7K+UEI9Agw==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "4.8.2",
- "@typescript-eslint/visitor-keys": "4.8.2"
+ "@typescript-eslint/types": "4.21.0",
+ "@typescript-eslint/visitor-keys": "4.21.0"
},
"engines": {
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/types": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.8.2.tgz",
- "integrity": "sha512-z1/AVcVF8ju5ObaHe2fOpZYEQrwHyZ7PTOlmjd3EoFeX9sv7UekQhfrCmgUO7PruLNfSHrJGQvrW3Q7xQ8EoAw==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.21.0.tgz",
+ "integrity": "sha512-+OQaupjGVVc8iXbt6M1oZMwyKQNehAfLYJJ3SdvnofK2qcjfor9pEM62rVjBknhowTkh+2HF+/KdRAc/wGBN2w==",
"dev": true,
"engines": {
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.8.2.tgz",
- "integrity": "sha512-HToGNwI6fekH0dOw3XEVESUm71Onfam0AKin6f26S2FtUmO7o3cLlWgrIaT1q3vjB3wCTdww3Dx2iGq5wtUOCg==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.21.0.tgz",
+ "integrity": "sha512-ZD3M7yLaVGVYLw4nkkoGKumb7Rog7QID9YOWobFDMQKNl+vPxqVIW/uDk+MDeGc+OHcoG2nJ2HphwiPNajKw3w==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "4.8.2",
- "@typescript-eslint/visitor-keys": "4.8.2",
+ "@typescript-eslint/types": "4.21.0",
+ "@typescript-eslint/visitor-keys": "4.21.0",
"debug": "^4.1.1",
"globby": "^11.0.1",
"is-glob": "^4.0.1",
- "lodash": "^4.17.15",
"semver": "^7.3.2",
"tsutils": "^3.17.1"
},
"engines": {
"node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/debug": {
@@ -1489,6 +1391,11 @@
},
"engines": {
"node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/ms": {
@@ -1498,25 +1405,20 @@
"dev": true
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.8.2.tgz",
- "integrity": "sha512-Vg+/SJTMZJEKKGHW7YC21QxgKJrSbxoYYd3MEUGtW7zuytHuEcksewq0DUmo4eh/CTNrVJGSdIY9AtRb6riWFw==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.21.0.tgz",
+ "integrity": "sha512-dH22dROWGi5Z6p+Igc8bLVLmwy7vEe8r+8c+raPQU0LxgogPUrRAtRGtvBWmlr9waTu3n+QLt/qrS/hWzk1x5w==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "4.8.2",
+ "@typescript-eslint/types": "4.21.0",
"eslint-visitor-keys": "^2.0.0"
},
"engines": {
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
- }
- },
- "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz",
- "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==",
- "dev": true,
- "engines": {
- "node": ">=10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@ungap/promise-all-settled": {
@@ -6905,12 +6807,12 @@
}
},
"node_modules/eslint-scope": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz",
- "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==",
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
"dev": true,
"dependencies": {
- "esrecurse": "^4.1.0",
+ "esrecurse": "^4.3.0",
"estraverse": "^4.1.1"
},
"engines": {
@@ -7037,40 +6939,6 @@
"node": ">=6.0.0"
}
},
- "node_modules/eslint/node_modules/eslint-scope": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
- "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
- "dev": true,
- "dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^4.1.1"
- },
- "engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/eslint/node_modules/esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
- "dev": true,
- "dependencies": {
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/eslint/node_modules/esrecurse/node_modules/estraverse": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
- "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
- "dev": true,
- "engines": {
- "node": ">=4.0"
- }
- },
"node_modules/eslint/node_modules/glob-parent": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
@@ -7234,17 +7102,26 @@
}
},
"node_modules/esrecurse": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
- "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
"dependencies": {
- "estraverse": "^4.1.0"
+ "estraverse": "^5.2.0"
},
"engines": {
"node": ">=4.0"
}
},
+ "node_modules/esrecurse/node_modules/estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
"node_modules/estraverse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
@@ -7577,9 +7454,9 @@
"dev": true
},
"node_modules/fast-glob": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz",
- "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==",
+ "version": "3.2.5",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz",
+ "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==",
"dev": true,
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
@@ -7618,9 +7495,9 @@
}
},
"node_modules/fast-glob/node_modules/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==",
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"dependencies": {
"is-glob": "^4.0.1"
@@ -7682,9 +7559,9 @@
"dev": true
},
"node_modules/fastq": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz",
- "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==",
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz",
+ "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==",
"dev": true,
"dependencies": {
"reusify": "^1.0.4"
@@ -8447,9 +8324,9 @@
}
},
"node_modules/globby": {
- "version": "11.0.1",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz",
- "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==",
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz",
+ "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==",
"dev": true,
"dependencies": {
"array-union": "^2.1.0",
@@ -8461,6 +8338,9 @@
},
"engines": {
"node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/globby/node_modules/ignore": {
@@ -12033,6 +11913,7 @@
"version": "2.29.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==",
+ "dev": true,
"engines": {
"node": "*"
}
@@ -13342,6 +13223,26 @@
"node": ">=0.4.x"
}
},
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
"node_modules/quickselect": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/quickselect/-/quickselect-1.1.1.tgz",
@@ -14095,10 +13996,27 @@
}
},
"node_modules/run-parallel": {
- "version": "1.1.9",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz",
- "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==",
- "dev": true
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
},
"node_modules/rx": {
"version": "4.1.0",
@@ -16360,9 +16278,9 @@
}
},
"node_modules/typescript": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz",
- "integrity": "sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==",
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz",
+ "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
@@ -18250,28 +18168,28 @@
}
},
"@nodelib/fs.scandir": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
- "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==",
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
+ "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==",
"dev": true,
"requires": {
- "@nodelib/fs.stat": "2.0.3",
+ "@nodelib/fs.stat": "2.0.4",
"run-parallel": "^1.1.9"
}
},
"@nodelib/fs.stat": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
- "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz",
+ "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==",
"dev": true
},
"@nodelib/fs.walk": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz",
- "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==",
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz",
+ "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==",
"dev": true,
"requires": {
- "@nodelib/fs.scandir": "2.1.3",
+ "@nodelib/fs.scandir": "2.1.4",
"fastq": "^1.6.0"
}
},
@@ -18435,9 +18353,9 @@
}
},
"@types/json-schema": {
- "version": "7.0.6",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
- "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==",
+ "version": "7.0.7",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz",
+ "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==",
"dev": true
},
"@types/minimatch": {
@@ -18634,46 +18552,21 @@
"dev": true
},
"@typescript-eslint/eslint-plugin": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.8.2.tgz",
- "integrity": "sha512-gQ06QLV5l1DtvYtqOyFLXD9PdcILYqlrJj2l+CGDlPtmgLUzc1GpqciJFIRvyfvgLALpnxYINFuw+n9AZhPBKQ==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.21.0.tgz",
+ "integrity": "sha512-FPUyCPKZbVGexmbCFI3EQHzCZdy2/5f+jv6k2EDljGdXSRc0cKvbndd2nHZkSLqCNOPk0jB6lGzwIkglXcYVsQ==",
"dev": true,
"requires": {
- "@typescript-eslint/experimental-utils": "4.8.2",
- "@typescript-eslint/scope-manager": "4.8.2",
+ "@typescript-eslint/experimental-utils": "4.21.0",
+ "@typescript-eslint/scope-manager": "4.21.0",
"debug": "^4.1.1",
"functional-red-black-tree": "^1.0.1",
+ "lodash": "^4.17.15",
"regexpp": "^3.0.0",
"semver": "^7.3.2",
"tsutils": "^3.17.1"
},
"dependencies": {
- "@typescript-eslint/scope-manager": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.8.2.tgz",
- "integrity": "sha512-qHQ8ODi7mMin4Sq2eh/6eu03uVzsf5TX+J43xRmiq8ujng7ViQSHNPLOHGw/Wr5dFEoxq/ubKhzClIIdQy5q3g==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "4.8.2",
- "@typescript-eslint/visitor-keys": "4.8.2"
- }
- },
- "@typescript-eslint/types": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.8.2.tgz",
- "integrity": "sha512-z1/AVcVF8ju5ObaHe2fOpZYEQrwHyZ7PTOlmjd3EoFeX9sv7UekQhfrCmgUO7PruLNfSHrJGQvrW3Q7xQ8EoAw==",
- "dev": true
- },
- "@typescript-eslint/visitor-keys": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.8.2.tgz",
- "integrity": "sha512-Vg+/SJTMZJEKKGHW7YC21QxgKJrSbxoYYd3MEUGtW7zuytHuEcksewq0DUmo4eh/CTNrVJGSdIY9AtRb6riWFw==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "4.8.2",
- "eslint-visitor-keys": "^2.0.0"
- }
- },
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
@@ -18683,12 +18576,6 @@
"ms": "2.1.2"
}
},
- "eslint-visitor-keys": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz",
- "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==",
- "dev": true
- },
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -18698,110 +18585,28 @@
}
},
"@typescript-eslint/experimental-utils": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.8.2.tgz",
- "integrity": "sha512-hpTw6o6IhBZEsQsjuw/4RWmceRyESfAiEzAEnXHKG1X7S5DXFaZ4IO1JO7CW1aQ604leQBzjZmuMI9QBCAJX8Q==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.21.0.tgz",
+ "integrity": "sha512-cEbgosW/tUFvKmkg3cU7LBoZhvUs+ZPVM9alb25XvR0dal4qHL3SiUqHNrzoWSxaXA9gsifrYrS1xdDV6w/gIA==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.3",
- "@typescript-eslint/scope-manager": "4.8.2",
- "@typescript-eslint/types": "4.8.2",
- "@typescript-eslint/typescript-estree": "4.8.2",
+ "@typescript-eslint/scope-manager": "4.21.0",
+ "@typescript-eslint/types": "4.21.0",
+ "@typescript-eslint/typescript-estree": "4.21.0",
"eslint-scope": "^5.0.0",
"eslint-utils": "^2.0.0"
- },
- "dependencies": {
- "@typescript-eslint/scope-manager": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.8.2.tgz",
- "integrity": "sha512-qHQ8ODi7mMin4Sq2eh/6eu03uVzsf5TX+J43xRmiq8ujng7ViQSHNPLOHGw/Wr5dFEoxq/ubKhzClIIdQy5q3g==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "4.8.2",
- "@typescript-eslint/visitor-keys": "4.8.2"
- }
- },
- "@typescript-eslint/types": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.8.2.tgz",
- "integrity": "sha512-z1/AVcVF8ju5ObaHe2fOpZYEQrwHyZ7PTOlmjd3EoFeX9sv7UekQhfrCmgUO7PruLNfSHrJGQvrW3Q7xQ8EoAw==",
- "dev": true
- },
- "@typescript-eslint/typescript-estree": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.8.2.tgz",
- "integrity": "sha512-HToGNwI6fekH0dOw3XEVESUm71Onfam0AKin6f26S2FtUmO7o3cLlWgrIaT1q3vjB3wCTdww3Dx2iGq5wtUOCg==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "4.8.2",
- "@typescript-eslint/visitor-keys": "4.8.2",
- "debug": "^4.1.1",
- "globby": "^11.0.1",
- "is-glob": "^4.0.1",
- "lodash": "^4.17.15",
- "semver": "^7.3.2",
- "tsutils": "^3.17.1"
- }
- },
- "@typescript-eslint/visitor-keys": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.8.2.tgz",
- "integrity": "sha512-Vg+/SJTMZJEKKGHW7YC21QxgKJrSbxoYYd3MEUGtW7zuytHuEcksewq0DUmo4eh/CTNrVJGSdIY9AtRb6riWFw==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "4.8.2",
- "eslint-visitor-keys": "^2.0.0"
- }
- },
- "debug": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
- "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- }
- },
- "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"
- },
- "dependencies": {
- "eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
- "dev": true
- }
- }
- },
- "eslint-visitor-keys": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz",
- "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==",
- "dev": true
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- }
}
},
"@typescript-eslint/parser": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.8.2.tgz",
- "integrity": "sha512-u0leyJqmclYr3KcXOqd2fmx6SDGBO0MUNHHAjr0JS4Crbb3C3d8dwAdlazy133PLCcPn+aOUFiHn72wcuc5wYw==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.21.0.tgz",
+ "integrity": "sha512-eyNf7QmE5O/l1smaQgN0Lj2M/1jOuNg2NrBm1dqqQN0sVngTLyw8tdCbih96ixlhbF1oINoN8fDCyEH9SjLeIA==",
"dev": true,
"requires": {
- "@typescript-eslint/scope-manager": "4.8.2",
- "@typescript-eslint/types": "4.8.2",
- "@typescript-eslint/typescript-estree": "4.8.2",
+ "@typescript-eslint/scope-manager": "4.21.0",
+ "@typescript-eslint/types": "4.21.0",
+ "@typescript-eslint/typescript-estree": "4.21.0",
"debug": "^4.1.1"
},
"dependencies": {
@@ -18823,33 +18628,32 @@
}
},
"@typescript-eslint/scope-manager": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.8.2.tgz",
- "integrity": "sha512-qHQ8ODi7mMin4Sq2eh/6eu03uVzsf5TX+J43xRmiq8ujng7ViQSHNPLOHGw/Wr5dFEoxq/ubKhzClIIdQy5q3g==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.21.0.tgz",
+ "integrity": "sha512-kfOjF0w1Ix7+a5T1knOw00f7uAP9Gx44+OEsNQi0PvvTPLYeXJlsCJ4tYnDj5PQEYfpcgOH5yBlw7K+UEI9Agw==",
"dev": true,
"requires": {
- "@typescript-eslint/types": "4.8.2",
- "@typescript-eslint/visitor-keys": "4.8.2"
+ "@typescript-eslint/types": "4.21.0",
+ "@typescript-eslint/visitor-keys": "4.21.0"
}
},
"@typescript-eslint/types": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.8.2.tgz",
- "integrity": "sha512-z1/AVcVF8ju5ObaHe2fOpZYEQrwHyZ7PTOlmjd3EoFeX9sv7UekQhfrCmgUO7PruLNfSHrJGQvrW3Q7xQ8EoAw==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.21.0.tgz",
+ "integrity": "sha512-+OQaupjGVVc8iXbt6M1oZMwyKQNehAfLYJJ3SdvnofK2qcjfor9pEM62rVjBknhowTkh+2HF+/KdRAc/wGBN2w==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.8.2.tgz",
- "integrity": "sha512-HToGNwI6fekH0dOw3XEVESUm71Onfam0AKin6f26S2FtUmO7o3cLlWgrIaT1q3vjB3wCTdww3Dx2iGq5wtUOCg==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.21.0.tgz",
+ "integrity": "sha512-ZD3M7yLaVGVYLw4nkkoGKumb7Rog7QID9YOWobFDMQKNl+vPxqVIW/uDk+MDeGc+OHcoG2nJ2HphwiPNajKw3w==",
"dev": true,
"requires": {
- "@typescript-eslint/types": "4.8.2",
- "@typescript-eslint/visitor-keys": "4.8.2",
+ "@typescript-eslint/types": "4.21.0",
+ "@typescript-eslint/visitor-keys": "4.21.0",
"debug": "^4.1.1",
"globby": "^11.0.1",
"is-glob": "^4.0.1",
- "lodash": "^4.17.15",
"semver": "^7.3.2",
"tsutils": "^3.17.1"
},
@@ -18872,21 +18676,13 @@
}
},
"@typescript-eslint/visitor-keys": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.8.2.tgz",
- "integrity": "sha512-Vg+/SJTMZJEKKGHW7YC21QxgKJrSbxoYYd3MEUGtW7zuytHuEcksewq0DUmo4eh/CTNrVJGSdIY9AtRb6riWFw==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.21.0.tgz",
+ "integrity": "sha512-dH22dROWGi5Z6p+Igc8bLVLmwy7vEe8r+8c+raPQU0LxgogPUrRAtRGtvBWmlr9waTu3n+QLt/qrS/hWzk1x5w==",
"dev": true,
"requires": {
- "@typescript-eslint/types": "4.8.2",
+ "@typescript-eslint/types": "4.21.0",
"eslint-visitor-keys": "^2.0.0"
- },
- "dependencies": {
- "eslint-visitor-keys": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz",
- "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==",
- "dev": true
- }
}
},
"@ungap/promise-all-settled": {
@@ -23268,33 +23064,6 @@
"esutils": "^2.0.2"
}
},
- "eslint-scope": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
- "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
- "dev": true,
- "requires": {
- "esrecurse": "^4.3.0",
- "estraverse": "^4.1.1"
- }
- },
- "esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
- "dev": true,
- "requires": {
- "estraverse": "^5.2.0"
- },
- "dependencies": {
- "estraverse": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
- "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
- "dev": true
- }
- }
- },
"glob-parent": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
@@ -23518,12 +23287,12 @@
}
},
"eslint-scope": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz",
- "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==",
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
"dev": true,
"requires": {
- "esrecurse": "^4.1.0",
+ "esrecurse": "^4.3.0",
"estraverse": "^4.1.1"
}
},
@@ -23593,12 +23362,20 @@
}
},
"esrecurse": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
- "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
"requires": {
- "estraverse": "^4.1.0"
+ "estraverse": "^5.2.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true
+ }
}
},
"estraverse": {
@@ -23880,9 +23657,9 @@
"dev": true
},
"fast-glob": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz",
- "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==",
+ "version": "3.2.5",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz",
+ "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==",
"dev": true,
"requires": {
"@nodelib/fs.stat": "^2.0.2",
@@ -23912,9 +23689,9 @@
}
},
"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==",
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"requires": {
"is-glob": "^4.0.1"
@@ -23966,9 +23743,9 @@
"dev": true
},
"fastq": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz",
- "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==",
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz",
+ "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==",
"dev": true,
"requires": {
"reusify": "^1.0.4"
@@ -24589,9 +24366,9 @@
}
},
"globby": {
- "version": "11.0.1",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz",
- "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==",
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz",
+ "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==",
"dev": true,
"requires": {
"array-union": "^2.1.0",
@@ -27499,7 +27276,8 @@
"moment": {
"version": "2.29.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
- "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
+ "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==",
+ "dev": true
},
"ms": {
"version": "2.0.0",
@@ -28566,6 +28344,12 @@
"integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
"dev": true
},
+ "queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true
+ },
"quickselect": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/quickselect/-/quickselect-1.1.1.tgz",
@@ -29194,10 +28978,13 @@
}
},
"run-parallel": {
- "version": "1.1.9",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz",
- "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==",
- "dev": true
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "requires": {
+ "queue-microtask": "^1.2.2"
+ }
},
"rx": {
"version": "4.1.0",
@@ -31114,9 +30901,9 @@
}
},
"typescript": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz",
- "integrity": "sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==",
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz",
+ "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==",
"dev": true
},
"ua-parser-js": {
diff --git a/gui/package.json b/gui/package.json
index 34bfb75e16..258a5b3f08 100644
--- a/gui/package.json
+++ b/gui/package.json
@@ -17,7 +17,6 @@
"d3-geo": "^1.12.1",
"gettext-parser": "^4.0.3",
"google-protobuf": "^3.14.0",
- "moment": "^2.29.1",
"node-gettext": "^3.0.0",
"rbush": "^2.0.2",
"react": "^17.0.1",
@@ -58,8 +57,8 @@
"@types/styled-components": "^5.1.4",
"@types/topojson-specification": "^1.0.1",
"@types/uuid": "^3.4.4",
- "@typescript-eslint/eslint-plugin": "^4.8.2",
- "@typescript-eslint/parser": "^4.8.2",
+ "@typescript-eslint/eslint-plugin": "^4.21.0",
+ "@typescript-eslint/parser": "^4.21.0",
"browser-sync": "^2.26.13",
"browserify": "^17.0.0",
"chai": "^4.2.0",
@@ -86,7 +85,7 @@
"spa-server": "^1.0.0",
"ts-node": "^9.1.1",
"tsc-watch": "^4.2.9",
- "typescript": "^4.1.5",
+ "typescript": "^4.2.3",
"vinyl-buffer": "^1.0.1",
"vinyl-source-stream": "^2.0.0"
},
diff --git a/gui/src/main/account-data-cache.ts b/gui/src/main/account-data-cache.ts
index a03728e004..7d3c59e5ef 100644
--- a/gui/src/main/account-data-cache.ts
+++ b/gui/src/main/account-data-cache.ts
@@ -1,6 +1,6 @@
-import moment from 'moment';
-import { hasExpired } from '../shared/account-expiry';
+import { closeToExpiry, hasExpired } from '../shared/account-expiry';
import { AccountToken, IAccountData } from '../shared/daemon-rpc-types';
+import { DateComponent, dateByAddingComponent } from '../shared/date-helper';
import log from '../shared/logging';
import consumePromise from '../shared/promise';
import { Scheduler } from '../shared/scheduler';
@@ -105,13 +105,12 @@ export default class AccountDataCache {
private calculateRefetchDelay(accountExpiry: string) {
const currentDate = new Date();
- const oneMinuteBeforeExpiry = moment(accountExpiry).subtract(1, 'minute');
- const closeToExpiry = moment(accountExpiry).isSameOrBefore(moment().add(3, 'days'));
+ const oneMinuteBeforeExpiry = dateByAddingComponent(accountExpiry, DateComponent.minute, -1);
if (hasExpired(accountExpiry)) {
return EXPIRED_ACCOUNT_REFRESH_PERIOD;
- } else if (oneMinuteBeforeExpiry.isSameOrAfter(currentDate) && closeToExpiry) {
- return oneMinuteBeforeExpiry.diff(currentDate);
+ } else if (oneMinuteBeforeExpiry >= currentDate && closeToExpiry(accountExpiry)) {
+ return oneMinuteBeforeExpiry.getTime() - currentDate.getTime();
} else {
return undefined;
}
diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts
index efbf9a4aa3..43807de5c3 100644
--- a/gui/src/main/index.ts
+++ b/gui/src/main/index.ts
@@ -10,7 +10,6 @@ import {
shell,
Tray,
} from 'electron';
-import moment from 'moment';
import * as path from 'path';
import { sprintf } from 'sprintf-js';
import * as uuid from 'uuid';
@@ -1339,7 +1338,7 @@ class ApplicationMain {
this.notificationController.notify(closeToExpiryNotification.getSystemNotification());
const twelveHours = 12 * 60 * 60 * 1000;
- const remainingMilliseconds = moment(this.accountData.expiry).diff(new Date());
+ const remainingMilliseconds = new Date(this.accountData.expiry).getTime() - Date.now();
const delay = Math.min(twelveHours, remainingMilliseconds);
this.accountExpiryNotificationScheduler.schedule(() => this.handleAccountExpiry(), delay);
}
diff --git a/gui/src/renderer/components/Settings.tsx b/gui/src/renderer/components/Settings.tsx
index 00c5d846f0..56b8fd5494 100644
--- a/gui/src/renderer/components/Settings.tsx
+++ b/gui/src/renderer/components/Settings.tsx
@@ -29,7 +29,6 @@ export interface IProps {
preferredLocaleDisplayName: string;
loginState: LoginState;
accountExpiry?: string;
- expiryLocale: string;
appVersion: string;
consistentVersion: boolean;
upToDateVersion: boolean;
@@ -106,7 +105,7 @@ export default class Settings extends React.Component<IProps> {
const isOutOfTime = this.props.accountExpiry ? hasExpired(this.props.accountExpiry) : false;
const formattedExpiry = this.props.accountExpiry
- ? formatRemainingTime(this.props.accountExpiry, this.props.expiryLocale).toUpperCase()
+ ? formatRemainingTime(this.props.accountExpiry).toUpperCase()
: '';
const outOfTimeMessage = messages.pgettext('settings-view', 'OUT OF TIME');
diff --git a/gui/src/renderer/components/WireguardKeys.tsx b/gui/src/renderer/components/WireguardKeys.tsx
index 9c181ad57e..f6e143e6a3 100644
--- a/gui/src/renderer/components/WireguardKeys.tsx
+++ b/gui/src/renderer/components/WireguardKeys.tsx
@@ -1,7 +1,7 @@
-import moment from 'moment';
import * as React from 'react';
import { sprintf } from 'sprintf-js';
import { TunnelState } from '../../shared/daemon-rpc-types';
+import { formatRelativeDate } from '../../shared/date-helper';
import { messages } from '../../shared/gettext';
import log from '../../shared/logging';
import { IWgKey, WgKeyState } from '../redux/settings/reducers';
@@ -35,7 +35,6 @@ import {
export interface IProps {
keyState: WgKeyState;
isOffline: boolean;
- locale: string;
tunnelState: TunnelState;
windowFocused: boolean;
@@ -56,14 +55,14 @@ export default class WireguardKeys extends React.Component<IProps, IState> {
public state = {
recentlyGeneratedKey: false,
userHasInitiatedVerification: false,
- ageOfKeyString: WireguardKeys.ageOfKeyString(this.props.keyState, this.props.locale),
+ ageOfKeyString: WireguardKeys.ageOfKeyString(this.props.keyState),
};
private keyAgeUpdateInterval?: number;
public static getDerivedStateFromProps(props: IProps) {
return {
- ageOfKeyString: WireguardKeys.ageOfKeyString(props.keyState, props.locale),
+ ageOfKeyString: WireguardKeys.ageOfKeyString(props.keyState),
};
}
@@ -276,11 +275,12 @@ export default class WireguardKeys extends React.Component<IProps, IState> {
}
}
- private static ageOfKeyString(keyState: WgKeyState, locale: string): string {
+ private static ageOfKeyString(keyState: WgKeyState): string {
switch (keyState.type) {
case 'key-set':
- case 'being-verified':
- return moment(keyState.key.created).locale(locale).fromNow();
+ case 'being-verified': {
+ return formatRelativeDate(new Date(), keyState.key.created, true);
+ }
default:
return '-';
}
@@ -288,7 +288,7 @@ export default class WireguardKeys extends React.Component<IProps, IState> {
private setAgeOfKeyStringState = () => {
this.setState({
- ageOfKeyString: WireguardKeys.ageOfKeyString(this.props.keyState, this.props.locale),
+ ageOfKeyString: WireguardKeys.ageOfKeyString(this.props.keyState),
});
};
diff --git a/gui/src/renderer/containers/SettingsPage.tsx b/gui/src/renderer/containers/SettingsPage.tsx
index 7d233e9f06..6985fd927c 100644
--- a/gui/src/renderer/containers/SettingsPage.tsx
+++ b/gui/src/renderer/containers/SettingsPage.tsx
@@ -10,7 +10,6 @@ const mapStateToProps = (state: IReduxState, props: IAppContext) => ({
),
loginState: state.account.status,
accountExpiry: state.account.expiry,
- expiryLocale: state.userInterface.locale,
appVersion: state.version.current,
consistentVersion: state.version.consistent,
upToDateVersion: state.version.suggestedUpgrade ? false : true,
diff --git a/gui/src/renderer/containers/WireguardKeysPage.tsx b/gui/src/renderer/containers/WireguardKeysPage.tsx
index 9e5fa6fc8c..e07e4718f2 100644
--- a/gui/src/renderer/containers/WireguardKeysPage.tsx
+++ b/gui/src/renderer/containers/WireguardKeysPage.tsx
@@ -9,7 +9,6 @@ import { IReduxState, ReduxDispatch } from '../redux/store';
const mapStateToProps = (state: IReduxState) => ({
keyState: state.settings.wireguardKeyState,
isOffline: state.connection.isBlocked,
- locale: state.userInterface.locale,
tunnelState: state.connection.status,
windowFocused: state.userInterface.windowFocused,
});
diff --git a/gui/src/shared/account-expiry.ts b/gui/src/shared/account-expiry.ts
index a76eb6ecc4..7ca382efb2 100644
--- a/gui/src/shared/account-expiry.ts
+++ b/gui/src/shared/account-expiry.ts
@@ -1,52 +1,27 @@
-import moment from 'moment';
-import { sprintf } from 'sprintf-js';
-import { messages } from './gettext';
+import { DateComponent, DateType, formatRelativeDate, dateByAddingComponent } from './date-helper';
import { capitalize } from './string-helpers';
-type DateArgument = string | Date | moment.Moment;
-
-export function hasExpired(expiry: DateArgument): boolean {
- return moment(expiry).isSameOrBefore(new Date());
+export function hasExpired(expiry: DateType): boolean {
+ return new Date(expiry).getTime() < Date.now();
}
-export function formatDate(date: DateArgument, locale: string): string {
- return moment(date).locale(locale).format('lll');
+export function closeToExpiry(expiry: DateType): boolean {
+ return (
+ !hasExpired(expiry) &&
+ new Date(expiry) <= dateByAddingComponent(new Date(), DateComponent.day, 3)
+ );
}
-export function formatDurationUntilExpiry(expiry: DateArgument, locale: string): string {
- const expiryMoment = moment(expiry).locale(locale);
- const daysDiff = expiryMoment.diff(new Date(), 'days');
-
- // Below three months we want to show the duration in days. Moments fromNow() method starts
- // measuring duration in months from 26 days and up.
- // https://momentjs.com/docs/#/displaying/fromnow/
- if (daysDiff >= 26 && daysDiff <= 90) {
- return sprintf(
- // TRANSLATORS: The remaining time left on the account measured in days.
- // TRANSLATORS: Available placeholders:
- // TRANSLATORS: %(duration)s - The remaining time measured in days.
- messages.pgettext('account-expiry', '%(duration)s days'),
- { duration: daysDiff },
- );
- } else {
- return expiryMoment.fromNow(true);
- }
+export function formatDate(date: DateType, locale: string): string {
+ return new Intl.DateTimeFormat(locale, { dateStyle: 'medium', timeStyle: 'short' }).format(
+ new Date(date),
+ );
}
export function formatRemainingTime(
- expiry: DateArgument,
- locale: string,
+ expiry: DateType,
shouldCapitalizeFirstLetter?: boolean,
): string {
- const duration = formatDurationUntilExpiry(expiry, locale);
-
- const remaining = sprintf(
- // TRANSLATORS: The remaining time left on the account displayed across the app.
- // TRANSLATORS: Available placeholders:
- // TRANSLATORS: %(duration)s - a localized remaining time (in minutes, hours, or days) until the account expiry
- messages.pgettext('account-expiry', '%(duration)s left'),
- { duration },
- );
-
+ const remaining = formatRelativeDate(new Date(), expiry, true);
return shouldCapitalizeFirstLetter ? capitalize(remaining) : remaining;
}
diff --git a/gui/src/shared/date-helper.ts b/gui/src/shared/date-helper.ts
new file mode 100644
index 0000000000..0011ed8fc2
--- /dev/null
+++ b/gui/src/shared/date-helper.ts
@@ -0,0 +1,121 @@
+import { sprintf } from 'sprintf-js';
+import { messages } from './gettext';
+
+export type DateType = Date | string;
+
+export enum DateComponent {
+ day,
+ hour,
+ minute,
+}
+
+export function dateByAddingComponent(date: DateType, component: DateComponent, value: number) {
+ const modifiedDate = new Date(date);
+ switch (component) {
+ case DateComponent.day:
+ modifiedDate.setDate(modifiedDate.getDate() + value);
+ break;
+ case DateComponent.hour:
+ modifiedDate.setHours(modifiedDate.getHours() + value);
+ break;
+ case DateComponent.minute:
+ modifiedDate.setMinutes(modifiedDate.getMinutes() + value);
+ break;
+ }
+
+ return modifiedDate;
+}
+
+export class DateDiff {
+ private readonly fromDate: Date;
+ private readonly toDate: Date;
+
+ public constructor(fromDate: DateType, toDate: DateType) {
+ this.fromDate = new Date(fromDate);
+ this.toDate = new Date(toDate);
+ }
+
+ get milliseconds(): number {
+ return this.toDate.getTime() - this.fromDate.getTime();
+ }
+
+ get seconds(): number {
+ return this.floor(this.milliseconds / 1000);
+ }
+
+ get minutes(): number {
+ return this.floor(this.seconds / 60);
+ }
+
+ get hours(): number {
+ return this.floor(this.minutes / 60);
+ }
+
+ get days(): number {
+ return this.floor(this.hours / 24);
+ }
+
+ get months(): number {
+ const months = new Date(Math.abs(this.milliseconds)).getUTCMonth();
+ const monthsWithSign = this.milliseconds >= 0 ? months : -months;
+ return this.years * 12 + monthsWithSign;
+ }
+
+ get years(): number {
+ const years = new Date(Math.abs(this.milliseconds)).getUTCFullYear() - 1970;
+ return this.milliseconds >= 0 ? years : -years;
+ }
+
+ private floor(n: number): number {
+ return n >= 0 ? Math.floor(n) : Math.ceil(n);
+ }
+}
+
+export function formatRelativeDate(
+ fromDate: DateType,
+ toDate: DateType,
+ withSuffix = false,
+): string {
+ const diff = new DateDiff(fromDate, toDate);
+ const years = Math.abs(diff.years);
+ const months = Math.abs(diff.months);
+ const days = Math.abs(diff.days);
+ const hours = Math.abs(diff.hours);
+ const minutes = Math.abs(diff.minutes);
+
+ if (!withSuffix) {
+ if (years > 0) {
+ return sprintf(messages.ngettext('1 year', '%d years', years), years);
+ } else if (months >= 3) {
+ return sprintf(messages.ngettext('1 month', '%d months', months), months);
+ } else if (days > 0) {
+ return sprintf(messages.ngettext('1 day', '%d days', days), days);
+ } else {
+ return messages.gettext('less than a day');
+ }
+ } else if (diff.milliseconds > 0) {
+ if (years > 0) {
+ return sprintf(messages.ngettext('1 year left', '%d years left', years), years);
+ } else if (months >= 3) {
+ return sprintf(messages.ngettext('1 month left', '%d months left', months), months);
+ } else if (days > 0) {
+ return sprintf(messages.ngettext('1 day left', '%d days left', days), days);
+ } else {
+ return messages.gettext('less than a day left');
+ }
+ } else {
+ if (years > 0) {
+ return sprintf(messages.ngettext('a year ago', '%d years ago', years), years);
+ } else if (months > 0) {
+ return sprintf(messages.ngettext('a month ago', '%d months ago', months), months);
+ } else if (days > 0) {
+ return sprintf(messages.ngettext('a day ago', '%d days ago', days), days);
+ } else if (hours > 0) {
+ return sprintf(messages.ngettext('an hour ago', '%d hours ago', hours), hours);
+ } else if (minutes > 0) {
+ return sprintf(messages.ngettext('a minute ago', '%d minutes ago', minutes), minutes);
+ } else {
+ return messages.gettext('less than a minute ago');
+ }
+ }
+}
diff --git a/gui/src/shared/logging.ts b/gui/src/shared/logging.ts
index 84eaa5f25c..f8c71fc41e 100644
--- a/gui/src/shared/logging.ts
+++ b/gui/src/shared/logging.ts
@@ -1,4 +1,3 @@
-import moment from 'moment';
import { ILogInput, ILogOutput, LogLevel } from './logging-types';
export class Logger {
@@ -13,7 +12,7 @@ export class Logger {
}
public log(level: LogLevel, ...data: unknown[]) {
- const time = moment().format('YYYY-MM-DD HH:mm:ss.SSS');
+ const time = this.getDateString();
const stringifiedData = data.map(this.stringifyData).join(' ');
const message = `[${time}][${LogLevel[level]}] ${stringifiedData}`;
@@ -30,6 +29,20 @@ export class Logger {
this.outputs.forEach((output) => output.dispose?.());
}
+ private getDateString(): string {
+ const date = new Date();
+ const year = date.getFullYear();
+ const month = Number(date.getMonth() + 1)
+ .toString()
+ .padStart(2, '0');
+ const day = Number(date.getDate()).toString().padStart(2, '0');
+ const hour = Number(date.getHours()).toString().padStart(2, '0');
+ const minute = Number(date.getMinutes()).toString().padStart(2, '0');
+ const second = Number(date.getSeconds()).toString().padStart(2, '0');
+ const millisecond = Number(date.getMilliseconds()).toString().padStart(3, '0');
+ return `${year}-${month}-${day} ${hour}:${minute}:${second}.${millisecond}`;
+ }
+
private stringifyData(data: unknown): string {
return typeof data === 'string' ? data : JSON.stringify(data);
}
diff --git a/gui/src/shared/notifications/close-to-account-expiry.ts b/gui/src/shared/notifications/close-to-account-expiry.ts
index 2e3c5ae49e..e0f13b33b3 100644
--- a/gui/src/shared/notifications/close-to-account-expiry.ts
+++ b/gui/src/shared/notifications/close-to-account-expiry.ts
@@ -1,8 +1,8 @@
-import moment from 'moment';
import { sprintf } from 'sprintf-js';
import { links } from '../../config.json';
import { messages } from '../../shared/gettext';
-import { formatDurationUntilExpiry, formatRemainingTime, hasExpired } from '../account-expiry';
+import { closeToExpiry, formatRemainingTime } from '../account-expiry';
+import { formatRelativeDate } from '../date-helper';
import {
InAppNotification,
InAppNotificationProvider,
@@ -19,13 +19,7 @@ export class CloseToAccountExpiryNotificationProvider
implements InAppNotificationProvider, SystemNotificationProvider {
public constructor(private context: CloseToAccountExpiryNotificationContext) {}
- public mayDisplay() {
- const willHaveExpiredInThreeDays = moment(this.context.accountExpiry).isSameOrBefore(
- moment().add(3, 'days'),
- );
-
- return !hasExpired(this.context.accountExpiry) && willHaveExpiredInThreeDays;
- }
+ public mayDisplay = () => closeToExpiry(this.context.accountExpiry);
public getSystemNotification(): SystemNotification {
const message = sprintf(
@@ -37,7 +31,7 @@ export class CloseToAccountExpiryNotificationProvider
'Account credit expires in %(duration)s. Buy more credit.',
),
{
- duration: formatDurationUntilExpiry(this.context.accountExpiry, this.context.locale),
+ duration: formatRelativeDate(new Date(), this.context.accountExpiry),
},
);
@@ -56,7 +50,7 @@ export class CloseToAccountExpiryNotificationProvider
public getInAppNotification(): InAppNotification {
const subtitle = sprintf(
messages.pgettext('in-app-notifications', '%(duration)s. Buy more credit.'),
- { duration: formatRemainingTime(this.context.accountExpiry, this.context.locale, true) },
+ { duration: formatRemainingTime(this.context.accountExpiry, true) },
);
return {
diff --git a/gui/test/date-helper.spec.ts b/gui/test/date-helper.spec.ts
new file mode 100644
index 0000000000..5ae9c5d496
--- /dev/null
+++ b/gui/test/date-helper.spec.ts
@@ -0,0 +1,152 @@
+import { expect } from 'chai';
+import { it, describe } from 'mocha';
+import * as date from '../src/shared/date-helper';
+
+describe('Date helper', () => {
+ it('should modify minutes', () => {
+ const initialDate = new Date('2021-01-01 13:37:10');
+ const earlierDate = date.dateByAddingComponent(initialDate, date.DateComponent.minute, -50);
+ const laterDate = date.dateByAddingComponent(initialDate, date.DateComponent.minute, 100);
+
+ expect(earlierDate.getFullYear()).to.equal(2021);
+ expect(earlierDate.getMonth()).to.equal(0);
+ expect(earlierDate.getDate()).to.equal(1);
+ expect(earlierDate.getHours()).to.equal(12);
+ expect(earlierDate.getMinutes()).to.equal(47);
+ expect(earlierDate.getSeconds()).to.equal(10);
+
+ expect(laterDate.getFullYear()).to.equal(2021);
+ expect(laterDate.getMonth()).to.equal(0);
+ expect(laterDate.getDate()).to.equal(1);
+ expect(laterDate.getHours()).to.equal(15);
+ expect(laterDate.getMinutes()).to.equal(17);
+ expect(laterDate.getSeconds()).to.equal(10);
+ });
+
+ it('should modify hours', () => {
+ const initialDate = new Date('2021-01-01 13:37:10');
+ const earlierDate = date.dateByAddingComponent(initialDate, date.DateComponent.hour, -50);
+ const laterDate = date.dateByAddingComponent(initialDate, date.DateComponent.hour, 100);
+
+ expect(earlierDate.getFullYear()).to.equal(2020);
+ expect(earlierDate.getMonth()).to.equal(11);
+ expect(earlierDate.getDate()).to.equal(30);
+ expect(earlierDate.getHours()).to.equal(11);
+ expect(earlierDate.getMinutes()).to.equal(37);
+ expect(earlierDate.getSeconds()).to.equal(10);
+
+ expect(laterDate.getFullYear()).to.equal(2021);
+ expect(laterDate.getMonth()).to.equal(0);
+ expect(laterDate.getDate()).to.equal(5);
+ expect(laterDate.getHours()).to.equal(17);
+ expect(laterDate.getMinutes()).to.equal(37);
+ expect(laterDate.getSeconds()).to.equal(10);
+ });
+
+ it('should modify days', () => {
+ const initialDate = new Date('2021-01-01 13:37:10');
+ const earlierDate = date.dateByAddingComponent(initialDate, date.DateComponent.day, -50);
+ const laterDate = date.dateByAddingComponent(initialDate, date.DateComponent.day, 100);
+
+ expect(earlierDate.getFullYear()).to.equal(2020);
+ expect(earlierDate.getMonth()).to.equal(10);
+ expect(earlierDate.getDate()).to.equal(12);
+ expect(earlierDate.getHours()).to.equal(13);
+ expect(earlierDate.getMinutes()).to.equal(37);
+ expect(earlierDate.getSeconds()).to.equal(10);
+
+ expect(laterDate.getFullYear()).to.equal(2021);
+ expect(laterDate.getMonth()).to.equal(3);
+ expect(laterDate.getDate()).to.equal(11);
+ expect(laterDate.getHours()).to.equal(13);
+ expect(laterDate.getMinutes()).to.equal(37);
+ expect(laterDate.getSeconds()).to.equal(10);
+ });
+
+ it('should calculate positive difference between dates', () => {
+ const diff1 = new date.DateDiff('2021-01-14 13:37:10', '2021-02-01 14:40:12');
+ expect(diff1.years).to.equal(0);
+ expect(diff1.months).to.equal(0);
+ expect(diff1.days).to.equal(18);
+ expect(diff1.hours).to.equal(diff1.days * 24 + 1);
+ expect(diff1.minutes).to.equal(diff1.hours * 60 + 3);
+ expect(diff1.seconds).to.equal(diff1.minutes * 60 + 2);
+
+ const diff2 = new date.DateDiff('2021-01-14 13:37:10', '2021-02-14 14:40:12');
+ expect(diff2.years).to.equal(0);
+ expect(diff2.months).to.equal(1);
+ expect(diff2.days).to.equal(31);
+ expect(diff2.hours).to.equal(diff2.days * 24 + 1);
+ expect(diff2.minutes).to.equal(diff2.hours * 60 + 3);
+ expect(diff2.seconds).to.equal(diff2.minutes * 60 + 2);
+
+ const diff3 = new date.DateDiff('2021-01-14 13:37:10', '2022-01-14 13:37:09');
+ expect(diff3.years).to.equal(0);
+ expect(diff3.months).to.equal(11);
+ expect(diff3.days).to.equal(364);
+ expect(diff3.hours).to.equal(diff3.days * 24 + 23);
+ expect(diff3.minutes).to.equal(diff3.hours * 60 + 59);
+ expect(diff3.seconds).to.equal(diff3.minutes * 60 + 59);
+ });
+
+ it('should calculate negative difference between dates', () => {
+ const diff1 = new date.DateDiff('2021-02-01 14:40:12', '2021-01-14 13:37:10');
+ expect(diff1.years).to.equal(0);
+ expect(diff1.months).to.equal(0);
+ expect(diff1.days).to.equal(-18, 'aa');
+ expect(diff1.hours).to.equal(diff1.days * 24 - 1);
+ expect(diff1.minutes).to.equal(diff1.hours * 60 - 3);
+ expect(diff1.seconds).to.equal(diff1.minutes * 60 - 2);
+ });
+
+ it('should format positive difference as string', () => {
+ const diff1 = date.formatRelativeDate('2021-01-01 13:37:10', '2021-01-01 13:37:20');
+ expect(diff1).to.equal('less than a day');
+
+ const diff2 = date.formatRelativeDate('2021-01-01 13:37:10', '2021-01-02 13:37:20');
+ expect(diff2).to.equal('1 day');
+
+ const diff3 = date.formatRelativeDate('2021-01-01 13:37:10', '2021-02-25 13:37:20');
+ expect(diff3).to.equal('55 days');
+
+ const diff4 = date.formatRelativeDate('2021-01-01 13:37:10', '2021-04-25 13:37:20');
+ expect(diff4).to.equal('3 months');
+
+ const diff5 = date.formatRelativeDate('2021-01-01 13:37:10', '2031-04-25 13:37:20');
+ expect(diff5).to.equal('10 years');
+ });
+
+ it('should format positive difference as string suffixed with "left"', () => {
+ const diff1 = date.formatRelativeDate('2021-01-01 13:37:10', '2021-01-01 13:37:20', true);
+ expect(diff1).to.equal('less than a day left');
+
+ const diff2 = date.formatRelativeDate('2021-01-01 13:37:10', '2021-01-02 13:37:20', true);
+ expect(diff2).to.equal('1 day left');
+
+ const diff3 = date.formatRelativeDate('2021-01-01 13:37:10', '2021-02-25 13:37:20', true);
+ expect(diff3).to.equal('55 days left');
+
+ const diff4 = date.formatRelativeDate('2021-01-01 13:37:10', '2021-04-25 13:37:20', true);
+ expect(diff4).to.equal('3 months left');
+
+ const diff5 = date.formatRelativeDate('2021-01-01 13:37:10', '2031-04-25 13:37:20', true);
+ expect(diff5).to.equal('10 years left');
+ });
+
+ it('should format negative difference as string', () => {
+ const diff1 = date.formatRelativeDate('2021-01-01 13:37:20', '2021-01-01 13:37:10', true);
+ expect(diff1).to.equal('less than a minute ago');
+
+ const diff2 = date.formatRelativeDate('2021-01-02 13:37:20', '2021-01-01 13:37:10', true);
+ expect(diff2).to.equal('a day ago');
+
+ const diff3 = date.formatRelativeDate('2021-02-25 13:37:20', '2021-01-01 13:37:10', true);
+ expect(diff3).to.equal('a month ago');
+
+ const diff4 = date.formatRelativeDate('2021-04-25 13:37:20', '2021-01-01 13:37:10', true);
+ expect(diff4).to.equal('3 months ago');
+
+ const diff5 = date.formatRelativeDate('2031-04-25 13:37:20', '2021-01-01 13:37:10', true);
+ expect(diff5).to.equal('10 years ago');
+ });
+});