Skip to content

fix(adapters): escape carriage returns in YAML frontmatter and dedupe escapeYamlValue#1240

Open
zied-jlassi wants to merge 1 commit into
Fission-AI:mainfrom
zied-jlassi:fix/yaml-escape-carriage-return
Open

fix(adapters): escape carriage returns in YAML frontmatter and dedupe escapeYamlValue#1240
zied-jlassi wants to merge 1 commit into
Fission-AI:mainfrom
zied-jlassi:fix/yaml-escape-carriage-return

Conversation

@zied-jlassi

@zied-jlassi zied-jlassi commented Jun 22, 2026

Copy link
Copy Markdown

Summary

escapeYamlValue flags \r (carriage return) as a character that requires quoting, but never escapes it. The value is wrapped in double quotes with a literal CR left inside the scalar. A literal carriage return inside a double-quoted YAML scalar is subject to line folding/normalization, so the value can be silently corrupted when the generated frontmatter is read back — realistic when a command name/description/category/tag is authored with CRLF (Windows) line endings.

This also extracts the helper, which is currently duplicated verbatim across five adapters, into a single shared module.

The bug (before)

// detection includes \r ...
const needsQuoting = /[:\n\r#{}[\],&*!|>'"%@`]|^\s|\s$/.test(value);
if (needsQuoting) {
  // ... but the escape chain never handles \r
  const escaped = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n');
  return `"${escaped}"`;
}

So escapeYamlValue("Line 1\rLine 2") produced "Line 1<CR>Line 2" (literal CR inside quotes) instead of "Line 1\rLine 2".

What changed

  • Fix: escape \r as \r alongside the existing \\, " and \n handling.
  • Dedupe (DRY): the identical helper lived in bob.ts, claude.ts, cursor.ts, pi.ts and windsurf.ts. It now lives once in src/core/command-generation/yaml.ts and is imported by all five. No behavior change for those adapters beyond the \r fix.
  • Tests: new test/core/command-generation/yaml.test.ts covers the escaping rules and round-trips values (plain / colon / quotes / backslash / \n / \r / CRLF / mixed) through a real YAML parser (yaml) to assert the value survives.

Note vs. the linked issues: the helper is duplicated in five files (bob, claude, cursor, pi, windsurf), not three — and qwen emits TOML, so it does not use this helper.

Testing

  • pnpm test for the touched area: yaml.test.ts (16) + adapters.test.ts (92) → 108 passing.
  • eslint src/core/command-generation/ → clean.
  • pnpm run build (tsc) → compiles.
  • Full pnpm test: all command-generation tests pass. I saw two unrelated timeouts in test/commands/initiative.test.ts under full-suite load; they pass on a pristine checkout (running ~6.5–7.3s, just under the 10s timeout) and are independent of this change (it only touches YAML escaping). Flagging transparently in case CI flakes there.

Closes #1205
Closes #1204

Summary by CodeRabbit

  • Bug Fixes
    • Fixed carriage returns not being properly escaped in YAML frontmatter generation across multiple command adapters, preventing literal carriage return characters from appearing in generated output.

… escapeYamlValue

escapeYamlValue detected \r as a character requiring quoting but never
escaped it, leaving a literal carriage return inside the double-quoted
scalar. A literal CR there is subject to YAML line folding/normalization
and could silently corrupt the round-tripped value (realistic with
CRLF-authored command descriptions).

- Escape \r as \r alongside the existing \, " and \n handling.
- Extract the helper, previously duplicated verbatim across five adapters
  (bob, claude, cursor, pi, windsurf), into a shared
  command-generation/yaml.ts module.
- Add unit tests covering the escaping rules and a round-trip through a
  real YAML parser.

Refs Fission-AI#1205, Fission-AI#1204
@zied-jlassi zied-jlassi requested a review from TabishB as a code owner June 22, 2026 16:20
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cf675443-d2f0-46c7-a5f3-247296ceae50

📥 Commits

Reviewing files that changed from the base of the PR and between 1b06fdd and cd89f2b.

📒 Files selected for processing (8)
  • .changeset/escape-yaml-carriage-return.md
  • src/core/command-generation/adapters/bob.ts
  • src/core/command-generation/adapters/claude.ts
  • src/core/command-generation/adapters/cursor.ts
  • src/core/command-generation/adapters/pi.ts
  • src/core/command-generation/adapters/windsurf.ts
  • src/core/command-generation/yaml.ts
  • test/core/command-generation/yaml.test.ts

📝 Walkthrough

Walkthrough

A new shared module src/core/command-generation/yaml.ts is introduced exporting escapeYamlValue, which now also escapes \r characters. Five command adapters (bob, claude, cursor, pi, windsurf) drop their local copies and import from this shared module. A Vitest test suite and a changeset entry accompany the change.

Changes

YAML utility extraction and adapter migration

Layer / File(s) Summary
Shared escapeYamlValue utility and tests
src/core/command-generation/yaml.ts, test/core/command-generation/yaml.test.ts, .changeset/escape-yaml-carriage-return.md
New yaml.ts module exports escapeYamlValue with \r → \\r escaping added. Vitest suite covers quoting, all escape sequences, and YAML round-trip validation. Changeset records the patch.
Adapter import migrations
src/core/command-generation/adapters/bob.ts, src/core/command-generation/adapters/claude.ts, src/core/command-generation/adapters/cursor.ts, src/core/command-generation/adapters/pi.ts, src/core/command-generation/adapters/windsurf.ts
Local escapeYamlValue implementations removed from all five adapters; each now imports the function from ../yaml.js while call sites remain unchanged.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

A carriage return snuck into YAML with glee,
But the rabbit said "Nope, you must be escaped, see!"
Five adapters once copied the same little function,
Now one shared module handles every conjunction.
\r gets a backslash, all frontmatter is clean,
The tidiest YAML the codebase has seen! 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: fixing carriage return escaping in YAML and deduplicating escapeYamlValue across adapters.
Linked Issues check ✅ Passed The PR successfully addresses all coding requirements from issues #1205 and #1204: extracting escapeYamlValue to a shared module, implementing \r escaping, updating five adapters (bob, claude, cursor, pi, windsurf), and adding comprehensive tests.
Out of Scope Changes check ✅ Passed All changes are directly related to the stated objectives: the new yaml.ts module, adapter refactoring, and test coverage. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant