| 367 | |
| 368 | // Validate flags and throw errors for unknown flags or unexpected positionals |
| 369 | #validateFlags (parsed, commandDefinitions, remains) { |
| 370 | // Build a set of all valid flag names (global + command-specific + shorthands) |
| 371 | const validFlags = new Set([ |
| 372 | ...Object.keys(definitions), |
| 373 | ...commandDefinitions.map(d => d.key), |
| 374 | ...Object.keys(shorthands), // Add global shorthands like 'verbose', 'dd', etc. |
| 375 | ]) |
| 376 | |
| 377 | // Add aliases to valid flags |
| 378 | for (const def of commandDefinitions) { |
| 379 | if (def.alias && Array.isArray(def.alias)) { |
| 380 | for (const alias of def.alias) { |
| 381 | validFlags.add(alias) |
| 382 | } |
| 383 | } |
| 384 | } |
| 385 | |
| 386 | // Check parsed flags against valid flags |
| 387 | const unknownFlags = [] |
| 388 | for (const key of Object.keys(parsed)) { |
| 389 | if (!validFlags.has(key)) { |
| 390 | unknownFlags.push(key) |
| 391 | } |
| 392 | } |
| 393 | |
| 394 | // Throw error if unknown flags were found |
| 395 | if (unknownFlags.length > 0) { |
| 396 | const flagList = unknownFlags.map(f => `--${f}`).join(', ') |
| 397 | throw this.usageError(`Unknown flag${unknownFlags.length > 1 ? 's' : ''}: ${flagList}`) |
| 398 | } |
| 399 | |
| 400 | // Remove warnings for command-specific definitions that npm's global config doesn't know about (these were queued as "unknown" during config.load()) |
| 401 | for (const def of commandDefinitions) { |
| 402 | this.npm.config.removeWarning(def.key) |
| 403 | if (def.alias && Array.isArray(def.alias)) { |
| 404 | for (const alias of def.alias) { |
| 405 | this.npm.config.removeWarning(alias) |
| 406 | } |
| 407 | } |
| 408 | } |
| 409 | |
| 410 | // Remove warnings for unknown positionals that were actually consumed as flag values by command-specific definitions (e.g., --id <value> where --id is command-specific) |
| 411 | const remainsSet = new Set(remains) |
| 412 | for (const unknownPos of this.npm.config.getUnknownPositionals()) { |
| 413 | if (!remainsSet.has(unknownPos)) { |
| 414 | // This value was consumed as a flag value, not truly a positional |
| 415 | this.npm.config.removeUnknownPositional(unknownPos) |
| 416 | } |
| 417 | } |
| 418 | |
| 419 | // Warn about extra positional arguments beyond what the command expects |
| 420 | const expectedPositionals = this.constructor.positionals |
| 421 | if (expectedPositionals !== null && remains.length > expectedPositionals) { |
| 422 | const extraPositionals = remains.slice(expectedPositionals) |
| 423 | for (const extra of extraPositionals) { |
| 424 | throw new Error(`Unknown positional argument: ${extra}`) |
| 425 | } |
| 426 | } |