Global

Members

(constant) PLAIN

The letters NFKD cannot help with, because they carry no separable combining mark: the ones written through the glyph (Đ, Ø, Ŧ), the ones that are two letters wearing one (Æ, ß, Þ), and Turkish ı, which is a letter in its own right rather than an i missing something. Serbian đ is the one that matters here; the rest are the same shape of problem next door.

Deliberately stops at the living orthographies. The IPA and Africanist letters — Ɔ, Ɛ, Ʃ, Ʒ and the click letters — survive whole, because in the texts they appear in the letter is the content and folding it to O, E, S, 3 would destroy the word.

Source:

(constant) PLAIN_RE

Runs before NFKD, and the order is the point: Ŀ has a compatibility decomposition to L + ·, so after NFKD there is no Ŀ left to match and the middle dot survives into the output as a stray character. Every replacement is ASCII, so decomposing afterwards has nothing left to do to them.

Source:

Methods

basicUID(safe)

Basic timestamp first UID generator that's good enough for most use cases but not for security purposes. There's an extremely small chance of collision, so create a map object to check for collisions if you're worried about that.

  • Date.now().toString(16) is used for the timestamp, which is a base16 representation of the current timestamp in milliseconds.
  • random().toString(16).substring(2) is used for the random number, which is a base16 representation of a random number between 0 and 1, with the first two characters removed.
Source:
Parameters:
Name Type Description
safe boolean

Defaults to false, if true will use a cryptographically secure random number generator for the random number improving security but reducing performance. If crypto is not available, will use Math.random() instead.

Returns:

string

Example
basicUID() // => '18d4613e4d2-750bf066ac6158'

clamp(value, min, max) → {number}

Hold a number inside an inclusive range.

NaN comes back as NaN: neither comparison is true of it, and a range check that quietly turned it into a bound would be the wrong answer wearing a right one's clothes.

Source:
Parameters:
Name Type Description
value number

The number to hold

min number

Lowest it may be

max number

Highest it may be

Returns:
Type:
number
Example
clamp(5, 0, 10) // => 5
clamp(-1, 0, 10) // => 0
clamp(11, 0, 10) // => 10
clamp(-8, -2, 2) // => -2, which is how a magnitude is capped with its sign kept

clone(o) → {T}

Deep clone for data. The copy shares no mutable structure with the original, the object graph survives — a value referenced twice is one object in the copy too, and a cycle terminates — and prototypes are kept, so a class instance clones into an instance of its class rather than a plain object.

The pair to deepEqual: whatever deepEqual reads as data, clone reproduces, so deepEqual(clone(x), x) holds. Handles plain and null-prototype objects, class instances, arrays including holes and subclasses, Date, RegExp with its lastIndex, Map, Set, Error with its non-enumerable message and stack, boxed primitives, ArrayBuffer, DataView and typed arrays — views over one buffer clone into views over one buffer.

Anything it does not recognise is shared by reference, not copied — a function, a DOM node, a Promise, a WeakMap, a SharedArrayBuffer, a host object. That is the difference worth having: structuredClone raises DataCloneError on all of them, so it cannot touch an options object carrying a callback or an element reference, which is most of the objects a page actually holds. Reproducing a value it cannot inspect would be the broken half-copy, so it shares instead — and never throws.

Versus the field, from bench/clone against structuredClone, rfdc 1.4.1, lodash 4.18.1, es-toolkit 1.50.0 and a JSON round-trip. rfdc is shown with its defaults, which is what rfdc() gives you; {circles: true} buys it the cycle row for 1–13%. The last four rows are semantics choices, not defects in the others; the rest are data the copy either kept or lost:

Input here structuredClone rfdc lodash es-toolkit JSON
Date, Map, Set cloned cloned cloned cloned cloned {}, or an ISO string
RegExp cloned cloned {} cloned cloned {}
typed array, ArrayBuffer, DataView cloned cloned {} cloned cloned {}
two views over one buffer one buffer one buffer lost two buffers two buffers lost
cycle terminates terminates stack overflow terminates terminates TypeError
repeated reference one object one object two objects one object one object two objects
Error with an assigned .code all of it .code dropped .code only whole Error is {} all of it .code only
undefined value kept kept kept kept kept dropped
nesting 20,000 deep RangeError RangeError RangeError RangeError RangeError survives
function, Promise, WeakMap shared DataCloneError function shared, rest lost shared shared dropped
class instance an instance plain object plain object an instance an instance plain object
null-prototype object kept null gains Object.prototype gains it gains it kept null gains it
symbol key kept dropped dropped kept kept dropped

It recurses, so depth is bounded by the stack — 200 levels is nothing, 20,000 throws. A JSON round-trip is the only column that survives that, being a loop in C++, and it loses thirteen of the eighteen scored rows to be there.

The cost, on a flat eight-key object: rfdc 7.2M ops/s, this 4.0M, es-toolkit 2.4M, lodash 2.0M, ramda 1.8M, a JSON round-trip 1.7M, structuredClone 775k. rfdc leads the object shapes by 1.1–2.9×, and that lead is what its defaults buy — the six rows above where the copy comes back missing the data. If you clone plain acyclic JSON in a hot loop, use rfdc; if you want the copy to still be the value you cloned, use this.

Shape decides it, though, and this is not uniformly ahead. On an array of 10,000 numbers es-toolkit does 14k ops/s against 3k here, with structuredClone at 6k: a long flat run of primitives is what a per-key walk is worst at and a specialised array path is best at. If that is your data, this is the wrong function for it.

Where structuredClone applies — pure data, no functions or nodes — it is still the one to reach for if you are not already importing this: it ships with the platform and costs you nothing. What it is not is reliably faster. A structured clone is a serialise and a deserialise rather than a walk, so it runs 1.5–5× behind on objects and roughly 2× ahead on that flat number array, on top of dropping prototypes, symbol keys and an Error's own properties.

Source:
Parameters:
Name Type Description
o T

The value to clone

Returns:
Type:
T

The cloned value; primitives, functions and symbols come back as themselves

Examples
const obj = { foo: 'bar', when: new Date(0), tags: new Set(['a']) }
const copy = clone(obj)
copy.foo = 'baz'
console.log(obj.foo, copy.foo) // 'bar' 'baz'
console.log(copy.when instanceof Date, copy.tags.has('a')) // true true
const options = { el: document.body, onDone: () => {} }
clone(options).onDone === options.onDone // => true, shared, not cloned
structuredClone(options) // => throws DataCloneError
const cyclic = { name: 'root' }
cyclic.self = cyclic
clone(cyclic).self === clone(cyclic) // => false, but each copy's .self is itself

closestNumber(goal, arr)

Finds the closest number to the set goal in an array to a given number

Source:
Parameters:
Name Type Description
goal number

Number to search for

arr Array

Array of numbers to search in

Returns:

number

Example
closestNumber(10, [1, 2, 3, 4, 5, 6, 7, 8, 9]) // => 9
closestNumber(10, [1, 2, 3, 4, 5, 6, 7, 8, 9, 11]) // => 9
closestNumber(10, [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 9.5]) // => 9.5
closestNumber(10, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) // => 10

dedupe(arr) → {Array}

Removes structural duplicates from an array — deepEqual decides what a duplicate is, so property order, prototype and reference identity don't matter, contents do. The first occurrence of every distinct value is kept, in order, and the input array is left untouched.

The platform's new Set(arr) dedupes by reference identity and lodash's uniqWith(arr, isEqual) compares every pair — O(N²). Here every value folds to a 32-bit FNV-1a hash in a single walk, values collide into buckets, and deepEqual runs only within a bucket: linear in practice. The hash is free to be coarse — a shared bucket costs one comparison, while correctness comes from deepEqual alone.

Sets and Maps fold their members too, commutatively, so insertion order never reaches the hash and equal collections still land in one bucket. The bill is a walk per member on every collection: a pile of large Sets costs more to fold than a pile of small documents, and a single pair of them is a job for deepEqual rather than for this. The bucket-then-verify idea is HashCache (2013, https://stamat.wordpress.com/2013/07/03/javascript-quickly-find-very-large-objects-in-a-large-array/) with the CRC32-over-canonical-string hash replaced by a fold over the live values — no string is ever built.

Source:
Parameters:
Name Type Description
arr Array

The array to dedupe

Returns:
Type:
Array

A new array: first occurrence of every distinct value, in order

Example
dedupe([{ a: 1, b: 2 }, { b: 2, a: 1 }]) // => [{ a: 1, b: 2 }]
dedupe([NaN, NaN, 0, -0]) // => [NaN, 0]
dedupe([new Set([1, 2]), new Set([2, 1])]) // => [new Set([1, 2])]

deepEqual(a, b)

Deep structural equality for data. Two values are equal when they hold the same data, regardless of reference identity, property order or prototype.

Semantics, where they differ from Node's util.isDeepStrictEqual (which browsers don't have anyway): primitives compare by SameValueZero (NaN equals NaN, 0 equals -0), prototypes are ignored (a class instance equals a plain object with the same own properties), and functions compare by reference only — functions are not data. Handles Date, RegExp, boxed primitives, Map, Set, typed arrays, ArrayBuffer/SharedArrayBuffer/DataView, symbol keys and cyclic structures. WeakMap/WeakSet contents are unobservable, so two distinct weak collections are never equal.

Versus the field, probed against fast-deep-equal 3.1.3 (/es6), dequal 2.0.3, lodash.isequal 4.5.0 and Node 25 util.isDeepStrictEqual. The last row is a semantics choice, not a defect in the others; the rest are facts:

Input here fast-deep-equal dequal lodash Node util
cyclic structure terminates stack overflow stack overflow on equal graphs terminates terminates
{[sym]: 1} vs {[sym]: 2} not equal equal — symbols ignored equal — symbols ignored not equal not equal
Map/Set members matched deeply yes no — by reference yes yes yes
two invalid dates equal not equal not equal equal equal
NaN inside a typed array equal not equal not equal equal equal
distinct WeakMaps never equal equal equal never equal never equal
cross-realm twin (iframe, vm) equal not equal — realm-bound constructor check not equal equal not equal
URLs / Errors with different content not equal — toString plus own props, so an Error's .code counts not equal URL yes, Error missed not equal not equal
class instance vs same-shape plain object equal — data is data not equal — constructor check not equal not equal not equal

The cost of the guarantees is small: the cycle guard only engages past recursion depth 30 (a cycle always crosses that, shallow data never pays), so on plain JSON this sits within ~15% of fast-deep-equal and dequal on nested documents and ~1.5× behind on tiny flat objects — where the remaining gap is the symbol-key pass they skip — at ~1KB min+gzip. If you compare acyclic symbol-free JSON a million times in a loop, use fast-deep-equal; if you want the answer to be right on the full range of inputs, use this.

Source:
Parameters:
Name Type Description
a *

The first value

b *

The second value

Returns:

boolean True when a and b are structurally equal

Example
deepEqual({ a: 1, b: [1, 2] }, { b: [1, 2], a: 1 }) // => true
deepEqual([1, 2], [2, 1]) // => false
deepEqual(new Set([1, 2]), new Set([2, 1])) // => true
deepEqual(NaN, NaN) // => true
const x = {}
x.self = x
const y = {}
y.self = y
deepEqual(x, y) // => true

deepMerge(target, source)

Deep merge function that's mindful of arrays and objects. Mutates target object. shallowMerge is faster than deepMerge, so use shallowMerge when you don't need to merge nested objects or arrays.

Source:
Parameters:
Name Type Description
target object

The target object to merge into

source object

The source object to merge from

Returns:

object The mutated target object with the source object's properties merged into it

Example
const target = { foo: 'bar' }
const source = { bar: 'baz' }
deepMerge(target, source) // { foo: 'bar', bar: 'baz' }

fixed(number, digits)

Gets fixed number of digits after the decimal point

Source:
Parameters:
Name Type Description
number number

Number to fix

digits number

Number of digits to fix to

Returns:

number

Example
fixed(1.234, 2) // => 1.23
fixed(1.235, 2) // => 1.24
fixed(1.234) // => 1
fixed(1.234, 0) // => 1
fixed(1.234, 5) // => 1.234

generateUUID(safe)

Generates a UUID v4

  • Uses crypto.randomUUID if available
  • Uses crypto.getRandomValues if available
  • Uses a fallback if neither is available, which is not safe because it uses Math.random() instead of a cryptographically secure random number generator

I'm bad at crypto and bitwise operations, not my cup of tea, so I had to rely on StackOverflow for the fallback: https://stackoverflow.com/a/2117523/5437943

Source:
Parameters:
Name Type Description
safe boolean

Defaults to true, if false will use a fallback that's not cryptographically secure but significantly faster

Returns:

string

Example
generateUUID() // UUID v4, example 09ed0fe4-8eb6-4c2a-a8d3-a862b7513294

getObjectValueByPath(obj, path) → {*}

Access nested object properties using a path

Source:
Parameters:
Name Type Description
obj object

The object to access

path Array | string

The path to access

Returns:
Type:
*

The value of the accessed property

Example
const obj = { foo: { bar: 'baz' } }
getObjectValueByPath(obj, 'foo.bar') // => 'baz'

hasOwnProperties(obj, properties)

Check if object has multiple properties

Source:
Parameters:
Name Type Description
obj object
properties string | array
Returns:

boolean

Example
const obj = { foo: 'bar', baz: 'qux' }
hasOwnProperties(obj, ['foo', 'baz']) // => true
hasOwnProperties(obj, ['foo', 'baz', 'qux']) // => false

humanize(str, casingopt)

Humanize a slug, e.g. 'foo-bar' => 'Foo Bar'. Opposite of slugify. Replaces dashes and underscores with spaces and applies the chosen casing.

Source:
Parameters:
Name Type Attributes Default Description
str string
casing 'title' | 'sentence' | 'upper' | 'lower' <optional>
'title'

Casing to apply: 'title' capitalizes each word, 'sentence' capitalizes the first word only, 'upper' converts to upper case, 'lower' converts to lower case

Returns:

string

Example
humanize('foo-bar') // => 'Foo Bar'
humanize('foo_bar-baz') // => 'Foo Bar Baz'
humanize('foo-bar', 'sentence') // => 'Foo bar'
humanize('foo-bar', 'upper') // => 'FOO BAR'
humanize('Foo-Bar', 'lower') // => 'foo bar'

isArray(o)

If provided variable is an array. Just a wrapper for Array.isArray

Source:
Parameters:
Name Type Description
o any
Returns:

boolean

Example
isArray([]) // => true
isArray({}) // => false

isEmpty(o)

Check if a variable is empty

Source:
Parameters:
Name Type Description
o any

The variable to check

Returns:

boolean True if the variable is empty, false otherwise

Example
isEmpty({}) // => true
isEmpty([]) // => true
isEmpty('') // => true
isEmpty(null) // => false
isEmpty(undefined) // => false
isEmpty(0) // => false

isEmptyArray(o)

Check if an array is empty, substitute for Array.length === 0

Source:
Parameters:
Name Type Description
o Array

The array to check

Returns:

boolean True if the array is empty, false otherwise

Example
isEmptyArray([]) // => true
isEmptyArray([1, 2, 3]) // => false

isEmptyObject(o)

Check if an object is empty

Source:
Parameters:
Name Type Description
o object

The object to check

Returns:

boolean True if the object is empty, false otherwise

Example
isEmptyObject({}) // => true
isEmptyObject({ foo: 'bar' }) // => false

isFunction(o)

If provided variable is a function, substitute for typeof === 'function'

Source:
Parameters:
Name Type Description
o any
Returns:

boolean

Example
isFunction(function() {}) // => true
isFunction({}) // => false

isObject(o)

If provided variable is an object

Source:
Parameters:
Name Type Description
o any
Returns:

boolean

Example
isObject({}) // => true
isObject([]) // => false
isObject(null) // => false

isString(o)

If provided variable is a string. Just a wrapper for typeof === 'string'

Source:
Parameters:
Name Type Description
o any
Returns:

boolean

Example
isString('foo') // => true
isString({}) // => false

keydown()

A keydown built the way a browser builds one, getModifierState and all.

Source:

mapByProperty(arr, propertyName)

Maps an array of objects by a property name

Source:
Parameters:
Name Type Description
arr Array
propertyName string
Returns:

object

Example
const arr = [{ foo: 'bar' }, { foo: 'baz' }]
mapByProperty(arr, 'foo') // => { bar: { foo: 'bar' }, baz: { foo: 'baz' } }

mapPropertyToProperty(arr, keyPropertyName, valuePropertyName)

Maps an array of objects by a property name to another property name

Source:
Parameters:
Name Type Description
arr Array
keyPropertyName string
valuePropertyName string
Returns:

object

Example
const arr = [{ foo: 'bar', baz: 'qux' }, { foo: 'quux', baz: 'corge' }]
mapPropertyToProperty(arr, 'foo', 'baz') // => { bar: 'qux', quux: 'corge' }

matchesSearch(label, search) → {boolean}

Whether a label answers what has been typed — the match a filtering list needs.

"Contains" and not "starts with": the reader looking through a list of cities for york knows New York is not spelled that way and is asking for the one word they remember. Both sides go through removeAccents and lower case, so a search typed with diacritics and one typed without both land on the same labels.

An empty search matches everything, which is what makes an unfiltered list the same code path as a filtered one.

Not slugify, further down this same file, which starts the same way and then keeps going: that one is for URLs, so it drops everything outside [\w0-9-] and leaves Београд and 北京 as empty strings. A search box that cannot find a Cyrillic city on a Serbian site is not a smaller bug than one that cannot fold an accent.

Source:
Parameters:
Name Type Description
label string
search string
Returns:
Type:
boolean
Example
matchesSearch('New York', 'york') // => true
matchesSearch('Šipka', 'sipka') // => true
matchesSearch('Lemon', '') // => true
matchesSearch('New York', 'boston') // => false

percentage(num, total)

Calculates the percentage of a number in relation to another number

Source:
Parameters:
Name Type Description
num number

Number to calculate percentage of

total number

Total number

Returns:

number

Example
percentage(1, 10) // => 10
percentage(5, 10) // => 50
percentage(10, 10) // => 100
percentage(0, 10) // => 0
percentage(10, 2) // => 500

pick(obj, props)

Pick properties from an object or elements from an array

Source:
Parameters:
Name Type Description
obj Array

Object or array to pick properties or elements from

props Array | string | number

Properties to remove, can be an array of strings or a single string or number

Returns:

object | array | undefined

Example
pick({ foo: 'bar', bar: 'baz', baz: 'qux' }) // => {}
pick({}, []) // => {}
pick(null, 'foo') // => undefined
pick({ foo: 'bar', bar: 'baz', baz: 'qux' }, undefined) // => {}
pick({ foo: 'bar', bar: 'baz', baz: 'qux' }, 'foo') // => { foo: 'bar'}
pick({ foo: 'bar', bar: 'baz', baz: 'qux' }, ['foo', 'baz']) // => { foo: 'bar', baz: 'qux' }

pick(['foo', 'bar', 'baz'], []) // => []
pick([], []) // => []
pick(null, 0) // => undefined
pick(['foo', 'bar', 'baz'], undefined) // => []
pick(['foo', 'bar', 'baz'], 0) // => ['foo']
pick(['foo', 'bar', 'baz'], [0, 2]) // => ['foo', 'baz']
pick(['foo', 'bar', 'baz'], [0, 2, 3]) // => ['foo', 'baz']

pickArrayElements(arr, indexes)

Pick elements from an array by index, returning a new array of the picked elements

Source:
Parameters:
Name Type Description
arr Array

The array to pick elements from

indexes Array | number

Indexes to pick, can be an array of numbers or a single number

Returns:

array | undefined A new array of the picked elements, or undefined if arr is not an array

Example
pickArrayElements(['foo', 'bar', 'baz'], 0) // => ['foo']
pickArrayElements(['foo', 'bar', 'baz'], [0, 2]) // => ['foo', 'baz']

pickProperties(obj, props)

Pick properties from an object, returning a new object with only the picked properties

Source:
Parameters:
Name Type Description
obj object

The object to pick properties from

props Array | string

Properties to pick, can be an array of strings or a single string

Returns:

object A new object with only the picked properties

Example
pickProperties({ foo: 'bar', baz: 'qux' }, 'foo') // => { foo: 'bar' }
pickProperties({ foo: 'bar', baz: 'qux' }, ['foo', 'baz']) // => { foo: 'bar', baz: 'qux' }

press()

Dispatches at an element and lets it bubble, which is where a real keydown starts.

Source:

propertyIsFunction(obj, propertyName)

If object property is a function

Source:
Parameters:
Name Type Description
obj object
propertyName string
Returns:

boolean

Example
const obj = { foo: 'bar', baz: function() {} }
propertyIsFunction(obj, 'foo') // => false
propertyIsFunction(obj, 'baz') // => true

propertyIsString(obj, propertyName)

If object property is a string

Source:
Parameters:
Name Type Description
obj object
propertyName string
Returns:

boolean

Example
const obj = { foo: 'bar', baz: function() {} }
propertyIsString(obj, 'foo') // => true
propertyIsString(obj, 'baz') // => false

random()

Generates a random number between 0 and 1, inclusive of 0 but not inclusive of 1.

  • Uses crypto.getRandomValues if available
  • Uses Math.random() if crypto.getRandomValues is not available
Source:
Returns:

number

Example
random() // => 0.123456789

randomIntInclusive(min, max, safe)

Generates a random integer between two values, inclusive of both

Source:
Parameters:
Name Type Description
min number

Minimum value

max number

Maximum value

safe boolean

Defaults to false, if true will use a cryptographically secure random number generator

Returns:

number

Example
randomIntInclusive(1, 10) // => 1
randomIntInclusive(1, 10) // => 10
randomIntInclusive(1, 10) // => 5

reject(obj, props, clone)

Remove properties from an object or elements from an array

Source:
Parameters:
Name Type Description
obj Array

Object or array to remove properties or elements from

props Array | string | number

Properties to remove, can be an array of strings or a single string or number

clone boolean

Defaults to true, will clone the object or array before removing properties or elements.

Returns:

object | array | undefined

Example
reject({ foo: 'bar', bar: 'baz', baz: 'qux' }) // => {}
reject({}, []) // => {}
reject(null, 'foo') // => undefined
reject({ foo: 'bar', bar: 'baz', baz: 'qux' }, undefined) // => {}
reject({ foo: 'bar', bar: 'baz', baz: 'qux' }, 'foo') // => { bar: 'baz', baz: 'qux' }
reject({ foo: 'bar', bar: 'baz', baz: 'qux' }, ['foo', 'baz']) // => { bar: 'baz' }

reject(['foo', 'bar', 'baz'], []) // => []
reject([], []) // => []
reject(null, 0) // => undefined
reject(['foo', 'bar', 'baz'], undefined) // => []
reject(['foo', 'bar', 'baz'], 0) // => ['bar', 'baz']
reject(['foo', 'bar', 'baz'], [0, 2]) // => ['bar']
reject(['foo', 'bar', 'baz'], [0, 2, 3]) // => ['bar']

rejectArrayElements(arr, indexes, clone)

Remove elements from an array by index. Indexes may be passed in any order and are deduplicated.

Source:
Parameters:
Name Type Description
arr Array

The array to remove elements from

indexes Array | number

Indexes to remove, can be an array of numbers or a single number

clone boolean

Defaults to true, will clone the array before removing elements

Returns:

array | undefined The array without the removed elements, or undefined if arr is not an array

Example
rejectArrayElements(['foo', 'bar', 'baz'], 0) // => ['bar', 'baz']
rejectArrayElements(['foo', 'bar', 'baz'], [2, 0]) // => ['bar']

rejectProperties(obj, props, clone)

Remove properties from an object

Source:
Parameters:
Name Type Description
obj object

The object to remove properties from

props Array | string

Properties to remove, can be an array of strings or a single string

clone boolean

Defaults to true, will clone the object before removing properties

Returns:

object The object without the removed properties

Example
rejectProperties({ foo: 'bar', baz: 'qux' }, 'foo') // => { baz: 'qux' }
rejectProperties({ foo: 'bar', baz: 'qux' }, ['foo', 'baz']) // => {}

removeAccents(inputString)

A string flattened to plain Latin: the accents taken off, the letters that are two letters wearing one glyph spelled out, and the stroked letters given their plain form. Case is preserved — .toLowerCase() afterwards if a comparison needs it.

Two mechanisms, because Unicode offers no single one. NFKD decomposes and the combining marks are dropped, which handles é and ź and unpacks the ligatures and digraphs that have a compatibility decomposition — fi, DŽ, LJ, IJ. What is left has no separable mark to strip and is mapped by hand: without that pass removeAccents('Đorđe') returns Đorđe unchanged, and a [^\w] filter downstream then deletes the letter outright rather than plainifying it.

Only the scripts that share the Latin alphabet are touched. Cyrillic, Greek, Arabic and CJK come through whole, because mapping those to Latin is transliteration — a different job, answered per language rather than per character.

Source:
Parameters:
Name Type Description
inputString string
Returns:

string

Example
removeAccents('áéíóú') // => 'aeiou'
removeAccents('ÁÉÍÓÚ') // => 'AEIOU'
removeAccents('señor') // => 'senor'
removeAccents('Crème Brûlée') // => 'Creme Brulee'
removeAccents('Đorđe') // => 'Dorde'
removeAccents('Łódź') // => 'Lodz'
removeAccents('Nørrebro') // => 'Norrebro'
removeAccents('Æ') // => 'AE'
removeAccents('Œ') // => 'OE'
removeAccents('ß') // => 'ss'
removeAccents('Straẞe') // => 'Strasse'
removeAccents('Þingvellir') // => 'THingvellir'
removeAccents('DŽungla') // => 'DZungla'
removeAccents('fi') // => 'fi'
removeAccents('Београд') // => 'Београд', a script with no Latin in it is left alone

sampleVelocity(samples, windowMsopt) → {object}

How fast a gesture is moving, out of the samples it has left behind.

Measured over a window of time rather than between the last two samples. A single-frame delta spikes on a quick flick - one large jump between two events sends whatever reads it straight to an extreme - and averaging the displacement over the last windowMs of movement is what smooths those spikes out.

Every numeric field except t is measured, so the answer wears the shape of the samples: { t, x, y } comes back as { x, y }, and { t, position } as { position }. One pass whatever the number of dimensions, because the window is the expensive part and it is the same window for all of them.

Fewer than two samples is not a speed. That comes back as zero for the keys the samples do carry, rather than as an empty object a caller would read undefined out of and multiply into NaN; an empty list carries no keys, so it comes back empty.

Source:
Parameters:
Name Type Attributes Default Description
samples Array.<object>

Ordered oldest to newest, each one { t, ...numbers } where t is a timestamp in milliseconds

windowMs number <optional>
80

How far back from the newest sample to measure

Returns:
Type:
object

One velocity per numeric key, in that key's units per millisecond

Example
sampleVelocity([{ t: 0, x: 0 }, { t: 10, x: 5 }]) // => { x: 0.5 }
sampleVelocity([{ t: 0, x: 0, y: 0 }, { t: 10, x: 5, y: -10 }]) // => { x: 0.5, y: -1 }
sampleVelocity([{ t: 0, position: 20 }]) // => { position: 0 }

setPlatform()

Pretends to be a Mac, or stops. jsdom leaves navigator.platform empty, so both ways are set here.

Source:

shallowMerge(target, source)

Shallow merges two objects together. Used to pass simple options to functions. Mutates the target object. Faster than deepMerge, so use when you don't need to merge nested objects or arrays.

Source:
Parameters:
Name Type Description
target object

The target object to merge into

source object

The source object to merge from

Returns:

object The mutated target object with the source object's properties merged into it

Example
const target = { foo: 'bar' }
const source = { bar: 'baz' }
shallowMerge(target, source) // { foo: 'bar', bar: 'baz' }

slugify(str)

Slugify a string, e.g. 'Foo Bar' => 'foo-bar'. Similar to WordPress' sanitize_title(). Will remove accents and HTML tags.

Anything outside [\w0-9-] is dropped, so a script with no Latin in it — Београд, 北京 — slugifies to the empty string. That is the job: a slug is for a URL. matchesSearch is the one for a search box, which keeps those scripts whole.

Source:
Parameters:
Name Type Description
str string
Returns:

string

Example
slugify('Foo Bar') // => 'foo-bar'
slugify('Foo Bar <span>baz</span>') // => 'foo-bar-baz'
slugify('Đorđe Balašević') // => 'dorde-balasevic'
slugify('Łódź') // => 'lodz'

stringToArray(str)

Try to convert a string to an array

Source:
Parameters:
Name Type Description
str string

The string to convert

Returns:

array The converted array or undefined if conversion failed

Example
stringToArray('[1, 2, 3]') // => [1, 2, 3]
stringToArray('foo') // => undefined
stringToArray('1') // => undefined
stringToArray('{"foo": "bar"}') // => undefined

stringToBoolean(str)

Try to convert a string to a boolean

Source:
Parameters:
Name Type Description
str string

The string to convert

Returns:

boolean The converted boolean or undefined if conversion failed

Example
stringToBoolean('true') // => true
stringToBoolean('false') // => false
stringToBoolean('foo') // => undefined

stringToNumber(str)

Try to convert a string to a number

Source:
Parameters:
Name Type Description
str string

The string to convert

Returns:

number The converted number or undefined if conversion failed

Example
stringToNumber('1') // => 1
stringToNumber('1.5') // => 1.5
stringToNumber('foo') // => undefined
stringToNumber('1foo') // => undefined

stringToObject(str)

Try to convert a string to an object

Source:
Parameters:
Name Type Description
str string

The string to convert

Returns:

object The converted object or undefined if conversion failed

Example
stringToObject('{ "foo": "bar" }') // => { foo: 'bar' }
stringToObject('foo') // => undefined
stringToObject('1') // => undefined
stringToObject('[1, 2, 3]') // => undefined

stringToPrimitive(str) → {null|boolean|int|float|string}

Try to convert a string to a primitive

Source:
Parameters:
Name Type Description
str string

The string to convert

Returns:
Type:
null | boolean | int | float | string

The converted primitive or input string if conversion failed

Example
stringToPrimitive('null') // => null
stringToPrimitive('true') // => true
stringToPrimitive('false') // => false
stringToPrimitive('1') // => 1
stringToPrimitive('1.5') // => 1.5
stringToPrimitive('foo') // => 'foo'
stringToPrimitive('1foo') // => '1foo'

stringToRegex(str)

Try to convert a string to a regex

Source:
Parameters:
Name Type Description
str string

The string to convert

Returns:

regex The converted regex or undefined if conversion failed

Example
stringToRegex('/foo/i') // => /foo/i
stringToRegex('foo') // => undefined
stringToRegex('1') // => undefined

stringToType(str)

Try to convert a string to a data type

Source:
Parameters:
Name Type Description
str string

The string to convert

Returns:

any The converted data type or input string if conversion failed

Example
stringToData('null') // => null
stringToData('true') // => true
stringToData('false') // => false
stringToData('1') // => 1
stringToData('1.5') // => 1.5
stringToData('foo') // => 'foo'
stringToData('1foo') // => '1foo'
stringToData('[1, 2, 3]') // => [1, 2, 3]
stringToData('{ "foo": "bar" }') // => { foo: 'bar' }
stringToData('/foo/i') // => /foo/i

stripHTMLTags(inputString)

Strip HTML tags from a string

Source:
Parameters:
Name Type Description
inputString string
Returns:

string

Example
stripHTMLTags('<span>foo</span>') // => 'foo'
stripHTMLTags('<span>foo</span> <span>bar</span>') // => 'foo bar'

transformCamelCaseToDash(str)

Transforms a camelCase string to dash separated string

Source:
Parameters:
Name Type Description
str string
Returns:

boolean

Example
transformCamelCaseToDash('fooBar') // => 'foo-bar'
transformCamelCaseToDash('fooBarBaz') // => 'foo-bar-baz'
transformCamelCaseToDash('foo') // => 'foo'
transformDashToCamelCase('fooBarBaz-qux') // => 'foo-bar-baz-qux'

transformDashToCamelCase(str)

Transforms a dash separated string to camelCase

Source:
Parameters:
Name Type Description
str string
Returns:

boolean

Example
transformDashToCamelCase('foo-bar') // => 'fooBar'
transformDashToCamelCase('foo-bar-baz') // => 'fooBarBaz'
transformDashToCamelCase('foo') // => 'foo'
transformDashToCamelCase('fooBarBaz-qux') // => 'fooBarBazQux'

truncateString(str, numWords, ellipsis)

Truncate a string to a given number of words

Source:
Parameters:
Name Type Description
str string

String to truncate

numWords number

Number of words to truncate to

ellipsis string

Ellipsis to append to the end of the string

Returns:

string

Example
truncateString('foo bar baz', 2) // => 'foo bar…'
truncateString('foo bar baz', 2, '...') // => 'foo bar...'
truncateString('foo bar. baz', 2, '...') // => 'foo bar. ...'

waitFor(condition, optionsopt) → {Promise.<*>}

Waits for a condition to become truthy, polling it until it does.

For an element appearing in the DOM reach for on instead — a MutationObserver reacts where polling only notices on its next tick. This is for what an observer cannot see: a third-party script defining its global, a widget flipping a flag, a value settling somewhere unwatchable.

The deadline is measured against the clock rather than counted in ticks, and the last sleep is cut short to land on it: a background tab clamps setTimeout to a second or more, and a caller who asked for two seconds means two seconds either way — including one last look at the moment they run out. A condition promise still pending when the deadline lands does not hold it open: the wait rejects on time and the late answer is discarded.

Source:
See:
Parameters:
Name Type Attributes Description
condition function

Called immediately and then on every tick. May return a promise. Truthy ends the wait

options object <optional>
Name Type Attributes Default Description
interval number <optional>
100

Milliseconds between checks. 0 checks again every tick

timeout number <optional>
10000

Milliseconds before giving up. 0 or Infinity waits forever, which leaks a timer if the condition never comes

signal AbortSignal <optional>

Aborting rejects the promise and stops the polling

Returns:
Type:
Promise.<*>

Resolves with whatever the condition returned. Rejects with a TimeoutError at the deadline, with the signal's reason when aborted, or with whatever the condition threw

Examples
const dataLayer = await waitFor(() => window.dataLayer)
// Give up rather than poll a widget that is never coming
try {
  await waitFor(() => window.Intercom, { timeout: 2000 })
} catch {
  renderContactFormInstead()
}
// Stop waiting when the thing that wanted the answer is gone
const controller = new AbortController()
waitFor(() => player.ready, { signal: controller.signal })
onUnmount(() => controller.abort())