diff --git a/package.json b/package.json index 1e6bc6abf7..82f4d700b1 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ "version": "1.0.0", "scripts": { "build": "script/build_frontend", - "lint": "eslint src hassio/src gallery/src test-mocha && tslint -c tslint.json 'src/**/*.ts' 'hassio/src/**/*.ts' 'gallery/src/**/*.ts' 'test-mocha/**/*.ts' && polymer lint && tsc", - "mocha": "node_modules/.bin/mocha --opts test-mocha/mocha.opts", + "lint": "eslint src hassio/src gallery/src && tslint 'src/**/*.ts' 'hassio/src/**/*.ts' 'gallery/src/**/*.ts' 'test-mocha/**/*.ts' && polymer lint && tsc", + "mocha": "node_modules/.bin/ts-mocha -p test-mocha/tsconfig.test.json --opts test-mocha/mocha.opts", "test": "npm run lint && npm run mocha", "docker_build": "sh ./script/docker_run.sh build $npm_package_version", "bash": "sh ./script/docker_run.sh bash $npm_package_version" @@ -100,10 +100,12 @@ "@babel/preset-env": "^7.1.0", "@babel/preset-typescript": "^7.1.0", "@gfx/zopfli": "^1.0.9", + "@types/chai": "^4.1.7", + "@types/mocha": "^5.2.5", "babel-eslint": "^10", "babel-loader": "^8.0.4", "babel-minify-webpack-plugin": "^0.3.1", - "chai": "^4.1.2", + "chai": "^4.2.0", "compression-webpack-plugin": "^2.0.0", "copy-webpack-plugin": "^4.5.2", "del": "^3.0.0", @@ -126,7 +128,6 @@ "husky": "^1.1.0", "lint-staged": "^8.0.2", "merge-stream": "^1.0.1", - "mocha": "^5.2.0", "parse5": "^5.1.0", "polymer-analyzer": "^3.1.2", "polymer-bundler": "^4.0.2", @@ -135,7 +136,8 @@ "raw-loader": "^0.5.1", "reify": "^0.18.1", "require-dir": "^1.0.0", - "sinon": "^7.1.0", + "sinon": "^7.1.1", + "ts-mocha": "^2.0.0", "tslint": "^5.11.0", "tslint-config-prettier": "^1.15.0", "tslint-eslint-rules": "^5.4.0", diff --git a/src/common/config/is_component_loaded.js b/src/common/config/is_component_loaded.js deleted file mode 100644 index 318eb56936..0000000000 --- a/src/common/config/is_component_loaded.js +++ /dev/null @@ -1,4 +0,0 @@ -/** Return if a component is loaded. */ -export default function isComponentLoaded(hass, component) { - return hass && hass.config.components.indexOf(component) !== -1; -} diff --git a/src/common/config/is_component_loaded.ts b/src/common/config/is_component_loaded.ts new file mode 100644 index 0000000000..c8535cda6b --- /dev/null +++ b/src/common/config/is_component_loaded.ts @@ -0,0 +1,9 @@ +import { HomeAssistant } from "../../types"; + +/** Return if a component is loaded. */ +export default function isComponentLoaded( + hass: HomeAssistant, + component: string +): boolean { + return hass && hass.config.components.indexOf(component) !== -1; +} diff --git a/src/common/config/is_pwa.js b/src/common/config/is_pwa.ts similarity index 75% rename from src/common/config/is_pwa.js rename to src/common/config/is_pwa.ts index c2a4bcbde6..a7fa4f4376 100644 --- a/src/common/config/is_pwa.js +++ b/src/common/config/is_pwa.ts @@ -1,4 +1,4 @@ /** Return if the displaymode is in standalone mode (PWA). */ -export default function isPwa() { +export default function isPwa(): boolean { return window.matchMedia("(display-mode: standalone)").matches; } diff --git a/src/common/config/location_name.js b/src/common/config/location_name.js deleted file mode 100644 index 83d8fc32a4..0000000000 --- a/src/common/config/location_name.js +++ /dev/null @@ -1,4 +0,0 @@ -/** Get the location name from a hass object. */ -export default function computeLocationName(hass) { - return hass && hass.config.location_name; -} diff --git a/src/common/config/location_name.ts b/src/common/config/location_name.ts new file mode 100644 index 0000000000..d198951b24 --- /dev/null +++ b/src/common/config/location_name.ts @@ -0,0 +1,6 @@ +import { HomeAssistant } from "../../types"; + +/** Get the location name from a hass object. */ +export default function computeLocationName(hass: HomeAssistant): string { + return hass && hass.config.location_name; +} diff --git a/src/common/const.js b/src/common/const.ts similarity index 100% rename from src/common/const.js rename to src/common/const.ts diff --git a/src/common/datetime/duration_to_seconds.js b/src/common/datetime/duration_to_seconds.ts similarity index 59% rename from src/common/datetime/duration_to_seconds.js rename to src/common/datetime/duration_to_seconds.ts index bdd4a006a9..f579c57b88 100644 --- a/src/common/datetime/duration_to_seconds.js +++ b/src/common/datetime/duration_to_seconds.ts @@ -1,4 +1,4 @@ -export default function durationToSeconds(duration) { +export default function durationToSeconds(duration: string): number { const parts = duration.split(":").map(Number); return parts[0] * 3600 + parts[1] * 60 + parts[2]; } diff --git a/src/common/datetime/format_date.js b/src/common/datetime/format_date.ts similarity index 70% rename from src/common/datetime/format_date.js rename to src/common/datetime/format_date.ts index fac7fb1ce9..09cd0223e2 100644 --- a/src/common/datetime/format_date.js +++ b/src/common/datetime/format_date.ts @@ -1,4 +1,4 @@ -import fecha from "fecha"; +import * as fecha from "fecha"; // Check for support of native locale string options function toLocaleDateStringSupportsOptions() { @@ -11,11 +11,10 @@ function toLocaleDateStringSupportsOptions() { } export default (toLocaleDateStringSupportsOptions() - ? (dateObj, locales) => + ? (dateObj: Date, locales: string) => dateObj.toLocaleDateString(locales, { year: "numeric", month: "long", day: "numeric", }) - : // eslint-disable-next-line no-unused-vars - (dateObj, locales) => fecha.format(dateObj, "mediumDate")); + : (dateObj: Date) => fecha.format(dateObj, "mediumDate")); diff --git a/src/common/datetime/format_date_time.js b/src/common/datetime/format_date_time.ts similarity index 72% rename from src/common/datetime/format_date_time.js rename to src/common/datetime/format_date_time.ts index bc8d54cd47..3421a5d291 100644 --- a/src/common/datetime/format_date_time.js +++ b/src/common/datetime/format_date_time.ts @@ -1,4 +1,4 @@ -import fecha from "fecha"; +import * as fecha from "fecha"; // Check for support of native locale string options function toLocaleStringSupportsOptions() { @@ -11,7 +11,7 @@ function toLocaleStringSupportsOptions() { } export default (toLocaleStringSupportsOptions() - ? (dateObj, locales) => + ? (dateObj: Date, locales: string) => dateObj.toLocaleString(locales, { year: "numeric", month: "long", @@ -19,5 +19,4 @@ export default (toLocaleStringSupportsOptions() hour: "numeric", minute: "2-digit", }) - : // eslint-disable-next-line no-unused-vars - (dateObj, locales) => fecha.format(dateObj, "haDateTime")); + : (dateObj: Date) => fecha.format(dateObj, "haDateTime")); diff --git a/src/common/datetime/format_time.js b/src/common/datetime/format_time.ts similarity index 70% rename from src/common/datetime/format_time.js rename to src/common/datetime/format_time.ts index dcf7d32d7d..e5abe800b6 100644 --- a/src/common/datetime/format_time.js +++ b/src/common/datetime/format_time.ts @@ -1,4 +1,4 @@ -import fecha from "fecha"; +import * as fecha from "fecha"; // Check for support of native locale string options function toLocaleTimeStringSupportsOptions() { @@ -11,10 +11,9 @@ function toLocaleTimeStringSupportsOptions() { } export default (toLocaleTimeStringSupportsOptions() - ? (dateObj, locales) => + ? (dateObj: Date, locales: string) => dateObj.toLocaleTimeString(locales, { hour: "numeric", minute: "2-digit", }) - : // eslint-disable-next-line no-unused-vars - (dateObj, locales) => fecha.format(dateObj, "shortTime")); + : (dateObj: Date) => fecha.format(dateObj, "shortTime")); diff --git a/src/common/datetime/relative_time.js b/src/common/datetime/relative_time.js deleted file mode 100644 index c76d071c22..0000000000 --- a/src/common/datetime/relative_time.js +++ /dev/null @@ -1,33 +0,0 @@ -/** Calculate a string representing a date object as relative time from now. - * - * Example output: 5 minutes ago, in 3 days. - */ -const tests = [60, "second", 60, "minute", 24, "hour", 7, "day"]; - -export default function relativeTime(dateObj, localize) { - let delta = (new Date() - dateObj) / 1000; - const tense = delta >= 0 ? "past" : "future"; - delta = Math.abs(delta); - - for (let i = 0; i < tests.length; i += 2) { - if (delta < tests[i]) { - delta = Math.floor(delta); - const time = localize( - `ui.components.relative_time.duration.${tests[i + 1]}`, - "count", - delta - ); - return localize(`ui.components.relative_time.${tense}`, "time", time); - } - - delta /= tests[i]; - } - - delta = Math.floor(delta); - const time = localize( - "ui.components.relative_time.duration.week", - "count", - delta - ); - return localize(`ui.components.relative_time.${tense}`, "time", time); -} diff --git a/src/common/datetime/relative_time.ts b/src/common/datetime/relative_time.ts new file mode 100644 index 0000000000..7daabdc657 --- /dev/null +++ b/src/common/datetime/relative_time.ts @@ -0,0 +1,40 @@ +import { LocalizeFunc } from "../../mixins/localize-base-mixin"; + +/** + * Calculate a string representing a date object as relative time from now. + * + * Example output: 5 minutes ago, in 3 days. + */ +const tests = [60, 60, 24, 7]; +const langKey = ["second", "minute", "hour", "day"]; + +export default function relativeTime( + dateObj: Date, + localize: LocalizeFunc +): string { + let delta = (new Date().getTime() - dateObj.getTime()) / 1000; + const tense = delta >= 0 ? "past" : "future"; + delta = Math.abs(delta); + + for (let i = 0; i < tests.length; i++) { + if (delta < tests[i]) { + delta = Math.floor(delta); + const timeDesc = localize( + `ui.components.relative_time.duration.${langKey[i]}`, + "count", + delta + ); + return localize(`ui.components.relative_time.${tense}`, "time", timeDesc); + } + + delta /= tests[i]; + } + + delta = Math.floor(delta); + const time = localize( + "ui.components.relative_time.duration.week", + "count", + delta + ); + return localize(`ui.components.relative_time.${tense}`, "time", time); +} diff --git a/src/common/datetime/seconds_to_duration.js b/src/common/datetime/seconds_to_duration.ts similarity index 71% rename from src/common/datetime/seconds_to_duration.js rename to src/common/datetime/seconds_to_duration.ts index a256c14632..4874137803 100644 --- a/src/common/datetime/seconds_to_duration.js +++ b/src/common/datetime/seconds_to_duration.ts @@ -1,6 +1,6 @@ -const leftPad = (number) => (number < 10 ? `0${number}` : number); +const leftPad = (num: number) => (num < 10 ? `0${num}` : num); -export default function secondsToDuration(d) { +export default function secondsToDuration(d: number) { const h = Math.floor(d / 3600); const m = Math.floor((d % 3600) / 60); const s = Math.floor((d % 3600) % 60); diff --git a/src/common/empty_image_base64.js b/src/common/empty_image_base64.ts similarity index 100% rename from src/common/empty_image_base64.js rename to src/common/empty_image_base64.ts diff --git a/src/common/entity/attribute_class_names.js b/src/common/entity/attribute_class_names.js deleted file mode 100644 index cde81825ac..0000000000 --- a/src/common/entity/attribute_class_names.js +++ /dev/null @@ -1,9 +0,0 @@ -export default function attributeClassNames(stateObj, attributes) { - if (!stateObj) return ""; - return attributes - .map(function(attribute) { - return attribute in stateObj.attributes ? "has-" + attribute : ""; - }) - .filter((attr) => attr !== "") - .join(" "); -} diff --git a/src/common/entity/attribute_class_names.ts b/src/common/entity/attribute_class_names.ts new file mode 100644 index 0000000000..28d06f53fa --- /dev/null +++ b/src/common/entity/attribute_class_names.ts @@ -0,0 +1,17 @@ +import { HassEntity } from "home-assistant-js-websocket"; + +export default function attributeClassNames( + stateObj: HassEntity, + attributes: string[] +): string { + if (!stateObj) { + return ""; + } + return attributes + .map( + (attribute) => + attribute in stateObj.attributes ? "has-" + attribute : "" + ) + .filter((attr) => attr !== "") + .join(" "); +} diff --git a/src/common/entity/binary_sensor_icon.js b/src/common/entity/binary_sensor_icon.ts similarity index 90% rename from src/common/entity/binary_sensor_icon.js rename to src/common/entity/binary_sensor_icon.ts index e617f10f6d..365aba566b 100644 --- a/src/common/entity/binary_sensor_icon.js +++ b/src/common/entity/binary_sensor_icon.ts @@ -1,7 +1,9 @@ +import { HassEntity } from "home-assistant-js-websocket"; + /** Return an icon representing a binary sensor state. */ -export default function binarySensorIcon(state) { - var activated = state.state && state.state === "off"; +export default function binarySensorIcon(state: HassEntity) { + const activated = state.state && state.state === "off"; switch (state.attributes.device_class) { case "battery": return activated ? "hass:battery" : "hass:battery-outline"; diff --git a/src/common/entity/can_toggle_domain.js b/src/common/entity/can_toggle_domain.ts similarity index 66% rename from src/common/entity/can_toggle_domain.js rename to src/common/entity/can_toggle_domain.ts index 6b284e5f17..f1a0bc47b3 100644 --- a/src/common/entity/can_toggle_domain.js +++ b/src/common/entity/can_toggle_domain.ts @@ -1,4 +1,6 @@ -export default function canToggleDomain(hass, domain) { +import { HomeAssistant } from "../../types"; + +export default function canToggleDomain(hass: HomeAssistant, domain: string) { const services = hass.services[domain]; if (!services) { return false; diff --git a/src/common/entity/can_toggle_state.js b/src/common/entity/can_toggle_state.ts similarity index 52% rename from src/common/entity/can_toggle_state.js rename to src/common/entity/can_toggle_state.ts index 8b7a1eaee0..71a1b5d6c8 100644 --- a/src/common/entity/can_toggle_state.js +++ b/src/common/entity/can_toggle_state.ts @@ -1,13 +1,19 @@ +import { HassEntity } from "home-assistant-js-websocket"; import canToggleDomain from "./can_toggle_domain"; import computeStateDomain from "./compute_state_domain"; +import { HomeAssistant } from "../../types"; -export default function canToggleState(hass, stateObj) { +export default function canToggleState( + hass: HomeAssistant, + stateObj: HassEntity +) { const domain = computeStateDomain(stateObj); if (domain === "group") { return stateObj.state === "on" || stateObj.state === "off"; } if (domain === "climate") { - return !!((stateObj.attributes || {}).supported_features & 4096); + // tslint:disable-next-line + return (stateObj.attributes.supported_features! & 4096) !== 0; } return canToggleDomain(hass, domain); diff --git a/src/common/entity/compute_domain.js b/src/common/entity/compute_domain.js deleted file mode 100644 index b9d6fecaf7..0000000000 --- a/src/common/entity/compute_domain.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function computeDomain(entityId) { - return entityId.substr(0, entityId.indexOf(".")); -} diff --git a/src/common/entity/compute_domain.ts b/src/common/entity/compute_domain.ts new file mode 100644 index 0000000000..47eeb9e890 --- /dev/null +++ b/src/common/entity/compute_domain.ts @@ -0,0 +1,3 @@ +export default function computeDomain(entityId: string): string { + return entityId.substr(0, entityId.indexOf(".")); +} diff --git a/src/common/entity/compute_object_id.js b/src/common/entity/compute_object_id.ts similarity index 58% rename from src/common/entity/compute_object_id.js rename to src/common/entity/compute_object_id.ts index 85888b5c79..865ab6254d 100644 --- a/src/common/entity/compute_object_id.js +++ b/src/common/entity/compute_object_id.ts @@ -1,4 +1,4 @@ /** Compute the object ID of a state. */ -export default function computeObjectId(entityId) { +export default function computeObjectId(entityId: string): string { return entityId.substr(entityId.indexOf(".") + 1); } diff --git a/src/common/entity/compute_state_display.js b/src/common/entity/compute_state_display.js deleted file mode 100644 index 56f5d28c48..0000000000 --- a/src/common/entity/compute_state_display.js +++ /dev/null @@ -1,84 +0,0 @@ -import computeStateDomain from "./compute_state_domain"; -import formatDateTime from "../datetime/format_date_time"; -import formatDate from "../datetime/format_date"; -import formatTime from "../datetime/format_time"; - -export default function computeStateDisplay(localize, stateObj, language) { - if (!stateObj._stateDisplay) { - const domain = computeStateDomain(stateObj); - if (domain === "binary_sensor") { - // Try device class translation, then default binary sensor translation - if (stateObj.attributes.device_class) { - stateObj._stateDisplay = localize( - `state.${domain}.${stateObj.attributes.device_class}.${ - stateObj.state - }` - ); - } - if (!stateObj._stateDisplay) { - stateObj._stateDisplay = localize( - `state.${domain}.default.${stateObj.state}` - ); - } - } else if ( - stateObj.attributes.unit_of_measurement && - !["unknown", "unavailable"].includes(stateObj.state) - ) { - stateObj._stateDisplay = - stateObj.state + " " + stateObj.attributes.unit_of_measurement; - } else if (domain === "input_datetime") { - let date; - if (!stateObj.attributes.has_time) { - date = new Date( - stateObj.attributes.year, - stateObj.attributes.month - 1, - stateObj.attributes.day - ); - stateObj._stateDisplay = formatDate(date, language); - } else if (!stateObj.attributes.has_date) { - const now = new Date(); - date = new Date( - // Due to bugs.chromium.org/p/chromium/issues/detail?id=797548 - // don't use artificial 1970 year. - now.getFullYear(), - now.getMonth(), - now.getDay(), - stateObj.attributes.hour, - stateObj.attributes.minute - ); - stateObj._stateDisplay = formatTime(date, language); - } else { - date = new Date( - stateObj.attributes.year, - stateObj.attributes.month - 1, - stateObj.attributes.day, - stateObj.attributes.hour, - stateObj.attributes.minute - ); - stateObj._stateDisplay = formatDateTime(date, language); - } - } else if (domain === "zwave") { - if (["initializing", "dead"].includes(stateObj.state)) { - stateObj._stateDisplay = localize( - `state.zwave.query_stage.${stateObj.state}`, - "query_stage", - stateObj.attributes.query_stage - ); - } else { - stateObj._stateDisplay = localize( - `state.zwave.default.${stateObj.state}` - ); - } - } else { - stateObj._stateDisplay = localize(`state.${domain}.${stateObj.state}`); - } - // Fall back to default, component backend translation, or raw state if nothing else matches. - stateObj._stateDisplay = - stateObj._stateDisplay || - localize(`state.default.${stateObj.state}`) || - localize(`component.${domain}.state.${stateObj.state}`) || - stateObj.state; - } - - return stateObj._stateDisplay; -} diff --git a/src/common/entity/compute_state_display.ts b/src/common/entity/compute_state_display.ts new file mode 100644 index 0000000000..83fb1f5578 --- /dev/null +++ b/src/common/entity/compute_state_display.ts @@ -0,0 +1,91 @@ +import { HassEntity } from "home-assistant-js-websocket"; +import computeStateDomain from "./compute_state_domain"; +import formatDateTime from "../datetime/format_date_time"; +import formatDate from "../datetime/format_date"; +import formatTime from "../datetime/format_time"; +import { LocalizeFunc } from "../../mixins/localize-base-mixin"; + +type CachedDisplayEntity = HassEntity & { + _stateDisplay?: string; +}; + +export default function computeStateDisplay( + localize: LocalizeFunc, + stateObj: HassEntity, + language: string +) { + const state = stateObj as CachedDisplayEntity; + if (!state._stateDisplay) { + const domain = computeStateDomain(state); + if (domain === "binary_sensor") { + // Try device class translation, then default binary sensor translation + if (state.attributes.device_class) { + state._stateDisplay = localize( + `state.${domain}.${state.attributes.device_class}.${state.state}` + ); + } + if (!state._stateDisplay) { + state._stateDisplay = localize( + `state.${domain}.default.${state.state}` + ); + } + } else if ( + state.attributes.unit_of_measurement && + !["unknown", "unavailable"].includes(state.state) + ) { + state._stateDisplay = + state.state + " " + state.attributes.unit_of_measurement; + } else if (domain === "input_datetime") { + let date; + if (!state.attributes.has_time) { + date = new Date( + state.attributes.year, + state.attributes.month - 1, + state.attributes.day + ); + state._stateDisplay = formatDate(date, language); + } else if (!state.attributes.has_date) { + const now = new Date(); + date = new Date( + // Due to bugs.chromium.org/p/chromium/issues/detail?id=797548 + // don't use artificial 1970 year. + now.getFullYear(), + now.getMonth(), + now.getDay(), + state.attributes.hour, + state.attributes.minute + ); + state._stateDisplay = formatTime(date, language); + } else { + date = new Date( + state.attributes.year, + state.attributes.month - 1, + state.attributes.day, + state.attributes.hour, + state.attributes.minute + ); + state._stateDisplay = formatDateTime(date, language); + } + } else if (domain === "zwave") { + if (["initializing", "dead"].includes(state.state)) { + state._stateDisplay = localize( + `state.zwave.query_stage.${state.state}`, + "query_stage", + state.attributes.query_stage + ); + } else { + state._stateDisplay = localize(`state.zwave.default.${state.state}`); + } + } else { + state._stateDisplay = localize(`state.${domain}.${state.state}`); + } + // Fall back to default, component backend translation, or raw state if nothing else matches. + state._stateDisplay = + state._stateDisplay || + localize(`state.default.${state.state}`) || + localize(`component.${domain}.state.${state.state}`) || + state.state; + } + + return state._stateDisplay; +} diff --git a/src/common/entity/compute_state_domain.js b/src/common/entity/compute_state_domain.js deleted file mode 100644 index 492b700eaa..0000000000 --- a/src/common/entity/compute_state_domain.js +++ /dev/null @@ -1,5 +0,0 @@ -import computeDomain from "./compute_domain"; - -export default function computeStateDomain(stateObj) { - return computeDomain(stateObj.entity_id); -} diff --git a/src/common/entity/compute_state_domain.ts b/src/common/entity/compute_state_domain.ts new file mode 100644 index 0000000000..1ef02f4e8f --- /dev/null +++ b/src/common/entity/compute_state_domain.ts @@ -0,0 +1,6 @@ +import { HassEntity } from "home-assistant-js-websocket"; +import computeDomain from "./compute_domain"; + +export default function computeStateDomain(stateObj: HassEntity) { + return computeDomain(stateObj.entity_id); +} diff --git a/src/common/entity/compute_state_name.js b/src/common/entity/compute_state_name.js deleted file mode 100644 index 0aa20d7ccf..0000000000 --- a/src/common/entity/compute_state_name.js +++ /dev/null @@ -1,11 +0,0 @@ -import computeObjectId from "./compute_object_id"; - -export default function computeStateName(stateObj) { - if (stateObj._entityDisplay === undefined) { - stateObj._entityDisplay = - stateObj.attributes.friendly_name || - computeObjectId(stateObj.entity_id).replace(/_/g, " "); - } - - return stateObj._entityDisplay; -} diff --git a/src/common/entity/compute_state_name.ts b/src/common/entity/compute_state_name.ts new file mode 100644 index 0000000000..c20bde78b7 --- /dev/null +++ b/src/common/entity/compute_state_name.ts @@ -0,0 +1,18 @@ +import { HassEntity } from "home-assistant-js-websocket"; +import computeObjectId from "./compute_object_id"; + +type CachedDisplayEntity = HassEntity & { + _entityDisplay?: string; +}; + +export default function computeStateName(stateObj: HassEntity) { + const state = stateObj as CachedDisplayEntity; + + if (state._entityDisplay === undefined) { + state._entityDisplay = + state.attributes.friendly_name || + computeObjectId(state.entity_id).replace(/_/g, " "); + } + + return state._entityDisplay; +} diff --git a/src/common/entity/cover_icon.js b/src/common/entity/cover_icon.ts similarity index 62% rename from src/common/entity/cover_icon.js rename to src/common/entity/cover_icon.ts index 78876025b4..88fe03f774 100644 --- a/src/common/entity/cover_icon.js +++ b/src/common/entity/cover_icon.ts @@ -1,8 +1,9 @@ /** Return an icon representing a cover state. */ +import { HassEntity } from "home-assistant-js-websocket"; import domainIcon from "./domain_icon"; -export default function coverIcon(state) { - var open = state.state && state.state !== "closed"; +export default function coverIcon(state: HassEntity): string { + const open = state.state !== "closed"; switch (state.attributes.device_class) { case "garage": return open ? "hass:garage-open" : "hass:garage"; diff --git a/src/common/entity/domain_icon.js b/src/common/entity/domain_icon.ts similarity index 95% rename from src/common/entity/domain_icon.js rename to src/common/entity/domain_icon.ts index a50fcb943e..5c6ac2a181 100644 --- a/src/common/entity/domain_icon.js +++ b/src/common/entity/domain_icon.ts @@ -44,7 +44,7 @@ const fixedIcons = { weblink: "hass:open-in-new", }; -export default function domainIcon(domain, state) { +export default function domainIcon(domain: string, state?: string): string { if (domain in fixedIcons) { return fixedIcons[domain]; } @@ -93,11 +93,10 @@ export default function domainIcon(domain, state) { } default: - /* eslint-disable no-console */ + // tslint:disable-next-line console.warn( "Unable to find icon for domain " + domain + " (" + state + ")" ); - /* eslint-enable no-console */ return DEFAULT_DOMAIN_ICON; } } diff --git a/src/common/entity/extract_views.js b/src/common/entity/extract_views.ts similarity index 74% rename from src/common/entity/extract_views.js rename to src/common/entity/extract_views.ts index c3b7949911..bcc7084646 100644 --- a/src/common/entity/extract_views.js +++ b/src/common/entity/extract_views.ts @@ -1,8 +1,9 @@ +import { HassEntities, HassEntity } from "home-assistant-js-websocket"; import { DEFAULT_VIEW_ENTITY_ID } from "../const"; // Return an ordered array of available views -export default function extractViews(entities) { - const views = []; +export default function extractViews(entities: HassEntities): HassEntity[] { + const views: HassEntity[] = []; Object.keys(entities).forEach((entityId) => { const entity = entities[entityId]; diff --git a/src/common/entity/feature_class_names.js b/src/common/entity/feature_class_names.js deleted file mode 100644 index 93766e549b..0000000000 --- a/src/common/entity/feature_class_names.js +++ /dev/null @@ -1,11 +0,0 @@ -// Expects classNames to be an object mapping feature-bit -> className -export default function featureClassNames(stateObj, classNames) { - if (!stateObj || !stateObj.attributes.supported_features) return ""; - - const features = stateObj.attributes.supported_features; - - return Object.keys(classNames) - .map((feature) => ((features & feature) !== 0 ? classNames[feature] : "")) - .filter((attr) => attr !== "") - .join(" "); -} diff --git a/src/common/entity/feature_class_names.ts b/src/common/entity/feature_class_names.ts new file mode 100644 index 0000000000..4cafc68b86 --- /dev/null +++ b/src/common/entity/feature_class_names.ts @@ -0,0 +1,22 @@ +import { HassEntity } from "home-assistant-js-websocket"; + +// Expects classNames to be an object mapping feature-bit -> className +export default function featureClassNames( + stateObj: HassEntity, + classNames: { [feature: number]: string } +) { + if (!stateObj || !stateObj.attributes.supported_features) { + return ""; + } + + const features = stateObj.attributes.supported_features; + + return Object.keys(classNames) + .map( + (feature) => + // tslint:disable-next-line + (features & Number(feature)) !== 0 ? classNames[feature] : "" + ) + .filter((attr) => attr !== "") + .join(" "); +} diff --git a/src/common/entity/get_group_entities.js b/src/common/entity/get_group_entities.ts similarity index 51% rename from src/common/entity/get_group_entities.js rename to src/common/entity/get_group_entities.ts index 5e034a9df8..b77353e0c1 100644 --- a/src/common/entity/get_group_entities.js +++ b/src/common/entity/get_group_entities.ts @@ -1,4 +1,10 @@ -export default function getGroupEntities(entities, group) { +import { HassEntities } from "home-assistant-js-websocket"; +import { GroupEntity } from "../../types"; + +export default function getGroupEntities( + entities: HassEntities, + group: GroupEntity +) { const result = {}; group.attributes.entity_id.forEach((entityId) => { diff --git a/src/common/entity/get_view_entities.js b/src/common/entity/get_view_entities.ts similarity index 73% rename from src/common/entity/get_view_entities.js rename to src/common/entity/get_view_entities.ts index 00b21ee30e..62aa7e5d89 100644 --- a/src/common/entity/get_view_entities.js +++ b/src/common/entity/get_view_entities.ts @@ -1,9 +1,14 @@ +import { HassEntities } from "home-assistant-js-websocket"; import computeDomain from "./compute_domain"; import getGroupEntities from "./get_group_entities"; +import { GroupEntity } from "../../types"; // Return an object containing all entities that the view will show // including embedded groups. -export default function getViewEntities(entities, view) { +export default function getViewEntities( + entities: HassEntities, + view: GroupEntity +) { const viewEntities = {}; view.attributes.entity_id.forEach((entityId) => { @@ -13,7 +18,7 @@ export default function getViewEntities(entities, view) { viewEntities[entity.entity_id] = entity; if (computeDomain(entity.entity_id) === "group") { - const groupEntities = getGroupEntities(entities, entity); + const groupEntities = getGroupEntities(entities, entity as GroupEntity); Object.keys(groupEntities).forEach((grEntityId) => { const grEntity = groupEntities[grEntityId]; diff --git a/src/common/entity/has_location.js b/src/common/entity/has_location.js deleted file mode 100644 index 5cbcd3a801..0000000000 --- a/src/common/entity/has_location.js +++ /dev/null @@ -1,5 +0,0 @@ -export default function hasLocation(stateObj) { - return ( - "latitude" in stateObj.attributes && "longitude" in stateObj.attributes - ); -} diff --git a/src/common/entity/has_location.ts b/src/common/entity/has_location.ts new file mode 100644 index 0000000000..5c290887bf --- /dev/null +++ b/src/common/entity/has_location.ts @@ -0,0 +1,7 @@ +import { HassEntity } from "home-assistant-js-websocket"; + +export default function hasLocation(stateObj: HassEntity) { + return ( + "latitude" in stateObj.attributes && "longitude" in stateObj.attributes + ); +} diff --git a/src/common/entity/input_dateteime_icon.js b/src/common/entity/input_dateteime_icon.ts similarity index 68% rename from src/common/entity/input_dateteime_icon.js rename to src/common/entity/input_dateteime_icon.ts index 8418226e90..016b19cc48 100644 --- a/src/common/entity/input_dateteime_icon.js +++ b/src/common/entity/input_dateteime_icon.ts @@ -1,7 +1,8 @@ /** Return an icon representing an input datetime state. */ import domainIcon from "./domain_icon"; +import { HassEntity } from "home-assistant-js-websocket"; -export default function inputDateTimeIcon(state) { +export default function inputDateTimeIcon(state: HassEntity): string { if (!state.attributes.has_date) { return "hass:clock"; } diff --git a/src/common/entity/sensor_icon.js b/src/common/entity/sensor_icon.ts similarity index 80% rename from src/common/entity/sensor_icon.js rename to src/common/entity/sensor_icon.ts index 44e6f3ce09..d08f7c6e97 100644 --- a/src/common/entity/sensor_icon.js +++ b/src/common/entity/sensor_icon.ts @@ -1,4 +1,5 @@ /** Return an icon representing a sensor state. */ +import { HassEntity } from "home-assistant-js-websocket"; import { UNIT_C, UNIT_F } from "../const"; import domainIcon from "./domain_icon"; @@ -9,17 +10,18 @@ const fixedDeviceClassIcons = { pressure: "hass:gauge", }; -export default function sensorIcon(state) { +export default function sensorIcon(state: HassEntity) { const dclass = state.attributes.device_class; - if (dclass in fixedDeviceClassIcons) { + if (dclass && dclass in fixedDeviceClassIcons) { return fixedDeviceClassIcons[dclass]; } if (dclass === "battery") { - if (isNaN(state.state)) { + const battery = Number(state.state); + if (isNaN(battery)) { return "hass:battery-unknown"; } - const batteryRound = Math.round(state.state / 10) * 10; + const batteryRound = Math.round(battery / 10) * 10; if (batteryRound >= 100) { return "hass:battery"; } diff --git a/src/common/entity/split_by_groups.js b/src/common/entity/split_by_groups.ts similarity index 72% rename from src/common/entity/split_by_groups.js rename to src/common/entity/split_by_groups.ts index e0631dfdda..a894472d8c 100644 --- a/src/common/entity/split_by_groups.js +++ b/src/common/entity/split_by_groups.ts @@ -1,11 +1,12 @@ import computeDomain from "./compute_domain"; +import { HassEntity, HassEntities } from "home-assistant-js-websocket"; // Split a collection into a list of groups and a 'rest' list of ungrouped // entities. // Returns { groups: [], ungrouped: {} } -export default function splitByGroups(entities) { - const groups = []; - const ungrouped = {}; +export default function splitByGroups(entities: HassEntities) { + const groups: HassEntity[] = []; + const ungrouped: HassEntities = {}; Object.keys(entities).forEach((entityId) => { const entity = entities[entityId]; diff --git a/src/common/entity/state_card_type.js b/src/common/entity/state_card_type.ts similarity index 71% rename from src/common/entity/state_card_type.js rename to src/common/entity/state_card_type.ts index 170ca9cb8b..00f6b73b6a 100644 --- a/src/common/entity/state_card_type.js +++ b/src/common/entity/state_card_type.ts @@ -1,8 +1,13 @@ +import { HassEntity } from "home-assistant-js-websocket"; import canToggleState from "./can_toggle_state"; import computeStateDomain from "./compute_state_domain"; import { DOMAINS_WITH_CARD } from "../const"; +import { HomeAssistant } from "../../types"; -export default function stateCardType(hass, stateObj) { +export default function stateCardType( + hass: HomeAssistant, + stateObj: HassEntity +) { if (stateObj.state === "unavailable") { return "display"; } diff --git a/src/common/entity/state_icon.js b/src/common/entity/state_icon.ts similarity index 87% rename from src/common/entity/state_icon.js rename to src/common/entity/state_icon.ts index 928d7bc186..351db86d12 100644 --- a/src/common/entity/state_icon.js +++ b/src/common/entity/state_icon.ts @@ -1,4 +1,5 @@ /** Return an icon representing a state. */ +import { HassEntity } from "home-assistant-js-websocket"; import { DEFAULT_DOMAIN_ICON } from "../const"; import computeDomain from "./compute_domain"; @@ -16,7 +17,7 @@ const domainIcons = { input_datetime: inputDateTimeIcon, }; -export default function stateIcon(state) { +export default function stateIcon(state: HassEntity) { if (!state) { return DEFAULT_DOMAIN_ICON; } diff --git a/src/common/entity/state_more_info_type.js b/src/common/entity/state_more_info_type.ts similarity index 73% rename from src/common/entity/state_more_info_type.js rename to src/common/entity/state_more_info_type.ts index a35ad61f35..dbdac2e198 100644 --- a/src/common/entity/state_more_info_type.js +++ b/src/common/entity/state_more_info_type.ts @@ -1,7 +1,8 @@ +import { HassEntity } from "home-assistant-js-websocket"; import computeStateDomain from "./compute_state_domain"; import { DOMAINS_HIDE_MORE_INFO, DOMAINS_WITH_MORE_INFO } from "../const"; -export default function stateMoreInfoType(stateObj) { +export default function stateMoreInfoType(stateObj: HassEntity) { const domain = computeStateDomain(stateObj); if (DOMAINS_WITH_MORE_INFO.includes(domain)) { diff --git a/src/common/entity/states_sort_by_name.js b/src/common/entity/states_sort_by_name.ts similarity index 71% rename from src/common/entity/states_sort_by_name.js rename to src/common/entity/states_sort_by_name.ts index f4b67fe2b4..e7afcd0559 100644 --- a/src/common/entity/states_sort_by_name.js +++ b/src/common/entity/states_sort_by_name.ts @@ -5,9 +5,13 @@ * const states = [state1, state2] * states.sort(statesSortByName); */ +import { HassEntity } from "home-assistant-js-websocket"; import computeStateName from "./compute_state_name"; -export default function sortStatesByName(entityA, entityB) { +export default function sortStatesByName( + entityA: HassEntity, + entityB: HassEntity +) { const nameA = computeStateName(entityA); const nameB = computeStateName(entityB); if (nameA < nameB) { diff --git a/src/common/entity/timer_time_remaining.js b/src/common/entity/timer_time_remaining.ts similarity index 55% rename from src/common/entity/timer_time_remaining.js rename to src/common/entity/timer_time_remaining.ts index 100c55a88c..05e19a46bc 100644 --- a/src/common/entity/timer_time_remaining.js +++ b/src/common/entity/timer_time_remaining.ts @@ -1,11 +1,12 @@ +import { HassEntity } from "home-assistant-js-websocket"; import durationToSeconds from "../datetime/duration_to_seconds"; -export default function timerTimeRemaining(stateObj) { +export default function timerTimeRemaining(stateObj: HassEntity) { let timeRemaining = durationToSeconds(stateObj.attributes.remaining); if (stateObj.state === "active") { - const now = new Date(); - const madeActive = new Date(stateObj.last_changed); + const now = new Date().getTime(); + const madeActive = new Date(stateObj.last_changed).getTime(); timeRemaining = Math.max(timeRemaining - (now - madeActive) / 1000, 0); } diff --git a/src/common/entity/valid_entity_id.js b/src/common/entity/valid_entity_id.js deleted file mode 100644 index 5a4ea9e23a..0000000000 --- a/src/common/entity/valid_entity_id.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function validEntityId(entityId) { - return /^(\w+)\.(\w+)$/.test(entityId); -} diff --git a/src/common/entity/valid_entity_id.ts b/src/common/entity/valid_entity_id.ts new file mode 100644 index 0000000000..29d345c633 --- /dev/null +++ b/src/common/entity/valid_entity_id.ts @@ -0,0 +1,2 @@ +const validEntityId = /^(\w+)\.(\w+)$/; +export default validEntityId.test; diff --git a/src/common/util/parse-aspect-ratio.js b/src/common/util/parse-aspect-ratio.ts similarity index 76% rename from src/common/util/parse-aspect-ratio.js rename to src/common/util/parse-aspect-ratio.ts index 1797e81e3a..cd80d4b90d 100644 --- a/src/common/util/parse-aspect-ratio.js +++ b/src/common/util/parse-aspect-ratio.ts @@ -1,9 +1,11 @@ export default function parseAspectRatio(input) { // Handle 16x9, 16:9, 1.78x1, 1.78:1, 1.78 // Ignore everything else - function parseOrThrow(number) { - const parsed = parseFloat(number); - if (isNaN(parsed)) throw new Error(`${number} is not a number`); + function parseOrThrow(num) { + const parsed = parseFloat(num); + if (isNaN(parsed)) { + throw new Error(`${num} is not a number`); + } return parsed; } try { diff --git a/src/panels/lovelace/cards/hui-glance-card.ts b/src/panels/lovelace/cards/hui-glance-card.ts index 0bda6acae7..261ad84dfa 100644 --- a/src/panels/lovelace/cards/hui-glance-card.ts +++ b/src/panels/lovelace/cards/hui-glance-card.ts @@ -211,7 +211,11 @@ export class HuiGlanceCard extends hassLocalizeLitMixin(LitElement) > ${ this._config!.show_state !== false - ? html`
${computeStateDisplay(this.localize, stateObj)}
` + ? html`
${computeStateDisplay( + this.localize, + stateObj, + this.hass!.language + )}
` : "" } diff --git a/src/panels/lovelace/elements/hui-state-label-element.ts b/src/panels/lovelace/elements/hui-state-label-element.ts index 20b8c3287d..5d838ecf9d 100644 --- a/src/panels/lovelace/elements/hui-state-label-element.ts +++ b/src/panels/lovelace/elements/hui-state-label-element.ts @@ -48,7 +48,9 @@ class HuiStateLabelElement extends hassLocalizeLitMixin(LitElement) .longPress="${longPress()}" > ${this._config.prefix}${ - state ? computeStateDisplay(this.localize, state) : "-" + state + ? computeStateDisplay(this.localize, state, this.hass!.language) + : "-" }${this._config.suffix} `; diff --git a/src/types.ts b/src/types.ts index 281eb63a6d..3dacd9f349 100644 --- a/src/types.ts +++ b/src/types.ts @@ -6,6 +6,7 @@ import { MessageBase, HassEntityBase, HassEntityAttributeBase, + HassServices, } from "home-assistant-js-websocket"; declare global { @@ -75,6 +76,7 @@ export interface HomeAssistant { connection: Connection; connected: boolean; states: HassEntities; + services: HassServices; config: HassConfig; themes: Themes; panels: Panels; @@ -141,3 +143,13 @@ export type LightEntity = HassEntityBase & { hs_color: number[]; }; }; + +export type GroupEntity = HassEntityBase & { + attributes: HassEntityAttributeBase & { + entity_id: string[]; + order: number; + auto?: boolean; + view?: boolean; + control?: "hidden"; + }; +}; diff --git a/test-mocha/common/datetime/duration_to_seconds_test.js b/test-mocha/common/datetime/duration_to_seconds_test.ts similarity index 100% rename from test-mocha/common/datetime/duration_to_seconds_test.js rename to test-mocha/common/datetime/duration_to_seconds_test.ts diff --git a/test-mocha/common/datetime/format_date.js b/test-mocha/common/datetime/format_date.ts similarity index 100% rename from test-mocha/common/datetime/format_date.js rename to test-mocha/common/datetime/format_date.ts diff --git a/test-mocha/common/datetime/format_date_time.js b/test-mocha/common/datetime/format_date_time.ts similarity index 100% rename from test-mocha/common/datetime/format_date_time.js rename to test-mocha/common/datetime/format_date_time.ts diff --git a/test-mocha/common/datetime/format_time.js b/test-mocha/common/datetime/format_time.ts similarity index 100% rename from test-mocha/common/datetime/format_time.js rename to test-mocha/common/datetime/format_time.ts diff --git a/test-mocha/common/datetime/seconds_to_duration_test.js b/test-mocha/common/datetime/seconds_to_duration_test.ts similarity index 100% rename from test-mocha/common/datetime/seconds_to_duration_test.js rename to test-mocha/common/datetime/seconds_to_duration_test.ts diff --git a/test-mocha/common/entity/attribute_class_names_test.js b/test-mocha/common/entity/attribute_class_names_test.ts similarity index 89% rename from test-mocha/common/entity/attribute_class_names_test.js rename to test-mocha/common/entity/attribute_class_names_test.ts index 1a5b29f327..b6a904b00a 100644 --- a/test-mocha/common/entity/attribute_class_names_test.js +++ b/test-mocha/common/entity/attribute_class_names_test.ts @@ -6,12 +6,12 @@ describe("attributeClassNames", () => { const attrs = ["mock_attr1", "mock_attr2"]; it("Skips null states", () => { - const stateObj = null; + const stateObj: any = null; assert.strictEqual(attributeClassNames(stateObj, attrs), ""); }); it("Matches no attrbutes", () => { - const stateObj = { + const stateObj: any = { attributes: { other_attr_1: 1, other_attr_2: 2, @@ -21,7 +21,7 @@ describe("attributeClassNames", () => { }); it("Matches one attrbute", () => { - const stateObj = { + const stateObj: any = { attributes: { other_attr_1: 1, other_attr_2: 2, @@ -32,7 +32,7 @@ describe("attributeClassNames", () => { }); it("Matches two attrbutes", () => { - const stateObj = { + const stateObj: any = { attributes: { other_attr_1: 1, other_attr_2: 2, diff --git a/test-mocha/common/entity/can_toggle_domain_test.js b/test-mocha/common/entity/can_toggle_domain_test.ts similarity index 97% rename from test-mocha/common/entity/can_toggle_domain_test.js rename to test-mocha/common/entity/can_toggle_domain_test.ts index 9416e885c2..a3d3d36b30 100644 --- a/test-mocha/common/entity/can_toggle_domain_test.js +++ b/test-mocha/common/entity/can_toggle_domain_test.ts @@ -3,7 +3,7 @@ import { assert } from "chai"; import canToggleDomain from "../../../src/common/entity/can_toggle_domain"; describe("canToggleDomain", () => { - const hass = { + const hass: any = { services: { light: { turn_on: null, // Service keys only need to be present for test diff --git a/test-mocha/common/entity/can_toggle_state_test.js b/test-mocha/common/entity/can_toggle_state_test.ts similarity index 83% rename from test-mocha/common/entity/can_toggle_state_test.js rename to test-mocha/common/entity/can_toggle_state_test.ts index 2a1c706031..b0239dd376 100644 --- a/test-mocha/common/entity/can_toggle_state_test.js +++ b/test-mocha/common/entity/can_toggle_state_test.ts @@ -3,7 +3,7 @@ import { assert } from "chai"; import canToggleState from "../../../src/common/entity/can_toggle_state"; describe("canToggleState", () => { - const hass = { + const hass: any = { services: { light: { turn_on: null, // Service keys only need to be present for test @@ -13,7 +13,7 @@ describe("canToggleState", () => { }; it("Detects lights toggle", () => { - const stateObj = { + const stateObj: any = { entity_id: "light.bla", state: "on", }; @@ -21,7 +21,7 @@ describe("canToggleState", () => { }); it("Detects group with toggle", () => { - const stateObj = { + const stateObj: any = { entity_id: "group.bla", state: "on", }; @@ -29,7 +29,7 @@ describe("canToggleState", () => { }); it("Detects group without toggle", () => { - const stateObj = { + const stateObj: any = { entity_id: "group.devices", state: "home", }; @@ -37,7 +37,7 @@ describe("canToggleState", () => { }); it("Detects climate with toggle", () => { - const stateObj = { + const stateObj: any = { entity_id: "climate.bla", attributes: { supported_features: 4096, @@ -47,8 +47,11 @@ describe("canToggleState", () => { }); it("Detects climate without toggle", () => { - const stateObj = { + const stateObj: any = { entity_id: "climate.bla", + attributes: { + supported_features: 0, + }, }; assert.isFalse(canToggleState(hass, stateObj)); }); diff --git a/test-mocha/common/entity/compute_domain.js b/test-mocha/common/entity/compute_domain.ts similarity index 100% rename from test-mocha/common/entity/compute_domain.js rename to test-mocha/common/entity/compute_domain.ts diff --git a/test-mocha/common/entity/compute_state_display.js b/test-mocha/common/entity/compute_state_display.ts similarity index 82% rename from test-mocha/common/entity/compute_state_display.js rename to test-mocha/common/entity/compute_state_display.ts index d599d0fc74..3d0da10b56 100644 --- a/test-mocha/common/entity/compute_state_display.js +++ b/test-mocha/common/entity/compute_state_display.ts @@ -3,13 +3,12 @@ import { assert } from "chai"; import computeStateDisplay from "../../../src/common/entity/compute_state_display"; describe("computeStateDisplay", () => { - const localize = function(message, ...args) { - // Mock Localize function for testing - return message + (args.length ? ": " + args.join(",") : ""); - }; + // Mock Localize function for testing + const localize = (message, ...args) => + message + (args.length ? ": " + args.join(",") : ""); it("Localizes binary sensor defaults", () => { - const stateObj = { + const stateObj: any = { entity_id: "binary_sensor.test", state: "off", attributes: {}, @@ -21,7 +20,7 @@ describe("computeStateDisplay", () => { }); it("Localizes binary sensor device class", () => { - const stateObj = { + const stateObj: any = { entity_id: "binary_sensor.test", state: "off", attributes: { @@ -35,12 +34,13 @@ describe("computeStateDisplay", () => { }); it("Localizes binary sensor invalid device class", () => { - const altLocalize = function(message, ...args) { - if (message === "state.binary_sensor.invalid_device_class.off") - return null; + const altLocalize = (message, ...args) => { + if (message === "state.binary_sensor.invalid_device_class.off") { + return ""; + } return localize(message, ...args); }; - const stateObj = { + const stateObj: any = { entity_id: "binary_sensor.test", state: "off", attributes: { @@ -54,7 +54,7 @@ describe("computeStateDisplay", () => { }); it("Localizes sensor value with units", () => { - const stateObj = { + const stateObj: any = { entity_id: "sensor.test", state: "123", attributes: { @@ -65,11 +65,13 @@ describe("computeStateDisplay", () => { }); it("Localizes unknown sensor value with units", () => { - const altLocalize = function(message, ...args) { - if (message === "state.sensor.unknown") return null; + const altLocalize = (message, ...args) => { + if (message === "state.sensor.unknown") { + return ""; + } return localize(message, ...args); }; - const stateObj = { + const stateObj: any = { entity_id: "sensor.test", state: "unknown", attributes: { @@ -83,11 +85,13 @@ describe("computeStateDisplay", () => { }); it("Localizes unavailable sensor value with units", () => { - const altLocalize = function(message, ...args) { - if (message === "state.sensor.unavailable") return null; + const altLocalize = (message, ...args) => { + if (message === "state.sensor.unavailable") { + return ""; + } return localize(message, ...args); }; - const stateObj = { + const stateObj: any = { entity_id: "sensor.test", state: "unavailable", attributes: { @@ -101,11 +105,13 @@ describe("computeStateDisplay", () => { }); it("Localizes sensor value with component translation", () => { - const altLocalize = function(message, ...args) { - if (message !== "component.sensor.state.custom_state") return null; + const altLocalize = (message, ...args) => { + if (message !== "component.sensor.state.custom_state") { + return ""; + } return localize(message, ...args); }; - const stateObj = { + const stateObj: any = { entity_id: "sensor.test", state: "custom_state", attributes: {}, @@ -117,7 +123,7 @@ describe("computeStateDisplay", () => { }); it("Localizes input_datetime with full date time", () => { - const stateObj = { + const stateObj: any = { entity_id: "input_datetime.test", state: "123", attributes: { @@ -138,7 +144,7 @@ describe("computeStateDisplay", () => { }); it("Localizes input_datetime with date", () => { - const stateObj = { + const stateObj: any = { entity_id: "input_datetime.test", state: "123", attributes: { @@ -159,7 +165,7 @@ describe("computeStateDisplay", () => { }); it("Localizes input_datetime with time", () => { - const stateObj = { + const stateObj: any = { entity_id: "input_datetime.test", state: "123", attributes: { @@ -180,7 +186,7 @@ describe("computeStateDisplay", () => { }); it("Localizes zwave ready", () => { - const stateObj = { + const stateObj: any = { entity_id: "zwave.test", state: "ready", attributes: { @@ -194,7 +200,7 @@ describe("computeStateDisplay", () => { }); it("Localizes zwave initializing", () => { - const stateObj = { + const stateObj: any = { entity_id: "zwave.test", state: "initializing", attributes: { @@ -208,7 +214,7 @@ describe("computeStateDisplay", () => { }); it("Localizes cover open", () => { - const stateObj = { + const stateObj: any = { entity_id: "cover.test", state: "open", attributes: {}, @@ -220,11 +226,13 @@ describe("computeStateDisplay", () => { }); it("Localizes unavailable", () => { - const altLocalize = function(message, ...args) { - if (message === "state.sensor.unavailable") return null; + const altLocalize = (message, ...args) => { + if (message === "state.sensor.unavailable") { + return ""; + } return localize(message, ...args); }; - const stateObj = { + const stateObj: any = { entity_id: "sensor.test", state: "unavailable", attributes: {}, @@ -236,11 +244,11 @@ describe("computeStateDisplay", () => { }); it("Localizes custom state", () => { - const altLocalize = function() { + const altLocalize = () => { // No matches can be found - return null; + return ""; }; - const stateObj = { + const stateObj: any = { entity_id: "sensor.test", state: "My Custom State", attributes: {}, @@ -252,7 +260,7 @@ describe("computeStateDisplay", () => { }); it("Only calculates state display once per immutable state object", () => { - const stateObj = { + const stateObj: any = { entity_id: "cover.test", state: "open", attributes: {}, diff --git a/test-mocha/common/entity/compute_state_domain.js b/test-mocha/common/entity/compute_state_domain.ts similarity index 91% rename from test-mocha/common/entity/compute_state_domain.js rename to test-mocha/common/entity/compute_state_domain.ts index f65cb2bac7..803737fa5a 100644 --- a/test-mocha/common/entity/compute_state_domain.js +++ b/test-mocha/common/entity/compute_state_domain.ts @@ -4,7 +4,7 @@ import computeStateDomain from "../../../src/common/entity/compute_state_domain" describe("computeStateDomain", () => { it("Detects sensor domain", () => { - const stateObj = { + const stateObj: any = { entity_id: "sensor.test", }; assert.strictEqual(computeStateDomain(stateObj), "sensor"); diff --git a/test-mocha/common/entity/extract_views.spec.js b/test-mocha/common/entity/extract_views.spec.ts similarity index 95% rename from test-mocha/common/entity/extract_views.spec.js rename to test-mocha/common/entity/extract_views.spec.ts index 2feb8879ea..9528f21a9a 100644 --- a/test-mocha/common/entity/extract_views.spec.js +++ b/test-mocha/common/entity/extract_views.spec.ts @@ -1,4 +1,4 @@ -import assert from "assert"; +import * as assert from "assert"; import extractViews from "../../../src/common/entity/extract_views"; diff --git a/test-mocha/common/entity/feature_class_names_test.js b/test-mocha/common/entity/feature_class_names_test.ts similarity index 74% rename from test-mocha/common/entity/feature_class_names_test.js rename to test-mocha/common/entity/feature_class_names_test.ts index 005359e2eb..544d95a1e6 100644 --- a/test-mocha/common/entity/feature_class_names_test.js +++ b/test-mocha/common/entity/feature_class_names_test.ts @@ -1,6 +1,7 @@ import { assert } from "chai"; import featureClassNames from "../../../src/common/entity/feature_class_names"; +import { HassEntity } from "home-assistant-js-websocket"; describe("featureClassNames", () => { const classNames = { @@ -12,11 +13,12 @@ describe("featureClassNames", () => { it("Skips null states", () => { const stateObj = null; - assert.strictEqual(featureClassNames(stateObj, classNames), ""); + assert.strictEqual(featureClassNames(stateObj!, classNames), ""); }); it("Matches no features", () => { - const stateObj = { + // tslint:disable-next-line + const stateObj = { attributes: { supported_features: 64, }, @@ -25,7 +27,8 @@ describe("featureClassNames", () => { }); it("Matches one feature", () => { - const stateObj = { + // tslint:disable-next-line + const stateObj = { attributes: { supported_features: 72, }, @@ -37,7 +40,8 @@ describe("featureClassNames", () => { }); it("Matches two features", () => { - const stateObj = { + // tslint:disable-next-line + const stateObj = { attributes: { supported_features: 73, }, diff --git a/test-mocha/common/entity/get_group_entities.spec.js b/test-mocha/common/entity/get_group_entities.spec.ts similarity index 96% rename from test-mocha/common/entity/get_group_entities.spec.js rename to test-mocha/common/entity/get_group_entities.spec.ts index 35052dee0a..a6c5d6177b 100644 --- a/test-mocha/common/entity/get_group_entities.spec.js +++ b/test-mocha/common/entity/get_group_entities.spec.ts @@ -1,4 +1,4 @@ -import assert from "assert"; +import * as assert from "assert"; import getGroupEntities from "../../../src/common/entity/get_group_entities"; diff --git a/test-mocha/common/entity/get_view_entities.spec.js b/test-mocha/common/entity/get_view_entities.spec.ts similarity index 98% rename from test-mocha/common/entity/get_view_entities.spec.js rename to test-mocha/common/entity/get_view_entities.spec.ts index b95cb573ac..c39b8a37ed 100644 --- a/test-mocha/common/entity/get_view_entities.spec.js +++ b/test-mocha/common/entity/get_view_entities.spec.ts @@ -1,4 +1,4 @@ -import assert from "assert"; +import * as assert from "assert"; import getViewEntities from "../../../src/common/entity/get_view_entities"; diff --git a/test-mocha/common/entity/has_location.test.js b/test-mocha/common/entity/has_location.test.ts similarity index 87% rename from test-mocha/common/entity/has_location.test.js rename to test-mocha/common/entity/has_location.test.ts index 10389d35be..88ee4f7508 100644 --- a/test-mocha/common/entity/has_location.test.js +++ b/test-mocha/common/entity/has_location.test.ts @@ -4,7 +4,7 @@ import hasLocation from "../../../src/common/entity/has_location"; describe("hasLocation", () => { it("flags states with location", () => { - const stateObj = { + const stateObj: any = { attributes: { latitude: 12.34, longitude: 12.34, @@ -13,7 +13,7 @@ describe("hasLocation", () => { assert(hasLocation(stateObj)); }); it("does not flag states with only latitude", () => { - const stateObj = { + const stateObj: any = { attributes: { latitude: 12.34, }, @@ -21,7 +21,7 @@ describe("hasLocation", () => { assert(!hasLocation(stateObj)); }); it("does not flag states with only longitude", () => { - const stateObj = { + const stateObj: any = { attributes: { longitude: 12.34, }, @@ -29,7 +29,7 @@ describe("hasLocation", () => { assert(!hasLocation(stateObj)); }); it("does not flag states with no location", () => { - const stateObj = { + const stateObj: any = { attributes: {}, }; assert(!hasLocation(stateObj)); diff --git a/test-mocha/common/entity/split_by_groups.spec.js b/test-mocha/common/entity/split_by_groups.spec.ts similarity index 96% rename from test-mocha/common/entity/split_by_groups.spec.js rename to test-mocha/common/entity/split_by_groups.spec.ts index 85c31f4715..ede3c3ea19 100644 --- a/test-mocha/common/entity/split_by_groups.spec.js +++ b/test-mocha/common/entity/split_by_groups.spec.ts @@ -1,4 +1,4 @@ -import assert from "assert"; +import * as assert from "assert"; import splitByGroups from "../../../src/common/entity/split_by_groups"; diff --git a/test-mocha/common/entity/state_card_type_test.js b/test-mocha/common/entity/state_card_type_test.ts similarity index 88% rename from test-mocha/common/entity/state_card_type_test.js rename to test-mocha/common/entity/state_card_type_test.ts index 3d9c66edbe..deb455784c 100644 --- a/test-mocha/common/entity/state_card_type_test.js +++ b/test-mocha/common/entity/state_card_type_test.ts @@ -3,7 +3,7 @@ import { assert } from "chai"; import stateCardType from "../../../src/common/entity/state_card_type"; describe("stateCardType", () => { - const hass = { + const hass: any = { services: { light: { turn_on: null, // Service keys only need to be present for test @@ -13,21 +13,21 @@ describe("stateCardType", () => { }; it("Returns display for unavailable states", () => { - const stateObj = { + const stateObj: any = { state: "unavailable", }; assert.strictEqual(stateCardType(hass, stateObj), "display"); }); it("Returns media_player for media_player states", () => { - const stateObj = { + const stateObj: any = { entity_id: "media_player.bla", }; assert.strictEqual(stateCardType(hass, stateObj), "media_player"); }); it("Returns toggle for states that can toggle", () => { - const stateObj = { + const stateObj: any = { entity_id: "light.bla", attributes: {}, }; @@ -35,7 +35,7 @@ describe("stateCardType", () => { }); it("Returns display for states with hidden control", () => { - const stateObj = { + const stateObj: any = { entity_id: "light.bla", attributes: { control: "hidden", @@ -45,7 +45,7 @@ describe("stateCardType", () => { }); it("Returns display for entities that cannot toggle", () => { - const stateObj = { + const stateObj: any = { entity_id: "sensor.bla", }; assert.strictEqual(stateCardType(hass, stateObj), "display"); diff --git a/test-mocha/common/entity/state_more_info_type_test.js b/test-mocha/common/entity/state_more_info_type_test.ts similarity index 89% rename from test-mocha/common/entity/state_more_info_type_test.js rename to test-mocha/common/entity/state_more_info_type_test.ts index 93a1e8d7cb..1d62f53b8d 100644 --- a/test-mocha/common/entity/state_more_info_type_test.js +++ b/test-mocha/common/entity/state_more_info_type_test.ts @@ -4,14 +4,14 @@ import stateMoreInfoType from "../../../src/common/entity/state_more_info_type"; describe("stateMoreInfoType", () => { it("Returns media_player for media_player states", () => { - const stateObj = { + const stateObj: any = { entity_id: "media_player.bla", }; assert.strictEqual(stateMoreInfoType(stateObj), "media_player"); }); it("Returns hidden for input_select states", () => { - const stateObj = { + const stateObj: any = { entity_id: "input_select.bla", attributes: {}, }; @@ -19,7 +19,7 @@ describe("stateMoreInfoType", () => { }); it("Returns default for switch states", () => { - const stateObj = { + const stateObj: any = { entity_id: "switch.bla", attributes: {}, }; diff --git a/test-mocha/common/entity/test_util.js b/test-mocha/common/entity/test_util.ts similarity index 97% rename from test-mocha/common/entity/test_util.js rename to test-mocha/common/entity/test_util.ts index 32aa92aef6..1d7b3f203c 100644 --- a/test-mocha/common/entity/test_util.js +++ b/test-mocha/common/entity/test_util.ts @@ -27,7 +27,7 @@ export function createView(entity) { return createGroup(entity); } -export function createLightEntity(isOn) { +export function createLightEntity(isOn?) { mockState++; if (isOn === undefined) { isOn = Math.random() > 0.5; diff --git a/test-mocha/common/entity/timer_time_remaining_test.js b/test-mocha/common/entity/timer_time_remaining_test.ts similarity index 92% rename from test-mocha/common/entity/timer_time_remaining_test.js rename to test-mocha/common/entity/timer_time_remaining_test.ts index fd77bc92b8..e049fa1015 100644 --- a/test-mocha/common/entity/timer_time_remaining_test.js +++ b/test-mocha/common/entity/timer_time_remaining_test.ts @@ -1,5 +1,5 @@ import { assert } from "chai"; -import sinon from "sinon"; +import * as sinon from "sinon"; import timerTimeRemaining from "../../../src/common/entity/timer_time_remaining"; @@ -11,7 +11,7 @@ describe("timerTimeRemaining", () => { attributes: { remaining: "0:01:05", }, - }), + } as any), 65 ); }); @@ -23,7 +23,7 @@ describe("timerTimeRemaining", () => { attributes: { remaining: "0:01:05", }, - }), + } as any), 65 ); }); @@ -44,7 +44,7 @@ describe("timerTimeRemaining", () => { remaining: "0:01:05", }, last_changed: "2018-01-17T16:15:12Z", - }), + } as any), 47 ); }); diff --git a/test-mocha/common/util/parse_aspect_ratio_test.js b/test-mocha/common/util/parse_aspect_ratio_test.ts similarity index 97% rename from test-mocha/common/util/parse_aspect_ratio_test.js rename to test-mocha/common/util/parse_aspect_ratio_test.ts index dd6af4f3cc..15b42a0cc1 100644 --- a/test-mocha/common/util/parse_aspect_ratio_test.js +++ b/test-mocha/common/util/parse_aspect_ratio_test.ts @@ -1,4 +1,4 @@ -import assert from "assert"; +import * as assert from "assert"; import parseAspectRatio from "../../../src/common/util/parse-aspect-ratio"; diff --git a/test-mocha/mocha.opts b/test-mocha/mocha.opts index f25388f803..7157db4af7 100644 --- a/test-mocha/mocha.opts +++ b/test-mocha/mocha.opts @@ -1,4 +1,3 @@ --recursive ---require reify --timeout 10000 -test-mocha +test-mocha/**/*.ts diff --git a/test-mocha/tsconfig.test.json b/test-mocha/tsconfig.test.json new file mode 100644 index 0000000000..0e7afc6855 --- /dev/null +++ b/test-mocha/tsconfig.test.json @@ -0,0 +1,6 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "module": "commonjs" + } +} diff --git a/test-mocha/tslint.json b/test-mocha/tslint.json new file mode 100644 index 0000000000..1e32f15d50 --- /dev/null +++ b/test-mocha/tslint.json @@ -0,0 +1,6 @@ +{ + "extends": ["../tslint.json"], + "rules": { + "no-implicit-dependencies": [true, "dev"] + } +} diff --git a/yarn.lock b/yarn.lock index 6bb4ab49fa..f88b1a14d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1372,10 +1372,10 @@ dependencies: any-observable "^0.3.0" -"@sinonjs/commons@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.0.2.tgz#3e0ac737781627b8844257fadc3d803997d0526e" - integrity sha512-WR3dlgqJP4QNrLC4iXN/5/2WaLQQ0VijOOkmflqFGVJ6wLEpbSjo7c0ZeGIdtY8Crk7xBBp87sM6+Mkerz7alw== +"@sinonjs/commons@^1.2.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.3.0.tgz#50a2754016b6f30a994ceda6d9a0a8c36adda849" + integrity sha512-j4ZwhaHmwsCb4DlDOIWnI5YyKDNMoNThsmwEpfHx6a1EpsGZ9qYLxP++LMlmBRjtGptGHFsGItJ768snllFWpA== dependencies: type-detect "4.0.8" @@ -1449,7 +1449,7 @@ dependencies: "@types/chai" "*" -"@types/chai@*": +"@types/chai@*", "@types/chai@^4.1.7": version "4.1.7" resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.7.tgz#1b8e33b61a8c09cbe1f85133071baa0dbf9fa71a" integrity sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA== @@ -1624,6 +1624,11 @@ resolved "https://registry.yarnpkg.com/@types/is-windows/-/is-windows-0.2.0.tgz#6f24ee48731d31168ea510610d6dd15e5fc9c6ff" integrity sha1-byTuSHMdMRaOpRBhDW3RXl/Jxv8= +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + "@types/launchpad@^0.6.0": version "0.6.0" resolved "https://registry.yarnpkg.com/@types/launchpad/-/launchpad-0.6.0.tgz#37296109b7f277f6e6c5fd7e0c0706bc918fbb51" @@ -1646,6 +1651,11 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== +"@types/mocha@^5.2.5": + version "5.2.5" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.5.tgz#8a4accfc403c124a0bafe8a9fc61a05ec1032073" + integrity sha512-lAVp+Kj54ui/vLUFxsJTMtWvZraZxum3w3Nwkble2dNuV5VnPA+Mi2oGX9XYJAaIvZi3tn3cbjS/qcJXRb6Bww== + "@types/mz@0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/mz/-/mz-0.0.29.tgz#bc24728c649973f1c7851e9033f9ce525668c27b" @@ -3667,11 +3677,6 @@ browser-stdout@1.3.0: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" integrity sha1-81HTKWnTL6XXpVZxVCY9korjvR8= -browser-stdout@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== - browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.2.0" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" @@ -3777,7 +3782,7 @@ buffer-fill@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= -buffer-from@^1.0.0: +buffer-from@^1.0.0, buffer-from@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== @@ -3965,7 +3970,7 @@ chai@^3.5.0: deep-eql "^0.1.3" type-detect "^1.0.0" -chai@^4.1.2: +chai@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw== @@ -4369,7 +4374,7 @@ command-line-usage@^5.0.5: table-layout "^0.4.3" typical "^2.6.1" -commander@2.15.1, commander@2.15.x, commander@~2.15.0: +commander@2.15.x, commander@~2.15.0: version "2.15.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== @@ -4848,7 +4853,7 @@ debug@2.6.8: dependencies: ms "2.0.0" -debug@3.1.0, debug@=3.1.0, debug@~3.1.0: +debug@=3.1.0, debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== @@ -4939,6 +4944,11 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +deepmerge@^2.0.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" + integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== + default-gateway@^2.6.0: version "2.7.2" resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-2.7.2.tgz#b7ef339e5e024b045467af403d50348db4642d0f" @@ -5118,16 +5128,16 @@ diff@3.2.0: resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" integrity sha1-yc45Okt8vQsFinJck98pkCeGj/k= -diff@3.5.0, diff@^3.1.0, diff@^3.2.0, diff@^3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" - integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== - diff@^2.1.2: version "2.2.3" resolved "https://registry.yarnpkg.com/diff/-/diff-2.2.3.tgz#60eafd0d28ee906e4e8ff0a52c1229521033bf99" integrity sha1-YOr9DSjukG5Oj/ClLBIpUhAzv5k= +diff@^3.1.0, diff@^3.2.0, diff@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + diffie-hellman@^5.0.0: version "5.0.3" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" @@ -6772,18 +6782,6 @@ glob@7.1.1: once "^1.3.0" path-is-absolute "^1.0.0" -glob@7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== - dependencies: - 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" - glob@^4.3.1: version "4.5.3" resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" @@ -7065,11 +7063,6 @@ grouped-queue@^0.3.0, grouped-queue@^0.3.3: dependencies: lodash "^4.17.2" -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== - growl@1.9.2: version "1.9.2" resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" @@ -9334,6 +9327,11 @@ make-dir@^1.0.0, make-dir@^1.1.0: dependencies: pify "^3.0.0" +make-error@^1.1.1: + version "1.3.5" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" + integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== + map-age-cleaner@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.2.tgz#098fb15538fd3dbe461f12745b0ca8568d4e3f74" @@ -9599,7 +9597,7 @@ minimatch-all@^1.1.0: dependencies: minimatch "^3.0.2" -"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== @@ -9721,23 +9719,6 @@ mocha@^3.4.2: mkdirp "0.5.1" supports-color "3.1.2" -mocha@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" - integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== - dependencies: - browser-stdout "1.3.1" - commander "2.15.1" - debug "3.1.0" - diff "3.5.0" - escape-string-regexp "1.0.5" - glob "7.1.2" - growl "1.10.5" - he "1.1.1" - minimatch "3.0.4" - mkdirp "0.5.1" - supports-color "5.4.0" - moment@^2.10.2, moment@^2.22.0: version "2.22.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.1.tgz#529a2e9bf973f259c9643d237fda84de3a26e8ad" @@ -12321,12 +12302,12 @@ sinon@^2.3.5: text-encoding "0.6.4" type-detect "^4.0.0" -sinon@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-7.1.0.tgz#819b63002ee09a90a3b50a0da4e0bdecb2e3f345" - integrity sha512-ffASxced8xr8eU0EGyfj9K++bRCtv/NyOFOxl7UBD86YH97oZjVxvecMhObwRlXe27GRUa6rVFEn67khPZ29rQ== +sinon@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-7.1.1.tgz#1202f317aa14d93cb9b69ff50b6bd49c0e05ffc9" + integrity sha512-iYagtjLVt1vN3zZY7D8oH7dkjNJEjLjyuzy8daX5+3bbQl8gaohrheB9VfH1O3L6LKuue5WTJvFluHiuZ9y3nQ== dependencies: - "@sinonjs/commons" "^1.0.2" + "@sinonjs/commons" "^1.2.0" "@sinonjs/formatio" "^3.0.0" "@sinonjs/samsam" "^2.1.2" diff "^3.5.0" @@ -12503,6 +12484,14 @@ source-map-support@^0.4.15: dependencies: source-map "^0.5.6" +source-map-support@^0.5.6: + version "0.5.9" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" + integrity sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" @@ -12513,7 +12502,7 @@ source-map@0.5.x, source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, sourc resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -12875,7 +12864,7 @@ strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -supports-color@3.1.2, supports-color@5.4.0, supports-color@^0.2.0, supports-color@^2.0.0, supports-color@^5.1.0, supports-color@^5.3.0, supports-color@^5.4.0, supports-color@^5.5.0: +supports-color@3.1.2, supports-color@^0.2.0, supports-color@^2.0.0, supports-color@^5.1.0, supports-color@^5.3.0, supports-color@^5.4.0, supports-color@^5.5.0: version "3.1.2" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" integrity sha1-cqJiiU2dQIuVbKBf83su2KbiotU= @@ -13251,6 +13240,40 @@ triple-beam@^1.2.0, triple-beam@^1.3.0: resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== +ts-mocha@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ts-mocha/-/ts-mocha-2.0.0.tgz#0dbd3cd04671df9933b9303b4aa46347573c5635" + integrity sha512-Rj6+vvwKtOTs5GsNO1jLl4DIXUGnyAg5HFt2Yb4SHIRN45clTJkHWpNdTxCSL0u+1oeavSYJah6d1PZ++Ju5pw== + dependencies: + ts-node "7.0.0" + optionalDependencies: + tsconfig-paths "^3.5.0" + +ts-node@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.0.tgz#a94a13c75e5e1aa6b82814b84c68deb339ba7bff" + integrity sha512-klJsfswHP0FuOLsvBZ/zzCfUvakOSSxds78mVeK7I+qP76YWtxf16hEZsp3U+b0kIo82R5UatGFeblYMqabb2Q== + dependencies: + arrify "^1.0.0" + buffer-from "^1.1.0" + diff "^3.1.0" + make-error "^1.1.1" + minimist "^1.2.0" + mkdirp "^0.5.1" + source-map-support "^0.5.6" + yn "^2.0.0" + +tsconfig-paths@^3.5.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.6.0.tgz#f14078630d9d6e8b1dc690c1fc0cfb9cd0663891" + integrity sha512-mrqQIP2F4e03aMTCiPdedCIT300//+q0ET53o5WqqtQjmEICxP9yfz/sHTpPqXpssuJEzODsEzJaLRaf5J2X1g== + dependencies: + "@types/json5" "^0.0.29" + deepmerge "^2.0.1" + json5 "^1.0.1" + minimist "^1.2.0" + strip-bom "^3.0.0" + tslib@1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" @@ -14645,6 +14668,11 @@ yeoman-generator@^3.1.1: through2 "^2.0.0" yeoman-environment "^2.0.5" +yn@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" + integrity sha1-5a2ryKz0CPY4X8dklWhMiOavaJo= + zip-stream@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-1.2.0.tgz#a8bc45f4c1b49699c6b90198baacaacdbcd4ba04"