Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Procesadorv3 #20

Merged
merged 5 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 6 additions & 27 deletions aplicaciones/procesador/fuente/ayudas.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { writeFileSync } from 'fs';
import colores from 'cli-color';
import { emojify } from 'node-emoji';
import slugificar from 'slug';
import type { ElementoLista } from '@/tipos/compartidos';

export const logError = colores.red.bold;
export const logAviso = colores.bold.xterm(214);
Expand Down Expand Up @@ -30,28 +28,6 @@ export const guardarJSON = (json: any, nombre: string) => {
*/
export const limpiarTextoSimple = (texto: string) => texto.trim().replace(/[\n\r\s\t]+/g, ' ');

export function procesarLista(valor: string, lista: ElementoLista[]) {
if (!valor) return;
const slug = valor ? slugificar(`${valor}`) : '';
const existe = lista.find((obj) => obj.slug === slug);
if (!valor || valor === 'No aplica' || valor === 'undefined' || valor === 'Sin Información' || valor === '(s.f)')
return;
const nombre = `${valor}`.trim();

if (!existe) {
const objeto: ElementoLista = {
nombre: nombre,
conteo: 1,
slug: slug,
relaciones: [],
publicaciones: [],
};
lista.push(objeto);
} else {
existe.conteo++;
}
}

export function ordenarListaObjetos(lista: any[], llave: string, descendente = false) {
lista.sort((a, b) => {
if (a[llave] < b[llave]) return descendente ? -1 : 1;
Expand All @@ -61,10 +37,10 @@ export function ordenarListaObjetos(lista: any[], llave: string, descendente = f
}

export const normalizar = (texto: string): string => {
return texto;
/* .toLocaleLowerCase()
return texto
.toLocaleLowerCase()
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, ''); */
.replace(/[\u0300-\u036f]/g, '');
};

export const enMinusculas = (texto: string) => texto === texto.toLowerCase();
Expand All @@ -78,3 +54,6 @@ export function separarPartes(entrada: string, separador?: string) {
export function mensajeExito(mensaje: string) {
console.log(chulo, logAviso(mensaje));
}

export const esNumero = (valor: string | number): boolean => !isNaN(parseInt(`${valor}`));
export const esFecha = (valor: string) => !isNaN(new Date(valor).getTime());
35 changes: 14 additions & 21 deletions aplicaciones/procesador/fuente/procesador.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { alerta, chulo, guardarJSON, logAviso, logNaranjaPulso } from './ayudas'
import { procesarIndicadores, procesarSubindicadores } from './indicadores';
import procesadorColectivos from './procesadorColectivos';
import procesadorPublicaciones from './procesadorPublicaciones';
import type { Errata } from './tipos';

async function inicio() {
/** Extraer diccionario de indicadores */
Expand All @@ -10,33 +11,25 @@ async function inicio() {
const subindicadores = await procesarSubindicadores(indicadores.datos);
const publicaciones = await procesadorPublicaciones(indicadores.datos, subindicadores.datos);

if (indicadores.errata.length) {
guardarJSON(indicadores.datos, `indicadores-produccionAcademica`);
console.log(
alerta,
logNaranjaPulso(
`Procesados indicadores (con ${indicadores.errata.length} errores, ver archivo: errataIndicadores.json)`
)
);
guardarJSON(indicadores.errata, 'errataIndicadores');
} else {
guardarJSON(indicadores.datos, `indicadores-produccionAcademica`);
console.log(chulo, logAviso('Procesados indicadores'));
}
guardar(indicadores.datos, indicadores.errata, 'indicadores-produccionAcademica', 'errataIndicadores');
guardar(subindicadores.datos, subindicadores.errata, 'subIndicadores-produccionAcademica', 'errataSubIndicadores');
guardar(publicaciones.datos, publicaciones.errata, 'publicaciones', 'errataPublicaciones');
}

inicio().catch(console.error);

if (subindicadores.errata.length) {
guardarJSON(subindicadores.datos, `subIndicadores-produccionAcademica`);
function guardar(datos: any, errata: Errata[], nombre: string, nombreErrata = `errata${nombre}`) {
if (errata.length) {
guardarJSON(datos, nombre);
console.log(
alerta,
logNaranjaPulso(
`Procesados subindicadores (con ${subindicadores.errata.length} errores, ver archivo: errataSubIndicadores.json)`
`Procesados ${nombre} (con ${errata.length} error${errata.length > 1 ? 'es' : ''}, ver archivo: ${nombreErrata}.json)`
)
);
guardarJSON(subindicadores.errata, 'errataSubIndicadores');
guardarJSON(errata, nombreErrata);
} else {
guardarJSON(subindicadores.datos, `subIndicadores-produccionAcademica`);
console.log(chulo, logAviso('Procesados subindicadores'));
guardarJSON(datos, nombre);
console.log(chulo, logAviso(`Procesados ${nombre}`));
}
}

inicio().catch(console.error);
171 changes: 97 additions & 74 deletions aplicaciones/procesador/fuente/procesadorPublicaciones.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { getXlsxStream } from 'xlstream';
import slugificar from 'slug';
import { separarPartes, ordenarListaObjetos, guardarJSON, procesarLista, limpiarTextoSimple } from './ayudas';
import { separarPartes, ordenarListaObjetos, guardarJSON, limpiarTextoSimple, esNumero } from './ayudas';
import type {
CamposPA,
DefinicionSimple,
ElementoLista,
ElementoListaIndicadores,
Indicador,
ListasPublicaciones,
Expand Down Expand Up @@ -49,46 +50,44 @@ export default async (

flujo.on('data', async ({ raw }) => {
const fila = raw.arr as FilaProduccionAcademica;
const id = fila[0];
const autores = fila[1]?.includes(';') ? separarPartes(fila[1], ';') : [fila[1]?.trim()];
const resumen = fila[2] ? fila[2].trim() : '';
const años = fila[3] ? fila[3] : '';
const tipos = fila[4] ? fila[4].trim() : '';
const titulo = fila[5] ? fila[5].trim() : '';
const referencia = fila[6] ? fila[6].trim() : '';
const fuente = fila[7] ? fila[7] : '';
const dependencia = fila[8] ? fila[8].trim() : '';
// POR HACER: Procesar indicadores y subindicadores
const indicador = fila[9] ? fila[9].trim() : '';
const subindicador = fila[10] ? fila[10].trim() : '';

const publicacion = procesarFila(raw.arr, numeroFila);
publicaciones.push(publicacion);

// Llenar listas
procesarLista(dependencia, listas.dependencias);
procesarLista(tipos, listas.tipos);
procesarLista(años, listas.años);
procesarLista(subindicador, listas.subindicadores);
procesarListaIndicadores(indicador);

for (let fila in autores) {
procesarLista(autores[fila]!, listas.autores); //¿Qué forma mejor hay de hacer esto sin forzar con '!'?
}
if (publicacion) {
publicaciones.push(publicacion);
// Llenar listas
procesarLista(fila[8], listas.dependencias);
procesarLista(fila[4], listas.tipos);
procesarLista(fila[3], listas.años);
procesarLista(fila[10], listas.subindicadores);
procesarListaIndicadores(fila[9]);

if (fila[1]) {
const autores = fila[1].includes(';') ? separarPartes(fila[1], ';') : [fila[1].trim()];

autores.forEach((autor) => {
if (autor) {
procesarLista(autor, listas.autores);
} else {
errata.push({
fila: numeroFila,
error: `No hay autor en la parte: ${autor} dentro del campo autores ${fila[1]}`,
});
}
});
}

for (const lista in listas) {
ordenarListaObjetos(listas[lista as keyof ListasPublicaciones], 'slug', true);
for (const lista in listas) {
ordenarListaObjetos(listas[lista as keyof ListasPublicaciones], 'slug', true);
}
}

imprimirErratas(autores, años, tipos, titulo, dependencia, numeroFila);
numeroFila++;
});

flujo.on('close', () => {
// Aquí ya terminó de leer toda la tabla
construirRelacionesDePublicaciones(publicaciones);

guardarJSON(publicaciones, 'publicaciones');
guardarJSON(listas, 'listas');
resolver({ datos: publicaciones, errata });
});
Expand All @@ -98,9 +97,23 @@ export default async (
});
});

function procesarFila(fila: FilaProduccionAcademica, numeroFila: number): Publicacion {
const tituloPublicacion = fila[5] ? limpiarTextoSimple(fila[5]) : '';
const autores = fila[1]?.includes(';') ? separarPartes(fila[1], ';') : [fila[1]?.trim()];
function procesarFila(fila: FilaProduccionAcademica, numeroFila: number): Publicacion | undefined {
if (!fila[0] || !esNumero(fila[0])) {
errata.push({ fila: numeroFila, error: `La fila no tiene ID o no es un número` });
return;
}

if (!fila[5]) {
errata.push({
fila: numeroFila,
error: `La fila no tiene titulo de publicación, el valor de la celda es ${fila[5]}`,
});

return;
}

const tituloPublicacion = limpiarTextoSimple(fila[5]);

const subindicador = fila[10] ? fila[10].trim() : '';

if (!subindicador) {
Expand All @@ -115,23 +128,40 @@ export default async (
console.log(`No existe el subindicador ${subindicador} en la lista de subindicadores procesados`);
}

// Convertir autores en tipo DefinicionSimple
const autoresProcesados = autores.map((autor) => {
return { nombre: autor ? autor : '', slug: autor ? slugificar(autor) : '' };
});
const autores: DefinicionSimple[] = [];

const indicador = indicadores.find((obj) => {
return slugificar(fila[9].trim()) === obj.slug;
});
if (fila[1]) {
const partes = fila[1].includes(';') ? separarPartes(fila[1], ';') : [fila[1].trim()];
// Convertir autores en tipo DefinicionSimple
partes.forEach((nombreAutor) => {
autores.push({ nombre: nombreAutor, slug: slugificar(nombreAutor) });
});
}

const indicador = indicadores.find((obj) => slugificar(fila[9].trim()) === obj.slug);

let años: number | undefined;

if (fila[3] && esNumero(fila[3])) {
años = +fila[3];
} else {
// Sólo registrar errata si la celda de fecha no tiene nada o es distinto a las convenciones que se usan para indicar que no hay fecha.
if (fila[3] !== '(s.f)') {
errata.push({
fila: numeroFila,
error: `No hay fecha para la publicación, el valor en la celda es: ${fila[3]}`,
});
}
}

// En la tabla todas las publicaciones parecen tener subindicador pero muchos son el mismo indicador repetido.
// Aquí estoy borrando el campo subindicador si es el mismo indicador y no un subindicador
const respuesta: Publicacion = {
id: +fila[0],
titulo: { nombre: tituloPublicacion, slug: slugificar(tituloPublicacion) },
resumen: fila[2] ? fila[2].trim() : '',
autores: autoresProcesados,
años: { año: +fila[3], valor: fila[3] },
autores,
años,
tipos: { nombre: fila[4].trim(), slug: slugificar(fila[4].trim()) },
referencia: fila[6] ? fila[6].trim() : '',
fuente: fila[7] ? fila[7] : '',
Expand All @@ -156,16 +186,16 @@ export default async (
}

function procesarListaIndicadores(indicador: string) {
const slug = indicador ? slugificar(indicador) : '';
const existe = listas.indicadores.find((obj) => obj.slug === slug);

if (!indicadores.length) {
console.log('No hay indicadores procesados');
}

const slug = indicador ? slugificar(indicador) : '';
const existe = listas.indicadores.find((obj) => obj.slug === slug);
const existeEnIndicadoresProcesados = indicadores.find((obj) => obj.slug === slug);

if (existeEnIndicadoresProcesados) {
const nombre = existeEnIndicadoresProcesados.nombre;
const { nombre } = existeEnIndicadoresProcesados;
if (!existe) {
const objeto: ElementoListaIndicadores = {
nombre: nombre,
Expand All @@ -182,35 +212,6 @@ export default async (
}
};

function imprimirErratas(
autores: (string | undefined)[],
años: string | number | undefined,
tipos: string,
titulo: string,
dependencia: string,
numeroFila: number
) {
// Imprimir datos que faltan
for (const fila in autores) {
if (!autores[fila]) {
console.log('sin autor: ', numeroFila);
}
}

if (!años) {
console.log('sin fecha: ', numeroFila);
}
if (!tipos) {
console.log('sin tipo: ', numeroFila);
}
if (!titulo) {
console.log('sin titulo: ', numeroFila);
}
if (!dependencia) {
console.log('sin dependencia: ', numeroFila);
}
}

// Ver haciendocaminos procesador.ts 240
function construirRelacionesDePublicaciones(publicaciones: Publicacion[]) {
for (const lista in listas) {
Expand Down Expand Up @@ -277,3 +278,25 @@ function construirRelacionesDePublicaciones(publicaciones: Publicacion[]) {
});
});
}

export function procesarLista(valor: string, lista: ElementoLista[]) {
if (!valor) return;
const slug = valor ? slugificar(`${valor}`) : '';
const existe = lista.find((obj) => obj.slug === slug);
if (!valor || valor === 'No aplica' || valor === 'undefined' || valor === 'Sin Información' || valor === '(s.f)')
return;
const nombre = `${valor}`.trim();

if (!existe) {
const objeto: ElementoLista = {
nombre: nombre,
conteo: 1,
slug: slug,
relaciones: [],
publicaciones: [],
};
lista.push(objeto);
} else {
existe.conteo++;
}
}
5 changes: 2 additions & 3 deletions aplicaciones/procesador/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@
},
"devDependencies": {
"@types/cli-color": "^2.0.6",
"@types/node": "^22.5.4",
"@types/node": "^22.7.4",
"@types/slug": "^5.0.9",
"nodemon": "^3.1.4",
"nodemon": "^3.1.7",
"rimraf": "^6.0.1",
"slug": "^9.1.0",
"ts-node": "^10.9.2",
"typescript": "^5.5.4",
"xlstream": "^2.5.5"
},
"nodemonConfig": {
Expand Down
1 change: 1 addition & 0 deletions aplicaciones/www/estaticos/datos/errataPublicaciones.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"fila":249,"error":"No hay fecha para la publicación, el valor en la celda es: undefined"}]
2 changes: 1 addition & 1 deletion aplicaciones/www/estaticos/datos/listas.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion aplicaciones/www/estaticos/datos/publicaciones.json

Large diffs are not rendered by default.

Loading