@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.
Files changed (45) hide show
  1. package/dist/src/index.d.ts +2 -6
  2. package/dist/src/index.d.ts.map +1 -1
  3. package/dist/src/index.js +2 -6
  4. package/dist/src/plugin.js +4 -12
  5. package/dist/src/rules/blank-line-utils.d.ts +30 -0
  6. package/dist/src/rules/blank-line-utils.d.ts.map +1 -0
  7. package/dist/src/rules/blank-line-utils.js +103 -0
  8. package/dist/src/rules/blank-line.d.ts +5 -14
  9. package/dist/src/rules/blank-line.d.ts.map +1 -1
  10. package/dist/src/rules/blank-line.js +426 -66
  11. package/dist/src/rules/merge-imports.d.ts +8 -0
  12. package/dist/src/rules/merge-imports.d.ts.map +1 -0
  13. package/dist/src/rules/merge-imports.js +199 -0
  14. package/dist/src/rules/overload-signatures-adjacent.js +1 -1
  15. package/package.json +1 -1
  16. package/src/index.ts +2 -6
  17. package/src/plugin.ts +4 -12
  18. package/src/rules/blank-line-utils.ts +165 -0
  19. package/src/rules/blank-line.ts +555 -97
  20. package/src/rules/merge-imports.ts +301 -0
  21. package/src/rules/overload-signatures-adjacent.ts +1 -1
  22. package/dist/src/rules/blank-line-after-control-block.d.ts +0 -7
  23. package/dist/src/rules/blank-line-after-control-block.d.ts.map +0 -1
  24. package/dist/src/rules/blank-line-after-control-block.js +0 -54
  25. package/dist/src/rules/blank-line-after-declaration.d.ts +0 -7
  26. package/dist/src/rules/blank-line-after-declaration.d.ts.map +0 -1
  27. package/dist/src/rules/blank-line-after-declaration.js +0 -79
  28. package/dist/src/rules/blank-line-after-variable-declaration.d.ts +0 -9
  29. package/dist/src/rules/blank-line-after-variable-declaration.d.ts.map +0 -1
  30. package/dist/src/rules/blank-line-after-variable-declaration.js +0 -118
  31. package/dist/src/rules/blank-line-before-return.d.ts +0 -7
  32. package/dist/src/rules/blank-line-before-return.d.ts.map +0 -1
  33. package/dist/src/rules/blank-line-before-return.js +0 -81
  34. package/dist/src/rules/blank-line-between-class-members.d.ts +0 -8
  35. package/dist/src/rules/blank-line-between-class-members.d.ts.map +0 -1
  36. package/dist/src/rules/blank-line-between-class-members.js +0 -85
  37. package/dist/src/rules/blank-line-between-switch-cases.d.ts +0 -8
  38. package/dist/src/rules/blank-line-between-switch-cases.d.ts.map +0 -1
  39. package/dist/src/rules/blank-line-between-switch-cases.js +0 -45
  40. package/src/rules/blank-line-after-control-block.ts +0 -82
  41. package/src/rules/blank-line-after-declaration.ts +0 -106
  42. package/src/rules/blank-line-after-variable-declaration.ts +0 -165
  43. package/src/rules/blank-line-before-return.ts +0 -101
  44. package/src/rules/blank-line-between-class-members.ts +0 -112
  45. package/src/rules/blank-line-between-switch-cases.ts +0 -53
@@ -0,0 +1,301 @@
1
+ import { defineRule } from "vite-plus/lint/plugins";
2
+ import type { ESTree, Comment, SourceCode } from "vite-plus/lint/plugins";
3
+
4
+ interface NamedSpecifier {
5
+ local: string;
6
+ text: string;
7
+ }
8
+
9
+ function getModuleName(node: ESTree.ImportDeclaration): string {
10
+ return node.source.value;
11
+ }
12
+
13
+ function getAttributeKey(attribute: ESTree.ImportAttribute): string {
14
+ const key = attribute.key.type === "Identifier" ? attribute.key.name : attribute.key.value;
15
+
16
+ return `${key}:${attribute.value.value}`;
17
+ }
18
+
19
+ function getAttributesKey(node: ESTree.ImportDeclaration): string {
20
+ return node.attributes.map(getAttributeKey).join(",");
21
+ }
22
+
23
+ function getLineIndent(source: string, offset: number): string {
24
+ const lineStart = source.lastIndexOf("\n", offset) + 1;
25
+ const match = /^[ \t]*/u.exec(source.slice(lineStart, offset));
26
+
27
+ return match?.[0] ?? "";
28
+ }
29
+
30
+ function isMergeableDeclaration(node: ESTree.Node): node is ESTree.ImportDeclaration {
31
+ return (
32
+ node.type === "ImportDeclaration" &&
33
+ node.phase === null &&
34
+ node.specifiers.length > 0 &&
35
+ node.specifiers.every((specifier) => specifier.type !== "ImportNamespaceSpecifier")
36
+ );
37
+ }
38
+
39
+ function hasUnsafeComment(
40
+ declarations: readonly ESTree.ImportDeclaration[],
41
+ comments: readonly Comment[],
42
+ ): boolean {
43
+ const first = declarations[0];
44
+ const last = declarations.at(-1);
45
+
46
+ if (first === undefined || last === undefined) {
47
+ return true;
48
+ }
49
+
50
+ const specifierRanges = declarations.flatMap((declaration) =>
51
+ declaration.specifiers.map((specifier) => specifier.range),
52
+ );
53
+
54
+ return comments.some(
55
+ (comment) =>
56
+ comment.range[0] >= first.range[0] &&
57
+ comment.range[1] <= last.range[1] &&
58
+ !specifierRanges.some(
59
+ (range) => comment.range[0] >= range[0] && comment.range[1] <= range[1],
60
+ ),
61
+ );
62
+ }
63
+
64
+ function buildNamedClause(
65
+ declarations: readonly ESTree.ImportDeclaration[],
66
+ specifiers: readonly NamedSpecifier[],
67
+ sourceCode: SourceCode,
68
+ ): string {
69
+ const texts = specifiers.map((specifier) => specifier.text);
70
+ const multiline = declarations.find((declaration) => {
71
+ const firstSpecifier = declaration.specifiers.find(
72
+ (specifier): specifier is ESTree.ImportSpecifier => specifier.type === "ImportSpecifier",
73
+ );
74
+
75
+ return (
76
+ firstSpecifier !== undefined && firstSpecifier.loc.start.line > declaration.loc.start.line
77
+ );
78
+ });
79
+
80
+ if (multiline === undefined) {
81
+ return `{ ${texts.join(", ")} }`;
82
+ }
83
+
84
+ const firstNamed = multiline.specifiers.find(
85
+ (specifier): specifier is ESTree.ImportSpecifier => specifier.type === "ImportSpecifier",
86
+ );
87
+ const lastNamed = multiline.specifiers.findLast(
88
+ (specifier): specifier is ESTree.ImportSpecifier => specifier.type === "ImportSpecifier",
89
+ );
90
+ const firstDeclaration = declarations[0];
91
+
92
+ if (firstNamed === undefined || lastNamed === undefined || firstDeclaration === undefined) {
93
+ return `{ ${texts.join(", ")} }`;
94
+ }
95
+
96
+ const indent = getLineIndent(sourceCode.text, firstNamed.range[0]);
97
+ const closingIndent = getLineIndent(sourceCode.text, firstDeclaration.range[0]);
98
+ const beforeSource = sourceCode.text.slice(lastNamed.range[1], multiline.source.range[0]);
99
+ const trailingComma = /,\s*\}/u.test(beforeSource);
100
+
101
+ return `{\n${indent}${texts.join(`,\n${indent}`)}${trailingComma ? "," : ""}\n${closingIndent}}`;
102
+ }
103
+
104
+ function buildReplacement(
105
+ declarations: readonly ESTree.ImportDeclaration[],
106
+ sourceCode: SourceCode,
107
+ ): string | null {
108
+ const first = declarations[0];
109
+
110
+ if (first === undefined) {
111
+ return null;
112
+ }
113
+
114
+ const defaultSpecifiers = declarations.flatMap((declaration) =>
115
+ declaration.specifiers
116
+ .filter(
117
+ (specifier): specifier is ESTree.ImportDefaultSpecifier =>
118
+ specifier.type === "ImportDefaultSpecifier",
119
+ )
120
+ .map((specifier) => ({
121
+ local: specifier.local.name,
122
+ typeOnly: declaration.importKind === "type",
123
+ })),
124
+ );
125
+ const hasNamed = declarations.some((declaration) =>
126
+ declaration.specifiers.some((specifier) => specifier.type === "ImportSpecifier"),
127
+ );
128
+
129
+ let defaultSpecifier: {
130
+ local: string;
131
+ typeOnly: boolean;
132
+ } | null = null;
133
+
134
+ for (const specifier of defaultSpecifiers) {
135
+ if (defaultSpecifier === null) {
136
+ defaultSpecifier = specifier;
137
+ continue;
138
+ }
139
+
140
+ // default import は 1 つしか置けないため、別名の default import はまとめられません。
141
+ if (
142
+ defaultSpecifier.local !== specifier.local ||
143
+ defaultSpecifier.typeOnly !== specifier.typeOnly
144
+ ) {
145
+ return null;
146
+ }
147
+ }
148
+
149
+ const allTypeOnly = declarations.every((declaration) => declaration.importKind === "type");
150
+ // `import type Foo, { Bar }` は書けないため、default と名前付きを併存させる場合は `type default as Foo` を使う通常の import に変換します。
151
+ const useTypeOnlyDeclaration = allTypeOnly && !(defaultSpecifier !== null && hasNamed);
152
+ const namedByLocal = new Map<string, string>();
153
+ const named: NamedSpecifier[] = [];
154
+
155
+ function addNamed(local: string, text: string): boolean {
156
+ const existing = namedByLocal.get(local);
157
+
158
+ if (existing !== undefined) {
159
+ return existing === text;
160
+ }
161
+
162
+ namedByLocal.set(local, text);
163
+ named.push({
164
+ text,
165
+ local,
166
+ });
167
+
168
+ return true;
169
+ }
170
+
171
+ let defaultClause: string | null = null;
172
+
173
+ if (defaultSpecifier !== null) {
174
+ if (useTypeOnlyDeclaration || !defaultSpecifier.typeOnly) {
175
+ defaultClause = defaultSpecifier.local;
176
+ } else if (!addNamed(defaultSpecifier.local, `type default as ${defaultSpecifier.local}`)) {
177
+ return null;
178
+ }
179
+ }
180
+
181
+ for (const declaration of declarations) {
182
+ const forceType = !useTypeOnlyDeclaration && declaration.importKind === "type";
183
+
184
+ for (const specifier of declaration.specifiers) {
185
+ if (specifier.type !== "ImportSpecifier") {
186
+ continue;
187
+ }
188
+
189
+ const original = sourceCode.getText(specifier);
190
+ const text = forceType && specifier.importKind !== "type" ? `type ${original}` : original;
191
+
192
+ if (!addNamed(specifier.local.name, text)) {
193
+ return null;
194
+ }
195
+ }
196
+ }
197
+
198
+ if (defaultClause !== null && namedByLocal.has(defaultClause)) {
199
+ return null;
200
+ }
201
+
202
+ const bindings: string[] = [];
203
+
204
+ if (defaultClause !== null) {
205
+ bindings.push(defaultClause);
206
+ }
207
+
208
+ if (named.length > 0) {
209
+ bindings.push(buildNamedClause(declarations, named, sourceCode));
210
+ }
211
+
212
+ if (bindings.length === 0) {
213
+ return null;
214
+ }
215
+
216
+ const sourceText = sourceCode.getText(first.source);
217
+ // `with { ... }` や `assert { ... }`、セミコロンの有無を元の宣言から引き継ぎます。
218
+ const suffix = sourceCode.text.slice(first.source.range[1], first.range[1]);
219
+
220
+ return `import ${useTypeOnlyDeclaration ? "type " : ""}${bindings.join(
221
+ ", ",
222
+ )} from ${sourceText}${suffix}`;
223
+ }
224
+
225
+ /**
226
+ * 同じモジュールを指す連続した import 宣言を 1 つにまとめます。
227
+ *
228
+ * 別名の default import、namespace import、副作用だけの import、属性が異なる import は安全にまとめられないため対象外にします。コメントが specifier の外側にある場合も、コメントを失わないように対象外にします。
229
+ */
230
+ const mergeImports = defineRule({
231
+ meta: {
232
+ docs: {
233
+ description: "Merge consecutive import declarations that import from the same module.",
234
+ },
235
+ type: "layout",
236
+ fixable: "whitespace",
237
+ messages: {
238
+ merge: "Import declarations from the same module must be merged.",
239
+ },
240
+ },
241
+ create(context) {
242
+ const sourceCode = context.sourceCode;
243
+
244
+ return {
245
+ Program(node): void {
246
+ const comments = sourceCode.getAllComments();
247
+ let index = 0;
248
+
249
+ while (index < node.body.length) {
250
+ const first = node.body[index];
251
+
252
+ if (first === undefined || !isMergeableDeclaration(first)) {
253
+ index += 1;
254
+ continue;
255
+ }
256
+
257
+ const declarations = [first];
258
+ let next = index + 1;
259
+
260
+ while (next < node.body.length) {
261
+ const candidate = node.body[next];
262
+
263
+ if (
264
+ candidate === undefined ||
265
+ !isMergeableDeclaration(candidate) ||
266
+ getModuleName(candidate) !== getModuleName(first) ||
267
+ getAttributesKey(candidate) !== getAttributesKey(first)
268
+ ) {
269
+ break;
270
+ }
271
+
272
+ declarations.push(candidate);
273
+ next += 1;
274
+ }
275
+
276
+ if (declarations.length > 1 && !hasUnsafeComment(declarations, comments)) {
277
+ const replacement = buildReplacement(declarations, sourceCode);
278
+ const last = declarations.at(-1);
279
+
280
+ if (replacement !== null && last !== undefined) {
281
+ context.report({
282
+ fix(fixer) {
283
+ return [
284
+ fixer.replaceText(first, replacement),
285
+ fixer.removeRange([first.range[1], last.range[1]]),
286
+ ];
287
+ },
288
+ node: first,
289
+ messageId: "merge",
290
+ });
291
+ }
292
+ }
293
+
294
+ index = next;
295
+ }
296
+ },
297
+ };
298
+ },
299
+ });
300
+
301
+ export default mergeImports;
@@ -1,7 +1,7 @@
1
1
  import { defineRule } from "vite-plus/lint/plugins";
2
2
  import type { ESTree, Context, SourceCode } from "vite-plus/lint/plugins";
3
3
 
4
- import { getNextStatement, getRemoveBlankLineFix } from "./blank-line.js";
4
+ import { getNextStatement, getRemoveBlankLineFix } from "./blank-line-utils.js";
5
5
 
6
6
  function getFunction(node: ESTree.Node): ESTree.Function | null {
7
7
  if (node.type === "FunctionDeclaration" || node.type === "TSDeclareFunction") {
@@ -1,7 +0,0 @@
1
- /**
2
- * 制御ブロックの直後に次の処理がある場合、空行を 1 行以上確保します。
3
- * 余分な空行は Oxfmt が 1 行に畳みます。
4
- */
5
- declare const blankLineAfterControlBlock: import("vite-plus/lint/plugins").Rule;
6
- export default blankLineAfterControlBlock;
7
- //# sourceMappingURL=blank-line-after-control-block.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"blank-line-after-control-block.d.ts","sourceRoot":"","sources":["../../../src/rules/blank-line-after-control-block.ts"],"names":[],"mappings":"AA+BA;;;GAGG;AACH,QAAA,MAAM,0BAA0B,uCA4C9B,CAAC;eAEY,0BAA0B"}
@@ -1,54 +0,0 @@
1
- import { defineRule } from "vite-plus/lint/plugins";
2
- import { hasBlankLine, getBlankLineFix, getNextStatement, getInsertionTarget, } from "./blank-line.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
- /**
14
- * 制御ブロックの直後に次の処理がある場合、空行を 1 行以上確保します。
15
- * 余分な空行は Oxfmt が 1 行に畳みます。
16
- */
17
- const blankLineAfterControlBlock = defineRule({
18
- meta: {
19
- docs: {
20
- description: "Require a blank line after a control block when another statement follows.",
21
- },
22
- type: "layout",
23
- fixable: "whitespace",
24
- messages: {
25
- blankLine: "Expected a blank line after a control block when another statement follows.",
26
- },
27
- },
28
- create(context) {
29
- const sourceCode = context.sourceCode;
30
- function checkNode(node) {
31
- const nextStatement = getNextStatement(node);
32
- if (nextStatement === null || nextStatement.type === "EmptyStatement") {
33
- return;
34
- }
35
- const target = getInsertionTarget(node, nextStatement, sourceCode);
36
- if (hasBlankLine(node, target)) {
37
- return;
38
- }
39
- context.report({
40
- fix(fixer) {
41
- return getBlankLineFix(fixer, sourceCode, node, target);
42
- },
43
- node,
44
- messageId: "blankLine",
45
- });
46
- }
47
- const visitors = {};
48
- for (const type of CONTROL_STATEMENT_TYPES) {
49
- visitors[type] = checkNode;
50
- }
51
- return visitors;
52
- },
53
- });
54
- export default blankLineAfterControlBlock;
@@ -1,7 +0,0 @@
1
- /**
2
- * 関数・クラス・型などの宣言の後に次の文がある場合、空行を 1 行以上確保します。
3
- * 余分な空行は Oxfmt が 1 行に畳みます。
4
- */
5
- declare const blankLineAfterDeclaration: import("vite-plus/lint/plugins").Rule;
6
- export default blankLineAfterDeclaration;
7
- //# sourceMappingURL=blank-line-after-declaration.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"blank-line-after-declaration.d.ts","sourceRoot":"","sources":["../../../src/rules/blank-line-after-declaration.ts"],"names":[],"mappings":"AA2CA;;;GAGG;AACH,QAAA,MAAM,yBAAyB,uCAwD7B,CAAC;eAEY,yBAAyB"}
@@ -1,79 +0,0 @@
1
- import { defineRule } from "vite-plus/lint/plugins";
2
- import { hasBlankLine, getBlankLineFix, getNextStatement, getInsertionTarget, } from "./blank-line.js";
3
- const DECLARATION_TYPES = new Set([
4
- "ClassDeclaration",
5
- "FunctionDeclaration",
6
- "TSDeclareFunction",
7
- "TSEnumDeclaration",
8
- "TSInterfaceDeclaration",
9
- "TSModuleDeclaration",
10
- "TSTypeAliasDeclaration",
11
- ]);
12
- function getDeclaration(node) {
13
- if (DECLARATION_TYPES.has(node.type)) {
14
- return node;
15
- }
16
- if ((node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration") &&
17
- node.declaration !== null &&
18
- DECLARATION_TYPES.has(node.declaration.type)) {
19
- return node.declaration;
20
- }
21
- return null;
22
- }
23
- function isOverload(declaration) {
24
- return ((declaration.type === "FunctionDeclaration" || declaration.type === "TSDeclareFunction") &&
25
- declaration.body === null);
26
- }
27
- /**
28
- * 関数・クラス・型などの宣言の後に次の文がある場合、空行を 1 行以上確保します。
29
- * 余分な空行は Oxfmt が 1 行に畳みます。
30
- */
31
- const blankLineAfterDeclaration = defineRule({
32
- meta: {
33
- docs: {
34
- description: "Require a blank line after a declaration when another statement follows.",
35
- },
36
- type: "layout",
37
- fixable: "whitespace",
38
- messages: {
39
- blankLine: "Expected a blank line after a declaration when another statement follows.",
40
- },
41
- },
42
- create(context) {
43
- const sourceCode = context.sourceCode;
44
- function checkNode(node) {
45
- const declaration = getDeclaration(node);
46
- if (declaration === null || isOverload(declaration)) {
47
- return;
48
- }
49
- const nextStatement = getNextStatement(node);
50
- if (nextStatement === null || nextStatement.type === "EmptyStatement") {
51
- return;
52
- }
53
- const target = getInsertionTarget(node, nextStatement, sourceCode);
54
- if (hasBlankLine(node, target)) {
55
- return;
56
- }
57
- context.report({
58
- fix(fixer) {
59
- return getBlankLineFix(fixer, sourceCode, node, target);
60
- },
61
- node,
62
- messageId: "blankLine",
63
- });
64
- }
65
- const visitors = {
66
- ClassDeclaration: checkNode,
67
- TSDeclareFunction: checkNode,
68
- TSEnumDeclaration: checkNode,
69
- FunctionDeclaration: checkNode,
70
- TSModuleDeclaration: checkNode,
71
- ExportNamedDeclaration: checkNode,
72
- TSInterfaceDeclaration: checkNode,
73
- TSTypeAliasDeclaration: checkNode,
74
- ExportDefaultDeclaration: checkNode,
75
- };
76
- return visitors;
77
- },
78
- });
79
- export default blankLineAfterDeclaration;
@@ -1,9 +0,0 @@
1
- /**
2
- * 連続する変数宣言の後に別の種類の文が続く場合、空行を 1 行以上確保します。
3
- *
4
- * 宣言した変数を使う式文は同じ宣言グループとして扱い、グループ内の空行は削除します。
5
- * return の直前は blank-line-before-return が担当するため対象外にします。
6
- */
7
- declare const blankLineAfterVariableDeclaration: import("vite-plus/lint/plugins").Rule;
8
- export default blankLineAfterVariableDeclaration;
9
- //# sourceMappingURL=blank-line-after-variable-declaration.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"blank-line-after-variable-declaration.d.ts","sourceRoot":"","sources":["../../../src/rules/blank-line-after-variable-declaration.ts"],"names":[],"mappings":"AA8CA;;;;;GAKG;AACH,QAAA,MAAM,iCAAiC,uCA8GrC,CAAC;eAEY,iCAAiC"}
@@ -1,118 +0,0 @@
1
- import { defineRule } from "vite-plus/lint/plugins";
2
- import { hasBlankLine, getBlankLineFix, getNextStatement, getInsertionTarget, getPreviousStatement, getRemoveBlankLineFix, } from "./blank-line.js";
3
- function getVariableDeclaration(node) {
4
- if (node.type === "VariableDeclaration") {
5
- return node;
6
- }
7
- if (node.type === "ExportNamedDeclaration" && node.declaration?.type === "VariableDeclaration") {
8
- return node.declaration;
9
- }
10
- return null;
11
- }
12
- function isRelatedExpression(statement, variables) {
13
- if (statement.type !== "ExpressionStatement") {
14
- return false;
15
- }
16
- for (const variable of variables) {
17
- for (const reference of variable.references) {
18
- if (reference.identifier.range[0] >= statement.range[0] &&
19
- reference.identifier.range[1] <= statement.range[1]) {
20
- return true;
21
- }
22
- }
23
- }
24
- return false;
25
- }
26
- /**
27
- * 連続する変数宣言の後に別の種類の文が続く場合、空行を 1 行以上確保します。
28
- *
29
- * 宣言した変数を使う式文は同じ宣言グループとして扱い、グループ内の空行は削除します。
30
- * return の直前は blank-line-before-return が担当するため対象外にします。
31
- */
32
- const blankLineAfterVariableDeclaration = defineRule({
33
- meta: {
34
- docs: {
35
- description: "Require a blank line after a variable declaration group and remove blank lines before related statements.",
36
- },
37
- type: "layout",
38
- fixable: "whitespace",
39
- messages: {
40
- blankLine: "Expected a blank line after a variable declaration group when another statement follows.",
41
- unexpectedBlankLine: "Expected no blank line between a variable declaration and its related statement.",
42
- },
43
- },
44
- create(context) {
45
- const sourceCode = context.sourceCode;
46
- function checkStatement(node) {
47
- const variableDeclaration = getVariableDeclaration(node);
48
- if (variableDeclaration === null) {
49
- return;
50
- }
51
- if (node.type === "VariableDeclaration" && node.parent.type === "ExportNamedDeclaration") {
52
- return;
53
- }
54
- const previousStatement = getPreviousStatement(node);
55
- if (previousStatement !== null && getVariableDeclaration(previousStatement) !== null) {
56
- return;
57
- }
58
- const variables = new Set(sourceCode.getDeclaredVariables(variableDeclaration));
59
- let last = node;
60
- let nextStatement = getNextStatement(last);
61
- while (nextStatement !== null) {
62
- const nextVariableDeclaration = getVariableDeclaration(nextStatement);
63
- if (nextVariableDeclaration !== null && getVariableDeclaration(last) !== null) {
64
- for (const variable of sourceCode.getDeclaredVariables(nextVariableDeclaration)) {
65
- variables.add(variable);
66
- }
67
- last = nextStatement;
68
- nextStatement = getNextStatement(last);
69
- continue;
70
- }
71
- if (nextStatement.type === "ExpressionStatement" &&
72
- isRelatedExpression(nextStatement, variables)) {
73
- const target = getInsertionTarget(last, nextStatement, sourceCode);
74
- if (hasBlankLine(last, target)) {
75
- context.report({
76
- fix(fixer) {
77
- return getRemoveBlankLineFix(fixer, sourceCode, last, target);
78
- },
79
- node: nextStatement,
80
- messageId: "unexpectedBlankLine",
81
- });
82
- }
83
- last = nextStatement;
84
- nextStatement = getNextStatement(last);
85
- continue;
86
- }
87
- break;
88
- }
89
- if (nextStatement === null ||
90
- nextStatement.type === "EmptyStatement" ||
91
- nextStatement.type === "ReturnStatement") {
92
- return;
93
- }
94
- const target = getInsertionTarget(last, nextStatement, sourceCode);
95
- if (hasBlankLine(last, target)) {
96
- return;
97
- }
98
- context.report({
99
- fix(fixer) {
100
- return getBlankLineFix(fixer, sourceCode, last, target);
101
- },
102
- node: nextStatement,
103
- messageId: "blankLine",
104
- });
105
- }
106
- return {
107
- VariableDeclaration(node) {
108
- checkStatement(node);
109
- },
110
- ExportNamedDeclaration(node) {
111
- if (node.declaration?.type === "VariableDeclaration") {
112
- checkStatement(node);
113
- }
114
- },
115
- };
116
- },
117
- });
118
- export default blankLineAfterVariableDeclaration;
@@ -1,7 +0,0 @@
1
- /**
2
- * return の直前に処理がある場合、空行を 1 行以上確保します。
3
- * 余分な空行は Oxfmt が 1 行に畳みます。
4
- */
5
- declare const blankLineBeforeReturn: import("vite-plus/lint/plugins").Rule;
6
- export default blankLineBeforeReturn;
7
- //# sourceMappingURL=blank-line-before-return.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"blank-line-before-return.d.ts","sourceRoot":"","sources":["../../../src/rules/blank-line-before-return.ts"],"names":[],"mappings":"AA2CA;;;GAGG;AACH,QAAA,MAAM,qBAAqB,uCAmDzB,CAAC;eAEY,qBAAqB"}