diff --git a/.gitignore b/.gitignore index aed2c28..608dc3c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ node_modules/ npm-debug.log dist +.idea diff --git a/CHANGELOG.md b/CHANGELOG.md index e769c56..f1afabd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,11 @@ +# UNRELEASED +- Support skipping of luhn check digit validation in card number validator. + # 9.0.0 - BREAKING CHANGES - Update node to v18 --DevDependency Updates: + -DevDependency Updates: - Update prettier to v3 - Update eslint-plugin-prettier to v5 diff --git a/README.md b/README.md index 573de72..1e043fb 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,8 @@ You can optionally pass `maxLength` as a property of an object as a second argum If a card brand has a normal max length that is shorter than the passed in max length, the validator will use the shorter one. For instance, if a `maxLength` of `16` is provided, the validator will still use `15` as the max length for American Express cards. +You can optionally pass `skipLuhnValidation: true` as a property of an object as a second argument. This will override the default behaviour and will skip the validation of the check digit of the card number using Luhn Algorithm. The `skipLuhnValidation` **should not** be set to `true` in production environment. + ```javascript valid.number(, {maxLength: 16}); diff --git a/src/__tests__/card-number.ts b/src/__tests__/card-number.ts index 494403d..8205f56 100644 --- a/src/__tests__/card-number.ts +++ b/src/__tests__/card-number.ts @@ -349,4 +349,25 @@ describe("number validates", () => { expect(actual.isValid).toBe(true); }); }); + + describe("Skip Luhn Validation", () => { + const number = "5732806135556590"; + it("should fail validation for a card with invalid luhn check digit", () => { + const actual = cardNumber(number); + + expect(actual.card.type).toBe("maestro"); + expect(actual.isPotentiallyValid).toBe(true); + expect(actual.isValid).toBe(false); + }); + + it("should succeed validation for a card with invalid luhn check digit when using skipLuhnValidation=true", () => { + const actual = cardNumber(number, { + skipLuhnValidation: true, + }); + + expect(actual.card.type).toBe("maestro"); + expect(actual.isPotentiallyValid).toBe(true); + expect(actual.isValid).toBe(true); + }); + }); }); diff --git a/src/card-number.ts b/src/card-number.ts index d012b3c..22dd311 100644 --- a/src/card-number.ts +++ b/src/card-number.ts @@ -22,6 +22,7 @@ export interface CardNumberVerification extends Verification { type CardNumberOptions = { maxLength?: number; luhnValidateUnionPay?: boolean; + skipLuhnValidation?: boolean; }; function verification( @@ -67,8 +68,9 @@ export function cardNumber( } if ( - cardType.type === getCardTypes.types.UNIONPAY && - options.luhnValidateUnionPay !== true + options.skipLuhnValidation === true || + (cardType.type === getCardTypes.types.UNIONPAY && + options.luhnValidateUnionPay !== true) ) { isValid = true; } else {