Sintaxis de plantillas

Las plantillas son archivos .docx editables con Microsoft Word o LibreOffice. El motor de render es docxtemplater. Se soporta dot-notation (ej. {persona.nombre}), loops, condicionales e imágenes con reglas estrictas de tamaño.

Variables simples

Encierra el nombre del campo entre llaves:

plantilla.docx
Folio: {folio}
Cliente: {cliente.nombre}
Importe total: {total}
data
{
  "folio": "F-001",
  "cliente": { "nombre": "Acme S.A." },
  "total": 1500
}

Dot-notation (objetos anidados)

Funciona con cualquier nivel de anidamiento: {a.b.c.d}. Si el path no resuelve, sale string vacío (no aparece la palabra "undefined" en el documento).

plantilla.docx
Generado por {persona.nombre} {persona.primer_apellido} {persona.segundo_apellido}

Loops

Usa {#variable}...{/variable}. La variable debe ser un array. Dentro del loop, cada elemento del array se vuelve el scope.

plantilla.docx
Conceptos:
{#items}
- {descripcion} (cantidad: {cantidad})
{/items}
data
{
  "items": [
    { "descripcion": "Servicio mensual", "cantidad": 12 },
    { "descripcion": "Soporte premium",  "cantidad": 1  }
  ]
}

Loops dentro de tablas Word

Para repetir filas de tabla, pon {#items} al inicio de la primera celda de la fila plantilla y {/items} al final de la última celda. docxtemplater detecta el patrón y duplica la fila completa por cada elemento.

Condicionales

Misma sintaxis que loops, pero con un valor escalar truthy/falsy. Si el valor es true, número distinto de cero, o string no vacío, el bloque se renderiza. Si es false, null, undefined,0 o array vacío, se omite.

plantilla.docx
{#descuento}Descuento aplicado: {descuento}%{/descuento}

Imágenes

Usa el prefijo % en el tag: {%logo}. El valor en data.logo debe ser uno de:

  • Data URI base64: data:image/png;base64,...
  • URL HTTP/HTTPS: ej. https://cdn.clickbalance.com/logo.png. Pasa por SSRF guard (rechaza IPs privadas, loopback, link-local).
  • Ruta relativa a IMAGES_DIR: ej. logos/empresa-acme.png. La carpeta se monta como volumen externo.
Regla obligatoria de placement

Toda etiqueta {%tag} debe estar en una celda de tabla 1×1.

El ancho de la celda determina el ancho de la imagen renderizada. La altura se calcula automáticamente respetando el aspect ratio nativo del archivo (PNG/JPEG/GIF). Si pones la etiqueta fuera de una tabla, el render falla con RENDER_ERROR:

{
  "error": {
    "code": "RENDER_ERROR",
    "message": "Image placeholders {%tag} must be inside a 1x1 table cell. Found outside a cell: {%logo}",
    "details": { "orphans": ["logo"] }
  }
}

Cómo crear la celda en Word

  1. Posiciónate donde quieres la imagen.
  2. Insert → Table → 1 fila × 1 columna.
  3. Ajusta el ancho de la columna al ancho deseado para la imagen.
  4. Dentro de la celda, escribe {%logo}.
  5. Opcional: oculta los bordes de la tabla si no los quieres visibles.

Límites

  • Tamaño máx por imagen: MAX_IMAGE_MB (default 5 MB).
  • Timeout de fetch HTTP: HTTP_FETCH_TIMEOUT_MS (default 10 s).
  • SSRF: se rechazan rangos 10/8, 127/8, 169.254/16, 172.16/12, 192.168/16, ::1, fc00::/7, fe80::/10.

Sintaxis completa de docxtemplater

La referencia completa está en docxtemplater.com/docs/tag-types. Lo que no está activado en este servicio:

  • Inverted sections ({^items}...{/items}) — funcionan, sólo no documentadas aquí.
  • Custom angular-expressions — usamos un parser de dot-notation simple, no expresiones aritméticas.
  • Subtemplates — no soportados.