feat: use parseJsDoc to parse propType docblock

This commit is contained in:
gengyang 2020-10-15 21:43:38 +08:00
parent 2c7dbe37f1
commit 0b80be68ae
7 changed files with 101 additions and 28 deletions

View File

@ -31,6 +31,7 @@ export default async (args: IParseArgs) => {
try { try {
return parseJS(moduleFileAbsolutePath); return parseJS(moduleFileAbsolutePath);
} catch (e) { } catch (e) {
log(e);
await install(args); await install(args);
const info = parseDynamic(mainFileAbsolutePath); const info = parseDynamic(mainFileAbsolutePath);
if (!info || !info.length) { if (!info || !info.length) {

View File

@ -3,6 +3,7 @@ import defaultPropsHandler from './defaultPropsHandler';
import flowTypeHandler from './flowTypeHandler'; import flowTypeHandler from './flowTypeHandler';
import componentMethodsHandler from './componentMethodsHandler'; import componentMethodsHandler from './componentMethodsHandler';
import preProcessHandler from './preProcessHandler'; import preProcessHandler from './preProcessHandler';
import propTypeJsDocHandler from './propTypeJsDocHandler';
const { handlers } = require('react-docgen'); const { handlers } = require('react-docgen');
@ -13,6 +14,7 @@ const defaultHandlers = [
childContextTypeHandler, childContextTypeHandler,
handlers.propTypeCompositionHandler, handlers.propTypeCompositionHandler,
handlers.propDocBlockHandler, handlers.propDocBlockHandler,
propTypeJsDocHandler,
flowTypeHandler, flowTypeHandler,
defaultPropsHandler, defaultPropsHandler,
handlers.componentDocblockHandler, handlers.componentDocblockHandler,

View File

@ -0,0 +1,36 @@
/* eslint-disable no-param-reassign */
const parseJsDoc = require('react-docgen/dist/utils/parseJsDoc').default;
const { getMemberValuePath, resolveToValue } = require('react-docgen').utils;
function resolveDocumentation(documentation) {
documentation._props.forEach(propDescriptor => {
const { description } = propDescriptor;
if (description.includes('@')) {
const jsDoc = parseJsDoc(description);
propDescriptor.description = jsDoc.description;
if (jsDoc.params) {
propDescriptor.params = jsDoc.params;
}
if (jsDoc.returns) {
propDescriptor.returns = jsDoc.returns;
}
}
});
}
/**
* Extract info from the propType jsdoc blocks. Must be run after
* propDocBlockHandler.
*/
export default function propTypeJsDocHandler(documentation, path) {
let propTypesPath = getMemberValuePath(path, 'propTypes');
if (!propTypesPath) {
return;
}
propTypesPath = resolveToValue(propTypesPath);
if (!propTypesPath) {
return;
}
resolveDocumentation(documentation);
}

View File

@ -6,7 +6,17 @@ const log = debug.extend('parse:transform');
export function transformType(itemType: any) { export function transformType(itemType: any) {
if (typeof itemType === 'string') return itemType; if (typeof itemType === 'string') return itemType;
const { name, elements, value = elements, computed, required, type, raw } = itemType; const {
name,
elements,
value = elements,
computed,
required,
type,
raw,
params,
returns,
} = itemType;
if (computed !== undefined && value) { if (computed !== undefined && value) {
return safeEval(value); return safeEval(value);
} }
@ -29,11 +39,19 @@ export function transformType(itemType: any) {
case 'node': case 'node':
break; break;
case 'func': case 'func':
if (value) { if (params) {
result.value = value.map(x => ({ result.params = params.map(x => ({
...x, ...x,
propType: transformType(x.propType), propType: transformType(x.propType),
})); }));
}
if (returns) {
result.returns = returns.map(x => ({
...x,
propType: transformType(x.propType),
}));
}
if (raw) {
result.raw = raw; result.raw = raw;
} }
break; break;

View File

@ -321,7 +321,7 @@ function getDocgenTypeHelper(
} else if (type?.symbol?.valueDeclaration?.parameters?.length) { } else if (type?.symbol?.valueDeclaration?.parameters?.length) {
return makeResult({ return makeResult({
name: 'func', name: 'func',
value: getFunctionParams( params: getFunctionParams(
// @ts-ignore // @ts-ignore
type?.symbol?.valueDeclaration?.parameters, type?.symbol?.valueDeclaration?.parameters,
checker, checker,
@ -335,7 +335,7 @@ function getDocgenTypeHelper(
) { ) {
return makeResult({ return makeResult({
name: 'func', name: 'func',
value: getFunctionParams( params: getFunctionParams(
// @ts-ignore // @ts-ignore
type?.members?.get('__call')?.declarations[0]?.symbol?.declarations[0]?.parameters, type?.members?.get('__call')?.declarations[0]?.symbol?.declarations[0]?.parameters,
checker, checker,

View File

@ -1,19 +1,19 @@
import _classCallCheck from "@babel/runtime/helpers/classCallCheck"; import _classCallCheck from '@babel/runtime/helpers/classCallCheck';
import _createClass from "@babel/runtime/helpers/createClass"; import _createClass from '@babel/runtime/helpers/createClass';
import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn"; import _possibleConstructorReturn from '@babel/runtime/helpers/possibleConstructorReturn';
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf"; import _getPrototypeOf from '@babel/runtime/helpers/getPrototypeOf';
import _inherits from "@babel/runtime/helpers/inherits"; import _inherits from '@babel/runtime/helpers/inherits';
/* eslint-disable react/no-unused-prop-types */ /* eslint-disable react/no-unused-prop-types */
/* eslint-disable react/require-default-props */ /* eslint-disable react/require-default-props */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import "./main.css"; import './main.css';
const Demo = const Demo =
/* #__PURE__ */ /* #__PURE__ */
function (_React$Component) { (function(_React$Component) {
_inherits(Demo, _React$Component); _inherits(Demo, _React$Component);
function Demo() { function Demo() {
@ -22,19 +22,26 @@ function (_React$Component) {
return _possibleConstructorReturn(this, _getPrototypeOf(Demo).apply(this, arguments)); return _possibleConstructorReturn(this, _getPrototypeOf(Demo).apply(this, arguments));
} }
_createClass(Demo, [{ _createClass(Demo, [
key: "render", {
key: 'render',
value: function render() { value: function render() {
return React.createElement("div", null, " Test "); return React.createElement('div', null, ' Test ');
}, },
}]); },
]);
return Demo; return Demo;
}(React.Component); })(React.Component);
Demo.propTypes = { Demo.propTypes = {
optionalArray: PropTypes.array, optionalArray: PropTypes.array,
optionalBool: PropTypes.bool, optionalBool: PropTypes.bool,
/**
* desc
* @param {{ok:String}} userName
* @returns {any}
*/
optionalFunc: PropTypes.func, optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number, optionalNumber: PropTypes.number,
optionalObject: PropTypes.object, optionalObject: PropTypes.object,
@ -54,7 +61,11 @@ Demo.propTypes = {
// it as an enum. // it as an enum.
optionalEnum: PropTypes.oneOf(['News', 'Photos']), optionalEnum: PropTypes.oneOf(['News', 'Photos']),
// An object that could be one of many types // An object that could be one of many types
optionalUnion: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.instanceOf(Demo)]), optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Demo),
]),
// An array of a certain type // An array of a certain type
optionalArrayOf: PropTypes.arrayOf(PropTypes.number), optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
// An object with property values of a certain type // An object with property values of a certain type

View File

@ -14,6 +14,11 @@ class Demo extends React.Component {
Demo.propTypes = { Demo.propTypes = {
optionalArray: PropTypes.array, optionalArray: PropTypes.array,
optionalBool: PropTypes.bool, optionalBool: PropTypes.bool,
/**
* desc
* @param {{ok:String}} userName
* @returns {any}
*/
optionalFunc: PropTypes.func, optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number, optionalNumber: PropTypes.number,
optionalObject: PropTypes.object, optionalObject: PropTypes.object,