Repository: ota-meshi/eslint-plugin-astro
Pull request #439 (2024-10-26 16:12:08)

chore: move 'utils/rules.ts' to 'rules/index.ts'
- The `lib/load-rules.ts` file is confusing because it behaves like an index file for the `src/rules` folder, so adding a comment helps clarify its purpose.
- Rename `tools/update-rules.ts` to `tools/update-rules-index.ts`.
- Move `utils/rules.ts` to `rules/index.ts`

**Motivation:**

- The first time I saw utils/rules.ts, it was a bit confusing because its behavior is more like an index file for src/rules than a utility.
- `lib/load-rules.ts` same as above.
- Making it an index file and placing it in src/rules makes its purpose clearer.

**Potential enhancement (later):**

- Write the original design to the doc under `Contributing guidelines` section

**Need help to review:**

- I don't understand why there is a `js` import here, the file is a `ts` file, so I don't know if this change breaks it or not
- I tried `npm run test` and it went well


<img width="1148" alt="image" src="https://github.com/user-attachments/assets/75c84209-dfe3-480f-b049-7fcaa51981f5">


changeset-bot[bot]: ###  ⚠️  No Changeset found

Latest commit: 388e65a64b4ef90101d85d21dcc3b3890dd658bd

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/Foxeye-Rinx/eslint-plugin-astro/new/unify-rules?filename=.changeset/polite-drinks-breathe.md&value=---%0A%22eslint-plugin-astro%22%3A%20patch%0A---%0A%0Achore%3A%20move%20'utils%2Frules.ts'%20to%20'rules%2Findex.ts'%0A)



Patch:
diff --git a/docs-build/src/components/eslint/scripts/linter.mts b/docs-build/src/components/eslint/scripts/linter.mts
index c28d2b6..88bed92 100644
--- a/docs-build/src/components/eslint/scripts/linter.mts
+++ b/docs-build/src/components/eslint/scripts/linter.mts
@@ -1,4 +1,4 @@
-import { rules as pluginRules } from "../../../../../src/utils/rules.js"
+import { rules as pluginRules } from "../../../../../src/rules"
 import type { Linter, Rule } from "eslint"
 import { builtinRules } from "eslint/use-at-your-own-risk"
 import * as astroEslintParser from "astro-eslint-parser"
diff --git a/docs-build/src/config.ts b/docs-build/src/config.ts
index f298763..3ba8136 100644
--- a/docs-build/src/config.ts
+++ b/docs-build/src/config.ts
@@ -1,4 +1,4 @@
-import { rules } from "../../src/utils/rules"
+import { rules } from "../../src/rules"
 
 const categories = [
   "Possible Errors",
diff --git a/src/configs/all.ts b/src/configs/all.ts
index 0d1c76b..100cd33 100644
--- a/src/configs/all.ts
+++ b/src/configs/all.ts
@@ -1,5 +1,5 @@
 import recommended from "./recommended"
-import { rules } from "../utils/rules"
+import { rules } from "../rules"
 
 const all: Record<string, string> = {}
 for (const rule of rules.filter(
diff --git a/src/configs/flat/all.ts b/src/configs/flat/all.ts
index 2d02a96..ae21f96 100644
--- a/src/configs/flat/all.ts
+++ b/src/configs/flat/all.ts
@@ -1,5 +1,5 @@
 import recommended from "./recommended"
-import { rules } from "../../utils/rules"
+import { rules } from "../../rules"
 
 const all: Record<string, string> = {}
 for (const rule of rules.filter(
diff --git a/src/plugin.ts b/src/plugin.ts
index bad1284..da54572 100644
--- a/src/plugin.ts
+++ b/src/plugin.ts
@@ -1,4 +1,4 @@
-import { rules as ruleList } from "./utils/rules"
+import { rules as ruleList } from "./rules"
 import * as processorsDefines from "./processor"
 import type { Rule } from "eslint"
 import { name, version } from "./meta"
diff --git a/src/rules/index.ts b/src/rules/index.ts
new file mode 100644
index 0000000..0af9add
--- /dev/null
+++ b/src/rules/index.ts
@@ -0,0 +1,42 @@
+// IMPORTANT!
+// This file has been automatically generated by "update-rules-index.ts",
+// in order to update its content, update "update-rules-index.ts" and execute "npm run update"
+import missingClientOnlyDirectiveValue from "./missing-client-only-directive-value"
+import noConflictSetDirectives from "./no-conflict-set-directives"
+import noDeprecatedAstroCanonicalurl from "./no-deprecated-astro-canonicalurl"
+import noDeprecatedAstroFetchcontent from "./no-deprecated-astro-fetchcontent"
+import noDeprecatedAstroResolve from "./no-deprecated-astro-resolve"
+import noDeprecatedGetentrybyslug from "./no-deprecated-getentrybyslug"
+import noExportsFromComponents from "./no-exports-from-components"
+import noSetHtmlDirective from "./no-set-html-directive"
+import noSetTextDirective from "./no-set-text-directive"
+import noUnusedCssSelector from "./no-unused-css-selector"
+import noUnusedDefineVarsInStyle from "./no-unused-define-vars-in-style"
+import preferClassListDirective from "./prefer-class-list-directive"
+import preferObjectClassList from "./prefer-object-class-list"
+import preferSplitClassList from "./prefer-split-class-list"
+import semi from "./semi"
+import sortAttributes from "./sort-attributes"
+import validCompile from "./valid-compile"
+import { buildA11yRules } from "../a11y"
+
+export const originalRules = [
+  missingClientOnlyDirectiveValue,
+  noConflictSetDirectives,
+  noDeprecatedAstroCanonicalurl,
+  noDeprecatedAstroFetchcontent,
+  noDeprecatedAstroResolve,
+  noDeprecatedGetentrybyslug,
+  noExportsFromComponents,
+  noSetHtmlDirective,
+  noSetTextDirective,
+  noUnusedCssSelector,
+  noUnusedDefineVarsInStyle,
+  preferClassListDirective,
+  preferObjectClassList,
+  preferSplitClassList,
+  semi,
+  sortAttributes,
+  validCompile,
+]
+export const rules = [...originalRules, ...buildA11yRules()]
diff --git a/src/utils/rules.ts b/src/utils/rules.ts
deleted file mode 100644
index f780fdd..0000000
--- a/src/utils/rules.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-// IMPORTANT!
-// This file has been automatically generated,
-// in order to update its content execute "npm run update"
-import type { RuleModule } from "../types"
-import missingClientOnlyDirectiveValue from "../rules/missing-client-only-directive-value"
-import noConflictSetDirectives from "../rules/no-conflict-set-directives"
-import noDeprecatedAstroCanonicalurl from "../rules/no-deprecated-astro-canonicalurl"
-import noDeprecatedAstroFetchcontent from "../rules/no-deprecated-astro-fetchcontent"
-import noDeprecatedAstroResolve from "../rules/no-deprecated-astro-resolve"
-import noDeprecatedGetentrybyslug from "../rules/no-deprecated-getentrybyslug"
-import noExportsFromComponents from "../rules/no-exports-from-components"
-import noSetHtmlDirective from "../rules/no-set-html-directive"
-import noSetTextDirective from "../rules/no-set-text-directive"
-import noUnusedCssSelector from "../rules/no-unused-css-selector"
-import noUnusedDefineVarsInStyle from "../rules/no-unused-define-vars-in-style"
-import preferClassListDirective from "../rules/prefer-class-list-directive"
-import preferObjectClassList from "../rules/prefer-object-class-list"
-import preferSplitClassList from "../rules/prefer-split-class-list"
-import semi from "../rules/semi"
-import sortAttributes from "../rules/sort-attributes"
-import validCompile from "../rules/valid-compile"
-import { buildA11yRules } from "../a11y"
-
-export const rules = [
-  missingClientOnlyDirectiveValue,
-  noConflictSetDirectives,
-  noDeprecatedAstroCanonicalurl,
-  noDeprecatedAstroFetchcontent,
-  noDeprecatedAstroResolve,
-  noDeprecatedGetentrybyslug,
-  noExportsFromComponents,
-  noSetHtmlDirective,
-  noSetTextDirective,
-  noUnusedCssSelector,
-  noUnusedDefineVarsInStyle,
-  preferClassListDirective,
-  preferObjectClassList,
-  preferSplitClassList,
-  semi,
-  sortAttributes,
-  validCompile,
-  ...buildA11yRules(),
-] as RuleModule[]
diff --git a/tools/lib/load-rules.ts b/tools/lib/load-rules.ts
index 590e21e..4b793a8 100644
--- a/tools/lib/load-rules.ts
+++ b/tools/lib/load-rules.ts
@@ -14,8 +14,13 @@ function readRules(): RuleModule[] {
   const rulesPath = path.resolve(__dirname, "../../src/rules")
   return fs
     .readdirSync(rulesPath)
-    .filter((n) => n.endsWith(".ts"))
+    .filter((n) => n.endsWith(".ts") && n !== "index.ts")
     .map((fileName) => require(path.join(rulesPath, fileName)).default)
 }
 
+/**
+ * This array is designed primarily for generator scripts in the "tools/" folder.
+ * It does not include extended rules (such as `a11y` rules).
+ * For a complete set of rules, consider using the generated file `rules/index.ts` instead.
+ */
 export const rules = readRules()
diff --git a/tools/render-rules-table.ts b/tools/render-rules-table.ts
index 8e45b36..75d9370 100644
--- a/tools/render-rules-table.ts
+++ b/tools/render-rules-table.ts
@@ -1,7 +1,7 @@
 // eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair -- ignore
 /* eslint-disable func-style -- Arrow functions are better when returning string */
 import type { RuleCategory, RuleModule } from "../src/types"
-import { rules } from "../src/utils/rules"
+import { rules } from "../src/rules"
 
 const categories: RuleCategory[] = [
   "Possible Errors",
diff --git a/tools/update-docs.ts b/tools/update-docs.ts
index fa11e06..d80772a 100644
--- a/tools/update-docs.ts
+++ b/tools/update-docs.ts
@@ -1,6 +1,6 @@
 import path from "path"
 import fs from "fs"
-import { rules } from "../src/utils/rules"
+import { rules } from "../src/rules"
 import type { RuleModule } from "../src/types"
 import { getNewVersion } from "./lib/changesets-util"
 import { formatAndSave } from "./lib/utils"
diff --git a/tools/update-rules-index.ts b/tools/update-rules-index.ts
new file mode 100644
index 0000000..4983bbd
--- /dev/null
+++ b/tools/update-rules-index.ts
@@ -0,0 +1,38 @@
+import path from "path"
+import { rules } from "./lib/load-rules"
+import { formatAndSave } from "./lib/utils"
+
+/**
+ * Convert text to camelCase
+ */
+function camelCase(str: string) {
+  return str.replace(/[-_](\w)/gu, (_, c) => (c ? c.toUpperCase() : ""))
+}
+
+/**
+ * Map rule name to import statement
+ */
+function mapRuleNameToImport(name: string) {
+  return `import ${camelCase(name)} from "./${name}"`
+}
+
+const currentFileName = path.basename(__filename)
+const ruleNames = rules.map((rule) => rule.meta.docs.ruleName)
+const content = `/*
+ * IMPORTANT!
+ * This file has been automatically generated by "${currentFileName}",
+ * in order to update its content, update "${currentFileName}" and execute "npm run update"
+ */
+${ruleNames.map(mapRuleNameToImport).join("\n")}
+import { buildA11yRules } from "../a11y"
+
+export const originalRules = [
+  ${ruleNames.map(camelCase).join(",")},
+]
+export const rules = [...originalRules, ...buildA11yRules()]
+`
+
+const filePath = path.resolve(__dirname, "../src/rules/index.ts")
+
+// Update file.
+void formatAndSave(filePath, content)
diff --git a/tools/update-rules.ts b/tools/update-rules.ts
deleted file mode 100644
index 22c3aea..0000000
--- a/tools/update-rules.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import path from "path"
-import { rules } from "./lib/load-rules"
-import { formatAndSave } from "./lib/utils"
-
-/**
- * Convert text to camelCase
- */
-function camelCase(str: string) {
-  return str.replace(/[-_](\w)/gu, (_, c) => (c ? c.toUpperCase() : ""))
-}
-
-const content = `/*
- * IMPORTANT!
- * This file has been automatically generated,
- * in order to update its content execute "npm run update"
- */
-import type { RuleModule } from "../types"
-${rules
-  .map(
-    (rule) =>
-      `import ${camelCase(rule.meta.docs.ruleName)} from "../rules/${
-        rule.meta.docs.ruleName
-      }"`,
-  )
-  .join("\n")}
-import { buildA11yRules } from "../a11y"
-
-export const rules = [
-  ${rules.map((rule) => camelCase(rule.meta.docs.ruleName)).join(",")},
-  ...buildA11yRules()
-] as RuleModule[]
-`
-
-const filePath = path.resolve(__dirname, "../src/utils/rules.ts")
-
-// Update file.
-void formatAndSave(filePath, content)
diff --git a/tools/update.ts b/tools/update.ts
index 441b6cb..26b8bbd 100644
--- a/tools/update.ts
+++ b/tools/update.ts
@@ -1,4 +1,4 @@
-import "./update-rules"
+import "./update-rules-index"
 import "./update-rulesets"
 import "./update-docs"
 import "./update-readme"


Test patch:
diff --git a/tests/src/rules/jsx-a11y/aria-proptypes.ts b/tests/src/rules/jsx-a11y/aria-proptypes.ts
index cdb4951..aed222b 100644
--- a/tests/src/rules/jsx-a11y/aria-proptypes.ts
+++ b/tests/src/rules/jsx-a11y/aria-proptypes.ts
@@ -1,5 +1,5 @@
 import { RuleTester } from "../../../utils/eslint-compat"
-import { rules } from "../../../../src/utils/rules"
+import { rules } from "../../../../src/rules"
 import { loadTestCases } from "../../../utils/utils"
 
 const rule = rules.find(
diff --git a/tests/src/rules/jsx-a11y/heading-has-content.ts b/tests/src/rules/jsx-a11y/heading-has-content.ts
index 4806db9..4c7db6a 100644
--- a/tests/src/rules/jsx-a11y/heading-has-content.ts
+++ b/tests/src/rules/jsx-a11y/heading-has-content.ts
@@ -1,5 +1,5 @@
 import { RuleTester } from "../../../utils/eslint-compat"
-import { rules } from "../../../../src/utils/rules"
+import { rules } from "../../../../src/rules"
 import { loadTestCases } from "../../../utils/utils"
 
 const rule = rules.find(
diff --git a/tests/src/rules/jsx-a11y/label-has-associated-control.ts b/tests/src/rules/jsx-a11y/label-has-associated-control.ts
index bf4ecba..7eee401 100644
--- a/tests/src/rules/jsx-a11y/label-has-associated-control.ts
+++ b/tests/src/rules/jsx-a11y/label-has-associated-control.ts
@@ -1,5 +1,5 @@
 import { RuleTester } from "../../../utils/eslint-compat"
-import { rules } from "../../../../src/utils/rules"
+import { rules } from "../../../../src/rules"
 import { loadTestCases } from "../../../utils/utils"
 
 const rule = rules.find(
diff --git a/tests/src/rules/jsx-a11y/no-autofocus.ts b/tests/src/rules/jsx-a11y/no-autofocus.ts
index 5dbe625..bdd5499 100644
--- a/tests/src/rules/jsx-a11y/no-autofocus.ts
+++ b/tests/src/rules/jsx-a11y/no-autofocus.ts
@@ -1,5 +1,5 @@
 import { RuleTester } from "../../../utils/eslint-compat"
-import { rules } from "../../../../src/utils/rules"
+import { rules } from "../../../../src/rules"
 import { loadTestCases } from "../../../utils/utils"
 
 const rule = rules.find(