Skip to content

Commit 35f7fb4

Browse files
os-zhuangclaude
andauthored
fix(spec): 参考文档顶层长枚举移入 Allowed Values,联合变体印数量 (#6225, #6226) (#6377)
#5340(PR #6211)压掉内联摘要里的长枚举后,`content/docs/references/**` 仍有 27 个 超过 400 字符的类型单元格。它们是两种机制,一次重生成一起收: - #6225:9 个「整格就是一个 Enum」的顶层词表。新增 `formatPropertyType`,是 `build-docs.ts` 里 `### Allowed Values` 项目符号分支的镜像,逐条件对齐 (`type === 'string'` 且 enum 是数组)。单元格印样本加数量,完整成员表印在表格 正下方 —— 信息没有离开页面。省略与搬迁来自同一个 `elideEnum` 调用,不会各说各话; 预算只在会搬迁的入口读取,`formatType` 本身未改,#5340 的「自己那一行不省略」原样成立。 - #6226:联合变体数上限(维护者裁决),超出印 `… +N more`,自报被省略的变体数。 阈值全部实测:枚举预算 40–176 给出完全相同的宽度结果,区间内只影响搬走多少份词表 (227 → 24),取 160;变体上限按 353 个联合的分布(2 个变体占 72.5%,累计到 4 个 是 92.6%)取 4,与 `INLINE_KEY_LIMIT` 同源。「标记必须挣回自己的位置」守卫共用, 实测拒绝 248 个候选省略里的 54 个(合计只省 328 字符),其中 7 个是整节搬迁。 全语料:>400 27 → 9,>900 4 → 1,p99 247 → 227,max 6092 → 1538,p95 145 不动。 25 份被搬迁的词表逐条核过完整成员表就在本页(25/25)。MDX 编译 216/216。 Claude-Session: https://claude.ai/code/session_014wsZeReNTqiceBfLb5Pyf5 Co-authored-by: Claude <noreply@anthropic.com>
1 parent 22a2b60 commit 35f7fb4

29 files changed

Lines changed: 1564 additions & 71 deletions
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
---
2+
"@objectstack/spec": patch
3+
---
4+
5+
docs(spec): 参考文档表格单元格的两条残留宽度 —— 顶层长枚举移入 `### Allowed Values`,联合变体印数量 (#6225, #6226)
6+
7+
#5340(PR #6211)把**内联摘要里**的长枚举压掉之后,`content/docs/references/**` 仍有 **27 个超过
8+
400 字符的类型单元格**。它们不是一种毛病,是两种,机制不同,因此分两条修,一次重生成:
9+
10+
**#6225 —— 9 个「整格就是一个 `Enum<…>`」的顶层词表。**
11+
12+
`build-docs.ts` 一直有一条更适合长词表的渲染路径 —— `### Allowed Values` 加每个成员一行项目符号
13+
—— 但它只在**整个 schema**`type: 'string'` + `enum` 时才走。同样 49 个成员,被 Zod 提升成具名
14+
schema(`data/FieldType`)的走项目符号,内联在**属性**上的(`Field.type`)得到一个 561 字符的表格
15+
单元格,而 `ApiError.code` 的 261 个成员得到 **6092 字符**。一份词表落在哪种渲染上,取决于它有没有
16+
被提升 —— 这是关于 Zod 的事实,不是关于读者怎么读它的事实。
17+
18+
新增的 `formatPropertyType` 就是那条分支的镜像,**逐条件对齐**(`type === 'string'``enum`
19+
数组):属性自己的类型节点就是那份词表。单元格印一个样本加数量,完整成员表由 `build-docs.ts` 印在
20+
表格正下方 —— **信息一个字都没有离开页面**。省略与搬迁是同一个 `elideEnum` 调用的两个返回值,不可能
21+
各说各话;预算只在会搬迁的那一个入口读取,`formatType` 本身一行没改,所以 #5340 立下的「词表自己那
22+
一行永不省略」在 `formatType` 上原样成立。
23+
24+
刻意****匹配的三种位置(各自都在单元格里渲染出 `Enum<…>`):`Enum<…>[]`
25+
`Record<string, Enum<…>>`、以及联合变体(`Enum<…> | string`,`ui/page.mdx``PageComponent.type`)。
26+
对它们来说「本属性的允许值」不是实话 —— 成员是**元素 / 值 / 某一个变体**的词表 —— 表格下面挂一份项目
27+
符号会宣称 schema 没说过的事。数字枚举同样不匹配:项目符号把每个成员渲染成 `` `x` ``,分不出 `2`
28+
`'2'`,那正是 #5729 修掉的错(镜像的整 schema 分支也要求 `type === 'string'`,所以这是对齐不是巧合)。
29+
30+
**#6226 —— 另外 18 个里的联合变体重复。** 维护者裁决:变体数上限 + 自报被省略的变体数。
31+
`formatType``anyOf` 分支原本是 `variants.map(...).join(' | ')`,对变体之间的相似度一无所知 ——
32+
`ui/app.mdx``App.navigation` 把同一个 `{ id; label; icon?; order?; … }` 印了 9 遍,其中 7 遍逐字
33+
相同,582 字符。现在最多印 4 个,其余印 `… +N more`
34+
35+
**阈值全部实测,没有拍脑袋的常数。** 在真实语料上逐个候选值重生成再量:
36+
37+
- 枚举预算:40 到 176 之间的**每一个**值都给出**完全相同**的宽度结果(>200 为 121、>400 为 18、
38+
>900 为 1、p99 227、max 1538),所以这段区间里选哪个跟宽度无关,只跟**搬走多少份词表**有关 ——
39+
从 227 份掉到 24 份。取 **160**:拿到能拿到的最好宽度,只搬 25 份而不是 227 份,距 184 的悬崖还
40+
留有余量;它恰好是内联预算 80 的两倍,把两个位置的不对称说明白了 —— 摘掉一份副本几乎免费,把词表
41+
搬出它自己那一行要在页面上多开一节。
42+
- 变体上限:语料共 353 个联合,2 个变体的占 256(72.5%),累计到 4 个变体是 92.6%,之后是薄尾。
43+
上限 2 → 8 个宽单元格,3 → 8,**4 → 9**,5 → 11,6 → 18(与不设上限无异)。取 **4**:它是仍能
44+
做完几乎全部工作的最松上限(收到 3 只多救回 1 个单元格,却要省略 44 个联合而不是 26 个),并且
45+
与读者上一行刚见过的 `INLINE_KEY_LIMIT = 4` 同源 —— 同一个单元格里两个不同的「印几个之后 ``
46+
才是裁决要避免的那种不一致。
47+
48+
**「标记必须挣回自己的位置」守卫**沿用 #5340 并被两条新省略共用。实测(把守卫改成无条件省略再重生成
49+
对比):它拒绝了 248 个候选省略里的 **54 个**,那 54 个加起来只省 **328 字符** —— 平均每个 6 字符,
50+
而标记本身要花 12–15 字符。其中 **7 个是搬迁候选**,也就是七整节 `### Allowed Values` 本来会为了给
51+
一个单元格削掉个位数字符而被加进页面。守卫在搬迁上比在 #5340 的内联省略上更要紧:那边一次拒绝省下
52+
一个标记,这边省下一整节。
53+
54+
**全语料重新测量(216 页 / 8541 个单元格):**
55+
56+
| | 之前 | 之后 |
57+
|---|---|---|
58+
| 超过 200 字符 | 145 | 121 |
59+
| 超过 400 字符 | 27 | **9** |
60+
| 超过 900 字符 | 4 | **1** |
61+
| p99 | 247 | 227 |
62+
| p95 | 145 | 145(不动) |
63+
| max | **6092** | 1538 |
64+
65+
p95 纹丝不动,是这次改动的重点:普通单元格一个都没有移位。9 份被搬迁的顶层词表连同另外 16 份 160
66+
字符档的,全部逐条核过完整成员表就在本页(25/25,0 缺失);新加的 25 个 `### Allowed Values: X.y`
67+
标题按 schema + 属性双重限定,全页面唯一(`api/errors.mdx``EnhancedApiError``FieldError` 都有
68+
`code`,只写属性名会撞锚点)。全语料 MDX 编译保持 **216/216**
69+
70+
**没有被这次改动够到的、如实记录:** 剩下 9 个超过 400 字符的单元格里,`ui/page.mdx``Page.slots`
71+
(1538,本轮新的 max)恰恰**不是**变体重复 —— 它的每个联合都只有 **2** 个变体(`T``T[]`),宽度
72+
来自 `INLINE_KEY_LIMIT` 的 4 个键 × 2 个变体 × 每个约 176 字符,任何 ≥2 的变体上限都够不到它。另有
73+
4 个(`Manifest.capabilities``PluginRegistryEntry.capabilities`
74+
`GetTranslationsResponse.translations``PluginSecurityManifest.permissions`)**根本没有联合**,宽度
75+
纯粹来自嵌套深度。这是第三种机制,已另立观察单,不在本 PR 范围内。

content/docs/references/ai/solution-blueprint.mdx

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,65 @@ const result = BlueprintAppSchema.parse(data);
6969
| :--- | :--- | :--- | :--- |
7070
| **name** | `string` || Field machine name (snake_case) |
7171
| **label** | `string` | optional | Human-readable field label |
72-
| **type** | `Enum<'text' \| 'textarea' \| 'email' \| 'url' \| 'phone' \| 'password' \| 'secret' \| 'markdown' \| 'html' \| 'richtext' \| 'number' \| 'currency' \| 'percent' \| 'date' \| 'datetime' \| 'time' \| 'boolean' \| 'toggle' \| 'select' \| 'multiselect' \| 'radio' \| 'checkboxes' \| 'lookup' \| 'master_detail' \| 'tree' \| 'user' \| 'image' \| 'file' \| 'avatar' \| 'video' \| 'audio' \| 'formula' \| 'summary' \| 'autonumber' \| 'composite' \| 'repeater' \| 'record' \| 'location' \| 'address' \| 'code' \| 'json' \| 'color' \| 'rating' \| 'slider' \| 'signature' \| 'qrcode' \| 'progress' \| 'tags' \| 'vector'>` || Field data type |
72+
| **type** | `Enum<'text' \| 'textarea' \| 'email' \| 'url' \| 'phone' \| 'password' \| 'secret' \| 'markdown' \| 'html' \| 'richtext' \| 'number' \| 'currency' \| 'percent' \| 'date' \| … +35 more>` || Field data type |
7373
| **required** | `boolean` | optional | Whether the field is required |
7474
| **reference** | `string` | optional | Target object name for lookup / master_detail relationship fields |
7575
| **options** | `{ label: string; value: string }[]` | optional | Choices for select / multiselect / radio fields |
7676
| **summaryOperations** | `{ object: string; function: Enum<'count' \| 'sum' \| 'avg' \| 'min' \| 'max'>; field?: string; relationshipField?: string; … }` | optional | REQUIRED when `type` is "summary" (a roll-up of child records: 任务总数 / 报名人数 / 合计金额 / 已完成任务数). Names the child object, the aggregation, and — for a qualified count/sum — the condition. A "summary" field without it materializes runtime-dead. |
7777
| **expression** | `string` | optional | REQUIRED when `type` is "formula" — the CEL body the field computes, e.g. "record.quantity * record.unit_price", or "record.order_no + ' · ' + record.customer" for a composed title. A "formula" field without it materializes runtime-dead: the engine builds its formula plan only from fields that HAVE an expression, so the field reads null everywhere, forever. Same failure shape as a "summary" with no `summaryOperations`. Note `nameField` on the object recommends a formula for numbered entities (invoice/ticket) — that formula needs THIS key, or the record title is blank on every card, lookup chip and breadcrumb. |
7878

79+
### Allowed Values: `BlueprintField.type`
80+
81+
* `text`
82+
* `textarea`
83+
* `email`
84+
* `url`
85+
* `phone`
86+
* `password`
87+
* `secret`
88+
* `markdown`
89+
* `html`
90+
* `richtext`
91+
* `number`
92+
* `currency`
93+
* `percent`
94+
* `date`
95+
* `datetime`
96+
* `time`
97+
* `boolean`
98+
* `toggle`
99+
* `select`
100+
* `multiselect`
101+
* `radio`
102+
* `checkboxes`
103+
* `lookup`
104+
* `master_detail`
105+
* `tree`
106+
* `user`
107+
* `image`
108+
* `file`
109+
* `avatar`
110+
* `video`
111+
* `audio`
112+
* `formula`
113+
* `summary`
114+
* `autonumber`
115+
* `composite`
116+
* `repeater`
117+
* `record`
118+
* `location`
119+
* `address`
120+
* `code`
121+
* `json`
122+
* `color`
123+
* `rating`
124+
* `slider`
125+
* `signature`
126+
* `qrcode`
127+
* `progress`
128+
* `tags`
129+
* `vector`
130+
79131

80132
---
81133

0 commit comments

Comments
 (0)