首页
/ Reactive Resume 的 Semantic CSS 语言参考与统一文档生成设计:一篇权威参考页加一条 `pnpm docs:gen` 流水线

Reactive Resume 的 Semantic CSS 语言参考与统一文档生成设计:一篇权威参考页加一条 `pnpm docs:gen` 流水线

2026-09-05 15:46:40作者:蔡怀权

本篇解读 Reactive Resume 仓库中「Semantic CSS Author Reference and Unified Documentation Generation」设计文档(状态:Approved,2026-07-29):它将 Semantic CSS 的作者级语言参考收敛为一个规范页面,并把 Semantic CSS 参考表、AI 技能 Schema 参考、公开 JSON Schema 指南和 OpenAPI 规范四类生成物统一到根命令 pnpm docs:gen 之下。读完后你会掌握:参考页的十节信息架构、基于标记(marker)的确定性 Markdown 生成机制、Zod 到 JSON Schema 的单一规范源设计,以及「全量计算后再落盘」的失败安全策略及其测试验证方式。

一、设计目标:一份面向作者的规范参考

设计文档明确了两条原则:

  • 受众是简历作者(resume authors),不是编译器贡献者。参考页是语言参考(language reference),而非贡献者文档:编译器架构、AST 实现细节、内部适配器名称和包归属关系都不得出现在公开页面中。
  • 单一规范入口,扩展而非重复。参考内容不新开页面、不拆分多页,而是扩展现有页面(原文设计为 docs/guides/semantic-css-reference.mdx,公开路由 https://docs.rxresu.me/guides/semantic-css-reference),把手写解释、可复制粘贴的示例,与从运行时注册表(runtime registries)和 PDF 模板清单(template manifests)生成的表格合并在同一页中。

参考页必须让作者能够:

  • 发现存在哪些选择器、属性、值和指令(directive);
  • 理解哪些语义节点和模板部件可以被定向;
  • 复制针对常见定制目标的可运行示例;
  • 诊断无效或不起作用的样式;
  • 理解可移植性、last-valid(最后一次有效样式)行为、资源限制与不支持的语法。

一个关键的边界约束值得注意:生成的属性表格不得把宽松的注册表提示(registry hint)呈现为穷尽的值文法。凡是值语法实际上由解析器或级联逻辑实现、且没有权威共享元数据的,必须保留手写说明。这一条防止了「生成表格看似精确、实际并不精确」的文档失真。

二、规范参考页的十节信息架构

参考页按「查」而非「顺读」组织,共十节。这是整份设计的主体骨架,完整继承如下:

  1. 一分钟了解 Semantic CSS(Semantic CSS in one minute)
    • @version 1; 指令;
    • 一份完整、可移植的样式表示例;
    • 可编辑源码(editable source)、实际生效源码(applied source)、预览与导出四者之间的关系。
  2. 选择器文法(Selector grammar)
    • 通配、语义类型、ID、属性选择器;
    • 支持的属性操作符;
    • 后代、子代、相邻兄弟、泛型兄弟四种组合器;
    • 选择器列表;
    • 支持的功能性与结构性伪类;
    • 大小写敏感行为;
    • 明确列出不支持的选择器语法;
    • 合法与非法示例成对给出。
  3. 语义元素目录(Semantic element catalog)
    • 生成的父子关系、属性与角色(roles);
    • 已知属性值域;
    • 可移植的 section 类型选择器 vs 简历专属 ID 的区分;
    • 富文本结构,特别是 list-item 行与 list-item-content 两种不同语义(后续计划文档还要求保留 list-marker 的独立作者语义)。
  4. 级联与值(Cascade and values)
    • 特异性、源码顺序、选择器列表特异性、继承、!important
    • initialinheritunsetrevert 在 Semantic CSS 中的行为;
    • 作者自定义属性、嵌套 var() 回退、未解析变量与循环;
    • 只读系统变量 --resume-*
    • 数字、长度、单位、颜色、函数与简写。
  5. 属性参考(Property reference)
    • 按类别分组的生成属性表;
    • 按语义节点标注适用性;
    • 继承性;
    • 有权威元数据时标注可接受单位与受约束关键字;
    • 文本、间距、边框、Flex 布局、图片、变换与结构性属性的示例。
  6. PDF 行为
    • 页面尺寸;
    • 隐藏节点与稳定的兄弟排序;
    • 分页、固定内容、最小存在性(minimum presence ahead)、孤行与寡行;
    • 媒体查询文法、求值顺序与页面尺寸行为;
    • 影响作者的 React PDF 特有布局限制。
  7. 模板专属选择器
    • 覆盖全部 15 个模板的生成矩阵;
    • 精确的模板部件名、选择器形态、归属或放置条件、允许的语义子节点;
    • 可移植性警告与受保护(guarded)的选择器示例。 矩阵从真实模板清单生成,而不是单独维护的一份列表。
  8. 诊断与限制(Diagnostics and limits)
    • 稳定的编译器与预检(preflight)诊断码、严重级别、含义与建议修复动作;
    • 源码、选择器、声明、节点、页面、尺寸、超时与内存限制;
    • 无效编辑之后 last-valid 预览与导出的行为。
  9. 复制粘贴配方(Copy-paste recipes)
    • 重排 section 标题、按类型定向 section、定向单个 section/条目/字段、按位置定制侧栏内容、定制富文本列表、修改页面尺寸、避免尴尬分页、定制模板装饰、用 @media 按尺寸应用 PDF 样式。
  10. 不支持的能力与可移植性清单
    • 不支持的选择器、at-rule、布局、资源、字体、脚本、交互与网络能力;
    • 保持样式表跨模板可移植的建议。

三、统一文档生成架构:pnpm docs:gen

设计将原先的 docs:semantic-css 命令替换为根命令 pnpm docs:gen,留下唯一规范文档生成入口。该命令一次性再生四类生成物:

  1. Semantic CSS 参考表;
  2. resume-builder 技能的 Schema 参考;
  3. 嵌入公开 Schema 指南的完整 JSON Schema;
  4. 签入仓库的 OpenAPI 规范。

3.1 仓库中的实际命令编排

当前仓库根 package.json 中该命令的实现是一条两级编排:

"docs:gen": "pnpm --filter server docs:gen && pnpm --filter @reactive-resume/tooling docs:gen"
  • server 侧 apps/server/package.jsondocs:gentsx src/openapi/generate-spec.ts,负责 OpenAPI 规范;
  • tooling 侧 tooling/package.jsondocs:gentsx semantic-css/generate-reference.ts,负责 Semantic CSS 与 Schema 文档。

两个生成器分属不同工作区包,但由根命令串联,保证「一次命令刷新全部文档产物」。

3.2 Semantic CSS 参考数据:从权威运行时元数据生成

生成器消费既有的权威来源(而非新建数据源):

  • 受支持的版本与编译限制;
  • 语义元素注册表;
  • 属性注册表;
  • 只读系统变量注册表;
  • PDF 模板清单;
  • 共享的编译器与预检诊断目录。

生成器把确定性的、标记分隔的段落写入参考页 MDX。生成式事实章节包括:语义元素(含父元素、属性、角色、已知值域)、属性(类别、适用性、继承、单位、受约束关键字)、系统变量、逐模板的模板部件、诊断、编译与预检限制。手写叙述始终保留在生成标记之外。

这些权威来源在仓库中的实际位置可以印证:Semantic CSS 编译器(解析、选择器、级联、诊断、限制、注册表)位于 packages/resume/src/stylesheet/,包含 compile.tsselector.tscascade.tsdiagnostics.tslimits.tsversion.tsregistry/ 子目录;PDF 侧的语义渲染与模板清单位于 packages/pdf/src/semantic/

3.3 标记替换机制与「全量计算后落盘」

tooling/semantic-css/generate-reference.ts 是 tooling 侧生成器。其核心是 replaceGeneratedBlock(source, name, body, path) 函数,以 HTML 注释形式的一对标记界定生成区:

const start = `<!-- ${name}:START -->`;
const end = `<!-- ${name}:END -->`;

if (startMatches === 0 || endMatches === 0) throw new Error(`Missing generated markers ${name} in ${path}.`);
if (startMatches !== 1 || endMatches !== 1) throw new Error(`Duplicate generated markers ${name} in ${path}.`);
// ...
if (endIndex < startIndex) throw new Error(`Generated markers ${name} are out of order in ${path}.`);

三种失败(缺失、重复、顺序颠倒)都会抛错,精确对应设计文档「要求每个预期标记存在、重复或缺失即失败」的确定性要求。

失败安全策略在 buildGeneratedDocumentationupdateGeneratedDocumentation 的拆分中体现:前者先计算全部输出文本(读取源文件、生成 JSON Schema、渲染 Markdown),后者才写入目标文件。设计文档明确「不引入通用事务框架」,只做「任一来源非法则零写入」。tooling/semantic-css/generate-reference.test.ts 中有直接对应测试:

it("does not write any output when one source is invalid", async () => {
  // 写入缺少标记的源文件
  await expect(updateGeneratedDocumentation(paths)).rejects.toThrow(/Missing generated markers/);
  // 断言所有目标文件内容与失败前完全一致
  expect(await readTargets(paths)).toEqual(before);
});

另有「两次构建输出完全相等」的确定性测试,以及「签入的生成文档必须与重新生成的结果逐字节一致」的同步性测试,对应设计中「非变更测试生成到临时文件并与签入输出逐字节比较」的验证要求。

3.4 Resume JSON Schema:一个规范源,两个输出

生成器使用 createResumeDataJsonSchema()(来自 @reactive-resume/schema/resume/json-schema,即从 resumeDataSchema 经 Zod JSON Schema 转换得到的唯一规范输入端 Schema)驱动两份输出:

  1. skills/resume-builder/references/schema.md——面向 AI 的紧凑 Markdown 参考:字段层级、类型、必填字段、约束与代表性结构。renderSchemaReference 的输出包含「Required top-level fields」「Union variant shapes」「Field catalog」三节,且对联合类型(anyOf/oneOf)按变体标注必填性(如 variant 1 at items[]),对 customSections[] 的 13 种条目类型(summaryprofilesexperience……cover-letter)按类型键映射到具名条目 Schema(experienceItemSchema` 等),而非匿名的「variant N」——这部分由 tooling/semantic-css/generate-reference.test.ts 逐类型断言覆盖。
  2. docs/guides/json-resume-schema.mdx——完整规范 JSON Schema 放在标记 <!-- RESUME-JSON-SCHEMA:START/END --> 之间的生成式 JSON 代码块中,人手写的解释留在块外。

测试还校验了文档与契约的一致性:引导文必须提到 draft 2020-12、不得残留 draft 7 字样、并明确「Resume 文档不包含顶层 version 属性」。

3.5 OpenAPI 规范:运行时与签入产物共用一个纯生成器

设计的 OpenAPI 部分要求消除「运行时 /api/openapi/spec.json 输出」与「签入的 docs/spec.json」之间的漂移(陈旧版本号、localhost 服务器 URL)。实现上由 apps/server/src/openapi/ 拥有一个可复用、纯函数式的生成器:运行时 handler 以 env.APP_URL 调用它,而文档生成脚本 apps/server/src/openapi/generate-spec.ts 以生产 URL 调用它并写入 docs/spec.json

const spec = await generateOpenApiSpec({ appUrl: "https://rxresu.me", version: packageJson.version });
await writeFile(target, `${JSON.stringify(spec, null, "\t")}\n`);

版本号取自根 package.json 的当前应用版本;脚本在缺失 APP_URLDATABASE_URLAUTH_SECRET 时注入仅用于隔离文档生成进程的值,因此该命令可在无真实环境变量的机器上执行。签入产物 docs/spec.json 即由此生成。

四、Custom Styles 帮助提示

设计在样式表编辑器的共享外壳(shared chrome)中、代码编辑器正上方加了一条提示:

Not sure what to write? Browse the Semantic CSS language reference.

链接契约非常具体:

  • 目标是 https://docs.rxresu.me/guides/semantic-css-reference
  • 新标签页打开,rel="noopener noreferrer"
  • 使用现有 BookOpenIcon 并标记为装饰性(decorative);
  • 可见文本经 i18n 翻译,屏幕阅读器文本额外说明「在新标签页打开」;
  • 因为桌面标准编辑器与移动端聚焦面板共用同一套编辑器外壳,所以一处实现两处生效。

设计上刻意保持实现局部化于样式表编辑器内部,不为一条链接引入共享组件或中央 URL 注册表——这是「不引入无关文档架构」原则的具体体现。

五、导航、验证门禁与验收标准

导航docs/docs.json 将参考页列在 using-custom-styles 之后。当前仓库的 docs/docs.json 可印证该设计的后续演化:/guides/semantic-css-reference 现已配置为重定向至 /applying-custom-styles,即参考内容已并入 docs/applying-custom-styles.mdx(对应仓库中 2026-07-30 的完整重命名设计),导航契约「紧跟 using-custom-styles」保持不变。

验证门禁分四层:

  • 生成器验证pnpm docs:gen 再生全部四组产物;临时文件逐字节比较;重复运行确定性;每个运行时模板部件都出现在模板矩阵中;跨注册表检查拒绝不一致的父子覆盖;签入 OpenAPI 与运行时生成器对同一 URL 与版本一致;两个 Schema Markdown 目标派生自同一规范 Schema。
  • 示例验证:标注为合法(valid)的完整复制粘贴示例必须编译成功;选定的故意非法示例必须产出其文档化诊断;非完整样式表的小片段不强制过完整编译器。当前测试即从公开指南提取全部 ```css 代码块并逐一断言 compileStylesheet 无 error 诊断(见 tooling/semantic-css/generate-reference.test.ts 的 "compiles every Semantic CSS example in the public guide" 用例,调用来自 packages/resume/src/stylesheet/ 的编译器)。
  • UI 验证:样式表编辑器测试校验可访问链接名、精确公开 URL、新标签页目标、noopener noreferrer,以及在标准编辑器与移动端聚焦面板中均存在。
  • 聚焦门禁:tooling 测试与类型检查、受导出元数据影响的 resume/schema 测试与类型检查、PDF 清单/参考一致性测试、API/server OpenAPI 测试、web 编辑器测试、工作区边界检查、聚焦格式化与 Markdown 校验;Chrome 验证不是必需的。

验收标准(完整继承):参考页记录全部作者可见的选择器、语义元素、属性、变量、指令、值族、模板部件、诊断族、限制与不支持语法类别;含常见作者目标的复制粘贴示例;生成式事实来自权威运行时元数据且有陈旧性覆盖;pnpm docs:gen 刷新 Semantic CSS 表、两份 Resume JSON Schema 参考与 docs/spec.json;运行时与签入 OpenAPI 共享一个生成器;参考页在文档导航中可见;桌面与移动端 Custom Styles 编辑器都链接到精确的公开参考路由;不引入无关产品行为或文档架构。

范围外(同样完整列出,避免误实现):贡献者/编译器架构文档;第二个 Semantic CSS 参考路由;把参考拆成多页;交互式文档 playground;新的编辑器补全或悬停功能;除「修正为生成准确参考所必需的注册表事实不一致」之外的新 Syntax 或渲染行为;通用文档 URL 集中化。

六、设计要点回顾

从这份设计与仓库实现对照,可以提炼出三条可复用的工程决策:

  1. 单一事实源优先于文档完整性:所有生成式表格都从运行时注册表与模板清单派生,并配以「签入产物必须与再生成结果逐字节一致」的同步测试,从机制上杜绝文档陈旧;
  2. 标记区 + 失败即中止:HTML 注释标记划定的生成区、缺失/重复/乱序即抛错、先全量计算后统一写入,是低成本实现「原子性文档更新」的实用方案,且被专门测试锁定;
  3. 按受众切分文档:作者参考页严格排除编译器内部概念,同时用「不支持清单 + 可移植性检查清单」明确语言边界,让参考页既是发现入口也是排错手册。
登录后查看全文
热门项目推荐
相关项目推荐