cache(fn)
Returns a function that caches the output values of fn(input)
against input values in a map, such that for each input value
fn is only ever called once.
A library of functions, observers and streams, published as ES6 modules.
Import functions from the Fn module:
import { get, matches } from '/fn/module.js';
cache(fn)
Returns a function that caches the output values of fn(input)
against input values in a map, such that for each input value
fn is only ever called once.
compose(fn2, fn1)
Calls fn1, passes the result to fn2, and returns that result.
curry(fn [, muteable, arity])
Returns a function that wraps fn and makes it partially applicable.
choose(fn, map)
Returns a function that takes its first argument as a key and uses it
to select a function in map which is invoked with the remaining arguments.
Where map has a function default, that function is run when a key
is not found, otherwise unfound keys will error.
var fn = choose({
'fish': function fn1(a, b) {...},
'chips': function fn2(a, b) {...}
});
fn('fish', a, b); // Calls fn1(a, b)once(fn)
Returns a function that calls fn the first time it is invoked,
and then becomes a noop.
overload(fn, map)
Returns a function that calls a function at the property of object that
matches the result of calling fn with all arguments.
var fn = overload(toType, {
string: function a(name, n) {...},
number: function b(n, m) {...}
});
fn('pie', 4); // Returns a('pie', 4)
fn(1, 2); // Returns b(1, 2)pipe(fn1, fn2, ...)
Returns a function that calls fn1, fn2, etc., passing the result of
calling one function to the next and returning the the last result.
weakCache(fn)
Returns a function that caches the return values of fn()
against input values in a WeakMap, such that for each input value
fn is only ever called once.
The functions below are curried (where they take more than one parameter). They may be partially applied.
argument(n)
Returns a function that returns its nth argument when called.
call(fn)
Returns a function that calls fn() with no arguments.
equals(a, b)
Perform a deep equality comparison of a and b. Returns true if
they are equal.
get(name, object)
Get property name of object.
getPath(path, object)
Returns the value at path in object.
const value = getPath('path.to.value', object);has(key, value, object)
Returns true if object[key] is strictly equal to value.
id(value)
Returns value.
invoke(name, parameters, object)
Invokes object.name() with parameters as arguments. For example:
models.forEach(invoke('save', [version]));is(a, b)
Perform a strict equality check of a === b.
isDefined(value)
Check for value – where value is undefined, NaN or null, returns
false, otherwise true.
matches(selector, object)
Where selector is an object containing properties to be compared against
properties of object. If they are all strictly equal, returns true,
otherwise false.
const vegeFoods = menu.filter(matches({ vegetarian: true }));noop()
Returns undefined.
not(value)
Returns !value.
requestTick(fn)
Call fn on the next tick.
self()
Returns this.
set(key, object, value)
// Set `input.value` whenever a value is pushed into a stream:
stream.scan(set('value'), input);setPath(path, object, value)
Sets value at path in object.
stream.each(setPath('prop.value'), object);toArray(object)
toClass(object)
toFixed(number)
toString(object)
Returns object.toString().
toType(object)
Returns typeof object.
append(str2, str1)
Returns str1 + str2.
prepend(string1, string2)
Returns str1 + str2.
prepad(chars, n, string)
Pads string to n characters by prepending chars.
postpad(chars, n, string)
Pads string to n characters by appending chars.
capture(regex, reducers, accumulator, string)
Parse string with regex, calling functions in reducers to modify
and return accumulator.
Reducers is an object of functions keyed by the index of their capturing
group in the regexp result (0 corresponding to the entire regex match,
the first capturing group being at index 1). Reducer functions are
called in capture order for all capturing groups that captured something.
Reducers may also define the function ‘close’, which is called at the end
of every capture. All reducer functions are passed the paremeters
(accumulator, tokens), where tokens is the regexp result, and are expected
to return a value that is passed as an accumulator to the next reducer function.
Reducers may also define a function 'catch', which is called when a match
has not been made (where 'catch' is not defined an error is thrown).
const parseValue = capture(/^\s*(-?\d*\.?\d+)(\w+)?\s*$/, {
// Create a new accumulator object each call
0: () => ({}),
1: (acc, tokens) => {
acc.number = parseFloat(tokens[1]);
return acc;
},
2: (acc, tokens) => {
acc.unit = tokens[2];
return acc;
}
}, null);
const value = parseValue('36rem'); // { number: 36, unit: 'rem' }
exec(regex, fn, string)
Calls fn with the result of regex.exec(string) if that result is not null,
and returns the resulting value.
parseInt(string)
Parse to integer without having to worry about the radix parameter,
making it suitable, for example, to use in array.map(parseInt).
slugify(string)
Replaces any series of non-word characters with a '-' and lowercases the rest.
slugify('Party on #mydudes!') // 'party-on-mydudes'
toCamelCase(string)
Capitalises any Letter following a '-' and removes the dash.
toPlainText(string)
Normalises string as plain text without accents using canonical decomposition (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize).
wrap(min, max, n)
gaussian()
Generate a random number with a gaussian distribution centred at 0 with limits -1 to 1.
todB(level)
Converts a value to decibels relative to unity (dBFS).
toLevel(dB)
Converts a dB value relative to unity (dBFS) to unit value.
toRad(deg)
toDeg(rad)
clamp(min, max, n)
mod(divisor, n)
JavaScript’s modulu operator (%) uses Euclidean division, but for
stuff that cycles through 0 the symmetrics of floored division are often
are more useful. This function implements floored division.
gcd(a, b)
Returns the greatest common divider of a and b.
lcm(a, b)
Returns the lowest common multiple of a and b.
factorise(array)
Reduces a fraction (represented by array in the form
[numerator, denominator]) by finding the greatest common divisor and
dividing by it both values by it.
Returns a new array in the form [numerator, denominator].
cubicBezier(point1, point2, duration, x)
Where point1 and point2 are [x, y] vectors describing control points.
toCartesian(polar)
toPolar(cartesian)
by(fn, a, b)
Compares fn(a) against fn(b) and returns -1, 0 or 1. Useful for sorting
objects by property:
[{id: '2'}, {id: '1'}].sort(by(get('id'))); // [{id: '1'}, {id: '2'}]byAlphabet(a, b)
Compares a against b alphabetically using the current locale alphabet.
each(fn, array)
Calls fn for each member in array.
map(fn, object)
Delegates to object.map or Array.map to return a new collection of mapped
values.
filter(fn, object)
Delegates to object.filter or Array.filter to return a new collection of
filtered objects.
reduce(fn, seed, object)
Delegates to object.reduce or Array.reduce to return a reduced value.
concat(array2, array1)
Where JavaScript’s Array.concat only works reliably on arrays, concat
will glue together any old array-like object.
insert(fn, array, object)
Inserts object into array at the first index where the result of
fn(object) is greater than fn(array[index]).
last(array)
Gets the last value from an array.
remove(array, value)
Remove value from array. Where value is not in array, does nothing.
rest(n, array)
take(n, array)
unique(array)
Takes an array or stream as array, returns an object of the same
type without duplicate values.
update(create, destroy, fn, target, source)
Returns a new array containing items that are either matched objects from
target assigned new data from source objects or, where no match is found,
new objects created by calling create on a source object. Any objects
in target that are not matched to source objects are destroyed by calling
destroy on them.
parseDate(date)
Parse a date, where, date may be:
Returns a date object (or the date object, if it represents a valid date).
parseDateLocal(date)
As parseDate(date), but returns a date object with local time set to the
result of the parse.
formatDate(format, locale, timezone, date)
Formats date, an ISO string or number in seconds or a JS date object,
to the format of the string format. The format string may contain the tokens:
'YYYY' years'YY' 2-digit year'MM' month, 2-digit'MMM' month, 3-letter'MMMM' month, full name'D' day of week'DD' day of week, two-digit'DDD' weekday, 3-letter'DDDD' weekday, full name'hh' hours'mm' minutes'ss' secondsThe locale string may be 'en' or 'fr'. The 'timezone' parameter is
either 'UTC' or an IANA timezone such as ‘Europe/Zurich‘
(timezones on Wikipedia).
const date = formatDate('YYYY', 'en', 'UTC', new Date()); // 2020formatDateLocal(format, locale, date)
As formatDate(date), but returns a date object with local time set to the
result of the parse.
formatDateISO(date)
Formats date (a string or a number or date accepted by parseDate(date)) as
a string in the ISO date format.
formatDateTimeISO(date)
Formats date (a string or a number or date accepted by parseDate(date)) as
a string in the ISO datetime format.
addDate(diff, date)
Sums diff and date, where diff is a string in ISO date format. Returns
a new date object.
const addWeek = addDate('0000-00-07');
const sameTimeNextWeek = addWeek(new Date());floorDate(token, date)
Floors date to the start of nearest calendar point in increment indicated
by token:
'Y' Year'M' Month'w' Week'd' Day'h' Hour'm' Minute's' Second'mon' Monday'tue' Tuesday'wed' Wednesday'thu' Thursday'fri' Friday'sat' Saturday'sun' Sundayconst dayCounts = times.map(floorDate('d'));parseTime(time)
Where time is a string it is parsed as a time in ISO time format: as
hours '13', with minutes '13:25', with seconds '13:25:14' or with
decimal seconds '13:25:14.001'. Returns a number in seconds.
const time = parseTime('13:25:14.001'); // 48314.001Where time is a number it is assumed to represent a time in seconds
and is returned directly.
const time = parseTime(60); // 60formatTime(format, time)
Formats time, an ‘hh:mm:ss’ time string or a number in seconds, to match
format, a string that may contain the tokens:
'±' Sign, renders ‘-‘ if time is negative, otherwise nothing'Y' Years, approx.'M' Months, approx.'MM' Months, remainder from years (max 12), approx.'w' Weeks'ww' Weeks, remainder from months (max 4)'d' Days'dd' Days, remainder from weeks (max 7)'h' Hours'hh' Hours, remainder from days (max 24), 2-digit format'm' Minutes'mm' Minutes, remainder from hours (max 60), 2-digit format's' Seconds'ss' Seconds, remainder from minutes (max 60), 2-digit format'sss' Seconds, remainder from minutes (max 60), fractional'ms' Milliseconds, remainder from seconds (max 1000), 3-digit formatconst time = formatTime('±hh:mm:ss', 3600); // 01:00:00formatTimeISO(time)
Formats time, an ‘hh:mm:sss’ time string or a number in seconds, as a string
in the ISO time format.
`
addTime(time1, time2)
Sums time2 and time1, which may be ‘hh:mm:sss’ time strings or numbers in
seconds, and returns time as a number in seconds. time1 may contain hours
outside the range 0-24 or minutes or seconds outside the range 0-60. For
example, to add 75 minutes to a list of times you may write:
const laters = times.map(addTime('00:75'));floorTime(token, time)
Floors time to the start of the nearest token, where token is one of:
'w' Week'd' Day'h' Hour'm' Minute's' Second'ms' Millisecondtime may be an ISO time string or a time in seconds. Returns a time in seconds.
const hourCounts = times.map(floorTime('h'));An observer is an ES6 Proxy of an object that intercepts and reports mutations. Import and create an observer:
import { Observer, observe } from '/fn/module.js';
const data = Observer({ value: true });
There is only ever one observer per object, ie, calling
Observer(object) multiple times with the same object
(or proxy of that object) always returns the same observer proxy.
Observers can be observed for mutations with the observe function:
observe('value', console.log, data);
Mutations made to the observer proxy's value
property are now logged to the console.
data.value = false; // Logs `false`
observe(path, fn, object [, init])
Observe path in object and call fn(value) with the value at the
end of that path when it mutates. Returns a function that destroys this
observer.
The callback fn is called immediately on initialisation if the value at
the end of the path is not equal to init. In the default case where
init is undefined, paths that end in undefined do not cause the
callback to be called.
(To force the callback to always be called on setup, pass in NaN as an
init value. In JS NaN is not equal to anything, even NaN, so it
always initialises.)
Import and create a stream:
import { Stream } from '/fn/module.js';
const stream = Stream.of(1,2,3,4);
.status
Reflects the running status of the stream. When all values have been consumed
status is 'done'.
.push(value)
Pushes a value (or multiple values) into the head of a writeable stream.
If the stream is not writeable, it does not have a .push() method.
.flat()
Flattens a stream of streams or arrays into a single stream.
.flatMap(fn)
Maps values to lists – fn(value) must return an array, functor, stream
(or any other duck with a .shift() method) and flattens those lists into a
single stream.
.map(fn)
Maps values to the result of fn(value).
.merge(stream)
Merges this stream with stream, which may be an array, array-like
or functor.
.scan(fn, seed)
Calls fn(accumulator, value) and emits accumulator for each value
in the stream.
.dedup()
Filters out consecutive equal values.
.filter(fn)
Filter values according to the truthiness of fn(value).
.latest()
When the stream has a values buffered, passes the last value in the buffer.
.rest(n)
Filters the stream to the nth value and above.
.take(n)
Filters the stream to the first n values.
.throttle(time)
Throttles values such that the latest value is emitted every time seconds.
Other values are discarded. The parameter time may also be a timer options
object, an object with { request, cancel, now } functions,
allowing the creation of, say, and animation frame throttle.
.wait(time)
Emits the latest value only after time seconds of inactivity.
Other values are discarded.
.combine(fn, stream)
Combines the latest values from this stream and stream via the combinator
fn any time a new value is emitted by either stream.
.clone()
Creates a read-only copy of the stream.
.each(fn)
Thirstilly consumes the stream, calling fn(value) whenever
a value is available.
.last(fn)
Consumes the stream when stopped, calling fn(value) with the
last value read from the stream.
.fold(fn, accumulator)
Consumes the stream when stopped, calling fn(accumulator, value)
for each value in the stream. Returns a promise.
.shift()
Reads a value from the stream. If no values are in the stream, returns
undefined. If this is the last value in the stream, stream.status
is 'done'.
.done(fn)
Calls fn() after the stream is stopped and all values have been drained.
.start()
If the stream’s producer is startable, starts the stream.
.stop()
Stops the stream. No more values can be pushed to the stream and any
consumers added will do nothing. However, depending on the stream’s source
the stream may yet drain any buffered values into an existing consumer
before entering 'done' state. Once in 'done' state a stream is
entirely inert.