Skip to content

fix(env): unquote reverses backslash escape#4

Open
oratis wants to merge 1 commit into
mainfrom
fix/env-unquote-backslash-3
Open

fix(env): unquote reverses backslash escape#4
oratis wants to merge 1 commit into
mainfrom
fix/env-unquote-backslash-3

Conversation

@oratis
Copy link
Copy Markdown
Owner

@oratis oratis commented May 20, 2026

Closes #3.

What

quoteValue and unquote in src/env.ts were asymmetric. saveConfigEnv escapes \\\ when serializing, but loadConfigEnvunquote only reverses \"" and \n → newline — it never undoes the \\. Every save/load cycle therefore doubled the number of backslashes in any value containing one.

Before vs after (round-trip)

Input Quoted (file) Before — unquote returned After
C:\Users\path "C:\\Users\\path" C:\\Users\\path C:\Users\path
API\KEY_X "API\\KEY_X" API\\KEY_X API\KEY_X
with\backslash "with\\backslash" with\\backslash with\backslash

ASCII-safe values (no special chars), values with ", and values with \n were unaffected — still round-trip identically.

Change

return first === '"'
  ? inner.replace(/\\(["\\n])/g, (_, c) => (c === "n" ? "\n" : c))
  : inner;

Single-pass replace with a substitution callback. The alternative — three sequential .replace() calls — has an ordering trap: doing /\\\\/g → \\ first would consume the leading \\ in \\n and produce a stray \n token; doing \n first would produce a real newline before the \\ step could see the surrounding context. The callback form covers all three escape sequences in one left-to-right pass.

Verification

10-case round-trip test (passthrough, spaces, quotes, newlines, single/double/trailing backslashes, Windows paths, combination): all pass. Output in the issue body.

Scope

  • One file (src/env.ts), one function (unquote, 3-line change)
  • No public API change, no new deps
  • npm run typecheck clean

🤖 Generated with Claude Code

quoteValue / unquote in src/env.ts were asymmetric: writing a value
containing `\` escaped it to `\\` in config.env, but reading it back
never unescaped, so every save/load cycle doubled the backslashes.
Windows paths and any tokens with literal backslashes accumulated
extra characters indefinitely.

Single-pass replace with a substitution callback so `\\`, `\"`, and
`\n` are all undone in one go (avoids the ordering trap where a
naive `/\\\\/ → \\` first-pass would collide with `\\n`).

Verified by 10-case round-trip table including ASCII-safe (passthrough),
spaces, quotes, newlines, single + double + trailing backslashes,
Windows paths, and a combo of all three escape sequences.

Closes #3

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

env: unquote doesn't reverse \\\\ escape — backslash values are corrupted on round-trip

1 participant