-
Notifications
You must be signed in to change notification settings - Fork 54
/
cli.ts
154 lines (146 loc) · 3.91 KB
/
cli.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
#!/usr/bin/env node
declare module 'ts-morph' {
// ts-morph does export the error, but it's missing from the typescript declarations
export const FileNotFoundError: typeof Error
}
import { FileNotFoundError } from 'ts-morph'
import commandLineArgs from 'command-line-args'
import commandLineUsage from 'command-line-usage'
import * as TsConfig from 'tsconfig'
import { generate } from './index'
interface ICliOptions {
shortcircuit?: string
paths: ReadonlyArray<string>
project?: string
help: boolean
debug?: boolean
'export-all'?: boolean
'import-guards'?: string
'prevent-export-imported'?: boolean
'guard-file-name'?: string
}
const optionList = [
{
description:
'A JavaScript condition used to automatically return `true` from guard functions, bypassing checks. eg. `process.env.DEBUG === "production"`.',
name: 'shortcircuit',
type: String,
typeLabel: '{underline javascript}',
},
{
defaultOption: true,
description:
'File(s) to generate guard for. If excluded this will process {italic all} project files.',
multiple: true,
name: 'paths',
type: String,
typeLabel: '{underline file[]} ...',
},
{
description:
'Generate checks for all exported types, even those not marked with comment',
name: 'export-all',
type: Boolean,
},
{
description:
'Adds TypeGuard import to source file, to also export TypeGuard from source use with --import-guards. Optionally accepts a string to choose custom import alias.',
name: 'import-guards',
typeLabel: '{underline TypeGuard}',
type: String,
},
{
description:
'Allows customisation of the filename for the generated guards file',
name: 'guard-file-name',
type: String,
typeLabel: '{underline extension}',
},
{
description:
'Overrides the default behavior for --import-guards by skipping export from source.',
name: 'prevent-export-imported',
type: Boolean,
},
{
description: 'Path to `tsconfig.json`.',
name: 'project',
type: String,
typeLabel: '{underline file}',
},
{
alias: 'h',
description: 'Print this usage guide.',
name: 'help',
type: Boolean,
},
{
alias: 'd',
description: 'Include debug logs in generated type guards.',
name: 'debug',
type: Boolean,
},
]
const options: ICliOptions = {
paths: [] as ReadonlyArray<string>,
help: false,
...(commandLineArgs(optionList) as Partial<ICliOptions>),
}
async function run() {
const project = await TsConfig.resolve(process.cwd(), options.project)
if (project === undefined) {
console.error('Could not find tsconfig')
return
}
if ('import-guards' in options) {
/** Checks if valid name passed as argument or replace with default if empty */
if (!options['import-guards']) {
options['import-guards'] = 'TypeGuards'
}
try {
eval(`const ${options['import-guards']} = true`)
} catch (error) {
console.log('Please pass a valid import alias')
throw error
}
}
try {
await generate({
paths: options.paths,
processOptions: {
debug: options.debug,
exportAll: options['export-all'],
importGuards: options['import-guards'],
preventExportImported: options['prevent-export-imported'],
shortCircuitCondition: options.shortcircuit,
guardFileName: options['guard-file-name'],
},
project,
})
console.log('Done!')
} catch (error) {
if (error instanceof FileNotFoundError) {
console.error(error.message)
} else {
throw error
}
}
}
if (options.help) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { name, version, description } = require('../package.json')
console.log(
commandLineUsage([
{
header: `${name} ${version}`,
content: description,
},
{
header: 'Options',
optionList,
},
])
)
} else {
run()
}