@th1o/frontend-lint 0.0.4 → 0.0.5

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,10 +2,10 @@
2
2
 
3
3
  整体代码基于[@antfu/eslint-config](https://github.com/antfu/eslint-config)开发。做了如下修改:
4
4
 
5
- 1. 修改lint命名空间[`antfu -> ynzh`](./src/namespace.ts)。
5
+ 1. 修改lint命名空间[antfu -> ynzh](./src/namespace.ts)。
6
6
  2. `configs/`扩展了团队自定义配置,后续如果有其他补充或修改,都是在这个文件夹下的对应语言配置文件中调整。
7
- 3. `stylistic`风格化剔除了`antfu`的特定风格([没有`lessOpinionated`配置](./src/types.ts#L338))。
8
- 4. 添加了[`stylelint`](./src/stylelint.ts)配置生成导出。
7
+ 3. `stylistic`风格化剔除了`antfu`的特定风格([没有lessOpinionated配置](./src/types.ts#L338))。
8
+ 4. 添加了[stylelint](./src/stylelint.ts)配置生成导出。
9
9
 
10
10
  ## 开发 & 检视规则
11
11
 
package/dist/cli.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { n as PACKAGE_NAMESPACE } from "./namespace-Dr1zqW02.mjs";
2
2
  import process from "node:process";
3
- import fs from "node:fs/promises";
4
- import fs$1 from "node:fs";
3
+ import fsPromises from "node:fs/promises";
4
+ import fs from "node:fs";
5
5
  import path from "node:path";
6
6
  import * as p from "@clack/prompts";
7
7
  import c, { green } from "ansis";
@@ -10,7 +10,7 @@ import parse from "parse-gitignore";
10
10
  import { execSync } from "node:child_process";
11
11
 
12
12
  //#region package.json
13
- var version = "0.0.4";
13
+ var version = "0.0.5";
14
14
 
15
15
  //#endregion
16
16
  //#region src/cli/constants.ts
@@ -144,13 +144,13 @@ async function updateEslintFiles(result) {
144
144
  const cwd = process.cwd();
145
145
  const pathESLintIgnore = path.join(cwd, ".eslintignore");
146
146
  const pathPackageJSON = path.join(cwd, "package.json");
147
- const pkgContent = await fs.readFile(pathPackageJSON, "utf-8");
147
+ const pkgContent = await fsPromises.readFile(pathPackageJSON, "utf-8");
148
148
  const configFileName = JSON.parse(pkgContent).type === "module" ? "eslint.config.js" : "eslint.config.mjs";
149
149
  const pathFlatConfig = path.join(cwd, configFileName);
150
150
  const eslintIgnores = [];
151
- if (fs$1.existsSync(pathESLintIgnore)) {
151
+ if (fs.existsSync(pathESLintIgnore)) {
152
152
  p.log.step(c.cyan`Migrating existing .eslintignore`);
153
- const globs = parse(await fs.readFile(pathESLintIgnore, "utf-8")).globs();
153
+ const globs = parse(await fsPromises.readFile(pathESLintIgnore, "utf-8")).globs();
154
154
  for (const glob of globs) if (glob.type === "ignore") eslintIgnores.push(...glob.patterns);
155
155
  else if (glob.type === "unignore") eslintIgnores.push(...glob.patterns.map((pattern) => `!${pattern}`));
156
156
  }
@@ -160,9 +160,9 @@ async function updateEslintFiles(result) {
160
160
  if (result.extra.includes("unocss")) configLines.push(`unocss: true,`);
161
161
  for (const framework of result.frameworks) configLines.push(`${framework}: true,`);
162
162
  const eslintConfigContent = getEslintConfigContent(configLines.map((i) => ` ${i}`).join("\n"), []);
163
- await fs.writeFile(pathFlatConfig, eslintConfigContent);
163
+ await fsPromises.writeFile(pathFlatConfig, eslintConfigContent);
164
164
  p.log.success(c.green`Created ${configFileName}`);
165
- const files = fs$1.readdirSync(cwd);
165
+ const files = fs.readdirSync(cwd);
166
166
  const legacyConfig = [];
167
167
  files.forEach((file) => {
168
168
  if (/eslint|prettier/.test(file) && !/eslint\.config\./.test(file)) legacyConfig.push(file);
@@ -173,15 +173,15 @@ async function updateEslintFiles(result) {
173
173
  //#endregion
174
174
  //#region src/cli/constants-generated.ts
175
175
  const versionsMap = {
176
- "@eslint-react/eslint-plugin": "^2.7.4",
177
- "@next/eslint-plugin-next": "^16.1.5",
176
+ "@eslint-react/eslint-plugin": "^2.12.2",
177
+ "@next/eslint-plugin-next": "^16.1.6",
178
178
  "@unocss/eslint-plugin": "^66.6.0",
179
179
  "astro-eslint-parser": "^1.2.2",
180
180
  "eslint": "^9.39.2",
181
181
  "eslint-plugin-astro": "^1.5.0",
182
- "eslint-plugin-format": "^1.3.1",
182
+ "eslint-plugin-format": "^1.4.0",
183
183
  "eslint-plugin-react-hooks": "^7.0.1",
184
- "eslint-plugin-react-refresh": "^0.4.26",
184
+ "eslint-plugin-react-refresh": "^0.5.0",
185
185
  "eslint-plugin-solid": "^0.14.5",
186
186
  "eslint-plugin-svelte": "^3.14.0",
187
187
  "prettier-plugin-astro": "^0.14.1",
@@ -195,7 +195,7 @@ async function updatePackageJson(result) {
195
195
  const cwd = process.cwd();
196
196
  const pathPackageJSON = path.join(cwd, "package.json");
197
197
  p.log.step(c.cyan`Bumping ${PACKAGE_NAMESPACE} to v${version}`);
198
- const pkgContent = await fs.readFile(pathPackageJSON, "utf-8");
198
+ const pkgContent = await fsPromises.readFile(pathPackageJSON, "utf-8");
199
199
  const pkg = JSON.parse(pkgContent);
200
200
  pkg.devDependencies ??= {};
201
201
  pkg.devDependencies[PACKAGE_NAMESPACE] = `^${version}`;
@@ -226,7 +226,7 @@ async function updatePackageJson(result) {
226
226
  });
227
227
  }
228
228
  if (addedPackages.length) p.note(c.dim(addedPackages.join(", ")), "Added packages");
229
- await fs.writeFile(pathPackageJSON, JSON.stringify(pkg, null, 2));
229
+ await fsPromises.writeFile(pathPackageJSON, JSON.stringify(pkg, null, 2));
230
230
  p.log.success(c.green`Changes wrote to package.json`);
231
231
  }
232
232
 
@@ -237,16 +237,16 @@ async function updateVscodeSettings(result) {
237
237
  if (!result.updateVscodeSettings) return;
238
238
  const dotVscodePath = path.join(cwd, ".vscode");
239
239
  const settingsPath = path.join(dotVscodePath, "settings.json");
240
- if (!fs$1.existsSync(dotVscodePath)) await fs.mkdir(dotVscodePath, { recursive: true });
241
- if (!fs$1.existsSync(settingsPath)) {
242
- await fs.writeFile(settingsPath, `{${vscodeSettingsString}}\n`, "utf-8");
240
+ if (!fs.existsSync(dotVscodePath)) await fsPromises.mkdir(dotVscodePath, { recursive: true });
241
+ if (!fs.existsSync(settingsPath)) {
242
+ await fsPromises.writeFile(settingsPath, `{${vscodeSettingsString}}\n`, "utf-8");
243
243
  p.log.success(green`Created .vscode/settings.json`);
244
244
  } else {
245
- let settingsContent = await fs.readFile(settingsPath, "utf8");
245
+ let settingsContent = await fsPromises.readFile(settingsPath, "utf8");
246
246
  settingsContent = settingsContent.trim().replace(/\s*\}$/, "");
247
247
  settingsContent += settingsContent.endsWith(",") || settingsContent.endsWith("{") ? "" : ",";
248
248
  settingsContent += `${vscodeSettingsString}}\n`;
249
- await fs.writeFile(settingsPath, settingsContent, "utf-8");
249
+ await fsPromises.writeFile(settingsPath, settingsContent, "utf-8");
250
250
  p.log.success(green`Updated .vscode/settings.json`);
251
251
  }
252
252
  }
@@ -257,7 +257,7 @@ async function run(options = {}) {
257
257
  const argSkipPrompt = !!process.env.SKIP_PROMPT || options.yes;
258
258
  const argTemplate = options.frameworks?.map((m) => m?.trim()).filter(Boolean);
259
259
  const argExtra = options.extra?.map((m) => m?.trim()).filter(Boolean);
260
- if (fs$1.existsSync(path.join(process.cwd(), "eslint.config.js"))) {
260
+ if (fs.existsSync(path.join(process.cwd(), "eslint.config.js"))) {
261
261
  p.log.warn(c.yellow`eslint.config.js already exists, migration wizard exited.`);
262
262
  return process.exit(1);
263
263
  }
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { FlatConfigComposer } from "eslint-flat-config-utils";
1
+ import { ConfigWithExtends, FlatConfigComposer } from "eslint-flat-config-utils";
2
2
  import { Linter } from "eslint";
3
3
  import { StylisticCustomizeOptions } from "@stylistic/eslint-plugin";
4
4
  import { ParserOptions } from "@typescript-eslint/parser";
@@ -3203,7 +3203,7 @@ interface RuleOptions {
3203
3203
  */
3204
3204
  'react-dom/no-unknown-property'?: Linter.RuleEntry<ReactDomNoUnknownProperty>;
3205
3205
  /**
3206
- * Enforces 'sandbox' attribute for 'iframe' elements is not set to unsafe combinations.
3206
+ * Enforces that the 'sandbox' attribute for 'iframe' elements is not set to unsafe combinations.
3207
3207
  * @see https://eslint-react.xyz/docs/rules/dom-no-unsafe-iframe-sandbox
3208
3208
  */
3209
3209
  'react-dom/no-unsafe-iframe-sandbox'?: Linter.RuleEntry<[]>;
@@ -3381,6 +3381,11 @@ interface RuleOptions {
3381
3381
  */
3382
3382
  'react-naming-convention/use-state'?: Linter.RuleEntry<ReactNamingConventionUseState>;
3383
3383
  'react-refresh/only-export-components'?: Linter.RuleEntry<ReactRefreshOnlyExportComponents>;
3384
+ /**
3385
+ * Validate and transform React Client/Server Function definitions.
3386
+ * @see https://eslint-react.xyz/docs/rules/function-definition
3387
+ */
3388
+ 'react-rsc/function-definition'?: Linter.RuleEntry<[]>;
3384
3389
  /**
3385
3390
  * Enforces that every 'addEventListener' in a component or custom hook has a corresponding 'removeEventListener'.
3386
3391
  * @see https://eslint-react.xyz/docs/rules/web-api-no-leaked-event-listener
@@ -3553,7 +3558,7 @@ interface RuleOptions {
3553
3558
  */
3554
3559
  'react/no-forward-ref'?: Linter.RuleEntry<[]>;
3555
3560
  /**
3556
- * Prevents 'key' from not being explicitly specified (e.g., spreading 'key' from objects).
3561
+ * Prevents implicitly passing the 'key' prop to components.
3557
3562
  * @see https://eslint-react.xyz/docs/rules/no-implicit-key
3558
3563
  */
3559
3564
  'react/no-implicit-key'?: Linter.RuleEntry<[]>;
@@ -3563,12 +3568,12 @@ interface RuleOptions {
3563
3568
  */
3564
3569
  'react/no-leaked-conditional-rendering'?: Linter.RuleEntry<[]>;
3565
3570
  /**
3566
- * Enforces that all components have a 'displayName' that can be used in devtools.
3571
+ * Enforces that all components have a 'displayName' that can be used in DevTools.
3567
3572
  * @see https://eslint-react.xyz/docs/rules/no-missing-component-display-name
3568
3573
  */
3569
3574
  'react/no-missing-component-display-name'?: Linter.RuleEntry<[]>;
3570
3575
  /**
3571
- * Enforces that all contexts have a 'displayName' that can be used in devtools.
3576
+ * Enforces that all contexts have a 'displayName' that can be used in DevTools.
3572
3577
  * @see https://eslint-react.xyz/docs/rules/no-missing-context-display-name
3573
3578
  */
3574
3579
  'react/no-missing-context-display-name'?: Linter.RuleEntry<[]>;
@@ -3623,7 +3628,7 @@ interface RuleOptions {
3623
3628
  */
3624
3629
  'react/no-string-refs'?: Linter.RuleEntry<[]>;
3625
3630
  /**
3626
- * Disallows unnecessary 'key' props on elements.
3631
+ * Disallows unnecessary 'key' props on nested child elements when rendering lists.
3627
3632
  * @see https://eslint-react.xyz/docs/rules/no-unnecessary-key
3628
3633
  */
3629
3634
  'react/no-unnecessary-key'?: Linter.RuleEntry<[]>;
@@ -9160,7 +9165,7 @@ type FormatDprint = [] | [{
9160
9165
  }];
9161
9166
  // ----- format/prettier -----
9162
9167
  type FormatPrettier = [] | [{
9163
- parser?: string;
9168
+ parser: string;
9164
9169
  [k: string]: unknown | undefined;
9165
9170
  }];
9166
9171
  // ----- func-call-spacing -----
@@ -11705,7 +11710,7 @@ type PerfectionistSortArrayIncludes = {
11705
11710
  pattern: string;
11706
11711
  flags?: string;
11707
11712
  } | string));
11708
- selector?: ("literal" | "spread");
11713
+ selector?: "literal";
11709
11714
  }, ...({
11710
11715
  elementNamePattern?: (({
11711
11716
  pattern: string;
@@ -11714,7 +11719,7 @@ type PerfectionistSortArrayIncludes = {
11714
11719
  pattern: string;
11715
11720
  flags?: string;
11716
11721
  } | string));
11717
- selector?: ("literal" | "spread");
11722
+ selector?: "literal";
11718
11723
  })[]];
11719
11724
  } | {
11720
11725
  fallbackSort?: {
@@ -11732,7 +11737,7 @@ type PerfectionistSortArrayIncludes = {
11732
11737
  pattern: string;
11733
11738
  flags?: string;
11734
11739
  } | string));
11735
- selector?: ("literal" | "spread");
11740
+ selector?: "literal";
11736
11741
  })[];
11737
11742
  newlinesInside?: (("ignore" | number) | "newlinesBetween");
11738
11743
  groups?: (string | [string, ...(string)[]] | {
@@ -11900,6 +11905,7 @@ type PerfectionistSortClasses = [] | [{
11900
11905
  order?: ("asc" | "desc");
11901
11906
  })[];
11902
11907
  newlinesBetween?: ("ignore" | number);
11908
+ useExperimentalDependencyDetection?: boolean;
11903
11909
  ignoreCallbackDependenciesPatterns?: (({
11904
11910
  pattern: string;
11905
11911
  flags?: string;
@@ -13803,7 +13809,7 @@ type PerfectionistSortSets = {
13803
13809
  pattern: string;
13804
13810
  flags?: string;
13805
13811
  } | string));
13806
- selector?: ("literal" | "spread");
13812
+ selector?: "literal";
13807
13813
  }, ...({
13808
13814
  elementNamePattern?: (({
13809
13815
  pattern: string;
@@ -13812,7 +13818,7 @@ type PerfectionistSortSets = {
13812
13818
  pattern: string;
13813
13819
  flags?: string;
13814
13820
  } | string));
13815
- selector?: ("literal" | "spread");
13821
+ selector?: "literal";
13816
13822
  })[]];
13817
13823
  } | {
13818
13824
  fallbackSort?: {
@@ -13830,7 +13836,7 @@ type PerfectionistSortSets = {
13830
13836
  pattern: string;
13831
13837
  flags?: string;
13832
13838
  } | string));
13833
- selector?: ("literal" | "spread");
13839
+ selector?: "literal";
13834
13840
  })[];
13835
13841
  newlinesInside?: (("ignore" | number) | "newlinesBetween");
13836
13842
  groups?: (string | [string, ...(string)[]] | {
@@ -14340,9 +14346,9 @@ type ReactNamingConventionUseState = [] | [{
14340
14346
  }];
14341
14347
  // ----- react-refresh/only-export-components -----
14342
14348
  type ReactRefreshOnlyExportComponents = [] | [{
14349
+ extraHOCs?: string[];
14343
14350
  allowExportNames?: string[];
14344
14351
  allowConstantExport?: boolean;
14345
- customHOCs?: string[];
14346
14352
  checkJS?: boolean;
14347
14353
  }];
14348
14354
  // ----- react/jsx-shorthand-boolean -----
@@ -19037,6 +19043,7 @@ type YnzhConsistentListNewline = [] | [{
19037
19043
  ExportNamedDeclaration?: boolean;
19038
19044
  FunctionDeclaration?: boolean;
19039
19045
  FunctionExpression?: boolean;
19046
+ IfStatement?: boolean;
19040
19047
  ImportDeclaration?: boolean;
19041
19048
  JSONArrayExpression?: boolean;
19042
19049
  JSONObjectExpression?: boolean;
@@ -19062,7 +19069,7 @@ type Yoda = [] | [("always" | "never")] | [("always" | "never"), {
19062
19069
  onlyEquality?: boolean;
19063
19070
  }];
19064
19071
  // Names of all the configs
19065
- type ConfigNames = 'ynzh/gitignore' | 'ynzh/ignores' | 'ynzh/javascript/setup' | 'ynzh/javascript/rules' | 'ynzh/eslint-comments/rules' | 'ynzh/command/rules' | 'ynzh/perfectionist/setup' | 'ynzh/node/rules' | 'ynzh/jsdoc/rules' | 'ynzh/imports/rules' | 'ynzh/unicorn/rules' | 'ynzh/jsx/setup' | 'ynzh/typescript/setup' | 'ynzh/typescript/parser' | 'ynzh/typescript/type-aware-parser' | 'ynzh/typescript/rules' | 'ynzh/typescript/rules-type-aware' | 'ynzh/typescript/erasable-syntax-only' | 'ynzh/stylistic/rules' | 'ynzh/regexp/rules' | 'ynzh/test/setup' | 'ynzh/test/rules' | 'ynzh/vue/setup' | 'ynzh/vue/rules' | 'ynzh/react/setup' | 'ynzh/react/rules' | 'ynzh/react/type-aware-rules' | 'ynzh/nextjs/setup' | 'ynzh/nextjs/rules' | 'ynzh/solid/setup' | 'ynzh/solid/rules' | 'ynzh/svelte/setup' | 'ynzh/svelte/rules' | 'ynzh/unocss' | 'ynzh/astro/setup' | 'ynzh/astro/rules' | 'ynzh/jsonc/setup' | 'ynzh/jsonc/rules' | 'ynzh/sort/package-json' | 'ynzh/sort/tsconfig-json' | 'ynzh/pnpm/package-json' | 'ynzh/pnpm/pnpm-workspace-yaml' | 'ynzh/pnpm/pnpm-workspace-yaml-sort' | 'ynzh/yaml/setup' | 'ynzh/yaml/rules' | 'ynzh/toml/setup' | 'ynzh/toml/rules' | 'ynzh/markdown/setup' | 'ynzh/markdown/processor' | 'ynzh/markdown/parser' | 'ynzh/markdown/disables' | 'ynzh/formatter/setup' | 'ynzh/formatter/css' | 'ynzh/formatter/scss' | 'ynzh/formatter/less' | 'ynzh/formatter/html' | 'ynzh/formatter/xml' | 'ynzh/formatter/svg' | 'ynzh/formatter/markdown' | 'ynzh/formatter/astro' | 'ynzh/formatter/astro/disables' | 'ynzh/formatter/graphql' | 'ynzh/disables/scripts' | 'ynzh/disables/cli' | 'ynzh/disables/bin' | 'ynzh/disables/dts' | 'ynzh/disables/cjs' | 'ynzh/disables/config-files';
19072
+ type ConfigNames = 'ynzh/gitignore' | 'ynzh/ignores' | 'ynzh/javascript/setup' | 'ynzh/javascript/rules' | 'ynzh/eslint-comments/rules' | 'ynzh/command/rules' | 'ynzh/perfectionist/setup' | 'ynzh/node/rules' | 'ynzh/jsdoc/rules' | 'ynzh/imports/rules' | 'ynzh/unicorn/rules' | 'ynzh/jsx/setup' | 'ynzh/typescript/setup' | 'ynzh/typescript/parser' | 'ynzh/typescript/type-aware-parser' | 'ynzh/typescript/rules' | 'ynzh/typescript/rules-type-aware' | 'ynzh/typescript/erasable-syntax-only' | 'ynzh/stylistic/rules' | 'ynzh/regexp/rules' | 'ynzh/test/setup' | 'ynzh/test/rules' | 'ynzh/vue/setup' | 'ynzh/vue/rules' | 'ynzh/react/setup' | 'ynzh/react/rules' | 'ynzh/react/typescript' | 'ynzh/react/type-aware-rules' | 'ynzh/nextjs/setup' | 'ynzh/nextjs/rules' | 'ynzh/solid/setup' | 'ynzh/solid/rules' | 'ynzh/svelte/setup' | 'ynzh/svelte/rules' | 'ynzh/unocss' | 'ynzh/astro/setup' | 'ynzh/astro/rules' | 'ynzh/jsonc/setup' | 'ynzh/jsonc/rules' | 'ynzh/sort/package-json' | 'ynzh/sort/tsconfig-json' | 'ynzh/pnpm/package-json' | 'ynzh/pnpm/pnpm-workspace-yaml' | 'ynzh/pnpm/pnpm-workspace-yaml-sort' | 'ynzh/yaml/setup' | 'ynzh/yaml/rules' | 'ynzh/toml/setup' | 'ynzh/toml/rules' | 'ynzh/markdown/setup' | 'ynzh/markdown/processor' | 'ynzh/markdown/parser' | 'ynzh/markdown/disables' | 'ynzh/formatter/setup' | 'ynzh/formatter/css' | 'ynzh/formatter/scss' | 'ynzh/formatter/less' | 'ynzh/formatter/html' | 'ynzh/formatter/xml' | 'ynzh/formatter/svg' | 'ynzh/formatter/markdown' | 'ynzh/formatter/astro' | 'ynzh/formatter/astro/disables' | 'ynzh/formatter/graphql' | 'ynzh/disables/scripts' | 'ynzh/disables/cli' | 'ynzh/disables/bin' | 'ynzh/disables/dts' | 'ynzh/disables/cjs' | 'ynzh/disables/config-files';
19066
19073
  //#endregion
19067
19074
  //#region src/vender/prettier-types.d.ts
19068
19075
  /**
@@ -19192,7 +19199,7 @@ type Rules = Record<string, Linter.RuleEntry<any> | undefined> & RuleOptions;
19192
19199
  * for `rules` and relaxes type limitations for `plugins` and `rules`, because
19193
19200
  * many plugins still lack proper type definitions.
19194
19201
  */
19195
- type TypedFlatConfigItem = Omit<Linter.Config, 'plugins' | 'rules'> & {
19202
+ type TypedFlatConfigItem = Omit<ConfigWithExtends, 'plugins' | 'rules'> & {
19196
19203
  /**
19197
19204
  * An object containing a name-value mapping of plugin names to plugin objects.
19198
19205
  * When `files` is specified, these plugins are only available to the matching files.
@@ -19916,4 +19923,4 @@ declare function ensurePackages(packages: (string | undefined)[]): Promise<void>
19916
19923
  declare function isInEditorEnv(): boolean;
19917
19924
  declare function isInGitHooksOrLintStaged(): boolean;
19918
19925
  //#endregion
19919
- export { Awaitable, CONFIG_PRESET_FULL_OFF, CONFIG_PRESET_FULL_ON, type ConfigNames, GLOB_ALL_SRC, GLOB_ASTRO, GLOB_ASTRO_TS, GLOB_CSS, GLOB_EXCLUDE, GLOB_GRAPHQL, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_MARKDOWN, GLOB_MARKDOWN_CODE, GLOB_MARKDOWN_IN_MARKDOWN, GLOB_POSTCSS, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_SVELTE, GLOB_SVG, GLOB_TESTS, GLOB_TOML, GLOB_TS, GLOB_TSX, GLOB_VUE, GLOB_XML, GLOB_YAML, OptionsComponentExts, OptionsConfig, OptionsFiles, OptionsFormatters, OptionsHasTypeScript, OptionsIsInEditor, OptionsJSX, OptionsJSXA11y, OptionsOverrides, OptionsPnpm, OptionsProjectType, OptionsReact, OptionsRegExp, OptionsStylistic, OptionsTypeScriptErasableOnly, OptionsTypeScriptParserOptions, OptionsTypeScriptWithTypes, OptionsTypescript, OptionsUnicorn, OptionsUnoCSS, OptionsVue, ResolvedOptions, Rules, StylisticConfig, StylisticConfigDefaults, StylisticOptions, TypedFlatConfigItem, astro, combine, command, comments, createESLintConfig, createESLintConfig as default, createStylelintConfig, defaultPluginRenaming, disables, ensurePackages, formatters, getOverrides, ignores, imports, interopDefault, isInEditorEnv, isInGitHooksOrLintStaged, isPackageInScope, javascript, jsdoc, jsonc, jsx, markdown, nextjs, node, parserPlain, perfectionist, pnpm, react, regexp, renamePluginInConfigs, renameRules, resolveSubOptions, solid, sortPackageJson, sortTsconfig, stylistic, svelte, test, toArray, toml, typescript, unicorn, unocss, vue, yaml };
19926
+ export { Awaitable, CONFIG_PRESET_FULL_OFF, CONFIG_PRESET_FULL_ON, type ConfigNames, GLOB_ALL_SRC, GLOB_ASTRO, GLOB_ASTRO_TS, GLOB_CSS, GLOB_EXCLUDE, GLOB_GRAPHQL, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_MARKDOWN, GLOB_MARKDOWN_CODE, GLOB_MARKDOWN_IN_MARKDOWN, GLOB_POSTCSS, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_SVELTE, GLOB_SVG, GLOB_TESTS, GLOB_TOML, GLOB_TS, GLOB_TSX, GLOB_VUE, GLOB_XML, GLOB_YAML, OptionsComponentExts, OptionsConfig, OptionsFiles, OptionsFormatters, OptionsHasTypeScript, OptionsIsInEditor, OptionsJSX, OptionsJSXA11y, OptionsOverrides, OptionsPnpm, OptionsProjectType, OptionsReact, OptionsRegExp, OptionsStylistic, OptionsTypeScriptErasableOnly, OptionsTypeScriptParserOptions, OptionsTypeScriptWithTypes, OptionsTypescript, OptionsUnicorn, OptionsUnoCSS, OptionsVue, ResolvedOptions, type RuleOptions, Rules, StylisticConfig, StylisticConfigDefaults, StylisticOptions, TypedFlatConfigItem, astro, combine, command, comments, createESLintConfig, createESLintConfig as default, createStylelintConfig, defaultPluginRenaming, disables, ensurePackages, formatters, getOverrides, ignores, imports, interopDefault, isInEditorEnv, isInGitHooksOrLintStaged, isPackageInScope, javascript, jsdoc, jsonc, jsx, markdown, nextjs, node, parserPlain, perfectionist, pnpm, react, regexp, renamePluginInConfigs, renameRules, resolveSubOptions, solid, sortPackageJson, sortTsconfig, stylistic, svelte, test, toArray, toml, typescript, unicorn, unocss, vue, yaml };
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import { n as PACKAGE_NAMESPACE, t as LINT_NAMESPACE } from "./namespace-Dr1zqW02.mjs";
2
2
  import { FlatConfigComposer } from "eslint-flat-config-utils";
3
3
  import process from "node:process";
4
- import fs from "node:fs/promises";
4
+ import fsPromises from "node:fs/promises";
5
5
  import { fileURLToPath } from "node:url";
6
- import fs$1 from "node:fs";
6
+ import fs from "node:fs";
7
7
  import path from "node:path";
8
8
  import { isPackageExists } from "local-pkg";
9
9
  import createCommand from "eslint-plugin-command/config";
@@ -28,7 +28,7 @@ async function findUp(name, { cwd = process.cwd(), type = "file", stopAt } = {})
28
28
  while (directory) {
29
29
  const filePath = isAbsoluteName ? name : path.join(directory, name);
30
30
  try {
31
- const stats = await fs.stat(filePath);
31
+ const stats = await fsPromises.stat(filePath);
32
32
  if (type === "file" && stats.isFile() || type === "directory" && stats.isDirectory()) return filePath;
33
33
  } catch {}
34
34
  if (directory === stopAt || directory === root) break;
@@ -43,7 +43,7 @@ function findUpSync(name, { cwd = process.cwd(), type = "file", stopAt } = {}) {
43
43
  while (directory) {
44
44
  const filePath = isAbsoluteName ? name : path.join(directory, name);
45
45
  try {
46
- const stats = fs$1.statSync(filePath, { throwIfNoEntry: false });
46
+ const stats = fs.statSync(filePath, { throwIfNoEntry: false });
47
47
  if (type === "file" && stats?.isFile() || type === "directory" && stats?.isDirectory()) return filePath;
48
48
  } catch {}
49
49
  if (directory === stopAt || directory === root) break;
@@ -463,7 +463,8 @@ async function formatters(options = {}, stylistic$1 = {}) {
463
463
  "eslint-plugin-format",
464
464
  options.markdown && options.slidev ? "prettier-plugin-slidev" : void 0,
465
465
  options.astro ? "prettier-plugin-astro" : void 0,
466
- options.xml || options.svg ? "@prettier/plugin-xml" : void 0
466
+ options.xml || options.svg ? "@prettier/plugin-xml" : void 0,
467
+ options.html ? "@awmottaz/prettier-plugin-void-html" : void 0
467
468
  ]);
468
469
  if (options.slidev && options.markdown !== true && options.markdown !== "prettier") throw new Error("`slidev` option only works when `markdown` is enabled with `prettier`");
469
470
  const { indent, quotes, semi } = {
@@ -515,7 +516,10 @@ async function formatters(options = {}, stylistic$1 = {}) {
515
516
  files: [GLOB_HTML],
516
517
  languageOptions: { parser: parserPlain },
517
518
  name: `${LINT_NAMESPACE}/formatter/html`,
518
- rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "html" })] }
519
+ rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, {
520
+ parser: "html",
521
+ plugins: ["@awmottaz/prettier-plugin-void-html"]
522
+ })] }
519
523
  });
520
524
  if (options.xml) configs$1.push({
521
525
  files: [GLOB_XML],
@@ -1173,7 +1177,7 @@ async function perfectionist() {
1173
1177
  async function detectCatalogUsage() {
1174
1178
  const workspaceFile = await findUp("pnpm-workspace.yaml");
1175
1179
  if (!workspaceFile) return false;
1176
- const yaml$1 = await fs.readFile(workspaceFile, "utf-8");
1180
+ const yaml$1 = await fsPromises.readFile(workspaceFile, "utf-8");
1177
1181
  return yaml$1.includes("catalog:") || yaml$1.includes("catalogs:");
1178
1182
  }
1179
1183
  async function pnpm(options) {
@@ -1318,7 +1322,10 @@ async function react(options = {}) {
1318
1322
  "eslint-plugin-react-refresh"
1319
1323
  ]);
1320
1324
  const isTypeAware = !!tsconfigPath;
1321
- const typeAwareRules = { "react/no-leaked-conditional-rendering": "warn" };
1325
+ const typeAwareRules = {
1326
+ "react/no-leaked-conditional-rendering": "warn",
1327
+ "react/no-implicit-key": "error"
1328
+ };
1322
1329
  const [pluginReact, pluginReactHooks, pluginReactRefresh] = await Promise.all([
1323
1330
  interopDefault(import("@eslint-react/eslint-plugin")),
1324
1331
  interopDefault(import("eslint-plugin-react-hooks")),
@@ -1339,6 +1346,7 @@ async function react(options = {}) {
1339
1346
  "react-hooks-extra": plugins["@eslint-react/hooks-extra"],
1340
1347
  "react-naming-convention": plugins["@eslint-react/naming-convention"],
1341
1348
  "react-refresh": pluginReactRefresh,
1349
+ "react-rsc": plugins["@eslint-react/rsc"],
1342
1350
  "react-web-api": plugins["@eslint-react/web-api"]
1343
1351
  }
1344
1352
  },
@@ -1370,9 +1378,7 @@ async function react(options = {}) {
1370
1378
  "react/no-create-ref": "error",
1371
1379
  "react/no-default-props": "error",
1372
1380
  "react/no-direct-mutation-state": "error",
1373
- "react/no-duplicate-key": "error",
1374
1381
  "react/no-forward-ref": "warn",
1375
- "react/no-implicit-key": "warn",
1376
1382
  "react/no-missing-key": "error",
1377
1383
  "react/no-nested-component-definitions": "error",
1378
1384
  "react/no-nested-lazy-component-declarations": "error",
@@ -1381,6 +1387,7 @@ async function react(options = {}) {
1381
1387
  "react/no-set-state-in-component-did-mount": "warn",
1382
1388
  "react/no-set-state-in-component-did-update": "warn",
1383
1389
  "react/no-set-state-in-component-will-update": "warn",
1390
+ "react/no-unused-class-component-members": "warn",
1384
1391
  "react/no-string-refs": "error",
1385
1392
  "react/no-unnecessary-use-prefix": "warn",
1386
1393
  "react/no-unsafe-component-will-mount": "warn",
@@ -1390,6 +1397,7 @@ async function react(options = {}) {
1390
1397
  "react/no-useless-forward-ref": "warn",
1391
1398
  "react/prefer-use-state-lazy-initialization": "warn",
1392
1399
  "react/prefer-namespace-import": "error",
1400
+ "react-rsc/function-definition": "error",
1393
1401
  "react-dom/no-dangerously-set-innerhtml": "warn",
1394
1402
  "react-dom/no-dangerously-set-innerhtml-with-children": "error",
1395
1403
  "react-dom/no-find-dom-node": "error",
@@ -1402,6 +1410,14 @@ async function react(options = {}) {
1402
1410
  "react-dom/no-unsafe-iframe-sandbox": "warn",
1403
1411
  "react-dom/no-use-form-state": "error",
1404
1412
  "react-dom/no-void-elements-with-children": "error",
1413
+ "react-hooks-extra/no-direct-set-state-in-use-effect": "warn",
1414
+ "react-naming-convention/context-name": "warn",
1415
+ "react-naming-convention/ref-name": "warn",
1416
+ "react-naming-convention/use-state": "warn",
1417
+ "react-web-api/no-leaked-event-listener": "warn",
1418
+ "react-web-api/no-leaked-interval": "warn",
1419
+ "react-web-api/no-leaked-resize-observer": "warn",
1420
+ "react-web-api/no-leaked-timeout": "warn",
1405
1421
  "react-hooks/rules-of-hooks": "error",
1406
1422
  "react-hooks/exhaustive-deps": "warn",
1407
1423
  ...reactCompiler ? {
@@ -1421,11 +1437,6 @@ async function react(options = {}) {
1421
1437
  "react-hooks/use-memo": "error",
1422
1438
  "react-hooks/incompatible-library": "warn"
1423
1439
  } : {},
1424
- "react-hooks-extra/no-direct-set-state-in-use-effect": "warn",
1425
- "react-web-api/no-leaked-event-listener": "warn",
1426
- "react-web-api/no-leaked-interval": "warn",
1427
- "react-web-api/no-leaked-resize-observer": "warn",
1428
- "react-web-api/no-leaked-timeout": "warn",
1429
1440
  "react-refresh/only-export-components": ["error", {
1430
1441
  allowConstantExport: isAllowConstantExport,
1431
1442
  allowExportNames: [...isUsingNext ? [
@@ -1458,6 +1469,18 @@ async function react(options = {}) {
1458
1469
  ...overrides
1459
1470
  }
1460
1471
  },
1472
+ {
1473
+ files: filesTypeAware,
1474
+ name: `${LINT_NAMESPACE}/react/typescript`,
1475
+ rules: {
1476
+ "react-dom/no-string-style-prop": "off",
1477
+ "react-dom/no-unknown-property": "off",
1478
+ "react/jsx-no-duplicate-props": "off",
1479
+ "react/jsx-no-undef": "off",
1480
+ "react/jsx-uses-react": "off",
1481
+ "react/jsx-uses-vars": "off"
1482
+ }
1483
+ },
1461
1484
  ...isTypeAware ? [{
1462
1485
  files: filesTypeAware,
1463
1486
  ignores: ignoresTypeAware,
@@ -2685,6 +2708,7 @@ function createStylelintConfig(overrides) {
2685
2708
  "declaration-no-important": true,
2686
2709
  "function-url-quotes": "never",
2687
2710
  "import-notation": "string",
2711
+ "selector-class-pattern": ["^[a-z0-9]+(?:-[a-z0-9]+)*(?:__[a-z0-9]+(?:-[a-z0-9]+)*)*(?:--[a-z0-9]+(?:-[a-z0-9]+)*)*$", { resolveNestedSelectors: true }],
2688
2712
  "selector-max-id": [0, { ignoreContextFunctionalPseudoClasses: [":not", "/^:(h|H)as$/"] }],
2689
2713
  ...overrides
2690
2714
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@th1o/frontend-lint",
3
3
  "type": "module",
4
- "version": "0.0.4",
4
+ "version": "0.0.5",
5
5
  "description": "ESLint config",
6
6
  "author": "张天昊 <theozhang.tech@outlook.com>",
7
7
  "keywords": [
@@ -92,7 +92,8 @@
92
92
  },
93
93
  "dependencies": {
94
94
  "@antfu/install-pkg": "^1.1.0",
95
- "@clack/prompts": "^0.11.0",
95
+ "@awmottaz/prettier-plugin-void-html": "^2.0.0",
96
+ "@clack/prompts": "^1.0.0",
96
97
  "@eslint-community/eslint-plugin-eslint-comments": "^4.6.0",
97
98
  "@eslint/markdown": "^7.5.1",
98
99
  "@stylistic/eslint-plugin": "^5.7.1",
@@ -102,56 +103,56 @@
102
103
  "ansis": "^4.2.0",
103
104
  "cac": "^6.7.14",
104
105
  "eslint-config-flat-gitignore": "^2.1.0",
105
- "eslint-flat-config-utils": "^2.1.4",
106
+ "eslint-flat-config-utils": "^3.0.1",
106
107
  "eslint-merge-processors": "^2.0.0",
107
- "eslint-plugin-antfu": "^3.1.3",
108
+ "eslint-plugin-antfu": "^3.2.0",
108
109
  "eslint-plugin-command": "^3.4.0",
109
110
  "eslint-plugin-import-lite": "^0.5.0",
110
- "eslint-plugin-jsdoc": "^62.4.1",
111
+ "eslint-plugin-jsdoc": "^62.5.4",
111
112
  "eslint-plugin-jsonc": "^2.21.0",
112
113
  "eslint-plugin-n": "^17.23.2",
113
114
  "eslint-plugin-no-only-tests": "^3.3.0",
114
- "eslint-plugin-perfectionist": "^5.4.0",
115
+ "eslint-plugin-perfectionist": "^5.5.0",
115
116
  "eslint-plugin-pnpm": "^1.5.0",
116
- "eslint-plugin-regexp": "^2.10.0",
117
- "eslint-plugin-toml": "^1.0.3",
117
+ "eslint-plugin-regexp": "^3.0.0",
118
+ "eslint-plugin-toml": "^1.0.4",
118
119
  "eslint-plugin-typescript-enum": "^2.1.0",
119
120
  "eslint-plugin-unicorn": "^62.0.0",
120
121
  "eslint-plugin-unused-imports": "^4.3.0",
121
122
  "eslint-plugin-vue": "^10.7.0",
122
- "eslint-plugin-yml": "^3.0.0",
123
+ "eslint-plugin-yml": "^3.1.2",
123
124
  "eslint-processor-vue-blocks": "^2.0.0",
124
- "globals": "^17.1.0",
125
+ "globals": "^17.3.0",
125
126
  "jsonc-eslint-parser": "^2.4.2",
126
127
  "local-pkg": "^1.1.2",
127
128
  "parse-gitignore": "^2.0.0",
128
- "postcss-html": "^1.5.0",
129
- "stylelint-config-recess-order": "^7.6.0",
129
+ "postcss-html": "^1.8.1",
130
+ "stylelint-config-recess-order": "^7.6.1",
130
131
  "stylelint-config-recommended-vue": "^1.6.1",
131
132
  "stylelint-config-standard": "^40.0.0",
132
- "stylelint-order": "^7.0.0",
133
+ "stylelint-order": "^7.0.1",
133
134
  "toml-eslint-parser": "^1.0.3",
134
135
  "vue-eslint-parser": "^10.2.0",
135
136
  "yaml-eslint-parser": "^2.0.0"
136
137
  },
137
138
  "devDependencies": {
138
139
  "@antfu/ni": "^28.2.0",
139
- "@eslint-react/eslint-plugin": "^2.7.4",
140
+ "@eslint-react/eslint-plugin": "^2.12.2",
140
141
  "@eslint/config-inspector": "^1.4.2",
141
- "@next/eslint-plugin-next": "^16.1.5",
142
+ "@next/eslint-plugin-next": "^16.1.6",
142
143
  "@prettier/plugin-xml": "^3.4.2",
143
144
  "@types/eslint-plugin-jsx-a11y": "^6.10.1",
144
- "@types/node": "^25.0.10",
145
+ "@types/node": "^25.2.2",
145
146
  "@unocss/eslint-plugin": "^66.6.0",
146
147
  "astro-eslint-parser": "^1.2.2",
147
- "bumpp": "^10.4.0",
148
+ "bumpp": "^10.4.1",
148
149
  "eslint": "^9.39.2",
149
150
  "eslint-plugin-astro": "^1.5.0",
150
151
  "eslint-plugin-erasable-syntax-only": "^0.4.0",
151
- "eslint-plugin-format": "^1.3.1",
152
+ "eslint-plugin-format": "^1.4.0",
152
153
  "eslint-plugin-jsx-a11y": "^6.10.2",
153
154
  "eslint-plugin-react-hooks": "^7.0.1",
154
- "eslint-plugin-react-refresh": "^0.4.26",
155
+ "eslint-plugin-react-refresh": "^0.5.0",
155
156
  "eslint-plugin-solid": "^0.14.5",
156
157
  "eslint-plugin-svelte": "^3.14.0",
157
158
  "eslint-plugin-vuejs-accessibility": "^2.4.1",
@@ -164,8 +165,8 @@
164
165
  "prettier-plugin-astro": "^0.14.1",
165
166
  "prettier-plugin-slidev": "^1.0.5",
166
167
  "simple-git-hooks": "^2.13.1",
167
- "stylelint": "^17.0.0",
168
- "svelte": "^5.48.3",
168
+ "stylelint": "^17.1.1",
169
+ "svelte": "^5.50.0",
169
170
  "svelte-eslint-parser": "^1.4.1",
170
171
  "taze": "^19.9.2",
171
172
  "tinyglobby": "^0.2.15",
@@ -174,7 +175,7 @@
174
175
  "typescript": "^5.9.3",
175
176
  "vitest": "^4.0.18",
176
177
  "vue": "^3.5.27",
177
- "@th1o/frontend-lint": "0.0.4"
178
+ "@th1o/frontend-lint": "0.0.5"
178
179
  },
179
180
  "resolutions": {
180
181
  "@eslint-community/eslint-utils": "catalog:peer",