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,365 @@
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
+ * @format
8
+ */
9
+ 'use strict';
10
+
11
+ 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); }
12
+
13
+ var stringWidth = require('string-width');
14
+
15
+ var getLast = require('../utils/get-last.js');
16
+
17
+ var notAsciiRegex = /[^\x20-\x7F]/;
18
+ /**
19
+ * @typedef {{backwards?: boolean}} SkipOptions
20
+ */
21
+
22
+ /**
23
+ * @param {string | RegExp} chars
24
+ * @returns {(text: string, index: number | false, opts?: SkipOptions) => number | false}
25
+ */
26
+
27
+ function skip(chars) {
28
+ return function (text, index, opts) {
29
+ var backwards = opts && opts.backwards; // Allow `skip` functions to be threaded together without having
30
+ // to check for failures (did someone say monads?).
31
+
32
+ /* istanbul ignore next */
33
+
34
+ if (index === false) {
35
+ return false;
36
+ }
37
+
38
+ var length = text.length;
39
+ var cursor = index;
40
+
41
+ while (cursor >= 0 && cursor < length) {
42
+ var c = text.charAt(cursor);
43
+
44
+ if (chars instanceof RegExp) {
45
+ if (!chars.test(c)) {
46
+ return cursor;
47
+ }
48
+ } else if (!chars.includes(c)) {
49
+ return cursor;
50
+ }
51
+
52
+ backwards ? cursor-- : cursor++;
53
+ }
54
+
55
+ if (cursor === -1 || cursor === length) {
56
+ // If we reached the beginning or end of the file, return the
57
+ // out-of-bounds cursor. It's up to the caller to handle this
58
+ // correctly. We don't want to indicate `false` though if it
59
+ // actually skipped valid characters.
60
+ return cursor;
61
+ }
62
+
63
+ return false;
64
+ };
65
+ }
66
+ /**
67
+ * @type {(text: string, index: number | false, opts?: SkipOptions) => number | false}
68
+ */
69
+
70
+
71
+ var skipWhitespace = skip(/\s/);
72
+ /**
73
+ * @type {(text: string, index: number | false, opts?: SkipOptions) => number | false}
74
+ */
75
+
76
+ var skipSpaces = skip(' \t');
77
+ /**
78
+ * @type {(text: string, index: number | false, opts?: SkipOptions) => number | false}
79
+ */
80
+
81
+ var skipToLineEnd = skip(',; \t');
82
+ /**
83
+ * @type {(text: string, index: number | false, opts?: SkipOptions) => number | false}
84
+ */
85
+
86
+ var skipEverythingButNewLine = skip(/[^\n\r]/);
87
+ /**
88
+ * @param {string} text
89
+ * @param {number | false} index
90
+ * @returns {number | false}
91
+ */
92
+
93
+ function skipInlineComment(text, index) {
94
+ /* istanbul ignore next */
95
+ if (index === false) {
96
+ return false;
97
+ }
98
+
99
+ if (text.charAt(index) === '/' && text.charAt(index + 1) === '*') {
100
+ for (var i = index + 2; i < text.length; ++i) {
101
+ if (text.charAt(i) === '*' && text.charAt(i + 1) === '/') {
102
+ return i + 2;
103
+ }
104
+ }
105
+ }
106
+
107
+ return index;
108
+ }
109
+ /**
110
+ * @param {string} text
111
+ * @param {number | false} index
112
+ * @returns {number | false}
113
+ */
114
+
115
+
116
+ function skipTrailingComment(text, index) {
117
+ /* istanbul ignore next */
118
+ if (index === false) {
119
+ return false;
120
+ }
121
+
122
+ if (text.charAt(index) === '/' && text.charAt(index + 1) === '/') {
123
+ return skipEverythingButNewLine(text, index);
124
+ }
125
+
126
+ return index;
127
+ } // This one doesn't use the above helper function because it wants to
128
+ // test \r\n in order and `skip` doesn't support ordering and we only
129
+ // want to skip one newline. It's simple to implement.
130
+
131
+ /**
132
+ * @param {string} text
133
+ * @param {number | false} index
134
+ * @param {SkipOptions=} opts
135
+ * @returns {number | false}
136
+ */
137
+
138
+
139
+ function skipNewline(text, index, opts) {
140
+ var backwards = opts && opts.backwards;
141
+
142
+ if (index === false) {
143
+ return false;
144
+ }
145
+
146
+ var atIndex = text.charAt(index);
147
+
148
+ if (backwards) {
149
+ // We already replace `\r\n` with `\n` before parsing
150
+
151
+ /* istanbul ignore next */
152
+ if (text.charAt(index - 1) === '\r' && atIndex === '\n') {
153
+ return index - 2;
154
+ }
155
+
156
+ if (atIndex === '\n' || atIndex === '\r' || atIndex === "\u2028" || atIndex === "\u2029") {
157
+ return index - 1;
158
+ }
159
+ } else {
160
+ // We already replace `\r\n` with `\n` before parsing
161
+
162
+ /* istanbul ignore next */
163
+ if (atIndex === '\r' && text.charAt(index + 1) === '\n') {
164
+ return index + 2;
165
+ }
166
+
167
+ if (atIndex === '\n' || atIndex === '\r' || atIndex === "\u2028" || atIndex === "\u2029") {
168
+ return index + 1;
169
+ }
170
+ }
171
+
172
+ return index;
173
+ }
174
+ /**
175
+ * @param {string} text
176
+ * @param {number} index
177
+ * @param {SkipOptions=} opts
178
+ * @returns {boolean}
179
+ */
180
+
181
+
182
+ function hasNewline(text, index) {
183
+ var opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
184
+ var idx = skipSpaces(text, opts.backwards ? index - 1 : index, opts);
185
+ var idx2 = skipNewline(text, idx, opts);
186
+ return idx !== idx2;
187
+ }
188
+ /**
189
+ * @param {string} text
190
+ * @param {number} start
191
+ * @param {number} end
192
+ * @returns {boolean}
193
+ */
194
+
195
+
196
+ function hasNewlineInRange(text, start, end) {
197
+ for (var i = start; i < end; ++i) {
198
+ if (text.charAt(i) === '\n') {
199
+ return true;
200
+ }
201
+ }
202
+
203
+ return false;
204
+ }
205
+ /**
206
+ * @param {string} text
207
+ * @param {number} index
208
+ * @returns {boolean}
209
+ */
210
+
211
+
212
+ function isNextLineEmptyAfterIndex(text, index) {
213
+ /** @type {number | false} */
214
+ var oldIdx = null;
215
+ /** @type {number | false} */
216
+
217
+ var idx = index;
218
+
219
+ while (idx !== oldIdx) {
220
+ // We need to skip all the potential trailing inline comments
221
+ oldIdx = idx;
222
+ idx = skipToLineEnd(text, idx);
223
+ idx = skipInlineComment(text, idx);
224
+ idx = skipSpaces(text, idx);
225
+ }
226
+
227
+ idx = skipTrailingComment(text, idx);
228
+ idx = skipNewline(text, idx);
229
+ return idx !== false && hasNewline(text, idx);
230
+ }
231
+ /**
232
+ * @param {string} text
233
+ * @param {number} idx
234
+ * @returns {number | false}
235
+ */
236
+
237
+
238
+ function getNextNonSpaceNonCommentCharacterIndexWithStartIndex(text, idx) {
239
+ /** @type {number | false} */
240
+ var oldIdx = null;
241
+ /** @type {number | false} */
242
+
243
+ var nextIdx = idx;
244
+
245
+ while (nextIdx !== oldIdx) {
246
+ oldIdx = nextIdx;
247
+ nextIdx = skipSpaces(text, nextIdx);
248
+ nextIdx = skipInlineComment(text, nextIdx);
249
+ nextIdx = skipTrailingComment(text, nextIdx);
250
+ nextIdx = skipNewline(text, nextIdx);
251
+ }
252
+
253
+ return nextIdx;
254
+ }
255
+ /**
256
+ * @template N
257
+ * @param {string} text
258
+ * @param {N} node
259
+ * @param {(node: N) => number} locEnd
260
+ * @returns {number | false}
261
+ */
262
+
263
+
264
+ function getNextNonSpaceNonCommentCharacterIndex(text, node, locEnd) {
265
+ return getNextNonSpaceNonCommentCharacterIndexWithStartIndex(text, locEnd(node));
266
+ }
267
+ /**
268
+ * @template N
269
+ * @param {string} text
270
+ * @param {N} node
271
+ * @param {(node: N) => number} locEnd
272
+ * @returns {string}
273
+ */
274
+
275
+
276
+ function getNextNonSpaceNonCommentCharacter(text, node, locEnd) {
277
+ return text.charAt( // @ts-expect-error => TBD: can return false, should we define a fallback?
278
+ getNextNonSpaceNonCommentCharacterIndex(text, node, locEnd));
279
+ }
280
+ /**
281
+ * @param {string} text
282
+ * @returns {number}
283
+ */
284
+
285
+
286
+ function getStringWidth(text) {
287
+ if (!text) {
288
+ return 0;
289
+ } // shortcut to avoid needless string `RegExp`s, replacements, and allocations within `string-width`
290
+
291
+
292
+ if (!notAsciiRegex.test(text)) {
293
+ return text.length;
294
+ }
295
+
296
+ return stringWidth(text);
297
+ }
298
+
299
+ function addCommentHelper(node, comment) {
300
+ var comments = node.comments || (node.comments = []);
301
+ comments.push(comment);
302
+ comment.printed = false;
303
+ comment.nodeDescription = describeNodeForDebugging(node);
304
+ }
305
+
306
+ function addLeadingComment(node, comment) {
307
+ comment.leading = true;
308
+ comment.trailing = false;
309
+ addCommentHelper(node, comment);
310
+ }
311
+
312
+ function addDanglingComment(node, comment, marker) {
313
+ comment.leading = false;
314
+ comment.trailing = false;
315
+
316
+ if (marker) {
317
+ comment.marker = marker;
318
+ }
319
+
320
+ addCommentHelper(node, comment);
321
+ }
322
+
323
+ function addTrailingComment(node, comment) {
324
+ comment.leading = false;
325
+ comment.trailing = true;
326
+ addCommentHelper(node, comment);
327
+ }
328
+ /**
329
+ * @param {any} object
330
+ * @returns {object is Array<any>}
331
+ */
332
+
333
+
334
+ function isNonEmptyArray(object) {
335
+ return Array.isArray(object) && object.length > 0;
336
+ }
337
+
338
+ function describeNodeForDebugging(node) {
339
+ var nodeType = node.type || node.kind || '(unknown type)';
340
+ var nodeName = String(node.name || node.id && (_typeof(node.id) === 'object' ? node.id.name : node.id) || node.key && (_typeof(node.key) === 'object' ? node.key.name : node.key) || node.value && (_typeof(node.value) === 'object' ? '' : String(node.value)) || node.operator || '');
341
+
342
+ if (nodeName.length > 20) {
343
+ nodeName = nodeName.slice(0, 19) + '…';
344
+ }
345
+
346
+ return nodeType + (nodeName ? ' ' + nodeName : '');
347
+ }
348
+
349
+ module.exports = {
350
+ getStringWidth: getStringWidth,
351
+ getLast: getLast,
352
+ getNextNonSpaceNonCommentCharacterIndexWithStartIndex: getNextNonSpaceNonCommentCharacterIndexWithStartIndex,
353
+ getNextNonSpaceNonCommentCharacterIndex: getNextNonSpaceNonCommentCharacterIndex,
354
+ getNextNonSpaceNonCommentCharacter: getNextNonSpaceNonCommentCharacter,
355
+ skipWhitespace: skipWhitespace,
356
+ skipSpaces: skipSpaces,
357
+ skipNewline: skipNewline,
358
+ isNextLineEmptyAfterIndex: isNextLineEmptyAfterIndex,
359
+ hasNewline: hasNewline,
360
+ hasNewlineInRange: hasNewlineInRange,
361
+ addLeadingComment: addLeadingComment,
362
+ addDanglingComment: addDanglingComment,
363
+ addTrailingComment: addTrailingComment,
364
+ isNonEmptyArray: isNonEmptyArray
365
+ };
@@ -0,0 +1,349 @@
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
+ * @format
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ const stringWidth = require('string-width');
13
+ const getLast = require('../utils/get-last.js');
14
+
15
+ const notAsciiRegex = /[^\x20-\x7F]/;
16
+
17
+ /**
18
+ * @typedef {{backwards?: boolean}} SkipOptions
19
+ */
20
+
21
+ /**
22
+ * @param {string | RegExp} chars
23
+ * @returns {(text: string, index: number | false, opts?: SkipOptions) => number | false}
24
+ */
25
+ function skip(chars) {
26
+ return (text, index, opts) => {
27
+ const backwards = opts && opts.backwards;
28
+
29
+ // Allow `skip` functions to be threaded together without having
30
+ // to check for failures (did someone say monads?).
31
+ /* istanbul ignore next */
32
+ if (index === false) {
33
+ return false;
34
+ }
35
+
36
+ const {length} = text;
37
+ let cursor = index;
38
+ while (cursor >= 0 && cursor < length) {
39
+ const c = text.charAt(cursor);
40
+ if (chars instanceof RegExp) {
41
+ if (!chars.test(c)) {
42
+ return cursor;
43
+ }
44
+ } else if (!chars.includes(c)) {
45
+ return cursor;
46
+ }
47
+
48
+ backwards ? cursor-- : cursor++;
49
+ }
50
+
51
+ if (cursor === -1 || cursor === length) {
52
+ // If we reached the beginning or end of the file, return the
53
+ // out-of-bounds cursor. It's up to the caller to handle this
54
+ // correctly. We don't want to indicate `false` though if it
55
+ // actually skipped valid characters.
56
+ return cursor;
57
+ }
58
+ return false;
59
+ };
60
+ }
61
+
62
+ /**
63
+ * @type {(text: string, index: number | false, opts?: SkipOptions) => number | false}
64
+ */
65
+ const skipWhitespace = skip(/\s/);
66
+ /**
67
+ * @type {(text: string, index: number | false, opts?: SkipOptions) => number | false}
68
+ */
69
+ const skipSpaces = skip(' \t');
70
+ /**
71
+ * @type {(text: string, index: number | false, opts?: SkipOptions) => number | false}
72
+ */
73
+ const skipToLineEnd = skip(',; \t');
74
+ /**
75
+ * @type {(text: string, index: number | false, opts?: SkipOptions) => number | false}
76
+ */
77
+ const skipEverythingButNewLine = skip(/[^\n\r]/);
78
+
79
+ /**
80
+ * @param {string} text
81
+ * @param {number | false} index
82
+ * @returns {number | false}
83
+ */
84
+ function skipInlineComment(text, index) {
85
+ /* istanbul ignore next */
86
+ if (index === false) {
87
+ return false;
88
+ }
89
+
90
+ if (text.charAt(index) === '/' && text.charAt(index + 1) === '*') {
91
+ for (let i = index + 2; i < text.length; ++i) {
92
+ if (text.charAt(i) === '*' && text.charAt(i + 1) === '/') {
93
+ return i + 2;
94
+ }
95
+ }
96
+ }
97
+ return index;
98
+ }
99
+
100
+ /**
101
+ * @param {string} text
102
+ * @param {number | false} index
103
+ * @returns {number | false}
104
+ */
105
+ function skipTrailingComment(text, index) {
106
+ /* istanbul ignore next */
107
+ if (index === false) {
108
+ return false;
109
+ }
110
+
111
+ if (text.charAt(index) === '/' && text.charAt(index + 1) === '/') {
112
+ return skipEverythingButNewLine(text, index);
113
+ }
114
+ return index;
115
+ }
116
+
117
+ // This one doesn't use the above helper function because it wants to
118
+ // test \r\n in order and `skip` doesn't support ordering and we only
119
+ // want to skip one newline. It's simple to implement.
120
+ /**
121
+ * @param {string} text
122
+ * @param {number | false} index
123
+ * @param {SkipOptions=} opts
124
+ * @returns {number | false}
125
+ */
126
+ function skipNewline(text, index, opts) {
127
+ const backwards = opts && opts.backwards;
128
+ if (index === false) {
129
+ return false;
130
+ }
131
+
132
+ const atIndex = text.charAt(index);
133
+ if (backwards) {
134
+ // We already replace `\r\n` with `\n` before parsing
135
+ /* istanbul ignore next */
136
+ if (text.charAt(index - 1) === '\r' && atIndex === '\n') {
137
+ return index - 2;
138
+ }
139
+ if (
140
+ atIndex === '\n' ||
141
+ atIndex === '\r' ||
142
+ atIndex === '\u2028' ||
143
+ atIndex === '\u2029'
144
+ ) {
145
+ return index - 1;
146
+ }
147
+ } else {
148
+ // We already replace `\r\n` with `\n` before parsing
149
+ /* istanbul ignore next */
150
+ if (atIndex === '\r' && text.charAt(index + 1) === '\n') {
151
+ return index + 2;
152
+ }
153
+ if (
154
+ atIndex === '\n' ||
155
+ atIndex === '\r' ||
156
+ atIndex === '\u2028' ||
157
+ atIndex === '\u2029'
158
+ ) {
159
+ return index + 1;
160
+ }
161
+ }
162
+
163
+ return index;
164
+ }
165
+
166
+ /**
167
+ * @param {string} text
168
+ * @param {number} index
169
+ * @param {SkipOptions=} opts
170
+ * @returns {boolean}
171
+ */
172
+ function hasNewline(text, index, opts = {}) {
173
+ const idx = skipSpaces(text, opts.backwards ? index - 1 : index, opts);
174
+ const idx2 = skipNewline(text, idx, opts);
175
+ return idx !== idx2;
176
+ }
177
+
178
+ /**
179
+ * @param {string} text
180
+ * @param {number} start
181
+ * @param {number} end
182
+ * @returns {boolean}
183
+ */
184
+ function hasNewlineInRange(text, start, end) {
185
+ for (let i = start; i < end; ++i) {
186
+ if (text.charAt(i) === '\n') {
187
+ return true;
188
+ }
189
+ }
190
+ return false;
191
+ }
192
+
193
+ /**
194
+ * @param {string} text
195
+ * @param {number} index
196
+ * @returns {boolean}
197
+ */
198
+ function isNextLineEmptyAfterIndex(text, index) {
199
+ /** @type {number | false} */
200
+ let oldIdx = null;
201
+ /** @type {number | false} */
202
+ let idx = index;
203
+ while (idx !== oldIdx) {
204
+ // We need to skip all the potential trailing inline comments
205
+ oldIdx = idx;
206
+ idx = skipToLineEnd(text, idx);
207
+ idx = skipInlineComment(text, idx);
208
+ idx = skipSpaces(text, idx);
209
+ }
210
+ idx = skipTrailingComment(text, idx);
211
+ idx = skipNewline(text, idx);
212
+ return idx !== false && hasNewline(text, idx);
213
+ }
214
+
215
+ /**
216
+ * @param {string} text
217
+ * @param {number} idx
218
+ * @returns {number | false}
219
+ */
220
+ function getNextNonSpaceNonCommentCharacterIndexWithStartIndex(text, idx) {
221
+ /** @type {number | false} */
222
+ let oldIdx = null;
223
+ /** @type {number | false} */
224
+ let nextIdx = idx;
225
+ while (nextIdx !== oldIdx) {
226
+ oldIdx = nextIdx;
227
+ nextIdx = skipSpaces(text, nextIdx);
228
+ nextIdx = skipInlineComment(text, nextIdx);
229
+ nextIdx = skipTrailingComment(text, nextIdx);
230
+ nextIdx = skipNewline(text, nextIdx);
231
+ }
232
+ return nextIdx;
233
+ }
234
+
235
+ /**
236
+ * @template N
237
+ * @param {string} text
238
+ * @param {N} node
239
+ * @param {(node: N) => number} locEnd
240
+ * @returns {number | false}
241
+ */
242
+ function getNextNonSpaceNonCommentCharacterIndex(text, node, locEnd) {
243
+ return getNextNonSpaceNonCommentCharacterIndexWithStartIndex(
244
+ text,
245
+ locEnd(node),
246
+ );
247
+ }
248
+
249
+ /**
250
+ * @template N
251
+ * @param {string} text
252
+ * @param {N} node
253
+ * @param {(node: N) => number} locEnd
254
+ * @returns {string}
255
+ */
256
+ function getNextNonSpaceNonCommentCharacter(text, node, locEnd) {
257
+ return text.charAt(
258
+ // @ts-expect-error => TBD: can return false, should we define a fallback?
259
+ getNextNonSpaceNonCommentCharacterIndex(text, node, locEnd),
260
+ );
261
+ }
262
+
263
+ /**
264
+ * @param {string} text
265
+ * @returns {number}
266
+ */
267
+ function getStringWidth(text) {
268
+ if (!text) {
269
+ return 0;
270
+ }
271
+
272
+ // shortcut to avoid needless string `RegExp`s, replacements, and allocations within `string-width`
273
+ if (!notAsciiRegex.test(text)) {
274
+ return text.length;
275
+ }
276
+
277
+ return stringWidth(text);
278
+ }
279
+
280
+ function addCommentHelper(node, comment) {
281
+ const comments = node.comments || (node.comments = []);
282
+ comments.push(comment);
283
+ comment.printed = false;
284
+ comment.nodeDescription = describeNodeForDebugging(node);
285
+ }
286
+
287
+ function addLeadingComment(node, comment) {
288
+ comment.leading = true;
289
+ comment.trailing = false;
290
+ addCommentHelper(node, comment);
291
+ }
292
+
293
+ function addDanglingComment(node, comment, marker) {
294
+ comment.leading = false;
295
+ comment.trailing = false;
296
+ if (marker) {
297
+ comment.marker = marker;
298
+ }
299
+ addCommentHelper(node, comment);
300
+ }
301
+
302
+ function addTrailingComment(node, comment) {
303
+ comment.leading = false;
304
+ comment.trailing = true;
305
+ addCommentHelper(node, comment);
306
+ }
307
+
308
+ /**
309
+ * @param {any} object
310
+ * @returns {object is Array<any>}
311
+ */
312
+ function isNonEmptyArray(object) {
313
+ return Array.isArray(object) && object.length > 0;
314
+ }
315
+
316
+ function describeNodeForDebugging(node) {
317
+ const nodeType = node.type || node.kind || '(unknown type)';
318
+ let nodeName = String(
319
+ node.name ||
320
+ (node.id && (typeof node.id === 'object' ? node.id.name : node.id)) ||
321
+ (node.key && (typeof node.key === 'object' ? node.key.name : node.key)) ||
322
+ (node.value &&
323
+ (typeof node.value === 'object' ? '' : String(node.value))) ||
324
+ node.operator ||
325
+ '',
326
+ );
327
+ if (nodeName.length > 20) {
328
+ nodeName = nodeName.slice(0, 19) + '…';
329
+ }
330
+ return nodeType + (nodeName ? ' ' + nodeName : '');
331
+ }
332
+
333
+ module.exports = {
334
+ getStringWidth,
335
+ getLast,
336
+ getNextNonSpaceNonCommentCharacterIndexWithStartIndex,
337
+ getNextNonSpaceNonCommentCharacterIndex,
338
+ getNextNonSpaceNonCommentCharacter,
339
+ skipWhitespace,
340
+ skipSpaces,
341
+ skipNewline,
342
+ isNextLineEmptyAfterIndex,
343
+ hasNewline,
344
+ hasNewlineInRange,
345
+ addLeadingComment,
346
+ addDanglingComment,
347
+ addTrailingComment,
348
+ isNonEmptyArray,
349
+ };