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

Ouverte Adaptée aux débutants
#67,226 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 1 jour

@yohannesjoya y travaille déjà.

Depuis le 3/11/2026.

  • #67228 par @yohannesjoya — ouverte

Évaluation

Difficulté
2/5
Temps estimé
1-3 heures
Accessibilité débutants
75/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
Active
Stack technique
javascript, nodejs
Domaine
cli

Piste de recherche

Commence par argsToTokens() dans lib/internal/util/parse_args/parse_args.js, où un groupe d'options courtes comme -a-b est développé puis réinséré dans la liste des arguments. Vérifie comment la boucle ordonne le test arg === '--' par rapport au compteur du groupe, afin qu'un -- synthétisé ne soit pas traité comme le véritable terminateur. Exécute la reproduction de l'issue en mode strict et non strict, ainsi qu'avec tokens: true, et confirme que -a-b produit une erreur d'option inconnue et que l'index de chaque token correspond à celui de son argument source. C'est terminé lorsque les tests parseArgs existants passent et que de nouveaux cas couvrent -a-b et -a-.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

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.

Langage dominant
JavaScript
Étoiles
123k
Forks
39.3k
Merge moyen
4 j 11 h
PR mergées (30 j)
237

Préparer son environnement

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de nodejs/node

Toutes les issues de nodejs/node

Issues similaires

Plus d'issues JavaScript

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.