@rickosborne/foundation
TypeScript icon, indicating that this package has built-in type declarations

2025.3.12 • Public • Published

@rickosborne/foundation

Basic data structures and algorithms. Built on @rickosborne/typical for types, and @rickosborne/guard for guards.

Usage

Install via your favorite package manager.

Each package supports CommonJS require, ESM import, and TypeScript usage.

You also have a choice: barrel imports or direct imports.

Barrel imports mean you're going to require/import everything from the same package-level namespace:

// CommonJS
const { isPlainObject, isListOf } = require("@rickosborne/guard");
// ESM / TypeScript
import { isPlainObject, isListOf } from "@rickosborne/guard";

Implications:

  • Nice and simple.
  • Your build system needs to do tree-shaking well ... or you'll end up adding the entire package even if you only import two functions.

The other option is to use direct imports:

// CommonJS
const { isPlainObject } = require("@rickosborne/guard/is-object");
const { isListOf } = require("@rickosborne/guard/is-list-of");
// ESM / TypeScript
import { isPlainObject } from "@rickosborne/guard/is-object.js";
import { isListOf } from "@rickosborne/guard/is-list-of.js";

Implications:

  • You (probably) don't have to worry about tree-shaking as your build (likely) ends up with only the functions you need.

If you're using a modern build system, there aren't any strong reasons to prefer one way over the other. It's really just down to your personal preference.

A quick note about file extensions

Do you need to use file extensions? And if so, which extensions?

Honestly ... this is a dumpster fire question. It really comes down to your own setup and configuration.

Within each package itself:

  • The CommonJS files all have .cjs extensions.
  • The ESM files all have .mjs extensions.
  • Node subpath exports have been set up to send .js imports to the .cjs (via require) or .mjs (via import) files, depending on your setup.

So, in theory, the only extension which won't work would be .ts because the source isn't included.

If you run into a problem with a particular configuration, file a GitHub issue with:

  • Your tsconfig.json's module, moduleResolution, and target settings.
  • Your package.json's type and imports settings.
  • An example of another package which imports correctly for you.

License

This package is licensed as CC-BY-NC-SA-4.0 unless otherwise noted. That is, Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International.


API

Classes

ArrayBinaryMinHeap

 class ArrayBinaryMinHeap<T> implements Queue<T> 

Simple implementation of a binary min-heap, meaning low values are sorted before high values, using the supplied comparator. Invert your comparator if you want a max-heap.

AsyncIteratorTransformer

 abstract class AsyncIteratorTransformer<InputT, OutputT> extends IteratorTransformerBase<InputT, OutputT> implements AsyncIterableIterator<OutputT, undefined, undefined> 

AsyncStringTokenizer

 class AsyncStringTokenizer extends AStringTokenizer 

IteratorTransformer

 abstract class IteratorTransformer<InputT, OutputT> extends IteratorTransformerBase<InputT, OutputT> implements IterableIterator<OutputT, undefined, undefined> 

IteratorTransformerBase

 abstract class IteratorTransformerBase<InputT, OutputT> 

Basic queues and statistic tracking for a dual-queued Iterator transformer.

JsonParseObserver

 class JsonParseObserver 

JsonPushTokenizer

 class JsonPushTokenizer 

MultiAsyncIterator

 class MultiAsyncIterator<T> implements AsyncIterable<T> 

Wrapper for an AsyncIterator which allows multiple consumers to read from the same iterable via a basic queue which tracks which consumers have read which values.

PriorityArray

 class PriorityArray<T> implements Queue<T> 

An implementation of a priority queue backed by a JS array, using the given comparator. Sorts low-to-high, so you will need to invert comparator if you want high-to-low.

PriorityLinkedList

 class PriorityLinkedList<T> implements Queue<T> 

Implementation of a priority queue backed by a linked list, using the given comparator. Sorts low-to-high, so you will need to invert comparator if you want high-to-low.

SkipList

 class SkipList<T> implements Queue<T> 

Basic skip list implementation, using the given comparator to keep values in order, low-to-high. If you want high-to-low you will need to invert your comparator.

StringTokenizer

 class StringTokenizer extends AStringTokenizer 

Primitive string tokenizer upon which parsers could be built.

TimeoutError

 class TimeoutError extends Error 

Error which will be thrown if a timeout happens and no other error is provided.

TokenGenerator

 abstract class TokenGenerator<TokenT> extends AsyncStringTokenizer implements AsyncIterable<TokenT> 

UnknownError

 class UnknownError extends Error 

An error thrown when the root problem is unknown.

Functions

addProperties

addProperties: <T, K extends string, R extends Record<K, TypedPropertyDescriptor<unknown>>>(target: T, descriptors: R) => Resolve<T & PropertiesFromDescriptors<R>>

A more type-friendly version of Object.defineProperties. See Object.defineProperties on MDN.

addProperty

addProperty: <T, K extends string, V, D extends TypedPropertyDescriptor<V>>(target: T, key: K, descriptor: D) => Resolve<T & PropertyFromDescriptor<K, D>>

A more type-friendly version of Object.defineProperty. See Object.defineProperty on MDN.

arrayBinaryMaxHeap

arrayBinaryMaxHeap: <T>(comparator: Comparator<T>) => ArrayBinaryMinHeap<T>

Build a max-heap using the given comparator. Will invert the comparator and build a min-heap, which produces the same outcomes.

arrayBinaryMinHeap

arrayBinaryMinHeap: <T>(comparator: Comparator<T>) => ArrayBinaryMinHeap<T>

Build a min-heap using the given comparator.

arrayEq

arrayEq: <T>(a: T[], b: T[], predicate?: ((a: T, b: T, index: number) => boolean)) => boolean

Simple comparison to see if two arrays are equivalent.

arrayFromAsync

arrayFromAsync: <T>(iterableOrArrayLike: AsyncIterable<T> | Iterable<T | PromiseLike<T>> | ArrayLike<T | PromiseLike<T>>) => Promise<T[]>

Polyfill for Array.fromAsync for node before v22.

arrayUnique

arrayUnique: <T>(array: T[]) => T[]

Generate a new array which has no duplicate values. Preserves the order of the first occurrence of each value. Returns the original array if no duplicates were found.

asFraction

asFraction: (num: number, percentError?: number) => FracTuple

Try to find a human-readable fraction for the given decimal value, within a given percentage error. See the original algorithm by Sjaak.

asIndexKey

asIndexKey: (key: string) => number | undefined

Try to convert the string-format key into an array index key.

asyncIteratorFrom

asyncIteratorFrom: <TYield, TReturn, TNext>(iterator: Iterator<TYield, TReturn, TNext>) => AsyncIterator<TYield, TReturn, TNext>

Convert a synchronous iterator into an asynchronous one.

asyncIteratorOf

asyncIteratorOf: <T>(it: AsyncIterable<T, undefined, undefined> | Iterable<T, undefined, undefined> | AsyncIterator<T, undefined, undefined>) => AsyncIterator<T, undefined, undefined>

If the value is already an Iterator, return it. If the value is AsyncIterable, return an Iterator for it. It the value is Iterable, upgrade an Iterator for it to an AsyncIterator and return that. Otherwise, throw an error.

asyncIteratorTransformer

asyncIteratorTransformer: <InputT, OutputT>(map: (inputs: InputT[], inputIsDone: boolean) => IteratorTransformerMapResult<OutputT> | Promise<IteratorTransformerMapResult<OutputT>>, options?: AsyncIteratorTransformerOptions) => (it: AsyncIterator<InputT, undefined, undefined> | AsyncIterable<InputT, undefined, undefined> | Iterable<InputT, undefined, undefined>) => AsyncIteratorTransformer<InputT, OutputT>

binaryIndexOf

binaryIndexOf: <T>(value: T, items: T[], comparator: Comparator<T>, config?: BinaryIndexOfConfig) => SearchResult

Perform a binary search through the given list for the given value using the given comparator.

catchAnd

catchAnd: <T, O extends CatchAndOptions<T>>(options?: O) => (err: unknown) => CatchAndReturn<T, O>

Catch block builder to reduce the noise of thorough error handling.

chainableComparator

chainableComparator: <T>(comparator: Comparator<T>) => ChainableComparator<T>

Wrap the given comparator so you can chain ChainableComparator functions from it.

closeTo

closeTo: (a: number, b: number, epsilon?: number) => boolean

Test for whether two numbers are close enough to each other, within an acceptable margin.

closeToZero

closeToZero: (n: number, epsilon?: number) => n is 0

Test for whether a number is close enough to zero, within an acceptable margin.

comparatorBuilder

comparatorBuilder: <T>() => ComparatorBuilder<T>

Start building a comparator.

computeIfAbsent

computeIfAbsent: <T, K>(key: K, map: Map<K, T>, compute: (key: K) => T) => T

Find the item in the Map, or compute and store it.

concatRegExp

concatRegExp: (...patterns: RegExp[]) => RegExp

Concatenate the patterns (and flags) of regular expressions so they will match all at once. This does not attempt to fix any problems, such as duplicate named capture groups or incorrectly-numbered backreferences.

deepCopy

deepCopy: <T>(source: T, options?: DeepCopyOptions) => T

Create a deep copy of an object. This is not a particularly robust check, and won't copy things like class instances.

deepEquals

 function deepEquals<T>(actual: unknown, expected: T): actual is T;

Recursively compare two objects for equivalence. Warning: does not attempt to resolve cycles.

deepMerge

deepMerge: <Loser, Winner>(loser: Loser, winner: Winner) => DeepMerge<Loser, Winner>

Recursively merge two values, if possible. See DeepMerge for details on the logic.

deepSort

deepSort: <T>(obj: T, options?: DeepSortOptions) => T

Sort an object, and any objects nested through plain objects or arrays, by key, so when JSON stringified you will get a deterministic output.

divMod

divMod: (num: number, divisor: number) => [quotient: number, remainder: number]

Euclidian division which returns a tuple of the quotient and remainder.

doubleLinkedList

doubleLinkedList: <T>() => DoubleLinkedList<T>

Build a doubly-linked list.

entriesOf

entriesOf: <T extends object>(obj: T) => [keyof T, T[keyof T]][]

A wrapper for Object.entries which has typed keys and values.

findConsole

findConsole: () => ConsoleLike

formatBytes

formatBytes: (bytes: number | bigint, base?: 1024 | 1000, precision?: number) => string

Pretty-print a byte value with low enough detail to be quickly human-readable.

formatDuration

formatDuration: (duration: Duration) => string

formatMarkdownTable

formatMarkdownTable: <T extends object>(values: T[], options: FormatMarkdownTableOptions<T>) => string

Generate a Markdown-formatted table for the given items.

holder

 function holder<T>(value: T): ValuedHolder<T>;

holder

 function holder<T>(): EmptyHolder<T>;

imprecise

imprecise: (num: number, resolution?: number) => string

String-format a number rounded to the given resolution, where human readability is more important than precision.

isConsoleLike

isConsoleLike: (obj: unknown) => obj is ConsoleLike

isSvgAbsolutePathCommand

isSvgAbsolutePathCommand: (value: unknown) => value is SvgAbsolutePathCommand

isSvgPathCommand

isSvgPathCommand: (value: unknown) => value is SvgPathCommand

isSvgRelativePathCommand

isSvgRelativePathCommand: (value: unknown) => value is SvgRelativePathCommand

iteratorOf

iteratorOf: <T>(it: Iterable<T, undefined, undefined> | Iterator<T, undefined, undefined>) => Iterator<T, undefined, undefined>

If the value is already an Iterator, return it. If the value is Iterable, return an Iterator for it. Otherwise, throw an error.

iteratorTransformer

iteratorTransformer: <InputT, OutputT>(map: (inputs: InputT[], inputIsDone: boolean) => IteratorTransformerMapResult<OutputT>) => (it: Iterator<InputT, undefined, undefined> | Iterable<InputT, undefined, undefined>) => IteratorTransformer<InputT, OutputT>

jsonParseEventsOf

 function jsonParseEventsOf(...its: StringIterable[]): Generator<JsonParseEvent, void, undefined>;

jsonParseEventsOfAsync

 function jsonParseEventsOfAsync(...its: AsyncStringIterable[]): AsyncGenerator<JsonParseEvent, void, undefined>;

jsonPathAppend

jsonPathAppend: (path: string, key: string | number | symbol, options?: JsonPathAppendOptions) => string

Append the given property key to the given JSON Path expression. This does not attempt to validate anything about the path or the key, only formats it according to very basic rules. Technically, the spec doesn't handle symbol values, so if you give it a path with a symbol you get an expression which other JSON Path parsers can't handle. However, it does use the correct function syntax, so it should still at least parse correctly.

jsonTokensOf

 function jsonTokensOf(...its: StringIterable[]): Generator<JsonToken, void, undefined>;

jsonTokensOfAsync

 function jsonTokensOfAsync(...its: AsyncStringIterable[]): AsyncGenerator<JsonToken, void, undefined>;

lowerFirst

 function lowerFirst(text: string): string;

lowerFirst

 function lowerFirst(text: string | null | undefined): string | undefined;

memoize

memoize: <T>(supplier: Supplier<T>) => Supplier<T>

Shorthand for memoizeSupplier.

memoizeSupplier

memoizeSupplier: <T>(supplier: Supplier<T>) => Supplier<T>

Memoize the given supplier so that it is called at most once.

minMax

 function minMax(values: number[]): [number, number];

minMax

 function minMax(...values: number[]): [number, number];

optionalRegExp

optionalRegExp: (pattern: RegExp) => RegExp

Modify a regular expression's pattern to make the entire expression optional, keeping any start/end anchors in place

parseDuration

parseDuration: (text: string) => DurationWithText

Parse an ISO-8601 duration from the given text. If the text contains extra non-duration characters after, will only throw an error if they would produce an ambiguous result, or could indicate an incomplete duration.

parseLocalDate

parseLocalDate: (text: string, config?: ParseLocalDateConfig) => Date

Parse an ISO-8860-like date, but do so assuming that the time is intended to be local, not UTC. But if allowed, the date could override this with specific time zone info.

positiveDiv

positiveDiv: (num: number, divisor: number) => number

Modulo where the result is always positive.

positiveMod

positiveMod: (num: number, divisor: number) => number

Modulo where the result is always positive.

priorityArray

priorityArray: <T>(comparator: Comparator<T>) => Queue<T>

Build a priority queue which uses an array as a backing store.

priorityLinkedList

priorityLinkedList: <T>(comparator: Comparator<T>) => Queue<T>

Build a priority queue which uses a linked list as a backing store.

randomNumberGenerator

randomNumberGenerator: (seedOrOptions?: number | RNGOptions, presetName?: LCEPresetName | undefined) => RNG

https://en.wikipedia.org/wiki/Linear_congruential_generator

reduceToUnique

reduceToUnique: <T>() => [(prev: T[], cur: T) => T[], T[]]

Generate the args for an array reducer which keeps only distinct values.

reQuote

reQuote: (text: string, options?: ReQuoteOptions) => string

Given a text, either wrap it in quotes which make the most sense for the text, or change the quotes to a different set.

resolvablePromise

 function resolvablePromise<T>(): ResolvablePromise<T>;

Build a promise which can be resolved from the outside.

roundTo

roundTo: (value: number, resolution?: number) => number

Round a given number to the nearest unit of resolution. For resolution of 1, this is equal to Math.round.

secondsFromDuration

secondsFromDuration: (duration: Partial<DurationWithText>) => number

Convert a given duration to an equivalent number of seconds.

shuffle

shuffle: <T>(list: T[], { into, random01 }?: ShuffleConfig<T>) => T[]

Fisher-Yates shuffle. Defaults to in-place sorting, but can sort into a new one via into.

simpleStarMatch

simpleStarMatch: (glob: string, text: string) => boolean

Match the given simple-* glob against the given text. This does not use "filesystem glob" logic. That is, a * here will match anything, including /. Similarly, there is no ? operator.

singleCharactersOf

 function singleCharactersOf(...its: StringIterable[]): Generator<string, void, unknown>;

singleCharactersOfAsync

 function singleCharactersOfAsync(...its: AsyncStringIterable[]): AsyncGenerator<string, void, unknown>;

singleLinkedList

singleLinkedList: <T>() => List<T>

Builder for a single-linked list.

skipList

skipList: <T>(comparator: Comparator<T>) => SkipList<T>

Build a priority queue using a skip list implementation.

sleep

 function sleep<T>(ms: number, value: T): Promise<T>;

Sleep at least some number of ms, returning the supplied value when complete.

sleep

 function sleep(ms: number): Promise<undefined>;

Sleep at least some number of ms.

splitFixed

splitFixed: (text: string, width: number) => string[]

Split a string into fixed-width substrings. The last one may be short.

starMatchParts

starMatchParts: (glob: string) => StarGlobPart[]

Parse a simple-* glob into its constituent tokens.

svgPathCommandsOf

 function svgPathCommandsOf(...d: StringIterable[]): Generator<SvgPathToken, void, undefined>;

Parse an SVG path definition into drawing commands.

svgPathValuesOf

 function svgPathValuesOf(...d: StringIterable[]): Generator<SvgPathValue, void, undefined>;

Tokenize an SVG path definition into command, number, and space tokens.

toBatches

toBatches: <T>(maxPerBatch: number, list: T[], mode?: ToBatchesMode) => T[][]

Group the given list into batches of the given maximum count, optionally using a given strategy.

toBatchesReducer

toBatchesReducer: <T>(maxPerBatch: number, mode?: ToBatchesMode) => [reduce: (prev: T[][], cur: T, index: number, list: T[]) => T[][], initial: T[][]]

Generate an array reducer which will group the given list into batches of the given maximum count, optionally using a given strategy.

toShuffled

toShuffled: <T>(list: T[], config?: Omit<ShuffleConfig<T>, "into"> | undefined) => T[]

Wrapper for the shuffle function which shuffles into a new array, leaving the original intact.

uniqueReducer

uniqueReducer: () => <T>(prev: T[], cur: T) => T[]

Generate a function for use in an array reducer which will track and only keep the first occurrence of each value.

window2

 function window2<T>(items: Readonly<T[]>): Generator<Readonly<[T, T, number, number]>, void, undefined>;

Generator for a sliding window of pairs of values from the given list. It yields each value in the list in a tuple with its successor. The last item wraps around to use the first item as its successor. The indices of the two values are also yielded after the values. For example:

for (const [ x, y, xIndex, yIndex ] of window2([ "a", "b", "c" ])) {
    console.log(x, y, xIndex, yIndex);
}

This would output:

 a, b, 0, 1 b, c, 1, 2 c, a, 2, 0 

window3

 function window3<T>(items: Readonly<T[]>): Generator<Readonly<[T, T, T, number, number, number]>, void, undefined>;

Generator for a sliding window of triplets of values from the given list. It yields each value in the list in a tuple with its predecessor and successor. The first and last items wrap around to use the last and first items as their predecessor/successor. The indices of the values are also provided after the values. The middle value (y in the example below) is the "current" value, with the first value (x) being its predecessor and the third (z) its successor. That current value is the one which will be at index 0 for the first iteration of the loop. For example:

for (const [ x, y, z, xIndex, yIndex, zIndex ] of window3([ "a", "b", "c" ])) {
    console.log(x, y, z, xIndex, yIndex, zIndex);
}

This would output:

 c, a, b, 2, 0, 1 a, b, c, 0, 1, 2 b, c, a, 1, 2, 0 

withLazyProperty

withLazyProperty: <Target, Property, Name extends string>(target: Target, name: Name, calculator: (t: Target) => Property) => WithProperty<Target, Name, Property>

Add a property to the given object which is calculated lazily, and only once.

withNullsFirst

withNullsFirst: <T>(comparator: Comparator<T>) => Comparator<T | null | undefined>

Wrap the given comparator to return null and undefined values before the others.

withNullsLast

withNullsLast: <T>(comparator: Comparator<T>) => Comparator<T | null | undefined>

Wrap the given comparator to return null and undefined values after the others.

withTimeout

 function withTimeout<T>(options: WithTimeoutOptions<T>): Promise<T>;

Wrap a given block or promise in another promise which will resolve or reject if the first has not resolved within the specified time limit.

zeroPad

zeroPad: (num: number, length: number, radix?: number) => string

Convert a number to a string and left-pad it out to the given length with zeroes.

Interfaces

ArcSvgPathToken

export interface ArcSvgPathToken extends SvgPathTokenBase<"arc"> 

AsyncIteratorTransformerOptions

export interface AsyncIteratorTransformerOptions 

Additional configuration for an asynchronous Iterator transformer.

CatchAndOptions

export interface CatchAndOptions<T> 

CloseSvgPathToken

export interface CloseSvgPathToken extends SvgPathTokenBase<"close"> 

CommandSvgPathValue

export interface CommandSvgPathValue extends SvgPathValueBase<"command"> 

ConsoleLike

export interface ConsoleLike 

CubicCurveSvgPathToken

export interface CubicCurveSvgPathToken extends SvgPathTokenBase<"cubic"> 

DeepCopyOptions

export interface DeepCopyOptions 

DeepSortOptions

export interface DeepSortOptions 

Duration

export interface Duration 

ISO8601-like measure of a duration. Does not include any concept of being relative to any specific date.

DurationWithText

export interface DurationWithText extends Duration 

A duration parsed from text, which includes the extracted (serialized) duration text.

EmptyHolder

export interface EmptyHolder<T> extends Holder<T> 

A Holder without a value, yet.

FormatMarkdownTableOptions

export interface FormatMarkdownTableOptions<T extends object> 

Options for formatMarkdownTable.

Holder

export interface Holder<T> 

A structure which can hold any value type, even undefined, and can itself be const, while still allowing the value to be added later.

IteratorTransformerMapResult

export interface IteratorTransformerMapResult<OutputT> 

JsonBooleanToken

export interface JsonBooleanToken extends JsonTokenBase 

JsonNullToken

export interface JsonNullToken extends JsonTokenBase 

JsonNumberToken

export interface JsonNumberToken extends JsonTokenBase 

JsonParseArrayState

export interface JsonParseArrayState extends JsonParseStateBase 

JsonParseItemState

export interface JsonParseItemState extends JsonParseStateBase 

JsonParseObjectState

export interface JsonParseObjectState extends JsonParseStateBase 

JsonParsePropertyState

export interface JsonParsePropertyState extends JsonParseStateBase 

JsonParseRootState

export interface JsonParseRootState extends JsonParseStateBase 

JsonParseStateBase

export interface JsonParseStateBase 

JsonPathAppendOptions

export interface JsonPathAppendOptions 

JsonPunctuationToken

export interface JsonPunctuationToken extends JsonTokenBase 

JsonSpaceToken

export interface JsonSpaceToken extends JsonTokenBase 

JsonStringToken

export interface JsonStringToken extends JsonTokenBase 

JsonTokenBase

export interface JsonTokenBase 

LineSvgPathToken

export interface LineSvgPathToken extends SvgPathTokenBase<"line"> 

LogLike

export interface LogLike 

MoveSvgPathToken

export interface MoveSvgPathToken extends SvgPathTokenBase<"move"> 

NumberSvgPathValue

export interface NumberSvgPathValue extends SvgPathValueBase<"number"> 

QuadraticCurveSvgPathToken

export interface QuadraticCurveSvgPathToken extends SvgPathTokenBase<"quad"> 

ResolvablePromise

export interface ResolvablePromise<T> extends Promise<T> 

A promise which can be resolved from the outside.

RNG

export interface RNG 

RNGOptions

export interface RNGOptions 

SpaceSvgPathValue

export interface SpaceSvgPathValue extends SvgPathValueBase<"space"> 

SvgPathTokenBase

export interface SvgPathTokenBase<T extends keyof SvgPathTokenByType> 

SvgPathTokenByType

export interface SvgPathTokenByType 

SvgPathValueBase

export interface SvgPathValueBase<T extends SvgPathValueType> 

SvgPathValueByType

export interface SvgPathValueByType 

UnknownErrorOptions

export interface UnknownErrorOptions extends ErrorOptions 

Options for UnknownError.

ValuedHolder

export interface ValuedHolder<T> extends Holder<T> 

A Holder whose value has been set.

WithTimeoutOptions

export interface WithTimeoutOptions<T> 

Options for withTimeout.

TypeAliases

AsyncIteratorTransformerConstructor

type AsyncIteratorTransformerConstructor<InputT, OutputT> = AbstractConstructorLike<[iterator: AsyncIterator<InputT, undefined, undefined>], AsyncIteratorTransformer<InputT, OutputT>>;

AsyncStringIterable

type AsyncStringIterable = StringIterable | AsyncIterable<string, undefined, undefined> | AsyncIterator<string, undefined, undefined>;

BinaryIndexOfConfig

type BinaryIndexOfConfig = {
    firstNonUnique?: boolean;
    initialLeft?: number;
    initialRight?: number;
    rangeCheck?: boolean;
};

Configuration options for binaryIndexOf.

ChainableComparator

type ChainableComparator<T> = Comparator<T> & {
    get desc(): ChainableComparator<T>;
    get nullsFirst(): ChainableComparator<T | undefined | null>;
    get nullsLast(): ChainableComparator<T | undefined | null>;
};

Mixin for a comparator with chaining functions to constrain the behavior of the comparator.

ComparatorBuilder

type ComparatorBuilder<T> = {
    build(): Comparator<T>;
    get desc(): ComparatorBuilder<T>;
    get nullsFirst(): ComparatorBuilder<T>;
    get nullsLast(): ComparatorBuilder<T>;
    num(accessor: (t: T) => (undefined | number)): ComparatorBuilder<T>;
    str(accessor: (t: T) => (undefined | string)): ComparatorBuilder<T>;
};

Build a comparator for the given type, which goes through the specified checks in the order they are defined.

DeepMerge

type DeepMerge<Loser, Winner> = Winner extends object ? Loser extends object ? ({
    [K in keyof Loser as K extends keyof Winner ? never : K]: Loser[K];
} & {
    [K in keyof Winner as K]: K extends keyof Loser ? DeepMerge<Loser[K], Winner[K]> : Winner[K];
}) : Winner : Winner;

Given two types, recursively compare and merge them with the following logic: 1. If the two types are different, Winner wins. 2. If either type is not a Record, Winner wins. 3. If both types are Records, each property, in the set of all keys from both, is compared using the same logic. A superset Record is created.

DoubleLinkedList

type DoubleLinkedList<T> = List<T> & {
    get tail(): T | undefined;
    reverseValues(): Generator<T, void, undefined>;
    reverseValuesAndIndexes(): Generator<[T, number], void, undefined>;
    reverseWalk(block: (value: T, index: number) => ListWalkDecision<T>): void;
};

Mixin for additional methods available when the linked list is double-linked.

DurationDesignator

type DurationDesignator = "Y" | "M" | "W" | "D" | "T" | "H" | "S";

ISO-8601 designator for a duration value.

FracTuple

type FracTuple = [numerator: number, denominator: number];

A fraction represented as a tuple of numerator and denominator. The numerator is negative if the value is negative. The denominator is always positive, and at least 1. Both values are integers, though the numerator may be Infinity or NaN as the value requires.

GetPropertyDescriptor

type GetPropertyDescriptor<T> = PropertyDescriptorFlags & {
    get(): T;
    set?: never;
    value?: never;
};

Partial property descriptor which includes only an accessor (getter) and not a mutator, and is thus read-only.

GetSetPropertyDescriptor

type GetSetPropertyDescriptor<T> = PropertyDescriptorFlags & {
    get(): T;
    set(t: T): void;
};

Partial property descriptor which includes both an accessor (getter) and mutator (setter), and is thus read-write.

IfReadOnlyDescriptor

type IfReadOnlyDescriptor<T, D extends TypedPropertyDescriptor<unknown>> = D extends ReadOnlyPropertyDescriptor | GetPropertyDescriptor<unknown> ? T : never;

Filter type T based on whether the property descriptor D would produce a read-only property.

IfReadWriteDescriptor

type IfReadWriteDescriptor<T, D extends TypedPropertyDescriptor<unknown>> = D extends ReadOnlyPropertyDescriptor | GetPropertyDescriptor<unknown> | SetPropertyDescriptor<unknown> ? never : T;

Filter type T based on whether the property descriptor D would produce a read-write (or write-only) property.

IfWriteOnlyDescriptor

type IfWriteOnlyDescriptor<T, D extends TypedPropertyDescriptor<unknown>> = D extends SetPropertyDescriptor<unknown> ? T : never;

Filter type T based on whether the property descriptor D would produce a write-only property. Note: JS has a concept of a write-only property, and the unit tests cover this. However, TS doesn't have a way of expressing it, at least as of v5.8. So for now, it goes into the read-write bucket, even though you can't actually read from it. The alternative would be to set it to undefined, to show you can't read from it ... but then you lose the type info for the setter. Yuck. For now ... The types below will, ahem, mangle the types they produce. Just a little. If you produce a setter-only property, it will end up looking like:

const withSetterOnly: WithSetterOnly = addProperty({}, "whatever", { set: (value: string) => void(whatever(value)) });
type WithSetterOnly = {
   whatever: string;
   whateverIsWriteOnly?: undefined;
}

So you get a reminder without breaking anything too hard.

IntGenerator

type IntGenerator = Generator<number, void, undefined> & {
    toArray(): number[];
};

Mixin for a generator which also has the ability to bundle its output into an array.

IntGeneratorTo

type IntGeneratorTo = {
    toExclusive(stopExclusive: number): IntGenerator;
    toInclusive(stopInclusive: number): IntGenerator;
};

Partial for the last step of an IntRange builder.

IntRange

type IntRange = {
    from(startInclusive: number): {
        by(skip: number): IntGeneratorTo;
        get down(): IntGeneratorTo;
        get up(): IntGeneratorTo;
    };
};

Integer range generators which (hopefully) make it super clear what your boundary, direction, and increment are.

IteratorTransformerConstructor

type IteratorTransformerConstructor<InputT, OutputT> = SyncIteratorTransformerConstructor<InputT, OutputT> | AsyncIteratorTransformerConstructor<InputT, OutputT>;

IteratorTransformerMore

type IteratorTransformerMore<T> = () => Optional<T>;

JsonParseEvent

type JsonParseEvent = JsonParseBeginEvent<JsonParseState> | JsonParseEndEvent<JsonParseState>;

JsonParseState

type JsonParseState = JsonParseObjectState | JsonParseArrayState | JsonParseItemState | JsonParsePropertyState | JsonParseRootState;

JsonParseTypeT

type JsonParseTypeT = (typeof JsonParseType)[keyof typeof JsonParseType];

JsonPunctuation

type JsonPunctuation = "{" | "}" | "[" | "]" | ":" | ",";

JsonToken

type JsonToken = JsonNullToken | JsonBooleanToken | JsonNumberToken | JsonStringToken | JsonPunctuationToken | JsonSpaceToken;

JsonTokenTypeT

type JsonTokenTypeT = (typeof JsonTokenType)[keyof typeof JsonTokenType];

LCEPresetName

type LCEPresetName = keyof typeof LCE_PRESETS;

List

type List<T> = {
    at(index: number): T | undefined;
    get head(): T | undefined;
    insertAt(index: number, value: T): void;
    get isEmpty(): boolean;
    get length(): number;
    pop(): T | undefined;
    push(value: T): void;
    shift(): T | undefined;
    toArray(): T[];
    unshift(value: T): void;
    values(): Generator<T, void, undefined>;
    valuesAndIndexes(): Generator<[T, number], void, undefined>;
    walk(block: (value: T, index: number) => ListWalkDecision<T>): void;
    readonly [Symbol.toStringTag]: string;
};

Basic list-like structure.

ListWalkDecision

type ListWalkDecision<T> = {
    deleteItem?: boolean;
    insertAfter?: T;
    insertBefore?: T;
    keepWalking: boolean;
};

Controls how a List's walk operation behaves after each iteration.

Optional

type Optional<T> = {
    value: T;
} | undefined;

ParseLocalDateConfig

type ParseLocalDateConfig = {
    offsetMinutes?: number;
    time?: boolean;
    timeDelimiters?: string[];
    zone?: boolean;
};

Configuration for a parseLocalDate call.

PropertiesFromDescriptors

type PropertiesFromDescriptors<R extends Record<string, TypedPropertyDescriptor<unknown>>> = {
    readonly [K in ReadOnlyDescriptorsKeys<R>]: R[K] extends TypedPropertyDescriptor<infer V> ? V : never;
} & {
    [K in ReadWriteDescriptorsKeys<R>]: R[K] extends TypedPropertyDescriptor<infer V> ? V : never;
} & {
    [K in WriteOnlyDescriptorsKeys<R>]: R[K] extends TypedPropertyDescriptor<infer V> ? V : never;
} & {
    [K in RenamedWriteOnlyDescriptorsKeys<R>]?: undefined;
};

Produce an object with the properties described by the descriptors. See RenameIfWriteOnlyDescriptor for details on the mangling of write-only properties.

PropertyDescriptorFlags

type PropertyDescriptorFlags = {
    configurable?: boolean;
    enumerable?: boolean;
    writable?: boolean;
};

Basic flags for any property descriptor.

PropertyFromDescriptor

type PropertyFromDescriptor<K extends string, D extends TypedPropertyDescriptor<unknown>> = D extends TypedPropertyDescriptor<infer V> ? ({
    readonly [key in IfReadOnlyDescriptor<K, D>]: V;
} & {
    [key in IfReadWriteDescriptor<K, D>]: V;
} & {
    [key in IfWriteOnlyDescriptor<K, D>]: V;
} & {
    [key in RenameIfWriteOnlyDescriptor<K, D>]?: undefined;
}) : never;

Produce a single-property object type for the given property descriptor. Note: will produce an additional mangled pseudo-property for write-only properties. See RenameIfWriteOnlyDescriptor for details on the mangling.

Queue

type Queue<T> = {
    add(value: T): void;
    peek(): T | undefined;
    remove(value: T): void;
    get length(): number;
    take(): T | undefined;
    toArray(): T[];
    values(): Generator<T, void, undefined>;
};

Basic interface for a queue.

ReadOnlyDescriptorsKeys

type ReadOnlyDescriptorsKeys<R> = R extends Record<infer K, TypedPropertyDescriptor<unknown>> ? {
    [key in K]: IfReadOnlyDescriptor<key, R[key]>;
}[K] : never;

Produce the keys for the given property descriptors record which would produce read-only properties.

ReadOnlyPropertyDescriptor

type ReadOnlyPropertyDescriptor = {
    writable: false;
};

Partial property descriptor which has been marked as non-writable.

ReadWriteDescriptorsKeys

type ReadWriteDescriptorsKeys<R> = R extends Record<infer K, TypedPropertyDescriptor<unknown>> ? {
    [key in K]: IfReadWriteDescriptor<key, R[key]>;
}[K] : never;

Produce the keys for the given property descriptors record which would produce read-write (or write-only) properties.

RenamedWriteOnlyDescriptorsKeys

type RenamedWriteOnlyDescriptorsKeys<R> = R extends Record<infer K, TypedPropertyDescriptor<unknown>> ? {
    [key in string & K]: RenameIfWriteOnlyDescriptor<key, R[key]>;
}[string & K] : never;

Produce the mangled keys for the given property descriptors record which would produce write-only properties. See RenameIfWriteOnlyDescriptor for details on the mangling.

RenameIfWriteOnlyDescriptor

type RenameIfWriteOnlyDescriptor<Key extends string, D extends TypedPropertyDescriptor<unknown>> = D extends SetPropertyDescriptor<unknown> ? `${Key}IsWriteOnly` : never;

Mangle the given Key to ${Key}IsWriteOnly if property descriptor D would produce a write-only property.

ReQuoteOptions

type ReQuoteOptions = {
    auto?: true;
    quotes?: never;
} | {
    auto?: never;
    quotes?: string;
};

SearchResult

type SearchResult = {
    before?: undefined;
    comparisons: number;
    exists: true;
    index: number;
} | {
    before: number;
    comparisons: number;
    exists: false;
    index?: undefined;
};

A result of a search through a list. If the value was found, its index is returned. Otherwise, the before value is the index before which the value could be inserted. For troubleshooting and instrumentation, also returns the number of comparisons it took to find the value.

SetPropertyDescriptor

type SetPropertyDescriptor<T> = PropertyDescriptorFlags & {
    get?: never;
    set(t: T): void;
};

Partial property descriptor which includes only a mutator (setter) and not an accessor (getter), and is thus write-only. Note: TypeScript support for these kinds of properties is very poor as of v5.7.

ShuffleConfig

type ShuffleConfig<T> = {
    into?: T[] | undefined;
    random01?: () => number;
};

Configuration options for the shuffle function.

StarGlobPart

type StarGlobPart = StarGlobText | StarGlobStar;

StringIterable

type StringIterable = string | Iterable<string, undefined, undefined> | Iterator<string, undefined, undefined>;

SvgAbsolutePathCommand

type SvgAbsolutePathCommand = "M" | "L" | "H" | "V" | "Z" | "C" | "S" | "Q" | "T" | "A";

SvgPathCommand

type SvgPathCommand = SvgAbsolutePathCommand | SvgRelativePathCommand;

SvgPathToken

type SvgPathToken = SvgPathTokenByType[keyof SvgPathTokenByType];

SvgPathValue

type SvgPathValue = SvgPathValueByType[SvgPathValueType];

SvgPathValueType

type SvgPathValueType = keyof SvgPathValueByType;

SvgRelativePathCommand

type SvgRelativePathCommand = Lowercase<SvgAbsolutePathCommand>;

SyncIteratorTransformerConstructor

type SyncIteratorTransformerConstructor<InputT, OutputT> = AbstractConstructorLike<[iterator: Iterator<InputT, undefined, undefined>], IteratorTransformer<InputT, OutputT>>;

ToBatchesMode

type ToBatchesMode = typeof SPREAD_BATCHES | typeof FILL_BATCHES;

Strategy for grouping array items into batches.

TypedPropertyDescriptor_2

type TypedPropertyDescriptor<T> = ValuePropertyDescriptor<T> | GetPropertyDescriptor<T> | SetPropertyDescriptor<T> | GetSetPropertyDescriptor<T>;

Union for reasonable configurations of property descriptors which could affect the type for the property.

ValuePropertyDescriptor

type ValuePropertyDescriptor<T> = PropertyDescriptorFlags & {
    get?: never;
    set?: never;
    value: T;
};

Partial property descriptor which contains a static value, instead of an accessor and/or mutator.

WriteOnlyDescriptorsKeys

type WriteOnlyDescriptorsKeys<R> = R extends Record<infer K, TypedPropertyDescriptor<unknown>> ? {
    [key in string & K]: IfWriteOnlyDescriptor<key, R[key]>;
}[string & K] : never;

Produce the non-mangled keys for the given property descriptors record which would produce write-only properties.

Variables

con

con: ConsoleLike

DQ

DQ: "\""

DURATION_DATE_DESIGNATORS

DURATION_DATE_DESIGNATORS: readonly DurationDesignator[]

DURATION_DESIGNATORS

DURATION_DESIGNATORS: readonly DurationDesignator[]

DURATION_KEY_BY_DESIGNATOR

DURATION_KEY_BY_DESIGNATOR: Readonly<{
    readonly Y: "year";
    readonly D: "day";
    readonly H: "hour";
    readonly S: "second";
    readonly W: "week";
}>

Map between DurationDesignator and Duration property name. Does not include M, which is ambiguous, nor T which does not correspond to a property.

DURATION_KEY_SECONDS

DURATION_KEY_SECONDS: Readonly<Required<Omit<Duration, "month" | "text" | "year">>>

Lookup table for the conversion of a Duration property value to seconds. Does not include month or year, which have variable numbers of days.

DURATION_TIME_DESIGNATORS

DURATION_TIME_DESIGNATORS: readonly DurationDesignator[]

ecmaKeySort

ecmaKeySort: Comparator<string>

Comparator for Object keys in ECMA "correct" order. Don't read the history on this. It will only depress you.

FILL_BATCHES

FILL_BATCHES = "fill"

Fill each batch to the maximum, except possibly the last. That is, if the list has 11 items with a maxPerBatch of 5, you would get [5, 5, 1].

INDEX_KEY_PATTERN

INDEX_KEY_PATTERN: RegExp

Pattern for an array index key, basically any integer.

INFINITY_SIGIL

INFINITY_SIGIL = "∞"

Text used for displaying human-readable infinity.

INT_SET_SIGIL

INT_SET_SIGIL = "ℤ"

intRange

intRange: IntRange

Start generating a range of integers.

JSON_PATH_ROOT

JSON_PATH_ROOT: "$"

JSON_PUNCTUATION

JSON_PUNCTUATION: readonly JsonPunctuation[]

JsonParseTransition

JsonParseTransition: Readonly<{
    readonly Begin: "begin";
    readonly End: "end";
}>

JsonParseType

JsonParseType: Readonly<{
    readonly Arr: "array";
    readonly Item: "item";
    readonly Obj: "object";
    readonly Prop: "property";
    readonly Root: "root";
}>

JsonTokenType

JsonTokenType: Readonly<{
    Boo: "boolean";
    Nul: "null";
    Num: "number";
    Pun: "pun";
    Spc: "space";
    Str: "string";
}>

Discriminators for each of the type values for JsonToken.

LCE_PRESET_NAMES

LCE_PRESET_NAMES: LCEPresetName[]

LCE_PRESETS

LCE_PRESETS: {
    ansiC: (seed: number | bigint | undefined) => {
        a: number;
        c: number;
        m: number;
        seed: number | bigint | undefined;
        width: number;
    };
    borlandC: (seed: number | bigint | undefined) => {
        a: number;
        c: number;
        m: number;
        seed: number | bigint | undefined;
        width: number;
    };
    c88: (seed: number | bigint | undefined) => {
        a: number;
        c: number;
        m: number;
        seed: number | bigint | undefined;
    };
    c93: (seed: number | bigint | undefined) => {
        a: number;
        c: number;
        m: number;
        seed: number | bigint | undefined;
    };
    delphi: (seed: number | bigint | undefined) => {
        a: number;
        c: number;
        m: number;
        seed: number | bigint | undefined;
        width: number;
    };
    glibc: (seed: number | bigint | undefined) => {
        a: number;
        c: number;
        m: number;
        seed: number | bigint | undefined;
        width: number;
    };
    java: (seed?: number | bigint | undefined) => RNGOptions;
    knuth: (seed: number | bigint | undefined) => {
        a: bigint;
        c: number;
        m: bigint;
        seed: number | bigint | undefined;
        width: number;
    };
    visualC: (seed: number | bigint | undefined) => {
        a: number;
        c: number;
        m: number;
        floor: number;
        seed: number | bigint | undefined;
        width: number;
    };
}

METRIC_PREFIXES

METRIC_PREFIXES: readonly string[]

List of metric prefixes, where the index is its base-1000 or base-1024 offset.

NEG_INFINITY_SIGIL

NEG_INFINITY_SIGIL = "-∞"

Text used for displaying human-readable negative infinity.

numberAsc

numberAsc: Comparator<number>

Numeric comparator which sorts lower values before higher ones.

numberDesc

numberDesc: Comparator<number>

Numeric (reverse) comparator which sorts higher values before lower ones.

PI_SIGIL

PI_SIGIL = "π"

Text used for displaying human-readable pi.

REAL_SET_SIGIL

REAL_SET_SIGIL = "ℝ"

SPREAD_BATCHES

SPREAD_BATCHES = "spread"

Try to spread out the batches evenly. That is, if the list has 11 items with a maxPerBatch of 5, instead of getting [5, 5, 1] you would get [4, 4, 3].

SQ

SQ: "'"

stringAsc

stringAsc: Comparator<string>

String comparator which sorts in lexicographic (dictionary) order.

stringDesc

stringDesc: Comparator<string>

String comparator which sorts in reverse lexicographic (dictionary) order.

SVG_ABSOLUTE_PATH_COMMANDS

SVG_ABSOLUTE_PATH_COMMANDS: readonly SvgAbsolutePathCommand[]

SVG_PATH_COMMANDS

SVG_PATH_COMMANDS: readonly SvgPathCommand[]

SVG_RELATIVE_PATH_COMMANDS

SVG_RELATIVE_PATH_COMMANDS: readonly SvgRelativePathCommand[]

TIME_DELIMITERS

TIME_DELIMITERS: string[]

Possible delimiters between a date and a time value.

Package Sidebar

Install

npm i @rickosborne/foundation

Weekly Downloads

17

Version

2025.3.12

License

CC-BY-NC-SA-4.0

Unpacked Size

692 kB

Total Files

398

Last publish

Collaborators

  • rickosborne