[{"data":1,"prerenderedAt":4},["ShallowReactive",2],{"doc-\u002Fzh-Hans\u002Fcmtx\u002Fdev-guide\u002FDEV-013-api-conventions\u002F":3},"\u003Ch1 id=\"dev-013%3A-cmtx-%E5%87%BD%E6%95%B0%E5%8F%8A-api-%E8%AE%BE%E8%AE%A1%E8%A7%84%E8%8C%83\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#dev-013%3A-cmtx-%E5%87%BD%E6%95%B0%E5%8F%8A-api-%E8%AE%BE%E8%AE%A1%E8%A7%84%E8%8C%83\">#\u003C\u002Fa> DEV-013: CMTX 函数及 API 设计规范\u003C\u002Fh1>\n\u003Cblockquote>\n\u003Cp>定义 CMTX 项目的函数和 API 设计规范，覆盖命名约定、参数设计、返回类型、错误处理、导出策略、跨包原则、Service 设计、CLI 命令、JSDoc 注释和 Review Checklist。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch2 id=\"1.-%E6%A6%82%E8%BF%B0%E4%B8%8E%E8%8C%83%E5%9B%B4\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#1.-%E6%A6%82%E8%BF%B0%E4%B8%8E%E8%8C%83%E5%9B%B4\">#\u003C\u002Fa> 1. 概述与范围\u003C\u002Fh2>\n\u003Ch3 id=\"1.1.-%E5%88%86%E5%B1%82%E7%BB%93%E6%9E%84\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#1.1.-%E5%88%86%E5%B1%82%E7%BB%93%E6%9E%84\">#\u003C\u002Fa> 1.1. 分层结构\u003C\u002Fh3>\n\u003Cp>本文档分三层：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Part 1（§1-§4）：通用函数规范\u003C\u002Fstrong>。适用于所有函数，无论是否公开导出。命名、参数、返回类型、错误处理。\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Part 2（§5-§9）：API 规范\u003C\u002Fstrong>。公开导出需要额外遵守的规则。导出策略、跨包原则、Service 设计、CLI 命令、JSDoc。\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Part 3（§10）：Review Checklist\u003C\u002Fstrong>。涵盖 Part 1 + Part 2 所有维度的检查清单。\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3 id=\"1.2.-%E5%B1%82%E6%AC%A1%E5%85%B3%E7%B3%BB\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#1.2.-%E5%B1%82%E6%AC%A1%E5%85%B3%E7%B3%BB\">#\u003C\u002Fa> 1.2. 层次关系\u003C\u002Fh3>\n\u003Cul>\n\u003Cli>\u003Cstrong>Part 1 的规则\u003C\u002Fstrong>——API 必须做到（因为 API 本身就是函数\u002F类型\u002F类的公开组合）\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Part 2 的规则\u003C\u002Fstrong>——内部函数不需要（\u003Ccode>@internal\u003C\u002Fcode> 标记、导出策略等仅公开导出相关）\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Chr>\n\u003Ch2 id=\"2.-part-1%3A-%E9%80%9A%E7%94%A8%E5%87%BD%E6%95%B0%E8%A7%84%E8%8C%83\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#2.-part-1%3A-%E9%80%9A%E7%94%A8%E5%87%BD%E6%95%B0%E8%A7%84%E8%8C%83\">#\u003C\u002Fa> 2. Part 1: 通用函数规范\u003C\u002Fh2>\n\u003Ch3 id=\"2.1.-%C2%A71-%E5%91%BD%E5%90%8D%E7%BA%A6%E5%AE%9A\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#2.1.-%C2%A71-%E5%91%BD%E5%90%8D%E7%BA%A6%E5%AE%9A\">#\u003C\u002Fa> 2.1. §1 命名约定\u003C\u002Fh3>\n\u003Ch4 id=\"1.1.-%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0%E5%91%BD%E5%90%8D\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#1.1.-%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0%E5%91%BD%E5%90%8D\">#\u003C\u002Fa> 1.1. 函数参数命名\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 配置参数统一使用 \u003Ccode>options\u003C\u002Fcode>\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] 正确\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> filterImages\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">markdown\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">options\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> FilterImagesOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> ImageMatch\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">[]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> uploadFile\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">options\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> Promise\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\">UploadResult\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [FAIL] 错误\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> filterImages\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">markdown\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">opts\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> FilterImagesOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 不使用 opts\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> uploadFile\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">config\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 不使用 config\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> uploadFile\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">params\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 不使用 params\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"1.2.-%E7%B1%BB%E5%9E%8B%E5%91%BD%E5%90%8D\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#1.2.-%E7%B1%BB%E5%9E%8B%E5%91%BD%E5%90%8D\">#\u003C\u002Fa> 1.2. 类型命名\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>函数选项类型: \u003Ccode>XxxOptions\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>结果类型: \u003Ccode>XxxResult\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>服务配置: \u003Ccode>XxxConfig\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>不使用 \u003Ccode>I\u003C\u002Fcode> 前缀\u003C\u002Fli>\n\u003Cli>不使用缩写（\u003Ccode>Res\u003C\u002Fcode> → \u003Ccode>Result\u003C\u002Fcode>、\u003Ccode>Cfg\u003C\u002Fcode> → \u003Ccode>Config\u003C\u002Fcode>）\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] 正确\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> FilterImagesOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadResult\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadServiceConfig\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [FAIL] 错误\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> IFilterImagesOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { }  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 不使用 I 前缀\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> FilterConfig\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { }  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 函数选项不使用 Config\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadRes\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { }  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 不使用缩写\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"1.3.-%E5%B1%9E%E6%80%A7%E5%91%BD%E5%90%8D\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#1.3.-%E5%B1%9E%E6%80%A7%E5%91%BD%E5%90%8D\">#\u003C\u002Fa> 1.3. 属性命名\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 统一使用 camelCase\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] 正确\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> CosAdapterConfig\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  bucket\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  region\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [FAIL] 错误\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> CosAdapterConfig\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  Bucket\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 不使用 PascalCase\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  Region\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>\u003Cstrong>例外\u003C\u002Fstrong>: 与外部 SDK 交互时，在内部映射，对外暴露 camelCase。\u003C\u002Fp>\n\u003Ch4 id=\"1.4.-%E5%87%BD%E6%95%B0%E5%91%BD%E5%90%8D\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#1.4.-%E5%87%BD%E6%95%B0%E5%91%BD%E5%90%8D\">#\u003C\u002Fa> 1.4. 函数命名\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\n\u003Cp>\u003Cstrong>动词 + 名词\u003C\u002Fstrong>: 函数名以动词开头，后接操作对象\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] 正确\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> filterImages\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">markdown\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">options\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> FilterImagesOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> ImageMatch\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">[]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> parseImages\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">text\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> ParsedImage\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">[]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> addSectionNumbers\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">markdown\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">options\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> SectionNumbersOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> SectionNumbersResult\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [FAIL] 错误 — 动词缺失\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> imagesFilter\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">markdown\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 名词在前\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> markdownSectionNumbers\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">markdown\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 以操作对象开头\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fli>\n\u003Cli>\n\u003Cp>\u003Cstrong>长度限制\u003C\u002Fstrong>: 函数名不超过 20 字符（超出需评审）\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] ≤20 字符\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> formatMarkdownImage\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">options\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> FormatMarkdownImageOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">   \u002F\u002F 19\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> generateCounterValue\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">value\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> number\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">config\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> CounterValueConfig\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">  \u002F\u002F 20\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> removeSectionNumbers\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">markdown\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">options\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> SectionNumbersOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> SectionNumbersResult\u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">  \u002F\u002F 20\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [FAIL] >20 字符 — 需缩短\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> convertMarkdownImageToHtml\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(...)  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 26 → 应改为 toHtmlImage(11)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fli>\n\u003Cli>\n\u003Cp>\u003Cstrong>成对对称\u003C\u002Fstrong>: 相反操作使用对称前缀\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] 正确\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">addSectionNumbers \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">\u002F\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> removeSectionNumbers\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">encryptString \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">\u002F\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> decryptString\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [FAIL] 错误\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">addSectionNumbers \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">\u002F\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> deleteSectionNumbers  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F add\u002Fremove 不对称\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">loadWASM \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">\u002F\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> checkWasmLoaded  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 应统一为 loadWASM \u002F isWasmLoaded\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fli>\n\u003Cli>\n\u003Cp>\u003Cstrong>方向标记\u003C\u002Fstrong>: 格式转换用 \u003Ccode>{源}To{目标}\u003C\u002Fcode> 或 \u003Ccode>to{目标}{对象}\u003C\u002Fcode>，前置方向标记\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] 正确 — 方向标记\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> toHtmlImage\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">markdown\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">attrs\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> Record\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\">string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\">string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">>)\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [FAIL] 错误 — 方向标记后置\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> convertMarkdownImageToHtml\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">markdown\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F \"convert\" + 完整描述 → 过长\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fli>\n\u003Cli>\n\u003Cp>\u003Cstrong>统一动词表\u003C\u002Fstrong>: 同一语义使用统一动词，不混用\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>语义\u003C\u002Fth>\n\u003Cth>动词\u003C\u002Fth>\n\u003Cth>示例\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>筛选\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>filter\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>filterImages\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>解析\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>parse\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>parseImages\u003C\u002Fcode>, \u003Ccode>parseYamlFrontmatter\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>生成（从结构化数据）\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>format\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>formatMarkdownImage\u003C\u002Fcode>, \u003Ccode>formatHtmlImage\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>转换格式\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>to\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>toHtmlImage\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>提取\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>extract\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>extractFrontmatter\u003C\u002Fcode>, \u003Ccode>extractSectionHeadings\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>新增\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>add\u003C\u002Fcode> \u002F \u003Ccode>create\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>addSectionNumbers\u003C\u002Fcode>, \u003Ccode>createFF1Cipher\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>删除\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>remove\u003C\u002Fcode> \u002F \u003Ccode>delete\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>removeSectionNumbers\u003C\u002Fcode>, \u003Ccode>deleteFrontmatterFields\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>更新\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>update\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>updateImageRefs\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>设置\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>set\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>setImageDimensions\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>判断\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>is\u003C\u002Fcode> \u002F \u003Ccode>has\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>isWebSource\u003C\u002Fcode>, \u003Ccode>isWasmLoaded\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F 内部使用 camelCase，映射到 SDK 的 PascalCase\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">class\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> TencentCOSAdapter\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">  constructor\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">config\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> CosAdapterConfig\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5\">    this\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">.sdkConfig \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">=\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">      Bucket: config.bucket,  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 内部映射\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">      Region: config.region,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">    };\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Chr>\n\u003Ch3 id=\"2.2.-%C2%A72-%E5%8F%82%E6%95%B0%E8%AE%BE%E8%AE%A1\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#2.2.-%C2%A72-%E5%8F%82%E6%95%B0%E8%AE%BE%E8%AE%A1\">#\u003C\u002Fa> 2.2. §2 参数设计\u003C\u002Fh3>\n\u003Ch4 id=\"2.1.-%E9%85%8D%E7%BD%AE%E5%8F%82%E6%95%B0%E7%94%A8-options-%E5%AF%B9%E8%B1%A1\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#2.1.-%E9%85%8D%E7%BD%AE%E5%8F%82%E6%95%B0%E7%94%A8-options-%E5%AF%B9%E8%B1%A1\">#\u003C\u002Fa> 2.1. 配置参数用 options 对象\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 如果函数有 2 个或以上可选\u002F配置参数，统一包装为一个 options 对象。（SPRINT-015 DECISION-004）\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] 正确\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> uploadFile\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">options\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> Promise\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\">UploadResult\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [FAIL] 错误（参数超过 2 个时）\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> uploadFile\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  filePath\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  prefix\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  overwrite\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> boolean\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  concurrency\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> number\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">)\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> Promise\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\">UploadResult\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"2.2.-%E5%8F%82%E6%95%B0%E9%A1%BA%E5%BA%8F\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#2.2.-%E5%8F%82%E6%95%B0%E9%A1%BA%E5%BA%8F\">#\u003C\u002Fa> 2.2. 参数顺序\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 必选参数在前，options 对象在最后。\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> filterImages\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">markdown\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">options\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> FilterImagesOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> ImageMatch\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">[]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F                   ↑ 必选                  ↑ 可选配置\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"2.3.-service-%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E7%BB%9F%E4%B8%80-config-%E5%AF%B9%E8%B1%A1\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#2.3.-service-%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E7%BB%9F%E4%B8%80-config-%E5%AF%B9%E8%B1%A1\">#\u003C\u002Fa> 2.3. Service 构造函数统一 config 对象\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 所有 Service 类统一使用 \u003Ccode>constructor(config: ServiceConfig)\u003C\u002Fcode> 模式，logger 必须嵌套在 config 中。（SPRINT-015 DECISION-001）\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] 正确\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">class\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadService\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">  constructor\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">config\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadServiceConfig\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">    \u002F\u002F config 中包含所有依赖，包括可选的 logger\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [FAIL] 错误\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">class\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadService\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">  constructor\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">config\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadServiceConfig\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">logger\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> Logger\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F logger 应嵌套在 config 中\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Chr>\n\u003Ch3 id=\"2.3.-%C2%A73-%E8%BF%94%E5%9B%9E%E7%B1%BB%E5%9E%8B\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#2.3.-%C2%A73-%E8%BF%94%E5%9B%9E%E7%B1%BB%E5%9E%8B\">#\u003C\u002Fa> 2.3. §3 返回类型\u003C\u002Fh3>\n\u003Ch4 id=\"3.1.-%E6%A0%87%E5%87%86-result-%E5%AD%97%E6%AE%B5\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#3.1.-%E6%A0%87%E5%87%86-result-%E5%AD%97%E6%AE%B5\">#\u003C\u002Fa> 3.1. 标准 Result 字段\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 操作结果类型统一使用以下字段。（SPRINT-015 DECISION-002）\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>字段\u003C\u002Fth>\n\u003Cth>类型\u003C\u002Fth>\n\u003Cth>说明\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>succeeded\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>number\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>成功计数\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>failed\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>number\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>失败计数\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>skipped\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>number\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>跳过计数\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>content\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>string\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>处理后的内容（可选）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>errors\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>Error[]\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>错误详情（可选）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] 正确\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadResult\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  succeeded\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> number\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  failed\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> number\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  skipped\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> number\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  content\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  errors\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> Error\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">[];\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [FAIL] 错误\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadResult\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  uploaded\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> number\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;   \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 不使用 uploaded\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  success\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> number\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;    \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 不使用 success\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  transferred\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> number\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">; \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 不使用 transferred\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"3.2.-%E6%89%A9%E5%B1%95-result-%E7%B1%BB%E5%9E%8B\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#3.2.-%E6%89%A9%E5%B1%95-result-%E7%B1%BB%E5%9E%8B\">#\u003C\u002Fa> 3.2. 扩展 Result 类型\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 在标准字段基础上扩展特定字段。\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadResult\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> extends\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> OperationResult\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  uploads\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { \u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">original\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">; \u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">newUrl\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> }[];\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> DownloadResult\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> extends\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> OperationResult\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  downloads\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { \u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">original\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">; \u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">localPath\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> }[];\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"3.3.-%E8%BF%94%E5%9B%9E%E7%B1%BB%E5%9E%8B%E4%BA%BA%E4%BD%93%E5%B7%A5%E5%AD%A6%EF%BC%88p5%EF%BC%89\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#3.3.-%E8%BF%94%E5%9B%9E%E7%B1%BB%E5%9E%8B%E4%BA%BA%E4%BD%93%E5%B7%A5%E5%AD%A6%EF%BC%88p5%EF%BC%89\">#\u003C\u002Fa> 3.3. 返回类型人体工学（P5）\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 当函数的返回值需要频繁进行模式化判断（判空、格式化、遍历）时，考虑包装为结果类。但不要在简单场景（如 \u003Ccode>filterImages\u003C\u002Fcode> 返回图片列表，消费者只需 \u003Ccode>.map()\u003C\u002Fcode>）中过度设计。（源自 SPRINT-009 P5）\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] 需要频繁模式化判断时，使用结果类\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> ValidationResult\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  valid\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> boolean\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  errors\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> ConfigValidationError\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">[];\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6F42C1\">  hasFatal\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">()\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> boolean\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6F42C1\">  format\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">()\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] 简单列表场景直接返回数组\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> filterImages\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">markdown\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">options\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> FilterImagesOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> ImageMatch\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">[]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Chr>\n\u003Ch3 id=\"2.4.-%C2%A74-%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#2.4.-%C2%A74-%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86\">#\u003C\u002Fa> 2.4. §4 错误处理\u003C\u002Fh3>\n\u003Ch4 id=\"4.1.-%E9%94%99%E8%AF%AF%E7%B1%BB%E5%9E%8B\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#4.1.-%E9%94%99%E8%AF%AF%E7%B1%BB%E5%9E%8B\">#\u003C\u002Fa> 4.1. 错误类型\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 使用自定义错误类型，继承 \u003Ccode>Error\u003C\u002Fcode>。\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">class\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> CmtxError\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> extends\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> Error\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">  constructor\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">message\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">public\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\"> code\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5\">    super\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(message);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5\">    this\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">.name \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">=\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> 'CmtxError'\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"4.2.-%E9%94%99%E8%AF%AF%E7%A0%81\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#4.2.-%E9%94%99%E8%AF%AF%E7%A0%81\">#\u003C\u002Fa> 4.2. 错误码\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 使用大写字母和下划线的常量定义错误码。\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">const\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> ERROR_UPLOAD_FAILED\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> 'UPLOAD_FAILED'\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">const\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> ERROR_DOWNLOAD_FAILED\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> 'DOWNLOAD_FAILED'\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Chr>\n\u003Ch2 id=\"3.-part-2%3A-api-%E8%A7%84%E8%8C%83\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#3.-part-2%3A-api-%E8%A7%84%E8%8C%83\">#\u003C\u002Fa> 3. Part 2: API 规范\u003C\u002Fh2>\n\u003Ch3 id=\"3.1.-%C2%A75-%E5%AF%BC%E5%87%BA%E7%AD%96%E7%95%A5\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#3.1.-%C2%A75-%E5%AF%BC%E5%87%BA%E7%AD%96%E7%95%A5\">#\u003C\u002Fa> 3.1. §5 导出策略\u003C\u002Fh3>\n\u003Ch4 id=\"5.1.-%E4%B8%80%E4%B8%BB%E5%A4%9A%E8%BE%85%EF%BC%88%E5%87%BD%E6%95%B0-api-%E4%BC%98%E5%85%88%EF%BC%89\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#5.1.-%E4%B8%80%E4%B8%BB%E5%A4%9A%E8%BE%85%EF%BC%88%E5%87%BD%E6%95%B0-api-%E4%BC%98%E5%85%88%EF%BC%89\">#\u003C\u002Fa> 5.1. 一主多辅（函数 API 优先）\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 函数 API 是主导出（默认），Service API 是辅导出（可选，仅 Rule 系统需要）。（源自 ADR-011）\u003C\u002Fp>\n\u003Cp>每个包的公共入口（\u003Ccode>src\u002Findex.ts\u003C\u002Fcode>）应优先暴露纯函数 API。Service 接口仅当存在 Rule 引擎这类需要运行时多态的消费者时才提供。\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] 函数 API 是主导出\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">export\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { filterImages, updateImageRefs } \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">from\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> \".\u002Ffilter.js\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">export\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> ImageMatch, \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> ReplaceOptions } \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">from\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> \".\u002Ftypes.js\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F Service API 作为辅导出（仅当需要时才暴露）\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">export\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { createUploadService, \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> UploadService } \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">from\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> \".\u002Fservices\u002Fupload-service.js\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"5.2.-%E7%A6%81%E6%AD%A2%E4%B8%8D%E5%BF%85%E8%A6%81%E7%9A%84-re-export\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#5.2.-%E7%A6%81%E6%AD%A2%E4%B8%8D%E5%BF%85%E8%A6%81%E7%9A%84-re-export\">#\u003C\u002Fa> 5.2. 禁止不必要的 re-export\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 从底层包 re-export 类型时，确认此 re-export 有实际消费者。SPRINT-010 RQ-014 的经验表明，大多数 re-export 零消费者。（源自 SPRINT-010）\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [FAIL] 零消费者的 re-export\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">export\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> type\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { IStorageAdapter } \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">from\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> \"@cmtx\u002Fstorage\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 消费者直接从 @cmtx\u002Fstorage 导入\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">export\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> type\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { UploadService } \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">from\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> \"@cmtx\u002Fasset\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;       \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 同上\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"5.3.-%E7%A7%81%E6%9C%89%E5%8C%96-api-%E7%94%A8-%40internal-%2B-%E5%81%9C%E6%AD%A2-barrel-%E5%AF%BC%E5%87%BA\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#5.3.-%E7%A7%81%E6%9C%89%E5%8C%96-api-%E7%94%A8-%40internal-%2B-%E5%81%9C%E6%AD%A2-barrel-%E5%AF%BC%E5%87%BA\">#\u003C\u002Fa> 5.3. 私有化 API 用 @internal + 停止 barrel 导出\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 私有化的 API 不能只在 JSDoc 上加 \u003Ccode>@internal\u003C\u002Fcode>，必须同时从 barrel（\u003Ccode>index.ts\u003C\u002Fcode>）移除导出。\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] 正确：@internal + 不导出\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F** \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">@internal\u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\"> *\u002F\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">export\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> class\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> ServiceRegistryImpl\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">...\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> }  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 此处虽保留 export（供包内测试），但不从 index.ts 导出\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [FAIL] 错误：只有 @internal 标签\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F** \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">@internal\u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\"> *\u002F\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">export\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> class\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> ServiceRegistryImpl\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">...\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> }  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 仍从 index.ts 导出\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"5.4.-%E9%81%BF%E5%85%8D%E9%9B%B6%E6%B6%88%E8%B4%B9%E8%80%85%E5%AF%BC%E5%87%BA\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#5.4.-%E9%81%BF%E5%85%8D%E9%9B%B6%E6%B6%88%E8%B4%B9%E8%80%85%E5%AF%BC%E5%87%BA\">#\u003C\u002Fa> 5.4. 避免零消费者导出\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 增加新导出前先确认包外是否有消费者。使用 \u003Ccode>scripts\u002Fapi-surface.sh\u003C\u002Fcode> 检查。（源自 SPRINT-010 经验）\u003C\u002Fp>\n\u003Ch4 id=\"5.5.-%E5%AD%90%E8%B7%AF%E5%BE%84%E6%98%BE%E5%BC%8F%E5%AF%BC%E5%87%BA%EF%BC%88p10%EF%BC%89\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#5.5.-%E5%AD%90%E8%B7%AF%E5%BE%84%E6%98%BE%E5%BC%8F%E5%AF%BC%E5%87%BA%EF%BC%88p10%EF%BC%89\">#\u003C\u002Fa> 5.5. 子路径显式导出（P10）\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 子路径 index 文件应显式列出导出项。禁止 \u003Ccode>export *\u003C\u002Fcode>。每个子路径应有清晰的消费者故事。（源自 SPRINT-009 P10）\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] 正确：显式列出\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">export\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { createDownloadService } \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">from\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> \".\u002Fdownload-service.js\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">export\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> type\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { DownloadOptions } \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">from\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> \".\u002Ftypes.js\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [FAIL] 错误\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">export\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> *\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> from\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> \".\u002Fdownload-service.js\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">export\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> *\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> from\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> \".\u002Ftypes.js\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"5.6.-%E5%90%91%E5%90%8E%E5%85%BC%E5%AE%B9%E4%B8%8E%E7%89%88%E6%9C%AC%E7%AD%96%E7%95%A5\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#5.6.-%E5%90%91%E5%90%8E%E5%85%BC%E5%AE%B9%E4%B8%8E%E7%89%88%E6%9C%AC%E7%AD%96%E7%95%A5\">#\u003C\u002Fa> 5.6. 向后兼容与版本策略\u003C\u002Fh4>\n\u003Cul>\n\u003Cli>当前版本处于 \u003Ccode>0.x\u003C\u002Fcode> 开发阶段，禁止使用 major bump\u003C\u002Fli>\n\u003Cli>破坏性变更在 minor 版本发布（如 \u003Ccode>0.1.0\u003C\u002Fcode> → \u003Ccode>0.2.0\u003C\u002Fcode>）\u003C\u002Fli>\n\u003Cli>常规更新（新功能、bug 修复、内部优化）使用 patch（如 \u003Ccode>0.1.0\u003C\u002Fcode> → \u003Ccode>0.1.1\u003C\u002Fcode>）\u003C\u002Fli>\n\u003Cli>\u003Ccode>0.x\u003C\u002Fcode> 阶段不保留废弃的 API，也不要求迁移文档\u003C\u002Fli>\n\u003Cli>破坏性变更仅在 changelog 中记录，供消费者参考\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch4 id=\"5.7.-%E5%BA%9F%E5%BC%83-api-%E5%A4%84%E7%90%86%EF%BC%88p6%EF%BC%89\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#5.7.-%E5%BA%9F%E5%BC%83-api-%E5%A4%84%E7%90%86%EF%BC%88p6%EF%BC%89\">#\u003C\u002Fa> 5.7. 废弃 API 处理（P6）\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 标记 \u003Ccode>@deprecated\u003C\u002Fcode> 时必须同步计划移除时间，在下一个发布窗口移除。不要保留 forwarding alias。（源自 SPRINT-009 P6）\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F**\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"> * \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">@deprecated\u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\"> Use filterImages(markdown, options) instead.\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"> * The logger parameter is now part of FilterImagesOptions.\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"> * Remove in next minor version.\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"> *\u002F\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"5.8.-api-%E5%85%AC%E5%BC%80%E5%BF%85%E8%A6%81%E6%80%A7%E5%88%A4%E6%96%AD\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#5.8.-api-%E5%85%AC%E5%BC%80%E5%BF%85%E8%A6%81%E6%80%A7%E5%88%A4%E6%96%AD\">#\u003C\u002Fa> 5.8. API 公开必要性判断\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 公开 API 应只包含 CMTX 领域逻辑。判断标准：\u003C\u002Fp>\n\u003Cp>✅ \u003Cstrong>应该公开\u003C\u002Fstrong>（至少一项为真）：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>包含 CMTX 特有的业务逻辑（正则解析、元数据处理、规则引擎、云存储适配等）\u003C\u002Fli>\n\u003Cli>定义了 CMTX 领域的类型\u002F接口（\u003Ccode>CmtxConfig\u003C\u002Fcode>, \u003Ccode>Rule\u003C\u002Fcode>, \u003Ccode>StorageAdapter\u003C\u002Fcode> 等）\u003C\u002Fli>\n\u003Cli>用户需要此 API 来完成 CMTX 工作流（\u003Ccode>compressFile\u003C\u002Fcode>, \u003Ccode>pack\u003C\u002Fcode>, \u003Ccode>publishAndReplaceFile\u003C\u002Fcode> 等）\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>❌ \u003Cstrong>不应公开\u003C\u002Fstrong>（全部为真）：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>对 Node 内置函数或知名 npm 包的薄透传（\u003Ccode>crypto.createHash\u003C\u002Fcode>, \u003Ccode>fs.statSync\u003C\u002Fcode>, \u003Ccode>js-yaml.load\u003C\u002Fcode>）\u003C\u002Fli>\n\u003Cli>用户在 CMTX 外的生态中有更好的同功能 API（\u003Ccode>mime-types\u003C\u002Fcode>, \u003Ccode>file-type\u003C\u002Fcode> 等）\u003C\u002Fli>\n\u003Cli>仅 CMTX 内部使用，无独立领域价值\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>⚠️ \u003Cstrong>例外——即使符合&quot;不应公开&quot;也应公开\u003C\u002Fstrong>（任意一项为真）：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>是框架约定的标准实现\u002F引用实现（如 Logger 接口的 \u003Ccode>consoleLogger\u003C\u002Fcode> 控制台实现）\u003C\u002Fli>\n\u003Cli>被框架 JSDoc\u002F文档示例直接引用的 API（如 \u003Ccode>class X { constructor(logger = dummyLogger) {} }\u003C\u002Fcode>）\u003C\u002Fli>\n\u003Cli>用户实现框架接口时必须依赖的类型或值（如 \u003Ccode>dummyLogger\u003C\u002Fcode> 作为默认参数）\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>处理方式：\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>场景\u003C\u002Fth>\n\u003Cth>操作\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>不应公开但被包内引用\u003C\u002Ftd>\n\u003Ctd>从 \u003Ccode>index.ts\u003C\u002Fcode> 的 \u003Ccode>export {...}\u003C\u002Fcode> 移除，保留普通 \u003Ccode>import\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>不应公开但有外部引用\u003C\u002Ftd>\n\u003Ctd>标记 \u003Ccode>@internal\u003C\u002Fcode> 后在下一个 minor 移出 barrel\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>不应公开且无引用\u003C\u002Ftd>\n\u003Ctd>直接移出 barrel + 标记 \u003Ccode>@internal\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>export function filterImages(\u003C\u002Ftd>\n\u003Ctd>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>markdown: string,\u003C\u002Ftd>\n\u003Ctd>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>options?: ImageFilterOptions,\u003C\u002Ftd>\n\u003Ctd>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>logger?: Logger\u003C\u002Ftd>\n\u003Ctd>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>): ImageMatch[] {\u003C\u002Ftd>\n\u003Ctd>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>return newFilterImages(markdown, { …options, logger });\u003C\u002Ftd>\n\u003Ctd>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>}\u003C\u002Ftd>\n\u003Ctd>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cpre>\u003Ccode>\n---\n\n### 3.2. §6 跨包设计原则\n\n以下原则用于在整个项目中定位和设计 API，确保跨包 API 的职责边界、类型归属和依赖方向合理。\n\n#### 6.1. P1: 包作用域感知\n\n**规则**: 符号名称不应重复包\u002F模块名已表达的领域上下文。（源自 SPRINT-009 P1）\n\n```typescript\n\u002F\u002F [OK] @cmtx\u002Fcore 中所有函数已处于&quot;文本处理&quot;上下文\nfunction filterImages(markdown: string, options?: ImageFilterOptions)\n\n\u002F\u002F [FAIL] 不应添加 InText 后缀\nfunction filterImagesInText(...)  \u002F\u002F 包名 core 已暗示文本处理\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch4 id=\"6.2.-p2%3A-%E7%BB%9F%E4%B8%80%E5%91%BD%E5%90%8D%E7%BA%A6%E5%AE%9A\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#6.2.-p2%3A-%E7%BB%9F%E4%B8%80%E5%91%BD%E5%90%8D%E7%BA%A6%E5%AE%9A\">#\u003C\u002Fa> 6.2. P2: 统一命名约定\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 全项目使用一致的命名模式。同一角色在不同包中应使用相同命名模式。（源自 SPRINT-009 P2）\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>角色\u003C\u002Fth>\n\u003Cth>模式\u003C\u002Fth>\n\u003Cth>示例\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>Service 类\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>{Verb}Service\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>DownloadService\u003C\u002Fcode>, \u003Ccode>UploadService\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>工厂函数\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>create{Verb}{Role}\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>createDownloadService\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Builder\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>{Domain}Builder\u003C\u002Fcode> \u002F \u003Ccode>{Domain}ConfigBuilder\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>TransferConfigBuilder\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Ch4 id=\"6.3.-p3%3A-%E5%B1%82%E7%BA%A7%E6%B6%88%E6%AD%A7\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#6.3.-p3%3A-%E5%B1%82%E7%BA%A7%E6%B6%88%E6%AD%A7\">#\u003C\u002Fa> 6.3. P3: 层级消歧\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 不同层的相似概念必须命名可区分。编排层使用高层抽象名称，子模块层使用更具体的名称。（源自 SPRINT-009 P3）\u003C\u002Fp>\n\u003Ch4 id=\"6.4.-p4%3A-%E7%BB%9F%E4%B8%80%E5%AE%9E%E4%BE%8B%E5%8C%96%E6%A8%A1%E5%BC%8F\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#6.4.-p4%3A-%E7%BB%9F%E4%B8%80%E5%AE%9E%E4%BE%8B%E5%8C%96%E6%A8%A1%E5%BC%8F\">#\u003C\u002Fa> 6.4. P4: 统一实例化模式\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 同一层次的同类对象使用统一的实例化方式，优先使用工厂函数 \u003Ccode>create{Verb}Service(config)\u003C\u002Fcode>，避免混用工厂函数和 \u003Ccode>new\u003C\u002Fcode>。（源自 SPRINT-009 P4）\u003C\u002Fp>\n\u003Ch4 id=\"6.5.-p5%3A-%E8%BF%94%E5%9B%9E%E7%B1%BB%E5%9E%8B%E4%BA%BA%E4%BD%93%E5%B7%A5%E5%AD%A6\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#6.5.-p5%3A-%E8%BF%94%E5%9B%9E%E7%B1%BB%E5%9E%8B%E4%BA%BA%E4%BD%93%E5%B7%A5%E5%AD%A6\">#\u003C\u002Fa> 6.5. P5: 返回类型人体工学\u003C\u002Fh4>\n\u003Cp>详见 §3.3。此原则同时适用于函数设计和跨包 API 设计。（源自 SPRINT-009 P5）\u003C\u002Fp>\n\u003Ch4 id=\"6.6.-p6%3A-%E6%97%A0%E5%BA%9F%E5%BC%83%E6%AE%8B%E7%95%99\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#6.6.-p6%3A-%E6%97%A0%E5%BA%9F%E5%BC%83%E6%AE%8B%E7%95%99\">#\u003C\u002Fa> 6.6. P6: 无废弃残留\u003C\u002Fh4>\n\u003Cp>详见 §5.7。标记 \u003Ccode>@deprecated\u003C\u002Fcode> 时必须同步计划移除时间，在下一个发布窗口移除。（源自 SPRINT-009 P6）\u003C\u002Fp>\n\u003Ch4 id=\"6.7.-p7%3A-api-%E5%BD%92%E5%B1%9E%E9%81%B5%E5%BE%AA%E5%88%86%E5%B1%82%E8%81%8C%E8%B4%A3\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#6.7.-p7%3A-api-%E5%BD%92%E5%B1%9E%E9%81%B5%E5%BE%AA%E5%88%86%E5%B1%82%E8%81%8C%E8%B4%A3\">#\u003C\u002Fa> 6.7. P7: API 归属遵循分层职责\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: API 的归属由操作类型决定，各层职责划分如下：（源自 SPRINT-009 P7）\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>层\u003C\u002Fth>\n\u003Cth>包\u003C\u002Fth>\n\u003Cth>职责\u003C\u002Fth>\n\u003Cth>示例\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>基础层\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>@cmtx\u002Fcore\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>纯内存操作，无文件 IO 无外部资源\u003C\u002Ftd>\n\u003Ctd>正则匹配、文本替换、YAML 解析、Luhn 算法\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>模板层\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>@cmtx\u002Ftemplate\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>模板渲染\u003C\u002Ftd>\n\u003Ctd>模板字符串处理\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>存储层\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>@cmtx\u002Fstorage\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>对象存储适配器\u003C\u002Ftd>\n\u003Ctd>OSS\u002FCOS 上传下载、签名 URL\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>编排层\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>@cmtx\u002Fasset\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>文件 IO、外部资源编排、多步骤流程\u003C\u002Ftd>\n\u003Ctd>图片下载\u002F上传\u002F转移、配置加载\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>引擎层\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>@cmtx\u002Frule-engine\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>规则引擎编排\u003C\u002Ftd>\n\u003Ctd>预设执行、批量处理\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cul>\n\u003Cli>core 的 API 不能放在 asset，asset 的 IO API 不能放在 core\u003C\u002Fli>\n\u003Cli>下层包（core\u002Ftemplate\u002Fstorage）不得依赖上层包（asset\u002Frule-engine）\u003C\u002Fli>\n\u003Cli>违反示例：\u003Ccode>@cmtx\u002Fcore\u003C\u002Fcode> 不应包含 \u003Ccode>fs.readFile\u003C\u002Fcode>，\u003Ccode>@cmtx\u002Frule-engine\u003C\u002Fcode> 不应包含 OSS 上传逻辑\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch4 id=\"6.8.-p8%3A-%E6%B6%88%E9%99%A4%E9%87%8D%E5%A4%8D%E5%AE%9E%E7%8E%B0\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#6.8.-p8%3A-%E6%B6%88%E9%99%A4%E9%87%8D%E5%A4%8D%E5%AE%9E%E7%8E%B0\">#\u003C\u002Fa> 6.8. P8: 消除重复实现\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 消费者必须 import 源头包或委托给源头包，不允许维护独立副本。（源自 SPRINT-009 P8）\u003C\u002Fp>\n\u003Cp>\u003Cstrong>实例\u003C\u002Fstrong>: vscode-extension 的 \u003Ccode>env-substitution.ts\u003C\u002Fcode> 和 \u003Ccode>image-processor.ts\u003C\u002Fcode> 曾分别是 asset 和 core 的重复副本。\u003C\u002Fp>\n\u003Ch4 id=\"6.9.-p9%3A-%E5%86%85%E9%83%A8%E7%B1%BB%E5%9E%8B%E5%8D%AB%E7%94%9F\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#6.9.-p9%3A-%E5%86%85%E9%83%A8%E7%B1%BB%E5%9E%8B%E5%8D%AB%E7%94%9F\">#\u003C\u002Fa> 6.9. P9: 内部类型卫生\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 不导出实现细节。增加新导出前先问外部消费者是否需要此类型。（源自 SPRINT-009 P9）\u003C\u002Fp>\n\u003Ch4 id=\"6.10.-p10%3A-%E5%AD%90%E8%B7%AF%E5%BE%84-api-%E8%AE%BE%E8%AE%A1\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#6.10.-p10%3A-%E5%AD%90%E8%B7%AF%E5%BE%84-api-%E8%AE%BE%E8%AE%A1\">#\u003C\u002Fa> 6.10. P10: 子路径 API 设计\u003C\u002Fh4>\n\u003Cp>详见 §5.5。（源自 SPRINT-009 P10）\u003C\u002Fp>\n\u003Chr>\n\u003Ch3 id=\"3.3.-%C2%A77-service-%E8%AE%BE%E8%AE%A1%E8%A7%84%E8%8C%83\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#3.3.-%C2%A77-service-%E8%AE%BE%E8%AE%A1%E8%A7%84%E8%8C%83\">#\u003C\u002Fa> 3.3. §7 Service 设计规范\u003C\u002Fh3>\n\u003Ch4 id=\"7.1.-%E5%B7%A5%E5%8E%82%E5%87%BD%E6%95%B0%E6%A8%A1%E5%BC%8F\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#7.1.-%E5%B7%A5%E5%8E%82%E5%87%BD%E6%95%B0%E6%A8%A1%E5%BC%8F\">#\u003C\u002Fa> 7.1. 工厂函数模式\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: Service 统一通过工厂函数创建，而非直接 \u003Ccode>new\u003C\u002Fcode>。（SPRINT-015 DECISION-001）\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] 正确\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">const\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> uploadService\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> createUploadService\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">({ adapter, prefix });\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">const\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> counterService\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> createCounterService\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">({ initialValue: \u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\">0\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> });\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [FAIL] 错误\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">const\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> uploadService\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> new\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadService\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(adapter, prefix);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"7.2.-logger-%E9%80%9A%E8%BF%87-config-%E6%B3%A8%E5%85%A5\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#7.2.-logger-%E9%80%9A%E8%BF%87-config-%E6%B3%A8%E5%85%A5\">#\u003C\u002Fa> 7.2. Logger 通过 config 注入\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: Logger 通过 config 对象注入，而非构造参数或全局单例。（SPRINT-015 DECISION-005）\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadServiceConfig\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  adapter\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> IStorageAdapter\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  logger\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> Logger\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 可选，默认 dummyLogger\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"7.3.-service-%E4%B8%8E%E5%87%BD%E6%95%B0-api-%E7%9A%84%E8%BE%B9%E7%95%8C\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#7.3.-service-%E4%B8%8E%E5%87%BD%E6%95%B0-api-%E7%9A%84%E8%BE%B9%E7%95%8C\">#\u003C\u002Fa> 7.3. Service 与函数 API 的边界\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 函数 API 优先，Service API 作为可选辅助。\u003C\u002Fp>\n\u003Cp>只有当调用方需要运行时多态（如 Rule 引擎通过 \u003Ccode>services.get&lt;T&gt;()\u003C\u002Fcode> 获取服务）时才提供 Service 接口。CLI 和 MCP Server 优先使用函数 API。（源自 ADR-011 + ANALYSIS-005）\u003C\u002Fp>\n\u003Chr>\n\u003Ch3 id=\"3.4.-%C2%A78-cli-%E5%91%BD%E4%BB%A4%E8%A7%84%E8%8C%83\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#3.4.-%C2%A78-cli-%E5%91%BD%E4%BB%A4%E8%A7%84%E8%8C%83\">#\u003C\u002Fa> 3.4. §8 CLI 命令规范\u003C\u002Fh3>\n\u003Ch4 id=\"8.1.-%E5%91%BD%E4%BB%A4%E9%80%89%E9%A1%B9%E5%AE%9A%E4%B9%89\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#8.1.-%E5%91%BD%E4%BB%A4%E9%80%89%E9%A1%B9%E5%AE%9A%E4%B9%89\">#\u003C\u002Fa> 8.1. 命令选项定义\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 所有命令选项定义在 \u003Ccode>types\u002Fcli.ts\u003C\u002Fcode>，必须 extend \u003Ccode>GlobalOptions\u003C\u002Fcode>。\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F types\u002Fcli.ts\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">export\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> interface\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadCommandOptions\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> extends\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> GlobalOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">  \u002F\u002F 特定选项\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F commands\u002Fimage\u002Fupload.ts\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">import\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> type\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> { UploadCommandOptions } \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">from\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> '..\u002F..\u002Ftypes\u002Fcli.js'\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">export\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> async\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> handler\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">options\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadCommandOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> Promise\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\">void\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">  \u002F\u002F 实现\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"8.2.-handler-%E5%8F%82%E6%95%B0%E5%91%BD%E5%90%8D\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#8.2.-handler-%E5%8F%82%E6%95%B0%E5%91%BD%E5%90%8D\">#\u003C\u002Fa> 8.2. Handler 参数命名\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 使用 \u003Ccode>options\u003C\u002Fcode>，与函数参数命名规范保持一致。\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] 正确\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">export\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> async\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> handler\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">options\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadCommandOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> Promise\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\">void\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [FAIL] 错误\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">export\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> async\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> handler\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E36209\">argv\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> UploadCommandOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">)  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 使用 argv\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"8.3.-%E9%81%BF%E5%85%8D%E5%B1%9E%E6%80%A7%E5%86%B2%E7%AA%81\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#8.3.-%E9%81%BF%E5%85%8D%E5%B1%9E%E6%80%A7%E5%86%B2%E7%AA%81\">#\u003C\u002Fa> 8.3. 避免属性冲突\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 不同语义的属性使用不同名称。\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [OK] 正确\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> FormatCommandOptions\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> extends\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> GlobalOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  outputPath\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 输出文件路径\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F\u002F [FAIL] 错误\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> FormatCommandOptions\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> extends\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> GlobalOptions\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  output\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">;  \u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">\u002F\u002F 与 GlobalOptions.output (OutputFormat) 冲突\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Chr>\n\u003Ch3 id=\"3.5.-%C2%A79-jsdoc-%E6%B3%A8%E9%87%8A%E8%A7%84%E8%8C%83\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#3.5.-%C2%A79-jsdoc-%E6%B3%A8%E9%87%8A%E8%A7%84%E8%8C%83\">#\u003C\u002Fa> 3.5. §9 JSDoc 注释规范\u003C\u002Fh3>\n\u003Ch4 id=\"9.1.-%E5%85%AC%E5%BC%80%E5%AF%BC%E5%87%BA%E2%80%94%E2%80%94%E5%BF%85%E9%A1%BB%E5%AE%8C%E6%95%B4%E7%9A%84-jsdoc\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#9.1.-%E5%85%AC%E5%BC%80%E5%AF%BC%E5%87%BA%E2%80%94%E2%80%94%E5%BF%85%E9%A1%BB%E5%AE%8C%E6%95%B4%E7%9A%84-jsdoc\">#\u003C\u002Fa> 9.1. 公开导出——必须完整的 JSDoc\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 所有从 \u003Ccode>index.ts\u003C\u002Fcode> 导出的公开 API（函数、类、接口、类型）必须包含 \u003Ccode>@param\u003C\u002Fcode>、\u003Ccode>@returns\u003C\u002Fcode>、\u003Ccode>@example\u003C\u002Fcode>。\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F**\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"> * 筛选 Markdown 中的图片\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"> * \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">@param\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> markdown\u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\"> - Markdown 文本\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"> * \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">@param\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\"> options\u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\"> - 筛选选项\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"> * \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">@returns\u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\"> 匹配的图片列表\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"> * \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">@example\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"> * ```typescript\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"> * const images = filterImages(\"# Hello\\n\\n![alt](img.png)\");\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"> * \u002F\u002F → [{ src: \"img.png\", alt: \"alt\" }]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"> * ```\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"> *\u002F\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">export\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> function\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> filterImages\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">(\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  markdown\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E36209\">  options\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">?:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> FilterImagesOptions\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E\">)\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">:\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> ImageMatch\u003C\u002Fspan>\u003Cspan style=\"color:#24292E\">[];\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"9.2.-%E5%86%85%E9%83%A8%E5%87%BD%E6%95%B0%E2%80%94%E2%80%94%E8%87%B3%E5%B0%91%E4%B8%80%E8%A1%8C%E6%8F%8F%E8%BF%B0\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#9.2.-%E5%86%85%E9%83%A8%E5%87%BD%E6%95%B0%E2%80%94%E2%80%94%E8%87%B3%E5%B0%91%E4%B8%80%E8%A1%8C%E6%8F%8F%E8%BF%B0\">#\u003C\u002Fa> 9.2. 内部函数——至少一行描述\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 不公开导出的内部函数、类型至少有一行功能描述。\u003C\u002Fp>\n\u003Ch4 id=\"9.3.-%40internal%E2%80%94%E2%80%94%E7%A7%81%E6%9C%89%E5%8C%96-%2B-%E5%81%9C%E6%AD%A2-barrel-%E5%AF%BC%E5%87%BA\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#9.3.-%40internal%E2%80%94%E2%80%94%E7%A7%81%E6%9C%89%E5%8C%96-%2B-%E5%81%9C%E6%AD%A2-barrel-%E5%AF%BC%E5%87%BA\">#\u003C\u002Fa> 9.3. @internal——私有化 + 停止 barrel 导出\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 标记 \u003Ccode>@internal\u003C\u002Fcode> 时必须同时从 barrel（\u003Ccode>index.ts\u003C\u002Fcode>）移除导出。仅加标签不移除导出属于规范违规。\u003C\u002Fp>\n\u003Ch4 id=\"9.4.-%40deprecated%E2%80%94%E2%80%94%E6%B3%A8%E6%98%8E%E6%9B%BF%E4%BB%A3%E6%96%B9%E6%A1%88\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#9.4.-%40deprecated%E2%80%94%E2%80%94%E6%B3%A8%E6%98%8E%E6%9B%BF%E4%BB%A3%E6%96%B9%E6%A1%88\">#\u003C\u002Fa> 9.4. @deprecated——注明替代方案\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 标记 \u003Ccode>@deprecated\u003C\u002Fcode> 时必须提供迁移说明，包括替代函数名称和移除计划。\u003C\u002Fp>\n\u003Cpre data-lang=\"typescript\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">\u002F**\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"> * \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\">@deprecated\u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\"> Use filterImages(markdown, options) instead.\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"> * Remove in next minor version.\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"> *\u002F\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch4 id=\"9.5.-%E6%96%B0%E5%A2%9E%E5%85%AC%E5%BC%80-api-%E9%9C%80%E5%90%8C%E6%AD%A5%E5%88%B0-api-%E6%96%87%E6%A1%A3\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#9.5.-%E6%96%B0%E5%A2%9E%E5%85%AC%E5%BC%80-api-%E9%9C%80%E5%90%8C%E6%AD%A5%E5%88%B0-api-%E6%96%87%E6%A1%A3\">#\u003C\u002Fa> 9.5. 新增公开 API 需同步到 API 文档\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>规则\u003C\u002Fstrong>: 新增公开导出后，必须在 \u003Ccode>docs\u002Fapi\u002F\u003C\u002Fcode> 下对应包的 API 文档中补充签名、参数表、返回值和示例。README 只展示代表性 API，不要求完整同步。TypeDoc 注释应完整，至少包含功能说明和参数描述。（源自 DEV-001 §12）\u003C\u002Fp>\n\u003Chr>\n\u003Ch2 id=\"4.-part-3%3A-review\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#4.-part-3%3A-review\">#\u003C\u002Fa> 4. Part 3: Review\u003C\u002Fh2>\n\u003Ch3 id=\"4.1.-%C2%A710-review-checklist\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#4.1.-%C2%A710-review-checklist\">#\u003C\u002Fa> 4.1. §10 Review Checklist\u003C\u002Fh3>\n\u003Cp>实施代码 review 时逐项检查。\u003C\u002Fp>\n\u003Ch4 id=\"10.1.-%E5%87%BD%E6%95%B0%E7%BB%B4%E5%BA%A6%EF%BC%88part-1%EF%BC%89\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#10.1.-%E5%87%BD%E6%95%B0%E7%BB%B4%E5%BA%A6%EF%BC%88part-1%EF%BC%89\">#\u003C\u002Fa> 10.1. 函数维度（Part 1）\u003C\u002Fh4>\n\u003Cul>\n\u003Cli>[ ] 参数使用 \u003Ccode>options\u003C\u002Fcode> 命名（如有配置参数）\u003C\u002Fli>\n\u003Cli>[ ] 类型使用 \u003Ccode>XxxOptions\u003C\u002Fcode> \u002F \u003Ccode>XxxResult\u003C\u002Fcode> \u002F \u003Ccode>XxxConfig\u003C\u002Fcode>，禁止 I 前缀和缩写\u003C\u002Fli>\n\u003Cli>[ ] 属性使用 camelCase\u003C\u002Fli>\n\u003Cli>[ ] 参数顺序：必选在前，options 在最后\u003C\u002Fli>\n\u003Cli>[ ] Service 构造函数统一 config 对象，logger 嵌套在 config 中\u003C\u002Fli>\n\u003Cli>[ ] Result 类型使用 \u003Ccode>succeeded\u002Ffailed\u002Fskipped\u003C\u002Fcode> 标准字段\u003C\u002Fli>\n\u003Cli>[ ] 错误处理：继承 Error，错误码大写+下划线\u003C\u002Fli>\n\u003Cli>[ ] 函数名 ≤ 20 字符（超长需评审）\u003C\u002Fli>\n\u003Cli>[ ] 同一提供商的命名前缀统一（\u003Ccode>AliyunCredentials\u003C\u002Fcode> + \u003Ccode>AliyunOSSAdapter\u003C\u002Fcode>，非 \u003Ccode>Ali\u003C\u002Fcode>）\u003C\u002Fli>\n\u003Cli>[ ] 同类实体的前缀对称（\u003Ccode>TencentCOSAdapter\u003C\u002Fcode> + \u003Ccode>TencentCOSAdapterConfig\u003C\u002Fcode>）\u003C\u002Fli>\n\u003Cli>[ ] 跨包同名概念的 API 对称（fpe-wasm ↔ autocorrect-wasm 的加载方式、类型导出应一致）\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch4 id=\"10.2.-api-%E7%BB%B4%E5%BA%A6%EF%BC%88part-2%EF%BC%89\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#10.2.-api-%E7%BB%B4%E5%BA%A6%EF%BC%88part-2%EF%BC%89\">#\u003C\u002Fa> 10.2. API 维度（Part 2）\u003C\u002Fh4>\n\u003Cul>\n\u003Cli>[ ] 新增的公开导出是否有包外消费者？（运行 \u003Ccode>api-surface.sh\u003C\u002Fcode> 检查）\u003C\u002Fli>\n\u003Cli>[ ] 是否有不必要的 re-export？\u003C\u002Fli>\n\u003Cli>[ ] 私有化的 API 是否同时加了 \u003Ccode>@internal\u003C\u002Fcode> 并停止 barrel 导出？（两者必须同时做）\u003C\u002Fli>\n\u003Cli>[ ] \u003Ccode>@public\u003C\u002Fcode> \u002F \u003Ccode>@internal\u003C\u002Fcode> 标注是否与 barrel 导出匹配？\u003C\u002Fli>\n\u003Cli>[ ] 废弃 API 是否标记了 \u003Ccode>@deprecated\u003C\u002Fcode> 并注明替代方案？\u003C\u002Fli>\n\u003Cli>[ ] 新增功能后，同模块是否有旧 API 可清理？\u003C\u002Fli>\n\u003Cli>[ ] 跨包迁入后，原调用方是否已更新？\u003C\u002Fli>\n\u003Cli>[ ] 子路径禁止 \u003Ccode>export *\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>[ ] 新增导出是否遵循了 P1-P10 原则？\u003C\u002Fli>\n\u003Cli>[ ] CLI 命令选项是否 extend GlobalOptions、handler 参数是否用 \u003Ccode>options\u003C\u002Fcode>？\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch4 id=\"10.3.-jsdoc-%E7%BB%B4%E5%BA%A6%EF%BC%88%C2%A79%EF%BC%89\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#10.3.-jsdoc-%E7%BB%B4%E5%BA%A6%EF%BC%88%C2%A79%EF%BC%89\">#\u003C\u002Fa> 10.3. JSDoc 维度（§9）\u003C\u002Fh4>\n\u003Cul>\n\u003Cli>[ ] 公开导出的 API 是否包含完整的 \u003Ccode>@param\u003C\u002Fcode>、\u003Ccode>@returns\u003C\u002Fcode>、\u003Ccode>@example\u003C\u002Fcode>？\u003C\u002Fli>\n\u003Cli>[ ] 新增\u002F删除的公开 API 是否同步到 \u003Ccode>docs\u002Fapi\u002F\u003C\u002Fcode> 对应文档？\u003C\u002Fli>\n\u003Cli>[ ] 运行 \u003Ccode>node scripts\u002Fcheck-api-docs-sync.mjs\u003C\u002Fcode> 确认无 SIGNATURE 警告？\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch4 id=\"10.4.-%E8%87%AA%E5%8A%A8%E5%8C%96%E6%A3%80%E6%9F%A5%E5%B7%A5%E5%85%B7\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#10.4.-%E8%87%AA%E5%8A%A8%E5%8C%96%E6%A3%80%E6%9F%A5%E5%B7%A5%E5%85%B7\">#\u003C\u002Fa> 10.4. 自动化检查工具\u003C\u002Fh4>\n\u003Cp>\u003Cstrong>消费者检查\u003C\u002Fstrong> — \u003Ccode>bash scripts\u002Fapi-surface.sh [package]\u003C\u002Fcode>\u003C\u002Fp>\n\u003Cp>检查各包 barrel 导出是否有包外消费者。零消费者的导出应评估是否应标记 \u003Ccode>@internal\u003C\u002Fcode> 或移除。\u003C\u002Fp>\n\u003Cp>例：\u003C\u002Fp>\n\u003Cpre data-lang=\"bash\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6F42C1\">bash\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> scripts\u002Fapi-surface.sh\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> core\u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">      # 仅检查 @cmtx\u002Fcore\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6F42C1\">bash\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> scripts\u002Fapi-surface.sh\u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">           # 检查所有包\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>\u003Cstrong>文档同步检查\u003C\u002Fstrong> — \u003Ccode>node scripts\u002Fcheck-api-docs-sync.mjs [package]\u003C\u002Fcode>\u003C\u002Fp>\n\u003Cp>检查 \u003Ccode>docs\u002Fapi\u002F*.md\u003C\u002Fcode> 手写文档与代码是否同步，覆盖：\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>报告标记\u003C\u002Fth>\n\u003Cth>含义\u003C\u002Fth>\n\u003Cth>处理方法\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>[MISSING]\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>代码中公开导出但文档未收录\u003C\u002Ftd>\n\u003Ctd>补充文档\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>[STALE]\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>文档中存在但代码中已不存在\u003C\u002Ftd>\n\u003Ctd>清理文档\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>[SIGNATURE]\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>文档中函数参数名与代码不一致\u003C\u002Ftd>\n\u003Ctd>修正文档签名\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>例：\u003C\u002Fp>\n\u003Cpre data-lang=\"bash\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6F42C1\">node\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> scripts\u002Fcheck-api-docs-sync.mjs\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> core\u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">   # 仅检查 @cmtx\u002Fcore\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6F42C1\">node\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> scripts\u002Fcheck-api-docs-sync.mjs\u003C\u002Fspan>\u003Cspan style=\"color:#6A737D\">        # 检查所有包\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>\u003Cstrong>排查消费者技巧\u003C\u002Fstrong>：\u003C\u002Fp>\n\u003Cpre data-lang=\"bash\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># 确认某个符号是否有跨包消费者（精确匹配 import 语句）\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6F42C1\">grep\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> -rl\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> --include=\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\">'*.ts'\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> \\\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#032F62\">  \"import[^;]*\\bFoo\\b[^;]*from\\s*['\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\">\\\"\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\">]@cmtx\u002Fxxx['\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\">\\\"\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\">]\"\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> \\\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#032F62\">  packages\u002F\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> |\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> grep\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> -v\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> \"packages\u002Fxxx\u002F\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># 列出所有从某个包导入的符号（全局视角）\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6F42C1\">grep\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> -roh\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> 'from \"@cmtx\u002Fcore\"[^;]*'\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> packages\u002F\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> \\\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">  |\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> grep\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> -v\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> \"packages\u002Fcore\u002F\"\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> \\\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49\">  |\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> grep\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> -oP\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> '\\{\\s*\\K[^}]+'\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> |\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> tr\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> ','\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> '\\n'\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> |\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> sed\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> 's\u002F^ *\u002F\u002F'\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> |\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> sort\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> -u\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>\u003Cstrong>死亡 API 排查工作流\u003C\u002Fstrong>：\u003C\u002Fp>\n\u003Cp>对 \u003Ccode>api-surface.sh\u003C\u002Fcode> 报告的零消费者导出，按以下步骤判断是否应标记 \u003Ccode>@internal\u003C\u002Fcode> 或移除：\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>包内引用\u003C\u002Fstrong>：确认是否仅在定义文件和 barrel 中出现，无其他调用方\u003Cpre data-lang=\"bash\" class=\"shiki github-light\" style=\"background-color:#fff;color:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6F42C1\">grep\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> -rn\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> '\\bFoo\\b'\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> packages\u002Fxxx\u002Fsrc\u002F\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49\"> |\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1\"> grep\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5\"> -v\u003C\u002Fspan>\u003Cspan style=\"color:#032F62\"> 'index.ts'\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fli>\n\u003Cli>\u003Cstrong>功能覆盖\u003C\u002Fstrong>：同模块内是否存在功能覆盖的上层 API\n\u003Cul>\n\u003Cli>底层辅助函数（如 \u003Ccode>updateImageAttribute\u003C\u002Fcode>）已被高层 API（如 \u003Ccode>setImageDimensions\u003C\u002Fcode> \u002F \u003Ccode>replaceImages\u003C\u002Fcode>）覆盖 → 内部化\u003C\u002Fli>\n\u003Cli>跨层下沉残留（如 \u003Ccode>applyReplacementOps\u003C\u002Fcode>）下沉后原调用方未更新 → 内部化\u003C\u002Fli>\n\u003Cli>独立的公共原语（如 \u003Ccode>filterImages\u003C\u002Fcode>）有真实消费者 → 保留\u003C\u002Fli>\n\u003C\u002Ful>\n\u003C\u002Fli>\n\u003Cli>\u003Cstrong>模式判断\u003C\u002Fstrong>：零消费者 + 无独立功能价值 = 死亡 API\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Chr>\n\u003Ch2 id=\"5.-%E9%99%84%E5%BD%95-a\" tabindex=\"-1\">\u003Ca class=\"header-anchor\" href=\"#5.-%E9%99%84%E5%BD%95-a\">#\u003C\u002Fa> 5. 附录 A\u003C\u002Fh2>\n\u003Cblockquote>\n\u003Cp>应用层交互设计（CLI 命令结构、VS Code 命令命名、MCP 工具设计）待后续 SPRINT 补充。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n",1786290224903]