@kazupon/eslint-plugin 0.2.2 → 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 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
- recommended: Linter.Config<Linter.RulesRecord>[]
6
- comment: Linter.Config<Linter.RulesRecord>[]
5
+ recommended: Linter.Config<Linter.RulesRecord>[];
6
+ comment: Linter.Config<Linter.RulesRecord>[];
7
7
  };
8
8
  declare const plugin: Omit<ESLint.Plugin, "configs"> & {
9
- configs: PluginConfigs
9
+ configs: PluginConfigs;
10
10
  };
11
11
  declare const commentConfig: Linter.Config[];
12
12
  declare const configs: {
13
- recommended: typeof commentConfig
14
- comment: typeof commentConfig
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
- const version = "0.2.2";
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
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$1 }) {
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,7 +34,7 @@ function RuleCreator(urlCreator, namespace$1 = "") {
21
34
  ruleId
22
35
  }
23
36
  },
24
- ...rule$1
37
+ ...rule$2
25
38
  };
26
39
  };
27
40
  }
@@ -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 = { "enforce-header-comment": enforce_header_comment_default };
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$1]) => {
197
- const ruleId = rule$1.meta?.docs?.ruleId || (namespace ? `${namespace}/${ruleName}` : ruleName);
198
- rules$1[ruleId] = rule$1.meta?.docs?.defaultSeverity || "warn";
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.2.2",
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.0",
51
- "@eslint/core": "^0.13.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/markdown": "^6.3.0",
58
- "@kazupon/eslint-config": "^0.28.0",
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.2.2",
61
- "@types/node": "^22.14.1",
62
- "@vitest/eslint-plugin": "^1.1.42",
63
- "bumpp": "^10.1.0",
64
- "eslint": "^9.24.0",
65
- "eslint-config-prettier": "^10.1.2",
66
- "eslint-import-resolver-typescript": "^4.3.2",
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.0",
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.17.0",
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.50.2",
77
- "lint-staged": "^15.5.1",
78
- "pkg-pr-new": "^0.0.42",
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.11",
81
- "tsdown": "^0.8.0-beta.2",
82
- "tsx": "^4.19.3",
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.29.1",
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.4.1",
89
- "vitest": "^3.1.1"
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": {