Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,12 @@ type PropFilter = (prop: PropItem, component: Component) => boolean;

const options = {
propFilter: (prop: PropItem, component: Component) => {
if (prop.parent) {
return !prop.parent.fileName.includes("node_modules");
if (prop.declarations !== undefined && prop.declarations.length > 0) {
const hasPropAdditionalDescription = prop.declarations.find((declaration) => {
return !declaration.fileName.includes("node_modules");
});

return Boolean(hasPropAdditionalDescription);
}

return true;
Expand Down
14 changes: 14 additions & 0 deletions src/__tests__/data/ButtonWithOnClickComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { FC, PropsWithRef } from 'react';

type HTMLButtonProps = JSX.IntrinsicElements['button'];

type Props = HTMLButtonProps & {
/** onClick event handler */
onClick?: HTMLButtonProps['onClick'];
};

const ButtonWithOnClickComponent: FC<Props> = props => {
return <button {...props} />;
};

export default ButtonWithOnClickComponent;
8 changes: 5 additions & 3 deletions src/__tests__/data/ColumnWithStaticComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ interface LabelProps {
}

/** Column.Label description */
const SubComponent = (props: LabelProps) => <div>My Property = {props.title}</div>;
const SubComponent = (props: LabelProps) => (
<div>My Property = {props.title}</div>
);

/**
* Column properties.
Expand All @@ -24,8 +26,8 @@ export class Column extends React.Component<IColumnProps, {}> {

/** Column.SubLabel description */
public static SubLabel() {
return <div>sub</div>
};
return <div>sub</div>;
}

public render() {
const { prop1 } = this.props;
Expand Down
19 changes: 10 additions & 9 deletions src/__tests__/data/ComplexGenericUnionIntersection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,23 @@ declare type PropsOf<
> = JSX.LibraryManagedAttributes<E, React.ComponentPropsWithoutRef<E>>;

/** Props for a Box component that supports the "innerRef" and "as" props. */
type BoxProps<E extends React.ElementType, P = any> = P & PropsOf<E> & {
/** Render the component as another component */
as?: E;
};
type BoxProps<E extends React.ElementType, P = any> = P &
PropsOf<E> & {
/** Render the component as another component */
as?: E;
};

interface StackBaseProps {
/** The flex "align" property */
align?: "stretch" | "center" | "flex-start" | "flex-end";
align?: 'stretch' | 'center' | 'flex-start' | 'flex-end';
}

interface StackJustifyProps {
/**
* Use flex 'space-between' | 'space-around' | 'space-evenly' and
* flex will space the children.
*/
justify?: "space-between" | "space-around" | "space-evenly";
justify?: 'space-between' | 'space-around' | 'space-evenly';
/** You cannot use gap when using a "space" justify property */
gap?: never;
}
Expand All @@ -28,18 +29,18 @@ interface StackGapProps {
* Use flex 'center' | 'flex-start' | 'flex-end' | 'stretch' with
* a gap between each child.
*/
justify?: "center" | "flex-start" | "flex-end" | "stretch";
justify?: 'center' | 'flex-start' | 'flex-end' | 'stretch';
/** The space between children */
gap?: number | string;
}

type StackProps = StackBaseProps & (StackGapProps | StackJustifyProps);

const defaultElement = "div" as const;
const defaultElement = 'div' as const;

/** ComplexGenericUnionIntersection description */
export const ComplexGenericUnionIntersection = <
E extends React.ElementType = typeof defaultElement
>(
props: BoxProps<E, StackProps>
) => <div />;
) => <div />;
7 changes: 4 additions & 3 deletions src/__tests__/data/ForwardRefDefaultExportAtExport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ export interface ForwardRefDefaultExportProps {
}

/** ForwardRefDefaultExport description */
const ForwardRefDefaultExport = (props: ForwardRefDefaultExportProps, ref: React.Ref<HTMLDivElement>) => (
<div ref={ref}>My Property = {props.myProp}</div>
)
const ForwardRefDefaultExport = (
props: ForwardRefDefaultExportProps,
ref: React.Ref<HTMLDivElement>
) => <div ref={ref}>My Property = {props.myProp}</div>;

export default React.forwardRef(ForwardRefDefaultExport);
2 changes: 1 addition & 1 deletion src/__tests__/data/FunctionDeclarationVisibleName.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export interface JumbotronProps {

/**
* Awesome Jumbotron description
*
*
* @visibleName Awesome Jumbotron
*/
export function Jumbotron(props: JumbotronProps) {
Expand Down
5 changes: 2 additions & 3 deletions src/__tests__/data/HOCIntersectionProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ export interface HOCProps {
}

/** HOCIntersectionProps description */
export const HOCIntersectionProps: React.SFC<
HOCProps & HOCInjectedProps
> = props => <div />;
export const HOCIntersectionProps: React.SFC<HOCProps &
HOCInjectedProps> = props => <div />;

export default withHOC({})(HOCIntersectionProps);
5 changes: 2 additions & 3 deletions src/__tests__/data/StatelessIntersectionExternalProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ export interface StatelessProps {
}

/** StatelessIntersectionExternalProps description */
export const StatelessIntersectionExternalProps: React.SFC<
StatelessProps & ExternalOptionalComponentProps
> = props => <div />;
export const StatelessIntersectionExternalProps: React.SFC<StatelessProps &
ExternalOptionalComponentProps> = props => <div />;
5 changes: 2 additions & 3 deletions src/__tests__/data/StatelessIntersectionProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,5 @@ export interface StatelessMoreProps {
}

/** StatelessIntersectionProps description */
export const StatelessIntersectionProps: React.SFC<
StatelessProps & StatelessMoreProps
> = props => <div />;
export const StatelessIntersectionProps: React.SFC<StatelessProps &
StatelessMoreProps> = props => <div />;
6 changes: 3 additions & 3 deletions src/__tests__/data/StatelessShorthandDefaultProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ export interface StatelessShorthandDefaultPropsProps {
}

/** StatelessShorthandDefaultProps description */
export const StatelessShorthandDefaultProps: React.SFC<
StatelessShorthandDefaultPropsProps
> = props => <div />;
export const StatelessShorthandDefaultProps: React.SFC<StatelessShorthandDefaultPropsProps> = props => (
<div />
);

const shorthandProp = 123;

Expand Down
12 changes: 7 additions & 5 deletions src/__tests__/data/StatelessStaticComponents.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import * as React from "react";
import * as React from 'react';

interface LabelProps {
/** title description */
title: string;
}

/** StatelessStaticComponents.Label description */
const SubComponent = (props: LabelProps) => <div>My Property = {props.title}</div>;
const SubComponent = (props: LabelProps) => (
<div>My Property = {props.title}</div>
);

interface StatelessStaticComponentsProps {
/** myProp description */
myProp: string;
}

/** StatelessStaticComponents description */
export const StatelessStaticComponents = (props: StatelessStaticComponentsProps) => (
<div>My Property = {props.myProp}</div>
);
export const StatelessStaticComponents = (
props: StatelessStaticComponentsProps
) => <div>My Property = {props.myProp}</div>;

StatelessStaticComponents.Label = SubComponent;
6 changes: 3 additions & 3 deletions src/__tests__/data/StatelessWithDefaultOnlyJsDoc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ export interface StatelessWithDefaultOnlyJsDocProps {
myProp: string;
}
/** StatelessWithDefaultOnlyJsDoc description */
export const StatelessWithDefaultOnlyJsDoc: React.StatelessComponent<
StatelessWithDefaultOnlyJsDocProps
> = props => <div>My Property = {props.myProp}</div>;
export const StatelessWithDefaultOnlyJsDoc: React.StatelessComponent<StatelessWithDefaultOnlyJsDocProps> = props => (
<div>My Property = {props.myProp}</div>
);
6 changes: 3 additions & 3 deletions src/__tests__/data/StatelessWithDefaultProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ export interface StatelessWithDefaultPropsProps {
}

/** StatelessWithDefaultProps description */
export const StatelessWithDefaultProps: React.StatelessComponent<
StatelessWithDefaultPropsProps
> = props => <div>test</div>;
export const StatelessWithDefaultProps: React.StatelessComponent<StatelessWithDefaultPropsProps> = props => (
<div>test</div>
);

StatelessWithDefaultProps.defaultProps = {
sampleEnum: enumSample.HELLO,
Expand Down
6 changes: 3 additions & 3 deletions src/__tests__/data/StatelessWithDefaultPropsAsString.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ export interface StatelessWithDefaultPropsAsStringProps {
sampleUndefined?: undefined;
}

export const StatelessWithDefaultPropsAsString: React.StatelessComponent<
StatelessWithDefaultPropsAsStringProps
> = props => <div>test</div>;
export const StatelessWithDefaultPropsAsString: React.StatelessComponent<StatelessWithDefaultPropsAsStringProps> = props => (
<div>test</div>
);

StatelessWithDefaultPropsAsString.defaultProps = {
sampleFalse: false,
Expand Down
6 changes: 3 additions & 3 deletions src/__tests__/data/StatelessWithDefaultPropsTypescript3.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ export interface StatelessWithDefaultPropsProps {
}

/** StatelessWithDefaultProps description */
export const StatelessWithDefaultProps: React.StatelessComponent<
StatelessWithDefaultPropsProps
> = props => <div>test</div>;
export const StatelessWithDefaultProps: React.StatelessComponent<StatelessWithDefaultPropsProps> = props => (
<div>test</div>
);

StatelessWithDefaultProps.defaultProps = {
sampleEnum: enumSample.HELLO,
Expand Down
4 changes: 1 addition & 3 deletions src/__tests__/data/StatelessWithDestructuredPropsArrow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ export interface StatelessWithDefaultPropsProps {
}

/** StatelessWithDefaultProps description */
export const StatelessWithDefaultProps: React.StatelessComponent<
StatelessWithDefaultPropsProps
> = ({
export const StatelessWithDefaultProps: React.StatelessComponent<StatelessWithDefaultPropsProps> = ({
sampleEnum = enumSample.HELLO,
sampleFalse = false,
sampleNull = null,
Expand Down
72 changes: 66 additions & 6 deletions src/__tests__/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import {
import { check, checkComponent, fixturePath } from './testUtils';

describe('parser', () => {
const children = { type: 'ReactNode', required: false, description: '' };

it('should parse simple react class component', () => {
check('Column', {
Column: {
Expand Down Expand Up @@ -741,11 +739,11 @@ describe('parser', () => {
});
});

it("should parse functional component component defined as function as default export", () => {
check("FunctionDeclarationAsDefaultExport", {
it('should parse functional component component defined as function as default export', () => {
check('FunctionDeclarationAsDefaultExport', {
Jumbotron: {
prop1: { type: "string", required: true },
},
prop1: { type: 'string', required: true }
}
});
});

Expand Down Expand Up @@ -986,6 +984,68 @@ describe('parser', () => {
});
});

it('should collect all `onClick prop` parent declarations', done => {
assert.doesNotThrow(() => {
withDefaultConfig({
propFilter: prop => {
if (prop.name === 'onClick') {
assert.deepEqual(prop.declarations, [
{
fileName:
'react-docgen-typescript/node_modules/@types/react/index.d.ts',
name: 'DOMAttributes'
},
{
fileName:
'react-docgen-typescript/src/__tests__/data/ButtonWithOnClickComponent.tsx',
name: 'TypeLiteral'
}
]);

done();
}

return true;
}
}).parse(fixturePath('ButtonWithOnClickComponent'));
});
});

it('should allow filtering by parent declarations', () => {
const propFilter: PropFilter = prop => {
if (prop.declarations !== undefined && prop.declarations.length > 0) {
const hasPropAdditionalDescription = prop.declarations.find(
declaration => {
return !declaration.fileName.includes('@types/react');
}
);

return Boolean(hasPropAdditionalDescription);
}

return true;
};

check(
'ButtonWithOnClickComponent',
{
ButtonWithOnClickComponent: {
onClick: {
type:
'(event: MouseEvent<HTMLButtonElement, MouseEvent>) => void',
required: false,
description: 'onClick event handler'
}
}
},
true,
'',
{
propFilter
}
);
});

describe('skipPropsWithName', () => {
it('should skip a single property in skipPropsWithName', () => {
const propFilter = { skipPropsWithName: 'prop1' };
Expand Down
Loading