Tslint: Propuesta: configuración de pelusa condicional

Creado en 3 nov. 2017  ·  42Comentarios  ·  Fuente: palantir/tslint

Hay algunas situaciones en las que nos gustaría aplicar condicionalmente una verificación de pelusa en función de si el código que se está aplicando es código de prueba o no. Por ejemplo, nos gustaría prohibir "cualquiera" del código de producción, ya que no es seguro. Pero en las pruebas, 'any' puede ser útil para proporcionar implementaciones falsas o simuladas de servicios, o para transmitir a través de él para que pueda llamar a métodos privados. O podríamos querer prohibir un conjunto diferente de métodos en las pruebas frente al código de producción, por ejemplo.

Lo que propongo es una forma de habilitar condicionalmente las comprobaciones de pelusa basadas en una coincidencia de expresiones regulares en el nombre del archivo. Esto también podría ser útil para desactivar las comprobaciones de pelusa para ciertos directorios (que contienen código "heredado", por ejemplo), o para archivos .tsx o .d.ts, etc.

Aquí hay algunas ideas de sintaxis del hombre de paja; También estoy abierto a sugerencias.

Objeto de secciones

{
  "rules": {
    "no-any": {"other": true},
    "no-console":
        {
          "test": [true, "warn", "error"], 
          "other": [true, "log", "warn", "error"]
        }
  },
  "sections": {
    "test": ".*\\.spec\\.ts$"
  }
}

"Otro" serían cosas que no coinciden con ninguna de las expresiones regulares. Esto es bastante conciso, pero creo que la legibilidad de la sección de reglas sufre un poco.

Reglas de "anulación"

{
  "rules": {
    "no-any": true,
    "no-console": [true, "log", "warn", "error"]
  },
  "override": {
    "match": ".*\\.spec\\.ts$",
    "rules": {
      "no-any": false,
      "no-console": [true, "warn", "error"]
    }
  }
}

(esto quizás debería ser una matriz, para permitir también múltiples invalidaciones).

Declined Enhancement

Comentario más útil

El anidamiento no resuelve los problemas discutidos aquí. Muchas personas quieren que sus pruebas en la misma estructura de directorio que el código se pone a prueba, y simplemente no hay buena manera de hacer eso con tslint en este momento.

Todos 42 comentarios

Si coloca sus pruebas y el código de producción en directorios separados, no necesitaría tal característica. Si no proporciona un archivo de configuración como argumento CLI, TSLint usa el tslint.json más cercano. Por lo tanto, puede tener diferentes configuraciones para diferentes carpetas. Al usar "extends" , puede usar la misma configuración base y anular solo reglas específicas.

Entiendo que muchos proyectos de Angular y React ponen pruebas en el mismo directorio que el código de producción correspondiente. Personalmente creo que esta es una mala práctica. He visto suficientes personas (accidentalmente) importando símbolos de pruebas en código de producción.

En mi opinión, la característica propuesta agrega mucha complejidad. Puede que la implementación no sea tan difícil, pero hace que el archivo de configuración sea difícil de leer y comprender.
Si vamos a implementar esto, preferiría la segunda sugerencia.

También necesitaríamos discutir cómo funciona al extender configuraciones. ¿En qué orden se aplican las anulaciones?

Es cierto que podría simplemente separar el código, pero daña la ergonomía. O tienes

src/
  tslint.json
  a/
    b/
      c/
test/
  tslint.json (extends ../src)
  a/
    b/
      c/

y c/foo.spec.ts tiene que import {symbol} from '../../../a/b/c/foo';

Ese camino se pone feo en nuestro monorepo, donde los archivos suelen estar muy profundos en el árbol.

o tienes

  a/
    src/
      tslint.json
    test/
      tslint.json (extends ../src)
    b/
      src/
        tslint.json
      test/
        tslint.json (extends ../src)
      c/
        src/
           tslint.json
        test/
          tslint.json (extends ../src)

que son demasiados archivos tslint.json

Sobre el tema de las anulaciones: yo diría que las anulaciones se aplican en el mismo orden en que se aplican las reglas. No sé qué es eso, y no pude encontrar documentación, pero intuitivamente creo que sería así:

// a.json
{"rules": {"foo": [true, 1]}}

// b.json
{"rules": {"foo": [true, 2]}}

// c.json
{
  "extends": ["a.json", "b.json"],
  "rules": {"foo": [true, 3]}
}

daría como resultado que la regla "foo" tenga el argumento 3. Si esa regla no estuviera en c.json , entonces "foo" debería tener el valor 2, debido al orden de la matriz "amplía".

Para las anulaciones, esperaría que se aplicara el mismo orden. Para mí tiene sentido usar la última anulación que coincida con la expresión regular proporcionada, teniendo en cuenta el orden en el que se consideran las reglas de 'extensión'. Un solo ejemplo de archivo:

{
  "rules": {"a": [true, 1]},
  "override": [
    {"match": "test|spec", "rules": {"a": [true, 2]}},
    {"match": "test", "rules": {"a": [true, 3]}}
  ]
}

tendría el valor 2 para la regla "foo" cuando la ruta del archivo contiene "spec", 3 si contiene "test" y 1 en caso contrario. (obviamente, no es un conjunto de anulaciones muy útil, ya que "prueba" también podría omitirse de la primera, pero entiendes la idea)

¿Tiene sentido y responde a tu pregunta?

@calebegg Hay algunos otros casos

// a.json
{
  "rules": {"foo": [true, 1]},
  "override": {"match": "test|spec", "rules": {"foo": [true, 2]}}
}

// b.json
{
  "extends": "./a.json"
  "rules": {"foo": false}
}

¿Cuál es el resultado esperado?

  • 2 porque el pedido es a.json/rules -> b.json/rules -> a.json/override
  • false porque el pedido es a.json/rules -> a.json/override -> b.json/rules

Lo mismo aquí, cuál es el resultado esperado:

// c.json
{
  "rules": {"foo": [true, 1]},
  "override": {"match": "test|spec", "rules": {"foo": false}}
}

// d.json
{
  "extends": "./a.json"
  "rules": {"foo": {"options": 2}},
  "override": {"match": "test|spec", "rules": {"foo": {"options": 3}}}
}

Solo un pensamiento al azar: ¿Por qué no simplemente hacer coincidir los patrones en orden y anular (parcialmente) la coincidencia anterior?

{
  "rules": { // same as "*"
    "rule-one": true,
    "rule-two": true
  },
  "*.js?(x)": { // we could get rid of "jsRules" with this
    "rule-two": false
  },
  "*.{t,j}sx": {
    "jsx-rule": true
  },
  "*.spec.*" {
    "rule-one": false
  }
}

Algunos ejemplos:

  • foo.ts : regla-uno, regla-dos
  • foo.tsx : regla-uno, regla-dos, regla-jsx
  • foo.js : regla-uno
  • foo.jsx : regla-uno, regla-jsx
  • foo.spec.tsx : regla-dos, regla-jsx
  • foo.spec.js : ninguno

Simplemente no sé dónde poner esto dentro de la configuración. El mismo nivel que "rules" facilita la escritura, pero puede confundir a los usuarios, porque está al mismo nivel que "extends" , "rulesDirectory" , ...

Otro problema es extender configs. Si aplicamos todas las invalidaciones de la configuración base y luego las invalidaciones de la configuración actual, es bastante difícil de entender.

También hace que el código sea más complejo. Actualmente, las configuraciones se combinan durante el análisis. Con esta propuesta, la configuración final solo se conoce cuando tenemos un nombre de archivo.

Hola,

Esta característica será genial. Creo que Eslint admite esta función: https://eslint.org/docs/user-guide/configuring#configuration -based-on-glob-patterns. Entonces, la sintaxis y la semántica podrían ser lo mismo, para evitar confusiones.

@minomikula Muchas gracias. Busqué los documentos de ESLint antes, pero no encontré esta sección.

Su enfoque tiene sentido. Para resumir:

  • "overrides" sección
  • una anulación puede especificar múltiples patrones globales ( "files" ). si uno de ellos coincide, se aplica la configuración
  • puede excluir archivos por patrón global: "excludedFiles"
  • Los patrones glob son relativos al archivo de configuración en el que se especifican
  • Los patrones glob siempre deben coincidir con toda la ruta, no solo con el nombre base.
  • las anulaciones se procesan en orden, anulando la anterior
  • al extender un archivo de configuración, la configuración base se evalúa por completo antes de continuar con la configuración extendida

    • base.json / rules

    • base.json / overrides

    • extendiendo.json / reglas

    • extending.json / overrides

Hay algunas cosas a considerar al migrar este comportamiento a TSLint:

  • definitivamente deberíamos deshabilitar extends y linterOptions en anulaciones
  • probablemente también queremos rechazar rulesDirectory
  • ¿Queremos permitir rules y jsRules en anulaciones o depreciamos jsRules a favor de una anulación de **/*.js?(x) ?

¿Pensamientos o comentarios @adidahiya @calebegg @alexeagle @minomikula?

Oh, vaya, sí, ese enfoque me parece razonable. También debería haber buscado el estado de la técnica.

¡Esta sería una adición increíble! El enfoque eslint funciona muy bien cuando se deshabilitan condicionalmente algunas reglas en archivos de prueba.

@calebegg , ¿todavía planeas impulsar esto cuando encuentres tiempo?

Sí, definitivamente me gustaría trabajar en esto. @ajafff ¿En general, está satisfecho con comenzar con el enfoque de ESLint e iterar en las relaciones públicas? ¿O cree que hay cuestiones de diseño de las que deberíamos hablar primero?

¿Queremos permitir reglas y jsRules en anulaciones o desaprobamos jsRules a favor de una anulación * / .js? (x)?

Para mí tiene sentido desaprobarlo, pero no me siento muy fuerte de ninguna manera.

@calebegg Estoy bien con el enfoque de ESLint. Implementé un concepto muy similar en mi tiempo de ejecución de linter POC https://github.com/fimbullinter/wotan/tree/master/packages/wotan#overrides

La integración en la API de TSLint actual podría ser difícil, porque actualmente fusiona todas las configuraciones durante el análisis. Esto debe posponerse hasta que se conozca el nombre del archivo y se debe hacer para cada archivo.

Este es sin duda un cambio de API importante.

@calebegg @mitchlloyd @ajafff @alexeagle Veo pocos beneficios en esta función sobre simplemente anidar archivos tslint.json para anular las configuraciones externas. esa característica ya funciona hoy y no requiere interrupciones complejas de API. ¿Se sentiría ofendido si rechazáramos esta solicitud?

El anidamiento no resuelve los problemas discutidos aquí. Muchas personas quieren que sus pruebas en la misma estructura de directorio que el código se pone a prueba, y simplemente no hay buena manera de hacer eso con tslint en este momento.

Hay muchos proyectos que colocan archivos de especificaciones en el mismo directorio que las fuentes. Esto se ha convertido en una práctica recomendada en muchos entornos, Angular CLI genera una estructura de proyecto como esa, etc. No creo que sea realista anidar archivos de configuración tslint vaya a funcionar para todas estas personas.

Estoy de acuerdo en que la estructura de mi proyecto no debería estar dictada por una herramienta de deshilachado. En cambio, la herramienta de pelado debe admitir patrones comunes existentes. Colocar pruebas y archivos fuente es un patrón común.

@giladgray El cambio solicitado admite un escenario en el que los usuarios colocan sus pruebas y archivos de producción uno al lado del otro de esta manera:

some-dir/
  my-component.ts
  my-component.test.ts

¿Cómo abordaría "anidar archivos tslint.json " este caso de uso cuando queremos reglas diferentes para my-component.ts y my-component.test.ts ?

Las pautas angulares de

@ohjames Permanezcamos en el tema y evitemos desviarnos hacia los ataques personales, ¿de acuerdo? Sugerir que alguien no está en condiciones de mantener su propio proyecto no es la forma de influir en el OSS, y ciertamente no ayudará a lo que todos estamos defendiendo aquí.

Tiene sentido querer anulaciones para archivos que no encajan en una estructura anidada como se mencionó anteriormente. Me parece que el comentario de @giladgray tenía la intención de determinar si todavía había un interés significativo de la comunidad en este cambio, dado que no había habido actividad sobre este tema durante más de 6 meses. Esto se evidencia específicamente en su comentario sobre el PR abierto (# 3708):

Si desea continuar con esto, actualice esta rama para que podamos revisarla, o ciérrela si ya no es relevante. cerraremos esto si no tenemos noticias suyas en dos semanas.

@ohjames Te sugiero que reconsideres tu comentario; como mencionó @DanielSchaffer , los ataques personales no te ayudarán aquí ni en ningún otro lugar del software de código abierto. Todos están haciendo todo lo posible para crear un software bueno, confiable y rico en funciones, y atacar a las personas de ninguna manera contribuye a eso.

¿Hay alguna actualización sobre este tema?
La idea propuesta por @ajafff en su comentario resumido parece razonable y satisface toda variedad de necesidades. Usar la misma semántica que eslint es un buen camino a seguir.

Como comenté en el # 1063 relacionado, mi caso de uso sería que el uso de tslint-microsoft-contrib actualmente bombardea los componentes de un solo archivo de Vue para algunas reglas. Esto podría ser un problema de Vue o un problema de TSLint, y esos equipos podrían o no solucionar el problema específico; deshabilitar las reglas infractoras hasta que eso suceda parece una solución simple que no es demasiado engorrosa. En comparación con tener que agregar la misma directiva de deshabilitación a cada archivo .vue y actualizarlo en todos esos lugares a medida que cambia el soporte de la regla. Tampoco tiene sentido dividir un proyecto en archivos .vue y .ts, sería una estructura muy incómoda.

Estoy a favor de que se incorpore esta característica. ¿Quizás también podamos resolver limpiamente la solicitud tslintignore en el n. ° 73 permitiendo que algunas anulaciones deshabiliten por completo todas las reglas?

{
    "files": "./src/test-data/*.ts",
    "reset": true // Resets tslint.json to {}
}

tslint-microsoft-contrib actualmente bombardea los componentes de un solo archivo de Vue para algunas reglas

Oh, @millimoose, ¿ podrías presentar un problema en tslint-microsoft-contrib?

@JoshuaKGoldberg : ya había hecho un informe detallado de ese error en @ vuejs / vue-cli, que parecía el más apropiado. (Está marcado como "en espera de reproducción", así que supongo que no está tan fuera de lugar). Lo mencioné como un motivador para intervenir aquí. Es el tipo de cosas que pueden surgir y surgirán en un ecosistema en evolución, lo que debería ser un argumento para que las herramientas sean lo suficientemente flexibles como para sortear obstáculos sin tener que escribir trucos en torno a los errores de los demás.

¿Alguna actualización sobre este tema?

Este problema está marcado actualmente como 'Necesita propuesta', pero creo que ya tenemos una propuesta en https://github.com/palantir/tslint/issues/3447#issuecomment -344020834?

La propuesta de @RoystonS @ajafff mencionó algunos cabos sueltos que deberían abordarse:

Hay algunas cosas a considerar al migrar este comportamiento a TSLint:

  • definitivamente deberíamos deshabilitar extends y linterOptions en anulaciones
  • probablemente también queremos rechazar rulesDirectory
  • ¿Queremos permitir rules y jsRules en anulaciones o depreciamos jsRules a favor de una anulación de **/*.js?(x) ?

También debería haber consenso de la gente de la organización palantirtech sobre esto antes de seguir adelante, ya que es una característica bastante importante.

Me encontré con esto yo mismo, y solo quiero expresar mi interés por este tipo de función.

Terminamos relajando algunas reglas que afectan el código de producción y veamos cómo funciona. ):

Me encantaría ver esta característica

suscribirse - También necesita esto.

Necesito esto tanto :(

¡Aquí igual! Estamos usando mecanografiado con Vuejs y nuestros archivos de prueba unitaria no están juntos en un directorio de pruebas sino en todas partes a lo largo del código fuente del componente.

Me encantaría ver esta función, actualmente estamos usando una configuración un poco inestable que da como resultado que vscode resalte diferentes errores de pelusa de lo que resalta nuestra línea de comando lint para solucionar este problema.

Dudo mucho que esta característica se implemente alguna vez, tslint no parece mantenerse activamente en general. Sugiero cambiar a @typescript-eslint , obtuvo soporte completo de los proyectos eslint y ts y la migración es más fácil que nunca con @ typescript-eslint / eslint-plugin-tslint . Y hay una tabla de compatibilidad con tslint y las correspondientes reglas de eslint / otras alternativas disponibles. La configuración de Eslint es altamente personalizable, por lo que no veo ningún punto para seguir con tslint.

Propongo aplicar el concepto de usos del repositorio git para archivos en .gitIgnore ... a las reglas tsLint. Uso de su posición jerárquica actual como contexto para el linter, junto con un archivo de anulación, al enlazar un subdirectorio en particular. Luego, puede incluir o excluir, configurar cualquier configuración en cualquier nivel de directorio que desee.

p.ej
Una configuración de tslint se coloca en la raíz, y en cualquier nivel particular de la estructura de su código fuente, le gustaría un comportamiento diferente, simplemente anótelo con un archivo tslint de extensión en la raíz de ese subdirectorio.

@redevill Ayuda a las personas a escribir pruebas en una carpeta test . Pero ni una prueba de escritura como something.test.ts en la misma carpeta del componente / servicio.

De acuerdo, pero con un cambio menor: (que podría automatizarse con el generador de plantillas (estilo CLI)
MyComponentDir
--- MyComponentTestsDir
------ tslint.test.json
------ algo.prueba.ts
--- mycomponent.component.css
--- mycomponent.component.html
--- mycomponent.component.ts

La idea aún podría funcionar.

Gran fan de esta propuesta. ¡SÍ, POR FAVOR! Mi preferencia sería el concepto Overrides.

Por cierto, dado el anuncio de desactivación de tslint, no puedo _realmente_ imaginar que se hará un cambio tan grande en esta etapa, y que mi equipo se mudará a eslint, que ya tiene funciones de anulación por regla + por archivo.

@RoystonS tiene básicamente razón, una característica tan grande no se agregará a tslint en este momento. ver # 4534

Usamos un proyecto Angular. Necesitamos el concepto de anulaciones. De lo contrario, es doloroso manejar

¿Fue útil esta página
0 / 5 - 0 calificaciones