Primitive + Semantic 双层令牌架构,HEX->HSL,明暗双份,@theme inline 暴露为 Tailwind 类。 - 新建 src/app/styles/tokens/ 6 个令牌文件(primitive/semantic-light/semantic-dark/lesson-preparation/tailwind-theme/index) - globals.css 改为 @import 引入,477->258 行 - 清理 91 处 #hex 硬编码颜色 -> hsl(var(--*)) - 清理 10 处硬编码字体 -> var(--font-family-*) - 清理 100 文件 Tailwind 任意值(Tier 1 映射/Tier 3 注释豁免) - 清理 M3 Surface 死代码,升级 --lp-* 令牌(HEX->HSL + 暗色补全) - 新建 ESLint 自定义规则 no-hardcoded-design-tokens(单词边界正则) - eslint.config.mjs 新增 no-restricted-syntax 禁止 #hex + 自定义规则加载(pathToFileURL) - 项目规则新增设计令牌规范强制章节 - 架构图 004/005 同步设计令牌体系节点 - known-issues.md 追加设计令牌问题分类(7 个规则表) 验证: tsc --noEmit 0 errors, npm run lint 0 errors/12 warnings(均为既有问题)
84 lines
2.3 KiB
JavaScript
84 lines
2.3 KiB
JavaScript
import { defineConfig, globalIgnores } from "eslint/config";
|
|
import nextVitals from "eslint-config-next/core-web-vitals";
|
|
import nextTs from "eslint-config-next/typescript";
|
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
import { dirname, join } from "node:path";
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
|
const eslintConfig = defineConfig([
|
|
...nextVitals,
|
|
...nextTs,
|
|
{
|
|
rules: {
|
|
"react-hooks/incompatible-library": "off",
|
|
"@typescript-eslint/no-unused-vars": [
|
|
"warn",
|
|
{
|
|
argsIgnorePattern: "^_",
|
|
varsIgnorePattern: "^_",
|
|
caughtErrorsIgnorePattern: "^_",
|
|
},
|
|
],
|
|
// 禁止硬编码 hex 颜色字面量(白名单:tokens 定义文件、邮件、manifest)
|
|
// 白名单文件内的 #hex 需在所在行上方加 // eslint-disable-next-line no-restricted-syntax 注释豁免
|
|
"no-restricted-syntax": [
|
|
"error",
|
|
{
|
|
selector: "Literal[value=/#[0-9a-fA-F]{3,8}/]",
|
|
message:
|
|
"禁止硬编码 hex 颜色,使用设计令牌 hsl(var(--*)) 或 Tailwind 类 bg-*",
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
files: ["tests/**/*.ts"],
|
|
languageOptions: {
|
|
globals: {
|
|
describe: "readonly",
|
|
it: "readonly",
|
|
test: "readonly",
|
|
expect: "readonly",
|
|
beforeAll: "readonly",
|
|
afterAll: "readonly",
|
|
beforeEach: "readonly",
|
|
afterEach: "readonly",
|
|
vi: "readonly",
|
|
},
|
|
},
|
|
},
|
|
// 自定义规则:检测硬编码字体家族字面量
|
|
{
|
|
plugins: {
|
|
"design-tokens": {
|
|
rules: {
|
|
"no-hardcoded-fonts": await import(
|
|
pathToFileURL(join(__dirname, "eslint-rules/no-hardcoded-design-tokens.js")).href
|
|
).then((m) => m.default ?? m),
|
|
},
|
|
},
|
|
},
|
|
rules: {
|
|
"design-tokens/no-hardcoded-fonts": "error",
|
|
},
|
|
},
|
|
// Override default ignores of eslint-config-next.
|
|
globalIgnores([
|
|
// Default ignores of eslint-config-next:
|
|
".next/**",
|
|
"out/**",
|
|
"build/**",
|
|
"next-env.d.ts",
|
|
"docs/scripts/**",
|
|
"playwright-report/**",
|
|
"test-results/**",
|
|
// Debug scripts using CommonJS
|
|
"tests/webapp/debug_drizzle.js",
|
|
// Migration/maintenance scripts using CommonJS require()
|
|
"scripts/**/*.js",
|
|
]),
|
|
]);
|
|
|
|
export default eslintConfig;
|