@kazupon/eslint-plugin 0.2.1 → 0.3.0
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/README.md +1 -0
- package/lib/index.d.ts +6 -5
- package/lib/index.js +124 -11
- package/package.json +24 -23
package/README.md
CHANGED
|
@@ -64,6 +64,7 @@ The rules with the following star ⭐ are included in the configs.
|
|
|
64
64
|
| Rule ID | Description | Category | Fixable | RECOMMENDED |
|
|
65
65
|
| :----------------------------------------------------------------------------------------------------- | :---------------------------------------------- | :------- | :-----: | :---------: |
|
|
66
66
|
| [@kazupon/enforce-header-comment](https://eslint-plugin.kazupon.dev/rules/enforce-header-comment.html) | Enforce heading the comment in source code file | Comment | | ⭐ |
|
|
67
|
+
| [@kazupon/no-tag-comments](https://eslint-plugin.kazupon.dev/rules/no-tag-comments.html) | disallow tag comments | Comment | | |
|
|
67
68
|
|
|
68
69
|
<!--RULES_TABLE_END-->
|
|
69
70
|
|
package/lib/index.d.ts
CHANGED
|
@@ -2,17 +2,18 @@ import { ESLint, Linter } from "eslint";
|
|
|
2
2
|
|
|
3
3
|
//#region src/index.d.ts
|
|
4
4
|
type PluginConfigs = {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
recommended: Linter.Config<Linter.RulesRecord>[];
|
|
6
|
+
comment: Linter.Config<Linter.RulesRecord>[];
|
|
7
7
|
};
|
|
8
8
|
declare const plugin: Omit<ESLint.Plugin, "configs"> & {
|
|
9
|
-
|
|
9
|
+
configs: PluginConfigs;
|
|
10
10
|
};
|
|
11
11
|
declare const commentConfig: Linter.Config[];
|
|
12
12
|
declare const configs: {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
recommended: typeof commentConfig;
|
|
14
|
+
comment: typeof commentConfig;
|
|
15
15
|
};
|
|
16
|
+
/** @alias */
|
|
16
17
|
|
|
17
18
|
//#endregion
|
|
18
19
|
export { configs, plugin as default, plugin };
|
package/lib/index.js
CHANGED
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
import { parseComment } from "@es-joy/jsdoccomment";
|
|
2
2
|
|
|
3
3
|
//#region src/utils/constants.ts
|
|
4
|
+
/**
|
|
5
|
+
* @author kazuya kawaguchi (a.k.a. kazupon)
|
|
6
|
+
* @license MIT
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* The plugin name.
|
|
10
|
+
*/
|
|
4
11
|
const name = "@kazupon/eslint-plugin";
|
|
5
|
-
|
|
12
|
+
/**
|
|
13
|
+
* The plugin version.
|
|
14
|
+
*/
|
|
15
|
+
const version = "0.3.0";
|
|
16
|
+
/**
|
|
17
|
+
* The namespace for rules
|
|
18
|
+
*/
|
|
6
19
|
const namespace = "@kazupon";
|
|
7
20
|
|
|
8
21
|
//#endregion
|
|
9
22
|
//#region src/utils/rule.ts
|
|
10
|
-
const BLOB_URL = "https://
|
|
23
|
+
const BLOB_URL = "https://eslint-plugin.kazupon.dev/rules";
|
|
11
24
|
function RuleCreator(urlCreator, namespace$1 = "") {
|
|
12
|
-
return function createNamedRule({ meta, name: name$1,...rule$
|
|
25
|
+
return function createNamedRule({ meta, name: name$1,...rule$2 }) {
|
|
13
26
|
const ruleId = namespace$1 ? `${namespace$1}/${name$1}` : name$1;
|
|
14
27
|
return {
|
|
15
28
|
meta: {
|
|
@@ -21,12 +34,12 @@ function RuleCreator(urlCreator, namespace$1 = "") {
|
|
|
21
34
|
ruleId
|
|
22
35
|
}
|
|
23
36
|
},
|
|
24
|
-
...rule$
|
|
37
|
+
...rule$2
|
|
25
38
|
};
|
|
26
39
|
};
|
|
27
40
|
}
|
|
28
41
|
const createRule = RuleCreator((ruleName) => {
|
|
29
|
-
return `${BLOB_URL}/${ruleName}
|
|
42
|
+
return `${BLOB_URL}/${ruleName}`;
|
|
30
43
|
}, namespace);
|
|
31
44
|
|
|
32
45
|
//#endregion
|
|
@@ -40,7 +53,7 @@ function initializeTagDiagnosis(tags) {
|
|
|
40
53
|
function validTagDiagnosis(tagDiagnosis) {
|
|
41
54
|
return Object.keys(tagDiagnosis).every((tag) => tagDiagnosis[tag] === "ok");
|
|
42
55
|
}
|
|
43
|
-
const rule = createRule({
|
|
56
|
+
const rule$1 = createRule({
|
|
44
57
|
name: "enforce-header-comment",
|
|
45
58
|
meta: {
|
|
46
59
|
type: "suggestion",
|
|
@@ -168,11 +181,110 @@ const rule = createRule({
|
|
|
168
181
|
};
|
|
169
182
|
}
|
|
170
183
|
});
|
|
171
|
-
var enforce_header_comment_default = rule;
|
|
184
|
+
var enforce_header_comment_default = rule$1;
|
|
185
|
+
|
|
186
|
+
//#endregion
|
|
187
|
+
//#region src/rules/no-tag-comments.ts
|
|
188
|
+
const DEFAULT_TAGS = ["FIXME", "BUG"];
|
|
189
|
+
/**
|
|
190
|
+
* Remove JSDoc asterisk prefix if present
|
|
191
|
+
*/
|
|
192
|
+
function stripJSDocPrefix(line) {
|
|
193
|
+
const trimmed = line.trim();
|
|
194
|
+
return trimmed.startsWith("*") ? trimmed.slice(1).trim() : trimmed;
|
|
195
|
+
}
|
|
196
|
+
const rule = createRule({
|
|
197
|
+
name: "no-tag-comments",
|
|
198
|
+
meta: {
|
|
199
|
+
type: "problem",
|
|
200
|
+
docs: {
|
|
201
|
+
description: "disallow tag comments",
|
|
202
|
+
category: "Comment",
|
|
203
|
+
recommended: false,
|
|
204
|
+
defaultSeverity: "warn"
|
|
205
|
+
},
|
|
206
|
+
messages: { avoidTagComment: "Fix '{{tag}}' tag comment" },
|
|
207
|
+
schema: [{
|
|
208
|
+
type: "object",
|
|
209
|
+
properties: { tags: {
|
|
210
|
+
type: "array",
|
|
211
|
+
items: { type: "string" },
|
|
212
|
+
minItems: 1,
|
|
213
|
+
uniqueItems: true
|
|
214
|
+
} },
|
|
215
|
+
additionalProperties: false
|
|
216
|
+
}]
|
|
217
|
+
},
|
|
218
|
+
create(ctx) {
|
|
219
|
+
const options = ctx.options[0] || { tags: DEFAULT_TAGS };
|
|
220
|
+
const tags = options.tags || DEFAULT_TAGS;
|
|
221
|
+
const sourceCode = ctx.sourceCode;
|
|
222
|
+
/**
|
|
223
|
+
* Check if the text starts with a tag followed by valid delimiter
|
|
224
|
+
*/
|
|
225
|
+
function hasTag(text) {
|
|
226
|
+
for (const tag of tags) if (text.startsWith(tag)) {
|
|
227
|
+
const afterTag = text.slice(tag.length);
|
|
228
|
+
if (afterTag === "" || afterTag.startsWith(":") || afterTag.startsWith(" ")) return tag;
|
|
229
|
+
}
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Report a tag comment violation
|
|
234
|
+
*/
|
|
235
|
+
function reportTag(comment, tag) {
|
|
236
|
+
ctx.report({
|
|
237
|
+
messageId: "avoidTagComment",
|
|
238
|
+
data: { tag },
|
|
239
|
+
loc: comment.loc
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Process a single line of text for tags
|
|
244
|
+
*/
|
|
245
|
+
function checkLine(text, comment) {
|
|
246
|
+
const tag = hasTag(text);
|
|
247
|
+
if (tag) {
|
|
248
|
+
reportTag(comment, tag);
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Check a comment for tag violations
|
|
255
|
+
*/
|
|
256
|
+
function checkComment(comment) {
|
|
257
|
+
const { value, type } = comment;
|
|
258
|
+
if (type === "Line") {
|
|
259
|
+
checkLine(value.trim(), comment);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
const lines = value.split("\n");
|
|
263
|
+
if (lines.length === 1) {
|
|
264
|
+
checkLine(value.trim(), comment);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
for (const line of lines) {
|
|
268
|
+
const trimmedLine = line.trim();
|
|
269
|
+
if (!trimmedLine) continue;
|
|
270
|
+
const contentToCheck = stripJSDocPrefix(line);
|
|
271
|
+
if (checkLine(contentToCheck, comment)) break;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return { Program() {
|
|
275
|
+
const comments = sourceCode.getAllComments();
|
|
276
|
+
for (const comment of comments) checkComment(comment);
|
|
277
|
+
} };
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
var no_tag_comments_default = rule;
|
|
172
281
|
|
|
173
282
|
//#endregion
|
|
174
283
|
//#region src/rules/index.ts
|
|
175
|
-
const rules = {
|
|
284
|
+
const rules = {
|
|
285
|
+
"enforce-header-comment": enforce_header_comment_default,
|
|
286
|
+
"no-tag-comments": no_tag_comments_default
|
|
287
|
+
};
|
|
176
288
|
|
|
177
289
|
//#endregion
|
|
178
290
|
//#region src/index.ts
|
|
@@ -193,9 +305,9 @@ const commentConfig = [{
|
|
|
193
305
|
"**/*.config.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"
|
|
194
306
|
],
|
|
195
307
|
plugins: { [namespace]: plugin },
|
|
196
|
-
rules: Object.entries(rules).reduce((rules$1, [ruleName, rule$
|
|
197
|
-
const ruleId = rule$
|
|
198
|
-
rules$1[ruleId] = rule$
|
|
308
|
+
rules: Object.entries(rules).reduce((rules$1, [ruleName, rule$2]) => {
|
|
309
|
+
const ruleId = rule$2.meta?.docs?.ruleId || (namespace ? `${namespace}/${ruleName}` : ruleName);
|
|
310
|
+
rules$1[ruleId] = rule$2.meta?.docs?.defaultSeverity || "warn";
|
|
199
311
|
return rules$1;
|
|
200
312
|
}, Object.create(null))
|
|
201
313
|
}];
|
|
@@ -204,6 +316,7 @@ const configs = {
|
|
|
204
316
|
comment: commentConfig
|
|
205
317
|
};
|
|
206
318
|
plugin.configs = configs;
|
|
319
|
+
/** @alias */
|
|
207
320
|
var src_default = plugin;
|
|
208
321
|
|
|
209
322
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kazupon/eslint-plugin",
|
|
3
3
|
"description": "ESLint plugin for @kazupon",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"funding": "https://github.com/sponsors/kazupon",
|
|
7
7
|
"bugs": {
|
|
@@ -47,46 +47,47 @@
|
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@es-joy/jsdoccomment": "^0.50.
|
|
51
|
-
"@eslint/core": "^0.
|
|
50
|
+
"@es-joy/jsdoccomment": "^0.50.2",
|
|
51
|
+
"@eslint/core": "^0.14.0"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"eslint": "^9.0.0"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@eslint/
|
|
58
|
-
"@
|
|
57
|
+
"@eslint/compat": "^1.2.9",
|
|
58
|
+
"@eslint/markdown": "^6.5.0",
|
|
59
|
+
"@kazupon/eslint-config": "^0.30.0",
|
|
59
60
|
"@kazupon/prettier-config": "^0.1.1",
|
|
60
|
-
"@shikijs/vitepress-twoslash": "^3.
|
|
61
|
-
"@types/node": "^22.
|
|
62
|
-
"@vitest/eslint-plugin": "^1.1
|
|
63
|
-
"bumpp": "^10.1.
|
|
64
|
-
"eslint": "^9.
|
|
65
|
-
"eslint-config-prettier": "^10.1.
|
|
66
|
-
"eslint-import-resolver-typescript": "^4.3
|
|
61
|
+
"@shikijs/vitepress-twoslash": "^3.6.0",
|
|
62
|
+
"@types/node": "^22.15.30",
|
|
63
|
+
"@vitest/eslint-plugin": "^1.2.1",
|
|
64
|
+
"bumpp": "^10.1.1",
|
|
65
|
+
"eslint": "^9.28.0",
|
|
66
|
+
"eslint-config-prettier": "^10.1.5",
|
|
67
|
+
"eslint-import-resolver-typescript": "^4.4.3",
|
|
67
68
|
"eslint-plugin-import": "^2.31.0",
|
|
68
|
-
"eslint-plugin-jsonc": "^2.20.
|
|
69
|
+
"eslint-plugin-jsonc": "^2.20.1",
|
|
69
70
|
"eslint-plugin-module-interop": "^0.3.1",
|
|
70
71
|
"eslint-plugin-promise": "^7.2.1",
|
|
71
72
|
"eslint-plugin-unicorn": "^58.0.0",
|
|
72
73
|
"eslint-plugin-unused-imports": "^4.1.4",
|
|
73
|
-
"eslint-plugin-yml": "^1.
|
|
74
|
+
"eslint-plugin-yml": "^1.18.0",
|
|
74
75
|
"eslint-vitest-rule-tester": "^2.2.0",
|
|
75
76
|
"gh-changelogen": "^0.2.8",
|
|
76
|
-
"knip": "^5.
|
|
77
|
-
"lint-staged": "^
|
|
78
|
-
"pkg-pr-new": "^0.0.
|
|
77
|
+
"knip": "^5.60.2",
|
|
78
|
+
"lint-staged": "^16.0.0",
|
|
79
|
+
"pkg-pr-new": "^0.0.51",
|
|
79
80
|
"prettier": "^3.5.3",
|
|
80
|
-
"publint": "^0.3.
|
|
81
|
-
"tsdown": "^0.
|
|
82
|
-
"tsx": "^4.19.
|
|
81
|
+
"publint": "^0.3.12",
|
|
82
|
+
"tsdown": "^0.12.7",
|
|
83
|
+
"tsx": "^4.19.4",
|
|
83
84
|
"twoslash-eslint": "^0.3.1",
|
|
84
85
|
"typescript": "^5.8.3",
|
|
85
|
-
"typescript-eslint": "^8.
|
|
86
|
+
"typescript-eslint": "^8.33.1",
|
|
86
87
|
"vite-plugin-eslint4b": "^0.5.1",
|
|
87
88
|
"vitepress": "^1.6.3",
|
|
88
|
-
"vitepress-plugin-group-icons": "^1.
|
|
89
|
-
"vitest": "^3.
|
|
89
|
+
"vitepress-plugin-group-icons": "^1.6.0",
|
|
90
|
+
"vitest": "^3.2.2"
|
|
90
91
|
},
|
|
91
92
|
"prettier": "@kazupon/prettier-config",
|
|
92
93
|
"lint-staged": {
|