156 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			156 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| '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;
 |