npm package: @layered-tree/core
Description: @layered-tree/core is an javascript solution ( framework agnostic ) that lets us create easily a full application Plugin architecture.
Author: Nicolas Ribes
Latest version: 1.0.0-dev.0
Deprecated: only

<div align="center">
  <a href="https://github.com/easyni/layered-tree">
    <img width="200" height="200" src="https://raw.githubusercontent.com/easyni/layered-tree/master/.github/logo-layered-tree.svg">
  </a>
</div>

[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/easyni/layered-tree/blob/ci/setup/packages/core/LICENCE)
[![npm version](https://badge.fury.io/js/%layered-tree%2Fcore.svg)](https://badge.fury.io/js/%layered-tree%2Fcore)
![build](https://github.com/easyni/layered-tree/workflows/build/badge.svg)
![test](https://github.com/easyni/layered-tree/workflows/test/badge.svg)


# Welcome to @layered-tree/core 👋

## <a name="intro"></a> ✨ Introduction

**Layered tree** is an javascript solution ( framework agnostic ) that lets us create easily a full application Plugin architecture. We just have to attach some [strategies](#strategies-references) at different moment of a life cycle application. Then we can subscribe on each of those declared strategies with a Plugin object, to provide those, some methods ( layer ) to use. And then fully override/enhance or totally rewire the tree of the application. 

- **🎁 Bonus :** It's developed in [Typescript](https://www.typescriptlang.org/index.html) and we have some strong inference between Strategy expectations and Plugin.

## <a name="need"></a> 🙋‍♂️ The need

- Make core applications with some plugin architecture for consumers.
- Make white label application and share it.
- Make overridable things, those can't be extends easily.

## 👷🏻‍♂️<a name="install"></a> Install

```bash
yarn add @layered-tree/core 
```

## <a name="how-to"></a> ⚙️ How to ?

<div align="center">
    <img src="https://raw.githubusercontent.com/easyni/layered-tree/master/.github/generic-schema.svg">
</div>


## <a name="usage"></a> 🛠 Usage

Imagine we want to create a core game with a character that have some random generate stats and possible actions to do.
keep in mind this game is for all ages.

### **Contributor side:**


#### 1- Create strategies

```ts
import { Pipeline } from '@layered-tree/core';

// I create my Strategies Storage for a Character creation
const characterStrategiesStorage = {
    // Stats is the source type i want to pass through my pipeline.
    // { name: string } is some data i need to pass for build my stats
    'character.initial.randomInitialStats': new Pipeline<Stats, { name: string }>(),
    // Actions is the source type i want top pass through my pipeline.
    // { stats: Stats } is some data i need to pass for build my actions
    'character.initial.randomInitialActions': new Pipeline<Actions, { stats: Stats }>(),
};

```

#### 2- Aggregate strategies

```ts
import { StrategyAggregator } from '@layered-tree/core';

// I instantiate a StrategyAggregator with my Strategies Storage
const characterStrategies = new StrategyAggregator('character', characterStrategiesStorage);

```

> ℹ️ It's possible to create all application strategies in one aggregator, but as a God class is an anti pattern a god aggregator is also a bad idea. Prefer an aggregator by responsibility.

#### 3- Place strategies in application workflow 

```ts
const createCharacter = (name: string): Character => {
    // Add a pipeline on the initial stats generation result.
    const stats = characterStrategies.processStrategy
      ('character.initial.randomInitialStats')
      // getRandomInitialStats(name) is the source i want to pass through my pipeline.
      // { name } is some data i need to pass for build my stats.
      (getRandomInitialStats(name), { name });

    // Add a pipeline on the initial action generation result.
    const actions = characterStrategies.processStrategy
      ('character.initial.randomInitialActions')
      // getRandomInitialActions(stats) is the source i want to pass through my pipeline.
      // { stats } is some data i need to pass for build my actions.
      (getRandomInitialActions(stats), { stats });

    return { stats, actions };
};
```

#### 4- Create LayeredTree mediator with strategies aggregators
```ts 
import { LayeredTree } from '@layered-tree/core';

// We instantiate LayeredTree object with all strategies of my application flow.
const gameLayeredTree = new LayeredTree({ strategies: [characterStrategies] });

```
> ℹ️ It's possible to register a strategyAggregator on the fly, but it's not recommended, for two reasons:
>   - Because it can be confusable and dangerous for consumer at to have access or not access to a strategy at different step of application workflow.
>   - And because of typescript static typing, strategyAggregator added on the fly would not be inferred.

#### 5- Expose mediator.
```ts 

// We just export the type of our LayeredTree instance for ours consumers.
// The LayeredTree instance can be also exported directly if it's needed that consumers manipulate it.
// (For create there own LayeredTree based on the main
// one, for example)
export type GameLayeredTree = typeof gameLayeredTree;

// Here i expose an entry function of my app that take in parameter an array 
// of LayeredTreePlugin.
export const init = async (plugins: LayeredTreePlugin<any>[] = []) => {
    // First we register all plugins
    gameLayeredTree.registerPlugins(plugins);

    // Then the scenario can start
    startScenario();
};
```

### **Consumer side:**

Now imagine with this core game i want to create an age restricted version, with violence.

#### 1- Create plugin

```ts
import { GameLayeredTree } from '@game/core'

// I create a plugin for the character creations
// => Here we declare our plugin with the static type GameLayeredTree 
// to have all inference of all strategies i can use on this app.
const characterPlugin = new LayeredTreePlugin<GameLayeredTree>('character');

```

#### 2- Attach some middleware to the wanted pipeline with a strategy subscriptions.

```ts
import { addFireWithGunAction, addRobBankAction } from 'actions'

// I subscribe to my pipeline strategy 'character.initial.randomInitialActions'
// And i provide two middlewares that add actions intended to an adult audience.
// ( it can be chain subscriptions ) 
characterPlugin
  .strategySubscribe('character.initial.randomInitialActions')
    (addFireWithGunAction)
    (addRobBankAction);
```

> ℹ️ It's possible to subscribe to all pipeline in one plugin, but as a God class is an anti pattern a god plugin is also a bad idea. Prefer a plugin by responsibility.

> ℹ️ for more details about **Middleware** check [Pipeline](#pipeline) strategy section.

#### 3- Launch application with plugins.

```ts
import { init } from '@game/core'

init([characterPlugin]);
```

 => And here it's done ! 🎉 

 > ℹ️ check the full example [here](./example)

 > It's even possible to try it ! 🎮
 >  -  clone the monorepo and run `yarn start:core:example:kid` or `yarn start:core:example:restricted`at root


## <a name="ref"></a> 📚 API References

[Main references:](#main-references)
- [LayeredTree](#layeredtree)
- [StrategyAggregator](#strategyaggregator)
- [LayeredTreePlugin](#layeredtreeplugin)

[Strategies references:](#strategies-references)
- [Injection](#injection)
- [Pipeline](#pipeline)

[Secondary references:](#secondary-references)
- [Strategy](#strategy)
- [StrategyObserver](#strategyobserver)
- [LayeredTreeComponent](#layeredtreecomponent)
  
[Tools](#tools)
- [LayeredTreeToStrategyLayer](#layeredtreetostrategylayer)
---
### Main references:
---

#### LayeredTree: 

![Contributor](https://img.shields.io/badge/Implementation_side-Contributor-73ADFF?style=flat-square)

**Class** `LayeredTree<SA, LT, LTO>`

LayeredTree is the mediator of all the solution.

That is what to share, from app to consumers.
  - It will register strategies, Aggregators, plugins, and allow to process those.
  - It could be instantiate with some other LayeredTree instantiations.

    Then it's possible to create a master Mediator with some others base mediators.
    It's useful in case of multiple packages that compose an app and to override those individually, but also override them globally through the master Mediator.



**Type parameters**
  - **SA**: [`StrategyAggregator[]`](#strategyaggregator) 
    
    ![Optionnal](https://img.shields.io/badge/Inferred-Optionnal-informational?style=flat-square)
  - **LT**: [`LayeredTree<any[], any>[]`](#layeredtree)  
    
    ![Optionnal](https://img.shields.io/badge/Inferred-Optionnal-informational?style=flat-square)
  - **LTO**: `LayeredTreeOption<SA, LT>`  
    
    ![Optionnal](https://img.shields.io/badge/Inferred-Optionnal-informational?style=flat-square) 

**Constructors:**
```ts
new LayeredTree(options: LayeredTreeOption<SA, LT>): LayeredTree
```

***Parameters***
  - **options**: 

    The options of LayeredTree

    `LayeredTreeOption<SA, LT>` (primitive: `object`)

    - **strategies**: 
      - type: `SA` | `StrategyAggregator[]` 
  
      Array of [StrategyAggregator](#strategyaggregator) instances.

    - **layeredTrees**:  
    
      ![Optionnal](https://img.shields.io/badge/-Optionnal-informational?style=flat-square) 

      - type: `LT` | `LayeredTree[]`
  
      Array of [LayeredTree](#layeredtree) instances.


***Returns***: `LayeredTree`

**Methods:**

  - **processStrategy**
    ```ts
    processStrategy(strategyName: string): unknown
    ```
    To process all StrategyLayer ( methods ) registered LayeredTree instance.

    - ***Parameters***:
      - **strategyName**: `string`
  
        The name associate to the strategy to pick.

    - ***Returns***: `unknown` 

       The strategy picked's return.

  - **registerPlugins**
    ```ts
    registerPlugins(plugins: LayeredTreePlugin<any>[]): void
    ```
    Register some LayeredTreePlugin in LayeredTree Mediator.

    - ***Parameters***: 
      - **plugins**: `LayeredTreePlugin<any>[]`
         Array of [LayeredTreePlugin](#layeredtreeplugin).

    - ***Returns***: `void` 
  
  - **registerStrategies**
    ```ts
    registerStrategies(strategies: StrategyAggregator[]): void
    ```
    Register on the fly, some StrategyAggregators in LayeredTree Mediator.

    - ***Parameters***:
      - **strategies**: `StrategyStorage`
      Array of StrategyAggregators instances.

    - ***Returns***: `void` 

    > ℹ️ It's possible to register a strategyAggregator on the fly, but it's not recommended, for two reasons:
    >   - Because it can be confusable and dangerous for consumer at to have access or not access to a strategy at different step of application workflow.
    >   - And because of typescript static typing, strategyAggregator added on the fly would not be inferred.

---

#### StrategyAggregator:

![Contributor](https://img.shields.io/badge/Implementation_side-Contributor-73ADFF?style=flat-square)

**Class** `StrategyAggregator<SS>` extends [LayeredTreeComponent](#layeredtreecomponent)

The aggregator of strategies. It will store all strategies and associate those to a name.

**Type parameters**
  - **SS**: `StrategyStorage` 
    
    ![Optionnal](https://img.shields.io/badge/Inferred-Optionnal-informational?style=flat-square)

**Constructors:**
```ts
new StrategyAggregator(name: string, strategies: SS): StrategyAggregator
```

***Parameters***
  - **name**: `string`
    The name of aggregator. Should be unique.

  - **strategies**:
    The object that will associate strategies to a name.
    
    `SS`| `StrategyStorage` (primitive: `object`)
    
    Represented by: `{ name: Strategy }`

    > ℹ️ check available [strategies](#strategies-references)
  
***Returns***: `StrategyAggregator`

**Methods:**

  - **isRegistered**
    ```ts
    isRegistered(): boolean
    ```
    Check if the StrategyAggregator have been registered in LayeredTree.

    - ***Returns***: `boolean`

  - **processStrategy**
    ```ts
    processStrategy(strategyName: string): unknown
    ```
    To process all StrategyLayer ( methods ) in this aggregator.

    - ***Parameters***:
      - **strategyName**: `string`

        The name associate to the strategy to pick.

    - ***Returns***: `unknown` 

      The strategy picked return.

---

#### LayeredTreePlugin:

![Consumer](https://img.shields.io/badge/Implementation_side-Consumer-blueviolet?style=flat-square)

**Class** `LayeredTreePlugin<LT>` extends [LayeredTreeComponent](#layeredtreecomponent)

LayeredTreePlugin is a plugin that allow access to all registered strategies to a LayeredTree instance (mediator).

Instantiation Generic type should be type with the typeof LayeredTree instance. It is intended to have a good type inference.

```ts 
const plugin = new LayeredTreePlugin<typeof layeredTreeInstance>(...)
```

It should be register in a LayeredTree instance (mediator).



**Type parameters**
  - **LT**: [`LayeredTree`](#layeredtree)

    ![Optionnal](https://img.shields.io/badge/Not_inferred-Should_be_defined-red?style=flat-square) 

    typeof a LayeredTree instance. (It couldn't be inferred, so it should be defined at the instantiation.)

**Constructors:**
```ts
new LayeredTreePlugin(name: string): LayeredTreePlugin
```

***Parameters***
  - **name**: `string`
    The name of plugin. Should be unique.

***Returns***: `LayeredTreePlugin`

**Methods:**

  - **isRegistered**
    ```ts
    isRegistered(): boolean
    ```
    Check if the component have been registered in LayeredTree.

    - ***Returns***: `boolean`

  - **strategySubscribe**
    ```ts
    strategySubscribe(strategyName: string): (Anonymous function): unknown
    ```
    info

    - ***Parameters***:
      - **strategyName**: `string`
  
        The strategy name to subscribe.

    - ***Returns***: `(Anonymous function): unknown`

      An Anonymous function that take a StrategyLayer method to attach at the subscribed strategy registered. The `return` of this function depend of strategy definition.

---
### Strategies references:
---
#### Injection

![Contributor](https://img.shields.io/badge/Implementation_side-Contributor-73ADFF?style=flat-square)

**Class** `Injection<Return, Data>`  extends [Strategy](#strategy)

Injection Strategy is usually to inject some data at a moment of an application flow. It will process the stored InjectionMethod (function) and return the data generated by this one. Each subscription override the precedent one.

<div align="center">
    <img src="https://raw.githubusercontent.com/easyni/layered-tree/master/.github/injection-schema.svg">
</div>

**Type parameters**
  - **Return**: `unknown | undefined`
        
    ![Optionnal](https://img.shields.io/badge/Not_inferred-Should_be_defined-red?style=flat-square) 

    The return type waited for the InjectionMethod. (It couldn't be inferred, so it should be defined at the instantiation.)

  - **Data**: `any`  

    ![Optionnal](https://img.shields.io/badge/Not_inferred-Optionnal-informational?style=flat-square) * depend if some data is needed

    To pass some data to the InjectionMethod, which is needed to make its job. (It couldn't be inferred, so it should be defined at the instantiation.)

**Constructors:**
```ts
new Injection<Return, Data>(defaultReturnValue: Return | undefined): Injection
```

***Parameters***
  - **defaultReturnValue**: `Return | undefined`
    ![Optionnal](https://img.shields.io/badge/-Optionnal-informational?style=flat-square)
    
    To force a default return value to the injection. bu default it's `undefined`

    default: `undefined`



***Returns***: `Injection`

**Methods:**

  - **use**
    ```ts
    use(injectionMethod: InjectionMethod<Return, Data>): void
    ```
    To use the injection Method for this Injection strategy, concretely it fill or replace injectionMethod property.

    - ***Parameters***:
      - **injectionMethod**: `InjectionMethod<Return, Data>` 

        A simple method that could take some data in parameter or not, it depend of the need.
        and return `Return` type defined on instantiation.

        - `InjectionMethod<R, D> = (() => R) | ((data: D) => R)`

    - ***Returns***: `void` 

      The return type that have been defined on instantiation.

  - **process**
    ```ts
    process(data: Data): Return | process(): Return
    ```
    Process the injectionMethod. It should not run manually. It's executed by the [`StrategyAggregator`](#strategyaggregator) through the `processStrategy` method.

    - ***Parameters***:
      - **data**: `Data`
        
        ![Optionnal](https://img.shields.io/badge/-Optionnal-informational?style=flat-square)
  
        The data parameter of the InjectionMethod. Not needed if not define on instantiation

    - ***Returns***: `Return` 

      The return type that have been defined on instantiation.

---
#### Pipeline

![Contributor](https://img.shields.io/badge/Implementation_side-Contributor-73ADFF?style=flat-square)

**Class** `Pipeline<Source, Data>`

Pipeline strategy is usually used to modify some data source at a moment of an application flow. It will process a stack of registered middleware (function) and return an augmented/altered provided source.

<div align="center">
    <img src="https://raw.githubusercontent.com/easyni/layered-tree/master/.github/pipeline-schema.svg">
</div>

**Type parameters**
  - **Source**: `any` 
    
    ![Optionnal](https://img.shields.io/badge/Not_inferred-Should_be_defined-red?style=flat-square) 

    The source to pass at the entry of the pipeline. (It couldn't be inferred, so it should be defined at the instantiation.)

  - **Data**: `any`
    
     ![Optionnal](https://img.shields.io/badge/Not_inferred-Optionnal-informational?style=flat-square) * depend if some data is needed

    To pass some data to the Middleware, which is needed to make its job. (It couldn't be inferred, so it should be defined at the instantiation.)
    
    

**Constructors:**
```ts
new Pipeline<Source, Data>(): Pipeline
```

***Returns***: `Pipeline`

**Methods:**

  - **use**
    ```ts
    use(middleware: Middleware<Source, Data>): this
    ```
    To use a middleware for this pipeline, concretely it add a middleware to the middleware stack.

    - ***Parameters***:
      - **middleware**: `Middleware<Source, Data>`  Middleware to use. A middleware can be `Simple` or `Complex`:

        - `SimpleMiddleware<Source>`: It's a function that take in parameter the src and the next function.
            ```ts
              (src: Source, next) => next(src)
            ```
      
            Next function, in the case of simple middleware, is a function that take the src in parameter (to transfer it to the next middleware),
            and return the value of the next middleware processed.
      
            ⚠️ The important thing to understand is if you don't call next function it break the
              chain of middlewares process.
      
            ⚠️ In the case you don't call next function, the process function will stop the chain to this middleware and the pipeline will return the value returned by the current middleware.

            for example: 

            ```ts
              (src) => src
            ```
            
            **The value returned by the middleware is the result of the pipeline processing.**


        - `ComplexMiddleware<Source, Data>`: It's a function that take in parameter the src, data object and the  next function.
            ```ts
              (src: Source, data: Data, next) => next(src, data)
            ```
      
            Next function, in the case of complex middleware, is a function that take the src,, and a data object (to transfer its to the next middleware) in parameter. 
            
            It return the value of the next middleware processed.
      
            ⚠️ The important thing to understand is if you don't call next function it break the
              chain of middlewares process.
      
            ⚠️ In the case you don't call next function, the process function will stop the chain to this middleware and the pipeline will return the value returned by the current middleware.

            For example: 

            ```ts
              (src, data) => src
            ```

            **The value returned by the middleware is the result of the pipeline processing.**

    - ***Returns***: `this` 

      return the same `use` function to easily chain middleware assignation.

  - **process**
    ```ts
    process(src: Source, data: Data): Source | process((src: Source): Source
    ```
    Process the Middleware stack.

    - ***Parameters***:

      - **src**: `Source` 
  
        The source transferred through the middleware stack.

      - **data**: `Data` 
        
        ![Optionnal](https://img.shields.io/badge/-Optionnal-informational?style=flat-square)
  
        The data to transfer to the middleware stack.

    - ***Returns***: `Source` 

      Return the same type of the original source.

___
### Secondary references:
___

#### Strategy 

![Contributor](https://img.shields.io/badge/Implementation_side-Contributor-73ADFF?style=flat-square)

**Class** `Strategy` 

![Abstract](https://img.shields.io/badge/-Abstract-yellow?style=flat-square)

Strategy is an abstract class. It should be extended to create a strategy able to be mapped in a [StrategyAggregator](#strategyaggregator).

 > ℹ️ It's useful to define a custom strategy.

**Type parameters**
  
*Depend of the strategy definition.*

**Constructors:**

*Depend of the strategy definition.*

***Returns***: `Strategy`

**Methods:**

  - **use**
    ```ts
    use(method: StrategyLayer): any
    ```
       Tell to the strategy to use a method `StrategyLayer`. Basically `StrategyLayer` is a **method**. The signature of this method depend of the strategy. 
       
      (For example in [Pipeline](#pipeline) strategy the expected method is a Middleware)

    - ***Parameters***:
      - **method**: `StrategyLayer`

        The method to add on the strategy stack.
     
    - ***Returns***: `any`

      *Depend of the strategy definition.*

___

#### StrategyObserver

![Library](https://img.shields.io/badge/Implementation_side-Library-orange?style=flat-square)

**Class** `StrategyObserver<SS>`

The StrategyObserver is used by the Mediator to manage all strategies registered, subscription, and execution.

 > ℹ️  Actually it only for deep contribution. It's documented for information, you should not use it, as consumer of the layered-tree solution.

**Type parameters**
  - **SS**: `StrategyStorage` 

**Constructors:**
```ts
new StrategyObserver(): StrategyObserver
```

***Returns***: `StrategyObserver`

**Methods:**

  - **addBaseObserver**
    ```ts
    addBaseObserver(strategyObserver: StrategyObserver<StrategyStorage>): void
    ```
    To register all observable strategies from an other observer to the current one.

    - ***Parameters***:
      - **strategyObserver**: `StrategyObserver<StrategyStorage>`
  
        The strategyObserver to register.

    - ***Returns***: `void` 

  - **register**
    ```ts
    register(strategyName: keyof SS | string, strategy: Strategy): void
    ```
    Register a strategy to the current observer. 
    
    > ℹ️ It's not advisable to directly register strategy from the observer, usually it's done by the LayeredTree mediator.

    - ***Parameters***:
      - **strategyName**: `keyof SS` | `string`
  
        The name associate to the strategy

      - **strategy**: [`Strategy`](#strategy)
  
        The strategy to Register

    - ***Returns***: `void` 

  - **subscribe**
    ```ts
    subscribe(strategyName: keyof SS | string, method: (...args: any[]) => any): void
    ```
    Subscribe to a strategy registered in the current observer.

    - ***Parameters***:
      - **strategyName**: `keyof SS` | `string`
  
        The name associate to the strategy to pick.

      - **method**: `(...args: any[]) => any`
  
        The method to add on the strategy stack.
        
        *Depend of the strategy picked.*

    - ***Returns***: `any` 

      *Depend of the strategy picked.*

  - **fire**
    ```ts
    fire(strategyName: keyof SS | string): Strategy["process"]
    ```
    Fire the strategy processing.

    > ℹ️ It's not advisable to directly call fire function from the observer, usually it's done by the [LayeredTree](#layeredtree) mediator or [StrategyAggregator](#strategyaggregator) through  `processStrategy` method.

    - ***Parameters***:
      - **strategyName**: `keyof SS` | `string`
  
        The name associate to the strategy.

    - ***Returns***: `Strategy["process"]`  

      It return the process function of the picked Strategy.
  

___

#### LayeredTreeComponent

![Library](https://img.shields.io/badge/Implementation_side-Library-orange?style=flat-square)

**Class** `LayeredTreeComponent<LT>` 

![Abstract](https://img.shields.io/badge/-Abstract-yellow?style=flat-square)

LayeredTreeComponent is an abstract class that should be extended to all components that could be registered in LayeredTree mediator, to make them communicate together.

 > ℹ️ Actually it only for deep contribution. It's documented for information, you should not use it, as consumer of the layered-tree solution.

**Type parameters**
  - *LT*: [LayeredTree](#layeredtree)

**Constructors:**
```ts
new LayeredTreeComponent(name: string): LayeredTreeComponent
```

***Parameters***
  - **name**: `string`
  The name of the component. Should be unique.

***Returns***: `LayeredTreeComponent`

**Accessors**
 - **layeredTree**
    ```ts
    get layeredTree(): undefined | LT
    set layeredTree(layeredTree: undefined | LT): void
    ```
    The LayeredTree instance (mediator) associate to this component when it's registered.

    - ***Returns***: `undefined | LT` 

  - **name**
    ```ts
    get name(): symbol
    set name(name: symbol): void
    ```
    Get the unique name.

    - ***Returns***: `symbol` 


**Methods:**

  - **isRegistered**
    ```ts
    isRegistered(): boolean
    ```
    Check if the component have been registered in LayeredTree.

    - ***Returns***: `boolean` 

___
### Tools
___

#### LayeredTreeToStrategyLayer

**Type alias** `LayeredTreeToStrategyLayer<<LT, SN>`

Very useful Utility Type to infer a specific StrategyLayer ( method ) signature from a LayerTree instance type. 
When StrategyLayer are abstracted for example, it could be very handy.

```ts
// With LayeredTreeToStrategyLayer utility Type, actions, data, next the return function are well inferred.
const addRobBankAction: LayeredTreeToLayerTreeToStrategyLayer<GameLayeredTree, 'character.initial.randomInitialActions'> = (
    actions,
    data,
    next,
) => {
    return next(
        {
            ...
        },
        data,
    );
};

characterPlugin.strategySubscribe('character.initial.randomInitialActions')(addRobBankAction);
```

> ℹ️ For full example check [here](./example/example.restricted.app.ts#L33)

**Type parameters**
  - *LT*: [LayeredTree](#layeredtree) 
    The typeof LayeredTree instance used to extract the desired StrategyLayer.
  - *SN*: `string`
    The strategy name.

**Methods:**

  - **isRegistered**
    ```ts
    isRegistered(): boolean
    ```
    Check if the component have been registered in LayeredTree.

    - ***Returns***: `boolean` 


#### Injection Strategy:

## <a name="contrib"></a> 🤝 Contributing
Contributions, issues and feature requests are welcome!

Feel free to check [issues page](https://github.com/easyni/layered-tree/issues). You can also take a look at the [contributing guide](../../CONTRIBUTING.md).

## <a name="contributors"></a>👤 Main Contributors
| <a href="https://github.com/easyni" target="_blank"><img src="https://avatars1.githubusercontent.com/u/8232893?s=460&u=88d421f642f6458ab07bf0c22a3a65c61334d5ec&v=4"></a><br>**Nicolas Ribes** <br> * Github: [@easyni](https://github.com/easyni) <br> *Author* |
| :------: |

## <a name="support"></a> 💚 Show your support

Give a ⭐️ if this project helped or interest you !

## <a name="license"></a> 📝 License

This project is [MIT](./LICENCE) licensed.