var DESCRIPTORS = require('../internals/descriptors'); var global = require('../internals/global'); var uncurryThis = require('../internals/function-uncurry-this'); var isForced = require('../internals/is-forced'); var inheritIfRequired = require('../internals/inherit-if-required'); var createNonEnumerableProperty = require('../internals/create-non-enumerable-property'); var getOwnPropertyNames = require('../internals/object-get-own-property-names').f; var isPrototypeOf = require('../internals/object-is-prototype-of'); var isRegExp = require('../internals/is-regexp'); var toString = require('../internals/to-string'); var getRegExpFlags = require('../internals/regexp-get-flags'); var stickyHelpers = require('../internals/regexp-sticky-helpers'); var proxyAccessor = require('../internals/proxy-accessor'); var defineBuiltIn = require('../internals/define-built-in'); var fails = require('../internals/fails'); var hasOwn = require('../internals/has-own-property'); var enforceInternalState = require('../internals/internal-state').enforce; var setSpecies = require('../internals/set-species'); var wellKnownSymbol = require('../internals/well-known-symbol'); var UNSUPPORTED_DOT_ALL = require('../internals/regexp-unsupported-dot-all'); var UNSUPPORTED_NCG = require('../internals/regexp-unsupported-ncg'); var MATCH = wellKnownSymbol('match'); var NativeRegExp = global.RegExp; var RegExpPrototype = NativeRegExp.prototype; var SyntaxError = global.SyntaxError; var exec = uncurryThis(RegExpPrototype.exec); var charAt = uncurryThis(''.charAt); var replace = uncurryThis(''.replace); var stringIndexOf = uncurryThis(''.indexOf); var stringSlice = uncurryThis(''.slice); // TODO: Use only proper RegExpIdentifierName var IS_NCG = /^\?<[^\s\d!#%&*+<=>@^][^\s!#%&*+<=>@^]*>/; var re1 = /a/g; var re2 = /a/g; // "new" should create a new object, old webkit bug var CORRECT_NEW = new NativeRegExp(re1) !== re1; var MISSED_STICKY = stickyHelpers.MISSED_STICKY; var UNSUPPORTED_Y = stickyHelpers.UNSUPPORTED_Y; var BASE_FORCED = DESCRIPTORS && (!CORRECT_NEW || MISSED_STICKY || UNSUPPORTED_DOT_ALL || UNSUPPORTED_NCG || fails(function () { re2[MATCH] = false; // RegExp constructor can alter flags and IsRegExp works correct with @@match return NativeRegExp(re1) != re1 || NativeRegExp(re2) == re2 || NativeRegExp(re1, 'i') != '/a/i'; })); var handleDotAll = function (string) { var length = string.length; var index = 0; var result = ''; var brackets = false; var chr; for (; index <= length; index++) { chr = charAt(string, index); if (chr === '\\') { result += chr + charAt(string, ++index); continue; } if (!brackets && chr === '.') { result += '[\\s\\S]'; } else { if (chr === '[') { brackets = true; } else if (chr === ']') { brackets = false; } result += chr; } } return result; }; var handleNCG = function (string) { var length = string.length; var index = 0; var result = ''; var named = []; var names = {}; var brackets = false; var ncg = false; var groupid = 0; var groupname = ''; var chr; for (; index <= length; index++) { chr = charAt(string, index); if (chr === '\\') { chr = chr + charAt(string, ++index); } else if (chr === ']') { brackets = false; } else if (!brackets) switch (true) { case chr === '[': brackets = true; break; case chr === '(': if (exec(IS_NCG, stringSlice(string, index + 1))) { index += 2; ncg = true; } result += chr; groupid++; continue; case chr === '>' && ncg: if (groupname === '' || hasOwn(names, groupname)) { throw new SyntaxError('Invalid capture group name'); } names[groupname] = true; named[named.length] = [groupname, groupid]; ncg = false; groupname = ''; continue; } if (ncg) groupname += chr; else result += chr; } return [result, named]; }; // `RegExp` constructor // https://tc39.es/ecma262/#sec-regexp-constructor if (isForced('RegExp', BASE_FORCED)) { var RegExpWrapper = function RegExp(pattern, flags) { var thisIsRegExp = isPrototypeOf(RegExpPrototype, this); var patternIsRegExp = isRegExp(pattern); var flagsAreUndefined = flags === undefined; var groups = []; var rawPattern = pattern; var rawFlags, dotAll, sticky, handled, result, state; if (!thisIsRegExp && patternIsRegExp && flagsAreUndefined && pattern.constructor === RegExpWrapper) { return pattern; } if (patternIsRegExp || isPrototypeOf(RegExpPrototype, pattern)) { pattern = pattern.source; if (flagsAreUndefined) flags = getRegExpFlags(rawPattern); } pattern = pattern === undefined ? '' : toString(pattern); flags = flags === undefined ? '' : toString(flags); rawPattern = pattern; if (UNSUPPORTED_DOT_ALL && 'dotAll' in re1) { dotAll = !!flags && stringIndexOf(flags, 's') > -1; if (dotAll) flags = replace(flags, /s/g, ''); } rawFlags = flags; if (MISSED_STICKY && 'sticky' in re1) { sticky = !!flags && stringIndexOf(flags, 'y') > -1; if (sticky && UNSUPPORTED_Y) flags = replace(flags, /y/g, ''); } if (UNSUPPORTED_NCG) { handled = handleNCG(pattern); pattern = handled[0]; groups = handled[1]; } result = inheritIfRequired(NativeRegExp(pattern, flags), thisIsRegExp ? this : RegExpPrototype, RegExpWrapper); if (dotAll || sticky || groups.length) { state = enforceInternalState(result); if (dotAll) { state.dotAll = true; state.raw = RegExpWrapper(handleDotAll(pattern), rawFlags); } if (sticky) state.sticky = true; if (groups.length) state.groups = groups; } if (pattern !== rawPattern) try { // fails in old engines, but we have no alternatives for unsupported regex syntax createNonEnumerableProperty(result, 'source', rawPattern === '' ? '(?:)' : rawPattern); } catch (error) { /* empty */ } return result; }; for (var keys = getOwnPropertyNames(NativeRegExp), index = 0; keys.length > index;) { proxyAccessor(RegExpWrapper, NativeRegExp, keys[index++]); } RegExpPrototype.constructor = RegExpWrapper; RegExpWrapper.prototype = RegExpPrototype; defineBuiltIn(global, 'RegExp', RegExpWrapper, { constructor: true }); } // https://tc39.es/ecma262/#sec-get-regexp-@@species setSpecies('RegExp');