es.regexp.constructor.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. var DESCRIPTORS = require('../internals/descriptors');
  2. var global = require('../internals/global');
  3. var uncurryThis = require('../internals/function-uncurry-this');
  4. var isForced = require('../internals/is-forced');
  5. var inheritIfRequired = require('../internals/inherit-if-required');
  6. var createNonEnumerableProperty = require('../internals/create-non-enumerable-property');
  7. var getOwnPropertyNames = require('../internals/object-get-own-property-names').f;
  8. var isPrototypeOf = require('../internals/object-is-prototype-of');
  9. var isRegExp = require('../internals/is-regexp');
  10. var toString = require('../internals/to-string');
  11. var getRegExpFlags = require('../internals/regexp-get-flags');
  12. var stickyHelpers = require('../internals/regexp-sticky-helpers');
  13. var proxyAccessor = require('../internals/proxy-accessor');
  14. var defineBuiltIn = require('../internals/define-built-in');
  15. var fails = require('../internals/fails');
  16. var hasOwn = require('../internals/has-own-property');
  17. var enforceInternalState = require('../internals/internal-state').enforce;
  18. var setSpecies = require('../internals/set-species');
  19. var wellKnownSymbol = require('../internals/well-known-symbol');
  20. var UNSUPPORTED_DOT_ALL = require('../internals/regexp-unsupported-dot-all');
  21. var UNSUPPORTED_NCG = require('../internals/regexp-unsupported-ncg');
  22. var MATCH = wellKnownSymbol('match');
  23. var NativeRegExp = global.RegExp;
  24. var RegExpPrototype = NativeRegExp.prototype;
  25. var SyntaxError = global.SyntaxError;
  26. var exec = uncurryThis(RegExpPrototype.exec);
  27. var charAt = uncurryThis(''.charAt);
  28. var replace = uncurryThis(''.replace);
  29. var stringIndexOf = uncurryThis(''.indexOf);
  30. var stringSlice = uncurryThis(''.slice);
  31. // TODO: Use only proper RegExpIdentifierName
  32. var IS_NCG = /^\?<[^\s\d!#%&*+<=>@^][^\s!#%&*+<=>@^]*>/;
  33. var re1 = /a/g;
  34. var re2 = /a/g;
  35. // "new" should create a new object, old webkit bug
  36. var CORRECT_NEW = new NativeRegExp(re1) !== re1;
  37. var MISSED_STICKY = stickyHelpers.MISSED_STICKY;
  38. var UNSUPPORTED_Y = stickyHelpers.UNSUPPORTED_Y;
  39. var BASE_FORCED = DESCRIPTORS &&
  40. (!CORRECT_NEW || MISSED_STICKY || UNSUPPORTED_DOT_ALL || UNSUPPORTED_NCG || fails(function () {
  41. re2[MATCH] = false;
  42. // RegExp constructor can alter flags and IsRegExp works correct with @@match
  43. return NativeRegExp(re1) != re1 || NativeRegExp(re2) == re2 || NativeRegExp(re1, 'i') != '/a/i';
  44. }));
  45. var handleDotAll = function (string) {
  46. var length = string.length;
  47. var index = 0;
  48. var result = '';
  49. var brackets = false;
  50. var chr;
  51. for (; index <= length; index++) {
  52. chr = charAt(string, index);
  53. if (chr === '\\') {
  54. result += chr + charAt(string, ++index);
  55. continue;
  56. }
  57. if (!brackets && chr === '.') {
  58. result += '[\\s\\S]';
  59. } else {
  60. if (chr === '[') {
  61. brackets = true;
  62. } else if (chr === ']') {
  63. brackets = false;
  64. } result += chr;
  65. }
  66. } return result;
  67. };
  68. var handleNCG = function (string) {
  69. var length = string.length;
  70. var index = 0;
  71. var result = '';
  72. var named = [];
  73. var names = {};
  74. var brackets = false;
  75. var ncg = false;
  76. var groupid = 0;
  77. var groupname = '';
  78. var chr;
  79. for (; index <= length; index++) {
  80. chr = charAt(string, index);
  81. if (chr === '\\') {
  82. chr = chr + charAt(string, ++index);
  83. } else if (chr === ']') {
  84. brackets = false;
  85. } else if (!brackets) switch (true) {
  86. case chr === '[':
  87. brackets = true;
  88. break;
  89. case chr === '(':
  90. if (exec(IS_NCG, stringSlice(string, index + 1))) {
  91. index += 2;
  92. ncg = true;
  93. }
  94. result += chr;
  95. groupid++;
  96. continue;
  97. case chr === '>' && ncg:
  98. if (groupname === '' || hasOwn(names, groupname)) {
  99. throw new SyntaxError('Invalid capture group name');
  100. }
  101. names[groupname] = true;
  102. named[named.length] = [groupname, groupid];
  103. ncg = false;
  104. groupname = '';
  105. continue;
  106. }
  107. if (ncg) groupname += chr;
  108. else result += chr;
  109. } return [result, named];
  110. };
  111. // `RegExp` constructor
  112. // https://tc39.es/ecma262/#sec-regexp-constructor
  113. if (isForced('RegExp', BASE_FORCED)) {
  114. var RegExpWrapper = function RegExp(pattern, flags) {
  115. var thisIsRegExp = isPrototypeOf(RegExpPrototype, this);
  116. var patternIsRegExp = isRegExp(pattern);
  117. var flagsAreUndefined = flags === undefined;
  118. var groups = [];
  119. var rawPattern = pattern;
  120. var rawFlags, dotAll, sticky, handled, result, state;
  121. if (!thisIsRegExp && patternIsRegExp && flagsAreUndefined && pattern.constructor === RegExpWrapper) {
  122. return pattern;
  123. }
  124. if (patternIsRegExp || isPrototypeOf(RegExpPrototype, pattern)) {
  125. pattern = pattern.source;
  126. if (flagsAreUndefined) flags = getRegExpFlags(rawPattern);
  127. }
  128. pattern = pattern === undefined ? '' : toString(pattern);
  129. flags = flags === undefined ? '' : toString(flags);
  130. rawPattern = pattern;
  131. if (UNSUPPORTED_DOT_ALL && 'dotAll' in re1) {
  132. dotAll = !!flags && stringIndexOf(flags, 's') > -1;
  133. if (dotAll) flags = replace(flags, /s/g, '');
  134. }
  135. rawFlags = flags;
  136. if (MISSED_STICKY && 'sticky' in re1) {
  137. sticky = !!flags && stringIndexOf(flags, 'y') > -1;
  138. if (sticky && UNSUPPORTED_Y) flags = replace(flags, /y/g, '');
  139. }
  140. if (UNSUPPORTED_NCG) {
  141. handled = handleNCG(pattern);
  142. pattern = handled[0];
  143. groups = handled[1];
  144. }
  145. result = inheritIfRequired(NativeRegExp(pattern, flags), thisIsRegExp ? this : RegExpPrototype, RegExpWrapper);
  146. if (dotAll || sticky || groups.length) {
  147. state = enforceInternalState(result);
  148. if (dotAll) {
  149. state.dotAll = true;
  150. state.raw = RegExpWrapper(handleDotAll(pattern), rawFlags);
  151. }
  152. if (sticky) state.sticky = true;
  153. if (groups.length) state.groups = groups;
  154. }
  155. if (pattern !== rawPattern) try {
  156. // fails in old engines, but we have no alternatives for unsupported regex syntax
  157. createNonEnumerableProperty(result, 'source', rawPattern === '' ? '(?:)' : rawPattern);
  158. } catch (error) { /* empty */ }
  159. return result;
  160. };
  161. for (var keys = getOwnPropertyNames(NativeRegExp), index = 0; keys.length > index;) {
  162. proxyAccessor(RegExpWrapper, NativeRegExp, keys[index++]);
  163. }
  164. RegExpPrototype.constructor = RegExpWrapper;
  165. RegExpWrapper.prototype = RegExpPrototype;
  166. defineBuiltIn(global, 'RegExp', RegExpWrapper, { constructor: true });
  167. }
  168. // https://tc39.es/ecma262/#sec-get-regexp-@@species
  169. setSpecies('RegExp');