import { type PullRequestTarget, type ReviewOptions, THINKING_LEVELS, type ThinkingLevel, } from "./types.ts"; const PR_URL = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)\/?$/; function tokenize(input: string): string[] { const tokens: string[] = []; let token = ""; let quote: "'" | '"' | undefined; let escaping = false; for (const character of input) { if (escaping) { token += character; escaping = false; continue; } if (character === "\\") { escaping = true; continue; } if (quote) { if (character === quote) quote = undefined; else token += character; continue; } if (character === "'" || character === '"') { quote = character; continue; } if (/\s/.test(character)) { if (token) { tokens.push(token); token = ""; } continue; } token += character; } if (escaping) throw new Error("Argument list ends with an incomplete escape"); if (quote) throw new Error("Argument list contains an unterminated quote"); if (token) tokens.push(token); return tokens; } function parseTarget(value: string): PullRequestTarget { if (/^[1-9]\d*$/.test(value)) return { kind: "number", number: Number(value) }; const match = PR_URL.exec(value); if (match) { return { kind: "url", url: value.replace(/\/$/, ""), owner: match[1], repo: match[2], number: Number(match[3]), }; } throw new Error(`Invalid pull request target: ${value}`); } export function parseArguments(input: string): ReviewOptions { const tokens = tokenize(input); let target: PullRequestTarget | undefined; let comment = false; let model: string | undefined; let thinking: ThinkingLevel | undefined; for (let index = 0; index < tokens.length; index++) { const token = tokens[index]; if (token === "--comment") { if (comment) throw new Error("Duplicate --comment flag"); comment = true; continue; } if (token === "--model") { if (model) throw new Error("Duplicate --model flag"); model = tokens[++index]; if (!model || model.startsWith("--")) throw new Error("--model requires a value"); continue; } if (token === "--thinking") { if (thinking) throw new Error("Duplicate --thinking flag"); const value = tokens[++index]; if (!value || !THINKING_LEVELS.includes(value as ThinkingLevel)) { throw new Error( `--thinking requires one of: ${THINKING_LEVELS.join(", ")}`, ); } thinking = value as ThinkingLevel; continue; } if (token.startsWith("--")) throw new Error(`Unknown flag: ${token}`); if (target) throw new Error("Only one pull request target may be provided"); target = parseTarget(token); } return { target: target ?? { kind: "current" }, comment, model, thinking }; }