mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-13 09:41:57 +00:00
165 lines
4.2 KiB
JavaScript
165 lines
4.2 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
*/
|
|
|
|
import getTSType from './getTSType';
|
|
|
|
const { namedTypes: t } = require('ast-types');
|
|
const {
|
|
resolveToValue,
|
|
getFlowType,
|
|
getParameterName,
|
|
getPropertyName,
|
|
getTypeAnnotation,
|
|
} = require('react-docgen').utils;
|
|
const { getDocblock } = require('react-docgen/dist/utils/docblock');
|
|
|
|
function getMethodFunctionExpression(methodPath) {
|
|
if (t.AssignmentExpression.check(methodPath.node)) {
|
|
return resolveToValue(methodPath.get('right'));
|
|
}
|
|
// Otherwise this is a method/property node
|
|
return methodPath.get('value');
|
|
}
|
|
|
|
function getMethodParamsDoc(methodPath) {
|
|
const params = [];
|
|
const functionExpression = getMethodFunctionExpression(methodPath);
|
|
|
|
// Extract param flow types.
|
|
functionExpression.get('params').each((paramPath) => {
|
|
let type = null;
|
|
const typePath = getTypeAnnotation(paramPath);
|
|
if (typePath && t.Flow.check(typePath.node)) {
|
|
type = getFlowType(typePath);
|
|
if (t.GenericTypeAnnotation.check(typePath.node)) {
|
|
type.alias = typePath.node.id.name;
|
|
}
|
|
} else if (typePath) {
|
|
type = getTSType(typePath);
|
|
if (t.TSTypeReference.check(typePath.node)) {
|
|
type.alias = typePath.node.typeName.name;
|
|
}
|
|
}
|
|
|
|
const param = {
|
|
name: getParameterName(paramPath),
|
|
optional: paramPath.node.optional,
|
|
type,
|
|
};
|
|
|
|
params.push(param);
|
|
});
|
|
|
|
return params;
|
|
}
|
|
|
|
// Extract flow return type.
|
|
function getMethodReturnDoc(methodPath) {
|
|
const functionExpression = getMethodFunctionExpression(methodPath);
|
|
|
|
if (functionExpression.node.returnType) {
|
|
const returnType = getTypeAnnotation(functionExpression.get('returnType'));
|
|
if (returnType && t.Flow.check(returnType.node)) {
|
|
return { type: getFlowType(returnType) };
|
|
}
|
|
if (returnType) {
|
|
return { type: getTSType(returnType) };
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function getMethodModifiers(methodPath) {
|
|
if (t.AssignmentExpression.check(methodPath.node)) {
|
|
return ['static'];
|
|
}
|
|
|
|
// Otherwise this is a method/property node
|
|
|
|
const modifiers = [];
|
|
|
|
if (methodPath.node.static) {
|
|
modifiers.push('static');
|
|
}
|
|
|
|
if (methodPath.node.kind === 'get' || methodPath.node.kind === 'set') {
|
|
modifiers.push(methodPath.node.kind);
|
|
}
|
|
|
|
const functionExpression = methodPath.get('value').node;
|
|
if (functionExpression.generator) {
|
|
modifiers.push('generator');
|
|
}
|
|
if (functionExpression.async) {
|
|
modifiers.push('async');
|
|
}
|
|
|
|
return modifiers;
|
|
}
|
|
|
|
function getMethodName(methodPath) {
|
|
if (t.AssignmentExpression.check(methodPath.node) && t.MemberExpression.check(methodPath.node.left)) {
|
|
const { left } = methodPath.node;
|
|
const { property } = left;
|
|
if (!left.computed) {
|
|
return property.name;
|
|
}
|
|
if (t.Literal.check(property)) {
|
|
return String(property.value);
|
|
}
|
|
return null;
|
|
}
|
|
return getPropertyName(methodPath);
|
|
}
|
|
|
|
function getMethodAccessibility(methodPath) {
|
|
if (t.AssignmentExpression.check(methodPath.node)) {
|
|
return null;
|
|
}
|
|
|
|
// Otherwise this is a method/property node
|
|
return methodPath.node.accessibility;
|
|
}
|
|
|
|
function getMethodDocblock(methodPath) {
|
|
if (t.AssignmentExpression.check(methodPath.node)) {
|
|
let path = methodPath;
|
|
do {
|
|
path = path.parent;
|
|
} while (path && !t.ExpressionStatement.check(path.node));
|
|
if (path) {
|
|
return getDocblock(path);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// Otherwise this is a method/property node
|
|
return getDocblock(methodPath);
|
|
}
|
|
|
|
// Gets the documentation object for a component method.
|
|
// Component methods may be represented as class/object method/property nodes
|
|
// or as assignment expresions of the form `Component.foo = function() {}`
|
|
export default function getMethodDocumentation(methodPath) {
|
|
if (getMethodAccessibility(methodPath) === 'private') {
|
|
return null;
|
|
}
|
|
|
|
const name = getMethodName(methodPath);
|
|
if (!name) return null;
|
|
|
|
return {
|
|
name,
|
|
docblock: getMethodDocblock(methodPath),
|
|
modifiers: getMethodModifiers(methodPath),
|
|
params: getMethodParamsDoc(methodPath),
|
|
returns: getMethodReturnDoc(methodPath),
|
|
};
|
|
}
|