1
0
Files
nex/frontend/eslint-rules/rules/no-hardcoded-color-in-style.js
lanyuanxiaoyao 52007c9461 feat: 前端 ESLint 规则增强,自动检测 LLM 编码违规
- 启用 TanStack Query flat/recommended(7 条规则)
- 新增 no-console(允许 warn/error)、consistent-type-imports(inline 风格)、no-non-null-assertion 规则
- 新增自定义规则 no-hardcoded-color-in-style,检测 JSX style 中硬编码颜色值
- 将 ESLint 检查集成到 build 命令(tsc -b && eslint . && vite build)
- 修复现有代码中的 lint 违规(import 顺序、type import 风格、unused vars)
- 使用 @typescript-eslint/rule-tester 编写自定义规则集成测试
2026-04-23 22:47:32 +08:00

112 lines
2.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { ESLintUtils } from '@typescript-eslint/utils'
const RE_HEX3 = /^#[0-9a-fA-F]{3}$/
const RE_HEX6 = /^#[0-9a-fA-F]{6}$/
const RE_HEX8 = /^#[0-9a-fA-F]{8}$/
const RE_RGB = /^rgb\s*\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)$/
const RE_RGBA = /^rgba\s*\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*[\d.]+\s*\)$/
const RE_HSL = /^hsl\s*\(\s*\d+\s*,\s*[\d.]+%?\s*,\s*[\d.]+%?\s*\)$/
const ALLOWED_KEYWORDS = new Set([
'inherit',
'transparent',
'currentColor',
'none',
'unset',
'initial',
'auto',
'contain',
'cover',
])
function isHardcodedColor(value) {
if (typeof value !== 'string') return false
const trimmed = value.trim()
if (ALLOWED_KEYWORDS.has(trimmed.toLowerCase())) return false
if (trimmed.startsWith('var(')) return false
if (/^\d+(\.\d+)?px?$/.test(trimmed)) return false
if (/^\d+(\.\d+)?\%$/.test(trimmed)) return false
return (
RE_HEX3.test(trimmed) ||
RE_HEX6.test(trimmed) ||
RE_HEX8.test(trimmed) ||
RE_RGB.test(trimmed) ||
RE_RGBA.test(trimmed) ||
RE_HSL.test(trimmed)
)
}
function extractStyleProperties(expression) {
const properties = []
if (
expression.type === 'ObjectExpression' &&
expression.properties
) {
for (const styleProp of expression.properties) {
if (
styleProp.type === 'Property' &&
styleProp.key?.type === 'Identifier' &&
styleProp.value?.type === 'Literal' &&
typeof styleProp.value.value === 'string'
) {
properties.push({
key: styleProp.key.name,
value: styleProp.value.value,
loc: styleProp.value.loc,
})
}
}
}
return properties
}
export const RULE_NAME = 'no-hardcoded-color-in-style'
export default ESLintUtils.RuleCreator((name) => {
return `https://eslint.dev/rules/#${name}`
})({
name: 'no-hardcoded-color-in-style',
meta: {
type: 'problem',
docs: {
description: 'Disallow hardcoded color values in JSX style properties',
recommended: false,
},
messages: {
hardcodedColor:
'硬编码的颜色值 "{{value}}" 不允许使用。请使用 TDesign CSS Token如 var(--td-text-color-placeholder))代替。',
},
schema: [],
},
create(context) {
return {
JSXAttribute(node) {
if (
node.name?.type === 'JSXIdentifier' &&
node.name.name === 'style' &&
node.value?.type === 'JSXExpressionContainer' &&
node.value.expression
) {
const styleProps = extractStyleProperties(
node.value.expression,
)
for (const prop of styleProps) {
if (isHardcodedColor(prop.value)) {
context.report({
node: context.sourceCode.getLastToken(node),
messageId: 'hardcodedColor',
data: { value: prop.value },
})
}
}
}
},
}
},
})