@tai-kun/vp-lint-plugins 0.0.1 → 0.0.3
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/rules/blank-line-after-variable-declaration.d.ts +1 -0
- package/dist/src/rules/blank-line-after-variable-declaration.d.ts.map +1 -1
- package/dist/src/rules/blank-line-after-variable-declaration.js +68 -12
- package/dist/src/rules/blank-line.d.ts +5 -1
- package/dist/src/rules/blank-line.d.ts.map +1 -1
- package/dist/src/rules/blank-line.js +19 -1
- package/dist/src/rules/comment-one-sentence-per-line.d.ts.map +1 -1
- package/dist/src/rules/jsdoc-utils.d.ts.map +1 -1
- package/dist/src/rules/object-sort-utils.d.ts +12 -0
- package/dist/src/rules/object-sort-utils.d.ts.map +1 -1
- package/dist/src/rules/object-sort-utils.js +100 -47
- package/dist/src/rules/overload-signatures-adjacent.d.ts.map +1 -1
- package/dist/src/rules/overload-signatures-adjacent.js +2 -17
- package/dist/src/rules/sort-jsx-props.d.ts.map +1 -1
- package/dist/src/rules/sort-object-properties.d.ts +1 -1
- package/dist/src/rules/sort-object-properties.d.ts.map +1 -1
- package/dist/src/rules/sort-object-properties.js +7 -1
- package/dist/src/rules/spaced-comment.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/rules/blank-line-after-variable-declaration.ts +93 -12
- package/src/rules/blank-line.ts +30 -0
- package/src/rules/comment-one-sentence-per-line.ts +1 -2
- package/src/rules/jsdoc-utils.ts +1 -2
- package/src/rules/object-sort-utils.ts +134 -61
- package/src/rules/overload-signatures-adjacent.ts +3 -29
- package/src/rules/sort-jsx-props.ts +0 -1
- package/src/rules/sort-object-properties.ts +13 -1
- package/src/rules/sort-type-members.ts +1 -1
- package/src/rules/spaced-comment.ts +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blank-line-after-variable-declaration.d.ts","sourceRoot":"","sources":["../../../src/rules/blank-line-after-variable-declaration.ts"],"names":[],"mappings":"
|
|
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,49 +1,105 @@
|
|
|
1
1
|
import { defineRule } from "vite-plus/lint/plugins";
|
|
2
|
-
import { hasBlankLine, getBlankLineFix, getNextStatement, getInsertionTarget, } from "./blank-line.js";
|
|
3
|
-
function
|
|
2
|
+
import { hasBlankLine, getBlankLineFix, getNextStatement, getInsertionTarget, getPreviousStatement, getRemoveBlankLineFix, } from "./blank-line.js";
|
|
3
|
+
function getVariableDeclaration(node) {
|
|
4
4
|
if (node.type === "VariableDeclaration") {
|
|
5
|
-
return
|
|
5
|
+
return node;
|
|
6
6
|
}
|
|
7
|
-
|
|
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;
|
|
8
25
|
}
|
|
9
26
|
/**
|
|
10
27
|
* 連続する変数宣言の後に別の種類の文が続く場合、空行を 1 行以上確保します。
|
|
11
28
|
*
|
|
29
|
+
* 宣言した変数を使う式文は同じ宣言グループとして扱い、グループ内の空行は削除します。
|
|
12
30
|
* return の直前は blank-line-before-return が担当するため対象外にします。
|
|
13
31
|
*/
|
|
14
32
|
const blankLineAfterVariableDeclaration = defineRule({
|
|
15
33
|
meta: {
|
|
16
34
|
docs: {
|
|
17
|
-
description: "Require a blank line after a variable declaration group
|
|
35
|
+
description: "Require a blank line after a variable declaration group and remove blank lines before related statements.",
|
|
18
36
|
},
|
|
19
37
|
type: "layout",
|
|
20
38
|
fixable: "whitespace",
|
|
21
39
|
messages: {
|
|
22
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.",
|
|
23
42
|
},
|
|
24
43
|
},
|
|
25
44
|
create(context) {
|
|
26
45
|
const sourceCode = context.sourceCode;
|
|
27
46
|
function checkStatement(node) {
|
|
47
|
+
const variableDeclaration = getVariableDeclaration(node);
|
|
48
|
+
if (variableDeclaration === null) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
28
51
|
if (node.type === "VariableDeclaration" && node.parent.type === "ExportNamedDeclaration") {
|
|
29
52
|
return;
|
|
30
53
|
}
|
|
31
|
-
const
|
|
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
|
+
}
|
|
32
89
|
if (nextStatement === null ||
|
|
33
90
|
nextStatement.type === "EmptyStatement" ||
|
|
34
|
-
nextStatement.type === "ReturnStatement"
|
|
35
|
-
isVariableDeclarationStatement(nextStatement)) {
|
|
91
|
+
nextStatement.type === "ReturnStatement") {
|
|
36
92
|
return;
|
|
37
93
|
}
|
|
38
|
-
const target = getInsertionTarget(
|
|
39
|
-
if (hasBlankLine(
|
|
94
|
+
const target = getInsertionTarget(last, nextStatement, sourceCode);
|
|
95
|
+
if (hasBlankLine(last, target)) {
|
|
40
96
|
return;
|
|
41
97
|
}
|
|
42
98
|
context.report({
|
|
43
99
|
fix(fixer) {
|
|
44
|
-
return getBlankLineFix(fixer, sourceCode,
|
|
100
|
+
return getBlankLineFix(fixer, sourceCode, last, target);
|
|
45
101
|
},
|
|
46
|
-
node,
|
|
102
|
+
node: nextStatement,
|
|
47
103
|
messageId: "blankLine",
|
|
48
104
|
});
|
|
49
105
|
}
|
|
@@ -10,5 +10,9 @@ declare function getPreviousStatement(node: ESTree.Node): ESTree.Node | null;
|
|
|
10
10
|
declare function getInsertionTarget(node: ESTree.Node, nextStatement: ESTree.Node, sourceCode: SourceCode): ESTree.Node | Comment;
|
|
11
11
|
declare function hasBlankLine(node: ESTree.Node, target: ESTree.Node | Comment): boolean;
|
|
12
12
|
declare function getBlankLineFix(fixer: Fixer, sourceCode: SourceCode, node: ESTree.Node, target: ESTree.Node | Comment): Fix | null;
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* 指定したノードと対象の間の空行を削除します。
|
|
15
|
+
*/
|
|
16
|
+
declare function getRemoveBlankLineFix(fixer: Fixer, sourceCode: SourceCode, node: ESTree.Node, target: ESTree.Node | Comment): Fix | null;
|
|
17
|
+
export { hasBlankLine, getBlankLineFix, getNextStatement, getInsertionTarget, getPreviousStatement, getRemoveBlankLineFix, };
|
|
14
18
|
//# sourceMappingURL=blank-line.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blank-line.d.ts","sourceRoot":"","sources":["../../../src/rules/blank-line.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AA4BtF,iBAAS,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,GAAG,IAAI,CAc/D;AAED,iBAAS,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,GAAG,IAAI,CAcnE;AAED;;;;;GAKG;AACH,iBAAS,kBAAkB,CACzB,IAAI,EAAE,MAAM,CAAC,IAAI,EACjB,aAAa,EAAE,MAAM,CAAC,IAAI,EAC1B,UAAU,EAAE,UAAU,GACrB,MAAM,CAAC,IAAI,GAAG,OAAO,CAWvB;AAED,iBAAS,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,GAAG,OAAO,GAAG,OAAO,CAE/E;AAED,iBAAS,eAAe,CACtB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,UAAU,EACtB,IAAI,EAAE,MAAM,CAAC,IAAI,EACjB,MAAM,EAAE,MAAM,CAAC,IAAI,GAAG,OAAO,GAC5B,GAAG,GAAG,IAAI,CAYZ;AAED,OAAO,EACL,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,
|
|
1
|
+
{"version":3,"file":"blank-line.d.ts","sourceRoot":"","sources":["../../../src/rules/blank-line.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AA4BtF,iBAAS,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,GAAG,IAAI,CAc/D;AAED,iBAAS,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,GAAG,IAAI,CAcnE;AAED;;;;;GAKG;AACH,iBAAS,kBAAkB,CACzB,IAAI,EAAE,MAAM,CAAC,IAAI,EACjB,aAAa,EAAE,MAAM,CAAC,IAAI,EAC1B,UAAU,EAAE,UAAU,GACrB,MAAM,CAAC,IAAI,GAAG,OAAO,CAWvB;AAED,iBAAS,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,GAAG,OAAO,GAAG,OAAO,CAE/E;AAED,iBAAS,eAAe,CACtB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,UAAU,EACtB,IAAI,EAAE,MAAM,CAAC,IAAI,EACjB,MAAM,EAAE,MAAM,CAAC,IAAI,GAAG,OAAO,GAC5B,GAAG,GAAG,IAAI,CAYZ;AAED;;GAEG;AACH,iBAAS,qBAAqB,CAC5B,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,UAAU,EACtB,IAAI,EAAE,MAAM,CAAC,IAAI,EACjB,MAAM,EAAE,MAAM,CAAC,IAAI,GAAG,OAAO,GAC5B,GAAG,GAAG,IAAI,CAmBZ;AAED,OAAO,EACL,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,qBAAqB,GACtB,CAAC"}
|
|
@@ -65,4 +65,22 @@ function getBlankLineFix(fixer, sourceCode, node, target) {
|
|
|
65
65
|
}
|
|
66
66
|
return fixer.insertTextBeforeRange([lineEnd, lineEnd + 1], "\n");
|
|
67
67
|
}
|
|
68
|
-
|
|
68
|
+
/**
|
|
69
|
+
* 指定したノードと対象の間の空行を削除します。
|
|
70
|
+
*/
|
|
71
|
+
function getRemoveBlankLineFix(fixer, sourceCode, node, target) {
|
|
72
|
+
if (target.loc.start.line <= node.loc.end.line + 1) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
const fromLineEnd = sourceCode.text.indexOf("\n", node.range[1]);
|
|
76
|
+
if (fromLineEnd === -1) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const targetLineStart = sourceCode.text.lastIndexOf("\n", target.range[0]) + 1;
|
|
80
|
+
const indent = sourceCode.text.slice(targetLineStart, target.range[0]);
|
|
81
|
+
if (indent.trim() !== "") {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
return fixer.replaceTextRange([fromLineEnd, target.range[0]], `\n${indent}`);
|
|
85
|
+
}
|
|
86
|
+
export { hasBlankLine, getBlankLineFix, getNextStatement, getInsertionTarget, getPreviousStatement, getRemoveBlankLineFix, };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comment-one-sentence-per-line.d.ts","sourceRoot":"","sources":["../../../src/rules/comment-one-sentence-per-line.ts"],"names":[],"mappings":"AAiKA;;;;;GAKG;AACH,QAAA,MAAM,yBAAyB,
|
|
1
|
+
{"version":3,"file":"comment-one-sentence-per-line.d.ts","sourceRoot":"","sources":["../../../src/rules/comment-one-sentence-per-line.ts"],"names":[],"mappings":"AAiKA;;;;;GAKG;AACH,QAAA,MAAM,yBAAyB,uCA6F7B,CAAC;eAEY,yBAAyB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsdoc-utils.d.ts","sourceRoot":"","sources":["../../../src/rules/jsdoc-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAI1E,UAAU,SAAS;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,iBAAS,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI/C;AAyBD;;GAEG;AACH,iBAAS,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAqBpD;AAED;;;;GAIG;AACH,iBAAS,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,GAAG,SAAS,EAAE,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"jsdoc-utils.d.ts","sourceRoot":"","sources":["../../../src/rules/jsdoc-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAI1E,UAAU,SAAS;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,iBAAS,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI/C;AAyBD;;GAEG;AACH,iBAAS,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAqBpD;AAED;;;;GAIG;AACH,iBAAS,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,GAAG,SAAS,EAAE,GAAG,IAAI,CA8DnF;AAED,iBAAS,iBAAiB,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,GAAG,OAAO,CAE/D;AAcD;;GAEG;AACH,iBAAS,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,GAAG,IAAI,CAmB/E;AAED,YAAY,EAAE,SAAS,EAAE,CAAC;AAE1B,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,CAAC"}
|
|
@@ -10,12 +10,23 @@ interface SortPlanOptions {
|
|
|
10
10
|
*/
|
|
11
11
|
forceMultiline?: boolean;
|
|
12
12
|
}
|
|
13
|
+
interface SortEdit {
|
|
14
|
+
end: number;
|
|
15
|
+
start: number;
|
|
16
|
+
text: string;
|
|
17
|
+
}
|
|
13
18
|
type SortPlan = {
|
|
19
|
+
edits: null;
|
|
14
20
|
needsFix: false;
|
|
15
21
|
replacement: null;
|
|
16
22
|
} | {
|
|
23
|
+
edits: null;
|
|
17
24
|
needsFix: true;
|
|
18
25
|
replacement: string;
|
|
26
|
+
} | {
|
|
27
|
+
edits: SortEdit[];
|
|
28
|
+
needsFix: true;
|
|
29
|
+
replacement: null;
|
|
19
30
|
};
|
|
20
31
|
declare function compareNames(left: string, right: string): number;
|
|
21
32
|
/**
|
|
@@ -24,6 +35,7 @@ declare function compareNames(left: string, right: string): number;
|
|
|
24
35
|
* - プロパティー名の長さが短い順、同じ長さなら名前順
|
|
25
36
|
* - 空行で区切られたグループ内だけで並び替え
|
|
26
37
|
* - プロパティー直上のコメントはプロパティーと一緒に移動
|
|
38
|
+
* - 空行を挟んだコメントはグループ見出しとしてその場に残す
|
|
27
39
|
*
|
|
28
40
|
* 並び替えが安全でない場合は null を返します。
|
|
29
41
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"object-sort-utils.d.ts","sourceRoot":"","sources":["../../../src/rules/object-sort-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAW,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAE1E,KAAK,cAAc,GAAG,MAAM,CAAC,gBAAgB,GAAG,MAAM,CAAC,aAAa,CAAC;AAIrE,UAAU,eAAe;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAYD,KAAK,QAAQ,GACT;IACE,QAAQ,EAAE,KAAK,CAAC;IAChB,WAAW,EAAE,IAAI,CAAC;CACnB,GACD;IACE,QAAQ,EAAE,IAAI,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAuEN,iBAAS,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAiBzD;
|
|
1
|
+
{"version":3,"file":"object-sort-utils.d.ts","sourceRoot":"","sources":["../../../src/rules/object-sort-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAW,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAE1E,KAAK,cAAc,GAAG,MAAM,CAAC,gBAAgB,GAAG,MAAM,CAAC,aAAa,CAAC;AAIrE,UAAU,eAAe;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAYD,UAAU,QAAQ;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAID,KAAK,QAAQ,GACT;IACE,KAAK,EAAE,IAAI,CAAC;IACZ,QAAQ,EAAE,KAAK,CAAC;IAChB,WAAW,EAAE,IAAI,CAAC;CACnB,GACD;IACE,KAAK,EAAE,IAAI,CAAC;IACZ,QAAQ,EAAE,IAAI,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB,GACD;IACE,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,QAAQ,EAAE,IAAI,CAAC;IACf,WAAW,EAAE,IAAI,CAAC;CACnB,CAAC;AAuEN,iBAAS,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAiBzD;AAyCD;;;;;;;;;GASG;AACH,iBAAS,WAAW,CAClB,IAAI,EAAE,cAAc,EACpB,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,eAAoB,GAC5B,QAAQ,GAAG,IAAI,CAuNjB;AAED,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -73,12 +73,33 @@ function sortGroup(group) {
|
|
|
73
73
|
const rest = group.filter((unit) => unit.name === null);
|
|
74
74
|
return [...sortable, ...rest];
|
|
75
75
|
}
|
|
76
|
+
function splitGroups(units) {
|
|
77
|
+
const groups = [];
|
|
78
|
+
let currentGroup = [];
|
|
79
|
+
let previousEndLine = null;
|
|
80
|
+
for (const unit of units) {
|
|
81
|
+
if (previousEndLine !== null && unit.startLine > previousEndLine + 1) {
|
|
82
|
+
groups.push(currentGroup);
|
|
83
|
+
currentGroup = [];
|
|
84
|
+
}
|
|
85
|
+
currentGroup.push(unit);
|
|
86
|
+
previousEndLine = unit.endLine;
|
|
87
|
+
}
|
|
88
|
+
if (currentGroup.length > 0) {
|
|
89
|
+
groups.push(currentGroup);
|
|
90
|
+
}
|
|
91
|
+
return groups;
|
|
92
|
+
}
|
|
93
|
+
function getEditText(units) {
|
|
94
|
+
return units.map((unit) => unit.text).join(",\n");
|
|
95
|
+
}
|
|
76
96
|
/**
|
|
77
97
|
* オブジェクトリテラル/オブジェクトパターンの並び替え計画を返します。
|
|
78
98
|
*
|
|
79
99
|
* - プロパティー名の長さが短い順、同じ長さなら名前順
|
|
80
100
|
* - 空行で区切られたグループ内だけで並び替え
|
|
81
101
|
* - プロパティー直上のコメントはプロパティーと一緒に移動
|
|
102
|
+
* - 空行を挟んだコメントはグループ見出しとしてその場に残す
|
|
82
103
|
*
|
|
83
104
|
* 並び替えが安全でない場合は null を返します。
|
|
84
105
|
*/
|
|
@@ -89,7 +110,6 @@ function getSortPlan(node, sourceCode, options = {}) {
|
|
|
89
110
|
}
|
|
90
111
|
const source = sourceCode.text;
|
|
91
112
|
const lineStarts = getLineStarts(source);
|
|
92
|
-
const lineIndent = getLineIndent(source, lineStarts, node.loc.start.line);
|
|
93
113
|
const comments = sourceCode
|
|
94
114
|
.getAllComments()
|
|
95
115
|
.filter((comment) => comment.range[0] >= node.range[0] && comment.range[1] <= node.range[1]);
|
|
@@ -111,7 +131,9 @@ function getSortPlan(node, sourceCode, options = {}) {
|
|
|
111
131
|
text: source.slice(property.range[0], property.range[1]),
|
|
112
132
|
endLine: property.loc.end.line,
|
|
113
133
|
property,
|
|
134
|
+
endOffset: property.range[1],
|
|
114
135
|
startLine: property.loc.start.line,
|
|
136
|
+
startOffset: property.range[0],
|
|
115
137
|
});
|
|
116
138
|
}
|
|
117
139
|
}
|
|
@@ -122,9 +144,10 @@ function getSortPlan(node, sourceCode, options = {}) {
|
|
|
122
144
|
const boundary = previous === null ? node.range[0] + 1 : previous.range[1];
|
|
123
145
|
const candidates = comments.filter((comment) => comment.range[0] >= boundary && comment.range[1] <= property.range[0]);
|
|
124
146
|
if (previous !== null &&
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
147
|
+
candidates.some((comment) => comment.loc.start.line === previous.loc.end.line)) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
if (candidates.some((comment) => comment.loc.start.line === node.loc.start.line)) {
|
|
128
151
|
return null;
|
|
129
152
|
}
|
|
130
153
|
const attached = [];
|
|
@@ -134,31 +157,47 @@ function getSortPlan(node, sourceCode, options = {}) {
|
|
|
134
157
|
if (comment === undefined) {
|
|
135
158
|
continue;
|
|
136
159
|
}
|
|
137
|
-
if (comment.loc.end.line
|
|
160
|
+
if (comment.loc.end.line === expectedLine) {
|
|
138
161
|
return null;
|
|
139
162
|
}
|
|
140
|
-
if (comment.loc.
|
|
141
|
-
|
|
163
|
+
if (comment.loc.end.line !== expectedLine - 1) {
|
|
164
|
+
break;
|
|
142
165
|
}
|
|
143
|
-
if (comment.loc.start.line ===
|
|
166
|
+
if (comment.loc.start.line === expectedLine) {
|
|
144
167
|
return null;
|
|
145
168
|
}
|
|
146
169
|
attached.unshift(comment);
|
|
147
170
|
expectedLine = comment.loc.start.line;
|
|
148
171
|
}
|
|
149
|
-
if (attached.length !== candidates.length) {
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
172
|
const first = attached[0] ?? property;
|
|
153
173
|
const startLine = first.loc.start.line;
|
|
154
|
-
|
|
174
|
+
let startOffset;
|
|
175
|
+
if (attached.length > 0) {
|
|
176
|
+
startOffset = lineStarts[startLine - 1] ?? first.range[0];
|
|
177
|
+
}
|
|
178
|
+
else if (startLine === previous?.loc.end.line) {
|
|
179
|
+
startOffset = property.range[0];
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
startOffset = lineStarts[startLine - 1] ?? property.range[0];
|
|
183
|
+
}
|
|
184
|
+
let endOffset = property.range[1];
|
|
185
|
+
while (endOffset > property.range[0]) {
|
|
186
|
+
const character = source[endOffset - 1];
|
|
187
|
+
if (character !== "," && character !== ";") {
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
endOffset -= 1;
|
|
191
|
+
}
|
|
155
192
|
const isRest = property.type === "RestElement";
|
|
156
193
|
units.push({
|
|
157
194
|
name: isRest ? null : getPropertyName(property),
|
|
158
|
-
text: source.slice(
|
|
195
|
+
text: source.slice(startOffset, endOffset),
|
|
159
196
|
endLine: property.loc.end.line,
|
|
160
197
|
property,
|
|
198
|
+
endOffset,
|
|
161
199
|
startLine,
|
|
200
|
+
startOffset,
|
|
162
201
|
});
|
|
163
202
|
previousProperty = property;
|
|
164
203
|
}
|
|
@@ -170,52 +209,66 @@ function getSortPlan(node, sourceCode, options = {}) {
|
|
|
170
209
|
return null;
|
|
171
210
|
}
|
|
172
211
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
212
|
+
if (inlineStart) {
|
|
213
|
+
const lineIndent = getLineIndent(source, lineStarts, node.loc.start.line);
|
|
214
|
+
const groups = splitGroups(units);
|
|
215
|
+
const needsFormat = forceMultiline;
|
|
216
|
+
const needsSort = groups.some((group) => {
|
|
217
|
+
const sorted = sortGroup(group);
|
|
218
|
+
return sorted.some((unit, index) => unit !== group[index]);
|
|
219
|
+
});
|
|
220
|
+
if (!needsSort && !needsFormat) {
|
|
221
|
+
return {
|
|
222
|
+
edits: null,
|
|
223
|
+
needsFix: false,
|
|
224
|
+
replacement: null,
|
|
225
|
+
};
|
|
180
226
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
227
|
+
if (singleLine && !forceMultiline) {
|
|
228
|
+
const sortedUnits = sortGroup(units);
|
|
229
|
+
return {
|
|
230
|
+
edits: null,
|
|
231
|
+
needsFix: true,
|
|
232
|
+
replacement: `{ ${sortedUnits.map((unit) => unit.text).join(", ")} }`,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
const groupsText = groups.map((group) => getEditText(sortGroup(group))).join(",\n\n");
|
|
236
|
+
const lastUnit = groups.flatMap((group) => sortGroup(group)).at(-1);
|
|
237
|
+
const trailingComma = lastUnit?.property.type === "RestElement" ? "" : ",";
|
|
238
|
+
return {
|
|
239
|
+
edits: null,
|
|
240
|
+
needsFix: true,
|
|
241
|
+
replacement: `{\n${groupsText}${trailingComma}\n${lineIndent}}`,
|
|
242
|
+
};
|
|
186
243
|
}
|
|
187
|
-
|
|
188
|
-
for (const group of
|
|
244
|
+
const edits = [];
|
|
245
|
+
for (const group of splitGroups(units)) {
|
|
189
246
|
const sorted = sortGroup(group);
|
|
190
|
-
if (sorted.
|
|
191
|
-
|
|
192
|
-
break;
|
|
247
|
+
if (sorted.every((unit, index) => unit === group[index])) {
|
|
248
|
+
continue;
|
|
193
249
|
}
|
|
250
|
+
const first = group[0];
|
|
251
|
+
const last = group.at(-1);
|
|
252
|
+
if (first === undefined || last === undefined) {
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
edits.push({
|
|
256
|
+
end: last.endOffset,
|
|
257
|
+
text: getEditText(sorted),
|
|
258
|
+
start: first.startOffset,
|
|
259
|
+
});
|
|
194
260
|
}
|
|
195
|
-
|
|
196
|
-
if (!needsSort && !needsFormat) {
|
|
261
|
+
if (edits.length === 0) {
|
|
197
262
|
return {
|
|
263
|
+
edits: null,
|
|
198
264
|
needsFix: false,
|
|
199
265
|
replacement: null,
|
|
200
266
|
};
|
|
201
267
|
}
|
|
202
|
-
if (singleLine && !forceMultiline) {
|
|
203
|
-
const sortedUnits = sortGroup(units);
|
|
204
|
-
return {
|
|
205
|
-
needsFix: true,
|
|
206
|
-
replacement: `{ ${sortedUnits.map((unit) => unit.text).join(", ")} }`,
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
const groupsText = groups
|
|
210
|
-
.map((group) => sortGroup(group)
|
|
211
|
-
.map((unit) => unit.text)
|
|
212
|
-
.join(",\n"))
|
|
213
|
-
.join(",\n\n");
|
|
214
|
-
const lastUnit = groups.flatMap((group) => sortGroup(group)).at(-1);
|
|
215
|
-
const trailingComma = lastUnit?.property.type === "RestElement" ? "" : ",";
|
|
216
268
|
return {
|
|
269
|
+
edits,
|
|
217
270
|
needsFix: true,
|
|
218
|
-
replacement:
|
|
271
|
+
replacement: null,
|
|
219
272
|
};
|
|
220
273
|
}
|
|
221
274
|
export { getSortPlan, compareNames };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overload-signatures-adjacent.d.ts","sourceRoot":"","sources":["../../../src/rules/overload-signatures-adjacent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"overload-signatures-adjacent.d.ts","sourceRoot":"","sources":["../../../src/rules/overload-signatures-adjacent.ts"],"names":[],"mappings":"AAuEA;;GAEG;AACH,QAAA,MAAM,0BAA0B,uCAqG9B,CAAC;eAEY,0BAA0B"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineRule } from "vite-plus/lint/plugins";
|
|
2
|
-
import { getNextStatement } from "./blank-line.js";
|
|
2
|
+
import { getNextStatement, getRemoveBlankLineFix } from "./blank-line.js";
|
|
3
3
|
function getFunction(node) {
|
|
4
4
|
if (node.type === "FunctionDeclaration" || node.type === "TSDeclareFunction") {
|
|
5
5
|
return node;
|
|
@@ -25,21 +25,6 @@ function getKeyName(node) {
|
|
|
25
25
|
}
|
|
26
26
|
return null;
|
|
27
27
|
}
|
|
28
|
-
function getRemoveBlankLinesFix(fixer, sourceCode, previous, next) {
|
|
29
|
-
if (next.loc.start.line <= previous.loc.end.line + 1) {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
const fromLineEnd = sourceCode.text.indexOf("\n", previous.range[1]);
|
|
33
|
-
if (fromLineEnd === -1) {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
const nextLineStart = sourceCode.text.lastIndexOf("\n", next.range[0]) + 1;
|
|
37
|
-
const indent = sourceCode.text.slice(nextLineStart, next.range[0]);
|
|
38
|
-
if (indent.trim() !== "") {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
return fixer.replaceTextRange([fromLineEnd, next.range[0]], `\n${indent}`);
|
|
42
|
-
}
|
|
43
28
|
function hasCommentBetween(sourceCode, previous, next) {
|
|
44
29
|
return sourceCode
|
|
45
30
|
.getAllComments()
|
|
@@ -52,7 +37,7 @@ function reportIfSeparated(context, sourceCode, previous, next) {
|
|
|
52
37
|
}
|
|
53
38
|
context.report({
|
|
54
39
|
fix(fixer) {
|
|
55
|
-
return
|
|
40
|
+
return getRemoveBlankLineFix(fixer, sourceCode, previous, next);
|
|
56
41
|
},
|
|
57
42
|
node: next,
|
|
58
43
|
messageId: "adjacent",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sort-jsx-props.d.ts","sourceRoot":"","sources":["../../../src/rules/sort-jsx-props.ts"],"names":[],"mappings":"AAsEA;;;GAGG;AACH,QAAA,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"sort-jsx-props.d.ts","sourceRoot":"","sources":["../../../src/rules/sort-jsx-props.ts"],"names":[],"mappings":"AAsEA;;;GAGG;AACH,QAAA,MAAM,YAAY,uCAuEhB,CAAC;eAEY,YAAY"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* オブジェクトリテラルのプロパティーを、名前の長さが短い順、同じ長さなら名前順に並べます。
|
|
3
3
|
*
|
|
4
4
|
* 空行で区切られたグループは意図的なまとまりとみなし、グループ内だけで並べ替えます。
|
|
5
|
-
*
|
|
5
|
+
* プロパティー直上のコメントはプロパティーと一緒に移動し、空行を挟んだコメントはグループ見出しとして残します。
|
|
6
6
|
*/
|
|
7
7
|
declare const sortObjectProperties: import("vite-plus/lint/plugins").Rule;
|
|
8
8
|
export default sortObjectProperties;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sort-object-properties.d.ts","sourceRoot":"","sources":["../../../src/rules/sort-object-properties.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,QAAA,MAAM,oBAAoB,
|
|
1
|
+
{"version":3,"file":"sort-object-properties.d.ts","sourceRoot":"","sources":["../../../src/rules/sort-object-properties.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,QAAA,MAAM,oBAAoB,uCA6DxB,CAAC;eAEY,oBAAoB"}
|
|
@@ -4,7 +4,7 @@ import { getSortPlan } from "./object-sort-utils.js";
|
|
|
4
4
|
* オブジェクトリテラルのプロパティーを、名前の長さが短い順、同じ長さなら名前順に並べます。
|
|
5
5
|
*
|
|
6
6
|
* 空行で区切られたグループは意図的なまとまりとみなし、グループ内だけで並べ替えます。
|
|
7
|
-
*
|
|
7
|
+
* プロパティー直上のコメントはプロパティーと一緒に移動し、空行を挟んだコメントはグループ見出しとして残します。
|
|
8
8
|
*/
|
|
9
9
|
const sortObjectProperties = defineRule({
|
|
10
10
|
meta: {
|
|
@@ -29,6 +29,9 @@ const sortObjectProperties = defineRule({
|
|
|
29
29
|
}
|
|
30
30
|
context.report({
|
|
31
31
|
fix(fixer) {
|
|
32
|
+
if (plan.edits !== null) {
|
|
33
|
+
return plan.edits.map((edit) => fixer.replaceTextRange([edit.start, edit.end], edit.text));
|
|
34
|
+
}
|
|
32
35
|
return fixer.replaceText(node, plan.replacement);
|
|
33
36
|
},
|
|
34
37
|
node,
|
|
@@ -42,6 +45,9 @@ const sortObjectProperties = defineRule({
|
|
|
42
45
|
}
|
|
43
46
|
context.report({
|
|
44
47
|
fix(fixer) {
|
|
48
|
+
if (plan.edits !== null) {
|
|
49
|
+
return plan.edits.map((edit) => fixer.replaceTextRange([edit.start, edit.end], edit.text));
|
|
50
|
+
}
|
|
45
51
|
return fixer.replaceText(node, plan.replacement);
|
|
46
52
|
},
|
|
47
53
|
node,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spaced-comment.d.ts","sourceRoot":"","sources":["../../../src/rules/spaced-comment.ts"],"names":[],"mappings":"AAyBA;;GAEG;AACH,QAAA,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"spaced-comment.d.ts","sourceRoot":"","sources":["../../../src/rules/spaced-comment.ts"],"names":[],"mappings":"AAyBA;;GAEG;AACH,QAAA,MAAM,aAAa,uCAgGjB,CAAC;eAEY,aAAa"}
|
package/package.json
CHANGED
|
@@ -1,69 +1,150 @@
|
|
|
1
1
|
import { defineRule } from "vite-plus/lint/plugins";
|
|
2
|
-
import type { ESTree } from "vite-plus/lint/plugins";
|
|
2
|
+
import type { ESTree, Variable } from "vite-plus/lint/plugins";
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
hasBlankLine,
|
|
6
6
|
getBlankLineFix,
|
|
7
7
|
getNextStatement,
|
|
8
8
|
getInsertionTarget,
|
|
9
|
+
getPreviousStatement,
|
|
10
|
+
getRemoveBlankLineFix,
|
|
9
11
|
} from "./blank-line.js";
|
|
10
12
|
|
|
11
|
-
function
|
|
13
|
+
function getVariableDeclaration(node: ESTree.Node): ESTree.VariableDeclaration | null {
|
|
12
14
|
if (node.type === "VariableDeclaration") {
|
|
13
|
-
return
|
|
15
|
+
return node;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
if (node.type === "ExportNamedDeclaration" && node.declaration?.type === "VariableDeclaration") {
|
|
19
|
+
return node.declaration;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function isRelatedExpression(
|
|
26
|
+
statement: ESTree.Statement,
|
|
27
|
+
variables: ReadonlySet<Variable>,
|
|
28
|
+
): boolean {
|
|
29
|
+
if (statement.type !== "ExpressionStatement") {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
for (const variable of variables) {
|
|
34
|
+
for (const reference of variable.references) {
|
|
35
|
+
if (
|
|
36
|
+
reference.identifier.range[0] >= statement.range[0] &&
|
|
37
|
+
reference.identifier.range[1] <= statement.range[1]
|
|
38
|
+
) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return false;
|
|
17
45
|
}
|
|
18
46
|
|
|
19
47
|
/**
|
|
20
48
|
* 連続する変数宣言の後に別の種類の文が続く場合、空行を 1 行以上確保します。
|
|
21
49
|
*
|
|
50
|
+
* 宣言した変数を使う式文は同じ宣言グループとして扱い、グループ内の空行は削除します。
|
|
22
51
|
* return の直前は blank-line-before-return が担当するため対象外にします。
|
|
23
52
|
*/
|
|
24
53
|
const blankLineAfterVariableDeclaration = defineRule({
|
|
25
54
|
meta: {
|
|
26
55
|
docs: {
|
|
27
56
|
description:
|
|
28
|
-
"Require a blank line after a variable declaration group
|
|
57
|
+
"Require a blank line after a variable declaration group and remove blank lines before related statements.",
|
|
29
58
|
},
|
|
30
59
|
type: "layout",
|
|
31
60
|
fixable: "whitespace",
|
|
32
61
|
messages: {
|
|
33
62
|
blankLine:
|
|
34
63
|
"Expected a blank line after a variable declaration group when another statement follows.",
|
|
64
|
+
unexpectedBlankLine:
|
|
65
|
+
"Expected no blank line between a variable declaration and its related statement.",
|
|
35
66
|
},
|
|
36
67
|
},
|
|
37
68
|
create(context) {
|
|
38
69
|
const sourceCode = context.sourceCode;
|
|
39
70
|
|
|
40
71
|
function checkStatement(node: ESTree.Node): void {
|
|
72
|
+
const variableDeclaration = getVariableDeclaration(node);
|
|
73
|
+
|
|
74
|
+
if (variableDeclaration === null) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
41
78
|
if (node.type === "VariableDeclaration" && node.parent.type === "ExportNamedDeclaration") {
|
|
42
79
|
return;
|
|
43
80
|
}
|
|
44
81
|
|
|
45
|
-
const
|
|
82
|
+
const previousStatement = getPreviousStatement(node);
|
|
83
|
+
|
|
84
|
+
if (previousStatement !== null && getVariableDeclaration(previousStatement) !== null) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const variables = new Set<Variable>(sourceCode.getDeclaredVariables(variableDeclaration));
|
|
89
|
+
let last = node;
|
|
90
|
+
let nextStatement = getNextStatement(last);
|
|
91
|
+
|
|
92
|
+
while (nextStatement !== null) {
|
|
93
|
+
const nextVariableDeclaration = getVariableDeclaration(nextStatement);
|
|
94
|
+
|
|
95
|
+
if (nextVariableDeclaration !== null && getVariableDeclaration(last) !== null) {
|
|
96
|
+
for (const variable of sourceCode.getDeclaredVariables(nextVariableDeclaration)) {
|
|
97
|
+
variables.add(variable);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
last = nextStatement;
|
|
101
|
+
nextStatement = getNextStatement(last);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (
|
|
106
|
+
nextStatement.type === "ExpressionStatement" &&
|
|
107
|
+
isRelatedExpression(nextStatement, variables)
|
|
108
|
+
) {
|
|
109
|
+
const target = getInsertionTarget(last, nextStatement, sourceCode);
|
|
110
|
+
|
|
111
|
+
if (hasBlankLine(last, target)) {
|
|
112
|
+
context.report({
|
|
113
|
+
fix(fixer) {
|
|
114
|
+
return getRemoveBlankLineFix(fixer, sourceCode, last, target);
|
|
115
|
+
},
|
|
116
|
+
node: nextStatement,
|
|
117
|
+
messageId: "unexpectedBlankLine",
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
last = nextStatement;
|
|
122
|
+
nextStatement = getNextStatement(last);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
46
128
|
|
|
47
129
|
if (
|
|
48
130
|
nextStatement === null ||
|
|
49
131
|
nextStatement.type === "EmptyStatement" ||
|
|
50
|
-
nextStatement.type === "ReturnStatement"
|
|
51
|
-
isVariableDeclarationStatement(nextStatement)
|
|
132
|
+
nextStatement.type === "ReturnStatement"
|
|
52
133
|
) {
|
|
53
134
|
return;
|
|
54
135
|
}
|
|
55
136
|
|
|
56
|
-
const target = getInsertionTarget(
|
|
137
|
+
const target = getInsertionTarget(last, nextStatement, sourceCode);
|
|
57
138
|
|
|
58
|
-
if (hasBlankLine(
|
|
139
|
+
if (hasBlankLine(last, target)) {
|
|
59
140
|
return;
|
|
60
141
|
}
|
|
61
142
|
|
|
62
143
|
context.report({
|
|
63
144
|
fix(fixer) {
|
|
64
|
-
return getBlankLineFix(fixer, sourceCode,
|
|
145
|
+
return getBlankLineFix(fixer, sourceCode, last, target);
|
|
65
146
|
},
|
|
66
|
-
node,
|
|
147
|
+
node: nextStatement,
|
|
67
148
|
messageId: "blankLine",
|
|
68
149
|
});
|
|
69
150
|
}
|
package/src/rules/blank-line.ts
CHANGED
|
@@ -104,10 +104,40 @@ function getBlankLineFix(
|
|
|
104
104
|
return fixer.insertTextBeforeRange([lineEnd, lineEnd + 1], "\n");
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
/**
|
|
108
|
+
* 指定したノードと対象の間の空行を削除します。
|
|
109
|
+
*/
|
|
110
|
+
function getRemoveBlankLineFix(
|
|
111
|
+
fixer: Fixer,
|
|
112
|
+
sourceCode: SourceCode,
|
|
113
|
+
node: ESTree.Node,
|
|
114
|
+
target: ESTree.Node | Comment,
|
|
115
|
+
): Fix | null {
|
|
116
|
+
if (target.loc.start.line <= node.loc.end.line + 1) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const fromLineEnd = sourceCode.text.indexOf("\n", node.range[1]);
|
|
121
|
+
|
|
122
|
+
if (fromLineEnd === -1) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const targetLineStart = sourceCode.text.lastIndexOf("\n", target.range[0]) + 1;
|
|
127
|
+
const indent = sourceCode.text.slice(targetLineStart, target.range[0]);
|
|
128
|
+
|
|
129
|
+
if (indent.trim() !== "") {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return fixer.replaceTextRange([fromLineEnd, target.range[0]], `\n${indent}`);
|
|
134
|
+
}
|
|
135
|
+
|
|
107
136
|
export {
|
|
108
137
|
hasBlankLine,
|
|
109
138
|
getBlankLineFix,
|
|
110
139
|
getNextStatement,
|
|
111
140
|
getInsertionTarget,
|
|
112
141
|
getPreviousStatement,
|
|
142
|
+
getRemoveBlankLineFix,
|
|
113
143
|
};
|
|
@@ -129,7 +129,6 @@ function collectDiagnostics(
|
|
|
129
129
|
if (next !== undefined && next !== null && canContinue(content, next)) {
|
|
130
130
|
const nextLeadingSpace = /^\s*/u.exec(next.content)?.[0] ?? "";
|
|
131
131
|
const separator = nextLeadingSpace === "" && needsSpace(content, next.content) ? " " : "";
|
|
132
|
-
|
|
133
132
|
fixes.push({
|
|
134
133
|
end: next.start,
|
|
135
134
|
loc: {
|
|
@@ -145,6 +144,7 @@ function collectDiagnostics(
|
|
|
145
144
|
text: separator,
|
|
146
145
|
start: info.end,
|
|
147
146
|
});
|
|
147
|
+
|
|
148
148
|
continue;
|
|
149
149
|
}
|
|
150
150
|
|
|
@@ -205,7 +205,6 @@ const commentOneSentencePerLine = defineRule({
|
|
|
205
205
|
|
|
206
206
|
for (const info of diagnostics.missingPunctuation) {
|
|
207
207
|
const column = info.column + info.content.trimEnd().length;
|
|
208
|
-
|
|
209
208
|
context.report({
|
|
210
209
|
loc: {
|
|
211
210
|
end: {
|
package/src/rules/jsdoc-utils.ts
CHANGED
|
@@ -101,13 +101,13 @@ function getJSDocLines(comment: Comment, sourceCode: SourceCode): JSDocLine[] |
|
|
|
101
101
|
const closeIndex = line.lastIndexOf("*/");
|
|
102
102
|
const contentEnd = closeIndex === -1 ? line.length : Math.max(contentStart, closeIndex);
|
|
103
103
|
const content = line.slice(contentStart, contentEnd);
|
|
104
|
-
|
|
105
104
|
lines.push({
|
|
106
105
|
raw: line,
|
|
107
106
|
prefix: line.slice(0, contentStart),
|
|
108
107
|
content,
|
|
109
108
|
tagName: getTagName(content),
|
|
110
109
|
});
|
|
110
|
+
|
|
111
111
|
continue;
|
|
112
112
|
}
|
|
113
113
|
|
|
@@ -122,7 +122,6 @@ function getJSDocLines(comment: Comment, sourceCode: SourceCode): JSDocLine[] |
|
|
|
122
122
|
const closeIndex = line.lastIndexOf("*/");
|
|
123
123
|
const contentEnd = closeIndex === -1 ? line.length : Math.max(contentStart, closeIndex);
|
|
124
124
|
const content = line.slice(contentStart, contentEnd);
|
|
125
|
-
|
|
126
125
|
lines.push({
|
|
127
126
|
raw: line,
|
|
128
127
|
prefix,
|
|
@@ -18,9 +18,17 @@ interface SortPlanOptions {
|
|
|
18
18
|
|
|
19
19
|
interface SortUnit {
|
|
20
20
|
endLine: number;
|
|
21
|
+
endOffset: number;
|
|
21
22
|
name: string | null;
|
|
22
23
|
property: SortableProperty;
|
|
23
24
|
startLine: number;
|
|
25
|
+
startOffset: number;
|
|
26
|
+
text: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface SortEdit {
|
|
30
|
+
end: number;
|
|
31
|
+
start: number;
|
|
24
32
|
text: string;
|
|
25
33
|
}
|
|
26
34
|
|
|
@@ -28,12 +36,19 @@ type NamedSortUnit = SortUnit & { name: string };
|
|
|
28
36
|
|
|
29
37
|
type SortPlan =
|
|
30
38
|
| {
|
|
39
|
+
edits: null;
|
|
31
40
|
needsFix: false;
|
|
32
41
|
replacement: null;
|
|
33
42
|
}
|
|
34
43
|
| {
|
|
44
|
+
edits: null;
|
|
35
45
|
needsFix: true;
|
|
36
46
|
replacement: string;
|
|
47
|
+
}
|
|
48
|
+
| {
|
|
49
|
+
edits: SortEdit[];
|
|
50
|
+
needsFix: true;
|
|
51
|
+
replacement: null;
|
|
37
52
|
};
|
|
38
53
|
|
|
39
54
|
function getLineStarts(text: string): number[] {
|
|
@@ -130,19 +145,46 @@ function compareUnits(left: NamedSortUnit, right: NamedSortUnit): number {
|
|
|
130
145
|
|
|
131
146
|
function sortGroup(group: readonly SortUnit[]): SortUnit[] {
|
|
132
147
|
const sortable = group.filter((unit): unit is NamedSortUnit => unit.name !== null);
|
|
133
|
-
|
|
134
148
|
sortable.sort(compareUnits);
|
|
149
|
+
|
|
135
150
|
const rest = group.filter((unit) => unit.name === null);
|
|
136
151
|
|
|
137
152
|
return [...sortable, ...rest];
|
|
138
153
|
}
|
|
139
154
|
|
|
155
|
+
function splitGroups(units: readonly SortUnit[]): SortUnit[][] {
|
|
156
|
+
const groups: SortUnit[][] = [];
|
|
157
|
+
let currentGroup: SortUnit[] = [];
|
|
158
|
+
let previousEndLine: number | null = null;
|
|
159
|
+
|
|
160
|
+
for (const unit of units) {
|
|
161
|
+
if (previousEndLine !== null && unit.startLine > previousEndLine + 1) {
|
|
162
|
+
groups.push(currentGroup);
|
|
163
|
+
currentGroup = [];
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
currentGroup.push(unit);
|
|
167
|
+
previousEndLine = unit.endLine;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (currentGroup.length > 0) {
|
|
171
|
+
groups.push(currentGroup);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return groups;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function getEditText(units: readonly SortUnit[]): string {
|
|
178
|
+
return units.map((unit) => unit.text).join(",\n");
|
|
179
|
+
}
|
|
180
|
+
|
|
140
181
|
/**
|
|
141
182
|
* オブジェクトリテラル/オブジェクトパターンの並び替え計画を返します。
|
|
142
183
|
*
|
|
143
184
|
* - プロパティー名の長さが短い順、同じ長さなら名前順
|
|
144
185
|
* - 空行で区切られたグループ内だけで並び替え
|
|
145
186
|
* - プロパティー直上のコメントはプロパティーと一緒に移動
|
|
187
|
+
* - 空行を挟んだコメントはグループ見出しとしてその場に残す
|
|
146
188
|
*
|
|
147
189
|
* 並び替えが安全でない場合は null を返します。
|
|
148
190
|
*/
|
|
@@ -159,7 +201,6 @@ function getSortPlan(
|
|
|
159
201
|
|
|
160
202
|
const source = sourceCode.text;
|
|
161
203
|
const lineStarts = getLineStarts(source);
|
|
162
|
-
const lineIndent = getLineIndent(source, lineStarts, node.loc.start.line);
|
|
163
204
|
const comments = sourceCode
|
|
164
205
|
.getAllComments()
|
|
165
206
|
.filter((comment) => comment.range[0] >= node.range[0] && comment.range[1] <= node.range[1]);
|
|
@@ -171,7 +212,6 @@ function getSortPlan(
|
|
|
171
212
|
|
|
172
213
|
const inlineStart = firstProperty.loc.start.line === node.loc.start.line;
|
|
173
214
|
const singleLine = node.loc.start.line === node.loc.end.line;
|
|
174
|
-
|
|
175
215
|
const units: SortUnit[] = [];
|
|
176
216
|
|
|
177
217
|
if (inlineStart) {
|
|
@@ -181,13 +221,14 @@ function getSortPlan(
|
|
|
181
221
|
|
|
182
222
|
for (const property of node.properties) {
|
|
183
223
|
const isRest = property.type === "RestElement";
|
|
184
|
-
|
|
185
224
|
units.push({
|
|
186
225
|
name: isRest ? null : getPropertyName(property),
|
|
187
226
|
text: source.slice(property.range[0], property.range[1]),
|
|
188
227
|
endLine: property.loc.end.line,
|
|
189
228
|
property,
|
|
229
|
+
endOffset: property.range[1],
|
|
190
230
|
startLine: property.loc.start.line,
|
|
231
|
+
startOffset: property.range[0],
|
|
191
232
|
});
|
|
192
233
|
}
|
|
193
234
|
} else {
|
|
@@ -202,16 +243,15 @@ function getSortPlan(
|
|
|
202
243
|
|
|
203
244
|
if (
|
|
204
245
|
previous !== null &&
|
|
205
|
-
|
|
206
|
-
(comment) =>
|
|
207
|
-
comment.loc.start.line === previous.loc.end.line &&
|
|
208
|
-
comment.range[0] >= previous.range[1] &&
|
|
209
|
-
comment.range[1] <= property.range[0],
|
|
210
|
-
)
|
|
246
|
+
candidates.some((comment) => comment.loc.start.line === previous.loc.end.line)
|
|
211
247
|
) {
|
|
212
248
|
return null;
|
|
213
249
|
}
|
|
214
250
|
|
|
251
|
+
if (candidates.some((comment) => comment.loc.start.line === node.loc.start.line)) {
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
|
|
215
255
|
const attached: Comment[] = [];
|
|
216
256
|
let expectedLine = property.loc.start.line;
|
|
217
257
|
|
|
@@ -222,15 +262,15 @@ function getSortPlan(
|
|
|
222
262
|
continue;
|
|
223
263
|
}
|
|
224
264
|
|
|
225
|
-
if (comment.loc.end.line
|
|
265
|
+
if (comment.loc.end.line === expectedLine) {
|
|
226
266
|
return null;
|
|
227
267
|
}
|
|
228
268
|
|
|
229
|
-
if (comment.loc.
|
|
230
|
-
|
|
269
|
+
if (comment.loc.end.line !== expectedLine - 1) {
|
|
270
|
+
break;
|
|
231
271
|
}
|
|
232
272
|
|
|
233
|
-
if (comment.loc.start.line ===
|
|
273
|
+
if (comment.loc.start.line === expectedLine) {
|
|
234
274
|
return null;
|
|
235
275
|
}
|
|
236
276
|
|
|
@@ -238,22 +278,41 @@ function getSortPlan(
|
|
|
238
278
|
expectedLine = comment.loc.start.line;
|
|
239
279
|
}
|
|
240
280
|
|
|
241
|
-
if (attached.length !== candidates.length) {
|
|
242
|
-
return null;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
281
|
const first = attached[0] ?? property;
|
|
246
282
|
const startLine = first.loc.start.line;
|
|
247
|
-
|
|
248
|
-
|
|
283
|
+
let startOffset: number;
|
|
284
|
+
|
|
285
|
+
if (attached.length > 0) {
|
|
286
|
+
startOffset = lineStarts[startLine - 1] ?? first.range[0];
|
|
287
|
+
} else if (startLine === previous?.loc.end.line) {
|
|
288
|
+
startOffset = property.range[0];
|
|
289
|
+
} else {
|
|
290
|
+
startOffset = lineStarts[startLine - 1] ?? property.range[0];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
let endOffset = property.range[1];
|
|
294
|
+
|
|
295
|
+
while (endOffset > property.range[0]) {
|
|
296
|
+
const character = source[endOffset - 1];
|
|
297
|
+
|
|
298
|
+
if (character !== "," && character !== ";") {
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
249
301
|
|
|
302
|
+
endOffset -= 1;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const isRest = property.type === "RestElement";
|
|
250
306
|
units.push({
|
|
251
307
|
name: isRest ? null : getPropertyName(property),
|
|
252
|
-
text: source.slice(
|
|
308
|
+
text: source.slice(startOffset, endOffset),
|
|
253
309
|
endLine: property.loc.end.line,
|
|
254
310
|
property,
|
|
311
|
+
endOffset,
|
|
255
312
|
startLine,
|
|
313
|
+
startOffset,
|
|
256
314
|
});
|
|
315
|
+
|
|
257
316
|
previousProperty = property;
|
|
258
317
|
}
|
|
259
318
|
|
|
@@ -273,66 +332,80 @@ function getSortPlan(
|
|
|
273
332
|
}
|
|
274
333
|
}
|
|
275
334
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
335
|
+
if (inlineStart) {
|
|
336
|
+
const lineIndent = getLineIndent(source, lineStarts, node.loc.start.line);
|
|
337
|
+
const groups = splitGroups(units);
|
|
338
|
+
const needsFormat = forceMultiline;
|
|
339
|
+
const needsSort = groups.some((group) => {
|
|
340
|
+
const sorted = sortGroup(group);
|
|
341
|
+
|
|
342
|
+
return sorted.some((unit, index) => unit !== group[index]);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
if (!needsSort && !needsFormat) {
|
|
346
|
+
return {
|
|
347
|
+
edits: null,
|
|
348
|
+
needsFix: false,
|
|
349
|
+
replacement: null,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
279
352
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
353
|
+
if (singleLine && !forceMultiline) {
|
|
354
|
+
const sortedUnits = sortGroup(units);
|
|
355
|
+
|
|
356
|
+
return {
|
|
357
|
+
edits: null,
|
|
358
|
+
needsFix: true,
|
|
359
|
+
replacement: `{ ${sortedUnits.map((unit) => unit.text).join(", ")} }`,
|
|
360
|
+
};
|
|
284
361
|
}
|
|
285
362
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
363
|
+
const groupsText = groups.map((group) => getEditText(sortGroup(group))).join(",\n\n");
|
|
364
|
+
const lastUnit = groups.flatMap((group) => sortGroup(group)).at(-1);
|
|
365
|
+
const trailingComma = lastUnit?.property.type === "RestElement" ? "" : ",";
|
|
289
366
|
|
|
290
|
-
|
|
291
|
-
|
|
367
|
+
return {
|
|
368
|
+
edits: null,
|
|
369
|
+
needsFix: true,
|
|
370
|
+
replacement: `{\n${groupsText}${trailingComma}\n${lineIndent}}`,
|
|
371
|
+
};
|
|
292
372
|
}
|
|
293
373
|
|
|
294
|
-
|
|
374
|
+
const edits: SortEdit[] = [];
|
|
295
375
|
|
|
296
|
-
for (const group of
|
|
376
|
+
for (const group of splitGroups(units)) {
|
|
297
377
|
const sorted = sortGroup(group);
|
|
298
378
|
|
|
299
|
-
if (sorted.
|
|
300
|
-
|
|
301
|
-
break;
|
|
379
|
+
if (sorted.every((unit, index) => unit === group[index])) {
|
|
380
|
+
continue;
|
|
302
381
|
}
|
|
303
|
-
}
|
|
304
382
|
|
|
305
|
-
|
|
383
|
+
const first = group[0];
|
|
384
|
+
const last = group.at(-1);
|
|
306
385
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
replacement: null,
|
|
311
|
-
};
|
|
312
|
-
}
|
|
386
|
+
if (first === undefined || last === undefined) {
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
313
389
|
|
|
314
|
-
|
|
315
|
-
|
|
390
|
+
edits.push({
|
|
391
|
+
end: last.endOffset,
|
|
392
|
+
text: getEditText(sorted),
|
|
393
|
+
start: first.startOffset,
|
|
394
|
+
});
|
|
395
|
+
}
|
|
316
396
|
|
|
397
|
+
if (edits.length === 0) {
|
|
317
398
|
return {
|
|
318
|
-
|
|
319
|
-
|
|
399
|
+
edits: null,
|
|
400
|
+
needsFix: false,
|
|
401
|
+
replacement: null,
|
|
320
402
|
};
|
|
321
403
|
}
|
|
322
404
|
|
|
323
|
-
const groupsText = groups
|
|
324
|
-
.map((group) =>
|
|
325
|
-
sortGroup(group)
|
|
326
|
-
.map((unit) => unit.text)
|
|
327
|
-
.join(",\n"),
|
|
328
|
-
)
|
|
329
|
-
.join(",\n\n");
|
|
330
|
-
const lastUnit = groups.flatMap((group) => sortGroup(group)).at(-1);
|
|
331
|
-
const trailingComma = lastUnit?.property.type === "RestElement" ? "" : ",";
|
|
332
|
-
|
|
333
405
|
return {
|
|
406
|
+
edits,
|
|
334
407
|
needsFix: true,
|
|
335
|
-
replacement:
|
|
408
|
+
replacement: null,
|
|
336
409
|
};
|
|
337
410
|
}
|
|
338
411
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineRule } from "vite-plus/lint/plugins";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ESTree, Context, SourceCode } from "vite-plus/lint/plugins";
|
|
3
3
|
|
|
4
|
-
import { getNextStatement } from "./blank-line.js";
|
|
4
|
+
import { getNextStatement, getRemoveBlankLineFix } from "./blank-line.js";
|
|
5
5
|
|
|
6
6
|
function getFunction(node: ESTree.Node): ESTree.Function | null {
|
|
7
7
|
if (node.type === "FunctionDeclaration" || node.type === "TSDeclareFunction") {
|
|
@@ -37,32 +37,6 @@ function getKeyName(node: ESTree.MethodDefinition): string | null {
|
|
|
37
37
|
return null;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
function getRemoveBlankLinesFix(
|
|
41
|
-
fixer: Fixer,
|
|
42
|
-
sourceCode: SourceCode,
|
|
43
|
-
previous: ESTree.Node,
|
|
44
|
-
next: ESTree.Node,
|
|
45
|
-
): Fix | null {
|
|
46
|
-
if (next.loc.start.line <= previous.loc.end.line + 1) {
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const fromLineEnd = sourceCode.text.indexOf("\n", previous.range[1]);
|
|
51
|
-
|
|
52
|
-
if (fromLineEnd === -1) {
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const nextLineStart = sourceCode.text.lastIndexOf("\n", next.range[0]) + 1;
|
|
57
|
-
const indent = sourceCode.text.slice(nextLineStart, next.range[0]);
|
|
58
|
-
|
|
59
|
-
if (indent.trim() !== "") {
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return fixer.replaceTextRange([fromLineEnd, next.range[0]], `\n${indent}`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
40
|
function hasCommentBetween(
|
|
67
41
|
sourceCode: SourceCode,
|
|
68
42
|
previous: ESTree.Node,
|
|
@@ -88,7 +62,7 @@ function reportIfSeparated(
|
|
|
88
62
|
|
|
89
63
|
context.report({
|
|
90
64
|
fix(fixer) {
|
|
91
|
-
return
|
|
65
|
+
return getRemoveBlankLineFix(fixer, sourceCode, previous, next);
|
|
92
66
|
},
|
|
93
67
|
node: next,
|
|
94
68
|
messageId: "adjacent",
|
|
@@ -6,7 +6,7 @@ import { getSortPlan } from "./object-sort-utils.js";
|
|
|
6
6
|
* オブジェクトリテラルのプロパティーを、名前の長さが短い順、同じ長さなら名前順に並べます。
|
|
7
7
|
*
|
|
8
8
|
* 空行で区切られたグループは意図的なまとまりとみなし、グループ内だけで並べ替えます。
|
|
9
|
-
*
|
|
9
|
+
* プロパティー直上のコメントはプロパティーと一緒に移動し、空行を挟んだコメントはグループ見出しとして残します。
|
|
10
10
|
*/
|
|
11
11
|
const sortObjectProperties = defineRule({
|
|
12
12
|
meta: {
|
|
@@ -34,6 +34,12 @@ const sortObjectProperties = defineRule({
|
|
|
34
34
|
|
|
35
35
|
context.report({
|
|
36
36
|
fix(fixer) {
|
|
37
|
+
if (plan.edits !== null) {
|
|
38
|
+
return plan.edits.map((edit) =>
|
|
39
|
+
fixer.replaceTextRange([edit.start, edit.end], edit.text),
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
37
43
|
return fixer.replaceText(node, plan.replacement);
|
|
38
44
|
},
|
|
39
45
|
node,
|
|
@@ -49,6 +55,12 @@ const sortObjectProperties = defineRule({
|
|
|
49
55
|
|
|
50
56
|
context.report({
|
|
51
57
|
fix(fixer) {
|
|
58
|
+
if (plan.edits !== null) {
|
|
59
|
+
return plan.edits.map((edit) =>
|
|
60
|
+
fixer.replaceTextRange([edit.start, edit.end], edit.text),
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
52
64
|
return fixer.replaceText(node, plan.replacement);
|
|
53
65
|
},
|
|
54
66
|
node,
|
|
@@ -176,8 +176,8 @@ function splitGroups(units: readonly MemberUnit[]): MemberUnit[][] {
|
|
|
176
176
|
|
|
177
177
|
function sortGroup(group: readonly MemberUnit[]): MemberUnit[] {
|
|
178
178
|
const sortable = group.filter((unit): unit is NamedUnit => unit.name !== null);
|
|
179
|
-
|
|
180
179
|
sortable.sort((left, right) => compareNames(left.name, right.name));
|
|
180
|
+
|
|
181
181
|
const rest = group.filter((unit) => unit.name === null);
|
|
182
182
|
|
|
183
183
|
return [...sortable, ...rest];
|
|
@@ -70,7 +70,6 @@ const spacedComment = defineRule({
|
|
|
70
70
|
const contentStart = prefixLength;
|
|
71
71
|
const contentEnd = raw.lastIndexOf("*/");
|
|
72
72
|
const content = raw.slice(contentStart, contentEnd);
|
|
73
|
-
|
|
74
73
|
needsLeading = content !== "" && !isWhitespace(content[0]);
|
|
75
74
|
needsTrailing = content !== "" && !isWhitespace(content.at(-1));
|
|
76
75
|
} else {
|
|
@@ -79,7 +78,6 @@ const spacedComment = defineRule({
|
|
|
79
78
|
const leadingContent = firstLine.slice(prefixLength);
|
|
80
79
|
const closeIndex = lastLine.lastIndexOf("*/");
|
|
81
80
|
const trailingContent = lastLine.slice(0, closeIndex);
|
|
82
|
-
|
|
83
81
|
needsLeading = leadingContent !== "" && !isWhitespace(leadingContent[0]);
|
|
84
82
|
needsTrailing = trailingContent !== "" && !isWhitespace(trailingContent.at(-1));
|
|
85
83
|
}
|