106 lines
2.9 KiB
TypeScript
106 lines
2.9 KiB
TypeScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
/**
|
|
* Randomly rearrange the items of an array in-place.
|
|
*
|
|
* @param arr Array to shuffle.
|
|
*/
|
|
export const shuffle = <T>(arr: T[]): void => {
|
|
let j: number;
|
|
let x: T;
|
|
for (let i = arr.length - 1; i > 0; i--) {
|
|
j = Math.floor(Math.random() * (i + 1));
|
|
x = arr[i];
|
|
arr[i] = arr[j];
|
|
arr[j] = x;
|
|
}
|
|
};
|
|
|
|
const areArraysEqual = <T>(a: T[], b: T[]): boolean => {
|
|
if (a.length != b.length) {
|
|
return false;
|
|
}
|
|
for (let i = 0; i < a.length; i++) {
|
|
if (!areEqual(a[i], b[i])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
|
|
const areObjectsEqual = <T extends object>(a: T, b: T): boolean => {
|
|
const aKeys = Object.keys(a) as Array<keyof T>;
|
|
const bKeys = Object.keys(b) as Array<keyof T>;
|
|
if (aKeys.length !== bKeys.length) {
|
|
return false;
|
|
}
|
|
for (const key of aKeys) {
|
|
if (!areEqual(a[key], b[key])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* Return whether two values are structurally equal, with support for
|
|
* primitive values, arrays, deeply nested objects, and RegExp.
|
|
*
|
|
* @param a First value to test equality with.
|
|
* @param b Second value to test equality with.
|
|
*
|
|
* @return Whether the two values are structurally equal.
|
|
*/
|
|
export const areEqual = <T>(a: T, b: T): boolean => {
|
|
if (Array.isArray(a) && Array.isArray(b)) {
|
|
return areArraysEqual(a, b);
|
|
}
|
|
if (a instanceof RegExp && b instanceof RegExp) {
|
|
return a.source === b.source;
|
|
}
|
|
if (typeof a === "object" && typeof b === "object") {
|
|
return areObjectsEqual(a as any, b);
|
|
}
|
|
return a === b;
|
|
};
|
|
|
|
/**
|
|
* Return whether a string exactly matches an expected string OR matches a
|
|
* RegExp pattern.
|
|
*
|
|
* If the passed pattern is a string this uses strict equality checking, and
|
|
* if the passed pattern is a RegExp object it tests the value against it.
|
|
*
|
|
* @param value String value to test.
|
|
* @param pattern String or RegExp pattern to match value against.
|
|
*/
|
|
export const matches = (value: string, pattern: string | RegExp): boolean => {
|
|
if (typeof pattern === "string") {
|
|
return value === pattern;
|
|
}
|
|
return pattern.test(value);
|
|
};
|
|
|
|
/**
|
|
* Render a JavaScript value for debugging and error messages.
|
|
*
|
|
* This is essentially JSON.stringify, but with special cases for undefined (
|
|
* which normally isn't rendered with JSON.stringify) and RegExp (to display
|
|
* source for the regexp).
|
|
*
|
|
* @param value Value to render.
|
|
*
|
|
* @return Rendered value to display.
|
|
*/
|
|
export const displayValue = (value: any): string => {
|
|
if (value === undefined) {
|
|
return "undefined";
|
|
}
|
|
if (value instanceof RegExp) {
|
|
return value.toString();
|
|
}
|
|
return JSON.stringify(value);
|
|
};
|