mirror of
https://github.com/chenasraf/massarg.git
synced 2026-05-18 01:39:05 +00:00
fix: let help flag ignore requirements
This commit is contained in:
@@ -318,13 +318,17 @@ export class MassargCommand<Args extends ArgsObject = ArgsObject> {
|
||||
* To parse the arguments without running any commands and only get the output args,
|
||||
* use `getArgs` instead.
|
||||
*/
|
||||
parse(argv: string[], args?: Partial<Args>, parent?: MassargCommand<Args>): Promise<void> | void {
|
||||
parse(
|
||||
argv = process.argv.slice(2),
|
||||
args?: Partial<Args>,
|
||||
parent?: MassargCommand<Args>,
|
||||
): Promise<void> | void {
|
||||
this.getArgs(argv, args, parent, true)
|
||||
}
|
||||
|
||||
private parseOption(arg: string, argv: string[]) {
|
||||
const prefixes = { ...this.optionPrefixes }
|
||||
const option = this.options.find((o) => o._match(arg, prefixes))
|
||||
const option = this.options.find((o) => o.isMatch(arg, prefixes))
|
||||
if (!option) {
|
||||
throw new ValidationError({
|
||||
path: [MassargOption.findNameInArg(arg, prefixes)],
|
||||
@@ -375,8 +379,9 @@ export class MassargCommand<Args extends ArgsObject = ArgsObject> {
|
||||
// parse options
|
||||
while (_argv.length) {
|
||||
const arg = _argv.shift()!
|
||||
|
||||
// make sure option exists
|
||||
const found = this.options.find((o) => o._isOption(arg, { ...this.optionPrefixes }))
|
||||
const found = this.options.find((o) => o.isMatch(arg, this.optionPrefixes))
|
||||
if (found) {
|
||||
if (this.helpConfig.bindOption && found.name === 'help') {
|
||||
if (parseCommands) {
|
||||
|
||||
@@ -177,7 +177,7 @@ export class MassargOption<OptionType extends any = unknown, Args extends ArgsOb
|
||||
parseDetails(argv: string[], options: ArgsObject, prefixes: Prefixes): ArgvValue<OptionType> {
|
||||
let input = ''
|
||||
try {
|
||||
if (!this._match(argv[0], prefixes)) {
|
||||
if (!this.isMatch(argv[0], prefixes)) {
|
||||
throw new ParseError({
|
||||
path: [this.name],
|
||||
code: 'invalid_option',
|
||||
@@ -207,20 +207,17 @@ export class MassargOption<OptionType extends any = unknown, Args extends ArgsOb
|
||||
return `--${this.name}${aliases} ${this.description}`
|
||||
}
|
||||
|
||||
_match(arg: string, prefixes: Prefixes): boolean {
|
||||
/** Returns true if the flag (including any prefixes) matches the name or aliases */
|
||||
isMatch(arg: string, prefixes: Prefixes): boolean {
|
||||
const name = MassargOption.findNameInArg(arg, prefixes)
|
||||
return name === this.name || this.aliases.includes(name)
|
||||
}
|
||||
|
||||
_isOption(arg: string, prefixes: Prefixes): boolean {
|
||||
return (
|
||||
arg.startsWith(prefixes.optionPrefix) ||
|
||||
arg.startsWith(prefixes.aliasPrefix) ||
|
||||
arg.startsWith(prefixes.negateFlagPrefix) ||
|
||||
arg.startsWith(prefixes.negateAliasPrefix)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the flag, removing any prefixes. It is discriminate of if the option
|
||||
* exists, as it is a static method; it only returns the name of the flag if it matches the
|
||||
* prefixes format.
|
||||
*/
|
||||
static findNameInArg(arg: string, prefixes: Prefixes): string {
|
||||
const { optionPrefix, aliasPrefix, negateFlagPrefix, negateAliasPrefix } = prefixes
|
||||
// negate full prefix
|
||||
@@ -337,7 +334,7 @@ export class MassargFlag extends MassargOption<boolean> {
|
||||
received: JSON.stringify(argv[0]),
|
||||
})
|
||||
}
|
||||
if (!this._match(argv[0], prefixes)) {
|
||||
if (!this.isMatch(argv[0], prefixes)) {
|
||||
throw new ParseError({
|
||||
path: [this.name],
|
||||
code: 'invalid_option',
|
||||
|
||||
20
src/utils.ts
20
src/utils.ts
@@ -91,17 +91,15 @@ export function deepMerge<T1, T2>(obj1: T1, obj2: T2): NonNullable<T1> & NonNull
|
||||
* regular spaced strings.
|
||||
*/
|
||||
export function splitWords(str: string): string[] {
|
||||
return (
|
||||
str
|
||||
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
||||
// .replace(/([a-zA-Z])([0-9])/g, '$1 $2')
|
||||
.replace(/([0-9])([a-zA-Z])/g, '$1 $2')
|
||||
.replace(/([a-z])([_-])/g, '$1 $2')
|
||||
.replace(/([_-])([a-zA-Z])/g, '$1 $2')
|
||||
.split(/[_-]/)
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean)
|
||||
)
|
||||
return str
|
||||
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
||||
.replace(/([a-zA-Z])([0-9])/g, '$1 $2')
|
||||
.replace(/([0-9])([a-zA-Z])/g, '$1 $2')
|
||||
.replace(/([a-z])([_-])/g, '$1 $2')
|
||||
.replace(/([_-])([a-zA-Z])/g, '$1 $2')
|
||||
.split(/[_\- ]/)
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
export function toCamelCase(str: string): string {
|
||||
|
||||
@@ -38,9 +38,10 @@ test('prints help from command', () => {
|
||||
const command = massarg(opts).help({
|
||||
bindCommand: true,
|
||||
})
|
||||
const log = jest.spyOn(console, 'log').mockImplementation(() => { })
|
||||
const log = jest.spyOn(console, 'log').mockImplementation(() => {})
|
||||
command.parse(['help'])
|
||||
expect(log).toHaveBeenCalled()
|
||||
log.mockRestore()
|
||||
})
|
||||
|
||||
test('binds option', () => {
|
||||
@@ -52,12 +53,26 @@ test('binds option', () => {
|
||||
expect(command.options.find((o) => o.name === 'help')).toBeTruthy()
|
||||
})
|
||||
|
||||
test('overrides required options', () => {
|
||||
const command = massarg(opts)
|
||||
.option({
|
||||
name: 'required',
|
||||
aliases: ['r'],
|
||||
description: 'required',
|
||||
required: true,
|
||||
})
|
||||
.help({
|
||||
bindOption: true,
|
||||
})
|
||||
expect(() => command.getArgs(['--help'])).not.toThrow()
|
||||
})
|
||||
|
||||
describe('prints help from option', () => {
|
||||
test('when no main command', () => {
|
||||
const command = massarg(opts).help({
|
||||
bindOption: true,
|
||||
})
|
||||
const log = jest.spyOn(console, 'log').mockImplementation(() => { })
|
||||
const log = jest.spyOn(console, 'log').mockImplementation(() => {})
|
||||
command.parse(['--help'])
|
||||
expect(log).toHaveBeenCalled()
|
||||
})
|
||||
@@ -80,7 +95,7 @@ test('help string', () => {
|
||||
})
|
||||
|
||||
test('print help', () => {
|
||||
const log = jest.spyOn(console, 'log').mockImplementation(() => { })
|
||||
const log = jest.spyOn(console, 'log').mockImplementation(() => {})
|
||||
const command = massarg(opts)
|
||||
command.printHelp()
|
||||
expect(log).toHaveBeenCalled()
|
||||
|
||||
14
test/utils.test.ts
Normal file
14
test/utils.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { toCamelCase } from '../src/utils'
|
||||
|
||||
describe('toCamelCase', () => {
|
||||
test('works', () => {
|
||||
expect(toCamelCase('foo')).toBe('foo')
|
||||
expect(toCamelCase('foo-bar')).toBe('fooBar')
|
||||
expect(toCamelCase('foo-bar baz')).toBe('fooBarBaz')
|
||||
expect(toCamelCase('foo-bar baz-qux')).toBe('fooBarBazQux')
|
||||
|
||||
expect(toCamelCase('foo123')).toBe('foo123')
|
||||
expect(toCamelCase('foo-123')).toBe('foo123')
|
||||
expect(toCamelCase('foo-123 bar')).toBe('foo123Bar')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user