HarmonyOS 7 / API 26 Code Linter 落地实战:规则分级、误报白名单和 CI 阻断一次验清
Code Linter 不是为了让代码看起来整齐,而是为了把低级问题提前挡在提交前。HarmonyOS 7 / API 26 工程如果多人协作,靠人工 review 去发现空判断、异步未处理、无意义状态更新、调试日志残留,效率很低,也容易漏。
这篇按工程落地来讲:规则怎么分级,误报怎么处理,提交前怎么检查,CI 怎么阻断,最后怎么让修复结果能回归。
版本和执行位置
| 项目 | 说明 |
| 工程目标 | HarmonyOS 7 / API 26 |
| 检查对象 | ArkTS、配置文件、工程脚本 |
| 执行位置 | 本地提交前、CI 构建前、合并前 |
| 结果要求 | 错误阻断,警告记录,误报可追踪 |
Linter 如果只在开发者本地跑,很容易有人漏跑。真正稳定的做法是本地快检加 CI 强制检查。
规则先分级
不要一上来把所有规则都设成阻断。否则误报多了,团队会绕开它。
~~~ts
type RuleLevel = 'error' | 'warn' | 'off'
type LintRule = {
name: string
level: RuleLevel
reason: string
}
const rules: LintRule[] = [
{ name: 'no-floating-promise', level: 'error', reason: '异步结果未处理会造成状态不可控' },
{ name: 'no-debug-log-in-release', level: 'error', reason: 'release 包不能残留调试日志' },
{ name: 'prefer-stable-key', level: 'warn', reason: '列表 key 不稳定容易造成状态错位' },
{ name: 'max-function-lines', level: 'warn', reason: '过长函数需要拆分,但不直接阻断' }
]
~~~
我的原则是:会造成线上风险的规则设 error;影响可维护性的先设 warn。等团队适应后,再逐步提高要求。
案例一:异步任务没有处理失败
下面这种写法很常见:
~~~ts
function onPageShow(): void {
loadRemoteConfig()
refreshList()
}
~~~
看起来没问题,但这两个异步任务如果失败,页面不知道;如果返回太晚,还可能覆盖新状态。Linter 至少要把未处理 Promise 拦出来。
~~~ts
function onPageShowBetter(): void {
void loadRemoteConfig().catch(error => {
console.error('[config]', String(error))
})
void refreshListSafely()
}
async function refreshListSafely(): Promise<void> {
try {
const rows = await requestRows()
applyRows(rows)
} catch (error) {
showListError(String(error))
}
}
~~~
这里不是要求所有异步都 await,而是要求每个异步都有明确去向:等待、捕获、忽略但说明原因。
案例二:release 包残留调试日志
调试日志在开发阶段有用,但 release 包里大量 console 会影响排查,也可能泄露内部信息。
~~~ts
type LintIssue = {
file: string
line: number
rule: string
level: RuleLevel
message: string
}
function checkDebugLog(file: string, content: string): LintIssue[] {
return content.split('
').flatMap((line, index) => {
if (line.includes('console.log(')) {
return [{
file,
line: index + 1,
rule: 'no-debug-log-in-release',
level: 'error',
message: 'release 代码不要保留 console.log'
}]
}
return []
})
}
~~~
实际项目可以接成熟 linter,这里写简化版本只是为了说明规则结果要结构化。结构化以后,CI 才能稳定判断是否阻断。
误报白名单要可追踪
没有白名单,误报会拖慢开发;白名单太随意,又会把门禁掏空。所以我会给白名单加原因和过期时间。
~~~ts
type LintIgnore = {
rule: string
file: string
reason: string
expireAt: string
}
function isIgnored(issue: LintIssue, ignores: LintIgnore[]): boolean {
const today = '2026-08-05'
return ignores.some(item => {
return item.rule === issue.rule &&
item.file === issue.file &&
item.expireAt >= today
})
}
~~~
白名单不是永久免死牌。过期后还要重新评估,不然规则会慢慢失效。
CI 阻断逻辑
CI 只需要一个清楚的判断:有没有 error 级问题。
~~~ts
function assertLintPassed(issues: LintIssue[], ignores: LintIgnore[]): void {
const activeIssues = issues.filter(issue => !isIgnored(issue, ignores))
const errors = activeIssues.filter(issue => issue.level === 'error')
for (const issue of activeIssues) {
console.info('[lint-issue]', issue.level, issue.rule, issue.file + ':' + issue.line, issue.message)
}
if (errors.length > 0) {
throw new Error('lint failed with ' + errors.length + ' error(s)')
}
}
~~~
warn 可以输出报告,但不阻断;error 必须失败。这个边界要固定,否则每次 CI 失败都要靠人解释。
本地验证脚本
先用两段代码模拟检查结果。
~~~ts
function verifyLintGate(): void {
const content = [
'function test() {',
' console.log("debug")',
' loadRemoteConfig()',
'}'
].join('
')
const issues = checkDebugLog('src/main/ets/pages/Index.ets', content)
const ignores: LintIgnore[] = []
assertLintPassed(issues, ignores)
}
~~~
预期结果是 CI 阻断,因为 release 代码里出现 console.log。再加一条未过期白名单,可以验证误报放行逻辑是否生效。
~~~ts
function verifyIgnore(): void {
const issue: LintIssue = {
file: 'src/main/ets/pages/DebugOnly.ets',
line: 10,
rule: 'no-debug-log-in-release',
level: 'error',
message: 'temporary debug page'
}
const ignores: LintIgnore[] = [{
rule: 'no-debug-log-in-release',
file: 'src/main/ets/pages/DebugOnly.ets',
reason: 'only used in internal debug build',
expireAt: '2026-08-30'
}]
console.info('[verify-ignore]', isIgnored(issue, ignores))
}
~~~
落地清单
| 检查项 | 通过标准 |
| 规则分级 | error/warn/off 有明确原因 |
| 异步处理 | 未处理 Promise 不能进主干 |
| release 日志 | console.log 等调试输出被阻断 |
| 白名单 | 有原因、有过期时间 |
| CI 输出 | 能定位到文件、行号、规则名 |
| 回归 | 本地脚本能复现阻断和放行 |
小结
HarmonyOS 7 / API 26 工程接 Code Linter,重点不是把规则一次开满,而是把质量门禁落稳。先分级,再处理误报,再把 error 级问题放进 CI 阻断。这样 review 不用反复纠结低级问题,团队也能把精力放到真正的架构和业务风险上。