diff --git a/.gitignore b/.gitignore
index c3cf9bdb..08c2df0c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
# Various Node ignoramuses.
-
logs
*.log
npm-debug.log*
@@ -13,9 +12,11 @@ build/Release
/node_modules/**/*
fonts/node_modules/**/*
vendor/node_modules/**/*
+!/tests/node_modules/**/*
jspm_modules
.npm
.node_repl_history
+.nyc_output/
# Visual Studio Code ignoramuses.
.vscode/
@@ -53,7 +54,6 @@ Temporary Items
.apdisk
# Various Linux ignoramuses.
-
.fuse_hidden*
.directory
.Trash-*
@@ -76,5 +76,3 @@ Temporary Items
*.orig
*.rej
*.bak
-
-!/tests/node_modules/**/*
diff --git a/.prettierignore b/.prettierignore
index e4a77657..3b87fcd2 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -1,5 +1,4 @@
package-lock.json
/config/**/*
-/modules/default/calendar/vendor/ical.js/**/*
/vendor/**/*
!/vendor/vendor.js
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3b4ee497..0f75d5e1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,33 @@ This project adheres to [Semantic Versioning](https://semver.org/).
❤️ **Donate:** Enjoying MagicMirror²? [Please consider a donation!](https://magicmirror.builders/donate) With your help we can continue to improve the MagicMirror²
+## [2.13.0] - Unreleased (Develop Branch - Please add your contributions to this release.)
+
+_This release is scheduled to be released on 2020-10-01._
+
+### Added
+
+- Test coverage with Istanbul, run it with `npm run test:coverage`.
+- Add lithuanian language.
+- Added support in weatherforecast for OpenWeather onecall API.
+- Added config option to calendar-icons for recurring- and fullday-events
+
+### Updated
+
+- Change incorrect weather.js default properties.
+- Cleaned up newsfeed module.
+
+### Deleted
+
+### Fixed
+
+- Fix backward compatibility issues for Safari < 11. [#1985](https://github.com/MichMich/MagicMirror/issues/1985)
+- Fix the use of "maxNumberOfDays" in the module "weatherforecast depending on the endpoint (forecast/daily or forecast)". [#2018](https://github.com/MichMich/MagicMirror/issues/2018)
+- Fix calendar display. Account for current timezone. [#2068](https://github.com/MichMich/MagicMirror/issues/2068)
+- Fix logLevel being set before loading config.
+- Fix incorrect namespace links in svg clockfaces. [#2072](https://github.com/MichMich/MagicMirror/issues/2072)
+- Fix weather/providers/weathergov for API guidelines [#2045]
+
## [2.12.0] - 2020-07-01
Special thanks to the following contributors: @AndreKoepke, @andrezibaia, @bryanzzhu, @chamakura, @DarthBrento, @Ekristoffe, @khassel, @Legion2, @ndom91, @radokristof, @rejas, @XBCreepinJesus & @ZoneMR.
diff --git a/js/app.js b/js/app.js
index 7cf7dd2e..b1fcc9bb 100644
--- a/js/app.js
+++ b/js/app.js
@@ -202,6 +202,8 @@ var App = function () {
loadConfig(function (c) {
config = c;
+ Log.setLogLevel(config.logLevel);
+
var modules = [];
for (var m in config.modules) {
diff --git a/js/logger.js b/js/logger.js
index 157420a7..0f33b473 100644
--- a/js/logger.js
+++ b/js/logger.js
@@ -19,7 +19,7 @@
root.Log = factory(root.config);
}
})(this, function (config) {
- let logLevel = {
+ const logLevel = {
info: Function.prototype.bind.call(console.info, console),
log: Function.prototype.bind.call(console.log, console),
error: Function.prototype.bind.call(console.error, console),
@@ -32,13 +32,15 @@
timeStamp: Function.prototype.bind.call(console.timeStamp, console)
};
- if (config && config.logLevel) {
- Object.keys(logLevel).forEach(function (key, index) {
- if (!config.logLevel.includes(key.toLocaleUpperCase())) {
- logLevel[key] = function () {};
- }
- });
- }
+ logLevel.setLogLevel = function (newLevel) {
+ if (newLevel) {
+ Object.keys(logLevel).forEach(function (key, index) {
+ if (!newLevel.includes(key.toLocaleUpperCase())) {
+ logLevel[key] = function () {};
+ }
+ });
+ }
+ };
return logLevel;
});
diff --git a/js/main.js b/js/main.js
index 07459f0f..cbf2566f 100644
--- a/js/main.js
+++ b/js/main.js
@@ -42,7 +42,7 @@ var MM = (function () {
dom.appendChild(moduleHeader);
if (typeof module.getHeader() === "undefined" || module.getHeader() !== "") {
- moduleHeader.style = "display: none;";
+ moduleHeader.style.display = "none;";
}
var moduleContent = document.createElement("div");
@@ -216,7 +216,11 @@ var MM = (function () {
contentWrapper[0].appendChild(newContent);
headerWrapper[0].innerHTML = newHeader;
- headerWrapper[0].style = headerWrapper.length > 0 && newHeader ? undefined : "display: none;";
+ if (headerWrapper.length > 0 && newHeader) {
+ delete headerWrapper[0].style;
+ } else {
+ headerWrapper[0].style.display = "none";
+ }
};
/* hideModule(module, speed, callback)
@@ -477,6 +481,9 @@ var MM = (function () {
init: function () {
Log.info("Initializing MagicMirror.");
loadConfig();
+
+ Log.setLogLevel(config.logLevel);
+
Translator.loadCoreTranslations(config.language);
Loader.loadModules();
},
diff --git a/js/translator.js b/js/translator.js
index 3a09fe0b..ee4e1051 100644
--- a/js/translator.js
+++ b/js/translator.js
@@ -19,92 +19,12 @@ var Translator = (function () {
xhr.open("GET", file, true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
- callback(JSON.parse(stripComments(xhr.responseText)));
+ callback(JSON.parse(xhr.responseText));
}
};
xhr.send(null);
}
- /* loadJSON(str, options)
- * Remove any commenting from a json file so it can be parsed.
- *
- * argument str string - The string that contains json with comments.
- * argument opts function - Strip options.
- *
- * return the stripped string.
- */
- function stripComments(str, opts) {
- // strip comments copied from: https://github.com/sindresorhus/strip-json-comments
-
- var singleComment = 1;
- var multiComment = 2;
-
- function stripWithoutWhitespace() {
- return "";
- }
-
- function stripWithWhitespace(str, start, end) {
- return str.slice(start, end).replace(/\S/g, " ");
- }
-
- opts = opts || {};
-
- var currentChar;
- var nextChar;
- var insideString = false;
- var insideComment = false;
- var offset = 0;
- var ret = "";
- var strip = opts.whitespace === false ? stripWithoutWhitespace : stripWithWhitespace;
-
- for (var i = 0; i < str.length; i++) {
- currentChar = str[i];
- nextChar = str[i + 1];
-
- if (!insideComment && currentChar === '"') {
- var escaped = str[i - 1] === "\\" && str[i - 2] !== "\\";
- if (!escaped) {
- insideString = !insideString;
- }
- }
-
- if (insideString) {
- continue;
- }
-
- if (!insideComment && currentChar + nextChar === "//") {
- ret += str.slice(offset, i);
- offset = i;
- insideComment = singleComment;
- i++;
- } else if (insideComment === singleComment && currentChar + nextChar === "\r\n") {
- i++;
- insideComment = false;
- ret += strip(str, offset, i);
- offset = i;
- continue;
- } else if (insideComment === singleComment && currentChar === "\n") {
- insideComment = false;
- ret += strip(str, offset, i);
- offset = i;
- } else if (!insideComment && currentChar + nextChar === "/*") {
- ret += str.slice(offset, i);
- offset = i;
- insideComment = multiComment;
- i++;
- continue;
- } else if (insideComment === multiComment && currentChar + nextChar === "*/") {
- i++;
- insideComment = false;
- ret += strip(str, offset, i + 1);
- offset = i + 1;
- continue;
- }
- }
-
- return ret + (insideComment ? strip(str.substr(offset)) : str.substr(offset));
- }
-
return {
coreTranslations: {},
coreTranslationsFallback: {},
diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js
index bba7565d..06026363 100755
--- a/modules/default/calendar/calendar.js
+++ b/modules/default/calendar/calendar.js
@@ -205,7 +205,7 @@ Module.register("calendar", {
eventWrapper.style.cssText = "color:" + this.colorForUrl(event.url);
}
- eventWrapper.className = "normal";
+ eventWrapper.className = "normal event";
if (this.config.displaySymbol) {
var symbolWrapper = document.createElement("td");
@@ -217,11 +217,7 @@ Module.register("calendar", {
var symbolClass = this.symbolClassForUrl(event.url);
symbolWrapper.className = "symbol align-right " + symbolClass;
- var symbols = this.symbolsForUrl(event.url);
- if (typeof symbols === "string") {
- symbols = [symbols];
- }
-
+ var symbols = this.symbolsForEvent(event);
for (var i = 0; i < symbols.length; i++) {
var symbol = document.createElement("span");
symbol.className = "fa fa-fw fa-" + symbols[i];
@@ -230,6 +226,7 @@ Module.register("calendar", {
}
symbolWrapper.appendChild(symbol);
}
+
eventWrapper.appendChild(symbolWrapper);
} else if (this.config.timeFormat === "dateheaders") {
var blankCell = document.createElement("td");
@@ -467,6 +464,7 @@ Module.register("calendar", {
var calendar = this.calendarData[c];
for (var e in calendar) {
var event = JSON.parse(JSON.stringify(calendar[e])); // clone object
+
if (event.endDate < now) {
continue;
}
@@ -558,15 +556,33 @@ Module.register("calendar", {
},
/**
- * symbolsForUrl(url)
- * Retrieves the symbols for a specific url.
+ * symbolsForEvent(event)
+ * Retrieves the symbols for a specific event.
*
- * argument url string - Url to look for.
+ * argument event object - Event to look for.
*
- * return string/array - The Symbols
+ * return array - The Symbols
*/
- symbolsForUrl: function (url) {
- return this.getCalendarProperty(url, "symbol", this.config.defaultSymbol);
+ symbolsForEvent: function (event) {
+ let symbols = this.getCalendarPropertyAsArray(event.url, "symbol", this.config.defaultSymbol);
+
+ if (event.recurringEvent === true && this.hasCalendarProperty(event.url, "recurringSymbol")) {
+ symbols = this.mergeUnique(this.getCalendarPropertyAsArray(event.url, "recurringSymbol", this.config.defaultSymbol), symbols);
+ }
+
+ if (event.fullDayEvent === true && this.hasCalendarProperty(event.url, "fullDaySymbol")) {
+ symbols = this.mergeUnique(this.getCalendarPropertyAsArray(event.url, "fullDaySymbol", this.config.defaultSymbol), symbols);
+ }
+
+ return symbols;
+ },
+
+ mergeUnique: function (arr1, arr2) {
+ return arr1.concat(
+ arr2.filter(function (item) {
+ return arr1.indexOf(item) === -1;
+ })
+ );
},
/**
@@ -658,6 +674,16 @@ Module.register("calendar", {
return defaultValue;
},
+ getCalendarPropertyAsArray: function (url, property, defaultValue) {
+ let p = this.getCalendarProperty(url, property, defaultValue);
+ if (!(p instanceof Array)) p = [p];
+ return p;
+ },
+
+ hasCalendarProperty: function (url, property) {
+ return !!this.getCalendarProperty(url, property, undefined);
+ },
+
/**
* Shortens a string if it's longer than maxLength and add a ellipsis to the end
*
@@ -755,7 +781,7 @@ Module.register("calendar", {
var calendar = this.calendarData[url];
for (var e in calendar) {
var event = cloneObject(calendar[e]);
- event.symbol = this.symbolsForUrl(url);
+ event.symbol = this.symbolsForEvent(event);
event.calendarName = this.calendarNameForUrl(url);
event.color = this.colorForUrl(url);
delete event.url;
diff --git a/modules/default/calendar/calendarfetcher.js b/modules/default/calendar/calendarfetcher.js
index 4a6fb0e6..888830ba 100644
--- a/modules/default/calendar/calendarfetcher.js
+++ b/modules/default/calendar/calendarfetcher.js
@@ -9,7 +9,7 @@ const ical = require("ical");
const moment = require("moment");
const request = require("request");
-const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumberOfDays, auth, includePastEvents) {
+const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, includePastEvents) {
const self = this;
let reloadTimer = null;
@@ -186,10 +186,7 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNu
// kblankenship1989 - to fix issue #1798, converting all dates to locale time first, then converting back to UTC time
const pastLocal = pastMoment.subtract(past.getTimezoneOffset(), "minutes").toDate();
const futureLocal = futureMoment.subtract(future.getTimezoneOffset(), "minutes").toDate();
- const datesLocal = rule.between(pastLocal, futureLocal, true, limitFunction);
- const dates = datesLocal.map(function (dateLocal) {
- return moment(dateLocal).add(dateLocal.getTimezoneOffset(), "minutes").toDate();
- });
+ const dates = rule.between(pastLocal, futureLocal, true, limitFunction);
// The "dates" array contains the set of dates within our desired date range range that are valid
// for the recurrence rule. *However*, it's possible for us to have a specific recurrence that
@@ -257,6 +254,7 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNu
startDate: startDate.format("x"),
endDate: endDate.format("x"),
fullDayEvent: isFullDayEvent(event),
+ recurringEvent: true,
class: event.class,
firstYear: event.start.getFullYear(),
location: location,
@@ -320,7 +318,7 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNu
return a.startDate - b.startDate;
});
- events = newEvents;
+ events = newEvents.slice(0, maximumEntries);
self.broadcastEvents();
scheduleTimer();
diff --git a/modules/default/calendar/node_helper.js b/modules/default/calendar/node_helper.js
index 5248919b..e731ca6c 100644
--- a/modules/default/calendar/node_helper.js
+++ b/modules/default/calendar/node_helper.js
@@ -20,7 +20,7 @@ module.exports = NodeHelper.create({
// Override socketNotificationReceived method.
socketNotificationReceived: function (notification, payload) {
if (notification === "ADD_CALENDAR") {
- this.createFetcher(payload.url, payload.fetchInterval, payload.excludedEvents, payload.maximumNumberOfDays, payload.auth, payload.broadcastPastEvents, payload.id);
+ this.createFetcher(payload.url, payload.fetchInterval, payload.excludedEvents, payload.maximumEntries, payload.maximumNumberOfDays, payload.auth, payload.broadcastPastEvents, payload.id);
}
},
@@ -31,7 +31,7 @@ module.exports = NodeHelper.create({
* attribute url string - URL of the news feed.
* attribute reloadInterval number - Reload interval in milliseconds.
*/
- createFetcher: function (url, fetchInterval, excludedEvents, maximumNumberOfDays, auth, broadcastPastEvents, identifier) {
+ createFetcher: function (url, fetchInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, broadcastPastEvents, identifier) {
var self = this;
if (!validUrl.isUri(url)) {
@@ -42,7 +42,7 @@ module.exports = NodeHelper.create({
var fetcher;
if (typeof self.fetchers[identifier + url] === "undefined") {
Log.log("Create new calendar fetcher for url: " + url + " - Interval: " + fetchInterval);
- fetcher = new CalendarFetcher(url, fetchInterval, excludedEvents, maximumNumberOfDays, auth, broadcastPastEvents);
+ fetcher = new CalendarFetcher(url, fetchInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, broadcastPastEvents);
fetcher.onReceive(function (fetcher) {
self.sendSocketNotification("CALENDAR_EVENTS", {
diff --git a/modules/default/clock/faces/face-001.svg b/modules/default/clock/faces/face-001.svg
index 13436c76..abd08ce7 100644
--- a/modules/default/clock/faces/face-001.svg
+++ b/modules/default/clock/faces/face-001.svg
@@ -1 +1 @@
-
+
diff --git a/modules/default/clock/faces/face-002.svg b/modules/default/clock/faces/face-002.svg
index a3ee3682..1ec31049 100644
--- a/modules/default/clock/faces/face-002.svg
+++ b/modules/default/clock/faces/face-002.svg
@@ -1 +1 @@
-
+
diff --git a/modules/default/clock/faces/face-003.svg b/modules/default/clock/faces/face-003.svg
index d3fc32de..7cfeebac 100644
--- a/modules/default/clock/faces/face-003.svg
+++ b/modules/default/clock/faces/face-003.svg
@@ -1 +1 @@
-
+
diff --git a/modules/default/clock/faces/face-004.svg b/modules/default/clock/faces/face-004.svg
index 140955d7..bc97588c 100644
--- a/modules/default/clock/faces/face-004.svg
+++ b/modules/default/clock/faces/face-004.svg
@@ -1 +1 @@
-
+
diff --git a/modules/default/clock/faces/face-005.svg b/modules/default/clock/faces/face-005.svg
index fb52a435..0bc1b430 100644
--- a/modules/default/clock/faces/face-005.svg
+++ b/modules/default/clock/faces/face-005.svg
@@ -1 +1 @@
-
+
diff --git a/modules/default/clock/faces/face-006.svg b/modules/default/clock/faces/face-006.svg
index a9eff826..63d1c935 100644
--- a/modules/default/clock/faces/face-006.svg
+++ b/modules/default/clock/faces/face-006.svg
@@ -1 +1 @@
-
+
diff --git a/modules/default/clock/faces/face-007.svg b/modules/default/clock/faces/face-007.svg
index b0dde834..e557f55f 100644
--- a/modules/default/clock/faces/face-007.svg
+++ b/modules/default/clock/faces/face-007.svg
@@ -1 +1 @@
-
+
diff --git a/modules/default/clock/faces/face-008.svg b/modules/default/clock/faces/face-008.svg
index 551ea7df..6fadb396 100644
--- a/modules/default/clock/faces/face-008.svg
+++ b/modules/default/clock/faces/face-008.svg
@@ -1 +1 @@
-
+
diff --git a/modules/default/clock/faces/face-009.svg b/modules/default/clock/faces/face-009.svg
index cd3720f2..bd207e09 100644
--- a/modules/default/clock/faces/face-009.svg
+++ b/modules/default/clock/faces/face-009.svg
@@ -1 +1 @@
-
+
diff --git a/modules/default/clock/faces/face-010.svg b/modules/default/clock/faces/face-010.svg
index d0af3acb..8c5e5848 100644
--- a/modules/default/clock/faces/face-010.svg
+++ b/modules/default/clock/faces/face-010.svg
@@ -1 +1 @@
-
+
diff --git a/modules/default/clock/faces/face-011.svg b/modules/default/clock/faces/face-011.svg
index 2d5f27ba..9886fed5 100644
--- a/modules/default/clock/faces/face-011.svg
+++ b/modules/default/clock/faces/face-011.svg
@@ -1 +1 @@
-
+
diff --git a/modules/default/clock/faces/face-012.svg b/modules/default/clock/faces/face-012.svg
index 8096d492..cfd80698 100644
--- a/modules/default/clock/faces/face-012.svg
+++ b/modules/default/clock/faces/face-012.svg
@@ -1 +1 @@
-
+
diff --git a/modules/default/newsfeed/newsfeed.js b/modules/default/newsfeed/newsfeed.js
index 70809522..3e26da4f 100644
--- a/modules/default/newsfeed/newsfeed.js
+++ b/modules/default/newsfeed/newsfeed.js
@@ -84,11 +84,11 @@ Module.register("newsfeed", {
// Override dom generator.
getDom: function () {
- var wrapper = document.createElement("div");
+ const wrapper = document.createElement("div");
if (this.config.feedUrl) {
wrapper.className = "small bright";
- wrapper.innerHTML = this.translate("configuration_changed");
+ wrapper.innerHTML = this.translate("MODULE_CONFIG_CHANGED", { MODULE_NAME: "Newsfeed" });
return wrapper;
}
@@ -99,7 +99,7 @@ Module.register("newsfeed", {
if (this.newsItems.length > 0) {
// this.config.showFullArticle is a run-time configuration, triggered by optional notifications
if (!this.config.showFullArticle && (this.config.showSourceTitle || this.config.showPublishDate)) {
- var sourceAndTimestamp = document.createElement("div");
+ const sourceAndTimestamp = document.createElement("div");
sourceAndTimestamp.className = "newsfeed-source light small dimmed";
if (this.config.showSourceTitle && this.newsItems[this.activeItem].sourceTitle !== "") {
@@ -157,22 +157,22 @@ Module.register("newsfeed", {
}
if (!this.config.showFullArticle) {
- var title = document.createElement("div");
+ const title = document.createElement("div");
title.className = "newsfeed-title bright medium light" + (!this.config.wrapTitle ? " no-wrap" : "");
title.innerHTML = this.newsItems[this.activeItem].title;
wrapper.appendChild(title);
}
if (this.isShowingDescription) {
- var description = document.createElement("div");
+ const description = document.createElement("div");
description.className = "newsfeed-desc small light" + (!this.config.wrapDescription ? " no-wrap" : "");
- var txtDesc = this.newsItems[this.activeItem].description;
+ const txtDesc = this.newsItems[this.activeItem].description;
description.innerHTML = this.config.truncDescription ? (txtDesc.length > this.config.lengthDescription ? txtDesc.substring(0, this.config.lengthDescription) + "..." : txtDesc) : txtDesc;
wrapper.appendChild(description);
}
if (this.config.showFullArticle) {
- var fullArticle = document.createElement("iframe");
+ const fullArticle = document.createElement("iframe");
fullArticle.className = "";
fullArticle.style.width = "100vw";
// very large height value to allow scrolling
@@ -332,17 +332,6 @@ Module.register("newsfeed", {
}, this.config.updateInterval);
},
- /* capitalizeFirstLetter(string)
- * Capitalizes the first character of a string.
- *
- * argument string string - Input string.
- *
- * return string - Capitalized output string.
- */
- capitalizeFirstLetter: function (string) {
- return string.charAt(0).toUpperCase() + string.slice(1);
- },
-
resetDescrOrFullArticleAndTimer: function () {
this.isShowingDescription = this.config.showDescription;
this.config.showFullArticle = false;
@@ -356,7 +345,7 @@ Module.register("newsfeed", {
},
notificationReceived: function (notification, payload, sender) {
- var before = this.activeItem;
+ const before = this.activeItem;
if (notification === "ARTICLE_NEXT") {
this.activeItem++;
if (this.activeItem >= this.newsItems.length) {
diff --git a/modules/default/newsfeed/fetcher.js b/modules/default/newsfeed/newsfeedfetcher.js
similarity index 72%
rename from modules/default/newsfeed/fetcher.js
rename to modules/default/newsfeed/newsfeedfetcher.js
index da9616dc..ba32d1ad 100644
--- a/modules/default/newsfeed/fetcher.js
+++ b/modules/default/newsfeed/newsfeedfetcher.js
@@ -1,10 +1,9 @@
/* Magic Mirror
- * Fetcher
+ * Node Helper: Newsfeed - NewsfeedFetcher
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
-
const Log = require("../../../js/logger.js");
const FeedMe = require("feedme");
const request = require("request");
@@ -17,39 +16,39 @@ const iconv = require("iconv-lite");
* attribute reloadInterval number - Reload interval in milliseconds.
* attribute logFeedWarnings boolean - Log warnings when there is an error parsing a news article.
*/
+const NewsfeedFetcher = function (url, reloadInterval, encoding, logFeedWarnings) {
+ const self = this;
+
+ let reloadTimer = null;
+ let items = [];
+
+ let fetchFailedCallback = function () {};
+ let itemsReceivedCallback = function () {};
-var Fetcher = function (url, reloadInterval, encoding, logFeedWarnings) {
- var self = this;
if (reloadInterval < 1000) {
reloadInterval = 1000;
}
- var reloadTimer = null;
- var items = [];
-
- var fetchFailedCallback = function () {};
- var itemsReceivedCallback = function () {};
-
/* private methods */
/* fetchNews()
* Request the new items.
*/
- var fetchNews = function () {
+ const fetchNews = function () {
clearTimeout(reloadTimer);
reloadTimer = null;
items = [];
- var parser = new FeedMe();
+ const parser = new FeedMe();
parser.on("item", function (item) {
- var title = item.title;
- var description = item.description || item.summary || item.content || "";
- var pubdate = item.pubdate || item.published || item.updated || item["dc:date"];
- var url = item.url || item.link || "";
+ const title = item.title;
+ let description = item.description || item.summary || item.content || "";
+ const pubdate = item.pubdate || item.published || item.updated || item["dc:date"];
+ const url = item.url || item.link || "";
if (title && pubdate) {
- var regex = /(<([^>]+)>)/gi;
+ const regex = /(<([^>]+)>)/gi;
description = description.toString().replace(regex, "");
items.push({
@@ -77,10 +76,17 @@ var Fetcher = function (url, reloadInterval, encoding, logFeedWarnings) {
scheduleTimer();
});
- var nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
- var headers = { "User-Agent": "Mozilla/5.0 (Node.js " + nodeVersion + ") MagicMirror/" + global.version + " (https://github.com/MichMich/MagicMirror/)", "Cache-Control": "max-age=0, no-cache, no-store, must-revalidate", Pragma: "no-cache" };
+ const nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
+ const opts = {
+ headers: {
+ "User-Agent": "Mozilla/5.0 (Node.js " + nodeVersion + ") MagicMirror/" + global.version + " (https://github.com/MichMich/MagicMirror/)",
+ "Cache-Control": "max-age=0, no-cache, no-store, must-revalidate",
+ Pragma: "no-cache"
+ },
+ encoding: null
+ };
- request({ uri: url, encoding: null, headers: headers })
+ request(url, opts)
.on("error", function (error) {
fetchFailedCallback(self, error);
scheduleTimer();
@@ -92,7 +98,7 @@ var Fetcher = function (url, reloadInterval, encoding, logFeedWarnings) {
/* scheduleTimer()
* Schedule the timer for the next update.
*/
- var scheduleTimer = function () {
+ const scheduleTimer = function () {
clearTimeout(reloadTimer);
reloadTimer = setTimeout(function () {
fetchNews();
@@ -148,4 +154,4 @@ var Fetcher = function (url, reloadInterval, encoding, logFeedWarnings) {
};
};
-module.exports = Fetcher;
+module.exports = NewsfeedFetcher;
diff --git a/modules/default/newsfeed/node_helper.js b/modules/default/newsfeed/node_helper.js
index 4ccef958..6aca2519 100644
--- a/modules/default/newsfeed/node_helper.js
+++ b/modules/default/newsfeed/node_helper.js
@@ -7,7 +7,7 @@
const NodeHelper = require("node_helper");
const validUrl = require("valid-url");
-const Fetcher = require("./fetcher.js");
+const NewsfeedFetcher = require("./newsfeedfetcher.js");
const Log = require("../../../js/logger");
module.exports = NodeHelper.create({
@@ -32,37 +32,35 @@ module.exports = NodeHelper.create({
* attribute config object - A configuration object containing reload interval in milliseconds.
*/
createFetcher: function (feed, config) {
- var self = this;
-
- var url = feed.url || "";
- var encoding = feed.encoding || "UTF-8";
- var reloadInterval = feed.reloadInterval || config.reloadInterval || 5 * 60 * 1000;
+ const url = feed.url || "";
+ const encoding = feed.encoding || "UTF-8";
+ const reloadInterval = feed.reloadInterval || config.reloadInterval || 5 * 60 * 1000;
if (!validUrl.isUri(url)) {
- self.sendSocketNotification("INCORRECT_URL", url);
+ this.sendSocketNotification("INCORRECT_URL", url);
return;
}
- var fetcher;
- if (typeof self.fetchers[url] === "undefined") {
+ let fetcher;
+ if (typeof this.fetchers[url] === "undefined") {
Log.log("Create new news fetcher for url: " + url + " - Interval: " + reloadInterval);
- fetcher = new Fetcher(url, reloadInterval, encoding, config.logFeedWarnings);
+ fetcher = new NewsfeedFetcher(url, reloadInterval, encoding, config.logFeedWarnings);
- fetcher.onReceive(function (fetcher) {
- self.broadcastFeeds();
+ fetcher.onReceive(() => {
+ this.broadcastFeeds();
});
- fetcher.onError(function (fetcher, error) {
- self.sendSocketNotification("FETCH_ERROR", {
+ fetcher.onError((fetcher, error) => {
+ this.sendSocketNotification("FETCH_ERROR", {
url: fetcher.url(),
error: error
});
});
- self.fetchers[url] = fetcher;
+ this.fetchers[url] = fetcher;
} else {
Log.log("Use existing news fetcher for url: " + url);
- fetcher = self.fetchers[url];
+ fetcher = this.fetchers[url];
fetcher.setReloadInterval(reloadInterval);
fetcher.broadcastItems();
}
diff --git a/modules/default/newsfeed/translations/de.json b/modules/default/newsfeed/translations/de.json
deleted file mode 100644
index a11eb323..00000000
--- a/modules/default/newsfeed/translations/de.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "configuration_changed": "Die Konfigurationsoptionen für das Newsfeed-Modul haben sich geändert. \nBitte überprüfen Sie die Dokumentation."
-}
diff --git a/modules/default/newsfeed/translations/en.json b/modules/default/newsfeed/translations/en.json
deleted file mode 100644
index 9e804445..00000000
--- a/modules/default/newsfeed/translations/en.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "configuration_changed": "The configuration options for the newsfeed module have changed.\nPlease check the documentation."
-}
diff --git a/modules/default/newsfeed/translations/es.json b/modules/default/newsfeed/translations/es.json
deleted file mode 100644
index b1124b6e..00000000
--- a/modules/default/newsfeed/translations/es.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "configuration_changed": "Las opciones de configuración para el módulo de suministro de noticias han cambiado. \nVerifique la documentación."
-}
diff --git a/modules/default/newsfeed/translations/fr.json b/modules/default/newsfeed/translations/fr.json
deleted file mode 100644
index fa6d522e..00000000
--- a/modules/default/newsfeed/translations/fr.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "configuration_changed": "Les options de configuration du module newsfeed ont changé. \nVeuillez consulter la documentation."
-}
diff --git a/modules/default/weather/providers/weathergov.js b/modules/default/weather/providers/weathergov.js
index c24e4de1..1b28bba1 100755
--- a/modules/default/weather/providers/weathergov.js
+++ b/modules/default/weather/providers/weathergov.js
@@ -3,76 +3,155 @@
/* Magic Mirror
* Module: Weather
* Provider: weather.gov
+ * https://weather-gov.github.io/api/general-faqs
*
- * By Vince Peri
+ * Original by Vince Peri
* MIT Licensed.
*
* This class is a provider for weather.gov.
* Note that this is only for US locations (lat and lon) and does not require an API key
- * Since it is free, there are some items missing - like sunrise, sunset, humidity, etc.
+ * Since it is free, there are some items missing - like sunrise, sunset
*/
+
WeatherProvider.register("weathergov", {
// Set the name of the provider.
// This isn't strictly necessary, since it will fallback to the provider identifier
// But for debugging (and future alerts) it would be nice to have the real name.
providerName: "Weather.gov",
+ // Flag all needed URLs availability
+ configURLs: false,
+
+ //This API has multiple urls involved
+ forecastURL: "tbd",
+ forecastHourlyURL: "tbd",
+ forecastGridDataURL: "tbd",
+ observationStationsURL: "tbd",
+ stationObsURL: "tbd",
+
+ // Called to set the config, this config is the same as the weather module's config.
+ setConfig: function (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 () {
+ Log.info(`Weather provider: ${this.providerName} started.`);
+ },
+
+ // This returns the name of the fetched location or an empty string.
+ fetchedLocation: function () {
+ return this.fetchedLocationName || "";
+ },
+
// Overwrite the fetchCurrentWeather method.
fetchCurrentWeather() {
- this.fetchData(this.getUrl())
+ if (!this.configURLs) {
+ Log.info("fetch wx waiting on config URLs");
+ return;
+ }
+ this.fetchData(this.stationObsURL)
.then((data) => {
- if (!data || !data.properties || !data.properties.periods || !data.properties.periods.length) {
+ if (!data || !data.properties) {
// Did not receive usable new data.
- // Maybe this needs a better check?
return;
}
-
- const currentWeather = this.generateWeatherObjectFromCurrentWeather(data.properties.periods[0]);
+ const currentWeather = this.generateWeatherObjectFromCurrentWeather(data.properties);
this.setCurrentWeather(currentWeather);
})
.catch(function (request) {
- Log.error("Could not load data ... ", request);
+ Log.error("Could not load station obs data ... ", request);
})
.finally(() => this.updateAvailable());
},
- // Overwrite the fetchCurrentWeather method.
+ // Overwrite the fetchWeatherForecast method.
fetchWeatherForecast() {
- this.fetchData(this.getUrl())
+ if (!this.configURLs) {
+ Log.info("fetch wx waiting on config URLs");
+ return;
+ }
+ this.fetchData(this.forecastURL)
.then((data) => {
if (!data || !data.properties || !data.properties.periods || !data.properties.periods.length) {
// Did not receive usable new data.
- // Maybe this needs a better check?
return;
}
-
const forecast = this.generateWeatherObjectsFromForecast(data.properties.periods);
this.setWeatherForecast(forecast);
})
.catch(function (request) {
- Log.error("Could not load data ... ", request);
+ Log.error("Could not load forecast hourly data ... ", request);
})
.finally(() => this.updateAvailable());
},
/** Weather.gov Specific Methods - These are not part of the default provider methods */
+
/*
- * Gets the complete url for the request
+ * Get specific URLs
*/
- getUrl() {
- return this.config.apiBase + this.config.lat + "," + this.config.lon + this.config.weatherEndpoint;
+ fetchWxGovURLs(config) {
+ this.fetchData(`${config.apiBase}/points/${config.lat},${config.lon}`)
+ .then((data) => {
+ if (!data || !data.properties) {
+ // points URL did not respond with usable data.
+ return;
+ }
+ this.fetchedLocationName = data.properties.relativeLocation.properties.city + ", " + data.properties.relativeLocation.properties.state;
+ Log.log("Forecast location is " + this.fetchedLocationName);
+ this.forecastURL = data.properties.forecast;
+ this.forecastHourlyURL = data.properties.forecastHourly;
+ this.forecastGridDataURL = data.properties.forecastGridData;
+ this.observationStationsURL = data.properties.observationStations;
+ // with this URL, we chain another promise for the station obs URL
+ return this.fetchData(data.properties.observationStations);
+ })
+ .then((obsData) => {
+ if (!obsData || !obsData.features) {
+ // obs station URL did not respond with usable data.
+ return;
+ }
+ this.stationObsURL = obsData.features[0].id + "/observations/latest";
+ })
+ .catch((err) => {
+ Log.error(err);
+ })
+ .finally(() => {
+ // excellent, let's fetch some actual wx data
+ this.configURLs = true;
+ this.fetchCurrentWeather();
+ });
},
/*
* Generate a WeatherObject based on currentWeatherInformation
+ * Weather.gov API uses specific units; API does not include choice of units
+ * ... object needs data in units based on config!
*/
generateWeatherObjectFromCurrentWeather(currentWeatherData) {
const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
- currentWeather.temperature = currentWeatherData.temperature;
- currentWeather.windSpeed = currentWeatherData.windSpeed.split(" ", 1);
- currentWeather.windDirection = this.convertWindDirection(currentWeatherData.windDirection);
- currentWeather.weatherType = this.convertWeatherType(currentWeatherData.shortForecast, currentWeatherData.isDaytime);
+ currentWeather.date = moment(currentWeatherData.timestamp);
+ currentWeather.temperature = this.convertTemp(currentWeatherData.temperature.value);
+ currentWeather.windSpeed = this.covertSpeed(currentWeatherData.windSpeed.value);
+ currentWeather.windDirection = currentWeatherData.windDirection.value;
+ currentWeather.minTemperature = this.convertTemp(currentWeatherData.minTemperatureLast24Hours.value);
+ currentWeather.maxTemperature = this.convertTemp(currentWeatherData.maxTemperatureLast24Hours.value);
+ currentWeather.humidity = Math.round(currentWeatherData.relativeHumidity.value);
+ currentWeather.rain = null;
+ currentWeather.snow = null;
+ currentWeather.precipitation = this.convertLength(currentWeatherData.precipitationLastHour.value);
+ currentWeather.feelsLikeTemp = this.convertTemp(currentWeatherData.heatIndex.value);
+
+ let isDaytime = true;
+ if (currentWeatherData.icon.includes("day")) {
+ isDaytime = true;
+ } else {
+ isDaytime = false;
+ }
+ currentWeather.weatherType = this.convertWeatherType(currentWeatherData.textDescription, isDaytime);
// determine the sunrise/sunset times - not supplied in weather.gov data
let times = this.calcAstroData(this.config.lat, this.config.lon);
@@ -124,7 +203,7 @@ WeatherProvider.register("weathergov", {
// specify date
weather.date = moment(forecast.startTime);
- // If the first value of today is later than 17:00, we have an icon at least!
+ // use the forecast isDayTime attribute to help build the weatherType label
weather.weatherType = this.convertWeatherType(forecast.shortForecast, forecast.isDaytime);
}
@@ -148,6 +227,34 @@ WeatherProvider.register("weathergov", {
return days.slice(1);
},
+ /*
+ * Unit conversions
+ */
+ // conversion to fahrenheit
+ convertTemp(temp) {
+ if (this.config.tempUnits === "imperial") {
+ return (9 / 5) * temp + 32;
+ } else {
+ return temp;
+ }
+ },
+ // conversion to mph
+ covertSpeed(metSec) {
+ if (this.config.windUnits === "imperial") {
+ return metSec * 2.23694;
+ } else {
+ return metSec;
+ }
+ },
+ // conversion to inches
+ convertLength(meters) {
+ if (this.config.units === "imperial") {
+ return meters * 39.3701;
+ } else {
+ return meters;
+ }
+ },
+
/*
* Calculate the astronomical data
*/
diff --git a/modules/default/weather/weather.js b/modules/default/weather/weather.js
index 150ba084..73c493e0 100644
--- a/modules/default/weather/weather.js
+++ b/modules/default/weather/weather.js
@@ -15,7 +15,6 @@ Module.register("weather", {
location: false,
locationID: false,
- appid: "",
units: config.units,
tempUnits: config.units,
@@ -43,8 +42,10 @@ Module.register("weather", {
initialLoadDelay: 0, // 0 seconds delay
retryDelay: 2500,
+ apiKey: "",
+ apiSecret: "",
apiVersion: "2.5",
- apiBase: "https://api.openweathermap.org/data/",
+ apiBase: "https://api.openweathermap.org/data/", // TODO: this should not be part of the weather.js file, but should be contained in the openweatherprovider
weatherEndpoint: "/weather",
appendLocationNameToHeader: true,
diff --git a/modules/default/weatherforecast/weatherforecast.js b/modules/default/weatherforecast/weatherforecast.js
index 83389911..3ff239ef 100644
--- a/modules/default/weatherforecast/weatherforecast.js
+++ b/modules/default/weatherforecast/weatherforecast.js
@@ -9,6 +9,8 @@ Module.register("weatherforecast", {
defaults: {
location: false,
locationID: false,
+ lat: false,
+ lon: false,
appid: "",
units: config.units,
maxNumberOfDays: 7,
@@ -29,6 +31,7 @@ Module.register("weatherforecast", {
apiVersion: "2.5",
apiBase: "https://api.openweathermap.org/data/",
forecastEndpoint: "forecast/daily",
+ excludes: false,
appendLocationNameToHeader: true,
calendarClass: "calendar",
@@ -283,6 +286,8 @@ Module.register("weatherforecast", {
var params = "?";
if (this.config.locationID) {
params += "id=" + this.config.locationID;
+ } else if (this.config.lat && this.config.lon) {
+ params += "lat=" + this.config.lat + "&lon=" + this.config.lon;
} else if (this.config.location) {
params += "q=" + this.config.location;
} else if (this.firstEvent && this.firstEvent.geo) {
@@ -294,8 +299,17 @@ Module.register("weatherforecast", {
return;
}
- params += "&cnt=" + (this.config.maxNumberOfDays < 1 || this.config.maxNumberOfDays > 17 ? 7 : this.config.maxNumberOfDays);
+ let numberOfDays;
+ if (this.config.forecastEndpoint === "forecast") {
+ numberOfDays = this.config.maxNumberOfDays < 1 || this.config.maxNumberOfDays > 5 ? 5 : this.config.maxNumberOfDays;
+ // don't get forecasts for the next day, as it would not represent the whole day
+ numberOfDays = numberOfDays * 8 - (Math.round(new Date().getHours() / 3) % 8);
+ } else {
+ numberOfDays = this.config.maxNumberOfDays < 1 || this.config.maxNumberOfDays > 17 ? 7 : this.config.maxNumberOfDays;
+ }
+ params += "&cnt=" + numberOfDays;
+ params += "&exclude=" + this.config.excludes;
params += "&units=" + this.config.units;
params += "&lang=" + this.config.lang;
params += "&APPID=" + this.config.appid;
@@ -323,15 +337,34 @@ Module.register("weatherforecast", {
* argument data object - Weather information received form openweather.org.
*/
processWeather: function (data) {
- this.fetchedLocationName = data.city.name + ", " + data.city.country;
+ // Forcast16 (paid) API endpoint provides this data. Onecall endpoint
+ // does not.
+ if (data.city) {
+ this.fetchedLocationName = data.city.name + ", " + data.city.country;
+ } else if (this.config.location) {
+ this.fetchedLocationName = this.config.location;
+ } else {
+ this.fetchedLocationName = "Unknown";
+ }
this.forecast = [];
var lastDay = null;
var forecastData = {};
- for (var i = 0, count = data.list.length; i < count; i++) {
- var forecast = data.list[i];
- this.parserDataWeather(forecast); // hack issue #1017
+ // Handle different structs between forecast16 and onecall endpoints
+ var forecastList = null;
+ if (data.list) {
+ forecastList = data.list;
+ } else if (data.daily) {
+ forecastList = data.daily;
+ } else {
+ Log.error("Unexpected forecast data");
+ return undefined;
+ }
+
+ for (var i = 0, count = forecastList.length; i < count; i++) {
+ var forecast = forecastList[i];
+ forecast = this.parserDataWeather(forecast); // hack issue #1017
var day;
var hour;
@@ -349,7 +382,7 @@ Module.register("weatherforecast", {
icon: this.config.iconTable[forecast.weather[0].icon],
maxTemp: this.roundValue(forecast.temp.max),
minTemp: this.roundValue(forecast.temp.min),
- rain: this.processRain(forecast, data.list)
+ rain: this.processRain(forecast, forecastList)
};
this.forecast.push(forecastData);
diff --git a/package-lock.json b/package-lock.json
index 15a6644a..87374cc7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "magicmirror",
- "version": "2.12.0",
+ "version": "2.13.0-develop",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -302,6 +302,24 @@
}
}
},
+ "@babel/runtime-corejs3": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.10.4.tgz",
+ "integrity": "sha512-BFlgP2SoLO9HJX9WBwN67gHWMBhDX/eDz64Jajd6mR/UAUzqrNMm99d4qHnVaKscAElZoFiPv+JpR/Siud5lXw==",
+ "dev": true,
+ "requires": {
+ "core-js-pure": "^3.0.0",
+ "regenerator-runtime": "^0.13.4"
+ },
+ "dependencies": {
+ "regenerator-runtime": {
+ "version": "0.13.5",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz",
+ "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==",
+ "dev": true
+ }
+ }
+ },
"@babel/template": {
"version": "7.10.1",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.1.tgz",
@@ -458,6 +476,88 @@
"to-fast-properties": "^2.0.0"
}
},
+ "@istanbuljs/load-nyc-config": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
+ "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.3.1",
+ "find-up": "^4.1.0",
+ "get-package-type": "^0.1.0",
+ "js-yaml": "^3.13.1",
+ "resolve-from": "^5.0.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true
+ },
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true
+ }
+ }
+ },
+ "@istanbuljs/schema": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz",
+ "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==",
+ "dev": true
+ },
"@nodelib/fs.scandir": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
@@ -636,6 +736,24 @@
"es6-promisify": "^5.0.0"
}
},
+ "aggregate-error": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz",
+ "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==",
+ "dev": true,
+ "requires": {
+ "clean-stack": "^2.0.0",
+ "indent-string": "^4.0.0"
+ },
+ "dependencies": {
+ "indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "dev": true
+ }
+ }
+ },
"ajv": {
"version": "6.10.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
@@ -650,7 +768,8 @@
"ansi-colors": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz",
- "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw=="
+ "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==",
+ "dev": true
},
"ansi-regex": {
"version": "2.1.1",
@@ -687,6 +806,21 @@
"integrity": "sha1-7klza2ObTxCLbp5ibG2pkwa0FpI=",
"dev": true
},
+ "append-transform": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz",
+ "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==",
+ "dev": true,
+ "requires": {
+ "default-require-extensions": "^3.0.0"
+ }
+ },
+ "archy": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
+ "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
+ "dev": true
+ },
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -983,9 +1117,9 @@
}
},
"bowser": {
- "version": "2.8.1",
- "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.8.1.tgz",
- "integrity": "sha512-FxxltGKqMHkVa3KtpA+kdnxH0caHPDewccyrK3vW1bsMw6Zco4vRPmMunowX0pXlDZqhxkKSpToADQI2Sk4OeQ=="
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.9.0.tgz",
+ "integrity": "sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA=="
},
"brace-expansion": {
"version": "1.1.11",
@@ -1088,6 +1222,18 @@
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
},
+ "caching-transform": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz",
+ "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==",
+ "dev": true,
+ "requires": {
+ "hasha": "^5.0.0",
+ "make-dir": "^3.0.0",
+ "package-hash": "^4.0.0",
+ "write-file-atomic": "^3.0.0"
+ }
+ },
"callsite": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
@@ -1226,6 +1372,12 @@
"resolved": "https://registry.npmjs.org/clarinet/-/clarinet-0.12.4.tgz",
"integrity": "sha512-Rx9Zw8KQkoPO3/O2yPRchCZm3cGubCQiRLmmFAlbkDKobUIPP3JYul+bKILR9DIv1gSVwPQSgF8JGGkXzX8Q0w=="
},
+ "clean-stack": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+ "dev": true
+ },
"cli-width": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
@@ -1328,6 +1480,12 @@
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
+ "commondir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
+ "dev": true
+ },
"compare-versions": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz",
@@ -1467,6 +1625,12 @@
"integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==",
"dev": true
},
+ "core-js-pure": {
+ "version": "3.6.5",
+ "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz",
+ "integrity": "sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==",
+ "dev": true
+ },
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
@@ -1758,6 +1922,23 @@
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
},
+ "default-require-extensions": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz",
+ "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==",
+ "dev": true,
+ "requires": {
+ "strip-bom": "^4.0.0"
+ },
+ "dependencies": {
+ "strip-bom": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
+ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
+ "dev": true
+ }
+ }
+ },
"define-properties": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
@@ -1819,11 +2000,6 @@
}
}
},
- "dns-prefetch-control": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz",
- "integrity": "sha512-hvSnros73+qyZXhHFjx2CMLwoj3Fe7eR9EJsFsqmcI1bB2OBWL/+0YzaEaKssCHnj/6crawNnUyw74Gm2EKe+Q=="
- },
"doctrine": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
@@ -2078,11 +2254,18 @@
}
},
"enquirer": {
- "version": "2.3.5",
- "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.5.tgz",
- "integrity": "sha512-BNT1C08P9XD0vNg3J475yIUG+mVdp9T6towYFHUv897X0KoHBjB1shyrNmhmtHWKP17iSWgo7Gqh7BBuzLZMSA==",
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
+ "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
"requires": {
- "ansi-colors": "^3.2.1"
+ "ansi-colors": "^4.1.1"
+ },
+ "dependencies": {
+ "ansi-colors": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+ "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA=="
+ }
}
},
"entities": {
@@ -2142,6 +2325,12 @@
"is-symbol": "^1.0.2"
}
},
+ "es6-error": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
+ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
+ "dev": true
+ },
"es6-promise": {
"version": "4.2.8",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
@@ -2189,9 +2378,9 @@
}
},
"eslint": {
- "version": "7.3.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.3.0.tgz",
- "integrity": "sha512-dJMVXwfU5PT1cj2Nv2VPPrKahKTGdX+5Dh0Q3YuKt+Y2UhdL2YbzsVaBMyG9HC0tBismlv/r1+eZqs6SMIV38Q==",
+ "version": "7.4.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.4.0.tgz",
+ "integrity": "sha512-gU+lxhlPHu45H3JkEGgYhWhkR9wLHHEXC9FbWFnTlEkbKyZKWgWRLgf61E8zWmBuI6g5xKBph9ltg3NtZMVF8g==",
"requires": {
"@babel/code-frame": "^7.0.0",
"ajv": "^6.10.0",
@@ -2518,11 +2707,6 @@
"homedir-polyfill": "^1.0.1"
}
},
- "expect-ct": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/expect-ct/-/expect-ct-0.2.0.tgz",
- "integrity": "sha512-6SK3MG/Bbhm8MsgyJAylg+ucIOU71/FzyFalcfu5nY19dH8y/z0tBJU0wrNBXD4B27EoQtqPF/9wqH0iYAd04g=="
- },
"express": {
"version": "4.17.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
@@ -2754,6 +2938,17 @@
}
}
},
+ "find-cache-dir": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz",
+ "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==",
+ "dev": true,
+ "requires": {
+ "commondir": "^1.0.1",
+ "make-dir": "^3.0.2",
+ "pkg-dir": "^4.1.0"
+ }
+ },
"find-up": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
@@ -2796,6 +2991,59 @@
"resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
"integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA=="
},
+ "foreground-child": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
+ "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
+ "dev": true,
+ "requires": {
+ "cross-spawn": "^7.0.0",
+ "signal-exit": "^3.0.2"
+ },
+ "dependencies": {
+ "cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "requires": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ }
+ },
+ "path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true
+ },
+ "shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "^3.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true
+ },
+ "which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ }
+ }
+ },
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
@@ -2816,16 +3064,17 @@
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
},
- "frameguard": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/frameguard/-/frameguard-3.1.0.tgz",
- "integrity": "sha512-TxgSKM+7LTA6sidjOiSZK9wxY0ffMPY3Wta//MqwmX0nZuEHc8QrkV8Fh3ZhMJeiH+Uyh/tcaarImRy8u77O7g=="
- },
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
+ "fromentries": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.0.tgz",
+ "integrity": "sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ==",
+ "dev": true
+ },
"fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
@@ -2898,6 +3147,12 @@
"integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
"dev": true
},
+ "get-package-type": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
+ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
+ "dev": true
+ },
"get-stdin": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
@@ -3129,6 +3384,24 @@
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
"dev": true
},
+ "hasha": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.0.tgz",
+ "integrity": "sha512-2W+jKdQbAdSIrggA8Q35Br8qKadTrqCTC8+XZvBWepKDK6m9XkX6Iz1a2yh2KP01kzAR/dpuMeUnocoLYDcskw==",
+ "dev": true,
+ "requires": {
+ "is-stream": "^2.0.0",
+ "type-fest": "^0.8.0"
+ },
+ "dependencies": {
+ "is-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
+ "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
+ "dev": true
+ }
+ }
+ },
"he": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
@@ -3136,22 +3409,18 @@
"dev": true
},
"helmet": {
- "version": "3.21.2",
- "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.21.2.tgz",
- "integrity": "sha512-okUo+MeWgg00cKB8Csblu8EXgcIoDyb5ZS/3u0W4spCimeVuCUvVZ6Vj3O2VJ1Sxpyb8jCDvzu0L1KKT11pkIg==",
+ "version": "3.23.3",
+ "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.23.3.tgz",
+ "integrity": "sha512-U3MeYdzPJQhtvqAVBPntVgAvNSOJyagwZwyKsFdyRa8TV3pOKVFljalPOCxbw5Wwf2kncGhmP0qHjyazIdNdSA==",
"requires": {
"depd": "2.0.0",
- "dns-prefetch-control": "0.2.0",
"dont-sniff-mimetype": "1.1.0",
- "expect-ct": "0.2.0",
"feature-policy": "0.3.0",
- "frameguard": "3.1.0",
"helmet-crossdomain": "0.4.0",
- "helmet-csp": "2.9.4",
+ "helmet-csp": "2.10.0",
"hide-powered-by": "1.1.0",
"hpkp": "2.0.0",
"hsts": "2.2.0",
- "ienoopen": "1.1.0",
"nocache": "2.1.0",
"referrer-policy": "1.2.0",
"x-xss-protection": "1.3.0"
@@ -3170,11 +3439,11 @@
"integrity": "sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA=="
},
"helmet-csp": {
- "version": "2.9.4",
- "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.9.4.tgz",
- "integrity": "sha512-qUgGx8+yk7Xl8XFEGI4MFu1oNmulxhQVTlV8HP8tV3tpfslCs30OZz/9uQqsWPvDISiu/NwrrCowsZBhFADYqg==",
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.10.0.tgz",
+ "integrity": "sha512-Rz953ZNEFk8sT2XvewXkYN0Ho4GEZdjAZy4stjiEQV3eN7GDxg1QKmYggH7otDyIA7uGA6XnUMVSgeJwbR5X+w==",
"requires": {
- "bowser": "^2.7.0",
+ "bowser": "2.9.0",
"camelize": "1.0.0",
"content-security-policy-builder": "2.1.0",
"dasherize": "2.0.0"
@@ -3228,6 +3497,12 @@
"whatwg-encoding": "^1.0.1"
}
},
+ "html-escaper": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+ "dev": true
+ },
"html-tags": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz",
@@ -3456,11 +3731,6 @@
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
"dev": true
},
- "ienoopen": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/ienoopen/-/ienoopen-1.1.0.tgz",
- "integrity": "sha512-MFs36e/ca6ohEKtinTJ5VvAJ6oDRAYFdYXweUnGY9L9vcoqFOU4n2ZhmJ0C4z/cwGZ3YIQRSB3XZ1+ghZkY5NQ=="
- },
"ignore": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
@@ -3710,6 +3980,12 @@
"integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==",
"dev": true
},
+ "is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "dev": true
+ },
"is-word-character": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz",
@@ -3731,6 +4007,168 @@
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
+ "istanbul-lib-coverage": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz",
+ "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==",
+ "dev": true
+ },
+ "istanbul-lib-hook": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz",
+ "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==",
+ "dev": true,
+ "requires": {
+ "append-transform": "^2.0.0"
+ }
+ },
+ "istanbul-lib-instrument": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz",
+ "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==",
+ "dev": true,
+ "requires": {
+ "@babel/core": "^7.7.5",
+ "@istanbuljs/schema": "^0.1.2",
+ "istanbul-lib-coverage": "^3.0.0",
+ "semver": "^6.3.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "istanbul-lib-processinfo": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz",
+ "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==",
+ "dev": true,
+ "requires": {
+ "archy": "^1.0.0",
+ "cross-spawn": "^7.0.0",
+ "istanbul-lib-coverage": "^3.0.0-alpha.1",
+ "make-dir": "^3.0.0",
+ "p-map": "^3.0.0",
+ "rimraf": "^3.0.0",
+ "uuid": "^3.3.3"
+ },
+ "dependencies": {
+ "cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "requires": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ }
+ },
+ "path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true
+ },
+ "rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "^3.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true
+ },
+ "which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ }
+ }
+ },
+ "istanbul-lib-report": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
+ "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
+ "dev": true,
+ "requires": {
+ "istanbul-lib-coverage": "^3.0.0",
+ "make-dir": "^3.0.0",
+ "supports-color": "^7.1.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+ "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "istanbul-lib-source-maps": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz",
+ "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==",
+ "dev": true,
+ "requires": {
+ "debug": "^4.1.1",
+ "istanbul-lib-coverage": "^3.0.0",
+ "source-map": "^0.6.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ }
+ }
+ },
+ "istanbul-reports": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz",
+ "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==",
+ "dev": true,
+ "requires": {
+ "html-escaper": "^2.0.0",
+ "istanbul-lib-report": "^3.0.0"
+ }
+ },
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -3785,9 +4223,9 @@
},
"dependencies": {
"acorn": {
- "version": "5.7.3",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
- "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==",
+ "version": "5.7.4",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz",
+ "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==",
"dev": true
},
"ws": {
@@ -4075,9 +4513,9 @@
}
},
"lodash": {
- "version": "4.17.15",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
- "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
+ "version": "4.17.19",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
+ "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
},
"lodash.find": {
"version": "4.6.0",
@@ -4085,6 +4523,12 @@
"integrity": "sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=",
"dev": true
},
+ "lodash.flattendeep": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
+ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
+ "dev": true
+ },
"lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
@@ -4212,6 +4656,23 @@
"integrity": "sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==",
"dev": true
},
+ "make-dir": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "dev": true,
+ "requires": {
+ "semver": "^6.0.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
"map-age-cleaner": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
@@ -4828,6 +5289,15 @@
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==",
"dev": true
},
+ "node-preload": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
+ "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==",
+ "dev": true,
+ "requires": {
+ "process-on-spawn": "^1.0.0"
+ }
+ },
"node-releases": {
"version": "1.1.58",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.58.tgz",
@@ -4924,6 +5394,270 @@
"integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==",
"dev": true
},
+ "nyc": {
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz",
+ "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==",
+ "dev": true,
+ "requires": {
+ "@istanbuljs/load-nyc-config": "^1.0.0",
+ "@istanbuljs/schema": "^0.1.2",
+ "caching-transform": "^4.0.0",
+ "convert-source-map": "^1.7.0",
+ "decamelize": "^1.2.0",
+ "find-cache-dir": "^3.2.0",
+ "find-up": "^4.1.0",
+ "foreground-child": "^2.0.0",
+ "get-package-type": "^0.1.0",
+ "glob": "^7.1.6",
+ "istanbul-lib-coverage": "^3.0.0",
+ "istanbul-lib-hook": "^3.0.0",
+ "istanbul-lib-instrument": "^4.0.0",
+ "istanbul-lib-processinfo": "^2.0.2",
+ "istanbul-lib-report": "^3.0.0",
+ "istanbul-lib-source-maps": "^4.0.0",
+ "istanbul-reports": "^3.0.2",
+ "make-dir": "^3.0.0",
+ "node-preload": "^0.2.1",
+ "p-map": "^3.0.0",
+ "process-on-spawn": "^1.0.0",
+ "resolve-from": "^5.0.0",
+ "rimraf": "^3.0.0",
+ "signal-exit": "^3.0.2",
+ "spawn-wrap": "^2.0.0",
+ "test-exclude": "^6.0.0",
+ "yargs": "^15.0.2"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+ "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+ "dev": true,
+ "requires": {
+ "@types/color-name": "^1.1.1",
+ "color-convert": "^2.0.1"
+ }
+ },
+ "camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true
+ },
+ "cliui": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+ "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+ "dev": true,
+ "requires": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^6.2.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true
+ },
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "require-main-filename": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+ "dev": true
+ },
+ "resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true
+ },
+ "rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ },
+ "wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "y18n": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+ "dev": true
+ },
+ "yargs": {
+ "version": "15.4.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.0.tgz",
+ "integrity": "sha512-D3fRFnZwLWp8jVAAhPZBsmeIHY8tTsb8ItV9KaAaopmC6wde2u6Yw29JBIZHXw14kgkRnYmDgmQU4FVMDlIsWw==",
+ "dev": true,
+ "requires": {
+ "cliui": "^6.0.0",
+ "decamelize": "^3.2.0",
+ "find-up": "^4.1.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^4.2.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^18.1.2"
+ },
+ "dependencies": {
+ "decamelize": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-3.2.0.tgz",
+ "integrity": "sha512-4TgkVUsmmu7oCSyGBm5FvfMoACuoh9EOidm7V5/J2X2djAwwt57qb3F2KMP2ITqODTCSwb+YRV+0Zqrv18k/hw==",
+ "dev": true,
+ "requires": {
+ "xregexp": "^4.2.4"
+ }
+ }
+ }
+ },
+ "yargs-parser": {
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+ "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ }
+ }
+ },
"oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
@@ -5106,12 +5840,33 @@
"p-limit": "^1.1.0"
}
},
+ "p-map": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
+ "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
+ "dev": true,
+ "requires": {
+ "aggregate-error": "^3.0.0"
+ }
+ },
"p-try": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
"integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
"dev": true
},
+ "package-hash": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz",
+ "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.15",
+ "hasha": "^5.0.0",
+ "lodash.flattendeep": "^4.4.0",
+ "release-zalgo": "^1.0.0"
+ }
+ },
"parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -5804,6 +6559,15 @@
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
+ "process-on-spawn": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz",
+ "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==",
+ "dev": true,
+ "requires": {
+ "fromentries": "^1.2.0"
+ }
+ },
"progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
@@ -5993,6 +6757,15 @@
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz",
"integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q=="
},
+ "release-zalgo": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
+ "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=",
+ "dev": true,
+ "requires": {
+ "es6-error": "^4.0.1"
+ }
+ },
"remark": {
"version": "12.0.0",
"resolved": "https://registry.npmjs.org/remark/-/remark-12.0.0.tgz",
@@ -6569,6 +7342,40 @@
"integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
"dev": true
},
+ "spawn-wrap": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz",
+ "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==",
+ "dev": true,
+ "requires": {
+ "foreground-child": "^2.0.0",
+ "is-windows": "^1.0.2",
+ "make-dir": "^3.0.0",
+ "rimraf": "^3.0.0",
+ "signal-exit": "^3.0.2",
+ "which": "^2.0.1"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ }
+ }
+ },
"spdx-correct": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
@@ -7713,6 +8520,33 @@
}
}
},
+ "test-exclude": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
+ "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+ "dev": true,
+ "requires": {
+ "@istanbuljs/schema": "^0.1.2",
+ "glob": "^7.1.4",
+ "minimatch": "^3.0.4"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ }
+ }
+ },
"text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -8304,6 +9138,15 @@
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
"integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4="
},
+ "xregexp": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.3.0.tgz",
+ "integrity": "sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime-corejs3": "^7.8.3"
+ }
+ },
"xtend": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz",
diff --git a/package.json b/package.json
index 5b9562d5..3941f415 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "magicmirror",
- "version": "2.12.0",
+ "version": "2.13.0-develop",
"description": "The open source modular smart mirror platform.",
"main": "js/electron.js",
"scripts": {
@@ -9,9 +9,10 @@
"install": "echo \"Installing vendor files ...\n\" && cd vendor && npm install --loglevel=error",
"install-fonts": "echo \"Installing fonts ...\n\" && cd fonts && npm install --loglevel=error",
"postinstall": "npm run install-fonts && echo \"MagicMirror installation finished successfully! \n\"",
- "test": "NODE_ENV=test ./node_modules/mocha/bin/mocha tests --recursive",
- "test:unit": "NODE_ENV=test ./node_modules/mocha/bin/mocha tests/unit --recursive",
- "test:e2e": "NODE_ENV=test ./node_modules/mocha/bin/mocha tests/e2e --recursive",
+ "test": "NODE_ENV=test mocha tests --recursive",
+ "test:coverage": "NODE_ENV=test nyc mocha tests --recursive --timeout=3000",
+ "test:e2e": "NODE_ENV=test mocha tests/e2e --recursive",
+ "test:unit": "NODE_ENV=test mocha tests/unit --recursive",
"test:prettier": "prettier --check **/*.{js,css,json,md,yml}",
"test:js": "eslint *.js js/**/*.js modules/default/**/*.js clientonly/*.js serveronly/*.js translations/*.js vendor/*.js tests/**/*.js config/* --config .eslintrc.json --quiet",
"test:css": "stylelint css/main.css modules/default/**/*.css --config .stylelintrc.json",
@@ -54,6 +55,7 @@
"mocha": "^7.1.2",
"mocha-each": "^2.0.1",
"mocha-logger": "^1.0.6",
+ "nyc": "^15.1.0",
"prettier": "^2.0.5",
"pretty-quick": "^2.0.1",
"spectron": "^8.0.0",
@@ -68,18 +70,18 @@
"dependencies": {
"colors": "^1.1.2",
"console-stamp": "^0.2.9",
- "eslint": "^7.3.0",
+ "eslint": "^7.4.0",
"express": "^4.16.2",
"express-ipfilter": "^1.0.1",
"feedme": "latest",
- "helmet": "^3.21.2",
+ "helmet": "^3.23.3",
"ical": "^0.8.0",
"iconv-lite": "latest",
- "lodash": "^4.17.15",
+ "lodash": "^4.17.19",
"module-alias": "^2.2.2",
"moment": "latest",
"request": "^2.88.2",
- "rrule": "^2.6.2",
+ "rrule": "^2.6.4",
"rrule-alt": "^2.2.8",
"simple-git": "^1.85.0",
"socket.io": "^2.1.1",
diff --git a/tests/configs/data/StripComments.json b/tests/configs/data/StripComments.json
deleted file mode 100644
index e9d1c403..00000000
--- a/tests/configs/data/StripComments.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- // Escaped
- "FOO\"BAR": "Today",
-
- /*
- * The following lines
- * represent cardinal directions
- */
- "N": "N",
- "E": "E",
- "S": "S",
- "W": "W"
-}
diff --git a/tests/configs/data/calendar_test_icons.ics b/tests/configs/data/calendar_test_icons.ics
new file mode 100644
index 00000000..7f24060d
--- /dev/null
+++ b/tests/configs/data/calendar_test_icons.ics
@@ -0,0 +1,56 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//ical.marudot.com//iCal Event Maker
+X-WR-CALNAME:TestEvents
+NAME:TestEvents
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:Europe/Berlin
+TZURL:http://tzurl.org/zoneinfo-outlook/Europe/Berlin
+X-LIC-LOCATION:Europe/Berlin
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0200
+TZNAME:CEST
+DTSTART:19700329T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0200
+TZOFFSETTO:+0100
+TZNAME:CET
+DTSTART:19701025T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTAMP:20200719T094531Z
+UID:20200719T094531Z-1871115387@marudot.com
+DTSTART;TZID=Europe/Berlin:20300101T120000
+DTEND;TZID=Europe/Berlin:20300101T130000
+SUMMARY:TestEvent
+END:VEVENT
+BEGIN:VEVENT
+DTSTAMP:20200719T094531Z
+UID:20200719T094531Z-1929725136@marudot.com
+DTSTART;TZID=Europe/Berlin:20300701T120000
+RRULE:FREQ=YEARLY;BYMONTH=7;BYMONTHDAY=1
+DTEND;TZID=Europe/Berlin:20300701T130000
+SUMMARY:TestEventRepeat
+END:VEVENT
+BEGIN:VEVENT
+DTSTAMP:20200719T094531Z
+UID:20200719T094531Z-371801474@marudot.com
+DTSTART;VALUE=DATE:20300401
+DTEND;VALUE=DATE:20300402
+SUMMARY:TestEventDay
+END:VEVENT
+BEGIN:VEVENT
+DTSTAMP:20200719T094531Z
+UID:20200719T094531Z-133401084@marudot.com
+DTSTART;VALUE=DATE:20301001
+RRULE:FREQ=YEARLY;BYMONTH=10;BYMONTHDAY=1
+DTEND;VALUE=DATE:20301002
+SUMMARY:TestEventRepeatDay
+END:VEVENT
+END:VCALENDAR
\ No newline at end of file
diff --git a/tests/configs/modules/calendar/custom.js b/tests/configs/modules/calendar/custom.js
new file mode 100644
index 00000000..2084419d
--- /dev/null
+++ b/tests/configs/modules/calendar/custom.js
@@ -0,0 +1,41 @@
+/* Magic Mirror Test config custom calendar
+ *
+ * MIT Licensed.
+ */
+let config = {
+ port: 8080,
+ ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"],
+
+ language: "en",
+ timeFormat: 12,
+ units: "metric",
+ electronOptions: {
+ webPreferences: {
+ nodeIntegration: true
+ }
+ },
+
+ modules: [
+ {
+ module: "calendar",
+ position: "bottom_bar",
+ config: {
+ calendars: [
+ {
+ symbol: "birthday-cake",
+ fullDaySymbol: "calendar-day",
+ recurringSymbol: "undo",
+ maximumEntries: 4,
+ maximumNumberOfDays: 10000,
+ url: "http://localhost:8080/tests/configs/data/calendar_test_icons.ics"
+ }
+ ]
+ }
+ }
+ ]
+};
+
+/*************** DO NOT EDIT THE LINE BELOW ***************/
+if (typeof module !== "undefined") {
+ module.exports = config;
+}
diff --git a/tests/e2e/modules/calendar_spec.js b/tests/e2e/modules/calendar_spec.js
index 7af78201..3712871c 100644
--- a/tests/e2e/modules/calendar_spec.js
+++ b/tests/e2e/modules/calendar_spec.js
@@ -1,5 +1,6 @@
const helpers = require("../global-setup");
const serverBasicAuth = require("../../servers/basic-auth.js");
+const expect = require("chai").expect;
const describe = global.describe;
const it = global.it;
@@ -31,8 +32,47 @@ describe("Calendar module", function () {
process.env.MM_CONFIG_FILE = "tests/configs/modules/calendar/default.js";
});
- it("Should return TestEvents", function () {
- return app.client.waitUntilTextExists(".calendar", "TestEvent", 10000);
+ it("should show the default maximumEntries of 10", async () => {
+ await app.client.waitUntilTextExists(".calendar", "TestEvent", 10000);
+ const events = await app.client.$$(".calendar .event");
+ return expect(events.length).equals(10);
+ });
+
+ it("should show the default calendar symbol in each event", async () => {
+ await app.client.waitUntilTextExists(".calendar", "TestEvent", 10000);
+ const icons = await app.client.$$(".calendar .event .fa-calendar");
+ return expect(icons.length).not.equals(0);
+ });
+ });
+
+ describe("Custom configuration", function () {
+ before(function () {
+ // Set config sample for use in test
+ process.env.MM_CONFIG_FILE = "tests/configs/modules/calendar/custom.js";
+ });
+
+ it("should show the custom maximumEntries of 4", async () => {
+ await app.client.waitUntilTextExists(".calendar", "TestEvent", 10000);
+ const events = await app.client.$$(".calendar .event");
+ return expect(events.length).equals(4);
+ });
+
+ it("should show the custom calendar symbol in each event", async () => {
+ await app.client.waitUntilTextExists(".calendar", "TestEvent", 10000);
+ const icons = await app.client.$$(".calendar .event .fa-birthday-cake");
+ return expect(icons.length).equals(4);
+ });
+
+ it("should show two custom icons for repeating events", async () => {
+ await app.client.waitUntilTextExists(".calendar", "TestEventRepeat", 10000);
+ const icons = await app.client.$$(".calendar .event .fa-undo");
+ return expect(icons.length).equals(2);
+ });
+
+ it("should show two custom icons for day events", async () => {
+ await app.client.waitUntilTextExists(".calendar", "TestEventDay", 10000);
+ const icons = await app.client.$$(".calendar .event .fa-calendar-day");
+ return expect(icons.length).equals(2);
});
});
@@ -47,7 +87,7 @@ describe("Calendar module", function () {
serverBasicAuth.close(done());
});
- it("Should return TestEvents", function () {
+ it("should return TestEvents", function () {
return app.client.waitUntilTextExists(".calendar", "TestEvent", 10000);
});
});
@@ -63,7 +103,7 @@ describe("Calendar module", function () {
serverBasicAuth.close(done());
});
- it("Should return TestEvents", function () {
+ it("should return TestEvents", function () {
return app.client.waitUntilTextExists(".calendar", "TestEvent", 10000);
});
});
@@ -79,7 +119,7 @@ describe("Calendar module", function () {
serverBasicAuth.close(done());
});
- it("Should return TestEvents", function () {
+ it("should return TestEvents", function () {
return app.client.waitUntilTextExists(".calendar", "TestEvent", 10000);
});
});
@@ -95,7 +135,7 @@ describe("Calendar module", function () {
serverBasicAuth.close(done());
});
- it("Should return No upcoming events", function () {
+ it("should return No upcoming events", function () {
return app.client.waitUntilTextExists(".calendar", "No upcoming events.", 10000);
});
});
diff --git a/tests/servers/basic-auth.js b/tests/servers/basic-auth.js
index b1277cf1..3c294a86 100644
--- a/tests/servers/basic-auth.js
+++ b/tests/servers/basic-auth.js
@@ -1,7 +1,7 @@
-var path = require("path");
-var auth = require("http-auth");
-var express = require("express");
-var app = express();
+const path = require("path");
+const auth = require("http-auth");
+const express = require("express");
+const app = express();
var server;
diff --git a/tests/unit/classes/translator_spec.js b/tests/unit/classes/translator_spec.js
index b0ec084c..e3355d68 100644
--- a/tests/unit/classes/translator_spec.js
+++ b/tests/unit/classes/translator_spec.js
@@ -171,25 +171,6 @@ describe("Translator", function () {
};
});
- it("should strip comments", function (done) {
- const dom = new JSDOM(`