(object: Record<string, string>)
| 17 | * @returns string of object |
| 18 | */ |
| 19 | export function stringify(object: Record<string, string>): string { |
| 20 | const lines: string[] = []; |
| 21 | for (const [key, value] of Object.entries(object)) { |
| 22 | let quote; |
| 23 | |
| 24 | let escapedValue = value ?? ""; |
| 25 | if (key.startsWith("#")) { |
| 26 | // deno-lint-ignore no-console |
| 27 | console.warn( |
| 28 | `key starts with a '#' indicates a comment and is ignored: '${key}'`, |
| 29 | ); |
| 30 | continue; |
| 31 | } else if ( |
| 32 | escapedValue.includes("\n") || |
| 33 | escapedValue.includes("\r") || |
| 34 | escapedValue.includes("\t") || |
| 35 | escapedValue.includes("'") || |
| 36 | escapedValue.includes("\\") |
| 37 | ) { |
| 38 | // Escape backslashes first so we don't double-escape sequences we add |
| 39 | // below (e.g. so a literal `\n` (backslash-n) is preserved distinctly |
| 40 | // from a real newline). |
| 41 | escapedValue = escapedValue |
| 42 | .replaceAll("\\", "\\\\") |
| 43 | .replaceAll("\n", "\\n") |
| 44 | .replaceAll("\r", "\\r") |
| 45 | .replaceAll("\t", "\\t"); |
| 46 | quote = `"`; |
| 47 | } else if (escapedValue.match(/\W/)) { |
| 48 | quote = "'"; |
| 49 | } |
| 50 | |
| 51 | if (quote) { |
| 52 | // escape inner quotes |
| 53 | escapedValue = escapedValue.replaceAll(quote, `\\${quote}`); |
| 54 | escapedValue = `${quote}${escapedValue}${quote}`; |
| 55 | } |
| 56 | const line = `${key}=${escapedValue}`; |
| 57 | lines.push(line); |
| 58 | } |
| 59 | return lines.join("\n"); |
| 60 | } |
no test coverage detected