Skip to content

Commit 1bb1d07

Browse files
author
Aleksei Dmitriev
committed
feat: Add parents field to prop information
1 parent 760ecea commit 1bb1d07

File tree

4 files changed

+113
-15
lines changed

4 files changed

+113
-15
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,12 @@ type PropFilter = (prop: PropItem, component: Component) => boolean;
109109

110110
const options = {
111111
propFilter: (prop: PropItem, component: Component) => {
112-
if (prop.parent) {
113-
return !prop.parent.fileName.includes("node_modules");
112+
if (prop.parents !== undefined && prop.parents.length > 0) {
113+
const hasPropAdditionalDescription = prop.parents.find((parent) => {
114+
return !parent.fileName.includes("node_modules");
115+
});
116+
117+
return Boolean(hasPropAdditionalDescription);
114118
}
115119

116120
return true;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { FC, PropsWithRef } from 'react';
2+
3+
type HTMLButtonProps = JSX.IntrinsicElements['button'];
4+
5+
type Props = HTMLButtonProps & {
6+
/** onClick event handler */
7+
onClick?: HTMLButtonProps['onClick'];
8+
};
9+
10+
const ButtonWithOnClickComponent: FC<Props> = props => {
11+
return <button {...props} />;
12+
};
13+
14+
export default ButtonWithOnClickComponent;

src/__tests__/parser.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ import {
1212
import { check, checkComponent, fixturePath } from './testUtils';
1313

1414
describe('parser', () => {
15-
const children = { type: 'ReactNode', required: false, description: '' };
16-
1715
it('should parse simple react class component', () => {
1816
check('Column', {
1917
Column: {
@@ -986,6 +984,39 @@ describe('parser', () => {
986984
});
987985
});
988986

987+
it('should allow filtering by parent interfaces', () => {
988+
const propFilter: PropFilter = prop => {
989+
if (prop.parents !== undefined && prop.parents.length > 0) {
990+
const hasPropAdditionalDescription = prop.parents.find(parent => {
991+
return !parent.fileName.includes('@types/react');
992+
});
993+
994+
return Boolean(hasPropAdditionalDescription);
995+
}
996+
997+
return true;
998+
};
999+
1000+
check(
1001+
'ButtonWithOnClickComponent',
1002+
{
1003+
ButtonWithOnClickComponent: {
1004+
onClick: {
1005+
type:
1006+
'(event: MouseEvent<HTMLButtonElement, MouseEvent>) => void',
1007+
required: false,
1008+
description: 'onClick event handler'
1009+
}
1010+
}
1011+
},
1012+
true,
1013+
'',
1014+
{
1015+
propFilter
1016+
}
1017+
);
1018+
});
1019+
9891020
describe('skipPropsWithName', () => {
9901021
it('should skip a single property in skipPropsWithName', () => {
9911022
const propFilter = { skipPropsWithName: 'prop1' };

src/parser.ts

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import * as path from 'path';
33
import * as ts from 'typescript';
44

55
import { buildFilter } from './buildFilter';
6-
import { symbol } from 'prop-types';
7-
import { check } from './__tests__/testUtils';
86

97
// We'll use the currentDirectoryName to trim parent fileNames
108
const currentDirectoryPath = process.cwd();
@@ -32,6 +30,7 @@ export interface PropItem {
3230
description: string;
3331
defaultValue: any;
3432
parent?: ParentType;
33+
parents?: ParentType[];
3534
}
3635

3736
export interface Method {
@@ -643,6 +642,7 @@ export class Parser {
643642
}
644643

645644
const parent = getParentType(prop);
645+
const parents = getParentsType(prop);
646646
const declarations = prop.declarations || [];
647647
const baseProp = baseProps.find(p => p.getName() === propName);
648648

@@ -665,6 +665,7 @@ export class Parser {
665665
description: jsDocComment.fullComment,
666666
name: propName,
667667
parent,
668+
parents,
668669
required,
669670
type
670671
};
@@ -1137,23 +1138,48 @@ export function getDefaultExportForFile(source: ts.SourceFile) {
11371138
return identifier.length ? identifier : 'DefaultName';
11381139
}
11391140

1140-
function getParentType(prop: ts.Symbol): ParentType | undefined {
1141+
function isTypeLiteral(node: ts.Node): node is ts.TypeLiteralNode {
1142+
return node.kind === ts.SyntaxKind.TypeLiteral;
1143+
}
1144+
1145+
function getParentsType(prop: ts.Symbol): ParentType[] | undefined {
11411146
const declarations = prop.getDeclarations();
11421147

1143-
if (declarations == null || declarations.length === 0) {
1148+
if (declarations === undefined || declarations.length === 0) {
11441149
return undefined;
11451150
}
11461151

1147-
// Props can be declared only in one place
1148-
const { parent } = declarations[0];
1152+
const parents: ParentType[] = [];
11491153

1150-
if (!isInterfaceOrTypeAliasDeclaration(parent)) {
1151-
return undefined;
1154+
for (let declaration of declarations) {
1155+
const { parent } = declaration;
1156+
1157+
if (!isTypeLiteral(parent) && !isInterfaceOrTypeAliasDeclaration(parent)) {
1158+
continue;
1159+
}
1160+
1161+
type InterfaceOrTypeAlias =
1162+
| ts.TypeAliasDeclaration
1163+
| ts.InterfaceDeclaration;
1164+
1165+
const parentName =
1166+
'name' in parent
1167+
? (parent as InterfaceOrTypeAlias).name.text
1168+
: 'TypeLiteral';
1169+
const { fileName } = (parent as
1170+
| InterfaceOrTypeAlias
1171+
| ts.TypeLiteralNode).getSourceFile();
1172+
1173+
parents.push({
1174+
fileName: trimFileName(fileName),
1175+
name: parentName
1176+
});
11521177
}
11531178

1154-
const parentName = parent.name.text;
1155-
const { fileName } = parent.getSourceFile();
1179+
return parents;
1180+
}
11561181

1182+
function trimFileName(fileName: string) {
11571183
const fileNameParts = fileName.split('/');
11581184
const trimmedFileNameParts = fileNameParts.slice();
11591185

@@ -1170,8 +1196,31 @@ function getParentType(prop: ts.Symbol): ParentType | undefined {
11701196
trimmedFileName = fileName;
11711197
}
11721198

1199+
return trimmedFileName;
1200+
}
1201+
1202+
/**
1203+
* @deprecated
1204+
*/
1205+
function getParentType(prop: ts.Symbol): ParentType | undefined {
1206+
const declarations = prop.getDeclarations();
1207+
1208+
if (declarations == null || declarations.length === 0) {
1209+
return undefined;
1210+
}
1211+
1212+
// Props can be declared only in one place
1213+
const { parent } = declarations[0];
1214+
1215+
if (!isInterfaceOrTypeAliasDeclaration(parent)) {
1216+
return undefined;
1217+
}
1218+
1219+
const parentName = parent.name.text;
1220+
const { fileName } = parent.getSourceFile();
1221+
11731222
return {
1174-
fileName: trimmedFileName,
1223+
fileName: trimFileName(fileName),
11751224
name: parentName
11761225
};
11771226
}

0 commit comments

Comments
 (0)