Understand any codebase in minutes.
CodeAtlas es una aplicación de escritorio que analiza proyectos locales y presenta su estructura y señales arquitectónicas en una interfaz navegable. La versión 1.4 suma soporte para proyectos JVM (Java y Kotlin) además de JavaScript y TypeScript.
| Campo | Valor |
|---|---|
| Versión | 1.4.0 (package.json) — visible en la barra de la app |
| Fase | v0.5 · Expansión JVM |
| Licencia | MIT |
| Sistema operativo | Artefacto en GitHub Releases | Build local (npm run electron:build) |
|---|---|---|
| Linux | .AppImage |
.AppImage y .snap |
| Windows | Instalador .exe (NSIS) y portable .exe |
.exe (NSIS y portable) |
| macOS | .dmg y .zip |
.dmg y .zip |
El CI publica .AppImage en Linux porque el .snap requiere snapcraft; localmente sí se genera con npm run electron:build.
Los binarios se generan automáticamente con GitHub Actions al crear un tag v* y se publican en GitHub Releases. Descarga el artefacto de tu sistema operativo en la última release.
Desde la v1.2.0 la app comprueba actualizaciones automáticamente y avisa dentro de la interfaz cuando hay una versión nueva. Las versiones anteriores deben actualizarse manualmente una vez.
Los binarios no están firmados: en Windows el SmartScreen y en macOS Gatekeeper mostrarán una advertencia al primer arranque (se salta con "Más información → Ejecutar de todas formas" / clic derecho → Abrir).
La v0.5 expande el análisis a proyectos JVM (Java y Kotlin):
- Detección de
pom.xml(Maven) ybuild.gradle/build.gradle.kts(Gradle) como proyectos JVM, con sus dependencias (groupId:artifactId:versiony scope). - Detección de imports Java y Kotlin, resolviendo las clases locales del propio proyecto a su archivo fuente (convención Java: nombre de archivo = nombre de clase). Los imports de la JDK y de librerías externas se conservan sin resolver.
- Detección de controladores Spring Boot (
@RestController,@Controller,@RequestMapping,@GetMapping,@PostMapping,@PutMapping,@PatchMapping,@DeleteMapping) componiendo prefijo + subruta con su método HTTP, tanto en Java como en Kotlin. - Los archivos
.java/.ktaparecen en el árbol de archivos y en el grafo como nodosfile; los imports locales generan aristasimports; los proyectos y dependencias JVM generan nodospackage/dependencycon aristasdepends-on(scopetest→development).
La v1.3 migra los detectores a un AST real (@typescript-eslint/typescript-estree):
- Imports/
require, rutas Express y variables de entorno se detectan sobre el árbol sintáctico, no por regex. - Los comentarios y strings ya no cuentan como código:
// app.get('/x')o// import './y'no generan falsos positivos. - Soporte de imports multilínea, destructuring de
process.env(const { PORT } = process.env) y template literals sin interpolación. - Los archivos con errores de sintaxis usan el escaneo por regex anterior como respaldo (nada se pierde).
- NestJS sigue con su detector heurístico (regex), ya probado y documentado.
La v1.2 añade actualizaciones automáticas:
- Comprobación de nuevas versiones al iniciar la app (via
electron-updatery GitHub Releases). - Notificación con versión nueva, botón "Descargar actualización" y progreso de descarga.
- Aviso "Reiniciar e instalar" al terminar la descarga.
- Botón "Buscar actualizaciones" en la cabecera para comprobación manual.
Usuarios con v0.1/v1.1: esas versiones no incluyen el actualizador. Instala una vez manualmente la v1.2.0 desde GitHub Releases; desde esa versión las futuras actualizaciones se notificarán solas.
La v1.1 incluye (además de todo el MVP):
- Toggle de tipos de nodo en el mapa (ocultar
dependencypor defecto). - Búsqueda de nodos por nombre, ruta o detalle con recuento de coincidencias.
- Exportación del grafo arquitectónico a un archivo JSON (
Exportar grafo). - Límite de tamaño para archivos fuente: los bundles de más de 512 KB se omiten del análisis para no degradar el rendimiento en proyectos grandes.
El núcleo del MVP incluye:
- Electron, React, TypeScript y Vite.
- Selección segura de un repositorio local mediante IPC.
- Árbol de archivos con exclusión de dependencias y artefactos de build.
- Detección y parseo de
package.json. - Detección de usos de
process.env(incluido destructuring, v1.3). - Detección de rutas Express y NestJS (decoradores
@Controller/@Get/@Posty similares), con método, ruta completa, archivo y línea. Sus límites se documentan en la sección Límites de los detectores. - Detección de imports y
require, resolviendo rutas relativas entre módulos. - Modelo de grafo común para archivos, rutas, variables, paquetes y dependencias.
- Mapa interactivo con React Flow: pan, zoom, minimapa y nodos coloreados por tipo.
- Selección de nodo: resaltado de dependencias y panel de detalles con "Depende de" / "Usado por".
- Apertura de archivo y línea en el IDE preferido: VS Code, Cursor, Windsurf, Zed, Sublime, JetBrains, Xcode y Visual Studio (detección automática).
- Manejo de directorios inaccesibles y errores de IPC.
- Análisis en un
worker_threadsdedicado: Electron nunca se congela y la interfaz muestra una barra de progreso con fases y porcentaje en vivo. - Suite automatizada del analizador con Vitest.
Desde la v1.3, los detectores de imports, rutas Express y variables de entorno analizan el AST real del archivo (@typescript-eslint/typescript-estree): los comentarios y strings ya no generan falsos positivos y los imports multilínea se detectan. Si un archivo no se puede parsear (sintaxis rota), se usa el escaneo por regex anterior como respaldo. El detector de NestJS sigue siendo heurístico (regex). La suite de pruebas cubre los comportamientos descritos aquí.
Detecta llamadas app|router|api o variables terminadas en Router/App con métodos get/post/put/patch/delete/all/use y una ruta literal. Límites:
- Solo receptores con nombres reconocibles: si el router se renombra (
const myRouter = express.Router()→myRouter.get(...)no es*Router), no se detecta. - Falsos positivos:
app.use('/estatico', express.static(...))se registra como ruta, y cualquier variable que cumpla el patrón de nombre (p. ej.userRouter.get(...)) aunque no sea Express. - Las plantillas con interpolación (
app.get(\/users/${id}`, ...)`) se omiten; las plantillas sin interpolación sí se detectan. - Los comentarios y strings ya no se detectan como rutas (desde v1.3).
Detecta decoradores @Controller, @Get, @Post, @Put, @Patch, @Delete, @Options, @Head y @All con argumento literal, componiendo prefijo del controlador y subruta. Límites:
- Los decoradores deben estar al inicio de línea (con solo espacios antes).
- Argumentos de ruta solo literales: variables y template literals no se resuelven.
- Las rutas de método sin un
@Controlleractivo previo en el archivo se ignoran. - Con varios
@Controlleren un mismo archivo, cada ruta se atribuye al último prefijo vigente.
Detecta process.env.NOMBRE, process.env['NOMBRE'] y el destructuring (const { PORT } = process.env) en código JS/TS. Límites:
- No detecta el acceso dinámico (
process.env[nombre]). - No lee archivos
.envni.env.example; solo detecta usos en el código. - Los comentarios y strings que mencionan
process.env.Xya no cuentan como uso (desde v1.3).
Detecta import, export ... from, import(...) y require(...), incluidos imports multilínea y template literals sin interpolación; resuelve specifiers relativos probando extensiones e index de carpeta. Límites:
- Los specifiers dinámicos (con interpolación) quedan sin
targetresuelto. - Los comentarios con imports ya no se detectan como imports reales (desde v1.3).
- Los specifiers de
node_modulesy los alias de tsconfig (@/...) quedan sintargetresuelto. - Solo se escanean
.js,.jsx,.ts,.tsx,.mjsy.cjs.
Detecta import de Java y Kotlin (import a.b.C;, import a.b.*;, import static a.b.C.metodo;) y resuelve a archivo local cuando la clase importada existe en el proyecto. Límites:
- La resolución asume la convención Java (nombre de archivo = nombre de clase) y el paquete declarado con
package. - Los imports de la JDK (
java.*,javax.*,jakarta.*,kotlin.*) y de librerías externas quedan sintarget. - Los imports wildcard (
a.b.*) no se resuelven a un archivo concreto. - Solo se escanean
.javay.kt.
Detecta controladores Java y Kotlin con @RestController/@Controller, prefijo @RequestMapping de clase y @GetMapping/@PostMapping/@PutMapping/@PatchMapping/@DeleteMapping (y @RequestMapping de método con method = RequestMethod.X), componiendo prefijo + subruta. Límites:
- Los argumentos de ruta deben ser literales: variables y concatenaciones no se resuelven.
- Los arrays de paths (
@RequestMapping({"/a", "/b"})) toman solo el primer elemento. @RequestMappingde método sin método HTTP explícito se ignora (no es una ruta accionable).- No se validan los imports de Spring: una anotación con el nombre correcto cuenta aunque el controlador no sea Spring real.
Detecta pom.xml (Maven) y build.gradle/build.gradle.kts (Gradle) como proyectos JVM con sus dependencias. Límites:
- Maven: parseo de tags XML simple; no resuelve properties (
${...}) ni dependencias delparent. - Gradle: solo dependencias con notación
group:artifact[:version]en la línea; no resuelveproject(...)ni catálogos de versiones. - Un
pom.xmlsingroupId/artifactIdni dependencias se ignora (inválido o incompleto).
- Lista fija de carpetas ignoradas (
node_modules,.git,dist,build…): carpetas de dependencias con otros nombres sí se escanean. - No sigue symlinks: módulos montados por symlink quedan fuera del análisis.
- Los archivos ocultos se omiten salvo
.env. - Los archivos fuente de más de 512 KB (
MAX_SOURCE_FILE_BYTES) se omiten del análisis de rutas, variables e imports (suelen ser bundles minificados). El árbol de archivos sí los sigue mostrando. - El análisis es un snapshot estático: no hay watch ni análisis incremental.
- v0.5 analiza proyectos JVM (Java y Kotlin) además de JavaScript y TypeScript.
ArchitectureGraph es un modelo de dominio serializable, independiente de React Flow, con schemaVersion: 1:
interface ArchitectureGraph {
schemaVersion: 1;
nodes: GraphNode[];
edges: GraphEdge[];
}| Tipo | Campos propios |
|---|---|
file |
path (ruta relativa) |
route |
method, routePath, location { file, line? } |
environment |
name |
package |
name, version?, manifestPath |
dependency |
name |
Todos los nodos tienen id estable (normalizado por ruta, ver normalizeGraphPath) y label legible. Los IDs son estables entre sistemas operativos: el mismo proyecto analizado en Windows, Linux o macOS produce el mismo grafo.
| Tipo | Campos propios | Significado |
|---|---|---|
imports |
specifier, location? |
archivo → archivo/dependencia |
declares-route |
location { file, line? } |
archivo → ruta |
uses-env |
— | archivo → variable de entorno |
depends-on |
scope: 'runtime' | 'development', version |
package → dependencia |
Todas las aristas tienen id, source y target (IDs de nodo).
El grafo se exporta desde la app (Exportar grafo) como JSON válido de este formato, listo para consumo externo o tests.
- Node.js 20 o superior.
- npm 10 o superior.
npm install
npm run electron:devEl comando compila el proceso principal, inicia Vite en http://localhost:5173 y abre Electron con recarga en caliente.
La suite usa proyectos temporales aislados. No analiza ni modifica repositorios reales.
# Ejecutar una vez
npm test
# Modo interactivo durante el desarrollo
npm run test:watch
# Verificar los tipos de las pruebas
npm run test:typecheckLa cobertura funcional actual incluye:
- Árbol, conteos, orden y carpetas ignoradas.
- Directorios inexistentes o sin permisos.
package.jsonraíz, paquetes anidados y JSON inválido.- Variables de entorno, agrupación y exclusiones.
- Rutas Express y NestJS, métodos HTTP, composición de prefijos y falsos positivos.
- Imports ES,
require, re-exports, resolución de extensiones e index. - IDs, nodos, relaciones y deduplicación del grafo arquitectónico.
- Integración completa mediante
analyzeProject(). - Progreso del análisis: fases, avance por archivo y rango monótono [0, 1].
- Mapeo visual: ids estables, posiciones deterministas, regiones por tipo y colores.
- Toggle de tipos: filtrado sin mutar el grafo original y conservación de aristas.
- Detección por AST: imports multilínea, destructuring de
process.env, rutas Express multilínea, y comentarios/strings ignorados en envscan, routescan e importscan. - Búsqueda: coincidencia por label y detalle, insensible a mayúsculas, y conservación de aristas.
- Límite de tamaño de archivos fuente en
collectSourceFiles.
Antes de proponer un cambio ejecuta:
npm run checkEste comando verifica tipos, ejecuta las pruebas y construye el renderer y Electron.
npm run electron:buildGenera los artefactos del sistema operativo actual en release/:
| Sistema | Comando | Artefactos |
|---|---|---|
| Linux | npm run electron:build |
.AppImage y .snap |
| Windows | npm run electron:build (en Windows) |
.exe (instalador NSIS y portable) |
| macOS | npm run electron:build (en macOS) |
.dmg y .zip |
Cada plataforma se compila en su propio sistema: Windows no se puede empaquetar desde Linux (requiere Wine) y macOS solo se empaqueta en macOS. El workflow .github/workflows/build.yml compila las tres plataformas en GitHub Actions y publica un release automáticamente al crear un tag v*. La firma se habilita configurando CSC_LINK/CSC_KEY_PASSWORD (macOS y Windows) en el CI.
En Linux, la primera vez que se ejecuta el AppImage la app se integra sola en el menú y el dock de GNOME (genera la entrada .desktop y el ícono en ~/.local/share). El acceso usa un launcher estable (~/.local/bin/codeatlas) que busca el AppImage más reciente, de modo que las actualizaciones automáticas no rompen el acceso del menú.
codeatlas/
├── electron/
│ ├── main.ts # Ventana, validación, IPC y ciclo de vida del worker
│ ├── analyzerWorker.ts # Ejecuta el análisis en worker_threads y reporta progreso
│ ├── preload.ts # API segura para el renderer
│ └── tsconfig.json
├── src/
│ ├── analyzer/
│ │ ├── astscan.ts # Parser AST compartido (typescript-estree)
│ │ ├── scanner.ts # Árbol y package.json
│ │ ├── envscan.ts # Variables de entorno (AST + fallback regex)
│ │ ├── routescan.ts # Rutas Express (AST + fallback regex)
│ │ ├── nestscan.ts # Rutas NestJS (decoradores, regex)
│ │ ├── importscan.ts # Imports y require entre módulos (AST + fallback regex)
│ │ ├── jvmimportscan.ts # Imports Java/Kotlin (paquete → archivo local)
│ │ ├── springscan.ts # Rutas Spring Boot (anotaciones, regex)
│ │ ├── jvmdepscan.ts # Proyectos JVM y dependencias (pom.xml, gradle)
│ │ ├── graph.ts # Grafo común y IDs estables
│ │ ├── types.ts # Contratos del análisis
│ │ └── index.ts # Orquestación
│ ├── editors/
│ │ └── registry.ts # IDEs soportados y builders de apertura
│ ├── platform/
│ │ └── linuxLauncher.ts # Launcher estable del AppImage y entrada .desktop
│ ├── components/
│ │ ├── TreeView.tsx
│ │ ├── GraphView.tsx # Lienzo React Flow y panel de detalles
│ │ ├── graphMapper.ts # Grafo del análisis → React Flow
│ │ └── graphLabels.ts # Etiquetas y colores por tipo
│ ├── App.tsx
│ └── main.tsx
├── tests/
│ ├── analyzer/ # Pruebas unitarias e integración
│ ├── graphview/ # Pruebas del mapeo visual
│ ├── platform/ # Pruebas del launcher de Linux
│ └── helpers/ # Fixtures temporales
├── tsconfig.json # Renderer
├── tsconfig.test.json # Pruebas
├── vite.config.mts
└── vitest.config.mts
El renderer no accede directamente a Node.js. preload.ts expone una API mínima mediante contextBridge, el proceso principal valida las entradas IPC y el analizador usa únicamente APIs de Node (fs y path).
El análisis corre en un hilo aparte (electron/analyzerWorker.ts, vía worker_threads): el proceso principal valida la ruta, lanza el worker y reenvía al renderer los eventos de progreso por IPC; el renderer no se congela aunque el proyecto sea grande.
En Linux AppImage, ensureDesktopIntegration() escribe un launcher estable (~/.local/bin/codeatlas, src/platform/linuxLauncher.ts) y una entrada .desktop que siempre apunta a ese launcher, no al AppImage versionado: así las actualizaciones automáticas no rompen el acceso del menú. El launcher busca el AppImage más reciente en el directorio de instalación y lo ejecuta.
ArchitectureGraph es un modelo de dominio serializable e independiente de React Flow. Sus IDs y rutas están normalizados para que el mismo análisis sea estable en distintos sistemas operativos. graphMapper.ts convierte el modelo en nodos y aristas de React Flow con posiciones deterministas, y GraphView.tsx lo renderiza en el mapa interactivo de módulos.
Esta separación permite mover el análisis a un worker o sustituir el motor en el futuro sin reescribir la interfaz.
Consulta CONTRIBUTING.md antes de abrir un pull request.