Skip to content

Commit

Permalink
enhance: add more action rule templating helpers (#4243)
Browse files Browse the repository at this point in the history
* enhance: add more action rule templating helpers

* chore: note
  • Loading branch information
UnderKoen authored Jan 28, 2025
1 parent 663f830 commit d1c3b9b
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 7 deletions.
39 changes: 39 additions & 0 deletions packages/loot-core/src/server/accounts/rules.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,20 @@ describe('Action', () => {
testHelper('{{regex notes "/Klaas/" "Jantje"}}', 'Sarah Condition');
// no regex format (/.../flags)
testHelper('{{regex notes "Sarah" "Jantje"}}', 'Jantje Condition');

// should not use regex when not in regex format
testHelper('{{replace notes "[a-z]" "a"}}', 'Sarah Condition');
// should use regex when in regex format
testHelper('{{replace notes "/[a-z]/g" "a"}}', 'Saaaa Caaaaaaaa');
// should replace once with non regex
testHelper('{{replace notes "a" "b"}}', 'Sbrah Condition');

// should not use regex when not in regex format
testHelper('{{replaceAll notes "[a-z]" "a"}}', 'Sarah Condition');
// should use regex when in regex format
testHelper('{{replaceAll notes "/[a-z]/g" "a"}}', 'Saaaa Caaaaaaaa');
// should replace all with non regex
testHelper('{{replaceAll notes "a" "b"}}', 'Sbrbh Condition');
});

describe('math helpers', () => {
Expand Down Expand Up @@ -413,6 +427,31 @@ describe('Action', () => {
testHelper('{{month undefined}}', '');
testHelper('{{year undefined}}', '');
testHelper('{{format undefined undefined}}', '');
testHelper('{{addDays "2002-07-25" 5}}', '2002-07-30');
testHelper('{{subDays "2002-07-25" 5}}', '2002-07-20');
testHelper('{{addMonths "2002-07-25" 5}}', '2002-12-25');
testHelper('{{subMonths "2002-07-25" 5}}', '2002-02-25');
testHelper('{{addYears "2002-07-25" 5}}', '2007-07-25');
testHelper('{{subYears "2002-07-25" 5}}', '1997-07-25');
testHelper('{{addWeeks "2002-07-25" 1}}', '2002-08-01');
testHelper('{{subWeeks "2002-07-25" 1}}', '2002-07-18');
testHelper('{{setDay "2002-07-25" 1}}', '2002-07-01');
testHelper('{{setDay "2002-07-25" 32}}', '2002-08-01');
testHelper('{{setDay "2002-07-25" 0}}', '2002-06-30');
});

describe('other 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('{{concat "Sarah" "Trops"}}', 'SarahTrops');
testHelper('{{concat "Sarah" "Trops" 12 "Wow"}}', 'SarahTrops12Wow');
});

test('{{debug}} should log the item', () => {
Expand Down
82 changes: 75 additions & 7 deletions packages/loot-core/src/server/accounts/rules.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
// @ts-strict-ignore
import * as dateFns from 'date-fns';
import {
addMonths,
addWeeks,
addYears,
subMonths,
subWeeks,
subYears,
} from 'date-fns';
import * as Handlebars from 'handlebars';

import {
Expand Down Expand Up @@ -43,8 +51,12 @@ function registerHandlebarsHelpers() {
};
}

const helpers = {
regex: (value: unknown, regex: unknown, replace: unknown) => {
function regexHelper(
mapRegex: (regex: string, flags: string) => string | RegExp,
mapNonRegex: (value: string) => string | RegExp,
apply: (value: string, regex: string | RegExp, replace: string) => string,
) {
return (value: unknown, regex: unknown, replace: unknown) => {
if (value == null) {
return null;
}
Expand All @@ -53,17 +65,35 @@ function registerHandlebarsHelpers() {
return '';
}

let regexp: RegExp;
let regexp: string | RegExp;
const match = regexTest.exec(regex);
// Regex is in format /regex/flags
if (match) {
regexp = new RegExp(match[1], match[2]);
regexp = mapRegex(match[1], match[2]);
} else {
regexp = new RegExp(regex);
regexp = mapNonRegex(regex);
}

return String(value).replace(regexp, replace);
},
return apply(String(value), regexp, replace);
};
}

const helpers = {
regex: regexHelper(
(regex, flags) => new RegExp(regex, flags),
value => new RegExp(value),
(value, regex, replace) => value.replace(regex, replace),
),
replace: regexHelper(
(regex, flags) => new RegExp(regex, flags),
value => value,
(value, regex, replace) => value.replace(regex, replace),
),
replaceAll: regexHelper(
(regex, flags) => new RegExp(regex, flags),
value => value,
(value, regex, replace) => value.replaceAll(regex, replace),
),
add: mathHelper((a, b) => a + b),
sub: mathHelper((a, b) => a - b),
div: mathHelper((a, b) => a / b),
Expand All @@ -80,9 +110,47 @@ function registerHandlebarsHelpers() {
month: (date?: string) => date && format(date, 'M'),
year: (date?: string) => date && format(date, 'yyyy'),
format: (date?: string, f?: string) => date && f && format(date, f),
addDays: (date?: string, days?: number) => {
if (!days || !days) return date;
return format(addDays(date, days), 'yyyy-MM-dd');
},
subDays: (date?: string, days?: number) => {
if (!days || !days) return date;
return format(subDays(date, days), 'yyyy-MM-dd');
},
addMonths: (date?: string, months?: number) => {
if (!months || !months) return date;
return format(addMonths(parseDate(date), months), 'yyyy-MM-dd');
},
subMonths: (date?: string, months?: number) => {
if (!months || !months) return date;
return format(subMonths(parseDate(date), months), 'yyyy-MM-dd');
},
addWeeks: (date?: string, weeks?: number) => {
if (!weeks || !weeks) return date;
return format(addWeeks(parseDate(date), weeks), 'yyyy-MM-dd');
},
subWeeks: (date?: string, weeks?: number) => {
if (!weeks || !weeks) return date;
return format(subWeeks(parseDate(date), weeks), 'yyyy-MM-dd');
},
addYears: (date?: string, years?: number) => {
if (!years || !years) return date;
return format(addYears(parseDate(date), years), 'yyyy-MM-dd');
},
subYears: (date?: string, years?: number) => {
if (!years || !years) return date;
return format(subYears(parseDate(date), years), 'yyyy-MM-dd');
},
setDay: (date?: string, day?: number) => {
if (!date) return date;
const actualDay = Number(format(date, 'd'));
return format(addDays(date, day - actualDay), 'yyyy-MM-dd');
},
debug: (value: unknown) => {
console.log(value);
},
concat: (...args: unknown[]) => args.slice(0, -1).join(''),
};

for (const [name, fn] of Object.entries(helpers)) {
Expand Down
6 changes: 6 additions & 0 deletions upcoming-release-notes/4243.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
category: Enhancements
authors: [UnderKoen]
---

Add new helpers to rule action templating

0 comments on commit d1c3b9b

Please sign in to comment.