JSFiddle - React, Tailwind, and code Playground

by dswitzer

CSS

.test-output {
	white-space: pre-line;
	font: 12px "Courier New";
}

JavaScript

function tokenReplacer(tokens, string){
	/*
	 * This parsers the string looking for tokens in the format:
	 * {some}, {some.nested.variable}, {&some}, {&some.nested.variable}
	 * 
	 * The expression:
	 * ([a-zA-Z_$][0-9a-zA-Z_$]*(\.[a-zA-Z_$][0-9a-zA-Z_$]*)*)
	 *
	 * Searches for any valid JS variable name.
	 */
	var regexParser = /\{\&?([a-zA-Z_$][0-9a-zA-Z_$]*(\.[a-zA-Z_$][0-9a-zA-Z_$]*)*)\}/g
		, matches = string.match(regexParser)
		, results = string;
		
		function getToken(token){
			// remove the { and } from the token
			var keyPath = token.substring(1, token.length-1)
				// if the token starts with "&" it means we URI encode the output
				, isUriEncode = (keyPath.indexOf("&") === 0);
			
			// if we have any special encoding commands, remove the encoding character
			if( isUriEncode ){
				keyPath = keyPath.substring(1);
			}
			
			// return the value found or an empty string
			var value = getValueFromPath(tokens, keyPath) || "";
			
			if( isUriEncode ){
				value = encodeURIComponent(value);
			}
			console.log("%s = %o", keyPath, value);
			
			return value;
		}
		
		function getValueFromPath(input, path) {
			try {
				var separator = '.';

				return path
					.replace('[', separator).replace(']','')
					.split(separator)
					.reduce(
						function (obj, property) { 
							return obj[property];
						}
						, input
					);
											
			} catch (e) {
				return;
			}   
		}			
		console.log(matches);
		
		if( matches ){
			matches.forEach(function (match){
				results = results.replace(match, getToken(match));
			});
		}
		
		return results;
}

function test(tokens, string){
	var output = document.createElement("div");
	output.className = "test-output";
	output.innerText = string + " -> " + tokenReplacer(tokens, string);
	
	document.body.appendChild(output);
}

var tokens = {
	widget: {title: "Hello World!"}
	, item: {label: "My Label", value: 3, series: "Series Name"}
};

test(tokens, "{widget.title}: {item.label} -...