mirror of
https://github.com/chenasraf/massarg.git
synced 2026-05-18 01:39:05 +00:00
fix: type inferences
This commit is contained in:
@@ -47,7 +47,7 @@ export type CommandConfig<RunArgs extends ArgsObject = ArgsObject> = z.infer<
|
||||
ReturnType<typeof CommandConfig<RunArgs>>
|
||||
>
|
||||
|
||||
export type ArgsObject = object
|
||||
export type ArgsObject = Record<string | number | symbol, any>
|
||||
|
||||
export type Runner<Args extends ArgsObject> = (
|
||||
options: Args,
|
||||
@@ -73,7 +73,9 @@ export type Runner<Args extends ArgsObject> = (
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export class MassargCommand<Args extends ArgsObject = ArgsObject> {
|
||||
export class MassargCommand<Args extends ArgsObject = ArgsObject>
|
||||
implements Omit<CommandConfig<Args>, 'run'>
|
||||
{
|
||||
name: string
|
||||
description: string
|
||||
aliases: string[]
|
||||
@@ -141,11 +143,11 @@ export class MassargCommand<Args extends ArgsObject = ArgsObject> {
|
||||
* While options are not inherited, they will be passed from any parent commands
|
||||
* to the sub-command when invoked.
|
||||
*/
|
||||
command<A extends ArgsObject = Args>(config: CommandConfig<A>): MassargCommand<Args>
|
||||
command<A extends ArgsObject = Args>(config: MassargCommand<A>): MassargCommand<Args>
|
||||
command<A extends ArgsObject = Args>(config: CommandConfig<A>): MassargCommand<Args & A>
|
||||
command<A extends ArgsObject = Args>(config: MassargCommand<A>): MassargCommand<Args & A>
|
||||
command<A extends ArgsObject = Args>(
|
||||
config: CommandConfig<A> | MassargCommand<A>,
|
||||
): MassargCommand<Args> {
|
||||
): MassargCommand<Args & A> {
|
||||
try {
|
||||
const command = config instanceof MassargCommand ? config : new MassargCommand(config)
|
||||
const existing = this.commands.find((c) => c.name === command.name)
|
||||
@@ -158,15 +160,16 @@ export class MassargCommand<Args extends ArgsObject = ArgsObject> {
|
||||
}
|
||||
command.parent = this
|
||||
this.commands.push(command)
|
||||
return this
|
||||
return this as unknown as MassargCommand<Args & A>
|
||||
} catch (e) {
|
||||
if (isZodError(e)) {
|
||||
throw new ValidationError({
|
||||
e = new ValidationError({
|
||||
path: [this.name, config.name, ...e.issues[0].path.map((p) => p.toString())],
|
||||
code: e.issues[0].code,
|
||||
message: e.issues[0].message,
|
||||
})
|
||||
}
|
||||
this.printError(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
@@ -192,12 +195,13 @@ export class MassargCommand<Args extends ArgsObject = ArgsObject> {
|
||||
return this
|
||||
} catch (e) {
|
||||
if (isZodError(e)) {
|
||||
throw new ValidationError({
|
||||
e = new ValidationError({
|
||||
path: [this.name, config.name, ...e.issues[0].path.map((p) => p.toString())],
|
||||
code: e.issues[0].code,
|
||||
message: e.issues[0].message,
|
||||
})
|
||||
}
|
||||
this.printError(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
@@ -233,12 +237,13 @@ export class MassargCommand<Args extends ArgsObject = ArgsObject> {
|
||||
return this
|
||||
} catch (e) {
|
||||
if (isZodError(e)) {
|
||||
throw new ValidationError({
|
||||
e = new ValidationError({
|
||||
path: [this.name, config.name, ...e.issues[0].path.map((p) => p.toString())],
|
||||
code: e.issues[0].code,
|
||||
message: e.issues[0].message,
|
||||
})
|
||||
}
|
||||
this.printError(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
@@ -307,14 +312,14 @@ export class MassargCommand<Args extends ArgsObject = ArgsObject> {
|
||||
*/
|
||||
help(config: HelpConfig): MassargCommand<Args> {
|
||||
this._helpConfig = HelpConfig.parse(config)
|
||||
|
||||
let ret: MassargCommand<any> = this
|
||||
if (this.helpConfig.bindCommand) {
|
||||
this.command(new MassargHelpCommand())
|
||||
ret = ret.command(new MassargHelpCommand())
|
||||
}
|
||||
if (this.helpConfig.bindOption) {
|
||||
this.option(new MassargHelpFlag())
|
||||
ret = ret.option(new MassargHelpFlag())
|
||||
}
|
||||
return this
|
||||
return this as MassargCommand<Args>
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -343,11 +348,15 @@ export class MassargCommand<Args extends ArgsObject = ArgsObject> {
|
||||
try {
|
||||
this.getArgs(argv, args, parent, true)
|
||||
} catch (e) {
|
||||
const message = getErrorMessage(e)
|
||||
console.error(format(message, { color: 'red' }))
|
||||
this.printError(e)
|
||||
}
|
||||
}
|
||||
|
||||
private printError(e: unknown) {
|
||||
const message = getErrorMessage(e)
|
||||
console.error(format(message, { color: 'red' }))
|
||||
}
|
||||
|
||||
private parseOption(arg: string, argv: string[]) {
|
||||
const prefixes = { ...this.optionPrefixes }
|
||||
const option = this.options.find((o) => o.isMatch(arg, prefixes))
|
||||
|
||||
@@ -136,7 +136,9 @@ export type ArgvValue<T> = { argv: string[]; value: T; key: string }
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export class MassargOption<OptionType extends any = unknown, Args extends ArgsObject = ArgsObject> {
|
||||
export class MassargOption<OptionType extends any = unknown, Args extends ArgsObject = ArgsObject>
|
||||
implements OptionConfig<OptionType, Args>
|
||||
{
|
||||
name: string
|
||||
description: string
|
||||
defaultValue?: OptionType
|
||||
|
||||
@@ -3,7 +3,7 @@ import { MassargCommand } from './command'
|
||||
import { ParseError } from './error'
|
||||
|
||||
type A = { test: boolean }
|
||||
const echoCmd = massarg<any>({
|
||||
const echoCmd = massarg<{}>({
|
||||
name: 'echo',
|
||||
description: 'Echo back the arguments',
|
||||
aliases: ['e'],
|
||||
@@ -88,7 +88,6 @@ const main = massarg<A>({
|
||||
.main((opts, parser) => {
|
||||
console.log('Main command - printing all opts')
|
||||
console.log(opts, '\n')
|
||||
parser.printHelp()
|
||||
})
|
||||
.command(echoCmd)
|
||||
.command(addCmd)
|
||||
|
||||
@@ -18,13 +18,16 @@ describe('sub command', () => {
|
||||
)
|
||||
})
|
||||
test('add duplicate', () => {
|
||||
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
|
||||
expect(() =>
|
||||
massarg(opts)
|
||||
.command({ name: 'test2', description: 'test2', run: jest.fn() })
|
||||
.command({ name: 'test2', description: 'test2', run: jest.fn() }),
|
||||
).toThrow('Command "test2" already exists')
|
||||
error.mockRestore()
|
||||
})
|
||||
test('validate', () => {
|
||||
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
|
||||
expect(() =>
|
||||
massarg(opts).command({
|
||||
name: 'test2',
|
||||
@@ -32,6 +35,7 @@ describe('sub command', () => {
|
||||
run: jest.fn(),
|
||||
}),
|
||||
).toThrow('Expected string, received number')
|
||||
error.mockRestore()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -38,10 +38,12 @@ 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(() => { })
|
||||
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
|
||||
command.parse(['help'])
|
||||
expect(log).toHaveBeenCalled()
|
||||
log.mockRestore()
|
||||
error.mockRestore()
|
||||
})
|
||||
|
||||
test('binds option', () => {
|
||||
@@ -72,7 +74,7 @@ describe('prints help from option', () => {
|
||||
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()
|
||||
})
|
||||
@@ -99,7 +101,7 @@ describe('prints help from option', () => {
|
||||
.help({
|
||||
bindOption: true,
|
||||
})
|
||||
const log = jest.spyOn(console, 'log').mockImplementation(() => {})
|
||||
const log = jest.spyOn(console, 'log').mockImplementation(() => { })
|
||||
command.parse(['--help'])
|
||||
expect(log).toHaveBeenCalled()
|
||||
})
|
||||
@@ -111,7 +113,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,6 +14,7 @@ describe('option', () => {
|
||||
).toBeInstanceOf(MassargCommand)
|
||||
})
|
||||
test('validate', () => {
|
||||
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
|
||||
expect(() =>
|
||||
massarg(opts).option({
|
||||
name: 'test2',
|
||||
@@ -22,8 +23,10 @@ describe('option', () => {
|
||||
defaultValue: '',
|
||||
}),
|
||||
).toThrow('Expected string, received number')
|
||||
error.mockRestore()
|
||||
})
|
||||
test('add duplicate', () => {
|
||||
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
|
||||
expect(() =>
|
||||
massarg(opts)
|
||||
.option({
|
||||
@@ -39,6 +42,7 @@ describe('option', () => {
|
||||
defaultValue: '',
|
||||
}),
|
||||
).toThrow('test.test2: Option name "test2" already exists')
|
||||
error.mockRestore()
|
||||
})
|
||||
test('default', () => {
|
||||
const command = massarg(opts)
|
||||
@@ -57,6 +61,7 @@ describe('option', () => {
|
||||
expect(command.getArgs(['123'])).toHaveProperty('def', '123')
|
||||
})
|
||||
test('add 2 defaults', () => {
|
||||
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
|
||||
expect(() =>
|
||||
massarg(opts)
|
||||
.option({
|
||||
@@ -74,6 +79,7 @@ describe('option', () => {
|
||||
).toThrow(
|
||||
'Option "test2" cannot be set as default because option "test" is already set as default',
|
||||
)
|
||||
error.mockRestore()
|
||||
})
|
||||
test('uses output name', () => {
|
||||
const command = massarg(opts).option({
|
||||
@@ -85,6 +91,7 @@ describe('option', () => {
|
||||
expect(command.getArgs(['--test2', 'test'])).toHaveProperty('test', 'test')
|
||||
})
|
||||
test('required', () => {
|
||||
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
|
||||
const command = massarg(opts).option({
|
||||
name: 'test2',
|
||||
description: 'test2',
|
||||
@@ -92,6 +99,7 @@ describe('option', () => {
|
||||
required: true,
|
||||
})
|
||||
expect(() => command.getArgs([])).toThrow('Missing required option: test2')
|
||||
error.mockRestore()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -104,13 +112,16 @@ describe('flag', () => {
|
||||
)
|
||||
})
|
||||
test('add duplicate', () => {
|
||||
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
|
||||
expect(() =>
|
||||
massarg(opts)
|
||||
.flag({ name: 'test2', description: 'test2', aliases: [] })
|
||||
.flag({ name: 'test2', description: 'test2', aliases: [] }),
|
||||
).toThrow('test.test2: Flag name "test2" already exists')
|
||||
error.mockRestore()
|
||||
})
|
||||
test('validate', () => {
|
||||
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
|
||||
expect(() =>
|
||||
massarg(opts).flag({
|
||||
name: 'test2',
|
||||
@@ -118,13 +129,16 @@ describe('flag', () => {
|
||||
aliases: [],
|
||||
}),
|
||||
).toThrow('Expected string, received number')
|
||||
error.mockRestore()
|
||||
})
|
||||
describe('negation', () => {
|
||||
test('no negation', () => {
|
||||
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
|
||||
const command = massarg(opts).flag({ name: 'test2', description: 'test2', aliases: [] })
|
||||
expect(() => command.getArgs(['--no-test2'])).toThrow(
|
||||
'test2: Option test2 cannot be negated (received: "--no-test2")',
|
||||
)
|
||||
error.mockRestore()
|
||||
})
|
||||
test('negation', () => {
|
||||
const command = massarg(opts).flag({
|
||||
|
||||
Reference in New Issue
Block a user