Skip to content

Commit 7a1e0eb

Browse files
committed
refactor: remove unnecessary raw block wrapping from command output
Command imports run in Phase 3 (after LiquidJS template processing), so there's no need to wrap output in {% raw %} blocks to prevent template interpretation. This simplifies the code and test assertions.
1 parent 7b3b6fb commit 7a1e0eb

File tree

3 files changed

+17
-30
lines changed

3 files changed

+17
-30
lines changed

src/__snapshots__/snapshot.test.ts.snap

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,8 @@ Process these files accordingly."
8585
exports[`Snapshot Tests Command substitution executes and inlines command output 1`] = `
8686
"Current date context:
8787
88-
8988
Test command output
9089
91-
9290
Please proceed with the task."
9391
`;
9492

src/imports.test.ts

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,14 @@ test("expandImports throws on missing file", async () => {
7171
test("expandImports executes command inline", async () => {
7272
const content = "Output: !`echo hello`";
7373
const result = await expandImports(content, testDir);
74-
// Command output is wrapped in {% raw %} to prevent LiquidJS template interpretation
75-
expect(result).toBe("Output: {% raw %}\nhello\n{% endraw %}");
74+
// Command output is returned directly (Phase 3 runs after LiquidJS)
75+
expect(result).toBe("Output: hello");
7676
});
7777

7878
test("expandImports handles command with arguments", async () => {
7979
const content = "!`echo one two three`";
8080
const result = await expandImports(content, testDir);
81-
expect(result).toBe("{% raw %}\none two three\n{% endraw %}")
81+
expect(result).toBe("one two three");
8282
});
8383

8484
test("expandImports handles multiple imports", async () => {
@@ -90,7 +90,7 @@ test("expandImports handles multiple imports", async () => {
9090
test("expandImports handles mixed file and command", async () => {
9191
const content = "File: @./simple.md Command: !`echo test`";
9292
const result = await expandImports(content, testDir);
93-
expect(result).toBe("File: Hello from simple.md Command: {% raw %}\ntest\n{% endraw %}");
93+
expect(result).toBe("File: Hello from simple.md Command: test");
9494
});
9595

9696
test("expandImports preserves content without imports", async () => {
@@ -525,15 +525,15 @@ describe("template variables in commands", () => {
525525
expect(result).toContain("piped-content");
526526
});
527527

528-
test("protects command output from template interpretation", async () => {
529-
// Command outputs {{ foo }} - should be wrapped in {% raw %} and not interpreted
528+
test("command output is returned directly (Phase 3 runs after LiquidJS)", async () => {
529+
// Command output containing template-like syntax is returned as-is
530+
// (no wrapping needed since commands run after template processing)
530531
const content = "!`echo '{{ output }}'`";
531532
const result = await expandImports(content, testDir, new Set(), false, {
532533
templateVars: {},
533534
});
534-
// Output should be wrapped in {% raw %}...{% endraw %}
535-
expect(result).toContain("{% raw %}");
536-
expect(result).toContain("{% endraw %}");
535+
// Output should contain the literal {{ output }} text
536+
expect(result).toContain("{{ output }}");
537537
});
538538
});
539539

@@ -651,7 +651,6 @@ describe("executable code fences", () => {
651651
const content = '```sh\n#!/bin/bash\necho "hello from bash"\n```';
652652
const result = await expandImports(content, testDir);
653653
expect(result).toContain("hello from bash");
654-
expect(result).toContain("{% raw %}");
655654
});
656655

657656
test("executes bun/typescript code fence with shebang", async () => {
@@ -672,13 +671,12 @@ describe("executable code fences", () => {
672671
await expect(expandImports(content, testDir)).rejects.toThrow("Code fence failed");
673672
});
674673

675-
test("code fence output is wrapped in raw block", async () => {
674+
test("code fence output is returned directly (Phase 3 runs after LiquidJS)", async () => {
676675
const content = '```sh\n#!/bin/bash\necho "{{ template syntax }}"\n```';
677676
const result = await expandImports(content, testDir);
678-
// Output should be protected from LiquidJS interpretation
679-
expect(result).toContain("{% raw %}");
680-
expect(result).toContain("{% endraw %}");
677+
// Output returned as-is (no wrapping needed since code fences run after template processing)
681678
expect(result).toContain("{{ template syntax }}");
679+
expect(result).not.toContain("{% raw %}");
682680
});
683681

684682
test("respects dry-run mode for code fences", async () => {

src/imports.ts

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,7 @@ async function processCommandInline(
952952
// Improvement #3: Dry-run safety - skip execution if in dry-run mode
953953
if (importCtx?.dryRun) {
954954
console.error(`[imports] Dry-run: Skipping execution of '${actualCommand}'`);
955-
return `{% raw %}\n[Dry Run: Command "${actualCommand}" not executed]\n{% endraw %}`;
955+
return `[Dry Run: Command "${actualCommand}" not executed]`;
956956
}
957957

958958
// Use importCtx.env if provided, otherwise fall back to process.env
@@ -1072,12 +1072,7 @@ async function processCommandInline(
10721072
`\n... [Output truncated: ${truncatedChars.toLocaleString()} characters removed]`;
10731073
}
10741074

1075-
// Improvement #7: Sanitize LiquidJS tags - escape {% endraw %} in output
1076-
// to prevent breaking out of the raw block
1077-
if (output) {
1078-
const safeOutput = output.replace(/\{% endraw %\}/g, "{% endraw %}{{ '{% endraw %}' }}{% raw %}");
1079-
return `{% raw %}\n${safeOutput}\n{% endraw %}`;
1080-
}
1075+
// Command output is processed after LiquidJS (Phase 3), so no template escaping needed
10811076
return output;
10821077
} catch (err) {
10831078
// Include more context in error messages
@@ -1104,7 +1099,7 @@ async function processExecutableCodeFence(
11041099
console.error(`[imports] Executing code fence (${language}): ${shebang}`);
11051100

11061101
if (importCtx?.dryRun) {
1107-
return `{% raw %}\n[Dry Run: Code fence not executed]\n{% endraw %}`;
1102+
return "[Dry Run: Code fence not executed]";
11081103
}
11091104

11101105
const ext = { ts: 'ts', js: 'js', py: 'py', sh: 'sh', bash: 'sh' }[language] ?? language;
@@ -1130,12 +1125,8 @@ async function processExecutableCodeFence(
11301125
throw new Error(`Code fence failed (Exit ${proc.exitCode}): ${errorOutput}`);
11311126
}
11321127

1133-
const output = (stdout + stderr).trim().replace(ANSI_ESCAPE_REGEX, '');
1134-
if (output) {
1135-
const safe = output.replace(/\{% endraw %\}/g, "{% endraw %}{{ '{% endraw %}' }}{% raw %}");
1136-
return `{% raw %}\n${safe}\n{% endraw %}`;
1137-
}
1138-
return output;
1128+
// Command output is processed after LiquidJS (Phase 3), so no template escaping needed
1129+
return (stdout + stderr).trim().replace(ANSI_ESCAPE_REGEX, '');
11391130
} finally {
11401131
try { await unlink(tmpFile); } catch {}
11411132
}

0 commit comments

Comments
 (0)