@kazupon/eslint-plugin 0.6.2 → 0.7.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.
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
- - **Configuration**: flat config style `eslint.config.[js|ts]`, not support legacy config style `.eslintrc`
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.
@@ -59,7 +70,7 @@ The rules with the following star ⭐ are included in the configs.
59
70
 
60
71
  <!--RULES_TABLE_START-->
61
72
 
62
- ### `@kazupon/eslint-plugin` Rules
73
+ ### @kazupon/eslint-plugin Rules
63
74
 
64
75
  | Rule ID | Description | Category | Fixable | RECOMMENDED |
65
76
  | :--------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------ | :------- | :-----: | :---------: |
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
  /**
@@ -24,4 +59,4 @@ declare const configs: {
24
59
  comment: typeof commentConfig;
25
60
  };
26
61
  //#endregion
27
- export { configs, plugin as default, plugin };
62
+ export { baseIgnores, configs, plugin as default, plugin, defaultOptions, enforceHeaderCommentIgnores };
package/lib/index.js CHANGED
@@ -25,13 +25,10 @@ function detectTag(text, tags) {
25
25
  const afterTag = text.slice(tag.length);
26
26
  if (afterTag.startsWith("(")) {
27
27
  const closingParenIndex = afterTag.indexOf(")");
28
- if (closingParenIndex > 0) {
29
- const scope = afterTag.slice(1, closingParenIndex).trim();
30
- return {
31
- tag,
32
- hasScope: scope.length > 0
33
- };
34
- }
28
+ if (closingParenIndex > 0) return {
29
+ tag,
30
+ hasScope: afterTag.slice(1, closingParenIndex).trim().length > 0
31
+ };
35
32
  return {
36
33
  tag,
37
34
  hasScope: false
@@ -163,24 +160,19 @@ function parseDirectiveComment(text, directives) {
163
160
  const description = afterDirective.slice(separatorIndex + 2).trim();
164
161
  const separatorPos = text.indexOf("--");
165
162
  const afterSeparator = text.slice(separatorPos + 2);
166
- const descriptionStart = separatorPos + 2 + (afterSeparator.length - afterSeparator.trimStart().length);
167
163
  return {
168
164
  directive,
169
165
  description,
170
- descriptionStart
166
+ descriptionStart: separatorPos + 2 + (afterSeparator.length - afterSeparator.trimStart().length)
171
167
  };
172
168
  }
173
169
  if (afterDirective.trim()) {
174
170
  const spaceMatch = afterDirective.match(/^\s+/);
175
- if (spaceMatch) {
176
- const description = afterDirective.trim();
177
- const descriptionStart = text.indexOf(directive) + directive.length + spaceMatch[0].length;
178
- return {
179
- directive,
180
- description,
181
- descriptionStart
182
- };
183
- }
171
+ if (spaceMatch) return {
172
+ directive,
173
+ description: afterDirective.trim(),
174
+ descriptionStart: text.indexOf(directive) + directive.length + spaceMatch[0].length
175
+ };
184
176
  }
185
177
  }
186
178
  return null;
@@ -195,29 +187,66 @@ function parseDirectiveComment(text, directives) {
195
187
  /**
196
188
  * The plugin name.
197
189
  */
198
- const name = "@kazupon/eslint-plugin";
190
+ const NAME = "@kazupon/eslint-plugin";
199
191
  /**
200
192
  * The plugin version.
201
193
  */
202
- const version = "0.6.2";
194
+ const VERSION = "0.7.1";
203
195
  /**
204
196
  * The namespace for rules
205
197
  */
206
- const namespace = "@kazupon";
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.{${EXTENSIONS}}`;
207
236
 
208
237
  //#endregion
209
238
  //#region src/utils/rule.ts
210
239
  const BLOB_URL = "https://eslint-plugin.kazupon.dev/rules";
211
- function RuleCreator(urlCreator, namespace$1 = "") {
212
- return function createNamedRule({ meta, name: name$1,...rule$4 }) {
213
- const ruleId = namespace$1 ? `${namespace$1}/${name$1}` : name$1;
240
+ function RuleCreator(urlCreator, namespace = "") {
241
+ return function createNamedRule({ meta, name,...rule$4 }) {
242
+ const ruleId = namespace ? `${namespace}/${name}` : name;
214
243
  return {
215
244
  meta: {
216
245
  ...meta,
217
246
  docs: {
218
247
  ...meta?.docs,
219
- url: urlCreator(name$1),
220
- ruleName: name$1,
248
+ url: urlCreator(name),
249
+ ruleName: name,
221
250
  ruleId
222
251
  }
223
252
  },
@@ -227,7 +256,7 @@ function RuleCreator(urlCreator, namespace$1 = "") {
227
256
  }
228
257
  const createRule = RuleCreator((ruleName) => {
229
258
  return `${BLOB_URL}/${ruleName}`;
230
- }, namespace);
259
+ }, NAMESPACE);
231
260
 
232
261
  //#endregion
233
262
  //#region src/rules/enforce-header-comment.ts
@@ -249,7 +278,7 @@ const rule$3 = createRule({
249
278
  description: "Enforce heading the comment in source code file",
250
279
  category: "Comment",
251
280
  recommended: true,
252
- defaultSeverity: "error"
281
+ defaultSeverity: "warn"
253
282
  },
254
283
  messages: {
255
284
  headerCommentEnforce: "Header comment is enforced",
@@ -366,30 +395,9 @@ const rule$3 = createRule({
366
395
  });
367
396
  var enforce_header_comment_default = rule$3;
368
397
 
369
- //#endregion
370
- //#region src/utils/options.ts
371
- /**
372
- * @author kazuya kawaguchi (a.k.a. kazupon)
373
- * @license MIT
374
- */
375
- /**
376
- * Parse array options with defaults
377
- *
378
- * @typeParam T - The type of the options object
379
- *
380
- * @param options - The options object that may contain array fields
381
- * @param arrayFields - Object mapping field names to their default arrays
382
- * @returns The parsed options with default arrays applied
383
- */
384
- function parseArrayOptions(options, arrayFields) {
385
- const result = options ? { ...options } : {};
386
- for (const [field, defaultArray] of Object.entries(arrayFields)) if (!result[field] || !Array.isArray(result[field])) result[field] = defaultArray;
387
- return result;
388
- }
389
-
390
398
  //#endregion
391
399
  //#region src/rules/no-tag-comments.ts
392
- const DEFAULT_TAGS$1 = ["FIXME", "BUG"];
400
+ const DEFAULT_TAGS = ["FIXME", "BUG"];
393
401
  const rule$2 = createRule({
394
402
  name: "no-tag-comments",
395
403
  meta: {
@@ -401,6 +409,7 @@ const rule$2 = createRule({
401
409
  defaultSeverity: "warn"
402
410
  },
403
411
  messages: { tagComment: "Exist '{{tag}}' tag comment" },
412
+ defaultOptions: [{ tags: DEFAULT_TAGS }],
404
413
  schema: [{
405
414
  type: "object",
406
415
  properties: { tags: {
@@ -413,7 +422,7 @@ const rule$2 = createRule({
413
422
  }]
414
423
  },
415
424
  create(ctx) {
416
- const tags = parseArrayOptions(ctx.options[0], { tags: DEFAULT_TAGS$1 }).tags;
425
+ const tags = ctx.options[0].tags;
417
426
  const sourceCode = ctx.sourceCode;
418
427
  /**
419
428
  * Report a tag comment violation
@@ -449,8 +458,7 @@ const rule$2 = createRule({
449
458
  const lines = value.split("\n");
450
459
  for (const [i, line] of lines.entries()) {
451
460
  if (!line.trim()) continue;
452
- const contentToCheck = stripJSDocPrefix(line);
453
- const tagInfo = detectTag(contentToCheck, tags);
461
+ const tagInfo = detectTag(stripJSDocPrefix(line), tags);
454
462
  if (tagInfo) {
455
463
  const location = calculateTagLocation(comment, line, i, tagInfo.tag);
456
464
  if (location) {
@@ -580,7 +588,7 @@ var prefer_inline_code_words_comments_default = rule$1;
580
588
 
581
589
  //#endregion
582
590
  //#region src/rules/prefer-scope-on-tag-comment.ts
583
- const DEFAULT_TAGS = [
591
+ const DEFAULT_TAGS$1 = [
584
592
  "TODO",
585
593
  "FIXME",
586
594
  "HACK",
@@ -606,6 +614,10 @@ const rule = createRule({
606
614
  defaultSeverity: "warn"
607
615
  },
608
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
+ }],
609
621
  schema: [{
610
622
  type: "object",
611
623
  properties: {
@@ -626,10 +638,7 @@ const rule = createRule({
626
638
  }]
627
639
  },
628
640
  create(ctx) {
629
- const options = parseArrayOptions(ctx.options[0], {
630
- tags: DEFAULT_TAGS,
631
- directives: DEFAULT_DIRECTIVES
632
- });
641
+ const options = ctx.options[0];
633
642
  const tags = options.tags;
634
643
  const directives = options.directives;
635
644
  const sourceCode = ctx.sourceCode;
@@ -714,8 +723,7 @@ const rule = createRule({
714
723
  }
715
724
  for (const [i, line] of lines.entries()) {
716
725
  if (!line.trim()) continue;
717
- const contentToCheck = stripJSDocPrefix(line);
718
- const tagInfo = detectTag(contentToCheck, tags);
726
+ const tagInfo = detectTag(stripJSDocPrefix(line), tags);
719
727
  if (tagInfo && !tagInfo.hasScope) {
720
728
  const location = calculateTagLocation(comment, line, i, tagInfo.tag);
721
729
  if (location) {
@@ -734,6 +742,13 @@ var prefer_scope_on_tag_comment_default = rule;
734
742
 
735
743
  //#endregion
736
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
+ };
737
752
  const rules = {
738
753
  "enforce-header-comment": enforce_header_comment_default,
739
754
  "no-tag-comments": no_tag_comments_default,
@@ -741,48 +756,78 @@ const rules = {
741
756
  "prefer-inline-code-words-comments": prefer_inline_code_words_comments_default
742
757
  };
743
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
+
744
798
  //#endregion
745
799
  //#region src/index.ts
746
800
  const plugin = {
747
801
  meta: {
748
- name,
749
- version
802
+ name: NAME,
803
+ version: VERSION
750
804
  },
751
805
  rules,
752
806
  configs: {}
753
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
+ };
754
819
  const recommendedConfig = [{
755
- name: "@kazupon/eslint-plugin/recommended",
756
- files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
757
- ignores: [
758
- "**/*.md",
759
- "**/*.md/**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}",
760
- "**/*.config.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"
761
- ],
762
- plugins: { [namespace]: plugin },
763
- rules: Object.entries(rules).reduce((acc, [ruleName, rule$4]) => {
764
- if (rule$4.meta?.docs?.recommended) {
765
- const ruleId = rule$4.meta?.docs?.ruleId || (namespace ? `${namespace}/${ruleName}` : ruleName);
766
- acc[ruleId] = rule$4.meta?.docs?.defaultSeverity || "warn";
767
- }
768
- return acc;
769
- }, Object.create(null))
770
- }];
771
- const commentConfig = [{
772
- name: "@kazupon/eslint-plugin/comment",
773
- files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
774
- ignores: [
775
- "**/*.md",
776
- "**/*.md/**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}",
777
- "**/*.config.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"
778
- ],
779
- plugins: { [namespace]: plugin },
780
- rules: Object.entries(rules).reduce((rules$1, [ruleName, rule$4]) => {
781
- const ruleId = rule$4.meta?.docs?.ruleId || (namespace ? `${namespace}/${ruleName}` : ruleName);
782
- rules$1[ruleId] = rule$4.meta?.docs?.defaultSeverity || "warn";
783
- return rules$1;
784
- }, 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
785
829
  }];
830
+ const commentConfig = recommendedConfig;
786
831
  /**
787
832
  * Plugin Configurations.
788
833
  */
@@ -795,4 +840,4 @@ plugin.configs = configs;
795
840
  var src_default = plugin;
796
841
 
797
842
  //#endregion
798
- 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.{js,mjs,cjs,ts,mts,cts,jsx,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.6.2",
4
+ "version": "0.7.1",
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
- "plugin",
17
- "lint"
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.60.0",
51
- "@eslint/core": "^0.15.2"
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/compat": "^1.4.0",
58
- "@eslint/markdown": "^7.3.0",
59
- "@kazupon/eslint-config": "^0.35.0",
60
- "@kazupon/prettier-config": "^0.1.1",
61
- "@shikijs/vitepress-twoslash": "^3.13.0",
62
- "@types/node": "^22.18.6",
63
- "@vitest/eslint-plugin": "^1.3.12",
64
- "bumpp": "^10.2.3",
65
- "eslint": "^9.36.0",
66
- "eslint-config-prettier": "^10.1.8",
67
- "eslint-import-resolver-typescript": "^4.4.4",
68
- "eslint-plugin-import": "^2.32.0",
69
- "eslint-plugin-jsdoc": "^52.0.4",
70
- "eslint-plugin-jsonc": "^2.20.1",
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",
71
69
  "eslint-plugin-markdown-preferences": "^0.10.0",
72
70
  "eslint-plugin-module-interop": "^0.3.1",
73
- "eslint-plugin-promise": "^7.2.1",
71
+ "eslint-plugin-oxlint": "^1.35.0",
74
72
  "eslint-plugin-regexp": "^2.10.0",
75
- "eslint-plugin-unicorn": "^60.0.0",
76
- "eslint-plugin-unused-imports": "^4.2.0",
77
- "eslint-plugin-yml": "^1.18.0",
78
- "eslint-vitest-rule-tester": "^2.2.2",
73
+ "eslint-plugin-yml": "^1.19.1",
74
+ "eslint-vitest-rule-tester": "^2.3.0",
79
75
  "gh-changelogen": "^0.2.8",
80
- "knip": "^5.64.0",
81
- "lint-staged": "^16.2.0",
82
- "pkg-pr-new": "^0.0.60",
83
- "prettier": "^3.6.2",
84
- "publint": "^0.3.13",
85
- "tsdown": "^0.15.4",
86
- "tsx": "^4.20.5",
87
- "twoslash-eslint": "^0.3.4",
88
- "typescript": "^5.9.2",
89
- "typescript-eslint": "^8.44.1",
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
90
  "vitepress": "^1.6.4",
92
- "vitepress-plugin-group-icons": "^1.6.3",
93
- "vitest": "^3.2.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
- "prettier --parser=typescript --write",
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
- "prettier --write",
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
- "*.{json,jsonc,json5,md,yml,yaml}": [
106
- "prettier --write"
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 --stream --color \"/^fix:/\"",
130
+ "fix": "pnpm run --color \"/^fix:/\"",
121
131
  "fix:eslint": "eslint . --fix",
122
132
  "fix:knip": "knip --fix --no-exit-code",
123
- "fix:prettier": "prettier . --write --experimental-cli",
124
- "lint": "pnpm run --stream --color \"/^lint:/\"",
125
- "lint:eslint": "eslint .",
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:prettier": "prettier . --check --experimental-cli",
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": "pnpm run --stream --color \"/^typecheck:/\"",
131
- "typecheck:tsc": "tsc --noEmit"
144
+ "typecheck": "tsgo --noEmit --diagnostics"
132
145
  }
133
146
  }