All files / src/codec/paths unfold.ts

100% Statements 30/30
100% Branches 4/4
100% Functions 1/1
100% Lines 30/30

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 491x 1x 1x 1x 1x                             1x 1x 88x 217x 217x 217x 217x   217x 217x   217x   217x 217x 217x 217x 217x   217x 64x 64x 64x 64x 64x 64x 64x 153x 217x  
import {type TreeUnfolder} from '#tree'
import * as TreeF from '#treeF'
import {type NonEmptyArray2} from '#Array'
import {orderToEqual} from '#Order'
import {Array, Equivalence, Order, pipe} from 'effect'
import type {NonEmptyArray} from 'effect/Array'
 
/**
 * Build a tree from a list of paths and an order. For example:
 * ```ts
 * const paths = [['A', 'B'], ['A', 'C', 'D'], ['A', 'C', 'E']]
 *
 * const tree = treeAna(pathListUnfold(STR.Order))(paths)
 * // A(B, C(D, E))
 * ```
 * @category unfold
 * @category codec
 * @function
 */
export const pathListUnfold =
  <A>(order: Order.Order<A>): TreeUnfolder<A, NonEmptyArray2<A>> =>
  paths => {
    const pathOrder = pipe(
      order,
      Order.mapInput<[A, ...A[]], A>(Array.headNonEmpty<A>),
    ) as Order.Order<A[]>
 
    const pathsEquals: Equivalence.Equivalence<NonEmptyArray<A>> =
      orderToEqual(pathOrder)
 
    const head: A = paths[0][0]
 
    const filtered = pipe(
      paths,
      Array.map(Array.tailNonEmpty),
      Array.filter(Array.isNonEmptyReadonlyArray),
    )
 
    return Array.isNonEmptyReadonlyArray(filtered)
      ? TreeF.branchF(
          head,
          Array.groupWith(
            pipe(filtered as NonEmptyArray2<A>, Array.sortBy(pathOrder)),
            pathsEquals,
          ),
        )
      : TreeF.leafF(head)
  }