xref: /expo/packages/@expo/cli/src/utils/args.ts (revision bfcd021e)
1// Common utilities for interacting with `args` library.
2// These functions should be used by every command.
3import arg from 'arg';
4import chalk from 'chalk';
5import { existsSync } from 'fs';
6import { resolve } from 'path';
7
8import * as Log from '../log';
9
10/**
11 * Parse the first argument as a project directory.
12 *
13 * @returns valid project directory.
14 */
15export function getProjectRoot(args: arg.Result<arg.Spec>) {
16  const projectRoot = resolve(args._[0] || '.');
17
18  if (!existsSync(projectRoot)) {
19    Log.exit(`Invalid project root: ${projectRoot}`);
20  }
21
22  return projectRoot;
23}
24
25/**
26 * Parse args and assert unknown options.
27 *
28 * @param schema the `args` schema for parsing the command line arguments.
29 * @param argv extra strings
30 * @returns processed args object.
31 */
32export function assertArgs(schema: arg.Spec, argv?: string[]): arg.Result<arg.Spec> {
33  return assertWithOptionsArgs(schema, { argv });
34}
35
36export function assertWithOptionsArgs(
37  schema: arg.Spec,
38  options: arg.Options
39): arg.Result<arg.Spec> {
40  try {
41    return arg(schema, options);
42  } catch (error: any) {
43    // Ensure unknown options are handled the same way.
44    if (error.code === 'ARG_UNKNOWN_OPTION') {
45      Log.exit(error.message, 1);
46    }
47    // Otherwise rethrow the error.
48    throw error;
49  }
50}
51
52export function printHelp(info: string, usage: string, options: string, extra: string = ''): never {
53  Log.exit(
54    chalk`
55  {bold Info}
56    ${info}
57
58  {bold Usage}
59    {dim $} ${usage}
60
61  {bold Options}
62    ${options.split('\n').join('\n    ')}
63` + extra,
64    0
65  );
66}
67