npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

invoke-if

v2.1.1

Published

A powerful control-flow invoker based on the structure of ES6 Maps

Downloads

12

Readme

invoke-if

A dependency-free micro-package providing composable control-flow that works the way we always wished switch would work. It evaluates groups of tests and provides a pattern for if, if/and, if/else, if/then.

Each test that passes invokes that tests function or array of functions. Optionally aggregates the results of the passing invokes to the caller.

Installation

yarn add invoke-if

or

npm install --save invoke-if

Flow Coverage

Proudly built with 100% Flow Coverage. Includes flow definitions so if you are using flow, it will type-check for you.

Breaking Update

Version 2.0 implements a change of the API for invoke-if. Previous versions are not likely to work. These changes were done during perf tests when we realized 90% speed improvements by slightly adjusting the data structure that invoke-if operates upon.

Examples

/* @flow */
import { log } from '../utils/log';
import invokeIf, { invokeMap } from '../src/main';

log('Begin InvokeIf Basic Tests');

// Note that `log()` returns the result of performance.now()

const INVOKE_TESTS = [
  [
    [true, () => log('one')],
    [true, () => log('two')],
    [false, () => log('three')],
    [false, () => log('four')],
  ],
  new Map([
    [() => true, () => log('five')],
    [() => 'true', () => log('six')],
    [() => 'seven', (arg: string) => log(arg)],
  ]),
];

function one() {
  log('Running Example One (invokeReduce / default)');
  return invokeIf(...INVOKE_TESTS);
}

function two() {
  log('Running Example Two (invokeMap)');
  return invokeMap(...INVOKE_TESTS);
}

log('Example One Result: \n', one());

log('Example Two Result: \n', two());

/*
  +1.5743    695406726.602197     Begin InvokeIf Basic Tests

  +1.3778    695406727.980045     Running Example One (invokeReduce / default)
  +0.3265    695406728.306522     one
  +0.0703    695406728.376835     two
  +0.0808    695406728.457588     five
  +0.0625    695406728.520046     six
  +0.0531    695406728.573129     seven
  +0.0336    695406728.606769     Example One Result:
  [
    695406728.306522,
    695406728.376835,
    695406728.457588,
    695406728.520046,
    695406728.573129
  ]

  +1.2038    695406729.810552     Running Example Two (invokeMap)
  +0.0957    695406729.906205     one
  +0.0450    695406729.951161     two
  +0.0308    695406729.981922     five
  +0.0267    695406730.008638     six
  +0.0256    695406730.034196     seven
  +0.0245    695406730.058679     Example Two Result:
  [
    [ 695406729.906205, 695406729.951161 ],
    [ 695406729.981922, 695406730.008638, 695406730.034196 ]
  ]
*/

There are many examples / tests available in the examples directory


Type Signatures

export type $NonFunction = boolean | string | number | { [key: string]: * };

export type InvokeCheck<+A> = (() => A) | A;
export type InvokeFn<A> = (arg: A) => mixed;

export type Invoker<A> =
  | Array<InvokeFn<A> | $NonFunction>
  | (InvokeFn<A> | $NonFunction);

export type ElseInvoker<A> =
  | Array<InvokeFn<A> | $NonFunction>
  | (InvokeFn<A> | $NonFunction);

export type InvokeTest<A> =
  | [InvokeCheck<A>, Invoker<A>]
  | [InvokeCheck<A>, Invoker<A>, ElseInvoker<A>];

export type FactoryFn<A> = () => void | false | null | InvokeTesters<A>;

export type InvokeTesters<A> =
  | Array<InvokeTest<A>>
  | Map<InvokeCheck<A>, Invoker<A>>
  | FactoryFn<A>;

Module Exports

invokeReduce (Function) (default, named)

The default export, reduces the results of the tests into a simple array of results.

declare function invokeReduce(...tests: Array<InvokeTesters<*>>): Array<mixed>;

invokeMap (Function)

Instead of reducing and merging the responses together, invokeMap simply runs the tests and maps the responses directly to the caller. The result is an array of results which are a closer match to the original array.

declare function invokeMap(...tests: Array<InvokeTesters<*>>): Array<mixed>;

invokeAny (Function)

A shortcut for handling the situation when you want to evaluate every entry regardless of if a falsey value is found within the chain.

It is an alias for doing something like:

invokeIf(
  [[true, () => console.log(1)]],
  [[true, () => console.log(2)]],
  [[false, () => console.log(3)]],
  [[true, () => console.log(4)]],
);

// Same as

invokeAny(
  [true, () => console.log(1)],
  [true, () => console.log(2)],
  [false, () => console.log(3)],
  [true, () => console.log(4)],
);
declare function invokeAny(...tests: Array<InvokeTest<*>>): Array<mixed>;

Control Flow

invoke-if makes composing various situations much simpler then nesting if/else statements of using switches in many cases. Below is a description of how the arguments will be evaluated.

if/if...

invoke-if evaluates entry within an argument until the it encounters a check that results in a falsey response. In the nested example below, we would invoke entries 1 and 2 while 3 and 4 would not occur since evaluating 3 resulting in a falsey result.

invokeIf([
  ['true', () => console.log(1)],
  [() => true, () => console.log(2)],
  [false, () => console.log(3)],
  [true, () => console.log(4)],
]);

if/then

invoke-if evaluates each argument independently of the others. Each separate argument sent to one of invoke-if's functions can be thought of as then arguments.

In the example below, we would invoke arguments 1, 2, 5, and 6.

invokeIf(
  [
    ['true', () => console.log(1)],
    [() => true, () => console.log(2)],
    [false, () => console.log(3)],
    [true, () => console.log(4)],
  ],
  [
    ['true', () => console.log(5)],
    [() => true, () => console.log(6)],
    [false, () => console.log(7)],
    [true, () => console.log(8)],
  ],
);

if/else

When encountering a failed argument, invoke-if will check if there is a third element to the entry (not compatible with Map). If there is, it will invoke the third element and add it to the results before breaking evaluation of the given argument.

In the example above it will print 1 then 2 then 'done'

const done = () => console.log('done');

invokeIf([
  ['true', () => console.log(1), done],
  [() => true, () => console.log(2), done],
  [false, () => console.log(3), done],
  [true, () => console.log(4), done],
]);

Customized Flow

When encountering a function rather than an Array or Map, it will assume that the function is a factory. It will first call the function and will evaluate the result if it can.

The example below will toggle which case is executed each time any of the current elements tests encounters a falsey response.

let i = 0;

const done = () => {
  i += 1;
  console.log('done');
};

function doinvoke() {
  return invokeIf(
    () =>
      i % 2 === 0 && [
        ['true', () => console.log(1), done],
        [() => true, () => console.log(2), done],
        [false, () => console.log(3), done],
        [true, () => console.log(4), done],
      ],
    () =>
      i % 2 !== 0 && [
        ['true', () => console.log(5), done],
        [() => true, () => console.log(6), done],
        [false, () => console.log(7), done],
        [true, () => console.log(8), done],
      ],
  );
}