@fohte/slint-配置
有TypeScript支持的个人ESLint配置包.
安装
npm install --save-dev @fohte/eslint-config
# Install peer dependencies
npm install --save-dev @eslint-community/eslint-plugin-eslint-comments @typescript-eslint/eslint-plugin @typescript-eslint/parser @vitest/eslint-plugin eslint eslint-config-prettier eslint-plugin-import-x eslint-plugin-simple-import-sort
# Optional: If using TypeScript
npm install --save-dev typescript
# Optional: If using the errorHandling option
npm install --save-dev @ninoseki/eslint-plugin-neverthrow
npm install neverthrow
# Optional: If using the tailwind option
npm install --save-dev eslint-plugin-tailwindcss
npm install tailwindcss
# Optional: If using the shadcn option
npm install --save-dev @shadcn/lint
使用量
eslint.config.js数字 :
import { config } from '@fohte/eslint-config'
// Basic (JS + TypeScript strict rules)
export default config()
// Alternatively, enable type-checked rules
// (strict-type-checked + strict-boolean-expressions):
// export default config({ typescript: { typeChecked: true } })
// Optionally, ban throw/try-catch and enforce neverthrow Result handling
// (requires typescript.typeChecked: true):
// export default config({
// typescript: { typeChecked: true },
// errorHandling: {},
// })
// Optionally, ban raw tracer.startSpan()/startActiveSpan() calls that skip context.with():
// export default config({ opentelemetry: { enabled: true } })
// Optionally, ban Tailwind CSS arbitrary values (e.g. `w-[600px]`),
// steering towards design tokens defined in `@theme` instead:
// export default config({
// tailwind: { cssConfigPath: 'src/index.css' },
// })
// Optionally, enforce shared component styling rules in selected files:
// export default config({
// shadcn: { files: ['src/**/*.{jsx,tsx}'] },
// })
// Optionally, ban raw form and button elements in selected files:
// export default config({
// noRawFormElements: {
// files: ['app/src/**/*.tsx'],
// ignores: ['app/src/components/ui/**'],
// },
// })
进口政策
config() 禁止相对进口./foo, (中文(简体) ), ../foo)和 @/* 别名通过 no-restricted-imports,并引导两者走向 节点子路径导入 (单位:千美元)#foo,在 imports 输入 package.json) (中文(简体) ). 这个 @/* 化名只解析 TypeScript/ bundler 级别,所以一个平地节点/tsx 不分享分辨率步骤的运行时间在运行时间失败; # 进口由Node自己的模块解析器自行解决,因此这种失败模式不可能发生.
选择退出(例如,不使用 src/ ,在后缀中覆盖规则 userConfigs 引用到 config()数字 :
export default config(
{},
{
rules: {
'no-restricted-imports': 'off',
},
},
)
errorHandling 选项
要求数 typescript.typeChecked: true,因为 neverthrow/must-use-result 需要类型信息以检测未使用 Result 数值.
启用时, 它对所有人适用两个规则 .ts{,x} 除测试文件外的文件 :
-
no-restricted-syntax: 禁令throw财务报告和审定财务报表try编号 :catch返回 aResult通过err()编号 :errAsync()相反,或使用ResultAsync.fromPromise()与丢弃的 API 互通,而无需本地throw如果外部SDK的以抛出为基础的合同真的不能这样包起来,则添加一个eslint-disable-next-line解释为什么:// eslint-disable-next-line no-restricted-syntax -- interops with an external SDK's throw-based contract try { return externalSdkCall() } catch (error) { return err(error) } -
neverthrow/must-use-result: 禁止抛弃aneverthrowResult编号 :ResultAsync不处理它.
opentelemetry 选项
当启用时, no-restricted-syntax 禁止直接呼叫 tracer.startSpan()编号 :tracer.startActiveSpan() 总计 .ts{,x} 文件,因为两者都能够默默地产生一个无法在孩子执行过程中创建的父跨:
startSpan()绝不单独进入主动语境——孩子的间距(例如在这个间距内发射的HTTP呼叫)将不会被嵌入其中,除非呼叫者明确将周围的代码包裹在其中context.with(trace.setSpan(context.active(), span), ...)。 。 。 .startActiveSpan()'回调在活动上下文中自动运行,但只用于回调的自身持续时间——将跨度存储到end()它后来(例如开始和结束在单独的回调中分拆)从活性上下文中从后期代码运行之前放弃.
这只显示为微量后端中错误的出错跨度,而不是运行时出错. 如果两者都不匹配,则添加一个 eslint-disable-next-line 解释原因.
与 errorHandling,两个选项都配置 no-restricted-syntax ——ESLint的平面配置完全取代了规则的设置(而不是将其合并),当两个配置对象为同一个文件设置了相同的规则时,所以 startSpan编号 :startActiveSpan 选择器合并为 errorHandling是因为 no-restricted-syntax 输入而不是他们自己的配置。 这意味着 opentelemetry 禁用然后共享 errorHandling对测试文件的豁免.
tailwind 选项
cssConfigPath (Tailwind的 CSS 文件路径) @theme (a) 需要指示牌); files 默认为全部 .ts{,x} 文件,但可以缩小(例如单列波中的单个软件包):
export default config({
tailwind: {
files: ['web/**/*.ts', 'web/**/*.tsx'], // optional, defaults to all .ts{,x} files
cssConfigPath: 'web/src/index.css',
},
})
启用时, 它对给定的规则 files (测试文件除外):
-
tailwindcss/no-arbitrary-value:禁止任意值(例如:.w-[600px](单位:千美元)className编号 :class属性和类名称函数( c)clsx, (中文(简体) ),cn(见E/CN.4/Sub.2/2002/L.48等)。 向@theme在您的 CSS 配置中 :@theme { --width-panel: 600px; }- <div className="w-[600px]" /> + <div className="w-panel" /> -
no-restricted-syntax数字 :no-arbitrary-value只检查类属性/功能,所以隐藏在空字符串常数中的括号值(然后插入)className)否则会滑出未被发现. 这个规则也抓住了那个案子.
喜欢 opentelemetry,这个共享其 no-restricted-syntax 条目 errorHandling (和 opentelemetry)而不是悄悄地压倒它,因此所有这三项禁令都在内部共同适用 tailwind.files。自 tailwind.files 范围可以小于 errorHandling编号 :opentelemetry默认( 全部) .ts{,x} 文件,合并发生于 tailwind.files范围: 它外的文件只保留 errorHandling编号 :opentelemetry 禁止 里面的档案可以完全结合.
noRawFormElements 选项
设定 files 以禁止原始 JSX 格式和按钮元素的文档。 测试文件被自动排除; 使用 ignores 用于额外排除,例如共享的UI组件:
export default config({
noRawFormElements: {
files: ['app/src/**/*.tsx'],
ignores: ['app/src/components/ui/**'],
},
})
这样可以 fohte/no-raw-form-elements,哪个标记小写 <button>, (中文(简体) ), <input>, (中文(简体) ), <select>,以及 <textarea> 元素,并要求您使用共享的 UI 组件. <a> 组件和资本化组件不受影响.
shadcn 选项
安装 @shadcn/lint 0.1.2或以后选择加入。 选择所支持的源文件 files; 测试文件自动排除,以及 ignores 还可增加更多的除外情形:
export default config({
shadcn: { files: ['src/**/*.{jsx,tsx}'] },
})
这样可以 shadcn/no-restyle, (中文(简体) ), shadcn/no-inline-styles, (中文(简体) ), shadcn/require-static-classes, (中文(简体) ), shadcn/no-unknown-classes,以及 shadcn/no-raw-colors 作为错误. no-restyle 确认从 @fohte/ui 及其子路径,同时允许布局类。 添加线索 userConfigs 条目以覆盖或禁用单个规则。 例如, 禁用 no-restyle 在保存其他规则的同时,允许:
export default config(
{ shadcn: { files: ['src/**/*.{jsx,tsx}'] } },
{
files: ['src/components/ui/**'],
rules: { 'shadcn/no-restyle': 'off' },
},
)
内部规则
除了上游预设外,这个配置船还装有本地插件(fohte) 用于测试文件和故事书故事文件,并选择用于选择由 noRawFormElements。由内建预设启用的规则设定为 error;需要明确选项或用户配置的规则如下文所记载.
fohte/require-story-name 被注册为 Storybook 故事文件,但默认关闭。 启用后缀 userConfigs 条目 :
export default config(
{},
{
files: ['**/*.stories.tsx'],
rules: { 'fohte/require-story-name': 'error' },
},
)
-
fohte/no-inline-object-in-expect(测试文件):旗帜expect(<object/array literal>).toEqual(...)(和toStrictEqual编号 :toMatchObject,包括:await … .resolves编号 :.rejects编号 :.not链条,以及as const编号 :satisfies编号 :!被包裹的文字)。 并标出同一字面别名,通过一个在expect()电话 直接传递测试中的值, 或将断言分为多个expect()打电话.// bad expect({ result, calls: spy.mock.calls.length }).toEqual({ result: 'ok', calls: 0, }) // bad: aliasing the literal through a variable doesn't escape the rule const actual = { result, calls: spy.mock.calls.length } expect(actual).toEqual({ result: 'ok', calls: 0 }) // good expect(result).toBe('ok') expect(spy).not.toHaveBeenCalled() -
fohte/no-raw-form-elements(当noRawFormElements已配置 : 标记小写 JSX<button>, (中文(简体) ),<input>, (中文(简体) ),<select>,以及<textarea>要素。 使用共享的 UI 组件代替 . -
fohte/no-play-in-stories(故事文件):旗帜 aplay函数和parameters: { screenshot: { skip: true } }用于描述一个故事或其元a(默认导出)。 故事应该通过args编号 :render; 移动行为断言(单击、输入、,expect电话).test.tsx,使状态成为play函数用于通过道具设置(例如打开菜单)取而代之(例如.defaultOpen) (中文(简体) ). 这也针对一个"故事书"VRT设置,在同一个文件中标出两个故事,其截图为字节-同义(通常是一个未被检测到的视觉错误,例如两个状态进行相同的渲染):一个被跳过的故事没有显示截图,这样检查就永远看不到. 由于故事不能定义play每一个故事的唯一说法就是它的外表 所以screenshot.skip总是隐藏着这个发现——解决潜在的视觉重复而不是跳过.// bad: play belongs in a .test.tsx file, not the story export const Disabled: Story = { args: { disabled: true }, play: async ({ canvasElement }) => { await expect(within(canvasElement).getByRole('checkbox')).toBeDisabled() }, } // good: the state play used to set up is driven by a prop instead export const Disabled: Story = { args: { disabled: true }, } -
fohte/require-story-name(故事文件,默认关闭):需要每个导出的对象故事定义自己的name属性。 它尊重文字字符串和正则表达式过滤器includeStories财务报告和审定财务报表excludeStories。如果任一过滤器是动态的,则规则会跳过该文件,因为它无法确定导出什么故事本.
发展
设置
# Install dependencies
npm install
# Build TypeScript
npm run build
# Watch mode
npm run watch
脚本
npm run build- 编译类型脚本文件npm run watch- 发展观察模式npm run lint- 在源文件中运行 ESLintnpm run test- 运行建设和涂抹
项目结构
src/
├── index.ts # Main export
├── main.ts # Base ESLint configuration
├── typescript.ts # TypeScript-specific configuration
├── error-handling.ts # errorHandling option (throw/try-catch ban, neverthrow enforcement)
├── opentelemetry.ts # opentelemetry option (startSpan/startActiveSpan ban)
├── no-raw-form-elements.ts # noRawFormElements option (raw JSX element ban)
├── tailwind.ts # tailwind option (Tailwind arbitrary-value ban)
├── shadcn.ts # shadcn option (shared component style rules)
└── types/ # Type definitions for untyped packages
释放进程
这个项目使用 请放行 自动发布.
1. 创建特征分支并作出修改
- 从
master - 更改( 承诺信件不需要遵循任何特定格式)
2. 创建 PR并合并为主
- 推动您的分支并创建 PR
- 公关标题必须遵循 常规武器委员会数字 :
fix:用于错误修正( patch 释放)feat:新特性(小于发布)feat!:或者说fix!:用于分解更改(主要发布)
- 审查后, 合并 PR( 只有平面合并)
3. 自动释放程序
当更改合并为 master,请自动释放:
- 创建/更新释放 PR
- 更新软件包中的版本。 json
- 更新变换
- 当发布 PR 合并时 :
- 创建 GitHub 发布和 git 标签
- 发布到 npm
承诺前虎克
这个项目使用承诺前钩来保证代码质量. 当您执行更改时, 钩会自动运行 .