iter(g56): ua style 增加单文件 200 行门禁

This commit is contained in:
HIsheR
2026-10-26 12:20:33 +08:00
parent a755758577
commit e6bf801679
4 changed files with 21 additions and 5 deletions
+1 -1
View File
@@ -13,7 +13,7 @@
所有 TS / JS 代码遵循 `CODING.md`:注释一律中文(函数级 `/*** 作用 ***/`、行尾 `// 短注释`),代码紧凑 + 行工整、卫语句单行,高可扩展、低抽象、可读性优先。 所有 TS / JS 代码遵循 `CODING.md`:注释一律中文(函数级 `/*** 作用 ***/`、行尾 `// 短注释`),代码紧凑 + 行工整、卫语句单行,高可扩展、低抽象、可读性优先。
**注释强制门禁**:`npm run style`(即 `ua style`)机器检查——导出必须有 `/*** ***/` 注释、接口字段必须有行尾注释、行注释必须中文;有违规即退出码 1,改完才能提交。 **注释强制门禁**:`npm run style`(即 `ua style`)机器检查——导出必须有 `/*** ***/` 注释、接口字段必须有行尾注释、行注释必须中文,并强制**分层包 src 下单文件 ≤ 200 行**(`types.ts` 与 `index.ts` 作为类型/导出汇总豁免);有违规即退出码 1,改完才能提交。
## 项目结构(权威定义见 ARCHITECTURE.md) ## 项目结构(权威定义见 ARCHITECTURE.md)
+2 -1
View File
@@ -66,4 +66,5 @@ let cached: RowModel | null = null; // memo:缓存产物
## 7. 落地方式 ## 7. 落地方式
- 新代码必须符合本规范;旧代码顺手迁移,不强制一次性全量重写。 - 新代码必须符合本规范;旧代码顺手迁移,不强制一次性全量重写。
- 后续可做成 `ua style` 检查项:导出缺注释、接口字段缺注释、类型散落实现文件、闭包状态未集中顶部。 - 已落地为 `ua style` 检查项:导出缺注释、接口字段缺注释、行注释非中文、分层包 src 内单文件超过 200 行(`types.ts` / `index.ts` 豁免)。
- 仍靠人工守的:类型散落实现文件、闭包状态未集中顶部。
+1 -1
View File
@@ -39,7 +39,7 @@ accordion · alert · autoComplete · avatar · backTop · badge · breadcrumb
## 三道门禁 ## 三道门禁
1. `ua style`:注释规范——导出必须有 `/*** 作用 ***/`、接口字段行尾注释、行注释用中文。 1. `ua style`:注释规范——导出必须有 `/*** 作用 ***/`、接口字段行尾注释、行注释用中文,且分层包 src 内单文件 ≤ 200 行(`types.ts` / `index.ts` 豁免)。
2. `ua verify`:清单 ↔ 文档 ↔ 演示一致(id 唯一、exports 对应、props 带 n/t/d、steps ≥ 3、demo 锚点存在),皮肤样式表禁止 `#hex` 硬编码颜色,`var(--ua-*)` 必须引用 tokens.css 已定义或组件自设的变量。 2. `ua verify`:清单 ↔ 文档 ↔ 演示一致(id 唯一、exports 对应、props 带 n/t/d、steps ≥ 3、demo 锚点存在),皮肤样式表禁止 `#hex` 硬编码颜色,`var(--ua-*)` 必须引用 tokens.css 已定义或组件自设的变量。
3. `ua index`:刷新 `.ua/index.json` / `llms.txt`,供 MCP 与 Agent 查询。 3. `ua index`:刷新 `.ua/index.json` / `llms.txt`,供 MCP 与 Agent 查询。
+17 -2
View File
@@ -639,19 +639,34 @@ function styleCheckFile(file, src) {
return issues; return issues;
} }
/*** 全仓风格检查:有违规退出码 1,全绿输出 OK ***/ // 单文件行数上限:CODING.md「单文件尽量 < 200 行」,只约束包内实现文件
const MAX_LINES = 200;
// 不受行数限制的汇总文件:类型集中文件与导出入口天然会长
const SIZE_EXEMPT = new Set(['types.ts', 'index.ts']);
/*** 行数检查:只查分层包 src 目录下的实现文件,超出上限即违规 ***/
function sizeCheckFile(file) {
const rel = path.relative(ROOT, file).replace(/\\/g, '/');
if (!/^packages\/[^/]+\/[^/]+\/src\//.test(rel)) return []; // 只约束分层包源码
if (SIZE_EXEMPT.has(path.basename(file))) return []; // 类型 / 导出汇总豁免
const lines = fs.readFileSync(file, 'utf8').split(/\r?\n/).length;
return lines > MAX_LINES ? [`${rel} 共 ${lines} 行,超过单文件 ${MAX_LINES} 行上限(CODING.md)`] : [];
}
/*** 全仓风格检查:注释规范 + 单文件行数,有违规退出码 1,全绿输出 OK ***/
function cmdStyle() { function cmdStyle() {
const files = collectSourceFiles(); const files = collectSourceFiles();
const issues = []; const issues = [];
for (const f of files) { for (const f of files) {
issues.push(...styleCheckFile(f, fs.readFileSync(f, 'utf8'))); issues.push(...styleCheckFile(f, fs.readFileSync(f, 'utf8')));
issues.push(...sizeCheckFile(f));
} }
if (issues.length) { if (issues.length) {
for (const it of issues) console.error('style: ' + it); for (const it of issues) console.error('style: ' + it);
console.error(`${issues.length} violation(s)`); console.error(`${issues.length} violation(s)`);
process.exit(1); process.exit(1);
} }
console.log(`style OK (${files.length} files)`); console.log(`style OK (${files.length} files, 实现文件 ≤ ${MAX_LINES} 行)`);
} }
/*** 皮肤包硬编码颜色检查:#hex 字面量一律禁止,颜色必须走 --ua-* 令牌(rgba 仅限阴影/遮罩的透明度叠加) ***/ /*** 皮肤包硬编码颜色检查:#hex 字面量一律禁止,颜色必须走 --ua-* 令牌(rgba 仅限阴影/遮罩的透明度叠加) ***/