summaryrefslogtreecommitdiff
path: root/src/cli.ts
blob: 62e50f3eb4064c8cb258252c3ea3caae4f8fa1cc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import type { AstroConfig } from './@types/astro';

import * as colors from 'kleur/colors';
import { join as pathJoin, resolve as pathResolve } from 'path';
import { existsSync, promises as fsPromises } from 'fs';
import yargs from 'yargs-parser';

import generate from './generate.js';
import devServer from './dev.js';

const { readFile } = fsPromises;

type Arguments = yargs.Arguments;
type cliState = 'help' | 'version' | 'dev' | 'build';

function resolveArgs(flags: Arguments): cliState {
  if (flags.version) {
    return 'version';
  } else if (flags.help) {
    return 'help';
  }

  const cmd = flags._[2];
  switch (cmd) {
    case 'dev':
      return 'dev';
    case 'build':
      return 'build';
    default:
      return 'help';
  }
}

function printHelp() {
  console.error(`  ${colors.bold('astro')} - Futuristic web development tool.

  ${colors.bold('Commands:')}
  astro dev         Run Astro in development mode.
  astro build       Build a pre-compiled production version of your site.

  ${colors.bold('Flags:')}
  --version         Show the version number and exit.
  --help            Show this help message.
`);
}

async function printVersion() {
  const pkg = JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf-8'));
  console.error(pkg.version);
}

async function loadConfig(rawRoot: string | undefined): Promise<AstroConfig | undefined> {
  if (typeof rawRoot === 'undefined') {
    rawRoot = process.cwd();
  }

  const root = pathResolve(rawRoot);
  const fileProtocolRoot = `file://${root}/`;
  const astroConfigPath = pathJoin(root, 'astro.config.mjs');

  if (!existsSync(astroConfigPath)) {
    return undefined;
  }

  const astroConfig: AstroConfig = (await import(astroConfigPath)).default;
  astroConfig.projectRoot = new URL(astroConfig.projectRoot + '/', fileProtocolRoot);
  astroConfig.hmxRoot = new URL(astroConfig.hmxRoot + '/', fileProtocolRoot);
  return astroConfig;
}

async function runCommand(rawRoot: string, cmd: (a: AstroConfig) => Promise<void>) {
  const astroConfig = await loadConfig(rawRoot);
  if (typeof astroConfig === 'undefined') {
    console.error(colors.red('  An astro.config.mjs file is required.\n'));
    printHelp();
    process.exit(1);
  }

  return cmd(astroConfig);
}

const cmdMap = new Map([
  ['build', generate],
  ['dev', devServer],
]);

export async function cli(args: string[]) {
  const flags = yargs(args);
  const state = resolveArgs(flags);

  switch (state) {
    case 'help': {
      printHelp();
      process.exit(1);
      break;
    }
    case 'version': {
      await printVersion();
      process.exit(0);
      break;
    }
    case 'build':
    case 'dev': {
      const cmd = cmdMap.get(state)!;
      runCommand(flags._[3], cmd);
    }
  }
}