Matching bracket validator

Read a string, make sure brackets (e.g. {}, (), []) do not overlap.

by Renoir Boulanger

HTML

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<section class="container-fluid" style="margin-top:20px;">
 <div class=jumbotron>
    <h1>Matching bracket validator</h1>
    <p>
       A validator to check if brackets (e.g. <tt>(), {}, &lt;&gt;, etc</tt>) are closed correctly without overlapping.
    </p>
 </div>
 <div class="row">
  <form class="col-xs-12 col-md-12">
    <div class="form-group">
      <label for="text">Text to validate</label>
      <textarea class="form-control" rows="3" id="text">Testing {[(if)]} brackets closes. This string (should) be valid.</textarea>
      <span id="textResult" class="help-block"><strong>How to use:</strong> Edit in textarea, then click elsewhere to validate</span>
    </div>    
  </form>
 </div>
</section>

JavaScript

/**
 * A validator to check if brackets are closed correctly without overlapping
 **/

var Validator = (function iife(){
 "use strict";

  var defaultRules = [
     ['{','}']
    ,['(',')']
    ,['[',']']
    ,['<','>']
  ];

  function openingTokenCheck(tokenList, inputChar) {
    var out = {resultValue: false, match: null};
    var matcher = tokenList.find((pair) => {
      return inputChar === pair[0];
    });
    if (!matcher) {
      return out;
    }
    out.resultValue = true;
    out.match = matcher;
    return out;
  }

  function closingTokenCheck(tokenList, inputChar) {
    var out = {resultValue: false, match: null};
    var matcher = tokenList.find((pair) => {
      return inputChar === pair[1];
    });
    if (!matcher) {
      return out;
    }
    out.resultValue = true;
    out.match = matcher;
    return out;
  }

  function looper(tokenPairs, inputString) {
    let stack = []
    ,   tokens = tokenPairs||[]
    ,   i = 0;
    do {
      let stackLast = (stack.length > 0) ? stack[stack.length - 1] : null;
      let isOpeningToken = openingTokenCheck(tokens, inputString[i]);
      let isClosingToken = closingTokenCheck(tokens, inputString[i]);
      if (isOpeningToken.resultValue === true) {
        stack.push(isOpeningToken);
      }
      /**
       * UNCOVERED CASE
       * When a close bracket when we did not get
       * an opening earlier. TODO.
       **/
      if (stackLast !== null) {
        if (
              isClosingToken.resultValue === true &&
              stackLast.match[1] === inputString[i]
          ) {
          stack.pop();
        }
      }
      ++i;
    } while (i < inputString.length);

    return {stack: stack};
  }

  class ParenthesisValidator {
    constructor(rules) {
      this.rules = rules || defaultRules;
    }

    validate(input) {
      let validation = looper(this.rules, input);
      validation.outcome = (validation.stack.length === 0) ? true : false;
      return validation;
    }

    assert(expected,...