@tai-kun/vp-lint-plugins 0.0.3 → 0.0.5
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/dist/src/index.d.ts +2 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -6
- package/dist/src/plugin.js +4 -12
- package/dist/src/rules/blank-line-utils.d.ts +30 -0
- package/dist/src/rules/blank-line-utils.d.ts.map +1 -0
- package/dist/src/rules/blank-line-utils.js +103 -0
- package/dist/src/rules/blank-line.d.ts +5 -14
- package/dist/src/rules/blank-line.d.ts.map +1 -1
- package/dist/src/rules/blank-line.js +426 -66
- package/dist/src/rules/merge-imports.d.ts +8 -0
- package/dist/src/rules/merge-imports.d.ts.map +1 -0
- package/dist/src/rules/merge-imports.js +199 -0
- package/dist/src/rules/overload-signatures-adjacent.js +1 -1
- package/package.json +1 -1
- package/src/index.ts +2 -6
- package/src/plugin.ts +4 -12
- package/src/rules/blank-line-utils.ts +165 -0
- package/src/rules/blank-line.ts +555 -97
- package/src/rules/merge-imports.ts +301 -0
- package/src/rules/overload-signatures-adjacent.ts +1 -1
- package/dist/src/rules/blank-line-after-control-block.d.ts +0 -7
- package/dist/src/rules/blank-line-after-control-block.d.ts.map +0 -1
- package/dist/src/rules/blank-line-after-control-block.js +0 -54
- package/dist/src/rules/blank-line-after-declaration.d.ts +0 -7
- package/dist/src/rules/blank-line-after-declaration.d.ts.map +0 -1
- package/dist/src/rules/blank-line-after-declaration.js +0 -79
- package/dist/src/rules/blank-line-after-variable-declaration.d.ts +0 -9
- package/dist/src/rules/blank-line-after-variable-declaration.d.ts.map +0 -1
- package/dist/src/rules/blank-line-after-variable-declaration.js +0 -118
- package/dist/src/rules/blank-line-before-return.d.ts +0 -7
- package/dist/src/rules/blank-line-before-return.d.ts.map +0 -1
- package/dist/src/rules/blank-line-before-return.js +0 -81
- package/dist/src/rules/blank-line-between-class-members.d.ts +0 -8
- package/dist/src/rules/blank-line-between-class-members.d.ts.map +0 -1
- package/dist/src/rules/blank-line-between-class-members.js +0 -85
- package/dist/src/rules/blank-line-between-switch-cases.d.ts +0 -8
- package/dist/src/rules/blank-line-between-switch-cases.d.ts.map +0 -1
- package/dist/src/rules/blank-line-between-switch-cases.js +0 -45
- package/src/rules/blank-line-after-control-block.ts +0 -82
- package/src/rules/blank-line-after-declaration.ts +0 -106
- package/src/rules/blank-line-after-variable-declaration.ts +0 -165
- package/src/rules/blank-line-before-return.ts +0 -101
- package/src/rules/blank-line-between-class-members.ts +0 -112
- package/src/rules/blank-line-between-switch-cases.ts +0 -53
|
@@ -1,86 +1,446 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { defineRule } from "vite-plus/lint/plugins";
|
|
2
|
+
import { isComment, hasBlankLine, isDocComment, getBlankLineFix, getInsertionTarget, getRemoveBlankLineFix, } from "./blank-line-utils.js";
|
|
3
|
+
const CONTROL_STATEMENT_TYPES = new Set([
|
|
4
|
+
"DoWhileStatement",
|
|
5
|
+
"ForInStatement",
|
|
6
|
+
"ForOfStatement",
|
|
7
|
+
"ForStatement",
|
|
8
|
+
"IfStatement",
|
|
9
|
+
"SwitchStatement",
|
|
10
|
+
"TryStatement",
|
|
11
|
+
"WhileStatement",
|
|
12
|
+
]);
|
|
13
|
+
const DECLARATION_TYPES = new Set([
|
|
14
|
+
"ClassDeclaration",
|
|
15
|
+
"FunctionDeclaration",
|
|
16
|
+
"TSDeclareFunction",
|
|
17
|
+
"TSEnumDeclaration",
|
|
18
|
+
"TSInterfaceDeclaration",
|
|
19
|
+
"TSModuleDeclaration",
|
|
20
|
+
"TSTypeAliasDeclaration",
|
|
21
|
+
]);
|
|
22
|
+
const SKIP_RETURN_PREVIOUS_TYPES = new Set([
|
|
23
|
+
// 制御ブロックの後は afterControlBlock が担当するため、ここでは判定しません。
|
|
24
|
+
"DoWhileStatement",
|
|
25
|
+
"ForInStatement",
|
|
26
|
+
"ForOfStatement",
|
|
27
|
+
"ForStatement",
|
|
28
|
+
"IfStatement",
|
|
29
|
+
"SwitchStatement",
|
|
30
|
+
"TryStatement",
|
|
31
|
+
"WhileStatement",
|
|
32
|
+
// 宣言の後は afterDeclaration が担当するため、ここでは判定しません。
|
|
33
|
+
"ClassDeclaration",
|
|
34
|
+
"ExportAllDeclaration",
|
|
35
|
+
"ExportDefaultDeclaration",
|
|
36
|
+
"ExportNamedDeclaration",
|
|
37
|
+
"FunctionDeclaration",
|
|
38
|
+
"ImportDeclaration",
|
|
39
|
+
"TSDeclareFunction",
|
|
40
|
+
"TSEnumDeclaration",
|
|
41
|
+
"TSInterfaceDeclaration",
|
|
42
|
+
"TSModuleDeclaration",
|
|
43
|
+
"TSTypeAliasDeclaration",
|
|
44
|
+
// 途中で終わる文や空文の後は対象外にします。
|
|
45
|
+
"BlockStatement",
|
|
46
|
+
"BreakStatement",
|
|
47
|
+
"ContinueStatement",
|
|
48
|
+
"DebuggerStatement",
|
|
49
|
+
"EmptyStatement",
|
|
50
|
+
"LabeledStatement",
|
|
51
|
+
"ReturnStatement",
|
|
52
|
+
"ThrowStatement",
|
|
53
|
+
"WithStatement",
|
|
54
|
+
]);
|
|
55
|
+
const DEFAULT_OPTIONS = {
|
|
56
|
+
beforeReturn: true,
|
|
57
|
+
afterDeclaration: true,
|
|
58
|
+
afterControlBlock: true,
|
|
59
|
+
betweenSwitchCases: true,
|
|
60
|
+
betweenTypeMembers: true,
|
|
61
|
+
betweenClassMembers: true,
|
|
62
|
+
afterVariableDeclaration: true,
|
|
63
|
+
};
|
|
64
|
+
function isObject(value) {
|
|
65
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
66
|
+
}
|
|
67
|
+
function getFlag(option, key) {
|
|
68
|
+
const value = option[key];
|
|
69
|
+
return value === undefined ? DEFAULT_OPTIONS[key] : value === true;
|
|
70
|
+
}
|
|
71
|
+
function getOptions(options) {
|
|
72
|
+
const option = options[0];
|
|
73
|
+
if (!isObject(option)) {
|
|
74
|
+
return { ...DEFAULT_OPTIONS };
|
|
8
75
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
76
|
+
return {
|
|
77
|
+
beforeReturn: getFlag(option, "beforeReturn"),
|
|
78
|
+
afterDeclaration: getFlag(option, "afterDeclaration"),
|
|
79
|
+
afterControlBlock: getFlag(option, "afterControlBlock"),
|
|
80
|
+
betweenSwitchCases: getFlag(option, "betweenSwitchCases"),
|
|
81
|
+
betweenTypeMembers: getFlag(option, "betweenTypeMembers"),
|
|
82
|
+
betweenClassMembers: getFlag(option, "betweenClassMembers"),
|
|
83
|
+
afterVariableDeclaration: getFlag(option, "afterVariableDeclaration"),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function isControlStatement(node) {
|
|
87
|
+
return CONTROL_STATEMENT_TYPES.has(node.type);
|
|
88
|
+
}
|
|
89
|
+
function getDeclaration(node) {
|
|
90
|
+
if (DECLARATION_TYPES.has(node.type)) {
|
|
91
|
+
return node;
|
|
14
92
|
}
|
|
15
|
-
if (
|
|
16
|
-
|
|
93
|
+
if ((node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration") &&
|
|
94
|
+
node.declaration !== null &&
|
|
95
|
+
DECLARATION_TYPES.has(node.declaration.type)) {
|
|
96
|
+
return node.declaration;
|
|
17
97
|
}
|
|
18
98
|
return null;
|
|
19
99
|
}
|
|
20
|
-
function
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
100
|
+
function isOverload(declaration) {
|
|
101
|
+
return ((declaration.type === "FunctionDeclaration" || declaration.type === "TSDeclareFunction") &&
|
|
102
|
+
declaration.body === null);
|
|
103
|
+
}
|
|
104
|
+
function getVariableDeclaration(node) {
|
|
105
|
+
if (node.type === "VariableDeclaration") {
|
|
106
|
+
return node;
|
|
24
107
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return null;
|
|
108
|
+
if (node.type === "ExportNamedDeclaration" && node.declaration?.type === "VariableDeclaration") {
|
|
109
|
+
return node.declaration;
|
|
28
110
|
}
|
|
29
|
-
return
|
|
111
|
+
return null;
|
|
30
112
|
}
|
|
31
|
-
function
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return null;
|
|
113
|
+
function isRelatedExpression(statement, variables) {
|
|
114
|
+
if (statement.type !== "ExpressionStatement") {
|
|
115
|
+
return false;
|
|
35
116
|
}
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
117
|
+
for (const variable of variables) {
|
|
118
|
+
for (const reference of variable.references) {
|
|
119
|
+
if (reference.identifier.range[0] >= statement.range[0] &&
|
|
120
|
+
reference.identifier.range[1] <= statement.range[1]) {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
39
124
|
}
|
|
40
|
-
return
|
|
125
|
+
return false;
|
|
41
126
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
*
|
|
45
|
-
* 次の文に付くコメントがある場合は、そのコメントの前を挿入位置にします。
|
|
46
|
-
* 同じ行の末尾コメントは対象外です。
|
|
47
|
-
*/
|
|
48
|
-
function getInsertionTarget(node, nextStatement, sourceCode) {
|
|
49
|
-
return (sourceCode
|
|
50
|
-
.getAllComments()
|
|
51
|
-
.find((comment) => comment.range[0] >= node.range[1] &&
|
|
52
|
-
comment.range[1] <= nextStatement.range[0] &&
|
|
53
|
-
comment.loc.start.line > node.loc.end.line) ?? nextStatement);
|
|
127
|
+
function isDirective(node) {
|
|
128
|
+
return node.type === "ExpressionStatement" && typeof node.directive === "string";
|
|
54
129
|
}
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
function getBlankLineFix(fixer, sourceCode, node, target) {
|
|
59
|
-
if (target.loc.start.line === node.loc.end.line) {
|
|
60
|
-
return fixer.insertTextAfterRange([node.range[1], node.range[1]], "\n\n");
|
|
130
|
+
function getKeyName(member) {
|
|
131
|
+
if (member.type === "TSIndexSignature" || member.type === "StaticBlock") {
|
|
132
|
+
return null;
|
|
61
133
|
}
|
|
62
|
-
|
|
63
|
-
if (lineEnd === -1) {
|
|
134
|
+
if (member.computed) {
|
|
64
135
|
return null;
|
|
65
136
|
}
|
|
66
|
-
|
|
137
|
+
const key = member.key;
|
|
138
|
+
if (key.type === "Identifier") {
|
|
139
|
+
return key.name;
|
|
140
|
+
}
|
|
141
|
+
if (key.type === "Literal" && (typeof key.value === "string" || typeof key.value === "number")) {
|
|
142
|
+
return String(key.value);
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
67
145
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
function
|
|
72
|
-
if (
|
|
73
|
-
return
|
|
146
|
+
function isOverloadMember(member) {
|
|
147
|
+
return member.type === "MethodDefinition" && member.value.body === null;
|
|
148
|
+
}
|
|
149
|
+
function isGetterSetterPair(previous, next) {
|
|
150
|
+
if (previous.type !== "MethodDefinition" || next.type !== "MethodDefinition") {
|
|
151
|
+
return false;
|
|
74
152
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return
|
|
153
|
+
if (!((previous.kind === "get" && next.kind === "set") ||
|
|
154
|
+
(previous.kind === "set" && next.kind === "get"))) {
|
|
155
|
+
return false;
|
|
78
156
|
}
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
157
|
+
const previousName = getKeyName(previous);
|
|
158
|
+
const nextName = getKeyName(next);
|
|
159
|
+
return previousName !== null && previousName === nextName;
|
|
160
|
+
}
|
|
161
|
+
function getMemberStart(member) {
|
|
162
|
+
if (member.type === "TSIndexSignature" || member.type === "StaticBlock") {
|
|
163
|
+
return member;
|
|
83
164
|
}
|
|
84
|
-
return
|
|
165
|
+
return member.decorators[0] ?? member;
|
|
85
166
|
}
|
|
86
|
-
|
|
167
|
+
/**
|
|
168
|
+
* 宣言・制御ブロック・変数宣言グループ・return・クラスや型のメンバー・switch の case における空行を、1 つのルールでまとめて扱います。
|
|
169
|
+
*
|
|
170
|
+
* 文の境界ごとに該当する項目を 1 つだけ判定するため、複数の診断が同じ箇所で矛盾しません。
|
|
171
|
+
* 行コメントや通常のブロックコメントを挟む場合、前後の空行は任意とします。
|
|
172
|
+
*/
|
|
173
|
+
const blankLine = defineRule({
|
|
174
|
+
meta: {
|
|
175
|
+
docs: {
|
|
176
|
+
description: "Require blank lines between statements, class members, and switch cases, and above JSDoc-style block comments.",
|
|
177
|
+
},
|
|
178
|
+
type: "layout",
|
|
179
|
+
schema: [
|
|
180
|
+
{
|
|
181
|
+
type: "object",
|
|
182
|
+
properties: {
|
|
183
|
+
beforeReturn: { type: "boolean" },
|
|
184
|
+
afterDeclaration: { type: "boolean" },
|
|
185
|
+
afterControlBlock: { type: "boolean" },
|
|
186
|
+
betweenSwitchCases: { type: "boolean" },
|
|
187
|
+
betweenTypeMembers: { type: "boolean" },
|
|
188
|
+
betweenClassMembers: { type: "boolean" },
|
|
189
|
+
afterVariableDeclaration: { type: "boolean" },
|
|
190
|
+
},
|
|
191
|
+
additionalProperties: false,
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
fixable: "whitespace",
|
|
195
|
+
messages: {
|
|
196
|
+
blankLine: "Expected a blank line here.",
|
|
197
|
+
unexpectedBlankLine: "Expected no blank line between a variable declaration and its related statement.",
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
create(context) {
|
|
201
|
+
const sourceCode = context.sourceCode;
|
|
202
|
+
const options = getOptions(context.options);
|
|
203
|
+
function requireBlankLine(previous, next, reportNode) {
|
|
204
|
+
const target = getInsertionTarget(previous, next, sourceCode);
|
|
205
|
+
// JSDoc 形式のブロックコメントの 1 行上は空行にします。
|
|
206
|
+
// それ以外のコメントを挟む場合、前後の空行は任意とします。
|
|
207
|
+
if (isComment(target) && !isDocComment(target)) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (hasBlankLine(previous, target)) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
context.report({
|
|
214
|
+
fix(fixer) {
|
|
215
|
+
return getBlankLineFix(fixer, sourceCode, previous, target);
|
|
216
|
+
},
|
|
217
|
+
node: reportNode,
|
|
218
|
+
messageId: "blankLine",
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* 変数宣言グループを収集します。
|
|
223
|
+
*
|
|
224
|
+
* 連続する変数宣言と、宣言した変数を使う式文を同じグループとして扱います。
|
|
225
|
+
* グループ開始でない場合は null を返します。
|
|
226
|
+
*/
|
|
227
|
+
function collectVariableGroup(body, start) {
|
|
228
|
+
const first = body[start];
|
|
229
|
+
if (first === undefined) {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
const firstDeclaration = getVariableDeclaration(first);
|
|
233
|
+
if (firstDeclaration === null) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
const variables = new Set(sourceCode.getDeclaredVariables(firstDeclaration));
|
|
237
|
+
const statements = [first];
|
|
238
|
+
let index = start + 1;
|
|
239
|
+
while (index < body.length) {
|
|
240
|
+
const next = body[index];
|
|
241
|
+
if (next === undefined) {
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
const nextDeclaration = getVariableDeclaration(next);
|
|
245
|
+
const lastStatement = statements.at(-1);
|
|
246
|
+
if (nextDeclaration !== null &&
|
|
247
|
+
lastStatement !== undefined &&
|
|
248
|
+
getVariableDeclaration(lastStatement) !== null) {
|
|
249
|
+
for (const variable of sourceCode.getDeclaredVariables(nextDeclaration)) {
|
|
250
|
+
variables.add(variable);
|
|
251
|
+
}
|
|
252
|
+
statements.push(next);
|
|
253
|
+
index += 1;
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
if (next.type === "ExpressionStatement" && isRelatedExpression(next, variables)) {
|
|
257
|
+
statements.push(next);
|
|
258
|
+
index += 1;
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
variables,
|
|
265
|
+
statements,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function checkVariableGroupBoundary(last, next) {
|
|
269
|
+
if (next === undefined || next.type === "EmptyStatement") {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (next.type === "ReturnStatement") {
|
|
273
|
+
if (options.beforeReturn) {
|
|
274
|
+
requireBlankLine(last, next, next);
|
|
275
|
+
}
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (options.afterVariableDeclaration) {
|
|
279
|
+
requireBlankLine(last, next, next);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
function checkStatementBody(body) {
|
|
283
|
+
let index = 0;
|
|
284
|
+
while (index < body.length) {
|
|
285
|
+
const group = options.afterVariableDeclaration || options.beforeReturn
|
|
286
|
+
? collectVariableGroup(body, index)
|
|
287
|
+
: null;
|
|
288
|
+
if (group !== null) {
|
|
289
|
+
if (options.afterVariableDeclaration) {
|
|
290
|
+
for (let offset = 0; offset < group.statements.length - 1; offset += 1) {
|
|
291
|
+
const previous = group.statements[offset];
|
|
292
|
+
const next = group.statements[offset + 1];
|
|
293
|
+
if (previous === undefined || next === undefined) {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
const target = getInsertionTarget(previous, next, sourceCode);
|
|
297
|
+
// JSDoc 形式のブロックコメントの 1 行上は空行にします。
|
|
298
|
+
if (isDocComment(target)) {
|
|
299
|
+
requireBlankLine(previous, next, next);
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
// 変数同士の境界は空行の有無を問いません。
|
|
303
|
+
if (next.type !== "ExpressionStatement") {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
if (isComment(target) || !hasBlankLine(previous, target)) {
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
context.report({
|
|
310
|
+
fix(fixer) {
|
|
311
|
+
return getRemoveBlankLineFix(fixer, sourceCode, previous, target);
|
|
312
|
+
},
|
|
313
|
+
node: next,
|
|
314
|
+
messageId: "unexpectedBlankLine",
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const last = group.statements.at(-1);
|
|
319
|
+
const next = body[index + group.statements.length];
|
|
320
|
+
if (last === undefined) {
|
|
321
|
+
index += group.statements.length;
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
checkVariableGroupBoundary(last, next);
|
|
325
|
+
index += group.statements.length;
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
const previous = body[index];
|
|
329
|
+
const next = body[index + 1];
|
|
330
|
+
if (previous === undefined || next === undefined || next.type === "EmptyStatement") {
|
|
331
|
+
index += 1;
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
if (isControlStatement(previous)) {
|
|
335
|
+
if (options.afterControlBlock) {
|
|
336
|
+
requireBlankLine(previous, next, previous);
|
|
337
|
+
}
|
|
338
|
+
index += 1;
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
const declaration = getDeclaration(previous);
|
|
342
|
+
if (declaration !== null) {
|
|
343
|
+
if (!isOverload(declaration) && options.afterDeclaration) {
|
|
344
|
+
requireBlankLine(previous, next, previous);
|
|
345
|
+
}
|
|
346
|
+
index += 1;
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
if (next.type === "ReturnStatement") {
|
|
350
|
+
if (options.beforeReturn &&
|
|
351
|
+
!SKIP_RETURN_PREVIOUS_TYPES.has(previous.type) &&
|
|
352
|
+
!isDirective(previous)) {
|
|
353
|
+
requireBlankLine(previous, next, next);
|
|
354
|
+
}
|
|
355
|
+
index += 1;
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
index += 1;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* 型や interface のメンバー境界を確認します。
|
|
363
|
+
*
|
|
364
|
+
* メンバー間の空行は要求せず、JSDoc 形式のブロックコメントの 1 行上だけ空行を要求します。
|
|
365
|
+
*/
|
|
366
|
+
function checkTypeMembers(members) {
|
|
367
|
+
for (let index = 1; index < members.length; index += 1) {
|
|
368
|
+
const previous = members[index - 1];
|
|
369
|
+
const next = members[index];
|
|
370
|
+
if (previous === undefined || next === undefined) {
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
const target = getInsertionTarget(previous, next, sourceCode);
|
|
374
|
+
if (!isDocComment(target) || hasBlankLine(previous, target)) {
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
context.report({
|
|
378
|
+
fix(fixer) {
|
|
379
|
+
return getBlankLineFix(fixer, sourceCode, previous, target);
|
|
380
|
+
},
|
|
381
|
+
node: next,
|
|
382
|
+
messageId: "blankLine",
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return {
|
|
387
|
+
Program(node) {
|
|
388
|
+
checkStatementBody(node.body);
|
|
389
|
+
},
|
|
390
|
+
ClassBody(node) {
|
|
391
|
+
if (!options.betweenClassMembers) {
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
for (let index = 1; index < node.body.length; index += 1) {
|
|
395
|
+
const previous = node.body[index - 1];
|
|
396
|
+
const next = node.body[index];
|
|
397
|
+
if (previous === undefined || next === undefined) {
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
if (isOverloadMember(previous) || isGetterSetterPair(previous, next)) {
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
requireBlankLine(previous, getMemberStart(next), next);
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
SwitchCase(node) {
|
|
407
|
+
checkStatementBody(node.consequent);
|
|
408
|
+
},
|
|
409
|
+
StaticBlock(node) {
|
|
410
|
+
checkStatementBody(node.body);
|
|
411
|
+
},
|
|
412
|
+
TSModuleBlock(node) {
|
|
413
|
+
checkStatementBody(node.body);
|
|
414
|
+
},
|
|
415
|
+
TSTypeLiteral(node) {
|
|
416
|
+
if (!options.betweenTypeMembers) {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
checkTypeMembers(node.members);
|
|
420
|
+
},
|
|
421
|
+
BlockStatement(node) {
|
|
422
|
+
checkStatementBody(node.body);
|
|
423
|
+
},
|
|
424
|
+
SwitchStatement(node) {
|
|
425
|
+
if (!options.betweenSwitchCases) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
for (let index = 1; index < node.cases.length; index += 1) {
|
|
429
|
+
const previous = node.cases[index - 1];
|
|
430
|
+
const next = node.cases[index];
|
|
431
|
+
if (previous === undefined || next === undefined || previous.consequent.length === 0) {
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
requireBlankLine(previous, next, next);
|
|
435
|
+
}
|
|
436
|
+
},
|
|
437
|
+
TSInterfaceBody(node) {
|
|
438
|
+
if (!options.betweenTypeMembers) {
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
checkTypeMembers(node.body);
|
|
442
|
+
},
|
|
443
|
+
};
|
|
444
|
+
},
|
|
445
|
+
});
|
|
446
|
+
export default blankLine;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 同じモジュールを指す連続した import 宣言を 1 つにまとめます。
|
|
3
|
+
*
|
|
4
|
+
* 別名の default import、namespace import、副作用だけの import、属性が異なる import は安全にまとめられないため対象外にします。コメントが specifier の外側にある場合も、コメントを失わないように対象外にします。
|
|
5
|
+
*/
|
|
6
|
+
declare const mergeImports: import("vite-plus/lint/plugins").Rule;
|
|
7
|
+
export default mergeImports;
|
|
8
|
+
//# sourceMappingURL=merge-imports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-imports.d.ts","sourceRoot":"","sources":["../../../src/rules/merge-imports.ts"],"names":[],"mappings":"AAgOA;;;;GAIG;AACH,QAAA,MAAM,YAAY,uCAqEhB,CAAC;eAEY,YAAY"}
|