# spitfirejs

> A tiny reactive data model library

Latest version **1.0.2** (published 2017-08-30) · ISC license · 0 weekly downloads

## Install

```sh
npm install spitfirejs
pnpm add spitfirejs
yarn add spitfirejs
bun add spitfirejs
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.0.2 |
| Published | 2017-08-30 |
| First published | 2017-06-15 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 1 |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 1 |
| Author | Luka Maljic |
| Maintainers | malj |
| Keywords | spitfire, reactive, data, model, rxjs |

## Links

- npm: https://www.npmjs.com/package/spitfirejs
- Repository: https://github.com/malj/spitfire
- Homepage: https://github.com/malj/spitfire#readme
- Issues: https://github.com/malj/spitfire/issues
- npm.io page: https://npm.io/package/spitfirejs

## Dependencies (1)

- [rxjs](https://npm.io/package/rxjs.md) ^5.4.0

## Alternatives

- [gamedig](https://npm.io/package/gamedig.md) — 29.3K weekly downloads
- [join-monster](https://npm.io/package/join-monster.md) — 12.8K weekly downloads
- [masked](https://npm.io/package/masked.md) — 5.5K weekly downloads
- [@comunica/actor-query-process-explain-logical](https://npm.io/package/@comunica/actor-query-process-explain-logical.md) — 4.7K weekly downloads
- [@veracity/vui](https://npm.io/package/@veracity/vui.md) — 4.6K weekly downloads

## Recent versions

- 1.0.2 (latest) — 2017-08-30
- 1.0.1 — 2017-06-15
- 1.0.0 — 2017-06-15

## README

***DEPRECATED: Please use [Observux](https://github.com/malj/observux) instead. It has the same functionality with a simpler API.***

# Spitfire.js

A tiny reactive data model library.

## Requirements

- [RxJS](https://github.com/ReactiveX/rxjs)

## Installation

```
npm install rxjs
npm install spitfirejs
```

## API

### Model.constructor([source])

Convenience class for extension and lazy model transformation. A `Model` instance gets transformed into a reactive data model when its prototype property `state$` is called for the first time. If a `source` object is available in the constructor, its own enumerable properties are copied onto the new `Model` instance.

```javascript
import {Model} from 'spitfirejs'

const model = new Model({foo: 'bar'})  // => Model { foo: 'bar' }

model.hasOwnProperty('state$')  // => false; the model is not transformed yet
model.state$  // => Observable<object>; the property `state$` gets called for the first time
model.hasOwnProperty('state$')  // => true; the model is now transformed
```

### Model.transform(source)

Transforms the `source` object into a reactive model by redefining its own enumerable non-function properties into proxies which handle values via getters and setters using RxJS `BehaviorSubject` instances. The combined latest properties are accessible via the `state$` property, an RxJS `Observable` stream of previous and next states.
Returns the frozen `source` object.

```javascript
import {Model} from 'spitfirejs'

const source = { foo: 'bar' }
const model = Model.transform(source)  // => Object { foo: 'bar' }

model === source  // => true; the original source object is transformed into a model
model.hasOwnProperty('state$')  // => true; the model is immediately transformed
```

## Usage

The reactive data model can be used to store any data and immediately notify its `state$` observers of any state changes. A simple example:

```javascript
import {Model} from 'spitfirejs'

class Counter extends Model {
    constructor() {
        super()
        this.count = 0
    }

    increment() {
        this.count += 1
    }

    decrement() {
        this.count -= 1
    }
}

const counter = new Counter()  // => Counter { count: 0 }

const subscriber1 = counter.state$.subscribe(state => {
    console.log(state.next.count)
})  // `0` is logged on subscription
counter.increment()  // `1` is logged on change
counter.decrement()  // `0` is logged on change

subscriber1.unsubscribe()
counter.increment()  // the count is incremented, but nothing is logged because there are no subscribers
const subscriber2 = counter.state$.subscribe(state => {
    console.log(state.next.count)
}  // `1` is logged on subscription
```

Since each `state$` property is a regular RxJS `Observable` instance, they can be used with any RxJS operators, e.g. for filtering, transforming or combining multiple states. An example:

```javascript
import {Model} from 'spitfirejs'
import {Observable} from 'rxjs/Observable'
import 'rxjs/add/observable/combineLatest'
import 'rxjs/add/operators/map'
import 'rxjs/add/operators/filter'

class Movie extends Model {
    constructor(name) {
        super()
        this.name = name
        this.lastWatched = null
    }

    watch() {
        this.lastWatched = new Date()
    }
}

const movie1 = new Movie("Monty Python and the Holy Grail")
const movie2 = new Movie("Monty Python's Life of Brian")
const movie3 = new Movie("Monty Python's The Meaning of Life")

// Observe the order of watched movies when all movies have been watched at least once
Observable.combineLatest(movie1.state$, movie2.state$, movie3.state$)
    .map(states => states.map(state => state.next))  // Discard the previous state
    .filter(movies => movies.every(movie => movie.lastWatched))  // Proceed only if all movies have been watched
    .map(movies => movies.sort((a, b) => a.lastWatched - b.lastWatched)) // Sort movies by the time they were last watched
    .map(movies => movies.map(movie => movie.name))  // Take only movie names
    .subscribe(watchOrder => {
        console.log(watchOrder)
    })

movie1.watch()  // Nothing happens, because not all movies have been watched yet
movie2.watch()  // Nothing happens, because not all movies have been watched yet
movie3.watch()  // ["Monty Python and the Holy Grail", "Monty Python's Life of Brian", "Monty Python's The Meaning of Life"]
movie2.watch()  // ["Monty Python and the Holy Grail", "Monty Python's The Meaning of Life", "Monty Python's Life of Brian"]
movie1.watch()  // ["Monty Python's The Meaning of Life", "Monty Python's Life of Brian", "Monty Python and the Holy Grail"]
```

## Resources
- [RxJS operators](https://www.learnrxjs.io/#operators)

---
_Source: https://npm.io/package/spitfirejs · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
