hermes-transform 0.28.0 → 0.29.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 (51) hide show
  1. package/dist/detachedNode.js +1 -0
  2. package/dist/detachedNode.js.flow +1 -0
  3. package/dist/generated/node-types.js +1 -12
  4. package/dist/generated/node-types.js.flow +2 -19
  5. package/dist/generated/special-case-node-types/misc.js +11 -0
  6. package/dist/generated/special-case-node-types/misc.js.flow +18 -0
  7. package/dist/src/detachedNode.js +178 -0
  8. package/dist/src/generated/node-types.js +2212 -0
  9. package/dist/src/generated/special-case-node-types/Comment.js +36 -0
  10. package/dist/src/generated/special-case-node-types/DeclareExportDeclaration.js +58 -0
  11. package/dist/src/generated/special-case-node-types/DeclareHook.js +33 -0
  12. package/dist/src/generated/special-case-node-types/ExportNamedDeclaration.js +44 -0
  13. package/dist/src/generated/special-case-node-types/Literal.js +97 -0
  14. package/dist/src/generated/special-case-node-types/ObjectTypeProperty.js +74 -0
  15. package/dist/src/generated/special-case-node-types/Property.js +136 -0
  16. package/dist/src/generated/special-case-node-types/misc.js +158 -0
  17. package/dist/src/generated/special-case-node-types.js +69 -0
  18. package/dist/src/index.js +53 -0
  19. package/dist/src/transform/Errors.js +43 -0
  20. package/dist/src/transform/MutationContext.js +81 -0
  21. package/dist/src/transform/TransformContext.js +213 -0
  22. package/dist/src/transform/comments/comments.js +308 -0
  23. package/dist/src/transform/comments/prettier/common/util.js +364 -0
  24. package/dist/src/transform/comments/prettier/language-js/comments.js +788 -0
  25. package/dist/src/transform/comments/prettier/language-js/loc.js +42 -0
  26. package/dist/src/transform/comments/prettier/language-js/printer-estree.js +32 -0
  27. package/dist/src/transform/comments/prettier/language-js/utils.js +119 -0
  28. package/dist/src/transform/comments/prettier/main/comments.js +440 -0
  29. package/dist/src/transform/comments/prettier/utils/get-last.js +13 -0
  30. package/dist/src/transform/mutations/AddComments.js +43 -0
  31. package/dist/src/transform/mutations/CloneCommentsTo.js +31 -0
  32. package/dist/src/transform/mutations/InsertStatement.js +91 -0
  33. package/dist/src/transform/mutations/ModifyNodeInPlace.js +59 -0
  34. package/dist/src/transform/mutations/RemoveComment.js +78 -0
  35. package/dist/src/transform/mutations/RemoveNode.js +205 -0
  36. package/dist/src/transform/mutations/RemoveStatement.js +59 -0
  37. package/dist/src/transform/mutations/ReplaceNode.js +92 -0
  38. package/dist/src/transform/mutations/ReplaceStatementWithMany.js +79 -0
  39. package/dist/src/transform/mutations/utils/getStatementParent.js +143 -0
  40. package/dist/src/transform/mutations/utils/isValidModuleDeclarationParent.js +43 -0
  41. package/dist/src/transform/parse.js +56 -0
  42. package/dist/src/transform/print.js +134 -0
  43. package/dist/src/transform/transform.js +36 -0
  44. package/dist/src/transform/transformAST.js +134 -0
  45. package/dist/src/traverse/NodeEventGenerator.js +353 -0
  46. package/dist/src/traverse/SafeEmitter.js +52 -0
  47. package/dist/src/traverse/esquery.js +37 -0
  48. package/dist/src/traverse/traverse.js +150 -0
  49. package/dist/transform/comments/prettier/language-js/comments.js +29 -1
  50. package/dist/transform/mutations/utils/getStatementParent.js.flow +7 -5
  51. package/package.json +5 -5
@@ -0,0 +1,353 @@
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.NodeEventGenerator = void 0;
16
+
17
+ var _hermesParser = require("hermes-parser");
18
+
19
+ var esquery = _interopRequireWildcard(require("./esquery"));
20
+
21
+ 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); }
22
+
23
+ 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; }
24
+
25
+ const ESQUERY_OPTIONS = Object.freeze({
26
+ visitorKeys: _hermesParser.FlowVisitorKeys,
27
+ fallback: node => {
28
+ throw new Error(`No visitor keys found for node type "${node.type}".`);
29
+ }
30
+ });
31
+ /**
32
+ * Computes the union of one or more arrays
33
+ * @param arrays One or more arrays to union
34
+ * @returns The union of the input arrays
35
+ */
36
+
37
+ function union(...arrays) {
38
+ return [...new Set(arrays.flat())];
39
+ }
40
+ /**
41
+ * Computes the intersection of one or more arrays
42
+ * @param arrays One or more arrays to intersect
43
+ * @returns The intersection of the input arrays
44
+ */
45
+
46
+
47
+ function intersection(...arrays) {
48
+ if (arrays.length === 0) {
49
+ return [];
50
+ }
51
+
52
+ let result = [...new Set(arrays[0])];
53
+
54
+ for (const array of arrays.slice(1)) {
55
+ result = result.filter(x => array.includes(x));
56
+ }
57
+
58
+ return result;
59
+ }
60
+ /**
61
+ * Gets the possible types of a selector
62
+ * @param parsedSelector An object (from esquery) describing the matching behavior of the selector
63
+ * @returns The node types that could possibly trigger this selector, or `null` if all node types could trigger it
64
+ */
65
+
66
+
67
+ function getPossibleTypes(parsedSelector) {
68
+ switch (parsedSelector.type) {
69
+ case 'identifier':
70
+ if (!(parsedSelector.value in _hermesParser.FlowVisitorKeys)) {
71
+ throw new Error(`Unexpected selector ${parsedSelector.value}`);
72
+ } // $FlowExpectedError[incompatible-return]
73
+
74
+
75
+ return [parsedSelector.value];
76
+
77
+ case 'matches':
78
+ {
79
+ const typesForComponents = parsedSelector.selectors.map(getPossibleTypes);
80
+ const typesForComponentsNonNull = typesForComponents.filter(Boolean);
81
+
82
+ if (typesForComponents.length === typesForComponentsNonNull.length) {
83
+ return union(...typesForComponentsNonNull);
84
+ }
85
+
86
+ return null;
87
+ }
88
+
89
+ case 'compound':
90
+ {
91
+ const typesForComponents = parsedSelector.selectors.map(getPossibleTypes).filter(Boolean); // If all of the components could match any type, then the compound could also match any type.
92
+
93
+ if (!typesForComponents.length) {
94
+ return null;
95
+ }
96
+ /*
97
+ * If at least one of the components could only match a particular type, the compound could only match
98
+ * the intersection of those types.
99
+ */
100
+
101
+
102
+ return intersection(...typesForComponents);
103
+ }
104
+
105
+ case 'child':
106
+ case 'descendant':
107
+ case 'sibling':
108
+ case 'adjacent':
109
+ return getPossibleTypes(parsedSelector.right);
110
+
111
+ case 'class':
112
+ if (parsedSelector.name === 'function') {
113
+ return ['FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression'];
114
+ }
115
+
116
+ return null;
117
+
118
+ default:
119
+ return null;
120
+ }
121
+ }
122
+ /**
123
+ * Counts the number of class, pseudo-class, and attribute queries in this selector
124
+ * @param parsedSelector An object (from esquery) describing the selector's matching behavior
125
+ * @returns The number of class, pseudo-class, and attribute queries in this selector
126
+ */
127
+
128
+
129
+ function countClassAttributes(parsedSelector) {
130
+ switch (parsedSelector.type) {
131
+ case 'child':
132
+ case 'descendant':
133
+ case 'sibling':
134
+ case 'adjacent':
135
+ return countClassAttributes(parsedSelector.left) + countClassAttributes(parsedSelector.right);
136
+
137
+ case 'compound':
138
+ case 'not':
139
+ case 'matches':
140
+ return parsedSelector.selectors.reduce((sum, childSelector) => sum + countClassAttributes(childSelector), 0);
141
+
142
+ case 'attribute':
143
+ case 'field':
144
+ case 'nth-child':
145
+ case 'nth-last-child':
146
+ return 1;
147
+
148
+ default:
149
+ return 0;
150
+ }
151
+ }
152
+ /**
153
+ * Counts the number of identifier queries in this selector
154
+ * @param parsedSelector An object (from esquery) describing the selector's matching behavior
155
+ * @returns The number of identifier queries
156
+ */
157
+
158
+
159
+ function countIdentifiers(parsedSelector) {
160
+ switch (parsedSelector.type) {
161
+ case 'child':
162
+ case 'descendant':
163
+ case 'sibling':
164
+ case 'adjacent':
165
+ return countIdentifiers(parsedSelector.left) + countIdentifiers(parsedSelector.right);
166
+
167
+ case 'compound':
168
+ case 'not':
169
+ case 'matches':
170
+ return parsedSelector.selectors.reduce((sum, childSelector) => sum + countIdentifiers(childSelector), 0);
171
+
172
+ case 'identifier':
173
+ return 1;
174
+
175
+ default:
176
+ return 0;
177
+ }
178
+ }
179
+ /**
180
+ * Compares the specificity of two selector objects, with CSS-like rules.
181
+ * @param selectorA An AST selector descriptor
182
+ * @param selectorB Another AST selector descriptor
183
+ * @returns
184
+ * a value less than 0 if selectorA is less specific than selectorB
185
+ * a value greater than 0 if selectorA is more specific than selectorB
186
+ * a value less than 0 if selectorA and selectorB have the same specificity, and selectorA <= selectorB alphabetically
187
+ * a value greater than 0 if selectorA and selectorB have the same specificity, and selectorA > selectorB alphabetically
188
+ */
189
+
190
+
191
+ function compareSpecificity(selectorA, selectorB) {
192
+ return selectorA.attributeCount - selectorB.attributeCount || selectorA.identifierCount - selectorB.identifierCount || (selectorA.rawSelector <= selectorB.rawSelector ? -1 : 1);
193
+ }
194
+ /**
195
+ * Parses a raw selector string, and throws a useful error if parsing fails.
196
+ * @param rawSelector A raw AST selector
197
+ * @returns An object (from esquery) describing the matching behavior of this selector
198
+ * @throws An error if the selector is invalid
199
+ */
200
+
201
+
202
+ function tryParseSelector(rawSelector) {
203
+ try {
204
+ return esquery.parse(rawSelector.replace(/:exit$/u, ''));
205
+ } catch (err) {
206
+ if (err.location && err.location.start && typeof err.location.start.offset === 'number') {
207
+ throw new SyntaxError(`Syntax error in selector "${rawSelector}" at position ${err.location.start.offset}: ${err.message}`);
208
+ }
209
+
210
+ throw err;
211
+ }
212
+ }
213
+
214
+ const selectorCache = new Map();
215
+ /**
216
+ * Parses a raw selector string, and returns the parsed selector along with specificity and type information.
217
+ * @param rawSelector A raw AST selector
218
+ * @returns A selector descriptor
219
+ */
220
+
221
+ function parseSelector(rawSelector) {
222
+ const cachedSelector = selectorCache.get(rawSelector);
223
+
224
+ if (cachedSelector) {
225
+ return cachedSelector;
226
+ }
227
+
228
+ const parsedSelector = tryParseSelector(rawSelector);
229
+ const result = {
230
+ rawSelector,
231
+ isExit: rawSelector.endsWith(':exit'),
232
+ parsedSelector,
233
+ listenerTypes: getPossibleTypes(parsedSelector),
234
+ attributeCount: countClassAttributes(parsedSelector),
235
+ identifierCount: countIdentifiers(parsedSelector)
236
+ };
237
+ selectorCache.set(rawSelector, result);
238
+ return result;
239
+ }
240
+ /**
241
+ * The event generator for AST nodes.
242
+ */
243
+
244
+
245
+ class NodeEventGenerator {
246
+ /**
247
+ * @param emitter
248
+ * An SafeEmitter which is the destination of events. This emitter must already
249
+ * have registered listeners for all of the events that it needs to listen for.
250
+ * (See lib/linter/safe-emitter.js for more details on `SafeEmitter`.)
251
+ */
252
+ constructor(emitter) {
253
+ this.emitter = void 0;
254
+ this._currentAncestry = [];
255
+ this._enterSelectorsByNodeType = new Map();
256
+ this._exitSelectorsByNodeType = new Map();
257
+ this._anyTypeEnterSelectors = [];
258
+ this._anyTypeExitSelectors = [];
259
+ this.emitter = emitter;
260
+ emitter.eventNames().forEach(rawSelector => {
261
+ const selector = parseSelector(rawSelector);
262
+
263
+ if (selector.listenerTypes) {
264
+ const typeMap = selector.isExit ? this._exitSelectorsByNodeType : this._enterSelectorsByNodeType;
265
+ selector.listenerTypes.forEach(nodeType => {
266
+ const selectors = typeMap.get(nodeType);
267
+
268
+ if (!selectors) {
269
+ typeMap.set(nodeType, [selector]);
270
+ } else {
271
+ selectors.push(selector);
272
+ }
273
+ });
274
+ } else {
275
+ const selectors = selector.isExit ? this._anyTypeExitSelectors : this._anyTypeEnterSelectors;
276
+ selectors.push(selector);
277
+ }
278
+ });
279
+
280
+ this._anyTypeEnterSelectors.sort(compareSpecificity);
281
+
282
+ this._anyTypeExitSelectors.sort(compareSpecificity);
283
+
284
+ this._enterSelectorsByNodeType.forEach(selectorList => selectorList.sort(compareSpecificity));
285
+
286
+ this._exitSelectorsByNodeType.forEach(selectorList => selectorList.sort(compareSpecificity));
287
+ }
288
+ /**
289
+ * Checks a selector against a node, and emits it if it matches
290
+ * @param node The node to check
291
+ * @param selector An AST selector descriptor
292
+ * @private
293
+ */
294
+
295
+
296
+ _applySelector(node, selector) {
297
+ if (esquery.matches(node, selector.parsedSelector, this._currentAncestry, ESQUERY_OPTIONS)) {
298
+ this.emitter.emit(selector.rawSelector, node);
299
+ }
300
+ }
301
+ /**
302
+ * Applies all appropriate selectors to a node, in specificity order
303
+ * @param node The node to check
304
+ * @param isExit `false` if the node is currently being entered, `true` if it's currently being exited
305
+ * @private
306
+ */
307
+
308
+
309
+ _applySelectors(node, isExit) {
310
+ const selectorsByNodeType = (isExit ? this._exitSelectorsByNodeType : this._enterSelectorsByNodeType).get(node.type) || [];
311
+ const anyTypeSelectors = isExit ? this._anyTypeExitSelectors : this._anyTypeEnterSelectors;
312
+ /*
313
+ * selectorsByNodeType and anyTypeSelectors were already sorted by specificity in the constructor.
314
+ * Iterate through each of them, applying selectors in the right order.
315
+ */
316
+
317
+ let selectorsByTypeIndex = 0;
318
+ let anyTypeSelectorsIndex = 0;
319
+
320
+ while (selectorsByTypeIndex < selectorsByNodeType.length || anyTypeSelectorsIndex < anyTypeSelectors.length) {
321
+ if (selectorsByTypeIndex >= selectorsByNodeType.length || anyTypeSelectorsIndex < anyTypeSelectors.length && compareSpecificity(anyTypeSelectors[anyTypeSelectorsIndex], selectorsByNodeType[selectorsByTypeIndex]) < 0) {
322
+ this._applySelector(node, anyTypeSelectors[anyTypeSelectorsIndex++]);
323
+ } else {
324
+ this._applySelector(node, selectorsByNodeType[selectorsByTypeIndex++]);
325
+ }
326
+ }
327
+ }
328
+ /**
329
+ * Emits an event of entering AST node.
330
+ * @param node A node which was entered.
331
+ */
332
+
333
+
334
+ enterNode(node) {
335
+ this._applySelectors(node, false);
336
+
337
+ this._currentAncestry.unshift(node);
338
+ }
339
+ /**
340
+ * Emits an event of leaving AST node.
341
+ * @param node A node which was left.
342
+ */
343
+
344
+
345
+ leaveNode(node) {
346
+ this._currentAncestry.shift();
347
+
348
+ this._applySelectors(node, true);
349
+ }
350
+
351
+ }
352
+
353
+ exports.NodeEventGenerator = NodeEventGenerator;
@@ -0,0 +1,52 @@
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.SafeEmitter = void 0;
16
+
17
+ /**
18
+ * Creates an object which can listen for and emit events.
19
+ * This is similar to the EventEmitter API in Node's standard library, but it has a few differences.
20
+ * The goal is to allow multiple modules to attach arbitrary listeners to the same emitter, without
21
+ * letting the modules know about each other at all.
22
+ * 1. It has no special keys like `error` and `newListener`, which would allow modules to detect when
23
+ * another module throws an error or registers a listener.
24
+ * 2. It calls listener functions without any `this` value. (`EventEmitter` calls listeners with a
25
+ * `this` value of the emitter instance, which would give listeners access to other listeners.)
26
+ */
27
+ class SafeEmitter {
28
+ constructor() {
29
+ this.listeners = Object.create(null);
30
+ }
31
+
32
+ on(eventName, listener) {
33
+ if (eventName in this.listeners) {
34
+ this.listeners[eventName].push(listener);
35
+ } else {
36
+ this.listeners[eventName] = [listener];
37
+ }
38
+ }
39
+
40
+ emit(eventName, node) {
41
+ if (eventName in this.listeners) {
42
+ this.listeners[eventName].forEach(listener => listener(node));
43
+ }
44
+ }
45
+
46
+ eventNames() {
47
+ return Object.keys(this.listeners);
48
+ }
49
+
50
+ }
51
+
52
+ exports.SafeEmitter = SafeEmitter;
@@ -0,0 +1,37 @@
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.query = exports.parse = exports.matches = exports.match = void 0;
16
+
17
+ var _esquery = _interopRequireDefault(require("esquery"));
18
+
19
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
20
+
21
+ // $FlowExpectedError[cannot-resolve-module]
22
+
23
+ /** Parse a selector and return its AST. */
24
+ const parse = _esquery.default.parse;
25
+ /** From a JS AST and a selector AST, collect all JS AST nodes that match the selector. */
26
+
27
+ exports.parse = parse;
28
+ const match = _esquery.default.match;
29
+ /** Given a `node` and its ancestors, determine if `node` is matched by `selector`. */
30
+
31
+ exports.match = match;
32
+ const matches = _esquery.default.matches;
33
+ /** Query the code AST using the selector string. */
34
+
35
+ exports.matches = matches;
36
+ const query = _esquery.default.query;
37
+ exports.query = query;
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.traverse = traverse;
7
+ exports.traverseWithContext = traverseWithContext;
8
+
9
+ var _codeFrame = require("@babel/code-frame");
10
+
11
+ var _NodeEventGenerator = require("./NodeEventGenerator");
12
+
13
+ var _SafeEmitter = require("./SafeEmitter");
14
+
15
+ var _hermesParser = require("hermes-parser");
16
+
17
+ /**
18
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
19
+ *
20
+ * This source code is licensed under the MIT license found in the
21
+ * LICENSE file in the root directory of this source tree.
22
+ *
23
+ *
24
+ * @format
25
+ */
26
+
27
+ /**
28
+ * Traverse the AST with additional context members provided by `additionalContext`.
29
+ * @param ast the ESTree AST to traverse
30
+ * @param scopeManager the eslint-scope compatible scope manager instance calculated using the ast
31
+ * @param additionalContext a callback function which returns additional context members to add to the context provided to the visitor
32
+ */
33
+ function traverseWithContext(code, ast, scopeManager, additionalContext, visitor) {
34
+ const emitter = new _SafeEmitter.SafeEmitter();
35
+ let currentNode = ast;
36
+ let shouldSkipTraversal = false;
37
+ let shouldStopTraversal = false;
38
+
39
+ const getScope = (givenNode = currentNode) => {
40
+ // On Program node, get the outermost scope to avoid return Node.js special function scope or ES modules scope.
41
+ const inner = givenNode.type !== 'Program';
42
+
43
+ for (let node = givenNode; node; node = node.parent) {
44
+ const scope = scopeManager.acquire(node, inner);
45
+
46
+ if (scope) {
47
+ if (scope.type === 'function-expression-name') {
48
+ return scope.childScopes[0];
49
+ }
50
+
51
+ return scope;
52
+ }
53
+ }
54
+
55
+ return scopeManager.scopes[0];
56
+ };
57
+
58
+ const traversalContextBase = Object.freeze({
59
+ buildCodeFrame: (node, message) => {
60
+ // babel uses 1-indexed columns
61
+ const locForBabel = {
62
+ start: {
63
+ line: node.loc.start.line,
64
+ column: node.loc.start.column + 1
65
+ },
66
+ end: {
67
+ line: node.loc.end.line,
68
+ column: node.loc.end.column + 1
69
+ }
70
+ };
71
+ return (0, _codeFrame.codeFrameColumns)(code, locForBabel, {
72
+ linesAbove: 0,
73
+ linesBelow: 0,
74
+ highlightCode: process.env.NODE_ENV !== 'test',
75
+ message: message
76
+ });
77
+ },
78
+ buildSimpleCodeFrame: (node, message) => {
79
+ return `[${node.type}:${node.loc.start.line}:${node.loc.start.column}] ${message}`;
80
+ },
81
+ getDeclaredVariables: node => scopeManager.getDeclaredVariables(node),
82
+ getBinding: name => {
83
+ let currentScope = getScope();
84
+
85
+ while (currentScope != null) {
86
+ for (const variable of currentScope.variables) {
87
+ if (variable.defs.length && variable.name === name) {
88
+ return variable;
89
+ }
90
+ }
91
+
92
+ currentScope = currentScope.upper;
93
+ }
94
+
95
+ return null;
96
+ },
97
+ getScope,
98
+ stopTraversal: () => {
99
+ shouldStopTraversal = true;
100
+ },
101
+ skipTraversal: () => {
102
+ shouldSkipTraversal = true;
103
+ }
104
+ });
105
+ const traversalContext = Object.freeze({ ...traversalContextBase,
106
+ ...additionalContext(traversalContextBase)
107
+ });
108
+ const selectors = visitor(traversalContext); // add all the selectors from the visitor as listeners
109
+
110
+ Object.keys(selectors).forEach(selector => {
111
+ // flow doesn't want us to be general here - but it's safe
112
+ const listener = selectors[selector];
113
+
114
+ if (listener) {
115
+ emitter.on(selector, listener);
116
+ }
117
+ });
118
+ const eventGenerator = new _NodeEventGenerator.NodeEventGenerator(emitter);
119
+
120
+ function checkTraversalFlags() {
121
+ if (shouldStopTraversal) {
122
+ // No need to reset the flag since we won't enter any more nodes.
123
+ throw _hermesParser.SimpleTraverser.Break;
124
+ }
125
+
126
+ if (shouldSkipTraversal) {
127
+ shouldSkipTraversal = false;
128
+ throw _hermesParser.SimpleTraverser.Skip;
129
+ }
130
+ }
131
+
132
+ _hermesParser.SimpleTraverser.traverse(ast, {
133
+ enter(node) {
134
+ currentNode = node;
135
+ eventGenerator.enterNode(node);
136
+ checkTraversalFlags();
137
+ },
138
+
139
+ leave(node) {
140
+ currentNode = node;
141
+ eventGenerator.leaveNode(node);
142
+ checkTraversalFlags();
143
+ }
144
+
145
+ });
146
+ }
147
+
148
+ function traverse(code, ast, scopeManager, visitor) {
149
+ traverseWithContext(code, ast, scopeManager, () => {}, visitor);
150
+ }
@@ -59,7 +59,7 @@ const {
59
59
 
60
60
 
61
61
  function handleOwnLineComment(context) {
62
- return [handleIgnoreComments, handleLastFunctionArgComments, handleMemberExpressionComments, handleIfStatementComments, handleWhileComments, handleTryStatementComments, handleClassComments, handleImportSpecifierComments, handleForComments, handleUnionTypeComments, handleOnlyComments, handleImportDeclarationComments, handleAssignmentPatternComments, handleMethodNameComments, handleLabeledStatementComments].some(fn => fn(context));
62
+ return [handleIgnoreComments, handleLastFunctionArgComments, handleMemberExpressionComments, handleIfStatementComments, handleWhileComments, handleTryStatementComments, handleClassComments, handleImportSpecifierComments, handleForComments, handleUnionTypeComments, handleMatchOrPatternComments, handleOnlyComments, handleImportDeclarationComments, handleAssignmentPatternComments, handleMethodNameComments, handleLabeledStatementComments].some(fn => fn(context));
63
63
  }
64
64
  /**
65
65
  * @param {CommentContext} context
@@ -553,6 +553,34 @@ function handleUnionTypeComments({
553
553
  return false;
554
554
  }
555
555
 
556
+ function handleMatchOrPatternComments({
557
+ comment,
558
+ precedingNode,
559
+ enclosingNode,
560
+ followingNode
561
+ }) {
562
+ if (enclosingNode && enclosingNode.type === 'MatchOrPattern') {
563
+ if (isPrettierIgnoreComment(comment)) {
564
+ followingNode.prettierIgnore = true;
565
+ comment.unignore = true;
566
+ }
567
+
568
+ if (precedingNode) {
569
+ addTrailingComment(precedingNode, comment);
570
+ return true;
571
+ }
572
+
573
+ return false;
574
+ }
575
+
576
+ if (followingNode && followingNode.type === 'MatchOrPattern' && isPrettierIgnoreComment(comment)) {
577
+ followingNode.types[0].prettierIgnore = true;
578
+ comment.unignore = true;
579
+ }
580
+
581
+ return false;
582
+ }
583
+
556
584
  function handlePropertyComments({
557
585
  comment,
558
586
  enclosingNode
@@ -19,9 +19,7 @@ import type {
19
19
 
20
20
  import {InvalidStatementError} from '../../Errors';
21
21
 
22
- export function getStatementParent(
23
- target: ModuleDeclaration | Statement,
24
- ): $ReadOnly<
22
+ type StatementParent = $ReadOnly<
25
23
  | {
26
24
  type: 'single',
27
25
  parent: StatementParentSingle,
@@ -33,7 +31,11 @@ export function getStatementParent(
33
31
  key: string,
34
32
  targetIndex: number,
35
33
  },
36
- > {
34
+ >;
35
+
36
+ export function getStatementParent(
37
+ target: ModuleDeclaration | Statement,
38
+ ): StatementParent {
37
39
  function assertValidStatementLocation<T: $ReadOnly<interface {type: string}>>(
38
40
  parentWithType: T,
39
41
  ...invalidKeys: $ReadOnlyArray<$Keys<T>>
@@ -63,7 +65,7 @@ export function getStatementParent(
63
65
  }
64
66
 
65
67
  const parent = target.parent;
66
- const result = (() => {
68
+ const result: StatementParent = (() => {
67
69
  switch (parent.type) {
68
70
  case 'IfStatement': {
69
71
  assertValidStatementLocation(parent, 'test');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hermes-transform",
3
- "version": "0.28.0",
3
+ "version": "0.29.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,14 +12,14 @@
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.28.0",
16
- "hermes-estree": "0.28.0",
17
- "hermes-parser": "0.28.0",
15
+ "hermes-eslint": "0.29.0",
16
+ "hermes-estree": "0.29.0",
17
+ "hermes-parser": "0.29.0",
18
18
  "string-width": "4.2.3"
19
19
  },
20
20
  "peerDependencies": {
21
21
  "prettier": "^3.0.0 || ^2.7.1",
22
- "prettier-plugin-hermes-parser": "0.28.0"
22
+ "prettier-plugin-hermes-parser": "0.29.0"
23
23
  },
24
24
  "files": [
25
25
  "dist",