diff --git a/src/config.ts b/src/config.ts index 74609001..56148cfc 100644 --- a/src/config.ts +++ b/src/config.ts @@ -3,6 +3,7 @@ import * as os from 'os' import * as path from 'path' import * as readPkg from 'read-pkg' +import {Hooks} from './hooks' import {PJSON} from './pjson' import * as Plugin from './plugin' @@ -147,15 +148,17 @@ export class Config extends Plugin.Plugin implements IConfig { debug('config done') } - async runHook(event: string, opts?: T) { + async runHook(event: K, opts: T[K]) { debug('start %s hook', event) - await super.runHook(event, {...opts || {}, config: this}) + await super.runHook(event, {...opts || {} as any, config: this}) debug('done %s hook', event) } async runCommand(id: string, argv: string[] = []) { + await this.runHook('init', {id}) debug('runCommand %s %o', id, argv) const cmd = this.findCommand(id, {must: true}).load() + await this.runHook('prerun', {Command: cmd, argv}) await cmd.run(argv, this) } diff --git a/src/hooks.ts b/src/hooks.ts index 53c72676..9661abc4 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -2,15 +2,15 @@ import * as Config from '.' export interface Hooks { init: {id: string} + prerun: { + Command: Config.Command.Class + argv: string[] + } update: {} 'command_not_found': {id: string}, 'plugins:parse': { pjson: Config.IPlugin } - prerun: { - Command: Config.Command.Class - argv: string[] - } } export type Hook = (options: Hooks[K] & {config: Config.IConfig}) => any diff --git a/src/plugin.ts b/src/plugin.ts index fdad92a0..5ab9a48c 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -7,11 +7,11 @@ import * as readPkg from 'read-pkg' import {inspect} from 'util' import {Command} from './command' +import {Hooks} from './hooks' import {Manifest} from './manifest' import {PJSON} from './pjson' import {Topic} from './topic' import {tsPath} from './ts_node' -import {undefault} from './util' export interface Options { root: string @@ -72,7 +72,7 @@ export interface IPlugin { findCommand(id: string, opts?: {must: boolean}): Command.Plugin | undefined findTopic(id: string, opts: {must: true}): Topic findTopic(id: string, opts?: {must: boolean}): Topic | undefined - runHook(event: string, opts?: T): Promise + runHook(event: K, opts: T[K]): Promise } const debug = require('debug')('@anycli/config') @@ -168,6 +168,7 @@ export class Plugin implements IPlugin { _findCommand(id: string): Command.Class { const search = (cmd: any) => { if (_.isFunction(cmd.run)) return cmd + if (cmd.default && cmd.default.run) return cmd.default return Object.values(cmd).find((cmd: any) => _.isFunction(cmd.run)) } const p = require.resolve(path.join(this.commandsDir!, ...id.split(':'))) @@ -189,13 +190,19 @@ export class Plugin implements IPlugin { if (opts.must) throw new Error(`topic ${name} not found`) } - async runHook(event: string, opts?: T) { + async runHook(event: K, opts: T[K]) { const promises = (this.hooks[event] || []) .map(async hook => { try { const p = tsPath(this.root, hook) debug('hook', event, p) - await undefault(require(p))(opts) + const search = (m: any) => { + if (_.isFunction(m)) return m + if (m.default && _.isFunction(m.default)) return m.default + return Object.values(m).find((m: any) => _.isFunction(m)) + } + + await search(require(p))(opts) } catch (err) { if (err.code === 'EEXIT') throw err cli.warn(err) diff --git a/src/util.ts b/src/util.ts deleted file mode 100644 index c00c7014..00000000 --- a/src/util.ts +++ /dev/null @@ -1,9 +0,0 @@ -export interface IESModule { - __esModule: true - default: T -} - -export function undefault(obj: T | IESModule): T { - if ((obj as any).__esModule === true) return (obj as any).default - return obj as any -} diff --git a/test/fixtures/typescript/package.json b/test/fixtures/typescript/package.json index 9eaccc34..e9d298c3 100644 --- a/test/fixtures/typescript/package.json +++ b/test/fixtures/typescript/package.json @@ -4,7 +4,8 @@ "anycli": { "commands": "./lib/commands", "hooks": { - "init": "./lib/hooks/init" + "init": "./lib/hooks/init", + "prerun": ["./lib/hooks/prerun"] } } } diff --git a/test/fixtures/typescript/src/hooks/init.ts b/test/fixtures/typescript/src/hooks/init.ts new file mode 100644 index 00000000..541b97a2 --- /dev/null +++ b/test/fixtures/typescript/src/hooks/init.ts @@ -0,0 +1,3 @@ +export function init() { + console.log('running ts init hook') +} diff --git a/test/fixtures/typescript/src/hooks/prerun.ts b/test/fixtures/typescript/src/hooks/prerun.ts new file mode 100644 index 00000000..60afddd3 --- /dev/null +++ b/test/fixtures/typescript/src/hooks/prerun.ts @@ -0,0 +1,3 @@ +export default function prerun() { + console.log('running ts prerun hook') +} diff --git a/test/typescript.test.ts b/test/typescript.test.ts index 2ca5b292..5dca3377 100644 --- a/test/typescript.test.ts +++ b/test/typescript.test.ts @@ -1,8 +1,9 @@ -import {expect, fancy} from 'fancy-test' import * as path from 'path' import * as Config from '../src' +import {expect, fancy} from './test' + const root = path.resolve(__dirname, 'fixtures/typescript') const p = (p: string) => path.join(root, p) @@ -19,8 +20,8 @@ describe('typescript', () => { withConfig .stdout() - .it('runs ts command', async ctx => { - ctx.config.runCommand('foo:bar:baz') - expect(ctx.stdout).to.equal('it works!\n') + .it('runs ts command init, and prerun hooks', async ctx => { + await ctx.config.runCommand('foo:bar:baz') + expect(ctx.stdout).to.equal('running ts init hook\nrunning ts prerun hook\nit works!\n') }) })