Skip to content

Fix the indentation of exported code - #1997

Merged
diemol merged 2 commits into
trunkfrom
fix-export-indentation
Oct 29, 2026
Merged

diemol merged 2 commits into
trunkfrom
fix-export-indentation

Conversation

@diemol

@diemol diemol commented Oct 29, 2026

Copy link
Copy Markdown
Member

Description

  • emitCommands keeps each command's emitted block whole instead of flattening it into loose lines. A block's startingLevelAdjustment and endingLevelAdjustment now apply again.
  • prettify renders each line of a block at the block's starting level plus the line's own level, like v3 did.
  • render walks a list of commands with a running level: each command starts at the level the previous one ended at.
  • Turned back on the 4 prettify tests, the Ruby repeatIf test, a hook test and the render tests (they used the v3 TestCase model; now a plain object). Added a render test for a block that indents the lines after it.
  • Snapshots changed only by dropping a trailing newline after each command, and the ending level of else/else if blocks at level 0.

Motivation and Context

Exported code lost its indentation: method bodies in Python were at class level, and if/loop bodies weren't indented. I exported every project in tests/examples in all six languages, before and after:

  • Python: 17 of 18 files didn't compile before, 2 now.
  • Ruby and JavaScript: same as before (2 and 3 failures).
  • Java and C# output now has the right indentation.

The remaining failures are other bugs, not indentation: variables inside strings (${name}) are exported as broken code, and an empty times loop has no body in Python.

Comments from a command's description also show up above the right command now.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • I have read the contributing document.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

🤖 Generated with Claude Code

Each command's emitted block is kept whole again, and each line of a block
is rendered at the block's starting level plus the line's own level. Before,
the blocks were flattened, so the level changes from if/else/loops were lost
and the exported code had no indentation. Python exports didn't compile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@diemol

diemol commented Oct 29, 2026

Copy link
Copy Markdown
Member Author

/agentic_review

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Restore indentation in exported test code

🐞 Bug fix 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Preserve each emitted command block so control-flow indentation changes reach the renderer.
• Indent block lines relative to their starting level, restoring correctly nested exported code.
• Re-enable indentation tests and refresh command snapshots for the six language exporters.
Diagram

graph TD
  A["Test commands"] --> B["Emit blocks"] --> C["Render sequence"] --> D["Prettify blocks"] --> E["Exported code"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Flatten blocks with level markers
  • ➕ Could retain a flat stream for existing rendering consumers.
  • ➖ Requires extra metadata and bookkeeping to preserve block boundaries, level adjustments, and command-to-comment alignment.

Recommendation: Keep the PR’s structured-block approach. The existing block model already expresses relative line levels and start/end adjustments; carrying it through rendering is simpler than reconstructing that information after flattening.

Files changed (13) +398 / -736

Bug fix (3) +57 / -70
emit.tsPreserve emitted command blocks +7/-19

Preserve emitted command blocks

• Stops flattening emitted blocks and splitting command strings into loose lines. Passes the resulting command list directly to test rendering so its level adjustments remain available.

packages/side-code-export/src/code-export/emit.ts

prettify.tsIndent block lines relative to their starting level +32/-31

Indent block lines relative to their starting level

• Applies the block’s adjusted starting level to every line while retaining each statement’s relative level. Keeps skipped-block level transitions and clamps ending levels at zero.

packages/side-code-export/src/code-export/prettify.ts

render.tsCarry indentation across command sequences +18/-20

Carry indentation across command sequences

• Renders arrays as ordered command sequences, passing each command the previous command’s ending level. Uses the preserved blocks for formatting while keeping origin-tracing rows associated with their commands.

packages/side-code-export/src/code-export/render.ts

Tests (10) +341 / -666
command.spec.js.snapRefresh C# NUnit command snapshots +55/-109

Refresh C# NUnit command snapshots

• Removes trailing newlines from emitted command bodies and records updated ending levels for control-flow commands.

packages/code-export-csharp-nunit/test/src/snapshots/command.spec.js.snap

command.spec.js.snapRefresh C# xUnit command snapshots +16/-32

Refresh C# xUnit command snapshots

• Updates multiline command expectations to omit the trailing newline from each emitted body.

packages/code-export-csharp-xunit/test/src/snapshots/command.spec.js.snap

command.spec.js.snapRefresh Java JUnit command snapshots +55/-109

Refresh Java JUnit command snapshots

• Removes trailing command-body newlines and captures corrected ending levels for branch and end commands.

packages/code-export-java-junit/test/src/snapshots/command.spec.js.snap

command.spec.js.snapRefresh JavaScript Mocha command snapshots +52/-115

Refresh JavaScript Mocha command snapshots

• Records command bodies without trailing newlines and revised control-flow ending levels.

packages/code-export-javascript-mocha/test/src/snapshots/command.spec.js.snap

command.spec.js.snapRefresh Python pytest command snapshots +58/-139

Refresh Python pytest command snapshots

• Removes trailing newlines from emitted bodies and records updated branch and end-command levels.

packages/code-export-python-pytest/test/src/snapshots/command.spec.js.snap

command.spec.js.snapRefresh Ruby RSpec command snapshots +58/-135

Refresh Ruby RSpec command snapshots

• Updates emitted bodies to exclude trailing newlines and captures corrected control-flow ending levels.

packages/code-export-ruby-rspec/test/src/snapshots/command.spec.js.snap

command.spec.jsRe-enable Ruby repeatIf coverage +1/-3

Re-enable Ruby repeatIf coverage

• Runs the previously skipped repeatIf emission snapshot test now that its negative indentation issue is addressed.

packages/code-export-ruby-rspec/test/src/command.spec.js

hook.spec.tsRestore optional-hook coverage +6/-6

Restore optional-hook coverage

• Re-enables the optional-hook test with the expected empty command list. Clarifies why the separate empty-hook test remains skipped.

packages/side-code-export/test/src/code-export/hook.spec.ts

prettify.spec.tsRe-enable relative indentation tests +4/-12

Re-enable relative indentation tests

• Restores four tests covering block line levels, nonzero starting levels, nested lines, and starting-level adjustments.

packages/side-code-export/test/src/code-export/prettify.spec.ts

render.spec.jsRestore render tests and cover level transitions +36/-6

Restore render tests and cover level transitions

• Replaces the legacy TestCase fixture with a plain test object. Adds a sequence test covering indentation through if, else, and skipped end blocks.

packages/side-code-export/test/src/code-export/render.spec.js

@qodo-code-review

qodo-code-review Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Traced blocks lose their source comments ✓ Resolved
Description
renderCommand now sends a single command block directly to prettify, which does not receive its
originTracing or enableOriginTracing options. When a caller renders a block with tracing
enabled, the command text appears without the tracing header or per-command records that the
previous block-rendering path emitted.
Code

packages/side-code-export/src/code-export/render.ts[R60-63]

+  const result = prettify(input, {
+    commandPrefixPadding,
+    startingLevel,
+  })
Evidence
The new single-block path passes only padding and starting level to prettify; tracing is emitted
exclusively inside renderCommands. renderCommand and its tracing options are exported.

packages/side-code-export/src/code-export/render.ts[20-67]
packages/side-code-export/src/code-export/render.ts[83-113]
packages/side-code-export/src/code-export/index.ts[23-34]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Rendering a single command block no longer emits requested origin-tracing comments because that path bypasses `renderCommands`.

## Fix Focus Areas
- packages/side-code-export/src/code-export/render.ts[51-67]
- packages/side-code-export/src/code-export/render.ts[83-120]

## Recommended Fix
Route traced block inputs through a rendering path that emits their tracing header and records while preserving block-level indentation adjustments. Add a test calling `renderCommand` with a block and tracing enabled.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Existing callers cannot render block lists ✓ Resolved
Description
renderCommands now calls forEach on its argument without accepting the previously supported `{
commands: [...] }` form. A caller passing that block form to the publicly exported helper now gets a
type error or, at runtime, commands.forEach is not a function.
Code

packages/side-code-export/src/code-export/render.ts[103]

+  commands.forEach((command, index) => {
Evidence
The changed parameter type excludes ExportCommandsShape, and the changed loop requires an array.
The helper remains publicly re-exported.

packages/side-code-export/src/code-export/render.ts[77-104]
packages/side-code-export/src/code-export/index.ts[23-34]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`renderCommands` no longer accepts its previously supported `{ commands: [...] }` input, breaking callers of this publicly exported helper.

## Fix Focus Areas
- packages/side-code-export/src/code-export/render.ts[77-104]

## Recommended Fix
Restore the block form in the parameter type and normalize block and array inputs to an array before iteration. Add a test that passes a block directly to `renderCommands`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
Review mode: Auto: ⚖️ Balanced: Behavioral rendering changes affect indentation, origin tracing, and command-level transitions.
✅ Fix-loop round: fix loop

Grey Divider

Tip of the day
💡 Did you know, you can add REVIEW.md to your repo root and Qodo follows it on every PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Previous reviews

Review updated until commit f2bf0be

Results up to commit 55231b4 🧠 Deep


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Remediation recommended
1. Traced blocks lose their source comments ✓ Resolved
Description
renderCommand now sends a single command block directly to prettify, which does not receive its
originTracing or enableOriginTracing options. When a caller renders a block with tracing
enabled, the command text appears without the tracing header or per-command records that the
previous block-rendering path emitted.
Code

packages/side-code-export/src/code-export/render.ts[R60-63]

+  const result = prettify(input, {
+    commandPrefixPadding,
+    startingLevel,
+  })
Evidence
The new single-block path passes only padding and starting level to prettify; tracing is emitted
exclusively inside renderCommands. renderCommand and its tracing options are exported.

packages/side-code-export/src/code-export/render.ts[20-67]
packages/side-code-export/src/code-export/render.ts[83-113]
packages/side-code-export/src/code-export/index.ts[23-34]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Rendering a single command block no longer emits requested origin-tracing comments because that path bypasses `renderCommands`.

## Fix Focus Areas
- packages/side-code-export/src/code-export/render.ts[51-67]
- packages/side-code-export/src/code-export/render.ts[83-120]

## Recommended Fix
Route traced block inputs through a rendering path that emits their tracing header and records while preserving block-level indentation adjustments. Add a test calling `renderCommand` with a block and tracing enabled.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Existing callers cannot render block lists ✓ Resolved
Description
renderCommands now calls forEach on its argument without accepting the previously supported `{
commands: [...] }` form. A caller passing that block form to the publicly exported helper now gets a
type error or, at runtime, commands.forEach is not a function.
Code

packages/side-code-export/src/code-export/render.ts[103]

+  commands.forEach((command, index) => {
Evidence
The changed parameter type excludes ExportCommandsShape, and the changed loop requires an array.
The helper remains publicly re-exported.

packages/side-code-export/src/code-export/render.ts[77-104]
packages/side-code-export/src/code-export/index.ts[23-34]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`renderCommands` no longer accepts its previously supported `{ commands: [...] }` input, breaking callers of this publicly exported helper.

## Fix Focus Areas
- packages/side-code-export/src/code-export/render.ts[77-104]

## Recommended Fix
Restore the block form in the parameter type and normalize block and array inputs to an array before iteration. Add a test that passes a block directly to `renderCommands`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

renderCommands accepts a block again, and renderCommand renders a block
with origin tracing one command at a time, like before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@diemol

diemol commented Oct 29, 2026

Copy link
Copy Markdown
Member Author

/agentic_review

@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit f2bf0be

@diemol
diemol merged commit 49bd539 into trunk Oct 29, 2026
5 checks passed
@diemol
diemol deleted the fix-export-indentation branch October 29, 2026 15:37
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.

1 participant