- 开发工具
【免费下载链接】remeda
A utility library for JavaScript and TypeScript.
本篇指南讲解 Remeda(JavaScript/TypeScript 工具库)文档站中Mapping(迁移对照)文档的编写规范:从文件放置位置、frontmatter 元数据,到标题层级、正文写法与代码示例组织方式。读完你将掌握如何为 lodash、Ramda、just 等第三方库的每个函数,撰写一条格式正确、能被文档站正确渲染并进入检索体系的对照条目,同时了解背后的 Astro 内容集合(Content Collection)加载与渲染机制。
Mapping 文档是什么:Remeda 文档站的"迁移对照层"
Remeda 是一个面向 JavaScript 与 TypeScript 的工具库,其文档站点位于仓库的 packages/docs 目录,采用 Astro 构建。在文档站中,除了面向 Remeda 自身 API 的函数文档(functions 集合)之外,还存在一套独立的mapping 集合(迁移对照集合):为 lodash、Ramda、just 等流行库的每个函数,给出"该函数对应 Remeda 的哪个 API、存在哪些行为差异、如何改写"的对照说明,帮助从其他函数库迁移到 Remeda 的开发者快速定位替代方案。
该集合的约定分散在两处:一是 packages/docs/src/content/mapping/content.config.ts 中定义的加载器与 schema(决定文件如何被发现、元数据如何校验);二是仓库根目录下 .claude/rules/content-mapping.md 这份规则文档(决定条目正文如何书写)。本文将以这份规则文档为核心,结合集合定义、渲染组件与大量既有条目,完整还原 Mapping 文档的编写规范。
文件布局:库目录即命名空间,文件名即函数名
Mapping 文档以 Markdown 文件形式存放在packages/docs/src/content/mapping/<library>/目录下,每个库一个子目录。当前仓库中已存在三个库的对照目录:
- packages/docs/src/content/mapping/lodash:lodash 函数对照(条目最多,按 Array、Math、Object、String、Util、Function 等分类组织);
- packages/docs/src/content/mapping/ramda:Ramda 函数对照;
- packages/docs/src/content/mapping/just:just 函数对照。
文件名的约束由 mapping/content.config.ts 中的globloader 决定:
export const mappingCollection = defineCollection({ loader: glob({ base: import.meta.dirname, pattern: "**/[^_]*.md", // We treat the file name as the function name, and function names are case- // sensitive, but the default ID generator lowers the case. generateId: ({ entry }) => entry.replace(/\.md$/, ""), }), // ... });- 文件名即函数名:例如 packages/docs/src/content/mapping/lodash/camelCase.md 表示对照 lodash 的
camelCase;packages/docs/src/content/mapping/just/has.md 表示对照 just 的has; - 大小写敏感:loader 特意覆盖了默认的 ID 生成器(默认会把 ID 转为小写),因为函数名区分大小写,
camelCase与camercase不能被合并; - 以
_开头的文件被排除在内容集合之外:pattern: "**/[^_]*.md"保证__MISSING.md、___TODO.md这类工作文档不会被当成正式条目加载; - ID 结构固定为「库名/函数名」两层:工具函数 libraries.ts 遍历全部条目,通过 invariant 断言每个 ID 都必须位于库目录之下(
hasAtLeast(parts, 2)),且不允许出现更深层级的子目录(parts.length <= 2),否则直接抛错。
frontmatter:category与remeda两个必填字段
每个 Mapping 文档的 frontmatter 由 content.config.ts 中的 zod schema 严格校验(.strict()意味着出现未知字段会被拒绝):
schema: z .object({ category: z.string().min(1), remeda: reference(functionsCollectionName).optional(), }) .strict() .readonly(),category(必填,非空字符串):该函数在源库中归属的分类,例如 lodash/add.md 的category: Math、lodash/assign.md 的category: Object、just/has.md 的category: Objects。分类会被用于页面上的分组与侧边导航(见下文渲染链路);remeda(可选):对 Remeda 自身 functions 集合(即 functions/content.config.ts 中通过 TypeDoc 从remeda/src/index.ts生成的 API 文档)的交叉引用。填写后,条目卡片顶部会渲染一个指向对应 Remeda 函数文档的"跳转链接";留空则意味着 Remeda 目前没有直接对应的函数(这类条目会在页面上以候选状态展示,见下文"特殊文件与候选机制")。
一个最小的合法条目甚至可以不写正文、只有 frontmatter,例如 lodash/cond.md:
--- category: Util remeda: conditional ---标题层级规则:正文子标题必须从####(h4)开始
这是 .claude/rules/content-mapping.md 中唯一一条直接规定写作格式的规则,也是本篇最核心的约定:
Body sub-headings start at
####(h4) — entries render inside an<article>whose function name is the<h3>
即:条目正文中的子标题从####起跳,不允许使用##或###。原因在于渲染结构——每个映射条目不是以独立的整页 HTML 文档呈现,而是被渲染成一张「卡片(card)」,卡片内已经有了两层标题占用:
- 函数名标题是
<h3>:由 h3-card-title.tsx 中的H3CardTitle组件渲染,它通过CardTitle asChild把标题元素强制固定为<h3>; - 卡片的语义容器是
<article>:由 article-card.tsx 中的ArticleCard组件渲染(Card asChild将外层元素固定为<article>); - 正文通过 Prose 组件挂载到卡片内。如果正文里再出现
###,就会和函数名的<h3>平级甚至产生层级混乱,破坏"article(h3)→ 正文子标题(h4)"的语义嵌套。
因此,写作条目正文时,若需要分小节,一律使用####。从既有的高质量条目中可以看到这一规则的实际运用,例如 lodash/camelCase.md 用#### Simple strings、#### Normalized、#### Missing input三个 h4 小节组织不同场景;lodash/debounce.md 用#### Reference、#### With call arguments、#### With cached value组织三种复杂度的参考实现。
正文写法:差异优先的条目化说明 + 双栏代码对照
Mapping 条目的正文不是 Remeda API 的复述,而是聚焦「从源库迁移到 Remeda 时需要知道的差异」。其标准写作模式可归纳为"差异要点列表 + 场景化代码对照":
行为差异用无序列表逐条列出
每个差异点单独成一条 bullet,直截了当地指出"Lodash 怎么做 / Remeda 怎么做"。以 lodash/camelCase.md 为例,它列出四条差异:
- 分词策略不同:Lodash 尝试伪语言学分词(pseudo-linguistic word splitting)来处理特殊字符,结果可能不准确;Remeda 采用基于 type-fest 定义的更简单分词方案,仅适用于标识符、内部 key 等简单字符串;涉及语言与区域敏感的文本处理,应改用原生
Intl.Segmenter; - 连续大写处理不同:Remeda 对连续大写字符的处理与 Lodash 不同,需要传第二个参数
{ preserveConsecutiveUppercase: false }才能得到与 Lodash 一致的结果; - 归一化(normalization)缺失:Lodash 在分词前会执行
deburr、移除撇号等归一化(见 lodash/deburr.md);Remeda 分词更简单、不含这些归一化,需要时需手动处理; - 入参边界不同:Lodash 允许无参调用或传入
undefined,Remeda 不支持,需在调用前自行兜底。
再如 lodash/assign.md,差异点聚焦在**可变性(mutability)与可变参数(variadic)**两个维度:
- Lodash 的
assign是就地合并,直接修改第一个入参;Remeda 的merge/mergeAll总是返回新对象,绝不改动任何输入对象; - Lodash 的
assign接受任意数量的参数;Remeda 中合并两个对象用merge,合并两个以上对象改用接收对象数组的mergeAll。
just/has.md 则直接点出 API 能力差距:just 的has支持深层路径(如["a", "b"]、"a.b"),而 Remeda 的hasProp只检查单层 key。
代码示例采用"源库写法 → Remeda 写法"的双栏对照
正文中的代码统一用 fenced code block,并严格标注注释前缀区分两侧。最简单的形式如 lodash/compact.md:
// Lodash compact(DATA); // Remeda filter(DATA, isTruthy);复杂场景则按差异拆成多个 h4 小节分别给出可运行片段。仍以 camelCase 为例,#### Simple strings给出直译写法:
// Lodash _.camelCase(input); // Remeda toCamelCase(input, { preserveConsecutiveUppercase: false });#### Normalized给出"Remeda + 原生 API"的等价还原(先normalize("NFD")提升变音符号为独立字符,再用正则剔除撇号与独立变音字符):
// Lodash _.camelCase(input); // Remeda + Native toCamelCase( input // "Promote" diacritics to be independent characters in the string. .normalize("NFD") // Remove apostrophes and all independent diacritic characters. .replace(/['\u2019\u0300-\u036f]/g, ""), { preserveConsecutiveUppercase: false }, );#### Missing input给出入参兜底的两种等价写法(显式条件分支或?? ""合并)。这种"逐差异小节 + 可复制代码"的结构,正是 Mapping 条目正文的标准形态。
特殊条目的写法:deburr与 Lodash 文档内锚点
Mapping 正文中引用同库其他条目时,原文档内使用锚点链接(如 camelCase 正文中的deburr)。在仓库内它们对应packages/docs/src/content/mapping/lodash/deburr.md这一实际文件;交叉引用 Remeda 自身 API 时同样使用锚点形式(如 assign 正文中的mergeAll,其实现位于 packages/remeda/src/mergeAll.ts)。撰写新条目时,应保持这种"以函数名作锚点"的引用习惯,使文档站页面内跳转与仓库文件结构一一对应。
渲染链路:一个条目如何变成页面上的卡片
Mapping 文档最终通过 packages/docs/src/pages/migrate/[library].astro 渲染成/migrate/<library>静态页面。整条渲染管线如下:
getStaticPaths调用 libraries.ts 的getAllMappedLibraries,从内容集合中推导出所有库名(lodash、ramda、just),为每个库生成一个页面;- 页面主体调用 entries.ts 的
getMigrationMappings(library):先按id过滤出该库的全部条目,用sortBy按字典序(忽略大小写)排序,再用groupBy按 frontmatter 的category分组,最后经 sort-categories.ts 排序——其中Deprecated分类被强制排到末尾,其余分类按字母序排列; - 每个分类渲染为一个 docs-section.astro 区块(其
<h2>仅作屏幕阅读器标签,sr-only),区块内每个条目渲染为一个 mapping-function-card.astro 卡片; MappingFunctionCard组装卡片内容:函数名(h3)、右侧"查看源库文档"外链按钮、分类 Badge、编辑链接,以及 frontmatter 中remeda引用对应的函数跳转;正文非空时才通过Prose渲染 Markdown 内容。函数名指向源库官方文档的 URL 由 urls.ts 的mappingUrl按库生成(lodash →https://lodash.com/docs/4.17.15#<name>,ramda →https://ramdajs.com/docs/#<name>,just →https://anguscroll.com/just/just-<name>)。
从这链路可以推断:category 字段不仅决定页面分组,还决定导航结构——entries.ts 的forNavbar会把「分类 → 条目函数名」的映射转成侧边导航条目,供 docs-page.astro 布局使用。
特殊文件与候选机制:__MISSING、___TODO与未提供函数
mapping 目录中还包含两类被 loader 排除([^_]*模式)的工作文档,它们不属于正式条目,但反映了规范背后的维护流程:
- lodash/__MISSING.md:lodash 中"尚未建立映射"的函数清单,按 Array / Date / Function / Lang / Number / Object / Seq / Util / String 分组罗列(如
fill、chain、thru、stubArray等),String 组已标注完成。该文件开头的 TODO 指向 You-Dont-Need-Lodash-Underscore 这一参考来源,说明清单主要用于评估"这些函数是否需要补写对照"; - lodash/___TODO.md:记录 Mapping 体系的待办与决策方向,其中与写作规范直接相关的有:lodash 的 collection 组函数实为「数组/对象混合」函数,需要给出通用引导(主要建议使用
values);lodash 多数数据入参接受null | undefined而 Remeda 不接受;lodash 的iteratee通常只接收一个参数而 Remeda 通常接收三个参数(index、data)等。
此外,对于"Remeda 未提供对应函数"的条目,TODO 中提出引入特殊标记(如candidate: true)来渲染鼓励用户提交使用场景的横幅,并点名pad、padStart、padEnd、parseInt、repeat、replace等候选函数——从源码结构看,该机制在写作规范中对应"frontmatter 中remeda字段留空"这一状态,MappingFunctionCard对此已有相应的无跳转链接渲染分支。
实操:编写一条 Mapping 文档的完整步骤
综合以上规范,在 Remeda 仓库中新增一条映射条目的标准流程是:
- 确定目标库与函数,创建文件
packages/docs/src/content/mapping/<library>/<函数名>.md(函数名保持与源库一致的大小写); - 填写 frontmatter:
category使用源库中的函数分类(如 lodash 的Math、Object、String、Util);若 Remeda 有对应实现,在remeda字段引用该函数(例如remeda: toCamelCase),无对应实现则留空; - 正文第一层小标题一律从
####开始(h3 已被函数名占用); - 先用无序列表逐条罗列与源库的行为差异(可变性、参数边界、分词/归一化策略、类型差异等);
- 为每个差异配一个 fenced code block,以
// Lodash/// Remeda(必要时// Remeda + Native)注释区分两侧写法,代码需可复制运行; - 若 Remeda 没有直接对应函数,给出基于现有 API(如
filter+isTruthy还原compact)的组合替代方案,或引用funnel等工具的组合实现(参见 lodash/debounce.md 中基于funnel的 debounce 参考实现,其完整版位于 packages/remeda/src/funnel.lodash-debounce.test.ts 与 packages/remeda/src/funnel.lodash-debounce-with-cached-value.test.ts,可整段复制); - 不要使用
##/###、不要添加 schema 之外的 frontmatter 字段、不要改变文件命名大小写,否则会被 loader 排除或 zod 校验拒绝。
结语
Mapping 文档是 Remeda 文档站中连接第三方函数库与 Remeda API 的桥梁层。它的写作规范可以浓缩为两句话:frontmatter 严格二字段(category+remeda)、文件名即函数名;正文标题从 h4 起跳、以"差异列表 + 双栏代码"为骨架。这两条约定分别由 content.config.ts 的 zod schema 与 .claude/rules/content-mapping.md 规则文档固化,并由 mapping-function-card.astro 等组件在渲染时兑现。对贡献者而言,参考 lodash/camelCase.md(差异拆解范本)、lodash/debounce.md(复杂参考实现范本)与 lodash/assign.md(语义差异范本)三份既有条目,即可快速写出符合规范、可被正确渲染和检索的迁移对照文档。
- 开发工具
【免费下载链接】remeda
A utility library for JavaScript and TypeScript.
相关推荐
Incus 文档写作语法速查表:Markdown 与 MyST 混排的 Sphinx 文档编写规范
Incus 文档写作语法速查表:Markdown 与 MyST 混排的 Sphinx 文档编写规范 Incus 项目的官方文档( doc https://lin
后端虚拟化容器运行时Livewire 文档写作规范:官方 docs 编写规则与源码实现对照指南
Livewire 文档写作规范:官方 docs 编写规则与源码实现对照指南 本篇技术指南基于 Livewire 仓库内实际生效的文档编写规范( .claude/
后端前端GoReleaser 文档编写规范:基于 Hugo 站点的技术文档作者指南
GoReleaser 文档编写规范:基于 Hugo 站点的技术文档作者指南 本文以仓库内 .copilot/skills/authoring docs/SKIL
开发工具CI/CD构建工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考