From 1b70e59bde8a3a3b069f445206dce0857a0fbb74 Mon Sep 17 00:00:00 2001 From: Robert Dyer <rdyer@unl.edu> Date: Thu, 22 Aug 2024 11:25:16 -0500 Subject: [PATCH] Apply regular expression conditions to imported transactions. (#3287) --- .../src/server/accounts/rules.test.ts | 20 +++++++++++++++++++ .../loot-core/src/server/accounts/rules.ts | 14 +++++++++++-- upcoming-release-notes/3287.md | 6 ++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 upcoming-release-notes/3287.md diff --git a/packages/loot-core/src/server/accounts/rules.test.ts b/packages/loot-core/src/server/accounts/rules.test.ts index 556230081..392add3ff 100644 --- a/packages/loot-core/src/server/accounts/rules.test.ts +++ b/packages/loot-core/src/server/accounts/rules.test.ts @@ -47,6 +47,9 @@ describe('Condition', () => { let cond = new Condition('contains', 'name', 'foo', null, fieldTypes); expect(cond.eval({ name: null })).toBe(false); + cond = new Condition('matches', 'name', '^fo*$', null, fieldTypes); + expect(cond.eval({ name: null })).toBe(false); + cond = new Condition('oneOf', 'name', ['foo'], null, fieldTypes); expect(cond.eval({ name: null })).toBe(false); @@ -69,6 +72,9 @@ describe('Condition', () => { cond = new Condition('contains', 'name', 'foo', null, fieldTypes); expect(cond.eval({ date: '2020-01-01' })).toBe(false); + cond = new Condition('matches', 'name', '^fo*$', null, fieldTypes); + expect(cond.eval({ date: '2020-01-01' })).toBe(false); + spy.mockRestore(); }); @@ -223,6 +229,20 @@ describe('Condition', () => { expect(cond.eval({ name: 'bfoo' })).toBe(true); expect(cond.eval({ name: 'bfo' })).toBe(false); expect(cond.eval({ name: 'f o o' })).toBe(false); + + cond = new Condition('matches', 'name', '^fo*$', null, fieldTypes); + expect(cond.eval({ name: 'bar foo baz' })).toBe(false); + expect(cond.eval({ name: 'bar FOOb' })).toBe(false); + expect(cond.eval({ name: 'foo' })).toBe(true); + expect(cond.eval({ name: 'foob' })).toBe(false); + expect(cond.eval({ name: 'bfoo' })).toBe(false); + expect(cond.eval({ name: 'bfo' })).toBe(false); + expect(cond.eval({ name: 'f o o' })).toBe(false); + }); + + test('matches handles invalid regex', () => { + const cond = new Condition('matches', 'name', 'fo**', null, fieldTypes); + expect(cond.eval({ name: 'foo' })).toBe(false); }); test('number validates value', () => { diff --git a/packages/loot-core/src/server/accounts/rules.ts b/packages/loot-core/src/server/accounts/rules.ts index b5fbde95d..467dc7bc8 100644 --- a/packages/loot-core/src/server/accounts/rules.ts +++ b/packages/loot-core/src/server/accounts/rules.ts @@ -162,7 +162,7 @@ const CONDITION_TYPES = { assert( Array.isArray(value), 'no-empty-array', - `oneOf must have an array value (field: ${fieldName}): ${JSON.stringify( + `${op} must have an array value (field: ${fieldName}): ${JSON.stringify( value, )}`, ); @@ -173,7 +173,7 @@ const CONDITION_TYPES = { assert( typeof value === 'string' && value.length > 0, 'no-empty-string', - `contains must have non-empty string (field: ${fieldName})`, + `${op} must have non-empty string (field: ${fieldName})`, ); } @@ -420,6 +420,16 @@ export class Condition { ); } return fieldValue <= extractValue(this.value); + case 'matches': + if (fieldValue === null) { + return false; + } + try { + return new RegExp(this.value).test(fieldValue); + } catch (e) { + console.log('invalid regexp in matches condition', e); + return false; + } default: } diff --git a/upcoming-release-notes/3287.md b/upcoming-release-notes/3287.md new file mode 100644 index 000000000..a1b272403 --- /dev/null +++ b/upcoming-release-notes/3287.md @@ -0,0 +1,6 @@ +--- +category: Bugfix +authors: [psybers, jameshurst] +--- + +Apply regular expression conditions to imported transactions. -- GitLab