npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

optionalist

v3.0.0

Published

The commandline parser for TypeScript

Downloads

385

Readme

optionalist

The commandline parser for TypeScript.

optionalistはTypeScript向けに作られたコマンドラインパーザーです。

NPM version NPM monthly download NPM total download MIT License

使い方

optionalist.parseにコマンドラインの詳細を渡して、解析した結果を受け取ります。

const options = optionalist.parse({
  [optionalist.helpString]: {
    describe: 'The description for command.',
    showUsageOnError: true,
  },
  help: {
    type: 'boolean',
    alias: ['?', 'h'],
    alone: true,
    describe: 'Show this help.',
  },
  init: {
    type: 'boolean',
    alone: true,
    describe: 'Initialize your project.',
  },
  output: {
    type: 'string',
    required: true,
    describe: 'Specify the filename to output.',
    example: 'output_filename',
  },
  config: {
    default: path.resolve('config.json'),
    describe: 'Specify the configuration file for your project.',
    example: 'config_filename',
  },
  watch: {
    type: 'boolean',
    describe: 'Specify when you want to set the watch mode.',
  },
  timeout: {
    type: 'number',
  },
  [optionalist.unnamed]: {
    example: 'script_filename',
    describe: 'Specify the script filename(s) to execute.',
  },
} as const);
options.help ? options : options.init ? options : options;
// この時点でのoptionsは
// const options:
//   | {
//       readonly help: true;
//       readonly init?: never;
//       readonly output?: never;
//       readonly config?: never;
//       readonly watch?: never;
//       readonly timeout?: never;
//       readonly [unnamed]?: never;
//       readonly [helpString]: string;
//     }
//   | {
//       readonly init: true;
//       readonly help?: never;
//       readonly output?: never;
//       readonly config?: never;
//       readonly watch?: never;
//       readonly timeout?: never;
//       readonly [unnamed]?: never;
//       readonly [helpString]: string;
//     }
//   | {
//       readonly [unnamed]: readonly string[];
//       readonly [helpString]: string;
//       readonly help?: never;
//       readonly init?: never;
//       readonly output: string;
//       readonly config: string;
//       readonly watch?: true;
//       readonly timeout?: number;
//     };

受け取った結果は自動的に型付けされ、もし指定されていればデフォルト値が設定された状態になっています。

// --helpが指定されたとき
if (options.help) {
  options;
  // このスコープでのoptionsは
  // const options: {
  //   readonly help: true;
  //   readonly init?: never;
  //   readonly output?: never;
  //   readonly config?: never;
  //   readonly watch?: never;
  //   readonly timeout?: never;
  //   readonly [unnamed]?: never;
  //   readonly [helpString]: string;
  // };

  // [optionalist.helpString]はコマンドの説明用文字列を返す。
  console.log(options[optionalist.helpString]);
  // この例では以下のような文字列になる。
  // Version: sample 0.0.1
  // Usage:
  //   node sample --output output_filename [--config config_filename] [--watch] [--timeout parameter] [--] [script_filename...]
  //   node sample --help
  //   node sample --init

  // Description:
  //   The description for command.

  // Options:
  //   --help, -?, -h
  //     Show this help.
  //   --init
  //     Initialize your project.
  //   --output output_filename
  //     Specify the filename to output.
  //   --config config_filename
  //     Specify the configuration file for your project.
  //   --watch
  //     Specify when you want to set the watch mode.
  //   --timeout parameter
  //   [--] [script_filename...]
  //     Specify the script filename(s) to execute.
  //
  process.exit(0);
}

options.init ? options : options;
// この時点でのoptionsは
// const options:
//   | {
//       readonly init: true;
//       readonly help?: never;
//       readonly output?: never;
//       readonly config?: never;
//       readonly watch?: never;
//       readonly timeout?: never;
//       readonly [unnamed]?: never;
//       readonly [helpString]: string;
//     }
//   | {
//       readonly [unnamed]: readonly string[];
//       readonly [helpString]: string;
//       readonly help?: never;
//       readonly init?: never;
//       readonly output: string;
//       readonly config: string;
//       readonly watch?: true;
//       readonly timeout?: number;
//     };

// --initが指定されたとき
if (options.init) {
  options;
  // このスコープでのoptionsは
  // const options: {
  //   readonly init: true;
  //   readonly help?: never;
  //   readonly output?: never;
  //   readonly config?: never;
  //   readonly watch?: never;
  //   readonly timeout?: never;
  //   readonly [unnamed]?: never;
  //   readonly [helpString]: string;
  // };

  initializeProject();
  process.exit(0);
}

options;
// この時点でのoptionsは
// const options: {
//   readonly [unnamed]: readonly string[];
//   readonly [helpString]: string;
//   readonly help?: never;
//   readonly init?: never;
//   readonly output: string;
//   readonly config: string;
//   readonly watch?: true;
//   readonly timeout?: number;
// };

// プロパティはそれぞれ指定された型になっている。

loadConfigfile(options.config);

for (const file of options[optionalist.unnamed]) {
  executeFile(file, options.output);
}

if (options.watch) {
  const list = options[optionalist.unnamed].slice(0);
  watch(list, file => executeFile(file, options.output));
}

コマンドラインの詳細

コマンドラインの詳細はoptionalist.parseの第1引数に、以下のように指定します。

  • [optionalist.helpString]: コマンド全体に関する指定を行います。

    • describe: ヘルプ用文字列で表示される、コマンドの説明を指定します。

      省略時にはコマンドの説明が表示されません。

    • showUsageOnError: コマンドラインでの指定に不備があった場合、ヘルプ用文字列を表示して終了するのであればtrueを指定します。

  • [name: string]: 各オプションの詳細を指定します。

    実際にコマンドラインパラメーターとして指定するには、nameが一文字だけの場合は-x、2文字以上の場合は--xxxのように指定します。

    • type: オプションの型を指定します。

      'string''number''boolean'のいずれかを指定します。

      'string'の場合には文字列型、'number'の場合には数値型、‘boolean'の場合には真偽値型になります。

      省略時には'string'が指定されたものと見なします。

    • constraints: 文字列型、数値型の場合、指定できる値への制約を指定します。

      • 配列が指定された場合は、その中の1つが指定されていないとエラーになります。(type: 'number'、もしくはtype: 'string')

      • minプロパティを持つオブジェクトが指定された場合は、min未満の値が指定されるとエラーになります。(type: 'number')

        maxもしくはmaxExclusiveと同時に指定できます。

      • maxプロパティを持つオブジェクトが指定された場合は、maxより大きい値が指定されるとエラーになります。(type: 'number')

        minもしくはminExclusiveと同時に指定できます。

      • minExclusiveプロパティを持つオブジェクトが指定された場合は、minExclusive以下の値が指定されるとエラーになります。(type: 'number')

        maxもしくはmaxExclusiveと同時に指定できます。

      • maxExclusiveプロパティを持つオブジェクトが指定された場合は、maxExclusive以上の値が指定されるとエラーになります。(type: 'number')

        minもしくはminExclusiveと同時に指定できます。

      • 正規表現が指定された場合は、その正規表現にマッチしない値が指定されるとエラーになります。(type: 'string')

      type: 'boolean'の場合には指定できません。

    • example: ヘルプ用文字列でパラメーターとして使用される文字列を指定します。

      たとえば{alpha: {example: 'filename'}}と指定した場合、ヘルプ用文字列では--alpha filenameのように使用されます。

      type: 'boolean'の場合には指定できません。

    • alone: 単独で指定するオプションのときにtrueを指定します。

      ほかのオプションは名前付き、無名にかかわらず指定するとエラーになります。

    • required: 指定が必須なオプションのときにtrueを指定します。

      このオプションが指定されていないとエラーになります。

      type: 'boolean'の場合には指定できません。

    • default: このオプションが省略されたときに使用するデフォルト値を指定します。

      デフォルト値にはtype: 'string'の場合には文字列を、type: 'number'の場合には数値を指定しなければなりません。

      type: 'boolean'の場合には指定できません。

    • alias: オプションの別名を指定します。

      実際にコマンドラインで使用する場合には、nameと同様に一文字だけの場合は-x、2文字以上の場合は--xxxのように指定します。

      複数指定するには配列で指定します。

    • describe: オプションの説明を指定します。

      ヘルプ用文字列で使用されます。

    オブジェクトではなく文字列、数値、trueを指定することも可能です。

    • 文字列を指定すると{default: その文字列}を指定したように扱います。
    • 数値を指定すると、{type: 'number', default: その数値}を指定したように扱います。
    • trueを指定すると{type: 'boolean'}を指定したように扱います。
  • [optionalist.unnamed]: 無名オプションの詳細を指定します。

    • example: ヘルプ用文字列の中で無名オプションを指す名前を指定します。

    • describe: ヘルプ用文字列の中で使用される無名オプションの説明を指定します。

    • min: 無名オプションの最小個数を指定します。

      省略時には最小個数のチェックを行いません。

    • max: 無名オプションの最大個数を指定します。

      省略時には最大個数のチェックを行いません。

解析するコマンドライン

parseの第2引数には解析するコマンドラインを指定します。

省略時にはprocess.argvの3番目から解析を開始します。

配列だけでなくIterable<string>を指定することが可能です。

解析結果

返値には解析結果を指定されたオプションの名前と型を持つオブジェクトにして返します。

aloneを指定したオプションがある場合は、aloneを指定したオプションだけの型と、それ以外のオプションだけの型のUnion型になっています。

const options = optionalist.parse({aaa: {alone: true, type: 'boolean'}, bbb: '', ccc: 0});
// options:
// | {
//   aaa: true; // aaaだけが存在する。
//   bbb?: never;
//   ccc?: never;
//   [unnamed]?: never; // unnamedもなし
//   [helpString]: string; // helpStringだけはヘルプのため常に追加
// }
// | {
//   aaa?:never; // aaaはなし
//   bbb: string;
//   ccc: number;
//   [unnamed]: string[];
//   [helpString]: string; // helpStringだけはヘルプのため常に追加
// }

aloneなオプションが指定された場合、その他のオプションは指定されていないためundefinedになっていることに注意してください。

逆にその他のオプションを使うときはすべてのaloneなオプションが指定されていないことを確認してからでないと、通常のプロパティのようにアクセスできません。これによりaloneなオプションの処理漏れが防げます。

if (options.aaa) {
  assert(options.bbb === undefined);
  assert(options.ccc === undefined);
  process.exit(0);
}

const { bbb,ccc } = options;
assert(typeof bbb === 'string');
assert(typeof ccc === 'number');

通常のオプションはoptionalになっていますが、必須のオプション、およびデフォルト値の指定されたオプションは非optionalとなっています。

  const options = optionalist.parse({
    aaa: {
      type: 'string',
    },
    bbb: {
      required: true,
    },
    ccc: {
      default: 'ccc',
    },
  });
  const { aaa, bbb, ccc } = options;
  // aaaにはrequiredもdefaultも指定されていないのでoptional
  assert(aaa === undefined || typeof aaa === 'string');
  // bbbにはrequiredが指定されているので非optional
  assert(typeof bbb === 'string');
  // cccにはdefaultが指定されているので非非optional
  assert(typeof ccc === 'string');

無名オプションは[optionalist.unnamed]stringの配列として取得できます。

for (const arg of options[optionalist.unnamed]) {
  // ...
}

ヘルプ

使い方を表示したい場合には、指定された情報から自動的に生成したヘルプ用文字列が[optionalist.helpString]で取得できます。

またparseの第1引数の[optionalist.helpString]showUsageOnErrorを指定していると、コマンドライン引数にエラーがあったとき、使い方を表示して終了します。

const options = optionalist.parse({
  // ...
  help: {alone: true, type: 'boolean'},
  [optionalist.helpString]: {
    // コマンドライン引数での指定にエラーがあれば使い方を表示して終了
    showUsageOnError: true,
  },
});

if (options.help) {
  // --helpが指定されたらヘルプを表示して終了
  console.log(options[optionalist.helpString]);
  process.exit(0);
}

VS Codeなどの型情報が表示されるエディターを使用しているなら、型情報として各パラメーターの説明が表示されます。

const options = optionalist.parse({
  // ...
  output: {
    type: 'string',
    required: true,
    describe: 'Specify the filename to output.',
    example: 'output_filename',
  },
  // ...
});

のように記述していれば

  executeFile(file, options.output);

と記述したときに、outputにマウスカーソルを合わせれば、

(property) output: string & {
    [description]: ["--output output_filename: Specify the filename to output.", "is specified always."];
}

のように表示されます。

実際にコマンドラインパラメーターとして指定する際の文字列 --output output_filename および説明 Specify the filename to output. と、requiredが指定されているので必須パラメーターであることを示す is specified always. が表示されています。同様にalonedefaultなどを指定した場合も説明が追加されます。

ただし実際にこの説明文をプロパティとして保持しているわけではないため、アクセスできないことに注意してください。