diff --git a/.eslintrc.json b/.eslintrc.json index 72143745..bc80bbf1 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,9 +1,9 @@ { - "extends": ["eslint:recommended", "plugin:import/recommended", "plugin:jest/recommended", "plugin:jsdoc/recommended", "plugin:prettier/recommended"], + "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 } @@ -38,6 +38,46 @@ "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.sample"], + "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/.prettierignore b/.prettierignore index b115c755..231245b1 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,4 @@ -.eslintignore +*.js .prettierignore /config /coverage diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fc22833..9148f9dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ _This release is scheduled to be released on 2024-01-01._ - 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 ### Fixed diff --git a/clientonly/index.js b/clientonly/index.js index e13b0873..cee8ba22 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 e54be6fa..06ff3a5d 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/js/animateCSS.js b/js/animateCSS.js index cf3f26bc..b4db77b9 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 0d675845..822021dc 100644 --- a/js/app.js +++ b/js/app.js @@ -47,7 +47,7 @@ process.on("uncaughtException", function (err) { * The core app. * @class */ -function App() { +function App () { let nodeHelpers = []; let httpServer; @@ -56,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`); @@ -136,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; @@ -150,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}`; @@ -204,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) { @@ -221,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 22a10918..3d868bd5 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 625785d4..c3a0ab22 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,14 +78,14 @@ 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; } diff --git a/js/electron.js b/js/electron.js index 9659e46f..07364294 100644 --- a/js/electron.js +++ b/js/electron.js @@ -25,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); @@ -121,11 +121,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 a5dc36fc..b4b32f4f 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 9ccded66..228c53e9 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") { @@ -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 c7d4d39f..7bda7aba 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 4ef3ab1d..d9d40ac5 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 c555eb72..dee0beeb 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 0cb1b922..726a18e3 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 a11e81a5..c975df7c 100644 --- a/js/server_functions.js +++ b/js/server_functions.js @@ -9,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); } @@ -18,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); } @@ -31,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; @@ -68,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) { @@ -89,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) { @@ -106,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); @@ -124,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 2ebb0580..d329ffd0 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 1bd11d02..da262923 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 5a7426e9..fcf7f345 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 7c06a124..bfb49af7 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -75,17 +75,17 @@ Module.register("calendar", { 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. @@ -93,7 +93,7 @@ Module.register("calendar", { }, // Override start method. - start: function () { + start () { Log.info(`Starting module: ${this.name}`); if (this.config.colored) { @@ -169,7 +169,7 @@ Module.register("calendar", { }, // Override socket notification handler. - socketNotificationReceived: function (notification, payload) { + socketNotificationReceived (notification, payload) { if (notification === "FETCH_CALENDAR") { this.sendSocketNotification(notification, { url: payload.url, id: this.identifier }); } @@ -210,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; @@ -552,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; @@ -567,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; @@ -617,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 @@ -686,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; @@ -701,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, @@ -724,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")) { @@ -751,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; @@ -764,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", ""); }, @@ -773,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", ""); }, @@ -782,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", ""); }, @@ -791,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", ""); }, @@ -801,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"); }, @@ -810,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); }, @@ -819,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); }, @@ -828,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); }, @@ -839,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]; @@ -849,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); @@ -860,7 +865,7 @@ Module.register("calendar", { return p; }, - hasCalendarProperty: function (url, property) { + hasCalendarProperty (url, property) { return !!this.getCalendarProperty(url, property, undefined); }, @@ -868,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); @@ -888,7 +893,7 @@ Module.register("calendar", { * 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: function () { + selfUpdate () { const ONE_MINUTE = 60 * 1000; setTimeout( () => { diff --git a/modules/default/calendar/calendarfetcherutils.js b/modules/default/calendar/calendarfetcherutils.js index 35b43cbc..af48b7e7 100644 --- a/modules/default/calendar/calendarfetcherutils.js +++ b/modules/default/calendar/calendarfetcherutils.js @@ -15,6 +15,7 @@ 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 @@ -22,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) { @@ -123,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 @@ -142,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) { @@ -521,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 @@ -533,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; @@ -549,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; } @@ -572,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]), @@ -593,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 1bfdf159..68aef521 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 ""; } @@ -98,7 +99,7 @@ const CalendarUtils = { * 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 tr in titleReplace) { let transform = titleReplace[tr]; diff --git a/modules/default/calendar/node_helper.js b/modules/default/calendar/node_helper.js index 05d4d457..c0d46ae4 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 b2c94fbf..6b4ae324 100644 --- a/modules/default/clock/clock.js +++ b/modules/default/clock/clock.js @@ -37,15 +37,15 @@ Module.register("clock", { 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); } @@ -211,12 +211,12 @@ Module.register("clock", { const showFraction = ["both", "percent"].includes(this.config.showMoonTimes); const showUnicode = ["both", "phase"].includes(this.config.showMoonTimes); const illuminatedFractionString = `${Math.round(moonIllumination.fraction * 100)}%`; - const image = showUnicode ? [..."๐ŸŒ‘๐ŸŒ’๐ŸŒ“๐ŸŒ”๐ŸŒ•๐ŸŒ–๐ŸŒ—๐ŸŒ˜"][Math.floor(moonIllumination.phase * 8)] : ''; + const image = showUnicode ? [..."๐ŸŒ‘๐ŸŒ’๐ŸŒ“๐ŸŒ”๐ŸŒ•๐ŸŒ–๐ŸŒ—๐ŸŒ˜"][Math.floor(moonIllumination.phase * 8)] : ""; - moonWrapper.innerHTML = - `${image} ${showFraction ? illuminatedFractionString : ""}` + - ` ${moonRise ? formatTime(this.config, moonRise) : "..."}` + - ` ${moonSet ? formatTime(this.config, moonSet) : "..."}`; + 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 a905581b..374cd54f 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 53357d0f..6adb382e 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 eee0b44a..27114d8e 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/node_helper.js b/modules/default/newsfeed/node_helper.js index 64ba5929..2110fde4 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 3628dc49..8efe478d 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 4061d2ad..c78f413d 100644 --- a/modules/default/updatenotification/node_helper.js +++ b/modules/default/updatenotification/node_helper.js @@ -14,7 +14,7 @@ module.exports = NodeHelper.create({ 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); @@ -26,7 +26,7 @@ module.exports = NodeHelper.create({ } }, - async socketNotificationReceived(notification, payload) { + async socketNotificationReceived (notification, payload) { switch (notification) { case "CONFIG": this.config = payload; @@ -51,7 +51,7 @@ module.exports = NodeHelper.create({ } }, - async performFetch() { + async performFetch () { const repos = await this.gitHelper.getRepos(); for (const repo of repos) { @@ -76,7 +76,7 @@ module.exports = NodeHelper.create({ this.scheduleNextFetch(this.config.updateInterval); }, - scheduleNextFetch(delay) { + scheduleNextFetch (delay) { clearTimeout(this.updateTimer); this.updateTimer = setTimeout( @@ -87,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 index 41eb66b4..25fd0aaa 100644 --- a/modules/default/updatenotification/update_helper.js +++ b/modules/default/updatenotification/update_helper.js @@ -39,7 +39,7 @@ const Log = require("logger"); */ class Updater { - constructor(config) { + constructor (config) { this.updates = config.updates; this.timeout = config.updateTimeout; this.autoRestart = config.updateAutorestart; @@ -53,7 +53,7 @@ class Updater { } // [main command] parse if module update is needed - async parse(modules) { + async parse (modules) { var parser = modules.map(async (module) => { if (this.moduleList[module.module] === undefined) { this.moduleList[module.module] = {}; @@ -90,7 +90,7 @@ class Updater { // updated: , // if updated successfully // needRestart: // if magicmirror restart required //}; - updateProcess(module) { + updateProcess (module) { let Result = { error: false, updated: false, @@ -130,13 +130,13 @@ class Updater { } // restart rules (pm2 or npm start) - restart() { + restart () { if (this.usePM2) this.pm2Restart(); else this.npmRestart(); } // restart MagicMiror with "pm2" - pm2Restart() { + pm2Restart () { Log.info("updatenotification: PM2 will restarting MagicMirror..."); Exec(`pm2 restart ${this.PM2}`, (err, std, sde) => { if (err) { @@ -146,7 +146,7 @@ class Updater { } // restart MagicMiror with "npm start" - npmRestart() { + npmRestart () { Log.info("updatenotification: Restarting MagicMirror..."); const out = process.stdout; const err = process.stderr; @@ -156,7 +156,7 @@ class Updater { } // Check using pm2 - check_PM2_Process() { + check_PM2_Process () { Log.info("updatenotification: Checking PM2 using..."); return new Promise((resolve) => { commandExists("pm2") @@ -191,7 +191,7 @@ class Updater { } // Get the list of pm2 process - PM2_GetList() { + PM2_GetList () { return new Promise((resolve) => { Exec("pm2 jlist", (err, std, sde) => { if (err) { @@ -211,13 +211,13 @@ class Updater { } // check if module is MagicMirror - isMagicMirror(module) { + isMagicMirror (module) { if (module === "MagicMirror") return true; return false; } // search update module command - applyCommand(module) { + applyCommand (module) { if (this.isMagicMirror(module.module)) return null; let command = null; this.updates.forEach((updater) => { diff --git a/modules/default/updatenotification/updatenotification.js b/modules/default/updatenotification/updatenotification.js index 7cfc1cea..7c5f595a 100644 --- a/modules/default/updatenotification/updatenotification.js +++ b/modules/default/updatenotification/updatenotification.js @@ -20,7 +20,7 @@ Module.register("updatenotification", { needRestart: false, updates: {}, - start() { + start () { Log.info(`Starting module: ${this.name}`); this.addFilters(); setInterval(() => { @@ -29,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); @@ -50,7 +50,7 @@ Module.register("updatenotification", { } }, - socketNotificationReceived(notification, payload) { + socketNotificationReceived (notification, payload) { switch (notification) { case "REPO_STATUS": this.updateUI(payload); @@ -64,19 +64,19 @@ Module.register("updatenotification", { } }, - getStyles() { + getStyles () { return [`${this.name}.css`]; }, - getTemplate() { + getTemplate () { return `${this.name}.njk`; }, - getTemplateData() { + 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) { @@ -94,7 +94,7 @@ Module.register("updatenotification", { } }, - addFilters() { + addFilters () { this.nunjucksEnvironment().addFilter("diffLink", (text, status) => { if (status.module !== "MagicMirror") { return text; @@ -106,7 +106,7 @@ Module.register("updatenotification", { }); }, - updatesNotifier(payload, done = true) { + updatesNotifier (payload, done = true) { if (this.updates[payload.name] === undefined) { this.updates[payload.name] = { name: payload.name, diff --git a/modules/default/utils.js b/modules/default/utils.js index e60d96ea..ca016693 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 4c0bf02f..934c5831 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 fcee5557..b80601a1 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,7 +393,7 @@ WeatherProvider.register("openmeteo", { }, // Implement WeatherForecast generator. - generateWeatherObjectsFromForecast(weathers) { + generateWeatherObjectsFromForecast (weathers) { const days = []; weathers.daily.forEach((weather) => { @@ -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 cf65604b..c389b7fd 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 e529efe4..a9002809 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 1bb95611..46106cfc 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 0cdd85f1..d1641b42 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 49c7d80c..e4e020b3 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 a4d41267..225e7b46 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 298d23ba..5bde8003 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 aecfb63e..9e15be82 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 8111044b..f6610146 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 150683c2..0c6701bf 100644 --- a/modules/default/weather/providers/yr.js +++ b/modules/default/weather/providers/yr.js @@ -24,7 +24,7 @@ WeatherProvider.register("yr", { currentForecastHours: 1 //1, 6 or 12 }, - start() { + start () { if (typeof Storage === "undefined") { //local storage unavailable Log.error("The Yr weather provider requires local storage."); @@ -33,7 +33,7 @@ WeatherProvider.register("yr", { Log.info(`Weather provider: ${this.providerName} started.`); }, - fetchCurrentWeather() { + fetchCurrentWeather () { this.getCurrentWeather() .then((currentWeather) => { this.setCurrentWeather(currentWeather); @@ -45,7 +45,7 @@ WeatherProvider.register("yr", { }); }, - async getCurrentWeather() { + async getCurrentWeather () { const [weatherData, stellarData] = await Promise.all([this.getWeatherData(), this.getStellarData()]); if (!stellarData) { Log.warn("No stellar data available."); @@ -73,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. @@ -99,7 +99,7 @@ WeatherProvider.register("yr", { }); }, - getWeatherDataFromYrOrCache(resolve, reject) { + getWeatherDataFromYrOrCache (resolve, reject) { localStorage.setItem("yrIsFetchingWeatherData", "true"); let weatherData = this.getWeatherDataFromCache(); @@ -131,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); @@ -149,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 }); @@ -171,7 +171,7 @@ WeatherProvider.register("yr", { }); }, - getConfigOptions() { + getConfigOptions () { if (!this.config.lat) { Log.error("Latitude not provided."); throw new Error("Latitude not provided."); @@ -187,7 +187,7 @@ WeatherProvider.register("yr", { return { lat, lon, altitude }; }, - getForecastUrl() { + getForecastUrl () { let { lat, lon, altitude } = this.getConfigOptions(); if (lat.includes(".") && lat.split(".")[1].length > 4) { @@ -204,11 +204,11 @@ WeatherProvider.register("yr", { 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)); }, - 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) => { @@ -234,7 +234,7 @@ WeatherProvider.register("yr", { }); }, - getStellarDataFromYrOrCache(resolve, reject) { + getStellarDataFromYrOrCache (resolve, reject) { localStorage.setItem("yrIsFetchingStellarData", "true"); let stellarData = this.getStellarDataFromCache(); @@ -292,7 +292,7 @@ WeatherProvider.register("yr", { } }, - getStellarDataFromCache() { + getStellarDataFromCache () { const stellarData = localStorage.getItem("stellarData"); if (stellarData) { return JSON.parse(stellarData); @@ -301,7 +301,7 @@ WeatherProvider.register("yr", { } }, - getStellarDataFromYr(date, days = 1) { + getStellarDataFromYr (date, days = 1) { const requestHeaders = [{ name: "Accept", value: "application/json" }]; return this.fetchData(this.getStellarDataUrl(date, days), "json", requestHeaders) .then((data) => { @@ -314,7 +314,7 @@ WeatherProvider.register("yr", { }); }, - getStellarDataUrl(date, days) { + getStellarDataUrl (date, days) { let { lat, lon, altitude } = this.getConfigOptions(); if (lat.includes(".") && lat.split(".")[1].length > 4) { @@ -345,11 +345,11 @@ WeatherProvider.register("yr", { 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); @@ -370,7 +370,7 @@ WeatherProvider.register("yr", { return weather; }, - convertWeatherType(weatherType, weatherTime) { + convertWeatherType (weatherType, weatherTime) { const weatherHour = moment(weatherTime).format("HH"); const weatherTypes = { @@ -462,7 +462,7 @@ WeatherProvider.register("yr", { return weatherTypes.hasOwnProperty(weatherType) ? weatherTypes[weatherType] : null; }, - getForecastForXHoursFrom(weather) { + getForecastForXHoursFrom (weather) { if (this.config.currentForecastHours === 1) { if (weather.next_1_hours) { return weather.next_1_hours; @@ -490,7 +490,7 @@ WeatherProvider.register("yr", { } }, - fetchWeatherHourly() { + fetchWeatherHourly () { this.getWeatherForecast("hourly") .then((forecast) => { this.setWeatherHourly(forecast); @@ -502,7 +502,7 @@ WeatherProvider.register("yr", { }); }, - async getWeatherForecast(type) { + 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."); @@ -528,7 +528,7 @@ WeatherProvider.register("yr", { return series; }, - getHourlyForecastFrom(weatherData) { + getHourlyForecastFrom (weatherData) { const series = []; for (const forecast of weatherData.properties.timeseries) { @@ -543,7 +543,7 @@ WeatherProvider.register("yr", { return series; }, - getDailyForecastFrom(weatherData) { + getDailyForecastFrom (weatherData) { const series = []; const days = weatherData.properties.timeseries.reduce(function (days, forecast) { @@ -593,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 57c91d7b..15e6cfc5 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 9fae8873..33c9e669 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 d3bdb78d..b85e1a99 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 47fea335..e0c5709e 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 42e0fa71..d0f1db79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "command-exists": "^1.2.9", "console-stamp": "^3.1.2", "envsub": "^4.1.0", - "eslint": "^8.55.0", + "eslint": "^8.56.0", "express": "^4.18.2", "express-ipfilter": "^1.3.1", "feedme": "^2.0.2", @@ -28,11 +28,10 @@ "socket.io": "^4.7.2" }, "devDependencies": { - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.29.0", + "@stylistic/eslint-plugin": "^1.5.1", + "eslint-plugin-import": "^2.29.1", "eslint-plugin-jest": "^27.6.0", - "eslint-plugin-jsdoc": "^46.9.0", - "eslint-plugin-prettier": "^5.0.1", + "eslint-plugin-jsdoc": "^46.9.1", "express-basic-auth": "^1.2.1", "husky": "^8.0.3", "jest": "^29.7.0", @@ -872,9 +871,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", - "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", + "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" } @@ -1381,32 +1380,6 @@ "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==", - "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" - }, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "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", @@ -1486,6 +1459,350 @@ "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-plus/node_modules/@typescript-eslint/scope-manager": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.15.0.tgz", + "integrity": "sha512-+BdvxYBltqrmgCNu4Li+fGDIkW9n//NrruzG9X1vBzaNK+ExVXPoGB71kneaVw/Jp+4rH/vaMAGC6JfMbHstVg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.15.0", + "@typescript-eslint/visitor-keys": "6.15.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/types": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.15.0.tgz", + "integrity": "sha512-yXjbt//E4T/ee8Ia1b5mGlbNj9fB9lJP4jqLbZualwpP2BCQ5is6BcWwxpIsY4XKAhmdv3hrW92GdtJbatC6dQ==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/typescript-estree": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.15.0.tgz", + "integrity": "sha512-7mVZJN7Hd15OmGuWrp2T9UvqR2Ecg+1j/Bp1jXUEY2GZKV6FXlOIoqVDmLpBiEiq3katvj/2n2mR0SDwtloCew==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.15.0", + "@typescript-eslint/visitor-keys": "6.15.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/utils": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.15.0.tgz", + "integrity": "sha512-eF82p0Wrrlt8fQSRL0bGXzK5nWPRV2dYQZdajcfzOD9+cQz9O7ugifrJxclB+xVOvWvagXfqS4Es7vpLP4augw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.15.0", + "@typescript-eslint/types": "6.15.0", + "@typescript-eslint/typescript-estree": "6.15.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/visitor-keys": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.15.0.tgz", + "integrity": "sha512-1zvtdC1a9h5Tb5jU9x3ADNXO9yjP8rXlaoChu0DQX40vf5ACVpYIVIZhIMZ6d5sDXH7vq4dsZBT1fEGj8D2n2w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.15.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/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/@stylistic/eslint-plugin-plus/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/@stylistic/eslint-plugin-plus/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/@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/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/scope-manager": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.15.0.tgz", + "integrity": "sha512-+BdvxYBltqrmgCNu4Li+fGDIkW9n//NrruzG9X1vBzaNK+ExVXPoGB71kneaVw/Jp+4rH/vaMAGC6JfMbHstVg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.15.0", + "@typescript-eslint/visitor-keys": "6.15.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/types": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.15.0.tgz", + "integrity": "sha512-yXjbt//E4T/ee8Ia1b5mGlbNj9fB9lJP4jqLbZualwpP2BCQ5is6BcWwxpIsY4XKAhmdv3hrW92GdtJbatC6dQ==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/typescript-estree": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.15.0.tgz", + "integrity": "sha512-7mVZJN7Hd15OmGuWrp2T9UvqR2Ecg+1j/Bp1jXUEY2GZKV6FXlOIoqVDmLpBiEiq3katvj/2n2mR0SDwtloCew==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.15.0", + "@typescript-eslint/visitor-keys": "6.15.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/utils": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.15.0.tgz", + "integrity": "sha512-eF82p0Wrrlt8fQSRL0bGXzK5nWPRV2dYQZdajcfzOD9+cQz9O7ugifrJxclB+xVOvWvagXfqS4Es7vpLP4augw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.15.0", + "@typescript-eslint/types": "6.15.0", + "@typescript-eslint/typescript-estree": "6.15.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/visitor-keys": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.15.0.tgz", + "integrity": "sha512-1zvtdC1a9h5Tb5jU9x3ADNXO9yjP8rXlaoChu0DQX40vf5ACVpYIVIZhIMZ6d5sDXH7vq4dsZBT1fEGj8D2n2w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.15.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/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/@stylistic/eslint-plugin-ts/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/@stylistic/eslint-plugin-ts/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/@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -2297,15 +2614,6 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "node_modules/big-integer": { - "version": "1.6.52", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", - "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -2364,18 +2672,6 @@ "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", @@ -2465,21 +2761,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", @@ -3078,162 +3359,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", @@ -3256,18 +3381,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", @@ -3717,14 +3830,14 @@ } }, "node_modules/eslint": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", - "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", + "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.4", - "@eslint/js": "8.55.0", + "@eslint/js": "8.56.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -3770,18 +3883,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", - "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", @@ -3829,9 +3930,9 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz", - "integrity": "sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==", + "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.7", @@ -3850,7 +3951,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" @@ -3906,9 +4007,9 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "46.9.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.9.0.tgz", - "integrity": "sha512-UQuEtbqLNkPf5Nr/6PPRCtr9xypXY+g8y/Q7gPa0YK7eDhh0y2lWprXRnaYbW7ACgIUvpDKy9X2bZqxtGzBG9Q==", + "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": { "@es-joy/jsdoccomment": "~0.41.0", @@ -3919,7 +4020,7 @@ "esquery": "^1.5.0", "is-builtin-module": "^3.2.1", "semver": "^7.5.4", - "spdx-expression-parse": "^3.0.1" + "spdx-expression-parse": "^4.0.0" }, "engines": { "node": ">=16" @@ -3961,35 +4062,6 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/eslint-plugin-prettier": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz", - "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.5" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "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 - } - } - }, "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -5321,21 +5393,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", @@ -5376,24 +5433,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", @@ -5542,33 +5581,6 @@ "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" - } - }, - "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" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -7349,24 +7361,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", @@ -8216,21 +8210,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", @@ -8672,9 +8651,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", @@ -9174,28 +9153,6 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "node_modules/synckit": { - "version": "0.8.6", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.6.tgz", - "integrity": "sha512-laHF2savN6sMeHCjLRkheIU4wo3Zg9Ln5YOjOo7sZ5dVQW8yF5pPE5SIw1dsPhq3TRp1jisKRCdPhfs/1WMqDA==", - "dev": true, - "dependencies": { - "@pkgr/utils": "^2.4.2", - "tslib": "^2.6.2" - }, - "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", @@ -9299,18 +9256,6 @@ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" }, - "node_modules/titleize": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", - "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -9382,10 +9327,22 @@ "node": ">=18" } }, + "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": ">=16.13.0" + }, + "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", @@ -9601,15 +9558,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", diff --git a/package.json b/package.json index 5dd75a13..8362b541 100644 --- a/package.json +++ b/package.json @@ -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,11 +49,10 @@ }, "homepage": "https://magicmirror.builders", "devDependencies": { - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.29.0", + "@stylistic/eslint-plugin": "^1.5.1", + "eslint-plugin-import": "^2.29.1", "eslint-plugin-jest": "^27.6.0", - "eslint-plugin-jsdoc": "^46.9.0", - "eslint-plugin-prettier": "^5.0.1", + "eslint-plugin-jsdoc": "^46.9.1", "express-basic-auth": "^1.2.1", "husky": "^8.0.3", "jest": "^29.7.0", @@ -76,7 +75,7 @@ "command-exists": "^1.2.9", "console-stamp": "^3.1.2", "envsub": "^4.1.0", - "eslint": "^8.55.0", + "eslint": "^8.56.0", "express": "^4.18.2", "express-ipfilter": "^1.3.1", "feedme": "^2.0.2", diff --git a/tests/e2e/animateCSS_spec.js b/tests/e2e/animateCSS_spec.js index b9e31a76..3cb3aca6 100644 --- a/tests/e2e/animateCSS_spec.js +++ b/tests/e2e/animateCSS_spec.js @@ -25,7 +25,7 @@ describe("AnimateCSS integration Test", () => { */ const doTest = async (animationIn, animationOut) => { await helpers.getDocument(); - let elem = await helpers.waitForElement(`.compliments`); + let elem = await helpers.waitForElement(".compliments"); expect(elem).not.toBeNull(); let styles = window.getComputedStyle(elem); diff --git a/tests/e2e/helpers/mock-console.js b/tests/e2e/helpers/mock-console.js index f87be964..c593b706 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/modules/calendar_spec.js b/tests/e2e/modules/calendar_spec.js index da497024..e7291782 100644 --- a/tests/e2e/modules/calendar_spec.js +++ b/tests/e2e/modules/calendar_spec.js @@ -2,6 +2,7 @@ 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 diff --git a/tests/e2e/modules/compliments_spec.js b/tests/e2e/modules/compliments_spec.js index 636a7b05..0604dab4 100644 --- a/tests/e2e/modules/compliments_spec.js +++ b/tests/e2e/modules/compliments_spec.js @@ -1,6 +1,7 @@ const helpers = require("../helpers/global-setup"); describe("Compliments module", () => { + /** * move similar tests in function doTest * @param {Array} complimentsArray The array of compliments. diff --git a/tests/e2e/translations_spec.js b/tests/e2e/translations_spec.js index 212d4386..a0124fc9 100644 --- a/tests/e2e/translations_spec.js +++ b/tests/e2e/translations_spec.js @@ -125,7 +125,7 @@ describe("Translations", () => { const mmm = { name: "TranslationTest", - file(file) { + file (file) { return `http://localhost:3000/${file}`; } }; diff --git a/tests/electron/modules/calendar_spec.js b/tests/electron/modules/calendar_spec.js index ac8a614d..2af61a93 100644 --- a/tests/electron/modules/calendar_spec.js +++ b/tests/electron/modules/calendar_spec.js @@ -1,6 +1,7 @@ const helpers = require("../helpers/global-setup"); describe("Calendar module", () => { + /** * move similar tests in function doTest * @param {string} cssClass css selector diff --git a/tests/electron/modules/compliments_spec.js b/tests/electron/modules/compliments_spec.js index d0887346..b4c4ed84 100644 --- a/tests/electron/modules/compliments_spec.js +++ b/tests/electron/modules/compliments_spec.js @@ -1,6 +1,7 @@ const helpers = require("../helpers/global-setup"); describe("Compliments module", () => { + /** * move similar tests in function doTest * @param {Array} complimentsArray The array of compliments. diff --git a/tests/unit/classes/translator_spec.js b/tests/unit/classes/translator_spec.js index 91eb5ead..c0957e68 100644 --- a/tests/unit/classes/translator_spec.js +++ b/tests/unit/classes/translator_spec.js @@ -163,7 +163,7 @@ describe("Translator", () => { describe("load", () => { const mmm = { name: "TranslationTest", - file(file) { + file (file) { return `http://localhost:3000/translations/${file}`; } }; diff --git a/tests/unit/functions/server_functions_spec.js b/tests/unit/functions/server_functions_spec.js index 98955675..f5fb98f2 100644 --- a/tests/unit/functions/server_functions_spec.js +++ b/tests/unit/functions/server_functions_spec.js @@ -31,7 +31,7 @@ describe("server_functions tests", () => { }; request = { - url: `/cors?url=www.test.com` + url: "/cors?url=www.test.com" }; }); diff --git a/tests/unit/functions/updatenotification_spec.js b/tests/unit/functions/updatenotification_spec.js index 23597568..b36592c4 100644 --- a/tests/unit/functions/updatenotification_spec.js +++ b/tests/unit/functions/updatenotification_spec.js @@ -32,7 +32,7 @@ describe("Updatenotification", () => { const { promisify } = require("util"); promisify.mockReturnValue(execMock); - const GitHelper = require(`../../../modules/default/updatenotification/git_helper`); + const GitHelper = require("../../../modules/default/updatenotification/git_helper"); gitHelper = new GitHelper(); }); diff --git a/tests/unit/modules/default/utils_spec.js b/tests/unit/modules/default/utils_spec.js index 9d0467e7..664db490 100644 --- a/tests/unit/modules/default/utils_spec.js +++ b/tests/unit/modules/default/utils_spec.js @@ -84,7 +84,7 @@ describe("Default modules utils tests", () => { it("Returns object when data is received", async () => { urlToCall = "www.test.com"; - fetchResponse = new Response('{"body": "some content"}'); + fetchResponse = new Response("{\"body\": \"some content\"}"); const response = await performWebRequest(urlToCall); @@ -93,7 +93,7 @@ describe("Default modules utils tests", () => { it("Returns expected headers when data is received", async () => { urlToCall = "www.test.com"; - fetchResponse = new Response('{"body": "some content"}', { headers: { header1: "value1", header2: "value2" } }); + fetchResponse = new Response("{\"body\": \"some content\"}", { headers: { header1: "value1", header2: "value2" } }); const response = await performWebRequest(urlToCall, "json", false, undefined, ["header1"]); diff --git a/tests/utils/test_sequencer.js b/tests/utils/test_sequencer.js index ecb989ee..7057f2a7 100644 --- a/tests/utils/test_sequencer.js +++ b/tests/utils/test_sequencer.js @@ -1,7 +1,7 @@ const TestSequencer = require("@jest/test-sequencer").default; class CustomSequencer extends TestSequencer { - sort(tests) { + sort (tests) { const orderPath = ["unit", "electron", "e2e"]; return tests.sort((testA, testB) => { let indexA = -1;