Coding Test: Validate Cards
// --- UTILS ------------------------------------------------
// pipe :: ...Functions => a -> b
const pipe = (...funcs) => data =>
funcs.reduce((acc, func) => func(acc), data);
// toNumber :: String -> Number
const toNumber = data => parseInt(data, 10);
// double :: Number -> Number
const double = data => data * 2;
// --- `validateCards` LIB -----------------------------------
// Implements a Luhn check for the given card
// isCardValid :: String -> Boolean
const isCardValid = card => {
let cardSum =
card
.slice(0, -1)
.split('')
.map(pipe(toNumber, double))
.reduce((acc, value) => acc += value, 0);
let checkDigit = toNumber(card.slice(-1));
// Luhn check to match the `checkDigit`
return ((cardSum % 10) === checkDigit);
};
// isCardAllowed :: Array => String -> Boolean
const isCardAllowed = blacklist => card =>
!blacklist.some((x) => card.startsWith(x));
// --- MAIN -----------------------------------
// TODO: If no other part of the application were performing
// type checking on these parameters, we would need to
// detect incorrect types and mark results as invalid with
// the passed in data
// validateCards :: (Array<String>, Array<String>) -> Array<Object>
const validateCards = (bannedPrefixes, cardsToValidate) =>
cardsToValidate
.map((card) => ({
card,
isValid: isCardValid(card),
isAllowed: isCardAllowed(bannedPrefixes)(card),
}));