index.js 3.6 KB

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