Skip to content

Commit

Permalink
add more docs
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanatkn committed Oct 5, 2024
1 parent eeb283e commit 139b934
Show file tree
Hide file tree
Showing 22 changed files with 248 additions and 19 deletions.
2 changes: 2 additions & 0 deletions src/lib/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import type {Array_Element} from '$lib/types.js';
// TODO try to cange to readonly again, see if upstream errors are tolerably fixed
export const EMPTY_ARRAY: any[] = Object.freeze([]) as any;

/** Converts `value` to an array if it's not already. */
export const to_array = <T>(value: T): T extends readonly any[] ? T : T[] =>
Array.isArray(value) ? value : ([value] as any);

/** Removes an element from `array` at `index` in an unordered manner. */
export const remove_unordered = (array: any[], index: number): void => {
array[index] = array[array.length - 1];
array.pop();
Expand Down
12 changes: 12 additions & 0 deletions src/lib/async.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
export type Async_Status = 'initial' | 'pending' | 'success' | 'failure';

/**
* Waits for the given `duration` before resolving.
*/
export const wait = (duration = 0): Promise<void> =>
new Promise((resolve) => setTimeout(resolve, duration));

/**
* Checks if `value` is a `Promise`.
*/
export const is_promise = (value: any): value is Promise<any> =>
value && typeof value.then === 'function';

/**
* Creates a deferred object with a promise and its resolve/reject handlers.
*/
export interface Deferred<T> {
promise: Promise<T>;
resolve: (value: T) => void;
reject: (reason: any) => void;
}

/**
* Creates a object with a `promise` and its `resolve`/`reject` handlers.
*/
export const create_deferred = <T>(): Deferred<T> => {
let resolve!: (value: T) => void;
let reject!: (reason: any) => void;
Expand Down
6 changes: 6 additions & 0 deletions src/lib/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@ export type Red = Flavored<number, 'Red'>; // [0, 255]
export type Green = Flavored<number, 'Green'>; // [0, 255]
export type Blue = Flavored<number, 'Blue'>; // [0, 255]

/**
* Converts an RGB color to a hex color.
*/
export const rgb_to_hex = (r: number, g: number, b: number): number => (r << 16) + (g << 8) + b;

/**
* Converts a hex color to an RGB color.
*/
export const hex_to_rgb = (hex: number): Rgb => [(hex >> 16) & 255, (hex >> 8) & 255, hex & 255];

export const hex_string_to_rgb = (hex: string): Rgb => {
Expand Down
4 changes: 3 additions & 1 deletion src/lib/counter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ export type Counter = () => number;

export type Create_Counter = (initial?: number) => Counter;

// 0-based counter by default
/**
* Creates a counter constructor function, starting at `0`.
*/
export const create_counter: Create_Counter = (count = 0) => {
let c = count;
return () => c++;
Expand Down
11 changes: 11 additions & 0 deletions src/lib/dom.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/**
* Checks if the given element is editable.
* Returns `true` for text-based input types, textareas, and contenteditable elements.
*/
export const is_editable = (el: any): boolean => {
if (!el) return false;
const {tagName} = el;
Expand All @@ -18,6 +22,9 @@ export const is_editable = (el: any): boolean => {
);
};

/**
* Returns `true` if the element is within a `contenteditable` ancestor.
*/
export const inside_editable = (el: HTMLElement | SVGElement): boolean => {
const found = el.closest('[contenteditable]');
return found !== null && found.getAttribute('contenteditable') !== 'false';
Expand Down Expand Up @@ -47,6 +54,10 @@ export const swallow = <
};

// TODO improve these types, the motivation was the strictness of Svelte DOM types
/**
* Handles the value of an event's target and invokes a callback.
* Defaults to swallowing the event to prevent default actions and propagation.
*/
export const handle_target_value =
(cb: (value: any, event: any) => void, swallow_event = true) =>
(e: any): void => {
Expand Down
4 changes: 4 additions & 0 deletions src/lib/error.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/**
* Error for asserting unreachable code paths in TypeScript.
* Useful for exhaustive matching.
*/
export class Unreachable_Error extends Error {
constructor(value: never, message = `Unreachable case: ${value}`) {
super(message);
Expand Down
6 changes: 6 additions & 0 deletions src/lib/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,14 @@ export const to_fetch_value_cache_key = (
return key;
};

/**
* Converts `Fetch_Value_Cache` to a JSON string.
*/
export const serialize_cache = (cache: Fetch_Value_Cache): string =>
JSON.stringify(Array.from(cache.entries()));

/**
* Converts a serialized cache string to a `Fetch_Value_Cache`.
*/
export const deserialize_cache = (serialized: string): Fetch_Value_Cache =>
Fetch_Value_Cache.parse(new Map(JSON.parse(serialized)));
18 changes: 17 additions & 1 deletion src/lib/function.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
/**
* Does nothing when called.
*/
export const noop: (...args: any[]) => any = () => {}; // eslint-disable-line @typescript-eslint/no-empty-function

/**
* Async function that returns a resolved promise.
*/
export const noop_async: (...args: any[]) => Promise<any> = () => resolved;

/**
* A singleton resolved `Promise`.
*/
export const resolved = Promise.resolve();

/**
* Returns the first arg.
*/
export const identity = <T>(t: T): T => t;

export type Lazy<T> = () => T;

/**
* Returns the result of calling `value` if it's a function,
* otherwise it's like the `identity` function and passes it through.
*/
export const lazy = <T>(value: T | Lazy<T>): T =>
typeof value === 'function' ? (value as any)() : value;
typeof value === 'function' ? (value as any)() : value; // TODO rename? `call_if_function` something?
9 changes: 6 additions & 3 deletions src/lib/id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import {create_counter} from '$lib/counter.js';

export type Uuid = Flavored<string, 'Uuid'>;

/**
* Loosely validates a UUID string.
*/
export const is_uuid = (str: string): str is Uuid => UUID_MATCHER.test(str);

/**
Expand All @@ -14,9 +17,9 @@ export const UUID_MATCHER = /^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/iu;

export type Client_Id_Creator = () => string;

// Creates a string id generator function.
// Client ids take the form `${name}_${count}`,
// and they're only safe to persist across page loads by hydrating the initial `count`.
/**
* Creates a string id generator function, outputting `${name}_${count}` by default.
*/
export const create_client_id_creator = (
name: string,
count?: number,
Expand Down
7 changes: 7 additions & 0 deletions src/lib/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@ import {is_plain_object} from '$lib/object.js';

export type Json = string | number | boolean | null | {[prop: string]: Json} | Json[];

/**
* Like `typeof json`, but includes arrays. Excludes `'undefined'` because it's not valid JSON.
*/
export type Json_Type = 'string' | 'number' | 'boolean' | 'null' | 'object' | 'array';

/**
* Converts `value` to a `Json_Type`, which is like `typeof json`
* but includes `'arrays'` and omits `'undefined'`.
*/
export const to_json_type = (value: Json): Json_Type | undefined => {
const type = typeof value;
switch (type) {
Expand Down
9 changes: 9 additions & 0 deletions src/lib/map.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
/**
* Sorts a map by `comparator`, a function that compares two entries,
* defaulting to using `localCompare` and `>`.
*/
export const sort_map = <T extends Map<any, any>>(
map: T,
comparator = compare_simple_map_entries,
): T => new Map([...map].sort(comparator)) as T;

/**
* Compares two map entries for sorting purposes.
* If the key is a string, it uses `localeCompare` for comparison.
* For other types, it uses `>`.
*/
export const compare_simple_map_entries = (a: [any, any], b: [any, any]): number => {
const a_key = a[0];
return typeof a_key === 'string' ? a_key.localeCompare(b[0]) : a[0] > b[0] ? 1 : -1;
Expand Down
64 changes: 63 additions & 1 deletion src/lib/maths.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,91 @@
/**
* Returns `n` bounded to `min` and `max`.
*/
export const clamp = (n: number, min: number, max: number): number =>
Math.min(Math.max(n, min), max);

/**
* Linear interpolation between `a` and `b` by `amount`.
*/
export const lerp = (a: number, b: number, amount: number): number => (1 - amount) * a + amount * b;

/**
* Returns a number clamped between `min` and `max`.
*/
export const round = (n: number, decimals: number): number => {
const mult = 10 ** decimals;
return Math.round(n * mult) / mult;
};

// golden ratio constants, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
/**
* golden ratio/mean constants, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR = 1.618033988749895;
/**
* golden ratio/mean constants, `1/GR`, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR_i = 0.6180339887498948;
/**
* golden ratio/mean constants, `GR**2`, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR_2 = 2.618033988749895;
/**
* golden ratio/mean constants, `1/(GR**2)`, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR_2i = 0.38196601125010515;
/**
* golden ratio/mean constants, `GR**3`, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR_3 = 4.23606797749979;
/**
* golden ratio/mean constants, `1/(GR**3)`, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR_3i = 0.2360679774997897;
/**
* golden ratio/mean constants, `GR**4`, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR_4 = 6.854101966249686;
/**
* golden ratio/mean constants, `1/(GR**4)`, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR_4i = 0.14589803375031543;
/**
* golden ratio/mean constants, `GR**5`, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR_5 = 11.090169943749476;
/**
* golden ratio/mean constants, `1/(GR**5)`, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR_5i = 0.09016994374947422;
/**
* golden ratio/mean constants, `GR**6`, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR_6 = 17.944271909999163;
/**
* golden ratio/mean constants, `1/(GR**6)`, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR_6i = 0.0557280900008412;
/**
* golden ratio/mean constants, `GR**7`, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR_7 = 29.03444185374864;
/**
* golden ratio/mean constants, `1/(GR**7)`, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR_7i = 0.03444185374863302;
/**
* golden ratio/mean constants, `GR**8`, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR_8 = 46.978713763747805;
/**
* golden ratio/mean constants, `1/(GR**8)`, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR_8i = 0.02128623625220818;
/**
* golden ratio/mean constants, `GR**9`, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR_9 = 76.01315561749645;
/**
* golden ratio/mean constants, `1/(GR**9)`, useful for scaling: https://wikipedia.org/wiki/Golden_ratio
*/
export const GR_9i = 0.013155617496424835;
9 changes: 9 additions & 0 deletions src/lib/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export const map_record = <T, K extends string | number, U>(
return result;
};

/**
* Creates a new object without the specified `keys`.
*/
export const omit = <T extends Record<K, any>, K extends keyof T>(
obj: T,
keys: K[],
Expand All @@ -37,6 +40,9 @@ export const omit = <T extends Record<K, any>, K extends keyof T>(
return result;
};

/**
* Creates a new object with properties that pass the `should_pick` predicate.
*/
export const pick_by = <T extends Record<K, any>, K extends string | number>(
obj: T,
should_pick: (value: any, key: K) => boolean,
Expand Down Expand Up @@ -76,6 +82,9 @@ export const reorder = <T extends Record<K, any>, K extends string | number>(
return result;
};

/**
* Frozen empty object with no properties, good for options default values.
*/
export const EMPTY_OBJECT: Record<string | number | symbol, undefined> & object = Object.freeze({});

/**
Expand Down
Loading

0 comments on commit 139b934

Please sign in to comment.