123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- '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;
|