hermes-parser 0.15.1 → 0.16.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/dist/index.js CHANGED
@@ -15,23 +15,30 @@ Object.defineProperty(exports, "__esModule", {
15
15
  var _exportNames = {
16
16
  parse: true,
17
17
  mutateESTreeASTForPrettier: true,
18
+ Transforms: true,
18
19
  FlowVisitorKeys: true,
19
20
  astArrayMutationHelpers: true,
20
21
  astNodeMutationHelpers: true
21
22
  };
22
- exports.mutateESTreeASTForPrettier = exports.astNodeMutationHelpers = exports.astArrayMutationHelpers = void 0;
23
+ exports.mutateESTreeASTForPrettier = exports.astNodeMutationHelpers = exports.astArrayMutationHelpers = exports.Transforms = void 0;
23
24
  exports.parse = parse;
24
25
 
25
26
  var HermesParser = _interopRequireWildcard(require("./HermesParser"));
26
27
 
27
- var _HermesToBabelAdapter = _interopRequireDefault(require("./HermesToBabelAdapter"));
28
-
29
28
  var _HermesToESTreeAdapter = _interopRequireDefault(require("./HermesToESTreeAdapter"));
30
29
 
31
30
  var _ESTreeVisitorKeys = _interopRequireDefault(require("./generated/ESTreeVisitorKeys"));
32
31
 
33
32
  exports.FlowVisitorKeys = _ESTreeVisitorKeys.default;
34
33
 
34
+ var StripComponentSyntax = _interopRequireWildcard(require("./estree/StripComponentSyntax"));
35
+
36
+ var StripFlowTypesForBabel = _interopRequireWildcard(require("./estree/StripFlowTypesForBabel"));
37
+
38
+ var TransformESTreeToBabel = _interopRequireWildcard(require("./babel/TransformESTreeToBabel"));
39
+
40
+ var StripFlowTypes = _interopRequireWildcard(require("./estree/StripFlowTypes"));
41
+
35
42
  var _ParserOptions = require("./ParserOptions");
36
43
 
37
44
  Object.keys(_ParserOptions).forEach(function (key) {
@@ -107,20 +114,33 @@ function getOptions(options = { ...DEFAULTS
107
114
  throw new Error('sourceType option must be "script", "module", or "unambiguous" if set');
108
115
  }
109
116
 
117
+ if (options.enableExperimentalComponentSyntax == null) {
118
+ options.enableExperimentalComponentSyntax = true; // Enable by default
119
+ }
120
+
110
121
  options.tokens = options.tokens === true;
111
122
  options.allowReturnOutsideFunction = options.allowReturnOutsideFunction === true;
112
123
  return options;
113
124
  }
114
125
 
115
- function getAdapter(options, code) {
116
- return options.babel === true ? new _HermesToBabelAdapter.default(options) : new _HermesToESTreeAdapter.default(options, code);
117
- } // $FlowExpectedError[unclear-type]
118
-
119
-
120
126
  // eslint-disable-next-line no-redeclare
121
127
  function parse(code, opts) {
122
128
  const options = getOptions(opts);
123
129
  const ast = HermesParser.parse(code, options);
124
- const adapter = getAdapter(options, code);
125
- return adapter.transform(ast);
126
- }
130
+ const estreeAdapter = new _HermesToESTreeAdapter.default(options, code);
131
+ const estreeAST = estreeAdapter.transform(ast);
132
+
133
+ if (options.babel !== true) {
134
+ return estreeAST;
135
+ }
136
+
137
+ const loweredESTreeAST = [StripComponentSyntax.transformProgram, StripFlowTypesForBabel.transformProgram].reduce((ast, transform) => transform(ast, options), estreeAST);
138
+ return TransformESTreeToBabel.transformProgram(loweredESTreeAST, options);
139
+ }
140
+
141
+ const Transforms = {
142
+ stripComponentSyntax: StripComponentSyntax.transformProgram,
143
+ stripFlowTypesForBabel: StripFlowTypesForBabel.transformProgram,
144
+ stripFlowTypes: StripFlowTypes.transformProgram
145
+ };
146
+ exports.Transforms = Transforms;
@@ -12,11 +12,15 @@
12
12
 
13
13
  import type {Program as ESTreeProgram} from 'hermes-estree';
14
14
  import type {ParserOptions} from './ParserOptions';
15
+ import type {BabelFile} from './babel/TransformESTreeToBabel';
15
16
 
16
17
  import * as HermesParser from './HermesParser';
17
- import HermesToBabelAdapter from './HermesToBabelAdapter';
18
18
  import HermesToESTreeAdapter from './HermesToESTreeAdapter';
19
19
  import FlowVisitorKeys from './generated/ESTreeVisitorKeys';
20
+ import * as StripComponentSyntax from './estree/StripComponentSyntax';
21
+ import * as StripFlowTypesForBabel from './estree/StripFlowTypesForBabel';
22
+ import * as TransformESTreeToBabel from './babel/TransformESTreeToBabel';
23
+ import * as StripFlowTypes from './estree/StripFlowTypes';
20
24
 
21
25
  const DEFAULTS = {
22
26
  flow: 'detect',
@@ -44,6 +48,10 @@ function getOptions(options?: ParserOptions = {...DEFAULTS}) {
44
48
  );
45
49
  }
46
50
 
51
+ if (options.enableExperimentalComponentSyntax == null) {
52
+ options.enableExperimentalComponentSyntax = true; // Enable by default
53
+ }
54
+
47
55
  options.tokens = options.tokens === true;
48
56
  options.allowReturnOutsideFunction =
49
57
  options.allowReturnOutsideFunction === true;
@@ -51,18 +59,10 @@ function getOptions(options?: ParserOptions = {...DEFAULTS}) {
51
59
  return options;
52
60
  }
53
61
 
54
- function getAdapter(options: ParserOptions, code: string) {
55
- return options.babel === true
56
- ? new HermesToBabelAdapter(options)
57
- : new HermesToESTreeAdapter(options, code);
58
- }
59
-
60
- // $FlowExpectedError[unclear-type]
61
- type BabelProgram = Object;
62
62
  declare function parse(
63
63
  code: string,
64
64
  opts: {...ParserOptions, babel: true},
65
- ): BabelProgram;
65
+ ): BabelFile;
66
66
  // eslint-disable-next-line no-redeclare
67
67
  declare function parse(
68
68
  code: string,
@@ -75,12 +75,23 @@ declare function parse(
75
75
  export function parse(
76
76
  code: string,
77
77
  opts?: ParserOptions,
78
- ): BabelProgram | ESTreeProgram {
78
+ ): BabelFile | ESTreeProgram {
79
79
  const options = getOptions(opts);
80
80
  const ast = HermesParser.parse(code, options);
81
- const adapter = getAdapter(options, code);
82
81
 
83
- return adapter.transform(ast);
82
+ const estreeAdapter = new HermesToESTreeAdapter(options, code);
83
+ const estreeAST = estreeAdapter.transform(ast);
84
+
85
+ if (options.babel !== true) {
86
+ return estreeAST;
87
+ }
88
+
89
+ const loweredESTreeAST = [
90
+ StripComponentSyntax.transformProgram,
91
+ StripFlowTypesForBabel.transformProgram,
92
+ ].reduce((ast, transform) => transform(ast, options), estreeAST);
93
+
94
+ return TransformESTreeToBabel.transformProgram(loweredESTreeAST, options);
84
95
  }
85
96
 
86
97
  export type {ParserOptions} from './ParserOptions';
@@ -92,3 +103,10 @@ export {FlowVisitorKeys};
92
103
  export * as astArrayMutationHelpers from './transform/astArrayMutationHelpers';
93
104
  export * as astNodeMutationHelpers from './transform/astNodeMutationHelpers';
94
105
  export {default as mutateESTreeASTForPrettier} from './utils/mutateESTreeASTForPrettier';
106
+
107
+ const Transforms = {
108
+ stripComponentSyntax: StripComponentSyntax.transformProgram,
109
+ stripFlowTypesForBabel: StripFlowTypesForBabel.transformProgram,
110
+ stripFlowTypes: StripFlowTypes.transformProgram,
111
+ };
112
+ export {Transforms};
@@ -18,9 +18,17 @@ var _SimpleTraverser = require("../traverse/SimpleTraverser");
18
18
 
19
19
  var _astNodeMutationHelpers = require("./astNodeMutationHelpers");
20
20
 
21
+ function setParentPointer(node, parent) {
22
+ if (parent != null) {
23
+ // $FlowExpectedError[cannot-write]
24
+ node.parent = parent;
25
+ }
26
+ }
21
27
  /**
22
28
  * A simple class to recursively tranform AST trees.
23
29
  */
30
+
31
+
24
32
  class SimpleTransform {
25
33
  /**
26
34
  * Transform the given AST tree.
@@ -33,10 +41,18 @@ class SimpleTransform {
33
41
 
34
42
  _SimpleTraverser.SimpleTraverser.traverse(rootNode, {
35
43
  enter: (node, parent) => {
44
+ // Ensure the parent pointers are correctly set before entering the node.
45
+ setParentPointer(node, parent);
36
46
  const resultNode = options.transform(node);
37
47
 
38
48
  if (resultNode !== node) {
39
- const traversedResultNode = resultNode != null ? this.transform(resultNode, options) : null;
49
+ let traversedResultNode = null;
50
+
51
+ if (resultNode != null) {
52
+ // Ensure the new node has the correct parent pointers before recursing again.
53
+ setParentPointer(resultNode, parent);
54
+ traversedResultNode = this.transform(resultNode, options);
55
+ }
40
56
 
41
57
  if (parent == null) {
42
58
  if (node !== rootNode) {
@@ -45,9 +61,10 @@ class SimpleTransform {
45
61
 
46
62
  resultRootNode = traversedResultNode;
47
63
  } else if (traversedResultNode == null) {
48
- (0, _astNodeMutationHelpers.removeNodeOnParent)(node, parent);
64
+ (0, _astNodeMutationHelpers.removeNodeOnParent)(node, parent, options.visitorKeys);
49
65
  } else {
50
- (0, _astNodeMutationHelpers.replaceNodeOnParent)(node, parent, traversedResultNode);
66
+ (0, _astNodeMutationHelpers.replaceNodeOnParent)(node, parent, traversedResultNode, options.visitorKeys);
67
+ setParentPointer(traversedResultNode, parent);
51
68
  }
52
69
 
53
70
  throw _SimpleTraverser.SimpleTraverser.Skip;
@@ -71,6 +88,16 @@ class SimpleTransform {
71
88
  static transform(node, options) {
72
89
  return new SimpleTransform().transform(node, options);
73
90
  }
91
+
92
+ static transformProgram(program, options) {
93
+ const result = SimpleTransform.transform(program, options);
94
+
95
+ if ((result == null ? void 0 : result.type) === 'Program') {
96
+ return result;
97
+ }
98
+
99
+ throw new Error('SimpleTransform.transformProgram: Expected program node.');
100
+ }
74
101
  /**
75
102
  * Return a new AST node with the given properties overrided if needed.
76
103
  *
@@ -84,8 +111,8 @@ class SimpleTransform {
84
111
  */
85
112
 
86
113
 
87
- static nodeWith(node, overrideProps) {
88
- return (0, _astNodeMutationHelpers.nodeWith)(node, overrideProps);
114
+ static nodeWith(node, overrideProps, visitorKeys) {
115
+ return (0, _astNodeMutationHelpers.nodeWith)(node, overrideProps, visitorKeys);
89
116
  }
90
117
 
91
118
  }
@@ -11,7 +11,7 @@
11
11
  'use strict';
12
12
 
13
13
  import type {VisitorKeysType} from '../traverse/getVisitorKeys';
14
- import type {ESNode} from 'hermes-estree';
14
+ import type {ESNode, Program} from 'hermes-estree';
15
15
 
16
16
  import {SimpleTraverser} from '../traverse/SimpleTraverser';
17
17
  import {
@@ -39,6 +39,13 @@ export type TransformOptions = $ReadOnly<{
39
39
  visitorKeys?: ?VisitorKeysType,
40
40
  }>;
41
41
 
42
+ function setParentPointer(node: ESNode, parent: ?ESNode): void {
43
+ if (parent != null) {
44
+ // $FlowExpectedError[cannot-write]
45
+ node.parent = parent;
46
+ }
47
+ }
48
+
42
49
  /**
43
50
  * A simple class to recursively tranform AST trees.
44
51
  */
@@ -53,10 +60,20 @@ export class SimpleTransform {
53
60
  let resultRootNode: ESNode | null = rootNode;
54
61
  SimpleTraverser.traverse(rootNode, {
55
62
  enter: (node: ESNode, parent: ?ESNode) => {
63
+ // Ensure the parent pointers are correctly set before entering the node.
64
+ setParentPointer(node, parent);
65
+
56
66
  const resultNode = options.transform(node);
57
67
  if (resultNode !== node) {
58
- const traversedResultNode =
59
- resultNode != null ? this.transform(resultNode, options) : null;
68
+ let traversedResultNode = null;
69
+
70
+ if (resultNode != null) {
71
+ // Ensure the new node has the correct parent pointers before recursing again.
72
+ setParentPointer(resultNode, parent);
73
+
74
+ traversedResultNode = this.transform(resultNode, options);
75
+ }
76
+
60
77
  if (parent == null) {
61
78
  if (node !== rootNode) {
62
79
  throw new Error(
@@ -65,9 +82,15 @@ export class SimpleTransform {
65
82
  }
66
83
  resultRootNode = traversedResultNode;
67
84
  } else if (traversedResultNode == null) {
68
- removeNodeOnParent(node, parent);
85
+ removeNodeOnParent(node, parent, options.visitorKeys);
69
86
  } else {
70
- replaceNodeOnParent(node, parent, traversedResultNode);
87
+ replaceNodeOnParent(
88
+ node,
89
+ parent,
90
+ traversedResultNode,
91
+ options.visitorKeys,
92
+ );
93
+ setParentPointer(traversedResultNode, parent);
71
94
  }
72
95
 
73
96
  throw SimpleTraverser.Skip;
@@ -88,6 +111,17 @@ export class SimpleTransform {
88
111
  return new SimpleTransform().transform(node, options);
89
112
  }
90
113
 
114
+ static transformProgram(
115
+ program: Program,
116
+ options: TransformOptions,
117
+ ): Program {
118
+ const result = SimpleTransform.transform(program, options);
119
+ if (result?.type === 'Program') {
120
+ return result;
121
+ }
122
+ throw new Error('SimpleTransform.transformProgram: Expected program node.');
123
+ }
124
+
91
125
  /**
92
126
  * Return a new AST node with the given properties overrided if needed.
93
127
  *
@@ -99,7 +133,11 @@ export class SimpleTransform {
99
133
  * @return Either the orginal node if the properties matched the existing node or a new node with
100
134
  * the new properties.
101
135
  */
102
- static nodeWith<T: ESNode>(node: T, overrideProps: Partial<T>): T {
103
- return nodeWith<T>(node, overrideProps);
136
+ static nodeWith<T: ESNode>(
137
+ node: T,
138
+ overrideProps: Partial<T>,
139
+ visitorKeys?: VisitorKeysType,
140
+ ): T {
141
+ return nodeWith<T>(node, overrideProps, visitorKeys);
104
142
  }
105
143
  }
@@ -26,12 +26,12 @@ var _getVisitorKeys = require("../traverse/getVisitorKeys");
26
26
 
27
27
  var _SimpleTraverser = require("../traverse/SimpleTraverser");
28
28
 
29
- function getParentKey(target, parent) {
29
+ function getParentKey(target, parent, visitorKeys) {
30
30
  if (parent == null) {
31
31
  throw new Error(`Expected parent node to be set on "${target.type}"`);
32
32
  }
33
33
 
34
- for (const key of (0, _getVisitorKeys.getVisitorKeys)(parent)) {
34
+ for (const key of (0, _getVisitorKeys.getVisitorKeys)(parent, visitorKeys)) {
35
35
  if ((0, _getVisitorKeys.isNode)( // $FlowExpectedError[prop-missing]
36
36
  parent[key])) {
37
37
  if (parent[key] === target) {
@@ -65,8 +65,8 @@ function getParentKey(target, parent) {
65
65
  */
66
66
 
67
67
 
68
- function replaceNodeOnParent(originalNode, originalNodeParent, nodeToReplaceWith) {
69
- const replacementParent = getParentKey(originalNode, originalNodeParent);
68
+ function replaceNodeOnParent(originalNode, originalNodeParent, nodeToReplaceWith, visitorKeys) {
69
+ const replacementParent = getParentKey(originalNode, originalNodeParent, visitorKeys);
70
70
  const parent = replacementParent.node;
71
71
 
72
72
  if (replacementParent.type === 'array') {
@@ -83,8 +83,8 @@ function replaceNodeOnParent(originalNode, originalNodeParent, nodeToReplaceWith
83
83
  */
84
84
 
85
85
 
86
- function removeNodeOnParent(originalNode, originalNodeParent) {
87
- const replacementParent = getParentKey(originalNode, originalNodeParent);
86
+ function removeNodeOnParent(originalNode, originalNodeParent, visitorKeys) {
87
+ const replacementParent = getParentKey(originalNode, originalNodeParent, visitorKeys);
88
88
  const parent = replacementParent.node;
89
89
 
90
90
  if (replacementParent.type === 'array') {
@@ -101,8 +101,8 @@ function removeNodeOnParent(originalNode, originalNodeParent) {
101
101
  */
102
102
 
103
103
 
104
- function setParentPointersInDirectChildren(node) {
105
- for (const key of (0, _getVisitorKeys.getVisitorKeys)(node)) {
104
+ function setParentPointersInDirectChildren(node, visitorKeys) {
105
+ for (const key of (0, _getVisitorKeys.getVisitorKeys)(node, visitorKeys)) {
106
106
  if ((0, _getVisitorKeys.isNode)(node[key])) {
107
107
  node[key].parent = node;
108
108
  } else if (Array.isArray(node[key])) {
@@ -117,15 +117,16 @@ function setParentPointersInDirectChildren(node) {
117
117
  */
118
118
 
119
119
 
120
- function updateAllParentPointers(node) {
120
+ function updateAllParentPointers(node, visitorKeys) {
121
121
  _SimpleTraverser.SimpleTraverser.traverse(node, {
122
122
  enter(node, parent) {
123
123
  // $FlowExpectedError[cannot-write]
124
124
  node.parent = parent;
125
125
  },
126
126
 
127
- leave() {}
127
+ leave() {},
128
128
 
129
+ visitorKeys
129
130
  });
130
131
  }
131
132
  /**
@@ -135,11 +136,17 @@ function updateAllParentPointers(node) {
135
136
  */
136
137
 
137
138
 
138
- function nodeWith(node, overrideProps) {
139
+ function nodeWith(node, overrideProps, visitorKeys) {
139
140
  // Check if this will actually result in a change, maintaining referential equality is important.
140
- const willBeUnchanged = Object.entries(overrideProps).every(([key, value]) => // $FlowExpectedError[incompatible-call]
141
- // $FlowExpectedError[prop-missing]
142
- Array.isArray(value) ? (0, _astArrayMutationHelpers.arrayIsEqual)(node[key], value) : node[key] === value);
141
+ const willBeUnchanged = Object.entries(overrideProps).every(([key, value]) => {
142
+ if (Array.isArray(value)) {
143
+ // $FlowExpectedError[prop-missing]
144
+ return Array.isArray(node[key]) ? (0, _astArrayMutationHelpers.arrayIsEqual)(node[key], value) : false;
145
+ } // $FlowExpectedError[prop-missing]
146
+
147
+
148
+ return node[key] === value;
149
+ });
143
150
 
144
151
  if (willBeUnchanged) {
145
152
  return node;
@@ -151,7 +158,7 @@ function nodeWith(node, overrideProps) {
151
158
  ...overrideProps
152
159
  }; // Ensure parent pointers are correctly set within this nodes children.
153
160
 
154
- setParentPointersInDirectChildren(newNode);
161
+ setParentPointersInDirectChildren(newNode, visitorKeys);
155
162
  return newNode;
156
163
  }
157
164
  /**
@@ -159,12 +166,12 @@ function nodeWith(node, overrideProps) {
159
166
  */
160
167
 
161
168
 
162
- function shallowCloneNode(node) {
169
+ function shallowCloneNode(node, visitorKeys) {
163
170
  // $FlowExpectedError[cannot-spread-interface]
164
171
  const newNode = { ...node
165
172
  }; // Ensure parent pointers are correctly set within this nodes children.
166
173
 
167
- setParentPointersInDirectChildren(newNode);
174
+ setParentPointersInDirectChildren(newNode, visitorKeys);
168
175
  return newNode;
169
176
  }
170
177
  /**
@@ -172,7 +179,7 @@ function shallowCloneNode(node) {
172
179
  */
173
180
 
174
181
 
175
- function deepCloneNode(node) {
182
+ function deepCloneNode(node, visitorKeys) {
176
183
  const clone = JSON.parse(JSON.stringify(node, (key, value) => {
177
184
  // null out parent pointers
178
185
  if (key === 'parent') {
@@ -181,6 +188,6 @@ function deepCloneNode(node) {
181
188
 
182
189
  return value;
183
190
  }));
184
- updateAllParentPointers(clone);
191
+ updateAllParentPointers(clone, visitorKeys);
185
192
  return clone;
186
193
  }
@@ -11,6 +11,7 @@
11
11
  'use strict';
12
12
 
13
13
  import type {ESNode} from 'hermes-estree';
14
+ import type {VisitorKeysType} from '../traverse/getVisitorKeys';
14
15
 
15
16
  import {
16
17
  arrayIsEqual,
@@ -23,6 +24,7 @@ import {SimpleTraverser} from '../traverse/SimpleTraverser';
23
24
  function getParentKey(
24
25
  target: ESNode,
25
26
  parent: ESNode,
27
+ visitorKeys?: ?VisitorKeysType,
26
28
  ): $ReadOnly<
27
29
  | {
28
30
  type: 'single',
@@ -39,7 +41,7 @@ function getParentKey(
39
41
  if (parent == null) {
40
42
  throw new Error(`Expected parent node to be set on "${target.type}"`);
41
43
  }
42
- for (const key of getVisitorKeys(parent)) {
44
+ for (const key of getVisitorKeys(parent, visitorKeys)) {
43
45
  if (
44
46
  isNode(
45
47
  // $FlowExpectedError[prop-missing]
@@ -72,8 +74,13 @@ export function replaceNodeOnParent(
72
74
  originalNode: ESNode,
73
75
  originalNodeParent: ESNode,
74
76
  nodeToReplaceWith: ESNode,
77
+ visitorKeys?: ?VisitorKeysType,
75
78
  ): void {
76
- const replacementParent = getParentKey(originalNode, originalNodeParent);
79
+ const replacementParent = getParentKey(
80
+ originalNode,
81
+ originalNodeParent,
82
+ visitorKeys,
83
+ );
77
84
  const parent = replacementParent.node;
78
85
  if (replacementParent.type === 'array') {
79
86
  // $FlowExpectedError[prop-missing]
@@ -95,8 +102,13 @@ export function replaceNodeOnParent(
95
102
  export function removeNodeOnParent(
96
103
  originalNode: ESNode,
97
104
  originalNodeParent: ESNode,
105
+ visitorKeys?: ?VisitorKeysType,
98
106
  ): void {
99
- const replacementParent = getParentKey(originalNode, originalNodeParent);
107
+ const replacementParent = getParentKey(
108
+ originalNode,
109
+ originalNodeParent,
110
+ visitorKeys,
111
+ );
100
112
  const parent = replacementParent.node;
101
113
  if (replacementParent.type === 'array') {
102
114
  // $FlowExpectedError[prop-missing]
@@ -114,8 +126,11 @@ export function removeNodeOnParent(
114
126
  /**
115
127
  * Corrects the parent pointers in direct children of the given node.
116
128
  */
117
- export function setParentPointersInDirectChildren(node: ESNode): void {
118
- for (const key: $FlowFixMe of getVisitorKeys(node)) {
129
+ export function setParentPointersInDirectChildren(
130
+ node: ESNode,
131
+ visitorKeys?: ?VisitorKeysType,
132
+ ): void {
133
+ for (const key: $FlowFixMe of getVisitorKeys(node, visitorKeys)) {
119
134
  if (isNode(node[key])) {
120
135
  node[key].parent = node;
121
136
  } else if (Array.isArray(node[key])) {
@@ -129,13 +144,17 @@ export function setParentPointersInDirectChildren(node: ESNode): void {
129
144
  /**
130
145
  * Traverses the entire subtree to ensure the parent pointers are set correctly.
131
146
  */
132
- export function updateAllParentPointers(node: ESNode) {
147
+ export function updateAllParentPointers(
148
+ node: ESNode,
149
+ visitorKeys?: ?VisitorKeysType,
150
+ ) {
133
151
  SimpleTraverser.traverse(node, {
134
152
  enter(node, parent) {
135
153
  // $FlowExpectedError[cannot-write]
136
154
  node.parent = parent;
137
155
  },
138
156
  leave() {},
157
+ visitorKeys,
139
158
  });
140
159
  }
141
160
 
@@ -144,12 +163,23 @@ export function updateAllParentPointers(node: ESNode) {
144
163
  *
145
164
  * This will only create a new object if the overrides actually result in a change.
146
165
  */
147
- export function nodeWith<T: ESNode>(node: T, overrideProps: Partial<T>): T {
166
+ export function nodeWith<T: ESNode>(
167
+ node: T,
168
+ overrideProps: Partial<T>,
169
+ visitorKeys?: ?VisitorKeysType,
170
+ ): T {
148
171
  // Check if this will actually result in a change, maintaining referential equality is important.
149
- const willBeUnchanged = Object.entries(overrideProps).every(([key, value]) =>
150
- // $FlowExpectedError[incompatible-call]
151
- // $FlowExpectedError[prop-missing]
152
- Array.isArray(value) ? arrayIsEqual(node[key], value) : node[key] === value,
172
+ const willBeUnchanged = Object.entries(overrideProps).every(
173
+ ([key, value]) => {
174
+ if (Array.isArray(value)) {
175
+ // $FlowExpectedError[prop-missing]
176
+ return Array.isArray(node[key])
177
+ ? arrayIsEqual(node[key], value)
178
+ : false;
179
+ }
180
+ // $FlowExpectedError[prop-missing]
181
+ return node[key] === value;
182
+ },
153
183
  );
154
184
  if (willBeUnchanged) {
155
185
  return node;
@@ -163,7 +193,7 @@ export function nodeWith<T: ESNode>(node: T, overrideProps: Partial<T>): T {
163
193
  };
164
194
 
165
195
  // Ensure parent pointers are correctly set within this nodes children.
166
- setParentPointersInDirectChildren(newNode);
196
+ setParentPointersInDirectChildren(newNode, visitorKeys);
167
197
 
168
198
  return newNode;
169
199
  }
@@ -171,12 +201,15 @@ export function nodeWith<T: ESNode>(node: T, overrideProps: Partial<T>): T {
171
201
  /**
172
202
  * Shallow clones node, providing a new reference for an existing node.
173
203
  */
174
- export function shallowCloneNode<T: ESNode>(node: T): T {
204
+ export function shallowCloneNode<T: ESNode>(
205
+ node: T,
206
+ visitorKeys?: ?VisitorKeysType,
207
+ ): T {
175
208
  // $FlowExpectedError[cannot-spread-interface]
176
209
  const newNode: T = {...node};
177
210
 
178
211
  // Ensure parent pointers are correctly set within this nodes children.
179
- setParentPointersInDirectChildren(newNode);
212
+ setParentPointersInDirectChildren(newNode, visitorKeys);
180
213
 
181
214
  return newNode;
182
215
  }
@@ -184,7 +217,10 @@ export function shallowCloneNode<T: ESNode>(node: T): T {
184
217
  /**
185
218
  * Deeply clones node and its entire tree.
186
219
  */
187
- export function deepCloneNode<T: ESNode>(node: T): T {
220
+ export function deepCloneNode<T: ESNode>(
221
+ node: T,
222
+ visitorKeys?: ?VisitorKeysType,
223
+ ): T {
188
224
  const clone: T = JSON.parse(
189
225
  JSON.stringify(node, (key, value) => {
190
226
  // null out parent pointers
@@ -195,7 +231,7 @@ export function deepCloneNode<T: ESNode>(node: T): T {
195
231
  }),
196
232
  );
197
233
 
198
- updateAllParentPointers(clone);
234
+ updateAllParentPointers(clone, visitorKeys);
199
235
 
200
236
  return clone;
201
237
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hermes-parser",
3
- "version": "0.15.1",
3
+ "version": "0.16.0",
4
4
  "description": "A JavaScript parser built from the Hermes engine",
5
5
  "main": "dist/index.js",
6
6
  "license": "MIT",
@@ -9,7 +9,7 @@
9
9
  "url": "git@github.com:facebook/hermes.git"
10
10
  },
11
11
  "dependencies": {
12
- "hermes-estree": "0.15.1"
12
+ "hermes-estree": "0.16.0"
13
13
  },
14
14
  "devDependencies": {
15
15
  "@babel/parser": "7.7.4",