@charcuterie/eslint-config

中文文档
1.7.1发布于 2026/09/04MITES Module构建来源已验证近 30 天下载 2326

房屋ESLint规则 Biome不能表达:有类型意识的命名,标识长度,以及仅逻辑属性.

中文使用文档
文档目录12 节
  1. 安装
  2. 使用量
  3. 手工制作
  4. 规则
  5. 仅逻辑属性
  6. 构成部分选择——选入
  7. 连接它
  8. 逃生舱
  9. Flex 溢出——选入
  10. 故意两分
  11. 它故意不这样做
  12. 测试

@charcuterie/eslint-config

Biome负责格式化和大部分的林克. 这个包只持有什么 生物体 无法 表达式:需要类型脚本类型的信息的规则,以及一个自定义 AST查询.

从 mux-magic/eslint.config.js,每个公约的参考应用 在此 repo 中, apps 消耗一个导入, 而不是六个复制的配置文件 .

安装

yarn add --dev @charcuterie/eslint-config eslint

两个包裹,和 eslint 只是因为CLI属于 消费者. typescript-eslint, (中文(简体) ), eslint-plugin-react 财务报告和审定财务报表 @vitest/eslint-plugin 为: 这个软件包本身的依赖性——一个共享的配置,其领养指令开始 "先安装这四个插件"的分享不多.

如果你的配置成像的话 tseslint.configs.* 从这里导入 :

import {
  createAppConfig,
  tseslint,
} from "@charcuterie/eslint-config"

不是从你自己 typescript-eslint平面配置抛出 Cannot redefine plugin "@typescript-eslint" 当两个块注册命名空间时 有两个不同的对象, 和第二个副本 typescript-eslint 在树上 没错. board-game-picker 将预设套装在锁上 而这个包 解决了8.67.0 旁边 eslint . 彻底失败; docket, (中文(简体) ), 使用相同的申报范围,去除并工作。 哪个回扣是财产 它的锁文件, 而非它的配置—— 因此实例被再出口, 有一个导入 其分明者.

使用量

// eslint.config.js — the whole file, in an app repo
import { createAppConfig } from "@charcuterie/eslint-config"
import { defineConfig } from "eslint/config"

export default defineConfig(
  ...createAppConfig({
    tsconfigRootDir: import.meta.dirname,
  }),
)

createAppConfig 是应用程序的默认答案。 由下面的工厂组成 按照正确的顺序, 缩小范围 @charcuterie/ui房子已经忽略了列表 已经就位。 如果不是,请写出来源所在 src数字 :

createAppConfig({
  tsconfigRootDir: import.meta.dirname,
  appDirectories: ["packages/web"],
  // Repo-specific paths are *added* to `APP_IGNORES`, not
  // swapped for it.
  ignores: ["e2e/**"],
})
选项默认它会做什么
tsconfigRootDir所需经费应用程序在哪里 tsconfig.json 活着. projectService 没有诚实的违约 别人的回扣.
appDirectories["src"]应用程序的自有来源. 这是使组件规则远离图书馆的范围.
ignores[]附录 APP_IGNORES。 。 。 .
componentChoice"pickers""all" 所有7个规则,一旦应用程序 扫过它的生锚和按钮; "off" 中期移民.
flexOverflow"off""warn" 或者说 "error" 以启动弹性家庭.
reactVersion"19.0.0"
storyFilesMULTI_COMPONENT_FILE_GLOBS可声明多个组件的文件.

react/no-multi-comp 说些故事, __fixtures__, (中文(简体) ), *.test.tsx图标 模块 (单位:千美元)icons.tsx, (中文(简体) ), *Icons.tsx) (中文(简体) ). 上两个发现 真正的应用程序运行的那一刻 预设, 并且是同样的论点 故事豁免已经做了—— 文件的工作是 保持一组。 需要包装器的组件测试 宣告了旁边的绳子 charcuterie没有故意的图标, 所以每个应用程序都有一个格言文件: 19岁 mail-sifter/components/icons.tsx十九个单行文件更糟糕, 没有人会写,规则就会被关闭.

为什么预设会存在,因为下面的每个工厂都已经 files:因为8个应用程序各自由手组成,到2026-08-21 6 已经漂流。 四个手工注册的插件对象和两个拾取规则 名称——同一段的四份解释为何不打电话 createComponentChoiceRules 旁边是 两个人根本没接过电线 分舰队的一条机器强制采摘规则 在分舰队的一半被执行。 规则 图书馆的船,但每个消费者必须重新思考 是规则舰队不 已经.

componentChoice: "pickers" 是默认,因为它是一个组件选择 家庭有长期决定,没有剩余积压: Select 实值 堕落, Picker 和每个拥有的应用程序被扫描到 Listbox 打开 2026-08-21. (中文(简体) ). 其他五个规则每个名字 一个扫描一个应用还没有完成 no-raw-button 单枪匹马地向舰队的每一个图标行开火 整个回波红色是一个被返回而不是迁移的配置.

flexOverflow 默认为 "off" 出于同样的原因,向前再走一步: no-shrink-0-with-flex-wrap 是一个 error,所以捆绑它会 使"通过 预设 ” 和“ 擦去弹性错误” 相同的更改.

手工制作

使用预设的应用程序无法描述是否仍然直接调用工厂 因此没有第二个执行程序可以保留 步骤. mux-magic 这样做,因为它 层自己 no-restricted-syntax 选中的逻辑属性 .

// eslint.config.js
import {
  createComponentChoiceRules,
  createFlexOverflowRules,
  createLogicalPropertiesRules,
  createPickerRules,
  createReactRules,
  createStoryOverrides,
  createTestRules,
  createTypedRules,
} from "@charcuterie/eslint-config"
import { defineConfig } from "eslint/config"

export default defineConfig(
  { ignores: ["**/dist/**", "**/node_modules/**"] },
  createTypedRules({
    tsconfigRootDir: import.meta.dirname,
  }),
  createReactRules({ files: ["packages/ui/**/*.tsx"] }),
  createLogicalPropertiesRules({
    files: ["packages/ui/**/*.tsx"],
  }),
  // The settled subset — `no-raw-select`,
  // `prefer-listbox-over-select`, and the suppression guard.
  createPickerRules({
    files: ["packages/web/**/*.tsx"],
  }),
  // All seven. Opt-in, and pointed at app source rather than the
  // library.
  createComponentChoiceRules({
    files: ["packages/web/**/*.tsx"],
  }),
  // Also opt-in. Warns by default; `severity: "error"` once the
  // app has been swept.
  createFlexOverflowRules({
    files: ["packages/web/**/*.tsx"],
  }),
  createStoryOverrides({}),
  createTestRules({}),
)

每个导出都是 工厂 files 而不是固定的配置数组。 A 类 共享硬码配置 packages/web/** 是个迷幻的装扮 共享名称; 消费者知道自己的布局, 而本套件没有. createAppConfig 不打破它,它从 appDirectories 而不是假设他们.

createTypedRules 需求 tsconfigRootDir 因为它打开 projectService —— 说 没有诚实的默认 别人的tsconfig生活的地方.

规则

规则它为什么在这里而不是在Biome
@typescript-eslint/naming-convention (是/有布尔斯)键关 types: ["boolean"],需要类型检查器
id-length (单位2, _ 财务报告和审定财务报表 $ 豁免)Biome没有等同物
react/no-multi-comp每个文件一个组件;故事关闭 __fixtures__
vitest/consistent-test-it (单位:千美元)test没有 it(中文(简体) )自动固定,这是唯一的原因 这个化妆品赚到一个插槽
no-restricted-syntax (仅逻辑属性)新来 - 见下文
charcuterie/* (构成部分选择)选入,但拾取子集——见下文
charcuterie/* (弹性溢出)这里新建, 并选入 - 见下文

所有的东西 charcuterie/* 规矩在 一个名称空间下的插件对象页:1 内 src/plugin.js平面配置抛出 Cannot redefine plugin 当两个块注册时 一个带有两个不同对象的命名空间,下面两个块将启用 独立——所以两个工厂都给ESLint提供了同样的参考. 第二个命名空间 (单位:千美元)charcuterie-layout这是另一种选择,但被拒绝:你们必定要记住 每个规则在写禁用注释时所用的前缀,以及错误的前缀 eslint-disable 沉默无声.

仅逻辑属性

这舰队的每一个空间价值都是逻辑消耗的—— ps-编号 :pe-, (中文(简体) ), ms-编号 :me-, (中文(简体) ), start-编号 :end-, (中文(简体) ), border-s编号 :border-e, (中文(简体) ), text-start编号 :text-end。它没有代价 今天,并让RTL 几乎在以后自由, 这就是为什么它是一个灵通规则而不是一个 偏好:偏好持续到第一人匆忙.

范围故意狭窄 —— 说 className 字符串字节和模板块 只有这个 有形财产 名称 样式对象( e)left, (中文(简体) ), paddingRight(没有) 匹配,因为 left 财务报告和审定财务报表 right 太多的合法身份识别器 地点 : getBoundingClientRect().left,浮动 UI 设置,渐变停止。 A 类 规则是哭狼被关闭, 而关闭规则执行 没什么 相同的推理使对比门 范围控制边界 而不是屏幕上的每行.

模式的锚是负载的,和 __fixtures__/logicalDirectionClassName.tsx 以证明: border-red-500 包含 border-r, (中文(简体) ), rounded-lg 包含 rounded-l, (中文(简体) ), place-items-center 开始于 pl这三个人必须保持干净.

构成部分选择——选入

2026-08-10测得的六起重案组 继续通过图书馆 原始内容。 文件一直没有到位,没有移动这些文件 数字,这是一个提示规则的整个参数: 医生读一次,规则是 执行每个保存.

规则着火了联系到在舰队中测量
charcuterie/no-raw-anchor<a>TextLink,或 ButtonLink 当导航显示为按钮时14个在mux-magic,10个在画廊倒装,31个在bambuddy
charcuterie/no-raw-button<button>Button,或 IconButton 当控件仅为图标时舰队中的每一个图标行
charcuterie/no-raw-select<select>Listbox (短,富)或 Combobox (长,可搜索)134个在巴姆巴迪,19分,积分市场2分
charcuterie/prefer-listbox-over-select<Select>Picker (滴入), Listbox,或 Combobox —— 说 Select 实值 已贬值,没有每个地点的例外2026-08-20 折旧
charcuterie/no-clickable-non-interactiveonClick 打开 <div>编号 :<span>编号 :<li>没有 role 或者说 tabIndexButton编号 :IconButton 行动, TextLink编号 :ButtonLink 导航points-market/…/AppShell.tsx:26-28 ——一个键盘无法到达的标题
charcuterie/no-navigation-in-click-handlernavigate(), (中文(简体) ), router.push(), (中文(简体) ), location.href = 在一个 onClickTextLink编号 :ButtonLink 带有 href所有复杂的通道,和邮件过滤器的整个外壳
charcuterie/require-suppression-reason禁用上方任何规则但没有 -- reason说为什么在一行—— 说

prefer-listbox-over-select 逃生舱门是一条规则 没有 呼叫地点 判决: Select 因此,禁用者引用的是决定记录,而不是 因为它本身。 已经是本地人了 Select 是一个转换的积压—— Picker 一样 label 编号 : options 编号 : value 编号 : onChange。 。 。 .

两个链接组件构成 真实 <a href>中键, ctrl-点击,打开-in-new-tab,复制链接和浏览器状态栏预览所有工作,以及 没有一个在点击处理器上工作。 链接去某个地方;按钮在这个页面上行事.

IconButton 获得自己的规则 出于同样的原因—— 仅一个图标 Button 已经 只能用一个格言来称呼它 IconButton 需要一个 label。 。 。 .

连接它

createComponentChoiceRules({
  // The app's own source. `packages/ui/**` is deliberately not
  // in here.
  files: ["packages/web/**/*.tsx"],
})

或只是拾取子集—— no-raw-select, (中文(简体) ), prefer-listbox-over-select,则 镇压警卫——这就是什么 createAppConfig 默认打开,什么 4个重新登记在存在之前:

createPickerRules({ files: ["packages/web/**/*.tsx"] })

子集不是妥协;而是决定与决定之间的界线 积压. Select 在不保留每个呼叫地点例外的情况下进行折旧 Picker 实值 所以那对子里没有什么是判决 其他五个都叫A 扫 -- no-raw-button 舰队每一图标行都起火 {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}一个明确的 componentChoice: "all"。 。 。 .

与 Biome 而不是 ESLint 相同的两个错误 @charcuterie/biome-config/app,表达他们 作为 noRestrictedElements 财务报告和审定财务报表 noRestrictedImports。 。 。 .

这是故意的. 5个应用软件在被收养的那天会红掉 和一个配置 将整个回波变为红色是一个被重回而不是迁移的配置——所以是 它自己的块,当一个应用程序准备好修复它找到的东西时添加.

files 也是整个机制 保持规则 @charcuterie/ui,它使得 原始内容 <a>, (中文(简体) ), <button> 财务报告和审定财务报表 <select> 因为它的正确性 实值 图书馆. 点 files 在应用程序源和库中从未匹配; __fixtures__/uiPackage/rawElements.tsx 说,因为范围界定机制 没有人 测试是一种无声地停止范围界定的范围界定机制.

这个街区 七个真正的插件规则没有 no-restricted-syntax 类似 逻辑属性一——插件对象在此包中内含,所以仍然有 没有额外的安装, 版本或发布 。 只有两种不同的规则身份才能做:

  1. 逃生舱关了它的名字. A 类 no-restricted-syntax 压制是一无是处,所以沉默一个生 <a> 一行也会沉默 上面的逻辑属性选择器.
  2. 平面配置取代了规则选项而不是将它们合并. 两块都设置好了 no-restricted-syntax 与相重叠的花纹相重叠,只留下后来的选手 悄悄地跑着.

逃生舱

每个规则都有一条,它必须有一个理由:

// eslint-disable-next-line charcuterie/no-raw-select -- posted by the browser with no JS on the page at all
<select name="theme">…</select>

charcuterie/require-suppression-reason 报告禁用其中任何一条没有 -- reason 之后,包括一条被子 // eslint-disable-next-line (让他们沉默) 也一样。 其他人的"禁用"评论被单独放出. 没有原因 规则停止 没有人知道为什么 本地元素是正确的呼叫, 下一个代理复制 模式——这就是整个区块存在的修复失败.

Flex 溢出——选入

一天内四次独立重新发现一个CSS规则 (2026-08-11), 期间 整个舰队的起伏 @charcuterie/[email protected]。17px型斜坡 消耗了懒惰 在11个重pos中,有5个隐藏了潜在布局错误,4个相同 形状:包含一个长而不可破的符号的弹性行.

弹性项目的自动最小尺寸与它的内容相对应 分钟内容 宽度因此,一个没有突破机会的标志 成为了排的地板 并推出它的 从容器里出来的兄弟. min-width: 0 让 项目 收缩但什么都不做 页:1 文本,然后会溢出 overflow-wrap: anywhere 缩小分量 大小本身.

规则着火了默认从哪里来
charcuterie/no-unconstrained-flex-texta 文本元素 (span, (中文(简体) ), h1– 说吧 –h6, (中文(简体) ), p, (中文(简体) ), label,.) 渲染 {dynamic} 文本作为弹性的直列子 横行,在其中无法逃脱 classNamewarn画廊下载器 ErrorRow,点-市场 ShopPage (标题+最近购买的芯片)
charcuterie/no-shrink-0-with-flex-wrapshrink-0 财务报告和审定财务报表 flex-wrap 在同一元素上,在弹性行内error夹克 RipCard ——它发现同样的bug uncount in HeldBayCard 财务报告和审定财务报表 QuarantinedBayCard

任何逃生都算数 因为四道运去的修补是四道不同的修补. min-w-0 wrap-anywhere (装货机,点-市场方向), flex-wrap + 键 shrink-0 (点-市场的价格行), truncate + 键 title (邮箱主机),和 删除 shrink-0 (rip-deck) (英语). 要求其中一人的规则对 其他三个。 接受: min-w-*, (中文(简体) ), truncate, (中文(简体) ), text-ellipsis, (中文(简体) ), line-clamp-*, (中文(简体) ), overflow-hidden, (中文(简体) ), wrap-anywhere, (中文(简体) ), break-all, (中文(简体) ), break-anywhere, (中文(简体) ), w-*, (中文(简体) ), max-w-*, (中文(简体) ), basis-*, (中文(简体) ), size-*, (中文(简体) ), shrink-0, (中文(简体) ), flex-none, (中文(简体) ), absolute, (中文(简体) ), fixed。 。 。 .

故意两分

no-unconstrained-flex-text 是一个 高压。它可以看到一行的文本孩子说 没有关于它是如何收缩的, 它不知道是否 {status} 实值 "OK" 或一个 300个字符 URL. 测量到整个舰队的6/49档案 画廊下拉机,点市5/11分,邮筛8/12分,夹克6/36分和 333/341 in mux-magic —— 音量低,但每次都有判断,所以 警告时A级 规则是将回波红了 而不是判决呼吁 是规则被删除而不是 满意了 一旦应用被扫描, 便推广它 :

createFlexOverflowRules({
  files: ["packages/web/**/*.tsx"],
  severity: "error",
})

no-shrink-0-with-flex-wrap 不是一个柔和的 shrink-0 将项目指向 最大内容,所以 flex-wrap 除了它 永远不能参与,所以它 错误。 。 。 .

它故意不这样做

  • <div> 不是一个文本元素. 这是通用的盒子 和最常见的孩子 弹性行宽;包括将规则变为噪音生成器.
  • 静态文本被跳过 . Cancel 从来没有300个字符。 虫子来了 数据,因此 {…} 儿童数——而不是 {children} 或者说 {rows.map(…)},哪个 做别人的标记 而不是文字运行.
  • tabular-nums 被跳过. 这是舰队的标记 一个有界位数运行. 没有排除,规则警告 河雀的三个特征 {percentText} 连 之后 运送的固定.
  • 列容器超出范围,任何集装箱也一样 flex-col 变体:形状是有条件的,有条件的形状不是自信的发现.
  • A 类 className 无法静态读取 联合国 clsx(…) 调用, 一个变量) 被跳过 -- 越狱很可能就在里面 报告它无法读到的东西最快 如何关闭.
  • shrink-0 + 键 flex-wrap 需要一个灵活排行的父程序 . 内部a flex-col, (中文(简体) ), shrink-0 抵制缩小 块 轴并不会影响元素的自包. 肌肉魔法师 FileExplorerModal 标题栏正是如此,本来是 规则的第一个假阳性 在它看到的第一个真实文件.

它没有抓住的一起案件,它明确指出: 邮件过滤器 LinkCard 主持人。 内容 溢出元素是网格柱内的一个块,而不是弹性项——上方的弹性行 它已经受到了正确的限制——因此没有任何弹性规则能够看到它。 那个还是个 truncate 通过阅读学习.

逃出舱门,和其他地方一样, 它欠一个原因:

{/* eslint-disable-next-line charcuterie/no-unconstrained-flex-text -- a closed enum, never longer than "running" */}
<span className="text-xs uppercase">{status}</span>

测试

src/houseRules.test.ts 运行真实 ESLint 课结束 src/__fixtures__/, (中文(简体) ), 如下 mux-magic/packages/tools/src/eslintBooleanPrefixRule.test.ts. 煽动 相对于实际的引擎,而不是规则-泰斯特绳 抓住了故障 repo最有可能被击中——这个规则配置正确,永远不会 应用, (中文(简体) ), 因为a files glob 或 解析器选项错误 。 那个沉默的不做是 与CI中的"干净"无法区分.

src/__fixtures__/ 拥有自己的 tsconfig.json 因此,类型意识规则可以解决 它,并且被排除在软件包本身的型号检查之外—— 固定装置是插入的, 不是来源.

__fixtures__/appPackage/unconstrainedFlexText.tsx 联 合 国 constrained… 双胞胎是 舰队在2026-08-11 实际固定的四行 从运输犯抄取 (下载器) 81e2c2a,点-市场 e6438b7邮件筛选 8ed11f4{\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你应该去 ce66aab)——前后. 诱导虫不在它的固定装置中的一条规则是 一条规则,没有人可以显示 捕获任何东西.

版本与发布记录

@charcuterie/eslint-config 共发布 10 个版本,首次发布于 2026/07/31;过去 12 个月发布了 10 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.7.1latest2026/09/042 个月前
1.7.02026/08/212 个月前
1.6.02026/08/212 个月前
1.5.02026/08/212 个月前
1.4.02026/08/212 个月前
1.3.02026/08/132 个月前

关于 @charcuterie/eslint-config 的常见问题

@charcuterie/eslint-config 是什么?

房屋ESLint规则 Biome不能表达:有类型意识的命名,标识长度,以及仅逻辑属性.

如何安装 @charcuterie/eslint-config?

在项目目录运行 npm install @charcuterie/eslint-config,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:eslint(>=10)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@charcuterie/eslint-config 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/charcuterie__eslint-config 是否存在。

@charcuterie/eslint-config 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@charcuterie/eslint-config 可以商用吗?

@charcuterie/eslint-config 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@charcuterie/eslint-config 的下载量有多少?

根据 npm 官方下载统计,@charcuterie/eslint-config 在 2026/10/10 – 2026/11/08 这 30 天内被下载 2,326 次,日均约 78 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@charcuterie/eslint-config 还在维护吗?

最新版本 1.7.1 发布于 2026/09/04(2 个月前);至今共发布 10 个版本,其中过去 12 个月发布了 10 个;首次发布于 2026/07/31。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。