# @cratis/eslint-plugin-components 中文文档

规范地址：https://npmcn.com/package/%40cratis/eslint-plugin-components/

版本：4\.40\.0
npm 元数据更新时间：2026-11-04T10:42:46.332Z
中文译文更新时间：2026-11-10T23:29:31.508Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40cratis/eslint-plugin-components
原文对照：https://npmcn.com/package/%40cratis/eslint-plugin-components/?lang=original
项目主页：https://www.cratis.io/components/
源码仓库：https://github.com/Cratis/Components

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：63.2 kB，12 个文件
- 模块格式：ES Module
- TypeScript 类型：未声明
- 运行依赖：0 个
- peer 依赖：eslint \>=9
- 首次发布：2026-06-04T17:10:17.349Z
- 最新版本发布：2026-11-04T10:42:46.016Z
- 近 30 天下载量：4431（2026-10-11 至 2026-11-09，npm 官方下载统计）
- 已发布版本数：114（近 12 个月 114 个）

## 中文简介

Cratis 组件 ESLint 规则: 从子路径而不是根桶导入, 使用 Cratis 对话框包, 而不是 primereact/ dialog , 要求在 Execute 调用后返回其值, 保留 resact 钩子退出视图模式, 保护寄存器- ow

## 安装

```sh
npm install @cratis/eslint-plugin-components
```

也可以使用：`pnpm add @cratis/eslint-plugin-components`、`yarn add @cratis/eslint-plugin-components`、`bun add @cratis/eslint-plugin-components`

## README

# @cratis/eslint-plugin 组件

ESLint规则用于消费克拉蒂斯组件的项目. 在上面写这些 克拉蒂斯基础配置, [`@cratis/eslint-config`](https://www.npmjs.com/package/@cratis/eslint-config)。 。 。 .

| 规则 | 它会做什么 |
| --- | --- |
| `no-root-barrel-import` | 拒绝从组件 4 中导入已删除的组件 3 的命名空间 。 使用精确的组件子路径( N)`@cratis/components/CommandDialog`, (中文(简体) ), `@cratis/components/DataPage`, (中文(简体) ), `@cratis/components/Toolbar`(中文(简体) ). 全包提供者/配置符号仍然允许在根上;一个明确的名称空间被自动固定. |
| `no-primereact-dialog` | 取消导入 `Dialog` 从 `primereact/dialog`启用 `CommandDialog` 从 `@cratis/components/CommandDialog`,或 `Dialog` 从 `@cratis/components/Dialogs` ——包装器会添加Arc命令绑定,覆盖/焦点修正,以及主题. |
| `onbeforeexecute-must-return` | 要求数 `onBeforeExecute` 在导入的组件命令对话框/步器或弧上 `CommandForm` 以返回命令值。 它没有标出Arc `CommandScope`,其回电无效. |
| `no-hooks-in-view-model` | Disallows 反应钩子(包括生成的Arc 代理) `.use()`)在取景模型类中. 视图模型必须是普通的,无钩的类,接收被注入抽象. |
| `no-raw-command-form-marker` | 以手写方式取消命令格式字段或列的标识 `displayName` 弦,在任意方向。 使用 `markAsCommandFormField`编号 :`markAsCommandFormColumn` 财务报告和审定财务报表 `isCommandFormField`编号 :`isCommandFormColumn` 从 `@cratis/components/CommandForm` ——它们经过一个标记 一个建筑变换不能重写. |
| `no-react-in-kernel` | Repository 架构规则拒绝 React, React DOM, React Aria 组件,和浏览器 DOM Globals 在显式组件内核目录中. 故意不是消费者的一部分 `recommended` 相会. |

两种导入规则都涵盖静态 `import` 再来..`export … from` 表单。 根条规则还报告 TypeScript `import = require(...)`,动态 `import(...)`,和 通用JS `require(...)` 中; 模棱两可的窗体永远不会自动被固定.

## 安装

插件以相同的版本发布 `@cratis/components`安装组件 4 已绑定到工具列 `>=4 <5` 所以,未来的少校不能突然到达。 永远不要使用 `latest`数字 :

```sh
TOOLING_RANGE='^4.0.0' # Shell-safe equivalent of >=4 <5.

# Choose the application package manager:
npm install --save-dev "@cratis/eslint-plugin-components@$TOOLING_RANGE" \
  @cratis/eslint-config eslint
pnpm add --save-dev "@cratis/eslint-plugin-components@$TOOLING_RANGE" \
  @cratis/eslint-config eslint
yarn add --dev "@cratis/eslint-plugin-components@$TOOLING_RANGE" \
  @cratis/eslint-config eslint
```

## 使用

```js
// eslint.config.mjs
import cratis from '@cratis/eslint-config';
import components from '@cratis/eslint-plugin-components';

export default [
    ...cratis.configs.consumer,
    ...components.configs.recommended,
    // …your project rules
];
```

### 选项

```js
'@cratis/components/no-root-barrel-import': ['error', {
    packageName: '@cratis/components',  // barrel to forbid
    allow: [],                          // exact specifiers to permit wholesale
}],
'@cratis/components/no-primereact-dialog': ['error', {
    source: 'primereact/dialog',        // module to forbid
}],
```

`onbeforeexecute-must-return`, (中文(简体) ), `no-hooks-in-view-model` 财务报告和审定财务报表 `no-raw-command-form-marker` 没有选择.

`no-react-in-kernel` 是一个存储器拥有的架构守护器,不由消费者预设启用. 组件配置为 Canonic 库存 `lib/kernelBoundary.js`; 明示 `kernelPaths` 当测试或将规则应用到另一棵自有树时,可以提供数组.

## 仓库内核边界

`no-react-in-kernel` 只有当所覆盖的文件名是明确宣布的文件名之一时才适用 `kernelPaths`它报告静态进口和再出口、TypeScript进口任务、动态进口、通用JS `require(...)`,包子路径,和浏览器 DOM 全球引用。 盘点外的近出行包名称和文件则被单独搁置. 储存库的决定和包含/排除的确切模块载于 `Documentation/decisions/0003-kernel-boundary.md`。 。 。 .

## 考虑并拒绝:硬码自有标签规则

在第174期本地化传出期间 绕行 `CratisComponentsProvider` 电文(例如a) `title`编号 :`aria-label` 坐在旁边的字符串 已经本地化的道具)被考虑和拒绝. 上面的每个规则都是一个综合的,结构的 格式化 AST 访问者清晰解析( 导入指定符, 已知显示名) ),一个回调控制-流形状。 检测 _自有标签绕行_ 相反,要求 理解一个组件的许多字符串字元中的哪一个是用户化的染色体对 CSS 类 名称, `data-*` 值,装饰性格,或真正正确的每层默认值——语义 判断召唤,不是综合召唤 规则宽到可以抓取一个真正的绕行( 任意字符串字元) 转至 `title`编号 :`aria-label`编号 :`placeholder`/a 资源 `Tooltip`是因为 `content`标记大部分 那些已经正确的呼叫站点 以及一个足够狭窄的许可证 以避免噪音停止 抓取新部件或道具名称被引入的瞬间——许可列表将 需要与未来每个组件同步更新,这不符合鼠标的目的. 发送时间 发送者规格(参见 `Source/Common/for_CratisComponentsProvider/when_every_owned_label_is_overridden.tsx`这是 相反,它们使每个经审计的地表都由一个信息全部齐全的供应商负责 不可混淆的哨兵串 并断言 已转换的标签是哨兵 绝不是英语 默认 —— 一个真实的行为检查, 静态规则如果没有相同的假阳性, 就无法近似 费用。 如果出现较窄的高度信任模式(例如,每一次),则重新检查一条提示规则 自有标签道具遵循一致的命名和JSDoc公约.

## 规则

### `no-root-barrel-import`

4组件从包根中删除了每个组件-家族命名空间. 规则保存从每个组件 3 命名空间到其组件 4 子路径的固定映射,外加原为根的精确设置允许列表:

-   `CratisComponentsProvider`, (中文(简体) ), `useCratisComponentsConfig`, (中文(简体) ), `cratisDefaults`,以及 `mergeCratisComponentsConfig`· ;
-   `CratisComponentsConfig`, (中文(简体) ), `CratisComponentsProviderProps`, (中文(简体) ), `CratisComponentsRouter`,以及 `CratisComponentsMessages`· ;
-   `CratisPaginatorMessages`, (中文(简体) ), `CratisDatePickerMessages`, (中文(简体) ), `CratisDropdownMessages`, (中文(简体) ), `CratisDialogMessages`, (中文(简体) ), `CratisStepperMessages`, (中文(简体) ), `CratisNotificationsMessages`, (中文(简体) ), `CratisDataTableMessages`, (中文(简体) ), `CratisFilterMessages`,以及 `CratisColumnFilterMessages`· ;
-   `CratisComponentsIcons`, (中文(简体) ), `CratisIconResolver`,以及 `useCratisIcon`。 。 。 .

```ts
// ✅ approved setup symbols stay at the root
import { CratisComponentsProvider } from '@cratis/components';

// ❌ a component namespace imported from the root barrel
import { Canvas } from '@cratis/components';

// ✅ the same namespace, imported from its subpath
import * as Canvas from '@cratis/components/Canvas';

// ❌ whole-package forms are ambiguous and reported without an autofix
import Components = require('@cratis/components');
const lazyComponents = await import('@cratis/components');
```

单名空间被自动固定在上述名称空间表上,保留了别名(`Canvas as C`和 `import type` (单位:千美元)`import type { Canvas } from '@cratis/components'` 变成 `import type * as Canvas from '@cratis/components/Canvas'`,并逐一说明 `type` 修饰者同样受到尊重)。 历史 `CommandStepper` 命名空间映射到 `@cratis/components/CommandDialog`,因为这个根命名空间暴露了完整的CommandDialog模块,而不仅仅是更窄的独立的阶梯条目. 混合导入同时命名一个设置符号和一个命名空间被分割——设置符号保留从根导入,命名空间移动:

```ts
// Before
import { CratisComponentsProvider, Canvas } from '@cratis/components';

// After (autofixed)
import { CratisComponentsProvider } from '@cratis/components';
import * as Canvas from '@cratis/components/Canvas';
```

规则从来不会猜测。 每一个都标有指导 **没有** 自动固定 :

-   整个软件包的命名空间导入( E)`import * as Everything from '@cratis/components'`(中文(简体) ) ——每个后进成员所属的子路径不能仅从导入中推断出.
-   默认导入( E)`import Everything from '@cratis/components'`)——包裹没有 默认导出 .
-   仅附带效果的导入( E)`import '@cratis/components'`)——没有强制推断a 子路径从.
-   既非经批准的设置符号, 也非已知名称空间的符号的命名导入 (例如,只有成员存在) _内部_ ——整个 语句未被固定,而不是部分迁移.
-   构成部分3.6 `Compatibility` 名称空间和直接通过出口——报告 由于部件 4 具有 无相容性子路径 .
-   任意 `export … from '@cratis/components'` 再导出命名空间, 删除相容性 导出或未知符号,以及任何复出通配符——标记为同一子路径 引导,但再出口从未自动固定。 再出口核准的设置符号为: 允许.

一个伴奏,独立的代码模块将等同的重写应用到一个整个工程中 通过, 并自动修复一个命名 `export { Canvas } from '@cratis/components'` 再出口方式与它自动修正匹配的导入方式相同——此规则标记每次再出口 以向导为正线,但绝不自动 [`@cratis/components.migrator`](https://www.npmjs.com/package/@cratis/components.migrator)。 。 。 .

### `onbeforeexecute-must-return`

`onBeforeExecute` 打开 `CommandDialog`, (中文(简体) ), `StepperCommandDialog`, (中文(简体) ), `CommandStepper`,和Arc's `CommandForm` 是一个 **变压器**: 它接收当前命令值, 必须 **返回时** (减值或 (没有) 在“组件包”中,不返回任何内容的回调不运行命令 `undefined` ——跑步后卫(`applyBeforeExecute`)返回当前对象并日志 a `console.warn`。Arc的独立 `CommandForm` (22.16.0)直接使用返回值,无 这样的倒背. 因此,现场突变可能依然存在,但一个替换对象被丢弃,呼叫 仍然违反变压器合同。 TypeScript 在完全输入的呼叫站点捕获到此; 这个规则是 JavaScript 和松散的用户的静态后台,所以行为永远不会 依赖倒计时.

```tsx
// ✅ returns the values
<CommandDialog onBeforeExecute={values => { values.id = Guid.create(); return values; }} />
<CommandDialog onBeforeExecute={values => values} />

// ❌ replacement is discarded — the runtime falls back to `values` and warns
<CommandDialog onBeforeExecute={values => { const updated = { ...values, id: Guid.create() }; }} />
// ❌ bare return — same guarded fallback
<CommandDialog onBeforeExecute={values => { return; }} />
```

规则检查 JSX 仅在组件通过从 `@cratis/components/CommandDialog` (单位:千美元)`CommandDialog`, (中文(简体) ), `StepperCommandDialog`, (中文(简体) ), `CommandStepper`, (中文(简体) ), `@cratis/components/CommandStepper` (单位:千美元)`CommandStepper`),或 `@cratis/arc.react/commands` (单位:千美元)`CommandForm`),支持异名和命名空间导入。 未知的组件,对象属性,和独立变量没有被标记,因为无法推断它们的回调合同. 特别是Arc `CommandScope` 有虚空返回 `onBeforeExecute` 副作用钩,不是变压器,所以没有标记。 这个规则并不是一个完整的控制流分析:一个返回一些分支的值但仍能掉入的回调没有被标记.

### `no-hooks-in-view-model`

一个取景模型是平坦的TypeScript——它决不能叫回放钩. `react-hooks/rules-of-hooks` 无法可靠地使用旗下钩子 **类方法**,因此这一规则填补了 克拉蒂斯MVVM取景模型. 输入抽象( I)`IIdentityProvider`, (中文(简体) ), `IMessenger`,查询 而不是叫钩子.

```ts
// ❌ generated Arc proxy hook inside a view model
class AuthorsViewModel {
    load() {
        const [authors] = AllAuthors.use();
    } // flagged
}

// ✅ inject the abstraction; call hooks only in the component
@injectable
class AuthorsViewModel {
    constructor(private readonly identity: IIdentityProvider) {}
}
```

类在通过下列方式登记时被视为一个视图模型: `withViewModel(...)`,装饰 与 `@injectable`,或名称 `*ViewModel`. 两只裸钩(`useState`, (中文(简体) ), `useIdentity`,(......)和 代理成员钩子( e)`.use()`, (中文(简体) ), `.useSuspense()`, (中文(简体) ), `.useChangeStream()`标出标记。 钩子 在一个巢穴中,非视觉模式的阶级不是.

### `no-raw-command-form-marker`

`CommandForm`, (中文(简体) ), `CommandDialog` 财务报告和审定财务报表 `CommandStepper` 决定哪些儿童是田地 检查儿童的成分类型。 从历史上看,测试是单一的字符串 比较 `displayName` - 和 `displayName` 是反应的公开,可写 _诊断_ 名称,用于构建工具的常规目标。 故事书 `reactDocgen: 'react-docgen-typescript'` 设置默认重写它.

重写后,孩子不再被确认为田地: 容器,所以没有标签,没有约束值和更改处理器。 没有错误,没有 警告,每个大门都保持绿色.

帮手们经过一个 `isCommandFormField` 编号 : `isCommandFormColumn` 标记重命名 不接触,同时仍然设置和尊重遗产 `displayName` -所以严格地说 比字面上更宽容 永远不要少. `@cratis/arc.react` 标记和读取相同的两个 属性,而这种共享形状就是将合同贯穿两个包.

```ts
// ❌ a build transform that rewrites displayName silently unbinds this field
MyField.displayName = 'CommandFormField';
if (component.displayName === 'CommandFormField') {
    wrap(component);
}

// ✅ marker first, legacy displayName still set and still honoured
import {
    markAsCommandFormField,
    isCommandFormField,
} from '@cratis/components/CommandForm';

markAsCommandFormField(MyField);
if (isCommandFormField(component)) {
    wrap(component);
}
```

双向:任务(`C.displayName = '…'`,包括计算和 对象-升表)和比较(`===`, (中文(简体) ), `!==`无论是操作命令。 提及 导出 `CommandFormFieldDisplayName` 编号 : `CommandFormColumnDisplayName` 常数不是 所以声明本身 以及任何刻意的遗产密码 都保持干净. 偏爱 `asCommandFormField` 从 `@cratis/arc.react` 它适用于你.

## 常见问题

### @cratis/eslint-plugin-components 是什么？

Cratis 组件 ESLint 规则: 从子路径而不是根桶导入, 使用 Cratis 对话框包, 而不是 primereact/ dialog , 要求在 Execute 调用后返回其值, 保留 resact 钩子退出视图模式, 保护寄存器- ow

### 如何安装 @cratis/eslint-plugin-components？

在项目目录运行 npm install @cratis/eslint-plugin-components，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：eslint（\>=9）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @cratis/eslint-plugin-components 支持 TypeScript 吗？

该包的 package\.json 没有声明类型入口。需要类型提示时，可以在 npm 上查找社区维护的 @types/cratis\_\_eslint-plugin-components 是否存在。

### @cratis/eslint-plugin-components 支持 ESM 还是 CommonJS？

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

### @cratis/eslint-plugin-components 可以商用吗？

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

### @cratis/eslint-plugin-components 的下载量有多少？

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

### @cratis/eslint-plugin-components 还在维护吗？

最新版本 4\.40\.0 发布于 2026/11/04（6 天前）；至今共发布 114 个版本，其中过去 12 个月发布了 114 个；首次发布于 2026/06/05。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

