@foundbyte/eslint-plugin
v1.1.4-alpha.7
Published
ESLint plugin for enforcing code style rules including arrow function padding, Vue script lines limit, and TypeScript type comment requirements
Readme
@foundbyte/eslint-plugin
一个为 FoundByte 项目定制的 ESLint 插件,提供了一系列代码质量检查和最佳实践规则。
安装
npm install @foundbyte/eslint-plugin --save-dev
# 或
yarn add @foundbyte/eslint-plugin --dev
# 或
pnpm add @foundbyte/eslint-plugin --dev使用
在 ESLint 配置文件中添加插件:
// .eslintrc.js
module.exports = {
plugins: ['@foundbyte'],
rules: {
// 启用所有推荐的规则
'@foundbyte/arrow-function-padding': 'error',
'@foundbyte/no-initial-as-assertion': ['error', {
excludeVariableAssertions: true,
excludeTypePatterns: ['^const$', '^[A-Z]$', '^unknown$'],
excludeMethodReturns: ['parse', 'querySelector']
}],
'@foundbyte/hooks-arrow-function-only': 'error',
'@foundbyte/type-comment-requirement': ['error', {
minCommentsPerGroup: 1,
groupSize: 8,
includeTypes: true,
includeInterfaces: true,
}],
'@foundbyte/hooks-export-limit': ['error', { maxExports: 20 }],
'@foundbyte/vue-script-lines-limit': ['error', { maxLines: 300 }],
'@foundbyte/tag-attribute-restriction': ['error', {
restrictions: [
{
tag: 'image',
attributes: [
{ name: 'mode', disallowedValues: [''] },
]
}
]
}],
'@foundbyte/no-restricted-components': ['error', [
{
pattern: '/^a-(textarea|table)$/',
message: '禁止使用的Arco Design组件,请使用Keyblade组件替代'
}
]],
'@foundbyte/no-excessive-any': ['error', { maxAnyCount: 5 }],
'@foundbyte/no-disabled-comments': ['error', {
patterns: [
'/^\\s*eslint-disable-next-line\\s*$/',
'/^\\s*eslint-disable\\s*$/',
'/no-explicit-any/',
'/vue-script-lines-limit/',
'/hooks-export-limit/'
]}]
},
}规则列表与配置示例
no-excessive-any
限制 any 类型的使用次数,包括:
- 显式
any类型 - 隐式
any类型(没有类型注解且无法推导类型的变量) - 泛型类型中的
any(如Ref<any>,Promise<any>,any[]等)
配置示例:
// 基本用法 - 限制 any 类型最多使用 5 次
'@foundbyte/no-excessive-any': ['error', { maxAnyCount: 5 }]
// 严格模式 - 禁止使用 any 类型
'@foundbyte/no-excessive-any': ['error', { maxAnyCount: 0 }]
// 宽松模式 - 允许最多 10 次 any 类型使用
'@foundbyte/no-excessive-any': ['error', { maxAnyCount: 10 }]检测范围:
- 显式
any类型:const a: any = 1 - 隐式
any类型:- 没有初始值的变量声明:
const a - 没有参数的函数调用:
const a = ref()
- 没有初始值的变量声明:
- 泛型类型中的
any:Ref<any>,Promise<any>,Array<any>any[],string | any,T extends any- 类型别名和接口中的
any
智能类型推导: 以下情况不计入 any 使用:
- 有初始值的变量:
const a = 1,const b = ref(60) - 对象字面量:
const obj = { name: 'test' } - 数组字面量:
const arr = [1, 2, 3] - 函数表达式和箭头函数:
const fn = () => {} - 有参数的函数调用:
const a = useRegex(phoneNum, 'phone-number') - 属性访问:
const value = ref.value - 异步函数调用:
const res = await ssoMobileAuth(...)
示例:
// ✅ 正确 - 当 maxAnyCount 为 3 时
const a: any = 1
const b: any = 'hello'
const c = ref() // 隐式 any
// ❌ 错误 - 当 maxAnyCount 为 3 时,第 4 次 any 使用会报错
const a: any = 1
const b: any = 'hello'
const c = ref() // 隐式 any
const d: any = true // 错误:any 类型使用次数不能超过 3 次,当前使用了 4 次
// ✅ 正确 - 使用具体类型
const a: number = 1
const b: string = 'hello'
const c: number = 123
const d: boolean = true
// ✅ 正确 - 可以推导类型的情况不计入 any 使用
const time = ref(60) // 有数字字面量参数,可以推导类型
const messages = { noMore: 'text' } // 对象字面量,可以推导类型
const fn = () => {} // 函数表达式,可以推导类型
const res = await ssoMobileAuth({ nonce: nonce.value }) // 异步函数调用,可以推导类型
// ❌ 错误 - 无法推导类型的隐式 any
const a // 没有初始值
const b = ref() // 没有参数的函数调用
const c: Ref<any> = ref() // 显式 any 类型
// ❌ 错误 - 泛型类型中的 any
type MyType<T = any> = T
interface MyInterface {
value: any
ref: Ref<any>
array: any[]
union: string | any
generic: Promise<any>
}配置选项:
maxAnyCount(number, 默认 0): 允许的any类型最大使用次数- 设置为 0 表示完全禁止使用
any类型 - 设置为正整数表示允许的最大次数
- 设置为 0 表示完全禁止使用
注意:
- 该规则统计文件中所有
any类型的使用,包括显式和隐式 - 规则会智能识别可以类型推导的情况,避免过度检测
- 建议在 TypeScript 项目中设置合理的限制,鼓励使用具体类型
- 对于遗留代码迁移,可以设置较高的限制值,然后逐步减少
no-initial-as-assertion
禁止在初始变量定义时使用 as 类型断言,强制使用显式类型注解。
配置示例:
// 基本用法
'@foundbyte/no-initial-as-assertion': 'error'
// 高级配置 - 排除特定情况
'@foundbyte/no-initial-as-assertion': ['error', {
excludeVariableAssertions: true, // 排除对变量的 as 断言
excludeMethodReturns: ['map', 'parse'] // 排除特定方法返回类型的 as 断言
}]示例:
// ✅ 正确 - 使用显式类型注解
const a: Ref<string> = ref()
const b: ComputedRef<number> = computed(() => {})
const c = ref() // 没有类型断言
const d: Ref<{ a: string }> = ref({}) // 使用显式类型注解
// ❌ 错误 - 在变量声明时使用 as 类型断言
const a = ref() as Ref<string>
const b = computed(() => {}) as ComputedRef<number>
const c = reactive({}) as Reactive<object>
const d = ref({} as { a: string }) // 嵌套的类型断言也会被检测到
// ✅ 当 excludeVariableAssertions 为 true 时 - 变量断言被排除
interface ID { a?: string, b?: string }
const d: ID = {}
const e = d as { a?: string } // 不会报错
// ✅ 当 excludeMethodReturns 包含 'map' 时 - 数组方法返回类型断言被排除
const arr = [1, 2, 3]
const mapped = arr.map(x => x * 2) as number[] // 不会报错
// ✅ 当 excludeMethodReturns 包含 'parse' 时 - JSON.parse 返回类型断言被排除
const jsonString = '{"name": "test"}'
const parsed = JSON.parse(jsonString) as { name: string } // 不会报错配置选项:
excludeVariableAssertions(boolean, 默认 false): 是否排除对变量的 as 断言- 当为 true 时,类似
const a = variable as Type的情况不会被报错 - 适用于变量到变量的类型断言场景
- 当为 true 时,类似
excludeMethodReturns(array, 默认 []): 排除特定方法返回类型的 as 断言- 支持数组方法:
map,filter,reduce等 - 支持全局函数:
JSON.parse等 - 支持链式调用:
arr.map().filter() as Type
- 支持数组方法:
excludeTypePatterns(array, 默认 []): 排除匹配正则表达式模式的类型断言- 支持正则表达式字符串数组
- 用于排除特定的类型断言模式,如
as const - 示例:
['^const$', '^Readonly<.*>$']可以排除as const和as Readonly<...>
注意:
- 该规则检查变量声明时的所有类型断言,包括嵌套在函数调用参数中的类型断言
- 推荐使用显式类型注解,因为类型断言会绕过 TypeScript 的类型检查
- 对于函数调用返回值的类型断言,可以通过配置选项排除特定情况
arrow-function-padding
要求函数体之间必须空行。
配置示例:
'@foundbyte/arrow-function-padding': 'error' // 总是要求空行示例:
// ✅ 正确
const one = () => {}
const two = () => {}
// ❌ 错误
const one = () => {}
const two = () => {}hooks-arrow-function-only
要求 React/Vue Hooks 必须使用箭头函数。
示例:
// ✅ 正确
const useMyHook = () => {
const [state, setState] = useState()
return state
};
// ❌ 错误
function useMyHook() {
const [state, setState] = useState()
return state
}hooks-export-limit
限制 Hooks 文件内部成员的导出数量。
配置示例:
'@foundbyte/hooks-export-limit': ['error', { maxExports: 2 }] // 最大允许的导出数量示例:
// ✅ 正确 - 只有一个导出
export const useMyHook = () => {
const a = ''
return {
a
}
}
// ❌ 错误 - 多个导出
export const useMyHook = () => {
const a = ''
const b = ''
return {
a,
b
}
}type-comment-requirement
要求复杂类型定义必须有类型注释。
配置示例:
'@foundbyte/type-comment-requirement': ['error', {
/** 至少1个注释 */
minCommentsPerGroup: 1,
/** 每3个类型 */
groupSize: 3,
}]示例:
// ✅ 正确 - 有类型注释
interface user {
/** 姓名 */
name: 'John'
/** 年龄 */
age: 30
ddress: { city: 'NY', zip: '10001' }
}
// ❌ 错误 - 复杂对象没有类型注释
interface user { name: 'John', age: 30, address: { city: 'NY', zip: '10001' } }vue-script-lines-limit
限制 Vue 单文件组件中 <script> 标签的行数。
配置示例:
'@foundbyte/vue-script-lines-limit': ['error', { maxLines: 200 }] // 最大允许的行数示例:
<!-- ✅ 正确 - script 标签行数在限制内 -->
<script>
export default {
data() {
return { count: 0 }
},
methods: {
increment() {
this.count++
}
}
}
</script>
<!-- ❌ 错误 - script 标签行数超过限制 -->
<script>
// ... 超过 200 行代码 ...
</script>no-disabled-comments
禁止使用特定的 ESLint 禁用注释,如 eslint-disable、eslint-disable-next-line 等。支持 JavaScript/TypeScript 注释和 Vue 模板中的 HTML 注释。
配置示例:
'@foundbyte/no-disabled-comments': ['error', {
patterns: [
'/^\\s*eslint-disable-next-line\\s*$/', // 匹配 "eslint-disable-next-line"(不加后缀规则)
'/^\\s*eslint-disable\\s*$/', // 匹配 "eslint-disable"
'/no-explicit-any/', // 模糊匹配包含 "no-explicit-any" 的注释
'/vue-script-lines-limit/', // 模糊匹配包含 "vue-script-lines-limit" 的注释
'/hooks-export-limit/' // 模糊匹配包含 "hooks-export-limit" 的注释
]
}]支持的注释类型:
JavaScript/TypeScript 注释:
- 行注释:
// eslint-disable-next-line - 块注释:
/* eslint-disable */
- 行注释:
Vue 模板中的 HTML 注释:
<!-- eslint-disable --><!-- eslint-disable-next-line -->
检测的注释内容:
- 注释内容经过
trim()处理,去除前后空白字符 - 支持正则表达式模糊匹配
- 支持多个模式同时匹配
示例:
// ✅ 正确 - 不匹配任何禁用模式
// 普通注释
/* 另一个普通注释 */
// ❌ 错误 - 匹配 "eslint-disable-next-line" 模式
// eslint-disable-next-line
console.log('test');
// ❌ 错误 - 匹配 "eslint-disable" 模式
/* eslint-disable */
console.log('test');
// ❌ 错误 - 模糊匹配包含 "no-explicit-any" 的注释
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const x: any = 1;
// ❌ 错误 - 模糊匹配包含 "vue-script-lines-limit" 的注释
/* eslint-disable vue-script-lines-limit */<!-- ✅ 正确 - 普通 HTML 注释 -->
<!-- 这是一个普通注释 -->
<!-- ❌ 错误 - 匹配 "eslint-disable" 模式 -->
<!-- eslint-disable -->
<!-- ❌ 错误 - 匹配 "eslint-disable-next-line" 模式 -->
<!-- eslint-disable-next-line -->
<!-- ❌ 错误 - 模糊匹配包含 "no-explicit-any" 的注释 -->
<!-- eslint-disable @typescript-eslint/no-explicit-any -->配置选项:
patterns(array, 必填): 要禁用的注释模式列表- 可以是正则表达式字符串,如
'/^\\s*eslint-disable-next-line\\s*$/' - 可以是普通字符串,会自动转义并创建正则表达式
- 支持多个模式,只要匹配任意一个模式就会报错
- 可以是正则表达式字符串,如
caseSensitive(boolean, 默认 false): 是否区分大小写- 当为 false 时,匹配不区分大小写
- 当为 true 时,匹配区分大小写
错误消息:
禁止使用注释: "eslint-disable-next-line",如必须排除,请在 .eslintignore 中排除,并写清楚排除原因禁止使用注释: "eslint-disable",如必须排除,请在 .eslintignore 中排除,并写清楚排除原因禁止使用注释: "eslint-disable-next-line @typescript-eslint/no-explicit-any",如必须排除,请在 .eslintignore 中排除,并写清楚排除原因
注意:
- 该规则会检查所有 JavaScript/TypeScript 注释和 Vue 模板中的 HTML 注释
- 对于 Vue 文件,规则会同时检查
<script>中的 JavaScript 注释和<template>中的 HTML 注释 - 建议只禁用特定的、有问题的规则,而不是使用无参数的
eslint-disable禁用所有规则 - 如果确实需要排除某些文件,建议使用
.eslintignore文件
no-restricted-components
通过正则表达式配置禁止使用某些组件,支持自定义错误消息。
配置示例:
'@foundbyte/no-restricted-components': ['error', [
{
pattern: '/^a-(textarea|table)$/', // 正则表达式字符串,匹配 a-textarea 和 a-input
message: '禁止使用 a-textarea 和 a-table 组件,请使用自定义组件替代'
},
{
pattern: 'kb-pro-table', // 普通字符串,自动转义为正则表达式
message: '禁止使用 kb-pro-table 组件,请使用其他表格组件'
}
]]支持的语法:
- 正则表达式字符串:以
/开头和结尾,如/^a-(textarea|table)$/ - 普通字符串:自动转义并创建正则表达式,如
'a-textarea' - 支持自闭合标签:
<a-textarea /> - 支持普通标签:
<a-textarea></a-textarea> - 支持带属性的标签:
<a-textarea v-model="value" /> - 只对 .vue 文件生效,不会影响其他文件类型
示例:
<!-- ✅ 正确 - 不匹配任何禁止模式的组件 -->
<div>正常内容</div>
<span>正常内容</span>
<custom-component />
<!-- ❌ 错误 - 匹配 a-textarea 模式 -->
<a-textarea />
<a-textarea></a-textarea>
<!-- ❌ 错误 - 匹配 a-input 模式 -->
<a-input />
<!-- ❌ 错误 - 匹配 kb-pro-table 模式 -->
<kb-pro-table />错误消息:
- 显示配置中指定的自定义消息,如:
禁止使用 a-textarea 和 a-input 组件,请使用自定义组件替代
注意:
- 该规则只检查 .vue 文件中的模板部分,不会检查 JavaScript/TypeScript 代码中的字符串
- 支持同时配置多个禁止模式,每个模式独立检查
- 正则表达式匹配组件名,不区分大小写
- 建议使用具体的组件名模式,避免过度匹配
tag-attribute-restriction
限制特定标签使用某些属性或属性值。
配置示例:
'@foundbyte/tag-attribute-restriction': ['error', {
restrictions: [
{
tag: 'image', // 标签名称
attributes: [ // 属性限制列表
{
name: 'mode', // 属性名称
disallowedValues: [ // 禁止的值列表(可选)
'',
'scaleToFill'
]
},
{
name: 'lazy-load' // 完全禁止该属性
}
]
}
]
}]支持的语法:
- 静态属性:
<image mode="" /> - 动态属性:
<image :mode="'scaleToFill'" /> - 无值属性:
<image lazy-load /> - 连字符属性名:
lazy-load,data-*等 - JSX 属性
示例:
<!-- ✅ 正确 -->
<image src="test.jpg" mode="aspectFit" />
<!-- ❌ 错误 - 禁止使用空字符串的 mode 属性 -->
<image mode="" />
<!-- ❌ 错误 - 禁止使用 scaleToFill 值 -->
<image :mode="'scaleToFill'" />
<!-- ❌ 错误 - 完全禁止 lazy-load 属性 -->
<image lazy-load />错误消息:
标签 <image> 不允许使用属性 mode- 当属性被完全禁止时标签 <image> 的属性 mode 不允许使用值 ""- 当特定属性值被禁止时
