Spaces:
Configuration error
Configuration error
| import { parseDurationMs } from "../../../cli/parse-duration.js"; | |
| import { normalizeQueueDropPolicy, normalizeQueueMode } from "./normalize.js"; | |
| import type { QueueDropPolicy, QueueMode } from "./types.js"; | |
| function parseQueueDebounce(raw?: string): number | undefined { | |
| if (!raw) return undefined; | |
| try { | |
| const parsed = parseDurationMs(raw.trim(), { defaultUnit: "ms" }); | |
| if (!parsed || parsed < 0) return undefined; | |
| return Math.round(parsed); | |
| } catch { | |
| return undefined; | |
| } | |
| } | |
| function parseQueueCap(raw?: string): number | undefined { | |
| if (!raw) return undefined; | |
| const num = Number(raw); | |
| if (!Number.isFinite(num)) return undefined; | |
| const cap = Math.floor(num); | |
| if (cap < 1) return undefined; | |
| return cap; | |
| } | |
| function parseQueueDirectiveArgs(raw: string): { | |
| consumed: number; | |
| queueMode?: QueueMode; | |
| queueReset: boolean; | |
| rawMode?: string; | |
| debounceMs?: number; | |
| cap?: number; | |
| dropPolicy?: QueueDropPolicy; | |
| rawDebounce?: string; | |
| rawCap?: string; | |
| rawDrop?: string; | |
| hasOptions: boolean; | |
| } { | |
| let i = 0; | |
| const len = raw.length; | |
| while (i < len && /\s/.test(raw[i])) i += 1; | |
| if (raw[i] === ":") { | |
| i += 1; | |
| while (i < len && /\s/.test(raw[i])) i += 1; | |
| } | |
| let consumed = i; | |
| let queueMode: QueueMode | undefined; | |
| let queueReset = false; | |
| let rawMode: string | undefined; | |
| let debounceMs: number | undefined; | |
| let cap: number | undefined; | |
| let dropPolicy: QueueDropPolicy | undefined; | |
| let rawDebounce: string | undefined; | |
| let rawCap: string | undefined; | |
| let rawDrop: string | undefined; | |
| let hasOptions = false; | |
| const takeToken = (): string | null => { | |
| if (i >= len) return null; | |
| const start = i; | |
| while (i < len && !/\s/.test(raw[i])) i += 1; | |
| if (start === i) return null; | |
| const token = raw.slice(start, i); | |
| while (i < len && /\s/.test(raw[i])) i += 1; | |
| return token; | |
| }; | |
| while (i < len) { | |
| const token = takeToken(); | |
| if (!token) break; | |
| const lowered = token.trim().toLowerCase(); | |
| if (lowered === "default" || lowered === "reset" || lowered === "clear") { | |
| queueReset = true; | |
| consumed = i; | |
| break; | |
| } | |
| if (lowered.startsWith("debounce:") || lowered.startsWith("debounce=")) { | |
| rawDebounce = token.split(/[:=]/)[1] ?? ""; | |
| debounceMs = parseQueueDebounce(rawDebounce); | |
| hasOptions = true; | |
| consumed = i; | |
| continue; | |
| } | |
| if (lowered.startsWith("cap:") || lowered.startsWith("cap=")) { | |
| rawCap = token.split(/[:=]/)[1] ?? ""; | |
| cap = parseQueueCap(rawCap); | |
| hasOptions = true; | |
| consumed = i; | |
| continue; | |
| } | |
| if (lowered.startsWith("drop:") || lowered.startsWith("drop=")) { | |
| rawDrop = token.split(/[:=]/)[1] ?? ""; | |
| dropPolicy = normalizeQueueDropPolicy(rawDrop); | |
| hasOptions = true; | |
| consumed = i; | |
| continue; | |
| } | |
| const mode = normalizeQueueMode(token); | |
| if (mode) { | |
| queueMode = mode; | |
| rawMode = token; | |
| consumed = i; | |
| continue; | |
| } | |
| // Stop at first unrecognized token. | |
| break; | |
| } | |
| return { | |
| consumed, | |
| queueMode, | |
| queueReset, | |
| rawMode, | |
| debounceMs, | |
| cap, | |
| dropPolicy, | |
| rawDebounce, | |
| rawCap, | |
| rawDrop, | |
| hasOptions, | |
| }; | |
| } | |
| export function extractQueueDirective(body?: string): { | |
| cleaned: string; | |
| queueMode?: QueueMode; | |
| queueReset: boolean; | |
| rawMode?: string; | |
| hasDirective: boolean; | |
| debounceMs?: number; | |
| cap?: number; | |
| dropPolicy?: QueueDropPolicy; | |
| rawDebounce?: string; | |
| rawCap?: string; | |
| rawDrop?: string; | |
| hasOptions: boolean; | |
| } { | |
| if (!body) { | |
| return { | |
| cleaned: "", | |
| hasDirective: false, | |
| queueReset: false, | |
| hasOptions: false, | |
| }; | |
| } | |
| const re = /(?:^|\s)\/queue(?=$|\s|:)/i; | |
| const match = re.exec(body); | |
| if (!match) { | |
| return { | |
| cleaned: body.trim(), | |
| hasDirective: false, | |
| queueReset: false, | |
| hasOptions: false, | |
| }; | |
| } | |
| const start = match.index + match[0].indexOf("/queue"); | |
| const argsStart = start + "/queue".length; | |
| const args = body.slice(argsStart); | |
| const parsed = parseQueueDirectiveArgs(args); | |
| const cleanedRaw = `${body.slice(0, start)} ${body.slice(argsStart + parsed.consumed)}`; | |
| const cleaned = cleanedRaw.replace(/\s+/g, " ").trim(); | |
| return { | |
| cleaned, | |
| queueMode: parsed.queueMode, | |
| queueReset: parsed.queueReset, | |
| rawMode: parsed.rawMode, | |
| debounceMs: parsed.debounceMs, | |
| cap: parsed.cap, | |
| dropPolicy: parsed.dropPolicy, | |
| rawDebounce: parsed.rawDebounce, | |
| rawCap: parsed.rawCap, | |
| rawDrop: parsed.rawDrop, | |
| hasDirective: true, | |
| hasOptions: parsed.hasOptions, | |
| }; | |
| } | |