Skip to content

docs(plugin-report): rewrite README export snippets against the real signatures - #5060

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-5048-report-export-signatures
Aug 17, 2026
Merged

docs(plugin-report): rewrite README export snippets against the real signatures#5060
yinlianghui merged 1 commit into
mainfrom
claude/issue-5048-report-export-signatures

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes#5048

packages/plugin-report/README.md### Export / ### Live Export 两节里,导出函数的名字全部真实,但调用的参数个数与顺序全错。这正是 #5016 用的名集合核对看不见的缺陷类:每个 import 读起来都是真的,错的是调用形。本 PR 只重写这三个示例块 + 一个 changeset,不改任何 API、不加导出、不动 src/

Base: ee4f796d26635c39ff1f9a814bf9fc04529a9e7a(含前置 PR #5053f331f5a8b)。

前提验证:卡面三处签名断言逐条对 src 复核

卡面的行号在本 base 上全部命中,三条断言全部为真 —— 前提成立。

断言卡面行号复核读数结论
六个格式导出器 (report, data, config?): voidReportExportEngine.ts:19,43,57,96,151:19 CSV / :43 JSON / :57 HTML / :96 PDF / :151 Excel,五个签名逐字一致,全部 : void、无 async
exportReport format-first:175exportReport(format: ReportExportFormat, report, data, config?): void
无 filename 形参名字取自 config?.filename || report.title || 'report'(:37,:50,:90,:169)
LiveExportOptionsdataSource/resource 必填LiveReportExporter.ts:34-45:34-45,dataSource: DataSource / resource: string 均无 ?
exportWithLiveData 真签名:97async (report, options: LiveExportOptions): Promise< LiveExportResult >
其 JSDoc 示例正确:88-95:86-94(内容定位;偏移 2 行),形状正确,已直接复用
exportExcelWithFormulas 三参:161:161(report, data, options = {}): void
ExcelColumnConfig 列键是 name 而非 field:50-61:50-61,{ name: string; header: string; width?; numberFormat?; formula? }
formula 用 {ROW} 占位正例 :139-146:149-156(偏移 10 行);实现在 :177col.formula.replace(/\{ROW\}/g, String(rowIndex + 2))

卡面未列、复核时补测到的一条:ExcelColumnConfig.header 也是必填(header: string,无 ?)。所以把 field 改成 name 并不足以让示例编译 —— 见下面探针 P6。重写后的列都带 header

逐块签名对照

块 1 — ### Export(旧 README.md:237-239)

调用形await exportAsCSV(reportData, 'sales-report.csv')exportAsCSV(report, rows, config?)
第 1 参reportData(读作数据)report: ReportComponentSchema —— 列与标题的来源
第 2 参文件名字符串data: any[] —— 引擎按行迭代
文件名幻想出的第 2 形参config.filename,否则 report.title
返回await(视作 async)void 同步,await 空转
exportReport无示例format 在最前:exportReport('csv', report, rows)

exportAsJSON / exportAsHTML 原先只在 import 列表里出现、从无调用,现在六个全部各给一行。顺带订正两处旧文字的事实错误:exportAsPDF 才是开打印窗口的那个(:100window.open,被拦则退回 .html),exportAsHTML 是下载 .html(:90);exportAsExcel 落盘的是带 BOM 的 TSV,默认名后缀 .tsv 而非旧示例写的 .xlsx(:169)。

块 2 — exportWithLiveData(旧 :249):旧写法 { format: 'pdf' } 缺两个必填键。改后直接复用函数自己的 JSDoc 示例(dataSource + resource + format),并补上返回值 LiveExportResult 的形状与失败语义(返回而非抛出)。

块 3 — exportExcelWithFormulas(旧 :250-252):旧写法传 2 参、列键写 field、formula 写死 SUM(B2:B100)。改后三参齐全,列键 name + 必填 header,formula 用 '=B{ROW}*C{ROW}'(即 :149-156 的正例)。

编译探针读数

探针把 README 的三个 tsx用脚本从 README.md 里提取(不是手抄),对构建产物编译。解析确认打到的是产物而非源码:

Module name '@object-ui/plugin-report' was successfully resolved to
'.../packages/plugin-report/dist/index.d.ts' with Package ID '@object-ui/plugin-report/dist/index.d.ts@17.5.0'

前置构建:pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-report...' build → Done。

探针结果
改后三块(脚本提取,tsc --noEmit --strict)rc=0,零诊断
接线自证:把 exportReport('csv', report, rows) 故意换成 exportReport(report, 'csv', rows)转红 TS2345: Argument of type 'ReportComponentSchema' is not assignable to parameter of type 'ReportExportFormat'. —— 证明探针不是静默 any

反向验证 —— 预判先写,含两条「抓不到」

预判在跑之前写进探针文件头,方向为旧写法回填必须转红:

预判结果实测
P1 块 1 转红:文件名字符串落进 data: any[],三次35,33 / 36,33 / 37,35: error TS2345: Argument of type 'string' is not assignable to parameter of type 'any[]'.
P2 块 2 转红:缺两个必填键42,42: error TS2345: ... '{ format: "pdf"; }' is missing the following properties from type 'LiveExportOptions': dataSource, resource
P3 块 3 转红,且红在参数位而非键名;arity 本身合法(options 有默认值),故无 TS2554✅ 方向对,诊断码预判错实际是 48,5: error TS2353: Object literal may only specify known properties, and 'columns' does not exist in type 'any[]'. —— 我预判 TS2345,实为 TS2353。同一缺陷,码不同,如实记录
P4 抓不到:对 void 同步函数 await。TS 允许 await 非 thenable,只有 eslint await-thenable 看得见✅ 确认抓不到单独隔离 await exportAsCSV(report, rows) + await exportExcelWithFormulas(report, rows, {})零诊断。故「await 空转」这一条没有编译期证据,证据改用源码读数:ReportExportEngine.ts:19,43,57,96,151 五个签名均为 : void、无 async、不返回 Promise;exportExcelWithFormulas(:161)同样 : void。README 里改为不写 await,并在正文点明「同步 void,没有可 await 的东西」
P5 抓不到(被遮蔽):块 3 的 field 键名。它只有在对象落到 options 位后才被判定,躺在 P3 后面永远轮不到✅ 确认被遮蔽,隔离后可见把同一列字面量放进真正的第 3 参 → 56,17: error TS2353: Object literal may only specify known properties, and 'field' does not exist in type 'ExcelColumnConfig'.
P6(卡面外补测)field 改成 name 后,缺 header 是否仍红✅ 仍红error TS2741: Property 'header' is missing in type '{ name: string; formula: string; }' but required in type 'ExcelColumnConfig'.

一处对 issue「影响」段的订正

Issue 的 Impact 写「块 1 和块 3 能过检(type-check as written against any[]/loose params),在运行期才炸」。实测不成立:在 strict 程序里两块都是硬编译错误(P1 / P3),读者会被编译器直接拦住,而不是拿到一份用文件名字符逐字拼出来的表格。签名断言本身全部为真,所以前提成立;错的只是严重性刻画。方向上这让缺陷更硬而非更软 —— 每个照抄的读者都会被拦,而不是只有一部分被误导。唯一真正「静默」的一条是 await 空转(P4),而它落在 tsc 的盲区里。

同文件同性质漂移扫描

README 其余带真实 API 调用的块(isDatasetReport + DatasetReportRendererReportViewerschema 形、createScheduleTrigger(report, dataSource, resource, onComplete) 四参 + trigger()formatValue(value, field?))逐块抄进同一探针 → rc=0,无未列的同性质签名漂移可修。#5047 的 schema 形(retired query form)是不同性质,按钉子未碰。

名集合核对(多行 import 块 + 剥注释,对 dist/index.d.tstypes/dist/index.d.ts 的真实导出面):14 块,fake=0 —— 本次改动没有引入任何假名。(过程中修了核对脚本自身一个贪婪正则:它会跨过相邻两条 import 语句把 ReportInput } from '@objectstack/spec/ui'; import { ReportRenderer 整段当成一个名字误报;改成 [^{}]*? 后归零。脚本是探针,不入库。)

验证

.changeset/plugin-report-export-signatures.md:@object-ui/plugin-report patch,docs 级说明。


Generated by Claude Code

…signatures
The `### Export` / `### Live Export` blocks named only real exports but called
every one of them with the wrong arity or argument order — a defect class the
name-set check used for #5016 cannot see, because each import reads as real.
- The six format exporters are `(report, data, config?)` returning `void`.
The README called them `(data, filename)`, so a filename string landed in the
`data` slot the engine iterates as rows, and no filename parameter exists at
all (the name comes from `config.filename`, else `report.title`). The `await`
on a synchronous `void` return was inert. `exportReport` takes the format
first, which no snippet showed.
- `exportWithLiveData(report, options)` requires `dataSource` and `resource`;
the README passed only `{ format: 'pdf' }`.
- `exportExcelWithFormulas(report, data, options)` takes three parameters, not
two, and `ExcelColumnConfig` has the required `name` + `header`, not `field`.
Formula templates use the `{ROW}` placeholder.
The replacements are the exporters' own correct JSDoc examples. Each block was
extracted from the README programmatically and compiled against the package's
built `dist/index.d.ts` (rc=0); the old form backfilled into the same probe goes
red on all three blocks. Docs only — no API or runtime change.
Fixes#5048
Co-authored-by: Claude <noreply@anthropic.com>
@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation plugin labels Aug 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Main entry (gzip)25.3 KB350 KB
Entry fileindex-DEKTDl1Q.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)122.95KB29.80KB
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 ee4f796d2(≥ 前置 PR #5053,序约束满足),2 files +91/−9 与报告一致,单 commit,模型标识 msg/diff 双零,releases 零触碰。CI 亲读:19 个 check-run 全 completed 零失败(docs-only 形状,类型证据为本地读数,同族口径)。

验收要点:

  1. 卡面签名断言全数复核为真,但 Impact 刻画被实测否证且方向是「更硬」:块 1/3 在 strict 下是硬编译错(P1/P3 探针),不是卡面说的「能过检、运行期才炸」;真正落在 tsc 盲区的只有 await 空转(P4 预判「抓不到」成立),该条证据改用源码读数(五签名 : void、无 async)—— 没有硬凑编译期证据。这是前提严重性修正的正确姿势。
  2. 探针工程质量:三块由脚本从 README 程序化提取(非手抄),--traceResolution 自证打到构建产物,接线自证(参数序换错必须转红)排除静默 any。P5 的「遮蔽」预判(field 键名错躺在 P3 后面轮不到判定)与隔离验证,是对诊断顺序的正确建模。
  3. 同块同性质扩展全部有据:header 必填(不补则只改 fieldname 仍不编译)、print window 归属 exportAsPDF.tsv 后缀 —— 逐条对 src 行号,PR 单列。
  4. P3 诊断码预判错(TS2345 → 实测 TS2353)按纪律保留原预判标注差异;28 分钟误判的过程失误自纠并披露(时间戳核对后改等通知再轮询)—— 都合格。
  5. ⛔ 零 API 改动、零新导出;plugin-report docs still teach the pre-9.0 query form as the live authoring shape — and name three renderers removed at the ADR-0021 cutover #5047(schema 形)未碰;门禁提案归 finding: 没有门禁核对包内 README 的自包导入名 vs 真实导出面 —— #5002 家族 7 个包的漂移全靠人工巡查发现(附已验证的检查器原型) #5043 未实施 —— 边界全部守住。

转 ready 并挂 auto-merge(squash)。


Generated by Claude Code

@yinlianghui
yinlianghui marked this pull request as ready for review August 17, 2026 21:51
@yinlianghui
yinlianghui added this pull request to the merge queueAug 17, 2026
Merged via the queue into main with commit 82a9417Aug 17, 2026
20 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-5048-report-export-signatures branch August 17, 2026 21:51
os-zhuang pushed a commit that referenced this pull request Aug 18, 2026
…t types (#5138)
objectui#5138 shape 2, as ruled: promote the snippet-extraction +
`tsc --strict`-against-built-`dist` harness into `scripts/`, where it runs once
in CI instead of three times by hand.
The harness already existed three times, hand-rolled and private — in #5053,
#5060 and #5047's PR — and each copy found defects its reviewer had not listed.
This keeps the practice each one proved: extraction by script rather than by
hand, resolution against the package's built `dist/*.d.ts` with a self-check
that says so, and a planted sentinel export that must produce a diagnostic.
The false-green mechanism #5047 measured is designed against structurally
rather than noted: parse errors suppress semantic checking program-wide, so a
run can print a few syntax errors, no semantic diagnostics at all, and read as
a meaningful red. The two phases are separate here, unparseable blocks are
reported and kept out of the semantic program, every failure line is tagged
`[syntax]` or `[semantic]`, and the summary always states how many blocks the
semantic phase actually judged.
Fragments are declared, never guessed: a block that is not meant to compile
carries a marker with a written reason immediately above its fence. A block
that fails to parse is a failure, never a skip — the alternative turns every
real defect into a silent skip.
Coverage is declared too. A document is covered unless it is named in the
script's ledger with a reason; the default is covered, so a new page is gated
from the day it lands. 13 documents and 67 blocks are covered today; the 44
documents on the ledger are debt with names, and the script's header says
plainly that they are unverified.
Scope of the gate, stated in its header because an unstated blind spot is how
this class stays green: it judges TypeScript resolvability only — not schema-key
validity against the spec (#5138 shape 1, unruled), not `type`-literal
registration (`check-doc-component-types.mjs`), and not shell examples (#5151).
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

2 participants

@yinlianghui@claude