card-validator
Version:
A library for validating credit card fields
95 lines (77 loc) • 2.33 kB
text/typescript
import luhn10 = require("./luhn-10");
import getCardTypes = require("credit-card-type");
import type { Verification } from "./types";
// TODO this should probably come from credit-card-type
type CreditCardType = {
niceType: string;
type: string;
patterns: Array<number[] | number>;
gaps: number[];
lengths: number[];
code: {
name: string;
size: number;
};
};
export interface CardNumberVerification extends Verification {
card: CreditCardType | null;
}
type CardNumberOptions = {
maxLength?: number;
luhnValidateUnionPay?: boolean;
skipLuhnValidation?: boolean;
};
function verification(
card: CreditCardType | null,
isPotentiallyValid: boolean,
isValid: boolean,
): CardNumberVerification {
return {
card,
isPotentiallyValid,
isValid,
};
}
export function cardNumber(
value: string | unknown,
options: CardNumberOptions = {},
): CardNumberVerification {
let isPotentiallyValid, isValid, maxLength;
if (typeof value !== "string" && typeof value !== "number") {
return verification(null, false, false);
}
const testCardValue = String(value).replace(/-|\s/g, "");
if (!/^\d*$/.test(testCardValue)) {
return verification(null, false, false);
}
const potentialTypes = getCardTypes(testCardValue);
if (potentialTypes.length === 0) {
return verification(null, false, false);
} else if (potentialTypes.length !== 1) {
return verification(null, true, false);
}
const cardType = potentialTypes[0];
if (options.maxLength && testCardValue.length > options.maxLength) {
return verification(cardType, false, false);
}
if (
options.skipLuhnValidation === true ||
(cardType.type === getCardTypes.types.UNIONPAY &&
options.luhnValidateUnionPay !== true)
) {
isValid = true;
} else {
isValid = luhn10(testCardValue);
}
maxLength = Math.max.apply(null, cardType.lengths);
if (options.maxLength) {
maxLength = Math.min(options.maxLength, maxLength);
}
for (let i = 0; i < cardType.lengths.length; i++) {
if (cardType.lengths[i] === testCardValue.length) {
isPotentiallyValid = testCardValue.length < maxLength || isValid;
return verification(cardType, isPotentiallyValid, isValid);
}
}
return verification(cardType, testCardValue.length < maxLength, false);
}