diff --git a/src/options.ts b/src/options.ts index a5ffcc9..03cbe35 100644 --- a/src/options.ts +++ b/src/options.ts @@ -1,4 +1,4 @@ -import { join } from 'path'; +import { join, resolve } from 'path'; import { readdir } from 'fs'; import { IActionSetup } from './action'; @@ -23,47 +23,49 @@ export interface IOptionParams { export class Options { setup: IActionSetup; path: string; + args: string[]; constructor (path: string, setup: IActionSetup) { this.path = join(path, 'options'); this.setup = setup; + this.args = process.argv; } - getParams (params: IOptionParam[], start: number) { + getParams (params: IOptionParam[]) { let final: IOptionParams = {}; params.forEach((param, idx) => { let name = param.name; - let value = process.argv.splice(start + idx, 1)[0]; + let value = this.args.shift(); - final[name] = value; + if (value) final[name] = value; }); return final; } - parseOptions () { - process.argv.forEach((arg, idx) => { - let match = arg.match(OPTION_REGEX); - if (!match) return; + parseOptions (): IActionSetup { + if (!this.args.length) return this.setup; + let match = this.args[0].match(OPTION_REGEX); + this.args.shift(); + + if (match) { let opt = match[1]; this.setup.flags.push(opt); - process.argv.splice(idx, 1); - let option = this.getOption(opt); - let params = this.getParams(option.params, idx); + let params = this.getParams(option.params); this.setup = option.run(params); - }); + } - return this.setup; + return this.parseOptions(); } getOption (opt: string): Option { let module_exists: boolean; - let file = join(this.path, opt + '.js'); + let file = resolve(join(this.path, opt + '.js')); try { require.resolve(file); diff --git a/src/spec/options.spec.ts b/src/spec/options.spec.ts new file mode 100644 index 0000000..77344e8 --- /dev/null +++ b/src/spec/options.spec.ts @@ -0,0 +1,102 @@ +import * as options from '../options'; +import * as action from '../action'; +import TestOption from './test-action/options/test'; + +describe('the options module', () => { + let test_action: string; + let setup: action.IActionSetup; + + beforeEach(() => { + test_action = './built/spec/test-action'; + setup = { + flags: [] + }; + }); + + describe('the parseOptions function', () => { + let option: options.Option; + let runSpy: jasmine.Spy; + let getOptionSpy: jasmine.Spy; + let _options: options.Options; + + beforeEach(() => { + option = new options.Option(setup); + option.params = [ + { name: 'firstParam', description: 'First Param' }, + { name: 'secondParam', description: 'Second Param' } + ] + + runSpy = spyOn(options.Option.prototype, 'run').and.returnValue(setup); + _options = new options.Options(test_action, setup); + + getOptionSpy = spyOn(_options, 'getOption').and.returnValue(option); + }); + + it('should ignore non-options args', () => { + let _options = new options.Options(test_action, setup); + _options.args = ['arg1', 'arg2']; + + let new_setup = _options.parseOptions(); + + expect(new_setup.flags).toEqual([]); + }); + + it('adds all options to the setup.flags', () => { + let _options = new options.Options(test_action, setup); + _options.args = ['--option1', '--option2']; + + let new_setup = _options.parseOptions(); + + expect(new_setup.flags).toEqual(['option1', 'option2']); + }); + + it('sends params to the run function', () => { + _options.args = ['--option1', 'param1', 'param2']; + _options.parseOptions(); + + expect(runSpy).toHaveBeenCalledWith({ + firstParam: 'param1', + secondParam: 'param2' + }); + }); + + it('should only pass the first param', () => { + _options.args = ['--option1', 'param1']; + _options.parseOptions(); + + expect(runSpy).toHaveBeenCalledWith({ + firstParam: 'param1', + }); + }); + }); + + describe('the getOption method', () => { + it('should return the default option class if no file is found', () => { + let _options = new options.Options(test_action, setup); + + let option = _options.getOption('fake-file'); + + expect(option.params.length).toEqual(0); + }); + + it('should load an options file if it exists', () => { + let _options = new options.Options(test_action, setup); + + let option = _options.getOption('test'); + let testOption = new TestOption(setup); + + expect(option.params.length).toEqual(2); + }); + }); + + describe('the Option class', () => { + describe('the run method', () => { + it('should return the setup passed in', () => { + let option = new options.Option(setup); + let new_setup = option.run({}); + + expect(new_setup).toEqual(setup); + }); + }); + }); +}); diff --git a/src/spec/test-action/options/test.ts b/src/spec/test-action/options/test.ts new file mode 100644 index 0000000..8c96fa1 --- /dev/null +++ b/src/spec/test-action/options/test.ts @@ -0,0 +1,17 @@ +import { Option, IOptionParams } from '../../../options' +import { IActionSetup } from '../../../action'; + +export default class TestOption extends Option { + constructor (setup: IActionSetup) { + super(setup); + + this.params = [ + { name: 'firstParam', description: 'First Param' }, + { name: 'secondParam', description: 'Second Param' } + ]; + } + + run (params: IOptionParams): IActionSetup { + return this.setup; + } +} \ No newline at end of file