Files
agenticSystem/mcp-server/utils/remoteParser.js
2026-04-01 23:16:45 +01:00

156 lines
5.3 KiB
JavaScript

import { JSDOM } from 'jsdom';
import axios from 'axios';
import vm from 'vm';
// Cache para los scripts y appParser
let appParserCache = null;
let windowCache = null;
let scriptsCache = null;
/**
* Descarga y ejecuta los scripts remotos necesarios para appParser
* Igual que en el frontend (src/main.js)
*/
async function loadRemoteParser() {
if (appParserCache) {
return { appParser: appParserCache, window: windowCache };
}
const scripts = [
"https://cms.cocosolution.com/lib/plugins/builder_saas/js/lexer.js",
"https://cms.cocosolution.com/lib/plugins/builder_saas/js/mixins/vuecomponents.js",
"https://cms.cocosolution.com/lib/plugins/builder_saas/js/mixins/builderdata.js",
"https://cms.cocosolution.com/lib/plugins/builder_saas/js/mixins/filters.js",
"https://cms.cocosolution.com/lib/plugins/builder_saas/js/parseDocument.js",
];
// Crear un contexto jsdom
const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>', {
runScripts: "dangerously",
resources: "usable"
});
const window = dom.window;
const document = window.document;
// Mock de objetos necesarios que pueden no estar en jsdom
if (!window.btoa) {
window.btoa = (str) => Buffer.from(str).toString('base64');
}
if (!window.atob) {
window.atob = (str) => Buffer.from(str, 'base64').toString();
}
// Asegurar que DOMParser esté disponible (jsdom lo tiene en window)
// Pero también lo necesitamos como variable global para los scripts
const DOMParser = window.DOMParser;
// Mock de window.bus (puede que no sea necesario para el parseo)
if (!window.bus) {
window.bus = {
$emit: () => {},
$on: () => {},
$off: () => {}
};
}
// Crear contexto VM con todas las referencias necesarias
// Los scripts remotos esperan que window, document, DOMParser, etc. estén disponibles globalmente
const context = vm.createContext({
window: window,
document: document,
DOMParser: DOMParser, // Añadir DOMParser como variable global
console: console,
Buffer: Buffer,
setTimeout: setTimeout,
setInterval: setInterval,
clearTimeout: clearTimeout,
clearInterval: clearInterval,
// Añadir todas las propiedades globales necesarias
...global,
// Asegurar que las referencias estén disponibles también como variables globales
global: global,
process: process
});
// Descargar y ejecutar cada script
for (const scriptUrl of scripts) {
try {
console.log(`Descargando script: ${scriptUrl}`);
const response = await axios.get(scriptUrl, {
timeout: 10000 // 10 segundos de timeout
});
const scriptContent = response.data;
// Ejecutar el script en el contexto VM
// Los scripts pueden usar 'window', 'document', etc. directamente
vm.runInContext(scriptContent, context);
} catch (error) {
console.error(`Error cargando script ${scriptUrl}:`, error.message);
// Si falla un script crítico, lanzar error
if (scriptUrl.includes('parseDocument.js')) {
throw new Error(`Error crítico cargando parseDocument.js: ${error.message}`);
}
// Continuar con los demás scripts para los no críticos
}
}
// Verificar que appParser esté disponible
if (!window.appParser) {
throw new Error('appParser no se cargó correctamente desde los scripts remotos');
}
appParserCache = window.appParser;
windowCache = window;
scriptsCache = scripts;
return { appParser: appParserCache, window: windowCache };
}
/**
* Obtiene appParser, cargándolo si es necesario
*/
export async function getAppParser() {
const { appParser } = await loadRemoteParser();
return appParser;
}
/**
* Wrapper para parseComponents usando appParser remoto
* Usa tipo 2 (Twig) explícitamente
* Firma real: parseComponents(code, prefixVar, type = 0)
*/
export async function parseComponents(html, moduleIds = [], listTables = [], prefixVar = "", skipBuilderData = false) {
const { appParser, window } = await loadRemoteParser();
// Setear las variables globales en el window real donde se cargó appParser
window.allModules = moduleIds;
window.tables = listTables;
// La firma real es: parseComponents(code, prefixVar, type = 0)
// Pasamos 2 (número) para Twig explícitamente
return appParser.parseComponents(html, prefixVar, 2);
}
/**
* Wrapper para generateBuilderVars usando appParser remoto
* Usa tipo 2 (Twig) explícitamente, igual que en Api.js
* Nota: El código remoto falla si previousSchema es null, así que pasamos {} en su lugar
*/
export async function generateBuilderVars(code, previousSchema = null) {
const appParser = await getAppParser();
// Pasar 2 para Twig (igual que en Api.js: parseInt(type) donde type="2")
// El código remoto falla si previousSchema es null, así que usamos {} en su lugar
const safePreviousSchema = previousSchema || {};
return appParser.generateBuilderVars(code, 2, safePreviousSchema);
}
/**
* Limpia la caché (útil para forzar recarga)
*/
export function clearCache() {
appParserCache = null;
scriptsCache = null;
}