Skip to content

docs(plugin-form): README 按真实导出面重写虚构的手动注册与两个协议类型的导入路径 - #5079

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-5011-plugin-form-readme
Aug 17, 2026
Merged

docs(plugin-form): README 按真实导出面重写虚构的手动注册与两个协议类型的导入路径#5079
yinlianghui merged 1 commit into
mainfrom
claude/issue-5011-plugin-form-readme

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes#5011

基线 origin/main @ e6cd3c26c9ee3c64d76b5e18ab8b41a4aaa09c97(worktree 显式建在该 sha 上)。方法学照抄同族已落地的四单:#5010 → PR #5046#5016 → PR #5053#5012 → PR #5059#5015 → PR #5069

前提验证:卡面两条读数自己复测,都成立

卡面的复核命令写的是裸 grep,按 #5012 的教训补词边界重测,并按 #5010 的教训对零命中做邻近词反查:

卡面断言复测结论
formComponents 全包零命中git grep -nw formComponents -- packages/plugin-form/src → exit 1,无输出✅ 成立
零命中不是扫描器坏了反查确定存在的邻近词:git grep -lnw ObjectForm -- packages/plugin-form/src → 20 个文件✅ 扫描器正常,零命中是真零命中
FormSchema / FormField 真身在 @object-ui/typespackages/types/src/form.ts:1055 / :898 声明,src/index.ts:163 / :156 导出;本包只 import 不 re-export✅ 成立,行号与卡面一致

premise_still_valid: true。顺带记一个假信号来源,与 #5015DashboardSchema 同形:裸 grep FormSchema 还会命中 packages/types/src/zod/form.zod.ts:452zod 同名 const,以及 types/src/index.ts:1154FormField as SpecFormField(spec 侧同名类型的别名再导出)。按导出面查而不是按名字查,这两个都不会误导判定。

判定表

卡面列了两处,名集合核对与散文复核在同一节里揪出第三处 —— 同为「README 断言某标识符在本包导出面上」,一并修,单列如下。

README(改前)判定依据处理
:41import { formComponents } + :45Object.entries(formComponents).forEach(…)纯虚构,且无同族真名可换导出面 51 个名字里没有任何聚合组件表删虚构节,改教真实机制
:408import type { FormSchema, FormField } from 本包真名,包错了两者是协议类型,真身 @object-ui/types;本包只 import 不 re-export只改导入路径(⛔ 不加 re-export)
:156 散文「isRuntimeDefault …(re-exported here)」真名,不在导出面上只由 src/schemaDefaults.ts:78 为包内自用 re-export;package.jsonexports 只有 ".",无深路径可绕改括注为 re-export 的真实位置

第三处不是夹带:本 PR 新增的 "Public exports" 一节是权威的导出面清单,isRuntimeDefault 不在其中;留着「(re-exported here)」会让同一个 README 在相隔 90 行处自相矛盾(#5012 的同款理由)。

未新增任何导出或 re-export来把 README 变真 —— 扩张公开面是契约变更,需另立卡。⛔ 同包 src 一行未碰(#5049 在飞)。

删掉的每一节,删因一行

  • ### Manual Registration 整节(改前 :38-48) —— 它教的 formComponents 不存在,读者复制的第一行就拿到 undefined,Object.entries(undefined) 当场抛 TypeError;而它想表达的「注册」根本不需要手动做,是 import 入口的副作用,没有可遍历的组件表。所以这一节不是「写错了」而是「描述了一个不存在的机制」,无法就地改对,只能删。
    • 补位内容(不是恢复该节,是改教真实机制,三节):① 六个 ComponentRegistry.register(...) 调用真正 claim 的 schema type 表,键从调用现场抄(src/index.tsx:100/159/211/232/276/356),并写明两个 skipFallback: true 正是裸 form 与裸 line_items 没被本包接管的原因(packages/core/src/registry/Registry.ts:194,224);② 真实导出面(51 个名字全列);③ 原片段真正想做的事 —— 把已导出的组件注册到自定义键,并如实注明本包自己注册的是内部 wrapper 而非这些导出组件(wrapper 先从 SchemaRendererContextdataSource,因为 SchemaRenderer.tsx:617 给注册组件传 schema 及其自身 props,从不传 dataSource)。

除此之外没有删任何一节。

名集合核对读数

导出名集合取自构建产物dist/index.d.ts,走 TS compiler API 的 checker.getExportsOfModule。README 侧不用正则抓 import:先抽 fenced 块,每块 ts.createSourceFile,再走 ImportDeclaration 的 AST,A as BpropertyName(导出名)而非本地别名。#5043 记的两个坑因此在结构上不可能发生。

export surfaces: @object-ui/plugin-form 51 / @object-ui/types 675 /
@object-ui/core 416 / @object-ui/data-objectstack 72
改前: README 5 bindings / MISSING COUNT: 3
- formComponents from @object-ui/plugin-form @ README.md:41
- FormSchema from @object-ui/plugin-form @ README.md:408
- FormField from @object-ui/plugin-form @ README.md:408
改后: README 56 bindings / MISSING COUNT: 0

改后 56 个绑定逐个 OK,其中 51 个覆盖新增的两个多行 import 块的全部导出名。

编译探针读数

README 的 ts/tsx 块抄进 scratch,对同一批构建产物编译(strict: true,没有为让块通过而放松任何选项);块按内容签名分类而非块序号,所以改前改后共用一套机器。每块独立成文件并补一行 export {}; —— 多个块各自声明 const schema 都是全局 script,会撞重复标识符;补这一行只改作用域,不影响块内检查。

改前: 8 个可编译块(5 块按设计跳过并列明理由) tsc -> rc=2
block02(1,10): error TS2305: Module '"@object-ui/plugin-form"' has no exported member 'formComponents'.
block04(7,16): error TS2304: Cannot find name 'ValidationRule'.
block09(38,14) / block10(23,14) / block12(13,20): error TS7006: Parameter 'data' implicitly has an 'any' type.
block13(1,15): error TS2305: … has no exported member 'FormSchema'.
block13(1,27): error TS2305: … has no exported member 'FormField'.
改后: 9 个可编译块 tsc -> rc=2
block05(7,16): error TS2304: Cannot find name 'ValidationRule'. (原样携带 —— 已立 #5075)
block10(38,14) / block11(23,14) / block13(13,20): error TS7006: … (原样携带,同上)

三条 TS2305 全部消失;新增的两块(公共导出面、自定义键注册)编译 0 error。可编译块 8 → 9 是因为删了 1 块、加了 2 块。

跳过的五块(输出里列明,不静默丢):Schema API 的形状速写(fields: FormField[]类型语法落在值位置)、两个 remind_at: Field.datetime({ … }),对象属性片段、以及 fieldTabs / fieldPanes 两块里 defaultFieldTab?: 'basics' 这种对象字面量里的可选属性语法 —— 都是故意不合法的 TS。

散文断言另做小探针(不靠外推):import { isRuntimeDefault } from '@object-ui/plugin-form'error TS2305: … has no exported member 'isRuntimeDefault',这就是第三处判定的依据。

反向验证(两条,预判先写)

(a) 名集合核对自证。 预判:往多行块里 planted,MISSING COUNT 0 → 2,恰为 {formComponents, FormThings};别名判导出名;行尾注释里的非导出词不得报。四条全符 ——

变异预判实测
多行导入块中段formComponentsformComponents @ :82
多行类型导入块里加 FormThings as Things报,且按导出名FormThings 而非别名 ThingsFormThings @ :114
LineItemsPanelLineItemsPanel as Panel仍 OK(别名判导出名)OK
行尾 // formComponentsMap was never real不得报(假阳性测试)未报

MISSING COUNT: 2,还原读数 0。变异全做在 README 的 scratch 副本上(检查器的 --readme 指向副本),git status --porcelain 全程只有本卡那一个 M —— 不存在「临时改动误入 commit」的窗口。附带一提,committed 版本第 97 行本身带一条 // deprecated alias of ObjectFormComponentProps 行尾注释,是一条常驻的假阳性哨兵。

(b) 改前 README 回填探针。 预判:回填后必须转红,且错误与所改三处一一对应,既有红原样携带。同一套机器直接跑 git show $BASE:packages/plugin-form/README.md 的副本,转红 rc=2:

所改之处预判实测诊断
formComponentsTS2305block02(1,10): TS2305 … has no exported member 'formComponents'
FormSchemaTS2305block13(1,15): TS2305 … has no exported member 'FormSchema'
FormFieldTS2305block13(1,27): TS2305 … has no exported member 'FormField'
isRuntimeDefault(散文,探针看不到)单独小探针 TS2305p1.ts(2,10): TS2305 … has no exported member 'isRuntimeDefault'
既有的 ValidationRule 与三条 TS7006原样携带改前改后同一内容,坐标随块号平移

预判与实测无出入,方向就是通常的「改前红 / 改后绿」。这里不存在反转或「诊断变多」的情形:判定的是导入名是否存在于导出面,不是 ?? 链的取值判决,也不喂任何计数门 —— 删掉的那一节整节消失,不留一个仍被读取的空壳。按「先写预判再跑」的纪律,这一条是预判即成立,不是事后追认。

(c) 键面漂移为什么留给 #5075 而不是顺手改 —— 改后仍在的 TS2304: Cannot find name 'ValidationRule' 来自 "Schema API → Form Field" 那个本地interface FormField 声明。裸声明永远编译通过,所以对真身做了双向 pin,两个方向都红(type 必填 vs 可选、validation 数组 vs FieldValidationRules 对象)。这属键面/形状而非导入面,且与两个示例块里的 validation: [ … ] 连体 —— 只改参考块会让 README 自相矛盾。已立 #5075,先例同族(#5045 / #5057 / #5066)。

验证

  • 仓根 pnpm exec turbo run type-check --concurrency=281 successful, 81 total,exit 0(4m8s;重活经 flock -w 3600 /tmp/os-heavy-verify.lock 串行 + --max-old-space-size=4096)。
  • node scripts/check-doc-links.mjsLinks are valid across 13 scan roots.(新增的 #public-exports 锚点在内)
  • node scripts/check-control-bytes.mjsOK (scanned 4517 tracked text file(s); skipped 85 binary);改动两文件另做 grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f]' 自扫,exit 1 零命中;file README.md 报 UTF-8 text(未被当成 binary)。
  • pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-form...' build → rc=0(探针与名集合核对所依赖的构建产物)。

docs-only 的 CI 形状:**/*.md.changeset/**paths-ignore 里,Test / Type Check 各 job 的实质步骤会被 path-filter 短路成 skipped 而 job 报 success。按纪律计绿,但类型证据是上面的本地仓根读数,不是 CI 的(#5046 / #5053 / #5059 / #5069 先例)。

顺手立的卡(均未认领,不夹带进本 PR)

changeset

.changeset/plugin-form-readme-truth-5011.md,@object-ui/plugin-form: patch,口径同 #5046 / #5053 / #5059 / #5069:无代码/类型/运行时改动,声明 patch 是因为 README.md 在包的 files 里,随下次发布到 npm。


Generated by Claude Code

`packages/plugin-form/README.md` 有三处对本包导出面的断言不成立,导出名集合取自
构建产物 `dist/index.d.ts`(走 TS compiler API 的 checker.getExportsOfModule,
不是对 src 做正则),README 的每个 TypeScript 块对同一批构建产物 strict 编译验证。
- `:41` `formComponents`:纯虚构,且**改不成同族真名** —— 本包 51 个导出里没有任何
聚合组件表,所以 "Manual Registration" 整节描述的是一个不存在的机制,照抄拿到
`undefined`,`Object.entries(undefined)` 当场抛 TypeError。删该节,改教真实机制:
注册是 import 入口的副作用,六个 `ComponentRegistry.register(...)` 调用 claim 的是
`plugin-form:object-form` / `view:form` / `plugin-form:embeddable-form` /
`plugin-form:form-analytics` / `plugin-form:object-master-detail-form` /
`record:line_items`,其中两个 `skipFallback: true` 正是裸 `form` 与裸 `line_items`
没有被本包接管的原因;另列真实导出面,以及原片段真正想做的事(把已导出的组件注册
到自定义键)。
- `:408` `FormSchema` / `FormField`:名字是真的、包错了。两者都是协议类型,声明在
`@object-ui/types`(`src/form.ts:1055` / `:898`),本包只 import 不 re-export,
照 README 的路径导入是两条 TS2305。只改导入路径 —— ⛔ 未加 re-export,扩张公开面
是契约变更而非文档修正。
- `:156` `isRuntimeDefault`「(re-exported here)」:该谓词只由 `src/schemaDefaults.ts`
为包内自用而 re-export,从不出现在入口上,且本包只发布 `"."` 一个 export,所以
`import { isRuntimeDefault } from '@object-ui/plugin-form'` 同样是 TS2305。括注改成
re-export 的真实位置。
无代码/类型/运行时改动,diff 只有一个 README 与 changeset;声明 patch 是因为
`README.md` 在包的 `files` 里,随下次发布到 npm。
Fixes#5011
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Main entry (gzip)25.3 KB350 KB
Entry fileindex-TJ-eodDQ.js
StatusPASS

📦 Bundle Size Report

PackageSizeGzipped
app-shell (index.js)9.56KB3.59KB
app-shell (runtime-config.js)7.42KB2.32KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)8.92KB3.41KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)1.17KB0.53KB
auth (AuthProvider.js)25.13KB5.40KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.13KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.64KB2.21KB
auth (SocialSignInButtons.js)9.60KB3.89KB
auth (UserMenu.js)3.40KB1.22KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.79KB
auth (createAuthenticatedFetch.js)6.34KB2.43KB
auth (index.js)2.71KB1.22KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.02KB0.88KB
auth (useIsWorkspaceAdmin.js)1.61KB0.85KB
collaboration (CommentThread.js)26.07KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.65KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)502.20KB112.21KB
core (index.js)4.11KB1.62KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)159.03KB44.08KB
fields (index.js)234.25KB58.48KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.35KB1.38KB
i18n (pickLocalized.js)3.69KB1.73KB
i18n (provider.js)23.12KB7.62KB
i18n (useDisplayLocale.js)2.84KB1.45KB
i18n (useObjectLabel.js)27.59KB6.63KB
i18n (useSafeTranslation.js)7.77KB3.13KB
layout (index.js)39.16KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.74KB
mobile (index.js)1.50KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.71KB0.42KB
mobile (useResponsiveConfig.js)1.36KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)9.35KB3.31KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)4.42KB1.42KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.91KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.52KB
permissions (usePermissions.js)1.81KB0.83KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.62KB12.83KB
plugin-charts (index.js)64.75KB18.37KB
plugin-chatbot (index.js)181.21KB43.14KB
plugin-dashboard (index.js)127.85KB32.73KB
plugin-designer (index.js)212.39KB42.83KB
plugin-detail (index.js)241.12KB60.43KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)123.10KB29.84KB
plugin-gantt (index.js)164.10KB39.87KB
plugin-grid (index.js)197.61KB53.03KB
plugin-kanban (index.js)52.72KB14.54KB
plugin-list (index.js)111.17KB26.99KB
plugin-map (index.js)18.72KB6.09KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)41.97KB11.33KB
plugin-timeline (index.js)26.68KB7.66KB
plugin-tree (index.js)8.50KB2.88KB
plugin-view (index.js)83.81KB20.49KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.44KB0.22KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)3.77KB1.33KB
react (SchemaRenderer.js)27.53KB9.41KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.28KB0.68KB
react (schema-input.js)1.45KB0.83KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (index.js)4.77KB2.16KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)10.76KB3.17KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.29KB0.24KB
sdui-parser (validate.js)6.92KB2.40KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)0.20KB0.18KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.87KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-retry.js)4.32KB2.02KB
types (index.js)3.05KB1.52KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)0.20KB0.18KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@yinlianghuiClaude

Copy link
Copy Markdown
CollaboratorAuthor

PM 验收:ACCEPT(session session_01GTRjn8xBqp75dk7kFupVRt,objectui 分片 PM,批次 22)

实物核验:merge-base e6cd3c26c,2 files +151/−9 与报告一致,单 commit,模型标识 msg/diff 双零,releases 零触碰,src 零触碰(#5049 并发边界守住)。CI 亲读:19 个 check-run 全 completed 零失败(docs-only 形状,类型证据本地 81/81)。

验收要点:

  1. 卡面两处 + 第三处同性质漂移(:156 散文的 isRuntimeDefault "(re-exported here)" 假断言,单独探针 TS2305 实证)—— 同性质一并修的判定正确:留着会与同文件新增的 Public exports 清单自相矛盾。
  2. 键面漂移的诚实分离是本单亮点:改后仍在的 TS2304 不冒充本卡的红;validation: 数组拼法的静默失效读数(form.tsx:1652 的 { ...validation } 把数组展开成 {'0':…},规则一条不跑且不报错)由双向 pin 承载而非探针 —— 归入 plugin-form README 的示例键面与 @object-ui/types 的真身不符:validation 数组拼法让校验静默失效、multi-step-form 全仓未注册、FormField 参考块五处漂移 #5075 交定级,不借 PR 的红主张。
  3. 六个 register 调用的键表(含两个 skipFallback: true 的为何)+ 51 名全量导出面进 import 块 —— 同族账本形收官。
  4. 反向验证四条自证全符,变异全做在 scratch 副本上、工作树无误入窗口。

派生物分诊(本评论即记录):#5075(form README 键面:validation 静默失效 + multi-step-form 未注册 + FormField 参考块五处漂移)→ pm:queue + bug —— dev 的「静默失效非文档级」定级判断采信,与本 PR 同文件、落 main 后再派(cast 感知口径);#5076(#5002 家族的 content/docs 镜像 —— plugin-{form,grid,view}.mdx 复制了同段虚构注册,七个 README PR 无人碰 mdx)→ pm:queue + bug + documentation,文件面独立、随时可派 —— 这张卡把家族的第二半打开了。

转 ready 并挂 auto-merge(squash)。


Generated by Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationplugin

Projects

None yet

Development

Successfully merging this pull request may close these issues.

plugin-form README 教三个不存在的导入:formComponents 手动注册、FormSchema / FormField 从本包导入

2 participants

@yinlianghui@claude