Soporte de lenguajes
18 lenguajes repartidos en dos niveles de análisis — qué extensiones reclama cada uno, a qué renuncia el nivel generic y las dos salvedades que conviene conocer antes de toparte con ellas.
--lang auto (el valor por defecto) detecta y fusiona todos los lenguajes en una sola
pasada. Casi nunca necesitas nombrar uno.
handbook analyze --source ~/code/polyglot-repo --work work/poly # one pass, all languages
handbook analyze --source ~/code/repo --work work/x --lang python # or pin oneNivel full
Adaptadores escritos a mano: resolución de llamadas guiada por tipos, miembros heredados, seguimiento de estado por atributo, spans de sentencias.
| Lenguaje | Extensiones | Clave del registro | Tipos indexados |
|---|---|---|---|
| Python | .py | python | class |
| TypeScript (y JavaScript) | .ts .tsx .js .jsx .mjs .cjs | typescript | class interface enum alias |
| Go | .go | go | struct interface alias other |
| Rust | .rs | rust | struct enum trait alias other |
| Java | .java | java | class interface enum record other |
| C# | .cs | csharp | class interface struct record enum other |
| C/C++ | .c .h .cpp .cc .cxx .c++ .hpp .hh .hxx | cpp | class struct enum alias other |
| Ruby | .rb .rake .gemspec | ruby | class other |
| PHP | .php .phtml | php | class interface enum trait |
| Swift | .swift | swift | class struct enum interface alias |
| Dart | .dart | dart | class enum trait alias other |
| Solidity | .sol | solidity | class interface struct enum other |
| Shell | .sh .bash | shell | — |
La última columna es AdapterCapabilities.typeKinds: lo que cada adaptador encuentra de
verdad, no lo que aspira a encontrar. Shell no tiene declaraciones de tipo, así que el — de
esa fila es una afirmación positiva y no una laguna. Las constantes, las variables y las macros
no se indexan en ningún lenguaje.
JavaScript no tiene un adaptador propio
Lo cubre el de TypeScript. No hay nada que elegir — .js, .jsx, .mjs y .cjs se reclaman
automáticamente.
Un solo adaptador para la familia C, no dos
La gramática cpp también maneja C; la gramática c no maneja C++ en absoluto. Así que un único adaptador
reclama ambos, y --lang cpp es lo correcto para un proyecto de C puro.
Nivel generic
Un único motor guiado por configuración, una spec declarativa por lenguaje. El inventario de archivos y funciones es exacto; las relaciones de llamada son best-effort.
| Lenguaje | Extensiones | Clave del registro |
|---|---|---|
| Kotlin | .kt .kts | kotlin |
| Scala | .scala .sc | scala |
| Zig | .zig | zig |
| Objective-C | .m | objc |
| OCaml | .ml | ocaml |
Un handbook cuyo análisis mezcla niveles lo dice en su visión general. Consulta Fidelidad del análisis para saber exactamente qué se degrada.
Dos salvedades, expuestas antes de que te topes con ellas
Swift aborta el proceso en V8 ≥ 13
La gramática de Swift incluida provoca un aborto fatal por falta de memoria en cuanto V8 sube de nivel el módulo WASM — medido como fatal 5 de 5 veces en Node 24, sin problemas en Node 21, y exclusivo de esa única gramática entre diecinueve.
En un runtime así, el adaptador se rehúsa en la fase de descubrimiento y nombra el remedio, en lugar de tumbar tu ejecución entera:
node --liftoff-only $(which handbook) analyze --source ~/code/ios-app --work work/ios--liftoff-only se salta la compilación de subida de nivel que lo desencadena. La propia
suite de tests del repositorio pasa esa misma bandera exactamente por esta razón.
Los scripts de shell que contienen case se saltan
El escáner externo de la gramática de bash fijada importa env.isalpha, que el enlazador
dinámico de web-tree-sitter@0.25.10 no proporciona, así que parse() lanza una excepción
con cualquier sentencia case — y deja el parser envenenado, por lo que el adaptador lo
descarta y sigue adelante.
Esto es más grande de lo que suena
case es omnipresente en shell. Medido sobre nvm: se
saltaron los 6 archivos y las 122 funciones. Shell figura como nivel full porque el
adaptador es de nivel full, pero trata la cobertura de shell como parcial hasta que
esa gramática se arregle upstream.
El log de escaneo lo dice explícitamente, y nombra el motivo:
[scan] shell: 5 file(s) the grammar could not parse — the pinned bash grammar throws on
`case`, which most real scripts use; their functions are absent from this graph, not
merely unresolved — install.sh, nvm.sh, …Cada uno de esos archivos aparece además nombrado individualmente en
phase1/scan-coverage.json con reason: "unparsable", y se queda fuera de los
scannedFiles del grafo — de modo que son un hueco visible en lugar de uno silencioso.
Qué se salta en todas partes
Todos los adaptadores respetan una única lista de exclusión compartida:
.git .hg .svn node_modules vendor target build dist out
__pycache__ .mypy_cache .pytest_cache .ruff_cache .tox
venv .venv env .env site-packages .idea .vscode .handbook-patchesSi tu salida de build vive en otro sitio, apunta --source a la raíz real del código
fuente en lugar de a la raíz del repositorio.
Cuando un archivo podría pertenecer a dos lenguajes
El descubrimiento ejecuta los adaptadores en un orden fijo y el primero que reclama un
archivo se lo queda; la coincidencia por extensión prefiere la más larga. En la práctica
esto solo importa para .h (reclamado por el adaptador de C/C++) y .m (Objective-C).
Leer qué se escaneó realmente
handbook analyze --source ~/code/repo --work work/x -v
# [scan] auto root=/Users/me/code/repo
# [scan] typescript: 284 files
# [scan] python: 96 files
# [scan] shell: 12 files
# [build] functions=3187 kept=9042 dropped=611jq '.metadata.languages | keys' work/x/phase1/graph.json # which tiers are in play
jq '.metadata.byCategory' work/x/phase1/dropped-calls.json # what could not be resolved
jq '.metadata.byReason, .files' work/x/phase1/scan-coverage.json # what could not be parsed at allAñadir un lenguaje
Añadir un lenguaje de nivel generic es una spec declarativa, no un parser — y no necesita ninguna dependencia nueva, porque las gramáticas ya vienen incluidas. Consulta Añadir un lenguaje.