mcpField
E
experience-cms-content-render

experience-cms-content-render

github.com/forcedotcom开发1.1k201 次安装1 天前更新
代码仓库

关于 experience-cms-content-render

面向 React 和 Angular uiBundle 应用的交互式技能,用于渲染 CMS 内容。它安装 Salesforce CMS toolkit,并生成类型化引用、渲染器和页面放置代码,同时区分初始搭建与内容嵌入。

主要功能

  1. 01检测 React 和 Angular 应用
  2. 02处理 CMS 标识与架构
  3. 03注册类型化引用
  4. 04生成框架专用渲染器
  5. 05识别 Init 与 Embed 流程

适用场景

  1. 01向 uiBundle 应用添加 CMS 内容
  2. 02渲染多个同类型 CMS 项目
  3. 03首次使用时搭建 CMS 运行时文件

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/forcedotcom/sf-skills --skill experience-cms-content-render

安装后在 Claude Code 中输入/experience-cms-content-render确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/angular/
cms-content.component.ts
cms-item.service.ts
DetailPage.component.ts
MediaRenderer.component.ts
TypeList.component.ts
TypeRenderer.component.ts
assets/react/
DetailPage.tsx
heuristicRenderer.tsx
MediaRenderer.tsx
TypeList.tsx
TypeRenderer.tsx
useCmsItem.ts
assets/shared/
cmsContentType.ts
cmsCore.types.ts
externalRefs.ts
mediaLabels.ts
references/
bulk-loading.md
codegen-guardrails.md
detail-pages.md
embed-recipes.md
failure-modes.md
heuristic-render-rules.md
init-scaffold.md
interaction-model.md
package-api.md
schema-sync.md
styling-scopes.md
verify.md

详细介绍

此技能负责指导如何将 CMS 内容渲染到 uiBundle 应用中;它不会重新实现内容交付传输。npm 包 @salesforce/ui-bundle-template-feature-cms-toolkit 负责 HTTP、信封拆包、目录键重映射、频道解析、图片 URL 解析、实体解码及其他实用功能。此技能会安装该包,然后为 React 和 Angular uiBundle 应用生成围绕该包的精简框架专用层(类型化引用、按类型划分的渲染器、获取生命周期、放置逻辑),根据文件状态推断 Init 与 Embed,并且绝不会在 Embed 提示中搭建 Init 而不告知用户。

仅含 API 的包 — 技能负责编写 UI

该工具包只导出函数和类型:不包含组件或钩子。导入目标及完整签名:references/package-api.md。三种读取方式(都接受 <TBody> 和 options?,失败时都会抛出错误):

  • getCmsContentByUrl — 公共 CDN,无需身份验证;粘贴的 unauthenticatedUrl 会按原样获取。
  • getCmsContentByKey — 获取单个项目,通过 Connect 进行身份验证;工具包会将源键重映射为目标键并解析频道。
  • getCmsContentByKeys — 获取多个项目,仅需一次经过身份验证的往返调用,并按键尽力处理(references/bulk-loading.md)。

此外还提供同步辅助函数 resolveCmsImageUrl、resolveMediaUrl、decodeRichHtmlEntities 以及类型化错误类。每种读取方式都会返回已解开信封的 contentBody,并将信封中的 title 提取到其中;技能代码只为 TBody 指定类型,绝不处理信封、{ items: [...] } 或 .value 包装。

随附文件(资源和参考文档会随此技能加载)

此技能的 assets/ 模板和 references/ 文档会与 SKILL.md 一同加载;请通过相对路径(assets/shared/…、assets/<framework>/…、references/…)引用,并将其内容视为可用。基础运行时文件会原样输出;只有 cmsContentType.ts 和渲染器模板包含 {{…}} 替换内容。切勿凭记忆重建模板——模板包含 StrictMode 钩子、消毒器接口以及正确的包调用位置。以下所有检测(框架、粘贴的 URL、Init/Embed/漂移)都要直接读取目标应用的文件;无需运行脚本。

交互模式(通过选项提问)

此技能是交互式的。每当提示中存在尚未决定的选项(框架、Init、漂移、内容类型、渲染目标、候选 bundle),都要通过包含 2–4 个带标签选项的选项选择问题提问,先列出推荐选项,然后等待回答——绝不能只让用户自由输入。仅在需要开放式回答时使用自由输入:组件/区域名称、URL、slug。完整措辞、选项和标题见 references/interaction-model.md;以下每处提问都必须遵循该文档。两种回答会终止流程(结束会话,不搭建任何内容):拒绝 Init,以及搜索结果为零条内容(见 HALT 行为)。

绕过模式(非交互式/自动化)。 当提示明确要求绕过交互模式(“非交互式”、“不要提问”、“全部继续/同意”、“自动继续”)时,不要提出任何选项选择问题:对于每个原本需要提问的问题,都采用其推荐选项作答并继续。这只会改变答案来源,不会改变流程逻辑,也不会覆盖终止条件——确实搜索结果为零条内容时仍须停止;存在安全默认值的情况下无法继续时,也须 HALT(未指定的原位放置、无法解析的候选 bundle)。每个问题的推荐回答见:references/interaction-model.md → 绕过模式。

框架检测(首先执行)

读取 <appRoot>/package.json(<appRoot> = 包含 package.json 的目录),合并 dependencies、devDependencies 和 peerDependencies 中的依赖名称;框架可能位于其中任一依赖类别:

  • react — 存在 react,且不存在 @angular/core → React 模板。
  • angular — 存在 @angular/core,且不存在 react → Angular 模板。
  • ambiguous — 两者都存在 → 停止,询问要以哪个框架为目标,并提供选项(references/interaction-model.md → 框架):React / Angular。
  • unknown — 两者都不存在,或无法读取 package.json → 停止;这不是受支持的 React/Angular 应用;不要搭建脚手架。

框架决定以下每个步骤使用的模板系列(assets/react/* 与 assets/angular/*);assets/shared/* 与框架无关,两者都会使用。

模式

Init(一次性搭建脚手架)。 首次 Embed 时,如果框架的基础文件集(参见 Init 与 Embed 检测)不存在,则在应用根目录运行 npm i @salesforce/ui-bundle-template-feature-cms-toolkit@latest --min-release-age=0,并写入共享运行时文件一次(先询问用户)。此 npm 安装是添加工具包的唯一方式;所有导入都使用 @salesforce/… 指定符。Init 永不覆盖:完整搭建的目录树无需处理;不完整的目录树表示存在偏差,必须停止(参见 Init 与 Embed 检测)。

逐字输出运行时文件(原因见 捆绑文件):逐个读取基础模板,并原样写入 src/cms/…,跳过任何已存在的目标文件(绝不覆盖)。始终复制 assets/shared/ 中的一对文件,以及检测到的框架对应的一对文件。完整目录树、复制集表格和回退方案:references/init-scaffold.md。

Embed(逐个提示词接线)。 根据指定一个 CMS 项目(或同类型的一组项目——参见 分组)的提示词,以及提示中说明的位置,运行以下流程。当既未说明位置,也未提出详情页请求时,步骤 4 会询问位置。每个步骤都是幂等的。

Embed 流程

Identity → Schema Sync → Ref Registration → Render Target → Verify
1. 身份识别 — 解析一个 { unauthenticatedUrl | contentKey, fqn, title }

有两种 ref 类型(参见 assets/shared/cmsCore.types.ts):外部 ref——条目有 unauthenticatedUrl(公共 CDN)→ 注册一个 CmsExternalRef(url),通过 getCmsContentByUrl 读取;独立媒体除外,其 url 就是资源本身,直接使用,不进行获取(规则 1/2;在步骤 3 捕获 altText/title);uiBundle 空间 ref——条目只有 contentKey → 注册一个 CmsRef(contentKey),通过 getCmsContentByKey 读取(工具包会通过 content-metadata.json 重新映射 key)。根据输入解析身份:

  • 粘贴的 URL——输入与 Experience CDN 交付 URL 匹配(正则表达式见 references/embed-recipes.md;不区分大小写,也能匹配嵌入正文中的 URL)。该 URL 即为 unauthenticatedUrl;跳过搜索 → 外部 ref。不匹配 → 继续执行下方逻辑。
  • 直接提供 contentKey(原始 contentKey,可选 channelId,无交付 URL):跳过搜索 → CmsRef。原样存储 contentKey;根据步骤 3 的 channel 解析关卡,将提供的任何 channelId 写入 public/content-metadata.json。如果 CmsRef 没有可解析的 channel(目录、提示词或用户均未提供),则必须停止——绝不能在没有 channel 的情况下渲染。
  • 自然语言提及:将原始提示词交给 experience-search-coordinate 能力(除非提示词指定了一个组,否则单选)。它会为每个条目返回 { unauthenticatedUrl, fqn, title, altText, contentKey };uiBundle 空间条目的 unauthenticatedUrl 为 null,因此使用 contentKey。对于媒体,将 altText/title 带到 CmsExternalRef 上(步骤 3)。

在以上三种情况中,内容类型未指定时 → 询问一次(references/interaction-model.md → 内容类型)。逐项解析与错误处理:

  • 没有内容 → 停止(终止)。 搜索没有结果 → 按 HALT 行为 → 终止停止 结束本轮。绝不捏造 URL/contentKey、盲目重试或放置占位符。
  • 搜索已取消/出错/不可用 → HALT(可恢复)。 请用户粘贴该条目的 unauthenticatedUrl 或其 contentKey(如果已知,还需提供 channelId 和类型);只有在用户提供身份信息后才能继续。绝不猜测。
  • 既没有 unauthenticatedUrl,也没有 contentKey → HALT("'{title}' 未提供交付 URL,也没有 contentKey——无法嵌入。")。
  • 否则:存在 unauthenticatedUrl → 外部 ref;否则,有 contentKey → uiBundle 空间 ref;fqn 为空 → 提出内容类型问题。

这些停止情况的问题措辞:references/interaction-model.md;完整目录:references/failure-modes.md。

组(N 个条目,类型相同)。 多个条目,或调用方传入多个 key/url,即构成一个组(内容类型相同;只询问一次类型问题)。差异如下:步骤 2 只运行一次,针对共享的 fqn(一个 <type>.ts 和一个渲染器,绝不逐项处理);步骤 3 循环处理 N 个 ref 条目,并在 ref 名称后添加短 contentKey/url 哈希,避免同名条目冲突;步骤 4 按照 组渲染目标 执行。尽力处理:跳过身份/架构验证失败的条目并报告,绝不因一个条目而 HALT 整个批次。组内同时包含 contentKey 和 unauthenticatedUrl 没有问题——每个 ref 根据自身形态进行分派。

2. 架构同步

OOTB sfdc_cms__news — 使用预定义架构,切勿获取。 元数据架构获取(ContentTypeBundle retrieve / MCP / SOQL)无法解析 OOTB Salesforce 内容类型,因此对于 fqn === 'sfdc_cms__news',完全跳过获取,并根据固定的三个字段生成 <Type>Body + <type>FieldTypes — bannerImage(Image→CmsImageField/'image')、body(RichText→string/'richText')、excerpt(Text→string/'text')— 内容逐字取自 references/schema-sync.md;不使用 sf project retrieve、MCP 或 SOQL。其他 OOTB 类型均未预定义;将它们视为自定义类型并获取。

OOTB 媒体类型 — 同样预定义,与 news 并行。 对于 fqn ∈ sfdc_cms__{image,audio,video,document},也跳过获取:该引用绑定到共享的 MediaRenderer(根据框架);不生成 <type>.ts,也不使用 heuristicRenderer。渲染器根据引用形态分支处理(外部 url → 直接使用;contentKey → 获取并按媒体类型解析;规则 2)。生成内容:references/heuristic-render-rules.md → Media types、references/init-scaffold.md。

对于自定义 fqn,通过 references/schema-sync.md 获取实时架构(使用不带前缀的 DeveloperName,去掉 sfdc_cms__/c__),将每个字段映射到 lightningType,再映射为 lowerCamel CmsFieldType 字面量(Text→'text'、RichText→'richText' 等;转换大小写,切勿直接复制 PascalCase 标记)。

  • Body 模块和渲染器均已存在 → 重新获取,与当前 <Type>Body 比较差异,仅重新生成 <framework>/types/<type>.ts 中标记下方的代码块(标记上方原样保留);完整重写渲染器。
  • 任一缺失 → 根据 assets/shared/cmsContentType.ts 和框架渲染器模板,在框架的 types/ 目录中生成二者;使用者通过直接路径(../types/{{TypeRenderer}})导入各个渲染器,因此无需更新汇总文件。
  • 任一标记缺失或格式错误 → 停止,要求用户恢复;切勿自动修复。获取失败 → 输出标记下方的代码块,并添加列出需手动填写字段的 TODO。

详情:references/schema-sync.md。

3. 注册 Ref

计算 EXT_<TITLE_SNAKE>(大写蛇形命名,ASCII),并将其追加到 src/cms/shared/externalRefs.ts 的 external-refs-begin 标记块中,采用与 Ref 类型匹配的形式,并在缺少相应 satisfies 类型时导入该类型。必须在放置前注册:ref('EXT_X') 的类型依据是 keyof typeof externalRefs,因此未注册的 Ref 按设计会导致编译错误。始终将 cmsType 设为 fqn DeveloperName,并使其与 satisfies 中的 <K> 匹配——省略此判别字段会导致错误类型保护静默失效。原样存储标识(绝不重新签署 URL 或手动映射 contentKey)。幂等性:名称相同且标识相同 → 跳过;名称相同但标识不同 → 停止(冲突)。两种 Ref 类型形式及其原因:references/embed-recipes.md。

外部 url Ref 上的媒体——记录 altText/title(不获取正文;规则 2):根据搜索移交的信息,在 CmsExternalRef 上设置这两个字段;对于 image/document,若两者均缺失 → 询问一次(媒体替代文本)。audio/video/contentKey Ref 跳过此步骤。

Channel 解析(仅限 CmsRef)——以目录为准。 CmsRef 必须解析出一个 Channel;按以下顺序解析,命中后即停止:(1)现有目录——public/content-metadata.json 中存在非空 channelId → 使用它,绝不覆盖;(2)提示词/标识——随 contentKey 提供了 channelId → 写入 public/content-metadata.json({ "channelId": …, "contents": [] }),如果文件不存在则创建;(3)两者皆无 → 询问用户提供 channelId,然后写入;(4)仍无法解析 → 停止(“'{title}' 是一个无法解析出 Channel 的 contentKey;渲染将失败。请提供 channelId,或将其添加到 public/content-metadata.json。”)。绝不写入占位或伪造的 Channel。**冲突:**提示词中的 Channel 与目录中的非空 Channel 不同 → 以选项选择的方式询问使用哪一个(references/interaction-model.md → Channel 冲突:保留目录值 = 不写入;使用提示词值 = 仅覆盖 channelId);只有获得确认后才能覆盖目录,绝不静默覆盖。外部 Ref 的 URL 中已包含其 Channel——无需检查。CMS_CHANNEL_ID_FALLBACK 仍仅作为谨慎使用的可选覆盖项(参见 assets/shared/externalRefs.ts)。结构、位置、优先级:references/embed-recipes.md。

4. 渲染目标 — 详情页或原位嵌入

按以下顺序确定内容的渲染位置:

  1. 提示词要求页面/路由 → 详情页分支,无需提问。
  2. 提示词指定原位放置位置(主页、侧边栏、主视觉区等) → 放置分支,无需提问。
  3. 两者都没有 → 提一个选项选择问题并等待(references/interaction-model.md → Render target):“我应该如何渲染‘{title}’?” — 专属详情页/路由 / 在现有视图中原位显示。若选择原位显示 → 接着用开放式问题询问 “‘{title}’应渲染在哪里?请指出一个组件、页面或区域。”,然后根据回答执行放置分支。

绝不猜测目标:不能默认使用详情页,也不能在未明确指定或回答目标时原位嵌入;未回答目标则必须停止。若提示词同时指定了页面和放置位置 → 询问哪个优先。

分组渲染目标(N 个项目)。 默认每个项目各用一个详情页。确定方式:(1) 提示词要求列表/网格/单页,或指定整个分组共用一个原位区域 → 列表/网格分支;(2) 提示词要求页面/路由 → 循环执行详情页分支,每个项目各生成一个页面和 slug;(3) 两者都没有 → 询问一次,默认使用详情页(references/interaction-model.md → Group render target):每个项目各用一个详情页 / 在单个页面上显示一个列表/网格。循环模式会对 slug 去重。

列表/网格分支 — 仅当目标解析选择此分支时执行。 生成框架的列表包装器(assets/<framework>/TypeList.*),每个 ref 生成一个渲染器,以确保各卡片的 fetch 相互隔离;然后通过放置分支放置一个节点,或通过详情页分支为其添加独立路由。列表与网格通过 className CSS 区分,而不是使用第二个组件(references/styling-scopes.md)。

放置分支。 在指定目标处插入对应类型的渲染器,如缺少相关导入则添加。操作具备幂等性。代码片段、配方和锚点相关的停止条件:references/embed-recipes.md。

详情页分支。 确认输入项(PageName、urlSlug、target ref、路由器文件),生成页面(基于 assets/<framework>/DetailPage.*),并将路由插入路由器的标记块中。仅追加、幂等且安全处理冲突。完整算法和前置条件停止规则:references/detail-pages.md。

样式。 此技能不会搭建 CSS 文件;展示样式以内联方式应用,并由提示词根据渲染目标指定。未指定方向时,使用默认阅读布局(居中的约 700px 列、大号字体、充足留白);原位嵌入保持简洁克制。类名钩子:references/styling-scopes.md。

5. 验证

仅对本技能写入或编辑的文件进行类型检查——范围有限,绝不循环执行。 执行一次 npx tsc --noEmit(React/Vite)或一次 npx tsc --noEmit -p tsconfig.json(Angular),然后只查看本次运行中本技能涉及文件的诊断信息;未涉及文件中的所有诊断均为已有问题,应忽略。最多进行一次修复:修复本技能生成的文件中的诊断,然后重新运行一次 tsc;绝不编辑逐字复制的基础文件(其中的诊断几乎总是工具包未解析导致的——将其作为环境说明报告,绝不修补)。不要运行 lint、build、ng build 或开发服务器;如果没有 tsc/tsconfig,则跳过并说明。然后报告写入/修改的文件、安装情况、类型检查结果、ref 身份、渲染器类型、渲染目标及任何停止条件。如果本次运行搭建了媒体,且其 ref 是 CmsRef(已认证渠道),则补充临时限制说明(内部应用目前尚不能渲染已认证渠道的媒体,后续版本将支持;使用公开 URL 的 CmsExternalRef 现在即可渲染);告知用户,但不要停止。完整修复政策和报告清单:references/verify.md。

代码生成护栏

五条规则,用于防止先前脚手架中重现的缺陷;每个生成的应用都必须满足这五条(违反任何一条都是阻塞性错误),且这些规则已写入 assets/ 模板 — 编辑时务必保持不变。下面是单行版;完整内容见 references/codegen-guardrails.md。

  • 规则 1 — 调用正确的工具包读取;绝不重新实现传输。 CmsExternalRef → 原样调用 getCmsContentByUrl(url);CmsRef → 调用 getCmsContentByKey/getCmsContentByKeys。绝不重新构造 URL、手动重映射 contentKey,或混用这两条路径。例外 — 不获取外部 url 引用中的独立媒体:其 unauthenticatedUrl 就是资源,直接用作元素的 src/href(规则 2);新闻/结构化的 CmsExternalRef 仍需获取。若 CmsRef 需要频道,将解析出的 channelId 和空 contents: [] 写入 public/content-metadata.json(如果文件不存在则创建;若已存在频道则绝不覆盖)— 并且绝不写入占位/虚假频道(工具包在目录缺失时会开放失败,但目录存在且内容错误时不会;部署流水线会填充真实的 contents)。
  • 规则 2 — 先根据引用形态,再根据媒体类型解析媒体 src。 首先根据引用形态分支:外部 url 引用直接使用 ref.url(不获取、不调用解析器,alt/title 使用引用本身的值);contentKey 引用则获取正文,并通过工具包的同步解析器解析 — image → resolveCmsImageUrl(sfdc_cms:media),audio/video/document → resolveMediaUrl(sfdc_cms:media.url)(仅传主题,绝不手动添加前缀)。媒体分发依据 ref.cmsType 和引用形态,绝不依据正文形态。
  • 规则 3 — 共享/去重的获取状态必须能在 React 19 StrictMode 下持续有效。 useCmsItem 通过模块级 inflight 映射,在挂载→清理→重新挂载期间去重:清理时设置本地 cancelled 标志,绝不能中止共享请求(Angular 的 CmsItemService 采用相同做法)。“运行一次正常,重新挂载就失败”属于阻塞性错误。
  • 规则 4 — 注入前解码 RichText;每个框架只走一条路径。 首先调用 decodeRichHtmlEntities,然后在唯一位置注入(React heuristicRenderer.tsx;Angular cms-content.component.ts 中的 [innerHTML])。绝不能同时解码和转义。 检测应匹配标签开头(<tag/<//<!)或 &lt;(RICH_TEXT_RE),绝不匹配单独的 < 或 value.includes('<')。
  • 规则 5 — 标量字段使用原始类型,绝不使用 { value } 包装。 Delivery 返回的标量是纯原始值(只有图像是对象,即 CmsImageField),因此读取 body.body,绝不读取 body.body.value(.value 解包结果始终为 undefined)。根据真实负载推导形状;条目的 title 位于信封根部,而非 contentBody 中。

HALT 行为

遇到以下情况时,技能会 HALT(不写入;报告失败文件、原因和最简修复方法;等待用户):框架不明确/未知;标记缺失/格式错误;内容既没有 unauthenticatedUrl 也没有 contentKey;引用名称与不同身份冲突;渲染目标未回答/无法解析;目标路由器不明确;slug 冲突;缺少详情页前置条件;Init/基础代码发生偏移;搜索已取消/出错(可恢复 — 用户粘贴一个身份)。多条目的选择按组渲染,不会触发 HALT。完整目录:references/failure-modes.md。

终止停止 — 会话结束,不生成任何脚手架(与可恢复的 HALT 不同):(1) 拒绝 Init — 对 Run Init? 选择“No”,因此无法生成运行时脚手架,技能也无法 Embed。(2) 搜索结果为零 — experience-search-coordinate 没有找到内容,这表示该条目尚未在此 uiBundle 空间中创作;告知用户先在那里生成内容,再重新运行。两种情况都不会写入、安装或猜测。详情:references/interaction-model.md → Terminal stops。

Init 与 Embed 检测

针对目标 uiBundle 根目录(包含 src/ 的目录),检查检测到的框架的必需基础文件集中的每个路径(不是只检查单个哨兵文件),然后根据已存在文件的数量进行分类(各框架文件列表和 bundle 解析规则:references/init-scaffold.md):

  • embed — 全部存在 → 运行 Embed 流程。
  • init — 全部缺失 → 提供选项并询问(references/interaction-model.md → Run Init?):是,进行脚手架搭建 / 否。选择是 → 运行 Init。选择否 → 终止(参见 HALT behaviour → Terminal stops):说明用户拒绝了 Init,不写入或安装任何内容,并结束本轮;不得转而运行 Embed 或只搭建部分脚手架。
  • drift — 部分存在、部分缺失 → 停止(运行时不完整时绝不运行 Embed)。逐字报告已存在与缺失的列表,然后询问(references/interaction-model.md → Complete a partial runtime?):是,写入缺失文件 / 否。选择是 → 逐字写入仅缺失的文件(读取→写入,跳过已存在文件;references/init-scaffold.md),然后重新检查;绝不触碰或“刷新”已存在的文件。选择否 → 停止。绝不默默补齐、覆盖或重置已存在的文件。

如果提示词说明运行时已经搭建好脚手架,这是一个强烈的 Embed 信号;仍须执行检查,但不要运行 Init。

Embed 仅处理增量——绝不重新输出运行时。 检测到 Embed 后,本次运行最多只写入新的 <framework>/types/<type>.ts + renderer,以及对 shared/externalRefs.ts 和渲染目标中的标记块进行编辑。每个已存在的基础文件都必须保持逐字节不变——不要重新搭建脚手架、重新复制、“刷新”或再次运行 npm install;重新输出 Init 模板(例如将 externalRefs 重置为 {})是阻断性错误。基础文件看起来有问题 → 作为 Init 漂移停止,绝不默默覆盖。

批量读取

默认按项读取:每个 renderer 独立读取,隔离每张卡片的失败情况。若要通过一次经过身份验证的往返读取一组已知的 contentKey,请直接调用 getCmsContentByKeys;无需搭建批量加载器。尽力返回每个键的结果;仅 contentKey 支持批量读取(外部 URL 单独读取)。references/bulk-loading.md。

不在范围内

动态发现 feed(“最新 10 条新闻”);跨引用审计工具;跨组织的媒体/图片引用映射;React + Angular uiBundles 以外的框架。

文件与参考资料

模板 — assets/shared/:cmsCore.types.ts、externalRefs.ts、cmsContentType.ts(基础文件 + 各类型的正文)、mediaLabels.ts。assets/react/:useCmsItem.ts、heuristicRenderer.tsx(renderer + RenderField 分发器)、TypeRenderer.tsx、TypeList.tsx、DetailPage.tsx、MediaRenderer.tsx。assets/angular/:cms-item.service.ts、cms-content.component.ts、TypeRenderer.component.ts、TypeList.component.ts、DetailPage.component.ts、MediaRenderer.component.ts。

文档(references/):package-api.md(工具包 API + 契约——事实依据)、interaction-model.md(措辞 + 终止条件)、init-scaffold.md(运行时目录树、复制集合、基础文件集)、schema-sync.md(检索 + 重新生成)、verify.md(修复策略 + 报告)、codegen-guardrails.md(完整规则 1–5)、embed-recipes.md(URL 正则 + 放置位置)、heuristic-render-rules.md、detail-pages.md、styling-scopes.md、bulk-loading.md、failure-modes.md。

评论

支持 Markdown