rjhilgefort
7/17/2017 - 10:11 PM

Coding Test: Validate Cards

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),
    }));