From e3da52bebcb1d91a4e3d99ce5322e7241a21120a Mon Sep 17 00:00:00 2001 From: Jakob Nylin Date: Thu, 3 Sep 2026 18:42:04 +0200 Subject: [PATCH] Match duplicate books by ISBN-10/13 equivalence (#6028) --------- Co-authored-by: Dan Stillman --- chrome/content/zotero/xpcom/duplicates.js | 2 ++ test/tests/duplicatesTest.js | 20 +++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/chrome/content/zotero/xpcom/duplicates.js b/chrome/content/zotero/xpcom/duplicates.js index 56f4812a8e..de8eaca05c 100644 --- a/chrome/content/zotero/xpcom/duplicates.js +++ b/chrome/content/zotero/xpcom/duplicates.js @@ -211,6 +211,8 @@ Zotero.Duplicates.prototype._findDuplicates = async function () { let row = rows[i]; let newVal = Zotero.Utilities.cleanISBN('' + row.value); if (!newVal) continue; + // Canonicalize to ISBN-13 so an ISBN-10 and its ISBN-13 equivalent match + newVal = Zotero.Utilities.toISBN13(newVal); isbnCache[row.itemID] = newVal; newRows.push({ itemID: row.itemID, diff --git a/test/tests/duplicatesTest.js b/test/tests/duplicatesTest.js index d86d382de5..bb63295d91 100644 --- a/test/tests/duplicatesTest.js +++ b/test/tests/duplicatesTest.js @@ -20,7 +20,25 @@ describe("Duplicate Items", function () { after(function () { win.close(); }); - + + + describe("ISBN matching", function () { + it("should match books with equivalent ISBN-10 and ISBN-13", async function () { + var item1 = await createDataObject('item', { itemType: 'book', title: 'Effective Java' }); + item1.setField('ISBN', '0134685997'); + await item1.saveTx(); + + var item2 = await createDataObject('item', { itemType: 'book', title: 'Effective Java, 3rd Edition' }); + item2.setField('ISBN', '9780134685991'); + await item2.saveTx(); + + var duplicates = new Zotero.Duplicates(Zotero.Libraries.userLibraryID); + await duplicates.getSearchObject(); + assert.sameMembers(duplicates.getSetItemsByItemID(item1.id), [item1.id, item2.id]); + }); + }); + + async function merge(itemID) { var userLibraryID = Zotero.Libraries.userLibraryID;