-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
feat(rules): templating actions #3305
base: master
Are you sure you want to change the base?
Conversation
✅ Deploy Preview for actualbudget ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
Bundle Stats — desktop-clientHey there, this message comes from a GitHub action that helps you and reviewers to understand how these changes affect the size of this project's bundle. As this PR is updated, I'll keep you updated on how the bundle size is impacted. Total
Changeset No files were changed View detailed bundle breakdownAdded No assets were added Removed No assets were removed Bigger No assets were bigger Smaller No assets were smaller Unchanged
|
Bundle Stats — loot-coreHey there, this message comes from a GitHub action that helps you and reviewers to understand how these changes affect the size of this project's bundle. As this PR is updated, I'll keep you updated on how the bundle size is impacted. Total
Changeset No files were changed View detailed bundle breakdownAdded No assets were added Removed No assets were removed Bigger No assets were bigger Smaller No assets were smaller Unchanged
|
Could you put in some more examples of what is possible with this? I see that you can pull in field values, can you pull in things like account balance? |
You can currently only pull in information about the transaction. This is limited to anything what is currently possible with data available to rules. So not the name of the payee or name of the category. I saw an todo The main use case for this would currently be cleaning imported transactions. Or altering existing transactions. Or changing the date of new income to the first of the month. Is this now very verbose but we could add another helper for adding duration to dates. The helpers I currently implemented are:
Values available:
This list can be extended by adding more values at |
There probably needs to be a syntax check in the rule edit window since its so easy to have bad syntax with something like this. Are these supposed to run when manually creating a transaction? My testing doesn't seem to work in that case. I think its working for file imports though. Im worried that there could be some issues with how the csv import checks for duplicates if someone has a templated rule. That will require more testing. edit: So the csv importer can't see the matching transaction if there is a big change (change the amount sign for example), but the rule gets run before the real deduplication goes. Maybe we should look at moving the rules inside of the check that the csv import does for duplication matching. |
Will add
I just tested this and it has been working but not consistently, I think the rules are not always run?
Seems smart, I wouldn't have a clue how to achieve this. Could this be fixxed in an separatem PR and making this feature expiremental? |
Making this experimental would probably be good for now. |
Can this be set? or is it just available to use? |
I'm not sure, if it's possible to change it with current
I will look how to do this! |
Out of scope of this PR I think but wouldn't this be best solved with field like |
I don't think that will fix matching if the amount gets changed |
I don't think I understand what the intented behaviour is and how to check the behaviour? |
If you import a csv and then import the same csv again you should see that all the "new" transactions get matched with the existing transaction and shown to you in the import window to decide what to do. So compare that to if you have a rule that modifies the amount using a template rule and there wont be a match even though its the same transaction and will get deduplicated after the rules run. |
This would be awesome! |
@youngcw Any clue what i'm doing wrong, or missing? |
with the CSV? Its not that the CSV import isn't working. The CSV importer shows which transactions are new and which ones match an existing transaction. If the rules change the amounts, for example, then the matching doesn't work since the transaction has changed too much. |
@youngcw How does this look, when I import an CSV I don't see anywhere that it matches even with no rules active. After importing with and without rules there are no duplicates. |
Import the same csv twice and you will see extra lines in the import window the second time. Those lines will show the matching |
@youngcw I don't see any extra line? Or any diffent in the dialog. |
Hmm. Something must have broke. Im not seeing it anymore either. |
https://deploy-preview-3179.demo.actualbudget.org/ This is the deploy for v24.8.0. It still works with the matching so you can see what it is supposed to be doing. |
Its possible that this would work fine if the table wasn't messed up prior to this. |
Ahha, thanks I really tough I was going crazy |
WalkthroughThe changes introduce an action templating feature that allows users to define dynamic action options using a new feature toggle. The Changes
Possibly related PRs
Suggested labels
Suggested reviewers
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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.
Actionable comments posted: 0
Outside diff range and nitpick comments (1)
packages/loot-core/src/server/accounts/rules.ts (1)
585-591
: Consider enhancing the template validation logic.While validating the Handlebars template by executing it with an empty object
{}
is a good start, it may not cover all possible scenarios and catch all potential template errors.Template errors that depend on specific object properties or complex logic within the template may not be detected by this validation approach. For example, if the template relies on certain properties being present in the object or performs conditional logic based on property values, executing it with an empty object may not trigger those specific error cases.
To improve the robustness of the template validation, consider the following suggestions:
- Use a more representative test object that includes common properties expected in the real usage scenario. This will help catch errors related to missing or invalid properties.
- Implement additional validation logic to check for common template issues, such as missing or invalid helpers, syntax errors, or invalid expressions.
- Consider using a template linting tool or library that specializes in validating Handlebars templates. These tools can provide more comprehensive checks and catch potential issues early in the development process.
By enhancing the template validation logic, you can improve the reliability and error handling of the
Action
class when using Handlebars templates.
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files ignored due to path filters (2)
packages/loot-core/src/server/accounts/__snapshots__/transaction-rules.test.ts.snap
is excluded by!**/*.snap
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
Files selected for processing (10)
- packages/desktop-client/src/components/modals/EditRuleModal.jsx (4 hunks)
- packages/desktop-client/src/components/rules/ActionExpression.tsx (1 hunks)
- packages/desktop-client/src/components/settings/Experimental.tsx (1 hunks)
- packages/desktop-client/src/hooks/useFeatureFlag.ts (1 hunks)
- packages/loot-core/package.json (1 hunks)
- packages/loot-core/src/server/accounts/rules.ts (6 hunks)
- packages/loot-core/src/shared/rules.ts (1 hunks)
- packages/loot-core/src/types/models/rule.d.ts (1 hunks)
- packages/loot-core/src/types/prefs.d.ts (1 hunks)
- upcoming-release-notes/3305.md (1 hunks)
Additional comments not posted (17)
upcoming-release-notes/3305.md (1)
1-6
: LGTM!The release notes provide a clear and concise description of the new rule action templating feature using Handlebars syntax. The categorization and authorship details are accurate.
The notes effectively communicate the core functionality of the feature, which allows users to manipulate transaction data based on predefined templates. The limitations and potential for future enhancements are also appropriately mentioned.
Overall, the release notes are well-written and informative.
packages/desktop-client/src/hooks/useFeatureFlag.ts (1)
11-11
: LGTM!The addition of the
actionTemplating
feature flag to theDEFAULT_FEATURE_FLAG_STATE
object is a valid way to introduce a new toggleable feature. Setting the default value tofalse
ensures that the feature is disabled by default, providing a safe and controlled rollout mechanism.packages/loot-core/src/types/prefs.d.ts (1)
8-9
: LGTM!The addition of the
'actionTemplating'
feature flag to theFeatureFlag
type is a straightforward change that enables the use of this flag in the codebase. It does not introduce any apparent issues or affect the existing feature flags.packages/loot-core/package.json (1)
31-31
: Looks good!The addition of the
handlebars
dependency at version^4.7.8
is a reasonable choice for introducing templating functionality to the project. Handlebars is a well-established and widely-used templating engine that can improve code maintainability and reusability by separating the presentation logic from the application logic.The version constraint follows semantic versioning and allows for minor and patch updates, ensuring compatibility with future releases.
packages/loot-core/src/types/models/rule.d.ts (1)
139-139
: LGTM!The addition of the optional
template
property to theoptions
object within theSetRuleActionEntity
interface is a good enhancement. It expands the capabilities of the interface by allowing the inclusion of a template string, which could be used for various purposes such as formatting or defining a structure for thevalue
being set.This change maintains backward compatibility as the property is marked as optional, ensuring existing functionality is not affected.
packages/desktop-client/src/components/rules/ActionExpression.tsx (1)
74-81
: LGTM!The conditional rendering logic for handling the
options.template
case is implemented correctly. It enhances the component's flexibility by allowing it to display a template value when available while maintaining backward compatibility with the existingValue
component rendering.The use of the optional chaining operator
?.
ensures safe access to thetemplate
property, and the rendering of theText
elements follows the existing style conventions.packages/desktop-client/src/components/settings/Experimental.tsx (1)
119-121
: Please provide more information about the "actionTemplating" feature.The PR objectives and AI-generated summary do not mention the "actionTemplating" feature flag. It would be helpful to understand:
- What is the purpose of the "actionTemplating" feature?
- How does it affect the application's behavior?
- What are the potential risks or benefits associated with this feature?
Providing this information will help reviewers better understand the context and impact of this change.
packages/loot-core/src/shared/rules.ts (1)
195-196
: LGTM!The addition of the 'invalid-template' case in the
getFieldError
function enhances the error handling capabilities by providing a specific error message for invalid handlebars templates. This change improves the user experience and the overall robustness of the error management system.packages/loot-core/src/server/accounts/rules.ts (4)
29-78
: LGTM!The code segment registers various Handlebars helpers for mathematical operations, date formatting, and regex matching. The use of an IIFE is a good practice to avoid polluting the global scope.
The
mathHelper
higher-order function is a nice abstraction for defining mathematical operation helpers. It reduces code duplication and makes it easy to add new mathematical helpers in the future.The
helpers
object is well-structured and contains a good set of helper functions for common use cases.Overall, the code is clean, modular, and follows best practices.
Line range hint
571-592
: LGTM!The addition of the
handlebarsTemplate
property to theAction
class and the corresponding changes in the constructor to initialize and validate the template are well-implemented.The use of
Handlebars.compile
to compile the template and store it as aTemplateDelegate
is a good approach. It allows for efficient execution of the template later on.The validation of the template by attempting to execute it with an empty object is a nice touch. It ensures that the template is valid and will not throw errors during runtime.
The use of
RuleError
to throw a specific error message when the template is invalid is also a good practice. It provides clear feedback to the user about the issue.Overall, the code changes are solid and enhance the functionality of the
Action
class.
617-637
: LGTM!The modifications to the
exec
method of theAction
class to support executing Handlebars templates are well-implemented and provide a powerful feature.The code correctly checks for the existence of the
handlebarsTemplate
property and executes the template with theobject
spread into the template context. This allows for dynamic value computation based on the object's properties.The addition of the
today
property to the template context is a nice touch, providing access to the current day within the template.The conversion of the computed value to the appropriate type based on the action's type is handled correctly. The code uses
parseFloat
for numbers,parseDate
for dates, and a comparison with the string "true" for booleans.Falling back to assigning the original value directly if no template is provided ensures backward compatibility and flexibility.
Overall, the code changes enhance the functionality of the
Action
class and provide a powerful templating mechanism for dynamic value computation.
623-634
: LGTM!The conversion of the computed value from the Handlebars template to the appropriate type based on the action's type is handled correctly in the
exec
method of theAction
class.The code uses appropriate methods and comparisons for each type:
- For numbers,
parseFloat
is used to parse the string value into a floating-point number. This ensures that the resulting value is a valid number.- For dates, the
parseDate
function is used to parse the string value into a date object. This function likely handles the parsing logic specific to the date format used in the application.- For booleans, the code compares the string value with the string "true" to determine its boolean value. This comparison is sufficient to convert the string to a boolean value.
The type-specific conversion logic ensures that the computed value is properly converted to the expected type before being assigned to the specified field in the
object
.Overall, the code changes are accurate and handle the type conversion correctly based on the action's type.
packages/desktop-client/src/components/modals/EditRuleModal.jsx (5)
39-39
: LGTM!The
useFeatureFlag
hook import looks good.
42-42
: LGTM!The new icon component imports look good.
368-371
: LGTM!The
templated
andisTemplatingEnabled
variables are correctly initialized based on theoptions.template
property and theactionTemplating
feature flag.
393-423
: LGTM!The conditional rendering logic for the
GenericInput
component'stype
prop and the templating button is implemented correctly. The exclusion of certain fields from having templating options is also handled properly.
849-863
: LGTM!The logic for updating the
options.template
property based on thetemplate
field is implemented correctly. Clearing thevalue
when disabling templating for non-string types and updating thevalue
to match theoptions.template
value are good practices to maintain consistency.
@youngcw it seems that the templating rules work with the CSV import. Could you confirm? |
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.
Actionable comments posted: 0
Outside diff range and nitpick comments (1)
packages/desktop-client/src/components/modals/EditRuleModal.jsx (1)
403-403
: Fix typo in commentThere's a minor typo in the comment. "Due to that" should be "Due to the fact that" or simply "Because".
Consider updating the comment to:
- {/*Due to that these fields have id's as value it is not helpful to have templating here*/} + {/* Because these fields have IDs as values, it is not helpful to have templating here */}
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files selected for processing (3)
- packages/desktop-client/src/components/modals/EditRuleModal.jsx (4 hunks)
- packages/desktop-client/src/components/settings/Experimental.tsx (1 hunks)
- packages/loot-core/src/types/prefs.d.ts (1 hunks)
Files skipped from review as they are similar to previous changes (2)
- packages/desktop-client/src/components/settings/Experimental.tsx
- packages/loot-core/src/types/prefs.d.ts
Additional comments not posted (4)
packages/desktop-client/src/components/modals/EditRuleModal.jsx (4)
39-39
: LGTM: New imports for templating featureThe new imports for
useFeatureFlag
and SVG icons are appropriate for the templating feature being implemented. These additions enhance the functionality and user interface of the component.Also applies to: 42-42
Line range hint
371-426
: LGTM: Templating feature implementationThe implementation of the templating feature in the ActionEditor component looks good. It correctly handles the toggling between templated and non-templated inputs, and provides a clear UI for users to switch between modes. The use of feature flags and conditional rendering ensures backwards compatibility.
852-876
: LGTM: Templating handling in onChangeActionThe updates to the
onChangeAction
function properly handle the templating feature. The code correctly manages the template state when actions are modified, including resetting the template when the field or operation is changed. This implementation ensures consistency and prevents potential issues with mismatched templates.
Line range hint
1-1337
: Summary: Solid implementation of templating featureThe changes in this file successfully implement a templating feature for action rules. Key points:
- New imports for feature flags and icons support the implementation.
- The ActionEditor component now handles templated inputs with a toggle UI.
- The EditRuleModal component's logic has been updated to manage templated actions correctly.
These changes enhance the flexibility of the rule system while maintaining backwards compatibility. The code is well-structured and follows React best practices.
Consider addressing the minor typo in the comment as noted earlier. Otherwise, this implementation is ready for production.
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.
Actionable comments posted: 10
🧹 Outside diff range and nitpick comments (5)
packages/loot-core/src/types/models/rule.d.ts (1)
141-141
: LGTM! Consider adding documentation for the newtemplate
property.The addition of the optional
template
property to theSetRuleActionEntity
interface aligns well with the PR objectives of introducing templating actions within rules. This change enhances the flexibility of rule actions without breaking existing functionality.Consider adding a brief comment to document the purpose and expected format of the
template
property. This will help other developers understand how to use this new feature correctly.Example:
options?: { /** * A string template for dynamic action options. * @example "Transaction amount: {{amount}}" */ template?: string; splitIndex?: number; };packages/loot-core/src/shared/rules.ts (1)
222-223
: LGTM! Consider a minor improvement for consistency.The addition of the 'invalid-template' case is a good extension to the error handling capabilities, aligning well with the new templating feature. The error message is clear and descriptive.
For consistency with other error messages in this function, consider capitalizing the first letter of each word in the error message:
- return 'Invalid handlebars template'; + return 'Invalid Handlebars Template';packages/desktop-client/src/components/modals/EditRuleModal.jsx (3)
374-376
: Clarify the comment regarding templating feature flag behavior.The comment on line 374 could be clearer:
// Even if the feature flag is disabled, we still want to be able to turn off templating
Consider rephrasing to:
// Even if the feature flag is disabled, we still want to allow disabling templating if previously enabled
This clarifies that templating can be toggled off even when the feature flag is disabled.
404-404
: Improve comment clarity and grammar.The comment on line 404 can be rephrased for better readability:
// Since these fields have IDs as values, it is not helpful to enable templating here
This improves clarity and ensures the intent is clearly communicated.
405-427
: UseArray.includes()
for better readability.In the condition on line 406, consider using
includes
for improved readability:{isTemplatingEnabled && !['payee', 'category', 'account'].includes(field) && ( <Button> {/* Button content */} </Button> )}Using
includes
makes the code more readable and aligns with modern JavaScript practices.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (1)
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
📒 Files selected for processing (5)
- packages/desktop-client/src/components/modals/EditRuleModal.jsx (4 hunks)
- packages/loot-core/src/server/accounts/rules.ts (6 hunks)
- packages/loot-core/src/shared/rules.ts (1 hunks)
- packages/loot-core/src/types/models/rule.d.ts (1 hunks)
- packages/loot-core/src/types/prefs.d.ts (1 hunks)
🔇 Additional comments (8)
packages/loot-core/src/types/prefs.d.ts (1)
5-6
: LGTM! Verify removal of 'spendingReport' across the codebase.The changes to the
FeatureFlag
type align with the PR objectives by adding 'actionTemplating'. However, the removal of 'spendingReport' requires attention:
- Ensure that 'spendingReport' is no longer used anywhere in the codebase.
- Update any relevant documentation that might reference the removed feature flag.
To verify the removal of 'spendingReport', run the following script:
If any results are found, please review and update the corresponding code to remove references to the 'spendingReport' feature flag.
packages/desktop-client/src/components/modals/EditRuleModal.jsx (6)
40-40
: Imports are appropriate and necessary.The added imports for
useFeatureFlag
and the new icons (SvgAlignLeft
,SvgCode
,SvgInformationOutline
) are correctly included and used in the code.Also applies to: 43-43
372-373
: Variabletemplated
is correctly initialized.The
templated
variable accurately reflects whether theoptions.template
property is defined, which is essential for controlling the templating behavior.
397-397
: Adjust input type and value based on templating.The
GenericInput
component correctly adjusts thetype
andvalue
properties whentemplated
is true. This ensures that the input handles templated strings appropriately.Also applies to: 399-399
854-863
: Ensurea.value
is properly handled when toggling templating.When the 'template' field changes, setting
a.value
tonull
ifa.type !== 'string'
may have unintended effects ifa.value
is required elsewhere. Verify thata.value
beingnull
in these cases does not lead to errors or unexpected behavior.
866-868
: Synchronizeoptions.template
withvalue
when necessary.When
a.options.template
is defined, updating it with the newvalue
ensures consistency between the template and the action value.
878-878
: Resetoptions.template
when field or operation changes.The code appropriately resets
a.options.template
toundefined
when the field or operation changes. This prevents stale templates from persisting and ensures that the action reflects the current field and operation.packages/loot-core/src/server/accounts/rules.ts (1)
3-3
: Handlebars module imported correctly.The import statement for the Handlebars library is appropriate and necessary for adding templating functionality.
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.
Actionable comments posted: 5
🧹 Outside diff range and nitpick comments (2)
packages/loot-core/src/server/accounts/rules.ts (1)
564-572
: Improve error handling in Handlebars template compilation.While the addition of Handlebars template compilation is a good feature, the error handling could be enhanced. Instead of using
console.debug
and a generic assertion, consider throwing a more informative error that includes details from the caught exception.Consider applying this change:
if (options?.template) { this.handlebarsTemplate = Handlebars.compile(options.template); try { this.handlebarsTemplate({}); } catch (e) { - console.debug(e); - assert(false, 'invalid-template', `Invalid Handlebars template`); + throw new Error(`Invalid Handlebars template: ${e.message}`); } }packages/loot-core/src/server/accounts/rules.test.ts (1)
323-323
: Fix the typo in the template stringIn line 323, 'payed' should be 'paid' in the template string.
Apply this diff to correct the typo:
- template: 'Hey {{notes}}! You just payed {{amount}}', + template: 'Hey {{notes}}! You just paid {{amount}}',
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (2)
- packages/loot-core/src/server/accounts/rules.test.ts (1 hunks)
- packages/loot-core/src/server/accounts/rules.ts (6 hunks)
🔇 Additional comments (4)
packages/loot-core/src/server/accounts/rules.ts (4)
3-3
: LGTM: Handlebars import added correctly.The Handlebars library is imported properly, allowing for template compilation and usage throughout the file.
34-85
: LGTM: Comprehensive Handlebars helpers implemented.The
registerHandlebarsHelpers
function provides a wide range of useful helpers for mathematical operations, string manipulation, and date formatting. The implementation is well-structured and should enhance the templating capabilities significantly.
46-61
:⚠️ Potential issueSecurity concern: Potential ReDoS vulnerability in regex helper.
The
regex
helper constructs regular expressions from user-provided input, which could lead to Regular Expression Denial of Service (ReDoS) attacks if not properly validated. Consider implementing safeguards to limit the complexity of user-provided regex patterns.To verify the potential impact, let's search for usages of this helper:
#!/bin/bash # Search for usage of the 'regex' helper in Handlebars templates rg --type typescript 'regex\s*=' -A 3 -B 3
Line range hint
1-1441
: Overall: Significant enhancement to rules system with Handlebars templating.The introduction of Handlebars templating to the rules system greatly increases its flexibility and power. Users can now create more dynamic rules based on transaction data. However, with this increased power comes increased complexity and potential for errors.
Recommendations:
- Implement comprehensive unit tests for the new templating functionality, especially edge cases and error scenarios.
- Consider adding a "dry run" feature for rules, allowing users to test their templates safely before applying them to real data.
- Update user documentation to explain the new templating features and provide examples of safe and effective usage.
To ensure proper test coverage, let's check for existing tests related to the
Action
class:✅ Verification successful
Action Required: Verify Coverage for the
Action
Class TestsThe previous attempt to locate test files for the
Action
class encountered issues. To ensure comprehensive test coverage, please execute the following shell scripts:[/run_scripts]
Test Coverage for the
Action
ClassThe search results indicate that the
Action
class is adequately covered by tests inaccounts/rules.test.ts
. This suggests that the new Handlebars templating functionality has corresponding test cases ensuring its correct behavior.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for test files that might cover the Action class rg --type typescript 'describe.*Action' -g '*test*'Length of output: 173
Script:
#!/bin/bash # Search for test files that cover the Action class by looking for describe blocks containing 'Action' rg --glob '*.test.ts' --glob '*.spec.ts' 'describe\s*\(\s*[\'"]Action[\'"]\s*,'Length of output: 93
Script:
#!/bin/bash # Alternatively, search for any references to the Action class within test files rg --glob '*.test.ts' --glob '*.spec.ts' 'Action' -A 5 -B 5Length of output: 9199
if (this.handlebarsTemplate) { | ||
object[this.field] = this.handlebarsTemplate({ | ||
...object, | ||
today: currentDay(), | ||
}); | ||
|
||
// Handlebars always returns a string, so we need to convert | ||
switch (this.type) { | ||
case 'number': | ||
object[this.field] = parseFloat(object[this.field]); | ||
break; | ||
case 'date': | ||
object[this.field] = parseDate(object[this.field]); | ||
break; | ||
case 'boolean': | ||
object[this.field] = object[this.field] === 'true'; | ||
break; | ||
} | ||
} else { | ||
object[this.field] = this.value; | ||
} |
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.
Add error handling for type conversions after template execution.
The current implementation doesn't handle potential errors in type conversion, such as NaN for numbers or invalid dates. Consider adding checks to ensure the converted values are valid.
Apply this diff to include conversion checks:
if (this.handlebarsTemplate) {
object[this.field] = this.handlebarsTemplate({
...object,
today: currentDay(),
});
// Handlebars always returns a string, so we need to convert
switch (this.type) {
case 'number':
- object[this.field] = parseFloat(object[this.field]);
+ const num = parseFloat(object[this.field]);
+ if (isNaN(num)) {
+ throw new Error(`Invalid number result from template for field ${this.field}`);
+ }
+ object[this.field] = num;
break;
case 'date':
- object[this.field] = parseDate(object[this.field]);
+ const date = parseDate(object[this.field]);
+ if (isNaN(date.getTime())) {
+ throw new Error(`Invalid date result from template for field ${this.field}`);
+ }
+ object[this.field] = date;
break;
case 'boolean':
object[this.field] = object[this.field] === 'true';
break;
}
} else {
object[this.field] = this.value;
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
if (this.handlebarsTemplate) { | |
object[this.field] = this.handlebarsTemplate({ | |
...object, | |
today: currentDay(), | |
}); | |
// Handlebars always returns a string, so we need to convert | |
switch (this.type) { | |
case 'number': | |
object[this.field] = parseFloat(object[this.field]); | |
break; | |
case 'date': | |
object[this.field] = parseDate(object[this.field]); | |
break; | |
case 'boolean': | |
object[this.field] = object[this.field] === 'true'; | |
break; | |
} | |
} else { | |
object[this.field] = this.value; | |
} | |
if (this.handlebarsTemplate) { | |
object[this.field] = this.handlebarsTemplate({ | |
...object, | |
today: currentDay(), | |
}); | |
// Handlebars always returns a string, so we need to convert | |
switch (this.type) { | |
case 'number': | |
const num = parseFloat(object[this.field]); | |
if (isNaN(num)) { | |
throw new Error(`Invalid number result from template for field ${this.field}`); | |
} | |
object[this.field] = num; | |
break; | |
case 'date': | |
const date = parseDate(object[this.field]); | |
if (isNaN(date.getTime())) { | |
throw new Error(`Invalid date result from template for field ${this.field}`); | |
} | |
object[this.field] = date; | |
break; | |
case 'boolean': | |
object[this.field] = object[this.field] === 'true'; | |
break; | |
} | |
} else { | |
object[this.field] = this.value; | |
} |
describe('math helpers', () => { | ||
function testHelper( | ||
template: string, | ||
expected: unknown, | ||
field = 'amount', | ||
) { | ||
test(template, () => { | ||
const action = new Action('set', field, '', { template }); | ||
const item = { [field]: 10 }; | ||
action.exec(item); | ||
expect(item[field]).toBe(expected); | ||
}); | ||
} | ||
|
||
testHelper('{{add amount 5}}', 15); | ||
testHelper('{{add amount 5 10}}', 25); | ||
testHelper('{{sub amount 5}}', 5); | ||
testHelper('{{sub amount 5 10}}', -5); | ||
testHelper('{{mul amount 5}}', 50); | ||
testHelper('{{mul amount 5 10}}', 500); | ||
testHelper('{{div amount 5}}', 2); | ||
testHelper('{{div amount 5 10}}', 0.2); | ||
testHelper('{{mod amount 3}}', 1); | ||
testHelper('{{mod amount 6 5}}', 4); | ||
testHelper('{{floor (div amount 3)}}', 3); | ||
testHelper('{{ceil (div amount 3)}}', 4); | ||
testHelper('{{round (div amount 3)}}', 3); | ||
testHelper('{{round (div amount 4)}}', 3); | ||
testHelper('{{abs -5}}', 5); | ||
testHelper('{{abs 5}}', 5); | ||
testHelper('{{min amount 5 500}}', 5); | ||
testHelper('{{max amount 5 500}}', 500); | ||
testHelper('{{fixed (div 10 4) 2}}', '2.50', 'notes'); | ||
}); |
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.
🛠️ Refactor suggestion
Consider adding tests for edge cases in math helpers
The current tests for math helpers cover standard arithmetic operations. To ensure robustness, consider adding tests for edge cases such as:
- Division by zero.
- Operations with negative numbers.
- Non-numeric input handling.
- Large number computations.
describe('date helpers', () => { | ||
function testHelper(template: string, expected: unknown) { | ||
test(template, () => { | ||
const action = new Action('set', 'notes', '', { template }); | ||
const item = { notes: '' }; | ||
action.exec(item); | ||
expect(item.notes).toBe(expected); | ||
}); | ||
} | ||
|
||
testHelper('{{day "2002-07-25"}}', '25'); | ||
testHelper('{{month "2002-07-25"}}', '7'); | ||
testHelper('{{year "2002-07-25"}}', '2002'); | ||
testHelper('{{format "2002-07-25" "MM yyyy d"}}', '07 2002 25'); | ||
}); |
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.
🛠️ Refactor suggestion
Expand tests for date helpers to cover invalid inputs
The date helper tests handle valid date strings effectively. To enhance reliability, consider adding tests for:
- Invalid date formats (e.g.,
'2020-13-01'
,'invalid-date'
). - Null or undefined inputs.
- Edge cases like leap years and end-of-month dates.
function testHelper(template: string, expected: unknown) { | ||
test(template, () => { | ||
const action = new Action('set', 'notes', '', { template }); | ||
const item = { notes: 'Sarah Condition' }; | ||
action.exec(item); | ||
expect(item.notes).toBe(expected); | ||
}); | ||
} |
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.
🛠️ Refactor suggestion
Refactor test helper functions to reduce code duplication
The testHelper
functions in the 'regex helper' (lines 331-338), 'math helpers' (lines 351-362), and 'date helpers' (lines 386-393) describe blocks share similar structures. Refactoring these into a single reusable function or abstracting common logic can reduce code duplication and improve maintainability.
Also applies to: 351-362, 386-393
} | ||
|
||
testHelper('{{regex notes "/[aeuio]/g" "a"}}', 'Sarah Candataan'); | ||
testHelper('{{regex notes "/[aeuio]/" ""}}', 'Srah Condition'); |
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.
Correct the expected result in the regex helper test
In line 341, the test aims to remove all vowels from 'Sarah Condition' by replacing [aeuio]
with an empty string. The expected result is currently 'Srah Condition'
, but removing vowels should result in 'Srh Cndtn'
.
Apply this diff to correct the expected result:
- testHelper('{{regex notes "/[aeuio]/" ""}}', 'Srah Condition');
+ testHelper('{{regex notes "/[aeuio]/" ""}}', 'Srh Cndtn');
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
testHelper('{{regex notes "/[aeuio]/" ""}}', 'Srah Condition'); | |
testHelper('{{regex notes "/[aeuio]/" ""}}', 'Srh Cndtn'); |
Relates to #500 and #3378
chrome_jgqSYZmJON.mp4