All files / json-pack/src/resp RespEncoderLegacy.ts

80.88% Statements 55/68
68.75% Branches 22/32
87.5% Functions 7/8
84.9% Lines 45/53

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  1x 1x 1x     1x 1x         1x   20x   5x   7x   2x   6x 5x 3x 2x 1x 1x         1x                       5x 1x       8x 8x 1x       1x       1x                 2x 2x 2x 2x 2x 2x 5x 5x 4x         1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x        
import {RESP} from './constants';
import {RespAttributes, RespPush, RespVerbatimString} from './extensions';
import {JsonPackExtension} from '../JsonPackExtension';
import {RespEncoder} from './RespEncoder';
import type {IWriter, IWriterGrowable} from '@jsonjoy.com/buffers/lib';
 
const REG_RN = /[\r\n]/;
const isSafeInteger = Number.isSafeInteger;
 
/**
 * Implements RESP v2 encoding.
 */
export class RespEncoderLegacy<W extends IWriter & IWriterGrowable = IWriter & IWriterGrowable> extends RespEncoder<W> {
  public writeAny(value: unknown): void {
    switch (typeof value) {
      case 'number':
        return this.writeNumber(value as number);
      case 'string':
        return this.writeStr(value);
      case 'boolean':
        return this.writeSimpleStr(value ? 'TRUE' : 'FALSE');
      case 'object': {
        if (!value) return this.writeNull();
        if (value instanceof Array) return this.writeArr(value);
        if (value instanceof Uint8Array) return this.writeBin(value);
        if (value instanceof Error) return this.writeErr(value.message);
        Iif (value instanceof Set) return this.writeSet(value);
        Iif (value instanceof JsonPackExtension) {
          Iif (value instanceof RespPush) return this.writeArr(value.val);
          Iif (value instanceof RespVerbatimString) return this.writeStr(value.val);
          Iif (value instanceof RespAttributes) return this.writeObj(value.val);
        }
        return this.writeObj(value as Record<string, unknown>);
      }
      case 'undefined':
        return this.writeUndef();
      case 'bigint':
        return this.writeSimpleStrAscii(value + '');
      default:
        return this.writeUnknown(value);
    }
  }
 
  public writeNumber(num: number): void {
    if (isSafeInteger(num)) this.writeInteger(num);
    else this.writeSimpleStrAscii(num + '');
  }
 
  public writeStr(str: string): void {
    const length = str.length;
    if (length < 64 && !REG_RN.test(str)) this.writeSimpleStr(str);
    else this.writeBulkStr(str);
  }
 
  public writeNull(): void {
    this.writeNullArr();
  }
 
  public writeErr(str: string): void {
    if (str.length < 64 && !REG_RN.test(str)) this.writeSimpleErr(str);
    else Ethis.writeBulkStr(str);
  }
 
  public writeSet(set: Set<unknown>): void {
    this.writeArr([...set]);
  }
 
  public writeArr(arr: unknown[]): void {
    const writer = this.writer;
    const length = arr.length;
    writer.u8(RESP.ARR); // *
    this.writeLength(length);
    writer.u16(RESP.RN); // \r\n
    for (let i = 0; i < length; i++) {
      const val = arr[i];
      if (val === null) this.writeNullStr();
      else this.writeAny(val);
    }
  }
 
  public writeObj(obj: Record<string, unknown>): void {
    const writer = this.writer;
    const keys = Object.keys(obj);
    const length = keys.length;
    writer.u8(RESP.ARR); // %
    this.writeLength(length << 1);
    writer.u16(RESP.RN); // \r\n
    for (let i = 0; i < length; i++) {
      const key = keys[i];
      this.writeStr(key);
      const val = obj[key];
      Iif (val === null) this.writeNullStr();
      else this.writeAny(val);
    }
  }
}