flow-upgrade 1.1.0 → 2.0.0
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 +10 -0
- 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 -158
- package/dist/runCodemods.js +36 -0
- package/dist/upgrade.js +127 -153
- 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 +29 -21
- package/dist/codemods/ReactUtils.js +0 -140
- package/dist/codemods/createAggregateCodemod.js +0 -36
- package/dist/codemods/runCodemods.js +0 -54
- package/dist/index.js +0 -38
- 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 -156
- package/dist/upgrades/0.53.0/ReactUtilityTypes/index.js +0 -59
- package/dist/upgrades/0.84.0/ExplicitInexactObjectSyntax/codemod.js +0 -18
- package/dist/upgrades/0.84.0/ExplicitInexactObjectSyntax/index.js +0 -25
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
|
|
8
|
+
var _getClassMemberName = require("../codemodUtils/getClassMemberName");
|
|
9
|
+
|
|
10
|
+
var _replaceMethodWithArrowProp = require("../codemodUtils/replaceMethodWithArrowProp");
|
|
11
|
+
|
|
12
|
+
var _Types = require("../Types");
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
16
|
+
*
|
|
17
|
+
* This source code is licensed under the MIT license found in the
|
|
18
|
+
* LICENSE file in the root directory of this source tree.
|
|
19
|
+
*
|
|
20
|
+
* @format
|
|
21
|
+
*
|
|
22
|
+
*/
|
|
23
|
+
function getKind(member) {
|
|
24
|
+
switch (member.type) {
|
|
25
|
+
case 'MethodDefinition':
|
|
26
|
+
switch (member.kind) {
|
|
27
|
+
case 'get':
|
|
28
|
+
return 'Getter';
|
|
29
|
+
|
|
30
|
+
case 'set':
|
|
31
|
+
return 'Setter';
|
|
32
|
+
|
|
33
|
+
case 'method':
|
|
34
|
+
case 'constructor':
|
|
35
|
+
return 'Method';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
throw new Error(`Unexpected method kind: ${member.kind}`);
|
|
39
|
+
|
|
40
|
+
case 'PropertyDefinition':
|
|
41
|
+
return 'Property';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
throw new Error(`Unexpected member type: ${member.type}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function findDuplicates(membersMap) {
|
|
48
|
+
const toDelete = [];
|
|
49
|
+
|
|
50
|
+
for (const [, members] of membersMap) {
|
|
51
|
+
if (members.length === 1) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let lastMember = null;
|
|
56
|
+
|
|
57
|
+
for (const member of members) {
|
|
58
|
+
const kind = getKind(member);
|
|
59
|
+
|
|
60
|
+
if (lastMember == null) {
|
|
61
|
+
lastMember = {
|
|
62
|
+
kind,
|
|
63
|
+
member
|
|
64
|
+
};
|
|
65
|
+
continue;
|
|
66
|
+
} // handle the valid cases
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
switch (lastMember.kind) {
|
|
70
|
+
case 'GetterSetter':
|
|
71
|
+
if (kind === 'Getter') {
|
|
72
|
+
const oldGetter = lastMember.getter;
|
|
73
|
+
lastMember.getter = member;
|
|
74
|
+
toDelete.push(oldGetter);
|
|
75
|
+
continue;
|
|
76
|
+
} else if (kind === 'Setter') {
|
|
77
|
+
const oldSetter = lastMember.setter;
|
|
78
|
+
lastMember.setter = member;
|
|
79
|
+
toDelete.push(oldSetter);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
break;
|
|
84
|
+
|
|
85
|
+
case 'Getter':
|
|
86
|
+
if (kind === 'Setter') {
|
|
87
|
+
lastMember = {
|
|
88
|
+
kind: 'GetterSetter',
|
|
89
|
+
getter: lastMember.member,
|
|
90
|
+
setter: member
|
|
91
|
+
};
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
break;
|
|
96
|
+
|
|
97
|
+
case 'Setter':
|
|
98
|
+
if (kind === 'Getter') {
|
|
99
|
+
lastMember = {
|
|
100
|
+
kind: 'GetterSetter',
|
|
101
|
+
getter: member,
|
|
102
|
+
setter: lastMember.member
|
|
103
|
+
};
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
break;
|
|
108
|
+
} // overwrite and delete the old member as it's incompatible
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
if (lastMember.kind === 'GetterSetter') {
|
|
112
|
+
toDelete.push(lastMember.getter);
|
|
113
|
+
toDelete.push(lastMember.setter);
|
|
114
|
+
} else {
|
|
115
|
+
toDelete.push(lastMember.member);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
lastMember = {
|
|
119
|
+
kind,
|
|
120
|
+
member
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return toDelete;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
var _default = (0, _Types.codemod)({
|
|
129
|
+
title: 'Remove Duplicate Class Properties',
|
|
130
|
+
description: 'Removes useless duplicate class properties and fixes bad constructor binding in those classes',
|
|
131
|
+
transform: context => {
|
|
132
|
+
let classStack = null;
|
|
133
|
+
return {
|
|
134
|
+
// find and delete duplicated members
|
|
135
|
+
'ClassDeclaration, ClassExpression'(node) {
|
|
136
|
+
const staticMembers = new Map();
|
|
137
|
+
const instanceMembers = new Map();
|
|
138
|
+
|
|
139
|
+
for (const member of node.body.body) {
|
|
140
|
+
const membersMap = member.static ? staticMembers : instanceMembers;
|
|
141
|
+
const name = (0, _getClassMemberName.getClassMemberName)(member);
|
|
142
|
+
|
|
143
|
+
if (name == null) {
|
|
144
|
+
// unsupported computed member
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const existingMember = membersMap.get(name);
|
|
149
|
+
|
|
150
|
+
if (existingMember == null) {
|
|
151
|
+
membersMap.set(name, [member]);
|
|
152
|
+
} else {
|
|
153
|
+
existingMember.push(member);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const toDelete = new Set(findDuplicates(staticMembers).concat(findDuplicates(instanceMembers)));
|
|
158
|
+
|
|
159
|
+
if (toDelete.size === 0) {
|
|
160
|
+
return;
|
|
161
|
+
} // mark members for deletion
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
for (const memberToDelete of toDelete) {
|
|
165
|
+
var _memberToDelete$value;
|
|
166
|
+
|
|
167
|
+
if (memberToDelete.type === 'PropertyDefinition' && ((_memberToDelete$value = memberToDelete.value) === null || _memberToDelete$value === void 0 ? void 0 : _memberToDelete$value.type) === 'CallExpression') {
|
|
168
|
+
console.log(context.buildCodeFrame(memberToDelete.value, 'Deleted a property with a CallExpression value. You should double check this was safe.'));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
context.removeNode(memberToDelete);
|
|
172
|
+
} // we need the final list of instance members so we can
|
|
173
|
+
// fix up rebinding later
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
const newInstanceMembers = new Map();
|
|
177
|
+
|
|
178
|
+
for (const member of node.body.body) {
|
|
179
|
+
if (toDelete.has(member)) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (member.static) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const name = (0, _getClassMemberName.getClassMemberName)(member);
|
|
188
|
+
|
|
189
|
+
if (name == null) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const kind = getKind(member);
|
|
194
|
+
newInstanceMembers.set(name, {
|
|
195
|
+
kind,
|
|
196
|
+
member
|
|
197
|
+
});
|
|
198
|
+
} // push the stack
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
classStack = {
|
|
202
|
+
current: node,
|
|
203
|
+
instanceMembers: newInstanceMembers,
|
|
204
|
+
parent: classStack
|
|
205
|
+
};
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
// remove unnecessary .bind in constructor
|
|
209
|
+
'MethodDefinition[kind = "constructor"] ExpressionStatement > AssignmentExpression[operator = "="] > MemberExpression[object.type = "ThisExpression"].left'(node) {
|
|
210
|
+
if (!classStack) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const instanceMembers = classStack.instanceMembers;
|
|
215
|
+
|
|
216
|
+
if (node.property.type !== 'Identifier') {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const subjectName = node.property.name;
|
|
221
|
+
const member = instanceMembers.get(subjectName); // the subject member must be a method
|
|
222
|
+
|
|
223
|
+
if ((member === null || member === void 0 ? void 0 : member.kind) !== 'Method') {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const assignmentExpr = node.parent;
|
|
228
|
+
const exprStatement = assignmentExpr.parent;
|
|
229
|
+
|
|
230
|
+
if (assignmentExpr.type !== 'AssignmentExpression' || exprStatement.type !== 'ExpressionStatement') {
|
|
231
|
+
throw new Error('this cannot happen');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const right = assignmentExpr.right; // we're looking for `this.thing = this.thing.bind(this)`
|
|
235
|
+
|
|
236
|
+
if (right.type !== 'CallExpression' || right.arguments.length !== 1 || right.arguments[0].type !== 'ThisExpression' || right.callee.type !== 'MemberExpression' || right.callee.computed || right.callee.property.type !== 'Identifier' || right.callee.property.name !== 'bind' || right.callee.object.type !== 'MemberExpression' || right.callee.object.computed || right.callee.object.object.type !== 'ThisExpression' || right.callee.object.property.type !== 'Identifier' || right.callee.object.property.name !== subjectName) {
|
|
237
|
+
console.log(context.buildCodeFrame(right, `${subjectName} was reassigned, but not to a bind. You can probably manually correct this.`));
|
|
238
|
+
return;
|
|
239
|
+
} // remove the bind assignment and...
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
context.removeStatement(exprStatement);
|
|
243
|
+
const method = member.member;
|
|
244
|
+
|
|
245
|
+
if (method.type !== 'MethodDefinition') {
|
|
246
|
+
throw new Error('this cannot happen');
|
|
247
|
+
} // convert the method to an arrow function
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
(0, _replaceMethodWithArrowProp.replaceMethodWithArrowProp)(context, method, subjectName);
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
// pop the stack
|
|
254
|
+
'ClassDeclaration, ClassExpression:exit'(node) {
|
|
255
|
+
var _classStack;
|
|
256
|
+
|
|
257
|
+
if (classStack && ((_classStack = classStack) === null || _classStack === void 0 ? void 0 : _classStack.current) === node) {
|
|
258
|
+
var _classStack2;
|
|
259
|
+
|
|
260
|
+
classStack = (_classStack2 = classStack) === null || _classStack2 === void 0 ? void 0 : _classStack2.parent;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
exports.default = _default;
|
package/dist/findFlowFiles.js
CHANGED
|
@@ -1,181 +1,159 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.findFlowFiles = findFlowFiles;
|
|
7
|
+
exports.findFlowFilesWithSpinner = findFlowFilesWithSpinner;
|
|
8
|
+
|
|
9
|
+
var _path = _interopRequireDefault(require("path"));
|
|
10
|
+
|
|
11
|
+
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
12
|
+
|
|
13
|
+
var _ora = _interopRequireDefault(require("ora"));
|
|
14
|
+
|
|
15
|
+
var _chalk = _interopRequireDefault(require("chalk"));
|
|
16
|
+
|
|
17
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
2
18
|
|
|
3
19
|
/**
|
|
20
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
21
|
+
*
|
|
22
|
+
* This source code is licensed under the MIT license found in the
|
|
23
|
+
* LICENSE file in the root directory of this source tree.
|
|
24
|
+
*
|
|
4
25
|
* @format
|
|
5
26
|
*
|
|
6
27
|
*/
|
|
7
28
|
|
|
8
|
-
const path = require('path');
|
|
9
|
-
const fs = require('graceful-fs');
|
|
10
|
-
|
|
11
29
|
/**
|
|
12
30
|
* How many bytes we should look at for the Flow pragma.
|
|
13
31
|
*/
|
|
14
32
|
const PRAGMA_BYTES = 5000;
|
|
15
|
-
|
|
16
33
|
/**
|
|
17
34
|
* Finds all of the Flow files in the provided directory as efficiently as
|
|
18
35
|
* possible.
|
|
19
36
|
*/
|
|
20
|
-
// If we use promises then Node.js will quickly run out of memory on
|
|
21
|
-
// large codebases. Instead we use the callback API.
|
|
22
|
-
module.exports = function findFlowFiles(rootDirectory, options) {
|
|
23
|
-
return new Promise((_resolve, _reject) => {
|
|
24
|
-
// Tracks whether or not we have rejected our promise.
|
|
25
|
-
let rejected = false;
|
|
26
|
-
// How many asynchronous tasks are waiting at the moment.
|
|
27
|
-
let waiting = 0;
|
|
28
|
-
// All the valid file paths that we have found.
|
|
29
|
-
const filePaths = [];
|
|
30
|
-
|
|
31
|
-
// Begin the recursion!
|
|
32
|
-
processDirectory(rootDirectory);
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Process a directory by looking at all of its entries and recursing
|
|
36
|
-
* through child directories as is appropriate.
|
|
37
|
-
*/
|
|
38
|
-
function processDirectory(directory) {
|
|
39
|
-
// If we were rejected then we should not continue.
|
|
40
|
-
if (rejected === true) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
// We are now waiting on this asynchronous task.
|
|
44
|
-
waiting++;
|
|
45
|
-
// Read the directory...
|
|
46
|
-
fs.readdir(directory, (error, fileNames) => {
|
|
47
|
-
if (error) {
|
|
48
|
-
return reject(error);
|
|
49
|
-
}
|
|
50
|
-
// Process every file name that we got from reading the directory.
|
|
51
|
-
for (let i = 0; i < fileNames.length; i++) {
|
|
52
|
-
processFilePath(directory, fileNames[i]);
|
|
53
|
-
}
|
|
54
|
-
// We are done with this async task.
|
|
55
|
-
done();
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
37
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
38
|
+
async function findFlowFiles({
|
|
39
|
+
includeNonAtFlow,
|
|
40
|
+
rootDirectory
|
|
41
|
+
}) {
|
|
42
|
+
// All the valid file paths that we have found.
|
|
43
|
+
const filePaths = []; // Begin the recursion!
|
|
44
|
+
|
|
45
|
+
await processDirectory(rootDirectory);
|
|
46
|
+
return filePaths;
|
|
47
|
+
/**
|
|
48
|
+
* Process a directory by looking at all of its entries and recursing
|
|
49
|
+
* through child directories as is appropriate.
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
async function processDirectory(directory) {
|
|
53
|
+
// Read the directory...
|
|
54
|
+
const fileNames = await _fsExtra.default.readdir(directory); // Process every file name that we got from reading the directory.
|
|
55
|
+
|
|
56
|
+
await Promise.all(fileNames.map(fileName => processFilePath(directory, fileName)));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Process a directory file path by seeing if it is a directory and either
|
|
60
|
+
* recursing or adding it to filePaths.
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
async function processFilePath(directory, fileName) {
|
|
65
|
+
// Get the file file path for this file.
|
|
66
|
+
const filePath = _path.default.join(directory, fileName); // Get the stats for the file.
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
const stats = await _fsExtra.default.lstat(filePath); // If this is a directory...
|
|
70
|
+
|
|
71
|
+
if (stats.isDirectory()) {
|
|
72
|
+
// ...and it is not an ignored directory...
|
|
73
|
+
if (fileName !== 'node_modules' && fileName !== 'flow-typed' && fileName !== '__flowtests__') {
|
|
74
|
+
// ...then recursively process the directory.
|
|
75
|
+
await processDirectory(filePath);
|
|
67
76
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
//
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
// ...and it is not an ignored directory...
|
|
80
|
-
if (fileName !== 'node_modules' && fileName !== 'flow-typed' && fileName !== '__flowtests__') {
|
|
81
|
-
// ...then recursively process the directory.
|
|
82
|
-
processDirectory(filePath);
|
|
83
|
-
}
|
|
84
|
-
} else if (stats.isFile()) {
|
|
85
|
-
// Otherwise if this is a JavaScript/JSX file and it is not an ignored
|
|
86
|
-
// JavaScript file...
|
|
87
|
-
const fileIsJsOrJsx = /\.jsx?$/.test(fileName);
|
|
88
|
-
const fileIsIgnored = fileName.endsWith('-flowtest.js');
|
|
89
|
-
if (fileIsJsOrJsx && !fileIsIgnored) {
|
|
90
|
-
// Then process the file path as JavaScript.
|
|
91
|
-
processJavaScriptFilePath(filePath, stats.size);
|
|
92
|
-
}
|
|
93
|
-
// If this is a Flow file then we don't need to check the file pragma
|
|
94
|
-
// and can add the file to our paths immediately.
|
|
95
|
-
if (fileName.endsWith('.flow')) {
|
|
96
|
-
filePaths.push(filePath);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
// We are done with this async task
|
|
100
|
-
done();
|
|
101
|
-
});
|
|
102
|
-
}
|
|
77
|
+
} else if (stats.isFile()) {
|
|
78
|
+
// Otherwise if this is a JavaScript/JSX file and it is not an ignored
|
|
79
|
+
// JavaScript file...
|
|
80
|
+
const fileIsJsOrJsx = /\.jsx?$/.test(fileName);
|
|
81
|
+
const fileIsIgnored = fileName.endsWith('-flowtest.js');
|
|
82
|
+
|
|
83
|
+
if (fileIsJsOrJsx && !fileIsIgnored) {
|
|
84
|
+
// Then process the file path as JavaScript.
|
|
85
|
+
await processJavaScriptFilePath(filePath, stats.size);
|
|
86
|
+
} // If this is a Flow file then we don't need to check the file pragma
|
|
87
|
+
// and can add the file to our paths immediately.
|
|
103
88
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
* header pragma.
|
|
107
|
-
*/
|
|
108
|
-
function processJavaScriptFilePath(filePath, fileByteSize) {
|
|
109
|
-
// If `all` was configured then we don't need to check for the Flow
|
|
110
|
-
// header pragma.
|
|
111
|
-
if (options.all) {
|
|
89
|
+
|
|
90
|
+
if (fileName.endsWith('.flow')) {
|
|
112
91
|
filePaths.push(filePath);
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
// If we were rejected then we should not continue.
|
|
116
|
-
if (rejected === true) {
|
|
117
|
-
return;
|
|
118
92
|
}
|
|
119
|
-
// We are now waiting on this asynchronous task.
|
|
120
|
-
waiting++;
|
|
121
|
-
// Open the file path.
|
|
122
|
-
fs.open(filePath, 'r', (error, file) => {
|
|
123
|
-
if (error) {
|
|
124
|
-
return reject(error);
|
|
125
|
-
}
|
|
126
|
-
// Get the smaller of our pragma chars constant and the file byte size.
|
|
127
|
-
const bytes = Math.min(PRAGMA_BYTES, fileByteSize);
|
|
128
|
-
// Create the buffer we will read to.
|
|
129
|
-
const buffer = new Buffer(bytes);
|
|
130
|
-
// Read a set number of bytes from the file.
|
|
131
|
-
fs.read(file, buffer, 0, bytes, 0, error => {
|
|
132
|
-
if (error) {
|
|
133
|
-
return reject(error);
|
|
134
|
-
}
|
|
135
|
-
// If the buffer has the pragma then add the file path to our
|
|
136
|
-
// final file paths array.
|
|
137
|
-
if (buffer.includes('@flow')) {
|
|
138
|
-
filePaths.push(filePath);
|
|
139
|
-
}
|
|
140
|
-
// Close the file.
|
|
141
|
-
fs.close(file, error => {
|
|
142
|
-
if (error) {
|
|
143
|
-
return reject(error);
|
|
144
|
-
}
|
|
145
|
-
// We are done with this async task
|
|
146
|
-
done();
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
93
|
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Check if a file path really is a Flow file by looking for the
|
|
97
|
+
* header pragma.
|
|
98
|
+
*/
|
|
151
99
|
|
|
152
|
-
/**
|
|
153
|
-
* Our implementation of resolve that will only actually resolve if we are
|
|
154
|
-
* done waiting everywhere.
|
|
155
|
-
*/
|
|
156
|
-
function done() {
|
|
157
|
-
// We don't care if we were rejected.
|
|
158
|
-
if (rejected === true) {
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
// Decrement the number of async tasks we are waiting on.
|
|
162
|
-
waiting--;
|
|
163
|
-
// If we are finished waiting then we want to resolve our promise.
|
|
164
|
-
if (waiting <= 0) {
|
|
165
|
-
if (waiting === 0) {
|
|
166
|
-
_resolve(filePaths);
|
|
167
|
-
} else {
|
|
168
|
-
reject(new Error(`Expected a positive number: ${waiting}`));
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
100
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
101
|
+
async function processJavaScriptFilePath(filePath, fileByteSize) {
|
|
102
|
+
// If `all` was configured then we don't need to check for the Flow
|
|
103
|
+
// header pragma.
|
|
104
|
+
if (includeNonAtFlow) {
|
|
105
|
+
filePaths.push(filePath);
|
|
106
|
+
return;
|
|
107
|
+
} // Open the file path.
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
const file = await _fsExtra.default.open(filePath, 'r'); // Get the smaller of our pragma chars constant and the file byte size.
|
|
111
|
+
|
|
112
|
+
const bytes = Math.min(PRAGMA_BYTES, fileByteSize); // Create the buffer we will read to.
|
|
113
|
+
|
|
114
|
+
const buffer = Buffer.alloc(bytes); // Read a set number of bytes from the file.
|
|
115
|
+
|
|
116
|
+
await _fsExtra.default.read(file, buffer, 0, bytes, 0); // If the buffer has the pragma then add the file path to our
|
|
117
|
+
// final file paths array.
|
|
118
|
+
|
|
119
|
+
if (buffer.includes('@flow')) {
|
|
120
|
+
filePaths.push(filePath);
|
|
121
|
+
} // Close the file.
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
await _fsExtra.default.close(file);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function findFlowFilesWithSpinner(rootDirectory, options) {
|
|
129
|
+
// Create a new spinner.
|
|
130
|
+
const spinner = (0, _ora.default)({
|
|
131
|
+
text: _chalk.default.italic.cyan('Finding all the Flow files to be upgraded...'),
|
|
132
|
+
color: 'cyan',
|
|
133
|
+
isSilent: options.silent
|
|
134
|
+
}); // Start the spinner.
|
|
135
|
+
|
|
136
|
+
spinner.start(); // Find all of the Flow files in the directory we are upgrading.
|
|
137
|
+
|
|
138
|
+
const filePaths = await (() => {
|
|
139
|
+
try {
|
|
140
|
+
return findFlowFiles({
|
|
141
|
+
rootDirectory,
|
|
142
|
+
includeNonAtFlow: options.all
|
|
143
|
+
});
|
|
144
|
+
} catch (error) {
|
|
145
|
+
// Stop the spinner if we get an error.
|
|
146
|
+
spinner.stop();
|
|
147
|
+
throw error;
|
|
179
148
|
}
|
|
180
|
-
});
|
|
181
|
-
|
|
149
|
+
})(); // Stop the spinner.
|
|
150
|
+
|
|
151
|
+
spinner.stop(); // Log the number of Flow files that we found.
|
|
152
|
+
|
|
153
|
+
if (!options.silent) {
|
|
154
|
+
console.log(`Found ${_chalk.default.bold.cyan(filePaths.length)} Flow files.`);
|
|
155
|
+
console.log();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return filePaths;
|
|
159
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = runCodemods;
|
|
7
|
+
|
|
8
|
+
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
9
|
+
|
|
10
|
+
var _hermesTransform = require("hermes-transform");
|
|
11
|
+
|
|
12
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
16
|
+
*
|
|
17
|
+
* This source code is licensed under the MIT license found in the
|
|
18
|
+
* LICENSE file in the root directory of this source tree.
|
|
19
|
+
*
|
|
20
|
+
* @format
|
|
21
|
+
*
|
|
22
|
+
*/
|
|
23
|
+
async function runCodemods(codemods, filePaths, options) {
|
|
24
|
+
const results = await Promise.allSettled(filePaths.map(async filePath => {
|
|
25
|
+
const originalContents = await _fsExtra.default.readFile(filePath, 'utf8');
|
|
26
|
+
let contents = originalContents;
|
|
27
|
+
|
|
28
|
+
for (const codemod of codemods) {
|
|
29
|
+
contents = (0, _hermesTransform.transform)(contents, codemod.transform, options.prettierOptions);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (originalContents !== contents) {
|
|
33
|
+
await _fsExtra.default.writeFile(filePath, contents, 'utf8');
|
|
34
|
+
}
|
|
35
|
+
}));
|
|
36
|
+
}
|