-
-
Notifications
You must be signed in to change notification settings - Fork 300
/
Copy pathcommand.ts
167 lines (151 loc) · 4.91 KB
/
command.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
#!/usr/bin/env node
import glob from 'fast-glob';
import debugFactory from 'debug';
import { program } from 'commander';
import { builtinHandlers, parse } from 'react-docgen';
import { readFile } from 'fs/promises';
import outputResult from './output/outputResult.js';
import loadOptions from './options/loadOptions.js';
import outputError from './output/outputError.js';
import { resolve } from 'path';
import slash from 'slash';
import type { Documentation } from 'react-docgen';
import { ResolverConfigs } from './options/loadResolvers.js';
const debug = debugFactory('react-docgen:cli');
const defaultIgnoreGlobs = [
'**/node_modules/**',
'**/__tests__/**',
'**/__mocks__/**',
];
const defaultHandlers = Object.keys(builtinHandlers);
const defaultResolvers = ['find-exported-component'];
function collect(value: string, previous: string[]): string[] {
if (
!previous ||
previous === defaultIgnoreGlobs ||
previous === defaultHandlers ||
previous === defaultResolvers
) {
previous = [];
}
const values = value.split(',');
return previous.concat(values);
}
interface CLIOptions {
defaultIgnores: boolean;
failOnWarning: boolean;
handler?: string[];
ignore: string[];
importer?: string;
out?: string;
pretty: boolean;
resolver?: string[];
}
program
.name('react-docgen-parse')
.description(
'Extract meta information from React components.\n' +
'Either specify a paths to files or a glob pattern that matches multiple files.',
)
.option(
'-o, --out <file>',
'Store extracted information in the specified file instead of printing to stdout. If the file exists it will be overwritten.',
)
.option(
'-i, --ignore <glob>',
'Comma separated list of glob patterns which will ignore the paths that match. Can also be used multiple times.',
collect,
defaultIgnoreGlobs,
)
.option(
'--no-default-ignores',
'Do not ignore the node_modules, __tests__, and __mocks__ directories.',
)
.option('--pretty', 'Print the output JSON pretty', false)
.option(
'--failOnWarning',
'Fail with exit code 2 on react-docgen component warnings. This includes "no component found" and "multiple components found" warnings.',
false,
)
.option(
'--resolver <resolvers>',
`Built-in resolver config (${Object.values(ResolverConfigs).join(
', ',
)}), package name or path to a module that exports a resolver. Can also be used multiple times. When used, no default handlers will be added.`,
collect,
defaultResolvers,
)
.option(
'--importer <importer>',
'Built-in importer name (fsImport, ignoreImporter), package name or path to a module that exports an importer.',
'fsImporter',
)
.option(
'--handler <handlers>',
'Comma separated list of handlers to use. Can also be used multiple times. When used, no default handlers will be added.',
collect,
defaultHandlers,
)
.argument('<globs...>', 'Can be globs or paths to files')
.action(async (globs: string[], input: CLIOptions) => {
const {
defaultIgnores,
failOnWarning,
handler,
ignore,
importer,
out: output,
pretty,
resolver,
} = input;
let finalIgnores = ignore;
// Push the default ignores unless the --no-default-ignore is set
if (defaultIgnores === true && ignore !== defaultIgnoreGlobs) {
finalIgnores.push(...defaultIgnoreGlobs);
} else if (defaultIgnores === false && ignore === defaultIgnoreGlobs) {
finalIgnores = [];
}
const options = await loadOptions({
handler,
importer,
resolver,
});
// we use slash to convert windows backslashes to unix format so fast-glob works
const files = await glob(globs.map(slash), {
ignore: finalIgnores?.map((ignorePath) => {
ignorePath = ignorePath.trim();
// If the ignore glob starts with a dot we need to resolve the path to an
// absolute path in order for it to work
if (ignorePath.startsWith('.')) {
ignorePath = resolve(process.cwd(), ignorePath);
}
// we use slash to convert windows backslashes to unix format so fast-glob works
return slash(ignorePath);
}),
});
const result: Record<string, Documentation[]> = {};
let errorEncountered = false;
await Promise.all(
files.map(async (path) => {
debug(`Reading file ${path}`);
const content = await readFile(path, 'utf-8');
try {
result[path] = parse(content, {
filename: path,
handlers: options.handlers,
importer: options.importer,
resolver: options.resolver,
});
} catch (error) {
const isError = outputError(error as Error, path, { failOnWarning });
if (isError) {
errorEncountered = true;
}
}
}),
);
if (!errorEncountered) {
await outputResult(result, { pretty, output });
}
});
program.parse();