Écrire du code pour réécrire votre code : jscodeshift

Publié: 2022-03-11

Codemods avec jscodeshift

Combien de fois avez-vous utilisé la fonctionnalité de recherche et de remplacement dans un répertoire pour apporter des modifications aux fichiers source JavaScript ? Si vous êtes bon, vous êtes devenu fantaisiste et avez utilisé des expressions régulières avec des groupes de capture, car cela en vaut la peine si votre base de code est importante. Regex a cependant des limites. Pour les modifications non triviales, vous avez besoin d'un développeur qui comprend le code dans son contexte et qui est également prêt à entreprendre le processus long, fastidieux et sujet aux erreurs.

C'est là qu'interviennent les "codemods".

Les codemods sont des scripts utilisés pour réécrire d'autres scripts. Considérez-les comme une fonctionnalité de recherche et de remplacement capable de lire et d'écrire du code. Vous pouvez les utiliser pour mettre à jour le code source afin de l'adapter aux conventions de codage d'une équipe, apporter des modifications généralisées lorsqu'une API est modifiée ou même corriger automatiquement le code existant lorsque votre package public apporte une modification avec rupture.

La boîte à outils jscodeshift est idéale pour travailler avec des codemods.

Considérez codemods comme une fonctionnalité scriptée de recherche et de remplacement capable de lire et d'écrire du code.
Tweeter

Dans cet article, nous allons explorer une boîte à outils pour codemods appelée "jscodeshift" tout en créant trois codemods de complexité croissante. À la fin, vous aurez une large exposition aux aspects importants de jscodeshift et serez prêt à commencer à écrire vos propres codemods. Nous allons passer par trois exercices qui couvrent certaines utilisations basiques, mais géniales, de codemods, et vous pouvez voir le code source de ces exercices sur mon projet github.

Qu'est-ce que jscodeshift ?

La boîte à outils jscodeshift vous permet de pomper un tas de fichiers source à travers une transformation et de les remplacer par ce qui sort à l'autre bout. À l'intérieur de la transformation, vous analysez la source dans un arbre de syntaxe abstraite (AST), fouillez pour apporter vos modifications, puis régénérez la source à partir de l'AST modifié.

L'interface fournie par jscodeshift est un wrapper autour des packages recast et ast-types . recast gère la conversion de source en AST et inversement tandis que ast-types gère l'interaction de bas niveau avec les nœuds AST.

Installer

Pour commencer, installez jscodeshift globalement à partir de npm.

 npm i -g jscodeshift

Il existe des options de coureur que vous pouvez utiliser et une configuration de test avisée qui rend l'exécution d'une suite de tests via Jest (un framework de test JavaScript open source) vraiment facile, mais nous allons contourner cela pour l'instant en faveur de la simplicité :

jscodeshift -t some-transform.js input-file.js -d -p

Cela exécutera input-file.js via la transformation some-transform.js et imprimera les résultats sans modifier le fichier.

Avant de se lancer, cependant, il est important de comprendre les trois principaux types d'objets traités par l'API jscodeshift : les nœuds, les chemins de nœuds et les collections.

Nœuds

Les nœuds sont les éléments de base de l'AST, souvent appelés « nœuds AST ». C'est ce que vous voyez lorsque vous explorez votre code avec AST Explorer. Ce sont des objets simples et ne fournissent aucune méthode.

Chemins de nœud

Les chemins de nœuds sont des enveloppes autour d'un nœud AST fourni par ast-types comme un moyen de traverser l'arbre de syntaxe abstraite (AST, vous vous souvenez ?). Isolément, les nœuds n'ont aucune information sur leur parent ou leur portée, donc les chemins de nœud s'en chargent. Vous pouvez accéder au nœud enveloppé via la propriété node et plusieurs méthodes sont disponibles pour modifier le nœud sous-jacent. les chemins de nœud sont souvent appelés simplement des « chemins ».

Collections

Les collections sont des groupes de zéro ou plusieurs chemins de nœud que l'API jscodeshift renvoie lorsque vous interrogez l'AST. Ils ont toutes sortes de méthodes utiles, dont certaines que nous allons explorer.

Les collections contiennent des chemins de nœuds, les chemins de nœuds contiennent des nœuds et les nœuds sont ce dont est fait l'AST. Gardez cela à l'esprit et il sera facile de comprendre l'API de requête jscodeshift.

Il peut être difficile de suivre les différences entre ces objets et leurs capacités d'API respectives. Il existe donc un outil astucieux appelé jscodeshift-helper qui enregistre le type d'objet et fournit d'autres informations clés.

Connaître la différence entre les nœuds, les chemins de nœuds et les collections est important.

Connaître la différence entre les nœuds, les chemins de nœuds et les collections est important.

Exercice 1 : Supprimer les appels vers la console

Pour nous mouiller les pieds, commençons par supprimer les appels à toutes les méthodes de la console dans notre base de code. Bien que vous puissiez le faire avec rechercher et remplacer et un peu de regex, cela commence à devenir délicat avec des instructions multilignes, des littéraux de modèle et des appels plus complexes, c'est donc un exemple idéal pour commencer.

Tout d'abord, créez deux fichiers, remove-consoles.js et remove-consoles.input.js :

 //remove-consoles.js export default (fileInfo, api) => { };
 //remove-consoles.input.js export const sum = (a, b) => { console.log('calling sum with', arguments); return a + b; }; export const multiply = (a, b) => { console.warn('calling multiply with', arguments); return a * b; }; export const divide = (a, b) => { console.error(`calling divide with ${ arguments }`); return a / b; }; export const average = (a, b) => { console.log('calling average with ' + arguments); return divide(sum(a, b), 2); };

Voici la commande que nous utiliserons dans le terminal pour le pousser via jscodeshift :

jscodeshift -t remove-consoles.js remove-consoles.input.js -d -p

Si tout est configuré correctement, lorsque vous l'exécutez, vous devriez voir quelque chose comme ça.

 Processing 1 files... Spawning 1 workers... Running in dry mode, no files will be written! Sending 1 files to free worker... All done. Results: 0 errors 0 unmodified 1 skipped 0 ok Time elapsed: 0.514seconds

OK, c'était un peu décevant puisque notre transformation ne fait encore rien, mais au moins nous savons que tout fonctionne. S'il ne fonctionne pas du tout, assurez-vous d'avoir installé jscodeshift globalement. Si la commande pour exécuter la transformation est incorrecte, vous verrez soit un message "ERREUR Le fichier de transformation... n'existe pas" ou "TypeError : le chemin doit être une chaîne ou un tampon" si le fichier d'entrée est introuvable. Si vous avez un gros doigt sur quelque chose, cela devrait être facile à repérer avec les erreurs de transformation très descriptives.

En relation: Feuille de triche JavaScript rapide et pratique de Toptal: ES6 et au-delà

Notre objectif final cependant, après une transformation réussie, est de voir cette source :

 export const sum = (a, b) => { return a + b; }; export const multiply = (a, b) => { return a * b; }; export const divide = (a, b) => { return a / b; }; export const average = (a, b) => { return divide(sum(a, b), 2); };

Pour y arriver, nous devons convertir la source en AST, trouver les consoles, les supprimer, puis reconvertir l'AST modifié en source. La première et la dernière étape sont faciles, c'est juste :

 remove-consoles.js export default (fileInfo, api) => { const j = api.jscodeshift; const root = j(fileInfo.source); return root.toSource(); };

Mais comment trouver les consoles et les supprimer ? À moins que vous n'ayez une connaissance exceptionnelle de l'API Mozilla Parser, vous aurez probablement besoin d'un outil pour vous aider à comprendre à quoi ressemble l'AST. Pour cela, vous pouvez utiliser l'explorateur AST. Collez-y le contenu de remove-consoles.input.js et vous verrez l'AST. Il y a beaucoup de données même dans le code le plus simple, il est donc utile de masquer les données et les méthodes de localisation. Vous pouvez basculer la visibilité des propriétés dans AST Explorer avec les cases à cocher au-dessus de l'arborescence.

Nous pouvons voir que les appels aux méthodes de la console sont appelés CallExpressions , alors comment les trouver dans notre transformation ? Nous utilisons les requêtes de jscodeshift, en nous souvenant de notre discussion précédente sur les différences entre les collections, les chemins de nœuds et les nœuds eux-mêmes :

 //remove-consoles.js export default (fileInfo, api) => { const j = api.jscodeshift; const root = j(fileInfo.source); return root.toSource(); };

La ligne const root = j(fileInfo.source); renvoie une collection d'un chemin de nœud, qui encapsule le nœud AST racine. Nous pouvons utiliser la méthode find de la collection pour rechercher des nœuds descendants d'un certain type, comme ceci :

 const callExpressions = root.find(j.CallExpression);

Cela renvoie une autre collection de chemins de nœuds contenant uniquement les nœuds qui sont CallExpressions. À première vue, cela semble être ce que nous voulons, mais c'est trop large. Nous pourrions finir par exécuter des centaines ou des milliers de fichiers via nos transformations, nous devons donc être précis pour avoir la certitude que cela fonctionnera comme prévu. La find naïve ci-dessus ne trouverait pas seulement la console CallExpressions, elle trouverait chaque CallExpression dans la source, y compris

 require('foo') bar() setTimeout(() => {}, 0)

Pour forcer une plus grande spécificité, nous fournissons un deuxième argument à .find : Un objet de paramètres supplémentaires, chaque nœud doit être inclus dans les résultats. Nous pouvons regarder l'explorateur AST pour voir que nos appels console.* ont la forme suivante :

 { "type": "CallExpression", "callee": { "type": "MemberExpression", "object": { "type": "Identifier", "name": "console" } } }

Avec cette connaissance, nous savons affiner notre requête avec un spécificateur qui renverra uniquement le type de CallExpressions qui nous intéresse :

 const callExpressions = root.find(j.CallExpression, { callee: { type: 'MemberExpression', object: { type: 'Identifier', name: 'console' }, }, });

Maintenant que nous avons une collection précise des sites d'appel, supprimons-les de l'AST. De manière pratique, le type d'objet collection a une méthode remove qui fera exactement cela. Notre fichier remove-consoles.js ressemblera désormais à ceci :

 //remove-consoles.js export default (fileInfo, api) => { const j = api.jscodeshift; const root = j(fileInfo.source) const callExpressions = root.find(j.CallExpression, { callee: { type: 'MemberExpression', object: { type: 'Identifier', name: 'console' }, }, } ); callExpressions.remove(); return root.toSource(); };

Maintenant, si nous exécutons notre transformation à partir de la ligne de commande en utilisant jscodeshift -t remove-consoles.js remove-consoles.input.js -d -p , nous devrions voir :

 Processing 1 files... Spawning 1 workers... Running in dry mode, no files will be written! Sending 1 files to free worker... export const sum = (a, b) => { return a + b; }; export const multiply = (a, b) => { return a * b; }; export const divide = (a, b) => { return a / b; }; export const average = (a, b) => { return divide(sum(a, b), 2); }; All done. Results: 0 errors 0 unmodified 0 skipped 1 ok Time elapsed: 0.604seconds

Ça à l'air bon. Maintenant que notre transformation modifie l'AST sous-jacent, l'utilisation .toSource() génère une chaîne différente de l'original. L'option -p de notre commande affiche le résultat, et un décompte des dispositions pour chaque fichier traité est affiché en bas. La suppression de l'option -d de notre commande remplacerait le contenu de remove-consoles.input.js par la sortie de la transformation.

Notre premier exercice est terminé… presque. Le code est bizarre et probablement très offensant pour tous les puristes fonctionnels, et donc pour améliorer le flux de code de transformation, jscodeshift a rendu la plupart des choses chaînées. Cela nous permet de réécrire notre transformation comme suit :

 // remove-consoles.js export default (fileInfo, api) => { const j = api.jscodeshift; return j(fileInfo.source) .find(j.CallExpression, { callee: { type: 'MemberExpression', object: { type: 'Identifier', name: 'console' }, }, } ) .remove() .toSource(); };

Beaucoup mieux. Pour récapituler l'exercice 1, nous avons enveloppé la source, interrogé une collection de chemins de nœuds, modifié l'AST, puis régénéré cette source. Nous nous sommes mouillés les pieds avec un exemple assez simple et avons abordé les aspects les plus importants. Maintenant, faisons quelque chose de plus intéressant.

Exercice 2 : Remplacement des appels de méthode importés

Pour ce scénario, nous avons un module "géométrie" avec une méthode nommée "circleArea" que nous avons déconseillée au profit de "getCircleArea". Nous pourrions facilement les trouver et les remplacer par /geometry\.circleArea/g , mais que se passe-t-il si l'utilisateur a importé le module et lui a attribué un nom différent ? Par exemple:

 import g from 'geometry'; const area = g.circleArea(radius);

Comment saurions-nous remplacer g.circleArea au lieu de geometry.circleArea ? Nous ne pouvons certainement pas supposer que tous les appels de circleArea sont ceux que nous recherchons, nous avons besoin d'un peu de contexte. C'est là que les codemods commencent à montrer leur valeur. Commençons par créer deux fichiers, deprecated.js et deprecated.input.js .

 //deprecated.js export default (fileInfo, api) => { const j = api.jscodeshift; const root = j(fileInfo.source); return root.toSource(); };
 deprecated.input.js import g from 'geometry'; import otherModule from 'otherModule'; const radius = 20; const area = g.circleArea(radius); console.log(area === Math.pow(g.getPi(), 2) * radius); console.log(area === otherModule.circleArea(radius));

Maintenant, exécutez cette commande pour exécuter le codemod.

jscodeshift -t ./deprecated.js ./deprecated.input.js -d -p

Vous devriez voir une sortie indiquant que la transformation a été exécutée, mais n'a encore rien changé.

 Processing 1 files... Spawning 1 workers... Running in dry mode, no files will be written! Sending 1 files to free worker... All done. Results: 0 errors 1 unmodified 0 skipped 0 ok Time elapsed: 0.892seconds

Nous devons savoir sous quelle forme notre module de geometry a été importé. Regardons l'explorateur AST et découvrons ce que nous recherchons. Notre import prend cette forme.

 { "type": "ImportDeclaration", "specifiers": [ { "type": "ImportDefaultSpecifier", "local": { "type": "Identifier", "name": "g" } } ], "source": { "type": "Literal", "value": "geometry" } }

Nous pouvons spécifier un type d'objet pour trouver une collection de nœuds comme ceci :

 const importDeclaration = root.find(j.ImportDeclaration, { source: { type: 'Literal', value: 'geometry', }, });

Cela nous donne la ImportDeclaration utilisée pour importer la "géométrie". À partir de là, creusez pour trouver le nom local utilisé pour contenir le module importé. Puisque c'est la première fois que nous le faisons, soulignons un point important et déroutant lors du premier démarrage.

Remarque : Il est important de savoir que root.find() renvoie une collection de chemins de nœuds. À partir de là, la .get(n) renvoie le chemin du nœud à l'index n dans cette collection, et pour obtenir le nœud réel, nous utilisons .node . Le nœud est essentiellement ce que nous voyons dans AST Explorer. N'oubliez pas que le chemin du nœud contient principalement des informations sur la portée et les relations du nœud, et non sur le nœud lui-même.

 // find the Identifiers const identifierCollection = importDeclaration.find(j.Identifier); // get the first NodePath from the Collection const nodePath = identifierCollection.get(0); // get the Node in the NodePath and grab its "name" const localName = nodePath.node.name;

Cela nous permet de déterminer dynamiquement sous quelle forme notre module de geometry a été importé. Ensuite, nous trouvons les endroits où il est utilisé et les modifions. En regardant AST Explorer, nous pouvons voir que nous devons trouver des MemberExpressions qui ressemblent à ceci :

 { "type": "MemberExpression", "object": { "name": "geometry" }, "property": { "name": "circleArea" } }

Rappelez-vous, cependant, que notre module peut avoir été importé avec un nom différent, nous devons donc en tenir compte en faisant en sorte que notre requête ressemble à ceci :

 j.MemberExpression, { object: { name: localName, }, property: { name: "circleArea", }, })

Maintenant que nous avons une requête, nous pouvons obtenir une collection de tous les sites d'appel vers notre ancienne méthode, puis utiliser la méthode replaceWith() de la collection pour les échanger. La méthode replaceWith() parcourt la collection, en transmettant chaque chemin de nœud à une fonction de rappel. Le nœud AST est ensuite remplacé par le nœud que vous renvoyez du rappel.

Les mods de code vous permettent de créer des scripts de considérations "intelligentes" pour la refactorisation.

Encore une fois, comprendre la différence entre les collections, les chemins de nœuds et les nœuds est nécessaire pour que cela ait un sens.

Une fois que nous avons terminé le remplacement, nous générons la source comme d'habitude. Voici notre transformation terminée :

 //deprecated.js export default (fileInfo, api) => { const j = api.jscodeshift; const root = j(fileInfo.source); // find declaration for "geometry" import const importDeclaration = root.find(j.ImportDeclaration, { source: { type: 'Literal', value: 'geometry', }, }); // get the local name for the imported module const localName = // find the Identifiers importDeclaration.find(j.Identifier) // get the first NodePath from the Collection .get(0) // get the Node in the NodePath and grab its "name" .node.name; return root.find(j.MemberExpression, { object: { name: localName, }, property: { name: 'circleArea', }, }) .replaceWith(nodePath => { // get the underlying Node const { node } = nodePath; // change to our new prop node.property.name = 'getCircleArea'; // replaceWith should return a Node, not a NodePath return node; }) .toSource(); };

Lorsque nous exécutons la source via la transformation, nous voyons que l'appel à la méthode obsolète dans le module de geometry a été modifié, mais le reste n'a pas été modifié, comme ceci :

 import g from 'geometry'; import otherModule from 'otherModule'; const radius = 20; const area = g.getCircleArea(radius); console.log(area === Math.pow(g.getPi(), 2) * radius); console.log(area === otherModule.circleArea(radius));

Exercice 3 : Modification d'une signature de méthode

Dans les exercices précédents, nous avons couvert l'interrogation de collections pour des types de nœuds spécifiques, la suppression de nœuds et la modification de nœuds, mais qu'en est-il de la création de nouveaux nœuds ? C'est ce que nous allons aborder dans cet exercice.

Dans ce scénario, nous avons une signature de méthode qui est devenue incontrôlable avec des arguments individuels au fur et à mesure que le logiciel s'est développé, et il a donc été décidé qu'il serait préférable d'accepter un objet contenant ces arguments à la place.

Au lieu de car.factory('white', 'Kia', 'Sorento', 2010, 50000, null, true);

nous aimerions voir

 const suv = car.factory({ color: 'white', make: 'Kia', model: 'Sorento', year: 2010, miles: 50000, bedliner: null, alarm: true, });

Commençons par créer la transformation et un fichier d'entrée à tester avec :

 //signature-change.js export default (fileInfo, api) => { const j = api.jscodeshift; const root = j(fileInfo.source); return root.toSource(); };
 //signature-change.input.js import car from 'car'; const suv = car.factory('white', 'Kia', 'Sorento', 2010, 50000, null, true); const truck = car.factory('silver', 'Toyota', 'Tacoma', 2006, 100000, true, true);

Notre commande pour exécuter la transformation sera jscodeshift -t signature-change.js signature-change.input.js -d -p et les étapes dont nous avons besoin pour effectuer cette transformation sont :

  • Trouver le nom local du module importé
  • Trouver tous les sites d'appel à la méthode .factory
  • Lire tous les arguments transmis
  • Remplacez cet appel par un seul argument qui contient un objet avec les valeurs d'origine

En utilisant l'explorateur AST et le processus que nous avons utilisé dans les exercices précédents, les deux premières étapes sont simples :

 //signature-change.js export default (fileInfo, api) => { const j = api.jscodeshift; const root = j(fileInfo.source); // find declaration for "car" import const importDeclaration = root.find(j.ImportDeclaration, { source: { type: 'Literal', value: 'car', }, }); // get the local name for the imported module const localName = importDeclaration.find(j.Identifier) .get(0) .node.name; // find where `.factory` is being called return root.find(j.CallExpression, { callee: { type: 'MemberExpression', object: { name: localName, }, property: { name: 'factory', }, } }) .toSource(); };

Pour lire tous les arguments actuellement transmis, nous utilisons la méthode replaceWith() sur notre collection de CallExpressions pour échanger chacun des nœuds. Les nouveaux nœuds remplaceront node.arguments par un nouvel argument unique, un objet.

Échangez facilement les arguments de méthode avec jscodeshift !

Modifiez les signatures de méthode avec 'replacewith()' et échangez des nœuds entiers.

Essayons avec un objet simple pour nous assurer que nous savons comment cela fonctionne avant d'utiliser les bonnes valeurs :

 .replaceWith(nodePath => { const { node } = nodePath; node.arguments = [{ foo: 'bar' }]; return node; })

Lorsque nous exécutons ceci ( jscodeshift -t signature-change.js signature-change.input.js -d -p ), la transformation explosera avec :

 ERR signature-change.input.js Transformation error Error: {foo: bar} does not match type Printable

Il s'avère que nous ne pouvons pas simplement bloquer des objets simples dans nos nœuds AST. Au lieu de cela, nous devons utiliser des constructeurs pour créer des nœuds appropriés.

Connexe : embauchez les 3 % de développeurs Javascript indépendants les plus performants.

Constructeurs de nœuds

Les constructeurs nous permettent de créer correctement de nouveaux nœuds ; ils sont fournis par ast-types et apparaissent via jscodeshift. Ils vérifient rigoureusement que les différents types de nœuds sont créés correctement, ce qui peut être frustrant lorsque vous piratez un rouleau, mais finalement, c'est une bonne chose. Pour comprendre comment utiliser les générateurs, il y a deux choses que vous devez garder à l'esprit :

Tous les types de nœuds AST disponibles sont définis dans le dossier def du projet github ast-types, principalement dans core.js. Il existe des générateurs pour tous les types de nœuds AST, mais ils utilisent une version camel du type de nœud, pas pascal. -Cas. (Ce n'est pas explicitement indiqué, mais vous pouvez voir que c'est le cas dans la source ast-types

Si nous utilisons AST Explorer avec un exemple de ce que nous voulons que le résultat soit, nous pouvons reconstituer cela assez facilement. Dans notre cas, nous voulons que le nouvel argument unique soit un ObjectExpression avec un tas de propriétés. En regardant les définitions de type mentionnées ci-dessus, nous pouvons voir ce que cela implique :

 def("ObjectExpression") .bases("Expression") .build("properties") .field("properties", [def("Property")]); def("Property") .bases("Node") .build("kind", "key", "value") .field("kind", or("init", "get", "set")) .field("key", or(def("Literal"), def("Identifier"))) .field("value", def("Expression"));

Ainsi, le code pour construire un nœud AST pour { foo: 'bar' } ressemblerait à :

 j.objectExpression([ j.property( 'init', j.identifier('foo'), j.literal('bar') ) ]);

Prenez ce code et branchez-le dans notre transformation comme ceci :

 .replaceWith(nodePath => { const { node } = nodePath; const object = j.objectExpression([ j.property( 'init', j.identifier('foo'), j.literal('bar') ) ]); node.arguments = [object]; return node; })

L'exécution de ceci nous donne le résultat :

 import car from 'car'; const suv = car.factory({ foo: "bar" }); const truck = car.factory({ foo: "bar" });

Maintenant que nous savons comment créer un nœud AST approprié, il est facile de parcourir les anciens arguments et de générer un nouvel objet à utiliser à la place. Voici à quoi ressemble notre fichier signature-change.js :

 //signature-change.js export default (fileInfo, api) => { const j = api.jscodeshift; const root = j(fileInfo.source); // find declaration for "car" import const importDeclaration = root.find(j.ImportDeclaration, { source: { type: 'Literal', value: 'car', }, }); // get the local name for the imported module const localName = importDeclaration.find(j.Identifier) .get(0) .node.name; // current order of arguments const argKeys = [ 'color', 'make', 'model', 'year', 'miles', 'bedliner', 'alarm', ]; // find where `.factory` is being called return root.find(j.CallExpression, { callee: { type: 'MemberExpression', object: { name: localName, }, property: { name: 'factory', }, } }) .replaceWith(nodePath => { const { node } = nodePath; // use a builder to create the ObjectExpression const argumentsAsObject = j.objectExpression( // map the arguments to an Array of Property Nodes node.arguments.map((arg, i) => j.property( 'init', j.identifier(argKeys[i]), j.literal(arg.value) ) ) ); // replace the arguments with our new ObjectExpression node.arguments = [argumentsAsObject]; return node; }) // specify print options for recast .toSource({ quote: 'single', trailingComma: true }); };

Exécutez la transformation ( jscodeshift -t signature-change.js signature-change.input.js -d -p ) et nous verrons que les signatures ont été mises à jour comme prévu :

 import car from 'car'; const suv = car.factory({ color: 'white', make: 'Kia', model: 'Sorento', year: 2010, miles: 50000, bedliner: null, alarm: true, }); const truck = car.factory({ color: 'silver', make: 'Toyota', model: 'Tacoma', year: 2006, miles: 100000, bedliner: true, alarm: true, });

Codemods avec jscodeshift Récapitulatif

Il a fallu un peu de temps et d'efforts pour arriver à ce point, mais les avantages sont énormes face à la refactorisation de masse. Distribuer des groupes de fichiers à différents processus et les exécuter en parallèle est quelque chose dans lequel jscodeshift excelle, vous permettant d'exécuter des transformations complexes sur une énorme base de code en quelques secondes. Au fur et à mesure que vous maîtriserez les codemods, vous commencerez à réaffecter des scripts existants (tels que le référentiel github de react-codemod ou à écrire le vôtre pour toutes sortes de tâches, et cela vous rendra, vous, votre équipe et vos utilisateurs de packages plus efficaces .