Este es un sistema sencillo de templates realizado con Node que hice como paso intermedio para adaptar nuestro ecosistema de plantillas a Twig, me permitió ir limpiando código duplicado e identificando bloques de forma rápida. La escribí desde cero y aunque es muy sencilla, funciona realmente bien. Está pensada para trabajar con plantillas php y necesita las siguientes carpetas:
/sources los archivos de texto con la extensión .tpl que generan las templates
/base Las plantillas base de las que derivan las demás.
/mods los módulos php para trabajar con los bloques
Se dividen los bloques de código susceptible de ser modificado con comentarios php con un nombre arbitrario con el siguiente formato (se pueden anidar):
<?php#bloque?> <?php#subbloque?> <?php#/subbloque?> <?php#/bloque?>
Si fuera necesario usarlos como “ancla” para añadir contenido se pueden poner bloques vacíos donde sea necesario sin problema, o añadir bloques en cualquier momento que surja la necesidad.
Primera linea>> el nombre (sin la extensión) de la plantilla base
Siguientes líneas>> modificaciones a la plantilla base.
El motor interpreta linea a linea secuencialmente, modificando el código resultado de aplicar la linea anterior, o sea que si en una línea cargamos un módulo, en las siguientes podemos modificar sus bloques cargando nuevos módulos en ellos y así hasta el infinito (o se acaben las lineas del archivo .tpl, lo primero que ocurra 🙂 ).
Una plantilla podría tener el siguiente contenido:
fr_base //coge la plantilla base/fr_base.php
head > head_orange // cambia el bloque head por el contenido de mods/head_orange.php
main + thumbs // a continuación del bloque “main” añade el modulo mods/thumbs.php
boton – //borra el bloque boton, que puede estar en cualquiera de los bloques anteriores
Toda la magia del sistema está en esta Regexp:
RegExp("<\\?php#" + origen + "\\?>((?!<\\?php#\\/\\?>).|\\r\\n|\\r|\\n)*<\\?php#\\/" + origen + "\\?>");
“Origen” es el bloque indicado a la izquierda del operador (>, + o -), con esto seleccionamos el contenido del bloque y el resto es trivial. Permite mantener los comentarios usuales en los phps porque se limita a buscar comentarios que estén cerrados con “/”
var fs = require('fs');
var glob = require('glob');
compila();
function compila() {
const util = require('util');
const glob = util.promisify(require('glob'));
glob('../cdn.landing.engine/sources/**/*.tpl', function(err, files) {
files.forEach(function(element) {
lee_plantilla(element);
});
});
}
function lee_plantilla(template) {
fs.readFile(template, (err, data, isdone) => {
data = data.toString().replace(" ", "");
if (data.charAt(data.length - 1) != "\n\n") {
data += "\n"
}
if (data.split(/[\r|\n]+/).length > 1) {
var index = 0;
data.split(/[\r|\n]+/).forEach(function(line) {
index++;
switch (index) {
case 1:
codigo = fs.readFileSync("..engine/sources/base/" + line + ".php");
break;
case data.split(/[\r|\n]+/).length:
escribe_php(codigo.toString(), template.split("/").pop())
break;
default:
codigo = interpreta(codigo.toString(), line, template);
break;
}
})
} else {
fs.readFile("../cdn.landing.engine/templates_sources/base/" + data.toString() + ".php", (err, data, isdone) => {
escribe_php(data.toString(), template.split("/").pop())
})
}
})
}
function escribe_php(contenido, destino) {
fs.writeFile("../engine/templates/" + destino.replace(".tpl", ".php"), limpiatags(contenido), function(err) {
console.log("error" + err)
});
}
function interpreta(codigo, linea, template) {
if (linea.indexOf('+') > -1) {
divisor = linea.indexOf('+');
var operador = "+";
}
if (linea.indexOf('>') > -1) {
divisor = linea.indexOf('>');
var operador = ">";
}
if (linea.indexOf('-') > -1) {
divisor = linea.indexOf('-');
var operador = "-";
}
var origen = linea.slice(0, divisor);
var destino = linea.slice(divisor + 1, linea.length);
var formula = new RegExp("<\\?php#" + origen + "\\?>((?!<\\?php#\\/\\?>).|\\r\\n|\\r|\\n)*<\\?php#\\/" + origen + "\\?>");
var a = codigo.match(formula).slice(0, -1);
new_code = fs.readFileSync("../engine/sources/mods/" + destino + ".php");
switch (operador) {
case "+":
return codigo.replace(a, (a + new_code));
break;
case ">":
return codigo.replace(a, new_code);
break;
case "-":
return codigo.replace(a, "");
break;
}
}
function limpiatags(codigo) {
var formula = new RegExp("<\\?php#((?!>).)*\\?>", "g");
var a = codigo.match(formula);
if (a) {
for (var i = 0; i < a.length; i++) {
codigo = codigo.replace(a[i], "")
}
}
return codigo.replace(/^(?:[\t ]*(?:\r?\n|\r))+/gm, "")
}