npm package: @lytics/wiz
Description: A specification for modeling wizard workflows, like the ones used in Lytics products, and a library for consuming these models.
Latest version: 3.0.0

# @lytics/wiz

A specification for modeling wizard workflows, like the ones used in Lytics products, and a library for consuming these models.

## installation

```
npm install @lytics/wiz
```

## playground

- [An Observable notebook for tinkering with the library](https://observablehq.com/@humanchimp/lytics-wiz-d3-playground)

## examples

Importing the `enter` function from the library:

```javascript
import { enter } from "@lytics/wiz";
```

Define and navigate immutable wizards:

```javascript
// Simple case of a wizard with no branches
const entry = enter([{ id: "1" }, { id: "2" }, { id: "3" }]);

const secondStep = entry.next();

const thirdStep = entry.next().next();

assert(secondStep.next() === thirdStep);

assert(thirdStep.prev() === secondStep);

assert(thirdStep.prev().prev() === entry);
```

Wizards can have alternate steps:

```javascript
const entry = enter([{ id: "1", alt: "1.5" }, { id: "1.5"}, { id: "2" }]);

const secondStep = entry.next();

const alternateStep = entry.alt();

// Subsequent steps have distinct identities...
assert(secondStep.next() !== alternateStep.next());

// ...because you need to be able to navigate back to the correct previous step...
assert(secondStep.next().prev() === secondStep);
assert(alternateStep.next().prev() === alternateStep);

// ...but they both point the same underlying spec...
assert(secondStep.next().spec === alternateStep.next().spec);

// ...going backwards we can arrive at the same entry node...
assert(secondStep.prev() === alternateStep.prev());
```

Wizards can have choicepoints:

```javascript
const entry = enter({
  entrypoint: "choice",
  choices: [
    {
      id: "choice",
      options: ["wimp", "shrimp"]
    }
  ],
  steps: [
    { id: "wimp" },
    { id: "shrimp" }
  ],
});

entry.next(); // Throws! a selection is required.
entry.next("opus"); // Throws! valid options are wimp, shrimp

const wimpCard = entry.next("wimp");
const shrimpCard = entry.next("shrimp");

// ...you can navigate to the previous card
assert(wimpCard.prev() === shrimpCard.prev());

// ...there is no "memory"
wimpCard.prev().next(); // Throws! a selection is required.

// ...for "memory", retain a reference in your program...
assert(wimpCard === entry.next("wimp"));
```

Wizards can specify flows, which are sequences of steps:

```javascript
const { enter } = LyticsWiz;

const simpleFlow = enter({
  entrypoint: "flow",
  flows: [
    {
      id: "flow",
      steps: ["one", "two", "three"],
    },
  ],
  steps: [{ id: "one" }, { id: "two" }, { id: "three" }],
});
```

These features compose orthogonally to one another. Here is kitchen sink example using flows, choices, and alts:

```javascript
const { enter } = LyticsWiz;

const checkoutFlow = enter({
  entrypoint: "gratuity",
  choices: [
    {
      id: "gratuity",
      options: [
        { when: "10-percent", goto: "payment-method" },
        { when: "20-percent", goto: "payment-method" },
        { when: "30-percent", goto: "heavy-tipper" },
      ],
    },
  ],
  flows: [
    {
      id: "heavy-tipper",
      steps: ["thanks-dude", "payment-method"],
    },
  ],
  steps: [
    { id: "payment-method" },
    { id: "thanks-dude", alt: "secret-promo" },
    { id: "secret-promo" },
  ],
});

// normal tip amounts route to the payment-method step
assert(step.next("10-percent").spec.id === "payment-method");
assert(step.next("20-percent").spec.id === "payment-method");

// 30-percent routes to the heavy-tipper flow
assert(step.next("30-percent").spec.id === "thanks-dude");

// "next" continuation routes back to the payment-method step
assert(step.next("30-percent").next().spec.id === "payment-method");

// "alt" continution routes to the secret-promo step before the payment-method step
assert(step.next("30-percent").alt().spec.id === "secret-promo");
assert(step.next("30-percent").alt().next().spec.id === "payment-method");
```

## docs

- [API Docs](doc/modules/_src_wiz_.md)

## specification

- [JSONSchema](schema.json)