From 95127150fba867c87d7e31fb5b3ca34740820986 Mon Sep 17 00:00:00 2001 From: taichunmin Date: Fri, 10 May 2024 14:14:20 +0800 Subject: [PATCH] v0.12.0: Buffer.isBuffer and util.inspect --- .npmignore | 5 ++++- lib/buffer.test.ts | 22 ++++++++++++++++++++ lib/buffer.ts | 50 +++++++++++++++++++++++++++++++--------------- package.json | 2 +- 4 files changed, 61 insertions(+), 18 deletions(-) diff --git a/.npmignore b/.npmignore index f1848aa..3623254 100644 --- a/.npmignore +++ b/.npmignore @@ -133,6 +133,7 @@ out *.html *.nojekyll *.test.ts +*.xml /.eslintrc.* /*.config.js /dist/assets @@ -140,4 +141,6 @@ out /tsdoc.json /tsup.config.ts /typedoc -/typedoc.json \ No newline at end of file +/typedoc.json +dotenv.ts +sitemap.ts \ No newline at end of file diff --git a/lib/buffer.test.ts b/lib/buffer.test.ts index fcd4ed6..6a67501 100644 --- a/lib/buffer.test.ts +++ b/lib/buffer.test.ts @@ -1,5 +1,6 @@ import _ from 'lodash' import { Buffer } from './buffer' +import util from 'node:util' describe('new Buffer', () => { test('0 arguments', () => { @@ -615,6 +616,15 @@ describe('Buffer.concat()', () => { const actual = Buffer.concat([Buffer.from('abc')], 1) expect(actual.toString()).toEqual('a') }) + + test('should throw error with invalid list', () => { + expect.hasAssertions() + try { + Buffer.concat('' as any) + } catch (err) { + expect(err.message).toMatch(/an array of Buffers/) + } + }) }) describe('Buffer#equals()', () => { @@ -1704,3 +1714,15 @@ test('Buffer.packCalcSize()', () => { const actual = Buffer.packCalcSize('!bbbx5sbbb') expect(actual).toBe(12) }) + +describe('util.inspect()', () => { + test('util.inpect() with short buffer', () => { + const actual = util.inspect(Buffer.from('1122334455', 'hex')) + expect(actual).toBe('') + }) + + test('util.inpect() with long buffer', () => { + const actual = util.inspect(new Buffer(100)) + expect(actual).toBe('') + }) +}) diff --git a/lib/buffer.ts b/lib/buffer.ts index 5c85743..fc28b40 100644 --- a/lib/buffer.ts +++ b/lib/buffer.ts @@ -1,23 +1,26 @@ import _ from 'lodash' import { type Uint8Array } from './Uint8Array' +const customBufferSymbol = Symbol.for('taichunmin.buffer') +const customInspectSymbol = Symbol.for('nodejs.util.inspect.custom') const float16Buf = new DataView(new ArrayBuffer(4)) +const INSPECT_MAX_BYTES = 50 const isNativeLittleEndian = new Uint8Array(new Uint16Array([0x1234]).buffer)[0] === 0x12 const K_MAX_LENGTH = 0x7FFFFFFF const SIGNED_MAX_VALUE = [0, 0x7F, 0x7FFF, 0x7FFFFF, 0x7FFFFFFF, 0x7FFFFFFFFF, 0x7FFFFFFFFFFF] const SIGNED_OFFSET = [0, 0x100, 0x10000, 0x1000000, 0x100000000, 0x10000000000, 0x1000000000000] -const CHARCODE_BASE64 = new Map() as unknown as BaseCharMap -initEncodingMap(CHARCODE_BASE64, '-_', 62) -initEncodingMap(CHARCODE_BASE64, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/') +const CHARCODE_BASE64 = new Map() as unknown as CharCodeMap +initCharCodeMap(CHARCODE_BASE64, '-_', 62) +initCharCodeMap(CHARCODE_BASE64, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/') -const CHARCODE_BASE64URL = new Map() as unknown as BaseCharMap -initEncodingMap(CHARCODE_BASE64URL, '+/', 62) -initEncodingMap(CHARCODE_BASE64URL, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_') +const CHARCODE_BASE64URL = new Map() as unknown as CharCodeMap +initCharCodeMap(CHARCODE_BASE64URL, '+/', 62) +initCharCodeMap(CHARCODE_BASE64URL, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_') -const CHARCODE_HEX = new Map() as unknown as BaseCharMap -initEncodingMap(CHARCODE_HEX, 'ABCDEF', 10) -initEncodingMap(CHARCODE_HEX, '0123456789abcdef') +const CHARCODE_HEX = new Map() as unknown as CharCodeMap +initCharCodeMap(CHARCODE_HEX, 'ABCDEF', 10) +initCharCodeMap(CHARCODE_HEX, '0123456789abcdef') const fromStringFns = { 'ucs-2': 'fromUcs2String', @@ -383,6 +386,7 @@ export class Buffer extends Uint8Array { * ``` */ static concat (list: Buffer[], totalLength?: number): Buffer { + if (!_.isArray(list)) throw new TypeError('"list" argument must be an array of Buffers') if (_.isNil(totalLength)) totalLength = _.sumBy(list, 'length') if (totalLength < 0) totalLength = 0 const buf = new Buffer(totalLength) @@ -715,6 +719,12 @@ export class Buffer extends Uint8Array { return new Buffer(view.buffer, view.byteOffset + offset * bytesPerElement, length * bytesPerElement) } + /** + * A helper function which `Buffer.isBuffer()` will invoke and determine whether `this` is a `Buffer` or not. + * @returns `true` if `this` is a `Buffer`, `false` otherwise. + */ + [customBufferSymbol] (): boolean { return true } + /** * @returns `true` if `obj` is a `Buffer`, `false` otherwise. * @group Static Methods @@ -732,7 +742,7 @@ export class Buffer extends Uint8Array { * ``` */ static isBuffer (obj: any): obj is Buffer { - return isInstance(obj, Buffer) + return obj?.[customBufferSymbol]?.() ?? false } /** @@ -999,13 +1009,11 @@ export class Buffer extends Uint8Array { } const me = this.subarray(sourceStart, sourceEnd) target = target.subarray(targetStart, targetEnd) - const len = Math.max(me.length, target.length) + const len = Math.min(me.length, target.length) for (let i = 0; i < len; i++) { - if (i >= me.length) return -1 - if (i >= target.length) return 1 if (me[i] !== target[i]) return me[i] < target[i] ? -1 : 1 } - return 0 + return me.length === target.length ? 0 : (me.length < target.length ? -1 : 1) } /** @@ -2108,6 +2116,16 @@ export class Buffer extends Uint8Array { return Buffer[toStringFns[encoding]](this.subarray(start, end)) } + /** + * Custom inspect functions which `util.inspect()` will invoke and use the result of when inspecting the object. + * @returns a string representation of `buf`. + */ + [customInspectSymbol] (): string { + const tmp = this.subarray(0, INSPECT_MAX_BYTES).toString('hex').match(/.{2}/g) as string[] + const strMoreBytes = this.length > INSPECT_MAX_BYTES ? ` ... ${this.length - INSPECT_MAX_BYTES} more bytes` : '' + return `` + } + /** * Creates a new `Buffer` which is reverse of the original `buf`. * @example @@ -3151,12 +3169,12 @@ interface PackFormat { items: Array<[number, string]> } -interface BaseCharMap { +interface CharCodeMap { set: ((key: string, val: number) => this) & ((key: number, val: string) => this) get: ((key: string) => number) & ((key: number) => string) } -function initEncodingMap (map: BaseCharMap, str: string, offset: number = 0): void { +function initCharCodeMap (map: CharCodeMap, str: string, offset: number = 0): void { for (let i = 0; i < str.length; i++) map.set(i + offset, str[i]).set(str[i], i + offset) } diff --git a/package.json b/package.json index 1789fe5..9b0fcf1 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "main": "index.js", "name": "@taichunmin/buffer", "unpkg": "dist/buffer.global.js", - "version": "0.11.0", + "version": "0.12.0", "author": { "email": "taichunmin@gmail.com", "name": "Chunmin Tai",