# @tangle/strategy

> a toolkit for composing tangle reducing strategies

Latest version **4.1.2** (published 2023-03-01) · LGPL-3.0-only license · 0 weekly downloads

## Install

```sh
npm install @tangle/strategy
pnpm add @tangle/strategy
yarn add @tangle/strategy
bun add @tangle/strategy
```

## 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 | 4.1.2 |
| Published | 2023-03-01 |
| First published | 2020-10-13 |
| Weekly downloads | 0 |
| License | LGPL-3.0-only |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 2 |
| Unpacked size | 31.9 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | mixmix |
| Maintainers | mixmix, chereseeriepa, cpilbrow |
| Keywords | tangle, dag |

## Links

- npm: https://www.npmjs.com/package/@tangle/strategy
- Repository: https://gitlab.com/tangle-js/strategies/strategy
- Homepage: https://gitlab.com/tangle-js/strategies/strategy#readme
- Issues: https://gitlab.com/tangle-js/strategies/strategy/issues
- npm.io page: https://npm.io/package/@tangle/strategy

## Dependencies (2)

- [lodash.isequal](https://npm.io/package/lodash.isequal.md) ^4.5.0
- [is-my-json-valid](https://npm.io/package/is-my-json-valid.md) ^2.20.5

## Recent versions

- 4.1.2 (latest) — 2023-03-01
- 4.1.1 — 2023-03-01
- 4.1.0 — 2022-01-25
- 4.0.0 — 2021-12-07
- 3.0.2 — 2021-11-19
- 3.0.1 — 2021-11-08
- 3.0.0 — 2021-10-31
- 2.0.1 — 2021-01-27
- 2.0.0 — 2021-01-26
- 1.4.1 — 2020-11-01
- 1.4.0 — 2020-11-01
- 1.3.1 — 2020-10-29
- 1.3.0 — 2020-10-28
- 1.2.1 — 2020-10-28
- 1.2.0 — 2020-10-28
- … 3 more at https://npm.io/package/@tangle/strategy/versions

## README

#  @tangle/strategy

A strategy is a way of describing "transformations" and how to apply them to one another

A valid strategy is an Object which provides the following:
- `identity() => I` *Function* - an getter which return an element which represents the identity-transformation, `I`.
- `schema` *Object* - a JSON schema which can be used to validate a transformation
- `concat(A, B) => C` *Function*
  - takes two transformations and concatenates (applies) `B` to `A` to produce a new transformation `C`
  - NOTE order matters
- `mapToOutput(T) => output` *Function*
    - takes a transformation `T` and maps it into a "real" state which can be used in e.g. human interfaces
- `mapFromInput(input, currentTips) => T` *Function* (optional)
    - Takes a current transformation state, `currentTips`, which is an array of `T` along with a human friendly
      (descriptive) `input` and returns a transformation `T` which satisfies the
      change requested in `input`.
    - you can define a function which maps human `input` form to a transformation `T`
    - useful if the raw transformation form is hard for people to write
    - default: `t => t`

This module allows you compose larger strategies for transformations made up of transformations

## Example Usage

```
const Strategy = require('@tangle/strategy')

const strategy = new Strategy({
  title: require('@tangle/overwrite')(),
  attendees: require('@tangle/simple-set')()
})

const T1 = {
  title: { set: 'brunch' },
  attendees: { mix: 1, alanna: 1 }
}

const T2 = {
  title: { set: 'Brunch at Mixs' },
  attendees: { alanna: -1, ben: 1 }
}

const T3 = strategy.concat(T1, T2)
// => {
//  title: { set: 'Brunch at Mixs' },
//  attendees: { mix: 1, ben: 1 }
// }

strategy.mapToOutput(T3)
// => {
//  title: 'Brunch at Mixs',
//  attendees: ['ben', 'mix']
// }
```

## API

### `Strategy.isValid(strategy) => Boolean`

A helper for checking whether a strategy is valid (has everything required).
This is a non-exhaustive test.

If the last result was `false` you can find a detailed Error under `Strategy.isValid.error`

See "Strategy requirements" below

### `Strategy.isValidComposition(composition) => Boolean`

Checks a composition of strategies is valid (including whether the constituent stragies for each property are valid)


### `new Strategy(composition) => strategy`

Takes an `composition` which is an Object where the keys are mutable fields,
and the values are strategies for that field (e.g. see @tangle/simple-set)

Returns a new `strategy` - an instance with the following methods:


### `strategy.isValid(T) => Boolean`

Check if a transformation is valid.
If the last result was `false` you can find a detailed Error under `strategy.isValid.error`

### `strategy.concat(A, B) => C`

Combine to transformations to produce a new transformation.
NOTE order matters (unless your strategy is commutative!)


### `strategy.identity() => I`

Returns the "identity transformation", `I`, for out strategy.
This is the transformation with the property:

```
strategy.concat(T, I) = T
strategy.concat(I, T) = T
```
(Equivalent to multiplying by 1 for numbers)


### `strategy.mapToOutput(T) => t`

Takes a transformation `T` and converts it into a nice human readable "state" `t`.
Typically transformations look a particular way so that they have nice mathematical
properties which makes combining them easy. Unfortunately these are not that easy
for humans to read.


### `strategy.mapFromInput(change, currentTips) => newT`

A helper method which transforms "human" changes into a new transformation, `newT`,
based on a current transformation state `currentTips`.


### `strategy.mapToPure(messyT) => T`

Takes an Object `t`, which may have supurflous or missing transformation fields
and creates from it a clean + explicit transformation, `T`.
Replaces any missing fields with the Identity for that field


### `strategy.schema => Schema`

A getter which returns a JSON schema on which `isValid` was built.
Useful for building higher order schema (e.g. see ssb-crut)

### `strategy.fields => Array`

A getter which returns an array of the fields in the mutation strategy

### `strategy.isConflict(graph, nodeIds) => Boolean`
where:
- `graph` is a `@tangle/graph` instance
- `nodeIds` is an Array of nodeIds you're wanting to check for conflict

### `strategy.isValidMerge(graph, mergeNode) => Boolean`
where:
- `graph` is a `@tangle/graph` instance
- `mergeNode` is the proposed merge-node
- If isValidMerge is false, you will can find more info under:
    - `isValidMerge.error` - a summary of the fields with errors
    - `isValidMerge.errors` - an Array of more detailed errors for each field
    - `isValidMerge.fields` - an Array field names which had conflicts

### `strategy.merge(graph, mergeNode) => T`
similar to `isValidMerge`, but return a transformation, `T`
If it cannot, an error is thrown!


## Strategy Requirements

Rules for how a strategy must behave:
- **have a unique `identity` element**
  ```js
  concat(identity(), a) === a
  concat(a, identity()) === a
  ```
- **be associative**
  ```js
  concat(concat(a, b), c) === concat(a, concat(b, c))
  ```

An `identity` element is important because we need to be able to clearly communicate "I don't want to perform a change"

Associativity is important because in scuttlebutt we may have many contributions from different people across time, and being able to group chunks of transformations in a free-form way greatly increases our flexibility.
(e.g. it allows us to summarise a bunch of transformations and save that. this is something useful for writing merge messages)

_p.s. a Set which has an associative concat and an identity element is called a "monoid"_

BONUS:
- if your strategy is _commutative_, merging gets REALLY easy
  ```js
  concat(a, b) === concat(b, a)
  ```

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