-
Notifications
You must be signed in to change notification settings - Fork 0
/
text-formatter.js
121 lines (120 loc) · 3.63 KB
/
text-formatter.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/* Formats text and replaces {{placeholders}} with respective text.
* {{placeholder}} is replaced with `replacements["placeholder"]`
* Recursive replacement [[placeholder]]seperator[[format]]
* - For each `replacements` object in `replacements["placeholder"]` array
* - Repeat `format` formatted with the specified {{placeholders}} filled
* - Join with the `seperator`
*/
fillTemplate = function (text, replacements, debug) {
var format = fillTemplate;
var rep = replacements || {};
var delimiters = "{}[]";
var splitrx = new RegExp("("+(delimiters.split("").map(ch => "\\"+ch+"{2}").join("|"))+")");
var tokens = text.split(splitrx);
// Buffers
var out = "", ph = "", sep = "", fmt = "", lastdelim = "", open = 0;
/* 5 States
* Normal (NORM)
* Reading a Simple Placeholder (TXPH)
* Reading a Recursive Placeholder (RCPH)
* Reading a RCPH Seperator (RCSP)
* Reading a RCPH Format (RFMT)
*/
var STATE = "NORM";
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
if (!token) continue;
if (debug) console.log(STATE);
var delim = (token.length === 2 && token[0] === token[1] && delimiters.indexOf(token[0]) !== -1) ? token[0] : false;
if (delim) {
if (delim === '{') {
switch (STATE) {
case "RCSP": sep += token; delim = false; break;
case "RFMT": fmt += token; delim = false; break;
case "TXPH":
case "RCPH":
out += lastdelim + ph;
ph = "";
case "NORM":
STATE = "TXPH";
}
} else if (delim === '}') {
switch (STATE) {
case "NORM": out += token; delim = false; break;
case "RCSP": sep += token; delim = false; break;
case "RFMT": fmt += token; delim = false; break;
case "RCPH":
case "TXPH":
var phname = ph.trim();
var replace = (STATE == "TXPH" && phname in rep);
if (replace) out += rep[phname];
else out += lastdelim + ph + token;
STATE = "NORM";
ph = ""; break;
}
} else if (delim === '[') {
switch (STATE) {
case "RCSP":
open++;
STATE = "RFMT"; break;
case "RFMT":
open++; fmt += token;
delim = false; break;
case "RCPH":
case "TXPH":
out += lastdelim + ph;
ph = "";
case "NORM":
STATE = "RCPH";
}
} else if (delim === ']') {
switch (STATE) {
case "RCPH":
STATE = "RCSP"; break;
case "TXPH":
out += lastdelim + ph;
ph = ""; STATE = "NORM";
case "NORM":
out += token; delim = false; break;
case "RCSP":
out += lastdelim + ph + token + sep + token;
STATE = "NORM";
ph = ""; sep = ""; fmt = ""; break;
case "RFMT":
open--;
if (open) {
fmt += token; delim = false;
break;
}
var phname = ph.trim();
var replace = phname in rep;
if (replace) {
var arr = [].concat(rep[phname]); // Ensures it's an array.
out += arr.map(dict => format(fmt, dict, debug)).join(sep);
} else {
out += lastdelim + ph + token + sep + lastdelim + fmt + token;
}
STATE = "NORM";
ph = ""; sep = ""; fmt = ""; break;
}
}
if (delim) lastdelim = token;
} else {
switch (STATE) {
case "NORM": out += token; break;
case "TXPH": ph += token; break;
case "RCPH": ph += token; break;
case "RCSP": sep += token; break;
case "RFMT": fmt += token; break;
}
}
}
switch (STATE) {
case "RCPH": case "TXPH":
out += lastdelim + ph; break;
case "RCSP": case "RFMT":
out += "[[" + ph + "]]" + sp + (fmt && ("[[" + fmt));
case "NORM": default:
}
return out;
}