assertNoRootAppElm(rootAppElm, className)
A convenience function that asserts the supplied rootAppElm is NOT defined.

When this constraint is not met, and error is thrown, after emitting applicable context in the console log.

For more information, please refer to Injecting DOM Content.

ParamTypeDescription
rootAppElmreactElm

the current react app element root to check.

classNamestring

the className on behalf of which this assertion is performed.




createFeature(name, [enabled], [fassets], [appWillStart], [appInit], [appDidStart], [extendedAspect]) ⇒ Feature
Create a new Feature object, cataloging AspectContent to be consumed by launchApp(). Each feature within an application promotes it's own Feature object.

For more information, please refer to Feature & aspect content.

Please Note this function uses named parameters.

ParamTypeDefaultDescription
namestring

the identity of the feature. Feature names are guaranteed to be unique. Application code can use the Feature name in various single-source-of-truth operations (see Best Practices).

[enabled]booleantrue

an indicator as to whether this feature is enabled (true) or not (false). When used, this indicator is typically based on a dynamic expression, allowing packaged code to be dynamically enabled/disabled at run-time (please refer to: Feature Enablement).

[fassets]fassets

an optional aspect that promotes feature assets used in Cross Feature Communication (i.e. the Public Face of a feature). fassets directives can both define resources, and/or declare a resource contract (the intention to use a set of fasset resources). Resources are accumulated across all features, and exposed through the Fassets object, and the withFassets() HoC.

[appWillStart]appWillStartCB

an optional Application Life Cycle Hook invoked one time, just before the app starts up. This life-cycle hook can do any type of initialization, and/or optionally supplement the app's top-level content (using a non-null return) (please refer to: appWillStart).

[appInit]appInitCB

an optional Application Life Cycle Hook invoked one time, later in the app startup process. This life-cycle hook supports blocking async initialization (by simply returning a promise) (please refer to: appInit).

[appDidStart]appDidStartCB

an optional Application Life Cycle Hook invoked one time, immediately after the app has started (please refer to: appDidStart).

[extendedAspect]AspectContent

additional aspects, as defined by the feature-u's Aspect plugins (please refer to: Extendable aspects -and- Extending feature-u).

Returns: Feature - a new Feature object (to be consumed by launchApp()).




extendFeatureProperty(name, owner)
Extend valid Feature properties to include the supplied name ... used when extending APIs for Aspect Cross Communication.

feature-u keeps track of the agent that owns this extension (using the owner parameter). This is used to prevent exceptions when duplicate extension requests are made by the same owner. This can happen when multiple instances of an aspect type are supported, and also in unit testing.

Throws:

  • Error when supplied name is already reserved by a different owner
ParamTypeDescription
namestring

the property name to allow.

ownerstring

the requesting owner id of this extension request. Use any string that uniquely identifies your utility (such as the aspect's npm package name).




expandWithFassets(expandWithFassetsCB) ⇒ expandWithFassetsCB
Mark the supplied expandWithFassetsCB() as a "Managed Expansion Callback", distinguishing it from other functions (such as reducer functions).

Features may communicate AspectContent directly, or through a expandWithFassetsCB(). In other words, the AspectContent can either be the actual content itself (ex: reducer, logic modules, etc.), or a function that returns the content. The latter:

  1. supports Cross Feature Communication (through fassets object injection), and
  2. minimizes circular dependency issues (of ES6 modules).

Managed Expansion Callbacks are used when a fully resolved Fassets object is required during in-line code expansion. They are merely functions that when invoked (under the control of feature-u), are supplied the Fassets object and return the expanded AspectContent (ex: reducer, logic modules, etc.).

For more information (with examples), please refer to Managed Code Expansion.

The expandWithFassetsCB() function should conform to the following signature:

API: expandWithFassetsCB(fassets): AspectContent

ParamTypeDescription
expandWithFassetsCBexpandWithFassetsCB

the callback function that when invoked (by feature-u) expands/returns the desired AspectContent.

Returns: expandWithFassetsCB - the supplied expandWithFassetsCB, marked as a "managed expansion callback".




launchApp(features, [aspects], registerRootAppElm, [showStatus]) ⇒ Fassets
Launch an application by assembling the supplied features, driving the configuration of the frameworks in use (as orchestrated by the supplied set of plugable Aspects).

For more information (with examples), please refer to Launching Your Application.

Please Note this function uses named parameters.

ParamTypeDescription
featuresArray.<Feature>

the features that comprise this application.

[aspects]Array.<Aspect>

the set of plugable Aspects that extend feature-u, integrating other frameworks to match your specific run-time stack.

When NO Aspects are supplied (an atypical case), only the very basic feature-u characteristics are in effect (like fassets and life-cycle hooks).

registerRootAppElmregisterRootAppElmCB

the callback hook that registers the supplied root application element to the specific React framework used in the app.

Because this registration is accomplished by app-specific code, feature-u can operate in any of the react platforms, such as: react web, react-native, expo, etc.

Please refer to React Registration for more details and complete examples.

[showStatus]showStatusCB

an optional callback hook that communicates a blocking "persistent" status message to the end user.

Please refer to showStatus() for more information.

Returns: Fassets - the Fassets object used in cross-feature-communication.




useFassets(p) ⇒ Fassets | fassets-resource | fassetsProps
A React Hook that provides functional component access to feature-u fassets.

Hooks allow you to "hook into" React state and lifecycle aspects from functional components. They greatly simplify the UI implementation as opposed to the alternative of Higher Order Components (see: withFassets()).

There are three ways to invoke useFassets() (examples can be found at UI Composition):

  1. Passing NO parameters, returns the Fassets object:

    + useFassets(): fassets
    
  2. Passing a fassetsKey (a string), returns the resolved fassets resource:

    + useFassets('MainPage.*.link@withKeys'): [] ... an array of cataloged links
    

    The fassetsKey parameter is identical (in usage) to the Fassets.get() method.

  3. Passing a mapFassetsToPropsStruct, returns a set of resolved fassetsProps:

    + useFassets({
        mainBodies: 'MainPage.*.body',
        mainLinks:  'MainPage.*.link@withKeys'
      }): {  // ... return structure:
        mainBodies: ... resolved cataloged resource
        mainLinks:  ... ditto
      }
    

    The mapFassetsToPropsStruct allows you to return more than one resolved fassets resources.

SideBar: For useFassets() to operate, <FassetsContext.Provider> must be rendered at the root of your application DOM. This is really a moot point, because feature-u automatically performs this initialization, so you really don't have to worry about this detail (automating configuration is a Hallmark of feature-u - reducing boilerplate code).

ParamTypeDescription
pstring | mapFassetsToPropsStruct

the parameter controlling what useFassets does (see explanation above).

Returns: Fassets | fassets-resource | fassetsProps - see explanation above.




withFassets(mapFassetsToProps, [component]) ⇒ HoC | HoF
Promotes a "wrapped" Component (an HoC - Higher-order Component) that injects fasset props into a component, as specified by the mapFassetsToProps parameter. Please refer to the mapFassetsToPropsStruct for the details of what this mapping construct looks like. Examples can be found at UI Composition.

Central to this process, a Higher-order Function (HoF) is created that encapsulates this "mapping knowledge". Ultimately, this HoF must be invoked (passing component), which exposes the HoC (the "wrapped" Component).

+ withFassetsHoF(component): HoC

There are two ways to use withFassets():

  1. By directly passing the component parameter, the HoC will be returned (internally invoking the HoF). This is the most common use case.

  2. By omitting the component parameter, the HoF will be returned. This is useful to facilitate "functional composition" (in functional programming). In this case it is the client's responsibility to invoke the HoF (either directly or indirectly) in order to expose the HoC.

SideBar: For withFassets() to operate, <FassetsContext.Provider> must be rendered at the root of your application DOM. This is really a moot point, because feature-u automatically performs this initialization, so you really don't have to worry about this detail (automating configuration is a Hallmark of feature-u - reducing boilerplate code).

Please Note this function uses named parameters.

ParamTypeDescription
mapFassetsToPropsmapFassetsToPropsStruct | mapFassetsToPropsFn

the structure defining the prop/fassetsKey mapping, from which fasset resources are injected into component. This can either be a direct structure (mapFassetsToPropsStruct) or a function returning the structure (mapFassetsToPropsFn).

[component]ReactComp

optionally, the React Component to be wrapped (see discussion above).

Returns: HoC | HoF - either the HoC (the "wrapped" Component) when component is supplied, otherwise the HoF (see discussion above).

Examples:

  1. Inject fasset resources from a static structure (mapFassetsToPropsStruct), auto wrapping the MainPage Component ...

    function MainPage({Logo, mainLinks, mainBodies}) {
      return (
        <div>
          <div>
            <Logo/>
          </div>
          <div>
            {mainLinks.map( ([fassetsKey, MainLink]) => <MainLink key={fassetsKey}/>)}
          </div>
          <div>
            {mainBodies.map( (MainBody, indx) => <MainBody key={indx}/>)}
          </div>
        </div>
      );
    }
    
    export default withFassets({
      component: MainPage,  // NOTE: auto wrap MainPage
      mapFassetsToProps: {   // NOTE: static structure (mapFassetsToPropsStruct)
        Logo:       'company.logo',
                    // Logo:  companyLogoResource,
    
        mainLinks:  'MainPage.*.link@withKeys',
                    // mainLinks:  [['MainPage.cart.link',   cartLinkResource],
                    //              ['MainPage.search.link', searchLinkResource]],
        mainBodies: 'MainPage.*.body'
                    // mainBodies: [cartBodyResource, searchBodyResource],
      }
    });
    
  2. Inject fasset resources from a functional directive (mapFassetsToPropsFn), returning the HoF - immediately invoked ...

    function MainPage({mainLinks, mainBodies}) {
      return (
        ... same as prior example
      );
    }
    
    export default withFassets({
      mapFassetsToProps(ownProps) { // NOTE: functional directive (mapFassetsToPropsFn)
        ... some conditional logic based on ownProps
        return {
          Logo:       'company.logo',
                      // Logo:  companyLogoResource,
    
          mainLinks:  'MainPage.*.link@withKeys',
                      // mainLinks:  [['MainPage.cart.link',   cartLinkResource],
                      //              ['MainPage.search.link', searchLinkResource]],
          mainBodies: 'MainPage.*.body'
                      // mainBodies: [cartBodyResource, searchBodyResource],
        };
      }
    })(MainPage); // NOTE: immediately invoke the HoF, emitting the wrapped MainPage Component
    




createAspect(name, [genesis], [validateFeatureContent], [expandFeatureContent], [assembleFeatureContent], [assembleAspectResources], [initialRootAppElm], [injectRootAppElm], [injectParamsInHooks], [config], [additionalMethods]) ⇒ Aspect
Create an Aspect object, used to extend feature-u.

The Aspect object promotes a series of life-cycle methods that feature-u invokes in a controlled way. This life-cycle is controlled by launchApp() ... it is supplied the Aspects, and it invokes their methods.

The essential characteristics of a typical Aspect life-cycle is to:

  • accumulate AspectContent across all features
  • perform the desired setup and configuration
  • expose the framework in some way (by injecting a component in the root DOM, or some Aspect Cross Communication mechanism)

The Extending feature-u section provides more insight on how Aspects are created and used.

Aspect Plugins have NO one specific method that is required. Rather the requirement is to specify something (so as to not have an empty plugin that does nothing). Please refer to the "No Single Aspect Method is Required" discussion in the Aspect Life Cycle Methods.

Please Note this function uses named parameters. The order in which these items are presented represents the same order they are executed.

ParamTypeDescription
namestring

the Aspect.name is used to "key" AspectContent of this type in the Feature object.

For example: an Aspect.name: 'xyz' would permit a Feature.xyz: xyzContent construct.

As a result, Aspect names cannot clash with built-in aspects, and they must be unique (across all aspects that are in-use).

The Aspect.name is required, primarily for identity purposes (in logs and such).

[genesis]genesisMeth

a Life Cycle Hook invoked one time, at the very beginning of the app's start up process. This hook can perform Aspect related initialization and validation:

[validateFeatureContent]validateFeatureContentMeth

a validation hook allowing this aspect to verify it's content on the supplied feature (which is known to contain this aspect).

[expandFeatureContent]expandFeatureContentMeth

an aspect expansion hook, defaulting to the algorithm defined by expandWithFassets().

This function rarely needs to be overridden. It provides a hook to aspects that need to transfer additional content from the expansion function to the expanded content.

[assembleFeatureContent]assembleFeatureContentMeth

the Aspect method that assembles content for this aspect across all features, retaining needed state for subsequent ops.

This method is typically the primary task that is accomplished by most aspects.

[assembleAspectResources]assembleAspectResourcesMeth

an Aspect method that assemble resources for this aspect across all other aspects, retaining needed state for subsequent ops.

This hook is executed after all the aspects have assembled their feature content (i.e. after assembleFeatureContent()).

[initialRootAppElm]initialRootAppElmMeth

a callback hook that promotes some characteristic of this aspect within the rootAppElm ... the top-level react DOM that represents the display of the entire application.

The Defining rootAppElm section highlights when to use initialRootAppElm() verses injectRootAppElm().

[injectRootAppElm]injectRootAppElmMeth

a callback hook that promotes some characteristic of this aspect within the rootAppElm ... the top-level react DOM that represents the display of the entire application.

The Defining rootAppElm section highlights when to use initialRootAppElm() verses injectRootAppElm().

[injectParamsInHooks]injectParamsInHooksMeth

an Aspect method that promotes namedParams into the feature's Application Life Cycle Hooks, from this aspect.
This hook is executed after all aspects have assembled their feature content (i.e. after assembleFeatureContent()).

[config]Any

a sub-object that can be used for any type of configuration that a specific Aspect may need (see: Aspect.config).

[additionalMethods]Any

additional methods (proprietary to specific Aspects), supporting Aspect Cross Communication ... a contract between one or more aspects (see: Aspect.additionalMethods()).

Returns: Aspect - a new Aspect object (to be consumed by launchApp()).




extendAspectProperty(name, owner)
Extend valid Aspect properties to include the supplied name ... used when extending APIs for Aspect Cross Communication.

feature-u keeps track of the agent that owns this extension (using the owner parameter). This is used to prevent exceptions when duplicate extension requests are made by the same owner. This can happen when multiple instances of an aspect type are supported, and also in unit testing.

Throws:

  • Error when supplied name is already reserved by a different owner
ParamTypeDescription
namestring

the property name to extend.

ownerstring

the requesting owner id of this extension request. Use any string that uniquely identifies your utility (such as the aspect's npm package name).




Fassets : Object
The fassets object (emitted from launchApp()) is an accumulation of public feature assets gathered from all features. It facilitates Cross Feature Communication by promoting the public resources of any given feature.

SideBar: The term fassets is a play on words. While it is pronounced "facet" and is loosely related to this term, it is spelled fassets (i.e. feature assets).

There are 3 different ways to reference the resources contained in the fassets object:

  1. You may directly dereference them. As an example, an 'action.openView' resource can be dereferenced as follows:

    fassets.action.openView('mainView');
    
  2. You may use the Fassets.get() method, which can collect multiple resources (using Wildcards).

  3. Your UI components may indirectly access fassets resources through the withFassets() Higher-order Component (HoC).

SideBar: There are several ways to get a handle to the fassets object (see Obtaining fassets object).

For more information, please refer to Cross Feature Communication and Basic Concepts: fassets.




Fassets.get(fassetsKey) ⇒ resource | Array.<resource>
Get (i.e. fetch) the resource(s) corresponding to the supplied fassetsKey.

The fassets.get() method is an alternative to directly dereferencing the fassets object ... the advantage being:

  1. it can accumulate a series of resources (when Wildcards are used)

  2. and it can more gracefully return undefined at any level within the federated namespace path

Regarding the fassetsKey:

  • It is case-sensitive (as are the defined resources).

  • It may contain Wildcards (*), resulting in a multiple resources being returned (a resource array), matching the supplied pattern

  • Matches are restricted to the actual fassetKeys registered through the fassets aspect define/defineUse directives. In other words, the matching algorithm will not drill into the resource itself (assuming it is an object with depth).

  • The special dot keyword ('.') will return the fassets object itself (in the same tradition as "current directory").

  • '@withKeys':

    In some cases, you may wish to know the corresponding fassetsKey of the returned resource. This is especially true when multiple resources are returned (using wildcards). As an example, JSX requires unique keys for array injections (the fassetsKey is a prime candidate for this, since it is guaranteed to be unique).

    To accomplish this, simply suffix the fassetsKey with the keyword: '@withKeys'. When this is encountered, the resource returned is a two-element array: [fassetsKey, resource]. SideBar: We use this suffix technique (as opposed to an additional parameter) to be consistent with how withFassets() operates.

SideBar: The fassets.get() method is the basis of both the useFassets() React Hook, and the withFassets() Higher-order Component (HoC).

ParamTypeDescription
fassetsKeystring

the key of the resource(s) to fetch. This may include wildcards (*), as well as the '@withKeys' suffix (see discussion above).

Returns: resource | Array.<resource> - the requested fassets resource(s).

  • without wildcards, a single resource is returned (undefined for none).

    'a.b.c':          abcResource
    'a.b.c@withKeys': ['a.b.c', abcResource]
    
  • with wildcards, the return is a resource array, in order of feature expansion (empty array for none).

    'a.*':          [ab1Resource, ab2Resource, ...]
    'a.*@withKeys': [ ['a.b1', ab1Resource], ['a.b2', ab2Resource], ... ]
    




Fassets.hasFeature(featureName) ⇒ boolean
Return an indicator as to whether the supplied feature is active or not.

Note: As an alternative to using this method, you can conditionally reason over the existence of "well-known fasset resources" specific to a given feature.

ParamTypeDescription
featureNamestring

the name of the feature to check.

Returns: boolean - true: is active, false: is not active (or doesn't exist).




Feature : Object
The Feature object is merely a lightweight container that holds AspectContent of interest to feature-u.

Each feature within an application promotes a Feature object (using createFeature()) which catalogs the aspects of that feature.

Ultimately, all Feature objects are consumed by launchApp().

Feature content are simple key/value pairs (the key being an Aspect.name with values of AspectContent). These aspects can either be built-in (from core feature-u), or extensions.

Here is an example:

export default createFeature({
  name:     'featureA', // builtin aspect (name must be unique across all features within app)
  enabled:  true,       // builtin aspect enabling/disabling feature

  fassets: {            // builtin aspect promoting Public Face - Cross Feature Communication
    define: {
      'api.openA':  () => ...,
      'api.closeA': () => ...,
    },
  },

  appWillStart: (...) => ..., // builtin aspect (Application Life Cycle Hook)
  appInit:      (...) => ..., // ditto
  appDidStart:  (...) => ..., // ditto

  reducer: ..., // feature redux reducer (extended aspect from the feature-redux plugin)
  logic:   ..., // feature logic modules (extended aspect from the feature-redux-logic plugin)
});

For more information, please refer to Feature & aspect content.




appWillStartCB ⇒ reactElm | void
An optional Application Life Cycle Hook invoked one time, very early in the app startup process.

This life-cycle hook can do any type of general app-specific initialization (for example initializing a PWA service worker).

In addition, it can optionally inject static content in the app's DOM root. Any return is interpreted as the app's new rootAppElm (an accumulative process). IMPORTANT: When this is used, the supplied curRootAppElm MUST be included as part of this definition (accommodating the accumulative process of other feature injections)! More information is available at Injecting DOM Content

For more information (with examples), please refer to the Guide's appWillStart.

Please Note this function uses named parameters.

ParamTypeDescription
fassetsFassets

the Fassets object used in cross-feature-communication.

curRootAppElmreactElm

the current react app element root.

Returns: reactElm | void - optionally, new top-level content (which in turn must contain the supplied curRootAppElm). Use a void return when top-level content is unchanged.




appInitCB ⇒ Promise | void
An optional Application Life Cycle Hook invoked one time, later in the app startup process. It supports blocking async initialization.

This hook is invoked when the app is nearly up-and-running.

  • The React Registration has already occurred (via the registerRootAppElm() callback). As a result, you can rely on utilities that require an app-specific rootAppElm to exist.

  • You have access to the getState() and dispatch() function, assuming you are using redux (when detected by feature-u's plugable aspects).

    These parameters are actually injected by the feature-redux Aspect, and are examples of what can be injected by any Aspect (please refer your specific Aspect's documentation to determine other parameters).

Just like the appWillStart() hook, you may perform any type of general initialization that is required by your feature.

However the hallmark of this hook is you can block for any asynchronous initialization to complete. By simply returning a promise, feature-u will wait for the process to complete.

The user is kept advised of any long-running async processes. By default an 'initializing feature: {feature.name}' message is used, but you can customize it through the supplied showStatus() function parameter.

For more info with examples, please see the Guide's appInit.

Please Note this function uses named parameters.

ParamTypeDescription
showStatusshowStatusCB

the function that (when invoked) will communicate a blocking "persistent" status message to the end user.

fassetsFassets

the Fassets object used in cross-feature-communication.

[getState]Any

the redux function returning the top-level app state (when redux is in use).

[dispatch]function

the redux dispatch() function (when redux is in use).

[injectedAspectParams]any

additional parameters injected by Aspect plugins (please refer your specific Aspect's documentation to determine other parameters). The getState and dispatch params (above) are examples of this.

Returns: Promise | void - optionally, a promise (for asynchronous processes) - and feature-u will wait for the process to complete. Use a void return (for synchronous processes) - and no blocking will occur.




appDidStartCB ⇒
An optional Application Life Cycle Hook invoked one time, once the app startup process has completed.

This life-cycle hook can be used to trigger "the app is running" events. A typical usage is to "kick start" some early application logic.

Because the app is up-and-running at this time, you have access to the getState() and dispatch() function ... assuming you are using redux (when detected by feature-u's plugable aspects). These parameters are actually injected by the feature-redux Aspect, and are examples of what can be injected by any Aspect (please refer your specific Aspect's documentation to determine other parameters).

For more info with examples, please see the Guide's appDidStart.

Please Note this function uses named parameters.

ParamTypeDescription
fassetsFassets

the Fassets object used in cross-feature-communication.

[getState]Any

the redux function returning the top-level app state (when redux is in use).

[dispatch]function

the redux dispatch() function (when redux is in use).

[injectedAspectParams]any

additional parameters injected by Aspect plugins (please refer your specific Aspect's documentation to determine other parameters). The getState and dispatch params (above) are examples of this.

Returns: void




fassets : BuiltInAspect
A builtin aspect that publicly promotes feature-based resources called fassets (feature assets). These resources are the basis of Cross Feature Communication. You can think of this as the Public Face of a feature.

SideBar: The term fassets is a play on words. While it is pronounced "facet" and is loosely related to this term, it is spelled fassets (i.e. feature assets).

Feature resources are accumulated across all features, and exposed through the Fassets object. They can also be referenced via the withFassets() HoC.

The fassets aspect can both define resources, and/or declare a resource contract (i.e. the intention to use a set of fasset resources). This is accomplished via three separate fassets directives: define, use, and defineUse. A good summary of these directives can be found at fassets Recap: Push or Pull.

  1. define: define public resources, held in the Fassets object

    fassets: {
      define: {
        '{fassetsKey}': {fassetsValue}
    
        ... 
    
        NOTES:
         - fassetsKey MUST be unique
         - are case-sensitive
         - may contain federated namespace (via dots ".")
           ... normalized in fassets object
           ... ex: 'MainPage.launch'
         - may be any valid JS identifier (less $ support)
         - may NOT contain wildcards
           ... i.e. must be defined completely
    
        // examples ...
        'openView': actions.view.open, // fassets.openView(viewName): Action
    
        // federated namespace example
        'selector.currentView': selector.currentView, // fassets.selector.currentView(appState): viewName
    
        // UI Component example
        'MainPage.cart.link': () => <Link to="/cart">Cart</Link>,
        'MainPage.cart.body': () => <Route path="/cart" component={ShoppingCart}/>,
      }
    }
    
  2. use: specify public resource keys that will be used by the containing feature (i.e. a resource contract)

    fassets: {
      use: [
        '{fassetsKey}',
        -or-
        ['$fassetsKey', {required: true/false, type: $validationFn}],
    
        ... 
    
        NOTES:
         - each key will be supplied by other features
         - this is a communication to other features (i.e. a contract)
           ... saying: I plan to "use" these injections
           HOWEVER: feature-u cannot strictly enforce this usage
                    ... enclosed feature should reference this
                        {fassetsKey} through fassets.get(), or withFassets()
         - is case-sensitive
         - may contain federated namespace (with dots ".")
           ... ex: 'MainPage.launch'
         - may be any valid JS identifier (less $ support)
         - may contain wildcards (with "*")
           ... ex: 'MainPage.*.link'
    
        // examples ...
        'MainPage.launch',
    
        // may contain wildcards ...
        'MainPage.*.link',
        'MainPage.*.body',
    
        // optionally supply options object, controlling optionality and data types
        ['MainPage.*.link',  { required: true,   type: any  }], // same as DEFAULTS
        ['MainPage.*.link',  { required: false,             }], // optional of any type
        ['MainPage.*.link',  {                   type: comp }], // required of react component type
        ['MainPage.*.link',  { required: false,  type: comp }], // optional of react component type
      ]
    }
    
  3. defineUse: define public resources specified by other features (via the use directive)

    fassets: {
      defineUse: {
        '{fassetsKey}': {fassetsValue}
    
        ... 
    
        NOTES:
         - this is identical to fassets.define EXCEPT:
         - it MUST MATCH a fassets.use directive
           ... using this directive, feature-u will perform additional
               validation to unsure these entries match a use contract
    
        // examples ...
        'MainPage.cart.link': () => <Link to="/cart">Cart</Link>,
        'MainPage.cart.body': () => <Route path="/cart" component={ShoppingCart}/>,
      }
    }
    

For more information, please refer to Cross Feature Communication, Fassets object, the withFassets() HoC, and the fassets Recap: Push or Pull.




expandWithFassetsCB ⇒ AspectContent
A "managed expansion callback" (defined by expandWithFassets()) that when invoked (by feature-u) expands and returns the desired AspectContent.

For more information (with examples), please refer to Managed Code Expansion.

ParamTypeDescription
fassetsFassets

the Fassets object used in cross-feature-communication.

Returns: AspectContent - The desired AspectContent (ex: reducer, logic module, etc.).




fassetValidations : Object
A pre-defined container of fasset validation functions, which can be employed in the fassets aspect use directive. This allows the use directive to specify data type and content validation constraints.

These validations are available as a convenience. Additional validations can be created as needed.

The validation API should adhere to the following signature:

 + fassetValidationFn(fassetsValue): string || null

A return value of null represents a valid value, while a string specifies a validation error that feature-u will format as follows (see ${returnStr}):

  VALIDATION ERROR in resource: '${fassetsKey}',
    expecting: ${returnStr} ... 
    resource defined in Feature: '${resource.definingFeature}',
    usage contract '${useKey}' found in Feature: '${featureName}'

The following pre-defined validations are promoted through fassetValidations:

  • any: any type (except undefined)
  • comp: a react component
  • fn: a function
  • str: a string
  • bool: a boolean

Example:

createFeature({
  fassets: {
    use: [
       'MainPage.*.link', // DEFAULT: required of type any
      ['MainPage.*.body', {required: false, type: fassetValidations.comp}],
    ],
  },
});




registerRootAppElmCB ⇒
The launchApp() callback hook that registers the supplied root application element to the specific React framework used in the app.

Because this registration is accomplished by app-specific code, feature-u can operate in any of the React platforms, such as: react web, react-native, expo, etc.

Please refer to React Registration for more details and complete examples.

ParamTypeDescription
rootAppElmreactElm

the root application element to be registered.

fassetsFassets

the Fassets object used in cross-feature-communication (rarely needed except to allow client to inject their own FassetsContext.Provider for a null rootAppElm).

Returns: void




showStatusCB ⇒
The optional launchApp() callback hook that communicates a blocking "persistent" status message to the end user.

These status messages originate from the blocking that occurs in the asynchronous processes managed by the Feature.appInit() life-cycle-hook.

By design feature-u has no ability to manifest messages to the end user, because this is very app-specific in styling and other heuristics. By default (when NO showStatus parameter is supplied, feature-u will simply console log these messages.

A typical manifestation of this callback is to display a running persistent SplashScreen, seeded with the supplied message. The SplashScreen should be taken down when NO message is supplied (i.e. '').

Please refer to Feature.appInit() for more details and examples.

ParamTypeDescription
[msg]string

the "persistent" message to display. When NO message is supplied (i.e. ''), all user notifications should be cleared (for example, take the SplashScreen down).

[err]Error

an optional error to communicate to the user.

Returns: void




mapFassetsToPropsStruct : Object
A structure (used by withFassets() and useFassets()) defining a prop/fassetsKey mapping, from which fasset resources are injected into a Component. Please see UI Composition for examples.

The injected Component properties will reference the fasset resource corresponding to the fassetsKey.

Each fassetsKey is case-sensitive (as are the defined resources).

Matches are restricted to the actual fassetKeys registered through the fassets aspect define/defineUse directives. In other words, the matching algorithm will not drill into the resource itself (assuming it is an object with depth).

The special dot keyword ('.') will yield the fassets object itself (in the same tradition as "current directory"). This is useful if you wish to inject fassets into downstream processes (such as redux connect() via it's ownProps).

Wildcards

Wildcards (*) are supported in the fassetsKey, accumulating multiple resources (a resource array), matching the supplied pattern:

  • without wildcards, a single resource is injected (undefined for none).

  • with wildcards, a resource array is injected, in order of feature expansion (empty array for none).

Example ...

mapFassetsToProps: {
  Logo:       'company.logo',
              // Logo:  companyLogoResource,

              // NOTE: wildcard usage ...
  mainLinks:  'MainPage.*.link',
              // mainLinks:  [cartLinkResource, searchLinkResource],
  mainBodies: 'MainPage.*.body'
              // mainBodies: [cartBodyResource, searchBodyResource],
}

@withKeys

In some cases, you may wish to know the corresponding fassetsKey of the returned resource. This is especially true when multiple resources are returned (using wildcards).

As an example, React requires a key attribute for array injections (the fassetsKey is a prime candidate for this, since it is guaranteed to be unique).

To accomplish this, simply suffix the fassetsKey with the keyword: '@withKeys'. When this is encountered, the resource returned is a two-element array: [fassetsKey, resource].

Example ...

mapFassetsToProps: {
  Logo:       'company.logo',
              // Logo:  companyLogoResource,

  mainLinks:  'MainPage.*.link@withKeys', // NOTE: @withKeys directive
              // mainLinks:  [['MainPage.cart.link',   cartLinkResource],
              //              ['MainPage.search.link', searchLinkResource]],
  mainBodies: 'MainPage.*.body'
              // mainBodies: [cartBodyResource, searchBodyResource],
}

This topic is discussed in more detail in: React Keys (in array processing).




mapFassetsToPropsFn ⇒ mapFassetsToPropsStruct
A function (used by withFassets()) that returns a mapFassetsToPropsStruct, defining a prop/fassetsKey mapping, from which fasset resources are injected into a Component.

ParamTypeDescription
ownPropsobj

the outlying properties supplied to the connected component.

Returns: mapFassetsToPropsStruct - the structure defining a prop/fassetsKey mapping, from which fasset resources are injected into a Component.




Aspect : Object
Aspect objects (emitted from createAspect()) are used to extend feature-u.

The Aspect object promotes a series of life-cycle methods that feature-u invokes in a controlled way. This life-cycle is controlled by launchApp() ... it is supplied the Aspects, and it invokes their methods.

Typically Aspects are packaged separately (as an external npm feature-u extension), although they can be created locally within a project (if needed).

For more information, please refer to Extendable aspects and Extending feature-u.




AspectContent : Any
The content (or payload) of an Aspect, specified within a Feature.

The content type is specific to the Aspect. For example, a redux Aspect assembles reducers (via Feature.reducer), while a redux-logic Aspect gathers logic modules (via Feature.logic), etc.

AspectContent can either be defined from built-in aspects (via core feature-u), or extensions (from Aspect).

An Aspect object extends feature-u by accumulating information of interest from Feature objects (indexed by the Aspect name).

Note: Whenever AspectContent definitions require the Fassets object at code expansion time, you can wrap the definition in a expandWithFassets() function. In other words, your aspect content can either be the actual content itself (ex: a reducer), or a function that returns the content.

For more information, please refer to Feature & aspect content.




genesisMeth ⇒ string
A Life Cycle Hook invoked one time, at the very beginning of the app's start up process.

Antiquated Note:

  • The genesis() hook is somewhat antiquated, relegated to Aspects that are promoted as singletons. In this scenario, client-side configuration could be introduced after instantiation (by adding content to Aspect.config), while still allowing initialization and validation to occur early in the startup process (via this genesis() hook).

  • A better alternative to the genesis() hook is to promote your Custom Aspect Plugins as non-singletons, where initialization and validation can be directly promoted though the plugin constructor.

The genesis() hook can perform Aspect related initialization and validation:

  • initialization: It is possible to to register proprietary Aspect/Feature APIs in the genesis() hook ... via extendAspectProperty() and extendFeatureProperty() (please see: Aspect Cross Communication and Cross Feature Communication).

    The preferred place to do this initialization is in the plugin constructor (see Antiquated Note above).

  • validation: It is possible to perform Aspect validation in the genesis() hook ... say for required configuration properties injected by the client after instantiation. This is the reason for the optional return string.

    The preferred place to do validation is in the plugin constructor, gathering this information as constructor parameters (see Antiquated Note above).

API: genesis(): string

Returns: string - an error message when self is in an invalid state (falsy when valid). Because this validation occurs under the control of launchApp(), any message is prefixed with: 'launchApp() parameter violation: '.




validateFeatureContentMeth ⇒ string
A validation hook allowing this aspect to verify it's content on the supplied feature.

API: validateFeatureContent(feature): string

ParamTypeDescription
featureFeature

the feature to validate, which is known to contain this aspect.

Returns: string - an error message string when the supplied feature contains invalid content for this aspect (falsy when valid). Because this validation conceptually occurs under the control of createFeature(), any message is prefixed with: 'createFeature() parameter violation: '.




expandFeatureContentMeth ⇒ string
Expand self's AspectContent in the supplied feature, replacing that content (within the feature). Once expansion is complete, feature-u will perform a delayed validation of the expanded content.

API: expandFeatureContent(fassets, feature): string

The default behavior simply implements the expansion algorithm defined by expandWithFassets():

feature[this.name] = feature[this.name](fassets);

This default behavior rarely needs to change. It however provides a hook for aspects that need to transfer additional content from the expansion function to the expanded content. As an example, the reducer aspect must transfer the slice property from the expansion function to the expanded reducer.

ParamTypeDescription
fassetsFassets

the Fassets object used in feature cross-communication.

featureFeature

the feature which is known to contain this aspect and is in need of expansion (as defined by expandWithFassets()).

Returns: string - an optional error message when the supplied feature contains invalid content for this aspect (falsy when valid). This is a specialized validation of the expansion function, over-and-above what is checked in the standard validateFeatureContent() hook.




assembleFeatureContentMeth ⇒
The Aspect method that assembles content for this aspect across all features, retaining needed state for subsequent ops. This method is typically the primary task that is accomplished by most aspects.

API: assembleFeatureContent(fassets, activeFeatures): void

ParamTypeDescription
fassetsFassets

the Fassets object used in feature cross-communication.

activeFeaturesArray.<Feature>

The set of active (enabled) features that comprise this application.

Returns: void




assembleAspectResourcesMeth ⇒
An Aspect method that assembles resources for this aspect across all other aspects, retaining needed state for subsequent ops. This hook is executed after all the aspects have assembled their feature content (i.e. after assembleFeatureContent()).

API: assembleAspectResources(fassets, aspects): void

This is an optional second-pass (so-to-speak) of Aspect data gathering, that facilitates Aspect Cross Communication. It allows an extending aspect to gather resources from other aspects, using an additional API (ex: Aspect.getXyz()).

ParamTypeDescription
fassetsFassets

the Fassets object used in feature cross-communication.

aspectsArray.<Aspect>

The set of feature-u Aspect objects used in this this application.

Returns: void




initialRootAppElmMeth ⇒ reactElm
A callback hook that promotes some characteristic of this aspect within the rootAppElm ... the top-level react DOM that represents the display of the entire application.

API: initialRootAppElm(fassets, curRootAppElm): rootAppElm

The Defining rootAppElm section highlights when to use initialRootAppElm() verses injectRootAppElm().

NOTE: When this hook is used, the supplied curRootAppElm MUST be included as part of this definition!

ParamTypeDescription
fassetsFassets

the Fassets object used in feature cross-communication.

curRootAppElmreactElm

the current react app element root.

Returns: reactElm - a new react app element root (which in turn must contain the supplied curRootAppElm), or simply the supplied curRootAppElm (if no change).




injectRootAppElmMeth ⇒ reactElm
A callback hook that promotes some characteristic of this aspect within the rootAppElm ... the top-level react DOM that represents the display of the entire application.

API: injectRootAppElm(fassets, curRootAppElm): rootAppElm

The Defining rootAppElm section highlights when to use initialRootAppElm() verses injectRootAppElm().

NOTE: When this hook is used, the supplied curRootAppElm MUST be included as part of this definition!

ParamTypeDescription
fassetsFassets

the Fassets object used in feature cross-communication.

curRootAppElmreactElm

the current react app element root.

Returns: reactElm - a new react app element root (which in turn must contain the supplied curRootAppElm), or simply the supplied curRootAppElm (if no change).




injectParamsInHooksMeth ⇒ namedParams
An Aspect method that promotes namedParams into the feature's Application Life Cycle Hooks, from this aspect. This hook is executed after all aspects have assembled their feature content (i.e. after assembleFeatureContent()).

Here is a namedParams example from a redux aspect, promoting it's state and dispatch functions:

{getState, dispatch}

API: injectParamsInHooks(fassets): namedParams

Any aspect may promote their own set of namedParams. feature-u will insure there are no name clashes across aspects (which results in an exception). If your parameter names have a high potential for clashing, a best practice would be to qualify them in some way to better insure uniqueness.

ParamTypeDescription
fassetsFassets

the Fassets object used in feature cross-communication.

Returns: namedParams - a plain object that will be injected (as named parameters) into the feature's Application Life Cycle Hooks, from this aspect.

results matching ""

    No results matching ""