├── .gitignore
├── .npmignore
├── .travis.yml
├── .vscode
└── settings.json
├── DOCUMENTATION.MD
├── LICENSE
├── README.md
├── demo
├── DOCUMENTATION.md
└── terminal.png
├── dist
├── __mocks__
│ ├── ExampleComponent.js
│ ├── OtherExampleComponent.js
│ └── inside
│ │ └── OtherExampleComponent.js
├── __tests__
│ ├── __snapshots__
│ │ ├── generatereactdoc.test.js.snap
│ │ ├── processprop.test.js.snap
│ │ └── react-doc-generator.test.js.snap
│ ├── generatereactdoc.test.js
│ ├── processprop.test.js
│ ├── react-doc-generator.test.js
│ └── utilities.test.js
├── generatereactdoc.js
├── lib
│ └── command.js
├── react-doc-generator.js
└── template.handlebars
├── package.json
├── src
├── .babelrc
├── __mocks__
│ ├── ExampleComponent.js
│ ├── OtherExampleComponent.js
│ └── inside
│ │ └── OtherExampleComponent.js
├── __tests__
│ ├── __snapshots__
│ │ ├── generatereactdoc.test.js.snap
│ │ ├── processprop.test.js.snap
│ │ └── react-doc-generator.test.js.snap
│ ├── generatereactdoc.test.js
│ ├── processprop.test.js
│ ├── react-doc-generator.test.js
│ └── utilities.test.js
├── generatereactdoc.js
├── lib
│ └── command.js
├── react-doc-generator.js
└── template.handlebars
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # react-doc-generator
2 |
3 | # Logs
4 | logs
5 | *.log
6 | npm-debug.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 |
13 | # Directory for instrumented libs generated by jscoverage/JSCover
14 | lib-cov
15 |
16 | # Coverage directory used by tools like istanbul
17 | coverage
18 |
19 | # nyc test coverage
20 | .nyc_output
21 |
22 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
23 | .grunt
24 |
25 | # node-waf configuration
26 | .lock-wscript
27 |
28 | # Compiled binary addons (http://nodejs.org/api/addons.html)
29 | build/Release
30 |
31 | # Dependency directories
32 | node_modules
33 | jspm_packages
34 |
35 | # Optional npm cache directory
36 | .npm
37 |
38 | # Optional REPL history
39 | .node_repl_history
40 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # react-doc-generator
2 | # Logs
3 | demo
4 | logs
5 | *.log
6 | npm-debug.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 |
13 | # Directory for instrumented libs generated by jscoverage/JSCover
14 | lib-cov
15 |
16 | # Coverage directory used by tools like istanbul
17 | coverage
18 |
19 | # nyc test coverage
20 | .nyc_output
21 |
22 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
23 | .grunt
24 |
25 | # node-waf configuration
26 | .lock-wscript
27 |
28 | # Compiled binary addons (http://nodejs.org/api/addons.html)
29 | build/Release
30 |
31 | # Dependency directories
32 | node_modules
33 | jspm_packages
34 |
35 | # Optional npm cache directory
36 | .npm
37 |
38 | # Optional REPL history
39 | .node_repl_history
40 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "6"
4 | - "node"
5 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.validate.enable": false,
3 | "javascript.validate.enable": false
4 | }
--------------------------------------------------------------------------------
/DOCUMENTATION.MD:
--------------------------------------------------------------------------------
1 |
2 |
3 | This document was generated by the **React DOC Generator v1.2.8** .
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Marcin Borkowski
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React DOC Generator
2 | [](https://www.npmjs.com/package/react-doc-generator)
3 | [](https://david-dm.org/marborkowski/react-doc-generator)
4 | [](https://travis-ci.org/marborkowski/react-doc-generator)
5 |
6 | Generate simple React components documentation in [Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet).
7 |
8 | ## Installation
9 |
10 | `$ npm install -save-dev react-doc-generator`
11 |
12 | ## Usage
13 |
14 | Check every option runnig `react-doc-generator` with `--help` or `-h`:
15 |
16 | ```
17 | $ react-doc-generator --help
18 |
19 | Usage: react-doc-generator
[options]
20 |
21 | Options:
22 |
23 | -h, --help output usage information
24 | -V, --version output the version number
25 | -x, --extensions Include only these file extensions. Default: js,jsx
26 | -i, --ignore Folders to ignore. Default: node_modules,__tests__,__mocks__
27 | -e, --exclude-patterns Filename patterns to exclude. Default: []
28 | -t, --title [value]> Document title. Default: 'Components'
29 | -o, --output Markdown file to write. Default: 'README.MD'
30 | ```
31 |
32 | ### By the command line
33 |
34 | Example:
35 |
36 | `$ react-doc-generator src -o DOCUMENTATION.md`
37 |
38 | ### NPM script
39 |
40 | Example:
41 |
42 | In your `package.json` put:
43 | ```
44 | {
45 | // ...
46 | "scripts": {
47 | "doc": "react-doc-generator ./app/components/custom -o DOCUMENTATION.md"
48 | }
49 | // ...
50 | }
51 | ```
52 |
53 | so then you are able to call this script by the command line:
54 |
55 | `$ npm run doc`
56 |
57 | ## API
58 |
59 | ```js
60 | /**
61 | * General component description.
62 | * You can even use the native Markdown here.
63 | * E.g.:
64 | * ```html
65 | *
66 | * ```
67 | */
68 | export class MyComponent extends React.Component {
69 | static displayName = 'Official Component Name'
70 | static propTypes = {
71 | /**
72 | * Description of prop "foo".
73 | */
74 | foo: React.PropTypes.number,
75 | /**
76 | * Description of prop "bar" (a custom validation function).
77 | */
78 | bar: function(props, propName, componentName) {
79 | // ...
80 | },
81 | baz: React.PropTypes.oneOfType([
82 | React.PropTypes.number,
83 | React.PropTypes.string
84 | ]),
85 | }
86 |
87 | static defaultProps = {
88 | foo: 10000099999
89 | }
90 |
91 | render () {
92 | return (Hello
);
93 | }
94 | }
95 | ```
96 |
97 | Because [**react-doc-generator**](https://github.com/marborkowski/react-doc-generator) uses [**react-docgen**](https://github.com/reactjs/react-docgen) library, you can [follow other examples here](https://github.com/reactjs/react-docgen).
98 |
99 | ## Demo
100 |
101 | * [Example output](https://github.com/marborkowski/react-doc-generator/blob/master/demo/DOCUMENTATION.md)
102 |
103 | ## Terminal
104 |
105 | This is an example of what you'll see in your terminal.
106 |
107 | 
108 |
109 | ### License
110 |
111 | MIT License
112 | Copyright (c) 2017 Marcin Borkowski ()
113 | Permission is hereby granted, free of charge, to any person obtaining a copy
114 | of this software and associated documentation files (the "Software"), to deal
115 | in the Software without restriction, including without limitation the rights
116 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
117 | copies of the Software, and to permit persons to whom the Software is
118 | furnished to do so, subject to the following conditions:
119 |
120 | The above copyright notice and this permission notice shall be included in all
121 | copies or substantial portions of the Software.
122 |
123 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
124 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
125 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
126 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
127 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
128 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
129 | SOFTWARE.
130 |
--------------------------------------------------------------------------------
/demo/DOCUMENTATION.md:
--------------------------------------------------------------------------------
1 | Components
2 | ----------
3 |
4 | **app/components/custom/articles/articles.jsx**
5 |
6 | ### 1. Simple `List Of Articles` component.
7 |
8 | WARNING: This is only the demo version to provide a sample data.
9 |
10 | Example:
11 | ```js
12 |
13 | ```
14 |
15 |
16 |
17 |
18 | Property | Type | Required | Default value | Description
19 | :--- | :--- | :--- | :--- | :---
20 | showMore|bool|yes|false|
21 | title|string|no||
22 | -----
23 | **app/components/button/button.jsx**
24 |
25 | ### 1. Button
26 |
27 | A button clearly communicates what action will occur when the user touches it. It consists of text, an image, or both, designed in accordance with your app’s color theme.
28 |
29 |
30 | ```js
31 | import {Button, IconButton} from 'react-toolbox/lib/button';
32 |
33 | const GithubIcon = () => (
34 |
35 |
36 |
37 | );
38 |
39 | const TestButtons = () => (
40 |
41 |
42 | Github
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | } accent />
51 |
52 |
53 |
54 |
55 | );
56 | ```
57 |
58 | Property | Type | Required | Default value | Description
59 | :--- | :--- | :--- | :--- | :---
60 | label|string|yes|Submit|Button label
61 | width|number|no|500|Button width
62 |
63 |
64 | -----
65 | **app/components/dropdown/dropdown.jsx**
66 |
67 | ### 1. Dropdown
68 |
69 | The Dropdown selects an option between multiple selections. The element displays the current state and a down arrow. When it is clicked, it displays the list of available options.
70 |
71 |
72 | ```js
73 | import Dropdown from 'react-toolbox/lib/dropdown';
74 |
75 | const countries = [
76 | { value: 'EN-gb', label: 'England' },
77 | { value: 'ES-es', label: 'Spain'},
78 | { value: 'TH-th', label: 'Thailand' },
79 | { value: 'EN-en', label: 'USA'}
80 | ];
81 |
82 | class DropdownTest extends React.Component {
83 | state = { value: 'ES-es' };
84 |
85 | handleChange = (value) => {
86 | this.setState({value: value});
87 | };
88 |
89 | render () {
90 | return (
91 |
97 | );
98 | }
99 | }
100 | ```
101 |
102 | Property | Type | Required | Default value | Description
103 | :--- | :--- | :--- | :--- | :---
104 | source|array|yes|[1, 2, 3]|Elements
105 |
--------------------------------------------------------------------------------
/demo/terminal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marborkowski/react-doc-generator/9b103405ce0744a7279a8fc1422406a891ff9a63/demo/terminal.png
--------------------------------------------------------------------------------
/dist/__mocks__/ExampleComponent.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var React = require('react');
4 |
5 | var PropTypes = require('prop-types');
6 | /**
7 | * General component description.
8 | * fdgdfgdf gfdgfdg fdgfdgdfg
9 | * gdfgfdgdfg dfgdfgfdg dfg df getDefaultPropsg fdgfd
10 | * gfdgfdgdfgfdg.
11 | *
12 | *
13 | * Example:
14 | * ```html
15 | *
16 | * ```
17 | */
18 |
19 |
20 | var Component = React.createClass({
21 | displayName: "Component",
22 | propTypes: {
23 | /**
24 | * Description of prop "toe" has one break line
25 | * here following more comments and has default
26 | * empty string.
27 | */
28 | toe: PropTypes.string,
29 |
30 | /**
31 | * Description of prop "finger".
32 | */
33 | finger: PropTypes.string,
34 |
35 | /**
36 | * Description of prop "foo".
37 | */
38 | foo: PropTypes.number,
39 |
40 | /**
41 | * Description of prop "bar" (a custom validation function).
42 | */
43 | bar: function bar(props, propName, componentName) {// ...
44 | },
45 | baz: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
46 | },
47 | getDefaultProps: function getDefaultProps() {
48 | return {
49 | finger: 'medium',
50 | toe: '',
51 | foo: 42,
52 | bar: 21
53 | };
54 | },
55 | render: function render() {
56 | return (
57 | /*#__PURE__*/
58 | React.createElement("div", null, "Hello World!")
59 | );
60 | }
61 | });
62 | module.exports = Component;
--------------------------------------------------------------------------------
/dist/__mocks__/OtherExampleComponent.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4 |
5 | Object.defineProperty(exports, "__esModule", {
6 | value: true
7 | });
8 | exports["default"] = exports.Component1 = void 0;
9 |
10 | var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
11 |
12 | var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
13 |
14 | var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
15 |
16 | var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
17 |
18 | var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
19 |
20 | var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
21 |
22 | var _react = _interopRequireDefault(require("react"));
23 |
24 | function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var result, Super = (0, _getPrototypeOf2["default"])(Derived); if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else result = Super.apply(this, arguments); return (0, _possibleConstructorReturn2["default"])(this, result); }; }
25 |
26 | function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { return Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})), true; } catch (e) { return false; } }
27 |
28 | /**
29 | * General component description.
30 | */
31 | var Component1 =
32 | /*#__PURE__*/
33 | function (_React$Component) {
34 | function Component1() {
35 | return (0, _classCallCheck2["default"])(this, Component1), _super.apply(this, arguments);
36 | }
37 |
38 | (0, _inherits2["default"])(Component1, _React$Component);
39 |
40 | var _super = _createSuper(Component1);
41 |
42 | return (0, _createClass2["default"])(Component1, [{
43 | key: "render",
44 | value: function render() {
45 | return (
46 | /*#__PURE__*/
47 | _react["default"].createElement("div", null, "Hello")
48 | );
49 | }
50 | }]), Component1;
51 | }(_react["default"].Component);
52 |
53 | exports.Component1 = Component1;
54 | (0, _defineProperty2["default"])(Component1, "defaultProps", {
55 | foo: 10000099999,
56 | onExit: function onExit() {
57 | console.debug('onExit');
58 | }
59 | });
60 |
61 | /**
62 | * General another component description.
63 | * Blah blah blah...
64 | * fdfdfsdf
65 | * fdsfsd
66 | */
67 | function Component2(props) {
68 | return (
69 | /*#__PURE__*/
70 | _react["default"].createElement("div", null, "Hello")
71 | );
72 | }
73 |
74 | Component2.displayName = "DUPA";
75 | var _default = Component2;
76 | exports["default"] = _default;
--------------------------------------------------------------------------------
/dist/__mocks__/inside/OtherExampleComponent.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4 |
5 | Object.defineProperty(exports, "__esModule", {
6 | value: true
7 | });
8 | exports["default"] = exports.Component1 = void 0;
9 |
10 | var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));
11 |
12 | var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
13 |
14 | var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
15 |
16 | var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
17 |
18 | var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
19 |
20 | var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
21 |
22 | var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
23 |
24 | var _react = _interopRequireDefault(require("react"));
25 |
26 | function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var result, Super = (0, _getPrototypeOf2["default"])(Derived); if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else result = Super.apply(this, arguments); return (0, _possibleConstructorReturn2["default"])(this, result); }; }
27 |
28 | function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { return Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})), true; } catch (e) { return false; } }
29 |
30 | /**
31 | * General component description.
32 | */
33 | var Component1 =
34 | /*#__PURE__*/
35 | function (_React$Component) {
36 | function Component1() {
37 | return (0, _classCallCheck2["default"])(this, Component1), _super.apply(this, arguments);
38 | }
39 |
40 | (0, _inherits2["default"])(Component1, _React$Component);
41 |
42 | var _super = _createSuper(Component1);
43 |
44 | return (0, _createClass2["default"])(Component1, [{
45 | key: "render",
46 | value: function render() {
47 | return (
48 | /*#__PURE__*/
49 | _react["default"].createElement("div", null, "Hello")
50 | );
51 | }
52 | }]), Component1;
53 | }(_react["default"].Component);
54 | /**
55 | * General another component description.
56 | * Blah blah blah...
57 | * fdfdfsdf
58 | * fdsfsd
59 | */
60 |
61 |
62 | exports.Component1 = Component1;
63 | (0, _defineProperty2["default"])(Component1, "propTypes", {
64 | /**
65 | * Description of prop "foo".
66 | */
67 | foo: _react["default"].PropTypes.number,
68 |
69 | /**
70 | * Description of prop "bar" (a custom validation function).
71 | */
72 | bar: function bar(props, propName, componentName) {// ...
73 | },
74 | baz: _react["default"].PropTypes.oneOfType([_react["default"].PropTypes.number, _react["default"].PropTypes.string]),
75 | onExit: _react["default"].PropTypes.func
76 | });
77 | (0, _defineProperty2["default"])(Component1, "defaultProps", {
78 | foo: 10000099999,
79 | onExit: function onExit() {
80 | console.debug('onExit');
81 | }
82 | });
83 |
84 | var Component2 =
85 | /*#__PURE__*/
86 | function (_React$Component2) {
87 | function Component2() {
88 | var _this;
89 |
90 | (0, _classCallCheck2["default"])(this, Component2);
91 |
92 | for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) args[_key] = arguments[_key];
93 |
94 | return _this = _super2.call.apply(_super2, [this].concat(args)), (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "displayName", "DUPA"), _this = _super2.call.apply(_super2, [this].concat(args)), (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "displayName", "DUPA"), _this;
95 | }
96 |
97 | (0, _inherits2["default"])(Component2, _React$Component2);
98 |
99 | var _super2 = _createSuper(Component2);
100 |
101 | return (0, _createClass2["default"])(Component2, [{
102 | key: "render",
103 | value: function render() {
104 | return (
105 | /*#__PURE__*/
106 | _react["default"].createElement("div", null, "Hello")
107 | );
108 | }
109 | }]), Component2;
110 | }(_react["default"].Component);
111 |
112 | (0, _defineProperty2["default"])(Component2, "propTypes", {
113 | /**
114 | * Description of prop "foo".
115 | */
116 | foo: _react["default"].PropTypes.number,
117 |
118 | /**
119 | * Description of prop "bar" (a custom validation function).
120 | */
121 | bar: function bar(props, propName, componentName) {// ...
122 | },
123 | baz: _react["default"].PropTypes.oneOfType([_react["default"].PropTypes.number, _react["default"].PropTypes.string])
124 | });
125 | var _default = Component2;
126 | exports["default"] = _default;
--------------------------------------------------------------------------------
/dist/__tests__/__snapshots__/generatereactdoc.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`GenerateReactDoc Whole thing should work 1`] = `
4 | Array [
5 | Object {
6 | "files": Array [
7 | Object {
8 | "components": Array [
9 | Object {
10 | "description": "fdgdfgdf gfdgfdg fdgfdgdfg
11 | gdfgfdgdfg dfgdfgfdg dfg df getDefaultPropsg fdgfd
12 | gfdgfdgdfgfdg.
13 |
14 |
15 | Example:
16 | \`\`\`html
17 |
18 | \`\`\`
19 |
20 | ",
21 | "methods": Array [],
22 | "props": Object {
23 | "bar": Object {
24 | "defaultValue": Object {
25 | "computed": false,
26 | "value": "21",
27 | },
28 | "description": "Description of prop \\"bar\\" (a custom validation function).",
29 | "required": false,
30 | "type": Object {
31 | "name": "custom",
32 | "raw": "function(props, propName, componentName) {
33 | // ...
34 | }",
35 | },
36 | },
37 | "baz": Object {
38 | "defaultValue": Object {
39 | "value": undefined,
40 | },
41 | "description": "",
42 | "required": false,
43 | "type": Object {
44 | "name": "union",
45 | "value": Array [
46 | Object {
47 | "name": "number",
48 | },
49 | Object {
50 | "name": "string",
51 | },
52 | ],
53 | },
54 | },
55 | "finger": Object {
56 | "defaultValue": Object {
57 | "computed": false,
58 | "value": "'medium'",
59 | },
60 | "description": "Description of prop \\"finger\\".",
61 | "required": false,
62 | "type": Object {
63 | "name": "string",
64 | },
65 | },
66 | "foo": Object {
67 | "defaultValue": Object {
68 | "computed": false,
69 | "value": "42",
70 | },
71 | "description": "Description of prop \\"foo\\".",
72 | "required": false,
73 | "type": Object {
74 | "name": "number",
75 | },
76 | },
77 | "toe": Object {
78 | "defaultValue": Object {
79 | "computed": false,
80 | "value": "''",
81 | },
82 | "description": "Description of prop \\"toe\\" has one break line here following more comments and has default empty string.",
83 | "required": false,
84 | "type": Object {
85 | "name": "string",
86 | },
87 | },
88 | },
89 | "title": "General component description.",
90 | },
91 | ],
92 | "filename": "/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/ExampleComponent.js",
93 | },
94 | Object {
95 | "components": Array [
96 | Object {
97 | "description": "null
98 |
99 | ",
100 | "displayName": "Component1",
101 | "methods": Array [],
102 | "props": Object {
103 | "bar": Object {
104 | "defaultValue": Object {
105 | "value": undefined,
106 | },
107 | "description": "Description of prop \\"bar\\" (a custom validation function).",
108 | "flowType": Object {
109 | "name": "signature",
110 | "raw": "() => void",
111 | "signature": Object {
112 | "arguments": Array [],
113 | "return": Object {
114 | "name": "void",
115 | },
116 | },
117 | "type": "function",
118 | },
119 | "required": true,
120 | "type": Object {
121 | "name": "() => void",
122 | },
123 | },
124 | "baz": Object {
125 | "defaultValue": Object {
126 | "value": undefined,
127 | },
128 | "description": "",
129 | "flowType": Object {
130 | "elements": Array [
131 | Object {
132 | "name": "number",
133 | },
134 | Object {
135 | "name": "string",
136 | },
137 | ],
138 | "name": "union",
139 | "raw": "number|string",
140 | },
141 | "required": true,
142 | "type": Object {
143 | "name": "number|string",
144 | },
145 | },
146 | "foo": Object {
147 | "defaultValue": Object {
148 | "computed": false,
149 | "value": "10000099999",
150 | },
151 | "description": "",
152 | "flowType": Object {
153 | "name": "number",
154 | },
155 | "required": false,
156 | "type": Object {
157 | "name": "number",
158 | },
159 | },
160 | "onExit": Object {
161 | "defaultValue": Object {
162 | "computed": false,
163 | "value": "() => {
164 | console.debug('onExit');
165 | }",
166 | },
167 | "description": "",
168 | "flowType": Object {
169 | "name": "signature",
170 | "raw": "() => void",
171 | "signature": Object {
172 | "arguments": Array [],
173 | "return": Object {
174 | "name": "void",
175 | },
176 | },
177 | "type": "function",
178 | },
179 | "required": false,
180 | "type": Object {
181 | "name": "() => void",
182 | },
183 | },
184 | },
185 | "title": "Component1",
186 | },
187 | Object {
188 | "description": "Blah blah blah...
189 | fdfdfsdf
190 | fdsfsd
191 |
192 | ",
193 | "displayName": "DUPA",
194 | "methods": Array [],
195 | "props": Object {
196 | "bar": Object {
197 | "defaultValue": Object {
198 | "value": undefined,
199 | },
200 | "description": "Description of prop \\"bar\\" (a custom validation function).",
201 | "flowType": Object {
202 | "name": "signature",
203 | "raw": "() => mixed",
204 | "signature": Object {
205 | "arguments": Array [],
206 | "return": Object {
207 | "name": "mixed",
208 | },
209 | },
210 | "type": "function",
211 | },
212 | "required": true,
213 | "type": Object {
214 | "name": "() => mixed",
215 | },
216 | },
217 | "baz": Object {
218 | "defaultValue": Object {
219 | "value": undefined,
220 | },
221 | "description": "",
222 | "flowType": Object {
223 | "elements": Array [
224 | Object {
225 | "name": "number",
226 | },
227 | Object {
228 | "name": "string",
229 | },
230 | ],
231 | "name": "union",
232 | "raw": "number | string",
233 | },
234 | "required": true,
235 | "type": Object {
236 | "name": "number | string",
237 | },
238 | },
239 | "foo": Object {
240 | "defaultValue": Object {
241 | "value": undefined,
242 | },
243 | "description": "Description of prop \\"foo\\".",
244 | "flowType": Object {
245 | "name": "number",
246 | },
247 | "required": true,
248 | "type": Object {
249 | "name": "number",
250 | },
251 | },
252 | },
253 | "title": "DUPA",
254 | },
255 | ],
256 | "filename": "/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/OtherExampleComponent.js",
257 | },
258 | Object {
259 | "components": Array [
260 | Object {
261 | "description": "null
262 |
263 | ",
264 | "displayName": "Component1",
265 | "methods": Array [],
266 | "props": Object {
267 | "bar": Object {
268 | "defaultValue": Object {
269 | "value": undefined,
270 | },
271 | "description": "Description of prop \\"bar\\" (a custom validation function).",
272 | "required": false,
273 | "type": Object {
274 | "name": "custom",
275 | "raw": "function(props, propName, componentName) {
276 | // ...
277 | }",
278 | },
279 | },
280 | "baz": Object {
281 | "defaultValue": Object {
282 | "value": undefined,
283 | },
284 | "description": "",
285 | "required": false,
286 | "type": Object {
287 | "name": "union",
288 | "value": Array [
289 | Object {
290 | "name": "number",
291 | },
292 | Object {
293 | "name": "string",
294 | },
295 | ],
296 | },
297 | },
298 | "foo": Object {
299 | "defaultValue": Object {
300 | "computed": false,
301 | "value": "10000099999",
302 | },
303 | "description": "Description of prop \\"foo\\".",
304 | "required": false,
305 | "type": Object {
306 | "name": "number",
307 | },
308 | },
309 | "onExit": Object {
310 | "defaultValue": Object {
311 | "computed": false,
312 | "value": "See code",
313 | },
314 | "description": "",
315 | "required": false,
316 | "type": Object {
317 | "name": "func",
318 | },
319 | },
320 | },
321 | "title": "Component1",
322 | },
323 | Object {
324 | "description": "Blah blah blah...
325 | fdfdfsdf
326 | fdsfsd
327 |
328 | ",
329 | "displayName": "DUPA",
330 | "methods": Array [],
331 | "props": Object {
332 | "bar": Object {
333 | "defaultValue": Object {
334 | "value": undefined,
335 | },
336 | "description": "Description of prop \\"bar\\" (a custom validation function).",
337 | "required": false,
338 | "type": Object {
339 | "name": "custom",
340 | "raw": "function(props, propName, componentName) {
341 | // ...
342 | }",
343 | },
344 | },
345 | "baz": Object {
346 | "defaultValue": Object {
347 | "value": undefined,
348 | },
349 | "description": "",
350 | "required": false,
351 | "type": Object {
352 | "name": "union",
353 | "value": Array [
354 | Object {
355 | "name": "number",
356 | },
357 | Object {
358 | "name": "string",
359 | },
360 | ],
361 | },
362 | },
363 | "foo": Object {
364 | "defaultValue": Object {
365 | "value": undefined,
366 | },
367 | "description": "Description of prop \\"foo\\".",
368 | "required": false,
369 | "type": Object {
370 | "name": "number",
371 | },
372 | },
373 | },
374 | "title": "DUPA",
375 | },
376 | ],
377 | "filename": "/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/inside/OtherExampleComponent.js",
378 | },
379 | ],
380 | "version": "1.2.7",
381 | },
382 | Array [
383 | Array [
384 | "/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/ExampleComponent.js",
385 | 1,
386 | "[32mOK.[39m",
387 | ],
388 | Array [
389 | "/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/OtherExampleComponent.js",
390 | 2,
391 | "[32mOK.[39m",
392 | ],
393 | Array [
394 | "/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/inside/OtherExampleComponent.js",
395 | 2,
396 | "[32mOK.[39m",
397 | ],
398 | ],
399 | ]
400 | `;
401 |
--------------------------------------------------------------------------------
/dist/__tests__/__snapshots__/processprop.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`ProcessProp Process prop should not modify the default value if the type is a string 1`] = `
4 | Object {
5 | "defaultValue": Object {
6 | "value": "somestring",
7 | },
8 | "description": "",
9 | "type": Object {
10 | "name": "string",
11 | },
12 | }
13 | `;
14 |
15 | exports[`ProcessProp Process prop should not modify the default value if the type is not string but default value doesnt have special characters 1`] = `
16 | Object {
17 | "defaultValue": Object {
18 | "value": 22,
19 | },
20 | "description": "",
21 | "type": Object {
22 | "name": "number",
23 | },
24 | }
25 | `;
26 |
27 | exports[`ProcessProp Process prop should overwrite the default value when type is not string and there are invalid characters 1`] = `
28 | Object {
29 | "defaultValue": Object {
30 | "value": "See code",
31 | },
32 | "description": "",
33 | "type": Object {
34 | "name": "number",
35 | },
36 | }
37 | `;
38 |
--------------------------------------------------------------------------------
/dist/__tests__/__snapshots__/react-doc-generator.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`output file has needed values 1`] = `
4 | Array [
5 | "",
6 | "**/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/ExampleComponent.js**",
7 | "",
8 | "### 1. General component description.",
9 | "",
10 | "fdgdfgdf gfdgfdg fdgfdgdfg ",
11 | "gdfgfdgdfg dfgdfgfdg dfg df getDefaultPropsg fdgfd ",
12 | "gfdgfdgdfgfdg. ",
13 | " ",
14 | " ",
15 | "Example: ",
16 | "\`\`\`html ",
17 | " ",
18 | "\`\`\` ",
19 | "",
20 | "",
21 | "",
22 | "",
23 | "Property | Type | Required | Default value | Description",
24 | ":--- | :--- | :--- | :--- | :---",
25 | "toe|string|no|''|Description of prop "toe" has one break line here following more comments and has default empty string.",
26 | "finger|string|no|'medium'|Description of prop "finger".",
27 | "foo|number|no|42|Description of prop "foo".",
28 | "bar|custom|no|21|Description of prop "bar" (a custom validation function).",
29 | "baz|union|no||",
30 | "-----",
31 | "**/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/OtherExampleComponent.js**",
32 | "",
33 | "### 1. Component1",
34 | "",
35 | "null ",
36 | "",
37 | "",
38 | "",
39 | "",
40 | "Property | Type | Required | Default value | Description",
41 | ":--- | :--- | :--- | :--- | :---",
42 | "foo|number|no|10000099999|",
43 | "bar|() => void|yes||Description of prop "bar" (a custom validation function).",
44 | "baz|number|string|yes||",
45 | "onExit|() => void|no|() => {",
46 | " console.debug('onExit');",
47 | "}|",
48 | "### 2. DUPA",
49 | "",
50 | "Blah blah blah... ",
51 | "fdfdfsdf ",
52 | "fdsfsd ",
53 | "",
54 | "",
55 | "",
56 | "",
57 | "Property | Type | Required | Default value | Description",
58 | ":--- | :--- | :--- | :--- | :---",
59 | "foo|number|yes||Description of prop "foo".",
60 | "bar|() => mixed|yes||Description of prop "bar" (a custom validation function).",
61 | "baz|number | string|yes||",
62 | "-----",
63 | "**/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/inside/OtherExampleComponent.js**",
64 | "",
65 | "### 1. Component1",
66 | "",
67 | "null ",
68 | "",
69 | "",
70 | "",
71 | "",
72 | "Property | Type | Required | Default value | Description",
73 | ":--- | :--- | :--- | :--- | :---",
74 | "foo|number|no|10000099999|Description of prop "foo".",
75 | "bar|custom|no||Description of prop "bar" (a custom validation function).",
76 | "baz|union|no||",
77 | "onExit|func|no|See code|",
78 | "### 2. DUPA",
79 | "",
80 | "Blah blah blah... ",
81 | "fdfdfsdf ",
82 | "fdsfsd ",
83 | "",
84 | "",
85 | "",
86 | "",
87 | "Property | Type | Required | Default value | Description",
88 | ":--- | :--- | :--- | :--- | :---",
89 | "foo|number|no||Description of prop "foo".",
90 | "bar|custom|no||Description of prop "bar" (a custom validation function).",
91 | "baz|union|no||",
92 | "-----",
93 | "",
94 | "This document was generated by the **React DOC Generator v1.2.7** . ",
95 | "",
96 | ]
97 | `;
98 |
99 | exports[`react-doc-generator contains help section if no argument is available in query 1`] = `
100 | "[37m[39m
101 |
102 | [37mREACT DOC GENERATOR v1.2.7[39m
103 | [37mby Marcin Borkowski [39m
104 | [31mPlease specify as the first argument![39m
105 | Usage: react-doc-generator [options]
106 |
107 | Options:
108 | -V, --version output the version number
109 | -x, --extensions Include only these file extensions. Default:
110 | js,jsx (default: [\\"js\\",\\"jsx\\"])
111 | -i, --ignore Folders to ignore. Default:
112 | node_modules,__tests__,__mocks__ (default:
113 | [\\"node_modules\\",\\"__tests__\\",\\"__mocks__\\"])
114 | -e, --exclude-patterns Filename patterns to exclude. Default: []
115 | (default: [])
116 | -t, --title [value] Document title. Default: 'Components'
117 | (default: \\"Components\\")
118 | -o, --output Markdown file to write. Default:
119 | 'DOCUMENTATION.MD' (default:
120 | \\"DOCUMENTATION.MD\\")
121 | -h, --help display help for command
122 | "
123 | `;
124 |
125 | exports[`react-doc-generator has the proper console output 1`] = `
126 | "[37m[39m
127 |
128 | [37mREACT DOC GENERATOR v1.2.7[39m
129 | [37mby Marcin Borkowski [39m
130 | ┌──────────────────────────────────────────────────────────────────────────────────────────────────┬────────────┬────────┐
131 | │ [36mPath[39m │ [36mComponents[39m │ [36mStatus[39m │
132 | ├──────────────────────────────────────────────────────────────────────────────────────────────────┼────────────┼────────┤
133 | │ /Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/ExampleComponent.js │ 1 │ [32mOK.[39m │
134 | ├──────────────────────────────────────────────────────────────────────────────────────────────────┼────────────┼────────┤
135 | │ /Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/OtherExampleComponent.js │ 2 │ [32mOK.[39m │
136 | ├──────────────────────────────────────────────────────────────────────────────────────────────────┼────────────┼────────┤
137 | │ /Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/inside/OtherExampleComponent.js │ 2 │ [32mOK.[39m │
138 | └──────────────────────────────────────────────────────────────────────────────────────────────────┴────────────┴────────┘
139 | "
140 | `;
141 |
142 | exports[`react-doc-generator return the proper message when given extensions not found 1`] = `
143 | "[37m[39m
144 |
145 | [37mREACT DOC GENERATOR v1.2.7[39m
146 | [37mby Marcin Borkowski [39m
147 | [1m[33mWarning:[39m[22m [33mCould not find any files matching the file type: \`*.4hs0\` OR \`*.kku4\`[39m
148 |
149 | ┌──────┬────────────┬────────┐
150 | │ [36mPath[39m │ [36mComponents[39m │ [36mStatus[39m │
151 | └──────┴────────────┴────────┘
152 | "
153 | `;
154 |
--------------------------------------------------------------------------------
/dist/__tests__/generatereactdoc.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4 |
5 | var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
6 |
7 | var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
8 |
9 | var _generatereactdoc = _interopRequireDefault(require("../generatereactdoc"));
10 |
11 | var _path = _interopRequireDefault(require("path"));
12 |
13 | describe("GenerateReactDoc", function () {
14 | it("Whole thing should work",
15 | /*#__PURE__*/
16 | (0, _asyncToGenerator2["default"])(
17 | /*#__PURE__*/
18 | _regenerator["default"].mark(function _callee() {
19 | var output;
20 | return _regenerator["default"].wrap(function _callee$(_context) {
21 | for (; 1;) switch (_context.prev = _context.next) {
22 | case 0:
23 | return _context.next = 2, (0, _generatereactdoc["default"])({
24 | sourceDir: _path["default"].resolve(__dirname, "../__mocks__"),
25 | extensions: ["js", "jsx"],
26 | outputDir: _path["default"].resolve(__dirname, "../__mocks__/output.md")
27 | });
28 |
29 | case 2:
30 | output = _context.sent, expect(output).toMatchSnapshot();
31 |
32 | case 4:
33 | case "end":
34 | return _context.stop();
35 | }
36 | }, _callee);
37 | })));
38 | });
--------------------------------------------------------------------------------
/dist/__tests__/processprop.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var _generatereactdoc = require("../generatereactdoc");
4 |
5 | describe('ProcessProp', function () {
6 | it('Process prop should not modify the default value if the type is a string', function () {
7 | var mockProp = {
8 | type: {
9 | name: 'string'
10 | },
11 | defaultValue: {
12 | value: 'somestring'
13 | }
14 | };
15 | var output = (0, _generatereactdoc.processProp)(mockProp);
16 | expect(output).toMatchSnapshot();
17 | }), it('Process prop should not modify the default value if the type is not string but default value doesnt have special characters', function () {
18 | var mockProp = {
19 | type: {
20 | name: 'number'
21 | },
22 | defaultValue: {
23 | value: 22
24 | }
25 | };
26 | var output = (0, _generatereactdoc.processProp)(mockProp);
27 | expect(output).toMatchSnapshot();
28 | }), it('Process prop should overwrite the default value when type is not string and there are invalid characters', function () {
29 | var mockProp = {
30 | type: {
31 | name: 'number'
32 | },
33 | defaultValue: {
34 | value: '@#454'
35 | }
36 | };
37 | var output = (0, _generatereactdoc.processProp)(mockProp);
38 | expect(output).toMatchSnapshot();
39 | });
40 | });
--------------------------------------------------------------------------------
/dist/__tests__/react-doc-generator.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4 |
5 | var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
6 |
7 | var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
8 |
9 | // https://travis-ci.org/marborkowski/react-doc-generator
10 | var path = require("path");
11 |
12 | var fs = require("fs");
13 |
14 | var spawn = require("child_process").spawn;
15 |
16 | function run(command, args) {
17 | var stdout = [];
18 | var stderr = [];
19 | return new Promise(function (resolve, reject) {
20 | var spawned = spawn(command, args);
21 | spawned.stdout.on("data", function (data) {
22 | stdout.push(data);
23 | }), spawned.stderr.on("data", function (data) {
24 | return stderr.push(data);
25 | }), spawned.on("close", function () {
26 | return resolve([stdout.join(""), stderr.join("")]);
27 | }), spawned.on("error", function (err) {
28 | throw err;
29 | });
30 | })["catch"](function (error) {
31 | throw console.log(error, "Error"), error;
32 | });
33 | }
34 |
35 | function loadDoc() {
36 | return new Promise(function (resolve, reject) {
37 | fs.readFile("./dist/DOCUMENTATION.md", "utf8", function (err, data) {
38 | err ? reject(err) : resolve(data);
39 | });
40 | });
41 | }
42 |
43 | var binPath = path.join(__dirname, "../../dist/react-doc-generator.js");
44 | fs.chmodSync(binPath, "0777"), describe("react-doc-generator", function () {
45 | it("has the proper console output",
46 | /*#__PURE__*/
47 | (0, _asyncToGenerator2["default"])(
48 | /*#__PURE__*/
49 | _regenerator["default"].mark(function _callee() {
50 | var stdout, output;
51 | return _regenerator["default"].wrap(function _callee$(_context) {
52 | for (; 1;) switch (_context.prev = _context.next) {
53 | case 0:
54 | return _context.prev = 0, _context.next = 3, run("node", [binPath, "src/__mocks__", "-o", "./dist/DOCUMENTATION.md"]);
55 |
56 | case 3:
57 | stdout = _context.sent, output = stdout[0], expect(output).toMatchSnapshot(), _context.next = 11;
58 | break;
59 |
60 | case 8:
61 | throw _context.prev = 8, _context.t0 = _context["catch"](0), (console.error(_context.t0), _context.t0);
62 |
63 | case 11:
64 | case "end":
65 | return _context.stop();
66 | }
67 | }, _callee, null, [[0, 8]]);
68 | }))), it("return the proper message when given extensions not found",
69 | /*#__PURE__*/
70 | (0, _asyncToGenerator2["default"])(
71 | /*#__PURE__*/
72 | _regenerator["default"].mark(function _callee2() {
73 | var stdout, output;
74 | return _regenerator["default"].wrap(function _callee2$(_context2) {
75 | for (; 1;) switch (_context2.prev = _context2.next) {
76 | case 0:
77 | return _context2.prev = 0, _context2.next = 3, run("node", [binPath, "src/__mocks__", "-o", "./dist/DOCUMENTATION.md", "-x", "4hs0,kku4"]);
78 |
79 | case 3:
80 | stdout = _context2.sent, output = stdout[0], expect(output).toMatchSnapshot(), _context2.next = 11;
81 | break;
82 |
83 | case 8:
84 | throw _context2.prev = 8, _context2.t0 = _context2["catch"](0), _context2.t0;
85 |
86 | case 11:
87 | case "end":
88 | return _context2.stop();
89 | }
90 | }, _callee2, null, [[0, 8]]);
91 | }))), it("contains help section if no argument is available in query",
92 | /*#__PURE__*/
93 | (0, _asyncToGenerator2["default"])(
94 | /*#__PURE__*/
95 | _regenerator["default"].mark(function _callee3() {
96 | var stdout, output;
97 | return _regenerator["default"].wrap(function _callee3$(_context3) {
98 | for (; 1;) switch (_context3.prev = _context3.next) {
99 | case 0:
100 | return _context3.prev = 0, _context3.next = 3, run("node", [binPath, "-o", "./dist/DOCUMENTATION.md"]);
101 |
102 | case 3:
103 | stdout = _context3.sent, output = stdout[0], expect(output).toMatchSnapshot(), _context3.next = 11;
104 | break;
105 |
106 | case 8:
107 | throw _context3.prev = 8, _context3.t0 = _context3["catch"](0), _context3.t0;
108 |
109 | case 11:
110 | case "end":
111 | return _context3.stop();
112 | }
113 | }, _callee3, null, [[0, 8]]);
114 | })));
115 | }), describe("output file", function () {
116 | it("has needed values",
117 | /*#__PURE__*/
118 | (0, _asyncToGenerator2["default"])(
119 | /*#__PURE__*/
120 | _regenerator["default"].mark(function _callee4() {
121 | var result, lines;
122 | return _regenerator["default"].wrap(function _callee4$(_context4) {
123 | for (; 1;) switch (_context4.prev = _context4.next) {
124 | case 0:
125 | return _context4.prev = 0, _context4.next = 3, run("node", [binPath, "src/__mocks__", "-o", "./dist/DOCUMENTATION.md", "-t", "MyTitleXYZ"]);
126 |
127 | case 3:
128 | return _context4.next = 5, loadDoc();
129 |
130 | case 5:
131 | result = _context4.sent, lines = result.split("\n"), expect(lines).toMatchSnapshot(), _context4.next = 13;
132 | break;
133 |
134 | case 10:
135 | throw _context4.prev = 10, _context4.t0 = _context4["catch"](0), _context4.t0;
136 |
137 | case 13:
138 | case "end":
139 | return _context4.stop();
140 | }
141 | }, _callee4, null, [[0, 10]]);
142 | })));
143 | });
--------------------------------------------------------------------------------
/dist/__tests__/utilities.test.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var _generatereactdoc = require("../generatereactdoc");
4 |
5 | describe('isDefaultValueTypeString', function () {
6 | it('Should return false if type of default value is not string', function () {
7 | var mockInput = {
8 | type: {
9 | name: 'number'
10 | },
11 | defaultValue: {
12 | value: 23
13 | }
14 | };
15 | var isString = (0, _generatereactdoc.isDefaultValueTypeString)(mockInput);
16 | expect(isString).toEqual(false);
17 | }), it('Should return false if type of default value is string but prop type is not string', function () {
18 | var mockInput = {
19 | type: {
20 | name: 'number'
21 | },
22 | defaultValue: {
23 | value: 'sdsd'
24 | }
25 | };
26 | var isString = (0, _generatereactdoc.isDefaultValueTypeString)(mockInput);
27 | expect(isString).toEqual(false);
28 | }), it('Should return null if prop was undefined', function () {
29 | var isString = (0, _generatereactdoc.isDefaultValueTypeString)();
30 | expect(isString).toEqual(null);
31 | }), it('Should return true if prop type was string and typeof default value was also string', function () {
32 | var mockInput = {
33 | type: {
34 | name: 'string'
35 | },
36 | defaultValue: {
37 | value: 'sdsd'
38 | }
39 | };
40 | var isString = (0, _generatereactdoc.isDefaultValueTypeString)(mockInput);
41 | expect(isString).toEqual(true);
42 | });
43 | }), describe('isInvalidDefaultValue', function () {
44 | it('Should return true for invalid input', function () {
45 | var isInValid = (0, _generatereactdoc.isInvalidDefaultValue)('3###');
46 | expect(isInValid).toEqual(true);
47 | }), it('Should return false for valid string input', function () {
48 | var isValid = (0, _generatereactdoc.isInvalidDefaultValue)('3333');
49 | expect(isValid).toEqual(false);
50 | }), it('Should return false for valid number input', function () {
51 | var isValid = (0, _generatereactdoc.isInvalidDefaultValue)(3333);
52 | expect(isValid).toEqual(false);
53 | });
54 | });
--------------------------------------------------------------------------------
/dist/generatereactdoc.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4 |
5 | Object.defineProperty(exports, "__esModule", {
6 | value: true
7 | });
8 | exports.isInvalidDefaultValue = exports.isDefaultValueTypeString = exports.getTypeOfProp = exports["default"] = void 0;
9 | exports.processProp = processProp;
10 |
11 | var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
12 |
13 | var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
14 |
15 | var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
16 |
17 | var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
18 |
19 | var _path = _interopRequireDefault(require("path"));
20 |
21 | var _reactDocgen = require("react-docgen");
22 |
23 | var _util = require("util");
24 |
25 | var _nodeDir = require("node-dir");
26 |
27 | var _colors = _interopRequireDefault(require("colors"));
28 |
29 | var _package = _interopRequireDefault(require("../package.json"));
30 |
31 | function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
32 |
33 | function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null == arguments[i] ? {} : arguments[i]; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
34 |
35 | var readFilesPromise = (0, _util.promisify)(_nodeDir.readFiles);
36 | var templateData = {
37 | files: [],
38 | version: _package["default"].version
39 | };
40 |
41 | var isDefaultValueTypeString = function isDefaultValueTypeString(prop) {
42 | return prop && prop.type ? prop.type.name === "string" && typeof prop.defaultValue.value === "string" : null;
43 | };
44 |
45 | exports.isDefaultValueTypeString = isDefaultValueTypeString;
46 |
47 | var isInvalidDefaultValue = function isInvalidDefaultValue(value) {
48 | return /[^\w\s.&:\-+*,!@%$]+/gim.test(value);
49 | };
50 |
51 | exports.isInvalidDefaultValue = isInvalidDefaultValue;
52 |
53 | var getTypeOfProp = function getTypeOfProp(prop) {
54 | if (!prop) return "";
55 | if (prop.type) return prop.type;
56 |
57 | if (prop.flowType) {
58 | var typeName = prop.flowType.raw ? prop.flowType.raw : prop.flowType.name;
59 | return {
60 | name: typeName
61 | };
62 | }
63 | };
64 |
65 | exports.getTypeOfProp = getTypeOfProp;
66 |
67 | function processProp(prop) {
68 | var _prop$defaultValue = prop.defaultValue,
69 | defaultValue = _prop$defaultValue === void 0 ? {} : _prop$defaultValue;
70 | var isString = isDefaultValueTypeString(prop);
71 | var isInvalidValue = isInvalidDefaultValue(defaultValue.value);
72 | var processedType = getTypeOfProp(prop);
73 | var processedDefaultValue = defaultValue && isInvalidValue && isString === false ? "See code" : defaultValue.value;
74 | var processedDescription = prop.description ? prop.description.split("\n").map(function (text) {
75 | return text.replace(/(^\s+|\s+$)/, "");
76 | }).map(function (hasValidValue) {
77 | return hasValidValue;
78 | }).join(" ") : "";
79 | return _objectSpread(_objectSpread({}, prop), {}, {
80 | defaultValue: _objectSpread(_objectSpread({}, prop.defaultValue), {}, {
81 | value: processedDefaultValue
82 | }),
83 | description: processedDescription,
84 | type: processedType
85 | });
86 | }
87 |
88 | function parseSingleFile(fileContent) {
89 | var components = (0, _reactDocgen.parse)(fileContent, _reactDocgen.resolver.findAllExportedComponentDefinitions);
90 | var componentObjects = components.map(function (component) {
91 | var description = component.description,
92 | displayName = component.displayName;
93 | var modifiedTitle = description && !displayName ? description.match(/^(.*)$/m)[0] : displayName;
94 | var modifiedDescription = null;
95 | description && (description.split("\n").length > 1 && (modifiedDescription = description.replace(/[\w\W]+?\n+?/, ""), modifiedDescription = modifiedDescription.replace(/(\n)/gm, " \n")), modifiedDescription = "".concat(modifiedDescription, " \n\n"));
96 | // validate default values
97 | var propEntries = Object.entries(component.props);
98 | var modifiedPropEntries = propEntries.map(function (_ref) {
99 | var _ref2 = (0, _slicedToArray2["default"])(_ref, 2),
100 | propName = _ref2[0],
101 | propObject = _ref2[1];
102 |
103 | var modifiedProp = processProp(propObject);
104 | return [propName, modifiedProp];
105 | });
106 | var modife = modifiedPropEntries.reduce(function (accum, current) {
107 | var modifiedAccum = _objectSpread(_objectSpread({}, accum), {}, (0, _defineProperty2["default"])({}, current[0], current[1]));
108 |
109 | return modifiedAccum;
110 | }, {});
111 | return _objectSpread(_objectSpread({}, component), {}, {
112 | title: modifiedTitle,
113 | description: modifiedDescription,
114 | props: modife
115 | });
116 | });
117 | return componentObjects;
118 | }
119 |
120 | function generateReactDocs(_x) {
121 | return _generateReactDocs.apply(this, arguments);
122 | }
123 |
124 | function _generateReactDocs() {
125 | return _generateReactDocs = (0, _asyncToGenerator2["default"])(
126 | /*#__PURE__*/
127 | _regenerator["default"].mark(function _callee(_ref3) {
128 | var sourceDir, _ref3$extensions, extensions, _ref3$excludePatterns, excludePatterns, _ref3$ignoreDirectory, ignoreDirectory, cliOutput, inputPath, allExtensions;
129 |
130 | return _regenerator["default"].wrap(function _callee$(_context) {
131 | for (; 1;) switch (_context.prev = _context.next) {
132 | case 0:
133 | return sourceDir = _ref3.sourceDir, _ref3$extensions = _ref3.extensions, extensions = _ref3$extensions === void 0 ? [] : _ref3$extensions, _ref3$excludePatterns = _ref3.excludePatterns, excludePatterns = _ref3$excludePatterns === void 0 ? [] : _ref3$excludePatterns, _ref3$ignoreDirectory = _ref3.ignoreDirectory, ignoreDirectory = _ref3$ignoreDirectory === void 0 ? [] : _ref3$ignoreDirectory, cliOutput = [], inputPath = _path["default"].resolve(sourceDir), _context.next = 5, readFilesPromise(inputPath, {
134 | match: new RegExp("\\.(?:" + extensions.join("|") + ")$"),
135 | exclude: excludePatterns,
136 | excludeDir: ignoreDirectory
137 | }, function (err, content, filename, next) {
138 | if (err) throw console.log(err, "error"), err;
139 |
140 | try {
141 | var components = parseSingleFile(content);
142 | templateData.files.push({
143 | filename: filename,
144 | components: components
145 | }), cliOutput.push([filename, components.length, _colors["default"].green("OK.")]);
146 | } catch (e) {
147 | console.error("In error", e), cliOutput.push([filename, 0, _colors["default"].red("You have to export at least one valid React Class!")]);
148 | }
149 |
150 | next();
151 | });
152 |
153 | case 5:
154 | if (templateData.files.length !== 0) {
155 | _context.next = 8;
156 | break;
157 | }
158 |
159 | allExtensions = extensions.map(function (ext) {
160 | return "`*.".concat(ext, "`");
161 | }), console.log("".concat(_colors["default"].bold.yellow("Warning:"), " ").concat(_colors["default"].yellow("Could not find any files matching the file type: ".concat(allExtensions.join(" OR "))), "\n"));
162 |
163 | case 8:
164 | return _context.abrupt("return", [templateData, cliOutput]);
165 |
166 | case 9:
167 | case "end":
168 | return _context.stop();
169 | }
170 | }, _callee);
171 | })), _generateReactDocs.apply(this, arguments);
172 | }
173 |
174 | var _default = generateReactDocs;
175 | exports["default"] = _default;
--------------------------------------------------------------------------------
/dist/lib/command.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _require = require("commander"),
9 | program = _require.program;
10 |
11 | var pkg = require("../../package.json");
12 |
13 | var _default = function Command() {
14 | var list = function list(val) {
15 | return val = val.replace(/[, ]+/g, ",").trim(), val.split(",").filter(function (value) {
16 | return value.length > 0;
17 | });
18 | };
19 |
20 | return program.version(pkg.version).usage(" [options]").option("-x, --extensions ", "Include only these file extensions. Default: js,jsx", list, ["js", "jsx"]).option("-i, --ignore ", "Folders to ignore. Default: node_modules,__tests__,__mocks__", list, ["node_modules", "__tests__", "__mocks__"]).option("-e, --exclude-patterns ", "Filename patterns to exclude. Default: []", list, []).option("-t, --title [value]", "Document title. Default: 'Components'", "Components").option("-o, --output ", "Markdown file to write. Default: 'DOCUMENTATION.MD'", "DOCUMENTATION.MD").parse(process.argv), program;
21 | }();
22 |
23 | exports["default"] = _default;
--------------------------------------------------------------------------------
/dist/react-doc-generator.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | "use strict";
3 |
4 | var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
5 |
6 | var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
7 |
8 | var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9 |
10 | var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
11 |
12 | var _fs = _interopRequireDefault(require("fs"));
13 |
14 | var _path = _interopRequireDefault(require("path"));
15 |
16 | var _generatereactdoc = _interopRequireDefault(require("./generatereactdoc"));
17 |
18 | var _command = _interopRequireDefault(require("./lib/command.js"));
19 |
20 | var _handlebars = _interopRequireDefault(require("handlebars"));
21 |
22 | var _colors = _interopRequireDefault(require("colors"));
23 |
24 | var _cliTable = _interopRequireDefault(require("cli-table"));
25 |
26 | _handlebars["default"].registerHelper("inc", function (value, options) {
27 | return parseInt(value, 10) + 1;
28 | }), (0, _asyncToGenerator2["default"])(
29 | /*#__PURE__*/
30 | _regenerator["default"].mark(function _callee() {
31 | var pkg, template, table, _yield$generateReactD, _yield$generateReactD2, templateData, cliOutput, outputFile;
32 |
33 | return _regenerator["default"].wrap(function _callee$(_context) {
34 | for (; 1;) switch (_context.prev = _context.next) {
35 | case 0:
36 | if (pkg = require("../package.json"), template = _handlebars["default"].compile("".concat(_fs["default"].readFileSync(_path["default"].join(__dirname, "template.handlebars")))), table = new _cliTable["default"]({
37 | head: [_colors["default"].cyan("Path"), _colors["default"].cyan("Components"), _colors["default"].cyan("Status")]
38 | }), console.log(_colors["default"].white("\n\nREACT DOC GENERATOR v".concat(pkg.version))), console.log(_colors["default"].white("by Marcin Borkowski ")), _context.prev = 4, _command["default"].args.length === 1) {
39 | _context.next = 9;
40 | break;
41 | }
42 |
43 | console.log("".concat(_colors["default"].red("Please specify as the first argument!"))), _command["default"].help(), _context.next = 17;
44 | break;
45 |
46 | case 9:
47 | return _context.next = 11, (0, _generatereactdoc["default"])({
48 | sourceDir: _command["default"].args[0],
49 | extensions: _command["default"].opts().extensions,
50 | excludePatterns: _command["default"].opts().excludePatterns,
51 | ignoreDirectory: _command["default"].opts().ignore
52 | });
53 |
54 | case 11:
55 | _yield$generateReactD = _context.sent, _yield$generateReactD2 = (0, _slicedToArray2["default"])(_yield$generateReactD, 2), templateData = _yield$generateReactD2[0], cliOutput = _yield$generateReactD2[1], outputFile = _fs["default"].createWriteStream(_command["default"].opts().output), outputFile.write(template(templateData)), cliOutput.forEach(function (cliRow) {
56 | table.push(cliRow);
57 | }), console.log(table.toString());
58 |
59 | case 17:
60 | _context.next = 22;
61 | break;
62 |
63 | case 19:
64 | _context.prev = 19, _context.t0 = _context["catch"](4), console.error("Error occurred", _context.t0);
65 |
66 | case 22:
67 | case "end":
68 | return _context.stop();
69 | }
70 | }, _callee, null, [[4, 19]]);
71 | }))();
--------------------------------------------------------------------------------
/dist/template.handlebars:
--------------------------------------------------------------------------------
1 | {{#if documentTitle}}
2 | {{documentTitle}}
3 | ----------
4 | {{/if}}
5 |
6 | {{#each files}}
7 | **{{filename}}**
8 |
9 | {{#each components}}
10 | ### {{inc @index}}. {{title}}
11 |
12 | {{{description}}}
13 |
14 |
15 | {{#if props}}
16 | Property | Type | Required | Default value | Description
17 | :--- | :--- | :--- | :--- | :---
18 | {{#each props}}
19 | {{@key}}|{{type.name}}|{{#if required}}yes{{else}}no{{/if}}|{{defaultValue.value}}|{{description}}
20 | {{/each}}
21 | {{/if}}
22 | {{/each}}
23 | -----
24 | {{/each}}
25 |
26 | This document was generated by the **React DOC Generator v{{version}}** .
27 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-doc-generator",
3 | "version": "1.2.8",
4 | "description": "Generate a simple React Component documentation in Markdown.",
5 | "main": "dist/index.js",
6 | "bin": {
7 | "react-doc-generator": "dist/react-doc-generator.js"
8 | },
9 | "scripts": {
10 | "lint": "eslint src",
11 | "transpile": "babel --plugins minify-simplify src -D -d dist --ignore '__tests__,__mocks__' --presets=@babel/preset-env,@babel/preset-flow,@babel/preset-react",
12 | "watch": "babel src -D -d dist --ignore '__tests__,__mocks__' --watch",
13 | "pretest": "npm run transpile",
14 | "preversion": "npm run lint",
15 | "test": "jest"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "git+https://github.com/marborkowski/react-doc-generator.git"
20 | },
21 | "author": "Marcin Borkowski",
22 | "license": "MIT",
23 | "bugs": {
24 | "url": "https://github.com/marborkowski/react-doc-generator/issues"
25 | },
26 | "homepage": "https://github.com/marborkowski/react-doc-generator#readme",
27 | "keywords": [
28 | "react",
29 | "react-docgen",
30 | "markdown",
31 | "documentation",
32 | "generator",
33 | "tool",
34 | "tools",
35 | "docgen",
36 | "readme file",
37 | "readme",
38 | "instruction",
39 | "guide",
40 | "list of components",
41 | "components",
42 | "spa",
43 | "webpack",
44 | "engine"
45 | ],
46 | "dependencies": {
47 | "cli-table": "^0.3.11",
48 | "colors": "^1.4.0",
49 | "commander": "9.1.0",
50 | "handlebars": "^4.7.7",
51 | "node-dir": "^0.1.17",
52 | "react-docgen": "^5.4.0"
53 | },
54 | "peerDependencies": {
55 | "prop-types": "16 - 18",
56 | "react": "16 - 18",
57 | "react-dom": "16 - 18"
58 | },
59 | "devDependencies": {
60 | "@babel/cli": "^7.17.6",
61 | "@babel/core": "^7.17.9",
62 | "@babel/plugin-proposal-class-properties": "^7.5.5",
63 | "@babel/plugin-transform-runtime": "^7.17.0",
64 | "@babel/preset-env": "^7.16.11",
65 | "@babel/preset-flow": "^7.16.7",
66 | "@babel/preset-react": "^7.16.7",
67 | "babel-eslint": "^10.1.0",
68 | "babel-jest": "^27.5.1",
69 | "babel-plugin-minify-simplify": "^0.5.1",
70 | "eslint": "^8.12.0",
71 | "eslint-config-react-app": "^7.0.0",
72 | "eslint-plugin-flowtype": "^8.0.3",
73 | "eslint-plugin-import": "^2.26.0",
74 | "eslint-plugin-jsx-a11y": "^6.5.1",
75 | "eslint-plugin-react": "^7.29.4",
76 | "jest-cli": "^27.5.1"
77 | },
78 | "babel": {
79 | "presets": [
80 | "env"
81 | ]
82 | },
83 | "eslintConfig": {
84 | "extends": "react-app"
85 | },
86 | "jest": {
87 | "roots": [
88 | "src"
89 | ],
90 | "testRegex": "/__tests__/(.+?).test.js$"
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "targets": {
7 | "esmodules": true
8 | }
9 | }
10 | ],
11 | "@babel/preset-flow",
12 | "@babel/preset-react"
13 | ],
14 | "plugins": ["minify-simplify", "@babel/plugin-transform-runtime"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/__mocks__/ExampleComponent.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var PropTypes = require('prop-types');
3 |
4 | /**
5 | * General component description.
6 | * fdgdfgdf gfdgfdg fdgfdgdfg
7 | * gdfgfdgdfg dfgdfgfdg dfg df getDefaultPropsg fdgfd
8 | * gfdgfdgdfgfdg.
9 | *
10 | *
11 | * Example:
12 | * ```html
13 | *
14 | * ```
15 | */
16 | var Component = React.createClass({
17 | propTypes: {
18 | /**
19 | * Description of prop "toe" has one break line
20 | * here following more comments and has default
21 | * empty string.
22 | */
23 | toe: PropTypes.string,
24 | /**
25 | * Description of prop "finger".
26 | */
27 | finger: PropTypes.string,
28 | /**
29 | * Description of prop "foo".
30 | */
31 | foo: PropTypes.number,
32 | /**
33 | * Description of prop "bar" (a custom validation function).
34 | */
35 | bar: function(props, propName, componentName) {
36 | // ...
37 | },
38 | baz: PropTypes.oneOfType([
39 | PropTypes.number,
40 | PropTypes.string
41 | ]),
42 | },
43 |
44 | getDefaultProps: function() {
45 | return {
46 | finger: 'medium',
47 | toe: '',
48 | foo: 42,
49 | bar: 21
50 | };
51 | },
52 |
53 | render: function() {
54 | return (
55 |
56 | Hello World!
57 |
58 | );
59 | }
60 | });
61 |
62 | module.exports = Component;
63 |
--------------------------------------------------------------------------------
/src/__mocks__/OtherExampleComponent.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 |
4 | type Component1PropType = {
5 | foo: number,
6 | /**
7 | * Description of prop "bar" (a custom validation function).
8 | */
9 | bar: () => void,
10 | baz: number|string,
11 | onExit: () => void
12 | }
13 | /**
14 | * General component description.
15 | */
16 | export class Component1 extends React.Component {
17 |
18 | static defaultProps = {
19 | foo: 10000099999,
20 | onExit: () => {
21 | console.debug('onExit');
22 | }
23 | }
24 |
25 | render () {
26 | return (Hello
);
27 | }
28 | }
29 |
30 | type Component2PropType = {
31 | /**
32 | * Description of prop "foo".
33 | */
34 | foo: number,
35 | /**
36 | * Description of prop "bar" (a custom validation function).
37 | */
38 | bar: () => mixed,
39 | baz: number | string,
40 | }
41 | /**
42 | * General another component description.
43 | * Blah blah blah...
44 | * fdfdfsdf
45 | * fdsfsd
46 | */
47 | function Component2(props: Component2PropType) {
48 | return (Hello
);
49 | }
50 | Component2.displayName = "DUPA"
51 | export default Component2;
52 |
--------------------------------------------------------------------------------
/src/__mocks__/inside/OtherExampleComponent.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | /**
4 | * General component description.
5 | */
6 | export class Component1 extends React.Component {
7 | static propTypes = {
8 | /**
9 | * Description of prop "foo".
10 | */
11 | foo: React.PropTypes.number,
12 | /**
13 | * Description of prop "bar" (a custom validation function).
14 | */
15 | bar: function(props, propName, componentName) {
16 | // ...
17 | },
18 | baz: React.PropTypes.oneOfType([
19 | React.PropTypes.number,
20 | React.PropTypes.string
21 | ]),
22 | onExit: React.PropTypes.func
23 | }
24 |
25 | static defaultProps = {
26 | foo: 10000099999,
27 | onExit: () => {
28 | console.debug('onExit');
29 | }
30 | }
31 |
32 | render () {
33 | return (Hello
);
34 | }
35 | }
36 |
37 | /**
38 | * General another component description.
39 | * Blah blah blah...
40 | * fdfdfsdf
41 | * fdsfsd
42 | */
43 | class Component2 extends React.Component {
44 | displayName = "DUPA";
45 | static propTypes = {
46 | /**
47 | * Description of prop "foo".
48 | */
49 | foo: React.PropTypes.number,
50 | /**
51 | * Description of prop "bar" (a custom validation function).
52 | */
53 | bar: function(props, propName, componentName) {
54 | // ...
55 | },
56 | baz: React.PropTypes.oneOfType([
57 | React.PropTypes.number,
58 | React.PropTypes.string
59 | ]),
60 | }
61 |
62 | render () {
63 | return (Hello
);
64 | }
65 | }
66 |
67 | export default Component2;
68 |
--------------------------------------------------------------------------------
/src/__tests__/__snapshots__/generatereactdoc.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`GenerateReactDoc Whole thing should work 1`] = `
4 | Array [
5 | Object {
6 | "files": Array [
7 | Object {
8 | "components": Array [
9 | Object {
10 | "description": "fdgdfgdf gfdgfdg fdgfdgdfg
11 | gdfgfdgdfg dfgdfgfdg dfg df getDefaultPropsg fdgfd
12 | gfdgfdgdfgfdg.
13 |
14 |
15 | Example:
16 | \`\`\`html
17 |
18 | \`\`\`
19 |
20 | ",
21 | "methods": Array [],
22 | "props": Object {
23 | "bar": Object {
24 | "defaultValue": Object {
25 | "computed": false,
26 | "value": "21",
27 | },
28 | "description": "Description of prop \\"bar\\" (a custom validation function).",
29 | "required": false,
30 | "type": Object {
31 | "name": "custom",
32 | "raw": "function(props, propName, componentName) {
33 | // ...
34 | }",
35 | },
36 | },
37 | "baz": Object {
38 | "defaultValue": Object {
39 | "value": undefined,
40 | },
41 | "description": "",
42 | "required": false,
43 | "type": Object {
44 | "name": "union",
45 | "value": Array [
46 | Object {
47 | "name": "number",
48 | },
49 | Object {
50 | "name": "string",
51 | },
52 | ],
53 | },
54 | },
55 | "finger": Object {
56 | "defaultValue": Object {
57 | "computed": false,
58 | "value": "'medium'",
59 | },
60 | "description": "Description of prop \\"finger\\".",
61 | "required": false,
62 | "type": Object {
63 | "name": "string",
64 | },
65 | },
66 | "foo": Object {
67 | "defaultValue": Object {
68 | "computed": false,
69 | "value": "42",
70 | },
71 | "description": "Description of prop \\"foo\\".",
72 | "required": false,
73 | "type": Object {
74 | "name": "number",
75 | },
76 | },
77 | "toe": Object {
78 | "defaultValue": Object {
79 | "computed": false,
80 | "value": "''",
81 | },
82 | "description": "Description of prop \\"toe\\" has one break line here following more comments and has default empty string.",
83 | "required": false,
84 | "type": Object {
85 | "name": "string",
86 | },
87 | },
88 | },
89 | "title": "General component description.",
90 | },
91 | ],
92 | "filename": "/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/ExampleComponent.js",
93 | },
94 | Object {
95 | "components": Array [
96 | Object {
97 | "description": "null
98 |
99 | ",
100 | "displayName": "Component1",
101 | "methods": Array [],
102 | "props": Object {
103 | "bar": Object {
104 | "defaultValue": Object {
105 | "value": undefined,
106 | },
107 | "description": "Description of prop \\"bar\\" (a custom validation function).",
108 | "flowType": Object {
109 | "name": "signature",
110 | "raw": "() => void",
111 | "signature": Object {
112 | "arguments": Array [],
113 | "return": Object {
114 | "name": "void",
115 | },
116 | },
117 | "type": "function",
118 | },
119 | "required": true,
120 | "type": Object {
121 | "name": "() => void",
122 | },
123 | },
124 | "baz": Object {
125 | "defaultValue": Object {
126 | "value": undefined,
127 | },
128 | "description": "",
129 | "flowType": Object {
130 | "elements": Array [
131 | Object {
132 | "name": "number",
133 | },
134 | Object {
135 | "name": "string",
136 | },
137 | ],
138 | "name": "union",
139 | "raw": "number|string",
140 | },
141 | "required": true,
142 | "type": Object {
143 | "name": "number|string",
144 | },
145 | },
146 | "foo": Object {
147 | "defaultValue": Object {
148 | "computed": false,
149 | "value": "10000099999",
150 | },
151 | "description": "",
152 | "flowType": Object {
153 | "name": "number",
154 | },
155 | "required": false,
156 | "type": Object {
157 | "name": "number",
158 | },
159 | },
160 | "onExit": Object {
161 | "defaultValue": Object {
162 | "computed": false,
163 | "value": "() => {
164 | console.debug('onExit');
165 | }",
166 | },
167 | "description": "",
168 | "flowType": Object {
169 | "name": "signature",
170 | "raw": "() => void",
171 | "signature": Object {
172 | "arguments": Array [],
173 | "return": Object {
174 | "name": "void",
175 | },
176 | },
177 | "type": "function",
178 | },
179 | "required": false,
180 | "type": Object {
181 | "name": "() => void",
182 | },
183 | },
184 | },
185 | "title": "Component1",
186 | },
187 | Object {
188 | "description": "Blah blah blah...
189 | fdfdfsdf
190 | fdsfsd
191 |
192 | ",
193 | "displayName": "DUPA",
194 | "methods": Array [],
195 | "props": Object {
196 | "bar": Object {
197 | "defaultValue": Object {
198 | "value": undefined,
199 | },
200 | "description": "Description of prop \\"bar\\" (a custom validation function).",
201 | "flowType": Object {
202 | "name": "signature",
203 | "raw": "() => mixed",
204 | "signature": Object {
205 | "arguments": Array [],
206 | "return": Object {
207 | "name": "mixed",
208 | },
209 | },
210 | "type": "function",
211 | },
212 | "required": true,
213 | "type": Object {
214 | "name": "() => mixed",
215 | },
216 | },
217 | "baz": Object {
218 | "defaultValue": Object {
219 | "value": undefined,
220 | },
221 | "description": "",
222 | "flowType": Object {
223 | "elements": Array [
224 | Object {
225 | "name": "number",
226 | },
227 | Object {
228 | "name": "string",
229 | },
230 | ],
231 | "name": "union",
232 | "raw": "number | string",
233 | },
234 | "required": true,
235 | "type": Object {
236 | "name": "number | string",
237 | },
238 | },
239 | "foo": Object {
240 | "defaultValue": Object {
241 | "value": undefined,
242 | },
243 | "description": "Description of prop \\"foo\\".",
244 | "flowType": Object {
245 | "name": "number",
246 | },
247 | "required": true,
248 | "type": Object {
249 | "name": "number",
250 | },
251 | },
252 | },
253 | "title": "DUPA",
254 | },
255 | ],
256 | "filename": "/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/OtherExampleComponent.js",
257 | },
258 | Object {
259 | "components": Array [
260 | Object {
261 | "description": "null
262 |
263 | ",
264 | "displayName": "Component1",
265 | "methods": Array [],
266 | "props": Object {
267 | "bar": Object {
268 | "defaultValue": Object {
269 | "value": undefined,
270 | },
271 | "description": "Description of prop \\"bar\\" (a custom validation function).",
272 | "required": false,
273 | "type": Object {
274 | "name": "custom",
275 | "raw": "function(props, propName, componentName) {
276 | // ...
277 | }",
278 | },
279 | },
280 | "baz": Object {
281 | "defaultValue": Object {
282 | "value": undefined,
283 | },
284 | "description": "",
285 | "required": false,
286 | "type": Object {
287 | "name": "union",
288 | "value": Array [
289 | Object {
290 | "name": "number",
291 | },
292 | Object {
293 | "name": "string",
294 | },
295 | ],
296 | },
297 | },
298 | "foo": Object {
299 | "defaultValue": Object {
300 | "computed": false,
301 | "value": "10000099999",
302 | },
303 | "description": "Description of prop \\"foo\\".",
304 | "required": false,
305 | "type": Object {
306 | "name": "number",
307 | },
308 | },
309 | "onExit": Object {
310 | "defaultValue": Object {
311 | "computed": false,
312 | "value": "See code",
313 | },
314 | "description": "",
315 | "required": false,
316 | "type": Object {
317 | "name": "func",
318 | },
319 | },
320 | },
321 | "title": "Component1",
322 | },
323 | Object {
324 | "description": "Blah blah blah...
325 | fdfdfsdf
326 | fdsfsd
327 |
328 | ",
329 | "displayName": "DUPA",
330 | "methods": Array [],
331 | "props": Object {
332 | "bar": Object {
333 | "defaultValue": Object {
334 | "value": undefined,
335 | },
336 | "description": "Description of prop \\"bar\\" (a custom validation function).",
337 | "required": false,
338 | "type": Object {
339 | "name": "custom",
340 | "raw": "function(props, propName, componentName) {
341 | // ...
342 | }",
343 | },
344 | },
345 | "baz": Object {
346 | "defaultValue": Object {
347 | "value": undefined,
348 | },
349 | "description": "",
350 | "required": false,
351 | "type": Object {
352 | "name": "union",
353 | "value": Array [
354 | Object {
355 | "name": "number",
356 | },
357 | Object {
358 | "name": "string",
359 | },
360 | ],
361 | },
362 | },
363 | "foo": Object {
364 | "defaultValue": Object {
365 | "value": undefined,
366 | },
367 | "description": "Description of prop \\"foo\\".",
368 | "required": false,
369 | "type": Object {
370 | "name": "number",
371 | },
372 | },
373 | },
374 | "title": "DUPA",
375 | },
376 | ],
377 | "filename": "/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/inside/OtherExampleComponent.js",
378 | },
379 | ],
380 | "version": "1.2.7",
381 | },
382 | Array [
383 | Array [
384 | "/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/ExampleComponent.js",
385 | 1,
386 | "[32mOK.[39m",
387 | ],
388 | Array [
389 | "/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/OtherExampleComponent.js",
390 | 2,
391 | "[32mOK.[39m",
392 | ],
393 | Array [
394 | "/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/inside/OtherExampleComponent.js",
395 | 2,
396 | "[32mOK.[39m",
397 | ],
398 | ],
399 | ]
400 | `;
401 |
--------------------------------------------------------------------------------
/src/__tests__/__snapshots__/processprop.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`ProcessProp Process prop should not modify the default value if the type is a string 1`] = `
4 | Object {
5 | "defaultValue": Object {
6 | "value": "somestring",
7 | },
8 | "description": "",
9 | "type": Object {
10 | "name": "string",
11 | },
12 | }
13 | `;
14 |
15 | exports[`ProcessProp Process prop should not modify the default value if the type is not string but default value doesnt have special characters 1`] = `
16 | Object {
17 | "defaultValue": Object {
18 | "value": 22,
19 | },
20 | "description": "",
21 | "type": Object {
22 | "name": "number",
23 | },
24 | }
25 | `;
26 |
27 | exports[`ProcessProp Process prop should overwrite the default value when type is not string and there are invalid characters 1`] = `
28 | Object {
29 | "defaultValue": Object {
30 | "value": "See code",
31 | },
32 | "description": "",
33 | "type": Object {
34 | "name": "number",
35 | },
36 | }
37 | `;
38 |
--------------------------------------------------------------------------------
/src/__tests__/__snapshots__/react-doc-generator.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`output file has needed values 1`] = `
4 | Array [
5 | "",
6 | "**/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/ExampleComponent.js**",
7 | "",
8 | "### 1. General component description.",
9 | "",
10 | "fdgdfgdf gfdgfdg fdgfdgdfg ",
11 | "gdfgfdgdfg dfgdfgfdg dfg df getDefaultPropsg fdgfd ",
12 | "gfdgfdgdfgfdg. ",
13 | " ",
14 | " ",
15 | "Example: ",
16 | "\`\`\`html ",
17 | " ",
18 | "\`\`\` ",
19 | "",
20 | "",
21 | "",
22 | "",
23 | "Property | Type | Required | Default value | Description",
24 | ":--- | :--- | :--- | :--- | :---",
25 | "toe|string|no|''|Description of prop "toe" has one break line here following more comments and has default empty string.",
26 | "finger|string|no|'medium'|Description of prop "finger".",
27 | "foo|number|no|42|Description of prop "foo".",
28 | "bar|custom|no|21|Description of prop "bar" (a custom validation function).",
29 | "baz|union|no||",
30 | "-----",
31 | "**/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/OtherExampleComponent.js**",
32 | "",
33 | "### 1. Component1",
34 | "",
35 | "null ",
36 | "",
37 | "",
38 | "",
39 | "",
40 | "Property | Type | Required | Default value | Description",
41 | ":--- | :--- | :--- | :--- | :---",
42 | "foo|number|no|10000099999|",
43 | "bar|() => void|yes||Description of prop "bar" (a custom validation function).",
44 | "baz|number|string|yes||",
45 | "onExit|() => void|no|() => {",
46 | " console.debug('onExit');",
47 | "}|",
48 | "### 2. DUPA",
49 | "",
50 | "Blah blah blah... ",
51 | "fdfdfsdf ",
52 | "fdsfsd ",
53 | "",
54 | "",
55 | "",
56 | "",
57 | "Property | Type | Required | Default value | Description",
58 | ":--- | :--- | :--- | :--- | :---",
59 | "foo|number|yes||Description of prop "foo".",
60 | "bar|() => mixed|yes||Description of prop "bar" (a custom validation function).",
61 | "baz|number | string|yes||",
62 | "-----",
63 | "**/Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/inside/OtherExampleComponent.js**",
64 | "",
65 | "### 1. Component1",
66 | "",
67 | "null ",
68 | "",
69 | "",
70 | "",
71 | "",
72 | "Property | Type | Required | Default value | Description",
73 | ":--- | :--- | :--- | :--- | :---",
74 | "foo|number|no|10000099999|Description of prop "foo".",
75 | "bar|custom|no||Description of prop "bar" (a custom validation function).",
76 | "baz|union|no||",
77 | "onExit|func|no|See code|",
78 | "### 2. DUPA",
79 | "",
80 | "Blah blah blah... ",
81 | "fdfdfsdf ",
82 | "fdsfsd ",
83 | "",
84 | "",
85 | "",
86 | "",
87 | "Property | Type | Required | Default value | Description",
88 | ":--- | :--- | :--- | :--- | :---",
89 | "foo|number|no||Description of prop "foo".",
90 | "bar|custom|no||Description of prop "bar" (a custom validation function).",
91 | "baz|union|no||",
92 | "-----",
93 | "",
94 | "This document was generated by the **React DOC Generator v1.2.7** . ",
95 | "",
96 | ]
97 | `;
98 |
99 | exports[`react-doc-generator contains help section if no argument is available in query 1`] = `
100 | "[37m[39m
101 |
102 | [37mREACT DOC GENERATOR v1.2.7[39m
103 | [37mby Marcin Borkowski [39m
104 | [31mPlease specify as the first argument![39m
105 | Usage: react-doc-generator [options]
106 |
107 | Options:
108 | -V, --version output the version number
109 | -x, --extensions Include only these file extensions. Default:
110 | js,jsx (default: [\\"js\\",\\"jsx\\"])
111 | -i, --ignore Folders to ignore. Default:
112 | node_modules,__tests__,__mocks__ (default:
113 | [\\"node_modules\\",\\"__tests__\\",\\"__mocks__\\"])
114 | -e, --exclude-patterns Filename patterns to exclude. Default: []
115 | (default: [])
116 | -t, --title [value] Document title. Default: 'Components'
117 | (default: \\"Components\\")
118 | -o, --output Markdown file to write. Default:
119 | 'DOCUMENTATION.MD' (default:
120 | \\"DOCUMENTATION.MD\\")
121 | -h, --help display help for command
122 | "
123 | `;
124 |
125 | exports[`react-doc-generator has the proper console output 1`] = `
126 | "[37m[39m
127 |
128 | [37mREACT DOC GENERATOR v1.2.7[39m
129 | [37mby Marcin Borkowski [39m
130 | ┌──────────────────────────────────────────────────────────────────────────────────────────────────┬────────────┬────────┐
131 | │ [36mPath[39m │ [36mComponents[39m │ [36mStatus[39m │
132 | ├──────────────────────────────────────────────────────────────────────────────────────────────────┼────────────┼────────┤
133 | │ /Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/ExampleComponent.js │ 1 │ [32mOK.[39m │
134 | ├──────────────────────────────────────────────────────────────────────────────────────────────────┼────────────┼────────┤
135 | │ /Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/OtherExampleComponent.js │ 2 │ [32mOK.[39m │
136 | ├──────────────────────────────────────────────────────────────────────────────────────────────────┼────────────┼────────┤
137 | │ /Users/marcin/Projects/Private/react-doc-generator/src/__mocks__/inside/OtherExampleComponent.js │ 2 │ [32mOK.[39m │
138 | └──────────────────────────────────────────────────────────────────────────────────────────────────┴────────────┴────────┘
139 | "
140 | `;
141 |
142 | exports[`react-doc-generator return the proper message when given extensions not found 1`] = `
143 | "[37m[39m
144 |
145 | [37mREACT DOC GENERATOR v1.2.7[39m
146 | [37mby Marcin Borkowski [39m
147 | [1m[33mWarning:[39m[22m [33mCould not find any files matching the file type: \`*.4hs0\` OR \`*.kku4\`[39m
148 |
149 | ┌──────┬────────────┬────────┐
150 | │ [36mPath[39m │ [36mComponents[39m │ [36mStatus[39m │
151 | └──────┴────────────┴────────┘
152 | "
153 | `;
154 |
--------------------------------------------------------------------------------
/src/__tests__/generatereactdoc.test.js:
--------------------------------------------------------------------------------
1 | import generateReactDocs from "../generatereactdoc";
2 | import path from "path";
3 |
4 | describe("GenerateReactDoc", () => {
5 | it("Whole thing should work", async () => {
6 | const output = await generateReactDocs({
7 | sourceDir: path.resolve(__dirname, "../__mocks__"),
8 | extensions: ["js", "jsx"],
9 | outputDir: path.resolve(__dirname, "../__mocks__/output.md"),
10 | });
11 | expect(output).toMatchSnapshot();
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/src/__tests__/processprop.test.js:
--------------------------------------------------------------------------------
1 | import { processProp } from '../generatereactdoc'
2 |
3 | describe('ProcessProp', () => {
4 | it('Process prop should not modify the default value if the type is a string', () => {
5 | const mockProp = {
6 | type: {
7 | name:'string'
8 | },
9 | defaultValue: {
10 | value:'somestring'
11 | }
12 | }
13 | const output = processProp(mockProp)
14 | expect(output).toMatchSnapshot()
15 | })
16 | it('Process prop should not modify the default value if the type is not string but default value doesnt have special characters', () => {
17 | const mockProp = {
18 | type: {
19 | name: 'number',
20 | },
21 | defaultValue: {
22 | value:22
23 | }
24 | }
25 | const output = processProp(mockProp)
26 | expect(output).toMatchSnapshot()
27 | })
28 | it('Process prop should overwrite the default value when type is not string and there are invalid characters', () => {
29 | const mockProp = {
30 | type: {
31 | name: 'number',
32 | },
33 | defaultValue: {
34 | value:'@#454'
35 | }
36 | }
37 | const output = processProp(mockProp)
38 | expect(output).toMatchSnapshot()
39 | })
40 | })
--------------------------------------------------------------------------------
/src/__tests__/react-doc-generator.test.js:
--------------------------------------------------------------------------------
1 | // https://travis-ci.org/marborkowski/react-doc-generator
2 |
3 | const path = require("path");
4 | const fs = require("fs");
5 | const spawn = require("child_process").spawn;
6 |
7 | function run(command, args) {
8 | let stdout = [];
9 | let stderr = [];
10 |
11 | return new Promise((resolve, reject) => {
12 | let spawned = spawn(command, args);
13 | spawned.stdout.on("data", (data) => {
14 | stdout.push(data);
15 | });
16 | spawned.stderr.on("data", (data) => stderr.push(data));
17 | spawned.on("close", () => resolve([stdout.join(""), stderr.join("")]));
18 | spawned.on("error", (err) => {
19 | throw err;
20 | });
21 | }).catch((error) => {
22 | console.log(error, "Error");
23 | throw error;
24 | });
25 | }
26 |
27 | function loadDoc() {
28 | return new Promise((resolve, reject) => {
29 | fs.readFile("./dist/DOCUMENTATION.md", "utf8", function (err, data) {
30 | if (err) {
31 | reject(err);
32 | } else {
33 | resolve(data);
34 | }
35 | });
36 | });
37 | }
38 | let binPath = path.join(__dirname, "../../dist/react-doc-generator.js");
39 | fs.chmodSync(binPath, "0777");
40 | describe("react-doc-generator", () => {
41 | it("has the proper console output", async () => {
42 | try {
43 | const stdout = await run("node", [
44 | binPath,
45 | "src/__mocks__",
46 | "-o",
47 | "./dist/DOCUMENTATION.md",
48 | ]);
49 | const output = stdout[0];
50 | expect(output).toMatchSnapshot();
51 | } catch (e) {
52 | console.error(e);
53 | throw e;
54 | }
55 | });
56 |
57 | it("return the proper message when given extensions not found", async () => {
58 | try {
59 | const stdout = await run("node", [
60 | binPath,
61 | "src/__mocks__",
62 | "-o",
63 | "./dist/DOCUMENTATION.md",
64 | "-x",
65 | "4hs0,kku4",
66 | ]);
67 | const output = stdout[0];
68 | expect(output).toMatchSnapshot();
69 | } catch (e) {
70 | throw e;
71 | }
72 | });
73 |
74 | it("contains help section if no argument is available in query", async () => {
75 | try {
76 | const stdout = await run("node", [
77 | binPath,
78 | "-o",
79 | "./dist/DOCUMENTATION.md",
80 | ]);
81 | const output = stdout[0];
82 | expect(output).toMatchSnapshot();
83 | } catch (e) {
84 | throw e;
85 | }
86 | });
87 | });
88 | describe("output file", () => {
89 | it("has needed values", async () => {
90 | try {
91 | await run("node", [
92 | binPath,
93 | "src/__mocks__",
94 | "-o",
95 | "./dist/DOCUMENTATION.md",
96 | "-t",
97 | "MyTitleXYZ",
98 | ]);
99 | const result = await loadDoc();
100 | const lines = result.split("\n");
101 | expect(lines).toMatchSnapshot();
102 | } catch (e) {
103 | throw e;
104 | }
105 | });
106 | });
107 |
--------------------------------------------------------------------------------
/src/__tests__/utilities.test.js:
--------------------------------------------------------------------------------
1 | import {isDefaultValueTypeString,isInvalidDefaultValue } from '../generatereactdoc'
2 | describe('isDefaultValueTypeString', () =>{
3 | it('Should return false if type of default value is not string', () => {
4 | const mockInput = {
5 | type: {name: 'number'},
6 | defaultValue: {
7 | value: 23
8 | }
9 | }
10 | const isString = isDefaultValueTypeString(mockInput)
11 | expect(isString).toEqual(false)
12 | })
13 | it('Should return false if type of default value is string but prop type is not string', () => {
14 | const mockInput = {
15 | type: {name: 'number'},
16 | defaultValue: {
17 | value: 'sdsd'
18 | }
19 | }
20 | const isString = isDefaultValueTypeString(mockInput)
21 | expect(isString).toEqual(false)
22 | })
23 | it('Should return null if prop was undefined', () => {
24 | const isString = isDefaultValueTypeString()
25 | expect(isString).toEqual(null)
26 | })
27 | it('Should return true if prop type was string and typeof default value was also string', () => {
28 | const mockInput = {
29 | type: {name: 'string'},
30 | defaultValue: {
31 | value: 'sdsd'
32 | }
33 | }
34 | const isString = isDefaultValueTypeString(mockInput)
35 | expect(isString).toEqual(true)
36 | })
37 | })
38 |
39 | describe('isInvalidDefaultValue', () => {
40 | it('Should return true for invalid input', () => {
41 | const isInValid = isInvalidDefaultValue('3###')
42 | expect(isInValid).toEqual(true)
43 | })
44 | it('Should return false for valid string input', () => {
45 | const isValid = isInvalidDefaultValue('3333')
46 | expect(isValid).toEqual(false)
47 | })
48 | it('Should return false for valid number input', () => {
49 | const isValid = isInvalidDefaultValue(3333)
50 | expect(isValid).toEqual(false)
51 | })
52 | })
--------------------------------------------------------------------------------
/src/generatereactdoc.js:
--------------------------------------------------------------------------------
1 | import path from "path";
2 | import { parse, resolver } from "react-docgen";
3 | import { promisify } from "util";
4 | import { readFiles } from "node-dir";
5 |
6 | import Colors from "colors";
7 | import pkg from "../package.json";
8 |
9 | const readFilesPromise = promisify(readFiles);
10 |
11 | const templateData = {
12 | files: [],
13 | version: pkg.version,
14 | };
15 |
16 | export const isDefaultValueTypeString = (prop) => {
17 | if (!prop || !prop.type) {
18 | return null;
19 | }
20 | return (
21 | prop.type.name === "string" && typeof prop.defaultValue.value === "string"
22 | );
23 | };
24 | export const isInvalidDefaultValue = (value) =>
25 | /[^\w\s.&:\-+*,!@%$]+/gim.test(value);
26 | export const getTypeOfProp = (prop) => {
27 | if (!prop) {
28 | return "";
29 | }
30 | if (prop.type) {
31 | return prop.type;
32 | } else if (prop.flowType) {
33 | const typeName = prop.flowType.raw ? prop.flowType.raw : prop.flowType.name;
34 | return {
35 | name: typeName,
36 | };
37 | }
38 | };
39 | export function processProp(prop) {
40 | const { defaultValue = {} } = prop;
41 | const isString = isDefaultValueTypeString(prop);
42 | const isInvalidValue = isInvalidDefaultValue(defaultValue.value);
43 | const processedType = getTypeOfProp(prop);
44 | const processedDefaultValue =
45 | defaultValue && isInvalidValue && isString === false
46 | ? "See code"
47 | : defaultValue.value;
48 | const processedDescription = prop.description
49 | ? prop.description
50 | .split("\n")
51 | .map((text) => text.replace(/(^\s+|\s+$)/, ""))
52 | .map((hasValidValue) => hasValidValue)
53 | .join(" ")
54 | : "";
55 |
56 | return {
57 | ...prop,
58 | defaultValue: { ...prop.defaultValue, value: processedDefaultValue },
59 | description: processedDescription,
60 | type: processedType,
61 | };
62 | }
63 | function parseSingleFile(fileContent) {
64 | const components = parse(
65 | fileContent,
66 | resolver.findAllExportedComponentDefinitions
67 | );
68 | const componentObjects = components.map((component) => {
69 | const { description, displayName } = component;
70 | const modifiedTitle =
71 | description && !displayName
72 | ? description.match(/^(.*)$/m)[0]
73 | : displayName;
74 | let modifiedDescription = null;
75 | if (description) {
76 | if (description.split("\n").length > 1) {
77 | modifiedDescription = description.replace(/[\w\W]+?\n+?/, "");
78 | modifiedDescription = modifiedDescription.replace(/(\n)/gm, " \n");
79 | }
80 | modifiedDescription = `${modifiedDescription} \n\n`;
81 | }
82 | // validate default values
83 | const propEntries = Object.entries(component.props);
84 | const modifiedPropEntries = propEntries.map(([propName, propObject]) => {
85 | const modifiedProp = processProp(propObject);
86 | return [propName, modifiedProp];
87 | });
88 | const modife = modifiedPropEntries.reduce((accum, current) => {
89 | const modifiedAccum = { ...accum, [current[0]]: current[1] };
90 | return modifiedAccum;
91 | }, {});
92 | return {
93 | ...component,
94 | title: modifiedTitle,
95 | description: modifiedDescription,
96 | props: modife,
97 | };
98 | });
99 | return componentObjects;
100 | }
101 | async function generateReactDocs({
102 | sourceDir,
103 | extensions = [],
104 | excludePatterns = [],
105 | ignoreDirectory = [],
106 | }) {
107 | const cliOutput = [];
108 | const inputPath = path.resolve(sourceDir);
109 | await readFilesPromise(
110 | inputPath,
111 | {
112 | match: new RegExp("\\.(?:" + extensions.join("|") + ")$"),
113 | exclude: excludePatterns,
114 | excludeDir: ignoreDirectory,
115 | },
116 | (err, content, filename, next) => {
117 | if (err) {
118 | console.log(err, "error");
119 | throw err;
120 | }
121 | try {
122 | const components = parseSingleFile(content);
123 | templateData.files.push({ filename, components });
124 | cliOutput.push([filename, components.length, Colors.green(`OK.`)]);
125 | } catch (e) {
126 | console.error("In error", e);
127 | cliOutput.push([
128 | filename,
129 | 0,
130 | Colors.red(`You have to export at least one valid React Class!`),
131 | ]);
132 | }
133 |
134 | next();
135 | }
136 | );
137 | if (templateData.files.length === 0) {
138 | let allExtensions = extensions.map((ext) => {
139 | return `\`*.${ext}\``;
140 | });
141 | console.log(
142 | `${Colors.bold.yellow("Warning:")} ${Colors.yellow(
143 | `Could not find any files matching the file type: ${allExtensions.join(
144 | " OR "
145 | )}`
146 | )}\n`
147 | );
148 | }
149 |
150 | return [templateData, cliOutput];
151 | }
152 | export default generateReactDocs;
153 |
--------------------------------------------------------------------------------
/src/lib/command.js:
--------------------------------------------------------------------------------
1 | const { program } = require("commander");
2 |
3 | const pkg = require("../../package.json");
4 |
5 | export default (function Command() {
6 | const list = (val) => {
7 | val = val.replace(/[, ]+/g, ",").trim();
8 | return val.split(",").filter((value) => value.length > 0);
9 | };
10 |
11 | program
12 | .version(pkg.version)
13 | .usage(` [options]`)
14 | .option(
15 | "-x, --extensions ",
16 | "Include only these file extensions. Default: js,jsx",
17 | list,
18 | ["js", "jsx"]
19 | )
20 | .option(
21 | "-i, --ignore ",
22 | "Folders to ignore. Default: node_modules,__tests__,__mocks__",
23 | list,
24 | ["node_modules", "__tests__", "__mocks__"]
25 | )
26 | .option(
27 | "-e, --exclude-patterns ",
28 | "Filename patterns to exclude. Default: []",
29 | list,
30 | []
31 | )
32 | .option(
33 | "-t, --title [value]",
34 | "Document title. Default: 'Components'",
35 | "Components"
36 | )
37 | .option(
38 | "-o, --output ",
39 | "Markdown file to write. Default: 'DOCUMENTATION.MD'",
40 | "DOCUMENTATION.MD"
41 | )
42 | .parse(process.argv);
43 |
44 | return program;
45 | })();
46 |
--------------------------------------------------------------------------------
/src/react-doc-generator.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | import fs from "fs";
3 | import path from "path";
4 | import generateReactDocs from "./generatereactdoc";
5 | import Command from "./lib/command.js";
6 | import Handlebars from "handlebars";
7 |
8 | import Colors from "colors";
9 | import Table from "cli-table";
10 | Handlebars.registerHelper("inc", (value, options) => {
11 | return parseInt(value, 10) + 1;
12 | });
13 | (async () => {
14 | const pkg = require("../package.json");
15 | const template = Handlebars.compile(
16 | `${fs.readFileSync(path.join(__dirname, "template.handlebars"))}`
17 | );
18 | const table = new Table({
19 | head: [
20 | Colors.cyan("Path"),
21 | Colors.cyan("Components"),
22 | Colors.cyan("Status"),
23 | ],
24 | });
25 | console.log(Colors.white(`\n\nREACT DOC GENERATOR v${pkg.version}`));
26 | console.log(Colors.white(`by Marcin Borkowski `));
27 |
28 | try {
29 | if (Command.args.length !== 1) {
30 | console.log(
31 | `${Colors.red("Please specify as the first argument!")}`
32 | );
33 | Command.help();
34 | } else {
35 | const [templateData, cliOutput] = await generateReactDocs({
36 | sourceDir: Command.args[0],
37 | extensions: Command.opts().extensions,
38 | excludePatterns: Command.opts().excludePatterns,
39 | ignoreDirectory: Command.opts().ignore,
40 | });
41 | const outputFile = fs.createWriteStream(Command.opts().output);
42 | outputFile.write(template(templateData));
43 | cliOutput.forEach((cliRow) => {
44 | table.push(cliRow);
45 | });
46 | console.log(table.toString());
47 | }
48 | } catch (e) {
49 | console.error("Error occurred", e);
50 | }
51 | })();
52 |
--------------------------------------------------------------------------------
/src/template.handlebars:
--------------------------------------------------------------------------------
1 | {{#if documentTitle}}
2 | {{documentTitle}}
3 | ----------
4 | {{/if}}
5 |
6 | {{#each files}}
7 | **{{filename}}**
8 |
9 | {{#each components}}
10 | ### {{inc @index}}. {{title}}
11 |
12 | {{{description}}}
13 |
14 |
15 | {{#if props}}
16 | Property | Type | Required | Default value | Description
17 | :--- | :--- | :--- | :--- | :---
18 | {{#each props}}
19 | {{@key}}|{{type.name}}|{{#if required}}yes{{else}}no{{/if}}|{{defaultValue.value}}|{{description}}
20 | {{/each}}
21 | {{/if}}
22 | {{/each}}
23 | -----
24 | {{/each}}
25 |
26 | This document was generated by the **React DOC Generator v{{version}}** .
27 |
--------------------------------------------------------------------------------