2018-03-25 18:03:08 +00:00
|
|
|
// License: LGPL-3.0-or-later
|
2018-03-25 17:30:42 +00:00
|
|
|
const R = require('ramda')
|
|
|
|
|
|
|
|
// Reference: https://en.wikipedia.org/wiki/Luhn_algorithm
|
|
|
|
|
|
|
|
module.exports = val => {
|
|
|
|
val = val.replace(/[-\s]/g, '')
|
|
|
|
return val.match(/^[0-9-\s]+$/) && luhnCheck(val)
|
|
|
|
}
|
|
|
|
|
|
|
|
const luhnCheck =
|
|
|
|
R.compose(
|
|
|
|
R.equals(0)
|
|
|
|
, R.modulo(R.__, 10)
|
|
|
|
, R.sum
|
|
|
|
, R.map(n => n > 9 ? n - 9 : n) // Subtract 9 from those digits greater than 9
|
|
|
|
, R.addIndex(R.map)((n, i) => i % 2 === 0 ? n : n * 2) // Double the value of every second digit
|
|
|
|
, R.map(ch => Number(ch))
|
|
|
|
, R.reverse)
|
|
|
|
|
|
|
|
/*
|
|
|
|
Luhn check in haskell:
|
|
|
|
luhn = (0 ==) . (`mod` 10) . sum . map (uncurry (+) . (`divMod` 10)) .
|
|
|
|
zipWith (*) (cycle [1,2]) . map digitToInt . reverse
|
|
|
|
*/
|