Neurological Phenomenon Multiplexer
    Have ideas to improve npm?Join in the discussion! »

    knifecycle
    TypeScript icon, indicating that this package has built-in type declarations

    11.1.1 • Public • Published

    knifecycle

    Manage your NodeJS processes's lifecycle automatically with an unobtrusive dependency injection implementation.

    GitHub license Build status Coverage Status NPM version Dependency Status devDependency Status Package Quality Code Climate

    Browser Support Matrix

    Most (maybe all) applications rely on two kinds of dependencies.

    The code dependencies are fully covered by JavaScript modules in a testable manner (with mockery or System directly). There is no need for another dependency management system if those libraries are pure functions (involve no global states at all).

    Unfortunately, applications often rely on global states where the JavaScript module system shows its limits. This is where knifecycle enters the game.

    It is largely inspired by the Angular service system except it should not provide code but access to global states (time, filesystem, db). It also have an important additional feature to shutdown processes which is really useful for back-end servers and doesn't exists in Angular.

    You may want to look at the architecture notes to better handle the reasonning behind knifecycle and its implementation.

    At this point you may think that a DI system is useless. My advice is that it depends. But at least, you should not make a definitive choice and allow both approaches. See this StackOverflow answer for more context about this statement.

    Features

    • services management: start services taking their dependencies in count and shut them down the same way for graceful exits (namely dependency injection with inverted control);
    • singleton: maintain singleton services across several running execution silos.
    • easy end to end testing: just replace your services per your own mocks and stubs while ensuring your application integrity between testing and production;
    • isolation: isolate processing in a clean manner, per concerns;
    • functional programming ready: encapsulate global states allowing the rest of your application to be purely functional;
    • no circular dependencies for services: while circular dependencies are not a problem within purely functional libraries (require allows it), it may be harmful for your services, knifecycle impeach that while providing an $injector service à la Angular to allow accessing existing services references if you really need to;
    • generate Mermaid graphs of the dependency tree;
    • build raw initialization modules to avoid embedding Knifecycle in your builds;
    • optionally autoload services dependencies with custom logic.

    Usage

    Using knifecycle is all about declaring the services our application needs and running your application over it.

    Let's say we are building a CLI script. Here is how we would proceed with Knifecycle:

    // bin.js
    import fs from 'fs';
    import YError from 'YError';
    import Knifecycle, { initializer, constant, inject, name } from 'knifecycle';
    
    // First of all we create a new Knifecycle instance
    const $ = new Knifecycle();
    
    // Some of our code with rely on the process environment
    // let's inject it as a constant instead of directly
    // pickking env vars in `process.env` to make our code
    // easily testable
    $.register(constant('ENV', process.env));
    
    // Let's do so for CLI args with another constant
    // in real world apps we would have created a service
    // that would parse args in a complexer way
    $.register(constant('ARGS', process.argv));
    
    // We want our CLI tool to rely on some configuration
    // Let's build an injectable service initializer that
    // reads environment variables via an injected but
    // optional `ENV` object
    async function initConfig({ ENV = { CONFIG_PATH: '.' } }) {
      return new Promise((resolve, reject) => {
        fs.readFile(ENV.CONFIG_PATH, 'utf-8', (err, data) => {
          if (err) {
            reject(err);
            return;
          }
          try {
            resolve(JSON.parse(data));
          } catch (err) {
            reject(err);
          }
        });
      });
    }
    
    // We are using the `initializer` decorator to
    // declare our service initializer specificities
    // and register it with our Knifecycle instance
    $.register(
      initializer(
        {
          // we have to give our final service a name
          // for further use in other services injections
          name: 'CONFIG',
          // we will need an `ENV` variable in the initializer
          // so adding it in the injected dependencies. The `?`
          // sign tells Knifecycle that the ENV dependency
          // is optional
          inject: ['?ENV'],
          // our initializer is simple so we use the `service`
          // type for the initializer which just indicate that
          // the initializer will return a promise of the actual
          // service
          type: 'service',
          // We don't want to read the config file everytime we
          // inject it so declaring it as a singleton
          singleton: true,
        },
        initConfig,
      ),
    );
    
    // Our CLI also uses a database so let's write an
    // initializer for it:
    const initDB = initializer(
      {
        name: 'db',
        // Here we are injecting the previous `CONFIG` service
        // as required so that our DB cannot be connected without
        // having a proper config.
        inject: ['CONFIG', 'DB_URI', '?log'],
        // The initializer type is slightly different. Indeed,
        // we need to manage the database connection errors
        // and wait for it to flush before shutting down the
        // process.
        // A service provider returns a promise of a provider
        // descriptor exposing:
        // - a mandatory `service` property containing the
        // actual service;
        // - an optional `dispose` function allowing to
        // gracefully close the service;
        // - an optional `fatalErrorPromise` property to
        // handle the service unrecoverable failure.
        type: 'provider',
        singleton: true,
      },
      async ({ CONFIG, DB_URI, log }) => {
        const db = await MongoClient.connect(DB_URI, CONFIG.databaseOptions);
        let fatalErrorPromise = new Promise((resolve, reject) => {
          db.once('error', reject);
        });
    
        // Logging only if the `log` service is defined
        log && log('info', 'db service initialized!');
    
        return {
          service: db,
          dispose: db.close.bind(db, true),
          fatalErrorPromise,
        };
      },
    );
    
    // Here we are registering our initializer apart to
    // be able to reuse it, we also declare the required
    // DB_URI constant it needs
    $.register(constant('DB_URI', 'posgresql://xxxx'));
    $.register(initDB);
    
    // Say we need to use two different DB server
    // We can reuse our initializer by tweaking
    // some of its properties
    $.register(constant('DB_URI2', 'posgresql://yyyy'));
    $.register(
      // First we remap the injected dependencies. It will
      // take the `DB_URI2` constant and inject it as
      // `DB_URI`
      inject(
        ['CONFIG', 'DB_URI2>DB_URI', '?log'],
        // Then we override its name to make it
        // available as a different service
        name('db2', initDB),
      ),
    );
    
    // A lot of NodeJS functions have some side effects
    // declaring them as constants allows you to easily
    // mock/monitor/patch it. The `common-services` NPM
    // module contains a few useful ones
    $.register(constant('now', Date.now.bind(Date)))
      .register(constant('log', console.log.bind(console)))
      .register(constant('exit', process.exit.bind(process)));
    
    // Finally, let's declare an `$autoload` service
    // to allow us to load only the initializers needed
    // to run the given commands
    $.register(
      initializer(
        {
          name: '$autoload',
          type: 'service',
          inject: ['CONFIG', 'ARGS'],
          // Note that the auto loader must be a singleton
          singleton: true,
        },
        async ({ CONFIG, ARGS }) => async (serviceName) => {
          if ('command' !== serviceName) {
            // Allows to signal that the dependency is not found
            // so that optional dependencies doesn't impeach the
            // injector to resolve the dependency tree
            throw new YError('E_UNMATCHED_DEPENDENCY', serviceName);
          }
          try {
            const path = CONFIG.commands + '/' + ARGS[2];
            return {
              path,
              initializer: require(path).default,
            };
          } catch (err) {
            throw new Error(`Cannot load ${serviceName}: ${ARGS[2]}!`);
          }
        },
      ),
    );
    
    // At this point, nothing is running. To instanciate the
    // services, we have to create an execution silo using
    // them. Note that we required the `$instance` service
    // implicitly created by `knifecycle`
    $.run(['command', '$instance', 'exit', 'log'])
      // Here, command contains the initializer eventually
      // found by automatically loading a NodeJS module
      // in the above `$autoload` service. The db connection
      // will only be instanciated if that command needs it
      .then(async ({ command, $instance, exit, log }) => {
        try {
          command();
    
          log('It worked!');
        } catch (err) {
          log('It failed!', err);
        } finally {
          // Here we ensure every db connections are closed
          // properly. We could have use `$.destroy()` the same
          // way but this is to illustrate that the Knifecycle
          // instance can be injected in services contexts
          // (rarely done but good to know it exists)
          await $instance.destroy().catch((err) => {
            console.error('Could not exit gracefully:', err);
            exit(1);
          });
        }
      })
      .catch((err) => {
        console.error('Could not launch the app:', err);
        process.exit(1);
      });

    Running the following should make the magic happen:

    cat "{ commands: './commands'}" > config.json
    DEBUG=knifecycle CONFIG_PATH=./config.json node -r @babel/register bin.js mycommand test
    // Prints: Could not launch the app: Error: Cannot load command: mycommand!
    // (...stack trace)

    Or at least, we still have to create commands, let's create the mycommand one:

    // commands/mycommand.js
    import { initializer } from './dist';
    
    // A simple command that prints the given args
    export default initializer(
      {
        name: 'command',
        type: 'service',
        // Here we could have injected whatever we declared
        // in the previous file: db, now, exit...
        inject: ['ARGS', 'log'],
      },
      async ({ ARGS, log }) => {
        return () => log('Command args:', ARGS.slice(2));
      },
    );

    So now, it works:

    DEBUG=knifecycle CONFIG_PATH=./config.json node -r @babel/register bin.js mycommand test
    // Prints: Command args: [ 'mycommand', 'test' ]
    // It worked!

    This is a very simple example but you can find a complexer CLI usage with (metapak)[https://github.com/nfroidure/metapak/blob/master/bin/metapak.js].

    Auto detection

    Knifecycle also provide some utility function to automatically assign the initializer property declarations, the following 3 ways to declare the getUser service are equivalent:

    import noop from 'noop';
    import { autoInject, inject, initializer, autoService } from 'knifecycle';
    
    initializer({
      name: 'getUser',
      inject: ['db', '?log'],
      type: 'service',
    }, getUser);
    
    service('getUser', autoInject(getUser)));
    
    autoService(getUser);
    
    async function getUser({ db, log = noop}) {}

    That said, if you need to build your code with webpack/babel you may have to convert auto-detections to raw declarations with the babel-plugin-knifecycle plugin. You can also do this only for the performance improvements it brings.

    Also, keep in mind that the auto-detection is based on a simple regular expression so you should care to keep initializer signatures simple to avoid having a E_AUTO_INJECTION_FAILURE error. As a rule of thumb, avoid setting complex default values.

    // Won't work
    autoInject(async ({ log = () => {} }) => {});
    
    // Will work
    function noop() {}
    autoInject(async ({ log = noop }) => {});

    Debugging

    Simply use the DEBUG environment variable by setting it to 'knifecycle':

    DEBUG=knifecycle npm t

    The output is very verbose but lead to a deep understanding of mechanisms that take place under the hood.

    Plans

    The scope of this library won't change. However the plan is:

    • improve performances;
    • track bugs ;).

    I'll also share most of my own initializers and their stubs/mocks in order to let you reuse it through your projects easily. Here are the current projects that use this DI lib:

    Notice that those modules remains usable without using Knifecycle at all which is maybe the best feature of this library ;).

    API

    Classes

    Knifecycle

    Members

    defaultPromise.<function()>

    Instantiate the initializer builder service

    Functions

    reuseSpecialProps(from, to, [amend])function

    Apply special props to the given initializer from another one and optionally amend with new special props

    constant(name, value)function

    Decorator that creates an initializer for a constant value

    service(serviceBuilder, [name], [dependencies], [singleton], [extra])function

    Decorator that creates an initializer from a service builder

    autoService(serviceBuilder)function

    Decorator that creates an initializer from a service builder by automatically detecting its name and dependencies

    provider(providerBuilder, [name], [dependencies], [singleton], [extra])function

    Decorator that creates an initializer for a provider builder

    autoProvider(providerBuilder)function

    Decorator that creates an initializer from a provider builder by automatically detecting its name and dependencies

    wrapInitializer(wrapper, baseInitializer)function

    Allows to wrap an initializer to add extra initialization steps

    inject(dependencies, initializer)function

    Decorator creating a new initializer with different dependencies declarations set to it.

    useInject(from, to)function

    Apply injected dependencies from the given initializer to another one

    mergeInject(from, to)function

    Merge injected dependencies of the given initializer with another one

    autoInject(initializer)function

    Decorator creating a new initializer with different dependencies declarations set to it according to the given function signature.

    alsoInject(dependencies, initializer)function

    Decorator creating a new initializer with some more dependencies declarations appended to it.

    extra(extraInformations, initializer, [merge])function

    Decorator creating a new initializer with some extra informations appended to it. It is just a way for user to store some additional informations but has no interaction with the Knifecycle internals.

    singleton(initializer, [isSingleton])function

    Decorator to set an initializer singleton option.

    name(name, initializer)function

    Decorator to set an initializer name.

    autoName(initializer)function

    Decorator to set an initializer name from its function name.

    type(type, initializer)function

    Decorator to set an initializer type.

    initializer(properties, initializer)function

    Decorator to set an initializer properties.

    handler(handlerFunction, [name], [dependencies], [options])function

    Shortcut to create an initializer with a simple handler

    autoHandler(handlerFunction)function

    Allows to create an initializer with a simple handler automagically

    parseDependencyDeclaration(dependencyDeclaration)Object

    Explode a dependency declaration an returns its parts.

    stringifyDependencyDeclaration(dependencyDeclarationParts)String

    Stringify a dependency declaration from its parts.

    unwrapInitializerProperties(initializer)function

    Utility function to check and reveal initializer properties.

    Knifecycle

    Kind: global class

    new Knifecycle()

    Create a new Knifecycle instance

    Returns: Knifecycle - The Knifecycle instance
    Example

    import Knifecycle from 'knifecycle'
    
    const $ = new Knifecycle();

    knifecycle.register(initializer) ⇒ Knifecycle

    Register an initializer

    Kind: instance method of Knifecycle
    Returns: Knifecycle - The Knifecycle instance (for chaining)

    Param Type Description
    initializer function An initializer

    knifecycle.toMermaidGraph(options) ⇒ String

    Outputs a Mermaid compatible dependency graph of the declared services. See Mermaid docs

    Kind: instance method of Knifecycle
    Returns: String - Returns a string containing the Mermaid dependency graph

    Param Type Description
    options Object Options for generating the graph (destructured)
    options.shapes Array.<Object> Various shapes to apply
    options.styles Array.<Object> Various styles to apply
    options.classes Object A hash of various classes contents

    Example

    import Knifecycle, { inject, constant, service } from 'knifecycle';
    import appInitializer from './app';
    
    const $ = new Knifecycle();
    
    $.register(constant('ENV', process.env));
    $.register(constant('OS', require('os')));
    $.register(service('app', inject(['ENV', 'OS'], appInitializer)));
    $.toMermaidGraph();
    
    // returns
    graph TD
      app-->ENV
      app-->OS

    knifecycle.run(dependenciesDeclarations) ⇒ Promise

    Creates a new execution silo

    Kind: instance method of Knifecycle
    Returns: Promise - Service descriptor promise

    Param Type Description
    dependenciesDeclarations Array.<String> Service name.

    Example

    import Knifecycle, { constant } from 'knifecycle'
    
    const $ = new Knifecycle();
    
    $.register(constant('ENV', process.env));
    $.run(['ENV'])
    .then(({ ENV }) => {
     // Here goes your code
    })

    knifecycle.destroy() ⇒ Promise

    Destroy the Knifecycle instance

    Kind: instance method of Knifecycle
    Returns: Promise - Full destruction promise
    Example

    import Knifecycle, { constant } from 'knifecycle'
    
    const $ = new Knifecycle();
    
    $.register(constant('ENV', process.env));
    $.run(['ENV'])
    .then(({ ENV }) => {
       // Here goes your code
    
       // Finally destroy the instance
       $.destroy()
    })

    knifecycle._getServiceDescriptor(siloContext, serviceName, options, serviceProvider) ⇒ Promise

    Initialize or return a service descriptor

    Kind: instance method of Knifecycle
    Returns: Promise - Service descriptor promise.

    Param Type Description
    siloContext Object Current execution silo context
    serviceName String Service name.
    options Object Options for service retrieval
    options.injectorContext Boolean Flag indicating the injection were initiated by the $injector
    options.autoloading Boolean Flag to indicating $autoload dependencies on the fly loading
    serviceProvider String Service provider.

    knifecycle._initializeServiceDescriptor(siloContext, serviceName, options) ⇒ Promise

    Initialize a service descriptor

    Kind: instance method of Knifecycle
    Returns: Promise - Service dependencies hash promise.

    Param Type Description
    siloContext Object Current execution silo context
    serviceName String Service name.
    options Object Options for service retrieval
    options.injectorContext Boolean Flag indicating the injection were initiated by the $injector
    options.autoloading Boolean Flag to indicating $autoload dependendencies on the fly loading.

    knifecycle._initializeDependencies(siloContext, serviceName, servicesDeclarations, options) ⇒ Promise

    Initialize a service dependencies

    Kind: instance method of Knifecycle
    Returns: Promise - Service dependencies hash promise.

    Param Type Description
    siloContext Object Current execution silo siloContext
    serviceName String Service name.
    servicesDeclarations String Dependencies declarations.
    options Object Options for service retrieval
    options.injectorContext Boolean Flag indicating the injection were initiated by the $injector
    options.autoloading Boolean Flag to indicating $autoload dependendencies on the fly loading.

    default ⇒ Promise.<function()>

    Instantiate the initializer builder service

    Kind: global variable
    Returns: Promise.<function()> - A promise of the buildInitializer function

    Param Type Description
    services Object The services to inject
    services.$autoload Object The dependencies autoloader

    Example

    import initInitializerBuilder from 'knifecycle/dist/build';
    
    const buildInitializer = await initInitializerBuilder({
      $autoload: async () => {},
    });

    reuseSpecialProps(from, to, [amend]) ⇒ function

    Apply special props to the given initializer from another one and optionally amend with new special props

    Kind: global function
    Returns: function - The newly built initializer

    Param Type Default Description
    from function The initializer in which to pick the props
    to function The initializer from which to build the new one
    [amend] Object {} Some properties to override

    constant(name, value) ⇒ function

    Decorator that creates an initializer for a constant value

    Kind: global function
    Returns: function - Returns a new constant initializer

    Param Type Description
    name String The constant's name.
    value any The constant's value

    Example

    import Knifecycle, { constant, service } from 'knifecycle';
    
    const { printAnswer } = new Knifecycle()
      .register(constant('THE_NUMBER', value))
      .register(constant('log', console.log.bind(console)))
      .register(service(
        async ({ THE_NUMBER, log }) => () => log(THE_NUMBER),
        'printAnswer',
        ['THE_NUMBER', 'log'],
      ))
      .run(['printAnswer']);
    
    printAnswer(); // 42

    service(serviceBuilder, [name], [dependencies], [singleton], [extra]) ⇒ function

    Decorator that creates an initializer from a service builder

    Kind: global function
    Returns: function - Returns a new initializer

    Param Type Description
    serviceBuilder function An async function to build the service
    [name] String The service's name
    [dependencies] Array.<String> The service's injected dependencies
    [singleton] Boolean Whether the service is a singleton or not
    [extra] any Eventual extra informations

    Example

    import Knifecycle, { constant, service } from 'knifecycle';
    
    const { printAnswer } = new Knifecycle()
      .register(constant('THE_NUMBER', value))
      .register(constant('log', console.log.bind(console)))
      .register(service(
        async ({ THE_NUMBER, log }) => () => log(THE_NUMBER),
        'printAnswer',
        ['THE_NUMBER', 'log'],
        true
      ))
      .run(['printAnswer']);
    
    printAnswer(); // 42

    autoService(serviceBuilder) ⇒ function

    Decorator that creates an initializer from a service builder by automatically detecting its name and dependencies

    Kind: global function
    Returns: function - Returns a new initializer

    Param Type Description
    serviceBuilder function An async function to build the service

    provider(providerBuilder, [name], [dependencies], [singleton], [extra]) ⇒ function

    Decorator that creates an initializer for a provider builder

    Kind: global function
    Returns: function - Returns a new provider initializer

    Param Type Description
    providerBuilder function An async function to build the service provider
    [name] String The service's name
    [dependencies] Array.<String> The service's dependencies
    [singleton] Boolean Whether the service is a singleton or not
    [extra] any Eventual extra informations

    Example

    import Knifecycle, { provider } from 'knifecycle'
    import fs from 'fs';
    
    const $ = new Knifecycle();
    
    $.register(provider(configProvider, 'config'));
    
    async function configProvider() {
      return new Promise((resolve, reject) {
        fs.readFile('config.js', function(err, data) {
          let config;
    
          if(err) {
            reject(err);
            return;
          }
    
          try {
            config = JSON.parse(data.toString);
          } catch (err) {
            reject(err);
            return;
          }
    
          resolve({
            service: config,
          });
        });
      });
    }

    autoProvider(providerBuilder) ⇒ function

    Decorator that creates an initializer from a provider builder by automatically detecting its name and dependencies

    Kind: global function
    Returns: function - Returns a new provider initializer

    Param Type Description
    providerBuilder function An async function to build the service provider

    wrapInitializer(wrapper, baseInitializer) ⇒ function

    Allows to wrap an initializer to add extra initialization steps

    Kind: global function
    Returns: function - The new initializer

    Param Type Description
    wrapper function A function taking dependencies and the base service in arguments
    baseInitializer function The initializer to decorate

    inject(dependencies, initializer) ⇒ function

    Decorator creating a new initializer with different dependencies declarations set to it.

    Kind: global function
    Returns: function - Returns a new initializer

    Param Type Description
    dependencies Array.<String> List of dependencies declarations to declare which services the initializer needs to provide its own service
    initializer function The initializer to tweak

    Example

    import Knifecycle, { inject } from 'knifecycle'
    import myServiceInitializer from './service';
    
    new Knifecycle()
     .register(
       service(
         inject(['ENV'], myServiceInitializer)
         'myService',
       )
      )
    );

    useInject(from, to) ⇒ function

    Apply injected dependencies from the given initializer to another one

    Kind: global function
    Returns: function - The newly built initialization function

    Param Type Description
    from function The initialization function in which to pick the dependencies
    to function The destination initialization function

    mergeInject(from, to) ⇒ function

    Merge injected dependencies of the given initializer with another one

    Kind: global function
    Returns: function - The newly built initialization function

    Param Type Description
    from function The initialization function in which to pick the dependencies
    to function The destination initialization function

    autoInject(initializer) ⇒ function

    Decorator creating a new initializer with different dependencies declarations set to it according to the given function signature.

    Kind: global function
    Returns: function - Returns a new initializer

    Param Type Description
    initializer function The original initializer

    Example

    import Knifecycle, { autoInject, name } from 'knifecycle'
    
    new Knifecycle()
      .register(
        name(
          'application',
          autoInject(
            async ({ NODE_ENV, mysql: db }) =>
              async () => db.query('SELECT applicationId FROM applications WHERE environment=?', [NODE_ENV])
            )
          )
        )
      )
    );

    alsoInject(dependencies, initializer) ⇒ function

    Decorator creating a new initializer with some more dependencies declarations appended to it.

    Kind: global function
    Returns: function - Returns a new initializer

    Param Type Description
    dependencies Array.<String> List of dependencies declarations to append
    initializer function The initializer to tweak

    Example

    import Knifecycle, { alsoInject } from 'knifecycle'
    import myServiceInitializer from './service';
    
    new Knifecycle()
    .register(service(
      alsoInject(['ENV'], myServiceInitializer),
      'myService',
    ));

    extra(extraInformations, initializer, [merge]) ⇒ function

    Decorator creating a new initializer with some extra informations appended to it. It is just a way for user to store some additional informations but has no interaction with the Knifecycle internals.

    Kind: global function
    Returns: function - Returns a new initializer

    Param Type Default Description
    extraInformations Object An object containing those extra informations.
    initializer function The initializer to tweak
    [merge] Boolean false Whether the extra object should be merged with the existing one or not

    Example

    import Knifecycle, { extra } from 'knifecycle'
    import myServiceInitializer from './service';
    
    new Knifecycle()
    .register(service(
      extra({ httpHandler: true }, myServiceInitializer),
      'myService',
    ));

    singleton(initializer, [isSingleton]) ⇒ function

    Decorator to set an initializer singleton option.

    Kind: global function
    Returns: function - Returns a new initializer

    Param Type Default Description
    initializer function The initializer to tweak
    [isSingleton] boolean true Define the initializer singleton option (one instance for several runs if true)

    Example

    import Knifecycle, { inject, singleton } from 'knifecycle';
    import myServiceInitializer from './service';
    
    new Knifecycle()
    .register(service(
      inject(['ENV'],
        singleton(myServiceInitializer)
      ),
      'myService',
    ));

    name(name, initializer) ⇒ function

    Decorator to set an initializer name.

    Kind: global function
    Returns: function - Returns a new initializer with that name set

    Param Type Description
    name String The name of the service the initializer resolves to.
    initializer function The initializer to tweak

    Example

    import Knifecycle, { name } from 'knifecycle';
    import myServiceInitializer from './service';
    
    new Knifecycle()
    .register(name('myService', myServiceInitializer));

    autoName(initializer) ⇒ function

    Decorator to set an initializer name from its function name.

    Kind: global function
    Returns: function - Returns a new initializer with that name set

    Param Type Description
    initializer function The initializer to name

    Example

    import Knifecycle, { autoName } from 'knifecycle';
    
    new Knifecycle()
    .register(autoName(async function myService() {}));

    type(type, initializer) ⇒ function

    Decorator to set an initializer type.

    Kind: global function
    Returns: function - Returns a new initializer

    Param Type Description
    type String The type to set to the initializer.
    initializer function The initializer to tweak

    Example

    import Knifecycle, { name, type } from 'knifecycle';
    import myServiceInitializer from './service';
    
    new Knifecycle()
    .register(
      type('service',
        name('myService',
          myServiceInitializer
        )
      )
    );

    initializer(properties, initializer) ⇒ function

    Decorator to set an initializer properties.

    Kind: global function
    Returns: function - Returns a new initializer

    Param Type Description
    properties Object Properties to set to the service.
    initializer function The initializer to tweak

    Example

    import Knifecycle, { initializer } from 'knifecycle';
    import myServiceInitializer from './service';
    
    new Knifecycle()
    .register(initializer({
      name: 'myService',
      type: 'service',
      inject: ['ENV'],
      singleton: true,
    }, myServiceInitializer));

    handler(handlerFunction, [name], [dependencies], [options]) ⇒ function

    Shortcut to create an initializer with a simple handler

    Kind: global function
    Returns: function - Returns a new initializer

    Param Type Default Description
    handlerFunction function The handler function
    [name] String The name of the handler. Default to the DI prop if exists
    [dependencies] Array.<String> [] The dependencies to inject in it
    [options] Object Options attached to the built initializer

    Example

    import Knifecycle, { handler } from 'knifecycle';
    
    new Knifecycle()
    .register(handler(getUser, 'getUser', ['db', '?log']));
    
    const QUERY = `SELECT * FROM users WHERE id=$1`
    async function getUser({ db }, userId) {
      const [row] = await db.query(QUERY, userId);
    
      return row;
    }

    autoHandler(handlerFunction) ⇒ function

    Allows to create an initializer with a simple handler automagically

    Kind: global function
    Returns: function - Returns a new initializer

    Param Type Description
    handlerFunction function The handler function

    Example

    import Knifecycle, { autoHandler } from 'knifecycle';
    
    new Knifecycle()
    .register(autoHandler(getUser));
    
    const QUERY = `SELECT * FROM users WHERE id=$1`
    async function getUser({ db }, userId) {
      const [row] = await db.query(QUERY, userId);
    
      return row;
    }

    parseDependencyDeclaration(dependencyDeclaration) ⇒ Object

    Explode a dependency declaration an returns its parts.

    Kind: global function
    Returns: Object - The various parts of it

    Param Type Description
    dependencyDeclaration String A dependency declaration string

    Example

    parseDependencyDeclaration('pgsql>db');
    // Returns
    {
      serviceName: 'pgsql',
      mappedName: 'db',
      optional: false,
    }

    stringifyDependencyDeclaration(dependencyDeclarationParts) ⇒ String

    Stringify a dependency declaration from its parts.

    Kind: global function
    Returns: String - The various parts of it

    Param Type Description
    dependencyDeclarationParts Object A dependency declaration string

    Example

    stringifyDependencyDeclaration({
      serviceName: 'pgsql',
      mappedName: 'db',
      optional: false,
    });
    
    // Returns
    'pgsql>db'

    unwrapInitializerProperties(initializer) ⇒ function

    Utility function to check and reveal initializer properties.

    Kind: global function
    Returns: function - Returns revealed initializer (with TypeScript types for properties)

    Param Type Description
    initializer function The initializer to tweak

    Authors

    License

    MIT

    Install

    npm i knifecycle

    DownloadsWeekly Downloads

    237

    Version

    11.1.1

    License

    MIT

    Unpacked Size

    1.19 MB

    Total Files

    52

    Last publish

    Collaborators

    • avatar