@kazupon/eslint-plugin 0.3.0 → 0.5.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 +5 -4
- package/lib/index.d.ts +2 -1
- package/lib/index.js +330 -41
- package/package.json +29 -28
package/README.md
CHANGED
|
@@ -61,10 +61,11 @@ The rules with the following star ⭐ are included in the configs.
|
|
|
61
61
|
|
|
62
62
|
### @kazupon/eslint-plugin Rules
|
|
63
63
|
|
|
64
|
-
| Rule ID
|
|
65
|
-
|
|
|
66
|
-
| [@kazupon/enforce-header-comment](https://eslint-plugin.kazupon.dev/rules/enforce-header-comment.html)
|
|
67
|
-
| [@kazupon/no-tag-comments](https://eslint-plugin.kazupon.dev/rules/no-tag-comments.html)
|
|
64
|
+
| Rule ID | Description | Category | Fixable | RECOMMENDED |
|
|
65
|
+
| :--------------------------------------------------------------------------------------------------------------- | :---------------------------------------------- | :------- | :-----: | :---------: |
|
|
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 | | ⭐ |
|
|
68
|
+
| [@kazupon/prefer-scope-on-tag-comment](https://eslint-plugin.kazupon.dev/rules/prefer-scope-on-tag-comment.html) | enforce adding a scope to tag comments | Comment | | ⭐ |
|
|
68
69
|
|
|
69
70
|
<!--RULES_TABLE_END-->
|
|
70
71
|
|
package/lib/index.d.ts
CHANGED
|
@@ -8,9 +8,10 @@ type PluginConfigs = {
|
|
|
8
8
|
declare const plugin: Omit<ESLint.Plugin, "configs"> & {
|
|
9
9
|
configs: PluginConfigs;
|
|
10
10
|
};
|
|
11
|
+
declare const recommendedConfig: Linter.Config[];
|
|
11
12
|
declare const commentConfig: Linter.Config[];
|
|
12
13
|
declare const configs: {
|
|
13
|
-
recommended: typeof
|
|
14
|
+
recommended: typeof recommendedConfig;
|
|
14
15
|
comment: typeof commentConfig;
|
|
15
16
|
};
|
|
16
17
|
/** @alias */
|
package/lib/index.js
CHANGED
|
@@ -12,7 +12,7 @@ const name = "@kazupon/eslint-plugin";
|
|
|
12
12
|
/**
|
|
13
13
|
* The plugin version.
|
|
14
14
|
*/
|
|
15
|
-
const version = "0.
|
|
15
|
+
const version = "0.5.0";
|
|
16
16
|
/**
|
|
17
17
|
* The namespace for rules
|
|
18
18
|
*/
|
|
@@ -22,7 +22,7 @@ const namespace = "@kazupon";
|
|
|
22
22
|
//#region src/utils/rule.ts
|
|
23
23
|
const BLOB_URL = "https://eslint-plugin.kazupon.dev/rules";
|
|
24
24
|
function RuleCreator(urlCreator, namespace$1 = "") {
|
|
25
|
-
return function createNamedRule({ meta, name: name$1,...rule$
|
|
25
|
+
return function createNamedRule({ meta, name: name$1,...rule$3 }) {
|
|
26
26
|
const ruleId = namespace$1 ? `${namespace$1}/${name$1}` : name$1;
|
|
27
27
|
return {
|
|
28
28
|
meta: {
|
|
@@ -34,7 +34,7 @@ function RuleCreator(urlCreator, namespace$1 = "") {
|
|
|
34
34
|
ruleId
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
|
-
...rule$
|
|
37
|
+
...rule$3
|
|
38
38
|
};
|
|
39
39
|
};
|
|
40
40
|
}
|
|
@@ -53,7 +53,7 @@ function initializeTagDiagnosis(tags) {
|
|
|
53
53
|
function validTagDiagnosis(tagDiagnosis) {
|
|
54
54
|
return Object.keys(tagDiagnosis).every((tag) => tagDiagnosis[tag] === "ok");
|
|
55
55
|
}
|
|
56
|
-
const rule$
|
|
56
|
+
const rule$2 = createRule({
|
|
57
57
|
name: "enforce-header-comment",
|
|
58
58
|
meta: {
|
|
59
59
|
type: "suggestion",
|
|
@@ -181,11 +181,10 @@ const rule$1 = createRule({
|
|
|
181
181
|
};
|
|
182
182
|
}
|
|
183
183
|
});
|
|
184
|
-
var enforce_header_comment_default = rule$
|
|
184
|
+
var enforce_header_comment_default = rule$2;
|
|
185
185
|
|
|
186
186
|
//#endregion
|
|
187
|
-
//#region src/
|
|
188
|
-
const DEFAULT_TAGS = ["FIXME", "BUG"];
|
|
187
|
+
//#region src/utils/comment.ts
|
|
189
188
|
/**
|
|
190
189
|
* Remove JSDoc asterisk prefix if present
|
|
191
190
|
*/
|
|
@@ -193,17 +192,77 @@ function stripJSDocPrefix(line) {
|
|
|
193
192
|
const trimmed = line.trim();
|
|
194
193
|
return trimmed.startsWith("*") ? trimmed.slice(1).trim() : trimmed;
|
|
195
194
|
}
|
|
196
|
-
|
|
195
|
+
/**
|
|
196
|
+
* Check if the text starts with any of the given tags
|
|
197
|
+
* @param text The text to check
|
|
198
|
+
* @param tags Array of tags to search for
|
|
199
|
+
* @returns Tag detection result or null if no tag found
|
|
200
|
+
*/
|
|
201
|
+
function detectTag(text, tags) {
|
|
202
|
+
for (const tag of tags) {
|
|
203
|
+
const tagRegex = /* @__PURE__ */ new RegExp(`^${tag}\\b`);
|
|
204
|
+
const match = text.match(tagRegex);
|
|
205
|
+
if (match) {
|
|
206
|
+
const afterTag = text.slice(tag.length);
|
|
207
|
+
if (afterTag.startsWith("(")) {
|
|
208
|
+
const closingParenIndex = afterTag.indexOf(")");
|
|
209
|
+
if (closingParenIndex > 0) {
|
|
210
|
+
const scope = afterTag.slice(1, closingParenIndex).trim();
|
|
211
|
+
return {
|
|
212
|
+
tag,
|
|
213
|
+
hasScope: scope.length > 0
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
tag,
|
|
218
|
+
hasScope: false
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
if (afterTag === "" || afterTag.startsWith(":") || afterTag.startsWith(" ")) return {
|
|
222
|
+
tag,
|
|
223
|
+
hasScope: false
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Calculate the exact location of a tag in a comment
|
|
231
|
+
* @param comment The comment containing the tag
|
|
232
|
+
* @param line The line of text containing the tag
|
|
233
|
+
* @param lineIndex The index of the line within the comment
|
|
234
|
+
* @param tag The tag to locate
|
|
235
|
+
* @returns Location with line and column, or null if not found
|
|
236
|
+
*/
|
|
237
|
+
function calculateTagLocation(comment, line, lineIndex, tag) {
|
|
238
|
+
const tagIndex = line.indexOf(tag);
|
|
239
|
+
if (tagIndex === -1) return null;
|
|
240
|
+
if (lineIndex === 0) {
|
|
241
|
+
const tagIndexInValue = comment.value.indexOf(tag);
|
|
242
|
+
return tagIndexInValue === -1 ? null : {
|
|
243
|
+
line: comment.loc.start.line,
|
|
244
|
+
column: comment.loc.start.column + 2 + tagIndexInValue
|
|
245
|
+
};
|
|
246
|
+
} else return {
|
|
247
|
+
line: comment.loc.start.line + lineIndex,
|
|
248
|
+
column: tagIndex
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
//#endregion
|
|
253
|
+
//#region src/rules/no-tag-comments.ts
|
|
254
|
+
const DEFAULT_TAGS$1 = ["FIXME", "BUG"];
|
|
255
|
+
const rule$1 = createRule({
|
|
197
256
|
name: "no-tag-comments",
|
|
198
257
|
meta: {
|
|
199
258
|
type: "problem",
|
|
200
259
|
docs: {
|
|
201
260
|
description: "disallow tag comments",
|
|
202
261
|
category: "Comment",
|
|
203
|
-
recommended:
|
|
262
|
+
recommended: true,
|
|
204
263
|
defaultSeverity: "warn"
|
|
205
264
|
},
|
|
206
|
-
messages: {
|
|
265
|
+
messages: { tagComment: "Exist '{{tag}}' tag comment" },
|
|
207
266
|
schema: [{
|
|
208
267
|
type: "object",
|
|
209
268
|
properties: { tags: {
|
|
@@ -216,59 +275,271 @@ const rule = createRule({
|
|
|
216
275
|
}]
|
|
217
276
|
},
|
|
218
277
|
create(ctx) {
|
|
219
|
-
const options = ctx.options[0] || { tags: DEFAULT_TAGS };
|
|
220
|
-
const tags = options.tags || DEFAULT_TAGS;
|
|
278
|
+
const options = ctx.options[0] || { tags: DEFAULT_TAGS$1 };
|
|
279
|
+
const tags = options.tags || DEFAULT_TAGS$1;
|
|
221
280
|
const sourceCode = ctx.sourceCode;
|
|
222
281
|
/**
|
|
223
|
-
*
|
|
282
|
+
* Report a tag comment violation
|
|
224
283
|
*/
|
|
225
|
-
function
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
284
|
+
function reportTag(comment, tag, loc) {
|
|
285
|
+
if (loc && comment.loc) ctx.report({
|
|
286
|
+
messageId: "tagComment",
|
|
287
|
+
data: { tag },
|
|
288
|
+
loc: {
|
|
289
|
+
start: {
|
|
290
|
+
line: loc.line,
|
|
291
|
+
column: loc.column
|
|
292
|
+
},
|
|
293
|
+
end: {
|
|
294
|
+
line: loc.line,
|
|
295
|
+
column: loc.column + tag.length
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
else ctx.report({
|
|
300
|
+
messageId: "tagComment",
|
|
301
|
+
data: { tag },
|
|
302
|
+
loc: comment.loc
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Check a comment for tag violations
|
|
307
|
+
*/
|
|
308
|
+
function checkComment(comment) {
|
|
309
|
+
const { value, type } = comment;
|
|
310
|
+
if (type === "Line") {
|
|
311
|
+
const tagInfo = detectTag(value.trim(), tags);
|
|
312
|
+
if (tagInfo) {
|
|
313
|
+
const tagIndex = value.indexOf(tagInfo.tag);
|
|
314
|
+
if (tagIndex !== -1) reportTag(comment, tagInfo.tag, {
|
|
315
|
+
line: comment.loc.start.line,
|
|
316
|
+
column: comment.loc.start.column + 2 + tagIndex
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const lines = value.split("\n");
|
|
322
|
+
for (const [i, line] of lines.entries()) {
|
|
323
|
+
const trimmedLine = line.trim();
|
|
324
|
+
if (!trimmedLine) continue;
|
|
325
|
+
const contentToCheck = stripJSDocPrefix(line);
|
|
326
|
+
const tagInfo = detectTag(contentToCheck, tags);
|
|
327
|
+
if (tagInfo) {
|
|
328
|
+
const location = calculateTagLocation(comment, line, i, tagInfo.tag);
|
|
329
|
+
if (location) {
|
|
330
|
+
reportTag(comment, tagInfo.tag, location);
|
|
331
|
+
break;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
229
334
|
}
|
|
230
|
-
return null;
|
|
231
335
|
}
|
|
336
|
+
return { Program() {
|
|
337
|
+
const comments = sourceCode.getAllComments();
|
|
338
|
+
for (const comment of comments) checkComment(comment);
|
|
339
|
+
} };
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
var no_tag_comments_default = rule$1;
|
|
343
|
+
|
|
344
|
+
//#endregion
|
|
345
|
+
//#region src/rules/prefer-scope-on-tag-comment.ts
|
|
346
|
+
const DEFAULT_TAGS = [
|
|
347
|
+
"TODO",
|
|
348
|
+
"FIXME",
|
|
349
|
+
"HACK",
|
|
350
|
+
"BUG",
|
|
351
|
+
"NOTE"
|
|
352
|
+
];
|
|
353
|
+
const DEFAULT_DIRECTIVES = [
|
|
354
|
+
"eslint-disable",
|
|
355
|
+
"eslint-disable-next-line",
|
|
356
|
+
"eslint-disable-line",
|
|
357
|
+
"@ts-expect-error",
|
|
358
|
+
"@ts-ignore",
|
|
359
|
+
"@ts-nocheck"
|
|
360
|
+
];
|
|
361
|
+
const rule = createRule({
|
|
362
|
+
name: "prefer-scope-on-tag-comment",
|
|
363
|
+
meta: {
|
|
364
|
+
type: "suggestion",
|
|
365
|
+
docs: {
|
|
366
|
+
description: "enforce adding a scope to tag comments",
|
|
367
|
+
category: "Comment",
|
|
368
|
+
recommended: true,
|
|
369
|
+
defaultSeverity: "warn"
|
|
370
|
+
},
|
|
371
|
+
messages: { missingScope: "Tag comment '{{tag}}' is missing a scope. Use format: {{tag}}(scope)" },
|
|
372
|
+
schema: [{
|
|
373
|
+
type: "object",
|
|
374
|
+
properties: {
|
|
375
|
+
tags: {
|
|
376
|
+
type: "array",
|
|
377
|
+
items: { type: "string" },
|
|
378
|
+
minItems: 1,
|
|
379
|
+
uniqueItems: true
|
|
380
|
+
},
|
|
381
|
+
directives: {
|
|
382
|
+
type: "array",
|
|
383
|
+
items: { type: "string" },
|
|
384
|
+
minItems: 1,
|
|
385
|
+
uniqueItems: true
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
additionalProperties: false
|
|
389
|
+
}]
|
|
390
|
+
},
|
|
391
|
+
create(ctx) {
|
|
392
|
+
const options = ctx.options[0] || { tags: DEFAULT_TAGS };
|
|
393
|
+
const tags = options.tags || DEFAULT_TAGS;
|
|
394
|
+
const directives = options.directives || DEFAULT_DIRECTIVES;
|
|
395
|
+
const sourceCode = ctx.sourceCode;
|
|
232
396
|
/**
|
|
233
|
-
* Report a
|
|
397
|
+
* Report a missing scope violation
|
|
234
398
|
*/
|
|
235
|
-
function
|
|
236
|
-
|
|
237
|
-
|
|
399
|
+
function reportMissingScope(comment, tag, loc) {
|
|
400
|
+
if (!comment.loc) {
|
|
401
|
+
ctx.report({
|
|
402
|
+
messageId: "missingScope",
|
|
403
|
+
data: { tag },
|
|
404
|
+
node: ctx.sourceCode.ast
|
|
405
|
+
});
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
if (loc && comment.loc) ctx.report({
|
|
409
|
+
messageId: "missingScope",
|
|
410
|
+
data: { tag },
|
|
411
|
+
loc: {
|
|
412
|
+
start: {
|
|
413
|
+
line: loc.line,
|
|
414
|
+
column: loc.column
|
|
415
|
+
},
|
|
416
|
+
end: {
|
|
417
|
+
line: loc.line,
|
|
418
|
+
column: loc.column + tag.length
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
else ctx.report({
|
|
423
|
+
messageId: "missingScope",
|
|
238
424
|
data: { tag },
|
|
239
425
|
loc: comment.loc
|
|
240
426
|
});
|
|
241
427
|
}
|
|
242
428
|
/**
|
|
243
|
-
*
|
|
429
|
+
* Check if comment starts with a directive and extract the description
|
|
430
|
+
* @returns Object with directive match info or null
|
|
244
431
|
*/
|
|
245
|
-
function
|
|
246
|
-
const
|
|
247
|
-
if (
|
|
248
|
-
|
|
249
|
-
|
|
432
|
+
function parseDirectiveComment(text) {
|
|
433
|
+
const trimmedText = text.trim();
|
|
434
|
+
for (const directive of directives) if (trimmedText.startsWith(directive)) {
|
|
435
|
+
const afterDirective = trimmedText.slice(directive.length);
|
|
436
|
+
const separatorIndex = afterDirective.indexOf("--");
|
|
437
|
+
if (separatorIndex !== -1) {
|
|
438
|
+
const description = afterDirective.slice(separatorIndex + 2).trim();
|
|
439
|
+
const separatorPos = text.indexOf("--");
|
|
440
|
+
const afterSeparator = text.slice(separatorPos + 2);
|
|
441
|
+
const descriptionStart = separatorPos + 2 + (afterSeparator.length - afterSeparator.trimStart().length);
|
|
442
|
+
return {
|
|
443
|
+
directive,
|
|
444
|
+
description,
|
|
445
|
+
descriptionStart
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
if (afterDirective.trim()) {
|
|
449
|
+
const spaceMatch = afterDirective.match(/^\s+/);
|
|
450
|
+
if (spaceMatch) {
|
|
451
|
+
const description = afterDirective.trim();
|
|
452
|
+
const directiveIndex = text.indexOf(directive);
|
|
453
|
+
const descriptionStart = directiveIndex + directive.length + spaceMatch[0].length;
|
|
454
|
+
return {
|
|
455
|
+
directive,
|
|
456
|
+
description,
|
|
457
|
+
descriptionStart
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
}
|
|
250
461
|
}
|
|
251
|
-
return
|
|
462
|
+
return null;
|
|
252
463
|
}
|
|
253
464
|
/**
|
|
254
|
-
* Check a comment for
|
|
465
|
+
* Check a comment for missing scope
|
|
255
466
|
*/
|
|
256
467
|
function checkComment(comment) {
|
|
257
468
|
const { value, type } = comment;
|
|
258
469
|
if (type === "Line") {
|
|
259
|
-
|
|
470
|
+
const directiveInfo$1 = parseDirectiveComment(value);
|
|
471
|
+
if (directiveInfo$1) {
|
|
472
|
+
const tagInfo$1 = detectTag(directiveInfo$1.description, tags);
|
|
473
|
+
if (tagInfo$1 && !tagInfo$1.hasScope) {
|
|
474
|
+
const tagIndex = directiveInfo$1.description.indexOf(tagInfo$1.tag);
|
|
475
|
+
if (tagIndex !== -1) reportMissingScope(comment, tagInfo$1.tag, {
|
|
476
|
+
line: comment.loc.start.line,
|
|
477
|
+
column: comment.loc.start.column + 2 + directiveInfo$1.descriptionStart + tagIndex
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
const tagInfo = detectTag(value.trim(), tags);
|
|
483
|
+
if (tagInfo && !tagInfo.hasScope) {
|
|
484
|
+
const tagIndex = value.indexOf(tagInfo.tag);
|
|
485
|
+
if (tagIndex !== -1) reportMissingScope(comment, tagInfo.tag, {
|
|
486
|
+
line: comment.loc.start.line,
|
|
487
|
+
column: comment.loc.start.column + 2 + tagIndex
|
|
488
|
+
});
|
|
489
|
+
}
|
|
260
490
|
return;
|
|
261
491
|
}
|
|
262
492
|
const lines = value.split("\n");
|
|
263
|
-
|
|
264
|
-
|
|
493
|
+
const directiveInfo = parseDirectiveComment(value);
|
|
494
|
+
if (directiveInfo) {
|
|
495
|
+
const tagInfo = detectTag(directiveInfo.description, tags);
|
|
496
|
+
if (tagInfo && !tagInfo.hasScope) if (lines.length === 1) {
|
|
497
|
+
const tagIndexInDesc = directiveInfo.description.indexOf(tagInfo.tag);
|
|
498
|
+
if (tagIndexInDesc !== -1) {
|
|
499
|
+
const tagIndexInValue = directiveInfo.descriptionStart + tagIndexInDesc;
|
|
500
|
+
const location = {
|
|
501
|
+
line: comment.loc.start.line,
|
|
502
|
+
column: comment.loc.start.column + 2 + tagIndexInValue
|
|
503
|
+
};
|
|
504
|
+
reportMissingScope(comment, tagInfo.tag, location);
|
|
505
|
+
}
|
|
506
|
+
} else {
|
|
507
|
+
const descLines = directiveInfo.description.split("\n");
|
|
508
|
+
for (const [descLineIndex, descLine] of descLines.entries()) {
|
|
509
|
+
const lineTagInfo = detectTag(descLine.trim(), tags);
|
|
510
|
+
if (lineTagInfo && !lineTagInfo.hasScope) {
|
|
511
|
+
const descStartInComment = value.indexOf(directiveInfo.description);
|
|
512
|
+
const linesBeforeDesc = value.slice(0, descStartInComment).split("\n").length - 1;
|
|
513
|
+
const actualLineIndex = linesBeforeDesc + descLineIndex;
|
|
514
|
+
if (actualLineIndex < lines.length) {
|
|
515
|
+
const actualLine = lines[actualLineIndex];
|
|
516
|
+
const tagIndex = actualLine.indexOf(lineTagInfo.tag);
|
|
517
|
+
if (tagIndex !== -1) {
|
|
518
|
+
const location = {
|
|
519
|
+
line: comment.loc.start.line + actualLineIndex,
|
|
520
|
+
column: actualLineIndex === 0 ? comment.loc.start.column + 2 + tagIndex : tagIndex
|
|
521
|
+
};
|
|
522
|
+
reportMissingScope(comment, lineTagInfo.tag, location);
|
|
523
|
+
break;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
265
529
|
return;
|
|
266
530
|
}
|
|
267
|
-
for (const line of lines) {
|
|
531
|
+
for (const [i, line] of lines.entries()) {
|
|
268
532
|
const trimmedLine = line.trim();
|
|
269
533
|
if (!trimmedLine) continue;
|
|
270
534
|
const contentToCheck = stripJSDocPrefix(line);
|
|
271
|
-
|
|
535
|
+
const tagInfo = detectTag(contentToCheck, tags);
|
|
536
|
+
if (tagInfo && !tagInfo.hasScope) {
|
|
537
|
+
const location = calculateTagLocation(comment, line, i, tagInfo.tag);
|
|
538
|
+
if (location) {
|
|
539
|
+
reportMissingScope(comment, tagInfo.tag, location);
|
|
540
|
+
break;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
272
543
|
}
|
|
273
544
|
}
|
|
274
545
|
return { Program() {
|
|
@@ -277,13 +548,14 @@ const rule = createRule({
|
|
|
277
548
|
} };
|
|
278
549
|
}
|
|
279
550
|
});
|
|
280
|
-
var
|
|
551
|
+
var prefer_scope_on_tag_comment_default = rule;
|
|
281
552
|
|
|
282
553
|
//#endregion
|
|
283
554
|
//#region src/rules/index.ts
|
|
284
555
|
const rules = {
|
|
285
556
|
"enforce-header-comment": enforce_header_comment_default,
|
|
286
|
-
"no-tag-comments": no_tag_comments_default
|
|
557
|
+
"no-tag-comments": no_tag_comments_default,
|
|
558
|
+
"prefer-scope-on-tag-comment": prefer_scope_on_tag_comment_default
|
|
287
559
|
};
|
|
288
560
|
|
|
289
561
|
//#endregion
|
|
@@ -296,6 +568,23 @@ const plugin = {
|
|
|
296
568
|
rules,
|
|
297
569
|
configs: {}
|
|
298
570
|
};
|
|
571
|
+
const recommendedConfig = [{
|
|
572
|
+
name: "@kazupon/eslint-plugin/recommended",
|
|
573
|
+
files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
|
574
|
+
ignores: [
|
|
575
|
+
"**/*.md",
|
|
576
|
+
"**/*.md/**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}",
|
|
577
|
+
"**/*.config.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"
|
|
578
|
+
],
|
|
579
|
+
plugins: { [namespace]: plugin },
|
|
580
|
+
rules: Object.entries(rules).reduce((acc, [ruleName, rule$3]) => {
|
|
581
|
+
if (rule$3.meta?.docs?.recommended) {
|
|
582
|
+
const ruleId = rule$3.meta?.docs?.ruleId || (namespace ? `${namespace}/${ruleName}` : ruleName);
|
|
583
|
+
acc[ruleId] = rule$3.meta?.docs?.defaultSeverity || "warn";
|
|
584
|
+
}
|
|
585
|
+
return acc;
|
|
586
|
+
}, Object.create(null))
|
|
587
|
+
}];
|
|
299
588
|
const commentConfig = [{
|
|
300
589
|
name: "@kazupon/eslint-plugin/comment",
|
|
301
590
|
files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
|
@@ -305,14 +594,14 @@ const commentConfig = [{
|
|
|
305
594
|
"**/*.config.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"
|
|
306
595
|
],
|
|
307
596
|
plugins: { [namespace]: plugin },
|
|
308
|
-
rules: Object.entries(rules).reduce((rules$1, [ruleName, rule$
|
|
309
|
-
const ruleId = rule$
|
|
310
|
-
rules$1[ruleId] = rule$
|
|
597
|
+
rules: Object.entries(rules).reduce((rules$1, [ruleName, rule$3]) => {
|
|
598
|
+
const ruleId = rule$3.meta?.docs?.ruleId || (namespace ? `${namespace}/${ruleName}` : ruleName);
|
|
599
|
+
rules$1[ruleId] = rule$3.meta?.docs?.defaultSeverity || "warn";
|
|
311
600
|
return rules$1;
|
|
312
601
|
}, Object.create(null))
|
|
313
602
|
}];
|
|
314
603
|
const configs = {
|
|
315
|
-
recommended:
|
|
604
|
+
recommended: recommendedConfig,
|
|
316
605
|
comment: commentConfig
|
|
317
606
|
};
|
|
318
607
|
plugin.configs = configs;
|
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.5.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"funding": "https://github.com/sponsors/kazupon",
|
|
7
7
|
"bugs": {
|
|
@@ -47,47 +47,48 @@
|
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@es-joy/jsdoccomment": "^0.
|
|
51
|
-
"@eslint/core": "^0.
|
|
50
|
+
"@es-joy/jsdoccomment": "^0.52.0",
|
|
51
|
+
"@eslint/core": "^0.15.1"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"eslint": "^9.0.0"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@eslint/compat": "^1.
|
|
58
|
-
"@eslint/markdown": "^
|
|
59
|
-
"@kazupon/eslint-config": "^0.
|
|
57
|
+
"@eslint/compat": "^1.3.1",
|
|
58
|
+
"@eslint/markdown": "^7.0.0",
|
|
59
|
+
"@kazupon/eslint-config": "^0.32.0",
|
|
60
60
|
"@kazupon/prettier-config": "^0.1.1",
|
|
61
|
-
"@shikijs/vitepress-twoslash": "^3.
|
|
62
|
-
"@types/node": "^22.
|
|
63
|
-
"@vitest/eslint-plugin": "^1.
|
|
64
|
-
"bumpp": "^10.
|
|
65
|
-
"eslint": "^9.
|
|
66
|
-
"eslint-config-prettier": "^10.1.
|
|
67
|
-
"eslint-import-resolver-typescript": "^4.4.
|
|
68
|
-
"eslint-plugin-import": "^2.
|
|
61
|
+
"@shikijs/vitepress-twoslash": "^3.8.1",
|
|
62
|
+
"@types/node": "^22.16.5",
|
|
63
|
+
"@vitest/eslint-plugin": "^1.3.4",
|
|
64
|
+
"bumpp": "^10.2.0",
|
|
65
|
+
"eslint": "^9.32.0",
|
|
66
|
+
"eslint-config-prettier": "^10.1.8",
|
|
67
|
+
"eslint-import-resolver-typescript": "^4.4.4",
|
|
68
|
+
"eslint-plugin-import": "^2.32.0",
|
|
69
69
|
"eslint-plugin-jsonc": "^2.20.1",
|
|
70
70
|
"eslint-plugin-module-interop": "^0.3.1",
|
|
71
71
|
"eslint-plugin-promise": "^7.2.1",
|
|
72
|
-
"eslint-plugin-
|
|
72
|
+
"eslint-plugin-regexp": "^2.9.0",
|
|
73
|
+
"eslint-plugin-unicorn": "^60.0.0",
|
|
73
74
|
"eslint-plugin-unused-imports": "^4.1.4",
|
|
74
75
|
"eslint-plugin-yml": "^1.18.0",
|
|
75
76
|
"eslint-vitest-rule-tester": "^2.2.0",
|
|
76
77
|
"gh-changelogen": "^0.2.8",
|
|
77
|
-
"knip": "^5.
|
|
78
|
-
"lint-staged": "^16.
|
|
79
|
-
"pkg-pr-new": "^0.0.
|
|
80
|
-
"prettier": "^3.
|
|
78
|
+
"knip": "^5.62.0",
|
|
79
|
+
"lint-staged": "^16.1.2",
|
|
80
|
+
"pkg-pr-new": "^0.0.54",
|
|
81
|
+
"prettier": "^3.6.2",
|
|
81
82
|
"publint": "^0.3.12",
|
|
82
|
-
"tsdown": "^0.
|
|
83
|
-
"tsx": "^4.
|
|
84
|
-
"twoslash-eslint": "^0.3.
|
|
83
|
+
"tsdown": "^0.13.0",
|
|
84
|
+
"tsx": "^4.20.3",
|
|
85
|
+
"twoslash-eslint": "^0.3.3",
|
|
85
86
|
"typescript": "^5.8.3",
|
|
86
|
-
"typescript-eslint": "^8.
|
|
87
|
-
"vite-plugin-eslint4b": "^0.
|
|
87
|
+
"typescript-eslint": "^8.38.0",
|
|
88
|
+
"vite-plugin-eslint4b": "^0.6.0",
|
|
88
89
|
"vitepress": "^1.6.3",
|
|
89
|
-
"vitepress-plugin-group-icons": "^1.6.
|
|
90
|
-
"vitest": "^3.2.
|
|
90
|
+
"vitepress-plugin-group-icons": "^1.6.1",
|
|
91
|
+
"vitest": "^3.2.4"
|
|
91
92
|
},
|
|
92
93
|
"prettier": "@kazupon/prettier-config",
|
|
93
94
|
"lint-staged": {
|
|
@@ -117,11 +118,11 @@
|
|
|
117
118
|
"fix": "pnpm run --stream --color \"/^fix:/\"",
|
|
118
119
|
"fix:eslint": "eslint . --fix",
|
|
119
120
|
"fix:knip": "knip --fix --no-exit-code",
|
|
120
|
-
"fix:prettier": "prettier . --write",
|
|
121
|
+
"fix:prettier": "prettier . --write --experimental-cli",
|
|
121
122
|
"lint": "pnpm run --stream --color \"/^lint:/\"",
|
|
122
123
|
"lint:eslint": "eslint .",
|
|
123
124
|
"lint:knip": "knip",
|
|
124
|
-
"lint:prettier": "prettier . --check",
|
|
125
|
+
"lint:prettier": "prettier . --check --experimental-cli",
|
|
125
126
|
"release": "bumpp --commit \"release: v%s\" --all --push --tag",
|
|
126
127
|
"test": "vitest run",
|
|
127
128
|
"typecheck": "pnpm run --stream --color \"/^typecheck:/\"",
|