AlfonsoFilho/match-ish

View on GitHub
src/ast-nodes/list.ts

Summary

Maintainability
A
3 hrs
Test Coverage
import { FAIL } from '../constants';
import { addAlias, addBind, getRest, is, isType, reverse } from '../helpers';
import { AstNode, AstType, MatchResult } from '../types';

export const list = (input: any[], node: AstNode, interpreter): MatchResult => {
  const restNode = getRest(node.value);

  if (
    !is(input, 'Array') ||
    (!!restNode ? input.length === 0 : input.length !== node.value.length)
  ) {
    return FAIL;
  }

  if (!input.every(it => isType(it, node))) {
    return FAIL;
  }

  if (restNode) {
    const nthBefore = node.value.findIndex(({ type }: AstNode) => type === AstType.REST);
    const nthAfter = reverse(node.value).findIndex(({ type }: AstNode) => type === AstType.REST);

    const restContent = input.slice(nthBefore, input.length - nthAfter);

    if (restContent.length === 0) {
      return FAIL;
    }

    if (!restNode.bind) {
      return [true, { ...addBind(node, restContent), ...addAlias(node, restContent) }];
    }

    input = [
      ...input.slice(0, nthBefore),
      restContent,
      ...input.slice(input.length - nthAfter, input.length)
    ];
  }

  const matchResult = input.map((inputValue, index) => {
    return interpreter({ root: node.value[index] }, inputValue);
  });

  if (matchResult.every(([status, _]) => status === true)) {
    return [
      true,
      matchResult.reduce((acc, it) => ({ ...acc, ...it[1] }), {
        ...addBind(node, node.value.map(({ value }: AstNode) => value)),
        ...addAlias(node, node.value.map(({ value }: AstNode) => value))
      })
    ];
  } else {
    return FAIL;
  }
};