v0.5.0
This commit is contained in:
parent
aaf7d22374
commit
8d6b53e431
@ -31,8 +31,8 @@ export class FastReportTemplateResolver {
|
||||
return this.resolveJoin([module, "templates", companySlug, languageCode]);
|
||||
}
|
||||
|
||||
// <root>/templates/<companySlug>/<module>/<languageCode>
|
||||
return this.resolveJoin([companySlug, module, languageCode]);
|
||||
// <root>/templates/<module>/<languageCode>
|
||||
return this.resolveJoin([module, languageCode]);
|
||||
}
|
||||
|
||||
/** Resuelve una ruta de recurso relativa al directorio de plantilla */
|
||||
|
||||
@ -0,0 +1,97 @@
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
|
||||
import Handlebars from "handlebars";
|
||||
import { lookup } from "mime-types";
|
||||
|
||||
import { RendererTemplateResolver } from "./renderer-template-resolver-SOBRA";
|
||||
|
||||
export class HandlebarsTemplateResolver extends RendererTemplateResolver {
|
||||
protected readonly hbs = Handlebars.create();
|
||||
protected registered = false;
|
||||
protected readonly assetCache = new Map<string, string>();
|
||||
|
||||
/**
|
||||
* Registra el helper "asset".
|
||||
*
|
||||
* - Si el fichero termina en .b64 → se asume que el contenido ya es base64
|
||||
* - Si no → se lee binario y se convierte a base64
|
||||
*/
|
||||
protected registerAssetHelper(templateDir: string) {
|
||||
// Si ya está registrado, no hacer nada
|
||||
if (this.registered) return;
|
||||
|
||||
this.hbs.registerHelper("asset", (resource: string) => {
|
||||
const assetPath = this.resolveAssetPath(templateDir, resource);
|
||||
const cacheKey = `${assetPath}`;
|
||||
|
||||
// 1) Caché en memoria
|
||||
const cached = this.assetCache.get(cacheKey);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
if (!existsSync(assetPath)) {
|
||||
throw new Error(`Asset not found: ${assetPath}`);
|
||||
}
|
||||
|
||||
// 3) Modo "base64"
|
||||
const isPreencoded = assetPath.endsWith(".b64");
|
||||
|
||||
let base64: string;
|
||||
let mimeType: string;
|
||||
let value: string;
|
||||
|
||||
if (isPreencoded) {
|
||||
// Fichero ya contiene el base64 en texto plano
|
||||
base64 = readFileSync(assetPath, "utf8").trim();
|
||||
|
||||
// Para el MIME usamos el nombre "original" sin .b64
|
||||
const mimeLookupPath = assetPath.replace(/\.b64$/, "");
|
||||
mimeType = (lookup(mimeLookupPath) || "application/octet-stream") as string;
|
||||
value = `data:${mimeType};base64,${base64}`;
|
||||
} else {
|
||||
// Fichero normal
|
||||
|
||||
// Si es un CSS no se convierte y se incrusta
|
||||
const isCSS = assetPath.endsWith(".css");
|
||||
if (isCSS) {
|
||||
const buffer = readFileSync(assetPath);
|
||||
value = buffer.toString();
|
||||
} else {
|
||||
// En otro caso, se transforma a Base64
|
||||
const buffer = readFileSync(assetPath);
|
||||
mimeType = (lookup(assetPath) || "application/octet-stream") as string;
|
||||
base64 = buffer.toString("base64");
|
||||
value = `data:${mimeType};base64,${base64}`;
|
||||
}
|
||||
}
|
||||
|
||||
this.assetCache.set(cacheKey, value);
|
||||
return value;
|
||||
});
|
||||
|
||||
this.registered = true;
|
||||
}
|
||||
|
||||
/** Compilación directa desde string (sin resolución de rutas) */
|
||||
public compile(templateSource: string) {
|
||||
return this.hbs.compile(templateSource);
|
||||
}
|
||||
|
||||
/** Localiza → lee → registra helpers → compila */
|
||||
public compileTemplate(
|
||||
module: string,
|
||||
companySlug: string,
|
||||
templateName: string
|
||||
): Handlebars.TemplateDelegate {
|
||||
// 1) Directorio de plantillas
|
||||
const templateDir = this.resolveTemplateDirectory(module, companySlug);
|
||||
const templatePath = this.resolveTemplatePath(module, companySlug, templateName); // 2) Path completo del template
|
||||
const source = this.readTemplateFile(templatePath); // Contenido
|
||||
|
||||
this.registerAssetHelper(templateDir);
|
||||
|
||||
// 5) Compilar
|
||||
return this.compile(source);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
|
||||
import type { IRendererTemplateResolver } from "../../../application";
|
||||
|
||||
import { FastReportTemplateNotFoundError } from "./fastreport";
|
||||
|
||||
/**
|
||||
* Resuelve rutas de plantillas para desarrollo y producción.
|
||||
*/
|
||||
export abstract class RendererTemplateResolver implements IRendererTemplateResolver {
|
||||
constructor(protected readonly rootPath: string) {}
|
||||
|
||||
/** Une partes de ruta relativas al rootPath */
|
||||
protected resolveJoin(parts: string[]): string {
|
||||
return join(this.rootPath, ...parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Devuelve el directorio donde residen las plantillas de un módulo/empresa
|
||||
* según el entorno (dev/prod).
|
||||
*/
|
||||
protected resolveTemplateDirectory(module: string, companySlug: string): string {
|
||||
const isDev = process.env.NODE_ENV === "development";
|
||||
|
||||
if (isDev) {
|
||||
// <root>/<module>/templates/<companySlug>/
|
||||
return this.resolveJoin([module, "templates", companySlug]);
|
||||
}
|
||||
|
||||
// <root>/templates/<module>/<companySlug>/
|
||||
//return this.resolveJoin(["templates", module, companySlug]);
|
||||
return this.resolveJoin([module]);
|
||||
}
|
||||
|
||||
/** Resuelve una ruta de recurso relativa al directorio de plantilla */
|
||||
protected resolveAssetPath(templateDir: string, relative: string): string {
|
||||
return join(templateDir, relative);
|
||||
}
|
||||
|
||||
/**
|
||||
* Devuelve la ruta absoluta del fichero de plantilla.
|
||||
*/
|
||||
public resolveTemplatePath(module: string, companySlug: string, templateName: string): string {
|
||||
const dir = this.resolveTemplateDirectory(module, companySlug);
|
||||
const filePath = this.resolveAssetPath(dir, templateName);
|
||||
|
||||
if (!existsSync(filePath)) {
|
||||
throw new FastReportTemplateNotFoundError(
|
||||
`Template not found: module=${module} company=${companySlug} name=${templateName}`
|
||||
);
|
||||
}
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
/** Lee el contenido de un fichero plantilla */
|
||||
protected readTemplateFile(templatePath: string): string {
|
||||
return readFileSync(templatePath, "utf8");
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_VERSION="1.2.8"
|
||||
SCRIPT_VERSION="1.2.9"
|
||||
|
||||
# =====================================================
|
||||
# FACTUGES Build Script
|
||||
@ -194,6 +194,7 @@ if [[ "$MODE" == "api" || "$MODE" == "all" ]]; then
|
||||
# Recopilar plantillas
|
||||
${SCRIPT_DIR}/build-templates.sh ${COMPANY}
|
||||
TEMPLATES_DIR="${PROJECT_DIR}/out/${COMPANY}/templates"
|
||||
echo "📑 Plantillas ${TEMPLATES_DIR}"
|
||||
|
||||
cd "${PROJECT_DIR}"
|
||||
echo "🐳 Construyendo imagen Docker..."
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_VERSION="0.0.2"
|
||||
SCRIPT_VERSION="0.0.3"
|
||||
|
||||
# =====================================================
|
||||
# TEMPLATES Build Script
|
||||
@ -54,7 +54,7 @@ rm -rf "${TARGET_DIR:?}/"*
|
||||
for module in "$SOURCE_DIR"/*; do
|
||||
if [ -d "$module/templates/$COMPANY" ]; then
|
||||
module_name=$(basename "$module")
|
||||
echo "→ Copying templates for module: $module_name"
|
||||
echo "📑 → Copying templates for module: $module_name"
|
||||
|
||||
mkdir -p "$TARGET_DIR/$module_name"
|
||||
cp -Rv "$module/templates/$COMPANY/." "$TARGET_DIR/$module_name/"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user