Add support for imported propTypes
Closed this issue Β· 50 comments
Importing prop types is a fairly common use case which doesn't appear to be possible at this stage. Any plans to support this pattern?
Example:
// defaultPropTypes.js
import { PropTypes } from 'react';
export default {
prop1: PropTypes.string
};
// otherPropTypes.js
import { PropTypes } from 'react';
export default {
prop2: PropTypes.object
};
// MyComponent.jsx
import { Component } from 'react';
import defaultPropTypes from './defaultPropTypes.js';
import otherPropTypes './otherPropTypes.js';
export default class MyComponent extends Component {
static propTypes = {
...defaultPropTypes,
...otherPropTypes
}
// etc...
}
Results in:
{
"MyComponent.jsx": {
"description": ""
}
}
I guess we could do this for simple cases, where a variable is spread into propTypes
(i.e. ...foo
, but not ..foo.bar
) and that variable resolves to a module import.
I didn't want to make react-docgen make any assumptions about how module identifiers are resolved, but I guess it's fair to assume that it will be CommonJS compatible (i.e. module identifiers refer to npm modules or local files).
Then we could inspect the other file and if it returns an object literal, inspect and merge it as well.
+1 :)
That would be a great feature
I've got a similar usecase, but not using spread when injecting the props.
// ILink.js
import {PropTypes} from 'react';
export default PropTypes.shape({
url: PropTypes.string.isRequired,
selected: PropTypes.bool,
target: PropTypes.string,
title: PropTypes.string.isRequired
});
// MyComponent.jsx
import { Component } from 'react';
import ILink from './ILink.js';
import otherPropTypes './otherPropTypes.js';
export default class MyComponent extends Component {
static propTypes = {
link: ILink
}
// etc...
}
The same idea would also apply to flow types, as they can be also imported. So maybe this "import something" could be abstracted in a way so it makes imported propTypes and flowTypes possible.
Even we stuck with similar use case, any plans to add support for external imports of propTypes, below is our use case.
constants.js
const BUTTON_STYLES = ['A', 'B', 'C', 'D'];
export default BUTTON_STYLES;
component.js
import BUTTON_STYLES from 'constants';
propTypes = {
kind: PropTypes.oneOf(constants),
}
class SomeComp extends React.Component{
static propTypes = propTypes;
}
export default SomeComp;
Generated AST:
'kind': {
'type': {
'name': 'enum',
'computed': true,
'value': 'BUTTON_STYLES'
},
'required': false,
'description': 'some description',
'defaultValue': {
'value': 'A',
'computed': false
}
},
Expected AST:
value of AST should be as below(which is working fine when BUTTON_STYLES are in same file, but not with import)
'kind': {
'type': {
'name': 'enum',
'value': [
{
'value': 'A',
'computed': false
},
{
'value': 'B',
'computed': false
},
{
'value': 'C',
'computed': false
},
{
'value': 'D',
'computed': false
}
]
},
'required': false,
'description': 'Button has a a different set of `kinds`',
'defaultValue': {
'value': 'A',
'computed': false
}
}
What do you think about a simpler approach? In our case, it would be enough to document our components with a generic message whenever a spread is found.
So, for a component like this one:
MyComponent.propTypes = {
/**
* Component Foo proptypes
*/
...Foo.propTypes,
/**
* Some other proptypes
*/
...propTypes,
/**
* Unhandled spread
*/
...{
bar: Prop.bool,
}
};
We would like to get the following descriptors:
{
"...Foo.propTypes": {
"description": "Component Foo proptypes"
},
"...propTypes": {
"description": "Some other proptypes"
}
}
Right now, these proptypes are just ignored, resulting in incomplete docs :(
We have got a proof of concept fork which adds support for Identifier or MemberExpression spreads, ignoring other spread expressions.
I can create a PR if you think this approach is worth it :)
@asis: They are not ignored: https://github.com/reactjs/react-docgen/blob/00f2d2d62d93b9243157c4cea19cf241121a7721/src/handlers/__tests__/propTypeCompositionHandler-test.js, but they are stored separately from normal props.
Oh, sorry! I was focused on extracting docs from the props declaration, so when I saw
I thought spread props were just being ignored altogether πThanks for the quick response!
+1
Have same use case as @asis We have our wrappers around semantic-ui components very often, and I try to spread their propTypes to have their props documented as well as ours but got nothing.
Just wrote some makes-no-sense component for test and parse it and got:
{
"description": "Our wrapper component around semantic-ui button\r\nFor more props visit\r\n[semantic-ui-button](https://react.semantic-ui.com/elements/button#button-example-button)",
"methods": [],
"props": {
"children": {
"type": {
"name": "any"
},
"required": false,
"description": "Button label"
}
},
"composes": [
"semantic-ui-react"
]
}
Code:
import React from "react";
import PT from "prop-types";
import { Button as SButton } from "semantic-ui-react";
/**
* Our wrapper component around semantic-ui button
* For more props visit
* [semantic-ui-button](https://react.semantic-ui.com/elements/button#button-example-button)
*/
const Button = ({ children, ...rest }) =>
<SButton {...rest}>{children}</SButton>;
Button.propTypes = {
/** Button label */
children: PT.any,
...SButton.propTypes
};
export default Button;
Will be awesome to have this with comments that propTypes of the imported component have. Since all semantic and our components are react-docgen documented.
@RIP21
The recommended approach (which is also what we do at Facebook), is to merge the docs yourself. I.e. since you know that this component composes semantic-ui-react
, you can look up the documentation for the imported component.
I guess in your specific case we would also have to record which export you are importing (Button
).
I'm running into the same thing while using either propTypes = CustomPropTypes;
or trying to destructure as propTypes = {...CustomPropTypes};
. Is there any work around currently or is this still being discussed? I apologize but reading through the comments here it was not clear to me what the proposed solution is.
We just used the list of "composed props" to infer the source files where they were defined. To solve the problem in styleguidist/react-styleguidist#548, we use a custom propsParser which turns each composed props reference into a "custom" prop, with a description containg a link to the relevant section of our docs. It is brittle... but it works.
Would you mind sharing your handler?
@reintroducing , Unfortunately I can't share it now, If possible will publish here for sure.
@pasupuletics, how about now? Care to share your custom handler?
So this is still not a thing?
@workjalexanderfox , Here you go https://github.com/pasupuletics/learning/blob/master/react-docgen-external-proptypes-handler.js
Just go through react-docgen custom handler documentation to configure.
This feature is really vital, especially for styleguides etc. Can somebody integrate such finally :(
@pasupuletics That's awesome!!! Works a treat, thanks!
@RIP21: Have you tried using @pasupuletics' custom handler?
Can somebody integrate such finally :(
Supporting dependency resolution in such a way that it works reliably in various environments is not trivial. That's why I'm suggesting that you are using a custom handler that works specifically for your environment.
Of course someone could write a reusable handler that works with plain CommonJS, someone else could provide one that understands with webpack, etc.
I don't have the bandwidth to build and support all this.
@pasupuletics can you please add some license to your repo?
If you find software that doesnβt have a license, that generally means you have no permission from the creators of the software to use, modify, or share the software. Although a code host such as GitHub may allow you to view and fork the code, this does not imply that you are permitted to use, modify, or share the software for any purpose.
https://choosealicense.com/no-permission/
You've added UNLICENSED
to your package.json, but that's probably not what you actually want:
Finally, if you do not wish to grant others the right to use a private or unpublished package under any terms:
{ "license": "UNLICENSED" }
@pasupuletics I hope you don't mind, I published the handler on npm and documented it: https://github.com/siddharthkp/react-docgen-external-proptypes-handler
@siddharthkp , Thats really awesome. No issues. Glad to see my name in repo.
This issue has been opened in 2015 and still open. Any progress on fixing this?
I'm here as I'm using docz which uses docgen in its pipeline. Each of my components have their own directory with several files at the root which abstracted from the main component, one of those is a Flow file which annotates the component and imports its types. Because docgen can't read this file, none of my props generate for the prop table.
@danez you mentioned this earlier and looks still to be an issue. Any ideas where could get started on this to create a PR?
@pasupuletics @siddharthkp If I understand correctly (I have downloaded and tried this handler in my project), that handler only works for imported constants but not for actual imported propTypes? I have entire propTypes declared in external files which I would like to use.
@benwiley4000 , It should work for both. If you never mind, can you please share your project config.
@pasupuletics thanks for following up! here's my styleguidist config which specifies the docgen handlers. https://github.com/benwiley4000/cassette/blob/48ab0a5ea187d4458df6933927b6cc1522cc1469/styleguide.config.js#L180
In particular I'm wanting this propType (repeatStrategy
) to show up as an enum which should be one of "none", "playlist" or "track" as specified here.
@benwiley4000 seems above URLs are broken.
@pasupuletics sorry I corrected the links now.
@pasupuletics and @siddharthkp got me inspired with their implementations. I forked their repo and expanded the functionality, wrote a whole lot of snapshot tests, and in the end mostly tweaked some code related to resolveToValue
.
I'd like to offer this up in hopes that it will help others: https://github.com/benjroy/react-docgen-imported-proptype-handler
npm install react-docgen-imported-proptype-handler --save-dev
Setup is pretty much the same as react-docgen-external-proptypes-handler
The test fixtures exercise the expanded capabilities: https://github.com/benjroy/react-docgen-imported-proptype-handler/tree/master/src/handlers/__tests__/fixtures/components
And there is nothing computed in the final snapshot: https://github.com/benjroy/react-docgen-imported-proptype-handler/blob/master/src/handlers/__tests__/__snapshots__/importedPropTypeHandler-test.js.snap
it works well following imports of files in your repo.
following imports from node_modules
: there is some basic path resolution and an implementation exercising it to make sure it won't throw, but I didn't write any logic to be able to read babel processed files from external dependencies
@benjroy thank you for sharing this! I have tried setting it up in my project and I ran into some issues that are keeping me from building my docs with this setup.
Do you have an example of how you've integrated the package in your own project?
@benwiley4000 thank you for trying it out! I forgot to ship @babel/runtime
. Just published v1.0.1
for the fix.
Additionally, here is a repo with basic example usage:
https://github.com/benjroy/react-docgen-imported-proptype-handler-example
And the script itself:
https://github.com/benjroy/react-docgen-imported-proptype-handler-example/blob/master/scripts/docgen.js
@benjroy That's brilliant!
If it works nicely, I don't mind deprecating my package. I'm not actively maintaining it anyways.
You can add @pasupuletics and me as maintainers if you like.
@benjroy Thanks for doing this. I'm unclear what the differences between your solution and this one is, however. Also, I think it would be good to show how this is used in the confines of react-styleguidist which is I think where all this originated, if possible. I'm also not able to see clearly how to use it there from your example.
@pasupuletics @siddharthkp and @benjroy , thanks for the great work!
I'm trying react-docgen-imported-proptype-handler
as it has the most robust set of supported cases and fixtures, but I'm getting the following when doing this:
import BaseComponent from './BaseComponent';
// ...
MyComponent.propTypes = {
...BaseComponent.propTypes,
// ... more
}
MyComponent.defaultProps = {
...BaseComponent.defaultProps,
// ... more
}
export default MyComponent;
Error:
Cannot find module 'react-docgen/dist/babylon' from 'resolveImportedNamespace.js'
at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:221:17)
at Object.<anonymous> (node_modules/react-docgen-imported-proptype-handler/dist/utils/resolveImportedNamespace.js:24:39)
Since there is not error without your handler, and all the Babel stuff works nicely, I'm a bit stumped.
react-docgen
and react-docgen-imported-proptype-handler
both use recast@0.16.1
, but I've got a different react-docgen
version floating around from babel-plugin-react-docgen
:
$ yarn list --pattern react-docgen
yarn list v1.13.0
ββ babel-plugin-react-docgen@2.0.0
β ββ react-docgen@3.0.0-rc.2
ββ react-docgen-external-proptypes-handler@1.0.2
ββ react-docgen-imported-proptype-handler@1.0.4
ββ react-docgen@3.0.0
It seems that these issues could be side-stepped if this handler were simply a pull-request agains the official react-docgen
repo, no? You're already copy/pasting a bunch of utils/
over, and the demand for this handler is so great that I'd be surprized if it didn't get accepted, right @fkling ?
@nemoDreamer yea, I think this handler I wrote would be better implemented as a PR into react-docgen
(the meat of the changes is slight tweaks to some of the utility methods to pass a filepath around).
Your problem specifically is that react-docgen
v3 doesn't ship the babylon
parser.
I noticed too late when i was working on the handler that react-docgen
was in alpha for major version 3.0.0
, but tl;dr;
:
this handler was only tested with react-docgen
^2.x.x
- you will get bit by the
babel-plugin-react-docgen
shipping docgen v3 - you will probably get bit by
recast
(this bit me because there were two competing versions ofrecast
in my node deps tree. In order for the handler to work, docgen and this handler MUST be pointing to the exact samerecast
dependency in node-modules
Reworking this for react-docgen
v3.0.0 will probably require a bit more work because of the dropped babylon
dep, and at that point the effort would be much better spent working this directly into react-docgen
itself
Haven't tried your package yet @benjroy but if it fixes the problem, it'd be awesome to see it merged into react-docgen
because a lot of people seem to have the same issue and it's been 3 years since it was created
Can this also solve the same problem with imported flow types?
any progress here?
I started hacking on this today and managed to get importing working for propTypes, flow, and typescript types. See devongovett/react-docgen@typescript...devongovett:importing. I'll open up a PR once the typescript PR (#348) is merged, since this builds on that. In the meantime, feel free to try out my branch.
Current limitations:
- ES6 imports only. Could add CommonJS support, but it's a bit more complicated and I'm not sure it's worth it when most apps should be using ES6 now anyway.
- Namespace imports are unsupported (
import * as foo from '...'
) - Wildcard re-exports are unsupported (
export * from '...'
) - Resolving from
node_modules
is supported, but flow libdefs (flow-typed
folder,.js.flow
files, and.d.ts
files) are unsupported. Would need to reimplement a custom resolver for those.
Please let me know if you try it out and encounter bugs.
PR opened: #352
There is an issue with PropTypes.oneOf(['a', 'b'])
. It creates next error: TypeError: Cannot read property 'type' of null
I have the same problem, is this being worked on?
@Tauana-Pacheco FYI
Dropping a link to this conversation to help my future self when I inevitably end up here in a couple months.
Dropping a link to this conversation to help my future self when I inevitably end up here in a couple months.
Just my 5 cents. Anyone who is still using prop-types should really invest in Typescript instead. Prop-types are quite dead at this point. While, I'm sure, many are still using prop-types, it is extremely dated approach and causes more issues than solves IMO. There are plenty of codemodes that can help you with migration.
@RIP21 the linked conversation is relevant for Typescript types...