diff --git a/src/parser/utils.ts b/src/parser/utils.ts index a404eb4b..2e383991 100644 --- a/src/parser/utils.ts +++ b/src/parser/utils.ts @@ -1,65 +1,44 @@ -const map = new WeakMap(); +const TypedArrayPrototypeGetSymbolToStringTag = (() => { + // Type check system lovingly referenced from: + // https://github.com/nodejs/node/blob/7450332339ed40481f470df2a3014e2ec355d8d8/lib/internal/util/types.js#L13-L15 + // eslint-disable-next-line @typescript-eslint/unbound-method -- the intention is to call this method with a bound value + const g = Object.getOwnPropertyDescriptor( + Object.getPrototypeOf(Uint8Array.prototype), + Symbol.toStringTag + )!.get!; -const TYPES = { - ArrayBuffer: '[object ArrayBuffer]', - SharedArrayBuffer: '[object SharedArrayBuffer]', - Uint8Array: '[object Uint8Array]', - BigInt64Array: '[object BigInt64Array]', - BigUint64Array: '[object BigUint64Array]', - RegExp: '[object RegExp]', - Map: '[object Map]', - Date: '[object Date]' -}; - -/** - * Retrieves the prototype.toString() of a value. - * If the value is an object, it will cache the result in a WeakMap for future use. - */ -function getPrototypeString(value: unknown): string { - let str = map.get(value as object); - - if (!str) { - str = Object.prototype.toString.call(value); - if (value !== null && typeof value === 'object') { - map.set(value, str); - } - } - return str; -} - -export function isAnyArrayBuffer(value: unknown): value is ArrayBuffer { - const type = getPrototypeString(value); - return type === TYPES.ArrayBuffer || type === TYPES.SharedArrayBuffer; -} + return (value: unknown) => g.call(value); +})(); export function isUint8Array(value: unknown): value is Uint8Array { - const type = getPrototypeString(value); - return type === TYPES.Uint8Array; + return TypedArrayPrototypeGetSymbolToStringTag(value) === 'Uint8Array'; } -export function isBigInt64Array(value: unknown): value is BigInt64Array { - const type = getPrototypeString(value); - return type === TYPES.BigInt64Array; -} - -export function isBigUInt64Array(value: unknown): value is BigUint64Array { - const type = getPrototypeString(value); - return type === TYPES.BigUint64Array; +export function isAnyArrayBuffer(value: unknown): value is ArrayBuffer { + return ( + typeof value === 'object' && + value != null && + Symbol.toStringTag in value && + (value[Symbol.toStringTag] === 'ArrayBuffer' || + value[Symbol.toStringTag] === 'SharedArrayBuffer') + ); } -export function isRegExp(d: unknown): d is RegExp { - const type = getPrototypeString(d); - return type === TYPES.RegExp; +export function isRegExp(regexp: unknown): regexp is RegExp { + return regexp instanceof RegExp || Object.prototype.toString.call(regexp) === '[object RegExp]'; } -export function isMap(d: unknown): d is Map { - const type = getPrototypeString(d); - return type === TYPES.Map; +export function isMap(value: unknown): value is Map { + return ( + typeof value === 'object' && + value != null && + Symbol.toStringTag in value && + value[Symbol.toStringTag] === 'Map' + ); } -export function isDate(d: unknown): d is Date { - const type = getPrototypeString(d); - return type === TYPES.Date; +export function isDate(date: unknown): date is Date { + return date instanceof Date || Object.prototype.toString.call(date) === '[object Date]'; } export type InspectFn = (x: unknown, options?: unknown) => string;