@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 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.
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
- const match = text.match(tagRegex);
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
- const scope = afterTag.slice(1, closingParenIndex).trim();
31
- return {
32
- tag,
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
- const description = afterDirective.trim();
178
- const directiveIndex = text.indexOf(directive);
179
- const descriptionStart = directiveIndex + directive.length + spaceMatch[0].length;
180
- return {
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 name = "@kazupon/eslint-plugin";
190
+ const NAME = "@kazupon/eslint-plugin";
201
191
  /**
202
192
  * The plugin version.
203
193
  */
204
- const version = "0.6.1";
194
+ const VERSION = "0.7.0";
205
195
  /**
206
196
  * The namespace for rules
207
197
  */
208
- 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.{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$1 = "") {
214
- return function createNamedRule({ meta, name: name$1,...rule$4 }) {
215
- 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;
216
243
  return {
217
244
  meta: {
218
245
  ...meta,
219
246
  docs: {
220
247
  ...meta?.docs,
221
- url: urlCreator(name$1),
222
- ruleName: name$1,
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
- }, namespace);
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: "error"
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
- const distance = Math.abs(lastComment.range[1] - firstNode.range[0]);
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$1 = ["FIXME", "BUG"];
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 options = parseArrayOptions(ctx.options[0], { tags: DEFAULT_TAGS$1 });
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
- const trimmedLine = line.trim();
456
- if (!trimmedLine) continue;
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 startOffset = comment.range[0] + 2 + index;
572
- const endOffset = startOffset + word.length;
573
- return fixer.replaceTextRange([startOffset, endOffset], `\`${word}\``);
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 = parseArrayOptions(ctx.options[0], {
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 linesBeforeDesc = value.slice(0, descStartInComment).split("\n").length - 1;
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 actualLine = lines[actualLineIndex];
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
- const trimmedLine = line.trim();
724
- if (!trimmedLine) continue;
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
- name: "@kazupon/eslint-plugin/recommended",
764
- files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
765
- ignores: [
766
- "**/*.md",
767
- "**/*.md/**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}",
768
- "**/*.config.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"
769
- ],
770
- plugins: { [namespace]: plugin },
771
- rules: Object.entries(rules).reduce((acc, [ruleName, rule$4]) => {
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.6.1",
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
- "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.52.0",
51
- "@eslint/core": "^0.15.1"
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.3.1",
58
- "@eslint/markdown": "^7.1.0",
59
- "@kazupon/eslint-config": "^0.34.0",
60
- "@kazupon/prettier-config": "^0.1.1",
61
- "@shikijs/vitepress-twoslash": "^3.9.1",
62
- "@types/node": "^22.17.0",
63
- "@vitest/eslint-plugin": "^1.3.4",
64
- "bumpp": "^10.2.2",
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
- "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-promise": "^7.2.1",
74
- "eslint-plugin-regexp": "^2.9.1",
75
- "eslint-plugin-unicorn": "^60.0.0",
76
- "eslint-plugin-unused-imports": "^4.1.4",
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
- "knip": "^5.62.0",
81
- "lint-staged": "^16.1.2",
82
- "pkg-pr-new": "^0.0.54",
83
- "prettier": "^3.6.2",
84
- "publint": "^0.3.12",
85
- "tsdown": "^0.13.2",
86
- "tsx": "^4.20.3",
87
- "twoslash-eslint": "^0.3.3",
88
- "typescript": "^5.9.2",
89
- "typescript-eslint": "^8.38.0",
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.3",
92
- "vitepress-plugin-group-icons": "^1.6.1",
93
- "vitest": "^3.2.4"
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
- "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
  }