xref: /expo/packages/@expo/cli/src/utils/args.ts (revision 83d464dc)
18d307f52SEvan Bacon// Common utilities for interacting with `args` library.
28d307f52SEvan Bacon// These functions should be used by every command.
38d307f52SEvan Baconimport arg from 'arg';
4*83d464dcSEvan Baconimport chalk from 'chalk';
58d307f52SEvan Baconimport { existsSync } from 'fs';
68d307f52SEvan Baconimport { resolve } from 'path';
78d307f52SEvan Bacon
88d307f52SEvan Baconimport * as Log from '../log';
98d307f52SEvan Bacon
108d307f52SEvan Bacon/**
118d307f52SEvan Bacon * Parse the first argument as a project directory.
128d307f52SEvan Bacon *
138d307f52SEvan Bacon * @returns valid project directory.
148d307f52SEvan Bacon */
158d307f52SEvan Baconexport function getProjectRoot(args: arg.Result<arg.Spec>) {
168d307f52SEvan Bacon  const projectRoot = resolve(args._[0] || '.');
178d307f52SEvan Bacon
188d307f52SEvan Bacon  if (!existsSync(projectRoot)) {
198d307f52SEvan Bacon    Log.exit(`Invalid project root: ${projectRoot}`);
208d307f52SEvan Bacon  }
218d307f52SEvan Bacon
228d307f52SEvan Bacon  return projectRoot;
238d307f52SEvan Bacon}
248d307f52SEvan Bacon
258d307f52SEvan Bacon/**
268d307f52SEvan Bacon * Parse args and assert unknown options.
278d307f52SEvan Bacon *
288d307f52SEvan Bacon * @param schema the `args` schema for parsing the command line arguments.
298d307f52SEvan Bacon * @param argv extra strings
308d307f52SEvan Bacon * @returns processed args object.
318d307f52SEvan Bacon */
3229975bfdSEvan Baconexport function assertArgs(schema: arg.Spec, argv?: string[]): arg.Result<arg.Spec> {
3309bb6093SEvan Bacon  return assertWithOptionsArgs(schema, { argv });
3409bb6093SEvan Bacon}
3509bb6093SEvan Bacon
3609bb6093SEvan Baconexport function assertWithOptionsArgs(
3709bb6093SEvan Bacon  schema: arg.Spec,
3809bb6093SEvan Bacon  options: arg.Options
3909bb6093SEvan Bacon): arg.Result<arg.Spec> {
408d307f52SEvan Bacon  try {
4109bb6093SEvan Bacon    return arg(schema, options);
4229975bfdSEvan Bacon  } catch (error: any) {
438d307f52SEvan Bacon    // Ensure unknown options are handled the same way.
448d307f52SEvan Bacon    if (error.code === 'ARG_UNKNOWN_OPTION') {
458d307f52SEvan Bacon      Log.exit(error.message, 1);
468d307f52SEvan Bacon    }
478d307f52SEvan Bacon    // Otherwise rethrow the error.
488d307f52SEvan Bacon    throw error;
498d307f52SEvan Bacon  }
508d307f52SEvan Bacon}
51*83d464dcSEvan Bacon
52*83d464dcSEvan Baconexport function printHelp(info: string, usage: string, options: string, extra: string = ''): never {
53*83d464dcSEvan Bacon  Log.exit(
54*83d464dcSEvan Bacon    chalk`
55*83d464dcSEvan Bacon  {bold Info}
56*83d464dcSEvan Bacon    ${info}
57*83d464dcSEvan Bacon
58*83d464dcSEvan Bacon  {bold Usage}
59*83d464dcSEvan Bacon    {dim $} ${usage}
60*83d464dcSEvan Bacon
61*83d464dcSEvan Bacon  {bold Options}
62*83d464dcSEvan Bacon    ${options.split('\n').join('\n    ')}
63*83d464dcSEvan Bacon` + extra,
64*83d464dcSEvan Bacon    0
65*83d464dcSEvan Bacon  );
66*83d464dcSEvan Bacon}
67