import { cx as classNames } from '@linaria/core' ; import type { ClassName } from '@linaria/core/types/cx' ; import deepmerge from 'deepmerge' ; import fastDeepEqual from 'fast-deep-equal' ; import { BaseError } from 'make-error' ; import omit from 'object.omit' ; import pick from 'object.pick' ; import { __INTERNAL_REMIRROR_IDENTIFIER_KEY__ } from '@remirror/core-constants' ; import type { AnyConstructor , AnyFunction , ConditionalExcept , JsonPrimitive , Nullable , Primitive , Shape , UnknownShape , } from '@remirror/types' ; type TupleRange < Size extends number > = Size extends Size ? number extends Size ? number [ ] : _NumberRangeTuple < [ ] , Size > : never ; type _NumberRangeTuple < Tuple extends readonly unknown [ ] , Length extends number > = Tuple [ 'length' ] extends Length ? Tuple : _NumberRangeTuple < [ ... Tuple , Tuple [ 'length' ] ] , Length > ; param arg export function Cast < Type = any > ( value ) { return value as Type ; } /**
 * Get the key from a given value. Throw an error if the referenced property is
 * `undefined`.
 */ export function assertGet < Value extends object , Key extends keyof Value > ( value , key , message ? ) { const prop = value [ key ] ; assert ( ! isUndefined ( prop ) , message ) ; return prop ; } /**
 * Assert the value is `truthy`. Good for defensive programming, especially
 * after enabling `noUncheckedIndexedAccess` in the tsconfig `compilerOptions`.
 */ export function assert ( testValue , message ? ) { if ( ! testValue ) { throw new AssertionError ( message ) ; } } class AssertionError extends BaseError { name = 'AssertionError' ; } /**
 * A typesafe implementation of `Object.entries()`
 *
 * Taken from
 * https://github.com/biggyspender/ts-entries/blob/master/src/ts-entries.ts
 */ export function entries < Type extends object , Key extends Extract < keyof Type , string > , Value extends Type [ Key ] , Entry extends [ Key , Value ] > ( value ) { return Object . entries ( value ) as Entry [ ] ; } /**
 * A typesafe implementation of `Object.keys()`
 */ export function keys < Type extends object , Key extends Extract < keyof Type , string > > ( value ) { return Object . keys ( value ) as Key [ ] ; } /**
 * A typesafe implementation of `Object.values()`
 */ export function values < Type extends object , Key extends Extract < keyof Type , string > , Value extends Type [ Key ] > ( value ) { return Object . values ( value ) as Value [ ] ; } /**
 * A more lenient typed version of `Array.prototype.includes` which allow less
 * specific types to be checked.
 */ export function includes < Type > ( array , item , fromIndex ? ) { return array . includes ( item as Type , fromIndex ) ; } param value export function object < Type extends object > ( value ? ) { return Object . assign ( Object . create ( null ) , value ) ; } private enum TypeName { Object = 'Object' , RegExp = 'RegExp' , Date = 'Date' , Promise = 'Promise' , Error = 'Error' , Map = 'Map' , Set = 'Set' } /**
 * Alias of toString for non-dom environments.
 *
 * This is a safe way of calling `toString` on objects created with
 * `Object.create(null)`.
 */ export function toString ( value ) { return Object . prototype . toString . call ( value ) ; } param value function getObjectType ( value ) { const objectName = toString ( value ) . slice ( 8 , - 1 ) ; return objectName as TypeName ; } param type returns function isOfType < Type > ( type , predicate ? ) { return ( value ) : value is Type => { if ( typeof value !== type ) { return false ; } return predicate ? predicate ( value as Type ) : true ; } ; } param type private function isObjectOfType < Type > ( type ) { return ( value ) : value is Type => getObjectType ( value ) === type ; } /**
 * Check if an instance is the direct instance of the provided class.
 */ export function isDirectInstanceOf < Type > ( instance , Constructor ) { return Object . getPrototypeOf ( instance ) === Constructor . prototype ; } param value export const isUndefined = isOfType < undefined > ( 'undefined' ) ; param value export const isString = isOfType < string > ( 'string' ) ; param value export const isNumber = isOfType < number > ( 'number' , ( value ) => { return ! Number . isNaN ( value ) ; } ) ; param value export const isFunction = isOfType < AnyFunction > ( 'function' ) ; param value export function isNull ( value ) { return value === null ; } deprecated param value export function isClass ( value ) { return isFunction ( value ) && value . toString ( ) . startsWith ( 'class ' ) ; } param value export function isBoolean ( value ) { return value === true || value === false ; } param value export const isSymbol = isOfType < symbol > ( 'symbol' ) ; param value export function isInteger ( value ) { return Number . isInteger ( value as number ) ; } param value export function isSafeInteger ( value ) { return Number . isSafeInteger ( value as number ) ; } param value export function isPlainObject < Type = unknown > ( value ) { if ( getObjectType ( value ) !== TypeName . Object ) { return false ; } const prototype = Object . getPrototypeOf ( value ) ; return prototype === null || prototype === Object . getPrototypeOf ( { } ) ; } /**
 * Predicate check for whether passed in value is a primitive value
 */ export function isPrimitive ( value ) { return value == null || /^[bns]/ . test ( typeof value ) ; } /**
 * Predicate check for whether passed in value is a JSON primitive value
 */ export function isJSONPrimitive ( value ) { return value === null || [ 'boolean' , 'number' , 'string' ] . includes ( typeof value ) ; } param value export function isNullOrUndefined ( value ) { return isNull ( value ) || isUndefined ( value ) ; } param value export function isObject < Type extends Shape > ( value ) { return ! isNullOrUndefined ( value ) && ( isFunction ( value ) || isOfType ( 'object' ) ( value ) ) ; } /**
 * A shorthand method for creating instance of checks.
 */ export function isInstanceOf < Constructor extends AnyConstructor > ( Constructor ) { return ( value ) : value is InstanceType < Constructor > => isObject ( value ) && value instanceof Constructor ; } param value export function isNativePromise ( value ) { return isObjectOfType < Promise < unknown > > ( TypeName . Promise ) ( value ) ; } param value const hasPromiseAPI = ( value ) : value is Promise < unknown > => { return ! ! ( ! isNull ( value ) && ( isObject ( value ) as unknown ) && isFunction ( ( value as Promise < unknown > ) . then ) && isFunction ( ( value as Promise < unknown > ) . catch ) ) ; } ; param value export function isPromise ( value ) { return isNativePromise ( value ) || hasPromiseAPI ( value ) ; } param value export const isRegExp = isObjectOfType < RegExp > ( TypeName . RegExp ) ; param value export const isDate = isObjectOfType < Date > ( TypeName . Date ) ; param value export const isError = isObjectOfType < Error > ( TypeName . Error ) ; param value export function isMap ( value ) { return isObjectOfType < Map < unknown , unknown > > ( TypeName . Map ) ( value ) ; } param value export function isSet ( value ) { return isObjectOfType < Set < unknown > > ( TypeName . Set ) ( value ) ; } param value export function isEmptyObject ( value ) { return isObject ( value ) && ! isMap ( value ) && ! isSet ( value ) && Object . keys ( value ) . length === 0 ; } /**
 * Alias the isArray method.
 */ export const isArray = Array . isArray ; param value export function isEmptyArray ( value ) { return isArray ( value ) && value . length === 0 ; } param value export function isNonEmptyArray < Item > ( value ) { return isArray ( value ) && value . length > 0 ; } param str export function capitalize ( string ) { return string . charAt ( 0 ) . toUpperCase ( ) + string . slice ( 1 ) ; } param str export function format ( value ) { value = value . trim ( ) ; return /^(?:webOS|i(?:OS|P))/ . test ( value ) ? value : capitalize ( value ) ; } param fn param args export function callIfDefined < Method extends AnyFunction > ( fn , ... args ) { if ( isFunction ( fn ) ) { fn ( ... args ) ; } } param text param regexp export function findMatches ( text , regexp , runWhile = ( match ) => ! ! match ) { regexp . lastIndex = 0 ; const results = [ ] ; const flags = regexp . flags ; let match ; if ( ! flags . includes ( 'g' ) ) { regexp = new RegExp ( regexp . source , `g${ flags }` ) ; } do { match = regexp . exec ( text ) ; if ( match ) { results . push ( match ) ; } } while ( runWhile ( match ) ) ; regexp . lastIndex = 0 ; return results ; } param os param pattern param label returns export function cleanupOS ( os , pattern ? , label ? ) { if ( pattern && label ) { os = os . replace ( new RegExp ( pattern , 'i' ) , label ) ; } return format ( os . replace ( / ce$/i , ' CE' ) . replace ( /\bhpw/i , 'web' ) . replace ( /\bMacintosh\b/ , 'Mac OS' ) . replace ( /_powerpc\b/i , ' OS' ) . replace ( /\b(os x) [^\d ]+/i , '$1' ) . replace ( /\bMac (OS X)\b/ , '$1' ) . replace ( /\/(\d)/ , ' $1' ) . replace ( /_/g , '.' ) . replace ( /(?: bepc|[ .]*fc[\d .]+)$/i , '' ) . replace ( /\bx86\.64\b/gi , 'x86_64' ) . replace ( /\b(Windows Phone) OS\b/ , '$1' ) . replace ( /\b(Chrome OS \w+) [\d.]+\b/ , '$1' ) . split ( ' on ' ) [ 0 ] ?? '' ) ; } /**
 * A utility function to check whether the current browser is running on the
 * android platform.
 */ export function isAndroidOS ( ) { const ua = navigator . userAgent ; const match = new RegExp ( '\\b' + 'Android' + '(?:/[\\d.]+|[ \\w.]*)' , 'i' ) . exec ( ua ) ; if ( ! match ) { return false ; } return cleanupOS ( match [ 0 ] ?? '' , 'Android' , 'Android' ) . includes ( 'Android' ) ; } param min param max export function randomFloat ( min , max ? ) { if ( ! max ) { max = min ; min = 0 ; } return Math . random ( ) * ( max - min + 1 ) + min ; } param min param max export function randomInt ( min , max ? ) { return Math . floor ( randomFloat ( min , max ) ) ; } param str export function startCase ( string ) { return string . replace ( /_/g , ' ' ) . replace ( /([a-z])([A-Z])/g , ( _ , $1 , $2 ) => `${ $1 } ${ $2 }` ) . replace ( /(\s|^)(\w)/g , ( _ , $1 , $2 ) => `${ $1 }${ $2 . toUpperCase ( ) }` ) ; } /**
 * Returns a number that is unique during the runtime of this code.
 */ function n ( ) { const time = Date . now ( ) ; const last = n . last || time ; return ( n . last = time > last ? time : last + 1 ) ; } n . last = 0 ; param prefix returns export function uniqueId ( prefix = '' ) { return `${ prefix }${ n ( ) . toString ( 36 ) }` ; } param arr param num export function take < Type > ( array , number ) { number = Math . max ( Math . min ( 0 , number ) , number ) ; return array . slice ( 0 , number ) ; } /**
 * Remove the undefined values from an object.
 */ export function omitUndefined < Type extends object > ( object ) { return omit ( object , ( value ) => ! isUndefined ( value ) ) as any ; } param value export function clone < Type extends object > ( value ) { if ( ! isPlainObject ( value ) ) { throw new Error ( 'An invalid value was passed into this clone utility. Expected a plain object' ) ; } return { ... value } ; } /**
 * Shallow clone an object while preserving it's getters and setters. This is a
 * an alternative to the spread clone.
 */ export function shallowClone < Type extends object > ( value ) { const clone = Object . create ( Object . getPrototypeOf ( value ) ) ; const descriptors = Object . getOwnPropertyDescriptors ( value ) ; Object . defineProperties ( clone , descriptors ) ; return clone ; } /**
 * Alias for fast deep equal
 */ export const isEqual = fastDeepEqual ; param array param fromStart returns export function uniqueArray < Type > ( array , fromStart = false ) { const array_ = fromStart ? [ ... array ] . reverse ( ) : array ; const set = new Set ( array_ ) ; return fromStart ? [ ... set ] . reverse ( ) : [ ... set ] ; } param array export function flattenArray < Type > ( array ) { const flattened = [ ] ; for ( const item of array ) { const itemsToInsert = isArray ( item ) ? flattenArray ( item ) : [ item ] ; flattened . push ( ... itemsToInsert ) ; } return flattened ; } /**
 * noop is a shorthand way of saying `No Operation` and is a function that does
 * nothing.
 *
 * And Sometimes doing nothing is the best policy.
 */ export function noop ( ) { return ; } /**
 * A deep merge which only merges plain objects and Arrays. It clones the object
 * before the merge so will not mutate any of the passed in values.
 *
 * To completely remove a key you can use the `Merge` helper class which
 * replaces it's key with a completely new object
 */ export function deepMerge < Type = any > ( ... objects ) { return deepmerge . all < Type > ( objects as any , { isMergeableObject : isPlainObject } ) ; } interface ClampProps { min : number ; max : number ; value : number ; } /**
 * Clamps the value to the provided range.
 */ export function clamp ( { min , max , value } ) { if ( value < min ) { return min ; } return value > max ? max : value ; } /**
 * Get the last element of the array.
 */ export function last < Type > ( array ) { return array [ array . length - 1 ] as Type ; } param array param compareFn export function sort < Type > ( array , compareFn ) { return [ ... array ] . map ( ( value , index ) => ( { value , index } ) ) . sort ( ( a , z ) => compareFn ( a . value , z . value ) || a . index - z . index ) . map ( ( { value } ) => value ) ; } param obj param path export function get < Return > ( root , path , defaultValue ? ) { try { if ( isString ( path ) && path in root ) { return ( root as any ) [ path ] ; } if ( isArray ( path ) ) { path = `['${ path . join ( "']['" ) }']` ; } let obj = root ; path . replace ( /\[\s*(["'])(.*?)\1\s*]|^\s*(\w+)\s*(?=\.|\[|$)|\.\s*(\w*)\s*(?=\.|\[|$)|\[\s*(-?\d+)\s*]/g , ( _ , __ , quotedProp , firstLevel , namedProp , index ) => { obj = obj [ quotedProp || firstLevel || namedProp || index ] ; return '' ; } ) ; return ( obj === undefined ? defaultValue : obj ) as Return ; } catch { return defaultValue as Return ; } } function setPropInternal < Type extends object = any > ( path , obj , value , index ) { if ( path . length === index ) { return value ; } obj = obj || { } ; const key = path [ index ] ; assert ( key ) ; return setClone ( obj , key , setPropInternal ( path , obj [ key ] , value , ++ index ) ) ; } function setClone ( obj , key , value ) { const newObj = clone ( obj ) ; newObj [ key ] = value ; return newObj ; } /**
 * Set the value of a given path for the provided object. Does not mutate the
 * original object.
 */ export function set ( path , obj , value ) { if ( isNumber ( path ) ) { return setClone ( obj , path , value ) ; } if ( isString ( path ) ) { path = path . split ( '.' ) ; } return setPropInternal ( path , obj , value , 0 ) ; } /**
 * Unset the value of a given path within an object.
 */ export function unset ( path , target ) { const clonedObject = clone ( target ) ; let value = clonedObject ; for ( const [ index , key ] of path . entries ( ) ) { const shouldDelete = index >= path . length - 1 ; let item = value [ key ] ; if ( shouldDelete ) { if ( isArray ( value ) ) { const indexKey = Number . parseInt ( key . toString ( ) , 10 ) ; if ( isNumber ( indexKey ) ) { value . splice ( indexKey , 1 ) ; } } else { Reflect . deleteProperty ( value , key ) ; } return clonedObject ; } if ( isPrimitive ( item ) ) { return clonedObject ; } item = isArray ( item ) ? [ ... item ] : { ... item } ; value [ key ] = item ; value = item ; } return clonedObject ; } function makeFunctionForUniqueBy < Item = any > ( value ) { return ( item ) => { return get ( item , value as string ) ; } ; } param array param getValue param fromStart export function uniqueBy < Item = any > ( array , getValue , fromStart = false ) { const unique = [ ] ; const found = new Set ( ) ; const getter = isFunction ( getValue ) ? getValue : makeFunctionForUniqueBy ( getValue ) ; const list = fromStart ? [ ... array ] . reverse ( ) : array ; for ( const item of list ) { const value = getter ( item ) ; if ( ! found . has ( value ) ) { found . add ( value ) ; unique . push ( item ) ; } } return fromStart ? unique . reverse ( ) : unique ; } /**
 * Create a range from start to end.
 *
 * If only start is provided it creates an array of the size provided. if start
 * and end are provided it creates an array who's first position is start and
 * final position is end. i.e. `length = (end - start) + 1`.
 *
 * If you'd like to create a typed tuple of up to `40` items then pass in a
 * `[number]` tuple as the first argument.
 */ export function range < Size extends number > ( size ) ; export function range ( size ) ; export function range ( start , end ) ; export function range ( start , end ? ) { const startValue = isArray ( start ) ? start [ 0 ] : start ; if ( ! isNumber ( end ) ) { return Array . from ( { length : Math . abs ( startValue ) } , ( _ , index ) => ( startValue < 0 ? - 1 : 1 ) * index ) ; } if ( startValue <= end ) { return Array . from ( { length : end + 1 - startValue } , ( _ , index ) => index + startValue ) ; } return Array . from ( { length : startValue + 1 - end } , ( _ , index ) => - 1 * index + startValue ) ; } param value export function within ( value , ... rest ) { const numbers = rest . filter < number > ( isNumber ) ; return value >= Math . min ( ... numbers ) && value <= Math . max ( ... numbers ) ; } remarks See  https param obj param key template Obj template Property export function hasOwnProperty < Obj extends object , Property extends string | number | symbol > ( object_ , key ) { return Object . prototype . hasOwnProperty . call ( object_ , key ) ; } /**
 * Helper for getting an array from a function or array.
 */ export function getLazyArray < Type > ( value ) { if ( isFunction ( value ) ) { return value ( ) ; } return value ; } export function cx ( ... classes ) { return uniqueArray ( classNames ( ... classes ) . split ( ' ' ) ) . join ( ' ' ) ; } export { camelCase , capitalCase , constantCase , kebabCase , pascalCase , pathCase , snakeCase , spaceCase , } from 'case-anything' ; export { debounce , throttle } from 'throttle-debounce' ; export { omit , pick } ;