@tai-kun/vp-lint-plugins 0.0.0 → 0.0.2
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 +1 -43
- package/dist/src/index.d.ts +22 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +21 -0
- package/dist/src/plugin.d.ts +3 -0
- package/dist/src/plugin.d.ts.map +1 -0
- package/dist/src/plugin.js +46 -0
- package/dist/src/rules/blank-line-after-control-block.d.ts +7 -0
- package/dist/src/rules/blank-line-after-control-block.d.ts.map +1 -0
- package/dist/src/rules/blank-line-after-control-block.js +54 -0
- package/dist/src/rules/blank-line-after-declaration.d.ts +7 -0
- package/dist/src/rules/blank-line-after-declaration.d.ts.map +1 -0
- package/dist/src/rules/blank-line-after-declaration.js +79 -0
- package/dist/src/rules/blank-line-after-variable-declaration.d.ts +9 -0
- package/dist/src/rules/blank-line-after-variable-declaration.d.ts.map +1 -0
- package/dist/src/rules/blank-line-after-variable-declaration.js +118 -0
- package/dist/src/rules/blank-line-before-return.d.ts +7 -0
- package/dist/src/rules/blank-line-before-return.d.ts.map +1 -0
- package/dist/src/rules/blank-line-before-return.js +81 -0
- package/dist/src/rules/blank-line-between-class-members.d.ts +8 -0
- package/dist/src/rules/blank-line-between-class-members.d.ts.map +1 -0
- package/dist/src/rules/blank-line-between-class-members.js +85 -0
- package/dist/src/rules/blank-line-between-switch-cases.d.ts +8 -0
- package/dist/src/rules/blank-line-between-switch-cases.d.ts.map +1 -0
- package/dist/src/rules/blank-line-between-switch-cases.js +45 -0
- package/dist/src/rules/blank-line.d.ts +18 -0
- package/dist/src/rules/blank-line.d.ts.map +1 -0
- package/dist/src/rules/blank-line.js +86 -0
- package/dist/src/rules/comment-japanese-spacing.d.ts +8 -0
- package/dist/src/rules/comment-japanese-spacing.d.ts.map +1 -0
- package/dist/src/rules/comment-japanese-spacing.js +195 -0
- package/dist/src/rules/comment-one-sentence-per-line.d.ts +9 -0
- package/dist/src/rules/comment-one-sentence-per-line.d.ts.map +1 -0
- package/dist/src/rules/comment-one-sentence-per-line.js +190 -0
- package/dist/src/rules/comment-utils.d.ts +30 -0
- package/dist/src/rules/comment-utils.d.ts.map +1 -0
- package/dist/src/rules/comment-utils.js +153 -0
- package/dist/src/rules/jsdoc-param-order.d.ts +6 -0
- package/dist/src/rules/jsdoc-param-order.d.ts.map +1 -0
- package/dist/src/rules/jsdoc-param-order.js +101 -0
- package/dist/src/rules/jsdoc-tag-lines.d.ts +6 -0
- package/dist/src/rules/jsdoc-tag-lines.d.ts.map +1 -0
- package/dist/src/rules/jsdoc-tag-lines.js +128 -0
- package/dist/src/rules/jsdoc-tag-order.d.ts +6 -0
- package/dist/src/rules/jsdoc-tag-order.d.ts.map +1 -0
- package/dist/src/rules/jsdoc-tag-order.js +62 -0
- package/dist/src/rules/jsdoc-utils.d.ts +26 -0
- package/dist/src/rules/jsdoc-utils.d.ts.map +1 -0
- package/dist/src/rules/jsdoc-utils.js +132 -0
- package/dist/src/rules/member-ordering.d.ts +6 -0
- package/dist/src/rules/member-ordering.d.ts.map +1 -0
- package/dist/src/rules/member-ordering.js +66 -0
- package/dist/src/rules/object-properties-newline.d.ts +9 -0
- package/dist/src/rules/object-properties-newline.d.ts.map +1 -0
- package/dist/src/rules/object-properties-newline.js +47 -0
- package/dist/src/rules/object-sort-utils.d.ts +32 -0
- package/dist/src/rules/object-sort-utils.d.ts.map +1 -0
- package/dist/src/rules/object-sort-utils.js +221 -0
- package/dist/src/rules/overload-signatures-adjacent.d.ts +6 -0
- package/dist/src/rules/overload-signatures-adjacent.d.ts.map +1 -0
- package/dist/src/rules/overload-signatures-adjacent.js +128 -0
- package/dist/src/rules/sort-import-export-specifiers.d.ts +8 -0
- package/dist/src/rules/sort-import-export-specifiers.d.ts.map +1 -0
- package/dist/src/rules/sort-import-export-specifiers.js +130 -0
- package/dist/src/rules/sort-jsx-props.d.ts +7 -0
- package/dist/src/rules/sort-jsx-props.d.ts.map +1 -0
- package/dist/src/rules/sort-jsx-props.js +102 -0
- package/dist/src/rules/sort-object-properties.d.ts +9 -0
- package/dist/src/rules/sort-object-properties.d.ts.map +1 -0
- package/dist/src/rules/sort-object-properties.js +54 -0
- package/dist/src/rules/sort-type-members.d.ts +8 -0
- package/dist/src/rules/sort-type-members.d.ts.map +1 -0
- package/dist/src/rules/sort-type-members.js +213 -0
- package/dist/src/rules/spaced-comment.d.ts +6 -0
- package/dist/src/rules/spaced-comment.d.ts.map +1 -0
- package/dist/src/rules/spaced-comment.js +105 -0
- package/dist/src/rules/type-literal-properties-newline.d.ts +8 -0
- package/dist/src/rules/type-literal-properties-newline.d.ts.map +1 -0
- package/dist/src/rules/type-literal-properties-newline.js +39 -0
- package/package.json +40 -8
- package/src/index.ts +22 -0
- package/src/plugin.ts +48 -0
- package/src/rules/blank-line-after-control-block.ts +82 -0
- package/src/rules/blank-line-after-declaration.ts +106 -0
- package/src/rules/blank-line-after-variable-declaration.ts +165 -0
- package/src/rules/blank-line-before-return.ts +101 -0
- package/src/rules/blank-line-between-class-members.ts +112 -0
- package/src/rules/blank-line-between-switch-cases.ts +53 -0
- package/src/rules/blank-line.ts +143 -0
- package/src/rules/comment-japanese-spacing.ts +271 -0
- package/src/rules/comment-one-sentence-per-line.ts +263 -0
- package/src/rules/comment-utils.ts +218 -0
- package/src/rules/jsdoc-param-order.ts +137 -0
- package/src/rules/jsdoc-tag-lines.ts +165 -0
- package/src/rules/jsdoc-tag-order.ts +75 -0
- package/src/rules/jsdoc-utils.ts +178 -0
- package/src/rules/member-ordering.ts +93 -0
- package/src/rules/object-properties-newline.ts +54 -0
- package/src/rules/object-sort-utils.ts +338 -0
- package/src/rules/overload-signatures-adjacent.ts +178 -0
- package/src/rules/sort-import-export-specifiers.ts +194 -0
- package/src/rules/sort-jsx-props.ts +148 -0
- package/src/rules/sort-object-properties.ts +62 -0
- package/src/rules/sort-type-members.ts +299 -0
- package/src/rules/spaced-comment.ts +127 -0
- package/src/rules/type-literal-properties-newline.ts +44 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { defineRule } from "vite-plus/lint/plugins";
|
|
2
|
+
import type { Fix, ESTree, Comment, SourceCode } from "vite-plus/lint/plugins";
|
|
3
|
+
|
|
4
|
+
import { compareNames } from "./object-sort-utils.js";
|
|
5
|
+
|
|
6
|
+
interface MemberUnit {
|
|
7
|
+
endLine: number;
|
|
8
|
+
endOffset: number;
|
|
9
|
+
name: string | null;
|
|
10
|
+
startLine: number;
|
|
11
|
+
startOffset: number;
|
|
12
|
+
text: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface SortEdit {
|
|
16
|
+
end: number;
|
|
17
|
+
start: number;
|
|
18
|
+
text: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type NamedUnit = MemberUnit & { name: string };
|
|
22
|
+
|
|
23
|
+
function getLineStarts(text: string): number[] {
|
|
24
|
+
const starts = [0];
|
|
25
|
+
|
|
26
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
27
|
+
if (text[index] === "\n") {
|
|
28
|
+
starts.push(index + 1);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return starts;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getMemberName(member: ESTree.TSSignature): string | null {
|
|
36
|
+
if (member.type !== "TSPropertySignature" && member.type !== "TSMethodSignature") {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (member.computed) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const key = member.key;
|
|
45
|
+
|
|
46
|
+
if (key.type === "Identifier") {
|
|
47
|
+
return key.name;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (key.type === "Literal" && (typeof key.value === "string" || typeof key.value === "number")) {
|
|
51
|
+
return String(key.value);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getUnits(node: ESTree.TSTypeLiteral, sourceCode: SourceCode): MemberUnit[] | null {
|
|
58
|
+
const source = sourceCode.text;
|
|
59
|
+
const lineStarts = getLineStarts(source);
|
|
60
|
+
const comments = sourceCode
|
|
61
|
+
.getAllComments()
|
|
62
|
+
.filter((comment) => comment.range[0] >= node.range[0] && comment.range[1] <= node.range[1]);
|
|
63
|
+
const units: MemberUnit[] = [];
|
|
64
|
+
let previousEnd = node.range[0] + 1;
|
|
65
|
+
|
|
66
|
+
for (const [index, member] of node.members.entries()) {
|
|
67
|
+
const previousMember = node.members[index - 1];
|
|
68
|
+
const candidates = comments.filter(
|
|
69
|
+
(comment) => comment.range[0] >= previousEnd && comment.range[1] <= member.range[0],
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
if (
|
|
73
|
+
previousMember !== undefined &&
|
|
74
|
+
candidates.some((comment) => comment.loc.start.line === previousMember.loc.end.line)
|
|
75
|
+
) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const attached: Comment[] = [];
|
|
80
|
+
let expectedLine = member.loc.start.line;
|
|
81
|
+
|
|
82
|
+
for (let commentIndex = candidates.length - 1; commentIndex >= 0; commentIndex -= 1) {
|
|
83
|
+
const comment = candidates[commentIndex];
|
|
84
|
+
|
|
85
|
+
if (comment === undefined) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (comment.loc.end.line !== expectedLine && comment.loc.end.line !== expectedLine - 1) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (comment.loc.start.line === expectedLine) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (comment.loc.start.line === node.loc.start.line) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
attached.unshift(comment);
|
|
102
|
+
expectedLine = comment.loc.start.line;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (attached.length !== candidates.length) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const first = attached[0] ?? member;
|
|
110
|
+
const startLine = first.loc.start.line;
|
|
111
|
+
let startOffset: number;
|
|
112
|
+
|
|
113
|
+
if (attached.length > 0) {
|
|
114
|
+
startOffset = lineStarts[startLine - 1] ?? first.range[0];
|
|
115
|
+
} else if (startLine === node.loc.start.line) {
|
|
116
|
+
startOffset = member.range[0];
|
|
117
|
+
} else {
|
|
118
|
+
startOffset = lineStarts[startLine - 1] ?? member.range[0];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let endOffset = member.range[1];
|
|
122
|
+
|
|
123
|
+
while (endOffset > member.range[0]) {
|
|
124
|
+
const character = source[endOffset - 1];
|
|
125
|
+
|
|
126
|
+
if (character !== ";" && character !== ",") {
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
endOffset -= 1;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
units.push({
|
|
134
|
+
name: getMemberName(member),
|
|
135
|
+
text: source.slice(startOffset, endOffset),
|
|
136
|
+
endLine: member.loc.end.line,
|
|
137
|
+
endOffset,
|
|
138
|
+
startLine,
|
|
139
|
+
startOffset,
|
|
140
|
+
});
|
|
141
|
+
previousEnd = member.range[1];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (
|
|
145
|
+
comments.some(
|
|
146
|
+
(comment) => comment.range[0] >= previousEnd && comment.range[1] <= node.range[1] - 1,
|
|
147
|
+
)
|
|
148
|
+
) {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return units;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function splitGroups(units: readonly MemberUnit[]): MemberUnit[][] {
|
|
156
|
+
const groups: MemberUnit[][] = [];
|
|
157
|
+
let current: MemberUnit[] = [];
|
|
158
|
+
let previousEndLine: number | null = null;
|
|
159
|
+
|
|
160
|
+
for (const unit of units) {
|
|
161
|
+
if (previousEndLine !== null && unit.startLine > previousEndLine + 1) {
|
|
162
|
+
groups.push(current);
|
|
163
|
+
current = [];
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
current.push(unit);
|
|
167
|
+
previousEndLine = unit.endLine;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (current.length > 0) {
|
|
171
|
+
groups.push(current);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return groups;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function sortGroup(group: readonly MemberUnit[]): MemberUnit[] {
|
|
178
|
+
const sortable = group.filter((unit): unit is NamedUnit => unit.name !== null);
|
|
179
|
+
sortable.sort((left, right) => compareNames(left.name, right.name));
|
|
180
|
+
|
|
181
|
+
const rest = group.filter((unit) => unit.name === null);
|
|
182
|
+
|
|
183
|
+
return [...sortable, ...rest];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function getSortEdits(units: readonly MemberUnit[]): SortEdit[] {
|
|
187
|
+
const edits: SortEdit[] = [];
|
|
188
|
+
let runStart = 0;
|
|
189
|
+
|
|
190
|
+
while (runStart < units.length) {
|
|
191
|
+
if (units[runStart]?.name === null) {
|
|
192
|
+
runStart += 1;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
let runEnd = runStart;
|
|
197
|
+
|
|
198
|
+
while (runEnd < units.length && units[runEnd]?.name !== null) {
|
|
199
|
+
runEnd += 1;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const run = units.slice(runStart, runEnd);
|
|
203
|
+
|
|
204
|
+
if (run.length >= 2) {
|
|
205
|
+
const names = new Set<string>();
|
|
206
|
+
let hasDuplicate = false;
|
|
207
|
+
|
|
208
|
+
for (const unit of run) {
|
|
209
|
+
if (unit.name === null) {
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (names.has(unit.name)) {
|
|
214
|
+
hasDuplicate = true;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
names.add(unit.name);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (!hasDuplicate) {
|
|
222
|
+
const groups = splitGroups(run);
|
|
223
|
+
const sortedGroups = groups.map(sortGroup);
|
|
224
|
+
const changed = sortedGroups.some((group, groupIndex) =>
|
|
225
|
+
group.some((unit, unitIndex) => unit !== groups[groupIndex]?.[unitIndex]),
|
|
226
|
+
);
|
|
227
|
+
const firstUnit = run[0];
|
|
228
|
+
const lastUnit = run.at(-1);
|
|
229
|
+
|
|
230
|
+
if (changed && firstUnit !== undefined && lastUnit !== undefined) {
|
|
231
|
+
edits.push({
|
|
232
|
+
end: lastUnit.endOffset,
|
|
233
|
+
text: sortedGroups
|
|
234
|
+
.map((group) => group.map((unit) => unit.text).join(";\n"))
|
|
235
|
+
.join(";\n\n"),
|
|
236
|
+
start: firstUnit.startOffset,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
runStart = runEnd;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return edits;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* 型リテラルのメンバーを、名前の長さが短い順、同じ長さなら名前順に並べます。
|
|
250
|
+
*
|
|
251
|
+
* `interface` は対象外です。
|
|
252
|
+
*/
|
|
253
|
+
const sortTypeMembers = defineRule({
|
|
254
|
+
meta: {
|
|
255
|
+
docs: {
|
|
256
|
+
description: "Sort type literal members by name length and name.",
|
|
257
|
+
},
|
|
258
|
+
type: "layout",
|
|
259
|
+
fixable: "whitespace",
|
|
260
|
+
messages: {
|
|
261
|
+
sort: "Type members must be sorted by name length, then by name.",
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
create(context) {
|
|
265
|
+
const sourceCode = context.sourceCode;
|
|
266
|
+
|
|
267
|
+
return {
|
|
268
|
+
TSTypeLiteral(node): void {
|
|
269
|
+
const units = getUnits(node, sourceCode);
|
|
270
|
+
|
|
271
|
+
if (units === null) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const edits = getSortEdits(units);
|
|
276
|
+
|
|
277
|
+
if (edits.length === 0) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
context.report({
|
|
282
|
+
fix(fixer) {
|
|
283
|
+
const fixes: Fix[] = [];
|
|
284
|
+
|
|
285
|
+
for (const edit of edits) {
|
|
286
|
+
fixes.push(fixer.replaceTextRange([edit.start, edit.end], edit.text));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return fixes;
|
|
290
|
+
},
|
|
291
|
+
node,
|
|
292
|
+
messageId: "sort",
|
|
293
|
+
});
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
export default sortTypeMembers;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { defineRule } from "vite-plus/lint/plugins";
|
|
2
|
+
import type { Fix, Comment } from "vite-plus/lint/plugins";
|
|
3
|
+
|
|
4
|
+
const DECORATIVE_LINE = /^[-=*#_~+]{3,}$/u;
|
|
5
|
+
|
|
6
|
+
function isWhitespace(char: string | undefined): boolean {
|
|
7
|
+
return char === " " || char === "\t";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function isExemptLineComment(raw: string): boolean {
|
|
11
|
+
if (raw.startsWith("///") || raw.startsWith("//!") || raw.startsWith("//@")) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (raw.startsWith("//#")) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return DECORATIVE_LINE.test(raw.slice(2));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isExemptBlockComment(raw: string): boolean {
|
|
23
|
+
return raw.startsWith("/*!");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* コメントの開始記号の直後と終了記号の直前に空白を要求します。
|
|
28
|
+
*/
|
|
29
|
+
const spacedComment = defineRule({
|
|
30
|
+
meta: {
|
|
31
|
+
docs: {
|
|
32
|
+
description: "Require whitespace after the comment marker and before the closing marker.",
|
|
33
|
+
},
|
|
34
|
+
type: "layout",
|
|
35
|
+
fixable: "whitespace",
|
|
36
|
+
messages: {
|
|
37
|
+
missingLeadingSpace: "Expected a whitespace after the comment marker.",
|
|
38
|
+
missingTrailingSpace: "Expected a whitespace before the closing comment marker.",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
create(context) {
|
|
42
|
+
const sourceCode = context.sourceCode;
|
|
43
|
+
|
|
44
|
+
function checkLineComment(comment: Comment, raw: string): void {
|
|
45
|
+
if (isExemptLineComment(raw) || isWhitespace(raw[2]) || raw.length === 2) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
context.report({
|
|
50
|
+
fix(fixer) {
|
|
51
|
+
return fixer.insertTextAfterRange([comment.range[0], comment.range[0] + 2], " ");
|
|
52
|
+
},
|
|
53
|
+
loc: comment.loc,
|
|
54
|
+
messageId: "missingLeadingSpace",
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function checkBlockComment(comment: Comment, raw: string): void {
|
|
59
|
+
if (isExemptBlockComment(raw)) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const prefixLength = raw.startsWith("/**") ? 3 : 2;
|
|
64
|
+
const firstLineEnd = raw.indexOf("\n");
|
|
65
|
+
const lastLineStart = raw.lastIndexOf("\n") + 1;
|
|
66
|
+
let needsLeading: boolean;
|
|
67
|
+
let needsTrailing: boolean;
|
|
68
|
+
|
|
69
|
+
if (firstLineEnd === -1) {
|
|
70
|
+
const contentStart = prefixLength;
|
|
71
|
+
const contentEnd = raw.lastIndexOf("*/");
|
|
72
|
+
const content = raw.slice(contentStart, contentEnd);
|
|
73
|
+
needsLeading = content !== "" && !isWhitespace(content[0]);
|
|
74
|
+
needsTrailing = content !== "" && !isWhitespace(content.at(-1));
|
|
75
|
+
} else {
|
|
76
|
+
const firstLine = raw.slice(0, firstLineEnd);
|
|
77
|
+
const lastLine = raw.slice(lastLineStart);
|
|
78
|
+
const leadingContent = firstLine.slice(prefixLength);
|
|
79
|
+
const closeIndex = lastLine.lastIndexOf("*/");
|
|
80
|
+
const trailingContent = lastLine.slice(0, closeIndex);
|
|
81
|
+
needsLeading = leadingContent !== "" && !isWhitespace(leadingContent[0]);
|
|
82
|
+
needsTrailing = trailingContent !== "" && !isWhitespace(trailingContent.at(-1));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (!needsLeading && !needsTrailing) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
context.report({
|
|
90
|
+
fix(fixer) {
|
|
91
|
+
const fixes: Fix[] = [];
|
|
92
|
+
|
|
93
|
+
if (needsLeading) {
|
|
94
|
+
fixes.push(
|
|
95
|
+
fixer.insertTextAfterRange([comment.range[0], comment.range[0] + prefixLength], " "),
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (needsTrailing) {
|
|
100
|
+
fixes.push(fixer.insertTextBeforeRange([comment.range[1] - 2, comment.range[1]], " "));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return fixes;
|
|
104
|
+
},
|
|
105
|
+
loc: comment.loc,
|
|
106
|
+
messageId: needsLeading ? "missingLeadingSpace" : "missingTrailingSpace",
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
Program(): void {
|
|
112
|
+
for (const comment of sourceCode.getAllComments()) {
|
|
113
|
+
if (comment.type === "Line") {
|
|
114
|
+
checkLineComment(comment, sourceCode.getText(comment));
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (comment.type === "Block") {
|
|
119
|
+
checkBlockComment(comment, sourceCode.getText(comment));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
export default spacedComment;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { defineRule } from "vite-plus/lint/plugins";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* メンバーが 2 つ以上ある型リテラルを複数行にします。
|
|
5
|
+
*
|
|
6
|
+
* Oxfmt の `objectWrap` はオブジェクトリテラル用のため、型リテラルは `{` の直後の改行を目印に複数行を維持します。
|
|
7
|
+
*/
|
|
8
|
+
const typeLiteralPropertiesNewline = defineRule({
|
|
9
|
+
meta: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: "Enforce multiline type literals when they have two or more members.",
|
|
12
|
+
},
|
|
13
|
+
type: "layout",
|
|
14
|
+
fixable: "whitespace",
|
|
15
|
+
messages: {
|
|
16
|
+
multiline: "Type literals with 2 or more members must be multiline.",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
create(context) {
|
|
20
|
+
return {
|
|
21
|
+
TSTypeLiteral(node): void {
|
|
22
|
+
if (node.members.length < 2) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const firstMember = node.members[0];
|
|
27
|
+
|
|
28
|
+
if (firstMember === undefined || firstMember.loc.start.line !== node.loc.start.line) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
context.report({
|
|
33
|
+
fix(fixer) {
|
|
34
|
+
return fixer.insertTextAfterRange([node.range[0], node.range[0] + 1], "\n");
|
|
35
|
+
},
|
|
36
|
+
node,
|
|
37
|
+
messageId: "multiline",
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export default typeLiteralPropertiesNewline;
|