@aforemendude/prettier-plugin-wrap-comments 1.0.6 → 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 +24 -6
- 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} +4 -1
- package/dist/comments/{block.js → wrap-block-comment.js} +15 -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 -439
- 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,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,10 +1,13 @@
|
|
|
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;
|
|
4
6
|
leadingMove?: {
|
|
5
7
|
removeEnd: number;
|
|
6
8
|
removeStart: number;
|
|
7
9
|
};
|
|
10
|
+
markerColumn?: number;
|
|
8
11
|
multilineIndent?: string;
|
|
9
12
|
placement: 'inline' | 'standalone' | 'trailing';
|
|
10
13
|
singleLineSuffixWidth?: 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,7 +33,7 @@ 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;
|
|
@@ -46,12 +46,13 @@ function buildBlockReplacement(text, comment, formattedLines, options, layout) {
|
|
|
46
46
|
const newline = getPreferredNewline(text, options);
|
|
47
47
|
const indent = layout.multilineIndent ?? getLinePrefix(text, comment.start);
|
|
48
48
|
const replacementText = buildMultilineBlockReplacement(formattedLines, newline, indent);
|
|
49
|
+
const replacementTextWithNewline = [replacementText, ''].join(newline);
|
|
49
50
|
if (layout.trailingMove !== undefined) {
|
|
50
51
|
return [
|
|
51
52
|
{
|
|
52
53
|
end: layout.trailingMove.insertAt,
|
|
53
54
|
start: layout.trailingMove.insertAt,
|
|
54
|
-
text:
|
|
55
|
+
text: replacementTextWithNewline,
|
|
55
56
|
},
|
|
56
57
|
{
|
|
57
58
|
end: layout.trailingMove.removeEnd,
|
|
@@ -65,7 +66,7 @@ function buildBlockReplacement(text, comment, formattedLines, options, layout) {
|
|
|
65
66
|
{
|
|
66
67
|
end: comment.end,
|
|
67
68
|
start: comment.start,
|
|
68
|
-
text:
|
|
69
|
+
text: replacementTextWithNewline,
|
|
69
70
|
},
|
|
70
71
|
{
|
|
71
72
|
end: layout.leadingMove.removeEnd,
|
|
@@ -78,7 +79,7 @@ function buildBlockReplacement(text, comment, formattedLines, options, layout) {
|
|
|
78
79
|
}
|
|
79
80
|
function buildMultilineBlockReplacement(formattedLines, newline, indent) {
|
|
80
81
|
const body = formattedLines.map((line) => `${indent} *${line.length === 0 ? '' : ` ${line}`}`).join(newline);
|
|
81
|
-
return
|
|
82
|
+
return ['/*', body, `${indent} */`].join(newline);
|
|
82
83
|
}
|
|
83
84
|
function getDefaultBlockCommentLayout(text, comment) {
|
|
84
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,
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as babelPlugin from 'prettier/plugins/babel';
|
|
2
|
+
import * as typescriptPlugin from 'prettier/plugins/typescript';
|
|
3
|
+
import { collectAstComments } from '../comments/comment-ranges.js';
|
|
4
|
+
import { neutralizePrettierIgnoreForIgnoredComments } from '../comments/prettier-ignore.js';
|
|
5
|
+
import { wrapCommentsWithMetadata } from '../comments/wrap-comments.js';
|
|
6
|
+
import { getPrinterLayoutSource } from './get-printer-layout-source.js';
|
|
7
|
+
import { markRewrittenJsxBlockComments, setJsxBlockCommentRewrites } from './jsx-comment-rewrite-metadata.js';
|
|
8
|
+
import { SUPPORTED_PARSER_NAMES } from './parser-names.js';
|
|
9
|
+
export function createParsers() {
|
|
10
|
+
const parsers = {};
|
|
11
|
+
for (const parserName of SUPPORTED_PARSER_NAMES) {
|
|
12
|
+
const sourceParsers = parserName === 'typescript' ? typescriptPlugin.parsers : babelPlugin.parsers;
|
|
13
|
+
const parser = sourceParsers[parserName];
|
|
14
|
+
if (parser !== undefined) {
|
|
15
|
+
parsers[parserName] = createWrappedParser(parserName, parser);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return parsers;
|
|
19
|
+
}
|
|
20
|
+
function createWrappedParser(parserName, parser) {
|
|
21
|
+
return {
|
|
22
|
+
...parser,
|
|
23
|
+
async parse(text, options) {
|
|
24
|
+
const ast = await parser.parse(text, options);
|
|
25
|
+
const neutralizedAst = neutralizePrettierIgnoreForIgnoredComments(text, ast);
|
|
26
|
+
markRewrittenJsxBlockComments(text, neutralizedAst, options);
|
|
27
|
+
return neutralizedAst;
|
|
28
|
+
},
|
|
29
|
+
async preprocess(text, options) {
|
|
30
|
+
setJsxBlockCommentRewrites(options, []);
|
|
31
|
+
const preprocessed = parser.preprocess === undefined ? text : await parser.preprocess(text, options);
|
|
32
|
+
if (hasOffsetSensitiveFormatting(text, options)) {
|
|
33
|
+
return preprocessed;
|
|
34
|
+
}
|
|
35
|
+
let ast;
|
|
36
|
+
try {
|
|
37
|
+
ast = await parser.parse(preprocessed, options);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return preprocessed;
|
|
41
|
+
}
|
|
42
|
+
if (collectAstComments(ast).length === 0) {
|
|
43
|
+
return preprocessed;
|
|
44
|
+
}
|
|
45
|
+
const printerLayoutSource = await getPrinterLayoutSource(preprocessed, ast, parserName, parser, options);
|
|
46
|
+
const result = await wrapCommentsWithMetadata(preprocessed, ast, options, printerLayoutSource);
|
|
47
|
+
setJsxBlockCommentRewrites(options, result.jsxBlockCommentRewrites);
|
|
48
|
+
return result.text;
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function hasOffsetSensitiveFormatting(text, options) {
|
|
53
|
+
const cursorOffset = options['cursorOffset'];
|
|
54
|
+
const hasCursor = typeof cursorOffset === 'number' && cursorOffset >= 0;
|
|
55
|
+
const hasPartialRange = options.rangeStart > 0 || options.rangeEnd < text.length;
|
|
56
|
+
return hasCursor || hasPartialRange;
|
|
57
|
+
}
|