utils.js

import {
  Iterable,
  List
} from 'immutable';

/**
 * @module utils
 */

/**
 * Accepts an Array, List or null and returns an equivalent List. Passing in null will return an empty List.
 *
 * @param {Array|List|null} input The input to be convert to a List. List items will pass through unchanged, all others will be passed into a List constructor.
 * @return {List} The equivalent List.
 */

function asList(input) {
    return List.isList(input) ? input : List(input);
}

/**
 * Accepts a node and returns a boolean indicating if the node is a leaf node (i.e. it has no children).
 *
 * @param {*} node The node to check.
 * @param {Array|List} [childPath=null] An {Array} or {List} of the key path to each node's children.
 * @return {boolean} A boolean indicating if the node is a leaf node.
 */

function isLeaf(node, childPath = null) {
  if(!Iterable.isIterable(node)) {
    return true;
  }
  const children = node.getIn(childPath || []);
  return !children || children.isEmpty();
}

/**
 * Turns a node's keys and its childPath into a full path.
 *
 * @param {Array|List} keys An {Array} or {List} of keys used to identify a node.
 * @param {Array|List} [childPath=null] An {Array} or {List} of the key path to each node's children.
 * @return {List}
 */

function keysToPath(keys, childPath = null) {
  childPath = asList(childPath);
  return keys.reduce((fullPath, key) => {
    return fullPath.concat(childPath).push(key);
  }, List());
}

/**
 * Turns a node's keys and its childPath into a full path to the node's children.
 *
 * @param {Array|List} keys An {Array} or {List} of keys used to identify a node.
 * @param {Array|List} [childPath=null] An {Array} or {List} of the key path to each node's children.
 * @return {List}
 */

function keysToPathChildren(keys, childPath = null) {
  return childPath == null
    ? asList(keys)
    : keysToPath(keys, childPath).concat(childPath);
}

export {
  asList,
  isLeaf,
  keysToPath,
  keysToPathChildren
}