hermes-transform 0.8.0 → 0.10.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/ESLINT_LICENCE +19 -0
- package/PRETTIER_LICENCE +7 -0
- package/dist/detachedNode.js +100 -42
- package/dist/detachedNode.js.flow +116 -41
- package/dist/generated/TransformCloneSignatures.js.flow +18 -0
- package/dist/generated/TransformModifySignatures.js.flow +1127 -0
- package/dist/generated/TransformReplaceSignatures.js.flow +15 -1
- package/dist/generated/node-types.js +852 -883
- package/dist/generated/node-types.js.flow +1187 -1217
- package/dist/generated/special-case-node-types/Comment.js +36 -0
- package/dist/generated/special-case-node-types/Comment.js.flow +36 -0
- package/dist/generated/special-case-node-types/DeclareExportDeclaration.js +55 -0
- package/dist/generated/special-case-node-types/DeclareExportDeclaration.js.flow +97 -0
- package/dist/generated/special-case-node-types/ExportNamedDeclaration.js +42 -0
- package/dist/generated/special-case-node-types/ExportNamedDeclaration.js.flow +75 -0
- package/dist/generated/special-case-node-types/Literal.js +97 -0
- package/dist/generated/special-case-node-types/Literal.js.flow +139 -0
- package/dist/generated/special-case-node-types/ObjectTypeProperty.js +73 -0
- package/dist/generated/special-case-node-types/ObjectTypeProperty.js.flow +107 -0
- package/dist/generated/special-case-node-types/Property.js +136 -0
- package/dist/generated/special-case-node-types/Property.js.flow +237 -0
- package/dist/generated/special-case-node-types/misc.js +119 -0
- package/dist/generated/special-case-node-types/misc.js.flow +205 -0
- package/dist/generated/special-case-node-types.js +42 -180
- package/dist/generated/special-case-node-types.js.flow +7 -258
- package/dist/index.js +19 -3
- package/dist/index.js.flow +6 -2
- package/dist/transform/TransformContext.js +34 -11
- package/dist/transform/TransformContext.js.flow +90 -33
- package/dist/transform/comments/comments.js +34 -5
- package/dist/transform/comments/comments.js.flow +39 -4
- package/dist/transform/comments/prettier/main/comments.js +1 -1
- package/dist/transform/comments/prettier/main/comments.js.flow +2 -1
- package/dist/transform/mutations/InsertStatement.js +4 -3
- package/dist/transform/mutations/InsertStatement.js.flow +4 -3
- package/dist/transform/mutations/RemoveComment.js +3 -3
- package/dist/transform/mutations/RemoveComment.js.flow +3 -5
- package/dist/transform/mutations/RemoveNode.js +2 -2
- package/dist/transform/mutations/RemoveNode.js.flow +2 -2
- package/dist/transform/mutations/RemoveStatement.js +2 -2
- package/dist/transform/mutations/RemoveStatement.js.flow +2 -2
- package/dist/transform/mutations/ReplaceNode.js +10 -7
- package/dist/transform/mutations/ReplaceNode.js.flow +7 -5
- package/dist/transform/mutations/ReplaceStatementWithMany.js +2 -2
- package/dist/transform/mutations/ReplaceStatementWithMany.js.flow +7 -4
- package/dist/transform/mutations/utils/getStatementParent.js +3 -2
- package/dist/transform/mutations/utils/getStatementParent.js.flow +5 -2
- package/dist/transform/parse.js +55 -0
- package/dist/transform/parse.js.flow +55 -0
- package/dist/transform/print.js +160 -0
- package/dist/transform/print.js.flow +176 -0
- package/dist/transform/transform.js +6 -67
- package/dist/transform/transform.js.flow +6 -69
- package/dist/transform/{getTransformedAST.js → transformAST.js} +7 -16
- package/dist/transform/{getTransformedAST.js.flow → transformAST.js.flow} +7 -14
- package/dist/traverse/NodeEventGenerator.js.flow +1 -1
- package/dist/traverse/traverse.js +36 -35
- package/dist/traverse/traverse.js.flow +46 -27
- package/package.json +10 -5
- package/dist/getVisitorKeys.js +0 -33
- package/dist/getVisitorKeys.js.flow +0 -31
- package/dist/transform/mutations/utils/arrayUtils.js +0 -43
- package/dist/transform/mutations/utils/arrayUtils.js.flow +0 -50
- package/dist/traverse/SimpleTraverser.js +0 -118
- package/dist/traverse/SimpleTraverser.js.flow +0 -112
|
@@ -14,84 +14,23 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
14
14
|
});
|
|
15
15
|
exports.transform = transform;
|
|
16
16
|
|
|
17
|
-
var
|
|
17
|
+
var _transformAST = require("./transformAST");
|
|
18
18
|
|
|
19
|
-
var
|
|
19
|
+
var _parse = require("./parse");
|
|
20
20
|
|
|
21
|
-
var
|
|
22
|
-
|
|
23
|
-
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); }
|
|
24
|
-
|
|
25
|
-
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; }
|
|
21
|
+
var _print = require("./print");
|
|
26
22
|
|
|
27
23
|
function transform(originalCode, visitors, prettierOptions = {}) {
|
|
24
|
+
const parseResult = (0, _parse.parse)(originalCode);
|
|
28
25
|
const {
|
|
29
26
|
ast,
|
|
30
27
|
astWasMutated,
|
|
31
28
|
mutatedCode
|
|
32
|
-
} = (0,
|
|
29
|
+
} = (0, _transformAST.transformAST)(parseResult, visitors);
|
|
33
30
|
|
|
34
31
|
if (!astWasMutated) {
|
|
35
32
|
return originalCode;
|
|
36
33
|
}
|
|
37
34
|
|
|
38
|
-
|
|
39
|
-
enter(node) {
|
|
40
|
-
// prettier fully expects the parent pointers are NOT set and
|
|
41
|
-
// certain cases can crash due to prettier infinite-looping
|
|
42
|
-
// whilst naively traversing the parent property
|
|
43
|
-
// https://github.com/prettier/prettier/issues/11793
|
|
44
|
-
// $FlowExpectedError[cannot-write]
|
|
45
|
-
delete node.parent; // prettier currently relies on the AST being in the old-school, deprecated AST format for optional chaining
|
|
46
|
-
// so we have to apply their transform to our AST so it can actually format it.
|
|
47
|
-
|
|
48
|
-
if (node.type === 'ChainExpression') {
|
|
49
|
-
const newNode = transformChainExpression(node.expression); // $FlowExpectedError[cannot-write]
|
|
50
|
-
|
|
51
|
-
delete node.expression; // $FlowExpectedError[prop-missing]
|
|
52
|
-
// $FlowExpectedError[cannot-write]
|
|
53
|
-
|
|
54
|
-
Object.assign(node, newNode);
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
|
|
58
|
-
leave() {}
|
|
59
|
-
|
|
60
|
-
}); // we need to delete the comments prop or else prettier will do
|
|
61
|
-
// its own attachment pass after the mutation and duplicate the
|
|
62
|
-
// comments on each node, borking the output
|
|
63
|
-
// $FlowExpectedError[cannot-write]
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
delete ast.comments;
|
|
67
|
-
return prettier.format(mutatedCode, // $FlowExpectedError[incompatible-exact] - we don't want to create a dependency on the prettier types
|
|
68
|
-
{ ...prettierOptions,
|
|
69
|
-
|
|
70
|
-
parser() {
|
|
71
|
-
return ast;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
});
|
|
75
|
-
} // https://github.com/prettier/prettier/blob/d962466a828f8ef51435e3e8840178d90b7ec6cd/src/language-js/parse/postprocess/index.js#L161-L182
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
function transformChainExpression(node) {
|
|
79
|
-
switch (node.type) {
|
|
80
|
-
case 'CallExpression':
|
|
81
|
-
// $FlowExpectedError[cannot-write]
|
|
82
|
-
node.type = 'OptionalCallExpression'; // $FlowExpectedError[cannot-write]
|
|
83
|
-
|
|
84
|
-
node.callee = transformChainExpression(node.callee);
|
|
85
|
-
break;
|
|
86
|
-
|
|
87
|
-
case 'MemberExpression':
|
|
88
|
-
// $FlowExpectedError[cannot-write]
|
|
89
|
-
node.type = 'OptionalMemberExpression'; // $FlowExpectedError[cannot-write]
|
|
90
|
-
|
|
91
|
-
node.object = transformChainExpression(node.object);
|
|
92
|
-
break;
|
|
93
|
-
// No default
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return node;
|
|
35
|
+
return (0, _print.print)(ast, mutatedCode, prettierOptions);
|
|
97
36
|
}
|
|
@@ -10,13 +10,12 @@
|
|
|
10
10
|
|
|
11
11
|
'use strict';
|
|
12
12
|
|
|
13
|
-
import type {ESNode} from 'hermes-estree';
|
|
14
13
|
import type {Visitor} from '../traverse/traverse';
|
|
15
14
|
import type {TransformContextAdditions} from './TransformContext';
|
|
16
15
|
|
|
17
|
-
import
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
16
|
+
import {transformAST} from './transformAST';
|
|
17
|
+
import {parse} from './parse';
|
|
18
|
+
import {print} from './print';
|
|
20
19
|
|
|
21
20
|
export type TransformVisitor = Visitor<TransformContextAdditions>;
|
|
22
21
|
|
|
@@ -25,74 +24,12 @@ export function transform(
|
|
|
25
24
|
visitors: TransformVisitor,
|
|
26
25
|
prettierOptions: {...} = {},
|
|
27
26
|
): string {
|
|
28
|
-
const
|
|
29
|
-
originalCode,
|
|
30
|
-
visitors,
|
|
31
|
-
);
|
|
27
|
+
const parseResult = parse(originalCode);
|
|
32
28
|
|
|
29
|
+
const {ast, astWasMutated, mutatedCode} = transformAST(parseResult, visitors);
|
|
33
30
|
if (!astWasMutated) {
|
|
34
31
|
return originalCode;
|
|
35
32
|
}
|
|
36
33
|
|
|
37
|
-
|
|
38
|
-
enter(node) {
|
|
39
|
-
// prettier fully expects the parent pointers are NOT set and
|
|
40
|
-
// certain cases can crash due to prettier infinite-looping
|
|
41
|
-
// whilst naively traversing the parent property
|
|
42
|
-
// https://github.com/prettier/prettier/issues/11793
|
|
43
|
-
// $FlowExpectedError[cannot-write]
|
|
44
|
-
delete node.parent;
|
|
45
|
-
|
|
46
|
-
// prettier currently relies on the AST being in the old-school, deprecated AST format for optional chaining
|
|
47
|
-
// so we have to apply their transform to our AST so it can actually format it.
|
|
48
|
-
if (node.type === 'ChainExpression') {
|
|
49
|
-
const newNode = transformChainExpression(node.expression);
|
|
50
|
-
// $FlowExpectedError[cannot-write]
|
|
51
|
-
delete node.expression;
|
|
52
|
-
// $FlowExpectedError[prop-missing]
|
|
53
|
-
// $FlowExpectedError[cannot-write]
|
|
54
|
-
Object.assign(node, newNode);
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
leave() {},
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// we need to delete the comments prop or else prettier will do
|
|
61
|
-
// its own attachment pass after the mutation and duplicate the
|
|
62
|
-
// comments on each node, borking the output
|
|
63
|
-
// $FlowExpectedError[cannot-write]
|
|
64
|
-
delete ast.comments;
|
|
65
|
-
|
|
66
|
-
return prettier.format(
|
|
67
|
-
mutatedCode,
|
|
68
|
-
// $FlowExpectedError[incompatible-exact] - we don't want to create a dependency on the prettier types
|
|
69
|
-
{
|
|
70
|
-
...prettierOptions,
|
|
71
|
-
parser() {
|
|
72
|
-
return ast;
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// https://github.com/prettier/prettier/blob/d962466a828f8ef51435e3e8840178d90b7ec6cd/src/language-js/parse/postprocess/index.js#L161-L182
|
|
79
|
-
function transformChainExpression(node: ESNode) {
|
|
80
|
-
switch (node.type) {
|
|
81
|
-
case 'CallExpression':
|
|
82
|
-
// $FlowExpectedError[cannot-write]
|
|
83
|
-
node.type = 'OptionalCallExpression';
|
|
84
|
-
// $FlowExpectedError[cannot-write]
|
|
85
|
-
node.callee = transformChainExpression(node.callee);
|
|
86
|
-
break;
|
|
87
|
-
|
|
88
|
-
case 'MemberExpression':
|
|
89
|
-
// $FlowExpectedError[cannot-write]
|
|
90
|
-
node.type = 'OptionalMemberExpression';
|
|
91
|
-
// $FlowExpectedError[cannot-write]
|
|
92
|
-
node.object = transformChainExpression(node.object);
|
|
93
|
-
break;
|
|
94
|
-
// No default
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return node;
|
|
34
|
+
return print(ast, mutatedCode, prettierOptions);
|
|
98
35
|
}
|
|
@@ -12,9 +12,7 @@
|
|
|
12
12
|
Object.defineProperty(exports, "__esModule", {
|
|
13
13
|
value: true
|
|
14
14
|
});
|
|
15
|
-
exports.
|
|
16
|
-
|
|
17
|
-
var _hermesEslint = require("hermes-eslint");
|
|
15
|
+
exports.transformAST = transformAST;
|
|
18
16
|
|
|
19
17
|
var _detachedNode = require("../detachedNode");
|
|
20
18
|
|
|
@@ -24,8 +22,6 @@ var _MutationContext = require("./MutationContext");
|
|
|
24
22
|
|
|
25
23
|
var _TransformContext = require("./TransformContext");
|
|
26
24
|
|
|
27
|
-
var _comments = require("./comments/comments");
|
|
28
|
-
|
|
29
25
|
var _AddComments = require("./mutations/AddComments");
|
|
30
26
|
|
|
31
27
|
var _CloneCommentsTo = require("./mutations/CloneCommentsTo");
|
|
@@ -42,17 +38,12 @@ var _ReplaceNode = require("./mutations/ReplaceNode");
|
|
|
42
38
|
|
|
43
39
|
var _ReplaceStatementWithMany = require("./mutations/ReplaceStatementWithMany");
|
|
44
40
|
|
|
45
|
-
function
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}); // attach comments before mutation. this will ensure that as nodes are
|
|
52
|
-
// cloned / moved around - comments remain in the correct place with respect to the node
|
|
53
|
-
|
|
54
|
-
(0, _comments.attachComments)(ast.comments, ast, code); // traverse the AST and colllect the mutations
|
|
55
|
-
|
|
41
|
+
function transformAST({
|
|
42
|
+
ast,
|
|
43
|
+
scopeManager,
|
|
44
|
+
code
|
|
45
|
+
}, visitors) {
|
|
46
|
+
// traverse the AST and colllect the mutations
|
|
56
47
|
const transformContext = (0, _TransformContext.getTransformContext)();
|
|
57
48
|
(0, _traverse.traverseWithContext)(code, ast, scopeManager, () => transformContext, visitors); // apply the mutations to the AST
|
|
58
49
|
|
|
@@ -13,13 +13,12 @@
|
|
|
13
13
|
import type {ESNode, Program} from 'hermes-estree';
|
|
14
14
|
import type {TransformVisitor} from './transform';
|
|
15
15
|
import type {RemoveCommentMutation} from './mutations/RemoveComment';
|
|
16
|
+
import type {ParseResult} from './parse';
|
|
16
17
|
|
|
17
|
-
import {parseForESLint} from 'hermes-eslint';
|
|
18
18
|
import {updateAllParentPointers} from '../detachedNode';
|
|
19
19
|
import {traverseWithContext} from '../traverse/traverse';
|
|
20
20
|
import {MutationContext} from './MutationContext';
|
|
21
21
|
import {getTransformContext} from './TransformContext';
|
|
22
|
-
import {attachComments} from './comments/comments';
|
|
23
22
|
import {performAddCommentsMutation} from './mutations/AddComments';
|
|
24
23
|
import {performCloneCommentsToMutation} from './mutations/CloneCommentsTo';
|
|
25
24
|
import {performInsertStatementMutation} from './mutations/InsertStatement';
|
|
@@ -29,22 +28,16 @@ import {performRemoveStatementMutation} from './mutations/RemoveStatement';
|
|
|
29
28
|
import {performReplaceNodeMutation} from './mutations/ReplaceNode';
|
|
30
29
|
import {performReplaceStatementWithManyMutation} from './mutations/ReplaceStatementWithMany';
|
|
31
30
|
|
|
32
|
-
export
|
|
33
|
-
code: string,
|
|
34
|
-
visitors: TransformVisitor,
|
|
35
|
-
): {
|
|
31
|
+
export type TransformASTResult = {
|
|
36
32
|
ast: Program,
|
|
37
33
|
astWasMutated: boolean,
|
|
38
34
|
mutatedCode: string,
|
|
39
|
-
}
|
|
40
|
-
const {ast, scopeManager} = parseForESLint(code, {
|
|
41
|
-
sourceType: 'module',
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// attach comments before mutation. this will ensure that as nodes are
|
|
45
|
-
// cloned / moved around - comments remain in the correct place with respect to the node
|
|
46
|
-
attachComments(ast.comments, ast, code);
|
|
35
|
+
};
|
|
47
36
|
|
|
37
|
+
export function transformAST(
|
|
38
|
+
{ast, scopeManager, code}: ParseResult,
|
|
39
|
+
visitors: TransformVisitor,
|
|
40
|
+
): TransformASTResult {
|
|
48
41
|
// traverse the AST and colllect the mutations
|
|
49
42
|
const transformContext = getTransformContext();
|
|
50
43
|
traverseWithContext(
|
|
@@ -34,7 +34,7 @@ type ParsedSelector = $ReadOnly<{
|
|
|
34
34
|
|
|
35
35
|
const ESQUERY_OPTIONS: ESQueryOptions = Object.freeze({
|
|
36
36
|
visitorKeys: VisitorKeys,
|
|
37
|
-
fallback: node => {
|
|
37
|
+
fallback: (node: ESNode) => {
|
|
38
38
|
throw new Error(`No visitor keys found for node type "${node.type}".`);
|
|
39
39
|
},
|
|
40
40
|
});
|
|
@@ -12,7 +12,7 @@ var _NodeEventGenerator = require("./NodeEventGenerator");
|
|
|
12
12
|
|
|
13
13
|
var _SafeEmitter = require("./SafeEmitter");
|
|
14
14
|
|
|
15
|
-
var
|
|
15
|
+
var _hermesParser = require("hermes-parser");
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -32,27 +32,9 @@ var _SimpleTraverser = require("./SimpleTraverser");
|
|
|
32
32
|
*/
|
|
33
33
|
function traverseWithContext(code, ast, scopeManager, additionalContext, visitor) {
|
|
34
34
|
const emitter = new _SafeEmitter.SafeEmitter();
|
|
35
|
-
|
|
36
|
-
let
|
|
37
|
-
|
|
38
|
-
_SimpleTraverser.SimpleTraverser.traverse(ast, {
|
|
39
|
-
enter(node, parent) {
|
|
40
|
-
// $FlowExpectedError[cannot-write] - hermes doesn't set this
|
|
41
|
-
node.parent = parent;
|
|
42
|
-
nodeQueue.push({
|
|
43
|
-
isEntering: true,
|
|
44
|
-
node
|
|
45
|
-
});
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
leave(node) {
|
|
49
|
-
nodeQueue.push({
|
|
50
|
-
isEntering: false,
|
|
51
|
-
node
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
});
|
|
35
|
+
let currentNode = ast;
|
|
36
|
+
let shouldSkipTraversal = false;
|
|
37
|
+
let shouldStopTraversal = false;
|
|
56
38
|
|
|
57
39
|
const getScope = (givenNode = currentNode) => {
|
|
58
40
|
// On Program node, get the outermost scope to avoid return Node.js special function scope or ES modules scope.
|
|
@@ -112,7 +94,13 @@ function traverseWithContext(code, ast, scopeManager, additionalContext, visitor
|
|
|
112
94
|
|
|
113
95
|
return null;
|
|
114
96
|
},
|
|
115
|
-
getScope
|
|
97
|
+
getScope,
|
|
98
|
+
stopTraversal: () => {
|
|
99
|
+
shouldStopTraversal = true;
|
|
100
|
+
},
|
|
101
|
+
skipTraversal: () => {
|
|
102
|
+
shouldSkipTraversal = true;
|
|
103
|
+
}
|
|
116
104
|
});
|
|
117
105
|
const traversalContext = Object.freeze({ ...traversalContextBase,
|
|
118
106
|
...additionalContext(traversalContextBase)
|
|
@@ -130,19 +118,32 @@ function traverseWithContext(code, ast, scopeManager, additionalContext, visitor
|
|
|
130
118
|
}
|
|
131
119
|
});
|
|
132
120
|
const eventGenerator = new _NodeEventGenerator.NodeEventGenerator(emitter);
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
121
|
+
|
|
122
|
+
function checkTraversalFlags() {
|
|
123
|
+
if (shouldStopTraversal) {
|
|
124
|
+
// No need to reset the flag since we won't enter any more nodes.
|
|
125
|
+
throw _hermesParser.SimpleTraverser.Break;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (shouldSkipTraversal) {
|
|
129
|
+
shouldSkipTraversal = false;
|
|
130
|
+
throw _hermesParser.SimpleTraverser.Skip;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
_hermesParser.SimpleTraverser.traverse(ast, {
|
|
135
|
+
enter(node) {
|
|
136
|
+
currentNode = node;
|
|
137
|
+
eventGenerator.enterNode(node);
|
|
138
|
+
checkTraversalFlags();
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
leave(node) {
|
|
142
|
+
currentNode = node;
|
|
143
|
+
eventGenerator.leaveNode(node);
|
|
144
|
+
checkTraversalFlags();
|
|
145
145
|
}
|
|
146
|
+
|
|
146
147
|
});
|
|
147
148
|
}
|
|
148
149
|
|
|
@@ -15,7 +15,7 @@ import type {EmitterListener} from './SafeEmitter';
|
|
|
15
15
|
import {codeFrameColumns} from '@babel/code-frame';
|
|
16
16
|
import {NodeEventGenerator} from './NodeEventGenerator';
|
|
17
17
|
import {SafeEmitter} from './SafeEmitter';
|
|
18
|
-
import {SimpleTraverser} from '
|
|
18
|
+
import {SimpleTraverser} from 'hermes-parser';
|
|
19
19
|
|
|
20
20
|
export type TraversalContextBase = $ReadOnly<{
|
|
21
21
|
/**
|
|
@@ -55,6 +55,17 @@ export type TraversalContextBase = $ReadOnly<{
|
|
|
55
55
|
* (where 56:44 represents L56, Col44)
|
|
56
56
|
*/
|
|
57
57
|
buildSimpleCodeFrame: (node: ESNode, message: string) => string,
|
|
58
|
+
/**
|
|
59
|
+
* Can be called at any point during the traversal to immediately stop traversal
|
|
60
|
+
* entirely.
|
|
61
|
+
*/
|
|
62
|
+
stopTraversal: () => void,
|
|
63
|
+
/**
|
|
64
|
+
* Can be called within the traversal "enter" function to prevent the traverser
|
|
65
|
+
* from traversing the node any further, essentially culling the remainder of the
|
|
66
|
+
* AST branch from traversal.
|
|
67
|
+
*/
|
|
68
|
+
skipTraversal: () => void,
|
|
58
69
|
}>;
|
|
59
70
|
export type TraversalContext<T> = $ReadOnly<{
|
|
60
71
|
...TraversalContextBase,
|
|
@@ -77,21 +88,10 @@ export function traverseWithContext<T = TraversalContextBase>(
|
|
|
77
88
|
visitor: Visitor<T>,
|
|
78
89
|
): void {
|
|
79
90
|
const emitter = new SafeEmitter();
|
|
80
|
-
const nodeQueue: Array<{isEntering: boolean, node: ESNode}> = [];
|
|
81
91
|
|
|
82
92
|
let currentNode: ESNode = ast;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
SimpleTraverser.traverse(ast, {
|
|
86
|
-
enter(node, parent) {
|
|
87
|
-
// $FlowExpectedError[cannot-write] - hermes doesn't set this
|
|
88
|
-
node.parent = parent;
|
|
89
|
-
nodeQueue.push({isEntering: true, node});
|
|
90
|
-
},
|
|
91
|
-
leave(node) {
|
|
92
|
-
nodeQueue.push({isEntering: false, node});
|
|
93
|
-
},
|
|
94
|
-
});
|
|
93
|
+
let shouldSkipTraversal = false;
|
|
94
|
+
let shouldStopTraversal = false;
|
|
95
95
|
|
|
96
96
|
const getScope = (givenNode: ESNode = currentNode) => {
|
|
97
97
|
// On Program node, get the outermost scope to avoid return Node.js special function scope or ES modules scope.
|
|
@@ -140,7 +140,7 @@ export function traverseWithContext<T = TraversalContextBase>(
|
|
|
140
140
|
scopeManager.getDeclaredVariables(node),
|
|
141
141
|
|
|
142
142
|
getBinding: (name: string) => {
|
|
143
|
-
let currentScope = getScope();
|
|
143
|
+
let currentScope: null | Scope = getScope();
|
|
144
144
|
|
|
145
145
|
while (currentScope != null) {
|
|
146
146
|
for (const variable of currentScope.variables) {
|
|
@@ -155,6 +155,14 @@ export function traverseWithContext<T = TraversalContextBase>(
|
|
|
155
155
|
},
|
|
156
156
|
|
|
157
157
|
getScope,
|
|
158
|
+
|
|
159
|
+
stopTraversal: () => {
|
|
160
|
+
shouldStopTraversal = true;
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
skipTraversal: () => {
|
|
164
|
+
shouldSkipTraversal = true;
|
|
165
|
+
},
|
|
158
166
|
});
|
|
159
167
|
|
|
160
168
|
const traversalContext: TraversalContext<T> = Object.freeze({
|
|
@@ -176,19 +184,30 @@ export function traverseWithContext<T = TraversalContextBase>(
|
|
|
176
184
|
});
|
|
177
185
|
|
|
178
186
|
const eventGenerator = new NodeEventGenerator(emitter);
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
err.currentNode = currentNode;
|
|
190
|
-
throw err;
|
|
187
|
+
|
|
188
|
+
function checkTraversalFlags(): void {
|
|
189
|
+
if (shouldStopTraversal) {
|
|
190
|
+
// No need to reset the flag since we won't enter any more nodes.
|
|
191
|
+
throw SimpleTraverser.Break;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (shouldSkipTraversal) {
|
|
195
|
+
shouldSkipTraversal = false;
|
|
196
|
+
throw SimpleTraverser.Skip;
|
|
191
197
|
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
SimpleTraverser.traverse(ast, {
|
|
201
|
+
enter(node) {
|
|
202
|
+
currentNode = node;
|
|
203
|
+
eventGenerator.enterNode(node);
|
|
204
|
+
checkTraversalFlags();
|
|
205
|
+
},
|
|
206
|
+
leave(node) {
|
|
207
|
+
currentNode = node;
|
|
208
|
+
eventGenerator.leaveNode(node);
|
|
209
|
+
checkTraversalFlags();
|
|
210
|
+
},
|
|
192
211
|
});
|
|
193
212
|
}
|
|
194
213
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hermes-transform",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Tools built on top of Hermes-ESTree to enable codebase transformation",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"license": "MIT",
|
|
@@ -12,13 +12,18 @@
|
|
|
12
12
|
"@babel/code-frame": "^7.16.0",
|
|
13
13
|
"esquery": "^1.4.0",
|
|
14
14
|
"flow-enums-runtime": "^0.0.6",
|
|
15
|
-
"hermes-eslint": "0.
|
|
16
|
-
"hermes-estree": "0.
|
|
15
|
+
"hermes-eslint": "0.10.0",
|
|
16
|
+
"hermes-estree": "0.10.0",
|
|
17
|
+
"hermes-parser": "0.10.0"
|
|
17
18
|
},
|
|
18
19
|
"peerDependencies": {
|
|
19
|
-
"prettier": "^2.
|
|
20
|
+
"prettier": "^2.7.1"
|
|
20
21
|
},
|
|
21
22
|
"files": [
|
|
22
|
-
"dist"
|
|
23
|
+
"dist",
|
|
24
|
+
"LICENCE",
|
|
25
|
+
"ESLINT_LICENCE",
|
|
26
|
+
"PRETTIER_LICENCE",
|
|
27
|
+
"README.md"
|
|
23
28
|
]
|
|
24
29
|
}
|
package/dist/getVisitorKeys.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the MIT license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* @format
|
|
9
|
-
*/
|
|
10
|
-
'use strict';
|
|
11
|
-
|
|
12
|
-
Object.defineProperty(exports, "__esModule", {
|
|
13
|
-
value: true
|
|
14
|
-
});
|
|
15
|
-
exports.getVisitorKeys = getVisitorKeys;
|
|
16
|
-
exports.isNode = isNode;
|
|
17
|
-
|
|
18
|
-
var _hermesEslint = require("hermes-eslint");
|
|
19
|
-
|
|
20
|
-
function isNode(thing) {
|
|
21
|
-
return typeof thing === 'object' && thing != null && typeof thing.type === 'string';
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function getVisitorKeys(node) {
|
|
25
|
-
const keys = _hermesEslint.VisitorKeys[node.type];
|
|
26
|
-
|
|
27
|
-
if (keys == null) {
|
|
28
|
-
throw new Error(`No visitor keys found for node type "${node.type}".`);
|
|
29
|
-
} // $FlowExpectedError[prop-missing]
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return keys;
|
|
33
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the MIT license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
* @flow strict-local
|
|
8
|
-
* @format
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
'use strict';
|
|
12
|
-
|
|
13
|
-
import type {ESNode} from 'hermes-estree';
|
|
14
|
-
|
|
15
|
-
import {VisitorKeys} from 'hermes-eslint';
|
|
16
|
-
|
|
17
|
-
export function isNode(thing: mixed): boolean %checks {
|
|
18
|
-
return (
|
|
19
|
-
typeof thing === 'object' && thing != null && typeof thing.type === 'string'
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function getVisitorKeys<T: ESNode>(node: T): $ReadOnlyArray<$Keys<T>> {
|
|
24
|
-
const keys = VisitorKeys[node.type];
|
|
25
|
-
if (keys == null) {
|
|
26
|
-
throw new Error(`No visitor keys found for node type "${node.type}".`);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// $FlowExpectedError[prop-missing]
|
|
30
|
-
return keys;
|
|
31
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.insertInArray = insertInArray;
|
|
7
|
-
exports.removeFromArray = removeFromArray;
|
|
8
|
-
exports.replaceInArray = replaceInArray;
|
|
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
|
-
*
|
|
17
|
-
* @format
|
|
18
|
-
*/
|
|
19
|
-
function assertArrayBounds(array, index) {
|
|
20
|
-
if (index < 0 || index >= array.length) {
|
|
21
|
-
throw new Error(`Invalid Mutation: Tried to mutate an elements array with an out of bounds index. Index: ${index}, Array Size: ${array.length}`);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function insertInArray(array, index, elements) {
|
|
26
|
-
if (index === array.length) {
|
|
27
|
-
// Support the insert at end of array case.
|
|
28
|
-
return array.concat(elements);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
assertArrayBounds(array, index);
|
|
32
|
-
return array.slice(0, index).concat(elements).concat(array.slice(index));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function removeFromArray(array, index) {
|
|
36
|
-
assertArrayBounds(array, index);
|
|
37
|
-
return [...array.slice(0, index), ...array.slice(index + 1)];
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function replaceInArray(array, index, elements) {
|
|
41
|
-
assertArrayBounds(array, index);
|
|
42
|
-
return array.slice(0, index).concat(elements).concat(array.slice(index + 1));
|
|
43
|
-
}
|