UNPKG

typia

Version:

Superfast runtime validators with only one line

162 lines (151 loc) • 5.31 kB
export const _isUniqueItems = (elements: any[]): boolean => { for (let i = 0; i < elements.length; i++) for (let j = i + 1; j < elements.length; j++) if (equals(new WeakMap())(elements[i], elements[j])) return false; return true; }; const equals = (visited: WeakMap<object, WeakMap<object, boolean>>) => { const next = (a: any, b: any): boolean => { if (a === b) return true; if ( a === null || b === null || typeof a !== "object" || typeof b !== "object" ) return false; const previous: boolean | undefined = visited.get(a)?.get(b); if (previous !== undefined) return previous; const pairs: WeakMap<object, boolean> = visited.get(a) ?? new WeakMap<object, boolean>(); visited.set(a, pairs); pairs.set(b, true); const result: boolean = compare(a, b); pairs.set(b, result); return result; }; const compare = (a: object, b: object): boolean => { if (Array.isArray(a)) { if (!Array.isArray(b) || a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { const aHas: boolean = Object.hasOwn(a, i); if (aHas !== Object.hasOwn(b, i) || (aHas && !next(a[i], b[i]))) return false; } return true; } if (Array.isArray(b)) return false; if (a instanceof Set) { if (!(b instanceof Set) || a.size !== b.size) return false; const unmatched: any[] = [...b]; for (const value of a) { const index: number = unmatched.findIndex((candidate) => next(value, candidate), ); if (index === -1) return false; unmatched.splice(index, 1); } return true; } if (a instanceof Map) { if (!(b instanceof Map) || a.size !== b.size) return false; const unmatched: [any, any][] = [...b]; for (const [key, value] of a) { const index: number = unmatched.findIndex( ([candidateKey, candidateValue]) => next(key, candidateKey) && next(value, candidateValue), ); if (index === -1) return false; unmatched.splice(index, 1); } return true; } if (a instanceof Boolean) return b instanceof Boolean && a.valueOf() === b.valueOf(); if (Object.prototype.toString.call(a) === "[object BigInt]") return ( Object.prototype.toString.call(b) === "[object BigInt]" && a.valueOf() === b.valueOf() ); if (Object.prototype.toString.call(a) === "[object Symbol]") return ( Object.prototype.toString.call(b) === "[object Symbol]" && a.valueOf() === b.valueOf() ); if (a instanceof Number) return b instanceof Number && a.valueOf() === b.valueOf(); if (a instanceof String) return b instanceof String && a.valueOf() === b.valueOf(); if (a instanceof Date) return b instanceof Date && a.getTime() === b.getTime(); if (a instanceof RegExp) return ( b instanceof RegExp && a.source === b.source && a.flags === b.flags ); if (typeof File !== "undefined" && a instanceof File) return ( b instanceof File && a.name === b.name && a.size === b.size && a.type === b.type && a.lastModified === b.lastModified ); if (typeof Blob !== "undefined" && a instanceof Blob) return b instanceof Blob && a.size === b.size && a.type === b.type; if (a instanceof DataView) { if (!(b instanceof DataView) || a.byteLength !== b.byteLength) return false; return bytes(a.buffer, a.byteOffset, a.byteLength).every( (value, index) => value === bytes(b.buffer, b.byteOffset, b.byteLength)[index], ); } if (ArrayBuffer.isView(a)) { if ( !ArrayBuffer.isView(b) || b instanceof DataView || Object.getPrototypeOf(a) !== Object.getPrototypeOf(b) || a.byteLength !== b.byteLength ) return false; const x: Uint8Array = bytes(a.buffer, a.byteOffset, a.byteLength); const y: Uint8Array = bytes(b.buffer, b.byteOffset, b.byteLength); return x.every((value, index) => value === y[index]); } if (a instanceof ArrayBuffer) return ( b instanceof ArrayBuffer && a.byteLength === b.byteLength && bytes(a).every((value, index) => value === bytes(b)[index]) ); if ( typeof SharedArrayBuffer !== "undefined" && a instanceof SharedArrayBuffer ) return ( b instanceof SharedArrayBuffer && a.byteLength === b.byteLength && bytes(a).every((value, index) => value === bytes(b)[index]) ); const keys: PropertyKey[] = Reflect.ownKeys(a).filter((key) => Object.prototype.propertyIsEnumerable.call(a, key), ); return ( keys.length === Reflect.ownKeys(b).filter((key) => Object.prototype.propertyIsEnumerable.call(b, key), ).length && keys.every( (key) => Object.prototype.propertyIsEnumerable.call(b, key) && next((a as any)[key], (b as any)[key]), ) ); }; return next; }; const bytes = ( buffer: ArrayBufferLike, byteOffset: number = 0, byteLength: number = buffer.byteLength, ): Uint8Array => new Uint8Array(buffer, byteOffset, byteLength);