Middlewares

Middlewares are simple functions which will be executed during the lifecyle of command flow. With this, you will be able to add new functionallity, tweak and change the entire behaviour of the command at any point of the flow.

Overview

Middlewares are simple objects with hook point property and run method. Based on the hook type, the run method will have specific argument values.

export default {
  on: "START",
  run: data => {
    console.log("running on start..");
    return data;
  },
};

What you can do with middlewares?

  • Async operations
  • Programatically run command
  • Change command
  • Change args and flags
  • Terminate the flow
  • Intercept and change the output
  • Modify running command competely
  • Print additional info at any stages
  • Capture and send logs to other services
  • Include data in command context data
  • And much more..

Create middleware

Middlewares are simple objects with hook point property and run function. Based on the hook, the run method will have specific context values.

export default {
  on: "START",
  run: context => {
    console.log("running on start..");
    return context;
  },
};

Middleware should return the input data to continue the flow.

Async middleware

By default middlewares are synchronous. But it supports async operations like resolving Promises and setTimeout.

export default {
  on: "INIT",
  run: async ctx => {
    return Promise(res => {
      ctx.newProp = "some value";
      res(ctx);
    });
  },
};

Add middleware

Add the middleware file in the index file, similar to commands.

const middlewares = [`${__dirname}/middlewares/start.js`];
const commands = [...];

export { commands, middlewares };

Middleware should return the input data to continue the flow.

Hook points

  • INIT
  • START
  • PRE_VALIDATE
  • POST_VALIDATE
  • PRE_PARSE
  • POST_PARSE
  • PRE_RUN
  • END

Hooks and context

For all of the hook points, config and root properties will be available in the context data. Otherwise, the context data will differ for each hooks.

If you want to use any third party module, require it inside run method

@init

It is plugged before loading commands and plugins. At this point you get complete access to lesyCore object. This is usefull if you want to alter or change the core behaviour.

@start

This will run after loading all commands and plugins. The run context will have all commands.

export default {
  on: "START",
  run: ctx => {
    console.log(ctx.cmds);
    return ctx;
  },
};

@pre_parse

This will run before parsing raw argv input. At this point you can change argv values to direct to different command.

export default {
  on: "PRE_PARSE",
  run: ctx => {
    // ctx.argv    - raw input argv values
    // ctx.root    - root path
    // ctx.config  - config object
    // ctx.utils   - colors() and spinner() object
    // ctx.feature - all features
    // ctx.request - oject of dynamic actions
    return ctx;
  },
};

@post_parse

Run after parsing raw argv values.

export default {
  on: "PRE_PARSE",
  run: ctx => {
    // ctx.argv    - raw input argv values
    // ctx.root    - root path
    // ctx.config  - config object
    // ctx.utils   - colors() and spinner() object
    // ctx.feature - all features
    // ctx.request - oject of dynamic actions

    // ctx.args    - resolved args
    // ctx.flags   -  resolved flags
    return ctx;
  },
};

@pre_validate

Once lesy found the right command to execute, it will pass the command object to pre_validate hook. At this point, the command object can be modified or validated by any middlewares.

export default {
  on: "PRE_VALIDATE",
  run: ctx => {
    console.log(ctx);
    return ctx;
  },
};

It would have,

{
	command:{
		id: 2,
		name: 'hello',
		args: { name: {} },
		flags: {},
		aliases: [ 'hello' ],
		main: null,
		group: 'Commands',
		description: '',
		isVisible: true,
		run: [Function: run],
		src: '/path/to/src/commands/hello.command.ts'
	},
	values: { name: 'john' },
	args: [ 'john' ]
}

@post_validate

This runs after lesy runs validation. If validation fails, process will exit and the flow will be terminated. In such cases this wont run. Run context is same as pre_validate

@pre_run

After validation passes, pre_run will be executed will all the necessary info about the command and essestial utilities.

export default {
  on: "PRE_RUN",
  run: ctx => {
    // ctx.argv    - raw input argv values
    // ctx.root    - root path
    // ctx.config  - config object
    // ctx.utils   - colors() and spinner() object
    // ctx.feature - all features
    // ctx.request - oject of dynamic actions
    // ctx.args    - resolved args
    // ctx.flags   -  resolved flags
    // ctx.rest    -  unknown args
    return ctx;
  },
};

@end

This hook will run at the end of the command flow.

export default {
  on: "END",
  run: ctx => {
    console.log("Command ran successfully!");
    return ctx;
  },
};

Example

Gotcha

Usages

  • Used in help plugin, to send all commands info as a context data. so that you can create your own help command with the data

  • Used in artist plugin, to run a render function instead of run function in command.