Tslint: Proposition : configuration conditionnelle des peluches

Créé le 3 nov. 2017  ·  42Commentaires  ·  Source: palantir/tslint

Dans certaines situations, nous aimerions appliquer sous condition une vérification du lint selon que le code lint est un code de test ou non. Par exemple, nous aimerions interdire « any » du code de production, car il est dangereux. Mais dans les tests, 'any' peut être utile pour fournir des implémentations fausses ou fictives de services, ou pour les diffuser afin que vous puissiez appeler des méthodes privées. Ou nous pourrions vouloir interdire un ensemble différent de méthodes dans les tests par rapport au code de production, par exemple.

Ce que je propose, c'est un moyen d'activer conditionnellement les vérifications de charpie en fonction d'une correspondance regex sur le nom de fichier. Cela pourrait également être utile pour désactiver les vérifications de charpie pour certains répertoires (contenant du code « hérité », par exemple), ou pour les fichiers .tsx ou .d.ts, etc.

Voici quelques idées d'hommes de paille de syntaxe ; Je suis ouvert aux suggestions aussi.

Objet Sections

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

"Autre" serait des choses qui ne correspondent à aucune des expressions régulières. C'est assez concis, mais je pense que la lisibilité de la section des règles en souffre un peu.

Règles de « dérogation »

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

(cela devrait peut-être être un tableau, pour permettre également plusieurs remplacements).

Declined Enhancement

Commentaire le plus utile

L'imbrication ne résout pas les problèmes abordés ici. Beaucoup de gens veulent que leurs tests dans la même structure de répertoire que le code qu'il teste, et il n'y a tout simplement pas de bonne façon de le faire avec tslint en ce moment.

Tous les 42 commentaires

Si vous placez vos tests et votre code de production dans des répertoires séparés, vous n'aurez pas besoin d'une telle fonctionnalité. Si vous ne fournissez pas de fichier de configuration comme argument CLI, TSLint utilise le tslint.json le plus proche. Par conséquent, vous pouvez avoir différents paramètres pour différents dossiers. En utilisant "extends" vous pouvez utiliser la même configuration de base et remplacer uniquement des règles spécifiques.

Je comprends que de nombreux projets Angular et React mettent les tests dans le même répertoire que le code de production correspondant. Personnellement, je pense que c'est une mauvaise pratique. J'ai vu assez de personnes importer (accidentellement) des symboles à partir de tests dans le code de production.

OMI, la fonctionnalité proposée ajoute beaucoup de complexité. L'implémentation n'est peut-être pas si difficile, mais elle rend le fichier de configuration difficile à lire et à comprendre.
Si nous allons mettre en œuvre cela, je préférerais la deuxième suggestion.

Nous aurions également besoin de discuter de son fonctionnement lors de l'extension des configurations. Dans quel ordre les dérogations sont-elles appliquées ?

Certes, vous pouvez simplement séparer le code, mais cela nuit à l'ergonomie. Soit vous avez

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

et c/foo.spec.ts doit à import {symbol} from '../../../a/b/c/foo';

Ce chemin devient moche dans notre monorepo où les fichiers sont souvent très profonds dans l'arborescence.

ou tu as

  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)

ce qui est trop de fichiers tslint.json

Au sujet des dérogations : je dirais que les dérogations s'appliquent dans le même ordre que les règles sont appliquées. Je ne sais pas ce que c'est, et je n'ai pas pu trouver de documentation, mais intuitivement, je pense que ce serait comme ça :

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

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

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

donnerait à la règle "foo" l'argument 3. Si cette règle n'était pas dans c.json , alors "foo" devrait avoir la valeur 2, en raison de l'ordre du tableau "extends".

Pour les dérogations, je m'attendrais à ce que le même ordre soit appliqué. Il est logique pour moi d'utiliser le dernier remplacement qui correspond à l'expression régulière fournie, en tenant compte de l'ordre dans lequel les règles d'extension sont prises en compte. Un exemple de fichier unique :

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

aurait la valeur 2 pour la règle "foo" lorsque le chemin du fichier contient "spec", 3 s'il contient "test", et 1 sinon. (évidemment, ce n'est pas un ensemble de remplacements très utile, car "test" pourrait aussi bien être omis du premier, mais vous voyez l'idée)

Cela a-t-il du sens et répond-il à votre question?

@calebegg Il y a d'autres cas limites à considérer :

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

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

Quel est le résultat attendu ?

  • 2 car la commande est a.json/rules -> b.json/rules -> a.json/override
  • false parce que la commande est a.json/rules -> a.json/override -> b.json/rules

Idem ici, quel est le résultat attendu :

// 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}}}
}

Juste une pensée aléatoire : Pourquoi ne pas simplement faire correspondre les modèles dans l'ordre et remplacer (partiellement) la correspondance précédente :

{
  "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
  }
}

Quelques exemples:

  • foo.ts : règle-un, règle-deux
  • foo.tsx : règle-une, règle-deux, règle jsx
  • foo.js : règle-un
  • foo.jsx : règle-une, règle-jsx
  • foo.spec.tsx : règle-deux, règle-jsx
  • foo.spec.js : aucun

Je ne sais pas où mettre cela dans la configuration. Le même niveau que "rules" facilite l'écriture, mais peut dérouter les utilisateurs, car il est au même niveau que "extends" , "rulesDirectory" , ...

Un autre problème est l'extension des configurations. Si nous appliquons tous les remplacements de la configuration de base, puis les remplacements de la configuration actuelle, c'est plutôt difficile à comprendre.

Cela rend également le code plus complexe. Actuellement, les configurations sont fusionnées lors de l'analyse. Avec cette proposition, la configuration finale n'est connue que lorsque nous avons un nom de fichier.

Bonjour,

Cette fonctionnalité sera géniale. Je pense qu'Eslint prend en charge cette fonctionnalité : https://eslint.org/docs/user-guide/configuring#configuration -based-on-glob-patterns. Ainsi, la syntaxe et la sémantique pourraient être les mêmes, pour éviter toute confusion.

@minomikula Merci beaucoup. J'ai déjà recherché la documentation ESLint mais je n'ai pas trouvé cette section.

Leur approche a du sens. Résumer:

  • "overrides" de la configuration contient un tableau de remplacements
  • un remplacement peut spécifier plusieurs modèles de glob ( "files" ). si l'un d'eux correspond, la config s'applique
  • vous pouvez exclure des fichiers par motif glob : "excludedFiles"
  • les modèles de glob sont relatifs au fichier de configuration dans lequel ils sont spécifiés
  • les modèles de glob doivent toujours correspondre à l'ensemble du chemin, pas seulement au nom de base
  • les remplacements sont traités dans l'ordre, annulant le précédent
  • lors de l'extension d'un fichier de configuration, la configuration de base est complètement évaluée avant de passer à la configuration d'extension

    • base.json/règles

    • base.json/overrides

    • extension.json/rules

    • extension.json/overrides

Il y a certaines choses à considérer lors du portage de ce comportement vers TSLint :

  • nous devons absolument désactiver extends et linterOptions dans les remplacements
  • nous voulons probablement aussi interdire rulesDirectory
  • voulons-nous autoriser rules et jsRules dans les dérogations ou déprécions-nous jsRules en faveur d'une dérogation **/*.js?(x) ?

Pensées ou commentaires @adidahiya @calebegg @alexeagle @minomikula?

Oh, wow, ouais, cette approche me semble raisonnable. J'aurais dû aussi chercher l'art antérieur.

Ce serait un ajout génial! L'approche eslint fonctionne très bien lors de la désactivation conditionnelle de certaines règles dans les fichiers de test.

@calebegg envisagez -vous toujours d'aller de l'avant quand vous en aurez le temps ?

Oui, j'aimerais vraiment travailler là-dessus. @ajafff Êtes-vous généralement satisfait de commencer avec l'approche ESLint et d'itérer dans les

voulons-nous autoriser les règles et jsRules dans les remplacements ou déprécions-nous jsRules en faveur d'un remplacement */ .js?(x) ?

Cela a du sens pour moi de déprécier, mais je ne me sens pas très fort de toute façon.

@calebegg Je suis d' https://github.com/fimbullinter/wotan/tree/master/packages/wotan#overrides

L'intégration dans l'API TSLint actuelle pourrait être difficile, car elle fusionne actuellement toutes les configurations lors de l'analyse. Cela doit être différé jusqu'à ce que le nom du fichier soit connu et doit être fait pour chaque fichier.

Il s'agit certainement d'un changement d'API de rupture.

@calebegg @mitchlloyd @ajafff @alexeagle Je vois peu d'avantages à cette fonctionnalité par rapport à la simple imbrication tslint.json fichiers

L'imbrication ne résout pas les problèmes abordés ici. Beaucoup de gens veulent que leurs tests dans la même structure de répertoire que le code qu'il teste, et il n'y a tout simplement pas de bonne façon de le faire avec tslint en ce moment.

Il existe de nombreux projets mettant les fichiers de spécifications dans le même répertoire que les sources. C'est devenu une bonne pratique dans de nombreux environnements, Angular CLI génère une structure de projet comme celle-ci, etc. Je ne pense pas que l'imbrication des fichiers de configuration tslint fonctionne pour toutes ces personnes.

Je suis d'accord que la structure de mon projet ne doit pas être dictée par un outil de peluchage. Au lieu de cela, l'outil de peluchage doit prendre en charge les modèles existants communs. La colocalisation des tests et des fichiers source est un modèle courant.

@giladgray La modification demandée prend en charge un scénario dans lequel les utilisateurs placent leurs tests et leurs fichiers de production les uns à côté des autres comme ceci :

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

Comment « l'imbrication tslint.json fichiers my-component.ts et my-component.test.ts ?

Les directives angulaires

@ohjames Restons dans le sujet et évitons de nous orienter vers des attaques personnelles, d'accord ? Suggérer que quelqu'un n'est pas apte à maintenir son propre projet n'est pas le moyen d'influencer l'OSS, et ne va certainement pas aider ce que nous défendons tous ici.

Il est logique de vouloir des remplacements pour les fichiers qui ne rentrent pas dans une structure imbriquée comme mentionné ci-dessus. Il me semble que le commentaire de @giladgray visait à déterminer s'il y avait encore un intérêt communautaire significatif pour ce changement, étant donné qu'il n'y avait eu aucune activité sur ce problème depuis plus de 6 mois. Ceci est spécifiquement mis en évidence par son commentaire sur le PR ouvert (#3708) :

si vous souhaitez continuer, veuillez mettre à jour cette branche afin que nous puissions l'examiner, ou la fermer si elle n'est plus pertinente. nous fermerons ceci si nous n'avons pas de vos nouvelles dans deux semaines.

@ohjames Je vous suggère de reconsidérer votre commentaire - comme @DanielSchaffer l'a mentionné, les attaques personnelles ne vont pas vous aider ici, ou n'importe où dans les logiciels open source. Tout le monde fait de son mieux pour créer un logiciel de qualité, fiable et riche en fonctionnalités, et attaquer les gens n'y contribue en aucun cas.

Y a-t-il une mise à jour sur ce sujet?
L'idée proposée par @ajafff dans son commentaire de synthèse semble raisonnable et satisfait toutes sortes de besoins. Utiliser la même sémantique que eslint est un bon moyen d'avancer.

Comme j'ai commenté le n° 1063 connexe, mon cas d'utilisation serait que l'utilisation de tslint-microsoft-contrib bombarde actuellement les composants à fichier unique de Vue pour certaines règles. Il peut s'agir d'un problème Vue ou d'un problème TSLint, et ces équipes peuvent ou non résoudre le problème spécifique - désactiver les règles incriminées jusqu'à ce que cela se produise semble être une solution de contournement simple qui n'est pas trop lourde. Comparé au fait d'avoir à ajouter la même directive de désactivation à chaque fichier .vue et à la mettre à jour à tous ces endroits à mesure que la prise en charge des règles change. Cela n'a pas non plus de sens de diviser un projet en fichiers .vue et .ts, ce serait une structure très délicate.

Je suis en faveur de l'arrivée de cette fonctionnalité. Peut-être pouvons-nous également résoudre proprement la requête tslintignore dans #73 en autorisant certains remplacements pour désactiver complètement toutes les règles ?

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

tslint-microsoft-contrib bombarde actuellement les composants à fichier unique de Vue pour certaines règles

Oh 😕 @millimoose pourriez-vous s'il vous plaît déposer un problème sur tslint-microsoft-contrib ?

@JoshuaKGoldberg - J'avais déjà fait un rapport détaillé de ce bogue dans @vuejs/vue-cli qui semblait le plus approprié. (C'est marqué comme "en attente de reproduction", donc je suppose que ce n'est pas complètement déplacé.) Je viens de le mentionner comme une motivation pour sonner ici. C'est le genre de chose qui peut et va se produire dans un écosystème en évolution, ce qui devrait être un argument pour que les outils soient suffisamment flexibles pour contourner les obstacles sans réellement écrire des hacks autour des bogues des autres.

Une mise à jour sur ce problème?

Ce problème est actuellement signalé comme « Proposition requise », mais je pense que nous avons déjà une proposition dans https://github.com/palantir/tslint/issues/3447#issuecomment -344020834 ?

La proposition de @RoystonS @ajafff mentionnait quelques points à régler :

Il y a certaines choses à considérer lors du portage de ce comportement vers TSLint :

  • nous devons absolument désactiver extends et linterOptions dans les remplacements
  • nous voulons probablement aussi interdire rulesDirectory
  • voulons-nous autoriser rules et jsRules dans les dérogations ou déprécions-nous jsRules en faveur d'une dérogation **/*.js?(x) ?

Il devrait également y avoir un consensus de la part des membres de l'organisation palantirtech à ce sujet avant d'aller de l'avant, car il s'agit d'une fonctionnalité assez importante.

Je viens de tomber dessus moi-même et je veux juste exprimer mon intérêt pour ce genre de fonctionnalité.

Nous avons fini par assouplir certaines règles de linting qui affectent le code de production et voyons comment cela se passe. ):

J'aimerais voir cette fonctionnalité

abonnement - J'en ai également besoin.

J'en ai tellement besoin :(

Pareil ici! Nous utilisons dactylographié avec Vuejs et nos fichiers de test unitaire ne sont pas ensemble dans un répertoire de tests mais partout dans le code source du composant.

J'adorerais voir cette fonctionnalité, nous utilisons actuellement une configuration légèrement bancale qui a pour résultat que vscode met en évidence des erreurs de linting différentes de celles que notre ligne de commande lint met en évidence pour contourner ce problème.

Je doute fortement que cette fonctionnalité ne soit jamais implémentée, tslint ne semble pas être activement maintenu en général. Je suggère de passer à @typescript-eslint , il bénéficie d'une prise en charge complète des projets eslint et ts et la migration est plus facile que jamais avec @typescript-eslint/eslint-plugin-tslint . Et il y a une table de compatibilité avec tslint et les règles eslint correspondantes / autres alternatives disponibles. La configuration d'Eslint est hautement personnalisable, donc je ne vois aucun intérêt à m'en tenir à tslint.

Je propose d'appliquer le concept utilisé par le référentiel git pour les fichiers dans le .gitIgnore... aux règles tsLint. Utilisation de votre position hiérarchique actuelle comme contexte pour le linter, avec un fichier de remplacement, lors du linting d'un sous-répertoire particulier. Ensuite, vous pouvez inclure ou exclure, configurer n'importe quelle configuration à n'importe quel niveau de répertoire que vous souhaitez.

par exemple
Une configuration tslint est placée à la racine, et à n'importe quel niveau de la structure de votre code source, vous souhaitez un comportement différent, remplacez-la simplement par un fichier d'extension tslint à la racine de ce sous-répertoire.

@redevill Cela aide les gens à écrire des tests dans un dossier test . Mais pas un seul test d'écriture en tant que something.test.ts dans le même dossier du composant/service.

D'accord - mais avec un changement mineur : (qui pourrait être automatisé avec le générateur de modèles (style CLI)
MonRépertoireComposant
---MyComponentTestsDir
------tslint.test.json
------quelquechose.test.ts
---mycomponent.component.css
---moncomposant.composant.html
---mycomponent.component.ts

L'idée pourrait encore fonctionner.

Grand fan de cette proposition. OUI S'IL VOUS PLAÎT! Ma préférence serait le concept Overrides.

Au fait, compte tenu de l'annonce de la dépréciation de tslint, je ne peux pas vraiment imaginer qu'un changement aussi important sera apporté à ce stade et que mon équipe passe à eslint, qui dispose déjà de fonctionnalités de remplacement par règle + par fichier.

@RoystonS a fondamentalement raison, une fonctionnalité aussi importante ne sera pas ajoutée à tslint à ce stade. voir #4534

Nous utilisons un projet angulaire. Nous avons besoin du concept des dérogations. Sinon, c'est pénible à gérer

Cette page vous a été utile?
0 / 5 - 0 notes