- Integración de 93 capítulos del manual completo - Componente MarkdownViewer para renderizar archivos .md - Navegación jerárquica completa (ManualIndex) - Sistema de búsqueda mejorado - Página ManualViewer con navegación anterior/siguiente - Scripts de verificación del manual - Puerto configurado en 8096 - Configuración de despliegue (Vercel, Netlify, GitHub Pages) - Todos los problemas detectados corregidos
211 lines
7.4 KiB
Python
211 lines
7.4 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Script para generar automáticamente el índice completo del Manual TES Digital
|
||
basado en los archivos .md existentes en la estructura
|
||
|
||
Uso:
|
||
python3 generar_indice.py [--salida archivo.md]
|
||
"""
|
||
|
||
import os
|
||
import re
|
||
from pathlib import Path
|
||
from typing import List, Tuple, Dict
|
||
import argparse
|
||
|
||
def extract_chapter_info(filepath: Path) -> Tuple[int, int, str]:
|
||
"""Extrae información del bloque, capítulo y nombre del archivo"""
|
||
filename = filepath.name
|
||
|
||
# Patrón: BLOQUE_XX_YY_NOMBRE.md
|
||
match = re.match(r'BLOQUE_(\d+)_(\d+|X)(?:_(.+))?\.md', filename)
|
||
if match:
|
||
block = int(match.group(1))
|
||
chapter_str = match.group(2)
|
||
|
||
if chapter_str == 'X':
|
||
chapter = None
|
||
else:
|
||
chapter = int(chapter_str)
|
||
|
||
# Extraer nombre del capítulo del nombre del archivo
|
||
name_part = match.group(3) if match.group(3) else filename.replace('.md', '')
|
||
name = name_part.replace('_', ' ').title()
|
||
|
||
return (block, chapter, name)
|
||
|
||
return (None, None, filename)
|
||
|
||
def read_title_from_file(filepath: Path) -> str:
|
||
"""Lee el título principal del archivo"""
|
||
try:
|
||
with open(filepath, 'r', encoding='utf-8') as f:
|
||
first_line = f.readline().strip()
|
||
# Extraer título después del número (ej: "# 2.0 – Anatomía...")
|
||
match = re.match(r'#\s*\d+\.\d+\s*[–-]\s*(.+)', first_line)
|
||
if match:
|
||
return match.group(1).strip()
|
||
# Si no tiene formato estándar, usar primera línea sin #
|
||
if first_line.startswith('#'):
|
||
return first_line.lstrip('#').strip()
|
||
return first_line
|
||
except:
|
||
return filepath.stem.replace('_', ' ').title()
|
||
|
||
def generate_index(source_dir: Path, output_file: Path) -> bool:
|
||
"""Genera el índice completo del manual"""
|
||
|
||
# Buscar todos los archivos .md
|
||
md_files = list(source_dir.rglob('*.md'))
|
||
|
||
# Excluir documentación interna y archivos especiales
|
||
excluded_patterns = ['_DOCUMENTACION_INTERNA', 'MAPA_MAESTRO', 'INFORME', 'ANALISIS',
|
||
'ESTANDAR', 'INDICE', 'LISTA', 'README', 'INSTALACION', 'LEEME']
|
||
md_files = [f for f in md_files if not any(pattern in str(f) for pattern in excluded_patterns)]
|
||
|
||
# Organizar por bloque
|
||
blocks: Dict[int, List[Tuple[int, Path, str]]] = {}
|
||
|
||
for md_file in md_files:
|
||
block, chapter, name = extract_chapter_info(md_file)
|
||
if block is not None:
|
||
if block not in blocks:
|
||
blocks[block] = []
|
||
|
||
# Leer título real del archivo
|
||
title = read_title_from_file(md_file)
|
||
blocks[block].append((chapter if chapter is not None else 999, md_file, title))
|
||
|
||
# Ordenar por bloque y capítulo
|
||
for block in blocks:
|
||
blocks[block].sort(key=lambda x: (x[0] if x[0] != 999 else 999, str(x[1])))
|
||
|
||
# Generar contenido del índice
|
||
content = []
|
||
content.append("# 📚 ÍNDICE COMPLETO - Manual TES Digital")
|
||
content.append("")
|
||
content.append("**Fecha de generación:** 2024-12-14")
|
||
content.append("**Versión:** 1.0 (Generado automáticamente)")
|
||
content.append("**Total de capítulos:** " + str(len(md_files)))
|
||
content.append("")
|
||
content.append("---")
|
||
content.append("")
|
||
|
||
# Nombres de bloques
|
||
block_names = {
|
||
0: "BLOQUE 0 – Fundamentos",
|
||
1: "BLOQUE 1 – Procedimientos Básicos TES",
|
||
2: "BLOQUE 2 – Material e Inmovilización",
|
||
3: "BLOQUE 3 – Material Sanitario y Oxigenoterapia",
|
||
4: "BLOQUE 4 – Soporte Vital Básico y RCP",
|
||
5: "BLOQUE 5 – Protocolos Transtelefónicos y Comunicación",
|
||
6: "BLOQUE 6 – Farmacología y Vademécum Operativo",
|
||
7: "BLOQUE 7 – Conducción y Seguridad Vial",
|
||
8: "BLOQUE 8 – Gestión Operativa y Documentación"
|
||
}
|
||
|
||
# Generar índice por bloque
|
||
for block_num in sorted(blocks.keys()):
|
||
block_files = blocks[block_num]
|
||
block_name = block_names.get(block_num, f"BLOQUE {block_num}")
|
||
|
||
content.append(f"## {block_name}")
|
||
content.append("")
|
||
|
||
if len(block_files) == 0:
|
||
content.append("**Estado:** ❌ VACÍO")
|
||
content.append("")
|
||
content.append("| # | Capítulo | Archivo | Estado |")
|
||
content.append("|---|----------|---------|--------|")
|
||
content.append("| - | - | - | ❌ Pendiente |")
|
||
else:
|
||
content.append(f"**Estado:** ✅ COMPLETO ({len(block_files)}/{len(block_files)} capítulos)")
|
||
content.append("")
|
||
content.append("| # | Capítulo | Archivo | Estado |")
|
||
content.append("|---|----------|---------|--------|")
|
||
|
||
for chapter, filepath, title in block_files:
|
||
relative_path = filepath.relative_to(source_dir)
|
||
|
||
if chapter == 999:
|
||
chapter_str = "X"
|
||
status = "✅"
|
||
else:
|
||
chapter_str = f"{block_num}.{chapter}"
|
||
status = "✅"
|
||
|
||
filename = filepath.name
|
||
content.append(f"| {chapter_str} | {title} | [`{filename}`](./{relative_path}) | {status} |")
|
||
|
||
content.append("")
|
||
content.append("---")
|
||
content.append("")
|
||
|
||
# Estadísticas
|
||
content.append("## 📊 ESTADÍSTICAS GENERALES")
|
||
content.append("")
|
||
content.append("| Bloque | Capítulos | Estado |")
|
||
content.append("|--------|-----------|--------|")
|
||
|
||
total = 0
|
||
for block_num in sorted(blocks.keys()):
|
||
count = len(blocks[block_num])
|
||
total += count
|
||
block_name = block_names.get(block_num, f"Bloque {block_num}")
|
||
status = "✅ Completo" if count > 0 else "❌ Vacío"
|
||
content.append(f"| {block_name} | {count} | {status} |")
|
||
|
||
content.append(f"| **TOTAL** | **{total}** | **{len(blocks)} bloques** |")
|
||
content.append("")
|
||
|
||
# Guardar archivo
|
||
try:
|
||
with open(output_file, 'w', encoding='utf-8') as f:
|
||
f.write('\n'.join(content))
|
||
return True
|
||
except Exception as e:
|
||
print(f"Error al guardar: {e}")
|
||
return False
|
||
|
||
def main():
|
||
parser = argparse.ArgumentParser(
|
||
description='Genera índice completo del Manual TES Digital',
|
||
formatter_class=argparse.RawDescriptionHelpFormatter
|
||
)
|
||
|
||
parser.add_argument(
|
||
'--directorio',
|
||
type=str,
|
||
default='.',
|
||
help='Directorio fuente (default: directorio actual)'
|
||
)
|
||
|
||
parser.add_argument(
|
||
'--salida',
|
||
type=str,
|
||
default='INDICE_COMPLETO_MANUAL_TES.md',
|
||
help='Archivo de salida (default: INDICE_COMPLETO_MANUAL_TES.md)'
|
||
)
|
||
|
||
args = parser.parse_args()
|
||
|
||
source_dir = Path(args.directorio).resolve()
|
||
output_file = Path(args.salida).resolve()
|
||
|
||
if not source_dir.exists():
|
||
print(f"❌ Error: El directorio no existe: {source_dir}")
|
||
return 1
|
||
|
||
print(f"Generando índice desde: {source_dir}")
|
||
print(f"Guardando en: {output_file}")
|
||
|
||
if generate_index(source_dir, output_file):
|
||
print(f"\n✅ Índice generado exitosamente: {output_file}")
|
||
return 0
|
||
else:
|
||
print("\n❌ Error al generar el índice")
|
||
return 1
|
||
|
||
if __name__ == '__main__':
|
||
exit(main())
|