diff --git a/.eslintrc.json b/.eslintrc.json index bc12bf8288..72cdf37c21 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,9 +1,9 @@ { - "extends": ["eslint:recommended", "plugin:prettier/recommended", "plugin:jsdoc/recommended"], - "plugins": ["prettier", "import", "jsdoc", "jest"], + "extends": ["eslint:recommended", "plugin:@stylistic/all-extends", "plugin:import/recommended", "plugin:jest/recommended", "plugin:jsdoc/recommended"], + "plugins": [], "env": { "browser": true, - "es2022": true, + "es2023": true, "jest/globals": true, "node": true }, @@ -16,7 +16,7 @@ }, "parserOptions": { "sourceType": "module", - "ecmaVersion": 2022, + "ecmaVersion": 2023, "ecmaFeatures": { "globalReturn": true } @@ -24,11 +24,60 @@ "rules": { "eqeqeq": "error", "import/order": "error", + "import/extensions": "error", + "import/newline-after-import": "error", + "jest/consistent-test-it": "warn", + "jest/expect-expect": "warn", + "jest/no-done-callback": "warn", + "jest/prefer-expect-resolves": "warn", + "jest/prefer-mock-promise-shorthand": "warn", + "jest/prefer-to-be": "warn", + "jest/prefer-to-have-length": "warn", "no-param-reassign": "error", "no-prototype-builtins": "off", "no-throw-literal": "error", "no-unused-vars": "off", "no-useless-return": "error", - "prefer-template": "error" - } + "object-shorthand": ["error", "methods"], + "prefer-template": "error", + "@stylistic/array-element-newline": ["error", "consistent"], + "@stylistic/arrow-parens": ["error", "always"], + "@stylistic/brace-style": "off", + "@stylistic/comma-dangle": ["error", "never"], + "@stylistic/dot-location": ["error", "property"], + "@stylistic/function-call-argument-newline": ["error", "consistent"], + "@stylistic/function-paren-newline": ["error", "consistent"], + "@stylistic/implicit-arrow-linebreak": ["error", "beside"], + "@stylistic/max-statements-per-line": ["error", { "max": 2 }], + "@stylistic/multiline-ternary": ["error", "always-multiline"], + "@stylistic/newline-per-chained-call": ["error", { "ignoreChainWithDepth": 4 }], + "@stylistic/no-extra-parens": "off", + "@stylistic/no-tabs": "off", + "@stylistic/object-curly-spacing": ["error", "always"], + "@stylistic/object-property-newline": ["error", { "allowAllPropertiesOnSameLine": true }], + "@stylistic/operator-linebreak": ["error", "before"], + "@stylistic/padded-blocks": "off", + "@stylistic/quote-props": ["error", "as-needed"], + "@stylistic/quotes": ["error", "double"], + "@stylistic/indent": ["error", "tab"], + "@stylistic/semi": ["error", "always"], + "@stylistic/space-before-function-paren": ["error", "always"], + "@stylistic/spaced-comment": "off" + }, + "overrides": [ + { + "files": ["config/config.js*"], + "rules": { + "@stylistic/comma-dangle": "off", + "@stylistic/indent": "off", + "@stylistic/no-multi-spaces": "off" + } + }, + { + "files": ["tests/configs/modules/weather/*.js"], + "rules": { + "@stylistic/quotes": "off" + } + } + ] } diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE.md similarity index 96% rename from .github/ISSUE_TEMPLATE/custom.md rename to .github/ISSUE_TEMPLATE.md index 7cbf0076b4..f24edfc4b0 100644 --- a/.github/ISSUE_TEMPLATE/custom.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,6 +1,6 @@ Hello and thank you for opening an issue. -**Please make sure that you have read the following lines before submitting your Issue:** +**⚠️ Please make sure that you have read the following lines before submitting your Issue:** ## I'm not sure if this is a bug diff --git a/.github/workflows/automated-tests.yaml b/.github/workflows/automated-tests.yaml index 959f43f5cd..fd3e1e898b 100644 --- a/.github/workflows/automated-tests.yaml +++ b/.github/workflows/automated-tests.yaml @@ -18,12 +18,12 @@ jobs: timeout-minutes: 30 strategy: matrix: - node-version: [18.x, 20.x] + node-version: [18.x, 20.x, 21.x] steps: - name: "Checkout code" uses: actions/checkout@v4 - name: "Use Node.js ${{ matrix.node-version }}" - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: "npm" diff --git a/.github/workflows/codecov-test-suites.yaml b/.github/workflows/codecov-test-suites.yaml deleted file mode 100644 index 44244bac69..0000000000 --- a/.github/workflows/codecov-test-suites.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# This workflow runs the automated test and uploads the coverage results to codecov.io -# For more information see: https://github.com/codecov/codecov-action - -name: "Run Codecov Tests" - -on: - push: - branches: [master, develop] - pull_request: - branches: [master, develop] - -permissions: - contents: read - -jobs: - run-and-upload-coverage-report: - runs-on: ubuntu-latest - timeout-minutes: 30 - steps: - - name: "Checkout code" - uses: actions/checkout@v4 - - name: "Install dependencies" - run: | - npm ci - - name: "Run coverage" - run: | - Xvfb :99 -screen 0 1024x768x16 & - export DISPLAY=:99 - touch css/custom.css - npm run test:coverage - - name: "Upload coverage results to codecov" - uses: codecov/codecov-action@v3 - with: - files: ./coverage/lcov.info - fail_ci_if_error: true diff --git a/.prettierignore b/.prettierignore index b92f216692..231245b1c1 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,6 @@ +*.js +.prettierignore /config /coverage package-lock.json +**.ics diff --git a/CHANGELOG.md b/CHANGELOG.md index 859bd590fb..2e4625d28b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,57 @@ This project adheres to [Semantic Versioning](https://semver.org/). ❤️ **Donate:** Enjoying MagicMirror²? [Please consider a donation!](https://magicmirror.builders/donate) With your help we can continue to improve the MagicMirror². +## [2.26.0] - 01-01-2024 + +Thanks to: @bnitkin, @bugsounet, @dependabot, @jkriegshauser, @kaennchenstruggle, @KristjanESPERANTO and @Ybbet. + +Special thanks to @khassel, @rejas and @sdetweil for taking over most (if not all) of the work on this release as project collaborators. This version would not be there without their effort. Thank you guys! You are awesome! + +This release also marks the latest release by Michael Teeuw. For more info, please read the following post: [A New Chapter for MagicMirror: The Community Takes the Lead](https://forum.magicmirror.builders/topic/18329/a-new-chapter-for-magicmirror-the-community-takes-the-lead). + +### Added + +- Added update notification updater (for 3rd party modules) +- Added node 21 to the test matrix +- Added transform object to calendar:customEvents +- Added ESLint rules for jest (including jest/expect-expect and jest/no-done-callback) + +### Removed + +- Removed Codecov workflow (not working anymore, other workflow required) (#3107) +- Removed titleReplace from calendar, replaced + extended by customEvents (backward compatibility included) (#3249) +- Removed failing unit test (#3254) +- Removed some unused variables + +### Updated + +- Update electron to v27 and update other dependencies as well as github actions +- Update newsfeed: Use `html-to-text` instead of regex for transform description +- Review ESLint config (#3269) +- Updated dependencies +- Clock module: optionally display current moon phase in addition to rise/set times +- electron is now per default started without gpu, if needed it must be enabled with new env var `ELECTRON_ENABLE_GPU=1` on startup (#3226) +- Replace prettier by stylistic in ESLint config to lint JavaScript (and disable some rules for `config/config.js*` files) +- Update node-ical to v0.17.1 and fix tests + +### Fixed + +- Avoid fade out/in on updateDom when many calendars are used +- Fix the option eventClass on customEvents. +- Fix yr API version in locationforecast and sunrise call (#3227) +- Fix cloneObject() function to respect RegExp (#3237) +- Fix newsfeed module for feeds using "a10:updated" tag (#3238) +- Fix issue template (#3167) +- Fix #3256 filter out bad results from rrule.between +- Fix calendar events sometimes not respecting deleted events (#3250) +- Fix electron loadurl locally on Windows when address "0.0.0.0" (#2550) +- Fix updatanotification (update_helper.js): catch error if reponse is not an JSON format (check PM2) +- Fix missing typeof in calendar module +- Fix style issues after prettier update +- Fix calendar test (#3291) by moving "Exdate check" from e2e to electron to run on a Thursday +- Fix calendar config params `fetchInterval` and `excludedEvents` were never used from single calendar config (#3297) +- Fix MM_PORT variable not used in electron and allow full path for MM_CONFIG_FILE variable (#3302) + ## [2.25.0] - 2023-10-01 Thanks to: @bugsounet, @dgoth, @dependabot, @kenzal, @Knapoc, @KristjanESPERANTO, @martingron, @NolanKingdon, @Paranoid93, @TeddyStarinvest and @Ybbet. @@ -37,7 +88,7 @@ Special thanks to @khassel, @rejas and @sdetweil for taking over most (if not al - Update issue template - Update dev/dependencies incl. electron to v26 - Replace pretty-quick by lint-staged () -- Update engine node >=18. v16 reached it's end of life. (#3170) +- Update engine node >=18. v16 reached its end of life. (#3170) - Update typescript definition for modules - Cleaned up nunjuck templates - Replace `node-fetch` with internal fetch (#2649) and remove `digest-fetch` @@ -50,7 +101,7 @@ Special thanks to @khassel, @rejas and @sdetweil for taking over most (if not al - Fix engine check on npm install (#3135) - Fix undefined formatTime method in clock module (#3143) - Fix clientonly startup fails after async added (#3151) -- Fix electron width/heigth when using xrandr under bullseye +- Fix electron width/height when using xrandr under bullseye - Fix time issue with certain recurring events in calendar module - Fix ipWhiteList test (#3179) - Fix newsfeed: Convert HTML entities, codes and tag in description (#3191) @@ -59,6 +110,7 @@ Special thanks to @khassel, @rejas and @sdetweil for taking over most (if not al - Fix `Uncaught SyntaxError: Identifier 'getCorsUrl' has already been declared (at utils.js:1:1)` when using `clock` and `weather` module (#3204) - Fix overriding `config.js` when running tests (#3201) - Fix issue in weathergov provider with probability of precipitation not showing up on hourly or daily forecast +- Fix yr weather provider after changes in yr API (#3189) ## [2.24.0] - 2023-07-01 @@ -101,7 +153,6 @@ Special thanks to @khassel, @rejas and @sdetweil for taking over most (if not al - Fix date not shown when clock in analog mode (#3100) - Fix envcanada today percentage-of-precipitation (#3106) - Fix updatenotification where no branch is checked out but e.g. a version tag (#3130) -- Fix yr weather provider after changes in yr API (#3189) ## [2.23.0] - 2023-04-04 diff --git a/README.md b/README.md index a7b795a6a8..2437c6b66e 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,6 @@ GitHub Actions Build Status - - CodeCov Status - diff --git a/clientonly/index.js b/clientonly/index.js index e13b0873dd..cee8ba22c6 100644 --- a/clientonly/index.js +++ b/clientonly/index.js @@ -7,7 +7,8 @@ /** * Helper function to get server address/hostname from either the commandline or env */ - function getServerAddress() { + function getServerAddress () { + /** * Get command line parameters * Assumes that a cmdline parameter is defined with `--key [value]` @@ -15,7 +16,7 @@ * @param {string} defaultValue value if no key is given at the command line * @returns {string} the value of the parameter */ - function getCommandLineParameter(key, defaultValue = undefined) { + function getCommandLineParameter (key, defaultValue = undefined) { const index = process.argv.indexOf(`--${key}`); const value = index > -1 ? process.argv[index + 1] : undefined; return value !== undefined ? String(value) : defaultValue; @@ -35,7 +36,7 @@ * @param {string} url location where the server is running. * @returns {Promise} the config */ - function getServerConfig(url) { + function getServerConfig (url) { // Return new pending promise return new Promise((resolve, reject) => { // Select http or https module, depending on requested url @@ -64,7 +65,7 @@ * @param {string} message error message to print * @param {number} code error code for the exit call */ - function fail(message, code = 1) { + function fail (message, code = 1) { if (message !== undefined && typeof message === "string") { console.log(message); } else { @@ -121,4 +122,4 @@ } else { fail(); } -})(); +}()); diff --git a/config/config.js.sample b/config/config.js.sample index e54be6fa28..06ff3a5d93 100644 --- a/config/config.js.sample +++ b/config/config.js.sample @@ -18,17 +18,17 @@ let config = { // - "0.0.0.0", "::" to listen on any interface // Default, when address config is left out or empty, is "localhost" port: 8080, - basePath: "/", // The URL path where MagicMirror² is hosted. If you are using a Reverse proxy - // you must set the sub path here. basePath must end with a / + basePath: "/", // The URL path where MagicMirror² is hosted. If you are using a Reverse proxy + // you must set the sub path here. basePath must end with a / ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], // Set [] to allow all IP addresses - // or add a specific IPv4 of 192.168.1.5 : - // ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.1.5"], - // or IPv4 range of 192.168.3.0 --> 192.168.3.15 use CIDR format : - // ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.3.0/28"], + // or add a specific IPv4 of 192.168.1.5 : + // ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.1.5"], + // or IPv4 range of 192.168.3.0 --> 192.168.3.15 use CIDR format : + // ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.3.0/28"], - useHttps: false, // Support HTTPS or not, default "false" will use HTTP - httpsPrivateKey: "", // HTTPS private key path, only require when useHttps is true - httpsCertificate: "", // HTTPS Certificate path, only require when useHttps is true + useHttps: false, // Support HTTPS or not, default "false" will use HTTP + httpsPrivateKey: "", // HTTPS private key path, only require when useHttps is true + httpsCertificate: "", // HTTPS Certificate path, only require when useHttps is true language: "en", locale: "en-US", @@ -109,4 +109,4 @@ let config = { }; /*************** DO NOT EDIT THE LINE BELOW ***************/ -if (typeof module !== "undefined") {module.exports = config;} +if (typeof module !== "undefined") { module.exports = config; } diff --git a/fonts/package-lock.json b/fonts/package-lock.json index 1324ec673c..d2b9f51074 100644 --- a/fonts/package-lock.json +++ b/fonts/package-lock.json @@ -1,6 +1,6 @@ { "name": "magicmirror-fonts", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -8,7 +8,7 @@ "license": "MIT", "dependencies": { "@fontsource/roboto": "^5.0.8", - "@fontsource/roboto-condensed": "^5.0.8" + "@fontsource/roboto-condensed": "^5.0.14" } }, "node_modules/@fontsource/roboto": { @@ -17,21 +17,9 @@ "integrity": "sha512-XxPltXs5R31D6UZeLIV1td3wTXU3jzd3f2DLsXI8tytMGBkIsGcc9sIyiupRtA8y73HAhuSCeweOoBqf6DbWCA==" }, "node_modules/@fontsource/roboto-condensed": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/@fontsource/roboto-condensed/-/roboto-condensed-5.0.8.tgz", - "integrity": "sha512-xAXYY+ys24OZ/eOfXJZILPu2xOB7c0ZruM4cd4TSzX3WGj4dZbXYwCEowLldKbZye6LTqiltpFLP/g/Ne0qGLg==" - } - }, - "dependencies": { - "@fontsource/roboto": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-5.0.8.tgz", - "integrity": "sha512-XxPltXs5R31D6UZeLIV1td3wTXU3jzd3f2DLsXI8tytMGBkIsGcc9sIyiupRtA8y73HAhuSCeweOoBqf6DbWCA==" - }, - "@fontsource/roboto-condensed": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/@fontsource/roboto-condensed/-/roboto-condensed-5.0.8.tgz", - "integrity": "sha512-xAXYY+ys24OZ/eOfXJZILPu2xOB7c0ZruM4cd4TSzX3WGj4dZbXYwCEowLldKbZye6LTqiltpFLP/g/Ne0qGLg==" + "version": "5.0.14", + "resolved": "https://registry.npmjs.org/@fontsource/roboto-condensed/-/roboto-condensed-5.0.14.tgz", + "integrity": "sha512-ZNBHUhE5/3z9efMIjpBblFsfLHgGotJjlzKd5Q8DODbkRRWy6Yh+JnbiaJZ8zwQyHyYBNOolk57BG4BcjSzrRg==" } } } diff --git a/fonts/package.json b/fonts/package.json index 0bb46d5715..5761f94f40 100644 --- a/fonts/package.json +++ b/fonts/package.json @@ -11,6 +11,6 @@ }, "dependencies": { "@fontsource/roboto": "^5.0.8", - "@fontsource/roboto-condensed": "^5.0.8" + "@fontsource/roboto-condensed": "^5.0.14" } } diff --git a/js/animateCSS.js b/js/animateCSS.js index cf3f26bcb7..b4db77b9ab 100644 --- a/js/animateCSS.js +++ b/js/animateCSS.js @@ -134,12 +134,12 @@ const AnimateCSSOut = [ * @param {string} [animation] animation name. * @param {number} [animationTime] animation duration. */ -function addAnimateCSS(element, animation, animationTime) { +function addAnimateCSS (element, animation, animationTime) { const animationName = `animate__${animation}`; const node = document.getElementById(element); if (!node) { // don't execute animate: we don't find div - Log.warn(`addAnimateCSS: node not found for`, element); + Log.warn("addAnimateCSS: node not found for", element); return; } node.style.setProperty("--animate-duration", `${animationTime}s`); @@ -151,12 +151,12 @@ function addAnimateCSS(element, animation, animationTime) { * @param {string} [element] div element to animate. * @param {string} [animation] animation name. */ -function removeAnimateCSS(element, animation) { +function removeAnimateCSS (element, animation) { const animationName = `animate__${animation}`; const node = document.getElementById(element); if (!node) { // don't execute animate: we don't find div - Log.warn(`removeAnimateCSS: node not found for`, element); + Log.warn("removeAnimateCSS: node not found for", element); return; } node.classList.remove("animate__animated", animationName); diff --git a/js/app.js b/js/app.js index 184940189c..3957ef933d 100644 --- a/js/app.js +++ b/js/app.js @@ -12,6 +12,7 @@ const fs = require("fs"); const path = require("path"); const envsub = require("envsub"); const Log = require("logger"); + const Server = require(`${__dirname}/server`); const Utils = require(`${__dirname}/utils`); const defaultModules = require(`${__dirname}/../modules/default/defaultmodules`); @@ -24,7 +25,7 @@ Log.log(`Starting MagicMirror: v${global.version}`); global.root_path = path.resolve(`${__dirname}/../`); if (process.env.MM_CONFIG_FILE) { - global.configuration_file = process.env.MM_CONFIG_FILE; + global.configuration_file = process.env.MM_CONFIG_FILE.replace(`${global.root_path}/`, ""); } // FIXME: Hotfix Pull Request @@ -46,7 +47,7 @@ process.on("uncaughtException", function (err) { * The core app. * @class */ -function App() { +function App () { let nodeHelpers = []; let httpServer; @@ -55,7 +56,7 @@ function App() { * @async * @returns {Promise} the loaded config or the defaults if something goes wrong */ - async function loadConfig() { + async function loadConfig () { Log.log("Loading config ..."); const defaults = require(`${__dirname}/defaults`); @@ -135,7 +136,7 @@ function App() { * if it encounters one option from the deprecated.js list * @param {object} userConfig The user config */ - function checkDeprecatedOptions(userConfig) { + function checkDeprecatedOptions (userConfig) { const deprecated = require(`${global.root_path}/js/deprecated`); const deprecatedOptions = deprecated.configs; @@ -149,7 +150,7 @@ function App() { * Loads a specific module. * @param {string} module The name of the module (including subpath). */ - function loadModule(module) { + function loadModule (module) { const elements = module.split("/"); const moduleName = elements[elements.length - 1]; let moduleFolder = `${__dirname}/../modules/${module}`; @@ -203,7 +204,7 @@ function App() { * @param {Module[]} modules All modules to be loaded * @returns {Promise} A promise that is resolved when all modules been loaded */ - async function loadModules(modules) { + async function loadModules (modules) { Log.log("Loading module helpers ..."); for (let module of modules) { @@ -220,7 +221,7 @@ function App() { * @returns {number} A positive number if a is larger than b, a negative * number if a is smaller and 0 if they are the same */ - function cmpVersions(a, b) { + function cmpVersions (a, b) { let i, diff; const regExStrip0 = /(\.0+)+$/; const segmentsA = a.replace(regExStrip0, "").split("."); diff --git a/js/check_config.js b/js/check_config.js index 22a109185c..3d868bd502 100644 --- a/js/check_config.js +++ b/js/check_config.js @@ -20,7 +20,7 @@ const Utils = require(`${rootPath}/js/utils.js`); * Check if set by environment variable MM_CONFIG_FILE * @returns {string} path and filename of the config file */ -function getConfigFile() { +function getConfigFile () { // FIXME: This function should be in core. Do you want refactor me ;) ?, be good! return path.resolve(process.env.MM_CONFIG_FILE || `${rootPath}/config/config.js`); } @@ -28,7 +28,7 @@ function getConfigFile() { /** * Checks the config file using eslint. */ -function checkConfigFile() { +function checkConfigFile () { const configFileName = getConfigFile(); // Check if file is present diff --git a/js/class.js b/js/class.js index 4e76935942..c3a0ab22eb 100644 --- a/js/class.js +++ b/js/class.js @@ -9,7 +9,7 @@ */ (function () { let initializing = false; - const fnTest = /xyz/.test(function () { + const fnTest = (/xyz/).test(function () { xyz; }) ? /\b_super\b/ @@ -36,31 +36,31 @@ // Copy the properties over onto the new prototype for (const name in prop) { // Check if we're overwriting an existing function - prototype[name] = - typeof prop[name] === "function" && typeof _super[name] === "function" && fnTest.test(prop[name]) + prototype[name] + = typeof prop[name] === "function" && typeof _super[name] === "function" && fnTest.test(prop[name]) ? (function (name, fn) { - return function () { - const tmp = this._super; + return function () { + const tmp = this._super; - // Add a new ._super() method that is the same method - // but on the super-class - this._super = _super[name]; + // Add a new ._super() method that is the same method + // but on the super-class + this._super = _super[name]; - // The method only need to be bound temporarily, so we - // remove it when we're done executing - const ret = fn.apply(this, arguments); - this._super = tmp; + // The method only need to be bound temporarily, so we + // remove it when we're done executing + const ret = fn.apply(this, arguments); + this._super = tmp; - return ret; - }; - })(name, prop[name]) + return ret; + }; + }(name, prop[name])) : prop[name]; } /** * The dummy class constructor */ - function Class() { + function Class () { // All construction is actually done in the init method if (!initializing && this.init) { this.init.apply(this, arguments); @@ -78,18 +78,22 @@ return Class; }; -})(); +}()); /** * Define the clone method for later use. Helper Method. * @param {object} obj Object to be cloned * @returns {object} the cloned object */ -function cloneObject(obj) { +function cloneObject (obj) { if (obj === null || typeof obj !== "object") { return obj; } + if (obj.constructor.name === "RegExp") { + return new RegExp(obj); + } + const temp = obj.constructor(); // give temp the original obj's constructor for (const key in obj) { temp[key] = cloneObject(obj[key]); diff --git a/js/electron.js b/js/electron.js index 43f637acbb..7eae34c544 100644 --- a/js/electron.js +++ b/js/electron.js @@ -8,9 +8,10 @@ const Log = require("./logger"); let config = process.env.config ? JSON.parse(process.env.config) : {}; // Module to control application life. const app = electron.app; -// If ELECTRON_DISABLE_GPU is set electron is started with --disable-gpu flag. +// Per default electron is started with --disable-gpu flag, if you want the gpu enabled, +// you must set the env var ELECTRON_ENABLE_GPU=1 on startup. // See https://www.electronjs.org/docs/latest/tutorial/offscreen-rendering for more info. -if (process.env.ELECTRON_DISABLE_GPU !== undefined) { +if (process.env.ELECTRON_ENABLE_GPU !== "1") { app.disableHardwareAcceleration(); } @@ -24,7 +25,7 @@ let mainWindow; /** * */ -function createWindow() { +function createWindow () { // see https://www.electronjs.org/docs/latest/api/screen // Create a window that fills the screen's available work area. let electronSize = (800, 600); @@ -77,8 +78,9 @@ function createWindow() { prefix = "http://"; } - let address = (config.address === void 0) | (config.address === "") ? (config.address = "localhost") : config.address; - mainWindow.loadURL(`${prefix}${address}:${config.port}`); + let address = (config.address === void 0) | (config.address === "") | (config.address === "0.0.0.0") ? (config.address = "localhost") : config.address; + const port = process.env.MM_PORT || config.port; + mainWindow.loadURL(`${prefix}${address}:${port}`); // Open the DevTools if run with "npm start dev" if (process.argv.includes("dev")) { @@ -120,11 +122,11 @@ function createWindow() { mainWindow.webContents.session.webRequest.onHeadersReceived((details, callback) => { let curHeaders = details.responseHeaders; if (config["ignoreXOriginHeader"] || false) { - curHeaders = Object.fromEntries(Object.entries(curHeaders).filter((header) => !/x-frame-options/i.test(header[0]))); + curHeaders = Object.fromEntries(Object.entries(curHeaders).filter((header) => !(/x-frame-options/i).test(header[0]))); } if (config["ignoreContentSecurityPolicy"] || false) { - curHeaders = Object.fromEntries(Object.entries(curHeaders).filter((header) => !/content-security-policy/i.test(header[0]))); + curHeaders = Object.fromEntries(Object.entries(curHeaders).filter((header) => !(/content-security-policy/i).test(header[0]))); } callback({ responseHeaders: curHeaders }); diff --git a/js/loader.js b/js/loader.js index a5dc36fcab..b4b32f4f3c 100644 --- a/js/loader.js +++ b/js/loader.js @@ -7,6 +7,7 @@ * MIT Licensed. */ const Loader = (function () { + /* Create helper variables */ const loadedModuleFiles = []; @@ -196,10 +197,11 @@ const Loader = (function () { /* Public Methods */ return { + /** * Load all modules as defined in the config. */ - loadModules: async function () { + async loadModules () { let moduleData = getModuleData(); /** @@ -230,7 +232,7 @@ const Loader = (function () { * @param {Module} module The module that calls the loadFile function. * @returns {Promise} resolved when the file is loaded */ - loadFileForModule: async function (fileName, module) { + async loadFileForModule (fileName, module) { if (loadedFiles.indexOf(fileName.toLowerCase()) !== -1) { Log.log(`File already loaded: ${fileName}`); return; @@ -256,4 +258,4 @@ const Loader = (function () { return loadFile(module.file(fileName)); } }; -})(); +}()); diff --git a/js/logger.js b/js/logger.js index e6a244cb73..228c53e999 100644 --- a/js/logger.js +++ b/js/logger.js @@ -22,7 +22,7 @@ // Browser globals (root is window) root.Log = factory(root.config); } -})(this, function (config) { +}(this, function (config) { let logLevel; let enableLog; if (typeof exports === "object") { @@ -50,7 +50,7 @@ logLevel.setLogLevel = function (newLevel) { if (newLevel) { - Object.keys(logLevel).forEach(function (key, index) { + Object.keys(logLevel).forEach(function (key) { if (!newLevel.includes(key.toLocaleUpperCase())) { logLevel[key] = function () {}; } @@ -59,21 +59,21 @@ }; } else { logLevel = { - debug: function () {}, - log: function () {}, - info: function () {}, - warn: function () {}, - error: function () {}, - group: function () {}, - groupCollapsed: function () {}, - groupEnd: function () {}, - time: function () {}, - timeEnd: function () {}, - timeStamp: function () {} + debug () {}, + log () {}, + info () {}, + warn () {}, + error () {}, + group () {}, + groupCollapsed () {}, + groupEnd () {}, + time () {}, + timeEnd () {}, + timeStamp () {} }; logLevel.setLogLevel = function () {}; } return logLevel; -}); +})); diff --git a/js/main.js b/js/main.js index c7d4d39f77..7bda7ababa 100644 --- a/js/main.js +++ b/js/main.js @@ -479,7 +479,6 @@ const MM = (function () { */ const loadConfig = function () { // FIXME: Think about how to pass config around without breaking tests - /* eslint-disable */ if (typeof config === "undefined") { config = defaults; Log.error("Config file is missing! Please create a config file."); @@ -487,7 +486,6 @@ const MM = (function () { } config = Object.assign({}, defaults, config); - /* eslint-enable */ }; /** @@ -495,6 +493,7 @@ const MM = (function () { * @param {Module[]} modules Array of modules. */ const setSelectionMethodsForModules = function (modules) { + /** * Filter modules with the specified classes. * @param {string|string[]} className one or multiple classnames (array or space divided). @@ -580,12 +579,13 @@ const MM = (function () { }; return { + /* Public Methods */ /** * Main init method. */ - init: async function () { + async init () { Log.info("Initializing MagicMirror²."); loadConfig(); @@ -599,7 +599,7 @@ const MM = (function () { * Gets called when all modules are started. * @param {Module[]} moduleObjects All module instances. */ - modulesStarted: function (moduleObjects) { + modulesStarted (moduleObjects) { modules = []; let startUp = ""; @@ -636,7 +636,7 @@ const MM = (function () { * @param {*} payload The payload of the notification. * @param {Module} sender The module that sent the notification. */ - sendNotification: function (notification, payload, sender) { + sendNotification (notification, payload, sender) { if (arguments.length < 3) { Log.error("sendNotification: Missing arguments."); return; @@ -661,7 +661,7 @@ const MM = (function () { * @param {Module} module The module that needs an update. * @param {object|number} [updateOptions] The (optional) number of microseconds for the animation or object with updateOptions (speed/animates) */ - updateDom: function (module, updateOptions) { + updateDom (module, updateOptions) { if (!(module instanceof Module)) { Log.error("updateDom: Sender should be a module."); return; @@ -680,7 +680,7 @@ const MM = (function () { * Returns a collection of all modules currently active. * @returns {Module[]} A collection of all modules currently active. */ - getModules: function () { + getModules () { setSelectionMethodsForModules(modules); return modules; }, @@ -692,7 +692,7 @@ const MM = (function () { * @param {Function} callback Called when the animation is done. * @param {object} [options] Optional settings for the hide method. */ - hideModule: function (module, speed, callback, options) { + hideModule (module, speed, callback, options) { module.hidden = true; hideModule(module, speed, callback, options); }, @@ -704,12 +704,12 @@ const MM = (function () { * @param {Function} callback Called when the animation is done. * @param {object} [options] Optional settings for the show method. */ - showModule: function (module, speed, callback, options) { + showModule (module, speed, callback, options) { // do not change module.hidden yet, only if we really show it later showModule(module, speed, callback, options); } }; -})(); +}()); // Add polyfill for Object.assign. if (typeof Object.assign !== "function") { @@ -732,7 +732,7 @@ if (typeof Object.assign !== "function") { } return output; }; - })(); + }()); } MM.init(); diff --git a/js/module.js b/js/module.js index 4ef3ab1d61..d9d40ac50b 100644 --- a/js/module.js +++ b/js/module.js @@ -8,6 +8,7 @@ * MIT Licensed. */ const Module = Class.extend({ + /********************************************************* * All methods (and properties) below can be subclassed. * *********************************************************/ @@ -33,14 +34,14 @@ const Module = Class.extend({ /** * Called when the module is instantiated. */ - init: function () { + init () { //Log.log(this.defaults); }, /** * Called when the module is started. */ - start: async function () { + async start () { Log.info(`Starting module: ${this.name}`); }, @@ -48,7 +49,7 @@ const Module = Class.extend({ * Returns a list of scripts the module requires to be loaded. * @returns {string[]} An array with filenames. */ - getScripts: function () { + getScripts () { return []; }, @@ -56,7 +57,7 @@ const Module = Class.extend({ * Returns a list of stylesheets the module requires to be loaded. * @returns {string[]} An array with filenames. */ - getStyles: function () { + getStyles () { return []; }, @@ -66,7 +67,7 @@ const Module = Class.extend({ * return Map - * @returns {*} A map with langKeys and filenames. */ - getTranslations: function () { + getTranslations () { return false; }, @@ -76,14 +77,14 @@ const Module = Class.extend({ * Alternatively, the getTemplate method could be subclassed. * @returns {HTMLElement|Promise} The dom or a promise with the dom to display. */ - getDom: function () { + getDom () { return new Promise((resolve) => { const div = document.createElement("div"); const template = this.getTemplate(); const templateData = this.getTemplateData(); // Check to see if we need to render a template string or a file. - if (/^.*((\.html)|(\.njk))$/.test(template)) { + if ((/^.*((\.html)|(\.njk))$/).test(template)) { // the template is a filename this.nunjucksEnvironment().render(template, templateData, function (err, res) { if (err) { @@ -109,7 +110,7 @@ const Module = Class.extend({ * This method needs to be subclassed if the module wants to display modified headers on the mirror. * @returns {string} The header to display above the header. */ - getHeader: function () { + getHeader () { return this.data.header; }, @@ -120,7 +121,7 @@ const Module = Class.extend({ * If the string ends with '.html' it's considered a file from within the module's folder. * @returns {string} The template string of filename. */ - getTemplate: function () { + getTemplate () { return `
${this.name}
${this.identifier}
`; }, @@ -129,7 +130,7 @@ const Module = Class.extend({ * This method needs to be subclassed if the module wants to use a custom data. * @returns {object} The data for the template */ - getTemplateData: function () { + getTemplateData () { return {}; }, @@ -139,7 +140,7 @@ const Module = Class.extend({ * @param {*} payload The payload of the notification. * @param {Module} sender The module that sent the notification. */ - notificationReceived: function (notification, payload, sender) { + notificationReceived (notification, payload, sender) { if (sender) { // Log.log(this.name + " received a module notification: " + notification + " from sender: " + sender.name); } else { @@ -152,7 +153,7 @@ const Module = Class.extend({ * The environment is checked in the _nunjucksEnvironment instance variable. * @returns {object} The Nunjucks Environment */ - nunjucksEnvironment: function () { + nunjucksEnvironment () { if (this._nunjucksEnvironment !== null) { return this._nunjucksEnvironment; } @@ -174,21 +175,21 @@ const Module = Class.extend({ * @param {string} notification The identifier of the notification. * @param {*} payload The payload of the notification. */ - socketNotificationReceived: function (notification, payload) { + socketNotificationReceived (notification, payload) { Log.log(`${this.name} received a socket notification: ${notification} - Payload: ${payload}`); }, /** * Called when the module is hidden. */ - suspend: function () { + suspend () { Log.log(`${this.name} is suspended.`); }, /** * Called when the module is shown. */ - resume: function () { + resume () { Log.log(`${this.name} is resumed.`); }, @@ -200,7 +201,7 @@ const Module = Class.extend({ * Set the module data. * @param {object} data The module data */ - setData: function (data) { + setData (data) { this.data = data; this.name = data.name; this.identifier = data.identifier; @@ -216,7 +217,7 @@ const Module = Class.extend({ * @param {object} config The combined module config. * @param {boolean} deep Merge module config in deep. */ - setConfig: function (config, deep) { + setConfig (config, deep) { this.config = deep ? configMerge({}, this.defaults, config) : Object.assign({}, this.defaults, config); }, @@ -225,7 +226,7 @@ const Module = Class.extend({ * It also registers the notification callback. * @returns {MMSocket} a socket object */ - socket: function () { + socket () { if (typeof this._socket === "undefined") { this._socket = new MMSocket(this.name); } @@ -242,7 +243,7 @@ const Module = Class.extend({ * @param {string} file Filename * @returns {string} the file path */ - file: function (file) { + file (file) { return `${this.data.path}/${file}`.replace("//", "/"); }, @@ -250,7 +251,7 @@ const Module = Class.extend({ * Load all required stylesheets by requesting the MM object to load the files. * @returns {Promise} */ - loadStyles: function () { + loadStyles () { return this.loadDependencies("getStyles"); }, @@ -258,7 +259,7 @@ const Module = Class.extend({ * Load all required scripts by requesting the MM object to load the files. * @returns {Promise} */ - loadScripts: function () { + loadScripts () { return this.loadDependencies("getScripts"); }, @@ -267,7 +268,7 @@ const Module = Class.extend({ * @param {string} funcName Function name to call to get scripts or styles. * @returns {Promise} */ - loadDependencies: async function (funcName) { + async loadDependencies (funcName) { let dependencies = this[funcName](); const loadNextDependency = async () => { @@ -288,7 +289,7 @@ const Module = Class.extend({ * Load all translations. * @returns {Promise} */ - loadTranslations: async function () { + async loadTranslations () { const translations = this.getTranslations() || {}; const language = config.language.toLowerCase(); @@ -320,7 +321,7 @@ const Module = Class.extend({ * @param {string} [defaultValue] The default value with variables. * @returns {string} the translated key */ - translate: function (key, defaultValueOrVariables, defaultValue) { + translate (key, defaultValueOrVariables, defaultValue) { if (typeof defaultValueOrVariables === "object") { return Translator.translate(this, key, defaultValueOrVariables) || defaultValue || ""; } @@ -331,7 +332,7 @@ const Module = Class.extend({ * Request an (animated) update of the module. * @param {number|object} [updateOptions] The speed of the animation or object with for updateOptions (speed/animates) */ - updateDom: function (updateOptions) { + updateDom (updateOptions) { MM.updateDom(this, updateOptions); }, @@ -340,7 +341,7 @@ const Module = Class.extend({ * @param {string} notification The identifier of the notification. * @param {*} payload The payload of the notification. */ - sendNotification: function (notification, payload) { + sendNotification (notification, payload) { MM.sendNotification(notification, payload, this); }, @@ -349,7 +350,7 @@ const Module = Class.extend({ * @param {string} notification The identifier of the notification. * @param {*} payload The payload of the notification. */ - sendSocketNotification: function (notification, payload) { + sendSocketNotification (notification, payload) { this.socket().sendNotification(notification, payload); }, @@ -359,7 +360,7 @@ const Module = Class.extend({ * @param {Function} callback Called when the animation is done. * @param {object} [options] Optional settings for the hide method. */ - hide: function (speed, callback, options = {}) { + hide (speed, callback, options = {}) { let usedCallback = callback || function () {}; let usedOptions = options; @@ -386,7 +387,7 @@ const Module = Class.extend({ * @param {Function} callback Called when the animation is done. * @param {object} [options] Optional settings for the show method. */ - show: function (speed, callback, options) { + show (speed, callback, options) { let usedCallback = callback || function () {}; let usedOptions = options; @@ -430,7 +431,7 @@ const Module = Class.extend({ * @param {object} result the initial object * @returns {object} the merged config */ -function configMerge(result) { +function configMerge (result) { const stack = Array.prototype.slice.call(arguments, 1); let item, key; @@ -493,7 +494,7 @@ window.Module = Module; * @returns {number} A positive number if a is larger than b, a negative * number if a is smaller and 0 if they are the same */ -function cmpVersions(a, b) { +function cmpVersions (a, b) { const regExStrip0 = /(\.0+)+$/; const segmentsA = a.replace(regExStrip0, "").split("."); const segmentsB = b.replace(regExStrip0, "").split("."); diff --git a/js/node_helper.js b/js/node_helper.js index c555eb72c0..dee0beeb3a 100644 --- a/js/node_helper.js +++ b/js/node_helper.js @@ -9,15 +9,15 @@ const Log = require("logger"); const Class = require("./class"); const NodeHelper = Class.extend({ - init() { + init () { Log.log("Initializing new module helper ..."); }, - loaded() { + loaded () { Log.log(`Module helper loaded: ${this.name}`); }, - start() { + start () { Log.log(`Starting module helper: ${this.name}`); }, @@ -26,7 +26,7 @@ const NodeHelper = Class.extend({ * Close any open connections, stop any sub-processes and * gracefully exit the module. */ - stop() { + stop () { Log.log(`Stopping module helper: ${this.name}`); }, @@ -35,7 +35,7 @@ const NodeHelper = Class.extend({ * @param {string} notification The identifier of the notification. * @param {*} payload The payload of the notification. */ - socketNotificationReceived(notification, payload) { + socketNotificationReceived (notification, payload) { Log.log(`${this.name} received a socket notification: ${notification} - Payload: ${payload}`); }, @@ -43,7 +43,7 @@ const NodeHelper = Class.extend({ * Set the module name. * @param {string} name Module name. */ - setName(name) { + setName (name) { this.name = name; }, @@ -51,7 +51,7 @@ const NodeHelper = Class.extend({ * Set the module path. * @param {string} path Module path. */ - setPath(path) { + setPath (path) { this.path = path; }, @@ -61,7 +61,7 @@ const NodeHelper = Class.extend({ * argument notification string - The identifier of the notification. * argument payload mixed - The payload of the notification. */ - sendSocketNotification(notification, payload) { + sendSocketNotification (notification, payload) { this.io.of(this.name).emit(notification, payload); }, @@ -71,7 +71,7 @@ const NodeHelper = Class.extend({ * * argument app Express app - The Express app object. */ - setExpressApp(app) { + setExpressApp (app) { this.expressApp = app; app.use(`/${this.name}`, express.static(`${this.path}/public`)); @@ -83,7 +83,7 @@ const NodeHelper = Class.extend({ * * argument io Socket.io - The Socket io object. */ - setSocketIO(io) { + setSocketIO (io) { this.io = io; Log.log(`Connecting socket for: ${this.name}`); diff --git a/js/server.js b/js/server.js index 0cb1b92286..726a18e32a 100644 --- a/js/server.js +++ b/js/server.js @@ -22,7 +22,7 @@ const { cors, getConfig, getHtml, getVersion, getStartup } = require("./server_f * @param {object} config The MM config * @class */ -function Server(config) { +function Server (config) { const app = express(); const port = process.env.MM_PORT || config.port; const serverSockets = new Set(); diff --git a/js/server_functions.js b/js/server_functions.js index 5693ad41c4..c975df7c5e 100644 --- a/js/server_functions.js +++ b/js/server_functions.js @@ -1,6 +1,7 @@ const fs = require("fs"); const path = require("path"); const Log = require("logger"); + const startUp = new Date(); /** @@ -8,7 +9,7 @@ const startUp = new Date(); * @param {Request} req - the request * @param {Response} res - the result */ -function getConfig(req, res) { +function getConfig (req, res) { res.send(config); } @@ -17,7 +18,7 @@ function getConfig(req, res) { * @param {Request} req - the request * @param {Response} res - the result */ -function getStartup(req, res) { +function getStartup (req, res) { res.send(startUp); } @@ -30,7 +31,7 @@ function getStartup(req, res) { * @param {Request} req - the request * @param {Response} res - the result */ -async function cors(req, res) { +async function cors (req, res) { try { const urlRegEx = "url=(.+?)$"; let url; @@ -67,7 +68,7 @@ async function cors(req, res) { * @param {string} url - The url containing the headers and values to send. * @returns {object} An object specifying name and value of the headers. */ -function getHeadersToSend(url) { +function getHeadersToSend (url) { const headersToSend = { "User-Agent": `Mozilla/5.0 MagicMirror/${global.version}` }; const headersToSendMatch = new RegExp("sendheaders=(.+?)(&|$)", "g").exec(url); if (headersToSendMatch) { @@ -88,7 +89,7 @@ function getHeadersToSend(url) { * @param {string} url - The url containing the expected headers from the response. * @returns {string[]} headers - The name of the expected headers. */ -function geExpectedRecievedHeaders(url) { +function geExpectedRecievedHeaders (url) { const expectedRecievedHeaders = ["Content-Type"]; const expectedRecievedHeadersMatch = new RegExp("expectedheaders=(.+?)(&|$)", "g").exec(url); if (expectedRecievedHeadersMatch) { @@ -105,7 +106,7 @@ function geExpectedRecievedHeaders(url) { * @param {Request} req - the request * @param {Response} res - the result */ -function getHtml(req, res) { +function getHtml (req, res) { let html = fs.readFileSync(path.resolve(`${global.root_path}/index.html`), { encoding: "utf8" }); html = html.replace("#VERSION#", global.version); @@ -123,7 +124,7 @@ function getHtml(req, res) { * @param {Request} req - the request * @param {Response} res - the result */ -function getVersion(req, res) { +function getVersion (req, res) { res.send(global.version); } diff --git a/js/translator.js b/js/translator.js index 2ebb0580fe..d329ffd076 100644 --- a/js/translator.js +++ b/js/translator.js @@ -7,12 +7,13 @@ * MIT Licensed. */ const Translator = (function () { + /** * Load a JSON file via XHR. * @param {string} file Path of the file we want to load. * @returns {Promise} the translations in the specified file */ - async function loadJSON(file) { + async function loadJSON (file) { const xhr = new XMLHttpRequest(); return new Promise(function (resolve) { xhr.overrideMimeType("application/json"); @@ -47,7 +48,8 @@ const Translator = (function () { * @param {object} variables The variables to use within the translation template (optional) * @returns {string} the translated key */ - translate: function (module, key, variables = {}) { + translate (module, key, variables = {}) { + /** * Combines template and variables like: * template: "Please wait for {timeToWait} before continuing with {work}." @@ -57,7 +59,7 @@ const Translator = (function () { * @param {object} variables Variables for the placeholder * @returns {string} the template filled with the variables */ - function createStringFromTemplate(template, variables) { + function createStringFromTemplate (template, variables) { if (Object.prototype.toString.call(template) !== "[object String]") { return template; } @@ -99,7 +101,7 @@ const Translator = (function () { * @param {string} file Path of the file we want to load. * @param {boolean} isFallback Flag to indicate fallback translations. */ - async load(module, file, isFallback) { + async load (module, file, isFallback) { Log.log(`${module.name} - Load translation${isFallback ? " fallback" : ""}: ${file}`); if (this.translationsFallback[module.name]) { @@ -115,7 +117,7 @@ const Translator = (function () { * Load the core translations. * @param {string} lang The language identifier of the core language. */ - loadCoreTranslations: async function (lang) { + async loadCoreTranslations (lang) { if (lang in translations) { Log.log(`Loading core translation file: ${translations[lang]}`); this.coreTranslations = await loadJSON(translations[lang]); @@ -130,7 +132,7 @@ const Translator = (function () { * Load the core translations' fallback. * The first language defined in translations.js will be used. */ - loadCoreTranslationsFallback: async function () { + async loadCoreTranslationsFallback () { let first = Object.keys(translations)[0]; if (first) { Log.log(`Loading core translation fallback file: ${translations[first]}`); @@ -138,6 +140,6 @@ const Translator = (function () { } } }; -})(); +}()); window.Translator = Translator; diff --git a/modules/default/alert/alert.js b/modules/default/alert/alert.js index 1bd11d02f6..da26292372 100644 --- a/modules/default/alert/alert.js +++ b/modules/default/alert/alert.js @@ -17,15 +17,15 @@ Module.register("alert", { welcome_message: false // shown at startup }, - getScripts() { + getScripts () { return ["notificationFx.js"]; }, - getStyles() { - return ["font-awesome.css", this.file(`./styles/notificationFx.css`), this.file(`./styles/${this.config.position}.css`)]; + getStyles () { + return ["font-awesome.css", this.file("./styles/notificationFx.css"), this.file(`./styles/${this.config.position}.css`)]; }, - getTranslations() { + getTranslations () { return { bg: "translations/bg.json", da: "translations/da.json", @@ -40,11 +40,11 @@ Module.register("alert", { }; }, - getTemplate(type) { + getTemplate (type) { return `templates/${type}.njk`; }, - async start() { + async start () { Log.info(`Starting module: ${this.name}`); if (this.config.effect === "slide") { @@ -57,7 +57,7 @@ Module.register("alert", { } }, - notificationReceived(notification, payload, sender) { + notificationReceived (notification, payload, sender) { if (notification === "SHOW_ALERT") { if (payload.type === "notification") { this.showNotification(payload); @@ -69,7 +69,7 @@ Module.register("alert", { } }, - async showNotification(notification) { + async showNotification (notification) { const message = await this.renderMessage(notification.templateName || "notification", notification); new NotificationFx({ @@ -80,7 +80,7 @@ Module.register("alert", { }).show(); }, - async showAlert(alert, sender) { + async showAlert (alert, sender) { // If module already has an open alert close it if (this.alerts[sender.name]) { this.hideAlert(sender, false); @@ -113,7 +113,7 @@ Module.register("alert", { } }, - hideAlert(sender, close = true) { + hideAlert (sender, close = true) { // Dismiss alert and remove from this.alerts if (this.alerts[sender.name]) { this.alerts[sender.name].dismiss(close); @@ -125,7 +125,7 @@ Module.register("alert", { } }, - renderMessage(type, data) { + renderMessage (type, data) { return new Promise((resolve) => { this.nunjucksEnvironment().render(this.getTemplate(type), data, function (err, res) { if (err) { @@ -137,7 +137,7 @@ Module.register("alert", { }); }, - toggleBlur(add = false) { + toggleBlur (add = false) { const method = add ? "add" : "remove"; const modules = document.querySelectorAll(".module"); for (const module of modules) { diff --git a/modules/default/alert/notificationFx.js b/modules/default/alert/notificationFx.js index 5a7426e981..fcf7f3456b 100644 --- a/modules/default/alert/notificationFx.js +++ b/modules/default/alert/notificationFx.js @@ -12,13 +12,14 @@ * @param {object} window The window object */ (function (window) { + /** * Extend one object with another one * @param {object} a The object to extend * @param {object} b The object which extends the other, overwrites existing keys * @returns {object} The merged object */ - function extend(a, b) { + function extend (a, b) { for (let key in b) { if (b.hasOwnProperty(key)) { a[key] = b[key]; @@ -32,7 +33,7 @@ * @param {object} options The configuration options * @class */ - function NotificationFx(options) { + function NotificationFx (options) { this.options = extend({}, this.options); extend(this.options, options); this._init(); @@ -63,10 +64,10 @@ ttl: 6000, al_no: "ns-box", // callbacks - onClose: function () { + onClose () { return false; }, - onOpen: function () { + onOpen () { return false; } }; @@ -78,7 +79,7 @@ // create HTML structure this.ntf = document.createElement("div"); this.ntf.className = `${this.options.al_no} ns-${this.options.layout} ns-effect-${this.options.effect} ns-type-${this.options.type}`; - let strinner = '
'; + let strinner = "
"; strinner += this.options.message; strinner += "
"; this.ntf.innerHTML = strinner; @@ -153,4 +154,4 @@ * Add to global namespace */ window.NotificationFx = NotificationFx; -})(window); +}(window)); diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index 681177d514..bfb49af78e 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -1,4 +1,4 @@ -/* global CalendarUtils, cloneObject */ +/* global CalendarUtils */ /* MagicMirror² * Module: Calendar @@ -28,6 +28,7 @@ Module.register("calendar", { fetchInterval: 60 * 60 * 1000, // Update every hour animationSpeed: 2000, fade: true, + fadePoint: 0.25, // Start on 1/4th of the list. urgency: 7, timeFormat: "relative", dateFormat: "MMM Do", @@ -35,14 +36,12 @@ Module.register("calendar", { fullDayEventDateFormat: "MMM Do", showEnd: false, getRelative: 6, - fadePoint: 0.25, // Start on 1/4th of the list. hidePrivate: false, hideOngoing: false, hideTime: false, hideDuplicates: true, showTimeToday: false, colored: false, - customEvents: [], // Array of {keyword: "", symbol: "", color: "", eventClass: ""} where Keyword is a regexp and symbol/color/eventClass are to be applied for matched tableClass: "small", calendars: [ { @@ -50,10 +49,11 @@ Module.register("calendar", { url: "https://www.calendarlabs.com/templates/ical/US-Holidays.ics" } ], - titleReplace: { - "De verjaardag van ": "", - "'s birthday": "" - }, + customEvents: [ + // Array of {keyword: "", symbol: "", color: "", eventClass: ""} where Keyword is a regexp and symbol/color/eventClass are to be applied for matched + { keyword: ".*", transform: { search: "De verjaardag van ", replace: "" } }, + { keyword: ".*", transform: { search: "'s birthday", replace: "" } } + ], locationTitleReplace: { "street ": "" }, @@ -68,23 +68,24 @@ Module.register("calendar", { coloredSymbol: false, coloredBackground: false, limitDaysNeverSkip: false, - flipDateHeaderTitle: false + flipDateHeaderTitle: false, + updateOnFetch: true }, requiresVersion: "2.1.0", // Define required scripts. - getStyles: function () { + getStyles () { return ["calendar.css", "font-awesome.css"]; }, // Define required scripts. - getScripts: function () { + getScripts () { return ["calendarutils.js", "moment.js"]; }, // Define required translations. - getTranslations: function () { + getTranslations () { // The translations for the default modules are defined in the core translation files. // Therefore we can just return false. Otherwise we should have returned a dictionary. // If you're trying to build your own module including translations, check out the documentation. @@ -92,9 +93,7 @@ Module.register("calendar", { }, // Override start method. - start: function () { - const ONE_MINUTE = 60 * 1000; - + start () { Log.info(`Starting module: ${this.name}`); if (this.config.colored) { @@ -117,6 +116,9 @@ Module.register("calendar", { // indicate no data available yet this.loaded = false; + // data holder of calendar url. Avoid fade out/in on updateDom (one for each calendar update) + this.calendarDisplayer = {}; + this.config.calendars.forEach((calendar) => { calendar.url = calendar.url.replace("webcal://", "http://"); @@ -125,23 +127,25 @@ Module.register("calendar", { maximumNumberOfDays: calendar.maximumNumberOfDays, pastDaysCount: calendar.pastDaysCount, broadcastPastEvents: calendar.broadcastPastEvents, - selfSignedCert: calendar.selfSignedCert + selfSignedCert: calendar.selfSignedCert, + excludedEvents: calendar.excludedEvents, + fetchInterval: calendar.fetchInterval }; - if (calendar.symbolClass === "undefined" || calendar.symbolClass === null) { + if (typeof calendar.symbolClass === "undefined" || calendar.symbolClass === null) { calendarConfig.symbolClass = ""; } - if (calendar.titleClass === "undefined" || calendar.titleClass === null) { + if (typeof calendar.titleClass === "undefined" || calendar.titleClass === null) { calendarConfig.titleClass = ""; } - if (calendar.timeClass === "undefined" || calendar.timeClass === null) { + if (typeof calendar.timeClass === "undefined" || calendar.timeClass === null) { calendarConfig.timeClass = ""; } // we check user and password here for backwards compatibility with old configs if (calendar.user && calendar.pass) { Log.warn("Deprecation warning: Please update your calendar authentication configuration."); - Log.warn("https://github.com/MichMich/MagicMirror/tree/v2.1.2/modules/default/calendar#calendar-authentication-options"); + Log.warn("https://docs.magicmirror.builders/modules/calendar.html#configuration-options"); calendar.auth = { user: calendar.user, pass: calendar.pass @@ -153,20 +157,19 @@ Module.register("calendar", { this.addCalendar(calendar.url, calendar.auth, calendarConfig); }); - // Refresh the DOM every minute if needed: When using relative date format for events that start - // or end in less than an hour, the date shows minute granularity and we want to keep that accurate. - setTimeout( - () => { - setInterval(() => { - this.updateDom(1); - }, ONE_MINUTE); - }, - ONE_MINUTE - (new Date() % ONE_MINUTE) - ); + // for backward compatibility titleReplace + if (typeof this.config.titleReplace !== "undefined") { + Log.warn("Deprecation warning: Please consider upgrading your calendar titleReplace configuration to customEvents."); + for (const [titlesearchstr, titlereplacestr] of Object.entries(this.config.titleReplace)) { + this.config.customEvents.push({ keyword: ".*", transform: { search: titlesearchstr, replace: titlereplacestr } }); + } + } + + this.selfUpdate(); }, // Override socket notification handler. - socketNotificationReceived: function (notification, payload) { + socketNotificationReceived (notification, payload) { if (notification === "FETCH_CALENDAR") { this.sendSocketNotification(notification, { url: payload.url, id: this.identifier }); } @@ -184,6 +187,18 @@ Module.register("calendar", { if (this.config.broadcastEvents) { this.broadcastEvents(); } + + if (!this.config.updateOnFetch) { + if (this.calendarDisplayer[payload.url] === undefined) { + // calendar will never displayed, so display it + this.updateDom(this.config.animationSpeed); + // set this calendar as displayed + this.calendarDisplayer[payload.url] = true; + } else { + Log.debug("[Calendar] DOM not updated waiting self update()"); + } + return; + } } } else if (notification === "CALENDAR_ERROR") { let error_message = this.translate(payload.error_type); @@ -195,7 +210,7 @@ Module.register("calendar", { }, // Override dom generator. - getDom: function () { + getDom () { const ONE_SECOND = 1000; // 1,000 milliseconds const ONE_MINUTE = ONE_SECOND * 60; const ONE_HOUR = ONE_MINUTE * 60; @@ -321,11 +336,16 @@ Module.register("calendar", { } } - // Color events if custom color or eventClass are specified + var transformedTitle = event.title; + + // Color events if custom color or eventClass are specified, transform title if required if (this.config.customEvents.length > 0) { for (let ev in this.config.customEvents) { let needle = new RegExp(this.config.customEvents[ev].keyword, "gi"); if (needle.test(event.title)) { + if (typeof this.config.customEvents[ev].transform === "object") { + transformedTitle = CalendarUtils.titleTransform(transformedTitle, [this.config.customEvents[ev].transform]); + } if (typeof this.config.customEvents[ev].color !== "undefined" && this.config.customEvents[ev].color !== "") { // Respect parameter ColoredSymbolOnly also for custom events if (this.config.coloredText) { @@ -335,7 +355,6 @@ Module.register("calendar", { if (this.config.displaySymbol && this.config.coloredSymbol) { symbolWrapper.style.cssText = `color:${this.config.customEvents[ev].color}`; } - break; } if (typeof this.config.customEvents[ev].eventClass !== "undefined" && this.config.customEvents[ev].eventClass !== "") { eventWrapper.className += ` ${this.config.customEvents[ev].eventClass}`; @@ -344,7 +363,6 @@ Module.register("calendar", { } } - const transformedTitle = CalendarUtils.titleTransform(event.title, this.config.titleReplace); titleWrapper.innerHTML = CalendarUtils.shorten(transformedTitle, this.config.maxTitleLength, this.config.wrapEvents, this.config.maxTitleLines) + repeatingCountTitle; const titleClass = this.titleClassForUrl(event.url); @@ -534,7 +552,7 @@ Module.register("calendar", { * @param {string} url The calendar url * @returns {boolean} True if the calendar config contains the url, False otherwise */ - hasCalendarURL: function (url) { + hasCalendarURL (url) { for (const calendar of this.config.calendars) { if (calendar.url === url) { return true; @@ -549,7 +567,7 @@ Module.register("calendar", { * @param {boolean} limitNumberOfEntries Whether to filter returned events for display. * @returns {object[]} Array with events. */ - createEventList: function (limitNumberOfEntries) { + createEventList (limitNumberOfEntries) { const ONE_SECOND = 1000; // 1,000 milliseconds const ONE_MINUTE = ONE_SECOND * 60; const ONE_HOUR = ONE_MINUTE * 60; @@ -599,7 +617,12 @@ Module.register("calendar", { const maxCount = Math.ceil((event.endDate - 1 - moment(event.startDate, "x").endOf("day").format("x")) / ONE_DAY) + 1; if (this.config.sliceMultiDayEvents && maxCount > 1) { const splitEvents = []; - let midnight = moment(event.startDate, "x").clone().startOf("day").add(1, "day").format("x"); + let midnight + = moment(event.startDate, "x") + .clone() + .startOf("day") + .add(1, "day") + .format("x"); let count = 1; while (event.endDate > midnight) { const thisEvent = JSON.parse(JSON.stringify(event)); // clone object @@ -668,7 +691,7 @@ Module.register("calendar", { return events.slice(0, this.config.maximumEntries); }, - listContainsEvent: function (eventList, event) { + listContainsEvent (eventList, event) { for (const evt of eventList) { if (evt.title === event.title && parseInt(evt.startDate) === parseInt(event.startDate) && parseInt(evt.endDate) === parseInt(event.endDate)) { return true; @@ -683,7 +706,7 @@ Module.register("calendar", { * @param {object} auth The authentication method and credentials * @param {object} calendarConfig The config of the specific calendar */ - addCalendar: function (url, auth, calendarConfig) { + addCalendar (url, auth, calendarConfig) { this.sendSocketNotification("ADD_CALENDAR", { id: this.identifier, url: url, @@ -706,7 +729,7 @@ Module.register("calendar", { * @param {object} event Event to look for. * @returns {string[]} The symbols */ - symbolsForEvent: function (event) { + symbolsForEvent (event) { let symbols = this.getCalendarPropertyAsArray(event.url, "symbol", this.config.defaultSymbol); if (event.recurringEvent === true && this.hasCalendarProperty(event.url, "recurringSymbol")) { @@ -733,7 +756,7 @@ Module.register("calendar", { return symbols; }, - mergeUnique: function (arr1, arr2) { + mergeUnique (arr1, arr2) { return arr1.concat( arr2.filter(function (item) { return arr1.indexOf(item) === -1; @@ -746,7 +769,7 @@ Module.register("calendar", { * @param {string} url The calendar url * @returns {string} The class to be used for the symbols of the calendar */ - symbolClassForUrl: function (url) { + symbolClassForUrl (url) { return this.getCalendarProperty(url, "symbolClass", ""); }, @@ -755,7 +778,7 @@ Module.register("calendar", { * @param {string} url The calendar url * @returns {string} The class to be used for the title of the calendar */ - titleClassForUrl: function (url) { + titleClassForUrl (url) { return this.getCalendarProperty(url, "titleClass", ""); }, @@ -764,7 +787,7 @@ Module.register("calendar", { * @param {string} url The calendar url * @returns {string} The class to be used for the time of the calendar */ - timeClassForUrl: function (url) { + timeClassForUrl (url) { return this.getCalendarProperty(url, "timeClass", ""); }, @@ -773,7 +796,7 @@ Module.register("calendar", { * @param {string} url The calendar url * @returns {string} The name of the calendar */ - calendarNameForUrl: function (url) { + calendarNameForUrl (url) { return this.getCalendarProperty(url, "name", ""); }, @@ -783,7 +806,7 @@ Module.register("calendar", { * @param {boolean} isBg Determines if we fetch the bgColor or not * @returns {string} The color */ - colorForUrl: function (url, isBg) { + colorForUrl (url, isBg) { return this.getCalendarProperty(url, isBg ? "bgColor" : "color", "#fff"); }, @@ -792,7 +815,7 @@ Module.register("calendar", { * @param {string} url The calendar url * @returns {string} The title */ - countTitleForUrl: function (url) { + countTitleForUrl (url) { return this.getCalendarProperty(url, "repeatingCountTitle", this.config.defaultRepeatingCountTitle); }, @@ -801,7 +824,7 @@ Module.register("calendar", { * @param {string} url The calendar url * @returns {number} The maximum entry count */ - maximumEntriesForUrl: function (url) { + maximumEntriesForUrl (url) { return this.getCalendarProperty(url, "maximumEntries", this.config.maximumEntries); }, @@ -810,7 +833,7 @@ Module.register("calendar", { * @param {string} url The calendar url * @returns {number} The maximum past days count */ - maximumPastDaysForUrl: function (url) { + maximumPastDaysForUrl (url) { return this.getCalendarProperty(url, "pastDaysCount", this.config.pastDaysCount); }, @@ -821,7 +844,7 @@ Module.register("calendar", { * @param {string} defaultValue The value if the property is not found * @returns {*} The property */ - getCalendarProperty: function (url, property, defaultValue) { + getCalendarProperty (url, property, defaultValue) { for (const calendar of this.config.calendars) { if (calendar.url === url && calendar.hasOwnProperty(property)) { return calendar[property]; @@ -831,7 +854,7 @@ Module.register("calendar", { return defaultValue; }, - getCalendarPropertyAsArray: function (url, property, defaultValue) { + getCalendarPropertyAsArray (url, property, defaultValue) { let p = this.getCalendarProperty(url, property, defaultValue); if (property === "symbol" || property === "recurringSymbol" || property === "fullDaySymbol") { const className = this.getCalendarProperty(url, "symbolClassName", this.config.defaultSymbolClassName); @@ -842,7 +865,7 @@ Module.register("calendar", { return p; }, - hasCalendarProperty: function (url, property) { + hasCalendarProperty (url, property) { return !!this.getCalendarProperty(url, property, undefined); }, @@ -850,7 +873,7 @@ Module.register("calendar", { * Broadcasts the events to all other modules for reuse. * The all events available in one array, sorted on startdate. */ - broadcastEvents: function () { + broadcastEvents () { const eventList = this.createEventList(false); for (const event of eventList) { event.symbol = this.symbolsForEvent(event); @@ -860,5 +883,30 @@ Module.register("calendar", { } this.sendNotification("CALENDAR_EVENTS", eventList); + }, + + /** + * Refresh the DOM every minute if needed: When using relative date format for events that start + * or end in less than an hour, the date shows minute granularity and we want to keep that accurate. + * -- + * When updateOnFetch is not set, it will Avoid fade out/in on updateDom when many calendars are used + * and it's allow to refresh The DOM every minute with animation speed too + * (because updateDom is not set in CALENDAR_EVENTS for this case) + */ + selfUpdate () { + const ONE_MINUTE = 60 * 1000; + setTimeout( + () => { + setInterval(() => { + Log.debug("[Calendar] self update"); + if (this.config.updateOnFetch) { + this.updateDom(1); + } else { + this.updateDom(this.config.animationSpeed); + } + }, ONE_MINUTE); + }, + ONE_MINUTE - (new Date() % ONE_MINUTE) + ); } }); diff --git a/modules/default/calendar/calendarfetcherutils.js b/modules/default/calendar/calendarfetcherutils.js index 34cc2578c6..af48b7e795 100644 --- a/modules/default/calendar/calendarfetcherutils.js +++ b/modules/default/calendar/calendarfetcherutils.js @@ -10,10 +10,12 @@ */ const path = require("path"); const moment = require("moment"); + const zoneTable = require(path.join(__dirname, "windowsZones.json")); const Log = require("../../../js/logger"); const CalendarFetcherUtils = { + /** * Calculate the time correction, either dst/std or full day in cases where * utc time is day before plus offset @@ -21,7 +23,7 @@ const CalendarFetcherUtils = { * @param {Date} date the date on which this event happens * @returns {number} the necessary adjustment in hours */ - calculateTimezoneAdjustment: function (event, date) { + calculateTimezoneAdjustment (event, date) { let adjustHours = 0; // if a timezone was specified if (!event.start.tz) { @@ -122,7 +124,7 @@ const CalendarFetcherUtils = { * @param {object} config The configuration object * @returns {string[]} the filtered events */ - filterEvents: function (data, config) { + filterEvents (data, config) { const newEvents = []; // limitFunction doesn't do much limiting, see comment re: the dates @@ -141,7 +143,12 @@ const CalendarFetcherUtils = { Log.debug("Processing entry..."); const now = new Date(); const today = moment().startOf("day").toDate(); - const future = moment().startOf("day").add(config.maximumNumberOfDays, "days").subtract(1, "seconds").toDate(); // Subtract 1 second so that events that start on the middle of the night will not repeat. + const future + = moment() + .startOf("day") + .add(config.maximumNumberOfDays, "days") + .subtract(1, "seconds") // Subtract 1 second so that events that start on the middle of the night will not repeat. + .toDate(); let past = today; if (config.includePastEvents) { @@ -247,7 +254,6 @@ const CalendarFetcherUtils = { if (typeof event.rrule !== "undefined" && event.rrule !== null && !isFacebookBirthday) { const rule = event.rrule; - let addedEvents = 0; const pastMoment = moment(past); const futureMoment = moment(future); @@ -283,8 +289,12 @@ const CalendarFetcherUtils = { futureLocal = futureMoment.toDate(); // future } Log.debug(`Search for recurring events between: ${pastLocal} and ${futureLocal}`); - const dates = rule.between(pastLocal, futureLocal, true, limitFunction); + let dates = rule.between(pastLocal, futureLocal, true, limitFunction); Log.debug(`Title: ${event.summary}, with dates: ${JSON.stringify(dates)}`); + dates = dates.filter((d) => { + if (JSON.stringify(d) === "null") return false; + else return true; + }); // The "dates" array contains the set of dates within our desired date range range that are valid // for the recurrence rule. *However*, it's possible for us to have a specific recurrence that // had its date changed from outside the range to inside the range. For the time being, @@ -305,11 +315,6 @@ const CalendarFetcherUtils = { // Loop through the set of date entries to see which recurrences should be added to our event list. for (let d in dates) { let date = dates[d]; - // Remove the time information of each date by using its substring, using the following method: - // .toISOString().substring(0,10). - // since the date is given as ISOString with YYYY-MM-DDTHH:MM:SS.SSSZ - // (see https://momentjs.com/docs/#/displaying/as-iso-string/). - const dateKey = date.toISOString().substring(0, 10); let curEvent = event; let showRecurrence = true; @@ -402,6 +407,13 @@ const CalendarFetcherUtils = { let adjustDays = CalendarFetcherUtils.calculateTimezoneAdjustment(event, date); + // Remove the time information of each date by using its substring, using the following method: + // .toISOString().substring(0,10). + // since the date is given as ISOString with YYYY-MM-DDTHH:MM:SS.SSSZ + // (see https://momentjs.com/docs/#/displaying/as-iso-string/). + // This must be done after `date` is adjusted + const dateKey = date.toISOString().substring(0, 10); + // For each date that we're checking, it's possible that there is a recurrence override for that one day. if (curEvent.recurrences !== undefined && curEvent.recurrences[dateKey] !== undefined) { // We found an override, so for this recurrence, use a potentially different title, start date, and duration. @@ -435,7 +447,6 @@ const CalendarFetcherUtils = { if (showRecurrence === true) { Log.debug(`saving event: ${description}`); - addedEvents++; newEvents.push({ title: recurrenceTitle, startDate: (adjustDays ? (adjustDays > 0 ? startDate.add(adjustDays, "hours") : startDate.subtract(Math.abs(adjustDays), "hours")) : startDate).format("x"), @@ -516,7 +527,7 @@ const CalendarFetcherUtils = { * @param {string} msTZName the timezone name to lookup * @returns {string|null} the iana name or null of none is found */ - getIanaTZFromMS: function (msTZName) { + getIanaTZFromMS (msTZName) { // Get hash entry const he = zoneTable[msTZName]; // If found return iana name, else null @@ -528,7 +539,7 @@ const CalendarFetcherUtils = { * @param {object} event The event object to check. * @returns {string} The title of the event, or "Event" if no title is found. */ - getTitleFromEvent: function (event) { + getTitleFromEvent (event) { let title = "Event"; if (event.summary) { title = typeof event.summary.val !== "undefined" ? event.summary.val : event.summary; @@ -544,7 +555,7 @@ const CalendarFetcherUtils = { * @param {object} event The event object to check. * @returns {boolean} True if the event is a fullday event, false otherwise */ - isFullDayEvent: function (event) { + isFullDayEvent (event) { if (event.start.length === 8 || event.start.dateOnly || event.datetype === "date") { return true; } @@ -567,7 +578,7 @@ const CalendarFetcherUtils = { * @param {string} filter The time to subtract from the end date to determine if an event should be shown * @returns {boolean} True if the event should be filtered out, false otherwise */ - timeFilterApplies: function (now, endDate, filter) { + timeFilterApplies (now, endDate, filter) { if (filter) { const until = filter.split(" "), value = parseInt(until[0]), @@ -588,7 +599,7 @@ const CalendarFetcherUtils = { * @param {string} regexFlags flags that should be applied to the regex * @returns {boolean} True if the title should be filtered out, false otherwise */ - titleFilterApplies: function (title, filter, useRegex, regexFlags) { + titleFilterApplies (title, filter, useRegex, regexFlags) { if (useRegex) { let regexFilter = filter; // Assume if leading slash, there is also trailing slash diff --git a/modules/default/calendar/calendarutils.js b/modules/default/calendar/calendarutils.js index e953b6352c..68aef52154 100644 --- a/modules/default/calendar/calendarutils.js +++ b/modules/default/calendar/calendarutils.js @@ -5,12 +5,13 @@ * MIT Licensed. */ const CalendarUtils = { + /** * Capitalize the first letter of a string * @param {string} string The string to capitalize * @returns {string} The capitalized string */ - capFirst: function (string) { + capFirst (string) { return string.charAt(0).toUpperCase() + string.slice(1); }, @@ -21,7 +22,7 @@ const CalendarUtils = { * @param {number} timeFormat Specifies either 12 or 24-hour time format * @returns {moment.LocaleSpecification} formatted time */ - getLocaleSpecification: function (timeFormat) { + getLocaleSpecification (timeFormat) { switch (timeFormat) { case 12: { return { longDateFormat: { LT: "h:mm A" } }; @@ -43,7 +44,7 @@ const CalendarUtils = { * @param {number} maxTitleLines The max number of vertical lines before cutting event title * @returns {string} The shortened string */ - shorten: function (string, maxLength, wrapEvents, maxTitleLines) { + shorten (string, maxLength, wrapEvents, maxTitleLines) { if (typeof string !== "string") { return ""; } @@ -90,23 +91,39 @@ const CalendarUtils = { /** * Transforms the title of an event for usage. * Replaces parts of the text as defined in config.titleReplace. - * Shortens title based on config.maxTitleLength and config.wrapEvents * @param {string} title The title to transform. - * @param {object} titleReplace Pairs of strings to be replaced in the title + * @param {object} titleReplace object definition of parts to be replaced in the title + * object definition: + * search: {string,required} RegEx in format //x or simple string to be searched. For (birthday) year calcluation, the element matching the year must be in a RegEx group + * replace: {string,required} Replacement string, may contain match group references (latter is required for year calculation) + * yearmatchgroup: {number,optional} match group for year element * @returns {string} The transformed title. */ - titleTransform: function (title, titleReplace) { + titleTransform (title, titleReplace) { let transformedTitle = title; - for (let needle in titleReplace) { - const replacement = titleReplace[needle]; + for (let tr in titleReplace) { + let transform = titleReplace[tr]; + if (typeof transform === "object") { + if (typeof transform.search !== "undefined" && transform.search !== "" && typeof transform.replace !== "undefined") { + let regParts = transform.search.match(/^\/(.+)\/([gim]*)$/); + let needle = new RegExp(transform.search, "g"); + if (regParts) { + // the parsed pattern is a regexp with flags. + needle = new RegExp(regParts[1], regParts[2]); + } - const regParts = needle.match(/^\/(.+)\/([gim]*)$/); - if (regParts) { - // the parsed pattern is a regexp. - needle = new RegExp(regParts[1], regParts[2]); + let replacement = transform.replace; + if (typeof transform.yearmatchgroup !== "undefined" && transform.yearmatchgroup !== "") { + const yearmatch = [...title.matchAll(needle)]; + if (yearmatch[0].length >= transform.yearmatchgroup + 1 && yearmatch[0][transform.yearmatchgroup] * 1 >= 1900) { + let calcage = new Date().getFullYear() - yearmatch[0][transform.yearmatchgroup] * 1; + let searchstr = `$${transform.yearmatchgroup}`; + replacement = replacement.replace(searchstr, calcage); + } + } + transformedTitle = transformedTitle.replace(needle, replacement); + } } - - transformedTitle = transformedTitle.replace(needle, replacement); } return transformedTitle; } diff --git a/modules/default/calendar/node_helper.js b/modules/default/calendar/node_helper.js index 05d4d4577f..c0d46ae468 100644 --- a/modules/default/calendar/node_helper.js +++ b/modules/default/calendar/node_helper.js @@ -10,13 +10,13 @@ const CalendarFetcher = require("./calendarfetcher"); module.exports = NodeHelper.create({ // Override start method. - start: function () { + start () { Log.log(`Starting node helper for: ${this.name}`); this.fetchers = []; }, // Override socketNotificationReceived method. - socketNotificationReceived: function (notification, payload) { + socketNotificationReceived (notification, payload) { if (notification === "ADD_CALENDAR") { this.createFetcher(payload.url, payload.fetchInterval, payload.excludedEvents, payload.maximumEntries, payload.maximumNumberOfDays, payload.auth, payload.broadcastPastEvents, payload.selfSignedCert, payload.id); } else if (notification === "FETCH_CALENDAR") { @@ -43,7 +43,7 @@ module.exports = NodeHelper.create({ * @param {boolean} selfSignedCert If true, the server certificate is not verified against the list of supplied CAs. * @param {string} identifier ID of the module */ - createFetcher: function (url, fetchInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, broadcastPastEvents, selfSignedCert, identifier) { + createFetcher (url, fetchInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, broadcastPastEvents, selfSignedCert, identifier) { try { new URL(url); } catch (error) { @@ -85,7 +85,7 @@ module.exports = NodeHelper.create({ * @param {object} fetcher the fetcher associated with the calendar * @param {string} identifier the identifier of the calendar */ - broadcastEvents: function (fetcher, identifier) { + broadcastEvents (fetcher, identifier) { this.sendSocketNotification("CALENDAR_EVENTS", { id: identifier, url: fetcher.url(), diff --git a/modules/default/clock/clock.js b/modules/default/clock/clock.js index c063d4dc88..6b4ae32412 100644 --- a/modules/default/clock/clock.js +++ b/modules/default/clock/clock.js @@ -32,20 +32,20 @@ Module.register("clock", { secondsColor: "#888888", showSunTimes: false, - showMoonTimes: false, + showMoonTimes: false, // options: false, 'times' (rise/set), 'percent' (lit percent), 'phase' (current phase), or 'both' (percent & phase) lat: 47.630539, lon: -122.344147 }, // Define required scripts. - getScripts: function () { + getScripts () { return ["moment.js", "moment-timezone.js", "suncalc.js"]; }, // Define styles. - getStyles: function () { + getStyles () { return ["clock_styles.css"]; }, // Define start sequence. - start: function () { + start () { Log.info(`Starting module: ${this.name}`); // Schedule update interval. @@ -94,7 +94,7 @@ Module.register("clock", { moment.locale(config.language); }, // Override dom generator. - getDom: function () { + getDom () { const wrapper = document.createElement("div"); wrapper.classList.add("clock-grid"); @@ -186,10 +186,10 @@ Module.register("clock", { } const untilNextEvent = moment.duration(moment(nextEvent).diff(now)); const untilNextEventString = `${untilNextEvent.hours()}h ${untilNextEvent.minutes()}m`; - sunWrapper.innerHTML = - ` ${untilNextEventString}` + - ` ${formatTime(this.config, sunTimes.sunrise)}` + - ` ${formatTime(this.config, sunTimes.sunset)}`; + sunWrapper.innerHTML + = ` ${untilNextEventString}` + + ` ${formatTime(this.config, sunTimes.sunrise)}` + + ` ${formatTime(this.config, sunTimes.sunset)}`; digitalWrapper.appendChild(sunWrapper); } @@ -208,11 +208,15 @@ Module.register("clock", { moonSet = nextMoonTimes.set; } const isVisible = now.isBetween(moonRise, moonSet) || moonTimes.alwaysUp === true; + const showFraction = ["both", "percent"].includes(this.config.showMoonTimes); + const showUnicode = ["both", "phase"].includes(this.config.showMoonTimes); const illuminatedFractionString = `${Math.round(moonIllumination.fraction * 100)}%`; - moonWrapper.innerHTML = - ` ${illuminatedFractionString}` + - ` ${moonRise ? formatTime(this.config, moonRise) : "..."}` + - ` ${moonSet ? formatTime(this.config, moonSet) : "..."}`; + const image = showUnicode ? [..."🌑🌒🌓🌔🌕🌖🌗🌘"][Math.floor(moonIllumination.phase * 8)] : ""; + + moonWrapper.innerHTML + = `${image} ${showFraction ? illuminatedFractionString : ""}` + + ` ${moonRise ? formatTime(this.config, moonRise) : "..."}` + + ` ${moonSet ? formatTime(this.config, moonSet) : "..."}`; digitalWrapper.appendChild(moonWrapper); } diff --git a/modules/default/compliments/compliments.js b/modules/default/compliments/compliments.js index a905581bd0..374cd54f76 100644 --- a/modules/default/compliments/compliments.js +++ b/modules/default/compliments/compliments.js @@ -28,12 +28,12 @@ Module.register("compliments", { currentWeatherType: "", // Define required scripts. - getScripts: function () { + getScripts () { return ["moment.js"]; }, // Define start sequence. - start: async function () { + async start () { Log.info(`Starting module: ${this.name}`); this.lastComplimentIndex = -1; @@ -55,7 +55,7 @@ Module.register("compliments", { * @param {string[]} compliments Array with compliments. * @returns {number} a random index of given array */ - randomIndex: function (compliments) { + randomIndex (compliments) { if (compliments.length === 1) { return 0; } @@ -79,7 +79,7 @@ Module.register("compliments", { * Retrieve an array of compliments for the time of the day. * @returns {string[]} array with compliments for the time of the day. */ - complimentArray: function () { + complimentArray () { const hour = moment().hour(); const date = moment().format("YYYY-MM-DD"); let compliments = []; @@ -115,7 +115,7 @@ Module.register("compliments", { * Retrieve a file from the local filesystem * @returns {Promise} Resolved when the file is loaded */ - loadComplimentFile: async function () { + async loadComplimentFile () { const isRemote = this.config.remoteFile.indexOf("http://") === 0 || this.config.remoteFile.indexOf("https://") === 0, url = isRemote ? this.config.remoteFile : this.file(this.config.remoteFile); const response = await fetch(url); @@ -126,7 +126,7 @@ Module.register("compliments", { * Retrieve a random compliment. * @returns {string} a compliment */ - getRandomCompliment: function () { + getRandomCompliment () { // get the current time of day compliments list const compliments = this.complimentArray(); // variable for index to next message to display @@ -145,7 +145,7 @@ Module.register("compliments", { }, // Override dom generator. - getDom: function () { + getDom () { const wrapper = document.createElement("div"); wrapper.className = this.config.classes ? this.config.classes : "thin xlarge bright pre-line"; // get the compliment text @@ -173,7 +173,7 @@ Module.register("compliments", { }, // Override notification handler. - notificationReceived: function (notification, payload, sender) { + notificationReceived (notification, payload, sender) { if (notification === "CURRENTWEATHER_TYPE") { this.currentWeatherType = payload.type; } diff --git a/modules/default/helloworld/helloworld.js b/modules/default/helloworld/helloworld.js index 53357d0fd2..6adb382e07 100644 --- a/modules/default/helloworld/helloworld.js +++ b/modules/default/helloworld/helloworld.js @@ -10,11 +10,11 @@ Module.register("helloworld", { text: "Hello World!" }, - getTemplate: function () { + getTemplate () { return "helloworld.njk"; }, - getTemplateData: function () { + getTemplateData () { return this.config; } }); diff --git a/modules/default/newsfeed/newsfeed.js b/modules/default/newsfeed/newsfeed.js index eee0b44a7b..27114d8e31 100644 --- a/modules/default/newsfeed/newsfeed.js +++ b/modules/default/newsfeed/newsfeed.js @@ -42,7 +42,7 @@ Module.register("newsfeed", { dangerouslyDisableAutoEscaping: false }, - getUrlPrefix: function (item) { + getUrlPrefix (item) { if (item.useCorsProxy) { return `${location.protocol}//${location.host}/cors?url=`; } else { @@ -51,17 +51,17 @@ Module.register("newsfeed", { }, // Define required scripts. - getScripts: function () { + getScripts () { return ["moment.js"]; }, //Define required styles. - getStyles: function () { + getStyles () { return ["newsfeed.css"]; }, // Define required translations. - getTranslations: function () { + getTranslations () { // The translations for the default modules are defined in the core translation files. // Therefor we can just return false. Otherwise we should have returned a dictionary. // If you're trying to build your own module including translations, check out the documentation. @@ -69,7 +69,7 @@ Module.register("newsfeed", { }, // Define start sequence. - start: function () { + start () { Log.info(`Starting module: ${this.name}`); // Set locale. @@ -87,7 +87,7 @@ Module.register("newsfeed", { }, // Override socket notification handler. - socketNotificationReceived: function (notification, payload) { + socketNotificationReceived (notification, payload) { if (notification === "NEWS_ITEMS") { this.generateFeed(payload); @@ -107,7 +107,7 @@ Module.register("newsfeed", { }, //Override fetching of template name - getTemplate: function () { + getTemplate () { if (this.config.feedUrl) { return "oldconfig.njk"; } else if (this.config.showFullArticle) { @@ -117,7 +117,7 @@ Module.register("newsfeed", { }, //Override template data and return whats used for the current template - getTemplateData: function () { + getTemplateData () { // this.config.showFullArticle is a run-time configuration, triggered by optional notifications if (this.config.showFullArticle) { return { @@ -156,7 +156,7 @@ Module.register("newsfeed", { }; }, - getActiveItemURL: function () { + getActiveItemURL () { const item = this.newsItems[this.activeItem]; if (item) { return typeof item.url === "string" ? this.getUrlPrefix(item) + item.url : this.getUrlPrefix(item) + item.url.href; @@ -168,7 +168,7 @@ Module.register("newsfeed", { /** * Registers the feeds to be used by the backend. */ - registerFeeds: function () { + registerFeeds () { for (let feed of this.config.feeds) { this.sendSocketNotification("ADD_FEED", { feed: feed, @@ -181,7 +181,7 @@ Module.register("newsfeed", { * Generate an ordered list of items for this configured module. * @param {object} feeds An object with feeds returned by the node helper. */ - generateFeed: function (feeds) { + generateFeed (feeds) { let newsItems = []; for (let feed in feeds) { const feedItems = feeds[feed]; @@ -274,7 +274,7 @@ Module.register("newsfeed", { * @param {string} feedUrl Url of the feed to check. * @returns {boolean} True if it is subscribed, false otherwise */ - subscribedToFeed: function (feedUrl) { + subscribedToFeed (feedUrl) { for (let feed of this.config.feeds) { if (feed.url === feedUrl) { return true; @@ -288,7 +288,7 @@ Module.register("newsfeed", { * @param {string} feedUrl Url of the feed * @returns {string} The title of the feed */ - titleForFeed: function (feedUrl) { + titleForFeed (feedUrl) { for (let feed of this.config.feeds) { if (feed.url === feedUrl) { return feed.title || ""; @@ -300,7 +300,7 @@ Module.register("newsfeed", { /** * Schedule visual update. */ - scheduleUpdateInterval: function () { + scheduleUpdateInterval () { this.updateDom(this.config.animationSpeed); // Broadcast NewsFeed if needed @@ -322,7 +322,7 @@ Module.register("newsfeed", { }, this.config.updateInterval); }, - resetDescrOrFullArticleAndTimer: function () { + resetDescrOrFullArticleAndTimer () { this.isShowingDescription = this.config.showDescription; this.config.showFullArticle = false; this.scrollPosition = 0; @@ -333,7 +333,7 @@ Module.register("newsfeed", { } }, - notificationReceived: function (notification, payload, sender) { + notificationReceived (notification, payload, sender) { const before = this.activeItem; if (notification === "MODULE_DOM_CREATED" && this.config.hideLoading) { this.hide(); @@ -394,7 +394,7 @@ Module.register("newsfeed", { } }, - showFullArticle: function () { + showFullArticle () { this.isShowingDescription = !this.isShowingDescription; this.config.showFullArticle = !this.isShowingDescription; // make bottom bar align to top to allow scrolling diff --git a/modules/default/newsfeed/newsfeedfetcher.js b/modules/default/newsfeed/newsfeedfetcher.js index a0d871fac5..0c52e347ce 100644 --- a/modules/default/newsfeed/newsfeedfetcher.js +++ b/modules/default/newsfeed/newsfeedfetcher.js @@ -48,14 +48,19 @@ const NewsfeedFetcher = function (url, reloadInterval, encoding, logFeedWarnings parser.on("item", (item) => { const title = item.title; let description = item.description || item.summary || item.content || ""; - const pubdate = item.pubdate || item.published || item.updated || item["dc:date"]; + const pubdate = item.pubdate || item.published || item.updated || item["dc:date"] || item["a10:updated"]; const url = item.url || item.link || ""; if (title && pubdate) { - const regex = /(<([^>]+)>)/gi; - description = description.toString().replace(regex, ""); // Convert HTML entities, codes and tag - description = htmlToText(description, { wordwrap: false }); + description = htmlToText(description, { + wordwrap: false, + selectors: [ + { selector: "a", options: { ignoreHref: true, noAnchorUrl: true } }, + { selector: "br", format: "inlineSurround", options: { prefix: " " } }, + { selector: "img", format: "skip" } + ] + }); items.push({ title: title, diff --git a/modules/default/newsfeed/node_helper.js b/modules/default/newsfeed/node_helper.js index 64ba59290a..2110fde406 100644 --- a/modules/default/newsfeed/node_helper.js +++ b/modules/default/newsfeed/node_helper.js @@ -11,13 +11,13 @@ const NewsfeedFetcher = require("./newsfeedfetcher"); module.exports = NodeHelper.create({ // Override start method. - start: function () { + start () { Log.log(`Starting node helper for: ${this.name}`); this.fetchers = []; }, // Override socketNotificationReceived received. - socketNotificationReceived: function (notification, payload) { + socketNotificationReceived (notification, payload) { if (notification === "ADD_FEED") { this.createFetcher(payload.feed, payload.config); } @@ -29,7 +29,7 @@ module.exports = NodeHelper.create({ * @param {object} feed The feed object * @param {object} config The configuration object */ - createFetcher: function (feed, config) { + createFetcher (feed, config) { const url = feed.url || ""; const encoding = feed.encoding || "UTF-8"; const reloadInterval = feed.reloadInterval || config.reloadInterval || 5 * 60 * 1000; @@ -76,7 +76,7 @@ module.exports = NodeHelper.create({ * Creates an object with all feed items of the different registered feeds, * and broadcasts these using sendSocketNotification. */ - broadcastFeeds: function () { + broadcastFeeds () { const feeds = {}; for (let f in this.fetchers) { feeds[f] = this.fetchers[f].items(); diff --git a/modules/default/updatenotification/git_helper.js b/modules/default/updatenotification/git_helper.js index 3628dc49d7..8efe478d13 100644 --- a/modules/default/updatenotification/git_helper.js +++ b/modules/default/updatenotification/git_helper.js @@ -7,22 +7,22 @@ const Log = require("logger"); const BASE_DIR = path.normalize(`${__dirname}/../../../`); class GitHelper { - constructor() { + constructor () { this.gitRepos = []; this.gitResultList = []; } - getRefRegex(branch) { + getRefRegex (branch) { return new RegExp(`s*([a-z,0-9]+[.][.][a-z,0-9]+) ${branch}`, "g"); } - async execShell(command) { + async execShell (command) { const { stdout = "", stderr = "" } = await exec(command); return { stdout, stderr }; } - async isGitRepo(moduleFolder) { + async isGitRepo (moduleFolder) { const { stderr } = await this.execShell(`cd ${moduleFolder} && git remote -v`); if (stderr) { @@ -34,7 +34,7 @@ class GitHelper { return true; } - async add(moduleName) { + async add (moduleName) { let moduleFolder = BASE_DIR; if (moduleName !== "MagicMirror") { @@ -59,7 +59,7 @@ class GitHelper { } } - async getStatusInfo(repo) { + async getStatusInfo (repo) { let gitInfo = { module: repo.module, behind: 0, // commits behind @@ -114,7 +114,7 @@ class GitHelper { return gitInfo; } - async getRepoInfo(repo) { + async getRepoInfo (repo) { const gitInfo = await this.getStatusInfo(repo); if (!gitInfo || !gitInfo.current) { @@ -174,7 +174,7 @@ class GitHelper { } } - async getRepos() { + async getRepos () { this.gitResultList = []; for (const repo of this.gitRepos) { @@ -192,7 +192,7 @@ class GitHelper { return this.gitResultList; } - async checkUpdates() { + async checkUpdates () { var updates = []; const allRepos = await this.gitResultList.map((module) => { diff --git a/modules/default/updatenotification/node_helper.js b/modules/default/updatenotification/node_helper.js index f3b05fc84a..c78f413dc9 100644 --- a/modules/default/updatenotification/node_helper.js +++ b/modules/default/updatenotification/node_helper.js @@ -1,6 +1,7 @@ const NodeHelper = require("node_helper"); const defaultModules = require("../defaultmodules"); const GitHelper = require("./git_helper"); +const UpdateHelper = require("./update_helper"); const ONE_MINUTE = 60 * 1000; @@ -11,8 +12,9 @@ module.exports = NodeHelper.create({ updateProcessStarted: false, gitHelper: new GitHelper(), + updateHelper: null, - async configureModules(modules) { + async configureModules (modules) { for (const moduleName of modules) { if (!this.ignoreUpdateChecking(moduleName)) { await this.gitHelper.add(moduleName); @@ -24,10 +26,12 @@ module.exports = NodeHelper.create({ } }, - async socketNotificationReceived(notification, payload) { + async socketNotificationReceived (notification, payload) { switch (notification) { case "CONFIG": this.config = payload; + this.updateHelper = new UpdateHelper(this.config); + await this.updateHelper.check_PM2_Process(); break; case "MODULES": // if this is the 1st time thru the update check process @@ -47,22 +51,32 @@ module.exports = NodeHelper.create({ } }, - async performFetch() { + async performFetch () { const repos = await this.gitHelper.getRepos(); for (const repo of repos) { - this.sendSocketNotification("STATUS", repo); + this.sendSocketNotification("REPO_STATUS", repo); } - if (this.config.sendUpdatesNotifications) { - const updates = await this.gitHelper.checkUpdates(); - if (updates.length) this.sendSocketNotification("UPDATES", updates); + const updates = await this.gitHelper.checkUpdates(); + + if (this.config.sendUpdatesNotifications && updates.length) { + this.sendSocketNotification("UPDATES", updates); + } + + if (updates.length) { + const updateResult = await this.updateHelper.parse(updates); + for (const update of updateResult) { + if (update.inProgress) { + this.sendSocketNotification("UPDATE_STATUS", update); + } + } } this.scheduleNextFetch(this.config.updateInterval); }, - scheduleNextFetch(delay) { + scheduleNextFetch (delay) { clearTimeout(this.updateTimer); this.updateTimer = setTimeout( @@ -73,7 +87,7 @@ module.exports = NodeHelper.create({ ); }, - ignoreUpdateChecking(moduleName) { + ignoreUpdateChecking (moduleName) { // Should not check for updates for default modules if (defaultModules.includes(moduleName)) { return true; diff --git a/modules/default/updatenotification/update_helper.js b/modules/default/updatenotification/update_helper.js new file mode 100644 index 0000000000..25fd0aaa18 --- /dev/null +++ b/modules/default/updatenotification/update_helper.js @@ -0,0 +1,230 @@ +const Exec = require("child_process").exec; +const Spawn = require("child_process").spawn; +const commandExists = require("command-exists"); +const Log = require("logger"); + +/* class Updater + * Allow to self updating 3rd party modules from command defined in config + * + * [constructor] read value in config: + * updates: [ // array of modules update commands + * { + * : + * }, + * { + * ... + * } + * ], + * updateTimeout: 2 * 60 * 1000, // max update duration + * updateAutorestart: false // autoRestart MM when update done ? + * + * [main command]: parse(): + * parse if module update is needed + * --> Apply ONLY one update (first of the module list) + * --> auto-restart MagicMirror or wait manual restart by user + * return array with modules update state information for `updatenotification` module displayer information + * [ + * { + * name = , // name of the module + * updateCommand = , // update command (if found) + * inProgress = , // an update if in progress for this module + * error = , // an error if detected when updating + * updated = , // updated successfully + * needRestart = // manual restart of MagicMirror is required by user + * }, + * { + * ... + * } + * ] + */ + +class Updater { + constructor (config) { + this.updates = config.updates; + this.timeout = config.updateTimeout; + this.autoRestart = config.updateAutorestart; + this.moduleList = {}; + this.updating = false; + this.usePM2 = false; + this.PM2 = null; + this.version = global.version; + this.root_path = global.root_path; + Log.info("updatenotification: Updater Class Loaded!"); + } + + // [main command] parse if module update is needed + async parse (modules) { + var parser = modules.map(async (module) => { + if (this.moduleList[module.module] === undefined) { + this.moduleList[module.module] = {}; + this.moduleList[module.module].name = module.module; + this.moduleList[module.module].updateCommand = await this.applyCommand(module.module); + this.moduleList[module.module].inProgress = false; + this.moduleList[module.module].error = null; + this.moduleList[module.module].updated = false; + this.moduleList[module.module].needRestart = false; + } + if (!this.moduleList[module.module].inProgress) { + if (!this.updating) { + if (!this.moduleList[module.module].updateCommand) { + this.updating = false; + } else { + this.updating = true; + this.moduleList[module.module].inProgress = true; + Object.assign(this.moduleList[module.module], await this.updateProcess(this.moduleList[module.module])); + } + } + } + }); + + await Promise.all(parser); + let updater = Object.values(this.moduleList); + Log.debug("updatenotification Update Result:", updater); + return updater; + } + + // module updater with his proper command + // return object as result + //{ + // error: , // if error detected + // updated: , // if updated successfully + // needRestart: // if magicmirror restart required + //}; + updateProcess (module) { + let Result = { + error: false, + updated: false, + needRestart: false + }; + let Command = null; + const Path = `${this.root_path}/modules/`; + const modulePath = Path + module.name; + + if (module.updateCommand) { + Command = module.updateCommand; + } else { + Log.warn(`updatenotification: Update of ${module.name} is not supported.`); + return Result; + } + Log.info(`updatenotification: Updating ${module.name}...`); + + return new Promise((resolve) => { + Exec(Command, { cwd: modulePath, timeout: this.timeout }, (error, stdout, stderr) => { + if (error) { + Log.error(`updatenotification: exec error: ${error}`); + Result.error = true; + } else { + Log.info(`updatenotification: Update logs of ${module.name}: ${stdout}`); + Result.updated = true; + if (this.autoRestart) { + Log.info("updatenotification: Update done"); + setTimeout(() => this.restart(), 3000); + } else { + Log.info("updatenotification: Update done, don't forget to restart MagicMirror!"); + Result.needRestart = true; + } + } + resolve(Result); + }); + }); + } + + // restart rules (pm2 or npm start) + restart () { + if (this.usePM2) this.pm2Restart(); + else this.npmRestart(); + } + + // restart MagicMiror with "pm2" + pm2Restart () { + Log.info("updatenotification: PM2 will restarting MagicMirror..."); + Exec(`pm2 restart ${this.PM2}`, (err, std, sde) => { + if (err) { + Log.error("updatenotification:[PM2] restart Error", err); + } + }); + } + + // restart MagicMiror with "npm start" + npmRestart () { + Log.info("updatenotification: Restarting MagicMirror..."); + const out = process.stdout; + const err = process.stderr; + const subprocess = Spawn("npm start", { cwd: this.root_path, shell: true, detached: true, stdio: ["ignore", out, err] }); + subprocess.unref(); + process.exit(); + } + + // Check using pm2 + check_PM2_Process () { + Log.info("updatenotification: Checking PM2 using..."); + return new Promise((resolve) => { + commandExists("pm2") + .then(async () => { + var PM2_List = await this.PM2_GetList(); + if (!PM2_List) { + Log.error("updatenotification: [PM2] Can't get process List!"); + this.usePM2 = false; + resolve(false); + return; + } + PM2_List.forEach((pm) => { + if (pm.pm2_env.version === this.version && pm.pm2_env.status === "online" && pm.pm2_env.PWD.includes(this.root_path)) { + this.PM2 = pm.name; + this.usePM2 = true; + Log.info("updatenotification: You are using pm2 with", this.PM2); + resolve(true); + } + }); + if (!this.PM2) { + Log.info("updatenotification: You are not using pm2"); + this.usePM2 = false; + resolve(false); + } + }) + .catch(() => { + Log.info("updatenotification: You are not using pm2"); + this.usePM2 = false; + resolve(false); + }); + }); + } + + // Get the list of pm2 process + PM2_GetList () { + return new Promise((resolve) => { + Exec("pm2 jlist", (err, std, sde) => { + if (err) { + resolve(null); + return; + } + try { + let result = JSON.parse(std); + resolve(result); + } catch (e) { + Log.error("updatenotification: [PM2] can't GetList!"); + Log.debug("updatenotification: [PM2] GetList is not an JSON format", e); + resolve(null); + } + }); + }); + } + + // check if module is MagicMirror + isMagicMirror (module) { + if (module === "MagicMirror") return true; + return false; + } + + // search update module command + applyCommand (module) { + if (this.isMagicMirror(module.module)) return null; + let command = null; + this.updates.forEach((updater) => { + if (updater[module]) command = updater[module]; + }); + return command; + } +} + +module.exports = Updater; diff --git a/modules/default/updatenotification/updatenotification.js b/modules/default/updatenotification/updatenotification.js index 73327ec844..7c5f595a79 100644 --- a/modules/default/updatenotification/updatenotification.js +++ b/modules/default/updatenotification/updatenotification.js @@ -9,13 +9,18 @@ Module.register("updatenotification", { updateInterval: 10 * 60 * 1000, // every 10 minutes refreshInterval: 24 * 60 * 60 * 1000, // one day ignoreModules: [], - sendUpdatesNotifications: false + sendUpdatesNotifications: false, + updates: [], + updateTimeout: 2 * 60 * 1000, // max update duration + updateAutorestart: false // autoRestart MM when update done ? }, suspended: false, moduleList: {}, + needRestart: false, + updates: {}, - start() { + start () { Log.info(`Starting module: ${this.name}`); this.addFilters(); setInterval(() => { @@ -24,16 +29,16 @@ Module.register("updatenotification", { }, this.config.refreshInterval); }, - suspend() { + suspend () { this.suspended = true; }, - resume() { + resume () { this.suspended = false; this.updateDom(2); }, - notificationReceived(notification) { + notificationReceived (notification) { switch (notification) { case "DOM_OBJECTS_CREATED": this.sendSocketNotification("CONFIG", this.config); @@ -45,30 +50,33 @@ Module.register("updatenotification", { } }, - socketNotificationReceived(notification, payload) { + socketNotificationReceived (notification, payload) { switch (notification) { - case "STATUS": + case "REPO_STATUS": this.updateUI(payload); break; case "UPDATES": this.sendNotification("UPDATES", payload); break; + case "UPDATE_STATUS": + this.updatesNotifier(payload); + break; } }, - getStyles() { + getStyles () { return [`${this.name}.css`]; }, - getTemplate() { + getTemplate () { return `${this.name}.njk`; }, - getTemplateData() { - return { moduleList: this.moduleList, suspended: this.suspended }; + getTemplateData () { + return { moduleList: this.moduleList, updatesList: this.updates, suspended: this.suspended, needRestart: this.needRestart }; }, - updateUI(payload) { + updateUI (payload) { if (payload && payload.behind > 0) { // if we haven't seen info for this module if (this.moduleList[payload.module] === undefined) { @@ -86,7 +94,7 @@ Module.register("updatenotification", { } }, - addFilters() { + addFilters () { this.nunjucksEnvironment().addFilter("diffLink", (text, status) => { if (status.module !== "MagicMirror") { return text; @@ -96,5 +104,29 @@ Module.register("updatenotification", { const remoteRef = status.tracking.replace(/.*\//, ""); return `${text}`; }); + }, + + updatesNotifier (payload, done = true) { + if (this.updates[payload.name] === undefined) { + this.updates[payload.name] = { + name: payload.name, + done: done + }; + + if (payload.error) { + this.sendSocketNotification("UPDATE_ERROR", payload.name); + this.updates[payload.name].done = false; + } else { + if (payload.updated) { + delete this.moduleList[payload.name]; + this.updates[payload.name].done = true; + } + if (payload.needRestart) { + this.needRestart = true; + } + } + + this.updateDom(2); + } } }); diff --git a/modules/default/updatenotification/updatenotification.njk b/modules/default/updatenotification/updatenotification.njk index 415688d6e1..fbc43f22fb 100644 --- a/modules/default/updatenotification/updatenotification.njk +++ b/modules/default/updatenotification/updatenotification.njk @@ -1,4 +1,13 @@ {% if not suspended %} + {% if needRestart %} +
+ + + {% set restartTextLabel = "UPDATE_NOTIFICATION_NEED-RESTART" %} + {{ restartTextLabel | translate() | safe }} + +
+ {% endif %} {% for name, status in moduleList %}
@@ -12,4 +21,21 @@ {{ subTextLabel | translate({COMMIT_COUNT: status.behind, BRANCH_NAME: status.current}) | diffLink(status) | safe }}
{% endfor %} + {% for name, status in updatesList %} +
+ {% if status.done %} + + + {% set updateTextLabel = "UPDATE_NOTIFICATION_DONE" %} + {{ updateTextLabel | translate({MODULE_NAME: name}) | safe }} + + {% else %} + + + {% set updateTextLabel = "UPDATE_NOTIFICATION_ERROR" %} + {{ updateTextLabel | translate({MODULE_NAME: name}) | safe }} + + {% endif %} +
+ {% endfor %} {% endif %} diff --git a/modules/default/utils.js b/modules/default/utils.js index e60d96ea87..ca0166935c 100644 --- a/modules/default/utils.js +++ b/modules/default/utils.js @@ -7,7 +7,7 @@ * @param {Array.} expectedResponseHeaders the expected HTTP headers to receive * @returns {Promise} resolved when the fetch is done. The response headers is placed in a headers-property (provided the response does not already contain a headers-property). */ -async function performWebRequest(url, type = "json", useCorsProxy = false, requestHeaders = undefined, expectedResponseHeaders = undefined) { +async function performWebRequest (url, type = "json", useCorsProxy = false, requestHeaders = undefined, expectedResponseHeaders = undefined) { const request = {}; let requestUrl; if (useCorsProxy) { @@ -165,8 +165,7 @@ const formatTime = (config, time) => { return date.format("HH:mm"); }; -if (typeof module !== "undefined") - module.exports = { - performWebRequest, - formatTime - }; +if (typeof module !== "undefined") module.exports = { + performWebRequest, + formatTime +}; diff --git a/modules/default/weather/providers/envcanada.js b/modules/default/weather/providers/envcanada.js index 4c0bf02f5b..934c5831d4 100644 --- a/modules/default/weather/providers/envcanada.js +++ b/modules/default/weather/providers/envcanada.js @@ -49,7 +49,7 @@ WeatherProvider.register("envcanada", { // Set config values (equates to weather module config values). Also set values pertaining to caching of // Today's temperature forecast (for use in the Forecast functions below) // - setConfig: function (config) { + setConfig (config) { this.config = config; this.todayTempCacheMin = 0; @@ -61,7 +61,7 @@ WeatherProvider.register("envcanada", { // // Called when the weather provider is started // - start: function () { + start () { Log.info(`Weather provider: ${this.providerName} started.`); this.setFetchedLocation(this.config.location); }, @@ -69,7 +69,7 @@ WeatherProvider.register("envcanada", { // // Override the fetchCurrentWeather method to query EC and construct a Current weather object // - fetchCurrentWeather() { + fetchCurrentWeather () { this.fetchData(this.getUrl(), "xml") .then((data) => { if (!data) { @@ -89,7 +89,7 @@ WeatherProvider.register("envcanada", { // // Override the fetchWeatherForecast method to query EC and construct Forecast weather objects // - fetchWeatherForecast() { + fetchWeatherForecast () { this.fetchData(this.getUrl(), "xml") .then((data) => { if (!data) { @@ -109,7 +109,7 @@ WeatherProvider.register("envcanada", { // // Override the fetchWeatherHourly method to query EC and construct Forecast weather objects // - fetchWeatherHourly() { + fetchWeatherHourly () { this.fetchData(this.getUrl(), "xml") .then((data) => { if (!data) { @@ -137,7 +137,7 @@ WeatherProvider.register("envcanada", { // URL defaults to the English version simply because there is no language dependency in the data // being accessed. This is only pertinent when using the EC data elements that contain a textual forecast. // - getUrl() { + getUrl () { return `https://dd.weather.gc.ca/citypage_weather/xml/${this.config.provCode}/${this.config.siteCode}_e.xml`; }, @@ -145,7 +145,7 @@ WeatherProvider.register("envcanada", { // Generate a WeatherObject based on current EC weather conditions // - generateWeatherObjectFromCurrentWeather(ECdoc) { + generateWeatherObjectFromCurrentWeather (ECdoc) { const currentWeather = new WeatherObject(); // There are instances where EC will update weather data and current temperature will not be @@ -216,7 +216,7 @@ WeatherProvider.register("envcanada", { // Generate an array of WeatherObjects based on EC weather forecast // - generateWeatherObjectsFromForecast(ECdoc) { + generateWeatherObjectsFromForecast (ECdoc) { // Declare an array to hold each day's forecast object const days = []; @@ -360,7 +360,7 @@ WeatherProvider.register("envcanada", { // Generate an array of WeatherObjects based on EC hourly weather forecast // - generateWeatherObjectsFromHourly(ECdoc) { + generateWeatherObjectsFromHourly (ECdoc) { // Declare an array to hold each hour's forecast object const hours = []; @@ -416,7 +416,7 @@ WeatherProvider.register("envcanada", { // the next Forecast element should be considered - i.e. look at Today *and* Tonight vs.Tonight-only // - setMinMaxTemps(weather, foreGroup, today, fullDay, currentTemp) { + setMinMaxTemps (weather, foreGroup, today, fullDay, currentTemp) { const todayTemp = foreGroup[today].querySelector("temperatures temperature").textContent; const todayClass = foreGroup[today].querySelector("temperatures temperature").getAttribute("class"); @@ -498,7 +498,7 @@ WeatherProvider.register("envcanada", { // the nightime forecast after a certain point in that specific scenario. // - setPrecipitation(weather, foreGroup, today) { + setPrecipitation (weather, foreGroup, today) { if (foreGroup[today].querySelector("precipitation accumulation")) { weather.precipitationAmount = foreGroup[today].querySelector("precipitation accumulation amount").textContent * 1.0; weather.precipitationUnits = foreGroup[today].querySelector("precipitation accumulation amount").getAttribute("units"); @@ -514,7 +514,7 @@ WeatherProvider.register("envcanada", { // // Convert the icons to a more usable name. // - convertWeatherType(weatherType) { + convertWeatherType (weatherType) { const weatherTypes = { "00": "day-sunny", "01": "day-sunny", diff --git a/modules/default/weather/providers/openmeteo.js b/modules/default/weather/providers/openmeteo.js index 79d7d1fadb..b80601a12e 100644 --- a/modules/default/weather/providers/openmeteo.js +++ b/modules/default/weather/providers/openmeteo.js @@ -140,11 +140,11 @@ WeatherProvider.register("openmeteo", { "et0_fao_evapotranspiration" ], - fetchedLocation: function () { + fetchedLocation () { return this.fetchedLocationName || ""; }, - fetchCurrentWeather() { + fetchCurrentWeather () { this.fetchData(this.getUrl()) .then((data) => this.parseWeatherApiResponse(data)) .then((parsedData) => { @@ -162,7 +162,7 @@ WeatherProvider.register("openmeteo", { .finally(() => this.updateAvailable()); }, - fetchWeatherForecast() { + fetchWeatherForecast () { this.fetchData(this.getUrl()) .then((data) => this.parseWeatherApiResponse(data)) .then((parsedData) => { @@ -180,7 +180,7 @@ WeatherProvider.register("openmeteo", { .finally(() => this.updateAvailable()); }, - fetchWeatherHourly() { + fetchWeatherHourly () { this.fetchData(this.getUrl()) .then((data) => this.parseWeatherApiResponse(data)) .then((parsedData) => { @@ -202,7 +202,7 @@ WeatherProvider.register("openmeteo", { * Overrides method for setting config to check if endpoint is correct for hourly * @param {object} config The configuration object */ - setConfig(config) { + setConfig (config) { this.config = { lang: config.lang ?? "en", ...this.defaults, @@ -226,7 +226,7 @@ WeatherProvider.register("openmeteo", { }, // Generate valid query params to perform the request - getQueryParameters() { + getQueryParameters () { let params = { latitude: this.config.lat, longitude: this.config.lon, @@ -278,25 +278,23 @@ WeatherProvider.register("openmeteo", { }, // Create a URL from the config and base URL. - getUrl() { + getUrl () { return `${this.config.apiBase}/forecast?${this.getQueryParameters()}`; }, // Transpose hourly and daily data matrices - transposeDataMatrix(data) { - return data.time.map((_, index) => - Object.keys(data).reduce((row, key) => { - return { - ...row, - // Parse time values as momentjs instances - [key]: ["time", "sunrise", "sunset"].includes(key) ? moment.unix(data[key][index]) : data[key][index] - }; - }, {}) - ); + transposeDataMatrix (data) { + return data.time.map((_, index) => Object.keys(data).reduce((row, key) => { + return { + ...row, + // Parse time values as momentjs instances + [key]: ["time", "sunrise", "sunset"].includes(key) ? moment.unix(data[key][index]) : data[key][index] + }; + }, {})); }, // Sanitize and validate API response - parseWeatherApiResponse(data) { + parseWeatherApiResponse (data) { const validByType = { current: data.current_weather && data.current_weather.time, hourly: data.hourly && data.hourly.time && Array.isArray(data.hourly.time) && data.hourly.time.length > 0, @@ -334,7 +332,7 @@ WeatherProvider.register("openmeteo", { }, // Reverse geocoding from latitude and longitude provided - fetchLocation() { + fetchLocation () { this.fetchData(`${GEOCODE_BASE}?latitude=${this.config.lat}&longitude=${this.config.lon}&localityLanguage=${this.config.lang}`) .then((data) => { if (!data || !data.city) { @@ -349,7 +347,8 @@ WeatherProvider.register("openmeteo", { }, // Implement WeatherDay generator. - generateWeatherDayFromCurrentWeather(weather) { + generateWeatherDayFromCurrentWeather (weather) { + /** * Since some units comes from API response "splitted" into daily, hourly and current_weather * every time you request it, you have to ensure to get the data from the right place every time. @@ -394,10 +393,10 @@ WeatherProvider.register("openmeteo", { }, // Implement WeatherForecast generator. - generateWeatherObjectsFromForecast(weathers) { + generateWeatherObjectsFromForecast (weathers) { const days = []; - weathers.daily.forEach((weather, i) => { + weathers.daily.forEach((weather) => { const currentWeather = new WeatherObject(); currentWeather.date = weather.time; @@ -422,7 +421,7 @@ WeatherProvider.register("openmeteo", { }, // Implement WeatherHourly generator. - generateWeatherObjectsFromHourly(weathers) { + generateWeatherObjectsFromHourly (weathers) { const hours = []; const now = moment(); @@ -457,7 +456,7 @@ WeatherProvider.register("openmeteo", { }, // Map icons from Dark Sky to our icons. - convertWeatherType(weathercode, isDayTime) { + convertWeatherType (weathercode, isDayTime) { const weatherConditions = { 0: "clear", 1: "mainly-clear", @@ -542,7 +541,7 @@ WeatherProvider.register("openmeteo", { }, // Define required scripts. - getScripts: function () { + getScripts () { return ["moment.js"]; } }); diff --git a/modules/default/weather/providers/openweathermap.js b/modules/default/weather/providers/openweathermap.js index cf65604b14..c389b7fd97 100644 --- a/modules/default/weather/providers/openweathermap.js +++ b/modules/default/weather/providers/openweathermap.js @@ -27,7 +27,7 @@ WeatherProvider.register("openweathermap", { }, // Overwrite the fetchCurrentWeather method. - fetchCurrentWeather() { + fetchCurrentWeather () { this.fetchData(this.getUrl()) .then((data) => { let currentWeather; @@ -46,7 +46,7 @@ WeatherProvider.register("openweathermap", { }, // Overwrite the fetchWeatherForecast method. - fetchWeatherForecast() { + fetchWeatherForecast () { this.fetchData(this.getUrl()) .then((data) => { let forecast; @@ -68,7 +68,7 @@ WeatherProvider.register("openweathermap", { }, // Overwrite the fetchWeatherHourly method. - fetchWeatherHourly() { + fetchWeatherHourly () { this.fetchData(this.getUrl()) .then((data) => { if (!data) { @@ -92,7 +92,7 @@ WeatherProvider.register("openweathermap", { * Overrides method for setting config to check if endpoint is correct for hourly * @param {object} config The configuration object */ - setConfig(config) { + setConfig (config) { this.config = config; if (!this.config.weatherEndpoint) { switch (this.config.type) { @@ -116,14 +116,14 @@ WeatherProvider.register("openweathermap", { /* * Gets the complete url for the request */ - getUrl() { + getUrl () { return this.config.apiBase + this.config.apiVersion + this.config.weatherEndpoint + this.getParams(); }, /* * Generate a WeatherObject based on currentWeatherInformation */ - generateWeatherObjectFromCurrentWeather(currentWeatherData) { + generateWeatherObjectFromCurrentWeather (currentWeatherData) { const currentWeather = new WeatherObject(); currentWeather.date = moment.unix(currentWeatherData.dt); @@ -142,7 +142,7 @@ WeatherProvider.register("openweathermap", { /* * Generate WeatherObjects based on forecast information */ - generateWeatherObjectsFromForecast(forecasts) { + generateWeatherObjectsFromForecast (forecasts) { if (this.config.weatherEndpoint === "/forecast") { return this.generateForecastHourly(forecasts); } else if (this.config.weatherEndpoint === "/forecast/daily") { @@ -155,7 +155,7 @@ WeatherProvider.register("openweathermap", { /* * Generate WeatherObjects based on One Call forecast information */ - generateWeatherObjectsFromOnecall(data) { + generateWeatherObjectsFromOnecall (data) { if (this.config.weatherEndpoint === "/onecall") { return this.fetchOnecall(data); } @@ -167,7 +167,7 @@ WeatherProvider.register("openweathermap", { * Generate forecast information for 3-hourly forecast (available for free * subscription). */ - generateForecastHourly(forecasts) { + generateForecastHourly (forecasts) { // initial variable declaration const days = []; // variables for temperature range and rain @@ -241,7 +241,7 @@ WeatherProvider.register("openweathermap", { * Generate forecast information for daily forecast (available for paid * subscription or old apiKey). */ - generateForecastDaily(forecasts) { + generateForecastDaily (forecasts) { // initial variable declaration const days = []; @@ -281,7 +281,7 @@ WeatherProvider.register("openweathermap", { * Factors in timezone offsets. * Minutely forecasts are excluded for the moment, see getParams(). */ - fetchOnecall(data) { + fetchOnecall (data) { let precip = false; // get current weather, if requested @@ -382,7 +382,7 @@ WeatherProvider.register("openweathermap", { /* * Convert the OpenWeatherMap icons to a more usable name. */ - convertWeatherType(weatherType) { + convertWeatherType (weatherType) { const weatherTypes = { "01d": "day-sunny", "02d": "day-cloudy", @@ -412,7 +412,7 @@ WeatherProvider.register("openweathermap", { * * return String - URL params. */ - getParams() { + getParams () { let params = "?"; if (this.config.weatherEndpoint === "/onecall") { params += `lat=${this.config.lat}`; diff --git a/modules/default/weather/providers/overrideWrapper.js b/modules/default/weather/providers/overrideWrapper.js index e529efe4c7..a9002809a1 100644 --- a/modules/default/weather/providers/overrideWrapper.js +++ b/modules/default/weather/providers/overrideWrapper.js @@ -21,7 +21,7 @@ const OverrideWrapper = Class.extend({ notificationWeatherObject: null, currentOverrideWeatherObject: null, - init(baseProvider) { + init (baseProvider) { this.baseProvider = baseProvider; // Binding the scope of current weather functions so any fetchData calls with @@ -33,43 +33,43 @@ const OverrideWrapper = Class.extend({ /* Unchanged Api Provider Methods */ - setConfig(config) { + setConfig (config) { this.baseProvider.setConfig(config); }, - start() { + start () { this.baseProvider.start(); }, - fetchCurrentWeather() { + fetchCurrentWeather () { this.baseProvider.fetchCurrentWeather(); }, - fetchWeatherForecast() { + fetchWeatherForecast () { this.baseProvider.fetchWeatherForecast(); }, - fetchWeatherHourly() { + fetchWeatherHourly () { this.baseProvider.fetchEatherHourly(); }, - weatherForecast() { + weatherForecast () { this.baseProvider.weatherForecast(); }, - weatherHourly() { + weatherHourly () { this.baseProvider.weatherHourly(); }, - fetchedLocation() { + fetchedLocation () { this.baseProvider.fetchedLocation(); }, - setWeatherForecast(weatherForecastArray) { + setWeatherForecast (weatherForecastArray) { this.baseProvider.setWeatherForecast(weatherForecastArray); }, - setWeatherHourly(weatherHourlyArray) { + setWeatherHourly (weatherHourlyArray) { this.baseProvider.setWeatherHourly(weatherHourlyArray); }, - setFetchedLocation(name) { + setFetchedLocation (name) { this.baseProvider.setFetchedLocation(name); }, - updateAvailable() { + updateAvailable () { this.baseProvider.updateAvailable(); }, - async fetchData(url, type = "json", requestHeaders = undefined, expectedResponseHeaders = undefined) { + async fetchData (url, type = "json", requestHeaders = undefined, expectedResponseHeaders = undefined) { this.baseProvider.fetchData(url, type, requestHeaders, expectedResponseHeaders); }, @@ -79,7 +79,7 @@ const OverrideWrapper = Class.extend({ * Override to return this scope's * @returns {WeatherObject} The current weather object. May or may not contain overridden data. */ - currentWeather() { + currentWeather () { return this.currentOverrideWeatherObject; }, @@ -89,7 +89,7 @@ const OverrideWrapper = Class.extend({ * api provider fetchData implementation. * @param {WeatherObject} currentWeatherObject - the api provider weather object */ - setCurrentWeather(currentWeatherObject) { + setCurrentWeather (currentWeatherObject) { this.currentOverrideWeatherObject = Object.assign(currentWeatherObject, this.notificationWeatherObject); }, @@ -101,7 +101,7 @@ const OverrideWrapper = Class.extend({ * notification. Represents information to augment the * existing currentOverrideWeatherObject with. */ - notificationReceived(payload) { + notificationReceived (payload) { this.notificationWeatherObject = payload; // setCurrentWeather combines the newly received notification weather with diff --git a/modules/default/weather/providers/pirateweather.js b/modules/default/weather/providers/pirateweather.js index 1bb956112a..46106cfc3e 100644 --- a/modules/default/weather/providers/pirateweather.js +++ b/modules/default/weather/providers/pirateweather.js @@ -25,7 +25,7 @@ WeatherProvider.register("pirateweather", { lon: 0 }, - fetchCurrentWeather() { + fetchCurrentWeather () { this.fetchData(this.getUrl()) .then((data) => { if (!data || !data.currently || typeof data.currently.temperature === "undefined") { @@ -42,7 +42,7 @@ WeatherProvider.register("pirateweather", { .finally(() => this.updateAvailable()); }, - fetchWeatherForecast() { + fetchWeatherForecast () { this.fetchData(this.getUrl()) .then((data) => { if (!data || !data.daily || !data.daily.data.length) { @@ -60,12 +60,12 @@ WeatherProvider.register("pirateweather", { }, // Create a URL from the config and base URL. - getUrl() { + getUrl () { return `${this.config.apiBase}${this.config.weatherEndpoint}/${this.config.apiKey}/${this.config.lat},${this.config.lon}?units=si&lang=${this.config.lang}`; }, // Implement WeatherDay generator. - generateWeatherDayFromCurrentWeather(currentWeatherData) { + generateWeatherDayFromCurrentWeather (currentWeatherData) { const currentWeather = new WeatherObject(); currentWeather.date = moment(); @@ -80,7 +80,7 @@ WeatherProvider.register("pirateweather", { return currentWeather; }, - generateWeatherObjectsFromForecast(forecasts) { + generateWeatherObjectsFromForecast (forecasts) { const days = []; for (const forecast of forecasts) { @@ -114,7 +114,7 @@ WeatherProvider.register("pirateweather", { }, // Map icons from Pirate Weather to our icons. - convertWeatherType(weatherType) { + convertWeatherType (weatherType) { const weatherTypes = { "clear-day": "day-sunny", "clear-night": "night-clear", diff --git a/modules/default/weather/providers/smhi.js b/modules/default/weather/providers/smhi.js index 0cdd85f1a9..d1641b4214 100644 --- a/modules/default/weather/providers/smhi.js +++ b/modules/default/weather/providers/smhi.js @@ -24,7 +24,7 @@ WeatherProvider.register("smhi", { /** * Implements method in interface for fetching current weather. */ - fetchCurrentWeather() { + fetchCurrentWeather () { this.fetchData(this.getURL()) .then((data) => { const closest = this.getClosestToCurrentTime(data.timeSeries); @@ -40,7 +40,7 @@ WeatherProvider.register("smhi", { /** * Implements method in interface for fetching a multi-day forecast. */ - fetchWeatherForecast() { + fetchWeatherForecast () { this.fetchData(this.getURL()) .then((data) => { const coordinates = this.resolveCoordinates(data); @@ -55,7 +55,7 @@ WeatherProvider.register("smhi", { /** * Implements method in interface for fetching hourly forecasts. */ - fetchWeatherHourly() { + fetchWeatherHourly () { this.fetchData(this.getURL()) .then((data) => { const coordinates = this.resolveCoordinates(data); @@ -71,7 +71,7 @@ WeatherProvider.register("smhi", { * Overrides method for setting config with checks for the precipitationValue being unset or invalid * @param {object} config The configuration object */ - setConfig(config) { + setConfig (config) { this.config = config; if (!config.precipitationValue || ["pmin", "pmean", "pmedian", "pmax"].indexOf(config.precipitationValue) === -1) { Log.log(`invalid or not set: ${config.precipitationValue}`); @@ -84,7 +84,7 @@ WeatherProvider.register("smhi", { * @param {object[]} times Array of time objects * @returns {object} The weatherdata closest to the current time */ - getClosestToCurrentTime(times) { + getClosestToCurrentTime (times) { let now = moment(); let minDiff = undefined; for (const time of times) { @@ -100,7 +100,7 @@ WeatherProvider.register("smhi", { * Get the forecast url for the configured coordinates * @returns {string} the url for the specified coordinates */ - getURL() { + getURL () { const formatter = new Intl.NumberFormat("en-US", { minimumFractionDigits: 6, maximumFractionDigits: 6 @@ -115,7 +115,7 @@ WeatherProvider.register("smhi", { * @param {object} weatherData Weatherdata to use for the calculation * @returns {number} The apparent temperature */ - calculateApparentTemperature(weatherData) { + calculateApparentTemperature (weatherData) { const Ta = this.paramValue(weatherData, "t"); const rh = this.paramValue(weatherData, "r"); const ws = this.paramValue(weatherData, "ws"); @@ -132,7 +132,7 @@ WeatherProvider.register("smhi", { * @param {object} coordinates Coordinates of the locations of the weather * @returns {WeatherObject} The converted weatherdata at the specified location */ - convertWeatherDataToObject(weatherData, coordinates) { + convertWeatherDataToObject (weatherData, coordinates) { let currentWeather = new WeatherObject(); currentWeather.date = moment(weatherData.validTime); @@ -178,7 +178,7 @@ WeatherProvider.register("smhi", { * @param {string} groupBy The interval to use for grouping the data (day, hour) * @returns {WeatherObject[]} Array of weatherobjects */ - convertWeatherDataGroupedBy(allWeatherData, coordinates, groupBy = "day") { + convertWeatherDataGroupedBy (allWeatherData, coordinates, groupBy = "day") { let currentWeather; let result = []; @@ -227,7 +227,7 @@ WeatherProvider.register("smhi", { * @param {object} data Response data from the weather service * @returns {{lon, lat}} the lat/long coordinates of the data */ - resolveCoordinates(data) { + resolveCoordinates (data) { return { lat: data.geometry.coordinates[0][1], lon: data.geometry.coordinates[0][0] }; }, @@ -237,7 +237,7 @@ WeatherProvider.register("smhi", { * @param {object[]} data Response data from the weather service * @returns {object[]} Given data with filled gaps */ - fillInGaps(data) { + fillInGaps (data) { let result = []; for (let i = 1; i < data.length; i++) { let to = moment(data[i].validTime); @@ -259,7 +259,7 @@ WeatherProvider.register("smhi", { * @param {string} name The name of the property * @returns {*} The value of the property in the weatherdata */ - paramValue(currentWeatherData, name) { + paramValue (currentWeatherData, name) { return currentWeatherData.parameters.filter((p) => p.name === name).flatMap((p) => p.values)[0]; }, @@ -271,7 +271,7 @@ WeatherProvider.register("smhi", { * @param {boolean} isDayTime True if the icon should be for daytime, false for nighttime * @returns {string} The icon name for the MagicMirror */ - convertWeatherType(input, isDayTime) { + convertWeatherType (input, isDayTime) { switch (input) { case 1: return isDayTime ? "day-sunny" : "night-clear"; // Clear sky diff --git a/modules/default/weather/providers/ukmetoffice.js b/modules/default/weather/providers/ukmetoffice.js index 49c7d80c24..e4e020b371 100644 --- a/modules/default/weather/providers/ukmetoffice.js +++ b/modules/default/weather/providers/ukmetoffice.js @@ -22,7 +22,7 @@ WeatherProvider.register("ukmetoffice", { }, // Overwrite the fetchCurrentWeather method. - fetchCurrentWeather() { + fetchCurrentWeather () { this.fetchData(this.getUrl("3hourly")) .then((data) => { if (!data || !data.SiteRep || !data.SiteRep.DV || !data.SiteRep.DV.Location || !data.SiteRep.DV.Location.Period || data.SiteRep.DV.Location.Period.length === 0) { @@ -43,7 +43,7 @@ WeatherProvider.register("ukmetoffice", { }, // Overwrite the fetchCurrentWeather method. - fetchWeatherForecast() { + fetchWeatherForecast () { this.fetchData(this.getUrl("daily")) .then((data) => { if (!data || !data.SiteRep || !data.SiteRep.DV || !data.SiteRep.DV.Location || !data.SiteRep.DV.Location.Period || data.SiteRep.DV.Location.Period.length === 0) { @@ -67,14 +67,14 @@ WeatherProvider.register("ukmetoffice", { /* * Gets the complete url for the request */ - getUrl(forecastType) { + getUrl (forecastType) { return this.config.apiBase + this.config.locationID + this.getParams(forecastType); }, /* * Generate a WeatherObject based on currentWeatherInformation */ - generateWeatherObjectFromCurrentWeather(currentWeatherData) { + generateWeatherObjectFromCurrentWeather (currentWeatherData) { const currentWeather = new WeatherObject(); const location = currentWeatherData.SiteRep.DV.Location; @@ -119,7 +119,7 @@ WeatherProvider.register("ukmetoffice", { /* * Generate WeatherObjects based on forecast information */ - generateWeatherObjectsFromForecast(forecasts) { + generateWeatherObjectsFromForecast (forecasts) { const days = []; // loop round the (5) periods getting the data @@ -150,7 +150,7 @@ WeatherProvider.register("ukmetoffice", { /* * Convert the Met Office icons to a more usable name. */ - convertWeatherType(weatherType) { + convertWeatherType (weatherType) { const weatherTypes = { 0: "night-clear", 1: "day-sunny", @@ -192,7 +192,7 @@ WeatherProvider.register("ukmetoffice", { * @param {string} forecastType daily or 3hourly forecast * @returns {string} url */ - getParams(forecastType) { + getParams (forecastType) { let params = "?"; params += `res=${forecastType}`; params += `&key=${this.config.apiKey}`; diff --git a/modules/default/weather/providers/ukmetofficedatahub.js b/modules/default/weather/providers/ukmetofficedatahub.js index a4d41267aa..225e7b4660 100644 --- a/modules/default/weather/providers/ukmetofficedatahub.js +++ b/modules/default/weather/providers/ukmetofficedatahub.js @@ -53,7 +53,7 @@ WeatherProvider.register("ukmetofficedatahub", { }, // Build URL with query strings according to DataHub API (https://metoffice.apiconnect.ibmcloud.com/metoffice/production/api) - getUrl(forecastType) { + getUrl (forecastType) { let queryStrings = "?"; queryStrings += `latitude=${this.config.lat}`; queryStrings += `&longitude=${this.config.lon}`; @@ -66,7 +66,7 @@ WeatherProvider.register("ukmetofficedatahub", { // Build the list of headers for the request // For DataHub requests, the API key/secret are sent in the headers rather than as query strings. // Headers defined according to Data Hub API (https://metoffice.apiconnect.ibmcloud.com/metoffice/production/api) - getHeaders() { + getHeaders () { return { accept: "application/json", "x-ibm-client-id": this.config.apiKey, @@ -75,7 +75,7 @@ WeatherProvider.register("ukmetofficedatahub", { }, // Fetch data using supplied URL and request headers - async fetchWeather(url, headers) { + async fetchWeather (url, headers) { const response = await fetch(url, { headers: headers }); // Return JSON data @@ -83,7 +83,7 @@ WeatherProvider.register("ukmetofficedatahub", { }, // Fetch hourly forecast data (to use for current weather) - fetchCurrentWeather() { + fetchCurrentWeather () { this.fetchWeather(this.getUrl("hourly"), this.getHeaders()) .then((data) => { // Check data is usable @@ -111,7 +111,7 @@ WeatherProvider.register("ukmetofficedatahub", { }, // Create a WeatherObject using current weather data (data for the current hour) - generateWeatherObjectFromCurrentWeather(currentWeatherData) { + generateWeatherObjectFromCurrentWeather (currentWeatherData) { const currentWeather = new WeatherObject(); // Extract the actual forecasts @@ -152,7 +152,7 @@ WeatherProvider.register("ukmetofficedatahub", { }, // Fetch daily forecast data - fetchWeatherForecast() { + fetchWeatherForecast () { this.fetchWeather(this.getUrl("daily"), this.getHeaders()) .then((data) => { // Check data is usable @@ -180,7 +180,7 @@ WeatherProvider.register("ukmetofficedatahub", { }, // Create a WeatherObject for each day using daily forecast data - generateWeatherObjectsFromForecast(forecasts) { + generateWeatherObjectsFromForecast (forecasts) { const dailyForecasts = []; // Extract the actual forecasts @@ -225,14 +225,14 @@ WeatherProvider.register("ukmetofficedatahub", { }, // Set the fetched location name. - setFetchedLocation: function (name) { + setFetchedLocation (name) { this.fetchedLocationName = name; }, // Match the Met Office "significant weather code" to a weathericons.css icon // Use: https://metoffice.apiconnect.ibmcloud.com/metoffice/production/node/264 // and: https://erikflowers.github.io/weather-icons/ - convertWeatherType(weatherType) { + convertWeatherType (weatherType) { const weatherTypes = { 0: "night-clear", 1: "day-sunny", diff --git a/modules/default/weather/providers/weatherbit.js b/modules/default/weather/providers/weatherbit.js index 298d23bab2..5bde8003bb 100644 --- a/modules/default/weather/providers/weatherbit.js +++ b/modules/default/weather/providers/weatherbit.js @@ -23,11 +23,11 @@ WeatherProvider.register("weatherbit", { lon: 0 }, - fetchedLocation: function () { + fetchedLocation () { return this.fetchedLocationName || ""; }, - fetchCurrentWeather() { + fetchCurrentWeather () { this.fetchData(this.getUrl()) .then((data) => { if (!data || !data.data[0] || typeof data.data[0].temp === "undefined") { @@ -44,7 +44,7 @@ WeatherProvider.register("weatherbit", { .finally(() => this.updateAvailable()); }, - fetchWeatherForecast() { + fetchWeatherForecast () { this.fetchData(this.getUrl()) .then((data) => { if (!data || !data.data) { @@ -67,7 +67,7 @@ WeatherProvider.register("weatherbit", { * Overrides method for setting config to check if endpoint is correct for hourly * @param {object} config The configuration object */ - setConfig(config) { + setConfig (config) { this.config = config; if (!this.config.weatherEndpoint) { switch (this.config.type) { @@ -88,12 +88,12 @@ WeatherProvider.register("weatherbit", { }, // Create a URL from the config and base URL. - getUrl() { + getUrl () { return `${this.config.apiBase}${this.config.weatherEndpoint}?lat=${this.config.lat}&lon=${this.config.lon}&units=M&key=${this.config.apiKey}`; }, // Implement WeatherDay generator. - generateWeatherDayFromCurrentWeather(currentWeatherData) { + generateWeatherDayFromCurrentWeather (currentWeatherData) { //Calculate TZ Offset and invert to convert Sunrise/Sunset times to Local const d = new Date(); let tzOffset = d.getTimezoneOffset(); @@ -115,7 +115,7 @@ WeatherProvider.register("weatherbit", { return currentWeather; }, - generateWeatherObjectsFromForecast(forecasts) { + generateWeatherObjectsFromForecast (forecasts) { const days = []; for (const forecast of forecasts) { @@ -135,7 +135,7 @@ WeatherProvider.register("weatherbit", { }, // Map icons from Dark Sky to our icons. - convertWeatherType(weatherType) { + convertWeatherType (weatherType) { const weatherTypes = { t01d: "day-thunderstorm", t01n: "night-alt-thunderstorm", diff --git a/modules/default/weather/providers/weatherflow.js b/modules/default/weather/providers/weatherflow.js index aecfb63e41..9e15be82d8 100644 --- a/modules/default/weather/providers/weatherflow.js +++ b/modules/default/weather/providers/weatherflow.js @@ -23,7 +23,7 @@ WeatherProvider.register("weatherflow", { stationid: "" }, - fetchCurrentWeather() { + fetchCurrentWeather () { this.fetchData(this.getUrl()) .then((data) => { const currentWeather = new WeatherObject(); @@ -44,7 +44,7 @@ WeatherProvider.register("weatherflow", { .finally(() => this.updateAvailable()); }, - fetchWeatherForecast() { + fetchWeatherForecast () { this.fetchData(this.getUrl()) .then((data) => { const days = []; @@ -71,7 +71,7 @@ WeatherProvider.register("weatherflow", { }, // Create a URL from the config and base URL. - getUrl() { + getUrl () { return `${this.config.apiBase}better_forecast?station_id=${this.config.stationid}&units_temp=c&units_wind=kph&units_pressure=mb&units_precip=mm&units_distance=km&token=${this.config.token}`; } }); diff --git a/modules/default/weather/providers/weathergov.js b/modules/default/weather/providers/weathergov.js index 8111044be4..f66101468b 100644 --- a/modules/default/weather/providers/weathergov.js +++ b/modules/default/weather/providers/weathergov.js @@ -37,24 +37,24 @@ WeatherProvider.register("weathergov", { stationObsURL: "tbd", // Called to set the config, this config is the same as the weather module's config. - setConfig: function (config) { + setConfig (config) { this.config = config; this.config.apiBase = "https://api.weather.gov"; this.fetchWxGovURLs(this.config); }, // Called when the weather provider is about to start. - start: function () { + start () { Log.info(`Weather provider: ${this.providerName} started.`); }, // This returns the name of the fetched location or an empty string. - fetchedLocation: function () { + fetchedLocation () { return this.fetchedLocationName || ""; }, // Overwrite the fetchCurrentWeather method. - fetchCurrentWeather() { + fetchCurrentWeather () { if (!this.configURLs) { Log.info("fetchCurrentWeather: fetch wx waiting on config URLs"); return; @@ -75,7 +75,7 @@ WeatherProvider.register("weathergov", { }, // Overwrite the fetchWeatherForecast method. - fetchWeatherForecast() { + fetchWeatherForecast () { if (!this.configURLs) { Log.info("fetchWeatherForecast: fetch wx waiting on config URLs"); return; @@ -96,7 +96,7 @@ WeatherProvider.register("weathergov", { }, // Overwrite the fetchWeatherHourly method. - fetchWeatherHourly() { + fetchWeatherHourly () { if (!this.configURLs) { Log.info("fetchWeatherHourly: fetch wx waiting on config URLs"); return; @@ -122,7 +122,7 @@ WeatherProvider.register("weathergov", { /* * Get specific URLs */ - fetchWxGovURLs(config) { + fetchWxGovURLs (config) { this.fetchData(`${config.apiBase}/points/${config.lat},${config.lon}`) .then((data) => { if (!data || !data.properties) { @@ -162,12 +162,13 @@ WeatherProvider.register("weathergov", { } }); }, + /* * Generate a WeatherObject based on hourlyWeatherInformation * Weather.gov API uses specific units; API does not include choice of units * ... object needs data in units based on config! */ - generateWeatherObjectsFromHourly(forecasts) { + generateWeatherObjectsFromHourly (forecasts) { const days = []; // variable for date @@ -206,7 +207,7 @@ WeatherProvider.register("weathergov", { * Weather.gov API uses specific units; API does not include choice of units * ... object needs data in units based on config! */ - generateWeatherObjectFromCurrentWeather(currentWeatherData) { + generateWeatherObjectFromCurrentWeather (currentWeatherData) { const currentWeather = new WeatherObject(); currentWeather.date = moment(currentWeatherData.timestamp); @@ -236,14 +237,14 @@ WeatherProvider.register("weathergov", { /* * Generate WeatherObjects based on forecast information */ - generateWeatherObjectsFromForecast(forecasts) { + generateWeatherObjectsFromForecast (forecasts) { return this.fetchForecastDaily(forecasts); }, /* * fetch forecast information for daily forecast. */ - fetchForecastDaily(forecasts) { + fetchForecastDaily (forecasts) { // initial variable declaration const days = []; // variables for temperature range and rain @@ -306,7 +307,7 @@ WeatherProvider.register("weathergov", { /* * Convert the icons to a more usable name. */ - convertWeatherType(weatherType, isDaytime) { + convertWeatherType (weatherType, isDaytime) { //https://w1.weather.gov/xml/current_obs/weather.php // There are way too many types to create, so lets just look for certain strings diff --git a/modules/default/weather/providers/yr.js b/modules/default/weather/providers/yr.js index be876a6dc8..0c6701bfab 100644 --- a/modules/default/weather/providers/yr.js +++ b/modules/default/weather/providers/yr.js @@ -18,11 +18,13 @@ WeatherProvider.register("yr", { defaults: { useCorsProxy: true, apiBase: "https://api.met.no/weatherapi", + forecastApiVersion: "2.0", + sunriseApiVersion: "3.0", altitude: 0, currentForecastHours: 1 //1, 6 or 12 }, - start() { + start () { if (typeof Storage === "undefined") { //local storage unavailable Log.error("The Yr weather provider requires local storage."); @@ -31,7 +33,7 @@ WeatherProvider.register("yr", { Log.info(`Weather provider: ${this.providerName} started.`); }, - fetchCurrentWeather() { + fetchCurrentWeather () { this.getCurrentWeather() .then((currentWeather) => { this.setCurrentWeather(currentWeather); @@ -43,9 +45,8 @@ WeatherProvider.register("yr", { }); }, - async getCurrentWeather() { - const getRequests = [this.getWeatherData(), this.getStellarData()]; - const [weatherData, stellarData] = await Promise.all(getRequests); + async getCurrentWeather () { + const [weatherData, stellarData] = await Promise.all([this.getWeatherData(), this.getStellarData()]); if (!stellarData) { Log.warn("No stellar data available."); } @@ -72,7 +73,7 @@ WeatherProvider.register("yr", { return this.getWeatherDataFrom(forecast, stellarData, weatherData.properties.meta.units); }, - getWeatherData() { + getWeatherData () { return new Promise((resolve, reject) => { // If a user has several Yr-modules, for instance one current and one forecast, the API calls must be synchronized across classes. // This is to avoid multiple similar calls to the API. @@ -98,7 +99,7 @@ WeatherProvider.register("yr", { }); }, - getWeatherDataFromYrOrCache(resolve, reject) { + getWeatherDataFromYrOrCache (resolve, reject) { localStorage.setItem("yrIsFetchingWeatherData", "true"); let weatherData = this.getWeatherDataFromCache(); @@ -130,16 +131,16 @@ WeatherProvider.register("yr", { } }, - weatherDataIsValid(weatherData) { + weatherDataIsValid (weatherData) { return ( - weatherData && - weatherData.timeout && - 0 < moment(weatherData.timeout).diff(moment()) && - (!weatherData.geometry || !weatherData.geometry.coordinates || !weatherData.geometry.coordinates.length < 2 || (weatherData.geometry.coordinates[0] === this.config.lat && weatherData.geometry.coordinates[1] === this.config.lon)) + weatherData + && weatherData.timeout + && 0 < moment(weatherData.timeout).diff(moment()) + && (!weatherData.geometry || !weatherData.geometry.coordinates || !weatherData.geometry.coordinates.length < 2 || (weatherData.geometry.coordinates[0] === this.config.lat && weatherData.geometry.coordinates[1] === this.config.lon)) ); }, - getWeatherDataFromCache() { + getWeatherDataFromCache () { const weatherData = localStorage.getItem("weatherData"); if (weatherData) { return JSON.parse(weatherData); @@ -148,7 +149,7 @@ WeatherProvider.register("yr", { } }, - getWeatherDataFromYr(currentDataFetchedAt) { + getWeatherDataFromYr (currentDataFetchedAt) { const requestHeaders = [{ name: "Accept", value: "application/json" }]; if (currentDataFetchedAt) { requestHeaders.push({ name: "If-Modified-Since", value: currentDataFetchedAt }); @@ -170,7 +171,7 @@ WeatherProvider.register("yr", { }); }, - getForecastUrl() { + getConfigOptions () { if (!this.config.lat) { Log.error("Latitude not provided."); throw new Error("Latitude not provided."); @@ -183,6 +184,11 @@ WeatherProvider.register("yr", { let lat = this.config.lat.toString(); let lon = this.config.lon.toString(); const altitude = this.config.altitude ?? 0; + return { lat, lon, altitude }; + }, + + getForecastUrl () { + let { lat, lon, altitude } = this.getConfigOptions(); if (lat.includes(".") && lat.split(".")[1].length > 4) { Log.warn("Latitude is too specific for weather data. Do not use more than four decimals. Trimming to maximum length."); @@ -195,19 +201,14 @@ WeatherProvider.register("yr", { lon = `${lonParts[0]}.${lonParts[1].substring(0, 4)}`; } - return `${this.config.apiBase}/locationforecast/2.0/complete?&altitude=${altitude}&lat=${lat}&lon=${lon}`; + return `${this.config.apiBase}/locationforecast/${this.config.forecastApiVersion}/complete?&altitude=${altitude}&lat=${lat}&lon=${lon}`; }, - cacheWeatherData(weatherData) { + cacheWeatherData (weatherData) { localStorage.setItem("weatherData", JSON.stringify(weatherData)); }, - getAuthenticationString() { - if (!this.config.authenticationEmail) throw new Error("Authentication email not provided."); - return `${this.config.applicaitionName} ${this.config.authenticationEmail}`; - }, - - getStellarData() { + getStellarData () { // If a user has several Yr-modules, for instance one current and one forecast, the API calls must be synchronized across classes. // This is to avoid multiple similar calls to the API. return new Promise((resolve, reject) => { @@ -233,7 +234,7 @@ WeatherProvider.register("yr", { }); }, - getStellarDataFromYrOrCache(resolve, reject) { + getStellarDataFromYrOrCache (resolve, reject) { localStorage.setItem("yrIsFetchingStellarData", "true"); let stellarData = this.getStellarDataFromCache(); @@ -291,7 +292,7 @@ WeatherProvider.register("yr", { } }, - getStellarDataFromCache() { + getStellarDataFromCache () { const stellarData = localStorage.getItem("stellarData"); if (stellarData) { return JSON.parse(stellarData); @@ -300,9 +301,9 @@ WeatherProvider.register("yr", { } }, - getStellarDataFromYr(date, days = 1) { + getStellarDataFromYr (date, days = 1) { const requestHeaders = [{ name: "Accept", value: "application/json" }]; - return this.fetchData(this.getStellarDatatUrl(date, days), "json", requestHeaders) + return this.fetchData(this.getStellarDataUrl(date, days), "json", requestHeaders) .then((data) => { Log.debug("Got stellar data from yr."); return data; @@ -313,19 +314,8 @@ WeatherProvider.register("yr", { }); }, - getStellarDatatUrl(date, days) { - if (!this.config.lat) { - Log.error("Latitude not provided."); - throw new Error("Latitude not provided."); - } - if (!this.config.lon) { - Log.error("Longitude not provided."); - throw new Error("Longitude not provided."); - } - - let lat = this.config.lat.toString(); - let lon = this.config.lon.toString(); - const altitude = this.config.altitude ?? 0; + getStellarDataUrl (date, days) { + let { lat, lon, altitude } = this.getConfigOptions(); if (lat.includes(".") && lat.split(".")[1].length > 4) { Log.warn("Latitude is too specific for stellar data. Do not use more than four decimals. Trimming to maximum length."); @@ -352,14 +342,14 @@ WeatherProvider.register("yr", { if (hours.length < 2) { hours = `0${hours}`; } - return `${this.config.apiBase}/sunrise/2.3/sun?lat=${lat}&lon=${lon}&date=${date}&offset=${utcOffsetPrefix}${hours}%3A${minutes}`; + return `${this.config.apiBase}/sunrise/${this.config.sunriseApiVersion}/sun?lat=${lat}&lon=${lon}&date=${date}&offset=${utcOffsetPrefix}${hours}%3A${minutes}`; }, - cacheStellarData(data) { + cacheStellarData (data) { localStorage.setItem("stellarData", JSON.stringify(data)); }, - getWeatherDataFrom(forecast, stellarData, units) { + getWeatherDataFrom (forecast, stellarData, units) { const weather = new WeatherObject(); weather.date = moment(forecast.time); @@ -380,7 +370,7 @@ WeatherProvider.register("yr", { return weather; }, - convertWeatherType(weatherType, weatherTime) { + convertWeatherType (weatherType, weatherTime) { const weatherHour = moment(weatherTime).format("HH"); const weatherTypes = { @@ -472,16 +462,7 @@ WeatherProvider.register("yr", { return weatherTypes.hasOwnProperty(weatherType) ? weatherTypes[weatherType] : null; }, - getStellarTimesFrom(stellarData, date) { - for (const time of stellarData.location.time) { - if (time.date === date) { - return time; - } - } - return undefined; - }, - - getForecastForXHoursFrom(weather) { + getForecastForXHoursFrom (weather) { if (this.config.currentForecastHours === 1) { if (weather.next_1_hours) { return weather.next_1_hours; @@ -509,7 +490,7 @@ WeatherProvider.register("yr", { } }, - fetchWeatherHourly() { + fetchWeatherHourly () { this.getWeatherForecast("hourly") .then((forecast) => { this.setWeatherHourly(forecast); @@ -521,9 +502,8 @@ WeatherProvider.register("yr", { }); }, - async getWeatherForecast(type) { - const getRequests = [this.getWeatherData(), this.getStellarData()]; - const [weatherData, stellarData] = await Promise.all(getRequests); + async getWeatherForecast (type) { + const [weatherData, stellarData] = await Promise.all([this.getWeatherData(), this.getStellarData()]); if (!weatherData.properties.timeseries || !weatherData.properties.timeseries[0]) { Log.error("No weather data available."); return; @@ -548,7 +528,7 @@ WeatherProvider.register("yr", { return series; }, - getHourlyForecastFrom(weatherData) { + getHourlyForecastFrom (weatherData) { const series = []; for (const forecast of weatherData.properties.timeseries) { @@ -563,7 +543,7 @@ WeatherProvider.register("yr", { return series; }, - getDailyForecastFrom(weatherData) { + getDailyForecastFrom (weatherData) { const series = []; const days = weatherData.properties.timeseries.reduce(function (days, forecast) { @@ -573,7 +553,7 @@ WeatherProvider.register("yr", { return days; }, Object.create(null)); - Object.keys(days).forEach(function (time, index) { + Object.keys(days).forEach(function (time) { let minTemperature = undefined; let maxTemperature = undefined; @@ -613,7 +593,7 @@ WeatherProvider.register("yr", { return series; }, - fetchWeatherForecast() { + fetchWeatherForecast () { this.getWeatherForecast("daily") .then((forecast) => { this.setWeatherForecast(forecast); diff --git a/modules/default/weather/weather.js b/modules/default/weather/weather.js index 57c91d7b07..15e6cfc51b 100644 --- a/modules/default/weather/weather.js +++ b/modules/default/weather/weather.js @@ -56,17 +56,17 @@ Module.register("weather", { firstEvent: null, // Define required scripts. - getStyles: function () { + getStyles () { return ["font-awesome.css", "weather-icons.css", "weather.css"]; }, // Return the scripts that are necessary for the weather module. - getScripts: function () { + getScripts () { return ["moment.js", "weatherutils.js", "weatherobject.js", this.file("providers/overrideWrapper.js"), "weatherprovider.js", "suncalc.js", this.file(`providers/${this.config.weatherProvider.toLowerCase()}.js`)]; }, // Override getHeader method. - getHeader: function () { + getHeader () { if (this.config.appendLocationNameToHeader && this.weatherProvider) { if (this.data.header) return `${this.data.header} ${this.weatherProvider.fetchedLocation()}`; else return this.weatherProvider.fetchedLocation(); @@ -76,7 +76,7 @@ Module.register("weather", { }, // Start the weather module. - start: function () { + start () { moment.locale(this.config.lang); if (this.config.useKmh) { @@ -101,7 +101,7 @@ Module.register("weather", { }, // Override notification handler. - notificationReceived: function (notification, payload, sender) { + notificationReceived (notification, payload, sender) { if (notification === "CALENDAR_EVENTS") { const senderClasses = sender.data.classes.toLowerCase().split(" "); if (senderClasses.indexOf(this.config.calendarClass.toLowerCase()) !== -1) { @@ -126,7 +126,7 @@ Module.register("weather", { }, // Select the template depending on the display type. - getTemplate: function () { + getTemplate () { switch (this.config.type.toLowerCase()) { case "current": return "current.njk"; @@ -142,7 +142,7 @@ Module.register("weather", { }, // Add all the data to the template. - getTemplateData: function () { + getTemplateData () { const currentData = this.weatherProvider.currentWeather(); const forecastData = this.weatherProvider.weatherForecast(); @@ -162,7 +162,7 @@ Module.register("weather", { }, // What to do when the weather provider has new information available? - updateAvailable: function () { + updateAvailable () { Log.log("New weather information available."); this.updateDom(0); this.scheduleUpdate(); @@ -181,7 +181,7 @@ Module.register("weather", { this.sendNotification("WEATHER_UPDATED", notificationPayload); }, - scheduleUpdate: function (delay = null) { + scheduleUpdate (delay = null) { let nextLoad = this.config.updateInterval; if (delay !== null && delay >= 0) { nextLoad = delay; @@ -205,13 +205,13 @@ Module.register("weather", { }, nextLoad); }, - roundValue: function (temperature) { + roundValue (temperature) { const decimals = this.config.roundTemp ? 0 : 1; const roundValue = parseFloat(temperature).toFixed(decimals); return roundValue === "-0" ? 0 : roundValue; }, - addFilters() { + addFilters () { this.nunjucksEnvironment().addFilter( "formatTime", function (date) { diff --git a/modules/default/weather/weatherobject.js b/modules/default/weather/weatherobject.js index 9fae88737c..33c9e669bf 100644 --- a/modules/default/weather/weatherobject.js +++ b/modules/default/weather/weatherobject.js @@ -16,10 +16,11 @@ * @external Moment */ class WeatherObject { + /** * Constructor for a WeatherObject */ - constructor() { + constructor () { this.date = null; this.windSpeed = null; this.windFromDirection = null; @@ -36,7 +37,7 @@ class WeatherObject { this.feelsLikeTemp = null; } - cardinalWindDirection() { + cardinalWindDirection () { if (this.windFromDirection > 11.25 && this.windFromDirection <= 33.75) { return "NNE"; } else if (this.windFromDirection > 33.75 && this.windFromDirection <= 56.25) { @@ -79,11 +80,11 @@ class WeatherObject { * action for. Useful only in tests, defaults to the current time. * @returns {string} "sunset" or "sunrise" */ - nextSunAction(date = moment()) { + nextSunAction (date = moment()) { return date.isBetween(this.sunrise, this.sunset) ? "sunset" : "sunrise"; } - feelsLike() { + feelsLike () { if (this.feelsLikeTemp) { return this.feelsLikeTemp; } @@ -94,7 +95,7 @@ class WeatherObject { * Checks if the weatherObject is at dayTime. * @returns {boolean} true if it is at dayTime */ - isDayTime() { + isDayTime () { const now = !this.date ? moment() : this.date; return now.isBetween(this.sunrise, this.sunset, undefined, "[]"); } @@ -106,7 +107,7 @@ class WeatherObject { * @param {number} lat latitude * @param {number} lon longitude */ - updateSunTime(lat, lon) { + updateSunTime (lat, lon) { const now = !this.date ? new Date() : this.date.toDate(); const times = SunCalc.getTimes(now, lat, lon); this.sunrise = moment(times.sunrise); @@ -120,7 +121,7 @@ class WeatherObject { * Especially 'moment' object is not immutable, so original 'date', 'sunrise', 'sunset' could be corrupted or changed by other modules. * @returns {object} plained object clone of original weatherObject */ - simpleClone() { + simpleClone () { const toFlat = ["date", "sunrise", "sunset"]; let clone = { ...this }; for (const prop of toFlat) { diff --git a/modules/default/weather/weatherprovider.js b/modules/default/weather/weatherprovider.js index d3bdb78d69..b85e1a9924 100644 --- a/modules/default/weather/weatherprovider.js +++ b/modules/default/weather/weatherprovider.js @@ -30,84 +30,84 @@ const WeatherProvider = Class.extend({ // All the following methods can be overwritten, although most are good as they are. // Called when a weather provider is initialized. - init: function (config) { + init (config) { this.config = config; Log.info(`Weather provider: ${this.providerName} initialized.`); }, // Called to set the config, this config is the same as the weather module's config. - setConfig: function (config) { + setConfig (config) { this.config = config; Log.info(`Weather provider: ${this.providerName} config set.`, this.config); }, // Called when the weather provider is about to start. - start: function () { + start () { Log.info(`Weather provider: ${this.providerName} started.`); }, // This method should start the API request to fetch the current weather. // This method should definitely be overwritten in the provider. - fetchCurrentWeather: function () { + fetchCurrentWeather () { Log.warn(`Weather provider: ${this.providerName} does not subclass the fetchCurrentWeather method.`); }, // This method should start the API request to fetch the weather forecast. // This method should definitely be overwritten in the provider. - fetchWeatherForecast: function () { + fetchWeatherForecast () { Log.warn(`Weather provider: ${this.providerName} does not subclass the fetchWeatherForecast method.`); }, // This method should start the API request to fetch the weather hourly. // This method should definitely be overwritten in the provider. - fetchWeatherHourly: function () { + fetchWeatherHourly () { Log.warn(`Weather provider: ${this.providerName} does not subclass the fetchWeatherHourly method.`); }, // This returns a WeatherDay object for the current weather. - currentWeather: function () { + currentWeather () { return this.currentWeatherObject; }, // This returns an array of WeatherDay objects for the weather forecast. - weatherForecast: function () { + weatherForecast () { return this.weatherForecastArray; }, // This returns an object containing WeatherDay object(s) depending on the type of call. - weatherHourly: function () { + weatherHourly () { return this.weatherHourlyArray; }, // This returns the name of the fetched location or an empty string. - fetchedLocation: function () { + fetchedLocation () { return this.fetchedLocationName || ""; }, // Set the currentWeather and notify the delegate that new information is available. - setCurrentWeather: function (currentWeatherObject) { + setCurrentWeather (currentWeatherObject) { // We should check here if we are passing a WeatherDay this.currentWeatherObject = currentWeatherObject; }, // Set the weatherForecastArray and notify the delegate that new information is available. - setWeatherForecast: function (weatherForecastArray) { + setWeatherForecast (weatherForecastArray) { // We should check here if we are passing a WeatherDay this.weatherForecastArray = weatherForecastArray; }, // Set the weatherHourlyArray and notify the delegate that new information is available. - setWeatherHourly: function (weatherHourlyArray) { + setWeatherHourly (weatherHourlyArray) { this.weatherHourlyArray = weatherHourlyArray; }, // Set the fetched location name. - setFetchedLocation: function (name) { + setFetchedLocation (name) { this.fetchedLocationName = name; }, // Notify the delegate that new weather is available. - updateAvailable: function () { + updateAvailable () { this.delegate.updateAvailable(this); }, @@ -119,7 +119,7 @@ const WeatherProvider = Class.extend({ * @param {Array.} expectedResponseHeaders the expected HTTP headers to recieve * @returns {Promise} resolved when the fetch is done */ - fetchData: async function (url, type = "json", requestHeaders = undefined, expectedResponseHeaders = undefined) { + async fetchData (url, type = "json", requestHeaders = undefined, expectedResponseHeaders = undefined) { const mockData = this.config.mockData; if (mockData) { const data = mockData.substring(1, mockData.length - 1); diff --git a/modules/default/weather/weatherutils.js b/modules/default/weather/weatherutils.js index 47fea3355d..e0c5709e0f 100644 --- a/modules/default/weather/weatherutils.js +++ b/modules/default/weather/weatherutils.js @@ -5,12 +5,13 @@ * MIT Licensed. */ const WeatherUtils = { + /** * Convert wind (from m/s) to beaufort scale * @param {number} speedInMS the windspeed you want to convert * @returns {number} the speed in beaufort */ - beaufortWindSpeed(speedInMS) { + beaufortWindSpeed (speedInMS) { const windInKmh = this.convertWind(speedInMS, "kmh"); const speeds = [1, 5, 11, 19, 28, 38, 49, 61, 74, 88, 102, 117, 1000]; for (const [index, speed] of speeds.entries()) { @@ -29,7 +30,7 @@ const WeatherUtils = { * @param {string} outputUnit - The unit system (imperial/metric) the return value should have. * @returns {string} - A string with tha value and a unit postfix. */ - convertPrecipitationUnit(value, valueUnit, outputUnit) { + convertPrecipitationUnit (value, valueUnit, outputUnit) { if (valueUnit === "%") return `${value.toFixed(0)} ${valueUnit}`; let convertedValue = value; @@ -52,7 +53,7 @@ const WeatherUtils = { * @param {string} unit can be 'imperial' or 'metric' * @returns {number} the converted temperature */ - convertTemp(tempInC, unit) { + convertTemp (tempInC, unit) { return unit === "imperial" ? tempInC * 1.8 + 32 : tempInC; }, @@ -63,7 +64,7 @@ const WeatherUtils = { * or 'metric' (mps) * @returns {number} the converted windspeed */ - convertWind(windInMS, unit) { + convertWind (windInMS, unit) { switch (unit) { case "beaufort": return this.beaufortWindSpeed(windInMS); @@ -82,7 +83,7 @@ const WeatherUtils = { /* * Convert the wind direction cardinal to value */ - convertWindDirection(windDirection) { + convertWindDirection (windDirection) { const windCardinals = { N: 0, NNE: 22, @@ -105,15 +106,15 @@ const WeatherUtils = { return windCardinals.hasOwnProperty(windDirection) ? windCardinals[windDirection] : null; }, - convertWindToMetric(mph) { + convertWindToMetric (mph) { return mph / 2.2369362920544; }, - convertWindToMs(kmh) { + convertWindToMs (kmh) { return kmh * 0.27777777777778; }, - calculateFeelsLike(temperature, windSpeed, humidity) { + calculateFeelsLike (temperature, windSpeed, humidity) { const windInMph = this.convertWind(windSpeed, "imperial"); const tempInF = this.convertTemp(temperature, "imperial"); let feelsLike = tempInF; @@ -121,16 +122,16 @@ const WeatherUtils = { if (windInMph > 3 && tempInF < 50) { feelsLike = Math.round(35.74 + 0.6215 * tempInF - 35.75 * Math.pow(windInMph, 0.16) + 0.4275 * tempInF * Math.pow(windInMph, 0.16)); } else if (tempInF > 80 && humidity > 40) { - feelsLike = - -42.379 + - 2.04901523 * tempInF + - 10.14333127 * humidity - - 0.22475541 * tempInF * humidity - - 6.83783 * Math.pow(10, -3) * tempInF * tempInF - - 5.481717 * Math.pow(10, -2) * humidity * humidity + - 1.22874 * Math.pow(10, -3) * tempInF * tempInF * humidity + - 8.5282 * Math.pow(10, -4) * tempInF * humidity * humidity - - 1.99 * Math.pow(10, -6) * tempInF * tempInF * humidity * humidity; + feelsLike + = -42.379 + + 2.04901523 * tempInF + + 10.14333127 * humidity + - 0.22475541 * tempInF * humidity + - 6.83783 * Math.pow(10, -3) * tempInF * tempInF + - 5.481717 * Math.pow(10, -2) * humidity * humidity + + 1.22874 * Math.pow(10, -3) * tempInF * tempInF * humidity + + 8.5282 * Math.pow(10, -4) * tempInF * humidity * humidity + - 1.99 * Math.pow(10, -6) * tempInF * tempInF * humidity * humidity; } return ((feelsLike - 32) * 5) / 9; diff --git a/package-lock.json b/package-lock.json index d9ca3b28bf..4d56f2d023 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,56 +1,55 @@ { "name": "magicmirror", - "version": "2.25.0", + "version": "2.26.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "magicmirror", - "version": "2.25.0", + "version": "2.26.0", "hasInstallScript": true, "license": "MIT", "dependencies": { "colors": "^1.4.0", + "command-exists": "^1.2.9", "console-stamp": "^3.1.2", "envsub": "^4.1.0", - "eslint": "^8.50.0", + "eslint": "^8.56.0", "express": "^4.18.2", "express-ipfilter": "^1.3.1", "feedme": "^2.0.2", - "helmet": "^7.0.0", + "helmet": "^7.1.0", "html-to-text": "^9.0.5", "iconv-lite": "^0.6.3", - "luxon": "^1.28.1", "module-alias": "^2.2.3", - "moment": "^2.29.4", - "node-ical": "^0.16.1", + "moment": "^2.30.1", + "node-ical": "^0.17.1", "socket.io": "^4.7.2" }, "devDependencies": { - "eslint-config-prettier": "^9.0.0", - "eslint-plugin-import": "^2.28.1", - "eslint-plugin-jest": "^27.4.2", - "eslint-plugin-jsdoc": "^46.8.2", - "eslint-plugin-prettier": "^5.0.0", + "@stylistic/eslint-plugin": "^1.5.1", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jest": "^27.6.0", + "eslint-plugin-jsdoc": "^46.9.1", "express-basic-auth": "^1.2.1", "husky": "^8.0.3", "jest": "^29.7.0", - "jsdom": "^22.1.0", - "lint-staged": "^14.0.1", + "jsdom": "^23.0.1", + "lint-staged": "^15.2.0", "lodash": "^4.17.21", - "playwright": "^1.38.1", - "prettier": "^3.0.3", - "sinon": "^16.0.0", - "stylelint": "^15.10.3", - "stylelint-config-standard": "^34.0.0", - "stylelint-prettier": "^4.0.2", + "playwright": "^1.40.1", + "prettier": "^3.1.1", + "sinon": "^17.0.1", + "stylelint": "^16.1.0", + "stylelint-config-standard": "^36.0.0", + "stylelint-prettier": "^5.0.0", "suncalc": "^1.9.0" }, "engines": { "node": ">=18" }, "optionalDependencies": { - "electron": "^26.2.4" + "electron": "^27.2.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -75,12 +74,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.13", + "@babel/highlight": "^7.23.4", "chalk": "^2.4.2" }, "engines": { @@ -159,30 +158,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.20.tgz", - "integrity": "sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.0.tgz", - "integrity": "sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.6.tgz", + "integrity": "sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.0", - "@babel/helpers": "^7.23.0", - "@babel/parser": "^7.23.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.6", + "@babel/parser": "^7.23.6", "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.0", - "@babel/types": "^7.23.0", + "@babel/traverse": "^7.23.6", + "@babel/types": "^7.23.6", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -197,13 +196,22 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dev": true, "dependencies": { - "@babel/types": "^7.23.0", + "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -213,14 +221,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -228,6 +236,15 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/helper-environment-visitor": { "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", @@ -275,9 +292,9 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", - "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", @@ -327,9 +344,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", "dev": true, "engines": { "node": ">=6.9.0" @@ -345,32 +362,32 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.23.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.1.tgz", - "integrity": "sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.6.tgz", + "integrity": "sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==", "dev": true, "dependencies": { "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.0", - "@babel/types": "^7.23.0" + "@babel/traverse": "^7.23.6", + "@babel/types": "^7.23.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", @@ -453,9 +470,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -525,9 +542,9 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", - "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -627,9 +644,9 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", - "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", + "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -656,20 +673,20 @@ } }, "node_modules/@babel/traverse": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz", - "integrity": "sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", + "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -686,12 +703,12 @@ } }, "node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-string-parser": "^7.23.4", "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, @@ -706,9 +723,9 @@ "dev": true }, "node_modules/@csstools/css-parser-algorithms": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.3.2.tgz", - "integrity": "sha512-sLYGdAdEY2x7TSw9FtmdaTrh2wFtRJO5VMbBrA8tEqEod7GEggFmxTSK9XqExib3yMuYNcvcTdCZIP6ukdjAIA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.4.0.tgz", + "integrity": "sha512-/PPLr2g5PAUCKAPEbfyk6/baZA+WJHQtUhPkoCQMpyRE8I0lXrG1QFRN8e5s3ZYxM8d/g5BZc6lH3s8Op7/VEg==", "dev": true, "funding": [ { @@ -724,13 +741,13 @@ "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "@csstools/css-tokenizer": "^2.2.1" + "@csstools/css-tokenizer": "^2.2.2" } }, "node_modules/@csstools/css-tokenizer": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.2.1.tgz", - "integrity": "sha512-Zmsf2f/CaEPWEVgw29odOj+WEVoiJy9s9NOv5GgNY9mZ1CZ7394By6wONrONrTsnNDv6F9hR02nvFihrGVGHBg==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.2.2.tgz", + "integrity": "sha512-wCDUe/MAw7npAHFLyW3QjSyLA66S5QFaV1jIXlNQvdJ8RzXDSgALa49eWcUO6P55ARQaz0TsDdAgdRgkXFYY8g==", "dev": true, "funding": [ { @@ -747,9 +764,9 @@ } }, "node_modules/@csstools/media-query-list-parser": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.5.tgz", - "integrity": "sha512-IxVBdYzR8pYe89JiyXQuYk4aVVoCPhMJkz6ElRwlVysjwURTsTk/bmY/z4FfeRE+CRBMlykPwXEVUg8lThv7AQ==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.6.tgz", + "integrity": "sha512-R6AKl9vaU0It7D7TR2lQn0pre5aQfdeqHRePlaRCY8rHL3l9eVlNRpsEVDKFi/zAjzv68CxH2M5kqbhPFPKjvw==", "dev": true, "funding": [ { @@ -765,14 +782,14 @@ "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^2.3.2", - "@csstools/css-tokenizer": "^2.2.1" + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2" } }, "node_modules/@csstools/selector-specificity": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.0.tgz", - "integrity": "sha512-hBI9tfBtuPIi885ZsZ32IMEU/5nlZH/KOVYJCOh7gyMxaVLGmLedYqFN6Ui1LXkI8JlC8IsuC0rF0btcRZKd5g==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.1.tgz", + "integrity": "sha512-NPljRHkq4a14YzZ3YD406uaxh7s0g6eAq3L9aLOWywoqe8PkYamAvtsh7KNX6c++ihDrJ0RiU+/z7rGnhlZ5ww==", "dev": true, "funding": [ { @@ -812,13 +829,22 @@ "global-agent": "^3.0.0" } }, + "node_modules/@electron/get/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "optional": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.40.1", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.40.1.tgz", - "integrity": "sha512-YORCdZSusAlBrFpZ77pJjc5r1bQs5caPWtAu+WWmiSo+8XaUzseapVrfAtiRFbQWnrBxxLLEwF6f6ZG/UgCQCg==", + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz", + "integrity": "sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==", "dev": true, "dependencies": { - "comment-parser": "1.4.0", + "comment-parser": "1.4.1", "esquery": "^1.5.0", "jsdoc-type-pratt-parser": "~4.0.0" }, @@ -841,17 +867,17 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.0.tgz", - "integrity": "sha512-zJmuCWj2VLBt4c25CfBIbMZLGLyhkvs7LznyVX5HfpzeocThgIj5XQK4L+g3U36mMcx8bPMhGyPpwCATamC4jQ==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -870,20 +896,40 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/js": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz", - "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", - "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" }, @@ -891,6 +937,26 @@ "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -904,9 +970,105 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==" + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -1339,9 +1501,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1380,32 +1542,16 @@ "node": ">= 8" } }, - "node_modules/@pkgr/utils": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", - "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "fast-glob": "^3.3.0", - "is-glob": "^4.0.3", - "open": "^9.1.0", - "picocolors": "^1.0.0", - "tslib": "^2.6.0" - }, + "optional": true, "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" + "node": ">=14" } }, - "node_modules/@pkgr/utils/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, "node_modules/@selderee/plugin-htmlparser2": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz", @@ -1485,6 +1631,86 @@ "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" }, + "node_modules/@stylistic/eslint-plugin": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-1.5.1.tgz", + "integrity": "sha512-y7ynUMh5Hq1MhYApAccl1iuQem5Sf2JSEIjV/qsBfmW1WfRDs74V+0kLkcOn1Y600W3t8orIFrrEuWmJSetAgw==", + "dev": true, + "dependencies": { + "@stylistic/eslint-plugin-js": "1.5.1", + "@stylistic/eslint-plugin-jsx": "1.5.1", + "@stylistic/eslint-plugin-plus": "1.5.1", + "@stylistic/eslint-plugin-ts": "1.5.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.5.1.tgz", + "integrity": "sha512-iZF0rF+uOhAmOJYOJx1Yvmm3CZ1uz9n0SRd9dpBYHA3QAvfABUORh9LADWwZCigjHJkp2QbCZelGFJGwGz7Siw==", + "dev": true, + "dependencies": { + "acorn": "^8.11.2", + "escape-string-regexp": "^4.0.0", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-1.5.1.tgz", + "integrity": "sha512-JuX+jsbVdpZ6EZXkbxYr9ERcGc0ndSMFgOuwEPHhOWPZ+7F8JP/nzpBjrRf7dUPMX7ezTYLZ2a3KRGRNme6rWQ==", + "dev": true, + "dependencies": { + "@stylistic/eslint-plugin-js": "^1.5.1", + "estraverse": "^5.3.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-plus": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-1.5.1.tgz", + "integrity": "sha512-yxkFHsUgoqEf/j1Og0FGkpEmeQoqx0CMmtgoyZGr34hka0ElCy9fRpsFkLcwx60SfiHXspbvs2YUMXiWIffnjg==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "^6.13.2" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@stylistic/eslint-plugin-ts": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-1.5.1.tgz", + "integrity": "sha512-oXM1V7Jp8G9+udxQTy+Igo79LR2e5HXiWqlA/3v+/PAqWxniR9nJqJSBjtQKJTPsGplDqn/ASpHUOETP4EI/4A==", + "dev": true, + "dependencies": { + "@stylistic/eslint-plugin-js": "1.5.1", + "@typescript-eslint/utils": "^6.13.2" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, "node_modules/@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -1497,19 +1723,10 @@ "node": ">=10" } }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, "node_modules/@types/babel__core": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz", - "integrity": "sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, "dependencies": { "@babel/parser": "^7.20.7", @@ -1520,18 +1737,18 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.5.tgz", - "integrity": "sha512-h9yIuWbJKdOPLJTbmSpPzkF67e659PbQDba7ifWm5BJ8xTv+sDmS7rFmywkWOvXedGTivCdeGSIIX8WLcRTz8w==", + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", "dev": true, "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.2.tgz", - "integrity": "sha512-/AVzPICMhMOMYoSx9MoKpGDKdBRsIXMNByh1PXSZoa+v6ZoLa8xxtsT/uLQ/NJm0XVAWl/BvId4MlDeXJaeIZQ==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, "dependencies": { "@babel/parser": "^7.1.0", @@ -1539,9 +1756,9 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.2.tgz", - "integrity": "sha512-ojlGK1Hsfce93J0+kn3H5R73elidKUaZonirN33GSmgTUMpzI/MIFfSpF3haANe3G1bEBS9/9/QEqwTzwqFsKw==", + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", "dev": true, "dependencies": { "@babel/types": "^7.20.7" @@ -1565,56 +1782,56 @@ "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" }, "node_modules/@types/cors": { - "version": "2.8.14", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.14.tgz", - "integrity": "sha512-RXHUvNWYICtbP6s18PnOCaqToK8y14DnLd75c6HfyKf228dxy7pHNOQkxPtvXKp/hINFMDjbYzsj63nnpPMSRQ==", + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", "dependencies": { "@types/node": "*" } }, "node_modules/@types/graceful-fs": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.7.tgz", - "integrity": "sha512-MhzcwU8aUygZroVwL2jeYk6JisJrPl/oov/gsgGCue9mkgl9wjGbzReYQClxiUgFDnib9FuHqTndccKeZKxTRw==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/http-cache-semantics": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.2.tgz", - "integrity": "sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", "optional": true }, "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true }, "node_modules/@types/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-gPQuzaPR5h/djlAv2apEG1HVOyj1IUs7GpfMZixU0/0KXT3pm64ylHuMUI1/Akh+sq/iikxg6Z2j+fcMDXaaTQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "*" } }, "node_modules/@types/istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-kv43F9eb3Lhj+lr/Hn6OcLCs/sSM8bt+fIaP11rCYngfV6NVjzWXJ17owQtDQTL9tQ8WSLUrGsSJ6rJz0F1w1A==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, "dependencies": { "@types/istanbul-lib-report": "*" } }, "node_modules/@types/json-schema": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", - "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/json5": { @@ -1632,79 +1849,70 @@ "@types/node": "*" } }, - "node_modules/@types/minimist": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.3.tgz", - "integrity": "sha512-ZYFzrvyWUNhaPomn80dsMNgMeXxNWZBdkuG/hWlUvXvbdUH8ZERNBGXnU87McuGcWDsyzX2aChCv/SVN348k3A==", - "dev": true - }, "node_modules/@types/node": { - "version": "18.18.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.1.tgz", - "integrity": "sha512-3G42sxmm0fF2+Vtb9TJQpnjmP+uKlWvFa8KoEGquh4gqRmoUG/N0ufuhikw6HEsdG2G2oIKhog1GCTfz9v5NdQ==" - }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.2.tgz", - "integrity": "sha512-lqa4UEhhv/2sjjIQgjX8B+RBjj47eo0mzGasklVJ78UKGQY1r0VpB9XHDaZZO9qzEFDdy4MrXLuEaSmPrPSe/A==", - "dev": true + "version": "18.19.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz", + "integrity": "sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==", + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/responselike": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.1.tgz", - "integrity": "sha512-TiGnitEDxj2X0j+98Eqk5lv/Cij8oHd32bU4D/Yw6AOq7vvTk0gSD2GPj0G/HkvhMoVsdlhYF4yqqlyPBTM6Sg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", "optional": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==", + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", "dev": true }, "node_modules/@types/yargs": { - "version": "17.0.26", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.26.tgz", - "integrity": "sha512-Y3vDy2X6zw/ZCumcwLpdhM5L7jmyGpmBCTYMHDLqT2IKVMYRRLdv6ZakA+wxhra6Z/3bwhNbNl9bDGXaFU+6rw==", + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-axdPBuLuEJt0c4yI5OZssC19K2Mq1uKdrfZBzuxLvaztgqUtFYZUNw7lETExPYJR9jdEoIg4mb7RQKRQzOkeGQ==", + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true }, "node_modules/@types/yauzl": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.1.tgz", - "integrity": "sha512-CHzgNU3qYBnp/O4S3yv2tXPlvMTq0YWSTVg2/JYLqWZGHwwgJGAwd00poay/11asPq8wLFwHzubyInqHIFmmiw==", + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", "optional": true, "dependencies": { "@types/node": "*" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.16.0.tgz", + "integrity": "sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" + "@typescript-eslint/types": "6.16.0", + "@typescript-eslint/visitor-keys": "6.16.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -1712,12 +1920,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.16.0.tgz", + "integrity": "sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -1725,21 +1933,22 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.16.0.tgz", + "integrity": "sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", + "@typescript-eslint/types": "6.16.0", + "@typescript-eslint/visitor-keys": "6.16.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -1751,142 +1960,52 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.16.0.tgz", + "integrity": "sha512-T83QPKrBm6n//q9mv7oiSvy/Xq/7Hyw9SzSEhMHJwznEmQayfBM87+oAlkNAMEO7/MjIwKyOHgBJbxB0s7gx2A==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.16.0", + "@typescript-eslint/types": "6.16.0", + "@typescript-eslint/typescript-estree": "6.16.0", + "semver": "^7.5.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/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/@typescript-eslint/utils/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "eslint": "^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz", + "integrity": "sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "6.16.0", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "dev": true + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, "node_modules/accepts": { "version": "1.3.8", @@ -1901,9 +2020,9 @@ } }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "bin": { "acorn": "bin/acorn" }, @@ -1920,15 +2039,15 @@ } }, "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", "dev": true, "dependencies": { - "debug": "4" + "debug": "^4.3.4" }, "engines": { - "node": ">= 6.0.0" + "node": ">= 14" } }, "node_modules/ajv": { @@ -2142,15 +2261,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -2177,9 +2287,9 @@ } }, "node_modules/axios": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", - "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -2239,6 +2349,15 @@ "node": ">=8" } }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/babel-plugin-jest-hoist": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", @@ -2324,15 +2443,6 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "node_modules/big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -2391,25 +2501,13 @@ "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", "optional": true }, - "node_modules/bplist-parser": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", - "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", - "dev": true, - "dependencies": { - "big-integer": "^1.6.44" - }, - "engines": { - "node": ">= 5.10.0" - } - }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -2425,9 +2523,9 @@ } }, "node_modules/browserslist": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", - "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", "dev": true, "funding": [ { @@ -2444,9 +2542,9 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001541", - "electron-to-chromium": "^1.4.535", - "node-releases": "^2.0.13", + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" }, "bin": { @@ -2492,21 +2590,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bundle-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", - "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", - "dev": true, - "dependencies": { - "run-applescript": "^5.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -2543,12 +2626,13 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2571,52 +2655,10 @@ "node": ">=6" } }, - "node_modules/camelcase-keys": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz", - "integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==", - "dev": true, - "dependencies": { - "camelcase": "^6.3.0", - "map-obj": "^4.1.0", - "quick-lru": "^5.1.1", - "type-fest": "^1.2.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/camelcase-keys/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/camelcase-keys/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/caniuse-lite": { - "version": "1.0.30001541", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001541.tgz", - "integrity": "sha512-bLOsqxDgTqUBkzxbNlSBt8annkDpQB9NdzdTbO2ooJ+eC/IQcvDspDc058g84ejCelF7vHUx57KIOjEecOHXaw==", + "version": "1.0.30001572", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001572.tgz", + "integrity": "sha512-1Pbh5FLmn5y4+QhNyJE9j3/7dK44dGB83/ZMjv/qJk86TvDbjk0LosiZo0i0WB0Vx607qMX9jYrn1VLHCkN4rw==", "dev": true, "funding": [ { @@ -2658,9 +2700,9 @@ } }, "node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", "dev": true, "funding": [ { @@ -2704,16 +2746,16 @@ } }, "node_modules/cli-truncate": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", - "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", "dev": true, "dependencies": { "slice-ansi": "^5.0.0", - "string-width": "^5.0.0" + "string-width": "^7.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2854,6 +2896,11 @@ "node": ">= 0.8" } }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==" + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -2863,9 +2910,9 @@ } }, "node_modules/comment-parser": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.0.tgz", - "integrity": "sha512-QLyTNiZ2KDOibvFPlZ6ZngVsZ/0gYnE6uTXi5aoDg8ed3AkJAz4sEje3Y8a29hQ1s6A99MZXe47fLAXQ1rTqaw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", "dev": true, "engines": { "node": ">= 12.0.0" @@ -2939,15 +2986,15 @@ } }, "node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, "dependencies": { + "env-paths": "^2.2.1", "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" + "parse-json": "^5.2.0" }, "engines": { "node": ">=14" @@ -2999,12 +3046,12 @@ } }, "node_modules/css-functions-list": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.0.tgz", - "integrity": "sha512-d/jBMPyYybkkLVypgtGv12R+pIFw4/f/IHtCTxWpZc8ofTYOPigIgmA6vu5rMHartZC+WuXhBUHfnyNUIQSYrg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.1.tgz", + "integrity": "sha512-Nj5YcaGgBtuUmn1D7oHqPW0c9iui7xsTsj5lIX8ZgevdfhmjFfKB3r8moHJtNJnctnYXJyYX5I1pp90HM4TPgQ==", "dev": true, "engines": { - "node": ">=12.22" + "node": ">=12 || >=16" } }, "node_modules/css-tree": { @@ -3045,17 +3092,16 @@ } }, "node_modules/data-urls": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", - "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", "dev": true, "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.0" + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/dateformat": { @@ -3082,52 +3128,6 @@ } } }, - "node_modules/decamelize": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz", - "integrity": "sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", - "dev": true, - "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decamelize-keys/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/decimal.js": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", @@ -3188,162 +3188,6 @@ "node": ">=0.10.0" } }, - "node_modules/default-browser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", - "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", - "dev": true, - "dependencies": { - "bundle-name": "^3.0.0", - "default-browser-id": "^3.0.0", - "execa": "^7.1.1", - "titleize": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser-id": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", - "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", - "dev": true, - "dependencies": { - "bplist-parser": "^0.2.0", - "untildify": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/execa": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", - "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": "^14.18.0 || ^16.14.0 || >=18.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/default-browser/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", - "dev": true, - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/default-browser/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "dev": true, - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/defer-to-connect": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", @@ -3354,9 +3198,9 @@ } }, "node_modules/define-data-property": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.0.tgz", - "integrity": "sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", "dependencies": { "get-intrinsic": "^1.2.1", "gopd": "^1.0.1", @@ -3366,18 +3210,6 @@ "node": ">= 0.4" } }, - "node_modules/define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", @@ -3498,18 +3330,6 @@ } ] }, - "node_modules/domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "dev": true, - "dependencies": { - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", @@ -3549,9 +3369,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron": { - "version": "26.2.4", - "resolved": "https://registry.npmjs.org/electron/-/electron-26.2.4.tgz", - "integrity": "sha512-weMUSMyDho5E0DPQ3breba3D96IxwNvtYHjMd/4/wNN3BdI5s3+0orNnPVGJFcLhSvKoxuKUqdVonUocBPwlQA==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-27.2.0.tgz", + "integrity": "sha512-no/iMICVLI/5G0IqgKFbB89HDN88DWwKeRO+dPfJPkpJISdEX8Cx/sMEOFuuRa4VNInNe5CKCqRWExK5z3AdcQ==", "hasInstallScript": true, "optional": true, "dependencies": { @@ -3567,9 +3387,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.537", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.537.tgz", - "integrity": "sha512-W1+g9qs9hviII0HAwOdehGYkr+zt7KKdmCcJcjH0mYg6oL8+ioT3Skjmt7BLoAQqXhjf40AXd+HlR4oAWMlXjA==", + "version": "1.4.616", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.616.tgz", + "integrity": "sha512-1n7zWYh8eS0L9Uy+GskE0lkBUNK83cXTVJI0pU3mGprFsbfSdAc15VTFbo+A+Bq4pwstmL30AVcEU3Fo463lNg==", "dev": true }, "node_modules/emittery": { @@ -3585,9 +3405,9 @@ } }, "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", "dev": true }, "node_modules/encodeurl": { @@ -3608,9 +3428,9 @@ } }, "node_modules/engine.io": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.2.tgz", - "integrity": "sha512-IXsMcGpw/xRfjra46sVZVHiSWo/nJ/3g1337q9KNXtS6YRzbW5yIzTCb9DjhrBe7r3GZQR0I4+nq+4ODk5g/cA==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", + "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -3678,7 +3498,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "optional": true, + "devOptional": true, "engines": { "node": ">=6" } @@ -3724,25 +3544,25 @@ } }, "node_modules/es-abstract": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", - "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", "dependencies": { "array-buffer-byte-length": "^1.0.0", "arraybuffer.prototype.slice": "^1.0.2", "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "call-bind": "^1.0.5", "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.1", + "get-intrinsic": "^1.2.2", "get-symbol-description": "^1.0.0", "globalthis": "^1.0.3", "gopd": "^1.0.1", - "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", + "hasown": "^2.0.0", "internal-slot": "^1.0.5", "is-array-buffer": "^3.0.2", "is-callable": "^1.2.7", @@ -3752,7 +3572,7 @@ "is-string": "^1.0.7", "is-typed-array": "^1.1.12", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", + "object-inspect": "^1.13.1", "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.5.1", @@ -3766,7 +3586,7 @@ "typed-array-byte-offset": "^1.0.0", "typed-array-length": "^1.0.4", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.11" + "which-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -3776,25 +3596,25 @@ } }, "node_modules/es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" } }, "node_modules/es-to-primitive": { @@ -3845,17 +3665,18 @@ } }, "node_modules/eslint": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", - "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.50.0", - "@humanwhocodes/config-array": "^0.11.11", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -3897,18 +3718,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-config-prettier": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", - "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -3956,28 +3765,28 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.28.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz", - "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==", + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", "dev": true, "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.findlastindex": "^1.2.2", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", + "eslint-import-resolver-node": "^0.3.9", "eslint-module-utils": "^2.8.0", - "has": "^1.0.3", - "is-core-module": "^2.13.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.fromentries": "^2.0.6", - "object.groupby": "^1.0.0", - "object.values": "^1.1.6", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", "semver": "^6.3.1", - "tsconfig-paths": "^3.14.2" + "tsconfig-paths": "^3.15.0" }, "engines": { "node": ">=4" @@ -3986,6 +3795,16 @@ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint-plugin-import/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", @@ -4007,10 +3826,31 @@ "node": ">=0.10.0" } }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/eslint-plugin-jest": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.4.2.tgz", - "integrity": "sha512-3Nfvv3wbq2+PZlRTf2oaAWXWwbdBejFRBR2O8tAO67o+P8zno+QGbcDYaAXODlreXVg+9gvWhKKmG2rgfb8GEg==", + "version": "27.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.6.0.tgz", + "integrity": "sha512-MTlusnnDMChbElsszJvrwD1dN3x6nZl//s4JD23BxB6MgR66TZlL064su24xEIS3VACfAoHV1vgyMgPw8nkdng==", "dev": true, "dependencies": { "@typescript-eslint/utils": "^5.10.0" @@ -4032,89 +3872,152 @@ } } }, - "node_modules/eslint-plugin-jsdoc": { - "version": "46.8.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.8.2.tgz", - "integrity": "sha512-5TSnD018f3tUJNne4s4gDWQflbsgOycIKEUBoCLn6XtBMgNHxQFmV8vVxUtiPxAQq8lrX85OaSG/2gnctxw9uQ==", + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dev": true, "dependencies": { - "@es-joy/jsdoccomment": "~0.40.1", - "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", "debug": "^4.3.4", - "escape-string-regexp": "^4.0.0", - "esquery": "^1.5.0", - "is-builtin-module": "^3.2.1", - "semver": "^7.5.4", - "spdx-expression-parse": "^3.0.1" + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, "engines": { - "node": ">=16" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/eslint-plugin-jsdoc/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/eslint-plugin-jsdoc/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" }, - "bin": { - "semver": "bin/semver.js" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/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": ">=10" + "node": ">=8.0.0" + } + }, + "node_modules/eslint-plugin-jest/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" } }, - "node_modules/eslint-plugin-jsdoc/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz", - "integrity": "sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==", + "node_modules/eslint-plugin-jsdoc": { + "version": "46.9.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.9.1.tgz", + "integrity": "sha512-11Ox5LCl2wY7gGkp9UOyew70o9qvii1daAH+h/MFobRVRNcy7sVlH+jm0HQdgcvcru6285GvpjpUyoa051j03Q==", "dev": true, "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.5" + "@es-joy/jsdoccomment": "~0.41.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.5.4", + "spdx-expression-parse": "^4.0.0" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": ">=16" }, "funding": { "url": "https://opencollective.com/prettier" }, "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } + "eslint": "^7.0.0 || ^8.0.0" } }, "node_modules/eslint-scope": { @@ -4143,6 +4046,26 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -4393,9 +4316,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -4440,9 +4363,9 @@ } }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", "dependencies": { "reusify": "^1.0.4" } @@ -4546,11 +4469,11 @@ } }, "node_modules/flat-cache": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", - "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dependencies": { - "flatted": "^3.2.7", + "flatted": "^3.2.9", "keyv": "^4.5.3", "rimraf": "^3.0.2" }, @@ -4590,6 +4513,34 @@ "is-callable": "^1.1.3" } }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -4653,9 +4604,12 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/function.prototype.name": { "version": "1.1.6", @@ -4700,15 +4654,27 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4783,6 +4749,26 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/global-agent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", @@ -4800,39 +4786,6 @@ "node": ">=10.0" } }, - "node_modules/global-agent/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/global-agent/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "optional": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/global-agent/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, "node_modules/global-modules": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", @@ -4872,9 +4825,9 @@ } }, "node_modules/globals": { - "version": "13.22.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.22.0.tgz", - "integrity": "sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dependencies": { "type-fest": "^0.20.2" }, @@ -4992,26 +4945,6 @@ "uglify-js": "^3.1.4" } }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -5029,11 +4962,11 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", "dependencies": { - "get-intrinsic": "^1.1.1" + "get-intrinsic": "^1.2.2" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5075,54 +5008,35 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/helmet": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.0.0.tgz", - "integrity": "sha512-MsIgYmdBh460ZZ8cJC81q4XJknjG567wzEmv46WOBblDb6TUd3z8/GhgmsM9pn8g2B80tAJ4m5/d3Bi1KrSUBQ==", - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", "dependencies": { - "lru-cache": "^6.0.0" + "function-bind": "^1.1.2" }, "engines": { - "node": ">=10" + "node": ">= 0.4" } }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, + "node_modules/helmet": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz", + "integrity": "sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg==", "engines": { - "node": ">=10" + "node": ">=16.0.0" } }, - "node_modules/hosted-git-info/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", "dev": true, "dependencies": { - "whatwg-encoding": "^2.0.0" + "whatwg-encoding": "^3.1.1" }, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/html-escaper": { @@ -5198,17 +5112,16 @@ } }, "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", "dev": true, "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/http2-wrapper": { @@ -5225,16 +5138,16 @@ } }, "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", "dev": true, "dependencies": { - "agent-base": "6", + "agent-base": "^7.0.2", "debug": "4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/human-signals": { @@ -5273,9 +5186,9 @@ } }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", "engines": { "node": ">= 4" } @@ -5295,15 +5208,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -5331,18 +5235,6 @@ "node": ">=0.8.19" } }, - "node_modules/indent-string": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", - "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -5364,12 +5256,12 @@ "dev": true }, "node_modules/internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", "side-channel": "^1.0.4" }, "engines": { @@ -5469,12 +5361,12 @@ } }, "node_modules/is-core-module": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", - "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5494,21 +5386,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -5549,24 +5426,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dev": true, - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -5609,15 +5468,6 @@ "node": ">=8" } }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-plain-object": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", @@ -5709,46 +5559,19 @@ "engines": { "node": ">= 0.4" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-wsl/node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dependencies": { + "call-bind": "^1.0.2" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/isarray": { @@ -5762,18 +5585,18 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-instrument": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.0.tgz", - "integrity": "sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz", + "integrity": "sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==", "dev": true, "dependencies": { "@babel/core": "^7.12.3", @@ -5860,6 +5683,24 @@ "node": ">=8" } }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", @@ -6320,39 +6161,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-snapshot/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-snapshot/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/jest-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", @@ -6475,40 +6283,38 @@ } }, "node_modules/jsdom": { - "version": "22.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", - "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", + "version": "23.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.0.1.tgz", + "integrity": "sha512-2i27vgvlUsGEBO9+/kJQRbtqtm+191b5zAZrU/UezVmnC2dlDAFLgDYJvAEi94T4kjsRKkezEtLQTgsNEsW2lQ==", "dev": true, "dependencies": { - "abab": "^2.0.6", "cssstyle": "^3.0.0", - "data-urls": "^4.0.0", + "data-urls": "^5.0.0", "decimal.js": "^10.4.3", - "domexception": "^4.0.0", "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.1", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.4", + "nwsapi": "^2.2.7", "parse5": "^7.1.2", "rrweb-cssom": "^0.6.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.2", - "w3c-xmlserializer": "^4.0.0", + "tough-cookie": "^4.1.3", + "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.1", - "ws": "^8.13.0", - "xml-name-validator": "^4.0.0" + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.14.2", + "xml-name-validator": "^5.0.0" }, "engines": { - "node": ">=16" + "node": ">=18" }, "peerDependencies": { - "canvas": "^2.5.0" + "canvas": "^2.11.2" }, "peerDependenciesMeta": { "canvas": { @@ -6583,9 +6389,9 @@ "dev": true }, "node_modules/keyv": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", - "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dependencies": { "json-buffer": "3.0.1" } @@ -6609,9 +6415,9 @@ } }, "node_modules/known-css-properties": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.28.0.tgz", - "integrity": "sha512-9pSL5XB4J+ifHP0e0jmmC98OGC1nL8/JjS+fi6mnTlIf//yt/MfVLtKg7S6nCtj/8KTcWX7nRlY0XywoYY1ISQ==", + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.29.0.tgz", + "integrity": "sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==", "dev": true }, "node_modules/leac": { @@ -6644,12 +6450,12 @@ } }, "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", "dev": true, "engines": { - "node": ">=10" + "node": ">=14" } }, "node_modules/lines-and-columns": { @@ -6659,27 +6465,27 @@ "dev": true }, "node_modules/lint-staged": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-14.0.1.tgz", - "integrity": "sha512-Mw0cL6HXnHN1ag0mN/Dg4g6sr8uf8sn98w2Oc1ECtFto9tvRF7nkXGJRbx8gPlHyoR0pLyBr2lQHbWwmUHe1Sw==", + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.0.tgz", + "integrity": "sha512-TFZzUEV00f+2YLaVPWBWGAMq7So6yQx+GG8YRMDeOEIf95Zn5RyiLMsEiX4KTNl9vq/w+NqRJkLA1kPIo15ufQ==", "dev": true, "dependencies": { "chalk": "5.3.0", - "commander": "11.0.0", + "commander": "11.1.0", "debug": "4.3.4", - "execa": "7.2.0", - "lilconfig": "2.1.0", - "listr2": "6.6.1", + "execa": "8.0.1", + "lilconfig": "3.0.0", + "listr2": "8.0.0", "micromatch": "4.0.5", "pidtree": "0.6.0", "string-argv": "0.3.2", - "yaml": "2.3.1" + "yaml": "2.3.4" }, "bin": { "lint-staged": "bin/lint-staged.js" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=18.12.0" }, "funding": { "url": "https://opencollective.com/lint-staged" @@ -6698,56 +6504,56 @@ } }, "node_modules/lint-staged/node_modules/commander": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", - "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "dev": true, "engines": { "node": ">=16" } }, "node_modules/lint-staged/node_modules/execa": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", - "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, "dependencies": { "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", - "signal-exit": "^3.0.7", + "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" }, "engines": { - "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + "node": ">=16.17" }, "funding": { "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, "node_modules/lint-staged/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", "dev": true, "engines": { - "node": ">=10" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lint-staged/node_modules/human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", "dev": true, "engines": { - "node": ">=14.18.0" + "node": ">=16.17.0" } }, "node_modules/lint-staged/node_modules/is-stream": { @@ -6775,9 +6581,9 @@ } }, "node_modules/lint-staged/node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", + "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", "dev": true, "dependencies": { "path-key": "^4.0.0" @@ -6816,6 +6622,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lint-staged/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/lint-staged/node_modules/strip-final-newline": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", @@ -6829,28 +6647,20 @@ } }, "node_modules/listr2": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-6.6.1.tgz", - "integrity": "sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.0.0.tgz", + "integrity": "sha512-u8cusxAcyqAiQ2RhYvV7kRKNLgUvtObIbhOX2NCXqvp1UU32xIg5CT22ykS2TPKJXZWJwtK3IKLiqAGlGNE+Zg==", "dev": true, "dependencies": { - "cli-truncate": "^3.1.0", + "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", - "log-update": "^5.0.1", + "log-update": "^6.0.0", "rfdc": "^1.3.0", - "wrap-ansi": "^8.1.0" + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "enquirer": ">= 2.3.0 < 3" - }, - "peerDependenciesMeta": { - "enquirer": { - "optional": true - } + "node": ">=18.0.0" } }, "node_modules/locate-path": { @@ -6890,34 +6700,34 @@ "dev": true }, "node_modules/log-update": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz", - "integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", + "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", "dev": true, "dependencies": { - "ansi-escapes": "^5.0.0", + "ansi-escapes": "^6.2.0", "cli-cursor": "^4.0.0", - "slice-ansi": "^5.0.0", - "strip-ansi": "^7.0.1", - "wrap-ansi": "^8.0.1" + "slice-ansi": "^7.0.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-update/node_modules/ansi-escapes": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", - "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", + "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", "dev": true, "dependencies": { - "type-fest": "^1.0.2" + "type-fest": "^3.0.0" }, "engines": { - "node": ">=12" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6935,6 +6745,49 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, "node_modules/log-update/node_modules/strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", @@ -6951,12 +6804,12 @@ } }, "node_modules/log-update/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", "dev": true, "engines": { - "node": ">=10" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6980,14 +6833,6 @@ "yallist": "^3.0.2" } }, - "node_modules/luxon": { - "version": "1.28.1", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.1.tgz", - "integrity": "sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw==", - "engines": { - "node": "*" - } - }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -7045,18 +6890,6 @@ "tmpl": "1.0.5" } }, - "node_modules/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/matcher": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", @@ -7094,38 +6927,12 @@ } }, "node_modules/meow": { - "version": "10.1.5", - "resolved": "https://registry.npmjs.org/meow/-/meow-10.1.5.tgz", - "integrity": "sha512-/d+PQ4GKmGvM9Bee/DPa8z3mXs/pkvJE2KEThngVNOqtmljC6K7NMPxtc2JeZYTmpWb9k/TmxjeL18ez3h7vCw==", - "dev": true, - "dependencies": { - "@types/minimist": "^1.2.2", - "camelcase-keys": "^7.0.0", - "decamelize": "^5.0.0", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.2", - "read-pkg-up": "^8.0.0", - "redent": "^4.0.0", - "trim-newlines": "^4.0.2", - "type-fest": "^1.2.2", - "yargs-parser": "^20.2.9" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.0.0.tgz", + "integrity": "sha512-4Hu+75Vo7EOR+8C9RmkabfLijuwd9SrzQ8f0SyC4qZZwU6BlxeOt5ulF3PGCpcMJX4hI+ktpJhea0P6PN1RiWw==", "dev": true, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -7220,24 +7027,19 @@ "node": ">=4" } }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { @@ -7248,18 +7050,13 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, "engines": { - "node": ">= 6" + "node": ">=16 || 14 >=14.17" } }, "node_modules/module-alias": { @@ -7268,9 +7065,9 @@ "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==" }, "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", "engines": { "node": "*" } @@ -7292,9 +7089,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, "funding": [ { @@ -7328,9 +7125,9 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "node_modules/nise": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz", - "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.5.tgz", + "integrity": "sha512-VJuPIfUFaXNRzETTQEEItTOP8Y171ijr+JLq42wHes3DiryR8vT+1TXQW/Rx8JNUhyYYWyIvjXTU6dOhJcs9Nw==", "dev": true, "dependencies": { "@sinonjs/commons": "^2.0.0", @@ -7365,13 +7162,13 @@ } }, "node_modules/node-ical": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/node-ical/-/node-ical-0.16.1.tgz", - "integrity": "sha512-AAlJbvyRlQ5QT3LtYAvveY/gZlvHAIjHR/suQp1YVX/RySCxI/qZcyauRDKv2QSH0zNG0J8iv5T1gv6FadoETA==", + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/node-ical/-/node-ical-0.17.1.tgz", + "integrity": "sha512-2vhc/tzO9rnvok3UtQxqKCAg0N6HfLnQzcfLGIHJotKuqlrcn7aCm8AgpB10m033JpJNng/EXxaQMCKIJycMwQ==", "dependencies": { - "axios": "1.4.0", + "axios": "1.6.2", "moment-timezone": "^0.5.31", - "rrule": "2.6.4", + "rrule": "2.7.1", "uuid": "^9.0.0" } }, @@ -7382,57 +7179,9 @@ "dev": true }, "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, "node_modules/normalize-path": { @@ -7483,9 +7232,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -7499,12 +7248,12 @@ } }, "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, @@ -7595,24 +7344,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/open": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", - "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", - "dev": true, - "dependencies": { - "default-browser": "^4.0.0", - "define-lazy-prop": "^3.0.0", - "is-inside-container": "^1.0.0", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -7766,6 +7497,31 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -7898,12 +7654,12 @@ } }, "node_modules/playwright": { - "version": "1.38.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.38.1.tgz", - "integrity": "sha512-oRMSJmZrOu1FP5iu3UrCx8JEFRIMxLDM0c/3o4bpzU5Tz97BypefWf7TuTNPWeCe279TPal5RtPPZ+9lW/Qkow==", + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.40.1.tgz", + "integrity": "sha512-2eHI7IioIpQ0bS1Ovg/HszsN/XKNwEG1kbzSDDmADpclKc7CyqkHw7Mg2JCz/bbCxg25QUPcjksoMW7JcIFQmw==", "dev": true, "dependencies": { - "playwright-core": "1.38.1" + "playwright-core": "1.40.1" }, "bin": { "playwright": "cli.js" @@ -7916,9 +7672,9 @@ } }, "node_modules/playwright-core": { - "version": "1.38.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.38.1.tgz", - "integrity": "sha512-tQqNFUKa3OfMf4b2jQ7aGLB8o9bS3bOY0yMEtldtC2+spf8QXG9zvXLTXUeRsoNuxEYMgLYR+NXfAa1rjKRcrg==", + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.1.tgz", + "integrity": "sha512-+hkOycxPiV534c4HhpfX6yrlawqVUzITRKwHAmYfmsVreltEl6fAZJ3DPfLMOODw0H3s1Itd6MDCWmP1fl/QvQ==", "dev": true, "bin": { "playwright-core": "cli.js" @@ -7942,9 +7698,9 @@ } }, "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "version": "8.4.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", + "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", "dev": true, "funding": [ { @@ -7961,7 +7717,7 @@ } ], "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -7976,25 +7732,35 @@ "dev": true }, "node_modules/postcss-safe-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", - "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.0.tgz", + "integrity": "sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">=18.0" }, "peerDependencies": { - "postcss": "^8.3.3" + "postcss": "^8.4.31" } }, "node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "version": "6.0.14", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.14.tgz", + "integrity": "sha512-65xXYsT40i9GyWzlHQ5ShZoK7JZdySeOozi/tz2EezDo6c04q6+ckYMeoY7idaie1qp2dT5KoYQ2yky6JuoHnA==", "dev": true, "dependencies": { "cssesc": "^3.0.0", @@ -8019,9 +7785,9 @@ } }, "node_modules/prettier": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", - "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz", + "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -8127,9 +7893,9 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "engines": { "node": ">=6" } @@ -8193,7 +7959,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "devOptional": true, + "optional": true, "engines": { "node": ">=10" }, @@ -8252,81 +8018,6 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, - "node_modules/read-pkg": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-6.0.0.tgz", - "integrity": "sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^3.0.2", - "parse-json": "^5.2.0", - "type-fest": "^1.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-8.0.0.tgz", - "integrity": "sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ==", - "dev": true, - "dependencies": { - "find-up": "^5.0.0", - "read-pkg": "^6.0.0", - "type-fest": "^1.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/redent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-4.0.0.tgz", - "integrity": "sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==", - "dev": true, - "dependencies": { - "indent-string": "^5.0.0", - "strip-indent": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/regexp.prototype.flags": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", @@ -8376,9 +8067,9 @@ "dev": true }, "node_modules/resolve": { - "version": "1.22.6", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", - "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { "is-core-module": "^2.13.0", @@ -8511,14 +8202,11 @@ } }, "node_modules/rrule": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.6.4.tgz", - "integrity": "sha512-sLdnh4lmjUqq8liFiOUXD5kWp/FcnbDLPwq5YAc/RrN6120XOPb86Ae5zxF7ttBVq8O3LxjjORMEit1baluahA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.7.1.tgz", + "integrity": "sha512-4p20u/1U7WqR3Nb1hOUrm0u1nSI7sO93ZUVZEZ5HeF6Gr5OlJuyhwEGRvUHq8ZfrPsq5gfa5b9dqnUs/kPqpIw==", "dependencies": { - "tslib": "^1.10.0" - }, - "optionalDependencies": { - "luxon": "^1.21.3" + "tslib": "^2.4.0" } }, "node_modules/rrweb-cssom": { @@ -8527,21 +8215,6 @@ "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", "dev": true }, - "node_modules/run-applescript": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", - "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", - "dev": true, - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -8647,12 +8320,18 @@ } }, "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "devOptional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/semver-compare": { @@ -8661,6 +8340,24 @@ "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", "optional": true }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "devOptional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "devOptional": true + }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -8743,6 +8440,20 @@ "node": ">= 0.8.0" } }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/set-function-name": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", @@ -8800,16 +8511,16 @@ "dev": true }, "node_modules/sinon": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-16.0.0.tgz", - "integrity": "sha512-B8AaZZm9CT5pqe4l4uWJztfD/mOTa7dL8Qo0W4+s+t74xECOgSZDDQCBjNgIK3+n4kyxQrSTv2V5ul8K25qkiQ==", + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz", + "integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==", "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^10.3.0", + "@sinonjs/fake-timers": "^11.2.2", "@sinonjs/samsam": "^8.0.0", "diff": "^5.1.0", - "nise": "^5.1.4", + "nise": "^5.1.5", "supports-color": "^7.2.0" }, "funding": { @@ -8817,6 +8528,15 @@ "url": "https://opencollective.com/sinon" } }, + "node_modules/sinon/node_modules/@sinonjs/fake-timers": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", + "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, "node_modules/sinon/node_modules/diff": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", @@ -8953,16 +8673,6 @@ "source-map": "^0.6.0" } }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, "node_modules/spdx-exceptions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", @@ -8970,9 +8680,9 @@ "dev": true }, "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", "dev": true, "dependencies": { "spdx-exceptions": "^2.1.0", @@ -8980,9 +8690,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.15", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.15.tgz", - "integrity": "sha512-lpT8hSQp9jAKp9mhtBU4Xjon8LPGBvLIuBiSVhMEtmLecTh2mO0tlqrAMp47tBXzMr13NJMQ2lf7RpQGLJ3HsQ==", + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", "dev": true }, "node_modules/sprintf-js": { @@ -9043,9 +8753,27 @@ } }, "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.0.0.tgz", + "integrity": "sha512-GPQHj7row82Hjo9hKZieKcHIhaAIKOJvFSIZXuCU9OASVZrMNUaZuz++SPVrBjnLsnk4k+z9f2EIypgxf2vNFw==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { "eastasianwidth": "^0.2.0", @@ -9059,6 +8787,39 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/string-width/node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -9158,6 +8919,19 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -9176,21 +8950,6 @@ "node": ">=6" } }, - "node_modules/strip-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", - "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", - "dev": true, - "dependencies": { - "min-indent": "^1.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -9202,54 +8961,46 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/style-search": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", - "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==", - "dev": true - }, "node_modules/stylelint": { - "version": "15.10.3", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-15.10.3.tgz", - "integrity": "sha512-aBQMMxYvFzJJwkmg+BUUg3YfPyeuCuKo2f+LOw7yYbU8AZMblibwzp9OV4srHVeQldxvSFdz0/Xu8blq2AesiA==", + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.1.0.tgz", + "integrity": "sha512-Sh1rRV0lN1qxz/QsuuooLWsIZ/ona7NKw/fRZd6y6PyXYdD2W0EAzJ8yJcwSx4Iw/muz0CF09VZ+z4EiTAcKmg==", "dev": true, "dependencies": { - "@csstools/css-parser-algorithms": "^2.3.1", - "@csstools/css-tokenizer": "^2.2.0", - "@csstools/media-query-list-parser": "^2.1.4", - "@csstools/selector-specificity": "^3.0.0", + "@csstools/css-parser-algorithms": "^2.4.0", + "@csstools/css-tokenizer": "^2.2.2", + "@csstools/media-query-list-parser": "^2.1.6", + "@csstools/selector-specificity": "^3.0.1", "balanced-match": "^2.0.0", "colord": "^2.9.3", - "cosmiconfig": "^8.2.0", - "css-functions-list": "^3.2.0", + "cosmiconfig": "^9.0.0", + "css-functions-list": "^3.2.1", "css-tree": "^2.3.1", "debug": "^4.3.4", - "fast-glob": "^3.3.1", + "fast-glob": "^3.3.2", "fastest-levenshtein": "^1.0.16", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "global-modules": "^2.0.0", "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.3.1", - "ignore": "^5.2.4", - "import-lazy": "^4.0.0", + "ignore": "^5.3.0", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.28.0", + "known-css-properties": "^0.29.0", "mathml-tag-names": "^2.1.3", - "meow": "^10.1.5", + "meow": "^13.0.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.27", + "postcss": "^8.4.32", "postcss-resolve-nested-selector": "^0.1.1", - "postcss-safe-parser": "^6.0.0", + "postcss-safe-parser": "^7.0.0", "postcss-selector-parser": "^6.0.13", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "style-search": "^0.1.0", + "strip-ansi": "^7.1.0", "supports-hyperlinks": "^3.0.0", "svg-tags": "^1.0.0", "table": "^6.8.1", @@ -9259,7 +9010,7 @@ "stylelint": "bin/stylelint.mjs" }, "engines": { - "node": "^14.13.1 || >=16.0.0" + "node": ">=18.12.0" }, "funding": { "type": "opencollective", @@ -9267,60 +9018,108 @@ } }, "node_modules/stylelint-config-recommended": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-13.0.0.tgz", - "integrity": "sha512-EH+yRj6h3GAe/fRiyaoO2F9l9Tgg50AOFhaszyfov9v6ayXJ1IkSHwTxd7lB48FmOeSGDPLjatjO11fJpmarkQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.0.tgz", + "integrity": "sha512-jSkx290CglS8StmrLp2TxAppIajzIBZKYm3IxT89Kg6fGlxbPiTiyH9PS5YUuVAFwaJLl1ikiXX0QWjI0jmgZQ==", + "dev": true, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "stylelint": "^16.0.0" + } + }, + "node_modules/stylelint-config-standard": { + "version": "36.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-36.0.0.tgz", + "integrity": "sha512-3Kjyq4d62bYFp/Aq8PMKDwlgUyPU4nacXsjDLWJdNPRUgpuxALu1KnlAHIj36cdtxViVhXexZij65yM0uNIHug==", + "dev": true, + "dependencies": { + "stylelint-config-recommended": "^14.0.0" + }, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "stylelint": "^16.1.0" + } + }, + "node_modules/stylelint-prettier": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/stylelint-prettier/-/stylelint-prettier-5.0.0.tgz", + "integrity": "sha512-RHfSlRJIsaVg5Br94gZVdWlz/rBTyQzZflNE6dXvSxt/GthWMY3gEHsWZEBaVGg7GM+XrtVSp4RznFlB7i0oyw==", "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, "engines": { - "node": "^14.13.1 || >=16.0.0" + "node": ">=18.12.0" }, "peerDependencies": { - "stylelint": "^15.10.0" + "prettier": ">=3.0.0", + "stylelint": ">=16.0.0" + } + }, + "node_modules/stylelint/node_modules/balanced-match": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", + "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", + "dev": true + }, + "node_modules/stylelint/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/stylelint/node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/stylelint-config-standard": { - "version": "34.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-34.0.0.tgz", - "integrity": "sha512-u0VSZnVyW9VSryBG2LSO+OQTjN7zF9XJaAJRX/4EwkmU0R2jYwmBSN10acqZisDitS0CLiEiGjX7+Hrq8TAhfQ==", + "node_modules/stylelint/node_modules/flat-cache": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.0.tgz", + "integrity": "sha512-EryKbCE/wxpxKniQlyas6PY1I9vwtF3uCBweX+N8KYTCn3Y12RTGtQAJ/bd5pl7kxUAc8v/R3Ake/N17OZiFqA==", "dev": true, "dependencies": { - "stylelint-config-recommended": "^13.0.0" + "flatted": "^3.2.9", + "keyv": "^4.5.4", + "rimraf": "^5.0.5" }, "engines": { - "node": "^14.13.1 || >=16.0.0" - }, - "peerDependencies": { - "stylelint": "^15.10.0" + "node": ">=16" } }, - "node_modules/stylelint-prettier": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/stylelint-prettier/-/stylelint-prettier-4.0.2.tgz", - "integrity": "sha512-EoHnR2PiaWgpGtoI4VW7AzneMfwmwQsNwQ+3/E2k/a+ju5yO6rfPfop4vzPQKcJN4ZM1YbspEOPu88D8538sbg==", + "node_modules/stylelint/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", "dev": true, "dependencies": { - "prettier-linter-helpers": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "^14.17.0 || >=16.0.0" + "node": ">=16 || 14 >=14.17" }, - "peerDependencies": { - "prettier": ">=3.0.0", - "stylelint": ">=15.8.0" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/stylelint/node_modules/balanced-match": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", - "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", - "dev": true - }, - "node_modules/stylelint/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "node_modules/stylelint/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -9339,6 +9138,24 @@ "node": ">=8" } }, + "node_modules/stylelint/node_modules/rimraf": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/stylelint/node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -9365,6 +9182,45 @@ "node": ">=8" } }, + "node_modules/stylelint/node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stylelint/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/stylelint/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/stylelint/node_modules/write-file-atomic": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", @@ -9444,28 +9300,6 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "node_modules/synckit": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", - "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", - "dev": true, - "dependencies": { - "@pkgr/utils": "^2.3.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/synckit/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, "node_modules/table": { "version": "6.8.1", "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", @@ -9564,23 +9398,33 @@ "node": ">=8" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } }, - "node_modules/titleize": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", - "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "engines": { - "node": ">=12" + "dependencies": { + "brace-expansion": "^1.1.7" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "*" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -9641,33 +9485,33 @@ } }, "node_modules/tr46": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", - "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", "dev": true, "dependencies": { - "punycode": "^2.3.0" + "punycode": "^2.3.1" }, "engines": { - "node": ">=14" + "node": ">=18" } }, - "node_modules/trim-newlines": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-4.1.1.tgz", - "integrity": "sha512-jRKj0n0jXWo6kh62nA5TEh3+4igKDXLvzBJcPpiizP7oOolUrYIxmVBG9TOtHYFHoddUk6YvAkGeGoSVTXfQXQ==", + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", "dev": true, "engines": { - "node": ">=12" + "node": ">=16.13.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "typescript": ">=4.2.0" } }, "node_modules/tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, "dependencies": { "@types/json5": "^0.0.29", @@ -9698,9 +9542,9 @@ } }, "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -9717,6 +9561,12 @@ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -9822,9 +9672,9 @@ } }, "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, "peer": true, "bin": { @@ -9861,6 +9711,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -9878,15 +9733,6 @@ "node": ">= 0.8" } }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/update-browserslist-db": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", @@ -9962,35 +9808,19 @@ } }, "node_modules/v8-to-istanbul": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", - "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", + "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" + "convert-source-map": "^2.0.0" }, "engines": { "node": ">=10.12.0" } }, - "node_modules/v8-to-istanbul/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -10000,15 +9830,15 @@ } }, "node_modules/w3c-xmlserializer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", - "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", "dev": true, "dependencies": { - "xml-name-validator": "^4.0.0" + "xml-name-validator": "^5.0.0" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/walker": { @@ -10030,37 +9860,37 @@ } }, "node_modules/whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", "dev": true, "dependencies": { "iconv-lite": "0.6.3" }, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", "dev": true, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/whatwg-url": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", - "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", "dev": true, "dependencies": { - "tr46": "^4.1.1", + "tr46": "^5.0.0", "webidl-conversions": "^7.0.0" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/which": { @@ -10093,12 +9923,12 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", - "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", "dependencies": { "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "call-bind": "^1.0.4", "for-each": "^0.3.3", "gopd": "^1.0.1", "has-tostringtag": "^1.0.0" @@ -10116,9 +9946,27 @@ "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==" }, "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "dependencies": { "ansi-styles": "^6.1.0", @@ -10132,6 +9980,68 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/wrap-ansi/node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -10190,9 +10100,9 @@ } }, "node_modules/ws": { - "version": "8.14.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", - "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", "dev": true, "engines": { "node": ">=10.0.0" @@ -10211,12 +10121,12 @@ } }, "node_modules/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", "dev": true, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/xmlchars": { @@ -10241,9 +10151,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", - "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", "dev": true, "engines": { "node": ">= 14" @@ -10268,12 +10178,12 @@ } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs/node_modules/emoji-regex": { @@ -10305,15 +10215,6 @@ "node": ">=8" } }, - "node_modules/yargs/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", diff --git a/package.json b/package.json index 811d0c1c8c..6d5206975f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "magicmirror", - "version": "2.25.0", + "version": "2.26.0", "description": "The open source modular smart mirror platform.", "main": "js/electron.js", "scripts": { @@ -18,12 +18,12 @@ "test:e2e": "NODE_ENV=test jest --selectProjects e2e -i --forceExit", "test:unit": "NODE_ENV=test jest --selectProjects unit", "test:prettier": "prettier . --check", - "test:js": "eslint 'js/**/*.js' 'modules/default/**/*.js' 'clientonly/*.js' 'serveronly/*.js' 'translations/*.js' 'vendor/*.js' 'tests/**/*.js' 'config/*' --config .eslintrc.json", + "test:js": "eslint 'js/**/*.js' 'modules/default/**/*.js' 'clientonly/*.js' 'serveronly/*.js' 'translations/*.js' 'vendor/*.js' 'tests/**/*.js' 'config/*'", "test:css": "stylelint 'css/main.css' 'fonts/*.css' 'modules/default/**/*.css' 'vendor/*.css' --config .stylelintrc.json", "test:calendar": "node ./modules/default/calendar/debug.js", "config:check": "node js/check_config.js", "lint:prettier": "prettier . --write", - "lint:js": "eslint 'js/**/*.js' 'modules/default/**/*.js' 'clientonly/*.js' 'serveronly/*.js' 'translations/*.js' 'vendor/*.js' 'tests/**/*.js' 'config/*' --config .eslintrc.json --fix", + "lint:js": "eslint 'js/**/*.js' 'modules/default/**/*.js' 'clientonly/*.js' 'serveronly/*.js' 'translations/*.js' 'vendor/*.js' 'tests/**/*.js' 'config/*' --fix", "lint:css": "stylelint 'css/main.css' 'fonts/*.css' 'modules/default/**/*.css' 'vendor/*.css' --config .stylelintrc.json --fix", "lint:staged": "lint-staged", "prepare": "[ -f node_modules/.bin/husky ] && husky install || echo no husky installed." @@ -49,43 +49,42 @@ }, "homepage": "https://magicmirror.builders", "devDependencies": { - "eslint-config-prettier": "^9.0.0", - "eslint-plugin-import": "^2.28.1", - "eslint-plugin-jest": "^27.4.2", - "eslint-plugin-jsdoc": "^46.8.2", - "eslint-plugin-prettier": "^5.0.0", + "@stylistic/eslint-plugin": "^1.5.1", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jest": "^27.6.0", + "eslint-plugin-jsdoc": "^46.9.1", "express-basic-auth": "^1.2.1", "husky": "^8.0.3", "jest": "^29.7.0", - "jsdom": "^22.1.0", - "lint-staged": "^14.0.1", + "jsdom": "^23.0.1", + "lint-staged": "^15.2.0", "lodash": "^4.17.21", - "playwright": "^1.38.1", - "prettier": "^3.0.3", - "sinon": "^16.0.0", - "stylelint": "^15.10.3", - "stylelint-config-standard": "^34.0.0", - "stylelint-prettier": "^4.0.2", + "playwright": "^1.40.1", + "prettier": "^3.1.1", + "sinon": "^17.0.1", + "stylelint": "^16.1.0", + "stylelint-config-standard": "^36.0.0", + "stylelint-prettier": "^5.0.0", "suncalc": "^1.9.0" }, "optionalDependencies": { - "electron": "^26.2.4" + "electron": "^27.2.0" }, "dependencies": { "colors": "^1.4.0", + "command-exists": "^1.2.9", "console-stamp": "^3.1.2", "envsub": "^4.1.0", - "eslint": "^8.50.0", + "eslint": "^8.56.0", "express": "^4.18.2", "express-ipfilter": "^1.3.1", "feedme": "^2.0.2", - "helmet": "^7.0.0", + "helmet": "^7.1.0", "html-to-text": "^9.0.5", "iconv-lite": "^0.6.3", - "luxon": "^1.28.1", "module-alias": "^2.2.3", - "moment": "^2.29.4", - "node-ical": "^0.16.1", + "moment": "^2.30.1", + "node-ical": "^0.17.1", "socket.io": "^4.7.2" }, "lint-staged": { diff --git a/tests/configs/modules/calendar/bad_rrule.js b/tests/configs/modules/calendar/bad_rrule.js new file mode 100644 index 0000000000..5a89b5e616 --- /dev/null +++ b/tests/configs/modules/calendar/bad_rrule.js @@ -0,0 +1,27 @@ +/* MagicMirror² Test ics with out of date event causing bad return from rrule.between + * + * By Sam Detweiler + * MIT Licensed. + */ +let config = { + timeFormat: 12, + logLevel: ["INFO", "LOG", "WARN", "ERROR", "DEBUG"], + modules: [ + { + module: "calendar", + position: "bottom_bar", + config: { + calendars: [ + { + url: "http://localhost:8080/tests/mocks/bad_rrule.ics" + } + ] + } + } + ] +}; + +/*************** DO NOT EDIT THE LINE BELOW ***************/ +if (typeof module !== "undefined") { + module.exports = config; +} diff --git a/tests/configs/modules/calendar/exdate.js b/tests/configs/modules/calendar/exdate.js new file mode 100644 index 0000000000..574b24fef8 --- /dev/null +++ b/tests/configs/modules/calendar/exdate.js @@ -0,0 +1,36 @@ +/* MagicMirror² Test calendar exdate + * + * By jkriegshauser + * MIT Licensed. + * + * NOTE: calendar_test_exdate.ics has exdate entries for the next 20 years, but without some + * way to set a debug date for tests, this test may become flaky on specific days (i.e. could + * not test easily on leap-years, the BYDAY specified in exdate, etc.) or when the 20 years + * elapses if this project is still in active development ;) + * See issue #3250 + */ +let config = { + timeFormat: 12, + + modules: [ + { + module: "calendar", + position: "bottom_bar", + config: { + maximumEntries: 100, + calendars: [ + { + maximumEntries: 100, + maximumNumberOfDays: 364, + url: "http://localhost:8080/tests/mocks/calendar_test_exdate.ics" + } + ] + } + } + ] +}; + +/*************** DO NOT EDIT THE LINE BELOW ***************/ +if (typeof module !== "undefined") { + module.exports = config; +} diff --git a/tests/e2e/animateCSS_spec.js b/tests/e2e/animateCSS_spec.js index 3f7cac8354..3cb3aca607 100644 --- a/tests/e2e/animateCSS_spec.js +++ b/tests/e2e/animateCSS_spec.js @@ -5,7 +5,7 @@ * 09/2023 * MIT Licensed. */ -const helpers = require("./helpers/global-setup.js"); +const helpers = require("./helpers/global-setup"); describe("AnimateCSS integration Test", () => { // define config file for testing @@ -21,27 +21,29 @@ describe("AnimateCSS integration Test", () => { * move similar tests in function doTest * @param {string} [animationIn] animation in name of AnimateCSS to test. * @param {string} [animationOut] animation out name of AnimateCSS to test. + * @returns {boolean} result */ const doTest = async (animationIn, animationOut) => { await helpers.getDocument(); - let elem = await helpers.waitForElement(`.compliments`); - expect(elem).not.toBe(null); + let elem = await helpers.waitForElement(".compliments"); + expect(elem).not.toBeNull(); let styles = window.getComputedStyle(elem); if (animationIn && animationIn !== "") { expect(styles._values["animation-name"]).toBe(animationIn); } else { - expect(styles._values["animation-name"]).toBe(undefined); + expect(styles._values["animation-name"]).toBeUndefined(); } if (animationOut && animationOut !== "") { elem = await helpers.waitForElement(`.compliments.animate__animated.animate__${animationOut}`); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); styles = window.getComputedStyle(elem); expect(styles._values["animation-name"]).toBe(animationOut); } else { - expect(styles._values["animation-name"]).toBe(undefined); + expect(styles._values["animation-name"]).toBeUndefined(); } + return true; }; afterEach(async () => { @@ -51,28 +53,28 @@ describe("AnimateCSS integration Test", () => { describe("animateIn and animateOut Test", () => { it("with flipInX and flipOutX animation", async () => { await helpers.startApplication(testConfigFile); - await doTest("flipInX", "flipOutX"); + await expect(doTest("flipInX", "flipOutX")).resolves.toBe(true); }); }); describe("use animateOut name for animateIn (vice versa) Test", () => { it("without animation", async () => { await helpers.startApplication(testConfigFileInvertedAnimationName); - await doTest(); + await expect(doTest()).resolves.toBe(true); }); }); describe("false Animation name test", () => { it("without animation", async () => { await helpers.startApplication(testConfigFileFallbackToDefault); - await doTest(); + await expect(doTest()).resolves.toBe(true); }); }); describe("no Animation defined test", () => { it("without animation", async () => { await helpers.startApplication(testConfigByDefault); - await doTest(); + await expect(doTest()).resolves.toBe(true); }); }); }); diff --git a/tests/e2e/env_spec.js b/tests/e2e/env_spec.js index 2a9945a85f..eebc8912f0 100644 --- a/tests/e2e/env_spec.js +++ b/tests/e2e/env_spec.js @@ -21,7 +21,7 @@ describe("App environment", () => { it("should show the title MagicMirror²", async () => { const elem = await helpers.waitForElement("title"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.textContent).toBe("MagicMirror²"); }); }); diff --git a/tests/e2e/fonts_spec.js b/tests/e2e/fonts_spec.js index 706ed4a909..458ff2baaf 100644 --- a/tests/e2e/fonts_spec.js +++ b/tests/e2e/fonts_spec.js @@ -20,7 +20,7 @@ describe("All font files from roboto.css should be downloadable", () => { await helpers.stopApplication(); }); - test.each(fontFiles)("should return 200 HTTP code for file '%s'", async (fontFile) => { + it.each(fontFiles)("should return 200 HTTP code for file '%s'", async (fontFile) => { const fontUrl = `http://localhost:8080/fonts/${fontFile}`; const res = await fetch(fontUrl); expect(res.status).toBe(200); diff --git a/tests/e2e/helpers/basic-auth.js b/tests/e2e/helpers/basic-auth.js index 8307464e23..c793085ba9 100644 --- a/tests/e2e/helpers/basic-auth.js +++ b/tests/e2e/helpers/basic-auth.js @@ -1,6 +1,7 @@ const path = require("path"); const auth = require("express-basic-auth"); const express = require("express"); + const app = express(); const basicAuth = auth({ diff --git a/tests/e2e/helpers/global-setup.js b/tests/e2e/helpers/global-setup.js index d20156e5fd..31a3e036c2 100644 --- a/tests/e2e/helpers/global-setup.js +++ b/tests/e2e/helpers/global-setup.js @@ -31,6 +31,11 @@ exports.getDocument = () => { jsdom.JSDOM.fromURL(url, { resources: "usable", runScripts: "dangerously" }).then((dom) => { dom.window.name = "jsdom"; global.window = dom.window; + // Following fixes `navigator is not defined` errors in e2e tests, found here + // https://www.appsloveworld.com/reactjs/100/37/mocha-react-navigator-is-not-defined + global.navigator = { + useragent: "node.js" + }; dom.window.fetch = fetch; dom.window.onload = () => { global.document = dom.window.document; @@ -82,6 +87,7 @@ exports.waitForAllElements = (selector) => { exports.testMatch = async (element, regex) => { const elem = await this.waitForElement(element); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.textContent).toMatch(regex); + return true; }; diff --git a/tests/e2e/helpers/mock-console.js b/tests/e2e/helpers/mock-console.js index f87be96424..c593b7062e 100644 --- a/tests/e2e/helpers/mock-console.js +++ b/tests/e2e/helpers/mock-console.js @@ -4,13 +4,13 @@ */ const mockError = (err) => { if ( - err.includes("ECONNREFUSED") || - err.includes("ECONNRESET") || - err.includes("socket hang up") || - err.includes("exports is not defined") || - err.includes("write EPIPE") || - err.includes("AggregateError") || - err.includes("ERR_SOCKET_CONNECTION_TIMEOUT") + err.includes("ECONNREFUSED") + || err.includes("ECONNRESET") + || err.includes("socket hang up") + || err.includes("exports is not defined") + || err.includes("write EPIPE") + || err.includes("AggregateError") + || err.includes("ERR_SOCKET_CONNECTION_TIMEOUT") ) { jest.fn(); } else { diff --git a/tests/e2e/helpers/weather-functions.js b/tests/e2e/helpers/weather-functions.js index 02713754cf..9b55f15e6a 100644 --- a/tests/e2e/helpers/weather-functions.js +++ b/tests/e2e/helpers/weather-functions.js @@ -3,13 +3,14 @@ const helpers = require("./global-setup"); exports.getText = async (element, result) => { const elem = await helpers.waitForElement(element); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect( elem.textContent .trim() .replace(/(\r\n|\n|\r)/gm, "") .replace(/[ ]+/g, " ") ).toBe(result); + return true; }; exports.startApp = async (configFileName, additionalMockData) => { diff --git a/tests/e2e/modules/alert_spec.js b/tests/e2e/modules/alert_spec.js index c118e17ef3..f3c95a6c3c 100644 --- a/tests/e2e/modules/alert_spec.js +++ b/tests/e2e/modules/alert_spec.js @@ -11,7 +11,7 @@ describe("Alert module", () => { it("should show the welcome message", async () => { const elem = await helpers.waitForElement(".ns-box .ns-box-inner .light.bright.small"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.textContent).toContain("Welcome, start was successful!"); }); }); diff --git a/tests/e2e/modules/calendar_spec.js b/tests/e2e/modules/calendar_spec.js index 299bdf664e..e72917820f 100644 --- a/tests/e2e/modules/calendar_spec.js +++ b/tests/e2e/modules/calendar_spec.js @@ -2,25 +2,29 @@ const helpers = require("../helpers/global-setup"); const serverBasicAuth = require("../helpers/basic-auth"); describe("Calendar module", () => { + /** * @param {string} element css selector * @param {string} result expected number * @param {string} not reverse result + * @returns {boolean} result */ const testElementLength = async (element, result, not) => { const elem = await helpers.waitForAllElements(element); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); if (not === "not") { - expect(elem.length).not.toBe(result); + expect(elem).not.toHaveLength(result); } else { - expect(elem.length).toBe(result); + expect(elem).toHaveLength(result); } + return true; }; const testTextContain = async (element, text) => { const elem = await helpers.waitForElement(element, "undefinedLoading"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.textContent).toContain(text); + return true; }; afterAll(async () => { @@ -34,11 +38,11 @@ describe("Calendar module", () => { }); it("should show the default maximumEntries of 10", async () => { - await testElementLength(".calendar .event", 10); + await expect(testElementLength(".calendar .event", 10)).resolves.toBe(true); }); it("should show the default calendar symbol in each event", async () => { - await testElementLength(".calendar .event .fa-calendar-alt", 0, "not"); + await expect(testElementLength(".calendar .event .fa-calendar-alt", 0, "not")).resolves.toBe(true); }); }); @@ -49,27 +53,27 @@ describe("Calendar module", () => { }); it("should show the custom maximumEntries of 5", async () => { - await testElementLength(".calendar .event", 5); + await expect(testElementLength(".calendar .event", 5)).resolves.toBe(true); }); it("should show the custom calendar symbol in four events", async () => { - await testElementLength(".calendar .event .fa-birthday-cake", 4); + await expect(testElementLength(".calendar .event .fa-birthday-cake", 4)).resolves.toBe(true); }); it("should show a customEvent calendar symbol in one event", async () => { - await testElementLength(".calendar .event .fa-dice", 1); + await expect(testElementLength(".calendar .event .fa-dice", 1)).resolves.toBe(true); }); it("should show a customEvent calendar eventClass in one event", async () => { - await testElementLength(".calendar .event.undo", 1); + await expect(testElementLength(".calendar .event.undo", 1)).resolves.toBe(true); }); it("should show two custom icons for repeating events", async () => { - await testElementLength(".calendar .event .fa-undo", 2); + await expect(testElementLength(".calendar .event .fa-undo", 2)).resolves.toBe(true); }); it("should show two custom icons for day events", async () => { - await testElementLength(".calendar .event .fa-calendar-day", 2); + await expect(testElementLength(".calendar .event .fa-calendar-day", 2)).resolves.toBe(true); }); }); @@ -80,7 +84,7 @@ describe("Calendar module", () => { }); it("should show the recurring birthday event 6 times", async () => { - await testElementLength(".calendar .event", 6); + await expect(testElementLength(".calendar .event", 6)).resolves.toBe(true); }); }); @@ -91,7 +95,7 @@ describe("Calendar module", () => { }); it("should show multiple events with the same title and start time from different calendars", async () => { - await testElementLength(".calendar .event", 22); + await expect(testElementLength(".calendar .event", 22)).resolves.toBe(true); }); }); @@ -107,7 +111,7 @@ describe("Calendar module", () => { }); it(`should contain text "Mar 25th" in timezone UTC ${-i}`, async () => { - await testTextContain(".calendar", "Mar 25th"); + await expect(testTextContain(".calendar", "Mar 25th")).resolves.toBe(true); }); }); } @@ -124,7 +128,7 @@ describe("Calendar module", () => { }); it("should return TestEvents", async () => { - await testElementLength(".calendar .event", 0, "not"); + await expect(testElementLength(".calendar .event", 0, "not")).resolves.toBe(true); }); }); @@ -135,7 +139,7 @@ describe("Calendar module", () => { }); it("should return TestEvents", async () => { - await testElementLength(".calendar .event", 0, "not"); + await expect(testElementLength(".calendar .event", 0, "not")).resolves.toBe(true); }); }); @@ -146,7 +150,7 @@ describe("Calendar module", () => { }); it("should return TestEvents", async () => { - await testElementLength(".calendar .event", 0, "not"); + await expect(testElementLength(".calendar .event", 0, "not")).resolves.toBe(true); }); }); @@ -157,7 +161,7 @@ describe("Calendar module", () => { }); it("should return TestEvents", async () => { - await testElementLength(".calendar .event", 0, "not"); + await expect(testElementLength(".calendar .event", 0, "not")).resolves.toBe(true); }); }); @@ -173,7 +177,7 @@ describe("Calendar module", () => { }); it("should show Unauthorized error", async () => { - await testTextContain(".calendar", "Error in the calendar module. Authorization failed"); + await expect(testTextContain(".calendar", "Error in the calendar module. Authorization failed")).resolves.toBe(true); }); }); }); diff --git a/tests/e2e/modules/clock_es_spec.js b/tests/e2e/modules/clock_es_spec.js index 4bdc4bccf7..134c795b0a 100644 --- a/tests/e2e/modules/clock_es_spec.js +++ b/tests/e2e/modules/clock_es_spec.js @@ -13,12 +13,12 @@ describe("Clock set to spanish language module", () => { it("shows date with correct format", async () => { const dateRegex = /^(?:lunes|martes|miércoles|jueves|viernes|sábado|domingo), \d{1,2} de (?:enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre) de \d{4}$/; - await helpers.testMatch(".clock .date", dateRegex); + await expect(helpers.testMatch(".clock .date", dateRegex)).resolves.toBe(true); }); it("shows time in 24hr format", async () => { const timeRegex = /^(?:2[0-3]|[01]\d):[0-5]\d[0-5]\d$/; - await helpers.testMatch(".clock .time", timeRegex); + await expect(helpers.testMatch(".clock .time", timeRegex)).resolves.toBe(true); }); }); @@ -30,12 +30,12 @@ describe("Clock set to spanish language module", () => { it("shows date with correct format", async () => { const dateRegex = /^(?:lunes|martes|miércoles|jueves|viernes|sábado|domingo), \d{1,2} de (?:enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre) de \d{4}$/; - await helpers.testMatch(".clock .date", dateRegex); + await expect(helpers.testMatch(".clock .date", dateRegex)).resolves.toBe(true); }); it("shows time in 12hr format", async () => { const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[ap]m$/; - await helpers.testMatch(".clock .time", timeRegex); + await expect(helpers.testMatch(".clock .time", timeRegex)).resolves.toBe(true); }); }); @@ -47,7 +47,7 @@ describe("Clock set to spanish language module", () => { it("shows 12hr time with upper case AM/PM", async () => { const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[AP]M$/; - await helpers.testMatch(".clock .time", timeRegex); + await expect(helpers.testMatch(".clock .time", timeRegex)).resolves.toBe(true); }); }); @@ -59,7 +59,7 @@ describe("Clock set to spanish language module", () => { it("shows week with correct format", async () => { const weekRegex = /^Semana [0-9]{1,2}$/; - await helpers.testMatch(".clock .week", weekRegex); + await expect(helpers.testMatch(".clock .week", weekRegex)).resolves.toBe(true); }); }); }); diff --git a/tests/e2e/modules/clock_spec.js b/tests/e2e/modules/clock_spec.js index d1a940f12e..651b20de66 100644 --- a/tests/e2e/modules/clock_spec.js +++ b/tests/e2e/modules/clock_spec.js @@ -14,12 +14,12 @@ describe("Clock module", () => { it("should show the date in the correct format", async () => { const dateRegex = /^(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (?:January|February|March|April|May|June|July|August|September|October|November|December) \d{1,2}, \d{4}$/; - await helpers.testMatch(".clock .date", dateRegex); + await expect(helpers.testMatch(".clock .date", dateRegex)).resolves.toBe(true); }); it("should show the time in 24hr format", async () => { const timeRegex = /^(?:2[0-3]|[01]\d):[0-5]\d[0-5]\d$/; - await helpers.testMatch(".clock .time", timeRegex); + await expect(helpers.testMatch(".clock .time", timeRegex)).resolves.toBe(true); }); }); @@ -31,12 +31,12 @@ describe("Clock module", () => { it("should show the date in the correct format", async () => { const dateRegex = /^(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (?:January|February|March|April|May|June|July|August|September|October|November|December) \d{1,2}, \d{4}$/; - await helpers.testMatch(".clock .date", dateRegex); + await expect(helpers.testMatch(".clock .date", dateRegex)).resolves.toBe(true); }); it("should show the time in 12hr format", async () => { const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[ap]m$/; - await helpers.testMatch(".clock .time", timeRegex); + await expect(helpers.testMatch(".clock .time", timeRegex)).resolves.toBe(true); }); }); @@ -48,7 +48,7 @@ describe("Clock module", () => { it("should show 12hr time with upper case AM/PM", async () => { const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[AP]M$/; - await helpers.testMatch(".clock .time", timeRegex); + await expect(helpers.testMatch(".clock .time", timeRegex)).resolves.toBe(true); }); }); @@ -60,7 +60,7 @@ describe("Clock module", () => { it("should show 12hr time without seconds am/pm", async () => { const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[ap]m$/; - await helpers.testMatch(".clock .time", timeRegex); + await expect(helpers.testMatch(".clock .time", timeRegex)).resolves.toBe(true); }); }); @@ -72,7 +72,7 @@ describe("Clock module", () => { it("should not show the time when digital clock is shown", async () => { const elem = document.querySelector(".clock .digital .time"); - expect(elem).toBe(null); + expect(elem).toBeNull(); }); }); @@ -84,12 +84,12 @@ describe("Clock module", () => { it("should show the sun times", async () => { const elem = await helpers.waitForElement(".clock .digital .sun"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); }); it("should show the moon times", async () => { const elem = await helpers.waitForElement(".clock .digital .moon"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); }); }); @@ -101,14 +101,14 @@ describe("Clock module", () => { it("should show the week in the correct format", async () => { const weekRegex = /^Week [0-9]{1,2}$/; - await helpers.testMatch(".clock .week", weekRegex); + await expect(helpers.testMatch(".clock .week", weekRegex)).resolves.toBe(true); }); it("should show the week with the correct number of week of year", async () => { const currentWeekNumber = moment().week(); const weekToShow = `Week ${currentWeekNumber}`; const elem = await helpers.waitForElement(".clock .week"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.textContent).toBe(weekToShow); }); }); @@ -121,7 +121,7 @@ describe("Clock module", () => { it("should show the analog clock face", async () => { const elem = helpers.waitForElement(".clock-circle"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); }); }); @@ -133,9 +133,9 @@ describe("Clock module", () => { it("should show the analog clock face and the date", async () => { const elemClock = helpers.waitForElement(".clock-circle"); - await expect(elemClock).not.toBe(null); + await expect(elemClock).not.toBeNull(); const elemDate = helpers.waitForElement(".clock .date"); - await expect(elemDate).not.toBe(null); + await expect(elemDate).not.toBeNull(); }); }); }); diff --git a/tests/e2e/modules/compliments_spec.js b/tests/e2e/modules/compliments_spec.js index 97c044f3e6..0604dab49f 100644 --- a/tests/e2e/modules/compliments_spec.js +++ b/tests/e2e/modules/compliments_spec.js @@ -1,16 +1,19 @@ const helpers = require("../helpers/global-setup"); describe("Compliments module", () => { + /** * move similar tests in function doTest * @param {Array} complimentsArray The array of compliments. + * @returns {boolean} result */ const doTest = async (complimentsArray) => { let elem = await helpers.waitForElement(".compliments"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); elem = await helpers.waitForElement(".module-content"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(complimentsArray).toContain(elem.textContent); + return true; }; afterAll(async () => { @@ -18,14 +21,14 @@ describe("Compliments module", () => { }); describe("Feature anytime in compliments module", () => { - describe("Set anytime and empty compliments for morning, evening and afternoon ", () => { + describe("Set anytime and empty compliments for morning, evening and afternoon", () => { beforeAll(async () => { await helpers.startApplication("tests/configs/modules/compliments/compliments_anytime.js"); await helpers.getDocument(); }); it("shows anytime because if configure empty parts of day compliments and set anytime compliments", async () => { - await doTest(["Anytime here"]); + await expect(doTest(["Anytime here"])).resolves.toBe(true); }); }); @@ -36,7 +39,7 @@ describe("Compliments module", () => { }); it("shows anytime compliments", async () => { - await doTest(["Anytime here"]); + await expect(doTest(["Anytime here"])).resolves.toBe(true); }); }); }); @@ -48,7 +51,7 @@ describe("Compliments module", () => { }); it("should show compliments from a remote file", async () => { - await doTest(["Remote compliment file works!"]); + await expect(doTest(["Remote compliment file works!"])).resolves.toBe(true); }); }); }); diff --git a/tests/e2e/modules/helloworld_spec.js b/tests/e2e/modules/helloworld_spec.js index ecdcdf2076..413c60e509 100644 --- a/tests/e2e/modules/helloworld_spec.js +++ b/tests/e2e/modules/helloworld_spec.js @@ -13,7 +13,7 @@ describe("Test helloworld module", () => { it("Test message helloworld module", async () => { const elem = await helpers.waitForElement(".helloworld"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.textContent).toContain("Test HelloWorld Module"); }); }); @@ -26,7 +26,7 @@ describe("Test helloworld module", () => { it("Test message helloworld module", async () => { const elem = await helpers.waitForElement(".helloworld"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.textContent).toContain("Hello World!"); }); }); diff --git a/tests/e2e/modules/newsfeed_spec.js b/tests/e2e/modules/newsfeed_spec.js index 5d419954d8..141b880661 100644 --- a/tests/e2e/modules/newsfeed_spec.js +++ b/tests/e2e/modules/newsfeed_spec.js @@ -13,20 +13,20 @@ describe("Newsfeed module", () => { it("should show the newsfeed title", async () => { const elem = await helpers.waitForElement(".newsfeed .newsfeed-source"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.textContent).toContain("Rodrigo Ramirez Blog"); }); it("should show the newsfeed article", async () => { const elem = await helpers.waitForElement(".newsfeed .newsfeed-title"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.textContent).toContain("QPanel"); }); it("should NOT show the newsfeed description", async () => { await helpers.waitForElement(".newsfeed"); const elem = document.querySelector(".newsfeed .newsfeed-desc"); - expect(elem).toBe(null); + expect(elem).toBeNull(); }); }); @@ -38,14 +38,14 @@ describe("Newsfeed module", () => { it("should not show articles with prohibited words", async () => { const elem = await helpers.waitForElement(".newsfeed .newsfeed-title"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.textContent).toContain("Problema VirtualBox"); }); it("should show the newsfeed description", async () => { const elem = await helpers.waitForElement(".newsfeed .newsfeed-desc"); - expect(elem).not.toBe(null); - expect(elem.textContent.length).not.toBe(0); + expect(elem).not.toBeNull(); + expect(elem.textContent).not.toHaveLength(0); }); }); @@ -57,7 +57,7 @@ describe("Newsfeed module", () => { it("should show malformed url warning", async () => { const elem = await helpers.waitForElement(".newsfeed .small", "No news at the moment."); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.textContent).toContain("Error in the Newsfeed module. Malformed url."); }); }); @@ -70,7 +70,7 @@ describe("Newsfeed module", () => { it("should show empty items info message", async () => { const elem = await helpers.waitForElement(".newsfeed .small"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.textContent).toContain("No news at the moment."); }); }); diff --git a/tests/e2e/modules/weather_current_spec.js b/tests/e2e/modules/weather_current_spec.js index d97f83094e..cc9ea38f52 100644 --- a/tests/e2e/modules/weather_current_spec.js +++ b/tests/e2e/modules/weather_current_spec.js @@ -15,15 +15,15 @@ describe("Weather module", () => { }); it("should render wind speed and wind direction", async () => { - await weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "12 WSW"); + await expect(weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "12 WSW")).resolves.toBe(true); }); it("should render temperature with icon", async () => { - await weatherFunc.getText(".weather .large.light span.bright", "1.5°"); + await expect(weatherFunc.getText(".weather .large.light span.bright", "1.5°")).resolves.toBe(true); }); it("should render feels like temperature", async () => { - await weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like -5.6°"); + await expect(weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like -5.6°")).resolves.toBe(true); }); }); }); @@ -34,7 +34,7 @@ describe("Weather module", () => { }); it("should render a compliment based on the current weather", async () => { - await weatherFunc.getText(".compliments .module-content span", "snow"); + await expect(weatherFunc.getText(".compliments .module-content span", "snow")).resolves.toBe(true); }); }); @@ -44,25 +44,25 @@ describe("Weather module", () => { }); it("should render windUnits in beaufort", async () => { - await weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "6"); + await expect(weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "6")).resolves.toBe(true); }); it("should render windDirection with an arrow", async () => { const elem = await helpers.waitForElement(".weather .normal.medium sup i.fa-long-arrow-alt-down"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.outerHTML).toContain("transform:rotate(250deg)"); }); it("should render humidity", async () => { - await weatherFunc.getText(".weather .normal.medium span:nth-child(3)", "93.7"); + await expect(weatherFunc.getText(".weather .normal.medium span:nth-child(3)", "93.7")).resolves.toBe(true); }); it("should render degreeLabel for temp", async () => { - await weatherFunc.getText(".weather .large.light span.bright", "1°C"); + await expect(weatherFunc.getText(".weather .large.light span.bright", "1°C")).resolves.toBe(true); }); it("should render degreeLabel for feels like", async () => { - await weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like -6°C"); + await expect(weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like -6°C")).resolves.toBe(true); }); }); @@ -72,15 +72,15 @@ describe("Weather module", () => { }); it("should render wind in imperial units", async () => { - await weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "26 WSW"); + await expect(weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "26 WSW")).resolves.toBe(true); }); it("should render temperatures in fahrenheit", async () => { - await weatherFunc.getText(".weather .large.light span.bright", "34,7°"); + await expect(weatherFunc.getText(".weather .large.light span.bright", "34,7°")).resolves.toBe(true); }); it("should render 'feels like' in fahrenheit", async () => { - await weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like 21,9°"); + await expect(weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like 21,9°")).resolves.toBe(true); }); }); }); diff --git a/tests/e2e/modules/weather_forecast_spec.js b/tests/e2e/modules/weather_forecast_spec.js index a5ce70d20a..da4c918875 100644 --- a/tests/e2e/modules/weather_forecast_spec.js +++ b/tests/e2e/modules/weather_forecast_spec.js @@ -16,7 +16,7 @@ describe("Weather module: Weather Forecast", () => { const days = ["Today", "Tomorrow", "Sun", "Mon", "Tue"]; for (const [index, day] of days.entries()) { it(`should render day ${day}`, async () => { - await weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(1)`, day); + await expect(weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(1)`, day)).resolves.toBe(true); }); } @@ -24,21 +24,21 @@ describe("Weather module: Weather Forecast", () => { for (const [index, icon] of icons.entries()) { it(`should render icon ${icon}`, async () => { const elem = await helpers.waitForElement(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(2) span.wi-${icon}`); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); }); } const maxTemps = ["24.4°", "21.0°", "22.9°", "23.4°", "20.6°"]; for (const [index, temp] of maxTemps.entries()) { it(`should render max temperature ${temp}`, async () => { - await weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(3)`, temp); + await expect(weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(3)`, temp)).resolves.toBe(true); }); } const minTemps = ["15.3°", "13.6°", "13.8°", "13.9°", "10.9°"]; for (const [index, temp] of minTemps.entries()) { it(`should render min temperature ${temp}`, async () => { - await weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(4)`, temp); + await expect(weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(4)`, temp)).resolves.toBe(true); }); } @@ -46,7 +46,7 @@ describe("Weather module: Weather Forecast", () => { for (const [index, opacity] of opacities.entries()) { it(`should render fading of rows with opacity=${opacity}`, async () => { const elem = await helpers.waitForElement(`.weather table.small tr:nth-child(${index + 1})`); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.outerHTML).toContain(``); }); } @@ -60,7 +60,7 @@ describe("Weather module: Weather Forecast", () => { const days = ["Fri", "Sat", "Sun", "Mon", "Tue"]; for (const [index, day] of days.entries()) { it(`should render day ${day}`, async () => { - await weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(1)`, day); + await expect(weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(1)`, day)).resolves.toBe(true); }); } }); @@ -72,21 +72,21 @@ describe("Weather module: Weather Forecast", () => { it("should render custom table class", async () => { const elem = await helpers.waitForElement(".weather table.myTableClass"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); }); it("should render colored rows", async () => { const table = await helpers.waitForElement(".weather table.myTableClass"); - expect(table).not.toBe(null); - expect(table.rows).not.toBe(null); - expect(table.rows.length).toBe(5); + expect(table).not.toBeNull(); + expect(table.rows).not.toBeNull(); + expect(table.rows).toHaveLength(5); }); const precipitations = [undefined, "2.51 mm"]; for (const [index, precipitation] of precipitations.entries()) { if (precipitation) { it(`should render precipitation amount ${precipitation}`, async () => { - await weatherFunc.getText(`.weather table tr:nth-child(${index + 1}) td.precipitation-amount`, precipitation); + await expect(weatherFunc.getText(`.weather table tr:nth-child(${index + 1}) td.precipitation-amount`, precipitation)).resolves.toBe(true); }); } } @@ -101,7 +101,7 @@ describe("Weather module: Weather Forecast", () => { const temperatures = ["75_9°", "69_8°", "73_2°", "74_1°", "69_1°"]; for (const [index, temp] of temperatures.entries()) { it(`should render custom decimalSymbol = '_' for temp ${temp}`, async () => { - await weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(3)`, temp); + await expect(weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(3)`, temp)).resolves.toBe(true); }); } }); @@ -111,7 +111,7 @@ describe("Weather module: Weather Forecast", () => { for (const [index, precipitation] of precipitations.entries()) { if (precipitation) { it(`should render precipitation amount ${precipitation}`, async () => { - await weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td.precipitation-amount`, precipitation); + await expect(weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td.precipitation-amount`, precipitation)).resolves.toBe(true); }); } } diff --git a/tests/e2e/modules/weather_hourly_spec.js b/tests/e2e/modules/weather_hourly_spec.js index 87fc4411cb..f61cee0546 100644 --- a/tests/e2e/modules/weather_hourly_spec.js +++ b/tests/e2e/modules/weather_hourly_spec.js @@ -16,7 +16,7 @@ describe("Weather module: Weather Hourly Forecast", () => { const minTemps = ["7:00 pm", "8:00 pm", "9:00 pm", "10:00 pm", "11:00 pm"]; for (const [index, hour] of minTemps.entries()) { it(`should render forecast for hour ${hour}`, async () => { - await weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td.day`, hour); + await expect(weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td.day`, hour)).resolves.toBe(true); }); } }); @@ -30,7 +30,7 @@ describe("Weather module: Weather Hourly Forecast", () => { const minTemps = ["7:00 pm", "9:00 pm", "11:00 pm", "1:00 am", "3:00 am"]; for (const [index, hour] of minTemps.entries()) { it(`should render forecast for hour ${hour}`, async () => { - await weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td.day`, hour); + await expect(weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td.day`, hour)).resolves.toBe(true); }); } }); @@ -46,7 +46,7 @@ describe("Weather module: Weather Hourly Forecast", () => { for (const [index, amount] of amounts.entries()) { if (amount) { it(`should render precipitation amount ${amount}`, async () => { - await weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td.precipitation-amount`, amount); + await expect(weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td.precipitation-amount`, amount)).resolves.toBe(true); }); } } @@ -57,7 +57,7 @@ describe("Weather module: Weather Hourly Forecast", () => { for (const [index, pop] of propabilities.entries()) { if (pop) { it(`should render probability ${pop}`, async () => { - await weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td.precipitation-prob`, pop); + await expect(weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td.precipitation-prob`, pop)).resolves.toBe(true); }); } } diff --git a/tests/e2e/modules_display_spec.js b/tests/e2e/modules_display_spec.js index 15520d05c9..c8dba6e9f8 100644 --- a/tests/e2e/modules_display_spec.js +++ b/tests/e2e/modules_display_spec.js @@ -11,14 +11,14 @@ describe("Display of modules", () => { it("should show the test header", async () => { const elem = await helpers.waitForElement("#module_0_helloworld .module-header"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); // textContent gibt hier lowercase zurück, das uppercase wird durch css realisiert, was daher nicht in textContent landet expect(elem.textContent).toBe("test_header"); }); it("should show no header if no header text is specified", async () => { const elem = await helpers.waitForElement("#module_1_helloworld .module-header"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.textContent).toBe("undefined"); }); }); diff --git a/tests/e2e/modules_empty_spec.js b/tests/e2e/modules_empty_spec.js index dfe6c0813c..535e3141c8 100644 --- a/tests/e2e/modules_empty_spec.js +++ b/tests/e2e/modules_empty_spec.js @@ -11,13 +11,13 @@ describe("Check configuration without modules", () => { it("shows the message MagicMirror² title", async () => { const elem = await helpers.waitForElement("#module_1_helloworld .module-content"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.textContent).toContain("MagicMirror²"); }); it("shows the url of michael's website", async () => { const elem = await helpers.waitForElement("#module_5_helloworld .module-content"); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.textContent).toContain("www.michaelteeuw.nl"); }); }); diff --git a/tests/e2e/modules_position_spec.js b/tests/e2e/modules_position_spec.js index b23ebeb24e..0aa8379092 100644 --- a/tests/e2e/modules_position_spec.js +++ b/tests/e2e/modules_position_spec.js @@ -15,7 +15,7 @@ describe("Position of modules", () => { const className = position.replace("_", "."); it(`should show text in ${position}`, async () => { const elem = await helpers.waitForElement(`.${className}`); - expect(elem).not.toBe(null); + expect(elem).not.toBeNull(); expect(elem.textContent).toContain(`Text in ${position}`); }); } diff --git a/tests/e2e/serveronly_spec.js b/tests/e2e/serveronly_spec.js index 82d0429b83..9a6f29ba75 100644 --- a/tests/e2e/serveronly_spec.js +++ b/tests/e2e/serveronly_spec.js @@ -1,5 +1,3 @@ -const helpers = require("./helpers/global-setup"); - const delay = (time) => { return new Promise((resolve) => setTimeout(resolve, time)); }; diff --git a/tests/e2e/translations_spec.js b/tests/e2e/translations_spec.js index ec1387572f..a0124fc9af 100644 --- a/tests/e2e/translations_spec.js +++ b/tests/e2e/translations_spec.js @@ -44,100 +44,110 @@ describe("Translations", () => { ); }); - it("should load translation file", (done) => { - dom.window.onload = async () => { - const { Translator, Module, config } = dom.window; - config.language = "en"; - Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null); + it("should load translation file", () => { + return new Promise((done) => { + dom.window.onload = async () => { + const { Translator, Module, config } = dom.window; + config.language = "en"; + Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null); - Module.register("name", { getTranslations: () => translations }); - const MMM = Module.create("name"); + Module.register("name", { getTranslations: () => translations }); + const MMM = Module.create("name"); - await MMM.loadTranslations(); + await MMM.loadTranslations(); - expect(Translator.load.args.length).toBe(1); - expect(Translator.load.calledWith(MMM, "translations/en.json", false)).toBe(true); + expect(Translator.load.args).toHaveLength(1); + expect(Translator.load.calledWith(MMM, "translations/en.json", false)).toBe(true); - done(); - }; + done(); + }; + }); }); - it("should load translation + fallback file", (done) => { - dom.window.onload = async () => { - const { Translator, Module } = dom.window; - Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null); + it("should load translation + fallback file", () => { + return new Promise((done) => { + dom.window.onload = async () => { + const { Translator, Module } = dom.window; + Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null); - Module.register("name", { getTranslations: () => translations }); - const MMM = Module.create("name"); + Module.register("name", { getTranslations: () => translations }); + const MMM = Module.create("name"); - await MMM.loadTranslations(); + await MMM.loadTranslations(); - expect(Translator.load.args.length).toBe(2); - expect(Translator.load.calledWith(MMM, "translations/de.json", false)).toBe(true); - expect(Translator.load.calledWith(MMM, "translations/en.json", true)).toBe(true); + expect(Translator.load.args).toHaveLength(2); + expect(Translator.load.calledWith(MMM, "translations/de.json", false)).toBe(true); + expect(Translator.load.calledWith(MMM, "translations/en.json", true)).toBe(true); - done(); - }; + done(); + }; + }); }); - it("should load translation fallback file", (done) => { - dom.window.onload = async () => { - const { Translator, Module, config } = dom.window; - config.language = "--"; - Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null); + it("should load translation fallback file", () => { + return new Promise((done) => { + dom.window.onload = async () => { + const { Translator, Module, config } = dom.window; + config.language = "--"; + Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null); - Module.register("name", { getTranslations: () => translations }); - const MMM = Module.create("name"); + Module.register("name", { getTranslations: () => translations }); + const MMM = Module.create("name"); - await MMM.loadTranslations(); + await MMM.loadTranslations(); - expect(Translator.load.args.length).toBe(1); - expect(Translator.load.calledWith(MMM, "translations/en.json", true)).toBe(true); + expect(Translator.load.args).toHaveLength(1); + expect(Translator.load.calledWith(MMM, "translations/en.json", true)).toBe(true); - done(); - }; + done(); + }; + }); }); - it("should load no file", (done) => { - dom.window.onload = async () => { - const { Translator, Module } = dom.window; - Translator.load = sinon.stub(); + it("should load no file", () => { + return new Promise((done) => { + dom.window.onload = async () => { + const { Translator, Module } = dom.window; + Translator.load = sinon.stub(); - Module.register("name", {}); - const MMM = Module.create("name"); + Module.register("name", {}); + const MMM = Module.create("name"); - await MMM.loadTranslations(); + await MMM.loadTranslations(); - expect(Translator.load.callCount).toBe(0); + expect(Translator.load.callCount).toBe(0); - done(); - }; + done(); + }; + }); }); }); const mmm = { name: "TranslationTest", - file(file) { + file (file) { return `http://localhost:3000/${file}`; } }; describe("Parsing language files through the Translator class", () => { for (let language in translations) { - it(`should parse ${language}`, (done) => { - const dom = new JSDOM( - `\ + it(`should parse ${language}`, () => { + return new Promise((done) => { + const dom = new JSDOM( + `\ \ + beforeAll(() => { + return new Promise((done) => { + const dom = new JSDOM( + `\ \ + beforeAll(() => { + return new Promise((done) => { + const dom = new JSDOM( + `\ \ + beforeAll(() => { + return new Promise((done) => { + dom = new JSDOM( + `\ \ + it("should load core translations and fallback", () => { + return new Promise((done) => { + const dom = new JSDOM( + `\ \ + it("should load core fallback if language cannot be found", () => { + return new Promise((done) => { + const dom = new JSDOM( + `\ \ + it("should load core translations fallback", () => { + return new Promise((done) => { + const dom = new JSDOM( + `\ \ + it("should load core fallback if language cannot be found", () => { + return new Promise((done) => { + const dom = new JSDOM( + `\ \ + beforeAll(() => { + return new Promise((done) => { + const dom = new JSDOM( + `\