util: parseArgs() treats a `-` inside a short option group as the `--` terminator

オープン 初心者向け
#67,226 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

@yohannesjoya がすでに取り組んでいます。

2026年11月3日 から。

  • #67228 @yohannesjoya による — オープン

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
75/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
javascript, nodejs
領域
cli

調査の方向性

lib/internal/util/parse_args/parse_args.js の argsToTokens() から始めてください。ここでは -a-b のような短いオプションのグループが展開され、引数リストに押し戻されます。ループが arg === '--' の判定とグループカウンタをどの順序で評価するかを確認し、合成された -- が本当の終端として扱われないようにしてください。issue の再現手順を strict モードと非 strict モード、さらに tokens: true で実行し、-a-b が不明なオプションのエラーになること、各トークンの index が元の引数の index と一致することを確認してください。既存の parseArgs テストが通り、-a-b と -a- を扱う新しいケースが追加されれば完了です。

索引モデルが issue の本文から書いたものです。

説明

Version

v28.0.0-pre (main, d2812af0), also v22.20.0

Platform

Linux 7.0.0-38-generic x86_64

Subsystem

util

What steps will reproduce the bug?
const { parseArgs } = require('node:util');

const options = { a: { type: 'boolean' }, b: { type: 'boolean' } };

// Non-strict, with tokens.
const args = ['-a-b', 'pos'];
const { values, positionals, tokens } = parseArgs({
  args, options, strict: false, allowPositionals: true, tokens: true,
});
console.log(values, positionals);
for (const token of tokens) {
  console.log(token, '-> args[index] =', args[token.index]);
}

// Strict.
for (const arg of ['-a-b', '-a-']) {
  try {
    parseArgs({ args: [arg], options });
    console.log(arg, 'ok');
  } catch (err) {
    console.log(arg, err.code, '-', err.message);
  }
}
How often does it reproduce? Is there a required condition?

Every time. Needs a - character inside a short option group, for example -a-b or -a-.

What is the expected behavior?

- is not a valid option character, so -a-b should be reported the same way as any other unknown short option in a group (compare -ar with r unknown). In strict mode that is ERR_PARSE_ARGS_UNKNOWN_OPTION. With tokens: true, every token's index should point at the argument it came from, as the docs say: "the source argument for a token is args[token.index]".

What do you see instead?
[Object: null prototype] { a: true } [ '-b', 'pos' ]
{ kind: 'option', name: 'a', rawName: '-a', index: 0, value: undefined, inlineValue: undefined } -> args[index] = -a-b
{ kind: 'option-terminator', index: 0 } -> args[index] = -a-b
{ kind: 'positional', index: 1, value: '-b' } -> args[index] = pos
{ kind: 'positional', index: 2, value: 'pos' } -> args[index] = undefined
-a-b ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL - Unexpected argument '-b'. This command does not take positional arguments
-a- ok
  • -b becomes a positional instead of an option.
  • An option-terminator token appears although the user never passed --.
  • The positional indexes are shifted by one, so args[token.index] is the wrong argument or undefined.
  • In strict mode -a-b reports a misleading unexpected-positional error, and -a- is accepted silently.
Additional information

argsToTokens() in lib/internal/util/parse_args/parse_args.js expands a short option group -a-b into -a, --, -b and pushes them back onto the argument list. The loop then checks arg === '--' before it looks at whether the argument came from a group, so the synthesized -- is handled as the real terminator. The group counter (groupCount) already knows the argument was expanded.

For comparison, getopt(3) reports -a-b as invalid option -- '-'.

I have a small fix with tests and can open a PR.

主要言語
JavaScript
スター
123k
フォーク
39.3k
平均マージ
4日 15時間
マージ済み PR(30日)
238

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

nodejs/node のほかの issue

nodejs/node の issue をすべて見る

似ている issue

JavaScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。