JavaScript/TypeScript utilities
npm i @softsky/utils
ZERO DEPENDENCIES utils library. Test coverage 100%.
Usual utils plus more obscure stuff that I've never seen in any library. Also fancy TypeScript generics and types that I often use.
I don't know why would you want to, but here's how to:
- Install Bun
- Install dependencies
bun iornpm i - Lint files
bun run lint - Run tests
bun run test - Update README
bun run gen-readme - Create merge request
Don't forget to follow comment style for new exported features:
/** Description of how it works (REQUIRED) */
export function newStuff() {}Everything array related.
function randomFromArray - Returns random element from non-empty array
function shuffleArray - Create new shuffled array
function swap - Swap two elements in array
function binarySearch - Binary search in sorted array.
Compare function should compare your needed value with value on index passed to it.
If compare returns 0 it means we found target.
If compare returns > 0 it means we have to cut out bigger side of array.
If compare returns < 0 it means we have to cut out smaller side of array.
function chunk - Split array into sub arrays of spicified size
function combinations - Return all combinations of items in array
function permutations - Return all permutations of items in array
function pushToSorted - Push data to sorted array. Array will always be kept sorted.
Compare function should compare your needed value with value on index passed to it. If compare returns 0 it means we found target. If compare returns > 0 it means target is smaller. If compare returns < 0 it means target is bigger.
pushToSorted(numArray, 10, x => x - 10);function removeFromArray - Delete value from array.
Only deletes first encountered.
Returns index of deleted value.
function removeLastFromArray - Delete value from array.
Only deletes last encountered.
Returns index of deleted value.
function reverse - Reverse part of array
Some useful consts. That's it.
const DAY_MS - Milliseconds in a full day
const HOUR_MS - Milliseconds in a hour
const MIN_MS - Milliseconds in a minute
const SEC_MS - Milliseconds in a second
Utils related to code execution flow.
const SESSION_ID - Id generated only once per session
function UUID - Get universally unique string id.
You can get information then id was generated using extractUUIDDate(uuid)
- 13 char - timestamp
- 13 char - SESSION_ID
- 4 char - incremental id
30 char total.
USING CUSTOM TIMESTAMP MAY RESULT IN COLLISSIONS
function extractUUIDDate - Extract exact date of uuid generation
function createCashedFunction - Creates cached function. All arguments/results are cached.
Returns [
fn [cached function],
delete [delete cached result for arguments]
hash
]
function createCashedAsyncFunction - Creates cached function. All arguments/results are cached. Will store in cache resolved data.
Returns [
fn [cached function],
delete [delete cached result for arguments]
hash
]
async function retry - Retry async function
function createDebouncedFunction - Create debounced function. Basically adds cooldown to function. Warning: throws!
function createThrottledFunction - Create throttled function. Basically limits function calls in time period. Warning: throws!
function createDelayedFunction - Create debounced function. Basically create function that will be called with delay,
but if another call comes in, we reset the timer (previous function isn't called).
class ImmediatePromise - Promise that accepts no callback, but exposes resolve and reject methods
function wait - setTimeout promisify
function timeout - Reject after specified time
function noop - Empty function that does nothing
async function concurrentRun - Run array of async tasks concurrently
class SimpleEventSource - Create simple event source. Consider using signal() for reactive state managment.
class Semaphore - Semaphore is used to limit concurrent tasks by delaying promise.
const semaphore = new Semaphore(2);
async function task() {
await semaphore.acquire();
try {
// This code can only be executed by two tasks at the same time
} finally {
semaphore.release();
}
}
task();
task();
task(); // This task will wait until one of the previous tasks releases the semaphore.
// === SHORTHAND ===
semaphore.run(()=>{
// Your code
})
semaphore.run(()=>{
// Your code
})
// ...async function withTimeout - Add timeout to a promise
function promisify - Promisify a function with callback
function promisifyEventSource - Create a promise out of EventSource
Custom errors, finding errors and error handling.
class ValidationError - Use as intended error. Basically 4** errors in HTTP
class TimeoutError - Use as intended error. Basically 4** errors in HTTP
function findErrorText - Find error inside anything recursively.
Good for finding human-readable errors.
Tries priority keys first.
Parses JSON automatically.
Returns undefind if nothing found.
Anything related to formatting and logging.
type FormatTimeRange - Type for formatTime ranges
const FORMAT_NUMBER_RANGES - Default time range
const FORMAT_NUMBER_RANGES_READABLE - Time range more suitable for readability
const FORMAT_NUMBER_RANGES_BYTES - Bytes range
function formatNumber - Milliseconds to human readable time. Minimum accuracy, if set to 1000 will stop at seconds
function camelToSnakeCase - thisCase to this_case
function snakeToCamelCase - this_case to thisCase
function formatBytes - Bytes to KB,MB,GB,TB
function log - Format logging
function capitalizeFirstLetter - Capitalize first letter
function pipe - pipe() can be called on one or more functions, each of which can take the return of previous value.
// Takes string, converts to int, calc sqrt, convert and return date
pipe(
(x: string) => Number.parseInt(x),
(x) => Math.sqrt(x),
(x) => new Date(x)
)('69')Pos
function unfoldPathfindingResult - Unfold pathfinding result to path array.
function aStar - Pathfind using aStar.
Returns a target and map of parents.
You can use unfoldPathfindingResult() to get array of nodes.
function bfs - Breadth-first search. Slower than dfs.
If isTarget is omitted becomes floodfill.
Returns a target and map of parents.
You can use unfoldPathfindingResult() to get array of nodes.
function dfs - Depth-first search. Faster than bfs.
If isTarget is omitted becomes floodfill.
Returns a target and map of parents.
You can use unfoldPathfindingResult() to get array of nodes.
function dijkstra - Dijkstra search. Like bfs but supports weight.
If isTarget is omitted becomes floodfill (WITH WEIGHT).
Returns a target and map of parents.
You can use unfoldPathfindingResult() to get array of nodes.
function knapsack - Knapsack find best way to get maximum value in limited capacity
function hamiltonianCycle - Find min path between points. You need to supply 2-dim array
where first index is a point and second index is a distance from this point to another.
Put infinity if where are no path. Returns cycle (start and end at the same point)
Original: https://github.com/qntm/held-karp
function traverseByNearestNeighbor - Traverse all points by nearest neighbor. Should be able to go from any point to any other point.
function twoOpt - 2-opt improvement
Numbers, math, etc.
function random - Random number between min and max. May enable float
function parseInt - Same as Number.parseInt but throws if NaN or not safe
function parseFloat - Same as Number.parseFloat but throws if NaN or Infinity
function factorial - Factorial
function fib - Fibonacci
function clamp - Clamp numbers to max and min
function inRange - Is number in range. Inclusive.
function mean - Calucalate avarage from array of numbers
function round - Round with precision.
round(1.2345); // 1
round(1.2345, 2); // 1.23
round(1.2345, 10); // 1.2345function sum - Sum of array of numbers
[object Object]
function getPropertyNames - Get all prorerty names, including in prototype
function objectMap - Map function like for arrays, but for objects
function objectFilter - Filter function like for arrays, but for objects
function addPrefixToObject - Adds prefix to every key in object
function deepEquals - Check if objects are deep equal
Supports:
- All primitives (String, Number, BigNumber, Null, undefined, Symbol)
- Objects
- Iterables (Arrays, Map, Sets, Queries, Generators etc.)
- Dates
Not supported:
- Functions
- Async iterables
- Promises
- etc
Behavior with types above are not defined, but it will still check them by reference.
function pick - Pick keys from object
class Base - Base class that helps to manage ids and subclasses.
Include next lines when extending this class:
static {
this.registerSubclass()
}Reactive signals
function signal - SIGNALS SYSTEM
Signal can hold any data (except functions), when this data has changed any effects containing this signal will be rerun.
const $mySignal = signal<number|undefined>(1) // Create signal with initial value 1
$mySignal(5) // Set to 5
$mySignal(undefined) // Set to undefined
$mySignal(prev=>prev+1) // Increment
// Will print signal on change
effect(()=>{
console.log($mySignal())
})function effect - SIGNALS SYSTEM
Effects are simplest way to react to signal changes. Returned data from handler function will be passed to it on next signal change. Returns a function that will clear the effect.
// Will print signal on change
effect(()=>{
console.log($mySignal())
})
// Use previous state as a reference
effect((last)=>{
const mySignal = $mySignal()
if(last>mySignal) console.log('Increment!')
return mySignal;
})function untrack - SIGNALS SYSTEM
Untrack helps to not react to changes in effects.
const $a = signal(1)
const $b = signal(2)
// Will only run on changes to $b
effect(()=>{
console.log(untrack($a)+$b())
})function computed - SIGNALS SYSTEM
Creates a derived reactive memoized signal.
// Sum of all changes of $a()
const { signal: $sumOfTwo, clear: clearSum } = derived((value) => value + $a(), 0)function batch - SIGNALS SYSTEM
Batches multiple edits, so they don't call same effects multiple times
const $a = signal(1)
const $b = signal(2)
effect(()=>{
console.log($a()+$b())
})
$a(2); // Prints 4
$b(3); // Prints 5
// Prints only 10
batch(()=>{
$a(5);
$b(5);
})function when - SIGNALS SYSTEM
Returns ImmediatePromise that is resolved when check function returns truthy value. If you want to, you can resolve or reject promise beforehand.
await when(() => $a()>5)
// With timeout
const promise = when(() => $a() > 5)
const timeout = setTimeout(() => promise.reject('Timeout')}, 5000)
primise.then(() => clearTimeout(timeout))function resource - SIGNALS SYSTEM
Creates a async resource with outputs:
- value$ - return value of function
- isLoading$ - whether promise is still running
- error$ - error that happened during. Set on error, cleared on refresh
- refresh - force rerun handler
MAKE SURE THAT ALL SIGNAL'S VALUES ARE GRABBED BEFORE NEXT TICK!!!
const userId$ = signal(1);
// WRONG
const userResource = resource(async () => {
const res = await fetch(`/api/user`)
const userId = userId$(); // ERROR: Will not subscribe because after Promise i.e. next tick
return res.json().find(x=>x.id===userId);
})
// Correct
const userResource = resource(async () => {
const userId = userId$(); // Correctly subscribed because ran on the same tick
const res = await fetch(`/api/user`)
return res.json().find(x=>x.id===userId);
})
// React to changes
effect(() => {
if (userResource.isLoading$()) {
console.log('loading user...')
} else if (userResource.error$()) {
console.error('failed to load user', userResource.error$())
} else {
console.log('user loaded', userResource.value$())
}
})
// Force a refresh
userResource.refresh()
// Stop automatic updates and cleanup
userResource.clear()Timers, CRON, etc.
function measurePerformance - Measure performance of a function
function setSafeTimeout - Original setTimeout and setIntval known for accumulating delay
and causing problem with timeouts bigger than 32bit integer.
This timeout wrapper fixes them. Returns clear function.
function setSafeInterval - Original setTimeout and setIntval known for accumulating delay
and causing problem with timeouts bigger than 32bit integer.
This interval wrapper fixes them. Returns clear function.
function cronInterval - Like setInterval but with cron.
Returns clear function.
For cron string syntax check getNextCron() description
function getNextCron - Find next cron date after passed date. This function DOES NOT implement regular CRON 1 to 1.
- [0-999] Milliseconds
- [0-59] Seconds
- [0-59] Minutes
- [0-23] Hours
- [1-31] Dates
- [1-12] Months
- [0-6] Weekdays
Main differences:
- Weekdays value only 0 to 6 (0 is Sunday)
- New supported syntax: 30-60/10 - means 30,40,50,60
- Second and millisecond support: 0,500 300 - every 30 seconds, two times
class SpeedCalculator - Object that calculates speed, ETA and percent of any measurable task.
push() chunks into speed calculator and then read stats for results.
size - a target then task is finished. Without it only speed is calculated.
historyTime - is a time period based on which speed will be calculated.
Damn, I love TypeScript.
type Primitive - Values that are copied by value, not by reference
type AnyFunction - Function with any arguments or return type
type Falsy - Values that convert to false
type Optional - Make keys in object optional
type RequiredKey - Make keys in object required
type Constructor - Get contructor type of an instance
type AwaitedObject - Recursively resolves promises in objects and arrays
type JSONSerializable - Anything that can be serialized to JSON
type ObjectAddPrefix - Adds prefix to all keys in object
type CamelToSnakeCase - Convert type of thisCase to this_case
type ObjectCamelToSnakeCase - Convert object keys of thisCase to this_case
type SnakeToCamel - Convert type of this-case to thisCase
type ObjectSnakeToCamel - Convert object keys of this-case to thisCase
type Concat - Concat types of array or objects
type Prettify - Visual only overhaul. Shows final type result on hover.
type a = {a: '1'}
type b = Prettify<a & { b: 'b' }>
// On hovering b it will show
type b = {
a: "1";
b: "b";
}
// instead of
type b = a & {
b: "b";
}type Tuple - Create a tuple of size.
type a = Tuple<number, 3>
type b = [number, number, number]