mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-03-01 13:40:41 +00:00
fix: fix typescript related bugs, including the following:
1. fix bug of failing to resolve RFC components
2. support transforming function args
3. fix bug of oneOfType
4. fix bug of crash when circular parsing
5. fix bug of union
6. support tuple
7. fix bug of builtin type parsing
8. fix bug of false positive component identification
9. fix bug of entry resolving
This commit is contained in:
parent
571883e6ed
commit
d4c45d2dea
9
packages/material-parser/.eslintrc.js
Normal file
9
packages/material-parser/.eslintrc.js
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = {
|
||||
extends: ['eslint-config-ali/typescript/react'],
|
||||
rules: {
|
||||
'implicit-arrow-linebreak': 1,
|
||||
'@typescript-eslint/indent': 1,
|
||||
'function-paren-newline': 1,
|
||||
'no-bitwise': 0,
|
||||
},
|
||||
};
|
||||
@ -42,13 +42,13 @@ export interface Npm {
|
||||
[k: string]: any;
|
||||
}
|
||||
export interface PropsSection {
|
||||
props: Array<{
|
||||
props: {
|
||||
name: string;
|
||||
propType: PropType;
|
||||
description?: string;
|
||||
defaultValue?: any;
|
||||
[k: string]: any;
|
||||
}>;
|
||||
}[];
|
||||
[k: string]: any;
|
||||
}
|
||||
export interface RequiredType {
|
||||
@ -57,7 +57,7 @@ export interface RequiredType {
|
||||
}
|
||||
export interface OneOf {
|
||||
type: 'oneOf';
|
||||
value: Array<string | number | boolean>;
|
||||
value: (string | number | boolean)[];
|
||||
isRequired?: boolean;
|
||||
[k: string]: any;
|
||||
}
|
||||
@ -81,19 +81,19 @@ export interface ObjectOf {
|
||||
}
|
||||
export interface Shape {
|
||||
type: 'shape';
|
||||
value: Array<{
|
||||
value: {
|
||||
name?: string;
|
||||
propType?: PropType;
|
||||
}>;
|
||||
}[];
|
||||
isRequired?: boolean;
|
||||
[k: string]: any;
|
||||
}
|
||||
export interface Exact {
|
||||
type: 'exact';
|
||||
value: Array<{
|
||||
value: {
|
||||
name?: string;
|
||||
propType?: PropType;
|
||||
}>;
|
||||
}[];
|
||||
isRequired?: boolean;
|
||||
[k: string]: any;
|
||||
}
|
||||
@ -119,24 +119,24 @@ export interface ConfigureFieldProp {
|
||||
}
|
||||
export interface ConfigureFieldSetter {
|
||||
componentName:
|
||||
| 'List'
|
||||
| 'Object'
|
||||
| 'Function'
|
||||
| 'Node'
|
||||
| 'Mixin'
|
||||
| 'Expression'
|
||||
| 'Switch'
|
||||
| 'Number'
|
||||
| 'Input'
|
||||
| 'TextArea'
|
||||
| 'Date'
|
||||
| 'DateYear'
|
||||
| 'DateMonth'
|
||||
| 'DateRange'
|
||||
| 'ColorPicker'
|
||||
| 'CodeEditor'
|
||||
| 'Select'
|
||||
| 'RadioGroup';
|
||||
| 'List'
|
||||
| 'Object'
|
||||
| 'Function'
|
||||
| 'Node'
|
||||
| 'Mixin'
|
||||
| 'Expression'
|
||||
| 'Switch'
|
||||
| 'Number'
|
||||
| 'Input'
|
||||
| 'TextArea'
|
||||
| 'Date'
|
||||
| 'DateYear'
|
||||
| 'DateMonth'
|
||||
| 'DateRange'
|
||||
| 'ColorPicker'
|
||||
| 'CodeEditor'
|
||||
| 'Select'
|
||||
| 'RadioGroup';
|
||||
props?: {
|
||||
[k: string]: any;
|
||||
};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import parseDynamic from './runtime';
|
||||
import parseDynamic from './dynamic';
|
||||
import parseJS from './js';
|
||||
import parseTS from './ts';
|
||||
import { install, installPeerDeps, installTypeModules } from '../utils';
|
||||
@ -24,9 +24,9 @@ export default async (args: IParseArgs) => {
|
||||
moduleFileAbsolutePath = mainFileAbsolutePath,
|
||||
} = args;
|
||||
if (args.accesser === 'local') {
|
||||
if (moduleFileAbsolutePath.endsWith('ts') || moduleFileAbsolutePath.endsWith('tsx')) {
|
||||
if (mainFileAbsolutePath.endsWith('ts') || mainFileAbsolutePath.endsWith('tsx')) {
|
||||
await install(args);
|
||||
return parseTS(moduleFileAbsolutePath);
|
||||
return parseTS(mainFileAbsolutePath);
|
||||
} else {
|
||||
try {
|
||||
return parseJS(moduleFileAbsolutePath);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { omit, pick, isNil } from 'lodash';
|
||||
import { omit, pick, isNil, uniq } from 'lodash';
|
||||
import { safeEval, isEvaluable } from '../utils';
|
||||
import { debug } from '../core';
|
||||
|
||||
@ -6,10 +6,7 @@ const log = debug.extend('parse:transform');
|
||||
|
||||
export function transformType(itemType: any) {
|
||||
if (typeof itemType === 'string') return itemType;
|
||||
const { name, elements, value = elements, computed, required, type } = itemType;
|
||||
// if (!value && !required && !type) {
|
||||
// return name;
|
||||
// }
|
||||
const { name, elements, value = elements, computed, required, type, raw } = itemType;
|
||||
if (computed !== undefined && value) {
|
||||
return safeEval(value);
|
||||
}
|
||||
@ -24,7 +21,6 @@ export function transformType(itemType: any) {
|
||||
case 'string':
|
||||
case 'bool':
|
||||
case 'any':
|
||||
case 'func':
|
||||
case 'symbol':
|
||||
case 'object':
|
||||
case 'null':
|
||||
@ -32,21 +28,34 @@ export function transformType(itemType: any) {
|
||||
case 'element':
|
||||
case 'node':
|
||||
break;
|
||||
case 'func':
|
||||
if (value) {
|
||||
result.value = value.map(x => ({
|
||||
...x,
|
||||
propType: transformType(x.propType),
|
||||
}));
|
||||
result.raw = raw;
|
||||
}
|
||||
break;
|
||||
case 'literal':
|
||||
return safeEval(value);
|
||||
result.type = 'oneOf';
|
||||
result.value = [safeEval(value)];
|
||||
break;
|
||||
case 'enum':
|
||||
case 'tuple':
|
||||
case 'oneOf':
|
||||
result.type = 'oneOf';
|
||||
result.value = value.map(transformType);
|
||||
break;
|
||||
case 'tuple':
|
||||
result.type = 'tuple';
|
||||
result.value = value.map(transformType);
|
||||
break;
|
||||
case 'union': {
|
||||
const { raw } = itemType;
|
||||
if (raw) {
|
||||
if (raw.match(/ReactNode$/)) {
|
||||
if (itemType.raw) {
|
||||
if (itemType.raw.match(/ReactNode$/)) {
|
||||
result.type = 'node';
|
||||
break;
|
||||
} else if (raw.match(/Element$/)) {
|
||||
} else if (itemType.raw.match(/Element$/)) {
|
||||
result.type = 'element';
|
||||
break;
|
||||
}
|
||||
@ -69,12 +78,12 @@ export function transformType(itemType: any) {
|
||||
case 'Array':
|
||||
case 'arrayOf': {
|
||||
result.type = 'arrayOf';
|
||||
const v = omit(transformType(value[0]), ['isRequired']);
|
||||
if (Object.keys(v).length === 1 && v.type) {
|
||||
result.value = v.type;
|
||||
} else {
|
||||
result.value = v;
|
||||
let _itemType = transformType(value[0]);
|
||||
if (typeof _itemType === 'object') {
|
||||
_itemType = omit(_itemType, ['isRequired']);
|
||||
}
|
||||
|
||||
result.value = _itemType;
|
||||
break;
|
||||
}
|
||||
case 'signature': {
|
||||
@ -83,13 +92,25 @@ export function transformType(itemType: any) {
|
||||
break;
|
||||
}
|
||||
result.type = 'shape';
|
||||
const properties = type?.signature?.properties || [];
|
||||
const properties = type?.signature?.properties || itemType?.signature?.properties || [];
|
||||
if (properties.length === 0) {
|
||||
result.type = 'object';
|
||||
if (raw?.includes('=>')) {
|
||||
result.type = 'func';
|
||||
result.raw = raw;
|
||||
} else {
|
||||
result.type = 'object';
|
||||
}
|
||||
} else if (properties.length === 1 && typeof properties[0].key === 'object') {
|
||||
result.type = 'objectOf';
|
||||
const v = transformType(properties[0].value);
|
||||
if (typeof v.type === 'string') result.value = v.type;
|
||||
if (typeof v === 'string') {
|
||||
result.value = v;
|
||||
result.type = 'objectOf';
|
||||
} else if (typeof v?.type === 'string') {
|
||||
result.value = v.type;
|
||||
result.type = 'objectOf';
|
||||
} else {
|
||||
result.type = 'object';
|
||||
}
|
||||
} else if (properties.length === 1 && properties[0].key === '__call') {
|
||||
result.type = 'func';
|
||||
} else {
|
||||
@ -97,10 +118,15 @@ export function transformType(itemType: any) {
|
||||
.filter((item: any) => typeof item.key !== 'object')
|
||||
.map((prop: any) => {
|
||||
const { key } = prop;
|
||||
return transformItem(key, {
|
||||
const typeItem = {
|
||||
...omit(prop.value, 'name'),
|
||||
type: pick(prop.value, ['name', 'value']),
|
||||
});
|
||||
type: prop.value.type || {},
|
||||
};
|
||||
typeItem.type = {
|
||||
...typeItem.type,
|
||||
...pick(prop.value, ['name', 'value']),
|
||||
};
|
||||
return transformItem(key, typeItem);
|
||||
});
|
||||
}
|
||||
break;
|
||||
@ -111,7 +137,7 @@ export function transformType(itemType: any) {
|
||||
break;
|
||||
case 'exact':
|
||||
case 'shape':
|
||||
result.value = Object.keys(value).map((n) => {
|
||||
result.value = Object.keys(value).map(n => {
|
||||
// tslint:disable-next-line:variable-name
|
||||
const { name: _name, ...others } = value[n];
|
||||
return transformItem(n, {
|
||||
@ -125,21 +151,71 @@ export function transformType(itemType: any) {
|
||||
case (name.match(/ReactNode$/) || {}).input:
|
||||
result.type = 'node';
|
||||
break;
|
||||
case (name.match(/Element$/) || {}).input:
|
||||
case (name.match(/JSX\.Element$/) || {}).input:
|
||||
result.type = 'element';
|
||||
break;
|
||||
// case (name.match(/ElementType$/) || {}).input:
|
||||
// result.type = 'elementType';
|
||||
// break;
|
||||
default:
|
||||
// result.type = 'instanceOf';
|
||||
// result.value = name;
|
||||
result.type = 'any';
|
||||
result.type = 'object';
|
||||
break;
|
||||
}
|
||||
if (Object.keys(result).length === 1) {
|
||||
return result.type;
|
||||
}
|
||||
if (result?.type === 'oneOfType') {
|
||||
return combineOneOfValues(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function combineOneOfValues(propType) {
|
||||
if (propType.type !== 'oneOfType') {
|
||||
return propType;
|
||||
}
|
||||
const newValue = [];
|
||||
let oneOfItem = null;
|
||||
let firstBooleanIndex = -1;
|
||||
propType.value.forEach(item => {
|
||||
if (item?.type === 'oneOf') {
|
||||
if (!oneOfItem) {
|
||||
oneOfItem = {
|
||||
type: 'oneOf',
|
||||
value: [],
|
||||
};
|
||||
}
|
||||
if (item.value.includes(true) || item.value.includes(false)) {
|
||||
if (firstBooleanIndex !== -1) {
|
||||
oneOfItem.value.splice(firstBooleanIndex, 1);
|
||||
newValue.push('bool');
|
||||
} else {
|
||||
firstBooleanIndex = oneOfItem.value.length;
|
||||
oneOfItem.value = oneOfItem.value.concat(item.value);
|
||||
}
|
||||
} else {
|
||||
oneOfItem.value = oneOfItem.value.concat(item.value);
|
||||
}
|
||||
} else {
|
||||
newValue.push(item);
|
||||
}
|
||||
});
|
||||
let result = propType;
|
||||
const oneOfItemLength = oneOfItem?.value?.length;
|
||||
if (oneOfItemLength) {
|
||||
newValue.push(oneOfItem);
|
||||
}
|
||||
if (firstBooleanIndex !== -1 || oneOfItemLength) {
|
||||
result = {
|
||||
...propType,
|
||||
value: newValue,
|
||||
};
|
||||
}
|
||||
if (result.value.length === 1 && result.value[0]?.type === 'oneOf') {
|
||||
result = {
|
||||
...result,
|
||||
type: 'oneOf',
|
||||
value: result.value[0].value,
|
||||
};
|
||||
}
|
||||
result.value = uniq(result.value);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -175,6 +251,8 @@ export function transformItem(name: string, item: any) {
|
||||
if (defaultValue === null) {
|
||||
result.defaultValue = defaultValue;
|
||||
} else {
|
||||
// if ('computed' in defaultValue) {
|
||||
// val = val.value;
|
||||
try {
|
||||
const value = safeEval(defaultValue.value);
|
||||
if (isEvaluable(value)) {
|
||||
@ -184,9 +262,13 @@ export function transformItem(name: string, item: any) {
|
||||
log(e);
|
||||
}
|
||||
}
|
||||
// else {
|
||||
// result.defaultValue = defaultValue.value;
|
||||
// }
|
||||
}
|
||||
if (result.propType === undefined) {
|
||||
delete result.propType;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -12,9 +12,18 @@ type ExtendedType = ts.Type & {
|
||||
typeArguments: any[];
|
||||
};
|
||||
|
||||
function getNextParentIds(parentIds: number[], type: ts.Type) {
|
||||
// @ts-ignore
|
||||
const id = type?.symbol?.id;
|
||||
if (id) {
|
||||
return [...parentIds, id];
|
||||
}
|
||||
return parentIds;
|
||||
}
|
||||
|
||||
function getSymbolName(symbol: ts.Symbol) {
|
||||
// @ts-ignore
|
||||
const prefix: string = symbol.parent && getSymbolName(symbol.parent);
|
||||
const prefix: string = symbol?.parent && getSymbolName(symbol.parent);
|
||||
const name = symbol.getName();
|
||||
if (prefix && prefix.length <= 20) {
|
||||
return `${prefix}.${name}`;
|
||||
@ -22,6 +31,33 @@ function getSymbolName(symbol: ts.Symbol) {
|
||||
return name;
|
||||
}
|
||||
|
||||
function getFunctionParams(parameters: any[] = [], checker, parentIds, type) {
|
||||
return parameters.map(node => {
|
||||
const typeObject = checker.getTypeOfSymbolAtLocation(node.symbol, node.symbol.valueDeclaration);
|
||||
const v = getDocgenTypeHelper(checker, typeObject, false, getNextParentIds(parentIds, type));
|
||||
const name = node.symbol.escapedName;
|
||||
return {
|
||||
name,
|
||||
propType: v,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that a symbol is an alias that does not merge with a local declaration.
|
||||
* OR Is a JSContainer which may merge an alias with a local declaration
|
||||
*/
|
||||
// function isNonLocalAlias(
|
||||
// symbol: ts.Symbol | undefined,
|
||||
// excludes = SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace,
|
||||
// ): symbol is ts.Symbol {
|
||||
// if (!symbol) return false;
|
||||
// return (
|
||||
// (symbol.flags & (SymbolFlags.Alias | excludes)) === SymbolFlags.Alias ||
|
||||
// !!(symbol.flags & SymbolFlags.Alias && symbol.flags & SymbolFlags.Assignment)
|
||||
// );
|
||||
// }
|
||||
|
||||
const blacklistNames = [
|
||||
'prototype',
|
||||
'getDerivedStateFromProps',
|
||||
@ -34,6 +70,38 @@ const blacklistNames = [
|
||||
'Consumer',
|
||||
];
|
||||
|
||||
const blacklistPatterns = [
|
||||
/^HTML/,
|
||||
/^React\./,
|
||||
/^Object$/,
|
||||
/^Date$/,
|
||||
/^Promise$/,
|
||||
/^XML/,
|
||||
/^Function$/,
|
||||
];
|
||||
|
||||
function hasTooManyTypes(type) {
|
||||
return type?.types?.length >= 20;
|
||||
}
|
||||
|
||||
function isComplexType(type) {
|
||||
let isAliasSymbol = false;
|
||||
let symbol = type?.symbol;
|
||||
if (!symbol) {
|
||||
symbol = type?.aliasSymbol;
|
||||
isAliasSymbol = true;
|
||||
}
|
||||
if (!symbol) return false;
|
||||
if (isAliasSymbol && !hasTooManyTypes(type)) {
|
||||
return false;
|
||||
}
|
||||
const name = getSymbolName(symbol);
|
||||
if (blacklistPatterns.some(patt => patt.test(name))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getDocgenTypeHelper(
|
||||
checker: ts.TypeChecker,
|
||||
type: ts.Type,
|
||||
@ -70,10 +138,10 @@ function getDocgenTypeHelper(
|
||||
function getShapeFromArray(symbolArr: ts.Symbol[], _type: ts.Type) {
|
||||
const shape: Array<{
|
||||
key:
|
||||
| {
|
||||
name: string;
|
||||
}
|
||||
| string;
|
||||
| {
|
||||
name: string;
|
||||
}
|
||||
| string;
|
||||
value: any;
|
||||
}> = symbolArr.map(prop => {
|
||||
const propType = checker.getTypeOfSymbolAtLocation(
|
||||
@ -89,7 +157,7 @@ function getDocgenTypeHelper(
|
||||
propType,
|
||||
false,
|
||||
// @ts-ignore
|
||||
[...parentIds, _type.id],
|
||||
getNextParentIds(parentIds, _type),
|
||||
// @ts-ignore
|
||||
prop?.valueDeclaration?.questionToken ? false : undefined,
|
||||
),
|
||||
@ -108,11 +176,13 @@ function getDocgenTypeHelper(
|
||||
key: {
|
||||
name: 'string',
|
||||
},
|
||||
// @ts-ignore use internal methods
|
||||
value: getDocgenTypeHelper(checker, _type.stringIndexInfo.type, false, [
|
||||
...parentIds,
|
||||
(_type as ExtendedType).id,
|
||||
]),
|
||||
value: getDocgenTypeHelper(
|
||||
checker,
|
||||
// @ts-ignore use internal methods
|
||||
_type.stringIndexInfo.type,
|
||||
false,
|
||||
getNextParentIds(parentIds, _type),
|
||||
),
|
||||
});
|
||||
} else if (_type.getNumberIndexType()) {
|
||||
// @ts-ignore use internal methods
|
||||
@ -124,11 +194,13 @@ function getDocgenTypeHelper(
|
||||
name: 'number',
|
||||
},
|
||||
|
||||
// @ts-ignore use internal methods
|
||||
value: getDocgenTypeHelper(checker, _type.numberIndexInfo.type, false, [
|
||||
...parentIds,
|
||||
(_type as ExtendedType).id,
|
||||
]),
|
||||
value: getDocgenTypeHelper(
|
||||
checker,
|
||||
// @ts-ignore use internal methods
|
||||
_type.numberIndexInfo.type,
|
||||
false,
|
||||
getNextParentIds(parentIds, _type),
|
||||
),
|
||||
});
|
||||
}
|
||||
return shape;
|
||||
@ -139,6 +211,9 @@ function getDocgenTypeHelper(
|
||||
if (symbol && symbol.members) {
|
||||
// @ts-ignore
|
||||
const props: ts.Symbol[] = Array.from(symbol.members.values());
|
||||
if (props.length >= 20) {
|
||||
throw new Error('too many props');
|
||||
}
|
||||
return getShapeFromArray(
|
||||
props.filter(prop => prop.getName() !== '__index'),
|
||||
_type,
|
||||
@ -147,6 +222,9 @@ function getDocgenTypeHelper(
|
||||
// @ts-ignore
|
||||
const args = _type.resolvedTypeArguments || [];
|
||||
const props = checker.getPropertiesOfType(_type);
|
||||
if (props.length >= 20) {
|
||||
throw new Error('too many props');
|
||||
}
|
||||
const shape = getShapeFromArray(props.slice(0, args.length), _type);
|
||||
return shape;
|
||||
}
|
||||
@ -154,9 +232,9 @@ function getDocgenTypeHelper(
|
||||
|
||||
const pattern = /^__global\.(.+)$/;
|
||||
// @ts-ignore
|
||||
if (parentIds.includes(type.id)) {
|
||||
if (parentIds.includes(type?.symbol?.id)) {
|
||||
return makeResult({
|
||||
name: checker.typeToString(type),
|
||||
name: 'object', // checker.typeToString(type),
|
||||
});
|
||||
}
|
||||
if (type.symbol) {
|
||||
@ -170,6 +248,7 @@ function getDocgenTypeHelper(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type.flags & TypeFlags.Number) {
|
||||
return makeResult({
|
||||
name: 'number',
|
||||
@ -198,63 +277,140 @@ function getDocgenTypeHelper(
|
||||
return makeResult({
|
||||
name: 'any',
|
||||
});
|
||||
} else if (type.flags & TypeFlags.Union) {
|
||||
} else if (type.flags & TypeFlags.Union && !isComplexType(type)) {
|
||||
return makeResult({
|
||||
name: 'union',
|
||||
// @ts-ignore
|
||||
value: type.types.map(t => getDocgenTypeHelper(checker, t, true, [...parentIds, type.id])),
|
||||
value: type.types.map(t =>
|
||||
getDocgenTypeHelper(checker, t, true, getNextParentIds(parentIds, type)),
|
||||
),
|
||||
});
|
||||
} else if (isComplexType(type)) {
|
||||
return makeResult({
|
||||
name: getSymbolName(type?.symbol || type?.aliasSymbol),
|
||||
});
|
||||
} else if (type.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
|
||||
if (isTuple(type)) {
|
||||
const props = getShape(type);
|
||||
return makeResult({
|
||||
name: 'union',
|
||||
value: props.map(p => p.value),
|
||||
});
|
||||
try {
|
||||
const props = getShape(type);
|
||||
return makeResult({
|
||||
name: 'tuple',
|
||||
value: props.map(p => p.value),
|
||||
});
|
||||
} catch (e) {
|
||||
return makeResult({
|
||||
name: 'object',
|
||||
});
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
} else if (checker.isArrayType(type)) {
|
||||
return makeResult({
|
||||
name: 'Array',
|
||||
// @ts-ignore
|
||||
elements: [
|
||||
getDocgenTypeHelper(checker, (type as ExtendedType).typeArguments[0], false, [
|
||||
...parentIds,
|
||||
(type as any).id,
|
||||
]),
|
||||
getDocgenTypeHelper(
|
||||
checker,
|
||||
(type as ExtendedType).typeArguments[0],
|
||||
false,
|
||||
getNextParentIds(parentIds, type),
|
||||
),
|
||||
],
|
||||
});
|
||||
} else if (type.aliasSymbol) {
|
||||
return makeResult({
|
||||
name: getSymbolName(type.aliasSymbol),
|
||||
});
|
||||
// @ts-ignore
|
||||
} else if (type?.symbol?.valueDeclaration?.parameters?.length) {
|
||||
return makeResult({
|
||||
name: 'func',
|
||||
value: getFunctionParams(
|
||||
// @ts-ignore
|
||||
type?.symbol?.valueDeclaration?.parameters,
|
||||
checker,
|
||||
parentIds,
|
||||
type,
|
||||
),
|
||||
});
|
||||
} else if (
|
||||
// @ts-ignore
|
||||
type?.members?.get('__call')?.declarations[0]?.symbol?.declarations[0]?.parameters?.length
|
||||
) {
|
||||
return makeResult({
|
||||
name: 'func',
|
||||
value: getFunctionParams(
|
||||
// @ts-ignore
|
||||
type?.members?.get('__call')?.declarations[0]?.symbol?.declarations[0]?.parameters,
|
||||
checker,
|
||||
parentIds,
|
||||
type,
|
||||
),
|
||||
});
|
||||
} else {
|
||||
const props = getShape(type);
|
||||
return makeResult({
|
||||
name: 'signature',
|
||||
type: {
|
||||
signature: {
|
||||
properties: props,
|
||||
try {
|
||||
const props = getShape(type);
|
||||
return makeResult({
|
||||
name: 'signature',
|
||||
type: {
|
||||
signature: {
|
||||
properties: props,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
return makeResult({
|
||||
name: 'object',
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return makeResult({
|
||||
name: 'any',
|
||||
name: 'object',
|
||||
});
|
||||
}
|
||||
}
|
||||
class MyParser extends Parser {
|
||||
getDocgenType(propType: ts.Type): any {
|
||||
const parentIds = [];
|
||||
// @ts-ignore
|
||||
const result = getDocgenTypeHelper(this.checker, propType, true);
|
||||
const parentId = propType?.symbol?.parent?.id;
|
||||
if (parentId) {
|
||||
parentIds.push(parentId);
|
||||
}
|
||||
// @ts-ignore
|
||||
const result = getDocgenTypeHelper(this.checker, propType, true, parentIds);
|
||||
return result;
|
||||
}
|
||||
|
||||
// override the builtin method, to avoid the false positive
|
||||
public extractPropsFromTypeIfStatelessComponent(type: ts.Type): ts.Symbol | null {
|
||||
const callSignatures = type.getCallSignatures();
|
||||
|
||||
if (callSignatures.length) {
|
||||
// Could be a stateless component. Is a function, so the props object we're interested
|
||||
// in is the (only) parameter.
|
||||
|
||||
for (const sig of callSignatures) {
|
||||
const params = sig.getParameters();
|
||||
if (params.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const returnSymbol = this.checker.getReturnTypeOfSignature(sig);
|
||||
if (!returnSymbol) continue;
|
||||
const symbol = returnSymbol?.symbol;
|
||||
if (!symbol) continue;
|
||||
// @ts-ignore
|
||||
const typeString = this.checker.symbolToString(symbol);
|
||||
if (typeString.startsWith('ReactElement')) {
|
||||
const propsParam = params[0];
|
||||
if (propsParam) {
|
||||
return propsParam;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const compilerOptions = {
|
||||
@ -300,6 +456,9 @@ export default function parseTS(
|
||||
if (blacklistNames.includes(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// polyfill valueDeclaration
|
||||
sym.valueDeclaration = sym.valueDeclaration || sym.declarations[0];
|
||||
// @ts-ignore
|
||||
const info = parser.getComponentInfo(sym, sourceFile, parserOpts.componentNameResolver);
|
||||
if (info === null) {
|
||||
@ -326,7 +485,6 @@ export default function parseTS(
|
||||
sym,
|
||||
sym.valueDeclaration || sym.declarations[0],
|
||||
);
|
||||
|
||||
Array.prototype.push.apply(
|
||||
exportSymbols,
|
||||
type.getProperties().map((x: SymbolWithMeta) => {
|
||||
@ -341,6 +499,10 @@ export default function parseTS(
|
||||
const coms = result.reduce((res: any[], info: any) => {
|
||||
if (!info || !info.props || isEmpty(info.props)) return res;
|
||||
const props = Object.keys(info.props).reduce((acc: any[], name) => {
|
||||
// omit aria related properties temporarily
|
||||
if (name.startsWith('aria-')) {
|
||||
return acc;
|
||||
}
|
||||
try {
|
||||
const item: any = transformItem(name, info.props[name]);
|
||||
acc.push(item);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -758,7 +758,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
{
|
||||
description: '面包屑子节点,需传入 Breadcrumb.Item',
|
||||
name: 'children',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
defaultValue: 100,
|
||||
@ -1066,12 +1066,12 @@ Generated by [AVA](https://avajs.dev).
|
||||
{
|
||||
description: '默认选中的日期(moment 对象)',
|
||||
name: 'defaultValue',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
description: '选中的日期值 (moment 对象)',
|
||||
name: 'value',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
name: 'modes',
|
||||
@ -1186,22 +1186,22 @@ Generated by [AVA](https://avajs.dev).
|
||||
{
|
||||
description: '默认的开始日期',
|
||||
name: 'defaultStartValue',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
description: '默认的结束日期',
|
||||
name: 'defaultEndValue',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
description: '开始日期(moment 对象)',
|
||||
name: 'startValue',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
description: '结束日期(moment 对象)',
|
||||
name: 'endValue',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
defaultValue: false,
|
||||
@ -1391,7 +1391,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
defaultValue: 'div',
|
||||
description: '设置标签类型',
|
||||
name: 'component',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
name: 'className',
|
||||
@ -1423,7 +1423,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
defaultValue: 'div',
|
||||
description: '设置标签类型',
|
||||
name: 'component',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
description: '背景图片地址',
|
||||
@ -1470,7 +1470,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
defaultValue: 'hr',
|
||||
description: '设置标签类型',
|
||||
name: 'component',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
description: '分割线是否向内缩进',
|
||||
@ -1507,7 +1507,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
defaultValue: 'div',
|
||||
description: '设置标签类型',
|
||||
name: 'component',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
name: 'className',
|
||||
@ -1539,7 +1539,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
defaultValue: 'div',
|
||||
description: '设置标签类型',
|
||||
name: 'component',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
name: 'className',
|
||||
@ -2524,12 +2524,12 @@ Generated by [AVA](https://avajs.dev).
|
||||
{
|
||||
description: '日期值(受控)moment 对象',
|
||||
name: 'value',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
description: '初始日期值,moment 对象',
|
||||
name: 'defaultValue',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
defaultValue: 'YYYY-MM-DD',
|
||||
@ -2711,7 +2711,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
},
|
||||
{
|
||||
name: 'popupComponent',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
name: 'popupContent',
|
||||
@ -2996,7 +2996,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
},
|
||||
{
|
||||
name: 'popupComponent',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
name: 'popupContent',
|
||||
@ -3059,12 +3059,12 @@ Generated by [AVA](https://avajs.dev).
|
||||
{
|
||||
description: '日期值(受控)moment 对象',
|
||||
name: 'value',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
description: '初始日期值,moment 对象',
|
||||
name: 'defaultValue',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
defaultValue: 'YYYY-MM',
|
||||
@ -3212,7 +3212,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
},
|
||||
{
|
||||
name: 'popupComponent',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
name: 'popupContent',
|
||||
@ -3270,12 +3270,12 @@ Generated by [AVA](https://avajs.dev).
|
||||
{
|
||||
description: '日期值(受控)moment 对象',
|
||||
name: 'value',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
description: '初始日期值,moment 对象',
|
||||
name: 'defaultValue',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
defaultValue: 'YYYY',
|
||||
@ -3418,7 +3418,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
},
|
||||
{
|
||||
name: 'popupComponent',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
name: 'popupContent',
|
||||
@ -3485,12 +3485,12 @@ Generated by [AVA](https://avajs.dev).
|
||||
{
|
||||
description: '日期值(受控)moment 对象',
|
||||
name: 'value',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
description: '初始日期值,moment 对象',
|
||||
name: 'defaultValue',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
defaultValue: 'YYYY-wo',
|
||||
@ -3639,7 +3639,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
},
|
||||
{
|
||||
name: 'popupComponent',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
name: 'popupContent',
|
||||
@ -5011,6 +5011,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
propType: {
|
||||
type: 'oneOfType',
|
||||
value: [
|
||||
'number',
|
||||
{
|
||||
type: 'oneOf',
|
||||
value: [
|
||||
@ -5025,7 +5026,6 @@ Generated by [AVA](https://avajs.dev).
|
||||
'inherit',
|
||||
],
|
||||
},
|
||||
'number',
|
||||
],
|
||||
},
|
||||
},
|
||||
@ -10159,12 +10159,12 @@ Generated by [AVA](https://avajs.dev).
|
||||
{
|
||||
description: '时间值(moment 对象或时间字符串,受控状态使用)',
|
||||
name: 'value',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
description: '时间初值(moment 对象或时间字符串,非受控状态使用)',
|
||||
name: 'defaultValue',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
defaultValue: 'medium',
|
||||
@ -10319,7 +10319,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
},
|
||||
{
|
||||
name: 'popupComponent',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
name: 'popupContent',
|
||||
@ -11233,7 +11233,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
defaultValue: 'article',
|
||||
description: '设置标签类型',
|
||||
name: 'component',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
],
|
||||
screenshot: '',
|
||||
@ -11261,7 +11261,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
defaultValue: 'p',
|
||||
description: '设置标签类型',
|
||||
name: 'component',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
defaultValue: 'long',
|
||||
@ -11327,7 +11327,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
defaultValue: 'span',
|
||||
description: '设置标签类型',
|
||||
name: 'component',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
name: 'children',
|
||||
@ -12171,6 +12171,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
propType: {
|
||||
type: 'oneOfType',
|
||||
value: [
|
||||
'number',
|
||||
{
|
||||
type: 'oneOf',
|
||||
value: [
|
||||
@ -12179,7 +12180,6 @@ Generated by [AVA](https://avajs.dev).
|
||||
'large',
|
||||
],
|
||||
},
|
||||
'number',
|
||||
],
|
||||
},
|
||||
},
|
||||
@ -12290,7 +12290,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
defaultValue: 'div',
|
||||
description: '设置标签类型',
|
||||
name: 'component',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
],
|
||||
screenshot: '',
|
||||
@ -12341,7 +12341,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
defaultValue: 'div',
|
||||
description: '设置标签类型',
|
||||
name: 'component',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
],
|
||||
screenshot: '',
|
||||
|
||||
Binary file not shown.
@ -357,7 +357,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
},
|
||||
{
|
||||
name: 'optionalElementType',
|
||||
propType: 'any',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
name: 'optionalMessage',
|
||||
@ -475,6 +475,60 @@ Generated by [AVA](https://avajs.dev).
|
||||
},
|
||||
]
|
||||
|
||||
## ts component 2 by local
|
||||
|
||||
> Snapshot 1
|
||||
|
||||
[
|
||||
{
|
||||
componentName: 'default',
|
||||
devMode: 'proCode',
|
||||
docUrl: '',
|
||||
npm: {
|
||||
destructuring: false,
|
||||
exportName: 'default',
|
||||
main: 'src/index.tsx',
|
||||
package: '@alife/empty',
|
||||
subName: '',
|
||||
version: '1.0.1',
|
||||
},
|
||||
props: [
|
||||
{
|
||||
name: 'className',
|
||||
propType: 'string',
|
||||
},
|
||||
{
|
||||
name: 'style',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
name: 'imageStyle',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
name: 'image',
|
||||
propType: 'node',
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
propType: 'node',
|
||||
},
|
||||
{
|
||||
name: 'type',
|
||||
propType: {
|
||||
type: 'oneOf',
|
||||
value: [
|
||||
'default',
|
||||
'custom',
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
screenshot: '',
|
||||
title: '@alife/empty',
|
||||
},
|
||||
]
|
||||
|
||||
## ts component by local
|
||||
|
||||
> Snapshot 1
|
||||
@ -493,10 +547,402 @@ Generated by [AVA](https://avajs.dev).
|
||||
version: '1.0.0',
|
||||
},
|
||||
props: [
|
||||
{
|
||||
name: 'object',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'object',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'trigger',
|
||||
propType: {
|
||||
type: 'arrayOf',
|
||||
value: {
|
||||
type: 'oneOf',
|
||||
value: [
|
||||
'click',
|
||||
'hover',
|
||||
'contextMenu',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'str',
|
||||
propType: 'string',
|
||||
},
|
||||
{
|
||||
name: 'num',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'number',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'gender',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'oneOf',
|
||||
value: [
|
||||
0,
|
||||
1,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'any',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'any',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'bool',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'bool',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'tuple',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'object',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'enum',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'oneOf',
|
||||
value: [
|
||||
'red',
|
||||
'yellow',
|
||||
'green',
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'arr',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'arrayOf',
|
||||
value: 'number',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'halfEmptyObj',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'shape',
|
||||
value: [
|
||||
{
|
||||
name: 'fun',
|
||||
propType: {
|
||||
raw: '(a: string[]) => void',
|
||||
type: 'func',
|
||||
value: [
|
||||
{
|
||||
name: 'a',
|
||||
propType: {
|
||||
type: 'arrayOf',
|
||||
value: 'string',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'emptyObj',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'object',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'func',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
raw: '{ (arg: string): number; (a: string): Element; }',
|
||||
type: 'func',
|
||||
value: [
|
||||
{
|
||||
name: 'arg',
|
||||
propType: 'string',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'funcs',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'shape',
|
||||
value: [
|
||||
{
|
||||
name: 'n',
|
||||
propType: {
|
||||
raw: '() => number',
|
||||
type: 'func',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'a',
|
||||
propType: {
|
||||
raw: '(arg: string, num: number) => void',
|
||||
type: 'func',
|
||||
value: [
|
||||
{
|
||||
name: 'arg',
|
||||
propType: 'string',
|
||||
},
|
||||
{
|
||||
name: 'num',
|
||||
propType: 'number',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'fuzzy',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'oneOfType',
|
||||
value: [
|
||||
'number',
|
||||
'bool',
|
||||
{
|
||||
type: 'shape',
|
||||
value: [
|
||||
{
|
||||
name: 'a',
|
||||
propType: 'any',
|
||||
},
|
||||
{
|
||||
name: 'sa',
|
||||
propType: {
|
||||
type: 'arrayOf',
|
||||
value: 'string',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'oneOf',
|
||||
value: [
|
||||
'number',
|
||||
'object',
|
||||
'test',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'oneOf',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'oneOfType',
|
||||
value: [
|
||||
'bool',
|
||||
{
|
||||
type: 'shape',
|
||||
value: [
|
||||
{
|
||||
name: 's',
|
||||
propType: 'string',
|
||||
},
|
||||
{
|
||||
name: 'n',
|
||||
propType: 'number',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'oneOf',
|
||||
value: [
|
||||
'test',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'refFunc',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
raw: '(p: Props) => void',
|
||||
type: 'func',
|
||||
value: [
|
||||
{
|
||||
name: 'p',
|
||||
propType: 'object',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'elementOrOther',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'oneOfType',
|
||||
value: [
|
||||
'element',
|
||||
{
|
||||
raw: 'Func',
|
||||
type: 'func',
|
||||
value: [
|
||||
{
|
||||
name: 'a',
|
||||
propType: 'string',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'obj',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'shape',
|
||||
value: [
|
||||
{
|
||||
name: 'a',
|
||||
propType: 'number',
|
||||
},
|
||||
{
|
||||
name: 'arrOfStr',
|
||||
propType: {
|
||||
type: 'arrayOf',
|
||||
value: 'string',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'arrOfObj',
|
||||
propType: {
|
||||
type: 'arrayOf',
|
||||
value: {
|
||||
type: 'shape',
|
||||
value: [
|
||||
{
|
||||
name: 's',
|
||||
propType: 'string',
|
||||
},
|
||||
{
|
||||
name: 'n',
|
||||
propType: 'number',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'func',
|
||||
propType: 'func',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'objOf',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'objectOf',
|
||||
value: 'number',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'exact',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'shape',
|
||||
value: [
|
||||
{
|
||||
name: 'a',
|
||||
propType: 'number',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'node',
|
||||
propType: 'node',
|
||||
},
|
||||
{
|
||||
name: 'element',
|
||||
propType: 'element',
|
||||
},
|
||||
{
|
||||
name: 'elementType',
|
||||
propType: 'object',
|
||||
},
|
||||
{
|
||||
name: 'union',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'oneOfType',
|
||||
value: [
|
||||
'string',
|
||||
'number',
|
||||
{
|
||||
type: 'shape',
|
||||
value: [
|
||||
{
|
||||
name: 'a',
|
||||
propType: 'string',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'func2',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
raw: 'Func',
|
||||
type: 'func',
|
||||
value: [
|
||||
{
|
||||
name: 'a',
|
||||
propType: 'string',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'html',
|
||||
propType: {
|
||||
isRequired: true,
|
||||
type: 'object',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'loading',
|
||||
propType: {
|
||||
type: 'oneOfType',
|
||||
value: [
|
||||
'bool',
|
||||
{
|
||||
type: 'shape',
|
||||
value: [
|
||||
{
|
||||
name: 'delay',
|
||||
propType: 'number',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
screenshot: '',
|
||||
title: 'ts-component',
|
||||
|
||||
Binary file not shown.
@ -46,21 +46,24 @@ export type AnchorContainer = HTMLElement | Window;
|
||||
|
||||
interface AnchorProps {
|
||||
prefixCls?: string;
|
||||
// className?: string;
|
||||
// style?: React.CSSProperties;
|
||||
// children?: React.ReactNode;
|
||||
// offsetTop?: number;
|
||||
// bounds?: number;
|
||||
// affix?: boolean;
|
||||
// showInkInFixed?: boolean;
|
||||
// getContainer?: () => AnchorContainer;
|
||||
// /** Return customize highlight anchor */
|
||||
// getCurrentAnchor?: () => string;
|
||||
// onClick?: (e: React.MouseEvent<HTMLElement>, link: { title: React.ReactNode; href: string }) => void;
|
||||
// /** Scroll to target offset value, if none, it's offsetTop prop value or 0. */
|
||||
// targetOffset?: number;
|
||||
// /** Listening event when scrolling change active link */
|
||||
// onChange?: (currentActiveLink: string) => void;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
children?: React.ReactNode;
|
||||
offsetTop?: number;
|
||||
bounds?: number;
|
||||
affix?: boolean;
|
||||
showInkInFixed?: boolean;
|
||||
getContainer?: () => AnchorContainer;
|
||||
/** Return customize highlight anchor */
|
||||
getCurrentAnchor?: () => string;
|
||||
onClick?: (
|
||||
e: React.MouseEvent<HTMLElement>,
|
||||
link: { title: React.ReactNode; href: string },
|
||||
) => void;
|
||||
/** Scroll to target offset value, if none, it's offsetTop prop value or 0. */
|
||||
targetOffset?: number;
|
||||
/** Listening event when scrolling change active link */
|
||||
onChange?: (currentActiveLink: string) => void;
|
||||
}
|
||||
|
||||
interface AnchorState {
|
||||
@ -79,7 +82,10 @@ interface AntAnchor {
|
||||
unregisterLink: (link: string) => void;
|
||||
activeLink: string | null;
|
||||
scrollTo: (link: string) => void;
|
||||
onClick?: (e: React.MouseEvent<HTMLElement>, link: { title: React.ReactNode; href: string }) => void;
|
||||
onClick?: (
|
||||
e: React.MouseEvent<HTMLElement>,
|
||||
link: { title: React.ReactNode; href: string },
|
||||
) => void;
|
||||
}
|
||||
|
||||
export default class Anchor extends React.Component<AnchorProps, AnchorState> {
|
||||
@ -249,7 +255,10 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
|
||||
return;
|
||||
}
|
||||
const { offsetTop, bounds, targetOffset } = this.props;
|
||||
const currentActiveLink = this.getCurrentAnchor(targetOffset !== undefined ? targetOffset : offsetTop || 0, bounds);
|
||||
const currentActiveLink = this.getCurrentAnchor(
|
||||
targetOffset !== undefined ? targetOffset : offsetTop || 0,
|
||||
bounds,
|
||||
);
|
||||
this.setCurrentActiveLink(currentActiveLink);
|
||||
};
|
||||
|
||||
|
||||
@ -1,40 +1,9 @@
|
||||
import * as React from 'react';
|
||||
import App from './main-module';
|
||||
import SubModule from './sub-module';
|
||||
|
||||
enum Gender {
|
||||
MALE,
|
||||
FEMALE,
|
||||
}
|
||||
|
||||
interface Props {
|
||||
// str?: string;
|
||||
// num: number;
|
||||
// gender: Gender;
|
||||
// any: any;
|
||||
// bool: boolean;
|
||||
// tuple: [1, 'str', true];
|
||||
// enum: 'red' | 'yellow' | 'green';
|
||||
// arr: number[];
|
||||
// obj: {
|
||||
// a: number;
|
||||
// [k: string]: number;
|
||||
// };
|
||||
// objOf: {
|
||||
// [k: string]: number;
|
||||
// };
|
||||
// exact: {
|
||||
// a: number;
|
||||
// };
|
||||
// empty: {};
|
||||
node?: React.ReactNode;
|
||||
// element?: JSX.Element;
|
||||
// elementType?: React.ElementType;
|
||||
}
|
||||
|
||||
const App = (props: Props) => {
|
||||
return <div>hello</div>;
|
||||
App.SubModule = SubModule;
|
||||
App.defaultProps = {
|
||||
str: 'str2',
|
||||
};
|
||||
|
||||
App.SubModule = SubModule;
|
||||
|
||||
export default App;
|
||||
|
||||
102
packages/material-parser/test/fixtures/ts-component/src/main-module.tsx
vendored
Normal file
102
packages/material-parser/test/fixtures/ts-component/src/main-module.tsx
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
/* eslint-disable @typescript-eslint/indent */
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable @typescript-eslint/member-ordering */
|
||||
import * as React from 'react';
|
||||
import SubModule from './sub-module';
|
||||
|
||||
enum Gender {
|
||||
MALE,
|
||||
FEMALE,
|
||||
}
|
||||
|
||||
interface Obj {
|
||||
s: string;
|
||||
n: number;
|
||||
}
|
||||
|
||||
type Func = (a: string) => JSX.Element;
|
||||
type Union =
|
||||
| string
|
||||
| number
|
||||
| {
|
||||
a: string;
|
||||
};
|
||||
|
||||
interface Props {
|
||||
object: Object;
|
||||
trigger?: Array<'click' | 'hover' | 'contextMenu'>;
|
||||
str?: string;
|
||||
num: number;
|
||||
gender: Gender;
|
||||
any: any;
|
||||
bool: boolean;
|
||||
tuple: [number, string, true];
|
||||
enum: 'red' | 'yellow' | 'green';
|
||||
arr: number[];
|
||||
halfEmptyObj: {
|
||||
[k: string]: any;
|
||||
fun(a: string[]): void;
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
emptyObj: {};
|
||||
func(arg: string): number;
|
||||
funcs: {
|
||||
n(): number;
|
||||
a(arg: string, num: number): void;
|
||||
};
|
||||
fuzzy:
|
||||
| boolean
|
||||
| 'object'
|
||||
| number
|
||||
| 'number'
|
||||
| 'test'
|
||||
| {
|
||||
a: any;
|
||||
sa: string[];
|
||||
};
|
||||
oneOf: boolean | 'test' | Obj;
|
||||
refFunc(p: Props): void;
|
||||
elementOrOther: JSX.Element | Func;
|
||||
obj: {
|
||||
a: number;
|
||||
arrOfStr: string[];
|
||||
arrOfObj: Obj[];
|
||||
func: () => void;
|
||||
};
|
||||
objOf: {
|
||||
[k: string]: number;
|
||||
};
|
||||
exact: {
|
||||
a: number;
|
||||
};
|
||||
node?: React.ReactNode;
|
||||
element?: JSX.Element;
|
||||
elementType?: React.ElementType;
|
||||
union: Union;
|
||||
// eslint-disable-next-line @typescript-eslint/adjacent-overload-signatures
|
||||
func(a: string): JSX.Element;
|
||||
func2: Func;
|
||||
html: HTMLBaseElement;
|
||||
loading?: boolean | { delay?: number };
|
||||
}
|
||||
|
||||
interface AppProps extends React.FC<Props> {
|
||||
SubModule?: typeof SubModule;
|
||||
}
|
||||
const App: AppProps = () => {
|
||||
return <div>hello</div>;
|
||||
};
|
||||
|
||||
App.defaultProps = {
|
||||
object: {
|
||||
a: '1',
|
||||
b: '2',
|
||||
},
|
||||
func(a) {
|
||||
return a;
|
||||
},
|
||||
str: 'str',
|
||||
};
|
||||
|
||||
export default App;
|
||||
@ -4,6 +4,19 @@ interface Props {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export default function SubModule({ name }: Props) {
|
||||
return <div>hello, {name}</div>;
|
||||
class SubModule extends React.Component<Props> {
|
||||
static defaultProps = {
|
||||
name: 'abc',
|
||||
};
|
||||
|
||||
render() {
|
||||
const { name } = this.props;
|
||||
return <div>hello, {name}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
SubModule.defaultProps = {
|
||||
name: 'abc',
|
||||
};
|
||||
|
||||
export default SubModule;
|
||||
|
||||
63
packages/material-parser/test/fixtures/ts-component2/package.json
vendored
Normal file
63
packages/material-parser/test/fixtures/ts-component2/package.json
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
{
|
||||
"name": "@alife/empty",
|
||||
"version": "1.0.1",
|
||||
"description": "空组件",
|
||||
"files": [
|
||||
"demo/",
|
||||
"es/",
|
||||
"lib/",
|
||||
"build/",
|
||||
"dist",
|
||||
"material-meta.json"
|
||||
],
|
||||
"main": "src/index.tsx",
|
||||
"module": "src/index.tsx",
|
||||
"stylePath": "style.js",
|
||||
"scripts": {
|
||||
"start": "build-scripts start",
|
||||
"build": "build-scripts build",
|
||||
"test": "build-scripts test",
|
||||
"prepublishOnly": "npm run build",
|
||||
"doc": "react-doc-gen",
|
||||
"lint": "eslint --cache --ext .js,.jsx ./"
|
||||
},
|
||||
"keywords": [
|
||||
"ice",
|
||||
"react",
|
||||
"component"
|
||||
],
|
||||
"dependencies": {
|
||||
"classnames": "^2.2.6",
|
||||
"prop-types": "^15.5.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@alife/build-plugin-lowcode": "^1.0.7",
|
||||
"@alib/build-scripts": "^0.1.3",
|
||||
"@alifd/adaptor-generate": "^0.1.3",
|
||||
"build-plugin-component": "^0.2.0",
|
||||
"build-plugin-fusion": "^0.1.0",
|
||||
"build-plugin-fusion-cool": "^0.1.0",
|
||||
"build-plugin-moment-locales": "^0.1.0",
|
||||
"react": "^16.3.0",
|
||||
"react-dom": "^16.3.0",
|
||||
"@ice/spec": "^1.0.0",
|
||||
"eslint": "^6.0.1",
|
||||
"@alifd/next": "1.x",
|
||||
"@types/react": "^16.9.13",
|
||||
"@types/react-dom": "^16.9.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.3.0",
|
||||
"@alifd/next": "1.x"
|
||||
},
|
||||
"componentConfig": {
|
||||
"name": "Empty",
|
||||
"title": "empty",
|
||||
"category": "DataDisplay"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npm.alibaba-inc.com"
|
||||
},
|
||||
"license": "MIT",
|
||||
"homepage": "https://unpkg.alibaba-inc.com/@alife/empty@1.0.1/build/index.html"
|
||||
}
|
||||
22
packages/material-parser/test/fixtures/ts-component2/src/empty.tsx
vendored
Normal file
22
packages/material-parser/test/fixtures/ts-component2/src/empty.tsx
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import './index';
|
||||
interface DefaultEmptyImg {
|
||||
className?: string;
|
||||
imageStyle?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export const DefaultEmptyImg = (props: DefaultEmptyImg) => {
|
||||
const { className, imageStyle, ...restProps } = props;
|
||||
const prefixCls = 'design-empty-default';
|
||||
const alt = 'empty';
|
||||
|
||||
return (
|
||||
<div className={classNames(prefixCls, className)} {...restProps}>
|
||||
<div className={`${prefixCls}-image`} style={imageStyle}>
|
||||
<img alt={alt} src="https://img.alicdn.com/tfs/TB13G0LTNv1gK0jSZFFXXb0sXXa-54-54.svg" />
|
||||
</div>
|
||||
<p className={`${prefixCls}-description`}>暂时没有数据</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
49
packages/material-parser/test/fixtures/ts-component2/src/index.scss
vendored
Normal file
49
packages/material-parser/test/fixtures/ts-component2/src/index.scss
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
.design-empty {
|
||||
margin: 0 8px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5715;
|
||||
text-align: center;
|
||||
|
||||
&-image {
|
||||
height: 200px;
|
||||
margin-bottom: 4px;
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
svg {
|
||||
height: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&-description {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&-footer {
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.design-empty-default {
|
||||
margin: 0 8px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5715;
|
||||
text-align: center;
|
||||
|
||||
&-image {
|
||||
height: 54px;
|
||||
margin-bottom: 8px;
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&-description {
|
||||
font-size: 14px;
|
||||
color: #c2c2c2;
|
||||
}
|
||||
}
|
||||
71
packages/material-parser/test/fixtures/ts-component2/src/index.tsx
vendored
Normal file
71
packages/material-parser/test/fixtures/ts-component2/src/index.tsx
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { DefaultEmptyImg } from './empty';
|
||||
|
||||
export interface EmptyProps {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
imageStyle?: React.CSSProperties;
|
||||
image?: React.ReactNode | string;
|
||||
description?: React.ReactNode;
|
||||
children?: React.ReactNode;
|
||||
type?: 'default' | 'custom'; // default 默认, custom 表示自定义
|
||||
}
|
||||
|
||||
const prefixCls = 'design-empty';
|
||||
interface EmptyType extends React.FC<EmptyProps> {
|
||||
IMAGE_TYPE_SERVERBUSY: string; //服务器繁忙
|
||||
IMAGE_TYPE_SERVERNOFOUND: string; // 404
|
||||
IMAGE_TYPE_FILENOFOUND: string; //文件不存在
|
||||
IMAGE_TYPE_PROJECTNOFOUND: string; // 项目不存在
|
||||
IMAGE_TYPE_EMPTY: string; //空
|
||||
}
|
||||
|
||||
const Empty: EmptyType = (props: EmptyProps) => {
|
||||
const {
|
||||
className,
|
||||
image = 'Empty.IMAGE_TYPE_EMPTY',
|
||||
description,
|
||||
children,
|
||||
imageStyle,
|
||||
type = 'custom',
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
if (type === 'default') {
|
||||
return <DefaultEmptyImg />;
|
||||
}
|
||||
|
||||
let imageNode: React.ReactNode = null;
|
||||
const alt = typeof description === 'string' ? description : 'empty';
|
||||
|
||||
if (typeof image === 'string') {
|
||||
imageNode = <img alt={alt} src={image} />;
|
||||
} else {
|
||||
imageNode = image;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classNames(prefixCls, className)} {...restProps}>
|
||||
<div className={`${prefixCls}-image`} style={imageStyle}>
|
||||
{imageNode}
|
||||
</div>
|
||||
{description && <p className={`${prefixCls}-description`}>{description}</p>}
|
||||
{children && <div className={`${prefixCls}-footer`}>{children}</div>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
//服务器繁忙
|
||||
Empty.IMAGE_TYPE_SERVERBUSY = 'https://img.alicdn.com/tfs/TB1qPJvTFY7gK0jSZKzXXaikpXa-400-400.png';
|
||||
//404
|
||||
Empty.IMAGE_TYPE_SERVERNOFOUND =
|
||||
'https://img.alicdn.com/tfs/TB18gVGTUH1gK0jSZSyXXXtlpXa-400-400.png';
|
||||
//文件不存在
|
||||
Empty.IMAGE_TYPE_FILENOFOUND = 'https://img.alicdn.com/tfs/TB1.ClQTUT1gK0jSZFrXXcNCXXa-400-400.png';
|
||||
//项目不存在
|
||||
Empty.IMAGE_TYPE_PROJECTNOFOUND =
|
||||
'https://img.alicdn.com/tfs/TB1ZWumfcieb18jSZFvXXaI3FXa-400-400.png';
|
||||
//空
|
||||
Empty.IMAGE_TYPE_EMPTY = 'https://img.alicdn.com/tfs/TB13G0LTNv1gK0jSZFFXXb0sXXa-54-54.svg';
|
||||
export default Empty;
|
||||
@ -6,6 +6,7 @@ import { getFromFixtures } from './helpers';
|
||||
const multiExportedComptPath = getFromFixtures('multiple-exported-component');
|
||||
const singleExportedComptPath = getFromFixtures('single-exported-component');
|
||||
const tsComponent = getFromFixtures('ts-component');
|
||||
const tsComponent2 = getFromFixtures('ts-component2');
|
||||
|
||||
test('materialize single exported component by local', async t => {
|
||||
const options: IMaterializeOptions = {
|
||||
@ -39,3 +40,14 @@ test('ts component by local', async t => {
|
||||
|
||||
t.snapshot(actual);
|
||||
});
|
||||
|
||||
test('ts component 2 by local', async t => {
|
||||
const options: IMaterializeOptions = {
|
||||
entry: tsComponent2,
|
||||
accesser: 'local',
|
||||
};
|
||||
|
||||
const actual = await parse(options);
|
||||
|
||||
t.snapshot(actual);
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user