UNPKG

@terminus/ngx-tools

Version:

[![CircleCI][circle-badge]][circle-link] [![codecov][codecov-badge]][codecov-project] [![semantic-release][semantic-release-badge]][semantic-release] [![MIT License][license-image]][license-url] <br> [![NPM version][npm-version-image]][npm-url] [![Github

1,145 lines (1,088 loc) 45.3 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@terminus/ngx-tools/type-guards'), require('@angular/forms'), require('@terminus/ngx-tools/coercion'), require('rxjs'), require('rxjs/internal/scheduler/async'), require('rxjs/operators')) : typeof define === 'function' && define.amd ? define('@terminus/ngx-tools/utilities', ['exports', '@terminus/ngx-tools/type-guards', '@angular/forms', '@terminus/ngx-tools/coercion', 'rxjs', 'rxjs/internal/scheduler/async', 'rxjs/operators'], factory) : (global = global || self, factory((global.terminus = global.terminus || {}, global.terminus['ngx-tools'] = global.terminus['ngx-tools'] || {}, global.terminus['ngx-tools'].utilities = {}), global.terminus['ngx-tools']['type-guards'], global.ng.forms, global.terminus['ngx-tools'].coercion, global.rxjs, global.rxjs['internal/scheduler/async'], global.rxjs.operators)); }(this, (function (exports, typeGuards, forms, coercion, rxjs, async, operators) { 'use strict'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } function __decorate(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; } function __param(paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } } function __metadata(metadataKey, metadataValue) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); } function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } function __exportStar(m, exports) { for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; } function __values(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; } function __spread() { for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); return ar; } function __spreadArrays() { for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]; return r; }; function __await(v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } function __asyncGenerator(thisArg, _arguments, generator) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var g = generator.apply(thisArg, _arguments || []), i, q = []; return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } function fulfill(value) { resume("next", value); } function reject(value) { resume("throw", value); } function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } } function __asyncDelegator(o) { var i, p; return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; } } function __asyncValues(o) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var m = o[Symbol.asyncIterator], i; return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } } function __makeTemplateObject(cooked, raw) { if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } return cooked; }; function __importStar(mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result.default = mod; return result; } function __importDefault(mod) { return (mod && mod.__esModule) ? mod : { default: mod }; } function __classPrivateFieldGet(receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); } function __classPrivateFieldSet(receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; } /** * Helper function to abbreviate a number * * @param input - The number to be abbreviated. * @param decimalPlace - The decimals users define for final abbreviated number. Default to 1. * @returns The abbreviated number * * @example * abbreviateNumber(1234, '1') // Returns: '1.2K' */ function abbreviateNumber(input, decimalPlace) { if (decimalPlace === void 0) { decimalPlace = 1; } var SCALE_NUMBER = 3; var MATH_POWER = 10; if (!input) { return ''; } var baseNumberAndExponent = input .toExponential() .split('e+') .map(function (el) { return +el; }); if (baseNumberAndExponent[1] < SCALE_NUMBER) { return input.toString(); } var scaleLevel = baseNumberAndExponent[1] % SCALE_NUMBER; baseNumberAndExponent[0] = baseNumberAndExponent[0] * Math.pow(MATH_POWER, scaleLevel); var calculatedScale = [ '', 'K', 'M', 'B', 'T', ][(baseNumberAndExponent[1] - scaleLevel) / SCALE_NUMBER]; var newNumber = baseNumberAndExponent[0].toFixed(decimalPlace).toString(); return newNumber + calculatedScale; } /** * A helper function to apply TypeScript mixins * * https://www.typescriptlang.org/docs/handbook/mixins.html * * @param derivedCtor - The mixin target class * @param baseCtors - An array of classes to combine into the target class * @returns The mixed class * * @example * applyMixins(SmartObject, [Disposable, Activatable]); */ // eslint-disable-next-line @typescript-eslint/no-explicit-any function applyMixins(derivedCtor, baseCtors) { baseCtors.forEach(function (baseCtor) { Object.getOwnPropertyNames(baseCtor.prototype).forEach(function (name) { derivedCtor.prototype[name] = baseCtor.prototype[name]; }); }); } /** * Determine if an object exists in an array * * @param object - The object to look for in the array * @param array - The array to search through * @param comparator - The function to determine what object values to compare * @returns True if a match was found * * @example * const arr = [{id: 1}, {id: 2}, {id: 3}]; * const comparator = (v) => v.id; * arrayContainsObject({id: 2}, array, comparator); // Returns: true */ // eslint-disable-next-line @typescript-eslint/no-explicit-any function arrayContainsObject(object, array, comparator) { var hasDuplicate = false; // eslint-disable-next-line @typescript-eslint/prefer-for-of for (var i = 0; i < array.length; i++) { if (comparator(array[i]) === comparator(object)) { hasDuplicate = true; break; } } return hasDuplicate; } /** * Create an array with `null` & `undefined` values removed * * @param arr - The array to compact * @returns The compacted array * * @example * compactArray(['hi', null, 2, true, undefined]) // Returns: ['hi', 2, true] */ function compactArray(arr) { if (!arr || arr.length < 1) { return undefined; } var valuesToReturn = []; arr.map(function (i) { if (i === null || i === undefined || '') { return; } valuesToReturn.push(i); }); return valuesToReturn; } /** * Return a function, that, as long as it continues to be invoked, will not be triggered. The * function will be called after it stops being called for N milliseconds. * * @param func - The function to call after the debounce period * @param wait - The length of time to wait between calls (ms) * @param immediate - Whether the debounced function should be fired immediately * @param windowRef - A reference to the global window object * @returns The debounced function * * @example * const myFunc = () => {console.log('hi!')}; * const myDebouncedFunc = debounce(myFunc, 200); * myDebouncedFunc(); * myDebouncedFunc(); * myDebouncedFunc(); * // 'hi!' will only be logged once */ function debounce(func, wait, immediate, windowRef) { if (immediate === void 0) { immediate = false; } if (windowRef === void 0) { windowRef = window; } var timeout = null; return function () { var context = this; var args = arguments; var later = function () { timeout = null; if (!immediate) { func.apply(context, args); } }; var callNow = immediate && !timeout; if (timeout) { clearTimeout(timeout); } timeout = windowRef.setTimeout(later, wait); if (callNow) { func.apply(context, args); } }; } /** * Define the typeCache which will hold all action types for the entire application */ var typeCache = {}; /** * Ensure you only define an action once in the entirety of the application * * @param label - The action label * @returns uniqueLabel - The unique label * * @example * defineType('[log-in] User log in') as '[log-in] User log in'; */ function defineType(label) { // Verify the label does not already exist in the cache if (typeCache[label]) { throw new Error("Action type '" + label + "' is not unique!"); } // Save the label to the cache typeCache[label] = true; return label; } /** * Ensure action is defined only once in the entirety of the application * * @param typeEnum * * @example * export enum actionTypes { * AssignState = '[mock-meta-reducer] Assign State', * }; * defineTypeEnum(actionTypes); */ // eslint-disable-next-line @typescript-eslint/no-explicit-any function defineTypeEnum(typeEnum) { for (var val in typeEnum) { // istanbul ignore else if (typeEnum.hasOwnProperty(val)) { defineType(typeEnum[val]); } } } /** * Reset the type cache * NOTE: FOR TESTS ONLY */ function resetTypeCache() { typeCache = {}; } /* eslint-disable @typescript-eslint/no-magic-numbers */ /** * Generate a canonically formatted UUID that is Version 1 through 5 and is the appropriate Variant as per RFC4122. * * @returns The UUID * * @example * generateUUID() // Returns a UUID such as: `f4ee5eed-ed19-3681-713e-907a23ed7858` */ function generateUUID() { var buf = new Uint16Array(8); window.crypto.getRandomValues(buf); var S4 = function (num) { var ret = num.toString(16); while (ret.length < 4) { ret = "0" + ret; } return ret; }; return (S4(buf[0]) + S4(buf[1]) + "-" + S4(buf[2]) + "-" + S4(buf[3]) + "-" + S4(buf[4]) + "-" + S4(buf[5]) + S4(buf[6]) + S4(buf[7])); } /** * Return the value of a FormControl within a FormGroup * * @param form - The FormGroup that contains the control * @param controlName - The name of the control * @returns The value * * @example * getFormControlValue(myFormGroup, 'myControl'); * getFormControlValue<boolean>(myFormGroup, 'myControl'); */ function getFormControlValue(form, controlName) { if (!form || !controlName) { return undefined; } var control = form.get(controlName); return !typeGuards.isNull(control) && typeGuards.isAbstractControl(control) ? control.value : undefined; } /** * Return an object containing arrays organized by property * * @param array - The array to split * @param key - The object property to split by * @returns An object containing arrays separated by property value * * @example * interface MyObj { * a: string; * b: number; * } * const myArray: MyObj[] = [{a: 'foo', b: 1}, {a: 'bar', b: 6}, {a: 'foo', b: 6}]; * groupBy<MyObj, keyof MyObj>(myArray, 'a'); * Returns: * { * foo: [{a: 'foo', b: 1}, {a: 'foo', b: 6}], * bar: [{a: 'bar', b: 6}], * } */ function groupBy(array, key) { var initialValue = {}; return array.reduce(function (accumulator, x) { // eslint-disable-next-line @typescript-eslint/no-explicit-any var idx = x[key]; // Create an array for the property if one does not exist if (!accumulator[idx]) { accumulator[idx] = []; } // Add the item to the property array accumulator[idx].push(x); return accumulator; }, initialValue); } /** * Determine if a form control has a required validator * * @param formItem - The control or form group to check * @returns If a required control is found * * @example * const ctrl = new FormControl(null, [Validators.required]; * const group = new FormGroup({myControl: [null, [Validators.required]]}); * hasRequiredControl(ctrl); // Returns: true * hasRequiredControl(group); // Returns: true */ function hasRequiredControl(formItem) { if (!formItem) { return false; } // Dealing with FormGroup if (formItem instanceof forms.FormGroup) { var isRequired = false; // Check each control within the group // eslint-disable-next-line @typescript-eslint/prefer-for-of for (var i = 0; i < Object.keys(formItem.controls).length; i += 1) { var control = formItem.controls[Object.keys(formItem.controls)[i]]; isRequired = controlHasRequiredField(control); // Break out of the loop when we find the first required control if (isRequired) { break; } } return isRequired; } // Dealing with AbstractControl return controlHasRequiredField(formItem); } /** * Determine if a form control has a required validator * * @param control - The control to test * @returns If the control is required * * @example * const ctrl = new FormControl(null, [Validators.required]; * controlHasRequiredField(ctrl); // Returns: true */ function controlHasRequiredField(control) { var validator = control.validator ? control.validator({}) : null; return !!(validator && validator.required); } var DEFAULT_JITTER_FACTOR = .3; var DEFAULT_BACK_OFF_TIME = 2; var DEFAULT_BASE_WAIT_TIME = 100; /** * Calculate retry timing * * `jitter`: "Slight irregular movement, variation, or unsteadiness, * especially in an electrical signal or electronic device" * * @param options - The options object * - `jitter`: If the duration should be affected by a jitter effect * - `jitterFactor`: How widely the jitter effect should vary * - `backOffFactor`: How quickly the duration should back off * - `baseWaitTime`: The base time when determining sleep duration * @returns The duration to sleep * * @example * const calcOpts: DelayCalculator = { * jitter: true, * jitterFactor: .3, * backOffFactor: 2, * baseWaitTime: 100, * } * // Create a retrier with a custom backoff * retryWithBackoff({retries: 3, delayCalculator: exponentialBackoffDelayCalculator(calcOpts)}) */ var exponentialBackoffDelayCalculator = function (_a) { var _b = _a.jitter, jitter = _b === void 0 ? true : _b, _c = _a.jitterFactor, jitterFactor = _c === void 0 ? DEFAULT_JITTER_FACTOR : _c, _d = _a.backOffFactor, backOffFactor = _d === void 0 ? DEFAULT_BACK_OFF_TIME : _d, _e = _a.baseWaitTime, baseWaitTime = _e === void 0 ? DEFAULT_BASE_WAIT_TIME : _e; return function (attempt) { var sleepDuration = baseWaitTime * Math.pow(backOffFactor, attempt); if (jitter) { sleepDuration *= (1 - (jitterFactor * Math.random())); } return sleepDuration; }; }; var DEFAULT_RETRY_COUNT = 2; var ERROR_CODE_TOO_MANY_REQUESTS = 429; var ERROR_CODE_500_MIN = 500; var ERROR_CODE_500_MAX = 599; var httpRetryer = function (_a) { var _b = _a.retries, retries = _b === void 0 ? DEFAULT_RETRY_COUNT : _b, _c = _a.delayCalculator, delayCalculator = _c === void 0 ? exponentialBackoffDelayCalculator({}) : _c, _d = _a.scheduler, scheduler = _d === void 0 ? async.async : _d; return operators.retryWhen(function (errors) { return rxjs.zip(errors, rxjs.range(1, retries + 1)).pipe(operators.mergeMap(function (_a) { var _b = __read(_a, 2), err = _b[0], retry = _b[1]; if (retry > retries || !isConsideredError(err)) { return rxjs.throwError(err); } var waitTime = delayCalculator(retry); if (err.status === ERROR_CODE_TOO_MANY_REQUESTS) { var headerWaitTime = extractRetryAfterTime(err); waitTime = headerWaitTime || waitTime; } return rxjs.timer(waitTime, scheduler).pipe(operators.take(1)); })); }); }; /** * @param err */ function extractRetryAfterTime(err) { var retryHeaderValue = err.headers.get('Retry-After'); if (retryHeaderValue) { return coercion.coerceNumberProperty(retryHeaderValue, null) || coercion.coerceDateProperty(retryHeaderValue, null); } return null; } /** * @param err */ function isConsideredError(err) { if (err.hasOwnProperty('status') && err.hasOwnProperty('headers')) { var e = err; return e.status === 0 || e.status === ERROR_CODE_TOO_MANY_REQUESTS || (e.status >= ERROR_CODE_500_MIN && e.status <= ERROR_CODE_500_MAX); } return false; } /** * Helper function to parse an object with deep keys * * @param object - An object with key as string or string * @param keys - A string or array of strings * @returns String value at the lowest layer or object itself * * @example * objectDeepParse(myObject, ['foo', 'bar']) // Returns: myObject.foo.bar if found * objectDeepParse(myObject, 'foo.bar') // Returns: myObject.foo.bar if found */ // eslint-disable-next-line @typescript-eslint/no-explicit-any function objectDeepParse(object, keys) { if (typeGuards.isString(object) || typeGuards.isBoolean(object) || !object) { return object; } keys = typeGuards.isArray(keys) ? keys : keys.split('.'); object = object[keys[0]]; if (object && keys.length > 1) { return objectDeepParse(object, keys.slice(1)); } return object; } /** * Utility class to assist with pulling specific values from a `SimpleChanges` object. */ var NgChangeObjectValueParser = /** @class */ (function () { function NgChangeObjectValueParser() { } /** * Function to parse previousValue from triggered by changes on ngOnChange * * @param changes - SimpleChanges * @param path - string * @returns lowest layer value or changes object itself when path cannot be parsed * * @example * valueParser.getOldValue(myChanges, 'my.path') */ // eslint-disable-next-line @typescript-eslint/no-explicit-any NgChangeObjectValueParser.getOldValue = function (changes, path) { var _a = __read(this.parsePath(path), 2), keys = _a[0], key = _a[1]; return (key && changes[key]) ? objectDeepParse(changes[key].previousValue, keys) : undefined; }; /** * Function to parse currentValue from triggered by changes on ngOnChange * * @param changes - SimpleChanges * @param path - string * @returns lowest layer value or changes object itself when path cannot be parsed * * @example * valueParser.getNewValue(myChanges, 'my.path') */ // eslint-disable-next-line @typescript-eslint/no-explicit-any NgChangeObjectValueParser.getNewValue = function (changes, path) { var _a = __read(this.parsePath(path), 2), keys = _a[0], key = _a[1]; return (key && changes[key]) ? objectDeepParse(changes[key].currentValue, keys) : undefined; }; /** * Function to parse path to get keys for each layer * * @param path - string * @returns an array of two elements, one being an array of all the keys except first one, one being the first key * * @example * valueParser.parsePath('my.path') // Returns: [['my'], 'path'] */ NgChangeObjectValueParser.parsePath = function (path) { var keys = path.split('.'); var key = keys.shift(); if (!key) { key = keys[0]; } return [keys, key]; }; return NgChangeObjectValueParser; }()); /** * Helper function to determine if a specific value has changed * * @param changes - The object of changes * @param path - The object path in question * @returns True if the value has changed * * @example * inputHasChanged(changesObject, 'myInputName') */ function inputHasChanged(changes, path) { if (!changes || !path) { return undefined; } var oldValue = NgChangeObjectValueParser.getOldValue(changes, path); var newValue = NgChangeObjectValueParser.getNewValue(changes, path); return oldValue !== newValue; } /** * Helper function to determine if input is unset. * * @param x - the input being tested * @returns boolean * * @example * isUnset(null); // Returns: true * isUnset(undefined); // Returns: true * isUnset('hello'); // Returns: false */ // eslint-disable-next-line @typescript-eslint/no-explicit-any var isUnset = function (x) { return typeGuards.isNull(x) || typeGuards.isUndefined(x); }; /** * Placeholder function. * * @returns Undefined */ var noop = function () { return void 0; }; /** * Helper function to get an object with deep keys * * @param object - The object to query. * @param path - The string path of the property to get. * @param defaultValue - (optional) - The value returned for undefined resolved values. * @returns The updated object * * @example * const myObj = {foo: {bar: 'baz', bing: 'bang'}}; * objectDeepGet(myObj, 'foo.bar') // Returns: 'baz' * objectDeepGet(myObj, 'does.not.exist', 'hi') // Returns: 'hi' */ // eslint-disable-next-line @typescript-eslint/no-explicit-any function objectDeepGet(object, path, defaultValue) { if (!object) { return defaultValue; } var keys = path.split('.'); object = object[keys[0]]; if (object && keys.length > 1) { return objectDeepGet(object, keys.slice(1).join('.'), defaultValue); } if (object === undefined && defaultValue) { return defaultValue; } return object; } /** * Helper function to get an object with deep keys * * @param obj - The object to modify. * @param keys - The path of the property to set. * @param value - The value to set. * @returns The updated object * * @example * const myObj: MyObjType = { * foo: { * bar: { * baz: true, * }, * }, * }; * const updatedObject = objectDeepSet(myObj, 'foo.bar.baz', false); * const updatedObject = objectDeepSet<boolean, MyObjType>(myObj, 'foo.bar.baz', false); */ // eslint-disable-next-line @typescript-eslint/no-explicit-any function objectDeepSet(obj, keys, value) { var _a, _b; var paths = keys.split('.'); if (paths.length === 1) { var path_1 = paths[0]; return (__assign(__assign({}, obj), (_a = {}, _a[path_1] = value, _a))); } var _c = __read(paths), path = _c[0], remainingPaths = _c.slice(1); var nestedObj = obj[path]; var newNestedObj = objectDeepSet(nestedObj, remainingPaths.join('.'), value); return (__assign(__assign({}, obj), (_b = {}, _b[path] = newNestedObj, _b))); } var DEFAULT_RETRY_COUNT$1 = 3; /** * Return the difference in time in words * * @param options - The options object * - `retries`: How many times it should retry before throwing an error * - `delayCalculator`: The calculator to determine the delay timing * @returns The observable timer * * @example * return this.exampleDatabase.getSomething() * .pipe( * map((res: MyResponse) => { * if (res) { * return res; * } else { * return null; * } * }), * retryWithBackoff({}), // Using default options * ) * ; */ var retryWithBackoff = function (_a) { var _b = _a.retries, retries = _b === void 0 ? DEFAULT_RETRY_COUNT$1 : _b, _c = _a.delayCalculator, delayCalculator = _c === void 0 ? exponentialBackoffDelayCalculator({}) : _c; return operators.retryWhen(function (errors) { return rxjs.zip(errors, rxjs.range(1, retries)) .pipe(operators.mergeMap(function (_a) { var _b = __read(_a, 2), err = _b[0], retry = _b[1]; if (retry >= retries) { return rxjs.throwError(err); } return rxjs.timer(delayCalculator(retry)); })); }); }; /** * Helper function to return an array of values from an hash object * * @param keys - The array containing the key values (number|string) to retrieve from the hash * @param hash - The object to pull values from * @returns The array of values that match keys * * @example * const tactic1: MyType = { * id: 1, * name: 'tactic1', * goal: 'goal1', * } * const tactic2: MyType = { * id: 2, * name: 'tactic2', * goal: 'goal2', * } * const tactics = { 1: tactic1, 2: tactic2 } * returnValuesByKeys<MyType>([1], tactics) // Returns: `[tactic1]` */ function returnValuesByKeys(keys, hash) { var e_1, _a; var stringyKeys = keys.map(function (id) { return id.toString(); }); var values = []; try { for (var stringyKeys_1 = __values(stringyKeys), stringyKeys_1_1 = stringyKeys_1.next(); !stringyKeys_1_1.done; stringyKeys_1_1 = stringyKeys_1.next()) { var key = stringyKeys_1_1.value; // istanbul ignore else if (hash[key]) { values.push(hash[key]); } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (stringyKeys_1_1 && !stringyKeys_1_1.done && (_a = stringyKeys_1.return)) _a.call(stringyKeys_1); } finally { if (e_1) throw e_1.error; } } return values; } /** * Round a number * * Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round#A_better_solution * * @param num - The number to round (also accepting strings for exponential support) * @param precision - How precise to make the rounding * @returns The rounded number * * @example * roundNumber(1.050, 1) // Returns: `1.1` * roundNumber(3456.3456, 1) // Returns: `3456.3` * roundNumber(3456.3456, -2) // Returns: `3500` * roundNumber('1.23e+5', -4) // Returns: `120000` */ function roundNumber(num, precision) { if (precision === void 0) { precision = 0; } if (!typeGuards.isNumber(num)) { return undefined; } var shift = function (innerNum, innerPrecision) { var numArray = innerNum.toString().split('e'); return +(numArray[0] + "e" + (numArray[1] ? (+numArray[1] + innerPrecision) : innerPrecision)); }; return shift(Math.round(shift(num, +precision)), -precision); } /** * Set the value of a FormControl * * @param form - The FormGroup * @param controlName - The name of the control * @param controlValue - The value to set the control to * * @example * setFormControlValue<number>(myForm, 'budget', 50); */ function setFormControlValue(form, controlName, controlValue) { if (!form || !controlName) { return; } var control = form.get(controlName); if (control) { control.setValue(controlValue); } } /* * 'Inspired' by https://github.com/sindresorhus/camelcase */ /** * Function that preserves camel case * * @param input - The string input * @returns The adjusted string */ function preserveCamelCase(input) { var isLastCharLower = false; var isLastCharUpper = false; var isLastLastCharUpper = false; for (var i = 0; i < input.length; i++) { var c = input[i]; if (isLastCharLower && /[a-zA-Z]/.test(c) && c.toUpperCase() === c) { input = input.slice(0, i) + "-" + input.slice(i); isLastCharLower = false; isLastLastCharUpper = isLastCharUpper; isLastCharUpper = true; i++; } else if (isLastCharUpper && isLastLastCharUpper && /[a-zA-Z]/.test(c) && c.toLowerCase() === c) { input = input.slice(0, i - 1) + "-" + input.slice(i - 1); isLastLastCharUpper = isLastCharUpper; isLastCharUpper = false; isLastCharLower = true; } else { isLastCharLower = c.toLowerCase() === c; isLastLastCharUpper = isLastCharUpper; isLastCharUpper = c.toUpperCase() === c; } } return input; } /** * Post process a conversion into PascalCase if necessary * * @param x - The string * @param pascalCase - A boolean representing if the string should be converted to PascalCase * @returns The final string */ var postProcess = function (x, pascalCase) { return (pascalCase ? x.charAt(0).toUpperCase() + x.slice(1) : x); }; var ɵ0 = postProcess; /** * Convert a string to camelCase * * @param input - The string to convert * @param pascalCase - A boolean representing if the string should be converted to PascalCase * @returns The camelCase version of the string * * @example * toCamelCase('MY_TEXT') // Returns: `myText` * toCamelCase('MY_TEXT', true) // Returns: `MyText` */ function toCamelCase(input, pascalCase) { if (pascalCase === void 0) { pascalCase = false; } if (!input) { return undefined; } // Trim whitespace input = input.trim(); // Test for a single character if (input.length === 1) { return pascalCase ? input.toUpperCase() : input.toLowerCase(); } // Test if we are dealing with a single lowercased word if (/^[a-z\d]+$/.test(input)) { return postProcess(input, pascalCase); } // Test if there are any uppercase if (input !== input.toLowerCase()) { input = preserveCamelCase(input); } input = input .replace(/^[_.\- ]+/, '') .toLowerCase() .replace(/[_.\- ]+(\w|$)/g, function (m, p1) { return p1.toUpperCase(); }); return postProcess(input, pascalCase); } /** * Patch the component with unsubscribe behavior * * @param component - The component class (`this` context) * @returns An observable representing the unsubscribe event */ function componentDestroyed(component) { if (component.componentDestroyed$) { return component.componentDestroyed$; } // eslint-disable-next-line @angular-eslint/no-lifecycle-call var oldNgOnDestroy = component.ngOnDestroy; var stop$ = new rxjs.ReplaySubject(); // eslint-disable-next-line @angular-eslint/no-lifecycle-call component.ngOnDestroy = function () { // istanbul ignore else if (oldNgOnDestroy) { oldNgOnDestroy.apply(component); } stop$.next(true); stop$.complete(); }; component.componentDestroyed$ = stop$.asObservable(); return component.componentDestroyed$; } /** * A pipe-able operator to unsubscribe during OnDestroy lifecycle event * * @param component - The component class (`this` context) * @returns The component wrapped in an Observable * * @example * source.pipe(untilComponentDestroyed(this)).subscribe... */ var untilComponentDestroyed = // eslint-disable-next-line max-len function (component) { return function (source) { return source.pipe(operators.takeUntil(componentDestroyed(component))); }; }; /** * Helper function to determine if a specific value has changed * * @param changes - The object of changes * @param path - A string with keys defined, separate with '.' * @param control - The formControl * @returns True if the value has changed * * @example * ... * AngularInput: * public myInput; * AngularInput: * public myFormControl; * * ngOnChanges(changes: SimpleChanges) { * // This will update the form control's value whenever the `@Input` value changes: * updateControlOnInputChanges(changes, 'myInput', this.myFormControl)); * } * ... */ function updateControlOnInputChanges(changes, path, control) { if (!changes || !path || !control) { return false; } if (inputHasChanged(changes, path)) { var newValue = NgChangeObjectValueParser.getNewValue(changes, path); control.setValue(newValue); return true; } return false; } /** * Create version information from a version string * * @example * VERSION.full // Returns: 1.2.3 * VERSION.major // Returns: 1 * VERSION.minor // Returns: 2 * VERSION.patch // Returns: 3 */ var Version = /** @class */ (function () { function Version(full) { this.full = full; var parts = full.split('.'); var itemsToRemoveForPatch = 2; this.major = parts[0]; this.minor = parts[1]; this.patch = parts.slice(itemsToRemoveForPatch).join('.'); } return Version; }()); var VERSION = new Version('8.0.6'); exports.NgChangeObjectValueParser = NgChangeObjectValueParser; exports.VERSION = VERSION; exports.Version = Version; exports.abbreviateNumber = abbreviateNumber; exports.applyMixins = applyMixins; exports.arrayContainsObject = arrayContainsObject; exports.compactArray = compactArray; exports.componentDestroyed = componentDestroyed; exports.debounce = debounce; exports.defineType = defineType; exports.defineTypeEnum = defineTypeEnum; exports.exponentialBackoffDelayCalculator = exponentialBackoffDelayCalculator; exports.generateUUID = generateUUID; exports.getFormControlValue = getFormControlValue; exports.groupBy = groupBy; exports.hasRequiredControl = hasRequiredControl; exports.httpRetryer = httpRetryer; exports.inputHasChanged = inputHasChanged; exports.isUnset = isUnset; exports.noop = noop; exports.objectDeepGet = objectDeepGet; exports.objectDeepParse = objectDeepParse; exports.objectDeepSet = objectDeepSet; exports.resetTypeCache = resetTypeCache; exports.retryWithBackoff = retryWithBackoff; exports.returnValuesByKeys = returnValuesByKeys; exports.roundNumber = roundNumber; exports.setFormControlValue = setFormControlValue; exports.toCamelCase = toCamelCase; exports.untilComponentDestroyed = untilComponentDestroyed; exports.updateControlOnInputChanges = updateControlOnInputChanges; exports0 = ɵ0; Object.defineProperty(exports, '__esModule', { value: true }); }))); //# sourceMappingURL=terminus-ngx-tools-utilities.umd.js.map