-
Notifications
You must be signed in to change notification settings - Fork 252
feat: Add conditional logic and variable assignment to template engine #584
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Add {% if %}...{% else %}...{% endif %} conditional logic support
- Add {% set variable = expression %} variable assignment functionality
- Support comparison operators (==, !=, >, <, >=, <=) in conditions
- Enable schema variables and nested property access in templates
- Maintain backward compatibility with existing template syntax
- Extend template compiler to process assignments before logic structures
This enhancement allows users to create more dynamic and flexible templates
with conditional content and custom variable definitions.
…l ops, and conditional sets
- Add expression evaluator supporting (), == != > < >= <=, not/and/or and !/&&/||, dotted/bracket access, and schema: identifiers.
- Rework IF handling to support elif/elseif chains and deep nesting reliably.
- Allow {% set %} to accept full expressions and execute only in selected branches.
- Clean up set tag whitespace (inline vs full-line) and improve render order.
fix(variables): handle non-string values and harden escapeHtml
- Prevents "unsafe.replace is not a function" in popup when opening the variables panel.
- Coerce variable values to strings and escape safely during rendering.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary
- Implements a production-ready logic layer for templates with a dedicated expression evaluator and a nesting-aware IF processor.
- New evaluator: parentheses, comparisons, logical ops (word and symbol), dotted/bracket paths, schema: identifiers.
- IF tags: elif/elseif support and correct handling of nested blocks.
- SET tags: full expression support; assignments execute only in chosen branches.
- Whitespace: remove entire set lines when isolated, keep surrounding text for inline tags.
- Compiler: phased processing to avoid side effects from non-selected branches.
Why
- Unlock complex, readable template logic without brittle regex parsing.
- Ensure correctness with nesting, precedence, and truthiness consistent across the codebase.
Testing
Copy and paste Test_NoteContent.txt into your Template Note Content and it will create a note that outputs tests.
File Changes
- src/utils/expression-evaluator.ts (new)
- Added a safe, self-contained expression parser/evaluator for template logic.
- Supports: parentheses, comparison operators (==, !=, >, <, >=, <=), logical operators (not/and/or and !/&&/||), JS-like truthiness, dotted/bracket variable access, and schema: identifiers.
- Exposes evaluateExpression (general values) and evaluateBoolean (conditions), plus isTruthy.
- src/utils/tags/if.ts (updated)
- Replaced ad-hoc condition logic with the shared evaluator.
- Added full support for elif and elseif chains.
- Delegates to a nesting-aware IF processor in the compiler and cleans up branch selection and rendering.
- src/utils/tags/set.ts (updated)
- Set assignment now uses evaluateExpression for robust parsing (strings, numbers, booleans, variable access, parentheses, logical ops).
- Preserves existing behavior for filter pipelines by delegating expressions containing "|" to the filter engine.
- src/utils/template-compiler.ts (updated)
- Introduced a nesting-aware IF parser (processIfBlocks) to correctly handle nested if/elif/elseif/else without regex pitfalls.
- Processes text in phases to ensure correct side effects:
- Renders content before/after IF blocks with current variables.
- Resolves the selected IF branch (handling nested logic), then renders.
- Ensures sets inside branches only execute for the chosen branch.
- Improved removal of {% set %} tags:
- Strips the entire line when a set is the only content.
- Removes only the tag when inline with surrounding text.
- Minor: adjusted processing order to avoid prematurely executing assignments in non-selected branches.
- src/utils/string-utils.ts (updated)
- Fix variables panel crash when values are non-strings (e.g., arrays/objects).
- formatVariables now coerces values safely (JSON.stringify fallback) before rendering.
- escapeHtml now accepts any input and stringifies before escaping to prevent unsafe.replace errors.
Backwards compatibility
- Filters inside IF conditions are not evaluated directly; use set-then-compare (documented and enforced consistently).
- Existing templates using basic IF/ELSE and SET semantics continue to work; behavior is stricter and more predictable with nesting.
Docs
- Consider a brief doc update to Templates/Variables to call out operator support and the “set then compare” pattern for filters.
…rendering logic - Clean up trailing whitespace in rendered output to ensure consistent formatting. - Adjust logic for processing IF blocks to handle leading and trailing blank lines more effectively. - Refine variable rendering to prevent unwanted spacing in tag-only lines.
|
Thanks! I'll take a look. Did you consider prompt variables? I'm wondering how you evaluate those because the results from Interpreter are not immediately available when the extension is loaded. |
It is currently not possible to set a variable using {% set %} equal to an interpreter/LLM response. This doesn't work because:
It could be possible with these changes:
But I'm not that deep yet haha I am exploring prompt variables and will soon have another PR that modifies processPrompt, collectPromptVariables, and replacePromptVariables functions so syntax is supported for something like: {% set myPrompt = "Calculate 9 divided by 3" %} Another low risk, medium effort, high value change! |
…improvements - Fix expression evaluator to properly handle quoted strings vs logical expressions - Add comprehensive error detection for missing variables in prompt references - Implement retry button with proper styling and error state management - Improve template compiler variable processing consistency - Enhance set tag filter detection to avoid conflicts with logical operators - Fix prompt variable collection with better regex and variable resolution - Add replace filter support for parentheses-wrapped replacement patterns - Clean up LLM response processing to remove code block artifacts
…n- Add isLocalOnly toggle (UI + type)\n- Load/save from sync and local with size-based fallback\n- Always update template_list and template_local_list; avoid stale entries\n- Remove stale copies when switching storage; delete updates both lists\n- Export/import supports local templates; import writes them to local storage\n- Fix replace filter callback and default replacement\n- Simplify popup to use centralized loadTemplates()
Major Functional Enhancements & Bug Fixes!Expression Evaluator Improvements:
Template Interpreter Error Handling:
Template Compiler Consistency:
Set Tag Filter Logic:
Prompt Variable Processing:
Bug FixesReplace Filter Enhancements:
LLM Response Cleanup:
UI State Management:
UI/UX ImprovementsRetry Button Implementation:
Error State Styling:
The core focus was on making the template interpreter more robust, providing better error feedback, and |
feat(templates): add local-only storage and sync/local consistencyHighlightsTestingThis testfile now includes all template logic tests plus comprehensive prompt variable testing. Only a usable template with local storage feature due to size >8 kB. Sync storage fails with a template of this size! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The local storage option should be split into a separate PR. It's a significantly different feature set that isn't necessary for template logic to be useful. It's okay for tests to be in different templates.
|
A few questions from exploring this PR:
Issue I noticed:
|
This enhancement allows users to create more dynamic and flexible templates with conditional content, custom variable definitions, and precise literal control while maintaining full backward compatibility (purely additive changes), adding requests from #585