export type CmdSetAssignment = { key: string; value: string }; export function assertNoCmdLineBreak(value: string, field: string): void { if (/[\r\n]/.test(value)) { throw new Error(`${field} cannot contain CR or LF in Windows task scripts.`); } } function escapeCmdSetAssignmentComponent(value: string): string { return value.replace(/\^/g, "^^").replace(/%/g, "%%").replace(/!/g, "^!").replace(/"/g, '^"'); } function unescapeCmdSetAssignmentComponent(value: string): string { let out = ""; for (let i = 0; i < value.length; i += 1) { const ch = value[i]; const next = value[i + 1]; if (ch === "^" && (next === "^" || next === '"' || next === "!")) { out += next; i += 1; continue; } if (ch === "%" && next === "%") { out += "%"; i += 1; continue; } out += ch; } return out; } export function parseCmdSetAssignment(line: string): CmdSetAssignment | null { const raw = line.trim(); if (!raw) { return null; } const quoted = raw.startsWith('"') && raw.endsWith('"') && raw.length >= 2; const assignment = quoted ? raw.slice(1, -1) : raw; const index = assignment.indexOf("="); if (index <= 0) { return null; } const key = assignment.slice(0, index).trim(); const value = assignment.slice(index + 1).trim(); if (!key) { return null; } if (!quoted) { return { key, value }; } return { key: unescapeCmdSetAssignmentComponent(key), value: unescapeCmdSetAssignmentComponent(value), }; } export function renderCmdSetAssignment(key: string, value: string): string { assertNoCmdLineBreak(key, "Environment variable name"); assertNoCmdLineBreak(value, "Environment variable value"); const escapedKey = escapeCmdSetAssignmentComponent(key); const escapedValue = escapeCmdSetAssignmentComponent(value); return `set "${escapedKey}=${escapedValue}"`; }