UNPKG

@dreamhorizonorg/sentinel

Version:

Open-source, zero-dependency tool that blocks compromised packages BEFORE download. Built to counter supply chain and credential theft attacks like Shai-Hulud.

118 lines (100 loc) 3.01 kB
/** * CLI argument parsing utilities * Pure functions for parsing command-line arguments */ import { BOOLEAN_STRING_VALUES } from '../constants/cli.constants.mjs'; /** * Convert string boolean to actual boolean */ const parseBoolean = (value) => { if (value === BOOLEAN_STRING_VALUES.TRUE) { return true; } if (value === BOOLEAN_STRING_VALUES.FALSE) { return false; } return value; }; /** * Parse command-line arguments * Returns { command, subcommand, options, positional } */ export const parseArgs = () => { const args = process.argv.slice(2); const command = args[0]; let subcommand = null; const options = {}; const positional = []; // Check if command supports subcommands (add, remove) const hasSubcommand = command === 'add' || command === 'remove'; // If has subcommand, args[1] is the subcommand if (hasSubcommand && args.length > 1 && !args[1].startsWith('-')) { subcommand = args[1]; } // Start parsing from index 1 (or 2 if we have a subcommand) const startIndex = hasSubcommand && subcommand ? 2 : 1; for (let i = startIndex; i < args.length; i++) { const arg = args[i]; // Handle --key=value format if (arg.startsWith('--') && arg.includes('=')) { const [key, ...valueParts] = arg.slice(2).split('='); const value = valueParts.join('='); // Rejoin in case value contains '=' const normalizedKey = key.replace(/-/g, '').toLowerCase(); options[normalizedKey] = parseBoolean(value); continue; } if (arg.startsWith('--')) { const key = arg.slice(2).replace(/-/g, '').toLowerCase(); const nextArg = args[i + 1]; if (nextArg && !nextArg.startsWith('-')) { options[key] = parseBoolean(nextArg); i++; } else { options[key] = true; } } else if (arg.startsWith('-')) { const key = arg.slice(1).toLowerCase(); const nextArg = args[i + 1]; if (nextArg && !nextArg.startsWith('-')) { options[key] = parseBoolean(nextArg); i++; } else { options[key] = true; } } else { positional.push(arg); } } return { command, subcommand, options, positional }; }; /** * Parse package spec (package-name@version or @scope/package@version) */ export const parsePackageSpec = (spec) => { // Handle scoped packages: @scope/package@version const scopedMatch = spec.match(/^(@[^/]+\/[^@]+)@?(.+)?$/); if (scopedMatch) { return { name: scopedMatch[1], version: scopedMatch[2] ?? null }; } // Handle regular packages: package@version const match = spec.match(/^(@?[^@]+)@?(.+)?$/); if (!match) { return { name: spec, version: null }; } return { name: match[1], version: match[2] ?? null }; }; /** * Check if command is help command */ export const isHelpCommand = (command) => { return !command || command === 'help' || command === '--help' || command === '-h'; };