Skip to content

Commit

Permalink
Merge pull request #79 from alfa-laboratory/feat/func-prop-types
Browse files Browse the repository at this point in the history
feat(*): add params information to func proptypes where possible
  • Loading branch information
Heymdall committed Jun 19, 2018
2 parents c0c9ded + 17c6f8b commit f1e2aae
Show file tree
Hide file tree
Showing 13 changed files with 1,421 additions and 48 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ before_script:

script:
- npm run lint
- npm test

after_script:
- greenkeeper-lockfile-upload
Expand Down
3 changes: 2 additions & 1 deletion gulp-tasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@ function createTasks(packageName, options = {}) {
}))
.pipe(filter(file => !fs.existsSync(
// ignore all files, that already emit d.ts file
path.join(options.publishDir, file.relative).replace(/\.ts$/, '.d.ts')
path.join(process.cwd(), options.publishDir, file.relative)
.replace(/\.tsx?$/, '.d.ts')
)))
.pipe(ts(tsOptions, ts.reporter.nullReporter())) // ignore all errors at compile time
.dts.pipe(gulp.dest(options.publishDir));
Expand Down
2 changes: 2 additions & 0 deletions gulp/component-docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ function componentDocs(libraryName) {
contents: Buffer.from(doc)
}));
} catch (e) {
// eslint-disable-next-line no-console
console.warn(`unable to build docs for ${file.path}`);
// eslint-disable-next-line no-console
console.warn(e);
callback(null);
}
Expand Down
3 changes: 2 additions & 1 deletion gulp/component-typings.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const getReactComponentDefinitionsContent = require('../typings/index');
/**
* Gulp plugin to generate react typings and root package.json for each component.
*
* @param {String} libraryName Library name, will be used in typescript declarations.
* @returns {Function}
*/
function componentTypings() {
Expand All @@ -18,6 +17,7 @@ function componentTypings() {
const componentName = path.parse(file.path).name;
getReactComponentDefinitionsContent(file.path).then((definitionsContent) => {
if (!definitionsContent) {
// eslint-disable-next-line no-console
console.warn(`Unable to create typings for ${file.path}`);
return callback(null);
}
Expand All @@ -28,6 +28,7 @@ function componentTypings() {
contents: Buffer.from(definitionsContent)
}));
}).catch((e) => {
// eslint-disable-next-line no-console
console.error(e);
});
}
Expand Down
1 change: 1 addition & 0 deletions gulp/library-doc.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ function libraryDoc(libraryName) {
try {
components.push(structureForFile(content, componentName));
} catch (e) {
// eslint-disable-next-line no-console
console.warn(`unable to build docs for ${file.path}`);
}

Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,16 @@
"arui-presets": "4.11.9",
"conventional-changelog-cli": "1.3.14",
"conventional-github-releaser": "2.0.0",
"husky": "0.14.3"
"husky": "0.14.3",
"jest": "^23.1.0"
},
"scripts": {
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
"github-release": "conventional-github-releaser -p angular",
"lint": "eslint ./*.js ./gulp/*.js ./typings/*.js",
"test": "jest",
"postversion": "git push origin master && git push --tags && npm publish",
"precommit": "npm run lint",
"precommit": "npm run lint && npm run test",
"release-patch": "npm version patch -m 'chore(*): patch version'",
"release-minor": "npm version minor -m 'chore(*): minor version'",
"release-major": "npm version major -m 'chore(*): major version'",
Expand Down
36 changes: 36 additions & 0 deletions react-doc/component-prop-types-js-doc-handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const getMemberValuePath = require('react-docgen/dist/utils/getMemberValuePath').default;
const resolveToValue = require('react-docgen/dist/utils/resolveToValue').default;
const getPropertyName = require('react-docgen/dist/utils/getPropertyName').default;
const parseJsDoc = require('react-docgen/dist/utils/parseJsDoc').default;
const recast = require('recast');

const { types: { namedTypes: types } } = recast;
// component-prop-types-js-doc-handler
function componentPropTypesJsDocHandler(documentation, path) {
let propTypesPath = getMemberValuePath(path, 'propTypes');

if (!propTypesPath) {
return;
}
propTypesPath = resolveToValue(propTypesPath);
if (!propTypesPath || !types.ObjectExpression.check(propTypesPath.node)) {
return;
}

propTypesPath.get('properties').each((propertyPath) => {
// we only support documentation of actual properties, not spread
if (types.Property.check(propertyPath.node)) {
const propName = getPropertyName(propertyPath);
const propDescriptor = documentation.getPropDescriptor(propName);
if (!propDescriptor.description || !propDescriptor.type) {
return;
}
const jsDoc = parseJsDoc(propDescriptor.description);
propDescriptor.description = jsDoc.description || propDescriptor.description;
propDescriptor.type.params = jsDoc.params || [];
propDescriptor.type.returns = jsDoc.returns;
}
});
}

module.exports = componentPropTypesJsDocHandler;
9 changes: 6 additions & 3 deletions react-doc/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
const path = require('path');
const reactDocGen = require('react-docgen');
const { createDisplayNameHandler } = require('react-docgen-displayname-handler');
const getSourceFileContent = require('./get-source-file-content');
const createResolver = require('./create-resolver');
const createDisplayNameHandler = require('react-docgen-displayname-handler').createDisplayNameHandler;
const componentPropTypesJsDocHandler = require('./component-prop-types-js-doc-handler');

const documentation = {};
const defaultHandlers = [
Expand All @@ -15,7 +16,8 @@ const defaultHandlers = [
reactDocGen.handlers.componentDocblockHandler,
reactDocGen.handlers.displayNameHandler,
reactDocGen.handlers.componentMethodsHandler,
reactDocGen.handlers.componentMethodsJsDocHandler
reactDocGen.handlers.componentMethodsJsDocHandler,
componentPropTypesJsDocHandler
];

function getReactComponentInfo(filePath, parentPath) {
Expand All @@ -24,7 +26,7 @@ function getReactComponentInfo(filePath, parentPath) {
}

const src = getSourceFileContent(filePath, parentPath);
const content = src.content;
const { content } = src;
filePath = src.filePath;
const info = reactDocGen.parse(
content,
Expand All @@ -45,4 +47,5 @@ function getReactComponentInfo(filePath, parentPath) {
return info;
}


module.exports = getReactComponentInfo;
122 changes: 122 additions & 0 deletions typings/__examples__/a.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/* eslint-disable */
import React from 'react';
import PropTypes from 'prop-types';

/**
* Component description.
*/
export default class A extends React.Component {
static propTypes = {
optionalArray: PropTypes.array,
requiredArray: PropTypes.array.isRequired,
/**
* Prop documentation
*/
optionalBool: PropTypes.bool,
requiredBool: PropTypes.bool.isRequired,
optionalFunc: PropTypes.func,
requiredFunc: PropTypes.func.isRequired,
optionalNumber: PropTypes.number,
requiredNumber: PropTypes.number.isRequired,
optionalObject: PropTypes.object,
requiredObject: PropTypes.object.isRequired,
optionalString: PropTypes.string,
requiredString: PropTypes.string.isRequired,
optionalSymbol: PropTypes.symbol,
requiredSymbol: PropTypes.symbol.isRequired,
optionalNode: PropTypes.node,
requiredNode: PropTypes.node.isRequired,
optionalElement: PropTypes.element,
requiredElement: PropTypes.element.isRequired,
optionalMessage: PropTypes.instanceOf(Message),
requiredMessage: PropTypes.instanceOf(Message).isRequired,
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
requiredEnum: PropTypes.oneOf(['News', 'Photos']).isRequired,
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number
]),
requiredUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number
]).isRequired,
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
requiredArrayOf: PropTypes.arrayOf(PropTypes.number).isRequired,
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
requiredObjectOf: PropTypes.objectOf(PropTypes.number).isRequired,
optionalAny: PropTypes.any,
requiredAny: PropTypes.any.isRequired,
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
/**
* Sub prop documentation
*/
fontSize: PropTypes.number.isRequired,
/**
* @param {string} value
*/
onChange: PropTypes.func,
subShape: PropTypes.shape({
/**
* Even deeper documentation
*/
name: PropTypes.string,
size: PropTypes.number
})
}),
/**
* Callback with documentation
*
* @param {String} stringParam
* @param {number} count
* @param {React.MouseEvent} event
* @param {React.KeyboardEvent} anotherEvent
* @param {HTMLDivElement} element some html element
*
* @returns {string|number}
*/
onClick: PropTypes.func,
onChange: PropTypes.func
};

render() {
return null;
}

privateMethod(name) {
}

/**
* Some description.
*
* @public
*/
publicMethod1() {

}

/**
* Maybe we just forgot to add params?
*
* @public
*/
publicMethodWithouParams() {

}

/**
* Some description.
*
* @public
* @param {string} str1 Some description.
* @param {String} str2 Some description.
* @param {number} num1 Some description.
* @param {Number} num2 Some description.
* @param {Boolean} bool1 Some description.
* @param {bool} bool2 Some description.
* @param {boolean} bool3 Some description.
* @param {string|number} union Some description.
*/
publicWithParams(str1, str2, num1, num2, bool1, bool2, bool3, union) {
}
}
Loading

0 comments on commit f1e2aae

Please sign in to comment.