UNPKG

luhn-generator

Version:

A generator of numbers that passes the validation of Luhn algorithm or Luhn formula, also known as the 'modulus 10' or 'mod 10' algorithm

156 lines (128 loc) 3.64 kB
'use strict'; var safe = require('safe-regex'); var define = require('define-property'); var extend = require('extend-shallow'); var not = require('regex-not'); var MAX_LENGTH = 1024 * 64; /** * Session cache */ var cache = {}; /** * Create a regular expression from the given `pattern` string. * * @param {String|RegExp} `pattern` Pattern can be a string or regular expression. * @param {Object} `options` * @return {RegExp} * @api public */ module.exports = function(patterns, options) { if (!Array.isArray(patterns)) { return makeRe(patterns, options); } return makeRe(patterns.join('|'), options); }; /** * Create a regular expression from the given `pattern` string. * * @param {String|RegExp} `pattern` Pattern can be a string or regular expression. * @param {Object} `options` * @return {RegExp} * @api public */ function makeRe(pattern, options) { if (pattern instanceof RegExp) { return pattern; } if (typeof pattern !== 'string') { throw new TypeError('expected a string'); } if (pattern.length > MAX_LENGTH) { throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); } var key = pattern; // do this before shallow cloning options, it's a lot faster if (!options || (options && options.cache !== false)) { key = createKey(pattern, options); if (cache.hasOwnProperty(key)) { return cache[key]; } } var opts = extend({}, options); if (opts.contains === true) { if (opts.negate === true) { opts.strictNegate = false; } else { opts.strict = false; } } if (opts.strict === false) { opts.strictOpen = false; opts.strictClose = false; } var open = opts.strictOpen !== false ? '^' : ''; var close = opts.strictClose !== false ? '$' : ''; var flags = opts.flags || ''; var regex; if (opts.nocase === true && !/i/.test(flags)) { flags += 'i'; } try { if (opts.negate || typeof opts.strictNegate === 'boolean') { pattern = not.create(pattern, opts); } var str = open + '(?:' + pattern + ')' + close; regex = new RegExp(str, flags); if (opts.safe === true && safe(regex) === false) { throw new Error('potentially unsafe regular expression: ' + regex.source); } } catch (err) { if (opts.strictErrors === true || opts.safe === true) { err.key = key; err.pattern = pattern; err.originalOptions = options; err.createdOptions = opts; throw err; } try { regex = new RegExp('^' + pattern.replace(/(\W)/g, '\\$1') + '$'); } catch (err) { regex = /.^/; //<= match nothing } } if (opts.cache !== false) { memoize(regex, key, pattern, opts); } return regex; } /** * Memoize generated regex. This can result in dramatic speed improvements * and simplify debugging by adding options and pattern to the regex. It can be * disabled by passing setting `options.cache` to false. */ function memoize(regex, key, pattern, options) { define(regex, 'cached', true); define(regex, 'pattern', pattern); define(regex, 'options', options); define(regex, 'key', key); cache[key] = regex; } /** * Create the key to use for memoization. The key is generated * by iterating over the options and concatenating key-value pairs * to the pattern string. */ function createKey(pattern, options) { if (!options) return pattern; var key = pattern; for (var prop in options) { if (options.hasOwnProperty(prop)) { key += ';' + prop + '=' + String(options[prop]); } } return key; } /** * Expose `makeRe` */ module.exports.makeRe = makeRe;