@aforemendude/prettier-plugin-wrap-comments 1.0.4 → 1.0.6

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/README.md CHANGED
@@ -67,6 +67,11 @@ Non-JSDoc `/* ... */` comments are also normalized as Markdown. A block comment
67
67
  comment fits within `printWidth`; otherwise, only standalone block comments are expanded into star-prefixed blocks. Long
68
68
  inline block comments are left unchanged when they cannot fit on one line.
69
69
 
70
+ Multiline block comments are normalized as conventional block-comment text before Markdown parsing: leading indentation
71
+ is removed, and a `*` that is the first non-whitespace character on a body line is treated as comment formatting, not
72
+ Markdown content. This also applies to unstarred `/* ... */` blocks, so use line comments when Markdown-significant
73
+ indentation or leading `*` characters must be preserved exactly.
74
+
70
75
  ```ts
71
76
  if (ready) {
72
77
  /*
@@ -78,9 +83,10 @@ if (ready) {
78
83
  ```
79
84
 
80
85
  JSX and TSX expression comments use the expression contents, not the outer React expression braces, to decide whether a
81
- block comment is standalone, trailing, or inline. A comment-only expression like `{/* ... */}` can wrap as a standalone
82
- JSX comment. A trailing expression comment like `{label /* ... */}` can move before `label` and wrap. A true inline
83
- expression comment like `{"abc" + /* ... */ "123"}` is left unchanged when it cannot fit on one line.
86
+ block comment is standalone, leading, trailing, or inline. A comment-only expression like `{/* ... */}` can wrap as a
87
+ standalone JSX comment. A leading expression comment like `{/* ... */ label}` can move above `label` and wrap. A
88
+ trailing expression comment like `{label /* ... */}` can move before `label` and wrap. A true inline expression comment
89
+ like `{"abc" + /* ... */ "123"}` is left unchanged when it cannot fit on one line.
84
90
 
85
91
  <!-- prettier-ignore-start -->
86
92
  ```tsx
@@ -91,6 +97,13 @@ expression comment like `{"abc" + /* ... */ "123"}` is left unchanged when it ca
91
97
  * make it inline.
92
98
  */
93
99
  }
100
+ {
101
+ /*
102
+ * This expression comment moved above the expression value because it was
103
+ * leading.
104
+ */
105
+ label
106
+ }
94
107
  {
95
108
  /*
96
109
  * This expression comment moved above the expression value because it was
@@ -109,11 +122,16 @@ the block comment is one the plugin would otherwise wrap, the following code sti
109
122
  comment is already skipped by the plugin, such as a JSDoc or directive block, Prettier keeps its normal ignore behavior
110
123
  for the following code.
111
124
 
112
- For trailing line comments, a `// prettier-ignore` line can apply to the code line and its inline comment. The plugin
113
- walks past adjacent standalone comments that it normally leaves alone, such as an `eslint-disable-next-line` directive,
114
- so an ignored code line's trailing comment remains inline and unchanged. A directive comment by itself does not ignore
115
- the following code line; without `// prettier-ignore`, an overlong trailing comment below a directive is still moved
116
- above the statement and wrapped.
125
+ An exact `// prettier-ignore` marker can also apply to the following adjacent standalone `//` comment group. The plugin
126
+ leaves that group unchanged and neutralizes the marker for Prettier, so code after the ignored comment group still
127
+ formats normally.
128
+
129
+ For trailing line comments, a standalone exact-body `prettier-ignore` marker, written as `// prettier-ignore` or
130
+ `/* prettier-ignore */`, can apply to the code line and its inline comment. The plugin walks past adjacent standalone
131
+ comments that it normally leaves alone, such as an `eslint-disable-next-line` directive, so an ignored code line's
132
+ trailing comment remains inline and unchanged. A directive comment by itself does not ignore the following code line;
133
+ without `prettier-ignore`, an overlong trailing comment below a directive is still moved above the statement and
134
+ wrapped.
117
135
 
118
136
  The plugin leaves these comments unchanged:
119
137
 
@@ -1,8 +1,13 @@
1
1
  import type { CommentRange, Replacement, WrapOptions } from '../shared/types.js';
2
2
  export type BlockCommentLayout = {
3
3
  contentColumn?: number;
4
+ leadingMove?: {
5
+ removeEnd: number;
6
+ removeStart: number;
7
+ };
4
8
  multilineIndent?: string;
5
9
  placement: 'inline' | 'standalone' | 'trailing';
10
+ singleLineSuffixWidth?: number;
6
11
  trailingMove?: {
7
12
  insertAt: number;
8
13
  removeEnd: number;
@@ -36,7 +36,8 @@ function buildBlockReplacement(text, comment, formattedLines, options, layout) {
36
36
  const markerColumn = getColumnAt(text, comment.start, tabWidth);
37
37
  const singleLine = `/* ${formattedLines.join(' ')} */`;
38
38
  const singleLineWidth = getColumns(singleLine, tabWidth);
39
- if (formattedLines.length === 1 && markerColumn + singleLineWidth <= getPrintWidth(options)) {
39
+ const singleLineSuffixWidth = layout.singleLineSuffixWidth ?? 0;
40
+ if (formattedLines.length === 1 && markerColumn + singleLineWidth + singleLineSuffixWidth <= getPrintWidth(options)) {
40
41
  return singleLine;
41
42
  }
42
43
  if (layout.placement === 'inline') {
@@ -59,6 +60,20 @@ function buildBlockReplacement(text, comment, formattedLines, options, layout) {
59
60
  },
60
61
  ];
61
62
  }
63
+ if (layout.leadingMove !== undefined) {
64
+ return [
65
+ {
66
+ end: comment.end,
67
+ start: comment.start,
68
+ text: `${replacementText}${newline}`,
69
+ },
70
+ {
71
+ end: layout.leadingMove.removeEnd,
72
+ start: layout.leadingMove.removeStart,
73
+ text: '',
74
+ },
75
+ ];
76
+ }
62
77
  return replacementText;
63
78
  }
64
79
  function buildMultilineBlockReplacement(formattedLines, newline, indent) {
@@ -22,14 +22,6 @@ export function toCommentRange(comment, text) {
22
22
  if (rawStart.startsWith('/*')) {
23
23
  return { end, kind: 'block', start };
24
24
  }
25
- if (typeof comment.type === 'string') {
26
- if (comment.type.includes('Line')) {
27
- return { end, kind: 'line', start };
28
- }
29
- if (comment.type.includes('Block')) {
30
- return { end, kind: 'block', start };
31
- }
32
- }
33
25
  return undefined;
34
26
  }
35
27
  export function normalizeLineCommentBody(rawBody) {
@@ -1,3 +1,3 @@
1
1
  import type { WrapOptions } from '../shared/types.js';
2
2
  export declare function wrapComments<T>(text: string, ast: T, options: WrapOptions): Promise<string>;
3
- export declare function neutralizePrettierIgnoreForIgnoredBlockComments<T>(text: string, ast: T): T;
3
+ export declare function neutralizePrettierIgnoreForIgnoredComments<T>(text: string, ast: T): T;
@@ -53,6 +53,10 @@ export async function wrapComments(text, ast, options) {
53
53
  if (shouldSkipLineComment(text, comment)) {
54
54
  continue;
55
55
  }
56
+ if (isPrettierIgnoredStandaloneLineComment(text, commentEntries, index)) {
57
+ index = getStandaloneLineCommentGroupEndIndex(text, comments, index, tabWidth);
58
+ continue;
59
+ }
56
60
  if (!isStandaloneLineComment(text, comment)) {
57
61
  if (isPrettierIgnoredTrailingLineComment(text, commentEntries, index)) {
58
62
  continue;
@@ -88,15 +92,16 @@ export async function wrapComments(text, ast, options) {
88
92
  }
89
93
  return applyReplacements(text, replacements);
90
94
  }
91
- export function neutralizePrettierIgnoreForIgnoredBlockComments(text, ast) {
95
+ export function neutralizePrettierIgnoreForIgnoredComments(text, ast) {
92
96
  const comments = collectSortedCommentEntries(ast, text);
93
97
  for (let index = 0; index < comments.length; index += 1) {
94
98
  const entry = comments[index];
95
99
  const previousEntry = comments[index - 1];
96
- if (entry !== undefined &&
100
+ const shouldNeutralize = entry !== undefined &&
97
101
  previousEntry !== undefined &&
98
- isPrettierIgnoredBlockComment(text, comments, index) &&
99
- !isBlockCommentNormallyIgnored(text, entry.range)) {
102
+ ((isPrettierIgnoredBlockComment(text, comments, index) && !isBlockCommentNormallyIgnored(text, entry.range)) ||
103
+ (isPrettierIgnoredStandaloneLineComment(text, comments, index) && !shouldSkipLineComment(text, entry.range)));
104
+ if (shouldNeutralize) {
100
105
  previousEntry.raw.value = NEUTRALIZED_PRETTIER_IGNORE_COMMENT;
101
106
  }
102
107
  }
@@ -114,8 +119,7 @@ function collectPrettierIgnoredLineRanges(text, ast, comments) {
114
119
  for (let index = 0; index < comments.length; index += 1) {
115
120
  const comment = comments[index]?.range;
116
121
  if (comment === undefined ||
117
- comment.kind !== 'line' ||
118
- !isStandaloneLineComment(text, comment) ||
122
+ !isStandaloneComment(text, comment) ||
119
123
  !isPrettierIgnoreComment(getCommentBody(text, comment))) {
120
124
  continue;
121
125
  }
@@ -251,7 +255,12 @@ function getJsxExpressionBlockCommentLayout(text, comment, jsxExpressionContaine
251
255
  const expressionTextAfterComment = text.slice(comment.end, container.end - 1).trim();
252
256
  const containerOutputColumn = getJsxExpressionContainerOutputColumn(text, container, tabWidth);
253
257
  if (expressionTextBeforeComment === '' && expressionTextAfterComment === '') {
254
- return { contentColumn: containerOutputColumn + tabWidth + 3, multilineIndent: '', placement: 'standalone' };
258
+ return {
259
+ contentColumn: containerOutputColumn + tabWidth + 3,
260
+ multilineIndent: '',
261
+ placement: 'standalone',
262
+ singleLineSuffixWidth: 1,
263
+ };
255
264
  }
256
265
  if (expressionTextBeforeComment !== '' && expressionTextAfterComment === '') {
257
266
  const expressionStart = skipWhitespace(text, container.start + 1);
@@ -261,6 +270,7 @@ function getJsxExpressionBlockCommentLayout(text, comment, jsxExpressionContaine
261
270
  contentColumn: containerOutputColumn + tabWidth + 3,
262
271
  multilineIndent: '',
263
272
  placement: 'trailing',
273
+ singleLineSuffixWidth: 1,
264
274
  trailingMove: {
265
275
  insertAt: expressionStart,
266
276
  removeEnd: removalEnd,
@@ -268,6 +278,22 @@ function getJsxExpressionBlockCommentLayout(text, comment, jsxExpressionContaine
268
278
  },
269
279
  };
270
280
  }
281
+ if (expressionTextBeforeComment === '') {
282
+ if (isStandaloneBlockComment(text, comment)) {
283
+ return { placement: 'inline' };
284
+ }
285
+ const expressionStart = skipWhitespace(text, comment.end);
286
+ return {
287
+ contentColumn: containerOutputColumn + tabWidth + 3,
288
+ leadingMove: {
289
+ removeEnd: expressionStart,
290
+ removeStart: comment.end,
291
+ },
292
+ multilineIndent: '',
293
+ placement: 'standalone',
294
+ singleLineSuffixWidth: getColumns(text.slice(comment.end, container.end), tabWidth),
295
+ };
296
+ }
271
297
  return { placement: 'inline' };
272
298
  }
273
299
  function getJsxExpressionContainerOutputColumn(text, container, tabWidth) {
@@ -312,6 +338,43 @@ function isPrettierIgnoredBlockComment(text, comments, index) {
312
338
  }
313
339
  return isPrettierIgnoreComment(getCommentBody(text, previousComment));
314
340
  }
341
+ function isPrettierIgnoredStandaloneLineComment(text, comments, index) {
342
+ const comment = comments[index]?.range;
343
+ const previousComment = comments[index - 1]?.range;
344
+ if (comment === undefined ||
345
+ comment.kind !== 'line' ||
346
+ !isStandaloneLineComment(text, comment) ||
347
+ previousComment === undefined ||
348
+ previousComment.kind !== 'line') {
349
+ return false;
350
+ }
351
+ if (!isStandaloneComment(text, previousComment) || !isAdjacentPreviousComment(text, previousComment, comment)) {
352
+ return false;
353
+ }
354
+ return isPrettierIgnoreComment(getCommentBody(text, previousComment));
355
+ }
356
+ function getStandaloneLineCommentGroupEndIndex(text, comments, startIndex, tabWidth) {
357
+ const firstComment = comments[startIndex];
358
+ if (firstComment === undefined) {
359
+ return startIndex;
360
+ }
361
+ let endIndex = startIndex;
362
+ let previousComment = firstComment;
363
+ while (endIndex + 1 < comments.length) {
364
+ const nextComment = comments[endIndex + 1];
365
+ if (nextComment === undefined ||
366
+ nextComment.kind !== 'line' ||
367
+ !isStandaloneLineComment(text, nextComment) ||
368
+ shouldSkipLineComment(text, nextComment) ||
369
+ !areAdjacentLineComments(text, previousComment, nextComment) ||
370
+ getColumnAt(text, firstComment.start, tabWidth) !== getColumnAt(text, nextComment.start, tabWidth)) {
371
+ break;
372
+ }
373
+ previousComment = nextComment;
374
+ endIndex += 1;
375
+ }
376
+ return endIndex;
377
+ }
315
378
  function isPrettierIgnoredTrailingLineComment(text, comments, index) {
316
379
  const comment = comments[index]?.range;
317
380
  if (comment === undefined || comment.kind !== 'line' || isStandaloneLineComment(text, comment)) {
@@ -330,7 +393,7 @@ function isPrettierIgnoredTrailingLineComment(text, comments, index) {
330
393
  return false;
331
394
  }
332
395
  const body = getCommentBody(text, previousComment);
333
- if (previousComment.kind === 'line' && isPrettierIgnoreComment(body)) {
396
+ if (isPrettierIgnoreComment(body)) {
334
397
  return true;
335
398
  }
336
399
  if (!isCommentNormallyIgnored(text, previousComment)) {
@@ -1,13 +1,13 @@
1
1
  import * as babelPlugin from 'prettier/plugins/babel';
2
2
  import * as typescriptPlugin from 'prettier/plugins/typescript';
3
- import { neutralizePrettierIgnoreForIgnoredBlockComments, wrapComments } from '../comments/wrap.js';
3
+ import { neutralizePrettierIgnoreForIgnoredComments, wrapComments } from '../comments/wrap.js';
4
4
  const parserNames = ['babel', 'babel-ts', 'typescript'];
5
5
  function wrapParser(parser) {
6
6
  return {
7
7
  ...parser,
8
8
  async parse(text, options) {
9
9
  const ast = await parser.parse(text, options);
10
- return neutralizePrettierIgnoreForIgnoredBlockComments(text, ast);
10
+ return neutralizePrettierIgnoreForIgnoredComments(text, ast);
11
11
  },
12
12
  async preprocess(text, options) {
13
13
  const preprocessed = parser.preprocess === undefined ? text : await parser.preprocess(text, options);
package/package.json CHANGED
@@ -51,5 +51,5 @@
51
51
  },
52
52
  "type": "module",
53
53
  "types": "./dist/index.d.ts",
54
- "version": "1.0.4"
54
+ "version": "1.0.6"
55
55
  }