• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

microstates / microstates.js / 274 / 4
99%
master: 99%

Build:
DEFAULT BRANCH: master
Ran 06 Dec 2017 03:44PM UTC
Files 19
Run time 1s
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

06 Dec 2017 03:41PM UTC coverage: 99.465% (+15.2%) from 84.259%
274.4

push

travis-ci

web-flow
Transition context and batching transitions (#33)


The original goal of this PR was to add transition context and the ability to batch transitions. I'll items everything that this PR introduces and how it can be used.

## `microstate(Type, value)`

Previously, to create a Microstate we exposed `Microstates.from(Type, value)`. This has now been replaced with `microstate(Type, value)`.

## `microstates(Type, value).transitions` is now hidden

Previously, `let { transitions } = Microstates(Type, value)` provided a collapsed object for mapping transitions. Now the transitions are hidden on result of `Microstates(Type, value)`. To retrieve metadata use the following,

```js
import { reveal } from 'microstates/src/utils/secret';
import microstate, * as MS from 'microstates';

let ms = microstate(MS.Number);
ms.transitions
// => undefined

reveal(ms);
// => { Type: MS.Number, value: undefined, state: Tree, transitions: Tree }
```

This should only be necessary for integrations.

## Chainable transitions

It was not possible to chain transitions because transitions returned the value which needed to be wrapped in Microstates. Closest was the `.to` method, but it was a weird API. Now, root level transitions are automatically chainable.

```js
microstate(MS.Number).increment().increment().increment().valueOf();
// 3
```

## Transition Context

This was the original purpose of this PR. It's to allow patching transitions inside of a transition. In our earlier conversations, we discussed `this(current)` syntax. This has been changed to support parity with Microstates constructor signature. `this()` is equivale to `this(Type, value)` but `Type` and `value` are provided by default. You can override the default `Type` and `value` with `this(AnotherType, anotherValue)`.

```js
class ModalContent {
  text = String;
}
class Modal {
  isOpen = Boolean;
  title = String;
  content = ModalContent;
}
class State {
  messages = Array;
  modal = Modal;

  addItemAndShowModal(current, message, prompt) {
    return this()
      .messages.push(message)
      .modal.isOpen.set(true)
      .modal.content.text.set(prompt);
  }
}
```

## Constants Support

Constants make it possible to define properties on Types that can't be transitioned. These values are meant to be used with Type-shifting to create nodes that transition through multiple states.

```js
let ms = microstate(
  class Type {
    n = 10;
    b = true;
    s = 'hello';
    o = { hello: 'world' };
    a = ['a', 'b', 'c'];
    null = null;
    greeting = MS.String;
  }
);

ms.state.n
//=> 10

ms.state.null
//=> null

ms.state.b
//=> true

ms.valueOf();
// undefined
```

Static values are shared by all instances of the Type.

```js
microstate(Type).state.o === microstate(Type).state.o;
```

## Type-shifting

This is what I called being able to change the structure of the Type tree at runtime. An important quality of Type-shifting is that the transitioned types are intended to be an intermittent and discardable state. It makes it possible to represent state machines like File Uploaders. Type-shifting is done using the transition context.

```js
class Line {
  a = MS.Number;
  add({ a }, b) {
    return this(Corner, { a, b });
  }
}

class Corner extends Line {
  a = MS.Number;
  b = MS.Number;
  add({ a, b }, c) {
    return this(Triangle, { a, b, c });
  }
}

class Triangle extends Corner {
  c = MS.Number;
}

```

## Type-shifting + Constant values

Together these two features make it possible to model state machines that have multiple related properties. 

```js
class Async {
  content = null;
  isLoaded = false;
  isLoading = false;
  isError = false;

  loading() {
    return this(AsyncLoading);
  }
}

class AsyncError extends Async {
  isError = true;
  isLoading = false;
  isLoaded = true;
}

class AsyncLoading extends Async {
  isLoading = true;

  loaded(current, content) {
    return this(
      class extends AsyncLoaded {
        content = content;
      }
    );
  }

  error(current, msg) {
    return this(
      class extends AsyncError {
        error = msg;
      }
    );
  }
}

class AsyncLoaded extends Async {
  isLoaded = true;
  isLoading = false;
  isError = false;
}
```

58 of 58 branches covered (100.0%)

Branch coverage included in aggregate %.

128 of 129 relevant lines covered (99.22%)

167.51 hits per line

Source Files on job 274.4
  • Tree
  • List 0
  • Changed 10
  • Source Changed 6
  • Coverage Changed 9
Coverage ∆ File Lines Relevant Covered Missed Hits/Line Branch Hits Branch Misses
  • Back to Build 274
  • Travis Job 274.4
  • f8af8034 on github
  • Prev Job for on master (#269.1)
  • Next Job for on master (#277.2)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc