@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
902 lines (872 loc) • 29.4 kB
JavaScript
import { isNull, isAbstractControl, isString, isBoolean, isArray, isUndefined, isNumber } from '@terminus/ngx-tools/type-guards';
import { FormGroup } from '@angular/forms';
import { __read, __assign, __values } from 'tslib';
import { coerceNumberProperty, coerceDateProperty } from '@terminus/ngx-tools/coercion';
import { zip, range, throwError, timer, ReplaySubject } from 'rxjs';
import { async } from 'rxjs/internal/scheduler/async';
import { retryWhen, mergeMap, take, takeUntil } from 'rxjs/operators';
/**
* 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 !isNull(control) && 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 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 : _d;
return retryWhen(function (errors) { return zip(errors, range(1, retries + 1)).pipe(mergeMap(function (_a) {
var _b = __read(_a, 2), err = _b[0], retry = _b[1];
if (retry > retries || !isConsideredError(err)) {
return throwError(err);
}
var waitTime = delayCalculator(retry);
if (err.status === ERROR_CODE_TOO_MANY_REQUESTS) {
var headerWaitTime = extractRetryAfterTime(err);
waitTime = headerWaitTime || waitTime;
}
return timer(waitTime, scheduler).pipe(take(1));
})); });
};
/**
* @param err
*/
function extractRetryAfterTime(err) {
var retryHeaderValue = err.headers.get('Retry-After');
if (retryHeaderValue) {
return coerceNumberProperty(retryHeaderValue, null)
|| 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 (isString(object) || isBoolean(object) || !object) {
return object;
}
keys = 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 isNull(x) || 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 retryWhen(function (errors) { return zip(errors, range(1, retries))
.pipe(mergeMap(function (_a) {
var _b = __read(_a, 2), err = _b[0], retry = _b[1];
if (retry >= retries) {
return throwError(err);
}
return 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 (!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 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(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');
/**
* Generated bundle index. Do not edit.
*/
export { NgChangeObjectValueParser, VERSION, Version, abbreviateNumber, applyMixins, arrayContainsObject, compactArray, componentDestroyed, debounce, defineType, defineTypeEnum, exponentialBackoffDelayCalculator, generateUUID, getFormControlValue, groupBy, hasRequiredControl, httpRetryer, inputHasChanged, isUnset, noop, objectDeepGet, objectDeepParse, objectDeepSet, resetTypeCache, retryWithBackoff, returnValuesByKeys, roundNumber, setFormControlValue, toCamelCase, untilComponentDestroyed, updateControlOnInputChanges, ɵ0 };
//# sourceMappingURL=terminus-ngx-tools-utilities.js.map