@aforemendude/prettier-plugin-wrap-comments 1.0.5 → 1.1.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 +50 -14
- package/dist/comments/comment-body.d.ts +4 -0
- package/dist/comments/comment-body.js +36 -0
- package/dist/comments/comment-directives.d.ts +2 -0
- package/dist/comments/comment-directives.js +48 -0
- package/dist/comments/comment-eligibility.d.ts +4 -0
- package/dist/comments/comment-eligibility.js +20 -0
- package/dist/comments/comment-location.d.ts +9 -0
- package/dist/comments/comment-location.js +21 -0
- package/dist/comments/comment-ranges.d.ts +24 -0
- package/dist/comments/comment-ranges.js +36 -0
- package/dist/comments/embedded-expression-ranges.d.ts +13 -0
- package/dist/comments/embedded-expression-ranges.js +105 -0
- package/dist/comments/jsx-expression-layout.d.ts +10 -0
- package/dist/comments/jsx-expression-layout.js +117 -0
- package/dist/comments/line-comment-groups.d.ts +6 -0
- package/dist/comments/line-comment-groups.js +28 -0
- package/dist/comments/prettier-ignore.d.ts +8 -0
- package/dist/comments/prettier-ignore.js +145 -0
- package/dist/comments/printer-layout.d.ts +17 -0
- package/dist/comments/printer-layout.js +64 -0
- package/dist/comments/{block.d.ts → wrap-block-comment.d.ts} +9 -1
- package/dist/comments/{block.js → wrap-block-comment.js} +30 -14
- package/dist/comments/wrap-comments.d.ts +9 -0
- package/dist/comments/wrap-comments.js +101 -0
- package/dist/comments/wrap-line-comment-group.d.ts +4 -0
- package/dist/comments/wrap-line-comment-group.js +39 -0
- package/dist/comments/wrap-trailing-line-comment.d.ts +9 -0
- package/dist/comments/wrap-trailing-line-comment.js +78 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -4
- package/dist/plugin/create-parsers.d.ts +2 -0
- package/dist/plugin/create-parsers.js +57 -0
- package/dist/plugin/create-printers.d.ts +2 -0
- package/dist/plugin/{printers.js → create-printers.js} +9 -10
- package/dist/plugin/get-printer-layout-source.d.ts +4 -0
- package/dist/plugin/get-printer-layout-source.js +27 -0
- package/dist/plugin/jsx-comment-rewrite-metadata.d.ts +8 -0
- package/dist/plugin/jsx-comment-rewrite-metadata.js +40 -0
- package/dist/plugin/parser-names.d.ts +2 -0
- package/dist/plugin/parser-names.js +1 -0
- package/dist/utils/ast.d.ts +6 -0
- package/dist/utils/ast.js +52 -0
- package/dist/utils/display-width.d.ts +2 -0
- package/dist/utils/display-width.js +19 -0
- package/dist/{shared/markdown.d.ts → utils/format-markdown.d.ts} +1 -1
- package/dist/{shared/markdown.js → utils/format-markdown.js} +12 -2
- package/dist/utils/indentation.d.ts +4 -0
- package/dist/utils/indentation.js +21 -0
- package/dist/utils/replacements.d.ts +6 -0
- package/dist/utils/replacements.js +21 -0
- package/dist/utils/source-lines.d.ts +6 -0
- package/dist/utils/source-lines.js +40 -0
- package/dist/utils/type-guards.d.ts +2 -0
- package/dist/utils/type-guards.js +6 -0
- package/dist/utils/whitespace.d.ts +2 -0
- package/dist/utils/whitespace.js +22 -0
- package/dist/{shared/options.d.ts → utils/wrap-options.d.ts} +2 -1
- package/package.json +17 -9
- package/dist/comments/core.d.ts +0 -8
- package/dist/comments/core.js +0 -114
- package/dist/comments/line.d.ts +0 -6
- package/dist/comments/line.js +0 -108
- package/dist/comments/wrap.d.ts +0 -3
- package/dist/comments/wrap.js +0 -375
- package/dist/plugin/parsers.d.ts +0 -2
- package/dist/plugin/parsers.js +0 -35
- package/dist/plugin/printers.d.ts +0 -2
- package/dist/shared/text.d.ts +0 -15
- package/dist/shared/text.js +0 -99
- package/dist/shared/types.d.ts +0 -30
- package/dist/shared/types.js +0 -1
- /package/dist/{shared/options.js → utils/wrap-options.js} +0 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CommentEntry, CommentRange } from './comment-ranges.js';
|
|
2
|
+
import type { SourceRange } from '../utils/ast.js';
|
|
3
|
+
export declare function neutralizePrettierIgnoreForIgnoredComments<T>(text: string, ast: T): T;
|
|
4
|
+
export declare function collectPrettierIgnoredLineRanges(text: string, ast: unknown, comments: CommentEntry[]): SourceRange[];
|
|
5
|
+
export declare function isCommentInIgnoredLineRange(comment: CommentRange, ignoredLineRanges: SourceRange[]): boolean;
|
|
6
|
+
export declare function isPrettierIgnoredBlockComment(text: string, comments: CommentEntry[], index: number): boolean;
|
|
7
|
+
export declare function isPrettierIgnoredStandaloneLineComment(text: string, comments: CommentEntry[], index: number): boolean;
|
|
8
|
+
export declare function isPrettierIgnoredTrailingLineComment(text: string, comments: CommentEntry[], index: number): boolean;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { getCommentBody } from './comment-body.js';
|
|
2
|
+
import { isPrettierIgnoreComment } from './comment-directives.js';
|
|
3
|
+
import { shouldSkipBlockComment, shouldSkipLineComment } from './comment-eligibility.js';
|
|
4
|
+
import { areCommentsOnAdjacentLines, isCommentAdjacentBeforeIndex, isStandaloneBlockComment, isStandaloneComment, isStandaloneLineComment, } from './comment-location.js';
|
|
5
|
+
import { collectCommentEntries } from './comment-ranges.js';
|
|
6
|
+
import { getAstNodeRange, visitAstNodes } from '../utils/ast.js';
|
|
7
|
+
import { getLineEnd, getLineStart } from '../utils/source-lines.js';
|
|
8
|
+
import { skipWhitespace } from '../utils/whitespace.js';
|
|
9
|
+
const NEUTRALIZED_PRETTIER_IGNORE_COMMENT = 'prettier-ignore wrap-comments';
|
|
10
|
+
export function neutralizePrettierIgnoreForIgnoredComments(text, ast) {
|
|
11
|
+
const comments = collectCommentEntries(ast, text);
|
|
12
|
+
for (let index = 0; index < comments.length; index += 1) {
|
|
13
|
+
const entry = comments[index];
|
|
14
|
+
const previousEntry = comments[index - 1];
|
|
15
|
+
const shouldNeutralize = entry !== undefined &&
|
|
16
|
+
previousEntry !== undefined &&
|
|
17
|
+
((isPrettierIgnoredBlockComment(text, comments, index) && !shouldSkipBlockComment(text, entry.range)) ||
|
|
18
|
+
(isPrettierIgnoredStandaloneLineComment(text, comments, index) && !shouldSkipLineComment(text, entry.range)));
|
|
19
|
+
if (shouldNeutralize) {
|
|
20
|
+
previousEntry.raw.value = NEUTRALIZED_PRETTIER_IGNORE_COMMENT;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return ast;
|
|
24
|
+
}
|
|
25
|
+
export function collectPrettierIgnoredLineRanges(text, ast, comments) {
|
|
26
|
+
const nodeRanges = collectAstNodeRanges(ast);
|
|
27
|
+
const ignoredLineRanges = [];
|
|
28
|
+
for (let index = 0; index < comments.length; index += 1) {
|
|
29
|
+
const comment = comments[index]?.range;
|
|
30
|
+
if (comment === undefined ||
|
|
31
|
+
!isStandaloneComment(text, comment) ||
|
|
32
|
+
!isPrettierIgnoreComment(getCommentBody(text, comment))) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const targetStart = getPrettierIgnoreTargetStart(text, comments, index);
|
|
36
|
+
if (targetStart === undefined) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const targetRange = nodeRanges.find((range) => range.start === targetStart);
|
|
40
|
+
if (targetRange === undefined) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
ignoredLineRanges.push({
|
|
44
|
+
end: getLineEnd(text, targetRange.end),
|
|
45
|
+
start: getLineStart(text, targetRange.start),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return ignoredLineRanges;
|
|
49
|
+
}
|
|
50
|
+
export function isCommentInIgnoredLineRange(comment, ignoredLineRanges) {
|
|
51
|
+
return ignoredLineRanges.some((range) => comment.start >= range.start && comment.start < range.end);
|
|
52
|
+
}
|
|
53
|
+
export function isPrettierIgnoredBlockComment(text, comments, index) {
|
|
54
|
+
const comment = comments[index]?.range;
|
|
55
|
+
const previousComment = comments[index - 1]?.range;
|
|
56
|
+
if (comment === undefined ||
|
|
57
|
+
comment.kind !== 'block' ||
|
|
58
|
+
!isStandaloneBlockComment(text, comment) ||
|
|
59
|
+
previousComment === undefined) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
if (!isStandaloneComment(text, previousComment) || !areCommentsOnAdjacentLines(text, previousComment, comment)) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
return isPrettierIgnoreComment(getCommentBody(text, previousComment));
|
|
66
|
+
}
|
|
67
|
+
export function isPrettierIgnoredStandaloneLineComment(text, comments, index) {
|
|
68
|
+
const comment = comments[index]?.range;
|
|
69
|
+
const previousComment = comments[index - 1]?.range;
|
|
70
|
+
if (comment === undefined ||
|
|
71
|
+
comment.kind !== 'line' ||
|
|
72
|
+
!isStandaloneLineComment(text, comment) ||
|
|
73
|
+
previousComment === undefined ||
|
|
74
|
+
previousComment.kind !== 'line') {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
if (!isStandaloneComment(text, previousComment) || !areCommentsOnAdjacentLines(text, previousComment, comment)) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
return isPrettierIgnoreComment(getCommentBody(text, previousComment));
|
|
81
|
+
}
|
|
82
|
+
export function isPrettierIgnoredTrailingLineComment(text, comments, index) {
|
|
83
|
+
const comment = comments[index]?.range;
|
|
84
|
+
if (comment === undefined || comment.kind !== 'line' || isStandaloneLineComment(text, comment)) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
let cursor = getLineStart(text, comment.start);
|
|
88
|
+
for (let previousIndex = index - 1; previousIndex >= 0; previousIndex -= 1) {
|
|
89
|
+
const previousComment = comments[previousIndex]?.range;
|
|
90
|
+
if (previousComment !== undefined && previousComment.end > cursor) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (previousComment === undefined || !isStandaloneComment(text, previousComment)) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
if (!isCommentAdjacentBeforeIndex(text, previousComment, cursor)) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
const body = getCommentBody(text, previousComment);
|
|
100
|
+
if (isPrettierIgnoreComment(body)) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
if (!isSkippableCommentBetweenIgnoreAndTarget(text, previousComment)) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
cursor = getLineStart(text, previousComment.start);
|
|
107
|
+
}
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
function collectAstNodeRanges(ast) {
|
|
111
|
+
const ranges = [];
|
|
112
|
+
visitAstNodes(ast, (node) => {
|
|
113
|
+
const range = getAstNodeRange(node);
|
|
114
|
+
if (range !== undefined) {
|
|
115
|
+
ranges.push(range);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
return ranges.sort((left, right) => left.start - right.start || right.end - left.end);
|
|
119
|
+
}
|
|
120
|
+
function getPrettierIgnoreTargetStart(text, comments, ignoreCommentIndex) {
|
|
121
|
+
const ignoreComment = comments[ignoreCommentIndex]?.range;
|
|
122
|
+
if (ignoreComment === undefined) {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
let cursor = ignoreComment.end;
|
|
126
|
+
for (let index = ignoreCommentIndex + 1; index < comments.length; index += 1) {
|
|
127
|
+
cursor = skipWhitespace(text, cursor);
|
|
128
|
+
const comment = comments[index]?.range;
|
|
129
|
+
if (comment === undefined || comment.start !== cursor) {
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
if (!isStandaloneComment(text, comment) || !isSkippableCommentBetweenIgnoreAndTarget(text, comment)) {
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
cursor = comment.end;
|
|
136
|
+
}
|
|
137
|
+
const targetStart = skipWhitespace(text, cursor);
|
|
138
|
+
return targetStart >= text.length ? undefined : targetStart;
|
|
139
|
+
}
|
|
140
|
+
function isSkippableCommentBetweenIgnoreAndTarget(text, comment) {
|
|
141
|
+
if (comment.kind === 'block') {
|
|
142
|
+
return shouldSkipBlockComment(text, comment);
|
|
143
|
+
}
|
|
144
|
+
return shouldSkipLineComment(text, comment) && !isPrettierIgnoreComment(getCommentBody(text, comment));
|
|
145
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CommentEntry } from './comment-ranges.js';
|
|
2
|
+
import type { JsxExpressionContainerRange } from './jsx-expression-layout.js';
|
|
3
|
+
export type PrinterLayoutSource = {
|
|
4
|
+
ast: unknown;
|
|
5
|
+
text: string;
|
|
6
|
+
};
|
|
7
|
+
export type PrinterCommentLayout = {
|
|
8
|
+
lineIndentColumn: number;
|
|
9
|
+
lineWidth: number;
|
|
10
|
+
markerColumn: number;
|
|
11
|
+
suffixWidth: number;
|
|
12
|
+
};
|
|
13
|
+
export type PrinterLayout = {
|
|
14
|
+
comments: Array<PrinterCommentLayout | undefined>;
|
|
15
|
+
jsxCommentMarkerColumns: Array<number | undefined>;
|
|
16
|
+
};
|
|
17
|
+
export declare function getPrinterLayout(text: string, commentEntries: CommentEntry[], jsxExpressionContainers: JsxExpressionContainerRange[], source: PrinterLayoutSource | undefined, tabWidth: number): PrinterLayout;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { collectCommentEntries } from './comment-ranges.js';
|
|
2
|
+
import { collectJsxExpressionContainerRanges, getPrintedJsxCommentMarkerColumn } from './jsx-expression-layout.js';
|
|
3
|
+
import { getColumns } from '../utils/display-width.js';
|
|
4
|
+
import { getLeadingIndent } from '../utils/indentation.js';
|
|
5
|
+
import { getLineEnd, getLineStart } from '../utils/source-lines.js';
|
|
6
|
+
export function getPrinterLayout(text, commentEntries, jsxExpressionContainers, source, tabWidth) {
|
|
7
|
+
if (source === undefined) {
|
|
8
|
+
return {
|
|
9
|
+
comments: [],
|
|
10
|
+
jsxCommentMarkerColumns: [],
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
const outputCommentEntries = collectCommentEntries(source.ast, source.text);
|
|
14
|
+
const alignedOutputComments = alignOutputComments(text, commentEntries, source.text, outputCommentEntries);
|
|
15
|
+
const outputJsxExpressionContainers = collectJsxExpressionContainerRanges(source.ast);
|
|
16
|
+
const jsxCommentMarkerColumns = outputJsxExpressionContainers.length === jsxExpressionContainers.length
|
|
17
|
+
? outputJsxExpressionContainers.map((container) => getPrintedJsxCommentMarkerColumn(source.text, container, tabWidth))
|
|
18
|
+
: [];
|
|
19
|
+
return {
|
|
20
|
+
comments: alignedOutputComments.map((comment) => comment === undefined ? undefined : getPrinterCommentLayout(source.text, comment.range, tabWidth)),
|
|
21
|
+
jsxCommentMarkerColumns,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function alignOutputComments(text, comments, outputText, outputComments) {
|
|
25
|
+
if (comments.length === outputComments.length &&
|
|
26
|
+
comments.every((comment, index) => comment.range.kind === outputComments[index]?.range.kind)) {
|
|
27
|
+
return outputComments;
|
|
28
|
+
}
|
|
29
|
+
const alignedComments = [];
|
|
30
|
+
let outputIndex = 0;
|
|
31
|
+
for (const comment of comments) {
|
|
32
|
+
const raw = normalizeCommentForMatching(text.slice(comment.range.start, comment.range.end));
|
|
33
|
+
let matchingComment;
|
|
34
|
+
while (outputIndex < outputComments.length) {
|
|
35
|
+
const candidate = outputComments[outputIndex];
|
|
36
|
+
outputIndex += 1;
|
|
37
|
+
if (candidate !== undefined &&
|
|
38
|
+
candidate.range.kind === comment.range.kind &&
|
|
39
|
+
normalizeCommentForMatching(outputText.slice(candidate.range.start, candidate.range.end)) === raw) {
|
|
40
|
+
matchingComment = candidate;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
alignedComments.push(matchingComment);
|
|
45
|
+
}
|
|
46
|
+
return alignedComments;
|
|
47
|
+
}
|
|
48
|
+
function normalizeCommentForMatching(raw) {
|
|
49
|
+
return raw.replace(/\r\n?/gu, '\n');
|
|
50
|
+
}
|
|
51
|
+
function getPrinterCommentLayout(text, comment, tabWidth) {
|
|
52
|
+
const lineStart = getLineStart(text, comment.start);
|
|
53
|
+
const lineEnd = getLineEnd(text, comment.end);
|
|
54
|
+
const linePrefix = text.slice(lineStart, comment.start);
|
|
55
|
+
const lineIndent = getLeadingIndent(linePrefix);
|
|
56
|
+
const lineText = text.slice(lineStart, lineEnd).replace(/[ \t]+$/u, '');
|
|
57
|
+
const suffix = text.slice(comment.end, lineEnd).replace(/[ \t]+$/u, '');
|
|
58
|
+
return {
|
|
59
|
+
lineIndentColumn: getColumns(lineIndent, tabWidth),
|
|
60
|
+
lineWidth: getColumns(lineText, tabWidth),
|
|
61
|
+
markerColumn: getColumns(linePrefix, tabWidth),
|
|
62
|
+
suffixWidth: getColumns(suffix, tabWidth),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
import type { CommentRange
|
|
1
|
+
import type { CommentRange } from './comment-ranges.js';
|
|
2
|
+
import type { Replacement } from '../utils/replacements.js';
|
|
3
|
+
import type { WrapOptions } from '../utils/wrap-options.js';
|
|
2
4
|
export type BlockCommentLayout = {
|
|
3
5
|
contentColumn?: number;
|
|
6
|
+
leadingMove?: {
|
|
7
|
+
removeEnd: number;
|
|
8
|
+
removeStart: number;
|
|
9
|
+
};
|
|
10
|
+
markerColumn?: number;
|
|
4
11
|
multilineIndent?: string;
|
|
5
12
|
placement: 'inline' | 'standalone' | 'trailing';
|
|
13
|
+
singleLineSuffixWidth?: number;
|
|
6
14
|
trailingMove?: {
|
|
7
15
|
insertAt: number;
|
|
8
16
|
removeEnd: number;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { getColumnAt, getColumns
|
|
1
|
+
import { normalizeBlockCommentBody } from './comment-body.js';
|
|
2
|
+
import { shouldSkipBlockComment } from './comment-eligibility.js';
|
|
3
|
+
import { isStandaloneBlockComment } from './comment-location.js';
|
|
4
|
+
import { getColumnAt, getColumns } from '../utils/display-width.js';
|
|
5
|
+
import { formatMarkdownLines } from '../utils/format-markdown.js';
|
|
6
|
+
import { getLinePrefix, getPreferredNewline } from '../utils/source-lines.js';
|
|
7
|
+
import { getAvailableContentWidth, getPrintWidth, getTabWidth } from '../utils/wrap-options.js';
|
|
5
8
|
export async function wrapBlockComment(text, comment, options, layout = getDefaultBlockCommentLayout(text, comment)) {
|
|
6
|
-
|
|
7
|
-
if (raw.startsWith('/**') || hasPreserveCommentMarker(raw)) {
|
|
9
|
+
if (shouldSkipBlockComment(text, comment)) {
|
|
8
10
|
return undefined;
|
|
9
11
|
}
|
|
12
|
+
const raw = text.slice(comment.start, comment.end);
|
|
10
13
|
const markdown = normalizeBlockCommentBody(raw);
|
|
11
|
-
if (markdown.trim() === '' || isDirectiveComment(markdown)) {
|
|
12
|
-
return undefined;
|
|
13
|
-
}
|
|
14
14
|
const tabWidth = getTabWidth(options);
|
|
15
|
-
const markerColumn = getColumnAt(text, comment.start, tabWidth);
|
|
15
|
+
const markerColumn = layout.markerColumn ?? getColumnAt(text, comment.start, tabWidth);
|
|
16
16
|
const availableWidth = getAvailableContentWidth(options, layout.contentColumn ?? markerColumn + 3);
|
|
17
17
|
const formattedLines = await formatMarkdownLines(markdown, availableWidth, options);
|
|
18
18
|
const replacement = buildBlockReplacement(text, comment, formattedLines, options, layout);
|
|
@@ -33,10 +33,11 @@ export async function wrapBlockComment(text, comment, options, layout = getDefau
|
|
|
33
33
|
}
|
|
34
34
|
function buildBlockReplacement(text, comment, formattedLines, options, layout) {
|
|
35
35
|
const tabWidth = getTabWidth(options);
|
|
36
|
-
const markerColumn = getColumnAt(text, comment.start, tabWidth);
|
|
36
|
+
const markerColumn = layout.markerColumn ?? getColumnAt(text, comment.start, tabWidth);
|
|
37
37
|
const singleLine = `/* ${formattedLines.join(' ')} */`;
|
|
38
38
|
const singleLineWidth = getColumns(singleLine, tabWidth);
|
|
39
|
-
|
|
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') {
|
|
@@ -45,12 +46,13 @@ function buildBlockReplacement(text, comment, formattedLines, options, layout) {
|
|
|
45
46
|
const newline = getPreferredNewline(text, options);
|
|
46
47
|
const indent = layout.multilineIndent ?? getLinePrefix(text, comment.start);
|
|
47
48
|
const replacementText = buildMultilineBlockReplacement(formattedLines, newline, indent);
|
|
49
|
+
const replacementTextWithNewline = [replacementText, ''].join(newline);
|
|
48
50
|
if (layout.trailingMove !== undefined) {
|
|
49
51
|
return [
|
|
50
52
|
{
|
|
51
53
|
end: layout.trailingMove.insertAt,
|
|
52
54
|
start: layout.trailingMove.insertAt,
|
|
53
|
-
text:
|
|
55
|
+
text: replacementTextWithNewline,
|
|
54
56
|
},
|
|
55
57
|
{
|
|
56
58
|
end: layout.trailingMove.removeEnd,
|
|
@@ -59,11 +61,25 @@ function buildBlockReplacement(text, comment, formattedLines, options, layout) {
|
|
|
59
61
|
},
|
|
60
62
|
];
|
|
61
63
|
}
|
|
64
|
+
if (layout.leadingMove !== undefined) {
|
|
65
|
+
return [
|
|
66
|
+
{
|
|
67
|
+
end: comment.end,
|
|
68
|
+
start: comment.start,
|
|
69
|
+
text: replacementTextWithNewline,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
end: layout.leadingMove.removeEnd,
|
|
73
|
+
start: layout.leadingMove.removeStart,
|
|
74
|
+
text: '',
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
}
|
|
62
78
|
return replacementText;
|
|
63
79
|
}
|
|
64
80
|
function buildMultilineBlockReplacement(formattedLines, newline, indent) {
|
|
65
81
|
const body = formattedLines.map((line) => `${indent} *${line.length === 0 ? '' : ` ${line}`}`).join(newline);
|
|
66
|
-
return
|
|
82
|
+
return ['/*', body, `${indent} */`].join(newline);
|
|
67
83
|
}
|
|
68
84
|
function getDefaultBlockCommentLayout(text, comment) {
|
|
69
85
|
return {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PrinterLayoutSource } from './printer-layout.js';
|
|
2
|
+
import type { JsxBlockCommentRewrite } from '../plugin/jsx-comment-rewrite-metadata.js';
|
|
3
|
+
import type { WrapOptions } from '../utils/wrap-options.js';
|
|
4
|
+
export type WrapCommentsResult = {
|
|
5
|
+
jsxBlockCommentRewrites: JsxBlockCommentRewrite[];
|
|
6
|
+
text: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function wrapComments<T>(text: string, ast: T, options: WrapOptions, printerLayoutSource?: PrinterLayoutSource): Promise<string>;
|
|
9
|
+
export declare function wrapCommentsWithMetadata<T>(text: string, ast: T, options: WrapOptions, printerLayoutSource?: PrinterLayoutSource): Promise<WrapCommentsResult>;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { shouldSkipLineComment } from './comment-eligibility.js';
|
|
2
|
+
import { isStandaloneBlockComment, isStandaloneLineComment } from './comment-location.js';
|
|
3
|
+
import { collectCommentEntries } from './comment-ranges.js';
|
|
4
|
+
import { collectEmbeddedExpressionRanges, doesBlockCommentSeparateEmbeddedTrailingLineComment, getEmbeddedTrailingLineCommentMove, isCommentInEmbeddedExpression, } from './embedded-expression-ranges.js';
|
|
5
|
+
import { collectJsxExpressionContainerRanges, getJsxExpressionBlockCommentLayout } from './jsx-expression-layout.js';
|
|
6
|
+
import { collectLineCommentGroup } from './line-comment-groups.js';
|
|
7
|
+
import { collectPrettierIgnoredLineRanges, isCommentInIgnoredLineRange, isPrettierIgnoredBlockComment, isPrettierIgnoredStandaloneLineComment, isPrettierIgnoredTrailingLineComment, } from './prettier-ignore.js';
|
|
8
|
+
import { getPrinterLayout } from './printer-layout.js';
|
|
9
|
+
import { wrapBlockComment } from './wrap-block-comment.js';
|
|
10
|
+
import { wrapLineCommentGroup } from './wrap-line-comment-group.js';
|
|
11
|
+
import { wrapTrailingLineComment } from './wrap-trailing-line-comment.js';
|
|
12
|
+
import { applyReplacements } from '../utils/replacements.js';
|
|
13
|
+
import { getTabWidth } from '../utils/wrap-options.js';
|
|
14
|
+
export async function wrapComments(text, ast, options, printerLayoutSource) {
|
|
15
|
+
return (await wrapCommentsWithMetadata(text, ast, options, printerLayoutSource)).text;
|
|
16
|
+
}
|
|
17
|
+
export async function wrapCommentsWithMetadata(text, ast, options, printerLayoutSource) {
|
|
18
|
+
const commentEntries = collectCommentEntries(ast, text);
|
|
19
|
+
const comments = commentEntries.map((entry) => entry.range);
|
|
20
|
+
const embeddedExpressionRanges = collectEmbeddedExpressionRanges(ast);
|
|
21
|
+
const jsxExpressionContainers = collectJsxExpressionContainerRanges(ast);
|
|
22
|
+
const ignoredLineRanges = collectPrettierIgnoredLineRanges(text, ast, commentEntries);
|
|
23
|
+
if (comments.length === 0) {
|
|
24
|
+
return { jsxBlockCommentRewrites: [], text };
|
|
25
|
+
}
|
|
26
|
+
const replacements = [];
|
|
27
|
+
const jsxBlockCommentRewrites = [];
|
|
28
|
+
const tabWidth = getTabWidth(options);
|
|
29
|
+
const printerLayout = getPrinterLayout(text, commentEntries, jsxExpressionContainers, printerLayoutSource, tabWidth);
|
|
30
|
+
let blockCommentIndex = -1;
|
|
31
|
+
for (let index = 0; index < comments.length; index += 1) {
|
|
32
|
+
const comment = comments[index];
|
|
33
|
+
const outputCommentLayout = printerLayout.comments[index];
|
|
34
|
+
if (comment?.kind === 'block') {
|
|
35
|
+
blockCommentIndex += 1;
|
|
36
|
+
}
|
|
37
|
+
if (comment === undefined || isCommentInIgnoredLineRange(comment, ignoredLineRanges)) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (comment.kind === 'block') {
|
|
41
|
+
if (isPrettierIgnoredBlockComment(text, commentEntries, index)) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const jsxLayout = getJsxExpressionBlockCommentLayout(text, comment, comments[index - 1], jsxExpressionContainers, tabWidth, outputCommentLayout, printerLayout.jsxCommentMarkerColumns);
|
|
45
|
+
if (jsxLayout?.placement === 'inline') {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const outputLayout = outputCommentLayout === undefined
|
|
49
|
+
? undefined
|
|
50
|
+
: {
|
|
51
|
+
markerColumn: outputCommentLayout.markerColumn,
|
|
52
|
+
placement: isStandaloneBlockComment(text, comment) ? 'standalone' : 'inline',
|
|
53
|
+
};
|
|
54
|
+
const replacement = await wrapBlockComment(text, comment, options, jsxLayout ?? outputLayout);
|
|
55
|
+
const preservesEmbeddedCommentOrder = doesBlockCommentSeparateEmbeddedTrailingLineComment(text, comment, comments[index + 1], embeddedExpressionRanges);
|
|
56
|
+
if (Array.isArray(replacement)) {
|
|
57
|
+
if (!preservesEmbeddedCommentOrder) {
|
|
58
|
+
replacements.push(...replacement);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else if (replacement !== undefined) {
|
|
62
|
+
replacements.push(replacement);
|
|
63
|
+
if (jsxLayout !== undefined) {
|
|
64
|
+
jsxBlockCommentRewrites.push({ blockCommentIndex, text: replacement.text });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (shouldSkipLineComment(text, comment)) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (isPrettierIgnoredStandaloneLineComment(text, commentEntries, index)) {
|
|
73
|
+
index = collectLineCommentGroup(text, comments, index, tabWidth).endIndex;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (!isStandaloneLineComment(text, comment)) {
|
|
77
|
+
if (isPrettierIgnoredTrailingLineComment(text, commentEntries, index)) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const embeddedMove = getEmbeddedTrailingLineCommentMove(text, comment, embeddedExpressionRanges);
|
|
81
|
+
if (embeddedMove === undefined && isCommentInEmbeddedExpression(comment, embeddedExpressionRanges)) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const replacement = await wrapTrailingLineComment(text, comment, options, outputCommentLayout, embeddedMove);
|
|
85
|
+
if (replacement !== undefined) {
|
|
86
|
+
replacements.push(...replacement);
|
|
87
|
+
}
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const group = collectLineCommentGroup(text, comments, index, tabWidth);
|
|
91
|
+
index = group.endIndex;
|
|
92
|
+
const replacement = await wrapLineCommentGroup(text, group.comments, options, outputCommentLayout?.markerColumn);
|
|
93
|
+
if (replacement !== undefined) {
|
|
94
|
+
replacements.push(replacement);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
jsxBlockCommentRewrites,
|
|
99
|
+
text: applyReplacements(text, replacements),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CommentRange } from './comment-ranges.js';
|
|
2
|
+
import type { Replacement } from '../utils/replacements.js';
|
|
3
|
+
import type { WrapOptions } from '../utils/wrap-options.js';
|
|
4
|
+
export declare function wrapLineCommentGroup(text: string, comments: CommentRange[], options: WrapOptions, outputMarkerColumn?: number): Promise<Replacement | undefined>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { normalizeLineCommentBody } from './comment-body.js';
|
|
2
|
+
import { getColumnAt } from '../utils/display-width.js';
|
|
3
|
+
import { formatMarkdownLines } from '../utils/format-markdown.js';
|
|
4
|
+
import { getContinuationIndent } from '../utils/indentation.js';
|
|
5
|
+
import { getPreferredNewline } from '../utils/source-lines.js';
|
|
6
|
+
import { getAvailableContentWidth, getTabWidth } from '../utils/wrap-options.js';
|
|
7
|
+
export async function wrapLineCommentGroup(text, comments, options, outputMarkerColumn) {
|
|
8
|
+
const firstComment = comments[0];
|
|
9
|
+
if (firstComment === undefined) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
const lastComment = comments.at(-1) ?? firstComment;
|
|
13
|
+
const bodyLines = comments.map((comment) => normalizeLineCommentBody(text.slice(comment.start + 2, comment.end)));
|
|
14
|
+
if (bodyLines.every((line) => line.trim() === '')) {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
const tabWidth = getTabWidth(options);
|
|
18
|
+
const markerColumn = outputMarkerColumn ?? getColumnAt(text, firstComment.start, tabWidth);
|
|
19
|
+
const availableWidth = getAvailableContentWidth(options, markerColumn + 3);
|
|
20
|
+
const formattedLines = await formatMarkdownLines(bodyLines.join('\n'), availableWidth, options);
|
|
21
|
+
const newline = getPreferredNewline(text, options);
|
|
22
|
+
const continuationIndent = getContinuationIndent(text, firstComment.start, markerColumn, options);
|
|
23
|
+
const replacementText = formattedLines
|
|
24
|
+
.map((line, index) => {
|
|
25
|
+
const commentText = line.length === 0 ? '//' : `// ${line}`;
|
|
26
|
+
return `${index === 0 ? '' : continuationIndent}${commentText}`;
|
|
27
|
+
})
|
|
28
|
+
.join(newline);
|
|
29
|
+
const start = firstComment.start;
|
|
30
|
+
const end = lastComment.end;
|
|
31
|
+
if (replacementText === text.slice(start, end)) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
end,
|
|
36
|
+
start,
|
|
37
|
+
text: replacementText,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CommentRange } from './comment-ranges.js';
|
|
2
|
+
import type { EmbeddedTrailingLineCommentMove } from './embedded-expression-ranges.js';
|
|
3
|
+
import type { Replacement } from '../utils/replacements.js';
|
|
4
|
+
import type { WrapOptions } from '../utils/wrap-options.js';
|
|
5
|
+
export type TrailingLineCommentLayout = {
|
|
6
|
+
lineIndentColumn: number;
|
|
7
|
+
lineWidth: number;
|
|
8
|
+
};
|
|
9
|
+
export declare function wrapTrailingLineComment(text: string, comment: CommentRange, options: WrapOptions, outputLayout?: TrailingLineCommentLayout, move?: EmbeddedTrailingLineCommentMove): Promise<Replacement[] | undefined>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { normalizeLineCommentBody } from './comment-body.js';
|
|
2
|
+
import { getColumnAt, getColumns } from '../utils/display-width.js';
|
|
3
|
+
import { formatMarkdownLines } from '../utils/format-markdown.js';
|
|
4
|
+
import { getLeadingIndent, makeIndent } from '../utils/indentation.js';
|
|
5
|
+
import { getLineEnd, getLineStart, getPreferredNewline } from '../utils/source-lines.js';
|
|
6
|
+
import { getAvailableContentWidth, getPrintWidth, getTabWidth } from '../utils/wrap-options.js';
|
|
7
|
+
export async function wrapTrailingLineComment(text, comment, options, outputLayout, move) {
|
|
8
|
+
const lineStart = getLineStart(text, comment.start);
|
|
9
|
+
const lineEnd = getLineEnd(text, comment.start);
|
|
10
|
+
if (comment.end > lineEnd) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
if (isTrailingLineCommentWithinPrintWidth(text, lineStart, lineEnd, options, outputLayout?.lineWidth)) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
const linePrefix = text.slice(lineStart, comment.start);
|
|
17
|
+
const codeText = linePrefix.replace(/[ \t]+$/u, '');
|
|
18
|
+
if (codeText.trim() === '') {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
const body = normalizeLineCommentBody(text.slice(comment.start + 2, comment.end));
|
|
22
|
+
if (body.trim() === '') {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
const tabWidth = getTabWidth(options);
|
|
26
|
+
const markerColumn = move === undefined ? undefined : (outputLayout?.lineIndentColumn ?? getColumnAt(text, move.insertAt, tabWidth));
|
|
27
|
+
const indent = markerColumn === undefined
|
|
28
|
+
? getTrailingCommentIndent(codeText, linePrefix, options, outputLayout?.lineIndentColumn)
|
|
29
|
+
: makeIndent(markerColumn, options);
|
|
30
|
+
const availableWidth = getAvailableContentWidth(options, getColumns(indent, tabWidth) + 3);
|
|
31
|
+
const formattedLines = await formatMarkdownLines(body, availableWidth, options);
|
|
32
|
+
const newline = getPreferredNewline(text, options);
|
|
33
|
+
const leadingCommentText = buildLeadingCommentText(formattedLines, indent, newline, move !== undefined);
|
|
34
|
+
const codeEnd = lineStart + codeText.length;
|
|
35
|
+
const insertAt = move?.insertAt ?? lineStart;
|
|
36
|
+
const insertionSuffix = move === undefined ? '' : indent;
|
|
37
|
+
return [
|
|
38
|
+
{
|
|
39
|
+
end: insertAt,
|
|
40
|
+
start: insertAt,
|
|
41
|
+
text: [leadingCommentText, insertionSuffix].join(newline),
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
end: lineEnd,
|
|
45
|
+
start: move?.removeStart ?? codeEnd,
|
|
46
|
+
text: '',
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
function buildLeadingCommentText(formattedLines, indent, newline, startsAtExpression) {
|
|
51
|
+
return formattedLines
|
|
52
|
+
.map((line, index) => {
|
|
53
|
+
const lineIndent = startsAtExpression && index === 0 ? '' : indent;
|
|
54
|
+
return `${lineIndent}${line.length === 0 ? '//' : `// ${line}`}`;
|
|
55
|
+
})
|
|
56
|
+
.join(newline);
|
|
57
|
+
}
|
|
58
|
+
function isTrailingLineCommentWithinPrintWidth(text, lineStart, lineEnd, options, outputLineWidth) {
|
|
59
|
+
if (outputLineWidth !== undefined) {
|
|
60
|
+
return outputLineWidth <= getPrintWidth(options);
|
|
61
|
+
}
|
|
62
|
+
const tabWidth = getTabWidth(options);
|
|
63
|
+
const lineText = text.slice(lineStart, lineEnd).replace(/[ \t]+$/u, '');
|
|
64
|
+
return getColumns(lineText, tabWidth) <= getPrintWidth(options);
|
|
65
|
+
}
|
|
66
|
+
function getTrailingCommentIndent(codeText, linePrefix, options, outputLineIndentColumn) {
|
|
67
|
+
const indent = getLeadingIndent(linePrefix);
|
|
68
|
+
if (outputLineIndentColumn === undefined && !isClosingDelimiterLine(codeText)) {
|
|
69
|
+
return indent;
|
|
70
|
+
}
|
|
71
|
+
const tabWidth = getTabWidth(options);
|
|
72
|
+
const indentColumn = outputLineIndentColumn ?? getColumns(indent, tabWidth);
|
|
73
|
+
const commentIndentColumn = isClosingDelimiterLine(codeText) ? indentColumn + tabWidth : indentColumn;
|
|
74
|
+
return makeIndent(commentIndentColumn, options);
|
|
75
|
+
}
|
|
76
|
+
function isClosingDelimiterLine(codeText) {
|
|
77
|
+
return /^[ \t]*[\])}]+[\])};,]*[ \t]*$/u.test(codeText);
|
|
78
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Plugin } from 'prettier';
|
|
2
2
|
declare const parsers: {
|
|
3
3
|
[parserName: string]: import("prettier").Parser<any>;
|
|
4
|
-
}
|
|
4
|
+
};
|
|
5
5
|
declare const printers: {
|
|
6
6
|
[astFormat: string]: import("prettier").Printer<any>;
|
|
7
|
-
}
|
|
7
|
+
};
|
|
8
8
|
declare const plugin: Plugin;
|
|
9
9
|
export { parsers, printers };
|
|
10
10
|
export default plugin;
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
const parsers =
|
|
4
|
-
const printers =
|
|
1
|
+
import { createParsers } from './plugin/create-parsers.js';
|
|
2
|
+
import { createPrinters } from './plugin/create-printers.js';
|
|
3
|
+
const parsers = createParsers();
|
|
4
|
+
const printers = createPrinters();
|
|
5
5
|
const plugin = {
|
|
6
6
|
parsers,
|
|
7
7
|
printers,
|