skills/check-test-code-quality/rules/R020/SKILL.md
# R020: .id重复 ## 规则信息 | 属性 | 值 | |------|-----| | 规则编号 | R020 | | 问题类型 | .id重复 | | 严重级别 | Critical | | 规则复杂度 | complex | | 扫描范围 | 同一独立XTS工程内的所有源代码文件(`.ets`, `.ts`, `.js`) | | testcase字段 | `-`(.id()不在it()块内) | ## 问题描述 一个独立XTS工程下的页面设计中,`.id()` 的字符串参数值不允许重复。即同一个独立XTS工程中,所有源代码文件里 `.id('xxx')` 的字符串参数值不能重复。 ## 与R019的关系 R020与R019的扫描逻辑完全一致,唯一差异是检测目标属性。两者共享相同的工程级检测基类(见 [references/project_level_scan.md](../../references/project_level_scan.md)),包括: - `find_independent_projects()` — 工程边界识别 - `get_pr
npx skillsauth add openharmonyinsight/openharmony-skills skills/check-test-code-quality/rules/R020Install this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
| 属性 | 值 |
|------|-----|
| 规则编号 | R020 |
| 问题类型 | .id重复 |
| 严重级别 | Critical |
| 规则复杂度 | complex |
| 扫描范围 | 同一独立XTS工程内的所有源代码文件(.ets, .ts, .js) |
| testcase字段 | -(.id()不在it()块内) |
一个独立XTS工程下的页面设计中,.id() 的字符串参数值不允许重复。即同一个独立XTS工程中,所有源代码文件里 .id('xxx') 的字符串参数值不能重复。
R020与R019的扫描逻辑完全一致,唯一差异是检测目标属性。两者共享相同的工程级检测基类(见 references/project_level_scan.md),包括:
find_independent_projects() — 工程边界识别get_project_source_files() — 递归源文件收集collect_attr_values() — 属性值提取find_duplicate_groups() — 重复检测| 属性 | R019 | R020 |
|------|------|------|
| 检测目标 | .key('xxx') | .id('xxx') |
| 正则 | \.key\s*\(\s*(["\'])([^"\']+)\1\s*\) | \.id\s*\(\s*(["\'])([^"\']+)\1\s*\) |
| 问题描述 | .key重复 | .id重复 |
import re
ID_PATTERN = re.compile(
r'\.id\s*\(\s*(["\'])([^"\']+)\1\s*\)',
re.MULTILINE
)
find_independent_projects(),见 references/project_level_scan.mdos.walk),见 get_project_source_files()collect_attr_values(project_dir, source_files, base_dir, ID_PATTERN)find_duplicate_groups(items)def scan_r020(scan_root, base_dir):
issues = []
projects = find_independent_projects(scan_root)
for project_dir in projects:
source_files = get_project_source_files(project_dir)
if not source_files:
continue
ids = collect_attr_values(project_dir, source_files, base_dir, ID_PATTERN)
duplicates = find_duplicate_groups(ids)
for dup in duplicates:
rel_project = os.path.relpath(project_dir, base_dir)
other_info = '; '.join(dup['other_locations'])
issues.append({
'rule': 'R020',
'type': '.id重复',
'severity': 'Critical',
'file': dup['first_file'],
'line': dup['first_line'],
'testcase': '-',
'snippet': f".id('{dup['value']}')",
'suggestion': (
f"路径: {dup['first_file']}, 行号: {dup['first_line']}, "
f"问题描述: 在独立XTS工程 '{rel_project}' 中,.id值 "
f"'{dup['value']}' 重复 {dup['count']} 次。"
f"重复位置: {other_info}。"
),
})
return issues
确保.id()的值在工程内唯一。修改重复的id值为有意义的唯一标识。
路径: {文件路径}, 行号: {行号}, 问题描述: 在独立XTS工程 '{工程名称}' 中,.id值 '{id值}' 重复 {重复次数} 次。重复位置: {位置1}, {位置2}, ...
// File1: TestAddCustomProperty.ets(同一独立工程内)
Button('Add')
.id('buttonCustomProperty') // 第一次出现
Text('Custom')
.id('customPropertyValue') // 第一次出现
// File2: TestRemoveCustomProperty.ets(同一独立工程内)
Button('Remove')
.id('buttonCustomProperty') // 错误:与File1重复
Text('RemoveCustom')
.id('customPropertyValue') // 错误:与File1重复
// File1: TestAddCustomProperty.ets(同一独立工程内)
Button('Add')
.id('addButtonCustomProperty') // id值唯一
Text('Custom')
.id('addCustomPropertyValue') // id值唯一
// File2: TestRemoveCustomProperty.ets(同一独立工程内)
Button('Remove')
.id('removeButtonCustomProperty') // id值唯一
Text('RemoveCustom')
.id('removeCustomPropertyValue') // id值唯一
与R019完全一致,详见 rules/R019/SKILL.md 的陷阱章节。
| 字段 | 值 |
|------|-----|
| rule | R020 |
| type | .id重复 |
| severity | Critical |
| file | 相对路径 |
| line | .id()所在行号 |
| testcase | - |
| snippet | .id('customPropertyValue') |
| suggestion | 路径: {文件路径}, 行号: {行号}, 问题描述: 在独立XTS工程 '{工程名}' 中,.id值 '{id值}' 重复 {次数} 次。重复位置: {文件:行号}; ... |
testing
--- name: ohos-req-value-decision description: Use after review meeting to record decision and route to next step. Triggers: 评审决策纪要, 评审结论回流, value decision, 评审接纳, 评审不接纳, 评审退回, 下次重新上会. Do NOT use for feature baseline (ohos-req-feature-baseline), review gate checks (ohos-req-review-gate), or IR generation (ohos-req-feature-to-ir). metadata: author: openharmony scope: common stage: requirements capability: value-decision version: 0.3.0 status: draft tags: - sdd - requirements
development
Use when converting an OpenHarmony requirement document, spec, or design proposal into an OpenHarmony review slide deck (需求评审 / 需求变更评审 / 设计评审 PPTX) — produces the fixed OpenHarmony-branded review-deck structure (OH logo on every page) with architecture/flow diagrams and field tables. Triggers on "需求评审PPT", "需求变更评审", "把需求文档转成评审PPT", "spec转评审PPT", "requirement/spec to review deck". NOT for arbitrary or generic slide decks unrelated to OpenHarmony requirement/design review.
testing
Use when performing the Phase 0 Step 0.5 Review Ready Gate on a 04-feature.md, especially when the user says "evaluate gate", "review readiness", "feature ready?", "should we generate IR", or when the ohos-req-intake-orchestration main session needs a structured Ready / Conditional Ready / Not Ready judgment instead of doing the check inline. Reads 01-04, runs seven fixed checks plus a conditional-items check, and returns a machine-readable JSON summary plus a human-readable table that the main session can route on. Do NOT use for feature baseline generation (ohos-req-feature-baseline), value decision recording (ohos-req-value-decision), or IR generation (ohos-req-feature-to-ir).
testing
--- name: ohos-req-requirement-intake description: Use when importing an OHOS requirement into Phase 0.1, especially for 01-requirement.md, requirement intake, background, user value, scenarios, scope, FR/NFR, affected modules, or priority. Triggers: 需求导入, 01-requirement, 需求基线, RR单号. Do NOT use for feasibility analysis (ohos-req-feasibility-analysis), architecture decision (ohos-req-arch-decision), or feature baseline (ohos-req-feature-baseline). metadata: author: openharmony scope: common