Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | 2x 2x 89x 47x 47x 47x 47x 47x 8x 8x 8x 8x 8x 8x 13x 13x 14x 14x 14x 14x 12x 12x 12x 12x 47x 47x 47x 17x 17x 17x 17x 16x 16x 16x 16x 16x 16x 16x 16x 16x 14x 14x 14x 14x 14x 14x 14x 14x 14x 47x 46x 46x 23x 23x 23x 92x 92x 23x 23x 23x 92x 23x | import type {Log} from '../Log'; import {FileModelEncoding} from './constants'; import type * as types from './types'; import type {CborEncoder} from '@jsonjoy.com/json-pack/lib/cbor/CborEncoder'; import type {JsonEncoder} from '@jsonjoy.com/json-pack/lib/json/JsonEncoder'; import type {Encoder as StructuralEncoderCompact} from '../../codec/structural/compact/Encoder'; import type {Encoder as StructuralEncoderVerbose} from '../../codec/structural/verbose/Encoder'; import type {Encoder as SidecarEncoder} from '../../codec/sidecar/binary/Encoder'; import type {encode as encodeCompact} from '../../../json-crdt-patch/codec/compact/encode'; import type {encode as encodeVerbose} from '../../../json-crdt-patch/codec/verbose/encode'; export interface LogEncoderOpts { jsonEncoder?: JsonEncoder; cborEncoder?: CborEncoder; structuralCompactEncoder?: StructuralEncoderCompact; structuralVerboseEncoder?: StructuralEncoderVerbose; sidecarEncoder?: SidecarEncoder; patchCompactEncoder?: typeof encodeCompact; patchVerboseEncoder?: typeof encodeVerbose; } export class LogEncoder { constructor(protected readonly options: LogEncoderOpts = {}) {} public serialize(log: Log, params: SerializeParams = {}): types.LogComponents { Iif (params.noView && params.model === 'sidecar') throw new Error('SIDECAR_MODEL_WITHOUT_VIEW'); const metadata: types.LogMetadata = [{}, FileModelEncoding.Auto]; let model: Uint8Array | unknown | null = null; const modelFormat = params.model ?? 'sidecar'; switch (modelFormat) { case 'sidecar': { metadata[1] = FileModelEncoding.SidecarBinary; const encoder = this.options.sidecarEncoder; Iif (!encoder) throw new Error('NO_SIDECAR_ENCODER'); const [, uint8] = encoder.encode(log.end); model = uint8; break; } case 'binary': { model = log.end.toBinary(); break; } case 'compact': { const encoder = this.options.structuralCompactEncoder; Iif (!encoder) throw new Error('NO_COMPACT_ENCODER'); model = encoder.encode(log.end); break; } case 'verbose': { const encoder = this.options.structuralVerboseEncoder; Iif (!encoder) throw new Error('NO_VERBOSE_ENCODER'); model = encoder.encode(log.end); break; } case 'none': { model = null; break; } default: throw new Error(`Invalid model format: ${modelFormat}`); } const history: types.LogHistory = [null, []]; const patchFormat = params.history ?? 'binary'; switch (patchFormat) { case 'binary': { history[0] = log.start().toBinary(); // biome-ignore lint: allow .forEach(), for now log.patches.forEach(({v}) => { history[1].push(v.toBinary()); }); break; } case 'compact': { const encoder = this.options.structuralCompactEncoder; Iif (!encoder) throw new Error('NO_COMPACT_ENCODER'); history[0] = encoder.encode(log.start()); const encodeCompact = this.options.patchCompactEncoder; Iif (!encodeCompact) throw new Error('NO_COMPACT_PATCH_ENCODER'); const list = history[1]; // biome-ignore lint: allow .forEach(), for now log.patches.forEach(({v}) => { list.push(encodeCompact(v)); }); break; } case 'verbose': { const encoder = this.options.structuralVerboseEncoder; Iif (!encoder) throw new Error('NO_VERBOSE_ENCODER'); history[0] = encoder.encode(log.start()); const encodeVerbose = this.options.patchVerboseEncoder; Iif (!encodeVerbose) throw new Error('NO_VERBOSE_PATCH_ENCODER'); const list = history[1]; // biome-ignore lint: allow .forEach(), for now log.patches.forEach(({v}) => { list.push(encodeVerbose(v)); }); break; } case 'none': { break; } default: throw new Error(`Invalid history format: ${patchFormat}`); } return [params.noView ? null : log.end.view(), metadata, model, history]; } public encode(log: Log, params: EncodingParams): Uint8Array { const sequence = this.serialize(log, params); switch (params.format) { case 'ndjson': { const json = this.options.jsonEncoder; Iif (!json) throw new Error('NO_JSON_ENCODER'); for (const component of sequence) { json.writeAny(component); json.writer.u8('\n'.charCodeAt(0)); } return json.writer.flush(); } case 'seq.cbor': { const cbor = this.options.cborEncoder; Iif (!cbor) throw new Error('NO_CBOR_ENCODER'); for (const component of sequence) cbor.writeAny(component); return cbor.writer.flush(); } } } } /** * High-level serialization parameters for encoding a {@link Log} instance into * a sequence of components. */ export interface SerializeParams { /** * If set to `false`, will not encode the view of the model as the very first * component. Encoding the view of the latest known state as the first * component of NDJSON or CBOR-Sequence is useful for allowing the decoders, * which do not know the details of JSON CRDTs, to just read the view and * ignore the rest of the components. */ noView?: boolean; /** * Specifies the model encoding format for the latest state `.end` for * the {@link Log}. The default is `'sidecar'`. The `'sidecar'` model format * is a binary format which encodes only the metadata, which is very compact * if the view was encoded separately. As it can then be used together with * the view to decode it back. */ model?: 'sidecar' | 'binary' | 'compact' | 'verbose' | 'none'; /** * Specifies the patch `log.patches` and start model `log.start()` encoding * encoding format of the "history" part of the document. The default is * `'binary'`. */ history?: 'binary' | 'compact' | 'verbose' | 'none'; } /** * High-level encoding parameters for encoding a {@link Log} instance into a * binary blob. */ export interface EncodingParams extends SerializeParams { /** * Specifies the encoding format of the whole log document. The document is * encoded as a sequence of JSON/CBOR-like components. Those can be encoded * as JSON (for human-readable text) or CBOR (for compact binary data). * * - `ndjson` - encodes the log document as a sequence of new-line delimited * JSON values. * - `seq.cbor` - encodes the log document as a CBOR sequence binary data. */ format: 'ndjson' | 'seq.cbor'; } |