()
| 265 | |
| 266 | /** |
| 267 | * 从 from 起、limit 之前,下一个**像负载**的行首 '{':结构由 nextLineStartBrace 给出, |
| 268 | * 形状按位置选谓词(首位 isLeakedToolPayloadShape / 正文之后 isPlausibleAfterProsePayload)。 |
| 269 | * 三个消费者共用(识别器、残片切点、抢救的锚点检查),候选的定义只有这一份。 |
| 270 | * 便宜的 "name" 窗口判断先行,像负载的候选才切出(可能很长的)尾巴给谓词。 |
| 271 | * @returns {number} -1 表示没有 |
| 272 | */ |
| 273 | const nextPayloadCandidate = (text, from, atLineStart, limit, afterProse) => { |
| 274 | let at = nextLineStartBrace(text, from, atLineStart, limit); |
| 275 | while (at !== -1) { |
| 276 | if (LEAKED_PAYLOAD_NAME_RE.test(text.slice(at, at + LEAKED_PAYLOAD_NAME_WINDOW))) { |
| 277 | const shape = afterProse |
| 278 | ? isPlausibleAfterProsePayload(text.slice(at, at + AFTER_PROSE_PAYLOAD_MAX + 1)) |
| 279 | : isLeakedToolPayloadShape(text.slice(at)); |
| 280 | if (shape) return at; |
| 281 | } |
| 282 | at = nextLineStartBrace(text, at + 1, false, limit); |
| 283 | } |
| 284 | return -1; |
| 285 | }; |
| 286 | |
| 287 | /** |
| 288 | * index 处是否处在**行首**:上一个换行(或文本开头)到 index 之间只有空白。两条路径 |
| 289 | * 共用同一个谓词(review loop 2):整段路径在每个扫描位置与残片切点之后的恢复点上问它 |
| 290 | * (`fullText[position-1] === '\n'` 会把缩进过的 ` {"name":…}` 拒之门外);流式解析器 |
| 291 | * 用它在每个放行点更新 lineStart —— 放行的文本没有换行时沿用之前的状态(prior), |
| 292 | * 于是切在前导空白中间的 chunk 边界也不会让下一个 '{' 失去行首身份。 |
| 293 | * 代价是 index 之前那一串空白的长度,遇到第一个非空白就停。 |
| 294 | * @param {string} text |
| 295 | * @param {number} index |
| 296 | * @param {boolean} [prior=true] - 文本开头之前的行首状态 |
| 297 | * @returns {boolean} |
| 298 | */ |
| 299 | const lineStartBefore = (text, index, prior = true) => { |
| 300 | let i = index - 1; |
| 301 | while (i >= 0 && (text[i] === ' ' || text[i] === '\t' || text[i] === '\r')) i -= 1; |
| 302 | return i < 0 ? prior : text[i] === '\n'; |
| 303 | }; |
| 304 | |
| 305 | /** |
| 306 | * 记录正文当前是否处在代码上下文里。文档里的例子必须保持是例子:``` 围栏内, |
| 307 | * 或同一行反引号数为奇数(行内代码)时,触发器不算触发器。 |
| 308 | * 增量式:只喂**已经放行**的正文,所以流式和整段两条路径可以共用同一套判断。 |
| 309 | */ |
| 310 | const createCodeContextTracker = () => { |
| 311 | let inFence = false; |
| 312 | let ticksOnLine = 0; |
| 313 | let run = 0; |
| 314 | let runAtLineStart = true; // 这串反引号前面,本行是不是只有空白 |
| 315 | let lineIsBlank = true; // 本行到目前为止是不是只有空白 |
| 316 | |
| 317 | // 围栏必须**顶行**(Markdown 的规则)。之前任何位置的三连反引号都会翻转围栏状态, |
| 318 | // 于是 JSON 字符串里的 ``` 也算围栏;一旦错位就再也回不来,后面每个真实调用都被 |
| 319 | // 当成文档静默丢掉 —— 正是这次要消灭的那类无声失败。 |
| 320 | const settle = () => { |
| 321 | if (run === 0) return; |
| 322 | if (run >= 3 && runAtLineStart) { |
| 323 | inFence = !inFence; |
| 324 | ticksOnLine = 0; |
no outgoing calls
no test coverage detected