From a9f9bc408ab58cbd34619e0cba44042110a409b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Sat, 1 Jun 2024 10:51:33 +0200 Subject: [PATCH 1/3] chore: update dependencies --- package.json | 14 +++++++------- tsconfig.json | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 56debec..e9cf1e7 100644 --- a/package.json +++ b/package.json @@ -47,15 +47,15 @@ }, "homepage": "https://github.com/cheminfo/mrz#readme", "devDependencies": { - "@babel/plugin-transform-modules-commonjs": "^7.23.0", - "@babel/preset-typescript": "^7.23.2", - "@types/jest": "^29.5.6", + "@babel/plugin-transform-modules-commonjs": "^7.24.6", + "@babel/preset-typescript": "^7.24.6", + "@types/jest": "^29.5.12", "cheminfo-build": "^1.2.0", "eslint": "^8.52.0", - "eslint-config-cheminfo-typescript": "^12.0.4", + "eslint-config-cheminfo-typescript": "^12.4.0", "jest": "^29.7.0", - "prettier": "^3.0.3", - "rimraf": "^5.0.5", - "typescript": "^5.2.2" + "prettier": "^3.2.5", + "rimraf": "^5.0.7", + "typescript": "^5.4.5" } } diff --git a/tsconfig.json b/tsconfig.json index 8b6f075..65ddc68 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,7 +8,8 @@ "sourceMap": true, "strict": true, "target": "es2021", - "useUnknownInCatchVariables": false + "useUnknownInCatchVariables": false, + "skipLibCheck": true }, "include": ["./src/**/*"] } From acb8a2c6ae9a93c4d2dec3626b9fcc756fa5410e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Sat, 1 Jun 2024 11:36:31 +0200 Subject: [PATCH 2/3] chore: remove useless "use strict" from TS code --- .eslintrc.yml | 2 -- builder/.eslintrc.yml | 2 ++ builder/createStatesJs.js | 1 - src/formats.ts | 2 -- src/generated/__tests__/states.test.ts | 2 -- src/generated/states.ts | 1 - src/index.ts | 2 -- src/parse/__tests__/errors.test.ts | 2 -- src/parse/__tests__/frenchDrivingLicense.test.ts | 2 -- src/parse/__tests__/frenchNationalId.test.ts | 2 -- src/parse/__tests__/swissDrivingLicense.test.ts | 2 -- src/parse/__tests__/td1.test.ts | 2 -- src/parse/__tests__/td2.test.ts | 2 -- src/parse/__tests__/td3.test.ts | 2 -- src/parse/autoCorrection.ts | 2 -- src/parse/checkLines.ts | 2 -- src/parse/createFieldParser.ts | 2 -- src/parse/fieldTemplates.ts | 2 -- src/parse/frenchDrivingLicence.ts | 2 -- src/parse/frenchDrivingLicenceFields.ts | 2 -- src/parse/frenchNationalId.ts | 2 -- src/parse/frenchNationalIdFields.ts | 2 -- src/parse/getResult.ts | 2 -- src/parse/parse.ts | 5 +++-- src/parse/parsers.ts | 2 -- src/parse/swissDrivingLicense.ts | 2 -- src/parse/swissDrivingLicenseFields.ts | 2 -- src/parse/td1.ts | 2 -- src/parse/td1Fields.ts | 2 -- src/parse/td2.ts | 2 -- src/parse/td2Fields.ts | 2 -- src/parse/td3.ts | 2 -- src/parse/td3Fields.ts | 2 -- src/parsers/__tests__/check.test.ts | 2 -- src/parsers/check.ts | 2 -- src/parsers/cleanText.ts | 2 -- src/parsers/frenchDrivingLicence/parseDocumentCode.ts | 2 -- src/parsers/parseAlpha.ts | 2 -- src/parsers/parseCompositeCheckDigit.ts | 2 -- src/parsers/parseDate.ts | 2 -- src/parsers/parseDateCheckDigit.ts | 2 -- src/parsers/parseDocumentCodeId.ts | 2 -- src/parsers/parseDocumentCodePassport.ts | 2 -- src/parsers/parseDocumentNumber.ts | 2 -- src/parsers/parseDocumentNumberCheckDigit.ts | 2 -- src/parsers/parseDocumentNumberOptional.ts | 2 -- src/parsers/parseFirstName.ts | 2 -- src/parsers/parseLastName.ts | 2 -- src/parsers/parseNumber.ts | 2 -- src/parsers/parseOptional.ts | 2 -- src/parsers/parsePersonalNumber.ts | 2 -- src/parsers/parsePersonalNumberCheckDigit.ts | 2 -- src/parsers/parseSex.ts | 2 -- src/parsers/parseState.ts | 2 -- src/parsers/parseText.ts | 2 -- src/parsers/swissDrivingLicense/checkSeparator.ts | 2 -- src/parsers/swissDrivingLicense/parseDocumentCode.ts | 2 -- src/parsers/swissDrivingLicense/parseDocumentNumber.ts | 2 -- src/parsers/swissDrivingLicense/parseIssuingState.ts | 2 -- src/parsers/swissDrivingLicense/parseLanguageCode.ts | 2 -- src/types.ts | 2 -- tsconfig.json | 1 - 62 files changed, 5 insertions(+), 119 deletions(-) create mode 100644 builder/.eslintrc.yml diff --git a/.eslintrc.yml b/.eslintrc.yml index 9e0bb1b..7fa2f92 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,5 +1,3 @@ extends: cheminfo-typescript env: node: true -parserOptions: - sourceType: script diff --git a/builder/.eslintrc.yml b/builder/.eslintrc.yml new file mode 100644 index 0000000..639250e --- /dev/null +++ b/builder/.eslintrc.yml @@ -0,0 +1,2 @@ +parserOptions: + sourceType: script \ No newline at end of file diff --git a/builder/createStatesJs.js b/builder/createStatesJs.js index 5c9ba2a..a09b2f3 100644 --- a/builder/createStatesJs.js +++ b/builder/createStatesJs.js @@ -43,7 +43,6 @@ const statesObject = { }; const result = []; -result.push("'use strict';"); result.push(`const states = ${JSON.stringify(statesObject, null, 2)};`); result.push('Object.freeze(states);'); result.push('export default states;'); diff --git a/src/formats.ts b/src/formats.ts index f0fcc73..760dc09 100644 --- a/src/formats.ts +++ b/src/formats.ts @@ -1,5 +1,3 @@ -'use strict'; - export type FormatType = keyof typeof formats; export const formats = { diff --git a/src/generated/__tests__/states.test.ts b/src/generated/__tests__/states.test.ts index b57327b..86b8872 100644 --- a/src/generated/__tests__/states.test.ts +++ b/src/generated/__tests__/states.test.ts @@ -1,5 +1,3 @@ -'use strict'; - import states from '../states'; describe('check countries', function () { diff --git a/src/generated/states.ts b/src/generated/states.ts index 0f046ff..e108271 100644 --- a/src/generated/states.ts +++ b/src/generated/states.ts @@ -1,4 +1,3 @@ -'use strict'; const states = { "AFG": "Afghanistan", "ALB": "Albania", diff --git a/src/index.ts b/src/index.ts index b054f6d..a5afc2b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,3 @@ -'use strict'; - import { formats } from './formats'; import states from './generated/states'; import parse from './parse/parse'; diff --git a/src/parse/__tests__/errors.test.ts b/src/parse/__tests__/errors.test.ts index 6af58c1..05366c3 100644 --- a/src/parse/__tests__/errors.test.ts +++ b/src/parse/__tests__/errors.test.ts @@ -1,5 +1,3 @@ -'use strict'; - import parse from '../parse'; describe('Bad MRZ', () => { diff --git a/src/parse/__tests__/frenchDrivingLicense.test.ts b/src/parse/__tests__/frenchDrivingLicense.test.ts index 9e311f8..66a4f9a 100644 --- a/src/parse/__tests__/frenchDrivingLicense.test.ts +++ b/src/parse/__tests__/frenchDrivingLicense.test.ts @@ -1,5 +1,3 @@ -'use strict'; - import parse from '../parse'; describe('parse French Driving License', () => { diff --git a/src/parse/__tests__/frenchNationalId.test.ts b/src/parse/__tests__/frenchNationalId.test.ts index a3f04e4..d56464e 100644 --- a/src/parse/__tests__/frenchNationalId.test.ts +++ b/src/parse/__tests__/frenchNationalId.test.ts @@ -1,5 +1,3 @@ -'use strict'; - import parse from '../parse'; describe('parse French National Id', () => { diff --git a/src/parse/__tests__/swissDrivingLicense.test.ts b/src/parse/__tests__/swissDrivingLicense.test.ts index e0ffbd8..cd70e5d 100644 --- a/src/parse/__tests__/swissDrivingLicense.test.ts +++ b/src/parse/__tests__/swissDrivingLicense.test.ts @@ -1,5 +1,3 @@ -'use strict'; - import parse from '../parse'; describe('parse Swiss Driving License', () => { diff --git a/src/parse/__tests__/td1.test.ts b/src/parse/__tests__/td1.test.ts index 0495164..5117aab 100644 --- a/src/parse/__tests__/td1.test.ts +++ b/src/parse/__tests__/td1.test.ts @@ -1,5 +1,3 @@ -'use strict'; - import parse from '../parse'; describe('parse TD1', () => { diff --git a/src/parse/__tests__/td2.test.ts b/src/parse/__tests__/td2.test.ts index 23c35bf..e7fc787 100644 --- a/src/parse/__tests__/td2.test.ts +++ b/src/parse/__tests__/td2.test.ts @@ -1,5 +1,3 @@ -'use strict'; - import parse from '../parse'; describe('parse TD2', () => { diff --git a/src/parse/__tests__/td3.test.ts b/src/parse/__tests__/td3.test.ts index c27dbac..7fbee79 100644 --- a/src/parse/__tests__/td3.test.ts +++ b/src/parse/__tests__/td3.test.ts @@ -1,5 +1,3 @@ -'use strict'; - import parse from '../parse'; describe('parse TD3', () => { diff --git a/src/parse/autoCorrection.ts b/src/parse/autoCorrection.ts index 094c24f..9f877bf 100644 --- a/src/parse/autoCorrection.ts +++ b/src/parse/autoCorrection.ts @@ -1,5 +1,3 @@ -'use strict'; - import { Autocorrect } from '../types'; import { FieldOptions, fieldTypes } from './createFieldParser'; diff --git a/src/parse/checkLines.ts b/src/parse/checkLines.ts index e2a176a..3776689 100644 --- a/src/parse/checkLines.ts +++ b/src/parse/checkLines.ts @@ -1,5 +1,3 @@ -'use strict'; - export function checkLines(lines: string | string[]) { if (typeof lines === 'string') { lines = lines.split(/[\r\n]+/); diff --git a/src/parse/createFieldParser.ts b/src/parse/createFieldParser.ts index 1c4b9ed..bf8a591 100644 --- a/src/parse/createFieldParser.ts +++ b/src/parse/createFieldParser.ts @@ -1,5 +1,3 @@ -'use strict'; - import { ParseTextError } from '../parsers/parseText'; import { Autocorrect, Details, FieldName, Range } from '../types'; diff --git a/src/parse/fieldTemplates.ts b/src/parse/fieldTemplates.ts index 7df5d6f..786bdce 100644 --- a/src/parse/fieldTemplates.ts +++ b/src/parse/fieldTemplates.ts @@ -1,5 +1,3 @@ -'use strict'; - import parseCompositeCheckDigit from '../parsers/parseCompositeCheckDigit'; import parseDate from '../parsers/parseDate'; import parseDateCheckDigit from '../parsers/parseDateCheckDigit'; diff --git a/src/parse/frenchDrivingLicence.ts b/src/parse/frenchDrivingLicence.ts index 8f6e358..0d00b1d 100644 --- a/src/parse/frenchDrivingLicence.ts +++ b/src/parse/frenchDrivingLicence.ts @@ -1,5 +1,3 @@ -'use strict'; - import { formats } from '../formats'; import frenchDrivingLicenceFields from './frenchDrivingLicenceFields'; diff --git a/src/parse/frenchDrivingLicenceFields.ts b/src/parse/frenchDrivingLicenceFields.ts index 864faa4..4b239b9 100644 --- a/src/parse/frenchDrivingLicenceFields.ts +++ b/src/parse/frenchDrivingLicenceFields.ts @@ -1,5 +1,3 @@ -'use strict'; - import parseDocumentCode from '../parsers/frenchDrivingLicence/parseDocumentCode'; import { parseAlpha } from '../parsers/parseAlpha'; diff --git a/src/parse/frenchNationalId.ts b/src/parse/frenchNationalId.ts index bacd26c..052cb2a 100644 --- a/src/parse/frenchNationalId.ts +++ b/src/parse/frenchNationalId.ts @@ -1,5 +1,3 @@ -'use strict'; - import { formats } from '../formats'; import frenchNationalIdFields from './frenchNationalIdFields'; diff --git a/src/parse/frenchNationalIdFields.ts b/src/parse/frenchNationalIdFields.ts index f53665f..8115929 100644 --- a/src/parse/frenchNationalIdFields.ts +++ b/src/parse/frenchNationalIdFields.ts @@ -1,5 +1,3 @@ -'use strict'; - import { parseAlpha } from '../parsers/parseAlpha'; import parseDocumentCode from '../parsers/parseDocumentCodeId'; import { parseOptional } from '../parsers/parseOptional'; diff --git a/src/parse/getResult.ts b/src/parse/getResult.ts index 8a8a375..35e4150 100644 --- a/src/parse/getResult.ts +++ b/src/parse/getResult.ts @@ -1,5 +1,3 @@ -'use strict'; - import { FormatType } from '../formats'; import { Autocorrect, Details, FieldRecords, ParseResult } from '../types'; diff --git a/src/parse/parse.ts b/src/parse/parse.ts index d06e419..818ff60 100644 --- a/src/parse/parse.ts +++ b/src/parse/parse.ts @@ -1,4 +1,4 @@ -'use strict'; +import { ParseResult } from '../types'; import { checkLines } from './checkLines'; import { parsers } from './parsers'; @@ -6,10 +6,11 @@ import { parsers } from './parsers'; export interface ParseMRZOptions { autocorrect?: boolean; } + function parseMRZ( inputLines: string | string[], options: ParseMRZOptions = {}, -) { +): ParseResult { const lines = checkLines(inputLines); switch (lines.length) { case 1: { diff --git a/src/parse/parsers.ts b/src/parse/parsers.ts index d3113e9..2baf592 100644 --- a/src/parse/parsers.ts +++ b/src/parse/parsers.ts @@ -1,5 +1,3 @@ -'use strict'; - import parseFrenchDrivingLicense from './frenchDrivingLicence'; import parseFrenchNationalId from './frenchNationalId'; import parseSwissDrivingLicense from './swissDrivingLicense'; diff --git a/src/parse/swissDrivingLicense.ts b/src/parse/swissDrivingLicense.ts index 5f81f1e..59ed66f 100644 --- a/src/parse/swissDrivingLicense.ts +++ b/src/parse/swissDrivingLicense.ts @@ -1,5 +1,3 @@ -'use strict'; - import { formats } from '../formats'; import { getResult } from './getResult'; diff --git a/src/parse/swissDrivingLicenseFields.ts b/src/parse/swissDrivingLicenseFields.ts index 3b15f96..fc308e8 100644 --- a/src/parse/swissDrivingLicenseFields.ts +++ b/src/parse/swissDrivingLicenseFields.ts @@ -1,5 +1,3 @@ -'use strict'; - import { parseNumber } from '../parsers/parseNumber'; import { checkSeparator } from '../parsers/swissDrivingLicense/checkSeparator'; import parseDocumentCode from '../parsers/swissDrivingLicense/parseDocumentCode'; diff --git a/src/parse/td1.ts b/src/parse/td1.ts index 4c5c85d..30645a9 100644 --- a/src/parse/td1.ts +++ b/src/parse/td1.ts @@ -1,5 +1,3 @@ -'use strict'; - import { formats } from '../formats'; import { getResult } from './getResult'; diff --git a/src/parse/td1Fields.ts b/src/parse/td1Fields.ts index e9db398..998a632 100644 --- a/src/parse/td1Fields.ts +++ b/src/parse/td1Fields.ts @@ -1,5 +1,3 @@ -'use strict'; - import parseDocumentCode from '../parsers/parseDocumentCodeId'; import { parseDocumentNumberOptional } from '../parsers/parseDocumentNumberOptional'; import { parseOptional } from '../parsers/parseOptional'; diff --git a/src/parse/td2.ts b/src/parse/td2.ts index 032286b..ee81646 100644 --- a/src/parse/td2.ts +++ b/src/parse/td2.ts @@ -1,5 +1,3 @@ -'use strict'; - import { formats } from '../formats'; import { getResult } from './getResult'; diff --git a/src/parse/td2Fields.ts b/src/parse/td2Fields.ts index ded3f19..3258a9e 100644 --- a/src/parse/td2Fields.ts +++ b/src/parse/td2Fields.ts @@ -1,5 +1,3 @@ -'use strict'; - import parseDocumentCode from '../parsers/parseDocumentCodeId'; import { parseOptional } from '../parsers/parseOptional'; diff --git a/src/parse/td3.ts b/src/parse/td3.ts index 3d07a5d..472fed1 100644 --- a/src/parse/td3.ts +++ b/src/parse/td3.ts @@ -1,5 +1,3 @@ -'use strict'; - import { formats } from '../formats'; import { getResult } from './getResult'; diff --git a/src/parse/td3Fields.ts b/src/parse/td3Fields.ts index faf7334..7d89c74 100644 --- a/src/parse/td3Fields.ts +++ b/src/parse/td3Fields.ts @@ -1,5 +1,3 @@ -'use strict'; - import parseDocumentCode from '../parsers/parseDocumentCodePassport'; import { parsePersonalNumber } from '../parsers/parsePersonalNumber'; import { parsePersonalNumberCheckDigit } from '../parsers/parsePersonalNumberCheckDigit'; diff --git a/src/parsers/__tests__/check.test.ts b/src/parsers/__tests__/check.test.ts index 0bf9662..c9e48fd 100644 --- a/src/parsers/__tests__/check.test.ts +++ b/src/parsers/__tests__/check.test.ts @@ -1,5 +1,3 @@ -'use strict'; - import { check } from '../check'; test('check digits', () => { diff --git a/src/parsers/check.ts b/src/parsers/check.ts index 4fe653c..344778b 100644 --- a/src/parsers/check.ts +++ b/src/parsers/check.ts @@ -1,5 +1,3 @@ -'use strict'; - export function check(string: string, value: string | number) { let code = 0; const factors = [7, 3, 1]; diff --git a/src/parsers/cleanText.ts b/src/parsers/cleanText.ts index acbebdc..1e7c00a 100644 --- a/src/parsers/cleanText.ts +++ b/src/parsers/cleanText.ts @@ -1,5 +1,3 @@ -'use strict'; - export function cleanText(string: string) { return string.replace(/<+$/g, '').replace(/ Date: Sat, 1 Jun 2024 12:04:50 +0200 Subject: [PATCH 3/3] feat: add `documentNumber` field to the result object This field contains the value shown in visual elements of the document and may be different than the `documentNumber` MRZ field. Also improve the consistency of tests assertions. --- README.md | 10 ++- .../__tests__/frenchDrivingLicense.test.ts | 11 ++- src/parse/__tests__/frenchNationalId.test.ts | 52 +++++++++++-- .../__tests__/swissDrivingLicense.test.ts | 73 +++++++++++-------- src/parse/__tests__/td1.test.ts | 49 ++++++++++--- src/parse/__tests__/td2.test.ts | 17 +++-- src/parse/__tests__/td3.test.ts | 52 ++++++++++--- src/parse/getDocumentNumber.ts | 39 ++++++++++ src/parse/getResult.ts | 2 + src/types.ts | 1 + 10 files changed, 241 insertions(+), 65 deletions(-) create mode 100644 src/parse/getDocumentNumber.ts diff --git a/README.md b/README.md index 59d0e6e..3e43a18 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,12 @@ Object mapping field names to their respective value. The value is set to `null` if it is invalid. The value may be different from the raw value. For example, `result.fields.sex` will be "male" when the raw value was "M". +##### result.documentNumber + +The document number, as can be found in the visual elements of the document, outside the MRZ. For some documents, it may +be composed of multiple parsed fields. It may also not include the MRZ field named `documentNumber`. If any of the used +fields is invalid, this field will be set to `null`. + ##### result.details Array of objects describing all parsed fields. Its structure is: @@ -113,11 +119,11 @@ https://www.icao.int/publications/pages/publication.aspx?docnum=9303 ### Swiss driving license -http://www.astra2.admin.ch/media/pdfpub/2003-10-15_2262_f.pdf +https://www.astra.admin.ch/dam/astra/fr/dokumente/dokumente-strassenverkehr/kreisschreiben/ch-fak.pdf.download.pdf/Le%20permis%20de%20conduire%20suisse%20format%20carte%20de%20cr%C3%A9dit%20(PCC).pdf ### French national id -https://fr.wikipedia.org/wiki/Carte_nationale_d%27identit%C3%A9_en_France#Codage_Bande_MRZ_(lecture_optique) +https://fr.wikipedia.org/wiki/Carte_nationale_d%27identit%C3%A9_en_France#Codage_bande_%C3%A0_lecture_optique ## License diff --git a/src/parse/__tests__/frenchDrivingLicense.test.ts b/src/parse/__tests__/frenchDrivingLicense.test.ts index 66a4f9a..91ddfff 100644 --- a/src/parse/__tests__/frenchDrivingLicense.test.ts +++ b/src/parse/__tests__/frenchDrivingLicense.test.ts @@ -6,9 +6,12 @@ describe('parse French Driving License', () => { const result = parse(MRZ); - expect(result.format).toBe('FRENCH_DRIVING_LICENSE'); - expect(result.valid).toBe(true); - expect(result.details.filter((a) => !a.valid)).toHaveLength(0); + expect(result).toMatchObject({ + format: 'FRENCH_DRIVING_LICENSE', + valid: true, + documentNumber: result.fields.documentNumber, + }); + expect(result.fields).toStrictEqual({ documentCode: 'D1', issuingState: 'FRA', @@ -18,6 +21,8 @@ describe('parse French Driving License', () => { lastName: 'MARTIN', compositeCheckDigit: '9', }); + + expect(result.details.filter((a) => !a.valid)).toHaveLength(0); }); it('Use autocorrect', () => { diff --git a/src/parse/__tests__/frenchNationalId.test.ts b/src/parse/__tests__/frenchNationalId.test.ts index d56464e..d8ff6ef 100644 --- a/src/parse/__tests__/frenchNationalId.test.ts +++ b/src/parse/__tests__/frenchNationalId.test.ts @@ -8,9 +8,13 @@ describe('parse French National Id', () => { ]; const result = parse(MRZ); - expect(result.format).toBe('FRENCH_NATIONAL_ID'); - // expect(result.valid).toStrictEqual(true); - expect(result.details.filter((a) => !a.valid)).toHaveLength(0); + + expect(result).toMatchObject({ + format: 'FRENCH_NATIONAL_ID', + valid: true, + documentNumber: '1710GVA12345', + }); + expect(result.fields).toStrictEqual({ documentCode: 'ID', issuingState: 'FRA', @@ -26,21 +30,59 @@ describe('parse French National Id', () => { sex: 'female', compositeCheckDigit: '2', }); + + expect(result.details.filter((a) => !a.valid)).toHaveLength(0); }); + + it('invalid MRZ', () => { + const MRZ = [ + 'IDFRATEST !a.valid)).toHaveLength(3); + }); + it('Use autocorrect', () => { const MRZ = [ 'IDFRATEST autocorrect), ).toStrictEqual([ diff --git a/src/parse/__tests__/swissDrivingLicense.test.ts b/src/parse/__tests__/swissDrivingLicense.test.ts index cd70e5d..fab5b4f 100644 --- a/src/parse/__tests__/swissDrivingLicense.test.ts +++ b/src/parse/__tests__/swissDrivingLicense.test.ts @@ -9,8 +9,25 @@ describe('parse Swiss Driving License', () => { ]; const result = parse(MRZ); - expect(result.format).toBe('SWISS_DRIVING_LICENSE'); - expect(result.valid).toBe(true); + + expect(result).toMatchObject({ + format: 'SWISS_DRIVING_LICENSE', + valid: true, + documentNumber: '305142128097', + }); + + expect(result.fields).toStrictEqual({ + documentNumber: 'AAA001D', + languageCode: 'D', + documentCode: 'FA', + issuingState: 'CHE', + pinCode: '305142128', + versionNumber: '097', + birthDate: '800126', + firstName: 'FABIENNE', + lastName: 'MARCHAND', + }); + expect(result.details.filter((a) => !a.valid)).toHaveLength(0); expect(result.details[0]).toStrictEqual({ label: 'Document number', @@ -41,29 +58,36 @@ describe('parse Swiss Driving License', () => { end: 18, autocorrect: [], }); + }); + + it('invalid text', () => { + const MRZ = [ + 'AAA001D<<', + 'FACHE305142128?97<<800126<<<<<', + 'M4RCHAND< { - const MRZ = [ - 'AAA001D<<', - 'FACHE305142128097<<800126<<<<<', - 'M4RCHAND< !a.valid)).toHaveLength(2); + expect(result.details.filter((a) => !a.valid)).toHaveLength(3); expect(result.details[0]).toStrictEqual({ label: 'Document number', field: 'documentNumber', @@ -103,17 +127,6 @@ describe('parse Swiss Driving License', () => { start: 0, end: 8, }); - expect(result.fields).toStrictEqual({ - documentNumber: 'AAA001D', - languageCode: 'D', - documentCode: 'FA', - issuingState: 'CHE', - pinCode: '305142128', - versionNumber: '097', - birthDate: '800126', - firstName: null, - lastName: null, - }); }); it('Use autocorrect', () => { const MRZ = [ @@ -121,16 +134,18 @@ describe('parse Swiss Driving License', () => { 'FACHE305142128097<<800126<<<<<', 'MARCHAND< autocorrect), ).toStrictEqual([ diff --git a/src/parse/__tests__/td1.test.ts b/src/parse/__tests__/td1.test.ts index 5117aab..4fc0eda 100644 --- a/src/parse/__tests__/td1.test.ts +++ b/src/parse/__tests__/td1.test.ts @@ -2,17 +2,20 @@ import parse from '../parse'; describe('parse TD1', () => { it('swiss ID - valid', () => { - const data = [ + const MRZ = [ 'IDCHEA1234567<6<<<<<<<<<<<<<<<', '7510256M2009018CHE<<<<<<<<<<<8', 'SMITH< { ]; const result = parse(MRZ); - expect(result.details.filter((a) => !a.valid)).toHaveLength(2); + + expect(result).toMatchObject({ + format: 'TD1', + valid: false, + documentNumber: result.fields.documentNumber, + }); + expect(result.fields).toStrictEqual({ firstName: 'ANNA MARIA', lastName: 'ERIKSSON', @@ -68,7 +77,8 @@ describe('parse TD1', () => { optional2: '', compositeCheckDigit: '1', }); - expect(result.valid).toBe(false); + + expect(result.details.filter((a) => !a.valid)).toHaveLength(2); expect(result.details.find((a) => a.field === 'issuingState')?.valid).toBe( false, ); @@ -96,8 +106,15 @@ describe('parse TD1', () => { '7408122F1204159UTO<<<<<<<<<<<8', 'ERIKSSON< !f.valid)).toHaveLength(2); const documentNumberDetails = result.details.find( (d) => d.field === 'documentNumber', @@ -139,26 +156,36 @@ describe('parse TD1', () => { ]; const result = parse(MRZ); - expect(result.valid).toBe(true); + + expect(result).toMatchObject({ + format: 'TD1', + valid: true, + documentNumber: result.fields.documentNumber, + }); + expect(result.fields.lastName).toBe(''); expect(result.fields.firstName).toBe('ANNA MARIA'); }); + it('Use autocorrection', () => { - const data = [ + const MRZ = [ 'IDCHEA1234567<6<<<<<<<<<<<<<<<', '7510256M2009018CHE<<<<<<<<<<<8', 'SMITH< autocorrect), ).toStrictEqual([ diff --git a/src/parse/__tests__/td2.test.ts b/src/parse/__tests__/td2.test.ts index e7fc787..be3bb3c 100644 --- a/src/parse/__tests__/td2.test.ts +++ b/src/parse/__tests__/td2.test.ts @@ -8,12 +8,13 @@ describe('parse TD2', () => { ]; const result = parse(MRZ); - const failed = result.details.filter((a) => !a.valid); + expect(result).toMatchObject({ format: 'TD2', valid: false, + documentNumber: result.fields.documentNumber, }); - expect(failed).toHaveLength(2); + expect(result.fields).toStrictEqual({ firstName: 'ANNA MARIA', lastName: 'ERIKSSON', @@ -30,22 +31,28 @@ describe('parse TD2', () => { compositeCheckDigit: '6', optional: '', }); - expect(result.valid).toBe(false); + + const failed = result.details.filter((a) => !a.valid); + expect(failed).toHaveLength(2); }); + it('Use autocorrect', () => { const MRZ = [ 'I autocorrect), ).toStrictEqual([ diff --git a/src/parse/__tests__/td3.test.ts b/src/parse/__tests__/td3.test.ts index 7fbee79..6fa0843 100644 --- a/src/parse/__tests__/td3.test.ts +++ b/src/parse/__tests__/td3.test.ts @@ -8,13 +8,13 @@ describe('parse TD3', () => { ]; const result = parse(MRZ); + expect(result).toMatchObject({ - valid: false, format: 'TD3', + valid: false, + documentNumber: result.fields.documentNumber, }); - expect(result.valid).toBe(false); - const errors = result.details.filter((a) => !a.valid); - expect(errors).toHaveLength(2); + expect(result.fields).toStrictEqual({ documentCode: 'P', firstName: 'ANNA MARIA', @@ -33,6 +33,9 @@ describe('parse TD3', () => { compositeCheckDigit: '0', }); + const errors = result.details.filter((a) => !a.valid); + expect(errors).toHaveLength(2); + const personalNumberDetails = result.details.find( (d) => d.field === 'personalNumber', ); @@ -69,7 +72,13 @@ describe('parse TD3', () => { ]; const result = parse(MRZ); - expect(result.valid).toBe(true); + + expect(result).toMatchObject({ + format: 'TD3', + valid: true, + documentNumber: result.fields.documentNumber, + }); + expect(result.fields).toStrictEqual({ documentCode: 'P', issuingState: 'D', @@ -94,8 +103,15 @@ describe('parse TD3', () => { 'P { 'POCHNABULIKEMU< { 'PTCHNCESHI< { 'P autocorrect), ).toStrictEqual([ diff --git a/src/parse/getDocumentNumber.ts b/src/parse/getDocumentNumber.ts new file mode 100644 index 0000000..81f6550 --- /dev/null +++ b/src/parse/getDocumentNumber.ts @@ -0,0 +1,39 @@ +import { FieldRecords, MRZFormat } from '../types'; + +export function getDocumentNumber(format: MRZFormat, fields: FieldRecords) { + switch (format) { + case 'TD1': + case 'TD2': + case 'TD3': + case 'FRENCH_DRIVING_LICENSE': + return buildDocumentNumber(fields.documentNumber); + case 'FRENCH_NATIONAL_ID': + return buildDocumentNumber( + fields.issueDate, + fields.administrativeCode2, + fields.documentNumber, + ); + case 'SWISS_DRIVING_LICENSE': + return buildDocumentNumber(fields.pinCode, fields.versionNumber); + default: + assertUnreachableFormat(format); + } +} + +function buildDocumentNumber( + ...parts: Array +): string | null { + let result = ''; + for (const part of parts) { + if (!part) { + return null; + } + result += part; + } + return result; +} + +function assertUnreachableFormat(format: never): never { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + throw new Error(`unrecognized format: ${format}`); +} diff --git a/src/parse/getResult.ts b/src/parse/getResult.ts index 35e4150..fa4124b 100644 --- a/src/parse/getResult.ts +++ b/src/parse/getResult.ts @@ -2,6 +2,7 @@ import { FormatType } from '../formats'; import { Autocorrect, Details, FieldRecords, ParseResult } from '../types'; import { CreateFieldParserResult } from './createFieldParser'; +import { getDocumentNumber } from './getDocumentNumber'; import { ParseMRZOptions } from './parse'; function getDetails( @@ -71,6 +72,7 @@ export function getResult( format, details, fields: fields.fields, + documentNumber: getDocumentNumber(format, fields.fields), valid: fields.allValid, }; } diff --git a/src/types.ts b/src/types.ts index 3e85fb0..255d43c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -28,6 +28,7 @@ export interface ParseResult { format: MRZFormat; valid: boolean; fields: FieldRecords; + documentNumber: string | null; details: Details[]; }