ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Huly 富文本核心包 @hcengineering/text-core:Markup 抽象模型、节点遍历与 textColor/textStyle 标记支持解析

Huly 富文本核心包 @hcengineering/text-core:Markup 抽象模型、节点遍历与 textColor/textStyle 标记支持解析 Huly 富文本核心包 hcengineering/text-coreMarkup 抽象模型、节点遍历与 textColor/textStyle 标记支持解析【免费下载链接】platformHuly — All-in-One Project Management Platform (alternative to Linear, Jira, Slack, Notion, Motion)项目地址: https://gitcode.com/GitHub_Trending/platform80/platform导读hcengineering/text-core是 HulyHuly — All-in-One Project Management Platform平台中承载结构化富文本Markup数据模型的基础包它不依赖任何 UI 框架以纯 TypeScript 定义了 Huly 全平台通用的「文档节点树MarkupNode 标记MarkupMark」抽象并提供了节点 DSL 构造器、树遍历、引用提取与序列化工具。本文以该包 CHANGELOG.md 为主线结合其 源码 与测试用例完整梳理 Markup 模型的节点/标记枚举、DSL 构造、遍历与引用解析、空判断与序列化工具并重点剖析 0.7.18 版本新增的textColor与textStyle标记在 Huly 富文本链路HTML 解析、ProseMirror 序列化中的底层实现。读完本文你将掌握 Huly 富文本数据的统一中间表示并能在自有功能中正确构造、遍历与比较 Markup 内容。一、包定位与版本演进1.1 包在仓库中的位置hcengineering/text-core位于 foundations/core/packages/text-core属于 Huly 的foundations/core基础设施层。其 package.json 表明依赖仅三个hcengineering/core提供Markup类型、Ref/Class/Doc基础类型、fast-equals深比较、hash-it属性哈希构建输出同时提供lib/index.jsCommonJS/ESM与types/index.d.ts通过 src/index.ts 统一导出dsl、model、reference、traverse、utils五个模块测试基于 Jest ts-jest见 jest.config.js。1.2 CHANGELOG 关键演进根据 CHANGELOG.md该包自 0.7.3 首发后经历以下关键节点版本日期变更内容0.7.32025-10-08初始发布Initial release0.7.42025-10-11升级到最新 platform righcengineering/platform-rig0.7.52025-10-14依赖更新0.7.172025-10-27仅版本号更新Version update only0.7.182025-10-27新增textColor与textStyle标记支持其中 0.7.18 是功能意义最大的一次它为 Huly 富文本引入了**文字颜色textColor与文字样式textStyle承载颜色等自定义样式属性**两类标记。当前仓库中包的发布版本已迭代至 0.7.19见 package.json 的version字段。二、Markup 数据模型节点与标记Huly 的富文本在存储与传输层面统一使用JSON 序列化的 Markup 字符串类型为hcengineering/core的Markup。text-core的价值在于为这一字符串定义了一套稳定的 TypeScript 结构化模型。2.1 节点类型枚举 MarkupNodeTypemodel.ts 定义了完整的MarkupNodeType枚举覆盖了块级、行内与扩展节点块级结构doc、paragraph、blockquote、horizontalRule、heading、codeBlock列表体系orderedList、bulletList、listItem以及taskList/taskItem、todoList/todoItem两组任务清单变体行内与媒体text、image带src/alt/width/height属性、file、emoji、hardBreak、subLink引用与嵌入reference指向平台内对象、mermaid图表、embed、comment、markdown表格体系table、tableRow、tableCell、tableHeader。2.2 标记类型枚举 MarkupMarkTypeMarkupMarkType 定义了作用于文本节点之上的「标记」即行内样式语义export enum MarkupMarkType { link link, em italic, bold bold, code code, strike strike, underline underline, textColor textColor, textStyle textStyle, highlight highlight }其中textColor与textStyle正是 0.7.18 新增的成员。textStyle在 ProseMirror 生态中是一个通用「样式容器」标记常用于携带任意 CSS 类、颜色等而textColor是语义化的颜色标记。二者的并存使 Huly 既能表达「这段文字是红色」textColor也能表达「这段文字带自定义样式属性」textStyle其attrs.color等。2.3 节点与标记的结构定义export interface MarkupMark { type: MarkupMarkType attrs?: Recordstring, any // 属性映射 } export interface MarkupNode { type: MarkupNodeType content?: MarkupNode[] // 子节点列表 marks?: MarkupMark[] attrs?: Attrs text?: string }MarkupNode是一个递归树节点content承载子节点marks承载行内标记text仅用于text节点。emptyMarkupNode()返回doc paragraph的最小合法空文档。另外 ReferenceMarkupNode 为reference节点约束了id、label、objectclass三个必选属性。三、DSL 构造器以类型安全的方式构建 Markup 树直接手写 JSON 易出错dsl.ts 提供了一组工厂函数节点构造nodeDoc(...)、nodeParagraph(...)、nodeText(text)、nodeImage(attrs)、nodeReference(attrs)标记包装markBold(node)、markCode(node)、markItalic(node)、markStrike(node)、markUnderline(node)、markLink(attrs, node)内部工具node(type, ...content)、mark(type, attrs)、withMarks(node, ...marks)。例如构造一个带链接的加粗段落import { nodeDoc, nodeParagraph, nodeText, markBold, markLink } from hcengineering/text-core const doc nodeDoc( nodeParagraph( markLink({ href: https://example.com, title: Example }, markBold(nodeText(Hello Huly))) ) ) // 序列化JSON.stringify(doc) 即得到平台 Markup 字符串这种「节点 标记」的分层设计标记挂在节点上而非作为节点类型与 ProseMirror 的 mark 体系一脉相承使得样式可叠加如同时boldlink。四、节点遍历traverse 模块traverse.ts 提供了四组遍历 API是后续所有 Markup 处理提取文本、提取引用、HTML 序列化的底层基座traverseNode(node, fn)深度优先遍历整棵树回调返回false时剪枝不再进入该节点的子节点traverseNodeMarks(node, f)仅遍历单个节点上的标记traverseNodeContent(node, f)仅遍历直接子节点traverseAllMarks(node, f)遍历整棵树所有节点上的所有标记回调签名(node, mark)。traverse.test.ts 中的用例验证了两个关键行为回调会以(node, parent)形式收到当前节点与其父节点根节点父为undefined当回调对paragraph返回false时其子text节点不会再被访问调用次数从 2 变为 1。五、平台对象引用reference 模块Huly 文档可以内嵌指向平台内任意对象任务、联系人、文档等的reference节点。reference.ts 提供export interface Reference { objectId: RefDoc objectClass: RefClassDoc parentNode: MarkupNode | null } export function extractReferences (content: MarkupNode): ArrayReferenceextractReferences基于traverseNode全树扫描凡是type MarkupNodeType.reference的节点即按id与objectclass提取为RefDoc/RefClassDoc引用并对相同对象去重同 id 同 class 只保留首个同时记录其父节点parentNode。这一机制支撑了 Huly 文档中对其他对象的「 提及」与反向引用功能。六、工具集序列化、比较与文本提取utils.ts 是日常使用最频繁的模块。6.1 空判断与相等比较EmptyMarkup/isEmptyMarkup(markup)判断空内容。isEmptyNode将hardBreak视为空而horizontalRule、image、reference、emoji、subLink、table视为非空其余节点递归判断text.trim()与非空子节点areEqualMarkups(m1, m2)/areEqualJson(j1, j2)结构化相等比较——类型、文本、子节点数组、标记数组、属性映射逐项比对属性比较前会先过滤掉null/undefined值并使用fast-equals做深比较。两个空文档视为相等。6.2 序列化与容错解析jsonToMarkup(json)把MarkupNode树JSON.stringify成平台Markup字符串markupToJSON(markup)反向解析。容错逻辑utils.ts若字符串以{开头则按 JSON 解析并调用traverseAllMarks对所有标记执行stripHash剥离 Yjs/ProseMirror 协作层附加在标记名后的 8 位哈希后缀如bold--c0decafe→bold若解析失败或不是 JSON历史遗留的 HTML 或纯文本则降级包装为doc paragraph text保证任何脏数据都不会让下游崩溃。6.3 文本提取与哈希工具stripTags(markup, textLimit 0)提取纯文本支持字符数上限超出截断并追加省略号…硬停后停止遍历块级节点paragraph/table/doc/blockquote之间插入空格reference节点输出label形式。常用于列表卡片、搜索结果等处的摘要预览markupToText(markup)提取文本并以\n\n分隔段落hashAttrs(attrs)基于hash-it对属性对象计算 8 位十六进制哈希hash 0保证无符号stripHash(attrName)按正则/(.*)(--[a-zA-Z0-9/]{8})$/剥离协作层哈希后缀。utils.test.ts 对hashAttrs同输入同哈希、不同输入不同哈希、固定长度 8与stripHash剥离合法哈希、保留无哈希原名、拒绝长度不符或非法 base64 的后缀均有完整断言。七、textColor 与 textStyle0.7.18 标记的落地链路0.7.18 的「add support for textColor and textStyle marks」不止是枚举新增而是打通了从外部格式解析 → 中间 Markup → 编辑器渲染的整条链路7.1 枚举定义textColor与textStyle已加入 MarkupMarkType所有基于text-core的工具序列化器、比较器、遍历器会自动兼容这两种新标记无需逐处改动。7.2 HTML 解析侧text-html 包的 parser.ts 在解析带颜色的 HTML如span stylecolor: red时会依次打开textColor标记携带颜色属性与textStyle标记携带完整样式属性再在文本节点结束后对称地closeMark关闭二者——正是靠text-core中新增的这两个枚举HTML 的颜色信息才能无损映射进统一的 Markup 中间表示。7.3 编辑器序列化与命令侧在 text 包的 marks/colors.ts 中可以看到对应的 ProseMirror 集成其 schema 扩展名为textColor、types: [textStyle]即颜色是挂载在textStyle标记之上的一种样式键并导出设置/取消颜色的编辑器命令——chain().setMark(textStyle, { color }).run()与chain().unsetMark(textStyle).run()。这意味着 Huly 编辑器中用户选择的文字颜色最终会被序列化为带textColor/textStyle标记的 Markup 节点树与text-core的模型一一对应。参考实现见 common-kit.ts 与 server-kit.ts。7.4 协作与比较兼容由于markupToJSON在解析时会统一执行stripHash剥离 Yjs 协作层附加的标记名哈希textStyle--xxxxxxxx会还原为textStyle因此即使在多人实时协同编辑的场景下areEqualMarkups等比较逻辑也能正确识别 0.7.18 新增标记不会因哈希后缀造成误判。八、典型应用场景小结摘要/搜索预览stripTags(markup, 140)一行生成带省略号的纯文本摘要文档内 提及extractReferences(node)提取全部平台对象引用并去重内容变更检测areEqualMarkups(prev, next)判断富文本是否实际变化空文档统一视为相同数据容错markupToJSON兜底解析历史脏数据HTML/纯文本/损坏 JSON保证下游渲染不崩溃颜色支持扩展如需让平台富文本支持文字颜色只需在MarkupMarkType中声明对应标记如 0.7.18 的textColor/textStyle并在各格式解析器HTML/Markdown与编辑器 schema 中注册映射即可。结语hcengineering/text-core虽小却是 Huly 全平台富文本能力的唯一事实来源从节点/标记的模型枚举到 DSL 构造、树遍历、引用提取、空判断与序列化工具再到 0.7.18 引入的textColor/textStyle标记支持它让文档内容在 HTML、Markdown、编辑器与存储之间始终以统一的结构化 Markup 呈现。结合 text-core 源码、遍历测试 与 HTML 解析实现读者可以将其直接复用或扩展于自有模块实现类型安全、可比较、可遍历的富文本数据管道。【免费下载链接】platformHuly — All-in-One Project Management Platform (alternative to Linear, Jira, Slack, Notion, Motion)项目地址: https://gitcode.com/GitHub_Trending/platform80/platform创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表