ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

loop-sync CRLF Frontmatter 回归测试:为 Windows 贡献者守护 YAML 解析的正确性

loop-sync CRLF Frontmatter 回归测试:为 Windows 贡献者守护 YAML 解析的正确性 人工智能AI AgentAgent 工作流CLI研发协作AI 技能MCP 服务【免费下载链接】loop-engineeringPractical patterns, starters CLI tools for loop engineering with AI coding agents. Design systems that prompt and orchestrate agents (inspired by Addy Osmani and Boris Cherny). Includes loop-audit, loop-init, loop-cost.项目地址https://gitcode.com/gh_mirrors/lo/loop-engineering点击查看免费下载本文围绕 loop-engineering 仓库中 scripts/issue-bodies/loop-sync-crlf-tests.md 这一任务文档展开讲解loop-sync工具中extractFrontmatter对 LF / CRLF 换行符的处理逻辑以及如何为它补齐回归测试防止 Windows 贡献者的提交在未来的重构中被悄悄破坏。导读loop-sync是 loop-engineering 仓库中负责检测并同步 Loop 配置文件STATE.md、LOOP.md、gate.yaml、docs/safety.md等漂移的 CLI 工具。社区 PR #476 修复了extractFrontmatter在 Windows 换行符\r\n即 CRLF下的解析问题但如果缺少回归测试任何未来的改动都可能重新破坏 Windows 贡献者的体验。本文以 loop-sync-crlf-tests.md 这份任务说明为主体骨架结合仓库源码与既有测试完整还原为什么 CRLF 会破坏 frontmatter 解析、修复后的解析规则是什么、回归测试应该覆盖哪些边界条件以及如何运行与验证测试。背景任务文档的由来与价值该任务文档是一份典型的好第一议题good first issue描述明确给出了目标、改动文件、验收标准与预估时间Goal为loop-sync的 CRLF frontmatter 解析添加回归测试Pain source社区 PR #476 修复了extractFrontmatter对 Windows 换行符\r\n的处理。没有测试未来的改动可能再次破坏 Windows 贡献者Files扩展tools/loop-sync/test/sync.test.mjs可选在tools/loop-sync/test/fixtures/下添加 fixture 文件Estimated time约 30–40 分钟标签tooling。它与仓库中的另一份文档 windows-contributor-notes.md 互为呼应——后者建议在 docs/QUICKSTART.md 中补充 Windows/CRLF 注意事项并明确指向loop-sync frontmatter LF/CRLF support (after #476)。这说明 CRLF 支持并非孤立的修复而是 Windows 贡献者体验整体建设的一部分。为什么 CRLF 会破坏 frontmatter 解析Markdown frontmatter 的规范形态是以---作为开闭围栏中间是key: value形式的键值对--- key: value --- body text在 Linux/macOS 上行尾是\nLF在 Windows 上文本文件的行尾通常是\r\nCRLF。Git 的core.autocrlf配置若未正确设置可能导致仓库中的STATE.md、LOOP.md或 SKILL.md 以 CRLF 提交。此时 frontmatter 长这样---\r\n key: value\r\n ---\r\n body text\r\n问题在于如果解析器按\n切分后不做处理value\r中的\r会被当作值的尾部字符导致解析出的 key 或 value 带上隐藏的\r后缀。这会让依赖 frontmatter 精确匹配的逻辑例如scanSkillsDirectory读取 SKILL.md 的version字段、loop-sync对比STATE.md ↔ LOOP.md的结构相似度产生看起来一样、实际不相等的漂移误报也就是 QUICKSTART 中提示的loop-syncreports drift unexpectedly on Windows。修复后的解析规则源码级还原当前仓库中extractFrontmatter的实现位于 tools/loop-sync/src/sync.ts编译产物在 tools/loop-sync/dist/sync.js。整体逻辑可以拆成四个关键分支1. 开围栏同时接受 LF 与 CRLFif (content.startsWith(---\n) || content.startsWith(---\r\n)) {只有文件严格以---\n或---\r\n开头时才进入 frontmatter 解析。这正是验收标准中第三条---hello开围栏后没有换行必须被拒绝/不当作 frontmatter的判定基础——---hello既不以---\n开头也不以---\r\n开头直接被拒。2. 闭合围栏必须前有换行const endIndex content.indexOf(\n---, 3);通过搜索\n---定位闭合围栏这意味着闭合围栏之前必须存在一个换行符。若文件以---\nkey: value\n---oops\n结尾indexOf(\n---, 3)无法匹配到合法的\n---序列---oops前虽有换行但\n---后紧跟oops而不是行尾/换行从而被拒绝。既有测试 sync.test.mjs 的 rejects closing fence without preceding newline 用例验证的正是这一边界。3. 闭合后校验行尾或换行含\rif (endIndex ! -1 (endIndex 4 content.length || content[endIndex 4] \n || content[endIndex 4] \r)) {找到\n---后闭合围栏之后的内容必须是文件末尾、\n或\r兼容 CRLF 的\r\n尾部。这样---\nkey: value\n---oops这类闭合围栏后跟多余字符的畸形输入会被拒绝。4. 键值按\r?\n切分并 trimfor (const line of fmContent.split(/\r?\n/)) { const colonIndex line.indexOf(:); if (colonIndex ! -1) { const key line.slice(0, colonIndex).trim(); const value line.slice(colonIndex 1).trim(); frontmatter[key] value; } }这是修复的核心用正则/\r?\n/切分 frontmatter 内容无论行尾是 LF 还是 CRLF 都能正确分行随后对 key 与 value 都执行.trim()把可能残留的\r一并清除。因此 CRLF 输入中的value\r最终被解析为干净的value。这正是任务验收标准中CRLF frontmatter 解析出的 key 不带尾部\r的底层保证。回归测试任务要求的三个验收点任务文档给出了三条明确的验收标准而仓库的既有测试已经把它们全部落地在 tools/loop-sync/test/sync.test.mjs 的describe(extractFrontmatter)块中。验收点 1LF frontmatter 仍然正常解析既有行为不被破坏test(parses LF frontmatter, () { const { frontmatter, body } extractFrontmatter( ---\nkey: value\n---\nbody text\n, ); assert.deepEqual(frontmatter, { key: value }); assert.equal(body, body text\n); });回归测试首先锁定既有行为LF 输入必须解析出{ key: value }且 body 保持body text\n原样。这是防回归的基线——修复 CRLF 不能以破坏 LF 为代价。验收点 2CRLF frontmatter 解析出不带\r的键值test(parses CRLF frontmatter without trailing carriage returns, () { const { frontmatter, body } extractFrontmatter( ---\r\nkey: value\r\nother: thing\r\n---\r\nbody text\r\n, ); assert.deepEqual(frontmatter, { key: value, other: thing }); assert.ok(!Object.values(frontmatter).some((v) v.endsWith(\r))); assert.ok(!Object.keys(frontmatter).some((k) k.endsWith(\r))); assert.equal(body, body text\r\n); });这个用例直击任务文档的核心验收标准CRLF frontmatter---\r\nkey: value\r\n---\r\nbody形态必须解析出不带尾部\r的 key 与 value。断言同时覆盖 value 和 key 两个方向确保.trim()的修复不遗漏任何一侧。body 部分则验证body text\r\n原样保留body 不做换行符归一化。验收点 3开围栏后无换行的---hello必须被拒绝test(rejects opening fence without newline (---hello), () { const { frontmatter } extractFrontmatter(---hello\nkey: value\n---\n); assert.deepEqual(frontmatter, {}); });输入---hello不满足content.startsWith(---\n)或content.startsWith(---\r\n)因此extractFrontmatter返回空对象{}——这防止了将非 frontmatter 内容误判为配置元数据。既有测试还额外补了一个对称用例闭合围栏后跟oops被拒绝虽然不是任务文档的显式要求但属于同一围栏合法性边界的自然延伸。extractFrontmatter 在 loop-sync 中的真实调用链extractFrontmatter并非孤立函数它是 loop-sync 读取配置元数据的底层基础设施。核心调用点位于 tools/loop-sync/src/sync.ts 的scanSkillsDirectoryconst skillMd path.join(skillPath, SKILL.md); const content await readFileContent(skillMd); if (content) { const { frontmatter } extractFrontmatter(content); skillsVersions.set(entry, frontmatter.version || unknown); }scanSkillsDirectory会扫描skills/、.grok/skills/、.claude/skills/、.codex/skills/四个目录对每个技能的SKILL.md调用extractFrontmatter读取version字段。如果 Windows 贡献者在编辑 SKILL.md 时引入了 CRLF而解析器把version\r当作版本号loop-sync就会报告版本漂移。换言之CRLF 回归测试保护的不仅是extractFrontmatter本身更是整个 loop-sync 的Skills version updates检查链路对应 README 中的检查项 4。此外runSync中STATE.md ↔ LOOP.md的一致性检查sync.ts依赖readFileContent读入的原始文本进行结构相似度对比CRLF 残留同样会造成similarity计算偏差。这正是 docs/QUICKSTART.md 中如果 loop-sync 在 Windows 上意外报告漂移先检查STATE.md/LOOP.md的 CRLF这条排障建议的技术根因。如何运行与验证测试任务的验收标准最后一条是cd tools/loop-sync npm test通过。仓库的 package.json 定义了完整的测试链路scripts: { build: tsc, test: npm run build node --test test/*.test.mjs, prepublishOnly: npm test }npm test会先执行tsc把src/*.ts编译到dist/再用 Node 内置的node:test运行test/*.test.mjs。注意测试文件顶部import { runSync, formatReport, extractFrontmatter } from ../dist/sync.js——测试对象是编译产物而非 TypeScript 源码因此每次改动src/sync.ts后必须先构建再跑测试。这一点从 tools/loop-sync/README.md 的 Development 段落也能看到同样顺序cd tools/loop-sync npm install npm run build npm test从 scripts/issue-bodies/loop-sync-crlf-tests.md 的定位看这份任务是面向贡献者的引导式任务文末Comment Ill take this to get assigned是标准的好议题认领流程预估 30–40 分钟、标签tooling。对完成者而言最小改动路径有两种扩展现有测试文件在 sync.test.mjs 的describe(extractFrontmatter)块中追加用例——仓库目前已经包含了任务要求的所有用例这是推荐做法改动集中、可读性好添加 fixture 文件当用例较长或需要模拟真实文件时可在tools/loop-sync/test/fixtures/下放置带 CRLF 的STATE.md/LOOP.md样本再在测试中通过readFile读取断言。更广视角CRLF 问题是 Windows 贡献者体验的一部分这次回归测试任务不是孤例。仓库中与之配套的文档工作包括scripts/issue-bodies/windows-contributor-notes.md建议在 docs/QUICKSTART.md 增加 Windows/CRLF 注意事项小节docs/QUICKSTART.md已落地 Windows / CRLF notes 小节推荐git config core.autocrlf input保持仓库 LF 行尾并明确说明loop-syncstrips carriage returns即 strip\r的行为正是extractFrontmatter中/\r?\n/切分与.trim()的实现效果CONTRIBUTING.md同样涉及 line-ending 相关的贡献规范。把这些线索串起来可以看到回归测试本任务防止代码回退文档windows-contributor-notes防止用户踩坑两者共同构成 CRLF 兼容性的完整闭环。小结extractFrontmatter通过content.startsWith(---\n) || content.startsWith(---\r\n)同时接受 LF 与 CRLF 开围栏用/\r?\n/切分并trim()清除残留\r从而让 CRLF frontmatter 解析出干净的键值回归测试的三个验收点LF 基线、CRLF 无\r残留、---hello拒绝已在 sync.test.mjs 全部落地并额外覆盖了闭合围栏后跟多余字符被拒绝的对称边界运行验证方式为cd tools/loop-sync npm test测试链路为tsc构建后由node --test执行CRLF 解析的正确性直接支撑scanSkillsDirectory的版本读取与STATE.md ↔ LOOP.md一致性检查是 Windows 贡献者体验整体建设配合 docs/QUICKSTART.md 的排障文档的基础设施级保障。相关仓库路径速查任务文档 scripts/issue-bodies/loop-sync-crlf-tests.md实现源码 tools/loop-sync/src/sync.ts测试用例 tools/loop-sync/test/sync.test.mjsCLI 入口 tools/loop-sync/src/cli.ts使用文档 tools/loop-sync/README.mdWindows 注意事项 docs/QUICKSTART.md赞分享人工智能AI AgentAgent 工作流CLI研发协作AI 技能MCP 服务【免费下载链接】loop-engineeringPractical patterns, starters CLI tools for loop engineering with AI coding agents. Design systems that prompt and orchestrate agents (inspired by Addy Osmani and Boris Cherny). Includes loop-audit, loop-init, loop-cost.项目地址https://gitcode.com/gh_mirrors/lo/loop-engineering点击查看免费下载相关推荐Paper2GUI 全景指南把论文算法变成人人可用的 AI 桌面工具箱Paper2GUI 全景指南把论文算法变成人人可用的 AI 桌面工具箱 Paper2GUIP2G是一个面向普通用户的 AI 桌面应用工具箱定位是让每个人工智能AI 应用桌面应用Fluent Bit 内置 zstd 的回归测试体系压缩比守护者 results.csv 的构建与解读Fluent Bit 内置 zstd 的回归测试体系压缩比守护者 results.csv 的构建与解读 导读 本篇文章聚焦于 zstdZstandard随可观测性日志分析云原生流处理flexivit_base.600ep_in1k与传统ViT对比为什么它能成为多尺度图像识别神器flexivit_base.600ep_in1k与传统ViT对比为什么它能成为多尺度图像识别神器 flexivit_base.600ep_in1k是一款基于创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表