@tai-kun/vp-lint-plugins 0.0.0 → 0.0.1

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 (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -43
  3. package/dist/src/index.d.ts +22 -0
  4. package/dist/src/index.d.ts.map +1 -0
  5. package/dist/src/index.js +21 -0
  6. package/dist/src/plugin.d.ts +3 -0
  7. package/dist/src/plugin.d.ts.map +1 -0
  8. package/dist/src/plugin.js +46 -0
  9. package/dist/src/rules/blank-line-after-control-block.d.ts +7 -0
  10. package/dist/src/rules/blank-line-after-control-block.d.ts.map +1 -0
  11. package/dist/src/rules/blank-line-after-control-block.js +54 -0
  12. package/dist/src/rules/blank-line-after-declaration.d.ts +7 -0
  13. package/dist/src/rules/blank-line-after-declaration.d.ts.map +1 -0
  14. package/dist/src/rules/blank-line-after-declaration.js +79 -0
  15. package/dist/src/rules/blank-line-after-variable-declaration.d.ts +8 -0
  16. package/dist/src/rules/blank-line-after-variable-declaration.d.ts.map +1 -0
  17. package/dist/src/rules/blank-line-after-variable-declaration.js +62 -0
  18. package/dist/src/rules/blank-line-before-return.d.ts +7 -0
  19. package/dist/src/rules/blank-line-before-return.d.ts.map +1 -0
  20. package/dist/src/rules/blank-line-before-return.js +81 -0
  21. package/dist/src/rules/blank-line-between-class-members.d.ts +8 -0
  22. package/dist/src/rules/blank-line-between-class-members.d.ts.map +1 -0
  23. package/dist/src/rules/blank-line-between-class-members.js +85 -0
  24. package/dist/src/rules/blank-line-between-switch-cases.d.ts +8 -0
  25. package/dist/src/rules/blank-line-between-switch-cases.d.ts.map +1 -0
  26. package/dist/src/rules/blank-line-between-switch-cases.js +45 -0
  27. package/dist/src/rules/blank-line.d.ts +14 -0
  28. package/dist/src/rules/blank-line.d.ts.map +1 -0
  29. package/dist/src/rules/blank-line.js +68 -0
  30. package/dist/src/rules/comment-japanese-spacing.d.ts +8 -0
  31. package/dist/src/rules/comment-japanese-spacing.d.ts.map +1 -0
  32. package/dist/src/rules/comment-japanese-spacing.js +195 -0
  33. package/dist/src/rules/comment-one-sentence-per-line.d.ts +9 -0
  34. package/dist/src/rules/comment-one-sentence-per-line.d.ts.map +1 -0
  35. package/dist/src/rules/comment-one-sentence-per-line.js +190 -0
  36. package/dist/src/rules/comment-utils.d.ts +30 -0
  37. package/dist/src/rules/comment-utils.d.ts.map +1 -0
  38. package/dist/src/rules/comment-utils.js +153 -0
  39. package/dist/src/rules/jsdoc-param-order.d.ts +6 -0
  40. package/dist/src/rules/jsdoc-param-order.d.ts.map +1 -0
  41. package/dist/src/rules/jsdoc-param-order.js +101 -0
  42. package/dist/src/rules/jsdoc-tag-lines.d.ts +6 -0
  43. package/dist/src/rules/jsdoc-tag-lines.d.ts.map +1 -0
  44. package/dist/src/rules/jsdoc-tag-lines.js +128 -0
  45. package/dist/src/rules/jsdoc-tag-order.d.ts +6 -0
  46. package/dist/src/rules/jsdoc-tag-order.d.ts.map +1 -0
  47. package/dist/src/rules/jsdoc-tag-order.js +62 -0
  48. package/dist/src/rules/jsdoc-utils.d.ts +26 -0
  49. package/dist/src/rules/jsdoc-utils.d.ts.map +1 -0
  50. package/dist/src/rules/jsdoc-utils.js +132 -0
  51. package/dist/src/rules/member-ordering.d.ts +6 -0
  52. package/dist/src/rules/member-ordering.d.ts.map +1 -0
  53. package/dist/src/rules/member-ordering.js +66 -0
  54. package/dist/src/rules/object-properties-newline.d.ts +9 -0
  55. package/dist/src/rules/object-properties-newline.d.ts.map +1 -0
  56. package/dist/src/rules/object-properties-newline.js +47 -0
  57. package/dist/src/rules/object-sort-utils.d.ts +32 -0
  58. package/dist/src/rules/object-sort-utils.d.ts.map +1 -0
  59. package/dist/src/rules/object-sort-utils.js +221 -0
  60. package/dist/src/rules/overload-signatures-adjacent.d.ts +6 -0
  61. package/dist/src/rules/overload-signatures-adjacent.d.ts.map +1 -0
  62. package/dist/src/rules/overload-signatures-adjacent.js +143 -0
  63. package/dist/src/rules/sort-import-export-specifiers.d.ts +8 -0
  64. package/dist/src/rules/sort-import-export-specifiers.d.ts.map +1 -0
  65. package/dist/src/rules/sort-import-export-specifiers.js +130 -0
  66. package/dist/src/rules/sort-jsx-props.d.ts +7 -0
  67. package/dist/src/rules/sort-jsx-props.d.ts.map +1 -0
  68. package/dist/src/rules/sort-jsx-props.js +102 -0
  69. package/dist/src/rules/sort-object-properties.d.ts +9 -0
  70. package/dist/src/rules/sort-object-properties.d.ts.map +1 -0
  71. package/dist/src/rules/sort-object-properties.js +54 -0
  72. package/dist/src/rules/sort-type-members.d.ts +8 -0
  73. package/dist/src/rules/sort-type-members.d.ts.map +1 -0
  74. package/dist/src/rules/sort-type-members.js +213 -0
  75. package/dist/src/rules/spaced-comment.d.ts +6 -0
  76. package/dist/src/rules/spaced-comment.d.ts.map +1 -0
  77. package/dist/src/rules/spaced-comment.js +105 -0
  78. package/dist/src/rules/type-literal-properties-newline.d.ts +8 -0
  79. package/dist/src/rules/type-literal-properties-newline.d.ts.map +1 -0
  80. package/dist/src/rules/type-literal-properties-newline.js +39 -0
  81. package/package.json +40 -8
  82. package/src/index.ts +22 -0
  83. package/src/plugin.ts +48 -0
  84. package/src/rules/blank-line-after-control-block.ts +82 -0
  85. package/src/rules/blank-line-after-declaration.ts +106 -0
  86. package/src/rules/blank-line-after-variable-declaration.ts +84 -0
  87. package/src/rules/blank-line-before-return.ts +101 -0
  88. package/src/rules/blank-line-between-class-members.ts +112 -0
  89. package/src/rules/blank-line-between-switch-cases.ts +53 -0
  90. package/src/rules/blank-line.ts +113 -0
  91. package/src/rules/comment-japanese-spacing.ts +271 -0
  92. package/src/rules/comment-one-sentence-per-line.ts +264 -0
  93. package/src/rules/comment-utils.ts +218 -0
  94. package/src/rules/jsdoc-param-order.ts +137 -0
  95. package/src/rules/jsdoc-tag-lines.ts +165 -0
  96. package/src/rules/jsdoc-tag-order.ts +75 -0
  97. package/src/rules/jsdoc-utils.ts +179 -0
  98. package/src/rules/member-ordering.ts +93 -0
  99. package/src/rules/object-properties-newline.ts +54 -0
  100. package/src/rules/object-sort-utils.ts +339 -0
  101. package/src/rules/overload-signatures-adjacent.ts +204 -0
  102. package/src/rules/sort-import-export-specifiers.ts +194 -0
  103. package/src/rules/sort-jsx-props.ts +149 -0
  104. package/src/rules/sort-object-properties.ts +62 -0
  105. package/src/rules/sort-type-members.ts +299 -0
  106. package/src/rules/spaced-comment.ts +129 -0
  107. package/src/rules/type-literal-properties-newline.ts +44 -0
@@ -0,0 +1,7 @@
1
+ /**
2
+ * JSX の props を「一般 → on* → aria-* → data-*」のグループ順に並べます。
3
+ * 各グループ内ではプロパティー名の長さが短い順、同じ長さなら名前順です。
4
+ */
5
+ declare const sortJsxProps: import("vite-plus/lint/plugins").Rule;
6
+ export default sortJsxProps;
7
+ //# sourceMappingURL=sort-jsx-props.d.ts.map
@@ -0,0 +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,uCAwEhB,CAAC;eAEY,YAAY"}
@@ -0,0 +1,102 @@
1
+ import { defineRule } from "vite-plus/lint/plugins";
2
+ import { compareNames } from "./object-sort-utils.js";
3
+ function isNamedAttribute(attribute) {
4
+ return attribute.type === "JSXAttribute" && attribute.name.type === "JSXIdentifier";
5
+ }
6
+ function getAttributeGroup(name) {
7
+ if (/^on[A-Z].*/u.test(name)) {
8
+ return 1;
9
+ }
10
+ if (/^aria-.+/u.test(name)) {
11
+ return 2;
12
+ }
13
+ if (/^data-.+/u.test(name)) {
14
+ return 3;
15
+ }
16
+ return 0;
17
+ }
18
+ function compareAttributes(left, right) {
19
+ const leftGroup = getAttributeGroup(left.name);
20
+ const rightGroup = getAttributeGroup(right.name);
21
+ if (leftGroup !== rightGroup) {
22
+ return leftGroup - rightGroup;
23
+ }
24
+ return compareNames(left.name, right.name);
25
+ }
26
+ function getLineIndent(source, offset) {
27
+ const lineStart = source.lastIndexOf("\n", offset) + 1;
28
+ const match = /^[ \t]*/u.exec(source.slice(lineStart, offset));
29
+ return match?.[0] ?? "";
30
+ }
31
+ function hasCommentBetweenAttributes(attributes, sourceCode) {
32
+ const comments = sourceCode.getAllComments();
33
+ return attributes.some((attribute, index) => {
34
+ const nextAttribute = attributes[index + 1];
35
+ if (nextAttribute === undefined) {
36
+ return false;
37
+ }
38
+ return comments.some((comment) => comment.range[0] >= attribute.range[1] && comment.range[1] <= nextAttribute.range[0]);
39
+ });
40
+ }
41
+ /**
42
+ * JSX の props を「一般 → on* → aria-* → data-*」のグループ順に並べます。
43
+ * 各グループ内ではプロパティー名の長さが短い順、同じ長さなら名前順です。
44
+ */
45
+ const sortJsxProps = defineRule({
46
+ meta: {
47
+ docs: {
48
+ description: "Sort JSX props by group (general, on*, aria-*, data-*), then by name length and name.",
49
+ },
50
+ type: "layout",
51
+ fixable: "whitespace",
52
+ messages: {
53
+ sort: "JSX props must be sorted by group, name length, then name.",
54
+ },
55
+ },
56
+ create(context) {
57
+ const sourceCode = context.sourceCode;
58
+ return {
59
+ JSXOpeningElement(node) {
60
+ const attributes = node.attributes.filter(isNamedAttribute);
61
+ if (attributes.length < 2 || attributes.length !== node.attributes.length) {
62
+ return;
63
+ }
64
+ const names = new Set();
65
+ for (const attribute of attributes) {
66
+ if (names.has(attribute.name.name)) {
67
+ return;
68
+ }
69
+ names.add(attribute.name.name);
70
+ }
71
+ if (hasCommentBetweenAttributes(attributes, sourceCode)) {
72
+ return;
73
+ }
74
+ const units = attributes.map((attribute) => ({
75
+ name: attribute.name.name,
76
+ text: sourceCode.text.slice(attribute.range[0], attribute.range[1]),
77
+ }));
78
+ const sorted = [...units].sort(compareAttributes);
79
+ if (sorted.every((unit, index) => unit === units[index])) {
80
+ return;
81
+ }
82
+ const firstAttribute = attributes[0];
83
+ const lastAttribute = attributes.at(-1);
84
+ if (firstAttribute === undefined || lastAttribute === undefined) {
85
+ return;
86
+ }
87
+ const multiline = firstAttribute.loc.start.line !== lastAttribute.loc.end.line;
88
+ const separator = multiline
89
+ ? `\n${getLineIndent(sourceCode.text, firstAttribute.range[0])}`
90
+ : " ";
91
+ context.report({
92
+ fix(fixer) {
93
+ return fixer.replaceTextRange([firstAttribute.range[0], lastAttribute.range[1]], sorted.map((unit) => unit.text).join(separator));
94
+ },
95
+ node,
96
+ messageId: "sort",
97
+ });
98
+ },
99
+ };
100
+ },
101
+ });
102
+ export default sortJsxProps;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * オブジェクトリテラルのプロパティーを、名前の長さが短い順、同じ長さなら名前順に並べます。
3
+ *
4
+ * 空行で区切られたグループは意図的なまとまりとみなし、グループ内だけで並べ替えます。
5
+ * プロパティー直上のコメントはプロパティーと一緒に移動します。
6
+ */
7
+ declare const sortObjectProperties: import("vite-plus/lint/plugins").Rule;
8
+ export default sortObjectProperties;
9
+ //# sourceMappingURL=sort-object-properties.d.ts.map
@@ -0,0 +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,uCAiDxB,CAAC;eAEY,oBAAoB"}
@@ -0,0 +1,54 @@
1
+ import { defineRule } from "vite-plus/lint/plugins";
2
+ import { getSortPlan } from "./object-sort-utils.js";
3
+ /**
4
+ * オブジェクトリテラルのプロパティーを、名前の長さが短い順、同じ長さなら名前順に並べます。
5
+ *
6
+ * 空行で区切られたグループは意図的なまとまりとみなし、グループ内だけで並べ替えます。
7
+ * プロパティー直上のコメントはプロパティーと一緒に移動します。
8
+ */
9
+ const sortObjectProperties = defineRule({
10
+ meta: {
11
+ docs: {
12
+ description: "Sort object properties by name length and name, preserving comment groups separated by blank lines.",
13
+ },
14
+ type: "layout",
15
+ fixable: "whitespace",
16
+ messages: {
17
+ sort: "Object properties must be sorted by name length, then by name.",
18
+ },
19
+ },
20
+ create(context) {
21
+ return {
22
+ ObjectPattern(node) {
23
+ const plan = getSortPlan(node, context.sourceCode, {
24
+ allowRest: true,
25
+ forceMultiline: false,
26
+ });
27
+ if (plan === null || !plan.needsFix) {
28
+ return;
29
+ }
30
+ context.report({
31
+ fix(fixer) {
32
+ return fixer.replaceText(node, plan.replacement);
33
+ },
34
+ node,
35
+ messageId: "sort",
36
+ });
37
+ },
38
+ ObjectExpression(node) {
39
+ const plan = getSortPlan(node, context.sourceCode);
40
+ if (plan === null || !plan.needsFix) {
41
+ return;
42
+ }
43
+ context.report({
44
+ fix(fixer) {
45
+ return fixer.replaceText(node, plan.replacement);
46
+ },
47
+ node,
48
+ messageId: "sort",
49
+ });
50
+ },
51
+ };
52
+ },
53
+ });
54
+ export default sortObjectProperties;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 型リテラルのメンバーを、名前の長さが短い順、同じ長さなら名前順に並べます。
3
+ *
4
+ * `interface` は対象外です。
5
+ */
6
+ declare const sortTypeMembers: import("vite-plus/lint/plugins").Rule;
7
+ export default sortTypeMembers;
8
+ //# sourceMappingURL=sort-type-members.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sort-type-members.d.ts","sourceRoot":"","sources":["../../../src/rules/sort-type-members.ts"],"names":[],"mappings":"AAuPA;;;;GAIG;AACH,QAAA,MAAM,eAAe,uCA4CnB,CAAC;eAEY,eAAe"}
@@ -0,0 +1,213 @@
1
+ import { defineRule } from "vite-plus/lint/plugins";
2
+ import { compareNames } from "./object-sort-utils.js";
3
+ function getLineStarts(text) {
4
+ const starts = [0];
5
+ for (let index = 0; index < text.length; index += 1) {
6
+ if (text[index] === "\n") {
7
+ starts.push(index + 1);
8
+ }
9
+ }
10
+ return starts;
11
+ }
12
+ function getMemberName(member) {
13
+ if (member.type !== "TSPropertySignature" && member.type !== "TSMethodSignature") {
14
+ return null;
15
+ }
16
+ if (member.computed) {
17
+ return null;
18
+ }
19
+ const key = member.key;
20
+ if (key.type === "Identifier") {
21
+ return key.name;
22
+ }
23
+ if (key.type === "Literal" && (typeof key.value === "string" || typeof key.value === "number")) {
24
+ return String(key.value);
25
+ }
26
+ return null;
27
+ }
28
+ function getUnits(node, sourceCode) {
29
+ const source = sourceCode.text;
30
+ const lineStarts = getLineStarts(source);
31
+ const comments = sourceCode
32
+ .getAllComments()
33
+ .filter((comment) => comment.range[0] >= node.range[0] && comment.range[1] <= node.range[1]);
34
+ const units = [];
35
+ let previousEnd = node.range[0] + 1;
36
+ for (const [index, member] of node.members.entries()) {
37
+ const previousMember = node.members[index - 1];
38
+ const candidates = comments.filter((comment) => comment.range[0] >= previousEnd && comment.range[1] <= member.range[0]);
39
+ if (previousMember !== undefined &&
40
+ candidates.some((comment) => comment.loc.start.line === previousMember.loc.end.line)) {
41
+ return null;
42
+ }
43
+ const attached = [];
44
+ let expectedLine = member.loc.start.line;
45
+ for (let commentIndex = candidates.length - 1; commentIndex >= 0; commentIndex -= 1) {
46
+ const comment = candidates[commentIndex];
47
+ if (comment === undefined) {
48
+ continue;
49
+ }
50
+ if (comment.loc.end.line !== expectedLine && comment.loc.end.line !== expectedLine - 1) {
51
+ return null;
52
+ }
53
+ if (comment.loc.start.line === expectedLine) {
54
+ return null;
55
+ }
56
+ if (comment.loc.start.line === node.loc.start.line) {
57
+ return null;
58
+ }
59
+ attached.unshift(comment);
60
+ expectedLine = comment.loc.start.line;
61
+ }
62
+ if (attached.length !== candidates.length) {
63
+ return null;
64
+ }
65
+ const first = attached[0] ?? member;
66
+ const startLine = first.loc.start.line;
67
+ let startOffset;
68
+ if (attached.length > 0) {
69
+ startOffset = lineStarts[startLine - 1] ?? first.range[0];
70
+ }
71
+ else if (startLine === node.loc.start.line) {
72
+ startOffset = member.range[0];
73
+ }
74
+ else {
75
+ startOffset = lineStarts[startLine - 1] ?? member.range[0];
76
+ }
77
+ let endOffset = member.range[1];
78
+ while (endOffset > member.range[0]) {
79
+ const character = source[endOffset - 1];
80
+ if (character !== ";" && character !== ",") {
81
+ break;
82
+ }
83
+ endOffset -= 1;
84
+ }
85
+ units.push({
86
+ name: getMemberName(member),
87
+ text: source.slice(startOffset, endOffset),
88
+ endLine: member.loc.end.line,
89
+ endOffset,
90
+ startLine,
91
+ startOffset,
92
+ });
93
+ previousEnd = member.range[1];
94
+ }
95
+ if (comments.some((comment) => comment.range[0] >= previousEnd && comment.range[1] <= node.range[1] - 1)) {
96
+ return null;
97
+ }
98
+ return units;
99
+ }
100
+ function splitGroups(units) {
101
+ const groups = [];
102
+ let current = [];
103
+ let previousEndLine = null;
104
+ for (const unit of units) {
105
+ if (previousEndLine !== null && unit.startLine > previousEndLine + 1) {
106
+ groups.push(current);
107
+ current = [];
108
+ }
109
+ current.push(unit);
110
+ previousEndLine = unit.endLine;
111
+ }
112
+ if (current.length > 0) {
113
+ groups.push(current);
114
+ }
115
+ return groups;
116
+ }
117
+ function sortGroup(group) {
118
+ const sortable = group.filter((unit) => unit.name !== null);
119
+ sortable.sort((left, right) => compareNames(left.name, right.name));
120
+ const rest = group.filter((unit) => unit.name === null);
121
+ return [...sortable, ...rest];
122
+ }
123
+ function getSortEdits(units) {
124
+ const edits = [];
125
+ let runStart = 0;
126
+ while (runStart < units.length) {
127
+ if (units[runStart]?.name === null) {
128
+ runStart += 1;
129
+ continue;
130
+ }
131
+ let runEnd = runStart;
132
+ while (runEnd < units.length && units[runEnd]?.name !== null) {
133
+ runEnd += 1;
134
+ }
135
+ const run = units.slice(runStart, runEnd);
136
+ if (run.length >= 2) {
137
+ const names = new Set();
138
+ let hasDuplicate = false;
139
+ for (const unit of run) {
140
+ if (unit.name === null) {
141
+ continue;
142
+ }
143
+ if (names.has(unit.name)) {
144
+ hasDuplicate = true;
145
+ break;
146
+ }
147
+ names.add(unit.name);
148
+ }
149
+ if (!hasDuplicate) {
150
+ const groups = splitGroups(run);
151
+ const sortedGroups = groups.map(sortGroup);
152
+ const changed = sortedGroups.some((group, groupIndex) => group.some((unit, unitIndex) => unit !== groups[groupIndex]?.[unitIndex]));
153
+ const firstUnit = run[0];
154
+ const lastUnit = run.at(-1);
155
+ if (changed && firstUnit !== undefined && lastUnit !== undefined) {
156
+ edits.push({
157
+ end: lastUnit.endOffset,
158
+ text: sortedGroups
159
+ .map((group) => group.map((unit) => unit.text).join(";\n"))
160
+ .join(";\n\n"),
161
+ start: firstUnit.startOffset,
162
+ });
163
+ }
164
+ }
165
+ }
166
+ runStart = runEnd;
167
+ }
168
+ return edits;
169
+ }
170
+ /**
171
+ * 型リテラルのメンバーを、名前の長さが短い順、同じ長さなら名前順に並べます。
172
+ *
173
+ * `interface` は対象外です。
174
+ */
175
+ const sortTypeMembers = defineRule({
176
+ meta: {
177
+ docs: {
178
+ description: "Sort type literal members by name length and name.",
179
+ },
180
+ type: "layout",
181
+ fixable: "whitespace",
182
+ messages: {
183
+ sort: "Type members must be sorted by name length, then by name.",
184
+ },
185
+ },
186
+ create(context) {
187
+ const sourceCode = context.sourceCode;
188
+ return {
189
+ TSTypeLiteral(node) {
190
+ const units = getUnits(node, sourceCode);
191
+ if (units === null) {
192
+ return;
193
+ }
194
+ const edits = getSortEdits(units);
195
+ if (edits.length === 0) {
196
+ return;
197
+ }
198
+ context.report({
199
+ fix(fixer) {
200
+ const fixes = [];
201
+ for (const edit of edits) {
202
+ fixes.push(fixer.replaceTextRange([edit.start, edit.end], edit.text));
203
+ }
204
+ return fixes;
205
+ },
206
+ node,
207
+ messageId: "sort",
208
+ });
209
+ },
210
+ };
211
+ },
212
+ });
213
+ export default sortTypeMembers;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * コメントの開始記号の直後と終了記号の直前に空白を要求します。
3
+ */
4
+ declare const spacedComment: import("vite-plus/lint/plugins").Rule;
5
+ export default spacedComment;
6
+ //# sourceMappingURL=spaced-comment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spaced-comment.d.ts","sourceRoot":"","sources":["../../../src/rules/spaced-comment.ts"],"names":[],"mappings":"AAyBA;;GAEG;AACH,QAAA,MAAM,aAAa,uCAkGjB,CAAC;eAEY,aAAa"}
@@ -0,0 +1,105 @@
1
+ import { defineRule } from "vite-plus/lint/plugins";
2
+ const DECORATIVE_LINE = /^[-=*#_~+]{3,}$/u;
3
+ function isWhitespace(char) {
4
+ return char === " " || char === "\t";
5
+ }
6
+ function isExemptLineComment(raw) {
7
+ if (raw.startsWith("///") || raw.startsWith("//!") || raw.startsWith("//@")) {
8
+ return true;
9
+ }
10
+ if (raw.startsWith("//#")) {
11
+ return true;
12
+ }
13
+ return DECORATIVE_LINE.test(raw.slice(2));
14
+ }
15
+ function isExemptBlockComment(raw) {
16
+ return raw.startsWith("/*!");
17
+ }
18
+ /**
19
+ * コメントの開始記号の直後と終了記号の直前に空白を要求します。
20
+ */
21
+ const spacedComment = defineRule({
22
+ meta: {
23
+ docs: {
24
+ description: "Require whitespace after the comment marker and before the closing marker.",
25
+ },
26
+ type: "layout",
27
+ fixable: "whitespace",
28
+ messages: {
29
+ missingLeadingSpace: "Expected a whitespace after the comment marker.",
30
+ missingTrailingSpace: "Expected a whitespace before the closing comment marker.",
31
+ },
32
+ },
33
+ create(context) {
34
+ const sourceCode = context.sourceCode;
35
+ function checkLineComment(comment, raw) {
36
+ if (isExemptLineComment(raw) || isWhitespace(raw[2]) || raw.length === 2) {
37
+ return;
38
+ }
39
+ context.report({
40
+ fix(fixer) {
41
+ return fixer.insertTextAfterRange([comment.range[0], comment.range[0] + 2], " ");
42
+ },
43
+ loc: comment.loc,
44
+ messageId: "missingLeadingSpace",
45
+ });
46
+ }
47
+ function checkBlockComment(comment, raw) {
48
+ if (isExemptBlockComment(raw)) {
49
+ return;
50
+ }
51
+ const prefixLength = raw.startsWith("/**") ? 3 : 2;
52
+ const firstLineEnd = raw.indexOf("\n");
53
+ const lastLineStart = raw.lastIndexOf("\n") + 1;
54
+ let needsLeading;
55
+ let needsTrailing;
56
+ if (firstLineEnd === -1) {
57
+ const contentStart = prefixLength;
58
+ const contentEnd = raw.lastIndexOf("*/");
59
+ const content = raw.slice(contentStart, contentEnd);
60
+ needsLeading = content !== "" && !isWhitespace(content[0]);
61
+ needsTrailing = content !== "" && !isWhitespace(content.at(-1));
62
+ }
63
+ else {
64
+ const firstLine = raw.slice(0, firstLineEnd);
65
+ const lastLine = raw.slice(lastLineStart);
66
+ const leadingContent = firstLine.slice(prefixLength);
67
+ const closeIndex = lastLine.lastIndexOf("*/");
68
+ const trailingContent = lastLine.slice(0, closeIndex);
69
+ needsLeading = leadingContent !== "" && !isWhitespace(leadingContent[0]);
70
+ needsTrailing = trailingContent !== "" && !isWhitespace(trailingContent.at(-1));
71
+ }
72
+ if (!needsLeading && !needsTrailing) {
73
+ return;
74
+ }
75
+ context.report({
76
+ fix(fixer) {
77
+ const fixes = [];
78
+ if (needsLeading) {
79
+ fixes.push(fixer.insertTextAfterRange([comment.range[0], comment.range[0] + prefixLength], " "));
80
+ }
81
+ if (needsTrailing) {
82
+ fixes.push(fixer.insertTextBeforeRange([comment.range[1] - 2, comment.range[1]], " "));
83
+ }
84
+ return fixes;
85
+ },
86
+ loc: comment.loc,
87
+ messageId: needsLeading ? "missingLeadingSpace" : "missingTrailingSpace",
88
+ });
89
+ }
90
+ return {
91
+ Program() {
92
+ for (const comment of sourceCode.getAllComments()) {
93
+ if (comment.type === "Line") {
94
+ checkLineComment(comment, sourceCode.getText(comment));
95
+ continue;
96
+ }
97
+ if (comment.type === "Block") {
98
+ checkBlockComment(comment, sourceCode.getText(comment));
99
+ }
100
+ }
101
+ },
102
+ };
103
+ },
104
+ });
105
+ export default spacedComment;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * メンバーが 2 つ以上ある型リテラルを複数行にします。
3
+ *
4
+ * Oxfmt の `objectWrap` はオブジェクトリテラル用のため、型リテラルは `{` の直後の改行を目印に複数行を維持します。
5
+ */
6
+ declare const typeLiteralPropertiesNewline: import("vite-plus/lint/plugins").Rule;
7
+ export default typeLiteralPropertiesNewline;
8
+ //# sourceMappingURL=type-literal-properties-newline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-literal-properties-newline.d.ts","sourceRoot":"","sources":["../../../src/rules/type-literal-properties-newline.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,QAAA,MAAM,4BAA4B,uCAkChC,CAAC;eAEY,4BAA4B"}
@@ -0,0 +1,39 @@
1
+ import { defineRule } from "vite-plus/lint/plugins";
2
+ /**
3
+ * メンバーが 2 つ以上ある型リテラルを複数行にします。
4
+ *
5
+ * Oxfmt の `objectWrap` はオブジェクトリテラル用のため、型リテラルは `{` の直後の改行を目印に複数行を維持します。
6
+ */
7
+ const typeLiteralPropertiesNewline = defineRule({
8
+ meta: {
9
+ docs: {
10
+ description: "Enforce multiline type literals when they have two or more members.",
11
+ },
12
+ type: "layout",
13
+ fixable: "whitespace",
14
+ messages: {
15
+ multiline: "Type literals with 2 or more members must be multiline.",
16
+ },
17
+ },
18
+ create(context) {
19
+ return {
20
+ TSTypeLiteral(node) {
21
+ if (node.members.length < 2) {
22
+ return;
23
+ }
24
+ const firstMember = node.members[0];
25
+ if (firstMember === undefined || firstMember.loc.start.line !== node.loc.start.line) {
26
+ return;
27
+ }
28
+ context.report({
29
+ fix(fixer) {
30
+ return fixer.insertTextAfterRange([node.range[0], node.range[0] + 1], "\n");
31
+ },
32
+ node,
33
+ messageId: "multiline",
34
+ });
35
+ },
36
+ };
37
+ },
38
+ });
39
+ export default typeLiteralPropertiesNewline;
package/package.json CHANGED
@@ -1,10 +1,42 @@
1
1
  {
2
2
  "name": "@tai-kun/vp-lint-plugins",
3
- "version": "0.0.0",
4
- "description": "OIDC trusted publishing setup package for @tai-kun/vp-lint-plugins",
5
- "keywords": [
6
- "oidc",
7
- "trusted-publishing",
8
- "setup"
9
- ]
10
- }
3
+ "version": "0.0.1",
4
+ "description": "",
5
+ "homepage": "https://tai-kun.github.io/vp-lint-plugins/",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "url": "https://github.com/tai-kun/vp-lint-plugins",
9
+ "directory": "packages/vp-lint-plugins"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "src",
14
+ "package.json",
15
+ "LICENSE",
16
+ "README.md"
17
+ ],
18
+ "type": "module",
19
+ "sideEffects": false,
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/src/index.d.ts",
23
+ "default": "./dist/src/index.js"
24
+ }
25
+ },
26
+ "devDependencies": {
27
+ "@tsconfig/node24": "24.0.5",
28
+ "@tsconfig/strictest": "2.0.8",
29
+ "@types/node": "24.19.2",
30
+ "@vitest/coverage-v8": "5.0.5",
31
+ "vite": "npm:@voidzero-dev/vite-plus-core@1.3.0",
32
+ "vite-plus": "1.3.0",
33
+ "vitest": "5.0.5"
34
+ },
35
+ "peerDependencies": {
36
+ "vite-plus": "^1.0.0"
37
+ },
38
+ "readme": "README.md",
39
+ "scripts": {
40
+ "build": "tsc --project ./.config/tsconfig.build.json"
41
+ }
42
+ }
package/src/index.ts ADDED
@@ -0,0 +1,22 @@
1
+ export { default as blankLineAfterControlBlock } from "./rules/blank-line-after-control-block.js";
2
+ export { default as blankLineAfterDeclaration } from "./rules/blank-line-after-declaration.js";
3
+ export { default as blankLineAfterVariableDeclaration } from "./rules/blank-line-after-variable-declaration.js";
4
+ export { default as blankLineBeforeReturn } from "./rules/blank-line-before-return.js";
5
+ export { default as blankLineBetweenClassMembers } from "./rules/blank-line-between-class-members.js";
6
+ export { default as blankLineBetweenSwitchCases } from "./rules/blank-line-between-switch-cases.js";
7
+ export { default as commentJapaneseSpacing } from "./rules/comment-japanese-spacing.js";
8
+ export { default as commentOneSentencePerLine } from "./rules/comment-one-sentence-per-line.js";
9
+ export { default as jsdocParamOrder } from "./rules/jsdoc-param-order.js";
10
+ export { default as jsdocTagLines } from "./rules/jsdoc-tag-lines.js";
11
+ export { default as jsdocTagOrder } from "./rules/jsdoc-tag-order.js";
12
+ export { default as memberOrdering } from "./rules/member-ordering.js";
13
+ export { default as objectPropertiesNewline } from "./rules/object-properties-newline.js";
14
+ export { default as overloadSignaturesAdjacent } from "./rules/overload-signatures-adjacent.js";
15
+ export { default as sortImportExportSpecifiers } from "./rules/sort-import-export-specifiers.js";
16
+ export { default as sortJsxProps } from "./rules/sort-jsx-props.js";
17
+ export { default as sortObjectProperties } from "./rules/sort-object-properties.js";
18
+ export { default as sortTypeMembers } from "./rules/sort-type-members.js";
19
+ export { default as spacedComment } from "./rules/spaced-comment.js";
20
+ export { default as typeLiteralPropertiesNewline } from "./rules/type-literal-properties-newline.js";
21
+
22
+ export { default } from "./plugin.js";