From b85a72d6b30cfae453c596ecaecfd2362c2d07f5 Mon Sep 17 00:00:00 2001 From: Vis Bot <53650362+vis-bot@users.noreply.github.com> Date: Tue, 13 Aug 2019 22:54:30 +0200 Subject: [PATCH] style: reformat (#48) --- src/index.ts | 6 +- src/util.ts | 1183 +++++++++++++----------- test/add-class-name.test.ts | 32 +- test/add-remove-event-listener.test.ts | 162 ++-- test/binary-search-custom.test.ts | 137 +-- test/bridge-object.test.ts | 171 ++-- test/copy-and-extend-array.test.ts | 56 +- test/copy-array.test.ts | 45 +- test/deep-extend.test.ts | 365 ++++---- test/for-each.test.ts | 56 +- test/get-absolute.test.ts | 34 +- test/helpers/index.ts | 25 +- test/hex-to-rgb.test.ts | 89 +- test/hsv-to-rgb.test.ts | 22 +- test/insert-sort.test.ts | 34 +- test/is-valid-hex.test.ts | 74 +- test/is-valid-rgb.test.ts | 108 +-- test/is-valid-rgba.test.ts | 112 +-- test/parse-color.test.ts | 333 +++---- test/remove-class-name.test.ts | 28 +- test/rgb-to-hex.test.ts | 38 +- test/selective-deep-extend.test.ts | 183 ++-- test/selective-extend.test.ts | 115 ++- test/throttle.test.ts | 184 ++-- test/top-most.test.ts | 71 +- 25 files changed, 1986 insertions(+), 1677 deletions(-) diff --git a/src/index.ts b/src/index.ts index 8cf88fc9..741552a2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ // New API (tree shakeable). -export * from './util' +export * from "./util"; // Old API (treeshakeable only if completely unused). -import * as util from './util' -export default util +import * as util from "./util"; +export default util; diff --git a/src/util.ts b/src/util.ts index 4e62a431..5396b27b 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,21 +1,21 @@ // utility functions // @TODO: Million different solutions online, none works here. -import { Moment } from 'moment' -import moment from 'moment' +import { Moment } from "moment"; +import moment from "moment"; -export { uuid4 as randomUUID } from 'vis-uuid' +export { uuid4 as randomUUID } from "vis-uuid"; // parse ASP.Net Date pattern, // for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/' // code from http://momentjs.com/ -const ASPDateRegex = /^\/?Date\((-?\d+)/i +const ASPDateRegex = /^\/?Date\((-?\d+)/i; // Color REs -const fullHexRE = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i -const shortHexRE = /^#?([a-f\d])([a-f\d])([a-f\d])$/i -const rgbRE = /^rgb\( *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *(1?\d{1,2}|2[0-4]\d|25[0-5]) *\)$/i -const rgbaRE = /^rgba\( *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *([01]|0?\.\d+) *\)$/i +const fullHexRE = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i; +const shortHexRE = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; +const rgbRE = /^rgb\( *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *(1?\d{1,2}|2[0-4]\d|25[0-5]) *\)$/i; +const rgbaRE = /^rgba\( *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *([01]|0?\.\d+) *\)$/i; /** * Hue, Saturation, Value. @@ -24,15 +24,15 @@ export interface HSV { /** * Hue <0, 1>. */ - h: number + h: number; /** * Saturation <0, 1>. */ - s: number + s: number; /** * Value <0, 1>. */ - v: number + v: number; } /** @@ -42,15 +42,15 @@ export interface RGB { /** * Red <0, 255> integer. */ - r: number + r: number; /** * Green <0, 255> integer. */ - g: number + g: number; /** * Blue <0, 255> integer. */ - b: number + b: number; } /** @@ -60,19 +60,19 @@ export interface RGBA { /** * Red <0, 255> integer. */ - r: number + r: number; /** * Green <0, 255> integer. */ - g: number + g: number; /** * Blue <0, 255> integer. */ - b: number + b: number; /** * Alpha <0, 1>. */ - a: number + a: number; } /** @@ -83,7 +83,7 @@ export interface RGBA { * @returns True if number, false otherwise. */ export function isNumber(value: unknown): value is number { - return value instanceof Number || typeof value === 'number' + return value instanceof Number || typeof value === "number"; } /** @@ -94,10 +94,10 @@ export function isNumber(value: unknown): value is number { export function recursiveDOMDelete(DOMobject: Node | null | undefined): void { if (DOMobject) { while (DOMobject.hasChildNodes() === true) { - const child = DOMobject.firstChild + const child = DOMobject.firstChild; if (child) { - recursiveDOMDelete(child) - DOMobject.removeChild(child) + recursiveDOMDelete(child); + DOMobject.removeChild(child); } } } @@ -111,7 +111,7 @@ export function recursiveDOMDelete(DOMobject: Node | null | undefined): void { * @returns True if string, false otherwise. */ export function isString(value: unknown): value is string { - return value instanceof String || typeof value === 'string' + return value instanceof String || typeof value === "string"; } /** @@ -122,7 +122,7 @@ export function isString(value: unknown): value is string { * @returns True if not null object, false otherwise. */ export function isObject(value: unknown): value is object { - return typeof value === 'object' && value !== null + return typeof value === "object" && value !== null; } /** @@ -134,18 +134,18 @@ export function isObject(value: unknown): value is object { */ export function isDate(value: unknown): value is Date | string { if (value instanceof Date) { - return true + return true; } else if (isString(value)) { // test whether this string contains a date - const match = ASPDateRegex.exec(value) + const match = ASPDateRegex.exec(value); if (match) { - return true + return true; } else if (!isNaN(Date.parse(value))) { - return true + return true; } } - return false + return false; } /** @@ -157,7 +157,7 @@ export function isDate(value: unknown): value is Date | string { * @returns True if Moment instance, false otherwise. */ export function isMoment(value: unknown): value is Moment { - return moment.isMoment(value) + return moment.isMoment(value); } /** @@ -171,16 +171,21 @@ export function isMoment(value: unknown): value is Moment { * @param prop - Name of property to copy from b to a. * @param allowDeletion if true, delete property in a if explicitly set to null in b */ -function copyOrDelete(a: any, b: any, prop: string, allowDeletion: boolean): void { - let doDeletion = false +function copyOrDelete( + a: any, + b: any, + prop: string, + allowDeletion: boolean +): void { + let doDeletion = false; if (allowDeletion === true) { - doDeletion = b[prop] === null && a[prop] !== undefined + doDeletion = b[prop] === null && a[prop] !== undefined; } if (doDeletion) { - delete a[prop] + delete a[prop]; } else { - a[prop] = b[prop] // Remember, this is a reference copy! + a[prop] = b[prop]; // Remember, this is a reference copy! } } @@ -194,19 +199,23 @@ function copyOrDelete(a: any, b: any, prop: string, allowDeletion: boolean): voi * @param b - The object with property updates. * @param allowDeletion - if true, delete properties in a that are explicitly set to null in b */ -export function fillIfDefined(a: T, b: Partial, allowDeletion: boolean = false): void { +export function fillIfDefined( + a: T, + b: Partial, + allowDeletion: boolean = false +): void { // NOTE: iteration of properties of a // NOTE: prototype properties iterated over as well for (const prop in a) { if (b[prop] !== undefined) { - if (b[prop] === null || typeof b[prop] !== 'object') { + if (b[prop] === null || typeof b[prop] !== "object") { // Note: typeof null === 'object' - copyOrDelete(a, b, prop, allowDeletion) + copyOrDelete(a, b, prop, allowDeletion); } else { - const aProp = a[prop] - const bProp = b[prop] + const aProp = a[prop]; + const bProp = b[prop]; if (isObject(aProp) && isObject(bProp)) { - fillIfDefined(aProp, bProp, allowDeletion) + fillIfDefined(aProp, bProp, allowDeletion); } } } @@ -222,7 +231,7 @@ export function fillIfDefined(a: T, b: Partial, allowDeleti * * @return The target object. */ -export const extend = Object.assign +export const extend = Object.assign; /** * Extend object a with selected properties of object b or a series of objects @@ -234,20 +243,24 @@ export const extend = Object.assign * * @returns Argument a. */ -export function selectiveExtend(props: string[], a: any, ...others: any[]): any { +export function selectiveExtend( + props: string[], + a: any, + ...others: any[] +): any { if (!Array.isArray(props)) { - throw new Error('Array with property names expected as first argument') + throw new Error("Array with property names expected as first argument"); } for (const other of others) { for (let p = 0; p < props.length; p++) { - const prop = props[p] + const prop = props[p]; if (other && Object.prototype.hasOwnProperty.call(other, prop)) { - a[prop] = other[prop] + a[prop] = other[prop]; } } } - return a + return a; } /** @@ -266,32 +279,37 @@ export function selectiveExtend(props: string[], a: any, ...others: any[]): any * * @returns Argument a. */ -export function selectiveDeepExtend(props: string[], a: any, b: any, allowDeletion: boolean = false): any { +export function selectiveDeepExtend( + props: string[], + a: any, + b: any, + allowDeletion: boolean = false +): any { // TODO: add support for Arrays to deepExtend if (Array.isArray(b)) { - throw new TypeError('Arrays are not supported by deepExtend') + throw new TypeError("Arrays are not supported by deepExtend"); } for (let p = 0; p < props.length; p++) { - const prop = props[p] + const prop = props[p]; if (Object.prototype.hasOwnProperty.call(b, prop)) { if (b[prop] && b[prop].constructor === Object) { if (a[prop] === undefined) { - a[prop] = {} + a[prop] = {}; } if (a[prop].constructor === Object) { - deepExtend(a[prop], b[prop], false, allowDeletion) + deepExtend(a[prop], b[prop], false, allowDeletion); } else { - copyOrDelete(a, b, prop, allowDeletion) + copyOrDelete(a, b, prop, allowDeletion); } } else if (Array.isArray(b[prop])) { - throw new TypeError('Arrays are not supported by deepExtend') + throw new TypeError("Arrays are not supported by deepExtend"); } else { - copyOrDelete(a, b, prop, allowDeletion) + copyOrDelete(a, b, prop, allowDeletion); } } } - return a + return a; } /** @@ -309,41 +327,46 @@ export function selectiveDeepExtend(props: string[], a: any, b: any, allowDeleti * * @returns Argument a. */ -export function selectiveNotDeepExtend(propsToExclude: string[], a: any, b: any, allowDeletion: boolean = false): any { +export function selectiveNotDeepExtend( + propsToExclude: string[], + a: any, + b: any, + allowDeletion: boolean = false +): any { // TODO: add support for Arrays to deepExtend // NOTE: array properties have an else-below; apparently, there is a problem here. if (Array.isArray(b)) { - throw new TypeError('Arrays are not supported by deepExtend') + throw new TypeError("Arrays are not supported by deepExtend"); } for (const prop in b) { if (!Object.prototype.hasOwnProperty.call(b, prop)) { - continue + continue; } // Handle local properties only if (propsToExclude.indexOf(prop) !== -1) { - continue + continue; } // In exclusion list, skip if (b[prop] && b[prop].constructor === Object) { if (a[prop] === undefined) { - a[prop] = {} + a[prop] = {}; } if (a[prop].constructor === Object) { - deepExtend(a[prop], b[prop]) // NOTE: allowDeletion not propagated! + deepExtend(a[prop], b[prop]); // NOTE: allowDeletion not propagated! } else { - copyOrDelete(a, b, prop, allowDeletion) + copyOrDelete(a, b, prop, allowDeletion); } } else if (Array.isArray(b[prop])) { - a[prop] = [] + a[prop] = []; for (let i = 0; i < b[prop].length; i++) { - a[prop].push(b[prop][i]) + a[prop].push(b[prop][i]); } } else { - copyOrDelete(a, b, prop, allowDeletion) + copyOrDelete(a, b, prop, allowDeletion); } } - return a + return a; } /** @@ -357,25 +380,33 @@ export function selectiveNotDeepExtend(propsToExclude: string[], a: any, b: any, * * @returns Argument a. */ -export function deepExtend(a: any, b: any, protoExtend: boolean = false, allowDeletion: boolean = false): any { +export function deepExtend( + a: any, + b: any, + protoExtend: boolean = false, + allowDeletion: boolean = false +): any { for (const prop in b) { if (Object.prototype.hasOwnProperty.call(b, prop) || protoExtend === true) { if (b[prop] && Object.getPrototypeOf(b[prop]) === Object.prototype) { if (a[prop] === undefined) { - a[prop] = deepExtend({}, b[prop], protoExtend) // NOTE: allowDeletion not propagated! - } else if (a[prop] && Object.getPrototypeOf(a[prop]) === Object.prototype) { - deepExtend(a[prop], b[prop], protoExtend) // NOTE: allowDeletion not propagated! + a[prop] = deepExtend({}, b[prop], protoExtend); // NOTE: allowDeletion not propagated! + } else if ( + a[prop] && + Object.getPrototypeOf(a[prop]) === Object.prototype + ) { + deepExtend(a[prop], b[prop], protoExtend); // NOTE: allowDeletion not propagated! } else { - copyOrDelete(a, b, prop, allowDeletion) + copyOrDelete(a, b, prop, allowDeletion); } } else if (Array.isArray(b[prop])) { - a[prop] = b[prop].slice() + a[prop] = b[prop].slice(); } else { - copyOrDelete(a, b, prop, allowDeletion) + copyOrDelete(a, b, prop, allowDeletion); } } } - return a + return a; } /** @@ -388,38 +419,38 @@ export function deepExtend(a: any, b: any, protoExtend: boolean = false, allowDe */ export function equalArray(a: unknown[], b: unknown[]): boolean { if (a.length !== b.length) { - return false + return false; } for (let i = 0, len = a.length; i < len; i++) { if (a[i] != b[i]) { - return false + return false; } } - return true + return true; } export type Types = - | 'boolean' - | 'Boolean' - | 'number' - | 'Number' - | 'string' - | 'String' - | 'Date' - | 'ISODate' - | 'ASPDate' - | 'Moment' -export function convert(object: T, type: null): T -export function convert(object: unknown, type: 'boolean' | 'Boolean'): boolean -export function convert(object: unknown, type: 'number' | 'Number'): number -export function convert(object: unknown, type: 'string' | 'String'): string -export function convert(object: unknown, type: 'Date'): Date -export function convert(object: unknown, type: 'ISODate'): string -export function convert(object: unknown, type: 'ASPDate'): string -export function convert(object: unknown, type: 'Moment'): Moment -export function convert(object: unknown, type: Types | null): any + | "boolean" + | "Boolean" + | "number" + | "Number" + | "string" + | "String" + | "Date" + | "ISODate" + | "ASPDate" + | "Moment"; +export function convert(object: T, type: null): T; +export function convert(object: unknown, type: "boolean" | "Boolean"): boolean; +export function convert(object: unknown, type: "number" | "Number"): number; +export function convert(object: unknown, type: "string" | "String"): string; +export function convert(object: unknown, type: "Date"): Date; +export function convert(object: unknown, type: "ISODate"): string; +export function convert(object: unknown, type: "ASPDate"): string; +export function convert(object: unknown, type: "Moment"): Moment; +export function convert(object: unknown, type: Types | null): any; /** * Convert an object into another type * @@ -430,125 +461,137 @@ export function convert(object: unknown, type: Types | null): any * @throws Error */ export function convert(object: unknown, type: Types | null): any { - let match + let match; if (object === undefined) { - return undefined + return undefined; } if (object === null) { - return null + return null; } if (!type) { - return object + return object; } - if (!(typeof type === 'string') && !((type as any) instanceof String)) { - throw new Error('Type must be a string') + if (!(typeof type === "string") && !((type as any) instanceof String)) { + throw new Error("Type must be a string"); } //noinspection FallthroughInSwitchStatementJS switch (type) { - case 'boolean': - case 'Boolean': - return Boolean(object) + case "boolean": + case "Boolean": + return Boolean(object); - case 'number': - case 'Number': + case "number": + case "Number": if (isString(object) && !isNaN(Date.parse(object))) { - return moment(object).valueOf() + return moment(object).valueOf(); } else { // @TODO: I don't think that Number and String constructors are a good idea. // This could also fail if the object doesn't have valueOf method or if it's redefined. // For example: Object.create(null) or { valueOf: 7 }. - return Number((object as any).valueOf()) + return Number((object as any).valueOf()); } - case 'string': - case 'String': - return String(object) + case "string": + case "String": + return String(object); - case 'Date': + case "Date": if (isNumber(object)) { - return new Date(object) + return new Date(object); } if (object instanceof Date) { - return new Date(object.valueOf()) + return new Date(object.valueOf()); } else if (isMoment(object)) { - return new Date(object.valueOf()) + return new Date(object.valueOf()); } if (isString(object)) { - match = ASPDateRegex.exec(object) + match = ASPDateRegex.exec(object); if (match) { // object is an ASP date - return new Date(Number(match[1])) // parse number + return new Date(Number(match[1])); // parse number } else { - return moment(new Date(object)).toDate() // parse string + return moment(new Date(object)).toDate(); // parse string } } else { - throw new Error('Cannot convert object of type ' + getType(object) + ' to type Date') + throw new Error( + "Cannot convert object of type " + getType(object) + " to type Date" + ); } - case 'Moment': + case "Moment": if (isNumber(object)) { - return moment(object) + return moment(object); } if (object instanceof Date) { - return moment(object.valueOf()) + return moment(object.valueOf()); } else if (isMoment(object)) { - return moment(object) + return moment(object); } if (isString(object)) { - match = ASPDateRegex.exec(object) + match = ASPDateRegex.exec(object); if (match) { // object is an ASP date - return moment(Number(match[1])) // parse number + return moment(Number(match[1])); // parse number } else { - return moment(object) // parse string + return moment(object); // parse string } } else { - throw new Error('Cannot convert object of type ' + getType(object) + ' to type Date') + throw new Error( + "Cannot convert object of type " + getType(object) + " to type Date" + ); } - case 'ISODate': + case "ISODate": if (isNumber(object)) { - return new Date(object) + return new Date(object); } else if (object instanceof Date) { - return object.toISOString() + return object.toISOString(); } else if (isMoment(object)) { - return object.toDate().toISOString() + return object.toDate().toISOString(); } else if (isString(object)) { - match = ASPDateRegex.exec(object) + match = ASPDateRegex.exec(object); if (match) { // object is an ASP date - return new Date(Number(match[1])).toISOString() // parse number + return new Date(Number(match[1])).toISOString(); // parse number } else { - return moment(object).format() // ISO 8601 + return moment(object).format(); // ISO 8601 } } else { - throw new Error('Cannot convert object of type ' + getType(object) + ' to type ISODate') + throw new Error( + "Cannot convert object of type " + + getType(object) + + " to type ISODate" + ); } - case 'ASPDate': + case "ASPDate": if (isNumber(object)) { - return '/Date(' + object + ')/' + return "/Date(" + object + ")/"; } else if (object instanceof Date || isMoment(object)) { - return '/Date(' + object.valueOf() + ')/' + return "/Date(" + object.valueOf() + ")/"; } else if (isString(object)) { - match = ASPDateRegex.exec(object) - let value + match = ASPDateRegex.exec(object); + let value; if (match) { // object is an ASP date - value = new Date(Number(match[1])).valueOf() // parse number + value = new Date(Number(match[1])).valueOf(); // parse number } else { - value = new Date(object).valueOf() // parse string + value = new Date(object).valueOf(); // parse string } - return '/Date(' + value + ')/' + return "/Date(" + value + ")/"; } else { - throw new Error('Cannot convert object of type ' + getType(object) + ' to type ASPDate') + throw new Error( + "Cannot convert object of type " + + getType(object) + + " to type ASPDate" + ); } default: - const never: never = type - throw new Error(`Unknown type ${never}`) + const never: never = type; + throw new Error(`Unknown type ${never}`); } } @@ -560,48 +603,51 @@ export function convert(object: unknown, type: Types | null): any { * @returns Detected type. */ export function getType(object: unknown): string { - const type = typeof object + const type = typeof object; - if (type === 'object') { + if (type === "object") { if (object === null) { - return 'null' + return "null"; } if (object instanceof Boolean) { - return 'Boolean' + return "Boolean"; } if (object instanceof Number) { - return 'Number' + return "Number"; } if (object instanceof String) { - return 'String' + return "String"; } if (Array.isArray(object)) { - return 'Array' + return "Array"; } if (object instanceof Date) { - return 'Date' + return "Date"; } - return 'Object' + return "Object"; } - if (type === 'number') { - return 'Number' + if (type === "number") { + return "Number"; } - if (type === 'boolean') { - return 'Boolean' + if (type === "boolean") { + return "Boolean"; } - if (type === 'string') { - return 'String' + if (type === "string") { + return "String"; } if (type === undefined) { - return 'undefined' + return "undefined"; } - return type + return type; } -export function copyAndExtendArray(arr: readonly T[], newValue: T): T[] -export function copyAndExtendArray(arr: readonly A[], newValue: V): (A | V)[] +export function copyAndExtendArray(arr: readonly T[], newValue: T): T[]; +export function copyAndExtendArray( + arr: readonly A[], + newValue: V +): (A | V)[]; /** * Used to extend an array and copy it. This is used to propagate paths recursively. * @@ -610,8 +656,11 @@ export function copyAndExtendArray(arr: readonly A[], newValue: V): (A | V * * @returns A new array with all items from arr and newValue (which is last). */ -export function copyAndExtendArray(arr: readonly A[], newValue: V): (A | V)[] { - return [...arr, newValue] +export function copyAndExtendArray( + arr: readonly A[], + newValue: V +): (A | V)[] { + return [...arr, newValue]; } /** @@ -622,7 +671,7 @@ export function copyAndExtendArray(arr: readonly A[], newValue: V): (A | V * @returns Shallow copy of arr. */ export function copyArray(arr: readonly T[]): T[] { - return arr.slice() + return arr.slice(); } /** @@ -633,7 +682,7 @@ export function copyArray(arr: readonly T[]): T[] { * @returns The absolute left position of this element in the browser page. */ export function getAbsoluteLeft(elem: Element): number { - return elem.getBoundingClientRect().left + return elem.getBoundingClientRect().left; } /** @@ -644,7 +693,7 @@ export function getAbsoluteLeft(elem: Element): number { * @returns The absolute right position of this element in the browser page. */ export function getAbsoluteRight(elem: Element): number { - return elem.getBoundingClientRect().right + return elem.getBoundingClientRect().right; } /** @@ -655,7 +704,7 @@ export function getAbsoluteRight(elem: Element): number { * @returns The absolute top position of this element in the browser page. */ export function getAbsoluteTop(elem: Element): number { - return elem.getBoundingClientRect().top + return elem.getBoundingClientRect().top; } /** @@ -665,14 +714,14 @@ export function getAbsoluteTop(elem: Element): number { * @param classNames - Space separated list of classes. */ export function addClassName(elem: Element, classNames: string): void { - let classes = elem.className.split(' ') - const newClasses = classNames.split(' ') + let classes = elem.className.split(" "); + const newClasses = classNames.split(" "); classes = classes.concat( newClasses.filter(function(className): boolean { - return classes.indexOf(className) < 0 + return classes.indexOf(className) < 0; }) - ) - elem.className = classes.join(' ') + ); + elem.className = classes.join(" "); } /** @@ -682,22 +731,22 @@ export function addClassName(elem: Element, classNames: string): void { * @param classNames - Space separated list of classes. */ export function removeClassName(elem: Element, classNames: string): void { - let classes = elem.className.split(' ') - const oldClasses = classNames.split(' ') + let classes = elem.className.split(" "); + const oldClasses = classNames.split(" "); classes = classes.filter(function(className): boolean { - return oldClasses.indexOf(className) < 0 - }) - elem.className = classes.join(' ') + return oldClasses.indexOf(className) < 0; + }); + elem.className = classes.join(" "); } export function forEach( array: undefined | null | V[], callback: (value: V, index: number, object: V[]) => void -): void +): void; export function forEach( object: undefined | null | O, callback: (value: O[Key], key: Key, object: O) => void -): void +): void; /** * For each method for both arrays and objects. * In case of an array, the built-in Array.forEach() is applied (**No, it's not!**). @@ -709,15 +758,15 @@ export function forEach( export function forEach(object: any, callback: any): void { if (Array.isArray(object)) { // array - const len = object.length + const len = object.length; for (let i = 0; i < len; i++) { - callback(object[i], i, object) + callback(object[i], i, object); } } else { // object for (const key in object) { if (Object.prototype.hasOwnProperty.call(object, key)) { - callback(object[key], key, object) + callback(object[key], key, object); } } } @@ -730,7 +779,7 @@ export function forEach(object: any, callback: any): void { * * @returns An array of unordered values. */ -export const toArray = Object.values +export const toArray = Object.values; /** * Update a property in an object @@ -741,12 +790,16 @@ export const toArray = Object.values * * @returns Whether the value was updated (true) or already strictly the same in the original object (false). */ -export function updateProperty(object: Record, key: K, value: V): boolean { +export function updateProperty( + object: Record, + key: K, + value: V +): boolean { if (object[key] !== value) { - object[key] = value - return true + object[key] = value; + return true; } else { - return false + return false; } } @@ -758,17 +811,17 @@ export function updateProperty(object: Record, key: K * @returns The throttled function. */ export function throttle(fn: () => void): () => void { - let scheduled = false + let scheduled = false; return (): void => { if (!scheduled) { - scheduled = true + scheduled = true; requestAnimationFrame((): void => { - scheduled = false - fn() - }) + scheduled = false; + fn(); + }); } - } + }; } /** @@ -781,23 +834,26 @@ export function throttle(fn: () => void): () => void { */ export function addEventListener( element: E, - action: Parameters[0], - listener: Parameters[1], - useCapture?: Parameters[2] + action: Parameters[0], + listener: Parameters[1], + useCapture?: Parameters[2] ): void { if (element.addEventListener) { if (useCapture === undefined) { - useCapture = false + useCapture = false; } - if (action === 'mousewheel' && navigator.userAgent.indexOf('Firefox') >= 0) { - action = 'DOMMouseScroll' // For Firefox + if ( + action === "mousewheel" && + navigator.userAgent.indexOf("Firefox") >= 0 + ) { + action = "DOMMouseScroll"; // For Firefox } - element.addEventListener(action, listener, useCapture) + element.addEventListener(action, listener, useCapture); } else { // @TODO: IE types? Does anyone care? - ;(element as any).attachEvent('on' + action, listener) // IE browsers + (element as any).attachEvent("on" + action, listener); // IE browsers } } @@ -811,24 +867,27 @@ export function addEventListener( */ export function removeEventListener( element: E, - action: Parameters[0], - listener: Parameters[1], - useCapture?: Parameters[2] + action: Parameters[0], + listener: Parameters[1], + useCapture?: Parameters[2] ): void { if (element.removeEventListener) { // non-IE browsers if (useCapture === undefined) { - useCapture = false + useCapture = false; } - if (action === 'mousewheel' && navigator.userAgent.indexOf('Firefox') >= 0) { - action = 'DOMMouseScroll' // For Firefox + if ( + action === "mousewheel" && + navigator.userAgent.indexOf("Firefox") >= 0 + ) { + action = "DOMMouseScroll"; // For Firefox } - element.removeEventListener(action, listener, useCapture) + element.removeEventListener(action, listener, useCapture); } else { // @TODO: IE types? Does anyone care? - ;(element as any).detachEvent('on' + action, listener) // IE browsers + (element as any).detachEvent("on" + action, listener); // IE browsers } } @@ -839,16 +898,16 @@ export function removeEventListener( */ export function preventDefault(event: Event | undefined): void { if (!event) { - event = window.event + event = window.event; } if (!event) { // No event, no work. } else if (event.preventDefault) { - event.preventDefault() // non-IE browsers + event.preventDefault(); // non-IE browsers } else { // @TODO: IE types? Does anyone care? - ;(event as any).returnValue = false // IE browsers + (event as any).returnValue = false; // IE browsers } } @@ -859,32 +918,34 @@ export function preventDefault(event: Event | undefined): void { * * @returns The element or null if not obtainable. */ -export function getTarget(event: Event | undefined = window.event): Element | null { +export function getTarget( + event: Event | undefined = window.event +): Element | null { // code from http://www.quirksmode.org/js/events_properties.html // @TODO: EventTarget can be almost anything, is it okay to return only Elements? - let target: null | EventTarget = null + let target: null | EventTarget = null; if (!event) { // No event, no target. } else if (event.target) { - target = event.target + target = event.target; } else if (event.srcElement) { - target = event.srcElement + target = event.srcElement; } if (!(target instanceof Element)) { - return null + return null; } if (target.nodeType != null && target.nodeType == 3) { // defeat Safari bug - target = target.parentNode + target = target.parentNode; if (!(target instanceof Element)) { - return null + return null; } } - return target + return target; } /** @@ -896,19 +957,19 @@ export function getTarget(event: Event | undefined = window.event): Element | nu * @returns True if parent is an ancestor of the element, false otherwise. */ export function hasParent(element: Element, parent: Element): boolean { - let elem: Node = element + let elem: Node = element; while (elem) { if (elem === parent) { - return true + return true; } else if (elem.parentNode) { - elem = elem.parentNode + elem = elem.parentNode; } else { - return false + return false; } } - return false + return false; } export const option = { @@ -921,15 +982,15 @@ export const option = { * @returns Corresponding boolean value, if none then the default value, if none then null. */ asBoolean(value: unknown, defaultValue?: boolean): boolean | null { - if (typeof value == 'function') { - value = value() + if (typeof value == "function") { + value = value(); } if (value != null) { - return value != false + return value != false; } - return defaultValue || null + return defaultValue || null; }, /** @@ -941,15 +1002,15 @@ export const option = { * @returns Corresponding **boxed** number value, if none then the default value, if none then null. */ asNumber(value: unknown, defaultValue?: number): number | null { - if (typeof value == 'function') { - value = value() + if (typeof value == "function") { + value = value(); } if (value != null) { - return Number(value) || defaultValue || null + return Number(value) || defaultValue || null; } - return defaultValue || null + return defaultValue || null; }, /** @@ -961,15 +1022,15 @@ export const option = { * @returns Corresponding **boxed** string value, if none then the default value, if none then null. */ asString(value: unknown, defaultValue?: string): string | null { - if (typeof value == 'function') { - value = value() + if (typeof value == "function") { + value = value(); } if (value != null) { - return String(value) + return String(value); } - return defaultValue || null + return defaultValue || null; }, /** @@ -981,16 +1042,16 @@ export const option = { * @returns Corresponding string value (number + 'px'), if none then the default value, if none then null. */ asSize(value: unknown, defaultValue?: string): string | null { - if (typeof value == 'function') { - value = value() + if (typeof value == "function") { + value = value(); } if (isString(value)) { - return value + return value; } else if (isNumber(value)) { - return value + 'px' + return value + "px"; } else { - return defaultValue || null + return defaultValue || null; } }, @@ -1002,14 +1063,17 @@ export const option = { * * @returns The DOM Element, if none then the default value, if none then null. */ - asElement(value: T | (() => T | undefined) | undefined, defaultValue: T): T | null { - if (typeof value == 'function') { - value = value() + asElement( + value: T | (() => T | undefined) | undefined, + defaultValue: T + ): T | null { + if (typeof value == "function") { + value = value(); } - return value || defaultValue || null - }, -} + return value || defaultValue || null; + } +}; /** * Convert hex color string into RGB color object. @@ -1020,30 +1084,30 @@ export const option = { * @returns RGB color object. */ export function hexToRGB(hex: string): RGB | null { - let result + let result; switch (hex.length) { case 3: case 4: - result = shortHexRE.exec(hex) + result = shortHexRE.exec(hex); return result ? { r: parseInt(result[1] + result[1], 16), g: parseInt(result[2] + result[2], 16), - b: parseInt(result[3] + result[3], 16), + b: parseInt(result[3] + result[3], 16) } - : null + : null; case 6: case 7: - result = fullHexRE.exec(hex) + result = fullHexRE.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), - b: parseInt(result[3], 16), + b: parseInt(result[3], 16) } - : null + : null; default: - return null + return null; } } @@ -1056,20 +1120,20 @@ export function hexToRGB(hex: string): RGB | null { * @returns RGBA string, for example 'rgba(255, 0, 127, 0.3)'. */ export function overrideOpacity(color: string, opacity: number): string { - if (color.indexOf('rgba') !== -1) { - return color - } else if (color.indexOf('rgb') !== -1) { + if (color.indexOf("rgba") !== -1) { + return color; + } else if (color.indexOf("rgb") !== -1) { const rgb = color - .substr(color.indexOf('(') + 1) - .replace(')', '') - .split(',') - return 'rgba(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ',' + opacity + ')' + .substr(color.indexOf("(") + 1) + .replace(")", "") + .split(","); + return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + opacity + ")"; } else { - const rgb = hexToRGB(color) + const rgb = hexToRGB(color); if (rgb == null) { - return color + return color; } else { - return 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + opacity + ')' + return "rgba(" + rgb.r + "," + rgb.g + "," + rgb.b + "," + opacity + ")"; } } } @@ -1084,42 +1148,47 @@ export function overrideOpacity(color: string, opacity: number): string { * @returns Hex color string (for example: '#0acdc0'). */ export function RGBToHex(red: number, green: number, blue: number): string { - return '#' + ((1 << 24) + (red << 16) + (green << 8) + blue).toString(16).slice(1) + return ( + "#" + ((1 << 24) + (red << 16) + (green << 8) + blue).toString(16).slice(1) + ); } export interface ColorObject { - background?: string - border?: string + background?: string; + border?: string; hover?: | string | { - border?: string - background?: string - } + border?: string; + background?: string; + }; highlight?: | string | { - border?: string - background?: string - } + border?: string; + background?: string; + }; } export interface FullColorObject { - background: string - border: string + background: string; + border: string; hover: { - border: string - background: string - } + border: string; + background: string; + }; highlight: { - border: string - background: string - } + border: string; + background: string; + }; } -export function parseColor(inputColor: string): FullColorObject -export function parseColor(inputColor: FullColorObject): FullColorObject -export function parseColor(inputColor: ColorObject): ColorObject -export function parseColor(inputColor: ColorObject, defaultColor: FullColorObject): FullColorObject +export function parseColor(inputColor: string): FullColorObject; +export function parseColor(inputColor: FullColorObject): FullColorObject; +export function parseColor(inputColor: ColorObject): ColorObject; +export function parseColor( + inputColor: ColorObject, + defaultColor: FullColorObject +): FullColorObject; /** * Parse a color property into an object with border, background, and highlight colors * @@ -1133,56 +1202,64 @@ export function parseColor( defaultColor?: FullColorObject ): ColorObject | FullColorObject { if (isString(inputColor)) { - let colorStr: string = inputColor + let colorStr: string = inputColor; if (isValidRGB(colorStr)) { const rgb = colorStr .substr(4) .substr(0, colorStr.length - 5) - .split(',') + .split(",") .map(function(value): number { - return parseInt(value) - }) - colorStr = RGBToHex(rgb[0], rgb[1], rgb[2]) + return parseInt(value); + }); + colorStr = RGBToHex(rgb[0], rgb[1], rgb[2]); } if (isValidHex(colorStr) === true) { - const hsv = hexToHSV(colorStr) + const hsv = hexToHSV(colorStr); const lighterColorHSV = { h: hsv.h, s: hsv.s * 0.8, - v: Math.min(1, hsv.v * 1.02), - } + v: Math.min(1, hsv.v * 1.02) + }; const darkerColorHSV = { h: hsv.h, s: Math.min(1, hsv.s * 1.25), - v: hsv.v * 0.8, - } - const darkerColorHex = HSVToHex(darkerColorHSV.h, darkerColorHSV.s, darkerColorHSV.v) - const lighterColorHex = HSVToHex(lighterColorHSV.h, lighterColorHSV.s, lighterColorHSV.v) + v: hsv.v * 0.8 + }; + const darkerColorHex = HSVToHex( + darkerColorHSV.h, + darkerColorHSV.s, + darkerColorHSV.v + ); + const lighterColorHex = HSVToHex( + lighterColorHSV.h, + lighterColorHSV.s, + lighterColorHSV.v + ); return { background: colorStr, border: darkerColorHex, highlight: { background: lighterColorHex, - border: darkerColorHex, + border: darkerColorHex }, hover: { background: lighterColorHex, - border: darkerColorHex, - }, - } + border: darkerColorHex + } + }; } else { return { background: colorStr, border: colorStr, highlight: { background: colorStr, - border: colorStr, + border: colorStr }, hover: { background: colorStr, - border: colorStr, - }, - } + border: colorStr + } + }; } } else { if (defaultColor) { @@ -1192,24 +1269,31 @@ export function parseColor( highlight: isString(inputColor.highlight) ? { border: inputColor.highlight, - background: inputColor.highlight, + background: inputColor.highlight } : { background: - (inputColor.highlight && inputColor.highlight.background) || defaultColor.highlight.background, - border: (inputColor.highlight && inputColor.highlight.border) || defaultColor.highlight.border, + (inputColor.highlight && inputColor.highlight.background) || + defaultColor.highlight.background, + border: + (inputColor.highlight && inputColor.highlight.border) || + defaultColor.highlight.border }, hover: isString(inputColor.hover) ? { border: inputColor.hover, - background: inputColor.hover, + background: inputColor.hover } : { - border: (inputColor.hover && inputColor.hover.border) || defaultColor.hover.border, - background: (inputColor.hover && inputColor.hover.background) || defaultColor.hover.background, - }, - } - return color + border: + (inputColor.hover && inputColor.hover.border) || + defaultColor.hover.border, + background: + (inputColor.hover && inputColor.hover.background) || + defaultColor.hover.background + } + }; + return color; } else { const color: ColorObject = { background: inputColor.background || undefined, @@ -1217,23 +1301,29 @@ export function parseColor( highlight: isString(inputColor.highlight) ? { border: inputColor.highlight, - background: inputColor.highlight, + background: inputColor.highlight } : { - background: (inputColor.highlight && inputColor.highlight.background) || undefined, - border: (inputColor.highlight && inputColor.highlight.border) || undefined, + background: + (inputColor.highlight && inputColor.highlight.background) || + undefined, + border: + (inputColor.highlight && inputColor.highlight.border) || + undefined }, hover: isString(inputColor.hover) ? { border: inputColor.hover, - background: inputColor.hover, + background: inputColor.hover } : { - border: (inputColor.hover && inputColor.hover.border) || undefined, - background: (inputColor.hover && inputColor.hover.background) || undefined, - }, - } - return color + border: + (inputColor.hover && inputColor.hover.border) || undefined, + background: + (inputColor.hover && inputColor.hover.background) || undefined + } + }; + return color; } } } @@ -1249,55 +1339,56 @@ export function parseColor( * @returns HSV color object. */ export function RGBToHSV(red: number, green: number, blue: number): HSV { - red = red / 255 - green = green / 255 - blue = blue / 255 - const minRGB = Math.min(red, Math.min(green, blue)) - const maxRGB = Math.max(red, Math.max(green, blue)) + red = red / 255; + green = green / 255; + blue = blue / 255; + const minRGB = Math.min(red, Math.min(green, blue)); + const maxRGB = Math.max(red, Math.max(green, blue)); // Black-gray-white if (minRGB === maxRGB) { - return { h: 0, s: 0, v: minRGB } + return { h: 0, s: 0, v: minRGB }; } // Colors other than black-gray-white: - const d = red === minRGB ? green - blue : blue === minRGB ? red - green : blue - red - const h = red === minRGB ? 3 : blue === minRGB ? 1 : 5 - const hue = (60 * (h - d / (maxRGB - minRGB))) / 360 - const saturation = (maxRGB - minRGB) / maxRGB - const value = maxRGB - return { h: hue, s: saturation, v: value } + const d = + red === minRGB ? green - blue : blue === minRGB ? red - green : blue - red; + const h = red === minRGB ? 3 : blue === minRGB ? 1 : 5; + const hue = (60 * (h - d / (maxRGB - minRGB))) / 360; + const saturation = (maxRGB - minRGB) / maxRGB; + const value = maxRGB; + return { h: hue, s: saturation, v: value }; } interface CSSStyles { - [key: string]: string + [key: string]: string; } const cssUtil = { // split a string with css styles into an object with key/values split(cssText: string): CSSStyles { - const styles: CSSStyles = {} - - cssText.split(';').forEach((style): void => { - if (style.trim() != '') { - const parts = style.split(':') - const key = parts[0].trim() - const value = parts[1].trim() - styles[key] = value + const styles: CSSStyles = {}; + + cssText.split(";").forEach((style): void => { + if (style.trim() != "") { + const parts = style.split(":"); + const key = parts[0].trim(); + const value = parts[1].trim(); + styles[key] = value; } - }) + }); - return styles + return styles; }, // build a css text string from an object with key/values join(styles: CSSStyles): string { return Object.keys(styles) .map(function(key): string { - return key + ': ' + styles[key] + return key + ": " + styles[key]; }) - .join('; ') - }, -} + .join("; "); + } +}; /** * Append a string with css styles to an element @@ -1306,14 +1397,14 @@ const cssUtil = { * @param cssText - The styles to be appended. */ export function addCssText(element: HTMLElement, cssText: string): void { - const currentStyles = cssUtil.split(element.style.cssText) - const newStyles = cssUtil.split(cssText) + const currentStyles = cssUtil.split(element.style.cssText); + const newStyles = cssUtil.split(cssText); const styles = { ...currentStyles, - ...newStyles, - } + ...newStyles + }; - element.style.cssText = cssUtil.join(styles) + element.style.cssText = cssUtil.join(styles); } /** @@ -1323,16 +1414,16 @@ export function addCssText(element: HTMLElement, cssText: string): void { * @param cssText - The styles to be removed. */ export function removeCssText(element: HTMLElement, cssText: string): void { - const styles = cssUtil.split(element.style.cssText) - const removeStyles = cssUtil.split(cssText) + const styles = cssUtil.split(element.style.cssText); + const removeStyles = cssUtil.split(cssText); for (const key in removeStyles) { if (Object.prototype.hasOwnProperty.call(removeStyles, key)) { - delete styles[key] + delete styles[key]; } } - element.style.cssText = cssUtil.join(styles) + element.style.cssText = cssUtil.join(styles); } /** @@ -1346,42 +1437,42 @@ export function removeCssText(element: HTMLElement, cssText: string): void { * @returns RGB color object. */ export function HSVToRGB(h: number, s: number, v: number): RGB { - let r: undefined | number - let g: undefined | number - let b: undefined | number + let r: undefined | number; + let g: undefined | number; + let b: undefined | number; - const i = Math.floor(h * 6) - const f = h * 6 - i - const p = v * (1 - s) - const q = v * (1 - f * s) - const t = v * (1 - (1 - f) * s) + const i = Math.floor(h * 6); + const f = h * 6 - i; + const p = v * (1 - s); + const q = v * (1 - f * s); + const t = v * (1 - (1 - f) * s); switch (i % 6) { case 0: - ;(r = v), (g = t), (b = p) - break + (r = v), (g = t), (b = p); + break; case 1: - ;(r = q), (g = v), (b = p) - break + (r = q), (g = v), (b = p); + break; case 2: - ;(r = p), (g = v), (b = t) - break + (r = p), (g = v), (b = t); + break; case 3: - ;(r = p), (g = q), (b = v) - break + (r = p), (g = q), (b = v); + break; case 4: - ;(r = t), (g = p), (b = v) - break + (r = t), (g = p), (b = v); + break; case 5: - ;(r = v), (g = p), (b = q) - break + (r = v), (g = p), (b = q); + break; } return { r: Math.floor((r as number) * 255), g: Math.floor((g as number) * 255), - b: Math.floor((b as number) * 255), - } + b: Math.floor((b as number) * 255) + }; } /** @@ -1394,8 +1485,8 @@ export function HSVToRGB(h: number, s: number, v: number): RGB { * @returns Hex color string. */ export function HSVToHex(h: number, s: number, v: number): string { - const rgb = HSVToRGB(h, s, v) - return RGBToHex(rgb.r, rgb.g, rgb.b) + const rgb = HSVToRGB(h, s, v); + return RGBToHex(rgb.r, rgb.g, rgb.b); } /** @@ -1406,11 +1497,11 @@ export function HSVToHex(h: number, s: number, v: number): string { * @returns HSV color object. */ export function hexToHSV(hex: string): HSV { - const rgb = hexToRGB(hex) + const rgb = hexToRGB(hex); if (!rgb) { - throw new TypeError(`'${hex}' is not a valid color.`) + throw new TypeError(`'${hex}' is not a valid color.`); } - return RGBToHSV(rgb.r, rgb.g, rgb.b) + return RGBToHSV(rgb.r, rgb.g, rgb.b); } /** @@ -1421,8 +1512,8 @@ export function hexToHSV(hex: string): HSV { * @returns True if the string is valid, false otherwise. */ export function isValidHex(hex: string): boolean { - const isOk = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(hex) - return isOk + const isOk = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(hex); + return isOk; } /** @@ -1433,7 +1524,7 @@ export function isValidHex(hex: string): boolean { * @returns True if the string is valid, false otherwise. */ export function isValidRGB(rgb: string): boolean { - return rgbRE.test(rgb) + return rgbRE.test(rgb); } /** @@ -1444,7 +1535,7 @@ export function isValidRGB(rgb: string): boolean { * @returns True if the string is valid, false otherwise. */ export function isValidRGBA(rgba: string): boolean { - return rgbaRE.test(rgba) + return rgbaRE.test(rgba); } /** @@ -1460,24 +1551,24 @@ export function selectiveBridgeObject( fields: F[], referenceObject: Record ): Record | null { - if (referenceObject !== null && typeof referenceObject === 'object') { + if (referenceObject !== null && typeof referenceObject === "object") { // !!! typeof null === 'object' - const objectTo = Object.create(referenceObject) + const objectTo = Object.create(referenceObject); for (let i = 0; i < fields.length; i++) { if (Object.prototype.hasOwnProperty.call(referenceObject, fields[i])) { - if (typeof referenceObject[fields[i]] == 'object') { - objectTo[fields[i]] = bridgeObject(referenceObject[fields[i]]) + if (typeof referenceObject[fields[i]] == "object") { + objectTo[fields[i]] = bridgeObject(referenceObject[fields[i]]); } } } - return objectTo + return objectTo; } else { - return null + return null; } } -export function bridgeObject(referenceObject: T): T -export function bridgeObject(referenceObject: T): null +export function bridgeObject(referenceObject: T): T; +export function bridgeObject(referenceObject: T): null; /** * This recursively redirects the prototype of JSON objects to the referenceObject. * This is used for default options. @@ -1486,26 +1577,28 @@ export function bridgeObject(referenceObject: T): null * * @returns The Element if the referenceObject is an Element, or a new object inheriting from the referenceObject. */ -export function bridgeObject(referenceObject: T): T | null { - if (referenceObject === null || typeof referenceObject !== 'object') { - return null +export function bridgeObject( + referenceObject: T +): T | null { + if (referenceObject === null || typeof referenceObject !== "object") { + return null; } if (referenceObject instanceof Element) { // Avoid bridging DOM objects - return referenceObject + return referenceObject; } - const objectTo = Object.create(referenceObject) + const objectTo = Object.create(referenceObject); for (const i in referenceObject) { if (Object.prototype.hasOwnProperty.call(referenceObject, i)) { - if (typeof (referenceObject as any)[i] == 'object') { - objectTo[i] = bridgeObject((referenceObject as any)[i]) + if (typeof (referenceObject as any)[i] == "object") { + objectTo[i] = bridgeObject((referenceObject as any)[i]); } } } - return objectTo + return objectTo; } /** @@ -1518,14 +1611,14 @@ export function bridgeObject(referenceObject: T): T | n */ export function insertSort(a: T[], compare: (a: T, b: T) => number): T[] { for (let i = 0; i < a.length; i++) { - const k = a[i] - let j + const k = a[i]; + let j; for (j = i; j > 0 && compare(k, a[j - 1]) < 0; j--) { - a[j] = a[j - 1] + a[j] = a[j - 1]; } - a[j] = k + a[j] = k; } - return a + return a; } /** @@ -1541,41 +1634,46 @@ export function insertSort(a: T[], compare: (a: T, b: T) => number): T[] { * @param option - Option key in the options argument. * @param globalOptions - Global options, passed in to determine value of option 'enabled'. */ -export function mergeOptions(mergeTarget: any, options: any, option: string, globalOptions: any = {}): void { +export function mergeOptions( + mergeTarget: any, + options: any, + option: string, + globalOptions: any = {} +): void { // Local helpers const isPresent = function(obj: any): boolean { - return obj !== null && obj !== undefined - } + return obj !== null && obj !== undefined; + }; const isObject = function(obj: unknown): boolean { - return obj !== null && typeof obj === 'object' - } + return obj !== null && typeof obj === "object"; + }; // https://stackoverflow.com/a/34491287/1223531 const isEmpty = function(obj: object): obj is {} { for (const x in obj) { if (Object.prototype.hasOwnProperty.call(obj, x)) { - return false + return false; } } - return true - } + return true; + }; // Guards if (!isObject(mergeTarget)) { - throw new Error('Parameter mergeTarget must be an object') + throw new Error("Parameter mergeTarget must be an object"); } if (!isObject(options)) { - throw new Error('Parameter options must be an object') + throw new Error("Parameter options must be an object"); } if (!isPresent(option)) { - throw new Error('Parameter option must have a value') + throw new Error("Parameter option must have a value"); } if (!isObject(globalOptions)) { - throw new Error('Parameter globalOptions must be an object') + throw new Error("Parameter globalOptions must be an object"); } // @@ -1584,83 +1682,87 @@ export function mergeOptions(mergeTarget: any, options: any, option: string, glo // const doMerge = function(target: any, options: any, option: string): void { if (!isObject(target[option])) { - target[option] = {} + target[option] = {}; } - const src = options[option] - const dst = target[option] + const src = options[option]; + const dst = target[option]; for (const prop in src) { if (Object.prototype.hasOwnProperty.call(src, prop)) { - dst[prop] = src[prop] + dst[prop] = src[prop]; } } - } + }; // Local initialization - const srcOption = options[option] - const globalPassed = isObject(globalOptions) && !isEmpty(globalOptions) - const globalOption = globalPassed ? globalOptions[option] : undefined - const globalEnabled = globalOption ? globalOption.enabled : undefined + const srcOption = options[option]; + const globalPassed = isObject(globalOptions) && !isEmpty(globalOptions); + const globalOption = globalPassed ? globalOptions[option] : undefined; + const globalEnabled = globalOption ? globalOption.enabled : undefined; ///////////////////////////////////////// // Main routine ///////////////////////////////////////// if (srcOption === undefined) { - return // Nothing to do + return; // Nothing to do } - if (typeof srcOption === 'boolean') { + if (typeof srcOption === "boolean") { if (!isObject(mergeTarget[option])) { - mergeTarget[option] = {} + mergeTarget[option] = {}; } - mergeTarget[option].enabled = srcOption - return + mergeTarget[option].enabled = srcOption; + return; } if (srcOption === null && !isObject(mergeTarget[option])) { // If possible, explicit copy from globals if (isPresent(globalOption)) { - mergeTarget[option] = Object.create(globalOption) + mergeTarget[option] = Object.create(globalOption); } else { - return // Nothing to do + return; // Nothing to do } } if (!isObject(srcOption)) { - return + return; } // // Ensure that 'enabled' is properly set. It is required internally // Note that the value from options will always overwrite the existing value // - let enabled = true // default value + let enabled = true; // default value if (srcOption.enabled !== undefined) { - enabled = srcOption.enabled + enabled = srcOption.enabled; } else { // Take from globals, if present if (globalEnabled !== undefined) { - enabled = globalOption.enabled + enabled = globalOption.enabled; } } - doMerge(mergeTarget, options, option) - mergeTarget[option].enabled = enabled + doMerge(mergeTarget, options, option); + mergeTarget[option].enabled = enabled; } -export function binarySearchCustom( +export function binarySearchCustom< + O extends object, + K1 extends keyof O, + K2 extends keyof O[K1] +>( orderedItems: O[], comparator: (v: O[K1][K2]) => -1 | 0 | 1, field: K1, field2: K2 -): number +): number; export function binarySearchCustom( orderedItems: O[], comparator: (v: O[K1]) => -1 | 0 | 1, field: K1 -): number +): number; /** * This function does a binary search for a visible item in a sorted list. If we find a visible item, the code that uses * this function will then iterate in both directions over this sorted list to find all visible items. @@ -1678,33 +1780,33 @@ export function binarySearchCustom( field: string, field2?: string ): number { - const maxIterations = 10000 - let iteration = 0 - let low = 0 - let high = orderedItems.length - 1 + const maxIterations = 10000; + let iteration = 0; + let low = 0; + let high = orderedItems.length - 1; while (low <= high && iteration < maxIterations) { - const middle = Math.floor((low + high) / 2) + const middle = Math.floor((low + high) / 2); - const item = orderedItems[middle] - const value = field2 === undefined ? item[field] : item[field][field2] + const item = orderedItems[middle]; + const value = field2 === undefined ? item[field] : item[field][field2]; - const searchResult = comparator(value) + const searchResult = comparator(value); if (searchResult == 0) { // jihaa, found a visible item! - return middle + return middle; } else if (searchResult == -1) { // it is too small --> increase low - low = middle + 1 + low = middle + 1; } else { // it is too big --> decrease high - high = middle - 1 + high = middle - 1; } - iteration++ + iteration++; } - return -1 + return -1; } /** @@ -1724,56 +1826,65 @@ export function binarySearchValue( orderedItems: { [K in T]: number }[], target: number, field: T, - sidePreference: 'before' | 'after', + sidePreference: "before" | "after", comparator?: (a: number, b: number) => -1 | 0 | 1 ): number { - const maxIterations = 10000 - let iteration = 0 - let low = 0 - let high = orderedItems.length - 1 - let prevValue - let value - let nextValue - let middle + const maxIterations = 10000; + let iteration = 0; + let low = 0; + let high = orderedItems.length - 1; + let prevValue; + let value; + let nextValue; + let middle; comparator = comparator != undefined ? comparator : function(a: number, b: number): -1 | 0 | 1 { - return a == b ? 0 : a < b ? -1 : 1 - } + return a == b ? 0 : a < b ? -1 : 1; + }; while (low <= high && iteration < maxIterations) { // get a new guess - middle = Math.floor(0.5 * (high + low)) - prevValue = orderedItems[Math.max(0, middle - 1)][field] - value = orderedItems[middle][field] - nextValue = orderedItems[Math.min(orderedItems.length - 1, middle + 1)][field] + middle = Math.floor(0.5 * (high + low)); + prevValue = orderedItems[Math.max(0, middle - 1)][field]; + value = orderedItems[middle][field]; + nextValue = + orderedItems[Math.min(orderedItems.length - 1, middle + 1)][field]; if (comparator(value, target) == 0) { // we found the target - return middle - } else if (comparator(prevValue, target) < 0 && comparator(value, target) > 0) { + return middle; + } else if ( + comparator(prevValue, target) < 0 && + comparator(value, target) > 0 + ) { // target is in between of the previous and the current - return sidePreference == 'before' ? Math.max(0, middle - 1) : middle - } else if (comparator(value, target) < 0 && comparator(nextValue, target) > 0) { + return sidePreference == "before" ? Math.max(0, middle - 1) : middle; + } else if ( + comparator(value, target) < 0 && + comparator(nextValue, target) > 0 + ) { // target is in between of the current and the next - return sidePreference == 'before' ? middle : Math.min(orderedItems.length - 1, middle + 1) + return sidePreference == "before" + ? middle + : Math.min(orderedItems.length - 1, middle + 1); } else { // didnt find the target, we need to change our boundaries. if (comparator(value, target) < 0) { // it is too small --> increase low - low = middle + 1 + low = middle + 1; } else { // it is too big --> decrease high - high = middle - 1 + high = middle - 1; } } - iteration++ + iteration++; } // didnt find anything. Return -1. - return -1 + return -1; } /* @@ -1792,7 +1903,7 @@ export const easingFunctions = { * @returns Value at time t. */ linear(t: number): number { - return t + return t; }, /** @@ -1803,7 +1914,7 @@ export const easingFunctions = { * @returns Value at time t. */ easeInQuad(t: number): number { - return t * t + return t * t; }, /** @@ -1814,7 +1925,7 @@ export const easingFunctions = { * @returns Value at time t. */ easeOutQuad(t: number): number { - return t * (2 - t) + return t * (2 - t); }, /** @@ -1825,7 +1936,7 @@ export const easingFunctions = { * @returns Value at time t. */ easeInOutQuad(t: number): number { - return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t + return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t; }, /** @@ -1836,7 +1947,7 @@ export const easingFunctions = { * @returns Value at time t. */ easeInCubic(t: number): number { - return t * t * t + return t * t * t; }, /** @@ -1847,7 +1958,7 @@ export const easingFunctions = { * @returns Value at time t. */ easeOutCubic(t: number): number { - return --t * t * t + 1 + return --t * t * t + 1; }, /** @@ -1858,7 +1969,7 @@ export const easingFunctions = { * @returns Value at time t. */ easeInOutCubic(t: number): number { - return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1 + return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1; }, /** @@ -1869,7 +1980,7 @@ export const easingFunctions = { * @returns Value at time t. */ easeInQuart(t: number): number { - return t * t * t * t + return t * t * t * t; }, /** @@ -1880,7 +1991,7 @@ export const easingFunctions = { * @returns Value at time t. */ easeOutQuart(t: number): number { - return 1 - --t * t * t * t + return 1 - --t * t * t * t; }, /** @@ -1891,7 +2002,7 @@ export const easingFunctions = { * @returns Value at time t. */ easeInOutQuart(t: number): number { - return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t + return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t; }, /** @@ -1902,7 +2013,7 @@ export const easingFunctions = { * @returns Value at time t. */ easeInQuint(t: number): number { - return t * t * t * t * t + return t * t * t * t * t; }, /** @@ -1913,7 +2024,7 @@ export const easingFunctions = { * @returns Value at time t. */ easeOutQuint(t: number): number { - return 1 + --t * t * t * t * t + return 1 + --t * t * t * t * t; }, /** @@ -1924,9 +2035,9 @@ export const easingFunctions = { * @returns Value at time t. */ easeInOutQuint(t: number): number { - return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t - }, -} + return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t; + } +}; /** * Experimentaly compute the width of the scrollbar for this browser. @@ -1934,31 +2045,31 @@ export const easingFunctions = { * @returns The width in pixels. */ export function getScrollBarWidth(): number { - const inner = document.createElement('p') - inner.style.width = '100%' - inner.style.height = '200px' - - const outer = document.createElement('div') - outer.style.position = 'absolute' - outer.style.top = '0px' - outer.style.left = '0px' - outer.style.visibility = 'hidden' - outer.style.width = '200px' - outer.style.height = '150px' - outer.style.overflow = 'hidden' - outer.appendChild(inner) - - document.body.appendChild(outer) - const w1 = inner.offsetWidth - outer.style.overflow = 'scroll' - let w2 = inner.offsetWidth + const inner = document.createElement("p"); + inner.style.width = "100%"; + inner.style.height = "200px"; + + const outer = document.createElement("div"); + outer.style.position = "absolute"; + outer.style.top = "0px"; + outer.style.left = "0px"; + outer.style.visibility = "hidden"; + outer.style.width = "200px"; + outer.style.height = "150px"; + outer.style.overflow = "hidden"; + outer.appendChild(inner); + + document.body.appendChild(outer); + const w1 = inner.offsetWidth; + outer.style.overflow = "scroll"; + let w2 = inner.offsetWidth; if (w1 == w2) { - w2 = outer.clientWidth + w2 = outer.clientWidth; } - document.body.removeChild(outer) + document.body.removeChild(outer); - return w1 - w2 + return w1 - w2; } // @TODO: This doesn't work properly. @@ -1985,22 +2096,22 @@ export function getScrollBarWidth(): number { * @returns Value of the property with given accessors path from the first pile item where it's not undefined. */ export function topMost(pile: any, accessors: any): any { - let candidate + let candidate; if (!Array.isArray(accessors)) { - accessors = [accessors] + accessors = [accessors]; } for (const member of pile) { if (member) { - candidate = member[accessors[0]] + candidate = member[accessors[0]]; for (let i = 1; i < accessors.length; i++) { if (candidate) { - candidate = candidate[accessors[i]] + candidate = candidate[accessors[i]]; } } - if (typeof candidate !== 'undefined') { - break + if (typeof candidate !== "undefined") { + break; } } } - return candidate + return candidate; } diff --git a/test/add-class-name.test.ts b/test/add-class-name.test.ts index 59e34735..94aa5d60 100644 --- a/test/add-class-name.test.ts +++ b/test/add-class-name.test.ts @@ -1,22 +1,26 @@ -import { expect } from 'chai' +import { expect } from "chai"; -import { addClassName } from '../src' +import { addClassName } from "../src"; -describe('addClassName', function(): void { +describe("addClassName", function(): void { const inputs: { input: string; classes: string; expected: string }[] = [ - { input: 'a b c', classes: 'a c', expected: 'a b c' }, - { input: 'a b c', classes: 'd', expected: 'a b c d' }, - { input: 'c', classes: 'a b', expected: 'c a b' }, - { input: 'class-1 class-2', classes: 'class-3', expected: 'class-1 class-2 class-3' }, - ] + { input: "a b c", classes: "a c", expected: "a b c" }, + { input: "a b c", classes: "d", expected: "a b c d" }, + { input: "c", classes: "a b", expected: "c a b" }, + { + input: "class-1 class-2", + classes: "class-3", + expected: "class-1 class-2 class-3" + } + ]; inputs.forEach(({ input, classes, expected }): void => { it(`${input} + ${classes} = ${expected}`, function(): void { - const elem = { className: input } + const elem = { className: input }; - addClassName(elem as any, classes) + addClassName(elem as any, classes); - expect(elem.className).to.equal(expected) - }) - }) -}) + expect(elem.className).to.equal(expected); + }); + }); +}); diff --git a/test/add-remove-event-listener.test.ts b/test/add-remove-event-listener.test.ts index 90f30ea3..3a39fd3c 100644 --- a/test/add-remove-event-listener.test.ts +++ b/test/add-remove-event-listener.test.ts @@ -1,97 +1,117 @@ -import { assert, spy } from 'sinon' -import { deepFreeze } from './helpers' +import { assert, spy } from "sinon"; +import { deepFreeze } from "./helpers"; -import { addEventListener, removeEventListener } from '../src' +import { addEventListener, removeEventListener } from "../src"; -describe('*EventListener', function(): void { +describe("*EventListener", function(): void { beforeEach((): void => { - ;(global as any).navigator = { - userAgent: 'ECMAScript compliant browser', - } - }) + (global as any).navigator = { + userAgent: "ECMAScript compliant browser" + }; + }); afterEach((): void => { - delete (global as any).navigator - }) + delete (global as any).navigator; + }); - const eventListener = deepFreeze((): void => {}) - ;[ + const eventListener = deepFreeze((): void => {}); + [ { - method: 'addEventListener' as const, - methodIE: 'attachEvent' as const, - fn: addEventListener, + method: "addEventListener" as const, + methodIE: "attachEvent" as const, + fn: addEventListener }, { - method: 'removeEventListener' as const, - methodIE: 'detachEvent' as const, - fn: removeEventListener, - }, + method: "removeEventListener" as const, + methodIE: "detachEvent" as const, + fn: removeEventListener + } ].forEach(({ method, methodIE, fn }): void => { describe(method, function(): void { - describe('standard compliant', function(): void { - it('without use capture', function(): void { + describe("standard compliant", function(): void { + it("without use capture", function(): void { const elem = { [method]: spy(), - [methodIE]: spy(), - } + [methodIE]: spy() + }; - fn((elem as unknown) as HTMLDivElement, 'click', eventListener) + fn((elem as unknown) as HTMLDivElement, "click", eventListener); - assert.notCalled(elem[methodIE]) + assert.notCalled(elem[methodIE]); - assert.calledOnce(elem[method]) - assert.calledWithExactly(elem[method], 'click', eventListener, false) - }) + assert.calledOnce(elem[method]); + assert.calledWithExactly(elem[method], "click", eventListener, false); + }); - it('with use capture', function(): void { + it("with use capture", function(): void { const elem = { [method]: spy(), - [methodIE]: spy(), - } - - fn((elem as unknown) as HTMLDivElement, 'mousewheel', eventListener, true) - - assert.notCalled(elem[methodIE]) - - assert.calledOnce(elem[method]) - assert.calledWithExactly(elem[method], 'mousewheel', eventListener, true) - }) - }) - - describe('Firefox', function(): void { + [methodIE]: spy() + }; + + fn( + (elem as unknown) as HTMLDivElement, + "mousewheel", + eventListener, + true + ); + + assert.notCalled(elem[methodIE]); + + assert.calledOnce(elem[method]); + assert.calledWithExactly( + elem[method], + "mousewheel", + eventListener, + true + ); + }); + }); + + describe("Firefox", function(): void { beforeEach((): void => { - ;(global as any).navigator = { - userAgent: 'Firefox', - } - }) + (global as any).navigator = { + userAgent: "Firefox" + }; + }); afterEach((): void => { - delete (global as any).navigator - }) + delete (global as any).navigator; + }); - it('mousewheel event', function(): void { + it("mousewheel event", function(): void { const elem = { [method]: spy(), - [methodIE]: spy(), - } - - fn((elem as unknown) as HTMLDivElement, 'mousewheel', eventListener, true) - - assert.notCalled(elem[methodIE]) - - assert.calledOnce(elem[method]) - assert.calledWithExactly(elem[method], 'DOMMouseScroll', eventListener, true) - }) - }) - - it('IE', function(): void { + [methodIE]: spy() + }; + + fn( + (elem as unknown) as HTMLDivElement, + "mousewheel", + eventListener, + true + ); + + assert.notCalled(elem[methodIE]); + + assert.calledOnce(elem[method]); + assert.calledWithExactly( + elem[method], + "DOMMouseScroll", + eventListener, + true + ); + }); + }); + + it("IE", function(): void { const elem = { - [methodIE]: spy(), - } + [methodIE]: spy() + }; - fn((elem as unknown) as HTMLDivElement, 'click', eventListener, true) + fn((elem as unknown) as HTMLDivElement, "click", eventListener, true); - assert.calledOnce(elem[methodIE]) - assert.calledWithExactly(elem[methodIE], 'onclick', eventListener) - }) - }) - }) -}) + assert.calledOnce(elem[methodIE]); + assert.calledWithExactly(elem[methodIE], "onclick", eventListener); + }); + }); + }); +}); diff --git a/test/binary-search-custom.test.ts b/test/binary-search-custom.test.ts index 199b596d..82a3849e 100644 --- a/test/binary-search-custom.test.ts +++ b/test/binary-search-custom.test.ts @@ -1,10 +1,10 @@ -import { expect } from 'chai' -import { assert, mock } from 'sinon' -import { deepFreeze } from './helpers' +import { expect } from "chai"; +import { assert, mock } from "sinon"; +import { deepFreeze } from "./helpers"; -import { binarySearchCustom } from '../src' +import { binarySearchCustom } from "../src"; -describe('binarySearchCustom', function(): void { +describe("binarySearchCustom", function(): void { const orderedItems = deepFreeze([ { prop1: -79, nested: { prop2: -0.79 } }, { prop1: -27, nested: { prop2: -0.27 } }, @@ -21,79 +21,106 @@ describe('binarySearchCustom', function(): void { { prop1: 71, nested: { prop2: 0.71 } }, { prop1: 71, nested: { prop2: 0.71 } }, { prop1: 71, nested: { prop2: 0.71 } }, - { prop1: 87, nested: { prop2: 0.87 } }, - ]) - const comparatorFactory = (target: number): ((value: number) => -1 | 0 | 1) => (value: number): -1 | 0 | 1 => { + { prop1: 87, nested: { prop2: 0.87 } } + ]); + const comparatorFactory = ( + target: number + ): ((value: number) => -1 | 0 | 1) => (value: number): -1 | 0 | 1 => { if (value < target) { - return -1 + return -1; } else if (value > target) { - return 1 + return 1; } else { - return 0 + return 0; } - } + }; - describe('array[index][prop1]', function(): void { - it('comparator args', function(): void { - const bscMock = mock() - bscMock.returns(0) + describe("array[index][prop1]", function(): void { + it("comparator args", function(): void { + const bscMock = mock(); + bscMock.returns(0); - binarySearchCustom(orderedItems, bscMock, 'prop1') + binarySearchCustom(orderedItems, bscMock, "prop1"); - assert.calledOnce(bscMock) + assert.calledOnce(bscMock); expect( bscMock.getCall(0).args, - 'The comparator should receive the value retrieved from the array item using the passed property name.' + "The comparator should receive the value retrieved from the array item using the passed property name." ) .to.have.lengthOf(1) - .and.to.have.ownProperty('0') - .that.is.a('number') - }) + .and.to.have.ownProperty("0") + .that.is.a("number"); + }); - it('missing item', function(): void { - expect(binarySearchCustom(orderedItems, comparatorFactory(13), 'prop1')).to.equal(-1) - }) + it("missing item", function(): void { + expect( + binarySearchCustom(orderedItems, comparatorFactory(13), "prop1") + ).to.equal(-1); + }); - it('present item', function(): void { - expect(binarySearchCustom(orderedItems, comparatorFactory(28), 'prop1')).to.equal(6) - }) + it("present item", function(): void { + expect( + binarySearchCustom(orderedItems, comparatorFactory(28), "prop1") + ).to.equal(6); + }); - it('multiple equal items', function(): void { - expect(binarySearchCustom(orderedItems, comparatorFactory(71), 'prop1')) + it("multiple equal items", function(): void { + expect(binarySearchCustom(orderedItems, comparatorFactory(71), "prop1")) .to.be.at.least(11) - .and.at.most(14) - }) - }) + .and.at.most(14); + }); + }); - describe('array[index][prop1][prop2]', function(): void { - it('comparator args', function(): void { - const bscMock = mock() - bscMock.returns(0) + describe("array[index][prop1][prop2]", function(): void { + it("comparator args", function(): void { + const bscMock = mock(); + bscMock.returns(0); - binarySearchCustom(orderedItems, bscMock, 'nested', 'prop2') + binarySearchCustom(orderedItems, bscMock, "nested", "prop2"); - assert.calledOnce(bscMock) + assert.calledOnce(bscMock); expect( bscMock.getCall(0).args, - 'The comparator should receive the value retrieved from the array item using the passed property names.' + "The comparator should receive the value retrieved from the array item using the passed property names." ) .to.have.lengthOf(1) - .and.to.have.ownProperty('0') - .that.is.a('number') - }) + .and.to.have.ownProperty("0") + .that.is.a("number"); + }); - it('missing item', function(): void { - expect(binarySearchCustom(orderedItems, comparatorFactory(0.13), 'nested', 'prop2')).to.equal(-1) - }) + it("missing item", function(): void { + expect( + binarySearchCustom( + orderedItems, + comparatorFactory(0.13), + "nested", + "prop2" + ) + ).to.equal(-1); + }); - it('present item', function(): void { - expect(binarySearchCustom(orderedItems, comparatorFactory(0.28), 'nested', 'prop2')).to.equal(6) - }) + it("present item", function(): void { + expect( + binarySearchCustom( + orderedItems, + comparatorFactory(0.28), + "nested", + "prop2" + ) + ).to.equal(6); + }); - it('multiple equal items', function(): void { - expect(binarySearchCustom(orderedItems, comparatorFactory(0.71), 'nested', 'prop2')) + it("multiple equal items", function(): void { + expect( + binarySearchCustom( + orderedItems, + comparatorFactory(0.71), + "nested", + "prop2" + ) + ) .to.be.at.least(11) - .and.at.most(14) - }) - }) -}) + .and.at.most(14); + }); + }); +}); diff --git a/test/bridge-object.test.ts b/test/bridge-object.test.ts index 6693c6f1..b9e4411a 100644 --- a/test/bridge-object.test.ts +++ b/test/bridge-object.test.ts @@ -1,102 +1,113 @@ -import { expect } from 'chai' +import { expect } from "chai"; -import { bridgeObject } from '../src' +import { bridgeObject } from "../src"; -describe('bridgeObject', function(): void { - describe('Invalid input', function(): void { - ;[ +describe("bridgeObject", function(): void { + describe("Invalid input", function(): void { + [ null, 0, 7, true, false, - Symbol('This just shouldn‘t work.'), + Symbol("This just shouldn‘t work."), Number.POSITIVE_INFINITY, Number.NaN, - '', - 'Have a nice day!', + "", + "Have a nice day!" ].forEach((input): void => { - it(typeof input === 'symbol' ? 'Symbol' : JSON.stringify(input), function(): void { - expect(bridgeObject(input), 'Null should be returned for invalid input.').to.be.null - }) - }) - }) - - describe('Valid input', function(): void { + it( + typeof input === "symbol" ? "Symbol" : JSON.stringify(input), + function(): void { + expect( + bridgeObject(input), + "Null should be returned for invalid input." + ).to.be.null; + } + ); + }); + }); + + describe("Valid input", function(): void { // @TODO: Set up DOM objects for testing. - describe('Empty object', function(): void { - const object = {} - let bridgedObject: {} + describe("Empty object", function(): void { + const object = {}; + let bridgedObject: {}; - it('Bridge the object', function(): void { - bridgedObject = bridgeObject(object) - }) + it("Bridge the object", function(): void { + bridgedObject = bridgeObject(object); + }); - it('Bridged object shouldn‘t equal the original', function(): void { - expect(bridgedObject).to.not.equal(object) - }) + it("Bridged object shouldn‘t equal the original", function(): void { + expect(bridgedObject).to.not.equal(object); + }); - it('Bridged object should have the original as it‘s prototype', function(): void { - expect(Object.getPrototypeOf(bridgedObject)).to.equal(object) - }) + it("Bridged object should have the original as it‘s prototype", function(): void { + expect(Object.getPrototypeOf(bridgedObject)).to.equal(object); + }); - it('Bridged object should have no additional properies', function(): void { - expect(Object.keys(bridgedObject)).to.be.empty - }) - }) + it("Bridged object should have no additional properies", function(): void { + expect(Object.keys(bridgedObject)).to.be.empty; + }); + }); - describe('Nested objects', function(): void { - const o1 = {} - const o2 = {} - const o3 = {} - const o4 = {} + describe("Nested objects", function(): void { + const o1 = {}; + const o2 = {}; + const o3 = {}; + const o4 = {}; const object = { 1: o1, 2: { 2: o2 }, 3: { 3: { 3: o3 } }, - 4: { 4: { 4: { 4: o4 } } }, - } - let bridgedObject: typeof object - - it('Bridge the object', function(): void { - bridgedObject = bridgeObject(object) - }) - - it('Bridged object shouldn‘t equal the original', function(): void { - expect(bridgedObject).to.not.equal(object) - }) - - it('Bridged object should have the original as it‘s prototype', function(): void { - expect(Object.getPrototypeOf(bridgedObject)).to.equal(object) - }) - - it('Bridged object should have all original properties but no additional', function(): void { - expect(Object.keys(bridgedObject).sort()).to.deep.equal(['1', '2', '3', '4']) - }) - - describe('Objects should be deeply bridged', function(): void { - it('#1', function(): void { - expect(bridgedObject[1]).to.not.equal(o1) - expect(Object.getPrototypeOf(bridgedObject[1])).to.equal(o1) - }) - - it('#2', function(): void { - expect(bridgedObject[2][2]).to.not.equal(o2) - expect(Object.getPrototypeOf(bridgedObject[2][2])).to.equal(o2) - }) - - it('#3', function(): void { - expect(bridgedObject[3][3][3]).to.not.equal(o3) - expect(Object.getPrototypeOf(bridgedObject[3][3][3])).to.equal(o3) - }) - - it('#4', function(): void { - expect(bridgedObject[4][4][4][4]).to.not.equal(o4) - expect(Object.getPrototypeOf(bridgedObject[4][4][4][4])).to.equal(o4) - }) - }) - }) - }) -}) + 4: { 4: { 4: { 4: o4 } } } + }; + let bridgedObject: typeof object; + + it("Bridge the object", function(): void { + bridgedObject = bridgeObject(object); + }); + + it("Bridged object shouldn‘t equal the original", function(): void { + expect(bridgedObject).to.not.equal(object); + }); + + it("Bridged object should have the original as it‘s prototype", function(): void { + expect(Object.getPrototypeOf(bridgedObject)).to.equal(object); + }); + + it("Bridged object should have all original properties but no additional", function(): void { + expect(Object.keys(bridgedObject).sort()).to.deep.equal([ + "1", + "2", + "3", + "4" + ]); + }); + + describe("Objects should be deeply bridged", function(): void { + it("#1", function(): void { + expect(bridgedObject[1]).to.not.equal(o1); + expect(Object.getPrototypeOf(bridgedObject[1])).to.equal(o1); + }); + + it("#2", function(): void { + expect(bridgedObject[2][2]).to.not.equal(o2); + expect(Object.getPrototypeOf(bridgedObject[2][2])).to.equal(o2); + }); + + it("#3", function(): void { + expect(bridgedObject[3][3][3]).to.not.equal(o3); + expect(Object.getPrototypeOf(bridgedObject[3][3][3])).to.equal(o3); + }); + + it("#4", function(): void { + expect(bridgedObject[4][4][4][4]).to.not.equal(o4); + expect(Object.getPrototypeOf(bridgedObject[4][4][4][4])).to.equal(o4); + }); + }); + }); + }); +}); diff --git a/test/copy-and-extend-array.test.ts b/test/copy-and-extend-array.test.ts index 9c672335..9a826894 100644 --- a/test/copy-and-extend-array.test.ts +++ b/test/copy-and-extend-array.test.ts @@ -1,26 +1,42 @@ -import { expect } from 'chai' +import { expect } from "chai"; -import { copyAndExtendArray } from '../src' +import { copyAndExtendArray } from "../src"; -describe('copyAndExtendArray', function(): void { - it('number[]', function(): void { - const original = Object.freeze([-77, 14, 78]) - const addition = Object.freeze(0) - const copied = copyAndExtendArray(original, addition) +describe("copyAndExtendArray", function(): void { + it("number[]", function(): void { + const original = Object.freeze([-77, 14, 78]); + const addition = Object.freeze(0); + const copied = copyAndExtendArray(original, addition); - expect(copied, 'They should be different instances.').to.not.equal(original) - expect(copied, 'All elements should be in the new array and in the right order.').to.deep.equal([-77, 14, 78, 0]) - }) + expect(copied, "They should be different instances.").to.not.equal( + original + ); + expect( + copied, + "All elements should be in the new array and in the right order." + ).to.deep.equal([-77, 14, 78, 0]); + }); - it('object[]', function(): void { - const original = Object.freeze([Object.freeze({ hi: ':-)' }), Object.freeze({ bye: ':-(' })]) - const addition = Object.freeze({ hello: '☺' }) - const copied = copyAndExtendArray(original, addition) + it("object[]", function(): void { + const original = Object.freeze([ + Object.freeze({ hi: ":-)" }), + Object.freeze({ bye: ":-(" }) + ]); + const addition = Object.freeze({ hello: "☺" }); + const copied = copyAndExtendArray(original, addition); - expect(copied, 'They should be different instances.').to.not.equal(original) + expect(copied, "They should be different instances.").to.not.equal( + original + ); - expect(copied[0], 'The objects should be copied by reference').to.equal(original[0]) - expect(copied[1], 'The objects should be copied by reference').to.equal(original[1]) - expect(copied[2], 'The objects should be copied by reference').to.equal(addition) - }) -}) + expect(copied[0], "The objects should be copied by reference").to.equal( + original[0] + ); + expect(copied[1], "The objects should be copied by reference").to.equal( + original[1] + ); + expect(copied[2], "The objects should be copied by reference").to.equal( + addition + ); + }); +}); diff --git a/test/copy-array.test.ts b/test/copy-array.test.ts index fefd6e10..01528e97 100644 --- a/test/copy-array.test.ts +++ b/test/copy-array.test.ts @@ -1,22 +1,33 @@ -import { expect } from 'chai' +import { expect } from "chai"; -import { copyArray } from '../src' +import { copyArray } from "../src"; -describe('copyArray', function(): void { - it('number[]', function(): void { - const original = Object.freeze([-77, 14, 78]) - const copied = copyArray(original) +describe("copyArray", function(): void { + it("number[]", function(): void { + const original = Object.freeze([-77, 14, 78]); + const copied = copyArray(original); - expect(copied, 'Their content should be the same.').to.deep.equal(original) - expect(copied, 'They should be different instances.').to.not.equal(original) - }) + expect(copied, "Their content should be the same.").to.deep.equal(original); + expect(copied, "They should be different instances.").to.not.equal( + original + ); + }); - it('object[]', function(): void { - const original = Object.freeze([Object.freeze({ hi: ':-)' }), Object.freeze({ bye: ':-(' })]) - const copied = copyArray(original) + it("object[]", function(): void { + const original = Object.freeze([ + Object.freeze({ hi: ":-)" }), + Object.freeze({ bye: ":-(" }) + ]); + const copied = copyArray(original); - expect(copied, 'They should be different instances.').to.not.equal(original) - expect(copied[0], 'The objects should be copied by reference').to.equal(original[0]) - expect(copied[1], 'The objects should be copied by reference').to.equal(original[1]) - }) -}) + expect(copied, "They should be different instances.").to.not.equal( + original + ); + expect(copied[0], "The objects should be copied by reference").to.equal( + original[0] + ); + expect(copied[1], "The objects should be copied by reference").to.equal( + original[1] + ); + }); +}); diff --git a/test/deep-extend.test.ts b/test/deep-extend.test.ts index 5ab5520f..5cabc897 100644 --- a/test/deep-extend.test.ts +++ b/test/deep-extend.test.ts @@ -1,238 +1,271 @@ -import { expect } from 'chai' -import { deepFreeze } from './helpers' +import { expect } from "chai"; +import { deepFreeze } from "./helpers"; -import { deepExtend } from '../src' +import { deepExtend } from "../src"; -describe('deepExtend', function(): void { - it('nested strings', function(): void { +describe("deepExtend", function(): void { + it("nested strings", function(): void { const target = { - p1: 'p1 T', - p2: 'p2 T', + p1: "p1 T", + p2: "p2 T", p4: { - p4p1: 'p4p1 T', - p4p2: 'p4p2 T', + p4p1: "p4p1 T", + p4p2: "p4p2 T", p4p4: { - p4p4p1: 'p4p4p1 T', - p4p4p2: 'p4p4p2 T', - }, - }, - } + p4p4p1: "p4p4p1 T", + p4p4p2: "p4p4p2 T" + } + } + }; const source = deepFreeze({ - p2: 'p2 S', - p3: 'p3 S', + p2: "p2 S", + p3: "p3 S", p4: { - p4p2: 'p4p2 S', - p4p3: 'p4p3 S', + p4p2: "p4p2 S", + p4p3: "p4p3 S", p4p4: { - p4p4p2: 'p4p4p2 S', - p4p4p3: 'p4p4p3 S', - }, - }, - }) + p4p4p2: "p4p4p2 S", + p4p4p3: "p4p4p3 S" + } + } + }); - const merged = deepExtend(target, source) + const merged = deepExtend(target, source); - expect(merged, 'They should be the same instance.').to.equal(target) - expect(merged, 'All the properties should be deeply merged.').to.deep.equal({ - p1: 'p1 T', - p2: 'p2 S', - p3: 'p3 S', - p4: { - p4p1: 'p4p1 T', - p4p2: 'p4p2 S', - p4p3: 'p4p3 S', - p4p4: { - p4p4p1: 'p4p4p1 T', - p4p4p2: 'p4p4p2 S', - p4p4p3: 'p4p4p3 S', - }, - }, - }) - }) + expect(merged, "They should be the same instance.").to.equal(target); + expect(merged, "All the properties should be deeply merged.").to.deep.equal( + { + p1: "p1 T", + p2: "p2 S", + p3: "p3 S", + p4: { + p4p1: "p4p1 T", + p4p2: "p4p2 S", + p4p3: "p4p3 S", + p4p4: { + p4p4p1: "p4p4p1 T", + p4p4p2: "p4p4p2 S", + p4p4p3: "p4p4p3 S" + } + } + } + ); + }); - it('arrays', function(): void { + it("arrays", function(): void { const target = { arrays: { - p1: ['T', 1, true, 'T'], - p2: ['T', 1, true, 'T'], - }, - } + p1: ["T", 1, true, "T"], + p2: ["T", 1, true, "T"] + } + }; const source = deepFreeze({ arrays: { - p2: ['S', false, 0, 'S'], - p3: ['S', false, 0, 'S'], - }, - }) + p2: ["S", false, 0, "S"], + p3: ["S", false, 0, "S"] + } + }); - const merged = deepExtend(target, source) + const merged = deepExtend(target, source); - expect(merged, 'They should be the same instance.').to.equal(target) - expect(merged, 'Objects inheriting directly from Object should be deeply merged, arrays replaced.').to.deep.equal({ + expect(merged, "They should be the same instance.").to.equal(target); + expect( + merged, + "Objects inheriting directly from Object should be deeply merged, arrays replaced." + ).to.deep.equal({ arrays: { - p1: ['T', 1, true, 'T'], - p2: ['S', false, 0, 'S'], - p3: ['S', false, 0, 'S'], - }, - }) - - expect(merged.arrays.p2, 'Array should not be copied by reference.').to.not.equal(source.arrays.p2) - expect(merged.arrays.p2, 'Array should not be copied by reference.').to.not.equal(source.arrays.p2) - }) - - it('objects with other than Object prototype', function(): void { - const objectLiteral = { p3: 'S' } - const objectFromNull = Object.create(null) - const objectFromObject = Object.create(Object) - const objectFromMap = new Map() + p1: ["T", 1, true, "T"], + p2: ["S", false, 0, "S"], + p3: ["S", false, 0, "S"] + } + }); + + expect( + merged.arrays.p2, + "Array should not be copied by reference." + ).to.not.equal(source.arrays.p2); + expect( + merged.arrays.p2, + "Array should not be copied by reference." + ).to.not.equal(source.arrays.p2); + }); + + it("objects with other than Object prototype", function(): void { + const objectLiteral = { p3: "S" }; + const objectFromNull = Object.create(null); + const objectFromObject = Object.create(Object); + const objectFromMap = new Map(); const target = { objects: { - objectLiteral: { p1: 'T' }, - }, - } + objectLiteral: { p1: "T" } + } + }; const source = deepFreeze({ objects: { objectLiteral, objectFromNull, objectFromObject, - objectFromMap, - }, - }) + objectFromMap + } + }); - const merged = deepExtend(target, source) + const merged = deepExtend(target, source); - expect(merged, 'They should be the same instance.').to.equal(target) - expect(merged, 'Objects inheriting directly from Object should be deeply merged, other replaced.').to.deep.equal({ + expect(merged, "They should be the same instance.").to.equal(target); + expect( + merged, + "Objects inheriting directly from Object should be deeply merged, other replaced." + ).to.deep.equal({ objects: { objectLiteral: { - p1: 'T', - p3: 'S', + p1: "T", + p3: "S" }, objectFromNull: {}, objectFromObject: {}, - objectFromMap: new Map(), - }, - }) - - expect(merged.objects.objectLiteral, 'Object literal should not be copied by reference.').to.not.equal( - source.objects.objectLiteral - ) - expect(merged.objects.objectFromNull, 'Object created from null should be copied by reference.').to.equal( - source.objects.objectFromNull - ) - expect(merged.objects.objectFromObject, 'Object created from null should be copied by reference.').to.equal( - source.objects.objectFromObject - ) - expect(merged.objects.objectFromMap, 'Object created from null should be copied by reference.').to.equal( - source.objects.objectFromMap - ) - }) - - describe('inherited properties', function(): void { - it('ignored by default', function(): void { - const target = {} + objectFromMap: new Map() + } + }); + + expect( + merged.objects.objectLiteral, + "Object literal should not be copied by reference." + ).to.not.equal(source.objects.objectLiteral); + expect( + merged.objects.objectFromNull, + "Object created from null should be copied by reference." + ).to.equal(source.objects.objectFromNull); + expect( + merged.objects.objectFromObject, + "Object created from null should be copied by reference." + ).to.equal(source.objects.objectFromObject); + expect( + merged.objects.objectFromMap, + "Object created from null should be copied by reference." + ).to.equal(source.objects.objectFromMap); + }); + + describe("inherited properties", function(): void { + it("ignored by default", function(): void { + const target = {}; const source = deepFreeze( Object.create( deepFreeze({ - inherited: 'S', + inherited: "S" }) ) - ) + ); - const merged = deepExtend(target, source) + const merged = deepExtend(target, source); - expect(merged, 'They should be the same instance.').to.equal(target) - expect(merged, 'Inherited properties shouldn’t be inherited by default.').to.deep.equal({}) - }) + expect(merged, "They should be the same instance.").to.equal(target); + expect( + merged, + "Inherited properties shouldn’t be inherited by default." + ).to.deep.equal({}); + }); - it('inherited if enabled', function(): void { - const target = {} + it("inherited if enabled", function(): void { + const target = {}; const source = deepFreeze( Object.create( deepFreeze({ - inherited: 'S', + inherited: "S" }) ) - ) + ); - const merged = deepExtend(target, source, true) + const merged = deepExtend(target, source, true); - expect(merged, 'They should be the same instance.').to.equal(target) - expect(merged, 'Inherited properties should be inherited when enabled.').to.deep.equal({ - inherited: 'S', - }) - }) - }) + expect(merged, "They should be the same instance.").to.equal(target); + expect( + merged, + "Inherited properties should be inherited when enabled." + ).to.deep.equal({ + inherited: "S" + }); + }); + }); - describe('deletion', function(): void { - it('disabled', function(): void { + describe("deletion", function(): void { + it("disabled", function(): void { const target = { - p1: 'p1 T', - p2: 'p2 T', - } + p1: "p1 T", + p2: "p2 T" + }; const source = deepFreeze({ p2: null, - p3: null, - }) + p3: null + }); - const merged = deepExtend(target, source) + const merged = deepExtend(target, source); - expect(merged, 'They should be the same instance.').to.equal(target) - expect(merged, 'No properties should be deleted unless enabled.').to.deep.equal({ - p1: 'p1 T', + expect(merged, "They should be the same instance.").to.equal(target); + expect( + merged, + "No properties should be deleted unless enabled." + ).to.deep.equal({ + p1: "p1 T", p2: null, - p3: null, - }) - }) + p3: null + }); + }); - it('enabled', function(): void { + it("enabled", function(): void { const target = { - p1: 'p1 T', - p2: 'p2 T', - } + p1: "p1 T", + p2: "p2 T" + }; const source = deepFreeze({ p2: null, - p3: null, - }) + p3: null + }); - const merged = deepExtend(target, source, false, true) + const merged = deepExtend(target, source, false, true); - expect(merged, 'They should be the same instance.').to.equal(target) - expect(merged, 'Null properties from the source should delete matching properties in the target.').to.deep.equal({ - p1: 'p1 T', - p3: null, // TODO: This seems wrong. - }) - }) - }) + expect(merged, "They should be the same instance.").to.equal(target); + expect( + merged, + "Null properties from the source should delete matching properties in the target." + ).to.deep.equal({ + p1: "p1 T", + p3: null // TODO: This seems wrong. + }); + }); + }); - describe('edge cases', function(): void { - it('constructor property', function(): void { + describe("edge cases", function(): void { + it("constructor property", function(): void { const target = { object: { constructor: { - p1: 'T', - }, - }, - } + p1: "T" + } + } + }; const source = deepFreeze({ object: { constructor: { - p3: 'S', - }, - }, - }) + p3: "S" + } + } + }); - const merged = deepExtend(target, source) + const merged = deepExtend(target, source); - expect(merged, 'They should be the same instance.').to.equal(target) - expect(merged, 'All the properties should be deeply merged.').to.deep.equal({ + expect(merged, "They should be the same instance.").to.equal(target); + expect( + merged, + "All the properties should be deeply merged." + ).to.deep.equal({ object: { constructor: { - p1: 'T', - p3: 'S', - }, - }, - }) - }) - }) -}) + p1: "T", + p3: "S" + } + } + }); + }); + }); +}); diff --git a/test/for-each.test.ts b/test/for-each.test.ts index e02ae71d..6966ef74 100644 --- a/test/for-each.test.ts +++ b/test/for-each.test.ts @@ -1,36 +1,36 @@ -import { assert, spy } from 'sinon' +import { assert, spy } from "sinon"; -import { forEach } from '../src' +import { forEach } from "../src"; -describe('forEach', function(): void { - it('Array', function(): void { - const forEachSpy = spy() - const array = [-1, 0, 1] +describe("forEach", function(): void { + it("Array", function(): void { + const forEachSpy = spy(); + const array = [-1, 0, 1]; - forEach(array, forEachSpy) + forEach(array, forEachSpy); - assert.calledWithExactly(forEachSpy.firstCall, -1, 0, array) - assert.calledWithExactly(forEachSpy.secondCall, 0, 1, array) - assert.calledWithExactly(forEachSpy.thirdCall, 1, 2, array) - assert.callCount(forEachSpy, 3) - }) + assert.calledWithExactly(forEachSpy.firstCall, -1, 0, array); + assert.calledWithExactly(forEachSpy.secondCall, 0, 1, array); + assert.calledWithExactly(forEachSpy.thirdCall, 1, 2, array); + assert.callCount(forEachSpy, 3); + }); - it('Object', function(): void { - const forEachSpy = spy() + it("Object", function(): void { + const forEachSpy = spy(); const objectProto = { - ignore: 'me', - } - const object = Object.create(objectProto) - object.a = -1 - object.b = 0 - object.c = 1 + ignore: "me" + }; + const object = Object.create(objectProto); + object.a = -1; + object.b = 0; + object.c = 1; - forEach(object, forEachSpy) + forEach(object, forEachSpy); - assert.calledWithExactly(forEachSpy, -1, 'a', object) - assert.calledWithExactly(forEachSpy, 0, 'b', object) - assert.calledWithExactly(forEachSpy, 1, 'c', object) - assert.neverCalledWith(forEachSpy, 'me', 'ignore', object) - assert.callCount(forEachSpy, 3) - }) -}) + assert.calledWithExactly(forEachSpy, -1, "a", object); + assert.calledWithExactly(forEachSpy, 0, "b", object); + assert.calledWithExactly(forEachSpy, 1, "c", object); + assert.neverCalledWith(forEachSpy, "me", "ignore", object); + assert.callCount(forEachSpy, 3); + }); +}); diff --git a/test/get-absolute.test.ts b/test/get-absolute.test.ts index 57c927e3..b24d7e95 100644 --- a/test/get-absolute.test.ts +++ b/test/get-absolute.test.ts @@ -1,26 +1,26 @@ -import { expect } from 'chai' -import { stub } from 'sinon' +import { expect } from "chai"; +import { stub } from "sinon"; -import { getAbsoluteLeft, getAbsoluteRight, getAbsoluteTop } from '../src' +import { getAbsoluteLeft, getAbsoluteRight, getAbsoluteTop } from "../src"; -describe('getAbsolute*', function(): void { - const elem = { getBoundingClientRect: stub() } +describe("getAbsolute*", function(): void { + const elem = { getBoundingClientRect: stub() }; elem.getBoundingClientRect.returns({ top: 1, right: 2, bottom: 3, - left: 4, - }) + left: 4 + }); - it('getAbsoluteTop', function(): void { - expect(getAbsoluteTop(elem as any)).to.equal(1) - }) + it("getAbsoluteTop", function(): void { + expect(getAbsoluteTop(elem as any)).to.equal(1); + }); - it('getAbsoluteRight', function(): void { - expect(getAbsoluteRight(elem as any)).to.equal(2) - }) + it("getAbsoluteRight", function(): void { + expect(getAbsoluteRight(elem as any)).to.equal(2); + }); - it('getAbsoluteLeft', function(): void { - expect(getAbsoluteLeft(elem as any)).to.equal(4) - }) -}) + it("getAbsoluteLeft", function(): void { + expect(getAbsoluteLeft(elem as any)).to.equal(4); + }); +}); diff --git a/test/helpers/index.ts b/test/helpers/index.ts index 05a9fcca..6414360a 100644 --- a/test/helpers/index.ts +++ b/test/helpers/index.ts @@ -12,8 +12,11 @@ * * @returns The frozen object (the same instance as object param). */ -export function deepFreeze(object: T, freeze: (object: any) => any = Object.freeze.bind(Object)): T { - const alreadyFrozen = new Set() +export function deepFreeze( + object: T, + freeze: (object: any) => any = Object.freeze.bind(Object) +): T { + const alreadyFrozen = new Set(); /** * Recursivelly freezes objects using alreadyFrozen to prevent infinite cycles. @@ -26,25 +29,25 @@ export function deepFreeze(object: T, freeze: (object: any) => // Prevent double freezing (could lead to stack overflow due to an infinite cycle) // Object.isFrozen is not used here because frozen objects can have unfrozen objects in their properties. if (alreadyFrozen.has(object)) { - return object + return object; } - alreadyFrozen.add(object) + alreadyFrozen.add(object); // Retrieve the property names defined on object - const names = Object.getOwnPropertyNames(object) + const names = Object.getOwnPropertyNames(object); // Freeze properties before freezing the object for (const name of names) { - const prop = object[name] - if (prop && typeof prop === 'object') { - recursivelyFreeze(prop) + const prop = object[name]; + if (prop && typeof prop === "object") { + recursivelyFreeze(prop); } else { - freeze(prop) + freeze(prop); } } - return freeze(object) + return freeze(object); } - return recursivelyFreeze(object) + return recursivelyFreeze(object); } diff --git a/test/hex-to-rgb.test.ts b/test/hex-to-rgb.test.ts index 96ed7595..2b14d4f2 100644 --- a/test/hex-to-rgb.test.ts +++ b/test/hex-to-rgb.test.ts @@ -1,23 +1,26 @@ -import { expect } from 'chai' +import { expect } from "chai"; -import { hexToRGB, RGB } from '../src' +import { hexToRGB, RGB } from "../src"; -describe('hexToRGB', function(): void { +describe("hexToRGB", function(): void { const valid = [ - { color: '#000000', expected: { r: 0x00, g: 0x00, b: 0x00 } }, - { color: '#0acdc0', expected: { r: 0x0a, g: 0xcd, b: 0xc0 } }, - { color: '#AC00DC', expected: { r: 0xac, g: 0x00, b: 0xdc } }, - { color: '#09afAF', expected: { r: 0x09, g: 0xaf, b: 0xaf } }, - { color: '#000', expected: { r: 0x00, g: 0x00, b: 0x00 } }, - { color: '#0ac', expected: { r: 0x00, g: 0xaa, b: 0xcc } }, - { color: '#0DC', expected: { r: 0x00, g: 0xdd, b: 0xcc } }, - { color: '#09a', expected: { r: 0x00, g: 0x99, b: 0xaa } }, - { color: '#fAF', expected: { r: 0xff, g: 0xaa, b: 0xff } }, - ] + { color: "#000000", expected: { r: 0x00, g: 0x00, b: 0x00 } }, + { color: "#0acdc0", expected: { r: 0x0a, g: 0xcd, b: 0xc0 } }, + { color: "#AC00DC", expected: { r: 0xac, g: 0x00, b: 0xdc } }, + { color: "#09afAF", expected: { r: 0x09, g: 0xaf, b: 0xaf } }, + { color: "#000", expected: { r: 0x00, g: 0x00, b: 0x00 } }, + { color: "#0ac", expected: { r: 0x00, g: 0xaa, b: 0xcc } }, + { color: "#0DC", expected: { r: 0x00, g: 0xdd, b: 0xcc } }, + { color: "#09a", expected: { r: 0x00, g: 0x99, b: 0xaa } }, + { color: "#fAF", expected: { r: 0xff, g: 0xaa, b: 0xff } } + ]; valid.push( // without # - ...valid.map(({ color, expected }): { color: string; expected: RGB } => ({ color: color.slice(1), expected })) - ) + ...valid.map(({ color, expected }): { color: string; expected: RGB } => ({ + color: color.slice(1), + expected + })) + ); const invalid = [ // 5 or 2 digits @@ -25,38 +28,38 @@ describe('hexToRGB', function(): void { // 4 or 1 digit ...valid.map(({ color }): string => color.slice(0, -2)), // 7 or 4 digits - ...valid.map(({ color }): string => color + '0'), + ...valid.map(({ color }): string => color + "0"), // 8 or 5 digits - ...valid.map(({ color }): string => color + 'Fa'), - ' #000000', - ' ', - '##abc', - '#000 ', - '#ABC is a color', - '#abc-ef', - '#Ř0AABB', - '', - '0', - 'false', - 'garbage', - 'orange', - 'the color is #00AAAA', - 'true', - ] + ...valid.map(({ color }): string => color + "Fa"), + " #000000", + " ", + "##abc", + "#000 ", + "#ABC is a color", + "#abc-ef", + "#Ř0AABB", + "", + "0", + "false", + "garbage", + "orange", + "the color is #00AAAA", + "true" + ]; - describe('Valid', function(): void { + describe("Valid", function(): void { valid.forEach(({ color, expected }): void => { it(color, function(): void { - expect(hexToRGB(color)).to.be.deep.equal(expected) - }) - }) - }) + expect(hexToRGB(color)).to.be.deep.equal(expected); + }); + }); + }); - describe('Invalid', function(): void { + describe("Invalid", function(): void { invalid.forEach((color): void => { it(color, function(): void { - expect(hexToRGB(color)).to.be.null - }) - }) - }) -}) + expect(hexToRGB(color)).to.be.null; + }); + }); + }); +}); diff --git a/test/hsv-to-rgb.test.ts b/test/hsv-to-rgb.test.ts index cc26202f..597a12f5 100644 --- a/test/hsv-to-rgb.test.ts +++ b/test/hsv-to-rgb.test.ts @@ -1,8 +1,8 @@ -import { expect } from 'chai' +import { expect } from "chai"; -import { HSVToRGB, RGB } from '../src' +import { HSVToRGB, RGB } from "../src"; -describe('HSVToRGB', function(): void { +describe("HSVToRGB", function(): void { const valid: { args: [number, number, number]; expected: RGB }[] = [ { args: [0, 0, 0], expected: { r: 0, g: 0, b: 0 } }, { args: [0.25, 0, 0], expected: { r: 0, g: 0, b: 0 } }, @@ -20,14 +20,14 @@ describe('HSVToRGB', function(): void { { args: [0.25, 1, 1], expected: { r: 127, g: 255, b: 0 } }, { args: [0.5, 1, 1], expected: { r: 0, g: 255, b: 255 } }, { args: [0.75, 1, 1], expected: { r: 127, g: 0, b: 255 } }, - { args: [1, 1, 1], expected: { r: 255, g: 0, b: 0 } }, - ] + { args: [1, 1, 1], expected: { r: 255, g: 0, b: 0 } } + ]; - describe('Valid', function(): void { + describe("Valid", function(): void { valid.forEach(({ args, expected }): void => { it(JSON.stringify(args), function(): void { - expect(HSVToRGB(...args)).to.be.deep.equal(expected) - }) - }) - }) -}) + expect(HSVToRGB(...args)).to.be.deep.equal(expected); + }); + }); + }); +}); diff --git a/test/insert-sort.test.ts b/test/insert-sort.test.ts index 3da52d36..f78deaac 100644 --- a/test/insert-sort.test.ts +++ b/test/insert-sort.test.ts @@ -1,9 +1,9 @@ -import { expect } from 'chai' +import { expect } from "chai"; -import { insertSort } from '../src' +import { insertSort } from "../src"; -describe('insertSort', function(): void { - it('Sorted data should stay in the same order', function(): void { +describe("insertSort", function(): void { + it("Sorted data should stay in the same order", function(): void { const getData = (): number[] => [ Number.NEGATIVE_INFINITY, Number.MIN_SAFE_INTEGER, @@ -22,13 +22,15 @@ describe('insertSort', function(): void { 2000, Number.MAX_SAFE_INTEGER, Number.MAX_VALUE, - Number.POSITIVE_INFINITY, - ] + Number.POSITIVE_INFINITY + ]; - expect(insertSort(getData(), (a, b): number => a - b)).to.deep.equal(getData()) - }) + expect(insertSort(getData(), (a, b): number => a - b)).to.deep.equal( + getData() + ); + }); - it('Same values should never swap places', function(): void { + it("Same values should never swap places", function(): void { const getData = (): { index?: number; value: number }[] => [ { value: 11 }, { index: 6, value: 7 }, @@ -45,14 +47,14 @@ describe('insertSort', function(): void { { value: 48 }, { index: 10, value: 7 }, { value: -77 }, - { value: 22 }, - ] + { value: 22 } + ]; - const sorted = insertSort(getData(), (a, b): number => a.value - b.value) + const sorted = insertSort(getData(), (a, b): number => a.value - b.value); sorted.forEach(({ index }, arrayIndex): void => { if (index != null) { - expect(index).to.equal(arrayIndex) + expect(index).to.equal(arrayIndex); } - }) - }) -}) + }); + }); +}); diff --git a/test/is-valid-hex.test.ts b/test/is-valid-hex.test.ts index 98011c9d..ce02c8de 100644 --- a/test/is-valid-hex.test.ts +++ b/test/is-valid-hex.test.ts @@ -1,9 +1,19 @@ -import { expect } from 'chai' +import { expect } from "chai"; -import { isValidHex } from '../src' +import { isValidHex } from "../src"; -describe('isValidHex', function(): void { - const valid = ['#000000', '#0acdc0', '#AC00DC', '#09afAF', '#000', '#0ac', '#0DC', '#09a', '#fAF'] +describe("isValidHex", function(): void { + const valid = [ + "#000000", + "#0acdc0", + "#AC00DC", + "#09afAF", + "#000", + "#0ac", + "#0DC", + "#09a", + "#fAF" + ]; const invalid = [ // without # ...valid.map((color): string => color.slice(1)), @@ -12,38 +22,38 @@ describe('isValidHex', function(): void { // 4 or 1 digit ...valid.map((color): string => color.slice(0, -2)), // 7 or 4 digits - ...valid.map((color): string => color + '0'), + ...valid.map((color): string => color + "0"), // 8 or 5 digits - ...valid.map((color): string => color + 'Fa'), - ' #000000', - ' ', - '##abc', - '#000 ', - '#ABC is a color', - '#abc-ef', - '#Ř0AABB', - '', - '0', - 'false', - 'garbage', - 'orange', - 'the color is #00AAAA', - 'true', - ] + ...valid.map((color): string => color + "Fa"), + " #000000", + " ", + "##abc", + "#000 ", + "#ABC is a color", + "#abc-ef", + "#Ř0AABB", + "", + "0", + "false", + "garbage", + "orange", + "the color is #00AAAA", + "true" + ]; - describe('Valid', function(): void { + describe("Valid", function(): void { valid.forEach((color): void => { it(color, function(): void { - expect(isValidHex(color)).to.be.true - }) - }) - }) + expect(isValidHex(color)).to.be.true; + }); + }); + }); - describe('Invalid', function(): void { + describe("Invalid", function(): void { invalid.forEach((color): void => { it(color, function(): void { - expect(isValidHex(color)).to.be.false - }) - }) - }) -}) + expect(isValidHex(color)).to.be.false; + }); + }); + }); +}); diff --git a/test/is-valid-rgb.test.ts b/test/is-valid-rgb.test.ts index a36005cd..037407c3 100644 --- a/test/is-valid-rgb.test.ts +++ b/test/is-valid-rgb.test.ts @@ -1,64 +1,64 @@ -import { expect } from 'chai' +import { expect } from "chai"; -import { isValidRGB } from '../src' +import { isValidRGB } from "../src"; -describe('isValidRGB', function(): void { +describe("isValidRGB", function(): void { const valid = [ - 'RGB(7, 200, 8)', - 'RGb(255,255,255)', - 'Rgb(0,12,123)', - 'rGB(44, 7, 220)', - 'rGb(210, 50,220)', - 'rgB(210,50, 220)', - 'rgb( 72 , 11 , 123 )', - 'rgb(0,0,0)', - ] + "RGB(7, 200, 8)", + "RGb(255,255,255)", + "Rgb(0,12,123)", + "rGB(44, 7, 220)", + "rGb(210, 50,220)", + "rgB(210,50, 220)", + "rgb( 72 , 11 , 123 )", + "rgb(0,0,0)" + ]; const invalid = [ - ' ', - ' Rgb(0,12,123) ', - ' rGb(210, 50,220)', - '#000000', - '#abc', - '', - '(0,12,123)', - '0', - '0,12,123)', - '5,7,9', - 'RGB(-1, 0, 0)', - 'RGB(0, -1, 0)', - 'RGB(0, 0, -1)', - 'RGB(255, 255, 256)', - 'RGB(255, 256, 255)', - 'RGB(256, 255, 255)', - 'RGBA(123, 147, 95, 1)', - 'false', - 'garbage', - 'hi rgb(0,12,123)', - 'orange', - 'rGb(210, 50,220) ', - 'rgb 7, 7, 7', - 'rgb(0, 12, 123) :-)', - 'rgb(0,12,123', - 'rgb(4 4, 7, 220)', - 'rgb(44, 7, 2 2 0)', - 'rgba(7,8,9,0.3)', - 'the color is #00AAAA', - 'true', - ] + " ", + " Rgb(0,12,123) ", + " rGb(210, 50,220)", + "#000000", + "#abc", + "", + "(0,12,123)", + "0", + "0,12,123)", + "5,7,9", + "RGB(-1, 0, 0)", + "RGB(0, -1, 0)", + "RGB(0, 0, -1)", + "RGB(255, 255, 256)", + "RGB(255, 256, 255)", + "RGB(256, 255, 255)", + "RGBA(123, 147, 95, 1)", + "false", + "garbage", + "hi rgb(0,12,123)", + "orange", + "rGb(210, 50,220) ", + "rgb 7, 7, 7", + "rgb(0, 12, 123) :-)", + "rgb(0,12,123", + "rgb(4 4, 7, 220)", + "rgb(44, 7, 2 2 0)", + "rgba(7,8,9,0.3)", + "the color is #00AAAA", + "true" + ]; - describe('Valid', function(): void { + describe("Valid", function(): void { valid.forEach((color): void => { it(color, function(): void { - expect(isValidRGB(color)).to.be.true - }) - }) - }) + expect(isValidRGB(color)).to.be.true; + }); + }); + }); - describe('Invalid', function(): void { + describe("Invalid", function(): void { invalid.forEach((color): void => { it(color, function(): void { - expect(isValidRGB(color)).to.be.false - }) - }) - }) -}) + expect(isValidRGB(color)).to.be.false; + }); + }); + }); +}); diff --git a/test/is-valid-rgba.test.ts b/test/is-valid-rgba.test.ts index e092e10f..223b4e90 100644 --- a/test/is-valid-rgba.test.ts +++ b/test/is-valid-rgba.test.ts @@ -1,66 +1,66 @@ -import { expect } from 'chai' +import { expect } from "chai"; -import { isValidRGBA } from '../src' +import { isValidRGBA } from "../src"; -describe('isValidRGBA', function(): void { +describe("isValidRGBA", function(): void { const valid = [ - 'RGBA(7, 200, 8, .7)', - 'RGBA(7, 200, 8, 0.7)', - 'RGba(255,255,255,1)', - 'Rgba(0,12,123,0.321)', - 'rGBa(44, 7, 220,0.92)', - 'rGba(210, 50,220, 0.42)', - 'rgBa(210,50, 220,0.37)', - 'rgbA( 72 , 11 , 123 , 0.21 )', - 'rgba(0,0,0,0)', - ] + "RGBA(7, 200, 8, .7)", + "RGBA(7, 200, 8, 0.7)", + "RGba(255,255,255,1)", + "Rgba(0,12,123,0.321)", + "rGBa(44, 7, 220,0.92)", + "rGba(210, 50,220, 0.42)", + "rgBa(210,50, 220,0.37)", + "rgbA( 72 , 11 , 123 , 0.21 )", + "rgba(0,0,0,0)" + ]; const invalid = [ - ' ', - ' RGBA(0, 12, 123, 0.3) ', - ' RGBA(210,50,220,0)', - '#000000', - '#abc', - '', - '(0,12,123)', - '0', - '0,12,123)', - '5,7,9', - 'RGBA(210, 50, 220, 0.77) ', - 'false', - 'garbage', - 'hi rgb(0,12,123)', - 'orange', - 'rgb 7, 7, 7', - 'rgb(0, 12, 123)', - 'rgb(0,12,123, 0.2)', - 'rgba(0, 0, -1, 0)', - 'rgba(0, 0, 0, -1)', - 'rgba(0, 0, 0, 1.1)', - 'rgba(0, 0, 0, 2)', - 'rgba(0, 12, 123, 0.7) :-)', - 'rgba(0, 300, 0, 0)', - 'rgba(0,1 2,0,0)', - 'rgba(0,12,123,0.3', - 'rgba(256, 0, 0, 0)', - 'rgba(7, 8, 9)', - 'rgba(7,8,9)', - 'the color is #00AAAA', - 'true', - ] + " ", + " RGBA(0, 12, 123, 0.3) ", + " RGBA(210,50,220,0)", + "#000000", + "#abc", + "", + "(0,12,123)", + "0", + "0,12,123)", + "5,7,9", + "RGBA(210, 50, 220, 0.77) ", + "false", + "garbage", + "hi rgb(0,12,123)", + "orange", + "rgb 7, 7, 7", + "rgb(0, 12, 123)", + "rgb(0,12,123, 0.2)", + "rgba(0, 0, -1, 0)", + "rgba(0, 0, 0, -1)", + "rgba(0, 0, 0, 1.1)", + "rgba(0, 0, 0, 2)", + "rgba(0, 12, 123, 0.7) :-)", + "rgba(0, 300, 0, 0)", + "rgba(0,1 2,0,0)", + "rgba(0,12,123,0.3", + "rgba(256, 0, 0, 0)", + "rgba(7, 8, 9)", + "rgba(7,8,9)", + "the color is #00AAAA", + "true" + ]; - describe('Valid', function(): void { + describe("Valid", function(): void { valid.forEach((color): void => { it(color, function(): void { - expect(isValidRGBA(color)).to.be.true - }) - }) - }) + expect(isValidRGBA(color)).to.be.true; + }); + }); + }); - describe('Invalid', function(): void { + describe("Invalid", function(): void { invalid.forEach((color): void => { it(color, function(): void { - expect(isValidRGBA(color)).to.be.false - }) - }) - }) -}) + expect(isValidRGBA(color)).to.be.false; + }); + }); + }); +}); diff --git a/test/parse-color.test.ts b/test/parse-color.test.ts index 7de7a0af..bffb4bc0 100644 --- a/test/parse-color.test.ts +++ b/test/parse-color.test.ts @@ -1,285 +1,292 @@ -import { expect } from 'chai' +import { expect } from "chai"; -import { parseColor, ColorObject, FullColorObject } from '../src' +import { parseColor, ColorObject, FullColorObject } from "../src"; -describe('parseColor', function(): void { - describe('strings', function(): void { +describe("parseColor", function(): void { + describe("strings", function(): void { const inputs: { color: string; expected: FullColorObject }[] = [ { - color: 'Hi, I’m a color :-).', + color: "Hi, I’m a color :-).", expected: { - background: 'Hi, I’m a color :-).', - border: 'Hi, I’m a color :-).', + background: "Hi, I’m a color :-).", + border: "Hi, I’m a color :-).", hover: { - background: 'Hi, I’m a color :-).', - border: 'Hi, I’m a color :-).', + background: "Hi, I’m a color :-).", + border: "Hi, I’m a color :-)." }, highlight: { - background: 'Hi, I’m a color :-).', - border: 'Hi, I’m a color :-).', - }, - }, + background: "Hi, I’m a color :-).", + border: "Hi, I’m a color :-)." + } + } }, { - color: 'rgb(0, 119, 238)', + color: "rgb(0, 119, 238)", expected: { - background: '#0077ee', - border: '#005fbe', + background: "#0077ee", + border: "#005fbe", hover: { - background: '#3091f2', - border: '#005fbe', + background: "#3091f2", + border: "#005fbe" }, highlight: { - background: '#3091f2', - border: '#005fbe', - }, - }, + background: "#3091f2", + border: "#005fbe" + } + } }, { - color: '#0077EE', + color: "#0077EE", expected: { - background: '#0077EE', - border: '#005fbe', + background: "#0077EE", + border: "#005fbe", hover: { - background: '#3091f2', - border: '#005fbe', + background: "#3091f2", + border: "#005fbe" }, highlight: { - background: '#3091f2', - border: '#005fbe', - }, - }, - }, - ] + background: "#3091f2", + border: "#005fbe" + } + } + } + ]; inputs.forEach(({ color, expected }): void => { it(color, function(): void { - expect(parseColor(color)).to.be.deep.equal(expected) - }) - }) - }) + expect(parseColor(color)).to.be.deep.equal(expected); + }); + }); + }); - describe('color objects', function(): void { - const inputs: { name: string; color: ColorObject; defaultColor?: FullColorObject; expected: ColorObject }[] = [ + describe("color objects", function(): void { + const inputs: { + name: string; + color: ColorObject; + defaultColor?: FullColorObject; + expected: ColorObject; + }[] = [ { - name: 'empty object without default color', + name: "empty object without default color", color: {}, expected: { background: undefined, border: undefined, hover: { background: undefined, - border: undefined, + border: undefined }, highlight: { background: undefined, - border: undefined, - }, - }, + border: undefined + } + } }, { - name: 'empty object with default color', + name: "empty object with default color", color: {}, defaultColor: { - border: 'rgb(0, 1, 2)', - background: 'rgb(3, 4, 5)', + border: "rgb(0, 1, 2)", + background: "rgb(3, 4, 5)", hover: { - border: 'rgb(6, 7, 8)', - background: 'rgb(9, 10, 11)', + border: "rgb(6, 7, 8)", + background: "rgb(9, 10, 11)" }, highlight: { - border: 'rgb(12, 13, 14)', - background: 'rgb(15, 16, 17)', - }, + border: "rgb(12, 13, 14)", + background: "rgb(15, 16, 17)" + } }, expected: { - border: 'rgb(0, 1, 2)', - background: 'rgb(3, 4, 5)', + border: "rgb(0, 1, 2)", + background: "rgb(3, 4, 5)", hover: { - border: 'rgb(6, 7, 8)', - background: 'rgb(9, 10, 11)', + border: "rgb(6, 7, 8)", + background: "rgb(9, 10, 11)" }, highlight: { - border: 'rgb(12, 13, 14)', - background: 'rgb(15, 16, 17)', - }, - }, + border: "rgb(12, 13, 14)", + background: "rgb(15, 16, 17)" + } + } }, { - name: 'partial without default color', + name: "partial without default color", color: { - border: '#0077EE', + border: "#0077EE", hover: { - background: '#123456', + background: "#123456" }, highlight: { - border: '#ABCDEF', - }, + border: "#ABCDEF" + } }, expected: { background: undefined, - border: '#0077EE', + border: "#0077EE", hover: { - background: '#123456', - border: undefined, + background: "#123456", + border: undefined }, highlight: { background: undefined, - border: '#ABCDEF', - }, - }, + border: "#ABCDEF" + } + } }, { - name: 'full without default color', + name: "full without default color", color: { - border: 'rgb(0, 1, 2)', - background: 'rgb(3, 4, 5)', + border: "rgb(0, 1, 2)", + background: "rgb(3, 4, 5)", hover: { - border: 'rgb(6, 7, 8)', - background: 'rgb(9, 10, 11)', + border: "rgb(6, 7, 8)", + background: "rgb(9, 10, 11)" }, highlight: { - border: 'rgb(12, 13, 14)', - background: 'rgb(15, 16, 17)', - }, + border: "rgb(12, 13, 14)", + background: "rgb(15, 16, 17)" + } }, expected: { - border: 'rgb(0, 1, 2)', - background: 'rgb(3, 4, 5)', + border: "rgb(0, 1, 2)", + background: "rgb(3, 4, 5)", hover: { - border: 'rgb(6, 7, 8)', - background: 'rgb(9, 10, 11)', + border: "rgb(6, 7, 8)", + background: "rgb(9, 10, 11)" }, highlight: { - border: 'rgb(12, 13, 14)', - background: 'rgb(15, 16, 17)', - }, - }, + border: "rgb(12, 13, 14)", + background: "rgb(15, 16, 17)" + } + } }, { - name: 'partial with default color', + name: "partial with default color", color: { - border: '#023456', + border: "#023456", hover: { - background: '#034567', + background: "#034567" }, highlight: { - border: '#06789A', - }, + border: "#06789A" + } }, defaultColor: { - background: '#112345', - border: '#123456', + background: "#112345", + border: "#123456", hover: { - background: '#134567', - border: '#145678', + background: "#134567", + border: "#145678" }, highlight: { - background: '#156789', - border: '#16789A', - }, + background: "#156789", + border: "#16789A" + } }, expected: { - background: '#112345', - border: '#023456', + background: "#112345", + border: "#023456", hover: { - background: '#034567', - border: '#145678', + background: "#034567", + border: "#145678" }, highlight: { - background: '#156789', - border: '#06789A', - }, - }, + background: "#156789", + border: "#06789A" + } + } }, { - name: 'strings without default color', + name: "strings without default color", color: { - background: '#012345', - border: '#023456', - hover: '#034567', - highlight: '#06789A', + background: "#012345", + border: "#023456", + hover: "#034567", + highlight: "#06789A" }, expected: { - background: '#012345', - border: '#023456', + background: "#012345", + border: "#023456", hover: { - background: '#034567', - border: '#034567', + background: "#034567", + border: "#034567" }, highlight: { - background: '#06789A', - border: '#06789A', - }, - }, + background: "#06789A", + border: "#06789A" + } + } }, { - name: 'strings with default color', + name: "strings with default color", color: { - background: '#012345', - border: '#023456', - hover: '#034567', - highlight: '#045678', + background: "#012345", + border: "#023456", + hover: "#034567", + highlight: "#045678" }, defaultColor: { - background: '#112345', - border: '#123456', + background: "#112345", + border: "#123456", hover: { - background: '#134567', - border: '#145678', + background: "#134567", + border: "#145678" }, highlight: { - background: '#156789', - border: '#16789A', - }, + background: "#156789", + border: "#16789A" + } }, expected: { - background: '#012345', - border: '#023456', + background: "#012345", + border: "#023456", hover: { - background: '#034567', - border: '#034567', + background: "#034567", + border: "#034567" }, highlight: { - background: '#045678', - border: '#045678', - }, - }, + background: "#045678", + border: "#045678" + } + } }, { - name: 'default color only', + name: "default color only", color: {}, defaultColor: { - background: '#112345', - border: '#123456', + background: "#112345", + border: "#123456", hover: { - background: '#134567', - border: '#145678', + background: "#134567", + border: "#145678" }, highlight: { - background: '#156789', - border: '#16789A', - }, + background: "#156789", + border: "#16789A" + } }, expected: { - background: '#112345', - border: '#123456', + background: "#112345", + border: "#123456", hover: { - background: '#134567', - border: '#145678', + background: "#134567", + border: "#145678" }, highlight: { - background: '#156789', - border: '#16789A', - }, - }, - }, - ] + background: "#156789", + border: "#16789A" + } + } + } + ]; inputs.forEach(({ name, color, defaultColor, expected }): void => { it(name, function(): void { - expect(parseColor(color, defaultColor as FullColorObject)).to.be.deep.equal(expected) - }) - }) - }) -}) + expect( + parseColor(color, defaultColor as FullColorObject) + ).to.be.deep.equal(expected); + }); + }); + }); +}); diff --git a/test/remove-class-name.test.ts b/test/remove-class-name.test.ts index a55607d1..1e0f04e5 100644 --- a/test/remove-class-name.test.ts +++ b/test/remove-class-name.test.ts @@ -1,22 +1,22 @@ -import { expect } from 'chai' +import { expect } from "chai"; -import { removeClassName } from '../src' +import { removeClassName } from "../src"; -describe('removeClassName', function(): void { +describe("removeClassName", function(): void { const inputs: { input: string; classes: string; expected: string }[] = [ - { input: 'a b c', classes: 'a c', expected: 'b' }, - { input: 'a b c', classes: 'b', expected: 'a c' }, - { input: 'a b c', classes: 'd', expected: 'a b c' }, - { input: 'class-1 class-2', classes: 'class-2', expected: 'class-1' }, - ] + { input: "a b c", classes: "a c", expected: "b" }, + { input: "a b c", classes: "b", expected: "a c" }, + { input: "a b c", classes: "d", expected: "a b c" }, + { input: "class-1 class-2", classes: "class-2", expected: "class-1" } + ]; inputs.forEach(({ input, classes, expected }): void => { it(`${input} - ${classes} = ${expected}`, function(): void { - const elem = { className: input } + const elem = { className: input }; - removeClassName(elem as any, classes) + removeClassName(elem as any, classes); - expect(elem.className).to.equal(expected) - }) - }) -}) + expect(elem.className).to.equal(expected); + }); + }); +}); diff --git a/test/rgb-to-hex.test.ts b/test/rgb-to-hex.test.ts index b9e9cc49..8f9d675b 100644 --- a/test/rgb-to-hex.test.ts +++ b/test/rgb-to-hex.test.ts @@ -1,25 +1,25 @@ -import { expect } from 'chai' +import { expect } from "chai"; -import { RGBToHex } from '../src' +import { RGBToHex } from "../src"; -describe('RGBToHex', function(): void { +describe("RGBToHex", function(): void { const valid: { args: [number, number, number]; expected: string }[] = [ - { args: [0x00, 0x00, 0x00], expected: '#000000' }, - { args: [0x00, 0x99, 0xaa], expected: '#0099aa' }, - { args: [0x00, 0xaa, 0xcc], expected: '#00aacc' }, - { args: [0x00, 0xdd, 0xcc], expected: '#00ddcc' }, - { args: [0x09, 0xaf, 0xaf], expected: '#09afaf' }, - { args: [0x0a, 0xcd, 0xc0], expected: '#0acdc0' }, - { args: [0xac, 0x00, 0xdc], expected: '#ac00dc' }, - { args: [0xff, 0xaa, 0xff], expected: '#ffaaff' }, - { args: [0xff, 0xff, 0xff], expected: '#ffffff' }, - ] + { args: [0x00, 0x00, 0x00], expected: "#000000" }, + { args: [0x00, 0x99, 0xaa], expected: "#0099aa" }, + { args: [0x00, 0xaa, 0xcc], expected: "#00aacc" }, + { args: [0x00, 0xdd, 0xcc], expected: "#00ddcc" }, + { args: [0x09, 0xaf, 0xaf], expected: "#09afaf" }, + { args: [0x0a, 0xcd, 0xc0], expected: "#0acdc0" }, + { args: [0xac, 0x00, 0xdc], expected: "#ac00dc" }, + { args: [0xff, 0xaa, 0xff], expected: "#ffaaff" }, + { args: [0xff, 0xff, 0xff], expected: "#ffffff" } + ]; - describe('Valid', function(): void { + describe("Valid", function(): void { valid.forEach(({ args, expected }): void => { it(JSON.stringify(args), function(): void { - expect(RGBToHex(...args)).to.be.deep.equal(expected) - }) - }) - }) -}) + expect(RGBToHex(...args)).to.be.deep.equal(expected); + }); + }); + }); +}); diff --git a/test/selective-deep-extend.test.ts b/test/selective-deep-extend.test.ts index 94d2f1d0..00b06e03 100644 --- a/test/selective-deep-extend.test.ts +++ b/test/selective-deep-extend.test.ts @@ -1,104 +1,123 @@ -import { expect } from 'chai' +import { expect } from "chai"; -import { selectiveDeepExtend } from '../src' +import { selectiveDeepExtend } from "../src"; -describe('selectiveDeepExtend', function(): void { - describe('copy 1, overwrite 1, ignore 1', function(): void { - it('shallow → shallow', function(): void { - const target = { ignored: 'target', merged: 'target' } - const source = Object.freeze({ ignored: 'source', merged: 'source', copied: 'source' }) - const copied = selectiveDeepExtend(['merged', 'copied'], target, source) +describe("selectiveDeepExtend", function(): void { + describe("copy 1, overwrite 1, ignore 1", function(): void { + it("shallow → shallow", function(): void { + const target = { ignored: "target", merged: "target" }; + const source = Object.freeze({ + ignored: "source", + merged: "source", + copied: "source" + }); + const copied = selectiveDeepExtend(["merged", "copied"], target, source); - expect(copied, 'They should be the same instance.').to.equal(target) - expect(copied, 'The selected properties of the objects should be deeply merged').to.deep.equal({ - ignored: 'target', - merged: 'source', - copied: 'source', - }) - }) + expect(copied, "They should be the same instance.").to.equal(target); + expect( + copied, + "The selected properties of the objects should be deeply merged" + ).to.deep.equal({ + ignored: "target", + merged: "source", + copied: "source" + }); + }); - it('deep → deep', function(): void { + it("deep → deep", function(): void { const target = { - ignored: { nested: { prop: 'target' }, additional: 'target' }, - merged: { nested: { prop: 'target', additional: 'target' } }, - } + ignored: { nested: { prop: "target" }, additional: "target" }, + merged: { nested: { prop: "target", additional: "target" } } + }; const source = Object.freeze({ - ignored: { nested: { prop: 'source', another: 'source' } }, - merged: { nested: { prop: 'source' }, another: 'source' }, - copied: { nested: { prop: 'source', another: 'source' } }, - }) - const copied = selectiveDeepExtend(['merged', 'copied'], target, source) + ignored: { nested: { prop: "source", another: "source" } }, + merged: { nested: { prop: "source" }, another: "source" }, + copied: { nested: { prop: "source", another: "source" } } + }); + const copied = selectiveDeepExtend(["merged", "copied"], target, source); - expect(copied, 'They should be the same instance.').to.equal(target) - expect(copied, 'The selected properties of the objects should be deeply merged').to.deep.equal({ - ignored: { nested: { prop: 'target' }, additional: 'target' }, - merged: { nested: { prop: 'source', additional: 'target' }, another: 'source' }, - copied: { nested: { prop: 'source', another: 'source' } }, - }) - }) + expect(copied, "They should be the same instance.").to.equal(target); + expect( + copied, + "The selected properties of the objects should be deeply merged" + ).to.deep.equal({ + ignored: { nested: { prop: "target" }, additional: "target" }, + merged: { + nested: { prop: "source", additional: "target" }, + another: "source" + }, + copied: { nested: { prop: "source", another: "source" } } + }); + }); - it('primitive → deep', function(): void { + it("primitive → deep", function(): void { const target = { - ignored: { nested: { prop: 'target' }, additional: 'target' }, - merged: { nested: { prop: 'target', additional: 'target' } }, - } + ignored: { nested: { prop: "target" }, additional: "target" }, + merged: { nested: { prop: "target", additional: "target" } } + }; const source = Object.freeze({ - ignored: 'source', - merged: 'source', - copied: 'source', - }) - const copied = selectiveDeepExtend(['merged', 'copied'], target, source) + ignored: "source", + merged: "source", + copied: "source" + }); + const copied = selectiveDeepExtend(["merged", "copied"], target, source); - expect(copied, 'They should be the same instance.').to.equal(target) - expect(copied, 'The selected properties of the objects should be deeply merged').to.deep.equal({ - ignored: { nested: { prop: 'target' }, additional: 'target' }, - merged: 'source', - copied: 'source', - }) - }) + expect(copied, "They should be the same instance.").to.equal(target); + expect( + copied, + "The selected properties of the objects should be deeply merged" + ).to.deep.equal({ + ignored: { nested: { prop: "target" }, additional: "target" }, + merged: "source", + copied: "source" + }); + }); - it('deep → primitive', function(): void { + it("deep → primitive", function(): void { const target = { - ignored: 'target', - merged: 'target', - } + ignored: "target", + merged: "target" + }; const source = Object.freeze({ - ignored: { nested: { prop: 'source', another: 'source' } }, - merged: { nested: { prop: 'source' }, another: 'source' }, - copied: { nested: { prop: 'source', another: 'source' } }, - }) - const copied = selectiveDeepExtend(['merged', 'copied'], target, source) + ignored: { nested: { prop: "source", another: "source" } }, + merged: { nested: { prop: "source" }, another: "source" }, + copied: { nested: { prop: "source", another: "source" } } + }); + const copied = selectiveDeepExtend(["merged", "copied"], target, source); - expect(copied, 'They should be the same instance.').to.equal(target) - expect(copied, 'The selected properties of the objects should be deeply merged').to.deep.equal({ - ignored: 'target', - merged: { nested: { prop: 'source' }, another: 'source' }, - copied: { nested: { prop: 'source', another: 'source' } }, - }) - }) - }) + expect(copied, "They should be the same instance.").to.equal(target); + expect( + copied, + "The selected properties of the objects should be deeply merged" + ).to.deep.equal({ + ignored: "target", + merged: { nested: { prop: "source" }, another: "source" }, + copied: { nested: { prop: "source", another: "source" } } + }); + }); + }); - describe('arrays', function(): void { - it('array source', function(): void { + describe("arrays", function(): void { + it("array source", function(): void { expect((): void => { - selectiveDeepExtend(['prop'], {}, []) - }).to.throw() - }) + selectiveDeepExtend(["prop"], {}, []); + }).to.throw(); + }); - it('array → array', function(): void { + it("array → array", function(): void { const target = { - ignored: ['target', 'target'], - merged: ['target', 'target'], - } + ignored: ["target", "target"], + merged: ["target", "target"] + }; const source = Object.freeze({ - ignored: ['source'], - merged: ['source'], - copied: ['source'], - }) + ignored: ["source"], + merged: ["source"], + copied: ["source"] + }); expect((): void => { - selectiveDeepExtend(['merged', 'copied'], target, source) - }).to.throw() - }) - }) -}) + selectiveDeepExtend(["merged", "copied"], target, source); + }).to.throw(); + }); + }); +}); diff --git a/test/selective-extend.test.ts b/test/selective-extend.test.ts index c6724c4e..aa142e20 100644 --- a/test/selective-extend.test.ts +++ b/test/selective-extend.test.ts @@ -1,51 +1,70 @@ -import { expect } from 'chai' +import { expect } from "chai"; -import { selectiveExtend } from '../src' +import { selectiveExtend } from "../src"; -describe('selectiveExtend', function(): void { - it('non-array property names', function(): void { +describe("selectiveExtend", function(): void { + it("non-array property names", function(): void { expect((): void => { - selectiveExtend('prop' as any, {}, {}) - }).to.throw() - }) - - it('copy 1 ignore 1', function(): void { - const target = { hi: ':-)' } - const source = Object.freeze({ hi: ':-( 1', bye: ':-) 1' }) - const copied = selectiveExtend(['bye'], target, source) - - expect(copied, 'They should be the same instance.').to.equal(target) - expect(copied, 'The selected properties should be copied by reference').to.deep.equal({ - hi: ':-)', - bye: ':-) 1', - }) - }) - - it('2 sources, copy 1 ignore 1', function(): void { - const target = { hi: ':-)' } - const source1 = Object.freeze({ hi: ':-( 1', bye: ':-) 1' }) - const source2 = Object.freeze({ hi: ':-( 2', bye: ':-) 2' }) - const copied = selectiveExtend(['bye'], target, source1, source2) - - expect(copied, 'They should be the same instance.').to.equal(target) - expect(copied, 'The selected properties should be copied by reference').to.deep.equal({ - hi: ':-)', - bye: ':-) 2', - }) - }) - - it('3 sources, copy 2 ignore 1', function(): void { - const target = { hi: ':-)' } - const source1 = Object.freeze({ hi: ':-( 1', bye: ':-) 1' }) - const source2 = Object.freeze({ hi: ':-( 2', bye: ':-) 2', hello: ':-) 2' }) - const source3 = Object.freeze({ hi: ':-( 3', bye: ':-) 3' }) - const copied = selectiveExtend(['bye', 'hello'], target, source1, source2, source3) - - expect(copied, 'They should be the same instance.').to.equal(target) - expect(copied, 'The selected properties should be copied by reference').to.deep.equal({ - hi: ':-)', - hello: ':-) 2', - bye: ':-) 3', - }) - }) -}) + selectiveExtend("prop" as any, {}, {}); + }).to.throw(); + }); + + it("copy 1 ignore 1", function(): void { + const target = { hi: ":-)" }; + const source = Object.freeze({ hi: ":-( 1", bye: ":-) 1" }); + const copied = selectiveExtend(["bye"], target, source); + + expect(copied, "They should be the same instance.").to.equal(target); + expect( + copied, + "The selected properties should be copied by reference" + ).to.deep.equal({ + hi: ":-)", + bye: ":-) 1" + }); + }); + + it("2 sources, copy 1 ignore 1", function(): void { + const target = { hi: ":-)" }; + const source1 = Object.freeze({ hi: ":-( 1", bye: ":-) 1" }); + const source2 = Object.freeze({ hi: ":-( 2", bye: ":-) 2" }); + const copied = selectiveExtend(["bye"], target, source1, source2); + + expect(copied, "They should be the same instance.").to.equal(target); + expect( + copied, + "The selected properties should be copied by reference" + ).to.deep.equal({ + hi: ":-)", + bye: ":-) 2" + }); + }); + + it("3 sources, copy 2 ignore 1", function(): void { + const target = { hi: ":-)" }; + const source1 = Object.freeze({ hi: ":-( 1", bye: ":-) 1" }); + const source2 = Object.freeze({ + hi: ":-( 2", + bye: ":-) 2", + hello: ":-) 2" + }); + const source3 = Object.freeze({ hi: ":-( 3", bye: ":-) 3" }); + const copied = selectiveExtend( + ["bye", "hello"], + target, + source1, + source2, + source3 + ); + + expect(copied, "They should be the same instance.").to.equal(target); + expect( + copied, + "The selected properties should be copied by reference" + ).to.deep.equal({ + hi: ":-)", + hello: ":-) 2", + bye: ":-) 3" + }); + }); +}); diff --git a/test/throttle.test.ts b/test/throttle.test.ts index 0bc3fa4c..1f6aa335 100644 --- a/test/throttle.test.ts +++ b/test/throttle.test.ts @@ -1,99 +1,99 @@ -import { assert, spy } from 'sinon' +import { assert, spy } from "sinon"; -import { throttle } from '../src' +import { throttle } from "../src"; -describe('throttle', function(): void { - const queue: ((str: string) => void)[] = [] +describe("throttle", function(): void { + const queue: ((str: string) => void)[] = []; const fire = (): void => { queue.splice(0).forEach((fn): void => { - fn('This should never be seen in the throttled callback.') - }) - } + fn("This should never be seen in the throttled callback."); + }); + }; beforeEach((): void => { - ;(global as any).requestAnimationFrame = queue.push.bind(queue) - }) + (global as any).requestAnimationFrame = queue.push.bind(queue); + }); afterEach((): void => { - delete (global as any).requestAnimationFrame - }) - - it('called on animation frame', function(): void { - const throttleSpy = spy() - const throttled = throttle(throttleSpy) - - throttled() - - assert.notCalled(throttleSpy) - fire() - assert.calledOnce(throttleSpy) - assert.alwaysCalledWith(throttleSpy) - }) - - it('called only once', function(): void { - const throttleSpy = spy() - const throttled = throttle(throttleSpy) - - throttled() - throttled() - throttled() - throttled() - - assert.notCalled(throttleSpy) - fire() - assert.calledOnce(throttleSpy) - assert.alwaysCalledWith(throttleSpy) - }) - - it('called once on each animation frame', function(): void { - const throttleSpy = spy() - const throttled = throttle(throttleSpy) - - throttled() - throttled() - throttled() - throttled() - assert.notCalled(throttleSpy) - - throttled() - throttled() - fire() - assert.calledOnce(throttleSpy) - assert.alwaysCalledWith(throttleSpy) - - throttled() - fire() - assert.calledTwice(throttleSpy) - assert.alwaysCalledWith(throttleSpy) - - throttled() - throttled() - throttled() - fire() - assert.calledThrice(throttleSpy) - assert.alwaysCalledWith(throttleSpy) - }) - - it('called only if requested before the animation frame', function(): void { - const throttleSpy = spy() - const throttled = throttle(throttleSpy) - - throttled() - throttled() - assert.notCalled(throttleSpy) - - throttled() - fire() - assert.calledOnce(throttleSpy) - assert.alwaysCalledWith(throttleSpy) - - fire() - assert.calledOnce(throttleSpy) - assert.alwaysCalledWith(throttleSpy) - - throttled() - throttled() - fire() - assert.calledTwice(throttleSpy) - assert.alwaysCalledWith(throttleSpy) - }) -}) + delete (global as any).requestAnimationFrame; + }); + + it("called on animation frame", function(): void { + const throttleSpy = spy(); + const throttled = throttle(throttleSpy); + + throttled(); + + assert.notCalled(throttleSpy); + fire(); + assert.calledOnce(throttleSpy); + assert.alwaysCalledWith(throttleSpy); + }); + + it("called only once", function(): void { + const throttleSpy = spy(); + const throttled = throttle(throttleSpy); + + throttled(); + throttled(); + throttled(); + throttled(); + + assert.notCalled(throttleSpy); + fire(); + assert.calledOnce(throttleSpy); + assert.alwaysCalledWith(throttleSpy); + }); + + it("called once on each animation frame", function(): void { + const throttleSpy = spy(); + const throttled = throttle(throttleSpy); + + throttled(); + throttled(); + throttled(); + throttled(); + assert.notCalled(throttleSpy); + + throttled(); + throttled(); + fire(); + assert.calledOnce(throttleSpy); + assert.alwaysCalledWith(throttleSpy); + + throttled(); + fire(); + assert.calledTwice(throttleSpy); + assert.alwaysCalledWith(throttleSpy); + + throttled(); + throttled(); + throttled(); + fire(); + assert.calledThrice(throttleSpy); + assert.alwaysCalledWith(throttleSpy); + }); + + it("called only if requested before the animation frame", function(): void { + const throttleSpy = spy(); + const throttled = throttle(throttleSpy); + + throttled(); + throttled(); + assert.notCalled(throttleSpy); + + throttled(); + fire(); + assert.calledOnce(throttleSpy); + assert.alwaysCalledWith(throttleSpy); + + fire(); + assert.calledOnce(throttleSpy); + assert.alwaysCalledWith(throttleSpy); + + throttled(); + throttled(); + fire(); + assert.calledTwice(throttleSpy); + assert.alwaysCalledWith(throttleSpy); + }); +}); diff --git a/test/top-most.test.ts b/test/top-most.test.ts index af2f2816..eca7cd73 100644 --- a/test/top-most.test.ts +++ b/test/top-most.test.ts @@ -1,39 +1,50 @@ -import { expect } from 'chai' +import { expect } from "chai"; -import { topMost } from '../src' +import { topMost } from "../src"; -describe('topMost', function(): void { - it('Single level, first object', function(): void { - const pile = [{ theValue: 'It‘s me :-).' }, { theValue: 'Nobody cares about me :-(.' }] +describe("topMost", function(): void { + it("Single level, first object", function(): void { + const pile = [ + { theValue: "It‘s me :-)." }, + { theValue: "Nobody cares about me :-(." } + ]; - expect(topMost(pile, ['theValue'])).to.equal('It‘s me :-).') - expect(topMost(pile, 'theValue'), 'String accessor should be accepted too.').to.equal('It‘s me :-).') - }) + expect(topMost(pile, ["theValue"])).to.equal("It‘s me :-)."); + expect( + topMost(pile, "theValue"), + "String accessor should be accepted too." + ).to.equal("It‘s me :-)."); + }); - it('Single level, middle object', function(): void { + it("Single level, middle object", function(): void { const pile = [ - { foo: 'Move along, I don‘t have it.' }, - { theValue: 'It‘s me :-).' }, - { theValue: 'Nobody cares about me :-(.' }, - ] + { foo: "Move along, I don‘t have it." }, + { theValue: "It‘s me :-)." }, + { theValue: "Nobody cares about me :-(." } + ]; - expect(topMost(pile, ['theValue'])).to.equal('It‘s me :-).') - expect(topMost(pile, 'theValue'), 'String accessor should be accepted too.').to.equal('It‘s me :-).') - }) + expect(topMost(pile, ["theValue"])).to.equal("It‘s me :-)."); + expect( + topMost(pile, "theValue"), + "String accessor should be accepted too." + ).to.equal("It‘s me :-)."); + }); - it('Nested objects', function(): void { + it("Nested objects", function(): void { const pile = [ {}, { foo: {} }, { foo: { bar: {} } }, - { foo: { bar: { theValue: 'It‘s finally me :-).' } } }, - { foo: { bar: { theValue: 'Nobody cares about me :-(.' } } }, - ] + { foo: { bar: { theValue: "It‘s finally me :-)." } } }, + { foo: { bar: { theValue: "Nobody cares about me :-(." } } } + ]; - expect(topMost(pile, ['foo', 'bar', 'theValue'])).to.equal('It‘s finally me :-).') - }) + expect(topMost(pile, ["foo", "bar", "theValue"])).to.equal( + "It‘s finally me :-)." + ); + }); - it.skip('Nested objects and primitives', function(): void { + it.skip("Nested objects and primitives", function(): void { // @TODO: This doesn't work, but I think it should work. // Any other opinions about it? const pile = [ @@ -45,10 +56,12 @@ describe('topMost', function(): void { { foo: {} }, { foo: { bar: 77 } }, { foo: { bar: {} } }, - { foo: { bar: { theValue: 'It‘s finally me :-).' } } }, - { foo: { bar: { theValue: 'Nobody cares about me :-(.' } } }, - ] + { foo: { bar: { theValue: "It‘s finally me :-)." } } }, + { foo: { bar: { theValue: "Nobody cares about me :-(." } } } + ]; - expect(topMost(pile, ['foo', 'bar', 'theValue'])).to.equal('It‘s finally me :-).') - }) -}) + expect(topMost(pile, ["foo", "bar", "theValue"])).to.equal( + "It‘s finally me :-)." + ); + }); +});