-
-
Notifications
You must be signed in to change notification settings - Fork 9.1k
/
react-docgen.ts
85 lines (75 loc) · 2.48 KB
/
react-docgen.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
import path from 'path';
import { createFilter } from '@rollup/pluginutils';
import type { Documentation } from 'react-docgen';
import {
ERROR_CODES,
parse,
builtinHandlers as docgenHandlers,
builtinResolvers as docgenResolver,
makeFsImporter,
} from 'react-docgen';
import MagicString from 'magic-string';
import type { PluginOption } from 'vite';
import actualNameHandler from './docgen-handlers/actualNameHandler';
import {
RESOLVE_EXTENSIONS,
ReactDocgenResolveError,
defaultLookupModule,
} from './docgen-resolver';
type DocObj = Documentation & { actualName: string };
// TODO: None of these are able to be overridden, so `default` is aspirational here.
const defaultHandlers = Object.values(docgenHandlers).map((handler) => handler);
const defaultResolver = new docgenResolver.FindExportedDefinitionsResolver();
const handlers = [...defaultHandlers, actualNameHandler];
type Options = {
include?: string | RegExp | (string | RegExp)[];
exclude?: string | RegExp | (string | RegExp)[];
};
export function reactDocgen({
include = /\.(mjs|tsx?|jsx?)$/,
exclude = [/node_modules\/.*/],
}: Options = {}): PluginOption {
const cwd = process.cwd();
const filter = createFilter(include, exclude);
return {
name: 'storybook:react-docgen-plugin',
enforce: 'pre',
async transform(src: string, id: string) {
if (!filter(path.relative(cwd, id))) {
return;
}
try {
const docgenResults = parse(src, {
resolver: defaultResolver,
handlers,
importer: makeFsImporter((filename, basedir) => {
const result = defaultLookupModule(filename, basedir);
if (RESOLVE_EXTENSIONS.find((ext) => result.endsWith(ext)) === undefined) {
return result;
}
throw new ReactDocgenResolveError(filename);
}),
filename: id,
}) as DocObj[];
const s = new MagicString(src);
docgenResults.forEach((info) => {
const { actualName, ...docgenInfo } = info;
if (actualName) {
const docNode = JSON.stringify(docgenInfo);
s.append(`;${actualName}.__docgenInfo=${docNode}`);
}
});
return {
code: s.toString(),
map: s.generateMap(),
};
} catch (e: any) {
// Ignore the error when react-docgen cannot find a react component
if (e.code === ERROR_CODES.MISSING_DEFINITION) {
return;
}
throw e;
}
},
};
}