Created
June 15, 2021 05:30
-
-
Save ialex32x/c16055d1619e1418b98155de25d33c07 to your computer and use it in GitHub Desktop.
'parseText' in Vue.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var validDivisionCharRE = /[\w).+\-_$\]]/; | |
function parseFilters(exp) { | |
var inSingle = false; | |
var inDouble = false; | |
var inTemplateString = false; | |
var inRegex = false; | |
var curly = 0; | |
var square = 0; | |
var paren = 0; | |
var lastFilterIndex = 0; | |
var c, prev, i, expression, filters; | |
for (i = 0; i < exp.length; i++) { | |
prev = c; | |
c = exp.charCodeAt(i); | |
if (inSingle) { | |
if (c === 0x27 && prev !== 0x5C) { inSingle = false; } | |
} else if (inDouble) { | |
if (c === 0x22 && prev !== 0x5C) { inDouble = false; } | |
} else if (inTemplateString) { | |
if (c === 0x60 && prev !== 0x5C) { inTemplateString = false; } | |
} else if (inRegex) { | |
if (c === 0x2f && prev !== 0x5C) { inRegex = false; } | |
} else if ( | |
c === 0x7C && // pipe | |
exp.charCodeAt(i + 1) !== 0x7C && | |
exp.charCodeAt(i - 1) !== 0x7C && | |
!curly && !square && !paren | |
) { | |
if (expression === undefined) { | |
// first filter, end of expression | |
lastFilterIndex = i + 1; | |
expression = exp.slice(0, i).trim(); | |
} else { | |
pushFilter(); | |
} | |
} else { | |
switch (c) { | |
case 0x22: inDouble = true; break // " | |
case 0x27: inSingle = true; break // ' | |
case 0x60: inTemplateString = true; break // ` | |
case 0x28: paren++; break // ( | |
case 0x29: paren--; break // ) | |
case 0x5B: square++; break // [ | |
case 0x5D: square--; break // ] | |
case 0x7B: curly++; break // { | |
case 0x7D: curly--; break // } | |
} | |
if (c === 0x2f) { // / | |
var j = i - 1; | |
var p = (void 0); | |
// find first non-whitespace prev char | |
for (; j >= 0; j--) { | |
p = exp.charAt(j); | |
if (p !== ' ') { break } | |
} | |
if (!p || !validDivisionCharRE.test(p)) { | |
inRegex = true; | |
} | |
} | |
} | |
} | |
if (expression === undefined) { | |
expression = exp.slice(0, i).trim(); | |
} else if (lastFilterIndex !== 0) { | |
pushFilter(); | |
} | |
function pushFilter() { | |
(filters || (filters = [])).push(exp.slice(lastFilterIndex, i).trim()); | |
lastFilterIndex = i + 1; | |
} | |
if (filters) { | |
for (i = 0; i < filters.length; i++) { | |
expression = wrapFilter(expression, filters[i]); | |
} | |
} | |
return expression | |
} | |
function wrapFilter(exp, filter) { | |
var i = filter.indexOf('('); | |
if (i < 0) { | |
// _f: resolveFilter | |
return ("_f(\"" + filter + "\")(" + exp + ")") | |
} else { | |
var name = filter.slice(0, i); | |
var args = filter.slice(i + 1); | |
return ("_f(\"" + name + "\")(" + exp + (args !== ')' ? ',' + args : args)) | |
} | |
} | |
var defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g; | |
var regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g; | |
/** | |
* Create a cached version of a pure function. | |
*/ | |
function cached(fn) { | |
var cache = Object.create(null); | |
return (function cachedFn(str) { | |
var hit = cache[str]; | |
return hit || (cache[str] = fn(str)) | |
}) | |
} | |
var buildRegex = cached(function (delimiters) { | |
var open = delimiters[0].replace(regexEscapeRE, '\\$&'); | |
var close = delimiters[1].replace(regexEscapeRE, '\\$&'); | |
return new RegExp(open + '((?:.|\\n)+?)' + close, 'g') | |
}); | |
function parseText( | |
text, | |
delimiters | |
) { | |
var tagRE = delimiters ? buildRegex(delimiters) : defaultTagRE; | |
if (!tagRE.test(text)) { | |
console.error(tagRE, text); | |
return | |
} | |
var tokens = []; | |
var rawTokens = []; | |
var lastIndex = tagRE.lastIndex = 0; | |
var match, index, tokenValue; | |
while ((match = tagRE.exec(text))) { | |
index = match.index; | |
// push text token | |
if (index > lastIndex) { | |
rawTokens.push(tokenValue = text.slice(lastIndex, index)); | |
tokens.push(JSON.stringify(tokenValue)); | |
} | |
// tag token | |
var exp = parseFilters(match[1].trim()); | |
tokens.push(("_s(" + exp + ")")); | |
rawTokens.push({ '@binding': exp }); | |
lastIndex = index + match[0].length; | |
} | |
if (lastIndex < text.length) { | |
rawTokens.push(tokenValue = text.slice(lastIndex)); | |
tokens.push(JSON.stringify(tokenValue)); | |
} | |
return { | |
expression: tokens.join('+'), | |
tokens: rawTokens | |
} | |
} | |
function fn() { | |
return 1; | |
} | |
function test() { | |
return "hello"; | |
} | |
let name = "Emma"; | |
let res = parseText("TEST {{1 + 1/2 * fn()}} WITH {{test()}} AND {{name}} Self {{self.name}}", null); | |
console.log(res.expression); | |
(function () { | |
let name = "Jill"; | |
let self = { name: "(self test)" }; | |
let e = eval("(function (_s) { return " + res.expression + "; })"); | |
console.log(e((v) => new String(v))); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment