From a19c80cb0686712404dbe0218d37bb329b73f82c Mon Sep 17 00:00:00 2001 From: Markus Wolf Date: Sat, 28 May 2016 10:22:18 +0200 Subject: [PATCH] feat(parsing): Add ability to parse babeled files (#121) If there are missing information during the default parsing, then try to match against already babeled sources to get that information. --- index.ts | 20 +++++++++-- package.json | 4 +-- tests/es7-class-babeled.js | 68 ++++++++++++++++++++++++++++++++++++++ tests/parsing-test.ts | 9 +++++ 4 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 tests/es7-class-babeled.js diff --git a/index.ts b/index.ts index e737fab6..23e0c1ed 100644 --- a/index.ts +++ b/index.ts @@ -154,12 +154,28 @@ function parseAst(ast: any, instanceOfResolver: InstanceOfResolver): IParsingRes 'ExpressionStatement': (expressionNode: any): void => { if (expressionNode.expression.type == 'AssignmentExpression' && expressionNode.expression.left.type == 'MemberExpression' - && expressionNode.expression.left.object.name == classname && expressionNode.expression.left.property.name == 'propTypes') { - propTypes = parsePropTypes(expressionNode.expression.right, instanceOfResolver); + if (classname === undefined) { + classname = expressionNode.expression.left.object.name; + } + if (expressionNode.expression.left.object.name == classname) { + propTypes = parsePropTypes(expressionNode.expression.right, instanceOfResolver); + } } } }); + if (exportType === undefined) { + walk(ast.program, { + 'ExpressionStatement': (expressionNode: any): void => { + if (expressionNode.expression.type == 'AssignmentExpression' + && expressionNode.expression.left.type == 'MemberExpression' + && expressionNode.expression.left.object.name == 'exports' + && expressionNode.expression.left.property.name == 'default') { + exportType = ExportType.default; + } + } + }); + } return { exportType, classname, diff --git a/package.json b/package.json index 411883ca..bf4e063e 100644 --- a/package.json +++ b/package.json @@ -14,12 +14,12 @@ ], "scripts": { "start": "npm test", - "clean": "rm -f index.js index.js.map tests/*.js tests/*.js.map", + "clean": "rm -f index.js index.js.map tests/*-test.js tests/*-test.js.map", "prebuild": "npm run clean", "build": "tsc --sourceMap", "build:inline": "tsc --inlineSourceMap", "pretest": "npm run clean && npm run build:inline", - "test": "nyc --reporter lcov ./node_modules/.bin/mocha --recursive tests --all", + "test": "nyc --all --reporter lcov ./node_modules/.bin/mocha --recursive tests/*-test.js", "coverage": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls", "changelog": "conventional-changelog -p angular -i CHANGELOG.md -w", "prerelease": "npm test && npm run build", diff --git a/tests/es7-class-babeled.js b/tests/es7-class-babeled.js new file mode 100644 index 00000000..5e731956 --- /dev/null +++ b/tests/es7-class-babeled.js @@ -0,0 +1,68 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _react = require('react'); + +var React = _interopRequireWildcard(_react); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var Component = function (_React$Component) { + _inherits(Component, _React$Component); + + function Component() { + _classCallCheck(this, Component); + + return _possibleConstructorReturn(this, Object.getPrototypeOf(Component).apply(this, arguments)); + } + + _createClass(Component, [{ + key: 'render', + value: function render() { + return React.createElement('div', null); + } + }]); + + return Component; +}(React.Component); + +Component.propTypes = { + /** + * This is a jsdoc comment for optionalAny. + */ + optionalAny: React.PropTypes.any, + optionalArray: React.PropTypes.array, + optionalBool: React.PropTypes.bool, + optionalFunc: React.PropTypes.func, + optionalNumber: React.PropTypes.number, + optionalObject: React.PropTypes.object, + optionalString: React.PropTypes.string, + optionalNode: React.PropTypes.node, + optionalElement: React.PropTypes.element, + optionalMessage: React.PropTypes.instanceOf(Message), + //optionalEnum: React.PropTypes.oneOf(['News', 'Photos']), + optionalUnion: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]), + optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number), + //optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number), + //optionalObjectWithShape: React.PropTypes.shape({ + // color: React.PropTypes.string, + // fontSize: React.PropTypes.number + //}), + requiredFunc: React.PropTypes.func.isRequired, + requiredAny: React.PropTypes.any.isRequired, + requiredUnion: React.PropTypes.oneOfType([React.PropTypes.array, React.PropTypes.bool]).isRequired, + requiredArrayOf: React.PropTypes.arrayOf(React.PropTypes.string).isRequired +}; +exports.default = Component; + diff --git a/tests/parsing-test.ts b/tests/parsing-test.ts index 3d4cf1b0..6f57338d 100644 --- a/tests/parsing-test.ts +++ b/tests/parsing-test.ts @@ -32,4 +32,13 @@ describe('Parsing', () => { fs.readFileSync(path.join(__dirname, 'es7-class-top-level-module.d.ts')).toString() ); }); + it('should create definition from babeled es7 class component', () => { + const opts: react2dts.IOptions = { + instanceOfResolver: (name: string): string => './path/to/Message' + }; + assert.equal( + react2dts.generateFromFile('component', path.join(__dirname, 'es7-class-babeled.js'), opts), + fs.readFileSync(path.join(__dirname, 'es7-class.d.ts')).toString() + ); + }); });