@lewishowles/lint-config 0.4.0 → 0.6.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.
@@ -1,275 +0,0 @@
1
- import { addTerminalPunctuation, capitaliseSentence, formatSentence } from "../utils/wrap.js";
2
- import { formatJSDocPunctuation, isJSDoc } from "../utils/jsdoc.js";
3
- import {
4
- getCommentText,
5
- getLineCommentGroups,
6
- getLineIndent,
7
- getNewline,
8
- replaceMinimalComment,
9
- } from "../utils/source.js";
10
-
11
- /**
12
- * Replace only the value of a line comment.
13
- *
14
- * @param {object} sourceCode
15
- * The Oxlint source code object.
16
- * @param {object} comment
17
- * The line comment token.
18
- * @param {string} value
19
- * The replacement comment value.
20
- *
21
- * @returns {string}
22
- * The replacement comment text.
23
- */
24
- function replaceLineCommentValue(sourceCode, comment, value) {
25
- // The comment's raw source text.
26
- const commentText = getCommentText(sourceCode, comment);
27
-
28
- return `${commentText.slice(0, 2)}${value}`;
29
- }
30
-
31
- /**
32
- * Format the prose text in a standard block-comment line.
33
- *
34
- * @param {string} line
35
- * The block-comment line.
36
- * @param {function} formatProse
37
- * The formatter for the line's prose.
38
- *
39
- * @returns {string}
40
- * The formatted block-comment line.
41
- */
42
- function formatBlockCommentLine(line, formatProse) {
43
- // The line's leading `*` decoration, when present.
44
- const marker = line.match(/^\s*\*\s?/);
45
-
46
- if (marker === null) {
47
- return line;
48
- }
49
-
50
- return `${marker[0]}${formatProse(line.slice(marker[0].length).trim())}`;
51
- }
52
-
53
- /**
54
- * Return a sentence-formatted line-comment group.
55
- *
56
- * @param {object} sourceCode
57
- * The Oxlint source code object.
58
- * @param {object[]} comments
59
- * The adjacent line comments.
60
- *
61
- * @returns {object|null}
62
- * The first and last replacements, or null when no sentence needs work.
63
- */
64
- function formatLineCommentGroup(sourceCode, comments) {
65
- // The group's first comment token.
66
- const firstComment = comments[0];
67
- // The group's last comment token.
68
- const lastComment = comments.at(-1);
69
- // The first comment's undecorated text.
70
- const firstText = firstComment.value.trim();
71
-
72
- if (firstText === "" || firstText.startsWith("@")) {
73
- return null;
74
- }
75
-
76
- // The first comment's value, capitalised or fully sentence-formatted.
77
- const firstValue =
78
- comments.length === 1
79
- ? formatSentence(firstComment.value)
80
- : capitaliseSentence(firstComment.value);
81
-
82
- // The last comment's value, punctuated to close the sentence.
83
- const lastValue = comments.length === 1 ? firstValue : addTerminalPunctuation(lastComment.value);
84
- // The replacement comment text for the first and last comments.
85
- const firstReplacement = replaceLineCommentValue(sourceCode, firstComment, firstValue);
86
- // The replacement comment text for the last comment.
87
- const lastReplacement = replaceLineCommentValue(sourceCode, lastComment, lastValue);
88
-
89
- if (
90
- firstReplacement === getCommentText(sourceCode, firstComment) &&
91
- lastReplacement === getCommentText(sourceCode, lastComment)
92
- ) {
93
- return null;
94
- }
95
-
96
- return { firstComment, firstReplacement, lastComment, lastReplacement };
97
- }
98
-
99
- /**
100
- * Format prose in an ordinary block comment.
101
- *
102
- * @param {object} sourceCode
103
- * The Oxlint source code object.
104
- * @param {object} comment
105
- * The block comment token.
106
- *
107
- * @returns {string}
108
- * The sentence-formatted comment text.
109
- */
110
- function formatOrdinaryBlockComment(sourceCode, comment) {
111
- // The comment's raw source text.
112
- const commentText = getCommentText(sourceCode, comment);
113
- // The indentation the comment's lines are aligned to.
114
- const indentation = getLineIndent(sourceCode, comment.range[0]);
115
- // The comment body, stripped of its /* */ delimiters.
116
- const content = commentText.slice(2, -2).trim();
117
-
118
- if (indentation === null || content === "" || /^(?:eslint|oxlint|istanbul|c8)-/.test(content)) {
119
- return commentText;
120
- }
121
-
122
- if (!commentText.includes("\n") && !commentText.includes("\r")) {
123
- return `/* ${formatSentence(content)} */`;
124
- }
125
-
126
- // The comment's individual source lines.
127
- const lines = commentText.split(/\r\n|\n|\r/);
128
-
129
- // The indexes of lines carrying prose, excluding the delimiter lines.
130
- const proseLineIndexes = lines
131
- .slice(1, -1)
132
- .map((line, index) => ({ index: index + 1, text: line.replace(/^\s*\*?\s?/, "").trim() }))
133
- .filter((line) => line.text !== "")
134
- .map((line) => line.index);
135
-
136
- if (lines[0] === "/*" && lines.at(-1).trim() === "*/" && proseLineIndexes.length > 0) {
137
- // The comment lines, formatted in place.
138
- const formattedLines = [...lines];
139
- // The first and last prose line indexes, which start and end the sentence.
140
- const firstProseLine = proseLineIndexes[0];
141
- // The last prose line index, which ends the sentence.
142
- const lastProseLine = proseLineIndexes.at(-1);
143
-
144
- formattedLines[firstProseLine] = formatBlockCommentLine(
145
- formattedLines[firstProseLine],
146
- capitaliseSentence,
147
- );
148
- formattedLines[lastProseLine] = formatBlockCommentLine(
149
- formattedLines[lastProseLine],
150
- addTerminalPunctuation,
151
- );
152
-
153
- return formattedLines.join(getNewline(sourceCode.text));
154
- }
155
-
156
- // The comment's prose, joined into a single paragraph.
157
- const paragraphs = content
158
- .split(/\r\n|\n|\r/)
159
- .map((line) => line.replace(/^\s*\*?\s?/, "").trim())
160
- .filter(Boolean)
161
- .join(" ");
162
-
163
- return ["/*", `${indentation} * ${formatSentence(paragraphs)}`, `${indentation} */`].join(
164
- getNewline(sourceCode.text),
165
- );
166
- }
167
-
168
- /**
169
- * Create the complete-sentence comment rule.
170
- *
171
- * @returns {object}
172
- * The Oxlint rule definition.
173
- */
174
- export default {
175
- meta: {
176
- docs: { description: "Format existing comments as complete sentences." },
177
- fixable: "code",
178
- type: "layout",
179
- },
180
- /**
181
- * Create the rule's node visitors.
182
- *
183
- * @param {object} context
184
- * The Oxlint rule context.
185
- *
186
- * @returns {object}
187
- * The visitor functions for this rule.
188
- */
189
- createOnce(context) {
190
- return {
191
- /**
192
- * Format every comment in the file as a complete sentence.
193
- */
194
- Program() {
195
- for (const commentGroup of getLineCommentGroups(context.sourceCode)) {
196
- // The group's replacement text, or null when it already reads as a sentence.
197
- const formattedGroup = formatLineCommentGroup(context.sourceCode, commentGroup);
198
-
199
- if (formattedGroup) {
200
- context.report({
201
- /**
202
- * Apply the formatted replacement to the comment group.
203
- *
204
- * @param {object} fixer
205
- * The Oxlint fixer.
206
- *
207
- * @returns {object[]}
208
- * The fixes to apply.
209
- */
210
- fix: (fixer) => {
211
- // The fixes to apply, starting with the first comment's replacement.
212
- const fixes = [
213
- replaceMinimalComment(
214
- fixer,
215
- formattedGroup.firstComment,
216
- getCommentText(context.sourceCode, formattedGroup.firstComment),
217
- formattedGroup.firstReplacement,
218
- ),
219
- ];
220
-
221
- if (formattedGroup.lastComment.range[0] !== formattedGroup.firstComment.range[0]) {
222
- fixes.push(
223
- replaceMinimalComment(
224
- fixer,
225
- formattedGroup.lastComment,
226
- getCommentText(context.sourceCode, formattedGroup.lastComment),
227
- formattedGroup.lastReplacement,
228
- ),
229
- );
230
- }
231
-
232
- return fixes;
233
- },
234
- message: "Comment text must be a complete sentence.",
235
- node: formattedGroup.firstComment,
236
- });
237
- }
238
- }
239
-
240
- for (const comment of context.sourceCode.getAllComments()) {
241
- if (comment.type !== "Block") {
242
- continue;
243
- }
244
-
245
- // The comment's raw source text.
246
- const commentText = getCommentText(context.sourceCode, comment);
247
-
248
- // The comment, sentence-formatted using the JSDoc or ordinary-block formatter.
249
- const formattedComment = isJSDoc(commentText)
250
- ? formatJSDocPunctuation(context.sourceCode, comment)
251
- : formatOrdinaryBlockComment(context.sourceCode, comment);
252
-
253
- if (formattedComment !== commentText) {
254
- context.report({
255
- /**
256
- * Apply the sentence-formatted replacement to the comment.
257
- *
258
- * @param {object} fixer
259
- * The Oxlint fixer.
260
- *
261
- * @returns {object}
262
- * The fix to apply.
263
- */
264
- fix: (fixer) => {
265
- return replaceMinimalComment(fixer, comment, commentText, formattedComment);
266
- },
267
- message: "Comment text must be a complete sentence.",
268
- node: comment,
269
- });
270
- }
271
- }
272
- },
273
- };
274
- },
275
- };