Functions

Import functions from the Fn module:

import { get, matches } from '/fn/module.js';

Functions

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.

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), allowing them to be partially applied.

Objects

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.

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 }));

Strings

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).

Numbers

Arrays

Time

parseDate(date)

Parse a date, where, date may be:

  • a string in ISO date format
  • a number in seconds UNIX time
  • a date object

Returns a date object, or the date object, if it validates.

parseDateLocal(date)

As parseDate(date), but returns a date object with local time set to the result of the parse (or the original date object, if it validates).

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.

toDay(date)

Returns day of week as a number, where monday is 0.

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 time 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' Sunday
const dayCounts = times.map(floorTime('days'));

formatDate(locale, timezone, format, date)

Formats date (a string or number or date accepted by parseDate(date)) 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' seconds
const date = formatDate('en', '', 'YYYY', new Date());   // 2020

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.001

Where time is a number it is assumed to represent a time in seconds and is returned directly.

const time = parseTime(60);               // 60

formatTime(format, time)

Formats time (an ‘hh:mm:sss’ 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 format
const time = formatTime('±hh:mm:ss', 3600);   // 01:00:00

formatTimeISO(time)

Formats time (a string or a number accepted by parseTime(time)) as a string in the ISO time format. `

addTime(time1, time2)

Sums time2 and time1, returning UNIX time as a number in seconds. If time1 is a string, it is parsed as a duration, where numbers are accepted outside the bounds of 0-24 hours or 0-60 minutes or seconds. For example, to add 72 minutes to a list of times:

const laters = times.map(addTime('00:72'));

floorTime(token, time)

Floors time to the nearest token, where token is one of: 'week', 'day', 'hour', 'minute' or 'second'. time may be an ISO time string or a time in seconds. Returns a time in seconds.

const hourCounts = times.map(floorTime('hour'));

Observer

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`

Stream

Import and create a stream:

import { Stream } from '/fn/module.js';
const stream = Stream.of(1,2,3,4);

Properties

.status

Reflects the running status of the stream. When all values have been consumed status is 'done'.

Write

.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.

Map

.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.

Filter

.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.

Read

.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'.

Lifecycle

.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.