3 var safe = require('safe-regex');
4 var define = require('define-property');
5 var extend = require('extend-shallow');
6 var not = require('regex-not');
7 var MAX_LENGTH = 1024 * 64;
16 * Create a regular expression from the given `pattern` string.
18 * @param {String|RegExp} `pattern` Pattern can be a string or regular expression.
19 * @param {Object} `options`
24 module.exports = function(patterns, options) {
25 if (!Array.isArray(patterns)) {
26 return makeRe(patterns, options);
28 return makeRe(patterns.join('|'), options);
32 * Create a regular expression from the given `pattern` string.
34 * @param {String|RegExp} `pattern` Pattern can be a string or regular expression.
35 * @param {Object} `options`
40 function makeRe(pattern, options) {
41 if (pattern instanceof RegExp) {
45 if (typeof pattern !== 'string') {
46 throw new TypeError('expected a string');
49 if (pattern.length > MAX_LENGTH) {
50 throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters');
54 // do this before shallow cloning options, it's a lot faster
55 if (!options || (options && options.cache !== false)) {
56 key = createKey(pattern, options);
58 if (cache.hasOwnProperty(key)) {
63 var opts = extend({}, options);
64 if (opts.contains === true) {
65 if (opts.negate === true) {
66 opts.strictNegate = false;
72 if (opts.strict === false) {
73 opts.strictOpen = false;
74 opts.strictClose = false;
77 var open = opts.strictOpen !== false ? '^' : '';
78 var close = opts.strictClose !== false ? '$' : '';
79 var flags = opts.flags || '';
82 if (opts.nocase === true && !/i/.test(flags)) {
87 if (opts.negate || typeof opts.strictNegate === 'boolean') {
88 pattern = not.create(pattern, opts);
91 var str = open + '(?:' + pattern + ')' + close;
92 regex = new RegExp(str, flags);
94 if (opts.safe === true && safe(regex) === false) {
95 throw new Error('potentially unsafe regular expression: ' + regex.source);
99 if (opts.strictErrors === true || opts.safe === true) {
101 err.pattern = pattern;
102 err.originalOptions = options;
103 err.createdOptions = opts;
108 regex = new RegExp('^' + pattern.replace(/(\W)/g, '\\$1') + '$');
110 regex = /.^/; //<= match nothing
114 if (opts.cache !== false) {
115 memoize(regex, key, pattern, opts);
121 * Memoize generated regex. This can result in dramatic speed improvements
122 * and simplify debugging by adding options and pattern to the regex. It can be
123 * disabled by passing setting `options.cache` to false.
126 function memoize(regex, key, pattern, options) {
127 define(regex, 'cached', true);
128 define(regex, 'pattern', pattern);
129 define(regex, 'options', options);
130 define(regex, 'key', key);
135 * Create the key to use for memoization. The key is generated
136 * by iterating over the options and concatenating key-value pairs
137 * to the pattern string.
140 function createKey(pattern, options) {
141 if (!options) return pattern;
143 for (var prop in options) {
144 if (options.hasOwnProperty(prop)) {
145 key += ';' + prop + '=' + String(options[prop]);
155 module.exports.makeRe = makeRe;