Alex A. Naanou c7b5152f9d docs...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2021-06-04 23:59:37 +03:00
2017-10-04 14:38:30 +03:00
2021-06-04 02:54:27 +03:00
2019-11-06 03:39:38 +03:00
2021-01-04 16:56:31 +03:00
2021-06-04 23:59:37 +03:00

features.js

features.js organizes sets of actions or object methods into features, applies them, manages merging of features via inter-feature dependencies and external criteria.

Basics

If actions are a means to organize how methods are extended and called in the prototype chain, features.js defined how that prototype chain is built.

A feature defines define a mixin / action-set and metadata:

  • documentation
  • dependencies, both hard and soft on other features
  • load priority
  • applicability tests

This metadata helps automatically build/rebuild a list of applicable features, sort it and mix their actions, configuration into an object.

In contrast to the traditional manual inheritance/prototyping, here the MRO (method resolution order) can self-adapt to the specific runtime requirements depending on feature metadata without the need to manually code prototype chains for each possible scenario.

This makes it trivial to split the desired functionality into features vertically, a-la MVC. As well as horizontally splitting the core functionality and extensions, plugins, etc. into separate features.

For example splitting an app into:

digraph {
    subgraph UI {
        "Standalone UI"
        "Web App UI" -> "Web Site UI"
        "Commandline UI"
    }
    UI -> "Data Handling"
}

Contents

Installing

var features = require('ig-features')

Organizational structure

  • FeatureSet
    Contains features, defines the main feature manipulation API, acts as the target object constructor/factory.
  • Feature
    Creates a feature in the feature-set, defines the feature metadata, references the feature mixin / action set and configuration.
  • ActionSet / mixin
    Contains the actions/methods of the feature mixin.
// feature-set...
var App = new features.FeatureSet()

// features...
App.Feature('A', {
    // ...
})
App.Feature('B', {
    // ...
})

// meta-features...
App.Feature('all', [
    'B',
    'C',
])

// init and start the app...
var app = App.start(['all'])

Lifecycle

How features are loaded

The main entities:

FeatureSet()

FeatureSet()
    -> <feature-set>
var feature_set = new features.FeatureSet()


// define features...
// ...


// setup features...
feature_set
    .setup([
        'feature-tag',
        //...
    ])

XXX

<feature-set>.Feature(..)

Feature constructor.

For more info see: Feature(..)

<feature-set>.<feature-tag> / <feature-set>[<feature-tag>]

<feature-set>.features

<feature-set>.setup(..)

<feature-set>.remove(..)

<feature-set>.gvGraph(..)

Get a Graphvis graph spec for the feature dependency graph.

Feature(..)

Standalone feature

Feature({ tag: <tag>, .. })
Feature(<tag>, { .. })
Feature(<tag>, [<suggested-tag>, .. ])
Feature(<tag>, <actions>)
	-> <feature>

Feature-set features

<feature-set>.Feature({ tag: <tag>, .. })
<feature-set>.Feature(<tag>, { .. })
<feature-set>.Feature(<tag>, [<suggested-tag>, .. ])
<feature-set>.Feature(<tag>, <actions>)
	-> <feature>
    
Feature(<feature-set>, { tag: <tag>, .. })
Feature(<feature-set>, <tag>, <actions>)
	-> <feature>

Examples:

feature_set.Feature('minimal_feature_example', {})
feature_set.Feature({
    // feature unique identifier (required)...
    tag: 'feature_example',

    // documentation (optional)...
    title: 'Example Feature',
    doc: 'A feature to demo the base API...',

    // applicability test (optional)
    isApplicable: function(){ /* ... */ },

    // feature load priority (optional)
    priority: 'medium',

    // list of feature tags to load if available (optional)
    suggested: [],

    // list of feature tags required to load before this feature (optional)
    depends: [],

    // Exclusive tag (optional)
    // NOTE: a feature can be a member of more than one exclusive group,
    //	to list more than one use an Array...
    exclusive: 'Example',

    // feature configuration (optional)
    // NOTE: if not present here this will be taken from .actions.config
    // NOTE: this takes priority over .actions.config, it is not recommended
    //	to define both.
    config: {
        option: 'value',
        // ...
    },

    // actions (optional)
    actions: Actions({
        // alternative configuration location...
        config: {
            // ...
        },
        // ...
    }),

    // action handlers (optional)
    handlers: [
        ['action.pre', 
            function(){ /* ... */ }],
        // ...
    ],
})

XXX

Meta-features

// meta-feature...
feature_set.Feature('meta-feature-tag', [
    'suggested-feature-tag',
    'other-suggested-feature-tag',
    // ...
])

XXX

Extending

License

BSD 3-Clause License

Copyright (c) 2018+, Alex A. Naanou, All rights reserved.

Description
WARNING: this module configuration is experimental and is likely to get redesigned before stabilizing.
Readme BSD-3-Clause 207 KiB
Languages
JavaScript 100%