fix(lint): translation-target-unknown 读取视图容器的默认 form.sections (#5415) - #5422
Merged
Merged
Conversation
…ult `form.sections` (#5415) `collectViewRecord` derived an object's legal `_sections` names from `fieldGroups[].key`, the named sections on `listViews.*` / `formViews.*`, a page's named `record:details` sections, and the view record's own `sections`. The view CONTAINER's default `form` — what `defineView({ list, form })` declares and `ObjectForm` renders when no named form view is asked for — was in none of those, so `view.form.sections[].name` contributed nothing: a bundle correctly translating a heading that DOES render was reported as keyed to a section "nothing declares", with a hint advising the author to delete it. The default form now feeds the same section collector as `formViews.*`, bound by `bindingOf(view.form) ?? listBinding` — the resolution the CLI i18n walker performs on `view.form.data.object` — so the rule that demands a key and the rule that accepts one agree on which object a heading belongs to. Every anchor is now a call into one collector instead of its own copy of the loop. Tests import the real showcase contact metadata (`Contact` +`ContactViews`): its object declares `field.group` and no `fieldGroups[]`, so the default form is its ONLY section anchor, which is exactly what a hand-reduced fixture could not have pinned. Over-widening controls kept: an unnamed section is still untranslatable, an undeclared key is still reported, and the default form is bound by its own `data`, not by the list beside it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh
…t-container-form-sections
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 3 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh
This was referenced Aug 5, 2026
baozhoutao
marked this pull request as ready for review
August 5, 2026 11:08
baozhoutao
enabled auto-merge
August 5, 2026 11:08
This was referenced Aug 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #5415
前提复核(改之前先证伪)
按正文在
origin/main(切 worktree 时9fad07f66,issue 钉的是b4872a868,两者之间未触packages/lint)重跑了 showcase 复现:直接 import 真实的examples/app-showcase/src/ui/views/contact.view.ts,把正确翻译showcase_contact._sections.contact的 bundle 喂给validateTranslationReferences,输出与 issue 正文逐字一致:前提成立。
改了什么
collectViewRecord原本从四个锚点收集对象的合法_sections名:fieldGroups[].key、listViews.*/formViews.*的具名段落、页面record:details的具名段落、以及视图记录自身的sections。容器的默认form(defineView({ list, form, formViews })里那个、没有指定具名表单视图时ObjectForm渲染的那个)哪一条都不是 —— 循环写死['listViews', 'formViews'],而它既不在其中、也不是记录自身的sections,于是view.form.sections[].name对事实集零贡献。现在默认
form走与formViews.*完全相同的段落收集路径,绑定取bindingOf(view.form) ?? listBinding—— 即先form.data.object、再记录级对象、最后旁边那个 list 的绑定 —— 与 CLI i18n walker 的viewObjectName对view.form.data.object的解析对齐。这正是 #5405 要建立的集合关系(覆盖走查器要求的 key ⊆ 引用校验器接受的 key)在 lint 侧的那一半。顺带把四处段落收集收敛成一个
addSections收集器:锚点清单从此是「一串调用点」,而不是四份会各自漂移的循环副本。没有任何收紧:无名段落依旧不可翻译(它没有可查的稳定 key),任何锚点都没声明的
_sectionskey 依旧上报 —— 只是 hint 现在会列出真实存在的锚点,而不再断言「declares no named section at all」。未触
_views族(#5164 领地),未触packages/lint/src/index.ts(PR #5416 在队列中触该文件)。测试
packages/lint/src/validate-translation-references.test.ts新增 4 例:form的具名段落可解析(合成最小形状)。form按自己的data绑定,而不是旁边的 list —— 一个 stack 里同时断言两个方向。只断言「crm_lead仍被上报」是不可证伪的:在修复前它同样通过,因为默认 form 什么都没贡献(空集合让断言"通过"的经典陷阱);是crm_contact那一半让这一对有了方向。import { Contact }+import { ContactViews })。选真实 import 而不是手工缩写:缺陷本身就是「锚点清单漏了一项」,手写 fixture 只能钉住作者记得的锚点。而这个面恰好是暴露它的形状 —— 对象只声明field.group、没有fieldGroups[],所以默认 form 是它唯一的段落锚点。一例钉四个具名段落全部被接受;一例是防过度放宽的反例:contract(contact的错拼)与who_is_this(formViews.create那个无名段落的 label)两个 key 仍各上报一条,且 hint 改口列出Declared sections: contact, notes, status, work。按车道口径,两条真实元数据 import 的用例显式
}, 60_000)。反向验证(方向先预判,再跑)
预判:删掉新加的这一条 limb,4 条新用例应全红(这是纯放宽,不存在 #5018 那种反转,也不存在 #5046 那种「计数从 1 变 0 反而多出诊断」)。实测一致:
恢复 limb 后:
消费半径已按规则的调用点(而非改动包)扫过:
translation-target-unknown/validateTranslationReferences仅由packages/lint内的reference-integrity-suite+index.ts消费,全仓_sections的 fixture 只出现在本规则的测试与packages/spec的 translation schema 测试里 —— 没有 #5046 那种跨包 fixture 需要同步。关于 #5416
切 worktree 时 PR #5416(#5405)尚未合入
main,故按分诊口径跳过「走查器要求 ⊆ 校验器接受」的集合断言,不为它引入跨分支依赖;本修复不依赖 #5416。#5416 落地后可在其上补该断言。越界发现(已另开 issue,未在本 PR 修)
ContactViewsis exported but never registered inobjectstack.config.ts— the docs' canonical "create form ≠ edit form" example does not run #5420 —ContactViews在examples/app-showcase/objectstack.config.ts的views里从未注册(barrel 导出了、config 第 23/196 行漏了),而 app 导航有nav_contacts、文档content/docs/ui/create-vs-edit-form.mdx又把该文件列为活参考实现。本 PR 的 fixture 直接 import 该模块,不依赖 showcase 注册。runtime-lazy-deps.test.ts"gating a flow in-process" runs on the default 5s timeout and flakes under load — its cold-load sibling already carriesCOLD_LOAD_TIMEOUT_MS#5421 —packages/lint/src/runtime-lazy-deps.test.ts的 in-process 用例用默认 5s 超时(同文件的冷加载兄弟用例已带COLD_LOAD_TIMEOUT_MS),负载下 4 跑 2 挂,与本改动无关。🤖 Generated with Claude Code
https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh
Generated by Claude Code