1dfe12d45SEvan Baconimport { CommandError } from '../utils/errors'; 2dfe12d45SEvan Bacon 3474a7a4bSEvan Baconconst debug = require('debug')('expo:utils:variadic') as typeof console.log; 4474a7a4bSEvan Bacon 5dfe12d45SEvan Bacon/** Given a list of CLI args, return a sorted set of args based on categories used in a complex command. */ 6dfe12d45SEvan Baconexport function parseVariadicArguments(argv: string[]): { 7dfe12d45SEvan Bacon variadic: string[]; 8dfe12d45SEvan Bacon extras: string[]; 9dfe12d45SEvan Bacon flags: Record<string, boolean>; 10dfe12d45SEvan Bacon} { 11dfe12d45SEvan Bacon const variadic: string[] = []; 12dfe12d45SEvan Bacon const flags: Record<string, boolean> = {}; 13dfe12d45SEvan Bacon 14dfe12d45SEvan Bacon for (const arg of argv) { 15dfe12d45SEvan Bacon if (!arg.startsWith('-')) { 16dfe12d45SEvan Bacon variadic.push(arg); 17dfe12d45SEvan Bacon } else if (arg === '--') { 18dfe12d45SEvan Bacon break; 19dfe12d45SEvan Bacon } else { 20dfe12d45SEvan Bacon flags[arg] = true; 21dfe12d45SEvan Bacon } 22dfe12d45SEvan Bacon } 23dfe12d45SEvan Bacon 24dfe12d45SEvan Bacon // Everything after `--` that is not an option is passed to the underlying install command. 25dfe12d45SEvan Bacon const extras: string[] = []; 26dfe12d45SEvan Bacon 27dfe12d45SEvan Bacon const extraOperator = argv.indexOf('--'); 28dfe12d45SEvan Bacon if (extraOperator > -1 && argv.length > extraOperator + 1) { 29dfe12d45SEvan Bacon const extraArgs = argv.slice(extraOperator + 1); 30dfe12d45SEvan Bacon if (extraArgs.includes('--')) { 31dfe12d45SEvan Bacon throw new CommandError('BAD_ARGS', 'Unexpected multiple --'); 32dfe12d45SEvan Bacon } 33dfe12d45SEvan Bacon extras.push(...extraArgs); 34474a7a4bSEvan Bacon debug('Extra arguments: ' + extras.join(', ')); 35dfe12d45SEvan Bacon } 36dfe12d45SEvan Bacon 37474a7a4bSEvan Bacon debug(`Parsed arguments (variadic: %O, flags: %O, extra: %O)`, variadic, flags, extras); 38dfe12d45SEvan Bacon 39dfe12d45SEvan Bacon return { 40dfe12d45SEvan Bacon variadic, 41dfe12d45SEvan Bacon flags, 42dfe12d45SEvan Bacon extras, 43dfe12d45SEvan Bacon }; 44dfe12d45SEvan Bacon} 45dfe12d45SEvan Bacon 46dfe12d45SEvan Baconexport function assertUnexpectedObjectKeys(keys: string[], obj: Record<string, any>): void { 47dfe12d45SEvan Bacon const unexpectedKeys = Object.keys(obj).filter((key) => !keys.includes(key)); 48dfe12d45SEvan Bacon if (unexpectedKeys.length > 0) { 49dfe12d45SEvan Bacon throw new CommandError('BAD_ARGS', `Unexpected: ${unexpectedKeys.join(', ')}`); 50dfe12d45SEvan Bacon } 51dfe12d45SEvan Bacon} 52*e0694585SCedric van Putten 53*e0694585SCedric van Puttenexport function assertUnexpectedVariadicFlags( 54*e0694585SCedric van Putten expectedFlags: string[], 55*e0694585SCedric van Putten { extras, flags, variadic }: ReturnType<typeof parseVariadicArguments>, 56*e0694585SCedric van Putten prefixCommand = '' 57*e0694585SCedric van Putten) { 58*e0694585SCedric van Putten const unexpectedFlags = Object.keys(flags).filter((key) => !expectedFlags.includes(key)); 59*e0694585SCedric van Putten 60*e0694585SCedric van Putten if (unexpectedFlags.length > 0) { 61*e0694585SCedric van Putten const intendedFlags = Object.entries(flags) 62*e0694585SCedric van Putten .filter(([key]) => expectedFlags.includes(key)) 63*e0694585SCedric van Putten .map(([key]) => key); 64*e0694585SCedric van Putten 65*e0694585SCedric van Putten const cmd = [ 66*e0694585SCedric van Putten prefixCommand, 67*e0694585SCedric van Putten ...variadic, 68*e0694585SCedric van Putten ...intendedFlags, 69*e0694585SCedric van Putten '--', 70*e0694585SCedric van Putten ...extras.concat(unexpectedFlags), 71*e0694585SCedric van Putten ].join(' '); 72*e0694585SCedric van Putten 73*e0694585SCedric van Putten throw new CommandError( 74*e0694585SCedric van Putten 'BAD_ARGS', 75*e0694585SCedric van Putten `Unexpected: ${unexpectedFlags.join(', ')}\nDid you mean: ${cmd.trim()}` 76*e0694585SCedric van Putten ); 77*e0694585SCedric van Putten } 78*e0694585SCedric van Putten} 79