Skip to content

Commit

Permalink
feat: add documentNumber field to the result object
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
targos committed Jun 3, 2024
1 parent b299836 commit 37f619d
Show file tree
Hide file tree
Showing 10 changed files with 241 additions and 65 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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

Expand Down
11 changes: 8 additions & 3 deletions src/parse/__tests__/frenchDrivingLicense.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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', () => {
Expand Down
52 changes: 47 additions & 5 deletions src/parse/__tests__/frenchNationalId.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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<NAME<<<<<<<<<<<<<<<<0CHE02',
'1710GV?123451ROBERTA<<<<<<<9112311F2',
];

const result = parse(MRZ);

expect(result).toMatchObject({
format: 'FRENCH_NATIONAL_ID',
valid: false,
documentNumber: null,
});

expect(result.fields).toStrictEqual({
documentCode: 'ID',
issuingState: 'FRA',
lastName: 'TEST NAME',
administrativeCode: '0CHE02',
issueDate: '1710',
administrativeCode2: null,
documentNumber: '12345',
documentNumberCheckDigit: null,
firstName: 'ROBERTA',
birthDate: '911231',
birthDateCheckDigit: '1',
sex: 'female',
compositeCheckDigit: null,
});

expect(result.details.filter((a) => !a.valid)).toHaveLength(3);
});

it('Use autocorrect', () => {
const MRZ = [
'IDFRATEST<NAME<<<<<<<<<<<<<<<<0CHE02',
'1710GVA123451ROBERTA<<<<<<<9112311F2',
];

const reference = parse(MRZ);

const falseMRZ = [
'1DFRATE5T<NAME<<<<<<<<<<<<<<<<0CHE02',
'I7I0GVA123451RO8ERTA<<<<<<<9IIZ3IIF2',
];

const result = parse(MRZ);
const correctedResult = parse(falseMRZ, { autocorrect: true });
expect(correctedResult.fields).toStrictEqual(reference.fields);

expect(result.fields).toStrictEqual(correctedResult.fields);
expect(
correctedResult.details.map(({ autocorrect }) => autocorrect),
).toStrictEqual([
Expand Down
73 changes: 44 additions & 29 deletions src/parse/__tests__/swissDrivingLicense.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -41,29 +58,36 @@ describe('parse Swiss Driving License', () => {
end: 18,
autocorrect: [],
});
});

it('invalid text', () => {
const MRZ = [
'AAA001D<<',
'FACHE305142128?97<<800126<<<<<',
'M4RCHAND<<FABI3NNE<<<<<<<<<<<<',
];

const result = parse(MRZ);

expect(result).toMatchObject({
format: 'SWISS_DRIVING_LICENSE',
valid: false,
documentNumber: null,
});

expect(result.fields).toStrictEqual({
documentNumber: 'AAA001D',
languageCode: 'D',
documentCode: 'FA',
issuingState: 'CHE',
pinCode: '305142128',
versionNumber: '097',
versionNumber: null,
birthDate: '800126',
firstName: 'FABIENNE',
lastName: 'MARCHAND',
firstName: null,
lastName: null,
});
});
it('invalid text', () => {
const MRZ = [
'AAA001D<<',
'FACHE305142128097<<800126<<<<<',
'M4RCHAND<<FABI3NNE<<<<<<<<<<<<',
];

const result = parse(MRZ);
expect(result.format).toBe('SWISS_DRIVING_LICENSE');
expect(result.valid).toBe(false);
expect(result.details.filter((a) => !a.valid)).toHaveLength(2);
expect(result.details.filter((a) => !a.valid)).toHaveLength(3);
expect(result.details[0]).toStrictEqual({
label: 'Document number',
field: 'documentNumber',
Expand Down Expand Up @@ -103,34 +127,25 @@ 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 = [
'AAA001D<<',
'FACHE305142128097<<800126<<<<<',
'MARCHAND<<FABIENNE<<<<<<<<<<<<',
];

const reference = parse(MRZ);

const falseMRZ = [
'AAA001D<<',
'FACHE30S142IZBO97<<8OO12G<<<<<',
'MARCHAND<<FA81ENNE<<<<<<<<<<<<',
];

const result = parse(MRZ);
const correctedResult = parse(falseMRZ, { autocorrect: true });

expect(result.fields).toStrictEqual(correctedResult.fields);
expect(correctedResult.fields).toStrictEqual(reference.fields);
expect(
correctedResult.details.map(({ autocorrect }) => autocorrect),
).toStrictEqual([
Expand Down
49 changes: 38 additions & 11 deletions src/parse/__tests__/td1.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ import parse from '../parse';

describe('parse TD1', () => {
it('swiss ID - valid', () => {
const data = [
const MRZ = [
'IDCHEA1234567<6<<<<<<<<<<<<<<<',
'7510256M2009018CHE<<<<<<<<<<<8',
'SMITH<<JOHN<ALBERT<<<<<<<<<<<<',
];

const result = parse(data);
const result = parse(MRZ);

expect(result).toMatchObject({
format: 'TD1',
valid: true,
documentNumber: result.fields.documentNumber,
});

expect(result.fields).toStrictEqual({
documentCode: 'ID',
issuingState: 'CHE',
Expand Down Expand Up @@ -50,7 +53,13 @@ describe('parse TD1', () => {
];

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',
Expand All @@ -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,
);
Expand Down Expand Up @@ -96,8 +106,15 @@ describe('parse TD1', () => {
'7408122F1204159UTO<<<<<<<<<<<8',
'ERIKSSON<<ANNA<MARIA<<<<<<<<<<',
];

const result = parse(MRZ);
expect(result.valid).toBe(false);

expect(result).toMatchObject({
format: 'TD1',
valid: false,
documentNumber: result.fields.documentNumber,
});

expect(result.details.filter((f) => !f.valid)).toHaveLength(2);
const documentNumberDetails = result.details.find(
(d) => d.field === 'documentNumber',
Expand Down Expand Up @@ -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<<JOHN<ALBERT<<<<<<<<<<<<',
];

const falseData = [
const reference = parse(MRZ);

const falseMRZ = [
'IDCHEA1234567<6<<<<<<<<<<<<<<<',
'7SIOZSGMZOO90IBCHE<<<<<<<<<<<B',
'5M1TH<<J0HN<AL8ERT<<<<<<<<<<<<',
];

const result = parse(data);
const correctedResult = parse(falseData, { autocorrect: true });
expect(result.fields).toStrictEqual(correctedResult.fields);
const correctedResult = parse(falseMRZ, { autocorrect: true });

expect(correctedResult.fields).toStrictEqual(reference.fields);

expect(
correctedResult.details.map(({ autocorrect }) => autocorrect),
).toStrictEqual([
Expand Down
Loading

0 comments on commit 37f619d

Please sign in to comment.