-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathindex.ts
More file actions
executable file
·119 lines (99 loc) · 3.45 KB
/
Copy pathindex.ts
File metadata and controls
executable file
·119 lines (99 loc) · 3.45 KB
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
import { err, ok } from "neverthrow";
import { artifactCommand } from "./commands/artifact";
import { codegenCommand } from "./commands/codegen/index";
import { doctorCommand } from "./commands/doctor";
import { formatCommand } from "./commands/format";
import { initCommand } from "./commands/init";
import { lspCommand } from "./commands/lsp";
import { typegenCommand } from "./commands/typegen";
import { cliErrors } from "./errors";
import type { CommandResult, CommandSuccess, OutputFormat } from "./types";
import { formatCliError } from "./utils/format";
const MAIN_HELP = `Usage: soda-gql <command> [options]
Commands:
init Initialize a new soda-gql project
codegen Generate graphql-system runtime module
typegen Generate prebuilt types from source code
format Format soda-gql field selections
artifact Manage soda-gql artifacts
doctor Run diagnostic checks
lsp Start the GraphQL language server
Run 'soda-gql <command> --help' for more information on a specific command.
`;
/**
* Parse output format from argv.
* Returns "json" if --format=json or --json flag is present, otherwise "human".
*/
const getOutputFormat = (argv: readonly string[]): OutputFormat => {
for (const arg of argv) {
if (arg === "--format=json" || arg === "--json") {
return "json";
}
if (arg === "--format=human") {
return "human";
}
}
return "human";
};
type DispatchResult = CommandResult<CommandSuccess & { exitCode?: number }>;
const dispatch = async (argv: readonly string[]): Promise<DispatchResult> => {
const [command, ...rest] = argv;
if (!command || command === "--help" || command === "-h") {
return ok({ message: MAIN_HELP });
}
if (command === "init") {
return initCommand(rest);
}
if (command === "codegen") {
return codegenCommand(rest);
}
if (command === "typegen") {
return typegenCommand(rest);
}
if (command === "format") {
const result = await formatCommand(rest);
if (result.isOk()) {
// Format command uses exit 1 for unformatted files in check mode or errors
const exitCode = result.value.data?.hasFormattingIssues ? 1 : 0;
return ok({ ...result.value, exitCode });
}
return err(result.error);
}
if (command === "artifact") {
return artifactCommand(rest);
}
if (command === "lsp") {
await lspCommand(rest);
return ok({ message: "" }); // unreachable, lsp runs forever
}
if (command === "doctor") {
const result = doctorCommand(rest);
if (result.isOk()) {
// Doctor uses exit 1 if issues found
const exitCode = result.value.data?.issueCount ? 1 : 0;
return ok({ ...result.value, exitCode });
}
return result;
}
return err(cliErrors.unknownCommand(command));
};
// Run CLI when executed directly
const main = async () => {
const argv = process.argv.slice(2);
const format = getOutputFormat(argv);
const result = await dispatch(argv);
if (result.isOk()) {
process.stdout.write(`${result.value.message}\n`);
process.exitCode = result.value.exitCode ?? 0;
} else {
process.stderr.write(`${formatCliError(result.error, format)}\n`);
process.exitCode = 1;
}
};
main().catch((error) => {
const unexpectedError = cliErrors.unexpected(error instanceof Error ? error.message : String(error), error);
const format = getOutputFormat(process.argv.slice(2));
process.stderr.write(`${formatCliError(unexpectedError, format)}\n`);
process.exitCode = 1;
});
export { dispatch };