diff --git a/CHANGELOG.md b/CHANGELOG.md index 01502e425d..916c68770b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ _This release is scheduled to be released on 2024-07-01._ ### Fixed +- Fix crash possibility if `module: ` is not defined and on `postion: ` misktake. - [weather] Fixed precipitationProbability in forecast for provider openmeteo (#3446) - [weather] Fixed type=daily for provider openmeteo having no data when running after 23:00 (#3449) - [weather] Fixed type=daily for provider openmeteo showing nightly icons in forecast when current time is "nightly" (#3458) diff --git a/js/app.js b/js/app.js index 77d0dc206f..f6e116d17d 100644 --- a/js/app.js +++ b/js/app.js @@ -253,8 +253,15 @@ function App () { let modules = []; for (const module of config.modules) { - if (!modules.includes(module.module) && !module.disabled) { - modules.push(module.module); + if (module.disabled) continue; + if (module.module) { + if (Utils.moduleHasValidPosition(module.position) || typeof (module.position) === "undefined") { + modules.push(module.module); + } else { + Log.warn("Invalid module position found for this configuration:", module); + } + } else { + Log.warn("No module name found for this configuration:", module); } } diff --git a/js/check_config.js b/js/check_config.js index ec5ebcae66..6a514de3eb 100644 --- a/js/check_config.js +++ b/js/check_config.js @@ -5,6 +5,10 @@ const { Linter } = require("eslint"); const linter = new Linter(); +const Ajv = require("ajv"); + +const ajv = new Ajv(); + const rootPath = path.resolve(`${__dirname}/../`); const Log = require(`${rootPath}/js/logger.js`); @@ -59,6 +63,68 @@ function checkConfigFile () { for (const error of errors) { Log.error(`Line ${error.line} column ${error.column}: ${error.message}`); } + return; + } + + Log.info("Checking modules structure configuration... "); + + // Make Ajv schema confguration of modules config + // only scan "module" and "position" + const schema = { + type: "object", + properties: { + modules: { + type: "array", + items: { + type: "object", + properties: { + module: { + type: "string" + }, + position: { + type: "string", + enum: [ + "top_bar", + "top_left", + "top_center", + "top_right", + "upper_third", + "middle_center", + "lower_third", + "bottom_left", + "bottom_center", + "bottom_right", + "bottom_bar", + "fullscreen_above", + "fullscreen_below" + ] + } + }, + required: ["module"] + } + } + } + }; + + // scan all modules + const validate = ajv.compile(schema); + const data = require(configFileName); + + const valid = validate(data); + if (!valid) { + let module = validate.errors[0].instancePath.split("/")[2]; + let position = validate.errors[0].instancePath.split("/")[3]; + + Log.error(colors.red("This module configuration contains errors:")); + Log.error(data.modules[module]); + if (position) { + Log.error(colors.red(`${position}: ${validate.errors[0].message}`)); + Log.error(validate.errors[0].params.allowedValues); + } else { + Log.error(colors.red(validate.errors[0].message)); + } + } else { + Log.info(colors.green("Your modules structure configuration doesn't contain errors :)")); } } diff --git a/js/loader.js b/js/loader.js index 0d59858c77..e8dff1907c 100644 --- a/js/loader.js +++ b/js/loader.js @@ -50,7 +50,8 @@ const Loader = (function () { * @returns {object[]} module data as configured in config */ const getAllModules = function () { - return config.modules; + const AllModules = config.modules.filter((module) => (module.module !== undefined) && (MM.getAvailableModulePositions.indexOf(module.position) > -1 || typeof (module.position) === "undefined")); + return AllModules; }; /** diff --git a/js/main.js b/js/main.js index 43ec02ad87..bc69f0bb93 100644 --- a/js/main.js +++ b/js/main.js @@ -450,10 +450,10 @@ const MM = (function () { * an ugly top margin. By using this function, the top bar will be hidden if the * update notification is not visible. */ - const updateWrapperStates = function () { - const positions = ["top_bar", "top_left", "top_center", "top_right", "upper_third", "middle_center", "lower_third", "bottom_left", "bottom_center", "bottom_right", "bottom_bar", "fullscreen_above", "fullscreen_below"]; + const modulePositions = ["top_bar", "top_left", "top_center", "top_right", "upper_third", "middle_center", "lower_third", "bottom_left", "bottom_center", "bottom_right", "bottom_bar", "fullscreen_above", "fullscreen_below"]; - positions.forEach(function (position) { + const updateWrapperStates = function () { + modulePositions.forEach(function (position) { const wrapper = selectWrapper(position); const moduleWrappers = wrapper.getElementsByClassName("module"); @@ -701,7 +701,10 @@ const MM = (function () { showModule (module, speed, callback, options) { // do not change module.hidden yet, only if we really show it later showModule(module, speed, callback, options); - } + }, + + // return all available module postions. + getAvailableModulePositions: modulePositions }; }()); diff --git a/js/utils.js b/js/utils.js index ba80004bb3..89784f6937 100644 --- a/js/utils.js +++ b/js/utils.js @@ -25,5 +25,16 @@ module.exports = { } catch (e) { Log.error(e); } + }, + + // return all available module positions + getAvailableModulePositions () { + return ["top_bar", "top_left", "top_center", "top_right", "upper_third", "middle_center", "lower_third", "bottom_left", "bottom_center", "bottom_right", "bottom_bar", "fullscreen_above", "fullscreen_below"]; + }, + + // return if postion is on modulePositions Array (true/false) + moduleHasValidPosition (position) { + if (this.getAvailableModulePositions().indexOf(position) === -1) return false; + return true; } }; diff --git a/package-lock.json b/package-lock.json index 22c2ad3242..018afa76b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { + "ajv": "^8.16.0", "ansis": "^3.2.0", "console-stamp": "^3.1.2", "envsub": "^4.1.0", @@ -923,6 +924,21 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -933,6 +949,11 @@ "concat-map": "0.0.1" } }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2353,15 +2374,14 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "license": "MIT", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" }, "funding": { "type": "github", @@ -4794,6 +4814,22 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-plugin-unicorn/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/eslint-plugin-unicorn/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4849,6 +4885,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint-plugin-unicorn/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/eslint-plugin-unicorn/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -4890,6 +4932,21 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4900,6 +4957,11 @@ "concat-map": "0.0.1" } }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -7522,10 +7584,9 @@ "license": "MIT" }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "license": "MIT" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -9938,8 +9999,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } diff --git a/package.json b/package.json index b79a8caa77..dc9a8d298e 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "*.css": "stylelint --fix" }, "dependencies": { + "ajv": "^8.16.0", "ansis": "^3.2.0", "console-stamp": "^3.1.2", "envsub": "^4.1.0",