Something went wrong. Try again.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100import type { Command, Script, Target } from "./parser";
const quote = (s: string): string => `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n")}"`;const textKey = (match: "ignoreCase" | "containsIgnoreCase" | undefined): string => (match === "ignoreCase" ? "text-i" : match === "containsIgnoreCase" ? "text~i" : "text");export const printTarget = (t: Target): string => Object.entries(t).map(([k, v]) => `${k}:${k === "role" && /^[a-z][a-z-]*$/.test(v) ? v : quote(v)}`).join(" ");
function modifiers(c: Command): string { const parts: string[] = []; if ("within" in c && c.within !== undefined) parts.push(`within:${quote(c.within)}`); if (c.timeoutMs !== undefined) parts.push(`timeout:${c.timeoutMs}ms`); if (c.as !== undefined) parts.push(`as:${quote(c.as)}`); if (c.on !== undefined) parts.push(`on:${c.on}`); return parts.length > 0 ? " " + parts.join(" ") : "";}
export function printCommand(c: Command): string { return `${body(c)}${modifiers(c)}`;}
function body(c: Command): string { switch (c.verb) { case "start": case "goto": return `${c.verb} ${c.url}`; case "click": case "doubleClick": case "check": case "uncheck": return `${c.verb} ${printTarget(c.target)}`; case "type": return `type ${printTarget(c.target)} ${quote(c.text)}`; case "select": return `select ${printTarget(c.target)} ${quote(c.option)}`; case "press": return `press ${quote(c.key)}`; case "sleep": return `sleep ${c.ms}ms`; case "capture": return `capture ${c.name} ${printTarget(c.target)}`; case "set": return `set ${c.name} ${quote(c.value)}`; case "switchTab": return c.tab.kind === "new" ? "switchTab new" : `switchTab url~:${quote(c.tab.contains)}`; case "closeTab": return "closeTab"; case "drag": { const [[key, value]] = Object.entries(c.to) as [[string, string]]; return `drag ${printTarget(c.target)} to:${key}:${quote(value)}`; } case "screenshot": return `screenshot ${quote(c.name)}`; case "call": return ["call", c.name, ...c.args.map(quote)].join(" "); case "run": return `run ${quote(c.path)}`; case "wait": switch (c.kind) { case "visible": return `wait ${printTarget(c.target)}`; case "gone": return `wait ${printTarget(c.target)} gone`; case "textChanges": return `wait ${printTarget(c.target)} text-changes`; case "url": return `wait url~:${quote(c.contains)}`; case "networkIdle": return "wait network-idle"; } break; case "verify": case "verifyNot": switch (c.kind) { case "exists": return `${c.verb} ${printTarget(c.target)}`; case "text": return `${c.verb} ${textKey(c.match)}:${quote(c.value)}`; case "targetText": return `${c.verb} ${printTarget(c.target)} ${textKey(c.match)}:${quote(c.value)}`; case "value": return `${c.verb} ${printTarget(c.target)} value:${quote(c.value)}`; case "state": return `${c.verb} ${printTarget(c.target)} ${c.state}`; case "count": return `${c.verb} ${printTarget(c.target)} count:${c.count}`; case "url": return `${c.verb} url~:${quote(c.contains)}`; case "title": return `${c.verb} title:${quote(c.value)}`; case "numberChange": return `${c.verb} ${printTarget(c.target)} number:changed-by from:${quote(c.from)} equals:${c.equals}`; case "attr": return `${c.verb} ${printTarget(c.target)} attr:${c.attr} ${c.op}:${quote(c.value)}`; case "download": return `${c.verb} download ${c.nameMatch === "contains" ? "name~" : "name"}:${quote(c.name)}${c.sizeMin !== undefined ? ` size-min:${c.sizeMin}` : ""}`; } } throw new Error("unreachable");}
/** The script as text that parses back to the same tree (comments and spacing are not kept). */export function printScript(script: Script): string { const lines = [`test ${quote(script.name)}`]; if (script.covers.length > 0) lines.push(`covers ${script.covers.join(" ")}`); if (script.posts === true) lines.push("posts"); if (script.spends === true) lines.push("spends"); if (script.start !== undefined) lines.push(`start ${script.start}`); if (script.needsSession !== undefined) lines.push(`needs session ${script.needsSession}`); for (const n of script.alsoNeeds ?? []) lines.push(`needs session ${n.name}`); if (script.timeoutMs !== undefined) lines.push(`timeout ${script.timeoutMs}ms`); for (const step of script.steps) { lines.push(`step ${quote(step.name)}`); for (const c of step.commands) lines.push(` ${printCommand(c)}`); } return lines.join("\n") + "\n";}