From 845356245c7a875259bbac2858fdc95cf9e07ed8 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Sun, 24 Nov 2024 12:08:09 +0100 Subject: [PATCH] enh(Scanner): Improve move matching by introducing a folder similarity measure Signed-off-by: Marcel Klehr --- src/lib/Scanner.ts | 12 ++++++++++-- src/lib/Tree.ts | 23 ++++++++++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/lib/Scanner.ts b/src/lib/Scanner.ts index 231c6ba685..d6ab810b46 100644 --- a/src/lib/Scanner.ts +++ b/src/lib/Scanner.ts @@ -187,7 +187,11 @@ export default class Scanner // give the browser time to breathe await Promise.resolve() const removedItem = removeAction.payload - const oldItem = removedItem.findItemFilter(createdItem.type, item => this.mergeable(item, createdItem)) + const oldItem = removedItem.findItemFilter( + createdItem.type, + item => this.mergeable(item, createdItem), + item => item.childrenSimilarity(createdItem) + ) if (oldItem) { let oldIndex this.result.CREATE.retract(createAction) @@ -215,7 +219,11 @@ export default class Scanner await this.diffItem(oldItem, createdItem) } } else { - const newItem = createdItem.findItemFilter(removedItem.type, item => this.mergeable(removedItem, item)) + const newItem = createdItem.findItemFilter( + removedItem.type, + item => this.mergeable(removedItem, item), + item => item.childrenSimilarity(createdItem) + ) let index if (newItem) { this.result.REMOVE.retract(removeAction) diff --git a/src/lib/Tree.ts b/src/lib/Tree.ts index 1910142af8..de941e2e61 100644 --- a/src/lib/Tree.ts +++ b/src/lib/Tree.ts @@ -74,6 +74,10 @@ export class Bookmark { return false } + childrenSimilarity(otherItem: TItem): number { + return 0 + } + async hash():Promise { if (!this.hashValue) { this.hashValue = await Crypto.sha256( @@ -107,7 +111,7 @@ export class Bookmark { } // TODO: Make this return the correct type based on the type param - findItemFilter(type:TItemType, fn:(Item)=>boolean):TItem|null { + findItemFilter(type:TItemType, fn:(item:TItem)=>boolean, prefer:(item: TItem)=>number = () => 1):TItem|null { if (type === ItemType.BOOKMARK && fn(this)) { return this } @@ -185,11 +189,13 @@ export class Folder { } // eslint-disable-next-line no-use-before-define - findItemFilter(type:TItemType, fn:(Item)=>boolean):TItem|null { + findItemFilter(type:TItemType, fn:(Item)=>boolean, prefer:(Item)=>number = () => 1):TItem|null { if (!this.index) { this.createIndex() } - return Object.values(this.index[type]).find(fn) + const candidates = Object.values(this.index[type]).filter(fn) + // return the preferred match based on a preference measure + return candidates.sort((a,b) => prefer(a) - prefer(b)).pop() } findFolder(id:string|number): Folder { @@ -256,6 +262,17 @@ export class Folder { return false } + childrenSimilarity(otherItem: TItem): number { + if (otherItem instanceof Folder) { + return this.children.reduce( + (count, item) => + otherItem.children.filter(i => i.title === item.title).length > 0 ? count + 1 : count, + 0 + ) / Math.max(this.children.length, otherItem.children.length) + } + return 0 + } + async hash(preserveOrder = false): Promise { if (this.hashValue && this.hashValue[String(preserveOrder)]) { return this.hashValue[String(preserveOrder)]