- added VTepL => is not WIP but works better then Template.js and will replace 90% of all templates with one do the for feature

This commit is contained in:
Maurice Grönwoldt 2020-09-18 23:40:45 +02:00
parent 4c4afe3bdf
commit 170a6cc716
5 changed files with 365 additions and 1 deletions

View file

@ -1,3 +1,4 @@
/** @deprecated use VTepL instead! */
class Template { class Template {
constructor() { constructor() {
this.tpl = {}; this.tpl = {};
@ -37,4 +38,4 @@ class Template {
} }
const templateEx = /\$(.*?)\$/gm; const templateEx = /\$(.*?)\$/gm;
const templateDir = "/out/tpl/" const templateDir = "/out/tpl/"

View file

@ -0,0 +1,34 @@
'use strict';
class VTpeLCore {
constructor(options = {}) {
this.templates = {};
this.dir = options.path || '/tpl/';
this.suffix = options.suffix || 'tpl';
this.path = options.template || `${this.dir}%s.${this.suffix}`;
this.cache = options.cache === undefined ? true : options.cache;
}
async loadTemplate(name) {
let rawData = await fetch(this.path.replace('%s', name));
if (rawData.ok) {
let data = await rawData.text();
this.addTpl(name, data);
}
}
async loadArray(names) {
for (let name of names) {
await this.loadTemplate(name);
}
}
addTpl(name, content) {
let temp = this.templates[name] = new VTpeLTemplate(name, content)
temp.parseContent(this.cache);
}
renderOn(name, data) {
return this.templates[name].render(data);
}
}

View file

@ -0,0 +1,133 @@
'use strict';
class VTepLInterpreter {
constructor(parser) {
this.parser = parser;
this.data = [];
this.content = '';
}
render(data) {
let self = this;
self.data = data;
let newData = self.interpreter(self.parser.parsed);
self.data = [];
return newData[0];
}
interpreter(parsed, index = 0) {
let self = this;
let types = VParserTypes;
let tplCont = '';
for (let i = index; i < parsed.length; i++) {
let item = parsed[i],
content = item.content;
switch (item.type) {
case types.content:
tplCont += content;
break;
case types.variable:
tplCont += self.getVariable(content)
break;
case types.assign:
let data = content.split("="),
key = data.shift();
self.setVariable(data.join("=").trim(), key.trim());
break;
case types.forEach:
let d = this.handleForEach(item, parsed, i);
i = d[0];
tplCont += d[1];
break;
case types.for:
let fd = this.handleFor(item, parsed, i);
i = fd[0];
tplCont += fd[1];
break;
case types.if:
let id = this.handleIf(item, parsed, i);
i = id[0];
tplCont += id[1];
break;
case types.ifEnd:
tplCont += content;
return [tplCont, i];
case types.forEnd:
tplCont += content;
return [tplCont, i];
default:
console.warn("Invalid Type found");
break;
}
}
//this.content = tplCont;
return [tplCont, parsed.length];
}
getVariable(variable) {
if (this.data[variable]) {
return this.data[variable];
}
let split = variable.split("."),
prevVar = this.data;
for (let i = 0; i < split.length; i++) {
prevVar = prevVar[split[i]] || prevVar;
}
if (typeof prevVar === 'string') {
return prevVar;
}
return '';
}
setVariable(value, variable) {
let c = this.getVariable(value);
if (c !== '') {
value = c;
}
this.data[variable] = value;
}
handleForEach(item, parsed, i) {
let content = item.content.split(" as ");
let root = this.getVariable(content[0].trim());
let addTo = 0,
isInvalid = false;
if (root === '') {
isInvalid = true;
root = [];
}
let d = Object.keys(root),
raw = '';
for (let x of d) {
this.setVariable(root[x], content[1].trim());
let data = this.interpreter(parsed, i + 1);
addTo = data[1];
raw += data[0];
}
if (isInvalid) {
raw = '';
}
return [addTo, raw];
}
handleFor(item, parsed, ind) {
let content = item.content.split(" as "),
addTo = 0,
count = content[0].trim().split(".."),
max = parseInt(count[1]),
min = parseInt(count[0]),
newContent = '';
for (let i = min; i < max; i++) {
this.setVariable(i.toString(), content[1]);
let data = this.interpreter(parsed, ind + 1);
addTo = data[1];
newContent += data[0];
}
return [addTo, newContent];
}
handleIf(item, parsed, i) {
let data = this.interpreter(parsed, i + 1);
return [data[1], data[0]];
}
}

View file

@ -0,0 +1,178 @@
'use strict';
const VParserTypes = {
content: 0,
variable: 1,
for: 2,
forEach: 3,
forContent: 4,
forEnd: 5,
if: 6,
ifContent: 7,
ifEnd: 8,
assign: 9,
none: -1,
// operators
'!=': 100,
'==': 101,
'&&': 102,
'||': 103,
'>=': 104,
'<=': 105,
'>': 106,
'<': 107,
'+': 108,
'-': 109,
'*': 110,
'/': 111,
'%': 112
};
class VTpeLParser {
constructor(name, content) {
let self = this;
self.name = name;
self.legex = content;
self.index = 0;
self.content = '';
self.parsed = [];
self.contexts = [0];
self.allowedOperators = ['!=', '==', '&&', '||', '>=', '<=', '>', '<', '+', '-', '*', '/', '%']
}
tokenize() {
let self = this;
for (self.index = 0; self.index < self.legex.length; self.index++) {
let i = self.index,
char = self.legex.charAt(i);
if (self.nextContains('/*', i, true)) {
self.extract('*/', VParserTypes.none)
} else if (self.nextContains('//', i, true)) {
self.extract('\n', VParserTypes.none);
} else if (self.nextContains('<!--', i, true)) {
self.extract('-->', VParserTypes.none);
} else if (self.nextContains('{for(', i, true)) {
self.extract(')}', VParserTypes.for);
self.contexts.push(VParserTypes.for);
} else if (self.nextContains('{foreach(', i, true)) {
self.extract(')}', VParserTypes.forEach);
self.contexts.push(VParserTypes.forEach);
} else if (self.nextContains('{/for}', i, true)) {
self.addType(VParserTypes.forEnd);
self.contexts.pop();
} else if (self.nextContains('{if(', i, true)) {
self.extract(')}', VParserTypes.if);
self.contexts.push(VParserTypes.if);
} else if (self.nextContains('{/if}', i, true)) {
self.addType(VParserTypes.ifEnd);
self.contexts.pop();
} else if (self.nextContains('$${', i, true)) {
self.extract('}', VParserTypes.assign);
} else if (self.nextContains('${', i, true)) {
self.extract('}', VParserTypes.variable);
} else {
self.content += char;
}
}
self.addType(VParserTypes.content);
return self.parsed;
}
addType(type) {
let self = this;
let content = self.content.trim(),
instructions = self.findInstructions(type);
self.content = '';
if (type !== VParserTypes.none) {
if (type === VParserTypes.content && content === '') {
return null;
}
return self.parsed.push({
content: content,
type: type,
context: self.contexts[self.contexts.length - 1],
instructions: instructions
});
}
return null;
}
nextContains(find, index, add = false) {
let count = this.nextContainsRaw(this.legex, find, index);
if (add && count > 0) {
this.index += count;
}
return count > 0 || count === -1;
}
nextContainsRaw(raw, find, index) {
if (typeof find === "string") {
find = find.split("");
}
let count = find.length;
if (count < 1) {
return -1;
}
for (let i = 0; i < count; i++) {
let nc = raw.charAt(index + i);
if ((find[i] === '\n' && nc === undefined)) {
return count;
}
if (find[i] !== nc) {
return 0;
}
}
return count;
}
extract(findUntil = '}', type = 1) {
let self = this;
self.addType(0);
findUntil = findUntil.split("")
let content = '',
index = self.index,
legex = self.legex,
firstFind = findUntil.shift();
for (let i = self.index; i < legex.length; i++) {
let char = legex.charAt(i);
if (char === firstFind && self.nextContains(findUntil, i + 1)) {
console.debug(`[Parser][${index} > ${i}] >> ${content}`);
self.index = i + findUntil.length;
self.content = content;
self.addType(type);
return;
}
content += char;
}
throw 'Template variable at Position: ' + index + ' not closed!';
}
// @todo implement split... is needed for if statements and math stuff or get it stupid!
getOperator(string) {
let operators = [];
for (let i = 0; i < string.length; i++) {
if (this.nextContainsRaw(string, "(", i)) {
let innerCon = '';
for (let x = 0; x < string.length; x++) {
let char = string.charAt(i + x);
if (char === ')') {
break;
}
innerCon += char;
}
operators = [...operators, this.getOperator(innerCon)];
} else {
}
}
return operators;
}
findInstructions(type) {
if (type === VParserTypes.if) {
return this.getOperator(this.content);
}
return [];
}
}

View file

@ -0,0 +1,18 @@
'use strict';
class VTpeLTemplate {
constructor(name, content) {
this.name = name;
this.tpl = content;
this.parser = new VTpeLParser(name, content);
this.interpreter = new VTepLInterpreter(this.parser);
}
render(data = {}) {
return this.interpreter.render(data);
}
parseContent() {
this.parser.tokenize();
}
}