Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

3 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. 'use strict';
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. /*!
  6. * XRegExp Unicode Base 4.0.0
  7. * <xregexp.com>
  8. * Steven Levithan (c) 2008-2017 MIT License
  9. */
  10. exports.default = function (XRegExp) {
  11. /**
  12. * Adds base support for Unicode matching:
  13. * - Adds syntax `\p{..}` for matching Unicode tokens. Tokens can be inverted using `\P{..}` or
  14. * `\p{^..}`. Token names ignore case, spaces, hyphens, and underscores. You can omit the
  15. * braces for token names that are a single letter (e.g. `\pL` or `PL`).
  16. * - Adds flag A (astral), which enables 21-bit Unicode support.
  17. * - Adds the `XRegExp.addUnicodeData` method used by other addons to provide character data.
  18. *
  19. * Unicode Base relies on externally provided Unicode character data. Official addons are
  20. * available to provide data for Unicode categories, scripts, blocks, and properties.
  21. *
  22. * @requires XRegExp
  23. */
  24. // ==--------------------------==
  25. // Private stuff
  26. // ==--------------------------==
  27. // Storage for Unicode data
  28. var unicode = {};
  29. // Reuse utils
  30. var dec = XRegExp._dec;
  31. var hex = XRegExp._hex;
  32. var pad4 = XRegExp._pad4;
  33. // Generates a token lookup name: lowercase, with hyphens, spaces, and underscores removed
  34. function normalize(name) {
  35. return name.replace(/[- _]+/g, '').toLowerCase();
  36. }
  37. // Gets the decimal code of a literal code unit, \xHH, \uHHHH, or a backslash-escaped literal
  38. function charCode(chr) {
  39. var esc = /^\\[xu](.+)/.exec(chr);
  40. return esc ? dec(esc[1]) : chr.charCodeAt(chr[0] === '\\' ? 1 : 0);
  41. }
  42. // Inverts a list of ordered BMP characters and ranges
  43. function invertBmp(range) {
  44. var output = '';
  45. var lastEnd = -1;
  46. XRegExp.forEach(range, /(\\x..|\\u....|\\?[\s\S])(?:-(\\x..|\\u....|\\?[\s\S]))?/, function (m) {
  47. var start = charCode(m[1]);
  48. if (start > lastEnd + 1) {
  49. output += '\\u' + pad4(hex(lastEnd + 1));
  50. if (start > lastEnd + 2) {
  51. output += '-\\u' + pad4(hex(start - 1));
  52. }
  53. }
  54. lastEnd = charCode(m[2] || m[1]);
  55. });
  56. if (lastEnd < 0xFFFF) {
  57. output += '\\u' + pad4(hex(lastEnd + 1));
  58. if (lastEnd < 0xFFFE) {
  59. output += '-\\uFFFF';
  60. }
  61. }
  62. return output;
  63. }
  64. // Generates an inverted BMP range on first use
  65. function cacheInvertedBmp(slug) {
  66. var prop = 'b!';
  67. return unicode[slug][prop] || (unicode[slug][prop] = invertBmp(unicode[slug].bmp));
  68. }
  69. // Combines and optionally negates BMP and astral data
  70. function buildAstral(slug, isNegated) {
  71. var item = unicode[slug];
  72. var combined = '';
  73. if (item.bmp && !item.isBmpLast) {
  74. combined = '[' + item.bmp + ']' + (item.astral ? '|' : '');
  75. }
  76. if (item.astral) {
  77. combined += item.astral;
  78. }
  79. if (item.isBmpLast && item.bmp) {
  80. combined += (item.astral ? '|' : '') + '[' + item.bmp + ']';
  81. }
  82. // Astral Unicode tokens always match a code point, never a code unit
  83. return isNegated ? '(?:(?!' + combined + ')(?:[\uD800-\uDBFF][\uDC00-\uDFFF]|[\0-\uFFFF]))' : '(?:' + combined + ')';
  84. }
  85. // Builds a complete astral pattern on first use
  86. function cacheAstral(slug, isNegated) {
  87. var prop = isNegated ? 'a!' : 'a=';
  88. return unicode[slug][prop] || (unicode[slug][prop] = buildAstral(slug, isNegated));
  89. }
  90. // ==--------------------------==
  91. // Core functionality
  92. // ==--------------------------==
  93. /*
  94. * Add astral mode (flag A) and Unicode token syntax: `\p{..}`, `\P{..}`, `\p{^..}`, `\pC`.
  95. */
  96. XRegExp.addToken(
  97. // Use `*` instead of `+` to avoid capturing `^` as the token name in `\p{^}`
  98. /\\([pP])(?:{(\^?)([^}]*)}|([A-Za-z]))/, function (match, scope, flags) {
  99. var ERR_DOUBLE_NEG = 'Invalid double negation ';
  100. var ERR_UNKNOWN_NAME = 'Unknown Unicode token ';
  101. var ERR_UNKNOWN_REF = 'Unicode token missing data ';
  102. var ERR_ASTRAL_ONLY = 'Astral mode required for Unicode token ';
  103. var ERR_ASTRAL_IN_CLASS = 'Astral mode does not support Unicode tokens within character classes';
  104. // Negated via \P{..} or \p{^..}
  105. var isNegated = match[1] === 'P' || !!match[2];
  106. // Switch from BMP (0-FFFF) to astral (0-10FFFF) mode via flag A
  107. var isAstralMode = flags.indexOf('A') !== -1;
  108. // Token lookup name. Check `[4]` first to avoid passing `undefined` via `\p{}`
  109. var slug = normalize(match[4] || match[3]);
  110. // Token data object
  111. var item = unicode[slug];
  112. if (match[1] === 'P' && match[2]) {
  113. throw new SyntaxError(ERR_DOUBLE_NEG + match[0]);
  114. }
  115. if (!unicode.hasOwnProperty(slug)) {
  116. throw new SyntaxError(ERR_UNKNOWN_NAME + match[0]);
  117. }
  118. // Switch to the negated form of the referenced Unicode token
  119. if (item.inverseOf) {
  120. slug = normalize(item.inverseOf);
  121. if (!unicode.hasOwnProperty(slug)) {
  122. throw new ReferenceError(ERR_UNKNOWN_REF + match[0] + ' -> ' + item.inverseOf);
  123. }
  124. item = unicode[slug];
  125. isNegated = !isNegated;
  126. }
  127. if (!(item.bmp || isAstralMode)) {
  128. throw new SyntaxError(ERR_ASTRAL_ONLY + match[0]);
  129. }
  130. if (isAstralMode) {
  131. if (scope === 'class') {
  132. throw new SyntaxError(ERR_ASTRAL_IN_CLASS);
  133. }
  134. return cacheAstral(slug, isNegated);
  135. }
  136. return scope === 'class' ? isNegated ? cacheInvertedBmp(slug) : item.bmp : (isNegated ? '[^' : '[') + item.bmp + ']';
  137. }, {
  138. scope: 'all',
  139. optionalFlags: 'A',
  140. leadChar: '\\'
  141. });
  142. /**
  143. * Adds to the list of Unicode tokens that XRegExp regexes can match via `\p` or `\P`.
  144. *
  145. * @memberOf XRegExp
  146. * @param {Array} data Objects with named character ranges. Each object may have properties
  147. * `name`, `alias`, `isBmpLast`, `inverseOf`, `bmp`, and `astral`. All but `name` are
  148. * optional, although one of `bmp` or `astral` is required (unless `inverseOf` is set). If
  149. * `astral` is absent, the `bmp` data is used for BMP and astral modes. If `bmp` is absent,
  150. * the name errors in BMP mode but works in astral mode. If both `bmp` and `astral` are
  151. * provided, the `bmp` data only is used in BMP mode, and the combination of `bmp` and
  152. * `astral` data is used in astral mode. `isBmpLast` is needed when a token matches orphan
  153. * high surrogates *and* uses surrogate pairs to match astral code points. The `bmp` and
  154. * `astral` data should be a combination of literal characters and `\xHH` or `\uHHHH` escape
  155. * sequences, with hyphens to create ranges. Any regex metacharacters in the data should be
  156. * escaped, apart from range-creating hyphens. The `astral` data can additionally use
  157. * character classes and alternation, and should use surrogate pairs to represent astral code
  158. * points. `inverseOf` can be used to avoid duplicating character data if a Unicode token is
  159. * defined as the exact inverse of another token.
  160. * @example
  161. *
  162. * // Basic use
  163. * XRegExp.addUnicodeData([{
  164. * name: 'XDigit',
  165. * alias: 'Hexadecimal',
  166. * bmp: '0-9A-Fa-f'
  167. * }]);
  168. * XRegExp('\\p{XDigit}:\\p{Hexadecimal}+').test('0:3D'); // -> true
  169. */
  170. XRegExp.addUnicodeData = function (data) {
  171. var ERR_NO_NAME = 'Unicode token requires name';
  172. var ERR_NO_DATA = 'Unicode token has no character data ';
  173. var item = void 0;
  174. for (var i = 0; i < data.length; ++i) {
  175. item = data[i];
  176. if (!item.name) {
  177. throw new Error(ERR_NO_NAME);
  178. }
  179. if (!(item.inverseOf || item.bmp || item.astral)) {
  180. throw new Error(ERR_NO_DATA + item.name);
  181. }
  182. unicode[normalize(item.name)] = item;
  183. if (item.alias) {
  184. unicode[normalize(item.alias)] = item;
  185. }
  186. }
  187. // Reset the pattern cache used by the `XRegExp` constructor, since the same pattern and
  188. // flags might now produce different results
  189. XRegExp.cache.flush('patterns');
  190. };
  191. /**
  192. * @ignore
  193. *
  194. * Return a reference to the internal Unicode definition structure for the given Unicode
  195. * Property if the given name is a legal Unicode Property for use in XRegExp `\p` or `\P` regex
  196. * constructs.
  197. *
  198. * @memberOf XRegExp
  199. * @param {String} name Name by which the Unicode Property may be recognized (case-insensitive),
  200. * e.g. `'N'` or `'Number'`. The given name is matched against all registered Unicode
  201. * Properties and Property Aliases.
  202. * @returns {Object} Reference to definition structure when the name matches a Unicode Property.
  203. *
  204. * @note
  205. * For more info on Unicode Properties, see also http://unicode.org/reports/tr18/#Categories.
  206. *
  207. * @note
  208. * This method is *not* part of the officially documented API and may change or be removed in
  209. * the future. It is meant for userland code that wishes to reuse the (large) internal Unicode
  210. * structures set up by XRegExp.
  211. */
  212. XRegExp._getUnicodeProperty = function (name) {
  213. var slug = normalize(name);
  214. return unicode[slug];
  215. };
  216. };
  217. module.exports = exports['default'];