CharSet.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. 'use strict';
  2. var $TypeError = require('es-errors/type');
  3. var GetIntrinsic = require('get-intrinsic');
  4. var callBound = require('call-bound');
  5. var hasOwn = require('hasown');
  6. var caseFolding = require('./caseFolding.json');
  7. var IsArray = require('./IsArray');
  8. var isLeadingSurrogate = require('./isLeadingSurrogate');
  9. var isTrailingSurrogate = require('./isTrailingSurrogate');
  10. var $charCodeAt = callBound('%String.prototype.charCodeAt%');
  11. var $fromCharCode = GetIntrinsic('%String.fromCharCode%');
  12. /* eslint func-style: 0 */
  13. function CharSet(test, yieldCh) {
  14. if (typeof test !== 'function') {
  15. throw new $TypeError('Assertion failed: `test` must be a function');
  16. }
  17. if (typeof yieldCh !== 'function') {
  18. throw new $TypeError('Assertion failed: `yield` must be a function');
  19. }
  20. this.test = test;
  21. this.yield = yieldCh;
  22. }
  23. CharSet.prototype.count = function () {
  24. var count = 0;
  25. this.yield(function () { count += 1; });
  26. return count;
  27. };
  28. function testCodeUnits(CharSetElement) {
  29. if (typeof CharSetElement !== 'string') {
  30. throw new $TypeError('Assertion failed: `CharSetElement` must be a string');
  31. }
  32. return CharSetElement.length !== 1;
  33. }
  34. function yieldCodeUnits(emit) {
  35. for (var i = 0; i <= 0xDFFF; i += 1) {
  36. emit($fromCharCode(i));
  37. }
  38. }
  39. function testCodePoints(CharSetElement) {
  40. if (typeof CharSetElement !== 'string') {
  41. throw new $TypeError('Assertion failed: `CharSetElement` must be a string');
  42. }
  43. if (CharSetElement.length === 1) {
  44. return true;
  45. }
  46. if (CharSetElement.length === 2) {
  47. var hi = $charCodeAt(CharSetElement, 0);
  48. var lo = $charCodeAt(CharSetElement, 1);
  49. return isLeadingSurrogate(hi) && isTrailingSurrogate(lo);
  50. }
  51. return false;
  52. }
  53. function yieldCodePoints(emit) {
  54. for (var i = 0; i <= 0xDFFF; i += 1) {
  55. emit($fromCharCode(i));
  56. }
  57. for (var u = 0x10000; u <= 0x10FFFF; u += 1) {
  58. var cp = u - 0x10000;
  59. var high = (cp >> 10) + 0xD800;
  60. var low = (cp & 0x3FF) + 0xDC00;
  61. emit($fromCharCode(high, low));
  62. }
  63. }
  64. function charsToMap(chars) {
  65. if (!IsArray(chars)) {
  66. throw new $TypeError('Assertion failed: `chars` must be an array');
  67. }
  68. var map = { __proto__: null };
  69. for (var i = 0; i < chars.length; i += 1) {
  70. var char = chars[i];
  71. if (typeof char !== 'string' || (char.length !== 1 && char.length !== 2)) {
  72. throw new $TypeError('Assertion failed: `chars` must be an array of strings of length 1');
  73. }
  74. map[char] = true;
  75. }
  76. return map;
  77. }
  78. module.exports = {
  79. CharSet: CharSet,
  80. from: function from(chars) {
  81. var map = charsToMap(chars);
  82. return new CharSet(
  83. function test(CharSetElement) {
  84. return hasOwn(map, CharSetElement);
  85. },
  86. function yieldChar(emit) {
  87. // eslint-disable-next-line no-restricted-syntax
  88. for (var k in map) {
  89. if (hasOwn(map, k)) {
  90. emit(k);
  91. }
  92. }
  93. }
  94. );
  95. },
  96. getCodeUnits: function () {
  97. return new CharSet(testCodeUnits, yieldCodeUnits);
  98. },
  99. getCodePoints: function () {
  100. return new CharSet(testCodePoints, yieldCodePoints);
  101. },
  102. getNonSimpleCaseFoldingCodePoints: function () {
  103. return new CharSet(
  104. function test(CharSetElement) {
  105. return testCodePoints(CharSetElement) && !hasOwn(caseFolding.S, CharSetElement);
  106. },
  107. function yieldChar(emit) {
  108. yieldCodePoints(function (CharSetElement) {
  109. if (!hasOwn(caseFolding.S, CharSetElement)) {
  110. emit(CharSetElement);
  111. }
  112. });
  113. }
  114. );
  115. }
  116. };