JSFiddle - React, Tailwind, and code Playground

HTML

<!-- 
We start with a hardcoded string, which demos two composite filter objects in a string representation.

The example sort string is also hardcoded, and demos parsing multiple sorts. Sorts are much less complicated to parse.

You'll find the converted object in the console.
-->

<button id="filter">Parse Filter String</button>
<button id="sort">Parse Sort String</button>

JavaScript

function parseFilterString() {

		var filterString = "(Auditor~startswith~'Gabe'~and~Auditor~endswith~'Newell')~and~(Company~contains~'Valve'~and~Company~neq~'EA')";

    console.log("filter: " + filterString);
		// Remove all of the ' characters from the string.
		filterString = filterString.replace(/[']/g, '');

		// Split the string into an array of strings, using the ~ as a delimiter.
		var ss = filterString.split("~"); // ss stands for "split string". I'm clever.

		var F = []; // Used to store all of the parsed filters.
		var fIndex = -1; // Used to track filter index.
		var cIndex = 0; // Used to track filter index within a composite filter object.
		var isComposite = false; // Used to indicate if a composite filter is currently being parsed.

		for (var i = 0; i < ss.length; i++) {
			if (i % 4 == 0) { // Field.
				if (ss[i].indexOf('(') > -1) { // If we're starting a composite object, create a composite object and add it to the parsed filters.
					F.push({
						filters: [],
						logic: ""
					});
					fIndex++; // We added an object to the array, so increment the counter.
					F[fIndex]
					F[fIndex].filters.push({
						field: ss[i].replace('(', ''),
						operator: "",
						value: ""
					});
					cIndex = 0; // We added the first filter to the composite object, so set the counter.
					isComposite = true;
				}
				else if (isComposite) { // If we're parsing the second filter in a composite filter object, then add the field to the child filter.
					F[fIndex].filters.push({
						field: ss[i],
						operator: "",
						value: ""
					});
					cIndex++; // We added the second filter to the composite object, so increment the counter.
				}
				else { // Add the field as normal.
					F.push({
						field: ss[i],
						operator: "",
						value: ""
					});
					fIndex++; // We added an object to the array, so increment the counter.
				}
			}
			if (i % 4 == 1) { // Operator.
				if (isComposite) {
					F[fIndex].filters[cIndex].operator =...