hermes-transform 0.5.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.
Files changed (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +8 -0
  3. package/dist/detachedNode.js +128 -0
  4. package/dist/detachedNode.js.flow +113 -0
  5. package/dist/generated/TransformCloneSignatures.js.flow +19 -0
  6. package/dist/generated/TransformReplaceSignatures.js.flow +943 -0
  7. package/dist/generated/node-types.js +2071 -0
  8. package/dist/generated/node-types.js.flow +3149 -0
  9. package/dist/generated/special-case-node-types.js +178 -0
  10. package/dist/generated/special-case-node-types.js.flow +248 -0
  11. package/dist/getVisitorKeys.js +35 -0
  12. package/dist/getVisitorKeys.js.flow +31 -0
  13. package/dist/index.js +41 -0
  14. package/dist/index.js.flow +15 -0
  15. package/dist/transform/Errors.js +151 -0
  16. package/dist/transform/Errors.js.flow +17 -0
  17. package/dist/transform/MutationContext.js +94 -0
  18. package/dist/transform/MutationContext.js.flow +80 -0
  19. package/dist/transform/TransformContext.js +136 -0
  20. package/dist/transform/TransformContext.js.flow +378 -0
  21. package/dist/transform/comments/comments.js +140 -0
  22. package/dist/transform/comments/comments.js.flow +145 -0
  23. package/dist/transform/comments/prettier/README.md +6 -0
  24. package/dist/transform/comments/prettier/common/util.js +365 -0
  25. package/dist/transform/comments/prettier/common/util.js.flow +349 -0
  26. package/dist/transform/comments/prettier/language-js/comments.js +777 -0
  27. package/dist/transform/comments/prettier/language-js/comments.js.flow +950 -0
  28. package/dist/transform/comments/prettier/language-js/loc.js +41 -0
  29. package/dist/transform/comments/prettier/language-js/loc.js.flow +41 -0
  30. package/dist/transform/comments/prettier/language-js/printer-estree.js +31 -0
  31. package/dist/transform/comments/prettier/language-js/printer-estree.js.flow +37 -0
  32. package/dist/transform/comments/prettier/language-js/utils.js +131 -0
  33. package/dist/transform/comments/prettier/language-js/utils.js.flow +135 -0
  34. package/dist/transform/comments/prettier/main/comments.js +513 -0
  35. package/dist/transform/comments/prettier/main/comments.js.flow +436 -0
  36. package/dist/transform/comments/prettier/utils/get-last.js +15 -0
  37. package/dist/transform/comments/prettier/utils/get-last.js.flow +14 -0
  38. package/dist/transform/getTransformedAST.js +159 -0
  39. package/dist/transform/getTransformedAST.js.flow +128 -0
  40. package/dist/transform/mutations/AddLeadingComments.js +47 -0
  41. package/dist/transform/mutations/AddLeadingComments.js.flow +49 -0
  42. package/dist/transform/mutations/AddTrailingComments.js +47 -0
  43. package/dist/transform/mutations/AddTrailingComments.js.flow +49 -0
  44. package/dist/transform/mutations/CloneCommentsTo.js +46 -0
  45. package/dist/transform/mutations/CloneCommentsTo.js.flow +51 -0
  46. package/dist/transform/mutations/InsertStatement.js +92 -0
  47. package/dist/transform/mutations/InsertStatement.js.flow +113 -0
  48. package/dist/transform/mutations/RemoveComment.js +96 -0
  49. package/dist/transform/mutations/RemoveComment.js.flow +80 -0
  50. package/dist/transform/mutations/RemoveStatement.js +61 -0
  51. package/dist/transform/mutations/RemoveStatement.js.flow +68 -0
  52. package/dist/transform/mutations/ReplaceNode.js +96 -0
  53. package/dist/transform/mutations/ReplaceNode.js.flow +113 -0
  54. package/dist/transform/mutations/ReplaceStatementWithMany.js +81 -0
  55. package/dist/transform/mutations/ReplaceStatementWithMany.js.flow +102 -0
  56. package/dist/transform/mutations/utils/arrayUtils.js +41 -0
  57. package/dist/transform/mutations/utils/arrayUtils.js.flow +35 -0
  58. package/dist/transform/mutations/utils/getStatementParent.js +147 -0
  59. package/dist/transform/mutations/utils/getStatementParent.js.flow +143 -0
  60. package/dist/transform/mutations/utils/isValidModuleDeclarationParent.js +53 -0
  61. package/dist/transform/mutations/utils/isValidModuleDeclarationParent.js.flow +50 -0
  62. package/dist/transform/transform.js +69 -0
  63. package/dist/transform/transform.js.flow +60 -0
  64. package/dist/traverse/NodeEventGenerator.js +427 -0
  65. package/dist/traverse/NodeEventGenerator.js.flow +406 -0
  66. package/dist/traverse/SafeEmitter.js +70 -0
  67. package/dist/traverse/SafeEmitter.js.flow +46 -0
  68. package/dist/traverse/SimpleTraverser.js +149 -0
  69. package/dist/traverse/SimpleTraverser.js.flow +109 -0
  70. package/dist/traverse/esquery.js +37 -0
  71. package/dist/traverse/esquery.js.flow +173 -0
  72. package/dist/traverse/traverse.js +139 -0
  73. package/dist/traverse/traverse.js.flow +149 -0
  74. package/package.json +22 -0
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createRemoveCommentMutation = createRemoveCommentMutation;
7
+ exports.performRemoveCommentMutations = performRemoveCommentMutations;
8
+
9
+ var _SimpleTraverser = require("../../traverse/SimpleTraverser");
10
+
11
+ var _comments = require("../comments/comments");
12
+
13
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
14
+
15
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
16
+
17
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
18
+
19
+ function createRemoveCommentMutation(comment) {
20
+ return {
21
+ type: 'removeComment',
22
+ comment: comment
23
+ };
24
+ }
25
+
26
+ function performRemoveCommentMutations(ast, mutations) {
27
+ if (mutations.length === 0) {
28
+ return;
29
+ }
30
+
31
+ var commentsToRemove = new Set(mutations.map(function (m) {
32
+ return m.comment;
33
+ }));
34
+
35
+ _SimpleTraverser.SimpleTraverser.traverse(ast, {
36
+ enter: function enter(node) {
37
+ if (node === ast) {
38
+ return;
39
+ }
40
+
41
+ var nodeCommentsSet = new Set((0, _comments.getCommentsForNode)(node));
42
+
43
+ if (nodeCommentsSet.size === 0) {
44
+ return;
45
+ }
46
+
47
+ var matchedComments = intersectSets(commentsToRemove, nodeCommentsSet);
48
+
49
+ var _iterator = _createForOfIteratorHelper(matchedComments),
50
+ _step;
51
+
52
+ try {
53
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
54
+ var comment = _step.value;
55
+ commentsToRemove["delete"](comment);
56
+ nodeCommentsSet["delete"](comment);
57
+ }
58
+ } catch (err) {
59
+ _iterator.e(err);
60
+ } finally {
61
+ _iterator.f();
62
+ }
63
+
64
+ (0, _comments.setCommentsOnNode)(node, Array.from(nodeCommentsSet));
65
+
66
+ if (commentsToRemove.size === 0) {
67
+ // no more comments to process - so we can exit traversal
68
+ throw _SimpleTraverser.SimpleTraverserBreak;
69
+ }
70
+ },
71
+ leave: function leave() {}
72
+ });
73
+ }
74
+
75
+ function intersectSets(first, other) {
76
+ var ret = new Set();
77
+
78
+ var _iterator2 = _createForOfIteratorHelper(first),
79
+ _step2;
80
+
81
+ try {
82
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
83
+ var value = _step2.value;
84
+
85
+ if (other.has(value)) {
86
+ ret.add(value);
87
+ }
88
+ }
89
+ } catch (err) {
90
+ _iterator2.e(err);
91
+ } finally {
92
+ _iterator2.f();
93
+ }
94
+
95
+ return ret;
96
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its 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
+ import type {Comment, Program} from 'hermes-estree';
12
+ import {
13
+ SimpleTraverser,
14
+ SimpleTraverserBreak,
15
+ } from '../../traverse/SimpleTraverser';
16
+ import {getCommentsForNode, setCommentsOnNode} from '../comments/comments';
17
+
18
+ export type RemoveCommentMutation = $ReadOnly<{
19
+ type: 'removeComment',
20
+ comment: Comment,
21
+ }>;
22
+
23
+ export function createRemoveCommentMutation(
24
+ comment: RemoveCommentMutation['comment'],
25
+ ): RemoveCommentMutation {
26
+ return {
27
+ type: 'removeComment',
28
+ comment,
29
+ };
30
+ }
31
+
32
+ export function performRemoveCommentMutations(
33
+ ast: Program,
34
+ mutations: $ReadOnlyArray<RemoveCommentMutation>,
35
+ ): void {
36
+ if (mutations.length === 0) {
37
+ return;
38
+ }
39
+
40
+ const commentsToRemove = new Set(mutations.map(m => m.comment));
41
+
42
+ SimpleTraverser.traverse(ast, {
43
+ enter(node) {
44
+ if (node === ast) {
45
+ return;
46
+ }
47
+
48
+ const nodeCommentsSet = new Set(getCommentsForNode(node));
49
+ if (nodeCommentsSet.size === 0) {
50
+ return;
51
+ }
52
+
53
+ const matchedComments = intersectSets(commentsToRemove, nodeCommentsSet);
54
+ for (const comment of matchedComments) {
55
+ commentsToRemove.delete(comment);
56
+ nodeCommentsSet.delete(comment);
57
+ }
58
+ setCommentsOnNode(node, Array.from(nodeCommentsSet));
59
+
60
+ if (commentsToRemove.size === 0) {
61
+ // no more comments to process - so we can exit traversal
62
+ throw SimpleTraverserBreak;
63
+ }
64
+ },
65
+ leave() {},
66
+ });
67
+ }
68
+
69
+ function intersectSets<T>(
70
+ first: $ReadOnlySet<T>,
71
+ other: $ReadOnlySet<T>,
72
+ ): Set<T> {
73
+ const ret = new Set();
74
+ for (const value of first) {
75
+ if (other.has(value)) {
76
+ ret.add(value);
77
+ }
78
+ }
79
+ return ret;
80
+ }
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+
3
+ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.createRemoveStatementMutation = createRemoveStatementMutation;
9
+ exports.performRemoveStatementMutation = performRemoveStatementMutation;
10
+
11
+ var _arrayUtils = require("./utils/arrayUtils");
12
+
13
+ var _getStatementParent = require("./utils/getStatementParent");
14
+
15
+ var t = _interopRequireWildcard(require("../../generated/node-types"));
16
+
17
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
18
+
19
+ 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; }
20
+
21
+ /**
22
+ * Copyright (c) Facebook, Inc. and its affiliates.
23
+ *
24
+ * This source code is licensed under the MIT license found in the
25
+ * LICENSE file in the root directory of this source tree.
26
+ *
27
+ *
28
+ * @format
29
+ */
30
+ function createRemoveStatementMutation(node) {
31
+ return {
32
+ type: 'removeStatement',
33
+ node: node
34
+ };
35
+ }
36
+
37
+ function performRemoveStatementMutation(mutationContext, mutation) {
38
+ var removalParent = (0, _getStatementParent.getStatementParent)(mutation.node);
39
+ mutationContext.markDeletion(mutation.node);
40
+ mutationContext.markMutation(removalParent.parent, removalParent.key);
41
+
42
+ if (removalParent.type === 'array') {
43
+ var parent = removalParent.parent;
44
+ parent[removalParent.key] = (0, _arrayUtils.removeFromArray)(parent[removalParent.key], removalParent.targetIndex);
45
+ } else {
46
+ // The parent has a 1:1 relationship on this key, so we can't just
47
+ // remove the node. Instead we replace it with an empty block statement.
48
+ // We COULD throw an error here and make the codemodder write a stricter
49
+ // codemod - but we decided to add this bit of magic to make it easier
50
+ // to write codemods.
51
+ // Worst case it creates some dead code that can be easily detected
52
+ // and cleaned up later.
53
+ var blockStatement = t.BlockStatement({
54
+ body: [],
55
+ parent: removalParent.parent
56
+ });
57
+ removalParent.parent[removalParent.key] = blockStatement;
58
+ }
59
+
60
+ return removalParent.parent;
61
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its 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
+ import type {ESNode, ModuleDeclaration, Statement} from 'hermes-estree';
12
+ import type {MutationContext} from '../MutationContext';
13
+ import type {DetachedNode} from '../../detachedNode';
14
+
15
+ import {removeFromArray} from './utils/arrayUtils';
16
+ import {getStatementParent} from './utils/getStatementParent';
17
+ import * as t from '../../generated/node-types';
18
+
19
+ export type RemoveStatementMutation = $ReadOnly<{
20
+ type: 'removeStatement',
21
+ node: ModuleDeclaration | Statement,
22
+ }>;
23
+
24
+ export function createRemoveStatementMutation(
25
+ node: RemoveStatementMutation['node'],
26
+ ): RemoveStatementMutation {
27
+ return {
28
+ type: 'removeStatement',
29
+ node,
30
+ };
31
+ }
32
+
33
+ export function performRemoveStatementMutation(
34
+ mutationContext: MutationContext,
35
+ mutation: RemoveStatementMutation,
36
+ ): ESNode {
37
+ const removalParent = getStatementParent(mutation.node);
38
+
39
+ mutationContext.markDeletion(mutation.node);
40
+ mutationContext.markMutation(removalParent.parent, removalParent.key);
41
+
42
+ if (removalParent.type === 'array') {
43
+ const parent: interface {
44
+ [string]: $ReadOnlyArray<DetachedNode<Statement | ModuleDeclaration>>,
45
+ } = removalParent.parent;
46
+ parent[removalParent.key] = removeFromArray(
47
+ parent[removalParent.key],
48
+ removalParent.targetIndex,
49
+ );
50
+ } else {
51
+ // The parent has a 1:1 relationship on this key, so we can't just
52
+ // remove the node. Instead we replace it with an empty block statement.
53
+ // We COULD throw an error here and make the codemodder write a stricter
54
+ // codemod - but we decided to add this bit of magic to make it easier
55
+ // to write codemods.
56
+ // Worst case it creates some dead code that can be easily detected
57
+ // and cleaned up later.
58
+ const blockStatement = t.BlockStatement({
59
+ body: [],
60
+ parent: removalParent.parent,
61
+ });
62
+
63
+ (removalParent.parent: interface {[string]: mixed})[removalParent.key] =
64
+ blockStatement;
65
+ }
66
+
67
+ return removalParent.parent;
68
+ }
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createReplaceNodeMutation = createReplaceNodeMutation;
7
+ exports.performReplaceNodeMutation = performReplaceNodeMutation;
8
+
9
+ var _arrayUtils = require("./utils/arrayUtils");
10
+
11
+ var _comments = require("../comments/comments");
12
+
13
+ var _Errors = require("../Errors");
14
+
15
+ var _getVisitorKeys = require("../../getVisitorKeys");
16
+
17
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
18
+
19
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
20
+
21
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
22
+
23
+ function createReplaceNodeMutation(target, nodeToReplaceWith, options) {
24
+ var _options$keepComments;
25
+
26
+ return {
27
+ type: 'replaceNode',
28
+ target: target,
29
+ nodeToReplaceWith: nodeToReplaceWith,
30
+ keepComments: (_options$keepComments = options === null || options === void 0 ? void 0 : options.keepComments) !== null && _options$keepComments !== void 0 ? _options$keepComments : false
31
+ };
32
+ }
33
+
34
+ function performReplaceNodeMutation(mutationContext, mutation) {
35
+ var replacementParent = getParentKey(mutation.target);
36
+ mutationContext.markDeletion(mutation.target);
37
+ mutationContext.markMutation(replacementParent.parent, replacementParent.key); // NOTE: currently this mutation assumes you're doing the right thing.
38
+ // it does no runtime checks and provides no guarantees about the
39
+ // correctness of the resulting code.
40
+ // TODO: maybe add some runtime checks based on codegenned predicates?
41
+
42
+ if (replacementParent.type === 'array') {
43
+ var parent = replacementParent.parent;
44
+ parent[replacementParent.key] = (0, _arrayUtils.replaceInArray)(parent[replacementParent.key], replacementParent.targetIndex, [mutation.nodeToReplaceWith]);
45
+ } else {
46
+ replacementParent.parent[replacementParent.key] = mutation.nodeToReplaceWith;
47
+ }
48
+
49
+ if (mutation.keepComments) {
50
+ (0, _comments.moveCommentsToNewNode)(mutation.target, mutation.nodeToReplaceWith);
51
+ }
52
+
53
+ return replacementParent.parent;
54
+ }
55
+
56
+ function getParentKey(target) {
57
+ var parent = target.parent;
58
+
59
+ var _iterator = _createForOfIteratorHelper((0, _getVisitorKeys.getVisitorKeys)(parent)),
60
+ _step;
61
+
62
+ try {
63
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
64
+ var key = _step.value;
65
+
66
+ if ((0, _getVisitorKeys.isNode)( // $FlowExpectedError[prop-missing]
67
+ parent[key])) {
68
+ if (parent[key] === target) {
69
+ return {
70
+ type: 'single',
71
+ parent: parent,
72
+ key: key
73
+ };
74
+ }
75
+ } else if (Array.isArray(parent[key])) {
76
+ for (var i = 0; i < parent[key].length; i += 1) {
77
+ if (parent[key][i] === target) {
78
+ return {
79
+ type: 'array',
80
+ parent: parent,
81
+ key: key,
82
+ targetIndex: i
83
+ };
84
+ }
85
+ }
86
+ }
87
+ } // this shouldn't happen ever
88
+
89
+ } catch (err) {
90
+ _iterator.e(err);
91
+ } finally {
92
+ _iterator.f();
93
+ }
94
+
95
+ throw new _Errors.InvalidReplacementError("Expected to find the ".concat(target.type, " as a direct child of the ").concat(target.type, "."));
96
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its 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
+ import type {ESNode} from 'hermes-estree';
12
+ import type {MutationContext} from '../MutationContext';
13
+ import type {DetachedNode} from '../../detachedNode';
14
+
15
+ import {replaceInArray} from './utils/arrayUtils';
16
+ import {moveCommentsToNewNode} from '../comments/comments';
17
+ import {InvalidReplacementError} from '../Errors';
18
+ import {getVisitorKeys, isNode} from '../../getVisitorKeys';
19
+
20
+ export type ReplaceNodeMutation = $ReadOnly<{
21
+ type: 'replaceNode',
22
+ target: ESNode,
23
+ nodeToReplaceWith: DetachedNode<ESNode>,
24
+ keepComments: boolean,
25
+ }>;
26
+
27
+ export function createReplaceNodeMutation(
28
+ target: ReplaceNodeMutation['target'],
29
+ nodeToReplaceWith: ReplaceNodeMutation['nodeToReplaceWith'],
30
+ options?: $ReadOnly<{keepComments?: boolean}>,
31
+ ): ReplaceNodeMutation {
32
+ return {
33
+ type: 'replaceNode',
34
+ target,
35
+ nodeToReplaceWith,
36
+ keepComments: options?.keepComments ?? false,
37
+ };
38
+ }
39
+
40
+ export function performReplaceNodeMutation(
41
+ mutationContext: MutationContext,
42
+ mutation: ReplaceNodeMutation,
43
+ ): ESNode {
44
+ const replacementParent = getParentKey(mutation.target);
45
+
46
+ mutationContext.markDeletion(mutation.target);
47
+ mutationContext.markMutation(replacementParent.parent, replacementParent.key);
48
+
49
+ // NOTE: currently this mutation assumes you're doing the right thing.
50
+ // it does no runtime checks and provides no guarantees about the
51
+ // correctness of the resulting code.
52
+ // TODO: maybe add some runtime checks based on codegenned predicates?
53
+
54
+ if (replacementParent.type === 'array') {
55
+ const parent: interface {
56
+ [string]: $ReadOnlyArray<DetachedNode<ESNode>>,
57
+ } = replacementParent.parent;
58
+ parent[replacementParent.key] = replaceInArray(
59
+ parent[replacementParent.key],
60
+ replacementParent.targetIndex,
61
+ [mutation.nodeToReplaceWith],
62
+ );
63
+ } else {
64
+ (replacementParent.parent: interface {[string]: mixed})[
65
+ replacementParent.key
66
+ ] = mutation.nodeToReplaceWith;
67
+ }
68
+
69
+ if (mutation.keepComments) {
70
+ moveCommentsToNewNode(mutation.target, mutation.nodeToReplaceWith);
71
+ }
72
+
73
+ return replacementParent.parent;
74
+ }
75
+
76
+ function getParentKey(target: ESNode): $ReadOnly<
77
+ | {
78
+ type: 'single',
79
+ parent: ESNode,
80
+ key: string,
81
+ }
82
+ | {
83
+ type: 'array',
84
+ parent: ESNode,
85
+ key: string,
86
+ targetIndex: number,
87
+ },
88
+ > {
89
+ const parent = target.parent;
90
+ for (const key of getVisitorKeys(parent)) {
91
+ if (
92
+ isNode(
93
+ // $FlowExpectedError[prop-missing]
94
+ parent[key],
95
+ )
96
+ ) {
97
+ if (parent[key] === target) {
98
+ return {type: 'single', parent, key};
99
+ }
100
+ } else if (Array.isArray(parent[key])) {
101
+ for (let i = 0; i < parent[key].length; i += 1) {
102
+ if (parent[key][i] === target) {
103
+ return {type: 'array', parent, key, targetIndex: i};
104
+ }
105
+ }
106
+ }
107
+ }
108
+
109
+ // this shouldn't happen ever
110
+ throw new InvalidReplacementError(
111
+ `Expected to find the ${target.type} as a direct child of the ${target.type}.`,
112
+ );
113
+ }
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+
3
+ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.createReplaceStatementWithManyMutation = createReplaceStatementWithManyMutation;
9
+ exports.performReplaceStatementWithManyMutation = performReplaceStatementWithManyMutation;
10
+
11
+ var _arrayUtils = require("./utils/arrayUtils");
12
+
13
+ var _getStatementParent = require("./utils/getStatementParent");
14
+
15
+ var _isValidModuleDeclarationParent = require("./utils/isValidModuleDeclarationParent");
16
+
17
+ var _comments = require("../comments/comments");
18
+
19
+ var _Errors = require("../Errors");
20
+
21
+ var t = _interopRequireWildcard(require("../../generated/node-types"));
22
+
23
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(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; }
26
+
27
+ /**
28
+ * Copyright (c) Facebook, Inc. and its affiliates.
29
+ *
30
+ * This source code is licensed under the MIT license found in the
31
+ * LICENSE file in the root directory of this source tree.
32
+ *
33
+ *
34
+ * @format
35
+ */
36
+ function createReplaceStatementWithManyMutation(target, nodesToReplaceWith, options) {
37
+ var _options$keepComments;
38
+
39
+ if (nodesToReplaceWith.length === 0) {
40
+ return null;
41
+ }
42
+
43
+ return {
44
+ type: 'replaceStatementWithMany',
45
+ target: target,
46
+ nodesToReplaceWith: nodesToReplaceWith,
47
+ keepComments: (_options$keepComments = options === null || options === void 0 ? void 0 : options.keepComments) !== null && _options$keepComments !== void 0 ? _options$keepComments : false
48
+ };
49
+ }
50
+
51
+ function performReplaceStatementWithManyMutation(mutationContext, mutation) {
52
+ var replacementParent = (0, _getStatementParent.getStatementParent)(mutation.target); // enforce that if we are replacing with module declarations - they are being inserted in a valid location
53
+
54
+ if (!(0, _isValidModuleDeclarationParent.isValidModuleDeclarationParent)(replacementParent.parent, mutation.nodesToReplaceWith)) {
55
+ throw new _Errors.InvalidReplacementError("import/export cannot be replaced into a ".concat(replacementParent.parent.type, "."));
56
+ }
57
+
58
+ mutationContext.markDeletion(mutation.target);
59
+ mutationContext.markMutation(replacementParent.parent, replacementParent.key);
60
+
61
+ if (mutation.keepComments) {
62
+ // attach comments to the very first replacement node
63
+ (0, _comments.moveCommentsToNewNode)(mutation.target, mutation.nodesToReplaceWith[0]);
64
+ }
65
+
66
+ if (replacementParent.type === 'array') {
67
+ var parent = replacementParent.parent;
68
+ parent[replacementParent.key] = (0, _arrayUtils.replaceInArray)(parent[replacementParent.key], replacementParent.targetIndex, mutation.nodesToReplaceWith);
69
+ return replacementParent.parent;
70
+ }
71
+
72
+ var statementsToReplaceWith = // $FlowExpectedError[incompatible-cast] -- this is enforced by isValidModuleDeclarationParent above
73
+ mutation.nodesToReplaceWith; // we need to wrap the nodes in a BlockStatement as before there was only 1 node
74
+
75
+ var blockStatement = t.BlockStatement({
76
+ body: statementsToReplaceWith,
77
+ parent: replacementParent.parent
78
+ });
79
+ replacementParent.parent[replacementParent.key] = blockStatement;
80
+ return replacementParent.parent;
81
+ }