@cratis/eslint-plugin 组件
ESLint规则用于消费克拉蒂斯组件的项目. 在上面写这些
克拉蒂斯基础配置, @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数字 :
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
使用
// 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
];
选项
'@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。 。 。 .
// ✅ 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模块,而不仅仅是更窄的独立的阶梯条目. 混合导入同时命名一个设置符号和一个命名空间被分割——设置符号保留从根导入,命名空间移动:
// 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。 。 。 .
onbeforeexecute-must-return
onBeforeExecute 打开 CommandDialog, (中文(简体) ), StepperCommandDialog, (中文(简体) ), CommandStepper,和Arc's
CommandForm 是一个 变压器: 它接收当前命令值, 必须 返回时 (减值或
(没有) 在“组件包”中,不返回任何内容的回调不运行命令
undefined ——跑步后卫(applyBeforeExecute)返回当前对象并日志 a
console.warn。Arc的独立 CommandForm (22.16.0)直接使用返回值,无
这样的倒背.
因此,现场突变可能依然存在,但一个替换对象被丢弃,呼叫
仍然违反变压器合同。 TypeScript 在完全输入的呼叫站点捕获到此;
这个规则是 JavaScript 和松散的用户的静态后台,所以行为永远不会
依赖倒计时.
// ✅ 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,查询
而不是叫钩子.
// ❌ 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 标记和读取相同的两个
属性,而这种共享形状就是将合同贯穿两个包.
// ❌ 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 它适用于你.