Saltar al contenido
AZ Tools

Probador de EditorConfig

Un .editorconfig no se lee de arriba abajo, sino desde el archivo hacia arriba. Cada directorio entre el archivo fuente y la raíz del disco puede contener uno; la búsqueda solo se detiene en el que declara root = true en su preámbulo; el archivo más cercano gana propiedad a propiedad; y dentro de un mismo archivo gana la última sección que coincide, sin ninguna noción de regla más específica. Esas cuatro reglas tirando en direcciones distintas explican por qué la pregunta «¿por qué este archivo se indenta con cuatro espacios?» casi nunca se responde en la línea que estás mirando. Esta herramienta toma la configuración —o varias, cada una introducida por una línea marcador «# path: src/.editorconfig»— y una lista de rutas. Para cada ruta muestra el conjunto de propiedades resuelto con el archivo, la línea y el glob de la sección que produjo cada valor, la cadena de archivos consultados al subir y el punto donde root = true la cortó. La coincidencia usa el glob de EditorConfig, que no es fnmatch ni el de gitignore. Un solo * se detiene en la barra y ** la cruza; ? es un carácter que no sea barra; [abc] y [!abc] son clases de caracteres que dejan de serlo en cuanto aparece una barra dentro; {js,ts} es alternancia mientras que {js} a solas coincide con esos tres caracteres literales; {1..10} acepta cualquier entero del rango, negativos incluidos, y rechaza un cero a la izquierda. Y la regla que casi todo el mundo falla: un glob con una barra en cualquier posición salvo el final queda anclado al directorio de su propio .editorconfig, mientras que uno sin barra compara solo el nombre del archivo, a cualquier profundidad. Tres valores del resultado no suelen estar escritos en ninguna parte. indent_size pasa a valer tab cuando indent_style es tab y no se indicó tamaño; tab_width copia a indent_size cuando este es un número; e indent_size toma tab_width cuando vale la palabra tab. Los tres se aplican después de fusionar, así que un tab_width del archivo raíz puede acabar alimentando un indent_size escrito tres directorios más abajo; esas filas se marcan como derivadas e indican la línea de origen. El panel de hallazgos señala lo que el archivo no puede contarte: una sección que no coincide con ninguna de tus rutas, un valor que se define y siempre pierde, indent_size sin indent_style, un {js, ts} cuyo espacio forma parte de la comparación, un nombre de sección repetido, una clave fuera de las nueve estándar, un valor que su propiedad no acepta, una propiedad escrita antes de la primera sección (que se descarta en silencio) y la falta de root = true, que deja en juego cualquier .editorconfig de tu directorio personal. Lo que no puede decirte: si tu editor respeta todo esto. El soporte depende del plugin —max_line_length y varios valores de charset se ignoran a menudo— y unset se entrega al plugin como el valor literal unset para que actúe. «No coincide con nada» también significa solo dentro de las rutas que pegaste, así que usa una lista representativa. Todo se ejecuta en tu navegador; no se sube ningún archivo.

Archivos de configuración

2

Secciones

6

Rutas

8

Hallazgos

1

src/app.js

Cadena de búsqueda: .editorconfig · detenida por root = true

PropiedadValorDefinida en
charsetutf-8.editorconfig:4 [*]
end_of_linelf.editorconfig:5 [*]
indent_size2.editorconfig:8 [*]
indent_stylespace.editorconfig:7 [*]
insert_final_newlinetrue.editorconfig:6 [*]
tab_width2derivada: no está escrita en ningún archivo.editorconfig:8 [*]copiada de indent_size, que no tenía tab_width al lado
lib/util.js

Cadena de búsqueda: .editorconfig · detenida por root = true

PropiedadValorDefinida en
charsetutf-8.editorconfig:4 [*]
end_of_linelf.editorconfig:5 [*]
indent_size4.editorconfig:20 [lib/**.js]sustituye a .editorconfig:8
indent_stylespace.editorconfig:7 [*]
insert_final_newlinetrue.editorconfig:6 [*]
tab_width4derivada: no está escrita en ningún archivo.editorconfig:20 [lib/**.js]copiada de indent_size, que no tenía tab_width al lado
lib/deep/util.min.js

Cadena de búsqueda: .editorconfig · detenida por root = true

PropiedadValorDefinida en
charsetutf-8.editorconfig:4 [*]
end_of_linelf.editorconfig:5 [*]
indent_size4.editorconfig:20 [lib/**.js]sustituye a .editorconfig:8
indent_stylespace.editorconfig:7 [*]
insert_final_newlinetrue.editorconfig:6 [*]
tab_width4derivada: no está escrita en ningún archivo.editorconfig:20 [lib/**.js]copiada de indent_size, que no tenía tab_width al lado
main.py

Cadena de búsqueda: .editorconfig · detenida por root = true

PropiedadValorDefinida en
charsetutf-8.editorconfig:4 [*]
end_of_linelf.editorconfig:5 [*]
indent_size4.editorconfig:11 [*.{py,rs}]sustituye a .editorconfig:8
indent_stylespace.editorconfig:7 [*]
insert_final_newlinetrue.editorconfig:6 [*]
tab_width4derivada: no está escrita en ningún archivo.editorconfig:11 [*.{py,rs}]copiada de indent_size, que no tenía tab_width al lado
Makefile

Cadena de búsqueda: .editorconfig · detenida por root = true

PropiedadValorDefinida en
charsetutf-8.editorconfig:4 [*]
end_of_linelf.editorconfig:5 [*]
indent_size2.editorconfig:8 [*]
indent_styletab.editorconfig:17 [Makefile]sustituye a .editorconfig:7
insert_final_newlinetrue.editorconfig:6 [*]
tab_width2derivada: no está escrita en ningún archivo.editorconfig:8 [*]copiada de indent_size, que no tenía tab_width al lado
docs/guide.md

Cadena de búsqueda: .editorconfig · detenida por root = true

PropiedadValorDefinida en
charsetutf-8.editorconfig:4 [*]
end_of_linelf.editorconfig:5 [*]
indent_size2.editorconfig:8 [*]
indent_stylespace.editorconfig:7 [*]
insert_final_newlinetrue.editorconfig:6 [*]
tab_width2derivada: no está escrita en ningún archivo.editorconfig:8 [*]copiada de indent_size, que no tenía tab_width al lado
trim_trailing_whitespacefalse.editorconfig:14 [*.{md, txt}]
notes.txt

Cadena de búsqueda: .editorconfig · detenida por root = true

PropiedadValorDefinida en
charsetutf-8.editorconfig:4 [*]
end_of_linelf.editorconfig:5 [*]
indent_size2.editorconfig:8 [*]
indent_stylespace.editorconfig:7 [*]
insert_final_newlinetrue.editorconfig:6 [*]
tab_width2derivada: no está escrita en ningún archivo.editorconfig:8 [*]copiada de indent_size, que no tenía tab_width al lado
vendor/jquery.js

Cadena de búsqueda: vendor/.editorconfig → .editorconfig · detenida por root = true

PropiedadValorDefinida en
charsetutf-8.editorconfig:4 [*]
end_of_linelf.editorconfig:5 [*]
indent_size2.editorconfig:8 [*]
indent_styletabvendor/.editorconfig:2 [*]sustituye a .editorconfig:7
insert_final_newlinetrue.editorconfig:6 [*]
tab_width4vendor/.editorconfig:3 [*]
trim_trailing_whitespacefalsevendor/.editorconfig:4 [*]
Hallazgos

Cada línea es un punto donde el archivo hace algo distinto de lo que aparenta.

  • .editorconfig:13 — un espacio dentro de las llaves forma parte de la cadena que se compara: [*.{md, txt}]

La resolución sigue a editorconfig-core; los nombres de sección distinguen mayúsculas. No se sube nada.

Cómo usar

  1. Pega el .editorconfig en el primer cuadro. Si tienes varios archivos, introduce cada uno con una línea marcador como «# path: vendor/.editorconfig» y pon primero el de la raíz del proyecto.
  2. Escribe las rutas a probar en el segundo cuadro, una por línea, relativas a la raíz del proyecto: el directorio que contiene el .editorconfig superior.
  3. Lee la tabla de cada ruta: la propiedad, el valor resuelto y el archivo, la línea y el glob de la sección que lo definió. Una fila marcada como derivada no está escrita en ningún archivo; la nota indica qué regla la produjo.
  4. Revisa la cadena de búsqueda sobre cada tabla: los .editorconfig consultados, del más cercano al más lejano, y si root = true detuvo el recorrido o este continuaría por encima de tu proyecto.
  5. Repasa el panel de hallazgos. Cada entrada apunta a un archivo y una línea donde la configuración hace algo distinto de lo que aparenta: una sección muerta, un ajuste que nunca gana, un espacio dentro de unas llaves.

Preguntas frecuentes

¿Por qué mi archivo usa cuatro espacios si [*] dice dos?
Porque ganó algo posterior o más cercano, y en EditorConfig no hay una jerarquía de especificidad a la que apelar. Dentro de un archivo gana la última sección que coincide, así que un bloque [*.py] veinte líneas más abajo sustituye sin avisar a tu bloque [*], igual que un segundo bloque [*] más abajo: por eso importa un nombre de sección repetido. Entre archivos gana, propiedad a propiedad, el .editorconfig más cercano, de modo que un archivo de dos líneas en el directorio que estás editando vence al archivo cuidado de la raíz. El orden y la distancia son toda la historia, y eso es justo lo que informa la columna «Definida en»: el archivo, la línea y el glob de la sección que produjo el valor, con los ajustes a los que venció listados debajo.
¿Qué diferencia hay entre [*.js], [lib/*.js] y [**/*.js]?
La presencia de una barra, y nada más. Un glob sin barra se compara solo con el nombre del archivo a cualquier profundidad, así que [*.js] cubre src/a.js y vendor/dist/b.js por igual. En cuanto el glob contiene una barra en cualquier posición salvo el final, queda anclado al directorio del .editorconfig que lo contiene: [lib/*.js] coincide con lib/a.js y no con lib/sub/a.js, ni con src/lib/a.js. [**/*.js] es la forma anclada que cruza directorios, porque ** atraviesa las barras donde un solo * se detiene, y el /**/ intermedio también representa la ausencia de directorio, de modo que coincide tanto con a.js como con lib/sub/a.js. Una trampa final: una barra al final, como en [lib/], no coincide con nada, porque la ruta de un archivo nunca termina en barra. El subárbol se escribe [lib/**].
¿De dónde salen indent_size = tab y tab_width si nunca los escribí?
De las reglas de reserva que el núcleo aplica después de fusionarlo todo. Si indent_style es tab y no se definió indent_size, indent_size pasa a ser la palabra tab. Si indent_size es un número y no hay tab_width, tab_width lo copia, por eso un archivo que solo menciona indent_size informa también de un tab_width. Y en sentido contrario, si indent_size vale tab y existe un tab_width, indent_size toma ese número. Como ocurre sobre el resultado ya fusionado, las dos mitades pueden venir de archivos distintos: un tab_width de la raíz puede alimentar un indent_size escrito tres directorios más abajo. unset recorre la misma maquinaria, así que indent_size = unset deja también tab_width en unset.
¿Qué detiene realmente root = true?
La búsqueda hacia arriba de más archivos .editorconfig. Sin él, el recorrido no se detiene en tu proyecto: sigue por todos los directorios superiores, incluidos tu carpeta personal y la raíz del sistema de archivos, y lo que encuentre allí rellena las propiedades que tu archivo no definió. Dos detalles deciden si funciona. Debe estar en el preámbulo, por encima de la primera cabecera de sección: escrito dentro de un bloque [*] es solo una propiedad corriente llamada root y no detiene nada. Y se lee aunque ninguna sección de ese archivo coincida, así que una configuración con todas las secciones equivocadas termina igualmente la búsqueda.
¿Por qué [*.{js, ts}] no se aplica a mis archivos .ts?
Porque el espacio forma parte del patrón. La alternancia entre llaves compara literalmente las cadenas separadas por comas, sin recortar espacios en ningún punto de una cabecera de sección, así que {js, ts} ofrece «js» y « ts», y solo coincide con la segunda un archivo cuyo nombre contenga de verdad un espacio antes de ts. Conviene conocer dos trampas vecinas: {js} sin coma no es alternancia y coincide con los caracteres literales {js}, de forma que [*.{js}] se aplica a un archivo llamado app.{js} y a ningún otro; y un rango numérico como {1..10} rechaza el cero a la izquierda, así que 1.txt y 10.txt coinciden pero 01.txt no.
¿Una barra invertida escapa un asterisco?
No en la implementación de referencia, diga lo que diga la documentación. El núcleo traduce el glob a una expresión regular en una sola pasada y el escape solo se respeta para la coma, la llave de cierre, # y ;, es decir, los caracteres que si no terminarían el patrón o partirían una alternancia. Una barra invertida delante de un asterisco o de una interrogación se descarta y el comodín sigue coincidiendo con cualquier cosa, de modo que [a\*b.txt] también coincide con aXb.txt. Peor aún, \[ y \{ dejan la expresión generada sin equilibrar: compilar el glob lanza un error y el plugin del editor suele reaccionar ignorando el .editorconfig entero sin decirlo. Esta herramienta reproduce ese comportamiento en lugar de adivinar y marca la sección como un glob inservible. El consejo práctico es mantener llaves, corchetes y asteriscos fuera de las cabeceras de sección.

Herramientas relacionadas