-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
/
index.ts
188 lines (176 loc) · 5.12 KB
/
index.ts
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/* eslint-disable no-console */
import * as colors from 'kleur/colors';
import yargs from 'yargs-parser';
import { ASTRO_VERSION } from '../core/constants.js';
type CLICommand =
| 'help'
| 'version'
| 'add'
| 'docs'
| 'dev'
| 'build'
| 'preview'
| 'sync'
| 'check'
| 'info'
| 'telemetry';
/** Display --help flag */
async function printAstroHelp() {
const { printHelp } = await import('../core/messages.js');
printHelp({
commandName: 'astro',
usage: '[command] [...flags]',
headline: 'Build faster websites.',
tables: {
Commands: [
['add', 'Add an integration.'],
['build', 'Build your project and write it to disk.'],
['check', 'Check your project for errors.'],
['dev', 'Start the development server.'],
['docs', 'Open documentation in your web browser.'],
['info', 'List info about your current Astro setup.'],
['preview', 'Preview your build locally.'],
['sync', 'Generate content collection types.'],
['telemetry', 'Configure telemetry settings.'],
],
'Global Flags': [
['--config <path>', 'Specify your config file.'],
['--root <path>', 'Specify your project root folder.'],
['--site <url>', 'Specify your project site.'],
['--base <pathname>', 'Specify your project base.'],
['--verbose', 'Enable verbose logging.'],
['--silent', 'Disable all logging.'],
['--version', 'Show the version number and exit.'],
['--help', 'Show this help message.'],
],
},
});
}
/** Display --version flag */
function printVersion() {
console.log();
console.log(` ${colors.bgGreen(colors.black(` astro `))} ${colors.green(`v${ASTRO_VERSION}`)}`);
}
/** Determine which command the user requested */
function resolveCommand(flags: yargs.Arguments): CLICommand {
const cmd = flags._[2] as string;
if (flags.version) return 'version';
const supportedCommands = new Set([
'add',
'sync',
'telemetry',
'dev',
'build',
'preview',
'check',
'docs',
'info',
]);
if (supportedCommands.has(cmd)) {
return cmd as CLICommand;
}
return 'help';
}
/**
* Run the given command with the given flags.
* NOTE: This function provides no error handling, so be sure
* to present user-friendly error output where the fn is called.
**/
async function runCommand(cmd: string, flags: yargs.Arguments) {
// These commands can run directly without parsing the user config.
switch (cmd) {
case 'help':
await printAstroHelp();
return;
case 'version':
printVersion();
return;
case 'info': {
const { printInfo } = await import('./info/index.js');
await printInfo({ flags });
return;
}
case 'docs': {
const { docs } = await import('./docs/index.js');
await docs({ flags });
return;
}
case 'telemetry': {
// Do not track session start, since the user may be trying to enable,
// disable, or modify telemetry settings.
const { update } = await import('./telemetry/index.js');
const subcommand = flags._[3]?.toString();
await update(subcommand, { flags });
return;
}
case 'sync': {
const { sync } = await import('./sync/index.js');
const exitCode = await sync({ flags });
return process.exit(exitCode);
}
}
// In verbose/debug mode, we log the debug logs asap before any potential errors could appear
if (flags.verbose) {
const { enableVerboseLogging } = await import('../core/logger/node.js');
enableVerboseLogging();
}
// Start with a default NODE_ENV so Vite doesn't set an incorrect default when loading the Astro config
if (!process.env.NODE_ENV) {
process.env.NODE_ENV = cmd === 'dev' ? 'development' : 'production';
}
const { notify } = await import('./telemetry/index.js');
await notify();
// These commands uses the logging and user config. All commands are assumed to have been handled
// by the end of this switch statement.
switch (cmd) {
case 'add': {
const { add } = await import('./add/index.js');
const packages = flags._.slice(3) as string[];
await add(packages, { flags });
return;
}
case 'dev': {
const { dev } = await import('./dev/index.js');
const server = await dev({ flags });
if (server) {
return await new Promise(() => {}); // lives forever
}
return;
}
case 'build': {
const { build } = await import('./build/index.js');
await build({ flags });
return;
}
case 'preview': {
const { preview } = await import('./preview/index.js');
const server = await preview({ flags });
if (server) {
return await server.closed(); // keep alive until the server is closed
}
return;
}
case 'check': {
const { check } = await import('./check/index.js');
const checkServer = await check(flags);
if (flags.watch) {
return await new Promise(() => {}); // lives forever
} else {
return process.exit(checkServer ? 1 : 0);
}
}
}
// No command handler matched! This is unexpected.
throw new Error(`Error running ${cmd} -- no command found.`);
}
/** The primary CLI action */
export async function cli(args: string[]) {
const flags = yargs(args);
const cmd = resolveCommand(flags);
try {
await runCommand(cmd, flags);
} catch (err) {
const { throwAndExit } = await import('./throw-and-exit.js');
await throwAndExit(cmd, err);
}
}