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
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A utility for upgrading your codebase to the latest version of Flow.
|
|
4
4
|
|
|
5
|
-
To run this utility to upgrade your codebase you can use
|
|
5
|
+
To run this utility to upgrade your codebase you can use `yarn create`:
|
|
6
6
|
|
|
7
7
|
[`yarn create`]: https://yarnpkg.com/en/docs/cli/create#search
|
|
8
8
|
|
|
@@ -17,7 +17,7 @@ yarn global add flow-upgrade
|
|
|
17
17
|
flow-upgrade
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
You may also use
|
|
20
|
+
You may also use `npx`:
|
|
21
21
|
|
|
22
22
|
[`npx`]: https://www.npmjs.com/package/npx
|
|
23
23
|
|
|
@@ -25,11 +25,23 @@ You may also use [`npx`][]:
|
|
|
25
25
|
npx flow-upgrade
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
We expect `prettier` to be installed as a [peer dependency](https://docs.npmjs.com/cli/v8/configuring-npm/package-json#peerdependencies) wherever you are running `flow-upgrade`.
|
|
29
|
+
|
|
28
30
|
## Options
|
|
29
31
|
|
|
32
|
+
### `all`
|
|
33
|
+
|
|
30
34
|
By default, Flow will only upgrade files that have an `// @flow` header comment.
|
|
31
35
|
If you want to upgrade all of your JavaScript files you may pass in the `--all`:
|
|
32
36
|
|
|
33
37
|
```
|
|
34
38
|
yarn create flow-upgrade --all
|
|
35
39
|
```
|
|
40
|
+
|
|
41
|
+
### `prettierrc`
|
|
42
|
+
|
|
43
|
+
Path to a `.prettierrc` file to use.
|
|
44
|
+
Upgrade codemods rely upon [`prettier`][] to print the resulting code after transformation.
|
|
45
|
+
If this is not provided, we will just use the defaults.
|
|
46
|
+
|
|
47
|
+
[`prettier`]: https://www.npmjs.com/package/prettier
|
package/dist/Styled.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*
|
|
4
9
|
* @format
|
|
5
10
|
*
|
|
6
11
|
*/
|
|
7
|
-
|
|
8
12
|
const chalk = require('chalk');
|
|
9
13
|
|
|
10
14
|
exports.divider = function divider() {
|
|
@@ -20,22 +24,16 @@ exports.upgradeTitle = function upgradeTitle(title, n) {
|
|
|
20
24
|
};
|
|
21
25
|
|
|
22
26
|
exports.codeblock = function codeblock(code) {
|
|
23
|
-
return code
|
|
24
|
-
// Add
|
|
25
|
-
.split('\n').map(line => ` ${line}`).join('\n')
|
|
26
|
-
// Add highlighting for puncuation. We need to do this first otherwise it
|
|
27
|
+
return code // Add indentation to the beginning of every line of code.
|
|
28
|
+
.split('\n').map(line => ` ${line}`).join('\n') // Add highlighting for puncuation. We need to do this first otherwise it
|
|
27
29
|
// breaks the other colors.
|
|
28
|
-
.replace(/([={}()\[\];<>,:.*/])/g, chalk.grey('$1'))
|
|
29
|
-
// Add highlighting for
|
|
30
|
-
.replace(/(import|from|typeof|type|class|extends|static|return|function)/g, chalk.magenta('$1'))
|
|
31
|
-
// Add highlighting for strings.
|
|
30
|
+
.replace(/([={}()\[\];<>,:.*/])/g, chalk.grey('$1')) // Add highlighting for reserved keywords.
|
|
31
|
+
.replace(/(import|from|typeof|type|class|extends|static|return|function)/g, chalk.magenta('$1')) // Add highlighting for strings.
|
|
32
32
|
.replace(/('[^\n]*')/g, chalk.green('$1'));
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
exports.list = function list(items) {
|
|
36
|
-
return items.map(item =>
|
|
37
|
-
|
|
38
|
-
item.split('\n').map((line, i) => `${i === 0 ? chalk.grey('- ') : ' '}${line}`).join('\n'))
|
|
39
|
-
// Combine all of our items into one list string.
|
|
36
|
+
return items.map(item => // Indent every item and add a `- ` to the beginning of each line.
|
|
37
|
+
item.split('\n').map((line, i) => `${i === 0 ? chalk.grey('- ') : ' '}${line}`).join('\n')) // Combine all of our items into one list string.
|
|
40
38
|
.join('\n');
|
|
41
39
|
};
|
package/dist/Types.js
CHANGED
|
@@ -1 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.codemod = codemod;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
10
|
+
*
|
|
11
|
+
* This source code is licensed under the MIT license found in the
|
|
12
|
+
* LICENSE file in the root directory of this source tree.
|
|
13
|
+
*
|
|
14
|
+
* @format
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
17
|
+
function codemod(config) {
|
|
18
|
+
return { ...config,
|
|
19
|
+
kind: 'codemod'
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @format
|
|
10
|
+
*
|
|
11
|
+
*/
|
|
12
|
+
"use strict";
|
|
13
|
+
|
|
14
|
+
var _chalk = _interopRequireDefault(require("chalk"));
|
|
15
|
+
|
|
16
|
+
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
17
|
+
|
|
18
|
+
var _yargs = _interopRequireDefault(require("yargs/yargs"));
|
|
19
|
+
|
|
20
|
+
var _upgrade = _interopRequireDefault(require("../upgrade"));
|
|
21
|
+
|
|
22
|
+
var _path = _interopRequireDefault(require("path"));
|
|
23
|
+
|
|
24
|
+
var _findFlowFiles = require("../findFlowFiles");
|
|
25
|
+
|
|
26
|
+
var _runCodemods = _interopRequireDefault(require("../runCodemods"));
|
|
27
|
+
|
|
28
|
+
var _Styled = _interopRequireDefault(require("../Styled"));
|
|
29
|
+
|
|
30
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
31
|
+
|
|
32
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
33
|
+
|
|
34
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
35
|
+
|
|
36
|
+
const CODEMOD_DIR = _path.default.resolve(__dirname, '..', 'codemods');
|
|
37
|
+
|
|
38
|
+
async function main(args) {
|
|
39
|
+
const codemodNames = _fsExtra.default.readdirSync(CODEMOD_DIR, {
|
|
40
|
+
withFileTypes: false
|
|
41
|
+
}).map(f => _path.default.parse(f).name);
|
|
42
|
+
|
|
43
|
+
const yargs = (0, _yargs.default)(args).usage('Usage: flow-upgrade-codemod <codemod name>').positional('codemod name', {
|
|
44
|
+
describe: 'Your current flow version',
|
|
45
|
+
choices: codemodNames
|
|
46
|
+
}).options({
|
|
47
|
+
all: {
|
|
48
|
+
type: 'boolean',
|
|
49
|
+
describe: 'Include all files, not just those with the @flow pragma'
|
|
50
|
+
},
|
|
51
|
+
prettierrc: {
|
|
52
|
+
type: 'string',
|
|
53
|
+
describe: 'The path to a `.prettierrc` file for formatting the output.',
|
|
54
|
+
requiresArg: true
|
|
55
|
+
},
|
|
56
|
+
silent: {
|
|
57
|
+
type: 'boolean',
|
|
58
|
+
describe: 'Disable console log output.'
|
|
59
|
+
},
|
|
60
|
+
yes: {
|
|
61
|
+
type: 'boolean',
|
|
62
|
+
describe: 'Answer yes to all prompts.'
|
|
63
|
+
}
|
|
64
|
+
}).demandCommand(1).help('help').argv;
|
|
65
|
+
const prettierOptions = await (() => {
|
|
66
|
+
if (!yargs.prettierrc) {
|
|
67
|
+
return {};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return _fsExtra.default.readJSON(yargs.prettierrc);
|
|
71
|
+
})();
|
|
72
|
+
const options = {
|
|
73
|
+
all: !!yargs.all,
|
|
74
|
+
prettierOptions,
|
|
75
|
+
silent: !!yargs.silent,
|
|
76
|
+
yes: !!yargs.yes
|
|
77
|
+
};
|
|
78
|
+
const codemodName = yargs._[0];
|
|
79
|
+
const directory = process.cwd();
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const filePaths = await (0, _findFlowFiles.findFlowFilesWithSpinner)(directory, options); // $FlowExpectedError[unsupported-syntax]
|
|
83
|
+
|
|
84
|
+
const {
|
|
85
|
+
default: upgrade
|
|
86
|
+
} = await Promise.resolve(`${CODEMOD_DIR}/${codemodName}.js`).then(s => _interopRequireWildcard(require(s))); // Tell the user what we are about to do.
|
|
87
|
+
|
|
88
|
+
if (!options.silent) {
|
|
89
|
+
console.log(_Styled.default.sectionHeader('Codemods'));
|
|
90
|
+
console.log();
|
|
91
|
+
console.log('We are now going to run the following codemods:');
|
|
92
|
+
console.log();
|
|
93
|
+
console.log(_Styled.default.upgradeTitle(upgrade.title, 1));
|
|
94
|
+
console.log();
|
|
95
|
+
console.log(upgrade.description);
|
|
96
|
+
console.log();
|
|
97
|
+
console.log(_Styled.default.divider());
|
|
98
|
+
console.log();
|
|
99
|
+
console.log(`Running ${_chalk.default.bold.cyan(1)} codemod...`);
|
|
100
|
+
console.log();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
switch (upgrade.kind) {
|
|
104
|
+
case 'codemod':
|
|
105
|
+
await (0, _runCodemods.default)([upgrade], filePaths, options);
|
|
106
|
+
break;
|
|
107
|
+
// Throw an error for all other kinds of upgrades.
|
|
108
|
+
|
|
109
|
+
default:
|
|
110
|
+
throw new Error(`Unexpected upgrade kind: '${upgrade.kind}'`);
|
|
111
|
+
}
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error(_chalk.default.red(error ? error.stack || error : error));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
void main(process.argv.slice(2));
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @format
|
|
10
|
+
*
|
|
11
|
+
*/
|
|
12
|
+
"use strict";
|
|
13
|
+
|
|
14
|
+
var _chalk = _interopRequireDefault(require("chalk"));
|
|
15
|
+
|
|
16
|
+
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
17
|
+
|
|
18
|
+
var _yargs = _interopRequireDefault(require("yargs/yargs"));
|
|
19
|
+
|
|
20
|
+
var _upgrade = _interopRequireDefault(require("../upgrade"));
|
|
21
|
+
|
|
22
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
23
|
+
|
|
24
|
+
async function main(args) {
|
|
25
|
+
const yargs = (0, _yargs.default)(args).usage('Usage: flow-upgrade <current version> <target version>').positional('current version', {
|
|
26
|
+
describe: 'Your current flow version'
|
|
27
|
+
}).positional('target version', {
|
|
28
|
+
describe: 'The flow version you are upgrading to'
|
|
29
|
+
}).options({
|
|
30
|
+
all: {
|
|
31
|
+
type: 'boolean',
|
|
32
|
+
describe: 'Include all files, not just those with the @flow pragma'
|
|
33
|
+
},
|
|
34
|
+
prettierrc: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
describe: 'The path to a `.prettierrc` file for formatting the output.',
|
|
37
|
+
requiresArg: true
|
|
38
|
+
},
|
|
39
|
+
silent: {
|
|
40
|
+
type: 'boolean',
|
|
41
|
+
describe: 'Disable console log output.'
|
|
42
|
+
},
|
|
43
|
+
yes: {
|
|
44
|
+
type: 'boolean',
|
|
45
|
+
describe: 'Answer yes to all prompts.'
|
|
46
|
+
}
|
|
47
|
+
}).demandCommand(2).help('help').argv;
|
|
48
|
+
const prettierOptions = await (() => {
|
|
49
|
+
if (!yargs.prettierrc) {
|
|
50
|
+
return {};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return _fsExtra.default.readJSON(yargs.prettierrc);
|
|
54
|
+
})();
|
|
55
|
+
const options = {
|
|
56
|
+
all: !!yargs.all,
|
|
57
|
+
prettierOptions,
|
|
58
|
+
silent: !!yargs.silent,
|
|
59
|
+
yes: !!yargs.yes
|
|
60
|
+
}; // For now we are asking for the version numbers out of convenience. When we add
|
|
61
|
+
// upgrades for future versions we will need to check `.flowconfig` or
|
|
62
|
+
// `flow-bin` for the current version and allow the new version to be
|
|
63
|
+
// configurable. (But still default to the latest version.)
|
|
64
|
+
|
|
65
|
+
const fromVersion = yargs._[0];
|
|
66
|
+
const toVersion = yargs._[1];
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
await (0, _upgrade.default)(process.cwd(), fromVersion, toVersion, options);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error(_chalk.default.red(error ? error.stack || error : error));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
void main(process.argv.slice(2));
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getClassMemberName = getClassMemberName;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
10
|
+
*
|
|
11
|
+
* This source code is licensed under the MIT license found in the
|
|
12
|
+
* LICENSE file in the root directory of this source tree.
|
|
13
|
+
*
|
|
14
|
+
* @format
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
17
|
+
function getClassMemberName(member) {
|
|
18
|
+
if (member.key.type === 'PrivateIdentifier') {
|
|
19
|
+
return `#${member.key.name}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (member.computed === true || member.key.type !== 'Identifier') {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return member.key.name;
|
|
27
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.replaceMethodWithArrowProp = replaceMethodWithArrowProp;
|
|
7
|
+
|
|
8
|
+
var _hermesTransform = require("hermes-transform");
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
12
|
+
*
|
|
13
|
+
* This source code is licensed under the MIT license found in the
|
|
14
|
+
* LICENSE file in the root directory of this source tree.
|
|
15
|
+
*
|
|
16
|
+
* @format
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Converts method definition to an arrow function property
|
|
22
|
+
* ```
|
|
23
|
+
* method<T>(arg) { ... }
|
|
24
|
+
* // to
|
|
25
|
+
* +method = <T>(arg) => { ... };
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
function replaceMethodWithArrowProp(context, method, name) {
|
|
29
|
+
context.replaceNode(method, _hermesTransform.t.PropertyDefinition({
|
|
30
|
+
computed: false,
|
|
31
|
+
declare: false,
|
|
32
|
+
key: _hermesTransform.t.Identifier({
|
|
33
|
+
name,
|
|
34
|
+
// for types-first compliance, this should ideally be filled out for
|
|
35
|
+
// non-private members. However it's *super* complicated to correctly
|
|
36
|
+
// handle these cases statically (type parameters and default args make
|
|
37
|
+
// it hard).
|
|
38
|
+
// So instead we just ignore it and they can be filled later using a
|
|
39
|
+
// type-aware codemod like
|
|
40
|
+
// ```
|
|
41
|
+
// flow codemod annotate-exports --write --munge-underscore-members --max-type-size 25
|
|
42
|
+
// ```
|
|
43
|
+
typeAnnotation: null
|
|
44
|
+
}),
|
|
45
|
+
optional: false,
|
|
46
|
+
static: false,
|
|
47
|
+
value: _hermesTransform.t.ArrowFunctionExpression({
|
|
48
|
+
async: method.value.async,
|
|
49
|
+
body: method.value.body,
|
|
50
|
+
params: method.value.params,
|
|
51
|
+
predicate: method.value.predicate,
|
|
52
|
+
typeParameters: method.value.typeParameters,
|
|
53
|
+
returnType: method.value.returnType
|
|
54
|
+
}),
|
|
55
|
+
// methods are readonly, so we mark the property as readonly as well
|
|
56
|
+
variance: _hermesTransform.t.Variance({
|
|
57
|
+
kind: 'plus'
|
|
58
|
+
})
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
|
|
8
|
+
var _hermesTransform = require("hermes-transform");
|
|
9
|
+
|
|
10
|
+
var _Types = require("../Types");
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
14
|
+
*
|
|
15
|
+
* This source code is licensed under the MIT license found in the
|
|
16
|
+
* LICENSE file in the root directory of this source tree.
|
|
17
|
+
*
|
|
18
|
+
* @format
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
var _default = (0, _Types.codemod)({
|
|
22
|
+
title: 'Collapse Object Initialization',
|
|
23
|
+
description: 'Converts static object assignments to inline properties',
|
|
24
|
+
transform: context => {
|
|
25
|
+
function getStatementContainerArray(stmtNode) {
|
|
26
|
+
const parent = stmtNode.parent;
|
|
27
|
+
|
|
28
|
+
switch (parent.type) {
|
|
29
|
+
case 'SwitchCase':
|
|
30
|
+
{
|
|
31
|
+
return parent.consequent;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
case 'BlockStatement':
|
|
35
|
+
{
|
|
36
|
+
return parent.body;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
case 'Program':
|
|
40
|
+
{
|
|
41
|
+
// $FlowIgnore[incompatible-return]
|
|
42
|
+
return parent.body;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
default:
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function getNextSibling(node) {
|
|
51
|
+
if (node == null) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const parentContainer = getStatementContainerArray(node);
|
|
56
|
+
|
|
57
|
+
if (parentContainer == null) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const nodeIndex = parentContainer.indexOf(node);
|
|
62
|
+
|
|
63
|
+
if (nodeIndex === -1) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return parentContainer[nodeIndex + 1];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function containsReference(node, references) {
|
|
71
|
+
return references.some(reference => {
|
|
72
|
+
const refRange = reference.identifier.range;
|
|
73
|
+
return node.range[0] <= refRange[0] && refRange[1] <= node.range[1];
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function processStmtNode(idNode, references, stmtNode) {
|
|
78
|
+
if (stmtNode.type !== 'ExpressionStatement') {
|
|
79
|
+
return {
|
|
80
|
+
type: 'abort'
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const exprNode = stmtNode.expression;
|
|
85
|
+
|
|
86
|
+
if (exprNode.type !== 'AssignmentExpression') {
|
|
87
|
+
return {
|
|
88
|
+
type: 'abort'
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const leftNode = exprNode.left;
|
|
93
|
+
|
|
94
|
+
if (leftNode.type !== 'MemberExpression') {
|
|
95
|
+
return {
|
|
96
|
+
type: 'abort'
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const exprRightNode = exprNode.right;
|
|
101
|
+
|
|
102
|
+
if (containsReference(exprRightNode, references)) {
|
|
103
|
+
return {
|
|
104
|
+
type: 'abort'
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const memberObjectNode = leftNode.object;
|
|
109
|
+
const memberPropertyNode = leftNode.property;
|
|
110
|
+
|
|
111
|
+
if (memberObjectNode.type === 'Identifier' && memberObjectNode.name === idNode.name && memberPropertyNode.type === 'Identifier') {
|
|
112
|
+
const shorthand = !leftNode.computed && exprRightNode.type === 'Identifier' && exprRightNode.name === memberPropertyNode.name; // $FlowIgnore[incompatible-type-arg] You gonna have to trust me
|
|
113
|
+
|
|
114
|
+
const property = _hermesTransform.t.Property({
|
|
115
|
+
key: memberPropertyNode,
|
|
116
|
+
value: exprRightNode,
|
|
117
|
+
computed: leftNode.computed,
|
|
118
|
+
kind: 'init',
|
|
119
|
+
method: false,
|
|
120
|
+
// $FlowIgnore[incompatible-call]
|
|
121
|
+
shorthand
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
type: 'property',
|
|
126
|
+
keyName: memberPropertyNode.name,
|
|
127
|
+
property,
|
|
128
|
+
computed: leftNode.computed
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
type: 'abort'
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function isWriteToObject(ref) {
|
|
138
|
+
let currNode = ref.identifier;
|
|
139
|
+
|
|
140
|
+
while (currNode.parent.type === 'MemberExpression' && currNode.parent.object === currNode) {
|
|
141
|
+
currNode = currNode.parent;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return currNode.parent.type === 'AssignmentExpression';
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
VariableDeclarator(node) {
|
|
149
|
+
const initNode = node.init;
|
|
150
|
+
|
|
151
|
+
if (initNode == null || initNode.type !== 'ObjectExpression' || initNode.properties.length > 0) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const idNode = node.id;
|
|
156
|
+
|
|
157
|
+
if (idNode.type !== 'Identifier' || idNode.typeAnnotation != null) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const stmtNode = node.parent;
|
|
162
|
+
|
|
163
|
+
if (stmtNode.type !== 'VariableDeclaration') {
|
|
164
|
+
throw new Error(context.buildCodeFrame(stmtNode, `This is not right, parent of VariableDeclarator should always be a VariableDeclaration, instead got a "${stmtNode.type}"`));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const binding = context.getBinding(idNode.name);
|
|
168
|
+
|
|
169
|
+
if (binding == null) {
|
|
170
|
+
throw new Error(context.buildCodeFrame(idNode, `No binding found for node of name "${idNode.name}"`));
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
let nextStmtNode = stmtNode;
|
|
174
|
+
let finish = false;
|
|
175
|
+
const objectProperties = [];
|
|
176
|
+
|
|
177
|
+
while (finish !== true && (nextStmtNode = getNextSibling(nextStmtNode)) && nextStmtNode != null) {
|
|
178
|
+
const out = processStmtNode(idNode, binding.references, nextStmtNode);
|
|
179
|
+
|
|
180
|
+
switch (out.type) {
|
|
181
|
+
case 'abort':
|
|
182
|
+
{
|
|
183
|
+
finish = true;
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
case 'skip':
|
|
188
|
+
{
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
case 'property':
|
|
193
|
+
{
|
|
194
|
+
const {
|
|
195
|
+
type: _type,
|
|
196
|
+
...rest
|
|
197
|
+
} = out;
|
|
198
|
+
objectProperties.push([rest, nextStmtNode]);
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (objectProperties.length > 0) {
|
|
205
|
+
const assignmentRefsCount = binding.references.reduce((acc, ref) => {
|
|
206
|
+
if (isWriteToObject(ref)) {
|
|
207
|
+
return acc + 1;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return acc;
|
|
211
|
+
}, 0);
|
|
212
|
+
|
|
213
|
+
if (assignmentRefsCount !== objectProperties.length) {
|
|
214
|
+
console.error(context.buildCodeFrame(stmtNode, 'Object had non inlinable and inlineable properties')); // If you don't wish to codemod these mixed objects return here.
|
|
215
|
+
// return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const keyNames = new Set();
|
|
219
|
+
|
|
220
|
+
for (const [{
|
|
221
|
+
keyName,
|
|
222
|
+
computed
|
|
223
|
+
}, _] of objectProperties) {
|
|
224
|
+
const name = `${computed ? 'c' : 'v'}-${keyName}`;
|
|
225
|
+
|
|
226
|
+
if (keyNames.has(name)) {
|
|
227
|
+
console.error(context.buildCodeFrame(stmtNode, `Object has duplicate key of "${keyName}"`));
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
keyNames.add(name);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const newProperties = objectProperties.map(([{
|
|
235
|
+
property
|
|
236
|
+
}, _]) => property);
|
|
237
|
+
context.replaceNode(initNode, _hermesTransform.t.ObjectExpression({
|
|
238
|
+
properties: newProperties
|
|
239
|
+
}));
|
|
240
|
+
objectProperties.forEach(([_, stmtToRemove]) => {
|
|
241
|
+
context.removeStatement(stmtToRemove);
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
exports.default = _default;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
|
|
8
|
+
var _Types = require("../Types");
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
12
|
+
*
|
|
13
|
+
* This source code is licensed under the MIT license found in the
|
|
14
|
+
* LICENSE file in the root directory of this source tree.
|
|
15
|
+
*
|
|
16
|
+
* @format
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
var _default = (0, _Types.codemod)({
|
|
20
|
+
title: 'Make implicitly inexact object types explicitly inexact',
|
|
21
|
+
description: 'Convert implicitly inexact object type syntax `{}` to explicitly inexact `{...}`',
|
|
22
|
+
transform: context => {
|
|
23
|
+
return {
|
|
24
|
+
':not(InterfaceDeclaration, InterfaceTypeAnnotation, DeclareInterface, DeclareClass) > ObjectTypeAnnotation[inexact=false][exact=false]'(node) {
|
|
25
|
+
// $FlowFixMe[incompatible-call] `inexact` can be true, as is the case with `{...}`
|
|
26
|
+
context.modifyNodeInPlace(node, {
|
|
27
|
+
inexact: true
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
exports.default = _default;
|