1import * as PackageManager from '@expo/package-manager'; 2 3import * as Log from '../log'; 4import { CommandError } from '../utils/errors'; 5 6export type Options = Pick<PackageManager.CreateForProjectOptions, 'npm' | 'yarn'> & { 7 /** Check which packages need to be updated, does not install any provided packages. */ 8 check?: boolean; 9 /** Should the dependencies be fixed automatically. */ 10 fix?: boolean; 11}; 12 13function resolveOptions(options: Options): Options { 14 if (options.fix && options.check) { 15 throw new CommandError('BAD_ARGS', 'Specify at most one of: --check, --fix'); 16 } 17 if (options.npm && options.yarn) { 18 throw new CommandError('BAD_ARGS', 'Specify at most one of: --npm, --yarn'); 19 } 20 return { 21 ...options, 22 }; 23} 24 25/** Given a list of CLI args, return a sorted set of args based on categories used in a complex command. */ 26export function parseVariadicArguments(argv: string[]): { 27 variadic: string[]; 28 extras: string[]; 29 flags: Record<string, boolean>; 30} { 31 const variadic: string[] = []; 32 const flags: Record<string, boolean> = {}; 33 34 for (const arg of argv) { 35 if (!arg.startsWith('-')) { 36 variadic.push(arg); 37 } else if (arg === '--') { 38 break; 39 } else { 40 flags[arg] = true; 41 } 42 } 43 44 // Everything after `--` that is not an option is passed to the underlying install command. 45 const extras: string[] = []; 46 47 const extraOperator = argv.indexOf('--'); 48 if (extraOperator > -1 && argv.length > extraOperator + 1) { 49 const extraArgs = argv.slice(extraOperator + 1); 50 if (extraArgs.includes('--')) { 51 throw new CommandError('BAD_ARGS', 'Unexpected multiple --'); 52 } 53 extras.push(...extraArgs); 54 Log.debug('Extra arguments: ' + extras.join(', ')); 55 } 56 57 Log.debug(`Parsed arguments (variadic: %O, flags: %O, extra: %O)`, variadic, flags, extras); 58 59 return { 60 variadic, 61 flags, 62 extras, 63 }; 64} 65 66export async function resolveArgsAsync( 67 argv: string[] 68): Promise<{ variadic: string[]; options: Options; extras: string[] }> { 69 const { variadic, extras, flags } = parseVariadicArguments(argv); 70 71 assertUnexpectedObjectKeys(['--check', '--fix', '--npm', '--yarn'], flags); 72 73 return { 74 // Variadic arguments like `npx expo install react react-dom` -> ['react', 'react-dom'] 75 variadic, 76 options: resolveOptions({ 77 fix: !!flags['--fix'], 78 check: !!flags['--check'], 79 yarn: !!flags['--yarn'], 80 npm: !!flags['--npm'], 81 }), 82 extras, 83 }; 84} 85 86function assertUnexpectedObjectKeys(keys: string[], obj: Record<string, any>): void { 87 const unexpectedKeys = Object.keys(obj).filter((key) => !keys.includes(key)); 88 if (unexpectedKeys.length > 0) { 89 throw new CommandError('BAD_ARGS', `Unexpected: ${unexpectedKeys.join(', ')}`); 90 } 91} 92