flow-upgrade 1.0.4 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -2
- package/dist/Styled.js +12 -14
- package/dist/Types.js +21 -1
- package/dist/bin/runSpecificCodemod.js +117 -0
- package/dist/bin/upgrade.js +75 -0
- package/dist/codemodUtils/getClassMemberName.js +27 -0
- package/dist/codemodUtils/replaceMethodWithArrowProp.js +60 -0
- package/dist/codemods/collapseObjectInitialization.js +250 -0
- package/dist/codemods/convertImplicitInexactObjectTypes.js +35 -0
- package/dist/codemods/removeAnnotationsInDestructuring.js +40 -0
- package/dist/codemods/removeDuplicateClassProperties.js +268 -0
- package/dist/findFlowFiles.js +136 -156
- package/dist/runCodemods.js +36 -0
- package/dist/upgrade.js +127 -150
- package/dist/upgrades/0.170.0/index.js +25 -0
- package/dist/upgrades/0.176.0/index.js +25 -0
- package/dist/upgrades/0.84.0/index.js +25 -0
- package/dist/upgrades/index.js +29 -0
- package/dist/utils/redirectConsole.js +59 -0
- package/package.json +36 -20
- package/dist/codemods/ReactUtils.js +0 -140
- package/dist/codemods/createAggregateCodemod.js +0 -36
- package/dist/codemods/runCodemods.js +0 -53
- package/dist/index.js +0 -26
- package/dist/upgrades/0.53.0/ReactComponentExplicitTypeArgs/codemod.js +0 -154
- package/dist/upgrades/0.53.0/ReactComponentExplicitTypeArgs/index.js +0 -75
- package/dist/upgrades/0.53.0/ReactComponentSimplifyTypeArgs/codemod.js +0 -65
- package/dist/upgrades/0.53.0/ReactComponentSimplifyTypeArgs/index.js +0 -52
- package/dist/upgrades/0.53.0/ReactUtilityTypes/codemod.js +0 -200
- package/dist/upgrades/0.53.0/ReactUtilityTypes/index.js +0 -59
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @format
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
'use strict';
|
|
6
|
-
|
|
7
|
-
// All the event names that we need to add <> to.
|
|
8
|
-
|
|
9
|
-
const SYNTHETIC_EVENT_NAMES = new Set(['SyntheticEvent', 'SyntheticAnimationEvent', 'SyntheticClipboardEvent', 'SyntheticCompositionEvent', 'SyntheticInputEvent', 'SyntheticUIEvent', 'SyntheticFocusEvent', 'SyntheticKeyboardEvent', 'SyntheticMouseEvent', 'SyntheticDragEvent', 'SyntheticWheelEvent', 'SyntheticTouchEvent', 'SyntheticTransitionEvent']);
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* This codemod alters, removes, and replaces various React utilities that
|
|
13
|
-
* had API changes when upgrading to this version. This includes the following
|
|
14
|
-
* list:
|
|
15
|
-
*
|
|
16
|
-
* - `React$Node`.
|
|
17
|
-
* - `React$Element`.
|
|
18
|
-
* - `ReactClass`.
|
|
19
|
-
* - `ReactComponent`.
|
|
20
|
-
* - The return type of React component render.
|
|
21
|
-
*/
|
|
22
|
-
module.exports = (j, root) => {
|
|
23
|
-
const recast = require('recast');
|
|
24
|
-
const ReactUtils = require('../../../codemods/ReactUtils')(j);
|
|
25
|
-
const reactName = ReactUtils.getImportedReactName(root);
|
|
26
|
-
const componentPattern = ReactUtils.getImportedComponentClassPattern(root);
|
|
27
|
-
const hasElement = ReactUtils.hasDestructuredElement(root, reactName);
|
|
28
|
-
|
|
29
|
-
// There is a bug in recast so we can't use `root.find()`. Instead we need to
|
|
30
|
-
// visit with recast manually so we can visit the nodes it misses.
|
|
31
|
-
root.paths().forEach(path => {
|
|
32
|
-
recast.visit(path, {
|
|
33
|
-
// Here is where we do all of our transformations.
|
|
34
|
-
visitGenericTypeAnnotation: visitGenericTypeAnnotation,
|
|
35
|
-
|
|
36
|
-
// We want to replace default React imports with a namespace import.
|
|
37
|
-
visitImportDeclaration: visitImportDeclaration,
|
|
38
|
-
|
|
39
|
-
// recast has a bug where it won't visit `superTypeParameters` on class
|
|
40
|
-
// declarations and expressions. Fix that here.
|
|
41
|
-
visitClassDeclaration: visitClass,
|
|
42
|
-
visitClassExpression: visitClass
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
function visitClass(path) {
|
|
47
|
-
// Continue traversing the path. This is the default behavior.
|
|
48
|
-
this.traverse(path);
|
|
49
|
-
// There is a bug in recast which means we end up not traversing
|
|
50
|
-
// `superTypeParameters`! So handle that that bug by visiting
|
|
51
|
-
// `superTypeParameters` here.
|
|
52
|
-
this.visitWithoutReset(path.get('superTypeParameters'));
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function visitImportDeclaration(path) {
|
|
56
|
-
const node = path.node;
|
|
57
|
-
|
|
58
|
-
// import React from 'react'; ==> import * as React from 'react';
|
|
59
|
-
if (node.importKind === 'value' && node.source && node.source.type === 'Literal' && node.source.value === 'react' && node.specifiers.length === 1 && node.specifiers[0].type === 'ImportDefaultSpecifier') {
|
|
60
|
-
node.specifiers[0] = j.importNamespaceSpecifier(node.specifiers[0].local);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Continue traversal if we do not want to apply a transformation to
|
|
64
|
-
// this node.
|
|
65
|
-
this.traverse(path);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function visitGenericTypeAnnotation(path) {
|
|
69
|
-
const node = path.node;
|
|
70
|
-
|
|
71
|
-
// React$Node<any> ==> React.Node
|
|
72
|
-
if (node.id.type === 'Identifier' && (node.id.name === 'React$Node' || node.id.name === 'ReactNode')) {
|
|
73
|
-
// React.Node no longer has type parameters.
|
|
74
|
-
node.typeParameters = null;
|
|
75
|
-
// Use the exported type from the React module. If it does not exist then
|
|
76
|
-
// use React$Node.
|
|
77
|
-
node.id = reactName ? j.qualifiedTypeIdentifier(j.identifier(reactName), j.identifier('Node')) : j.identifier('React$Node');
|
|
78
|
-
// We have handled this node. No need to continue traversing.
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// React$Element<Config> ==> React.Element<React.ComponentType<Props>>
|
|
83
|
-
if (
|
|
84
|
-
// React$Element or ReactElement
|
|
85
|
-
node.id.type === 'Identifier' && (node.id.name === 'React$Element' || node.id.name === 'ReactElement') ||
|
|
86
|
-
// React.Element
|
|
87
|
-
node.id.type === 'QualifiedTypeIdentifier' && node.id.qualification && node.id.qualification.type === 'Identifier' && node.id.qualification.name === reactName && node.id.id && node.id.id.type === 'Identifier' && node.id.id.name === 'Element' ||
|
|
88
|
-
// const {Element} = React;
|
|
89
|
-
// Element
|
|
90
|
-
hasElement && node.id.type === 'Identifier' && node.id.name === 'Element') {
|
|
91
|
-
// If we have no type parameters then add an empty type parameter
|
|
92
|
-
// instantiation.
|
|
93
|
-
if (!node.typeParameters) {
|
|
94
|
-
node.typeParameters = j.typeParameterInstantiation([]);
|
|
95
|
-
}
|
|
96
|
-
// If we have a first type parameter...
|
|
97
|
-
if (node.typeParameters.params[0]) {
|
|
98
|
-
const firstTypeParam = node.typeParameters.params[0];
|
|
99
|
-
// ...and that type parameter is not `any`, `mixed`, or `*`...
|
|
100
|
-
if (firstTypeParam && firstTypeParam.type !== 'AnyTypeAnnotation' && firstTypeParam.type !== 'ExistsTypeAnnotation') {
|
|
101
|
-
// ...then wrap the type parameter with `React.ComponentType<Props>`.
|
|
102
|
-
node.typeParameters.params[0] = j.genericTypeAnnotation(
|
|
103
|
-
// Get the `React.ComponentType` type name, or use the global.
|
|
104
|
-
reactName ? j.qualifiedTypeIdentifier(j.identifier(reactName), j.identifier('ComponentType')) : j.identifier('React$ComponentType'),
|
|
105
|
-
// Put the type param we are wrapping as the first and only
|
|
106
|
-
// type argument.
|
|
107
|
-
j.typeParameterInstantiation([firstTypeParam]));
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
// If we do not have a first type parameter, or our type parameter is `*`
|
|
111
|
-
// then we want to use `any` instead. This is because using `*` will often
|
|
112
|
-
// cause errors that are unrelated to whether or not the code is correct.
|
|
113
|
-
// Almost all of the time when a user writes `React.Element<*>` they meant
|
|
114
|
-
// `React.Element<any>`. They just felt bad about writing `any`.
|
|
115
|
-
if (node.typeParameters.params.length === 0 || node.typeParameters.params[0].type === 'ExistsTypeAnnotation') {
|
|
116
|
-
node.typeParameters = j.typeParameterInstantiation([j.anyTypeAnnotation()]);
|
|
117
|
-
}
|
|
118
|
-
// Update the type identifier to be `React.Element` or the
|
|
119
|
-
// equivalent global.
|
|
120
|
-
node.id = reactName ? j.qualifiedTypeIdentifier(j.identifier(reactName), j.identifier('Element')) : j.identifier('React$Element');
|
|
121
|
-
// We have handled this node. No need to continue traversing.
|
|
122
|
-
return false;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// ReactClass<Config> ==> React.ComponentType<Props>
|
|
126
|
-
if (node.id.type === 'Identifier' && node.id.name === 'ReactClass' && node.typeParameters && node.typeParameters.type === 'TypeParameterInstantiation') {
|
|
127
|
-
// Replace ReactClass with the new type.
|
|
128
|
-
return j.genericTypeAnnotation(
|
|
129
|
-
// Get the component type name. Either as a qualified name from our
|
|
130
|
-
// React import or using the global.
|
|
131
|
-
reactName ? j.qualifiedTypeIdentifier(j.identifier(reactName), j.identifier('ComponentType')) : j.identifier('React$ComponentType'),
|
|
132
|
-
// Keep the type parameters we had previously.
|
|
133
|
-
node.typeParameters);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// React$Component<Defaults, Props, State> ==> React.Component<Props, State>
|
|
137
|
-
if ((node.id.type === 'Identifier' && (node.id.name === 'ReactComponent' || node.id.name === 'React$Component') || componentPattern && componentPattern(node.id)) && node.typeParameters && node.typeParameters.type === 'TypeParameterInstantiation') {
|
|
138
|
-
// Remove the default props type argument.
|
|
139
|
-
if (node.typeParameters.params.length >= 3) {
|
|
140
|
-
node.typeParameters.params.shift();
|
|
141
|
-
}
|
|
142
|
-
// If the user has destructured React and used Component or PureComponent
|
|
143
|
-
// directly then we should not update the identifier of this node.
|
|
144
|
-
if (node.id.type === 'Identifier' && (node.id.name === 'Component' || node.id.name === 'PureComponent')) {
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
// Replace the identifier with React.Component
|
|
148
|
-
node.id = reactName ? j.qualifiedTypeIdentifier(j.identifier(reactName), j.identifier('Component')) : j.identifier('React$Component');
|
|
149
|
-
// We have handled this node. No need to continue traversing.
|
|
150
|
-
return false;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// SyntheticEvent ==> SyntheticEvent<>
|
|
154
|
-
if (node.id.type === 'Identifier' && SYNTHETIC_EVENT_NAMES.has(node.id.name)) {
|
|
155
|
-
node.typeParameters = j.typeParameterInstantiation([]);
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Continue traversal if we do not want to apply a transformation to
|
|
160
|
-
// this node.
|
|
161
|
-
this.traverse(path);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// render(): React.Element<any> ==> render(): React.Node
|
|
165
|
-
if (componentPattern) {
|
|
166
|
-
root.find(j.ClassDeclaration, {
|
|
167
|
-
superClass: componentPattern,
|
|
168
|
-
body: { type: 'ClassBody' }
|
|
169
|
-
}).forEach(handleReactClassPath);
|
|
170
|
-
|
|
171
|
-
root.find(j.ClassExpression, {
|
|
172
|
-
superClass: componentPattern,
|
|
173
|
-
body: { type: 'ClassBody' }
|
|
174
|
-
}).forEach(handleReactClassPath);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function handleReactClassPath(path) {
|
|
178
|
-
// For every member in the class's body...
|
|
179
|
-
path.node.body.body.forEach(method => {
|
|
180
|
-
// If this member is the component's render method and it has a
|
|
181
|
-
// return type...
|
|
182
|
-
if (method.type === 'MethodDefinition' && method.key && method.key.type === 'Identifier' && method.key.name === 'render' && method.value && method.value.type === 'FunctionExpression' && method.value.returnType && method.value.returnType.type === 'TypeAnnotation') {
|
|
183
|
-
const returnType = method.value.returnType;
|
|
184
|
-
// If this is a return type from render that people commonly use then
|
|
185
|
-
// replace it with the new recommendation. React.Node
|
|
186
|
-
if (isRenderReturnReactElement(returnType.typeAnnotation) || returnType.typeAnnotation.type === 'NullableTypeAnnotation' && isRenderReturnReactElement(returnType.typeAnnotation.typeAnnotation)) {
|
|
187
|
-
returnType.typeAnnotation = reactName ? j.qualifiedTypeIdentifier(j.identifier(reactName), j.identifier('Node')) : j.identifier('React$Node');
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function isRenderReturnReactElement(node) {
|
|
194
|
-
// Is the node React.Element<any>, React.Element<mixed>,
|
|
195
|
-
// or React.Element<*>?
|
|
196
|
-
return reactName && node && node.type === 'GenericTypeAnnotation' && node.id.type === 'QualifiedTypeIdentifier' && node.id.qualification.type === 'Identifier' && node.id.qualification.name === reactName && node.id.id.type === 'Identifier' && node.id.id.name === 'Element' && node.typeParameters && node.typeParameters.type === 'TypeParameterInstantiation' && (node.typeParameters.params.length === 0 || node.typeParameters.params[0] && (node.typeParameters.params[0].type === 'AnyTypeAnnotation' || node.typeParameters.params[0].type === 'ExistsTypeAnnotation'));
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
return true;
|
|
200
|
-
};
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @format
|
|
5
|
-
*
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const path = require('path');
|
|
9
|
-
const Styled = require('../../../Styled');
|
|
10
|
-
|
|
11
|
-
exports.kind = 'codemod';
|
|
12
|
-
|
|
13
|
-
exports.title = 'Remove and replace old React utility types.';
|
|
14
|
-
|
|
15
|
-
exports.description = `
|
|
16
|
-
In the past Flow has some very confusing and inconvenient utility types for
|
|
17
|
-
React. We removed these utility types and replaced them with types which should
|
|
18
|
-
make a lot more sense. These types will make it a lot easier to effectively type
|
|
19
|
-
advanced React features like higher order components.
|
|
20
|
-
|
|
21
|
-
Some of the most powerful new utility types can be seen in the following
|
|
22
|
-
example:
|
|
23
|
-
|
|
24
|
-
${Styled.codeblock(`
|
|
25
|
-
import * as React from 'react';
|
|
26
|
-
|
|
27
|
-
function MyComponent(props: Props): React.Node {
|
|
28
|
-
/* ... */
|
|
29
|
-
}
|
|
30
|
-
(React.createElement(MyComponent): React.Element<typeof MyComponent>);
|
|
31
|
-
|
|
32
|
-
class MyStatefulComponent extends React.Component<Props> {
|
|
33
|
-
/* ... */
|
|
34
|
-
}
|
|
35
|
-
(React.createElement(MyComponent): React.Element<typeof MyStatefulComponent>);
|
|
36
|
-
|
|
37
|
-
function myHOC(
|
|
38
|
-
Component: React.ComponentType<Props>,
|
|
39
|
-
): React.ComponentType<NewProps> {
|
|
40
|
-
return class extends React.Component<NewProps> {
|
|
41
|
-
/* ... */
|
|
42
|
-
};
|
|
43
|
-
}`.slice(1))}
|
|
44
|
-
|
|
45
|
-
${Styled.list([`React.Node is the new return type for render methods. This codemod will
|
|
46
|
-
replace any render methods that return the type ?React.Element<any> with
|
|
47
|
-
React.Node.`, `React.Element<Component> now takes the type of a component as its type
|
|
48
|
-
argument instead of the type of a the component's props as it used to. This
|
|
49
|
-
codemod will upgrade everywhere you use React.Element<Props> to
|
|
50
|
-
React.Element<React.ComponentType<Props>>.`, `Speaking of React.ComponentType<Props>, this is a new utility type which
|
|
51
|
-
represents either a class component, or a stateless functional component. This
|
|
52
|
-
type is very useful when you want to type higher order components. We will
|
|
53
|
-
replace everywhere you use ReactClass<Props> in your codebase with
|
|
54
|
-
React.ComponentType<Props>. (ReactClass<Props> was very buggy and so this may
|
|
55
|
-
cause a lot of new errors!)`, `Also note that we used import * as React from 'react'. You must use the
|
|
56
|
-
import * syntax if you want to use the new utility types. This codemod will
|
|
57
|
-
update your code to use this new style of import.`])}`.slice(1);
|
|
58
|
-
|
|
59
|
-
exports.transformPath = path.join(__dirname, './codemod.js');
|