diff --git a/src/binary.ts b/src/binary.ts deleted file mode 100644 index 521508e..0000000 --- a/src/binary.ts +++ /dev/null @@ -1,25 +0,0 @@ -export function arrayBufferToBase64(buffer: ArrayBufferLike) { - if (typeof Buffer !== 'undefined') { - return Buffer.from(buffer).toString('base64') - } - let binary = '' - const bytes = new Uint8Array(buffer) - for (let i = 0; i < bytes.byteLength; i++) { - binary += String.fromCharCode(bytes[i]) - } - return btoa(binary) -} - -export function base64ToArrayBuffer(base64: string) { - if (typeof Buffer !== 'undefined') { - // https://nodejs.org/api/buffer.html#bufbyteoffset - const buf = Buffer.from(base64, 'base64') - return new Uint8Array(buf.buffer, buf.byteOffset, buf.length) - } - const binary = atob(base64.replace(/\s/g, '')) - const buffer = new Uint8Array(binary.length) - for (let i = 0; i < binary.length; i++) { - buffer[i] = binary.charCodeAt(i) - } - return buffer -} diff --git a/src/index.ts b/src/index.ts index 02f4bf8..5344e27 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ export * from './array' -export * from './binary' +export * from './types' export * from './misc' export * from './string' export * from './time' diff --git a/src/misc.ts b/src/misc.ts index e6f01ee..3cfde49 100644 --- a/src/misc.ts +++ b/src/misc.ts @@ -28,40 +28,6 @@ export function mapValues(object: Dict, transform: export { mapValues as valueMap } -export function is(type: K): (value: any) => value is InstanceType -export function is(type: K, value: any): value is InstanceType -export function is(type: K, value?: any): any { - if (arguments.length === 1) return (value: any) => is(type, value) - return type in globalThis && value instanceof (globalThis[type] as any) - || Object.prototype.toString.call(value).slice(8, -1) === type -} - -export function clone(source: T): T -export function clone(source: any) { - if (!source || typeof source !== 'object') return source - if (Array.isArray(source)) return source.map(clone) - if (is('Date', source)) return new Date(source.valueOf()) - if (is('RegExp', source)) return new RegExp(source.source, source.flags) - return mapValues(source, clone) -} - -export function deepEqual(a: any, b: any, strict?: boolean): boolean { - if (a === b) return true - if (!strict && isNullable(a) && isNullable(b)) return true - if (typeof a !== typeof b) return false - if (typeof a !== 'object') return false - if (!a || !b) return false - - function check(test: (x: any) => x is T, then: (a: T, b: T) => boolean) { - return test(a) ? test(b) ? then(a, b) : false : test(b) ? false : undefined - } - - return check(Array.isArray, (a, b) => a.length === b.length && a.every((item, index) => deepEqual(item, b[index]))) - ?? check(is('Date'), (a, b) => a.valueOf() === b.valueOf()) - ?? check(is('RegExp'), (a, b) => a.source === b.source && a.flags === b.flags) - ?? Object.keys({ ...a, ...b }).every(key => deepEqual(a[key], b[key], strict)) -} - export function pick(source: T, keys?: Iterable, forced?: boolean) { if (!keys) return { ...source } const result = {} as Pick diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..669007b --- /dev/null +++ b/src/types.ts @@ -0,0 +1,75 @@ +import { isNullable, mapValues } from './misc' + +export function arrayBufferToBase64(buffer: ArrayBufferLike) { + if (typeof Buffer !== 'undefined') { + return Buffer.from(buffer).toString('base64') + } + let binary = '' + const bytes = new Uint8Array(buffer) + for (let i = 0; i < bytes.byteLength; i++) { + binary += String.fromCharCode(bytes[i]) + } + return btoa(binary) +} + +export function base64ToArrayBuffer(base64: string) { + if (typeof Buffer !== 'undefined') { + // https://nodejs.org/api/buffer.html#bufbyteoffset + const buf = Buffer.from(base64, 'base64') + return new Uint8Array(buf.buffer, buf.byteOffset, buf.length) + } + const binary = atob(base64.replace(/\s/g, '')) + const buffer = new Uint8Array(binary.length) + for (let i = 0; i < binary.length; i++) { + buffer[i] = binary.charCodeAt(i) + } + return buffer.buffer +} + +type GlobalConstructorNames = keyof { + [K in keyof typeof globalThis as typeof globalThis[K] extends abstract new (...args: any) => any ? K : never]: K +} + +export function is(type: K): (value: any) => value is InstanceType +export function is(type: K, value: any): value is InstanceType +export function is(type: K, value?: any): any { + if (arguments.length === 1) return (value: any) => is(type, value) + return type in globalThis && value instanceof (globalThis[type] as any) + || Object.prototype.toString.call(value).slice(8, -1) === type +} + +export function isArrayBufferLike(value: any): value is ArrayBufferLike { + return is('ArrayBuffer', value) || is('SharedArrayBuffer', value) +} + +export function isArrayBufferSource(value: any): value is ArrayBufferLike | ArrayBufferView { + return isArrayBufferLike(value) || ArrayBuffer.isView(value) +} + +export function clone(source: T): T +export function clone(source: any) { + if (!source || typeof source !== 'object') return source + if (Array.isArray(source)) return source.map(clone) + if (is('Date', source)) return new Date(source.valueOf()) + if (is('RegExp', source)) return new RegExp(source.source, source.flags) + if (is('ArrayBuffer', source)) return source.slice(0) + if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength) + return mapValues(source, clone) +} + +export function deepEqual(a: any, b: any, strict?: boolean): boolean { + if (a === b) return true + if (!strict && isNullable(a) && isNullable(b)) return true + if (typeof a !== typeof b) return false + if (typeof a !== 'object') return false + if (!a || !b) return false + + function check(test: (x: any) => x is T, then: (a: T, b: T) => boolean) { + return test(a) ? test(b) ? then(a, b) : false : test(b) ? false : undefined + } + + return check(Array.isArray, (a, b) => a.length === b.length && a.every((item, index) => deepEqual(item, b[index]))) + ?? check(is('Date'), (a, b) => a.valueOf() === b.valueOf()) + ?? check(is('RegExp'), (a, b) => a.source === b.source && a.flags === b.flags) + ?? Object.keys({ ...a, ...b }).every(key => deepEqual(a[key], b[key], strict)) +}