- 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:
parent
4c4afe3bdf
commit
170a6cc716
5 changed files with 365 additions and 1 deletions
|
@ -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/"
|
||||||
|
|
34
raw/javascript/templateLang/VTepLCore.js
Normal file
34
raw/javascript/templateLang/VTepLCore.js
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
133
raw/javascript/templateLang/VTepLInterpreter.js
Normal file
133
raw/javascript/templateLang/VTepLInterpreter.js
Normal 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]];
|
||||||
|
}
|
||||||
|
}
|
178
raw/javascript/templateLang/VTepLParser.js
Normal file
178
raw/javascript/templateLang/VTepLParser.js
Normal 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 [];
|
||||||
|
}
|
||||||
|
}
|
18
raw/javascript/templateLang/VTepLTemplate.js
Normal file
18
raw/javascript/templateLang/VTepLTemplate.js
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue