@aforemendude/prettier-plugin-wrap-comments 1.0.5 → 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) {
@@ -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
  }
@@ -250,7 +255,12 @@ function getJsxExpressionBlockCommentLayout(text, comment, jsxExpressionContaine
250
255
  const expressionTextAfterComment = text.slice(comment.end, container.end - 1).trim();
251
256
  const containerOutputColumn = getJsxExpressionContainerOutputColumn(text, container, tabWidth);
252
257
  if (expressionTextBeforeComment === '' && expressionTextAfterComment === '') {
253
- return { contentColumn: containerOutputColumn + tabWidth + 3, multilineIndent: '', placement: 'standalone' };
258
+ return {
259
+ contentColumn: containerOutputColumn + tabWidth + 3,
260
+ multilineIndent: '',
261
+ placement: 'standalone',
262
+ singleLineSuffixWidth: 1,
263
+ };
254
264
  }
255
265
  if (expressionTextBeforeComment !== '' && expressionTextAfterComment === '') {
256
266
  const expressionStart = skipWhitespace(text, container.start + 1);
@@ -260,6 +270,7 @@ function getJsxExpressionBlockCommentLayout(text, comment, jsxExpressionContaine
260
270
  contentColumn: containerOutputColumn + tabWidth + 3,
261
271
  multilineIndent: '',
262
272
  placement: 'trailing',
273
+ singleLineSuffixWidth: 1,
263
274
  trailingMove: {
264
275
  insertAt: expressionStart,
265
276
  removeEnd: removalEnd,
@@ -267,6 +278,22 @@ function getJsxExpressionBlockCommentLayout(text, comment, jsxExpressionContaine
267
278
  },
268
279
  };
269
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
+ }
270
297
  return { placement: 'inline' };
271
298
  }
272
299
  function getJsxExpressionContainerOutputColumn(text, container, tabWidth) {
@@ -311,6 +338,43 @@ function isPrettierIgnoredBlockComment(text, comments, index) {
311
338
  }
312
339
  return isPrettierIgnoreComment(getCommentBody(text, previousComment));
313
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
+ }
314
378
  function isPrettierIgnoredTrailingLineComment(text, comments, index) {
315
379
  const comment = comments[index]?.range;
316
380
  if (comment === undefined || comment.kind !== 'line' || isStandaloneLineComment(text, comment)) {
@@ -329,7 +393,7 @@ function isPrettierIgnoredTrailingLineComment(text, comments, index) {
329
393
  return false;
330
394
  }
331
395
  const body = getCommentBody(text, previousComment);
332
- if (previousComment.kind === 'line' && isPrettierIgnoreComment(body)) {
396
+ if (isPrettierIgnoreComment(body)) {
333
397
  return true;
334
398
  }
335
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.5"
54
+ "version": "1.0.6"
55
55
  }