From 7381b50c8534a94d594a8704de6356c6e9e365ed Mon Sep 17 00:00:00 2001 From: streamich Date: Wed, 29 Nov 2023 21:07:18 +0100 Subject: [PATCH] =?UTF-8?q?feat(json-crdt):=20=F0=9F=8E=B8=20improve=20oct?= =?UTF-8?q?et=20textual=20representation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/json-crdt/__demos__/docs-bin.ts | 42 +++++++++++++++++--------- src/json-crdt/nodes/rga/AbstractRga.ts | 9 +++--- src/util/buffers/printOctets.ts | 14 +++++++++ 3 files changed, 46 insertions(+), 19 deletions(-) create mode 100644 src/util/buffers/printOctets.ts diff --git a/src/json-crdt/__demos__/docs-bin.ts b/src/json-crdt/__demos__/docs-bin.ts index a9fc552476..a3c3e1151b 100644 --- a/src/json-crdt/__demos__/docs-bin.ts +++ b/src/json-crdt/__demos__/docs-bin.ts @@ -13,40 +13,52 @@ console.clear(); const model = Model.withLogicalClock(1234); // 1234 is session ID model.api.root({ - blob: new Uint8Array([1, 2, 3]), + blob: new Uint8Array([1, 2, 3, 14, 15, 16, 17]), }); console.log(model.view()); -// { blob: Uint8Array(3) [ 1, 2, 3 ] } +// { +// blob: Uint8Array(7) [ +// 1, 2, 3, 14, +// 15, 16, 17 +// ] +// } console.log(model.root + ''); -// RootNode 0.0 -// └─ ObjNode 1234.1 +// root 0.0 +// └─ obj 1234.1 // └─ "blob" -// └─ BinNode 1234.2 { 1, 2, 3 } -// └─ BinChunk 1234.3!3 len:3 { 1, 2, 3 } +// └─ bin 1234.2 { 01 02 03 0e 0f 10 11 } +// └─ BinChunk 1234.3!7 len:7 { 01 02 03 0e 0f 10 11 } // Retrieve node at path ['blob'] as "bin" type. const blob = model.api.bin(['blob']); console.log(blob + ''); // BinApi -// └─ BinNode 1234.2 { 1, 2, 3 } -// └─ BinChunk 1234.3!3 len:3 { 1, 2, 3 } +// └─ bin 1234.2 { 01 02 03 0e 0f 10 11 } +// └─ BinChunk 1234.3!7 len:7 { 01 02 03 0e 0f 10 11 } blob.ins(3, new Uint8Array([4, 5])); console.log(blob + ''); // BinApi -// └─ BinNode 1234.2 { 1, 2, 3, 4, 5 } -// └─ BinChunk 1234.8!2 len:5 { 4, 5 } -// ← BinChunk 1234.3!3 len:3 { 1, 2, 3 } +// └─ bin 1234.2 { 01 02 03 04 05 0e 0f 10 11 } +// └─ BinChunk 1234.12!2 len:9 { 04 05 } +// ← BinChunk 1234.3!3 len:3 { 01 02 03 } +// → BinChunk 1234.6!4 len:4 { 0e 0f 10 11 } blob.del(2, 1); console.log(blob + ''); // BinApi -// └─ BinNode 1234.2 { 1, 2, 4, 5 } -// └─ BinChunk 1234.8!2 len:4 { 4, 5 } -// ← BinChunk 1234.3!2 len:2 { 1, 2 } +// └─ bin 1234.2 { 01 02 04 05 0e 0f 10 11 } +// └─ BinChunk 1234.12!2 len:8 { 04 05 } +// ← BinChunk 1234.3!2 len:2 { 01 02 } // → BinChunk 1234.5!1 len:0 [1] +// → BinChunk 1234.6!4 len:4 { 0e 0f 10 11 } console.log(model.view()); -// { blob: Uint8Array(4) [ 1, 2, 4, 5 ] } +// { +// blob: Uint8Array(8) [ +// 1, 2, 4, 5, +// 14, 15, 16, 17 +// ] +// } diff --git a/src/json-crdt/nodes/rga/AbstractRga.ts b/src/json-crdt/nodes/rga/AbstractRga.ts index 27a3347c87..5e0437e04c 100644 --- a/src/json-crdt/nodes/rga/AbstractRga.ts +++ b/src/json-crdt/nodes/rga/AbstractRga.ts @@ -12,9 +12,10 @@ import {isUint8Array} from '../../../util/buffers/isUint8Array'; import {rSplay, lSplay, llSplay, rrSplay, lrSplay, rlSplay} from '../../../util/trees/splay/util'; import {splay2} from '../../../util/trees/splay/util2'; import {insert2, remove2} from '../../../util/trees/util2'; -import {printBinary} from '../../../util/print/printBinary'; -import {printTree} from '../../../util/print/printTree'; import {ORIGIN} from '../../../json-crdt-patch/constants'; +import {printTree} from '../../../util/print/printTree'; +import {printBinary} from '../../../util/print/printBinary'; +import {printOctets} from '../../../util/buffers/printOctets'; /** * @category CRDT Node @@ -876,7 +877,7 @@ export abstract class AbstractRga { public toString(tab: string = ''): string { const view = this.view(); let value = ''; - if (isUint8Array(view)) value += ` { ${('' + view).replaceAll(',', ', ')} }`; + if (isUint8Array(view)) value += ` { ${printOctets(view) || '∅'} }`; else if (typeof view === 'string') value += `{ ${view.length > 32 ? JSON.stringify(view.substring(0, 32)) + ' …' : JSON.stringify(view)} }`; const header = `${this.toStringName()} ${toDisplayString(this.id)} ${value}`; @@ -898,7 +899,7 @@ export abstract class AbstractRga { let str = `${chunk.constructor.name} ${id}!${chunk.span} len:${chunk.len}`; if (chunk.del) str += ` [${chunk.span}]`; else { - if (isUint8Array(chunk.data)) str += ` { ${chunk.data.toString().replaceAll(',', ', ')} }`; + if (isUint8Array(chunk.data)) str += ` { ${printOctets(chunk.data) || '∅'} }`; else if (typeof chunk.data === 'string') { const data = chunk.data.length > 32 ? JSON.stringify(chunk.data.substring(0, 32)) + ' …' : JSON.stringify(chunk.data); diff --git a/src/util/buffers/printOctets.ts b/src/util/buffers/printOctets.ts new file mode 100644 index 0000000000..9e5c01fd3e --- /dev/null +++ b/src/util/buffers/printOctets.ts @@ -0,0 +1,14 @@ +export const printOctets = (octets: Uint8Array, max: number = 16): string => { + let str = ''; + if (!octets.length) return str; + if (octets[0] < 16) str += '0'; + str += octets[0].toString(16); + for (let i = 1; i < octets.length && i < max; i++) { + const n = octets[i]; + str += ' '; + if (n < 16) str += '0'; + str += n.toString(16); + } + if (octets.length > max) str += `… (${octets.length - max} more)`; + return str; +};