prettier-plugin-multiline-arrays-2 1.0.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 (69) hide show
  1. package/LICENSE +3 -0
  2. package/LICENSE-CC0 +121 -0
  3. package/LICENSE-MIT +21 -0
  4. package/README.md +91 -0
  5. package/dist/augments/array.d.ts +3 -0
  6. package/dist/augments/array.js +21 -0
  7. package/dist/augments/array.test.d.ts +1 -0
  8. package/dist/augments/array.test.js +34 -0
  9. package/dist/augments/doc.d.ts +5 -0
  10. package/dist/augments/doc.js +30 -0
  11. package/dist/augments/string.d.ts +1 -0
  12. package/dist/augments/string.js +6 -0
  13. package/dist/index.d.ts +11 -0
  14. package/dist/index.js +46 -0
  15. package/dist/options.d.ts +32 -0
  16. package/dist/options.js +71 -0
  17. package/dist/options.test.d.ts +1 -0
  18. package/dist/options.test.js +48 -0
  19. package/dist/plugin-marker.d.ts +1 -0
  20. package/dist/plugin-marker.js +2 -0
  21. package/dist/preprocessing.d.ts +2 -0
  22. package/dist/preprocessing.js +94 -0
  23. package/dist/printer/child-docs.d.ts +18 -0
  24. package/dist/printer/child-docs.js +89 -0
  25. package/dist/printer/comment-triggers.d.ts +25 -0
  26. package/dist/printer/comment-triggers.js +327 -0
  27. package/dist/printer/comments.d.ts +2 -0
  28. package/dist/printer/comments.js +34 -0
  29. package/dist/printer/insert-new-lines.d.ts +15 -0
  30. package/dist/printer/insert-new-lines.js +580 -0
  31. package/dist/printer/insert-new-lines.test.d.ts +1 -0
  32. package/dist/printer/insert-new-lines.test.js +36 -0
  33. package/dist/printer/leading-new-line.d.ts +7 -0
  34. package/dist/printer/leading-new-line.js +31 -0
  35. package/dist/printer/multiline-array-printer.d.ts +4 -0
  36. package/dist/printer/multiline-array-printer.js +42 -0
  37. package/dist/printer/original-printer.d.ts +3 -0
  38. package/dist/printer/original-printer.js +10 -0
  39. package/dist/printer/supported-node-types.d.ts +9 -0
  40. package/dist/printer/supported-node-types.js +16 -0
  41. package/dist/printer/trailing-comma.d.ts +6 -0
  42. package/dist/printer/trailing-comma.js +28 -0
  43. package/dist/readme-examples/formatted-with-comments.example.d.ts +3 -0
  44. package/dist/readme-examples/formatted-with-comments.example.js +16 -0
  45. package/dist/readme-examples/formatted.example.d.ts +2 -0
  46. package/dist/readme-examples/formatted.example.js +12 -0
  47. package/dist/readme-examples/not-formatted.example.d.ts +2 -0
  48. package/dist/readme-examples/not-formatted.example.js +6 -0
  49. package/dist/readme-examples/prettier-options.example.d.ts +4 -0
  50. package/dist/readme-examples/prettier-options.example.js +5 -0
  51. package/dist/test/babel-ts.test.d.ts +1 -0
  52. package/dist/test/babel-ts.test.js +10 -0
  53. package/dist/test/javascript.test.d.ts +1 -0
  54. package/dist/test/javascript.test.js +702 -0
  55. package/dist/test/json.test.d.ts +1 -0
  56. package/dist/test/json.test.js +403 -0
  57. package/dist/test/json5.test.d.ts +1 -0
  58. package/dist/test/json5.test.js +210 -0
  59. package/dist/test/prettier-config.d.ts +2 -0
  60. package/dist/test/prettier-config.js +12 -0
  61. package/dist/test/prettier-versions.mock.script.d.ts +1 -0
  62. package/dist/test/prettier-versions.mock.script.js +123 -0
  63. package/dist/test/run-tests.mock.d.ts +17 -0
  64. package/dist/test/run-tests.mock.js +95 -0
  65. package/dist/test/typescript-tests.mock.d.ts +2 -0
  66. package/dist/test/typescript-tests.mock.js +1575 -0
  67. package/dist/test/typescript.test.d.ts +1 -0
  68. package/dist/test/typescript.test.js +10 -0
  69. package/package.json +117 -0
@@ -0,0 +1,580 @@
1
+ import { getObjectTypedKeys, stringify, } from "@augment-vir/common";
2
+ import { doc } from "prettier";
3
+ import { isDocCommand } from "../augments/doc.js";
4
+ import {} from "../options.js";
5
+ import { walkDoc } from "./child-docs.js";
6
+ import { getCommentTriggers, parseNextLineCounts, } from "./comment-triggers.js";
7
+ import { containsLeadingNewline } from "./leading-new-line.js";
8
+ import { getArrayLikeElements, isArrayLikeNode, } from "./supported-node-types.js";
9
+ import { containsTrailingComma } from "./trailing-comma.js";
10
+ const nestingSyntaxOpen = "[{(`";
11
+ const nestingSyntaxClose = "]})`";
12
+ const matchingNestingSyntaxClose = {
13
+ "[": "]",
14
+ "{": "}",
15
+ "(": ")",
16
+ "`": "`",
17
+ };
18
+ const found = 'Found "[" but:';
19
+ function isMatchingNestingSyntaxClose({ maybeClose, openingSyntax, }) {
20
+ const closingSyntax = matchingNestingSyntaxClose[openingSyntax];
21
+ const firstCharacter = maybeClose.trimStart()[0];
22
+ return !!firstCharacter && closingSyntax === firstCharacter;
23
+ }
24
+ function extractIndentDoc({ maybeIndentDoc, }) {
25
+ if (isDocCommand(maybeIndentDoc) && maybeIndentDoc.type === "indent") {
26
+ return maybeIndentDoc;
27
+ }
28
+ else if (Array.isArray(maybeIndentDoc)) {
29
+ const firstDoc = maybeIndentDoc[0];
30
+ if (isDocCommand(firstDoc) && firstDoc.type === "indent") {
31
+ return firstDoc;
32
+ }
33
+ }
34
+ return undefined;
35
+ }
36
+ export function insertLinesIntoArray({ inputDoc, manualWrap, lineCounts, wrapThreshold, debug, }) {
37
+ /**
38
+ * Each call to `insertLinesIntoArray` corresponds to a single array-like
39
+ * AST node, but its Doc can contain additional `[` characters that belong
40
+ * to sibling nodes (for example, the tuple type annotation on a
41
+ * destructuring pattern). Only the first `[` is our own array; skip the
42
+ * rest so we don't rewrite unrelated brackets.
43
+ */
44
+ let hasProcessedOwnArray = false;
45
+ walkDoc({
46
+ startDoc: inputDoc,
47
+ debug,
48
+ callback: (currentDoc, parentDocs, childIndex) => {
49
+ const currentParent = parentDocs[0];
50
+ const parentDoc = currentParent?.parent;
51
+ if (typeof currentDoc === "string" && currentDoc.trim() === "[") {
52
+ if (hasProcessedOwnArray) {
53
+ return true;
54
+ }
55
+ const undoMutations = [];
56
+ let finalLineBreakExists = false;
57
+ function undoAllMutations() {
58
+ undoMutations.toReversed().forEach((undoMutation) => {
59
+ undoMutation();
60
+ });
61
+ }
62
+ if (!Array.isArray(parentDoc)) {
63
+ if (debug) {
64
+ console.error({
65
+ brokenParent: parentDoc,
66
+ currentDoc,
67
+ });
68
+ }
69
+ throw new Error(`${found} parentDoc is not an array.`);
70
+ }
71
+ if (debug) {
72
+ console.info({
73
+ currentDoc,
74
+ parentDoc,
75
+ });
76
+ console.info(stringify(parentDoc));
77
+ }
78
+ if (childIndex !== 0) {
79
+ /**
80
+ * This happens in some situations which we don't want to
81
+ * format in this plugin, like in type accessors:
82
+ *
83
+ * ```typescript
84
+ * type mockType = exampleObject["property"];
85
+ * ```
86
+ */
87
+ return true;
88
+ }
89
+ const maybeBreak = parentDoc[childIndex + 2];
90
+ if (isDocCommand(maybeBreak) &&
91
+ maybeBreak.type === "if-break") {
92
+ undoMutations.push(() => {
93
+ parentDoc[childIndex + 2] = maybeBreak;
94
+ });
95
+ parentDoc[childIndex + 2] = maybeBreak.breakContents;
96
+ }
97
+ const indentIndex = childIndex + 1;
98
+ const maybeBracketSibling = parentDoc[indentIndex] === ""
99
+ ? parentDoc[indentIndex + 1]
100
+ : parentDoc[indentIndex];
101
+ const bracketSibling = extractIndentDoc({
102
+ maybeIndentDoc: maybeBracketSibling,
103
+ });
104
+ if (debug) {
105
+ console.info({
106
+ bracketSibling,
107
+ });
108
+ }
109
+ if (maybeBracketSibling === "]") {
110
+ return false;
111
+ }
112
+ else if (!bracketSibling) {
113
+ throw new Error(`${found} its sibling was not an indent Doc.: ${stringify(maybeBracketSibling)}`);
114
+ }
115
+ const indentContents = bracketSibling.contents;
116
+ if (debug) {
117
+ console.info({
118
+ indentContents,
119
+ });
120
+ }
121
+ if (!Array.isArray(indentContents)) {
122
+ throw new TypeError(`${found} indent didn't have array contents.`);
123
+ }
124
+ else if (indentContents.length < 2) {
125
+ if (debug) {
126
+ console.error(stringify(indentContents));
127
+ }
128
+ throw new Error(`${found} indent contents did not have at least 2 children`);
129
+ }
130
+ const startingLine = indentContents[0];
131
+ if (debug) {
132
+ console.info({
133
+ firstIndentContentsChild: startingLine,
134
+ });
135
+ }
136
+ if (!isDocCommand(startingLine) ||
137
+ startingLine.type !== "line") {
138
+ if (Array.isArray(startingLine)) {
139
+ undoAllMutations();
140
+ return false;
141
+ }
142
+ else {
143
+ throw new TypeError(`${found} first indent child was not a line.`);
144
+ }
145
+ }
146
+ indentContents[0] = "";
147
+ undoMutations.push(() => {
148
+ indentContents[0] = startingLine;
149
+ });
150
+ const indentedContent = indentContents[1];
151
+ if (debug) {
152
+ console.info({
153
+ secondIndentContentsChild: indentedContent,
154
+ itsFirstChild: indentedContent[0],
155
+ });
156
+ }
157
+ if (!indentedContent) {
158
+ console.error("second indent child (indentedContent) is not defined:", {
159
+ indentContents,
160
+ indentedContent,
161
+ });
162
+ throw new Error(`${found} second indent child is not a fill.`);
163
+ }
164
+ else if (!Array.isArray(indentedContent) &&
165
+ !(isDocCommand(indentedContent) &&
166
+ indentedContent.type === "fill")) {
167
+ console.error("second indent child (indentCode) is not a fill doc or an array:", {
168
+ indentContents,
169
+ indentCode: indentedContent,
170
+ });
171
+ throw new Error(`${found} second indent child is not a fill doc or an array.`);
172
+ }
173
+ else if (Array.isArray(indentedContent)
174
+ ? indentedContent.length === 0
175
+ : indentedContent.parts.length === 0) {
176
+ throw new Error(`${found} indentedContent has no length.`);
177
+ }
178
+ // lineIndex is 0 indexed
179
+ let lineIndex = 0;
180
+ // columnCount is 1 indexed
181
+ let columnCount = 1;
182
+ if (debug) {
183
+ console.info(">>>>>>>>>>>>>> Walking children for commas");
184
+ }
185
+ let arrayChildCount = 0;
186
+ let forceFinalLineBreakExists = false;
187
+ if (!finalLineBreakExists) {
188
+ walkDoc({
189
+ startDoc: indentedContent,
190
+ debug,
191
+ callback: (currentDoc, commaParents, commaChildIndex) => {
192
+ finalLineBreakExists = false;
193
+ const innerCurrentParent = commaParents[0];
194
+ const innerCurrentParentDoc = innerCurrentParent?.parent;
195
+ if (isDocCommand(currentDoc) &&
196
+ currentDoc.type === "if-break" &&
197
+ currentDoc.breakContents === ",") {
198
+ /**
199
+ * Only treat a trailing-comma if-break (whose
200
+ * `breakContents` is `,`) as the array's final
201
+ * line-break marker. Other if-break commands —
202
+ * like the leading `| ` Prettier emits when a
203
+ * union type wraps — appear inside element docs
204
+ * (e.g. `[A | B | C]`) and must not be forced
205
+ * open, otherwise the inner union breaks
206
+ * unnecessarily.
207
+ */
208
+ if (debug) {
209
+ console.info("found final line break inside of if-break");
210
+ }
211
+ finalLineBreakExists = true;
212
+ if (!innerCurrentParentDoc) {
213
+ throw new Error("Found if-break without a parent");
214
+ }
215
+ else if (!Array.isArray(innerCurrentParentDoc)) {
216
+ throw new TypeError("if-break parent is not an array");
217
+ }
218
+ else if (commaChildIndex == undefined) {
219
+ throw new Error("if-break child index is undefined");
220
+ }
221
+ innerCurrentParentDoc[commaChildIndex] =
222
+ currentDoc.breakContents;
223
+ innerCurrentParentDoc.splice(commaChildIndex + 1, 0, doc.builders.breakParent);
224
+ undoMutations.push(() => {
225
+ innerCurrentParentDoc.splice(commaChildIndex + 1, 1);
226
+ innerCurrentParentDoc[commaChildIndex] =
227
+ currentDoc;
228
+ });
229
+ }
230
+ else if (typeof currentDoc === "string") {
231
+ if (!innerCurrentParentDoc) {
232
+ console.error({
233
+ innerParentDoc: innerCurrentParentDoc,
234
+ });
235
+ throw new Error("Found string but innerParentDoc is not defined.");
236
+ }
237
+ else if (currentDoc === "<" &&
238
+ Array.isArray(innerCurrentParentDoc) &&
239
+ commaChildIndex != undefined &&
240
+ innerCurrentParentDoc
241
+ .slice(commaChildIndex + 1)
242
+ .includes(">")) {
243
+ /**
244
+ * A paired `<...>` in the same Doc array is
245
+ * a generic type-argument group (e.g.
246
+ * `Omit<MyType, 'field'>`). Skip walking
247
+ * its siblings so commas inside the generic
248
+ * aren't mistaken for array-element
249
+ * separators. A lone `<` or `>` without a
250
+ * match in the same array is a comparison
251
+ * operator and handled by the default
252
+ * walk.
253
+ */
254
+ return false;
255
+ }
256
+ else if (currentDoc &&
257
+ nestingSyntaxOpen.includes(currentDoc)) {
258
+ if (!Array.isArray(innerCurrentParentDoc)) {
259
+ throw new TypeError("Found opening syntax but parent is not an array.");
260
+ }
261
+ const closingIndex = innerCurrentParentDoc.findIndex((sibling) => typeof sibling === "string" &&
262
+ sibling &&
263
+ isMatchingNestingSyntaxClose({
264
+ maybeClose: sibling,
265
+ openingSyntax: currentDoc,
266
+ }));
267
+ if (closingIndex < 0) {
268
+ throw new Error(`Could not find closing match for ${currentDoc}`);
269
+ }
270
+ return false;
271
+ }
272
+ else if (currentDoc &&
273
+ nestingSyntaxClose.includes(currentDoc)) {
274
+ throw new Error("Found closing syntax which shouldn't be walked");
275
+ }
276
+ else if (currentDoc === ",") {
277
+ if (debug) {
278
+ console.info({
279
+ foundCommaIn: innerCurrentParentDoc,
280
+ });
281
+ }
282
+ if (!Array.isArray(innerCurrentParentDoc)) {
283
+ console.error({
284
+ innerParentDoc: innerCurrentParentDoc,
285
+ });
286
+ throw new Error("Found comma but innerParentDoc is not an array.");
287
+ }
288
+ else if (commaChildIndex == undefined) {
289
+ throw new Error("Found comma but childIndex is undefined.");
290
+ }
291
+ let siblingIndex = commaChildIndex + 1;
292
+ let parentToMutate = innerCurrentParentDoc;
293
+ if (commaChildIndex ===
294
+ innerCurrentParentDoc.length - 1) {
295
+ const commaGrandParent = commaParents[1];
296
+ if (commaGrandParent == undefined) {
297
+ throw new Error("Could not find grandparent of comma group.");
298
+ }
299
+ else if (commaGrandParent.childIndexInThisParent ==
300
+ undefined) {
301
+ throw new Error("Could not find index of comma group parent");
302
+ }
303
+ else if (!Array.isArray(commaGrandParent.parent)) {
304
+ throw new TypeError("Comma group grandparent is not an array.");
305
+ }
306
+ siblingIndex =
307
+ commaGrandParent.childIndexInThisParent +
308
+ 1;
309
+ parentToMutate =
310
+ commaGrandParent.parent;
311
+ }
312
+ if (debug) {
313
+ console.info({
314
+ commaParentDoc: innerCurrentParentDoc,
315
+ parentToMutate,
316
+ siblingIndex,
317
+ });
318
+ }
319
+ let maybeCommaSibling = parentToMutate[siblingIndex];
320
+ if (debug) {
321
+ console.info(`Trying to find comma sibling at index ${siblingIndex}`, stringify({
322
+ parentToMutate,
323
+ maybeCommaSibling,
324
+ }));
325
+ }
326
+ function isCommaSibling(maybe) {
327
+ return ((isDocCommand(maybe) &&
328
+ maybe.type === "line") ||
329
+ (Array.isArray(maybe) &&
330
+ isDocCommand(maybe[0]) &&
331
+ maybe[0].type === "line"));
332
+ }
333
+ while (!isCommaSibling(maybeCommaSibling) &&
334
+ siblingIndex < parentToMutate.length) {
335
+ siblingIndex++;
336
+ maybeCommaSibling =
337
+ parentToMutate[siblingIndex];
338
+ if (debug) {
339
+ console.info(`Trying to find comma sibling at index ${siblingIndex}`, parentToMutate, maybeCommaSibling);
340
+ }
341
+ }
342
+ if (debug) {
343
+ console.info(`Found comma sibling at index ${siblingIndex}`, parentToMutate, maybeCommaSibling);
344
+ }
345
+ if (!isCommaSibling(maybeCommaSibling)) {
346
+ throw new Error(`Found comma but its following sibling is not a line: ${stringify(maybeCommaSibling)}`);
347
+ }
348
+ const commaSibling = maybeCommaSibling;
349
+ const currentLineCountIndex = lineIndex % lineCounts.length;
350
+ const currentLineCount = lineCounts.length
351
+ ? lineCounts[currentLineCountIndex]
352
+ : undefined;
353
+ arrayChildCount++;
354
+ if ((currentLineCount &&
355
+ columnCount === currentLineCount) ||
356
+ !currentLineCount) {
357
+ // if we're on the last element of the line then increment to the next line
358
+ lineIndex++;
359
+ columnCount = 1;
360
+ /**
361
+ * Don't use doc.builders.hardline here.
362
+ * It causes "invalid size error" which
363
+ * I don't understand and which has no
364
+ * other useful information or stack
365
+ * trace.
366
+ */
367
+ if (debug) {
368
+ console.info({
369
+ breakingAfter: parentToMutate[siblingIndex - 1],
370
+ });
371
+ }
372
+ parentToMutate[siblingIndex] =
373
+ doc.builders.hardlineWithoutBreakParent;
374
+ }
375
+ else {
376
+ parentToMutate[siblingIndex] = " ";
377
+ columnCount++;
378
+ }
379
+ undoMutations.push(() => {
380
+ parentToMutate[siblingIndex] =
381
+ commaSibling;
382
+ });
383
+ }
384
+ }
385
+ else if (Array.isArray(currentDoc)) {
386
+ const firstPart = currentDoc[0];
387
+ const secondPart = currentDoc[1];
388
+ if (debug) {
389
+ console.info("got concat child doc");
390
+ console.info(currentDoc, {
391
+ firstPart,
392
+ secondPart,
393
+ });
394
+ console.info(isDocCommand(firstPart), isDocCommand(secondPart), firstPart?.type === "line", firstPart?.hard, secondPart?.type ===
395
+ "break-parent");
396
+ }
397
+ if (isDocCommand(firstPart) &&
398
+ isDocCommand(secondPart) &&
399
+ firstPart.type === "line" &&
400
+ firstPart.hard &&
401
+ secondPart.type === "break-parent") {
402
+ if (debug) {
403
+ console.info("concat child was indeed a line break");
404
+ }
405
+ forceFinalLineBreakExists = true;
406
+ return false;
407
+ }
408
+ else if (debug) {
409
+ console.info("concat child doc was not a line break");
410
+ }
411
+ }
412
+ return true;
413
+ },
414
+ });
415
+ }
416
+ if (forceFinalLineBreakExists) {
417
+ finalLineBreakExists = true;
418
+ }
419
+ if (!finalLineBreakExists) {
420
+ if (debug) {
421
+ console.info(`Parsed all array children but finalBreakHappened = ${finalLineBreakExists}`);
422
+ }
423
+ const closingBracketIndex = parentDoc.indexOf("]");
424
+ const preBracketChild = parentDoc[closingBracketIndex - 1];
425
+ if (isDocCommand(preBracketChild) &&
426
+ preBracketChild.type === "line") {
427
+ parentDoc.splice(closingBracketIndex - 1, 1);
428
+ undoMutations.push(() => {
429
+ parentDoc.splice(closingBracketIndex - 1, 0, preBracketChild);
430
+ });
431
+ }
432
+ parentDoc.splice(closingBracketIndex - 1, 0, doc.builders.hardlineWithoutBreakParent);
433
+ undoMutations.push(() => {
434
+ parentDoc.splice(closingBracketIndex - 1, 1);
435
+ });
436
+ }
437
+ if (Array.isArray(indentedContent)) {
438
+ const oldIndentContentChild = indentContents[1];
439
+ indentContents.splice(1, 1, doc.builders.group([
440
+ doc.builders.hardlineWithoutBreakParent,
441
+ ...indentedContent,
442
+ ]));
443
+ undoMutations.push(() => {
444
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
445
+ indentContents[1] = oldIndentContentChild;
446
+ });
447
+ }
448
+ else {
449
+ const oldParts = indentedContent.parts;
450
+ indentedContent.parts = [
451
+ doc.builders.group([
452
+ doc.builders.hardlineWithoutBreakParent,
453
+ ...indentedContent.parts,
454
+ ]),
455
+ ];
456
+ undoMutations.push(() => {
457
+ indentedContent.parts = oldParts;
458
+ });
459
+ }
460
+ if (arrayChildCount < wrapThreshold &&
461
+ !lineCounts.length &&
462
+ !manualWrap) {
463
+ undoAllMutations();
464
+ }
465
+ hasProcessedOwnArray = true;
466
+ // don't walk any deeper
467
+ return false;
468
+ }
469
+ else if (debug) {
470
+ console.info({
471
+ ignoring: currentDoc,
472
+ });
473
+ }
474
+ return true;
475
+ },
476
+ });
477
+ if (debug) {
478
+ console.info("final doc:", stringify(inputDoc));
479
+ }
480
+ // return what is input because we perform mutations on it
481
+ return inputDoc;
482
+ }
483
+ function getLatestSetValue(currentLine, triggers) {
484
+ const relevantSetLineCountsKey = getObjectTypedKeys(triggers)
485
+ .sort()
486
+ .reduce((closestKey, currentKey) => {
487
+ if (Number(currentKey) < currentLine) {
488
+ const currentData = triggers[currentKey];
489
+ if (currentData && currentData.lineEnd > currentLine) {
490
+ return currentKey;
491
+ }
492
+ }
493
+ return closestKey;
494
+ }, "");
495
+ const relevantSetLineCount = triggers[relevantSetLineCountsKey]?.data;
496
+ return relevantSetLineCount;
497
+ }
498
+ export function printWithMultilineArrays({ originalFormattedOutput, path, inputOptions, debug, }) {
499
+ const rootNode = path.stack[0];
500
+ if (!rootNode) {
501
+ throw new Error(`Could not find valid root node in ${path.stack.map((entry) => entry.type).join(",")}`);
502
+ }
503
+ const node = path.getNode();
504
+ if (debug) {
505
+ console.info("[multiline-arrays] printWithMultilineArrays node type:", node?.type);
506
+ }
507
+ if (node && isArrayLikeNode(node)) {
508
+ if (!node.loc) {
509
+ throw new Error(`Could not find location of node ${node.type}`);
510
+ }
511
+ const currentLineNumber = node.loc.start.line;
512
+ const commentTriggers = getCommentTriggers(rootNode, debug);
513
+ const originalText = inputOptions.originalText;
514
+ const splitOriginalText = originalText.split("\n");
515
+ /**
516
+ * ArrayPattern nodes in Babel-TS include their `typeAnnotation` in the
517
+ * node's `loc`, so the node's end location can be well past the array's
518
+ * `]`. Use the typeAnnotation's start (when present) as the effective
519
+ * end so trailing-comma / leading-newline detection only inspects text
520
+ * inside the actual array brackets.
521
+ */
522
+ const typeAnnotationStart = node.typeAnnotation?.loc?.start;
523
+ const arrayLoc = typeAnnotationStart
524
+ ? {
525
+ start: node.loc.start,
526
+ end: typeAnnotationStart,
527
+ }
528
+ : node.loc;
529
+ const elements = getArrayLikeElements(node);
530
+ const includesLeadingNewline = containsLeadingNewline({
531
+ nodeLocation: arrayLoc,
532
+ children: elements,
533
+ originalLines: splitOriginalText,
534
+ debug,
535
+ });
536
+ const includesTrailingComma = containsTrailingComma({
537
+ nodeLocation: arrayLoc,
538
+ children: elements,
539
+ originalLines: splitOriginalText,
540
+ });
541
+ const relevantSetLineCount = getLatestSetValue(currentLineNumber, commentTriggers.setLineCounts);
542
+ const lineCounts = commentTriggers.nextLineCounts[currentLineNumber] ??
543
+ relevantSetLineCount ??
544
+ parseNextLineCounts({
545
+ input: inputOptions.multilineArraysLinePattern,
546
+ nextOnly: false,
547
+ debug,
548
+ });
549
+ const relevantSetWrapCommentThreshold = getLatestSetValue(currentLineNumber, commentTriggers.setWrapThresholds);
550
+ const wrapThreshold = commentTriggers.nextWrapThresholds[currentLineNumber] ??
551
+ relevantSetWrapCommentThreshold ??
552
+ (inputOptions.multilineArraysWrapThreshold < 0
553
+ ? Infinity
554
+ : inputOptions.multilineArraysWrapThreshold);
555
+ const includesCommentTrigger = (commentTriggers.nextWrapThresholds[currentLineNumber] ??
556
+ relevantSetWrapCommentThreshold) != undefined ||
557
+ !!lineCounts.length;
558
+ if (debug) {
559
+ console.info(`======= Starting call to ${insertLinesIntoArray.name}: =======`);
560
+ console.info({
561
+ options: {
562
+ lineCounts,
563
+ wrapThreshold,
564
+ },
565
+ });
566
+ }
567
+ const manualWrap = includesCommentTrigger
568
+ ? false
569
+ : includesTrailingComma || includesLeadingNewline;
570
+ const newDoc = insertLinesIntoArray({
571
+ inputDoc: originalFormattedOutput,
572
+ manualWrap,
573
+ lineCounts,
574
+ wrapThreshold,
575
+ debug,
576
+ });
577
+ return newDoc;
578
+ }
579
+ return originalFormattedOutput;
580
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,36 @@
1
+ import { assert } from '@augment-vir/assert';
2
+ import { describe, it } from '@augment-vir/test';
3
+ import { doc } from 'prettier';
4
+ import { insertLinesIntoArray } from './insert-new-lines.js';
5
+ describe(insertLinesIntoArray.name, () => {
6
+ it('handles comment-only array doc emitted by Prettier GitHub Issue #75', () => {
7
+ const commentOnlyArrayDoc = [
8
+ '[',
9
+ [
10
+ doc.builders.indent([
11
+ doc.builders.softline,
12
+ [
13
+ '// "source.fixAll.eslint",',
14
+ [
15
+ doc.builders.hardline,
16
+ doc.builders.breakParent,
17
+ ],
18
+ '// "source.fixAll.prettier",',
19
+ ],
20
+ ]),
21
+ [
22
+ doc.builders.hardline,
23
+ doc.builders.breakParent,
24
+ ],
25
+ ],
26
+ ']',
27
+ ];
28
+ assert.strictEquals(insertLinesIntoArray({
29
+ inputDoc: commentOnlyArrayDoc,
30
+ manualWrap: false,
31
+ lineCounts: [],
32
+ wrapThreshold: Infinity,
33
+ debug: false,
34
+ }), commentOnlyArrayDoc);
35
+ });
36
+ });
@@ -0,0 +1,7 @@
1
+ import type { BaseNode } from "estree";
2
+ export declare function containsLeadingNewline({ nodeLocation, children, originalLines, debug, }: Readonly<{
3
+ nodeLocation: BaseNode["loc"];
4
+ children: (BaseNode | null)[];
5
+ originalLines: string[];
6
+ debug: boolean;
7
+ }>): boolean;
@@ -0,0 +1,31 @@
1
+ import { extractTextBetweenRanges } from "../augments/array.js";
2
+ export function containsLeadingNewline({ nodeLocation, children, originalLines, debug, }) {
3
+ const firstElement = children[0];
4
+ if (firstElement) {
5
+ const startLocation = nodeLocation?.start;
6
+ if (!startLocation) {
7
+ return false;
8
+ }
9
+ const endLocation = firstElement.loc?.start;
10
+ if (!endLocation) {
11
+ return false;
12
+ }
13
+ const textBeforeFirstElement = extractTextBetweenRanges(originalLines, {
14
+ start: {
15
+ column: startLocation.column - 1,
16
+ line: startLocation.line - 1,
17
+ },
18
+ end: {
19
+ column: endLocation.column - 1,
20
+ line: endLocation.line - 1,
21
+ },
22
+ });
23
+ if (debug) {
24
+ console.info(`containsLeadingNewline textBeforeFirstElement: ${textBeforeFirstElement}`);
25
+ }
26
+ if (textBeforeFirstElement.includes("\n")) {
27
+ return true;
28
+ }
29
+ }
30
+ return false;
31
+ }
@@ -0,0 +1,4 @@
1
+ import type { Node } from "estree";
2
+ import type { Printer } from "prettier";
3
+ export declare function createMultilineArrayPrinter(basePrinter: Printer<Node>): Printer<Node>;
4
+ export declare const multilineArrayPrinter: Printer<Node>;