credit-card-type
Version:
A library for determining credit card type
152 lines (117 loc) • 3.67 kB
text/typescript
import cardTypes = require("./lib/card-types");
import { addMatchingCardsToResults } from "./lib/add-matching-cards-to-results";
import { isValidInputType } from "./lib/is-valid-input-type";
import { findBestMatch } from "./lib/find-best-match";
import { clone } from "./lib/clone";
import type {
CreditCardType,
CardCollection,
CreditCardTypeCardBrandId,
} from "./types";
let customCards = {} as CardCollection;
const cardNames: Record<string, CreditCardTypeCardBrandId> = {
VISA: "visa",
MASTERCARD: "mastercard",
AMERICAN_EXPRESS: "american-express",
DINERS_CLUB: "diners-club",
DISCOVER: "discover",
JCB: "jcb",
UNIONPAY: "unionpay",
MAESTRO: "maestro",
ELO: "elo",
MIR: "mir",
HIPER: "hiper",
HIPERCARD: "hipercard",
};
const ORIGINAL_TEST_ORDER = [
cardNames.VISA,
cardNames.MASTERCARD,
cardNames.AMERICAN_EXPRESS,
cardNames.DINERS_CLUB,
cardNames.DISCOVER,
cardNames.JCB,
cardNames.UNIONPAY,
cardNames.MAESTRO,
cardNames.ELO,
cardNames.MIR,
cardNames.HIPER,
cardNames.HIPERCARD,
];
let testOrder = clone(ORIGINAL_TEST_ORDER) as string[];
function findType(cardType: string | number): CreditCardType {
return customCards[cardType] || cardTypes[cardType];
}
function getAllCardTypes(): CreditCardType[] {
return testOrder.map(
(cardType) => clone(findType(cardType)) as CreditCardType,
);
}
function getCardPosition(
name: string,
ignoreErrorForNotExisting = false,
): number {
const position = testOrder.indexOf(name);
if (!ignoreErrorForNotExisting && position === -1) {
throw new Error('"' + name + '" is not a supported card type.');
}
return position;
}
function creditCardType(cardNumber: string): Array<CreditCardType> {
const results = [] as CreditCardType[];
if (!isValidInputType(cardNumber)) {
return results;
}
if (cardNumber.length === 0) {
return getAllCardTypes();
}
testOrder.forEach((cardType) => {
const cardConfiguration = findType(cardType);
addMatchingCardsToResults(cardNumber, cardConfiguration, results);
});
const bestMatch = findBestMatch(results) as CreditCardType;
if (bestMatch) {
return [bestMatch];
}
return results;
}
creditCardType.getTypeInfo = (cardType: string): CreditCardType =>
clone(findType(cardType)) as CreditCardType;
creditCardType.removeCard = (name: string): void => {
const position = getCardPosition(name);
testOrder.splice(position, 1);
};
creditCardType.addCard = (config: CreditCardType): void => {
const existingCardPosition = getCardPosition(config.type, true);
customCards[config.type] = config;
if (existingCardPosition === -1) {
testOrder.push(config.type);
}
};
creditCardType.updateCard = (
cardType: string,
updates: Partial<CreditCardType>,
): void => {
const originalObject = customCards[cardType] || cardTypes[cardType];
if (!originalObject) {
throw new Error(
`"${cardType}" is not a recognized type. Use \`addCard\` instead.'`,
);
}
if (updates.type && originalObject.type !== updates.type) {
throw new Error("Cannot overwrite type parameter.");
}
let clonedCard = clone(originalObject) as CreditCardType;
clonedCard = { ...clonedCard, ...updates };
customCards[clonedCard.type] = clonedCard;
};
creditCardType.changeOrder = (name: string, position: number): void => {
const currentPosition = getCardPosition(name);
testOrder.splice(currentPosition, 1);
testOrder.splice(position, 0, name);
};
creditCardType.resetModifications = (): void => {
testOrder = clone(ORIGINAL_TEST_ORDER) as string[];
customCards = {};
};
creditCardType.types = cardNames;
export = creditCardType;