-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
docgen.ts
98 lines (85 loc) · 2.87 KB
/
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
86
87
88
89
90
91
92
93
94
95
96
97
98
import * as fs from 'fs-extra'
import { isFunction } from 'lodash/fp'
import logger from 'signale'
import findUp from 'find-up'
import externalProptypesHandler from 'react-docgen-external-proptypes-handler'
// import importedProptypesHandler from 'react-docgen-imported-proptype-handler'
import actualNameHandler from 'react-docgen-actual-name-handler'
import reactDocgenTs from 'react-docgen-typescript'
import reactDocgen from 'react-docgen'
import ts from 'typescript'
import * as paths from '../config/paths'
import { Config } from '../config/argv'
const throwError = (err: any) => {
logger.fatal(`Error parsing static types`)
logger.error(err)
}
const tsProgram = (files: string[]) =>
ts.createProgram(files, {
jsx: ts.JsxEmit.React,
module: ts.ModuleKind.CommonJS,
target: ts.ScriptTarget.Latest,
})
const tsDocgen = (config: Config, tsconfig: string, program: ts.Program) => (
files: string[]
) =>
new Promise<reactDocgenTs.ComponentDoc[]>((resolve, reject) => {
try {
const opts = {
propFilter(prop: any): any {
if (prop.parent == null) return true
const propFilter = config.docgenConfig.propFilter
const val = propFilter && isFunction(propFilter) && propFilter(prop)
return !prop.parent.fileName.includes('node_modules') || Boolean(val)
},
}
const docs = reactDocgenTs
.withCustomConfig(tsconfig, opts)
.parseWithProgramProvider(files, () => program)
resolve(docs)
} catch (err) {
reject(err)
}
})
const tsParser = async (
files: string[],
config: Config,
tsconfig?: string,
program?: ts.Program | null
) => {
if (!program || !tsconfig) return
const parse = tsDocgen(config, tsconfig, program)
try {
const props = await parse(files)
return props.map((prop, idx) => ({ [files[idx]]: [prop] }))
} catch (err) {
if (config.debug) throwError(err)
return null
}
}
const jsParser = async (filepath: string, config: Config) => {
const resolver =
config.docgenConfig.resolver ||
reactDocgen.resolver.findAllExportedComponentDefinitions
const handlers = reactDocgen.defaultHandlers.concat([
externalProptypesHandler(filepath),
actualNameHandler,
])
try {
const code = fs.readFileSync(filepath, 'utf-8')
const data = reactDocgen.parse(code, resolver, handlers)
return { [filepath]: data }
} catch (err) {
if (config.debug) throwError(err)
return null
}
}
export const docgen = async (files: string[], config: Config) => {
const ts = config.typescript
const program = ts ? tsProgram(files) : null
const tsconfig = await findUp('tsconfig.json', { cwd: paths.root })
const docs = ts
? await tsParser(files, config, tsconfig, program)
: await Promise.all(files.map(async filepath => jsParser(filepath, config)))
return docs && docs.reduce((obj, doc) => (doc ? { ...obj, ...doc } : obj), {})
}