Skip to content

stack 渲染器读一个从未声明的 spacing 键,catalog 里 135 个节点照着它写 #4890

Description

@yinlianghui

发现于 #4003 的实施,不在该 PR 处理 —— 那一单只把 div 转成布局类型并一律写声明键 gap,没有碰既有 stack 节点。

现象

StackSchema 继承自 FlexSchema,声明的间距键只有 gap:

  • packages/types/src/layout.ts:180-182 —— export interface StackSchema extends Omit<FlexSchema, 'type'> { type: 'stack'; }
  • FlexSchema 的键:direction / justify / align / gap / wrap / children

spacing 不在其中。但渲染器额外读它,还特意用 as any 绕过类型:

  • packages/components/src/renderers/layout/stack.tsx:25 —— const gap = schema.gap ?? (schema as any).spacing ?? 2;

于是 spacing 成了一个只存在于 consumer 里的第二套事实契约。catalog 里实测 135 个 stack 节点、39 个文件写的是 spacing 而不是 gap(例如 marketing/features-grid.json{"type":"stack","spacing":3}auth/*.json 全系列、actions/action-toolbar.json)。

#4001 的关系:同一个病,另一种表现

#4001 是"未声明的键被静默丢弃"(cols → 列数丢失,渲染成 2 列)。这条是同一个病的宽容变体:未声明的键被consumer 接住了,所以渲染看起来是对的,没人会去查,错的写法就一直传播 —— 而 #4001 正文说过,"碰巧看起来对"的那一类是最坏的一类。

AGENTS.md #0.1 直接点名这个形状:"宽容的 fallback 会把错写法固化成第二套事实契约,稀释 spec,并掩盖 producer 的 bug —— 一套严格契约胜过 N 种方言。"

今天没有用户撞到,但作者面已经被教坏

修法方向(契约优先)

producer:135 个节点 spacinggap,然后删掉 stack.tsx:25(schema as any).spacing ?? 那一截。⛔ 不要反过来把 spacing 补进 StackSchema 来"合法化" —— 那是把一个纯粹多余的别名提升成公共契约,gap 已经在那里,两个名字做同一件事只会让 AI 作者继续猜。

注意:改完之后渲染不变(两条路径本来就归到同一个 gap),所以这是一次纯机械替换,适合和 #4003 之后的 catalog sweep 合并成一张卡。#4003 已经留下 examples/schema-catalog/test/layout-props-conversion.test.tsx 这个位置,禁令加在那里最省。

参考位置

  • packages/types/src/layout.ts:180-182(StackSchema,无 spacing)
  • packages/components/src/renderers/layout/stack.tsx:25((schema as any).spacing)
  • packages/components/src/renderers/layout/flex.tsx(同族,spacing)
  • packages/components/src/renderers/layout/stack.tsx:98-103(注册 inputs 只有 gap,与渲染器读的键已不一致)
  • examples/schema-catalog/src/schemas/**(135 个命中节点)

关联:#4001 / #4003 / #3965

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions