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.
- package/LICENSE +21 -0
- package/README.md +8 -0
- package/dist/detachedNode.js +128 -0
- package/dist/detachedNode.js.flow +113 -0
- package/dist/generated/TransformCloneSignatures.js.flow +19 -0
- package/dist/generated/TransformReplaceSignatures.js.flow +943 -0
- package/dist/generated/node-types.js +2071 -0
- package/dist/generated/node-types.js.flow +3149 -0
- package/dist/generated/special-case-node-types.js +178 -0
- package/dist/generated/special-case-node-types.js.flow +248 -0
- package/dist/getVisitorKeys.js +35 -0
- package/dist/getVisitorKeys.js.flow +31 -0
- package/dist/index.js +41 -0
- package/dist/index.js.flow +15 -0
- package/dist/transform/Errors.js +151 -0
- package/dist/transform/Errors.js.flow +17 -0
- package/dist/transform/MutationContext.js +94 -0
- package/dist/transform/MutationContext.js.flow +80 -0
- package/dist/transform/TransformContext.js +136 -0
- package/dist/transform/TransformContext.js.flow +378 -0
- package/dist/transform/comments/comments.js +140 -0
- package/dist/transform/comments/comments.js.flow +145 -0
- package/dist/transform/comments/prettier/README.md +6 -0
- package/dist/transform/comments/prettier/common/util.js +365 -0
- package/dist/transform/comments/prettier/common/util.js.flow +349 -0
- package/dist/transform/comments/prettier/language-js/comments.js +777 -0
- package/dist/transform/comments/prettier/language-js/comments.js.flow +950 -0
- package/dist/transform/comments/prettier/language-js/loc.js +41 -0
- package/dist/transform/comments/prettier/language-js/loc.js.flow +41 -0
- package/dist/transform/comments/prettier/language-js/printer-estree.js +31 -0
- package/dist/transform/comments/prettier/language-js/printer-estree.js.flow +37 -0
- package/dist/transform/comments/prettier/language-js/utils.js +131 -0
- package/dist/transform/comments/prettier/language-js/utils.js.flow +135 -0
- package/dist/transform/comments/prettier/main/comments.js +513 -0
- package/dist/transform/comments/prettier/main/comments.js.flow +436 -0
- package/dist/transform/comments/prettier/utils/get-last.js +15 -0
- package/dist/transform/comments/prettier/utils/get-last.js.flow +14 -0
- package/dist/transform/getTransformedAST.js +159 -0
- package/dist/transform/getTransformedAST.js.flow +128 -0
- package/dist/transform/mutations/AddLeadingComments.js +47 -0
- package/dist/transform/mutations/AddLeadingComments.js.flow +49 -0
- package/dist/transform/mutations/AddTrailingComments.js +47 -0
- package/dist/transform/mutations/AddTrailingComments.js.flow +49 -0
- package/dist/transform/mutations/CloneCommentsTo.js +46 -0
- package/dist/transform/mutations/CloneCommentsTo.js.flow +51 -0
- package/dist/transform/mutations/InsertStatement.js +92 -0
- package/dist/transform/mutations/InsertStatement.js.flow +113 -0
- package/dist/transform/mutations/RemoveComment.js +96 -0
- package/dist/transform/mutations/RemoveComment.js.flow +80 -0
- package/dist/transform/mutations/RemoveStatement.js +61 -0
- package/dist/transform/mutations/RemoveStatement.js.flow +68 -0
- package/dist/transform/mutations/ReplaceNode.js +96 -0
- package/dist/transform/mutations/ReplaceNode.js.flow +113 -0
- package/dist/transform/mutations/ReplaceStatementWithMany.js +81 -0
- package/dist/transform/mutations/ReplaceStatementWithMany.js.flow +102 -0
- package/dist/transform/mutations/utils/arrayUtils.js +41 -0
- package/dist/transform/mutations/utils/arrayUtils.js.flow +35 -0
- package/dist/transform/mutations/utils/getStatementParent.js +147 -0
- package/dist/transform/mutations/utils/getStatementParent.js.flow +143 -0
- package/dist/transform/mutations/utils/isValidModuleDeclarationParent.js +53 -0
- package/dist/transform/mutations/utils/isValidModuleDeclarationParent.js.flow +50 -0
- package/dist/transform/transform.js +69 -0
- package/dist/transform/transform.js.flow +60 -0
- package/dist/traverse/NodeEventGenerator.js +427 -0
- package/dist/traverse/NodeEventGenerator.js.flow +406 -0
- package/dist/traverse/SafeEmitter.js +70 -0
- package/dist/traverse/SafeEmitter.js.flow +46 -0
- package/dist/traverse/SimpleTraverser.js +149 -0
- package/dist/traverse/SimpleTraverser.js.flow +109 -0
- package/dist/traverse/esquery.js +37 -0
- package/dist/traverse/esquery.js.flow +173 -0
- package/dist/traverse/traverse.js +139 -0
- package/dist/traverse/traverse.js.flow +149 -0
- 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
|
+
};
|