Skip to content

fix(pipeline): evaluate chained || in template engine#305

Open
Astro-Han wants to merge 2 commits intojackwener:mainfrom
Astro-Han:worktree-fix-chained-or-eval
Open

fix(pipeline): evaluate chained || in template engine#305
Astro-Han wants to merge 2 commits intojackwener:mainfrom
Astro-Han:worktree-fix-chained-or-eval

Conversation

@Astro-Han
Copy link
Contributor

@Astro-Han Astro-Han commented Mar 23, 2026

Description

The || handler in evalExpr (src/pipeline/template.ts) only evaluated the left side recursively. When the left side was falsy, the right side was returned as a literal string instead of being recursively evaluated.

Single || worked:

phonetic: "${{ item.phonetic || 'N/A' }}"
# item.phonetic = '' → 'N/A' ✓

Chained || broke:

phonetic: "${{ item.phonetic || item.phonetics[0].text || '' }}"
# item.phonetic = '' → literal "item.phonetics[0].text || ''" ✗

Fix: call evalExpr() on the right side so chained || evaluates at any depth.

Closes #303

Type of Change

  • 🐛 Bug fix
  • ✨ New feature
  • 🌐 New site adapter
  • 📝 Documentation
  • ♻️ Refactor
  • 🔧 CI / build / tooling

Checklist

  • I ran the checks relevant to this PR
  • I updated tests or docs if needed
  • I included output or screenshots when useful

Changes

Commit 1: chore: fix pre-existing biome lint in template.ts

Unrelated to the bug — biome hook blocks commits on any file with lint errors, so these pre-existing issues had to be fixed first:

  • isNaNNumber.isNaN (2 occurrences)
  • string concatenation → template literal
  • biome-ignore for intentional control chars in sanitize regex

Commit 2: fix(pipeline): evaluate chained || in template engine

Core fix (1 line): change the || handler's right-side from literal string return to recursive evalExpr() call.

-    const right = orMatch[2].trim();
-    return right.replace(/^['"]|['"]$/g, '');
+    return evalExpr(orMatch[2].trim(), ctx);

Tests (7 new cases):

Test Verifies
3-way chain, all falsy → default Core fix: chained fallback evaluates to the end
3-way chain, middle truthy Stops at first truthy value
3-way chain, first truthy Short-circuits correctly
0 as falsy left JS `
empty string as falsy left JS `
numeric fallback `item.a
4-way chain Deeper chains work

Screenshots / Output

$ npx vitest run src/

 Test Files  32 passed (32)
      Tests  316 passed (316)
   Duration  705ms

$ npm run typecheck
> tsc --noEmit
(clean)

- isNaN → Number.isNaN (2 occurrences)
- string concatenation → template literal
- biome-ignore for intentional control chars in sanitize regex
The || handler in evalExpr returned the right side as a literal string
instead of recursively evaluating it. This broke chained fallbacks like
`item.a || item.b || 'default'` — when item.a was falsy, the entire
`item.b || 'default'` was returned as text.

Fix: call evalExpr on the right side so chained || works at any depth.
@Astro-Han
Copy link
Contributor Author

The docs-build CI failure is a pre-existing dead link (/adapters/desktop/doubao-app) introduced by #289 — not related to this PR. It affects all open PRs on main.

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.

[Bug]: template engine chained || returns literal string instead of evaluating

1 participant