@tko/provider.mustache
Version:
Interpolate text/node attributes {{ }}
88 lines (87 loc) • 2.42 kB
JavaScript
;
// @tko/provider.mustache 🥊 4.0.0-beta1.6 ESM
import {
Parser
} from "@tko/utils.parser";
const INNER_EXPRESSION = /^([\s\S]*)}}([\s\S]*?)\{\{([\s\S]*)$/;
const OUTER_EXPRESSION = /^([\s\S]*?)\{\{([\s\S]*)}}([\s\S]*)$/;
const BINDING_EXPRESSION = /^([^,"'{}()/:[\]\s]+)\s+([^\s:].*)/;
class Interpolated {
constructor(text) {
this.text = text;
}
trim(string) {
return string === null ? "" : string.trim();
}
}
class Expression extends Interpolated {
asAttr(context, globals, node) {
return new Parser().parseExpression(this.text, context, globals, node)();
}
*textNodeReplacement(textNode) {
const text = this.trim(this.text);
const ownerDocument = textNode ? textNode.ownerDocument : document;
const firstChar = text[0];
const lastChar = text[text.length - 1];
var closeComment = true;
var binding;
if (firstChar === "#") {
if (lastChar === "/") {
binding = text.slice(1, -1);
} else {
binding = text.slice(1);
closeComment = false;
}
const matches = binding.match(BINDING_EXPRESSION);
if (matches) {
binding = matches[1] + ":" + matches[2];
}
} else if (firstChar === "/") {
} else if (firstChar === "{" && lastChar === "}") {
binding = "html:" + this.trim(text.slice(1, -1));
} else {
binding = "text:" + this.trim(text);
}
if (binding) {
yield ownerDocument.createComment("ko " + binding);
}
if (closeComment) {
yield ownerDocument.createComment("/ko");
}
}
}
class Text extends Interpolated {
asAttr() {
return this.text;
}
*textNodeReplacement() {
yield document.createTextNode(this.text.replace(/"/g, '\\"'));
}
}
export function* innerParse(text) {
const innerMatch = text.match(INNER_EXPRESSION);
if (innerMatch) {
const [pre, inner, post] = innerMatch.slice(1);
yield* innerParse(pre);
yield new Text(inner);
yield new Expression(post);
} else {
yield new Expression(text);
}
}
export function* parseOuterMatch(outerMatch) {
if (!outerMatch) {
return;
}
let [pre, inner, post] = outerMatch.slice(1);
yield new Text(pre);
yield* innerParse(inner);
yield new Text(post);
}
export function* parseInterpolation(text) {
for (const textOrExpr of parseOuterMatch(text.match(OUTER_EXPRESSION))) {
if (textOrExpr.text) {
yield textOrExpr;
}
}
}