Skip to content
This repository has been archived by the owner on Aug 22, 2023. It is now read-only.

Commit

Permalink
Load plugin relative to lib or src directory based on pjson configura…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
chadian committed Apr 10, 2020
1 parent 4a7dabb commit 98f160b
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 70 deletions.
11 changes: 3 additions & 8 deletions src/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {HelpBase} from '@oclif/plugin-help'
import {format, inspect} from 'util'

import * as flags from './flags'
import {sortBy, uniqBy, getHelpPluginPackage} from './util'
import {sortBy, uniqBy, getHelpPlugin} from './util'

/**
* swallows stdout epipe errors
Expand Down Expand Up @@ -185,14 +185,9 @@ export default abstract class Command {
}
}

protected _helpPlugin() {
return getHelpPluginPackage(this.config.pjson)
}

protected _help() {
const helpPlugin = this._helpPlugin()
const HHelp = require(helpPlugin).default
const help: HelpBase = new HHelp(this.config)
const HelpPlugin = getHelpPlugin(this.config)
const help: HelpBase = new HelpPlugin(this.config)
const cmd = Config.Command.toCached(this.ctor as any as Config.Command.Class)
if (!cmd.id) cmd.id = ''
let topics = this.config.topics
Expand Down
6 changes: 3 additions & 3 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as Config from '@oclif/config'
import {HelpBase} from '@oclif/plugin-help'

import {Command} from '.'
import {getHelpPlugin} from './util'

export class Main extends Command {
static run(argv = process.argv.slice(2), options?: Config.LoadOptions) {
Expand Down Expand Up @@ -36,9 +37,8 @@ export class Main extends Command {
}

protected _help() {
const helpPlugin = this._helpPlugin()
const HHelp = require(helpPlugin).default
const help: HelpBase = new HHelp(this.config)
const HelpPlugin = getHelpPlugin(this.config)
const help: HelpBase = new HelpPlugin(this.config)
help.showHelp(this.argv)
return this.exit(0)
}
Expand Down
41 changes: 29 additions & 12 deletions src/util.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {Config} from '@oclif/config'
import {IConfig} from '@oclif/config'
import {tsPath} from '@oclif/config/lib/ts-node'
import {HelpBase} from '@oclif/plugin-help'

export function compact<T>(a: (T | undefined)[]): T[] {
return a.filter((a): a is T => Boolean(a))
Expand Down Expand Up @@ -34,21 +36,36 @@ export function sortBy<T>(arr: T[], fn: (i: T) => sort.Types | sort.Types[]): T[
return arr.sort((a, b) => compare(fn(a), fn(b)))
}

export function getHelpPluginPackage(pjson: Config['pjson'], defaultPlugin = '@oclif/plugin-help'): string {
const configuredPlugin = pjson.oclif.helpPlugin
interface HelpBaseDerived {
new(config: IConfig): HelpBase;
}

export function extractPlugin(config: IConfig, pluginPath: string): HelpBaseDerived {
const helpPlugin = tsPath(config.root, pluginPath)
return require(helpPlugin) as HelpBaseDerived
}

export function extractExport(exported: any): HelpBaseDerived {
return exported && exported.default ? exported.default : exported
}

export function getHelpPlugin(config: IConfig, defaultPlugin = '@oclif/plugin-help'): HelpBaseDerived {
const pjson = config.pjson
const configuredPlugin = pjson && pjson.oclif && pjson.oclif.helpPlugin

if (configuredPlugin) {
try {
require(configuredPlugin)
return configuredPlugin
} catch {}
const exported = extractPlugin(config, configuredPlugin)
return extractExport(exported) as HelpBaseDerived
} catch (error) {
throw new Error(`Unable to load configured help plugin "${configuredPlugin}" from package.json, failed with message:\n${error.message}`)
}
}

try {
require(defaultPlugin)
return defaultPlugin
} catch {}

if (configuredPlugin) throw new Error(`Unable to load configured help plugin "${configuredPlugin}" from package.json`)
throw new Error('Could not load a help plugin, consider installing the @oclif/plugin-help package')
const exported = require(defaultPlugin)
return extractExport(exported) as HelpBaseDerived
} catch (error) {
throw new Error(`Could not load a help plugin, consider installing the @oclif/plugin-help package, failed with message:\n${error.message}`)
}
}
80 changes: 62 additions & 18 deletions test/command.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import * as Config from '@oclif/config'
import {expect, fancy} from 'fancy-test'

import Base, {flags} from '../src'
import {TestHelpPluginConfig} from './helpers/test-help-plugin'
import {getHelpPluginPackage} from '../src/util'
import {TestHelpPluginConfig} from './helpers/test-help-in-src/src/test-help-plugin'
import * as Util from '../src/util'

const originalGetHelpPlugin = Util.getHelpPlugin

// const pjson = require('../package.json')

Expand Down Expand Up @@ -280,19 +282,17 @@ USAGE
.do(async ({config}) => {
class CMD extends Command {
config = config

_helpPlugin() {
return getHelpPluginPackage(this.config.pjson, '')
}
}

await CMD.run(['-h'])
})
.catch((error: Error) => expect(error.message).to.equal('Unable to load configured help plugin "plugin-does-not-exist" from package.json'))
.catch((error: Error) => expect(error.message).to.contain('Unable to load configured help plugin "plugin-does-not-exist" from package.json, failed with message:\n'))
.it('shows useful error message when configured help plugin cannot be loaded')

fancy
.stdout()
.stub(Util, 'getHelpPlugin', function (config: any) {
return originalGetHelpPlugin(config, '')
})
.add('config', async () => {
const config: TestHelpPluginConfig = await Config.load()
config.pjson.oclif.helpPlugin = undefined
Expand All @@ -301,23 +301,26 @@ USAGE
.do(async ({config}) => {
class CMD extends Command {
config = config

_helpPlugin() {
return getHelpPluginPackage(this.config.pjson, '')
}
}

await CMD.run(['-h'])
})
.catch((error: Error) => expect(error.message).to.equal('Could not load a help plugin, consider installing the @oclif/plugin-help package'))
.catch((error: Error) => expect(error.message).to.contain('Could not load a help plugin, consider installing the @oclif/plugin-help package, failed with message:\n'))
.it('shows useful error message when no help plugin has been configured and the default cannot be loaded')

describe('from a help plugin', () => {
fancy
.stdout()
.stub(Util, 'getHelpPlugin', function (config: Config.IConfig) {
const patchedConfig = {
...config,
root: `${__dirname}/helpers/test-help-in-lib/`,
}

return originalGetHelpPlugin(patchedConfig)
})
.add('config', async () => {
const config: TestHelpPluginConfig = await Config.load()
config.pjson.oclif.helpPlugin = `${__dirname}/helpers/test-help-plugin`
config.pjson.oclif.helpPlugin = './lib/test-help-plugin'
return config
})
.do(async ({config}) => {
Expand All @@ -329,7 +332,40 @@ USAGE
await CMD.run(['-h'])
})
.catch(/EEXIT: 0/)
.it('-h', ctx => {
.it('-h via a plugin in lib dir (compiled to js)', ctx => {
expect(ctx.stdout).to.equal('hello from test-help-plugin #showCommandHelp in the lib folder and in compiled javascript\n')
expect(ctx.config.showCommandHelpSpy!.getCalls().length).to.equal(1)
expect(ctx.config.showHelpSpy!.getCalls().length).to.equal(0)
const [Command, Topics] = ctx.config.showCommandHelpSpy!.firstCall.args
expect(Command.id).to.deep.equal('test-command-for-help-plugin')
expect(Topics).to.be.an('array')
})

fancy
.stdout()
.stub(Util, 'getHelpPlugin', function (config: Config.IConfig) {
const patchedConfig = {
...config,
root: `${__dirname}/helpers/test-help-in-src/`,
}

return originalGetHelpPlugin(patchedConfig)
})
.add('config', async () => {
const config: TestHelpPluginConfig = await Config.load()
config.pjson.oclif.helpPlugin = './lib/test-help-plugin'
return config
})
.do(async ({config}) => {
class CMD extends Command {
static id = 'test-command-for-help-plugin'

config = config
}
await CMD.run(['-h'])
})
.catch(/EEXIT: 0/)
.it('-h via a plugin in src dir (source in ts)', ctx => {
expect(ctx.stdout).to.equal('hello from test-help-plugin #showCommandHelp\n')
expect(ctx.config.showCommandHelpSpy!.getCalls().length).to.equal(1)
expect(ctx.config.showHelpSpy!.getCalls().length).to.equal(0)
Expand All @@ -340,9 +376,17 @@ USAGE

fancy
.stdout()
.stub(Util, 'getHelpPlugin', function (config: Config.IConfig) {
const patchedConfig = {
...config,
root: `${__dirname}/helpers/test-help-in-src/`,
}

return originalGetHelpPlugin(patchedConfig)
})
.add('config', async () => {
const config: TestHelpPluginConfig = await Config.load()
config.pjson.oclif.helpPlugin = `${__dirname}/helpers/test-help-plugin`
config.pjson.oclif.helpPlugin = './lib/test-help-plugin'
return config
})
.do(async ({config}) => {
Expand All @@ -356,7 +400,7 @@ USAGE
return CMD.run(['--help'])
})
.catch(/EEXIT: 0/)
.it('--help', ctx => {
.it('--help via a plugin in src dir (source in ts)', ctx => {
expect(ctx.stdout).to.equal('hello from test-help-plugin #showCommandHelp\n')
expect(ctx.config.showCommandHelpSpy!.getCalls().length).to.equal(1)
expect(ctx.config.showHelpSpy!.getCalls().length).to.equal(0)
Expand Down
20 changes: 20 additions & 0 deletions test/helpers/test-help-in-lib/lib/test-help-plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* eslint-disable */
'use strict';
Object.defineProperty (exports, '__esModule', {value: true});
const sinon_1 = require ('sinon');
class default_1 {
constructor (config, opts) {
this.showCommandHelp = sinon_1.spy (() => {
console.log ('hello from test-help-plugin #showCommandHelp in the lib folder and in compiled javascript');
});
this.showHelp = sinon_1.spy (() => {
console.log ('hello showHelp');
});
config.showCommandHelpSpy = this.showCommandHelp;
config.showHelpSpy = this.showHelp;
}
command () {
throw new Error ('not needed for testing @oclif/command');
}
}
exports.default = default_1;
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ export default class extends HelpBase {
showHelp = spy(() => {
console.log('hello showHelp')
})

getCommandHelpForReadme(): string {
throw new Error('not needed for testing @oclif/command')
}
}
6 changes: 6 additions & 0 deletions test/helpers/test-help-in-src/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"compilerOptions": {
"rootDir": "./src",
"outDir": "./lib"
}
}
84 changes: 55 additions & 29 deletions test/main.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import {expect, fancy} from 'fancy-test'

import {Main} from '../src/main'
import {TestHelpPluginConfig} from './helpers/test-help-plugin'
import * as Config from '@oclif/config'
import * as Util from '../src/util'
import * as Config from '@oclif/config'
import {TestHelpPluginConfig} from './helpers/test-help-in-src/src/test-help-plugin'

const pjson = require('../package.json')
const version = `@oclif/command/${pjson.version} ${process.platform}-${process.arch} node-${process.version}`
const originalGetHelpPlugin = Util.getHelpPlugin

describe('main', () => {
fancy
Expand Down Expand Up @@ -39,38 +41,62 @@ COMMANDS
`))
.it('runs -h')
})

describe('with an alternative help plugin', async () => {
const getMainWithHelpPlugin = async () => {
const config: TestHelpPluginConfig = await Config.load()
config.pjson.oclif.helpPlugin = `${__dirname}/helpers/test-help-plugin`
describe('with an alternative help plugin', async () => {
const getMainWithHelpPlugin = async () => {
const config: TestHelpPluginConfig = await Config.load()
config.pjson.oclif.helpPlugin = './lib/test-help-plugin'

class MainWithHelpPlugin extends Main {
config = config
}

class MainWithHelpPlugin extends Main {
config = config
return MainWithHelpPlugin
}

return MainWithHelpPlugin
}
fancy
.stdout()
.stub(Util, 'getHelpPlugin', function (config: Config.IConfig) {
const patchedConfig = {
...config,
root: `${__dirname}/helpers/test-help-in-src/`,
}

fancy
.stdout()
.do(async () => (await getMainWithHelpPlugin()).run(['-h']))
.catch('EEXIT: 0')
.do(output => expect(output.stdout).to.equal('hello showHelp\n'))
.it('works with -h')
return originalGetHelpPlugin(patchedConfig)
})
.do(async () => (await getMainWithHelpPlugin()).run(['-h']))
.catch('EEXIT: 0')
.do(output => expect(output.stdout).to.equal('hello showHelp\n'))
.it('works with -h')

fancy
.stdout()
.do(async () => (await getMainWithHelpPlugin()).run(['--help']))
.catch('EEXIT: 0')
.do(output => expect(output.stdout).to.equal('hello showHelp\n'))
.it('works with --help')
fancy
.stdout()
.stub(Util, 'getHelpPlugin', function (config: Config.IConfig) {
const patchedConfig = {
...config,
root: `${__dirname}/helpers/test-help-in-src/`,
}

fancy
.stdout()
.do(async () => (await getMainWithHelpPlugin()).run(['help']))
.catch('EEXIT: 0')
.do(output => expect(output.stdout).to.equal('hello showHelp\n'))
.it('works with help')
return originalGetHelpPlugin(patchedConfig)
})
.do(async () => (await getMainWithHelpPlugin()).run(['--help']))
.catch('EEXIT: 0')
.do(output => expect(output.stdout).to.equal('hello showHelp\n'))
.it('works with --help')

fancy
.stdout()
.stub(Util, 'getHelpPlugin', function (config: Config.IConfig) {
const patchedConfig = {
...config,
root: `${__dirname}/helpers/test-help-in-src/`,
}

return originalGetHelpPlugin(patchedConfig)
})
.do(async () => (await getMainWithHelpPlugin()).run(['help']))
.catch('EEXIT: 0')
.do(output => expect(output.stdout).to.equal('hello showHelp\n'))
.it('works with help')
})
})

0 comments on commit 98f160b

Please sign in to comment.