diff --git a/.eslintrc.js b/.eslintrc.js index 2b5ea3d6..605a3f43 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -10,4 +10,8 @@ module.exports = { ecmaFeatures: { modules: false }, + + rules: { + 'no-use-before-define': 2, + }, }; diff --git a/README.md b/README.md index 7b41a8c3..d0aecf7e 100644 --- a/README.md +++ b/README.md @@ -101,51 +101,47 @@ guide](https://github.com/airbnb/javascript/blob/7684892951ef663e1c4e62ad57d662e jscodeshift -t react-codemod/transforms/sort-comp.js ``` -### Explanation of the ES2015 class transform - - * Ignore components with calls to deprecated APIs. This is very defensive, if - the script finds any identifiers called `isMounted`, `getDOMNode`, - `replaceProps`, `replaceState` or `setProps` it will skip the component. - * Replaces `var A = React.createClass(spec)` with - `class A (extends React.Component) {spec}`. - * Pulls out all statics defined on `statics` plus the few special cased - statics like `propTypes`, `childContextTypes`, `contextTypes` and - `displayName` and assigns them after the class is created. - `class A {}; A.foo = bar;` - * Takes `getDefaultProps` and inlines it as a static `defaultProps`. - If `getDefaultProps` is defined as a function with a single statement that - returns an object, it optimizes and transforms - `getDefaultProps() { return {foo: 'bar'}; }` into - `A.defaultProps = {foo: 'bar'};`. If `getDefaultProps` contains more than - one statement it will transform into a self-invoking function like this: - `A.defaultProps = function() {…}();`. Note that this means that the function - will be executed only a single time per app-lifetime. In practice this - hasn't caused any issues – `getDefaultProps` should not contain any - side-effects. - * Binds class methods to the instance if methods are referenced without being - called directly. It checks for `this.foo` but also traces variable - assignments like `var self = this; self.foo`. It does not bind functions - from the React API and ignores functions that are being called directly - (unless it is both called directly and passed around to somewhere else) - * Creates a constructor if necessary. This is necessary if either - `getInitialState` exists in the `React.createClass` spec OR if functions - need to be bound to the instance. - * When `--no-super-class` is passed it only optionally extends - `React.Component` when `setState` or `forceUpdate` are used within the - class. - -The constructor logic is as follows: - - * Call `super(props, context)` if the base class needs to be extended. - * Bind all functions that are passed around, - like `this.foo = this.foo.bind(this)` - * Inline `getInitialState` (and remove `getInitialState` from the spec). It - also updates access of `this.props.foo` to `props.foo` and adds `props` as - argument to the constructor. This is necessary in the case when the base - class does not need to be extended where `this.props` will only be set by - React after the constructor has been run. - * Changes `return StateObject` from `getInitialState` to assign `this.state` - directly. +### Explanation of the new ES2015 class transform with property initializers +1. Determine if mixins are convertible. We only transform a `createClass` call to an ES6 class component when: + - There are no mixins on the class, or + - `options['pure-component']` is true, the `mixins` property is an array and it _only_ contains pure render mixin (the specific module name can be specified using `options['mixin-module-name']`, which defaults to `react-addons-pure-render-mixin`) +2. Ignore components that: + - Call deprecated APIs. This is very defensive, if the script finds any identifiers called `isMounted`, `getDOMNode`, `replaceProps`, `replaceState` or `setProps` it will skip the component + - Explicitly call `this.getInitialState()` and/or `this.getDefaultProps()` since an ES6 class component will no longer have these methods + - Use `arguments` in methods since arrow functions don't have `arguments`. Also please notice that `arguments` should be [very carefully used](https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#3-managing-arguments) and it's generally better to switch to spread (`...args`) instead + - Have inconvertible `getInitialState()`. Specifically if you have variable declarations like `var props = ...` and the right hand side is not `this.props` then we can't inline the state initialization in the `constructor` due to variable shadowing issues + - Have non-primitive right hand side values (like `foo: getStuff()`) in the class spec +3. Transform it to an ES6 class component + 1. Replace `var A = React.createClass(spec)` with `class A extends React.Component {spec}`. If a component uses pure render mixin and passes the mixins test (as described above), it will extend `React.PureComponent` instead + - Remove the `require`/`import` statement that imports pure render mixin when it's no longer being referenced + 2. Pull out all statics defined on `statics` plus the few special cased statics like `childContextTypes`, `contextTypes`, `displayName`, `getDefaultProps()`, and `propTypes` and transform them to `static` properties (`static propTypes = {...};`) + - If `getDefaultProps()` is simple (i.e. it only contains a return statement that returns an object) it will be converted to a simple assignment (`static defaultProps = {...};`). Otherwise an IIFE (immediately-invoked function expression) will be created (`static defaultProps = function() { ... }();`). Note that this means that the function will be executed only a single time per app-lifetime. In practice this hasn't caused any issues — `getDefaultProps` should not contain any side-effects + 3. Transform `getInitialState()` + - If there's no `getInitialState()` or the `getInitialState()` function is simple (i.e., it only contains a return statement that returns an object) then we don't need a constructor; `state` will be lifted to a property initializer (`state = {...};`) + - However, if the object contains references to `this` other than `this.props` and/or `this.context`, we can't be sure about what you'll need from `this`. We need to ensure that our property initializers' evaluation order is safe, so we defer `state`'s initialization by moving it all the way down until all other property initializers have been initialized + - If `getInitialState()` is not simple, we create a `constructor` and convert `getInitialState()` to an assignment to `this.state` + - `constructor` always have `props` as the first parameter + - We only put `context` as the second parameter when (one of) the following things happen in `getInitialState()`: + - It accesses `this.context`, or + - There's a direct method call `this.x()`, or + - `this` is referenced alone + - Rewrite accesses to `this.props` to `props` and accesses to `this.context` to `context` since the values will be passed as `constructor` arguments + - Remove _simple_ variable declarations like `var props = this.props;` and `var context = this.context` + - Rewrite top-level return statements (`return {...};`) to `this.state = {...}` + - Add `return;` after the assignment when the return statement is part of a control flow statement (not a direct child of `getInitialState()`'s body) and not in an inner function declaration + 4. Transform all non-lifecycle methods and fields to class property initializers (like `onClick = () => {};`). All your Flow annotations will be preserved + - It's actually not necessary to transform all methods to arrow functions (i.e., to bind them), but this behavior is the same as `createClass()` and we can make sure that we won't accidentally break stuff + 5. Rewrite `AnotherClass.getDefaultProps()` to `AnotherClass.defaultProps` +4. Generate Flow annotations from `propTypes` and put it on the class (this only happens when there's `/* @flow */` in your code and `options['flow']` is `true`) + - Flow actually understands `propTypes` in `createClass` calls but not ES6 class components. Here the transformation logic is identical to [how](https://github.com/facebook/flow/blob/master/src/typing/statement.ml#L3526) Flow treats `propTypes` + - Notice that Flow treats an optional propType as non-nullable + - For example, `foo: React.PropTypes.number` is valid when you pass `{}`, `{foo: null}`, or `{foo: undefined}` as props at **runtime**. However, when Flow infers type from a `createClass` call, only `{}` and `{foo: undefined}` are valid; `{foo: null}` is not. Thus the equivalent type annotation in Flow is actually `{foo?: number}`. The question mark on the left hand side indicates `{}` and `{foo: undefined}` are fine, but when `foo` is present it must be a `number` + - For `propTypes` fields that can't be recognized by Flow, `$FlowFixMe` will be used + +#### Usage +```bash +./node_modules/.bin/jscodeshift -t ./transforms/class.js --mixin-module-name=react-addons-pure-render-mixin --flow=true --pure-component=true --remove-runtime-proptypes=false +``` ### Recast Options diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json new file mode 100644 index 00000000..d1bd92af --- /dev/null +++ b/npm-shrinkwrap.json @@ -0,0 +1,2980 @@ +{ + "name": "react-codemod", + "version": "4.0.0", + "dependencies": { + "abab": { + "version": "1.0.3", + "from": "abab@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.3.tgz" + }, + "abbrev": { + "version": "1.0.9", + "from": "abbrev@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz" + }, + "acorn": { + "version": "3.2.0", + "from": "acorn@>=3.2.0 <4.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.2.0.tgz" + }, + "acorn-globals": { + "version": "1.0.9", + "from": "acorn-globals@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", + "dependencies": { + "acorn": { + "version": "2.7.0", + "from": "acorn@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz" + } + } + }, + "acorn-jsx": { + "version": "3.0.1", + "from": "acorn-jsx@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz" + }, + "align-text": { + "version": "0.1.4", + "from": "align-text@>=0.1.3 <0.2.0", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz" + }, + "alter": { + "version": "0.2.0", + "from": "alter@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz" + }, + "amdefine": { + "version": "1.0.0", + "from": "amdefine@>=0.0.4", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" + }, + "ansi-escapes": { + "version": "1.4.0", + "from": "ansi-escapes@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz" + }, + "ansi-regex": { + "version": "2.0.0", + "from": "ansi-regex@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" + }, + "ansi-styles": { + "version": "2.2.1", + "from": "ansi-styles@>=2.2.1 <3.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz" + }, + "ansicolors": { + "version": "0.2.1", + "from": "ansicolors@>=0.2.1 <0.3.0", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz" + }, + "argparse": { + "version": "1.0.7", + "from": "argparse@>=1.0.7 <2.0.0", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.7.tgz" + }, + "arr-diff": { + "version": "2.0.0", + "from": "arr-diff@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz" + }, + "arr-flatten": { + "version": "1.0.1", + "from": "arr-flatten@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.1.tgz" + }, + "array-differ": { + "version": "1.0.0", + "from": "array-differ@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz" + }, + "array-equal": { + "version": "1.0.0", + "from": "array-equal@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz" + }, + "array-find-index": { + "version": "1.0.1", + "from": "array-find-index@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.1.tgz" + }, + "array-union": { + "version": "1.0.2", + "from": "array-union@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz" + }, + "array-uniq": { + "version": "1.0.3", + "from": "array-uniq@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz" + }, + "array-unique": { + "version": "0.2.1", + "from": "array-unique@>=0.2.1 <0.3.0", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz" + }, + "arrify": { + "version": "1.0.1", + "from": "arrify@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz" + }, + "asn1": { + "version": "0.2.3", + "from": "asn1@>=0.2.3 <0.3.0", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz" + }, + "assert-plus": { + "version": "0.2.0", + "from": "assert-plus@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz" + }, + "ast-traverse": { + "version": "0.1.1", + "from": "ast-traverse@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz" + }, + "ast-types": { + "version": "0.8.12", + "from": "ast-types@0.8.12", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz" + }, + "async": { + "version": "1.5.2", + "from": "async@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz" + }, + "aws-sign2": { + "version": "0.6.0", + "from": "aws-sign2@>=0.6.0 <0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz" + }, + "aws4": { + "version": "1.4.1", + "from": "aws4@>=1.2.1 <2.0.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.4.1.tgz" + }, + "babel-code-frame": { + "version": "6.11.0", + "from": "babel-code-frame@>=6.8.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.11.0.tgz" + }, + "babel-core": { + "version": "6.10.4", + "from": "babel-core@>=6.0.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.10.4.tgz" + }, + "babel-eslint": { + "version": "6.1.0", + "from": "babel-eslint@>=6.0.5 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-6.1.0.tgz" + }, + "babel-generator": { + "version": "6.11.0", + "from": "babel-generator@>=6.9.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.11.0.tgz" + }, + "babel-helper-call-delegate": { + "version": "6.8.0", + "from": "babel-helper-call-delegate@>=6.8.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.8.0.tgz" + }, + "babel-helper-define-map": { + "version": "6.9.0", + "from": "babel-helper-define-map@>=6.9.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.9.0.tgz" + }, + "babel-helper-function-name": { + "version": "6.8.0", + "from": "babel-helper-function-name@>=6.8.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.8.0.tgz" + }, + "babel-helper-get-function-arity": { + "version": "6.8.0", + "from": "babel-helper-get-function-arity@>=6.8.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.8.0.tgz" + }, + "babel-helper-hoist-variables": { + "version": "6.8.0", + "from": "babel-helper-hoist-variables@>=6.8.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.8.0.tgz" + }, + "babel-helper-optimise-call-expression": { + "version": "6.8.0", + "from": "babel-helper-optimise-call-expression@>=6.8.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.8.0.tgz" + }, + "babel-helper-regex": { + "version": "6.9.0", + "from": "babel-helper-regex@>=6.8.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.9.0.tgz" + }, + "babel-helper-replace-supers": { + "version": "6.8.0", + "from": "babel-helper-replace-supers@>=6.8.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.8.0.tgz" + }, + "babel-helpers": { + "version": "6.8.0", + "from": "babel-helpers@>=6.8.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.8.0.tgz" + }, + "babel-jest": { + "version": "13.2.2", + "from": "babel-jest@>=13.0.0 <14.0.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-13.2.2.tgz" + }, + "babel-messages": { + "version": "6.8.0", + "from": "babel-messages@>=6.8.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.8.0.tgz" + }, + "babel-plugin-check-es2015-constants": { + "version": "6.8.0", + "from": "babel-plugin-check-es2015-constants@>=6.3.13 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.8.0.tgz" + }, + "babel-plugin-constant-folding": { + "version": "1.0.1", + "from": "babel-plugin-constant-folding@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz" + }, + "babel-plugin-dead-code-elimination": { + "version": "1.0.2", + "from": "babel-plugin-dead-code-elimination@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz" + }, + "babel-plugin-eval": { + "version": "1.0.1", + "from": "babel-plugin-eval@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz" + }, + "babel-plugin-inline-environment-variables": { + "version": "1.0.1", + "from": "babel-plugin-inline-environment-variables@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz" + }, + "babel-plugin-jest-hoist": { + "version": "13.2.2", + "from": "babel-plugin-jest-hoist@>=13.2.2 <14.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-13.2.2.tgz" + }, + "babel-plugin-jscript": { + "version": "1.0.4", + "from": "babel-plugin-jscript@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz" + }, + "babel-plugin-member-expression-literals": { + "version": "1.0.1", + "from": "babel-plugin-member-expression-literals@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz" + }, + "babel-plugin-property-literals": { + "version": "1.0.1", + "from": "babel-plugin-property-literals@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz" + }, + "babel-plugin-proto-to-assign": { + "version": "1.0.4", + "from": "babel-plugin-proto-to-assign@>=1.0.3 <2.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz", + "dependencies": { + "lodash": { + "version": "3.10.1", + "from": "lodash@>=3.9.3 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" + } + } + }, + "babel-plugin-react-constant-elements": { + "version": "1.0.3", + "from": "babel-plugin-react-constant-elements@>=1.0.3 <2.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz" + }, + "babel-plugin-react-display-name": { + "version": "1.0.3", + "from": "babel-plugin-react-display-name@>=1.0.3 <2.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz" + }, + "babel-plugin-remove-console": { + "version": "1.0.1", + "from": "babel-plugin-remove-console@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz" + }, + "babel-plugin-remove-debugger": { + "version": "1.0.1", + "from": "babel-plugin-remove-debugger@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz" + }, + "babel-plugin-runtime": { + "version": "1.0.7", + "from": "babel-plugin-runtime@>=1.0.7 <2.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz" + }, + "babel-plugin-syntax-async-functions": { + "version": "6.8.0", + "from": "babel-plugin-syntax-async-functions@>=6.8.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.8.0.tgz" + }, + "babel-plugin-syntax-class-properties": { + "version": "6.8.0", + "from": "babel-plugin-syntax-class-properties@>=6.8.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.8.0.tgz" + }, + "babel-plugin-syntax-flow": { + "version": "6.8.0", + "from": "babel-plugin-syntax-flow@>=6.5.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.8.0.tgz" + }, + "babel-plugin-syntax-object-rest-spread": { + "version": "6.8.0", + "from": "babel-plugin-syntax-object-rest-spread@>=6.8.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.8.0.tgz" + }, + "babel-plugin-syntax-trailing-function-commas": { + "version": "6.8.0", + "from": "babel-plugin-syntax-trailing-function-commas@>=6.5.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.8.0.tgz" + }, + "babel-plugin-transform-class-properties": { + "version": "6.10.2", + "from": "babel-plugin-transform-class-properties@>=6.6.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.10.2.tgz" + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.8.0", + "from": "babel-plugin-transform-es2015-arrow-functions@>=6.3.13 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.8.0.tgz" + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.8.0", + "from": "babel-plugin-transform-es2015-block-scoped-functions@>=6.3.13 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.8.0.tgz" + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.10.1", + "from": "babel-plugin-transform-es2015-block-scoping@>=6.9.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.10.1.tgz" + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.9.0", + "from": "babel-plugin-transform-es2015-classes@>=6.9.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.9.0.tgz" + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.8.0", + "from": "babel-plugin-transform-es2015-computed-properties@>=6.3.13 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.8.0.tgz" + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.9.0", + "from": "babel-plugin-transform-es2015-destructuring@>=6.9.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.9.0.tgz" + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.8.0", + "from": "babel-plugin-transform-es2015-duplicate-keys@>=6.6.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.8.0.tgz" + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.8.0", + "from": "babel-plugin-transform-es2015-for-of@>=6.6.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.8.0.tgz" + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.9.0", + "from": "babel-plugin-transform-es2015-function-name@>=6.9.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.9.0.tgz" + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.8.0", + "from": "babel-plugin-transform-es2015-literals@>=6.3.13 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.8.0.tgz" + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.10.3", + "from": "babel-plugin-transform-es2015-modules-commonjs@>=6.6.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.10.3.tgz" + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.8.0", + "from": "babel-plugin-transform-es2015-object-super@>=6.3.13 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.8.0.tgz" + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.9.0", + "from": "babel-plugin-transform-es2015-parameters@>=6.9.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.9.0.tgz" + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.8.0", + "from": "babel-plugin-transform-es2015-shorthand-properties@>=6.3.13 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.8.0.tgz" + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.8.0", + "from": "babel-plugin-transform-es2015-spread@>=6.3.13 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.8.0.tgz" + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.8.0", + "from": "babel-plugin-transform-es2015-sticky-regex@>=6.3.13 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.8.0.tgz" + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.8.0", + "from": "babel-plugin-transform-es2015-template-literals@>=6.6.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.8.0.tgz" + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.8.0", + "from": "babel-plugin-transform-es2015-typeof-symbol@>=6.6.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.8.0.tgz" + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.11.0", + "from": "babel-plugin-transform-es2015-unicode-regex@>=6.3.13 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.11.0.tgz" + }, + "babel-plugin-transform-es3-member-expression-literals": { + "version": "6.8.0", + "from": "babel-plugin-transform-es3-member-expression-literals@>=6.5.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es3-member-expression-literals/-/babel-plugin-transform-es3-member-expression-literals-6.8.0.tgz" + }, + "babel-plugin-transform-es3-property-literals": { + "version": "6.8.0", + "from": "babel-plugin-transform-es3-property-literals@>=6.5.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es3-property-literals/-/babel-plugin-transform-es3-property-literals-6.8.0.tgz" + }, + "babel-plugin-transform-flow-strip-types": { + "version": "6.8.0", + "from": "babel-plugin-transform-flow-strip-types@>=6.7.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.8.0.tgz" + }, + "babel-plugin-transform-object-rest-spread": { + "version": "6.8.0", + "from": "babel-plugin-transform-object-rest-spread@>=6.6.5 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.8.0.tgz" + }, + "babel-plugin-transform-regenerator": { + "version": "6.9.0", + "from": "babel-plugin-transform-regenerator@>=6.9.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.9.0.tgz" + }, + "babel-plugin-transform-strict-mode": { + "version": "6.8.0", + "from": "babel-plugin-transform-strict-mode@>=6.8.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.8.0.tgz" + }, + "babel-plugin-undeclared-variables-check": { + "version": "1.0.2", + "from": "babel-plugin-undeclared-variables-check@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz" + }, + "babel-plugin-undefined-to-void": { + "version": "1.1.6", + "from": "babel-plugin-undefined-to-void@>=1.1.6 <2.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz" + }, + "babel-preset-es2015": { + "version": "6.9.0", + "from": "babel-preset-es2015@>=6.6.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.9.0.tgz" + }, + "babel-preset-fbjs": { + "version": "1.0.0", + "from": "babel-preset-fbjs@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-1.0.0.tgz" + }, + "babel-preset-jest": { + "version": "13.2.2", + "from": "babel-preset-jest@>=13.2.2 <14.0.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-13.2.2.tgz" + }, + "babel-register": { + "version": "6.9.0", + "from": "babel-register@>=6.9.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.9.0.tgz" + }, + "babel-runtime": { + "version": "6.9.2", + "from": "babel-runtime@>=6.9.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.9.2.tgz" + }, + "babel-template": { + "version": "6.9.0", + "from": "babel-template@>=6.9.0 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.9.0.tgz" + }, + "babel-traverse": { + "version": "6.10.4", + "from": "babel-traverse@>=6.0.20 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.10.4.tgz" + }, + "babel-types": { + "version": "6.11.1", + "from": "babel-types@>=6.0.19 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.11.1.tgz" + }, + "babylon": { + "version": "6.8.4", + "from": "babylon@>=6.0.18 <7.0.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.8.4.tgz" + }, + "balanced-match": { + "version": "0.4.1", + "from": "balanced-match@>=0.4.1 <0.5.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz" + }, + "beeper": { + "version": "1.1.0", + "from": "beeper@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.0.tgz" + }, + "bl": { + "version": "1.1.2", + "from": "bl@>=1.1.2 <1.2.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz" + }, + "bluebird": { + "version": "3.4.1", + "from": "bluebird@>=3.1.1 <4.0.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.1.tgz" + }, + "boom": { + "version": "2.10.1", + "from": "boom@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz" + }, + "brace-expansion": { + "version": "1.1.5", + "from": "brace-expansion@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz" + }, + "braces": { + "version": "1.8.5", + "from": "braces@>=1.8.2 <2.0.0", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz" + }, + "breakable": { + "version": "1.0.0", + "from": "breakable@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz" + }, + "browser-resolve": { + "version": "1.11.2", + "from": "browser-resolve@>=1.11.2 <2.0.0", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz" + }, + "bser": { + "version": "1.0.2", + "from": "bser@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz" + }, + "builtin-modules": { + "version": "1.1.1", + "from": "builtin-modules@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz" + }, + "caller-path": { + "version": "0.1.0", + "from": "caller-path@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz" + }, + "callsites": { + "version": "0.2.0", + "from": "callsites@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz" + }, + "camelcase": { + "version": "2.1.1", + "from": "camelcase@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz" + }, + "camelcase-keys": { + "version": "2.1.0", + "from": "camelcase-keys@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz" + }, + "cardinal": { + "version": "0.5.0", + "from": "cardinal@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-0.5.0.tgz" + }, + "caseless": { + "version": "0.11.0", + "from": "caseless@>=0.11.0 <0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz" + }, + "center-align": { + "version": "0.1.3", + "from": "center-align@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz" + }, + "chalk": { + "version": "1.1.3", + "from": "chalk@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz" + }, + "cli-cursor": { + "version": "1.0.2", + "from": "cli-cursor@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz" + }, + "cli-table": { + "version": "0.3.1", + "from": "cli-table@>=0.3.1 <0.4.0", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz" + }, + "cli-usage": { + "version": "0.1.2", + "from": "cli-usage@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/cli-usage/-/cli-usage-0.1.2.tgz", + "dependencies": { + "minimist": { + "version": "0.2.0", + "from": "minimist@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.2.0.tgz" + } + } + }, + "cli-width": { + "version": "2.1.0", + "from": "cli-width@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz" + }, + "cliui": { + "version": "2.1.0", + "from": "cliui@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "from": "wordwrap@0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz" + } + } + }, + "clone": { + "version": "1.0.2", + "from": "clone@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz" + }, + "clone-stats": { + "version": "0.0.1", + "from": "clone-stats@>=0.0.1 <0.0.2", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz" + }, + "code-point-at": { + "version": "1.0.0", + "from": "code-point-at@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.0.0.tgz" + }, + "colors": { + "version": "1.0.3", + "from": "colors@1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz" + }, + "combined-stream": { + "version": "1.0.5", + "from": "combined-stream@>=1.0.5 <1.1.0", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz" + }, + "commander": { + "version": "2.9.0", + "from": "commander@>=2.9.0 <3.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz" + }, + "commoner": { + "version": "0.10.4", + "from": "commoner@>=0.10.3 <0.11.0", + "resolved": "https://registry.npmjs.org/commoner/-/commoner-0.10.4.tgz", + "dependencies": { + "glob": { + "version": "5.0.15", + "from": "glob@>=5.0.15 <6.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz" + } + } + }, + "concat-map": { + "version": "0.0.1", + "from": "concat-map@0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + }, + "concat-stream": { + "version": "1.5.1", + "from": "concat-stream@>=1.4.6 <2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.1.tgz" + }, + "convert-source-map": { + "version": "1.2.0", + "from": "convert-source-map@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.2.0.tgz" + }, + "core-js": { + "version": "2.4.0", + "from": "core-js@>=2.4.0 <3.0.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.0.tgz" + }, + "core-util-is": { + "version": "1.0.2", + "from": "core-util-is@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" + }, + "cross-spawn": { + "version": "3.0.1", + "from": "cross-spawn@>=3.0.1 <4.0.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz" + }, + "cryptiles": { + "version": "2.0.5", + "from": "cryptiles@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz" + }, + "cssom": { + "version": "0.3.1", + "from": "cssom@>=0.3.0 <0.4.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.1.tgz" + }, + "cssstyle": { + "version": "0.2.36", + "from": "cssstyle@>=0.2.36 <0.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.36.tgz" + }, + "currently-unhandled": { + "version": "0.4.1", + "from": "currently-unhandled@>=0.4.1 <0.5.0", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz" + }, + "d": { + "version": "0.1.1", + "from": "d@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz" + }, + "dashdash": { + "version": "1.14.0", + "from": "dashdash@>=1.12.0 <2.0.0", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.0.tgz", + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "from": "assert-plus@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" + } + } + }, + "dateformat": { + "version": "1.0.12", + "from": "dateformat@>=1.0.11 <2.0.0", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz" + }, + "debug": { + "version": "2.2.0", + "from": "debug@>=2.2.0 <3.0.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz" + }, + "decamelize": { + "version": "1.2.0", + "from": "decamelize@>=1.1.2 <2.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" + }, + "deep-is": { + "version": "0.1.3", + "from": "deep-is@>=0.1.3 <0.2.0", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz" + }, + "defined": { + "version": "1.0.0", + "from": "defined@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz" + }, + "defs": { + "version": "1.1.1", + "from": "defs@>=1.1.0 <1.2.0", + "resolved": "https://registry.npmjs.org/defs/-/defs-1.1.1.tgz", + "dependencies": { + "camelcase": { + "version": "1.2.1", + "from": "camelcase@>=1.2.1 <2.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz" + }, + "esprima-fb": { + "version": "15001.1001.0-dev-harmony-fb", + "from": "esprima-fb@>=15001.1001.0-dev-harmony-fb <15001.1002.0", + "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz" + }, + "window-size": { + "version": "0.1.4", + "from": "window-size@>=0.1.2 <0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz" + }, + "yargs": { + "version": "3.27.0", + "from": "yargs@>=3.27.0 <3.28.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.27.0.tgz" + } + } + }, + "del": { + "version": "2.2.1", + "from": "del@>=2.0.2 <3.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.1.tgz" + }, + "delayed-stream": { + "version": "1.0.0", + "from": "delayed-stream@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + }, + "detect-indent": { + "version": "3.0.1", + "from": "detect-indent@>=3.0.1 <4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz" + }, + "detective": { + "version": "4.3.1", + "from": "detective@>=4.3.1 <5.0.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-4.3.1.tgz", + "dependencies": { + "acorn": { + "version": "1.2.2", + "from": "acorn@>=1.0.3 <2.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz" + } + } + }, + "diff": { + "version": "2.2.3", + "from": "diff@>=2.1.1 <3.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-2.2.3.tgz" + }, + "doctrine": { + "version": "1.2.2", + "from": "doctrine@>=1.2.2 <2.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.2.2.tgz", + "dependencies": { + "esutils": { + "version": "1.1.6", + "from": "esutils@>=1.1.6 <2.0.0", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz" + } + } + }, + "duplexer2": { + "version": "0.0.2", + "from": "duplexer2@0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "dependencies": { + "isarray": { + "version": "0.0.1", + "from": "isarray@0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" + }, + "readable-stream": { + "version": "1.1.14", + "from": "readable-stream@>=1.1.9 <1.2.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz" + } + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "from": "ecc-jsbn@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz" + }, + "errno": { + "version": "0.1.4", + "from": "errno@>=0.1.1 <0.2.0-0", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz" + }, + "error-ex": { + "version": "1.3.0", + "from": "error-ex@>=1.2.0 <2.0.0", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.0.tgz" + }, + "es5-ext": { + "version": "0.10.12", + "from": "es5-ext@>=0.10.11 <0.11.0", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.12.tgz" + }, + "es6-iterator": { + "version": "2.0.0", + "from": "es6-iterator@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.0.tgz" + }, + "es6-map": { + "version": "0.1.4", + "from": "es6-map@>=0.1.3 <0.2.0", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.4.tgz" + }, + "es6-promise": { + "version": "3.2.1", + "from": "es6-promise@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz" + }, + "es6-set": { + "version": "0.1.4", + "from": "es6-set@>=0.1.3 <0.2.0", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.4.tgz" + }, + "es6-symbol": { + "version": "3.1.0", + "from": "es6-symbol@>=3.1.0 <3.2.0", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.0.tgz" + }, + "es6-weak-map": { + "version": "2.0.1", + "from": "es6-weak-map@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.1.tgz" + }, + "escape-string-regexp": { + "version": "1.0.5", + "from": "escape-string-regexp@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + }, + "escodegen": { + "version": "1.8.0", + "from": "escodegen@>=1.8.0 <1.9.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.0.tgz", + "dependencies": { + "estraverse": { + "version": "1.9.3", + "from": "estraverse@>=1.9.1 <2.0.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz" + }, + "source-map": { + "version": "0.2.0", + "from": "source-map@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz" + } + } + }, + "escope": { + "version": "3.6.0", + "from": "escope@>=3.6.0 <4.0.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz" + }, + "eslint": { + "version": "2.13.1", + "from": "eslint@>=2.13.1 <3.0.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-2.13.1.tgz", + "dependencies": { + "globals": { + "version": "9.9.0", + "from": "globals@>=9.2.0 <10.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.9.0.tgz" + }, + "user-home": { + "version": "2.0.0", + "from": "user-home@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz" + } + } + }, + "eslint-plugin-react": { + "version": "5.2.2", + "from": "eslint-plugin-react@>=5.2.2 <6.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-5.2.2.tgz" + }, + "espree": { + "version": "3.1.6", + "from": "espree@>=3.1.6 <4.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.1.6.tgz" + }, + "esprima": { + "version": "2.7.2", + "from": "esprima@>=2.6.0 <3.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz" + }, + "esrecurse": { + "version": "4.1.0", + "from": "esrecurse@>=4.1.0 <5.0.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.1.0.tgz", + "dependencies": { + "estraverse": { + "version": "4.1.1", + "from": "estraverse@>=4.1.0 <4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz" + } + } + }, + "estraverse": { + "version": "4.2.0", + "from": "estraverse@>=4.2.0 <5.0.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz" + }, + "esutils": { + "version": "2.0.2", + "from": "esutils@>=2.0.2 <3.0.0", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz" + }, + "event-emitter": { + "version": "0.3.4", + "from": "event-emitter@>=0.3.4 <0.4.0", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.4.tgz" + }, + "exec-sh": { + "version": "0.2.0", + "from": "exec-sh@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz" + }, + "exit-hook": { + "version": "1.1.1", + "from": "exit-hook@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz" + }, + "expand-brackets": { + "version": "0.1.5", + "from": "expand-brackets@>=0.1.4 <0.2.0", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz" + }, + "expand-range": { + "version": "1.8.2", + "from": "expand-range@>=1.8.1 <2.0.0", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz" + }, + "extend": { + "version": "3.0.0", + "from": "extend@>=3.0.0 <3.1.0", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz" + }, + "extglob": { + "version": "0.3.2", + "from": "extglob@>=0.3.1 <0.4.0", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz" + }, + "extsprintf": { + "version": "1.0.2", + "from": "extsprintf@1.0.2", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz" + }, + "fancy-log": { + "version": "1.2.0", + "from": "fancy-log@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.2.0.tgz" + }, + "fast-levenshtein": { + "version": "1.1.3", + "from": "fast-levenshtein@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.3.tgz" + }, + "fb-watchman": { + "version": "1.9.0", + "from": "fb-watchman@>=1.9.0 <2.0.0", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.0.tgz" + }, + "fbjs-scripts": { + "version": "0.7.1", + "from": "fbjs-scripts@>=0.7.1 <0.8.0", + "resolved": "https://registry.npmjs.org/fbjs-scripts/-/fbjs-scripts-0.7.1.tgz", + "dependencies": { + "core-js": { + "version": "1.2.6", + "from": "core-js@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.6.tgz" + } + } + }, + "figures": { + "version": "1.7.0", + "from": "figures@>=1.3.5 <2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz" + }, + "file-entry-cache": { + "version": "1.2.4", + "from": "file-entry-cache@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-1.2.4.tgz" + }, + "filename-regex": { + "version": "2.0.0", + "from": "filename-regex@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz" + }, + "fileset": { + "version": "0.2.1", + "from": "fileset@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz", + "dependencies": { + "glob": { + "version": "5.0.15", + "from": "glob@>=5.0.0 <6.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz" + }, + "minimatch": { + "version": "2.0.10", + "from": "minimatch@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz" + } + } + }, + "fill-range": { + "version": "2.2.3", + "from": "fill-range@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz" + }, + "find-up": { + "version": "1.1.2", + "from": "find-up@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "dependencies": { + "path-exists": { + "version": "2.1.0", + "from": "path-exists@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz" + } + } + }, + "flat-cache": { + "version": "1.0.10", + "from": "flat-cache@>=1.0.9 <2.0.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.0.10.tgz" + }, + "flow-parser": { + "version": "0.26.0", + "from": "flow-parser@>=0.0.0 <1.0.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.26.0.tgz", + "dependencies": { + "ast-types": { + "version": "0.8.16", + "from": "ast-types@0.8.16", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.16.tgz" + } + } + }, + "for-in": { + "version": "0.1.5", + "from": "for-in@>=0.1.5 <0.2.0", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.5.tgz" + }, + "for-own": { + "version": "0.1.4", + "from": "for-own@>=0.1.3 <0.2.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.4.tgz" + }, + "forever-agent": { + "version": "0.6.1", + "from": "forever-agent@>=0.6.1 <0.7.0", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" + }, + "form-data": { + "version": "1.0.0-rc4", + "from": "form-data@>=1.0.0-rc3 <1.1.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc4.tgz" + }, + "fs-readdir-recursive": { + "version": "0.1.2", + "from": "fs-readdir-recursive@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz" + }, + "fs.realpath": { + "version": "1.0.0", + "from": "fs.realpath@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + }, + "generate-function": { + "version": "2.0.0", + "from": "generate-function@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz" + }, + "generate-object-property": { + "version": "1.2.0", + "from": "generate-object-property@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz" + }, + "get-stdin": { + "version": "4.0.1", + "from": "get-stdin@>=4.0.1 <5.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz" + }, + "getpass": { + "version": "0.1.6", + "from": "getpass@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz", + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "from": "assert-plus@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" + } + } + }, + "glob": { + "version": "7.0.5", + "from": "glob@>=7.0.3 <8.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.5.tgz" + }, + "glob-base": { + "version": "0.3.0", + "from": "glob-base@>=0.3.0 <0.4.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz" + }, + "glob-parent": { + "version": "2.0.0", + "from": "glob-parent@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz" + }, + "globals": { + "version": "8.18.0", + "from": "globals@>=8.3.0 <9.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz" + }, + "globby": { + "version": "5.0.0", + "from": "globby@>=5.0.0 <6.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz" + }, + "glogg": { + "version": "1.0.0", + "from": "glogg@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz" + }, + "graceful-fs": { + "version": "4.1.4", + "from": "graceful-fs@>=4.1.2 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz" + }, + "graceful-readlink": { + "version": "1.0.1", + "from": "graceful-readlink@>=1.0.0", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" + }, + "growly": { + "version": "1.3.0", + "from": "growly@>=1.2.0 <2.0.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz" + }, + "gulp-util": { + "version": "3.0.7", + "from": "gulp-util@>=3.0.4 <4.0.0", + "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.7.tgz", + "dependencies": { + "object-assign": { + "version": "3.0.0", + "from": "object-assign@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz" + } + } + }, + "gulplog": { + "version": "1.0.0", + "from": "gulplog@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz" + }, + "handlebars": { + "version": "4.0.5", + "from": "handlebars@>=4.0.1 <5.0.0", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.5.tgz", + "dependencies": { + "source-map": { + "version": "0.4.4", + "from": "source-map@>=0.4.4 <0.5.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz" + } + } + }, + "har-validator": { + "version": "2.0.6", + "from": "har-validator@>=2.0.6 <2.1.0", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz" + }, + "has-ansi": { + "version": "2.0.0", + "from": "has-ansi@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz" + }, + "has-color": { + "version": "0.1.7", + "from": "has-color@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz" + }, + "has-flag": { + "version": "1.0.0", + "from": "has-flag@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz" + }, + "has-gulplog": { + "version": "0.1.0", + "from": "has-gulplog@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz" + }, + "hawk": { + "version": "3.1.3", + "from": "hawk@>=3.1.3 <3.2.0", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz" + }, + "hoek": { + "version": "2.16.3", + "from": "hoek@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz" + }, + "home-or-tmp": { + "version": "1.0.0", + "from": "home-or-tmp@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz" + }, + "hosted-git-info": { + "version": "2.1.5", + "from": "hosted-git-info@>=2.1.4 <3.0.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz" + }, + "http-signature": { + "version": "1.1.1", + "from": "http-signature@>=1.1.0 <1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz" + }, + "iconv-lite": { + "version": "0.4.13", + "from": "iconv-lite@>=0.4.13 <0.5.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz" + }, + "ignore": { + "version": "3.1.3", + "from": "ignore@>=3.1.2 <4.0.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.1.3.tgz" + }, + "imurmurhash": { + "version": "0.1.4", + "from": "imurmurhash@>=0.1.4 <0.2.0", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + }, + "indent-string": { + "version": "2.1.0", + "from": "indent-string@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "dependencies": { + "repeating": { + "version": "2.0.1", + "from": "repeating@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz" + } + } + }, + "inflight": { + "version": "1.0.5", + "from": "inflight@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz" + }, + "inherits": { + "version": "2.0.1", + "from": "inherits@>=2.0.1 <2.1.0", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" + }, + "inquirer": { + "version": "0.12.0", + "from": "inquirer@>=0.12.0 <0.13.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz" + }, + "invariant": { + "version": "2.2.1", + "from": "invariant@>=2.2.0 <3.0.0", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.1.tgz" + }, + "invert-kv": { + "version": "1.0.0", + "from": "invert-kv@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz" + }, + "is-arrayish": { + "version": "0.2.1", + "from": "is-arrayish@>=0.2.1 <0.3.0", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + }, + "is-buffer": { + "version": "1.1.3", + "from": "is-buffer@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz" + }, + "is-builtin-module": { + "version": "1.0.0", + "from": "is-builtin-module@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz" + }, + "is-dotfile": { + "version": "1.0.2", + "from": "is-dotfile@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz" + }, + "is-equal-shallow": { + "version": "0.1.3", + "from": "is-equal-shallow@>=0.1.3 <0.2.0", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz" + }, + "is-extendable": { + "version": "0.1.1", + "from": "is-extendable@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz" + }, + "is-extglob": { + "version": "1.0.0", + "from": "is-extglob@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz" + }, + "is-finite": { + "version": "1.0.1", + "from": "is-finite@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.1.tgz" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "from": "is-fullwidth-code-point@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz" + }, + "is-glob": { + "version": "2.0.1", + "from": "is-glob@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz" + }, + "is-integer": { + "version": "1.0.6", + "from": "is-integer@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/is-integer/-/is-integer-1.0.6.tgz" + }, + "is-my-json-valid": { + "version": "2.13.1", + "from": "is-my-json-valid@>=2.10.0 <3.0.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.13.1.tgz" + }, + "is-number": { + "version": "2.1.0", + "from": "is-number@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz" + }, + "is-path-cwd": { + "version": "1.0.0", + "from": "is-path-cwd@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz" + }, + "is-path-in-cwd": { + "version": "1.0.0", + "from": "is-path-in-cwd@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz" + }, + "is-path-inside": { + "version": "1.0.0", + "from": "is-path-inside@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz" + }, + "is-posix-bracket": { + "version": "0.1.1", + "from": "is-posix-bracket@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz" + }, + "is-primitive": { + "version": "2.0.0", + "from": "is-primitive@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz" + }, + "is-property": { + "version": "1.0.2", + "from": "is-property@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz" + }, + "is-resolvable": { + "version": "1.0.0", + "from": "is-resolvable@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz" + }, + "is-typedarray": { + "version": "1.0.0", + "from": "is-typedarray@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" + }, + "is-utf8": { + "version": "0.2.1", + "from": "is-utf8@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz" + }, + "isarray": { + "version": "1.0.0", + "from": "isarray@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + }, + "isexe": { + "version": "1.1.2", + "from": "isexe@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz" + }, + "isobject": { + "version": "2.1.0", + "from": "isobject@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz" + }, + "isstream": { + "version": "0.1.2", + "from": "isstream@>=0.1.2 <0.2.0", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" + }, + "istanbul": { + "version": "0.4.4", + "from": "istanbul@>=0.4.2 <0.5.0", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.4.tgz", + "dependencies": { + "supports-color": { + "version": "3.1.2", + "from": "supports-color@>=3.1.0 <4.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz" + } + } + }, + "jasmine-check": { + "version": "0.1.5", + "from": "jasmine-check@>=0.1.4 <0.2.0", + "resolved": "https://registry.npmjs.org/jasmine-check/-/jasmine-check-0.1.5.tgz" + }, + "jest-changed-files": { + "version": "13.2.2", + "from": "jest-changed-files@>=13.2.2 <14.0.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-13.2.2.tgz" + }, + "jest-cli": { + "version": "13.2.3", + "from": "jest-cli@>=13.0.0 <14.0.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-13.2.3.tgz", + "dependencies": { + "lodash.escape": { + "version": "4.0.0", + "from": "lodash.escape@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.0.tgz" + }, + "lodash.template": { + "version": "4.2.5", + "from": "lodash.template@>=4.2.4 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.2.5.tgz" + }, + "lodash.templatesettings": { + "version": "4.0.1", + "from": "lodash.templatesettings@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.0.1.tgz" + } + } + }, + "jest-config": { + "version": "13.2.3", + "from": "jest-config@>=13.2.3 <14.0.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-13.2.3.tgz" + }, + "jest-environment-jsdom": { + "version": "13.2.2", + "from": "jest-environment-jsdom@>=13.2.2 <14.0.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-13.2.2.tgz" + }, + "jest-environment-node": { + "version": "13.2.2", + "from": "jest-environment-node@>=13.2.2 <14.0.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-13.2.2.tgz" + }, + "jest-haste-map": { + "version": "13.2.2", + "from": "jest-haste-map@>=13.2.2 <14.0.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-13.2.2.tgz" + }, + "jest-jasmine1": { + "version": "13.2.2", + "from": "jest-jasmine1@>=13.2.2 <14.0.0", + "resolved": "https://registry.npmjs.org/jest-jasmine1/-/jest-jasmine1-13.2.2.tgz" + }, + "jest-jasmine2": { + "version": "13.2.3", + "from": "jest-jasmine2@>=13.2.3 <14.0.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-13.2.3.tgz" + }, + "jest-mock": { + "version": "13.2.2", + "from": "jest-mock@>=13.2.2 <14.0.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-13.2.2.tgz" + }, + "jest-resolve": { + "version": "13.2.2", + "from": "jest-resolve@>=13.2.2 <14.0.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-13.2.2.tgz" + }, + "jest-runtime": { + "version": "13.2.3", + "from": "jest-runtime@>=13.2.3 <14.0.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-13.2.3.tgz" + }, + "jest-snapshot": { + "version": "13.2.3", + "from": "jest-snapshot@>=13.2.3 <14.0.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-13.2.3.tgz" + }, + "jest-util": { + "version": "13.2.2", + "from": "jest-util@>=13.2.2 <14.0.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-13.2.2.tgz" + }, + "jodid25519": { + "version": "1.0.2", + "from": "jodid25519@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz" + }, + "js-tokens": { + "version": "2.0.0", + "from": "js-tokens@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-2.0.0.tgz" + }, + "js-yaml": { + "version": "3.6.1", + "from": "js-yaml@>=3.5.1 <4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz" + }, + "jsbn": { + "version": "0.1.0", + "from": "jsbn@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz" + }, + "jscodeshift": { + "version": "0.3.25", + "from": "jscodeshift@0.3.25", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.3.25.tgz", + "dependencies": { + "ast-types": { + "version": "0.8.17", + "from": "git+https://github.com/keyanzhang/ast-types.git", + "resolved": "git+https://github.com/keyanzhang/ast-types.git#e2d344814be03c5f9934379d17af62a872e70570" + }, + "babel-core": { + "version": "5.8.38", + "from": "babel-core@>=5.0.0 <6.0.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.38.tgz", + "dependencies": { + "babylon": { + "version": "5.8.38", + "from": "babylon@>=5.8.38 <6.0.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz" + }, + "lodash": { + "version": "3.10.1", + "from": "lodash@>=3.10.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" + } + } + }, + "bluebird": { + "version": "2.10.2", + "from": "bluebird@>=2.9.33 <3.0.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.10.2.tgz" + }, + "colors": { + "version": "1.1.2", + "from": "colors@>=1.1.2 <2.0.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz" + }, + "core-js": { + "version": "1.2.6", + "from": "core-js@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.6.tgz" + }, + "globals": { + "version": "6.4.1", + "from": "globals@>=6.4.0 <7.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz" + }, + "js-tokens": { + "version": "1.0.1", + "from": "js-tokens@1.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz" + }, + "minimatch": { + "version": "2.0.10", + "from": "minimatch@>=2.0.3 <3.0.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz" + }, + "recast": { + "version": "0.11.10", + "from": "recast@https://github.com/keyanzhang/recast", + "resolved": "git+https://github.com/keyanzhang/recast.git#5a5fe8b470e37470744a51678c24ef03b4a8c96b" + } + } + }, + "jsdom": { + "version": "9.4.1", + "from": "jsdom@>=9.2.1 <10.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.4.1.tgz", + "dependencies": { + "acorn": { + "version": "2.7.0", + "from": "acorn@>=2.4.0 <3.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz" + } + } + }, + "jsesc": { + "version": "0.5.0", + "from": "jsesc@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz" + }, + "json-schema": { + "version": "0.2.2", + "from": "json-schema@0.2.2", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.2.tgz" + }, + "json-stable-stringify": { + "version": "1.0.1", + "from": "json-stable-stringify@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz" + }, + "json-stringify-safe": { + "version": "5.0.1", + "from": "json-stringify-safe@>=5.0.1 <5.1.0", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" + }, + "json5": { + "version": "0.4.0", + "from": "json5@>=0.4.0 <0.5.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz" + }, + "jsonify": { + "version": "0.0.0", + "from": "jsonify@>=0.0.0 <0.1.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz" + }, + "jsonpointer": { + "version": "2.0.0", + "from": "jsonpointer@2.0.0", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz" + }, + "jsprim": { + "version": "1.3.0", + "from": "jsprim@>=1.2.2 <2.0.0", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.3.0.tgz" + }, + "jsx-ast-utils": { + "version": "1.2.1", + "from": "jsx-ast-utils@>=1.2.1 <2.0.0", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.2.1.tgz" + }, + "kind-of": { + "version": "3.0.3", + "from": "kind-of@>=3.0.2 <4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.3.tgz" + }, + "lazy-cache": { + "version": "1.0.4", + "from": "lazy-cache@>=1.0.3 <2.0.0", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz" + }, + "lcid": { + "version": "1.0.0", + "from": "lcid@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz" + }, + "leven": { + "version": "1.0.2", + "from": "leven@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz" + }, + "levn": { + "version": "0.3.0", + "from": "levn@>=0.3.0 <0.4.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" + }, + "load-json-file": { + "version": "1.1.0", + "from": "load-json-file@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz" + }, + "lodash": { + "version": "4.13.1", + "from": "lodash@>=4.2.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.13.1.tgz" + }, + "lodash._arraycopy": { + "version": "3.0.0", + "from": "lodash._arraycopy@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz" + }, + "lodash._arrayeach": { + "version": "3.0.0", + "from": "lodash._arrayeach@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz" + }, + "lodash._baseassign": { + "version": "3.2.0", + "from": "lodash._baseassign@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "dependencies": { + "lodash.keys": { + "version": "3.1.2", + "from": "lodash.keys@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz" + } + } + }, + "lodash._baseclone": { + "version": "3.3.0", + "from": "lodash._baseclone@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz", + "dependencies": { + "lodash.keys": { + "version": "3.1.2", + "from": "lodash.keys@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz" + } + } + }, + "lodash._basecopy": { + "version": "3.0.1", + "from": "lodash._basecopy@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz" + }, + "lodash._basefor": { + "version": "3.0.3", + "from": "lodash._basefor@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz" + }, + "lodash._baseiteratee": { + "version": "4.7.0", + "from": "lodash._baseiteratee@>=4.7.0 <4.8.0", + "resolved": "https://registry.npmjs.org/lodash._baseiteratee/-/lodash._baseiteratee-4.7.0.tgz" + }, + "lodash._basetostring": { + "version": "4.12.0", + "from": "lodash._basetostring@>=4.12.0 <4.13.0", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-4.12.0.tgz" + }, + "lodash._basevalues": { + "version": "3.0.0", + "from": "lodash._basevalues@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz" + }, + "lodash._bindcallback": { + "version": "3.0.1", + "from": "lodash._bindcallback@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz" + }, + "lodash._createassigner": { + "version": "3.1.1", + "from": "lodash._createassigner@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz" + }, + "lodash._getnative": { + "version": "3.9.1", + "from": "lodash._getnative@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz" + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "from": "lodash._isiterateecall@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz" + }, + "lodash._reescape": { + "version": "3.0.0", + "from": "lodash._reescape@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz" + }, + "lodash._reevaluate": { + "version": "3.0.0", + "from": "lodash._reevaluate@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz" + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "from": "lodash._reinterpolate@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz" + }, + "lodash._root": { + "version": "3.0.1", + "from": "lodash._root@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz" + }, + "lodash._stringtopath": { + "version": "4.8.0", + "from": "lodash._stringtopath@>=4.8.0 <4.9.0", + "resolved": "https://registry.npmjs.org/lodash._stringtopath/-/lodash._stringtopath-4.8.0.tgz" + }, + "lodash.assign": { + "version": "4.0.9", + "from": "lodash.assign@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.0.9.tgz" + }, + "lodash.assigninwith": { + "version": "4.0.7", + "from": "lodash.assigninwith@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.assigninwith/-/lodash.assigninwith-4.0.7.tgz" + }, + "lodash.clonedeep": { + "version": "3.0.2", + "from": "lodash.clonedeep@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz" + }, + "lodash.escape": { + "version": "3.2.0", + "from": "lodash.escape@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz" + }, + "lodash.isarguments": { + "version": "3.0.8", + "from": "lodash.isarguments@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.8.tgz" + }, + "lodash.isarray": { + "version": "3.0.4", + "from": "lodash.isarray@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" + }, + "lodash.keys": { + "version": "4.0.7", + "from": "lodash.keys@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-4.0.7.tgz" + }, + "lodash.keysin": { + "version": "4.1.4", + "from": "lodash.keysin@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-4.1.4.tgz" + }, + "lodash.pickby": { + "version": "4.4.0", + "from": "lodash.pickby@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.4.0.tgz" + }, + "lodash.rest": { + "version": "4.0.3", + "from": "lodash.rest@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.rest/-/lodash.rest-4.0.3.tgz" + }, + "lodash.restparam": { + "version": "3.6.1", + "from": "lodash.restparam@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz" + }, + "lodash.template": { + "version": "3.6.2", + "from": "lodash.template@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "dependencies": { + "lodash._basetostring": { + "version": "3.0.1", + "from": "lodash._basetostring@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz" + }, + "lodash.keys": { + "version": "3.1.2", + "from": "lodash.keys@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz" + } + } + }, + "lodash.templatesettings": { + "version": "3.1.1", + "from": "lodash.templatesettings@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz" + }, + "lodash.tostring": { + "version": "4.1.3", + "from": "lodash.tostring@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.tostring/-/lodash.tostring-4.1.3.tgz" + }, + "longest": { + "version": "1.0.1", + "from": "longest@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz" + }, + "loose-envify": { + "version": "1.2.0", + "from": "loose-envify@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.2.0.tgz", + "dependencies": { + "js-tokens": { + "version": "1.0.3", + "from": "js-tokens@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.3.tgz" + } + } + }, + "loud-rejection": { + "version": "1.6.0", + "from": "loud-rejection@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz" + }, + "lru-cache": { + "version": "4.0.1", + "from": "lru-cache@>=4.0.1 <5.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.1.tgz" + }, + "makeerror": { + "version": "1.0.11", + "from": "makeerror@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz" + }, + "map-obj": { + "version": "1.0.1", + "from": "map-obj@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz" + }, + "marked": { + "version": "0.3.5", + "from": "marked@>=0.3.2 <0.4.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.5.tgz" + }, + "marked-terminal": { + "version": "1.6.1", + "from": "marked-terminal@>=1.6.1 <2.0.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-1.6.1.tgz", + "dependencies": { + "lodash.assign": { + "version": "3.2.0", + "from": "lodash.assign@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz" + }, + "lodash.keys": { + "version": "3.1.2", + "from": "lodash.keys@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz" + } + } + }, + "meow": { + "version": "3.7.0", + "from": "meow@>=3.3.0 <4.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz" + }, + "merge": { + "version": "1.2.0", + "from": "merge@>=1.1.3 <2.0.0", + "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz" + }, + "micromatch": { + "version": "2.3.10", + "from": "micromatch@>=2.3.7 <3.0.0", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.10.tgz" + }, + "mime-db": { + "version": "1.23.0", + "from": "mime-db@>=1.23.0 <1.24.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.23.0.tgz" + }, + "mime-types": { + "version": "2.1.11", + "from": "mime-types@>=2.1.7 <2.2.0", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.11.tgz" + }, + "minimatch": { + "version": "3.0.2", + "from": "minimatch@>=3.0.2 <4.0.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.2.tgz" + }, + "minimist": { + "version": "1.2.0", + "from": "minimist@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz" + }, + "mkdirp": { + "version": "0.5.1", + "from": "mkdirp@>=0.5.1 <0.6.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "dependencies": { + "minimist": { + "version": "0.0.8", + "from": "minimist@0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" + } + } + }, + "ms": { + "version": "0.7.1", + "from": "ms@0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" + }, + "multipipe": { + "version": "0.1.2", + "from": "multipipe@>=0.1.2 <0.2.0", + "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz" + }, + "mute-stream": { + "version": "0.0.5", + "from": "mute-stream@0.0.5", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz" + }, + "node-dir": { + "version": "0.1.8", + "from": "node-dir@0.1.8", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.8.tgz" + }, + "node-emoji": { + "version": "0.1.0", + "from": "node-emoji@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-0.1.0.tgz" + }, + "node-int64": { + "version": "0.4.0", + "from": "node-int64@>=0.4.0 <0.5.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" + }, + "node-notifier": { + "version": "4.6.0", + "from": "node-notifier@>=4.6.0 <5.0.0", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-4.6.0.tgz" + }, + "node-uuid": { + "version": "1.4.7", + "from": "node-uuid@>=1.4.7 <1.5.0", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz" + }, + "nomnom": { + "version": "1.8.1", + "from": "nomnom@>=1.8.1 <2.0.0", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", + "dependencies": { + "ansi-styles": { + "version": "1.0.0", + "from": "ansi-styles@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz" + }, + "chalk": { + "version": "0.4.0", + "from": "chalk@>=0.4.0 <0.5.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz" + }, + "strip-ansi": { + "version": "0.1.1", + "from": "strip-ansi@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz" + } + } + }, + "nopt": { + "version": "3.0.6", + "from": "nopt@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz" + }, + "normalize-package-data": { + "version": "2.3.5", + "from": "normalize-package-data@>=2.3.4 <3.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz" + }, + "normalize-path": { + "version": "2.0.1", + "from": "normalize-path@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.0.1.tgz" + }, + "number-is-nan": { + "version": "1.0.0", + "from": "number-is-nan@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz" + }, + "nwmatcher": { + "version": "1.3.8", + "from": "nwmatcher@>=1.3.7 <2.0.0", + "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.3.8.tgz" + }, + "oauth-sign": { + "version": "0.8.2", + "from": "oauth-sign@>=0.8.1 <0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz" + }, + "object-assign": { + "version": "4.1.0", + "from": "object-assign@>=4.0.1 <5.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz" + }, + "object.omit": { + "version": "2.0.0", + "from": "object.omit@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.0.tgz" + }, + "once": { + "version": "1.3.3", + "from": "once@>=1.3.0 <2.0.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz" + }, + "onetime": { + "version": "1.1.0", + "from": "onetime@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz" + }, + "optimist": { + "version": "0.6.1", + "from": "optimist@>=0.6.1 <0.7.0", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "dependencies": { + "minimist": { + "version": "0.0.10", + "from": "minimist@>=0.0.1 <0.1.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz" + }, + "wordwrap": { + "version": "0.0.3", + "from": "wordwrap@>=0.0.2 <0.1.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" + } + } + }, + "optionator": { + "version": "0.8.1", + "from": "optionator@>=0.8.1 <0.9.0", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.1.tgz" + }, + "os-homedir": { + "version": "1.0.1", + "from": "os-homedir@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz" + }, + "os-locale": { + "version": "1.4.0", + "from": "os-locale@>=1.4.0 <2.0.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz" + }, + "os-tmpdir": { + "version": "1.0.1", + "from": "os-tmpdir@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz" + }, + "output-file-sync": { + "version": "1.1.2", + "from": "output-file-sync@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz" + }, + "parse-glob": { + "version": "3.0.4", + "from": "parse-glob@>=3.0.4 <4.0.0", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz" + }, + "parse-json": { + "version": "2.2.0", + "from": "parse-json@>=2.2.0 <3.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz" + }, + "parse5": { + "version": "1.5.1", + "from": "parse5@>=1.5.1 <2.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz" + }, + "path-exists": { + "version": "1.0.0", + "from": "path-exists@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz" + }, + "path-is-absolute": { + "version": "1.0.0", + "from": "path-is-absolute@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" + }, + "path-is-inside": { + "version": "1.0.1", + "from": "path-is-inside@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.1.tgz" + }, + "path-type": { + "version": "1.1.0", + "from": "path-type@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz" + }, + "pify": { + "version": "2.3.0", + "from": "pify@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" + }, + "pinkie": { + "version": "2.0.4", + "from": "pinkie@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" + }, + "pinkie-promise": { + "version": "2.0.1", + "from": "pinkie-promise@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" + }, + "pkg-conf": { + "version": "1.1.3", + "from": "pkg-conf@>=1.1.2 <2.0.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-1.1.3.tgz" + }, + "pluralize": { + "version": "1.2.1", + "from": "pluralize@>=1.2.1 <2.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz" + }, + "prelude-ls": { + "version": "1.1.2", + "from": "prelude-ls@>=1.1.2 <1.2.0", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" + }, + "preserve": { + "version": "0.2.0", + "from": "preserve@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz" + }, + "pretty-format": { + "version": "3.4.3", + "from": "pretty-format@>=3.4.3 <4.0.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.4.3.tgz" + }, + "private": { + "version": "0.1.6", + "from": "private@>=0.1.6 <0.2.0", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.6.tgz" + }, + "process-nextick-args": { + "version": "1.0.7", + "from": "process-nextick-args@>=1.0.6 <1.1.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz" + }, + "progress": { + "version": "1.1.8", + "from": "progress@>=1.1.8 <2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz" + }, + "prr": { + "version": "0.0.0", + "from": "prr@>=0.0.0 <0.1.0", + "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz" + }, + "pseudomap": { + "version": "1.0.2", + "from": "pseudomap@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz" + }, + "q": { + "version": "1.4.1", + "from": "q@>=1.1.2 <2.0.0", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz" + }, + "qs": { + "version": "6.1.0", + "from": "qs@>=6.1.0 <6.2.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.1.0.tgz" + }, + "randomatic": { + "version": "1.1.5", + "from": "randomatic@>=1.1.3 <2.0.0", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.5.tgz" + }, + "read-json-sync": { + "version": "1.1.1", + "from": "read-json-sync@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/read-json-sync/-/read-json-sync-1.1.1.tgz" + }, + "read-pkg": { + "version": "1.1.0", + "from": "read-pkg@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz" + }, + "read-pkg-up": { + "version": "1.0.1", + "from": "read-pkg-up@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz" + }, + "readable-stream": { + "version": "2.0.6", + "from": "readable-stream@>=2.0.0 <2.1.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz" + }, + "readline2": { + "version": "1.0.1", + "from": "readline2@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz" + }, + "recast": { + "version": "0.10.33", + "from": "recast@0.10.33", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz", + "dependencies": { + "esprima-fb": { + "version": "15001.1001.0-dev-harmony-fb", + "from": "esprima-fb@>=15001.1001.0-dev-harmony-fb <15001.1002.0", + "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz" + } + } + }, + "redent": { + "version": "1.0.0", + "from": "redent@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz" + }, + "redeyed": { + "version": "0.5.0", + "from": "redeyed@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-0.5.0.tgz", + "dependencies": { + "esprima-fb": { + "version": "12001.1.0-dev-harmony-fb", + "from": "esprima-fb@>=12001.1.0-dev-harmony-fb <12001.2.0", + "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-12001.1.0-dev-harmony-fb.tgz" + } + } + }, + "regenerate": { + "version": "1.3.1", + "from": "regenerate@>=1.2.1 <2.0.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.1.tgz" + }, + "regenerator": { + "version": "0.8.40", + "from": "regenerator@0.8.40", + "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz", + "dependencies": { + "esprima-fb": { + "version": "15001.1001.0-dev-harmony-fb", + "from": "esprima-fb@>=15001.1001.0-dev-harmony-fb <15001.1002.0", + "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz" + } + } + }, + "regenerator-runtime": { + "version": "0.9.5", + "from": "regenerator-runtime@>=0.9.5 <0.10.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.9.5.tgz" + }, + "regex-cache": { + "version": "0.4.3", + "from": "regex-cache@>=0.4.2 <0.5.0", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz" + }, + "regexpu": { + "version": "1.3.0", + "from": "regexpu@>=1.3.0 <2.0.0", + "resolved": "https://registry.npmjs.org/regexpu/-/regexpu-1.3.0.tgz" + }, + "regexpu-core": { + "version": "2.0.0", + "from": "regexpu-core@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz" + }, + "regjsgen": { + "version": "0.2.0", + "from": "regjsgen@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz" + }, + "regjsparser": { + "version": "0.1.5", + "from": "regjsparser@>=0.1.4 <0.2.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz" + }, + "repeat-element": { + "version": "1.1.2", + "from": "repeat-element@>=1.1.2 <2.0.0", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz" + }, + "repeat-string": { + "version": "1.5.4", + "from": "repeat-string@>=1.5.2 <2.0.0", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz" + }, + "repeating": { + "version": "1.1.3", + "from": "repeating@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz" + }, + "replace-ext": { + "version": "0.0.1", + "from": "replace-ext@0.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz" + }, + "request": { + "version": "2.72.0", + "from": "request@>=2.55.0 <3.0.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.72.0.tgz" + }, + "require-main-filename": { + "version": "1.0.1", + "from": "require-main-filename@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz" + }, + "require-uncached": { + "version": "1.0.2", + "from": "require-uncached@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.2.tgz" + }, + "resolve": { + "version": "1.1.7", + "from": "resolve@>=1.1.0 <1.2.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz" + }, + "resolve-from": { + "version": "1.0.1", + "from": "resolve-from@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz" + }, + "restore-cursor": { + "version": "1.0.1", + "from": "restore-cursor@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz" + }, + "right-align": { + "version": "0.1.3", + "from": "right-align@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz" + }, + "rimraf": { + "version": "2.5.3", + "from": "rimraf@>=2.2.8 <3.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.3.tgz" + }, + "run-async": { + "version": "0.1.0", + "from": "run-async@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz" + }, + "rx-lite": { + "version": "3.1.2", + "from": "rx-lite@>=3.1.2 <4.0.0", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz" + }, + "sane": { + "version": "1.4.0", + "from": "sane@>=1.2.0 <2.0.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-1.4.0.tgz" + }, + "sax": { + "version": "1.2.1", + "from": "sax@>=1.1.4 <2.0.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz" + }, + "semver": { + "version": "5.2.0", + "from": "semver@>=5.1.0 <6.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.2.0.tgz" + }, + "set-blocking": { + "version": "1.0.0", + "from": "set-blocking@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-1.0.0.tgz" + }, + "shebang-regex": { + "version": "1.0.0", + "from": "shebang-regex@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz" + }, + "shelljs": { + "version": "0.6.0", + "from": "shelljs@>=0.6.0 <0.7.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.6.0.tgz" + }, + "shellwords": { + "version": "0.1.0", + "from": "shellwords@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.0.tgz" + }, + "signal-exit": { + "version": "3.0.0", + "from": "signal-exit@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.0.tgz" + }, + "simple-fmt": { + "version": "0.1.0", + "from": "simple-fmt@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz" + }, + "simple-is": { + "version": "0.2.0", + "from": "simple-is@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz" + }, + "slash": { + "version": "1.0.0", + "from": "slash@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz" + }, + "slice-ansi": { + "version": "0.0.4", + "from": "slice-ansi@0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz" + }, + "sntp": { + "version": "1.0.9", + "from": "sntp@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz" + }, + "source-map": { + "version": "0.5.6", + "from": "source-map@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz" + }, + "source-map-support": { + "version": "0.2.10", + "from": "source-map-support@>=0.2.10 <0.3.0", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz", + "dependencies": { + "source-map": { + "version": "0.1.32", + "from": "source-map@0.1.32", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz" + } + } + }, + "sparkles": { + "version": "1.0.0", + "from": "sparkles@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz" + }, + "spdx-correct": { + "version": "1.0.2", + "from": "spdx-correct@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz" + }, + "spdx-exceptions": { + "version": "1.0.4", + "from": "spdx-exceptions@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-1.0.4.tgz" + }, + "spdx-expression-parse": { + "version": "1.0.2", + "from": "spdx-expression-parse@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.2.tgz" + }, + "spdx-license-ids": { + "version": "1.2.1", + "from": "spdx-license-ids@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.1.tgz" + }, + "sprintf-js": { + "version": "1.0.3", + "from": "sprintf-js@>=1.0.2 <1.1.0", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + }, + "sshpk": { + "version": "1.8.3", + "from": "sshpk@>=1.7.0 <2.0.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.8.3.tgz", + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "from": "assert-plus@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" + } + } + }, + "stable": { + "version": "0.1.5", + "from": "stable@>=0.1.3 <0.2.0", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.5.tgz" + }, + "string_decoder": { + "version": "0.10.31", + "from": "string_decoder@>=0.10.0 <0.11.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" + }, + "string-width": { + "version": "1.0.1", + "from": "string-width@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.1.tgz" + }, + "stringmap": { + "version": "0.2.2", + "from": "stringmap@>=0.2.2 <0.3.0", + "resolved": "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz" + }, + "stringset": { + "version": "0.2.1", + "from": "stringset@>=0.2.1 <0.3.0", + "resolved": "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz" + }, + "stringstream": { + "version": "0.0.5", + "from": "stringstream@>=0.0.4 <0.1.0", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz" + }, + "strip-ansi": { + "version": "3.0.1", + "from": "strip-ansi@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" + }, + "strip-bom": { + "version": "2.0.0", + "from": "strip-bom@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz" + }, + "strip-indent": { + "version": "1.0.1", + "from": "strip-indent@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz" + }, + "strip-json-comments": { + "version": "1.0.4", + "from": "strip-json-comments@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz" + }, + "supports-color": { + "version": "2.0.0", + "from": "supports-color@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" + }, + "symbol": { + "version": "0.2.3", + "from": "symbol@>=0.2.1 <0.3.0", + "resolved": "https://registry.npmjs.org/symbol/-/symbol-0.2.3.tgz" + }, + "symbol-tree": { + "version": "3.1.4", + "from": "symbol-tree@>=3.1.0 <4.0.0", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.1.4.tgz" + }, + "table": { + "version": "3.7.8", + "from": "table@>=3.7.8 <4.0.0", + "resolved": "https://registry.npmjs.org/table/-/table-3.7.8.tgz" + }, + "temp": { + "version": "0.8.3", + "from": "temp@>=0.8.1 <0.9.0", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", + "dependencies": { + "rimraf": { + "version": "2.2.8", + "from": "rimraf@>=2.2.6 <2.3.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz" + } + } + }, + "testcheck": { + "version": "0.1.4", + "from": "testcheck@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/testcheck/-/testcheck-0.1.4.tgz" + }, + "text-table": { + "version": "0.2.0", + "from": "text-table@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + }, + "through": { + "version": "2.3.8", + "from": "through@>=2.3.6 <3.0.0", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + }, + "through2": { + "version": "2.0.1", + "from": "through2@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.1.tgz" + }, + "time-stamp": { + "version": "1.0.1", + "from": "time-stamp@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.0.1.tgz" + }, + "tmpl": { + "version": "1.0.4", + "from": "tmpl@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz" + }, + "to-fast-properties": { + "version": "1.0.2", + "from": "to-fast-properties@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.2.tgz" + }, + "tough-cookie": { + "version": "2.2.2", + "from": "tough-cookie@>=2.2.0 <3.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz" + }, + "tr46": { + "version": "0.0.3", + "from": "tr46@>=0.0.3 <0.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" + }, + "trim-newlines": { + "version": "1.0.0", + "from": "trim-newlines@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz" + }, + "trim-right": { + "version": "1.0.1", + "from": "trim-right@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz" + }, + "try-resolve": { + "version": "1.0.1", + "from": "try-resolve@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz" + }, + "tryit": { + "version": "1.0.2", + "from": "tryit@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.2.tgz" + }, + "tryor": { + "version": "0.1.2", + "from": "tryor@>=0.1.2 <0.2.0", + "resolved": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz" + }, + "tunnel-agent": { + "version": "0.4.3", + "from": "tunnel-agent@>=0.4.1 <0.5.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz" + }, + "tv4": { + "version": "1.2.7", + "from": "tv4@>=1.2.7 <2.0.0", + "resolved": "https://registry.npmjs.org/tv4/-/tv4-1.2.7.tgz" + }, + "tweetnacl": { + "version": "0.13.3", + "from": "tweetnacl@>=0.13.0 <0.14.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.13.3.tgz" + }, + "type-check": { + "version": "0.3.2", + "from": "type-check@>=0.3.2 <0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" + }, + "typedarray": { + "version": "0.0.6", + "from": "typedarray@>=0.0.5 <0.1.0", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" + }, + "uglify-js": { + "version": "2.7.0", + "from": "uglify-js@>=2.6.0 <3.0.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.0.tgz", + "dependencies": { + "async": { + "version": "0.2.10", + "from": "async@>=0.2.6 <0.3.0", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz" + }, + "camelcase": { + "version": "1.2.1", + "from": "camelcase@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz" + }, + "yargs": { + "version": "3.10.0", + "from": "yargs@>=3.10.0 <3.11.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz" + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "from": "uglify-to-browserify@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz" + }, + "underscore": { + "version": "1.6.0", + "from": "underscore@>=1.6.0 <1.7.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz" + }, + "user-home": { + "version": "1.1.1", + "from": "user-home@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz" + }, + "util-deprecate": { + "version": "1.0.2", + "from": "util-deprecate@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + }, + "validate-npm-package-license": { + "version": "3.0.1", + "from": "validate-npm-package-license@>=3.0.1 <4.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz" + }, + "verror": { + "version": "1.3.6", + "from": "verror@1.3.6", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz" + }, + "vinyl": { + "version": "0.5.3", + "from": "vinyl@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz" + }, + "walker": { + "version": "1.0.7", + "from": "walker@>=1.0.5 <1.1.0", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz" + }, + "watch": { + "version": "0.10.0", + "from": "watch@>=0.10.0 <0.11.0", + "resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz" + }, + "webidl-conversions": { + "version": "3.0.1", + "from": "webidl-conversions@>=3.0.1 <4.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" + }, + "whatwg-url": { + "version": "3.0.0", + "from": "whatwg-url@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-3.0.0.tgz" + }, + "which": { + "version": "1.2.10", + "from": "which@>=1.2.9 <2.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.10.tgz" + }, + "window-size": { + "version": "0.1.0", + "from": "window-size@0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz" + }, + "wordwrap": { + "version": "1.0.0", + "from": "wordwrap@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" + }, + "worker-farm": { + "version": "1.3.1", + "from": "worker-farm@>=1.3.1 <2.0.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.3.1.tgz" + }, + "wrap-ansi": { + "version": "2.0.0", + "from": "wrap-ansi@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.0.0.tgz" + }, + "wrappy": { + "version": "1.0.2", + "from": "wrappy@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + }, + "write": { + "version": "0.2.1", + "from": "write@>=0.2.1 <0.3.0", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz" + }, + "xml-name-validator": { + "version": "2.0.1", + "from": "xml-name-validator@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz" + }, + "xregexp": { + "version": "3.1.1", + "from": "xregexp@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-3.1.1.tgz" + }, + "xtend": { + "version": "4.0.1", + "from": "xtend@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" + }, + "y18n": { + "version": "3.2.1", + "from": "y18n@>=3.2.1 <4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz" + }, + "yallist": { + "version": "2.0.0", + "from": "yallist@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.0.0.tgz" + }, + "yargs": { + "version": "4.7.1", + "from": "yargs@>=4.7.1 <5.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.7.1.tgz", + "dependencies": { + "camelcase": { + "version": "3.0.0", + "from": "camelcase@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz" + }, + "cliui": { + "version": "3.2.0", + "from": "cliui@>=3.2.0 <4.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz" + }, + "window-size": { + "version": "0.2.0", + "from": "window-size@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz" + } + } + }, + "yargs-parser": { + "version": "2.4.0", + "from": "yargs-parser@>=2.4.0 <3.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.0.tgz" + } + } +} diff --git a/package.json b/package.json index 31ce4496..74a148d1 100644 --- a/package.json +++ b/package.json @@ -9,14 +9,14 @@ "lint": "eslint ." }, "dependencies": { - "jscodeshift": "^0.3.23", + "jscodeshift": "^0.3.25", "babel-eslint": "^6.0.5", "babel-plugin-transform-object-rest-spread": "^6.6.5", "babel-preset-es2015": "^6.6.0", - "babel-jest": "^12.1.0", + "babel-jest": "^13.0.0", "eslint": "^2.13.1", "fbjs-scripts": "^0.7.1", - "jest-cli": "^12.1.0" + "jest-cli": "^13.0.0" }, "jest": { "automock": false, diff --git a/transforms/__testfixtures__/class-access-default-props1.input.js b/transforms/__testfixtures__/class-access-default-props1.input.js new file mode 100644 index 00000000..3518c8f9 --- /dev/null +++ b/transforms/__testfixtures__/class-access-default-props1.input.js @@ -0,0 +1,15 @@ +/* @flow */ +var React = require('react'); +var OtherClass = require('OtherClass'); + +var NewThing = React.createClass({ + getDefaultProps: OtherClass.getDefaultProps, + getData() { + return OtherClass.getDefaultProps(); + }, + render() { + return
; + }, +}); + +module.exports = NewThing; diff --git a/transforms/__testfixtures__/class-access-default-props1.output.js b/transforms/__testfixtures__/class-access-default-props1.output.js new file mode 100644 index 00000000..c33fc85c --- /dev/null +++ b/transforms/__testfixtures__/class-access-default-props1.output.js @@ -0,0 +1,17 @@ +/* @flow */ +var React = require('react'); +var OtherClass = require('OtherClass'); + +class NewThing extends React.Component { + static defaultProps = OtherClass.defaultProps; + + getData = () => { + return OtherClass.defaultProps; + }; + + render() { + return
; + } +} + +module.exports = NewThing; diff --git a/transforms/__testfixtures__/class-anonymous.input.js b/transforms/__testfixtures__/class-anonymous.input.js new file mode 100644 index 00000000..22b4ca7b --- /dev/null +++ b/transforms/__testfixtures__/class-anonymous.input.js @@ -0,0 +1,21 @@ +var React = require('react'); + +const wrapper = (x) => x; + +const Foo = wrapper(React.createClass({ + render() { + return
wow so anonymous
; + }, +})); + +module.exports = wrapper(React.createClass({ + render() { + return
wow so anonymous
; + }, +})); + +export default wrapper(React.createClass({ + render() { + return
wow so anonymous
; + }, +})); diff --git a/transforms/__testfixtures__/class-anonymous.output.js b/transforms/__testfixtures__/class-anonymous.output.js new file mode 100644 index 00000000..c90ecbc4 --- /dev/null +++ b/transforms/__testfixtures__/class-anonymous.output.js @@ -0,0 +1,21 @@ +var React = require('react'); + +const wrapper = (x) => x; + +const Foo = wrapper(class extends React.Component { + render() { + return
wow so anonymous
; + } +}); + +module.exports = wrapper(class extends React.Component { + render() { + return
wow so anonymous
; + } +}); + +export default wrapper(class extends React.Component { + render() { + return
wow so anonymous
; + } +}); diff --git a/transforms/__testfixtures__/class-anonymous2.input.js b/transforms/__testfixtures__/class-anonymous2.input.js new file mode 100644 index 00000000..a9024745 --- /dev/null +++ b/transforms/__testfixtures__/class-anonymous2.input.js @@ -0,0 +1,50 @@ +/** + * @flow + */ +/* eslint-disable no-use-before-define */ +'use strict'; + +var React = require('React'); + +var CrazyObject = { + foo: { + bar: 123, + }, + method: { + wrapThisGuy: (x) => x, + deep: { + wrapThatGuy: (x) => x, + }, + }, + iDontUnderstand: { + whyYouDoThis: { + butAnyway: { + comp1: React.createClass({ + render() { + return
; + }, + }), + comp2: CrazyObject.method.wrapThatGuy(React.createClass({ + render() { + return
; + }, + })), + waitWhatArrayForReal: [React.createClass({ + render() { + return
; + }, + }), [React.createClass({ + render() { + return

; + }, + }), React.createClass({ + render() { + return ; + }, + })]], + }, + }, + }, +}; + +module.exports = WaltUtils; diff --git a/transforms/__testfixtures__/class-anonymous2.output.js b/transforms/__testfixtures__/class-anonymous2.output.js new file mode 100644 index 00000000..1b7a8fcb --- /dev/null +++ b/transforms/__testfixtures__/class-anonymous2.output.js @@ -0,0 +1,50 @@ +/** + * @flow + */ +/* eslint-disable no-use-before-define */ +'use strict'; + +var React = require('React'); + +var CrazyObject = { + foo: { + bar: 123, + }, + method: { + wrapThisGuy: (x) => x, + deep: { + wrapThatGuy: (x) => x, + }, + }, + iDontUnderstand: { + whyYouDoThis: { + butAnyway: { + comp1: class extends React.Component { + render() { + return

; + } + }, + comp2: CrazyObject.method.wrapThatGuy(class extends React.Component { + render() { + return
; + } + }), + waitWhatArrayForReal: [class extends React.Component { + render() { + return
; + } + }, [class extends React.Component { + render() { + return

; + } + }, class extends React.Component { + render() { + return ; + } + }]], + }, + }, + }, +}; + +module.exports = WaltUtils; diff --git a/transforms/__testfixtures__/class-flow1.input.js b/transforms/__testfixtures__/class-flow1.input.js new file mode 100644 index 00000000..da855cb9 --- /dev/null +++ b/transforms/__testfixtures__/class-flow1.input.js @@ -0,0 +1,40 @@ +/* @flow */ + +var React = require('react'); + +var Component = React.createClass({ + propTypes: { + 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', 1, true, null, undefined]), + optionalUnion: React.PropTypes.oneOfType([ + React.PropTypes.string, + React.PropTypes.number, + React.PropTypes.instanceOf(Message), + ]), + optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number), + optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number), + optionalObjectOfRequiredField: React.PropTypes.objectOf(React.PropTypes.number.isRequired), + requiredObjectOfRequiredField: React.PropTypes.objectOf(React.PropTypes.number.isRequired).isRequired, + requiredObjectOfOptionalField: React.PropTypes.objectOf(React.PropTypes.number).isRequired, + optionalObjectWithShape: React.PropTypes.shape({ + color: React.PropTypes.string, + fontSize: React.PropTypes.number.isRequired, + }), + requiredFunc: React.PropTypes.func.isRequired, + requiredAny: React.PropTypes.any.isRequired, + }, + + render: function() { + return ( +

type safety
+ ); + }, +}); diff --git a/transforms/__testfixtures__/class-flow1.output.js b/transforms/__testfixtures__/class-flow1.output.js new file mode 100644 index 00000000..7e506225 --- /dev/null +++ b/transforms/__testfixtures__/class-flow1.output.js @@ -0,0 +1,65 @@ +/* @flow */ + +var React = require('react'); + +class Component extends React.Component { + props: { + optionalArray?: Array<$FlowFixMe>, + optionalBool?: boolean, + optionalFunc?: Function, + optionalNumber?: number, + optionalObject?: Object, + optionalString?: string, + optionalNode?: $FlowFixMe, + optionalElement?: $FlowFixMe, + optionalMessage?: Message, + optionalEnum?: 'News' | 'Photos' | 1 | true | null | void, + optionalUnion?: string | number | Message, + optionalArrayOf?: Array, + optionalObjectOf?: {[key: string]: number}, + optionalObjectOfRequiredField?: {[key: string]: number}, + requiredObjectOfRequiredField: {[key: string]: number}, + requiredObjectOfOptionalField: {[key: string]: number}, + optionalObjectWithShape?: { + color?: string, + fontSize: number, + }, + requiredFunc: Function, + requiredAny: any, + }; + + static propTypes = { + 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', 1, true, null, undefined]), + optionalUnion: React.PropTypes.oneOfType([ + React.PropTypes.string, + React.PropTypes.number, + React.PropTypes.instanceOf(Message), + ]), + optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number), + optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number), + optionalObjectOfRequiredField: React.PropTypes.objectOf(React.PropTypes.number.isRequired), + requiredObjectOfRequiredField: React.PropTypes.objectOf(React.PropTypes.number.isRequired).isRequired, + requiredObjectOfOptionalField: React.PropTypes.objectOf(React.PropTypes.number).isRequired, + optionalObjectWithShape: React.PropTypes.shape({ + color: React.PropTypes.string, + fontSize: React.PropTypes.number.isRequired, + }), + requiredFunc: React.PropTypes.func.isRequired, + requiredAny: React.PropTypes.any.isRequired, + }; + + render() { + return ( +
type safety
+ ); + } +} diff --git a/transforms/__testfixtures__/class-flow2.input.js b/transforms/__testfixtures__/class-flow2.input.js new file mode 100644 index 00000000..490706c6 --- /dev/null +++ b/transforms/__testfixtures__/class-flow2.input.js @@ -0,0 +1,52 @@ +/* code taken from https://github.com/reactjs/react-router/blob/master/modules/IndexRoute.js */ +/* @flow */ + +import React from 'react' +import warning from './routerWarning' +import invariant from 'invariant' +import { createRouteFromReactElement } from './RouteUtils' +import { component, components, falsy } from './InternalPropTypes' + +const { func } = React.PropTypes + +/** + * An is used to specify its parent's in + * a JSX route config. + */ +const IndexRoute = React.createClass({ + + statics: { + + createRouteFromReactElement(element, parentRoute) { + /* istanbul ignore else: sanity check */ + if (parentRoute) { + parentRoute.indexRoute = createRouteFromReactElement(element) + } else { + warning( + false, + 'An does not make sense at the root of your route config' + ) + } + } + + }, + + propTypes: { + path: falsy, + component, + components, + getComponent: func, + getComponents: func + }, + + /* istanbul ignore next: sanity check */ + render() { + invariant( + false, + ' elements are for router configuration only and should not be rendered' + ) + } + +}) + +export default IndexRoute diff --git a/transforms/__testfixtures__/class-flow2.output.js b/transforms/__testfixtures__/class-flow2.output.js new file mode 100644 index 00000000..3a6b74d5 --- /dev/null +++ b/transforms/__testfixtures__/class-flow2.output.js @@ -0,0 +1,54 @@ +/* code taken from https://github.com/reactjs/react-router/blob/master/modules/IndexRoute.js */ +/* @flow */ + +import React from 'react' +import warning from './routerWarning' +import invariant from 'invariant' +import { createRouteFromReactElement } from './RouteUtils' +import { component, components, falsy } from './InternalPropTypes' + +const { func } = React.PropTypes + +/** + * An is used to specify its parent's in + * a JSX route config. + */ +class IndexRoute extends React.Component { + props: { + path?: $FlowFixMe, + component?: $FlowFixMe, + components?: $FlowFixMe, + getComponent?: $FlowFixMe, + getComponents?: $FlowFixMe, + }; + + static createRouteFromReactElement(element, parentRoute) { + /* istanbul ignore else: sanity check */ + if (parentRoute) { + parentRoute.indexRoute = createRouteFromReactElement(element) + } else { + warning( + false, + 'An does not make sense at the root of your route config' + ) + } + } + + static propTypes = { + path: falsy, + component, + components, + getComponent: func, + getComponents: func + }; + + /* istanbul ignore next: sanity check */ + render() { + invariant( + false, + ' elements are for router configuration only and should not be rendered' + ) + } +} + +export default IndexRoute diff --git a/transforms/__testfixtures__/class-flow3.input.js b/transforms/__testfixtures__/class-flow3.input.js new file mode 100644 index 00000000..f42dfd44 --- /dev/null +++ b/transforms/__testfixtures__/class-flow3.input.js @@ -0,0 +1,47 @@ +/* @flow */ + +var React = require('react'); +var {PropTypes} = React; + +var getPropTypes = () => PropTypes.string; + +var myUnionPropType = PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + PropTypes.instanceOf(Message), +]); + +var spreadMe = { + optionalArray: PropTypes.array, + optionalBool: PropTypes.bool, +}; + +var optionalFuncShortHand = PropTypes.func; + +var Component = React.createClass({ + propTypes: { + ...spreadMe, + optionalFuncShortHand, + optionalNumber: 1 + 1 === 2 ? PropTypes.number : PropTypes.string, + optionalObject: PropTypes.object, + optionalString: getPropTypes(), + optionalNode: PropTypes.node, + optionalElement: PropTypes.element, + optionalMessage: PropTypes.instanceOf(Message), + optionalEnum: PropTypes.oneOf(['News', 'Photos', 1, true, null]), + optionalUnion: myUnionPropType, + optionalArrayOf: PropTypes.arrayOf(PropTypes.number), + optionalObjectOf: PropTypes.objectOf(PropTypes.number), + optionalObjectWithShape: PropTypes.shape({ + color: PropTypes.string, + }), + requiredFunc: PropTypes.func.isRequired, + requiredAny: PropTypes.any.isRequired, + }, + + render: function() { + return ( +
type safety
+ ); + }, +}); diff --git a/transforms/__testfixtures__/class-flow3.output.js b/transforms/__testfixtures__/class-flow3.output.js new file mode 100644 index 00000000..932b2337 --- /dev/null +++ b/transforms/__testfixtures__/class-flow3.output.js @@ -0,0 +1,64 @@ +/* @flow */ + +var React = require('react'); +var {PropTypes} = React; + +var getPropTypes = () => PropTypes.string; + +var myUnionPropType = PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + PropTypes.instanceOf(Message), +]); + +var spreadMe = { + optionalArray: PropTypes.array, + optionalBool: PropTypes.bool, +}; + +var optionalFuncShortHand = PropTypes.func; + +class Component extends React.Component { + props: { + optionalFuncShortHand?: $FlowFixMe, + optionalNumber?: $FlowFixMe, + optionalObject?: Object, + optionalString?: $FlowFixMe, + optionalNode?: $FlowFixMe, + optionalElement?: $FlowFixMe, + optionalMessage?: Message, + optionalEnum?: 'News' | 'Photos' | 1 | true | null, + optionalUnion?: $FlowFixMe, + optionalArrayOf?: Array, + optionalObjectOf?: {[key: string]: number}, + optionalObjectWithShape?: {color?: string}, + requiredFunc: Function, + requiredAny: any, + }; + + static propTypes = { + ...spreadMe, + optionalFuncShortHand, + optionalNumber: 1 + 1 === 2 ? PropTypes.number : PropTypes.string, + optionalObject: PropTypes.object, + optionalString: getPropTypes(), + optionalNode: PropTypes.node, + optionalElement: PropTypes.element, + optionalMessage: PropTypes.instanceOf(Message), + optionalEnum: PropTypes.oneOf(['News', 'Photos', 1, true, null]), + optionalUnion: myUnionPropType, + optionalArrayOf: PropTypes.arrayOf(PropTypes.number), + optionalObjectOf: PropTypes.objectOf(PropTypes.number), + optionalObjectWithShape: PropTypes.shape({ + color: PropTypes.string, + }), + requiredFunc: PropTypes.func.isRequired, + requiredAny: PropTypes.any.isRequired, + }; + + render() { + return ( +
type safety
+ ); + } +} diff --git a/transforms/__testfixtures__/class-flow4.input.js b/transforms/__testfixtures__/class-flow4.input.js new file mode 100644 index 00000000..9694eb60 --- /dev/null +++ b/transforms/__testfixtures__/class-flow4.input.js @@ -0,0 +1,44 @@ +/* @flow */ + +var React = require('react'); +var {PropTypes} = React; + +var myUnionPropType = PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + PropTypes.instanceOf(Message), +]); + +var spreadMe = { + optionalArray: PropTypes.array, + optionalBool: PropTypes.bool, +}; + +var optionalFuncShortHand = PropTypes.func; + +var Component = React.createClass({ + propTypes: Object.assign({}, { + ...spreadMe, + optionalFuncShortHand, + optionalNumber: PropTypes.number, + optionalObject: PropTypes.object, + }), + + render: function() { + return ( +
type safety
+ ); + }, +}); + +var thatPropTypes = {}; + +var Component2 = React.createClass({ + propTypes: thatPropTypes, + + render: function() { + return ( +
type safety
+ ); + }, +}); diff --git a/transforms/__testfixtures__/class-flow4.output.js b/transforms/__testfixtures__/class-flow4.output.js new file mode 100644 index 00000000..a25c6254 --- /dev/null +++ b/transforms/__testfixtures__/class-flow4.output.js @@ -0,0 +1,44 @@ +/* @flow */ + +var React = require('react'); +var {PropTypes} = React; + +var myUnionPropType = PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + PropTypes.instanceOf(Message), +]); + +var spreadMe = { + optionalArray: PropTypes.array, + optionalBool: PropTypes.bool, +}; + +var optionalFuncShortHand = PropTypes.func; + +class Component extends React.Component { + static propTypes = Object.assign({}, { + ...spreadMe, + optionalFuncShortHand, + optionalNumber: PropTypes.number, + optionalObject: PropTypes.object, + }); + + render() { + return ( +
type safety
+ ); + } +} + +var thatPropTypes = {}; + +class Component2 extends React.Component { + static propTypes = thatPropTypes; + + render() { + return ( +
type safety
+ ); + } +} diff --git a/transforms/__testfixtures__/class-flow5.input.js b/transforms/__testfixtures__/class-flow5.input.js new file mode 100644 index 00000000..3abae359 --- /dev/null +++ b/transforms/__testfixtures__/class-flow5.input.js @@ -0,0 +1,40 @@ +/* @flow */ + +var React = require('react'); + +type SomeStuff = { // TypeParameter + fetch: () => Promise, +}; + +var Component = React.createClass({ + statics: { + notTyped: true, + nothing: (null: null), // NullTypeAnnotation + numberOrBool: (true: number | boolean), + logger: (x: any): void => { console.log(x); }, + logger2: function(x: any): void { + console.log(x); + }, + }, + + notTyped: true, + foo: (12: number), + bar: ('2000': string), + handleClick: (null: ?(evt: any) => void), + + doStuff: function(x: number, y: boolean): boolean { + return y && (x > 0); + }, + + componentDidMount: function() { + this.handleClick = function(e) { + console.log(e); + }; + }, + + render: function() { + return ( +
{this.foo}
+ ); + }, +}); diff --git a/transforms/__testfixtures__/class-flow5.output.js b/transforms/__testfixtures__/class-flow5.output.js new file mode 100644 index 00000000..ca001120 --- /dev/null +++ b/transforms/__testfixtures__/class-flow5.output.js @@ -0,0 +1,39 @@ +/* @flow */ + +var React = require('react'); + +type SomeStuff
= { // TypeParameter + fetch: () => Promise, +}; + +class Component extends React.Component { + static notTyped = true; + static nothing: null = null; // NullTypeAnnotation + static numberOrBool: number | boolean = true; + static logger = (x: any): void => { console.log(x); }; + + static logger2(x: any): void { + console.log(x); + } + + notTyped = true; + foo: number = 12; + bar: string = '2000'; + handleClick: ?(evt: any) => void = null; + + doStuff = (x: number, y: boolean): boolean => { + return y && (x > 0); + }; + + componentDidMount() { + this.handleClick = function(e) { + console.log(e); + }; + } + + render() { + return ( +
{this.foo}
+ ); + } +} diff --git a/transforms/__testfixtures__/class-flow6.input.js b/transforms/__testfixtures__/class-flow6.input.js new file mode 100644 index 00000000..b008f814 --- /dev/null +++ b/transforms/__testfixtures__/class-flow6.input.js @@ -0,0 +1,41 @@ +/* @flow */ + +var React = require('react'); + +const justNeedKeys = { + a: 12, + b: 23, +}; + +var Component = React.createClass({ + propTypes: { + optionalMessage: React.PropTypes.instanceOf(Message), + optionalMessageOops: React.PropTypes.instanceOf(foo()), + optionalEnum: React.PropTypes.oneOf(Object.keys(justNeedKeys)), + optionalEnumOops: React.PropTypes.oneOf(bar), + optionalUnion: React.PropTypes.oneOfType([ + React.PropTypes.string, + React.PropTypes.number, + React.PropTypes.instanceOf(Message), + ]), + optionalUnionOops: React.PropTypes.oneOfType(foo()), + optionalUnionOops2: React.PropTypes.oneOfType(Bar), + optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number), + optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number), + optionalObjectWithShape: React.PropTypes.shape({ + color: React.PropTypes.string, + fontSize: foo, + name: bla(), + }), + optionalObjectWithShapeOops: React.PropTypes.shape(foo()), + optionalObjectWithShapeOops2: React.PropTypes.shape(bla), + 'is-literal-cool': React.PropTypes.bool, + 'well-fine': React.PropTypes.number.isRequired, + }, + + render: function() { + return ( +
type safety
+ ); + }, +}); diff --git a/transforms/__testfixtures__/class-flow6.output.js b/transforms/__testfixtures__/class-flow6.output.js new file mode 100644 index 00000000..1ac3ff07 --- /dev/null +++ b/transforms/__testfixtures__/class-flow6.output.js @@ -0,0 +1,62 @@ +/* @flow */ + +var React = require('react'); + +const justNeedKeys = { + a: 12, + b: 23, +}; + +class Component extends React.Component { + props: { + optionalMessage?: Message, + optionalMessageOops?: $FlowFixMe, + optionalEnum?: $FlowFixMe, + optionalEnumOops?: $FlowFixMe, + optionalUnion?: string | number | Message, + optionalUnionOops?: $FlowFixMe, + optionalUnionOops2?: $FlowFixMe, + optionalArrayOf?: Array, + optionalObjectOf?: {[key: string]: number}, + optionalObjectWithShape?: { + color?: string, + fontSize?: $FlowFixMe, + name?: $FlowFixMe, + }, + optionalObjectWithShapeOops?: $FlowFixMe, + optionalObjectWithShapeOops2?: $FlowFixMe, + 'is-literal-cool'?: boolean, + 'well-fine': number, + }; + + static propTypes = { + optionalMessage: React.PropTypes.instanceOf(Message), + optionalMessageOops: React.PropTypes.instanceOf(foo()), + optionalEnum: React.PropTypes.oneOf(Object.keys(justNeedKeys)), + optionalEnumOops: React.PropTypes.oneOf(bar), + optionalUnion: React.PropTypes.oneOfType([ + React.PropTypes.string, + React.PropTypes.number, + React.PropTypes.instanceOf(Message), + ]), + optionalUnionOops: React.PropTypes.oneOfType(foo()), + optionalUnionOops2: React.PropTypes.oneOfType(Bar), + optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number), + optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number), + optionalObjectWithShape: React.PropTypes.shape({ + color: React.PropTypes.string, + fontSize: foo, + name: bla(), + }), + optionalObjectWithShapeOops: React.PropTypes.shape(foo()), + optionalObjectWithShapeOops2: React.PropTypes.shape(bla), + 'is-literal-cool': React.PropTypes.bool, + 'well-fine': React.PropTypes.number.isRequired, + }; + + render() { + return ( +
type safety
+ ); + } +} diff --git a/transforms/__testfixtures__/class-flow7.input.js b/transforms/__testfixtures__/class-flow7.input.js new file mode 100644 index 00000000..b008f814 --- /dev/null +++ b/transforms/__testfixtures__/class-flow7.input.js @@ -0,0 +1,41 @@ +/* @flow */ + +var React = require('react'); + +const justNeedKeys = { + a: 12, + b: 23, +}; + +var Component = React.createClass({ + propTypes: { + optionalMessage: React.PropTypes.instanceOf(Message), + optionalMessageOops: React.PropTypes.instanceOf(foo()), + optionalEnum: React.PropTypes.oneOf(Object.keys(justNeedKeys)), + optionalEnumOops: React.PropTypes.oneOf(bar), + optionalUnion: React.PropTypes.oneOfType([ + React.PropTypes.string, + React.PropTypes.number, + React.PropTypes.instanceOf(Message), + ]), + optionalUnionOops: React.PropTypes.oneOfType(foo()), + optionalUnionOops2: React.PropTypes.oneOfType(Bar), + optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number), + optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number), + optionalObjectWithShape: React.PropTypes.shape({ + color: React.PropTypes.string, + fontSize: foo, + name: bla(), + }), + optionalObjectWithShapeOops: React.PropTypes.shape(foo()), + optionalObjectWithShapeOops2: React.PropTypes.shape(bla), + 'is-literal-cool': React.PropTypes.bool, + 'well-fine': React.PropTypes.number.isRequired, + }, + + render: function() { + return ( +
type safety
+ ); + }, +}); diff --git a/transforms/__testfixtures__/class-flow7.output.js b/transforms/__testfixtures__/class-flow7.output.js new file mode 100644 index 00000000..a30533bc --- /dev/null +++ b/transforms/__testfixtures__/class-flow7.output.js @@ -0,0 +1,37 @@ +/* @flow */ + +var React = require('react'); + +const justNeedKeys = { + a: 12, + b: 23, +}; + +class Component extends React.Component { + props: { + optionalMessage?: Message, + optionalMessageOops?: $FlowFixMe, + optionalEnum?: $FlowFixMe, + optionalEnumOops?: $FlowFixMe, + optionalUnion?: string | number | Message, + optionalUnionOops?: $FlowFixMe, + optionalUnionOops2?: $FlowFixMe, + optionalArrayOf?: Array, + optionalObjectOf?: {[key: string]: number}, + optionalObjectWithShape?: { + color?: string, + fontSize?: $FlowFixMe, + name?: $FlowFixMe, + }, + optionalObjectWithShapeOops?: $FlowFixMe, + optionalObjectWithShapeOops2?: $FlowFixMe, + 'is-literal-cool'?: boolean, + 'well-fine': number, + }; + + render() { + return ( +
type safety
+ ); + } +} diff --git a/transforms/__testfixtures__/class-initial-state.input.js b/transforms/__testfixtures__/class-initial-state.input.js new file mode 100644 index 00000000..b5ecfdaf --- /dev/null +++ b/transforms/__testfixtures__/class-initial-state.input.js @@ -0,0 +1,309 @@ +/* @flow */ + +import React from 'React'; + +type SomeState = {foo: string}; + +// only needs props +var MyComponent = React.createClass({ + getInitialState: function(): {heyoo: number} { + var x = this.props.foo; + return { + heyoo: 23, + }; + }, + + foo: function(): void { + this.setState({heyoo: 24}); + }, +}); + +var ComponentWithBothPropsAndContextAccess = React.createClass({ + contextTypes: { + name: React.PropTypes.string, + }, + + // we actually don't need a constructor here since this will be + // initialized after a proper super(props, context) call. + // in other words, `this` will be ready when it reaches here. + getInitialState: function() { + return { + foo: this.props.foo, + bar: this.context.bar, + }; + }, + + render: function() { + return ( +
{this.context.name}
+ ); + }, +}); + +const App = React.createClass({ + getInitialState(): SomeState { + const state = this.calculateState(); // _might_ use `this.context` + return state; + }, + calculateState() { + return { color: this.context.color }; + }, + render() { + return
; + }, +}); + +const App2 = React.createClass({ + getInitialState() { + const state = { + whatever: this.context.whatever, // needs context + }; + return state; + }, + render() { + return
; + }, +}); + +App.contextTypes = { + whatever: React.PropTypes.object, +}; + +var MyComponent2 = React.createClass({ + getInitialState: function() { + var x = this.props.foo.bar.wow.so.deep; + return { + heyoo: 23, + }; + }, + + foo: function(): void { + this.setState({heyoo: 24}); + }, +}); + +const getContextFromInstance = (x) => x.context; // meh + +var MyComponent3 = React.createClass({ + getInitialState: function() { + var x = getContextFromInstance(this); // `this` is referenced alone + return { + heyoo: x, + }; + }, + + foo: function(): void { + this.setState({heyoo: 24}); + }, +}); + +// we are not sure what you'll need from `this`, +// so it's safe to defer `state`'s initialization +var MyComponent4 = React.createClass({ + getInitialState: function() { + return { + heyoo: getContextFromInstance(this), + }; + }, + + foo: function(): void { + this.setState({heyoo: 24}); + }, +}); + +// but only accessing `this.props` and/or `this.context` is safe +var MyComponent5 = React.createClass({ + getInitialState: function() { + return { + heyoo: getContextFromInstance(this.props), + }; + }, + + foo: function(): void { + this.setState({heyoo: 24}); + }, +}); + +// intense control flow testing +var Loader = React.createClass({ + getInitialState() { + if (this.props.stuff) { + return {x: 1}; + } else if (this.props.thing) { + return {x: 2}; + } + switch (this.props.wow) { + case 1: + return this.props.lol ? + {x: 3} : + this.whatever(this.props); + } + for (let i = 0; i < 100; i++) { + if (i === 20) { + return {x: i}; + } + } + + try { + doSomeThingReallyBad(); + } catch (e) { + return {error: e}; + } + + return this.lol(); + }, + + render() { + return null; + }, +}); + +var FunctionDeclarationInGetInitialState = React.createClass({ + getInitialState() { + function func() { + var x = 1; + return x; // dont change me + } + + const foo = () => { + return 120; // dont change me + }; + + var q = function() { + return 100; // dont change me + }; + + return { + x: func(), + y: foo(), + z: q(), + }; + }, + + render() { + return null; + }, +}); + +var DeferStateInitialization = React.createClass({ + getInitialState() { + return {x: this.something}; + }, + + something: 42, + + render() { + return
; + }, +}); + +var helper = () => {}; + +var PassGetInitialState = React.createClass({ // bail out here + getInitialState() { + return this.lol(); + }, + + helper1: function() { + helper(this.getInitialState); + }, + + render() { + return null; + }, +}); + +var UseGetInitialState = React.createClass({ // bail out here + getInitialState() { + return this.lol(); + }, + + helper2() { + this.setState(this.getInitialState()); + }, + + render() { + return null; + }, +}); + +var UseArguments = React.createClass({ // bail out here + helper() { + console.log(arguments); + }, + + render() { + return null; + }, +}); + +var ShadowingIssue = React.createClass({ // bail out here + getInitialState() { + const props = { x: 123 }; + return { x: props.x }; + }, + + render() { + return null; + }, +}); + +// will remove unnecessary bindings +var ShadowingButFine = React.createClass({ + getInitialState() { + const props = this.props; + const context = this.context; + return { x: props.x + context.x }; + }, + + render() { + return null; + }, +}); + +// move type annotations +var WithSimpleType = React.createClass({ + getInitialState(): Object { + return { + x: 12, + y: 13, + z: 14, + }; + }, + + render() { + return null; + }, +}); + +var WithLongType = React.createClass({ + getInitialState(): {name: string, age: number, counter: number} { + return { + name: 'Michael', + age: 23, + count: 6, + }; + }, + + render() { + return null; + }, +}); + +var WithMultiLineType = React.createClass({ + getInitialState(): { + nameLists: Array>, + age?: ?number, + counter?: ?number, + } { + return { + nameLists: [['James']], + count: 1400, + foo: 'bar', + }; + }, + + render() { + return null; + }, +}); diff --git a/transforms/__testfixtures__/class-initial-state.output.js b/transforms/__testfixtures__/class-initial-state.output.js new file mode 100644 index 00000000..e71740c0 --- /dev/null +++ b/transforms/__testfixtures__/class-initial-state.output.js @@ -0,0 +1,328 @@ +/* @flow */ + +import React from 'React'; + +type SomeState = {foo: string}; + +// only needs props +class MyComponent extends React.Component { + state: {heyoo: number}; + + constructor(props) { + super(props); + var x = props.foo; + + this.state = { + heyoo: 23, + }; + } + + foo = (): void => { + this.setState({heyoo: 24}); + }; +} + +class ComponentWithBothPropsAndContextAccess extends React.Component { + static contextTypes = { + name: React.PropTypes.string, + }; + + // we actually don't need a constructor here since this will be + // initialized after a proper super(props, context) call. + // in other words, `this` will be ready when it reaches here. + state = { + foo: this.props.foo, + bar: this.context.bar, + }; + + render() { + return ( +
{this.context.name}
+ ); + } +} + +class App extends React.Component { + state: SomeState; + + constructor(props, context) { + super(props, context); + const state = this.calculateState(); // _might_ use `this.context` + this.state = state; + } + + calculateState = () => { + return { color: this.context.color }; + }; + + render() { + return
; + } +} + +class App2 extends React.Component { + state: Object; + + constructor(props, context) { + super(props, context); + const state = { + whatever: context.whatever, // needs context + }; + this.state = state; + } + + render() { + return
; + } +} + +App.contextTypes = { + whatever: React.PropTypes.object, +}; + +class MyComponent2 extends React.Component { + state: Object; + + constructor(props) { + super(props); + var x = props.foo.bar.wow.so.deep; + + this.state = { + heyoo: 23, + }; + } + + foo = (): void => { + this.setState({heyoo: 24}); + }; +} + +const getContextFromInstance = (x) => x.context; // meh + +class MyComponent3 extends React.Component { + state: Object; + + constructor(props, context) { + super(props, context); + var x = getContextFromInstance(this); // `this` is referenced alone + + this.state = { + heyoo: x, + }; + } + + foo = (): void => { + this.setState({heyoo: 24}); + }; +} + +// we are not sure what you'll need from `this`, +// so it's safe to defer `state`'s initialization +class MyComponent4 extends React.Component { + foo = (): void => { + this.setState({heyoo: 24}); + }; + + state = { + heyoo: getContextFromInstance(this), + }; +} + +// but only accessing `this.props` and/or `this.context` is safe +class MyComponent5 extends React.Component { + state = { + heyoo: getContextFromInstance(this.props), + }; + + foo = (): void => { + this.setState({heyoo: 24}); + }; +} + +// intense control flow testing +class Loader extends React.Component { + state: Object; + + constructor(props, context) { + super(props, context); + if (props.stuff) { + this.state = {x: 1}; + return; + } else if (props.thing) { + this.state = {x: 2}; + return; + } + switch (props.wow) { + case 1: + this.state = props.lol ? + {x: 3} : + this.whatever(props); + + return; + } + for (let i = 0; i < 100; i++) { + if (i === 20) { + this.state = {x: i}; + return; + } + } + + try { + doSomeThingReallyBad(); + } catch (e) { + this.state = {error: e}; + return; + } + + this.state = this.lol(); + } + + render() { + return null; + } +} + +class FunctionDeclarationInGetInitialState extends React.Component { + state: Object; + + constructor(props) { + super(props); + function func() { + var x = 1; + return x; // dont change me + } + + const foo = () => { + return 120; // dont change me + }; + + var q = function() { + return 100; // dont change me + }; + + this.state = { + x: func(), + y: foo(), + z: q(), + }; + } + + render() { + return null; + } +} + +class DeferStateInitialization extends React.Component { + something = 42; + state = {x: this.something}; + + render() { + return
; + } +} + +var helper = () => {}; + +var PassGetInitialState = React.createClass({ // bail out here + getInitialState() { + return this.lol(); + }, + + helper1: function() { + helper(this.getInitialState); + }, + + render() { + return null; + }, +}); + +var UseGetInitialState = React.createClass({ // bail out here + getInitialState() { + return this.lol(); + }, + + helper2() { + this.setState(this.getInitialState()); + }, + + render() { + return null; + }, +}); + +var UseArguments = React.createClass({ // bail out here + helper() { + console.log(arguments); + }, + + render() { + return null; + }, +}); + +var ShadowingIssue = React.createClass({ // bail out here + getInitialState() { + const props = { x: 123 }; + return { x: props.x }; + }, + + render() { + return null; + }, +}); + +// will remove unnecessary bindings +class ShadowingButFine extends React.Component { + state: Object; + + constructor(props, context) { + super(props, context); + this.state = { x: props.x + context.x }; + } + + render() { + return null; + } +} + +// move type annotations +class WithSimpleType extends React.Component { + state: Object = { + x: 12, + y: 13, + z: 14, + }; + + render() { + return null; + } +} + +class WithLongType extends React.Component { + state: {name: string, age: number, counter: number} = { + name: 'Michael', + age: 23, + count: 6, + }; + + render() { + return null; + } +} + +class WithMultiLineType extends React.Component { + state: { + nameLists: Array>, + age?: ?number, + counter?: ?number, + } = { + nameLists: [['James']], + count: 1400, + foo: 'bar', + }; + + render() { + return null; + } +} diff --git a/transforms/__testfixtures__/class-property-field.input.js b/transforms/__testfixtures__/class-property-field.input.js new file mode 100644 index 00000000..e6ba4006 --- /dev/null +++ b/transforms/__testfixtures__/class-property-field.input.js @@ -0,0 +1,28 @@ +const React = require('react'); + +const Component1 = React.createClass({ + statics: { + booleanPrim: true, + numberPrim: 12, + stringPrim: 'foo', + nullPrim: null, + undefinedPrim: undefined, + }, + booleanPrim: true, + numberPrim: 12, + stringPrim: 'foo', + nullPrim: null, + undefinedPrim: undefined, + + foobar: function() { + return 123; + }, + + componentDidMount: function() { + console.log('hello'); + }, + + render: function() { + return
; + }, +}); diff --git a/transforms/__testfixtures__/class-property-field.output.js b/transforms/__testfixtures__/class-property-field.output.js new file mode 100644 index 00000000..34305a2b --- /dev/null +++ b/transforms/__testfixtures__/class-property-field.output.js @@ -0,0 +1,26 @@ +const React = require('react'); + +class Component1 extends React.Component { + static booleanPrim = true; + static numberPrim = 12; + static stringPrim = 'foo'; + static nullPrim = null; + static undefinedPrim = undefined; + booleanPrim = true; + numberPrim = 12; + stringPrim = 'foo'; + nullPrim = null; + undefinedPrim = undefined; + + foobar = () => { + return 123; + }; + + componentDidMount() { + console.log('hello'); + } + + render() { + return
; + } +} diff --git a/transforms/__testfixtures__/class-pure-mixin1.input.js b/transforms/__testfixtures__/class-pure-mixin1.input.js new file mode 100644 index 00000000..381a7e7f --- /dev/null +++ b/transforms/__testfixtures__/class-pure-mixin1.input.js @@ -0,0 +1,19 @@ +// dont remove me +var ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin'); +var React = require('React'); + +var ComponentWithOnlyPureRenderMixin = React.createClass({ + mixins: [ReactComponentWithPureRenderMixin], + + getInitialState: function() { + return { + counter: this.props.initialNumber + 1, + }; + }, + + render: function() { + return ( +
{this.state.counter}
+ ); + }, +}); diff --git a/transforms/__testfixtures__/class-pure-mixin1.output.js b/transforms/__testfixtures__/class-pure-mixin1.output.js new file mode 100644 index 00000000..741db3c9 --- /dev/null +++ b/transforms/__testfixtures__/class-pure-mixin1.output.js @@ -0,0 +1,14 @@ +// dont remove me +var React = require('React'); + +class ComponentWithOnlyPureRenderMixin extends React.PureComponent { + state = { + counter: this.props.initialNumber + 1, + }; + + render() { + return ( +
{this.state.counter}
+ ); + } +} diff --git a/transforms/__testfixtures__/class-pure-mixin2.input.js b/transforms/__testfixtures__/class-pure-mixin2.input.js new file mode 100644 index 00000000..02734881 --- /dev/null +++ b/transforms/__testfixtures__/class-pure-mixin2.input.js @@ -0,0 +1,27 @@ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + * + * @providesModule Bar + * @typechecks + * @flow + */ +import WhateverYouCallIt from 'react-addons-pure-render-mixin'; +import React from 'React'; +import dontPruneMe from 'foobar'; + +var ComponentWithOnlyPureRenderMixin = React.createClass({ + mixins: [WhateverYouCallIt], + + getInitialState: function() { + return { + counter: this.props.initialNumber + 1, + }; + }, + + render: function() { + dontPruneMe(); + return ( +
{this.state.counter}
+ ); + }, +}); diff --git a/transforms/__testfixtures__/class-pure-mixin2.output.js b/transforms/__testfixtures__/class-pure-mixin2.output.js new file mode 100644 index 00000000..91b13c6a --- /dev/null +++ b/transforms/__testfixtures__/class-pure-mixin2.output.js @@ -0,0 +1,22 @@ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + * + * @providesModule Bar + * @typechecks + * @flow + */ +import React from 'React'; +import dontPruneMe from 'foobar'; + +class ComponentWithOnlyPureRenderMixin extends React.PureComponent { + state = { + counter: this.props.initialNumber + 1, + }; + + render() { + dontPruneMe(); + return ( +
{this.state.counter}
+ ); + } +} diff --git a/transforms/__testfixtures__/class-pure-mixin3.input.js b/transforms/__testfixtures__/class-pure-mixin3.input.js new file mode 100644 index 00000000..32592bf2 --- /dev/null +++ b/transforms/__testfixtures__/class-pure-mixin3.input.js @@ -0,0 +1,20 @@ +// for this file we disable the `pure-component` option +// so the output should be just nothing +var React = require('React'); +var ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin'); + +var ComponentWithOnlyPureRenderMixin = React.createClass({ + mixins: [ReactComponentWithPureRenderMixin], + + getInitialState: function() { + return { + counter: this.props.initialNumber + 1, + }; + }, + + render: function() { + return ( +
{this.state.counter}
+ ); + }, +}); diff --git a/transforms/__testfixtures__/class-pure-mixin3.output.js b/transforms/__testfixtures__/class-pure-mixin3.output.js new file mode 100644 index 00000000..e69de29b diff --git a/transforms/__testfixtures__/class-pure-mixin4.input.js b/transforms/__testfixtures__/class-pure-mixin4.input.js new file mode 100644 index 00000000..6cc257c7 --- /dev/null +++ b/transforms/__testfixtures__/class-pure-mixin4.input.js @@ -0,0 +1,34 @@ +/** + * Copyright 2004-present Facebook. All rights reserved. + * + * @providesModule HelloGuys + * @fbt {"foo": "bar"} + * @flow + * @typechecks + */ + +'use strict'; + +const React = require('React'); +const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin'); + +/** + * just a description here + */ +const HelloGuys = React.createClass({ + mixins: [ + ReactComponentWithPureRenderMixin, + ], + + propTypes: {}, + + render(): ReactElement { + return ( +
+ wassup +
+ ); + }, +}); + +module.exports = HelloGuys; diff --git a/transforms/__testfixtures__/class-pure-mixin4.output.js b/transforms/__testfixtures__/class-pure-mixin4.output.js new file mode 100644 index 00000000..0bc2f737 --- /dev/null +++ b/transforms/__testfixtures__/class-pure-mixin4.output.js @@ -0,0 +1,30 @@ +/** + * Copyright 2004-present Facebook. All rights reserved. + * + * @providesModule HelloGuys + * @fbt {"foo": "bar"} + * @flow + * @typechecks + */ + +'use strict'; + +const React = require('React'); + +/** + * just a description here + */ +class HelloGuys extends React.PureComponent { + props: {}; + static propTypes = {}; + + render(): ReactElement { + return ( +
+ wassup +
+ ); + } +} + +module.exports = HelloGuys; diff --git a/transforms/__testfixtures__/class-test2.input.js b/transforms/__testfixtures__/class-test2.input.js new file mode 100644 index 00000000..ae54847f --- /dev/null +++ b/transforms/__testfixtures__/class-test2.input.js @@ -0,0 +1,116 @@ +'use strict'; + +var React = require('React'); +var ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin'); +var FooBarMixin = require('FooBarMixin'); + +var ComponentWithNonSimpleInitialState = React.createClass({ + statics: { + iDontKnowWhyYouNeedThis: true, // but comment it + foo: 'bar', + dontBindMe: function(count: number): any { + return this; + }, + }, + + getInitialState: function() { + return { + counter: this.props.initialNumber + 1, + }; + }, + + render: function() { + return ( +
{this.state.counter}
+ ); + }, +}); + +// Comment +module.exports = React.createClass({ + propTypes: { + foo: React.PropTypes.bool, + }, + + getDefaultProps: function() { + return { + foo: 12, + }; + }, + + getInitialState: function() { // non-simple getInitialState + var data = 'bar'; + return { + bar: data, + }; + }, + + render: function() { + return
; + }, +}); + +var ComponentWithInconvertibleMixins = React.createClass({ + mixins: [ReactComponentWithPureRenderMixin, FooBarMixin], + + getInitialState: function() { + return { + counter: this.props.initialNumber + 1, + }; + }, + + render: function() { + return ( +
{this.state.counter}
+ ); + }, +}); + +var listOfInconvertibleMixins = [ReactComponentWithPureRenderMixin, FooBarMixin]; + +var ComponentWithInconvertibleMixins2 = React.createClass({ + mixins: listOfInconvertibleMixins, + + getInitialState: function() { + return { + counter: this.props.initialNumber + 1, + }; + }, + + render: function() { + return ( +
{this.state.counter}
+ ); + }, +}); + +// taken from https://facebook.github.io/react/docs/context.html#updating-context +var MediaQuery = React.createClass({ + childContextTypes: { + type: React.PropTypes.string, + }, + + getInitialState: function() { + return {type:'desktop'}; + }, + + getChildContext: function() { + return {type: this.state.type}; + }, + + componentDidMount: function() { + const checkMediaQuery = () => { + const type = window.matchMedia('(min-width: 1025px)').matches ? 'desktop' : 'mobile'; + if (type !== this.state.type) { + this.setState({type}); + } + }; + + window.addEventListener('resize', checkMediaQuery); + checkMediaQuery(); + }, + + render: function() { + return this.props.children; + }, +}); diff --git a/transforms/__testfixtures__/class-test2.js b/transforms/__testfixtures__/class-test2.js deleted file mode 100644 index b0f04327..00000000 --- a/transforms/__testfixtures__/class-test2.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; - -var React = require('React'); - -// Comment -module.exports = React.createClass({ - propTypes: { - foo: React.PropTypes.bool, - }, - - getInitialState: function() { - return { - foo: 'bar', - }; - }, - - render: function() { - return
; - }, -}); diff --git a/transforms/__testfixtures__/class-test2.output.js b/transforms/__testfixtures__/class-test2.output.js index 68803e41..d6253f1b 100644 --- a/transforms/__testfixtures__/class-test2.output.js +++ b/transforms/__testfixtures__/class-test2.output.js @@ -1,14 +1,45 @@ 'use strict'; var React = require('React'); +var ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin'); +var FooBarMixin = require('FooBarMixin'); + +class ComponentWithNonSimpleInitialState extends React.Component { + static iDontKnowWhyYouNeedThis = true; // but comment it + static foo = 'bar'; + + static dontBindMe(count: number): any { + return this; + } + + state = { + counter: this.props.initialNumber + 1, + }; + + render() { + return ( +
{this.state.counter}
+ ); + } +} // Comment module.exports = class extends React.Component { - constructor(props, context) { - super(props, context); + static propTypes = { + foo: React.PropTypes.bool, + }; + + static defaultProps = { + foo: 12, + }; + + constructor(props) { + super(props); + // non-simple getInitialState + var data = 'bar'; this.state = { - foo: 'bar', + bar: data, }; } @@ -17,6 +48,65 @@ module.exports = class extends React.Component { } }; -module.exports.propTypes = { - foo: React.PropTypes.bool, -}; +var ComponentWithInconvertibleMixins = React.createClass({ + mixins: [ReactComponentWithPureRenderMixin, FooBarMixin], + + getInitialState: function() { + return { + counter: this.props.initialNumber + 1, + }; + }, + + render: function() { + return ( +
{this.state.counter}
+ ); + }, +}); + +var listOfInconvertibleMixins = [ReactComponentWithPureRenderMixin, FooBarMixin]; + +var ComponentWithInconvertibleMixins2 = React.createClass({ + mixins: listOfInconvertibleMixins, + + getInitialState: function() { + return { + counter: this.props.initialNumber + 1, + }; + }, + + render: function() { + return ( +
{this.state.counter}
+ ); + }, +}); + +// taken from https://facebook.github.io/react/docs/context.html#updating-context +class MediaQuery extends React.Component { + static childContextTypes = { + type: React.PropTypes.string, + }; + + state = {type:'desktop'}; + + getChildContext() { + return {type: this.state.type}; + } + + componentDidMount() { + const checkMediaQuery = () => { + const type = window.matchMedia('(min-width: 1025px)').matches ? 'desktop' : 'mobile'; + if (type !== this.state.type) { + this.setState({type}); + } + }; + + window.addEventListener('resize', checkMediaQuery); + checkMediaQuery(); + } + + render() { + return this.props.children; + } +} diff --git a/transforms/__testfixtures__/class-top-comment.input.js b/transforms/__testfixtures__/class-top-comment.input.js new file mode 100644 index 00000000..05b4c011 --- /dev/null +++ b/transforms/__testfixtures__/class-top-comment.input.js @@ -0,0 +1,25 @@ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + * + * @providesModule FooBar + * @typechecks + * @flow + */ +var ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin'); +var React = require('React'); + +var ComponentWithOnlyPureRenderMixin = React.createClass({ + mixins: [ReactComponentWithPureRenderMixin], + + getInitialState: function() { + return { + counter: this.props.initialNumber + 1, + }; + }, + + render: function() { + return ( +
{this.state.counter}
+ ); + }, +}); diff --git a/transforms/__testfixtures__/class-top-comment.output.js b/transforms/__testfixtures__/class-top-comment.output.js new file mode 100644 index 00000000..f77f052b --- /dev/null +++ b/transforms/__testfixtures__/class-top-comment.output.js @@ -0,0 +1,20 @@ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + * + * @providesModule FooBar + * @typechecks + * @flow + */ +var React = require('React'); + +class ComponentWithOnlyPureRenderMixin extends React.PureComponent { + state = { + counter: this.props.initialNumber + 1, + }; + + render() { + return ( +
{this.state.counter}
+ ); + } +} diff --git a/transforms/__testfixtures__/class.input.js b/transforms/__testfixtures__/class.input.js index a79ff180..96a0d9dc 100644 --- a/transforms/__testfixtures__/class.input.js +++ b/transforms/__testfixtures__/class.input.js @@ -5,28 +5,13 @@ var Relay = require('Relay'); var Image = require('Image.react'); -/* - * Multiline - */ -var MyComponent = React.createClass({ - getInitialState: function() { - var x = this.props.foo; - return { - heyoo: 23, - }; - }, - - foo: function() { - this.setState({heyoo: 24}); - }, -}); - // Class comment var MyComponent2 = React.createClass({ - getDefaultProps: function() { + getDefaultProps: function(): Object { return {a: 1}; }, - foo: function() { + foo: function(): void { + const x = (a: Object, b: string): void => {}; // This code cannot be parsed by Babel v5 pass(this.foo); this.forceUpdate(); }, @@ -35,7 +20,7 @@ var MyComponent2 = React.createClass({ var MyComponent3 = React.createClass({ statics: { someThing: 10, - foo: function() {}, + funcThatDoesNothing: function(): void {}, }, propTypes: { highlightEntities: React.PropTypes.bool, @@ -47,7 +32,7 @@ var MyComponent3 = React.createClass({ }, getDefaultProps: function() { - foo(); + unboundFunc(); return { linkifyEntities: true, highlightEntities: false, @@ -61,11 +46,12 @@ var MyComponent3 = React.createClass({ }; }, - _renderText: function(text) { + // comment here + _renderText: function(text: string): ReactElement { // say something return ; }, - _renderImageRange: function(text, range) { + _renderImageRange: function(text: string, range): ReactElement { var image = range.image; if (image) { return ( @@ -80,13 +66,13 @@ var MyComponent3 = React.createClass({ }, autobindMe: function() {}, - dontAutobindMe: function() {}, + okBindMe: function(): number { return 12; }, // Function comment - _renderRange: function(text, range) { + _renderRange: function(text: string, range, bla: Promise): ReactElement { var self = this; - self.dontAutobindMe(); + self.okBindMe(); call(self.autobindMe); var type = rage.type; @@ -132,3 +118,97 @@ module.exports = Relay.createContainer(MyComponent, { me: Relay.graphql`this is not graphql`, }, }); + +var MyComponent5 = React.createClass({ + getDefaultProps: function() { + return { + thisIs: true, + andThisIs: false, + }; + }, + + statics: {}, + + getInitialState: function() { + return { + todos: [], + }; + }, + + renderTodo: function(): ReactElement { + return ( +
+ {this.state.todos.map((item) =>

{item.text}

)} +
+ ); + }, + + render: function() { + return ( +
+

TODOs

+ {this.renderTodo()} +
+ ); + }, +}); + +var GoodName = React.createClass({ + displayName: 'GoodName', + render() { + return
; + }, +}); + +var SingleArgArrowFunction = React.createClass({ + formatInt: function(/*number*/ num) /*string*/ { + return 'foobar'; + }, + render() { + return
; + }, +}); + +var mySpec = {}; +var NotAnObjectLiteral = React.createClass(mySpec); + +var WaitWhat = React.createClass(); + +var HasSpreadArgs = React.createClass({ + _helper: function(...args) { + return args; + }, + _helper2: function(a, b, c, ...args) { + return args.concat(a); + }, + _helper3: function(a: number, ...args: Array) { + return args.concat('' + a); + }, + render() { + return
; + }, +}); + +var HasDefaultArgs = React.createClass({ + _helper: function(foo = 12) { + return foo; + }, + _helper2: function({foo: number = 12, abc}, bar: string = 'hey', ...args: Array) { + return args.concat(foo, bar); + }, + render() { + return
; + }, +}); + +var ManyArgs = React.createClass({ + _helper: function(foo = 12) { + return foo; + }, + _helper2: function({foo: number = 12, abc}, bar: string = 'hey', x: number, y: number, ...args: Array) { + return args.concat(foo, bar); + }, + render() { + return
; + }, +}); diff --git a/transforms/__testfixtures__/class.output.js b/transforms/__testfixtures__/class.output.js index 6ffb8a2f..150c68d6 100644 --- a/transforms/__testfixtures__/class.output.js +++ b/transforms/__testfixtures__/class.output.js @@ -5,45 +5,40 @@ var Relay = require('Relay'); var Image = require('Image.react'); -/* - * Multiline - */ -class MyComponent extends React.Component { - constructor(props, context) { - super(props, context); - var x = props.foo; - - this.state = { - heyoo: 23, - }; - } - - foo() { - this.setState({heyoo: 24}); - } -} - // Class comment class MyComponent2 extends React.Component { - constructor(props, context) { - super(props, context); - this.foo = this.foo.bind(this); - } + static defaultProps = {a: 1}; - foo() { + foo = (): void => { + const x = (a: Object, b: string): void => {}; // This code cannot be parsed by Babel v5 pass(this.foo); this.forceUpdate(); - } + }; } -MyComponent2.defaultProps = {a: 1}; - class MyComponent3 extends React.Component { - constructor(props, context) { - super(props, context); - this._renderRange = this._renderRange.bind(this); - this._renderText = this._renderText.bind(this); - this.autobindMe = this.autobindMe.bind(this); + static someThing = 10; + static funcThatDoesNothing(): void {} + + static propTypes = { + highlightEntities: React.PropTypes.bool, + linkifyEntities: React.PropTypes.bool, + text: React.PropTypes.shape({ + text: React.PropTypes.string, + ranges: React.PropTypes.array, + }).isRequired, + }; + + static defaultProps = function() { + unboundFunc(); + return { + linkifyEntities: true, + highlightEntities: false, + }; + }(); + + constructor(props) { + super(props); props.foo(); this.state = { @@ -51,11 +46,12 @@ class MyComponent3 extends React.Component { }; } - _renderText(text) { + // comment here + _renderText = (text: string): ReactElement => { // say something return ; - } + }; - _renderImageRange(text, range) { + _renderImageRange = (text: string, range): ReactElement => { var image = range.image; if (image) { return ( @@ -67,16 +63,16 @@ class MyComponent3 extends React.Component { ); } return null; - } + }; - autobindMe() {} - dontAutobindMe() {} + autobindMe = () => {}; + okBindMe = (): number => { return 12; }; // Function comment - _renderRange(text, range) { + _renderRange = (text: string, range, bla: Promise): ReactElement => { var self = this; - self.dontAutobindMe(); + self.okBindMe(); call(self.autobindMe); var type = rage.type; @@ -96,7 +92,7 @@ class MyComponent3 extends React.Component { } return text; - } + }; /* This is a comment */ render() { @@ -112,27 +108,6 @@ class MyComponent3 extends React.Component { } } -MyComponent3.defaultProps = function() { - foo(); - return { - linkifyEntities: true, - highlightEntities: false, - }; -}(); - -MyComponent3.foo = function() {}; - -MyComponent3.propTypes = { - highlightEntities: React.PropTypes.bool, - linkifyEntities: React.PropTypes.bool, - text: React.PropTypes.shape({ - text: React.PropTypes.string, - ranges: React.PropTypes.array, - }).isRequired, -}; - -MyComponent3.someThing = 10; - var MyComponent4 = React.createClass({ foo: callMeMaybe(), render: function() {}, @@ -143,3 +118,106 @@ module.exports = Relay.createContainer(MyComponent, { me: Relay.graphql`this is not graphql`, }, }); + +class MyComponent5 extends React.Component { + static defaultProps = { + thisIs: true, + andThisIs: false, + }; + + state = { + todos: [], + }; + + renderTodo = (): ReactElement => { + return ( +
+ {this.state.todos.map((item) =>

{item.text}

)} +
+ ); + }; + + render() { + return ( +
+

TODOs

+ {this.renderTodo()} +
+ ); + } +} + +class GoodName extends React.Component { + static displayName = 'GoodName'; + + render() { + return
; + } +} + +class SingleArgArrowFunction extends React.Component { + formatInt = (/*number*/ num) => /*string*/ { + return 'foobar'; + }; + + render() { + return
; + } +} + +var mySpec = {}; +var NotAnObjectLiteral = React.createClass(mySpec); + +var WaitWhat = React.createClass(); + +class HasSpreadArgs extends React.Component { + _helper = (...args) => { + return args; + }; + + _helper2 = (a, b, c, ...args) => { + return args.concat(a); + }; + + _helper3 = (a: number, ...args: Array) => { + return args.concat('' + a); + }; + + render() { + return
; + } +} + +class HasDefaultArgs extends React.Component { + _helper = (foo = 12) => { + return foo; + }; + + _helper2 = ({foo: number = 12, abc}, bar: string = 'hey', ...args: Array) => { + return args.concat(foo, bar); + }; + + render() { + return
; + } +} + +class ManyArgs extends React.Component { + _helper = (foo = 12) => { + return foo; + }; + + _helper2 = ( + {foo: number = 12, abc}, + bar: string = 'hey', + x: number, + y: number, + ...args: Array + ) => { + return args.concat(foo, bar); + }; + + render() { + return
; + } +} diff --git a/transforms/__testfixtures__/export-default-class.output.js b/transforms/__testfixtures__/export-default-class.output.js index 21bc58c9..dec5942a 100644 --- a/transforms/__testfixtures__/export-default-class.output.js +++ b/transforms/__testfixtures__/export-default-class.output.js @@ -5,18 +5,14 @@ import React from 'React'; export default class extends React.Component { - constructor(props, context) { - super(props, context); - - this.state = { - foo: 'bar', - }; - } - static propTypes = { foo: React.PropTypes.string, }; + state = { + foo: 'bar', + }; + render() { return
; } diff --git a/transforms/__tests__/class-test.js b/transforms/__tests__/class-test.js index 02355b38..2442ca95 100644 --- a/transforms/__tests__/class-test.js +++ b/transforms/__tests__/class-test.js @@ -11,5 +11,46 @@ 'use strict'; const defineTest = require('jscodeshift/dist/testUtils').defineTest; + +const pureMixinAlternativeOption = { + 'mixin-module-name': 'ReactComponentWithPureRenderMixin', + 'pure-component': true, +}; + +const enableFlowOption = {flow: true}; + defineTest(__dirname, 'class'); -defineTest(__dirname, 'class', null, 'export-default-class'); +defineTest(__dirname, 'class', enableFlowOption, 'class-anonymous'); +defineTest(__dirname, 'class', enableFlowOption, 'class-anonymous2'); +defineTest(__dirname, 'class', pureMixinAlternativeOption, 'class-test2'); +defineTest(__dirname, 'class', enableFlowOption, 'export-default-class'); +defineTest(__dirname, 'class', pureMixinAlternativeOption, 'class-pure-mixin1'); +defineTest(__dirname, 'class', { + ...enableFlowOption, + 'pure-component': true, +}, 'class-pure-mixin2'); +defineTest(__dirname, 'class', null, 'class-pure-mixin3'); +defineTest(__dirname, 'class', { + ...pureMixinAlternativeOption, + ...enableFlowOption, +}, 'class-pure-mixin4'); +defineTest(__dirname, 'class', { + ...pureMixinAlternativeOption, + ...enableFlowOption, +}, 'class-top-comment'); +defineTest(__dirname, 'class', { + ...pureMixinAlternativeOption, + ...enableFlowOption, +}, 'class-access-default-props1'); +defineTest(__dirname, 'class', enableFlowOption, 'class-initial-state'); +defineTest(__dirname, 'class', enableFlowOption, 'class-property-field'); +defineTest(__dirname, 'class', enableFlowOption, 'class-flow1'); +defineTest(__dirname, 'class', enableFlowOption, 'class-flow2'); +defineTest(__dirname, 'class', enableFlowOption, 'class-flow3'); +defineTest(__dirname, 'class', enableFlowOption, 'class-flow4'); +defineTest(__dirname, 'class', enableFlowOption, 'class-flow5'); +defineTest(__dirname, 'class', enableFlowOption, 'class-flow6'); +defineTest(__dirname, 'class', { + ...enableFlowOption, + 'remove-runtime-proptypes': true, +}, 'class-flow7'); diff --git a/transforms/class.js b/transforms/class.js index 4ddff794..6e1ee901 100644 --- a/transforms/class.js +++ b/transforms/class.js @@ -17,9 +17,18 @@ module.exports = (file, api, options) => { const ReactUtils = require('./utils/ReactUtils')(j); const printOptions = - options.printOptions || {quote: 'single', trailingComma: true}; + options.printOptions || { + quote: 'single', + trailingComma: true, + flowObjectCommas: true, + arrowParensAlways: true, + }; + const root = j(file.source); + // retain top comments + const { comments: topComments } = root.find(j.Program).get('body', 0).node; + const AUTOBIND_IGNORE_KEYS = { componentDidMount: true, componentDidUpdate: true, @@ -27,6 +36,7 @@ module.exports = (file, api, options) => { componentWillMount: true, componentWillUpdate: true, componentWillUnmount: true, + getChildContext: true, getDefaultProps: true, getInitialState: true, render: true, @@ -45,6 +55,9 @@ module.exports = (file, api, options) => { 'setProps', ]; + const PURE_MIXIN_MODULE_NAME = options['mixin-module-name'] || + 'react-addons-pure-render-mixin'; + const STATIC_KEY = 'statics'; const STATIC_KEYS = { @@ -54,6 +67,90 @@ module.exports = (file, api, options) => { propTypes: true, }; + const MIXIN_KEY = 'mixins'; + + let shouldTransformFlow = false; + + if (options['flow']) { + const programBodyNode = root.find(j.Program).get('body', 0).node; + if (programBodyNode && programBodyNode.comments) { + programBodyNode.comments.forEach(node => { + if (node.value.indexOf('@flow') !== -1) { + shouldTransformFlow = true; + } + }); + } + } + + // --------------------------------------------------------------------------- + // Helpers + const createFindPropFn = prop => property => ( + property.key && + property.key.type === 'Identifier' && + property.key.name === prop + ); + + const filterDefaultPropsField = node => + createFindPropFn(DEFAULT_PROPS_FIELD)(node); + + const filterGetInitialStateField = node => + createFindPropFn(GET_INITIAL_STATE_FIELD)(node); + + const findGetInitialState = specPath => + specPath.properties.find(createFindPropFn(GET_INITIAL_STATE_FIELD)); + + const withComments = (to, from) => { + to.comments = from.comments; + return to; + }; + + const isPrimExpression = node => ( + node.type === 'Literal' || ( // NOTE this might change in babylon v6 + node.type === 'Identifier' && + node.name === 'undefined' + )); + + const isFunctionExpression = node => ( + node.key && + node.key.type === 'Identifier' && + node.value && + node.value.type === 'FunctionExpression' + ); + + const isPrimProperty = prop => ( + prop.key && + prop.key.type === 'Identifier' && + prop.value && + isPrimExpression(prop.value) + ); + + const isPrimPropertyWithTypeAnnotation = prop => ( + prop.key && + prop.key.type === 'Identifier' && + prop.value && + prop.value.type === 'TypeCastExpression' && + isPrimExpression(prop.value.expression) + ); + + const hasSingleReturnStatementWithObject = value => ( + value.type === 'FunctionExpression' && + value.body && + value.body.type === 'BlockStatement' && + value.body.body && + value.body.body.length === 1 && + value.body.body[0].type === 'ReturnStatement' && + value.body.body[0].argument && + value.body.body[0].argument.type === 'ObjectExpression' + ); + + const isInitialStateLiftable = getInitialState => { + if (!getInitialState || !(getInitialState.value)) { + return true; + } + + return hasSingleReturnStatementWithObject(getInitialState.value); + }; + // --------------------------------------------------------------------------- // Checks if the module uses mixins or accesses deprecated APIs. const checkDeprecatedAPICalls = classPath => @@ -65,10 +162,10 @@ module.exports = (file, api, options) => { 0 ) > 0; - const callsDeprecatedAPIs = classPath => { + const hasNoCallsToDeprecatedAPIs = classPath => { if (checkDeprecatedAPICalls(classPath)) { - console.log( - file.path + ': `' + ReactUtils.getComponentName(classPath) + '` ' + + console.warn( + file.path + ': `' + ReactUtils.directlyGetComponentName(classPath) + '` ' + 'was skipped because of deprecated API calls. Remove calls to ' + DEPRECATED_APIS.join(', ') + ' in your React component and re-run ' + 'this script.' @@ -78,15 +175,125 @@ module.exports = (file, api, options) => { return true; }; + const hasNoRefsToAPIsThatWillBeRemoved = classPath => { + const hasInvalidCalls = ( + j(classPath).find(j.MemberExpression, { + object: {type: 'ThisExpression'}, + property: {name: DEFAULT_PROPS_FIELD}, + }).size() > 0 || + j(classPath).find(j.MemberExpression, { + object: {type: 'ThisExpression'}, + property: {name: GET_INITIAL_STATE_FIELD}, + }).size() > 0 + ); + + if (hasInvalidCalls) { + console.warn( + file.path + ': `' + ReactUtils.directlyGetComponentName(classPath) + '` ' + + 'was skipped because of API calls that will be removed. Remove calls to `' + + DEFAULT_PROPS_FIELD + '` and/or `' + GET_INITIAL_STATE_FIELD + + '` in your React component and re-run this script.' + ); + return false; + } + return true; + }; + + const doesNotUseArguments = classPath => { + const hasArguments = ( + j(classPath).find(j.Identifier, {name: 'arguments'}).size() > 0 + ); + if (hasArguments) { + console.warn( + file.path + ': `' + ReactUtils.directlyGetComponentName(classPath) + '` ' + + 'was skipped because `arguments` was found in your functions. ' + + 'Arrow functions do not expose an `arguments` object; ' + + 'consider changing to use ES6 spread operator and re-run this script.' + ); + return false; + } + return true; + }; + + const isGetInitialStateConstructorSafe = getInitialState => { + if (!getInitialState) { + return true; + } + + const collection = j(getInitialState); + let result = true; + + const propsVarDeclarationCount = collection.find(j.VariableDeclarator, { + id: {name: 'props'}, + }).size(); + + const contextVarDeclarationCount = collection.find(j.VariableDeclarator, { + id: {name: 'context'}, + }).size(); + + if ( + propsVarDeclarationCount && + propsVarDeclarationCount !== collection.find(j.VariableDeclarator, { + id: {name: 'props'}, + init: { + type: 'MemberExpression', + object: {type: 'ThisExpression'}, + property: {name: 'props'}, + } + }).size() + ) { + result = false; + } + + if ( + contextVarDeclarationCount && + contextVarDeclarationCount !== collection.find(j.VariableDeclarator, { + id: {name: 'context'}, + init: { + type: 'MemberExpression', + object: {type: 'ThisExpression'}, + property: {name: 'context'}, + } + }).size() + ) { + result = false; + } + + return result; + }; + + const isInitialStateConvertible = classPath => { + const specPath = ReactUtils.directlyGetCreateClassSpec(classPath); + if (!specPath) { + return false; + } + const result = isGetInitialStateConstructorSafe(findGetInitialState(specPath)); + if (!result) { + console.warn( + file.path + ': `' + ReactUtils.directlyGetComponentName(classPath) + '` ' + + 'was skipped because of potential shadowing issues were found in ' + + 'the React component. Rename variable declarations of `props` and/or `context` ' + + 'in your `getInitialState` and re-run this script.' + ); + } + return result; + }; + const canConvertToClass = classPath => { - const specPath = ReactUtils.getReactCreateClassSpec(classPath); + const specPath = ReactUtils.directlyGetCreateClassSpec(classPath); + if (!specPath) { + return false; + } const invalidProperties = specPath.properties.filter(prop => ( !prop.key.name || ( !STATIC_KEYS[prop.key.name] && STATIC_KEY != prop.key.name && !filterDefaultPropsField(prop) && !filterGetInitialStateField(prop) && - !isFunctionExpression(prop) + !isFunctionExpression(prop) && + !isPrimProperty(prop) && + !isPrimPropertyWithTypeAnnotation(prop) && + MIXIN_KEY != prop.key.name ) )); @@ -94,8 +301,8 @@ module.exports = (file, api, options) => { const invalidText = invalidProperties .map(prop => prop.key.name ? prop.key.name : prop.key) .join(', '); - console.log( - file.path + ': `' + ReactUtils.getComponentName(classPath) + '` ' + + console.warn( + file.path + ': `' + ReactUtils.directlyGetComponentName(classPath) + '` ' + 'was skipped because of invalid field(s) `' + invalidText + '` on ' + 'the React component. Remove any right-hand-side expressions that ' + 'are not simple, like: `componentWillUpdate: createWillUpdate()` or ' + @@ -105,138 +312,110 @@ module.exports = (file, api, options) => { return !invalidProperties.length; }; - const hasMixins = classPath => { - if (ReactUtils.hasMixins(classPath)) { - console.log( - file.path + ': `' + ReactUtils.getComponentName(classPath) + '` ' + - 'was skipped because of mixins.' - ); + const areMixinsConvertible = (mixinIdentifierNames, classPath) => { + if ( + ReactUtils.directlyHasMixinsField(classPath) && + !ReactUtils.directlyHasSpecificMixins(classPath, mixinIdentifierNames) + ) { return false; } return true; }; // --------------------------------------------------------------------------- - // Helpers - const createFindPropFn = prop => property => ( - property.key && - property.key.type === 'Identifier' && - property.key.name === prop - ); - - const filterDefaultPropsField = node => - createFindPropFn(DEFAULT_PROPS_FIELD)(node); - - const filterGetInitialStateField = node => - createFindPropFn(GET_INITIAL_STATE_FIELD)(node); - - const findGetDefaultProps = specPath => - specPath.properties.find(createFindPropFn(DEFAULT_PROPS_FIELD)); - - const findGetInitialState = specPath => - specPath.properties.find(createFindPropFn(GET_INITIAL_STATE_FIELD)); - - const withComments = (to, from) => { - to.comments = from.comments; - return to; + // Collectors + const pickReturnValueOrCreateIIFE = value => { + if (hasSingleReturnStatementWithObject(value)) { + return value.body.body[0].argument; + } else { + return j.callExpression( + value, + [] + ); + } }; - // --------------------------------------------------------------------------- - // Collectors - const isFunctionExpression = node => ( - node.key && - node.key.type === 'Identifier' && - node.value && - node.value.type === 'FunctionExpression' - ); + const createDefaultProps = prop => + withComments( + j.property( + 'init', + j.identifier(DEFAULT_PROPS_KEY), + pickReturnValueOrCreateIIFE(prop.value) + ), + prop + ); + // Collects `childContextTypes`, `contextTypes`, `displayName`, and `propTypes`; + // simplifies `getDefaultProps` or converts it to an IIFE; + // and collects everything else in the `statics` property object. const collectStatics = specPath => { - const statics = specPath.properties.find(createFindPropFn('statics')); - const staticsObject = - (statics && statics.value && statics.value.properties) || []; - - const getDefaultProps = findGetDefaultProps(specPath); - if (getDefaultProps) { - staticsObject.push(createDefaultProps(getDefaultProps)); + const result = []; + + for (let i = 0; i < specPath.properties.length; i++) { + const property = specPath.properties[i]; + if (createFindPropFn('statics')(property) && property.value && property.value.properties) { + result.push(...property.value.properties); + } else if (createFindPropFn(DEFAULT_PROPS_FIELD)(property)) { + result.push(createDefaultProps(property)); + } else if (property.key && STATIC_KEYS[property.key.name]) { + result.push(property); + } } - return ( - staticsObject.concat(specPath.properties.filter(property => - property.key && STATIC_KEYS[property.key.name] - )) - .sort((a, b) => a.key.name < b.key.name) - ); + return result; }; - const collectFunctions = specPath => specPath.properties + const collectNonStaticProperties = specPath => specPath.properties .filter(prop => !(filterDefaultPropsField(prop) || filterGetInitialStateField(prop)) ) - .filter(isFunctionExpression); - - const findAutobindNamesFor = (subtree, fnNames, literalOrIdentifier) => { - const node = literalOrIdentifier; - const autobindNames = {}; - - j(subtree) - .find(j.MemberExpression, { - object: node.name ? { - type: node.type, - name: node.name, - } : {type: node.type}, - property: { - type: 'Identifier', - }, - }) - .filter(path => path.value.property && fnNames[path.value.property.name]) - .filter(path => { - const call = path.parent.value; - return !( - call && - call.type === 'CallExpression' && - call.callee.type === 'MemberExpression' && - call.callee.object.type === node.type && - call.callee.object.name === node.name && - call.callee.property.type === 'Identifier' && - call.callee.property.name === path.value.property.name - ); - }) - .forEach(path => autobindNames[path.value.property.name] = true); - - return Object.keys(autobindNames); - }; + .filter(prop => (!STATIC_KEYS[prop.key.name]) && prop.key.name !== STATIC_KEY) + .filter(prop => + isFunctionExpression(prop) || + isPrimPropertyWithTypeAnnotation(prop) || + isPrimProperty(prop) + ); - const collectAutoBindFunctions = (functions, classPath) => { - const fnNames = {}; - functions - .filter(fn => !AUTOBIND_IGNORE_KEYS[fn.key.name]) - .forEach(fn => fnNames[fn.key.name] = true); + const findRequirePathAndBinding = (moduleName) => { + let result = null; - const autobindNames = {}; - const add = name => autobindNames[name] = true; + const requireCall = root.find(j.VariableDeclarator, { + id: {type: 'Identifier'}, + init: { + callee: {name: 'require'}, + arguments: [{value: moduleName}], + }, + }); - // Find `this.` - findAutobindNamesFor(classPath, fnNames, j.thisExpression()).forEach(add); + const importStatement = root.find(j.ImportDeclaration, { + source: { + value: moduleName, + }, + }); - // Find `self.` if `self = this` - j(classPath) - .findVariableDeclarators() - .filter(path => ( - path.value.id.type === 'Identifier' && - path.value.init && - path.value.init.type === 'ThisExpression' - )) - .forEach(path => - findAutobindNamesFor( - j(path).closest(j.FunctionExpression).get(), - fnNames, - path.value.id - ).forEach(add) - ); + if (importStatement.size()) { + importStatement.forEach(path => { + result = { + path, + binding: path.value.specifiers[0].id.name, + type: 'import', + }; + }); + } else if (requireCall.size()) { + requireCall.forEach(path => { + result = { + path, + binding: path.value.id.name, + type: 'require', + }; + }); + } - return Object.keys(autobindNames).sort(); + return result; }; + const pureRenderMixinPathAndBinding = findRequirePathAndBinding(PURE_MIXIN_MODULE_NAME); + // --------------------------------------------------------------------------- // Boom! const createMethodDefinition = fn => @@ -246,54 +425,72 @@ module.exports = (file, api, options) => { fn.value ), fn); - const createBindAssignment = name => - j.expressionStatement( - j.assignmentExpression( - '=', - j.memberExpression( - j.thisExpression(), - j.identifier(name), - false - ), - j.callExpression( - j.memberExpression( - j.memberExpression( - j.thisExpression(), - j.identifier(name), - false - ), - j.identifier('bind'), - false - ), - [j.thisExpression()] - ) - ) - ); + const updatePropsAndContextAccess = getInitialState => { + const collection = j(getInitialState); + + collection.find(j.MemberExpression, { + object: { + type: 'ThisExpression', + }, + property: { + type: 'Identifier', + name: 'props', + }, + }).forEach(path => j(path).replaceWith(j.identifier('props'))); + + collection.find(j.MemberExpression, { + object: { + type: 'ThisExpression', + }, + property: { + type: 'Identifier', + name: 'context', + }, + }).forEach(path => j(path).replaceWith(j.identifier('context'))); + }; - const updatePropsAccess = getInitialState => - getInitialState ? - j(getInitialState) - .find(j.MemberExpression, { - object: { - type: 'ThisExpression', - }, - property: { - type: 'Identifier', - name: 'props', - }, - }) - .forEach(path => j(path).replaceWith(j.identifier('props'))) - .size() > 0 : - false; const inlineGetInitialState = getInitialState => { - if (!getInitialState) { - return []; - } + const functionExpressionCollection = j(getInitialState.value); + + // at this point if there exists bindings like `const props = ...`, we + // already know the RHS must be `this.props` (see `isGetInitialStateConstructorSafe`) + // so it's safe to just remove them + functionExpressionCollection.find(j.VariableDeclarator, {id: {name: 'props'}}) + .forEach(path => j(path).remove()); + + functionExpressionCollection.find(j.VariableDeclarator, {id: {name: 'context'}}) + .forEach(path => j(path).remove()); - return getInitialState.value.body.body.map(statement => { - if (statement.type === 'ReturnStatement') { - return j.expressionStatement( + return functionExpressionCollection + .find(j.ReturnStatement) + .filter(path => { + // filter out inner function declarations here (helper functions, promises, etc.). + const mainBodyCollection = j(getInitialState.value.body); + return ( + mainBodyCollection + .find(j.ArrowFunctionExpression) + .find(j.ReturnStatement, path.value) + .size() === 0 && + mainBodyCollection + .find(j.FunctionDeclaration) + .find(j.ReturnStatement, path.value) + .size() === 0 && + mainBodyCollection + .find(j.FunctionExpression) + .find(j.ReturnStatement, path.value) + .size() === 0 + ); + }) + .forEach(path => { + let shouldInsertReturnAfterAssignment = false; + + // if the return statement is not a direct child of getInitialState's body + if (getInitialState.value.body.body.indexOf(path.value) === -1) { + shouldInsertReturnAfterAssignment = true; + } + + j(path).replaceWith(j.expressionStatement( j.assignmentExpression( '=', j.memberExpression( @@ -301,45 +498,73 @@ module.exports = (file, api, options) => { j.identifier('state'), false ), - statement.argument + path.value.argument ) - ); - } + )); - return statement; - }); + if (shouldInsertReturnAfterAssignment) { + j(path).insertAfter(j.returnStatement(null)); + } + }).getAST()[0].value.body.body; }; - const createConstructorArgs = (hasPropsAccess) => { - return [j.identifier('props'), j.identifier('context')]; + const convertInitialStateToClassProperty = getInitialState => + withComments(j.classProperty( + j.identifier('state'), + pickReturnValueOrCreateIIFE(getInitialState.value), + getInitialState.value.returnType, + false + ), getInitialState); + + const createConstructorArgs = (hasContextAccess) => { + if (hasContextAccess) { + return [j.identifier('props'), j.identifier('context')]; + } + + return [j.identifier('props')]; }; - const createConstructor = ( - getInitialState, - autobindFunctions - ) => { - if (!getInitialState && !autobindFunctions.length) { - return []; + const createConstructor = (getInitialState) => { + const initialStateAST = j(getInitialState); + let hasContextAccess = false; + + if ( + initialStateAST.find(j.MemberExpression, { // has `this.context` access + object: {type: 'ThisExpression'}, + property: {type: 'Identifier', name: 'context'}, + }).size() || + initialStateAST.find(j.CallExpression, { // a direct method call `this.x()` + callee: { + type: 'MemberExpression', + object: {type: 'ThisExpression'}, + }, + }).size() || + initialStateAST.find(j.MemberExpression, { // `this` is referenced alone + object: {type: 'ThisExpression'}, + }).size() !== initialStateAST.find(j.ThisExpression).size() + ) { + hasContextAccess = true; } - const hasPropsAccess = updatePropsAccess(getInitialState); + updatePropsAndContextAccess(getInitialState); + const constructorArgs = createConstructorArgs(hasContextAccess); + return [ createMethodDefinition({ key: j.identifier('constructor'), value: j.functionExpression( null, - createConstructorArgs(hasPropsAccess), + constructorArgs, j.blockStatement( [].concat( [ j.expressionStatement( j.callExpression( j.identifier('super'), - [j.identifier('props'), j.identifier('context')] + constructorArgs ) ), ], - autobindFunctions.map(createBindAssignment), inlineGetInitialState(getInitialState) ) ) @@ -348,90 +573,433 @@ module.exports = (file, api, options) => { ]; }; + const createArrowFunctionExpression = fn => { + const arrowFunc = j.arrowFunctionExpression( + fn.params, + fn.body, + false + ); + + arrowFunc.returnType = fn.returnType; + arrowFunc.defaults = fn.defaults; + arrowFunc.rest = fn.rest; + + return arrowFunc; + }; + + const createArrowProperty = prop => + withComments(j.classProperty( + j.identifier(prop.key.name), + createArrowFunctionExpression(prop.value), + null, + false + ), prop); + + const createClassProperty = prop => + withComments(j.classProperty( + j.identifier(prop.key.name), + prop.value, + null, + false + ), prop); + + const createClassPropertyWithType = prop => + withComments(j.classProperty( + j.identifier(prop.key.name), + prop.value.expression, + prop.value.typeAnnotation, + false + ), prop); + + // --------------------------------------------------------------------------- + // Flow! + + const flowAnyType = j.anyTypeAnnotation(); + const flowFixMeType = j.genericTypeAnnotation( + j.identifier('$FlowFixMe'), + null + ); + + const literalToFlowType = node => { + if (node.type === 'Identifier' && node.name === 'undefined') { + return j.voidTypeAnnotation(); + } + + switch (typeof node.value) { + case 'string': + return j.stringLiteralTypeAnnotation(node.value, node.raw); + case 'number': + return j.numberLiteralTypeAnnotation(node.value, node.raw); + case 'boolean': + return j.booleanLiteralTypeAnnotation(node.value, node.raw); + case 'object': // we already know it's a NullLiteral here + return j.nullLiteralTypeAnnotation(); + default: // this should never happen + return flowFixMeType; + } + }; + + const propTypeToFlowMapping = { + // prim types + any: flowAnyType, + array: j.genericTypeAnnotation( + j.identifier('Array'), + j.typeParameterInstantiation([flowFixMeType]) + ), + bool: j.booleanTypeAnnotation(), + element: flowFixMeType, // flow does the same for `element` type in `propTypes` + func: j.genericTypeAnnotation( + j.identifier('Function'), + null + ), + node: flowFixMeType, // flow does the same for `node` type in `propTypes` + number: j.numberTypeAnnotation(), + object: j.genericTypeAnnotation( + j.identifier('Object'), + null + ), + string: j.stringTypeAnnotation(), + + // type classes + arrayOf: (type) => j.genericTypeAnnotation( + j.identifier('Array'), + j.typeParameterInstantiation([type]) + ), + instanceOf: (type) => j.genericTypeAnnotation( + type, + null + ), + objectOf: (type) => j.objectTypeAnnotation([], [ + j.objectTypeIndexer( + j.identifier('key'), + j.stringTypeAnnotation(), + type + ) + ]), + oneOf: (typeList) => j.unionTypeAnnotation(typeList), + oneOfType: (typeList) => j.unionTypeAnnotation(typeList), + shape: (propList) => j.objectTypeAnnotation(propList), + }; + + const propTypeToFlowAnnotation = val => { + let cursor = val; + let isOptional = true; + let typeResult = flowFixMeType; + + if ( // check `.isRequired` first + cursor.type === 'MemberExpression' && + cursor.property.type === 'Identifier' && + cursor.property.name === 'isRequired' + ) { + isOptional = false; + cursor = cursor.object; + } + + switch (cursor.type) { + case 'CallExpression': { // type class + const calleeName = cursor.callee.type === 'MemberExpression' ? + cursor.callee.property.name : + cursor.callee.name; + + const constructor = propTypeToFlowMapping[calleeName]; + if (!constructor) { // unknown type class + // it's not necessary since `typeResult` defaults to `flowFixMeType`, + // but it's more explicit this way + typeResult = flowFixMeType; + break; + } + + switch (cursor.callee.property.name) { + case 'arrayOf': { + const arg = cursor.arguments[0]; + typeResult = constructor( + propTypeToFlowAnnotation(arg)[0] + ); + break; + } + case 'instanceOf': { + const arg = cursor.arguments[0]; + if (arg.type !== 'Identifier') { + typeResult = flowFixMeType; + break; + } + + typeResult = constructor(arg); + break; + } + case 'objectOf': { + const arg = cursor.arguments[0]; + typeResult = constructor( + propTypeToFlowAnnotation(arg)[0] + ); + break; + } + case 'oneOf': { + const argList = cursor.arguments[0].elements; + if ( + !argList || + !argList.every(node => + (node.type === 'Literal') || + (node.type === 'Identifier' && node.name === 'undefined') + ) + ) { + typeResult = flowFixMeType; + } else { + typeResult = constructor( + argList.map(literalToFlowType) + ); + } + break; + } + case 'oneOfType': { + const argList = cursor.arguments[0].elements; + if (!argList) { + typeResult = flowFixMeType; + } else { + typeResult = constructor( + argList.map(arg => propTypeToFlowAnnotation(arg)[0]) + ); + } + break; + } + case 'shape': { + const rawPropList = cursor.arguments[0].properties; + if (!rawPropList) { + typeResult = flowFixMeType; + break; + } + const flowPropList = []; + rawPropList.forEach(typeProp => { + const keyIsLiteral = typeProp.key.type === 'Literal'; + const name = keyIsLiteral ? typeProp.key.value : typeProp.key.name; + + const [valueType, isOptional] = propTypeToFlowAnnotation(typeProp.value); + flowPropList.push(j.objectTypeProperty( + keyIsLiteral ? j.literal(name) : j.identifier(name), + valueType, + isOptional + )); + }); + + typeResult = constructor(flowPropList); + break; + } + default: { + break; + } + } + break; + } + case 'MemberExpression': { // prim type + if (cursor.property.type !== 'Identifier') { // unrecognizable + typeResult = flowFixMeType; + break; + } + + const maybeType = propTypeToFlowMapping[cursor.property.name]; + if (maybeType) { + typeResult = propTypeToFlowMapping[cursor.property.name]; + } else { // type not found + typeResult = flowFixMeType; + } + + break; + } + default: { // unrecognizable + break; + } + } + + return [typeResult, isOptional]; + }; + + const createFlowAnnotationsFromPropTypesProperties = (prop) => { + const typePropertyList = []; + + if (!prop || prop.value.type !== 'ObjectExpression') { + return typePropertyList; + } + + prop.value.properties.forEach(typeProp => { + if (!typeProp.key) { // stuff like SpreadProperty + return; + } + + const keyIsLiteral = typeProp.key.type === 'Literal'; + const name = keyIsLiteral ? typeProp.key.value : typeProp.key.name; + + const [valueType, isOptional] = propTypeToFlowAnnotation(typeProp.value); + typePropertyList.push(j.objectTypeProperty( + keyIsLiteral ? j.literal(name) : j.identifier(name), + valueType, + isOptional + )); + }); + + return j.classProperty( + j.identifier('props'), + null, + j.typeAnnotation(j.objectTypeAnnotation(typePropertyList)), + false + ); + }; + + // to ensure that our property initializers' evaluation order is safe + const repositionStateProperty = (initialStateProperty, propertiesAndMethods) => { + const initialStateCollection = j(initialStateProperty); + const thisCount = initialStateCollection.find(j.ThisExpression).size(); + const safeThisMemberCount = initialStateCollection.find(j.MemberExpression, { + object: { + type: 'ThisExpression', + }, + property: { + type: 'Identifier', + name: 'props', + }, + }).size() + initialStateCollection.find(j.MemberExpression, { + object: { + type: 'ThisExpression', + }, + property: { + type: 'Identifier', + name: 'context', + }, + }).size(); + + if (thisCount === safeThisMemberCount) { + return initialStateProperty.concat(propertiesAndMethods); + } + + const result = [].concat(propertiesAndMethods); + let lastPropPosition = result.length - 1; + + while (lastPropPosition >= 0 && result[lastPropPosition].kind === 'method') { + lastPropPosition--; + } + + result.splice(lastPropPosition + 1, 0, initialStateProperty[0]); + return result; + }; + + // if there's no `getInitialState` or the `getInitialState` function is simple + // (i.e., it's just a return statement) then we don't need a constructor. + // we can simply lift `state = {...}` as a property initializer. + // otherwise, create a constructor and inline `this.state = ...`. + // + // when we need to create a constructor, we only put `context` as the + // second parameter when the following things happen in `getInitialState()`: + // 1. there's a `this.context` access, or + // 2. there's a direct method call `this.x()`, or + // 3. `this` is referenced alone const createESClass = ( name, - properties, + baseClassName, + staticProperties, getInitialState, - autobindFunctions, + rawProperties, comments - ) => - withComments(j.classDeclaration( + ) => { + const initialStateProperty = []; + let maybeConstructor = []; + let maybeFlowStateAnnotation = []; // we only need this when we do `this.state = ...` + + if (isInitialStateLiftable(getInitialState)) { + if (getInitialState) { + initialStateProperty.push(convertInitialStateToClassProperty(getInitialState)); + } + } else { + maybeConstructor = createConstructor(getInitialState); + if (shouldTransformFlow) { + let stateType = j.typeAnnotation( + j.genericTypeAnnotation(j.identifier('Object'), null) + ); + + if (getInitialState.value.returnType) { + stateType = getInitialState.value.returnType; + } + + maybeFlowStateAnnotation.push(j.classProperty( + j.identifier('state'), + null, + stateType, + false + )); + } + } + + const propertiesAndMethods = rawProperties.map(prop => { + if (isPrimPropertyWithTypeAnnotation(prop)) { + return createClassPropertyWithType(prop); + } else if (isPrimProperty(prop)) { + return createClassProperty(prop); + } else if (AUTOBIND_IGNORE_KEYS[prop.key.name]) { + return createMethodDefinition(prop); + } + + return createArrowProperty(prop); + }); + + const flowPropsAnnotation = shouldTransformFlow ? + createFlowAnnotationsFromPropTypesProperties( + staticProperties.find((path) => path.key.name === 'propTypes') + ) : + []; + + let finalStaticProperties = staticProperties; + + if (shouldTransformFlow && options['remove-runtime-proptypes']) { + finalStaticProperties = staticProperties.filter((prop) => prop.key.name !== 'propTypes'); + } + + return withComments(j.classDeclaration( name ? j.identifier(name) : null, j.classBody( [].concat( - createConstructor( - getInitialState, - autobindFunctions - ), - properties + flowPropsAnnotation, + maybeFlowStateAnnotation, + finalStaticProperties, + maybeConstructor, + repositionStateProperty(initialStateProperty, propertiesAndMethods) ) ), j.memberExpression( j.identifier('React'), - j.identifier('Component'), + j.identifier(baseClassName), false ) ), {comments}); + }; - const createStaticAssignment = (name, staticProperty) => - withComments(j.expressionStatement( - j.assignmentExpression( - '=', - j.memberExpression( - name, - j.identifier(staticProperty.key.name), - false - ), - staticProperty.value - ) - ), staticProperty); + const createStaticClassProperty = staticProperty => { + if (staticProperty.value.type === 'FunctionExpression') { + return withComments(j.methodDefinition( + 'method', + j.identifier(staticProperty.key.name), + staticProperty.value, + true + ), staticProperty); + } - const createStaticAssignmentExpressions = (name, statics) => - statics.map(staticProperty => createStaticAssignment(name, staticProperty)); + if (staticProperty.value.type === 'TypeCastExpression') { + return withComments(j.classProperty( + j.identifier(staticProperty.key.name), + staticProperty.value.expression, + staticProperty.value.typeAnnotation, + true + ), staticProperty); + } - const createStaticClassProperty = staticProperty => - withComments(j.classProperty( + return withComments(j.classProperty( j.identifier(staticProperty.key.name), staticProperty.value, null, true ), staticProperty); + }; const createStaticClassProperties = statics => statics.map(createStaticClassProperty); - const hasSingleReturnStatement = value => ( - value.type === 'FunctionExpression' && - value.body && - value.body.type === 'BlockStatement' && - value.body.body && - value.body.body.length === 1 && - value.body.body[0].type === 'ReturnStatement' && - value.body.body[0].argument && - value.body.body[0].argument.type === 'ObjectExpression' - ); - - const createDefaultPropsValue = value => { - if (hasSingleReturnStatement(value)) { - return value.body.body[0].argument; - } else { - return j.callExpression( - value, - [] - ); - } - }; - - const createDefaultProps = prop => - withComments( - j.property( - 'init', - j.identifier(DEFAULT_PROPS_KEY), - createDefaultPropsValue(prop.value) - ), - prop - ); - const getComments = classPath => { if (classPath.value.comments) { return classPath.value.comments; @@ -443,83 +1011,164 @@ module.exports = (file, api, options) => { return null; }; - const createModuleExportsMemberExpression = () => - j.memberExpression( - j.identifier('module'), - j.identifier('exports'), - false - ); + const findUnusedVariables = (path, varName) => j(path) + .closestScope() + .find(j.Identifier, {name: varName}) + // Ignore require vars + .filter(identifierPath => identifierPath.value !== path.value.id) + // Ignore import bindings + .filter(identifierPath => !( + path.value.type === 'ImportDeclaration' && + path.value.specifiers.some(specifier => specifier.id === identifierPath.value) + )) + // Ignore properties in MemberExpressions + .filter(identifierPath => { + const parent = identifierPath.parent.value; + return !( + j.MemberExpression.check(parent) && + parent.property === identifierPath.value + ); + }); + + // convert `OtherClass.getDefaultProps()` to `OtherClass.defaultProps` + const updateOtherDefaultPropsAccess = (classPath) => { + j(classPath) + .find(j.CallExpression, { + callee: { + type: 'MemberExpression', + property: { name: 'getDefaultProps' }, + }, + }) + .forEach(path => j(path).replaceWith( + j.memberExpression( + path.value.callee.object, + j.identifier('defaultProps') + ))); + }; - const updateToClass = (classPath, type) => { - const specPath = ReactUtils.getReactCreateClassSpec(classPath); - const name = ReactUtils.getComponentName(classPath); + const updateToClass = (classPath) => { + const specPath = ReactUtils.directlyGetCreateClassSpec(classPath); + const name = ReactUtils.directlyGetComponentName(classPath); const statics = collectStatics(specPath); - const functions = collectFunctions(specPath); + const properties = collectNonStaticProperties(specPath); const comments = getComments(classPath); - const autobindFunctions = collectAutoBindFunctions(functions, classPath); const getInitialState = findGetInitialState(specPath); - const staticName = - name ? j.identifier(name) : createModuleExportsMemberExpression(); - - var path; - if (type == 'moduleExports' || type == 'exportDefault') { - path = ReactUtils.findReactCreateClassCallExpression(classPath); - } else { - path = j(classPath).closest(j.VariableDeclaration); + var path = classPath; + + if ( + classPath.parentPath && + classPath.parentPath.value && + classPath.parentPath.value.type === 'VariableDeclarator' + ) { + // the reason that we need to do this awkward dance here is that + // for things like `var Foo = React.createClass({...})`, we need to + // replace the _entire_ VariableDeclaration with + // `class Foo extends React.Component {...}`. + // it looks scary but since we already know it's a VariableDeclarator + // it's actually safe. + // (VariableDeclaration > declarations > VariableDeclarator > CallExpression) + path = classPath.parentPath.parentPath.parentPath; } - const properties = - (type == 'exportDefault') ? createStaticClassProperties(statics) : []; + const staticProperties = createStaticClassProperties(statics); + const baseClassName = + pureRenderMixinPathAndBinding && + ReactUtils.directlyHasSpecificMixins(classPath, [pureRenderMixinPathAndBinding.binding]) ? + 'PureComponent' : + 'Component'; - path.replaceWith( + j(path).replaceWith( createESClass( name, - properties.concat(functions.map(createMethodDefinition)), + baseClassName, + staticProperties, getInitialState, - autobindFunctions, + properties, comments ) ); - if (type == 'moduleExports' || type == 'var') { - const staticAssignments = createStaticAssignmentExpressions( - staticName, - statics - ); - if (type == 'moduleExports') { - root.get().value.program.body.push(...staticAssignments); - } else { - path.insertAfter(staticAssignments.reverse()); - } - } + updateOtherDefaultPropsAccess(path); }; if ( options['explicit-require'] === false || ReactUtils.hasReact(root) ) { - const apply = (path, type) => + // no mixins found on the classPath -> true + // pure mixin identifier not found -> (has mixins) -> false + // found pure mixin identifier -> + // class mixins is an array and only contains the identifier -> true + // otherwise -> false + const mixinsFilter = (classPath) => { + if (!ReactUtils.directlyHasMixinsField(classPath)) { + return true; + } else if (options['pure-component'] && pureRenderMixinPathAndBinding) { + const {binding} = pureRenderMixinPathAndBinding; + if (areMixinsConvertible([binding], classPath)) { + return true; + } + } + console.warn( + file.path + ': `' + ReactUtils.directlyGetComponentName(classPath) + '` ' + + 'was skipped because of inconvertible mixins.' + ); + + return false; + }; + + // the only time that we can't simply replace the createClass call path + // with a new class is when the parent of that is a variable declaration. + // let's delay it and figure it out later (by looking at `path.parentPath`) + // in `updateToClass`. + const apply = (path) => path - .filter(hasMixins) - .filter(callsDeprecatedAPIs) + .filter(mixinsFilter) + .filter(hasNoCallsToDeprecatedAPIs) + .filter(hasNoRefsToAPIsThatWillBeRemoved) + .filter(doesNotUseArguments) + .filter(isInitialStateConvertible) .filter(canConvertToClass) - .forEach(classPath => updateToClass(classPath, type)); - - const didTransform = ( - apply(ReactUtils.findReactCreateClass(root), 'var') - .size() + - apply(ReactUtils.findReactCreateClassModuleExports(root), 'moduleExports') - .size() + - apply(ReactUtils.findReactCreateClassExportDefault(root), 'exportDefault') - .size() - ) > 0; + .forEach(updateToClass); + + const didTransform = apply( + ReactUtils.findAllReactCreateClassCalls(root) + ).size() > 0; if (didTransform) { + // prune removed requires + if (pureRenderMixinPathAndBinding) { + const {binding, path, type} = pureRenderMixinPathAndBinding; + let shouldReinsertComment = false; + if (findUnusedVariables(path, binding).size() === 0) { + var removePath = null; + if (type === 'require') { + const bodyNode = path.parentPath.parentPath.parentPath.value; + const variableDeclarationNode = path.parentPath.parentPath.value; + + removePath = path.parentPath.parentPath; + shouldReinsertComment = bodyNode.indexOf(variableDeclarationNode) === 0; + } else { + const importDeclarationNode = path.value; + const bodyNode = path.parentPath.value; + + removePath = path; + shouldReinsertComment = bodyNode.indexOf(importDeclarationNode) === 0; + } + + j(removePath).remove(); + if (shouldReinsertComment) { + root.get().node.comments = topComments; + } + } + } + return root.toSource(printOptions); } - } return null; }; + +module.exports.parser = 'flow'; diff --git a/transforms/sort-comp.js b/transforms/sort-comp.js index 97af1ac4..d37eee01 100644 --- a/transforms/sort-comp.js +++ b/transforms/sort-comp.js @@ -36,7 +36,7 @@ module.exports = function(fileInfo, api, options) { const printOptions = options.printOptions || {quote: 'single', trailingComma: true}; - const methodsOrder = getMethodsOrder(fileInfo, options); + const methodsOrder = getMethodsOrder(fileInfo, options); // eslint-disable-line no-use-before-define const root = j(fileInfo.source); @@ -44,8 +44,8 @@ module.exports = function(fileInfo, api, options) { const nameA = a.key.name; const nameB = b.key.name; - const indexA = getCorrectIndex(methodsOrder, a); - const indexB = getCorrectIndex(methodsOrder, b); + const indexA = getCorrectIndex(methodsOrder, a); // eslint-disable-line no-use-before-define + const indexB = getCorrectIndex(methodsOrder, b); // eslint-disable-line no-use-before-define const sameLocation = indexA === indexB; diff --git a/transforms/utils/ReactUtils.js b/transforms/utils/ReactUtils.js index 830c6ccc..c09757a2 100644 --- a/transforms/utils/ReactUtils.js +++ b/transforms/utils/ReactUtils.js @@ -58,7 +58,8 @@ module.exports = function(j) { .filter(decl => findReactCreateClassCallExpression(decl).size() > 0); const findReactCreateClassExportDefault = path => - path.find(j.ExportDefaultDeclaration, { + path.find(j.ExportDeclaration, { + default: true, declaration: { type: 'CallExpression', callee: REACT_CREATE_CLASS_MEMBER_EXPRESSION, @@ -85,6 +86,18 @@ module.exports = function(j) { }, }); + const getReactCreateClassSpec = classPath => { + const {value} = classPath; + const args = (value.init || value.right || value.declaration).arguments; + if (args && args.length) { + const spec = args[0]; + if (spec.type === 'ObjectExpression' && Array.isArray(spec.properties)) { + return spec; + } + } + return null; + }; + // --------------------------------------------------------------------------- // Finds alias for React.Component if used as named import. const findReactComponentName = path => { @@ -160,18 +173,6 @@ module.exports = function(j) { // --------------------------------------------------------------------------- // Others - const getReactCreateClassSpec = classPath => { - const {value} = classPath; - const args = (value.init || value.right || value.declaration).arguments; - if (args) { - const spec = args[0]; - if (spec.type === 'ObjectExpression' && Array.isArray(spec.properties)) { - return spec; - } - } - return null; - }; - const getClassExtendReactSpec = classPath => classPath.value.body; const createCreateReactClassCallExpression = properties => @@ -187,6 +188,78 @@ module.exports = function(j) { const getComponentName = classPath => classPath.node.id && classPath.node.id.name; + // --------------------------------------------------------------------------- + // Direct methods! (see explanation below) + const findAllReactCreateClassCalls = path => + path.find(j.CallExpression, { + callee: REACT_CREATE_CLASS_MEMBER_EXPRESSION, + }); + + // Mixin Stuff + const containSameElements = (ls1, ls2) => { + if (ls1.length !== ls2.length) { + return false; + } + + return ( + ls1.reduce((res, x) => res && ls2.indexOf(x) !== -1, true) && + ls2.reduce((res, x) => res && ls1.indexOf(x) !== -1, true) + ); + }; + + const keyNameIsMixins = property => property.key.name === 'mixins'; + + const isSpecificMixinsProperty = (property, mixinIdentifierNames) => { + const key = property.key; + const value = property.value; + + return ( + key.name === 'mixins' && + value.type === 'ArrayExpression' && + Array.isArray(value.elements) && + value.elements.every(elem => elem.type === 'Identifier') && + containSameElements(value.elements.map(elem => elem.name), mixinIdentifierNames) + ); + }; + + // These following methods assume that the argument is + // a `React.createClass` call expression. In other words, + // they should only be used with `findAllReactCreateClassCalls`. + const directlyGetCreateClassSpec = classPath => { + if (!classPath || !classPath.value) { + return null; + } + const args = classPath.value.arguments; + if (args && args.length) { + const spec = args[0]; + if (spec.type === 'ObjectExpression' && Array.isArray(spec.properties)) { + return spec; + } + } + return null; + }; + + const directlyGetComponentName = classPath => { + let result = ''; + if ( + classPath.parentPath.value && + classPath.parentPath.value.type === 'VariableDeclarator' + ) { + result = classPath.parentPath.value.id.name; + } + return result; + }; + + const directlyHasMixinsField = classPath => { + const spec = directlyGetCreateClassSpec(classPath); + return spec && spec.properties.some(keyNameIsMixins); + }; + + const directlyHasSpecificMixins = (classPath, mixinIdentifierNames) => { + const spec = directlyGetCreateClassSpec(classPath); + return spec && spec.properties.some(prop => isSpecificMixinsProperty(prop, mixinIdentifierNames)); + }; + return { createCreateReactClassCallExpression, findReactES6ClassDeclaration, @@ -201,5 +274,12 @@ module.exports = function(j) { hasModule, hasReact, isMixinProperty, + + // "direct" methods + findAllReactCreateClassCalls, + directlyGetComponentName, + directlyGetCreateClassSpec, + directlyHasMixinsField, + directlyHasSpecificMixins, }; };