@kazupon/eslint-plugin 0.6.1 → 0.7.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 +22 -11
- package/lib/index.d.ts +36 -3
- package/lib/index.js +148 -111
- package/oxlint/recommended.json +57 -0
- package/package.json +65 -52
package/README.md
CHANGED
|
@@ -2,16 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
ESLint plugin for @kazupon
|
|
4
4
|
|
|
5
|
-
<!-- eslint-disable markdown/no-missing-label-refs -->
|
|
6
|
-
|
|
7
|
-
> [!WARNING]
|
|
8
|
-
> This eslint-plugin is a rule that I’ve made as I needed it to advance the open-source project.
|
|
9
|
-
> Therefore, updates are often made, and sometimes there are also destructive changes.
|
|
10
|
-
> This eslint-plugin is open-source, so you can use it for your own projects, but please keep in mind that this plugin is specialized for my own use.
|
|
11
|
-
> Of course, since it is open-source, you are free to fork it and use it yourself 😉.
|
|
12
|
-
|
|
13
|
-
<!-- eslint-enable markdown/no-missing-label-refs -->
|
|
14
|
-
|
|
15
5
|
## 💿 Installation
|
|
16
6
|
|
|
17
7
|
```sh
|
|
@@ -31,11 +21,16 @@ bun add -D @kazupon/eslint-plugin
|
|
|
31
21
|
## 📋 Requirements
|
|
32
22
|
|
|
33
23
|
- **ESLint**: v9 or later
|
|
34
|
-
- **
|
|
24
|
+
- **oxlint**: v1.35 or later
|
|
25
|
+
- **Configuration**:
|
|
26
|
+
- ESLint: flat config style `eslint.config.[js|ts]`, not support legacy config style `.eslintrc`
|
|
27
|
+
- oxlint: json or jsonc style like `.oxlintrc.json` or `.oxlintrc.jsonc`
|
|
35
28
|
- **Node.js**: v20 or later
|
|
36
29
|
|
|
37
30
|
## 🚀 Usage
|
|
38
31
|
|
|
32
|
+
### ESLint
|
|
33
|
+
|
|
39
34
|
Example `eslint.config.js`:
|
|
40
35
|
|
|
41
36
|
```js
|
|
@@ -52,6 +47,22 @@ export default defineConfig(
|
|
|
52
47
|
)
|
|
53
48
|
```
|
|
54
49
|
|
|
50
|
+
### oxlint
|
|
51
|
+
|
|
52
|
+
Example [oxlint configuration file](https://oxc.rs/docs/guide/usage/linter/config.html) such as `.oxlintrc.json`:
|
|
53
|
+
|
|
54
|
+
<!-- eslint-skip -->
|
|
55
|
+
|
|
56
|
+
```jsonc
|
|
57
|
+
{
|
|
58
|
+
// ...
|
|
59
|
+
|
|
60
|
+
"extends": ["./node_modules/@kazupon/eslint-plugin/oxlint/recommended.json"]
|
|
61
|
+
|
|
62
|
+
// ...
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
55
66
|
## ✅ Rules
|
|
56
67
|
|
|
57
68
|
The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) automatically fixes problems reported by rules which have a wrench 🔧 below.
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
import { ESLint, Linter } from "eslint";
|
|
2
2
|
|
|
3
|
+
//#region src/utils/types.d.ts
|
|
4
|
+
|
|
5
|
+
declare module "@eslint/core" {
|
|
6
|
+
interface RulesMetaDocs {
|
|
7
|
+
/**
|
|
8
|
+
* The id of the rule. (e.g `@typescript-eslint/explicit-module-boundary-types`)
|
|
9
|
+
*/
|
|
10
|
+
ruleId?: string | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* The name of the rule. (e.g `explicit-module-boundary-types`)
|
|
13
|
+
*/
|
|
14
|
+
ruleName?: string | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* The default severity of the rule. (e.g `error`, `warn`, `off`)
|
|
17
|
+
*/
|
|
18
|
+
defaultSeverity?: Linter.StringSeverity | undefined;
|
|
19
|
+
}
|
|
20
|
+
interface RuleDefinition {
|
|
21
|
+
/**
|
|
22
|
+
* The name of rule. (e.g `@typescript-eslint/explicit-module-boundary-types`)
|
|
23
|
+
*/
|
|
24
|
+
name: string;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* NOTE(kazupon):
|
|
29
|
+
* The current `RuleDefinition` is inferred by the `SourceCode` of `@eslint/core` whose type parameter is the context passed to create.
|
|
30
|
+
* We want to use interfaces of `SourceCode` of `eslint`, so we redefine it so that we can use them.
|
|
31
|
+
*/
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/rules/index.d.ts
|
|
34
|
+
declare const defaultOptions: Record<string, unknown>;
|
|
35
|
+
//#endregion
|
|
3
36
|
//#region src/index.d.ts
|
|
4
37
|
type PluginConfigs = {
|
|
5
38
|
recommended: Linter.Config<Linter.RulesRecord>[];
|
|
@@ -8,6 +41,8 @@ type PluginConfigs = {
|
|
|
8
41
|
declare const plugin: Omit<ESLint.Plugin, "configs"> & {
|
|
9
42
|
configs: PluginConfigs;
|
|
10
43
|
};
|
|
44
|
+
declare const baseIgnores: string[];
|
|
45
|
+
declare const enforceHeaderCommentIgnores: string[];
|
|
11
46
|
declare const recommendedConfig: Linter.Config[];
|
|
12
47
|
declare const commentConfig: Linter.Config[];
|
|
13
48
|
/**
|
|
@@ -23,7 +58,5 @@ declare const configs: {
|
|
|
23
58
|
*/
|
|
24
59
|
comment: typeof commentConfig;
|
|
25
60
|
};
|
|
26
|
-
/** @alias */
|
|
27
|
-
|
|
28
61
|
//#endregion
|
|
29
|
-
export { configs, plugin as default, plugin };
|
|
62
|
+
export { baseIgnores, configs, plugin as default, plugin, defaultOptions, enforceHeaderCommentIgnores };
|
package/lib/index.js
CHANGED
|
@@ -21,18 +21,14 @@ function stripJSDocPrefix(line) {
|
|
|
21
21
|
function detectTag(text, tags) {
|
|
22
22
|
for (const tag of tags) {
|
|
23
23
|
const tagRegex = /* @__PURE__ */ new RegExp(`^${tag}\\b`);
|
|
24
|
-
|
|
25
|
-
if (match) {
|
|
24
|
+
if (text.match(tagRegex)) {
|
|
26
25
|
const afterTag = text.slice(tag.length);
|
|
27
26
|
if (afterTag.startsWith("(")) {
|
|
28
27
|
const closingParenIndex = afterTag.indexOf(")");
|
|
29
|
-
if (closingParenIndex > 0) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
hasScope: scope.length > 0
|
|
34
|
-
};
|
|
35
|
-
}
|
|
28
|
+
if (closingParenIndex > 0) return {
|
|
29
|
+
tag,
|
|
30
|
+
hasScope: afterTag.slice(1, closingParenIndex).trim().length > 0
|
|
31
|
+
};
|
|
36
32
|
return {
|
|
37
33
|
tag,
|
|
38
34
|
hasScope: false
|
|
@@ -164,25 +160,19 @@ function parseDirectiveComment(text, directives) {
|
|
|
164
160
|
const description = afterDirective.slice(separatorIndex + 2).trim();
|
|
165
161
|
const separatorPos = text.indexOf("--");
|
|
166
162
|
const afterSeparator = text.slice(separatorPos + 2);
|
|
167
|
-
const descriptionStart = separatorPos + 2 + (afterSeparator.length - afterSeparator.trimStart().length);
|
|
168
163
|
return {
|
|
169
164
|
directive,
|
|
170
165
|
description,
|
|
171
|
-
descriptionStart
|
|
166
|
+
descriptionStart: separatorPos + 2 + (afterSeparator.length - afterSeparator.trimStart().length)
|
|
172
167
|
};
|
|
173
168
|
}
|
|
174
169
|
if (afterDirective.trim()) {
|
|
175
170
|
const spaceMatch = afterDirective.match(/^\s+/);
|
|
176
|
-
if (spaceMatch) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
directive,
|
|
182
|
-
description,
|
|
183
|
-
descriptionStart
|
|
184
|
-
};
|
|
185
|
-
}
|
|
171
|
+
if (spaceMatch) return {
|
|
172
|
+
directive,
|
|
173
|
+
description: afterDirective.trim(),
|
|
174
|
+
descriptionStart: text.indexOf(directive) + directive.length + spaceMatch[0].length
|
|
175
|
+
};
|
|
186
176
|
}
|
|
187
177
|
}
|
|
188
178
|
return null;
|
|
@@ -197,29 +187,66 @@ function parseDirectiveComment(text, directives) {
|
|
|
197
187
|
/**
|
|
198
188
|
* The plugin name.
|
|
199
189
|
*/
|
|
200
|
-
const
|
|
190
|
+
const NAME = "@kazupon/eslint-plugin";
|
|
201
191
|
/**
|
|
202
192
|
* The plugin version.
|
|
203
193
|
*/
|
|
204
|
-
const
|
|
194
|
+
const VERSION = "0.7.0";
|
|
205
195
|
/**
|
|
206
196
|
* The namespace for rules
|
|
207
197
|
*/
|
|
208
|
-
const
|
|
198
|
+
const NAMESPACE = "@kazupon";
|
|
199
|
+
/**
|
|
200
|
+
* The file extensions to be linted.
|
|
201
|
+
*/
|
|
202
|
+
const EXTENSIONS = [
|
|
203
|
+
"js",
|
|
204
|
+
"mjs",
|
|
205
|
+
"cjs",
|
|
206
|
+
"ts",
|
|
207
|
+
"mts",
|
|
208
|
+
"cts",
|
|
209
|
+
"jsx",
|
|
210
|
+
"tsx"
|
|
211
|
+
].join(",");
|
|
212
|
+
/**
|
|
213
|
+
* The markdown glob patterns.
|
|
214
|
+
*/
|
|
215
|
+
const GLOB_MARKDOWN = `**/*.md`;
|
|
216
|
+
/**
|
|
217
|
+
* The code files glob patterns based on markdown glob patterns.
|
|
218
|
+
*/
|
|
219
|
+
const GLOB_MARKDOWN_CODES = `${GLOB_MARKDOWN}/**/*.{${EXTENSIONS}}`;
|
|
220
|
+
/**
|
|
221
|
+
* The glob patterns for all code files.
|
|
222
|
+
*/
|
|
223
|
+
const GLOB_FILES = `**/*.{${EXTENSIONS}}`;
|
|
224
|
+
/**
|
|
225
|
+
* The glob patterns for all config files.
|
|
226
|
+
*/
|
|
227
|
+
const GLOB_CONFIG_FILES = `**/*.config.{${EXTENSIONS}}`;
|
|
228
|
+
/**
|
|
229
|
+
* The glob patterns for test files.
|
|
230
|
+
*/
|
|
231
|
+
const TEST_GLOB_FILES = `**/*.{test,spec}.{${EXTENSIONS}}`;
|
|
232
|
+
/**
|
|
233
|
+
* The glob patterns for test declaration files.
|
|
234
|
+
*/
|
|
235
|
+
const TEST_DTS_GLOB_FILES = `**/*.{test,spec}.d.{ts,tsx}`;
|
|
209
236
|
|
|
210
237
|
//#endregion
|
|
211
238
|
//#region src/utils/rule.ts
|
|
212
239
|
const BLOB_URL = "https://eslint-plugin.kazupon.dev/rules";
|
|
213
|
-
function RuleCreator(urlCreator, namespace
|
|
214
|
-
return function createNamedRule({ meta, name
|
|
215
|
-
const ruleId = namespace
|
|
240
|
+
function RuleCreator(urlCreator, namespace = "") {
|
|
241
|
+
return function createNamedRule({ meta, name,...rule$4 }) {
|
|
242
|
+
const ruleId = namespace ? `${namespace}/${name}` : name;
|
|
216
243
|
return {
|
|
217
244
|
meta: {
|
|
218
245
|
...meta,
|
|
219
246
|
docs: {
|
|
220
247
|
...meta?.docs,
|
|
221
|
-
url: urlCreator(name
|
|
222
|
-
ruleName: name
|
|
248
|
+
url: urlCreator(name),
|
|
249
|
+
ruleName: name,
|
|
223
250
|
ruleId
|
|
224
251
|
}
|
|
225
252
|
},
|
|
@@ -229,7 +256,7 @@ function RuleCreator(urlCreator, namespace$1 = "") {
|
|
|
229
256
|
}
|
|
230
257
|
const createRule = RuleCreator((ruleName) => {
|
|
231
258
|
return `${BLOB_URL}/${ruleName}`;
|
|
232
|
-
},
|
|
259
|
+
}, NAMESPACE);
|
|
233
260
|
|
|
234
261
|
//#endregion
|
|
235
262
|
//#region src/rules/enforce-header-comment.ts
|
|
@@ -251,7 +278,7 @@ const rule$3 = createRule({
|
|
|
251
278
|
description: "Enforce heading the comment in source code file",
|
|
252
279
|
category: "Comment",
|
|
253
280
|
recommended: true,
|
|
254
|
-
defaultSeverity: "
|
|
281
|
+
defaultSeverity: "warn"
|
|
255
282
|
},
|
|
256
283
|
messages: {
|
|
257
284
|
headerCommentEnforce: "Header comment is enforced",
|
|
@@ -296,8 +323,7 @@ const rule$3 = createRule({
|
|
|
296
323
|
else {
|
|
297
324
|
const lastComment = comments.at(-1);
|
|
298
325
|
const firstNode = node.body[0];
|
|
299
|
-
|
|
300
|
-
taregetComments = distance > 1 ? comments : comments.slice(0, -1);
|
|
326
|
+
taregetComments = Math.abs(lastComment.range[1] - firstNode.range[0]) > 1 ? comments : comments.slice(0, -1);
|
|
301
327
|
}
|
|
302
328
|
},
|
|
303
329
|
"Program:exit": (node) => {
|
|
@@ -369,30 +395,9 @@ const rule$3 = createRule({
|
|
|
369
395
|
});
|
|
370
396
|
var enforce_header_comment_default = rule$3;
|
|
371
397
|
|
|
372
|
-
//#endregion
|
|
373
|
-
//#region src/utils/options.ts
|
|
374
|
-
/**
|
|
375
|
-
* @author kazuya kawaguchi (a.k.a. kazupon)
|
|
376
|
-
* @license MIT
|
|
377
|
-
*/
|
|
378
|
-
/**
|
|
379
|
-
* Parse array options with defaults
|
|
380
|
-
*
|
|
381
|
-
* @typeParam T - The type of the options object
|
|
382
|
-
*
|
|
383
|
-
* @param options - The options object that may contain array fields
|
|
384
|
-
* @param arrayFields - Object mapping field names to their default arrays
|
|
385
|
-
* @returns The parsed options with default arrays applied
|
|
386
|
-
*/
|
|
387
|
-
function parseArrayOptions(options, arrayFields) {
|
|
388
|
-
const result = options ? { ...options } : {};
|
|
389
|
-
for (const [field, defaultArray] of Object.entries(arrayFields)) if (!result[field] || !Array.isArray(result[field])) result[field] = defaultArray;
|
|
390
|
-
return result;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
398
|
//#endregion
|
|
394
399
|
//#region src/rules/no-tag-comments.ts
|
|
395
|
-
const DEFAULT_TAGS
|
|
400
|
+
const DEFAULT_TAGS = ["FIXME", "BUG"];
|
|
396
401
|
const rule$2 = createRule({
|
|
397
402
|
name: "no-tag-comments",
|
|
398
403
|
meta: {
|
|
@@ -404,6 +409,7 @@ const rule$2 = createRule({
|
|
|
404
409
|
defaultSeverity: "warn"
|
|
405
410
|
},
|
|
406
411
|
messages: { tagComment: "Exist '{{tag}}' tag comment" },
|
|
412
|
+
defaultOptions: [{ tags: DEFAULT_TAGS }],
|
|
407
413
|
schema: [{
|
|
408
414
|
type: "object",
|
|
409
415
|
properties: { tags: {
|
|
@@ -416,8 +422,7 @@ const rule$2 = createRule({
|
|
|
416
422
|
}]
|
|
417
423
|
},
|
|
418
424
|
create(ctx) {
|
|
419
|
-
const
|
|
420
|
-
const tags = options.tags;
|
|
425
|
+
const tags = ctx.options[0].tags;
|
|
421
426
|
const sourceCode = ctx.sourceCode;
|
|
422
427
|
/**
|
|
423
428
|
* Report a tag comment violation
|
|
@@ -452,10 +457,8 @@ const rule$2 = createRule({
|
|
|
452
457
|
}
|
|
453
458
|
const lines = value.split("\n");
|
|
454
459
|
for (const [i, line] of lines.entries()) {
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
const contentToCheck = stripJSDocPrefix(line);
|
|
458
|
-
const tagInfo = detectTag(contentToCheck, tags);
|
|
460
|
+
if (!line.trim()) continue;
|
|
461
|
+
const tagInfo = detectTag(stripJSDocPrefix(line), tags);
|
|
459
462
|
if (tagInfo) {
|
|
460
463
|
const location = calculateTagLocation(comment, line, i, tagInfo.tag);
|
|
461
464
|
if (location) {
|
|
@@ -567,10 +570,10 @@ const rule$1 = createRule({
|
|
|
567
570
|
column: position.column + word.length
|
|
568
571
|
}
|
|
569
572
|
},
|
|
570
|
-
fix(fixer) {
|
|
571
|
-
const
|
|
572
|
-
const
|
|
573
|
-
return fixer.
|
|
573
|
+
*fix(fixer) {
|
|
574
|
+
const start = comment.range[0] + 2 + index;
|
|
575
|
+
const end = start + word.length;
|
|
576
|
+
return [yield fixer.insertTextBeforeRange([start, start], "`"), yield fixer.insertTextAfterRange([start, end], "`")];
|
|
574
577
|
}
|
|
575
578
|
});
|
|
576
579
|
}
|
|
@@ -585,7 +588,7 @@ var prefer_inline_code_words_comments_default = rule$1;
|
|
|
585
588
|
|
|
586
589
|
//#endregion
|
|
587
590
|
//#region src/rules/prefer-scope-on-tag-comment.ts
|
|
588
|
-
const DEFAULT_TAGS = [
|
|
591
|
+
const DEFAULT_TAGS$1 = [
|
|
589
592
|
"TODO",
|
|
590
593
|
"FIXME",
|
|
591
594
|
"HACK",
|
|
@@ -611,6 +614,10 @@ const rule = createRule({
|
|
|
611
614
|
defaultSeverity: "warn"
|
|
612
615
|
},
|
|
613
616
|
messages: { missingScope: "Tag comment '{{tag}}' is missing a scope. Use format: {{tag}}(scope)" },
|
|
617
|
+
defaultOptions: [{
|
|
618
|
+
tags: DEFAULT_TAGS$1,
|
|
619
|
+
directives: DEFAULT_DIRECTIVES
|
|
620
|
+
}],
|
|
614
621
|
schema: [{
|
|
615
622
|
type: "object",
|
|
616
623
|
properties: {
|
|
@@ -631,10 +638,7 @@ const rule = createRule({
|
|
|
631
638
|
}]
|
|
632
639
|
},
|
|
633
640
|
create(ctx) {
|
|
634
|
-
const options =
|
|
635
|
-
tags: DEFAULT_TAGS,
|
|
636
|
-
directives: DEFAULT_DIRECTIVES
|
|
637
|
-
});
|
|
641
|
+
const options = ctx.options[0];
|
|
638
642
|
const tags = options.tags;
|
|
639
643
|
const directives = options.directives;
|
|
640
644
|
const sourceCode = ctx.sourceCode;
|
|
@@ -700,11 +704,9 @@ const rule = createRule({
|
|
|
700
704
|
const lineTagInfo = detectTag(descLine.trim(), tags);
|
|
701
705
|
if (lineTagInfo && !lineTagInfo.hasScope) {
|
|
702
706
|
const descStartInComment = value.indexOf(directiveInfo.description);
|
|
703
|
-
const
|
|
704
|
-
const actualLineIndex = linesBeforeDesc + descLineIndex;
|
|
707
|
+
const actualLineIndex = value.slice(0, descStartInComment).split("\n").length - 1 + descLineIndex;
|
|
705
708
|
if (actualLineIndex < lines.length) {
|
|
706
|
-
const
|
|
707
|
-
const tagIndex = actualLine.indexOf(lineTagInfo.tag);
|
|
709
|
+
const tagIndex = lines[actualLineIndex].indexOf(lineTagInfo.tag);
|
|
708
710
|
if (tagIndex !== -1) {
|
|
709
711
|
const location = {
|
|
710
712
|
line: comment.loc.start.line + actualLineIndex,
|
|
@@ -720,10 +722,8 @@ const rule = createRule({
|
|
|
720
722
|
return;
|
|
721
723
|
}
|
|
722
724
|
for (const [i, line] of lines.entries()) {
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
const contentToCheck = stripJSDocPrefix(line);
|
|
726
|
-
const tagInfo = detectTag(contentToCheck, tags);
|
|
725
|
+
if (!line.trim()) continue;
|
|
726
|
+
const tagInfo = detectTag(stripJSDocPrefix(line), tags);
|
|
727
727
|
if (tagInfo && !tagInfo.hasScope) {
|
|
728
728
|
const location = calculateTagLocation(comment, line, i, tagInfo.tag);
|
|
729
729
|
if (location) {
|
|
@@ -742,6 +742,13 @@ var prefer_scope_on_tag_comment_default = rule;
|
|
|
742
742
|
|
|
743
743
|
//#endregion
|
|
744
744
|
//#region src/rules/index.ts
|
|
745
|
+
const defaultOptions = {
|
|
746
|
+
"no-tag-comments": { tags: DEFAULT_TAGS },
|
|
747
|
+
"prefer-scope-on-tag-comment": {
|
|
748
|
+
tags: DEFAULT_TAGS$1,
|
|
749
|
+
directives: DEFAULT_DIRECTIVES
|
|
750
|
+
}
|
|
751
|
+
};
|
|
745
752
|
const rules = {
|
|
746
753
|
"enforce-header-comment": enforce_header_comment_default,
|
|
747
754
|
"no-tag-comments": no_tag_comments_default,
|
|
@@ -749,48 +756,78 @@ const rules = {
|
|
|
749
756
|
"prefer-inline-code-words-comments": prefer_inline_code_words_comments_default
|
|
750
757
|
};
|
|
751
758
|
|
|
759
|
+
//#endregion
|
|
760
|
+
//#region src/utils/config.ts
|
|
761
|
+
/**
|
|
762
|
+
* Get namespaced rules
|
|
763
|
+
*
|
|
764
|
+
* @param rules - All rules
|
|
765
|
+
* @param ruleNames - The rule names to include
|
|
766
|
+
* @param defaultSeverity - The default severity level
|
|
767
|
+
* @returns Namespaced rules
|
|
768
|
+
*/
|
|
769
|
+
function getNamespacedRulesRecord(rules$1, ruleNames, defaultSeverity = "warn") {
|
|
770
|
+
return Object.entries(rules$1).reduce((rulesRecord, [ruleName, rule$4]) => {
|
|
771
|
+
if (!ruleNames.includes(ruleName)) return rulesRecord;
|
|
772
|
+
if (rule$4.meta?.docs?.recommended) {
|
|
773
|
+
const ruleId = rule$4.meta?.docs?.ruleId || resolveConfigName(ruleName);
|
|
774
|
+
rulesRecord[ruleId] = rule$4.meta?.docs?.defaultSeverity || defaultSeverity;
|
|
775
|
+
}
|
|
776
|
+
return rulesRecord;
|
|
777
|
+
}, Object.create(null));
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Resolve config name
|
|
781
|
+
*
|
|
782
|
+
* @param name - The config name
|
|
783
|
+
* @returns The resolved config name
|
|
784
|
+
*/
|
|
785
|
+
function resolveConfigName(name) {
|
|
786
|
+
return `${NAME}/${name}`;
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* The rules to be enforced in the header comment.
|
|
790
|
+
*/
|
|
791
|
+
const enforceHeaderCommentRuleOnly = getNamespacedRulesRecord(rules, ["enforce-header-comment"]);
|
|
792
|
+
const baseRulesNames = Object.keys(rules).filter((name) => name !== "enforce-header-comment");
|
|
793
|
+
/**
|
|
794
|
+
* The base rules excluding the header comment enforcement rule.
|
|
795
|
+
*/
|
|
796
|
+
const baseRules = getNamespacedRulesRecord(rules, baseRulesNames);
|
|
797
|
+
|
|
752
798
|
//#endregion
|
|
753
799
|
//#region src/index.ts
|
|
754
800
|
const plugin = {
|
|
755
801
|
meta: {
|
|
756
|
-
name,
|
|
757
|
-
version
|
|
802
|
+
name: NAME,
|
|
803
|
+
version: VERSION
|
|
758
804
|
},
|
|
759
805
|
rules,
|
|
760
806
|
configs: {}
|
|
761
807
|
};
|
|
808
|
+
const baseIgnores = [GLOB_MARKDOWN, GLOB_MARKDOWN_CODES];
|
|
809
|
+
const enforceHeaderCommentIgnores = [
|
|
810
|
+
...baseIgnores,
|
|
811
|
+
GLOB_CONFIG_FILES,
|
|
812
|
+
TEST_GLOB_FILES,
|
|
813
|
+
TEST_DTS_GLOB_FILES
|
|
814
|
+
];
|
|
815
|
+
const baseConfig = {
|
|
816
|
+
files: [GLOB_FILES],
|
|
817
|
+
plugins: { [NAMESPACE]: plugin }
|
|
818
|
+
};
|
|
762
819
|
const recommendedConfig = [{
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
ignores:
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
rules:
|
|
772
|
-
if (rule$4.meta?.docs?.recommended) {
|
|
773
|
-
const ruleId = rule$4.meta?.docs?.ruleId || (namespace ? `${namespace}/${ruleName}` : ruleName);
|
|
774
|
-
acc[ruleId] = rule$4.meta?.docs?.defaultSeverity || "warn";
|
|
775
|
-
}
|
|
776
|
-
return acc;
|
|
777
|
-
}, Object.create(null))
|
|
778
|
-
}];
|
|
779
|
-
const commentConfig = [{
|
|
780
|
-
name: "@kazupon/eslint-plugin/comment",
|
|
781
|
-
files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
|
782
|
-
ignores: [
|
|
783
|
-
"**/*.md",
|
|
784
|
-
"**/*.md/**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}",
|
|
785
|
-
"**/*.config.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"
|
|
786
|
-
],
|
|
787
|
-
plugins: { [namespace]: plugin },
|
|
788
|
-
rules: Object.entries(rules).reduce((rules$1, [ruleName, rule$4]) => {
|
|
789
|
-
const ruleId = rule$4.meta?.docs?.ruleId || (namespace ? `${namespace}/${ruleName}` : ruleName);
|
|
790
|
-
rules$1[ruleId] = rule$4.meta?.docs?.defaultSeverity || "warn";
|
|
791
|
-
return rules$1;
|
|
792
|
-
}, Object.create(null))
|
|
820
|
+
...baseConfig,
|
|
821
|
+
name: resolveConfigName("recommended/base"),
|
|
822
|
+
ignores: baseIgnores,
|
|
823
|
+
rules: baseRules
|
|
824
|
+
}, {
|
|
825
|
+
...baseConfig,
|
|
826
|
+
name: resolveConfigName("recommended/enforce-header-comment"),
|
|
827
|
+
ignores: enforceHeaderCommentIgnores,
|
|
828
|
+
rules: enforceHeaderCommentRuleOnly
|
|
793
829
|
}];
|
|
830
|
+
const commentConfig = recommendedConfig;
|
|
794
831
|
/**
|
|
795
832
|
* Plugin Configurations.
|
|
796
833
|
*/
|
|
@@ -803,4 +840,4 @@ plugin.configs = configs;
|
|
|
803
840
|
var src_default = plugin;
|
|
804
841
|
|
|
805
842
|
//#endregion
|
|
806
|
-
export { configs, src_default as default, plugin };
|
|
843
|
+
export { baseIgnores, configs, src_default as default, defaultOptions, enforceHeaderCommentIgnores, plugin };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"overrides": [
|
|
3
|
+
{
|
|
4
|
+
"files": [
|
|
5
|
+
"**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"
|
|
6
|
+
],
|
|
7
|
+
"jsPlugins": [
|
|
8
|
+
"@kazupon/eslint-plugin"
|
|
9
|
+
],
|
|
10
|
+
"rules": {
|
|
11
|
+
"@kazupon/enforce-header-comment": "warn",
|
|
12
|
+
"@kazupon/no-tag-comments": [
|
|
13
|
+
"warn",
|
|
14
|
+
{
|
|
15
|
+
"tags": [
|
|
16
|
+
"FIXME",
|
|
17
|
+
"BUG"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"@kazupon/prefer-scope-on-tag-comment": [
|
|
22
|
+
"warn",
|
|
23
|
+
{
|
|
24
|
+
"tags": [
|
|
25
|
+
"TODO",
|
|
26
|
+
"FIXME",
|
|
27
|
+
"HACK",
|
|
28
|
+
"BUG",
|
|
29
|
+
"NOTE"
|
|
30
|
+
],
|
|
31
|
+
"directives": [
|
|
32
|
+
"eslint-disable",
|
|
33
|
+
"eslint-disable-next-line",
|
|
34
|
+
"eslint-disable-line",
|
|
35
|
+
"@ts-expect-error",
|
|
36
|
+
"@ts-ignore",
|
|
37
|
+
"@ts-nocheck"
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"@kazupon/prefer-inline-code-words-comments": "error"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"files": [
|
|
46
|
+
"**/*.md",
|
|
47
|
+
"**/*.md/**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}",
|
|
48
|
+
"**/*.config.{js,mjs,cjs,ts,mts,cts,jsx,tsx}",
|
|
49
|
+
"**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}",
|
|
50
|
+
"**/*.{test,spec}.d.{ts,tsx}"
|
|
51
|
+
],
|
|
52
|
+
"rules": {
|
|
53
|
+
"@kazupon/enforce-header-comment": "off"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
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.7.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"funding": "https://github.com/sponsors/kazupon",
|
|
7
7
|
"bugs": {
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
},
|
|
14
14
|
"keywords": [
|
|
15
15
|
"eslint",
|
|
16
|
-
"
|
|
17
|
-
"
|
|
16
|
+
"lint",
|
|
17
|
+
"plugin"
|
|
18
18
|
],
|
|
19
19
|
"publishConfig": {
|
|
20
20
|
"access": "public"
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
"type": "module",
|
|
26
26
|
"sideEffects": false,
|
|
27
27
|
"files": [
|
|
28
|
-
"lib"
|
|
28
|
+
"lib",
|
|
29
|
+
"oxlint"
|
|
29
30
|
],
|
|
30
31
|
"module": "lib/index.js",
|
|
31
32
|
"exports": {
|
|
@@ -47,67 +48,76 @@
|
|
|
47
48
|
}
|
|
48
49
|
},
|
|
49
50
|
"dependencies": {
|
|
50
|
-
"@es-joy/jsdoccomment": "^0.
|
|
51
|
-
"@eslint/core": "^0.
|
|
51
|
+
"@es-joy/jsdoccomment": "^0.78.0",
|
|
52
|
+
"@eslint/core": "^0.17.0"
|
|
52
53
|
},
|
|
53
54
|
"peerDependencies": {
|
|
54
55
|
"eslint": "^9.0.0"
|
|
55
56
|
},
|
|
56
57
|
"devDependencies": {
|
|
57
|
-
"@eslint/
|
|
58
|
-
"@eslint
|
|
59
|
-
"@kazupon/
|
|
60
|
-
"@
|
|
61
|
-
"@
|
|
62
|
-
"@
|
|
63
|
-
"@vitest/eslint-plugin": "^1.
|
|
64
|
-
"bumpp": "^10.
|
|
65
|
-
"eslint": "^9.
|
|
66
|
-
"eslint-
|
|
67
|
-
"eslint-
|
|
68
|
-
"eslint-plugin-
|
|
69
|
-
"eslint-plugin-jsdoc": "^52.0.2",
|
|
70
|
-
"eslint-plugin-jsonc": "^2.20.1",
|
|
71
|
-
"eslint-plugin-markdown-preferences": "^0.5.0",
|
|
58
|
+
"@eslint/markdown": "^7.5.1",
|
|
59
|
+
"@kazupon/eslint-config": "^0.42.0",
|
|
60
|
+
"@kazupon/prettier-config": "^0.2.0",
|
|
61
|
+
"@shikijs/vitepress-twoslash": "^3.20.0",
|
|
62
|
+
"@types/node": "^25.0.3",
|
|
63
|
+
"@typescript/native-preview": "7.0.0-dev.20251218.3",
|
|
64
|
+
"@vitest/eslint-plugin": "^1.6.4",
|
|
65
|
+
"bumpp": "^10.3.2",
|
|
66
|
+
"eslint": "^9.39.2",
|
|
67
|
+
"eslint-plugin-jsdoc": "^58.1.1",
|
|
68
|
+
"eslint-plugin-jsonc": "^2.21.0",
|
|
69
|
+
"eslint-plugin-markdown-preferences": "^0.10.0",
|
|
72
70
|
"eslint-plugin-module-interop": "^0.3.1",
|
|
73
|
-
"eslint-plugin-
|
|
74
|
-
"eslint-plugin-regexp": "^2.
|
|
75
|
-
"eslint-plugin-
|
|
76
|
-
"eslint-
|
|
77
|
-
"eslint-plugin-yml": "^1.18.0",
|
|
78
|
-
"eslint-vitest-rule-tester": "^2.2.1",
|
|
71
|
+
"eslint-plugin-oxlint": "^1.35.0",
|
|
72
|
+
"eslint-plugin-regexp": "^2.10.0",
|
|
73
|
+
"eslint-plugin-yml": "^1.19.1",
|
|
74
|
+
"eslint-vitest-rule-tester": "^2.3.0",
|
|
79
75
|
"gh-changelogen": "^0.2.8",
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
76
|
+
"json-schema-to-typescript": "^15.0.4",
|
|
77
|
+
"knip": "^5.77.1",
|
|
78
|
+
"lint-staged": "^16.2.7",
|
|
79
|
+
"oxfmt": "^0.20.0",
|
|
80
|
+
"oxlint": "^1.35.0",
|
|
81
|
+
"oxlint-tsgolint": "^0.10.0",
|
|
82
|
+
"pkg-pr-new": "^0.0.62",
|
|
83
|
+
"publint": "^0.3.16",
|
|
84
|
+
"tsdown": "^0.15.12",
|
|
85
|
+
"tsx": "^4.21.0",
|
|
86
|
+
"twoslash-eslint": "^0.3.6",
|
|
87
|
+
"typescript": "^5.9.3",
|
|
88
|
+
"typescript-eslint": "^8.50.1",
|
|
90
89
|
"vite-plugin-eslint4b": "^0.6.0",
|
|
91
|
-
"vitepress": "^1.6.
|
|
92
|
-
"vitepress-plugin-group-icons": "^1.6.
|
|
93
|
-
"vitest": "^
|
|
90
|
+
"vitepress": "^1.6.4",
|
|
91
|
+
"vitepress-plugin-group-icons": "^1.6.5",
|
|
92
|
+
"vitest": "^4.0.16"
|
|
94
93
|
},
|
|
95
94
|
"prettier": "@kazupon/prettier-config",
|
|
96
95
|
"lint-staged": {
|
|
97
96
|
"*.ts?(x)": [
|
|
98
|
-
"
|
|
97
|
+
"oxfmt --config ./node_modules/@kazupon/prettier-config/index.json",
|
|
98
|
+
"oxlint --config .oxlintrc.json --type-aware --fix",
|
|
99
99
|
"eslint --fix"
|
|
100
100
|
],
|
|
101
101
|
"*.{js,mjs,cjs}": [
|
|
102
|
-
"
|
|
102
|
+
"oxfmt --config ./node_modules/@kazupon/prettier-config/index.json",
|
|
103
|
+
"oxlint --config .oxlintrc.json --type-aware --fix",
|
|
103
104
|
"eslint --fix"
|
|
104
105
|
],
|
|
105
|
-
"*.{
|
|
106
|
-
"
|
|
106
|
+
"*.{jsonc,json5,md,yml,yaml}": [
|
|
107
|
+
"oxfmt --config ./node_modules/@kazupon/prettier-config/index.json",
|
|
108
|
+
"eslint --fix"
|
|
109
|
+
],
|
|
110
|
+
"!(package|jsr).json": [
|
|
111
|
+
"oxfmt --config ./node_modules/@kazupon/prettier-config/index.json",
|
|
112
|
+
"eslint --fix"
|
|
113
|
+
],
|
|
114
|
+
"!(pnpm-lock).{yml,yaml}": [
|
|
115
|
+
"oxfmt --config ./node_modules/@kazupon/prettier-config/index.json",
|
|
116
|
+
"eslint --fix"
|
|
107
117
|
]
|
|
108
118
|
},
|
|
109
119
|
"scripts": {
|
|
110
|
-
"build": "tsdown",
|
|
120
|
+
"build": "tsdown && pnpm run gen:oxlint:config",
|
|
111
121
|
"changelog": "gh-changelogen --repo=kazupon/eslint-plugin",
|
|
112
122
|
"clean": "git clean -df",
|
|
113
123
|
"dev": "pnpx @eslint/config-inspector --config eslint.config.ts",
|
|
@@ -117,17 +127,20 @@
|
|
|
117
127
|
"docs:preview": "vitepress preview docs",
|
|
118
128
|
"docs:readme": "tsx scripts/update-readme.ts",
|
|
119
129
|
"docs:rules": "tsx scripts/update-docs.ts",
|
|
120
|
-
"fix": "pnpm run --
|
|
130
|
+
"fix": "pnpm run --color \"/^fix:/\"",
|
|
121
131
|
"fix:eslint": "eslint . --fix",
|
|
122
132
|
"fix:knip": "knip --fix --no-exit-code",
|
|
123
|
-
"fix:
|
|
124
|
-
"
|
|
125
|
-
"
|
|
133
|
+
"fix:oxfmt": "oxfmt --config ./node_modules/@kazupon/prettier-config/index.json",
|
|
134
|
+
"fix:oxlint": "oxlint --type-aware --fix",
|
|
135
|
+
"gen:oxlint:config": "tsx ./scripts/generate-oxlint-config.ts",
|
|
136
|
+
"gen:oxlint:dts": "cat ./node_modules/oxlint/configuration_schema.json | json2ts > scripts/oxlint-config.d.ts",
|
|
137
|
+
"lint": "pnpm run --color \"/^lint:/\"",
|
|
138
|
+
"lint:eslint": "eslint . --cache",
|
|
126
139
|
"lint:knip": "knip",
|
|
127
|
-
"lint:
|
|
140
|
+
"lint:oxfmt": "oxfmt . --check --config ./node_modules/@kazupon/prettier-config/index.json",
|
|
141
|
+
"lint:oxlint": "oxlint --type-aware",
|
|
128
142
|
"release": "bumpp --commit \"release: v%s\" --all --push --tag",
|
|
129
143
|
"test": "vitest run",
|
|
130
|
-
"typecheck": "
|
|
131
|
-
"typecheck:tsc": "tsc --noEmit"
|
|
144
|
+
"typecheck": "tsgo --noEmit --diagnostics"
|
|
132
145
|
}
|
|
133
146
|
}
|