index.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. 'use strict';
  2. var forEach = require('for-each');
  3. var availableTypedArrays = require('available-typed-arrays');
  4. var callBind = require('call-bind');
  5. var callBound = require('call-bind/callBound');
  6. var gOPD = require('gopd');
  7. var $toString = callBound('Object.prototype.toString');
  8. var hasToStringTag = require('has-tostringtag/shams')();
  9. var g = typeof globalThis === 'undefined' ? global : globalThis;
  10. var typedArrays = availableTypedArrays();
  11. var $slice = callBound('String.prototype.slice');
  12. var getPrototypeOf = Object.getPrototypeOf; // require('getprototypeof');
  13. var $indexOf = callBound('Array.prototype.indexOf', true) || /** @type {(array: readonly unknown[], value: unknown) => keyof array} */ function indexOf(array, value) {
  14. for (var i = 0; i < array.length; i += 1) {
  15. if (array[i] === value) {
  16. return i;
  17. }
  18. }
  19. return -1;
  20. };
  21. /** @typedef {Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array} TypedArray */
  22. /** @typedef {'Int8Array' | 'Uint8Array' | 'Uint8ClampedArray' | 'Int16Array' | 'Uint16Array' | 'Int32Array' | 'Uint32Array' | 'Float32Array' | 'Float64Array' | 'BigInt64Array' | 'BigUint64Array'} TypedArrayName */
  23. /** @type {{ [k in `\$${TypedArrayName}`]?: (receiver: TypedArray) => string | typeof Uint8Array.prototype.slice.call | typeof Uint8Array.prototype.set.call } & { __proto__: null }} */
  24. var cache = { __proto__: null };
  25. if (hasToStringTag && gOPD && getPrototypeOf) {
  26. forEach(typedArrays, function (typedArray) {
  27. var arr = new g[typedArray]();
  28. if (Symbol.toStringTag in arr) {
  29. var proto = getPrototypeOf(arr);
  30. // @ts-expect-error TS won't narrow inside a closure
  31. var descriptor = gOPD(proto, Symbol.toStringTag);
  32. if (!descriptor) {
  33. var superProto = getPrototypeOf(proto);
  34. // @ts-expect-error TS won't narrow inside a closure
  35. descriptor = gOPD(superProto, Symbol.toStringTag);
  36. }
  37. // @ts-expect-error TODO: fix
  38. cache['$' + typedArray] = callBind(descriptor.get);
  39. }
  40. });
  41. } else {
  42. forEach(typedArrays, function (typedArray) {
  43. var arr = new g[typedArray]();
  44. var fn = arr.slice || arr.set;
  45. if (fn) {
  46. // @ts-expect-error TODO: fix
  47. cache['$' + typedArray] = callBind(fn);
  48. }
  49. });
  50. }
  51. /** @type {import('.')} */
  52. var tryTypedArrays = function tryAllTypedArrays(value) {
  53. /** @type {ReturnType<tryAllTypedArrays>} */ var found = false;
  54. forEach(
  55. // eslint-disable-next-line no-extra-parens
  56. /** @type {Record<`\$${TypedArrayName}`, typeof cache>} */ /** @type {any} */ (cache),
  57. /** @type {(getter: typeof cache, name: `\$${TypedArrayName}`) => void} */ function (getter, typedArray) {
  58. if (!found) {
  59. try {
  60. // @ts-expect-error TODO: fix
  61. if ('$' + getter(value) === typedArray) {
  62. found = $slice(typedArray, 1);
  63. }
  64. } catch (e) { /**/ }
  65. }
  66. }
  67. );
  68. return found;
  69. };
  70. /** @type {import('.')} */
  71. var trySlices = function tryAllSlices(value) {
  72. /** @type {ReturnType<tryAllSlices>} */ var found = false;
  73. forEach(
  74. // eslint-disable-next-line no-extra-parens
  75. /** @type {any} */ (cache),
  76. /** @type {(getter: typeof cache, name: `\$${TypedArrayName}`) => void} */ function (getter, name) {
  77. if (!found) {
  78. try {
  79. // @ts-expect-error TODO: fix
  80. getter(value);
  81. found = $slice(name, 1);
  82. } catch (e) { /**/ }
  83. }
  84. }
  85. );
  86. return found;
  87. };
  88. /** @type {import('.')} */
  89. module.exports = function whichTypedArray(value) {
  90. if (!value || typeof value !== 'object') { return false; }
  91. if (!hasToStringTag) {
  92. var tag = $slice($toString(value), 8, -1);
  93. if ($indexOf(typedArrays, tag) > -1) {
  94. return tag;
  95. }
  96. if (tag !== 'Object') {
  97. return false;
  98. }
  99. // node < 0.6 hits here on real Typed Arrays
  100. return trySlices(value);
  101. }
  102. if (!gOPD) { return null; } // unknown engine
  103. return tryTypedArrays(value);
  104. };