From f89e4b73ca9179ace5f5f48cefcd88eef37db9ea Mon Sep 17 00:00:00 2001 From: Urs Wolfer Date: Fri, 6 Mar 2026 09:32:56 +0100 Subject: [PATCH] fix: Handle TD1 embedded document check digits in optional1 for non-compliant documents like PRT and BEL IDs Some TD1 issuers embed the document number check digit inside optional1 when the check-digit slot is `<`. This update validates the embedded digit against the concatenated document number + optional prefix before falling back to the ICAO-style separator variant. This is related to #66. --- src/parse/__tests__/td1.test.ts | 36 ++++++++++++++++++++ src/parsers/__tests__/check.test.ts | 7 +++- src/parsers/check.ts | 8 +++-- src/parsers/parseDocumentNumberCheckDigit.ts | 21 ++++++++++-- 4 files changed, 66 insertions(+), 6 deletions(-) diff --git a/src/parse/__tests__/td1.test.ts b/src/parse/__tests__/td1.test.ts index 0b89373..f2e3355 100644 --- a/src/parse/__tests__/td1.test.ts +++ b/src/parse/__tests__/td1.test.ts @@ -470,4 +470,40 @@ describe('parse TD1', () => { ], ]); }); + + it('Belgium ID BEL-BO-03003 with embedded document check digit', () => { + // source: https://www.consilium.europa.eu/prado/en/BEL-BO-03003/index.html + // This Belgian ID has the document number check digit embedded in optional1 + const MRZ = [ + 'IDBEL000590240<6013<<<<<<<<<<<', + '8512017F1311048BEL851201002007', + 'REINARTZ< { expect(() => check('592166117<231', 8)).not.toThrow(); @@ -11,3 +11,8 @@ test('check digits', () => { expect(() => check('600001795015', 2)).not.toThrow(); expect(() => check('592166111<773', 4)).toThrow(/invalid check digit/); }); + +test('compute embedded TD1 check digit', () => { + expect(computeCheckDigit('123456789AAB')).toBe(8); + expect(computeCheckDigit('123456789