Skip to content

Consider supporting async option/argument parsers #1900

@aweebit

Description

@aweebit

I would like to parse an argument that is expected to equal an index to an array that can only be read asynchronously. Currently, I see no better way than to use an async argument parser and handle the promise it returns in the action handler. Here is a simple example with lowdb:

import { Command, InvalidArgumentError } from 'commander';

import { Low } from 'lowdb';
import { JSONFile } from 'lowdb/node';

const adapter = new JSONFile('test.json');
const db = new Low(adapter, ['foo', 'bar']);
await db.read();
await db.write();

const indexParser = async (val) => {
  if (val) {
    val = Number(val);
    if (Number.isInteger(val) && val >= 0) {
      await db.read();
      if (val < db.data.length) return val;
    }
  }
  throw new InvalidArgumentError('Index out of bounds');
};

const program = new Command()
  .argument('index', 'Array element to access', indexParser)
  .action(function(indexPromise) {
    indexPromise.then(async function(index) {
      await db.read();
      console.log(db.data[index]);
    });
  });

// go modify test.json manually or whatever...

setTimeout(() => program.parse(), 10000);

Obviously, it would be better and more intuitive if the action handler execution were deferred until after the promise is resolved.

Possible implementations:

  • explicit, something along these lines:

    program.addArgument(new Argument('index').argParser(indexParser).async())
  • defer action handler execution whenever parser returns a thenable object

    • if a certain new method was called on the command, e.g. program.respectAsyncArgParsers(true)
    • or if the parseAsync() method was called (breaking)

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions