# All files / src/streamComponents csvtondjson.js

100% Statements 79/79
100% Branches 18/18
100% Functions 5/5
100% Lines 79/79

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
    791x
    1x
    1x
    1x
    1x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    6x
    6x
    6x
    6x
    6x
    6x
    6x
    6x
    6x
    21x
    21x
    15x
    15x
    15x
    15x
    15x
    15x
    15x
    15x
    15x
    15x
    15x
    21x
    11x
    11x
    21x
    25x
    25x
    25x
    21x
    21x
    21x
    21x
    7x
    7x
    7x
    7x
    6x
    4x
    4x
    4x
    5x
    5x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    4ximport { Transform } from 'node:stream'
    const BREAK_LINE_SYMBOL = "\n"
    const INDEX_NOT_FOUND = -1

    export default class CSVToNDJSON extends Transform {
      #delimiter = ''
      #headers = []
      #buffer = Buffer.alloc(0)

      constructor({
        delimiter =  ',',
        headers
      }) {
        super()

        this.#delimiter = delimiter
        this.#headers  = headers
      }
      * #updateBuffer(chunk) {
        // it'll ensure if we got a chunk that is not completed
        // and doesnt have a breakline
        // will concat with the previous read chunk
        // 1st time = 01,
        // 2st time = ,erick,adreress\n
        // try parsing and returning data!
        this.#buffer = Buffer.concat([this.#buffer, chunk])
        let breaklineIndex = 0
        while(breaklineIndex !== INDEX_NOT_FOUND) {
          breaklineIndex = this.#buffer.indexOf(Buffer.from(BREAK_LINE_SYMBOL))
          if(breaklineIndex === INDEX_NOT_FOUND) break;

          const lineToProcessIndex = breaklineIndex + BREAK_LINE_SYMBOL.length
          const line = this.#buffer.subarray(0, lineToProcessIndex)
          const lineData = line.toString()

          // I'll remove from the main buffer the data
          // we already processed!
          this.#buffer = this.#buffer.subarray(lineToProcessIndex)

          // if it's an empty line ignore this line
          if(lineData === BREAK_LINE_SYMBOL) continue;
          const NDJSONLine = []
          const headers = Array.from(this.#headers)
          for(const item of lineData.split(this.#delimiter)) {
            const key = headers.shift()
            const value = item.replace(BREAK_LINE_SYMBOL, "")
            if(key === value) break;

            NDJSONLine.push(`"${key}":"${value}"`)
          }
          if(!NDJSONLine.length) continue;
          const ndJSONData = NDJSONLine.join(',')

          yield Buffer.from('{'.concat(ndJSONData).concat('}').concat(BREAK_LINE_SYMBOL))
        }
      }
      _transform(chunk, enc, callback) {

        for(const item of this.#updateBuffer(chunk)) {
          this.push(item);
        }

        return callback()
      }

      // when it finishes processing
      // this.push(null) on the readable side
      // or .end()
      _final(callback) {
        if(!this.#buffer.length) return callback()

        for(const item of this.#updateBuffer(Buffer.from(BREAK_LINE_SYMBOL))) {
          this.push(item)
        }

        callback()
      }
    }