Giter Club home page Giter Club logo

react-docgen-typescript's Introduction

react-docgen-typescript

Build Status

A simple parser for React properties defined in TypeScript instead of propTypes.

It can be used with React Styleguidist.

Installation

npm install --save-dev react-docgen-typescript

Usage

To parse a file for docgen information use the parse function.

const docgen = require("react-docgen-typescript");

const options = {
  savePropValueAsString: true,
};

// Parse a file for docgen info
docgen.parse("./path/to/component", options);

If you want to customize the typescript configuration or docgen options, this package exports a variety of ways to create custom parsers.

const docgen = require("react-docgen-typescript");

// Create a parser with the default typescript config and custom docgen options
const customParser = docgen.withDefaultConfig(options);

const docs = customParser.parse("./path/to/component");

// Create a parser with the custom typescript and custom docgen options
const customCompilerOptionsParser = docgen.withCompilerOptions(
  { esModuleInterop: true },
  options
);

// Create a parser with using your typescript config
const tsConfigParser = docgen.withCustomConfig("./tsconfig.json", {
  savePropValueAsString: true,
});

React Styleguidist integration

Include following line in your styleguide.config.js:

module.exports = {
  propsParser: require("react-docgen-typescript").withDefaultConfig([
    parserOptions,
  ]).parse,
};

or if you want to use custom tsconfig file

module.exports = {
  propsParser: require("react-docgen-typescript").withCustomConfig(
    "./tsconfig.json",
    [parserOptions]
  ).parse,
};

Options

propFilter

The propFilter option allows you to omit certain props from documentation generation.

You can either provide and object with some of our pre-configured filters:

interface FilterOptions {
  skipPropsWithName?: string[] | string;
  skipPropsWithoutDoc?: boolean;
}

const options = {
  propFilter: {
    skipPropsWithName: ['as', 'id'];
    skipPropsWithoutDoc: true;
  }
}

If you do not want to print out all the HTML attributes of a component typed like the following:

const MyComponent: React.FC<React.HTMLAttributes<HTMLDivElement>> = ()...

you can provide a propFilter function and do the filtering logic yourself.

type PropFilter = (prop: PropItem, component: Component) => boolean;

const options = {
  propFilter: (prop: PropItem, component: Component) => {
    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;
  },
};

Note: children without a doc comment will not be documented.

componentNameResolver

(exp: ts.Symbol, source: ts.SourceFile) => string | undefined | null | false;

If a string is returned, then the component will use that name. Else it will fallback to the default logic of parser.

shouldExtractLiteralValuesFromEnum: boolean

If set to true, string enums and unions will be converted to docgen enum format. Useful if you use Storybook and want to generate knobs automatically using addon-smart-knobs.

shouldExtractValuesFromUnion: boolean

If set to true, every unions will be converted to docgen enum format.

skipChildrenPropWithoutDoc: boolean (default: true)

If set to false the docs for the children prop will be generated even without an explicit description.

shouldRemoveUndefinedFromOptional: boolean

If set to true, types that are optional will not display " | undefined" in the type.

savePropValueAsString: boolean

If set to true, defaultValue to props will be string. Example:

Component.defaultProps = {
  counter: 123,
  disabled: false,
};

Will return:

  counter: {
      defaultValue: '123',
      required: true,
      type: 'number'
  },
  disabled: {
      defaultValue: 'false',
      required: true,
      type: 'boolean'
  }

Styled components example:

componentNameResolver: (exp, source) =>
  exp.getName() === "StyledComponentClass" && getDefaultExportForFile(source);

The parser exports getDefaultExportForFile helper through its public API.

Example

In the example folder you can see React Styleguidist integration.

Warning: only named exports are supported. If your project uses default exports, you still need to include named exports for react-docgen-typescript.

The component Column.tsx

import * as React from "react";
import { Component } from "react";

/**
 * Column properties.
 */
export interface IColumnProps {
  /** prop1 description */
  prop1?: string;
  /** prop2 description */
  prop2: number;
  /**
   * prop3 description
   */
  prop3: () => void;
  /** prop4 description */
  prop4: "option1" | "option2" | "option3";
}

/**
 * Form column.
 */
export class Column extends Component<IColumnProps, {}> {
  render() {
    return <div>Test</div>;
  }
}

Will generate the following stylesheet:

Stylesheet example

The functional component Grid.tsx

import * as React from "react";

/**
 * Grid properties.
 */
export interface IGridProps {
  /** prop1 description */
  prop1?: string;
  /** prop2 description */
  prop2: number;
  /**
   * prop3 description
   */
  prop3: () => void;
  /** Working grid description */
  prop4: "option1" | "option2" | "option3";
}

/**
 * Form Grid.
 */
export const Grid = (props: IGridProps) => {
  const smaller = () => {
    return;
  };
  return <div>Grid</div>;
};

Will generate the following stylesheet:

Stylesheet example

Contributions

The typescript is pretty complex and there are many different ways how to define components and their props so it's realy hard to support all these use cases. That means only one thing, contributions are highly welcome. Just keep in mind that each PR should also include tests for the part it's fixing.

Thanks to all contributors without their help there wouldn't be a single bug fixed or feature implemented. Check the contributors tab to find out more. All those people supported this project. THANK YOU!

Thanks to others

The integration with React Styleguidist wouldn't be possible without Vyacheslav Slinko pull request #118 at React Styleguidist.

react-docgen-typescript's People

Contributors

angular-moon avatar argshook avatar bebraw avatar benlorantfy avatar beroburny avatar carmnk avatar dependabot[bot] avatar diegolanda avatar dotcs avatar ecraig12345 avatar evless avatar fforres avatar havret avatar hipstersmoothie avatar jocd avatar kealjones-wk avatar kylemh avatar malcolm-kee avatar michelengelen avatar milesj avatar nekitk avatar pvasek avatar ron0115 avatar royston-shufflebotham-i2 avatar sapegin avatar shilman avatar skeate avatar strothj avatar thomasmost avatar trevorburnham avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-docgen-typescript's Issues

Ignore / exclude props from output

Hi there,

I'm working on a large component library that has to be very flexible, and therefore am defining my props in the following way to allow all the standard props, should users want to provide them:

export interface ButtonProps extends HTMLProps<HTMLButtonElement> {
  component?: string;
  block?: boolean;
  large?: boolean;
  small?: boolean;
}

Using this with styleguidist generates a huge list of props. Is there some way I can exclude these from the output? If not, would such a thing be possible?

Example output:

screen shot 2017-10-11 at 22 13 00

I'd be happy to try to add this feature, as well as fixing some of the other open issues.

How to use with React.SFC?

Sorry guys, but I can't figure out how to use react-docgen-typescript with React.SFC

Here is my code and I'm not getting anything back from react-docgen-typescript. It works when I change my component to Class, but it doesn't work when I'm using it as a stateless component.
Please advice. Thank you very much!

export type IconSize = 'default' | 'small' | 'medium' | 'large'
export type IconColor = 'inherit' | 'primary' | 'secondary' | 'success' | 'error' | 'warning' | 'disabled'

/**
 * Icon properties.
 */

export interface IconProps {
  /** type description */
  type: string
  /** className description */
  className?: string
  color?: IconColor
  size?: IconSize
  style?: object
}

/**
 * Icon Component.
 */

const Icon: React.SFC<IconProps> = ({
  type,
  className,
  size,
  color,
  style
}) => {
  const classes = classNames('oi', styles.base, {
    [`${styles[size]}`]: !!size,
    [`${styles[color]}`]: !!color
  }, className)

  return (
    <span
      className={classes}
      data-glyph={type}
      title={type}
      style={style}
      aria-hidden='true' />
  )
}

Icon.defaultProps = {
  size: 'medium'
}

Icon.displayName = 'Icon'

export default Icon

Documentation not inherited in Child Interface from Parent Interface.

I have my interfaces setup something like this in my Components.

// Helpers.tsx

type StringLiteralDiff<T extends string, U extends string> = ({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T];

export type Omit<T, K extends keyof T> = Pick<T, StringLiteralDiff<keyof T, K>>;

// ComponentA.tsx

/** Component A Properties */
export interface ComponentAProps {
    
    /** propA documentation */
    propA: string

    /** propB documentation */
    propB?: boolean

    /** propC documentation */
    propC?: string

    /** propD documentation */
    propD: () =>  void 

    /** propE documentation */
    propE?: string
}

/** ComponentA */
export class ComponentA extends React.Component<ComponentAProps, {}> {
    render() {
        return (...)
    }
}

// ComponentB.tsx
import { ComponentA, ComponentAProps } from "./ComponentA"
import { Omit } from "./Helpers"

/** @inheritdoc */
interface ComponentBProps extends Omit<ComponentAProps, 'propC' | 'propE' > {
     // All the prop definitions are extended here except 'propC' & 'propE'.
}

/** ComponentB */
export class ComponentB extends React.Component<ComponentBProps, {}> {
    render() {
        return (<ComponentA { ...this.props } />)
    }
}

Now when I build the documentation, the Props of ComponentA are documented correctly. But, the Props of ComponentB are not documented, i.e., the Documentation from interface ComponentAProps are not inherited to interfaceComponentBProps.

How should I inherit the documentation?

JSDoc tags missing from react-docgen-typescript output

JSDoc tags in comments on props (such as @ignore) are missed out by react-docgen-typescript.

Repro Case

With this component, styleguidist should be skipping property2 from the styleguide, but it's still shown.

import * as React from 'react';

interface IJsDocTagsDontWorkProps {
    /**
     * First property.
     */
    property1: string;

    /**
     * Second property.
     * @ignore
     */
    property2: string;
}

export class JsDocTagsDontWork extends React.PureComponent<IJsDocTagsDontWorkProps, undefined> {
    render() {
        return <div>Hello</div>;
    }
}

export default JsDocTagsDontWork;

Issue

I've had a very quick poke around... I suspect that the TypeScript compiler is being 'helpful' and is splitting JsDoc comments into two: the plain text part is returned by symbol.getDocumentationComment() but it removes JsDoc tags from the result of that call: they're instead returned by symbol.getJsDocTags().

react-docgen expects to receive a full JsDoc comment containing both the plain text and the tags (which it then parses), but right now, react-docgen-typescript only returns the plain text part because it's only calling getDocumentationComment(), meaning the JsDoc tags are just dropped.

Thanks!

@default annotation is not picked up unless description is present

If I have a jsdoc annotation with a description and a default, the @default annotation is picked up fine, e.g.

    /**
     * The size of the button.
     *
     * @default medium
     */
    size?: 'small' | 'medium';

image

However, if I remove the description, then the @default annotation is no longer picked up, e.g.

    /**
     * @default medium
     */
    size?: 'small' | 'medium';

image

Documenting referenced types

Hi!
First of all I'd like to start by saying that I really appreciate all the time and effort you've put in to building this!

In a project that I'm working on right now we would really benefit from being able to document referenced types. I have seen the existing issue, since I was unable to reopen it I'm writing here instead.

A possible solution to the UI problem might be to use the popover approach taken here for flow-types: styleguidist/react-styleguidist#781

It might not work for all cases, but at least it would be better than just displaying the name. If you think outputting JSDoc is a better approach, I'd be happy to contribute either the code and/or docs needed to get that working. Provided I can get some initial pointers on where to start :)

Best,
Jonatan

Property defaults value

Are there any ways to set property defaults values (not "required") or parse it from defaultProps of Component ?

Add support for composed component via HOC

Hi! We are using HOC and react-styleguidist on project. We expect to see all exported components in react-styleguidist documentation, but actually HOC-derived components are not loaded.

Version of "react-docgen-typescript": "0.0.5"

Here is our styleguidist.conf.js:

const path = require('path');
const webpackDevConf = require('./webpack-dev.conf');
module.exports = {
    title: 'Documentation',
    components: './../src/**/*.component.tsx',
    ignore:[
        '**/core/**'
    ],
    serverHost: 'localhost',
    serverPort: 3000,
    styleguideDir: path.resolve(__dirname, './../styleguide'),
    webpackConfig: webpackDevConf,
    propsParser: require('react-docgen-typescript').parse
};

And example of Component export using HOC:

import { timerHOC } from './timerHOC';
export const TimerDesktop = ( props: TimerDesktopProps) => {
    return (
        <div className="timer-desktop">
            ...
        </div>
    );
};
export const Timer = timerHOC(TimerDesktop);
export default Timer;

let declaration without assignment causes hard to find error

If I have the class:

import * as React from 'react';

export interface IReproProps {
    foo: any;
}
export class Repro extends React.Component<IReproProps, {}> {
    constructor(props) {
        super(props);
    }

    private repro() {
        let repro;
        repro = 1;
    }

    public render() {
        return(<div/>);
    }
}

Typescript is fine with that code, but using Styleguidist, react-docgen fails with the error:

Error when parsing src\components\repro\index.tsx: TypeError: Cannot read property 'kind' of undefined

It usually means that react-docgen cannot parse your source code, try to file an issue here:
https://github.com/reactjs/react-docgen/issues

And there's no line number for the error, just a file path.

Thanks,
Scott

Components with defined types not picked up

Components that have defined types aren't pickup in the styleguide.

const Button: React.StatelessComponent<ButtonProps> = ({ title }) => (
  <button className="button">{title}</button>
)

export default Button

The above example shows
Warning: src/components/Button/Button.tsx matches a pattern defined in “components” or “sections” options in your style guide config but doesn’t export a component.

It fails for React.Component as well:

class Button extends React.Component<ButtonProps> {
  render() {
    const { title } = this.props

    return <button className="button">{title}</button>
  }
}

export default Button

If I remove the prop definitions to

const Button = ({ title }: ButtonProps) => (
  <button className="button">{title}</button>
)

export default Button

It works again.

Versions:
"react-docgen-typescript": "^1.2.3",
"react-styleguidist": "^6.2.2",
"typescript": "^2.7.1",
"webpack": "^3.10.0"
"react": "^16.2.0"

Wrong name using StatelessComponent

Hi guys :),

I'm checking this project and I've found this small issue when I declare a StatelessComponent using this notation

import * as React from 'react';


interface IButton {
  /** prop1 */
  prop1: string;
}

const Button: React.SFC<IButton> = props => (
  <button>{props.prop1 || "1"}</button>
);

export default Button;

I see this output,

screen shot 2018-02-19 at 7 11 25 pm

But If I write the component using this notation, I get the right component name

export const Button: React.SFC<IButton> = props => (
  <button>{props.prop1 || "1"}</button>
);

screen shot 2018-02-19 at 7 12 59 pm

Is there a way to indicate the component name when I use the React.SFC<> interface?.

Thanks in advance

Props as types instead of interfaces are not supported

This example is based on the one in this project.

How to reproduce?

Add new file, FlippableImage.tsx:

import * as React from 'react';

export interface Props extends React.HTMLAttributes<HTMLImageElement> {
  /** whether the image is flipped horizontally */
  isFlippedX?: boolean;
  /** whether the image is flipped vertically */
  isFlippedY?: boolean;
}

/** An enhanced image component */
export const FlippableImage = (props: Props) => {
  const {
    src,
    isFlippedX = false,
    isFlippedY = false,
    style,
    ...rest,
  } = props;

  let transform = '';
  if (isFlippedX) {
    transform += ` scale(-1, 1)`;
  }
  if (isFlippedY) {
    transform += ` scale(1, -1)`;
  }

  return (
    <img
      src={src || undefined}
      style={{ ...style, transform }}
      {...rest}
    />
  );
};

export default FlippableImage;

This works as intended. However, when using type instead of interface, like this:

export type Props = React.HTMLAttributes<HTMLImageElement> & {
  /** whether the image is flipped horizontally */
  isFlippedX?: boolean;
  /** whether the image is flipped vertically */
  isFlippedY?: boolean;
}

I get the following error:

Error in ./components/FlippableImage.tsx
Module build failed: TypeError: Cannot read property 'methods' of null
 @ ./~/react-styleguidist/loaders/styleguide-loader.js!./~/react-styleguidist/lib/index.js 26:29-276
 @ ./~/react-styleguidist/lib/index.js
 @ multi ./~/react-styleguidist/lib/index ./~/react-dev-utils/webpackHotDevClient.js

Wrong component names in react-styleguideist

Hey, this tool makes i really easy to document the component using typescript as it's extracts the typescript definition of props into react-styleguidist in my case.

The problem is that it also somehow uses typescript in order to resolve the name of the components.

Case:

  1. I import and re-exporting semantic-ui components in my components folder.
  2. Points react-styleguideist to that components folder.
  3. Apply the the this typescript docgen in the config.

Now my component names went from "Dropdown" to "DropdownComponenet". This is only happening for the components imported form 'semantic-ui-react'. The components defined in the folder works awesome as expected :-)

Why is do the propParser have and impact on the component names and is i possible to turn the of so when only the propTypes is extracted and the component names stays the same as when using the normal react-docgen :-) ?

Without typescript version of react-docgen:
image
With typescript version of react-docgen:
image

Cannot find components in TSX files with default export.

I've got various components not being picked by the doc-gen, I get the message:

Warning: $component_path matches a pattern defined in “components” or “sections” options in your style guide config but doesn’t export a component.

I managed to make a reduced test case to reproduce the message by using default export. Oddly this seems to be really inconsistent in practise - I have plenty of components that are using default exports that appear to be being picked up no problem.

The following will not work (using default export only):

import * as React from 'react';

const MyComp: React.SFC<any> = () => {
  return <div />;
};

export default MyComp;

The following will work (using named export only):

import * as React from 'react';
export const MyComp: React.SFC<any> = () => {
  return <div />;
};

My styleguide.config.js is nothing special:

module.exports = {
  components: ...,
  propsParser: require('react-docgen-typescript').parse,
};

This may be specific to stateless functional components - I've not yet got a reliable repro using regular components

How to document referenced type

interface` Product {
  label: string;
  id: number;
}

interface Props {
  products: Product[]
}

export default class Category extends React.Component<Props>{}

will display type as Product[]

Thats not really helpful because I'm not able to document Product own its own (if I'm not mistaken). Am I missing something and it was somehow implemented?
Thank you.

Prop interface comments from other files not included

If my component imports an interface from another file to extend its props e.g.

import { GeneralProps } from './types';

interface MyComponentProps extends GeneralProps {
  foo: 'bar';
}

The comments from the other file are not included in the documentation.

I'd be happy to try to add this feature, as well as fixing some of the other open issues.

Problem with functional components

Hi!

Unfortunately, I can't use Styleguidist+DocGenTypescript for stateless functional components.

Here bug demo.

Example of working code (class component):

import * as React from 'react';
import * as styles from './Logo.styl';

export class Logo extends React.Component<any, any> {
    render() {
        return (
            <span className={styles.logo} />
        );
    }
}

export default Logo;

Just refactor if to SFC:

import * as React from 'react';
import * as styles from './Logo.styl';

export const Logo = () =>
    <span className={styles.logo} />;

export default Logo;

After that we got the error:

Error in ./src/components/common/Logo/Logo.tsx
Module build failed: TypeError: Cannot read property 'methods' of null
 @ ./~/react-styleguidist/loaders/styleguide-loader.js!./~/react-styleguidist/lib/index.js 43:29-195

console.log causes TypeError in parser

I'm using the react-docgen-typescript-loader in combination with storybook and webpack v4.

When I place a console.log statement inside a Component the compiler crashes with the following error:

Module build failed: TypeError: Cannot read property 'name' of undefined
    at /...project/node_modules/react-docgen-typescript/lib/parser.js:409:27
    at Array.filter (<anonymous>)
    at getTextValueOfFunctionProperty (/...project/node_modules/react-docgen-typescript/lib/parser.js:406:10)
    at computeComponentName (/...project/node_modules/react-docgen-typescript/src/parser.ts:627:32)
    at Parser.getComponentInfo (/...project/node_modules/react-docgen-typescript/src/parser.ts:211:29)
    at /...project/node_modules/react-docgen-typescript/src/parser.ts:137:28
    at Array.map (<anonymous>)
    at Object.parse (/...project/node_modules/react-docgen-typescript/src/parser.ts:137:10)
    at Object.processResource (/...project/node_modules/react-docgen-typescript-loader/dist/loader.js:69:32)
    at Object.loader (/...project/node_modules/react-docgen-typescript-loader/dist/loader.js:15:41)

For example it will fail to compile the following Component:

import React, { SFC } from 'react'

console.log('this log causes the compiler to fail!')

export const Header: SFC = ({ children, ...rest }) => <h1 {...rest}>{children}</h1>

Perhaps the getTextValueOfFunctionProperty should be wrapped in a trycatch? Or perhaps I'm missing something?

Any help would be much appreciated!

Thanks in advance!

Need to use TypeScript compiler to parse props properly

Hi there,

As my components get increasingly complex, I've been struggling to get react-docgen-typescript to parse them. In particular, I have

  • props interfaces extending other interfaces
  • components using ANDed (&) intersection props interfaces
  • higher-order components that change returned prop types

Right now, react-docgen-typescript can't cope with any of those because it's trying to look up interfaces by name by hand, and do other jiggery-pokery which can't work in the general case.

I think the only general solution to making this work properly is to engage the help of the TypeScript compiler itself to process the file and expose the type information. (It appears to be relatively little code to get the compiler to do that.)

I'd be happy to help out with modifying react-docgen-typescript to use this approach, but wanted to check in with you before beginning on it as it's not an entirely trivial change.

Proof of Concept

I've developed a little (~120 lines) proof of concept standalone app which is capable of parsing any component file I've thrown at it yet. It simply asks TypeScript to give it the resolved type for any exported objects, and can scan that and extract props successfully.

Demo app (both TS and the compiled JS): https://gist.github.com/RoystonS/f590f336643a782ac5abb5059817e06c

That app takes a filename as a parameter and parses the file. If you have an especially complex setup, it'll also optionally take a tsconfig file to aid the TS compiler, but works in most cases without it.

Sample nasty test component (indicative of the types we're using with glamorous) and the output from the program:
https://gist.github.com/RoystonS/92784110dc263de4eea5329142badc5d

So...

Would you be happy for me to begin modification of react-docgen-typescript on a branch, to use this approach? Or would you rather do it? As far as I can make out, it would close a number of existing issues too.

react-docgen-typescript causes styleguidist to bomb fatally if it can't parse props

Hi! Thanks very much for react-docgen-styleguidist. We're making good progress on creating a living style guide for our in-house documents thanks to it!

One blocking issue, however, is the impact on styleguidist when react-docgen-typescript can't parse the props in one component: it fails catastrophically with the dreaded TypeError: Cannot read property 'methods' of null error, and prevents the entire styleguide from being generated.

Our workaround right now is to remove that component from the styleguide, but it would be really helpful to be able to have a component in the styleguide even if react-docgen-styleguidist can't figure out props for it, so we can provide examples and live views of the component.

Here's an example of one of our problematic components, where we're using glamorous to produce a simple low-level styled component:

import glamorous from 'glamorous';
import { ITheme } from './ITheme';

export const BodyText = glamorous.span({
}, (_props: any, theme: ITheme) => ({
    color: theme.bodyTextColor,
    fontSize: theme.bodyTextSize
}));

export default BodyText;

It would be unreasonable to expect react-docgen-stypescript to figure out the props for that, but it would be great if it could still advertise a BodyText component with enough data to prevent styleguidist from blowing up, allowing a BodyText.md file to be created with examples.

Thanks!

typescript Cannot read property 'getTypeAtLocation' of undefined problem.

I tried to upgrade typescript version as 2.9.1 and after I got bellow error.
After when downgraded to 2.8.1 or 2.6.2 I got Unknown kind error.

It usually means that react-docgen does not understand your source code, try to file an issue here:
https://github.com/reactjs/react-docgen/issues

undefined
TypeError: Cannot read property 'getTypeAtLocation' of undefined
    at /Users/kamilbukum/DEV/tvm/bambu/node_modules/typescript/lib/typescript.js:106675:41
    at Object.firstDefined (/Users/kamilbukum/DEV/tvm/bambu/node_modules/typescript/lib/typescript.js:1807:26)
    at findInheritedJSDocComments (/Users/kamilbukum/DEV/tvm/bambu/node_modules/typescript/lib/typescript.js:106673:19)
    at getDocumentationComment (/Users/kamilbukum/DEV/tvm/bambu/node_modules/typescript/lib/typescript.js:106656:37)
    at SymbolObject.getDocumentationComment (/Users/kamilbukum/DEV/tvm/bambu/node_modules/typescript/lib/typescript.js:106505:45)
    at Parser.getFullJsDocComment (/Users/kamilbukum/DEV/tvm/bambu/node_modules/react-docgen-typescript/lib/parser.js:235:58)
    at Parser.findDocComment (/Users/kamilbukum/DEV/tvm/bambu/node_modules/react-docgen-typescript/lib/parser.js:211:28)
    at /Users/kamilbukum/DEV/tvm/bambu/node_modules/react-docgen-typescript/lib/parser.js:191:38
    at Array.forEach (<anonymous>)
    at Parser.getPropsInfo (/Users/kamilbukum/DEV/tvm/bambu/node_modules/react-docgen-typescript/lib/parser.js:184:27)
    at Parser.getComponentInfo (/Users/kamilbukum/DEV/tvm/bambu/node_modules/react-docgen-typescript/lib/parser.js:121:30)
    at /Users/kamilbukum/DEV/tvm/bambu/node_modules/react-docgen-typescript/lib/parser.js:68:53
    at Array.map (<anonymous>)
    at Object.parse (/Users/kamilbukum/DEV/tvm/bambu/node_modules/react-docgen-typescript/lib/parser.js:68:18)
    at propsParser (/Users/kamilbukum/DEV/tvm/bambu/styleguide.config.js:14:116)
    at Object.module.exports (/Users/kamilbukum/DEV/tvm/bambu/node_modules/react-styleguidist/loaders/props-loader.js:29:10)
Warning: Cannot parse src/components/dropdown/DropdownDivider.tsx: TypeError: Cannot read property 'getTypeAtLocation' of undefined

Hide " | undefined"

When a prop is marked as optional, it shows " | undefined" in SG. This is quite annoying. Is there a way to opt-in and remove this?

screen shot 2018-04-18 at 5 10 35 pm

Also default values aren't being pulled in for SFCs, even with the latest release.

Explicitly-named exports not supported

It seems that explicitly named TypeScript exports (i.e. export { Foo }) aren't supported by react-docgen-typescript right now: TypeErrors are thrown during execution if they're present.

Repro Steps

It's easy to reproduce, by modifying one line of react-docgen-typescript's own example code:

Use: [email protected], [email protected]:

  1. Run styleguidist against the examples in react-docgen-typescript. That works fine.
  2. Edit the examples/react-styleguidist-example/components/HocComponent.tsx example file, and change the line:
export const HocComponent = hoc(Component);

to

const HocComponent = hoc(Component);
export { HocComponent };
  1. Run styleguidist against the examples again. An error is now produced:
Module build failed: TypeError: Cannot read property 'methods' of null
at getProps (/.../Dev/react-docgen-typescript/examples/react-styleguidist-example/node_modules/react-styleguidist/loaders/utils/getProps.js:36:20)

Children propType parsed not as expected

So, I have small component
https://github.com/Faradey27/elementary-ui/blob/master/src/Text/Text.tsx

In which I want to allow to pass only strings as children and in general it works,
<Text><div /></Text> - will not compile and <Text>123</Text> - will work fine

But in styleguidist it looks like: screenshot,
so
Expected:
i will see children: string
Reality:
i see children:

string \| (number & string) \| (true & string) \| (false & string) \| (string
--

...

Which is completely valid typing, but looks really ugly.

Small research telling me that problem is coming from this line of code

which is from typescript.

So, question:

  • is it really typescript only part to transform typings to propTypes?
  • is it possible to have something like "trick"(doing typeToString in react-docgen-typescript) for children prop?

p.s. for user experience I think it is much better to have as simple texts as possible and string \| (number & string) \| (true & string) \| (false & string) \| (string looks like hard to read

Props not displayed from an interface imported from a .tsx file

version 1.0.0

When importing props from a file with a .tsx extension, the props are not displayed. Example:

// Component2.tsx
export interface Component2Props {
  prop1?: string;
  prop2?: number;
}
// Component1.tsx
import { Component2Props } from './Component2';

export interface Component1Props extends Component2Props {
  prop3?: string;
  prop4?: number;
}

In the above example prop1 and prop2 are not displayed. Happens even if the only thing in Component2.tsx is the interface, therefore doesn't appear to be related to React being imported or a component being exported in the same file. Also happens if the props are imported from a .tsx file and are used as-is (i.e. not extended).

Works fine if the inherited props are housed in the same file or imported from a .ts file.

defaultProps enum

I'm using this with Styleguidist.
image

In the image above, Button.defaultProps.size === ButtonSize.Normal but nothing shows up under "Default".

react-docgen gets something like this:
image

Minimally, it would be nice to show ButtonSize for Type (like it is right now) and ButtonSize.Normal for Default.

An extra feature could be to describe that it is an enum. Maybe enum: ButtonSize for Type. Also "One of: ButtonSize.Small, ButtonSize.Normal, ButtonSize.Large" would be nice to have.

Note that string literal types work fine, but they aren't enums:
image

publish to npm?

Hey,

Just wondering... do you think would be possible to publish #7 and #8 to npm? this would help me use the changes on my projects

Thanks!

Support for Union types

As far as I have noticed react-docgen-typescript doesn't support union types like:

interface I1 {
  /** property 1 */
  a: string;
}
interface I2 {
  /** property 2 */
  b: string;
}
export default class Sample extends React.Component<I1 | I2, {}> {
...

At the moment when supplying styleguidist with this construct it just shows children as sole property.

Prop types missing when using an intersection

A ton of our components in the styleguide are missing the prop types table. After digging around, it turns out that props with an intersection are causing it.

For example, with an intersection:

export const Spacing: React.SFC<SpacingProps & WithStylesProps> = () => {};

screen shot 2018-06-01 at 12 22 20 pm

And without the intersection:

export const Spacing: React.SFC<SpacingProps> = () => {};

screen shot 2018-06-01 at 12 22 55 pm

The with styles pieces are imported as such:

import withStyles, { css, withStylesPropTypes, WithStylesProps } from '../../composers/withStyles';

Defined as:

export interface WithStylesProps {
  /** Current component styles provided by `withStyles`. */
  styles: StyleDeclaration;
  /** Current theme declaration provided by `withStyles`. */
  theme?: Theme;
  /** Name of the current theme provided by `withStyles`. */
  themeName?: string;
}

export default function withStyles<TP = {}>(
  callback: StyleDeclaration | ((theme: Theme, props: TP) => StyleDeclaration),
  options?: {
    extendable?: boolean;
    extendFrom?: string;
    passThemeNameProp?: boolean;
    passThemeProp?: boolean;
    pure?: boolean;
    styleName?: string;
    stylesPropName?: string;
    themePropName?: string;
  },
): <P = {}>(
  component: React.ComponentType<P & WithStylesProps>,
) => React.ComponentType<Exclude<P, WithStylesProps>> {
  return style(callback, options);
}

And used as:

export default withStyles(theme => ({
  // styles
}))(Spacing);

propsParser config option should be function, received Object.

Hi, I faced some problems with propsParser configuration.

According to documentation, correct value should be
propsParser: require('react-docgen-typescript').withDefaultConfig()

which gives an error

Something is wrong with your style guide config
propsParser config option should be function, received Object.

react-docgen-typescript version: [email protected]
styleguidist version: [email protected]

And according to some short looking into source-code, both styleguide and react-docgen-typescript this error is correct.
For example here https://github.com/styleguidist/react-styleguidist/blob/master/loaders/props-loader.js#L24 defaultParser expected to be function, while withDefaultConfig() from here return an object https://github.com/styleguidist/react-docgen-typescript/blob/master/src/parser.ts#L75 { parse: ... }

If I use
propsParser: require('react-docgen-typescript').withDefaultConfig().parse
in config, everything looks okay and working.

Minimal steps to reproduce that problem can be:

mkdir test-props-parser && cd test-props-parser
touch package.json && echo '{ "devDependencies": { "react-docgen-typescript": "^1.0.2", "react-styleguidist": "^6.0.31", "webpack": "^3.7.1", "webpack-blocks": "^1.0.0-rc" }, "dependencies": { "react": "15.6.1", "react-dom": "15.6.1" }, "scripts": { "styleguide": "styleguidist server", "styleguide:build": "styleguidist build" }}' > package.json
touch styleguide.config.js && echo "const { createConfig } = require('webpack-blocks'); const typescript = require('@webpack-blocks/typescript'); module.exports = {propsParser: require('react-docgen-typescript').withDefaultConfig(), components: 'src/**/*.tsx', webpackConfig: createConfig([typescript()])};" > styleguide.config.js
mkdir -p src/Button
touch src/Button/Button.tsx && echo 'import * as React from "react"; export default class Button extends React.Component<{}, {}> {  public render() { return "OK";}}
' > src/Button/Button.tsx

and then run
npm run styleguide

inlined content of config is

const { createConfig } = require('webpack-blocks');
const typescript = require('@webpack-blocks/typescript');

module.exports = {
  propsParser: require('react-docgen-typescript').withDefaultConfig(),
  components: 'src/**/*.tsx',
  webpackConfig: createConfig([
    typescript()
  ])
};

Can I use .parse method programmatically?

Hi, I was successful in getting the json output of a .tsx file by using the .parse method. However, if a file has something like export class Row extends Component<IRowProps, {}> {

render() {
    return <div>Row</div>;
}

}
where there is an extends my output without fail always becomes something like { displayName: 'column', description: '', props: {} }. There should be documentation because the readMe had the documentation. Is there anyway i can fix this issue?

Wrong detection of exported component

When using with react-styleguidist on this component:

https://github.com/buildo/react-components/blob/d9b21080a486064d1397825baa718ef7b71833a1/src/AsyncStatusIndicator/AsyncStatusIndicator.tsx

it erroneously detects AsyncStatusIndicatorState instead of AsyncStatusIndicator, resulting in

image

If I do this simple edit, it detects the change correctly (but I can't do it because I want the type to be inferred):

- export const AsyncStatusIndicatorState = t.enums.of([
+ export const AsyncStatusIndicatorState: any = t.enums.of([

image

Cannot read property 'methods' of null

Hi! Getting this error trying to use with styleguidist

`Failed to compile.

Error in ./client/app/shared/Dropdown/Dropdown.tsx
Module build failed: TypeError: Cannot read property 'methods' of null
@ .//react-styleguidist/loaders/styleguide-loader.js!.//react-styleguidist/lib/index.js 23:29-232`

[email protected]

[email protected]

[email protected]

My styleguidist config

`const path = require('path');
const webpackDevConf = require('./webpack-dev.conf');

module.exports = {
title: 'Documentation',
components: './../client/app/shared/Dropdown/**.tsx',
serverHost: 'localhost',
serverPort: 3000,
styleguideDir: path.resolve(__dirname, './../styleguide'),
webpackConfig: webpackDevConf,
propsParser: require('react-docgen-typescript').parse
};`

Thanks!

How to document class inner static components

Here is the example:

...
export interface ITabsPanelProps extends React.Props<any> {
  /* title */
  title: string;
  children?: React.ReactNode;
}
const Panel = ({ title, children }: ITabsPanelProps) => <div>{children}</div>;

export default class Tabs extends React.Component<IProps, {}> {
  static Panel = Panel; // The one I wanna to show it`s props documents
  ...
}

how to show the Tab.Panel Doc?

Extracting public methods from components

Hello,

I am using Styleguidist with this package for my react components, but can't get my public methods to show in the documentation. Neither using the @public directive in the JSDoc block or explicitly setting a method public in typescript will show the method in the documentation.

Is there another way to make a public method appear in the docs?

Function Declaration Style

I prefer the Function Declaration Style over the const Foo = () => style. Unfortunatley:

export interface JumbotronProps {
    children?: string;
}

export function Jumbotron(props: JumbotronProps) {
    return <div>Test</div>;
};

does not generate any props info. Instead I have to write:

export interface JumbotronProps {
    children?: string;
}

export const Jumbotron = (props: JumbotronProps) => {
    return <div>Test</div>;
};

unappropriate webpack Loader

I installed everything according to both documentantions (yours, and react-styleguidist), but I cannot get to start styleguide: any attempt raises the following :

Cannot Load [any .tsx file]: you may need an appropriate webpack loader to handle this file type.

I'm using awesome-typescript-loader to parse my TS files

Here is my styleguide config:

module.exports = {
  webpackConfig: require('./config/webpack.config.dev.js'),
  components: 'src/components/navbar/Navbar.tsx',
  propsParser: require('react-docgen-typescript').parse
};

I guess the loader works fine, since yarn start works perfectly fine, but somehow fails to run styleguide. Did I miss something ? is there any particular requirement when using yarn ?

Regression in v0.0.12

I just upgraded to v0.0.12 and I'm getting the following error:

Error when parsing src/components/Zoomable/Zoomable.tsx: TypeError: Cannot read property 'forEach' of undefined

Contents of file Zoomable.tsx:

import * as React from 'react';
import * as cx from 'classnames';
import * as bindClassnames from 'classnames/bind';
import round from 'lodash/round';
import clamp from 'lodash/clamp';
import { applyToPoint } from 'transformation-matrix/applyToPoint';
import { inverse } from 'transformation-matrix/inverse';
import { scale } from 'transformation-matrix/scale';
import { toCSS } from 'transformation-matrix/toString';
import { transform } from 'transformation-matrix/transform';
import { translate } from 'transformation-matrix/translate';

import * as classNames from './Zoomable.module.css';

const cxm = bindClassnames.bind(classNames);

type Coords = { x: number; y: number };

export interface Props extends React.HTMLAttributes<Element> {
  /**
   * The x-axis value of the zoom origin, which corresponds to the mouse pointer
   * location relative to the wrapped element without the zoom applied
   */
  originX: number;
  /** The y-axis value of the zoom origin, which corresponds to the mouse pointer
   * location relative to the wrapped element without the zoom applied
   */
  originY: number;
  /** The zoom level */
  scaleFactor: number;
  /** Maximum zoom level */
  maxScale?: number;
  /** Minimum zoom level */
  minScale?: number;
  /**
   * The zoom change handler for controlled components.
   * It should update the other props in order to reflect the zoom change.
   */
  onZoom(
    scale: number,
    translateX: number,
    translateY: number,
  ): void;
}

interface State {
  matrix: Matrix;
  canZoomIn: boolean;
  canZoomOut: boolean;
}

function getMatrixFromProps({ originX, originY, scaleFactor }: Props): Matrix {
  return transform(
    translate(originX, originY),
    scale(scaleFactor, scaleFactor),
    translate(-originX, -originY),
  );
}

function getCanZoomIn({ maxScale = Infinity, scaleFactor }: Props): boolean {
  return scaleFactor < maxScale;
}

function getCanZoomOut({ minScale = Infinity, scaleFactor }: Props): boolean {
  return scaleFactor > minScale;
}

/** A Zoomable component wraps any DOM element and provides mouse-based
 * zooming capabilities. Support for touch gestures is planned soon.
 */
export class Zoomable extends React.PureComponent<Props, State> {
  static defaultProps: Partial<Props> = {
    scaleFactor: 1,
    originX: 0,
    originY: 0,
    minScale: 1,
    maxScale: 5,
  };

  state: State = {
    matrix: getMatrixFromProps(this.props),
    canZoomIn: getCanZoomIn(this.props),
    canZoomOut: getCanZoomOut(this.props),
  };

  viewer: Element;
  setViewer = (node: Element) => (this.viewer = node);

  applyZoom(f: number, e: React.MouseEvent<Element>) {
    const { x: mouseX, y: mouseY }: Coords = this.getMouseCoords(e);
    if ((this.state.canZoomIn && f > 1) || (this.state.canZoomOut && f < 1)) {
      const newScaleFactor = round(this.props.scaleFactor * f, 1);
      this.props.onZoom(newScaleFactor, mouseX, mouseY);
      e.preventDefault();
    }
  }

  /**
   * Gets the original mouse position relative to the element
   * as if the coordinates were on the element without the transformations
   * applied to it.
   */
  getMouseCoords(ev: React.MouseEvent<Element>) {
    const { top, left, width, height } = this.viewer.getBoundingClientRect();
    const x = clamp(round(ev.clientX - left), 0, width);
    const y = clamp(round(ev.clientY - top), 0, height);
    // Now we have the mouse position applied correctly to the transormation
    // matrix, we inverse the matrix to get the original point on the element
    // with no transformations applied.
    const matrix = this.state.matrix;
    const inverseMatrix = inverse(matrix);

    return applyToPoint(inverseMatrix, { x, y });
  }

  handleMouseDown = (e: React.MouseEvent<Element>) => {
    this.applyZoom(e.button === 2 ? 0.9 : 1.1, e);
  };

  handleMouseWheel = (e: React.WheelEvent<Element>) => {
    const delta = e.deltaY;
    this.applyZoom(delta > 0 ? 0.9 : 1.1, e);
  };

  handleContextMenu = (e: React.MouseEvent<Element>) => {
    e.preventDefault();
  };

  componentWillReceiveProps(newProps: Props) {
    this.setState({
      matrix: getMatrixFromProps(newProps),
      canZoomIn: getCanZoomIn(newProps),
      canZoomOut: getCanZoomOut(newProps),
    });
  }

  render() {
    const {
      style,
      className,
      children,
      scaleFactor,
      onZoom,
      minScale,
      maxScale,
      originX,
      originY,
      ...rest,
    } = this.props;
    const { canZoomIn, canZoomOut } = this.state;

    return (
      <div ref={this.setViewer} className={cx(classNames.viewer, className)}>
        <div
          {...rest}
          onContextMenu={this.handleContextMenu}
          onMouseDown={this.handleMouseDown}
          onWheel={this.handleMouseWheel}
          className={cxm('zoomable', { canZoomIn, canZoomOut })}
          role="presentation"
          style={{
            ...style,
            transform: toCSS(this.state.matrix),
          }}
        >
          {children}
        </div>
      </div>
    );
  }
}

export default Zoomable;

Negative numbers as default values are not parsed

If a negative number is defined as the default prop value, it is ignored in the styleguidist output, e.g.

interface TestProps {
  numProp: number;
}
export Test extends React.Component<TestProps, {}> {
  static defaultProps: TestProps = {
    numProp: -1
  };
 //...

This is due to the parsing in parser.ts#getLiteralValueFromPropertyAssignment - the switch-case-block handles SyntaxKind.NumericLiteral, but the - from -1 is passed as SyntaxKind.PrefixUnaryExpression

External props interfaces not displayed

One issue that we are facing is that if the props interface is not defined in the same file *.tsx where the reactjs component was defined then styleguidist will not display the possible properties.

I created an Example Project to show our issues.

unclear workflow for contributors

hello! thanks for react-docgen-typescript

i want to contribute but am stumbling upon some easy-to-fix issues:

  1. i should be using yarn but i can know about it only that there's yarn.lock.
  2. what is expected node version? .travis.yml says node 6, but i would suggest to add .nvmrc or a note in readme about it
  3. running tests with typescript 2.7.2 (which you get with npm, because of ^2.3.3 in package.json) fails:
⇶ npm t                                                                                           ◷ 14:48
> [email protected] test /home/arijus/repos/react-docgen-typescript
> tsc && mocha --timeout 10000 ./lib/**/__tests__/**.js

src/parser.ts(125,56): error TS2345: Argument of type 'SourceFile | undefined' is not assignable to parameter of type 'Node'.
  Type 'undefined' is not assignable to type 'Node'.
src/parser.ts(132,50): error TS2345: Argument of type 'SourceFile | undefined' is not assignable to parameter of type 'SourceFile'.
  Type 'undefined' is not assignable to type 'SourceFile'.
src/parser.ts(359,7): error TS2554: Expected 1 arguments, but got 0.
npm ERR! Test failed.  See above for more details.

on a side note, if it were up to me, i would go with npm and no package-lock

Union types cannot be documented

I ran into an issue earlier where union types caused the all of the props of a component not to be documented (the props names appeared in the documentation, but none of their descriptions, etc). I have removed my unions, but it's not the best solution.

There are cases where this is useful, when one prop should only be provided if another is present, and must be provided if another is present e.g.

interface FixedWidth {
  fixWidth: true;
  width: number;
}

interface FlexibleWidth {
  fixWidth?: false;
  width?: never;
}

type Props = FixedWidth | FlexibleWidth;

Enable strict mode in tsconfig?

Maybe there is a point to enable strict mode in tsconfig? There are around 30 or more possible errors about "possible undefined" values.

Also, i made an example, which produces no output when using current version of react-docgen-typescript. It also produces error with 0.10 version, but it was fixed in #15.
I don't really understand why it gives me null, but i want to dig into it :)

Props cannot extend from an interface using `Pick`

The Pick operator allows us to specify a subset of properties from another interface. However this causes a parsing error in the file, and it crashes and fails to generate anything at all for this class.

export interface IButtonProps extends Pick<React.HTMLProps<HTMLInputElement>, 'onClick'|'type'> {
    icon?: string
}
export class Button extends React.PureComponent<IButtonProps, {}> {
    render() {
        const { type, onClick, icon } = this.props;
        return (
            <input type={type} onClick={onClick}>
                {this.props.icon
                    ? <i className={`fa fa-${icon}`} />
                    : null
                }
                {this.props.children}
            </input>
        );
    }
}

Gives the following error:

Error when parsing src/components/Button/Button.tsx: TypeError: Cannot read property 'parent' of undefined

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.