JSFiddle - React, Tailwind, and code Playground

HTML

<div>
  Pattern:
  <textarea id="pattern" rows="2" cols="80">(hello|hi), {0}, (how are you|nice to see you)</textarea>
</div>
<div>
  String:
  <input id="string" value="John" />
</div>
<div>
  <input id="generate" type="button" value="Generate" />
</div>
<div>
  Results:
  <ul id="results"></ul>
</div>

JavaScript

String.prototype.formatUnicorn = String.prototype.formatUnicorn ||
  function () {
  "use strict";
  var str = this.toString();
  if (arguments.length) {
    var t = typeof arguments[0];
    var key;
    var args = ("string" === t || "number" === t) ?
        Array.prototype.slice.call(arguments)
    : arguments[0];

    for (key in args) {
      str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]);
    }
  }

  return str;
};

function cartesianProduct(arr) {
  return arr.reduce(function (a, b) {
    return a.map(function (x) {
      return b.map(function (y) {
        return x.concat([y]);
      })
    }).reduce(function (a, b) { return a.concat(b) }, [])
  }, [[]])
}

function parsePattern(pattern, str) {
  var regex = /\(([^|()]+\|)*[^|()]+\)/g;
  var results = [];

  var matches = pattern.match(regex);

  // replace input string match groups with format strings
  matches.forEach(function (el, idx) {
    pattern = pattern.replace(el, '{' + (idx + 1) + '}');
  });

  // split matches into parts
  var matchesSplit = [];

  matches.forEach(function (el, idx) {
    matchesSplit[idx] = el.replace(/[()]/g, '').split('|');
  });

  // generate result strings
  matchesSplit.splice(0, 0, [str]);

  cartesianProduct(matchesSplit).forEach(function (el) {
    results.push(pattern.formatUnicorn(el));
  });

  return results;
}

$(function () {
  $("#generate").on("click", function () {
    $("#results").empty();
    parsePattern($("#pattern").val(), $("#string").val()).forEach(function (el) {
      $("#results").append("<li>" + el + "</li>");
    });
  });
});