fix-knip-unused-exports

Par factory-ai · factory-plugins

Corriger les violations knip « Unused exports ». Gère toutes les catégories de violations : exports utilisés uniquement dans les tests (extraire vers un nouveau fichier), re-exports barrel morts (supprimer de index.ts), et exports utilisés uniquement en interne (supprimer le mot-clé export). Utiliser quand `npm run knip` signale des exports inutilisés.

npx skills add https://github.com/factory-ai/factory-plugins --skill fix-knip-unused-exports

Corriger les Unused Exports de Knip

Corriger les violations « Unused exports » de knip. Il existe plusieurs catégories de violation, chacune avec une stratégie de correction différente.

Quand l'utiliser

  • npm run knip rapporte « Unused exports »

Quand NE PAS l'utiliser

  • L'export est consommé par du code production non-test dans un autre fichier -- quelque chose d'autre ne va pas

Workflow

1. Identifier les Violations

npm run knip

Le résultat ressemble à :

Unused exports (3)
::error file=packages/foo/src/bar.ts,line=42,title=Unused exports::myFunction

2. Classer chaque Violation

Pour chaque export signalé, grep l'ensemble du repository (pas seulement le package) :

rg "myFunction"

Déterminez dans quelle catégorie elle s'inscrit :

Catégorie Appelants Correction
Export test-only Utilisé dans le même fichier + fichiers de test uniquement Extraire dans un nouveau fichier
Dead barrel re-export Ré-exporté depuis index.ts, mais le code production importe via des chemins relatifs ou d'autres sous-chemins Supprimer le re-export du barrel
Export utilisé uniquement en interne Utilisé seulement au sein du même fichier, pas par les tests ou d'autres fichiers Supprimer le mot-clé export
Code mort Aucun appelant nulle part Supprimer l'export
Consommateur production existe Utilisé par du code non-test dans un autre fichier Pas un problème knip -- investiguer davantage

Important : Lors du grep, excluez les fichiers de test pour identifier les consommateurs production :

rg "myFunction" --glob '!**/*.test.*'

Correction : Exports Test-Only (Extraire dans un Nouveau Fichier)

Quand une fonction est exportée uniquement pour l'accès aux tests mais est aussi utilisée en interne dans le même fichier.

Planifier l'Extraction

Avant d'écrire du code, répondez à ces questions :

a) Qu'est-ce qui se déplace vers le nouveau fichier ?

  • La fonction/classe/const exportée signalée
  • Toutes les fonctions helper privées dont elle dépend
  • Toutes les constantes/types privés dont elle dépend

b) Certains helpers sont-ils partagés avec les fonctions qui restent ?

  • Si oui, le helper doit être exporté depuis le nouveau fichier, et le fichier original l'importe
  • Cela signifie que le nouveau fichier aura 2+ exports (ce qui est correct pour toute règle lint filename-match-export)

c) Le nouveau fichier aura-t-il exactement une fonction exportée ?

  • Si votre projet applique une règle lint filename-match-export, le fichier DOIT être nommé d'après cet export : myFunction.ts
  • Si le fichier a 2+ exports de fonction, le nom est flexible

d) Existe-t-il un fichier test avec un nom correspondant ?

  • Si bar.ts reste et que bar.test.ts existe, le test doit toujours importer quelque chose depuis ./bar (si votre projet applique une règle test-imports-source)
  • Si bar.ts est supprimé (tout a été déplacé), cette règle s'applique généralement seulement quand le fichier source correspondant existe

e) Y a-t-il un risque de dépendance circulaire ?

  • Dessinez le graphe d'imports : nouveau fichier -> fichier original -> nouveau fichier est circulaire
  • Correction : déplacer la dépendance partagée vers le nouveau fichier ou un troisième fichier

f) Exporte-t-il une constante ?

  • Si votre projet applique une règle lint constants-file-organization, les constantes exportées doivent vivre dans un fichier nommé constants.ts
  • Si la fonction extraite dépend d'une constante qu'autres fonctions du fichier original utilisent aussi, N'EXPORTEZ PAS la constante depuis le nouveau fichier. À la place, appelez la fonction (par exemple, remplacez BUDGET[effort] par getBudget(effort)) pour éviter d'avoir besoin d'un constants.ts séparé

Exécuter l'Extraction

Créez le nouveau fichier dans le même répertoire :

// myFunction.ts (nouveau fichier)
import { SomeType } from '../types';

function privateHelper(): void { /* ... */ }

export function myFunction(): SomeType {
  return privateHelper();
}

Mettez à jour le fichier original pour importer depuis le nouveau fichier :

// bar.ts (fichier original, mis à jour)
import { myFunction } from './myFunction';

function otherFunction() {
  const result = myFunction(); // Importe maintenant depuis le nouveau fichier
}

Mettez à jour les fichiers de test pour importer depuis le nouveau fichier :

// bar.test.ts (mis à jour)
import { myFunction } from './myFunction';
// Si bar.ts existe toujours, vous pourriez avoir besoin d'importer aussi quelque chose depuis './bar'
// pour satisfaire à toute règle test-imports-source

Attention aux Violations en Chaîne

Après l'extraction, lancez npm run knip à nouveau. Si la fonction A a été extraite vers un nouveau fichier aux côtés de la fonction B que A appelle, mais B est aussi consommée seulement par les tests en externe, knip signalera aussi B. Vous devez extraire B vers son propre fichier pour que le fichier de A crée un véritable import production de B.

Exemple : supposons que throwMappedError ait d'abord été extrait aux côtés de mapResponseFailure dans error-mappers.ts. Si throwMappedError est appelée seulement en interne au sein de ce fichier (par mapResponseFailure), elle sera toujours signalée. Correction : extraire vers throwMappedError.ts, rendant l'import depuis error-mappers.ts un véritable consommateur production.

Correction : Dead Barrel Re-Exports (Supprimer depuis index.ts)

Quand un barrel index.ts ré-exporte quelque chose, mais aucun code production ne l'importe via le barrel. Cela se produit quand :

  • Le code production au sein du même package utilise des imports relatifs (par exemple, import { x } from './source') au lieu du barrel
  • Le code production dans d'autres packages importe directement depuis un sous-chemin (par exemple, @scope/pkg/feature/handlers) au lieu du barrel
  • Le re-export a été ajouté de manière spéculative mais n'a jamais été consommé

Comment Identifier

Grep en excluant les fichiers de test. Si les seuls résultats sont :

  • Le barrel index.ts lui-même
  • Les fichiers source utilisant des imports relatifs au sein du même package
  • Les fichiers de test

Alors le re-export du barrel est inutilisé. Supprimez-le simplement depuis index.ts.

Imports de Test Entre Packages

Si un test dans un autre package importe le symbole via le barrel (par exemple, import { x } from '@scope/pkg/feature'), vous devez fournir un chemin d'import alternatif après suppression du re-export du barrel :

  1. Ajoutez une subpath export dans package.json du package source :

    {
      "exports": {
        "./feature": "./src/feature/index.ts",
        "./feature/doSomething": "./src/feature/doSomething.ts"
      }
    }
  2. Mettez à jour le test pour importer depuis le nouveau sous-chemin :

    import { doSomething } from '@scope/pkg/feature/doSomething';

Ce pattern suit les conventions de subpath-export typiques utilisées dans les monorepos.

Correction : Exports Utilisés Uniquement en Interne (Ôter l'export)

Quand un export est utilisé uniquement au sein du même fichier et n'est importé par rien d'autre (pas même par les tests), supprimez simplement le mot-clé export :

// Avant
export const MySchema = z.object({ ... });

// Après
const MySchema = z.object({ ... });

C'est courant pour les schémas Zod qui sont seulement utilisés comme blocs de construction pour d'autres schémas du même fichier.

Vérifier

Exécutez TOUS ces contrôles sur les packages affectés :

# Knip passe (c'est le point de la manœuvre)
npm run knip

# Les types compilent toujours
npm run typecheck

# Les tests passent toujours
npm run test

# Le lint passe (détecte filename-match-export, test-imports-source, constants-file-organization, etc.)
npm run lint

S'il existe des imports entre packages, vérifiez aussi le package consommateur.

Règles Lint en Interaction

De nombreux monorepos TypeScript superposent des règles lint personnalisées supplémentaires par-dessus knip. Adaptez les corrections ci-dessous à celles que votre projet utilise.

filename-match-export (ou similaire)

Si un fichier a exactement UNE fonction exportée (pas un composant React), le nom du fichier doit correspondre au nom de la fonction.

  • export function loadConfig dans loadConfig.ts -- réussit
  • export function loadConfig dans helpers.ts -- échoue
  • Deux exports dans helpers.ts -- la règle ne s'applique pas (exports multiples)

test-imports-source (ou similaire)

Si foo.test.ts et foo.ts existent tous les deux, le test doit importer depuis ./foo.

  • Les imports comme import { x } from './foo' satisfont la règle
  • Accepte généralement aussi d'importer depuis '.' ou './index' si index.ts ré-exporte depuis foo.ts
  • Si foo.ts est supprimé, la règle ne s'applique pas

constants-file-organization (ou similaire)

Les constantes exportées doivent être définies dans un fichier nommé constants.ts.

  • Si vous extrayez une fonction qui dépend d'une constante partagée, N'EXPORTEZ PAS la constante depuis le fichier de la fonction
  • À la place, remplacez l'accès direct à la constante par des appels de fonction (par exemple, BUDGET[effort] devient getBudget(effort))
  • Ou déplacez la constante vers un fichier constants.ts

Comment Knip Trace les Exports

  • Knip ignore les fichiers de test (**/*.test.*, **/*.spec.*)
  • ignoreIssues dans knip.json supprime les avertissements SUR le fichier listé, mais NE REND PAS l'export source « utilisé »
  • Les ré-exports de barrel (export { x } from './source') depuis un index.ts avec ignoreIssues ne comptent PAS comme une utilisation de l'export source
  • Seuls les imports authentiques depuis des fichiers project non-test, non-ignorés comptent comme une utilisation
  • includeEntryExports: true (si défini) signifie que les exports depuis les fichiers entry point sont aussi vérifiés, donc les fichiers de style entry-point (migrations, scripts) pourraient avoir besoin d'un ignoreIssues explicite

Package Subpath Exports

Quand vous supprimez des ré-exports de barrel sur lesquels des tests cross-package s'appuyaient, ajoutez des subpath exports à package.json :

{
  "exports": {
    "./feature": "./src/feature/index.ts",
    "./feature/doSomething": "./src/feature/doSomething.ts"
  }
}

Quoi Ne Pas Faire

  • N'ajoutez pas de fichiers à ignoreIssues dans knip.json à moins qu'ils ne soient de véritables scripts entry point (migrations, CLIs)
  • Ne fusionnez pas toutes les fonctions dans un seul fichier pour réduire les exports -- l'utilisation au sein du même fichier d'un export ne compte pas comme utilisation du point de vue de knip
  • Ne supprimez pas le mot-clé export si les tests en ont besoin -- les tests se casseraient
  • Ne créez pas d'imports circulaires entre le nouveau et le fichier original
  • N'exportez pas de constantes depuis des fichiers autres que constants.ts si votre projet applique une règle lint constants-file-organization

Skills similaires